@adhdev/daemon-standalone 0.9.82-rc.12 → 0.9.82-rc.122

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.
Files changed (37) hide show
  1. package/dist/index.js +27232 -21374
  2. package/dist/index.js.map +1 -1
  3. package/package.json +1 -1
  4. package/public/assets/index--3Wc6sJr.js +100 -0
  5. package/public/assets/index-BJ05ceSl.js +98 -0
  6. package/public/assets/index-BKsjvBcH.js +100 -0
  7. package/public/assets/index-BNKDsz6G.css +1 -0
  8. package/public/assets/index-BfLqOvWH.js +98 -0
  9. package/public/assets/index-BggZArlj.js +99 -0
  10. package/public/assets/index-Bso1b8Lh.css +1 -0
  11. package/public/assets/index-BzfqwAXl.js +98 -0
  12. package/public/assets/index-CAip3He8.js +100 -0
  13. package/public/assets/index-CCQPbtl4.css +1 -0
  14. package/public/assets/index-CYwXUKol.js +98 -0
  15. package/public/assets/index-CiB8XPwO.css +1 -0
  16. package/public/assets/index-CsEmn20l.css +1 -0
  17. package/public/assets/index-CsR4qRd4.js +98 -0
  18. package/public/assets/index-DDB8O9lr.js +100 -0
  19. package/public/assets/index-DJmCzwTk.js +98 -0
  20. package/public/assets/index-DW3PmABW.js +99 -0
  21. package/public/assets/index-DaIkPFUd.js +99 -0
  22. package/public/assets/index-Dc9o_onl.js +98 -0
  23. package/public/assets/index-DcAeIiVq.css +1 -0
  24. package/public/assets/index-Deb1Bk0M.js +98 -0
  25. package/public/assets/index-DhQzhjNN.js +98 -0
  26. package/public/assets/index-Dt2Xvr87.js +98 -0
  27. package/public/assets/index-R9GDvGJ8.js +98 -0
  28. package/public/assets/index-kt4CV7OM.js +100 -0
  29. package/public/assets/index-phY3RKNC.js +98 -0
  30. package/public/assets/index-xSlc1ntZ.css +1 -0
  31. package/public/assets/index-yF4m-swI.js +100 -0
  32. package/public/assets/terminal-D46M5EWH.js +143 -0
  33. package/public/assets/terminal-NZFQPQy6.js +143 -0
  34. package/public/assets/vendor-C7br1-G2.js +2745 -0
  35. package/public/index.html +2 -2
  36. package/vendor/mcp-server/index.js +979 -88
  37. package/vendor/mcp-server/index.js.map +1 -1
@@ -35,9 +35,21 @@ __export(index_exports, {
35
35
  });
36
36
  module.exports = __toCommonJS(index_exports);
37
37
 
38
+ // src/tools/mesh-tools.ts
39
+ var import_node_crypto = require("crypto");
40
+
38
41
  // src/transports/ipc.ts
39
42
  var DEFAULT_IPC_PORT = 19222;
40
43
  var DEFAULT_IPC_PATH = "/ipc";
44
+ var DEFAULT_IPC_COMMAND_TIMEOUT_MS = 15e3;
45
+ var IPC_COMMAND_TIMEOUTS_MS = {
46
+ mesh_relay_command: 12e4,
47
+ agent_command: 3e4,
48
+ git_status: 45e3,
49
+ git_diff_summary: 45e3,
50
+ fast_forward_mesh_node: 12e4,
51
+ mesh_status: 12e4
52
+ };
41
53
  var IpcTransport = class {
42
54
  port;
43
55
  path;
@@ -85,9 +97,22 @@ var IpcTransport = class {
85
97
  }
86
98
  fn();
87
99
  };
88
- const timeoutMs = type === "mesh_relay_command" ? 6e4 : 15e3;
100
+ const nestedCommand = typeof args?.command === "string" ? args.command : "";
101
+ const targetDaemonId = typeof args?.targetDaemonId === "string" ? args.targetDaemonId : "";
102
+ const effectiveType = type === "mesh_relay_command" && nestedCommand ? nestedCommand : type;
103
+ const timeoutMs = Math.max(
104
+ IPC_COMMAND_TIMEOUTS_MS[type] ?? DEFAULT_IPC_COMMAND_TIMEOUT_MS,
105
+ IPC_COMMAND_TIMEOUTS_MS[effectiveType] ?? DEFAULT_IPC_COMMAND_TIMEOUT_MS
106
+ );
107
+ const diagnosticParts = [
108
+ `command='${type}'`,
109
+ ...nestedCommand ? [`relayedCommand='${nestedCommand}'`] : [],
110
+ ...targetDaemonId ? [`targetDaemonId='${targetDaemonId.slice(0, 12)}'`] : [],
111
+ ...typeof args?.nodeId === "string" ? [`nodeId='${args.nodeId}'`] : [],
112
+ ...typeof args?.workspace === "string" ? [`workspace='${args.workspace}'`] : []
113
+ ];
89
114
  const timeout = setTimeout(() => {
90
- finish(() => reject(new Error(`Daemon IPC command '${type}' timed out after ${Math.round(timeoutMs / 1e3)}s`)));
115
+ finish(() => reject(new Error(`Daemon IPC ${diagnosticParts.join(" ")} timed out after ${Math.round(timeoutMs / 1e3)}s (requestId=${requestId})`)));
91
116
  }, timeoutMs);
92
117
  let commandSent = false;
