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

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.mjs CHANGED
@@ -311,10 +311,10 @@ function readInjected(value) {
311
311
  }
312
312
  function getDaemonBuildInfo() {
313
313
  if (cached) return cached;
314
- const commit = readInjected(true ? "47e042dcb10c9ca07c30ac4bf8e0d5a4153a63c6" : void 0) ?? "unknown";
315
- const commitShort = readInjected(true ? "47e042dc" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
316
- const version = readInjected(true ? "0.9.82-rc.374" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
317
- const builtAt = readInjected(true ? "2026-06-25T00:33:05.038Z" : void 0);
314
+ const commit = readInjected(true ? "b17fb9165bd52c9e2ab8cccf2ce80734e2165680" : void 0) ?? "unknown";
315
+ const commitShort = readInjected(true ? "b17fb916" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
316
+ const version = readInjected(true ? "0.9.82-rc.375" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
317
+ const builtAt = readInjected(true ? "2026-06-25T02:21:59.111Z" : void 0);
318
318
  cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
319
319
  return cached;
320
320
  }
@@ -3039,6 +3039,10 @@ Default branch: \`${mesh.defaultBranch}\`` : ""}`);
3039
3039
  if (ctx.missionSection?.trim()) {
3040
3040
  sections.push(ctx.missionSection.trim());
3041
3041
  }
3042
+ const recentActivity = buildRecentActivitySection(ctx.recentActivity);
3043
+ if (recentActivity) sections.push(recentActivity);
3044
+ const operatingNotes = buildOperatingNotesSection(ctx.operatingNotes);
3045
+ if (operatingNotes) sections.push(operatingNotes);
3042
3046
  sections.push(buildPolicySection({ ...DEFAULT_MESH_POLICY, ...mesh.policy || {} }));
3043
3047
  sections.push(TOOLS_SECTION);
3044
3048
  sections.push(TOOL_EXPOSURE_PREFLIGHT_SECTION);
@@ -3070,6 +3074,8 @@ function expandPromptPlaceholders(template, ctx) {
3070
3074
  cliType: coordinatorCliType || "",
3071
3075
  nodes: nodesSection,
3072
3076
  mission: ctx.missionSection?.trim() || "",
3077
+ recentActivity: buildRecentActivitySection(ctx.recentActivity) || "",
3078
+ operatingNotes: buildOperatingNotesSection(ctx.operatingNotes) || "",
3073
3079
  policy: buildPolicySection({ ...DEFAULT_MESH_POLICY, ...mesh.policy || {} }),
3074
3080
  tools: TOOLS_SECTION,
3075
3081
  workflow: WORKFLOW_SECTION,
@@ -3141,6 +3147,56 @@ function indentFollowing(text, pad) {
3141
3147
  if (lines.length === 1) return lines[0];
3142
3148
  return [lines[0], ...lines.slice(1).map((l) => pad + l)].join("\n");
3143
3149
  }
3150
+ function buildRecentActivitySection(activity) {
3151
+ if (!activity) return "";
3152
+ const failures = Array.isArray(activity.recentFailures) ? activity.recentFailures : [];
3153
+ const pending = Number.isFinite(activity.pendingTasks) ? Number(activity.pendingTasks) : 0;
3154
+ const assigned = Number.isFinite(activity.assignedTasks) ? Number(activity.assignedTasks) : 0;
3155
+ const stalled = Number.isFinite(activity.stalledTasks) ? Number(activity.stalledTasks) : 0;
3156
+ const recentFailureCount = Number.isFinite(activity.recentFailureCount) ? Number(activity.recentFailureCount) : failures.length;
3157
+ if (failures.length === 0 && pending === 0 && assigned === 0 && stalled === 0 && recentFailureCount === 0) {
3158
+ return "";
3159
+ }
3160
+ const lines = ["## Recent Activity", ""];
3161
+ 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.");
3162
+ lines.push("");
3163
+ const counts = [];
3164
+ if (pending > 0) counts.push(`**${pending}** pending`);
3165
+ if (assigned > 0) counts.push(`**${assigned}** assigned`);
3166
+ if (stalled > 0) counts.push(`**${stalled}** stalled`);
3167
+ if (recentFailureCount > 0) counts.push(`**${recentFailureCount}** failed in the last 30 min`);
3168
+ if (counts.length) lines.push(`- Queue/ledger: ${counts.join(", ")}.`);
3169
+ if (activity.lastActivityAt) lines.push(`- Last ledger activity: ${activity.lastActivityAt}.`);
3170
+ if (failures.length > 0) {
3171
+ const recent = failures.slice(-5).reverse();
3172
+ lines.push("", "Recent failures (newest first):");
3173
+ for (const f of recent) {
3174
+ const when = f.timestamp ? `${f.timestamp} ` : "";
3175
+ const node = f.nodeId ? `node \`${f.nodeId}\`` : "unknown node";
3176
+ const summary = (f.summary || "").trim();
3177
+ lines.push(`- ${when}${node}${summary ? ` \u2014 ${summary}` : ""}`);
3178
+ }
3179
+ lines.push("", "_Check `mesh_task_history` before retrying; repeated failures on the same node mean reassign or escalate, not retry._");
3180
+ }
3181
+ return lines.join("\n");
3182
+ }
3183
+ function buildOperatingNotesSection(notes) {
3184
+ const valid = Array.isArray(notes) ? notes.filter((n) => n && typeof n.text === "string" && n.text.trim()) : [];
3185
+ if (valid.length === 0) return "";
3186
+ const categoryLabel = {
3187
+ provider_quirk: "provider quirk",
3188
+ pattern_to_avoid: "pattern to avoid",
3189
+ recovery_lesson: "recovery lesson"
3190
+ };
3191
+ const lines = ["## Operating Notes", ""];
3192
+ 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.");
3193
+ lines.push("");
3194
+ for (const n of valid) {
3195
+ const cat = n.category && categoryLabel[n.category] ? `[${categoryLabel[n.category]}] ` : "";
3196
+ lines.push(`- ${cat}${n.text.trim()}`);
3197
+ }
3198
+ return lines.join("\n");
3199
+ }
3144
3200
  function buildPolicySection(policy) {
3145
3201
  const rules = [];
3146
3202
  if (policy.requirePreTaskCheckpoint) rules.push("- Create a git checkpoint **before** starting each task");
@@ -3201,6 +3257,7 @@ var init_coordinator_prompt = __esm({
3201
3257
  | \`mesh_read_chat\` | Read recent chat messages from a delegated agent session |
3202
3258
  | \`mesh_read_debug\` | Collect a daemon-side chat/parser debug bundle for a session |
3203
3259
  | \`mesh_task_history\` | Read the task ledger \u2014 dispatches, completions, failures. Use to understand what has been done before deciding next steps |
3260
+ | \`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 |
3204
3261
  | \`mesh_git_status\` | Check git status on a specific node |
3205
3262
  | \`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 |
3206
3263
  | \`mesh_fast_forward_node\` | Safely dry-run or explicitly execute an obvious clean fast-forward without launching an agent session |
@@ -12936,6 +12993,18 @@ function isWeakTerminalLedgerPayload(payload) {
12936
12993
  const diag = readRecord4(payload.completionDiagnostic);
12937
12994
  return diag?.finalAssistantPresent === false || diag?.blockReason === "missing_final_assistant";
12938
12995
  }
12996
+ function supersedesTruncatedTerminalSummary(args) {
12997
+ if (!args.terminalTaskId || !args.eventTaskId || args.terminalTaskId !== args.eventTaskId) return false;
12998
+ if (!isGenuineCompletionEvidence(args.metadataEvent)) return false;
12999
+ const terminalSummary = readNonEmptyString2(args.terminalPayload.finalSummary);
13000
+ const eventSummary = readNonEmptyString2(args.metadataEvent.finalSummary);
13001
+ if (!eventSummary) return false;
13002
+ if (terminalSummary === eventSummary) return false;
13003
+ if (isWeakTerminalLedgerPayload(args.terminalPayload)) return false;
13004
+ if (!terminalSummary) return true;
13005
+ if (eventSummary.startsWith(terminalSummary)) return true;
13006
+ return eventSummary.length > terminalSummary.length + 32;
13007
+ }
12939
13008
  function resolveActiveDirectDispatchTaskId(meshId, sessionId) {
12940
13009
  try {
12941
13010
  const matches = getActiveDirectDispatches(meshId).filter((d) => d.sessionId === sessionId);
@@ -13852,7 +13921,13 @@ function evaluateMeshEventSuppression(args, ctx) {
13852
13921
  const terminalTaskId = readNonEmptyString2(terminal.payload.taskId);
13853
13922
  const eventTaskId = readNonEmptyString2(args.metadataEvent.taskId);
13854
13923
  const distinctTaskCompletion = !!eventTaskId && !!terminalTaskId && eventTaskId !== terminalTaskId;
13855
- if (!newDispatchAfterTerminal && !supersedesWeakTerminal && !distinctTaskCompletion) {
13924
+ const supersedesTruncatedTerminal = supersedesTruncatedTerminalSummary({
13925
+ terminalPayload: terminal.payload,
13926
+ metadataEvent: args.metadataEvent,
13927
+ terminalTaskId,
13928
+ eventTaskId
13929
+ });
13930
+ if (!newDispatchAfterTerminal && !supersedesWeakTerminal && !distinctTaskCompletion && !supersedesTruncatedTerminal) {
13856
13931
  const terminalProviderSessionId = readNonEmptyString2(terminal.payload.providerSessionId);
13857
13932
  const terminalFinalSummary = readNonEmptyString2(terminal.payload.finalSummary);
13858
13933
  const eventProviderSessionId = readNonEmptyString2(args.metadataEvent.providerSessionId);
@@ -14628,6 +14703,16 @@ function findLiveCoordinators(components) {
14628
14703
  const status = readNonEmptyString2(state.status).toLowerCase();
14629
14704
  const modalParked = status === "waiting_choice" || status === "waiting_approval";
14630
14705
  const sessionId = readNonEmptyString2(state.instanceId);
14706
+ const stateKey = `${meshId}::${sessionId || "?"}`;
14707
+ const prevParked = coordinatorModalParkState.get(stateKey);
14708
+ if (prevParked !== modalParked) {
14709
+ coordinatorModalParkState.set(stateKey, modalParked);
14710
+ if (modalParked) {
14711
+ 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`);
14712
+ } else if (prevParked === true) {
14713
+ LOG.info("MeshReconcile", `Coordinator ${sessionId || "?"} (mesh ${meshId}) left modal-park (status=${status}) \u2014 held events will drain on this/next tick`);
14714
+ }
14715
+ }
14631
14716
  out.push({ meshId, instance: inst, sessionId, idle: status === "idle", modalParked });
