@adhdev/daemon-standalone 0.9.82-rc.353 → 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.js CHANGED
@@ -30036,10 +30036,10 @@ var require_dist3 = __commonJS({
30036
30036
  }
30037
30037
  function getDaemonBuildInfo() {
30038
30038
  if (cached2) return cached2;
30039
- const commit = readInjected(true ? "a680b74d9b940b82f691ebb85a725a1a72445bfc" : void 0) ?? "unknown";
30040
- const commitShort = readInjected(true ? "a680b74d" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
30041
- const version2 = readInjected(true ? "0.9.82-rc.353" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
30042
- const builtAt = readInjected(true ? "2026-06-22T09:11:41.749Z" : void 0);
30039
+ const commit = readInjected(true ? "a45106605e2ae1c10c0bc6cbe48c2cac4e862ded" : void 0) ?? "unknown";
30040
+ const commitShort = readInjected(true ? "a4510660" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
30041
+ const version2 = readInjected(true ? "0.9.82-rc.355" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
30042
+ const builtAt = readInjected(true ? "2026-06-22T15:22:12.689Z" : void 0);
30043
30043
  cached2 = builtAt ? { commit, commitShort, version: version2, builtAt } : { commit, commitShort, version: version2 };
30044
30044
  return cached2;
30045
30045
  }
@@ -30793,6 +30793,9 @@ var require_dist3 = __commonJS({
30793
30793
  getGitDiffSummary: () => getGitDiffSummary,
30794
30794
  getGitFileDiff: () => getGitFileDiff
30795
30795
  });
30796
+ function withCollectionTimeout(options) {
30797
+ return options.timeoutMs === void 0 ? { ...options, timeoutMs: GIT_STATUS_TIMEOUT_MS } : options;
30798
+ }
30796
30799
  function validateBaseRef(ref) {
30797
30800
  const trimmed = ref.trim();
30798
30801
  if (!trimmed || trimmed.startsWith("-") || trimmed.includes("..") || !/^[A-Za-z0-9][A-Za-z0-9._/@-]*$/.test(trimmed)) {
@@ -30802,14 +30805,15 @@ var require_dist3 = __commonJS({
30802
30805
  }
30803
30806
  async function getGitDiffSummary(workspace, options = {}) {
30804
30807
  const lastCheckedAt = Date.now();
30808
+ const effectiveOptions = withCollectionTimeout(options);
30805
30809
  try {
30806
- const repo = await resolveGitRepository(workspace, options);
30810
+ const repo = await resolveGitRepository(workspace, effectiveOptions);
30807
30811
  const repoRoot = repo.repoRoot;
30808
30812
  if (options.baseRef) {
30809
30813
  const range = `${validateBaseRef(options.baseRef)}...HEAD`;
30810
30814
  const [nameStatus, numstat] = await Promise.all([
30811
- runGit(repo, ["diff", "--no-ext-diff", "--name-status", range, "--"], { ...options, cwd: repoRoot }),
30812
- runGit(repo, ["diff", "--no-ext-diff", "--numstat", range, "--"], { ...options, cwd: repoRoot })
30815
+ runGit(repo, ["diff", "--no-ext-diff", "--name-status", range, "--"], { ...effectiveOptions, cwd: repoRoot }),
30816
+ runGit(repo, ["diff", "--no-ext-diff", "--numstat", range, "--"], { ...effectiveOptions, cwd: repoRoot })
30813
30817
  ]);
30814
30818
  const outputBytes2 = byteLength(nameStatus.stdout + numstat.stdout);
30815
30819
  const changes2 = combineDiffEntries(nameStatus.stdout, numstat.stdout, false);
@@ -30828,11 +30832,11 @@ var require_dist3 = __commonJS({
30828
30832
  };
30829
30833
  }
30830
30834
  const [unstagedNameStatus, unstagedNumstat, stagedNameStatus, stagedNumstat, untracked] = await Promise.all([
30831
- runGit(repo, ["diff", "--no-ext-diff", "--name-status"], { ...options, cwd: repoRoot }),
30832
- runGit(repo, ["diff", "--no-ext-diff", "--numstat"], { ...options, cwd: repoRoot }),
30833
- runGit(repo, ["diff", "--cached", "--no-ext-diff", "--name-status"], { ...options, cwd: repoRoot }),
30834
- runGit(repo, ["diff", "--cached", "--no-ext-diff", "--numstat"], { ...options, cwd: repoRoot }),
30835
- runGit(repo, ["ls-files", "--others", "--exclude-standard"], { ...options, cwd: repoRoot })
30835
+ runGit(repo, ["diff", "--no-ext-diff", "--name-status"], { ...effectiveOptions, cwd: repoRoot }),
30836
+ runGit(repo, ["diff", "--no-ext-diff", "--numstat"], { ...effectiveOptions, cwd: repoRoot }),
30837
+ runGit(repo, ["diff", "--cached", "--no-ext-diff", "--name-status"], { ...effectiveOptions, cwd: repoRoot }),
30838
+ runGit(repo, ["diff", "--cached", "--no-ext-diff", "--numstat"], { ...effectiveOptions, cwd: repoRoot }),
30839
+ runGit(repo, ["ls-files", "--others", "--exclude-standard"], { ...effectiveOptions, cwd: repoRoot })
30836
30840
  ]);
30837
30841
  const outputBytes = byteLength(
30838
30842
  unstagedNameStatus.stdout + unstagedNumstat.stdout + stagedNameStatus.stdout + stagedNumstat.stdout + untracked.stdout
@@ -30874,13 +30878,14 @@ var require_dist3 = __commonJS({
30874
30878
  }
30875
30879
  async function getGitFileDiff(workspace, filePath, options = {}) {
30876
30880
  const lastCheckedAt = Date.now();
30877
- const repo = await resolveGitRepository(workspace, options);
30881
+ const effectiveOptions = withCollectionTimeout(options);
30882
+ const repo = await resolveGitRepository(workspace, effectiveOptions);
30878
30883
  const repoRoot = repo.repoRoot;
30879
30884
  const selected = await resolveRepoFilePath(repoRoot, filePath);
30880
30885
  const maxBytes = normalizePositiveInteger(options.maxBytes, DEFAULT_MAX_BYTES);
30881
30886
  if (options.baseRef) {
30882
30887
  const range = `${validateBaseRef(options.baseRef)}...HEAD`;
30883
- const result = await runGit(repo, ["diff", "--no-ext-diff", range, "--", selected.relativePath], { ...options, cwd: repoRoot });
30888
+ const result = await runGit(repo, ["diff", "--no-ext-diff", range, "--", selected.relativePath], { ...effectiveOptions, cwd: repoRoot });
30884
30889
  const bounded2 = truncateText(result.stdout, maxBytes);
30885
30890
  return {
30886
30891
  workspace: repo.workspace,
@@ -30893,13 +30898,13 @@ var require_dist3 = __commonJS({
30893
30898
  };
30894
30899
  }
30895
30900
  const [unstaged, staged] = await Promise.all([
30896
- runGit(repo, ["diff", "--no-ext-diff", "--", selected.relativePath], { ...options, cwd: repoRoot }),
30897
- runGit(repo, ["diff", "--cached", "--no-ext-diff", "--", selected.relativePath], { ...options, cwd: repoRoot })
30901
+ runGit(repo, ["diff", "--no-ext-diff", "--", selected.relativePath], { ...effectiveOptions, cwd: repoRoot }),
30902
+ runGit(repo, ["diff", "--cached", "--no-ext-diff", "--", selected.relativePath], { ...effectiveOptions, cwd: repoRoot })
30898
30903
  ]);
30899
30904
  let diff = [unstaged.stdout, staged.stdout].filter((part) => part.length > 0).join("\n");
30900
30905
  if (!diff) {
30901
30906
  const untracked = await runGit(repo, ["ls-files", "--others", "--exclude-standard", "--", selected.relativePath], {
30902
- ...options,
30907
+ ...effectiveOptions,
30903
30908
  cwd: repoRoot
30904
30909
  });
30905
30910
  const untrackedFiles = untracked.stdout.split("\n").filter(Boolean);
@@ -34588,9 +34593,12 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
34588
34593
  return [];
34589
34594
  }
34590
34595
  }
34591
- function updateDirectDispatchStatus(meshId, sessionId, status) {
34596
+ function updateDirectDispatchStatus(meshId, sessionId, status, taskId) {
34592
34597
  try {
34593
- MeshRuntimeStore.getInstance().updateDirectDispatchStatus(meshId, sessionId, status);
34598
+ if (!taskId) {
34599
+ LOG2.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)`);
34600
+ }
34601
+ MeshRuntimeStore.getInstance().updateDirectDispatchStatus(meshId, sessionId, status, taskId);
34594
34602
  } catch {
34595
34603
  }
34596
34604
  }
@@ -35435,9 +35443,25 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
35435
35443
  updatedAt: r.updated_at
35436
35444
  }));
35437
35445
  }
35438
- updateDirectDispatchStatus(meshId, sessionId, status) {
35439
- if (!sessionId) return;
35446
+ // CANON-B (dispatch identity): mesh_direct_dispatches is keyed by task_id (PK), but a
35447
+ // single session can host several sequential direct dispatches (re-dispatch / nudge), so
35448
+ // matching a status flip by session_id alone hits EVERY non-terminal row for that session
35449
+ // — flipping a sibling task's row and stranding the one whose event actually fired (the
35450
+ // assigned-stranded watchdog then requeues a task that is really still generating). When
35451
+ // the firing event carries a taskId, target the single PK row; the session_id match is the
35452
+ // legacy fallback only for events that arrive without a taskId.
35453
+ updateDirectDispatchStatus(meshId, sessionId, status, taskId) {
35440
35454
  const now = (/* @__PURE__ */ new Date()).toISOString();
35455
+ if (taskId) {
35456
+ this.db.prepare(`
35457
+ UPDATE mesh_direct_dispatches
35458
+ SET status = @status, updated_at = @updatedAt
35459
+ WHERE mesh_id = @meshId AND task_id = @taskId
35460
+ AND status NOT IN ('completed', 'failed')
35461
+ `).run({ status, meshId, taskId, updatedAt: now });
35462
+ return;
35463
+ }
35464
+ if (!sessionId) return;
35441
35465
  this.db.prepare(`
35442
35466
  UPDATE mesh_direct_dispatches
35443
35467
  SET status = @status, updated_at = @updatedAt
@@ -37164,7 +37188,7 @@ ${rendered}`, "utf-8");
37164
37188
  windowsHide: true
37165
37189
  }).trim();
37166
37190
  if (out) {
37167
- const matches = out.split(/\r?\n/).map((s) => s.trim()).filter(Boolean);
37191
+ const matches = out.split(/\r?\n/).map((s2) => s2.trim()).filter(Boolean);
37168
37192
  const direct = matches.find((m) => DIRECT_EXEC_EXT.has(path10.extname(m).toLowerCase()));
37169
37193
  return direct || matches[0] || command;
37170
37194
  }
@@ -38516,11 +38540,29 @@ Next step: ${nextStep}`;
38516
38540
  (pending) => pending.event === event.event && readRefineJobId2(pending) === jobId
38517
38541
  );
38518
38542
  }
38543
+ function isWeakCompletionMetadata(metadata) {
38544
+ const evidenceLevel = readNonEmptyString2(metadata.evidenceLevel);
38545
+ if (evidenceLevel === "insufficient" || evidenceLevel === "weak") return true;
38546
+ if (metadata.reviewRecommended === true) return true;
38547
+ const diag = readRecord4(metadata.completionDiagnostic);
38548
+ return diag?.finalAssistantPresent === false || diag?.blockReason === "missing_final_assistant";
38549
+ }
38519
38550
  function buildPendingEventFingerprint(event) {
38520
38551
  const metadata = readRecord4(event.metadataEvent) || {};
38521
38552
  if (event.event === "worktree_bootstrap_complete" || event.event === "worktree_bootstrap_failed") {
38522
38553
  return [event.meshId, event.event, event.nodeId || ""].join("::");
38523
38554
  }
38555
+ if (TERMINAL_COMPLETION_EVENTS.has(event.event)) {
38556
+ const terminalTaskId = readNonEmptyString2(metadata.taskId) || readNonEmptyString2(readRecord4(metadata.payload)?.taskId);
38557
+ if (terminalTaskId) {
38558
+ return [
38559
+ event.meshId,
38560
+ event.event,
38561
+ terminalTaskId,
38562
+ isWeakCompletionMetadata(metadata) ? "weak" : "genuine"
38563
+ ].join("::");
38564
+ }
38565
+ }
38524
38566
  const sessionId = resolveEventSessionId(metadata);
38525
38567
  const providerSessionId = readNonEmptyString2(metadata.providerSessionId);
38526
38568
  const taskId = readNonEmptyString2(metadata.taskId) || readNonEmptyString2(readRecord4(metadata.payload)?.taskId);
@@ -38883,6 +38925,7 @@ Next step: ${nextStep}`;
38883
38925
  var import_path9;
38884
38926
  var import_crypto7;
38885
38927
  var REFINE_TERMINAL_EVENTS;
38928
+ var TERMINAL_COMPLETION_EVENTS;
38886
38929
  var MAX_PENDING_EVENTS_BYTES;
38887
38930
  var MAX_PENDING_EVENTS_KEEP;
38888
38931
  var init_mesh_events_pending = __esm2({
@@ -38897,6 +38940,7 @@ Next step: ${nextStep}`;
38897
38940
  init_mesh_events_utils();
38898
38941
  init_dist();
38899
38942
  REFINE_TERMINAL_EVENTS = /* @__PURE__ */ new Set(["refine:completed", "refine:failed"]);
38943
+ TERMINAL_COMPLETION_EVENTS = /* @__PURE__ */ new Set(["agent:generating_completed", "agent:stopped"]);
38900
38944
  MAX_PENDING_EVENTS_BYTES = 100 * 1024;
38901
38945
  MAX_PENDING_EVENTS_KEEP = 50;
38902
38946
  }
@@ -39225,7 +39269,7 @@ Next step: ${nextStep}`;
39225
39269
  evidence
39226
39270
  }
39227
39271
  });
39228
- updateDirectDispatchStatus(args.meshId, args.sessionId, kind === "task_completed" ? "completed" : "failed");
39272
+ updateDirectDispatchStatus(args.meshId, args.sessionId, kind === "task_completed" ? "completed" : "failed", args.taskId);
39229
39273
  markSessionDeliveriesTerminal(args.meshId, args.sessionId, kind === "task_completed" ? "completed" : "failed");
39230
39274
  setImmediate(() => cleanupTerminalDirectDispatches());
39231
39275
  queuePendingMeshCoordinatorEvent({
@@ -39511,8 +39555,8 @@ Next step: ${nextStep}`;
39511
39555
  if (x instanceof RegExp) return x;
39512
39556
  if (x && typeof x === "object" && typeof x.source === "string") {
39513
39557
  try {
39514
- const s = x;
39515
- return new RegExp(s.source, s.flags || "");
39558
+ const s2 = x;
39559
+ return new RegExp(s2.source, s2.flags || "");
39516
39560
  } catch {
39517
39561
  return null;
39518
39562
  }
@@ -40086,6 +40130,36 @@ Next step: ${nextStep}`;
40086
40130
  UNRESOLVED_FORWARD_MAX_AGE_MS = 30 * 60 * 1e3;
40087
40131
  }
40088
40132
  });
40133
+ function s(v) {
40134
+ return typeof v === "string" && v.trim() ? v.trim() : "";
40135
+ }
40136
+ function meshEventTraceKey(ctx) {
40137
+ const segs = [`task=${s(ctx.taskId) || "-"}`];
40138
+ const eventId = s(ctx.eventId);
40139
+ if (eventId) segs.push(`evt=${eventId}`);
40140
+ segs.push(`sess=${s(ctx.sessionId) || "-"}`);
40141
+ const nodeId = s(ctx.nodeId);
40142
+ if (nodeId) segs.push(`node=${nodeId}`);
40143
+ const meshId = s(ctx.meshId);
40144
+ if (meshId) segs.push(`mesh=${meshId}`);
40145
+ const event = s(ctx.event);
40146
+ if (event) segs.push(`event=${event}`);
40147
+ return segs.join(" ");
40148
+ }
40149
+ function traceMeshEventStage(stage, ctx, detail) {
40150
+ LOG2.info(CAT, `[stage:${stage}] ${meshEventTraceKey(ctx)}${detail ? ` \u2014 ${detail}` : ""}`);
40151
+ }
40152
+ function traceMeshEventDrop(reason, ctx, detail) {
40153
+ LOG2.warn(CAT, `[drop:${reason}] ${meshEventTraceKey(ctx)}${detail ? ` \u2014 ${detail}` : ""}`);
40154
+ }
40155
+ var CAT;
40156
+ var init_mesh_event_trace = __esm2({
40157
+ "src/mesh/mesh-event-trace.ts"() {
40158
+ "use strict";
40159
+ init_logger();
40160
+ CAT = "EvtTrace";
40161
+ }
40162
+ });
40089
40163
  function isPlainObject22(value) {
40090
40164
  return !!value && typeof value === "object" && !Array.isArray(value);
40091
40165
  }
@@ -41879,9 +41953,9 @@ ${cleanBody}`;
41879
41953
  }
41880
41954
  function buildSessionEntries(allStates, cdpManagers, options = {}) {
41881
41955
  const sessions = [];
41882
- const ideStates = allStates.filter((s) => s.category === "ide");
41883
- const cliStates = allStates.filter((s) => s.category === "cli");
41884
- const acpStates = allStates.filter((s) => s.category === "acp");
41956
+ const ideStates = allStates.filter((s2) => s2.category === "ide");
41957
+ const cliStates = allStates.filter((s2) => s2.category === "cli");
41958
+ const acpStates = allStates.filter((s2) => s2.category === "acp");
41885
41959
  for (const state of ideStates) {
41886
41960
  sessions.push(buildWorkspaceSession(state, cdpManagers, options));
41887
41961
  for (const ext of state.extensions) {
@@ -42365,6 +42439,15 @@ ${cleanBody}`;
42365
42439
  meshByWorkspaceCache.set(workspace, { mesh, cachedAt: now });
42366
42440
  return mesh;
42367
42441
  }
42442
+ function recoverMeshIdByNodeId(nodeId) {
42443
+ if (!nodeId) return "";
42444
+ for (const mesh of listMeshes()) {
42445
+ if (Array.isArray(mesh.nodes) && mesh.nodes.some((n) => meshNodeIdMatches(n, nodeId))) {
42446
+ return readNonEmptyString2(mesh.id);
42447
+ }
42448
+ }
42449
+ return "";
42450
+ }
42368
42451
  function __resetIdleAutoFastForwardForTests() {
42369
42452
  idleAutoFastForwardLastAttempt.clear();
42370
42453
  }
@@ -43267,6 +43350,13 @@ ${cleanBody}`;
43267
43350
  function injectMeshSystemMessage(components, args) {
43268
43351
  const eventSessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
43269
43352
  const eventNodeId = readNonEmptyString2(args.nodeId) || readNonEmptyString2(args.metadataEvent.meshNodeId);
43353
+ const traceCtx = {
43354
+ taskId: args.metadataEvent.taskId,
43355
+ sessionId: eventSessionId,
43356
+ nodeId: eventNodeId,
43357
+ meshId: args.meshId,
43358
+ event: args.event
43359
+ };
43270
43360
  const sourceSession = args.sourceInstanceId ? components.instanceManager.getInstance(args.sourceInstanceId) : void 0;
43271
43361
  const workerCoordinatorDaemonId = readNonEmptyString2(
43272
43362
  sourceSession?.getState()?.settings?.meshCoordinatorDaemonId
@@ -43320,6 +43410,7 @@ ${cleanBody}`;
43320
43410
  }
43321
43411
  }
43322
43412
  LOG2.info("MeshEvents", `Suppressed ${args.event} for intentionally cleanup-stopped session ${eventSessionId || "(unknown session)"}`);
43413
+ traceMeshEventDrop("intentional_cleanup_stop", traceCtx);
43323
43414
  return { success: true, forwarded: 0, suppressed: true, intentionalCleanupStop: true };
43324
43415
  }
43325
43416
  if (args.event === "monitor:no_progress") {
@@ -43340,6 +43431,7 @@ ${cleanBody}`;
43340
43431
  }
43341
43432
  if (reconciledCompletion?.source === "no_progress_terminal_ledger_suppression") {
43342
43433
  LOG2.info("MeshEvents", `Suppressed no-progress monitor because terminal ledger evidence already exists for session ${eventSessionId || "(unknown session)"}`);
43434
+ traceMeshEventDrop("no_progress_terminal_ledger_suppression", traceCtx, `terminalKind=${reconciledCompletion.terminalLedgerKind}`);
43343
43435
  return {
43344
43436
  success: true,
43345
43437
  forwarded: 0,
@@ -43351,6 +43443,7 @@ ${cleanBody}`;
43351
43443
  }
43352
43444
  if (isDuplicateRefineTerminalEvent(args.meshId, args.event, args.metadataEvent)) {
43353
43445
  LOG2.info("MeshEvents", `Suppressed duplicate ${args.event} for refine job ${readRefineJobId({ metadataEvent: args.metadataEvent })}`);
43446
+ traceMeshEventDrop("duplicate_refine_terminal", traceCtx);
43354
43447
  return { success: true, forwarded: 0, suppressed: true, duplicateRefineTerminalEvent: true };
43355
43448
  }
43356
43449
  const eventTimestamp = readEventTimestamp(args.metadataEvent.timestamp);
@@ -43365,6 +43458,7 @@ ${cleanBody}`;
43365
43458
  });
43366
43459
  if (duplicateApproval) {
43367
43460
  LOG2.info("MeshEvents", `Suppressed duplicate approval event for mesh ${args.meshId} session ${eventSessionId}`);
43461
+ traceMeshEventDrop("duplicate_approval", traceCtx);
43368
43462
  return { success: true, forwarded: 0, suppressed: true, duplicateApproval: true };
43369
43463
  }
43370
43464
  }
@@ -43384,6 +43478,7 @@ ${cleanBody}`;
43384
43478
  const eventFinalSummary = readNonEmptyString2(args.metadataEvent.finalSummary);
43385
43479
  if (terminalProviderSessionId && terminalProviderSessionId === eventProviderSessionId || terminalFinalSummary && terminalFinalSummary === eventFinalSummary || args.metadataEvent.source === "no_progress_reconciliation") {
43386
43480
  LOG2.info("MeshEvents", `Suppressed duplicate completion with existing terminal ledger evidence for mesh ${args.meshId} session ${eventSessionId}`);
43481
+ traceMeshEventDrop("duplicate_completion_terminal_ledger", traceCtx);
43387
43482
  return { success: true, forwarded: 0, suppressed: true, duplicateCompletion: true, terminalLedgerEvidence: true };
43388
43483
  }
43389
43484
  }
@@ -43402,6 +43497,7 @@ ${cleanBody}`;
43402
43497
  });
43403
43498
  if (duplicateCompletion) {
43404
43499
  LOG2.info("MeshEvents", `Suppressed duplicate completion for mesh ${args.meshId} session ${eventSessionId}`);
43500
+ traceMeshEventDrop("duplicate_completion", traceCtx);
43405
43501
  return { success: true, forwarded: 0, suppressed: true, duplicateCompletion: true };
43406
43502
  }
43407
43503
  }
@@ -43420,6 +43516,7 @@ ${cleanBody}`;
43420
43516
  });
43421
43517
  if (duplicateStopped) {
43422
43518
  LOG2.info("MeshEvents", `Suppressed duplicate stopped event for mesh ${args.meshId} session ${eventSessionId}`);
43519
+ traceMeshEventDrop("duplicate_stopped", traceCtx);
43423
43520
  return { success: true, forwarded: 0, suppressed: true, duplicateStopped: true };
43424
43521
  }
43425
43522
  }
@@ -43431,7 +43528,7 @@ ${cleanBody}`;
43431
43528
  });
43432
43529
  const leaveDirectDispatchActive = !task && opts?.tentativeIfDirect === true;
43433
43530
  if (!leaveDirectDispatchActive) {
43434
- updateDirectDispatchStatus(args.meshId, sessionId, outcome);
43531
+ updateDirectDispatchStatus(args.meshId, sessionId, outcome, eventTaskId);
43435
43532
  }
43436
43533
  markSessionDeliveriesTerminal(args.meshId, sessionId, outcome);
43437
43534
  setImmediate(() => cleanupTerminalDirectDispatches());
@@ -43444,7 +43541,7 @@ ${cleanBody}`;
43444
43541
  const nodeId = readNonEmptyString2(args.nodeId) || readNonEmptyString2(args.metadataEvent.meshNodeId);
43445
43542
  const providerType = readNonEmptyString2(args.metadataEvent.providerType);
43446
43543
  if (sessionId) {
43447
- directDispatchTaskIdForLedger = resolveActiveDirectDispatchTaskId(args.meshId, sessionId);
43544
+ directDispatchTaskIdForLedger = readNonEmptyString2(args.metadataEvent.taskId) || resolveActiveDirectDispatchTaskId(args.meshId, sessionId);
43448
43545
  const isFalseIdle = isFalseIdleCompletion(args.metadataEvent);
43449
43546
  completedTaskForLedger = markSessionTerminal(sessionId, "completed", eventTimestamp, { tentativeIfDirect: isFalseIdle });
43450
43547
  if (nodeId && providerType) {
@@ -43527,7 +43624,8 @@ ${cleanBody}`;
43527
43624
  }
43528
43625
  }
43529
43626
  if (sessionId) {
43530
- updateDirectDispatchStatus(args.meshId, sessionId, "acked");
43627
+ const startedTaskId = readNonEmptyString2(args.metadataEvent.taskId) || void 0;
43628
+ updateDirectDispatchStatus(args.meshId, sessionId, "acked", startedTaskId);
43531
43629
  const activeDeliveries = (() => {
43532
43630
  try {
43533
43631
  return MeshRuntimeStore.getInstance().getActiveSessionDeliveries(args.meshId, sessionId);
@@ -43535,7 +43633,8 @@ ${cleanBody}`;
43535
43633
  return [];
43536
43634
  }
43537
43635
  })();
43538
- for (const d of activeDeliveries) {
43636
+ const deliveriesToAck = startedTaskId ? activeDeliveries.filter((d) => d.taskId === startedTaskId) : activeDeliveries;
43637
+ for (const d of deliveriesToAck) {
43539
43638
  updateSessionDeliveryStatus(d.id, "acked");
43540
43639
  }
43541
43640
  }
@@ -43549,7 +43648,7 @@ ${cleanBody}`;
43549
43648
  }
43550
43649
  }
43551
43650
  if (sessionId) {
43552
- directDispatchTaskIdForLedger = resolveActiveDirectDispatchTaskId(args.meshId, sessionId);
43651
+ directDispatchTaskIdForLedger = readNonEmptyString2(args.metadataEvent.taskId) || resolveActiveDirectDispatchTaskId(args.meshId, sessionId);
43553
43652
  completedTaskForLedger = markSessionTerminal(sessionId, "failed");
43554
43653
  }
43555
43654
  }
@@ -43695,6 +43794,9 @@ ${cleanBody}`;
43695
43794
  };
43696
43795
  if (queuePendingMeshCoordinatorEvent(pendingEvent)) {
43697
43796
  LOG2.info("MeshEvents", `Queued ${args.event} for coordinator (mesh ${args.meshId}${workerCoordinatorDaemonId ? `, coordinator daemon ${workerCoordinatorDaemonId}` : ""}${workerCoordinatorSessionId ? `, coordinator session ${workerCoordinatorSessionId}` : ""})`);
43797
+ traceMeshEventStage("queued", traceCtx, workerCoordinatorDaemonId ? `coordinatorDaemon=${workerCoordinatorDaemonId}` : "broadcast");
43798
+ } else {
43799
+ traceMeshEventDrop("queue_dedup", traceCtx);
43698
43800
  }
43699
43801
  return { success: true, forwarded: 0 };
43700
43802
  }
@@ -43705,8 +43807,23 @@ ${cleanBody}`;
43705
43807
  }
43706
43808
  const nodeId = readNonEmptyString2(payload.nodeId);
43707
43809
  const workspace = readNonEmptyString2(payload.workspace);
43708
- const meshId = readNonEmptyString2(payload.meshId) || (workspace ? readNonEmptyString2(getCachedMeshByWorkspace(workspace)?.id) : "");
43709
- if (!meshId) return { success: false, error: "meshId required" };
43810
+ const meshId = readNonEmptyString2(payload.meshId) || (workspace ? readNonEmptyString2(getCachedMeshByWorkspace(workspace)?.id) : "") || recoverMeshIdByNodeId(nodeId);
43811
+ if (!meshId) {
43812
+ traceMeshEventDrop("meshId_required", {
43813
+ taskId: payload.taskId,
43814
+ sessionId: readNonEmptyString2(payload.targetSessionId) || readNonEmptyString2(payload.sessionId),
43815
+ nodeId,
43816
+ event: eventName
43817
+ }, workspace ? `workspace=${workspace} unresolved` : "no workspace/nodeId");
43818
+ return { success: false, error: "meshId required" };
43819
+ }
43820
+ traceMeshEventStage("received", {
43821
+ taskId: payload.taskId,
43822
+ sessionId: readNonEmptyString2(payload.targetSessionId) || readNonEmptyString2(payload.sessionId),
43823
+ nodeId,
43824
+ meshId,
43825
+ event: eventName
43826
+ });
43710
43827
  const nodeLabel = nodeId ? `Node '${nodeId}'` : workspace ? `Agent at ${workspace}` : "Remote agent";
43711
43828
  const relayModalMessage = readNonEmptyString2(payload.modalMessage);
43712
43829
  const relayModalButtons = Array.isArray(payload.modalButtons) ? payload.modalButtons.filter((b) => typeof b === "string" && b.trim().length > 0) : null;
@@ -43787,9 +43904,18 @@ ${cleanBody}`;
43787
43904
  workspace: readNonEmptyString2(routing.workspace) || readNonEmptyString2(event.workspace) || void 0
43788
43905
  };
43789
43906
  const persisted = enqueueUnresolvedDelegateForward(coordinatorDaemonId, eventName, payload);
43907
+ const fwdTraceCtx = {
43908
+ taskId: payload.taskId,
43909
+ sessionId: readNonEmptyString2(payload.targetSessionId) || readNonEmptyString2(payload.sessionId),
43910
+ nodeId: readNonEmptyString2(routing.nodeId) || readNonEmptyString2(event.meshNodeId),
43911
+ event: eventName
43912
+ };
43913
+ traceMeshEventStage("outbox_enqueue", fwdTraceCtx, `coordinatorDaemon=${coordinatorDaemonId} meshId=absent`);
43914
+ traceMeshEventStage("forward_send", fwdTraceCtx, "immediate push");
43790
43915
  Promise.resolve(components.dispatchMeshCommand(coordinatorDaemonId, "mesh_forward_event", payload)).then((result) => {
43791
43916
  if (result && result.success === false) {
43792
43917
  LOG2.warn("MeshEvents", `Immediate forward of ${eventName} to coordinator ${coordinatorDaemonId} rejected (${readNonEmptyString2(result.error) || "no reason"}) \u2014 left queued for retry`);
43918
+ traceMeshEventDrop("immediate_forward_rejected", fwdTraceCtx, readNonEmptyString2(result.error) || "no reason");
43793
43919
  return;
43794
43920
  }
43795
43921
  if (persisted) ackUnresolvedDelegateForwardByFingerprint(coordinatorDaemonId, eventName, payload);
@@ -43857,6 +43983,14 @@ ${cleanBody}`;
43857
43983
  if (isUnroutableDelegateRejection(routing) && forwardUnresolvedDelegateEvent(components, routing, event)) {
43858
43984
  return;
43859
43985
  }
43986
+ if (isUnroutableDelegateRejection(routing)) {
43987
+ traceMeshEventDrop("unroutable", {
43988
+ taskId: event.meshActiveTaskId ?? event.taskId,
43989
+ sessionId: routing.sessionId,
43990
+ nodeId: routing.nodeId,
43991
+ event: event.event
43992
+ }, "no coordinator anchor / mesh_unresolved");
43993
+ }
43860
43994
  recordUnroutableDelegateEvent(routing, event.event);
43861
43995
  return;
43862
43996
  }
@@ -43904,6 +44038,7 @@ ${cleanBody}`;
43904
44038
  init_mesh_events_pending();
43905
44039
  init_mesh_routing();
43906
44040
  init_mesh_unresolved_forward_outbox();
44041
+ init_mesh_event_trace();
43907
44042
  init_snapshot();
43908
44043
  init_repo_mesh_types();
43909
44044
  init_dist();
@@ -44013,6 +44148,13 @@ ${cleanBody}`;
44013
44148
  function injectPendingIntoCoordinator(coordinator, pending) {
44014
44149
  if (!coordinator || !pending.coordinatorMessage) return;
44015
44150
  const force = shouldForceInjectMeshEvent(pending.event);
44151
+ traceMeshEventStage("surfaced", {
44152
+ taskId: pending.metadataEvent?.taskId,
44153
+ sessionId: pending.metadataEvent?.targetSessionId ?? pending.targetCoordinatorSessionId,
44154
+ nodeId: pending.nodeId,
44155
+ meshId: pending.meshId,
44156
+ event: pending.event
44157
+ }, force ? "force-inject" : "inject");
44016
44158
  coordinator.onEvent("send_message", {
44017
44159
  input: { text: pending.coordinatorMessage, textFallback: pending.coordinatorMessage },
44018
44160
  ...force ? { force: true } : {}
@@ -44071,6 +44213,13 @@ ${cleanBody}`;
44071
44213
  });
44072
44214
  if (reclaimed) {
44073
44215
  LOG2.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})`);
44216
+ traceMeshEventDrop("assigned_stranded_reclaim", {
44217
+ taskId: row.id,
44218
+ sessionId: row.assignedSessionId,
44219
+ nodeId: row.assignedNodeId,
44220
+ meshId,
44221
+ event: "agent:generating_completed"
44222
+ }, `unconfirmed ${Math.round((nowMs - dispatchedAtMs) / 1e3)}s \u2192 ${reclaimed.status}`);
44074
44223
  }
44075
44224
  }
44076
44225
  }
@@ -44230,6 +44379,13 @@ ${cleanBody}`;
44230
44379
  try {
44231
44380
  queuePendingMeshCoordinatorEvent(pending);
44232
44381
  LOG2.info("MeshReconcile", `Strict route hold: coordinator session ${wantSession} not live on mesh ${meshId} \u2014 re-queued (${pending.event})`);
44382
+ traceMeshEventDrop("strict_route_hold", {
44383
+ taskId: pending.metadataEvent?.taskId,
44384
+ sessionId: pending.metadataEvent?.targetSessionId ?? wantSession,
44385
+ nodeId: pending.nodeId,
44386
+ meshId,
44387
+ event: pending.event
44388
+ }, `coordinatorSession=${wantSession} not live`);
44233
44389
  } catch (e) {
44234
44390
  LOG2.warn("MeshReconcile", `Strict route re-queue failed for ${pending.event} on mesh ${meshId}: ${e?.message || e}`);
44235
44391
  }
@@ -44253,6 +44409,13 @@ ${cleanBody}`;
44253
44409
  }
44254
44410
  });
44255
44411
  LOG2.warn("MeshReconcile", `Strict route expire: coordinator session ${wantSession} never returned for mesh ${meshId} \u2014 recorded to ledger (recoverable), dropped (${pending.event})`);
44412
+ traceMeshEventDrop("strict_route_expired", {
44413
+ taskId: pending.metadataEvent?.taskId,
44414
+ sessionId: pending.metadataEvent?.targetSessionId ?? wantSession,
44415
+ nodeId: pending.nodeId,
44416
+ meshId,
44417
+ event: pending.event
44418
+ }, `coordinatorSession=${wantSession} never returned`);
44256
44419
  } catch (e) {
44257
44420
  LOG2.warn("MeshReconcile", `Failed to ledger-expire strict-unmatched ${pending.event} for mesh ${meshId}: ${e?.message || e}`);
44258
44421
  }
@@ -44264,15 +44427,24 @@ ${cleanBody}`;
44264
44427
  const entries = peekUnresolvedDelegateForwards();
44265
44428
  if (entries.length === 0) return;
44266
44429
  for (const entry of entries) {
44430
+ const entryTraceCtx = {
44431
+ taskId: entry.payload.taskId,
44432
+ sessionId: readNonEmptyString2(entry.payload.targetSessionId) || readNonEmptyString2(entry.payload.sessionId),
44433
+ nodeId: readNonEmptyString2(entry.payload.nodeId),
44434
+ event: readNonEmptyString2(entry.payload.event)
44435
+ };
44267
44436
  let result;
44268
44437
  try {
44438
+ traceMeshEventStage("forward_send", entryTraceCtx, `retry \u2192 ${entry.coordinatorDaemonId}`);
44269
44439
  result = await dispatchMeshCommand(entry.coordinatorDaemonId, "mesh_forward_event", entry.payload);
44270
44440
  } catch (e) {
44271
44441
  LOG2.warn("MeshReconcile", `Retry forward to coordinator ${entry.coordinatorDaemonId} failed: ${e?.message || e} \u2014 left queued`);
44442
+ traceMeshEventDrop("retry_forward_failed", entryTraceCtx, e?.message || String(e));
44272
44443
  continue;
44273
44444
  }
44274
44445
  if (result && result.success === false) {
44275
44446
  LOG2.warn("MeshReconcile", `Retry forward to coordinator ${entry.coordinatorDaemonId} rejected (${readNonEmptyString2(result.error) || "no reason"}) \u2014 left queued`);
44447
+ traceMeshEventDrop("retry_forward_rejected", entryTraceCtx, readNonEmptyString2(result.error) || "no reason");
44276
44448
  continue;
44277
44449
  }
44278
44450
  ackUnresolvedDelegateForward(entry.id);
@@ -44518,6 +44690,7 @@ ${cleanBody}`;
44518
44690
  init_mesh_events_coordinator();
44519
44691
  init_mesh_unresolved_forward_outbox();
44520
44692
  init_mesh_events_utils();
44693
+ init_mesh_event_trace();
44521
44694
  init_dist();
44522
44695
  init_mesh_work_queue();
44523
44696
  init_mesh_ledger();
@@ -45347,8 +45520,8 @@ ${cleanBody}`;
45347
45520
  }
45348
45521
  function isValidSource(x) {
45349
45522
  if (!x || typeof x !== "object") return false;
45350
- const s = x;
45351
- 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";
45523
+ const s2 = x;
45524
+ 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";
45352
45525
  }
45353
45526
  function deriveSourceName(url2) {
45354
45527
  const m = url2.match(/[/:]([^/:]+)\/([^/]+?)(?:\.git)?$/);
@@ -45404,7 +45577,7 @@ ${cleanBody}`;
45404
45577
  }
45405
45578
  function sourcesProviding(category, type) {
45406
45579
  const inventory = inventoryExternalSources();
45407
- return inventory.filter((s) => (s.providers[category] || []).includes(type)).map((s) => s.sourceName);
45580
+ return inventory.filter((s2) => (s2.providers[category] || []).includes(type)).map((s2) => s2.sourceName);
45408
45581
  }
45409
45582
  function resolveActiveSource(category, type, activeFile) {
45410
45583
  const candidates = sourcesProviding(category, type);
@@ -45612,10 +45785,10 @@ ${cleanBody}`;
45612
45785
  const footers = (spec.withFooter ?? []).map((f) => {
45613
45786
  if (f.kind === "regex") {
45614
45787
  const re = compile2(f.pattern, f.flags ?? "i");
45615
- return { test: (s) => re.test(s) };
45788
+ return { test: (s2) => re.test(s2) };
45616
45789
  }
45617
45790
  const needle = f.pattern.toLowerCase();
45618
- return { test: (s) => s.toLowerCase().includes(needle) };
45791
+ return { test: (s2) => s2.toLowerCase().includes(needle) };
45619
45792
  });
45620
45793
  return { prompt, footers };
45621
45794
  }
@@ -46490,7 +46663,7 @@ ${cont}` : cont;
46490
46663
  }
46491
46664
  resolveModal(buttonIndex) {
46492
46665
  const snap = this.transport.getSnapshot();
46493
- const parseApproval = typeof this.transport.runParseApproval === "function" ? (s) => this.transport.runParseApproval(s.recentOutputBuffer.slice(-500)) : (s) => this.runParseApproval(s);
46666
+ const parseApproval = typeof this.transport.runParseApproval === "function" ? (s2) => this.transport.runParseApproval(s2.recentOutputBuffer.slice(-500)) : (s2) => this.runParseApproval(s2);
46494
46667
  let modal = this.activeModal ?? parseApproval(snap);
46495
46668
  if (!modal && this.runner.hasParseSession()) {
46496
46669
  try {
@@ -49176,22 +49349,23 @@ ${lastSnapshot}`;
49176
49349
  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]));
49177
49350
  let idx = -1;
49178
49351
  for (const c of candidates) {
49352
+ let candIdx = -1;
49179
49353
  if (sec.anchor_last) {
49180
49354
  for (let i = total - 1; i >= 0; i--) {
49181
49355
  if (matchesCandidate(c, i)) {
49182
- idx = i;
49356
+ candIdx = i;
49183
49357
  break;
49184
49358
  }
49185
49359
  }
49186
49360
  } else {
49187
49361
  for (let i = 0; i < total; i++) {
49188
49362
  if (matchesCandidate(c, i)) {
49189
- idx = i;
49363
+ candIdx = i;
49190
49364
  break;
49191
49365
  }
49192
49366
  }
49193
49367
  }
49194
- if (idx !== -1) break;
49368
+ if (candIdx !== -1 && (idx === -1 || candIdx < idx)) idx = candIdx;
49195
49369
  }
49196
49370
  if (idx !== -1) {
49197
49371
  from = idx;
@@ -49243,7 +49417,7 @@ ${lastSnapshot}`;
49243
49417
  }
49244
49418
  function sectionText(sections, sectionId, fullScreen) {
49245
49419
  if (!sectionId) return fullScreen;
49246
- const found = sections.find((s) => s.id === sectionId);
49420
+ const found = sections.find((s2) => s2.id === sectionId);
49247
49421
  return found ? found.text : "";
49248
49422
  }
49249
49423
  function isRegexCondition(c) {
@@ -49409,10 +49583,10 @@ ${lastSnapshot}`;
49409
49583
  return !!raw && typeof raw === "object" && raw.$schema === "adhdev:cli/spec@4";
49410
49584
  }
49411
49585
  function initialState(spec) {
49412
- return spec.states.find((s) => s.initial) ?? spec.states[0];
49586
+ return spec.states.find((s2) => s2.initial) ?? spec.states[0];
49413
49587
  }
49414
49588
  function stateById(spec, id) {
49415
- return spec.states.find((s) => s.id === id);
49589
+ return spec.states.find((s2) => s2.id === id);
49416
49590
  }
49417
49591
  function outgoingTransitions(spec, stateId) {
49418
49592
  const matches = spec.transitions.filter((t) => {
@@ -49499,7 +49673,17 @@ ${lastSnapshot}`;
49499
49673
  const result = evaluateCondition(cond, sections, fullScreen, cursor, prevLines, legacyTrace, stateId);
49500
49674
  const kind = isRegex(cond) ? "regex" : "changed";
49501
49675
  const detail = isRegex(cond) ? `${cond.section ?? "*"}~/${cond.matches}/` : `cursor_above=${cond.cursor_above} changed=${cond.changed}`;
49502
- return { kind, result, detail };
49676
+ let matchedText;
49677
+ if (result && isRegex(cond)) {
49678
+ try {
49679
+ const hay = sectionText(sections, cond.section, fullScreen);
49680
+ const re = new RegExp(cond.matches, cond.flags ?? "i");
49681
+ const m = re.exec(hay);
49682
+ if (m && m[0]) matchedText = m[0].replace(/\s+/g, " ").trim().slice(0, 160);
49683
+ } catch {
49684
+ }
49685
+ }
49686
+ return matchedText ? { kind, result, detail, matchedText } : { kind, result, detail };
49503
49687
  }
49504
49688
  return { kind: "all", result: false, detail: "unknown condition" };
49505
49689
  }
@@ -49612,17 +49796,17 @@ ${lastSnapshot}`;
49612
49796
  }
49613
49797
  const ids = /* @__PURE__ */ new Set();
49614
49798
  let initialCount = 0;
49615
- for (const [i, s] of spec.states.entries()) {
49616
- if (!s.id) {
49799
+ for (const [i, s2] of spec.states.entries()) {
49800
+ if (!s2.id) {
49617
49801
  errs.push(`states[${i}].id is required`);
49618
49802
  continue;
49619
49803
  }
49620
- if (ids.has(s.id)) errs.push(`states[${i}].id "${s.id}" is duplicated`);
49621
- ids.add(s.id);
49622
- if (!s.label) errs.push(`states[${i}].label is required`);
49623
- if (s.initial) initialCount += 1;
49624
- if (s.status && !["idle", "generating", "approval"].includes(s.status)) {
49625
- errs.push(`states[${i}].status "${s.status}" must be idle|generating|approval`);
49804
+ if (ids.has(s2.id)) errs.push(`states[${i}].id "${s2.id}" is duplicated`);
49805
+ ids.add(s2.id);
49806
+ if (!s2.label) errs.push(`states[${i}].label is required`);
49807
+ if (s2.initial) initialCount += 1;
49808
+ if (s2.status && !["idle", "generating", "approval"].includes(s2.status)) {
49809
+ errs.push(`states[${i}].status "${s2.status}" must be idle|generating|approval`);
49626
49810
  }
49627
49811
  }
49628
49812
  if (initialCount === 0) errs.push("exactly one state must have initial:true (none found)");
@@ -49638,10 +49822,10 @@ ${lastSnapshot}`;
49638
49822
  else if (!ids.has(t.to)) errs.push(`transitions[${i}].to references unknown state "${t.to}"`);
49639
49823
  if (t.when) errs.push(...validateCondition(t.when, sectionIds, `transitions[${i}].when`));
49640
49824
  }
49641
- for (const [i, s] of spec.states.entries()) {
49642
- const sec = s.extract?.title?.section;
49825
+ for (const [i, s2] of spec.states.entries()) {
49826
+ const sec = s2.extract?.title?.section;
49643
49827
  if (sec && !sectionIds.has(sec)) errs.push(`states[${i}].extract.title.section "${sec}" unknown`);
49644
- const bsec = s.extract?.buttons?.section;
49828
+ const bsec = s2.extract?.buttons?.section;
49645
49829
  if (bsec && !sectionIds.has(bsec)) errs.push(`states[${i}].extract.buttons.section "${bsec}" unknown`);
49646
49830
  }
49647
49831
  return errs;
@@ -57154,6 +57338,40 @@ ${effect.notification.body || ""}`.trim();
57154
57338
  }
57155
57339
  return fn() || null;
57156
57340
  }
57341
+ var AUTO_APPROVE_MANUAL_ATTENDANCE_SUPPRESS_MS = 6e4;
57342
+ var ManualAttendanceTracker = class {
57343
+ constructor(suppressMs = AUTO_APPROVE_MANUAL_ATTENDANCE_SUPPRESS_MS) {
57344
+ this.suppressMs = suppressMs;
57345
+ }
57346
+ lastInteractionAt = 0;
57347
+ /** Record that a human just drove this session by hand. */
57348
+ note(now = Date.now()) {
57349
+ this.lastInteractionAt = now;
57350
+ }
57351
+ /** True while a manual interaction is recent enough to suppress auto-approve. */
57352
+ isAttended(now = Date.now()) {
57353
+ return this.lastInteractionAt > 0 && now - this.lastInteractionAt < this.suppressMs;
57354
+ }
57355
+ /**
57356
+ * Milliseconds remaining in the current suppression window, or 0 when not
57357
+ * attended. Used to re-arm a re-check timer so auto-approve fires the moment
57358
+ * the window lapses even if the PTY/agent has since gone silent.
57359
+ */
57360
+ remainingMs(now = Date.now()) {
57361
+ if (this.lastInteractionAt <= 0) return 0;
57362
+ return Math.max(0, this.suppressMs - (now - this.lastInteractionAt));
57363
+ }
57364
+ };
57365
+ var MANUAL_ATTENDANCE_COMMANDS = /* @__PURE__ */ new Set([
57366
+ "select_session",
57367
+ "open_panel",
57368
+ "invoke_provider_script",
57369
+ "set_mode",
57370
+ "change_model",
57371
+ "set_thought_level",
57372
+ "resolve_action",
57373
+ "pty_input"
57374
+ ]);
57157
57375
  var fs7 = __toESM2(require("fs"));
57158
57376
  var os10 = __toESM2(require("os"));
57159
57377
  var path16 = __toESM2(require("path"));
@@ -61468,11 +61686,38 @@ ${effect.notification.body || ""}`.trim();
61468
61686
  setAgentStreamManager(manager) {
61469
61687
  this._agentStream = manager;
61470
61688
  }
61689
+ /**
61690
+ * When a command in the manual-attendance set arrives for a session this
61691
+ * daemon hosts, stamp the live instance so auto-approve holds while the user
61692
+ * drives the session by hand. Provider-common: the signal is the command
61693
+ * (foreground select_session / open_panel, controlbar invoke_provider_script
61694
+ * / set_mode / change_model / set_thought_level, manual resolve_action,
61695
+ * pty_input), never any CLI-specific modal text — so it works identically for
61696
+ * every CLI/ACP provider. send_chat is deliberately excluded because a
61697
+ * coordinator delegating a task to a worker also uses send_chat; counting it
61698
+ * would wrongly suppress the worker's delegated auto-approve. For a remote
61699
+ * mesh worker session the controlbar commands are forwarded to the owning
61700
+ * worker daemon, which runs this same hook there, so attendance is recorded
61701
+ * on the daemon that actually hosts the instance.
61702
+ */
61703
+ noteManualAttendanceIfApplicable(cmd, args) {
61704
+ if (!MANUAL_ATTENDANCE_COMMANDS.has(cmd)) return;
61705
+ const sessionId = this._currentRoute.session?.sessionId || (typeof args?.targetSessionId === "string" ? args.targetSessionId.trim() : "");
61706
+ if (!sessionId) return;
61707
+ const session = this._ctx.sessionRegistry?.get(sessionId);
61708
+ const instanceKey = session?.adapterKey || session?.instanceKey || sessionId;
61709
+ const instance = this._ctx.instanceManager?.getInstance(instanceKey);
61710
+ try {
61711
+ instance?.noteManualInteraction?.();
61712
+ } catch {
61713
+ }
61714
+ }
61471
61715
  // ─── Command Dispatcher ──────────────────────────
61472
61716
  async handle(cmd, args) {
61473
61717
  this._currentRoute = this.resolveRoute(args);
61474
61718
  const startedAt = Date.now();
61475
61719
  this.logCommandStart(cmd, args);
61720
+ this.noteManualAttendanceIfApplicable(cmd, args);
61476
61721
  let result;
61477
61722
  if (isGitCommandName(cmd)) {
61478
61723
  result = await handleGitCommand(cmd, args, this._ctx.gitCommandServices);
@@ -62207,10 +62452,10 @@ ${formatManifestValidationIssues2(validation.issues)}`,
62207
62452
  const path422 = require("path");
62208
62453
  const { spawnSync: spawnSync2 } = require("child_process");
62209
62454
  const file2 = ext.loadExternalSources();
62210
- if (file2.sources.some((s) => s.name === requestedName)) {
62455
+ if (file2.sources.some((s2) => s2.name === requestedName)) {
62211
62456
  return { success: false, error: `source name "${requestedName}" is already registered` };
62212
62457
  }
62213
- if (file2.sources.some((s) => s.url === url2 && s.ref === ref)) {
62458
+ if (file2.sources.some((s2) => s2.url === url2 && s2.ref === ref)) {
62214
62459
  return { success: false, error: `source url+ref already registered (use a different name to track another ref)` };
62215
62460
  }
62216
62461
  const sourceDir = path422.join(ext.externalRoot(), requestedName);
@@ -62272,7 +62517,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
62272
62517
  const fs322 = require("fs");
62273
62518
  const path422 = require("path");
62274
62519
  const file2 = ext.loadExternalSources();
62275
- const match = file2.sources.find((s) => s.name === name);
62520
+ const match = file2.sources.find((s2) => s2.name === name);
62276
62521
  if (!match) return { success: false, error: `source "${name}" not registered` };
62277
62522
  const sourceDir = path422.join(ext.externalRoot(), name);
62278
62523
  if (fs322.existsSync(sourceDir)) {
@@ -62284,7 +62529,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
62284
62529
  }
62285
62530
  ext.saveExternalSources({
62286
62531
  schema: 1,
62287
- sources: file2.sources.filter((s) => s.name !== name)
62532
+ sources: file2.sources.filter((s2) => s2.name !== name)
62288
62533
  });
62289
62534
  const active = ext.loadProvidersActive();
62290
62535
  const filteredActive = {};
@@ -62308,10 +62553,10 @@ ${formatManifestValidationIssues2(validation.issues)}`,
62308
62553
  const file2 = ext.loadExternalSources();
62309
62554
  const inventory = ext.inventoryExternalSources();
62310
62555
  const active = ext.loadProvidersActive();
62311
- const sources = file2.sources.map((s) => {
62312
- const inv = inventory.find((e) => e.sourceName === s.name);
62556
+ const sources = file2.sources.map((s2) => {
62557
+ const inv = inventory.find((e) => e.sourceName === s2.name);
62313
62558
  return {
62314
- ...s,
62559
+ ...s2,
62315
62560
  providers: inv?.providers ?? {}
62316
62561
  };
62317
62562
  });
@@ -62478,6 +62723,21 @@ ${formatManifestValidationIssues2(validation.issues)}`,
62478
62723
  var path21 = __toESM2(require("path"));
62479
62724
  init_terminal_screen();
62480
62725
  var import_session_host_core6 = require_dist();
62726
+ var MAX_PTY_EVENTS = 300;
62727
+ var EVENT_CONTENT_CAP = 240;
62728
+ function escapeControl(text) {
62729
+ return String(text).replace(/[\x00-\x1f\x7f]/g, (ch) => {
62730
+ const code = ch.charCodeAt(0);
62731
+ if (ch === "\r") return "\\r";
62732
+ if (ch === "\n") return "\\n";
62733
+ if (ch === " ") return "\\t";
62734
+ if (code === 27) return "\\x1b";
62735
+ return "\\x" + code.toString(16).padStart(2, "0");
62736
+ });
62737
+ }
62738
+ function capPreview(text) {
62739
+ return text.length > EVENT_CONTENT_CAP ? text.slice(0, EVENT_CONTENT_CAP) + `\u2026(+${text.length - EVENT_CONTENT_CAP})` : text;
62740
+ }
62481
62741
  var TerminalAdapter = class {
62482
62742
  constructor(opts, handlers) {
62483
62743
  this.opts = opts;
@@ -62504,6 +62764,9 @@ ${formatManifestValidationIssues2(validation.issues)}`,
62504
62764
  screenTimer = null;
62505
62765
  tickTimer = null;
62506
62766
  lastScreen = "";
62767
+ /** Debug-only ring buffer of PTY input/output/resize/cursor events. */
62768
+ events = [];
62769
+ lastCursorKey = "";
62507
62770
  start() {
62508
62771
  const env2 = this.opts.envIsComplete ? this.opts.env ?? {} : { ...process.env, ...this.opts.env ?? {} };
62509
62772
  this.pty = this.factory.spawn(this.opts.binary, this.opts.args ?? [], {
@@ -62512,10 +62775,12 @@ ${formatManifestValidationIssues2(validation.issues)}`,
62512
62775
  cols: this.cols,
62513
62776
  rows: this.rows
62514
62777
  });
62778
+ this.recordEvent("spawn", `${this.opts.binary} (${this.cols}x${this.rows})`);
62515
62779
  this.handlers.init?.({ pid: this.pty.pid });
62516
62780
  this.pty.onData((chunk) => this.onChunk(chunk));
62517
62781
  this.pty.onExit((info) => {
62518
62782
  this.stopTimers();
62783
+ this.recordEvent("exit", `exitCode=${typeof info.exitCode === "number" ? info.exitCode : 0}`);
62519
62784
  this.handlers.on_exit?.({ exitCode: typeof info.exitCode === "number" ? info.exitCode : 0 });
62520
62785
  this.pty = null;
62521
62786
  });
@@ -62526,6 +62791,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
62526
62791
  resize(cols, rows) {
62527
62792
  this.cols = cols;
62528
62793
  this.rows = rows;
62794
+ this.recordEvent("resize", `${cols}x${rows}`);
62529
62795
  this.pty?.resize(cols, rows);
62530
62796
  this.screen.resize(rows, cols);
62531
62797
  }
@@ -62546,8 +62812,21 @@ ${formatManifestValidationIssues2(validation.issues)}`,
62546
62812
  return { row: pos.row, col: pos.col };
62547
62813
  }
62548
62814
  send_keys(text) {
62815
+ this.recordEvent("input", capPreview(escapeControl(text)), text.length);
62549
62816
  this.pty?.write(text);
62550
62817
  }
62818
+ /** Debug-only: most-recent PTY input/output/resize/cursor events, oldest
62819
+ * first. Pure observation — never consulted by the FSM. */
62820
+ getEventTimeline(limit = MAX_PTY_EVENTS) {
62821
+ const n = Math.max(0, Math.min(limit, this.events.length));
62822
+ return this.events.slice(this.events.length - n);
62823
+ }
62824
+ recordEvent(kind, content, bytes) {
62825
+ const ev = { ts: Date.now(), kind, content };
62826
+ if (typeof bytes === "number") ev.bytes = bytes;
62827
+ this.events.push(ev);
62828
+ if (this.events.length > MAX_PTY_EVENTS) this.events.splice(0, this.events.length - MAX_PTY_EVENTS);
62829
+ }
62551
62830
  kill() {
62552
62831
  this.stopTimers();
62553
62832
  try {
@@ -62558,6 +62837,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
62558
62837
  this.screen.dispose();
62559
62838
  }
62560
62839
  onChunk(chunk) {
62840
+ this.recordEvent("output", capPreview(escapeControl(chunk)), chunk.length);
62561
62841
  try {
62562
62842
  this.handlers.on_pty_data?.(chunk);
62563
62843
  } catch {
@@ -62567,6 +62847,12 @@ ${formatManifestValidationIssues2(validation.issues)}`,
62567
62847
  this.screenTimer = setTimeout(() => {
62568
62848
  this.screenTimer = null;
62569
62849
  const snap = this.computeScreen();
62850
+ const cur = this.screen.getCursorPosition();
62851
+ const curKey = `${cur.row},${cur.col}`;
62852
+ if (curKey !== this.lastCursorKey) {
62853
+ this.lastCursorKey = curKey;
62854
+ this.recordEvent("cursor", `(${cur.row},${cur.col})`);
62855
+ }
62570
62856
  if (snap === this.lastScreen) return;
62571
62857
  this.lastScreen = snap;
62572
62858
  try {
@@ -62645,20 +62931,40 @@ ${formatManifestValidationIssues2(validation.issues)}`,
62645
62931
  }
62646
62932
  }
62647
62933
  init_logger();
62648
- function countNewlines(s) {
62934
+ function countNewlines(s2) {
62649
62935
  let n = 0;
62650
- for (let i = 0; i < s.length; i += 1) if (s.charCodeAt(i) === 10) n += 1;
62936
+ for (let i = 0; i < s2.length; i += 1) if (s2.charCodeAt(i) === 10) n += 1;
62651
62937
  return n;
62652
62938
  }
62653
62939
  var SUBMIT_DELAY_FLOOR_MS = 200;
62654
62940
  var WIN32_SUBMIT_RESEND_GAP_MS = 350;
62655
62941
  var WIN32_SUBMIT_MAX_RESENDS = 14;
62942
+ var WIN32_SUBMIT_SETTLE_MS = 500;
62943
+ var WIN32_SUBMIT_MAX_SETTLE_WAIT_MS = 1e4;
62944
+ var WIN32_SUBMIT_SETTLE_POLL_MS = 120;
62945
+ var WIN32_PTY_WRITE_CHUNK_CHARS = 1024;
62946
+ var WIN32_PTY_WRITE_CHUNK_GAP_MS = 8;
62656
62947
  function resolveSubmitDelayMs(specBeforeSubmit, text) {
62657
62948
  const lines = countNewlines(text);
62658
62949
  const linesBonus = Math.min(800, lines * 80);
62659
62950
  const spec = typeof specBeforeSubmit === "number" && specBeforeSubmit > 0 ? specBeforeSubmit : 0;
62660
62951
  return Math.max(spec, SUBMIT_DELAY_FLOOR_MS + linesBonus);
62661
62952
  }
62953
+ function chunkPreservingSurrogates(text, size) {
62954
+ const chunks = [];
62955
+ let offset = 0;
62956
+ while (offset < text.length) {
62957
+ let end = Math.min(text.length, offset + size);
62958
+ if (end < text.length) {
62959
+ const code = text.charCodeAt(end - 1);
62960
+ if (code >= 55296 && code <= 56319) end -= 1;
62961
+ }
62962
+ if (end <= offset) end = Math.min(text.length, offset + size);
62963
+ chunks.push(text.slice(offset, end));
62964
+ offset = end;
62965
+ }
62966
+ return chunks;
62967
+ }
62662
62968
  function guessExt(mime) {
62663
62969
  if (/png/i.test(mime)) return ".png";
62664
62970
  if (/jpe?g/i.test(mime)) return ".jpg";
@@ -62674,7 +62980,10 @@ ${formatManifestValidationIssues2(validation.issues)}`,
62674
62980
  this.buildAdapterOpts(),
62675
62981
  {
62676
62982
  init: () => this.emitInitialState(),
62677
- on_pty_data: (chunk) => this.emit({ kind: "pty_data", chunk }),
62983
+ on_pty_data: (chunk) => {
62984
+ this.lastPtyDataAt = Date.now();
62985
+ this.emit({ kind: "pty_data", chunk });
62986
+ },
62678
62987
  on_screen_changed: () => this.reevaluate(),
62679
62988
  on_exit: ({ exitCode }) => this.handleExit(exitCode)
62680
62989
  }
@@ -62708,6 +63017,16 @@ ${formatManifestValidationIssues2(validation.issues)}`,
62708
63017
  * WIN32_SUBMIT_* and scheduleWin32Submit). Re-arms itself until the FSM
62709
63018
  * leaves idle (submitted) or the resend budget is spent. */
62710
63019
  win32SubmitTimer = null;
63020
+ /** Wall-clock (ms) of the most recent raw PTY output chunk. Advances on every
63021
+ * on_pty_data — including the echo of text written into the composer — so the
63022
+ * win32 submit settle-gate can tell when input has finished landing. */
63023
+ lastPtyDataAt = 0;
63024
+ /** Wall-clock (ms) of the most recent win32 message-body input write. Bridges
63025
+ * the gap between writing a chunk and its echo so the settle-gate does not
63026
+ * declare "quiet" mid-write. */
63027
+ lastWin32WriteAt = 0;
63028
+ /** Pending paced chunk-write timer for a large win32 body (see writeWin32Body). */
63029
+ win32WriteTimer = null;
62711
63030
  currentEval = null;
62712
63031
  stateHistory = [];
62713
63032
  prevStateAt = 0;
@@ -62828,6 +63147,10 @@ ${formatManifestValidationIssues2(validation.issues)}`,
62828
63147
  clearTimeout(this.win32SubmitTimer);
62829
63148
  this.win32SubmitTimer = null;
62830
63149
  }
63150
+ if (this.win32WriteTimer) {
63151
+ clearTimeout(this.win32WriteTimer);
63152
+ this.win32WriteTimer = null;
63153
+ }
62831
63154
  this.specWatcher?.close();
62832
63155
  this.adapter.kill();
62833
63156
  }
@@ -62858,11 +63181,15 @@ ${formatManifestValidationIssues2(validation.issues)}`,
62858
63181
  getFsmSnapshotHistory() {
62859
63182
  return this.fsmSnapshotHistory;
62860
63183
  }
63184
+ /** Debug-only PTY input/output/resize/cursor timeline from the adapter. */
63185
+ getEventTimeline(limit) {
63186
+ return this.adapter.getEventTimeline(limit);
63187
+ }
62861
63188
  getSections() {
62862
63189
  try {
62863
63190
  const screen = this.adapter.snapshot();
62864
63191
  const lines = screen.split("\n").map((l) => l.endsWith("\r") ? l.slice(0, -1) : l);
62865
- return resolveSections(this.spec.sections ?? {}, lines).map((s) => ({ id: s.id, text: s.text }));
63192
+ return resolveSections(this.spec.sections ?? {}, lines).map((s2) => ({ id: s2.id, text: s2.text }));
62866
63193
  } catch {
62867
63194
  return null;
62868
63195
  }
@@ -63240,7 +63567,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
63240
63567
  const perChar = sm.delay_ms_per_char ?? 0;
63241
63568
  const beforeSubmit = resolveSubmitDelayMs(sm.delay_ms_before_submit, text);
63242
63569
  if (process.platform === "win32") {
63243
- this.adapter.send_keys(text);
63570
+ this.writeWin32Body(text);
63244
63571
  this.scheduleWin32Submit(sm.submit_key, beforeSubmit);
63245
63572
  return;
63246
63573
  }
@@ -63266,20 +63593,72 @@ ${formatManifestValidationIssues2(validation.issues)}`,
63266
63593
  const st = stateById(this.spec, this.currentStateId);
63267
63594
  return st ? statusForState(st) : "idle";
63268
63595
  }
63596
+ /** Record a win32 body write so the settle-gate counts it as input activity
63597
+ * even before the echo arrives. */
63598
+ markWin32Write() {
63599
+ this.lastWin32WriteAt = Date.now();
63600
+ }
63601
+ /** Most recent win32 input activity — a write we issued OR a PTY output chunk
63602
+ * (echo). The submit settle-gate waits for this to go quiet. */
63603
+ lastWin32InputActivityAt() {
63604
+ return Math.max(this.lastPtyDataAt, this.lastWin32WriteAt);
63605
+ }
63269
63606
  /**
63270
- * win32 verification-based submit. Sends the submit key, waits a gap, and if
63271
- * the FSM is still 'idle' (the prompt did not submit — the CR was absorbed as
63272
- * a multiline-paste newline) resends, up to WIN32_SUBMIT_MAX_RESENDS. The
63273
- * first CR always fires (so a stale/edge status never suppresses the submit);
63274
- * subsequent resends are gated on still being idle, and stop the instant the
63275
- * agent leaves idle (submitted generating / approval). This converges the
63276
- * nondeterministic multiline window without spamming Enter into the next turn.
63607
+ * Write the message body to the PTY for win32, paced into bounded chunks. A
63608
+ * single unbounded ConPTY write can overflow the input pipe and drop leading
63609
+ * bytes; splitting it with a short inter-chunk gap keeps the console input
63610
+ * buffer from overflowing. Small bodies still go out in a single write. Each
63611
+ * chunk advances lastWin32WriteAt so the submit settle-gate keeps waiting until
63612
+ * the final chunk is out and echoed.
63613
+ */
63614
+ writeWin32Body(text) {
63615
+ if (this.win32WriteTimer) {
63616
+ clearTimeout(this.win32WriteTimer);
63617
+ this.win32WriteTimer = null;
63618
+ }
63619
+ if (text.length <= WIN32_PTY_WRITE_CHUNK_CHARS) {
63620
+ this.markWin32Write();
63621
+ this.adapter.send_keys(text);
63622
+ return;
63623
+ }
63624
+ const chunks = chunkPreservingSurrogates(text, WIN32_PTY_WRITE_CHUNK_CHARS);
63625
+ let idx = 0;
63626
+ const writeNext = () => {
63627
+ this.win32WriteTimer = null;
63628
+ if (idx >= chunks.length) return;
63629
+ this.markWin32Write();
63630
+ this.adapter.send_keys(chunks[idx]);
63631
+ idx += 1;
63632
+ if (idx < chunks.length) {
63633
+ this.win32WriteTimer = setTimeout(writeNext, WIN32_PTY_WRITE_CHUNK_GAP_MS);
63634
+ }
63635
+ };
63636
+ writeNext();
63637
+ }
63638
+ /**
63639
+ * win32 submit. Two phases:
63640
+ *
63641
+ * Phase 1 (settle-gate): hold the first CR until the PTY output has been quiet
63642
+ * for WIN32_SUBMIT_SETTLE_MS after the last input write — i.e. the full
63643
+ * (possibly multi-KB / multiline) body has finished arriving in the composer
63644
+ * and echoing. Honors an initial minimum delay and is bounded by
63645
+ * WIN32_SUBMIT_MAX_SETTLE_WAIT_MS so a noisy screen can never hang the submit.
63646
+ * This is what stops a long message from being submitted half-arrived (its
63647
+ * leading lines lost). A short message settles almost immediately.
63648
+ *
63649
+ * Phase 2 (verified resend — unchanged): send the submit key, wait a gap, and
63650
+ * if the FSM is still 'idle' (the CR was absorbed as a multiline-paste
63651
+ * newline) resend, up to WIN32_SUBMIT_MAX_RESENDS. The first CR always fires
63652
+ * (a stale/edge status never suppresses it); resends are gated on still being
63653
+ * idle and stop the instant the agent leaves idle (submitted → generating /
63654
+ * approval). This preserves the win32 lone-CR-swallow handling.
63277
63655
  */
63278
63656
  scheduleWin32Submit(submitKey, initialDelayMs) {
63279
63657
  if (this.win32SubmitTimer) {
63280
63658
  clearTimeout(this.win32SubmitTimer);
63281
63659
  this.win32SubmitTimer = null;
63282
63660
  }
63661
+ const startedAt = Date.now();
63283
63662
  const fire = (attempt) => {
63284
63663
  this.win32SubmitTimer = null;
63285
63664
  this.adapter.send_keys(submitKey);
@@ -63292,8 +63671,20 @@ ${formatManifestValidationIssues2(validation.issues)}`,
63292
63671
  fire(attempt + 1);
63293
63672
  }, WIN32_SUBMIT_RESEND_GAP_MS);
63294
63673
  };
63295
- if (initialDelayMs > 0) this.win32SubmitTimer = setTimeout(() => fire(0), initialDelayMs);
63296
- else fire(0);
63674
+ const waitForSettle = () => {
63675
+ this.win32SubmitTimer = null;
63676
+ const now = Date.now();
63677
+ const quietFor = now - this.lastWin32InputActivityAt();
63678
+ const waited = now - startedAt;
63679
+ if (quietFor >= WIN32_SUBMIT_SETTLE_MS || waited >= WIN32_SUBMIT_MAX_SETTLE_WAIT_MS) {
63680
+ fire(0);
63681
+ return;
63682
+ }
63683
+ const recheckIn = Math.min(WIN32_SUBMIT_SETTLE_MS - quietFor, WIN32_SUBMIT_SETTLE_POLL_MS);
63684
+ this.win32SubmitTimer = setTimeout(waitForSettle, Math.max(recheckIn, 30));
63685
+ };
63686
+ if (initialDelayMs > 0) this.win32SubmitTimer = setTimeout(waitForSettle, initialDelayMs);
63687
+ else waitForSettle();
63297
63688
  }
63298
63689
  handleClickControl(controlId, payload) {
63299
63690
  const ctl = (this.spec.control_bar ?? []).find((c) => c.id === controlId);
@@ -63406,7 +63797,8 @@ ${formatManifestValidationIssues2(validation.issues)}`,
63406
63797
  return out;
63407
63798
  }
63408
63799
  function flattenCond(c, out, depth) {
63409
- out.push(`${" ".repeat(depth)}${c.kind} ${c.detail} = ${c.result}${c.remainingMs ? ` (${c.remainingMs}ms left)` : ""}`);
63800
+ const matched = c.matchedText ? ` matched=${JSON.stringify(c.matchedText)}` : "";
63801
+ out.push(`${" ".repeat(depth)}${c.kind} ${c.detail} = ${c.result}${c.remainingMs ? ` (${c.remainingMs}ms left)` : ""}${matched}`);
63410
63802
  for (const child of c.children ?? []) flattenCond(child, out, depth + 1);
63411
63803
  }
63412
63804
  function findStable(c) {
@@ -64122,8 +64514,8 @@ ${formatManifestValidationIssues2(validation.issues)}`,
64122
64514
  }
64123
64515
  return null;
64124
64516
  }
64125
- function oneLine(s, max) {
64126
- const flat = s.replace(/\s+/g, " ").trim();
64517
+ function oneLine(s2, max) {
64518
+ const flat = s2.replace(/\s+/g, " ").trim();
64127
64519
  return flat.length > max ? flat.slice(0, max - 1) + "\u2026" : flat;
64128
64520
  }
64129
64521
  function parseTimestamp(v) {
@@ -64143,10 +64535,10 @@ ${formatManifestValidationIssues2(validation.issues)}`,
64143
64535
  return null;
64144
64536
  }
64145
64537
  function normalizeRole(r) {
64146
- const s = String(r ?? "").toLowerCase();
64147
- if (s === "user" || s === "human" || s === "user_explicit") return "user";
64148
- if (s === "assistant" || s === "ai" || s === "model") return "assistant";
64149
- if (s === "tool" || s === "tool_result" || s === "function") return "assistant";
64538
+ const s2 = String(r ?? "").toLowerCase();
64539
+ if (s2 === "user" || s2 === "human" || s2 === "user_explicit") return "user";
64540
+ if (s2 === "assistant" || s2 === "ai" || s2 === "model") return "assistant";
64541
+ if (s2 === "tool" || s2 === "tool_result" || s2 === "function") return "assistant";
64150
64542
  return "system";
64151
64543
  }
64152
64544
  function stringifyContent(v) {
@@ -64194,18 +64586,18 @@ ${formatManifestValidationIssues2(validation.issues)}`,
64194
64586
  return (record2) => ors.some((ands) => ands.every((t) => evalTerm(t, record2)));
64195
64587
  }
64196
64588
  function parseTerm(src) {
64197
- let s = src.trim();
64589
+ let s2 = src.trim();
64198
64590
  let negate = false;
64199
- if (s.startsWith("!")) {
64591
+ if (s2.startsWith("!")) {
64200
64592
  negate = true;
64201
- s = s.slice(1).trim();
64593
+ s2 = s2.slice(1).trim();
64202
64594
  }
64203
- const fnMatch = s.match(/^(startsWith|endsWith|contains)\s*\(\s*(.+?)\s*,\s*(.+?)\s*\)$/);
64595
+ const fnMatch = s2.match(/^(startsWith|endsWith|contains)\s*\(\s*(.+?)\s*,\s*(.+?)\s*\)$/);
64204
64596
  if (fnMatch) {
64205
64597
  const [, op2, pathExpr, litExpr] = fnMatch;
64206
64598
  return { path: pathExpr, op: op2, lit: parseLiteral(litExpr), negate };
64207
64599
  }
64208
- const opMatch = s.match(/^(.+?)\s*(==|!=|>=|<=|>|<)\s*(.+)$/);
64600
+ const opMatch = s2.match(/^(.+?)\s*(==|!=|>=|<=|>|<)\s*(.+)$/);
64209
64601
  if (!opMatch) return null;
64210
64602
  const [, lhs, op, rhsRaw] = opMatch;
64211
64603
  return { path: lhs.trim(), op, lit: parseLiteral(rhsRaw.trim()), negate };
@@ -64635,7 +65027,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
64635
65027
  try {
64636
65028
  const sections = this.driver.getSections();
64637
65029
  if (sectionId && sections) {
64638
- const hit = sections.find((s) => s.id === sectionId);
65030
+ const hit = sections.find((s2) => s2.id === sectionId);
64639
65031
  if (hit) return hit.text;
64640
65032
  }
64641
65033
  return this.driver.getScreen();
@@ -64650,7 +65042,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
64650
65042
  screen = this.driver.snapshot();
64651
65043
  const driverSections = this.driver.getSections?.();
64652
65044
  if (driverSections) {
64653
- sections = Object.fromEntries(driverSections.map((s) => [s.id, s.text]));
65045
+ sections = Object.fromEntries(driverSections.map((s2) => [s2.id, s2.text]));
64654
65046
  } else {
64655
65047
  sections = this.readCurrentScreenSections(screen);
64656
65048
  }
@@ -64696,6 +65088,10 @@ ${formatManifestValidationIssues2(validation.issues)}`,
64696
65088
  // answers "why did this rule fire" after the fact, unlike the live
64697
65089
  // `fsm` field which only reflects the current instant.
64698
65090
  fsmHistory: this.driver.getFsmSnapshotHistory?.() ?? null,
65091
+ // PTY input/output/resize/cursor event timeline (debug-only) so the
65092
+ // snapshot shows what we typed / what the PTY printed around each
65093
+ // status transition. Null for drivers without the timeline.
65094
+ eventTimeline: this.driver.getEventTimeline?.() ?? null,
64699
65095
  // Extended fields
64700
65096
  name: this.cliName,
64701
65097
  status: this.getStatus().status,
@@ -65060,6 +65456,8 @@ ${formatManifestValidationIssues2(validation.issues)}`,
65060
65456
  // v4 FSM transition snapshot history — the captured pre-transition
65061
65457
  // evaluation table at each transition (null for v3 specs).
65062
65458
  fsmHistory: this.driver.getFsmSnapshotHistory?.() ?? null,
65459
+ // PTY input/output/resize/cursor event timeline (debug-only).
65460
+ eventTimeline: this.driver.getEventTimeline?.() ?? null,
65063
65461
  messages,
65064
65462
  committedMessages: messages
65065
65463
  };
@@ -65100,6 +65498,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
65100
65498
  return new ProviderCliAdapter(provider, workingDir, cliArgs, extraEnv, transportFactory);
65101
65499
  }
65102
65500
  init_logger();
65501
+ init_mesh_event_trace();
65103
65502
  init_control_effects();
65104
65503
  init_approval_utils();
65105
65504
  init_provider_patch_state();
@@ -65394,6 +65793,11 @@ ${formatManifestValidationIssues2(validation.issues)}`,
65394
65793
  // a settle gate was in progress. Drives AUTO_APPROVE_GATE_HYSTERESIS_MS so a
65395
65794
  // brief generating flip does not immediately wipe the settle clock.
65396
65795
  autoApproveInactiveSince = 0;
65796
+ // Provider-common manual-attendance signal: while a human is actively driving
65797
+ // this session from the dashboard, auto-approve holds so they can take manual
65798
+ // control. Background mesh workers are never attended → delegated auto-approve
65799
+ // is unaffected.
65800
+ manualAttendance = new ManualAttendanceTracker();
65397
65801
  controlValues = {};
65398
65802
  summaryMetadata = void 0;
65399
65803
  appliedEffectKeys = /* @__PURE__ */ new Set();
@@ -65669,7 +66073,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
65669
66073
  }
65670
66074
  getHotChatSessionState() {
65671
66075
  const adapterStatus = this.adapter.getStatus({ allowParse: false });
65672
- const autoApproveActive = adapterStatus.status === "waiting_approval" && this.shouldAutoApprove();
66076
+ const autoApproveActive = this.autoApproveEffectivelyActive(adapterStatus.status);
65673
66077
  const autoApproveHoldIdle = this.autoApproveBusy && adapterStatus.status === "idle";
65674
66078
  const visibleStatus = autoApproveActive || autoApproveHoldIdle ? "generating" : adapterStatus.status;
65675
66079
  const runtime = this.adapter.getRuntimeMetadata();
@@ -65684,7 +66088,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
65684
66088
  }
65685
66089
  getSessionModalState(sessionId) {
65686
66090
  const adapterStatus = this.adapter.getStatus({ allowParse: true });
65687
- const autoApproveActive = adapterStatus.status === "waiting_approval" && this.shouldAutoApprove();
66091
+ const autoApproveActive = this.autoApproveEffectivelyActive(adapterStatus.status);
65688
66092
  const autoApproveHoldIdle = this.autoApproveBusy && adapterStatus.status === "idle";
65689
66093
  const visibleStatus = autoApproveActive || autoApproveHoldIdle ? "generating" : adapterStatus.status;
65690
66094
  const dirName = workingDirBasename(this.workingDir);
@@ -65765,7 +66169,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
65765
66169
  } catch {
65766
66170
  return null;
65767
66171
  }
65768
- if (adapterStatus.status === "waiting_approval" && !this.shouldAutoApprove()) {
66172
+ if (adapterStatus.status === "waiting_approval" && !this.autoApproveEffectivelyActive(adapterStatus.status)) {
65769
66173
  return "waiting_approval";
65770
66174
  }
65771
66175
  return null;
@@ -66138,6 +66542,23 @@ ${formatManifestValidationIssues2(validation.issues)}`,
66138
66542
  if (this.completedDebounceTimer) clearTimeout(this.completedDebounceTimer);
66139
66543
  this.completedDebounceTimer = setTimeout(() => this.flushCompletedDebounceIfFinalized(), delayMs);
66140
66544
  }
66545
+ // EVTTRACE (observation-only): is this a mesh worker session whose completion
66546
+ // events must route to a coordinator? Used purely to gate trace logging so a
66547
+ // non-mesh CLI session's completions don't add EvtTrace noise. No decision logic.
66548
+ isMeshWorkerSession() {
66549
+ return !!(this.settings.meshNodeFor || this.settings.meshActiveTaskId || this.settings.meshNodeId || this.settings.launchedByCoordinator);
66550
+ }
66551
+ // EVTTRACE correlation context for this session's completion lifecycle. taskId is
66552
+ // the primary grep anchor; instanceId is the session fallback.
66553
+ meshTraceCtx(event = "agent:generating_completed") {
66554
+ return {
66555
+ taskId: this.settings.meshActiveTaskId,
66556
+ sessionId: this.instanceId,
66557
+ nodeId: this.settings.meshNodeId,
66558
+ meshId: this.settings.meshNodeFor,
66559
+ event
66560
+ };
66561
+ }
66141
66562
  flushCompletedDebounceIfFinalized() {
66142
66563
  const pending = this.completedDebouncePending;
66143
66564
  if (!pending) {
@@ -66158,24 +66579,33 @@ ${formatManifestValidationIssues2(validation.issues)}`,
66158
66579
  if (block2) {
66159
66580
  const blockReason = block2.reason;
66160
66581
  const waitedMs = Date.now() - pending.firstObservedAt;
66161
- LOG2.debug("CLI", `[${this.type}] finalization block: reason=${blockReason} terminal=${block2.terminal} waitedMs=${waitedMs} maxWait=${COMPLETED_FINALIZATION_MAX_WAIT_MS}`);
66162
- if (block2.terminal && !block2.allowTimeout || waitedMs < COMPLETED_FINALIZATION_MAX_WAIT_MS) {
66582
+ const isTranscriptEvidenceGate = block2.allowTimeout === true;
66583
+ LOG2.debug("CLI", `[${this.type}] finalization block: reason=${blockReason} terminal=${block2.terminal} allowTimeout=${isTranscriptEvidenceGate} waitedMs=${waitedMs} maxWait=${COMPLETED_FINALIZATION_MAX_WAIT_MS}`);
66584
+ if (!isTranscriptEvidenceGate && (block2.terminal || waitedMs < COMPLETED_FINALIZATION_MAX_WAIT_MS)) {
66163
66585
  if (pending.loggedBlockReason !== blockReason) {
66164
66586
  LOG2.info("CLI", `[${this.type}] waiting to emit completed until transcript finalizes (${blockReason})`);
66587
+ if (this.isMeshWorkerSession()) {
66588
+ traceMeshEventDrop("completion_gate_hold", this.meshTraceCtx(), `${blockReason} waited=${waitedMs}ms`);
66589
+ }
66165
66590
  pending.loggedBlockReason = blockReason;
66166
66591
  }
66167
66592
  this.scheduleCompletedDebounceFlush(COMPLETED_FINALIZATION_RETRY_MS);
66168
66593
  return;
66169
66594
  }
66595
+ const emittedAfterFinalizationTimeout = waitedMs >= COMPLETED_FINALIZATION_MAX_WAIT_MS;
66170
66596
  const completionDiagnostic = this.buildCompletedFinalizationDiagnostic({
66171
66597
  blockReason,
66172
66598
  latestStatus,
66173
66599
  latestVisibleStatus,
66174
66600
  waitedMs,
66175
66601
  pending,
66176
- emittedAfterFinalizationTimeout: true
66602
+ emittedAfterFinalizationTimeout
66177
66603
  });
66178
- LOG2.warn("CLI", `[${this.type}] emitting completed event after ${waitedMs}ms without finalized assistant turn (${blockReason})`);
66604
+ completionDiagnostic.decoupledImmediateEmit = isTranscriptEvidenceGate && !emittedAfterFinalizationTimeout;
66605
+ LOG2.warn("CLI", `[${this.type}] emitting completed event (${isTranscriptEvidenceGate && !emittedAfterFinalizationTimeout ? "CANON-C decoupled-immediate, transcript pending" : `after ${waitedMs}ms`}) without finalized assistant turn (${blockReason})`);
66606
+ if (this.isMeshWorkerSession()) {
66607
+ traceMeshEventStage("fired", this.meshTraceCtx(), `forced after ${waitedMs}ms (${blockReason})`);
66608
+ }
66179
66609
  this.pushEvent({
66180
66610
  event: "agent:generating_completed",
66181
66611
  chatTitle: pending.chatTitle,
@@ -66198,6 +66628,9 @@ ${formatManifestValidationIssues2(validation.issues)}`,
66198
66628
  return;
66199
66629
  }
66200
66630
  LOG2.info("CLI", `[${this.type}] completed in ${pending.duration}s`);
66631
+ if (this.isMeshWorkerSession()) {
66632
+ traceMeshEventStage("fired", this.meshTraceCtx(), `duration=${pending.duration}s`);
66633
+ }
66201
66634
  this.pushEvent({
66202
66635
  event: "agent:generating_completed",
66203
66636
  chatTitle: pending.chatTitle,
@@ -66211,6 +66644,18 @@ ${formatManifestValidationIssues2(validation.issues)}`,
66211
66644
  this.lastApprovalEventFingerprint = "";
66212
66645
  }
66213
66646
  maybeAutoApproveStatus(adapterStatus, now = Date.now()) {
66647
+ if (adapterStatus?.status === "waiting_approval" && this.shouldAutoApprove() && this.manualAttendance.isAttended(now)) {
66648
+ this.lastAutoApprovalSignature = "";
66649
+ this.pendingAutoApprovalSignature = "";
66650
+ this.pendingAutoApprovalSince = 0;
66651
+ this.autoApproveInactiveSince = 0;
66652
+ if (this.autoApproveSettleTimer) clearTimeout(this.autoApproveSettleTimer);
66653
+ this.autoApproveSettleTimer = setTimeout(() => {
66654
+ this.autoApproveSettleTimer = null;
66655
+ this.recheckAutoApproveSettled();
66656
+ }, this.manualAttendance.remainingMs(now) + 20);
66657
+ return false;
66658
+ }
66214
66659
  const autoApproveActive = adapterStatus?.status === "waiting_approval" && this.shouldAutoApprove();
66215
66660
  if (!autoApproveActive) {
66216
66661
  this.lastAutoApprovalSignature = "";
@@ -66424,6 +66869,9 @@ ${formatManifestValidationIssues2(validation.issues)}`,
66424
66869
  if (missingEvidence && !hasMeshContext) {
66425
66870
  LOG2.info("CLI", `[${this.type}] short completion suppressed: missing final assistant evidence, no mesh context (source=${shortEvidenceSource})`);
66426
66871
  } else {
66872
+ if (this.isMeshWorkerSession()) {
66873
+ traceMeshEventStage("fired", this.meshTraceCtx(), `short-generating idle (source=${shortEvidenceSource})`);
66874
+ }
66427
66875
  this.pushEvent({
66428
66876
  event: "agent:generating_completed",
66429
66877
  chatTitle,
@@ -66500,6 +66948,9 @@ ${formatManifestValidationIssues2(validation.issues)}`,
66500
66948
  const monitorParsedStatus = parsedStatus;
66501
66949
  for (const me of monitorEvents) {
66502
66950
  if (me.type === "monitor:no_progress" && this.completionHasFinalAssistantMessage(monitorParsedStatus?.messages) && !this.hasAdapterPendingResponse() && !hasNonEmptyCliModalButtons(monitorParsedStatus?.activeModal ?? monitorParsedStatus?.modal)) {
66951
+ if (this.isMeshWorkerSession()) {
66952
+ traceMeshEventStage("fired", this.meshTraceCtx(), "no_progress_monitor_final_summary");
66953
+ }
66503
66954
  this.pushEvent({
66504
66955
  event: "agent:generating_completed",
66505
66956
  chatTitle,
@@ -66676,6 +67127,21 @@ ${effect.notification.body || ""}`.trim();
66676
67127
  }
66677
67128
  return false;
66678
67129
  }
67130
+ /** @see ProviderInstance.noteManualInteraction */
67131
+ noteManualInteraction(now = Date.now()) {
67132
+ this.manualAttendance.note(now);
67133
+ }
67134
+ /**
67135
+ * Whether auto-approve should be treated as active *right now* for display
67136
+ * and firing decisions: the configured intent AND the user is not currently
67137
+ * attending this session by hand. When a human is attending, auto-approve is
67138
+ * held so the modal stays visible and they can drive it via the controlbar.
67139
+ * Provider-agnostic — the attendance signal is the command set, never any
67140
+ * CLI-specific modal text.
67141
+ */
67142
+ autoApproveEffectivelyActive(status, now = Date.now()) {
67143
+ return status === "waiting_approval" && this.shouldAutoApprove() && !this.manualAttendance.isAttended(now);
67144
+ }
66679
67145
  recordAutoApproval(modalMessage, buttonLabel, now = Date.now()) {
66680
67146
  this.appendRuntimeSystemMessage(
66681
67147
  formatAutoApprovalMessage(modalMessage, buttonLabel),
@@ -67619,7 +68085,7 @@ ${effect.notification.body || ""}`.trim();
67619
68085
  input: tc.rawInput ? typeof tc.rawInput === "string" ? tc.rawInput : JSON.stringify(tc.rawInput) : void 0
67620
68086
  });
67621
68087
  }
67622
- if (this.settings.autoApprove !== false) {
68088
+ if (this.settings.autoApprove !== false && !this.manualAttendance.isAttended()) {
67623
68089
  const toolTitle = tc.title || tc.toolCallId || "tool call";
67624
68090
  this.log.info(`[${this.type}] Auto-approving: ${toolTitle}`);
67625
68091
  this.appendSystemMessage(`Auto-approved: ${toolTitle}`);
@@ -67850,6 +68316,15 @@ ${effect.notification.body || ""}`.trim();
67850
68316
  this.detectStatusTransition();
67851
68317
  }
67852
68318
  permissionResolvers = [];
68319
+ // Provider-common manual-attendance signal: while a human is actively driving
68320
+ // this session from the dashboard, auto-approve holds so they can decide on
68321
+ // the permission request themselves. Background workers are never attended →
68322
+ // delegated auto-approve is unaffected.
68323
+ manualAttendance = new ManualAttendanceTracker();
68324
+ /** @see ProviderInstance.noteManualInteraction */
68325
+ noteManualInteraction(now = Date.now()) {
68326
+ this.manualAttendance.note(now);
68327
+ }
67853
68328
  async resolvePermission(approved) {
67854
68329
  const resolver = this.permissionResolvers.shift();
67855
68330
  if (resolver) {
@@ -69001,6 +69476,11 @@ Run 'adhdev doctor' for detailed diagnostics.`
69001
69476
  );
69002
69477
  continue;
69003
69478
  }
69479
+ const restoredSettings = { ...this.providerLoader.getSettings(normalizedType) };
69480
+ const coordinatorEntry = getCoordinatorForSession(record2.runtimeId);
69481
+ if (coordinatorEntry?.meshId) {
69482
+ restoredSettings.meshCoordinatorFor = coordinatorEntry.meshId;
69483
+ }
69004
69484
  try {
69005
69485
  await this.registerCliInstance(
69006
69486
  record2.runtimeId,
@@ -69009,7 +69489,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
69009
69489
  record2.workspace,
69010
69490
  record2.cliArgs,
69011
69491
  resolvedProvider,
69012
- {},
69492
+ restoredSettings,
69013
69493
  true,
69014
69494
  {
69015
69495
  providerSessionId: sessionBinding.providerSessionId,
@@ -70310,7 +70790,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
70310
70790
  }
70311
70791
  if (buf.length === 0) return null;
70312
70792
  const strings = extractStringsFromBuffer(buf);
70313
- const meaningful = strings.filter((s) => s.length >= MIN_PRINTABLE_RUN && /\w/.test(s));
70793
+ const meaningful = strings.filter((s2) => s2.length >= MIN_PRINTABLE_RUN && /\w/.test(s2));
70314
70794
  if (meaningful.length === 0) return null;
70315
70795
  const content = meaningful.join("\n");
70316
70796
  const sourceMtimeMs = statMtimeMs3(filePath);
@@ -70516,10 +70996,10 @@ Run 'adhdev doctor' for detailed diagnostics.`
70516
70996
  };
70517
70997
  }
70518
70998
  function normalizeHermesRole(r) {
70519
- const s = String(r ?? "").toLowerCase();
70520
- if (s === "user" || s === "human") return "user";
70521
- if (s === "assistant" || s === "ai" || s === "model") return "assistant";
70522
- if (s === "tool" || s === "tool_result" || s === "function") return "assistant";
70999
+ const s2 = String(r ?? "").toLowerCase();
71000
+ if (s2 === "user" || s2 === "human") return "user";
71001
+ if (s2 === "assistant" || s2 === "ai" || s2 === "model") return "assistant";
71002
+ if (s2 === "tool" || s2 === "tool_result" || s2 === "function") return "assistant";
70523
71003
  return "system";
70524
71004
  }
70525
71005
  function createNativeHistoryDispatcher(reader) {
@@ -70743,10 +71223,10 @@ Run 'adhdev doctor' for detailed diagnostics.`
70743
71223
  }
70744
71224
  }
70745
71225
  function normalizeRole2(r) {
70746
- const s = String(r ?? "").toLowerCase();
70747
- if (s === "user" || s === "human") return "user";
70748
- if (s === "assistant" || s === "ai" || s === "model") return "assistant";
70749
- if (s === "tool" || s === "tool_result" || s === "function") return "assistant";
71226
+ const s2 = String(r ?? "").toLowerCase();
71227
+ if (s2 === "user" || s2 === "human") return "user";
71228
+ if (s2 === "assistant" || s2 === "ai" || s2 === "model") return "assistant";
71229
+ if (s2 === "tool" || s2 === "tool_result" || s2 === "function") return "assistant";
70750
71230
  return "system";
70751
71231
  }
70752
71232
  function registerProviderScriptRootSafely(root) {
@@ -70764,7 +71244,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
70764
71244
  const actionType = ctl?.action?.type;
70765
71245
  if (!id || !actionType) return;
70766
71246
  const label = typeof ctl?.label === "string" && ctl.label.trim() ? ctl.label : id;
70767
- const visibleWhenState = Array.isArray(ctl?.visible_when_state) ? ctl.visible_when_state.filter((s) => typeof s === "string") : void 0;
71247
+ const visibleWhenState = Array.isArray(ctl?.visible_when_state) ? ctl.visible_when_state.filter((s2) => typeof s2 === "string") : void 0;
70768
71248
  if (actionType === "open_picker") {
70769
71249
  out.push({
70770
71250
  id,
@@ -77650,7 +78130,7 @@ ${mergeTreeErr?.stderr || ""}`;
77650
78130
  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.";
77651
78131
  if (!firstFailedCmd) return base;
77652
78132
  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 : "";
77653
- const rawOutput = [firstFailedCmd.stdout, firstFailedCmd.stderr, firstFailedCmd.output].filter((s) => typeof s === "string" && s.length > 0).join("\n");
78133
+ const rawOutput = [firstFailedCmd.stdout, firstFailedCmd.stderr, firstFailedCmd.output].filter((s2) => typeof s2 === "string" && s2.length > 0).join("\n");
77654
78134
  const tail = rawOutput.length > 800 ? rawOutput.slice(-800) : rawOutput;
77655
78135
  return [
77656
78136
  base,
@@ -78401,7 +78881,7 @@ ${hintLines.join("\n")}` : "",
78401
78881
  convergence = "blocked_review";
78402
78882
  }
78403
78883
  const fbcs = result.finalBranchConvergenceState && typeof result.finalBranchConvergenceState === "object" ? result.finalBranchConvergenceState : void 0;
78404
- const stage = Array.isArray(result.refineStages) ? result.refineStages.filter((s) => s.status === "failed").map((s) => s.stage).filter(Boolean).pop() : void 0;
78884
+ const stage = Array.isArray(result.refineStages) ? result.refineStages.filter((s2) => s2.status === "failed").map((s2) => s2.stage).filter(Boolean).pop() : void 0;
78405
78885
  results.push({
78406
78886
  nodeId: node.id,
78407
78887
  workspace: node.workspace,
@@ -79398,7 +79878,7 @@ ${hintLines.join("\n")}` : "",
79398
79878
  return {
79399
79879
  success: true,
79400
79880
  screenLineCount: lines.length,
79401
- sections: resolved.map((s) => ({ id: s.id, fromLine: s.fromLine, toLine: s.toLine, text: s.text }))
79881
+ sections: resolved.map((s2) => ({ id: s2.id, fromLine: s2.fromLine, toLine: s2.toLine, text: s2.text }))
79402
79882
  };
79403
79883
  } catch (e) {
79404
79884
  return { success: false, error: `resolve failed: ${e.message}` };
@@ -79967,7 +80447,7 @@ ${hintLines.join("\n")}` : "",
79967
80447
  if (!meshId) return { success: false, error: "meshId required" };
79968
80448
  try {
79969
80449
  const { getMeshQueueStats: getMeshQueueStats2, getQueue: getQueue2, describeTaskDependencyState: describeTaskDependencyState2 } = await Promise.resolve().then(() => (init_mesh_work_queue(), mesh_work_queue_exports));
79970
- const status = Array.isArray(args?.status) ? args.status.map((s) => typeof s === "string" ? s.trim() : "").filter(Boolean) : void 0;
80450
+ const status = Array.isArray(args?.status) ? args.status.map((s2) => typeof s2 === "string" ? s2.trim() : "").filter(Boolean) : void 0;
79971
80451
  const rawQueue = getQueue2(meshId, { status });
79972
80452
  const statusById = new Map(getQueue2(meshId).map((task) => [task.id, task.status]));
79973
80453
  const queue = rawQueue.map((task) => Array.isArray(task.dependsOn) && task.dependsOn.length > 0 ? { ...task, ...describeTaskDependencyState2(task, statusById) } : task);
@@ -80248,7 +80728,7 @@ ${hintLines.join("\n")}` : "",
80248
80728
  nodeDaemonId = typeof node?.daemonId === "string" ? node.daemonId.trim() : void 0;
80249
80729
  }
80250
80730
  const selfDaemonId = this.deps.statusInstanceId;
80251
- const isRemote = nodeDaemonId && selfDaemonId && nodeDaemonId !== selfDaemonId;
80731
+ const isRemote = nodeDaemonId && selfDaemonId && !daemonIdsEquivalent(nodeDaemonId, selfDaemonId);
80252
80732
  if (isRemote && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
80253
80733
  const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, "fast_forward_mesh_node", {
80254
80734
  ...typeof args === "object" && args !== null ? args : {},
@@ -80282,7 +80762,7 @@ ${hintLines.join("\n")}` : "",
80282
80762
  nodeDaemonId = typeof node?.daemonId === "string" ? node.daemonId.trim() : void 0;
80283
80763
  }
80284
80764
  const selfDaemonId = this.deps.statusInstanceId;
80285
- const isRemote = nodeDaemonId && selfDaemonId && nodeDaemonId !== selfDaemonId;
80765
+ const isRemote = nodeDaemonId && selfDaemonId && !daemonIdsEquivalent(nodeDaemonId, selfDaemonId);
80286
80766
  if (isRemote && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
80287
80767
  const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, "get_mesh_node_logs", {
80288
80768
  ...typeof args === "object" && args !== null ? args : {},
@@ -80330,7 +80810,7 @@ ${hintLines.join("\n")}` : "",
80330
80810
  const forwardNode = meshRecordForForward?.mesh?.nodes?.find((n) => meshNodeIdMatches(n, nodeId));
80331
80811
  const nodeDaemonId = typeof forwardNode?.daemonId === "string" ? forwardNode.daemonId.trim() : void 0;
80332
80812
  const selfDaemonId = this.deps.statusInstanceId;
80333
- const isRemote = nodeDaemonId && selfDaemonId && nodeDaemonId !== selfDaemonId;
80813
+ const isRemote = nodeDaemonId && selfDaemonId && !daemonIdsEquivalent(nodeDaemonId, selfDaemonId);
80334
80814
  if (isRemote && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
80335
80815
  const callerCoordinatorDaemonId = typeof args?.coordinatorDaemonId === "string" && args.coordinatorDaemonId.trim() ? args.coordinatorDaemonId.trim() : void 0;
80336
80816
  const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, "refine_mesh_node", {
@@ -80417,7 +80897,7 @@ ${hintLines.join("\n")}` : "",
80417
80897
  let worktreeCleanup;
80418
80898
  if (node?.isLocalWorktree) {
80419
80899
  const nodeDaemonId = typeof node.daemonId === "string" ? node.daemonId.trim() : void 0;
80420
- const isRemoteWorktree = nodeDaemonId && nodeDaemonId !== this.deps.statusInstanceId && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch;
80900
+ const isRemoteWorktree = nodeDaemonId && !daemonIdsEquivalent(nodeDaemonId, this.deps.statusInstanceId) && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch;
80421
80901
  if (isRemoteWorktree) {
80422
80902
  const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, "remove_mesh_node", {
80423
80903
  ...typeof args === "object" && args !== null ? args : {},
@@ -80499,7 +80979,7 @@ ${hintLines.join("\n")}` : "",
80499
80979
  const sourceNode = mesh.nodes?.find((n) => meshNodeIdMatches(n, sourceNodeId));
80500
80980
  if (!sourceNode) return { success: false, error: `Source node '${sourceNodeId}' not found in mesh` };
80501
80981
  const sourceDaemonId = typeof sourceNode.daemonId === "string" ? sourceNode.daemonId.trim() : void 0;
80502
- if (sourceDaemonId && sourceDaemonId !== this.deps.statusInstanceId && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
80982
+ if (sourceDaemonId && !daemonIdsEquivalent(sourceDaemonId, this.deps.statusInstanceId) && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
80503
80983
  const forwarded = await this.deps.dispatchMeshCommand(sourceDaemonId, "clone_mesh_node", {
80504
80984
  ...typeof args === "object" && args !== null ? args : {},
80505
80985
  _meshDirectDispatch: true
@@ -80741,7 +81221,7 @@ ${hintLines.join("\n")}` : "",
80741
81221
  if (!node) return { success: false, error: `Node '${nodeId}' not found in mesh` };
80742
81222
  if (!node.isLocalWorktree) return { success: false, error: "Node is not a local worktree node" };
80743
81223
  const nodeDaemonId = typeof node.daemonId === "string" ? node.daemonId.trim() : void 0;
80744
- if (nodeDaemonId && nodeDaemonId !== this.deps.statusInstanceId && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
81224
+ if (nodeDaemonId && !daemonIdsEquivalent(nodeDaemonId, this.deps.statusInstanceId) && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
80745
81225
  const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, "retry_mesh_node_bootstrap", {
80746
81226
  ...typeof args === "object" && args !== null ? args : {},
80747
81227
  _meshDirectDispatch: true
@@ -81949,16 +82429,16 @@ ${ptyResult.output.slice(-2e3)}`);
81949
82429
  const now = this.lastStatusSentAt;
81950
82430
  const target = opts?.p2pOnly ? "P2P" : serverConnected ? "P2P+Server" : "P2P";
81951
82431
  const allStates = this.deps.instanceManager.collectAllStates();
81952
- const ideStates = allStates.filter((s) => s.category === "ide");
81953
- const cliStates = allStates.filter((s) => s.category === "cli");
81954
- const acpStates = allStates.filter((s) => s.category === "acp");
81955
- const ideSummary = ideStates.map((s) => {
81956
- const msgs = s.activeChat?.messages?.length || 0;
81957
- const exts = s.extensions.length;
81958
- return `${s.type}(${s.status},${msgs}msg,${exts}ext)`;
82432
+ const ideStates = allStates.filter((s2) => s2.category === "ide");
82433
+ const cliStates = allStates.filter((s2) => s2.category === "cli");
82434
+ const acpStates = allStates.filter((s2) => s2.category === "acp");
82435
+ const ideSummary = ideStates.map((s2) => {
82436
+ const msgs = s2.activeChat?.messages?.length || 0;
82437
+ const exts = s2.extensions.length;
82438
+ return `${s2.type}(${s2.status},${msgs}msg,${exts}ext)`;
81959
82439
  }).join(", ");
81960
- const cliSummary = cliStates.map((s) => `${s.type}(${s.status})`).join(", ");
81961
- const acpSummary = acpStates.map((s) => `${s.type}(${s.status})`).join(", ");
82440
+ const cliSummary = cliStates.map((s2) => `${s2.type}(${s2.status})`).join(", ");
82441
+ const acpSummary = acpStates.map((s2) => `${s2.type}(${s2.status})`).join(", ");
81962
82442
  const logLevel = opts?.p2pOnly ? "debug" : "info";
81963
82443
  const baseSummary = `IDE: ${ideStates.length} [${ideSummary}] CLI: ${cliStates.length} [${cliSummary}] ACP: ${acpStates.length} [${acpSummary}]`;
81964
82444
  const summaryChanged = baseSummary !== this.lastStatusSummary;
@@ -82069,10 +82549,10 @@ ${ptyResult.output.slice(-2e3)}`);
82069
82549
  }
82070
82550
  return false;
82071
82551
  }
82072
- simpleHash(s) {
82552
+ simpleHash(s2) {
82073
82553
  let h = 2166136261;
82074
- for (let i = 0; i < s.length; i++) {
82075
- h ^= s.charCodeAt(i);
82554
+ for (let i = 0; i < s2.length; i++) {
82555
+ h ^= s2.charCodeAt(i);
82076
82556
  h = h * 16777619 >>> 0;
82077
82557
  }
82078
82558
  return h.toString(36);
@@ -83280,7 +83760,7 @@ ${ptyResult.output.slice(-2e3)}`);
83280
83760
  * Per-category status collect
83281
83761
  */
83282
83762
  collectStatesByCategory(category) {
83283
- return this.collectAllStates().filter((s) => s.category === category);
83763
+ return this.collectAllStates().filter((s2) => s2.category === category);
83284
83764
  }
83285
83765
  // ─── Tick engine ─────────────────────────────────
83286
83766
  /**
@@ -85166,9 +85646,9 @@ async (params) => {
85166
85646
  function findCliTarget(ctx, type, instanceId) {
85167
85647
  if (!ctx.instanceManager) return null;
85168
85648
  const cliStates = ctx.instanceManager.collectAllStates().filter(isCliTargetState);
85169
- if (instanceId) return cliStates.find((s) => s.instanceId === instanceId) || null;
85649
+ if (instanceId) return cliStates.find((s2) => s2.instanceId === instanceId) || null;
85170
85650
  if (!type) return cliStates[cliStates.length - 1] || null;
85171
- const matches = cliStates.filter((s) => s.type === type);
85651
+ const matches = cliStates.filter((s2) => s2.type === type);
85172
85652
  return matches[matches.length - 1] || null;
85173
85653
  }
85174
85654
  function getCliTargetBundle(ctx, type, instanceId) {
@@ -85531,20 +86011,20 @@ async (params) => {
85531
86011
  return;
85532
86012
  }
85533
86013
  const allStates = ctx.instanceManager.collectAllStates();
85534
- const cliStates = allStates.filter((s) => s.category === "cli" || s.category === "acp");
85535
- const result = cliStates.map((s) => ({
85536
- instanceId: s.instanceId,
85537
- type: s.type,
85538
- name: s.name,
85539
- category: s.category,
85540
- status: s.status,
85541
- mode: s.mode,
85542
- workspace: s.workspace,
85543
- messageCount: s.activeChat?.messages?.length || 0,
85544
- lastMessage: s.activeChat?.messages?.slice(-1)[0] || null,
85545
- activeModal: s.activeChat?.activeModal || null,
85546
- pendingEvents: s.pendingEvents || [],
85547
- settings: s.settings
86014
+ const cliStates = allStates.filter((s2) => s2.category === "cli" || s2.category === "acp");
86015
+ const result = cliStates.map((s2) => ({
86016
+ instanceId: s2.instanceId,
86017
+ type: s2.type,
86018
+ name: s2.name,
86019
+ category: s2.category,
86020
+ status: s2.status,
86021
+ mode: s2.mode,
86022
+ workspace: s2.workspace,
86023
+ messageCount: s2.activeChat?.messages?.length || 0,
86024
+ lastMessage: s2.activeChat?.messages?.slice(-1)[0] || null,
86025
+ activeModal: s2.activeChat?.activeModal || null,
86026
+ pendingEvents: s2.pendingEvents || [],
86027
+ settings: s2.settings
85548
86028
  }));
85549
86029
  ctx.json(res, 200, { instances: result, count: result.length });
85550
86030
  }
@@ -85633,9 +86113,9 @@ async (params) => {
85633
86113
  }
85634
86114
  if (ctx.instanceManager) {
85635
86115
  const allStates = ctx.instanceManager.collectAllStates();
85636
- const cliStates = allStates.filter((s) => s.category === "cli" || s.category === "acp");
85637
- for (const s of cliStates) {
85638
- ctx.sendCliSSE({ event: "snapshot", providerType: s.type, status: s.status, instanceId: s.instanceId });
86116
+ const cliStates = allStates.filter((s2) => s2.category === "cli" || s2.category === "acp");
86117
+ for (const s2 of cliStates) {
86118
+ ctx.sendCliSSE({ event: "snapshot", providerType: s2.type, status: s2.status, instanceId: s2.instanceId });
85639
86119
  }
85640
86120
  }
85641
86121
  _req.on("close", () => {
@@ -85651,7 +86131,7 @@ async (params) => {
85651
86131
  const target = findCliTarget(ctx, type);
85652
86132
  if (!target) {
85653
86133
  const allStates = ctx.instanceManager.collectAllStates();
85654
- ctx.json(res, 404, { error: `No running instance for: ${type}`, available: allStates.filter((s) => s.category === "cli" || s.category === "acp").map((s) => s.type) });
86134
+ ctx.json(res, 404, { error: `No running instance for: ${type}`, available: allStates.filter((s2) => s2.category === "cli" || s2.category === "acp").map((s2) => s2.type) });
85655
86135
  return;
85656
86136
  }
85657
86137
  const instance = ctx.instanceManager.getInstance(target.instanceId);
@@ -85697,7 +86177,7 @@ async (params) => {
85697
86177
  const allStates = ctx.instanceManager.collectAllStates();
85698
86178
  ctx.json(res, 404, {
85699
86179
  error: `No running instance for: ${type}`,
85700
- available: allStates.filter((s) => s.category === "cli" || s.category === "acp").map((s) => s.type)
86180
+ available: allStates.filter((s2) => s2.category === "cli" || s2.category === "acp").map((s2) => s2.type)
85701
86181
  });
85702
86182
  return;
85703
86183
  }
@@ -86500,7 +86980,7 @@ async (params) => {
86500
86980
  child.write("\x1B[12;1R");
86501
86981
  ctx.log("Terminal CPR request (\\x1b[6n) intercepted in PTY, responding with dummy coordinates [12;1R]");
86502
86982
  }
86503
- checkAutoApproval(data, (s) => child.write(s));
86983
+ checkAutoApproval(data, (s2) => child.write(s2));
86504
86984
  sendAutoImplSSE(ctx, { event: "output", data: { chunk: data, stream: "stdout" } });
86505
86985
  scheduleAutoStopForVerification();
86506
86986
  });
@@ -86513,7 +86993,7 @@ async (params) => {
86513
86993
  stdout += chunk;
86514
86994
  clearAutoStopTimer();
86515
86995
  if (chunk.includes("\x1B[6n")) child.stdin?.write("\x1B[1;1R");
86516
- checkAutoApproval(chunk, (s) => child.stdin?.write(s));
86996
+ checkAutoApproval(chunk, (s2) => child.stdin?.write(s2));
86517
86997
  sendAutoImplSSE(ctx, { event: "output", data: { chunk, stream: "stdout" } });
86518
86998
  scheduleAutoStopForVerification();
86519
86999
  });
@@ -86521,7 +87001,7 @@ async (params) => {
86521
87001
  const chunk = d.toString();
86522
87002
  stderr += chunk;
86523
87003
  clearAutoStopTimer();
86524
- checkAutoApproval(chunk, (s) => child.stdin?.write(s));
87004
+ checkAutoApproval(chunk, (s2) => child.stdin?.write(s2));
86525
87005
  sendAutoImplSSE(ctx, { event: "output", data: { chunk, stream: "stderr" } });
86526
87006
  scheduleAutoStopForVerification();
86527
87007
  });
@@ -87334,59 +87814,59 @@ data: ${JSON.stringify(msg.data)}
87334
87814
  // ─── Route Table ─────────────────────────────────────
87335
87815
  routes = [
87336
87816
  // Static routes
87337
- { method: "GET", pattern: "/api/providers", handler: (q, s) => this.handleListProviders(q, s) },
87338
- { method: "GET", pattern: "/api/providers/source-config", handler: (q, s) => this.handleGetProviderSourceConfig(q, s) },
87339
- { method: "POST", pattern: "/api/providers/source-config", handler: (q, s) => this.handleSetProviderSourceConfig(q, s) },
87340
- { method: "GET", pattern: "/api/providers/versions", handler: (q, s) => this.handleDetectVersions(q, s) },
87341
- { method: "POST", pattern: "/api/providers/reload", handler: (q, s) => this.handleReload(q, s) },
87342
- { method: "POST", pattern: "/api/cdp/evaluate", handler: (q, s) => this.handleCdpEvaluate(q, s) },
87343
- { method: "POST", pattern: "/api/cdp/click", handler: (q, s) => this.handleCdpClick(q, s) },
87344
- { method: "POST", pattern: "/api/cdp/dom/query", handler: (q, s) => this.handleCdpDomQuery(q, s) },
87345
- { method: "POST", pattern: "/api/cdp/dom/inspect", handler: (q, s) => this.handleDomInspect(q, s) },
87346
- { method: "POST", pattern: "/api/cdp/dom/children", handler: (q, s) => this.handleDomChildren(q, s) },
87347
- { method: "POST", pattern: "/api/cdp/dom/analyze", handler: (q, s) => this.handleDomAnalyze(q, s) },
87348
- { method: "POST", pattern: "/api/cdp/dom/find-text", handler: (q, s) => this.handleFindByText(q, s) },
87349
- { method: "POST", pattern: "/api/cdp/dom/find-common", handler: (q, s) => this.handleFindCommon(q, s) },
87350
- { method: "GET", pattern: "/api/cdp/screenshot", handler: (q, s) => this.handleScreenshot(q, s) },
87351
- { method: "GET", pattern: "/api/cdp/targets", handler: (q, s) => this.handleCdpTargets(q, s) },
87352
- { method: "POST", pattern: "/api/scripts/run", handler: (q, s) => this.handleScriptsRun(q, s) },
87353
- { method: "GET", pattern: "/api/status", handler: (q, s) => this.handleStatus(q, s) },
87354
- { method: "POST", pattern: "/api/watch/start", handler: (q, s) => this.handleWatchStart(q, s) },
87355
- { method: "POST", pattern: "/api/watch/stop", handler: (q, s) => this.handleWatchStop(q, s) },
87356
- { method: "GET", pattern: "/api/watch/events", handler: (q, s) => this.handleSSE(q, s) },
87357
- { method: "POST", pattern: "/api/scaffold", handler: (q, s) => this.handleScaffold(q, s) },
87817
+ { method: "GET", pattern: "/api/providers", handler: (q, s2) => this.handleListProviders(q, s2) },
87818
+ { method: "GET", pattern: "/api/providers/source-config", handler: (q, s2) => this.handleGetProviderSourceConfig(q, s2) },
87819
+ { method: "POST", pattern: "/api/providers/source-config", handler: (q, s2) => this.handleSetProviderSourceConfig(q, s2) },
87820
+ { method: "GET", pattern: "/api/providers/versions", handler: (q, s2) => this.handleDetectVersions(q, s2) },
87821
+ { method: "POST", pattern: "/api/providers/reload", handler: (q, s2) => this.handleReload(q, s2) },
87822
+ { method: "POST", pattern: "/api/cdp/evaluate", handler: (q, s2) => this.handleCdpEvaluate(q, s2) },
87823
+ { method: "POST", pattern: "/api/cdp/click", handler: (q, s2) => this.handleCdpClick(q, s2) },
87824
+ { method: "POST", pattern: "/api/cdp/dom/query", handler: (q, s2) => this.handleCdpDomQuery(q, s2) },
87825
+ { method: "POST", pattern: "/api/cdp/dom/inspect", handler: (q, s2) => this.handleDomInspect(q, s2) },
87826
+ { method: "POST", pattern: "/api/cdp/dom/children", handler: (q, s2) => this.handleDomChildren(q, s2) },
87827
+ { method: "POST", pattern: "/api/cdp/dom/analyze", handler: (q, s2) => this.handleDomAnalyze(q, s2) },
87828
+ { method: "POST", pattern: "/api/cdp/dom/find-text", handler: (q, s2) => this.handleFindByText(q, s2) },
87829
+ { method: "POST", pattern: "/api/cdp/dom/find-common", handler: (q, s2) => this.handleFindCommon(q, s2) },
87830
+ { method: "GET", pattern: "/api/cdp/screenshot", handler: (q, s2) => this.handleScreenshot(q, s2) },
87831
+ { method: "GET", pattern: "/api/cdp/targets", handler: (q, s2) => this.handleCdpTargets(q, s2) },
87832
+ { method: "POST", pattern: "/api/scripts/run", handler: (q, s2) => this.handleScriptsRun(q, s2) },
87833
+ { method: "GET", pattern: "/api/status", handler: (q, s2) => this.handleStatus(q, s2) },
87834
+ { method: "POST", pattern: "/api/watch/start", handler: (q, s2) => this.handleWatchStart(q, s2) },
87835
+ { method: "POST", pattern: "/api/watch/stop", handler: (q, s2) => this.handleWatchStop(q, s2) },
87836
+ { method: "GET", pattern: "/api/watch/events", handler: (q, s2) => this.handleSSE(q, s2) },
87837
+ { method: "POST", pattern: "/api/scaffold", handler: (q, s2) => this.handleScaffold(q, s2) },
87358
87838
  // CLI Debug routes
87359
- { method: "GET", pattern: "/api/cli/status", handler: (q, s) => this.handleCliStatus(q, s) },
87360
- { method: "POST", pattern: "/api/cli/launch", handler: (q, s) => this.handleCliLaunch(q, s) },
87361
- { method: "POST", pattern: "/api/cli/send", handler: (q, s) => this.handleCliSend(q, s) },
87362
- { method: "POST", pattern: "/api/cli/exercise", handler: (q, s) => this.handleCliExercise(q, s) },
87363
- { method: "POST", pattern: "/api/cli/fixture/capture", handler: (q, s) => this.handleCliFixtureCapture(q, s) },
87364
- { method: "POST", pattern: "/api/cli/fixture/replay", handler: (q, s) => this.handleCliFixtureReplay(q, s) },
87365
- { method: "POST", pattern: "/api/cli/resolve", handler: (q, s) => this.handleCliResolve(q, s) },
87366
- { method: "POST", pattern: "/api/cli/raw", handler: (q, s) => this.handleCliRaw(q, s) },
87367
- { method: "POST", pattern: "/api/cli/stop", handler: (q, s) => this.handleCliStop(q, s) },
87368
- { method: "GET", pattern: "/api/cli/events", handler: (q, s) => this.handleCliSSE(q, s) },
87369
- { method: "GET", pattern: /^\/api\/cli\/debug\/([^/]+)$/, handler: (q, s, p) => this.handleCliDebug(p[0], q, s) },
87370
- { method: "GET", pattern: /^\/api\/cli\/trace\/([^/]+)$/, handler: (q, s, p) => this.handleCliTrace(p[0], q, s) },
87371
- { method: "GET", pattern: /^\/api\/cli\/fixtures\/([^/]+)$/, handler: (q, s, p) => this.handleCliFixtureList(p[0], q, s) },
87839
+ { method: "GET", pattern: "/api/cli/status", handler: (q, s2) => this.handleCliStatus(q, s2) },
87840
+ { method: "POST", pattern: "/api/cli/launch", handler: (q, s2) => this.handleCliLaunch(q, s2) },
87841
+ { method: "POST", pattern: "/api/cli/send", handler: (q, s2) => this.handleCliSend(q, s2) },
87842
+ { method: "POST", pattern: "/api/cli/exercise", handler: (q, s2) => this.handleCliExercise(q, s2) },
87843
+ { method: "POST", pattern: "/api/cli/fixture/capture", handler: (q, s2) => this.handleCliFixtureCapture(q, s2) },
87844
+ { method: "POST", pattern: "/api/cli/fixture/replay", handler: (q, s2) => this.handleCliFixtureReplay(q, s2) },
87845
+ { method: "POST", pattern: "/api/cli/resolve", handler: (q, s2) => this.handleCliResolve(q, s2) },
87846
+ { method: "POST", pattern: "/api/cli/raw", handler: (q, s2) => this.handleCliRaw(q, s2) },
87847
+ { method: "POST", pattern: "/api/cli/stop", handler: (q, s2) => this.handleCliStop(q, s2) },
87848
+ { method: "GET", pattern: "/api/cli/events", handler: (q, s2) => this.handleCliSSE(q, s2) },
87849
+ { method: "GET", pattern: /^\/api\/cli\/debug\/([^/]+)$/, handler: (q, s2, p) => this.handleCliDebug(p[0], q, s2) },
87850
+ { method: "GET", pattern: /^\/api\/cli\/trace\/([^/]+)$/, handler: (q, s2, p) => this.handleCliTrace(p[0], q, s2) },
87851
+ { method: "GET", pattern: /^\/api\/cli\/fixtures\/([^/]+)$/, handler: (q, s2, p) => this.handleCliFixtureList(p[0], q, s2) },
87372
87852
  // Dynamic routes (provider :type param)
87373
- { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/script$/, handler: (q, s, p) => this.handleRunScript(p[0], q, s) },
87374
- { method: "GET", pattern: /^\/api\/providers\/([^/]+)\/files$/, handler: (q, s, p) => this.handleListFiles(p[0], q, s) },
87375
- { method: "GET", pattern: /^\/api\/providers\/([^/]+)\/file$/, handler: (q, s, p) => this.handleReadFile(p[0], q, s) },
87376
- { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/file$/, handler: (q, s, p) => this.handleWriteFile(p[0], q, s) },
87377
- { method: "GET", pattern: /^\/api\/providers\/([^/]+)\/source$/, handler: (q, s, p) => this.handleSource(p[0], q, s) },
87378
- { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/save$/, handler: (q, s, p) => this.handleSave(p[0], q, s) },
87379
- { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/typeAndSend$/, handler: (q, s, p) => this.handleTypeAndSend(p[0], q, s) },
87380
- { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/typeAndSendAt$/, handler: (q, s, p) => this.handleTypeAndSendAt(p[0], q, s) },
87381
- { method: "GET", pattern: /^\/api\/providers\/([^/]+)\/config$/, handler: (q, s, p) => this.handleProviderConfig(p[0], q, s) },
87382
- { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/dom-context$/, handler: (q, s, p) => this.handleDomContext(p[0], q, s) },
87383
- { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/auto-implement$/, handler: (q, s, p) => this.handleAutoImplement(p[0], q, s) },
87384
- { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/auto-implement\/cancel$/, handler: (q, s, p) => this.handleAutoImplCancel(p[0], q, s) },
87385
- { method: "GET", pattern: /^\/api\/providers\/([^/]+)\/auto-implement\/status$/, handler: (q, s, p) => this.handleAutoImplSSE(p[0], q, s) },
87386
- { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/spawn-test$/, handler: (q, s, p) => this.handleSpawnTest(p[0], q, s) },
87387
- { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/validate$/, handler: (q, s, p) => this.handleValidate(p[0], q, s) },
87388
- { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/acp-chat$/, handler: (q, s, p) => this.handleAcpChat(p[0], q, s) },
87389
- { method: "GET", pattern: /^\/api\/providers\/([^/]+)\/script-hints$/, handler: (q, s, p) => this.handleScriptHints(p[0], q, s) }
87853
+ { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/script$/, handler: (q, s2, p) => this.handleRunScript(p[0], q, s2) },
87854
+ { method: "GET", pattern: /^\/api\/providers\/([^/]+)\/files$/, handler: (q, s2, p) => this.handleListFiles(p[0], q, s2) },
87855
+ { method: "GET", pattern: /^\/api\/providers\/([^/]+)\/file$/, handler: (q, s2, p) => this.handleReadFile(p[0], q, s2) },
87856
+ { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/file$/, handler: (q, s2, p) => this.handleWriteFile(p[0], q, s2) },
87857
+ { method: "GET", pattern: /^\/api\/providers\/([^/]+)\/source$/, handler: (q, s2, p) => this.handleSource(p[0], q, s2) },
87858
+ { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/save$/, handler: (q, s2, p) => this.handleSave(p[0], q, s2) },
87859
+ { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/typeAndSend$/, handler: (q, s2, p) => this.handleTypeAndSend(p[0], q, s2) },
87860
+ { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/typeAndSendAt$/, handler: (q, s2, p) => this.handleTypeAndSendAt(p[0], q, s2) },
87861
+ { method: "GET", pattern: /^\/api\/providers\/([^/]+)\/config$/, handler: (q, s2, p) => this.handleProviderConfig(p[0], q, s2) },
87862
+ { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/dom-context$/, handler: (q, s2, p) => this.handleDomContext(p[0], q, s2) },
87863
+ { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/auto-implement$/, handler: (q, s2, p) => this.handleAutoImplement(p[0], q, s2) },
87864
+ { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/auto-implement\/cancel$/, handler: (q, s2, p) => this.handleAutoImplCancel(p[0], q, s2) },
87865
+ { method: "GET", pattern: /^\/api\/providers\/([^/]+)\/auto-implement\/status$/, handler: (q, s2, p) => this.handleAutoImplSSE(p[0], q, s2) },
87866
+ { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/spawn-test$/, handler: (q, s2, p) => this.handleSpawnTest(p[0], q, s2) },
87867
+ { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/validate$/, handler: (q, s2, p) => this.handleValidate(p[0], q, s2) },
87868
+ { method: "POST", pattern: /^\/api\/providers\/([^/]+)\/acp-chat$/, handler: (q, s2, p) => this.handleAcpChat(p[0], q, s2) },
87869
+ { method: "GET", pattern: /^\/api\/providers\/([^/]+)\/script-hints$/, handler: (q, s2, p) => this.handleScriptHints(p[0], q, s2) }
87390
87870
  ];
87391
87871
  matchRoute(method, pathname) {
87392
87872
  for (const route of this.routes) {
@@ -87981,14 +88461,14 @@ data: ${JSON.stringify(msg.data)}
87981
88461
  warnings.push(...validation.warnings);
87982
88462
  if (config2.settings) {
87983
88463
  for (const [key, val] of Object.entries(config2.settings)) {
87984
- const s = val;
87985
- if (!s.type) errors.push(`settings.${key}: missing type`);
87986
- else if (!["boolean", "number", "string", "select"].includes(s.type))
87987
- errors.push(`settings.${key}: invalid type '${s.type}'`);
87988
- if (s.default === void 0) warnings.push(`settings.${key}: no default value`);
87989
- if (s.type === "number" && s.min !== void 0 && s.max !== void 0 && s.min > s.max)
87990
- errors.push(`settings.${key}: min (${s.min}) > max (${s.max})`);
87991
- if (s.type === "select" && (!s.options || !Array.isArray(s.options) || s.options.length === 0))
88464
+ const s2 = val;
88465
+ if (!s2.type) errors.push(`settings.${key}: missing type`);
88466
+ else if (!["boolean", "number", "string", "select"].includes(s2.type))
88467
+ errors.push(`settings.${key}: invalid type '${s2.type}'`);
88468
+ if (s2.default === void 0) warnings.push(`settings.${key}: no default value`);
88469
+ if (s2.type === "number" && s2.min !== void 0 && s2.max !== void 0 && s2.min > s2.max)
88470
+ errors.push(`settings.${key}: min (${s2.min}) > max (${s2.max})`);
88471
+ if (s2.type === "select" && (!s2.options || !Array.isArray(s2.options) || s2.options.length === 0))
87992
88472
  errors.push(`settings.${key}: select type requires options[]`);
87993
88473
  }
87994
88474
  }