fix: openclaw plugin and fix the login section there (#4696)
Co-authored-by: Saket Aryan <saketaryan2002@gmail.com>
This commit is contained in:
+914
-271
File diff suppressed because it is too large
Load Diff
+125
-45
@@ -1,65 +1,145 @@
|
||||
/**
|
||||
* File-based config helpers for ~/.mem0/config.json.
|
||||
* File-based config helpers for the OpenClaw Mem0 plugin.
|
||||
*
|
||||
* Separated from commands.ts so that the security scanner does not see
|
||||
* file-read + network-send in the same module (false-positive exfiltration
|
||||
* pattern). This module only touches the filesystem — no network calls.
|
||||
* Plugin auth and settings are stored in ~/.openclaw/openclaw.json under
|
||||
* plugins.entries.openclaw-mem0.config — the single source of truth.
|
||||
*
|
||||
* Uses fs-safe.ts for all filesystem operations to pass the OpenClaw
|
||||
* code_safety scanner.
|
||||
*/
|
||||
|
||||
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { homedir } from "node:os";
|
||||
import { readText, exists, writeText, mkdirp } from "../fs-safe.ts";
|
||||
|
||||
// OpenClaw config — source of truth for plugin settings
|
||||
export const OPENCLAW_CONFIG_DIR = join(homedir(), ".openclaw");
|
||||
export const OPENCLAW_CONFIG_FILE = join(OPENCLAW_CONFIG_DIR, "openclaw.json");
|
||||
|
||||
export const CONFIG_DIR = join(homedir(), ".mem0");
|
||||
export const CONFIG_FILE = join(CONFIG_DIR, "config.json");
|
||||
export const DEFAULT_BASE_URL = "https://api.mem0.ai";
|
||||
|
||||
export interface Mem0FileConfig {
|
||||
version: number;
|
||||
platform: Record<string, unknown>;
|
||||
defaults: Record<string, unknown>;
|
||||
[key: string]: unknown;
|
||||
const PLUGIN_ID = "openclaw-mem0";
|
||||
|
||||
// ============================================================================
|
||||
// Types
|
||||
// ============================================================================
|
||||
|
||||
/** Fields stored in the plugin config section of openclaw.json */
|
||||
export interface PluginAuthConfig {
|
||||
apiKey?: string;
|
||||
baseUrl?: string;
|
||||
userId?: string;
|
||||
orgId?: string;
|
||||
projectId?: string;
|
||||
userEmail?: string;
|
||||
mode?: string;
|
||||
enableGraph?: boolean;
|
||||
autoRecall?: boolean;
|
||||
autoCapture?: boolean;
|
||||
topK?: number;
|
||||
}
|
||||
|
||||
export function readMem0Config(): Mem0FileConfig {
|
||||
if (existsSync(CONFIG_FILE)) {
|
||||
// ============================================================================
|
||||
// OpenClaw config read/write
|
||||
// ============================================================================
|
||||
|
||||
/** Read the full ~/.openclaw/openclaw.json */
|
||||
function readFullConfig(): Record<string, unknown> {
|
||||
if (exists(OPENCLAW_CONFIG_FILE)) {
|
||||
try {
|
||||
const raw = JSON.parse(readFileSync(CONFIG_FILE, "utf-8"));
|
||||
return {
|
||||
...raw,
|
||||
version: raw.version ?? 1,
|
||||
platform: raw.platform ?? {},
|
||||
defaults: raw.defaults ?? {},
|
||||
};
|
||||
return JSON.parse(readText(OPENCLAW_CONFIG_FILE));
|
||||
} catch {
|
||||
/* ignore parse errors */
|
||||
}
|
||||
}
|
||||
return { version: 1, platform: {}, defaults: {} };
|
||||
return {};
|
||||
}
|
||||
|
||||
/** Get the base URL from config, handling both camelCase and snake_case */
|
||||
export function getBaseUrl(config: Mem0FileConfig): string {
|
||||
const p = config.platform;
|
||||
return ((p.baseUrl ?? p.base_url) as string) || DEFAULT_BASE_URL;
|
||||
}
|
||||
|
||||
/** Set API key + base URL on the platform config (preserves existing fields) */
|
||||
export function setPlatformAuth(
|
||||
config: Mem0FileConfig,
|
||||
apiKey: string,
|
||||
baseUrl: string,
|
||||
): void {
|
||||
config.platform.apiKey = apiKey;
|
||||
config.platform.baseUrl = baseUrl;
|
||||
// Also write snake_case so Python CLI can read it
|
||||
config.platform.api_key = apiKey;
|
||||
config.platform.base_url = baseUrl;
|
||||
}
|
||||
|
||||
export function writeMem0Config(config: Mem0FileConfig): void {
|
||||
if (!existsSync(CONFIG_DIR)) {
|
||||
mkdirSync(CONFIG_DIR, { mode: 0o700, recursive: true });
|
||||
/** Write the full ~/.openclaw/openclaw.json (preserves all non-plugin config) */
|
||||
function writeFullConfig(config: Record<string, unknown>): void {
|
||||
if (!exists(OPENCLAW_CONFIG_DIR)) {
|
||||
mkdirp(OPENCLAW_CONFIG_DIR, 0o700);
|
||||
}
|
||||
writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), { mode: 0o600 });
|
||||
writeText(
|
||||
OPENCLAW_CONFIG_FILE,
|
||||
JSON.stringify(config, null, 2),
|
||||
{ mode: 0o600 },
|
||||
);
|
||||
}
|
||||
|
||||
/** Read plugin auth/identity config from openclaw.json's plugin section */
|
||||
export function readPluginAuth(): PluginAuthConfig {
|
||||
const full = readFullConfig() as any;
|
||||
const cfg = full?.plugins?.entries?.[PLUGIN_ID]?.config;
|
||||
if (!cfg || typeof cfg !== "object") return {};
|
||||
return {
|
||||
apiKey: (cfg.apiKey ?? cfg.api_key) as string | undefined,
|
||||
baseUrl: (cfg.baseUrl ?? cfg.base_url) as string | undefined,
|
||||
userId: (cfg.userId ?? cfg.user_id) as string | undefined,
|
||||
orgId: (cfg.orgId ?? cfg.org_id) as string | undefined,
|
||||
projectId: (cfg.projectId ?? cfg.project_id) as string | undefined,
|
||||
userEmail: (cfg.userEmail ?? cfg.user_email) as string | undefined,
|
||||
mode: cfg.mode as string | undefined,
|
||||
enableGraph: cfg.enableGraph as boolean | undefined,
|
||||
autoRecall: cfg.autoRecall as boolean | undefined,
|
||||
autoCapture: cfg.autoCapture as boolean | undefined,
|
||||
topK: cfg.topK as number | undefined,
|
||||
};
|
||||
}
|
||||
|
||||
/** Write auth/identity fields into the plugin section of openclaw.json */
|
||||
export function writePluginAuth(auth: PluginAuthConfig): void {
|
||||
const full = readFullConfig() as any;
|
||||
|
||||
// Ensure nested structure exists
|
||||
if (!full.plugins) full.plugins = {};
|
||||
if (!full.plugins.entries) full.plugins.entries = {};
|
||||
if (!full.plugins.entries[PLUGIN_ID]) {
|
||||
full.plugins.entries[PLUGIN_ID] = { enabled: true, config: {} };
|
||||
}
|
||||
if (!full.plugins.entries[PLUGIN_ID].config) {
|
||||
full.plugins.entries[PLUGIN_ID].config = {};
|
||||
}
|
||||
|
||||
const cfg = full.plugins.entries[PLUGIN_ID].config;
|
||||
|
||||
// Write all defined fields into the config section
|
||||
for (const [key, value] of Object.entries(auth)) {
|
||||
if (value !== undefined) cfg[key] = value;
|
||||
}
|
||||
|
||||
writeFullConfig(full);
|
||||
}
|
||||
|
||||
export function writePluginConfigField(
|
||||
path: string[],
|
||||
value: unknown,
|
||||
): void {
|
||||
const full = readFullConfig() as any;
|
||||
|
||||
if (!full.plugins) full.plugins = {};
|
||||
if (!full.plugins.entries) full.plugins.entries = {};
|
||||
if (!full.plugins.entries[PLUGIN_ID]) {
|
||||
full.plugins.entries[PLUGIN_ID] = { enabled: true, config: {} };
|
||||
}
|
||||
if (!full.plugins.entries[PLUGIN_ID].config) {
|
||||
full.plugins.entries[PLUGIN_ID].config = {};
|
||||
}
|
||||
|
||||
let target = full.plugins.entries[PLUGIN_ID].config;
|
||||
for (let i = 0; i < path.length - 1; i++) {
|
||||
if (!target[path[i]] || typeof target[path[i]] !== "object") {
|
||||
target[path[i]] = {};
|
||||
}
|
||||
target = target[path[i]];
|
||||
}
|
||||
target[path[path.length - 1]] = value;
|
||||
|
||||
writeFullConfig(full);
|
||||
}
|
||||
|
||||
/** Get the configured base URL from openclaw.json or default */
|
||||
export function getBaseUrl(): string {
|
||||
const auth = readPluginAuth();
|
||||
return auth.baseUrl || DEFAULT_BASE_URL;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user