14632
14717
  }
14633
14718
  return out;
@@ -14821,7 +14906,55 @@ async function runMeshReconcileTick(components) {
14821
14906
  const forceOnly = idleCoordinators.length === 0;
14822
14907
  if (targetCoordinators.length === 0) {
14823
14908
  if (modalParkedCoordinators.length > 0) {
14824
- 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)`);
14909
+ const liveSessionIds = new Set(
14910
+ meshCoordinators.map((c) => readNonEmptyString2(c.sessionId)).filter(Boolean)
14911
+ );
14912
+ let orphanEscaped = 0;
14913
+ const hasPendingForOrphanPeek = !store || (() => {
14914
+ try {
14915
+ return store.pendingEventCount(meshId) > 0;
14916
+ } catch {
14917
+ return true;
14918
+ }
14919
+ })();
14920
+ if (hasPendingForOrphanPeek) {
14921
+ let peeked = [];
14922
+ try {
14923
+ peeked = getPendingMeshCoordinatorEvents(meshId, drainDaemonIds.length > 0 ? drainDaemonIds : void 0);
14924
+ } catch {
14925
+ peeked = [];
14926
+ }
14927
+ const isOrphan = (e) => {
14928
+ const want = readNonEmptyString2(e.targetCoordinatorSessionId);
14929
+ return !!want && !liveSessionIds.has(want);
14930
+ };
14931
+ const orphanEventNames = new Set(peeked.filter(isOrphan).map((e) => e.event));
14932
+ if (orphanEventNames.size > 0) {
14933
+ let drained = [];
14934
+ try {
14935
+ drained = drainPendingMeshCoordinatorEvents(
14936
+ meshId,
14937
+ drainDaemonIds.length > 0 ? drainDaemonIds : localDaemonId,
14938
+ { onlyEvents: orphanEventNames }
14939
+ );
14940
+ } catch (e) {
14941
+ LOG.warn("MeshReconcile", `Orphan-escape drain failed for mesh ${meshId}: ${e?.message || e}`);
14942
+ drained = [];
14943
+ }
14944
+ for (const pending of drained) {
14945
+ if (isOrphan(pending)) {
14946
+ holdOrExpireStrictUnmatchedEvent(pending, readNonEmptyString2(pending.targetCoordinatorSessionId), meshId);
14947
+ orphanEscaped++;
14948
+ } else {
14949
+ try {
14950
+ queuePendingMeshCoordinatorEvent(pending);
14951
+ } catch {
14952
+ }
14953
+ }
14954
+ }
14955
+ }
14956
+ }
14957
+ 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` : ""})`);
14825
14958
  let hasPending = true;
14826
14959
  if (store) {
14827
14960
  try {
@@ -15092,6 +15225,19 @@ async function reconcileUnterminatedDirectDispatches(components, mesh, selfIds,
15092
15225
  const messages = Array.isArray(payload.messages) ? payload.messages : [];
15093
15226
  const evidence = extractFinalAssistantSummaryEvidence(messages);
15094
15227
  if (!evidence.finalSummary) continue;
15228
+ const dispatchedAtMs = Date.parse(readNonEmptyString2(dispatch.dispatchedAt));
15229
+ const transcriptAtMs = Date.parse(evidence.transcriptMessageAt ?? "");
15230
+ if (Number.isFinite(dispatchedAtMs) && Number.isFinite(transcriptAtMs) && transcriptAtMs < dispatchedAtMs) {
15231
+ 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`);
15232
+ traceMeshEventDrop("reconcile_stale_summary_before_dispatch", {
15233
+ taskId,
15234
+ sessionId,
15235
+ nodeId,
15236
+ meshId: mesh.id,
15237
+ event: "agent:generating_completed"
15238
+ }, `transcriptAt=${evidence.transcriptMessageAt} < dispatchedAt=${dispatch.dispatchedAt}`);
15239
+ continue;
15240
+ }
15095
15241
  const providerSessionId = readNonEmptyString2(payload.providerSessionId);
