@adhdev/daemon-core 0.9.82-rc.374 → 0.9.82-rc.376

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -316,10 +316,10 @@ function readInjected(value) {
316
316
  }
317
317
  function getDaemonBuildInfo() {
318
318
  if (cached) return cached;
319
- const commit = readInjected(true ? "47e042dcb10c9ca07c30ac4bf8e0d5a4153a63c6" : void 0) ?? "unknown";
320
- const commitShort = readInjected(true ? "47e042dc" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
321
- const version = readInjected(true ? "0.9.82-rc.374" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
322
- const builtAt = readInjected(true ? "2026-06-25T00:33:05.038Z" : void 0);
319
+ const commit = readInjected(true ? "5f02f35175e6b8b9d8c70d2232438b332cd18d84" : void 0) ?? "unknown";
320
+ const commitShort = readInjected(true ? "5f02f351" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
321
+ const version = readInjected(true ? "0.9.82-rc.376" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
322
+ const builtAt = readInjected(true ? "2026-06-25T03:48:14.181Z" : void 0);
323
323
  cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
324
324
  return cached;
325
325
  }
@@ -3042,6 +3042,10 @@ Default branch: \`${mesh.defaultBranch}\`` : ""}`);
3042
3042
  if (ctx.missionSection?.trim()) {
3043
3043
  sections.push(ctx.missionSection.trim());
3044
3044
  }
3045
+ const recentActivity = buildRecentActivitySection(ctx.recentActivity);
3046
+ if (recentActivity) sections.push(recentActivity);
3047
+ const operatingNotes = buildOperatingNotesSection(ctx.operatingNotes);
3048
+ if (operatingNotes) sections.push(operatingNotes);
3045
3049
  sections.push(buildPolicySection({ ...DEFAULT_MESH_POLICY, ...mesh.policy || {} }));
3046
3050
  sections.push(TOOLS_SECTION);
3047
3051
  sections.push(TOOL_EXPOSURE_PREFLIGHT_SECTION);
@@ -3073,6 +3077,8 @@ function expandPromptPlaceholders(template, ctx) {
3073
3077
  cliType: coordinatorCliType || "",
3074
3078
  nodes: nodesSection,
3075
3079
  mission: ctx.missionSection?.trim() || "",
3080
+ recentActivity: buildRecentActivitySection(ctx.recentActivity) || "",
3081
+ operatingNotes: buildOperatingNotesSection(ctx.operatingNotes) || "",
3076
3082
  policy: buildPolicySection({ ...DEFAULT_MESH_POLICY, ...mesh.policy || {} }),
3077
3083
  tools: TOOLS_SECTION,
3078
3084
  workflow: WORKFLOW_SECTION,
@@ -3144,6 +3150,56 @@ function indentFollowing(text, pad) {
3144
3150
  if (lines.length === 1) return lines[0];
3145
3151
  return [lines[0], ...lines.slice(1).map((l) => pad + l)].join("\n");
3146
3152
  }
3153
+ function buildRecentActivitySection(activity) {
3154
+ if (!activity) return "";
3155
+ const failures = Array.isArray(activity.recentFailures) ? activity.recentFailures : [];
3156
+ const pending = Number.isFinite(activity.pendingTasks) ? Number(activity.pendingTasks) : 0;
3157
+ const assigned = Number.isFinite(activity.assignedTasks) ? Number(activity.assignedTasks) : 0;
3158
+ const stalled = Number.isFinite(activity.stalledTasks) ? Number(activity.stalledTasks) : 0;
3159
+ const recentFailureCount = Number.isFinite(activity.recentFailureCount) ? Number(activity.recentFailureCount) : failures.length;
3160
+ if (failures.length === 0 && pending === 0 && assigned === 0 && stalled === 0 && recentFailureCount === 0) {
3161
+ return "";
3162
+ }
3163
+ const lines = ["## Recent Activity", ""];
3164
+ lines.push("A snapshot of this mesh's recent ledger/queue state at launch. Use it to decide what needs attention first; call `mesh_task_history` / `mesh_view_queue` for full detail.");
3165
+ lines.push("");
3166
+ const counts = [];
3167
+ if (pending > 0) counts.push(`**${pending}** pending`);
3168
+ if (assigned > 0) counts.push(`**${assigned}** assigned`);
3169
+ if (stalled > 0) counts.push(`**${stalled}** stalled`);
3170
+ if (recentFailureCount > 0) counts.push(`**${recentFailureCount}** failed in the last 30 min`);
3171
+ if (counts.length) lines.push(`- Queue/ledger: ${counts.join(", ")}.`);
3172
+ if (activity.lastActivityAt) lines.push(`- Last ledger activity: ${activity.lastActivityAt}.`);
3173
+ if (failures.length > 0) {
3174
+ const recent = failures.slice(-5).reverse();
3175
+ lines.push("", "Recent failures (newest first):");
3176
+ for (const f of recent) {
3177
+ const when = f.timestamp ? `${f.timestamp} ` : "";
3178
+ const node = f.nodeId ? `node \`${f.nodeId}\`` : "unknown node";
3179
+ const summary = (f.summary || "").trim();
3180
+ lines.push(`- ${when}${node}${summary ? ` \u2014 ${summary}` : ""}`);
3181
+ }
3182
+ lines.push("", "_Check `mesh_task_history` before retrying; repeated failures on the same node mean reassign or escalate, not retry._");
3183
+ }
3184
+ return lines.join("\n");
3185
+ }
3186
+ function buildOperatingNotesSection(notes) {
3187
+ const valid = Array.isArray(notes) ? notes.filter((n) => n && typeof n.text === "string" && n.text.trim()) : [];
3188
+ if (valid.length === 0) return "";
3189
+ const categoryLabel = {
3190
+ provider_quirk: "provider quirk",
3191
+ pattern_to_avoid: "pattern to avoid",
3192
+ recovery_lesson: "recovery lesson"
3193
+ };
3194
+ const lines = ["## Operating Notes", ""];
3195
+ lines.push("Lessons earlier coordinators on this mesh recorded via `mesh_record_note`. Treat them as accumulated operating knowledge \u2014 apply them. When you learn a durable lesson (a provider quirk, a pattern to avoid, a recovery lesson), record it with `mesh_record_note` so future coordinators inherit it.");
3196
+ lines.push("");
3197
+ for (const n of valid) {
3198
+ const cat = n.category && categoryLabel[n.category] ? `[${categoryLabel[n.category]}] ` : "";
3199
+ lines.push(`- ${cat}${n.text.trim()}`);
3200
+ }
3201
+ return lines.join("\n");
3202
+ }
3147
3203
  function buildPolicySection(policy) {
3148
3204
  const rules = [];
3149
3205
  if (policy.requirePreTaskCheckpoint) rules.push("- Create a git checkpoint **before** starting each task");
@@ -3207,6 +3263,7 @@ var init_coordinator_prompt = __esm({
3207
3263
  | \`mesh_read_chat\` | Read recent chat messages from a delegated agent session |
3208
3264
  | \`mesh_read_debug\` | Collect a daemon-side chat/parser debug bundle for a session |
3209
3265
  | \`mesh_task_history\` | Read the task ledger \u2014 dispatches, completions, failures. Use to understand what has been done before deciding next steps |
3266
+ | \`mesh_record_note\` | Record a durable, provider-neutral operating note (provider quirk / pattern to avoid / recovery lesson). Future coordinators see it under "## Operating Notes" at launch |
3210
3267
  | \`mesh_git_status\` | Check git status on a specific node |
3211
3268
  | \`mesh_read_node_logs\` | Fetch a remote node's daemon log tail directly over P2P (grep/since/byte-bounded, secrets redacted) \u2014 no session/PowerShell needed to debug a node's daemon |
3212
3269
  | \`mesh_fast_forward_node\` | Safely dry-run or explicitly execute an obvious clean fast-forward without launching an agent session |
@@ -12940,6 +12997,18 @@ function isWeakTerminalLedgerPayload(payload) {
12940
12997
  const diag = readRecord4(payload.completionDiagnostic);
12941
12998
  return diag?.finalAssistantPresent === false || diag?.blockReason === "missing_final_assistant";
12942
12999
  }
13000
+ function supersedesTruncatedTerminalSummary(args) {
13001
+ if (!args.terminalTaskId || !args.eventTaskId || args.terminalTaskId !== args.eventTaskId) return false;
13002
+ if (!isGenuineCompletionEvidence(args.metadataEvent)) return false;
13003
+ const terminalSummary = readNonEmptyString2(args.terminalPayload.finalSummary);
13004
+ const eventSummary = readNonEmptyString2(args.metadataEvent.finalSummary);
13005
+ if (!eventSummary) return false;
13006
+ if (terminalSummary === eventSummary) return false;
13007
+ if (isWeakTerminalLedgerPayload(args.terminalPayload)) return false;
13008
+ if (!terminalSummary) return true;
13009
+ if (eventSummary.startsWith(terminalSummary)) return true;
13010
+ return eventSummary.length > terminalSummary.length + 32;
13011
+ }
12943
13012
  function resolveActiveDirectDispatchTaskId(meshId, sessionId) {
12944
13013
  try {
12945
13014
  const matches = getActiveDirectDispatches(meshId).filter((d) => d.sessionId === sessionId);
@@ -13856,7 +13925,13 @@ function evaluateMeshEventSuppression(args, ctx) {
13856
13925
  const terminalTaskId = readNonEmptyString2(terminal.payload.taskId);
13857
13926
  const eventTaskId = readNonEmptyString2(args.metadataEvent.taskId);
13858
13927
  const distinctTaskCompletion = !!eventTaskId && !!terminalTaskId && eventTaskId !== terminalTaskId;
13859
- if (!newDispatchAfterTerminal && !supersedesWeakTerminal && !distinctTaskCompletion) {
13928
+ const supersedesTruncatedTerminal = supersedesTruncatedTerminalSummary({
13929
+ terminalPayload: terminal.payload,
13930
+ metadataEvent: args.metadataEvent,
13931
+ terminalTaskId,
13932
+ eventTaskId
13933
+ });
13934
+ if (!newDispatchAfterTerminal && !supersedesWeakTerminal && !distinctTaskCompletion && !supersedesTruncatedTerminal) {
13860
13935
  const terminalProviderSessionId = readNonEmptyString2(terminal.payload.providerSessionId);
13861
13936
  const terminalFinalSummary = readNonEmptyString2(terminal.payload.finalSummary);
13862
13937
  const eventProviderSessionId = readNonEmptyString2(args.metadataEvent.providerSessionId);
@@ -14633,6 +14708,16 @@ function findLiveCoordinators(components) {
14633
14708
  const status = readNonEmptyString2(state.status).toLowerCase();
14634
14709
  const modalParked = status === "waiting_choice" || status === "waiting_approval";
14635
14710
  const sessionId = readNonEmptyString2(state.instanceId);
14711
+ const stateKey = `${meshId}::${sessionId || "?"}`;
14712
+ const prevParked = coordinatorModalParkState.get(stateKey);
14713
+ if (prevParked !== modalParked) {
14714
+ coordinatorModalParkState.set(stateKey, modalParked);
14715
+ if (modalParked) {
14716
+ LOG.info("MeshReconcile", `Coordinator ${sessionId || "?"} (mesh ${meshId}) entered modal-park (status=${status}) \u2014 terminal events for it will be held until the modal is answered`);
14717
+ } else if (prevParked === true) {
14718
+ LOG.info("MeshReconcile", `Coordinator ${sessionId || "?"} (mesh ${meshId}) left modal-park (status=${status}) \u2014 held events will drain on this/next tick`);
14719
+ }
14720
+ }
14636
14721
  out.push({ meshId, instance: inst, sessionId, idle: status === "idle", modalParked });
14637
14722
  }
14638
14723
  return out;
@@ -14826,7 +14911,55 @@ async function runMeshReconcileTick(components) {
14826
14911
  const forceOnly = idleCoordinators.length === 0;
14827
14912
  if (targetCoordinators.length === 0) {
14828
14913
  if (modalParkedCoordinators.length > 0) {
14829
- LOG.info("MeshReconcile", `Reconcile skip \u2192 modal-parked: holding pending event(s) for mesh ${meshId} (${modalParkedCoordinators.length} coordinator(s) awaiting a modal answer; events left queued)`);
14914
+ const liveSessionIds = new Set(
14915
+ meshCoordinators.map((c) => readNonEmptyString2(c.sessionId)).filter(Boolean)
14916
+ );
14917
+ let orphanEscaped = 0;
14918
+ const hasPendingForOrphanPeek = !store || (() => {
14919
+ try {
14920
+ return store.pendingEventCount(meshId) > 0;
14921
+ } catch {
14922
+ return true;
14923
+ }
14924
+ })();
14925
+ if (hasPendingForOrphanPeek) {
14926
+ let peeked = [];
14927
+ try {
14928
+ peeked = getPendingMeshCoordinatorEvents(meshId, drainDaemonIds.length > 0 ? drainDaemonIds : void 0);
14929
+ } catch {
14930
+ peeked = [];
14931
+ }
14932
+ const isOrphan = (e) => {
14933
+ const want = readNonEmptyString2(e.targetCoordinatorSessionId);
14934
+ return !!want && !liveSessionIds.has(want);
14935
+ };
14936
+ const orphanEventNames = new Set(peeked.filter(isOrphan).map((e) => e.event));
14937
+ if (orphanEventNames.size > 0) {
14938
+ let drained = [];
14939
+ try {
14940
+ drained = drainPendingMeshCoordinatorEvents(
14941
+ meshId,
14942
+ drainDaemonIds.length > 0 ? drainDaemonIds : localDaemonId,
14943
+ { onlyEvents: orphanEventNames }
14944
+ );
14945
+ } catch (e) {
14946
+ LOG.warn("MeshReconcile", `Orphan-escape drain failed for mesh ${meshId}: ${e?.message || e}`);
14947
+ drained = [];
14948
+ }
14949
+ for (const pending of drained) {
14950
+ if (isOrphan(pending)) {
14951
+ holdOrExpireStrictUnmatchedEvent(pending, readNonEmptyString2(pending.targetCoordinatorSessionId), meshId);
14952
+ orphanEscaped++;
14953
+ } else {
14954
+ try {
14955
+ queuePendingMeshCoordinatorEvent(pending);
14956
+ } catch {
14957
+ }
14958
+ }
14959
+ }
14960
+ }
14961
+ }
14962
+ LOG.info("MeshReconcile", `Reconcile skip \u2192 modal-parked: holding pending event(s) for mesh ${meshId} (${modalParkedCoordinators.length} coordinator(s) awaiting a modal answer; events left queued${orphanEscaped > 0 ? `; ${orphanEscaped} orphan-targeted event(s) routed to strict-route TTL` : ""})`);
14830
14963
  let hasPending = true;
14831
14964
  if (store) {
14832
14965
  try {
@@ -15097,6 +15230,19 @@ async function reconcileUnterminatedDirectDispatches(components, mesh, selfIds,
15097
15230
  const messages = Array.isArray(payload.messages) ? payload.messages : [];
15098
15231
  const evidence = extractFinalAssistantSummaryEvidence(messages);
15099
15232
  if (!evidence.finalSummary) continue;
15233
+ const dispatchedAtMs = Date.parse(readNonEmptyString2(dispatch.dispatchedAt));
15234
+ const transcriptAtMs = Date.parse(evidence.transcriptMessageAt ?? "");
15235
+ if (Number.isFinite(dispatchedAtMs) && Number.isFinite(transcriptAtMs) && transcriptAtMs < dispatchedAtMs) {
15236
+ LOG.info("MeshReconcile", `Stale-summary guard: skipping transcript reconcile for task ${taskId} on node ${nodeId} (mesh ${mesh.id}) \u2014 final assistant message (${evidence.transcriptMessageAt}) predates this task's dispatch (${dispatch.dispatchedAt}); it is a prior task's summary`);
15237
+ traceMeshEventDrop("reconcile_stale_summary_before_dispatch", {
15238
+ taskId,
15239
+ sessionId,
15240
+ nodeId,
15241
+ meshId: mesh.id,
15242
+ event: "agent:generating_completed"
15243
+ }, `transcriptAt=${evidence.transcriptMessageAt} < dispatchedAt=${dispatch.dispatchedAt}`);
15244
+ continue;
15245
+ }
15100
15246
  const providerSessionId = readNonEmptyString2(payload.providerSessionId);
15101
15247
  const coordinatorDaemonId = selfIds.find((id) => !!id);
15102
15248
  try {
@@ -15224,7 +15370,7 @@ function setupMeshReconcileLoop(components) {
15224
15370
  }
15225
15371
  };
15226
15372
  }
15227
- var DEFAULT_RECONCILE_INTERVAL_MS, DEFAULT_AUTO_PRUNE_MIN_AGE_MS, heldEventLedgerRecorded, ASSIGNED_STRANDED_DEADLINE_MS, STRICT_SESSION_MATCH_TTL_MS, unresolvedForwardRejectionCounts, MAX_FORWARD_REJECTIONS;
15373
+ var DEFAULT_RECONCILE_INTERVAL_MS, DEFAULT_AUTO_PRUNE_MIN_AGE_MS, coordinatorModalParkState, heldEventLedgerRecorded, ASSIGNED_STRANDED_DEADLINE_MS, STRICT_SESSION_MATCH_TTL_MS, unresolvedForwardRejectionCounts, MAX_FORWARD_REJECTIONS;
15228
15374
  var init_mesh_reconcile_loop = __esm({
15229
15375
  "src/mesh/mesh-reconcile-loop.ts"() {
15230
15376
  "use strict";
@@ -15246,6 +15392,7 @@ var init_mesh_reconcile_loop = __esm({
15246
15392
  init_chat_message_normalization();
15247
15393
  DEFAULT_RECONCILE_INTERVAL_MS = 4e3;
15248
15394
  DEFAULT_AUTO_PRUNE_MIN_AGE_MS = 24 * 60 * 6e4;
15395
+ coordinatorModalParkState = /* @__PURE__ */ new Map();
15249
15396
  heldEventLedgerRecorded = /* @__PURE__ */ new Set();
15250
15397
  ASSIGNED_STRANDED_DEADLINE_MS = 5 * 6e4;
15251
15398
  STRICT_SESSION_MATCH_TTL_MS = 6e4;
@@ -38184,6 +38331,8 @@ function getMessageTime(message) {
38184
38331
  }
38185
38332
  var COMPLETED_FINALIZATION_RETRY_MS = 1e3;
38186
38333
  var COMPLETED_FINALIZATION_MAX_WAIT_MS = 3e4;
38334
+ var NATIVE_HISTORY_MESH_IDLE_SETTLE_MS = 1500;
38335
+ var USER_INPUT_ACK_DEDUP_WINDOW_MS = 6e4;
38187
38336
  var TERMINAL_MESH_EVENTS = /* @__PURE__ */ new Set([
38188
38337
  "agent:generating_completed",
38189
38338
  "agent:stopped",
@@ -38455,6 +38604,14 @@ var CliProviderInstance = class _CliProviderInstance {
38455
38604
  runtimeMessages = [];
38456
38605
  lastPersistedHistoryMessages = [];
38457
38606
  lastAcknowledgedUserInputAt = 0;
38607
+ // TASKBUBBLE-DUP: per-content last-ack timestamps so the same dispatched
38608
+ // prompt acked twice in quick succession (the worker buffers the first
38609
+ // send during bootstrap/busy, then a redelivery — dispatch-confirm-timeout
38610
+ // requeue or a reconcile re-dispatch — fires a SECOND send_chat before the
38611
+ // outbound queue drains) collapses to ONE user bubble. Keyed on the trimmed
38612
+ // content; an entry older than USER_INPUT_ACK_DEDUP_WINDOW_MS is treated as
38613
+ // a fresh, intentional resend and is NOT suppressed.
38614
+ recentUserInputAcks = /* @__PURE__ */ new Map();
38458
38615
  lastNativeSourceCanonicalCheckAt = 0;
38459
38616
  lastNativeSourceCanonicalCacheKey = void 0;
38460
38617
  cachedSqliteDb = null;
@@ -38889,6 +39046,15 @@ var CliProviderInstance = class _CliProviderInstance {
38889
39046
  const content = typeof input === "string" ? input.trim() : buildCliStructuredInputPrompt(input).trim();
38890
39047
  if (!content) return;
38891
39048
  const receivedAt = Date.now();
39049
+ const ackContentKey = shortHash(`${this.instanceId}:${content}`, 24);
39050
+ const lastAckAt = this.recentUserInputAcks.get(ackContentKey);
39051
+ if (lastAckAt !== void 0 && receivedAt - lastAckAt <= USER_INPUT_ACK_DEDUP_WINDOW_MS) {
39052
+ this.recentUserInputAcks.set(ackContentKey, receivedAt);
39053
+ this.pruneRecentUserInputAcks(receivedAt);
39054
+ return;
39055
+ }
39056
+ this.recentUserInputAcks.set(ackContentKey, receivedAt);
39057
+ this.pruneRecentUserInputAcks(receivedAt);
38892
39058
  this.lastAcknowledgedUserInputAt = receivedAt;
38893
39059
  const dedupKey = `user_input_ack:${shortHash(`${this.instanceId}:${content}:${receivedAt}`, 24)}`;
38894
39060
  this.appendRuntimeMessage(buildChatMessage({
@@ -38906,6 +39072,13 @@ var CliProviderInstance = class _CliProviderInstance {
38906
39072
  }
38907
39073
  }), dedupKey);
38908
39074
  }
39075
+ /** Drop user-input ack entries older than the dedup window so the map can't grow unbounded. */
39076
+ pruneRecentUserInputAcks(now) {
39077
+ if (this.recentUserInputAcks.size <= 1) return;
39078
+ for (const [key, at] of this.recentUserInputAcks) {
39079
+ if (now - at > USER_INPUT_ACK_DEDUP_WINDOW_MS) this.recentUserInputAcks.delete(key);
39080
+ }
39081
+ }
38909
39082
  dispose() {
38910
39083
  this.adapter.shutdown();
38911
39084
  this.monitor.reset();
@@ -39595,8 +39768,9 @@ var CliProviderInstance = class _CliProviderInstance {
39595
39768
  previousStatus: this.lastStatus
39596
39769
  };
39597
39770
  const ownsExternalHistory = !!this.adapter?.chatMessagesOwnedExternally;
39598
- const flushDelay = ownsExternalHistory ? 0 : 3e3;
39599
- LOG.debug("CLI", `[${this.type}] set completedDebouncePending duration=${duration}s ownsExternalHistory=${ownsExternalHistory} flushDelay=${flushDelay}ms generatingStartedAt=${this.generatingStartedAt}`);
39771
+ const meshWorkerSession = this.isMeshWorkerSession();
39772
+ const flushDelay = ownsExternalHistory ? meshWorkerSession ? NATIVE_HISTORY_MESH_IDLE_SETTLE_MS : 0 : 3e3;
39773
+ LOG.debug("CLI", `[${this.type}] set completedDebouncePending duration=${duration}s ownsExternalHistory=${ownsExternalHistory} meshWorker=${meshWorkerSession} flushDelay=${flushDelay}ms generatingStartedAt=${this.generatingStartedAt}`);
39600
39774
  this.scheduleCompletedDebounceFlush(flushDelay);
39601
39775
  }
39602
39776
  } else if (newStatus === "idle" && this.lastStatus === "starting") {
@@ -42651,11 +42825,11 @@ var cliAgentHandlers = {
42651
42825
  }
42652
42826
  }
42653
42827
  }
42654
- const agentResult = await ctx.deps.cliManager.handleCliCommand("agent_command", args);
42655
42828
  const meshCtx = args?.meshContext;
42656
42829
  const dispatchNodeId = readStringValue(meshCtx?.nodeId);
42657
42830
  const dispatchMeshId = readStringValue(meshCtx?.meshId);
42658
- if (dispatchNodeId && dispatchMeshId && agentResult?.success !== false) {
42831
+ const isSendChat = args?.action === "send_chat";
42832
+ if (isSendChat && dispatchNodeId && dispatchMeshId) {
42659
42833
  try {
42660
42834
  const { getMesh: getMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
42661
42835
  const meshObj = getMesh2(dispatchMeshId) ?? ctx.getCachedInlineMesh(dispatchMeshId);
@@ -42663,17 +42837,22 @@ var cliAgentHandlers = {
42663
42837
  const bootstrapStatus = readStringValue(nodeObj?.worktreeBootstrap?.status);
42664
42838
  if (bootstrapStatus === "running") {
42665
42839
  return {
42666
- success: true,
42667
- ...agentResult,
42668
- dispatchAcknowledgementRisk: true,
42669
- dispatchAcknowledgementRiskReason: "bootstrap_still_running",
42670
- nextAction: "Wait for worktree_bootstrap_complete event before dispatching work to this node."
42840
+ success: false,
42841
+ recoverable: true,
42842
+ dispatched: false,
42843
+ code: "mesh_node_bootstrap_pending",
42844
+ reason: "bootstrap_still_running",
42845
+ nodeId: dispatchNodeId,
42846
+ meshId: dispatchMeshId,
42847
+ ...readStringValue(meshCtx?.taskId) ? { taskId: readStringValue(meshCtx?.taskId) } : {},
42848
+ error: `Node '${dispatchNodeId}' worktree bootstrap is still running; a task injected now would land in the session input buffer before the provider is ready to consume it and be silently lost. Dispatch deferred.`,
42849
+ nextAction: "Wait for the worktree_bootstrap_complete event (or poll mesh_status until the node session is ready), then re-send the task with mesh_send_task. Alternatively use mesh_enqueue_task so the queue auto-assigns it once a ready session is available."
42671
42850
  };
42672
42851
  }
42673
42852
  } catch {
42674
42853
  }
42675
42854
  }
42676
- return agentResult;
42855
+ return ctx.deps.cliManager.handleCliCommand("agent_command", args);
42677
42856
  },
42678
42857
  // ─── Logs ───
42679
42858
  list_saved_sessions: async (ctx, args) => {
@@ -47795,49 +47974,72 @@ var fastForwardHandlers = {
47795
47974
  };
47796
47975
  },
47797
47976
  fast_forward_mesh_node: async (ctx, args) => {
47798
- const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
47799
- const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
47800
- let workspace = typeof args?.workspace === "string" ? args.workspace.trim() : "";
47801
- let submoduleIgnorePaths = Array.isArray(args?.submoduleIgnorePaths) ? args.submoduleIgnorePaths.filter((value) => typeof value === "string") : void 0;
47802
- let nodeDaemonId;
47803
- let allowAutoPublishSubmoduleMainCommits = false;
47804
- if (meshId && nodeId) {
47805
- const meshRecord = await ctx.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
47806
- const mesh = meshRecord?.mesh;
47807
- const node = mesh?.nodes?.find((n) => meshNodeIdMatches(n, nodeId));
47808
- if (!workspace) {
47809
- workspace = typeof node?.workspace === "string" ? node.workspace.trim() : "";
47977
+ const workspaceForError = typeof args?.workspace === "string" ? args.workspace.trim() : "";
47978
+ const meshIdForError = typeof args?.meshId === "string" ? args.meshId.trim() : "";
47979
+ const nodeIdForError = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
47980
+ try {
47981
+ const meshId = meshIdForError;
47982
+ const nodeId = nodeIdForError;
47983
+ let workspace = workspaceForError;
47984
+ let submoduleIgnorePaths = Array.isArray(args?.submoduleIgnorePaths) ? args.submoduleIgnorePaths.filter((value) => typeof value === "string") : void 0;
47985
+ let nodeDaemonId;
47986
+ let allowAutoPublishSubmoduleMainCommits = false;
47987
+ if (meshId && nodeId) {
47988
+ const meshRecord = await ctx.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
47989
+ const mesh = meshRecord?.mesh;
47990
+ const node = mesh?.nodes?.find((n) => meshNodeIdMatches(n, nodeId));
47991
+ if (!workspace) {
47992
+ workspace = typeof node?.workspace === "string" ? node.workspace.trim() : "";
47993
+ }
47994
+ if (!submoduleIgnorePaths && Array.isArray(node?.policy?.submoduleIgnorePaths)) {
47995
+ submoduleIgnorePaths = node.policy.submoduleIgnorePaths.filter((value) => typeof value === "string");
47996
+ }
47997
+ allowAutoPublishSubmoduleMainCommits = mesh?.policy?.allowAutoPublishSubmoduleMainCommits === true;
47998
+ nodeDaemonId = typeof node?.daemonId === "string" ? node.daemonId.trim() : void 0;
47810
47999
  }
47811
- if (!submoduleIgnorePaths && Array.isArray(node?.policy?.submoduleIgnorePaths)) {
47812
- submoduleIgnorePaths = node.policy.submoduleIgnorePaths.filter((value) => typeof value === "string");
48000
+ const selfDaemonId = ctx.deps.statusInstanceId;
48001
+ const isRemote = nodeDaemonId && selfDaemonId && !daemonIdsEquivalent(nodeDaemonId, selfDaemonId);
48002
+ if (isRemote && ctx.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
48003
+ const forwarded = await ctx.deps.dispatchMeshCommand(nodeDaemonId, "fast_forward_mesh_node", {
48004
+ ...typeof args === "object" && args !== null ? args : {},
48005
+ workspace,
48006
+ _meshDirectDispatch: true
48007
+ });
48008
+ return forwarded ?? { success: false, error: "no response from remote node" };
47813
48009
  }
47814
- allowAutoPublishSubmoduleMainCommits = mesh?.policy?.allowAutoPublishSubmoduleMainCommits === true;
47815
- nodeDaemonId = typeof node?.daemonId === "string" ? node.daemonId.trim() : void 0;
47816
- }
47817
- const selfDaemonId = ctx.deps.statusInstanceId;
47818
- const isRemote = nodeDaemonId && selfDaemonId && !daemonIdsEquivalent(nodeDaemonId, selfDaemonId);
47819
- if (isRemote && ctx.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
47820
- const forwarded = await ctx.deps.dispatchMeshCommand(nodeDaemonId, "fast_forward_mesh_node", {
47821
- ...typeof args === "object" && args !== null ? args : {},
48010
+ const result = await fastForwardMeshNode({
48011
+ meshId: meshId || void 0,
48012
+ nodeId: nodeId || void 0,
47822
48013
  workspace,
47823
- _meshDirectDispatch: true
48014
+ branch: typeof args?.branch === "string" ? args.branch : void 0,
48015
+ execute: args?.execute === true,
48016
+ dryRun: args?.dryRun === true,
48017
+ updateSubmodules: args?.updateSubmodules === true,
48018
+ submoduleIgnorePaths,
48019
+ mode: args?.mode === "push" ? "push" : "merge",
48020
+ pushSubmodules: args?.pushSubmodules === true,
48021
+ allowAutoPublishSubmoduleMainCommits
47824
48022
  });
47825
- return forwarded ?? { success: false, error: "no response from remote node" };
48023
+ return result;
48024
+ } catch (e) {
48025
+ const errorMessage = e?.message || String(e);
48026
+ return {
48027
+ success: false,
48028
+ code: "fast_forward_safety_gate_error",
48029
+ ...meshIdForError ? { meshId: meshIdForError } : {},
48030
+ ...nodeIdForError ? { nodeId: nodeIdForError } : {},
48031
+ workspace: workspaceForError,
48032
+ mode: args?.mode === "push" ? "push" : "merge",
48033
+ allowed: false,
48034
+ willRun: false,
48035
+ executed: false,
48036
+ // Surface the throw as a blocking reason instead of an opaque IPC crash
48037
+ // so the coordinator gets the same structured shape a clean node returns.
48038
+ blockingReasons: ["fast_forward_safety_gate_error"],
48039
+ operationError: errorMessage,
48040
+ error: errorMessage
48041
+ };
47826
48042
  }
47827
- const result = await fastForwardMeshNode({
47828
- meshId: meshId || void 0,
47829
- nodeId: nodeId || void 0,
47830
- workspace,
47831
- branch: typeof args?.branch === "string" ? args.branch : void 0,
47832
- execute: args?.execute === true,
47833
- dryRun: args?.dryRun === true,
47834
- updateSubmodules: args?.updateSubmodules === true,
47835
- submoduleIgnorePaths,
47836
- mode: args?.mode === "push" ? "push" : "merge",
47837
- pushSubmodules: args?.pushSubmodules === true,
47838
- allowAutoPublishSubmoduleMainCommits
47839
- });
47840
- return result;
47841
48043
  },
47842
48044
  refine_mesh_node: async (ctx, args) => {
47843
48045
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
@@ -47994,6 +48196,56 @@ var meshCoordinatorLaunchHandlers = {
47994
48196
  return "";
47995
48197
  }
47996
48198
  };
48199
+ const buildRecentActivityBestEffort = async (id) => {
48200
+ try {
48201
+ const { getLedgerSummary: getLedgerSummary2, readLedgerEntries: readLedgerEntries2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
48202
+ const { getMeshQueueStats: getMeshQueueStats2 } = await Promise.resolve().then(() => (init_mesh_work_queue(), mesh_work_queue_exports));
48203
+ const summary = getLedgerSummary2(id);
48204
+ const queue = getMeshQueueStats2(id);
48205
+ const failureEntries = readLedgerEntries2(id, { kind: ["task_failed"], tail: 5 });
48206
+ const recentFailures = failureEntries.map((e) => {
48207
+ const p = e.payload || {};
48208
+ const raw = typeof p.taskSummary === "string" ? p.taskSummary : typeof p.message === "string" ? p.message : typeof p.error === "string" ? p.error : "";
48209
+ const summaryText = raw.length > 160 ? `${raw.slice(0, 160)}\u2026` : raw;
48210
+ return {
48211
+ timestamp: e.timestamp,
48212
+ nodeId: e.nodeId,
48213
+ summary: summaryText
48214
+ };
48215
+ });
48216
+ return {
48217
+ recentFailures,
48218
+ recentFailureCount: summary.recentFailures,
48219
+ pendingTasks: queue.pending,
48220
+ assignedTasks: queue.assigned,
48221
+ stalledTasks: summary.taskStalled,
48222
+ lastActivityAt: summary.lastActivityAt
48223
+ };
48224
+ } catch {
48225
+ return void 0;
48226
+ }
48227
+ };
48228
+ const buildOperatingNotesBestEffort = async (id) => {
48229
+ try {
48230
+ const { readLedgerEntries: readLedgerEntries2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
48231
+ const noteEntries = readLedgerEntries2(id, { kind: ["coordinator_operating_note"], tail: 20 });
48232
+ const notes = noteEntries.map((e) => {
48233
+ const p = e.payload || {};
48234
+ const text = typeof p.text === "string" ? p.text.trim() : "";
48235
+ if (!text) return null;
48236
+ const category = p.category === "provider_quirk" || p.category === "pattern_to_avoid" || p.category === "recovery_lesson" ? p.category : void 0;
48237
+ return {
48238
+ text,
48239
+ category,
48240
+ createdAt: typeof p.createdAt === "string" ? p.createdAt : e.timestamp,
48241
+ sourceCoordinator: typeof p.sourceCoordinator === "string" ? p.sourceCoordinator : void 0
48242
+ };
48243
+ }).filter((n) => n !== null);
48244
+ return notes.length ? notes : void 0;
48245
+ } catch {
48246
+ return void 0;
48247
+ }
48248
+ };
47997
48249
  let mesh;
47998
48250
  if (args?.inlineMesh && typeof args.inlineMesh === "object") {
47999
48251
  mesh = args.inlineMesh;
@@ -48084,7 +48336,7 @@ var meshCoordinatorLaunchHandlers = {
48084
48336
  if (coordinatorSetup.kind === "cli_command") {
48085
48337
  let cliCmdSystemPrompt = "";
48086
48338
  try {
48087
- cliCmdSystemPrompt = buildCoordinatorSystemPrompt2({ mesh, coordinatorCliType: cliType, userInstruction: extraSystemPrompt || void 0, missionSection: buildMissionSectionBestEffort(mesh.id) });
48339
+ cliCmdSystemPrompt = buildCoordinatorSystemPrompt2({ mesh, coordinatorCliType: cliType, userInstruction: extraSystemPrompt || void 0, missionSection: buildMissionSectionBestEffort(mesh.id), recentActivity: await buildRecentActivityBestEffort(mesh.id), operatingNotes: await buildOperatingNotesBestEffort(mesh.id) });
48088
48340
  } catch (error) {
48089
48341
  const message = error?.message || String(error);
48090
48342
  LOG.error("MeshCoordinator", `Failed to build coordinator prompt: ${message}`);
@@ -48261,7 +48513,7 @@ ${ptyResult.output.slice(-2e3)}`);
48261
48513
  }
48262
48514
  let systemPrompt = "";
48263
48515
  try {
48264
- systemPrompt = buildCoordinatorSystemPrompt2({ mesh, coordinatorCliType: cliType, userInstruction: extraSystemPrompt || void 0, missionSection: buildMissionSectionBestEffort(mesh.id) });
48516
+ systemPrompt = buildCoordinatorSystemPrompt2({ mesh, coordinatorCliType: cliType, userInstruction: extraSystemPrompt || void 0, missionSection: buildMissionSectionBestEffort(mesh.id), recentActivity: await buildRecentActivityBestEffort(mesh.id), operatingNotes: await buildOperatingNotesBestEffort(mesh.id) });
48265
48517
  } catch (error) {
48266
48518
  const message = error?.message || String(error);
48267
48519
  LOG.error("MeshCoordinator", `Failed to build coordinator prompt: ${message}`);