@adhdev/daemon-core 0.9.82-rc.565 → 0.9.82-rc.567

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.
@@ -13,6 +13,19 @@ export interface CliAdapterStatus {
13
13
  activeModal?: {
14
14
  message: string;
15
15
  buttons: string[];
16
+ /**
17
+ * BUTTON-INDEX-MISMAP (Fix C.1): each button's label paired with its real FSM
18
+ * DISPLAYED index (evaluator's Number(m[1])). `buttons` above is the label-only list
19
+ * every existing consumer reads (array position === pick order); `buttonMeta` preserves
20
+ * the index → label mapping so a partial / non-contiguous modal (display indices [1,3,4]
21
+ * at array positions [0,1,2]) does not lose its true indices once the modal leaves the
22
+ * adapter. Present only on spec/FSM adapters; absent for adapters that surface labels
23
+ * alone.
24
+ */
25
+ buttonMeta?: {
26
+ index: number;
27
+ label: string;
28
+ }[];
16
29
  /**
17
30
  * Semantic modal class, when the adapter knows it (spec/FSM path):
18
31
  * 'approval' = tool/command/trust consent (auto-approve may fire);
@@ -155,6 +168,7 @@ export interface CliAdapter {
155
168
  resolveAction?(data: unknown): Promise<void>;
156
169
  setInteractivePromptResponse?(response: InteractivePromptResponse): Promise<void>;
157
170
  resolveModal?(buttonIndex: number): void;
171
+ resolveModalMatched?(buttonIndex: number): boolean;
158
172
  isApprovalRecentlyResolved?(): boolean;
159
173
  setOnPtyData?(callback: (data: string) => void): void;
160
174
  writeRaw?(data: string): void;
package/dist/index.js CHANGED
@@ -428,10 +428,10 @@ function readInjected(value) {
428
428
  }
429
429
  function getDaemonBuildInfo() {
430
430
  if (cached) return cached;
431
- const commit = readInjected(true ? "7e94d6ed1034781a2d3b9857c3217eff63a8cbfd" : void 0) ?? "unknown";
432
- const commitShort = readInjected(true ? "7e94d6ed" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
433
- const version = readInjected(true ? "0.9.82-rc.565" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
434
- const builtAt = readInjected(true ? "2026-07-18T04:28:04.680Z" : void 0);
431
+ const commit = readInjected(true ? "86f8d403efe203d7ff1d9b6997ede5f30620a485" : void 0) ?? "unknown";
432
+ const commitShort = readInjected(true ? "86f8d403" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
433
+ const version = readInjected(true ? "0.9.82-rc.567" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
434
+ const builtAt = readInjected(true ? "2026-07-18T09:04:16.210Z" : void 0);
435
435
  cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
436
436
  return cached;
437
437
  }
@@ -14974,12 +14974,16 @@ function buildMeshActiveWork(opts) {
14974
14974
  for (const task of opts.queue || []) {
14975
14975
  if (task.status !== "pending" && task.status !== "assigned") continue;
14976
14976
  const { title, summary: summary2 } = summarizeMessage(task.message || "");
14977
+ const queueNodeId = task.assignedNodeId || task.targetNodeId;
14978
+ const queueSessionId = task.assignedSessionId || task.targetSessionId;
14979
+ const queueLive = task.status === "assigned" ? sessionStatusFromNodes(opts.nodes, queueNodeId ?? void 0, queueSessionId ?? void 0) : {};
14980
+ const queueStatus = queueLive.status === "awaiting_approval" || queueLive.status === "generating" ? queueLive.status : task.status;
14977
14981
  records.push({
14978
14982
  taskId: task.id,
14979
14983
  source: "queue",
14980
- status: task.status,
14981
- nodeId: task.assignedNodeId || task.targetNodeId,
14982
- sessionId: task.assignedSessionId || task.targetSessionId,
14984
+ status: queueStatus,
14985
+ nodeId: queueNodeId,
14986
+ sessionId: queueSessionId,
14983
14987
  taskTitle: title,
14984
14988
  taskSummary: summary2,
14985
14989
  message: task.message,
@@ -20562,12 +20566,15 @@ function evaluateMeshEventSuppression(args, ctx) {
20562
20566
  }
20563
20567
  return null;
20564
20568
  }
20565
- function sourceWorkerAutoApproves(components, sessionId) {
20569
+ function shouldSuppressAutoApprovingWorkerApproval(components, sessionId) {
20566
20570
  if (!sessionId) return false;
20567
20571
  try {
20568
- const state = components.instanceManager?.getInstance?.(sessionId)?.getState?.();
20572
+ const instance = components.instanceManager?.getInstance?.(sessionId);
20573
+ const state = instance?.getState?.();
20569
20574
  const settings = state?.settings || {};
20570
- return settings.autoApprove === true;
20575
+ if (settings.autoApprove !== true) return false;
20576
+ const resolvedLocally = instance?.approvalRecentlyResolvedLocally;
20577
+ return typeof resolvedLocally === "function" ? resolvedLocally.call(instance) === true : false;
20571
20578
  } catch {
20572
20579
  return false;
20573
20580
  }
@@ -20712,8 +20719,8 @@ function injectMeshSystemMessage(components, args) {
20712
20719
  }
20713
20720
  }
20714
20721
  const eventTimestamp = readEventTimestamp(args.metadataEvent.timestamp);
20715
- if (args.event === "agent:waiting_approval" && sourceWorkerAutoApproves(components, eventSessionId)) {
20716
- LOG.info("MeshEvents", `Suppressed agent:waiting_approval for auto-approving worker session ${eventSessionId || "(unknown)"} (mesh ${args.meshId}) \u2014 modal is resolved locally, coordinator not notified`);
20722
+ if (args.event === "agent:waiting_approval" && shouldSuppressAutoApprovingWorkerApproval(components, eventSessionId)) {
20723
+ LOG.info("MeshEvents", `Suppressed agent:waiting_approval for auto-approving worker session ${eventSessionId || "(unknown)"} (mesh ${args.meshId}) \u2014 modal resolved locally within cooldown, coordinator not notified`);
20717
20724
  traceMeshEventDrop("waiting_approval_auto_approving_worker", traceCtx);
20718
20725
  return { success: true, forwarded: 0, suppressed: true, autoApprovingWorkerApproval: true };
20719
20726
  }
@@ -22412,6 +22419,14 @@ function drainAndDeliverApprovalNudges(meshId, drainDaemonIds, localDaemonId, me
22412
22419
  }
22413
22420
  return delivered;
22414
22421
  }
22422
+ function assignedRowLiveStatusIsAwaitingApproval(mesh, nodeId, sessionId) {
22423
+ if (!nodeId || !sessionId) return false;
22424
+ try {
22425
+ return sessionStatusFromNodes(mesh.nodes, nodeId, sessionId).status === "awaiting_approval";
22426
+ } catch {
22427
+ return false;
22428
+ }
22429
+ }
22415
22430
  async function recoverStrandedAssignedDispatches(components, mesh, store) {
22416
22431
  const meshId = mesh.id;
22417
22432
  const assigned = getQueue(meshId, { status: ["assigned"] });
@@ -22443,6 +22458,15 @@ async function recoverStrandedAssignedDispatches(components, mesh, store) {
22443
22458
  } else {
22444
22459
  if (verdict === "IDLE_CONFIRMED") {
22445
22460
  deliveredUnconsumedUnknownStreak.delete(shortStreakKey);
22461
+ } else if (assignedRowLiveStatusIsAwaitingApproval(mesh, row.assignedNodeId, row.assignedSessionId)) {
22462
+ traceMeshEventDrop("short_redrive_deferred_awaiting_approval", {
22463
+ taskId: row.id,
22464
+ sessionId: row.assignedSessionId,
22465
+ nodeId: row.assignedNodeId,
22466
+ meshId,
22467
+ event: "agent:waiting_approval"
22468
+ }, "live_awaiting_approval");
22469
+ continue;
22446
22470
  } else {
22447
22471
  const streak = (deliveredUnconsumedUnknownStreak.get(shortStreakKey) ?? 0) + 1;
22448
22472
  deliveredUnconsumedUnknownStreak.set(shortStreakKey, streak);
@@ -22505,6 +22529,15 @@ async function recoverStrandedAssignedDispatches(components, mesh, store) {
22505
22529
  if (verdict === "IDLE_CONFIRMED") {
22506
22530
  deliveredNoTurnUnknownStreak.delete(streakKey);
22507
22531
  reclaimReason = "delivered_no_turn_deadline";
22532
+ } else if (assignedRowLiveStatusIsAwaitingApproval(mesh, row.assignedNodeId, row.assignedSessionId)) {
22533
+ traceMeshEventDrop("reclaim_deferred_awaiting_approval", {
22534
+ taskId: row.id,
22535
+ sessionId: row.assignedSessionId,
22536
+ nodeId: row.assignedNodeId,
22537
+ meshId,
22538
+ event: "agent:waiting_approval"
22539
+ }, "live_awaiting_approval");
22540
+ continue;
22508
22541
  } else {
22509
22542
  const streak = (deliveredNoTurnUnknownStreak.get(streakKey) ?? 0) + 1;
22510
22543
  deliveredNoTurnUnknownStreak.set(streakKey, streak);
@@ -23072,6 +23105,7 @@ var init_mesh_reconcile_loop = __esm({
23072
23105
  init_mesh_reconcile_config();
23073
23106
  init_mesh_remote_event_pull();
23074
23107
  init_mesh_completion_synthesis();
23108
+ init_mesh_active_work();
23075
23109
  init_mesh_reconcile_v2_backstop();
23076
23110
  init_mesh_reconcile_acked_hold();
23077
23111
  coordinatorModalParkState = /* @__PURE__ */ new Map();
@@ -39441,7 +39475,13 @@ async function handleResolveAction(h, args) {
39441
39475
  LOG.info("Command", `[resolveAction] CLI PTY \u2192 stale_prompt (already resolved within cooldown)`);
39442
39476
  return { success: true, stalePrompt: true, buttonIndex, button: buttons[buttonIndex] ?? button };
39443
39477
  }
39444
- if (typeof adapter.resolveModal === "function") {
39478
+ if (typeof adapter.resolveModalMatched === "function") {
39479
+ const matched = adapter.resolveModalMatched(buttonIndex);
39480
+ if (!matched) {
39481
+ LOG.warn("Command", `[resolveAction] CLI PTY \u2192 no button matched for buttonIndex=${buttonIndex} "${buttons[buttonIndex] ?? "?"}" (modal not resolved)`);
39482
+ return { success: false, error: "Approval button index did not map to a visible modal button", buttonIndex, button: buttons[buttonIndex] ?? button };
39483
+ }
39484
+ } else if (typeof adapter.resolveModal === "function") {
39445
39485
  adapter.resolveModal(buttonIndex);
39446
39486
  } else {
39447
39487
  const keys = "\x1B[B".repeat(Math.max(0, buttonIndex)) + "\r";
@@ -44034,7 +44074,7 @@ var FsmDriver = class {
44034
44074
  this.handleClickControl(cmd.control_id, cmd.payload);
44035
44075
  return;
44036
44076
  case "click_modal_button":
44037
- this.handleClickModalButton(cmd.index);
44077
+ this.clickModalButton(cmd.index);
44038
44078
  return;
44039
44079
  case "attach_image":
44040
44080
  this.handleAttachImage(cmd.blob, cmd.mime);
@@ -44777,11 +44817,24 @@ var FsmDriver = class {
44777
44817
  }
44778
44818
  }
44779
44819
  }
44820
+ /**
44821
+ * BUTTON-INDEX-MISMAP (Fix C.3): public modal-click entry that returns whether a button
44822
+ * matching the requested FSM display index was actually found and its confirm keys were
44823
+ * dispatched. The old private handleClickModalButton silently `return`ed on a miss (no
44824
+ * modal captured, or no button whose `.index` equals the requested display index), so a
44825
+ * mis-mapped index looked identical to a successful press. Callers that need to know
44826
+ * whether the click landed (mesh_approve → resolveModal) can now observe the miss instead
44827
+ * of reporting success into the void. The generic `dispatch('click_modal_button')` path
44828
+ * keeps ignoring the return (fire-and-forget UI clicks).
44829
+ */
44830
+ clickModalButton(index) {
44831
+ return this.handleClickModalButton(index);
44832
+ }
44780
44833
  handleClickModalButton(index) {
44781
44834
  const m = this.currentEval?.modal;
44782
- if (!m) return;
44835
+ if (!m) return false;
44783
44836
  const btn = m.buttons.find((b) => b.index === index);
44784
- if (!btn) return;
44837
+ if (!btn) return false;
44785
44838
  const rule = stateById(this.spec, this.currentStateId)?.extract?.buttons;
44786
44839
  if (rule?.select_mode === "arrow_keys") {
44787
44840
  const from = m.buttons.find((b) => b.current)?.index ?? 1;
@@ -44793,9 +44846,10 @@ var FsmDriver = class {
44793
44846
  const confirm = (rule.key_for_index || "\r").replace(/\{index\}/g, "") || "\r";
44794
44847
  if (nav) this.adapter.send_keys(nav);
44795
44848
  this.submitModalConfirm(confirm);
44796
- return;
44849
+ return true;
44797
44850
  }
44798
44851
  this.submitModalConfirm(btn.key);
44852
+ return true;
44799
44853
  }
44800
44854
  /**
44801
44855
  * Submit a modal-confirm key sequence (the choice key + its trailing CR).
@@ -46227,7 +46281,20 @@ var SpecCliAdapter = class _SpecCliAdapter {
46227
46281
  // modal this frame still stays waiting_approval (no activeModal yet).
46228
46282
  // `kind` carries the semantic modal class through to the auto-approve
46229
46283
  // gate so a /model picker (kind='picker') is never auto-answered.
46230
- activeModal: modal ? { message: modal.title ?? state.label, buttons: modal.buttons.map((b) => b.label), kind: modal.kind ?? null } : null,
46284
+ // BUTTON-INDEX-MISMAP (Fix C.1): keep `buttons` as the label list every
46285
+ // existing consumer (pickApprovalButton, mesh_approve, auto-approve) reads,
46286
+ // but ALSO surface `buttonMeta` carrying each button's real FSM display index
46287
+ // alongside its label. A partial/non-contiguous modal (display indices [1,3,4]
46288
+ // at array positions [0,1,2]) then no longer loses the index → label mapping
46289
+ // once it leaves the adapter: a consumer that has an array position can recover
46290
+ // the true FSM index without re-parsing. resolveModal() below relies on the same
46291
+ // ordered list to translate an array position to the correct FSM index.
46292
+ activeModal: modal ? {
46293
+ message: modal.title ?? state.label,
46294
+ buttons: modal.buttons.map((b) => b.label),
46295
+ buttonMeta: modal.buttons.map((b) => ({ index: b.index, label: b.label })),
46296
+ kind: modal.kind ?? null
46297
+ } : null,
46231
46298
  activeInteractivePrompt: this.activeInteractivePrompt,
46232
46299
  ...sessionFields
46233
46300
  };
@@ -46399,7 +46466,12 @@ var SpecCliAdapter = class _SpecCliAdapter {
46399
46466
  this.driver.dispatch({ kind: "resize", cols, rows });
46400
46467
  }
46401
46468
  resolveModal(buttonIndex) {
46402
- this.driver.dispatch({ kind: "click_modal_button", index: buttonIndex + 1 });
46469
+ this.resolveModalMatched(buttonIndex);
46470
+ }
46471
+ resolveModalMatched(buttonIndex) {
46472
+ const buttons = this.latestModal?.buttons ?? [];
46473
+ const target = buttonIndex >= 0 && buttonIndex < buttons.length ? buttons[buttonIndex].index : buttonIndex + 1;
46474
+ return this.driver.clickModalButton(target);
46403
46475
  }
46404
46476
  async resolveAction(data) {
46405
46477
  const args = data && typeof data === "object" ? data : {};
@@ -47559,6 +47631,15 @@ var CliProviderInstance = class _CliProviderInstance {
47559
47631
  * keystroke until the modal *content* has settled.
47560
47632
  */
47561
47633
  static AUTO_APPROVE_SETTLE_MS = 600;
47634
+ /**
47635
+ * APPROVAL-INBOX-BLINDSPOT (Fix A): how long after a LOCAL auto-approve fire the mesh
47636
+ * event forwarder still treats the modal as "being resolved locally" and suppresses the
47637
+ * coordinator notification. Chosen to comfortably cover the resolveModal → PTY absorb →
47638
+ * status-leaves-approval round trip (incl. the win32 CR-resend loop) while staying short
47639
+ * enough that a modal which auto-approve fired at but did NOT resolve re-surfaces to the
47640
+ * coordinator on the next event. Aligned with the adapter's own approval cooldown scale.
47641
+ */
47642
+ static APPROVAL_LOCAL_RESOLUTION_COOLDOWN_MS = 8e3;
47562
47643
  /**
47563
47644
  * Busy-side hysteresis for the settle gate. A momentary `generating` flip
47564
47645
  * while the SAME approval modal's button block is still on screen (its
@@ -47831,6 +47912,16 @@ var CliProviderInstance = class _CliProviderInstance {
47831
47912
  // signature) while a genuinely closed modal — buttons empty continuously past
47832
47913
  // the continuity window — is still recognised and resets the gate.
47833
47914
  autoApproveLastModalSeenAt = 0;
47915
+ // APPROVAL-INBOX-BLINDSPOT (Fix A): wall-clock of the last time this session actually
47916
+ // FIRED a local auto-approve resolveModal (the settle gate passed → resolveModal
47917
+ // dispatched). The mesh event forwarder keys its agent:waiting_approval suppression on
47918
+ // this + a cooldown so it only drops the coordinator notification when we can positively
47919
+ // confirm the modal was (or is being) resolved LOCALLY. If auto-approve is merely
47920
+ // *configured* on but has NOT recently fired for this modal, the raw waiting_approval is
47921
+ // forwarded so a task_approval_needed ledger row is created and the coordinator/inbox is
47922
+ // told — closing the blind spot where a never-resolving worker approval was silently
47923
+ // dropped just because settings.autoApprove===true.
47924
+ lastAutoApproveFiredAt = 0;
47834
47925
  // AUTOAPPROVE-FLAP-INBOX-MISSING sticky-approval overlay (see APPROVAL_STICKY_FLAP_MS).
47835
47926
  // The wall-clock of the last frame where the RAW adapter reported waiting_approval with
47836
47927
  // a CONCRETE modal (buttons present), the cached modal to re-present across a busy blip,
@@ -48316,6 +48407,33 @@ var CliProviderInstance = class _CliProviderInstance {
48316
48407
  }
48317
48408
  return null;
48318
48409
  }
48410
+ /**
48411
+ * APPROVAL-INBOX-BLINDSPOT (Fix A): true when this session's approval modal was — or is
48412
+ * being — resolved LOCALLY within the recent cooldown. Two independent positive signals:
48413
+ * (1) auto-approve fired its resolveModal within APPROVAL_LOCAL_RESOLUTION_COOLDOWN_MS
48414
+ * (lastAutoApproveFiredAt), or
48415
+ * (2) the underlying adapter reports isApprovalRecentlyResolved() — its own resolve
48416
+ * cooldown, which also covers a dashboard / mesh_approve resolution.
48417
+ * The mesh event forwarder uses this to decide whether an agent:waiting_approval from an
48418
+ * auto-approving worker can be safely SUPPRESSED (a local resolution is in flight) or must
48419
+ * be FORWARDED (auto-approve is configured but has NOT actually resolved this modal, so the
48420
+ * coordinator/inbox must be told). Keying suppression on real resolution — not just the
48421
+ * autoApprove *intent* — is the blind-spot fix: a never-resolving worker approval is no
48422
+ * longer silently dropped.
48423
+ */
48424
+ approvalRecentlyResolvedLocally(now = Date.now()) {
48425
+ if (this.lastAutoApproveFiredAt && now - this.lastAutoApproveFiredAt < _CliProviderInstance.APPROVAL_LOCAL_RESOLUTION_COOLDOWN_MS) {
48426
+ return true;
48427
+ }
48428
+ try {
48429
+ const adapter = this.adapter;
48430
+ if (typeof adapter.isApprovalRecentlyResolved === "function") {
48431
+ return adapter.isApprovalRecentlyResolved() === true;
48432
+ }
48433
+ } catch {
48434
+ }
48435
+ return false;
48436
+ }
48319
48437
  /**
48320
48438
  * NOTIF-HELD-DRAIN: true when this `waiting_approval` is a routine, transient tool-consent
48321
48439
  * of an autonomously-progressing mesh session rather than a genuine human-await modal —
@@ -49666,8 +49784,18 @@ ${buttons.join("\n")}`;
49666
49784
  this.lastAutoApprovalSignature = "";
49667
49785
  }, 5e3);
49668
49786
  this.recordAutoApproval(modal?.message, buttonLabel, now);
49787
+ this.lastAutoApproveFiredAt = now;
49669
49788
  setTimeout(() => {
49670
- this.adapter.resolveModal(buttonIndex);
49789
+ const adapter = this.adapter;
49790
+ if (typeof adapter.resolveModalMatched === "function") {
49791
+ const matched = adapter.resolveModalMatched(buttonIndex);
49792
+ if (!matched) {
49793
+ if (this.lastAutoApproveFiredAt === now) this.lastAutoApproveFiredAt = 0;
49794
+ LOG.warn("CLI", `[${this.type}] auto-approve resolveModal matched no button (index ${buttonIndex}) \u2014 surfacing approval to coordinator`);
49795
+ }
49796
+ } else {
49797
+ adapter.resolveModal?.(buttonIndex);
49798
+ }
49671
49799
  }, 0);
49672
49800
  return autoApproveActive;
49673
49801
  }