openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
93 lines (92 loc) • 5.5 kB
JavaScript
import { t as formatCliCommand } from "./command-format-CKGmlpAQ.js";
import "./agent-scope-MrLta7Pq.js";
import { c as resolveDefaultAgentId, o as resolveAgentWorkspaceDir } from "./agent-scope-config-CgCYpZfK.js";
import { I as listTaskFlowRecords, m as listTasksForFlowId } from "./task-registry-FH-Ti23C.js";
import "./runtime-internal-DmbNZJaP.js";
import { t as buildWorkspaceSkillStatus } from "./status-Dlj2eT9o.js";
import { t as note } from "./note-BRSJp0UF.js";
import { i as buildPluginCompatibilityWarnings } from "./status-TB29O9XH.js";
import { t as buildPluginRegistrySnapshotReport } from "./status-snapshot-DfN6qhDb.js";
import { i as formatLegacyWorkspaceWarning, n as detectLegacyWorkspaceDirs } from "./doctor-workspace-Bb0DQcvv.js";
//#region src/commands/doctor-workspace-status.ts
/** Doctor status summary for workspace skills, plugins, and task-flow recovery hints. */
function noteFlowRecoveryHints() {
const suspicious = listTaskFlowRecords().flatMap((flow) => {
const tasks = listTasksForFlowId(flow.flowId);
const findings = [];
if (flow.syncMode === "managed" && flow.status === "running" && tasks.length === 0 && flow.waitJson === void 0) findings.push(`${flow.flowId}: running managed TaskFlow has no linked tasks or wait state; inspect or cancel it manually.`);
if (flow.status === "blocked" && flow.blockedTaskId && !tasks.some((task) => task.taskId === flow.blockedTaskId)) findings.push(`${flow.flowId}: blocked TaskFlow points at missing task ${flow.blockedTaskId}; inspect before retrying.`);
return findings;
});
if (suspicious.length === 0) return;
note([
...suspicious.slice(0, 5),
suspicious.length > 5 ? `...and ${suspicious.length - 5} more.` : null,
`Inspect: ${formatCliCommand("openclaw tasks flow show <flow-id>")}`,
`Cancel: ${formatCliCommand("openclaw tasks flow cancel <flow-id>")}`
].filter((line) => Boolean(line)).join("\n"), "TaskFlow recovery");
}
function notePluginVersionDrift(drift) {
if (!drift || drift.drifts.length === 0) return;
const singleDrift = drift.drifts.length === 1 ? drift.drifts[0] : void 0;
note([
`${drift.drifts.length} active official plugin${drift.drifts.length === 1 ? "" : "s"} not on OpenClaw ${drift.gatewayVersion}`,
...drift.drifts.map((entry) => {
const sourceLabel = entry.source === "clawhub" ? "clawhub" : "npm";
return `- ${entry.pluginId}: ${entry.installedVersion} (${sourceLabel}) -> expected ${drift.gatewayVersion}`;
}),
singleDrift ? `Fix: ${formatCliCommand(`openclaw plugins update ${singleDrift.pluginId}`)} && ${formatCliCommand("openclaw gateway restart")}.` : `Fix: ${formatCliCommand("openclaw plugins update <plugin-id>")} for each drifted plugin, then ${formatCliCommand("openclaw gateway restart")}.`
].join("\n"), "Plugin version drift");
}
/** Emits workspace, skills, plugin, and TaskFlow recovery status notes for doctor. */
function noteWorkspaceStatus(cfg, options = {}) {
const workspaceDir = resolveAgentWorkspaceDir(cfg, resolveDefaultAgentId(cfg));
const legacyWorkspace = detectLegacyWorkspaceDirs({ workspaceDir });
if (legacyWorkspace.legacyDirs.length > 0) note(formatLegacyWorkspaceWarning(legacyWorkspace), "Extra workspace");
const skillsReport = buildWorkspaceSkillStatus(workspaceDir, { config: cfg });
note([
`Eligible: ${skillsReport.skills.filter((s) => s.eligible).length}`,
`Missing requirements: ${skillsReport.skills.filter((s) => !s.eligible && !s.disabled && !s.blockedByAllowlist).length}`,
`Blocked by allowlist: ${skillsReport.skills.filter((s) => s.blockedByAllowlist).length}`
].join("\n"), "Skills status");
const pluginRegistry = buildPluginRegistrySnapshotReport({
config: cfg,
workspaceDir
});
if (pluginRegistry.plugins.length > 0) {
const loaded = pluginRegistry.plugins.filter((p) => p.status === "loaded");
const disabled = pluginRegistry.plugins.filter((p) => p.status === "disabled");
const errored = pluginRegistry.plugins.filter((p) => p.status === "error");
const imported = pluginRegistry.plugins.filter((p) => p.imported);
const lines = [
`Loaded: ${loaded.length}`,
`Imported: ${imported.length}`,
`Disabled: ${disabled.length}`,
`Errors: ${errored.length}`,
errored.length > 0 ? `- ${errored.slice(0, 10).map((p) => p.id).join("\n- ")}${errored.length > 10 ? "\n- ..." : ""}` : null
].filter((line) => Boolean(line));
const bundlePlugins = loaded.filter((p) => p.format === "bundle" && (p.bundleCapabilities?.length ?? 0) > 0);
if (bundlePlugins.length > 0) {
const allCaps = new Set(bundlePlugins.flatMap((p) => p.bundleCapabilities ?? []));
lines.push(`Bundle plugins: ${bundlePlugins.length} (${[...allCaps].toSorted().join(", ")})`);
}
note(lines.join("\n"), "Plugins");
}
notePluginVersionDrift(options.pluginVersionDrift);
const compatibilityWarnings = buildPluginCompatibilityWarnings({
config: cfg,
workspaceDir,
report: pluginRegistry
});
if (compatibilityWarnings.length > 0) note(compatibilityWarnings.map((line) => `- ${line}`).join("\n"), "Plugin compatibility");
if (pluginRegistry.diagnostics.length > 0) note(pluginRegistry.diagnostics.map((diag) => {
const prefix = diag.level.toUpperCase();
const plugin = diag.pluginId ? ` ${diag.pluginId}` : "";
const source = diag.source ? ` (${diag.source})` : "";
return `- ${prefix}${plugin}: ${diag.message}${source}`;
}).join("\n"), "Plugin diagnostics");
noteFlowRecoveryHints();
return { workspaceDir };
}
//#endregion
export { noteWorkspaceStatus };