15096
15242
  const coordinatorDaemonId = selfIds.find((id) => !!id);
15097
15243
  try {
@@ -15219,7 +15365,7 @@ function setupMeshReconcileLoop(components) {
15219
15365
  }
15220
15366
  };
15221
15367
  }
15222
- 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;
15368
+ 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;
15223
15369
  var init_mesh_reconcile_loop = __esm({
15224
15370
  "src/mesh/mesh-reconcile-loop.ts"() {
15225
15371
  "use strict";
@@ -15241,6 +15387,7 @@ var init_mesh_reconcile_loop = __esm({
15241
15387
  init_chat_message_normalization();
15242
15388
  DEFAULT_RECONCILE_INTERVAL_MS = 4e3;
15243
15389
  DEFAULT_AUTO_PRUNE_MIN_AGE_MS = 24 * 60 * 6e4;
15390
+ coordinatorModalParkState = /* @__PURE__ */ new Map();
15244
15391
  heldEventLedgerRecorded = /* @__PURE__ */ new Set();
15245
15392
  ASSIGNED_STRANDED_DEADLINE_MS = 5 * 6e4;
15246
15393
  STRICT_SESSION_MATCH_TTL_MS = 6e4;
@@ -37810,6 +37957,8 @@ function getMessageTime(message) {
37810
37957
  }
37811
37958
  var COMPLETED_FINALIZATION_RETRY_MS = 1e3;
37812
37959
  var COMPLETED_FINALIZATION_MAX_WAIT_MS = 3e4;
37960
+ var NATIVE_HISTORY_MESH_IDLE_SETTLE_MS = 1500;
37961
+ var USER_INPUT_ACK_DEDUP_WINDOW_MS = 6e4;
37813
37962
  var TERMINAL_MESH_EVENTS = /* @__PURE__ */ new Set([
37814
37963
  "agent:generating_completed",
37815
37964
  "agent:stopped",
@@ -38081,6 +38230,14 @@ var CliProviderInstance = class _CliProviderInstance {
38081
38230
  runtimeMessages = [];
38082
38231
  lastPersistedHistoryMessages = [];
38083
38232
  lastAcknowledgedUserInputAt = 0;
38233
+ // TASKBUBBLE-DUP: per-content last-ack timestamps so the same dispatched
38234
+ // prompt acked twice in quick succession (the worker buffers the first
38235
+ // send during bootstrap/busy, then a redelivery — dispatch-confirm-timeout
38236
+ // requeue or a reconcile re-dispatch — fires a SECOND send_chat before the
38237
+ // outbound queue drains) collapses to ONE user bubble. Keyed on the trimmed
38238
+ // content; an entry older than USER_INPUT_ACK_DEDUP_WINDOW_MS is treated as
38239
+ // a fresh, intentional resend and is NOT suppressed.
38240
+ recentUserInputAcks = /* @__PURE__ */ new Map();
38084
38241
  lastNativeSourceCanonicalCheckAt = 0;
38085
38242
  lastNativeSourceCanonicalCacheKey = void 0;
38086
38243
  cachedSqliteDb = null;
@@ -38515,6 +38672,15 @@ var CliProviderInstance = class _CliProviderInstance {
38515
38672
  const content = typeof input === "string" ? input.trim() : buildCliStructuredInputPrompt(input).trim();
38516
38673
  if (!content) return;
38517
38674
  const receivedAt = Date.now();
38675
+ const ackContentKey = shortHash(`${this.instanceId}:${content}`, 24);
38676
+ const lastAckAt = this.recentUserInputAcks.get(ackContentKey);
38677
+ if (lastAckAt !== void 0 && receivedAt - lastAckAt <= USER_INPUT_ACK_DEDUP_WINDOW_MS) {
38678
+ this.recentUserInputAcks.set(ackContentKey, receivedAt);
38679
+ this.pruneRecentUserInputAcks(receivedAt);
38680
+ return;
38681
+ }
38682
+ this.recentUserInputAcks.set(ackContentKey, receivedAt);
38683
+ this.pruneRecentUserInputAcks(receivedAt);
38518
38684
  this.lastAcknowledgedUserInputAt = receivedAt;
38519
38685
  const dedupKey = `user_input_ack:${shortHash(`${this.instanceId}:${content}:${receivedAt}`, 24)}`;
38520
38686
  this.appendRuntimeMessage(buildChatMessage({
@@ -38532,6 +38698,13 @@ var CliProviderInstance = class _CliProviderInstance {
38532
38698
  }
38533
38699
  }), dedupKey);
38534
38700
  }
38701
+ /** Drop user-input ack entries older than the dedup window so the map can't grow unbounded. */
38702
+ pruneRecentUserInputAcks(now) {
38703
+ if (this.recentUserInputAcks.size <= 1) return;
38704
+ for (const [key, at] of this.recentUserInputAcks) {
38705
+ if (now - at > USER_INPUT_ACK_DEDUP_WINDOW_MS) this.recentUserInputAcks.delete(key);
38706
+ }
38707
+ }
38535
38708
  dispose() {
38536
38709
  this.adapter.shutdown();
38537
38710
  this.monitor.reset();
@@ -39221,8 +39394,9 @@ var CliProviderInstance = class _CliProviderInstance {
39221
39394
  previousStatus: this.lastStatus
39222
39395
  };
39223
39396
  const ownsExternalHistory = !!this.adapter?.chatMessagesOwnedExternally;
39224
- const flushDelay = ownsExternalHistory ? 0 : 3e3;
39225
- LOG.debug("CLI", `[${this.type}] set completedDebouncePending duration=${duration}s ownsExternalHistory=${ownsExternalHistory} flushDelay=${flushDelay}ms generatingStartedAt=${this.generatingStartedAt}`);
39397
+ const meshWorkerSession = this.isMeshWorkerSession();
39398
+ const flushDelay = ownsExternalHistory ? meshWorkerSession ? NATIVE_HISTORY_MESH_IDLE_SETTLE_MS : 0 : 3e3;
39399
+ LOG.debug("CLI", `[${this.type}] set completedDebouncePending duration=${duration}s ownsExternalHistory=${ownsExternalHistory} meshWorker=${meshWorkerSession} flushDelay=${flushDelay}ms generatingStartedAt=${this.generatingStartedAt}`);
39226
39400
  this.scheduleCompletedDebounceFlush(flushDelay);
39227
39401
  }
39228
39402
  } else if (newStatus === "idle" && this.lastStatus === "starting") {
@@ -42282,11 +42456,11 @@ var cliAgentHandlers = {
42282
42456
  }
42283
42457
  }
42284
42458
  }
42285
- const agentResult = await ctx.deps.cliManager.handleCliCommand("agent_command", args);
42286
42459
  const meshCtx = args?.meshContext;
42287
42460
  const dispatchNodeId = readStringValue(meshCtx?.nodeId);
42288
42461
  const dispatchMeshId = readStringValue(meshCtx?.meshId);
42289
- if (dispatchNodeId && dispatchMeshId && agentResult?.success !== false) {
42462
+ const isSendChat = args?.action === "send_chat";
42463
+ if (isSendChat && dispatchNodeId && dispatchMeshId) {
42290
42464
  try {
42291
42465
  const { getMesh: getMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
42292
42466
  const meshObj = getMesh2(dispatchMeshId) ?? ctx.getCachedInlineMesh(dispatchMeshId);
@@ -42294,17 +42468,22 @@ var cliAgentHandlers = {
42294
42468
  const bootstrapStatus = readStringValue(nodeObj?.worktreeBootstrap?.status);
42295
42469
  if (bootstrapStatus === "running") {
42296
42470
  return {
42297
- success: true,
42298
- ...agentResult,
42299
- dispatchAcknowledgementRisk: true,
42300
- dispatchAcknowledgementRiskReason: "bootstrap_still_running",
42301
- nextAction: "Wait for worktree_bootstrap_complete event before dispatching work to this node."
42471
+ success: false,
42472
+ recoverable: true,
42473
+ dispatched: false,
42474
+ code: "mesh_node_bootstrap_pending",
42475
+ reason: "bootstrap_still_running",
42476
+ nodeId: dispatchNodeId,
42477
+ meshId: dispatchMeshId,
42478
+ ...readStringValue(meshCtx?.taskId) ? { taskId: readStringValue(meshCtx?.taskId) } : {},
42479
+ 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.`,
42480
+ 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."
42302
42481
  };
42303
42482
  }
42304
42483
  } catch {
42305
42484
  }
42306
42485
  }
42307
- return agentResult;
42486
+ return ctx.deps.cliManager.handleCliCommand("agent_command", args);
42308
42487
  },
42309
42488
  // ─── Logs ───
42310
42489
  list_saved_sessions: async (ctx, args) => {
@@ -47426,49 +47605,72 @@ var fastForwardHandlers = {
47426
47605
  };
47427
47606
  },
47428
47607
  fast_forward_mesh_node: async (ctx, args) => {
47429
- const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
47430
- const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
47431
- let workspace = typeof args?.workspace === "string" ? args.workspace.trim() : "";
47432
- let submoduleIgnorePaths = Array.isArray(args?.submoduleIgnorePaths) ? args.submoduleIgnorePaths.filter((value) => typeof value === "string") : void 0;
47433
- let nodeDaemonId;
47434
- let allowAutoPublishSubmoduleMainCommits = false;
47435
- if (meshId && nodeId) {
47436
- const meshRecord = await ctx.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
47437
- const mesh = meshRecord?.mesh;
47438
- const node = mesh?.nodes?.find((n) => meshNodeIdMatches(n, nodeId));
47439
- if (!workspace) {
47440
- workspace = typeof node?.workspace === "string" ? node.workspace.trim() : "";
47608
+ const workspaceForError = typeof args?.workspace === "string" ? args.workspace.trim() : "";
47609
+ const meshIdForError = typeof args?.meshId === "string" ? args.meshId.trim() : "";
47610
+ const nodeIdForError = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
47611
+ try {
47612
+ const meshId = meshIdForError;
47613
+ const nodeId = nodeIdForError;
47614
+ let workspace = workspaceForError;
47615
+ let submoduleIgnorePaths = Array.isArray(args?.submoduleIgnorePaths) ? args.submoduleIgnorePaths.filter((value) => typeof value === "string") : void 0;
47616
+ let nodeDaemonId;
47617
+ let allowAutoPublishSubmoduleMainCommits = false;
47618
+ if (meshId && nodeId) {
47619
+ const meshRecord = await ctx.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
47620
+ const mesh = meshRecord?.mesh;
47621
+ const node = mesh?.nodes?.find((n) => meshNodeIdMatches(n, nodeId));
47622
+ if (!workspace) {
47623
+ workspace = typeof node?.workspace === "string" ? node.workspace.trim() : "";
47624
+ }
47625
+ if (!submoduleIgnorePaths && Array.isArray(node?.policy?.submoduleIgnorePaths)) {
47626
+ submoduleIgnorePaths = node.policy.submoduleIgnorePaths.filter((value) => typeof value === "string");
47627
+ }
47628
+ allowAutoPublishSubmoduleMainCommits = mesh?.policy?.allowAutoPublishSubmoduleMainCommits === true;
47629
+ nodeDaemonId = typeof node?.daemonId === "string" ? node.daemonId.trim() : void 0;
47441
47630
  }
47442
- if (!submoduleIgnorePaths && Array.isArray(node?.policy?.submoduleIgnorePaths)) {
47443
- submoduleIgnorePaths = node.policy.submoduleIgnorePaths.filter((value) => typeof value === "string");
47631
+ const selfDaemonId = ctx.deps.statusInstanceId;
47632
+ const isRemote = nodeDaemonId && selfDaemonId && !daemonIdsEquivalent(nodeDaemonId, selfDaemonId);
47633
+ if (isRemote && ctx.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
47634
+ const forwarded = await ctx.deps.dispatchMeshCommand(nodeDaemonId, "fast_forward_mesh_node", {
47635
+ ...typeof args === "object" && args !== null ? args : {},
47636
+ workspace,
47637
+ _meshDirectDispatch: true
47638
+ });
47639
+ return forwarded ?? { success: false, error: "no response from remote node" };
47444
47640
  }
47445
- allowAutoPublishSubmoduleMainCommits = mesh?.policy?.allowAutoPublishSubmoduleMainCommits === true;
47446
- nodeDaemonId = typeof node?.daemonId === "string" ? node.daemonId.trim() : void 0;
47447
- }
47448
- const selfDaemonId = ctx.deps.statusInstanceId;
47449
- const isRemote = nodeDaemonId && selfDaemonId && !daemonIdsEquivalent(nodeDaemonId, selfDaemonId);
47450
- if (isRemote && ctx.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
47451
- const forwarded = await ctx.deps.dispatchMeshCommand(nodeDaemonId, "fast_forward_mesh_node", {
47452
- ...typeof args === "object" && args !== null ? args : {},
47641
+ const result = await fastForwardMeshNode({
47642
+ meshId: meshId || void 0,
47643
+ nodeId: nodeId || void 0,
47453
47644
  workspace,
47454
- _meshDirectDispatch: true
47645
+ branch: typeof args?.branch === "string" ? args.branch : void 0,
47646
+ execute: args?.execute === true,
47647
+ dryRun: args?.dryRun === true,
47648
+ updateSubmodules: args?.updateSubmodules === true,
47649
+ submoduleIgnorePaths,
47650
+ mode: args?.mode === "push" ? "push" : "merge",
47651
+ pushSubmodules: args?.pushSubmodules === true,
47652
+ allowAutoPublishSubmoduleMainCommits
47455
47653
  });
47456
- return forwarded ?? { success: false, error: "no response from remote node" };
47654
+ return result;
47655
+ } catch (e) {
47656
+ const errorMessage = e?.message || String(e);
47657
+ return {
47658
+ success: false,
47659
+ code: "fast_forward_safety_gate_error",
47660
+ ...meshIdForError ? { meshId: meshIdForError } : {},
47661
+ ...nodeIdForError ? { nodeId: nodeIdForError } : {},
47662
+ workspace: workspaceForError,
47663
+ mode: args?.mode === "push" ? "push" : "merge",
47664
+ allowed: false,
47665
+ willRun: false,
47666
+ executed: false,
47667
+ // Surface the throw as a blocking reason instead of an opaque IPC crash
47668
+ // so the coordinator gets the same structured shape a clean node returns.
47669
+ blockingReasons: ["fast_forward_safety_gate_error"],
47670
+ operationError: errorMessage,
47671
+ error: errorMessage
47672
+ };
47457
47673
  }
47458
- const result = await fastForwardMeshNode({
47459
- meshId: meshId || void 0,
47460
- nodeId: nodeId || void 0,
47461
- workspace,
47462
- branch: typeof args?.branch === "string" ? args.branch : void 0,
47463
- execute: args?.execute === true,
47464
- dryRun: args?.dryRun === true,
47465
- updateSubmodules: args?.updateSubmodules === true,
47466
- submoduleIgnorePaths,
47467
- mode: args?.mode === "push" ? "push" : "merge",
47468
- pushSubmodules: args?.pushSubmodules === true,
47469
- allowAutoPublishSubmoduleMainCommits
47470
- });
47471
- return result;
47472
47674
  },
47473
47675
  refine_mesh_node: async (ctx, args) => {
47474
47676
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
@@ -47625,6 +47827,56 @@ var meshCoordinatorLaunchHandlers = {
47625
47827
  return "";
47626
47828
  }
47627
47829
  };
47830
+ const buildRecentActivityBestEffort = async (id) => {
47831
+ try {
47832
+ const { getLedgerSummary: getLedgerSummary2, readLedgerEntries: readLedgerEntries2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
47833
+ const { getMeshQueueStats: getMeshQueueStats2 } = await Promise.resolve().then(() => (init_mesh_work_queue(), mesh_work_queue_exports));
47834
+ const summary = getLedgerSummary2(id);
47835
+ const queue = getMeshQueueStats2(id);
47836
+ const failureEntries = readLedgerEntries2(id, { kind: ["task_failed"], tail: 5 });
47837
+ const recentFailures = failureEntries.map((e) => {
47838
+ const p = e.payload || {};
47839
+ const raw = typeof p.taskSummary === "string" ? p.taskSummary : typeof p.message === "string" ? p.message : typeof p.error === "string" ? p.error : "";
47840
+ const summaryText = raw.length > 160 ? `${raw.slice(0, 160)}\u2026` : raw;
47841
+ return {
47842
+ timestamp: e.timestamp,
47843
+ nodeId: e.nodeId,
47844
+ summary: summaryText
47845
+ };
47846
+ });
47847
+ return {
47848
+ recentFailures,
47849
+ recentFailureCount: summary.recentFailures,
47850
+ pendingTasks: queue.pending,
47851
+ assignedTasks: queue.assigned,
47852
+ stalledTasks: summary.taskStalled,
47853
+ lastActivityAt: summary.lastActivityAt
47854
+ };
47855
+ } catch {
47856
+ return void 0;
47857
+ }
47858
+ };
47859
+ const buildOperatingNotesBestEffort = async (id) => {
47860
+ try {
47861
+ const { readLedgerEntries: readLedgerEntries2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
47862
+ const noteEntries = readLedgerEntries2(id, { kind: ["coordinator_operating_note"], tail: 20 });
47863
+ const notes = noteEntries.map((e) => {
47864
+ const p = e.payload || {};
47865
+ const text = typeof p.text === "string" ? p.text.trim() : "";
47866
+ if (!text) return null;
47867
+ const category = p.category === "provider_quirk" || p.category === "pattern_to_avoid" || p.category === "recovery_lesson" ? p.category : void 0;
47868
+ return {
47869
+ text,
47870
+ category,
47871
+ createdAt: typeof p.createdAt === "string" ? p.createdAt : e.timestamp,
47872
+ sourceCoordinator: typeof p.sourceCoordinator === "string" ? p.sourceCoordinator : void 0
47873
+ };
47874
+ }).filter((n) => n !== null);
47875
+ return notes.length ? notes : void 0;
47876
+ } catch {
47877
+ return void 0;
47878
+ }
47879
+ };
47628
47880
  let mesh;
47629
47881
  if (args?.inlineMesh && typeof args.inlineMesh === "object") {
47630
47882
  mesh = args.inlineMesh;
@@ -47715,7 +47967,7 @@ var meshCoordinatorLaunchHandlers = {
47715
47967
  if (coordinatorSetup.kind === "cli_command") {
47716
47968
  let cliCmdSystemPrompt = "";
47717
47969
  try {
47718
- cliCmdSystemPrompt = buildCoordinatorSystemPrompt2({ mesh, coordinatorCliType: cliType, userInstruction: extraSystemPrompt || void 0, missionSection: buildMissionSectionBestEffort(mesh.id) });
47970
+ cliCmdSystemPrompt = buildCoordinatorSystemPrompt2({ mesh, coordinatorCliType: cliType, userInstruction: extraSystemPrompt || void 0, missionSection: buildMissionSectionBestEffort(mesh.id), recentActivity: await buildRecentActivityBestEffort(mesh.id), operatingNotes: await buildOperatingNotesBestEffort(mesh.id) });
47719
47971
  } catch (error) {
47720
47972
  const message = error?.message || String(error);
47721
47973
  LOG.error("MeshCoordinator", `Failed to build coordinator prompt: ${message}`);
@@ -47892,7 +48144,7 @@ ${ptyResult.output.slice(-2e3)}`);
47892
48144
  }
47893
48145
  let systemPrompt = "";
47894
48146
  try {
47895
- systemPrompt = buildCoordinatorSystemPrompt2({ mesh, coordinatorCliType: cliType, userInstruction: extraSystemPrompt || void 0, missionSection: buildMissionSectionBestEffort(mesh.id) });
48147
+ systemPrompt = buildCoordinatorSystemPrompt2({ mesh, coordinatorCliType: cliType, userInstruction: extraSystemPrompt || void 0, missionSection: buildMissionSectionBestEffort(mesh.id), recentActivity: await buildRecentActivityBestEffort(mesh.id), operatingNotes: await buildOperatingNotesBestEffort(mesh.id) });
47896
48148
  } catch (error) {
47897
48149
  const message = error?.message || String(error);
47898
48150
  LOG.error("MeshCoordinator", `Failed to build coordinator prompt: ${message}`);