@ouro.bot/cli 0.1.0-alpha.714 → 0.1.0-alpha.716
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/changelog.json
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_note": "This changelog is maintained as part of the PR/version-bump workflow. Agent-curated, not auto-generated. Agents read this file directly via read_file to understand what changed between versions.",
|
|
3
3
|
"versions": [
|
|
4
|
+
{
|
|
5
|
+
"version": "0.1.0-alpha.716",
|
|
6
|
+
"changes": [
|
|
7
|
+
"Add durable MCP bridge doctor and repair guidance."
|
|
8
|
+
]
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"version": "0.1.0-alpha.715",
|
|
12
|
+
"changes": [
|
|
13
|
+
"Keep RSVP routine-specific report copy in bundle metadata while leaving harness fixtures and help generic."
|
|
14
|
+
]
|
|
15
|
+
},
|
|
4
16
|
{
|
|
5
17
|
"version": "0.1.0-alpha.714",
|
|
6
18
|
"changes": [
|
|
@@ -60,6 +60,7 @@ const diary_1 = require("../../mind/diary");
|
|
|
60
60
|
const record_paths_1 = require("../../mind/record-paths");
|
|
61
61
|
const runtime_1 = require("../../nerves/runtime");
|
|
62
62
|
const socket_client_1 = require("./socket-client");
|
|
63
|
+
const mcp_canary_1 = require("./mcp-canary");
|
|
63
64
|
/** Format diary hits the same way the search_facts tool does. */
|
|
64
65
|
function formatDiaryHits(hits) {
|
|
65
66
|
return hits.map((f) => `[diary] ${f.text} (source=${f.source}, createdAt=${f.createdAt})`);
|
|
@@ -250,7 +251,7 @@ async function readRuntimeStatus(socketPath, agent) {
|
|
|
250
251
|
};
|
|
251
252
|
}
|
|
252
253
|
}
|
|
253
|
-
function formatRuntimeStatusLines(runtime, mcpVersion) {
|
|
254
|
+
function formatRuntimeStatusLines(runtime, mcpVersion, agent) {
|
|
254
255
|
if (!runtime)
|
|
255
256
|
return mcpVersion ? [`mcpVersion=${mcpVersion}`] : [];
|
|
256
257
|
if (!runtime.daemonReachable) {
|
|
@@ -264,10 +265,16 @@ function formatRuntimeStatusLines(runtime, mcpVersion) {
|
|
|
264
265
|
const versionPart = runtime.overview.version ? `\tdaemonVersion=${runtime.overview.version}` : "";
|
|
265
266
|
const modePart = runtime.overview.mode ? `\tmode=${runtime.overview.mode}` : "";
|
|
266
267
|
const mcpVersionPart = mcpVersion ? `\tmcpVersion=${mcpVersion}` : "";
|
|
267
|
-
const
|
|
268
|
+
const hasVersionMismatch = !!(mcpVersion && runtime.overview.version && mcpVersion !== runtime.overview.version);
|
|
269
|
+
const mismatchPart = hasVersionMismatch
|
|
268
270
|
? `\tversionMismatch=mcp:${mcpVersion},daemon:${runtime.overview.version}`
|
|
269
271
|
: "";
|
|
270
272
|
lines.push(`daemon=${runtime.overview.daemon}\thealth=${runtime.overview.health}${versionPart}${modePart}${mcpVersionPart}${mismatchPart}`);
|
|
273
|
+
if (hasVersionMismatch) {
|
|
274
|
+
const repair = (0, mcp_canary_1.buildMcpBridgeRepairGuidance)(agent);
|
|
275
|
+
lines.push(`mcpRepair=${repair.actor}\tcodex=${repair.commands[0]}\tclaudeCode=${repair.commands[1]}`);
|
|
276
|
+
lines.push(`mcpReload=required\treason=${repair.reload}`);
|
|
277
|
+
}
|
|
271
278
|
}
|
|
272
279
|
for (const worker of runtime.workers) {
|
|
273
280
|
lines.push(`worker=${worker.worker}:${worker.status}`);
|
|
@@ -297,6 +304,16 @@ function formatRuntimeStatusLines(runtime, mcpVersion) {
|
|
|
297
304
|
lines.push(`mcpVersion=${mcpVersion}`);
|
|
298
305
|
return lines;
|
|
299
306
|
}
|
|
307
|
+
function summarizeMcpBridgeHealth(agent, runtime, mcpVersion) {
|
|
308
|
+
const daemonVersion = runtime?.daemonReachable ? runtime.overview?.version ?? null : null;
|
|
309
|
+
const versionMismatch = !!(mcpVersion && daemonVersion && mcpVersion !== daemonVersion);
|
|
310
|
+
return {
|
|
311
|
+
mcpVersion,
|
|
312
|
+
daemonVersion,
|
|
313
|
+
versionMismatch,
|
|
314
|
+
...(versionMismatch ? { repair: (0, mcp_canary_1.buildMcpBridgeRepairGuidance)(agent) } : {}),
|
|
315
|
+
};
|
|
316
|
+
}
|
|
300
317
|
// ─── Handlers ────────────────────────────────────────────────────────────────
|
|
301
318
|
async function handleAgentStatus(params) {
|
|
302
319
|
(0, runtime_1.emitNervesEvent)({ component: "daemon", event: "daemon.agent_service_start", message: "handling agent.status", meta: { agent: params.agent } });
|
|
@@ -316,7 +333,8 @@ async function handleAgentStatus(params) {
|
|
|
316
333
|
`sessionCount=${sessions.length}`,
|
|
317
334
|
`diaryEntries=${facts.length}`,
|
|
318
335
|
].join("\t");
|
|
319
|
-
const runtimeLines = formatRuntimeStatusLines(runtime, mcpVersion);
|
|
336
|
+
const runtimeLines = formatRuntimeStatusLines(runtime, mcpVersion, params.agent);
|
|
337
|
+
const mcpHealth = summarizeMcpBridgeHealth(params.agent, runtime, mcpVersion);
|
|
320
338
|
const message = [agentLine, ...runtimeLines].join("\n");
|
|
321
339
|
return {
|
|
322
340
|
ok: true,
|
|
@@ -330,6 +348,7 @@ async function handleAgentStatus(params) {
|
|
|
330
348
|
factCount: facts.length,
|
|
331
349
|
runtime,
|
|
332
350
|
mcpVersion,
|
|
351
|
+
mcpHealth,
|
|
333
352
|
},
|
|
334
353
|
};
|
|
335
354
|
}
|
|
@@ -125,6 +125,10 @@ const DEFAULT_DAEMON_STARTUP_TIMEOUT_MS = 60_000;
|
|
|
125
125
|
const DEFAULT_DAEMON_STARTUP_POLL_INTERVAL_MS = 500;
|
|
126
126
|
const DEFAULT_DAEMON_STARTUP_STABILITY_WINDOW_MS = 1_500;
|
|
127
127
|
const DEFAULT_DAEMON_STARTUP_RETRY_LIMIT = 1;
|
|
128
|
+
function setupReloadNotice(tool) {
|
|
129
|
+
const host = tool === "codex" ? "Codex" : "Claude Code";
|
|
130
|
+
return ` reload required: open a fresh ${host} session so the host launches the newly registered MCP bridge; existing MCP processes keep their old runtime`;
|
|
131
|
+
}
|
|
128
132
|
const DEFAULT_DAEMON_STARTUP_LOG_LINES = 10;
|
|
129
133
|
const RSVP_CLI_KINDS = new Set([
|
|
130
134
|
"rsvp.doctor",
|
|
@@ -6940,7 +6944,7 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
6940
6944
|
if (!existingClaudeMd.includes("Agent conversations (ouro)")) {
|
|
6941
6945
|
fs.writeFileSync(claudeMdPath, existingClaudeMd + agentInstructions);
|
|
6942
6946
|
}
|
|
6943
|
-
const message = `setup complete: claude-code + ${setupAgent}\n MCP server registered\n hooks configured\n conversation formatting instructions added`;
|
|
6947
|
+
const message = `setup complete: claude-code + ${setupAgent}\n MCP server registered\n hooks configured\n conversation formatting instructions added\n${setupReloadNotice("claude-code")}`;
|
|
6944
6948
|
deps.writeStdout(message);
|
|
6945
6949
|
return message;
|
|
6946
6950
|
}
|
|
@@ -6954,7 +6958,7 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
6954
6958
|
message: "dev tool setup complete",
|
|
6955
6959
|
meta: { tool, agent: setupAgent, runtimeMode, platform },
|
|
6956
6960
|
});
|
|
6957
|
-
const message = `setup complete: codex + ${setupAgent}\n MCP server registered`;
|
|
6961
|
+
const message = `setup complete: codex + ${setupAgent}\n MCP server registered\n${setupReloadNotice("codex")}`;
|
|
6958
6962
|
deps.writeStdout(message);
|
|
6959
6963
|
return message;
|
|
6960
6964
|
}
|
|
@@ -6981,6 +6985,32 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
6981
6985
|
deps.writeStdout(message);
|
|
6982
6986
|
return message;
|
|
6983
6987
|
}
|
|
6988
|
+
if (command.kind === "mcp.doctor") {
|
|
6989
|
+
const canarySocketPath = command.socketOverride ?? deps.socketPath;
|
|
6990
|
+
const result = await (0, mcp_canary_1.runMcpStatusCanary)({
|
|
6991
|
+
agent: command.agent,
|
|
6992
|
+
socketPath: canarySocketPath,
|
|
6993
|
+
command: process.execPath,
|
|
6994
|
+
commandArgs: [
|
|
6995
|
+
path.join(__dirname, "ouro-bot-entry.js"),
|
|
6996
|
+
"mcp-serve",
|
|
6997
|
+
"--agent",
|
|
6998
|
+
command.agent,
|
|
6999
|
+
"--socket",
|
|
7000
|
+
canarySocketPath,
|
|
7001
|
+
],
|
|
7002
|
+
});
|
|
7003
|
+
if (!result.ok)
|
|
7004
|
+
deps.setExitCode?.(1);
|
|
7005
|
+
const jsonPayload = result.ok || result.repair
|
|
7006
|
+
? { ...result, repair: result.repair ?? (0, mcp_canary_1.buildMcpBridgeRepairGuidance)(command.agent) }
|
|
7007
|
+
: { ...result, nextSteps: (0, mcp_canary_1.buildMcpDoctorNextSteps)(result, command.agent) };
|
|
7008
|
+
const message = command.json
|
|
7009
|
+
? JSON.stringify(jsonPayload, null, 2)
|
|
7010
|
+
: (0, mcp_canary_1.formatMcpStatusDoctorResult)(result, command.agent);
|
|
7011
|
+
deps.writeStdout(message);
|
|
7012
|
+
return message;
|
|
7013
|
+
}
|
|
6984
7014
|
/* v8 ignore start — mcp-serve block binds to process.stdin/stdout; tested via mcp-server unit tests */
|
|
6985
7015
|
// ── mcp-serve: start MCP server in-process on stdin/stdout ──
|
|
6986
7016
|
if (command.kind === "mcp-serve") {
|
|
@@ -148,7 +148,7 @@ exports.COMMAND_REGISTRY = {
|
|
|
148
148
|
category: "Habits",
|
|
149
149
|
description: "AislePlanner-backed RSVP habit operations, triage, receipts, ledgers, migration checks, refreshes, and smoke tests",
|
|
150
150
|
usage: "ouro rsvp <doctor|incident|cutover|legacy-render|replay|config|habit|import-legacy|refresh|compare|smoke> ...",
|
|
151
|
-
example: "ouro rsvp doctor --agent
|
|
151
|
+
example: "ouro rsvp doctor --agent rsvp-agent --json",
|
|
152
152
|
subcommands: [
|
|
153
153
|
"doctor",
|
|
154
154
|
"incident",
|
|
@@ -335,8 +335,8 @@ exports.COMMAND_REGISTRY = {
|
|
|
335
335
|
category: "System",
|
|
336
336
|
description: "Interact with MCP servers",
|
|
337
337
|
usage: "ouro mcp <subcommand>",
|
|
338
|
-
example: "ouro mcp
|
|
339
|
-
subcommands: ["list", "call", "canary"],
|
|
338
|
+
example: "ouro mcp doctor --agent ouroboros",
|
|
339
|
+
subcommands: ["list", "call", "canary", "doctor"],
|
|
340
340
|
},
|
|
341
341
|
"mcp-serve": {
|
|
342
342
|
category: "System",
|
|
@@ -456,12 +456,12 @@ const SUBCOMMAND_HELP = {
|
|
|
456
456
|
"rsvp doctor": {
|
|
457
457
|
description: "Check native RSVP configuration, credentials, BlueBubbles attachment, ledgers, receipts, and migration readiness without sending messages; use --json --strict in triage",
|
|
458
458
|
usage: "ouro rsvp doctor [--agent <name>] [--strict] [--output <path>] [--json]",
|
|
459
|
-
example: "ouro rsvp doctor --agent
|
|
459
|
+
example: "ouro rsvp doctor --agent rsvp-agent --strict --json",
|
|
460
460
|
},
|
|
461
461
|
"rsvp incident": {
|
|
462
462
|
description: "Collect a redacted local RSVP diagnostic incident bundle with doctor status, receipts, and ledger pointers without contacting the daemon",
|
|
463
463
|
usage: "ouro rsvp incident [--agent <name>] [--output <path>] [--json]",
|
|
464
|
-
example: "ouro rsvp incident --agent
|
|
464
|
+
example: "ouro rsvp incident --agent rsvp-agent --output /tmp/rsvp-incident.json",
|
|
465
465
|
},
|
|
466
466
|
"rsvp cutover": {
|
|
467
467
|
description: "Inspect or retire legacy RSVP sender state before native live send",
|
|
@@ -486,7 +486,7 @@ const SUBCOMMAND_HELP = {
|
|
|
486
486
|
"rsvp habit stage": {
|
|
487
487
|
description: "Stage an RSVP refresh habit with bundle-owned routine naming and report copy",
|
|
488
488
|
usage: "ouro rsvp habit stage [--agent <name>] [--name <rsvp-name>] [--title <title>] [--report-title <title>] --mode shadow|live --cadence '<cron>' [--output <path>] [--json]",
|
|
489
|
-
example: "ouro rsvp habit stage --agent rsvp-agent --name rsvp-
|
|
489
|
+
example: "ouro rsvp habit stage --agent rsvp-agent --name rsvp-updates --title 'RSVP Updates' --mode shadow --cadence '0 10 * * *'",
|
|
490
490
|
},
|
|
491
491
|
"rsvp import-legacy": {
|
|
492
492
|
description: "Compatibility alias for `ouro rsvp config import-legacy`; mutates only with --yes",
|
|
@@ -496,17 +496,17 @@ const SUBCOMMAND_HELP = {
|
|
|
496
496
|
"rsvp refresh": {
|
|
497
497
|
description: "Run the native RSVP refresh path and write receipts; defaults to dry-run behavior unless --allow-send is explicit",
|
|
498
498
|
usage: "ouro rsvp refresh [--agent <name>] [--habit <rsvp-name>] --mode shadow|live [--no-send|--allow-send] [--output <path>] [--json]",
|
|
499
|
-
example: "ouro rsvp refresh --agent rsvp-agent --habit rsvp-
|
|
499
|
+
example: "ouro rsvp refresh --agent rsvp-agent --habit rsvp-updates --mode shadow --no-send --json",
|
|
500
500
|
},
|
|
501
501
|
"rsvp compare": {
|
|
502
502
|
description: "Compare native and legacy RSVP render outputs for migration verification",
|
|
503
503
|
usage: "ouro rsvp compare [--agent <name>] --native <path> --legacy <path> [--output <path>] [--json]",
|
|
504
|
-
example: "ouro rsvp compare --agent
|
|
504
|
+
example: "ouro rsvp compare --agent rsvp-agent --native /tmp/native.json --legacy /tmp/legacy.json",
|
|
505
505
|
},
|
|
506
506
|
"rsvp smoke": {
|
|
507
507
|
description: "Smoke-test RSVP follow-up behavior through a target sense; preflight is no-send and live mode requires --allow-send",
|
|
508
508
|
usage: "ouro rsvp smoke [--agent <name>] --mode preflight|live --surface bluebubbles [--question <text>] [--allow-send] [--output <path>] [--replay-output <path>] [--json]",
|
|
509
|
-
example: "ouro rsvp smoke --agent
|
|
509
|
+
example: "ouro rsvp smoke --agent rsvp-agent --mode preflight --surface bluebubbles --question 'who is pending?'",
|
|
510
510
|
},
|
|
511
511
|
"mail import-mbox": {
|
|
512
512
|
description: "Import a HEY or other MBOX export into an existing delegated Mailroom source grant",
|
|
@@ -134,6 +134,7 @@ function usage() {
|
|
|
134
134
|
" ouro session list [--agent <name>]",
|
|
135
135
|
" ouro mcp list",
|
|
136
136
|
" ouro mcp call <server> <tool> [--args '{...}']",
|
|
137
|
+
" ouro mcp doctor --agent <name> [--json]",
|
|
137
138
|
" ouro rollback [<version>]",
|
|
138
139
|
" ouro versions",
|
|
139
140
|
" ouro clone <remote> [--agent <name>]",
|
|
@@ -1458,6 +1459,31 @@ function parseMcpCommand(args) {
|
|
|
1458
1459
|
...(json ? { json: true } : {}),
|
|
1459
1460
|
};
|
|
1460
1461
|
}
|
|
1462
|
+
if (sub === "doctor") {
|
|
1463
|
+
let socketOverride;
|
|
1464
|
+
let json = false;
|
|
1465
|
+
for (let i = 0; i < rest.length; i++) {
|
|
1466
|
+
if (rest[i] === "--socket") {
|
|
1467
|
+
if (!rest[i + 1])
|
|
1468
|
+
throw new Error("mcp doctor requires a value after --socket");
|
|
1469
|
+
socketOverride = rest[++i];
|
|
1470
|
+
continue;
|
|
1471
|
+
}
|
|
1472
|
+
if (rest[i] === "--json") {
|
|
1473
|
+
json = true;
|
|
1474
|
+
continue;
|
|
1475
|
+
}
|
|
1476
|
+
throw new Error(`Unknown mcp doctor flag: ${rest[i]}`);
|
|
1477
|
+
}
|
|
1478
|
+
if (!agent)
|
|
1479
|
+
throw new Error("mcp doctor requires --agent <name>");
|
|
1480
|
+
return {
|
|
1481
|
+
kind: "mcp.doctor",
|
|
1482
|
+
agent,
|
|
1483
|
+
...(socketOverride ? { socketOverride } : {}),
|
|
1484
|
+
...(json ? { json: true } : {}),
|
|
1485
|
+
};
|
|
1486
|
+
}
|
|
1461
1487
|
throw new Error(`Usage\n${usage()}`);
|
|
1462
1488
|
}
|
|
1463
1489
|
function inferAgentNameFromRemote(remote) {
|
|
@@ -33,9 +33,14 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.buildMcpBridgeRepairGuidance = buildMcpBridgeRepairGuidance;
|
|
37
|
+
exports.formatMcpBridgeRepairDetails = formatMcpBridgeRepairDetails;
|
|
38
|
+
exports.buildMcpDoctorNextSteps = buildMcpDoctorNextSteps;
|
|
39
|
+
exports.formatMcpDoctorNextStepDetails = formatMcpDoctorNextStepDetails;
|
|
36
40
|
exports.parseMcpStatusText = parseMcpStatusText;
|
|
37
41
|
exports.runMcpStatusCanary = runMcpStatusCanary;
|
|
38
42
|
exports.formatMcpStatusCanaryResult = formatMcpStatusCanaryResult;
|
|
43
|
+
exports.formatMcpStatusDoctorResult = formatMcpStatusDoctorResult;
|
|
39
44
|
exports.createMcpStatusCanaryProbe = createMcpStatusCanaryProbe;
|
|
40
45
|
const child_process_1 = require("child_process");
|
|
41
46
|
const path = __importStar(require("path"));
|
|
@@ -75,6 +80,65 @@ function parseFields(line) {
|
|
|
75
80
|
}
|
|
76
81
|
return parsed;
|
|
77
82
|
}
|
|
83
|
+
function shellArg(value) {
|
|
84
|
+
return /^[A-Za-z0-9._/-]+$/.test(value)
|
|
85
|
+
? value
|
|
86
|
+
: `'${value.replace(/'/g, "'\\''")}'`;
|
|
87
|
+
}
|
|
88
|
+
function buildMcpBridgeRepairGuidance(agent) {
|
|
89
|
+
const agentArg = shellArg(agent);
|
|
90
|
+
return {
|
|
91
|
+
actor: "agent-runnable",
|
|
92
|
+
commands: [
|
|
93
|
+
`ouro setup --tool codex --agent ${agentArg}`,
|
|
94
|
+
`ouro setup --tool claude-code --agent ${agentArg}`,
|
|
95
|
+
],
|
|
96
|
+
reload: "open a fresh dev-tool session after setup; existing MCP processes keep their old runtime",
|
|
97
|
+
verify: `ouro mcp doctor --agent ${agentArg}`,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function formatMcpBridgeRepairDetails(repair) {
|
|
101
|
+
return [
|
|
102
|
+
`repair actor=${repair.actor}`,
|
|
103
|
+
...repair.commands.map((command) => `repair command=${command}`),
|
|
104
|
+
`reload required: ${repair.reload}`,
|
|
105
|
+
`verify command=${repair.verify}`,
|
|
106
|
+
];
|
|
107
|
+
}
|
|
108
|
+
function buildMcpDoctorNextSteps(result, agent) {
|
|
109
|
+
const agentArg = shellArg(agent);
|
|
110
|
+
const text = [result.summary, ...result.details].join("\n");
|
|
111
|
+
const daemonUnreachable = text.includes("daemon=unreachable")
|
|
112
|
+
|| text.includes("ECONNREFUSED")
|
|
113
|
+
|| text.includes("ENOENT");
|
|
114
|
+
if (daemonUnreachable) {
|
|
115
|
+
return {
|
|
116
|
+
actor: "agent-runnable",
|
|
117
|
+
commands: [
|
|
118
|
+
"ouro up",
|
|
119
|
+
`ouro mcp doctor --agent ${agentArg}`,
|
|
120
|
+
],
|
|
121
|
+
note: "start or refresh the daemon before trusting bridge status",
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
return {
|
|
125
|
+
actor: "agent-runnable",
|
|
126
|
+
commands: [
|
|
127
|
+
"ouro doctor",
|
|
128
|
+
`ouro status --agent ${agentArg}`,
|
|
129
|
+
`ouro repair --agent ${agentArg}`,
|
|
130
|
+
`ouro mcp doctor --agent ${agentArg}`,
|
|
131
|
+
],
|
|
132
|
+
note: "fix reported daemon or sense health before rerunning bridge registration repair",
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
function formatMcpDoctorNextStepDetails(nextSteps) {
|
|
136
|
+
return [
|
|
137
|
+
`next actor=${nextSteps.actor}`,
|
|
138
|
+
...nextSteps.commands.map((command) => `next command=${command}`),
|
|
139
|
+
`next note=${nextSteps.note}`,
|
|
140
|
+
];
|
|
141
|
+
}
|
|
78
142
|
function parseMcpStatusText(text) {
|
|
79
143
|
const daemon = {};
|
|
80
144
|
const senses = {};
|
|
@@ -105,9 +169,10 @@ function validateMcpStatus(parsed, requiredSenses, options = {}) {
|
|
|
105
169
|
if (!options.ignoreOverviewHealth && parsed.daemon.health !== "ok") {
|
|
106
170
|
failures.push(`health=${parsed.daemon.health ?? "missing"}`);
|
|
107
171
|
}
|
|
108
|
-
|
|
172
|
+
const hasVersionMismatch = !!(parsed.daemon.daemonVersion &&
|
|
109
173
|
parsed.daemon.mcpVersion &&
|
|
110
|
-
parsed.daemon.daemonVersion !== parsed.daemon.mcpVersion)
|
|
174
|
+
parsed.daemon.daemonVersion !== parsed.daemon.mcpVersion);
|
|
175
|
+
if (hasVersionMismatch) {
|
|
111
176
|
failures.push(`version mismatch daemon=${parsed.daemon.daemonVersion} mcp=${parsed.daemon.mcpVersion}`);
|
|
112
177
|
}
|
|
113
178
|
for (const [sense, row] of Object.entries(parsed.senses)) {
|
|
@@ -133,11 +198,16 @@ function validateMcpStatus(parsed, requiredSenses, options = {}) {
|
|
|
133
198
|
const summary = failures.length === 0
|
|
134
199
|
? `mcp canary ok: daemon=${parsed.daemon.daemon} health=${parsed.daemon.health}${options.ignoreOverviewHealth ? " (overview ignored)" : ""} senses=${senseSummary}`
|
|
135
200
|
: `mcp canary failed: ${failures.join("; ")}`;
|
|
201
|
+
const repair = hasVersionMismatch && options.agent
|
|
202
|
+
? buildMcpBridgeRepairGuidance(options.agent)
|
|
203
|
+
: undefined;
|
|
204
|
+
const repairDetails = repair ? formatMcpBridgeRepairDetails(repair) : [];
|
|
136
205
|
return {
|
|
137
206
|
ok: failures.length === 0,
|
|
138
207
|
summary,
|
|
139
|
-
details: failures.length === 0 ? [parsed.raw] : [...failures, parsed.raw],
|
|
208
|
+
details: failures.length === 0 ? [parsed.raw] : [...failures, ...repairDetails, parsed.raw],
|
|
140
209
|
parsed,
|
|
210
|
+
...(repair ? { repair } : {}),
|
|
141
211
|
};
|
|
142
212
|
}
|
|
143
213
|
async function runMcpStatusCanary(options) {
|
|
@@ -252,6 +322,7 @@ async function runMcpStatusCanary(options) {
|
|
|
252
322
|
}
|
|
253
323
|
const parsed = parseMcpStatusText(responseText(statusResponse));
|
|
254
324
|
const canary = validateMcpStatus(parsed, requiredSenses, {
|
|
325
|
+
agent: options.agent,
|
|
255
326
|
ignoreOverviewHealth: options.ignoreOverviewHealth,
|
|
256
327
|
});
|
|
257
328
|
(0, runtime_1.emitNervesEvent)({
|
|
@@ -286,6 +357,26 @@ function formatMcpStatusCanaryResult(result) {
|
|
|
286
357
|
...result.details.map((line) => ` ${line}`),
|
|
287
358
|
].join("\n");
|
|
288
359
|
}
|
|
360
|
+
function formatMcpStatusDoctorResult(result, agent) {
|
|
361
|
+
const rawDetails = result.details.filter((line) => !line.startsWith("repair ")
|
|
362
|
+
&& !line.startsWith("reload required:")
|
|
363
|
+
&& !line.startsWith("verify command="));
|
|
364
|
+
const lines = [
|
|
365
|
+
result.ok ? "mcp doctor: ok" : "mcp doctor: failed",
|
|
366
|
+
result.summary,
|
|
367
|
+
...rawDetails.map((line) => ` ${line}`),
|
|
368
|
+
];
|
|
369
|
+
if (result.ok || result.repair) {
|
|
370
|
+
const repair = result.repair ?? buildMcpBridgeRepairGuidance(agent);
|
|
371
|
+
lines.push("bridge registration path:");
|
|
372
|
+
lines.push(...formatMcpBridgeRepairDetails(repair).map((line) => ` ${line}`));
|
|
373
|
+
}
|
|
374
|
+
else {
|
|
375
|
+
lines.push("next checks:");
|
|
376
|
+
lines.push(...formatMcpDoctorNextStepDetails(buildMcpDoctorNextSteps(result, agent)).map((line) => ` ${line}`));
|
|
377
|
+
}
|
|
378
|
+
return lines.join("\n");
|
|
379
|
+
}
|
|
289
380
|
function createMcpStatusCanaryProbe(options) {
|
|
290
381
|
return {
|
|
291
382
|
name: `mcp-canary:${options.agent}`,
|