@adhdev/daemon-core 0.9.82-rc.354 → 0.9.82-rc.355

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 ? "5d100a177f412ae29a58048f0a211c3928b06910" : void 0) ?? "unknown";
315
- const commitShort = readInjected(true ? "5d100a17" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
316
- const version = readInjected(true ? "0.9.82-rc.354" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
317
- const builtAt = readInjected(true ? "2026-06-22T11:32:05.389Z" : void 0);
314
+ const commit = readInjected(true ? "a45106605e2ae1c10c0bc6cbe48c2cac4e862ded" : void 0) ?? "unknown";
315
+ const commitShort = readInjected(true ? "a4510660" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
316
+ const version = readInjected(true ? "0.9.82-rc.355" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
317
+ const builtAt = readInjected(true ? "2026-06-22T15:21:19.981Z" : void 0);
318
318
  cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
319
319
  return cached;
320
320
  }
@@ -4822,9 +4822,12 @@ function getActiveDirectDispatches(meshId) {
4822
4822
  return [];
4823
4823
  }
4824
4824
  }
4825
- function updateDirectDispatchStatus(meshId, sessionId, status) {
4825
+ function updateDirectDispatchStatus(meshId, sessionId, status, taskId) {
4826
4826
  try {
4827
- MeshRuntimeStore.getInstance().updateDirectDispatchStatus(meshId, sessionId, status);
4827
+ if (!taskId) {
4828
+ LOG.warn("MeshQueue", `updateDirectDispatchStatus(${status}) for mesh ${meshId} session ${sessionId} has no taskId \u2014 falling back to session_id match (may flip a sibling dispatch row)`);
4829
+ }
4830
+ MeshRuntimeStore.getInstance().updateDirectDispatchStatus(meshId, sessionId, status, taskId);
4828
4831
  } catch {
4829
4832
  }
4830
4833
  }
@@ -5656,9 +5659,25 @@ var init_mesh_runtime_store = __esm({
5656
5659
  updatedAt: r.updated_at
5657
5660
  }));
5658
5661
  }
5659
- updateDirectDispatchStatus(meshId, sessionId, status) {
5660
- if (!sessionId) return;
5662
+ // CANON-B (dispatch identity): mesh_direct_dispatches is keyed by task_id (PK), but a
5663
+ // single session can host several sequential direct dispatches (re-dispatch / nudge), so
5664
+ // matching a status flip by session_id alone hits EVERY non-terminal row for that session
5665
+ // — flipping a sibling task's row and stranding the one whose event actually fired (the
5666
+ // assigned-stranded watchdog then requeues a task that is really still generating). When
5667
+ // the firing event carries a taskId, target the single PK row; the session_id match is the
5668
+ // legacy fallback only for events that arrive without a taskId.
5669
+ updateDirectDispatchStatus(meshId, sessionId, status, taskId) {
5661
5670
  const now = (/* @__PURE__ */ new Date()).toISOString();
5671
+ if (taskId) {
5672
+ this.db.prepare(`
5673
+ UPDATE mesh_direct_dispatches
5674
+ SET status = @status, updated_at = @updatedAt
5675
+ WHERE mesh_id = @meshId AND task_id = @taskId
5676
+ AND status NOT IN ('completed', 'failed')
5677
+ `).run({ status, meshId, taskId, updatedAt: now });
5678
+ return;
5679
+ }
5680
+ if (!sessionId) return;
5662
5681
  this.db.prepare(`
5663
5682
  UPDATE mesh_direct_dispatches
5664
5683
  SET status = @status, updated_at = @updatedAt
@@ -7387,7 +7406,7 @@ function resolveWin32Executable(command) {
7387
7406
  windowsHide: true
7388
7407
  }).trim();
7389
7408
  if (out) {
7390
- const matches = out.split(/\r?\n/).map((s) => s.trim()).filter(Boolean);
7409
+ const matches = out.split(/\r?\n/).map((s2) => s2.trim()).filter(Boolean);
7391
7410
  const direct = matches.find((m) => DIRECT_EXEC_EXT.has(path10.extname(m).toLowerCase()));
7392
7411
  return direct || matches[0] || command;
7393
7412
  }
@@ -8739,11 +8758,29 @@ function hasPendingRefineTerminalEventDuplicate(event) {
8739
8758
  (pending) => pending.event === event.event && readRefineJobId2(pending) === jobId
8740
8759
  );
8741
8760
  }
8761
+ function isWeakCompletionMetadata(metadata) {
8762
+ const evidenceLevel = readNonEmptyString2(metadata.evidenceLevel);
8763
+ if (evidenceLevel === "insufficient" || evidenceLevel === "weak") return true;
8764
+ if (metadata.reviewRecommended === true) return true;
8765
+ const diag = readRecord4(metadata.completionDiagnostic);
8766
+ return diag?.finalAssistantPresent === false || diag?.blockReason === "missing_final_assistant";
8767
+ }
8742
8768
  function buildPendingEventFingerprint(event) {
8743
8769
  const metadata = readRecord4(event.metadataEvent) || {};
8744
8770
  if (event.event === "worktree_bootstrap_complete" || event.event === "worktree_bootstrap_failed") {
8745
8771
  return [event.meshId, event.event, event.nodeId || ""].join("::");
8746
8772
  }
8773
+ if (TERMINAL_COMPLETION_EVENTS.has(event.event)) {
8774
+ const terminalTaskId = readNonEmptyString2(metadata.taskId) || readNonEmptyString2(readRecord4(metadata.payload)?.taskId);
8775
+ if (terminalTaskId) {
8776
+ return [
8777
+ event.meshId,
8778
+ event.event,
8779
+ terminalTaskId,
8780
+ isWeakCompletionMetadata(metadata) ? "weak" : "genuine"
8781
+ ].join("::");
8782
+ }
8783
+ }
8747
8784
  const sessionId = resolveEventSessionId(metadata);
8748
8785
  const providerSessionId = readNonEmptyString2(metadata.providerSessionId);
8749
8786
  const taskId = readNonEmptyString2(metadata.taskId) || readNonEmptyString2(readRecord4(metadata.payload)?.taskId);
@@ -9102,7 +9139,7 @@ function clearPendingMeshCoordinatorEvents(meshId, coordinatorDaemonId) {
9102
9139
  }
9103
9140
  }
9104
9141
  }
9105
- var REFINE_TERMINAL_EVENTS, MAX_PENDING_EVENTS_BYTES, MAX_PENDING_EVENTS_KEEP;
9142
+ var REFINE_TERMINAL_EVENTS, TERMINAL_COMPLETION_EVENTS, MAX_PENDING_EVENTS_BYTES, MAX_PENDING_EVENTS_KEEP;
9106
9143
  var init_mesh_events_pending = __esm({
9107
9144
  "src/mesh/mesh-events-pending.ts"() {
9108
9145
  "use strict";
@@ -9112,6 +9149,7 @@ var init_mesh_events_pending = __esm({
9112
9149
  init_mesh_events_utils();
9113
9150
  init_dist();
9114
9151
  REFINE_TERMINAL_EVENTS = /* @__PURE__ */ new Set(["refine:completed", "refine:failed"]);
9152
+ TERMINAL_COMPLETION_EVENTS = /* @__PURE__ */ new Set(["agent:generating_completed", "agent:stopped"]);
9115
9153
  MAX_PENDING_EVENTS_BYTES = 100 * 1024;
9116
9154
  MAX_PENDING_EVENTS_KEEP = 50;
9117
9155
  }
@@ -9441,7 +9479,7 @@ function reconcileDirectDispatchCompletionFromTranscript(args) {
9441
9479
  evidence
9442
9480
  }
9443
9481
  });
9444
- updateDirectDispatchStatus(args.meshId, args.sessionId, kind === "task_completed" ? "completed" : "failed");
9482
+ updateDirectDispatchStatus(args.meshId, args.sessionId, kind === "task_completed" ? "completed" : "failed", args.taskId);
9445
9483
  markSessionDeliveriesTerminal(args.meshId, args.sessionId, kind === "task_completed" ? "completed" : "failed");
9446
9484
  setImmediate(() => cleanupTerminalDirectDispatches());
9447
9485
  queuePendingMeshCoordinatorEvent({
@@ -9736,8 +9774,8 @@ function parsePatternEntry(x) {
9736
9774
  if (x instanceof RegExp) return x;
9737
9775
  if (x && typeof x === "object" && typeof x.source === "string") {
9738
9776
  try {
9739
- const s = x;
9740
- return new RegExp(s.source, s.flags || "");
9777
+ const s2 = x;
9778
+ return new RegExp(s2.source, s2.flags || "");
9741
9779
  } catch {
9742
9780
  return null;
9743
9781
  }
@@ -10305,6 +10343,38 @@ var init_mesh_unresolved_forward_outbox = __esm({
10305
10343
  }
10306
10344
  });
10307
10345
 
10346
+ // src/mesh/mesh-event-trace.ts
10347
+ function s(v) {
10348
+ return typeof v === "string" && v.trim() ? v.trim() : "";
10349
+ }
10350
+ function meshEventTraceKey(ctx) {
10351
+ const segs = [`task=${s(ctx.taskId) || "-"}`];
10352
+ const eventId = s(ctx.eventId);
10353
+ if (eventId) segs.push(`evt=${eventId}`);
10354
+ segs.push(`sess=${s(ctx.sessionId) || "-"}`);
10355
+ const nodeId = s(ctx.nodeId);
10356
+ if (nodeId) segs.push(`node=${nodeId}`);
10357
+ const meshId = s(ctx.meshId);
10358
+ if (meshId) segs.push(`mesh=${meshId}`);
10359
+ const event = s(ctx.event);
10360
+ if (event) segs.push(`event=${event}`);
10361
+ return segs.join(" ");
10362
+ }
10363
+ function traceMeshEventStage(stage, ctx, detail) {
10364
+ LOG.info(CAT, `[stage:${stage}] ${meshEventTraceKey(ctx)}${detail ? ` \u2014 ${detail}` : ""}`);
10365
+ }
10366
+ function traceMeshEventDrop(reason, ctx, detail) {
10367
+ LOG.warn(CAT, `[drop:${reason}] ${meshEventTraceKey(ctx)}${detail ? ` \u2014 ${detail}` : ""}`);
10368
+ }
10369
+ var CAT;
10370
+ var init_mesh_event_trace = __esm({
10371
+ "src/mesh/mesh-event-trace.ts"() {
10372
+ "use strict";
10373
+ init_logger();
10374
+ CAT = "EvtTrace";
10375
+ }
10376
+ });
10377
+
10308
10378
  // src/config/state-store.ts
10309
10379
  import { existsSync as existsSync16, readFileSync as readFileSync12, writeFileSync as writeFileSync7 } from "fs";
10310
10380
  import { join as join18 } from "path";
@@ -12090,9 +12160,9 @@ function buildAcpSession(state, options) {
12090
12160
  }
12091
12161
  function buildSessionEntries(allStates, cdpManagers, options = {}) {
12092
12162
  const sessions = [];
12093
- const ideStates = allStates.filter((s) => s.category === "ide");
12094
- const cliStates = allStates.filter((s) => s.category === "cli");
12095
- const acpStates = allStates.filter((s) => s.category === "acp");
12163
+ const ideStates = allStates.filter((s2) => s2.category === "ide");
12164
+ const cliStates = allStates.filter((s2) => s2.category === "cli");
12165
+ const acpStates = allStates.filter((s2) => s2.category === "acp");
12096
12166
  for (const state of ideStates) {
12097
12167
  sessions.push(buildWorkspaceSession(state, cdpManagers, options));
12098
12168
  for (const ext of state.extensions) {
@@ -12577,6 +12647,15 @@ function getCachedMeshByWorkspace(workspace) {
12577
12647
  meshByWorkspaceCache.set(workspace, { mesh, cachedAt: now });
12578
12648
  return mesh;
12579
12649
  }
12650
+ function recoverMeshIdByNodeId(nodeId) {
12651
+ if (!nodeId) return "";
12652
+ for (const mesh of listMeshes()) {
12653
+ if (Array.isArray(mesh.nodes) && mesh.nodes.some((n) => meshNodeIdMatches(n, nodeId))) {
12654
+ return readNonEmptyString2(mesh.id);
12655
+ }
12656
+ }
12657
+ return "";
12658
+ }
12580
12659
  function __resetIdleAutoFastForwardForTests() {
12581
12660
  idleAutoFastForwardLastAttempt.clear();
12582
12661
  }
@@ -13479,6 +13558,13 @@ function shouldForceInjectMeshEvent(eventName) {
13479
13558
  function injectMeshSystemMessage(components, args) {
13480
13559
  const eventSessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
13481
13560
  const eventNodeId = readNonEmptyString2(args.nodeId) || readNonEmptyString2(args.metadataEvent.meshNodeId);
13561
+ const traceCtx = {
13562
+ taskId: args.metadataEvent.taskId,
13563
+ sessionId: eventSessionId,
13564
+ nodeId: eventNodeId,
13565
+ meshId: args.meshId,
13566
+ event: args.event
13567
+ };
13482
13568
  const sourceSession = args.sourceInstanceId ? components.instanceManager.getInstance(args.sourceInstanceId) : void 0;
13483
13569
  const workerCoordinatorDaemonId = readNonEmptyString2(
13484
13570
  sourceSession?.getState()?.settings?.meshCoordinatorDaemonId
@@ -13532,6 +13618,7 @@ function injectMeshSystemMessage(components, args) {
13532
13618
  }
13533
13619
  }
13534
13620
  LOG.info("MeshEvents", `Suppressed ${args.event} for intentionally cleanup-stopped session ${eventSessionId || "(unknown session)"}`);
13621
+ traceMeshEventDrop("intentional_cleanup_stop", traceCtx);
13535
13622
  return { success: true, forwarded: 0, suppressed: true, intentionalCleanupStop: true };
13536
13623
  }
13537
13624
  if (args.event === "monitor:no_progress") {
@@ -13552,6 +13639,7 @@ function injectMeshSystemMessage(components, args) {
13552
13639
  }
13553
13640
  if (reconciledCompletion?.source === "no_progress_terminal_ledger_suppression") {
13554
13641
  LOG.info("MeshEvents", `Suppressed no-progress monitor because terminal ledger evidence already exists for session ${eventSessionId || "(unknown session)"}`);
13642
+ traceMeshEventDrop("no_progress_terminal_ledger_suppression", traceCtx, `terminalKind=${reconciledCompletion.terminalLedgerKind}`);
13555
13643
  return {
13556
13644
  success: true,
13557
13645
  forwarded: 0,
@@ -13563,6 +13651,7 @@ function injectMeshSystemMessage(components, args) {
13563
13651
  }
13564
13652
  if (isDuplicateRefineTerminalEvent(args.meshId, args.event, args.metadataEvent)) {
13565
13653
  LOG.info("MeshEvents", `Suppressed duplicate ${args.event} for refine job ${readRefineJobId({ metadataEvent: args.metadataEvent })}`);
13654
+ traceMeshEventDrop("duplicate_refine_terminal", traceCtx);
13566
13655
  return { success: true, forwarded: 0, suppressed: true, duplicateRefineTerminalEvent: true };
13567
13656
  }
13568
13657
  const eventTimestamp = readEventTimestamp(args.metadataEvent.timestamp);
@@ -13577,6 +13666,7 @@ function injectMeshSystemMessage(components, args) {
13577
13666
  });
13578
13667
  if (duplicateApproval) {
13579
13668
  LOG.info("MeshEvents", `Suppressed duplicate approval event for mesh ${args.meshId} session ${eventSessionId}`);
13669
+ traceMeshEventDrop("duplicate_approval", traceCtx);
13580
13670
  return { success: true, forwarded: 0, suppressed: true, duplicateApproval: true };
13581
13671
  }
13582
13672
  }
@@ -13596,6 +13686,7 @@ function injectMeshSystemMessage(components, args) {
13596
13686
  const eventFinalSummary = readNonEmptyString2(args.metadataEvent.finalSummary);
13597
13687
  if (terminalProviderSessionId && terminalProviderSessionId === eventProviderSessionId || terminalFinalSummary && terminalFinalSummary === eventFinalSummary || args.metadataEvent.source === "no_progress_reconciliation") {
13598
13688
  LOG.info("MeshEvents", `Suppressed duplicate completion with existing terminal ledger evidence for mesh ${args.meshId} session ${eventSessionId}`);
13689
+ traceMeshEventDrop("duplicate_completion_terminal_ledger", traceCtx);
13599
13690
  return { success: true, forwarded: 0, suppressed: true, duplicateCompletion: true, terminalLedgerEvidence: true };
13600
13691
  }
13601
13692
  }
@@ -13614,6 +13705,7 @@ function injectMeshSystemMessage(components, args) {
13614
13705
  });
13615
13706
  if (duplicateCompletion) {
13616
13707
  LOG.info("MeshEvents", `Suppressed duplicate completion for mesh ${args.meshId} session ${eventSessionId}`);
13708
+ traceMeshEventDrop("duplicate_completion", traceCtx);
13617
13709
  return { success: true, forwarded: 0, suppressed: true, duplicateCompletion: true };
13618
13710
  }
13619
13711
  }
@@ -13632,6 +13724,7 @@ function injectMeshSystemMessage(components, args) {
13632
13724
  });
13633
13725
  if (duplicateStopped) {
13634
13726
  LOG.info("MeshEvents", `Suppressed duplicate stopped event for mesh ${args.meshId} session ${eventSessionId}`);
13727
+ traceMeshEventDrop("duplicate_stopped", traceCtx);
13635
13728
  return { success: true, forwarded: 0, suppressed: true, duplicateStopped: true };
13636
13729
  }
13637
13730
  }
@@ -13643,7 +13736,7 @@ function injectMeshSystemMessage(components, args) {
13643
13736
  });
13644
13737
  const leaveDirectDispatchActive = !task && opts?.tentativeIfDirect === true;
13645
13738
  if (!leaveDirectDispatchActive) {
13646
- updateDirectDispatchStatus(args.meshId, sessionId, outcome);
13739
+ updateDirectDispatchStatus(args.meshId, sessionId, outcome, eventTaskId);
13647
13740
  }
13648
13741
  markSessionDeliveriesTerminal(args.meshId, sessionId, outcome);
13649
13742
  setImmediate(() => cleanupTerminalDirectDispatches());
@@ -13656,7 +13749,7 @@ function injectMeshSystemMessage(components, args) {
13656
13749
  const nodeId = readNonEmptyString2(args.nodeId) || readNonEmptyString2(args.metadataEvent.meshNodeId);
13657
13750
  const providerType = readNonEmptyString2(args.metadataEvent.providerType);
13658
13751
  if (sessionId) {
13659
- directDispatchTaskIdForLedger = resolveActiveDirectDispatchTaskId(args.meshId, sessionId);
13752
+ directDispatchTaskIdForLedger = readNonEmptyString2(args.metadataEvent.taskId) || resolveActiveDirectDispatchTaskId(args.meshId, sessionId);
13660
13753
  const isFalseIdle = isFalseIdleCompletion(args.metadataEvent);
13661
13754
  completedTaskForLedger = markSessionTerminal(sessionId, "completed", eventTimestamp, { tentativeIfDirect: isFalseIdle });
13662
13755
  if (nodeId && providerType) {
@@ -13739,7 +13832,8 @@ function injectMeshSystemMessage(components, args) {
13739
13832
  }
13740
13833
  }
13741
13834
  if (sessionId) {
13742
- updateDirectDispatchStatus(args.meshId, sessionId, "acked");
13835
+ const startedTaskId = readNonEmptyString2(args.metadataEvent.taskId) || void 0;
13836
+ updateDirectDispatchStatus(args.meshId, sessionId, "acked", startedTaskId);
13743
13837
  const activeDeliveries = (() => {
13744
13838
  try {
13745
13839
  return MeshRuntimeStore.getInstance().getActiveSessionDeliveries(args.meshId, sessionId);
@@ -13747,7 +13841,8 @@ function injectMeshSystemMessage(components, args) {
13747
13841
  return [];
13748
13842
  }
13749
13843
  })();
13750
- for (const d of activeDeliveries) {
13844
+ const deliveriesToAck = startedTaskId ? activeDeliveries.filter((d) => d.taskId === startedTaskId) : activeDeliveries;
13845
+ for (const d of deliveriesToAck) {
13751
13846
  updateSessionDeliveryStatus(d.id, "acked");
13752
13847
  }
13753
13848
  }
@@ -13761,7 +13856,7 @@ function injectMeshSystemMessage(components, args) {
13761
13856
  }
13762
13857
  }
13763
13858
  if (sessionId) {
13764
- directDispatchTaskIdForLedger = resolveActiveDirectDispatchTaskId(args.meshId, sessionId);
13859
+ directDispatchTaskIdForLedger = readNonEmptyString2(args.metadataEvent.taskId) || resolveActiveDirectDispatchTaskId(args.meshId, sessionId);
13765
13860
  completedTaskForLedger = markSessionTerminal(sessionId, "failed");
13766
13861
  }
13767
13862
  }
@@ -13907,6 +14002,9 @@ function injectMeshSystemMessage(components, args) {
13907
14002
  };
13908
14003
  if (queuePendingMeshCoordinatorEvent(pendingEvent)) {
13909
14004
  LOG.info("MeshEvents", `Queued ${args.event} for coordinator (mesh ${args.meshId}${workerCoordinatorDaemonId ? `, coordinator daemon ${workerCoordinatorDaemonId}` : ""}${workerCoordinatorSessionId ? `, coordinator session ${workerCoordinatorSessionId}` : ""})`);
14005
+ traceMeshEventStage("queued", traceCtx, workerCoordinatorDaemonId ? `coordinatorDaemon=${workerCoordinatorDaemonId}` : "broadcast");
14006
+ } else {
14007
+ traceMeshEventDrop("queue_dedup", traceCtx);
13910
14008
  }
13911
14009
  return { success: true, forwarded: 0 };
13912
14010
  }
@@ -13917,8 +14015,23 @@ function handleMeshForwardEvent(components, payload) {
13917
14015
  }
13918
14016
  const nodeId = readNonEmptyString2(payload.nodeId);
13919
14017
  const workspace = readNonEmptyString2(payload.workspace);
13920
- const meshId = readNonEmptyString2(payload.meshId) || (workspace ? readNonEmptyString2(getCachedMeshByWorkspace(workspace)?.id) : "");
13921
- if (!meshId) return { success: false, error: "meshId required" };
14018
+ const meshId = readNonEmptyString2(payload.meshId) || (workspace ? readNonEmptyString2(getCachedMeshByWorkspace(workspace)?.id) : "") || recoverMeshIdByNodeId(nodeId);
14019
+ if (!meshId) {
14020
+ traceMeshEventDrop("meshId_required", {
14021
+ taskId: payload.taskId,
14022
+ sessionId: readNonEmptyString2(payload.targetSessionId) || readNonEmptyString2(payload.sessionId),
14023
+ nodeId,
14024
+ event: eventName
14025
+ }, workspace ? `workspace=${workspace} unresolved` : "no workspace/nodeId");
14026
+ return { success: false, error: "meshId required" };
14027
+ }
14028
+ traceMeshEventStage("received", {
14029
+ taskId: payload.taskId,
14030
+ sessionId: readNonEmptyString2(payload.targetSessionId) || readNonEmptyString2(payload.sessionId),
14031
+ nodeId,
14032
+ meshId,
14033
+ event: eventName
14034
+ });
13922
14035
  const nodeLabel = nodeId ? `Node '${nodeId}'` : workspace ? `Agent at ${workspace}` : "Remote agent";
13923
14036
  const relayModalMessage = readNonEmptyString2(payload.modalMessage);
13924
14037
  const relayModalButtons = Array.isArray(payload.modalButtons) ? payload.modalButtons.filter((b) => typeof b === "string" && b.trim().length > 0) : null;
@@ -13999,9 +14112,18 @@ function forwardUnresolvedDelegateEvent(components, routing, event) {
13999
14112
  workspace: readNonEmptyString2(routing.workspace) || readNonEmptyString2(event.workspace) || void 0
14000
14113
  };
14001
14114
  const persisted = enqueueUnresolvedDelegateForward(coordinatorDaemonId, eventName, payload);
14115
+ const fwdTraceCtx = {
14116
+ taskId: payload.taskId,
14117
+ sessionId: readNonEmptyString2(payload.targetSessionId) || readNonEmptyString2(payload.sessionId),
14118
+ nodeId: readNonEmptyString2(routing.nodeId) || readNonEmptyString2(event.meshNodeId),
14119
+ event: eventName
14120
+ };
14121
+ traceMeshEventStage("outbox_enqueue", fwdTraceCtx, `coordinatorDaemon=${coordinatorDaemonId} meshId=absent`);
14122
+ traceMeshEventStage("forward_send", fwdTraceCtx, "immediate push");
14002
14123
  Promise.resolve(components.dispatchMeshCommand(coordinatorDaemonId, "mesh_forward_event", payload)).then((result) => {
14003
14124
  if (result && result.success === false) {
14004
14125
  LOG.warn("MeshEvents", `Immediate forward of ${eventName} to coordinator ${coordinatorDaemonId} rejected (${readNonEmptyString2(result.error) || "no reason"}) \u2014 left queued for retry`);
14126
+ traceMeshEventDrop("immediate_forward_rejected", fwdTraceCtx, readNonEmptyString2(result.error) || "no reason");
14005
14127
  return;
14006
14128
  }
14007
14129
  if (persisted) ackUnresolvedDelegateForwardByFingerprint(coordinatorDaemonId, eventName, payload);
@@ -14069,6 +14191,14 @@ function setupMeshEventForwarding(components) {
14069
14191
  if (isUnroutableDelegateRejection(routing) && forwardUnresolvedDelegateEvent(components, routing, event)) {
14070
14192
  return;
14071
14193
  }
14194
+ if (isUnroutableDelegateRejection(routing)) {
14195
+ traceMeshEventDrop("unroutable", {
14196
+ taskId: event.meshActiveTaskId ?? event.taskId,
14197
+ sessionId: routing.sessionId,
14198
+ nodeId: routing.nodeId,
14199
+ event: event.event
14200
+ }, "no coordinator anchor / mesh_unresolved");
14201
+ }
14072
14202
  recordUnroutableDelegateEvent(routing, event.event);
14073
14203
  return;
14074
14204
  }
@@ -14098,6 +14228,7 @@ var init_mesh_events_coordinator = __esm({
14098
14228
  init_mesh_events_pending();
14099
14229
  init_mesh_routing();
14100
14230
  init_mesh_unresolved_forward_outbox();
14231
+ init_mesh_event_trace();
14101
14232
  init_snapshot();
14102
14233
  init_repo_mesh_types();
14103
14234
  init_dist();
@@ -14209,6 +14340,13 @@ function findLiveCoordinators(components) {
14209
14340
  function injectPendingIntoCoordinator(coordinator, pending) {
14210
14341
  if (!coordinator || !pending.coordinatorMessage) return;
14211
14342
  const force = shouldForceInjectMeshEvent(pending.event);
14343
+ traceMeshEventStage("surfaced", {
14344
+ taskId: pending.metadataEvent?.taskId,
14345
+ sessionId: pending.metadataEvent?.targetSessionId ?? pending.targetCoordinatorSessionId,
14346
+ nodeId: pending.nodeId,
14347
+ meshId: pending.meshId,
14348
+ event: pending.event
14349
+ }, force ? "force-inject" : "inject");
14212
14350
  coordinator.onEvent("send_message", {
14213
14351
  input: { text: pending.coordinatorMessage, textFallback: pending.coordinatorMessage },
14214
14352
  ...force ? { force: true } : {}
@@ -14267,6 +14405,13 @@ function recoverStrandedAssignedDispatches(meshId, store) {
14267
14405
  });
14268
14406
  if (reclaimed) {
14269
14407
  LOG.warn("MeshReconcile", `Reclaimed stranded assigned task ${row.id} on mesh ${meshId} (node=${row.assignedNodeId ?? "?"} session=${row.assignedSessionId ?? "?"}, dispatched ${Math.round((nowMs - dispatchedAtMs) / 1e3)}s ago, never confirmed delivered \u2192 ${reclaimed.status})`);
14408
+ traceMeshEventDrop("assigned_stranded_reclaim", {
14409
+ taskId: row.id,
14410
+ sessionId: row.assignedSessionId,
14411
+ nodeId: row.assignedNodeId,
14412
+ meshId,
14413
+ event: "agent:generating_completed"
14414
+ }, `unconfirmed ${Math.round((nowMs - dispatchedAtMs) / 1e3)}s \u2192 ${reclaimed.status}`);
14270
14415
  }
14271
14416
  }
14272
14417
  }
@@ -14426,6 +14571,13 @@ function holdOrExpireStrictUnmatchedEvent(pending, wantSession, meshId) {
14426
14571
  try {
14427
14572
  queuePendingMeshCoordinatorEvent(pending);
14428
14573
  LOG.info("MeshReconcile", `Strict route hold: coordinator session ${wantSession} not live on mesh ${meshId} \u2014 re-queued (${pending.event})`);
14574
+ traceMeshEventDrop("strict_route_hold", {
14575
+ taskId: pending.metadataEvent?.taskId,
14576
+ sessionId: pending.metadataEvent?.targetSessionId ?? wantSession,
14577
+ nodeId: pending.nodeId,
14578
+ meshId,
14579
+ event: pending.event
14580
+ }, `coordinatorSession=${wantSession} not live`);
14429
14581
  } catch (e) {
14430
14582
  LOG.warn("MeshReconcile", `Strict route re-queue failed for ${pending.event} on mesh ${meshId}: ${e?.message || e}`);
14431
14583
  }
@@ -14449,6 +14601,13 @@ function holdOrExpireStrictUnmatchedEvent(pending, wantSession, meshId) {
14449
14601
  }
14450
14602
  });
14451
14603
  LOG.warn("MeshReconcile", `Strict route expire: coordinator session ${wantSession} never returned for mesh ${meshId} \u2014 recorded to ledger (recoverable), dropped (${pending.event})`);
14604
+ traceMeshEventDrop("strict_route_expired", {
14605
+ taskId: pending.metadataEvent?.taskId,
14606
+ sessionId: pending.metadataEvent?.targetSessionId ?? wantSession,
14607
+ nodeId: pending.nodeId,
14608
+ meshId,
14609
+ event: pending.event
14610
+ }, `coordinatorSession=${wantSession} never returned`);
14452
14611
  } catch (e) {
14453
14612
  LOG.warn("MeshReconcile", `Failed to ledger-expire strict-unmatched ${pending.event} for mesh ${meshId}: ${e?.message || e}`);
14454
14613
  }
@@ -14460,15 +14619,24 @@ async function retryUnresolvedDelegateForwards(components) {
14460
14619
  const entries = peekUnresolvedDelegateForwards();
14461
14620
  if (entries.length === 0) return;
14462
14621
  for (const entry of entries) {
14622
+ const entryTraceCtx = {
14623
+ taskId: entry.payload.taskId,
14624
+ sessionId: readNonEmptyString2(entry.payload.targetSessionId) || readNonEmptyString2(entry.payload.sessionId),
14625
+ nodeId: readNonEmptyString2(entry.payload.nodeId),
14626
+ event: readNonEmptyString2(entry.payload.event)
14627
+ };
14463
14628
  let result;
14464
14629
  try {
14630
+ traceMeshEventStage("forward_send", entryTraceCtx, `retry \u2192 ${entry.coordinatorDaemonId}`);
14465
14631
  result = await dispatchMeshCommand(entry.coordinatorDaemonId, "mesh_forward_event", entry.payload);
14466
14632
  } catch (e) {
14467
14633
  LOG.warn("MeshReconcile", `Retry forward to coordinator ${entry.coordinatorDaemonId} failed: ${e?.message || e} \u2014 left queued`);
14634
+ traceMeshEventDrop("retry_forward_failed", entryTraceCtx, e?.message || String(e));
14468
14635
  continue;
14469
14636
  }
14470
14637
  if (result && result.success === false) {
14471
14638
  LOG.warn("MeshReconcile", `Retry forward to coordinator ${entry.coordinatorDaemonId} rejected (${readNonEmptyString2(result.error) || "no reason"}) \u2014 left queued`);
14639
+ traceMeshEventDrop("retry_forward_rejected", entryTraceCtx, readNonEmptyString2(result.error) || "no reason");
14472
14640
  continue;
14473
14641
  }
14474
14642
  ackUnresolvedDelegateForward(entry.id);
@@ -14710,6 +14878,7 @@ var init_mesh_reconcile_loop = __esm({
14710
14878
  init_mesh_events_coordinator();
14711
14879
  init_mesh_unresolved_forward_outbox();
14712
14880
  init_mesh_events_utils();
14881
+ init_mesh_event_trace();
14713
14882
  init_dist();
14714
14883
  init_mesh_work_queue();
14715
14884
  init_mesh_ledger();
@@ -15548,8 +15717,8 @@ function saveProvidersActive(file) {
15548
15717
  }
15549
15718
  function isValidSource(x) {
15550
15719
  if (!x || typeof x !== "object") return false;
15551
- const s = x;
15552
- return typeof s.name === "string" && s.name.length > 0 && typeof s.url === "string" && s.url.length > 0 && typeof s.ref === "string" && s.ref.length > 0 && typeof s.addedAt === "string";
15720
+ const s2 = x;
15721
+ return typeof s2.name === "string" && s2.name.length > 0 && typeof s2.url === "string" && s2.url.length > 0 && typeof s2.ref === "string" && s2.ref.length > 0 && typeof s2.addedAt === "string";
15553
15722
  }
15554
15723
  function deriveSourceName(url) {
15555
15724
  const m = url.match(/[/:]([^/:]+)\/([^/]+?)(?:\.git)?$/);
@@ -15605,7 +15774,7 @@ function inventoryExternalSources() {
15605
15774
  }
15606
15775
  function sourcesProviding(category, type) {
15607
15776
  const inventory = inventoryExternalSources();
15608
- return inventory.filter((s) => (s.providers[category] || []).includes(type)).map((s) => s.sourceName);
15777
+ return inventory.filter((s2) => (s2.providers[category] || []).includes(type)).map((s2) => s2.sourceName);
15609
15778
  }
15610
15779
  function resolveActiveSource(category, type, activeFile) {
15611
15780
  const candidates = sourcesProviding(category, type);
@@ -15809,10 +15978,10 @@ function compileSettledPromptMatchers(spec) {
15809
15978
  const footers = (spec.withFooter ?? []).map((f) => {
15810
15979
  if (f.kind === "regex") {
15811
15980
  const re = compile2(f.pattern, f.flags ?? "i");
15812
- return { test: (s) => re.test(s) };
15981
+ return { test: (s2) => re.test(s2) };
15813
15982
  }
15814
15983
  const needle = f.pattern.toLowerCase();
15815
- return { test: (s) => s.toLowerCase().includes(needle) };
15984
+ return { test: (s2) => s2.toLowerCase().includes(needle) };
15816
15985
  });
15817
15986
  return { prompt, footers };
15818
15987
  }
@@ -16686,7 +16855,7 @@ var init_cli_state_engine = __esm({
16686
16855
  }
16687
16856
  resolveModal(buttonIndex) {
16688
16857
  const snap = this.transport.getSnapshot();
16689
- const parseApproval = typeof this.transport.runParseApproval === "function" ? (s) => this.transport.runParseApproval(s.recentOutputBuffer.slice(-500)) : (s) => this.runParseApproval(s);
16858
+ const parseApproval = typeof this.transport.runParseApproval === "function" ? (s2) => this.transport.runParseApproval(s2.recentOutputBuffer.slice(-500)) : (s2) => this.runParseApproval(s2);
16690
16859
  let modal = this.activeModal ?? parseApproval(snap);
16691
16860
  if (!modal && this.runner.hasParseSession()) {
16692
16861
  try {
@@ -19374,22 +19543,23 @@ function resolveSections(sectionsObj, lines) {
19374
19543
  const matchesCandidate = (c, i) => c.re.test(lines[i]) && (c.prevRe === null || i > 0 && c.prevRe.test(lines[i - 1])) && (c.nextRe === null || i < total - 1 && c.nextRe.test(lines[i + 1]));
19375
19544
  let idx = -1;
19376
19545
  for (const c of candidates) {
19546
+ let candIdx = -1;
19377
19547
  if (sec.anchor_last) {
19378
19548
  for (let i = total - 1; i >= 0; i--) {
19379
19549
  if (matchesCandidate(c, i)) {
19380
- idx = i;
19550
+ candIdx = i;
19381
19551
  break;
19382
19552
  }
19383
19553
  }
19384
19554
  } else {
19385
19555
  for (let i = 0; i < total; i++) {
19386
19556
  if (matchesCandidate(c, i)) {
19387
- idx = i;
19557
+ candIdx = i;
19388
19558
  break;
19389
19559
  }
19390
19560
  }
19391
19561
  }
19392
- if (idx !== -1) break;
19562
+ if (candIdx !== -1 && (idx === -1 || candIdx < idx)) idx = candIdx;
19393
19563
  }
19394
19564
  if (idx !== -1) {
19395
19565
  from = idx;
@@ -19441,7 +19611,7 @@ function resolveSections(sectionsObj, lines) {
19441
19611
  }
19442
19612
  function sectionText(sections, sectionId, fullScreen) {
19443
19613
  if (!sectionId) return fullScreen;
19444
- const found = sections.find((s) => s.id === sectionId);
19614
+ const found = sections.find((s2) => s2.id === sectionId);
19445
19615
  return found ? found.text : "";
19446
19616
  }
19447
19617
  function isRegexCondition(c) {
@@ -19609,10 +19779,10 @@ function isV4Spec(raw) {
19609
19779
  return !!raw && typeof raw === "object" && raw.$schema === "adhdev:cli/spec@4";
19610
19780
  }
19611
19781
  function initialState(spec) {
19612
- return spec.states.find((s) => s.initial) ?? spec.states[0];
19782
+ return spec.states.find((s2) => s2.initial) ?? spec.states[0];
19613
19783
  }
19614
19784
  function stateById(spec, id) {
19615
- return spec.states.find((s) => s.id === id);
19785
+ return spec.states.find((s2) => s2.id === id);
19616
19786
  }
19617
19787
  function outgoingTransitions(spec, stateId) {
19618
19788
  const matches = spec.transitions.filter((t) => {
@@ -19701,7 +19871,17 @@ function evalCond(cond, sections, fullScreen, cursor, prevLines, clock, legacyTr
19701
19871
  const result = evaluateCondition(cond, sections, fullScreen, cursor, prevLines, legacyTrace, stateId);
19702
19872
  const kind = isRegex(cond) ? "regex" : "changed";
19703
19873
  const detail = isRegex(cond) ? `${cond.section ?? "*"}~/${cond.matches}/` : `cursor_above=${cond.cursor_above} changed=${cond.changed}`;
19704
- return { kind, result, detail };
19874
+ let matchedText;
19875
+ if (result && isRegex(cond)) {
19876
+ try {
19877
+ const hay = sectionText(sections, cond.section, fullScreen);
19878
+ const re = new RegExp(cond.matches, cond.flags ?? "i");
19879
+ const m = re.exec(hay);
19880
+ if (m && m[0]) matchedText = m[0].replace(/\s+/g, " ").trim().slice(0, 160);
19881
+ } catch {
19882
+ }
19883
+ }
19884
+ return matchedText ? { kind, result, detail, matchedText } : { kind, result, detail };
19705
19885
  }
19706
19886
  return { kind: "all", result: false, detail: "unknown condition" };
19707
19887
  }
@@ -19817,17 +19997,17 @@ function validateFsmSpec(raw) {
19817
19997
  }
19818
19998
  const ids = /* @__PURE__ */ new Set();
19819
19999
  let initialCount = 0;
19820
- for (const [i, s] of spec.states.entries()) {
19821
- if (!s.id) {
20000
+ for (const [i, s2] of spec.states.entries()) {
20001
+ if (!s2.id) {
19822
20002
  errs.push(`states[${i}].id is required`);
19823
20003
  continue;
19824
20004
  }
19825
- if (ids.has(s.id)) errs.push(`states[${i}].id "${s.id}" is duplicated`);
19826
- ids.add(s.id);
19827
- if (!s.label) errs.push(`states[${i}].label is required`);
19828
- if (s.initial) initialCount += 1;
19829
- if (s.status && !["idle", "generating", "approval"].includes(s.status)) {
19830
- errs.push(`states[${i}].status "${s.status}" must be idle|generating|approval`);
20005
+ if (ids.has(s2.id)) errs.push(`states[${i}].id "${s2.id}" is duplicated`);
20006
+ ids.add(s2.id);
20007
+ if (!s2.label) errs.push(`states[${i}].label is required`);
20008
+ if (s2.initial) initialCount += 1;
20009
+ if (s2.status && !["idle", "generating", "approval"].includes(s2.status)) {
20010
+ errs.push(`states[${i}].status "${s2.status}" must be idle|generating|approval`);
19831
20011
  }
19832
20012
  }
19833
20013
  if (initialCount === 0) errs.push("exactly one state must have initial:true (none found)");
@@ -19843,10 +20023,10 @@ function validateFsmSpec(raw) {
19843
20023
  else if (!ids.has(t.to)) errs.push(`transitions[${i}].to references unknown state "${t.to}"`);
19844
20024
  if (t.when) errs.push(...validateCondition(t.when, sectionIds, `transitions[${i}].when`));
19845
20025
  }
19846
- for (const [i, s] of spec.states.entries()) {
19847
- const sec = s.extract?.title?.section;
20026
+ for (const [i, s2] of spec.states.entries()) {
20027
+ const sec = s2.extract?.title?.section;
19848
20028
  if (sec && !sectionIds.has(sec)) errs.push(`states[${i}].extract.title.section "${sec}" unknown`);
19849
- const bsec = s.extract?.buttons?.section;
20029
+ const bsec = s2.extract?.buttons?.section;
19850
20030
  if (bsec && !sectionIds.has(bsec)) errs.push(`states[${i}].extract.buttons.section "${bsec}" unknown`);
19851
20031
  }
19852
20032
  return errs;
@@ -32218,10 +32398,10 @@ ${formatManifestValidationIssues2(validation.issues)}`,
32218
32398
  const path42 = __require("path");
32219
32399
  const { spawnSync: spawnSync2 } = __require("child_process");
32220
32400
  const file = ext.loadExternalSources();
32221
- if (file.sources.some((s) => s.name === requestedName)) {
32401
+ if (file.sources.some((s2) => s2.name === requestedName)) {
32222
32402
  return { success: false, error: `source name "${requestedName}" is already registered` };
32223
32403
  }
32224
- if (file.sources.some((s) => s.url === url && s.ref === ref)) {
32404
+ if (file.sources.some((s2) => s2.url === url && s2.ref === ref)) {
32225
32405
  return { success: false, error: `source url+ref already registered (use a different name to track another ref)` };
32226
32406
  }
32227
32407
  const sourceDir = path42.join(ext.externalRoot(), requestedName);
@@ -32283,7 +32463,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
32283
32463
  const fs32 = __require("fs");
32284
32464
  const path42 = __require("path");
32285
32465
  const file = ext.loadExternalSources();
32286
- const match = file.sources.find((s) => s.name === name);
32466
+ const match = file.sources.find((s2) => s2.name === name);
32287
32467
  if (!match) return { success: false, error: `source "${name}" not registered` };
32288
32468
  const sourceDir = path42.join(ext.externalRoot(), name);
32289
32469
  if (fs32.existsSync(sourceDir)) {
@@ -32295,7 +32475,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
32295
32475
  }
32296
32476
  ext.saveExternalSources({
32297
32477
  schema: 1,
32298
- sources: file.sources.filter((s) => s.name !== name)
32478
+ sources: file.sources.filter((s2) => s2.name !== name)
32299
32479
  });
32300
32480
  const active = ext.loadProvidersActive();
32301
32481
  const filteredActive = {};
@@ -32319,10 +32499,10 @@ ${formatManifestValidationIssues2(validation.issues)}`,
32319
32499
  const file = ext.loadExternalSources();
32320
32500
  const inventory = ext.inventoryExternalSources();
32321
32501
  const active = ext.loadProvidersActive();
32322
- const sources = file.sources.map((s) => {
32323
- const inv = inventory.find((e) => e.sourceName === s.name);
32502
+ const sources = file.sources.map((s2) => {
32503
+ const inv = inventory.find((e) => e.sourceName === s2.name);
32324
32504
  return {
32325
- ...s,
32505
+ ...s2,
32326
32506
  providers: inv?.providers ?? {}
32327
32507
  };
32328
32508
  });
@@ -32499,6 +32679,21 @@ import * as path21 from "path";
32499
32679
  // src/providers/spec/adapter.ts
32500
32680
  init_terminal_screen();
32501
32681
  import { DEFAULT_SESSION_HOST_COLS as DEFAULT_SESSION_HOST_COLS5, DEFAULT_SESSION_HOST_ROWS as DEFAULT_SESSION_HOST_ROWS5 } from "@adhdev/session-host-core";
32682
+ var MAX_PTY_EVENTS = 300;
32683
+ var EVENT_CONTENT_CAP = 240;
32684
+ function escapeControl(text) {
32685
+ return String(text).replace(/[\x00-\x1f\x7f]/g, (ch) => {
32686
+ const code = ch.charCodeAt(0);
32687
+ if (ch === "\r") return "\\r";
32688
+ if (ch === "\n") return "\\n";
32689
+ if (ch === " ") return "\\t";
32690
+ if (code === 27) return "\\x1b";
32691
+ return "\\x" + code.toString(16).padStart(2, "0");
32692
+ });
32693
+ }
32694
+ function capPreview(text) {
32695
+ return text.length > EVENT_CONTENT_CAP ? text.slice(0, EVENT_CONTENT_CAP) + `\u2026(+${text.length - EVENT_CONTENT_CAP})` : text;
32696
+ }
32502
32697
  var TerminalAdapter = class {
32503
32698
  constructor(opts, handlers) {
32504
32699
  this.opts = opts;
@@ -32525,6 +32720,9 @@ var TerminalAdapter = class {
32525
32720
  screenTimer = null;
32526
32721
  tickTimer = null;
32527
32722
  lastScreen = "";
32723
+ /** Debug-only ring buffer of PTY input/output/resize/cursor events. */
32724
+ events = [];
32725
+ lastCursorKey = "";
32528
32726
  start() {
32529
32727
  const env = this.opts.envIsComplete ? this.opts.env ?? {} : { ...process.env, ...this.opts.env ?? {} };
32530
32728
  this.pty = this.factory.spawn(this.opts.binary, this.opts.args ?? [], {
@@ -32533,10 +32731,12 @@ var TerminalAdapter = class {
32533
32731
  cols: this.cols,
32534
32732
  rows: this.rows
32535
32733
  });
32734
+ this.recordEvent("spawn", `${this.opts.binary} (${this.cols}x${this.rows})`);
32536
32735
  this.handlers.init?.({ pid: this.pty.pid });
32537
32736
  this.pty.onData((chunk) => this.onChunk(chunk));
32538
32737
  this.pty.onExit((info) => {
32539
32738
  this.stopTimers();
32739
+ this.recordEvent("exit", `exitCode=${typeof info.exitCode === "number" ? info.exitCode : 0}`);
32540
32740
  this.handlers.on_exit?.({ exitCode: typeof info.exitCode === "number" ? info.exitCode : 0 });
32541
32741
  this.pty = null;
32542
32742
  });
@@ -32547,6 +32747,7 @@ var TerminalAdapter = class {
32547
32747
  resize(cols, rows) {
32548
32748
  this.cols = cols;
32549
32749
  this.rows = rows;
32750
+ this.recordEvent("resize", `${cols}x${rows}`);
32550
32751
  this.pty?.resize(cols, rows);
32551
32752
  this.screen.resize(rows, cols);
32552
32753
  }
@@ -32567,8 +32768,21 @@ var TerminalAdapter = class {
32567
32768
  return { row: pos.row, col: pos.col };
32568
32769
  }
32569
32770
  send_keys(text) {
32771
+ this.recordEvent("input", capPreview(escapeControl(text)), text.length);
32570
32772
  this.pty?.write(text);
32571
32773
  }
32774
+ /** Debug-only: most-recent PTY input/output/resize/cursor events, oldest
32775
+ * first. Pure observation — never consulted by the FSM. */
32776
+ getEventTimeline(limit = MAX_PTY_EVENTS) {
32777
+ const n = Math.max(0, Math.min(limit, this.events.length));
32778
+ return this.events.slice(this.events.length - n);
32779
+ }
32780
+ recordEvent(kind, content, bytes) {
32781
+ const ev = { ts: Date.now(), kind, content };
32782
+ if (typeof bytes === "number") ev.bytes = bytes;
32783
+ this.events.push(ev);
32784
+ if (this.events.length > MAX_PTY_EVENTS) this.events.splice(0, this.events.length - MAX_PTY_EVENTS);
32785
+ }
32572
32786
  kill() {
32573
32787
  this.stopTimers();
32574
32788
  try {
@@ -32579,6 +32793,7 @@ var TerminalAdapter = class {
32579
32793
  this.screen.dispose();
32580
32794
  }
32581
32795
  onChunk(chunk) {
32796
+ this.recordEvent("output", capPreview(escapeControl(chunk)), chunk.length);
32582
32797
  try {
32583
32798
  this.handlers.on_pty_data?.(chunk);
32584
32799
  } catch {
@@ -32588,6 +32803,12 @@ var TerminalAdapter = class {
32588
32803
  this.screenTimer = setTimeout(() => {
32589
32804
  this.screenTimer = null;
32590
32805
  const snap = this.computeScreen();
32806
+ const cur = this.screen.getCursorPosition();
32807
+ const curKey = `${cur.row},${cur.col}`;
32808
+ if (curKey !== this.lastCursorKey) {
32809
+ this.lastCursorKey = curKey;
32810
+ this.recordEvent("cursor", `(${cur.row},${cur.col})`);
32811
+ }
32591
32812
  if (snap === this.lastScreen) return;
32592
32813
  this.lastScreen = snap;
32593
32814
  try {
@@ -32672,20 +32893,40 @@ function applyPreLaunchTrust(trust, workingDir) {
32672
32893
 
32673
32894
  // src/providers/spec/fsm-driver.ts
32674
32895
  init_logger();
32675
- function countNewlines(s) {
32896
+ function countNewlines(s2) {
32676
32897
  let n = 0;
32677
- for (let i = 0; i < s.length; i += 1) if (s.charCodeAt(i) === 10) n += 1;
32898
+ for (let i = 0; i < s2.length; i += 1) if (s2.charCodeAt(i) === 10) n += 1;
32678
32899
  return n;
32679
32900
  }
32680
32901
  var SUBMIT_DELAY_FLOOR_MS = 200;
32681
32902
  var WIN32_SUBMIT_RESEND_GAP_MS = 350;
32682
32903
  var WIN32_SUBMIT_MAX_RESENDS = 14;
32904
+ var WIN32_SUBMIT_SETTLE_MS = 500;
32905
+ var WIN32_SUBMIT_MAX_SETTLE_WAIT_MS = 1e4;
32906
+ var WIN32_SUBMIT_SETTLE_POLL_MS = 120;
32907
+ var WIN32_PTY_WRITE_CHUNK_CHARS = 1024;
32908
+ var WIN32_PTY_WRITE_CHUNK_GAP_MS = 8;
32683
32909
  function resolveSubmitDelayMs(specBeforeSubmit, text) {
32684
32910
  const lines = countNewlines(text);
32685
32911
  const linesBonus = Math.min(800, lines * 80);
32686
32912
  const spec = typeof specBeforeSubmit === "number" && specBeforeSubmit > 0 ? specBeforeSubmit : 0;
32687
32913
  return Math.max(spec, SUBMIT_DELAY_FLOOR_MS + linesBonus);
32688
32914
  }
32915
+ function chunkPreservingSurrogates(text, size) {
32916
+ const chunks = [];
32917
+ let offset = 0;
32918
+ while (offset < text.length) {
32919
+ let end = Math.min(text.length, offset + size);
32920
+ if (end < text.length) {
32921
+ const code = text.charCodeAt(end - 1);
32922
+ if (code >= 55296 && code <= 56319) end -= 1;
32923
+ }
32924
+ if (end <= offset) end = Math.min(text.length, offset + size);
32925
+ chunks.push(text.slice(offset, end));
32926
+ offset = end;
32927
+ }
32928
+ return chunks;
32929
+ }
32689
32930
  function guessExt(mime) {
32690
32931
  if (/png/i.test(mime)) return ".png";
32691
32932
  if (/jpe?g/i.test(mime)) return ".jpg";
@@ -32701,7 +32942,10 @@ var FsmDriver = class {
32701
32942
  this.buildAdapterOpts(),
32702
32943
  {
32703
32944
  init: () => this.emitInitialState(),
32704
- on_pty_data: (chunk) => this.emit({ kind: "pty_data", chunk }),
32945
+ on_pty_data: (chunk) => {
32946
+ this.lastPtyDataAt = Date.now();
32947
+ this.emit({ kind: "pty_data", chunk });
32948
+ },
32705
32949
  on_screen_changed: () => this.reevaluate(),
32706
32950
  on_exit: ({ exitCode }) => this.handleExit(exitCode)
32707
32951
  }
@@ -32735,6 +32979,16 @@ var FsmDriver = class {
32735
32979
  * WIN32_SUBMIT_* and scheduleWin32Submit). Re-arms itself until the FSM
32736
32980
  * leaves idle (submitted) or the resend budget is spent. */
32737
32981
  win32SubmitTimer = null;
32982
+ /** Wall-clock (ms) of the most recent raw PTY output chunk. Advances on every
32983
+ * on_pty_data — including the echo of text written into the composer — so the
32984
+ * win32 submit settle-gate can tell when input has finished landing. */
32985
+ lastPtyDataAt = 0;
32986
+ /** Wall-clock (ms) of the most recent win32 message-body input write. Bridges
32987
+ * the gap between writing a chunk and its echo so the settle-gate does not
32988
+ * declare "quiet" mid-write. */
32989
+ lastWin32WriteAt = 0;
32990
+ /** Pending paced chunk-write timer for a large win32 body (see writeWin32Body). */
32991
+ win32WriteTimer = null;
32738
32992
  currentEval = null;
32739
32993
  stateHistory = [];
32740
32994
  prevStateAt = 0;
@@ -32855,6 +33109,10 @@ var FsmDriver = class {
32855
33109
  clearTimeout(this.win32SubmitTimer);
32856
33110
  this.win32SubmitTimer = null;
32857
33111
  }
33112
+ if (this.win32WriteTimer) {
33113
+ clearTimeout(this.win32WriteTimer);
33114
+ this.win32WriteTimer = null;
33115
+ }
32858
33116
  this.specWatcher?.close();
32859
33117
  this.adapter.kill();
32860
33118
  }
@@ -32885,11 +33143,15 @@ var FsmDriver = class {
32885
33143
  getFsmSnapshotHistory() {
32886
33144
  return this.fsmSnapshotHistory;
32887
33145
  }
33146
+ /** Debug-only PTY input/output/resize/cursor timeline from the adapter. */
33147
+ getEventTimeline(limit) {
33148
+ return this.adapter.getEventTimeline(limit);
33149
+ }
32888
33150
  getSections() {
32889
33151
  try {
32890
33152
  const screen = this.adapter.snapshot();
32891
33153
  const lines = screen.split("\n").map((l) => l.endsWith("\r") ? l.slice(0, -1) : l);
32892
- return resolveSections(this.spec.sections ?? {}, lines).map((s) => ({ id: s.id, text: s.text }));
33154
+ return resolveSections(this.spec.sections ?? {}, lines).map((s2) => ({ id: s2.id, text: s2.text }));
32893
33155
  } catch {
32894
33156
  return null;
32895
33157
  }
@@ -33267,7 +33529,7 @@ var FsmDriver = class {
33267
33529
  const perChar = sm.delay_ms_per_char ?? 0;
33268
33530
  const beforeSubmit = resolveSubmitDelayMs(sm.delay_ms_before_submit, text);
33269
33531
  if (process.platform === "win32") {
33270
- this.adapter.send_keys(text);
33532
+ this.writeWin32Body(text);
33271
33533
  this.scheduleWin32Submit(sm.submit_key, beforeSubmit);
33272
33534
  return;
33273
33535
  }
@@ -33293,20 +33555,72 @@ var FsmDriver = class {
33293
33555
  const st = stateById(this.spec, this.currentStateId);
33294
33556
  return st ? statusForState(st) : "idle";
33295
33557
  }
33558
+ /** Record a win32 body write so the settle-gate counts it as input activity
33559
+ * even before the echo arrives. */
33560
+ markWin32Write() {
33561
+ this.lastWin32WriteAt = Date.now();
33562
+ }
33563
+ /** Most recent win32 input activity — a write we issued OR a PTY output chunk
33564
+ * (echo). The submit settle-gate waits for this to go quiet. */
33565
+ lastWin32InputActivityAt() {
33566
+ return Math.max(this.lastPtyDataAt, this.lastWin32WriteAt);
33567
+ }
33296
33568
  /**
33297
- * win32 verification-based submit. Sends the submit key, waits a gap, and if
33298
- * the FSM is still 'idle' (the prompt did not submit — the CR was absorbed as
33299
- * a multiline-paste newline) resends, up to WIN32_SUBMIT_MAX_RESENDS. The
33300
- * first CR always fires (so a stale/edge status never suppresses the submit);
33301
- * subsequent resends are gated on still being idle, and stop the instant the
33302
- * agent leaves idle (submitted generating / approval). This converges the
33303
- * nondeterministic multiline window without spamming Enter into the next turn.
33569
+ * Write the message body to the PTY for win32, paced into bounded chunks. A
33570
+ * single unbounded ConPTY write can overflow the input pipe and drop leading
33571
+ * bytes; splitting it with a short inter-chunk gap keeps the console input
33572
+ * buffer from overflowing. Small bodies still go out in a single write. Each
33573
+ * chunk advances lastWin32WriteAt so the submit settle-gate keeps waiting until
33574
+ * the final chunk is out and echoed.
33575
+ */
33576
+ writeWin32Body(text) {
33577
+ if (this.win32WriteTimer) {
33578
+ clearTimeout(this.win32WriteTimer);
33579
+ this.win32WriteTimer = null;
33580
+ }
33581
+ if (text.length <= WIN32_PTY_WRITE_CHUNK_CHARS) {
33582
+ this.markWin32Write();
33583
+ this.adapter.send_keys(text);
33584
+ return;
33585
+ }
33586
+ const chunks = chunkPreservingSurrogates(text, WIN32_PTY_WRITE_CHUNK_CHARS);
33587
+ let idx = 0;
33588
+ const writeNext = () => {
33589
+ this.win32WriteTimer = null;
33590
+ if (idx >= chunks.length) return;
33591
+ this.markWin32Write();
33592
+ this.adapter.send_keys(chunks[idx]);
33593
+ idx += 1;
33594
+ if (idx < chunks.length) {
33595
+ this.win32WriteTimer = setTimeout(writeNext, WIN32_PTY_WRITE_CHUNK_GAP_MS);
33596
+ }
33597
+ };
33598
+ writeNext();
33599
+ }
33600
+ /**
33601
+ * win32 submit. Two phases:
33602
+ *
33603
+ * Phase 1 (settle-gate): hold the first CR until the PTY output has been quiet
33604
+ * for WIN32_SUBMIT_SETTLE_MS after the last input write — i.e. the full
33605
+ * (possibly multi-KB / multiline) body has finished arriving in the composer
33606
+ * and echoing. Honors an initial minimum delay and is bounded by
33607
+ * WIN32_SUBMIT_MAX_SETTLE_WAIT_MS so a noisy screen can never hang the submit.
33608
+ * This is what stops a long message from being submitted half-arrived (its
33609
+ * leading lines lost). A short message settles almost immediately.
33610
+ *
33611
+ * Phase 2 (verified resend — unchanged): send the submit key, wait a gap, and
33612
+ * if the FSM is still 'idle' (the CR was absorbed as a multiline-paste
33613
+ * newline) resend, up to WIN32_SUBMIT_MAX_RESENDS. The first CR always fires
33614
+ * (a stale/edge status never suppresses it); resends are gated on still being
33615
+ * idle and stop the instant the agent leaves idle (submitted → generating /
33616
+ * approval). This preserves the win32 lone-CR-swallow handling.
33304
33617
  */
33305
33618
  scheduleWin32Submit(submitKey, initialDelayMs) {
33306
33619
  if (this.win32SubmitTimer) {
33307
33620
  clearTimeout(this.win32SubmitTimer);
33308
33621
  this.win32SubmitTimer = null;
33309
33622
  }
33623
+ const startedAt = Date.now();
33310
33624
  const fire = (attempt) => {
33311
33625
  this.win32SubmitTimer = null;
33312
33626
  this.adapter.send_keys(submitKey);
@@ -33319,8 +33633,20 @@ var FsmDriver = class {
33319
33633
  fire(attempt + 1);
33320
33634
  }, WIN32_SUBMIT_RESEND_GAP_MS);
33321
33635
  };
33322
- if (initialDelayMs > 0) this.win32SubmitTimer = setTimeout(() => fire(0), initialDelayMs);
33323
- else fire(0);
33636
+ const waitForSettle = () => {
33637
+ this.win32SubmitTimer = null;
33638
+ const now = Date.now();
33639
+ const quietFor = now - this.lastWin32InputActivityAt();
33640
+ const waited = now - startedAt;
33641
+ if (quietFor >= WIN32_SUBMIT_SETTLE_MS || waited >= WIN32_SUBMIT_MAX_SETTLE_WAIT_MS) {
33642
+ fire(0);
33643
+ return;
33644
+ }
33645
+ const recheckIn = Math.min(WIN32_SUBMIT_SETTLE_MS - quietFor, WIN32_SUBMIT_SETTLE_POLL_MS);
33646
+ this.win32SubmitTimer = setTimeout(waitForSettle, Math.max(recheckIn, 30));
33647
+ };
33648
+ if (initialDelayMs > 0) this.win32SubmitTimer = setTimeout(waitForSettle, initialDelayMs);
33649
+ else waitForSettle();
33324
33650
  }
33325
33651
  handleClickControl(controlId, payload) {
33326
33652
  const ctl = (this.spec.control_bar ?? []).find((c) => c.id === controlId);
@@ -33433,7 +33759,8 @@ function summarizeTransition(t) {
33433
33759
  return out;
33434
33760
  }
33435
33761
  function flattenCond(c, out, depth) {
33436
- out.push(`${" ".repeat(depth)}${c.kind} ${c.detail} = ${c.result}${c.remainingMs ? ` (${c.remainingMs}ms left)` : ""}`);
33762
+ const matched = c.matchedText ? ` matched=${JSON.stringify(c.matchedText)}` : "";
33763
+ out.push(`${" ".repeat(depth)}${c.kind} ${c.detail} = ${c.result}${c.remainingMs ? ` (${c.remainingMs}ms left)` : ""}${matched}`);
33437
33764
  for (const child of c.children ?? []) flattenCond(child, out, depth + 1);
33438
33765
  }
33439
33766
  function findStable(c) {
@@ -34151,8 +34478,8 @@ function projectToolBlock(block2, role, tmap) {
34151
34478
  }
34152
34479
  return null;
34153
34480
  }
34154
- function oneLine(s, max) {
34155
- const flat = s.replace(/\s+/g, " ").trim();
34481
+ function oneLine(s2, max) {
34482
+ const flat = s2.replace(/\s+/g, " ").trim();
34156
34483
  return flat.length > max ? flat.slice(0, max - 1) + "\u2026" : flat;
34157
34484
  }
34158
34485
  function parseTimestamp(v) {
@@ -34172,10 +34499,10 @@ function parseTimestamp(v) {
34172
34499
  return null;
34173
34500
  }
34174
34501
  function normalizeRole(r) {
34175
- const s = String(r ?? "").toLowerCase();
34176
- if (s === "user" || s === "human" || s === "user_explicit") return "user";
34177
- if (s === "assistant" || s === "ai" || s === "model") return "assistant";
34178
- if (s === "tool" || s === "tool_result" || s === "function") return "assistant";
34502
+ const s2 = String(r ?? "").toLowerCase();
34503
+ if (s2 === "user" || s2 === "human" || s2 === "user_explicit") return "user";
34504
+ if (s2 === "assistant" || s2 === "ai" || s2 === "model") return "assistant";
34505
+ if (s2 === "tool" || s2 === "tool_result" || s2 === "function") return "assistant";
34179
34506
  return "system";
34180
34507
  }
34181
34508
  function stringifyContent(v) {
@@ -34223,18 +34550,18 @@ function compileWhere(src) {
34223
34550
  return (record) => ors.some((ands) => ands.every((t) => evalTerm(t, record)));
34224
34551
  }
34225
34552
  function parseTerm(src) {
34226
- let s = src.trim();
34553
+ let s2 = src.trim();
34227
34554
  let negate = false;
34228
- if (s.startsWith("!")) {
34555
+ if (s2.startsWith("!")) {
34229
34556
  negate = true;
34230
- s = s.slice(1).trim();
34557
+ s2 = s2.slice(1).trim();
34231
34558
  }
34232
- const fnMatch = s.match(/^(startsWith|endsWith|contains)\s*\(\s*(.+?)\s*,\s*(.+?)\s*\)$/);
34559
+ const fnMatch = s2.match(/^(startsWith|endsWith|contains)\s*\(\s*(.+?)\s*,\s*(.+?)\s*\)$/);
34233
34560
  if (fnMatch) {
34234
34561
  const [, op2, pathExpr, litExpr] = fnMatch;
34235
34562
  return { path: pathExpr, op: op2, lit: parseLiteral(litExpr), negate };
34236
34563
  }
34237
- const opMatch = s.match(/^(.+?)\s*(==|!=|>=|<=|>|<)\s*(.+)$/);
34564
+ const opMatch = s2.match(/^(.+?)\s*(==|!=|>=|<=|>|<)\s*(.+)$/);
34238
34565
  if (!opMatch) return null;
34239
34566
  const [, lhs, op, rhsRaw] = opMatch;
34240
34567
  return { path: lhs.trim(), op, lit: parseLiteral(rhsRaw.trim()), negate };
@@ -34666,7 +34993,7 @@ var SpecCliAdapter = class _SpecCliAdapter {
34666
34993
  try {
34667
34994
  const sections = this.driver.getSections();
34668
34995
  if (sectionId && sections) {
34669
- const hit = sections.find((s) => s.id === sectionId);
34996
+ const hit = sections.find((s2) => s2.id === sectionId);
34670
34997
  if (hit) return hit.text;
34671
34998
  }
34672
34999
  return this.driver.getScreen();
@@ -34681,7 +35008,7 @@ var SpecCliAdapter = class _SpecCliAdapter {
34681
35008
  screen = this.driver.snapshot();
34682
35009
  const driverSections = this.driver.getSections?.();
34683
35010
  if (driverSections) {
34684
- sections = Object.fromEntries(driverSections.map((s) => [s.id, s.text]));
35011
+ sections = Object.fromEntries(driverSections.map((s2) => [s2.id, s2.text]));
34685
35012
  } else {
34686
35013
  sections = this.readCurrentScreenSections(screen);
34687
35014
  }
@@ -34727,6 +35054,10 @@ var SpecCliAdapter = class _SpecCliAdapter {
34727
35054
  // answers "why did this rule fire" after the fact, unlike the live
34728
35055
  // `fsm` field which only reflects the current instant.
34729
35056
  fsmHistory: this.driver.getFsmSnapshotHistory?.() ?? null,
35057
+ // PTY input/output/resize/cursor event timeline (debug-only) so the
35058
+ // snapshot shows what we typed / what the PTY printed around each
35059
+ // status transition. Null for drivers without the timeline.
35060
+ eventTimeline: this.driver.getEventTimeline?.() ?? null,
34730
35061
  // Extended fields
34731
35062
  name: this.cliName,
34732
35063
  status: this.getStatus().status,
@@ -35091,6 +35422,8 @@ var SpecCliAdapter = class _SpecCliAdapter {
35091
35422
  // v4 FSM transition snapshot history — the captured pre-transition
35092
35423
  // evaluation table at each transition (null for v3 specs).
35093
35424
  fsmHistory: this.driver.getFsmSnapshotHistory?.() ?? null,
35425
+ // PTY input/output/resize/cursor event timeline (debug-only).
35426
+ eventTimeline: this.driver.getEventTimeline?.() ?? null,
35094
35427
  messages,
35095
35428
  committedMessages: messages
35096
35429
  };
@@ -35135,6 +35468,7 @@ function createCliAdapter(provider, workingDir, cliArgs, extraEnv, transportFact
35135
35468
 
35136
35469
  // src/providers/cli-provider-instance.ts
35137
35470
  init_logger();
35471
+ init_mesh_event_trace();
35138
35472
  init_control_effects();
35139
35473
  init_approval_utils();
35140
35474
  init_provider_patch_state();
@@ -36186,6 +36520,23 @@ var CliProviderInstance = class _CliProviderInstance {
36186
36520
  if (this.completedDebounceTimer) clearTimeout(this.completedDebounceTimer);
36187
36521
  this.completedDebounceTimer = setTimeout(() => this.flushCompletedDebounceIfFinalized(), delayMs);
36188
36522
  }
36523
+ // EVTTRACE (observation-only): is this a mesh worker session whose completion
36524
+ // events must route to a coordinator? Used purely to gate trace logging so a
36525
+ // non-mesh CLI session's completions don't add EvtTrace noise. No decision logic.
36526
+ isMeshWorkerSession() {
36527
+ return !!(this.settings.meshNodeFor || this.settings.meshActiveTaskId || this.settings.meshNodeId || this.settings.launchedByCoordinator);
36528
+ }
36529
+ // EVTTRACE correlation context for this session's completion lifecycle. taskId is
36530
+ // the primary grep anchor; instanceId is the session fallback.
36531
+ meshTraceCtx(event = "agent:generating_completed") {
36532
+ return {
36533
+ taskId: this.settings.meshActiveTaskId,
36534
+ sessionId: this.instanceId,
36535
+ nodeId: this.settings.meshNodeId,
36536
+ meshId: this.settings.meshNodeFor,
36537
+ event
36538
+ };
36539
+ }
36189
36540
  flushCompletedDebounceIfFinalized() {
36190
36541
  const pending = this.completedDebouncePending;
36191
36542
  if (!pending) {
@@ -36206,24 +36557,33 @@ var CliProviderInstance = class _CliProviderInstance {
36206
36557
  if (block2) {
36207
36558
  const blockReason = block2.reason;
36208
36559
  const waitedMs = Date.now() - pending.firstObservedAt;
36209
- LOG.debug("CLI", `[${this.type}] finalization block: reason=${blockReason} terminal=${block2.terminal} waitedMs=${waitedMs} maxWait=${COMPLETED_FINALIZATION_MAX_WAIT_MS}`);
36210
- if (block2.terminal && !block2.allowTimeout || waitedMs < COMPLETED_FINALIZATION_MAX_WAIT_MS) {
36560
+ const isTranscriptEvidenceGate = block2.allowTimeout === true;
36561
+ LOG.debug("CLI", `[${this.type}] finalization block: reason=${blockReason} terminal=${block2.terminal} allowTimeout=${isTranscriptEvidenceGate} waitedMs=${waitedMs} maxWait=${COMPLETED_FINALIZATION_MAX_WAIT_MS}`);
36562
+ if (!isTranscriptEvidenceGate && (block2.terminal || waitedMs < COMPLETED_FINALIZATION_MAX_WAIT_MS)) {
36211
36563
  if (pending.loggedBlockReason !== blockReason) {
36212
36564
  LOG.info("CLI", `[${this.type}] waiting to emit completed until transcript finalizes (${blockReason})`);
36565
+ if (this.isMeshWorkerSession()) {
36566
+ traceMeshEventDrop("completion_gate_hold", this.meshTraceCtx(), `${blockReason} waited=${waitedMs}ms`);
36567
+ }
36213
36568
  pending.loggedBlockReason = blockReason;
36214
36569
  }
36215
36570
  this.scheduleCompletedDebounceFlush(COMPLETED_FINALIZATION_RETRY_MS);
36216
36571
  return;
36217
36572
  }
36573
+ const emittedAfterFinalizationTimeout = waitedMs >= COMPLETED_FINALIZATION_MAX_WAIT_MS;
36218
36574
  const completionDiagnostic = this.buildCompletedFinalizationDiagnostic({
36219
36575
  blockReason,
36220
36576
  latestStatus,
36221
36577
  latestVisibleStatus,
36222
36578
  waitedMs,
36223
36579
  pending,
36224
- emittedAfterFinalizationTimeout: true
36580
+ emittedAfterFinalizationTimeout
36225
36581
  });
36226
- LOG.warn("CLI", `[${this.type}] emitting completed event after ${waitedMs}ms without finalized assistant turn (${blockReason})`);
36582
+ completionDiagnostic.decoupledImmediateEmit = isTranscriptEvidenceGate && !emittedAfterFinalizationTimeout;
36583
+ LOG.warn("CLI", `[${this.type}] emitting completed event (${isTranscriptEvidenceGate && !emittedAfterFinalizationTimeout ? "CANON-C decoupled-immediate, transcript pending" : `after ${waitedMs}ms`}) without finalized assistant turn (${blockReason})`);
36584
+ if (this.isMeshWorkerSession()) {
36585
+ traceMeshEventStage("fired", this.meshTraceCtx(), `forced after ${waitedMs}ms (${blockReason})`);
36586
+ }
36227
36587
  this.pushEvent({
36228
36588
  event: "agent:generating_completed",
36229
36589
  chatTitle: pending.chatTitle,
@@ -36246,6 +36606,9 @@ var CliProviderInstance = class _CliProviderInstance {
36246
36606
  return;
36247
36607
  }
36248
36608
  LOG.info("CLI", `[${this.type}] completed in ${pending.duration}s`);
36609
+ if (this.isMeshWorkerSession()) {
36610
+ traceMeshEventStage("fired", this.meshTraceCtx(), `duration=${pending.duration}s`);
36611
+ }
36249
36612
  this.pushEvent({
36250
36613
  event: "agent:generating_completed",
36251
36614
  chatTitle: pending.chatTitle,
@@ -36484,6 +36847,9 @@ var CliProviderInstance = class _CliProviderInstance {
36484
36847
  if (missingEvidence && !hasMeshContext) {
36485
36848
  LOG.info("CLI", `[${this.type}] short completion suppressed: missing final assistant evidence, no mesh context (source=${shortEvidenceSource})`);
36486
36849
  } else {
36850
+ if (this.isMeshWorkerSession()) {
36851
+ traceMeshEventStage("fired", this.meshTraceCtx(), `short-generating idle (source=${shortEvidenceSource})`);
36852
+ }
36487
36853
  this.pushEvent({
36488
36854
  event: "agent:generating_completed",
36489
36855
  chatTitle,
@@ -36560,6 +36926,9 @@ var CliProviderInstance = class _CliProviderInstance {
36560
36926
  const monitorParsedStatus = parsedStatus;
36561
36927
  for (const me of monitorEvents) {
36562
36928
  if (me.type === "monitor:no_progress" && this.completionHasFinalAssistantMessage(monitorParsedStatus?.messages) && !this.hasAdapterPendingResponse() && !hasNonEmptyCliModalButtons(monitorParsedStatus?.activeModal ?? monitorParsedStatus?.modal)) {
36929
+ if (this.isMeshWorkerSession()) {
36930
+ traceMeshEventStage("fired", this.meshTraceCtx(), "no_progress_monitor_final_summary");
36931
+ }
36563
36932
  this.pushEvent({
36564
36933
  event: "agent:generating_completed",
36565
36934
  chatTitle,
@@ -40428,7 +40797,7 @@ function parsePbFile(filePath, sessionId) {
40428
40797
  }
40429
40798
  if (buf.length === 0) return null;
40430
40799
  const strings = extractStringsFromBuffer(buf);
40431
- const meaningful = strings.filter((s) => s.length >= MIN_PRINTABLE_RUN && /\w/.test(s));
40800
+ const meaningful = strings.filter((s2) => s2.length >= MIN_PRINTABLE_RUN && /\w/.test(s2));
40432
40801
  if (meaningful.length === 0) return null;
40433
40802
  const content = meaningful.join("\n");
40434
40803
  const sourceMtimeMs = statMtimeMs3(filePath);
@@ -40636,10 +41005,10 @@ function readSession4(sessionPath) {
40636
41005
  };
40637
41006
  }
40638
41007
  function normalizeHermesRole(r) {
40639
- const s = String(r ?? "").toLowerCase();
40640
- if (s === "user" || s === "human") return "user";
40641
- if (s === "assistant" || s === "ai" || s === "model") return "assistant";
40642
- if (s === "tool" || s === "tool_result" || s === "function") return "assistant";
41008
+ const s2 = String(r ?? "").toLowerCase();
41009
+ if (s2 === "user" || s2 === "human") return "user";
41010
+ if (s2 === "assistant" || s2 === "ai" || s2 === "model") return "assistant";
41011
+ if (s2 === "tool" || s2 === "tool_result" || s2 === "function") return "assistant";
40643
41012
  return "system";
40644
41013
  }
40645
41014
 
@@ -40865,10 +41234,10 @@ function safeMtime(p) {
40865
41234
  }
40866
41235
  }
40867
41236
  function normalizeRole2(r) {
40868
- const s = String(r ?? "").toLowerCase();
40869
- if (s === "user" || s === "human") return "user";
40870
- if (s === "assistant" || s === "ai" || s === "model") return "assistant";
40871
- if (s === "tool" || s === "tool_result" || s === "function") return "assistant";
41237
+ const s2 = String(r ?? "").toLowerCase();
41238
+ if (s2 === "user" || s2 === "human") return "user";
41239
+ if (s2 === "assistant" || s2 === "ai" || s2 === "model") return "assistant";
41240
+ if (s2 === "tool" || s2 === "tool_result" || s2 === "function") return "assistant";
40872
41241
  return "system";
40873
41242
  }
40874
41243
 
@@ -40888,7 +41257,7 @@ function synthesizeControlsFromControlBar(specControls) {
40888
41257
  const actionType = ctl?.action?.type;
40889
41258
  if (!id || !actionType) return;
40890
41259
  const label = typeof ctl?.label === "string" && ctl.label.trim() ? ctl.label : id;
40891
- const visibleWhenState = Array.isArray(ctl?.visible_when_state) ? ctl.visible_when_state.filter((s) => typeof s === "string") : void 0;
41260
+ const visibleWhenState = Array.isArray(ctl?.visible_when_state) ? ctl.visible_when_state.filter((s2) => typeof s2 === "string") : void 0;
40892
41261
  if (actionType === "open_picker") {
40893
41262
  out.push({
40894
41263
  id,
@@ -47804,7 +48173,7 @@ var DaemonCommandRouter = class {
47804
48173
  const base = validationSummary.failureCode === "missing_dependencies" ? "Refinery validation dependencies are missing; merge/refine was not attempted. Configure validation.bootstrapCommands if Refinery should bootstrap dependencies before validation." : validationSummary.failureCode === "dependency_bootstrap_failed" ? "Refinery dependency/bootstrap command failed; merge/refine was not attempted." : validationSummary.failureCode === "spawn_resolution_failed" ? validationSummary.spawnResolutionError || "Refinery validation command could not be spawned (executable not found); merge/refine was not attempted." : "Refinery validation gate failed; merge/refine was not attempted.";
47805
48174
  if (!firstFailedCmd) return base;
47806
48175
  const cmdName = typeof firstFailedCmd.displayCommand === "string" ? firstFailedCmd.displayCommand : typeof firstFailedCmd.command === "string" ? [firstFailedCmd.command, ...Array.isArray(firstFailedCmd.args) ? firstFailedCmd.args : []].join(" ").trim() : typeof firstFailedCmd.cmd === "string" ? firstFailedCmd.cmd : "";
47807
- const rawOutput = [firstFailedCmd.stdout, firstFailedCmd.stderr, firstFailedCmd.output].filter((s) => typeof s === "string" && s.length > 0).join("\n");
48176
+ const rawOutput = [firstFailedCmd.stdout, firstFailedCmd.stderr, firstFailedCmd.output].filter((s2) => typeof s2 === "string" && s2.length > 0).join("\n");
47808
48177
  const tail = rawOutput.length > 800 ? rawOutput.slice(-800) : rawOutput;
47809
48178
  return [
47810
48179
  base,
@@ -48555,7 +48924,7 @@ ${hintLines.join("\n")}` : "",
48555
48924
  convergence = "blocked_review";
48556
48925
  }
48557
48926
  const fbcs = result.finalBranchConvergenceState && typeof result.finalBranchConvergenceState === "object" ? result.finalBranchConvergenceState : void 0;
48558
- const stage = Array.isArray(result.refineStages) ? result.refineStages.filter((s) => s.status === "failed").map((s) => s.stage).filter(Boolean).pop() : void 0;
48927
+ const stage = Array.isArray(result.refineStages) ? result.refineStages.filter((s2) => s2.status === "failed").map((s2) => s2.stage).filter(Boolean).pop() : void 0;
48559
48928
  results.push({
48560
48929
  nodeId: node.id,
48561
48930
  workspace: node.workspace,
@@ -49552,7 +49921,7 @@ ${hintLines.join("\n")}` : "",
49552
49921
  return {
49553
49922
  success: true,
49554
49923
  screenLineCount: lines.length,
49555
- sections: resolved.map((s) => ({ id: s.id, fromLine: s.fromLine, toLine: s.toLine, text: s.text }))
49924
+ sections: resolved.map((s2) => ({ id: s2.id, fromLine: s2.fromLine, toLine: s2.toLine, text: s2.text }))
49556
49925
  };
49557
49926
  } catch (e) {
49558
49927
  return { success: false, error: `resolve failed: ${e.message}` };
@@ -50121,7 +50490,7 @@ ${hintLines.join("\n")}` : "",
50121
50490
  if (!meshId) return { success: false, error: "meshId required" };
50122
50491
  try {
50123
50492
  const { getMeshQueueStats: getMeshQueueStats2, getQueue: getQueue2, describeTaskDependencyState: describeTaskDependencyState2 } = await Promise.resolve().then(() => (init_mesh_work_queue(), mesh_work_queue_exports));
50124
- const status = Array.isArray(args?.status) ? args.status.map((s) => typeof s === "string" ? s.trim() : "").filter(Boolean) : void 0;
50493
+ const status = Array.isArray(args?.status) ? args.status.map((s2) => typeof s2 === "string" ? s2.trim() : "").filter(Boolean) : void 0;
50125
50494
  const rawQueue = getQueue2(meshId, { status });
50126
50495
  const statusById = new Map(getQueue2(meshId).map((task) => [task.id, task.status]));
50127
50496
  const queue = rawQueue.map((task) => Array.isArray(task.dependsOn) && task.dependsOn.length > 0 ? { ...task, ...describeTaskDependencyState2(task, statusById) } : task);
@@ -50402,7 +50771,7 @@ ${hintLines.join("\n")}` : "",
50402
50771
  nodeDaemonId = typeof node?.daemonId === "string" ? node.daemonId.trim() : void 0;
50403
50772
  }
50404
50773
  const selfDaemonId = this.deps.statusInstanceId;
50405
- const isRemote = nodeDaemonId && selfDaemonId && nodeDaemonId !== selfDaemonId;
50774
+ const isRemote = nodeDaemonId && selfDaemonId && !daemonIdsEquivalent(nodeDaemonId, selfDaemonId);
50406
50775
  if (isRemote && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
50407
50776
  const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, "fast_forward_mesh_node", {
50408
50777
  ...typeof args === "object" && args !== null ? args : {},
@@ -50436,7 +50805,7 @@ ${hintLines.join("\n")}` : "",
50436
50805
  nodeDaemonId = typeof node?.daemonId === "string" ? node.daemonId.trim() : void 0;
50437
50806
  }
50438
50807
  const selfDaemonId = this.deps.statusInstanceId;
50439
- const isRemote = nodeDaemonId && selfDaemonId && nodeDaemonId !== selfDaemonId;
50808
+ const isRemote = nodeDaemonId && selfDaemonId && !daemonIdsEquivalent(nodeDaemonId, selfDaemonId);
50440
50809
  if (isRemote && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
50441
50810
  const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, "get_mesh_node_logs", {
50442
50811
  ...typeof args === "object" && args !== null ? args : {},
@@ -50484,7 +50853,7 @@ ${hintLines.join("\n")}` : "",
50484
50853
  const forwardNode = meshRecordForForward?.mesh?.nodes?.find((n) => meshNodeIdMatches(n, nodeId));
50485
50854
  const nodeDaemonId = typeof forwardNode?.daemonId === "string" ? forwardNode.daemonId.trim() : void 0;
50486
50855
  const selfDaemonId = this.deps.statusInstanceId;
50487
- const isRemote = nodeDaemonId && selfDaemonId && nodeDaemonId !== selfDaemonId;
50856
+ const isRemote = nodeDaemonId && selfDaemonId && !daemonIdsEquivalent(nodeDaemonId, selfDaemonId);
50488
50857
  if (isRemote && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
50489
50858
  const callerCoordinatorDaemonId = typeof args?.coordinatorDaemonId === "string" && args.coordinatorDaemonId.trim() ? args.coordinatorDaemonId.trim() : void 0;
50490
50859
  const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, "refine_mesh_node", {
@@ -50571,7 +50940,7 @@ ${hintLines.join("\n")}` : "",
50571
50940
  let worktreeCleanup;
50572
50941
  if (node?.isLocalWorktree) {
50573
50942
  const nodeDaemonId = typeof node.daemonId === "string" ? node.daemonId.trim() : void 0;
50574
- const isRemoteWorktree = nodeDaemonId && nodeDaemonId !== this.deps.statusInstanceId && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch;
50943
+ const isRemoteWorktree = nodeDaemonId && !daemonIdsEquivalent(nodeDaemonId, this.deps.statusInstanceId) && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch;
50575
50944
  if (isRemoteWorktree) {
50576
50945
  const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, "remove_mesh_node", {
50577
50946
  ...typeof args === "object" && args !== null ? args : {},
@@ -50653,7 +51022,7 @@ ${hintLines.join("\n")}` : "",
50653
51022
  const sourceNode = mesh.nodes?.find((n) => meshNodeIdMatches(n, sourceNodeId));
50654
51023
  if (!sourceNode) return { success: false, error: `Source node '${sourceNodeId}' not found in mesh` };
50655
51024
  const sourceDaemonId = typeof sourceNode.daemonId === "string" ? sourceNode.daemonId.trim() : void 0;
50656
- if (sourceDaemonId && sourceDaemonId !== this.deps.statusInstanceId && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
51025
+ if (sourceDaemonId && !daemonIdsEquivalent(sourceDaemonId, this.deps.statusInstanceId) && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
50657
51026
  const forwarded = await this.deps.dispatchMeshCommand(sourceDaemonId, "clone_mesh_node", {
50658
51027
  ...typeof args === "object" && args !== null ? args : {},
50659
51028
  _meshDirectDispatch: true
@@ -50895,7 +51264,7 @@ ${hintLines.join("\n")}` : "",
50895
51264
  if (!node) return { success: false, error: `Node '${nodeId}' not found in mesh` };
50896
51265
  if (!node.isLocalWorktree) return { success: false, error: "Node is not a local worktree node" };
50897
51266
  const nodeDaemonId = typeof node.daemonId === "string" ? node.daemonId.trim() : void 0;
50898
- if (nodeDaemonId && nodeDaemonId !== this.deps.statusInstanceId && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
51267
+ if (nodeDaemonId && !daemonIdsEquivalent(nodeDaemonId, this.deps.statusInstanceId) && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
50899
51268
  const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, "retry_mesh_node_bootstrap", {
50900
51269
  ...typeof args === "object" && args !== null ? args : {},
50901
51270
  _meshDirectDispatch: true
@@ -52105,16 +52474,16 @@ var DaemonStatusReporter = class {
52105
52474
  const now = this.lastStatusSentAt;
52106
52475
  const target = opts?.p2pOnly ? "P2P" : serverConnected ? "P2P+Server" : "P2P";
52107
52476
  const allStates = this.deps.instanceManager.collectAllStates();
52108
- const ideStates = allStates.filter((s) => s.category === "ide");
52109
- const cliStates = allStates.filter((s) => s.category === "cli");
52110
- const acpStates = allStates.filter((s) => s.category === "acp");
52111
- const ideSummary = ideStates.map((s) => {
52112
- const msgs = s.activeChat?.messages?.length || 0;
52113
- const exts = s.extensions.length;
52114
- return `${s.type}(${s.status},${msgs}msg,${exts}ext)`;
52477
+ const ideStates = allStates.filter((s2) => s2.category === "ide");
52478
+ const cliStates = allStates.filter((s2) => s2.category === "cli");
52479
+ const acpStates = allStates.filter((s2) => s2.category === "acp");
52480
+ const ideSummary = ideStates.map((s2) => {
52481
+ const msgs = s2.activeChat?.messages?.length || 0;
52482
+ const exts = s2.extensions.length;
52483
+ return `${s2.type}(${s2.status},${msgs}msg,${exts}ext)`;
52115
52484
  }).join(", ");
52116
- const cliSummary = cliStates.map((s) => `${s.type}(${s.status})`).join(", ");
52117
- const acpSummary = acpStates.map((s) => `${s.type}(${s.status})`).join(", ");
52485
+ const cliSummary = cliStates.map((s2) => `${s2.type}(${s2.status})`).join(", ");
52486
+ const acpSummary = acpStates.map((s2) => `${s2.type}(${s2.status})`).join(", ");
52118
52487
  const logLevel = opts?.p2pOnly ? "debug" : "info";
52119
52488
  const baseSummary = `IDE: ${ideStates.length} [${ideSummary}] CLI: ${cliStates.length} [${cliSummary}] ACP: ${acpStates.length} [${acpSummary}]`;
52120
52489
  const summaryChanged = baseSummary !== this.lastStatusSummary;
@@ -52225,10 +52594,10 @@ var DaemonStatusReporter = class {
52225
52594
  }
52226
52595
  return false;
52227
52596
  }
52228
- simpleHash(s) {
52597
+ simpleHash(s2) {
52229
52598
  let h = 2166136261;
52230
- for (let i = 0; i < s.length; i++) {
52231
- h ^= s.charCodeAt(i);
52599
+ for (let i = 0; i < s2.length; i++) {
52600
+ h ^= s2.charCodeAt(i);
52232
52601
  h = h * 16777619 >>> 0;
52233
52602
  }
52234
52603
  return h.toString(36);
@@ -53454,7 +53823,7 @@ var ProviderInstanceManager = class {
53454
53823
  * Per-category status collect
53455
53824
  */
53456
53825
  collectStatesByCategory(category) {
53457
- return this.collectAllStates().filter((s) => s.category === category);
53826
+ return this.collectAllStates().filter((s2) => s2.category === category);
53458
53827
  }
53459
53828
  // ─── Tick engine ─────────────────────────────────
53460
53829
  /**
@@ -55354,9 +55723,9 @@ function getCliProviderResolutionMeta(ctx, type, adapter) {
55354
55723
  function findCliTarget(ctx, type, instanceId) {
55355
55724
  if (!ctx.instanceManager) return null;
55356
55725
  const cliStates = ctx.instanceManager.collectAllStates().filter(isCliTargetState);
55357
- if (instanceId) return cliStates.find((s) => s.instanceId === instanceId) || null;
55726
+ if (instanceId) return cliStates.find((s2) => s2.instanceId === instanceId) || null;
55358
55727
  if (!type) return cliStates[cliStates.length - 1] || null;
55359
- const matches = cliStates.filter((s) => s.type === type);
55728
+ const matches = cliStates.filter((s2) => s2.type === type);
55360
55729
  return matches[matches.length - 1] || null;
55361
55730
  }
55362
55731
  function getCliTargetBundle(ctx, type, instanceId) {
@@ -55719,20 +56088,20 @@ async function handleCliStatus(ctx, _req, res) {
55719
56088
  return;
55720
56089
  }
55721
56090
  const allStates = ctx.instanceManager.collectAllStates();
55722
- const cliStates = allStates.filter((s) => s.category === "cli" || s.category === "acp");
55723
- const result = cliStates.map((s) => ({
55724
- instanceId: s.instanceId,
55725
- type: s.type,
55726
- name: s.name,
55727
- category: s.category,
55728
- status: s.status,
55729
- mode: s.mode,
55730
- workspace: s.workspace,
55731
- messageCount: s.activeChat?.messages?.length || 0,
55732
- lastMessage: s.activeChat?.messages?.slice(-1)[0] || null,
55733
- activeModal: s.activeChat?.activeModal || null,
55734
- pendingEvents: s.pendingEvents || [],
55735
- settings: s.settings
56091
+ const cliStates = allStates.filter((s2) => s2.category === "cli" || s2.category === "acp");
56092
+ const result = cliStates.map((s2) => ({
56093
+ instanceId: s2.instanceId,
56094
+ type: s2.type,
56095
+ name: s2.name,
56096
+ category: s2.category,
56097
+ status: s2.status,
56098
+ mode: s2.mode,
56099
+ workspace: s2.workspace,
56100
+ messageCount: s2.activeChat?.messages?.length || 0,
56101
+ lastMessage: s2.activeChat?.messages?.slice(-1)[0] || null,
56102
+ activeModal: s2.activeChat?.activeModal || null,
56103
+ pendingEvents: s2.pendingEvents || [],
56104
+ settings: s2.settings
55736
56105
  }));
55737
56106
  ctx.json(res, 200, { instances: result, count: result.length });
55738
56107
  }
@@ -55821,9 +56190,9 @@ function handleCliSSE(ctx, cliSSEClients, _req, res) {
55821
56190
  }
55822
56191
  if (ctx.instanceManager) {
55823
56192
  const allStates = ctx.instanceManager.collectAllStates();
55824
- const cliStates = allStates.filter((s) => s.category === "cli" || s.category === "acp");
55825
- for (const s of cliStates) {
55826
- ctx.sendCliSSE({ event: "snapshot", providerType: s.type, status: s.status, instanceId: s.instanceId });
56193
+ const cliStates = allStates.filter((s2) => s2.category === "cli" || s2.category === "acp");
56194
+ for (const s2 of cliStates) {
56195
+ ctx.sendCliSSE({ event: "snapshot", providerType: s2.type, status: s2.status, instanceId: s2.instanceId });
55827
56196
  }
55828
56197
  }
55829
56198
  _req.on("close", () => {
@@ -55839,7 +56208,7 @@ async function handleCliDebug(ctx, type, _req, res) {
55839
56208
  const target = findCliTarget(ctx, type);
55840
56209
  if (!target) {
55841
56210
  const allStates = ctx.instanceManager.collectAllStates();
55842
- ctx.json(res, 404, { error: `No running instance for: ${type}`, available: allStates.filter((s) => s.category === "cli" || s.category === "acp").map((s) => s.type) });
56211
+ ctx.json(res, 404, { error: `No running instance for: ${type}`, available: allStates.filter((s2) => s2.category === "cli" || s2.category === "acp").map((s2) => s2.type) });
55843
56212
  return;
55844
56213
  }
55845
56214
  const instance = ctx.instanceManager.getInstance(target.instanceId);
@@ -55885,7 +56254,7 @@ async function handleCliTrace(ctx, type, req, res) {
55885
56254
  const allStates = ctx.instanceManager.collectAllStates();
55886
56255
  ctx.json(res, 404, {
55887
56256
  error: `No running instance for: ${type}`,
55888
- available: allStates.filter((s) => s.category === "cli" || s.category === "acp").map((s) => s.type)
56257
+ available: allStates.filter((s2) => s2.category === "cli" || s2.category === "acp").map((s2) => s2.type)
55889
56258
  });
55890
56259
  return;
55891
56260
  }
@@ -56690,7 +57059,7 @@ async function handleAutoImplement(ctx, type, req, res) {
56690
57059
  child.write("\x1B[12;1R");
56691
57060
  ctx.log("Terminal CPR request (\\x1b[6n) intercepted in PTY, responding with dummy coordinates [12;1R]");
56692
57061
  }
56693
- checkAutoApproval(data, (s) => child.write(s));
57062
+ checkAutoApproval(data, (s2) => child.write(s2));
56694
57063
  sendAutoImplSSE(ctx, { event: "output", data: { chunk: data, stream: "stdout" } });
56695
57064
  scheduleAutoStopForVerification();
56696
57065
  });
@@ -56703,7 +57072,7 @@ async function handleAutoImplement(ctx, type, req, res) {
56703
57072
  stdout += chunk;
56704
57073
  clearAutoStopTimer();
56705
57074
  if (chunk.includes("\x1B[6n")) child.stdin?.write("\x1B[1;1R");
56706
- checkAutoApproval(chunk, (s) => child.stdin?.write(s));
57075
+ checkAutoApproval(chunk, (s2) => child.stdin?.write(s2));
56707
57076
  sendAutoImplSSE(ctx, { event: "output", data: { chunk, stream: "stdout" } });
56708
57077
  scheduleAutoStopForVerification();
56709
57078
  });
@@ -56711,7 +57080,7 @@ async function handleAutoImplement(ctx, type, req, res) {
56711
57080
  const chunk = d.toString();
56712
57081
  stderr += chunk;
56713
57082
  clearAutoStopTimer();
56714
- checkAutoApproval(chunk, (s) => child.stdin?.write(s));
57083
+ checkAutoApproval(chunk, (s2) => child.stdin?.write(s2));
56715
57084
  sendAutoImplSSE(ctx, { event: "output", data: { chunk, stream: "stderr" } });
56716
57085
  scheduleAutoStopForVerification();
56717
57086
  });
@@ -57526,59 +57895,59 @@ var DevServer = class _DevServer {
57526
57895
  // ─── Route Table ─────────────────────────────────────
57527
57896
  routes = [
57528
57897
  // Static routes
57529
- { method: "GET", pattern: "/api/providers", handler: (q, s) => this.handleListProviders(q, s) },
57530
- { method: "GET", pattern: "/api/providers/source-config", handler: (q, s) => this.handleGetProviderSourceConfig(q, s) },
57531
- { method: "POST", pattern: "/api/providers/source-config", handler: (q, s) => this.handleSetProviderSourceConfig(q, s) },
57532
- { method: "GET", pattern: "/api/providers/versions", handler: (q, s) => this.handleDetectVersions(q, s) },
57533
- { method: "POST", pattern: "/api/providers/reload", handler: (q, s) => this.handleReload(q, s) },
57534
- { method: "POST", pattern: "/api/cdp/evaluate", handler: (q, s) => this.handleCdpEvaluate(q, s) },
57535
- { method: "POST", pattern: "/api/cdp/click", handler: (q, s) => this.handleCdpClick(q, s) },
57536
- { method: "POST", pattern: "/api/cdp/dom/query", handler: (q, s) => this.handleCdpDomQuery(q, s) },
57537
- { method: "POST", pattern: "/api/cdp/dom/inspect", handler: (q, s) => this.handleDomInspect(q, s) },
57538
- { method: "POST", pattern: "/api/cdp/dom/children", handler: (q, s) => this.handleDomChildren(q, s) },
57539
- { method: "POST", pattern: "/api/cdp/dom/analyze", handler: (q, s) => this.handleDomAnalyze(q, s) },
57540
- { method: "POST", pattern: "/api/cdp/dom/find-text", handler: (q, s) => this.handleFindByText(q, s) },
57541
- { method: "POST", pattern: "/api/cdp/dom/find-common", handler: (q, s) => this.handleFindCommon(q, s) },
57542
- { method: "GET", pattern: "/api/cdp/screenshot", handler: (q, s) => this.handleScreenshot(q, s) },
57543
- { method: "GET", pattern: "/api/cdp/targets", handler: (q, s) => this.handleCdpTargets(q, s) },
57544
- { method: "POST", pattern: "/api/scripts/run", handler: (q, s) => this.handleScriptsRun(q, s) },
57545
- { method: "GET", pattern: "/api/status", handler: (q, s) => this.handleStatus(q, s) },
57546
- { method: "POST", pattern: "/api/watch/start", handler: (q, s) => this.handleWatchStart(q, s) },
57547
- { method: "POST", pattern: "/api/watch/stop", handler: (q, s) => this.handleWatchStop(q, s) },
57548
- { method: "GET", pattern: "/api/watch/events", handler: (q, s) => this.handleSSE(q, s) },
57549
- { method: "POST", pattern: "/api/scaffold", handler: (q, s) => this.handleScaffold(q, s) },
57898
+ { method: "GET", pattern: "/api/providers", handler: (q, s2) => this.handleListProviders(q, s2) },
57899
+ { method: "GET", pattern: "/api/providers/source-config", handler: (q, s2) => this.handleGetProviderSourceConfig(q, s2) },
57900
+ { method: "POST", pattern: "/api/providers/source-config", handler: (q, s2) => this.handleSetProviderSourceConfig(q, s2) },
57901
+ { method: "GET", pattern: "/api/providers/versions", handler: (q, s2) => this.handleDetectVersions(q, s2) },
57902
+ { method: "POST", pattern: "/api/providers/reload", handler: (q, s2) => this.handleReload(q, s2) },
57903
+ { method: "POST", pattern: "/api/cdp/evaluate", handler: (q, s2) => this.handleCdpEvaluate(q, s2) },
57904
+ { method: "POST", pattern: "/api/cdp/click", handler: (q, s2) => this.handleCdpClick(q, s2) },
57905
+ { method: "POST", pattern: "/api/cdp/dom/query", handler: (q, s2) => this.handleCdpDomQuery(q, s2) },
57906
+ { method: "POST", pattern: "/api/cdp/dom/inspect", handler: (q, s2) => this.handleDomInspect(q, s2) },
57907
+ { method: "POST", pattern: "/api/cdp/dom/children", handler: (q, s2) => this.handleDomChildren(q, s2) },
57908
+ { method: "POST", pattern: "/api/cdp/dom/analyze", handler: (q, s2) => this.handleDomAnalyze(q, s2) },
57909
+ { method: "POST", pattern: "/api/cdp/dom/find-text", handler: (q, s2) => this.handleFindByText(q, s2) },
57910
+ { method: "POST", pattern: "/api/cdp/dom/find-common", handler: (q, s2) => this.handleFindCommon(q, s2) },
57911
+ { method: "GET", pattern: "/api/cdp/screenshot", handler: (q, s2) => this.handleScreenshot(q, s2) },
57912
+ { method: "GET", pattern: "/api/cdp/targets", handler: (q, s2) => this.handleCdpTargets(q, s2) },
57913
+ { method: "POST", pattern: "/api/scripts/run", handler: (q, s2) => this.handleScriptsRun(q, s2) },
57914
+ { method: "GET", pattern: "/api/status", handler: (q, s2) => this.handleStatus(q, s2) },
57915
+ { method: "POST", pattern: "/api/watch/start", handler: (q, s2) => this.handleWatchStart(q, s2) },
57916
+ { method: "POST", pattern: "/api/watch/stop", handler: (q, s2) => this.handleWatchStop(q, s2) },
57917
+ { method: "GET", pattern: "/api/watch/events", handler: (q, s2) => this.handleSSE(q, s2) },
57918
+ { method: "POST", pattern: "/api/scaffold", handler: (q, s2) => this.handleScaffold(q, s2) },
57550
57919
  // CLI Debug routes
57551
- { method: "GET", pattern: "/api/cli/status", handler: (q, s) => this.handleCliStatus(q, s) },
57552
- { method: "POST", pattern: "/api/cli/launch", handler: (q, s) => this.handleCliLaunch(q, s) },
57553
- { method: "POST", pattern: "/api/cli/send", handler: (q, s) => this.handleCliSend(q, s) },
57554
- { method: "POST", pattern: "/api/cli/exercise", handler: (q, s) => this.handleCliExercise(q, s) },
57555
- { method: "POST", pattern: "/api/cli/fixture/capture", handler: (q, s) => this.handleCliFixtureCapture(q, s) },
57556
- { method: "POST", pattern: "/api/cli/fixture/replay", handler: (q, s) => this.handleCliFixtureReplay(q, s) },
57557
- { method: "POST", pattern: "/api/cli/resolve", handler: (q, s) => this.handleCliResolve(q, s) },
57558
- { method: "POST", pattern: "/api/cli/raw", handler: (q, s) => this.handleCliRaw(q, s) },
57559
- { method: "POST", pattern: "/api/cli/stop", handler: (q, s) => this.handleCliStop(q, s) },
57560
- { method: "GET", pattern: "/api/cli/events", handler: (q, s) => this.handleCliSSE(q, s) },
57561
- { method: "GET", pattern: /^\/api\/cli\/debug\/([^/]+)$/, handler: (q, s, p) => this.handleCliDebug(p[0], q, s) },
57562
- { method: "GET", pattern: /^\/api\/cli\/trace\/([^/]+)$/, handler: (q, s, p) => this.handleCliTrace(p[0], q, s) },
57563
- { method: "GET", pattern: /^\/api\/cli\/fixtures\/([^/]+)$/, handler: (q, s, p) => this.handleCliFixtureList(p[0], q, s) },
57920
+ { method: "GET", pattern: "/api/cli/status", handler: (q, s2) => this.handleCliStatus(q, s2) },
57921
+ { method: "POST", pattern: "/api/cli/launch", handler: (q, s2) => this.handleCliLaunch(q, s2) },
57922
+ { method: "POST", pattern: "/api/cli/send", handler: (q, s2) => this.handleCliSend(q, s2) },
57923
+ { method: "POST", pattern: "/api/cli/exercise", handler: (q, s2) => this.handleCliExercise(q, s2) },
57924
+ { method: "POST", pattern: "/api/cli/fixture/capture", handler: (q, s2) => this.handleCliFixtureCapture(q, s2) },
57925
+ { method: "POST", pattern: "/api/cli/fixture/replay", handler: (q, s2) => this.handleCliFixtureReplay(q, s2) },
57926
+ { method: "POST", pattern: "/api/cli/resolve", handler: (q, s2) => this.handleCliResolve(q, s2) },
57927
+ { method: "POST", pattern: "/api/cli/raw", handler: (q, s2) => this.handleCliRaw(q, s2) },
57928
+ { method: "POST", pattern: "/api/cli/stop", handler: (q, s2) => this.handleCliStop(q, s2) },
57929
+ { method: "GET", pattern: "/api/cli/events", handler: (q, s2) => this.handleCliSSE(q, s2) },
57930
+ { method: "GET", pattern: /^\/api\/cli\/debug\/([^/]+)$/, handler: (q, s2, p) => this.handleCliDebug(p[0], q, s2) },
57931
+ { method: "GET", pattern: /^\/api\/cli\/trace\/([^/]+)$/, handler: (q, s2, p) => this.handleCliTrace(p[0], q, s2) },
57932
+ { method: "GET", pattern: /^\/api\/cli\/fixtures\/([^/]+)$/, handler: (q, s2, p) => this.handleCliFixtureList(p[0], q, s2) },
57564
57933
  // Dynamic routes (provider :type param)
57565
- { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/script$/, handler: (q, s, p) => this.handleRunScript(p[0], q, s) },
57566
- { method: "GET", pattern: /^\/api\/providers\/([^/]+)\/files$/, handler: (q, s, p) => this.handleListFiles(p[0], q, s) },
57567
- { method: "GET", pattern: /^\/api\/providers\/([^/]+)\/file$/, handler: (q, s, p) => this.handleReadFile(p[0], q, s) },
57568
- { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/file$/, handler: (q, s, p) => this.handleWriteFile(p[0], q, s) },
57569
- { method: "GET", pattern: /^\/api\/providers\/([^/]+)\/source$/, handler: (q, s, p) => this.handleSource(p[0], q, s) },
57570
- { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/save$/, handler: (q, s, p) => this.handleSave(p[0], q, s) },
57571
- { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/typeAndSend$/, handler: (q, s, p) => this.handleTypeAndSend(p[0], q, s) },
57572
- { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/typeAndSendAt$/, handler: (q, s, p) => this.handleTypeAndSendAt(p[0], q, s) },
57573
- { method: "GET", pattern: /^\/api\/providers\/([^/]+)\/config$/, handler: (q, s, p) => this.handleProviderConfig(p[0], q, s) },
57574
- { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/dom-context$/, handler: (q, s, p) => this.handleDomContext(p[0], q, s) },
57575
- { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/auto-implement$/, handler: (q, s, p) => this.handleAutoImplement(p[0], q, s) },
57576
- { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/auto-implement\/cancel$/, handler: (q, s, p) => this.handleAutoImplCancel(p[0], q, s) },
57577
- { method: "GET", pattern: /^\/api\/providers\/([^/]+)\/auto-implement\/status$/, handler: (q, s, p) => this.handleAutoImplSSE(p[0], q, s) },
57578
- { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/spawn-test$/, handler: (q, s, p) => this.handleSpawnTest(p[0], q, s) },
57579
- { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/validate$/, handler: (q, s, p) => this.handleValidate(p[0], q, s) },
57580
- { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/acp-chat$/, handler: (q, s, p) => this.handleAcpChat(p[0], q, s) },
57581
- { method: "GET", pattern: /^\/api\/providers\/([^/]+)\/script-hints$/, handler: (q, s, p) => this.handleScriptHints(p[0], q, s) }
57934
+ { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/script$/, handler: (q, s2, p) => this.handleRunScript(p[0], q, s2) },
57935
+ { method: "GET", pattern: /^\/api\/providers\/([^/]+)\/files$/, handler: (q, s2, p) => this.handleListFiles(p[0], q, s2) },
57936
+ { method: "GET", pattern: /^\/api\/providers\/([^/]+)\/file$/, handler: (q, s2, p) => this.handleReadFile(p[0], q, s2) },
57937
+ { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/file$/, handler: (q, s2, p) => this.handleWriteFile(p[0], q, s2) },
57938
+ { method: "GET", pattern: /^\/api\/providers\/([^/]+)\/source$/, handler: (q, s2, p) => this.handleSource(p[0], q, s2) },
57939
+ { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/save$/, handler: (q, s2, p) => this.handleSave(p[0], q, s2) },
57940
+ { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/typeAndSend$/, handler: (q, s2, p) => this.handleTypeAndSend(p[0], q, s2) },
57941
+ { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/typeAndSendAt$/, handler: (q, s2, p) => this.handleTypeAndSendAt(p[0], q, s2) },
57942
+ { method: "GET", pattern: /^\/api\/providers\/([^/]+)\/config$/, handler: (q, s2, p) => this.handleProviderConfig(p[0], q, s2) },
57943
+ { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/dom-context$/, handler: (q, s2, p) => this.handleDomContext(p[0], q, s2) },
57944
+ { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/auto-implement$/, handler: (q, s2, p) => this.handleAutoImplement(p[0], q, s2) },
57945
+ { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/auto-implement\/cancel$/, handler: (q, s2, p) => this.handleAutoImplCancel(p[0], q, s2) },
57946
+ { method: "GET", pattern: /^\/api\/providers\/([^/]+)\/auto-implement\/status$/, handler: (q, s2, p) => this.handleAutoImplSSE(p[0], q, s2) },
57947
+ { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/spawn-test$/, handler: (q, s2, p) => this.handleSpawnTest(p[0], q, s2) },
57948
+ { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/validate$/, handler: (q, s2, p) => this.handleValidate(p[0], q, s2) },
57949
+ { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/acp-chat$/, handler: (q, s2, p) => this.handleAcpChat(p[0], q, s2) },
57950
+ { method: "GET", pattern: /^\/api\/providers\/([^/]+)\/script-hints$/, handler: (q, s2, p) => this.handleScriptHints(p[0], q, s2) }
57582
57951
  ];
57583
57952
  matchRoute(method, pathname) {
57584
57953
  for (const route of this.routes) {
@@ -58173,14 +58542,14 @@ var DevServer = class _DevServer {
58173
58542
  warnings.push(...validation.warnings);
58174
58543
  if (config.settings) {
58175
58544
  for (const [key, val] of Object.entries(config.settings)) {
58176
- const s = val;
58177
- if (!s.type) errors.push(`settings.${key}: missing type`);
58178
- else if (!["boolean", "number", "string", "select"].includes(s.type))
58179
- errors.push(`settings.${key}: invalid type '${s.type}'`);
58180
- if (s.default === void 0) warnings.push(`settings.${key}: no default value`);
58181
- if (s.type === "number" && s.min !== void 0 && s.max !== void 0 && s.min > s.max)
58182
- errors.push(`settings.${key}: min (${s.min}) > max (${s.max})`);
58183
- if (s.type === "select" && (!s.options || !Array.isArray(s.options) || s.options.length === 0))
58545
+ const s2 = val;
58546
+ if (!s2.type) errors.push(`settings.${key}: missing type`);
58547
+ else if (!["boolean", "number", "string", "select"].includes(s2.type))
58548
+ errors.push(`settings.${key}: invalid type '${s2.type}'`);
58549
+ if (s2.default === void 0) warnings.push(`settings.${key}: no default value`);
58550
+ if (s2.type === "number" && s2.min !== void 0 && s2.max !== void 0 && s2.min > s2.max)
58551
+ errors.push(`settings.${key}: min (${s2.min}) > max (${s2.max})`);
58552
+ if (s2.type === "select" && (!s2.options || !Array.isArray(s2.options) || s2.options.length === 0))
58184
58553
  errors.push(`settings.${key}: select type requires options[]`);
58185
58554
  }
58186
58555
  }