@adhdev/daemon-standalone 0.9.82-rc.209 → 0.9.82-rc.210
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/dist/index.js +5865 -3679
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/public/assets/index-DBlsL5MS.css +1 -0
- package/public/assets/index-fge7gXie.js +112 -0
- package/public/index.html +2 -2
- package/vendor/mcp-server/index.js +174 -13
- package/vendor/mcp-server/index.js.map +1 -1
- package/public/assets/index-BxT7AHR9.css +0 -1
- package/public/assets/index-CtWWaEgh.js +0 -112
package/public/index.html
CHANGED
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
<meta name="description" content="ADHDev self-hosted dashboard for controlling AI agents" />
|
|
8
8
|
<link rel="icon" href="/otter-logo.png" />
|
|
9
9
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet" />
|
|
10
|
-
<script type="module" crossorigin src="/assets/index-
|
|
10
|
+
<script type="module" crossorigin src="/assets/index-fge7gXie.js"></script>
|
|
11
11
|
<link rel="modulepreload" crossorigin href="/assets/vendor-BwuWgaJI.js">
|
|
12
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
12
|
+
<link rel="stylesheet" crossorigin href="/assets/index-DBlsL5MS.css">
|
|
13
13
|
</head>
|
|
14
14
|
<body>
|
|
15
15
|
<!-- Apply theme immediately to prevent FOIT (Flash of Incorrect Theme) -->
|
|
@@ -248,6 +248,30 @@ function isCoordinatorVisibleMessage(message) {
|
|
|
248
248
|
if (meta?.internal === true || meta?.debug === true || meta?.control === true || meta?.userVisible === false || meta?.user_visible === false) return false;
|
|
249
249
|
return role === "user" || role === "assistant" || role === "agent";
|
|
250
250
|
}
|
|
251
|
+
function summarizeToolMessage(message) {
|
|
252
|
+
if (!message || typeof message !== "object") return null;
|
|
253
|
+
const kind = String(message.kind ?? message.type ?? message.messageKind ?? "").toLowerCase();
|
|
254
|
+
const role = String(message.role ?? "").toLowerCase();
|
|
255
|
+
if (kind === "terminal" || kind === "bash") {
|
|
256
|
+
const cmd = message.command ?? message.cmd ?? message.input ?? messageContent(message);
|
|
257
|
+
const exit = message.exitCode ?? message.exit_code ?? message.code;
|
|
258
|
+
const cmdShort = typeof cmd === "string" ? cmd.split("\n")[0].slice(0, 120) : null;
|
|
259
|
+
if (!cmdShort) return null;
|
|
260
|
+
return exit !== void 0 && exit !== null ? `[Bash] ${cmdShort} \u2192 exit ${exit}` : `[Bash] ${cmdShort}`;
|
|
261
|
+
}
|
|
262
|
+
if (kind === "tool_call" || kind === "tool" || role === "tool") {
|
|
263
|
+
const name = message.name ?? message.toolName ?? message.tool_name ?? message.function?.name;
|
|
264
|
+
if (typeof name === "string" && name.trim()) return `[Tool] ${name.trim()}`;
|
|
265
|
+
return null;
|
|
266
|
+
}
|
|
267
|
+
if (kind === "tool_result") {
|
|
268
|
+
const exit = message.exitCode ?? message.exit_code ?? message.code;
|
|
269
|
+
const name = message.name ?? message.toolName ?? message.tool_name;
|
|
270
|
+
const label = typeof name === "string" && name.trim() ? name.trim() : "tool";
|
|
271
|
+
return exit !== void 0 && exit !== null ? `[Tool result: ${label}] exit ${exit}` : null;
|
|
272
|
+
}
|
|
273
|
+
return null;
|
|
274
|
+
}
|
|
251
275
|
function buildCompactMessageTail(visibleMessages, opts) {
|
|
252
276
|
return visibleMessages.slice(-opts.limit);
|
|
253
277
|
}
|
|
@@ -261,6 +285,9 @@ function compactChatPayload(payload, opts = {}) {
|
|
|
261
285
|
});
|
|
262
286
|
const summary = typeof payload?.summary === "string" && payload.summary.trim() ? payload.summary.trim() : messageContent(finalAssistant).trim();
|
|
263
287
|
const messages = buildCompactMessageTail(visible, { summary, finalAssistant, limit });
|
|
288
|
+
const toolSummaries = rawMessages.filter((m) => !isCoordinatorVisibleMessage(m)).map(summarizeToolMessage).filter((s) => s !== null);
|
|
289
|
+
const omittedMessages = Math.max(0, rawMessages.length - messages.length);
|
|
290
|
+
const filteredMessages = Math.max(0, rawMessages.length - visible.length);
|
|
264
291
|
return {
|
|
265
292
|
success: payload?.success !== false,
|
|
266
293
|
compact: true,
|
|
@@ -270,8 +297,9 @@ function compactChatPayload(payload, opts = {}) {
|
|
|
270
297
|
providerSessionId: payload?.providerSessionId ?? null,
|
|
271
298
|
totalMessages: rawMessages.length,
|
|
272
299
|
visibleMessages: visible.length,
|
|
273
|
-
filteredMessages
|
|
274
|
-
omittedMessages
|
|
300
|
+
filteredMessages,
|
|
301
|
+
omittedMessages,
|
|
302
|
+
...toolSummaries.length > 0 ? { toolSummaries } : {},
|
|
275
303
|
summary,
|
|
276
304
|
...payload?.changedFiles !== void 0 ? { changedFiles: payload.changedFiles } : {},
|
|
277
305
|
...payload?.testsRun !== void 0 ? { testsRun: payload.testsRun } : {},
|
|
@@ -1608,9 +1636,21 @@ function getNodeLaunchReadiness(node) {
|
|
|
1608
1636
|
launchBlockedMessage: missingProviderPriorityMessage(node.id)
|
|
1609
1637
|
};
|
|
1610
1638
|
}
|
|
1611
|
-
function getWorktreeBootstrapLaunchBlock(node) {
|
|
1639
|
+
function getWorktreeBootstrapLaunchBlock(node, meshPolicy) {
|
|
1640
|
+
if (!node.isLocalWorktree) return void 0;
|
|
1612
1641
|
const bootstrap = node.worktreeBootstrap;
|
|
1613
|
-
|
|
1642
|
+
const requireReady = !!(meshPolicy && typeof meshPolicy === "object" && meshPolicy.requireBootstrapBeforeLaunch === true);
|
|
1643
|
+
if (requireReady && bootstrap?.status !== "ready") {
|
|
1644
|
+
return {
|
|
1645
|
+
success: false,
|
|
1646
|
+
code: "bootstrap_not_ready",
|
|
1647
|
+
error: `Node '${node.id}' bootstrap state is '${bootstrap?.status ?? "unknown"}' and mesh policy requireBootstrapBeforeLaunch is enabled.`,
|
|
1648
|
+
nodeId: node.id,
|
|
1649
|
+
worktreeBootstrap: bootstrap ?? null,
|
|
1650
|
+
recoveryHint: "Run the worktree bootstrap (clone runOnClone or a refine with bootstrap inherit) until the node reports ready, or disable requireBootstrapBeforeLaunch."
|
|
1651
|
+
};
|
|
1652
|
+
}
|
|
1653
|
+
if (bootstrap?.status !== "failed" || bootstrap?.required === false) return void 0;
|
|
1614
1654
|
return {
|
|
1615
1655
|
success: false,
|
|
1616
1656
|
code: "worktree_bootstrap_failed",
|
|
@@ -1898,7 +1938,11 @@ var MESH_ENQUEUE_TASK_TOOL = {
|
|
|
1898
1938
|
task_mode: { type: "string", enum: ["code_change", "validation", "live_debug_readonly", "launch_app", "convergence"], description: "Optional task-mode contract. live_debug_readonly rejects obvious write/commit/push/deploy/destructive instructions before dispatch." },
|
|
1899
1939
|
taskMode: { type: "string", enum: ["code_change", "validation", "live_debug_readonly", "launch_app", "convergence"], description: "CamelCase alias for task_mode." },
|
|
1900
1940
|
requiredTags: { type: "array", items: { type: "string" }, description: "Optional capability tags that every eligible node must have, e.g. os=darwin, provider=codex-cli, gpu." },
|
|
1901
|
-
required_tags: { type: "array", items: { type: "string" }, description: "Snake_case alias for requiredTags." }
|
|
1941
|
+
required_tags: { type: "array", items: { type: "string" }, description: "Snake_case alias for requiredTags." },
|
|
1942
|
+
depends_on: { type: "array", items: { type: "string" }, description: "Task ids that must complete before this task becomes claimable. Cycles are rejected at enqueue." },
|
|
1943
|
+
dependsOn: { type: "array", items: { type: "string" }, description: "CamelCase alias for depends_on." },
|
|
1944
|
+
mission_id: { type: "string", description: "Mission this task belongs to (mesh_mission record id)." },
|
|
1945
|
+
missionId: { type: "string", description: "CamelCase alias for mission_id." }
|
|
1902
1946
|
},
|
|
1903
1947
|
required: ["message"]
|
|
1904
1948
|
}
|
|
@@ -1936,7 +1980,7 @@ var MESH_QUEUE_CANCEL_TOOL = {
|
|
|
1936
1980
|
};
|
|
1937
1981
|
var MESH_QUEUE_REQUEUE_TOOL = {
|
|
1938
1982
|
name: "mesh_queue_requeue",
|
|
1939
|
-
description: "Return a mesh queue task to pending for retry. By default clears stale assigned owner and target session so another live session can claim it.",
|
|
1983
|
+
description: "Return a mesh queue task to pending for retry. By default clears stale assigned owner and target session so another live session can claim it. When the task has exceeded its retry cap it is auto-failed instead; use force=true to override.",
|
|
1940
1984
|
inputSchema: {
|
|
1941
1985
|
type: "object",
|
|
1942
1986
|
properties: {
|
|
@@ -1945,7 +1989,8 @@ var MESH_QUEUE_REQUEUE_TOOL = {
|
|
|
1945
1989
|
target_node_id: { type: "string", description: "Optional replacement target node ID." },
|
|
1946
1990
|
target_session_id: { type: "string", description: "Optional replacement target runtime session ID." },
|
|
1947
1991
|
clear_target_node: { type: "boolean", description: "When true, remove any existing target node constraint." },
|
|
1948
|
-
keep_target_session: { type: "boolean", description: "When true, preserve an existing target session if target_session_id is not provided. Defaults false to avoid stale session targets." }
|
|
1992
|
+
keep_target_session: { type: "boolean", description: "When true, preserve an existing target session if target_session_id is not provided. Defaults false to avoid stale session targets." },
|
|
1993
|
+
force: { type: "boolean", description: "When true, bypass the retry cap and requeue even if maxRetries has been exceeded. Use only for explicit operator recovery." }
|
|
1949
1994
|
},
|
|
1950
1995
|
required: ["task_id"]
|
|
1951
1996
|
}
|
|
@@ -2045,6 +2090,20 @@ var MESH_CHECKPOINT_TOOL = {
|
|
|
2045
2090
|
required: ["node_id", "message"]
|
|
2046
2091
|
}
|
|
2047
2092
|
};
|
|
2093
|
+
var MESH_MISSION_UPSERT_TOOL = {
|
|
2094
|
+
name: "mesh_mission_upsert",
|
|
2095
|
+
description: "Create or update a persistent mission record so the plan survives coordinator restarts. Create a mission before enqueueing a multi-task batch, attach tasks via mesh_enqueue_task mission_id, and update status to completed/abandoned when the outcome is decided. Progress is derived from task statuses \u2014 there is no separate progress field.",
|
|
2096
|
+
inputSchema: {
|
|
2097
|
+
type: "object",
|
|
2098
|
+
properties: {
|
|
2099
|
+
mission_id: { type: "string", description: "Mission id to update. Omit to create a new mission." },
|
|
2100
|
+
title: { type: "string", description: "Short mission title." },
|
|
2101
|
+
goal: { type: "string", description: "Free-text mission goal/definition of done." },
|
|
2102
|
+
status: { type: "string", enum: ["active", "paused", "completed", "abandoned"], description: "Mission lifecycle status. Defaults to active on create." }
|
|
2103
|
+
},
|
|
2104
|
+
required: ["title"]
|
|
2105
|
+
}
|
|
2106
|
+
};
|
|
2048
2107
|
var MESH_APPROVE_TOOL = {
|
|
2049
2108
|
name: "mesh_approve",
|
|
2050
2109
|
description: "Approve or reject a pending action on a delegated agent session.",
|
|
@@ -2182,6 +2241,17 @@ var MESH_REFINE_PLAN_TOOL = {
|
|
|
2182
2241
|
required: ["node_id"]
|
|
2183
2242
|
}
|
|
2184
2243
|
};
|
|
2244
|
+
var MESH_REVIEW_INBOX_TOOL = {
|
|
2245
|
+
name: "mesh_review_inbox",
|
|
2246
|
+
description: "List local worktree nodes that need human review: merge candidates (pushed feature branches ready to merge) and Refinery-blocked review results. Returns evidence summaries, diff stats vs. the default branch, and suggested actions (Refine / Requeue / Dismiss). Remote nodes are excluded in M4.0.",
|
|
2247
|
+
inputSchema: {
|
|
2248
|
+
type: "object",
|
|
2249
|
+
properties: {
|
|
2250
|
+
mesh_id: { type: "string", description: "Mesh ID (optional \u2014 inferred from active mesh if omitted)." }
|
|
2251
|
+
},
|
|
2252
|
+
required: []
|
|
2253
|
+
}
|
|
2254
|
+
};
|
|
2185
2255
|
var ALL_MESH_TOOLS = [
|
|
2186
2256
|
MESH_STATUS_TOOL,
|
|
2187
2257
|
MESH_LIST_NODES_TOOL,
|
|
@@ -2206,9 +2276,12 @@ var ALL_MESH_TOOLS = [
|
|
|
2206
2276
|
MESH_REFINE_PLAN_TOOL,
|
|
2207
2277
|
MESH_CLEANUP_SESSIONS_TOOL,
|
|
2208
2278
|
MESH_TASK_HISTORY_TOOL,
|
|
2209
|
-
MESH_RECONCILE_LEDGER_TOOL
|
|
2279
|
+
MESH_RECONCILE_LEDGER_TOOL,
|
|
2280
|
+
MESH_MISSION_UPSERT_TOOL,
|
|
2281
|
+
MESH_REVIEW_INBOX_TOOL
|
|
2210
2282
|
];
|
|
2211
2283
|
async function meshStatus(ctx, args = {}) {
|
|
2284
|
+
const rateResult = (0, import_daemon_core.recordMeshToolCall)({ meshId: ctx.mesh.id, tool: "mesh_status" });
|
|
2212
2285
|
await refreshMeshFromDaemon(ctx);
|
|
2213
2286
|
const { mesh, transport } = ctx;
|
|
2214
2287
|
let ledgerSummary = (0, import_daemon_core.getLedgerSummary)(mesh.id);
|
|
@@ -2396,6 +2469,7 @@ async function meshStatus(ctx, args = {}) {
|
|
|
2396
2469
|
...args.includeTerminalDirectWork === true ? { terminalDirectWork: activeWorkEvidence.terminalDirectWork } : {},
|
|
2397
2470
|
activeWorkSummary: activeWorkEvidence.summary,
|
|
2398
2471
|
...pollingGuidance ? { pollingGuidance } : {},
|
|
2472
|
+
...rateResult.rateLimitExceeded ? { pollingRateAdvisory: { type: "rate_limit_exceeded", tool: "mesh_status", callsInWindow: rateResult.callsInWindow, message: rateResult.advisory } } : {},
|
|
2399
2473
|
branchConvergenceSummary: summarizeBranchConvergence(results),
|
|
2400
2474
|
...coordinatorSessions.length > 0 ? {
|
|
2401
2475
|
coordinatorSessions,
|
|
@@ -2410,6 +2484,19 @@ async function meshStatus(ctx, args = {}) {
|
|
|
2410
2484
|
response.ledgerSummary = ledgerSummary;
|
|
2411
2485
|
} catch {
|
|
2412
2486
|
}
|
|
2487
|
+
try {
|
|
2488
|
+
const missions = (0, import_daemon_core.getActiveMeshMissionSummaries)(mesh.id);
|
|
2489
|
+
if (missions.length > 0) {
|
|
2490
|
+
response.missions = missions.map((mission) => {
|
|
2491
|
+
try {
|
|
2492
|
+
return { ...mission, stats: (0, import_daemon_core.computeMeshMissionStats)(mesh.id, mission.id) };
|
|
2493
|
+
} catch {
|
|
2494
|
+
return mission;
|
|
2495
|
+
}
|
|
2496
|
+
});
|
|
2497
|
+
}
|
|
2498
|
+
} catch {
|
|
2499
|
+
}
|
|
2413
2500
|
try {
|
|
2414
2501
|
const pendingEvents = await drainCoordinatorPendingEvents(ctx);
|
|
2415
2502
|
const asyncRefineJobs = (0, import_daemon_core.buildMeshAsyncRefineJobs)({
|
|
@@ -2438,10 +2525,20 @@ async function meshTaskHistory(ctx, args) {
|
|
|
2438
2525
|
payload: e.payload ? slimLedgerPayload(e.payload) : e.payload
|
|
2439
2526
|
}));
|
|
2440
2527
|
const summary = (0, import_daemon_core.getLedgerSummary)(mesh.id);
|
|
2528
|
+
let taskStats;
|
|
2529
|
+
try {
|
|
2530
|
+
const taskIds = [...new Set(rawEntries.map((e) => typeof e.payload?.taskId === "string" ? e.payload.taskId : "").filter(Boolean))];
|
|
2531
|
+
if (taskIds.length > 0) {
|
|
2532
|
+
const stats = (0, import_daemon_core.computeMeshTaskStats)(mesh.id, { taskIds });
|
|
2533
|
+
if (stats.length > 0) taskStats = stats;
|
|
2534
|
+
}
|
|
2535
|
+
} catch {
|
|
2536
|
+
}
|
|
2441
2537
|
return JSON.stringify({
|
|
2442
2538
|
meshId: mesh.id,
|
|
2443
2539
|
entries,
|
|
2444
2540
|
summary,
|
|
2541
|
+
...taskStats ? { taskStats } : {},
|
|
2445
2542
|
...pendingEvents.length > 0 ? { pendingCoordinatorEvents: pendingEvents } : {}
|
|
2446
2543
|
}, null, 2);
|
|
2447
2544
|
}
|
|
@@ -2460,7 +2557,7 @@ async function meshReconcileLedger(ctx, args) {
|
|
|
2460
2557
|
for (const node of nodes) {
|
|
2461
2558
|
try {
|
|
2462
2559
|
if (isLocalControlPlaneNode(ctx, node) || !node.daemonId) {
|
|
2463
|
-
const slice2 = (0, import_daemon_core.
|
|
2560
|
+
const slice2 = (0, import_daemon_core.readLedgerSliceFromStore)(ctx.mesh.id, queryArgs);
|
|
2464
2561
|
replicas.push((0, import_daemon_core.buildMeshLedgerReplicaEvidence)({
|
|
2465
2562
|
nodeId: node.id,
|
|
2466
2563
|
daemonId: node.daemonId,
|
|
@@ -2544,11 +2641,32 @@ async function meshListNodes(ctx) {
|
|
|
2544
2641
|
}))
|
|
2545
2642
|
}, null, 2);
|
|
2546
2643
|
}
|
|
2644
|
+
async function meshMissionUpsert(ctx, args) {
|
|
2645
|
+
try {
|
|
2646
|
+
const mission = (0, import_daemon_core.upsertMeshMission)(ctx.mesh.id, {
|
|
2647
|
+
id: readString(args.mission_id) || readString(args.missionId) || void 0,
|
|
2648
|
+
title: args.title,
|
|
2649
|
+
goal: typeof args.goal === "string" ? args.goal : void 0,
|
|
2650
|
+
status: readString(args.status) || void 0
|
|
2651
|
+
});
|
|
2652
|
+
return JSON.stringify({
|
|
2653
|
+
success: true,
|
|
2654
|
+
mission,
|
|
2655
|
+
nextAction: "Attach tasks with mesh_enqueue_task mission_id and depends_on. mesh_status shows live task aggregates for this mission."
|
|
2656
|
+
});
|
|
2657
|
+
} catch (e) {
|
|
2658
|
+
const message = e?.message || String(e);
|
|
2659
|
+
const code = message.includes("mission_title_required") ? "mission_title_required" : message.includes("invalid_mission_status") ? "invalid_mission_status" : void 0;
|
|
2660
|
+
return JSON.stringify({ success: false, ...code ? { code } : {}, error: message });
|
|
2661
|
+
}
|
|
2662
|
+
}
|
|
2547
2663
|
async function meshEnqueueTask(ctx, args) {
|
|
2548
2664
|
const taskMode = readString(args.task_mode) || readString(args.taskMode);
|
|
2549
2665
|
const requiredTags = (0, import_daemon_core.normalizeMeshCapabilityTags)(Array.isArray(args.requiredTags) ? args.requiredTags : args.required_tags);
|
|
2666
|
+
const dependsOn = Array.isArray(args.dependsOn) ? args.dependsOn : Array.isArray(args.depends_on) ? args.depends_on : void 0;
|
|
2667
|
+
const missionId = readString(args.missionId) || readString(args.mission_id) || void 0;
|
|
2550
2668
|
try {
|
|
2551
|
-
const task = (0, import_daemon_core.enqueueTask)(ctx.mesh.id, args.message, { taskMode, requiredTags });
|
|
2669
|
+
const task = (0, import_daemon_core.enqueueTask)(ctx.mesh.id, args.message, { taskMode, requiredTags, dependsOn, missionId });
|
|
2552
2670
|
if (isLocalTransport(ctx.transport) && !(ctx.transport instanceof IpcTransport)) {
|
|
2553
2671
|
const queueTrigger = await triggerMeshQueueAndReport(ctx);
|
|
2554
2672
|
return JSON.stringify({
|
|
@@ -2632,15 +2750,26 @@ async function meshEnqueueTask(ctx, args) {
|
|
|
2632
2750
|
if (message.includes("live_debug_readonly_guardrail_violation")) {
|
|
2633
2751
|
return JSON.stringify({ success: false, code: "live_debug_readonly_guardrail_violation", taskMode, error: message });
|
|
2634
2752
|
}
|
|
2753
|
+
if (message.includes("dependency_cycle_detected")) {
|
|
2754
|
+
return JSON.stringify({ success: false, code: "dependency_cycle_detected", dependsOn, error: message });
|
|
2755
|
+
}
|
|
2635
2756
|
return JSON.stringify({ success: false, error: message });
|
|
2636
2757
|
}
|
|
2637
2758
|
}
|
|
2638
2759
|
async function meshViewQueue(ctx, args) {
|
|
2760
|
+
const rateResult = (0, import_daemon_core.recordMeshToolCall)({ meshId: ctx.mesh.id, tool: "mesh_view_queue" });
|
|
2639
2761
|
try {
|
|
2640
2762
|
await refreshMeshFromDaemon(ctx);
|
|
2641
2763
|
const statusFilter = sanitizeQueueStatusFilter(args.status);
|
|
2642
2764
|
const view = normalizeQueueViewMode(args.view);
|
|
2643
|
-
const
|
|
2765
|
+
const rawQueue = (0, import_daemon_core.getQueue)(ctx.mesh.id);
|
|
2766
|
+
const statusById = new Map(rawQueue.map((task) => [task.id, task.status]));
|
|
2767
|
+
const withDependencies = rawQueue.map((task) => {
|
|
2768
|
+
if (!Array.isArray(task.dependsOn) || task.dependsOn.length === 0) return task;
|
|
2769
|
+
const depState = (0, import_daemon_core.describeTaskDependencyState)(task, statusById);
|
|
2770
|
+
return { ...task, ...depState };
|
|
2771
|
+
});
|
|
2772
|
+
const fullQueue = prioritizeActiveQueueRows(annotateQueueStaleness(withDependencies, ctx.mesh));
|
|
2644
2773
|
const queue = filterQueueForView(fullQueue, view, statusFilter);
|
|
2645
2774
|
const summary = buildQueueStatusSummary(fullQueue);
|
|
2646
2775
|
const visibleSummary = buildQueueStatusSummary(queue);
|
|
@@ -2692,6 +2821,7 @@ async function meshViewQueue(ctx, args) {
|
|
|
2692
2821
|
staleDirectWork: activeWorkEvidence.staleDirectWork,
|
|
2693
2822
|
activeWorkSummary: activeWorkEvidence.summary,
|
|
2694
2823
|
...pollingGuidance ? { pollingGuidance } : {},
|
|
2824
|
+
...rateResult.rateLimitExceeded ? { pollingRateAdvisory: { type: "rate_limit_exceeded", tool: "mesh_view_queue", callsInWindow: rateResult.callsInWindow, message: rateResult.advisory } } : {},
|
|
2695
2825
|
summary,
|
|
2696
2826
|
visibleSummary,
|
|
2697
2827
|
activeCounts: summary.activeCounts,
|
|
@@ -2751,9 +2881,19 @@ async function meshQueueRequeue(ctx, args) {
|
|
|
2751
2881
|
targetNodeId,
|
|
2752
2882
|
targetSessionId,
|
|
2753
2883
|
clearTargetNode: args.clear_target_node === true || args.clearTargetNode === true,
|
|
2754
|
-
clearTargetSession: targetSessionId ? false : !keepTargetSession
|
|
2884
|
+
clearTargetSession: targetSessionId ? false : !keepTargetSession,
|
|
2885
|
+
force: args.force === true
|
|
2755
2886
|
});
|
|
2756
2887
|
if (!task) return JSON.stringify({ success: false, error: `Queue task '${taskId}' not found` });
|
|
2888
|
+
if (task.status === "failed" && task.cancelReason?.startsWith("max_retries_exceeded")) {
|
|
2889
|
+
return JSON.stringify({
|
|
2890
|
+
success: false,
|
|
2891
|
+
code: "max_retries_exceeded",
|
|
2892
|
+
error: task.cancelReason,
|
|
2893
|
+
task,
|
|
2894
|
+
hint: "Use force=true to bypass the retry cap for explicit operator recovery."
|
|
2895
|
+
}, null, 2);
|
|
2896
|
+
}
|
|
2757
2897
|
if (isLocalTransport(ctx.transport)) {
|
|
2758
2898
|
ctx.transport.command("trigger_mesh_queue", { meshId: ctx.mesh.id }).catch(() => {
|
|
2759
2899
|
});
|
|
@@ -3211,7 +3351,7 @@ async function meshReadDebug(ctx, args) {
|
|
|
3211
3351
|
}
|
|
3212
3352
|
async function meshLaunchSession(ctx, args) {
|
|
3213
3353
|
const node = await findNodeWithRefresh(ctx, args.node_id);
|
|
3214
|
-
const bootstrapBlock = getWorktreeBootstrapLaunchBlock(node);
|
|
3354
|
+
const bootstrapBlock = getWorktreeBootstrapLaunchBlock(node, ctx.mesh.policy);
|
|
3215
3355
|
if (bootstrapBlock) return JSON.stringify(bootstrapBlock, null, 2);
|
|
3216
3356
|
if (isLocalTransport(ctx.transport)) {
|
|
3217
3357
|
let resolvedProviderType = typeof args.type === "string" && args.type.trim() ? args.type : "";
|
|
@@ -3247,6 +3387,9 @@ async function meshLaunchSession(ctx, args) {
|
|
|
3247
3387
|
cliType: resolvedProviderType,
|
|
3248
3388
|
dir: node.workspace,
|
|
3249
3389
|
settings: {
|
|
3390
|
+
// Worker launch envelope (A5): structured metadata so worker sessions
|
|
3391
|
+
// know their role and can route completion events back correctly.
|
|
3392
|
+
role: "worker",
|
|
3250
3393
|
meshNodeFor: ctx.mesh.id,
|
|
3251
3394
|
meshNodeId: args.node_id,
|
|
3252
3395
|
spawnedSessionVisibility,
|
|
@@ -3716,6 +3859,18 @@ async function meshRefineNode(ctx, args) {
|
|
|
3716
3859
|
return JSON.stringify({ error: "Cloud mesh refine_node requires node daemonId" });
|
|
3717
3860
|
}
|
|
3718
3861
|
}
|
|
3862
|
+
async function meshReviewInbox(ctx, args = {}) {
|
|
3863
|
+
if (!isLocalTransport(ctx.transport)) {
|
|
3864
|
+
return JSON.stringify({ error: "mesh_review_inbox requires a local daemon transport (M4.0 scope: local nodes only)" });
|
|
3865
|
+
}
|
|
3866
|
+
await refreshMeshFromDaemon(ctx);
|
|
3867
|
+
const meshId = (args.mesh_id ?? ctx.mesh.id).trim();
|
|
3868
|
+
const result = await commandForNode(ctx, ctx.mesh.nodes[0], "get_mesh_review_inbox", {
|
|
3869
|
+
meshId,
|
|
3870
|
+
inlineMesh: ctx.mesh
|
|
3871
|
+
});
|
|
3872
|
+
return JSON.stringify(result, null, 2);
|
|
3873
|
+
}
|
|
3719
3874
|
|
|
3720
3875
|
// src/help.ts
|
|
3721
3876
|
var STANDARD_TOOLS = [
|
|
@@ -5570,6 +5725,12 @@ async function startMcpServer(opts) {
|
|
|
5570
5725
|
case "mesh_reconcile_ledger":
|
|
5571
5726
|
text = await meshReconcileLedger(meshCtx, a);
|
|
5572
5727
|
break;
|
|
5728
|
+
case "mesh_mission_upsert":
|
|
5729
|
+
text = await meshMissionUpsert(meshCtx, a);
|
|
5730
|
+
break;
|
|
5731
|
+
case "mesh_review_inbox":
|
|
5732
|
+
text = await meshReviewInbox(meshCtx, a);
|
|
5733
|
+
break;
|
|
5573
5734
|
default:
|
|
5574
5735
|
return { content: [{ type: "text", text: `Unknown tool: ${name}` }], isError: true };
|
|
5575
5736
|
}
|