93
118
  const send = () => {
@@ -143,6 +168,10 @@ function isLocalTransport(transport) {
143
168
  }
144
169
 
145
170
  // src/tools/chat-compact.ts
171
+ function isAssistantLike(message) {
172
+ const role = String(message?.role ?? "").toLowerCase();
173
+ return role === "assistant" || role === "agent";
174
+ }
146
175
  function messageContent(message) {
147
176
  const content = message?.content;
148
177
  if (typeof content === "string") return content;
@@ -161,16 +190,22 @@ function isCoordinatorVisibleMessage(message) {
161
190
  if (meta?.internal === true || meta?.debug === true || meta?.control === true || meta?.userVisible === false || meta?.user_visible === false) return false;
162
191
  return role === "user" || role === "assistant" || role === "agent";
163
192
  }
193
+ function buildCompactMessageTail(visibleMessages, opts) {
194
+ const summary = typeof opts.summary === "string" ? opts.summary.trim() : "";
195
+ const shouldOmitSummaryMessage = !!summary && !!opts.finalAssistant && isAssistantLike(opts.finalAssistant) && messageContent(opts.finalAssistant).trim() === summary;
196
+ const sourceMessages = shouldOmitSummaryMessage ? visibleMessages.filter((message) => message !== opts.finalAssistant) : visibleMessages;
197
+ return sourceMessages.slice(-opts.limit);
198
+ }
164
199
  function compactChatPayload(payload, opts = {}) {
165
200
  const rawMessages = Array.isArray(payload?.messages) ? payload.messages : [];
166
201
  const visible = rawMessages.filter(isCoordinatorVisibleMessage);
167
202
  const limit = Math.max(1, Math.min(opts.limit ?? 10, 10));
168
- const messages = visible.slice(-limit);
169
203
  const finalAssistant = [...visible].reverse().find((message) => {
170
204
  const role = String(message?.role ?? "").toLowerCase();
171
205
  return (role === "assistant" || role === "agent") && messageContent(message).trim();
172
206
  });
173
207
  const summary = typeof payload?.summary === "string" && payload.summary.trim() ? payload.summary.trim() : messageContent(finalAssistant).trim();
208
+ const messages = buildCompactMessageTail(visible, { summary, finalAssistant, limit });
174
209
  return {
175
210
  success: payload?.success !== false,
176
211
  compact: true,
@@ -232,9 +267,45 @@ function annotateRapidReadChatAdvisory(payload, options) {
232
267
  // src/tools/mesh-tools.ts
233
268
  var import_daemon_core = require("@adhdev/daemon-core");
234
269
  var meshSessionProviderMetadata = /* @__PURE__ */ new Map();
270
+ var ACTIVE_WORK_POLLING_BACKOFF_MS = 6e4;
271
+ function buildActiveWorkPollingGuidance(summary, now = Date.now()) {
272
+ if (!summary || summary.generatingCount <= 0) return void 0;
273
+ return {
274
+ activeGeneratingWork: true,
275
+ generatingCount: summary.generatingCount,
276
+ doNotPollBefore: new Date(now + ACTIVE_WORK_POLLING_BACKOFF_MS).toISOString(),
277
+ eventSurface: "pendingCoordinatorEvents",
278
+ nextRecommendedAction: "Wait for pendingCoordinatorEvents/completion events or an explicit user status request. If no terminal evidence appears and the user asks for status, make one bounded status check, then wait again.",
279
+ message: "Do not repeatedly poll mesh_status/mesh_view_queue/mesh_read_chat while delegated work is generating; terminal ledger or completion evidence will be surfaced through pendingCoordinatorEvents when available."
280
+ };
281
+ }
235
282
  function readString(value) {
236
283
  return typeof value === "string" && value.trim() ? value.trim() : void 0;
237
284
  }
285
+ function summarizeTaskMessage(message) {
286
+ const taskSummary = message.replace(/\s+/g, " ").trim();
287
+ const taskTitle = taskSummary.length > 96 ? `${taskSummary.slice(0, 93)}...` : taskSummary;
288
+ return { taskTitle: taskTitle || "(untitled task)", taskSummary };
289
+ }
290
+ function buildDirectTaskPayload(message, via, opts) {
291
+ const descriptor = summarizeTaskMessage(message);
292
+ return {
293
+ source: "direct",
294
+ via,
295
+ taskId: opts.taskId,
296
+ message,
297
+ taskTitle: descriptor.taskTitle,
298
+ taskSummary: descriptor.taskSummary,
299
+ ...opts.taskMode ? { taskMode: opts.taskMode } : {},
300
+ ...opts.providerType ? { providerType: opts.providerType } : {},
301
+ ...opts.targetSessionId ? { targetSessionId: opts.targetSessionId } : {}
302
+ };
303
+ }
304
+ function findNode(mesh, nodeId) {
305
+ const node = mesh.nodes.find((n) => n.id === nodeId);
306
+ if (!node) throw new Error(`Node '${nodeId}' is not a member of mesh '${mesh.name}'`);
307
+ return node;
308
+ }
238
309
  var DUPLICATE_DISPATCH_WINDOW_MS = 6e4;
239
310
  var STALE_ASSIGNED_QUEUE_MS = 30 * 6e4;
240
311
  var OLD_HISTORICAL_QUEUE_RECORD_MS = 7 * 24 * 60 * 6e4;
@@ -246,15 +317,24 @@ async function refreshMeshFromDaemon(ctx) {
246
317
  const result = await ctx.transport.command("get_mesh", { meshId: ctx.mesh.id });
247
318
  if (!result?.success || !Array.isArray(result.mesh?.nodes)) return;
248
319
  const refreshedNodes = result.mesh.nodes.filter((n) => n?.id).map((n) => n);
249
- if (!refreshedNodes.length) return;
250
320
  ctx.mesh.nodes.splice(0, ctx.mesh.nodes.length, ...refreshedNodes);
251
321
  ctx.mesh.updatedAt = result.mesh.updatedAt ?? ctx.mesh.updatedAt;
252
322
  } catch {
253
323
  }
254
324
  }
325
+ async function syncCoordinatorDaemonMeshCache(ctx) {
326
+ if (!(ctx.transport instanceof IpcTransport)) return;
327
+ try {
328
+ await ctx.transport.command("get_mesh", {
329
+ meshId: ctx.mesh.id,
330
+ inlineMesh: ctx.mesh
331
+ });
332
+ } catch {
333
+ }
334
+ }
255
335
  async function findNodeWithRefresh(ctx, nodeId) {
256
336
  const hit = ctx.mesh.nodes.find((n) => n.id === nodeId);
257
- if (hit) return hit;
337
+ if (hit && !hit.isLocalWorktree) return hit;
258
338
  await refreshMeshFromDaemon(ctx);
259
339
  const refreshed = ctx.mesh.nodes.find((n) => n.id === nodeId);
260
340
  if (!refreshed) throw new Error(`Node '${nodeId}' is not a member of mesh '${ctx.mesh.name}'`);
@@ -262,7 +342,7 @@ async function findNodeWithRefresh(ctx, nodeId) {
262
342
  }
263
343
  async function findOptionalNodeWithRefresh(ctx, nodeId) {
264
344
  const hit = ctx.mesh.nodes.find((n) => n.id === nodeId);
265
- if (hit) return hit;
345
+ if (hit && !hit.isLocalWorktree) return hit;
266
346
  await refreshMeshFromDaemon(ctx);
267
347
  return ctx.mesh.nodes.find((n) => n.id === nodeId) ?? null;
268
348
  }
@@ -314,9 +394,26 @@ function buildMissingNodeReadChatRecovery(ctx, args) {
314
394
  readDebugLocator: readString(lastTerminal?.payload?.readDebugLocator) || readString(lastTerminal?.payload?.debugBundlePath)
315
395
  };
316
396
  if (finalSummary) {
397
+ if (args.compact === true) {
398
+ return {
399
+ ...compactChatPayload({
400
+ success: true,
401
+ status: "idle",
402
+ providerSessionId,
403
+ summary: finalSummary,
404
+ messages: [{ role: "assistant", content: finalSummary, isHistorical: true }]
405
+ }, {
406
+ nodeId: args.node_id,
407
+ sessionId: args.session_id,
408
+ limit: args.tail ?? 10
409
+ }),
410
+ recoveredFromLedger: true,
411
+ ledger
412
+ };
413
+ }
317
414
  return {
318
415
  success: true,
319
- compact: args.compact === true,
416
+ compact: false,
320
417
  recoveredFromLedger: true,
321
418
  nodeId: args.node_id,
322
419
  sessionId: args.session_id,
@@ -368,6 +465,33 @@ function buildMissingNodeReadChatRecovery(ctx, args) {
368
465
  function readSessionRecordId(session) {
369
466
  return readString(session?.id) || readString(session?.sessionId) || readString(session?.session_id) || readString(session?.runtimeSessionId) || readString(session?.runtime_session_id) || readString(session?.instanceId) || readString(session?.instance_id);
370
467
  }
468
+ function extractStatusMetadataSessions(value) {
469
+ const payload = unwrapCommandPayload(value);
470
+ const status = payload?.status && typeof payload.status === "object" ? payload.status : payload;
471
+ return Array.isArray(status?.sessions) ? status.sessions : [];
472
+ }
473
+ function resolveSessionProviderType(session) {
474
+ return readString(session?.providerType) || readString(session?.cliType) || readString(session?.agentType) || "";
475
+ }
476
+ function isMeshCoordinatorSessionRecord(session) {
477
+ return Boolean(
478
+ readString(session?.settings?.meshCoordinatorFor) || readString(session?.meta?.meshCoordinatorFor) || readString(session?.metadata?.meshCoordinatorFor) || readString(session?.meshCoordinatorFor)
479
+ );
480
+ }
481
+ function isUnmanagedSessionRecord(session) {
482
+ const hasMeshNodeFor = Boolean(
483
+ readString(session?.settings?.meshNodeFor) || readString(session?.meta?.meshNodeFor) || readString(session?.metadata?.meshNodeFor) || readString(session?.meshNodeFor)
484
+ );
485
+ if (hasMeshNodeFor) return false;
486
+ if (isMeshCoordinatorSessionRecord(session)) return false;
487
+ const launchedByCoordinator = Boolean(
488
+ session?.settings?.launchedByCoordinator === true || session?.meta?.launchedByCoordinator === true || session?.launchedByCoordinator === true
489
+ );
490
+ return !launchedByCoordinator;
491
+ }
492
+ function isWorkerTaskMode(taskMode) {
493
+ return taskMode !== "live_debug_readonly";
494
+ }
371
495
  function addSessionRecord(target, session) {
372
496
  if (!session || typeof session !== "object" || isTerminalSessionRecord(session)) return;
373
497
  const sessionId = readSessionRecordId(session);
@@ -436,18 +560,26 @@ function queueAssignmentStaleReason(task, liveness) {
436
560
  }
437
561
  function buildQueueStatusSummary(queue) {
438
562
  const counts = { pending: 0, assigned: 0, completed: 0, failed: 0, cancelled: 0 };
563
+ let staleAssigned = 0;
439
564
  for (const task of queue) {
440
565
  const status = typeof task?.status === "string" ? task.status : void 0;
441
566
  if (status && Object.prototype.hasOwnProperty.call(counts, status)) {
442
567
  counts[status] += 1;
443
568
  }
569
+ if (status === "assigned" && task?.staleAssigned === true) staleAssigned += 1;
444
570
  }
571
+ const liveAssigned = Math.max(0, counts.assigned - staleAssigned);
445
572
  return {
446
573
  totalCount: queue.length,
447
- activeCount: counts.pending + counts.assigned,
574
+ activeCount: counts.pending + liveAssigned,
448
575
  historicalCount: counts.completed + counts.failed + counts.cancelled,
449
576
  counts,
450
577
  activeCounts: {
578
+ pending: counts.pending,
579
+ assigned: liveAssigned
580
+ },
581
+ staleAssignedCount: staleAssigned,
582
+ rawActiveCounts: {
451
583
  pending: counts.pending,
452
584
  assigned: counts.assigned
453
585
  },
@@ -475,6 +607,18 @@ function filterQueueForView(queue, view, statuses) {
475
607
  if (view === "historical") return queue.filter((task) => HISTORICAL_QUEUE_STATUSES.has(String(task?.status || "")));
476
608
  return queue;
477
609
  }
610
+ function prioritizeActiveQueueRows(queue) {
611
+ const active = [];
612
+ const historical = [];
613
+ const other = [];
614
+ for (const task of queue) {
615
+ const status = String(task?.status || "");
616
+ if (ACTIVE_QUEUE_STATUSES.has(status)) active.push(task);
617
+ else if (HISTORICAL_QUEUE_STATUSES.has(status)) historical.push(task);
618
+ else other.push(task);
619
+ }
620
+ return [...active, ...other, ...historical];
621
+ }
478
622
  function slimQueueTask(task) {
479
623
  return {
480
624
  id: task?.id,
@@ -580,22 +724,60 @@ function isIdleSessionRecord(session) {
580
724
  const chatStatus = typeof session?.activeChat?.status === "string" ? session.activeChat.status.toLowerCase() : "";
581
725
  return status === "idle" || chatStatus === "waiting_input";
582
726
  }
727
+ function isMeshOwnedDelegateSession(session, meshId, nodeId) {
728
+ const settings = session?.settings;
729
+ const sessionMeshId = typeof settings?.meshNodeFor === "string" ? settings.meshNodeFor.trim() : "";
730
+ const coordinatorDaemonId = typeof settings?.meshCoordinatorDaemonId === "string" ? settings.meshCoordinatorDaemonId.trim() : "";
731
+ const sessionNodeId = typeof settings?.meshNodeId === "string" ? settings.meshNodeId.trim() : "";
732
+ if (sessionMeshId !== meshId || !coordinatorDaemonId) return false;
733
+ return !sessionNodeId || sessionNodeId === nodeId;
734
+ }
583
735
  function chooseDispatchableSession(sessions, providerType, meshId, nodeId) {
584
736
  const live = sessions.filter((session) => !isTerminalSessionRecord(session));
585
737
  const matchingProvider = (session) => !providerType || session?.providerType === providerType || session?.cliType === providerType;
586
- const isMeshOwnedDelegateSession = (session) => {
587
- const settings = session?.settings;
588
- const sessionMeshId = typeof settings?.meshNodeFor === "string" ? settings.meshNodeFor.trim() : "";
589
- const coordinatorDaemonId = typeof settings?.meshCoordinatorDaemonId === "string" ? settings.meshCoordinatorDaemonId.trim() : "";
590
- const sessionNodeId = typeof settings?.meshNodeId === "string" ? settings.meshNodeId.trim() : "";
591
- if (sessionMeshId !== meshId || !coordinatorDaemonId) return false;
592
- return !sessionNodeId || sessionNodeId === nodeId;
593
- };
594
738
  const meshSessions = live.filter(
595
- (session) => isMeshOwnedDelegateSession(session)
739
+ (session) => isMeshOwnedDelegateSession(session, meshId, nodeId)
596
740
  );
597
741
  return meshSessions.find((session) => isIdleSessionRecord(session) && matchingProvider(session)) || meshSessions.find(matchingProvider) || void 0;
598
742
  }
743
+ function buildRelayUnsafeRemoteSessionFailure(ctx, node, sessionId, providerType) {
744
+ return {
745
+ success: false,
746
+ recoverable: true,
747
+ code: "mesh_delegate_session_missing_relay_metadata",
748
+ reason: "mesh_delegate_session_missing_relay_metadata",
749
+ transport: "mesh_transport",
750
+ retryRecommended: true,
751
+ meshId: ctx.mesh.id,
752
+ nodeId: node.id,
753
+ daemonId: node.daemonId,
754
+ workspace: node.workspace,
755
+ sessionId,
756
+ unsafeTranscriptAlias: true,
757
+ ...providerType ? { resolvedProviderType: providerType } : {},
758
+ error: `Remote session '${sessionId}' is not relay-safe for mesh '${ctx.mesh.id}': missing meshNodeFor/meshCoordinatorDaemonId metadata, so completion events would not reach the coordinator ledger. This session may be the coordinator itself or an unrelated session (unsafe_transcript_alias risk).`,
759
+ nextAction: `Launch a fresh relay-safe session with mesh_launch_session(node_id: '${node.id}'${providerType ? `, type: '${providerType}'` : ""}) or dispatch without session_id so Repo Mesh can choose a valid delegate session.`,
760
+ noFallbackReason: "Blindly reusing a remote session without mesh relay metadata would silently drop task_completed / generating_completed events."
761
+ };
762
+ }
763
+ function buildMissingCoordinatorDaemonIdFailure(ctx, node, providerType) {
764
+ return {
765
+ success: false,
766
+ recoverable: true,
767
+ code: "mesh_coordinator_daemon_unknown",
768
+ reason: "mesh_coordinator_daemon_unknown",
769
+ transport: "mesh_transport",
770
+ retryRecommended: true,
771
+ meshId: ctx.mesh.id,
772
+ nodeId: node.id,
773
+ daemonId: node.daemonId,
774
+ workspace: node.workspace,
775
+ ...providerType ? { resolvedProviderType: providerType } : {},
776
+ error: `Cannot launch a remote mesh delegate for node '${node.id}': coordinator daemon identity is unavailable, so the worker would be unable to relay completion events back to the coordinator.`,
777
+ nextAction: "Retry after the coordinator daemon identity is available (for example from an attached daemon-backed MCP session) so meshCoordinatorDaemonId can be stamped on the worker session.",
778
+ noFallbackReason: "Launching without meshCoordinatorDaemonId would create a worker session that can finish work but cannot emit task_completed / generating_completed back to the coordinator."
779
+ };
780
+ }
599
781
  function findNestedPayload(value, predicate) {
600
782
  const seen = /* @__PURE__ */ new Set();
601
783
  const stack = [{ payload: value, depth: 0 }];
@@ -623,12 +805,16 @@ function extractGitDiff(value) {
623
805
  }
624
806
  function extractSubmodules(value, ignorePaths) {
625
807
  const payload = unwrapCommandPayload(value);
626
- const subs = payload?.submodules ?? value?.submodules;
808
+ const subs = payload?.status?.submodules ?? payload?.submodules ?? value?.status?.submodules ?? value?.submodules;
627
809
  if (!Array.isArray(subs)) return void 0;
628
810
  if (ignorePaths.length === 0) return subs;
629
811
  const ignoreSet = new Set(ignorePaths);
630
812
  return subs.filter((s) => s?.path && !ignoreSet.has(s.path));
631
813
  }
814
+ function assignFullGitSnapshot(entry, status) {
815
+ if (!status || typeof status !== "object" || Array.isArray(status)) return;
816
+ entry.git = status;
817
+ }
632
818
  function extractLaunchPayload(value) {
633
819
  return findNestedPayload(value, (payload) => Boolean(payload?.sessionId || payload?.id || payload?.runtimeSessionId));
634
820
  }
@@ -753,20 +939,76 @@ async function ipcDispatchToRemoteAgent(ctx, node, args) {
753
939
  let sessionId = args.session_id?.trim() || "";
754
940
  const providerPriorityList = Array.isArray(node.policy?.providerPriority) ? node.policy.providerPriority : [];
755
941
  let resolvedProviderType = args.providerType?.trim() || providerPriorityList[0] || "";
756
- if (!sessionId) {
942
+ if (sessionId && args.verifiedSession) {
943
+ const explicitSession = args.verifiedSession;
944
+ if (!isMeshOwnedDelegateSession(explicitSession, ctx.mesh.id, node.id)) {
945
+ return buildRelayUnsafeRemoteSessionFailure(
946
+ ctx,
947
+ node,
948
+ sessionId,
949
+ resolvedProviderType || resolveSessionProviderType(explicitSession) || void 0
950
+ );
951
+ }
952
+ if (!resolvedProviderType) {
953
+ resolvedProviderType = resolveSessionProviderType(explicitSession);
954
+ }
955
+ } else if (!sessionId || args.session_id) {
757
956
  try {
758
957
  const relayResult = await transport.meshCommand(daemonId, "get_status_metadata", {});
759
- const innerResult = relayResult?.result ?? relayResult;
760
- const statusObj = innerResult?.status ?? innerResult;
761
- const sessions = Array.isArray(statusObj?.sessions) ? statusObj.sessions : [];
762
- const targetSession = chooseDispatchableSession(sessions, resolvedProviderType, ctx.mesh.id, node.id);
763
- if (targetSession?.id || targetSession?.sessionId) {
764
- sessionId = targetSession.id || targetSession.sessionId;
958
+ const sessions = extractStatusMetadataSessions(relayResult);
959
+ if (sessionId) {
960
+ const explicitSession = sessions.find((session) => readSessionRecordId(session) === sessionId);
961
+ if (!explicitSession) {
962
+ return {
963
+ success: false,
964
+ recoverable: true,
965
+ code: "mesh_target_session_not_found",
966
+ reason: "mesh_target_session_not_found",
967
+ transport: "mesh_transport",
968
+ retryRecommended: true,
969
+ meshId: ctx.mesh.id,
970
+ nodeId: node.id,
971
+ daemonId,
972
+ workspace: node.workspace,
973
+ sessionId,
974
+ ...resolvedProviderType ? { resolvedProviderType } : {},
975
+ error: `Remote session '${sessionId}' is not present in the live status for node '${node.id}'.`,
976
+ nextAction: `Launch a fresh session with mesh_launch_session(node_id: '${node.id}'${resolvedProviderType ? `, type: '${resolvedProviderType}'` : ""}) or retry without session_id so Repo Mesh can target a live delegate session.`
977
+ };
978
+ }
979
+ if (!isMeshOwnedDelegateSession(explicitSession, ctx.mesh.id, node.id)) {
980
+ return buildRelayUnsafeRemoteSessionFailure(
981
+ ctx,
982
+ node,
983
+ sessionId,
984
+ resolvedProviderType || resolveSessionProviderType(explicitSession) || void 0
985
+ );
986
+ }
765
987
  if (!resolvedProviderType) {
766
- resolvedProviderType = targetSession.providerType || targetSession.cliType || "";
988
+ resolvedProviderType = resolveSessionProviderType(explicitSession);
989
+ }
990
+ } else {
991
+ const targetSession = chooseDispatchableSession(sessions, resolvedProviderType, ctx.mesh.id, node.id);
992
+ if (targetSession?.id || targetSession?.sessionId) {
993
+ sessionId = targetSession.id || targetSession.sessionId;
994
+ if (!resolvedProviderType) {
995
+ resolvedProviderType = resolveSessionProviderType(targetSession);
996
+ }
767
997
  }
768
998
  }
769
999
  } catch (e) {
1000
+ if (sessionId) {
1001
+ return {
1002
+ ...buildCoordinatorP2pRelayFailure(e, {
1003
+ command: "get_status_metadata",
1004
+ targetDaemonId: daemonId,
1005
+ nodeId: node.id,
1006
+ sessionId
1007
+ }),
1008
+ success: false,
1009
+ error: `Cannot verify remote session '${sessionId}' before dispatch: ${e?.message || String(e)}`
1010
+ };
1011
+ }
770
1012
  }
771
1013
  }
772
1014
  if (!resolvedProviderType) {
@@ -796,7 +1038,7 @@ async function ipcDispatchToRemoteAgent(ctx, node, args) {
796
1038
  error: `P2P dispatch failed: ${errorMessage}`
797
1039
  };
798
1040
  }
799
- return { success: true, dispatched: true, sessionId: sessionId || resolvedProviderType };
1041
+ return { success: true, dispatched: true, sessionId: sessionId || resolvedProviderType, providerType: resolvedProviderType };
800
1042
  } catch (e) {
801
1043
  const errorMessage = e?.message || String(e);
802
1044
  return {
@@ -826,34 +1068,198 @@ function resolveCoordinatorNode(ctx) {
826
1068
  return void 0;
827
1069
  }
828
1070
  function readNodeMachineId(node) {
829
- return readString(node.machineId) || readString(node.machine_id);
1071
+ return readString(node.machineId) || readString(node.machine_id) || readString(node.machine?.id) || readString(node.machine?.machineId) || readString(node.lastProbe?.machineId) || readString(node.last_probe?.machine_id) || readString(node.lastProbe?.machine?.id) || readString(node.lastProbe?.machine?.machineId) || readString(node.last_probe?.machine?.id) || readString(node.last_probe?.machine?.machine_id);
830
1072
  }
831
1073
  function readNodeDaemonId(node) {
832
- return readString(node.daemonId) || readString(node.daemon_id);
1074
+ return readString(node.daemonId) || readString(node.daemon_id) || readString(node.machine?.daemonId) || readString(node.machine?.daemon_id) || readString(node.lastProbe?.daemonId) || readString(node.last_probe?.daemon_id) || readString(node.lastProbe?.machine?.daemonId) || readString(node.lastProbe?.machine?.daemon_id) || readString(node.last_probe?.machine?.daemonId) || readString(node.last_probe?.machine?.daemon_id);
1075
+ }
1076
+ function normalizeHostname(value) {
1077
+ const hostname = readString(value);
1078
+ if (!hostname) return void 0;
1079
+ return hostname.toLowerCase().replace(/\.$/, "");
1080
+ }
1081
+ function readNodeHostname(node) {
1082
+ return readString(node.hostname) || readString(node.host) || readString(node.machineHostname) || readString(node.machine_hostname) || readString(node.machine?.hostname) || readString(node.machine?.host) || readString(node.lastProbe?.hostname) || readString(node.last_probe?.hostname) || readString(node.lastProbe?.machine?.hostname) || readString(node.last_probe?.machine?.hostname);
1083
+ }
1084
+ function readNodeDisplayMachineName(node) {
1085
+ return readString(node.machineName) || readString(node.machine_name) || readString(node.machineLabel) || readString(node.machine_label) || readString(node.machineNickname) || readString(node.machine_nickname) || readString(node.alias) || readString(node.machine?.name) || readString(node.machine?.displayName) || readString(node.machine?.display_name) || readString(node.lastProbe?.machineName) || readString(node.last_probe?.machine_name) || readString(node.lastProbe?.machine?.name) || readString(node.last_probe?.machine?.name) || readNodeHostname(node);
1086
+ }
1087
+ function compactIdentityEvidence(value) {
1088
+ if (!value) return void 0;
1089
+ return value.length > 24 ? `${value.slice(0, 12)}\u2026${value.slice(-8)}` : value;
1090
+ }
1091
+ function pushIdentityEvidence(evidence, label, value) {
1092
+ const compact = compactIdentityEvidence(value);
1093
+ if (compact) evidence.push(`${label}:${compact}`);
1094
+ }
1095
+ function buildNodeMachineIdentity(ctx, node) {
1096
+ const machineId = readNodeMachineId(node);
1097
+ const daemonId = readNodeDaemonId(node);
1098
+ const hostname = readNodeHostname(node);
1099
+ const machineName = readNodeDisplayMachineName(node);
1100
+ const coordinatorHostname = readString(ctx.coordinatorHostname);
1101
+ const localControlPlaneReason = getLocalControlPlaneMatchReason(ctx, node);
1102
+ const directLocal = !!localControlPlaneReason;
1103
+ const hostnameMatches = Boolean(
1104
+ normalizeHostname(hostname) && normalizeHostname(coordinatorHostname) && normalizeHostname(hostname) === normalizeHostname(coordinatorHostname)
1105
+ );
1106
+ const sameMachine = directLocal || hostnameMatches;
1107
+ const evidence = [];
1108
+ pushIdentityEvidence(evidence, "machineName", machineName);
1109
+ pushIdentityEvidence(evidence, "hostname", hostname);
1110
+ pushIdentityEvidence(evidence, "machineId", machineId);
1111
+ pushIdentityEvidence(evidence, "daemonId", daemonId);
1112
+ if (localControlPlaneReason) {
1113
+ pushIdentityEvidence(evidence, "localMatch", localControlPlaneReason);
1114
+ pushIdentityEvidence(evidence, "localMachineId", ctx.localMachineId);
1115
+ pushIdentityEvidence(evidence, "localDaemonId", ctx.localDaemonId);
1116
+ }
1117
+ const locality = sameMachine ? "same_machine" : evidence.length > 0 ? "remote_known" : "remote_or_unknown";
1118
+ const localityReason = sameMachine ? localControlPlaneReason || "matched coordinator hostname" : evidence.length > 0 ? `known remote/other machine identity; no local coordinator match (${evidence.join(", ")})` : "no useful machine identity evidence available";
1119
+ return {
1120
+ daemonId,
1121
+ machineId,
1122
+ hostname,
1123
+ machineName,
1124
+ displayName: machineName || hostname || daemonId || machineId,
1125
+ coordinatorHostname,
1126
+ sameMachine,
1127
+ locality,
1128
+ localityReason,
1129
+ identityEvidence: evidence
1130
+ };
1131
+ }
1132
+ function nodeHasLocalDaemonEvidence(ctx, node) {
1133
+ const isLocal = (session) => {
1134
+ if (!session || typeof session !== "object") return false;
1135
+ if (ctx.localDaemonId && session.settings?.meshCoordinatorDaemonId === ctx.localDaemonId) return true;
1136
+ if (session.launchedByCoordinator === true) return true;
1137
+ if (ctx.localDaemonId && session.runtime?.owner === ctx.localDaemonId) return true;
1138
+ if (ctx.localDaemonId && session.daemonClient?.daemonId === ctx.localDaemonId) return true;
1139
+ return false;
1140
+ };
1141
+ const sessionArrays = [
1142
+ node?.sessions,
1143
+ node?.activeSessions,
1144
+ node?.active_sessions,
1145
+ node?.lastProbe?.sessions,
1146
+ node?.last_probe?.sessions,
1147
+ node?.lastProbe?.status?.sessions,
1148
+ node?.last_probe?.status?.sessions
1149
+ ];
1150
+ for (const arr of sessionArrays) {
1151
+ if (Array.isArray(arr) && arr.some(isLocal)) return true;
1152
+ }
1153
+ const sessionRecords = [
1154
+ node?.activeSession,
1155
+ node?.active_session,
1156
+ node?.currentSession,
1157
+ node?.current_session,
1158
+ node?.runtimeSession,
1159
+ node?.runtime_session,
1160
+ node?.session,
1161
+ node?.lastProbe?.activeSession,
1162
+ node?.last_probe?.active_session,
1163
+ node?.lastProbe?.currentSession,
1164
+ node?.last_probe?.current_session,
1165
+ node?.lastProbe?.session,
1166
+ node?.last_probe?.session
1167
+ ];
1168
+ for (const session of sessionRecords) {
1169
+ if (isLocal(session)) return true;
1170
+ }
1171
+ return false;
833
1172
  }
834
1173
  function isDirectLocalNode(ctx, node) {
835
1174
  const machineId = readNodeMachineId(node);
836
1175
  const daemonId = readNodeDaemonId(node);
837
1176
  return Boolean(
838
- ctx.localMachineId && machineId === ctx.localMachineId || ctx.localDaemonId && daemonId === ctx.localDaemonId
1177
+ ctx.localMachineId && machineId === ctx.localMachineId || ctx.localDaemonId && daemonId === ctx.localDaemonId || nodeHasLocalDaemonEvidence(ctx, node)
839
1178
  );
840
1179
  }
1180
+ function isConfiguredCoordinatorNode(ctx, node) {
1181
+ if (!ctx.localMachineId && !ctx.localDaemonId) return false;
1182
+ const nodeId = readString(node.id) || readString(node.nodeId) || readString(node.node_id);
1183
+ if (!nodeId) return false;
1184
+ const nodeDaemonId = readNodeDaemonId(node);
1185
+ const nodeMachineId = readNodeMachineId(node);
1186
+ if (nodeDaemonId && ctx.localDaemonId && nodeDaemonId !== ctx.localDaemonId) return false;
1187
+ if (nodeMachineId && ctx.localMachineId && nodeMachineId !== ctx.localMachineId) return false;
1188
+ const preferredNodeId = readString(ctx.mesh.coordinator?.preferredNodeId) || readString(ctx.mesh.coordinator?.preferred_node_id);
1189
+ if (preferredNodeId) return nodeId === preferredNodeId;
1190
+ const first = ctx.mesh.nodes?.[0];
1191
+ const firstNodeId = readString(first?.id) || readString(first?.nodeId) || readString(first?.node_id);
1192
+ return !!firstNodeId && nodeId === firstNodeId;
1193
+ }
1194
+ function getLocalControlPlaneMatchReason(ctx, node) {
1195
+ if (isDirectLocalNode(ctx, node)) return "matched coordinator daemon or machine id";
1196
+ if (isConfiguredCoordinatorNode(ctx, node)) return "matched configured coordinator node";
1197
+ if (node.isLocalWorktree === true) {
1198
+ const sourceNode = findClonedFromNode(ctx, node);
1199
+ if (sourceNode && isDirectLocalNode(ctx, sourceNode)) return "matched local cloned-from node";
1200
+ if (sourceNode && isConfiguredCoordinatorNode(ctx, sourceNode)) return "matched configured coordinator source node";
1201
+ }
1202
+ return void 0;
1203
+ }
841
1204
  function findClonedFromNode(ctx, node) {
842
1205
  const clonedFromNodeId = readString(node.clonedFromNodeId) || readString(node.cloned_from_node_id);
843
1206
  if (!clonedFromNodeId) return void 0;
844
1207
  return ctx.mesh.nodes.find((n) => n.id === clonedFromNodeId || n.nodeId === clonedFromNodeId || n.node_id === clonedFromNodeId);
845
1208
  }
846
1209
  function isLocalControlPlaneNode(ctx, node) {
847
- if (isDirectLocalNode(ctx, node)) return true;
848
- if (node.isLocalWorktree === true) {
849
- const sourceNode = findClonedFromNode(ctx, node);
850
- if (sourceNode && isDirectLocalNode(ctx, sourceNode)) return true;
851
- }
852
- return false;
1210
+ return !!getLocalControlPlaneMatchReason(ctx, node);
853
1211
  }
854
1212
  function meshSessionCacheKey(nodeId, runtimeSessionId) {
855
1213
  return `${nodeId}:${runtimeSessionId}`;
856
1214
  }
1215
+ function rememberMeshSessionProviderMetadata(nodeId, runtimeSessionId, metadata) {
1216
+ const keyNodeId = readString(nodeId);
1217
+ const keySessionId = readString(runtimeSessionId);
1218
+ if (!keyNodeId || !keySessionId) return;
1219
+ const providerType = readString(metadata.providerType);
1220
+ const providerSessionId = readString(metadata.providerSessionId);
1221
+ if (!providerType && !providerSessionId) return;
1222
+ const existing = meshSessionProviderMetadata.get(meshSessionCacheKey(keyNodeId, keySessionId)) || { providerType: "" };
1223
+ meshSessionProviderMetadata.set(meshSessionCacheKey(keyNodeId, keySessionId), {
1224
+ providerType: providerType || existing.providerType,
1225
+ providerSessionId: providerSessionId || existing.providerSessionId
1226
+ });
1227
+ }
1228
+ function rememberMeshSessionProviderMetadataFromEvent(event) {
1229
+ const metadataEvent = event?.metadataEvent && typeof event.metadataEvent === "object" ? event.metadataEvent : event && typeof event === "object" ? event : {};
1230
+ const nodeId = readString(event?.nodeId) || readString(metadataEvent.nodeId) || readString(metadataEvent.meshNodeId);
1231
+ const sessionId = readString(metadataEvent.targetSessionId) || readString(metadataEvent.sessionId) || readString(metadataEvent.instanceId) || readString(event?.sessionId);
1232
+ rememberMeshSessionProviderMetadata(nodeId, sessionId, {
1233
+ providerType: readString(metadataEvent.providerType) || readString(event?.providerType) || "",
1234
+ providerSessionId: readString(metadataEvent.providerSessionId) || readString(event?.providerSessionId)
1235
+ });
1236
+ }
1237
+ function resolveMeshSessionProviderMetadataFromLedger(ctx, nodeId, runtimeSessionId) {
1238
+ const entries = (0, import_daemon_core.readLedgerEntries)(ctx.mesh.id, { tail: 500 });
1239
+ for (let i = entries.length - 1; i >= 0; i -= 1) {
1240
+ const entry = entries[i];
1241
+ const payload = entry.payload && typeof entry.payload === "object" && !Array.isArray(entry.payload) ? entry.payload : {};
1242
+ const entryNodeId = readString(entry.nodeId) || readString(payload.nodeId) || readString(payload.meshNodeId);
1243
+ if (entryNodeId && entryNodeId !== nodeId) continue;
1244
+ const entrySessionId = readString(entry.sessionId) || readString(payload.targetSessionId) || readString(payload.sessionId) || readString(payload.instanceId);
1245
+ if (entrySessionId !== runtimeSessionId) continue;
1246
+ const providerType = readString(entry.providerType) || readString(payload.providerType);
1247
+ const completionDiagnostic = payload.completionDiagnostic && typeof payload.completionDiagnostic === "object" && !Array.isArray(payload.completionDiagnostic) ? payload.completionDiagnostic : {};
1248
+ const metadataEvent = payload.metadataEvent && typeof payload.metadataEvent === "object" && !Array.isArray(payload.metadataEvent) ? payload.metadataEvent : {};
1249
+ const providerSessionId = readString(payload.providerSessionId) || readString(completionDiagnostic.providerSessionId) || readString(metadataEvent.providerSessionId);
1250
+ if (providerType || providerSessionId) {
1251
+ return { providerType: providerType || "", providerSessionId };
1252
+ }
1253
+ }
1254
+ return void 0;
1255
+ }
1256
+ function resolveMeshSessionProviderMetadata(ctx, nodeId, runtimeSessionId) {
1257
+ const cached = meshSessionProviderMetadata.get(meshSessionCacheKey(nodeId, runtimeSessionId));
1258
+ if (cached?.providerType || cached?.providerSessionId) return cached;
1259
+ const fromLedger = resolveMeshSessionProviderMetadataFromLedger(ctx, nodeId, runtimeSessionId);
1260
+ if (fromLedger) rememberMeshSessionProviderMetadata(nodeId, runtimeSessionId, fromLedger);
1261
+ return fromLedger;
1262
+ }
857
1263
  function countUncommittedChanges(status) {
858
1264
  if (typeof status?.uncommittedChanges === "number") return status.uncommittedChanges;
859
1265
  const keys = ["staged", "modified", "untracked", "deleted", "renamed"];
@@ -924,6 +1330,16 @@ function missingProviderPriorityMessage(nodeId) {
924
1330
  return `Node '${nodeId}' has no providerPriority policy; pass type explicitly or configure node.policy.providerPriority`;
925
1331
  }
926
1332
  function getNodeLaunchReadiness(node) {
1333
+ const bootstrap = node.worktreeBootstrap;
1334
+ if (node.isLocalWorktree && bootstrap?.status === "failed" && bootstrap?.required !== false) {
1335
+ return {
1336
+ providerPriority: readProviderPriority(node.policy),
1337
+ launchReady: false,
1338
+ launchBlockedReason: "worktree_bootstrap_failed",
1339
+ launchBlockedMessage: typeof bootstrap.error === "string" && bootstrap.error.trim() ? bootstrap.error.trim() : "Required worktree bootstrap failed; resolve it before launching an agent into this node.",
1340
+ worktreeBootstrap: bootstrap
1341
+ };
1342
+ }
927
1343
  const providerPriority = readProviderPriority(node.policy);
928
1344
  if (providerPriority.length) {
929
1345
  return {
@@ -938,6 +1354,33 @@ function getNodeLaunchReadiness(node) {
938
1354
  launchBlockedMessage: missingProviderPriorityMessage(node.id)
939
1355
  };
940
1356
  }
1357
+ function getWorktreeBootstrapLaunchBlock(node) {
1358
+ const bootstrap = node.worktreeBootstrap;
1359
+ if (!node.isLocalWorktree || bootstrap?.status !== "failed" || bootstrap?.required === false) return void 0;
1360
+ return {
1361
+ success: false,
1362
+ code: "worktree_bootstrap_failed",
1363
+ error: typeof bootstrap.error === "string" && bootstrap.error.trim() ? bootstrap.error.trim() : `Node '${node.id}' has a failed required worktree bootstrap.`,
1364
+ nodeId: node.id,
1365
+ worktreeBootstrap: bootstrap,
1366
+ recoveryHint: "Fix the configured worktree bootstrap command or remove/recreate the worktree node before launching an agent."
1367
+ };
1368
+ }
1369
+ async function collectLiveStatusSessions(ctx, node) {
1370
+ try {
1371
+ const statusResult = await commandForNode(ctx, node, "get_status_metadata", {});
1372
+ return extractStatusMetadataSessions(statusResult);
1373
+ } catch {
1374
+ return [];
1375
+ }
1376
+ }
1377
+ async function collectMeshViewQueueNodesWithLiveSessions(ctx) {
1378
+ const nodes = await Promise.all(ctx.mesh.nodes.map(async (node) => {
1379
+ const liveSessions = await collectLiveStatusSessions(ctx, node);
1380
+ return liveSessions.length > 0 ? { ...node, sessions: liveSessions } : node;
1381
+ }));
1382
+ return nodes;
1383
+ }
941
1384
  function readNumeric(value, fallback = 0) {
942
1385
  const parsed = Number(value);
943
1386
  return Number.isFinite(parsed) ? parsed : fallback;
@@ -1073,7 +1516,8 @@ async function commandForNode(ctx, node, command, args = {}) {
1073
1516
  if (isLocalTransport(ctx.transport)) {
1074
1517
  return ctx.transport.command(command, args);
1075
1518
  }
1076
- throw new Error(`Command '${command}' requires daemon IPC/local transport for node '${node.id}'`);
1519
+ const identity = buildNodeMachineIdentity(ctx, node);
1520
+ throw new Error(`Command '${command}' requires daemon IPC/local transport for node '${node.id}' (hostname=${identity.hostname || "unknown"}, coordinatorHostname=${identity.coordinatorHostname || "unknown"}, sameMachine=${identity.sameMachine})`);
1077
1521
  }
1078
1522
  function normalizePendingMeshCoordinatorEvents(value) {
1079
1523
  const payload = unwrapCommandPayload(value);
@@ -1091,6 +1535,14 @@ function buildMeshForwardPayloadFromPendingEvent(event) {
1091
1535
  providerType: readString(metadataEvent.providerType),
1092
1536
  providerSessionId: readString(metadataEvent.providerSessionId),
1093
1537
  finalSummary: readString(metadataEvent.finalSummary) || readString(metadataEvent.summary),
1538
+ jobId: readString(metadataEvent.jobId),
1539
+ interactionId: readString(metadataEvent.interactionId),
1540
+ status: readString(metadataEvent.status),
1541
+ targetDaemonId: readString(metadataEvent.targetDaemonId),
1542
+ startedAt: readString(metadataEvent.startedAt),
1543
+ completedAt: readString(metadataEvent.completedAt),
1544
+ retryOfJobId: readString(metadataEvent.retryOfJobId),
1545
+ ...metadataEvent.result && typeof metadataEvent.result === "object" && !Array.isArray(metadataEvent.result) ? { result: metadataEvent.result } : {},
1094
1546
  ...metadataEvent.intentional === true ? { intentional: true } : {},
1095
1547
  ...metadataEvent.intentionalStop === true ? { intentionalStop: true } : {},
1096
1548
  ...metadataEvent.operatorCleanup === true ? { operatorCleanup: true } : {},
@@ -1107,8 +1559,9 @@ async function drainCoordinatorPendingEvents(ctx, opts) {
1107
1559
  const surfacedEvents = [];
1108
1560
  try {
1109
1561
  surfacedEvents.push(
1110
- ...normalizePendingMeshCoordinatorEvents(await ctx.transport.command("get_pending_mesh_events", {})).filter(matchesCurrentMesh)
1562
+ ...normalizePendingMeshCoordinatorEvents(await ctx.transport.command("get_pending_mesh_events", { meshId: ctx.mesh.id })).filter(matchesCurrentMesh)
1111
1563
  );
1564
+ surfacedEvents.forEach(rememberMeshSessionProviderMetadataFromEvent);
1112
1565
  } catch {
1113
1566
  }
1114
1567
  for (const node of ctx.mesh.nodes) {
@@ -1116,27 +1569,31 @@ async function drainCoordinatorPendingEvents(ctx, opts) {
1116
1569
  if (requestedNodeIds && !requestedNodeIds.has(node.id)) continue;
1117
1570
  try {
1118
1571
  const remoteEvents = normalizePendingMeshCoordinatorEvents(
1119
- await ctx.transport.meshCommand(node.daemonId, "get_pending_mesh_events", {})
1572
+ await ctx.transport.meshCommand(node.daemonId, "get_pending_mesh_events", { meshId: ctx.mesh.id })
1120
1573
  ).filter(matchesCurrentMesh);
1121
1574
  if (remoteEvents.length === 0) continue;
1122
1575
  for (const event of remoteEvents) {
1123
1576
  const payload = buildMeshForwardPayloadFromPendingEvent(event);
1124
1577
  if (!payload.event || !payload.meshId) continue;
1125
1578
  await ctx.transport.command("mesh_forward_event", payload);
1579
+ rememberMeshSessionProviderMetadataFromEvent({ ...event, metadataEvent: payload });
1126
1580
  }
1127
1581
  } catch {
1128
1582
  }
1129
1583
  }
1130
1584
  try {
1131
1585
  surfacedEvents.push(
1132
- ...normalizePendingMeshCoordinatorEvents(await ctx.transport.command("get_pending_mesh_events", {})).filter(matchesCurrentMesh)
1586
+ ...normalizePendingMeshCoordinatorEvents(await ctx.transport.command("get_pending_mesh_events", { meshId: ctx.mesh.id })).filter(matchesCurrentMesh)
1133
1587
  );
1588
+ surfacedEvents.forEach(rememberMeshSessionProviderMetadataFromEvent);
1134
1589
  } catch {
1135
1590
  }
1136
1591
  return surfacedEvents;
1137
1592
  }
1138
1593
  if (isLocalTransport(ctx.transport)) {
1139
- return (0, import_daemon_core.drainPendingMeshCoordinatorEvents)().filter(matchesCurrentMesh);
1594
+ const events = (0, import_daemon_core.drainPendingMeshCoordinatorEvents)(ctx.mesh.id).filter(matchesCurrentMesh);
1595
+ events.forEach(rememberMeshSessionProviderMetadataFromEvent);
1596
+ return events;
1140
1597
  }
1141
1598
  return [];
1142
1599
  }
@@ -1153,11 +1610,12 @@ function buildRemoveNodeArgs(ctx, nodeId, sessionCleanupMode) {
1153
1610
  }
1154
1611
  var MESH_STATUS_TOOL = {
1155
1612
  name: "mesh_status",
1156
- 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.",
1613
+ 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. Do not repeatedly call this to wait for generating delegated work; wait for pendingCoordinatorEvents/completion events or an explicit user status request.",
1157
1614
  inputSchema: {
1158
1615
  type: "object",
1159
1616
  properties: {
1160
- _gemini_compat: { type: "string", description: "Dummy property for Gemini compatibility. Ignore this." }
1617
+ _gemini_compat: { type: "string", description: "Dummy property for Gemini compatibility. Ignore this." },
1618
+ includeStaleDirectWorkDetails: { type: "boolean", description: "Opt in to the full staleDirectWork array. Defaults false; normal status returns compact staleDirectWorkSummary only." }
1161
1619
  }
1162
1620
  }
1163
1621
  };
@@ -1177,14 +1635,16 @@ var MESH_ENQUEUE_TASK_TOOL = {
1177
1635
  inputSchema: {
1178
1636
  type: "object",
1179
1637
  properties: {
1180
- message: { type: "string", description: "The task instruction for the agent." }
1638
+ message: { type: "string", description: "The task instruction for the agent." },
1639
+ task_mode: { type: "string", enum: ["code_change", "validation", "live_debug_readonly", "launch_app", "convergence"], description: "Optional task-mode contract. live_debug_readonly rejects obvious write/commit/push/deploy/destructive instructions before dispatch." },
1640
+ taskMode: { type: "string", enum: ["code_change", "validation", "live_debug_readonly", "launch_app", "convergence"], description: "CamelCase alias for task_mode." }
1181
1641
  },
1182
1642
  required: ["message"]
1183
1643
  }
1184
1644
  };
1185
1645
  var MESH_VIEW_QUEUE_TOOL = {
1186
1646
  name: "mesh_view_queue",
1187
- description: "View the mesh work queue with source-of-truth active counts separated from historical completed/failed/cancelled records.",
1647
+ description: "View the mesh work queue with source-of-truth active counts separated from historical completed/failed/cancelled records. Do not repeatedly call this to wait for generating assigned work; wait for pendingCoordinatorEvents/completion events or an explicit user status request.",
1188
1648
  inputSchema: {
1189
1649
  type: "object",
1190
1650
  properties: {
@@ -1237,7 +1697,9 @@ var MESH_SEND_TASK_TOOL = {
1237
1697
  properties: {
1238
1698
  node_id: { type: "string", description: "Target node ID (from mesh_list_nodes)." },
1239
1699
  session_id: { type: "string", description: "Agent session ID on the target node." },
1240
- message: { type: "string", description: "Natural-language task to send to the agent." }
1700
+ message: { type: "string", description: "Natural-language task to send to the agent." },
1701
+ task_mode: { type: "string", enum: ["code_change", "validation", "live_debug_readonly", "launch_app", "convergence"], description: "Optional task-mode contract. live_debug_readonly rejects obvious write/commit/push/deploy/destructive instructions before local or remote direct dispatch." },
1702
+ taskMode: { type: "string", enum: ["code_change", "validation", "live_debug_readonly", "launch_app", "convergence"], description: "CamelCase alias for task_mode." }
1241
1703
  },
1242
1704
  required: ["node_id", "session_id", "message"]
1243
1705
  }
@@ -1295,6 +1757,21 @@ var MESH_GIT_STATUS_TOOL = {
1295
1757
  required: ["node_id"]
1296
1758
  }
1297
1759
  };
1760
+ var MESH_FAST_FORWARD_NODE_TOOL = {
1761
+ name: "mesh_fast_forward_node",
1762
+ description: "Safely dry-run or execute an obvious direct fast-forward for a mesh node without launching an agent session. Defaults to dry-run; execution requires execute=true. Never pushes, rebases, resets, cleans, or checks out arbitrary revisions.",
1763
+ inputSchema: {
1764
+ type: "object",
1765
+ properties: {
1766
+ node_id: { type: "string", description: "Target node ID." },
1767
+ branch: { type: "string", description: "Optional guard: require the node's current branch to match this branch before planning/executing." },
1768
+ execute: { type: "boolean", description: "When true, apply the fast-forward if all safety gates pass. Defaults false/dry-run." },
1769
+ dry_run: { type: "boolean", description: "Preview only. Defaults true unless execute=true; dry_run=true overrides execute." },
1770
+ update_submodules: { type: "boolean", description: "When true, if the root fast-forward changes gitlinks, run only git submodule update --init --recursive and verify submodules clean." }
1771
+ },
1772
+ required: ["node_id"]
1773
+ }
1774
+ };
1298
1775
  var MESH_CHECKPOINT_TOOL = {
1299
1776
  name: "mesh_checkpoint",
1300
1777
  description: "Create a git checkpoint (commit) on a mesh node workspace.",
@@ -1378,7 +1855,7 @@ var MESH_TASK_HISTORY_TOOL = {
1378
1855
  type: "object",
1379
1856
  properties: {
1380
1857
  tail: { type: "number", description: "Number of recent entries to return (default: 20)." },
1381
- kind: { type: "string", description: "Filter by entry kind: task_dispatched, task_completed, task_failed, task_stalled, session_launched, checkpoint_created, node_cloned, node_removed." }
1858
+ kind: { type: "string", description: "Filter by entry kind: task_dispatched, task_completed, task_failed, task_stalled, session_launched, checkpoint_created, node_cloned, node_removed, direct_fast_forward." }
1382
1859
  }
1383
1860
  }
1384
1861
  };
@@ -1398,7 +1875,7 @@ var MESH_RECONCILE_LEDGER_TOOL = {
1398
1875
  };
1399
1876
  var MESH_REFINE_NODE_TOOL = {
1400
1877
  name: "mesh_refine_node",
1401
- description: "The Refinery: Automatically validate and merge a completed worktree node back into its base branch. This tool automates the validation gate and merge queue step. It will merge the node's branch into its base branch and cleanly remove the worktree node and its sessions.",
1878
+ description: "The Refinery: Accept an async validation/merge/cleanup job for a completed worktree node. The immediate response includes async:true, status:'accepted', jobId, interactionId, target node, and startedAt; completion/failure evidence is delivered through pending mesh events and the mesh task ledger.",
1402
1879
  inputSchema: {
1403
1880
  type: "object",
1404
1881
  properties: {
@@ -1407,6 +1884,43 @@ var MESH_REFINE_NODE_TOOL = {
1407
1884
  required: ["node_id"]
1408
1885
  }
1409
1886
  };
1887
+ var MESH_REFINE_CONFIG_SCHEMA_TOOL = {
1888
+ name: "mesh_refine_config_schema",
1889
+ description: "Return the Repo Mesh Refinery config JSON schema and supported repo-local config locations. This is the validation source of truth; heuristic command detection is suggestions-only.",
1890
+ inputSchema: { type: "object", properties: {} }
1891
+ };
1892
+ var MESH_VALIDATE_REFINE_CONFIG_TOOL = {
1893
+ name: "mesh_validate_refine_config",
1894
+ description: "Validate the repo mesh/refine config for a node/workspace without running validation commands or merging.",
1895
+ inputSchema: {
1896
+ type: "object",
1897
+ properties: {
1898
+ node_id: { type: "string", description: "Optional node/workspace whose refine config should be loaded. Defaults to the first mesh node." },
1899
+ config: { type: "object", description: "Optional inline config object to validate instead of loading from the repo." }
1900
+ }
1901
+ }
1902
+ };
1903
+ var MESH_SUGGEST_REFINE_CONFIG_TOOL = {
1904
+ name: "mesh_suggest_refine_config",
1905
+ description: "Suggest a repo mesh/refine config scaffold from project context/package scripts. Suggestions are never executed until saved as explicit refine config.",
1906
+ inputSchema: {
1907
+ type: "object",
1908
+ properties: {
1909
+ node_id: { type: "string", description: "Optional node/workspace used for suggestions. Defaults to the first mesh node." }
1910
+ }
1911
+ }
1912
+ };
1913
+ var MESH_REFINE_PLAN_TOOL = {
1914
+ name: "mesh_refine_plan",
1915
+ description: "Dry-run Refinery plan for a worktree node: reports config source, validation commands, suggestions/unavailable reason, and merge/cleanup intent without executing validation or git merge.",
1916
+ inputSchema: {
1917
+ type: "object",
1918
+ properties: {
1919
+ node_id: { type: "string", description: "Node ID of the worktree node to plan." }
1920
+ },
1921
+ required: ["node_id"]
1922
+ }
1923
+ };
1410
1924
  var ALL_MESH_TOOLS = [
1411
1925
  MESH_STATUS_TOOL,
1412
1926
  MESH_LIST_NODES_TOOL,
@@ -1419,16 +1933,21 @@ var ALL_MESH_TOOLS = [
1419
1933
  MESH_READ_DEBUG_TOOL,
1420
1934
  MESH_LAUNCH_SESSION_TOOL,
1421
1935
  MESH_GIT_STATUS_TOOL,
1936
+ MESH_FAST_FORWARD_NODE_TOOL,
1422
1937
  MESH_CHECKPOINT_TOOL,
1423
1938
  MESH_APPROVE_TOOL,
1424
1939
  MESH_CLONE_NODE_TOOL,
1425
1940
  MESH_REMOVE_NODE_TOOL,
1426
1941
  MESH_REFINE_NODE_TOOL,
1942
+ MESH_REFINE_CONFIG_SCHEMA_TOOL,
1943
+ MESH_VALIDATE_REFINE_CONFIG_TOOL,
1944
+ MESH_SUGGEST_REFINE_CONFIG_TOOL,
1945
+ MESH_REFINE_PLAN_TOOL,
1427
1946
  MESH_CLEANUP_SESSIONS_TOOL,
1428
1947
  MESH_TASK_HISTORY_TOOL,
1429
1948
  MESH_RECONCILE_LEDGER_TOOL
1430
1949
  ];
1431
- async function meshStatus(ctx) {
1950
+ async function meshStatus(ctx, args = {}) {
1432
1951
  await refreshMeshFromDaemon(ctx);
1433
1952
  const { mesh, transport } = ctx;
1434
1953
  const results = [];
@@ -1437,6 +1956,9 @@ async function meshStatus(ctx) {
1437
1956
  const entry = {
1438
1957
  nodeId: node.id,
1439
1958
  workspace: node.workspace,
1959
+ machine: buildNodeMachineIdentity(ctx, node),
1960
+ daemonId: readNodeDaemonId(node),
1961
+ machineId: readNodeMachineId(node),
1440
1962
  ...getNodeLaunchReadiness(node)
1441
1963
  };
1442
1964
  try {
@@ -1446,6 +1968,7 @@ async function meshStatus(ctx) {
1446
1968
  const uncommittedChanges = countUncommittedChanges(status);
1447
1969
  const dirty = isGitStatusDirty(status);
1448
1970
  entry.health = status?.isGitRepo ? dirty ? "dirty" : "online" : "degraded";
1971
+ assignFullGitSnapshot(entry, status);
1449
1972
  entry.branch = status?.branch;
1450
1973
  entry.isDirty = dirty;
1451
1974
  entry.uncommittedChanges = uncommittedChanges;
@@ -1467,6 +1990,7 @@ async function meshStatus(ctx) {
1467
1990
  const uncommittedChanges = countUncommittedChanges(status);
1468
1991
  const dirty = isGitStatusDirty(status);
1469
1992
  entry.health = status?.isGitRepo ? dirty ? "dirty" : "online" : "degraded";
1993
+ assignFullGitSnapshot(entry, status);
1470
1994
  entry.branch = status?.branch;
1471
1995
  entry.isDirty = dirty;
1472
1996
  entry.uncommittedChanges = uncommittedChanges;
@@ -1542,15 +2066,43 @@ async function meshStatus(ctx) {
1542
2066
  }
1543
2067
  const relatedRepos = await collectRelatedRepoStatuses(ctx, node);
1544
2068
  if (relatedRepos.length) entry.relatedRepos = relatedRepos;
2069
+ const liveSessions = await collectLiveStatusSessions(ctx, node);
2070
+ if (liveSessions.length > 0) {
2071
+ entry.sessions = liveSessions;
2072
+ }
1545
2073
  results.push(entry);
1546
2074
  }
2075
+ const ledgerEntries = (0, import_daemon_core.readLedgerEntries)(mesh.id, { tail: 500 });
2076
+ const activeWorkEvidence = (0, import_daemon_core.buildMeshActiveWork)({
2077
+ meshId: mesh.id,
2078
+ queue: (0, import_daemon_core.getQueue)(mesh.id),
2079
+ ledgerEntries,
2080
+ nodes: results
2081
+ });
2082
+ const pollingGuidance = buildActiveWorkPollingGuidance(activeWorkEvidence.summary);
2083
+ const staleDirectWorkSummary = (0, import_daemon_core.buildCompactStaleDirectWorkSummary)(activeWorkEvidence.staleDirectWork, {
2084
+ note: activeWorkEvidence.staleDirectWorkNote,
2085
+ detailHint: "Full stale direct entries are omitted from mesh_status by default. Call mesh_status with includeStaleDirectWorkDetails=true or inspect mesh_task_history for ledger detail."
2086
+ });
1547
2087
  const response = {
1548
2088
  meshId: mesh.id,
1549
2089
  meshName: mesh.name,
1550
2090
  repoIdentity: mesh.repoIdentity,
1551
2091
  policy: mesh.policy,
1552
2092
  refreshedAt: (/* @__PURE__ */ new Date()).toISOString(),
2093
+ sourceOfTruth: {
2094
+ membership: "coordinator_daemon_live_mesh",
2095
+ currentStatus: "live_git_and_session_probes",
2096
+ activeWork: "mesh_queue_file_and_local_ledger",
2097
+ historicalEvidenceOnly: ["recoveryHints", "ledgerSummary"]
2098
+ },
1553
2099
  nodes: results,
2100
+ activeWork: activeWorkEvidence.activeWork,
2101
+ staleDirectWorkSummary,
2102
+ ...args.includeStaleDirectWorkDetails === true ? { staleDirectWork: activeWorkEvidence.staleDirectWork } : {},
2103
+ terminalDirectWork: activeWorkEvidence.terminalDirectWork,
2104
+ activeWorkSummary: activeWorkEvidence.summary,
2105
+ ...pollingGuidance ? { pollingGuidance } : {},
1554
2106
  branchConvergenceSummary: summarizeBranchConvergence(results)
1555
2107
  };
1556
2108
  try {
@@ -1559,6 +2111,14 @@ async function meshStatus(ctx) {
1559
2111
  }
1560
2112
  try {
1561
2113
  const pendingEvents = await drainCoordinatorPendingEvents(ctx);
2114
+ const asyncRefineJobs = (0, import_daemon_core.buildMeshAsyncRefineJobs)({
2115
+ meshId: mesh.id,
2116
+ ledgerEntries,
2117
+ pendingEvents
2118
+ });
2119
+ if (asyncRefineJobs.length > 0) {
2120
+ response.asyncRefineJobs = asyncRefineJobs;
2121
+ }
1562
2122
  if (pendingEvents.length > 0) {
1563
2123
  response.pendingCoordinatorEvents = pendingEvents;
1564
2124
  }
@@ -1568,12 +2128,17 @@ async function meshStatus(ctx) {
1568
2128
  }
1569
2129
  async function meshTaskHistory(ctx, args) {
1570
2130
  const { mesh } = ctx;
1571
- await drainCoordinatorPendingEvents(ctx);
2131
+ const pendingEvents = await drainCoordinatorPendingEvents(ctx);
1572
2132
  const tail = typeof args.tail === "number" && args.tail > 0 ? args.tail : 20;
1573
2133
  const kind = typeof args.kind === "string" && args.kind.trim() ? [args.kind.trim()] : void 0;
1574
2134
  const entries = (0, import_daemon_core.readLedgerEntries)(mesh.id, { tail, kind });
1575
2135
  const summary = (0, import_daemon_core.getLedgerSummary)(mesh.id);
1576
- return JSON.stringify({ meshId: mesh.id, entries, summary }, null, 2);
2136
+ return JSON.stringify({
2137
+ meshId: mesh.id,
2138
+ entries,
2139
+ summary,
2140
+ ...pendingEvents.length > 0 ? { pendingCoordinatorEvents: pendingEvents } : {}
2141
+ }, null, 2);
1577
2142
  }
1578
2143
  async function meshReconcileLedger(ctx, args) {
1579
2144
  await refreshMeshFromDaemon(ctx);
@@ -1663,6 +2228,9 @@ async function meshListNodes(ctx) {
1663
2228
  nodeId: n.id,
1664
2229
  workspace: n.workspace,
1665
2230
  repoRoot: n.repoRoot,
2231
+ daemonId: readNodeDaemonId(n),
2232
+ machineId: readNodeMachineId(n),
2233
+ machine: buildNodeMachineIdentity(ctx, n),
1666
2234
  isLocalWorktree: n.isLocalWorktree,
1667
2235
  policy: n.policy,
1668
2236
  relatedRepos: readRelatedRepos(n),
@@ -1672,12 +2240,13 @@ async function meshListNodes(ctx) {
1672
2240
  }, null, 2);
1673
2241
  }
1674
2242
  async function meshEnqueueTask(ctx, args) {
2243
+ const taskMode = readString(args.task_mode) || readString(args.taskMode);
1675
2244
  try {
1676
- const task = (0, import_daemon_core.enqueueTask)(ctx.mesh.id, args.message);
2245
+ const task = (0, import_daemon_core.enqueueTask)(ctx.mesh.id, args.message, { taskMode });
1677
2246
  if (isLocalTransport(ctx.transport) && !(ctx.transport instanceof IpcTransport)) {
1678
2247
  ctx.transport.command("trigger_mesh_queue", { meshId: ctx.mesh.id }).catch(() => {
1679
2248
  });
1680
- return JSON.stringify({ success: true, taskId: task.id, status: task.status });
2249
+ return JSON.stringify({ success: true, source: "queue", taskId: task.id, status: task.status, taskMode: task.taskMode });
1681
2250
  }
1682
2251
  if (ctx.transport instanceof IpcTransport) {
1683
2252
  ctx.transport.command("trigger_mesh_queue", { meshId: ctx.mesh.id }).catch(() => {
@@ -1690,11 +2259,24 @@ async function meshEnqueueTask(ctx, args) {
1690
2259
  ipcDispatchToRemoteAgent(ctx, node, { message: args.message }).then((result) => {
1691
2260
  if (result.success) {
1692
2261
  try {
2262
+ const providerType = result.providerType;
2263
+ const descriptor = summarizeTaskMessage(args.message);
1693
2264
  (0, import_daemon_core.appendLedgerEntry)(ctx.mesh.id, {
1694
2265
  kind: "task_dispatched",
1695
2266
  nodeId: node.id,
1696
2267
  sessionId: result.sessionId,
1697
- payload: { message: args.message, via: "p2p_direct", taskId: task.id }
2268
+ providerType,
2269
+ payload: {
2270
+ source: "queue",
2271
+ via: "p2p_direct",
2272
+ taskId: task.id,
2273
+ message: args.message,
2274
+ taskTitle: descriptor.taskTitle,
2275
+ taskSummary: descriptor.taskSummary,
2276
+ ...task.taskMode ? { taskMode: task.taskMode } : {},
2277
+ ...providerType ? { providerType } : {},
2278
+ targetSessionId: result.sessionId
2279
+ }
1698
2280
  });
1699
2281
  } catch {
1700
2282
  }
@@ -1705,24 +2287,37 @@ async function meshEnqueueTask(ctx, args) {
1705
2287
  }
1706
2288
  Promise.all(dispatchPromises).catch(() => {
1707
2289
  });
1708
- return JSON.stringify({ success: true, taskId: task.id, status: task.status });
2290
+ return JSON.stringify({ success: true, source: "queue", taskId: task.id, status: task.status, taskMode: task.taskMode });
1709
2291
  }
1710
- return JSON.stringify({ success: true, taskId: task.id, status: task.status });
2292
+ return JSON.stringify({ success: true, source: "queue", taskId: task.id, status: task.status, taskMode: task.taskMode });
1711
2293
  } catch (e) {
1712
- return JSON.stringify({ success: false, error: e.message });
2294
+ const message = e?.message || String(e);
2295
+ if (message.includes("live_debug_readonly_guardrail_violation")) {
2296
+ return JSON.stringify({ success: false, code: "live_debug_readonly_guardrail_violation", taskMode, error: message });
2297
+ }
2298
+ return JSON.stringify({ success: false, error: message });
1713
2299
  }
1714
2300
  }
1715
2301
  async function meshViewQueue(ctx, args) {
1716
2302
  try {
2303
+ await refreshMeshFromDaemon(ctx);
1717
2304
  const statusFilter = sanitizeQueueStatusFilter(args.status);
1718
2305
  const view = normalizeQueueViewMode(args.view);
1719
- const fullQueue = annotateQueueStaleness((0, import_daemon_core.getQueue)(ctx.mesh.id), ctx.mesh);
2306
+ const fullQueue = prioritizeActiveQueueRows(annotateQueueStaleness((0, import_daemon_core.getQueue)(ctx.mesh.id), ctx.mesh));
1720
2307
  const queue = filterQueueForView(fullQueue, view, statusFilter);
1721
2308
  const summary = buildQueueStatusSummary(fullQueue);
1722
2309
  const visibleSummary = buildQueueStatusSummary(queue);
1723
2310
  const maintenance = buildQueueMaintenanceReport(fullQueue);
2311
+ const liveNodes = await collectMeshViewQueueNodesWithLiveSessions(ctx);
2312
+ const activeWorkEvidence = (0, import_daemon_core.buildMeshActiveWork)({
2313
+ meshId: ctx.mesh.id,
2314
+ queue: fullQueue,
2315
+ ledgerEntries: (0, import_daemon_core.readLedgerEntries)(ctx.mesh.id, { tail: 500 }),
2316
+ nodes: liveNodes
2317
+ });
1724
2318
  const staleAssignedTasks = maintenance.staleAssignedTasks || [];
1725
2319
  const requestedHistoricalRows = queue.some((task) => HISTORICAL_QUEUE_STATUSES.has(String(task?.status || "")));
2320
+ const pollingGuidance = buildActiveWorkPollingGuidance(activeWorkEvidence.summary);
1726
2321
  return JSON.stringify({
1727
2322
  success: true,
1728
2323
  sourceOfTruth: {
@@ -1738,6 +2333,10 @@ async function meshViewQueue(ctx, args) {
1738
2333
  },
1739
2334
  queue,
1740
2335
  visibleQueue: queue,
2336
+ activeWork: activeWorkEvidence.activeWork,
2337
+ staleDirectWork: activeWorkEvidence.staleDirectWork,
2338
+ activeWorkSummary: activeWorkEvidence.summary,
2339
+ ...pollingGuidance ? { pollingGuidance } : {},
1741
2340
  visibleSummary,
1742
2341
  summary,
1743
2342
  activeCounts: summary.activeCounts,
@@ -1771,6 +2370,10 @@ async function meshQueueCancel(ctx, args) {
1771
2370
  if (!taskId) return JSON.stringify({ success: false, error: "task_id required" });
1772
2371
  const task = (0, import_daemon_core.cancelTask)(ctx.mesh.id, taskId, { reason: args.reason });
1773
2372
  if (!task) return JSON.stringify({ success: false, error: `Queue task '${taskId}' not found` });
2373
+ if (isLocalTransport(ctx.transport)) {
2374
+ ctx.transport.command("trigger_mesh_queue", { meshId: ctx.mesh.id }).catch(() => {
2375
+ });
2376
+ }
1774
2377
  return JSON.stringify({ success: true, task }, null, 2);
1775
2378
  } catch (e) {
1776
2379
  return JSON.stringify({ success: false, error: e.message });
@@ -1801,10 +2404,60 @@ async function meshQueueRequeue(ctx, args) {
1801
2404
  }
1802
2405
  }
1803
2406
  async function meshSendTask(ctx, args) {
2407
+ const requestedTaskMode = readString(args.task_mode) || readString(args.taskMode);
2408
+ const modeValidation = (0, import_daemon_core.validateMeshTaskModeRequest)(requestedTaskMode, args.message);
2409
+ if (!modeValidation.valid) {
2410
+ return JSON.stringify({
2411
+ success: false,
2412
+ code: "live_debug_readonly_guardrail_violation",
2413
+ taskMode: modeValidation.taskMode || requestedTaskMode,
2414
+ violations: modeValidation.violations,
2415
+ allowedOperations: modeValidation.allowedOperations,
2416
+ error: `live_debug_readonly_guardrail_violation: forbidden operations (${modeValidation.violations.join(", ")})`
2417
+ });
2418
+ }
2419
+ const taskMode = modeValidation.taskMode;
1804
2420
  const node = await findNodeWithRefresh(ctx, args.node_id);
1805
2421
  if (node.policy?.readOnly) {
1806
2422
  return JSON.stringify({ error: `Node '${args.node_id}' is read-only` });
1807
2423
  }
2424
+ let explicitTargetSession;
2425
+ if (args.session_id && isWorkerTaskMode(taskMode) && (ctx.transport instanceof IpcTransport || isLocalTransport(ctx.transport))) {
2426
+ try {
2427
+ const statusResult = await commandForNode(ctx, node, "get_status_metadata", {});
2428
+ const sessions = extractStatusMetadataSessions(statusResult);
2429
+ explicitTargetSession = sessions.find((session) => readSessionRecordId(session) === args.session_id);
2430
+ if (explicitTargetSession && isMeshCoordinatorSessionRecord(explicitTargetSession)) {
2431
+ return JSON.stringify({
2432
+ success: false,
2433
+ recoverable: true,
2434
+ code: "mesh_target_session_is_coordinator",
2435
+ reason: "mesh_target_session_is_coordinator",
2436
+ nodeId: args.node_id,
2437
+ sessionId: args.session_id,
2438
+ taskMode: taskMode || "unspecified",
2439
+ error: `Session '${args.session_id}' is a Repo Mesh coordinator session, not a visible worker session. Launch or use a visible worker session before dispatching this task.`,
2440
+ nextAction: `Call mesh_launch_session for node '${args.node_id}' and then retry mesh_send_task with that worker session_id, or use mesh_enqueue_task for queue-based worker assignment.`
2441
+ });
2442
+ }
2443
+ if (explicitTargetSession && isUnmanagedSessionRecord(explicitTargetSession)) {
2444
+ return JSON.stringify({
2445
+ success: false,
2446
+ recoverable: true,
2447
+ code: "mesh_target_session_unmanaged",
2448
+ reason: "mesh_target_session_unmanaged",
2449
+ nodeId: args.node_id,
2450
+ sessionId: args.session_id,
2451
+ taskMode: taskMode || "unspecified",
2452
+ unsafeTranscriptAlias: true,
2453
+ error: `Session '${args.session_id}' on node '${args.node_id}' has no Repo Mesh delegation metadata (missing meshNodeFor/meshCoordinatorFor/launchedByCoordinator). It may be the coordinator's own session or an unrelated session \u2014 dispatching risks self-send and orphaned completion events that never reach the coordinator ledger.`,
2454
+ nextAction: `Call mesh_launch_session for node '${args.node_id}' to start a fresh managed worker session, then retry mesh_send_task with the returned session_id. Alternatively use mesh_enqueue_task for queue-based assignment without specifying session_id.`
2455
+ });
2456
+ }
2457
+ } catch {
2458
+ explicitTargetSession = void 0;
2459
+ }
2460
+ }
1808
2461
  const duplicate = hasRecentDuplicateDispatch(ctx, args);
1809
2462
  if (duplicate.duplicate) {
1810
2463
  return JSON.stringify({
@@ -1828,75 +2481,172 @@ async function meshSendTask(ctx, args) {
1828
2481
  const res = await ctx.transport.meshEnqueueTask(node.daemonId, {
1829
2482
  meshId: ctx.mesh.id,
1830
2483
  message: args.message,
1831
- targetNodeId: args.node_id
2484
+ targetNodeId: args.node_id,
2485
+ ...taskMode ? { taskMode } : {}
1832
2486
  });
1833
2487
  return JSON.stringify(res);
1834
2488
  }
1835
2489
  const isLocalNode = isLocalControlPlaneNode(ctx, node);
1836
2490
  if (ctx.transport instanceof IpcTransport && node.daemonId && !isLocalNode) {
1837
2491
  const cached = meshSessionProviderMetadata.get(meshSessionCacheKey(args.node_id, args.session_id || ""));
2492
+ const taskId = (0, import_node_crypto.randomUUID)();
1838
2493
  const result2 = await ipcDispatchToRemoteAgent(ctx, node, {
1839
2494
  session_id: args.session_id,
1840
2495
  message: args.message,
1841
- providerType: cached?.providerType
2496
+ providerType: cached?.providerType,
2497
+ verifiedSession: explicitTargetSession
1842
2498
  });
1843
2499
  if (result2.success) {
1844
2500
  const dispatchedSessionId = args.session_id || result2.sessionId;
1845
2501
  try {
2502
+ const providerType = result2.providerType || cached?.providerType;
1846
2503
  (0, import_daemon_core.appendLedgerEntry)(ctx.mesh.id, {
1847
2504
  kind: "task_dispatched",
1848
2505
  nodeId: args.node_id,
1849
2506
  sessionId: dispatchedSessionId,
1850
- payload: {
1851
- message: args.message,
1852
- via: "p2p_direct",
1853
- ...dispatchedSessionId ? { targetSessionId: dispatchedSessionId } : {}
1854
- }
2507
+ providerType,
2508
+ payload: buildDirectTaskPayload(args.message, "p2p_direct", {
2509
+ taskId,
2510
+ taskMode,
2511
+ providerType,
2512
+ targetSessionId: dispatchedSessionId
2513
+ })
1855
2514
  });
1856
2515
  } catch {
1857
2516
  }
1858
2517
  }
1859
- return JSON.stringify({ ...result2, nodeId: args.node_id, dispatched: result2.success === true });
2518
+ return JSON.stringify({
2519
+ ...result2,
2520
+ nodeId: args.node_id,
2521
+ sessionId: result2.success ? args.session_id || result2.sessionId : args.session_id,
2522
+ ...result2.success ? { source: "direct", taskId } : {},
2523
+ taskMode,
2524
+ ...result2.success && result2.providerType ? { providerType: result2.providerType } : {},
2525
+ dispatched: result2.success === true
2526
+ });
1860
2527
  }
1861
2528
  if (args.session_id && isLocalTransport(ctx.transport)) {
1862
2529
  const cached = meshSessionProviderMetadata.get(meshSessionCacheKey(args.node_id, args.session_id));
2530
+ let resolvedProviderType = cached?.providerType || "";
2531
+ if (!resolvedProviderType) {
2532
+ let explicitSession = explicitTargetSession;
2533
+ if (!explicitSession) {
2534
+ const statusResult = await commandForNode(ctx, node, "get_status_metadata", {});
2535
+ const sessions = extractStatusMetadataSessions(statusResult);
2536
+ explicitSession = sessions.find((session) => readSessionRecordId(session) === args.session_id);
2537
+ }
2538
+ if (!explicitSession) {
2539
+ return JSON.stringify({
2540
+ success: false,
2541
+ recoverable: true,
2542
+ code: "mesh_target_session_not_found",
2543
+ reason: "mesh_target_session_not_found",
2544
+ transport: "local_ipc",
2545
+ retryRecommended: true,
2546
+ nodeId: args.node_id,
2547
+ sessionId: args.session_id,
2548
+ error: `Local session '${args.session_id}' is not present in live status for node '${args.node_id}'.`,
2549
+ nextAction: `Launch a fresh session with mesh_launch_session(node_id: '${args.node_id}') or retry without session_id so Repo Mesh can target a live delegate session.`
2550
+ });
2551
+ }
2552
+ if (isMeshCoordinatorSessionRecord(explicitSession)) {
2553
+ return JSON.stringify({
2554
+ success: false,
2555
+ recoverable: true,
2556
+ code: "mesh_target_session_is_coordinator",
2557
+ reason: "mesh_target_session_is_coordinator",
2558
+ nodeId: args.node_id,
2559
+ sessionId: args.session_id,
2560
+ taskMode: taskMode || "unspecified",
2561
+ error: `Session '${args.session_id}' is a Repo Mesh coordinator session, not a visible worker session. Launch or use a visible worker session before dispatching this task.`,
2562
+ nextAction: `Call mesh_launch_session for node '${args.node_id}' and then retry mesh_send_task with that worker session_id, or use mesh_enqueue_task for queue-based worker assignment.`
2563
+ });
2564
+ }
2565
+ if (isUnmanagedSessionRecord(explicitSession)) {
2566
+ return JSON.stringify({
2567
+ success: false,
2568
+ recoverable: true,
2569
+ code: "mesh_target_session_unmanaged",
2570
+ reason: "mesh_target_session_unmanaged",
2571
+ nodeId: args.node_id,
2572
+ sessionId: args.session_id,
2573
+ taskMode: taskMode || "unspecified",
2574
+ unsafeTranscriptAlias: true,
2575
+ unsafeDelegateTarget: true,
2576
+ error: `Session '${args.session_id}' on node '${args.node_id}' has no Repo Mesh delegation metadata (missing meshNodeFor/meshCoordinatorFor/launchedByCoordinator). It may be the coordinator's own session or an unrelated session \u2014 dispatching risks self-send and orphaned completion events that never reach the coordinator ledger.`,
2577
+ nextAction: `Call mesh_launch_session for node '${args.node_id}' to start a fresh managed worker session, then retry mesh_send_task with the returned session_id. Alternatively use mesh_enqueue_task for queue-based assignment without specifying session_id.`
2578
+ });
2579
+ }
2580
+ resolvedProviderType = resolveSessionProviderType(explicitSession);
2581
+ if (resolvedProviderType) {
2582
+ meshSessionProviderMetadata.set(meshSessionCacheKey(args.node_id, args.session_id), {
2583
+ providerType: resolvedProviderType,
2584
+ providerSessionId: readString(explicitSession?.providerSessionId) || void 0
2585
+ });
2586
+ }
2587
+ }
2588
+ if (!resolvedProviderType) {
2589
+ return JSON.stringify({
2590
+ success: false,
2591
+ recoverable: true,
2592
+ code: "mesh_target_session_provider_unknown",
2593
+ reason: "mesh_target_session_provider_unknown",
2594
+ transport: "local_ipc",
2595
+ retryRecommended: false,
2596
+ nodeId: args.node_id,
2597
+ sessionId: args.session_id,
2598
+ error: `Local session '${args.session_id}' is live but does not expose providerType/cliType, so agent_command cannot be routed safely.`,
2599
+ nextAction: `Relaunch the target session on node '${args.node_id}' or retry without session_id so Repo Mesh can pick a session with provider metadata.`
2600
+ });
2601
+ }
1863
2602
  const dispatchResult = await commandForNode(ctx, node, "agent_command", {
1864
2603
  targetSessionId: args.session_id,
1865
- ...cached?.providerType ? { agentType: cached.providerType, cliType: cached.providerType, providerType: cached.providerType } : {},
2604
+ agentType: resolvedProviderType,
2605
+ cliType: resolvedProviderType,
2606
+ providerType: resolvedProviderType,
1866
2607
  action: "send_chat",
1867
2608
  message: args.message
1868
2609
  });
1869
2610
  const dispatchPayload = unwrapCommandPayload(dispatchResult);
1870
2611
  if (dispatchPayload?.success === false || dispatchResult?.success === false) {
2612
+ const source = dispatchPayload?.success === false ? dispatchPayload : dispatchResult;
1871
2613
  return JSON.stringify({
2614
+ ...source && typeof source === "object" ? source : {},
1872
2615
  success: false,
1873
2616
  nodeId: args.node_id,
1874
2617
  sessionId: args.session_id,
1875
2618
  error: dispatchPayload?.error || dispatchResult?.error || "agent_command rejected the task"
1876
2619
  });
1877
2620
  }
2621
+ const taskId = (0, import_node_crypto.randomUUID)();
1878
2622
  try {
1879
2623
  (0, import_daemon_core.appendLedgerEntry)(ctx.mesh.id, {
1880
2624
  kind: "task_dispatched",
1881
2625
  nodeId: args.node_id,
1882
2626
  sessionId: args.session_id,
1883
- providerType: cached?.providerType,
1884
- payload: { message: args.message, via: "local_direct" }
2627
+ providerType: resolvedProviderType,
2628
+ payload: buildDirectTaskPayload(args.message, "local_direct", {
2629
+ taskId,
2630
+ taskMode,
2631
+ providerType: resolvedProviderType,
2632
+ targetSessionId: args.session_id
2633
+ })
1885
2634
  });
1886
2635
  } catch {
1887
2636
  }
1888
- return JSON.stringify({ success: true, dispatched: true, nodeId: args.node_id, sessionId: args.session_id });
2637
+ return JSON.stringify({ success: true, dispatched: true, source: "direct", taskId, taskMode, providerType: resolvedProviderType, nodeId: args.node_id, sessionId: args.session_id });
1889
2638
  }
1890
2639
  const task = (0, import_daemon_core.enqueueTask)(ctx.mesh.id, args.message, {
1891
2640
  targetNodeId: args.node_id,
1892
- targetSessionId: args.session_id
2641
+ targetSessionId: args.session_id,
2642
+ taskMode
1893
2643
  });
1894
2644
  if (isLocalTransport(ctx.transport) || ctx.transport instanceof IpcTransport) {
1895
2645
  ctx.transport.command("trigger_mesh_queue", { meshId: ctx.mesh.id }).catch(() => {
1896
2646
  });
1897
2647
  }
1898
- const pendingEvents = isLocalTransport(ctx.transport) ? (0, import_daemon_core.drainPendingMeshCoordinatorEvents)() : [];
1899
- const result = { success: true, nodeId: args.node_id, taskId: task.id, status: task.status };
2648
+ const pendingEvents = isLocalTransport(ctx.transport) ? (0, import_daemon_core.drainPendingMeshCoordinatorEvents)(ctx.mesh.id) : [];
2649
+ const result = { success: true, source: "queue", nodeId: args.node_id, taskId: task.id, status: task.status, taskMode: task.taskMode };
1900
2650
  if (pendingEvents.length > 0) {
1901
2651
  result.pendingCoordinatorEvents = pendingEvents;
1902
2652
  }
@@ -1920,7 +2670,7 @@ async function meshReadChat(ctx, args) {
1920
2670
  await drainCoordinatorPendingEvents(ctx, { nodeIds: [args.node_id] });
1921
2671
  }
1922
2672
  if (isLocalTransport(ctx.transport)) {
1923
- const cached = meshSessionProviderMetadata.get(meshSessionCacheKey(args.node_id, args.session_id));
2673
+ const cached = resolveMeshSessionProviderMetadata(ctx, args.node_id, args.session_id);
1924
2674
  const providerSessionId = typeof args.provider_session_id === "string" && args.provider_session_id.trim() ? args.provider_session_id.trim() : cached?.providerSessionId;
1925
2675
  const result = await commandForNode(ctx, node, "read_chat", {
1926
2676
  sessionId: args.session_id,
@@ -1966,7 +2716,7 @@ async function meshReadChat(ctx, args) {
1966
2716
  async function meshReadDebug(ctx, args) {
1967
2717
  const node = await findNodeWithRefresh(ctx, args.node_id);
1968
2718
  if (isLocalTransport(ctx.transport)) {
1969
- const cached = meshSessionProviderMetadata.get(meshSessionCacheKey(args.node_id, args.session_id));
2719
+ const cached = resolveMeshSessionProviderMetadata(ctx, args.node_id, args.session_id);
1970
2720
  const providerSessionId = typeof args.provider_session_id === "string" && args.provider_session_id.trim() ? args.provider_session_id.trim() : cached?.providerSessionId;
1971
2721
  const delivery = args.delivery === "inline" ? void 0 : "daemon_file";
1972
2722
  const result = await commandForNode(ctx, node, "get_chat_debug_bundle", {
@@ -1997,6 +2747,8 @@ async function meshReadDebug(ctx, args) {
1997
2747
  }
1998
2748
  async function meshLaunchSession(ctx, args) {
1999
2749
  const node = await findNodeWithRefresh(ctx, args.node_id);
2750
+ const bootstrapBlock = getWorktreeBootstrapLaunchBlock(node);
2751
+ if (bootstrapBlock) return JSON.stringify(bootstrapBlock, null, 2);
2000
2752
  if (isLocalTransport(ctx.transport)) {
2001
2753
  let resolvedProviderType = typeof args.type === "string" && args.type.trim() ? args.type : "";
2002
2754
  if (!resolvedProviderType) {
@@ -2021,6 +2773,10 @@ async function meshLaunchSession(ctx, args) {
2021
2773
  const coordinatorNode = resolveCoordinatorNode(ctx);
2022
2774
  const coordinatorDaemonId = coordinatorNode?.daemonId || ctx.localDaemonId;
2023
2775
  const spawnedSessionVisibility = readSpawnedSessionVisibility(ctx.mesh.policy);
2776
+ const isLocalNode = isLocalControlPlaneNode(ctx, node);
2777
+ if (node.daemonId && !isLocalNode && !coordinatorDaemonId) {
2778
+ return JSON.stringify(buildMissingCoordinatorDaemonIdFailure(ctx, node, resolvedProviderType), null, 2);
2779
+ }
2024
2780
  let result;
2025
2781
  try {
2026
2782
  result = await commandForNode(ctx, node, "launch_cli", {
@@ -2061,7 +2817,6 @@ async function meshLaunchSession(ctx, args) {
2061
2817
  });
2062
2818
  } catch {
2063
2819
  }
2064
- const isLocalNode = isLocalControlPlaneNode(ctx, node);
2065
2820
  if (ctx.transport instanceof IpcTransport && node.daemonId && !isLocalNode) {
2066
2821
  ctx.transport.meshCommand(node.daemonId, "trigger_mesh_queue", { meshId: ctx.mesh.id }).catch(() => {
2067
2822
  });
@@ -2086,6 +2841,9 @@ async function meshLaunchSession(ctx, args) {
2086
2841
  const coordinatorNode = resolveCoordinatorNode(ctx);
2087
2842
  const coordinatorDaemonId = coordinatorNode?.daemonId || ctx.localDaemonId;
2088
2843
  const spawnedSessionVisibility = readSpawnedSessionVisibility(ctx.mesh.policy);
2844
+ if (!coordinatorDaemonId) {
2845
+ return JSON.stringify(buildMissingCoordinatorDaemonIdFailure(ctx, node, resolvedProviderType), null, 2);
2846
+ }
2089
2847
  try {
2090
2848
  const res = await ctx.transport.launch(node.daemonId, {
2091
2849
  type: resolvedProviderType,
@@ -2166,6 +2924,51 @@ async function meshGitStatus(ctx, args) {
2166
2924
  }, null, 2);
2167
2925
  }
2168
2926
  }
2927
+ async function meshFastForwardNode(ctx, args) {
2928
+ await refreshMeshFromDaemon(ctx);
2929
+ const node = await findNodeWithRefresh(ctx, args.node_id);
2930
+ const submoduleIgnorePaths = node.policy?.submoduleIgnorePaths || [];
2931
+ if (node.policy?.readOnly) {
2932
+ return JSON.stringify({
2933
+ success: false,
2934
+ code: "node_read_only",
2935
+ nodeId: args.node_id,
2936
+ workspace: node.workspace,
2937
+ allowed: false,
2938
+ willRun: false,
2939
+ executed: false,
2940
+ blockingReasons: ["node_read_only"]
2941
+ }, null, 2);
2942
+ }
2943
+ try {
2944
+ const dryRun = args.dry_run === true || args.execute !== true;
2945
+ const result = await commandForNode(ctx, node, "fast_forward_mesh_node", {
2946
+ meshId: ctx.mesh.id,
2947
+ nodeId: node.id,
2948
+ workspace: node.workspace,
2949
+ branch: typeof args.branch === "string" ? args.branch : void 0,
2950
+ execute: args.execute === true && args.dry_run !== true,
2951
+ dryRun,
2952
+ updateSubmodules: args.update_submodules === true,
2953
+ submoduleIgnorePaths: submoduleIgnorePaths.length > 0 ? submoduleIgnorePaths : void 0
2954
+ });
2955
+ return JSON.stringify(unwrapCommandPayload(result), null, 2);
2956
+ } catch (e) {
2957
+ const failure = buildCoordinatorP2pRelayFailure(e, {
2958
+ command: "fast_forward_mesh_node",
2959
+ targetDaemonId: node.daemonId,
2960
+ nodeId: args.node_id
2961
+ });
2962
+ return JSON.stringify({
2963
+ ...failure,
2964
+ workspace: node.workspace,
2965
+ allowed: false,
2966
+ willRun: false,
2967
+ executed: false,
2968
+ blockingReasons: [failure.code || "mesh_fast_forward_unavailable"]
2969
+ }, null, 2);
2970
+ }
2971
+ }
2169
2972
  async function meshCheckpoint(ctx, args) {
2170
2973
  const node = await findNodeWithRefresh(ctx, args.node_id);
2171
2974
  if (node.policy?.readOnly) {
@@ -2181,7 +2984,13 @@ async function meshCheckpoint(ctx, args) {
2181
2984
  (0, import_daemon_core.appendLedgerEntry)(ctx.mesh.id, {
2182
2985
  kind: "checkpoint_created",
2183
2986
  nodeId: args.node_id,
2184
- payload: { message: args.message, commit: result?.checkpoint?.commit }
2987
+ payload: {
2988
+ message: args.message,
2989
+ commit: result?.checkpoint?.commit,
2990
+ outcome: result?.checkpoint?.status || (result?.checkpoint?.noop ? "skipped" : void 0),
2991
+ noop: result?.checkpoint?.noop === true,
2992
+ reason: result?.checkpoint?.reason
2993
+ }
2185
2994
  });
2186
2995
  } catch {
2187
2996
  }
@@ -2197,7 +3006,13 @@ async function meshCheckpoint(ctx, args) {
2197
3006
  (0, import_daemon_core.appendLedgerEntry)(ctx.mesh.id, {
2198
3007
  kind: "checkpoint_created",
2199
3008
  nodeId: args.node_id,
2200
- payload: { message: args.message, commit: res?.checkpoint?.commit }
3009
+ payload: {
3010
+ message: args.message,
3011
+ commit: res?.checkpoint?.commit,
3012
+ outcome: res?.checkpoint?.status || (res?.checkpoint?.noop ? "skipped" : void 0),
3013
+ noop: res?.checkpoint?.noop === true,
3014
+ reason: res?.checkpoint?.reason
3015
+ }
2201
3016
  });
2202
3017
  } catch {
2203
3018
  }
@@ -2251,6 +3066,7 @@ async function meshCloneNode(ctx, args) {
2251
3066
  if (existingIndex >= 0) ctx.mesh.nodes[existingIndex] = clonePayload.node;
2252
3067
  else ctx.mesh.nodes.push(clonePayload.node);
2253
3068
  ctx.mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
3069
+ await syncCoordinatorDaemonMeshCache(ctx);
2254
3070
  }
2255
3071
  return JSON.stringify(result, null, 2);
2256
3072
  } else if (!isLocalTransport(ctx.transport) && sourceNode.daemonId) {
@@ -2268,6 +3084,7 @@ async function meshCloneNode(ctx, args) {
2268
3084
  if (existingIndex >= 0) ctx.mesh.nodes[existingIndex] = clonePayload.node;
2269
3085
  else ctx.mesh.nodes.push(clonePayload.node);
2270
3086
  ctx.mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
3087
+ await syncCoordinatorDaemonMeshCache(ctx);
2271
3088
  }
2272
3089
  return JSON.stringify(res, null, 2);
2273
3090
  } catch (e) {
@@ -2363,6 +3180,43 @@ async function meshRemoveNode(ctx, args) {
2363
3180
  return JSON.stringify({ error: "Cloud mesh remove_node requires node daemonId" });
2364
3181
  }
2365
3182
  }
3183
+ function resolveRefineConfigNode(ctx, nodeId) {
3184
+ if (nodeId) return findNode(ctx.mesh, nodeId);
3185
+ const node = ctx.mesh.nodes.find((entry) => !!entry.workspace);
3186
+ if (!node) throw new Error("No mesh node with a workspace is available");
3187
+ return node;
3188
+ }
3189
+ async function meshRefineConfigSchema(ctx) {
3190
+ const node = resolveRefineConfigNode(ctx);
3191
+ const result = await commandForNode(ctx, node, "get_mesh_refine_config_schema", {});
3192
+ return JSON.stringify(result, null, 2);
3193
+ }
3194
+ async function meshValidateRefineConfig(ctx, args) {
3195
+ const node = resolveRefineConfigNode(ctx, args.node_id);
3196
+ const result = await commandForNode(ctx, node, "validate_mesh_refine_config", {
3197
+ workspace: node.workspace,
3198
+ inlineMesh: ctx.mesh,
3199
+ ...args.config ? { config: args.config } : {}
3200
+ });
3201
+ return JSON.stringify(result, null, 2);
3202
+ }
3203
+ async function meshSuggestRefineConfig(ctx, args) {
3204
+ const node = resolveRefineConfigNode(ctx, args.node_id);
3205
+ const result = await commandForNode(ctx, node, "suggest_mesh_refine_config", {
3206
+ workspace: node.workspace,
3207
+ inlineMesh: ctx.mesh
3208
+ });
3209
+ return JSON.stringify(result, null, 2);
3210
+ }
3211
+ async function meshRefinePlan(ctx, args) {
3212
+ const node = await findNodeWithRefresh(ctx, args.node_id);
3213
+ const result = await commandForNode(ctx, node, "plan_mesh_refine_node", {
3214
+ meshId: ctx.mesh.id,
3215
+ nodeId: args.node_id,
3216
+ inlineMesh: ctx.mesh
3217
+ });
3218
+ return JSON.stringify(result, null, 2);
3219
+ }
2366
3220
  async function meshRefineNode(ctx, args) {
2367
3221
  const node = await findNodeWithRefresh(ctx, args.node_id);
2368
3222
  if (isLocalTransport(ctx.transport)) {
@@ -2371,7 +3225,7 @@ async function meshRefineNode(ctx, args) {
2371
3225
  nodeId: args.node_id,
2372
3226
  inlineMesh: ctx.mesh
2373
3227
  });
2374
- if (result?.success && result.removeResult?.removed !== false) {
3228
+ if (result?.success && result.async !== true && result.removeResult?.removed !== false) {
2375
3229
  const idx = ctx.mesh.nodes.findIndex((n) => n.id === args.node_id);
2376
3230
  if (idx >= 0) {
2377
3231
  ctx.mesh.nodes.splice(idx, 1);
@@ -2386,7 +3240,7 @@ async function meshRefineNode(ctx, args) {
2386
3240
  nodeId: args.node_id,
2387
3241
  inlineMesh: ctx.mesh
2388
3242
  });
2389
- if (res?.success && res.removeResult?.removed !== false) {
3243
+ if (res?.success && res.async !== true && res.removeResult?.removed !== false) {
2390
3244
  const idx = ctx.mesh.nodes.findIndex((n) => n.id === args.node_id);
2391
3245
  if (idx >= 0) {
2392
3246
  ctx.mesh.nodes.splice(idx, 1);
@@ -2423,13 +3277,13 @@ var STANDARD_TOOLS = [
2423
3277
  function buildMcpHelpText() {
2424
3278
  const meshTools = ALL_MESH_TOOLS.map((tool) => tool.name);
2425
3279
  return `
2426
- adhdev-mcp \u2014 ADHDev MCP Server
3280
+ ADHDev MCP Server
2427
3281
 
2428
3282
  Usage:
2429
- adhdev-mcp Local mode (requires standalone daemon)
2430
- adhdev-mcp --api-key <key> Cloud mode (ADHDev cloud API)
2431
- adhdev-mcp --mode ipc --repo-mesh <mesh_id> Cloud daemon IPC mesh mode
2432
- adhdev-mcp --repo-mesh <mesh_id> Mesh mode (coordinator-scoped tools)
3283
+ adhdev mcp Local mode (requires standalone daemon)
3284
+ adhdev mcp --api-key <key> Cloud mode (ADHDev cloud API)
3285
+ adhdev mcp --mode ipc --repo-mesh <mesh_id> Cloud daemon IPC mesh mode
3286
+ adhdev-mcp --help Compatibility bin (same server, legacy package entrypoint)
2433
3287
 
2434
3288
  Options:
2435
3289
  --mode <mode> Transport: local, cloud, or ipc
@@ -2454,6 +3308,7 @@ Mesh tools: ${meshTools.join(", ")}
2454
3308
  // src/server.ts
2455
3309
  var import_server = require("@modelcontextprotocol/sdk/server/index.js");
2456
3310
  var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
3311
+ var import_node_os = __toESM(require("os"));
2457
3312
  var import_types = require("@modelcontextprotocol/sdk/types.js");
2458
3313
 
2459
3314
  // src/transports/local.ts
@@ -3004,6 +3859,22 @@ function formatChatResult(result, sessionId, format, limit = 50, compact = false
3004
3859
  }))
3005
3860
  }, null, 2);
3006
3861
  }
3862
+ if ((format === "text" || format === void 0) && compact && compactPayload) {
3863
+ const lines2 = outputMessages.slice(-limit).map((m) => {
3864
+ const role = m.role === "user" ? "User" : m.role === "assistant" ? "Agent" : m.role;
3865
+ const content = messageContent(m);
3866
+ const truncated = content.length > 500 ? `${content.slice(0, 500)}\u2026` : content;
3867
+ return `[${role}] ${truncated}`;
3868
+ });
3869
+ if (compactPayload.summary) {
3870
+ const truncatedSummary = compactPayload.summary.length > 500 ? `${compactPayload.summary.slice(0, 500)}\u2026` : compactPayload.summary;
3871
+ lines2.push(`[Summary] ${truncatedSummary}`);
3872
+ }
3873
+ if (result?.pollingAdvisory) {
3874
+ lines2.push(`Advisory: ${result.pollingAdvisory.message}`);
3875
+ }
3876
+ return lines2.length > 0 ? lines2.join("\n\n") : "No messages in chat.";
3877
+ }
3007
3878
  if (outputMessages.length === 0) {
3008
3879
  return result?.pollingAdvisory ? `No messages in chat.
3009
3880
 
@@ -3971,6 +4842,7 @@ async function startMcpServer(opts) {
3971
4842
  requirePreTaskCheckpoint: false,
3972
4843
  requirePostTaskCheckpoint: true,
3973
4844
  requireApprovalForPush: true,
4845
+ allowAutoPublishSubmoduleMainCommits: false,
3974
4846
  requireApprovalForDestructiveGit: true,
3975
4847
  dirtyWorkspaceBehavior: "warn",
3976
4848
  maxParallelTasks: 2,
@@ -4027,11 +4899,13 @@ async function startMcpServer(opts) {
4027
4899
  }
4028
4900
  let localDaemonId;
4029
4901
  let localMachineId;
4902
+ let coordinatorHostname = import_node_os.default.hostname();
4030
4903
  if (transport instanceof LocalTransport || transport instanceof IpcTransport) {
4031
4904
  try {
4032
4905
  const { loadConfig } = await import("@adhdev/daemon-core");
4033
4906
  const cfg = loadConfig();
4034
- if (cfg.registeredMachineId) localMachineId = cfg.registeredMachineId;
4907
+ if (cfg.machineId) localMachineId = cfg.machineId;
4908
+ else if (cfg.registeredMachineId) localMachineId = cfg.registeredMachineId;
4035
4909
  } catch {
4036
4910
  }
4037
4911
  }
@@ -4039,11 +4913,13 @@ async function startMcpServer(opts) {
4039
4913
  try {
4040
4914
  const statusResult = await transport.getStatus();
4041
4915
  const instanceId = typeof statusResult?.status?.instanceId === "string" ? statusResult.status.instanceId.trim() : "";
4916
+ const hostname = typeof statusResult?.status?.hostname === "string" ? statusResult.status.hostname.trim() : typeof statusResult?.status?.machine?.hostname === "string" ? statusResult.status.machine.hostname.trim() : "";
4042
4917
  if (instanceId) localDaemonId = instanceId;
4918
+ if (hostname) coordinatorHostname = hostname;
4043
4919
  } catch {
4044
4920
  }
4045
4921
  }
4046
- const meshCtx = { mesh, transport, ...localDaemonId ? { localDaemonId } : {}, ...localMachineId ? { localMachineId } : {} };
4922
+ const meshCtx = { mesh, transport, ...localDaemonId ? { localDaemonId } : {}, ...localMachineId ? { localMachineId } : {}, ...coordinatorHostname ? { coordinatorHostname } : {} };
4047
4923
  const coordinatorPrompt = await buildMeshModeCoordinatorPrompt(mesh);
4048
4924
  const server2 = new import_server.Server(
4049
4925
  { name: "adhdev-mcp-server", version: "0.9.81" },
@@ -4072,7 +4948,7 @@ async function startMcpServer(opts) {
4072
4948
  let text;
4073
4949
  switch (name) {
4074
4950
  case "mesh_status":
4075
- text = await meshStatus(meshCtx);
4951
+ text = await meshStatus(meshCtx, a);
4076
4952
  break;
4077
4953
  case "mesh_list_nodes":
4078
4954
  text = await meshListNodes(meshCtx);
@@ -4104,6 +4980,9 @@ async function startMcpServer(opts) {
4104
4980
  case "mesh_git_status":
4105
4981
  text = await meshGitStatus(meshCtx, a);
4106
4982
  break;
4983
+ case "mesh_fast_forward_node":
4984
+ text = await meshFastForwardNode(meshCtx, a);
4985
+ break;
4107
4986
  case "mesh_checkpoint":
4108
4987
  text = await meshCheckpoint(meshCtx, a);
4109
4988
  break;
@@ -4119,6 +4998,18 @@ async function startMcpServer(opts) {
4119
4998
  case "mesh_refine_node":
4120
4999
  text = await meshRefineNode(meshCtx, a);
4121
5000
  break;
5001
+ case "mesh_refine_config_schema":
5002
+ text = await meshRefineConfigSchema(meshCtx);
5003
+ break;
5004
+ case "mesh_validate_refine_config":
5005
+ text = await meshValidateRefineConfig(meshCtx, a);
5006
+ break;
5007
+ case "mesh_suggest_refine_config":
5008
+ text = await meshSuggestRefineConfig(meshCtx, a);
5009
+ break;
5010
+ case "mesh_refine_plan":
5011
+ text = await meshRefinePlan(meshCtx, a);
5012
+ break;
4122
5013
  case "mesh_cleanup_sessions":
4123
5014
  text = await meshCleanupSessions(meshCtx, a);
4124
5015
  break;