@adhdev/daemon-standalone 0.9.82-rc.7 → 0.9.82-rc.71

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.
@@ -35,9 +35,19 @@ __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: 6e4,
47
+ agent_command: 3e4,
48
+ git_status: 45e3,
49
+ mesh_status: 12e4
50
+ };
41
51
  var IpcTransport = class {
42
52
  port;
43
53
  path;
@@ -85,7 +95,7 @@ var IpcTransport = class {
85
95
  }
86
96
  fn();
87
97
  };
88
- const timeoutMs = type === "mesh_relay_command" ? 6e4 : 15e3;
98
+ const timeoutMs = IPC_COMMAND_TIMEOUTS_MS[type] ?? DEFAULT_IPC_COMMAND_TIMEOUT_MS;
89
99
  const timeout = setTimeout(() => {
90
100
  finish(() => reject(new Error(`Daemon IPC command '${type}' timed out after ${Math.round(timeoutMs / 1e3)}s`)));
91
101
  }, timeoutMs);
@@ -143,6 +153,10 @@ function isLocalTransport(transport) {
143
153
  }
144
154
 
145
155
  // src/tools/chat-compact.ts
156
+ function isAssistantLike(message) {
157
+ const role = String(message?.role ?? "").toLowerCase();
158
+ return role === "assistant" || role === "agent";
159
+ }
146
160
  function messageContent(message) {
147
161
  const content = message?.content;
148
162
  if (typeof content === "string") return content;
@@ -161,16 +175,22 @@ function isCoordinatorVisibleMessage(message) {
161
175
  if (meta?.internal === true || meta?.debug === true || meta?.control === true || meta?.userVisible === false || meta?.user_visible === false) return false;
162
176
  return role === "user" || role === "assistant" || role === "agent";
163
177
  }
178
+ function buildCompactMessageTail(visibleMessages, opts) {
179
+ const summary = typeof opts.summary === "string" ? opts.summary.trim() : "";
180
+ const shouldOmitSummaryMessage = !!summary && !!opts.finalAssistant && isAssistantLike(opts.finalAssistant) && messageContent(opts.finalAssistant).trim() === summary;
181
+ const sourceMessages = shouldOmitSummaryMessage ? visibleMessages.filter((message) => message !== opts.finalAssistant) : visibleMessages;
182
+ return sourceMessages.slice(-opts.limit);
183
+ }
164
184
  function compactChatPayload(payload, opts = {}) {
165
185
  const rawMessages = Array.isArray(payload?.messages) ? payload.messages : [];
166
186
  const visible = rawMessages.filter(isCoordinatorVisibleMessage);
167
187
  const limit = Math.max(1, Math.min(opts.limit ?? 10, 10));
168
- const messages = visible.slice(-limit);
169
188
  const finalAssistant = [...visible].reverse().find((message) => {
170
189
  const role = String(message?.role ?? "").toLowerCase();
171
190
  return (role === "assistant" || role === "agent") && messageContent(message).trim();
172
191
  });
173
192
  const summary = typeof payload?.summary === "string" && payload.summary.trim() ? payload.summary.trim() : messageContent(finalAssistant).trim();
193
+ const messages = buildCompactMessageTail(visible, { summary, finalAssistant, limit });
174
194
  return {
175
195
  success: payload?.success !== false,
176
196
  compact: true,
@@ -235,6 +255,30 @@ var meshSessionProviderMetadata = /* @__PURE__ */ new Map();
235
255
  function readString(value) {
236
256
  return typeof value === "string" && value.trim() ? value.trim() : void 0;
237
257
  }
258
+ function summarizeTaskMessage(message) {
259
+ const taskSummary = message.replace(/\s+/g, " ").trim();
260
+ const taskTitle = taskSummary.length > 96 ? `${taskSummary.slice(0, 93)}...` : taskSummary;
261
+ return { taskTitle: taskTitle || "(untitled task)", taskSummary };
262
+ }
263
+ function buildDirectTaskPayload(message, via, opts) {
264
+ const descriptor = summarizeTaskMessage(message);
265
+ return {
266
+ source: "direct",
267
+ via,
268
+ taskId: opts.taskId,
269
+ message,
270
+ taskTitle: descriptor.taskTitle,
271
+ taskSummary: descriptor.taskSummary,
272
+ ...opts.taskMode ? { taskMode: opts.taskMode } : {},
273
+ ...opts.providerType ? { providerType: opts.providerType } : {},
274
+ ...opts.targetSessionId ? { targetSessionId: opts.targetSessionId } : {}
275
+ };
276
+ }
277
+ function findNode(mesh, nodeId) {
278
+ const node = mesh.nodes.find((n) => n.id === nodeId);
279
+ if (!node) throw new Error(`Node '${nodeId}' is not a member of mesh '${mesh.name}'`);
280
+ return node;
281
+ }
238
282
  var DUPLICATE_DISPATCH_WINDOW_MS = 6e4;
239
283
  var STALE_ASSIGNED_QUEUE_MS = 30 * 6e4;
240
284
  var OLD_HISTORICAL_QUEUE_RECORD_MS = 7 * 24 * 60 * 6e4;
@@ -246,15 +290,24 @@ async function refreshMeshFromDaemon(ctx) {
246
290
  const result = await ctx.transport.command("get_mesh", { meshId: ctx.mesh.id });
247
291
  if (!result?.success || !Array.isArray(result.mesh?.nodes)) return;
248
292
  const refreshedNodes = result.mesh.nodes.filter((n) => n?.id).map((n) => n);
249
- if (!refreshedNodes.length) return;
250
293
  ctx.mesh.nodes.splice(0, ctx.mesh.nodes.length, ...refreshedNodes);
251
294
  ctx.mesh.updatedAt = result.mesh.updatedAt ?? ctx.mesh.updatedAt;
252
295
  } catch {
253
296
  }
254
297
  }
298
+ async function syncCoordinatorDaemonMeshCache(ctx) {
299
+ if (!(ctx.transport instanceof IpcTransport)) return;
300
+ try {
301
+ await ctx.transport.command("get_mesh", {
302
+ meshId: ctx.mesh.id,
303
+ inlineMesh: ctx.mesh
304
+ });
305
+ } catch {
306
+ }
307
+ }
255
308
  async function findNodeWithRefresh(ctx, nodeId) {
256
309
  const hit = ctx.mesh.nodes.find((n) => n.id === nodeId);
257
- if (hit) return hit;
310
+ if (hit && !hit.isLocalWorktree) return hit;
258
311
  await refreshMeshFromDaemon(ctx);
259
312
  const refreshed = ctx.mesh.nodes.find((n) => n.id === nodeId);
260
313
  if (!refreshed) throw new Error(`Node '${nodeId}' is not a member of mesh '${ctx.mesh.name}'`);
@@ -262,7 +315,7 @@ async function findNodeWithRefresh(ctx, nodeId) {
262
315
  }
263
316
  async function findOptionalNodeWithRefresh(ctx, nodeId) {
264
317
  const hit = ctx.mesh.nodes.find((n) => n.id === nodeId);
265
- if (hit) return hit;
318
+ if (hit && !hit.isLocalWorktree) return hit;
266
319
  await refreshMeshFromDaemon(ctx);
267
320
  return ctx.mesh.nodes.find((n) => n.id === nodeId) ?? null;
268
321
  }
@@ -314,9 +367,26 @@ function buildMissingNodeReadChatRecovery(ctx, args) {
314
367
  readDebugLocator: readString(lastTerminal?.payload?.readDebugLocator) || readString(lastTerminal?.payload?.debugBundlePath)
315
368
  };
316
369
  if (finalSummary) {
370
+ if (args.compact === true) {
371
+ return {
372
+ ...compactChatPayload({
373
+ success: true,
374
+ status: "idle",
375
+ providerSessionId,
376
+ summary: finalSummary,
377
+ messages: [{ role: "assistant", content: finalSummary, isHistorical: true }]
378
+ }, {
379
+ nodeId: args.node_id,
380
+ sessionId: args.session_id,
381
+ limit: args.tail ?? 10
382
+ }),
383
+ recoveredFromLedger: true,
384
+ ledger
385
+ };
386
+ }
317
387
  return {
318
388
  success: true,
319
- compact: args.compact === true,
389
+ compact: false,
320
390
  recoveredFromLedger: true,
321
391
  nodeId: args.node_id,
322
392
  sessionId: args.session_id,
@@ -368,6 +438,14 @@ function buildMissingNodeReadChatRecovery(ctx, args) {
368
438
  function readSessionRecordId(session) {
369
439
  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
440
  }
441
+ function extractStatusMetadataSessions(value) {
442
+ const payload = unwrapCommandPayload(value);
443
+ const status = payload?.status && typeof payload.status === "object" ? payload.status : payload;
444
+ return Array.isArray(status?.sessions) ? status.sessions : [];
445
+ }
446
+ function resolveSessionProviderType(session) {
447
+ return readString(session?.providerType) || readString(session?.cliType) || readString(session?.agentType) || "";
448
+ }
371
449
  function addSessionRecord(target, session) {
372
450
  if (!session || typeof session !== "object" || isTerminalSessionRecord(session)) return;
373
451
  const sessionId = readSessionRecordId(session);
@@ -475,6 +553,18 @@ function filterQueueForView(queue, view, statuses) {
475
553
  if (view === "historical") return queue.filter((task) => HISTORICAL_QUEUE_STATUSES.has(String(task?.status || "")));
476
554
  return queue;
477
555
  }
556
+ function prioritizeActiveQueueRows(queue) {
557
+ const active = [];
558
+ const historical = [];
559
+ const other = [];
560
+ for (const task of queue) {
561
+ const status = String(task?.status || "");
562
+ if (ACTIVE_QUEUE_STATUSES.has(status)) active.push(task);
563
+ else if (HISTORICAL_QUEUE_STATUSES.has(status)) historical.push(task);
564
+ else other.push(task);
565
+ }
566
+ return [...active, ...other, ...historical];
567
+ }
478
568
  function slimQueueTask(task) {
479
569
  return {
480
570
  id: task?.id,
@@ -580,22 +670,59 @@ function isIdleSessionRecord(session) {
580
670
  const chatStatus = typeof session?.activeChat?.status === "string" ? session.activeChat.status.toLowerCase() : "";
581
671
  return status === "idle" || chatStatus === "waiting_input";
582
672
  }
673
+ function isMeshOwnedDelegateSession(session, meshId, nodeId) {
674
+ const settings = session?.settings;
675
+ const sessionMeshId = typeof settings?.meshNodeFor === "string" ? settings.meshNodeFor.trim() : "";
676
+ const coordinatorDaemonId = typeof settings?.meshCoordinatorDaemonId === "string" ? settings.meshCoordinatorDaemonId.trim() : "";
677
+ const sessionNodeId = typeof settings?.meshNodeId === "string" ? settings.meshNodeId.trim() : "";
678
+ if (sessionMeshId !== meshId || !coordinatorDaemonId) return false;
679
+ return !sessionNodeId || sessionNodeId === nodeId;
680
+ }
583
681
  function chooseDispatchableSession(sessions, providerType, meshId, nodeId) {
584
682
  const live = sessions.filter((session) => !isTerminalSessionRecord(session));
585
683
  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
684
  const meshSessions = live.filter(
595
- (session) => isMeshOwnedDelegateSession(session)
685
+ (session) => isMeshOwnedDelegateSession(session, meshId, nodeId)
596
686
  );
597
687
  return meshSessions.find((session) => isIdleSessionRecord(session) && matchingProvider(session)) || meshSessions.find(matchingProvider) || void 0;
598
688
  }
689
+ function buildRelayUnsafeRemoteSessionFailure(ctx, node, sessionId, providerType) {
690
+ return {
691
+ success: false,
692
+ recoverable: true,
693
+ code: "mesh_delegate_session_missing_relay_metadata",
694
+ reason: "mesh_delegate_session_missing_relay_metadata",
695
+ transport: "mesh_transport",
696
+ retryRecommended: true,
697
+ meshId: ctx.mesh.id,
698
+ nodeId: node.id,
699
+ daemonId: node.daemonId,
700
+ workspace: node.workspace,
701
+ sessionId,
702
+ ...providerType ? { resolvedProviderType: providerType } : {},
703
+ 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.`,
704
+ 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.`,
705
+ noFallbackReason: "Blindly reusing a remote session without mesh relay metadata would silently drop task_completed / generating_completed events."
706
+ };
707
+ }
708
+ function buildMissingCoordinatorDaemonIdFailure(ctx, node, providerType) {
709
+ return {
710
+ success: false,
711
+ recoverable: true,
712
+ code: "mesh_coordinator_daemon_unknown",
713
+ reason: "mesh_coordinator_daemon_unknown",
714
+ transport: "mesh_transport",
715
+ retryRecommended: true,
716
+ meshId: ctx.mesh.id,
717
+ nodeId: node.id,
718
+ daemonId: node.daemonId,
719
+ workspace: node.workspace,
720
+ ...providerType ? { resolvedProviderType: providerType } : {},
721
+ 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.`,
722
+ 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.",
723
+ noFallbackReason: "Launching without meshCoordinatorDaemonId would create a worker session that can finish work but cannot emit task_completed / generating_completed back to the coordinator."
724
+ };
725
+ }
599
726
  function findNestedPayload(value, predicate) {
600
727
  const seen = /* @__PURE__ */ new Set();
601
728
  const stack = [{ payload: value, depth: 0 }];
@@ -623,12 +750,16 @@ function extractGitDiff(value) {
623
750
  }
624
751
  function extractSubmodules(value, ignorePaths) {
625
752
  const payload = unwrapCommandPayload(value);
626
- const subs = payload?.submodules ?? value?.submodules;
753
+ const subs = payload?.status?.submodules ?? payload?.submodules ?? value?.status?.submodules ?? value?.submodules;
627
754
  if (!Array.isArray(subs)) return void 0;
628
755
  if (ignorePaths.length === 0) return subs;
629
756
  const ignoreSet = new Set(ignorePaths);
630
757
  return subs.filter((s) => s?.path && !ignoreSet.has(s.path));
631
758
  }
759
+ function assignFullGitSnapshot(entry, status) {
760
+ if (!status || typeof status !== "object" || Array.isArray(status)) return;
761
+ entry.git = status;
762
+ }
632
763
  function extractLaunchPayload(value) {
633
764
  return findNestedPayload(value, (payload) => Boolean(payload?.sessionId || payload?.id || payload?.runtimeSessionId));
634
765
  }
@@ -753,20 +884,63 @@ async function ipcDispatchToRemoteAgent(ctx, node, args) {
753
884
  let sessionId = args.session_id?.trim() || "";
754
885
  const providerPriorityList = Array.isArray(node.policy?.providerPriority) ? node.policy.providerPriority : [];
755
886
  let resolvedProviderType = args.providerType?.trim() || providerPriorityList[0] || "";
756
- if (!sessionId) {
887
+ if (!sessionId || args.session_id) {
757
888
  try {
758
889
  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;
890
+ const sessions = extractStatusMetadataSessions(relayResult);
891
+ if (sessionId) {
892
+ const explicitSession = sessions.find((session) => readSessionRecordId(session) === sessionId);
893
+ if (!explicitSession) {
894
+ return {
895
+ success: false,
896
+ recoverable: true,
897
+ code: "mesh_target_session_not_found",
898
+ reason: "mesh_target_session_not_found",
899
+ transport: "mesh_transport",
900
+ retryRecommended: true,
901
+ meshId: ctx.mesh.id,
902
+ nodeId: node.id,
903
+ daemonId,
904
+ workspace: node.workspace,
905
+ sessionId,
906
+ ...resolvedProviderType ? { resolvedProviderType } : {},
907
+ error: `Remote session '${sessionId}' is not present in the live status for node '${node.id}'.`,
908
+ 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.`
909
+ };
910
+ }
911
+ if (!isMeshOwnedDelegateSession(explicitSession, ctx.mesh.id, node.id)) {
912
+ return buildRelayUnsafeRemoteSessionFailure(
913
+ ctx,
914
+ node,
915
+ sessionId,
916
+ resolvedProviderType || resolveSessionProviderType(explicitSession) || void 0
917
+ );
918
+ }
765
919
  if (!resolvedProviderType) {
766
- resolvedProviderType = targetSession.providerType || targetSession.cliType || "";
920
+ resolvedProviderType = resolveSessionProviderType(explicitSession);
921
+ }
922
+ } else {
923
+ const targetSession = chooseDispatchableSession(sessions, resolvedProviderType, ctx.mesh.id, node.id);
924
+ if (targetSession?.id || targetSession?.sessionId) {
925
+ sessionId = targetSession.id || targetSession.sessionId;
926
+ if (!resolvedProviderType) {
927
+ resolvedProviderType = resolveSessionProviderType(targetSession);
928
+ }
767
929
  }
768
930
  }
769
931
  } catch (e) {
932
+ if (sessionId) {
933
+ return {
934
+ ...buildCoordinatorP2pRelayFailure(e, {
935
+ command: "get_status_metadata",
936
+ targetDaemonId: daemonId,
937
+ nodeId: node.id,
938
+ sessionId
939
+ }),
940
+ success: false,
941
+ error: `Cannot verify remote session '${sessionId}' before dispatch: ${e?.message || String(e)}`
942
+ };
943
+ }
770
944
  }
771
945
  }
772
946
  if (!resolvedProviderType) {
@@ -796,7 +970,7 @@ async function ipcDispatchToRemoteAgent(ctx, node, args) {
796
970
  error: `P2P dispatch failed: ${errorMessage}`
797
971
  };
798
972
  }
799
- return { success: true, dispatched: true, sessionId: sessionId || resolvedProviderType };
973
+ return { success: true, dispatched: true, sessionId: sessionId || resolvedProviderType, providerType: resolvedProviderType };
800
974
  } catch (e) {
801
975
  const errorMessage = e?.message || String(e);
802
976
  return {
@@ -880,6 +1054,10 @@ function summarizeRelatedRepoStatus(repo, status) {
880
1054
  workspace: repo.workspace,
881
1055
  isGitRepo: status?.isGitRepo === true,
882
1056
  branch: status?.branch ?? null,
1057
+ upstream: status?.upstream ?? null,
1058
+ upstreamStatus: typeof status?.upstreamStatus === "string" ? status.upstreamStatus : status?.upstream ? "unchecked" : "no_upstream",
1059
+ upstreamFetchedAt: Number.isFinite(Number(status?.upstreamFetchedAt)) ? Number(status.upstreamFetchedAt) : null,
1060
+ upstreamFetchError: typeof status?.upstreamFetchError === "string" ? status.upstreamFetchError : null,
883
1061
  ahead: Number.isFinite(Number(status?.ahead)) ? Number(status.ahead) : 0,
884
1062
  behind: Number.isFinite(Number(status?.behind)) ? Number(status.behind) : 0,
885
1063
  dirty,
@@ -896,7 +1074,7 @@ async function collectRelatedRepoStatuses(ctx, node) {
896
1074
  const results = [];
897
1075
  for (const repo of relatedRepos) {
898
1076
  try {
899
- const statusResult = !isLocalTransport(ctx.transport) && node.daemonId ? await ctx.transport.gitStatus(node.daemonId, repo.workspace, false) : await commandForNode(ctx, node, "git_status", { workspace: repo.workspace });
1077
+ const statusResult = !isLocalTransport(ctx.transport) && node.daemonId ? await ctx.transport.gitStatus(node.daemonId, repo.workspace, false, true) : await commandForNode(ctx, node, "git_status", { workspace: repo.workspace, refreshUpstream: true });
900
1078
  const status = extractGitStatus(statusResult);
901
1079
  results.push(summarizeRelatedRepoStatus(repo, status));
902
1080
  } catch (e) {
@@ -944,11 +1122,13 @@ function buildBranchConvergence(mesh, node, status, dirty, uncommittedChanges) {
944
1122
  const ahead = readNumeric(status?.ahead);
945
1123
  const behind = readNumeric(status?.behind);
946
1124
  const upstream = readString(status?.upstream) ?? null;
1125
+ const upstreamStatus = readString(status?.upstreamStatus) ?? (upstream ? "unchecked" : "no_upstream");
947
1126
  const hasConflicts = status?.hasConflicts === true || Array.isArray(status?.conflictFiles) && status.conflictFiles.length > 0;
948
1127
  const base = {
949
1128
  defaultBranch,
950
1129
  branch,
951
1130
  upstream,
1131
+ upstreamStatus,
952
1132
  ahead,
953
1133
  behind,
954
1134
  isWorktree: node.isLocalWorktree === true,
@@ -982,6 +1162,15 @@ function buildBranchConvergence(mesh, node, status, dirty, uncommittedChanges) {
982
1162
  };
983
1163
  }
984
1164
  if (branch === defaultBranch) {
1165
+ if (upstream && upstreamStatus !== "fresh") {
1166
+ return {
1167
+ ...base,
1168
+ status: "blocked_review",
1169
+ needsConvergence: true,
1170
+ reason: "default_branch_upstream_unverified",
1171
+ nextStep: `Refresh ${defaultBranch}'s upstream refs or resolve the fetch failure before declaring convergence complete for node '${node.id}'.`
1172
+ };
1173
+ }
985
1174
  if (ahead > 0 || behind > 0) {
986
1175
  return {
987
1176
  ...base,
@@ -1008,6 +1197,15 @@ function buildBranchConvergence(mesh, node, status, dirty, uncommittedChanges) {
1008
1197
  nextStep: `Run mesh_refine_node(node_id: "${node.id}") or explicitly classify this worktree as blocked_review/not_mergeable before ending the task.`
1009
1198
  };
1010
1199
  }
1200
+ if (upstream && upstreamStatus !== "fresh") {
1201
+ return {
1202
+ ...base,
1203
+ status: "blocked_review",
1204
+ needsConvergence: true,
1205
+ reason: "feature_branch_upstream_unverified",
1206
+ nextStep: `Refresh branch '${branch}' upstream refs or resolve the fetch failure before deciding whether it is ready to merge into ${defaultBranch}.`
1207
+ };
1208
+ }
1011
1209
  if (!upstream || ahead > 0 || behind > 0) {
1012
1210
  return {
1013
1211
  ...base,
@@ -1051,6 +1249,79 @@ async function commandForNode(ctx, node, command, args = {}) {
1051
1249
  }
1052
1250
  throw new Error(`Command '${command}' requires daemon IPC/local transport for node '${node.id}'`);
1053
1251
  }
1252
+ function normalizePendingMeshCoordinatorEvents(value) {
1253
+ const payload = unwrapCommandPayload(value);
1254
+ const events = Array.isArray(payload?.events) ? payload.events : Array.isArray(value?.events) ? value.events : [];
1255
+ return events.filter((event) => event && typeof event === "object");
1256
+ }
1257
+ function buildMeshForwardPayloadFromPendingEvent(event) {
1258
+ const metadataEvent = event?.metadataEvent && typeof event.metadataEvent === "object" ? event.metadataEvent : {};
1259
+ return {
1260
+ event: readString(event?.event),
1261
+ meshId: readString(event?.meshId),
1262
+ nodeId: readString(event?.nodeId) || readString(metadataEvent.meshNodeId),
1263
+ workspace: readString(event?.workspace) || readString(metadataEvent.workspace),
1264
+ targetSessionId: readString(metadataEvent.targetSessionId) || readString(metadataEvent.sessionId) || readString(metadataEvent.instanceId),
1265
+ providerType: readString(metadataEvent.providerType),
1266
+ providerSessionId: readString(metadataEvent.providerSessionId),
1267
+ finalSummary: readString(metadataEvent.finalSummary) || readString(metadataEvent.summary),
1268
+ jobId: readString(metadataEvent.jobId),
1269
+ interactionId: readString(metadataEvent.interactionId),
1270
+ status: readString(metadataEvent.status),
1271
+ targetDaemonId: readString(metadataEvent.targetDaemonId),
1272
+ startedAt: readString(metadataEvent.startedAt),
1273
+ completedAt: readString(metadataEvent.completedAt),
1274
+ retryOfJobId: readString(metadataEvent.retryOfJobId),
1275
+ ...metadataEvent.result && typeof metadataEvent.result === "object" && !Array.isArray(metadataEvent.result) ? { result: metadataEvent.result } : {},
1276
+ ...metadataEvent.intentional === true ? { intentional: true } : {},
1277
+ ...metadataEvent.intentionalStop === true ? { intentionalStop: true } : {},
1278
+ ...metadataEvent.operatorCleanup === true ? { operatorCleanup: true } : {},
1279
+ ...readString(metadataEvent.reason) ? { reason: readString(metadataEvent.reason) } : {},
1280
+ ...readString(metadataEvent.stopReason) ? { stopReason: readString(metadataEvent.stopReason) } : {},
1281
+ ...readString(metadataEvent.cleanupReason) ? { cleanupReason: readString(metadataEvent.cleanupReason) } : {},
1282
+ ...readString(metadataEvent.source) ? { source: readString(metadataEvent.source) } : {}
1283
+ };
1284
+ }
1285
+ async function drainCoordinatorPendingEvents(ctx, opts) {
1286
+ const requestedNodeIds = opts?.nodeIds?.length ? new Set(opts.nodeIds) : null;
1287
+ const matchesCurrentMesh = (event) => readString(event?.meshId) === ctx.mesh.id;
1288
+ if (ctx.transport instanceof IpcTransport) {
1289
+ const surfacedEvents = [];
1290
+ try {
1291
+ surfacedEvents.push(
1292
+ ...normalizePendingMeshCoordinatorEvents(await ctx.transport.command("get_pending_mesh_events", { meshId: ctx.mesh.id })).filter(matchesCurrentMesh)
1293
+ );
1294
+ } catch {
1295
+ }
1296
+ for (const node of ctx.mesh.nodes) {
1297
+ if (!node.daemonId || isLocalControlPlaneNode(ctx, node)) continue;
1298
+ if (requestedNodeIds && !requestedNodeIds.has(node.id)) continue;
1299
+ try {
1300
+ const remoteEvents = normalizePendingMeshCoordinatorEvents(
1301
+ await ctx.transport.meshCommand(node.daemonId, "get_pending_mesh_events", { meshId: ctx.mesh.id })
1302
+ ).filter(matchesCurrentMesh);
1303
+ if (remoteEvents.length === 0) continue;
1304
+ for (const event of remoteEvents) {
1305
+ const payload = buildMeshForwardPayloadFromPendingEvent(event);
1306
+ if (!payload.event || !payload.meshId) continue;
1307
+ await ctx.transport.command("mesh_forward_event", payload);
1308
+ }
1309
+ } catch {
1310
+ }
1311
+ }
1312
+ try {
1313
+ surfacedEvents.push(
1314
+ ...normalizePendingMeshCoordinatorEvents(await ctx.transport.command("get_pending_mesh_events", { meshId: ctx.mesh.id })).filter(matchesCurrentMesh)
1315
+ );
1316
+ } catch {
1317
+ }
1318
+ return surfacedEvents;
1319
+ }
1320
+ if (isLocalTransport(ctx.transport)) {
1321
+ return (0, import_daemon_core.drainPendingMeshCoordinatorEvents)(ctx.mesh.id).filter(matchesCurrentMesh);
1322
+ }
1323
+ return [];
1324
+ }
1054
1325
  function isP2pTransportUnavailableError(error) {
1055
1326
  return (0, import_daemon_core.isP2pRelayTransportFailure)(error);
1056
1327
  }
@@ -1088,7 +1359,9 @@ var MESH_ENQUEUE_TASK_TOOL = {
1088
1359
  inputSchema: {
1089
1360
  type: "object",
1090
1361
  properties: {
1091
- message: { type: "string", description: "The task instruction for the agent." }
1362
+ message: { type: "string", description: "The task instruction for the agent." },
1363
+ 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." },
1364
+ taskMode: { type: "string", enum: ["code_change", "validation", "live_debug_readonly", "launch_app", "convergence"], description: "CamelCase alias for task_mode." }
1092
1365
  },
1093
1366
  required: ["message"]
1094
1367
  }
@@ -1148,7 +1421,9 @@ var MESH_SEND_TASK_TOOL = {
1148
1421
  properties: {
1149
1422
  node_id: { type: "string", description: "Target node ID (from mesh_list_nodes)." },
1150
1423
  session_id: { type: "string", description: "Agent session ID on the target node." },
1151
- message: { type: "string", description: "Natural-language task to send to the agent." }
1424
+ message: { type: "string", description: "Natural-language task to send to the agent." },
1425
+ 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." },
1426
+ taskMode: { type: "string", enum: ["code_change", "validation", "live_debug_readonly", "launch_app", "convergence"], description: "CamelCase alias for task_mode." }
1152
1427
  },
1153
1428
  required: ["node_id", "session_id", "message"]
1154
1429
  }
@@ -1206,6 +1481,21 @@ var MESH_GIT_STATUS_TOOL = {
1206
1481
  required: ["node_id"]
1207
1482
  }
1208
1483
  };
1484
+ var MESH_FAST_FORWARD_NODE_TOOL = {
1485
+ name: "mesh_fast_forward_node",
1486
+ 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.",
1487
+ inputSchema: {
1488
+ type: "object",
1489
+ properties: {
1490
+ node_id: { type: "string", description: "Target node ID." },
1491
+ branch: { type: "string", description: "Optional guard: require the node's current branch to match this branch before planning/executing." },
1492
+ execute: { type: "boolean", description: "When true, apply the fast-forward if all safety gates pass. Defaults false/dry-run." },
1493
+ dry_run: { type: "boolean", description: "Preview only. Defaults true unless execute=true; dry_run=true overrides execute." },
1494
+ 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." }
1495
+ },
1496
+ required: ["node_id"]
1497
+ }
1498
+ };
1209
1499
  var MESH_CHECKPOINT_TOOL = {
1210
1500
  name: "mesh_checkpoint",
1211
1501
  description: "Create a git checkpoint (commit) on a mesh node workspace.",
@@ -1289,7 +1579,7 @@ var MESH_TASK_HISTORY_TOOL = {
1289
1579
  type: "object",
1290
1580
  properties: {
1291
1581
  tail: { type: "number", description: "Number of recent entries to return (default: 20)." },
1292
- kind: { type: "string", description: "Filter by entry kind: task_dispatched, task_completed, task_failed, task_stalled, session_launched, checkpoint_created, node_cloned, node_removed." }
1582
+ 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." }
1293
1583
  }
1294
1584
  }
1295
1585
  };
@@ -1309,7 +1599,7 @@ var MESH_RECONCILE_LEDGER_TOOL = {
1309
1599
  };
1310
1600
  var MESH_REFINE_NODE_TOOL = {
1311
1601
  name: "mesh_refine_node",
1312
- 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.",
1602
+ 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.",
1313
1603
  inputSchema: {
1314
1604
  type: "object",
1315
1605
  properties: {
@@ -1318,6 +1608,43 @@ var MESH_REFINE_NODE_TOOL = {
1318
1608
  required: ["node_id"]
1319
1609
  }
1320
1610
  };
1611
+ var MESH_REFINE_CONFIG_SCHEMA_TOOL = {
1612
+ name: "mesh_refine_config_schema",
1613
+ 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.",
1614
+ inputSchema: { type: "object", properties: {} }
1615
+ };
1616
+ var MESH_VALIDATE_REFINE_CONFIG_TOOL = {
1617
+ name: "mesh_validate_refine_config",
1618
+ description: "Validate the repo mesh/refine config for a node/workspace without running validation commands or merging.",
1619
+ inputSchema: {
1620
+ type: "object",
1621
+ properties: {
1622
+ node_id: { type: "string", description: "Optional node/workspace whose refine config should be loaded. Defaults to the first mesh node." },
1623
+ config: { type: "object", description: "Optional inline config object to validate instead of loading from the repo." }
1624
+ }
1625
+ }
1626
+ };
1627
+ var MESH_SUGGEST_REFINE_CONFIG_TOOL = {
1628
+ name: "mesh_suggest_refine_config",
1629
+ description: "Suggest a repo mesh/refine config scaffold from project context/package scripts. Suggestions are never executed until saved as explicit refine config.",
1630
+ inputSchema: {
1631
+ type: "object",
1632
+ properties: {
1633
+ node_id: { type: "string", description: "Optional node/workspace used for suggestions. Defaults to the first mesh node." }
1634
+ }
1635
+ }
1636
+ };
1637
+ var MESH_REFINE_PLAN_TOOL = {
1638
+ name: "mesh_refine_plan",
1639
+ 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.",
1640
+ inputSchema: {
1641
+ type: "object",
1642
+ properties: {
1643
+ node_id: { type: "string", description: "Node ID of the worktree node to plan." }
1644
+ },
1645
+ required: ["node_id"]
1646
+ }
1647
+ };
1321
1648
  var ALL_MESH_TOOLS = [
1322
1649
  MESH_STATUS_TOOL,
1323
1650
  MESH_LIST_NODES_TOOL,
@@ -1330,11 +1657,16 @@ var ALL_MESH_TOOLS = [
1330
1657
  MESH_READ_DEBUG_TOOL,
1331
1658
  MESH_LAUNCH_SESSION_TOOL,
1332
1659
  MESH_GIT_STATUS_TOOL,
1660
+ MESH_FAST_FORWARD_NODE_TOOL,
1333
1661
  MESH_CHECKPOINT_TOOL,
1334
1662
  MESH_APPROVE_TOOL,
1335
1663
  MESH_CLONE_NODE_TOOL,
1336
1664
  MESH_REMOVE_NODE_TOOL,
1337
1665
  MESH_REFINE_NODE_TOOL,
1666
+ MESH_REFINE_CONFIG_SCHEMA_TOOL,
1667
+ MESH_VALIDATE_REFINE_CONFIG_TOOL,
1668
+ MESH_SUGGEST_REFINE_CONFIG_TOOL,
1669
+ MESH_REFINE_PLAN_TOOL,
1338
1670
  MESH_CLEANUP_SESSIONS_TOOL,
1339
1671
  MESH_TASK_HISTORY_TOOL,
1340
1672
  MESH_RECONCILE_LEDGER_TOOL
@@ -1352,11 +1684,12 @@ async function meshStatus(ctx) {
1352
1684
  };
1353
1685
  try {
1354
1686
  if (!isLocalTransport(transport) && node.daemonId) {
1355
- const result = await transport.gitStatus(node.daemonId, node.workspace, false);
1687
+ const result = await transport.gitStatus(node.daemonId, node.workspace, false, true);
1356
1688
  const status = extractGitStatus(result);
1357
1689
  const uncommittedChanges = countUncommittedChanges(status);
1358
1690
  const dirty = isGitStatusDirty(status);
1359
1691
  entry.health = status?.isGitRepo ? dirty ? "dirty" : "online" : "degraded";
1692
+ assignFullGitSnapshot(entry, status);
1360
1693
  entry.branch = status?.branch;
1361
1694
  entry.isDirty = dirty;
1362
1695
  entry.uncommittedChanges = uncommittedChanges;
@@ -1370,6 +1703,7 @@ async function meshStatus(ctx) {
1370
1703
  const autoDiscover = node.policy?.autoDiscoverSubmodules !== false;
1371
1704
  const statusResult = await commandForNode(ctx, node, "git_status", {
1372
1705
  workspace: node.workspace,
1706
+ refreshUpstream: true,
1373
1707
  includeSubmodules: autoDiscover,
1374
1708
  submoduleIgnorePaths: node.policy?.submoduleIgnorePaths || void 0
1375
1709
  });
@@ -1377,6 +1711,7 @@ async function meshStatus(ctx) {
1377
1711
  const uncommittedChanges = countUncommittedChanges(status);
1378
1712
  const dirty = isGitStatusDirty(status);
1379
1713
  entry.health = status?.isGitRepo ? dirty ? "dirty" : "online" : "degraded";
1714
+ assignFullGitSnapshot(entry, status);
1380
1715
  entry.branch = status?.branch;
1381
1716
  entry.isDirty = dirty;
1382
1717
  entry.uncommittedChanges = uncommittedChanges;
@@ -1454,13 +1789,27 @@ async function meshStatus(ctx) {
1454
1789
  if (relatedRepos.length) entry.relatedRepos = relatedRepos;
1455
1790
  results.push(entry);
1456
1791
  }
1792
+ const activeWorkEvidence = (0, import_daemon_core.buildMeshActiveWork)({
1793
+ meshId: mesh.id,
1794
+ queue: (0, import_daemon_core.getQueue)(mesh.id),
1795
+ ledgerEntries: (0, import_daemon_core.readLedgerEntries)(mesh.id, { tail: 500 }),
1796
+ nodes: mesh.nodes
1797
+ });
1457
1798
  const response = {
1458
1799
  meshId: mesh.id,
1459
1800
  meshName: mesh.name,
1460
1801
  repoIdentity: mesh.repoIdentity,
1461
1802
  policy: mesh.policy,
1462
1803
  refreshedAt: (/* @__PURE__ */ new Date()).toISOString(),
1804
+ sourceOfTruth: {
1805
+ membership: "coordinator_daemon_live_mesh",
1806
+ currentStatus: "live_git_and_session_probes",
1807
+ activeWork: "mesh_queue_file_and_local_ledger",
1808
+ historicalEvidenceOnly: ["recoveryHints", "ledgerSummary"]
1809
+ },
1463
1810
  nodes: results,
1811
+ activeWork: activeWorkEvidence.activeWork,
1812
+ activeWorkSummary: activeWorkEvidence.summary,
1464
1813
  branchConvergenceSummary: summarizeBranchConvergence(results)
1465
1814
  };
1466
1815
  try {
@@ -1468,13 +1817,7 @@ async function meshStatus(ctx) {
1468
1817
  } catch {
1469
1818
  }
1470
1819
  try {
1471
- let pendingEvents = [];
1472
- if (ctx.transport instanceof IpcTransport) {
1473
- const eventsResult = await ctx.transport.command("get_pending_mesh_events", {});
1474
- pendingEvents = Array.isArray(eventsResult?.events) ? eventsResult.events : [];
1475
- } else if (isLocalTransport(ctx.transport)) {
1476
- pendingEvents = (0, import_daemon_core.drainPendingMeshCoordinatorEvents)();
1477
- }
1820
+ const pendingEvents = await drainCoordinatorPendingEvents(ctx);
1478
1821
  if (pendingEvents.length > 0) {
1479
1822
  response.pendingCoordinatorEvents = pendingEvents;
1480
1823
  }
@@ -1484,6 +1827,7 @@ async function meshStatus(ctx) {
1484
1827
  }
1485
1828
  async function meshTaskHistory(ctx, args) {
1486
1829
  const { mesh } = ctx;
1830
+ await drainCoordinatorPendingEvents(ctx);
1487
1831
  const tail = typeof args.tail === "number" && args.tail > 0 ? args.tail : 20;
1488
1832
  const kind = typeof args.kind === "string" && args.kind.trim() ? [args.kind.trim()] : void 0;
1489
1833
  const entries = (0, import_daemon_core.readLedgerEntries)(mesh.id, { tail, kind });
@@ -1587,12 +1931,13 @@ async function meshListNodes(ctx) {
1587
1931
  }, null, 2);
1588
1932
  }
1589
1933
  async function meshEnqueueTask(ctx, args) {
1934
+ const taskMode = readString(args.task_mode) || readString(args.taskMode);
1590
1935
  try {
1591
- const task = (0, import_daemon_core.enqueueTask)(ctx.mesh.id, args.message);
1936
+ const task = (0, import_daemon_core.enqueueTask)(ctx.mesh.id, args.message, { taskMode });
1592
1937
  if (isLocalTransport(ctx.transport) && !(ctx.transport instanceof IpcTransport)) {
1593
1938
  ctx.transport.command("trigger_mesh_queue", { meshId: ctx.mesh.id }).catch(() => {
1594
1939
  });
1595
- return JSON.stringify({ success: true, taskId: task.id, status: task.status });
1940
+ return JSON.stringify({ success: true, source: "queue", taskId: task.id, status: task.status, taskMode: task.taskMode });
1596
1941
  }
1597
1942
  if (ctx.transport instanceof IpcTransport) {
1598
1943
  ctx.transport.command("trigger_mesh_queue", { meshId: ctx.mesh.id }).catch(() => {
@@ -1605,11 +1950,24 @@ async function meshEnqueueTask(ctx, args) {
1605
1950
  ipcDispatchToRemoteAgent(ctx, node, { message: args.message }).then((result) => {
1606
1951
  if (result.success) {
1607
1952
  try {
1953
+ const providerType = result.providerType;
1954
+ const descriptor = summarizeTaskMessage(args.message);
1608
1955
  (0, import_daemon_core.appendLedgerEntry)(ctx.mesh.id, {
1609
1956
  kind: "task_dispatched",
1610
1957
  nodeId: node.id,
1611
1958
  sessionId: result.sessionId,
1612
- payload: { message: args.message, via: "p2p_direct", taskId: task.id }
1959
+ providerType,
1960
+ payload: {
1961
+ source: "queue",
1962
+ via: "p2p_direct",
1963
+ taskId: task.id,
1964
+ message: args.message,
1965
+ taskTitle: descriptor.taskTitle,
1966
+ taskSummary: descriptor.taskSummary,
1967
+ ...task.taskMode ? { taskMode: task.taskMode } : {},
1968
+ ...providerType ? { providerType } : {},
1969
+ targetSessionId: result.sessionId
1970
+ }
1613
1971
  });
1614
1972
  } catch {
1615
1973
  }
@@ -1620,22 +1978,32 @@ async function meshEnqueueTask(ctx, args) {
1620
1978
  }
1621
1979
  Promise.all(dispatchPromises).catch(() => {
1622
1980
  });
1623
- return JSON.stringify({ success: true, taskId: task.id, status: task.status });
1981
+ return JSON.stringify({ success: true, source: "queue", taskId: task.id, status: task.status, taskMode: task.taskMode });
1624
1982
  }
1625
- return JSON.stringify({ success: true, taskId: task.id, status: task.status });
1983
+ return JSON.stringify({ success: true, source: "queue", taskId: task.id, status: task.status, taskMode: task.taskMode });
1626
1984
  } catch (e) {
1627
- return JSON.stringify({ success: false, error: e.message });
1985
+ const message = e?.message || String(e);
1986
+ if (message.includes("live_debug_readonly_guardrail_violation")) {
1987
+ return JSON.stringify({ success: false, code: "live_debug_readonly_guardrail_violation", taskMode, error: message });
1988
+ }
1989
+ return JSON.stringify({ success: false, error: message });
1628
1990
  }
1629
1991
  }
1630
1992
  async function meshViewQueue(ctx, args) {
1631
1993
  try {
1632
1994
  const statusFilter = sanitizeQueueStatusFilter(args.status);
1633
1995
  const view = normalizeQueueViewMode(args.view);
1634
- const fullQueue = annotateQueueStaleness((0, import_daemon_core.getQueue)(ctx.mesh.id), ctx.mesh);
1996
+ const fullQueue = prioritizeActiveQueueRows(annotateQueueStaleness((0, import_daemon_core.getQueue)(ctx.mesh.id), ctx.mesh));
1635
1997
  const queue = filterQueueForView(fullQueue, view, statusFilter);
1636
1998
  const summary = buildQueueStatusSummary(fullQueue);
1637
1999
  const visibleSummary = buildQueueStatusSummary(queue);
1638
2000
  const maintenance = buildQueueMaintenanceReport(fullQueue);
2001
+ const activeWorkEvidence = (0, import_daemon_core.buildMeshActiveWork)({
2002
+ meshId: ctx.mesh.id,
2003
+ queue: fullQueue,
2004
+ ledgerEntries: (0, import_daemon_core.readLedgerEntries)(ctx.mesh.id, { tail: 500 }),
2005
+ nodes: ctx.mesh.nodes
2006
+ });
1639
2007
  const staleAssignedTasks = maintenance.staleAssignedTasks || [];
1640
2008
  const requestedHistoricalRows = queue.some((task) => HISTORICAL_QUEUE_STATUSES.has(String(task?.status || "")));
1641
2009
  return JSON.stringify({
@@ -1653,6 +2021,8 @@ async function meshViewQueue(ctx, args) {
1653
2021
  },
1654
2022
  queue,
1655
2023
  visibleQueue: queue,
2024
+ activeWork: activeWorkEvidence.activeWork,
2025
+ activeWorkSummary: activeWorkEvidence.summary,
1656
2026
  visibleSummary,
1657
2027
  summary,
1658
2028
  activeCounts: summary.activeCounts,
@@ -1686,6 +2056,10 @@ async function meshQueueCancel(ctx, args) {
1686
2056
  if (!taskId) return JSON.stringify({ success: false, error: "task_id required" });
1687
2057
  const task = (0, import_daemon_core.cancelTask)(ctx.mesh.id, taskId, { reason: args.reason });
1688
2058
  if (!task) return JSON.stringify({ success: false, error: `Queue task '${taskId}' not found` });
2059
+ if (isLocalTransport(ctx.transport)) {
2060
+ ctx.transport.command("trigger_mesh_queue", { meshId: ctx.mesh.id }).catch(() => {
2061
+ });
2062
+ }
1689
2063
  return JSON.stringify({ success: true, task }, null, 2);
1690
2064
  } catch (e) {
1691
2065
  return JSON.stringify({ success: false, error: e.message });
@@ -1716,6 +2090,19 @@ async function meshQueueRequeue(ctx, args) {
1716
2090
  }
1717
2091
  }
1718
2092
  async function meshSendTask(ctx, args) {
2093
+ const requestedTaskMode = readString(args.task_mode) || readString(args.taskMode);
2094
+ const modeValidation = (0, import_daemon_core.validateMeshTaskModeRequest)(requestedTaskMode, args.message);
2095
+ if (!modeValidation.valid) {
2096
+ return JSON.stringify({
2097
+ success: false,
2098
+ code: "live_debug_readonly_guardrail_violation",
2099
+ taskMode: modeValidation.taskMode || requestedTaskMode,
2100
+ violations: modeValidation.violations,
2101
+ allowedOperations: modeValidation.allowedOperations,
2102
+ error: `live_debug_readonly_guardrail_violation: forbidden operations (${modeValidation.violations.join(", ")})`
2103
+ });
2104
+ }
2105
+ const taskMode = modeValidation.taskMode;
1719
2106
  const node = await findNodeWithRefresh(ctx, args.node_id);
1720
2107
  if (node.policy?.readOnly) {
1721
2108
  return JSON.stringify({ error: `Node '${args.node_id}' is read-only` });
@@ -1743,13 +2130,15 @@ async function meshSendTask(ctx, args) {
1743
2130
  const res = await ctx.transport.meshEnqueueTask(node.daemonId, {
1744
2131
  meshId: ctx.mesh.id,
1745
2132
  message: args.message,
1746
- targetNodeId: args.node_id
2133
+ targetNodeId: args.node_id,
2134
+ ...taskMode ? { taskMode } : {}
1747
2135
  });
1748
2136
  return JSON.stringify(res);
1749
2137
  }
1750
2138
  const isLocalNode = isLocalControlPlaneNode(ctx, node);
1751
2139
  if (ctx.transport instanceof IpcTransport && node.daemonId && !isLocalNode) {
1752
2140
  const cached = meshSessionProviderMetadata.get(meshSessionCacheKey(args.node_id, args.session_id || ""));
2141
+ const taskId = (0, import_node_crypto.randomUUID)();
1753
2142
  const result2 = await ipcDispatchToRemoteAgent(ctx, node, {
1754
2143
  session_id: args.session_id,
1755
2144
  message: args.message,
@@ -1758,60 +2147,123 @@ async function meshSendTask(ctx, args) {
1758
2147
  if (result2.success) {
1759
2148
  const dispatchedSessionId = args.session_id || result2.sessionId;
1760
2149
  try {
2150
+ const providerType = result2.providerType || cached?.providerType;
1761
2151
  (0, import_daemon_core.appendLedgerEntry)(ctx.mesh.id, {
1762
2152
  kind: "task_dispatched",
1763
2153
  nodeId: args.node_id,
1764
2154
  sessionId: dispatchedSessionId,
1765
- payload: {
1766
- message: args.message,
1767
- via: "p2p_direct",
1768
- ...dispatchedSessionId ? { targetSessionId: dispatchedSessionId } : {}
1769
- }
2155
+ providerType,
2156
+ payload: buildDirectTaskPayload(args.message, "p2p_direct", {
2157
+ taskId,
2158
+ taskMode,
2159
+ providerType,
2160
+ targetSessionId: dispatchedSessionId
2161
+ })
1770
2162
  });
1771
2163
  } catch {
1772
2164
  }
1773
2165
  }
1774
- return JSON.stringify({ ...result2, nodeId: args.node_id, dispatched: result2.success === true });
2166
+ return JSON.stringify({
2167
+ ...result2,
2168
+ nodeId: args.node_id,
2169
+ sessionId: result2.success ? args.session_id || result2.sessionId : args.session_id,
2170
+ ...result2.success ? { source: "direct", taskId } : {},
2171
+ taskMode,
2172
+ ...result2.success && result2.providerType ? { providerType: result2.providerType } : {},
2173
+ dispatched: result2.success === true
2174
+ });
1775
2175
  }
1776
2176
  if (args.session_id && isLocalTransport(ctx.transport)) {
1777
2177
  const cached = meshSessionProviderMetadata.get(meshSessionCacheKey(args.node_id, args.session_id));
2178
+ let resolvedProviderType = cached?.providerType || "";
2179
+ if (!resolvedProviderType) {
2180
+ const statusResult = await commandForNode(ctx, node, "get_status_metadata", {});
2181
+ const sessions = extractStatusMetadataSessions(statusResult);
2182
+ const explicitSession = sessions.find((session) => readSessionRecordId(session) === args.session_id);
2183
+ if (!explicitSession) {
2184
+ return JSON.stringify({
2185
+ success: false,
2186
+ recoverable: true,
2187
+ code: "mesh_target_session_not_found",
2188
+ reason: "mesh_target_session_not_found",
2189
+ transport: "local_ipc",
2190
+ retryRecommended: true,
2191
+ nodeId: args.node_id,
2192
+ sessionId: args.session_id,
2193
+ error: `Local session '${args.session_id}' is not present in live status for node '${args.node_id}'.`,
2194
+ 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.`
2195
+ });
2196
+ }
2197
+ resolvedProviderType = resolveSessionProviderType(explicitSession);
2198
+ if (resolvedProviderType) {
2199
+ meshSessionProviderMetadata.set(meshSessionCacheKey(args.node_id, args.session_id), {
2200
+ providerType: resolvedProviderType,
2201
+ providerSessionId: readString(explicitSession?.providerSessionId) || void 0
2202
+ });
2203
+ }
2204
+ }
2205
+ if (!resolvedProviderType) {
2206
+ return JSON.stringify({
2207
+ success: false,
2208
+ recoverable: true,
2209
+ code: "mesh_target_session_provider_unknown",
2210
+ reason: "mesh_target_session_provider_unknown",
2211
+ transport: "local_ipc",
2212
+ retryRecommended: false,
2213
+ nodeId: args.node_id,
2214
+ sessionId: args.session_id,
2215
+ error: `Local session '${args.session_id}' is live but does not expose providerType/cliType, so agent_command cannot be routed safely.`,
2216
+ 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.`
2217
+ });
2218
+ }
1778
2219
  const dispatchResult = await commandForNode(ctx, node, "agent_command", {
1779
2220
  targetSessionId: args.session_id,
1780
- ...cached?.providerType ? { agentType: cached.providerType, cliType: cached.providerType, providerType: cached.providerType } : {},
2221
+ agentType: resolvedProviderType,
2222
+ cliType: resolvedProviderType,
2223
+ providerType: resolvedProviderType,
1781
2224
  action: "send_chat",
1782
2225
  message: args.message
1783
2226
  });
1784
2227
  const dispatchPayload = unwrapCommandPayload(dispatchResult);
1785
2228
  if (dispatchPayload?.success === false || dispatchResult?.success === false) {
2229
+ const source = dispatchPayload?.success === false ? dispatchPayload : dispatchResult;
1786
2230
  return JSON.stringify({
2231
+ ...source && typeof source === "object" ? source : {},
1787
2232
  success: false,
1788
2233
  nodeId: args.node_id,
1789
2234
  sessionId: args.session_id,
1790
2235
  error: dispatchPayload?.error || dispatchResult?.error || "agent_command rejected the task"
1791
2236
  });
1792
2237
  }
2238
+ const taskId = (0, import_node_crypto.randomUUID)();
1793
2239
  try {
1794
2240
  (0, import_daemon_core.appendLedgerEntry)(ctx.mesh.id, {
1795
2241
  kind: "task_dispatched",
1796
2242
  nodeId: args.node_id,
1797
2243
  sessionId: args.session_id,
1798
- providerType: cached?.providerType,
1799
- payload: { message: args.message, via: "local_direct" }
2244
+ providerType: resolvedProviderType,
2245
+ payload: buildDirectTaskPayload(args.message, "local_direct", {
2246
+ taskId,
2247
+ taskMode,
2248
+ providerType: resolvedProviderType,
2249
+ targetSessionId: args.session_id
2250
+ })
1800
2251
  });
1801
2252
  } catch {
1802
2253
  }
1803
- return JSON.stringify({ success: true, dispatched: true, nodeId: args.node_id, sessionId: args.session_id });
2254
+ return JSON.stringify({ success: true, dispatched: true, source: "direct", taskId, taskMode, providerType: resolvedProviderType, nodeId: args.node_id, sessionId: args.session_id });
1804
2255
  }
1805
2256
  const task = (0, import_daemon_core.enqueueTask)(ctx.mesh.id, args.message, {
1806
2257
  targetNodeId: args.node_id,
1807
- targetSessionId: args.session_id
2258
+ targetSessionId: args.session_id,
2259
+ taskMode
1808
2260
  });
1809
2261
  if (isLocalTransport(ctx.transport) || ctx.transport instanceof IpcTransport) {
1810
2262
  ctx.transport.command("trigger_mesh_queue", { meshId: ctx.mesh.id }).catch(() => {
1811
2263
  });
1812
2264
  }
1813
- const pendingEvents = isLocalTransport(ctx.transport) ? (0, import_daemon_core.drainPendingMeshCoordinatorEvents)() : [];
1814
- const result = { success: true, nodeId: args.node_id, taskId: task.id, status: task.status };
2265
+ const pendingEvents = isLocalTransport(ctx.transport) ? (0, import_daemon_core.drainPendingMeshCoordinatorEvents)(ctx.mesh.id) : [];
2266
+ const result = { success: true, source: "queue", nodeId: args.node_id, taskId: task.id, status: task.status, taskMode: task.taskMode };
1815
2267
  if (pendingEvents.length > 0) {
1816
2268
  result.pendingCoordinatorEvents = pendingEvents;
1817
2269
  }
@@ -1831,6 +2283,9 @@ async function meshReadChat(ctx, args) {
1831
2283
  if (!node) {
1832
2284
  return JSON.stringify(buildMissingNodeReadChatRecovery(ctx, args), null, 2);
1833
2285
  }
2286
+ if (ctx.transport instanceof IpcTransport || isLocalTransport(ctx.transport)) {
2287
+ await drainCoordinatorPendingEvents(ctx, { nodeIds: [args.node_id] });
2288
+ }
1834
2289
  if (isLocalTransport(ctx.transport)) {
1835
2290
  const cached = meshSessionProviderMetadata.get(meshSessionCacheKey(args.node_id, args.session_id));
1836
2291
  const providerSessionId = typeof args.provider_session_id === "string" && args.provider_session_id.trim() ? args.provider_session_id.trim() : cached?.providerSessionId;
@@ -1933,6 +2388,10 @@ async function meshLaunchSession(ctx, args) {
1933
2388
  const coordinatorNode = resolveCoordinatorNode(ctx);
1934
2389
  const coordinatorDaemonId = coordinatorNode?.daemonId || ctx.localDaemonId;
1935
2390
  const spawnedSessionVisibility = readSpawnedSessionVisibility(ctx.mesh.policy);
2391
+ const isLocalNode = isLocalControlPlaneNode(ctx, node);
2392
+ if (node.daemonId && !isLocalNode && !coordinatorDaemonId) {
2393
+ return JSON.stringify(buildMissingCoordinatorDaemonIdFailure(ctx, node, resolvedProviderType), null, 2);
2394
+ }
1936
2395
  let result;
1937
2396
  try {
1938
2397
  result = await commandForNode(ctx, node, "launch_cli", {
@@ -1973,7 +2432,6 @@ async function meshLaunchSession(ctx, args) {
1973
2432
  });
1974
2433
  } catch {
1975
2434
  }
1976
- const isLocalNode = isLocalControlPlaneNode(ctx, node);
1977
2435
  if (ctx.transport instanceof IpcTransport && node.daemonId && !isLocalNode) {
1978
2436
  ctx.transport.meshCommand(node.daemonId, "trigger_mesh_queue", { meshId: ctx.mesh.id }).catch(() => {
1979
2437
  });
@@ -1998,6 +2456,9 @@ async function meshLaunchSession(ctx, args) {
1998
2456
  const coordinatorNode = resolveCoordinatorNode(ctx);
1999
2457
  const coordinatorDaemonId = coordinatorNode?.daemonId || ctx.localDaemonId;
2000
2458
  const spawnedSessionVisibility = readSpawnedSessionVisibility(ctx.mesh.policy);
2459
+ if (!coordinatorDaemonId) {
2460
+ return JSON.stringify(buildMissingCoordinatorDaemonIdFailure(ctx, node, resolvedProviderType), null, 2);
2461
+ }
2001
2462
  try {
2002
2463
  const res = await ctx.transport.launch(node.daemonId, {
2003
2464
  type: resolvedProviderType,
@@ -2036,7 +2497,7 @@ async function meshGitStatus(ctx, args) {
2036
2497
  const submoduleIgnorePaths = node.policy?.submoduleIgnorePaths || [];
2037
2498
  try {
2038
2499
  if (!isLocalTransport(ctx.transport) && node.daemonId) {
2039
- const result = await ctx.transport.gitStatus(node.daemonId, node.workspace, true);
2500
+ const result = await ctx.transport.gitStatus(node.daemonId, node.workspace, true, true);
2040
2501
  return JSON.stringify({
2041
2502
  nodeId: args.node_id,
2042
2503
  workspace: node.workspace,
@@ -2048,6 +2509,7 @@ async function meshGitStatus(ctx, args) {
2048
2509
  } else if (isLocalTransport(ctx.transport)) {
2049
2510
  const statusResult = await commandForNode(ctx, node, "git_status", {
2050
2511
  workspace: node.workspace,
2512
+ refreshUpstream: true,
2051
2513
  includeSubmodules: autoDiscoverSubmodules,
2052
2514
  submoduleIgnorePaths: submoduleIgnorePaths.length > 0 ? submoduleIgnorePaths : void 0
2053
2515
  });
@@ -2077,6 +2539,51 @@ async function meshGitStatus(ctx, args) {
2077
2539
  }, null, 2);
2078
2540
  }
2079
2541
  }
2542
+ async function meshFastForwardNode(ctx, args) {
2543
+ await refreshMeshFromDaemon(ctx);
2544
+ const node = await findNodeWithRefresh(ctx, args.node_id);
2545
+ const submoduleIgnorePaths = node.policy?.submoduleIgnorePaths || [];
2546
+ if (node.policy?.readOnly) {
2547
+ return JSON.stringify({
2548
+ success: false,
2549
+ code: "node_read_only",
2550
+ nodeId: args.node_id,
2551
+ workspace: node.workspace,
2552
+ allowed: false,
2553
+ willRun: false,
2554
+ executed: false,
2555
+ blockingReasons: ["node_read_only"]
2556
+ }, null, 2);
2557
+ }
2558
+ try {
2559
+ const dryRun = args.dry_run === true || args.execute !== true;
2560
+ const result = await commandForNode(ctx, node, "fast_forward_mesh_node", {
2561
+ meshId: ctx.mesh.id,
2562
+ nodeId: node.id,
2563
+ workspace: node.workspace,
2564
+ branch: typeof args.branch === "string" ? args.branch : void 0,
2565
+ execute: args.execute === true && args.dry_run !== true,
2566
+ dryRun,
2567
+ updateSubmodules: args.update_submodules === true,
2568
+ submoduleIgnorePaths: submoduleIgnorePaths.length > 0 ? submoduleIgnorePaths : void 0
2569
+ });
2570
+ return JSON.stringify(unwrapCommandPayload(result), null, 2);
2571
+ } catch (e) {
2572
+ const failure = buildCoordinatorP2pRelayFailure(e, {
2573
+ command: "fast_forward_mesh_node",
2574
+ targetDaemonId: node.daemonId,
2575
+ nodeId: args.node_id
2576
+ });
2577
+ return JSON.stringify({
2578
+ ...failure,
2579
+ workspace: node.workspace,
2580
+ allowed: false,
2581
+ willRun: false,
2582
+ executed: false,
2583
+ blockingReasons: [failure.code || "mesh_fast_forward_unavailable"]
2584
+ }, null, 2);
2585
+ }
2586
+ }
2080
2587
  async function meshCheckpoint(ctx, args) {
2081
2588
  const node = await findNodeWithRefresh(ctx, args.node_id);
2082
2589
  if (node.policy?.readOnly) {
@@ -2162,6 +2669,7 @@ async function meshCloneNode(ctx, args) {
2162
2669
  if (existingIndex >= 0) ctx.mesh.nodes[existingIndex] = clonePayload.node;
2163
2670
  else ctx.mesh.nodes.push(clonePayload.node);
2164
2671
  ctx.mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
2672
+ await syncCoordinatorDaemonMeshCache(ctx);
2165
2673
  }
2166
2674
  return JSON.stringify(result, null, 2);
2167
2675
  } else if (!isLocalTransport(ctx.transport) && sourceNode.daemonId) {
@@ -2179,6 +2687,7 @@ async function meshCloneNode(ctx, args) {
2179
2687
  if (existingIndex >= 0) ctx.mesh.nodes[existingIndex] = clonePayload.node;
2180
2688
  else ctx.mesh.nodes.push(clonePayload.node);
2181
2689
  ctx.mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
2690
+ await syncCoordinatorDaemonMeshCache(ctx);
2182
2691
  }
2183
2692
  return JSON.stringify(res, null, 2);
2184
2693
  } catch (e) {
@@ -2274,6 +2783,43 @@ async function meshRemoveNode(ctx, args) {
2274
2783
  return JSON.stringify({ error: "Cloud mesh remove_node requires node daemonId" });
2275
2784
  }
2276
2785
  }
2786
+ function resolveRefineConfigNode(ctx, nodeId) {
2787
+ if (nodeId) return findNode(ctx.mesh, nodeId);
2788
+ const node = ctx.mesh.nodes.find((entry) => !!entry.workspace);
2789
+ if (!node) throw new Error("No mesh node with a workspace is available");
2790
+ return node;
2791
+ }
2792
+ async function meshRefineConfigSchema(ctx) {
2793
+ const node = resolveRefineConfigNode(ctx);
2794
+ const result = await commandForNode(ctx, node, "get_mesh_refine_config_schema", {});
2795
+ return JSON.stringify(result, null, 2);
2796
+ }
2797
+ async function meshValidateRefineConfig(ctx, args) {
2798
+ const node = resolveRefineConfigNode(ctx, args.node_id);
2799
+ const result = await commandForNode(ctx, node, "validate_mesh_refine_config", {
2800
+ workspace: node.workspace,
2801
+ inlineMesh: ctx.mesh,
2802
+ ...args.config ? { config: args.config } : {}
2803
+ });
2804
+ return JSON.stringify(result, null, 2);
2805
+ }
2806
+ async function meshSuggestRefineConfig(ctx, args) {
2807
+ const node = resolveRefineConfigNode(ctx, args.node_id);
2808
+ const result = await commandForNode(ctx, node, "suggest_mesh_refine_config", {
2809
+ workspace: node.workspace,
2810
+ inlineMesh: ctx.mesh
2811
+ });
2812
+ return JSON.stringify(result, null, 2);
2813
+ }
2814
+ async function meshRefinePlan(ctx, args) {
2815
+ const node = await findNodeWithRefresh(ctx, args.node_id);
2816
+ const result = await commandForNode(ctx, node, "plan_mesh_refine_node", {
2817
+ meshId: ctx.mesh.id,
2818
+ nodeId: args.node_id,
2819
+ inlineMesh: ctx.mesh
2820
+ });
2821
+ return JSON.stringify(result, null, 2);
2822
+ }
2277
2823
  async function meshRefineNode(ctx, args) {
2278
2824
  const node = await findNodeWithRefresh(ctx, args.node_id);
2279
2825
  if (isLocalTransport(ctx.transport)) {
@@ -2282,7 +2828,7 @@ async function meshRefineNode(ctx, args) {
2282
2828
  nodeId: args.node_id,
2283
2829
  inlineMesh: ctx.mesh
2284
2830
  });
2285
- if (result?.success && result.removeResult?.removed !== false) {
2831
+ if (result?.success && result.async !== true && result.removeResult?.removed !== false) {
2286
2832
  const idx = ctx.mesh.nodes.findIndex((n) => n.id === args.node_id);
2287
2833
  if (idx >= 0) {
2288
2834
  ctx.mesh.nodes.splice(idx, 1);
@@ -2297,7 +2843,7 @@ async function meshRefineNode(ctx, args) {
2297
2843
  nodeId: args.node_id,
2298
2844
  inlineMesh: ctx.mesh
2299
2845
  });
2300
- if (res?.success && res.removeResult?.removed !== false) {
2846
+ if (res?.success && res.async !== true && res.removeResult?.removed !== false) {
2301
2847
  const idx = ctx.mesh.nodes.findIndex((n) => n.id === args.node_id);
2302
2848
  if (idx >= 0) {
2303
2849
  ctx.mesh.nodes.splice(idx, 1);
@@ -2334,13 +2880,13 @@ var STANDARD_TOOLS = [
2334
2880
  function buildMcpHelpText() {
2335
2881
  const meshTools = ALL_MESH_TOOLS.map((tool) => tool.name);
2336
2882
  return `
2337
- adhdev-mcp \u2014 ADHDev MCP Server
2883
+ ADHDev MCP Server
2338
2884
 
2339
2885
  Usage:
2340
- adhdev-mcp Local mode (requires standalone daemon)
2341
- adhdev-mcp --api-key <key> Cloud mode (ADHDev cloud API)
2342
- adhdev-mcp --mode ipc --repo-mesh <mesh_id> Cloud daemon IPC mesh mode
2343
- adhdev-mcp --repo-mesh <mesh_id> Mesh mode (coordinator-scoped tools)
2886
+ adhdev mcp Local mode (requires standalone daemon)
2887
+ adhdev mcp --api-key <key> Cloud mode (ADHDev cloud API)
2888
+ adhdev mcp --mode ipc --repo-mesh <mesh_id> Cloud daemon IPC mesh mode
2889
+ adhdev-mcp --help Compatibility bin (same server, legacy package entrypoint)
2344
2890
 
2345
2891
  Options:
2346
2892
  --mode <mode> Transport: local, cloud, or ipc
@@ -2519,8 +3065,8 @@ var CloudTransport = class {
2519
3065
  if (!res.ok) throw new Error(`Approve failed: ${res.status}`);
2520
3066
  return res.json();
2521
3067
  }
2522
- async gitStatus(daemonId, workspace, includeDiff = true) {
2523
- const params = new URLSearchParams({ workspace, includeDiff: String(includeDiff) });
3068
+ async gitStatus(daemonId, workspace, includeDiff = true, refreshUpstream = false) {
3069
+ const params = new URLSearchParams({ workspace, includeDiff: String(includeDiff), refreshUpstream: String(refreshUpstream) });
2524
3070
  const res = await fetch(
2525
3071
  `${this.baseUrl}/api/v1/shortcuts/${encodeURIComponent(daemonId)}/git-status?${params}`,
2526
3072
  { headers: this.headers() }
@@ -2915,6 +3461,22 @@ function formatChatResult(result, sessionId, format, limit = 50, compact = false
2915
3461
  }))
2916
3462
  }, null, 2);
2917
3463
  }
3464
+ if ((format === "text" || format === void 0) && compact && compactPayload) {
3465
+ const lines2 = outputMessages.slice(-limit).map((m) => {
3466
+ const role = m.role === "user" ? "User" : m.role === "assistant" ? "Agent" : m.role;
3467
+ const content = messageContent(m);
3468
+ const truncated = content.length > 500 ? `${content.slice(0, 500)}\u2026` : content;
3469
+ return `[${role}] ${truncated}`;
3470
+ });
3471
+ if (compactPayload.summary) {
3472
+ const truncatedSummary = compactPayload.summary.length > 500 ? `${compactPayload.summary.slice(0, 500)}\u2026` : compactPayload.summary;
3473
+ lines2.push(`[Summary] ${truncatedSummary}`);
3474
+ }
3475
+ if (result?.pollingAdvisory) {
3476
+ lines2.push(`Advisory: ${result.pollingAdvisory.message}`);
3477
+ }
3478
+ return lines2.length > 0 ? lines2.join("\n\n") : "No messages in chat.";
3479
+ }
2918
3480
  if (outputMessages.length === 0) {
2919
3481
  return result?.pollingAdvisory ? `No messages in chat.
2920
3482
 
@@ -4015,6 +4577,9 @@ async function startMcpServer(opts) {
4015
4577
  case "mesh_git_status":
4016
4578
  text = await meshGitStatus(meshCtx, a);
4017
4579
  break;
4580
+ case "mesh_fast_forward_node":
4581
+ text = await meshFastForwardNode(meshCtx, a);
4582
+ break;
4018
4583
  case "mesh_checkpoint":
4019
4584
  text = await meshCheckpoint(meshCtx, a);
4020
4585
  break;
@@ -4030,6 +4595,18 @@ async function startMcpServer(opts) {
4030
4595
  case "mesh_refine_node":
4031
4596
  text = await meshRefineNode(meshCtx, a);
4032
4597
  break;
4598
+ case "mesh_refine_config_schema":
4599
+ text = await meshRefineConfigSchema(meshCtx);
4600
+ break;
4601
+ case "mesh_validate_refine_config":
4602
+ text = await meshValidateRefineConfig(meshCtx, a);
4603
+ break;
4604
+ case "mesh_suggest_refine_config":
4605
+ text = await meshSuggestRefineConfig(meshCtx, a);
4606
+ break;
4607
+ case "mesh_refine_plan":
4608
+ text = await meshRefinePlan(meshCtx, a);
4609
+ break;
4033
4610
  case "mesh_cleanup_sessions":
4034
4611
  text = await meshCleanupSessions(meshCtx, a);
4035
4612
  break;