UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

150 lines (149 loc) 6.35 kB
import { m as shortenHomePath } from "./utils-P__uGsPB.js"; import { o as listAgentIds, u as resolveAgentDir, v as resolveDefaultAgentDir } from "./agent-scope-config-DcbEhP0R.js"; import "./agent-scope-DbtJyKUL.js"; import { t as privateFileStore } from "./private-file-store-CaBdNw0y.js"; import { a as isPluginModelCatalogMigrationFile, c as migrateLegacyPluginModelCatalogs, i as isGeneratedPluginModelCatalog, t as decodePluginModelCatalogRelativePathPluginId } from "./plugin-model-catalog-MRmefceV.js"; import { t as note } from "./note-DqHk3fA1.js"; import path from "node:path"; import fs from "node:fs/promises"; //#region src/commands/doctor-plugin-model-catalog.ts function resolveMigrationAgentDirs(params) { if (params.agentDirs) return [...new Set(params.agentDirs)].toSorted((left, right) => left.localeCompare(right)); const env = params.env ?? process.env; const agentIds = listAgentIds(params.cfg); const configuredAgentDirs = agentIds.length > 0 ? agentIds.map((agentId) => resolveAgentDir(params.cfg, agentId, env)) : [resolveDefaultAgentDir(params.cfg, env)]; return [...new Set(configuredAgentDirs)].toSorted((left, right) => left.localeCompare(right)); } async function readLegacyPluginCatalogContents(params) { const pluginDir = path.dirname(path.join(params.agentDir, params.relativePath)); return await privateFileStore(pluginDir).readTextIfExists(path.basename(params.relativePath)); } /** Detects only marker-backed catalogs produced by tagged OpenClaw releases. */ async function collectLegacyPluginModelCatalogMigrations(params) { const migrations = []; for (const agentDir of resolveMigrationAgentDirs(params)) { const pluginsDir = path.join(agentDir, "plugins"); let pluginDirs; try { pluginDirs = await fs.readdir(pluginsDir, { withFileTypes: true }); } catch (error) { if (error.code === "ENOENT") continue; params.warnings?.push(`Could not inspect legacy provider catalogs: ${shortenHomePath(pluginsDir)}`); continue; } for (const pluginDir of pluginDirs) { if (!pluginDir.isDirectory()) continue; const canonicalRelativePath = path.join("plugins", pluginDir.name, "catalog.json"); const pluginId = decodePluginModelCatalogRelativePathPluginId(canonicalRelativePath); if (!pluginId) continue; const pluginPath = path.join(pluginsDir, pluginDir.name); let catalogFiles; try { catalogFiles = await fs.readdir(pluginPath, { withFileTypes: true }); } catch { params.warnings?.push(`Could not inspect legacy provider catalogs: ${shortenHomePath(pluginPath)}`); continue; } const sourceFiles = catalogFiles.filter((entry) => entry.isFile() && isPluginModelCatalogMigrationFile(entry.name)).toSorted((left, right) => { if (left.name === "catalog.json") return 1; if (right.name === "catalog.json") return -1; return left.name.localeCompare(right.name); }); const pluginMigrations = []; let hasUnreadableCatalog = false; for (const sourceFile of sourceFiles) { const relativePath = path.join("plugins", pluginDir.name, sourceFile.name); let contents; try { contents = await readLegacyPluginCatalogContents({ agentDir, relativePath }); } catch { hasUnreadableCatalog = true; params.warnings?.push(`Could not read legacy provider catalog: ${shortenHomePath(path.join(agentDir, relativePath))}`); continue; } if (contents === null) continue; let parsed; try { parsed = JSON.parse(contents); } catch { continue; } if (isGeneratedPluginModelCatalog(parsed)) pluginMigrations.push({ agentDir, pluginId, relativePath, contents }); } if (hasUnreadableCatalog) continue; if (!pluginMigrations.some((migration) => path.basename(migration.relativePath) === "catalog.json") && new Set(pluginMigrations.map((migration) => migration.contents)).size > 1) { params.warnings?.push(`Conflicting retained legacy provider catalogs: ${shortenHomePath(pluginPath)}`); continue; } migrations.push(...pluginMigrations); } } return migrations.toSorted((left, right) => { const agentOrder = left.agentDir.localeCompare(right.agentDir); return agentOrder !== 0 ? agentOrder : left.pluginId.localeCompare(right.pluginId); }); } /** Imports and verifies released sidecars before Doctor removes any legacy bytes. */ async function maybeMigrateLegacyPluginModelCatalogs(params) { const warnings = []; const migrations = await collectLegacyPluginModelCatalogMigrations({ ...params, warnings }); for (const warning of warnings) params.runtime.error(warning); if (migrations.length === 0) return { detected: 0, migrated: 0, warnings }; const emitNote = params.note ?? note; emitNote([ "Legacy generated provider catalogs contain model and credential state.", ...migrations.map((migration) => `- ${shortenHomePath(path.join(migration.agentDir, migration.relativePath))}`), "Run openclaw doctor --fix to verify and migrate these catalogs into agent SQLite." ].join("\n"), "Plugin model catalogs"); if (!(params.prompter.shouldRepair || await params.prompter.confirmAutoFix({ message: "Migrate generated provider model catalogs into agent SQLite now?", initialValue: true }))) return { detected: migrations.length, migrated: 0, warnings }; const grouped = /* @__PURE__ */ new Map(); for (const migration of migrations) { const agentMigrations = grouped.get(migration.agentDir) ?? []; agentMigrations.push(migration); grouped.set(migration.agentDir, agentMigrations); } let migrated = 0; for (const [agentDir, agentMigrations] of grouped) { const result = migrateLegacyPluginModelCatalogs({ agentDir, expectedContents: new Map(agentMigrations.map((migration) => [migration.pluginId, migration.contents])) }); migrated += result.migrated; for (const warning of result.warnings) { const displayWarning = shortenHomePath(warning); if (warnings.includes(displayWarning)) continue; warnings.push(displayWarning); params.runtime.error(displayWarning); } } if (migrated > 0) emitNote(`Migrated and verified ${migrated} generated provider catalog${migrated === 1 ? "" : "s"} in agent SQLite.`, "Doctor changes"); return { detected: migrations.length, migrated, warnings }; } //#endregion export { maybeMigrateLegacyPluginModelCatalogs };