@adhdev/daemon-standalone 1.0.28-rc.9 → 1.0.29-rc.1
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 +27976 -20522
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/public/assets/index-D9aov25q.js +121 -0
- package/public/assets/index-Jy4W-yh-.css +1 -0
- package/public/index.html +2 -2
- package/vendor/mcp-server/index.js +309 -41
- package/vendor/mcp-server/index.js.map +1 -1
- package/vendor/mcp-server/package.json +1 -1
- package/vendor/session-host-daemon/index.d.mts +2 -0
- package/vendor/session-host-daemon/index.d.ts +2 -0
- package/vendor/session-host-daemon/index.js +38 -24
- package/vendor/session-host-daemon/index.js.map +1 -1
- package/vendor/session-host-daemon/index.mjs +26 -10
- package/vendor/session-host-daemon/index.mjs.map +1 -1
- package/public/assets/index-8TNNoifN.css +0 -1
- package/public/assets/index-CD0m71Da.js +0 -121
|
@@ -51,6 +51,9 @@ var IPC_COMMAND_TIMEOUTS_MS = {
|
|
|
51
51
|
// 120s leaves headroom and matches the relay-wrapped remote path.
|
|
52
52
|
clone_mesh_node: 12e4,
|
|
53
53
|
remove_mesh_node: 6e4,
|
|
54
|
+
// Retention plan/execute runs the same git probes as a remove dry-run plus
|
|
55
|
+
// queue/session/ledger reads; 60s matches the remove budget.
|
|
56
|
+
cleanup_worktree_nodes: 6e4,
|
|
54
57
|
// A5: plan_mesh_refine_node is the SYNCHRONOUS refine dry-run — it runs several git
|
|
55
58
|
// probes (status/merge-tree/submodule) inline before replying, which can approach the
|
|
56
59
|
// 15s default on a slow (Windows) host. 45s defensively, matching git_status/diff.
|
|
@@ -304,6 +307,33 @@ function dedupeSummaryFromTail(messages, summary) {
|
|
|
304
307
|
return { ...rest, content: "", _sameAsSummary: true };
|
|
305
308
|
});
|
|
306
309
|
}
|
|
310
|
+
var TURN_IDENTITY_FIELDS = [
|
|
311
|
+
"authority",
|
|
312
|
+
"status",
|
|
313
|
+
"stage",
|
|
314
|
+
"terminalOutcome",
|
|
315
|
+
"terminalReason",
|
|
316
|
+
"meshId",
|
|
317
|
+
"taskId",
|
|
318
|
+
"attemptId",
|
|
319
|
+
"attemptSeq",
|
|
320
|
+
"sessionId",
|
|
321
|
+
"nodeId",
|
|
322
|
+
"providerType",
|
|
323
|
+
"acceptedAt",
|
|
324
|
+
"deliveredAt",
|
|
325
|
+
"consumedAt",
|
|
326
|
+
"terminalAt",
|
|
327
|
+
"updatedAt"
|
|
328
|
+
];
|
|
329
|
+
function slimTurnPresentation(turn) {
|
|
330
|
+
if (!turn || typeof turn !== "object" || Array.isArray(turn)) return null;
|
|
331
|
+
const slim = {};
|
|
332
|
+
for (const key of TURN_IDENTITY_FIELDS) {
|
|
333
|
+
if (turn[key] !== void 0) slim[key] = turn[key];
|
|
334
|
+
}
|
|
335
|
+
return Object.keys(slim).length > 0 ? slim : null;
|
|
336
|
+
}
|
|
307
337
|
function compactChatPayload(payload, opts = {}) {
|
|
308
338
|
const rawMessages = Array.isArray(payload?.messages) ? payload.messages : [];
|
|
309
339
|
const visible = rawMessages.filter(isCoordinatorVisibleMessage);
|
|
@@ -320,6 +350,7 @@ function compactChatPayload(payload, opts = {}) {
|
|
|
320
350
|
const toolSummaries = rawMessages.filter((m) => !isCoordinatorVisibleMessage(m)).map(summarizeToolMessage).filter((s) => s !== null);
|
|
321
351
|
const omittedMessages = Math.max(0, rawMessages.length - messages.length);
|
|
322
352
|
const filteredMessages = Math.max(0, rawMessages.length - visible.length);
|
|
353
|
+
const slimTurn = opts.preserveTurn ? slimTurnPresentation(payload?.turn) : null;
|
|
323
354
|
return {
|
|
324
355
|
success: payload?.success !== false,
|
|
325
356
|
compact: true,
|
|
@@ -327,6 +358,9 @@ function compactChatPayload(payload, opts = {}) {
|
|
|
327
358
|
...opts.sessionId !== void 0 ? { sessionId: opts.sessionId } : {},
|
|
328
359
|
status: payload?.status ?? null,
|
|
329
360
|
providerSessionId: payload?.providerSessionId ?? null,
|
|
361
|
+
...slimTurn ? { turn: slimTurn } : {},
|
|
362
|
+
...slimTurn?.attemptId !== void 0 ? { attemptId: slimTurn.attemptId } : {},
|
|
363
|
+
...slimTurn?.stage !== void 0 ? { turnStage: slimTurn.stage } : {},
|
|
330
364
|
totalMessages: rawMessages.length,
|
|
331
365
|
visibleMessages: visible.length,
|
|
332
366
|
filteredMessages,
|
|
@@ -393,10 +427,12 @@ var CANONICAL_MESH_TOOL_NAMES = [
|
|
|
393
427
|
"mesh_approve",
|
|
394
428
|
"mesh_answer_question",
|
|
395
429
|
"mesh_list_pending_approvals",
|
|
430
|
+
"mesh_plan_onboarding",
|
|
396
431
|
"mesh_create",
|
|
397
432
|
"mesh_add_node",
|
|
398
433
|
"mesh_clone_node",
|
|
399
434
|
"mesh_remove_node",
|
|
435
|
+
"mesh_cleanup_worktree_nodes",
|
|
400
436
|
"mesh_refine_node",
|
|
401
437
|
"mesh_refine_batch",
|
|
402
438
|
"mesh_refine_config",
|
|
@@ -1000,12 +1036,19 @@ var MESH_FAST_FORWARD_NODE_TOOL = {
|
|
|
1000
1036
|
};
|
|
1001
1037
|
var MESH_RESTART_DAEMON_TOOL = {
|
|
1002
1038
|
name: "mesh_restart_daemon",
|
|
1003
|
-
description: `
|
|
1039
|
+
description: `Restart a mesh node's daemon, optionally updating it first \u2014 the same path as the dashboard "preview update" button, exposed as a mesh command so a coordinator can roll a worker daemon without a manual restart round-trip. No agent session is launched. mode="upgrade" (default): update to the latest published version on the release channel, then restart; already-latest is a no-op (no restart, returns alreadyLatest:true). mode="restart": pure re-spawn with no reinstall \u2014 restarts even when already latest, with much shorter downtime; use it to reset wedged daemon state (memory leaks, zombie sessions). Idle-gated: a node whose daemon has an active session (generating / waiting_approval / starting) is refused with code "blocking_sessions" so an in-flight turn is never interrupted. self_only=true waives ONLY this mesh's own coordinator session (the structural self-deadlock case \u2014 the coordinator is always generating while it calls). Other sessions still refuse. force=true bypasses the gate entirely: in-flight turns die and the unpersisted pendingOutboundQueue is lost. when_idle=true schedules the restart to run automatically once the daemon goes idle (the safest path \u2014 no queue loss); cancel_when_idle=true cancels it and every response reports the schedule under deferredRestart. kill_session_host=true additionally stops the session-host process, destroying ALL hosted CLI sessions (hard refresh; this is what Windows already does on every upgrade). Default off. Note: on Windows any daemon restart/upgrade terminates all hosted sessions regardless of options; on POSIX hosted sessions survive a plain restart and rebind on next boot. Passing channel switches the daemon's release channel (and server URL) before restarting; omit it to keep the daemon on its configured channel.`,
|
|
1004
1040
|
inputSchema: {
|
|
1005
1041
|
type: "object",
|
|
1006
1042
|
properties: {
|
|
1007
|
-
node_id: { type: "string", description: "Target node ID \u2014 the daemon that owns this node is
|
|
1008
|
-
channel: { type: "string", enum: ["stable", "preview"], description: "Optional release channel to update from. Defaults to the daemon's configured updateChannel. Setting it also repoints the daemon's server URL to that channel." }
|
|
1043
|
+
node_id: { type: "string", description: "Target node ID \u2014 the daemon that owns this node is restarted (and updated, in upgrade mode)." },
|
|
1044
|
+
channel: { type: "string", enum: ["stable", "preview"], description: "Optional release channel to update from (upgrade mode only). Defaults to the daemon's configured updateChannel. Setting it also repoints the daemon's server URL to that channel." },
|
|
1045
|
+
mode: { type: "string", enum: ["upgrade", "restart"], description: "upgrade (default): update to latest on channel, then restart (already-latest is a no-op). restart: pure re-spawn, no reinstall \u2014 restarts even when already latest." },
|
|
1046
|
+
force: { type: "boolean", description: "Bypass the idle-gate entirely. Destructive: in-flight turns are killed and the in-memory pendingOutboundQueue is permanently lost. Default false." },
|
|
1047
|
+
self_only: { type: "boolean", description: "Waive only this mesh's own coordinator session when it blocks the restart (the coordinator self-deadlock). Other nodes' active sessions still refuse. Default false." },
|
|
1048
|
+
when_idle: { type: "boolean", description: "If blocked, schedule the restart to execute automatically once the daemon goes idle (safest \u2014 no pendingOutboundQueue loss). The schedule expires after timeout_ms (default 30 min). Default false." },
|
|
1049
|
+
cancel_when_idle: { type: "boolean", description: "Cancel a previously scheduled when_idle restart on the owning daemon." },
|
|
1050
|
+
timeout_ms: { type: "number", description: "Expiry for a when_idle schedule in milliseconds (default 1800000 = 30 min, max 6 h)." },
|
|
1051
|
+
kill_session_host: { type: "boolean", description: "Hard refresh: also stop the session-host process, destroying ALL hosted CLI sessions on the machine. Default false." }
|
|
1009
1052
|
},
|
|
1010
1053
|
required: ["node_id"]
|
|
1011
1054
|
}
|
|
@@ -1120,23 +1163,41 @@ var MESH_LIST_PENDING_APPROVALS_TOOL = {
|
|
|
1120
1163
|
};
|
|
1121
1164
|
var MESH_CREATE_TOOL = {
|
|
1122
1165
|
name: "mesh_create",
|
|
1123
|
-
description: "Bootstrap a brand-new mesh for a Git repository \u2014 the first step for an MCP-only agent that has no mesh yet. Mirrors `adhdev mesh create <name>`. A mesh groups one repo's workspaces/nodes so the coordinator can delegate work across them.
|
|
1166
|
+
description: "Bootstrap a brand-new mesh for a Git repository \u2014 the first step for an MCP-only agent that has no mesh yet. Mirrors `adhdev mesh create <name>`. A mesh groups one repo's workspaces/nodes so the coordinator can delegate work across them. Pass workspace to auto-detect Git identity/branch/worktree metadata through the read-only planner, or explicitly pass repo_remote_url / repo_identity for backward compatibility. This is a persistent write: call mesh_plan_onboarding first and obtain explicit user approval before invoking it. Set add_current:true to also register a node in the same call (uses workspace if given, else the daemon's current working directory). BOOT-GATE / WHEN CALLABLE: this tool is reachable in STANDARD mode (adhdev mcp, no --repo-mesh) \u2014 the bootstrap context where no mesh exists \u2014 and also in mesh mode (where it creates a SEPARATE additional mesh). It is NOT reachable before any mesh exists via mesh mode, because `adhdev mcp --repo-mesh <id>` refuses to start without an existing meshId. So the intended flow is: run standard-mode MCP \u2192 mesh_create \u2192 mesh_add_node \u2192 then relaunch as `adhdev mcp --repo-mesh <returned mesh_id>`. Returns mesh_id (and node_id when add_current is used); use mesh_id for the follow-up mesh_add_node call and to launch mesh mode.",
|
|
1124
1167
|
inputSchema: {
|
|
1125
1168
|
type: "object",
|
|
1126
1169
|
properties: {
|
|
1127
1170
|
name: { type: "string", description: 'Human-readable mesh name (e.g. "adhdev-main"). Trimmed, max 100 chars.' },
|
|
1128
|
-
repo_remote_url: { type: "string", description: "Git remote URL
|
|
1129
|
-
repo_identity: { type: "string", description: "
|
|
1171
|
+
repo_remote_url: { type: "string", description: "Optional explicit Git remote URL. When omitted with repo_identity, identity is read-only auto-detected from workspace." },
|
|
1172
|
+
repo_identity: { type: "string", description: "Optional explicit normalized repo identity. Wins over repo_remote_url; when both are omitted, workspace is auto-detected." },
|
|
1130
1173
|
default_branch: { type: "string", description: 'Default branch for the repo (e.g. "main"). Optional; used as the merge/convergence target.' },
|
|
1131
1174
|
add_current: { type: "boolean", description: "Also register a node in this same call (parity with CLI --add-current). Uses `workspace` if provided, otherwise the daemon's current working directory." },
|
|
1132
|
-
workspace: { type: "string", description: "Absolute workspace path
|
|
1175
|
+
workspace: { type: "string", description: "Absolute workspace path used for Git auto-detection and, when add_current:true, node registration. Defaults to the daemon cwd." }
|
|
1133
1176
|
},
|
|
1134
1177
|
required: ["name"]
|
|
1135
1178
|
}
|
|
1136
1179
|
};
|
|
1180
|
+
var MESH_PLAN_ONBOARDING_TOOL = {
|
|
1181
|
+
name: "mesh_plan_onboarding",
|
|
1182
|
+
description: "Read-only Git-aware Repo Mesh discovery and dry-run planning for a workspace path. Detects the Git root, normalized remotes/repo identity, current/default branch, main checkout vs linked worktree/common-dir metadata, dirty/conflict state, and existing mesh/node membership. Returns a typed create+onboarding, add-existing-workspace, or clone-new-worktree plan with suggested .adhdev configs. It never fetches, writes config, creates a mesh/node/branch/worktree, or otherwise mutates state. Use this before mesh_create, mesh_add_node, or mesh_clone_node; execute write steps only after explicit user approval.",
|
|
1183
|
+
inputSchema: {
|
|
1184
|
+
type: "object",
|
|
1185
|
+
properties: {
|
|
1186
|
+
workspace: { type: "string", description: "Absolute path on the daemon that owns the Git checkout." },
|
|
1187
|
+
mesh_id: { type: "string", description: "Optional existing mesh to validate against. In mesh mode defaults to the active mesh." },
|
|
1188
|
+
operation: {
|
|
1189
|
+
type: "string",
|
|
1190
|
+
enum: ["auto", "add_existing", "clone_worktree", "create_mesh"],
|
|
1191
|
+
description: "Planning intent. auto chooses create+onboard when no compatible mesh exists, otherwise add existing. clone_worktree requires branch and a clean source."
|
|
1192
|
+
},
|
|
1193
|
+
branch: { type: "string", description: "New branch name when operation=clone_worktree." }
|
|
1194
|
+
},
|
|
1195
|
+
required: ["workspace"]
|
|
1196
|
+
}
|
|
1197
|
+
};
|
|
1137
1198
|
var MESH_ADD_NODE_TOOL = {
|
|
1138
1199
|
name: "mesh_add_node",
|
|
1139
|
-
description: "Register a workspace as a node in an EXISTING mesh \u2014 the second bootstrap step after mesh_create (or to add more nodes later). Mirrors `adhdev mesh add-node <mesh_id>` with --workspace / --read-only / --provider-priority. A node is a repo checkout on a daemon that the coordinator can launch agents on and delegate tasks to. mesh_id is REQUIRED in standard mode (pass the id returned by mesh_create); in mesh mode it defaults to the active mesh. workspace is the absolute path to the repo checkout ON THE DAEMON that owns it \u2014 the local base node is added by the daemon that created the mesh. NOTE: this registers an EXISTING directory as a node (including
|
|
1200
|
+
description: "Register a workspace as a node in an EXISTING mesh \u2014 the second bootstrap step after mesh_create (or to add more nodes later). Mirrors `adhdev mesh add-node <mesh_id>` with --workspace / --read-only / --provider-priority. A node is a repo checkout on a daemon that the coordinator can launch agents on and delegate tasks to. mesh_id is REQUIRED in standard mode (pass the id returned by mesh_create); in mesh mode it defaults to the active mesh. workspace is the absolute path to the repo checkout ON THE DAEMON that owns it \u2014 the local base node is added by the daemon that created the mesh. This is a persistent mesh write: call mesh_plan_onboarding first and obtain explicit user approval. The implementation re-runs that preflight before writing. NOTE: this registers an EXISTING directory as a node (including auto-detected linked worktrees). To CREATE a fresh git worktree + branch for isolated parallel work, use mesh_clone_node instead \u2014 that runs the actual `git worktree add`. Returns node_id + workspace so you can immediately target the node with mesh_launch_session / mesh_send_task / mesh_enqueue_task.",
|
|
1140
1201
|
inputSchema: {
|
|
1141
1202
|
type: "object",
|
|
1142
1203
|
properties: {
|
|
@@ -1155,7 +1216,7 @@ var MESH_ADD_NODE_TOOL = {
|
|
|
1155
1216
|
};
|
|
1156
1217
|
var MESH_CLONE_NODE_TOOL = {
|
|
1157
1218
|
name: "mesh_clone_node",
|
|
1158
|
-
description: "Create a new worktree-based node from an existing node for isolated parallel work. Creates a git worktree on a new branch so multiple tasks can run on separate branches simultaneously.",
|
|
1219
|
+
description: "Create a new worktree-based node from an existing node for isolated parallel work. Creates a git worktree on a new branch so multiple tasks can run on separate branches simultaneously. This writes a branch, worktree and mesh node: call mesh_plan_onboarding with operation=clone_worktree and obtain explicit user approval first; the implementation re-runs the clean/source preflight.",
|
|
1159
1220
|
inputSchema: {
|
|
1160
1221
|
type: "object",
|
|
1161
1222
|
properties: {
|
|
@@ -1183,6 +1244,18 @@ var MESH_REMOVE_NODE_TOOL = {
|
|
|
1183
1244
|
required: ["node_id"]
|
|
1184
1245
|
}
|
|
1185
1246
|
};
|
|
1247
|
+
var MESH_CLEANUP_WORKTREE_NODES_TOOL = {
|
|
1248
|
+
name: "mesh_cleanup_worktree_nodes",
|
|
1249
|
+
description: "Plan (dry-run, default) or execute safe removal of CONVERGED local worktree nodes (lifecycle retention). A node is eligible only when its feature branch is proven merged/pushed/converged AND every safety exclusion passes: no dirty/conflicted/stashed/submodule-drift state, no live session, no queue/direct-dispatch reference, no in-flight or blocked_review Refinery job, not the coordinator/base/cwd/evidence node. The automatic reconcile pass additionally requires two consecutive eligible ticks spanning a grace window (default 48h). Per-node reason codes are always returned; removal never uses force and branch refs are deleted only when proven fully merged.",
|
|
1250
|
+
inputSchema: {
|
|
1251
|
+
type: "object",
|
|
1252
|
+
properties: {
|
|
1253
|
+
node_id: { type: "string", description: "Optional: restrict the plan/execute to a single node. When omitted, every node in the mesh is evaluated." },
|
|
1254
|
+
dry_run: { type: "boolean", description: "Default true. true = read-only reason-coded plan (identical shape to the automatic pass); false = execute removal for every currently-eligible node (never forces; the non-destructive precheck re-runs immediately before each removal)." }
|
|
1255
|
+
},
|
|
1256
|
+
required: []
|
|
1257
|
+
}
|
|
1258
|
+
};
|
|
1186
1259
|
var MESH_CLEANUP_SESSIONS_TOOL = {
|
|
1187
1260
|
name: "mesh_cleanup_sessions",
|
|
1188
1261
|
description: "Manually clean up delegated session records for a mesh node without removing the node. Defaults should preserve reviewable history unless the caller chooses a mode explicitly.",
|
|
@@ -1579,10 +1652,12 @@ var ALL_MESH_TOOLS = [
|
|
|
1579
1652
|
MESH_APPROVE_TOOL,
|
|
1580
1653
|
MESH_ANSWER_QUESTION_TOOL,
|
|
1581
1654
|
MESH_LIST_PENDING_APPROVALS_TOOL,
|
|
1655
|
+
MESH_PLAN_ONBOARDING_TOOL,
|
|
1582
1656
|
MESH_CREATE_TOOL,
|
|
1583
1657
|
MESH_ADD_NODE_TOOL,
|
|
1584
1658
|
MESH_CLONE_NODE_TOOL,
|
|
1585
1659
|
MESH_REMOVE_NODE_TOOL,
|
|
1660
|
+
MESH_CLEANUP_WORKTREE_NODES_TOOL,
|
|
1586
1661
|
MESH_REFINE_NODE_TOOL,
|
|
1587
1662
|
MESH_REFINE_BATCH_TOOL,
|
|
1588
1663
|
MESH_REFINE_CONFIG_TOOL,
|
|
@@ -2359,6 +2434,7 @@ async function reconcileDirectDispatchesFromTranscriptEvidence(ctx, liveNodes, d
|
|
|
2359
2434
|
});
|
|
2360
2435
|
const payload = unwrapCommandPayload(readResult);
|
|
2361
2436
|
if (payload?.success === false) continue;
|
|
2437
|
+
if ((0, import_daemon_core3.hasTrailingToolActivityAfterFinalAssistant)(Array.isArray(payload?.messages) ? payload.messages : [])) continue;
|
|
2362
2438
|
const evidence = readFinalAssistantTranscriptEvidence(payload);
|
|
2363
2439
|
if (!evidence.finalSummary) continue;
|
|
2364
2440
|
const result = (0, import_daemon_core3.reconcileDirectDispatchCompletionFromTranscript)({
|
|
@@ -3231,6 +3307,12 @@ function buildMeshForwardPayloadFromPendingEvent(event) {
|
|
|
3231
3307
|
interactionId: readString(metadataEvent.interactionId),
|
|
3232
3308
|
status: readString(metadataEvent.status),
|
|
3233
3309
|
targetDaemonId: readString(metadataEvent.targetDaemonId),
|
|
3310
|
+
// RC32: carry the coordinator DAEMON anchor across the remote-pull relay (the
|
|
3311
|
+
// pending event stores it top-level, not inside metadataEvent). The receive-side
|
|
3312
|
+
// whitelist (daemon-core buildRelayMetadataEvent) reads it back so a sessionless
|
|
3313
|
+
// refine terminal event re-queues targeted at THIS coordinator instead of
|
|
3314
|
+
// self-fallback-stamping the relaying worker daemon.
|
|
3315
|
+
targetCoordinatorDaemonId: readString(event?.targetCoordinatorDaemonId),
|
|
3234
3316
|
startedAt: readString(metadataEvent.startedAt),
|
|
3235
3317
|
completedAt: readString(metadataEvent.completedAt),
|
|
3236
3318
|
retryOfJobId: readString(metadataEvent.retryOfJobId),
|
|
@@ -3577,6 +3659,11 @@ async function meshStatus(ctx, args = {}) {
|
|
|
3577
3659
|
status: s.status ?? s.lifecycle ?? s.state,
|
|
3578
3660
|
providerType: s.providerType ?? s.cliType ?? s.type,
|
|
3579
3661
|
...s.activeChat?.status ? { chatStatus: s.activeChat.status } : {},
|
|
3662
|
+
// Stage 6: attempt identity + causal stage from the unified turn
|
|
3663
|
+
// projection (present on mesh-owned sessions only), so mesh_status
|
|
3664
|
+
// reports the SAME attemptId/stage as read_chat and the dashboard.
|
|
3665
|
+
...s.turn?.attemptId ? { attemptId: s.turn.attemptId } : {},
|
|
3666
|
+
...s.turn?.stage ? { turnStage: s.turn.stage } : {},
|
|
3580
3667
|
...isSelfCoordinator ? { isSelfCoordinator: true, role: "coordinator" } : {},
|
|
3581
3668
|
// [T2] Carry the worker-computed last-message preview through the slim so
|
|
3582
3669
|
// the coordinator's inbox can show the worker's latest ASSISTANT reply
|
|
@@ -6671,30 +6758,29 @@ async function meshSendTask(ctx, args) {
|
|
|
6671
6758
|
}
|
|
6672
6759
|
if (explicitTargetSession && !isIdleSessionRecord(explicitTargetSession) && !isTerminalSessionRecord(explicitTargetSession)) {
|
|
6673
6760
|
const sessionStatus = typeof explicitTargetSession?.status === "string" ? explicitTargetSession.status : "unknown";
|
|
6674
|
-
const {
|
|
6761
|
+
const { resolveDeliveryDecision } = await import("@adhdev/daemon-core");
|
|
6675
6762
|
const policyResult = resolveDeliveryDecision(sessionStatus, { kind: "task" });
|
|
6676
6763
|
if (policyResult.decision === "queued") {
|
|
6677
|
-
const
|
|
6678
|
-
|
|
6679
|
-
|
|
6680
|
-
|
|
6681
|
-
|
|
6682
|
-
|
|
6683
|
-
|
|
6684
|
-
status: "queued"
|
|
6764
|
+
const queuedTask = (0, import_daemon_core4.enqueueTask)(ctx.mesh.id, message, {
|
|
6765
|
+
targetNodeId: args.node_id,
|
|
6766
|
+
targetSessionId: args.session_id,
|
|
6767
|
+
taskMode,
|
|
6768
|
+
...readonly ? { readonly: true } : {},
|
|
6769
|
+
...missionId ? { missionId } : {},
|
|
6770
|
+
...ctx.coordinatorSessionId ? { sourceCoordinatorSessionId: ctx.coordinatorSessionId } : {}
|
|
6685
6771
|
});
|
|
6686
6772
|
return JSON.stringify({
|
|
6687
6773
|
success: true,
|
|
6688
6774
|
dispatched: false,
|
|
6689
6775
|
decision: "queued_delivery",
|
|
6690
|
-
|
|
6776
|
+
taskId: queuedTask.id,
|
|
6691
6777
|
reason: policyResult.reason,
|
|
6692
6778
|
nodeId: args.node_id,
|
|
6693
6779
|
sessionId: args.session_id,
|
|
6694
6780
|
sessionStatus,
|
|
6695
6781
|
taskMode: taskMode || void 0,
|
|
6696
6782
|
message: policyResult.message,
|
|
6697
|
-
nextAction: `
|
|
6783
|
+
nextAction: `Task '${queuedTask.id}' is queued and pinned to session '${args.session_id}' \u2014 it auto-delivers the moment the session goes idle. Use mesh_status or mesh_task_history to track it; no manual resend needed.`
|
|
6698
6784
|
});
|
|
6699
6785
|
}
|
|
6700
6786
|
}
|
|
@@ -6886,7 +6972,11 @@ async function meshReadChat(ctx, args) {
|
|
|
6886
6972
|
const compactPayload = compactChatPayload(payload, {
|
|
6887
6973
|
nodeId: args.node_id,
|
|
6888
6974
|
sessionId: args.session_id,
|
|
6889
|
-
limit: args.tail ?? 10
|
|
6975
|
+
limit: args.tail ?? 10,
|
|
6976
|
+
// Carry the daemon's Stage 6 turn projection (attemptId/turnStage/
|
|
6977
|
+
// authority/terminal outcome) so the slim response stays at parity
|
|
6978
|
+
// with daemon read_chat and mesh_status. Non-content scalars only.
|
|
6979
|
+
preserveTurn: true
|
|
6890
6980
|
});
|
|
6891
6981
|
return JSON.stringify(
|
|
6892
6982
|
payload.pollingAdvisory ? { ...compactPayload, pollingAdvisory: payload.pollingAdvisory } : compactPayload,
|
|
@@ -7365,7 +7455,14 @@ async function meshRestartDaemon(ctx, args) {
|
|
|
7365
7455
|
meshId: ctx.mesh.id,
|
|
7366
7456
|
nodeId: node.id,
|
|
7367
7457
|
inlineMesh: ctx.mesh,
|
|
7368
|
-
...args.channel ? { channel: args.channel } : {}
|
|
7458
|
+
...args.channel ? { channel: args.channel } : {},
|
|
7459
|
+
...args.mode ? { mode: args.mode } : {},
|
|
7460
|
+
...args.force === true ? { force: true } : {},
|
|
7461
|
+
...args.self_only === true ? { selfOnly: true } : {},
|
|
7462
|
+
...args.when_idle === true ? { whenIdle: true } : {},
|
|
7463
|
+
...args.cancel_when_idle === true ? { cancelWhenIdle: true } : {},
|
|
7464
|
+
...typeof args.timeout_ms === "number" ? { timeoutMs: args.timeout_ms } : {},
|
|
7465
|
+
...args.kill_session_host === true ? { killSessionHost: true } : {}
|
|
7369
7466
|
});
|
|
7370
7467
|
return JSON.stringify(unwrapCommandPayload(result), null, 2);
|
|
7371
7468
|
} catch (e) {
|
|
@@ -7405,6 +7502,23 @@ async function meshCheckpoint(ctx, args) {
|
|
|
7405
7502
|
}
|
|
7406
7503
|
async function meshCloneNode(ctx, args) {
|
|
7407
7504
|
const sourceNode = await findNodeWithRefresh(ctx, args.source_node_id);
|
|
7505
|
+
const planned = unwrapCommandPayload(await commandForNode(ctx, sourceNode, "plan_mesh_onboarding", {
|
|
7506
|
+
workspace: sourceNode.workspace,
|
|
7507
|
+
meshId: ctx.mesh.id,
|
|
7508
|
+
inlineMesh: ctx.mesh,
|
|
7509
|
+
operation: "clone_worktree",
|
|
7510
|
+
branch: args.branch
|
|
7511
|
+
}));
|
|
7512
|
+
if (!planned?.success) {
|
|
7513
|
+
return JSON.stringify({
|
|
7514
|
+
success: false,
|
|
7515
|
+
dry_run: true,
|
|
7516
|
+
code: planned?.code || "onboarding_blocked",
|
|
7517
|
+
error: planned?.error || "Worktree clone preflight failed",
|
|
7518
|
+
action: planned?.action,
|
|
7519
|
+
raw: planned
|
|
7520
|
+
}, null, 2);
|
|
7521
|
+
}
|
|
7408
7522
|
const result = await commandForNode(ctx, sourceNode, "clone_mesh_node", {
|
|
7409
7523
|
meshId: ctx.mesh.id,
|
|
7410
7524
|
sourceNodeId: args.source_node_id,
|
|
@@ -7455,21 +7569,105 @@ async function meshRemoveNode(ctx, args) {
|
|
|
7455
7569
|
}
|
|
7456
7570
|
return JSON.stringify({ ...result || {}, ...transportFallback ? { transportFallback } : {} }, null, 2);
|
|
7457
7571
|
}
|
|
7572
|
+
async function meshCleanupWorktreeNodes(ctx, args) {
|
|
7573
|
+
const dryRun = args?.dry_run !== false;
|
|
7574
|
+
const wireArgs = {
|
|
7575
|
+
meshId: ctx.mesh.id,
|
|
7576
|
+
dryRun,
|
|
7577
|
+
...args?.node_id ? { nodeId: args.node_id } : {}
|
|
7578
|
+
};
|
|
7579
|
+
let result;
|
|
7580
|
+
try {
|
|
7581
|
+
if (args?.node_id) {
|
|
7582
|
+
const node = await findNodeWithRefresh(ctx, args.node_id);
|
|
7583
|
+
result = await commandForNode(ctx, node, "cleanup_worktree_nodes", wireArgs);
|
|
7584
|
+
} else {
|
|
7585
|
+
result = await ctx.transport.command("cleanup_worktree_nodes", wireArgs);
|
|
7586
|
+
}
|
|
7587
|
+
} catch (e) {
|
|
7588
|
+
return JSON.stringify({
|
|
7589
|
+
success: false,
|
|
7590
|
+
code: isP2pTransportUnavailableError(e) ? "p2p_unavailable" : "mesh_cleanup_worktree_nodes_failed",
|
|
7591
|
+
error: e?.message || String(e),
|
|
7592
|
+
recoveryHint: "Inspect mesh_status and retry after resolving the reported failure; per-node reasons are never hidden in a successful plan."
|
|
7593
|
+
}, null, 2);
|
|
7594
|
+
}
|
|
7595
|
+
if (!dryRun && result?.success && Array.isArray(result.entries)) {
|
|
7596
|
+
let changed = false;
|
|
7597
|
+
for (const entry of result.entries) {
|
|
7598
|
+
if (entry?.execution?.success && entry.execution.removed) {
|
|
7599
|
+
const idx = ctx.mesh.nodes.findIndex((n) => n.id === entry.nodeId);
|
|
7600
|
+
if (idx >= 0) {
|
|
7601
|
+
ctx.mesh.nodes.splice(idx, 1);
|
|
7602
|
+
changed = true;
|
|
7603
|
+
}
|
|
7604
|
+
}
|
|
7605
|
+
}
|
|
7606
|
+
if (changed) ctx.mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
7607
|
+
}
|
|
7608
|
+
return JSON.stringify(result ?? { success: false, error: "no response from daemon" }, null, 2);
|
|
7609
|
+
}
|
|
7458
7610
|
|
|
7459
7611
|
// src/tools/mesh-tools-crud.ts
|
|
7612
|
+
async function meshPlanOnboarding(transport, args, defaultMeshId) {
|
|
7613
|
+
const workspace = typeof args?.workspace === "string" ? args.workspace.trim() : "";
|
|
7614
|
+
if (!workspace) {
|
|
7615
|
+
return JSON.stringify({
|
|
7616
|
+
success: false,
|
|
7617
|
+
dryRun: true,
|
|
7618
|
+
code: "workspace_required",
|
|
7619
|
+
error: "workspace required",
|
|
7620
|
+
action: "Pass an absolute path on the daemon that owns the checkout."
|
|
7621
|
+
}, null, 2);
|
|
7622
|
+
}
|
|
7623
|
+
const meshId = typeof args?.mesh_id === "string" && args.mesh_id.trim() ? args.mesh_id.trim() : typeof defaultMeshId === "string" ? defaultMeshId.trim() : "";
|
|
7624
|
+
const result = await transport.command("plan_mesh_onboarding", {
|
|
7625
|
+
workspace,
|
|
7626
|
+
...meshId ? { meshId } : {},
|
|
7627
|
+
...args?.operation ? { operation: args.operation } : {},
|
|
7628
|
+
...typeof args?.branch === "string" && args.branch.trim() ? { branch: args.branch.trim() } : {}
|
|
7629
|
+
});
|
|
7630
|
+
return JSON.stringify(unwrapCommandPayload(result), null, 2);
|
|
7631
|
+
}
|
|
7460
7632
|
async function meshCreate(transport, args) {
|
|
7461
7633
|
const name = typeof args?.name === "string" ? args.name.trim() : "";
|
|
7462
7634
|
if (!name) {
|
|
7463
7635
|
return JSON.stringify({ success: false, error: "name required" }, null, 2);
|
|
7464
7636
|
}
|
|
7465
|
-
|
|
7466
|
-
|
|
7467
|
-
|
|
7637
|
+
let repoRemoteUrl = typeof args?.repo_remote_url === "string" ? args.repo_remote_url.trim() : "";
|
|
7638
|
+
let repoIdentity = typeof args?.repo_identity === "string" ? args.repo_identity.trim() : "";
|
|
7639
|
+
let defaultBranch = typeof args?.default_branch === "string" ? args.default_branch.trim() : "";
|
|
7640
|
+
let discovery;
|
|
7468
7641
|
if (!repoRemoteUrl && !repoIdentity) {
|
|
7469
|
-
|
|
7470
|
-
|
|
7471
|
-
|
|
7472
|
-
|
|
7642
|
+
const workspace = typeof args?.workspace === "string" && args.workspace.trim() ? args.workspace.trim() : void 0;
|
|
7643
|
+
const planned = unwrapCommandPayload(await transport.command("plan_mesh_onboarding", {
|
|
7644
|
+
...workspace ? { workspace } : {},
|
|
7645
|
+
operation: "auto"
|
|
7646
|
+
}));
|
|
7647
|
+
if (!planned?.success) {
|
|
7648
|
+
return JSON.stringify({
|
|
7649
|
+
success: false,
|
|
7650
|
+
dry_run: true,
|
|
7651
|
+
code: planned?.code || "onboarding_blocked",
|
|
7652
|
+
error: planned?.error || "Could not infer repository identity from the workspace.",
|
|
7653
|
+
action: planned?.action,
|
|
7654
|
+
raw: planned
|
|
7655
|
+
}, null, 2);
|
|
7656
|
+
}
|
|
7657
|
+
if (planned?.plan?.kind !== "create_mesh_and_onboard") {
|
|
7658
|
+
return JSON.stringify({
|
|
7659
|
+
success: false,
|
|
7660
|
+
dry_run: true,
|
|
7661
|
+
code: "compatible_mesh_exists",
|
|
7662
|
+
error: planned?.plan?.summary || "A compatible mesh already exists.",
|
|
7663
|
+
action: "Use mesh_add_node with the compatible mesh instead of creating a duplicate mesh.",
|
|
7664
|
+
raw: planned
|
|
7665
|
+
}, null, 2);
|
|
7666
|
+
}
|
|
7667
|
+
discovery = planned.discovery;
|
|
7668
|
+
repoRemoteUrl = discovery?.origin?.urls?.[0] || discovery?.upstream?.urls?.[0] || "";
|
|
7669
|
+
repoIdentity = discovery?.repoIdentity || "";
|
|
7670
|
+
defaultBranch ||= discovery?.defaultBranch || "";
|
|
7473
7671
|
}
|
|
7474
7672
|
const createResult = await transport.command("create_mesh", {
|
|
7475
7673
|
name,
|
|
@@ -7499,7 +7697,9 @@ async function meshCreate(transport, args) {
|
|
|
7499
7697
|
const workspace = typeof args?.workspace === "string" && args.workspace.trim() ? args.workspace.trim() : "";
|
|
7500
7698
|
const addResult = await transport.command("add_mesh_node", {
|
|
7501
7699
|
meshId: mesh.id,
|
|
7502
|
-
...workspace ? { workspace } : {},
|
|
7700
|
+
...workspace || discovery?.repoRoot ? { workspace: discovery?.repoRoot || workspace } : {},
|
|
7701
|
+
...discovery?.repoRoot ? { repoRoot: discovery.repoRoot } : {},
|
|
7702
|
+
...discovery?.isLinkedWorktree === true ? { isLocalWorktree: true } : {},
|
|
7503
7703
|
inlineMesh: mesh
|
|
7504
7704
|
});
|
|
7505
7705
|
const addPayload = unwrapCommandPayload(addResult);
|
|
@@ -7522,12 +7722,31 @@ async function meshAddNode(transport, args, defaultMeshId) {
|
|
|
7522
7722
|
return JSON.stringify({ success: false, error: "workspace required (absolute path to the repo checkout on the target daemon)." }, null, 2);
|
|
7523
7723
|
}
|
|
7524
7724
|
const providerPriority = Array.isArray(args?.provider_priority) ? args.provider_priority.map((v) => typeof v === "string" ? v.trim() : "").filter(Boolean) : typeof args?.provider_priority === "string" ? args.provider_priority.split(",").map((v) => v.trim()).filter(Boolean) : [];
|
|
7525
|
-
const
|
|
7725
|
+
const planResult = await transport.command("plan_mesh_onboarding", {
|
|
7526
7726
|
meshId,
|
|
7527
7727
|
workspace,
|
|
7728
|
+
operation: "add_existing",
|
|
7729
|
+
...args?.inline_mesh ? { inlineMesh: args.inline_mesh } : {}
|
|
7730
|
+
});
|
|
7731
|
+
const planPayload = unwrapCommandPayload(planResult);
|
|
7732
|
+
if (!planPayload?.success) {
|
|
7733
|
+
return JSON.stringify({
|
|
7734
|
+
success: false,
|
|
7735
|
+
dry_run: true,
|
|
7736
|
+
code: planPayload?.code || "onboarding_blocked",
|
|
7737
|
+
error: planPayload?.error || "Repo Mesh onboarding preflight failed",
|
|
7738
|
+
action: planPayload?.action,
|
|
7739
|
+
raw: planPayload ?? planResult
|
|
7740
|
+
}, null, 2);
|
|
7741
|
+
}
|
|
7742
|
+
const discoveredWorkspace = typeof planPayload?.discovery?.repoRoot === "string" ? planPayload.discovery.repoRoot : workspace;
|
|
7743
|
+
const addResult = await transport.command("add_mesh_node", {
|
|
7744
|
+
meshId,
|
|
7745
|
+
workspace: discoveredWorkspace,
|
|
7746
|
+
repoRoot: discoveredWorkspace,
|
|
7528
7747
|
...args?.read_only === true ? { readOnly: true } : {},
|
|
7529
7748
|
...providerPriority.length ? { providerPriority } : {},
|
|
7530
|
-
...args?.is_worktree === true ? { isLocalWorktree: true } : {},
|
|
7749
|
+
...args?.is_worktree === true || planPayload?.discovery?.isLinkedWorktree === true ? { isLocalWorktree: true } : {},
|
|
7531
7750
|
...args?.inline_mesh ? { inlineMesh: args.inline_mesh } : {}
|
|
7532
7751
|
});
|
|
7533
7752
|
const addPayload = unwrapCommandPayload(addResult);
|
|
@@ -7668,11 +7887,13 @@ async function meshRefinePlan(ctx, args) {
|
|
|
7668
7887
|
}
|
|
7669
7888
|
async function meshRefineNode(ctx, args) {
|
|
7670
7889
|
const node = await findNodeWithRefresh(ctx, args.node_id);
|
|
7890
|
+
const coordinatorDaemonId = resolveCoordinatorDaemonId(ctx);
|
|
7671
7891
|
const result = await commandForNode(ctx, node, "refine_mesh_node", {
|
|
7672
7892
|
meshId: ctx.mesh.id,
|
|
7673
7893
|
nodeId: args.node_id,
|
|
7674
7894
|
...args.execute !== void 0 ? { execute: args.execute } : {},
|
|
7675
7895
|
...args.dry_run !== void 0 ? { dryRun: args.dry_run } : {},
|
|
7896
|
+
...coordinatorDaemonId ? { coordinatorDaemonId } : {},
|
|
7676
7897
|
inlineMesh: ctx.mesh
|
|
7677
7898
|
});
|
|
7678
7899
|
if (result?.success && result.async !== true && result.removeResult?.removed !== false) {
|
|
@@ -7687,11 +7908,13 @@ async function meshRefineNode(ctx, args) {
|
|
|
7687
7908
|
async function meshRefineBatch(ctx, args = {}) {
|
|
7688
7909
|
await refreshMeshFromDaemon(ctx);
|
|
7689
7910
|
const nodeIds = Array.isArray(args.node_ids) ? args.node_ids.filter((v) => typeof v === "string" && v.trim().length > 0).map((v) => v.trim()) : void 0;
|
|
7911
|
+
const coordinatorDaemonId = resolveCoordinatorDaemonId(ctx);
|
|
7690
7912
|
const result = await ctx.transport.command("batch_refine_mesh_nodes", {
|
|
7691
7913
|
meshId: ctx.mesh.id,
|
|
7692
7914
|
...nodeIds ? { nodeIds } : {},
|
|
7693
7915
|
...args.execute !== void 0 ? { execute: args.execute } : {},
|
|
7694
7916
|
...args.dry_run !== void 0 ? { dryRun: args.dry_run } : {},
|
|
7917
|
+
...coordinatorDaemonId ? { coordinatorDaemonId } : {},
|
|
7695
7918
|
inlineMesh: ctx.mesh
|
|
7696
7919
|
});
|
|
7697
7920
|
const payload = unwrapCommandPayload(result) ?? result;
|
|
@@ -7916,7 +8139,7 @@ function formatChatResult(result, sessionId, format, limit = 50, compact = false
|
|
|
7916
8139
|
}
|
|
7917
8140
|
const messages = result?.messages ?? result?.data?.messages ?? [];
|
|
7918
8141
|
const source = { ...result, messages };
|
|
7919
|
-
const compactPayload = compact ? compactChatPayload(source, { sessionId: sessionId ?? null, limit }) : null;
|
|
8142
|
+
const compactPayload = compact ? compactChatPayload(source, { sessionId: sessionId ?? null, limit, preserveTurn: true }) : null;
|
|
7920
8143
|
const outputMessages = compact ? compactPayload.messages : messages;
|
|
7921
8144
|
if (format === "json") {
|
|
7922
8145
|
if (compact && compactPayload) {
|
|
@@ -8649,13 +8872,13 @@ ${raw.output}` : "";
|
|
|
8649
8872
|
// src/tools/launch-session.ts
|
|
8650
8873
|
var LAUNCH_SESSION_TOOL = {
|
|
8651
8874
|
name: "launch_session",
|
|
8652
|
-
description: "Launch a new agent session on the daemon. Supports CLI agents (e.g. hermes-cli, claude-cli, gemini-cli), ACP agents (e.g. claude-acp), and IDEs (e.g. cursor, vscode).",
|
|
8875
|
+
description: "Launch a new agent session on the daemon. Supports CLI agents (e.g. kimi, hermes-cli, claude-cli, gemini-cli), ACP agents (e.g. claude-acp), and IDEs (e.g. cursor, vscode).",
|
|
8653
8876
|
inputSchema: {
|
|
8654
8877
|
type: "object",
|
|
8655
8878
|
properties: {
|
|
8656
8879
|
type: {
|
|
8657
8880
|
type: "string",
|
|
8658
|
-
description: "Provider type to launch. CLI examples: hermes-cli, claude-cli, gemini-cli. ACP examples: claude-acp. IDE examples: cursor, vscode."
|
|
8881
|
+
description: "Provider type to launch. CLI examples: kimi, hermes-cli, claude-cli, gemini-cli. ACP examples: claude-acp. IDE examples: cursor, vscode. Manifest aliases (e.g. codex \u2192 codex-cli) resolve to the canonical provider type."
|
|
8659
8882
|
},
|
|
8660
8883
|
workspace: {
|
|
8661
8884
|
type: "string",
|
|
@@ -8669,14 +8892,48 @@ var LAUNCH_SESSION_TOOL = {
|
|
|
8669
8892
|
required: ["type"]
|
|
8670
8893
|
}
|
|
8671
8894
|
};
|
|
8895
|
+
function legacyHeuristicRoute(type) {
|
|
8896
|
+
const isCliOrAcp = type.includes("-cli") || type.includes("-acp") || type === "codex";
|
|
8897
|
+
return { route: isCliOrAcp ? "cli" : "ide", canonicalType: type };
|
|
8898
|
+
}
|
|
8899
|
+
async function resolveProviderRoute(transport, requestedType) {
|
|
8900
|
+
const type = requestedType.trim();
|
|
8901
|
+
if (!type) return { error: "type is required" };
|
|
8902
|
+
let catalog;
|
|
8903
|
+
try {
|
|
8904
|
+
catalog = await transport.command("list_provider_availability", {});
|
|
8905
|
+
} catch {
|
|
8906
|
+
catalog = null;
|
|
8907
|
+
}
|
|
8908
|
+
const providers = Array.isArray(catalog?.providers) ? catalog.providers : null;
|
|
8909
|
+
if (!catalog || catalog.success === false || !providers) {
|
|
8910
|
+
return legacyHeuristicRoute(type);
|
|
8911
|
+
}
|
|
8912
|
+
const query = type.toLowerCase();
|
|
8913
|
+
const hit = providers.find((p) => {
|
|
8914
|
+
if (!p || typeof p.type !== "string") return false;
|
|
8915
|
+
if (p.type.toLowerCase() === query) return true;
|
|
8916
|
+
const aliases = Array.isArray(p.aliases) ? p.aliases : [];
|
|
8917
|
+
return aliases.some((alias) => typeof alias === "string" && alias.toLowerCase() === query);
|
|
8918
|
+
});
|
|
8919
|
+
if (!hit) {
|
|
8920
|
+
const known = providers.map((p) => p && typeof p.type === "string" ? p.type : null).filter(Boolean).sort();
|
|
8921
|
+
return {
|
|
8922
|
+
error: `Unknown provider type '${type}'. Known provider types: ${known.join(", ")}`
|
|
8923
|
+
};
|
|
8924
|
+
}
|
|
8925
|
+
const route = hit.category === "cli" || hit.category === "acp" ? "cli" : "ide";
|
|
8926
|
+
return { route, canonicalType: hit.type };
|
|
8927
|
+
}
|
|
8672
8928
|
async function launchSession(transport, args) {
|
|
8673
|
-
const
|
|
8674
|
-
|
|
8675
|
-
const
|
|
8929
|
+
const resolved = await resolveProviderRoute(transport, args.type);
|
|
8930
|
+
if ("error" in resolved) return `Error: ${resolved.error}`;
|
|
8931
|
+
const commandType = resolved.route === "cli" ? "launch_cli" : "launch_ide";
|
|
8932
|
+
const payload = resolved.route === "cli" ? { cliType: resolved.canonicalType, dir: args.workspace ?? "~", ...args.model ? { model: args.model } : {} } : { ideType: resolved.canonicalType, enableCdp: true };
|
|
8676
8933
|
const result = await transport.command(commandType, payload);
|
|
8677
8934
|
if (result?.success === false) return `Error: ${result.error ?? "launch failed"}`;
|
|
8678
8935
|
const id = result?.id ?? result?.sessionId;
|
|
8679
|
-
return id ? `Session launched. id: ${id}, type: ${
|
|
8936
|
+
return id ? `Session launched. id: ${id}, type: ${resolved.canonicalType}` : `Launched: ${JSON.stringify(result)}`;
|
|
8680
8937
|
}
|
|
8681
8938
|
|
|
8682
8939
|
// src/tools/stop-session.ts
|
|
@@ -8844,7 +9101,7 @@ async function startMcpServer(opts) {
|
|
|
8844
9101
|
const meshCtx = { mesh, transport, ...localDaemonId ? { localDaemonId } : {}, ...localMachineId ? { localMachineId } : {}, ...coordinatorHostname ? { coordinatorHostname } : {}, ...coordinatorSessionId ? { coordinatorSessionId } : {} };
|
|
8845
9102
|
const coordinatorPrompt = await buildMeshModeCoordinatorPrompt(mesh);
|
|
8846
9103
|
const server2 = new import_server.Server(
|
|
8847
|
-
{ name: "adhdev-mcp-server", version: "1.0.
|
|
9104
|
+
{ name: "adhdev-mcp-server", version: "1.0.28" },
|
|
8848
9105
|
{ capabilities: { tools: {}, resources: {} } }
|
|
8849
9106
|
);
|
|
8850
9107
|
const { ListResourcesRequestSchema, ReadResourceRequestSchema } = await import("@modelcontextprotocol/sdk/types.js");
|
|
@@ -8929,11 +9186,14 @@ async function startMcpServer(opts) {
|
|
|
8929
9186
|
case "mesh_list_pending_approvals":
|
|
8930
9187
|
text = await meshListPendingApprovals(meshCtx, a);
|
|
8931
9188
|
break;
|
|
9189
|
+
case "mesh_plan_onboarding":
|
|
9190
|
+
text = await meshPlanOnboarding(meshCtx.transport, a, meshCtx.mesh.id);
|
|
9191
|
+
break;
|
|
8932
9192
|
case "mesh_create":
|
|
8933
9193
|
text = await meshCreate(meshCtx.transport, a);
|
|
8934
9194
|
break;
|
|
8935
9195
|
case "mesh_add_node":
|
|
8936
|
-
text = await meshAddNode(meshCtx.transport, a, meshCtx.mesh.id);
|
|
9196
|
+
text = await meshAddNode(meshCtx.transport, { ...a, inline_mesh: meshCtx.mesh }, meshCtx.mesh.id);
|
|
8937
9197
|
break;
|
|
8938
9198
|
case "mesh_clone_node":
|
|
8939
9199
|
text = await meshCloneNode(meshCtx, a);
|
|
@@ -8941,6 +9201,9 @@ async function startMcpServer(opts) {
|
|
|
8941
9201
|
case "mesh_remove_node":
|
|
8942
9202
|
text = await meshRemoveNode(meshCtx, a);
|
|
8943
9203
|
break;
|
|
9204
|
+
case "mesh_cleanup_worktree_nodes":
|
|
9205
|
+
text = await meshCleanupWorktreeNodes(meshCtx, a);
|
|
9206
|
+
break;
|
|
8944
9207
|
case "mesh_refine_node":
|
|
8945
9208
|
text = await meshRefineNode(meshCtx, a);
|
|
8946
9209
|
break;
|
|
@@ -9075,6 +9338,7 @@ async function startMcpServer(opts) {
|
|
|
9075
9338
|
// Mesh bootstrap: create a mesh + register its first node from an MCP-only agent.
|
|
9076
9339
|
// Exposed in standard mode precisely because this is the no-mesh-yet context —
|
|
9077
9340
|
// mesh mode refuses to boot without an existing meshId (see the mesh-mode block above).
|
|
9341
|
+
MESH_PLAN_ONBOARDING_TOOL,
|
|
9078
9342
|
MESH_CREATE_TOOL,
|
|
9079
9343
|
MESH_ADD_NODE_TOOL,
|
|
9080
9344
|
...isLocal ? [SCREENSHOT_TOOL] : []
|
|
@@ -9170,6 +9434,10 @@ async function startMcpServer(opts) {
|
|
|
9170
9434
|
const text = await meshCreate(transport, a);
|
|
9171
9435
|
return { content: [{ type: "text", text }] };
|
|
9172
9436
|
}
|
|
9437
|
+
case "mesh_plan_onboarding": {
|
|
9438
|
+
const text = await meshPlanOnboarding(transport, a);
|
|
9439
|
+
return { content: [{ type: "text", text }] };
|
|
9440
|
+
}
|
|
9173
9441
|
case "mesh_add_node": {
|
|
9174
9442
|
const text = await meshAddNode(transport, a);
|
|
9175
9443
|
return { content: [{ type: "text", text }] };
|