UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

262 lines (261 loc) • 11.8 kB
import { c as isRecord, r as asNullableRecord } from "../../record-coerce-TIsquoVR.mjs"; import { t as FsSafeError, w as root } from "../../fs-safe-CS1DrPTK.mjs"; import "../../string-coerce-runtime-B1b8UNzb.mjs"; import "../../runtime-doctor-migrations-CB-H2TCs.mjs"; import { n as legacyStateFileExists, t as archiveLegacyStateSource } from "../../doctor-state-migration-fs-CfVap4xL.mjs"; import "../../security-runtime-9ynw5sNI.mjs"; import { a as resolveMemoryWikiConfig, i as resolveMemoryWikiAgentConfig, o as resolveMemoryWikiConfiguredAgentIds } from "../../config-DgD41BlM.mjs"; import { S as writeMemoryWikiSourceSyncState, _ as readLegacyMemoryWikiSourceSyncState, a as createMemoryWikiImportRunStateStore, d as MEMORY_WIKI_SOURCE_SYNC_STATE_MAX_ENTRIES, f as MEMORY_WIKI_SOURCE_SYNC_STATE_NAMESPACE, h as createMemoryWikiSourceSyncStateStore, i as countMemoryWikiImportRunStateRows, l as resolveMemoryWikiImportRunsDir, n as MEMORY_WIKI_IMPORT_RUN_STATE_NAMESPACE, o as listMemoryWikiImportRunRecords, s as readLegacyMemoryWikiImportRunRecords, t as MEMORY_WIKI_IMPORT_RUN_STATE_MAX_ENTRIES, u as writeMemoryWikiImportRunRecord, y as resolveMemoryWikiSourceSyncStatePath } from "../../import-runs-state-G9XjcAMp.mjs"; import path from "node:path"; import fs from "node:fs/promises"; //#region extensions/memory-wiki/src/config-compat.ts function hasLegacyBridgeArtifactToggle(value) { return Object.hasOwn(asNullableRecord(value) ?? {}, "readMemoryCore"); } const legacyConfigRules = [{ path: [ "plugins", "entries", "memory-wiki", "config", "bridge" ], message: "plugins.entries.memory-wiki.config.bridge.readMemoryCore is legacy; use plugins.entries.memory-wiki.config.bridge.readMemoryArtifacts. Run \"openclaw doctor --fix\".", match: hasLegacyBridgeArtifactToggle }]; function migrateMemoryWikiLegacyConfig(config) { const rawEntry = asNullableRecord(config.plugins?.entries?.["memory-wiki"]); const rawPluginConfig = asNullableRecord(rawEntry?.config); const rawBridge = asNullableRecord(rawPluginConfig?.bridge); if (!rawBridge || !hasLegacyBridgeArtifactToggle(rawBridge)) return null; const nextConfig = structuredClone(config); const nextPlugins = asNullableRecord(nextConfig.plugins) ?? {}; nextConfig.plugins = nextPlugins; const nextEntries = asNullableRecord(nextPlugins.entries) ?? {}; nextPlugins.entries = nextEntries; const nextEntry = asNullableRecord(nextEntries["memory-wiki"]) ?? {}; nextEntries["memory-wiki"] = nextEntry; const nextPluginConfig = asNullableRecord(nextEntry.config) ?? {}; nextEntry.config = nextPluginConfig; const nextBridge = asNullableRecord(nextPluginConfig.bridge) ?? {}; nextPluginConfig.bridge = nextBridge; const legacyValue = nextBridge.readMemoryCore; const hasCanonical = Object.hasOwn(nextBridge, "readMemoryArtifacts"); if (!hasCanonical) nextBridge.readMemoryArtifacts = legacyValue; delete nextBridge.readMemoryCore; return { config: nextConfig, changes: hasCanonical ? ["Removed legacy plugins.entries.memory-wiki.config.bridge.readMemoryCore; kept explicit plugins.entries.memory-wiki.config.bridge.readMemoryArtifacts."] : ["Moved plugins.entries.memory-wiki.config.bridge.readMemoryCore → plugins.entries.memory-wiki.config.bridge.readMemoryArtifacts."] }; } function normalizeCompatibilityConfig({ cfg }) { return migrateMemoryWikiLegacyConfig(cfg) ?? { config: cfg, changes: [] }; } //#endregion //#region extensions/memory-wiki/doctor-contract-api.ts const LEGACY_MEMORY_WIKI_COMPILED_CACHE_PATHS = [".openclaw-wiki/cache/agent-digest.json", ".openclaw-wiki/cache/claims.jsonl"]; function resolveHomeDir(env) { return env.HOME?.trim() || env.USERPROFILE?.trim() || void 0; } function isMissingPathError(error) { return error instanceof FsSafeError && error.code === "not-found" || isRecord(error) && error.code === "ENOENT"; } async function safeLegacyCacheFileExists(vaultRoot, relativePath) { try { return (await vaultRoot.stat(relativePath)).isFile; } catch (error) { if (isMissingPathError(error) || error instanceof FsSafeError) return false; throw error; } } async function openExistingVaultRoot(vaultRoot) { try { return await root(vaultRoot); } catch (error) { if (isMissingPathError(error)) return null; throw error; } } function readConfiguredPluginConfig(config) { const entries = config.plugins?.entries; const pluginEntry = isRecord(entries) ? entries["memory-wiki"] : void 0; if (!isRecord(pluginEntry) || !isRecord(pluginEntry.config)) return; return pluginEntry.config; } function resolveConfiguredVaultRoots(params) { const homeDir = resolveHomeDir(params.env); const resolved = resolveMemoryWikiConfig(readConfiguredPluginConfig(params.config), { homedir: homeDir, env: params.env }); if (resolved.vault.scope === "global") return [resolved.vault.path]; return resolveMemoryWikiConfiguredAgentIds(params.config).map((agentId) => resolveMemoryWikiAgentConfig({ config: resolved, appConfig: params.config, agentId }).vault.path); } async function archiveLegacyImportRunRecords(params) { const importRunsDir = resolveMemoryWikiImportRunsDir(params.vaultRoot); const entries = await fs.readdir(importRunsDir, { withFileTypes: true }).catch((error) => { if (isRecord(error) && error.code === "ENOENT") return []; throw error; }); for (const entry of entries) { if (!entry.isFile() || !entry.name.endsWith(".json")) continue; await archiveLegacyStateSource({ filePath: path.join(importRunsDir, entry.name), label: "Memory Wiki import-run", changes: params.changes, warnings: params.warnings }); } } function countImportRunStateRows(records) { return records.reduce((total, record) => total + 1 + record.createdPaths.length + record.updatedPaths.length, 0); } const stateMigrations = [ { id: "memory-wiki-compiled-cache-file-cleanup", label: "Memory Wiki compiled cache files", async detectLegacyState(params) { const previews = []; for (const vaultRoot of resolveConfiguredVaultRoots(params)) { const root = await openExistingVaultRoot(vaultRoot); if (!root) continue; const stalePaths = (await Promise.all(LEGACY_MEMORY_WIKI_COMPILED_CACHE_PATHS.map(async (relativePath) => { const filePath = path.join(vaultRoot, relativePath); return await safeLegacyCacheFileExists(root, relativePath) ? filePath : null; }))).filter((filePath) => Boolean(filePath)); for (const filePath of stalePaths) previews.push(`- Remove rebuildable Memory Wiki compiled cache: ${filePath}`); } return previews.length > 0 ? { preview: previews } : null; }, async migrateLegacyState(params) { const changes = []; const warnings = []; for (const vaultRoot of resolveConfiguredVaultRoots(params)) { const root = await openExistingVaultRoot(vaultRoot); if (!root) continue; for (const relativePath of LEGACY_MEMORY_WIKI_COMPILED_CACHE_PATHS) { const filePath = path.join(vaultRoot, relativePath); if (!await safeLegacyCacheFileExists(root, relativePath)) continue; try { await root.remove(relativePath); changes.push(`Removed rebuildable Memory Wiki compiled cache: ${filePath}`); } catch (error) { if (!isMissingPathError(error)) warnings.push(`Skipped rebuildable Memory Wiki compiled cache cleanup. Run openclaw doctor --fix to retry. ${filePath}: ${String(error)}`); } } } return { changes, warnings, ...warnings.length > 0 ? { warningDisposition: "recoverable" } : {} }; } }, { id: "memory-wiki-source-sync-json-to-plugin-state", label: "Memory Wiki source sync state", async detectLegacyState(params) { const previews = []; for (const vaultRoot of resolveConfiguredVaultRoots(params)) { const filePath = resolveMemoryWikiSourceSyncStatePath(vaultRoot); const state = await readLegacyMemoryWikiSourceSyncState(vaultRoot); const count = Object.keys(state.entries).length; if (count === 0 || !await legacyStateFileExists(filePath)) continue; previews.push(`- Memory Wiki source sync: ${filePath} -> plugin state (${MEMORY_WIKI_SOURCE_SYNC_STATE_NAMESPACE}, ${count} entries)`); } return previews.length > 0 ? { preview: previews } : null; }, async migrateLegacyState(params) { const changes = []; const warnings = []; const store = createMemoryWikiSourceSyncStateStore(params.context.openPluginStateKeyedStore); for (const vaultRoot of resolveConfiguredVaultRoots(params)) { const filePath = resolveMemoryWikiSourceSyncStatePath(vaultRoot); if (!await legacyStateFileExists(filePath)) continue; const state = await readLegacyMemoryWikiSourceSyncState(vaultRoot); if (Object.keys(state.entries).length === 0) continue; const existingState = await store.read(vaultRoot); const mergedEntries = { ...state.entries, ...existingState.entries }; const mergedCount = Object.keys(mergedEntries).length; if (mergedCount > 2e4) { warnings.push(`Skipped Memory Wiki source-sync import for ${vaultRoot}: ${mergedCount} entries exceeds ${MEMORY_WIKI_SOURCE_SYNC_STATE_MAX_ENTRIES}`); continue; } await writeMemoryWikiSourceSyncState(vaultRoot, { version: 1, entries: mergedEntries }, store); const existingCount = Object.keys(existingState.entries).length; const importedCount = mergedCount - existingCount; changes.push(`Migrated Memory Wiki source sync -> plugin state (${importedCount} imported, ${existingCount} existing)`); await archiveLegacyStateSource({ filePath, label: "Memory Wiki source-sync", changes, warnings }); } return { changes, warnings }; } }, { id: "memory-wiki-import-runs-json-to-plugin-state", label: "Memory Wiki import run records", async detectLegacyState(params) { const previews = []; for (const vaultRoot of resolveConfiguredVaultRoots(params)) { const records = await readLegacyMemoryWikiImportRunRecords(vaultRoot); if (records.length === 0) continue; previews.push(`- Memory Wiki import runs: ${resolveMemoryWikiImportRunsDir(vaultRoot)}/*.json -> plugin state (${MEMORY_WIKI_IMPORT_RUN_STATE_NAMESPACE}, ${records.length} records)`); } return previews.length > 0 ? { preview: previews } : null; }, async migrateLegacyState(params) { const changes = []; const warnings = []; const store = createMemoryWikiImportRunStateStore(params.context.openPluginStateKeyedStore); for (const vaultRoot of resolveConfiguredVaultRoots(params)) { const records = await readLegacyMemoryWikiImportRunRecords(vaultRoot); if (records.length === 0) continue; const existingRecords = await listMemoryWikiImportRunRecords(vaultRoot, store); const existingRunIds = new Set(existingRecords.map((record) => record.runId)); const importedRecords = records.filter((record) => !existingRunIds.has(record.runId)); const nextRowCount = await countMemoryWikiImportRunStateRows(store) + countImportRunStateRows(importedRecords); if (nextRowCount > 2e4) { warnings.push(`Skipped Memory Wiki import-run import for ${vaultRoot}: ${nextRowCount} state rows exceeds ${MEMORY_WIKI_IMPORT_RUN_STATE_MAX_ENTRIES}`); continue; } let importedCount = 0; for (const record of importedRecords) { await writeMemoryWikiImportRunRecord(vaultRoot, record, store); importedCount += 1; } changes.push(`Migrated Memory Wiki import runs -> plugin state (${importedCount} imported, ${existingRunIds.size} existing)`); await archiveLegacyImportRunRecords({ vaultRoot, changes, warnings }); } return { changes, warnings }; } } ]; //#endregion export { legacyConfigRules, normalizeCompatibilityConfig, stateMigrations };