UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

219 lines (218 loc) • 11.7 kB
import { t as formatCliCommand } from "./command-format-DwEdrDKL.mjs"; import { c as resolveOpenClawReleaseCohortVersion } from "./npm-registry-spec-Dw2vyAJw.mjs"; import { d as resolveAgentWorkspaceDir } from "./agent-scope-config-CDYpzA0r.mjs"; import { i as listAgentIds, o as tryResolveDefaultAgentId } from "./agent-roster-BXD1uMJD.mjs"; import "./agent-scope-CG17uXFn.mjs"; import { t as note } from "./note-Byxgt4MB.mjs"; import { i as resolvePluginVersionDriftRegistryLag, o as resolvePluginVersionDriftUpdateCommand } from "./plugin-version-drift-Ctw71gC9.mjs"; import { i as buildPluginCompatibilityWarnings } from "./status-ms_HxCBN.mjs"; import { t as buildPluginRegistrySnapshotReport } from "./status-snapshot-CzfbkfgH.mjs"; //#region src/commands/doctor-workspace-status.ts const WORKSPACE_STATUS_CHECK_ID = "core/doctor/workspace-status"; function claimPluginDiagnostic(seen, diagnostic) { const key = [ diagnostic.level, diagnostic.pluginId ?? "", diagnostic.code ?? "", diagnostic.errorCode ?? "", diagnostic.source ?? "", diagnostic.message ].map((value) => `${value.length}:${value}`).join(""); if (seen.has(key)) return false; seen.add(key); return true; } function pluginVersionReadinessToHealthFindings(readiness) { if (!readiness) return []; if (readiness.status === "unresolved") return [{ checkId: WORKSPACE_STATUS_CHECK_ID, severity: "warning", message: `Could not check plugin restart readiness: ${readiness.reason}`, path: "plugins", requirement: "plugin-version-restart-readiness", fixHint: "Repair the Gateway service installation, then rerun openclaw doctor before restarting." }]; const { report: drift, runningGatewayVersion } = readiness; if (drift.drifts.length === 0) { if (!isGatewayRestartPending(drift, runningGatewayVersion)) return []; return [{ checkId: WORKSPACE_STATUS_CHECK_ID, severity: "warning", message: `Active official plugins match post-restart OpenClaw ${drift.gatewayVersion}, but the running Gateway is ${runningGatewayVersion}.`, path: "plugins", requirement: "plugin-version-gateway-restart", fixHint: formatCliCommand("openclaw gateway restart") }]; } return drift.drifts.map((entry) => { const registryLag = resolvePluginVersionDriftRegistryLag(entry); if (registryLag) return { checkId: WORKSPACE_STATUS_CHECK_ID, severity: "info", message: `Plugin ${entry.pluginId} is ${entry.installedVersion} and its registry publishes no newer release (registry version ${registryLag.registryVersion}), but a Gateway restart will load OpenClaw ${drift.gatewayVersion}.${runningGatewayVersion ? ` The running Gateway is ${runningGatewayVersion}.` : ""} No plugin update can reach ${registryLag.expectedVersion}.`, path: `plugins.entries.${entry.pluginId}`, target: entry.pluginId, requirement: "plugin-version-drift" }; const updateCommand = resolvePluginVersionDriftUpdateCommand(entry); const targetResolution = entry.targetResolution; const targetError = targetResolution?.status === "unresolved" ? targetResolution.error : "npm registry target was not resolved"; return { checkId: WORKSPACE_STATUS_CHECK_ID, severity: "warning", message: `Plugin ${entry.pluginId} is ${entry.installedVersion}, but a Gateway restart will load OpenClaw ${drift.gatewayVersion}.${targetResolution?.status === "resolved" ? ` The confirmed plugin target is ${targetResolution.version}.` : ""}${runningGatewayVersion ? ` The running Gateway is ${runningGatewayVersion}.` : ""}${updateCommand ? "" : ` Repair target resolution failed: ${targetError}.`}`, path: `plugins.entries.${entry.pluginId}`, target: entry.pluginId, requirement: "plugin-version-drift", fixHint: updateCommand ? `${formatCliCommand(updateCommand)} && ${formatCliCommand("openclaw gateway restart")}` : `No install command generated; retry openclaw doctor after checking registry availability (${targetError}).` }; }); } function isGatewayRestartPending(drift, runningGatewayVersion) { return Boolean(runningGatewayVersion && resolveOpenClawReleaseCohortVersion(runningGatewayVersion) !== resolveOpenClawReleaseCohortVersion(drift.gatewayVersion)); } function pluginCompatibilityWarningToHealthFinding(message) { return { checkId: WORKSPACE_STATUS_CHECK_ID, severity: "warning", message, path: "plugins", requirement: "plugin-compatibility", fixHint: "Update or replace the plugin so it no longer depends on legacy compatibility paths." }; } function pluginDiagnosticToHealthFinding(diagnostic, message = diagnostic.message) { return { checkId: WORKSPACE_STATUS_CHECK_ID, severity: diagnostic.level === "warn" ? "warning" : diagnostic.level, message, ...diagnostic.pluginId ? { path: `plugins.entries.${diagnostic.pluginId}`, target: diagnostic.pluginId } : {}, ...diagnostic.source ? { source: diagnostic.source } : {}, ...diagnostic.errorCode ? { errorCode: diagnostic.errorCode } : {}, requirement: diagnostic.code || "plugin-diagnostic" }; } /** Runtime failures belong to this Doctor run, independently of metadata-only inventory. */ function collectPluginLoadHealthFindings(diagnostics) { const seen = /* @__PURE__ */ new Set(); return diagnostics.filter((diagnostic) => claimPluginDiagnostic(seen, diagnostic)).map((diagnostic) => pluginDiagnosticToHealthFinding(diagnostic, `Plugin ${diagnostic.pluginId}: ${diagnostic.message}${diagnostic.errorCode ? ` [${diagnostic.errorCode}]` : ""} (${diagnostic.source})`)); } function visitWorkspacePluginStatus(cfg, options, visit) { const agentIds = listAgentIds(cfg); const scopes = agentIds.map((agentId) => ({ agentId, workspaceDir: resolveAgentWorkspaceDir(cfg, agentId) })); const reportedPluginDiagnostics = /* @__PURE__ */ new Set(); for (const { agentId, workspaceDir } of scopes) { const inspect = () => { const registry = buildPluginRegistrySnapshotReport({ config: cfg, workspaceDir }); const compatibilityWarnings = buildPluginCompatibilityWarnings({ config: cfg, workspaceDir, report: registry }); visit({ agentLabel: agentIds.length > 1 ? `Agent "${agentId}":` : "", registry, compatibilityWarnings, diagnostics: registry.diagnostics.filter((diagnostic) => claimPluginDiagnostic(reportedPluginDiagnostics, diagnostic)) }); }; if (options.runWithPluginMetadataSnapshot) options.runWithPluginMetadataSnapshot({ config: cfg, workspaceDir }, inspect); else inspect(); } return scopes; } function collectWorkspaceStatusHealthFindings(cfg, options = {}) { const workspaceFindings = []; visitWorkspacePluginStatus(cfg, options, ({ agentLabel, compatibilityWarnings, diagnostics }) => { const prefix = agentLabel ? `${agentLabel} ` : ""; workspaceFindings.push(...compatibilityWarnings.map((message) => pluginCompatibilityWarningToHealthFinding(`${prefix}${message}`)), ...diagnostics.map((diagnostic) => pluginDiagnosticToHealthFinding(diagnostic, `${prefix}${diagnostic.message}`))); }); return [...pluginVersionReadinessToHealthFindings(options.pluginVersionReadiness), ...workspaceFindings]; } function notePluginVersionReadiness(readiness) { if (!readiness) return; if (readiness.status === "unresolved") { const running = readiness.runningGatewayVersion ? `\nRunning Gateway: OpenClaw ${readiness.runningGatewayVersion}` : ""; note(`${readiness.reason}${running}\nRepair the Gateway service installation, then rerun openclaw doctor before restarting.`, "Plugin restart readiness"); return; } const drift = readiness.report; if (drift.drifts.length === 0) { if (!isGatewayRestartPending(drift, readiness.runningGatewayVersion)) return; note([ `Running Gateway: OpenClaw ${readiness.runningGatewayVersion}`, `Active official plugins match post-restart OpenClaw ${drift.gatewayVersion}.`, `Fix: ${formatCliCommand("openclaw gateway restart")}.` ].join("\n"), "Plugin restart readiness"); return; } const singleDrift = drift.drifts.length === 1 ? drift.drifts[0] : void 0; const repairs = drift.drifts.map((entry) => ({ entry, command: resolvePluginVersionDriftUpdateCommand(entry) })); const updateCommands = repairs.map(({ command }) => command).filter((command) => Boolean(command)).map((command) => formatCliCommand(command)); const registryLagRepairs = repairs.filter(({ entry }) => Boolean(resolvePluginVersionDriftRegistryLag(entry))); const unresolvedRepairs = repairs.filter(({ entry, command }) => !command && !resolvePluginVersionDriftRegistryLag(entry)); const lines = [ ...readiness.runningGatewayVersion ? [`Running Gateway: OpenClaw ${readiness.runningGatewayVersion}`] : [], `${drift.drifts.length} active official plugin${drift.drifts.length === 1 ? "" : "s"} not on post-restart OpenClaw ${drift.gatewayVersion}`, ...drift.drifts.map((entry) => { const sourceLabel = entry.source === "clawhub" ? "clawhub" : "npm"; const expectedVersion = entry.targetResolution?.status === "resolved" ? entry.targetResolution.version : drift.gatewayVersion; return `- ${entry.pluginId}: ${entry.installedVersion} (${sourceLabel}) -> expected ${expectedVersion}`; }), ...registryLagRepairs.map(({ entry }) => { const registryLag = resolvePluginVersionDriftRegistryLag(entry); return `${entry.pluginId} already holds registry version ${registryLag?.registryVersion}; no release reaches ${registryLag?.expectedVersion} yet, so no update command applies.`; }), ...unresolvedRepairs.map(({ entry }) => { const targetResolution = entry.targetResolution; const detail = targetResolution?.status === "unresolved" ? targetResolution.error : "npm registry target was not resolved"; return `Repair target resolution failed for ${entry.pluginId}: ${detail}. No install command generated.`; }), singleDrift && updateCommands.length === 1 ? `Fix: ${updateCommands[0]} && ${formatCliCommand("openclaw gateway restart")}.` : updateCommands.length > 0 ? [ "Fix each drifted plugin:", ...updateCommands.map((command) => `- ${command}`), ...unresolvedRepairs.length === 0 ? [`Then run ${formatCliCommand("openclaw gateway restart")}.`] : [] ].join("\n") : null ]; note(lines.filter((line) => Boolean(line)).join("\n"), "Plugin restart readiness"); } function noteWorkspaceStatus(cfg, options = {}) { const defaultAgentId = tryResolveDefaultAgentId(cfg); const scopes = visitWorkspacePluginStatus(cfg, options, ({ agentLabel, registry, compatibilityWarnings, diagnostics }) => { const prefix = agentLabel ? `${agentLabel}\n` : ""; const errored = registry.plugins.filter((plugin) => plugin.status === "error").toSorted((a, b) => a.id.localeCompare(b.id)); if (errored.length > 0) { const lines = [`${prefix}Errors: ${errored.length}`, `- ${errored.slice(0, 10).map((plugin) => plugin.id).join("\n- ")}${errored.length > 10 ? "\n- ..." : ""}`]; note(lines.join("\n"), "Plugins"); } if (compatibilityWarnings.length > 0) note(`${prefix}${compatibilityWarnings.map((line) => `- ${line}`).join("\n")}`, "Plugin compatibility"); if (diagnostics.length > 0) { const lines = diagnostics.map((diag) => { const level = diag.level.toUpperCase(); const plugin = diag.pluginId ? ` ${diag.pluginId}` : ""; const source = diag.source ? ` (${diag.source})` : ""; return `- ${level}${plugin}: ${diag.message}${source}`; }); note(`${prefix}${lines.join("\n")}`, "Plugin diagnostics"); } }); notePluginVersionReadiness(options.pluginVersionReadiness); return { workspaceDir: scopes.find((scope) => scope.agentId === defaultAgentId)?.workspaceDir ?? scopes[0]?.workspaceDir }; } //#endregion export { collectPluginLoadHealthFindings, collectWorkspaceStatusHealthFindings, noteWorkspaceStatus };