@adhdev/daemon-standalone 0.9.77-rc.4 → 0.9.77-rc.40

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.
@@ -25120,6 +25120,7 @@ __export(dist_exports, {
25120
25120
  buildThoughtChatMessage: () => buildThoughtChatMessage,
25121
25121
  buildToolChatMessage: () => buildToolChatMessage,
25122
25122
  buildUserChatMessage: () => buildUserChatMessage,
25123
+ cancelTask: () => cancelTask,
25123
25124
  claimNextTask: () => claimNextTask,
25124
25125
  classifyChatMessageVisibility: () => classifyChatMessageVisibility,
25125
25126
  classifyHotChatSessionsForSubscriptionFlush: () => classifyHotChatSessionsForSubscriptionFlush,
@@ -25163,6 +25164,7 @@ __export(dist_exports, {
25163
25164
  getLogLevel: () => getLogLevel,
25164
25165
  getMesh: () => getMesh,
25165
25166
  getMeshByRepo: () => getMeshByRepo,
25167
+ getMeshQueueStats: () => getMeshQueueStats,
25166
25168
  getNpmExecOptions: () => getNpmExecOptions,
25167
25169
  getQueue: () => getQueue,
25168
25170
  getRecentActivity: () => getRecentActivity,
@@ -25231,6 +25233,7 @@ __export(dist_exports, {
25231
25233
  registerExtensionProviders: () => registerExtensionProviders,
25232
25234
  removeNode: () => removeNode,
25233
25235
  removeWorktree: () => removeWorktree,
25236
+ requeueTask: () => requeueTask,
25234
25237
  resetConfig: () => resetConfig,
25235
25238
  resetDebugRuntimeConfig: () => resetDebugRuntimeConfig,
25236
25239
  resetState: () => resetState,
@@ -26029,6 +26032,7 @@ function enqueueTask(meshId, message, opts) {
26029
26032
  message,
26030
26033
  status: "pending",
26031
26034
  targetNodeId: opts?.targetNodeId,
26035
+ targetSessionId: opts?.targetSessionId,
26032
26036
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
26033
26037
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
26034
26038
  };
@@ -26046,9 +26050,14 @@ function getQueue(meshId, opts) {
26046
26050
  }
26047
26051
  function claimNextTask(meshId, nodeId, sessionId) {
26048
26052
  const queue = readQueue(meshId);
26049
- let targetIdx = queue.findIndex((q) => q.status === "pending" && q.targetNodeId === nodeId);
26053
+ const hasActiveAssignment = queue.some((q) => q.status === "assigned" && (q.assignedSessionId === sessionId || q.assignedNodeId === nodeId));
26054
+ if (hasActiveAssignment) return null;
26055
+ let targetIdx = queue.findIndex((q) => q.status === "pending" && q.targetSessionId === sessionId);
26050
26056
  if (targetIdx === -1) {
26051
- targetIdx = queue.findIndex((q) => q.status === "pending" && !q.targetNodeId);
26057
+ targetIdx = queue.findIndex((q) => q.status === "pending" && q.targetNodeId === nodeId && !q.targetSessionId);
26058
+ }
26059
+ if (targetIdx === -1) {
26060
+ targetIdx = queue.findIndex((q) => q.status === "pending" && !q.targetNodeId && !q.targetSessionId);
26052
26061
  }
26053
26062
  if (targetIdx === -1) return null;
26054
26063
  const entry = queue[targetIdx];
@@ -26068,6 +26077,40 @@ function updateTaskStatus(meshId, taskId, status) {
26068
26077
  writeQueue(meshId, queue);
26069
26078
  return queue[idx];
26070
26079
  }
26080
+ function cancelTask(meshId, taskId, opts) {
26081
+ const queue = readQueue(meshId);
26082
+ const idx = queue.findIndex((q) => q.id === taskId);
26083
+ if (idx === -1) return null;
26084
+ const now = (/* @__PURE__ */ new Date()).toISOString();
26085
+ queue[idx].status = "cancelled";
26086
+ queue[idx].updatedAt = now;
26087
+ queue[idx].cancelledAt = now;
26088
+ if (opts?.reason) queue[idx].cancelReason = opts.reason;
26089
+ writeQueue(meshId, queue);
26090
+ return queue[idx];
26091
+ }
26092
+ function requeueTask(meshId, taskId, opts) {
26093
+ const queue = readQueue(meshId);
26094
+ const idx = queue.findIndex((q) => q.id === taskId);
26095
+ if (idx === -1) return null;
26096
+ const entry = queue[idx];
26097
+ const now = (/* @__PURE__ */ new Date()).toISOString();
26098
+ entry.status = "pending";
26099
+ delete entry.assignedNodeId;
26100
+ delete entry.assignedSessionId;
26101
+ delete entry.cancelledAt;
26102
+ delete entry.cancelReason;
26103
+ if (opts?.clearTargetNode) delete entry.targetNodeId;
26104
+ if (typeof opts?.targetNodeId === "string") entry.targetNodeId = opts.targetNodeId;
26105
+ if (opts?.clearTargetSession !== false) delete entry.targetSessionId;
26106
+ if (typeof opts?.targetSessionId === "string") entry.targetSessionId = opts.targetSessionId;
26107
+ entry.updatedAt = now;
26108
+ entry.requeuedAt = now;
26109
+ entry.requeueCount = (entry.requeueCount || 0) + 1;
26110
+ if (opts?.reason) entry.requeueReason = opts.reason;
26111
+ writeQueue(meshId, queue);
26112
+ return entry;
26113
+ }
26071
26114
  function updateSessionTaskStatus(meshId, sessionId, status) {
26072
26115
  const queue = readQueue(meshId);
26073
26116
  for (let i = queue.length - 1; i >= 0; i--) {
@@ -26086,7 +26129,14 @@ function getMeshQueueStats(meshId) {
26086
26129
  pending: queue.filter((q) => q.status === "pending").length,
26087
26130
  assigned: queue.filter((q) => q.status === "assigned").length,
26088
26131
  completed: queue.filter((q) => q.status === "completed").length,
26089
- failed: queue.filter((q) => q.status === "failed").length
26132
+ failed: queue.filter((q) => q.status === "failed").length,
26133
+ cancelled: queue.filter((q) => q.status === "cancelled").length,
26134
+ activeAssignments: queue.filter((q) => q.status === "assigned").map((q) => ({
26135
+ id: q.id,
26136
+ nodeId: q.assignedNodeId,
26137
+ sessionId: q.assignedSessionId,
26138
+ message: q.message
26139
+ }))
26090
26140
  };
26091
26141
  }
26092
26142
  function setLogLevel(level) {
@@ -26245,6 +26295,9 @@ function drainPendingMeshCoordinatorEvents() {
26245
26295
  function readNonEmptyString(value) {
26246
26296
  return typeof value === "string" && value.trim() ? value.trim() : "";
26247
26297
  }
26298
+ function resolveEventSessionId(event, fallback) {
26299
+ return readNonEmptyString(event.targetSessionId) || readNonEmptyString(event.sessionId) || readNonEmptyString(event.instanceId) || readNonEmptyString(fallback);
26300
+ }
26248
26301
  function isMeshCoordinatorEvent(eventName) {
26249
26302
  return typeof eventName === "string" && MESH_COORDINATOR_EVENTS.has(eventName);
26250
26303
  }
@@ -26256,38 +26309,74 @@ function formatCompletionMetadata(event) {
26256
26309
  ].filter(Boolean);
26257
26310
  return parts.length > 0 ? ` (${parts.join("; ")})` : "";
26258
26311
  }
26312
+ function getMeshWithCache(components, meshId) {
26313
+ const localMesh = getMesh(meshId);
26314
+ if (localMesh) return localMesh;
26315
+ return components.router?.getCachedInlineMesh(meshId);
26316
+ }
26259
26317
  function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType) {
26260
26318
  const task = claimNextTask(meshId, nodeId, sessionId);
26261
- if (!task) return false;
26319
+ if (!task) {
26320
+ return false;
26321
+ }
26262
26322
  LOG.info("MeshQueue", `Node ${nodeId} (${sessionId}) pulled task ${task.id}`);
26323
+ const mesh = getMeshWithCache(components, meshId);
26324
+ const node = mesh?.nodes.find((n) => n.id === nodeId);
26325
+ if (node?.daemonId && components.dispatchMeshCommand) {
26326
+ const isLocalNode = components.cliManager.adapters.has(sessionId);
26327
+ if (!isLocalNode) {
26328
+ components.dispatchMeshCommand(node.daemonId, "agent_command", {
26329
+ targetSessionId: sessionId,
26330
+ cliType: providerType,
26331
+ action: "send_chat",
26332
+ message: task.message
26333
+ }).catch((e) => {
26334
+ LOG.error("MeshQueue", `Failed to dispatch task via P2P to remote node ${nodeId}: ${e?.message}`);
26335
+ updateTaskStatus(meshId, task.id, "failed");
26336
+ });
26337
+ return true;
26338
+ }
26339
+ }
26263
26340
  components.cliManager.handleCliCommand("agent_command", {
26264
26341
  targetSessionId: sessionId,
26265
26342
  cliType: providerType,
26266
26343
  action: "send_chat",
26267
- input: task.message
26344
+ message: task.message
26268
26345
  }).catch((e) => {
26269
- LOG.error("MeshQueue", `Failed to dispatch task to node ${nodeId}: ${e?.message}`);
26346
+ LOG.error("MeshQueue", `Failed to dispatch task locally to node ${nodeId}: ${e?.message}`);
26347
+ updateTaskStatus(meshId, task.id, "failed");
26270
26348
  });
26271
26349
  return true;
26272
26350
  }
26273
26351
  function triggerMeshQueue(components, meshId) {
26274
- const mesh = getMesh(meshId);
26352
+ const mesh = getMeshWithCache(components, meshId);
26275
26353
  if (!mesh) return;
26276
26354
  const cliInstances = components.instanceManager.getByCategory("cli");
26277
26355
  for (const inst of cliInstances) {
26278
26356
  const state = inst.getState();
26279
26357
  const settings = state.settings || {};
26280
26358
  const instMeshId = readNonEmptyString(settings.meshNodeFor);
26281
- if (instMeshId !== meshId && !settings.launchedByCoordinator) continue;
26359
+ if (instMeshId !== meshId) continue;
26282
26360
  const nodeId = readNonEmptyString(settings.meshNodeId) || readNonEmptyString(settings.nodeId);
26283
26361
  if (!nodeId) continue;
26284
- if (state.status !== "idle" && state.status !== "stopped" && state.activeChat?.status !== "waiting_input") continue;
26362
+ const status = readNonEmptyString(state.status).toLowerCase();
26363
+ if (["stopped", "failed", "terminated", "exited", "closed"].includes(status)) continue;
26364
+ if (status !== "idle" && state.activeChat?.status !== "waiting_input") continue;
26285
26365
  const sessionId = state.instanceId;
26286
26366
  const providerType = state.type || readNonEmptyString(settings.providerType);
26287
26367
  if (providerType) {
26288
26368
  tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType);
26289
26369
  }
26290
26370
  }
26371
+ for (const [key, idle] of remoteIdleSessions.entries()) {
26372
+ const node = mesh.nodes.find((n) => n.id === idle.nodeId);
26373
+ if (node) {
26374
+ const assigned = tryAssignQueueTask(components, meshId, idle.nodeId, idle.sessionId, idle.providerType);
26375
+ if (assigned) {
26376
+ remoteIdleSessions.delete(key);
26377
+ }
26378
+ }
26379
+ }
26291
26380
  }
26292
26381
  function buildMeshSystemMessage(args) {
26293
26382
  const metadata = formatCompletionMetadata(args.metadataEvent);
@@ -26334,20 +26423,67 @@ Do NOT retry on this node. Consider reassigning to a different node or asking th
26334
26423
  return "";
26335
26424
  }
26336
26425
  function injectMeshSystemMessage(components, args) {
26426
+ let completedTaskForLedger = null;
26337
26427
  if (args.event === "agent:generating_completed") {
26338
- const sessionId = readNonEmptyString(args.metadataEvent.targetSessionId);
26339
- const nodeId = readNonEmptyString(args.metadataEvent.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId);
26428
+ const sessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
26429
+ const nodeId = readNonEmptyString(args.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId);
26340
26430
  const providerType = readNonEmptyString(args.metadataEvent.providerType);
26341
26431
  if (sessionId) {
26342
- updateSessionTaskStatus(args.meshId, sessionId, "completed");
26432
+ const completedTask = updateSessionTaskStatus(args.meshId, sessionId, "completed");
26433
+ completedTaskForLedger = completedTask ? { id: completedTask.id } : null;
26343
26434
  if (nodeId && providerType) {
26344
26435
  setTimeout(() => {
26345
26436
  tryAssignQueueTask(components, args.meshId, nodeId, sessionId, providerType);
26346
26437
  }, 500);
26347
26438
  }
26348
26439
  }
26440
+ } else if (args.event === "agent:ready") {
26441
+ const sessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
26442
+ const nodeId = readNonEmptyString(args.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId);
26443
+ const providerType = readNonEmptyString(args.metadataEvent.providerType);
26444
+ const completedTask = sessionId ? updateSessionTaskStatus(args.meshId, sessionId, "completed") : null;
26445
+ if (completedTask) {
26446
+ completedTaskForLedger = { id: completedTask.id };
26447
+ try {
26448
+ appendLedgerEntry(args.meshId, {
26449
+ kind: "task_completed",
26450
+ nodeId: nodeId || void 0,
26451
+ sessionId,
26452
+ providerType: providerType || void 0,
26453
+ payload: {
26454
+ event: args.event,
26455
+ nodeLabel: args.nodeLabel,
26456
+ taskId: completedTask.id,
26457
+ completedViaReady: true,
26458
+ providerSessionId: readNonEmptyString(args.metadataEvent.providerSessionId) || void 0,
26459
+ finalSummary: readNonEmptyString(args.metadataEvent.finalSummary) || void 0
26460
+ }
26461
+ });
26462
+ } catch (e) {
26463
+ LOG.warn("MeshLedger", `Failed to record task_completed from ready: ${e?.message || e}`);
26464
+ }
26465
+ }
26466
+ if (sessionId && nodeId && providerType) {
26467
+ remoteIdleSessions.set(`${nodeId}:${sessionId}`, { nodeId, sessionId, providerType });
26468
+ setTimeout(() => {
26469
+ const assigned = tryAssignQueueTask(components, args.meshId, nodeId, sessionId, providerType);
26470
+ if (assigned) {
26471
+ remoteIdleSessions.delete(`${nodeId}:${sessionId}`);
26472
+ }
26473
+ }, 500);
26474
+ }
26475
+ } else if (args.event === "agent:generating_started") {
26476
+ const sessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
26477
+ const nodeId = readNonEmptyString(args.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId);
26478
+ if (sessionId && nodeId) {
26479
+ remoteIdleSessions.delete(`${nodeId}:${sessionId}`);
26480
+ }
26349
26481
  } else if (args.event === "agent:stopped") {
26350
- const sessionId = readNonEmptyString(args.metadataEvent.targetSessionId);
26482
+ const sessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
26483
+ const nodeId = readNonEmptyString(args.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId);
26484
+ if (sessionId && nodeId) {
26485
+ remoteIdleSessions.delete(`${nodeId}:${sessionId}`);
26486
+ }
26351
26487
  if (sessionId) {
26352
26488
  updateSessionTaskStatus(args.meshId, sessionId, "failed");
26353
26489
  }
@@ -26357,13 +26493,15 @@ function injectMeshSystemMessage(components, args) {
26357
26493
  try {
26358
26494
  appendLedgerEntry(args.meshId, {
26359
26495
  kind: ledgerKind,
26360
- nodeId: readNonEmptyString(args.metadataEvent.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId) || void 0,
26361
- sessionId: readNonEmptyString(args.metadataEvent.targetSessionId) || void 0,
26496
+ nodeId: readNonEmptyString(args.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId) || void 0,
26497
+ sessionId: resolveEventSessionId(args.metadataEvent, args.sourceInstanceId) || void 0,
26362
26498
  providerType: readNonEmptyString(args.metadataEvent.providerType) || void 0,
26363
26499
  payload: {
26364
26500
  event: args.event,
26365
26501
  nodeLabel: args.nodeLabel,
26366
- providerSessionId: readNonEmptyString(args.metadataEvent.providerSessionId) || void 0
26502
+ taskId: completedTaskForLedger?.id || void 0,
26503
+ providerSessionId: readNonEmptyString(args.metadataEvent.providerSessionId) || void 0,
26504
+ finalSummary: readNonEmptyString(args.metadataEvent.finalSummary) || void 0
26367
26505
  }
26368
26506
  });
26369
26507
  } catch (e) {
@@ -26376,8 +26514,8 @@ function injectMeshSystemMessage(components, args) {
26376
26514
  const mesh = getMesh(args.meshId);
26377
26515
  const maxRetries = mesh?.policy?.maxTaskRetries ?? 1;
26378
26516
  recoveryContext = getSessionRecoveryContext(args.meshId, {
26379
- sessionId: readNonEmptyString(args.metadataEvent.targetSessionId) || void 0,
26380
- nodeId: readNonEmptyString(args.metadataEvent.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId) || void 0,
26517
+ sessionId: resolveEventSessionId(args.metadataEvent, args.sourceInstanceId) || void 0,
26518
+ nodeId: readNonEmptyString(args.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId) || void 0,
26381
26519
  maxRetries
26382
26520
  });
26383
26521
  recoveryContext.failedProviderType = readNonEmptyString(args.metadataEvent.providerType) || null;
@@ -26472,12 +26610,14 @@ function handleMeshForwardEvent(components, payload) {
26472
26610
  const nodeLabel = nodeId ? `Node '${nodeId}'` : workspace ? `Agent at ${workspace}` : "Remote agent";
26473
26611
  return injectMeshSystemMessage(components, {
26474
26612
  meshId,
26613
+ nodeId,
26475
26614
  nodeLabel,
26476
26615
  event: eventName,
26477
26616
  metadataEvent: {
26478
- targetSessionId: readNonEmptyString(payload.targetSessionId) || readNonEmptyString(payload.sessionId),
26617
+ targetSessionId: readNonEmptyString(payload.targetSessionId) || readNonEmptyString(payload.sessionId) || readNonEmptyString(payload.instanceId),
26479
26618
  providerType: readNonEmptyString(payload.providerType),
26480
- providerSessionId: readNonEmptyString(payload.providerSessionId)
26619
+ providerSessionId: readNonEmptyString(payload.providerSessionId),
26620
+ finalSummary: readNonEmptyString(payload.finalSummary) || readNonEmptyString(payload.summary)
26481
26621
  }
26482
26622
  });
26483
26623
  }
@@ -26496,15 +26636,17 @@ function setupMeshEventForwarding(components) {
26496
26636
  const meshIdFromRuntime = readNonEmptyString(settings.meshNodeFor);
26497
26637
  const isMeshDelegate = Boolean(meshIdFromRuntime || settings.launchedByCoordinator);
26498
26638
  if (!isMeshDelegate) return;
26499
- const mesh = meshIdFromRuntime ? getMesh(meshIdFromRuntime) : getMeshByRepo(workspace);
26639
+ const mesh = meshIdFromRuntime ? getMeshWithCache(components, meshIdFromRuntime) : getMeshByRepo(workspace);
26500
26640
  const meshId = meshIdFromRuntime || readNonEmptyString(mesh?.id);
26501
26641
  if (!meshId) return;
26502
26642
  const targetNode = mesh?.nodes?.find((n) => n.workspace === workspace);
26503
26643
  const runtimeNodeId = readNonEmptyString(settings.meshNodeId);
26644
+ const resolvedNodeId = targetNode?.id || runtimeNodeId;
26504
26645
  const nodeLabel = targetNode ? `Node '${targetNode.id}'` : runtimeNodeId ? `Node '${runtimeNodeId}'` : `Agent at ${workspace}`;
26505
26646
  injectMeshSystemMessage(components, {
26506
26647
  meshId,
26507
26648
  sourceInstanceId: instanceId,
26649
+ nodeId: resolvedNodeId,
26508
26650
  nodeLabel,
26509
26651
  event: event.event,
26510
26652
  metadataEvent: event
@@ -33701,11 +33843,13 @@ async function handleOpenPanel(h, args) {
33701
33843
  async function handlePtyInput(h, args) {
33702
33844
  const { cliType, data, targetSessionId } = args || {};
33703
33845
  if (!data) return { success: false, error: "data required" };
33846
+ const cleanData = typeof data === "string" ? data.replace(/\x1b\[[?>][0-9;]*c/g, "") : data;
33847
+ if (!cleanData) return { success: true };
33704
33848
  const adapter = h.getCliAdapter(targetSessionId || cliType);
33705
33849
  if (!adapter || typeof adapter.writeRaw !== "function") {
33706
33850
  return { success: false, error: `CLI adapter not found: ${targetSessionId || cliType || "unknown"}` };
33707
33851
  }
33708
- await adapter.writeRaw(data);
33852
+ await adapter.writeRaw(cleanData);
33709
33853
  return { success: true };
33710
33854
  }
33711
33855
  function handlePtyResize(_h, args) {
@@ -34532,9 +34676,6 @@ function buildCoordinatorDelegatedCliLaunchOptions(input) {
34532
34676
  const cliType = String(input.cliType || "").trim();
34533
34677
  const cliArgs = Array.isArray(input.cliArgs) ? [...input.cliArgs] : [];
34534
34678
  const env2 = { ...input.env || {}, ...COORDINATOR_DELEGATED_ENV_UNSETS };
34535
- if (cliType === "hermes-cli" && !hasCliArg(cliArgs, "--ignore-user-config")) {
34536
- cliArgs.unshift("--ignore-user-config");
34537
- }
34538
34679
  if (cliType === "claude-cli" && !hasCliArg(cliArgs, "--mcp-config")) {
34539
34680
  cliArgs.unshift("--mcp-config", ensureEmptyDelegatedMcpConfig(input.workspace));
34540
34681
  }
@@ -35478,7 +35619,9 @@ function resolveHermesMeshCoordinatorSetup(options) {
35478
35619
  const mcpServer = resolveAdhdevMcpServerLaunch({
35479
35620
  meshId: options.meshId,
35480
35621
  nodeExecutable: options.nodeExecutable,
35481
- adhdevMcpEntryPath: options.adhdevMcpEntryPath
35622
+ adhdevMcpEntryPath: options.adhdevMcpEntryPath,
35623
+ adhdevMcpTransport: options.adhdevMcpTransport,
35624
+ adhdevMcpPort: options.adhdevMcpPort
35482
35625
  });
35483
35626
  if (!mcpServer) {
35484
35627
  return {
@@ -35545,7 +35688,9 @@ function resolveMeshCoordinatorSetup(options) {
35545
35688
  const mcpServer = resolveAdhdevMcpServerLaunch({
35546
35689
  meshId,
35547
35690
  nodeExecutable: options.nodeExecutable,
35548
- adhdevMcpEntryPath: options.adhdevMcpEntryPath
35691
+ adhdevMcpEntryPath: options.adhdevMcpEntryPath,
35692
+ adhdevMcpTransport: options.adhdevMcpTransport,
35693
+ adhdevMcpPort: options.adhdevMcpPort
35549
35694
  });
35550
35695
  if (!mcpServer) {
35551
35696
  return {
@@ -35567,6 +35712,22 @@ function resolveMeshCoordinatorSetup(options) {
35567
35712
  if (!instructions || !template?.trim()) {
35568
35713
  return { kind: "unsupported", reason: "Provider manual MCP setup is missing instructions or template" };
35569
35714
  }
35715
+ const renderedTemplate = renderMeshCoordinatorTemplate(template, {
35716
+ meshId,
35717
+ workspace,
35718
+ serverName,
35719
+ adhdevMcpCommand: options.adhdevMcpCommand || DEFAULT_ADHDEV_MCP_COMMAND
35720
+ });
35721
+ const isCliCommand = !renderedTemplate.trim().includes("\n") && !renderedTemplate.trim().startsWith("{");
35722
+ if (isCliCommand) {
35723
+ return {
35724
+ kind: "cli_command",
35725
+ serverName,
35726
+ command: renderedTemplate.trim(),
35727
+ requiresRestart: mcpConfig.requiresRestart === true,
35728
+ instructions
35729
+ };
35730
+ }
35570
35731
  return {
35571
35732
  kind: "manual",
35572
35733
  serverName,
@@ -35574,12 +35735,7 @@ function resolveMeshCoordinatorSetup(options) {
35574
35735
  configPathCommand: mcpConfig.configPathCommand,
35575
35736
  requiresRestart: mcpConfig.requiresRestart === true,
35576
35737
  instructions,
35577
- template: renderMeshCoordinatorTemplate(template, {
35578
- meshId,
35579
- workspace,
35580
- serverName,
35581
- adhdevMcpCommand: options.adhdevMcpCommand || DEFAULT_ADHDEV_MCP_COMMAND
35582
- })
35738
+ template: renderedTemplate
35583
35739
  };
35584
35740
  }
35585
35741
  return {
@@ -35608,11 +35764,27 @@ function resolveAdhdevMcpServerLaunch(options) {
35608
35764
  if (!entryPath) return null;
35609
35765
  const nodeExecutable = resolveMcpNodeExecutable(options.nodeExecutable);
35610
35766
  if (!nodeExecutable) return null;
35767
+ const transport = resolveMcpTransport(options.adhdevMcpTransport);
35768
+ const args = [entryPath, "--mode", transport, "--repo-mesh", options.meshId];
35769
+ const port = resolveMcpPort(options.adhdevMcpPort);
35770
+ if (port !== void 0) args.push("--port", String(port));
35611
35771
  return {
35612
35772
  command: nodeExecutable,
35613
- args: [entryPath, "--mode", "ipc", "--repo-mesh", options.meshId]
35773
+ args
35614
35774
  };
35615
35775
  }
35776
+ function resolveMcpTransport(explicitTransport) {
35777
+ if (explicitTransport === "local" || explicitTransport === "ipc") return explicitTransport;
35778
+ const envTransport = process.env.ADHDEV_COORDINATOR_MCP_TRANSPORT?.trim();
35779
+ return envTransport === "local" ? "local" : "ipc";
35780
+ }
35781
+ function resolveMcpPort(explicitPort) {
35782
+ if (typeof explicitPort === "number" && Number.isInteger(explicitPort) && explicitPort > 0) return explicitPort;
35783
+ const raw = process.env.ADHDEV_COORDINATOR_MCP_PORT?.trim();
35784
+ if (!raw) return void 0;
35785
+ const parsed = Number(raw);
35786
+ return Number.isInteger(parsed) && parsed > 0 ? parsed : void 0;
35787
+ }
35616
35788
  function resolveMcpNodeExecutable(explicitExecutable) {
35617
35789
  const explicit = explicitExecutable?.trim();
35618
35790
  if (explicit) return explicit;
@@ -40855,7 +41027,8 @@ async function initDaemonComponents(config2) {
40855
41027
  cdpManagers,
40856
41028
  sessionRegistry,
40857
41029
  detectedIdes: detectedIdesRef,
40858
- refreshProviderAvailability
41030
+ refreshProviderAvailability,
41031
+ dispatchMeshCommand: config2.dispatchMeshCommand
40859
41032
  };
40860
41033
  setupMeshEventForwarding(components);
40861
41034
  return components;
@@ -40913,7 +41086,7 @@ async function shutdownDaemonComponents(components) {
40913
41086
  }
40914
41087
  cdpManagers.clear();
40915
41088
  }
40916
- var path4, import_promises4, import_fs3, import_child_process, import_util3, import_os2, import_path, import_fs4, import_crypto2, import_fs5, import_path2, import_crypto3, import_fs6, import_path3, import_crypto4, import_events2, import_fs7, import_path4, import_crypto5, fs2, path8, os22, os8, os9, path14, import_child_process2, os10, path15, os11, import_child_process3, import_fs8, import_promises5, path, import_util4, import_promises6, path22, path32, fs, os4, path5, import_crypto6, path6, path7, import_fs9, import_path5, import_child_process4, import_fs10, import_os3, path9, import_child_process5, os32, path10, import_fs11, os42, import_child_process6, http, crypto2, fs3, path11, os5, fs4, os6, path12, import_crypto7, fs5, path13, os7, os13, path18, crypto4, import_fs12, import_child_process7, os12, path16, crypto3, fs6, import_module, path17, import_stream2, import_child_process8, import_child_process9, net2, os15, path20, fs7, path19, os14, fs8, path21, os16, import_child_process10, import_crypto8, import_fs13, import_module2, os17, import_path6, os18, import_child_process11, import_child_process12, fs9, os19, path222, import_os4, import_path7, fs10, fs11, path23, os20, import_child_process13, import_os5, http2, fs15, path27, fs12, path24, fs13, path25, fs14, path26, os21, import_child_process14, __defProp2, __getOwnPropDesc2, __getOwnPropNames2, __hasOwnProp2, __require2, __esm2, __export2, __copyProps2, __toCommonJS2, DEFAULT_MESH_POLICY, init_repo_mesh_types, git_worktree_exports, execFileAsync2, WORKTREE_DIR_NAME, GIT_TIMEOUT_MS, GIT_MAX_BUFFER, init_git_worktree, config_exports, DEFAULT_CONFIG, MACHINE_ID_PREFIX, init_config, mesh_config_exports, SESSION_CLEANUP_MODES, SPAWNED_SESSION_VISIBILITY_MODES, init_mesh_config, coordinator_prompt_exports, TOOLS_SECTION, TOOL_EXPOSURE_PREFLIGHT_SECTION, WORKFLOW_SECTION, init_coordinator_prompt, mesh_ledger_exports, LEDGER_DIR_NAME, MAX_FILE_SIZE_BYTES, RECENT_FAILURE_WINDOW_MS, meshLedgerEvents, init_mesh_ledger, init_mesh_work_queue, LEVEL_NUM, LEVEL_LABEL, currentLevel, LOG_DIR, MAX_LOG_SIZE, MAX_LOG_DAYS, currentDate, currentLogFile, writeCount, RING_BUFFER_SIZE, ringBuffer, origConsoleLog, origConsoleError, origConsoleWarn, LOG, interceptorInstalled, LOG_PATH, init_logger, mesh_events_exports, MAX_PENDING_EVENTS, pendingMeshCoordinatorEvents, MESH_COORDINATOR_EVENTS, EVENT_TO_LEDGER_KIND, init_mesh_events, NORMAL_TRACE_BUFFER_SIZE, DEV_TRACE_BUFFER_SIZE, DEFAULT_CONFIG2, currentConfig, init_debug_config, DEFAULT_BINDING_CANDIDATES, cachedBinding, cachedBindingError, GhosttyVtTerminalBackend, init_ghostty_vt_backend, TerminalCtor, XtermTerminalBackend, init_xterm_backend, DEFAULT_SCROLLBACK, loggedTerminalBackends, TerminalScreen, init_terminal_screen, init_spawn_env, cachedPty, NodePtyRuntimeTransport, NodePtyTransportFactory, init_pty_transport, TerminalTranscriptAccumulator, buildCliSpawnEnv, init_provider_cli_shared, init_provider_cli_parse, init_provider_cli_config, init_provider_cli_runtime, provider_cli_adapter_exports, ProviderCliAdapter, init_provider_cli_adapter, execFileAsync, DEFAULT_TIMEOUT_MS, DEFAULT_MAX_BUFFER, GitCommandError, DEFAULT_MAX_FILES, DEFAULT_MAX_BYTES, summarizeGitStatus, InMemoryGitSnapshotStore, DEFAULT_GIT_WORKSPACE_POLL_INTERVAL_MS, MIN_GIT_WORKSPACE_POLL_INTERVAL_MS, GitWorkspaceMonitor, GIT_COMMAND_NAMES, SNAPSHOT_REASONS, FAILURE_REASONS, defaultSnapshotStore, defaultGitCommandServices, BUSY_STATUSES, TERMINAL_STATUSES, TurnSnapshotTracker, MAX_WORKSPACES, MAX_ACTIVITY, MAX_SAVED_SESSIONS, DEFAULT_STATE, BUILTIN_IDE_DEFINITIONS, registeredIDEs, LIVE_LIFECYCLES, DEFAULT_ACTIVE_CHAT_POLL_STATUSES, DEFAULT_CHAT_TAIL_RECENT_MESSAGE_GRACE_MS, LIVE_RUNTIME_LIFECYCLES, DaemonCdpManager, CdpDomHandlers, DEFAULT_MONITOR_CONFIG, StatusMonitor, BUILTIN_CHAT_MESSAGE_KINDS, CHAT_MESSAGE_VISIBILITIES, CHAT_MESSAGE_TRANSCRIPT_VISIBILITIES, CHAT_MESSAGE_AUDIENCES, CHAT_MESSAGE_SOURCES, CHAT_MESSAGE_ACTIVITY_SOURCES, CHAT_MESSAGE_INTERNAL_SOURCES, KNOWN_CHAT_MESSAGE_KINDS, CHAT_MESSAGE_KIND_ALIASES, EXPLICIT_HIDDEN_VISIBILITIES, EXPLICIT_VISIBLE_VISIBILITIES, HIDDEN_AUDIENCES, ACTIVITY_SOURCE_SET, INTERNAL_SOURCE_SET, HISTORY_DIR, RETAIN_DAYS, SAVED_HISTORY_INDEX_VERSION, SAVED_HISTORY_INDEX_FILE, SAVED_HISTORY_INDEX_LOCK_SUFFIX, SAVED_HISTORY_INDEX_LOCK_WAIT_MS, SAVED_HISTORY_INDEX_LOCK_STALE_MS, SAVED_HISTORY_INDEX_LOCK_POLL_MS, SAVED_HISTORY_ROLLUP_THRESHOLD_BYTES, savedHistorySessionCache, savedHistoryFileSummaryCache, savedHistoryBackgroundRefresh, savedHistoryRollupInFlight, ChatHistoryWriter, IDE_PROVIDER_SESSION_CAPABILITIES_BASE, EXTENSION_PROVIDER_SESSION_CAPABILITIES_BASE, ExtensionProviderInstance, VALID_STATUSES, VALID_ROLES, VALID_BUBBLE_STATES, VALID_TURN_STATUSES, DEFAULT_APPROVAL_POSITIVE_HINTS, IdeProviderInstance, DEFAULT_CDP_SCAN_INTERVAL_MS, DEFAULT_CDP_DISCOVERY_INTERVAL_MS, DEFAULT_STATUS_INITIAL_REPORT_DELAY_MS, DEFAULT_STATUS_SERVER_REPORT_INTERVAL_MS, DEFAULT_STATUS_P2P_REPORT_INTERVAL_MS, MIN_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS, DEFAULT_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS, MIN_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS, DEFAULT_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS, DEFAULT_SESSION_HOST_READY_TIMEOUT_MS, STANDALONE_CDP_SCAN_INTERVAL_MS, DaemonCdpScanner, DaemonCdpInitializer, WORKING_STATUSES, FULL_STATUS_ACTIVE_CHAT_OPTIONS, LIVE_STATUS_ACTIVE_CHAT_OPTIONS, STATUS_MODAL_MESSAGE_LIMIT, STATUS_MODAL_BUTTON_LIMIT, VALID_INPUT_MEDIA_TYPES, VALID_INPUT_STRATEGIES, TEXT_ONLY_MESSAGE_INPUT_SUPPORT, IDE_SESSION_CAPABILITIES, EXTENSION_SESSION_CAPABILITIES, PTY_SESSION_CAPABILITIES, CLI_CHAT_SESSION_CAPABILITIES, ACP_SESSION_CAPABILITIES, globalStore, RECENT_SEND_WINDOW_MS, READ_CHAT_PROVIDER_EVAL_TIMEOUT_MS, HERMES_CLI_STARTING_SEND_SETTLE_MS, recentSendByTarget, DEFAULT_DEBUG_SANITIZE_OPTIONS, SECRET_KEY_PATTERN, KEY_TO_VK, COMMAND_DEBUG_LEVELS, DaemonCommandHandler, IMAGE_MIME_EXTENSIONS, MATERIALIZED_IMAGE_MAX_AGE_MS, MATERIALIZED_IMAGE_CLEANUP_INTERVAL_MS, lastMaterializedImageCleanupAt, CachedDatabaseSync, CliProviderInstance, AcpProviderInstance, chalkModule, chalkApi, COORDINATOR_DELEGATED_ENV_UNSETS, DaemonCliManager, VALID_CAPABILITY_MEDIA_TYPES, VALID_INPUT_STRATEGIES2, KNOWN_PROVIDER_FIELDS, VALUE_CONTROL_TYPES, ProviderLoader, _providerLoader, LOG_DIR2, MAX_FILE_SIZE, MAX_DAYS, SENSITIVE_KEYS, currentDate2, currentFile, writeCount2, SKIP_COMMANDS, DEFAULT_SERVER_NAME, DEFAULT_ADHDEV_MCP_COMMAND, HERMES_CLI_TYPE, HERMES_MCP_CONFIG_PATH, READ_DEBUG_ENABLED, recentReadDebugSignatureBySession, UPGRADE_HELPER_ENV, CHANNEL_NPM_TAG, CHANNEL_SERVER_URL, CHAT_COMMANDS, READ_DEBUG_ENABLED2, DaemonCommandRouter, DaemonStatusReporter, DEFAULT_DAEMON_PORT, DAEMON_WS_PATH, ProviderStreamAdapter, DaemonAgentStreamManager, AgentStreamPoller, ProviderInstanceManager, ARCHIVE_PATH, MAX_ENTRIES_PER_PROVIDER, VersionArchive, DEV_SERVER_PORT, DevServer, SessionHostRuntimeTransport, SessionHostPtyTransportFactory, DEFAULT_SESSION_HOST_APP_NAME, DEFAULT_STANDALONE_SESSION_HOST_APP_NAME, STARTUP_TIMEOUT_MS, STARTUP_POLL_MS, SessionHostCompatibilityError, EXTENSION_CATALOG, SessionRegistry;
41089
+ var path4, import_promises4, import_fs3, import_child_process, import_util3, import_os2, import_path, import_fs4, import_crypto2, import_fs5, import_path2, import_crypto3, import_fs6, import_path3, import_crypto4, import_events2, import_fs7, import_path4, import_crypto5, fs2, path8, os22, os8, os9, path14, import_child_process2, os10, path15, os11, import_child_process3, import_fs8, import_promises5, path, import_util4, import_promises6, path22, path32, fs, os4, path5, import_crypto6, path6, path7, import_fs9, import_path5, import_child_process4, import_fs10, import_os3, path9, import_child_process5, os32, path10, import_fs11, os42, import_child_process6, http, crypto2, fs3, path11, os5, fs4, os6, path12, import_crypto7, fs5, path13, os7, os13, path18, crypto4, import_fs12, import_child_process7, os12, path16, crypto3, fs6, import_module, path17, import_stream2, import_child_process8, import_child_process9, net2, os15, path20, fs7, path19, os14, fs8, path21, os16, import_child_process10, import_crypto8, import_fs13, import_module2, os17, import_path6, os18, import_child_process11, import_child_process12, fs9, os19, path222, import_os4, import_path7, fs10, fs11, path23, os20, import_child_process13, import_os5, http2, fs15, path27, fs12, path24, fs13, path25, fs14, path26, os21, import_child_process14, __defProp2, __getOwnPropDesc2, __getOwnPropNames2, __hasOwnProp2, __require2, __esm2, __export2, __copyProps2, __toCommonJS2, DEFAULT_MESH_POLICY, init_repo_mesh_types, git_worktree_exports, execFileAsync2, WORKTREE_DIR_NAME, GIT_TIMEOUT_MS, GIT_MAX_BUFFER, init_git_worktree, config_exports, DEFAULT_CONFIG, MACHINE_ID_PREFIX, init_config, mesh_config_exports, SESSION_CLEANUP_MODES, SPAWNED_SESSION_VISIBILITY_MODES, init_mesh_config, coordinator_prompt_exports, TOOLS_SECTION, TOOL_EXPOSURE_PREFLIGHT_SECTION, WORKFLOW_SECTION, init_coordinator_prompt, mesh_ledger_exports, LEDGER_DIR_NAME, MAX_FILE_SIZE_BYTES, RECENT_FAILURE_WINDOW_MS, meshLedgerEvents, init_mesh_ledger, mesh_work_queue_exports, init_mesh_work_queue, LEVEL_NUM, LEVEL_LABEL, currentLevel, LOG_DIR, MAX_LOG_SIZE, MAX_LOG_DAYS, currentDate, currentLogFile, writeCount, RING_BUFFER_SIZE, ringBuffer, origConsoleLog, origConsoleError, origConsoleWarn, LOG, interceptorInstalled, LOG_PATH, init_logger, mesh_events_exports, remoteIdleSessions, MAX_PENDING_EVENTS, pendingMeshCoordinatorEvents, MESH_COORDINATOR_EVENTS, EVENT_TO_LEDGER_KIND, init_mesh_events, NORMAL_TRACE_BUFFER_SIZE, DEV_TRACE_BUFFER_SIZE, DEFAULT_CONFIG2, currentConfig, init_debug_config, DEFAULT_BINDING_CANDIDATES, cachedBinding, cachedBindingError, GhosttyVtTerminalBackend, init_ghostty_vt_backend, TerminalCtor, XtermTerminalBackend, init_xterm_backend, DEFAULT_SCROLLBACK, loggedTerminalBackends, TerminalScreen, init_terminal_screen, init_spawn_env, cachedPty, NodePtyRuntimeTransport, NodePtyTransportFactory, init_pty_transport, TerminalTranscriptAccumulator, buildCliSpawnEnv, init_provider_cli_shared, init_provider_cli_parse, init_provider_cli_config, init_provider_cli_runtime, provider_cli_adapter_exports, ProviderCliAdapter, init_provider_cli_adapter, execFileAsync, DEFAULT_TIMEOUT_MS, DEFAULT_MAX_BUFFER, GitCommandError, DEFAULT_MAX_FILES, DEFAULT_MAX_BYTES, summarizeGitStatus, InMemoryGitSnapshotStore, DEFAULT_GIT_WORKSPACE_POLL_INTERVAL_MS, MIN_GIT_WORKSPACE_POLL_INTERVAL_MS, GitWorkspaceMonitor, GIT_COMMAND_NAMES, SNAPSHOT_REASONS, FAILURE_REASONS, defaultSnapshotStore, defaultGitCommandServices, BUSY_STATUSES, TERMINAL_STATUSES, TurnSnapshotTracker, MAX_WORKSPACES, MAX_ACTIVITY, MAX_SAVED_SESSIONS, DEFAULT_STATE, BUILTIN_IDE_DEFINITIONS, registeredIDEs, LIVE_LIFECYCLES, DEFAULT_ACTIVE_CHAT_POLL_STATUSES, DEFAULT_CHAT_TAIL_RECENT_MESSAGE_GRACE_MS, LIVE_RUNTIME_LIFECYCLES, DaemonCdpManager, CdpDomHandlers, DEFAULT_MONITOR_CONFIG, StatusMonitor, BUILTIN_CHAT_MESSAGE_KINDS, CHAT_MESSAGE_VISIBILITIES, CHAT_MESSAGE_TRANSCRIPT_VISIBILITIES, CHAT_MESSAGE_AUDIENCES, CHAT_MESSAGE_SOURCES, CHAT_MESSAGE_ACTIVITY_SOURCES, CHAT_MESSAGE_INTERNAL_SOURCES, KNOWN_CHAT_MESSAGE_KINDS, CHAT_MESSAGE_KIND_ALIASES, EXPLICIT_HIDDEN_VISIBILITIES, EXPLICIT_VISIBLE_VISIBILITIES, HIDDEN_AUDIENCES, ACTIVITY_SOURCE_SET, INTERNAL_SOURCE_SET, HISTORY_DIR, RETAIN_DAYS, SAVED_HISTORY_INDEX_VERSION, SAVED_HISTORY_INDEX_FILE, SAVED_HISTORY_INDEX_LOCK_SUFFIX, SAVED_HISTORY_INDEX_LOCK_WAIT_MS, SAVED_HISTORY_INDEX_LOCK_STALE_MS, SAVED_HISTORY_INDEX_LOCK_POLL_MS, SAVED_HISTORY_ROLLUP_THRESHOLD_BYTES, savedHistorySessionCache, savedHistoryFileSummaryCache, savedHistoryBackgroundRefresh, savedHistoryRollupInFlight, ChatHistoryWriter, IDE_PROVIDER_SESSION_CAPABILITIES_BASE, EXTENSION_PROVIDER_SESSION_CAPABILITIES_BASE, ExtensionProviderInstance, VALID_STATUSES, VALID_ROLES, VALID_BUBBLE_STATES, VALID_TURN_STATUSES, DEFAULT_APPROVAL_POSITIVE_HINTS, IdeProviderInstance, DEFAULT_CDP_SCAN_INTERVAL_MS, DEFAULT_CDP_DISCOVERY_INTERVAL_MS, DEFAULT_STATUS_INITIAL_REPORT_DELAY_MS, DEFAULT_STATUS_SERVER_REPORT_INTERVAL_MS, DEFAULT_STATUS_P2P_REPORT_INTERVAL_MS, MIN_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS, DEFAULT_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS, MIN_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS, DEFAULT_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS, DEFAULT_SESSION_HOST_READY_TIMEOUT_MS, STANDALONE_CDP_SCAN_INTERVAL_MS, DaemonCdpScanner, DaemonCdpInitializer, WORKING_STATUSES, FULL_STATUS_ACTIVE_CHAT_OPTIONS, LIVE_STATUS_ACTIVE_CHAT_OPTIONS, STATUS_MODAL_MESSAGE_LIMIT, STATUS_MODAL_BUTTON_LIMIT, VALID_INPUT_MEDIA_TYPES, VALID_INPUT_STRATEGIES, TEXT_ONLY_MESSAGE_INPUT_SUPPORT, IDE_SESSION_CAPABILITIES, EXTENSION_SESSION_CAPABILITIES, PTY_SESSION_CAPABILITIES, CLI_CHAT_SESSION_CAPABILITIES, ACP_SESSION_CAPABILITIES, globalStore, RECENT_SEND_WINDOW_MS, READ_CHAT_PROVIDER_EVAL_TIMEOUT_MS, HERMES_CLI_STARTING_SEND_SETTLE_MS, recentSendByTarget, DEFAULT_DEBUG_SANITIZE_OPTIONS, SECRET_KEY_PATTERN, KEY_TO_VK, COMMAND_DEBUG_LEVELS, DaemonCommandHandler, IMAGE_MIME_EXTENSIONS, MATERIALIZED_IMAGE_MAX_AGE_MS, MATERIALIZED_IMAGE_CLEANUP_INTERVAL_MS, lastMaterializedImageCleanupAt, CachedDatabaseSync, CliProviderInstance, AcpProviderInstance, chalkModule, chalkApi, COORDINATOR_DELEGATED_ENV_UNSETS, DaemonCliManager, VALID_CAPABILITY_MEDIA_TYPES, VALID_INPUT_STRATEGIES2, KNOWN_PROVIDER_FIELDS, VALUE_CONTROL_TYPES, ProviderLoader, _providerLoader, LOG_DIR2, MAX_FILE_SIZE, MAX_DAYS, SENSITIVE_KEYS, currentDate2, currentFile, writeCount2, SKIP_COMMANDS, DEFAULT_SERVER_NAME, DEFAULT_ADHDEV_MCP_COMMAND, HERMES_CLI_TYPE, HERMES_MCP_CONFIG_PATH, READ_DEBUG_ENABLED, recentReadDebugSignatureBySession, UPGRADE_HELPER_ENV, CHANNEL_NPM_TAG, CHANNEL_SERVER_URL, CHAT_COMMANDS, READ_DEBUG_ENABLED2, DaemonCommandRouter, DaemonStatusReporter, DEFAULT_DAEMON_PORT, DAEMON_WS_PATH, ProviderStreamAdapter, DaemonAgentStreamManager, AgentStreamPoller, ProviderInstanceManager, ARCHIVE_PATH, MAX_ENTRIES_PER_PROVIDER, VersionArchive, DEV_SERVER_PORT, DevServer, SessionHostRuntimeTransport, SessionHostPtyTransportFactory, DEFAULT_SESSION_HOST_APP_NAME, DEFAULT_STANDALONE_SESSION_HOST_APP_NAME, STARTUP_TIMEOUT_MS, STARTUP_POLL_MS, SessionHostCompatibilityError, EXTENSION_CATALOG, SessionRegistry;
40917
41090
  var init_dist2 = __esm({
40918
41091
  "../daemon-core/dist/index.mjs"() {
40919
41092
  "use strict";
@@ -41246,6 +41419,17 @@ Follow these recovery rules:
41246
41419
  meshLedgerEvents = new import_events2.EventEmitter();
41247
41420
  }
41248
41421
  });
41422
+ mesh_work_queue_exports = {};
41423
+ __export2(mesh_work_queue_exports, {
41424
+ cancelTask: () => cancelTask,
41425
+ claimNextTask: () => claimNextTask,
41426
+ enqueueTask: () => enqueueTask,
41427
+ getMeshQueueStats: () => getMeshQueueStats,
41428
+ getQueue: () => getQueue,
41429
+ requeueTask: () => requeueTask,
41430
+ updateSessionTaskStatus: () => updateSessionTaskStatus,
41431
+ updateTaskStatus: () => updateTaskStatus
41432
+ });
41249
41433
  init_mesh_work_queue = __esm2({
41250
41434
  "src/mesh/mesh-work-queue.ts"() {
41251
41435
  "use strict";
@@ -41325,12 +41509,15 @@ Follow these recovery rules:
41325
41509
  init_logger();
41326
41510
  init_mesh_ledger();
41327
41511
  init_mesh_work_queue();
41512
+ remoteIdleSessions = /* @__PURE__ */ new Map();
41328
41513
  MAX_PENDING_EVENTS = 50;
41329
41514
  pendingMeshCoordinatorEvents = [];
41330
41515
  MESH_COORDINATOR_EVENTS = /* @__PURE__ */ new Set([
41516
+ "agent:generating_started",
41331
41517
  "agent:generating_completed",
41332
41518
  "agent:waiting_approval",
41333
41519
  "agent:stopped",
41520
+ "agent:ready",
41334
41521
  "monitor:long_generating"
41335
41522
  ]);
41336
41523
  EVENT_TO_LEDGER_KIND = {
@@ -41865,6 +42052,8 @@ Follow these recovery rules:
41865
42052
  statusHistory = [];
41866
42053
  // ─── CLI Scripts (script-based parsing) ───
41867
42054
  cliScripts;
42055
+ /** Per-session opaque state object created by cliScripts.createState(), reset on stop. */
42056
+ scriptState = null;
41868
42057
  runtimeSettings = {};
41869
42058
  /** Full accumulated rendered PTY transcript for parser/readback use */
41870
42059
  accumulatedBuffer = "";
@@ -41943,7 +42132,7 @@ ${lastSnapshot}`;
41943
42132
  }
41944
42133
  getFreshParsedStatusCache() {
41945
42134
  const cached2 = this.parsedStatusCache;
41946
- if (cached2 && cached2.responseBuffer === this.responseBuffer && cached2.currentTurnScope === this.currentTurnScope && cached2.recentOutputBuffer === this.recentOutputBuffer && cached2.accumulatedBuffer === this.accumulatedBuffer && cached2.screenText === this.lastScreenText && cached2.currentStatus === this.currentStatus && cached2.activeModal === this.activeModal && cached2.cliName === this.cliName) {
42135
+ if (cached2 && cached2.responseBuffer === this.responseBuffer && cached2.currentTurnScope === this.currentTurnScope && cached2.recentOutputBuffer === this.recentOutputBuffer && cached2.accumulatedBuffer === this.accumulatedBuffer && cached2.accumulatedRawBuffer === this.accumulatedRawBuffer && cached2.screenText === this.lastScreenText && cached2.currentStatus === this.currentStatus && cached2.activeModal === this.activeModal && cached2.cliName === this.cliName) {
41947
42136
  return cached2.result;
41948
42137
  }
41949
42138
  return null;
@@ -42046,6 +42235,7 @@ ${lastSnapshot}`;
42046
42235
  this.cliScripts = scripts;
42047
42236
  this.parsedStatusCache = null;
42048
42237
  this.parseErrorMessage = null;
42238
+ this.scriptState = typeof scripts.createState === "function" ? scripts.createState() : null;
42049
42239
  const scriptNames = listCliScriptNames(scripts);
42050
42240
  LOG.info("CLI", `[${this.cliType}] CLI scripts injected: [${scriptNames.join(", ")}]`);
42051
42241
  }
@@ -42163,6 +42353,7 @@ ${lastSnapshot}`;
42163
42353
  this.ready = false;
42164
42354
  this.startupParseGate = false;
42165
42355
  this.spawnAt = 0;
42356
+ this.scriptState = null;
42166
42357
  this.onStatusChange?.();
42167
42358
  });
42168
42359
  this.spawnAt = Date.now();
@@ -42916,6 +43107,11 @@ ${lastSnapshot}`;
42916
43107
  };
42917
43108
  }
42918
43109
  // ─── Script Execution ──────────────────────────
43110
+ invokeCliScript(script, input) {
43111
+ const hasStateFactory = typeof this.cliScripts?.createState === "function";
43112
+ const expectsStateArgument = hasStateFactory || this.scriptState !== null || script.length >= 2;
43113
+ return expectsStateArgument ? script(this.scriptState, input) : script(input);
43114
+ }
42919
43115
  runParseSession() {
42920
43116
  if (typeof this.cliScripts?.parseSession !== "function") {
42921
43117
  this.parseErrorMessage = `${this.cliType} parseSession unavailable`;
@@ -42936,7 +43132,10 @@ ${lastSnapshot}`;
42936
43132
  scope: this.currentTurnScope,
42937
43133
  runtimeSettings: this.runtimeSettings
42938
43134
  });
42939
- const session = this.cliScripts.parseSession({ ...input, tail, tailScreen: buildCliScreenSnapshot(tail) });
43135
+ const session = this.invokeCliScript(
43136
+ this.cliScripts.parseSession,
43137
+ { ...input, tail, tailScreen: buildCliScreenSnapshot(tail) }
43138
+ );
42940
43139
  this.parseErrorMessage = null;
42941
43140
  return session && typeof session === "object" ? session : null;
42942
43141
  } catch (e) {
@@ -42950,7 +43149,7 @@ ${lastSnapshot}`;
42950
43149
  if (!this.cliScripts?.detectStatus) return null;
42951
43150
  try {
42952
43151
  const screenText = this.terminalScreen.getText();
42953
- const status = this.cliScripts.detectStatus({
43152
+ const status = this.invokeCliScript(this.cliScripts.detectStatus, {
42954
43153
  tail: text.slice(-500),
42955
43154
  screenText,
42956
43155
  rawBuffer: this.accumulatedRawBuffer,
@@ -42969,7 +43168,7 @@ ${lastSnapshot}`;
42969
43168
  try {
42970
43169
  const screenText = this.terminalScreen.getText();
42971
43170
  const buffer = screenText || this.accumulatedBuffer;
42972
- return this.cliScripts.parseApproval({
43171
+ return this.invokeCliScript(this.cliScripts.parseApproval, {
42973
43172
  buffer,
42974
43173
  screenText,
42975
43174
  rawBuffer: this.accumulatedRawBuffer,
@@ -43025,7 +43224,7 @@ ${lastSnapshot}`;
43025
43224
  const screenText = this.readTerminalScreenText();
43026
43225
  const parseScreenText = this.getParseScreenText(screenText);
43027
43226
  const cached2 = this.parsedStatusCache;
43028
- if (cached2 && cached2.responseBuffer === this.responseBuffer && cached2.currentTurnScope === this.currentTurnScope && cached2.recentOutputBuffer === this.recentOutputBuffer && cached2.accumulatedBuffer === this.accumulatedBuffer && cached2.screenText === parseScreenText && cached2.currentStatus === this.currentStatus && cached2.activeModal === this.activeModal && cached2.cliName === this.cliName) {
43227
+ if (cached2 && cached2.responseBuffer === this.responseBuffer && cached2.currentTurnScope === this.currentTurnScope && cached2.recentOutputBuffer === this.recentOutputBuffer && cached2.accumulatedBuffer === this.accumulatedBuffer && cached2.accumulatedRawBuffer === this.accumulatedRawBuffer && cached2.screenText === parseScreenText && cached2.currentStatus === this.currentStatus && cached2.activeModal === this.activeModal && cached2.cliName === this.cliName) {
43029
43228
  return cached2.result;
43030
43229
  }
43031
43230
  const parsed = this.runParseSession();
@@ -43053,6 +43252,7 @@ ${lastSnapshot}`;
43053
43252
  currentTurnScope: this.currentTurnScope,
43054
43253
  recentOutputBuffer: this.recentOutputBuffer,
43055
43254
  accumulatedBuffer: this.accumulatedBuffer,
43255
+ accumulatedRawBuffer: this.accumulatedRawBuffer,
43056
43256
  screenText: parseScreenText,
43057
43257
  currentStatus: this.currentStatus,
43058
43258
  activeModal: this.activeModal,
@@ -43077,7 +43277,7 @@ ${lastSnapshot}`;
43077
43277
  scope: this.currentTurnScope,
43078
43278
  runtimeSettings: this.runtimeSettings
43079
43279
  });
43080
- return await Promise.resolve(fn({
43280
+ return await Promise.resolve(fn(this.scriptState, {
43081
43281
  ...input,
43082
43282
  args: args && typeof args === "object" ? { ...args } : {}
43083
43283
  }));
@@ -48296,6 +48496,8 @@ ${effect.notification.body || ""}`.trim();
48296
48496
  this.completedDebounceTimer = null;
48297
48497
  }, 3e3);
48298
48498
  }
48499
+ } else if (newStatus === "idle" && this.lastStatus === "starting") {
48500
+ this.pushEvent({ event: "agent:ready", chatTitle, timestamp: now });
48299
48501
  } else if (newStatus === "stopped") {
48300
48502
  if (this.generatingDebounceTimer) {
48301
48503
  clearTimeout(this.generatingDebounceTimer);
@@ -53014,6 +53216,51 @@ Run 'adhdev doctor' for detailed diagnostics.`
53014
53216
  return { success: false, error: e.message };
53015
53217
  }
53016
53218
  }
53219
+ case "get_mesh_queue": {
53220
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
53221
+ if (!meshId) return { success: false, error: "meshId required" };
53222
+ try {
53223
+ const { getQueue: getQueue2 } = await Promise.resolve().then(() => (init_mesh_work_queue(), mesh_work_queue_exports));
53224
+ const status = Array.isArray(args?.status) ? args.status.map((s) => typeof s === "string" ? s.trim() : "").filter(Boolean) : void 0;
53225
+ const queue = getQueue2(meshId, { status });
53226
+ return { success: true, queue };
53227
+ } catch (e) {
53228
+ return { success: false, error: e.message };
53229
+ }
53230
+ }
53231
+ case "cancel_mesh_queue_task": {
53232
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
53233
+ const taskId = typeof args?.taskId === "string" ? args.taskId.trim() : "";
53234
+ if (!meshId || !taskId) return { success: false, error: "meshId and taskId required" };
53235
+ try {
53236
+ const { cancelTask: cancelTask2 } = await Promise.resolve().then(() => (init_mesh_work_queue(), mesh_work_queue_exports));
53237
+ const reason = typeof args?.reason === "string" ? args.reason : void 0;
53238
+ const task = cancelTask2(meshId, taskId, { reason });
53239
+ if (!task) return { success: false, error: `Queue task '${taskId}' not found` };
53240
+ return { success: true, task };
53241
+ } catch (e) {
53242
+ return { success: false, error: e.message };
53243
+ }
53244
+ }
53245
+ case "requeue_mesh_queue_task": {
53246
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
53247
+ const taskId = typeof args?.taskId === "string" ? args.taskId.trim() : "";
53248
+ if (!meshId || !taskId) return { success: false, error: "meshId and taskId required" };
53249
+ try {
53250
+ const { requeueTask: requeueTask2 } = await Promise.resolve().then(() => (init_mesh_work_queue(), mesh_work_queue_exports));
53251
+ const task = requeueTask2(meshId, taskId, {
53252
+ reason: typeof args?.reason === "string" ? args.reason : void 0,
53253
+ targetNodeId: typeof args?.targetNodeId === "string" ? args.targetNodeId.trim() : void 0,
53254
+ targetSessionId: typeof args?.targetSessionId === "string" ? args.targetSessionId.trim() : void 0,
53255
+ clearTargetNode: args?.clearTargetNode === true,
53256
+ clearTargetSession: args?.clearTargetSession !== false
53257
+ });
53258
+ if (!task) return { success: false, error: `Queue task '${taskId}' not found` };
53259
+ return { success: true, task };
53260
+ } catch (e) {
53261
+ return { success: false, error: e.message };
53262
+ }
53263
+ }
53017
53264
  case "add_mesh_node": {
53018
53265
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
53019
53266
  const workspace = typeof args?.workspace === "string" ? args.workspace.trim() : "";
@@ -53171,7 +53418,13 @@ Run 'adhdev doctor' for detailed diagnostics.`
53171
53418
  appendLedgerEntry2(meshId, {
53172
53419
  kind: "node_removed",
53173
53420
  nodeId,
53174
- payload: { worktree: !!node?.isLocalWorktree, sessionCleanupMode }
53421
+ payload: {
53422
+ worktree: !!node?.isLocalWorktree,
53423
+ sessionCleanupMode,
53424
+ workspace: typeof node?.workspace === "string" ? node.workspace : void 0,
53425
+ daemonId: typeof node?.daemonId === "string" ? node.daemonId : void 0,
53426
+ worktreeBranch: typeof node?.worktreeBranch === "string" ? node.worktreeBranch : void 0
53427
+ }
53175
53428
  });
53176
53429
  } catch {
53177
53430
  }
@@ -53342,6 +53595,93 @@ Run 'adhdev doctor' for detailed diagnostics.`
53342
53595
  meshCoordinatorSetup: coordinatorSetup
53343
53596
  };
53344
53597
  }
53598
+ if (coordinatorSetup.kind === "cli_command") {
53599
+ let cliCmdSystemPrompt = "";
53600
+ try {
53601
+ cliCmdSystemPrompt = buildCoordinatorSystemPrompt2({ mesh, coordinatorCliType: cliType });
53602
+ } catch (error48) {
53603
+ const message = error48?.message || String(error48);
53604
+ LOG.error("MeshCoordinator", `Failed to build coordinator prompt: ${message}`);
53605
+ return {
53606
+ success: false,
53607
+ code: "mesh_coordinator_prompt_failed",
53608
+ error: `Failed to build Repo Mesh coordinator prompt: ${message}`,
53609
+ meshId,
53610
+ cliType,
53611
+ workspace
53612
+ };
53613
+ }
53614
+ try {
53615
+ const { execFileSync: execCmdSync } = await import("child_process");
53616
+ const cmdParts = coordinatorSetup.command.trim().split(/\s+/);
53617
+ const [regCmd, ...regArgs] = cmdParts;
53618
+ LOG.info("MeshCoordinator", `Running MCP registration: ${coordinatorSetup.command}`);
53619
+ execCmdSync(regCmd, regArgs, { stdio: "pipe", timeout: 15e3 });
53620
+ } catch (error48) {
53621
+ LOG.warn("MeshCoordinator", `MCP registration command failed (may be pre-registered): ${error48?.message || error48}`);
53622
+ }
53623
+ const cliCmdArgs = [];
53624
+ const cliCmdEnv = {};
53625
+ if (cliCmdSystemPrompt) {
53626
+ if (cliType === "codex-cli") {
53627
+ cliCmdArgs.push("-c", `developer_instructions=${JSON.stringify(cliCmdSystemPrompt)}`);
53628
+ } else if (cliType === "gemini-cli") {
53629
+ try {
53630
+ const { writeFileSync: wfs, existsSync: efs, readFileSync: rfs } = await import("fs");
53631
+ const geminiMdPath = `${workspace}/GEMINI.md`;
53632
+ const marker = "<!-- adhdev-mesh-coordinator-prompt -->";
53633
+ const markerEnd = "<!-- /adhdev-mesh-coordinator-prompt -->";
53634
+ const block = `${marker}
53635
+ ${cliCmdSystemPrompt}
53636
+ ${markerEnd}`;
53637
+ if (efs(geminiMdPath)) {
53638
+ const existing = rfs(geminiMdPath, "utf-8");
53639
+ const replaced = existing.replace(
53640
+ new RegExp(`${marker}[\\s\\S]*?${markerEnd}`, "g"),
53641
+ block
53642
+ );
53643
+ wfs(geminiMdPath, replaced.includes(marker) ? replaced : `${existing}
53644
+
53645
+ ${block}`);
53646
+ } else {
53647
+ wfs(geminiMdPath, block);
53648
+ }
53649
+ LOG.info("MeshCoordinator", `Wrote coordinator prompt to ${workspace}/GEMINI.md`);
53650
+ } catch (e) {
53651
+ LOG.warn("MeshCoordinator", `Could not write GEMINI.md: ${e?.message || e}`);
53652
+ }
53653
+ }
53654
+ }
53655
+ const cliCmdLaunch = await this.deps.cliManager.handleCliCommand("launch_cli", {
53656
+ cliType,
53657
+ dir: workspace,
53658
+ cliArgs: cliCmdArgs.length > 0 ? cliCmdArgs : void 0,
53659
+ env: Object.keys(cliCmdEnv).length > 0 ? cliCmdEnv : void 0,
53660
+ settings: { meshCoordinatorFor: meshId }
53661
+ });
53662
+ if (!cliCmdLaunch?.success) {
53663
+ return { success: false, error: cliCmdLaunch?.error || "Failed to launch CLI session" };
53664
+ }
53665
+ LOG.info("MeshCoordinator", `Launched ${cliType} coordinator (cli_command) for mesh ${meshId}`);
53666
+ try {
53667
+ const { appendLedgerEntry: appendLedgerEntry2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
53668
+ appendLedgerEntry2(meshId, {
53669
+ kind: "coordinator_started",
53670
+ sessionId: cliCmdLaunch.sessionId || cliCmdLaunch.id,
53671
+ providerType: cliType,
53672
+ payload: { workspace }
53673
+ });
53674
+ } catch {
53675
+ }
53676
+ return {
53677
+ success: true,
53678
+ meshId,
53679
+ cliType,
53680
+ workspace,
53681
+ sessionId: cliCmdLaunch.sessionId || cliCmdLaunch.id,
53682
+ mcpRegistered: true
53683
+ };
53684
+ }
53345
53685
  const configFormat = coordinatorSetup.configFormat;
53346
53686
  if (configFormat !== "claude_mcp_json" && configFormat !== "hermes_config_yaml") {
53347
53687
  return {
@@ -53396,9 +53736,11 @@ Run 'adhdev doctor' for detailed diagnostics.`
53396
53736
  args: coordinatorSetup.mcpServer.args
53397
53737
  };
53398
53738
  if (args?.inlineMesh) {
53739
+ const modeArgIndex = coordinatorSetup.mcpServer.args.findIndex((value) => value === "--mode");
53740
+ const mcpTransport = modeArgIndex >= 0 ? coordinatorSetup.mcpServer.args[modeArgIndex + 1] : "ipc";
53399
53741
  mcpServerEntry.env = {
53400
53742
  ADHDEV_INLINE_MESH: JSON.stringify(mesh),
53401
- ADHDEV_MCP_TRANSPORT: "ipc"
53743
+ ADHDEV_MCP_TRANSPORT: mcpTransport === "local" ? "local" : "ipc"
53402
53744
  };
53403
53745
  }
53404
53746
  try {
@@ -57240,6 +57582,11 @@ function annotateRapidReadChatAdvisory(payload, options) {
57240
57582
  // src/tools/mesh-tools.ts
57241
57583
  init_dist2();
57242
57584
  var meshSessionProviderMetadata = /* @__PURE__ */ new Map();
57585
+ function readString(value) {
57586
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
57587
+ }
57588
+ var DUPLICATE_DISPATCH_WINDOW_MS = 6e4;
57589
+ var STALE_ASSIGNED_QUEUE_MS = 30 * 6e4;
57243
57590
  async function refreshMeshFromDaemon(ctx) {
57244
57591
  if (!(ctx.transport instanceof IpcTransport)) return;
57245
57592
  try {
@@ -57260,6 +57607,138 @@ async function findNodeWithRefresh(ctx, nodeId) {
57260
57607
  if (!refreshed) throw new Error(`Node '${nodeId}' is not a member of mesh '${ctx.mesh.name}'`);
57261
57608
  return refreshed;
57262
57609
  }
57610
+ async function findOptionalNodeWithRefresh(ctx, nodeId) {
57611
+ const hit = ctx.mesh.nodes.find((n) => n.id === nodeId);
57612
+ if (hit) return hit;
57613
+ await refreshMeshFromDaemon(ctx);
57614
+ return ctx.mesh.nodes.find((n) => n.id === nodeId) ?? null;
57615
+ }
57616
+ function hasRecentDuplicateDispatch(ctx, args) {
57617
+ const now = Date.now();
57618
+ const normalizedMessage = args.message.trim();
57619
+ for (const task of getQueue(ctx.mesh.id)) {
57620
+ const timestamp2 = new Date(task.updatedAt || task.createdAt).getTime();
57621
+ if (!Number.isFinite(timestamp2) || now - timestamp2 > DUPLICATE_DISPATCH_WINDOW_MS) continue;
57622
+ if (task.targetNodeId && task.targetNodeId !== args.node_id) continue;
57623
+ if (task.assignedNodeId && task.assignedNodeId !== args.node_id) continue;
57624
+ if (args.session_id && task.targetSessionId !== args.session_id && task.assignedSessionId !== args.session_id) continue;
57625
+ if (task.message?.trim() === normalizedMessage) {
57626
+ return { duplicate: true, entry: task, source: "queue" };
57627
+ }
57628
+ }
57629
+ const entries = readLedgerEntries(ctx.mesh.id, { tail: 200 });
57630
+ for (let i = entries.length - 1; i >= 0; i -= 1) {
57631
+ const entry = entries[i];
57632
+ const timestamp2 = new Date(entry.timestamp).getTime();
57633
+ if (Number.isFinite(timestamp2) && now - timestamp2 > DUPLICATE_DISPATCH_WINDOW_MS) break;
57634
+ if (entry.kind !== "task_dispatched") continue;
57635
+ if (entry.nodeId !== args.node_id) continue;
57636
+ if (args.session_id && entry.sessionId !== args.session_id) continue;
57637
+ if (typeof entry.payload?.message !== "string") continue;
57638
+ if (entry.payload.message.trim() === normalizedMessage) {
57639
+ return { duplicate: true, entry, source: "ledger" };
57640
+ }
57641
+ }
57642
+ return { duplicate: false };
57643
+ }
57644
+ function buildMissingNodeReadChatRecovery(ctx, args) {
57645
+ const entries = readLedgerEntries(ctx.mesh.id, { tail: 300 });
57646
+ const relatedEntries = entries.filter((entry) => entry.nodeId === args.node_id || entry.sessionId === args.session_id);
57647
+ const completedEntries = relatedEntries.filter((entry) => entry.kind === "task_completed");
57648
+ const lastDispatch = [...relatedEntries].reverse().find((entry) => entry.kind === "task_dispatched");
57649
+ const lastTerminal = [...relatedEntries].reverse().find((entry) => entry.kind === "task_completed" || entry.kind === "task_failed" || entry.kind === "task_stalled");
57650
+ const lastRemoved = [...relatedEntries].reverse().find((entry) => entry.kind === "node_removed");
57651
+ const lastLaunch = [...relatedEntries].reverse().find((entry) => entry.kind === "session_launched");
57652
+ const providerSessionId = args.provider_session_id || readString(lastTerminal?.payload?.providerSessionId) || readString(lastLaunch?.payload?.providerSessionId) || readString(lastDispatch?.payload?.providerSessionId);
57653
+ const finalSummary = readString(lastTerminal?.payload?.finalSummary) || readString(lastTerminal?.payload?.compactSummary) || readString(lastTerminal?.payload?.summary);
57654
+ const ledger = {
57655
+ taskCompletedFound: completedEntries.length > 0,
57656
+ nodeRemovedFound: !!lastRemoved,
57657
+ providerType: lastTerminal?.providerType || lastLaunch?.providerType || lastDispatch?.providerType,
57658
+ providerSessionId,
57659
+ nodeRemovedAt: lastRemoved?.timestamp,
57660
+ sessionCleanupMode: readString(lastRemoved?.payload?.sessionCleanupMode),
57661
+ readDebugLocator: readString(lastTerminal?.payload?.readDebugLocator) || readString(lastTerminal?.payload?.debugBundlePath)
57662
+ };
57663
+ if (finalSummary) {
57664
+ return {
57665
+ success: true,
57666
+ compact: args.compact === true,
57667
+ recoveredFromLedger: true,
57668
+ nodeId: args.node_id,
57669
+ sessionId: args.session_id,
57670
+ summary: finalSummary,
57671
+ ledger,
57672
+ messages: [{ role: "assistant", content: finalSummary, isHistorical: true }]
57673
+ };
57674
+ }
57675
+ return {
57676
+ success: false,
57677
+ recoverable: true,
57678
+ code: "mesh_removed_node_transcript_unavailable",
57679
+ error: `Node '${args.node_id}' is not a current member of mesh '${ctx.mesh.name}'.`,
57680
+ nodeId: args.node_id,
57681
+ sessionId: args.session_id,
57682
+ providerSessionId,
57683
+ reason: "node_not_in_current_mesh_snapshot",
57684
+ ledger,
57685
+ completedSessionSeenInLedger: ledger.taskCompletedFound,
57686
+ lastDispatch: lastDispatch ? {
57687
+ timestamp: lastDispatch.timestamp,
57688
+ sessionId: lastDispatch.sessionId,
57689
+ providerType: lastDispatch.providerType,
57690
+ taskId: typeof lastDispatch.payload?.taskId === "string" ? lastDispatch.payload.taskId : void 0,
57691
+ messagePreview: typeof lastDispatch.payload?.message === "string" ? lastDispatch.payload.message.slice(0, 500) : void 0
57692
+ } : null,
57693
+ lastTerminalEvent: lastTerminal ? {
57694
+ kind: lastTerminal.kind,
57695
+ timestamp: lastTerminal.timestamp,
57696
+ sessionId: lastTerminal.sessionId,
57697
+ providerType: lastTerminal.providerType,
57698
+ taskId: typeof lastTerminal.payload?.taskId === "string" ? lastTerminal.payload.taskId : void 0,
57699
+ payload: lastTerminal.payload
57700
+ } : null,
57701
+ nextSteps: [
57702
+ providerSessionId ? `Retry mesh_read_chat with provider_session_id='${providerSessionId}' on a current live node for the same daemon if one exists.` : "If the node UI shows a provider transcript id, retry mesh_read_chat/mesh_read_debug with provider_session_id.",
57703
+ "Use mesh_read_debug with the provider_session_id or daemon-side debug bundle locator if available.",
57704
+ "Check mesh_task_history for task_completed and node_removed entries before redispatching; do not resend solely because transcript recovery failed.",
57705
+ "If this node was removed with stop_and_delete, the runtime transcript may be gone; rely on the ledger summary/locator or ask the operator for the saved UI output."
57706
+ ],
57707
+ recoveryHints: [
57708
+ "The worktree/node may have been removed or the mesh snapshot may be stale after task completion.",
57709
+ "If you have a provider_session_id, retry mesh_read_chat with that value while targeting a live node for the same daemon if available.",
57710
+ "Use mesh_read_debug with provider_session_id, or inspect the daemon/session-host history locator if the transcript has already been archived.",
57711
+ "Avoid redispatching the same task solely because read_chat could not recover the transcript; check task_history and git status first."
57712
+ ]
57713
+ };
57714
+ }
57715
+ function annotateQueueStaleness(queue) {
57716
+ const now = Date.now();
57717
+ return queue.map((task) => {
57718
+ const taskStatus = typeof task?.status === "string" ? task.status : void 0;
57719
+ const annotated = {
57720
+ ...task,
57721
+ taskStatus,
57722
+ dispatchedAt: task?.createdAt,
57723
+ ...taskStatus === "assigned" ? { activeTaskId: task.id } : {},
57724
+ ...taskStatus === "completed" || taskStatus === "failed" ? {
57725
+ isHistorical: true,
57726
+ completedAt: task.updatedAt
57727
+ } : {}
57728
+ };
57729
+ if (taskStatus !== "assigned") return annotated;
57730
+ const updatedAt = new Date(task.updatedAt).getTime();
57731
+ const ageMs = Number.isFinite(updatedAt) ? now - updatedAt : null;
57732
+ if (ageMs === null || ageMs < STALE_ASSIGNED_QUEUE_MS) return annotated;
57733
+ return {
57734
+ ...annotated,
57735
+ stale: true,
57736
+ staleAssigned: true,
57737
+ staleReason: "assigned task has not reached a terminal state within 30 minutes",
57738
+ assignedAgeMs: ageMs
57739
+ };
57740
+ });
57741
+ }
57263
57742
  function unwrapCommandPayload(value) {
57264
57743
  let current = value;
57265
57744
  const seen = /* @__PURE__ */ new Set();
@@ -57272,6 +57751,26 @@ function unwrapCommandPayload(value) {
57272
57751
  }
57273
57752
  return current;
57274
57753
  }
57754
+ function isTerminalSessionRecord(session) {
57755
+ const status = typeof session?.status === "string" ? session.status.toLowerCase() : "";
57756
+ const lifecycle = typeof session?.lifecycle === "string" ? session.lifecycle.toLowerCase() : "";
57757
+ const state = typeof session?.state === "string" ? session.state.toLowerCase() : "";
57758
+ return [status, lifecycle, state].some((value) => ["stopped", "failed", "terminated", "exited", "closed"].includes(value));
57759
+ }
57760
+ function isIdleSessionRecord(session) {
57761
+ if (isTerminalSessionRecord(session)) return false;
57762
+ const status = typeof session?.status === "string" ? session.status.toLowerCase() : "";
57763
+ const chatStatus = typeof session?.activeChat?.status === "string" ? session.activeChat.status.toLowerCase() : "";
57764
+ return status === "idle" || chatStatus === "waiting_input";
57765
+ }
57766
+ function chooseDispatchableSession(sessions, providerType, meshId, nodeId) {
57767
+ const live = sessions.filter((session) => !isTerminalSessionRecord(session));
57768
+ const matchingProvider = (session) => !providerType || session?.providerType === providerType || session?.cliType === providerType;
57769
+ const meshSessions = live.filter(
57770
+ (session) => session?.settings?.meshNodeFor === meshId || session?.settings?.meshNodeId === nodeId
57771
+ );
57772
+ return meshSessions.find((session) => isIdleSessionRecord(session) && matchingProvider(session)) || meshSessions.find(matchingProvider) || live.find((session) => isIdleSessionRecord(session) && matchingProvider(session)) || live.find(matchingProvider) || live.find(isIdleSessionRecord) || live[0];
57773
+ }
57275
57774
  function findNestedPayload(value, predicate) {
57276
57775
  const seen = /* @__PURE__ */ new Set();
57277
57776
  const stack = [{ payload: value, depth: 0 }];
@@ -57300,12 +57799,136 @@ function extractGitDiff(value) {
57300
57799
  function extractLaunchPayload(value) {
57301
57800
  return findNestedPayload(value, (payload) => Boolean(payload?.sessionId || payload?.id || payload?.runtimeSessionId));
57302
57801
  }
57802
+ function classifyMeshLaunchFailure(error48) {
57803
+ const message = error48 instanceof Error ? error48.message : String(error48 || "launch failed");
57804
+ const lower = message.toLowerCase();
57805
+ if (lower.includes("p2p") || lower.includes("datachannel") || lower.includes("node-datachannel")) {
57806
+ return { code: "p2p_unavailable", reason: "daemon_mesh_p2p_transport_unavailable", transport: "daemon_mesh_p2p" };
57807
+ }
57808
+ if (lower.includes("cannot connect to daemon ipc") || lower.includes("daemon ipc command")) {
57809
+ return { code: "local_ipc_unavailable", reason: "local_daemon_ipc_unavailable", transport: "local_ipc" };
57810
+ }
57811
+ if (lower.includes("timed out") || lower.includes("timeout")) {
57812
+ return { code: "mesh_transport_timeout", reason: "mesh_transport_timeout", transport: "mesh_transport" };
57813
+ }
57814
+ return { code: "mesh_launch_failed", reason: "provider_launch_failed", transport: "mesh_transport" };
57815
+ }
57816
+ function buildWorktreeCleanupHint(node) {
57817
+ if (!node.isLocalWorktree) return void 0;
57818
+ return {
57819
+ tool: "mesh_remove_node",
57820
+ args: { node_id: node.id, session_cleanup_mode: "preserve" },
57821
+ hint: `If the worktree is no longer needed, remove the orphan worktree node with mesh_remove_node(node_id: "${node.id}").`
57822
+ };
57823
+ }
57824
+ function buildRecoverableLaunchFailure(ctx, node, providerType, error48) {
57825
+ const message = error48 instanceof Error ? error48.message : String(error48 || "launch failed");
57826
+ const classified = classifyMeshLaunchFailure(error48);
57827
+ const cleanup = buildWorktreeCleanupHint(node);
57828
+ return {
57829
+ success: false,
57830
+ recoverable: true,
57831
+ code: classified.code,
57832
+ reason: classified.reason,
57833
+ transport: classified.transport,
57834
+ error: message,
57835
+ meshId: ctx.mesh.id,
57836
+ nodeId: node.id,
57837
+ daemonId: node.daemonId,
57838
+ workspace: node.workspace,
57839
+ isLocalWorktree: node.isLocalWorktree === true,
57840
+ worktreeBranch: node.worktreeBranch,
57841
+ clonedFromNodeId: node.clonedFromNodeId,
57842
+ ...providerType ? { resolvedProviderType: providerType } : {},
57843
+ retryHint: `Retry mesh_launch_session(node_id: "${node.id}"${providerType ? `, type: "${providerType}"` : ""}) after daemon mesh transport/P2P is healthy.`,
57844
+ ...cleanup ? { cleanup } : {},
57845
+ nextStepHints: [
57846
+ `Retry mesh_launch_session(node_id: "${node.id}"${providerType ? `, type: "${providerType}"` : ""}) after checking daemon/P2P health.`,
57847
+ ...cleanup ? [`Cleanup orphan worktree node with mesh_remove_node(node_id: "${node.id}") if retry is not desired.`] : [],
57848
+ "Run mesh_status to see the degraded reason and recovery hints before redispatching work."
57849
+ ]
57850
+ };
57851
+ }
57852
+ function recordRecoverableLaunchFailure(ctx, node, providerType, error48) {
57853
+ const failure2 = buildRecoverableLaunchFailure(ctx, node, providerType, error48);
57854
+ try {
57855
+ appendLedgerEntry(ctx.mesh.id, {
57856
+ kind: "recovery_attempted",
57857
+ nodeId: node.id,
57858
+ providerType,
57859
+ payload: {
57860
+ event: "session_launch_failed",
57861
+ ...failure2
57862
+ }
57863
+ });
57864
+ } catch {
57865
+ }
57866
+ return failure2;
57867
+ }
57868
+ function getLatestActiveLaunchFailure(meshId, nodeId) {
57869
+ const entries = readLedgerEntries(meshId, { tail: 200 });
57870
+ for (let i = entries.length - 1; i >= 0; i -= 1) {
57871
+ const entry = entries[i];
57872
+ if (entry.nodeId !== nodeId) continue;
57873
+ if (entry.kind === "session_launched" || entry.kind === "node_removed") return null;
57874
+ if (entry.kind === "recovery_attempted" && entry.payload?.event === "session_launch_failed") {
57875
+ return { timestamp: entry.timestamp, ...entry.payload };
57876
+ }
57877
+ }
57878
+ return null;
57879
+ }
57880
+ async function ipcDispatchToRemoteAgent(ctx, node, args) {
57881
+ const transport = ctx.transport;
57882
+ const daemonId = node.daemonId;
57883
+ let sessionId = args.session_id?.trim() || "";
57884
+ const providerPriorityList = Array.isArray(node.policy?.providerPriority) ? node.policy.providerPriority : [];
57885
+ let resolvedProviderType = args.providerType?.trim() || providerPriorityList[0] || "";
57886
+ if (!sessionId) {
57887
+ try {
57888
+ const relayResult = await transport.meshCommand(daemonId, "get_status_metadata", {});
57889
+ const innerResult = relayResult?.result ?? relayResult;
57890
+ const statusObj = innerResult?.status ?? innerResult;
57891
+ const sessions = Array.isArray(statusObj?.sessions) ? statusObj.sessions : [];
57892
+ const targetSession = chooseDispatchableSession(sessions, resolvedProviderType, ctx.mesh.id, node.id);
57893
+ if (targetSession?.id || targetSession?.sessionId) {
57894
+ sessionId = targetSession.id || targetSession.sessionId;
57895
+ if (!resolvedProviderType) {
57896
+ resolvedProviderType = targetSession.providerType || targetSession.cliType || "";
57897
+ }
57898
+ }
57899
+ } catch (e) {
57900
+ }
57901
+ }
57902
+ if (!resolvedProviderType) {
57903
+ return { success: false, error: `Cannot dispatch to remote node '${node.id}': providerType unknown. Set providerPriority on the node policy or call mesh_launch_session first.` };
57904
+ }
57905
+ try {
57906
+ const dispatchResult = await transport.meshCommand(daemonId, "agent_command", {
57907
+ ...sessionId ? { targetSessionId: sessionId } : {},
57908
+ agentType: resolvedProviderType,
57909
+ cliType: resolvedProviderType,
57910
+ action: "send_chat",
57911
+ message: args.message
57912
+ });
57913
+ const dispatchPayload = unwrapCommandPayload(dispatchResult);
57914
+ if (dispatchPayload?.success === false || dispatchResult?.success === false) {
57915
+ return { success: false, error: `P2P dispatch failed: ${dispatchPayload?.error || dispatchResult?.error || "agent_command rejected the task"}` };
57916
+ }
57917
+ return { success: true, dispatched: true, sessionId: sessionId || resolvedProviderType };
57918
+ } catch (e) {
57919
+ return { success: false, error: `P2P dispatch failed: ${e?.message || String(e)}` };
57920
+ }
57921
+ }
57303
57922
  function resolveCoordinatorNode(ctx) {
57304
57923
  const preferredNodeId = typeof ctx.mesh.coordinator?.preferredNodeId === "string" ? ctx.mesh.coordinator.preferredNodeId.trim() : "";
57305
57924
  if (preferredNodeId) {
57306
57925
  const preferred = ctx.mesh.nodes.find((n) => n.id === preferredNodeId && typeof n.daemonId === "string" && n.daemonId.trim());
57307
57926
  if (preferred) return preferred;
57308
57927
  }
57928
+ if (ctx.localMachineId) {
57929
+ const byMachine = ctx.mesh.nodes.find((n) => n.machineId === ctx.localMachineId);
57930
+ if (byMachine) return byMachine;
57931
+ }
57309
57932
  if (ctx.localDaemonId) {
57310
57933
  return ctx.mesh.nodes.find((n) => n.daemonId === ctx.localDaemonId);
57311
57934
  }
@@ -57395,7 +58018,8 @@ function getNodeLaunchReadiness(node) {
57395
58018
  };
57396
58019
  }
57397
58020
  async function commandForNode(ctx, node, command, args = {}) {
57398
- if (ctx.transport instanceof IpcTransport && node.daemonId && node.daemonId !== ctx.localDaemonId) {
58021
+ const isLocalNode = ctx.localMachineId && node.machineId === ctx.localMachineId || ctx.localDaemonId && node.daemonId === ctx.localDaemonId;
58022
+ if (ctx.transport instanceof IpcTransport && node.daemonId && !isLocalNode) {
57399
58023
  return ctx.transport.meshCommand(node.daemonId, command, args);
57400
58024
  }
57401
58025
  if (isLocalTransport(ctx.transport)) {
@@ -57405,10 +58029,12 @@ async function commandForNode(ctx, node, command, args = {}) {
57405
58029
  }
57406
58030
  var MESH_STATUS_TOOL = {
57407
58031
  name: "mesh_status",
57408
- description: "Get the current status of all nodes in the repo mesh \u2014 health, git state, active sessions. Use this to decide which node to send work to.",
58032
+ description: "Get the current status of all nodes in the repo mesh \u2014 health, git state, active sessions, recovery hints, and recommended next steps. Use this to decide which node to send work to or how to recover from failures.",
57409
58033
  inputSchema: {
57410
58034
  type: "object",
57411
- properties: {}
58035
+ properties: {
58036
+ _gemini_compat: { type: "string", description: "Dummy property for Gemini compatibility. Ignore this." }
58037
+ }
57412
58038
  }
57413
58039
  };
57414
58040
  var MESH_LIST_NODES_TOOL = {
@@ -57416,7 +58042,9 @@ var MESH_LIST_NODES_TOOL = {
57416
58042
  description: "List all nodes in the mesh with their capabilities, platform, and workspace paths.",
57417
58043
  inputSchema: {
57418
58044
  type: "object",
57419
- properties: {}
58045
+ properties: {
58046
+ _gemini_compat: { type: "string", description: "Dummy property for Gemini compatibility. Ignore this." }
58047
+ }
57420
58048
  }
57421
58049
  };
57422
58050
  var MESH_ENQUEUE_TASK_TOOL = {
@@ -57432,18 +58060,46 @@ var MESH_ENQUEUE_TASK_TOOL = {
57432
58060
  };
57433
58061
  var MESH_VIEW_QUEUE_TOOL = {
57434
58062
  name: "mesh_view_queue",
57435
- description: "View the current status of the mesh work queue (pending, assigned, completed, failed tasks).",
58063
+ description: "View the current status of the mesh work queue (pending, assigned, completed, failed, cancelled tasks).",
57436
58064
  inputSchema: {
57437
58065
  type: "object",
57438
58066
  properties: {
57439
58067
  status: {
57440
58068
  type: "array",
57441
58069
  items: { type: "string" },
57442
- description: "Filter by task status: pending, assigned, completed, failed. Returns all if omitted."
58070
+ description: "Filter by task status: pending, assigned, completed, failed, cancelled. Returns all if omitted."
57443
58071
  }
57444
58072
  }
57445
58073
  }
57446
58074
  };
58075
+ var MESH_QUEUE_CANCEL_TOOL = {
58076
+ name: "mesh_queue_cancel",
58077
+ description: "Cancel a pending/assigned/completed/failed mesh queue task without deleting audit history. Use this to retire stale queue items that target dead sessions.",
58078
+ inputSchema: {
58079
+ type: "object",
58080
+ properties: {
58081
+ task_id: { type: "string", description: "Queue task ID to cancel." },
58082
+ reason: { type: "string", description: "Optional operator-visible reason for cancellation." }
58083
+ },
58084
+ required: ["task_id"]
58085
+ }
58086
+ };
58087
+ var MESH_QUEUE_REQUEUE_TOOL = {
58088
+ name: "mesh_queue_requeue",
58089
+ 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.",
58090
+ inputSchema: {
58091
+ type: "object",
58092
+ properties: {
58093
+ task_id: { type: "string", description: "Queue task ID to requeue." },
58094
+ reason: { type: "string", description: "Optional operator-visible reason for requeueing." },
58095
+ target_node_id: { type: "string", description: "Optional replacement target node ID." },
58096
+ target_session_id: { type: "string", description: "Optional replacement target runtime session ID." },
58097
+ clear_target_node: { type: "boolean", description: "When true, remove any existing target node constraint." },
58098
+ 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." }
58099
+ },
58100
+ required: ["task_id"]
58101
+ }
58102
+ };
57447
58103
  var MESH_SEND_TASK_TOOL = {
57448
58104
  name: "mesh_send_task",
57449
58105
  description: "Legacy push-based task assignment. Enqueues a task specifically targeted at a given node. The node will pull it immediately if idle.",
@@ -57613,6 +58269,8 @@ var ALL_MESH_TOOLS = [
57613
58269
  MESH_LIST_NODES_TOOL,
57614
58270
  MESH_ENQUEUE_TASK_TOOL,
57615
58271
  MESH_VIEW_QUEUE_TOOL,
58272
+ MESH_QUEUE_CANCEL_TOOL,
58273
+ MESH_QUEUE_REQUEUE_TOOL,
57616
58274
  MESH_SEND_TASK_TOOL,
57617
58275
  MESH_READ_CHAT_TOOL,
57618
58276
  MESH_READ_DEBUG_TOOL,
@@ -57630,6 +58288,7 @@ async function meshStatus(ctx) {
57630
58288
  await refreshMeshFromDaemon(ctx);
57631
58289
  const { mesh, transport } = ctx;
57632
58290
  const results = [];
58291
+ const ledgerSummary = getLedgerSummary(mesh.id);
57633
58292
  for (const node of mesh.nodes) {
57634
58293
  const entry = {
57635
58294
  nodeId: node.id,
@@ -57663,6 +58322,45 @@ async function meshStatus(ctx) {
57663
58322
  entry.health = "degraded";
57664
58323
  entry.error = e.message;
57665
58324
  }
58325
+ const recoveryContext = getSessionRecoveryContext(mesh.id, { nodeId: node.id });
58326
+ if (recoveryContext.consecutiveNodeFailures > 0) {
58327
+ entry.recoveryHints = {
58328
+ consecutiveFailures: recoveryContext.consecutiveNodeFailures,
58329
+ lastTaskMessage: recoveryContext.lastTaskMessage,
58330
+ advice: recoveryContext.advice,
58331
+ retryRecommended: recoveryContext.retryRecommended
58332
+ };
58333
+ }
58334
+ const activeLaunchFailure = getLatestActiveLaunchFailure(mesh.id, node.id);
58335
+ if (activeLaunchFailure && node.isLocalWorktree) {
58336
+ entry.health = "degraded";
58337
+ entry.degradedReason = "worktree_launch_failed";
58338
+ entry.launchReady = false;
58339
+ entry.launchBlockedReason = activeLaunchFailure.code || "mesh_launch_failed";
58340
+ entry.launchBlockedMessage = activeLaunchFailure.error || "Previous worktree session launch failed";
58341
+ entry.lastLaunchFailure = activeLaunchFailure;
58342
+ }
58343
+ const nextStepHints = [];
58344
+ if (entry.degradedReason === "worktree_launch_failed") {
58345
+ nextStepHints.push(`Retry mesh_launch_session(node_id: "${node.id}") after daemon mesh transport/P2P is healthy.`);
58346
+ nextStepHints.push(`If retry is not desired, cleanup the orphan worktree node with mesh_remove_node(node_id: "${node.id}").`);
58347
+ } else if (entry.health === "online" && node.isLocalWorktree) {
58348
+ nextStepHints.push(`Merge worktree to base via mesh_refine_node(node_id: "${node.id}")`);
58349
+ } else if (entry.health === "dirty") {
58350
+ nextStepHints.push(`Commit changes via mesh_checkpoint(node_id: "${node.id}", message: "...")`);
58351
+ } else if (entry.health === "degraded" && entry.error?.includes("git")) {
58352
+ nextStepHints.push("Initialize git repository or check workspace path.");
58353
+ }
58354
+ if (recoveryContext.consecutiveNodeFailures > 0) {
58355
+ if (recoveryContext.retryRecommended) {
58356
+ nextStepHints.push(`Retry task on this node or launch a fresh session.`);
58357
+ } else {
58358
+ nextStepHints.push(`Consider reassigning work to a different node.`);
58359
+ }
58360
+ }
58361
+ if (nextStepHints.length > 0) {
58362
+ entry.nextStepHints = nextStepHints;
58363
+ }
57666
58364
  const relatedRepos = await collectRelatedRepoStatuses(ctx, node);
57667
58365
  if (relatedRepos.length) entry.relatedRepos = relatedRepos;
57668
58366
  results.push(entry);
@@ -57676,7 +58374,7 @@ async function meshStatus(ctx) {
57676
58374
  nodes: results
57677
58375
  };
57678
58376
  try {
57679
- response.ledgerSummary = getLedgerSummary(mesh.id);
58377
+ response.ledgerSummary = ledgerSummary;
57680
58378
  } catch {
57681
58379
  }
57682
58380
  if (ctx.transport instanceof IpcTransport) {
@@ -57720,12 +58418,38 @@ async function meshListNodes(ctx) {
57720
58418
  async function meshEnqueueTask(ctx, args) {
57721
58419
  try {
57722
58420
  const task = enqueueTask(ctx.mesh.id, args.message);
57723
- if (ctx.transport instanceof IpcTransport && ctx.localDaemonId) {
57724
- ctx.transport.meshCommand(ctx.localDaemonId, "trigger_mesh_queue", { meshId: ctx.mesh.id }).catch(() => {
58421
+ if (isLocalTransport(ctx.transport) && !(ctx.transport instanceof IpcTransport)) {
58422
+ ctx.transport.command("trigger_mesh_queue", { meshId: ctx.mesh.id }).catch(() => {
57725
58423
  });
57726
- } else if (isLocalTransport(ctx.transport)) {
58424
+ return JSON.stringify({ success: true, taskId: task.id, status: task.status });
58425
+ }
58426
+ if (ctx.transport instanceof IpcTransport) {
57727
58427
  ctx.transport.command("trigger_mesh_queue", { meshId: ctx.mesh.id }).catch(() => {
57728
58428
  });
58429
+ const dispatchPromises = [];
58430
+ for (const node of ctx.mesh.nodes) {
58431
+ const isLocalNode = ctx.localMachineId && node.machineId === ctx.localMachineId || ctx.localDaemonId && node.daemonId === ctx.localDaemonId;
58432
+ if (isLocalNode || !node.daemonId) continue;
58433
+ dispatchPromises.push(
58434
+ ipcDispatchToRemoteAgent(ctx, node, { message: args.message }).then((result) => {
58435
+ if (result.success) {
58436
+ try {
58437
+ appendLedgerEntry(ctx.mesh.id, {
58438
+ kind: "task_dispatched",
58439
+ nodeId: node.id,
58440
+ sessionId: result.sessionId,
58441
+ payload: { message: args.message, via: "p2p_direct", taskId: task.id }
58442
+ });
58443
+ } catch {
58444
+ }
58445
+ }
58446
+ }).catch(() => {
58447
+ })
58448
+ );
58449
+ }
58450
+ Promise.all(dispatchPromises).catch(() => {
58451
+ });
58452
+ return JSON.stringify({ success: true, taskId: task.id, status: task.status });
57729
58453
  }
57730
58454
  return JSON.stringify({ success: true, taskId: task.id, status: task.status });
57731
58455
  } catch (e) {
@@ -57734,8 +58458,51 @@ async function meshEnqueueTask(ctx, args) {
57734
58458
  }
57735
58459
  async function meshViewQueue(ctx, args) {
57736
58460
  try {
57737
- const queue = getQueue(ctx.mesh.id, { status: args.status });
57738
- return JSON.stringify({ success: true, queue }, null, 2);
58461
+ const queue = annotateQueueStaleness(getQueue(ctx.mesh.id, { status: args.status }));
58462
+ const staleAssignedTasks = queue.filter((task) => task?.status === "assigned" && task?.staleAssigned);
58463
+ return JSON.stringify({
58464
+ success: true,
58465
+ queue,
58466
+ staleAssignedTasks,
58467
+ staleAssignedCount: staleAssignedTasks.length,
58468
+ // Back-compat alias for callers already reading the first hardening payload.
58469
+ staleAssignments: staleAssignedTasks
58470
+ }, null, 2);
58471
+ } catch (e) {
58472
+ return JSON.stringify({ success: false, error: e.message });
58473
+ }
58474
+ }
58475
+ async function meshQueueCancel(ctx, args) {
58476
+ try {
58477
+ const taskId = (args.task_id || args.taskId || "").trim();
58478
+ if (!taskId) return JSON.stringify({ success: false, error: "task_id required" });
58479
+ const task = cancelTask(ctx.mesh.id, taskId, { reason: args.reason });
58480
+ if (!task) return JSON.stringify({ success: false, error: `Queue task '${taskId}' not found` });
58481
+ return JSON.stringify({ success: true, task }, null, 2);
58482
+ } catch (e) {
58483
+ return JSON.stringify({ success: false, error: e.message });
58484
+ }
58485
+ }
58486
+ async function meshQueueRequeue(ctx, args) {
58487
+ try {
58488
+ const taskId = (args.task_id || args.taskId || "").trim();
58489
+ if (!taskId) return JSON.stringify({ success: false, error: "task_id required" });
58490
+ const targetNodeId = (args.target_node_id || args.targetNodeId || "").trim() || void 0;
58491
+ const targetSessionId = (args.target_session_id || args.targetSessionId || "").trim() || void 0;
58492
+ const keepTargetSession = args.keep_target_session === true || args.keepTargetSession === true;
58493
+ const task = requeueTask(ctx.mesh.id, taskId, {
58494
+ reason: args.reason,
58495
+ targetNodeId,
58496
+ targetSessionId,
58497
+ clearTargetNode: args.clear_target_node === true || args.clearTargetNode === true,
58498
+ clearTargetSession: targetSessionId ? false : !keepTargetSession
58499
+ });
58500
+ if (!task) return JSON.stringify({ success: false, error: `Queue task '${taskId}' not found` });
58501
+ if (isLocalTransport(ctx.transport)) {
58502
+ ctx.transport.command("trigger_mesh_queue", { meshId: ctx.mesh.id }).catch(() => {
58503
+ });
58504
+ }
58505
+ return JSON.stringify({ success: true, task }, null, 2);
57739
58506
  } catch (e) {
57740
58507
  return JSON.stringify({ success: false, error: e.message });
57741
58508
  }
@@ -57745,6 +58512,24 @@ async function meshSendTask(ctx, args) {
57745
58512
  if (node.policy?.readOnly) {
57746
58513
  return JSON.stringify({ error: `Node '${args.node_id}' is read-only` });
57747
58514
  }
58515
+ const duplicate = hasRecentDuplicateDispatch(ctx, args);
58516
+ if (duplicate.duplicate) {
58517
+ return JSON.stringify({
58518
+ success: true,
58519
+ duplicate: true,
58520
+ dispatched: false,
58521
+ warning: "Duplicate mesh_send_task suppressed: the same node/session/message was dispatched recently.",
58522
+ nodeId: args.node_id,
58523
+ sessionId: args.session_id,
58524
+ source: duplicate.source,
58525
+ previousDispatch: duplicate.entry ? {
58526
+ id: duplicate.entry.id,
58527
+ timestamp: duplicate.entry.timestamp || duplicate.entry.updatedAt || duplicate.entry.createdAt,
58528
+ nodeId: duplicate.entry.nodeId || duplicate.entry.targetNodeId || duplicate.entry.assignedNodeId,
58529
+ sessionId: duplicate.entry.sessionId || duplicate.entry.targetSessionId || duplicate.entry.assignedSessionId
58530
+ } : void 0
58531
+ });
58532
+ }
57748
58533
  try {
57749
58534
  if (!isLocalTransport(ctx.transport) && node.daemonId) {
57750
58535
  const res = await ctx.transport.meshEnqueueTask(node.daemonId, {
@@ -57754,11 +58539,66 @@ async function meshSendTask(ctx, args) {
57754
58539
  });
57755
58540
  return JSON.stringify(res);
57756
58541
  }
57757
- const task = enqueueTask(ctx.mesh.id, args.message, { targetNodeId: args.node_id });
57758
- if (ctx.transport instanceof IpcTransport && node.daemonId && node.daemonId !== ctx.localDaemonId) {
57759
- ctx.transport.meshCommand(node.daemonId, "trigger_mesh_queue", { meshId: ctx.mesh.id }).catch(() => {
58542
+ const isLocalNode = ctx.localMachineId && node.machineId === ctx.localMachineId || ctx.localDaemonId && node.daemonId === ctx.localDaemonId;
58543
+ if (ctx.transport instanceof IpcTransport && node.daemonId && !isLocalNode) {
58544
+ const cached2 = meshSessionProviderMetadata.get(meshSessionCacheKey(args.node_id, args.session_id || ""));
58545
+ const result = await ipcDispatchToRemoteAgent(ctx, node, {
58546
+ session_id: args.session_id,
58547
+ message: args.message,
58548
+ providerType: cached2?.providerType
57760
58549
  });
57761
- } else if (isLocalTransport(ctx.transport)) {
58550
+ if (result.success) {
58551
+ const dispatchedSessionId = args.session_id || result.sessionId;
58552
+ try {
58553
+ appendLedgerEntry(ctx.mesh.id, {
58554
+ kind: "task_dispatched",
58555
+ nodeId: args.node_id,
58556
+ sessionId: dispatchedSessionId,
58557
+ payload: {
58558
+ message: args.message,
58559
+ via: "p2p_direct",
58560
+ ...dispatchedSessionId ? { targetSessionId: dispatchedSessionId } : {}
58561
+ }
58562
+ });
58563
+ } catch {
58564
+ }
58565
+ }
58566
+ return JSON.stringify({ ...result, nodeId: args.node_id, dispatched: result.success === true });
58567
+ }
58568
+ if (args.session_id && isLocalTransport(ctx.transport)) {
58569
+ const cached2 = meshSessionProviderMetadata.get(meshSessionCacheKey(args.node_id, args.session_id));
58570
+ const dispatchResult = await commandForNode(ctx, node, "agent_command", {
58571
+ targetSessionId: args.session_id,
58572
+ ...cached2?.providerType ? { agentType: cached2.providerType, cliType: cached2.providerType, providerType: cached2.providerType } : {},
58573
+ action: "send_chat",
58574
+ message: args.message
58575
+ });
58576
+ const dispatchPayload = unwrapCommandPayload(dispatchResult);
58577
+ if (dispatchPayload?.success === false || dispatchResult?.success === false) {
58578
+ return JSON.stringify({
58579
+ success: false,
58580
+ nodeId: args.node_id,
58581
+ sessionId: args.session_id,
58582
+ error: dispatchPayload?.error || dispatchResult?.error || "agent_command rejected the task"
58583
+ });
58584
+ }
58585
+ try {
58586
+ appendLedgerEntry(ctx.mesh.id, {
58587
+ kind: "task_dispatched",
58588
+ nodeId: args.node_id,
58589
+ sessionId: args.session_id,
58590
+ providerType: cached2?.providerType,
58591
+ payload: { message: args.message, via: "local_direct" }
58592
+ });
58593
+ } catch {
58594
+ }
58595
+ return JSON.stringify({ success: true, dispatched: true, nodeId: args.node_id, sessionId: args.session_id });
58596
+ }
58597
+ const task = enqueueTask(ctx.mesh.id, args.message, {
58598
+ targetNodeId: args.node_id,
58599
+ targetSessionId: args.session_id
58600
+ });
58601
+ if (isLocalTransport(ctx.transport) || ctx.transport instanceof IpcTransport) {
57762
58602
  ctx.transport.command("trigger_mesh_queue", { meshId: ctx.mesh.id }).catch(() => {
57763
58603
  });
57764
58604
  }
@@ -57768,7 +58608,10 @@ async function meshSendTask(ctx, args) {
57768
58608
  }
57769
58609
  }
57770
58610
  async function meshReadChat(ctx, args) {
57771
- const node = await findNodeWithRefresh(ctx, args.node_id);
58611
+ const node = await findOptionalNodeWithRefresh(ctx, args.node_id);
58612
+ if (!node) {
58613
+ return JSON.stringify(buildMissingNodeReadChatRecovery(ctx, args), null, 2);
58614
+ }
57772
58615
  if (isLocalTransport(ctx.transport)) {
57773
58616
  const cached2 = meshSessionProviderMetadata.get(meshSessionCacheKey(args.node_id, args.session_id));
57774
58617
  const providerSessionId = typeof args.provider_session_id === "string" && args.provider_session_id.trim() ? args.provider_session_id.trim() : cached2?.providerSessionId;
@@ -57871,19 +58714,28 @@ async function meshLaunchSession(ctx, args) {
57871
58714
  const coordinatorNode = resolveCoordinatorNode(ctx);
57872
58715
  const coordinatorDaemonId = coordinatorNode?.daemonId || ctx.localDaemonId;
57873
58716
  const spawnedSessionVisibility = readSpawnedSessionVisibility(ctx.mesh.policy);
57874
- const result = await commandForNode(ctx, node, "launch_cli", {
57875
- cliType: resolvedProviderType,
57876
- dir: node.workspace,
57877
- settings: {
57878
- meshNodeFor: ctx.mesh.id,
57879
- meshNodeId: args.node_id,
57880
- spawnedSessionVisibility,
57881
- ...coordinatorDaemonId ? { meshCoordinatorDaemonId: coordinatorDaemonId } : {},
57882
- ...coordinatorNode?.id ? { meshCoordinatorNodeId: coordinatorNode.id } : {},
57883
- launchedByCoordinator: true
57884
- }
57885
- });
58717
+ let result;
58718
+ try {
58719
+ result = await commandForNode(ctx, node, "launch_cli", {
58720
+ cliType: resolvedProviderType,
58721
+ dir: node.workspace,
58722
+ settings: {
58723
+ meshNodeFor: ctx.mesh.id,
58724
+ meshNodeId: args.node_id,
58725
+ spawnedSessionVisibility,
58726
+ ...coordinatorDaemonId ? { meshCoordinatorDaemonId: coordinatorDaemonId } : {},
58727
+ ...coordinatorNode?.id ? { meshCoordinatorNodeId: coordinatorNode.id } : {},
58728
+ launchedByCoordinator: true
58729
+ }
58730
+ });
58731
+ } catch (e) {
58732
+ return JSON.stringify(recordRecoverableLaunchFailure(ctx, node, resolvedProviderType, e), null, 2);
58733
+ }
57886
58734
  const launchPayload = extractLaunchPayload(result);
58735
+ if (launchPayload?.success === false || result?.success === false) {
58736
+ const launchError = new Error(launchPayload?.error || result?.error || "launch_cli rejected the session launch");
58737
+ return JSON.stringify(recordRecoverableLaunchFailure(ctx, node, resolvedProviderType, launchError), null, 2);
58738
+ }
57887
58739
  const runtimeSessionId = typeof launchPayload?.sessionId === "string" ? launchPayload.sessionId : typeof launchPayload?.id === "string" ? launchPayload.id : typeof launchPayload?.runtimeSessionId === "string" ? launchPayload.runtimeSessionId : "";
57888
58740
  const providerSessionId = typeof launchPayload?.providerSessionId === "string" && launchPayload.providerSessionId.trim() ? launchPayload.providerSessionId.trim() : void 0;
57889
58741
  if (runtimeSessionId) {
@@ -57902,7 +58754,8 @@ async function meshLaunchSession(ctx, args) {
57902
58754
  });
57903
58755
  } catch {
57904
58756
  }
57905
- if (ctx.transport instanceof IpcTransport && node.daemonId && node.daemonId !== ctx.localDaemonId) {
58757
+ const isLocalNode = ctx.localMachineId && node.machineId === ctx.localMachineId || ctx.localDaemonId && node.daemonId === ctx.localDaemonId;
58758
+ if (ctx.transport instanceof IpcTransport && node.daemonId && !isLocalNode) {
57906
58759
  ctx.transport.meshCommand(node.daemonId, "trigger_mesh_queue", { meshId: ctx.mesh.id }).catch(() => {
57907
58760
  });
57908
58761
  } else if (isLocalTransport(ctx.transport)) {
@@ -57952,7 +58805,7 @@ async function meshLaunchSession(ctx, args) {
57952
58805
  }
57953
58806
  return JSON.stringify({ ...res, resolvedProviderType }, null, 2);
57954
58807
  } catch (e) {
57955
- return JSON.stringify({ success: false, error: e.message });
58808
+ return JSON.stringify(recordRecoverableLaunchFailure(ctx, node, resolvedProviderType, e), null, 2);
57956
58809
  }
57957
58810
  } else {
57958
58811
  return JSON.stringify({ error: "Cloud mesh launch_session requires node daemonId" });
@@ -59840,6 +60693,15 @@ async function startMcpServer(opts) {
59840
60693
  process.exit(1);
59841
60694
  }
59842
60695
  let localDaemonId;
60696
+ let localMachineId;
60697
+ if (transport instanceof LocalTransport || transport instanceof IpcTransport) {
60698
+ try {
60699
+ const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_dist2(), dist_exports));
60700
+ const cfg = loadConfig2();
60701
+ if (cfg.registeredMachineId) localMachineId = cfg.registeredMachineId;
60702
+ } catch {
60703
+ }
60704
+ }
59843
60705
  if (transport instanceof IpcTransport) {
59844
60706
  try {
59845
60707
  const statusResult = await transport.getStatus();
@@ -59848,7 +60710,7 @@ async function startMcpServer(opts) {
59848
60710
  } catch {
59849
60711
  }
59850
60712
  }
59851
- const meshCtx = { mesh, transport, ...localDaemonId ? { localDaemonId } : {} };
60713
+ const meshCtx = { mesh, transport, ...localDaemonId ? { localDaemonId } : {}, ...localMachineId ? { localMachineId } : {} };
59852
60714
  const coordinatorPrompt = await buildMeshModeCoordinatorPrompt(mesh);
59853
60715
  const server2 = new import_server.Server(
59854
60716
  { name: "adhdev-mcp-server", version: "0.9.76" },
@@ -59888,6 +60750,12 @@ async function startMcpServer(opts) {
59888
60750
  case "mesh_view_queue":
59889
60751
  text = await meshViewQueue(meshCtx, a);
59890
60752
  break;
60753
+ case "mesh_queue_cancel":
60754
+ text = await meshQueueCancel(meshCtx, a);
60755
+ break;
60756
+ case "mesh_queue_requeue":
60757
+ text = await meshQueueRequeue(meshCtx, a);
60758
+ break;
59891
60759
  case "mesh_send_task":
59892
60760
  text = await meshSendTask(meshCtx, a);
59893
60761
  break;