@adhdev/daemon-core 0.9.82-rc.350 → 0.9.82-rc.352

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -316,10 +316,10 @@ function readInjected(value) {
316
316
  }
317
317
  function getDaemonBuildInfo() {
318
318
  if (cached) return cached;
319
- const commit = readInjected(true ? "f066449c7e758daf63ad40d431a5e97fc8d79a0e" : void 0) ?? "unknown";
320
- const commitShort = readInjected(true ? "f066449c" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
321
- const version = readInjected(true ? "0.9.82-rc.350" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
322
- const builtAt = readInjected(true ? "2026-06-21T19:33:17.868Z" : void 0);
319
+ const commit = readInjected(true ? "ca5f944b7763a621357fc28a9f62ac398b0ced6c" : void 0) ?? "unknown";
320
+ const commitShort = readInjected(true ? "ca5f944b" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
321
+ const version = readInjected(true ? "0.9.82-rc.352" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
322
+ const builtAt = readInjected(true ? "2026-06-22T07:17:05.715Z" : void 0);
323
323
  cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
324
324
  return cached;
325
325
  }
@@ -3195,7 +3195,7 @@ function installGlobalInterceptor() {
3195
3195
  function getLogPath() {
3196
3196
  return currentLogFile;
3197
3197
  }
3198
- var fs4, path9, os3, LEVEL_NUM, LEVEL_LABEL, currentLevel, LOG_DIR, MAX_LOG_SIZE, MAX_LOG_DAYS, currentDate, currentLogFile, writeCount, RING_BUFFER_SIZE, ringBuffer, origConsoleLog, origConsoleError, origConsoleWarn, LOG, interceptorInstalled, LOG_PATH, LOG_DIR_PATH;
3198
+ var fs4, path9, os3, LEVEL_NUM, LEVEL_LABEL, currentLevel, ADHDEV_HOME, LOG_DIR, MAX_LOG_SIZE, MAX_LOG_DAYS, currentDate, currentLogFile, writeCount, RING_BUFFER_SIZE, ringBuffer, origConsoleLog, origConsoleError, origConsoleWarn, LOG, interceptorInstalled, LOG_PATH, LOG_DIR_PATH;
3199
3199
  var init_logger = __esm({
3200
3200
  "src/logging/logger.ts"() {
3201
3201
  "use strict";
@@ -3206,7 +3206,8 @@ var init_logger = __esm({
3206
3206
  LEVEL_NUM = { debug: 0, info: 1, warn: 2, error: 3 };
3207
3207
  LEVEL_LABEL = { debug: "DBG", info: "INF", warn: "WRN", error: "ERR" };
3208
3208
  currentLevel = "info";
3209
- LOG_DIR = process.platform === "win32" ? path9.join(process.env.LOCALAPPDATA || process.env.APPDATA || path9.join(os3.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path9.join(os3.homedir(), "Library", "Logs", "adhdev") : path9.join(os3.homedir(), ".local", "share", "adhdev", "logs");
3209
+ ADHDEV_HOME = process.env.ADHDEV_CONFIG_DIR && process.env.ADHDEV_CONFIG_DIR.trim() ? process.env.ADHDEV_CONFIG_DIR.trim() : path9.join(os3.homedir(), ".adhdev");
3210
+ LOG_DIR = path9.join(ADHDEV_HOME, "logs");
3210
3211
  MAX_LOG_SIZE = 5 * 1024 * 1024;
3211
3212
  MAX_LOG_DAYS = 7;
3212
3213
  try {
@@ -4007,6 +4008,7 @@ __export(mesh_work_queue_exports, {
4007
4008
  nodeSatisfiesRequiredTags: () => nodeSatisfiesRequiredTags,
4008
4009
  normalizeMeshCapabilityTags: () => normalizeMeshCapabilityTags,
4009
4010
  normalizeMeshTaskMode: () => normalizeMeshTaskMode,
4011
+ reclaimStrandedAssignedTask: () => reclaimStrandedAssignedTask,
4010
4012
  recordDirectDispatchTask: () => recordDirectDispatchTask,
4011
4013
  recordMeshToolCall: () => recordMeshToolCall,
4012
4014
  recordTaskAutoLaunch: () => recordTaskAutoLaunch,
@@ -4442,6 +4444,52 @@ function requeueTask(meshId, taskId, opts) {
4442
4444
  return entry;
4443
4445
  });
4444
4446
  }
4447
+ function reclaimStrandedAssignedTask(meshId, taskId, opts) {
4448
+ requireMeshHostQueueOwner(opts);
4449
+ return withQueueLock(meshId, () => {
4450
+ const entry = MeshRuntimeStore.getInstance().findQueueEntryById(meshId, taskId);
4451
+ if (!entry) return null;
4452
+ if (entry.status !== "assigned") return null;
4453
+ const now = (/* @__PURE__ */ new Date()).toISOString();
4454
+ const reason = opts?.reason || "assigned_stranded_dispatch_unconfirmed";
4455
+ const reclaims = (entry.strandedReclaimCount || 0) + 1;
4456
+ const prevNode = entry.assignedNodeId;
4457
+ const prevSession = entry.assignedSessionId;
4458
+ delete entry.assignedNodeId;
4459
+ delete entry.assignedSessionId;
4460
+ delete entry.assignedProviderType;
4461
+ delete entry.dispatchTimestamp;
4462
+ entry.strandedReclaimCount = reclaims;
4463
+ entry.updatedAt = now;
4464
+ if (reclaims > MAX_STRANDED_RECLAIMS) {
4465
+ entry.status = "failed";
4466
+ entry.cancelReason = `stranded_dispatch_unrecovered: reclaimed ${reclaims - 1} time(s) without a confirmed dispatch`;
4467
+ MeshRuntimeStore.getInstance().updateQueueEntry(entry);
4468
+ propagateDependencyFailure(meshId, taskId);
4469
+ } else {
4470
+ entry.status = "pending";
4471
+ entry.requeuedAt = now;
4472
+ entry.requeueReason = reason;
4473
+ MeshRuntimeStore.getInstance().updateQueueEntry(entry);
4474
+ }
4475
+ try {
4476
+ appendLedgerEntry(meshId, {
4477
+ kind: "task_reclaimed",
4478
+ nodeId: prevNode,
4479
+ sessionId: prevSession,
4480
+ payload: {
4481
+ taskId,
4482
+ reason,
4483
+ ...typeof opts?.ageMs === "number" ? { ageMs: opts.ageMs } : {},
4484
+ reclaimCount: reclaims,
4485
+ outcome: entry.status
4486
+ }
4487
+ });
4488
+ } catch {
4489
+ }
4490
+ return entry;
4491
+ });
4492
+ }
4445
4493
  function updateSessionTaskStatus(meshId, sessionId, status, opts) {
4446
4494
  return withQueueLock(meshId, () => {
4447
4495
  const store = MeshRuntimeStore.getInstance();
@@ -4555,7 +4603,7 @@ function recordMeshToolCall(opts) {
4555
4603
  return { rateLimitExceeded: false, callsInWindow: 0, advisory: null };
4556
4604
  }
4557
4605
  }
4558
- var import_crypto5, ACTIVE_MESH_QUEUE_STATUSES, HISTORICAL_MESH_QUEUE_STATUSES, MESH_TASK_MODES, LIVE_DEBUG_READONLY_FORBIDDEN, NEGATION_CUES, NEGATION_WINDOW_TOKENS, GIT_MUTATION_SUBCOMMANDS, GIT_STASH_READONLY_SUBCOMMANDS, DEPENDENCY_FAILURE_TERMINALS;
4606
+ var import_crypto5, ACTIVE_MESH_QUEUE_STATUSES, HISTORICAL_MESH_QUEUE_STATUSES, MESH_TASK_MODES, LIVE_DEBUG_READONLY_FORBIDDEN, NEGATION_CUES, NEGATION_WINDOW_TOKENS, GIT_MUTATION_SUBCOMMANDS, GIT_STASH_READONLY_SUBCOMMANDS, DEPENDENCY_FAILURE_TERMINALS, MAX_STRANDED_RECLAIMS;
4559
4607
  var init_mesh_work_queue = __esm({
4560
4608
  "src/mesh/mesh-work-queue.ts"() {
4561
4609
  "use strict";
@@ -4565,6 +4613,7 @@ var init_mesh_work_queue = __esm({
4565
4613
  init_mesh_runtime_store();
4566
4614
  init_mesh_config();
4567
4615
  init_logger();
4616
+ init_mesh_ledger();
4568
4617
  ACTIVE_MESH_QUEUE_STATUSES = ["pending", "assigned"];
4569
4618
  HISTORICAL_MESH_QUEUE_STATUSES = ["completed", "failed", "cancelled"];
4570
4619
  MESH_TASK_MODES = ["code_change", "validation", "live_debug_readonly", "launch_app", "convergence"];
@@ -4617,6 +4666,7 @@ var init_mesh_work_queue = __esm({
4617
4666
  ]);
4618
4667
  GIT_STASH_READONLY_SUBCOMMANDS = /* @__PURE__ */ new Set(["list", "show"]);
4619
4668
  DEPENDENCY_FAILURE_TERMINALS = /* @__PURE__ */ new Set(["failed", "cancelled"]);
4669
+ MAX_STRANDED_RECLAIMS = 3;
4620
4670
  }
4621
4671
  });
4622
4672
 
@@ -4676,6 +4726,10 @@ var init_mesh_runtime_store = __esm({
4676
4726
  migratedMeshIds = /* @__PURE__ */ new Set();
4677
4727
  fingerprintSweepCounter = 0;
4678
4728
  walWriteCounter = 0;
4729
+ // Independent cadence for the tool-call-log sweep. Must NOT share walWriteCounter:
4730
+ // sharing makes each store's threshold drift by the other's write volume (WAL
4731
+ // checkpoint at 500 vs tool-log sweep at 200 would interfere arbitrarily).
4732
+ toolCallLogCounter = 0;
4679
4733
  static WAL_CHECK_INTERVAL = 500;
4680
4734
  static WAL_MAX_BYTES = 50 * 1024 * 1024;
4681
4735
  // 50 MB
@@ -5498,6 +5552,22 @@ var init_mesh_runtime_store = __esm({
5498
5552
  updatedAt: r.updated_at
5499
5553
  }));
5500
5554
  }
5555
+ /**
5556
+ * Bug B watchdog support: true when at least one delivery record for the task has
5557
+ * reached a confirmed-handed-off status (delivered / acked / completed). The
5558
+ * assigned-stranded watchdog uses this to distinguish a dispatch that was never
5559
+ * confirmed (reclaimable) from one that WAS handed to the worker (a genuinely
5560
+ * in-flight or completion-lost task, which is PHASE 4's responsibility, not this
5561
+ * watchdog's). Indexed by (mesh_id, task_id).
5562
+ */
5563
+ taskHasConfirmedDelivery(meshId, taskId) {
5564
+ const row = this.db.prepare(`
5565
+ SELECT 1 FROM mesh_session_delivery
5566
+ WHERE mesh_id = ? AND task_id = ? AND status IN ('delivered','acked','completed')
5567
+ LIMIT 1
5568
+ `).get(meshId, taskId);
5569
+ return !!row;
5570
+ }
5501
5571
  expireStaleSessionDeliveries(meshId) {
5502
5572
  const now = (/* @__PURE__ */ new Date()).toISOString();
5503
5573
  this.db.prepare(`
@@ -5569,7 +5639,7 @@ var init_mesh_runtime_store = __esm({
5569
5639
  "SELECT COUNT(*) as cnt FROM mesh_tool_call_log WHERE mesh_id = ? AND tool = ? AND called_at >= ?"
5570
5640
  ).get(meshId, tool, windowStart);
5571
5641
  const callsInWindow = row?.cnt ?? 0;
5572
- if (++this.walWriteCounter % 200 === 0) {
5642
+ if (++this.toolCallLogCounter % 200 === 0) {
5573
5643
  this.db.prepare(
5574
5644
  "DELETE FROM mesh_tool_call_log WHERE called_at < ?"
5575
5645
  ).run(now - Math.max(windowMs * 10, 6e4));
@@ -6024,9 +6094,9 @@ function computeMeshTaskStats(meshId, opts) {
6024
6094
  }
6025
6095
  return targetIds.map((taskId) => {
6026
6096
  const queueEntry = queueById.get(taskId);
6027
- const status = queueEntry?.status ?? "unknown";
6028
6097
  const dispatch = dispatches.get(taskId);
6029
6098
  const terminal = terminals.get(taskId);
6099
+ const status = queueEntry?.status ?? (terminal ? terminal.kind === "task_completed" ? "completed" : "failed" : "unknown");
6030
6100
  const isTerminalStatus = status === "completed" || status === "failed" || status === "cancelled";
6031
6101
  const dispatchTime = parseTime(dispatch?.first ?? queueEntry?.dispatchTimestamp);
6032
6102
  const terminalTime = parseTime(terminal?.at);
@@ -7921,6 +7991,35 @@ function meshNodeIdMatches(node, candidateId) {
7921
7991
  if (!trimmed) return false;
7922
7992
  return normalizeMeshNodeId(node) === trimmed;
7923
7993
  }
7994
+ function machineCoreFromDaemonId(id) {
7995
+ const trimmed = readString5(id);
7996
+ if (!trimmed) return void 0;
7997
+ for (const prefix of DAEMON_ID_PREFIXES) {
7998
+ if (trimmed.startsWith(prefix)) {
7999
+ const core = trimmed.slice(prefix.length).trim();
8000
+ return core || void 0;
8001
+ }
8002
+ }
8003
+ return trimmed;
8004
+ }
8005
+ function expandDaemonIdForms(ids) {
8006
+ const list = Array.isArray(ids) ? ids : ids != null ? [ids] : [];
8007
+ const out = [];
8008
+ const seen = /* @__PURE__ */ new Set();
8009
+ const add = (value) => {
8010
+ if (!value || seen.has(value)) return;
8011
+ seen.add(value);
8012
+ out.push(value);
8013
+ };
8014
+ for (const raw of list) add(readString5(raw));
8015
+ for (const raw of list) {
8016
+ const core = machineCoreFromDaemonId(readString5(raw));
8017
+ if (!core || !core.startsWith("mach_")) continue;
8018
+ add(core);
8019
+ for (const prefix of DAEMON_ID_PREFIXES) add(`${prefix}${core}`);
8020
+ }
8021
+ return out;
8022
+ }
7924
8023
  function summarizeGitShape(status) {
7925
8024
  const record = readRecord3(status);
7926
8025
  if (!Object.keys(record).length) return null;
@@ -7955,9 +8054,11 @@ function summarizeGitShape(status) {
7955
8054
  submodules
7956
8055
  };
7957
8056
  }
8057
+ var DAEMON_ID_PREFIXES;
7958
8058
  var init_dist = __esm({
7959
8059
  "../mesh-shared/dist/index.mjs"() {
7960
8060
  "use strict";
8061
+ DAEMON_ID_PREFIXES = ["daemon_", "standalone_"];
7961
8062
  }
7962
8063
  });
7963
8064
 
@@ -8035,6 +8136,14 @@ function statusFromTerminal(entry) {
8035
8136
  if (entry.kind === "task_completed") return "idle";
8036
8137
  return "failed";
8037
8138
  }
8139
+ function classifyDirectDispatch(params) {
8140
+ const { status, isTerminalRow, hasTerminalStatus, liveStatus, liveStaleReason, dispatchedToIdleSession } = params;
8141
+ const isNoTransition = !hasTerminalStatus && !liveStatus;
8142
+ const isIdleUnacknowledged = status === "idle";
8143
+ const ledgerOnlyStaleReason = !isTerminalRow && (isIdleUnacknowledged || isNoTransition || dispatchedToIdleSession && isIdleUnacknowledged) ? LEDGER_ONLY_STALE_REASON : void 0;
8144
+ const isFreshUnacknowledged = Boolean(ledgerOnlyStaleReason && !liveStaleReason);
8145
+ return { ledgerOnlyStaleReason, isFreshUnacknowledged };
8146
+ }
8038
8147
  function buildMeshActiveWorkSummary(activeWork) {
8039
8148
  const statusCounts = {
8040
8149
  pending: 0,
@@ -8097,10 +8206,14 @@ function buildMeshActiveWork(opts) {
8097
8206
  const dbStatus = dispatch.status;
8098
8207
  const isTerminal = dbStatus === "completed" || dbStatus === "failed" || dbStatus === "stale";
8099
8208
  const status = isTerminal ? dbStatus === "completed" ? "idle" : "failed" : live.status || (dbStatus === "acked" ? "generating" : "assigned");
8100
- const isNoTransition = !isTerminal && !live.status;
8101
- const isIdleUnacknowledged = status === "idle" && !isTerminal;
8102
- const ledgerOnlyStaleReason = !isTerminal && (isIdleUnacknowledged || isNoTransition || dispatch.dispatchedToIdleSession && isIdleUnacknowledged) ? "direct task dispatch has no provider acknowledgement, transcript append, or active runtime transition" : void 0;
8103
- const isFreshUnacknowledged = Boolean(ledgerOnlyStaleReason && !live.staleReason);
8209
+ const { ledgerOnlyStaleReason, isFreshUnacknowledged } = classifyDirectDispatch({
8210
+ status,
8211
+ isTerminalRow: isTerminal,
8212
+ hasTerminalStatus: isTerminal,
8213
+ liveStatus: live.status,
8214
+ liveStaleReason: live.staleReason,
8215
+ dispatchedToIdleSession: dispatch.dispatchedToIdleSession === true
8216
+ });
8104
8217
  const { title, summary: summary2 } = summarizeMessage(dispatch.message || "");
8105
8218
  const record = {
8106
8219
  taskId: dispatch.taskId,
@@ -8143,13 +8256,16 @@ function buildMeshActiveWork(opts) {
8143
8256
  const live = sessionStatusFromNodes(opts.nodes, dispatch.nodeId, dispatch.sessionId);
8144
8257
  const status = terminalStatus || live.status || "assigned";
8145
8258
  const terminalRow = Boolean(terminal && terminal.kind !== "task_approval_needed");
8146
- const dispatchedToIdleSession = dispatch.payload?.dispatchedToIdleSession === true;
8147
- const isNoTransition = !terminalStatus && !live.status;
8148
- const isIdleUnacknowledged = status === "idle";
8149
- const ledgerOnlyStaleReason = !terminalRow && (isIdleUnacknowledged || isNoTransition || dispatchedToIdleSession && isIdleUnacknowledged) ? "direct task dispatch has no provider acknowledgement, transcript append, or active runtime transition" : void 0;
8259
+ const { ledgerOnlyStaleReason, isFreshUnacknowledged } = classifyDirectDispatch({
8260
+ status,
8261
+ isTerminalRow: terminalRow,
8262
+ hasTerminalStatus: Boolean(terminalStatus),
8263
+ liveStatus: live.status,
8264
+ liveStaleReason: live.staleReason,
8265
+ dispatchedToIdleSession: dispatch.payload?.dispatchedToIdleSession === true
8266
+ });
8150
8267
  const message = readString6(dispatch.payload?.message) || readString6(dispatch.payload?.summary) || "";
8151
8268
  const { title, summary: summary2 } = summarizeMessage(message);
8152
- const isFreshUnacknowledged = Boolean(ledgerOnlyStaleReason && !live.staleReason);
8153
8269
  const record = {
8154
8270
  taskId,
8155
8271
  source: "direct",
@@ -8191,13 +8307,16 @@ function buildMeshActiveWork(opts) {
8191
8307
  const live = sessionStatusFromNodes(opts.nodes, dispatch.nodeId, dispatch.sessionId);
8192
8308
  const status = terminalStatus || live.status || "assigned";
8193
8309
  const terminalRow = Boolean(terminal && terminal.kind !== "task_approval_needed");
8194
- const dispatchedToIdleSession = dispatch.payload?.dispatchedToIdleSession === true;
8195
- const isNoTransition = !terminalStatus && !live.status;
8196
- const isIdleUnacknowledged = status === "idle";
8197
- const ledgerOnlyStaleReason = !terminalRow && (isIdleUnacknowledged || isNoTransition || dispatchedToIdleSession && isIdleUnacknowledged) ? "direct task dispatch has no provider acknowledgement, transcript append, or active runtime transition" : void 0;
8310
+ const { ledgerOnlyStaleReason, isFreshUnacknowledged } = classifyDirectDispatch({
8311
+ status,
8312
+ isTerminalRow: terminalRow,
8313
+ hasTerminalStatus: Boolean(terminalStatus),
8314
+ liveStatus: live.status,
8315
+ liveStaleReason: live.staleReason,
8316
+ dispatchedToIdleSession: dispatch.payload?.dispatchedToIdleSession === true
8317
+ });
8198
8318
  const message = readString6(dispatch.payload?.message) || readString6(dispatch.payload?.summary) || "";
8199
8319
  const { title, summary: summary2 } = summarizeMessage(message);
8200
- const isFreshUnacknowledged = Boolean(ledgerOnlyStaleReason && !live.staleReason);
8201
8320
  const record = {
8202
8321
  taskId,
8203
8322
  source: "direct",
@@ -8348,7 +8467,7 @@ function buildCompactStaleDirectWorkSummary(staleDirectWork, opts = {}) {
8348
8467
  ...opts.note ? { note: opts.note } : {}
8349
8468
  };
8350
8469
  }
8351
- var DIRECT_DISPATCH_VIA, TERMINAL_LEDGER_KINDS, PRUNABLE_ORPHAN_STALE_REASONS;
8470
+ var DIRECT_DISPATCH_VIA, TERMINAL_LEDGER_KINDS, LEDGER_ONLY_STALE_REASON, PRUNABLE_ORPHAN_STALE_REASONS;
8352
8471
  var init_mesh_active_work = __esm({
8353
8472
  "src/mesh/mesh-active-work.ts"() {
8354
8473
  "use strict";
@@ -8357,6 +8476,7 @@ var init_mesh_active_work = __esm({
8357
8476
  init_dist();
8358
8477
  DIRECT_DISPATCH_VIA = /* @__PURE__ */ new Set(["p2p_direct", "local_direct", "mesh_send_task"]);
8359
8478
  TERMINAL_LEDGER_KINDS = /* @__PURE__ */ new Set(["task_completed", "task_failed", "task_stalled"]);
8479
+ LEDGER_ONLY_STALE_REASON = "direct task dispatch has no provider acknowledgement, transcript append, or active runtime transition";
8360
8480
  PRUNABLE_ORPHAN_STALE_REASONS = /* @__PURE__ */ new Set([
8361
8481
  "direct task node is no longer in the live mesh",
8362
8482
  "direct task session is not present in live session records",
@@ -8595,17 +8715,7 @@ var init_mesh_events_utils = __esm({
8595
8715
 
8596
8716
  // src/mesh/mesh-events-pending.ts
8597
8717
  function normalizeCoordinatorDaemonIds(coordinatorDaemonId) {
8598
- const raw = Array.isArray(coordinatorDaemonId) ? coordinatorDaemonId : coordinatorDaemonId != null ? [coordinatorDaemonId] : [];
8599
- const seen = /* @__PURE__ */ new Set();
8600
- const out = [];
8601
- for (const id of raw) {
8602
- if (typeof id !== "string") continue;
8603
- const trimmed = id.trim();
8604
- if (!trimmed || seen.has(trimmed)) continue;
8605
- seen.add(trimmed);
8606
- out.push(trimmed);
8607
- }
8608
- return out;
8718
+ return expandDaemonIdForms(coordinatorDaemonId);
8609
8719
  }
8610
8720
  function readRefineJobId2(event) {
8611
8721
  const metadata = readRecord4(event.metadataEvent) || event;
@@ -8793,6 +8903,7 @@ function queuePendingMeshCoordinatorEvent(event) {
8793
8903
  return true;
8794
8904
  }
8795
8905
  const fingerprint = buildPendingEventFingerprint(event);
8906
+ let sqliteOk = false;
8796
8907
  try {
8797
8908
  MeshRuntimeStore.getInstance().insertPendingEvent({
8798
8909
  id: (0, import_crypto7.randomUUID)(),
@@ -8803,11 +8914,17 @@ function queuePendingMeshCoordinatorEvent(event) {
8803
8914
  fingerprint: fingerprint || null,
8804
8915
  queuedAt: event.queuedAt
8805
8916
  });
8917
+ sqliteOk = true;
8806
8918
  } catch {
8807
8919
  }
8808
- const path42 = getPendingEventsPath(event.meshId, event.targetCoordinatorDaemonId);
8809
- trimPendingEventsIfNeeded(path42);
8810
- (0, import_fs10.appendFileSync)(path42, JSON.stringify(event) + "\n", "utf-8");
8920
+ try {
8921
+ const path42 = getPendingEventsPath(event.meshId, event.targetCoordinatorDaemonId);
8922
+ trimPendingEventsIfNeeded(path42);
8923
+ (0, import_fs10.appendFileSync)(path42, JSON.stringify(event) + "\n", "utf-8");
8924
+ } catch (e) {
8925
+ if (!sqliteOk) throw e;
8926
+ LOG.warn("MeshEvents", `JSONL append failed for mesh ${event.meshId}; SQLite holds the event: ${e?.message || e}`);
8927
+ }
8811
8928
  return true;
8812
8929
  } catch (e) {
8813
8930
  LOG.warn("MeshEvents", `Failed to persist pending coordinator event: ${e?.message || e}`);
@@ -8988,6 +9105,7 @@ var init_mesh_events_pending = __esm({
8988
9105
  init_mesh_ledger();
8989
9106
  init_mesh_runtime_store();
8990
9107
  init_mesh_events_utils();
9108
+ init_dist();
8991
9109
  REFINE_TERMINAL_EVENTS = /* @__PURE__ */ new Set(["refine:completed", "refine:failed"]);
8992
9110
  MAX_PENDING_EVENTS_BYTES = 100 * 1024;
8993
9111
  MAX_PENDING_EVENTS_KEEP = 50;
@@ -9206,6 +9324,12 @@ function hasUnterminalDirectDispatchLedgerEntry(meshId, sessionId) {
9206
9324
  }
9207
9325
  return false;
9208
9326
  }
9327
+ function isWeakCompletionLedgerPayload(payload) {
9328
+ if (!payload) return false;
9329
+ if (payload.evidenceLevel === "insufficient" || payload.reviewRecommended === true) return true;
9330
+ const diag = readRecord4(payload.completionDiagnostic);
9331
+ return diag?.finalAssistantPresent === false || diag?.blockReason === "missing_final_assistant";
9332
+ }
9209
9333
  function findDirectDispatchLedgerEntry(args) {
9210
9334
  const entries = readLedgerEntries(args.meshId, { tail: 500 });
9211
9335
  for (let i = entries.length - 1; i >= 0; i--) {
@@ -9242,6 +9366,7 @@ function hasTerminalLedgerAfterDispatch(args) {
9242
9366
  if (!afterDispatch) continue;
9243
9367
  }
9244
9368
  if (entry.kind !== "task_completed" && entry.kind !== "task_failed" && entry.kind !== "task_stalled") continue;
9369
+ if (entry.kind === "task_completed" && isWeakCompletionLedgerPayload(entry.payload)) continue;
9245
9370
  const terminalTaskId = readNonEmptyString2(entry.payload?.taskId);
9246
9371
  if (terminalTaskId && terminalTaskId === args.taskId) return true;
9247
9372
  if (terminalTaskId && terminalTaskId !== args.taskId) continue;
@@ -12432,12 +12557,9 @@ var init_snapshot = __esm({
12432
12557
 
12433
12558
  // src/mesh/mesh-events-coordinator.ts
12434
12559
  function resolveCoordinatorDrainDaemonIds(components) {
12435
- const ids = /* @__PURE__ */ new Set();
12436
12560
  const statusInstanceId = readNonEmptyString2(components.statusInstanceId);
12437
- if (statusInstanceId) ids.add(statusInstanceId);
12438
12561
  const machineId = readNonEmptyString2(loadConfig().machineId);
12439
- if (machineId) ids.add(machineId);
12440
- return [...ids];
12562
+ return expandDaemonIdForms([statusInstanceId, machineId]);
12441
12563
  }
12442
12564
  function getCachedMeshByWorkspace(workspace) {
12443
12565
  const now = Date.now();
@@ -12564,6 +12686,79 @@ function isDuplicateRefineTerminalEvent(meshId, eventName, metadataEvent) {
12564
12686
  recordFingerprintSeen(fingerprint);
12565
12687
  return false;
12566
12688
  }
12689
+ function isFalseIdleCompletion(metadataEvent) {
12690
+ const diag = readRecord4(metadataEvent.completionDiagnostic);
12691
+ if (!diag) return false;
12692
+ return diag.finalAssistantPresent === false || diag.blockReason === "missing_final_assistant";
12693
+ }
12694
+ function isGenuineCompletionEvidence(metadataEvent) {
12695
+ if (isFalseIdleCompletion(metadataEvent)) return false;
12696
+ return !!readWorkerResultMetadata(metadataEvent) || !!readNonEmptyString2(metadataEvent.finalSummary);
12697
+ }
12698
+ function isWeakTerminalLedgerPayload(payload) {
12699
+ if (!payload) return false;
12700
+ if (payload.evidenceLevel === "insufficient" || payload.reviewRecommended === true) return true;
12701
+ const diag = readRecord4(payload.completionDiagnostic);
12702
+ return diag?.finalAssistantPresent === false || diag?.blockReason === "missing_final_assistant";
12703
+ }
12704
+ function resolveActiveDirectDispatchTaskId(meshId, sessionId) {
12705
+ try {
12706
+ const matches = getActiveDirectDispatches(meshId).filter((d) => d.sessionId === sessionId);
12707
+ if (!matches.length) return void 0;
12708
+ return readNonEmptyString2(matches[matches.length - 1].taskId) || void 0;
12709
+ } catch {
12710
+ return void 0;
12711
+ }
12712
+ }
12713
+ function deliverTaskToSession(dispatchThunk, ctx) {
12714
+ const delivery = createSessionDelivery({
12715
+ meshId: ctx.meshId,
12716
+ nodeId: ctx.nodeId,
12717
+ sessionId: ctx.sessionId,
12718
+ providerType: ctx.providerType,
12719
+ taskId: ctx.task.id,
12720
+ kind: "task",
12721
+ message: ctx.task.message,
12722
+ status: "delivering",
12723
+ ...ctx.sourceCoordinatorSessionId ? { sourceCoordinatorSessionId: ctx.sourceCoordinatorSessionId } : {},
12724
+ ...ctx.sourceCoordinatorDaemonId ? { sourceCoordinatorDaemonId: ctx.sourceCoordinatorDaemonId } : {}
12725
+ });
12726
+ let dispatchPromise;
12727
+ try {
12728
+ dispatchPromise = Promise.resolve(dispatchThunk());
12729
+ } catch (e) {
12730
+ dispatchPromise = Promise.reject(e);
12731
+ }
12732
+ let timer;
12733
+ const guarded = Promise.race([
12734
+ dispatchPromise,
12735
+ new Promise((_, reject) => {
12736
+ timer = setTimeout(
12737
+ () => reject(new Error(`dispatch_confirm_timeout after ${DISPATCH_CONFIRM_TIMEOUT_MS}ms`)),
12738
+ DISPATCH_CONFIRM_TIMEOUT_MS
12739
+ );
12740
+ if (typeof timer?.unref === "function") timer.unref();
12741
+ })
12742
+ ]);
12743
+ guarded.then(() => {
12744
+ if (timer) clearTimeout(timer);
12745
+ updateSessionDeliveryStatus(delivery.id, "delivered");
12746
+ }).catch((e) => {
12747
+ if (timer) clearTimeout(timer);
12748
+ LOG.error("MeshQueue", `Failed to dispatch task via ${ctx.transport} to node ${ctx.nodeId}: ${e?.message}`);
12749
+ updateSessionDeliveryStatus(delivery.id, "failed", { lastError: e?.message, incrementAttempt: true });
12750
+ updateTaskStatus(ctx.meshId, ctx.task.id, "pending");
12751
+ try {
12752
+ appendLedgerEntry(ctx.meshId, {
12753
+ kind: "dispatch_failed",
12754
+ nodeId: ctx.nodeId,
12755
+ sessionId: ctx.sessionId,
12756
+ payload: { taskId: ctx.task.id, deliveryId: delivery.id, error: e?.message, retryable: true, transport: ctx.transport }
12757
+ });
12758
+ } catch {
12759
+ }
12760
+ });
12761
+ }
12567
12762
  function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType) {
12568
12763
  const mesh = getMeshWithCache(components, meshId);
12569
12764
  const node = mesh?.nodes.find((n) => readMeshNodeId(n) === nodeId);
@@ -12582,46 +12777,33 @@ function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType)
12582
12777
  if (!isLocalNode) {
12583
12778
  const localDaemonIdForDispatch = readNonEmptyString2(loadConfig().machineId) || void 0;
12584
12779
  const sourceCoordinatorSessionId = readNonEmptyString2(task.sourceCoordinatorSessionId) || void 0;
12585
- const delivery2 = createSessionDelivery({
12586
- meshId,
12587
- nodeId,
12588
- sessionId,
12589
- providerType,
12590
- taskId: task.id,
12591
- kind: "task",
12592
- message: task.message,
12593
- status: "delivering",
12594
- ...sourceCoordinatorSessionId ? { sourceCoordinatorSessionId } : {},
12595
- ...localDaemonIdForDispatch ? { sourceCoordinatorDaemonId: localDaemonIdForDispatch } : {}
12596
- });
12597
- components.dispatchMeshCommand(node.daemonId, "agent_command", {
12598
- targetSessionId: sessionId,
12599
- cliType: providerType,
12600
- action: "send_chat",
12601
- message: task.message,
12602
- meshContext: {
12780
+ const dispatchMeshCommand = components.dispatchMeshCommand;
12781
+ const remoteDaemonId = node.daemonId;
12782
+ deliverTaskToSession(
12783
+ () => dispatchMeshCommand(remoteDaemonId, "agent_command", {
12784
+ targetSessionId: sessionId,
12785
+ cliType: providerType,
12786
+ action: "send_chat",
12787
+ message: task.message,
12788
+ meshContext: {
12789
+ meshId,
12790
+ nodeId,
12791
+ taskId: task.id,
12792
+ ...localDaemonIdForDispatch ? { coordinatorDaemonId: localDaemonIdForDispatch } : {},
12793
+ ...sourceCoordinatorSessionId ? { coordinatorSessionId: sourceCoordinatorSessionId } : {}
12794
+ }
12795
+ }),
12796
+ {
12603
12797
  meshId,
12604
12798
  nodeId,
12605
- taskId: task.id,
12606
- ...localDaemonIdForDispatch ? { coordinatorDaemonId: localDaemonIdForDispatch } : {},
12607
- ...sourceCoordinatorSessionId ? { coordinatorSessionId: sourceCoordinatorSessionId } : {}
12608
- }
12609
- }).then(() => {
12610
- updateSessionDeliveryStatus(delivery2.id, "delivered");
12611
- }).catch((e) => {
12612
- LOG.error("MeshQueue", `Failed to dispatch task via P2P to remote node ${nodeId}: ${e?.message}`);
12613
- updateSessionDeliveryStatus(delivery2.id, "failed", { lastError: e?.message, incrementAttempt: true });
12614
- updateTaskStatus(meshId, task.id, "pending");
12615
- try {
12616
- appendLedgerEntry(meshId, {
12617
- kind: "dispatch_failed",
12618
- nodeId,
12619
- sessionId,
12620
- payload: { taskId: task.id, deliveryId: delivery2.id, error: e?.message, retryable: true }
12621
- });
12622
- } catch {
12799
+ sessionId,
12800
+ providerType,
12801
+ task,
12802
+ transport: "remote",
12803
+ ...sourceCoordinatorSessionId ? { sourceCoordinatorSessionId } : {},
12804
+ ...localDaemonIdForDispatch ? { sourceCoordinatorDaemonId: localDaemonIdForDispatch } : {}
12623
12805
  }
12624
- });
12806
+ );
12625
12807
  return true;
12626
12808
  }
12627
12809
  }
@@ -12643,39 +12825,24 @@ function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType)
12643
12825
  }
12644
12826
  } catch {
12645
12827
  }
12646
- const delivery = createSessionDelivery({
12647
- meshId,
12648
- nodeId,
12649
- sessionId,
12650
- providerType,
12651
- taskId: task.id,
12652
- kind: "task",
12653
- message: task.message,
12654
- status: "delivering",
12655
- ...readNonEmptyString2(task.sourceCoordinatorSessionId) ? { sourceCoordinatorSessionId: readNonEmptyString2(task.sourceCoordinatorSessionId) } : {},
12656
- ...readNonEmptyString2(loadConfig().machineId) ? { sourceCoordinatorDaemonId: readNonEmptyString2(loadConfig().machineId) } : {}
12657
- });
12658
- components.cliManager.handleCliCommand("agent_command", {
12659
- targetSessionId: sessionId,
12660
- cliType: providerType,
12661
- action: "send_chat",
12662
- message: task.message
12663
- }).then(() => {
12664
- updateSessionDeliveryStatus(delivery.id, "delivered");
12665
- }).catch((e) => {
12666
- LOG.error("MeshQueue", `Failed to dispatch task locally to node ${nodeId}: ${e?.message}`);
12667
- updateSessionDeliveryStatus(delivery.id, "failed", { lastError: e?.message, incrementAttempt: true });
12668
- updateTaskStatus(meshId, task.id, "pending");
12669
- try {
12670
- appendLedgerEntry(meshId, {
12671
- kind: "dispatch_failed",
12672
- nodeId,
12673
- sessionId,
12674
- payload: { taskId: task.id, deliveryId: delivery.id, error: e?.message, retryable: true }
12675
- });
12676
- } catch {
12828
+ deliverTaskToSession(
12829
+ () => components.cliManager.handleCliCommand("agent_command", {
12830
+ targetSessionId: sessionId,
12831
+ cliType: providerType,
12832
+ action: "send_chat",
12833
+ message: task.message
12834
+ }),
12835
+ {
12836
+ meshId,
12837
+ nodeId,
12838
+ sessionId,
12839
+ providerType,
12840
+ task,
12841
+ transport: "local",
12842
+ ...readNonEmptyString2(task.sourceCoordinatorSessionId) ? { sourceCoordinatorSessionId: readNonEmptyString2(task.sourceCoordinatorSessionId) } : {},
12843
+ ...readNonEmptyString2(loadConfig().machineId) ? { sourceCoordinatorDaemonId: readNonEmptyString2(loadConfig().machineId) } : {}
12677
12844
  }
12678
- });
12845
+ );
12679
12846
  return true;
12680
12847
  }
12681
12848
  function sweepExpiredCooldowns() {
@@ -12940,7 +13107,7 @@ async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
12940
13107
  }
12941
13108
  }
12942
13109
  const candidateNodes = Array.isArray(mesh?.nodes) ? mesh.nodes.filter((node) => {
12943
- if (task.targetNodeId && readMeshNodeId(node) !== task.targetNodeId) return false;
13110
+ if (task.targetNodeId && !meshNodeIdMatches(node, task.targetNodeId)) return false;
12944
13111
  if (task.requiredTags?.length) {
12945
13112
  const priorities = normalizeProviderPriority(node?.policy);
12946
13113
  const providerCandidates = priorities.length ? priorities : [void 0];
@@ -12951,7 +13118,12 @@ async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
12951
13118
  return true;
12952
13119
  }) : [];
12953
13120
  if (!candidateNodes.length) {
12954
- markAutoLaunch(meshId, task.id, { status: "skipped", reason: "no_node_satisfies_required_tags", nodeId: task.targetNodeId });
13121
+ const targetPinUnmatched = !!task.targetNodeId && !(Array.isArray(mesh?.nodes) && mesh.nodes.some((n) => meshNodeIdMatches(n, task.targetNodeId)));
13122
+ markAutoLaunch(meshId, task.id, {
13123
+ status: "skipped",
13124
+ reason: targetPinUnmatched ? "target_node_id_unmatched" : "no_node_satisfies_required_tags",
13125
+ nodeId: task.targetNodeId
13126
+ });
12955
13127
  continue;
12956
13128
  }
12957
13129
  const strategy = resolveSchedulingStrategy(mesh);
@@ -13408,7 +13580,8 @@ function injectMeshSystemMessage(components, args) {
13408
13580
  });
13409
13581
  if (terminal?.kind === "task_completed" && !sessionHasActiveAssignment(args.meshId, eventSessionId)) {
13410
13582
  const newDispatchAfterTerminal = hasDispatchAfterTerminal(args.meshId, eventSessionId, terminal.id);
13411
- if (!newDispatchAfterTerminal) {
13583
+ const supersedesWeakTerminal = isWeakTerminalLedgerPayload(terminal.payload) && isGenuineCompletionEvidence(args.metadataEvent);
13584
+ if (!newDispatchAfterTerminal && !supersedesWeakTerminal) {
13412
13585
  const terminalProviderSessionId = readNonEmptyString2(terminal.payload.providerSessionId);
13413
13586
  const terminalFinalSummary = readNonEmptyString2(terminal.payload.finalSummary);
13414
13587
  const eventProviderSessionId = readNonEmptyString2(args.metadataEvent.providerSessionId);
@@ -13454,24 +13627,30 @@ function injectMeshSystemMessage(components, args) {
13454
13627
  return { success: true, forwarded: 0, suppressed: true, duplicateStopped: true };
13455
13628
  }
13456
13629
  }
13457
- function markSessionTerminal(sessionId, outcome, occurredAtMs) {
13630
+ function markSessionTerminal(sessionId, outcome, occurredAtMs, opts) {
13458
13631
  const eventTaskId = readNonEmptyString2(args.metadataEvent.taskId) || void 0;
13459
13632
  const task = updateSessionTaskStatus(args.meshId, sessionId, outcome, {
13460
13633
  occurredAt: occurredAtMs != null ? new Date(occurredAtMs).toISOString() : void 0,
13461
13634
  taskId: eventTaskId
13462
13635
  });
13463
- updateDirectDispatchStatus(args.meshId, sessionId, outcome);
13636
+ const leaveDirectDispatchActive = !task && opts?.tentativeIfDirect === true;
13637
+ if (!leaveDirectDispatchActive) {
13638
+ updateDirectDispatchStatus(args.meshId, sessionId, outcome);
13639
+ }
13464
13640
  markSessionDeliveriesTerminal(args.meshId, sessionId, outcome);
13465
13641
  setImmediate(() => cleanupTerminalDirectDispatches());
13466
13642
  return task ? { id: task.id } : null;
13467
13643
  }
13468
13644
  let completedTaskForLedger = null;
13645
+ let directDispatchTaskIdForLedger;
13469
13646
  if (args.event === "agent:generating_completed") {
13470
13647
  const sessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
13471
13648
  const nodeId = readNonEmptyString2(args.nodeId) || readNonEmptyString2(args.metadataEvent.meshNodeId);
13472
13649
  const providerType = readNonEmptyString2(args.metadataEvent.providerType);
13473
13650
  if (sessionId) {
13474
- completedTaskForLedger = markSessionTerminal(sessionId, "completed", eventTimestamp);
13651
+ directDispatchTaskIdForLedger = resolveActiveDirectDispatchTaskId(args.meshId, sessionId);
13652
+ const isFalseIdle = isFalseIdleCompletion(args.metadataEvent);
13653
+ completedTaskForLedger = markSessionTerminal(sessionId, "completed", eventTimestamp, { tentativeIfDirect: isFalseIdle });
13475
13654
  if (nodeId && providerType) {
13476
13655
  runIdleMaintenanceThenAssignQueue(components, { meshId: args.meshId, nodeId, sessionId, providerType });
13477
13656
  }
@@ -13574,6 +13753,7 @@ function injectMeshSystemMessage(components, args) {
13574
13753
  }
13575
13754
  }
13576
13755
  if (sessionId) {
13756
+ directDispatchTaskIdForLedger = resolveActiveDirectDispatchTaskId(args.meshId, sessionId);
13577
13757
  completedTaskForLedger = markSessionTerminal(sessionId, "failed");
13578
13758
  }
13579
13759
  }
@@ -13603,7 +13783,10 @@ function injectMeshSystemMessage(components, args) {
13603
13783
  payload: {
13604
13784
  event: args.event,
13605
13785
  nodeLabel: args.nodeLabel,
13606
- taskId: completedTaskForLedger?.id || void 0,
13786
+ // Fix B: fall back to the direct-dispatch taskId when no work-queue row
13787
+ // matched, so the terminal entry is attributable in mesh task-stats
13788
+ // (otherwise the direct task shows status='unknown' / terminalKind=null).
13789
+ taskId: completedTaskForLedger?.id || directDispatchTaskIdForLedger || void 0,
13607
13790
  providerSessionId,
13608
13791
  finalSummary,
13609
13792
  workerResult,
@@ -13891,7 +14074,7 @@ function setupMeshEventForwarding(components) {
13891
14074
  });
13892
14075
  });
13893
14076
  }
13894
- var import_fs13, REMOTE_IDLE_SESSION_TTL_MS, meshByWorkspaceCache, MESH_WORKSPACE_CACHE_TTL_MS, IDLE_AUTO_FAST_FORWARD_THROTTLE_MS, idleAutoFastForwardLastAttempt, INTENTIONAL_CLEANUP_STOP_SUPPRESSION_MS, RECENT_COMPLETION_FINGERPRINT_TTL_MS, autoLaunchInProgress, autoLaunchCooldownUntil, AUTO_LAUNCH_COOLDOWN_MS, AUTO_LAUNCH_AWAIT_CLAIM_MS, lastAutoLaunchLedgerKey, AUTO_LAUNCH_LEDGER_DEDUP_MAX, MESH_COORDINATOR_EVENTS, EVENT_TO_LEDGER_KIND, MESH_FORCE_INJECT_EVENTS;
14077
+ var import_fs13, REMOTE_IDLE_SESSION_TTL_MS, meshByWorkspaceCache, MESH_WORKSPACE_CACHE_TTL_MS, IDLE_AUTO_FAST_FORWARD_THROTTLE_MS, idleAutoFastForwardLastAttempt, INTENTIONAL_CLEANUP_STOP_SUPPRESSION_MS, RECENT_COMPLETION_FINGERPRINT_TTL_MS, DISPATCH_CONFIRM_TIMEOUT_MS, autoLaunchInProgress, autoLaunchCooldownUntil, AUTO_LAUNCH_COOLDOWN_MS, AUTO_LAUNCH_AWAIT_CLAIM_MS, lastAutoLaunchLedgerKey, AUTO_LAUNCH_LEDGER_DEDUP_MAX, MESH_COORDINATOR_EVENTS, EVENT_TO_LEDGER_KIND, MESH_FORCE_INJECT_EVENTS;
13895
14078
  var init_mesh_events_coordinator = __esm({
13896
14079
  "src/mesh/mesh-events-coordinator.ts"() {
13897
14080
  "use strict";
@@ -13920,6 +14103,7 @@ var init_mesh_events_coordinator = __esm({
13920
14103
  idleAutoFastForwardLastAttempt = /* @__PURE__ */ new Map();
13921
14104
  INTENTIONAL_CLEANUP_STOP_SUPPRESSION_MS = 30 * 60 * 1e3;
13922
14105
  RECENT_COMPLETION_FINGERPRINT_TTL_MS = 10 * 60 * 1e3;
14106
+ DISPATCH_CONFIRM_TIMEOUT_MS = 12e4;
13923
14107
  autoLaunchInProgress = /* @__PURE__ */ new Set();
13924
14108
  autoLaunchCooldownUntil = /* @__PURE__ */ new Map();
13925
14109
  AUTO_LAUNCH_COOLDOWN_MS = 5e3;
@@ -13975,12 +14159,9 @@ function resolveReconcileIntervalMs() {
13975
14159
  return DEFAULT_RECONCILE_INTERVAL_MS;
13976
14160
  }
13977
14161
  function resolveCoordinatorDaemonIds(components) {
13978
- const ids = /* @__PURE__ */ new Set();
13979
14162
  const statusInstanceId = readNonEmptyString2(components.statusInstanceId);
13980
- if (statusInstanceId) ids.add(statusInstanceId);
13981
14163
  const machineId = readNonEmptyString2(loadConfig().machineId);
13982
- if (machineId) ids.add(machineId);
13983
- return [...ids];
14164
+ return expandDaemonIdForms([statusInstanceId, machineId]);
13984
14165
  }
13985
14166
  function daemonHostsMesh(mesh, daemonIds) {
13986
14167
  const host = mesh.meshHost;
@@ -14064,6 +14245,24 @@ function recordHeldTerminalEventsToLedger(meshId, drainDaemonIds, reason, heldFo
14064
14245
  }
14065
14246
  }
14066
14247
  }
14248
+ function recoverStrandedAssignedDispatches(meshId, store) {
14249
+ const assigned = getQueue(meshId, { status: ["assigned"] });
14250
+ if (!assigned.length) return;
14251
+ const nowMs = Date.now();
14252
+ for (const row of assigned) {
14253
+ const dispatchedAtMs = Date.parse(row.dispatchTimestamp ?? "");
14254
+ if (!Number.isFinite(dispatchedAtMs)) continue;
14255
+ if (nowMs - dispatchedAtMs < ASSIGNED_STRANDED_DEADLINE_MS) continue;
14256
+ if (store.taskHasConfirmedDelivery(meshId, row.id)) continue;
14257
+ const reclaimed = reclaimStrandedAssignedTask(meshId, row.id, {
14258
+ reason: "assigned_stranded_dispatch_unconfirmed",
14259
+ ageMs: nowMs - dispatchedAtMs
14260
+ });
14261
+ if (reclaimed) {
14262
+ LOG.warn("MeshReconcile", `Reclaimed stranded assigned task ${row.id} on mesh ${meshId} (node=${row.assignedNodeId ?? "?"} session=${row.assignedSessionId ?? "?"}, dispatched ${Math.round((nowMs - dispatchedAtMs) / 1e3)}s ago, never confirmed delivered \u2192 ${reclaimed.status})`);
14263
+ }
14264
+ }
14265
+ }
14067
14266
  async function runMeshReconcileTick(components) {
14068
14267
  const localDaemonId = readNonEmptyString2(loadConfig().machineId) || void 0;
14069
14268
  const drainDaemonIds = resolveCoordinatorDaemonIds(components);
@@ -14093,6 +14292,17 @@ async function runMeshReconcileTick(components) {
14093
14292
  }
14094
14293
  }
14095
14294
  }
14295
+ if (store) {
14296
+ for (const mesh of listMeshes()) {
14297
+ const selfIds = resolveCoordinatorSelfIds(mesh, drainDaemonIds);
14298
+ if (!daemonHostsMesh(mesh, selfIds)) continue;
14299
+ try {
14300
+ recoverStrandedAssignedDispatches(mesh.id, store);
14301
+ } catch (e) {
14302
+ LOG.warn("MeshReconcile", `Assigned-stranded watchdog failed for mesh ${mesh.id}: ${e?.message || e}`);
14303
+ }
14304
+ }
14305
+ }
14096
14306
  for (const mesh of listMeshes()) {
14097
14307
  const selfIds = resolveCoordinatorSelfIds(mesh, drainDaemonIds);
14098
14308
  if (!daemonHostsMesh(mesh, selfIds)) continue;
@@ -14480,7 +14690,7 @@ function setupMeshReconcileLoop(components) {
14480
14690
  }
14481
14691
  };
14482
14692
  }
14483
- var DEFAULT_RECONCILE_INTERVAL_MS, DEFAULT_AUTO_PRUNE_MIN_AGE_MS, heldEventLedgerRecorded, STRICT_SESSION_MATCH_TTL_MS;
14693
+ var DEFAULT_RECONCILE_INTERVAL_MS, DEFAULT_AUTO_PRUNE_MIN_AGE_MS, heldEventLedgerRecorded, ASSIGNED_STRANDED_DEADLINE_MS, STRICT_SESSION_MATCH_TTL_MS;
14484
14694
  var init_mesh_reconcile_loop = __esm({
14485
14695
  "src/mesh/mesh-reconcile-loop.ts"() {
14486
14696
  "use strict";
@@ -14493,6 +14703,7 @@ var init_mesh_reconcile_loop = __esm({
14493
14703
  init_mesh_events_coordinator();
14494
14704
  init_mesh_unresolved_forward_outbox();
14495
14705
  init_mesh_events_utils();
14706
+ init_dist();
14496
14707
  init_mesh_work_queue();
14497
14708
  init_mesh_ledger();
14498
14709
  init_mesh_active_work();
@@ -14501,6 +14712,7 @@ var init_mesh_reconcile_loop = __esm({
14501
14712
  DEFAULT_RECONCILE_INTERVAL_MS = 4e3;
14502
14713
  DEFAULT_AUTO_PRUNE_MIN_AGE_MS = 24 * 60 * 6e4;
14503
14714
  heldEventLedgerRecorded = /* @__PURE__ */ new Set();
14715
+ ASSIGNED_STRANDED_DEADLINE_MS = 5 * 6e4;
14504
14716
  STRICT_SESSION_MATCH_TTL_MS = 6e4;
14505
14717
  }
14506
14718
  });
@@ -14533,6 +14745,84 @@ var init_mesh_events = __esm({
14533
14745
  }
14534
14746
  });
14535
14747
 
14748
+ // src/providers/approval-utils.ts
14749
+ function normalizeApprovalLabel(value) {
14750
+ return String(value || "").toLowerCase().replace(/^[\s\[(<{]*\d+(?:\s*[.)\]}>:-]|\s)+/, "").replace(/[^\p{L}\p{N}]+/gu, " ").trim();
14751
+ }
14752
+ function isNegativeApprovalLabel(value) {
14753
+ const label = normalizeApprovalLabel(value);
14754
+ return /^(no|deny|reject|cancel|skip|exit|stop)\b/.test(label) || /\bwithout\b/.test(label) || /\bdo not\b/.test(label);
14755
+ }
14756
+ function hasNegativeApprovalOption(buttons) {
14757
+ return (buttons || []).some((button) => isNegativeApprovalLabel(String(button || "")));
14758
+ }
14759
+ function getApprovalPositiveHints(provider) {
14760
+ const customHints = Array.isArray(provider?.approvalPositiveHints) ? provider.approvalPositiveHints.map((hint) => normalizeApprovalLabel(String(hint || ""))).filter(Boolean) : [];
14761
+ return customHints.length > 0 ? customHints : DEFAULT_APPROVAL_POSITIVE_HINTS;
14762
+ }
14763
+ function pickApprovalButton(buttons, provider) {
14764
+ const labels = (buttons || []).map((button) => String(button || "").trim()).filter(Boolean);
14765
+ if (labels.length === 0) {
14766
+ return { index: -1, label: "" };
14767
+ }
14768
+ const normalizedButtons = labels.map((label) => normalizeApprovalLabel(label));
14769
+ const hints = getApprovalPositiveHints(provider);
14770
+ for (const hint of hints) {
14771
+ const exactIndex = normalizedButtons.findIndex((label, index) => label === hint && !isNegativeApprovalLabel(labels[index]));
14772
+ if (exactIndex >= 0) return { index: exactIndex, label: labels[exactIndex] };
14773
+ const prefixIndex = normalizedButtons.findIndex((label, index) => label.startsWith(hint) && !isNegativeApprovalLabel(labels[index]));
14774
+ if (prefixIndex >= 0) return { index: prefixIndex, label: labels[prefixIndex] };
14775
+ const includeIndex = normalizedButtons.findIndex((label, index) => label.includes(hint) && !isNegativeApprovalLabel(labels[index]));
14776
+ if (includeIndex >= 0) return { index: includeIndex, label: labels[includeIndex] };
14777
+ }
14778
+ return { index: -1, label: "" };
14779
+ }
14780
+ function pickAutoApprovalButton(buttons) {
14781
+ const labels = (buttons || []).map((button) => String(button || "").trim());
14782
+ const index = labels.findIndex(Boolean);
14783
+ return index >= 0 ? { index, label: labels[index] } : { index: -1, label: "" };
14784
+ }
14785
+ function formatAutoApprovalMessage(modalMessage, buttonLabel) {
14786
+ const lines = [`Auto-approved${buttonLabel ? `: ${buttonLabel}` : ""}`];
14787
+ const cleanMessage = String(modalMessage || "").trim();
14788
+ if (cleanMessage) lines.push(cleanMessage);
14789
+ return lines.join("\n");
14790
+ }
14791
+ function looksLikeActiveApprovalPromptText(content) {
14792
+ const text = content.trim();
14793
+ if (!text || text.length > 2e3) return false;
14794
+ const hasApprovalQuestion = /do you want to (?:proceed|allow|run|make this edit|create)/i.test(text) || /this command requires approval/i.test(text) || /quick safety check/i.test(text) || /is this a project you trust/i.test(text);
14795
+ const hasNumberedChoices = /^\s*[❯›>]?\s*1[.)]\s+(?:yes|allow|proceed|run)/im.test(text) || /^\s*1[.)]\s+yes\b/im.test(text);
14796
+ if (hasApprovalQuestion && hasNumberedChoices) return true;
14797
+ const lastLines = text.split(/\r?\n/).slice(-12).join("\n");
14798
+ const hasDontAskAgain = /yes.*don'?t ask again/i.test(lastLines) || /yes.*always allow/i.test(lastLines);
14799
+ const hasNoOption = /^\s*[❯›>]?\s*\d+[.)]\s+no\b/im.test(lastLines);
14800
+ if (hasDontAskAgain && hasNoOption) return true;
14801
+ if (/what do you want to do\?/i.test(text) && /^\s*\d+[.)]\s+\S/m.test(text)) return true;
14802
+ return false;
14803
+ }
14804
+ var DEFAULT_APPROVAL_POSITIVE_HINTS;
14805
+ var init_approval_utils = __esm({
14806
+ "src/providers/approval-utils.ts"() {
14807
+ "use strict";
14808
+ DEFAULT_APPROVAL_POSITIVE_HINTS = [
14809
+ "yes",
14810
+ "allow once",
14811
+ "approve",
14812
+ "accept",
14813
+ "continue",
14814
+ "run",
14815
+ "proceed",
14816
+ "confirm",
14817
+ "save",
14818
+ "ok",
14819
+ "trust",
14820
+ "allow",
14821
+ "always allow"
14822
+ ];
14823
+ }
14824
+ });
14825
+
14536
14826
  // src/logging/debug-config.ts
14537
14827
  function normalizeCategories(categories) {
14538
14828
  if (!Array.isArray(categories)) return [];
@@ -15519,6 +15809,27 @@ function compileSettledPromptMatchers(spec) {
15519
15809
  });
15520
15810
  return { prompt, footers };
15521
15811
  }
15812
+ function extractButtonLabels(spec, text) {
15813
+ if (!text) return [];
15814
+ const flags = spec.buttonFlags && spec.buttonFlags.includes("m") ? spec.buttonFlags : `${spec.buttonFlags ?? ""}m`;
15815
+ const buttonRe = compile2(spec.buttonPattern, flags);
15816
+ const labelGroup = Number.isInteger(spec.buttonLabelGroup) && (spec.buttonLabelGroup ?? 0) > 0 ? spec.buttonLabelGroup : 1;
15817
+ const out = [];
15818
+ for (const line of text.split("\n")) {
15819
+ buttonRe.lastIndex = 0;
15820
+ const m = buttonRe.exec(line);
15821
+ if (!m) continue;
15822
+ const captured = m[labelGroup] ?? (labelGroup === 1 && m.length > 2 ? m[m.length - 1] : void 0);
15823
+ if (captured && captured.trim()) out.push(captured.trim());
15824
+ }
15825
+ return out;
15826
+ }
15827
+ function buttonBlockApprovalCue(spec, text) {
15828
+ const labels = extractButtonLabels(spec, text);
15829
+ if (labels.length < 2) return false;
15830
+ if (pickApprovalButton(labels).index < 0) return false;
15831
+ return hasNegativeApprovalOption(labels);
15832
+ }
15522
15833
  function modalMatches(spec, input) {
15523
15834
  const text = input.screenText ?? "";
15524
15835
  const question = compile2(spec.questionPattern, spec.questionFlags ?? "i");
@@ -15527,6 +15838,7 @@ function modalMatches(spec, input) {
15527
15838
  const re = compile2(variant.regex, variant.flags ?? "i");
15528
15839
  if (re.test(text)) return true;
15529
15840
  }
15841
+ if (buttonBlockApprovalCue(spec, text)) return true;
15530
15842
  return false;
15531
15843
  }
15532
15844
  function evaluateGroup(group, spec, input, compiled) {
@@ -15581,6 +15893,7 @@ var init_detect_status = __esm({
15581
15893
  "src/providers/sdk/v1/builders/cli/detect-status.ts"() {
15582
15894
  "use strict";
15583
15895
  init_visible_region();
15896
+ init_approval_utils();
15584
15897
  DEFAULT_ORDER = ["spinner", "modal", "settled-prompt"];
15585
15898
  }
15586
15899
  });
@@ -20174,6 +20487,7 @@ __export(index_exports, {
20174
20487
  readLedgerEntries: () => readLedgerEntries,
20175
20488
  readLedgerSlice: () => readLedgerSlice,
20176
20489
  readLedgerSliceFromStore: () => readLedgerSliceFromStore,
20490
+ readMeshCompletionSummary: () => readMeshCompletionSummary,
20177
20491
  reconcileDirectDispatchCompletionFromTranscript: () => reconcileDirectDispatchCompletionFromTranscript,
20178
20492
  recordCompletionConflict: () => recordCompletionConflict,
20179
20493
  recordDebugTrace: () => recordDebugTrace,
@@ -20199,6 +20513,7 @@ __export(index_exports, {
20199
20513
  resolveMeshHostStatus: () => resolveMeshHostStatus,
20200
20514
  resolveMeshNodeAttribution: () => resolveMeshNodeAttribution,
20201
20515
  resolveMeshRefineValidationPlan: () => resolveMeshRefineValidationPlan,
20516
+ resolveMeshSurfacedSessionPreview: () => resolveMeshSurfacedSessionPreview,
20202
20517
  resolveNodeSchedulingPriority: () => resolveNodeSchedulingPriority,
20203
20518
  resolveSessionHostAppName: () => resolveSessionHostAppName,
20204
20519
  resolveSessionHostAppNameResolution: () => resolveSessionHostAppNameResolution,
@@ -22117,6 +22432,7 @@ init_mesh_active_work();
22117
22432
  init_mesh_refine_status();
22118
22433
  init_mesh_host_ownership();
22119
22434
  init_mesh_events();
22435
+ init_mesh_events_utils();
22120
22436
  init_mesh_delivery_policy();
22121
22437
 
22122
22438
  // src/mesh/p2p-relay-failure.ts
@@ -26036,76 +26352,8 @@ function validateReadChatResultPayload(raw, source = "read_chat") {
26036
26352
  return normalized;
26037
26353
  }
26038
26354
 
26039
- // src/providers/approval-utils.ts
26040
- var DEFAULT_APPROVAL_POSITIVE_HINTS = [
26041
- "yes",
26042
- "allow once",
26043
- "approve",
26044
- "accept",
26045
- "continue",
26046
- "run",
26047
- "proceed",
26048
- "confirm",
26049
- "save",
26050
- "ok",
26051
- "trust",
26052
- "allow",
26053
- "always allow"
26054
- ];
26055
- function normalizeApprovalLabel(value) {
26056
- return String(value || "").toLowerCase().replace(/^[\s\[(<{]*\d+(?:\s*[.)\]}>:-]|\s)+/, "").replace(/[^\p{L}\p{N}]+/gu, " ").trim();
26057
- }
26058
- function isNegativeApprovalLabel(value) {
26059
- const label = normalizeApprovalLabel(value);
26060
- return /^(no|deny|reject|cancel|skip|exit|stop)\b/.test(label) || /\bwithout\b/.test(label) || /\bdo not\b/.test(label);
26061
- }
26062
- function getApprovalPositiveHints(provider) {
26063
- const customHints = Array.isArray(provider?.approvalPositiveHints) ? provider.approvalPositiveHints.map((hint) => normalizeApprovalLabel(String(hint || ""))).filter(Boolean) : [];
26064
- return customHints.length > 0 ? customHints : DEFAULT_APPROVAL_POSITIVE_HINTS;
26065
- }
26066
- function pickApprovalButton(buttons, provider) {
26067
- const labels = (buttons || []).map((button) => String(button || "").trim()).filter(Boolean);
26068
- if (labels.length === 0) {
26069
- return { index: -1, label: "" };
26070
- }
26071
- const normalizedButtons = labels.map((label) => normalizeApprovalLabel(label));
26072
- const hints = getApprovalPositiveHints(provider);
26073
- for (const hint of hints) {
26074
- const exactIndex = normalizedButtons.findIndex((label, index) => label === hint && !isNegativeApprovalLabel(labels[index]));
26075
- if (exactIndex >= 0) return { index: exactIndex, label: labels[exactIndex] };
26076
- const prefixIndex = normalizedButtons.findIndex((label, index) => label.startsWith(hint) && !isNegativeApprovalLabel(labels[index]));
26077
- if (prefixIndex >= 0) return { index: prefixIndex, label: labels[prefixIndex] };
26078
- const includeIndex = normalizedButtons.findIndex((label, index) => label.includes(hint) && !isNegativeApprovalLabel(labels[index]));
26079
- if (includeIndex >= 0) return { index: includeIndex, label: labels[includeIndex] };
26080
- }
26081
- return { index: -1, label: "" };
26082
- }
26083
- function pickAutoApprovalButton(buttons) {
26084
- const labels = (buttons || []).map((button) => String(button || "").trim());
26085
- const index = labels.findIndex(Boolean);
26086
- return index >= 0 ? { index, label: labels[index] } : { index: -1, label: "" };
26087
- }
26088
- function formatAutoApprovalMessage(modalMessage, buttonLabel) {
26089
- const lines = [`Auto-approved${buttonLabel ? `: ${buttonLabel}` : ""}`];
26090
- const cleanMessage = String(modalMessage || "").trim();
26091
- if (cleanMessage) lines.push(cleanMessage);
26092
- return lines.join("\n");
26093
- }
26094
- function looksLikeActiveApprovalPromptText(content) {
26095
- const text = content.trim();
26096
- if (!text || text.length > 2e3) return false;
26097
- const hasApprovalQuestion = /do you want to (?:proceed|allow|run|make this edit|create)/i.test(text) || /this command requires approval/i.test(text) || /quick safety check/i.test(text) || /is this a project you trust/i.test(text);
26098
- const hasNumberedChoices = /^\s*[❯›>]?\s*1[.)]\s+(?:yes|allow|proceed|run)/im.test(text) || /^\s*1[.)]\s+yes\b/im.test(text);
26099
- if (hasApprovalQuestion && hasNumberedChoices) return true;
26100
- const lastLines = text.split(/\r?\n/).slice(-12).join("\n");
26101
- const hasDontAskAgain = /yes.*don'?t ask again/i.test(lastLines) || /yes.*always allow/i.test(lastLines);
26102
- const hasNoOption = /^\s*[❯›>]?\s*\d+[.)]\s+no\b/im.test(lastLines);
26103
- if (hasDontAskAgain && hasNoOption) return true;
26104
- if (/what do you want to do\?/i.test(text) && /^\s*\d+[.)]\s+\S/m.test(text)) return true;
26105
- return false;
26106
- }
26107
-
26108
26355
  // src/providers/ide-provider-instance.ts
26356
+ init_approval_utils();
26109
26357
  init_provider_patch_state();
26110
26358
  init_chat_message_normalization();
26111
26359
  init_open_panel_support();
@@ -27189,6 +27437,7 @@ var path16 = __toESM(require("path"));
27189
27437
  var import_node_crypto3 = require("crypto");
27190
27438
  init_contracts();
27191
27439
  init_provider_input_support();
27440
+ init_approval_utils();
27192
27441
  init_coordinator_registry();
27193
27442
  init_logger();
27194
27443
 
@@ -35177,6 +35426,7 @@ function createCliAdapter(provider, workingDir, cliArgs, extraEnv, transportFact
35177
35426
  // src/providers/cli-provider-instance.ts
35178
35427
  init_logger();
35179
35428
  init_control_effects();
35429
+ init_approval_utils();
35180
35430
  init_provider_patch_state();
35181
35431
 
35182
35432
  // src/providers/provider-session-id.ts
@@ -35438,6 +35688,20 @@ var CliProviderInstance = class _CliProviderInstance {
35438
35688
  * keystroke until the modal *content* has settled.
35439
35689
  */
35440
35690
  static AUTO_APPROVE_SETTLE_MS = 600;
35691
+ /**
35692
+ * Busy-side hysteresis for the settle gate. A momentary `generating` flip
35693
+ * while the SAME approval modal's button block is still on screen (its
35694
+ * question line scrolled out of the captured frame, only the buttons + a
35695
+ * residual `esc to interrupt` spinner remain) briefly reports
35696
+ * status!=waiting_approval. Without hysteresis that flip wipes the settle
35697
+ * clock, and the modal→generating→modal flap restarts the 600ms window
35698
+ * every time so auto-approve never fires. We keep the in-progress settle
35699
+ * gate warm across an inactive blip up to this bound; only once the modal
35700
+ * has genuinely stayed gone this long (a real resolution → idle) is the
35701
+ * gate cleared. Bounded so a genuinely new, later approval still re-settles
35702
+ * from scratch rather than firing on a stale timestamp.
35703
+ */
35704
+ static AUTO_APPROVE_GATE_HYSTERESIS_MS = 1500;
35441
35705
  adapter;
35442
35706
  context = null;
35443
35707
  events = [];
@@ -35459,6 +35723,10 @@ var CliProviderInstance = class _CliProviderInstance {
35459
35723
  pendingAutoApprovalSignature = "";
35460
35724
  pendingAutoApprovalSince = 0;
35461
35725
  autoApproveSettleTimer = null;
35726
+ // Wall-clock when auto-approve first observed status!=waiting_approval while
35727
+ // a settle gate was in progress. Drives AUTO_APPROVE_GATE_HYSTERESIS_MS so a
35728
+ // brief generating flip does not immediately wipe the settle clock.
35729
+ autoApproveInactiveSince = 0;
35462
35730
  controlValues = {};
35463
35731
  summaryMetadata = void 0;
35464
35732
  appliedEffectKeys = /* @__PURE__ */ new Set();
@@ -36279,14 +36547,28 @@ var CliProviderInstance = class _CliProviderInstance {
36279
36547
  const autoApproveActive = adapterStatus?.status === "waiting_approval" && this.shouldAutoApprove();
36280
36548
  if (!autoApproveActive) {
36281
36549
  this.lastAutoApprovalSignature = "";
36550
+ if (this.pendingAutoApprovalSince) {
36551
+ if (!this.autoApproveInactiveSince) this.autoApproveInactiveSince = now;
36552
+ const goneForMs = now - this.autoApproveInactiveSince;
36553
+ if (goneForMs < _CliProviderInstance.AUTO_APPROVE_GATE_HYSTERESIS_MS) {
36554
+ if (this.autoApproveSettleTimer) clearTimeout(this.autoApproveSettleTimer);
36555
+ this.autoApproveSettleTimer = setTimeout(() => {
36556
+ this.autoApproveSettleTimer = null;
36557
+ this.recheckAutoApproveSettled();
36558
+ }, _CliProviderInstance.AUTO_APPROVE_GATE_HYSTERESIS_MS - goneForMs + 20);
36559
+ return autoApproveActive;
36560
+ }
36561
+ }
36282
36562
  this.pendingAutoApprovalSignature = "";
36283
36563
  this.pendingAutoApprovalSince = 0;
36564
+ this.autoApproveInactiveSince = 0;
36284
36565
  if (this.autoApproveSettleTimer) {
36285
36566
  clearTimeout(this.autoApproveSettleTimer);
36286
36567
  this.autoApproveSettleTimer = null;
36287
36568
  }
36288
36569
  return autoApproveActive;
36289
36570
  }
36571
+ this.autoApproveInactiveSince = 0;
36290
36572
  const modal = adapterStatus.activeModal;
36291
36573
  const buttons = Array.isArray(modal?.buttons) ? modal.buttons.map((b) => String(b || "").trim()).filter(Boolean) : [];
36292
36574
  if (!modal || buttons.length === 0) {
@@ -36296,18 +36578,18 @@ var CliProviderInstance = class _CliProviderInstance {
36296
36578
  if (buttonIndex < 0) {
36297
36579
  return autoApproveActive;
36298
36580
  }
36299
- const approvalEntrySeq = typeof adapterStatus?.approvalEntrySeq === "number" ? adapterStatus.approvalEntrySeq : 0;
36300
- const signature = [
36301
- approvalEntrySeq,
36581
+ const modalSignature = [
36302
36582
  typeof modal?.message === "string" ? modal.message.trim() : "",
36303
36583
  buttons.join("|"),
36304
36584
  buttonIndex
36305
36585
  ].join("::");
36306
- if (this.autoApproveBusy && signature === this.lastAutoApprovalSignature) {
36586
+ const approvalEntrySeq = typeof adapterStatus?.approvalEntrySeq === "number" ? adapterStatus.approvalEntrySeq : 0;
36587
+ const busySignature = `${approvalEntrySeq}::${modalSignature}`;
36588
+ if (this.autoApproveBusy && busySignature === this.lastAutoApprovalSignature) {
36307
36589
  return autoApproveActive;
36308
36590
  }
36309
- if (signature !== this.pendingAutoApprovalSignature) {
36310
- this.pendingAutoApprovalSignature = signature;
36591
+ if (modalSignature !== this.pendingAutoApprovalSignature) {
36592
+ this.pendingAutoApprovalSignature = modalSignature;
36311
36593
  this.pendingAutoApprovalSince = now;
36312
36594
  }
36313
36595
  const settledForMs = now - this.pendingAutoApprovalSince;
@@ -36324,9 +36606,10 @@ var CliProviderInstance = class _CliProviderInstance {
36324
36606
  this.autoApproveSettleTimer = null;
36325
36607
  }
36326
36608
  this.autoApproveBusy = true;
36327
- this.lastAutoApprovalSignature = signature;
36609
+ this.lastAutoApprovalSignature = busySignature;
36328
36610
  this.pendingAutoApprovalSignature = "";
36329
36611
  this.pendingAutoApprovalSince = 0;
36612
+ this.autoApproveInactiveSince = 0;
36330
36613
  if (this.autoApproveBusyTimer) clearTimeout(this.autoApproveBusyTimer);
36331
36614
  this.autoApproveBusyTimer = setTimeout(() => {
36332
36615
  this.autoApproveBusy = false;
@@ -43213,7 +43496,8 @@ init_logger();
43213
43496
  var fs23 = __toESM(require("fs"));
43214
43497
  var path35 = __toESM(require("path"));
43215
43498
  var os26 = __toESM(require("os"));
43216
- var LOG_DIR2 = process.platform === "win32" ? path35.join(process.env.LOCALAPPDATA || process.env.APPDATA || path35.join(os26.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path35.join(os26.homedir(), "Library", "Logs", "adhdev") : path35.join(os26.homedir(), ".local", "share", "adhdev", "logs");
43499
+ var ADHDEV_HOME2 = process.env.ADHDEV_CONFIG_DIR && process.env.ADHDEV_CONFIG_DIR.trim() ? process.env.ADHDEV_CONFIG_DIR.trim() : path35.join(os26.homedir(), ".adhdev");
43500
+ var LOG_DIR2 = path35.join(ADHDEV_HOME2, "logs");
43217
43501
  var MAX_FILE_SIZE = 5 * 1024 * 1024;
43218
43502
  var MAX_DAYS = 7;
43219
43503
  try {
@@ -43673,7 +43957,7 @@ function runGit2(repoRoot, args) {
43673
43957
  return "";
43674
43958
  }
43675
43959
  }
43676
- function readRecord6(repoRoot) {
43960
+ function readRecord5(repoRoot) {
43677
43961
  const path42 = (0, import_node_path2.resolve)(repoRoot, PREVIEW_DEPLOY_RECORD);
43678
43962
  if (!(0, import_node_fs4.existsSync)(path42)) return null;
43679
43963
  try {
@@ -43713,7 +43997,7 @@ function readCurrentMainCommit(repoRoot) {
43713
43997
  }
43714
43998
  function buildPreviewFreshness(repoRoot) {
43715
43999
  const current = readCurrentMainCommit(repoRoot);
43716
- const record = readRecord6(repoRoot);
44000
+ const record = readRecord5(repoRoot);
43717
44001
  const lastPreviewCommit = normalizeCommit(record?.lastPreviewCommit);
43718
44002
  const targets = readTargetFreshness(record, current.currentMainCommit);
43719
44003
  let status = "unknown";
@@ -44068,13 +44352,14 @@ async function waitForPidExit(pid, timeoutMs) {
44068
44352
  }
44069
44353
  }
44070
44354
  }
44071
- function stopSessionHostProcesses(appName) {
44355
+ async function stopSessionHostProcesses(appName) {
44072
44356
  const pidFile = path36.join(os27.homedir(), ".adhdev", `${appName}-session-host.pid`);
44357
+ let killedPid = null;
44073
44358
  try {
44074
44359
  if (fs25.existsSync(pidFile)) {
44075
44360
  const pid = Number.parseInt(fs25.readFileSync(pidFile, "utf8").trim(), 10);
44076
44361
  if (Number.isFinite(pid) && pid !== process.pid && isManagedSessionHostPid(pid)) {
44077
- killPid(pid);
44362
+ if (killPid(pid)) killedPid = pid;
44078
44363
  }
44079
44364
  }
44080
44365
  } catch {
@@ -44084,6 +44369,15 @@ function stopSessionHostProcesses(appName) {
44084
44369
  } catch {
44085
44370
  }
44086
44371
  }
44372
+ if (killedPid !== null) {
44373
+ await waitForPidExit(killedPid, 15e3);
44374
+ }
44375
+ }
44376
+ function isRetriableInstallLockError(error) {
44377
+ const code = error?.code;
44378
+ if (code === "EBUSY" || code === "EPERM") return true;
44379
+ const text = `${error?.message || ""} ${error?.stderr || ""}`;
44380
+ return /\bEBUSY\b|\bEPERM\b|resource busy or locked/i.test(text);
44087
44381
  }
44088
44382
  function removeDaemonPidFile() {
44089
44383
  const pidFile = path36.join(os27.homedir(), ".adhdev", "daemon.pid");
@@ -44163,22 +44457,37 @@ async function runDaemonUpgradeHelper(payload) {
44163
44457
  appendUpgradeLog(`Waiting for parent pid ${payload.parentPid} to exit`);
44164
44458
  await waitForPidExit(payload.parentPid, 15e3);
44165
44459
  }
44166
- stopSessionHostProcesses(sessionHostAppName);
44460
+ await stopSessionHostProcesses(sessionHostAppName);
44167
44461
  removeDaemonPidFile();
44168
44462
  cleanupStaleGlobalInstallDirs(payload.packageName, installCommand.surface);
44169
44463
  const spec = `${payload.packageName}@${payload.targetVersion || "latest"}`;
44170
44464
  appendUpgradeLog(`Installing ${spec}`);
44171
- const installOutput = (0, import_child_process8.execFileSync)(
44172
- installCommand.command,
44173
- installCommand.args,
44174
- {
44175
- encoding: "utf8",
44176
- stdio: "pipe",
44177
- maxBuffer: 20 * 1024 * 1024,
44178
- env: buildInstallEnvWithNodeOnPath(),
44179
- ...installCommand.execOptions
44465
+ const maxInstallAttempts = process.platform === "win32" ? 3 : 1;
44466
+ let installOutput = "";
44467
+ for (let attempt = 1; attempt <= maxInstallAttempts; attempt++) {
44468
+ try {
44469
+ installOutput = String((0, import_child_process8.execFileSync)(
44470
+ installCommand.command,
44471
+ installCommand.args,
44472
+ {
44473
+ encoding: "utf8",
44474
+ stdio: "pipe",
44475
+ maxBuffer: 20 * 1024 * 1024,
44476
+ env: buildInstallEnvWithNodeOnPath(),
44477
+ ...installCommand.execOptions
44478
+ }
44479
+ ));
44480
+ break;
44481
+ } catch (error) {
44482
+ if (attempt < maxInstallAttempts && isRetriableInstallLockError(error)) {
44483
+ appendUpgradeLog(`Install attempt ${attempt} hit a file lock (${error?.code || "lock"}); cleaning staging and retrying after backoff`);
44484
+ cleanupStaleGlobalInstallDirs(payload.packageName, installCommand.surface);
44485
+ await new Promise((resolve24) => setTimeout(resolve24, attempt * 1500));
44486
+ continue;
44487
+ }
44488
+ throw error;
44180
44489
  }
44181
- );
44490
+ }
44182
44491
  if (installOutput.trim()) {
44183
44492
  appendUpgradeLog(installOutput.trim());
44184
44493
  }
@@ -52940,6 +53249,7 @@ var DaemonAgentStreamManager = class {
52940
53249
 
52941
53250
  // src/agent-stream/poller.ts
52942
53251
  init_logger();
53252
+ init_approval_utils();
52943
53253
  init_chat_message_normalization();
52944
53254
  var AgentStreamPoller = class {
52945
53255
  deps;
@@ -60635,6 +60945,7 @@ var V1_CONTRACT_VERSION = "1.0.0";
60635
60945
  readLedgerEntries,
60636
60946
  readLedgerSlice,
60637
60947
  readLedgerSliceFromStore,
60948
+ readMeshCompletionSummary,
60638
60949
  reconcileDirectDispatchCompletionFromTranscript,
60639
60950
  recordCompletionConflict,
60640
60951
  recordDebugTrace,
@@ -60660,6 +60971,7 @@ var V1_CONTRACT_VERSION = "1.0.0";
60660
60971
  resolveMeshHostStatus,
60661
60972
  resolveMeshNodeAttribution,
60662
60973
  resolveMeshRefineValidationPlan,
60974
+ resolveMeshSurfacedSessionPreview,
60663
60975
  resolveNodeSchedulingPriority,
60664
60976
  resolveSessionHostAppName,
60665
60977
  resolveSessionHostAppNameResolution,