@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.mjs CHANGED
@@ -311,10 +311,10 @@ function readInjected(value) {
311
311
  }
312
312
  function getDaemonBuildInfo() {
313
313
  if (cached) return cached;
314
- const commit = readInjected(true ? "f066449c7e758daf63ad40d431a5e97fc8d79a0e" : void 0) ?? "unknown";
315
- const commitShort = readInjected(true ? "f066449c" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
316
- const version = readInjected(true ? "0.9.82-rc.350" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
317
- const builtAt = readInjected(true ? "2026-06-21T19:33:17.868Z" : void 0);
314
+ const commit = readInjected(true ? "ca5f944b7763a621357fc28a9f62ac398b0ced6c" : void 0) ?? "unknown";
315
+ const commitShort = readInjected(true ? "ca5f944b" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
316
+ const version = readInjected(true ? "0.9.82-rc.352" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
317
+ const builtAt = readInjected(true ? "2026-06-22T07:17:05.715Z" : void 0);
318
318
  cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
319
319
  return cached;
320
320
  }
@@ -3193,7 +3193,7 @@ function installGlobalInterceptor() {
3193
3193
  function getLogPath() {
3194
3194
  return currentLogFile;
3195
3195
  }
3196
- var 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;
3196
+ var 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;
3197
3197
  var init_logger = __esm({
3198
3198
  "src/logging/logger.ts"() {
3199
3199
  "use strict";
@@ -3201,7 +3201,8 @@ var init_logger = __esm({
3201
3201
  LEVEL_NUM = { debug: 0, info: 1, warn: 2, error: 3 };
3202
3202
  LEVEL_LABEL = { debug: "DBG", info: "INF", warn: "WRN", error: "ERR" };
3203
3203
  currentLevel = "info";
3204
- 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");
3204
+ ADHDEV_HOME = process.env.ADHDEV_CONFIG_DIR && process.env.ADHDEV_CONFIG_DIR.trim() ? process.env.ADHDEV_CONFIG_DIR.trim() : path9.join(os3.homedir(), ".adhdev");
3205
+ LOG_DIR = path9.join(ADHDEV_HOME, "logs");
3205
3206
  MAX_LOG_SIZE = 5 * 1024 * 1024;
3206
3207
  MAX_LOG_DAYS = 7;
3207
3208
  try {
@@ -4001,6 +4002,7 @@ __export(mesh_work_queue_exports, {
4001
4002
  nodeSatisfiesRequiredTags: () => nodeSatisfiesRequiredTags,
4002
4003
  normalizeMeshCapabilityTags: () => normalizeMeshCapabilityTags,
4003
4004
  normalizeMeshTaskMode: () => normalizeMeshTaskMode,
4005
+ reclaimStrandedAssignedTask: () => reclaimStrandedAssignedTask,
4004
4006
  recordDirectDispatchTask: () => recordDirectDispatchTask,
4005
4007
  recordMeshToolCall: () => recordMeshToolCall,
4006
4008
  recordTaskAutoLaunch: () => recordTaskAutoLaunch,
@@ -4437,6 +4439,52 @@ function requeueTask(meshId, taskId, opts) {
4437
4439
  return entry;
4438
4440
  });
4439
4441
  }
4442
+ function reclaimStrandedAssignedTask(meshId, taskId, opts) {
4443
+ requireMeshHostQueueOwner(opts);
4444
+ return withQueueLock(meshId, () => {
4445
+ const entry = MeshRuntimeStore.getInstance().findQueueEntryById(meshId, taskId);
4446
+ if (!entry) return null;
4447
+ if (entry.status !== "assigned") return null;
4448
+ const now = (/* @__PURE__ */ new Date()).toISOString();
4449
+ const reason = opts?.reason || "assigned_stranded_dispatch_unconfirmed";
4450
+ const reclaims = (entry.strandedReclaimCount || 0) + 1;
4451
+ const prevNode = entry.assignedNodeId;
4452
+ const prevSession = entry.assignedSessionId;
4453
+ delete entry.assignedNodeId;
4454
+ delete entry.assignedSessionId;
4455
+ delete entry.assignedProviderType;
4456
+ delete entry.dispatchTimestamp;
4457
+ entry.strandedReclaimCount = reclaims;
4458
+ entry.updatedAt = now;
4459
+ if (reclaims > MAX_STRANDED_RECLAIMS) {
4460
+ entry.status = "failed";
4461
+ entry.cancelReason = `stranded_dispatch_unrecovered: reclaimed ${reclaims - 1} time(s) without a confirmed dispatch`;
4462
+ MeshRuntimeStore.getInstance().updateQueueEntry(entry);
4463
+ propagateDependencyFailure(meshId, taskId);
4464
+ } else {
4465
+ entry.status = "pending";
4466
+ entry.requeuedAt = now;
4467
+ entry.requeueReason = reason;
4468
+ MeshRuntimeStore.getInstance().updateQueueEntry(entry);
4469
+ }
4470
+ try {
4471
+ appendLedgerEntry(meshId, {
4472
+ kind: "task_reclaimed",
4473
+ nodeId: prevNode,
4474
+ sessionId: prevSession,
4475
+ payload: {
4476
+ taskId,
4477
+ reason,
4478
+ ...typeof opts?.ageMs === "number" ? { ageMs: opts.ageMs } : {},
4479
+ reclaimCount: reclaims,
4480
+ outcome: entry.status
4481
+ }
4482
+ });
4483
+ } catch {
4484
+ }
4485
+ return entry;
4486
+ });
4487
+ }
4440
4488
  function updateSessionTaskStatus(meshId, sessionId, status, opts) {
4441
4489
  return withQueueLock(meshId, () => {
4442
4490
  const store = MeshRuntimeStore.getInstance();
@@ -4550,7 +4598,7 @@ function recordMeshToolCall(opts) {
4550
4598
  return { rateLimitExceeded: false, callsInWindow: 0, advisory: null };
4551
4599
  }
4552
4600
  }
4553
- var 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;
4601
+ var 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;
4554
4602
  var init_mesh_work_queue = __esm({
4555
4603
  "src/mesh/mesh-work-queue.ts"() {
4556
4604
  "use strict";
@@ -4559,6 +4607,7 @@ var init_mesh_work_queue = __esm({
4559
4607
  init_mesh_runtime_store();
4560
4608
  init_mesh_config();
4561
4609
  init_logger();
4610
+ init_mesh_ledger();
4562
4611
  ACTIVE_MESH_QUEUE_STATUSES = ["pending", "assigned"];
4563
4612
  HISTORICAL_MESH_QUEUE_STATUSES = ["completed", "failed", "cancelled"];
4564
4613
  MESH_TASK_MODES = ["code_change", "validation", "live_debug_readonly", "launch_app", "convergence"];
@@ -4611,6 +4660,7 @@ var init_mesh_work_queue = __esm({
4611
4660
  ]);
4612
4661
  GIT_STASH_READONLY_SUBCOMMANDS = /* @__PURE__ */ new Set(["list", "show"]);
4613
4662
  DEPENDENCY_FAILURE_TERMINALS = /* @__PURE__ */ new Set(["failed", "cancelled"]);
4663
+ MAX_STRANDED_RECLAIMS = 3;
4614
4664
  }
4615
4665
  });
4616
4666
 
@@ -4670,6 +4720,10 @@ var init_mesh_runtime_store = __esm({
4670
4720
  migratedMeshIds = /* @__PURE__ */ new Set();
4671
4721
  fingerprintSweepCounter = 0;
4672
4722
  walWriteCounter = 0;
4723
+ // Independent cadence for the tool-call-log sweep. Must NOT share walWriteCounter:
4724
+ // sharing makes each store's threshold drift by the other's write volume (WAL
4725
+ // checkpoint at 500 vs tool-log sweep at 200 would interfere arbitrarily).
4726
+ toolCallLogCounter = 0;
4673
4727
  static WAL_CHECK_INTERVAL = 500;
4674
4728
  static WAL_MAX_BYTES = 50 * 1024 * 1024;
4675
4729
  // 50 MB
@@ -5492,6 +5546,22 @@ var init_mesh_runtime_store = __esm({
5492
5546
  updatedAt: r.updated_at
5493
5547
  }));
5494
5548
  }
5549
+ /**
5550
+ * Bug B watchdog support: true when at least one delivery record for the task has
5551
+ * reached a confirmed-handed-off status (delivered / acked / completed). The
5552
+ * assigned-stranded watchdog uses this to distinguish a dispatch that was never
5553
+ * confirmed (reclaimable) from one that WAS handed to the worker (a genuinely
5554
+ * in-flight or completion-lost task, which is PHASE 4's responsibility, not this
5555
+ * watchdog's). Indexed by (mesh_id, task_id).
5556
+ */
5557
+ taskHasConfirmedDelivery(meshId, taskId) {
5558
+ const row = this.db.prepare(`
5559
+ SELECT 1 FROM mesh_session_delivery
5560
+ WHERE mesh_id = ? AND task_id = ? AND status IN ('delivered','acked','completed')
5561
+ LIMIT 1
5562
+ `).get(meshId, taskId);
5563
+ return !!row;
5564
+ }
5495
5565
  expireStaleSessionDeliveries(meshId) {
5496
5566
  const now = (/* @__PURE__ */ new Date()).toISOString();
5497
5567
  this.db.prepare(`
@@ -5563,7 +5633,7 @@ var init_mesh_runtime_store = __esm({
5563
5633
  "SELECT COUNT(*) as cnt FROM mesh_tool_call_log WHERE mesh_id = ? AND tool = ? AND called_at >= ?"
5564
5634
  ).get(meshId, tool, windowStart);
5565
5635
  const callsInWindow = row?.cnt ?? 0;
5566
- if (++this.walWriteCounter % 200 === 0) {
5636
+ if (++this.toolCallLogCounter % 200 === 0) {
5567
5637
  this.db.prepare(
5568
5638
  "DELETE FROM mesh_tool_call_log WHERE called_at < ?"
5569
5639
  ).run(now - Math.max(windowMs * 10, 6e4));
@@ -6018,9 +6088,9 @@ function computeMeshTaskStats(meshId, opts) {
6018
6088
  }
6019
6089
  return targetIds.map((taskId) => {
6020
6090
  const queueEntry = queueById.get(taskId);
6021
- const status = queueEntry?.status ?? "unknown";
6022
6091
  const dispatch = dispatches.get(taskId);
6023
6092
  const terminal = terminals.get(taskId);
6093
+ const status = queueEntry?.status ?? (terminal ? terminal.kind === "task_completed" ? "completed" : "failed" : "unknown");
6024
6094
  const isTerminalStatus = status === "completed" || status === "failed" || status === "cancelled";
6025
6095
  const dispatchTime = parseTime(dispatch?.first ?? queueEntry?.dispatchTimestamp);
6026
6096
  const terminalTime = parseTime(terminal?.at);
@@ -7915,6 +7985,35 @@ function meshNodeIdMatches(node, candidateId) {
7915
7985
  if (!trimmed) return false;
7916
7986
  return normalizeMeshNodeId(node) === trimmed;
7917
7987
  }
7988
+ function machineCoreFromDaemonId(id) {
7989
+ const trimmed = readString5(id);
7990
+ if (!trimmed) return void 0;
7991
+ for (const prefix of DAEMON_ID_PREFIXES) {
7992
+ if (trimmed.startsWith(prefix)) {
7993
+ const core = trimmed.slice(prefix.length).trim();
7994
+ return core || void 0;
7995
+ }
7996
+ }
7997
+ return trimmed;
7998
+ }
7999
+ function expandDaemonIdForms(ids) {
8000
+ const list = Array.isArray(ids) ? ids : ids != null ? [ids] : [];
8001
+ const out = [];
8002
+ const seen = /* @__PURE__ */ new Set();
8003
+ const add = (value) => {
8004
+ if (!value || seen.has(value)) return;
8005
+ seen.add(value);
8006
+ out.push(value);
8007
+ };
8008
+ for (const raw of list) add(readString5(raw));
8009
+ for (const raw of list) {
8010
+ const core = machineCoreFromDaemonId(readString5(raw));
8011
+ if (!core || !core.startsWith("mach_")) continue;
8012
+ add(core);
8013
+ for (const prefix of DAEMON_ID_PREFIXES) add(`${prefix}${core}`);
8014
+ }
8015
+ return out;
8016
+ }
7918
8017
  function summarizeGitShape(status) {
7919
8018
  const record = readRecord3(status);
7920
8019
  if (!Object.keys(record).length) return null;
@@ -7949,9 +8048,11 @@ function summarizeGitShape(status) {
7949
8048
  submodules
7950
8049
  };
7951
8050
  }
8051
+ var DAEMON_ID_PREFIXES;
7952
8052
  var init_dist = __esm({
7953
8053
  "../mesh-shared/dist/index.mjs"() {
7954
8054
  "use strict";
8055
+ DAEMON_ID_PREFIXES = ["daemon_", "standalone_"];
7955
8056
  }
7956
8057
  });
7957
8058
 
@@ -8029,6 +8130,14 @@ function statusFromTerminal(entry) {
8029
8130
  if (entry.kind === "task_completed") return "idle";
8030
8131
  return "failed";
8031
8132
  }
8133
+ function classifyDirectDispatch(params) {
8134
+ const { status, isTerminalRow, hasTerminalStatus, liveStatus, liveStaleReason, dispatchedToIdleSession } = params;
8135
+ const isNoTransition = !hasTerminalStatus && !liveStatus;
8136
+ const isIdleUnacknowledged = status === "idle";
8137
+ const ledgerOnlyStaleReason = !isTerminalRow && (isIdleUnacknowledged || isNoTransition || dispatchedToIdleSession && isIdleUnacknowledged) ? LEDGER_ONLY_STALE_REASON : void 0;
8138
+ const isFreshUnacknowledged = Boolean(ledgerOnlyStaleReason && !liveStaleReason);
8139
+ return { ledgerOnlyStaleReason, isFreshUnacknowledged };
8140
+ }
8032
8141
  function buildMeshActiveWorkSummary(activeWork) {
8033
8142
  const statusCounts = {
8034
8143
  pending: 0,
@@ -8091,10 +8200,14 @@ function buildMeshActiveWork(opts) {
8091
8200
  const dbStatus = dispatch.status;
8092
8201
  const isTerminal = dbStatus === "completed" || dbStatus === "failed" || dbStatus === "stale";
8093
8202
  const status = isTerminal ? dbStatus === "completed" ? "idle" : "failed" : live.status || (dbStatus === "acked" ? "generating" : "assigned");
8094
- const isNoTransition = !isTerminal && !live.status;
8095
- const isIdleUnacknowledged = status === "idle" && !isTerminal;
8096
- const ledgerOnlyStaleReason = !isTerminal && (isIdleUnacknowledged || isNoTransition || dispatch.dispatchedToIdleSession && isIdleUnacknowledged) ? "direct task dispatch has no provider acknowledgement, transcript append, or active runtime transition" : void 0;
8097
- const isFreshUnacknowledged = Boolean(ledgerOnlyStaleReason && !live.staleReason);
8203
+ const { ledgerOnlyStaleReason, isFreshUnacknowledged } = classifyDirectDispatch({
8204
+ status,
8205
+ isTerminalRow: isTerminal,
8206
+ hasTerminalStatus: isTerminal,
8207
+ liveStatus: live.status,
8208
+ liveStaleReason: live.staleReason,
8209
+ dispatchedToIdleSession: dispatch.dispatchedToIdleSession === true
8210
+ });
8098
8211
  const { title, summary: summary2 } = summarizeMessage(dispatch.message || "");
8099
8212
  const record = {
8100
8213
  taskId: dispatch.taskId,
@@ -8137,13 +8250,16 @@ function buildMeshActiveWork(opts) {
8137
8250
  const live = sessionStatusFromNodes(opts.nodes, dispatch.nodeId, dispatch.sessionId);
8138
8251
  const status = terminalStatus || live.status || "assigned";
8139
8252
  const terminalRow = Boolean(terminal && terminal.kind !== "task_approval_needed");
8140
- const dispatchedToIdleSession = dispatch.payload?.dispatchedToIdleSession === true;
8141
- const isNoTransition = !terminalStatus && !live.status;
8142
- const isIdleUnacknowledged = status === "idle";
8143
- const ledgerOnlyStaleReason = !terminalRow && (isIdleUnacknowledged || isNoTransition || dispatchedToIdleSession && isIdleUnacknowledged) ? "direct task dispatch has no provider acknowledgement, transcript append, or active runtime transition" : void 0;
8253
+ const { ledgerOnlyStaleReason, isFreshUnacknowledged } = classifyDirectDispatch({
8254
+ status,
8255
+ isTerminalRow: terminalRow,
8256
+ hasTerminalStatus: Boolean(terminalStatus),
8257
+ liveStatus: live.status,
8258
+ liveStaleReason: live.staleReason,
8259
+ dispatchedToIdleSession: dispatch.payload?.dispatchedToIdleSession === true
8260
+ });
8144
8261
  const message = readString6(dispatch.payload?.message) || readString6(dispatch.payload?.summary) || "";
8145
8262
  const { title, summary: summary2 } = summarizeMessage(message);
8146
- const isFreshUnacknowledged = Boolean(ledgerOnlyStaleReason && !live.staleReason);
8147
8263
  const record = {
8148
8264
  taskId,
8149
8265
  source: "direct",
@@ -8185,13 +8301,16 @@ function buildMeshActiveWork(opts) {
8185
8301
  const live = sessionStatusFromNodes(opts.nodes, dispatch.nodeId, dispatch.sessionId);
8186
8302
  const status = terminalStatus || live.status || "assigned";
8187
8303
  const terminalRow = Boolean(terminal && terminal.kind !== "task_approval_needed");
8188
- const dispatchedToIdleSession = dispatch.payload?.dispatchedToIdleSession === true;
8189
- const isNoTransition = !terminalStatus && !live.status;
8190
- const isIdleUnacknowledged = status === "idle";
8191
- const ledgerOnlyStaleReason = !terminalRow && (isIdleUnacknowledged || isNoTransition || dispatchedToIdleSession && isIdleUnacknowledged) ? "direct task dispatch has no provider acknowledgement, transcript append, or active runtime transition" : void 0;
8304
+ const { ledgerOnlyStaleReason, isFreshUnacknowledged } = classifyDirectDispatch({
8305
+ status,
8306
+ isTerminalRow: terminalRow,
8307
+ hasTerminalStatus: Boolean(terminalStatus),
8308
+ liveStatus: live.status,
8309
+ liveStaleReason: live.staleReason,
8310
+ dispatchedToIdleSession: dispatch.payload?.dispatchedToIdleSession === true
8311
+ });
8192
8312
  const message = readString6(dispatch.payload?.message) || readString6(dispatch.payload?.summary) || "";
8193
8313
  const { title, summary: summary2 } = summarizeMessage(message);
8194
- const isFreshUnacknowledged = Boolean(ledgerOnlyStaleReason && !live.staleReason);
8195
8314
  const record = {
8196
8315
  taskId,
8197
8316
  source: "direct",
@@ -8342,7 +8461,7 @@ function buildCompactStaleDirectWorkSummary(staleDirectWork, opts = {}) {
8342
8461
  ...opts.note ? { note: opts.note } : {}
8343
8462
  };
8344
8463
  }
8345
- var DIRECT_DISPATCH_VIA, TERMINAL_LEDGER_KINDS, PRUNABLE_ORPHAN_STALE_REASONS;
8464
+ var DIRECT_DISPATCH_VIA, TERMINAL_LEDGER_KINDS, LEDGER_ONLY_STALE_REASON, PRUNABLE_ORPHAN_STALE_REASONS;
8346
8465
  var init_mesh_active_work = __esm({
8347
8466
  "src/mesh/mesh-active-work.ts"() {
8348
8467
  "use strict";
@@ -8351,6 +8470,7 @@ var init_mesh_active_work = __esm({
8351
8470
  init_dist();
8352
8471
  DIRECT_DISPATCH_VIA = /* @__PURE__ */ new Set(["p2p_direct", "local_direct", "mesh_send_task"]);
8353
8472
  TERMINAL_LEDGER_KINDS = /* @__PURE__ */ new Set(["task_completed", "task_failed", "task_stalled"]);
8473
+ LEDGER_ONLY_STALE_REASON = "direct task dispatch has no provider acknowledgement, transcript append, or active runtime transition";
8354
8474
  PRUNABLE_ORPHAN_STALE_REASONS = /* @__PURE__ */ new Set([
8355
8475
  "direct task node is no longer in the live mesh",
8356
8476
  "direct task session is not present in live session records",
@@ -8592,17 +8712,7 @@ import { appendFileSync as appendFileSync2, existsSync as existsSync14, readFile
8592
8712
  import { join as join15 } from "path";
8593
8713
  import { randomUUID as randomUUID7 } from "crypto";
8594
8714
  function normalizeCoordinatorDaemonIds(coordinatorDaemonId) {
8595
- const raw = Array.isArray(coordinatorDaemonId) ? coordinatorDaemonId : coordinatorDaemonId != null ? [coordinatorDaemonId] : [];
8596
- const seen = /* @__PURE__ */ new Set();
8597
- const out = [];
8598
- for (const id of raw) {
8599
- if (typeof id !== "string") continue;
8600
- const trimmed = id.trim();
8601
- if (!trimmed || seen.has(trimmed)) continue;
8602
- seen.add(trimmed);
8603
- out.push(trimmed);
8604
- }
8605
- return out;
8715
+ return expandDaemonIdForms(coordinatorDaemonId);
8606
8716
  }
8607
8717
  function readRefineJobId2(event) {
8608
8718
  const metadata = readRecord4(event.metadataEvent) || event;
@@ -8790,6 +8900,7 @@ function queuePendingMeshCoordinatorEvent(event) {
8790
8900
  return true;
8791
8901
  }
8792
8902
  const fingerprint = buildPendingEventFingerprint(event);
8903
+ let sqliteOk = false;
8793
8904
  try {
8794
8905
  MeshRuntimeStore.getInstance().insertPendingEvent({
8795
8906
  id: randomUUID7(),
@@ -8800,11 +8911,17 @@ function queuePendingMeshCoordinatorEvent(event) {
8800
8911
  fingerprint: fingerprint || null,
8801
8912
  queuedAt: event.queuedAt
8802
8913
  });
8914
+ sqliteOk = true;
8803
8915
  } catch {
8804
8916
  }
8805
- const path42 = getPendingEventsPath(event.meshId, event.targetCoordinatorDaemonId);
8806
- trimPendingEventsIfNeeded(path42);
8807
- appendFileSync2(path42, JSON.stringify(event) + "\n", "utf-8");
8917
+ try {
8918
+ const path42 = getPendingEventsPath(event.meshId, event.targetCoordinatorDaemonId);
8919
+ trimPendingEventsIfNeeded(path42);
8920
+ appendFileSync2(path42, JSON.stringify(event) + "\n", "utf-8");
8921
+ } catch (e) {
8922
+ if (!sqliteOk) throw e;
8923
+ LOG.warn("MeshEvents", `JSONL append failed for mesh ${event.meshId}; SQLite holds the event: ${e?.message || e}`);
8924
+ }
8808
8925
  return true;
8809
8926
  } catch (e) {
8810
8927
  LOG.warn("MeshEvents", `Failed to persist pending coordinator event: ${e?.message || e}`);
@@ -8982,6 +9099,7 @@ var init_mesh_events_pending = __esm({
8982
9099
  init_mesh_ledger();
8983
9100
  init_mesh_runtime_store();
8984
9101
  init_mesh_events_utils();
9102
+ init_dist();
8985
9103
  REFINE_TERMINAL_EVENTS = /* @__PURE__ */ new Set(["refine:completed", "refine:failed"]);
8986
9104
  MAX_PENDING_EVENTS_BYTES = 100 * 1024;
8987
9105
  MAX_PENDING_EVENTS_KEEP = 50;
@@ -9200,6 +9318,12 @@ function hasUnterminalDirectDispatchLedgerEntry(meshId, sessionId) {
9200
9318
  }
9201
9319
  return false;
9202
9320
  }
9321
+ function isWeakCompletionLedgerPayload(payload) {
9322
+ if (!payload) return false;
9323
+ if (payload.evidenceLevel === "insufficient" || payload.reviewRecommended === true) return true;
9324
+ const diag = readRecord4(payload.completionDiagnostic);
9325
+ return diag?.finalAssistantPresent === false || diag?.blockReason === "missing_final_assistant";
9326
+ }
9203
9327
  function findDirectDispatchLedgerEntry(args) {
9204
9328
  const entries = readLedgerEntries(args.meshId, { tail: 500 });
9205
9329
  for (let i = entries.length - 1; i >= 0; i--) {
@@ -9236,6 +9360,7 @@ function hasTerminalLedgerAfterDispatch(args) {
9236
9360
  if (!afterDispatch) continue;
9237
9361
  }
9238
9362
  if (entry.kind !== "task_completed" && entry.kind !== "task_failed" && entry.kind !== "task_stalled") continue;
9363
+ if (entry.kind === "task_completed" && isWeakCompletionLedgerPayload(entry.payload)) continue;
9239
9364
  const terminalTaskId = readNonEmptyString2(entry.payload?.taskId);
9240
9365
  if (terminalTaskId && terminalTaskId === args.taskId) return true;
9241
9366
  if (terminalTaskId && terminalTaskId !== args.taskId) continue;
@@ -12429,12 +12554,9 @@ var init_snapshot = __esm({
12429
12554
  // src/mesh/mesh-events-coordinator.ts
12430
12555
  import { existsSync as existsSync17 } from "fs";
12431
12556
  function resolveCoordinatorDrainDaemonIds(components) {
12432
- const ids = /* @__PURE__ */ new Set();
12433
12557
  const statusInstanceId = readNonEmptyString2(components.statusInstanceId);
12434
- if (statusInstanceId) ids.add(statusInstanceId);
12435
12558
  const machineId = readNonEmptyString2(loadConfig().machineId);
12436
- if (machineId) ids.add(machineId);
12437
- return [...ids];
12559
+ return expandDaemonIdForms([statusInstanceId, machineId]);
12438
12560
  }
12439
12561
  function getCachedMeshByWorkspace(workspace) {
12440
12562
  const now = Date.now();
@@ -12561,6 +12683,79 @@ function isDuplicateRefineTerminalEvent(meshId, eventName, metadataEvent) {
12561
12683
  recordFingerprintSeen(fingerprint);
12562
12684
  return false;
12563
12685
  }
12686
+ function isFalseIdleCompletion(metadataEvent) {
12687
+ const diag = readRecord4(metadataEvent.completionDiagnostic);
12688
+ if (!diag) return false;
12689
+ return diag.finalAssistantPresent === false || diag.blockReason === "missing_final_assistant";
12690
+ }
12691
+ function isGenuineCompletionEvidence(metadataEvent) {
12692
+ if (isFalseIdleCompletion(metadataEvent)) return false;
12693
+ return !!readWorkerResultMetadata(metadataEvent) || !!readNonEmptyString2(metadataEvent.finalSummary);
12694
+ }
12695
+ function isWeakTerminalLedgerPayload(payload) {
12696
+ if (!payload) return false;
12697
+ if (payload.evidenceLevel === "insufficient" || payload.reviewRecommended === true) return true;
12698
+ const diag = readRecord4(payload.completionDiagnostic);
12699
+ return diag?.finalAssistantPresent === false || diag?.blockReason === "missing_final_assistant";
12700
+ }
12701
+ function resolveActiveDirectDispatchTaskId(meshId, sessionId) {
12702
+ try {
12703
+ const matches = getActiveDirectDispatches(meshId).filter((d) => d.sessionId === sessionId);
12704
+ if (!matches.length) return void 0;
12705
+ return readNonEmptyString2(matches[matches.length - 1].taskId) || void 0;
12706
+ } catch {
12707
+ return void 0;
12708
+ }
12709
+ }
12710
+ function deliverTaskToSession(dispatchThunk, ctx) {
12711
+ const delivery = createSessionDelivery({
12712
+ meshId: ctx.meshId,
12713
+ nodeId: ctx.nodeId,
12714
+ sessionId: ctx.sessionId,
12715
+ providerType: ctx.providerType,
12716
+ taskId: ctx.task.id,
12717
+ kind: "task",
12718
+ message: ctx.task.message,
12719
+ status: "delivering",
12720
+ ...ctx.sourceCoordinatorSessionId ? { sourceCoordinatorSessionId: ctx.sourceCoordinatorSessionId } : {},
12721
+ ...ctx.sourceCoordinatorDaemonId ? { sourceCoordinatorDaemonId: ctx.sourceCoordinatorDaemonId } : {}
12722
+ });
12723
+ let dispatchPromise;
12724
+ try {
12725
+ dispatchPromise = Promise.resolve(dispatchThunk());
12726
+ } catch (e) {
12727
+ dispatchPromise = Promise.reject(e);
12728
+ }
12729
+ let timer;
12730
+ const guarded = Promise.race([
12731
+ dispatchPromise,
12732
+ new Promise((_, reject) => {
12733
+ timer = setTimeout(
12734
+ () => reject(new Error(`dispatch_confirm_timeout after ${DISPATCH_CONFIRM_TIMEOUT_MS}ms`)),
12735
+ DISPATCH_CONFIRM_TIMEOUT_MS
12736
+ );
12737
+ if (typeof timer?.unref === "function") timer.unref();
12738
+ })
12739
+ ]);
12740
+ guarded.then(() => {
12741
+ if (timer) clearTimeout(timer);
12742
+ updateSessionDeliveryStatus(delivery.id, "delivered");
12743
+ }).catch((e) => {
12744
+ if (timer) clearTimeout(timer);
12745
+ LOG.error("MeshQueue", `Failed to dispatch task via ${ctx.transport} to node ${ctx.nodeId}: ${e?.message}`);
12746
+ updateSessionDeliveryStatus(delivery.id, "failed", { lastError: e?.message, incrementAttempt: true });
12747
+ updateTaskStatus(ctx.meshId, ctx.task.id, "pending");
12748
+ try {
12749
+ appendLedgerEntry(ctx.meshId, {
12750
+ kind: "dispatch_failed",
12751
+ nodeId: ctx.nodeId,
12752
+ sessionId: ctx.sessionId,
12753
+ payload: { taskId: ctx.task.id, deliveryId: delivery.id, error: e?.message, retryable: true, transport: ctx.transport }
12754
+ });
12755
+ } catch {
12756
+ }
12757
+ });
12758
+ }
12564
12759
  function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType) {
12565
12760
  const mesh = getMeshWithCache(components, meshId);
12566
12761
  const node = mesh?.nodes.find((n) => readMeshNodeId(n) === nodeId);
@@ -12579,46 +12774,33 @@ function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType)
12579
12774
  if (!isLocalNode) {
12580
12775
  const localDaemonIdForDispatch = readNonEmptyString2(loadConfig().machineId) || void 0;
12581
12776
  const sourceCoordinatorSessionId = readNonEmptyString2(task.sourceCoordinatorSessionId) || void 0;
12582
- const delivery2 = createSessionDelivery({
12583
- meshId,
12584
- nodeId,
12585
- sessionId,
12586
- providerType,
12587
- taskId: task.id,
12588
- kind: "task",
12589
- message: task.message,
12590
- status: "delivering",
12591
- ...sourceCoordinatorSessionId ? { sourceCoordinatorSessionId } : {},
12592
- ...localDaemonIdForDispatch ? { sourceCoordinatorDaemonId: localDaemonIdForDispatch } : {}
12593
- });
12594
- components.dispatchMeshCommand(node.daemonId, "agent_command", {
12595
- targetSessionId: sessionId,
12596
- cliType: providerType,
12597
- action: "send_chat",
12598
- message: task.message,
12599
- meshContext: {
12777
+ const dispatchMeshCommand = components.dispatchMeshCommand;
12778
+ const remoteDaemonId = node.daemonId;
12779
+ deliverTaskToSession(
12780
+ () => dispatchMeshCommand(remoteDaemonId, "agent_command", {
12781
+ targetSessionId: sessionId,
12782
+ cliType: providerType,
12783
+ action: "send_chat",
12784
+ message: task.message,
12785
+ meshContext: {
12786
+ meshId,
12787
+ nodeId,
12788
+ taskId: task.id,
12789
+ ...localDaemonIdForDispatch ? { coordinatorDaemonId: localDaemonIdForDispatch } : {},
12790
+ ...sourceCoordinatorSessionId ? { coordinatorSessionId: sourceCoordinatorSessionId } : {}
12791
+ }
12792
+ }),
12793
+ {
12600
12794
  meshId,
12601
12795
  nodeId,
12602
- taskId: task.id,
12603
- ...localDaemonIdForDispatch ? { coordinatorDaemonId: localDaemonIdForDispatch } : {},
12604
- ...sourceCoordinatorSessionId ? { coordinatorSessionId: sourceCoordinatorSessionId } : {}
12605
- }
12606
- }).then(() => {
12607
- updateSessionDeliveryStatus(delivery2.id, "delivered");
12608
- }).catch((e) => {
12609
- LOG.error("MeshQueue", `Failed to dispatch task via P2P to remote node ${nodeId}: ${e?.message}`);
12610
- updateSessionDeliveryStatus(delivery2.id, "failed", { lastError: e?.message, incrementAttempt: true });
12611
- updateTaskStatus(meshId, task.id, "pending");
12612
- try {
12613
- appendLedgerEntry(meshId, {
12614
- kind: "dispatch_failed",
12615
- nodeId,
12616
- sessionId,
12617
- payload: { taskId: task.id, deliveryId: delivery2.id, error: e?.message, retryable: true }
12618
- });
12619
- } catch {
12796
+ sessionId,
12797
+ providerType,
12798
+ task,
12799
+ transport: "remote",
12800
+ ...sourceCoordinatorSessionId ? { sourceCoordinatorSessionId } : {},
12801
+ ...localDaemonIdForDispatch ? { sourceCoordinatorDaemonId: localDaemonIdForDispatch } : {}
12620
12802
  }
12621
- });
12803
+ );
12622
12804
  return true;
12623
12805
  }
12624
12806
  }
@@ -12640,39 +12822,24 @@ function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType)
12640
12822
  }
12641
12823
  } catch {
12642
12824
  }
12643
- const delivery = createSessionDelivery({
12644
- meshId,
12645
- nodeId,
12646
- sessionId,
12647
- providerType,
12648
- taskId: task.id,
12649
- kind: "task",
12650
- message: task.message,
12651
- status: "delivering",
12652
- ...readNonEmptyString2(task.sourceCoordinatorSessionId) ? { sourceCoordinatorSessionId: readNonEmptyString2(task.sourceCoordinatorSessionId) } : {},
12653
- ...readNonEmptyString2(loadConfig().machineId) ? { sourceCoordinatorDaemonId: readNonEmptyString2(loadConfig().machineId) } : {}
12654
- });
12655
- components.cliManager.handleCliCommand("agent_command", {
12656
- targetSessionId: sessionId,
12657
- cliType: providerType,
12658
- action: "send_chat",
12659
- message: task.message
12660
- }).then(() => {
12661
- updateSessionDeliveryStatus(delivery.id, "delivered");
12662
- }).catch((e) => {
12663
- LOG.error("MeshQueue", `Failed to dispatch task locally to node ${nodeId}: ${e?.message}`);
12664
- updateSessionDeliveryStatus(delivery.id, "failed", { lastError: e?.message, incrementAttempt: true });
12665
- updateTaskStatus(meshId, task.id, "pending");
12666
- try {
12667
- appendLedgerEntry(meshId, {
12668
- kind: "dispatch_failed",
12669
- nodeId,
12670
- sessionId,
12671
- payload: { taskId: task.id, deliveryId: delivery.id, error: e?.message, retryable: true }
12672
- });
12673
- } catch {
12825
+ deliverTaskToSession(
12826
+ () => components.cliManager.handleCliCommand("agent_command", {
12827
+ targetSessionId: sessionId,
12828
+ cliType: providerType,
12829
+ action: "send_chat",
12830
+ message: task.message
12831
+ }),
12832
+ {
12833
+ meshId,
12834
+ nodeId,
12835
+ sessionId,
12836
+ providerType,
12837
+ task,
12838
+ transport: "local",
12839
+ ...readNonEmptyString2(task.sourceCoordinatorSessionId) ? { sourceCoordinatorSessionId: readNonEmptyString2(task.sourceCoordinatorSessionId) } : {},
12840
+ ...readNonEmptyString2(loadConfig().machineId) ? { sourceCoordinatorDaemonId: readNonEmptyString2(loadConfig().machineId) } : {}
12674
12841
  }
12675
- });
12842
+ );
12676
12843
  return true;
12677
12844
  }
12678
12845
  function sweepExpiredCooldowns() {
@@ -12937,7 +13104,7 @@ async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
12937
13104
  }
12938
13105
  }
12939
13106
  const candidateNodes = Array.isArray(mesh?.nodes) ? mesh.nodes.filter((node) => {
12940
- if (task.targetNodeId && readMeshNodeId(node) !== task.targetNodeId) return false;
13107
+ if (task.targetNodeId && !meshNodeIdMatches(node, task.targetNodeId)) return false;
12941
13108
  if (task.requiredTags?.length) {
12942
13109
  const priorities = normalizeProviderPriority(node?.policy);
12943
13110
  const providerCandidates = priorities.length ? priorities : [void 0];
@@ -12948,7 +13115,12 @@ async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
12948
13115
  return true;
12949
13116
  }) : [];
12950
13117
  if (!candidateNodes.length) {
12951
- markAutoLaunch(meshId, task.id, { status: "skipped", reason: "no_node_satisfies_required_tags", nodeId: task.targetNodeId });
13118
+ const targetPinUnmatched = !!task.targetNodeId && !(Array.isArray(mesh?.nodes) && mesh.nodes.some((n) => meshNodeIdMatches(n, task.targetNodeId)));
13119
+ markAutoLaunch(meshId, task.id, {
13120
+ status: "skipped",
13121
+ reason: targetPinUnmatched ? "target_node_id_unmatched" : "no_node_satisfies_required_tags",
13122
+ nodeId: task.targetNodeId
13123
+ });
12952
13124
  continue;
12953
13125
  }
12954
13126
  const strategy = resolveSchedulingStrategy(mesh);
@@ -13405,7 +13577,8 @@ function injectMeshSystemMessage(components, args) {
13405
13577
  });
13406
13578
  if (terminal?.kind === "task_completed" && !sessionHasActiveAssignment(args.meshId, eventSessionId)) {
13407
13579
  const newDispatchAfterTerminal = hasDispatchAfterTerminal(args.meshId, eventSessionId, terminal.id);
13408
- if (!newDispatchAfterTerminal) {
13580
+ const supersedesWeakTerminal = isWeakTerminalLedgerPayload(terminal.payload) && isGenuineCompletionEvidence(args.metadataEvent);
13581
+ if (!newDispatchAfterTerminal && !supersedesWeakTerminal) {
13409
13582
  const terminalProviderSessionId = readNonEmptyString2(terminal.payload.providerSessionId);
13410
13583
  const terminalFinalSummary = readNonEmptyString2(terminal.payload.finalSummary);
13411
13584
  const eventProviderSessionId = readNonEmptyString2(args.metadataEvent.providerSessionId);
@@ -13451,24 +13624,30 @@ function injectMeshSystemMessage(components, args) {
13451
13624
  return { success: true, forwarded: 0, suppressed: true, duplicateStopped: true };
13452
13625
  }
13453
13626
  }
13454
- function markSessionTerminal(sessionId, outcome, occurredAtMs) {
13627
+ function markSessionTerminal(sessionId, outcome, occurredAtMs, opts) {
13455
13628
  const eventTaskId = readNonEmptyString2(args.metadataEvent.taskId) || void 0;
13456
13629
  const task = updateSessionTaskStatus(args.meshId, sessionId, outcome, {
13457
13630
  occurredAt: occurredAtMs != null ? new Date(occurredAtMs).toISOString() : void 0,
13458
13631
  taskId: eventTaskId
13459
13632
  });
13460
- updateDirectDispatchStatus(args.meshId, sessionId, outcome);
13633
+ const leaveDirectDispatchActive = !task && opts?.tentativeIfDirect === true;
13634
+ if (!leaveDirectDispatchActive) {
13635
+ updateDirectDispatchStatus(args.meshId, sessionId, outcome);
13636
+ }
13461
13637
  markSessionDeliveriesTerminal(args.meshId, sessionId, outcome);
13462
13638
  setImmediate(() => cleanupTerminalDirectDispatches());
13463
13639
  return task ? { id: task.id } : null;
13464
13640
  }
13465
13641
  let completedTaskForLedger = null;
13642
+ let directDispatchTaskIdForLedger;
13466
13643
  if (args.event === "agent:generating_completed") {
13467
13644
  const sessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
13468
13645
  const nodeId = readNonEmptyString2(args.nodeId) || readNonEmptyString2(args.metadataEvent.meshNodeId);
13469
13646
  const providerType = readNonEmptyString2(args.metadataEvent.providerType);
13470
13647
  if (sessionId) {
13471
- completedTaskForLedger = markSessionTerminal(sessionId, "completed", eventTimestamp);
13648
+ directDispatchTaskIdForLedger = resolveActiveDirectDispatchTaskId(args.meshId, sessionId);
13649
+ const isFalseIdle = isFalseIdleCompletion(args.metadataEvent);
13650
+ completedTaskForLedger = markSessionTerminal(sessionId, "completed", eventTimestamp, { tentativeIfDirect: isFalseIdle });
13472
13651
  if (nodeId && providerType) {
13473
13652
  runIdleMaintenanceThenAssignQueue(components, { meshId: args.meshId, nodeId, sessionId, providerType });
13474
13653
  }
@@ -13571,6 +13750,7 @@ function injectMeshSystemMessage(components, args) {
13571
13750
  }
13572
13751
  }
13573
13752
  if (sessionId) {
13753
+ directDispatchTaskIdForLedger = resolveActiveDirectDispatchTaskId(args.meshId, sessionId);
13574
13754
  completedTaskForLedger = markSessionTerminal(sessionId, "failed");
13575
13755
  }
13576
13756
  }
@@ -13600,7 +13780,10 @@ function injectMeshSystemMessage(components, args) {
13600
13780
  payload: {
13601
13781
  event: args.event,
13602
13782
  nodeLabel: args.nodeLabel,
13603
- taskId: completedTaskForLedger?.id || void 0,
13783
+ // Fix B: fall back to the direct-dispatch taskId when no work-queue row
13784
+ // matched, so the terminal entry is attributable in mesh task-stats
13785
+ // (otherwise the direct task shows status='unknown' / terminalKind=null).
13786
+ taskId: completedTaskForLedger?.id || directDispatchTaskIdForLedger || void 0,
13604
13787
  providerSessionId,
13605
13788
  finalSummary,
13606
13789
  workerResult,
@@ -13888,7 +14071,7 @@ function setupMeshEventForwarding(components) {
13888
14071
  });
13889
14072
  });
13890
14073
  }
13891
- var 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;
14074
+ var 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;
13892
14075
  var init_mesh_events_coordinator = __esm({
13893
14076
  "src/mesh/mesh-events-coordinator.ts"() {
13894
14077
  "use strict";
@@ -13916,6 +14099,7 @@ var init_mesh_events_coordinator = __esm({
13916
14099
  idleAutoFastForwardLastAttempt = /* @__PURE__ */ new Map();
13917
14100
  INTENTIONAL_CLEANUP_STOP_SUPPRESSION_MS = 30 * 60 * 1e3;
13918
14101
  RECENT_COMPLETION_FINGERPRINT_TTL_MS = 10 * 60 * 1e3;
14102
+ DISPATCH_CONFIRM_TIMEOUT_MS = 12e4;
13919
14103
  autoLaunchInProgress = /* @__PURE__ */ new Set();
13920
14104
  autoLaunchCooldownUntil = /* @__PURE__ */ new Map();
13921
14105
  AUTO_LAUNCH_COOLDOWN_MS = 5e3;
@@ -13971,12 +14155,9 @@ function resolveReconcileIntervalMs() {
13971
14155
  return DEFAULT_RECONCILE_INTERVAL_MS;
13972
14156
  }
13973
14157
  function resolveCoordinatorDaemonIds(components) {
13974
- const ids = /* @__PURE__ */ new Set();
13975
14158
  const statusInstanceId = readNonEmptyString2(components.statusInstanceId);
13976
- if (statusInstanceId) ids.add(statusInstanceId);
13977
14159
  const machineId = readNonEmptyString2(loadConfig().machineId);
13978
- if (machineId) ids.add(machineId);
13979
- return [...ids];
14160
+ return expandDaemonIdForms([statusInstanceId, machineId]);
13980
14161
  }
13981
14162
  function daemonHostsMesh(mesh, daemonIds) {
13982
14163
  const host = mesh.meshHost;
@@ -14060,6 +14241,24 @@ function recordHeldTerminalEventsToLedger(meshId, drainDaemonIds, reason, heldFo
14060
14241
  }
14061
14242
  }
14062
14243
  }
14244
+ function recoverStrandedAssignedDispatches(meshId, store) {
14245
+ const assigned = getQueue(meshId, { status: ["assigned"] });
14246
+ if (!assigned.length) return;
14247
+ const nowMs = Date.now();
14248
+ for (const row of assigned) {
14249
+ const dispatchedAtMs = Date.parse(row.dispatchTimestamp ?? "");
14250
+ if (!Number.isFinite(dispatchedAtMs)) continue;
14251
+ if (nowMs - dispatchedAtMs < ASSIGNED_STRANDED_DEADLINE_MS) continue;
14252
+ if (store.taskHasConfirmedDelivery(meshId, row.id)) continue;
14253
+ const reclaimed = reclaimStrandedAssignedTask(meshId, row.id, {
14254
+ reason: "assigned_stranded_dispatch_unconfirmed",
14255
+ ageMs: nowMs - dispatchedAtMs
14256
+ });
14257
+ if (reclaimed) {
14258
+ 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})`);
14259
+ }
14260
+ }
14261
+ }
14063
14262
  async function runMeshReconcileTick(components) {
14064
14263
  const localDaemonId = readNonEmptyString2(loadConfig().machineId) || void 0;
14065
14264
  const drainDaemonIds = resolveCoordinatorDaemonIds(components);
@@ -14089,6 +14288,17 @@ async function runMeshReconcileTick(components) {
14089
14288
  }
14090
14289
  }
14091
14290
  }
14291
+ if (store) {
14292
+ for (const mesh of listMeshes()) {
14293
+ const selfIds = resolveCoordinatorSelfIds(mesh, drainDaemonIds);
14294
+ if (!daemonHostsMesh(mesh, selfIds)) continue;
14295
+ try {
14296
+ recoverStrandedAssignedDispatches(mesh.id, store);
14297
+ } catch (e) {
14298
+ LOG.warn("MeshReconcile", `Assigned-stranded watchdog failed for mesh ${mesh.id}: ${e?.message || e}`);
14299
+ }
14300
+ }
14301
+ }
14092
14302
  for (const mesh of listMeshes()) {
14093
14303
  const selfIds = resolveCoordinatorSelfIds(mesh, drainDaemonIds);
14094
14304
  if (!daemonHostsMesh(mesh, selfIds)) continue;
@@ -14476,7 +14686,7 @@ function setupMeshReconcileLoop(components) {
14476
14686
  }
14477
14687
  };
14478
14688
  }
14479
- var DEFAULT_RECONCILE_INTERVAL_MS, DEFAULT_AUTO_PRUNE_MIN_AGE_MS, heldEventLedgerRecorded, STRICT_SESSION_MATCH_TTL_MS;
14689
+ var DEFAULT_RECONCILE_INTERVAL_MS, DEFAULT_AUTO_PRUNE_MIN_AGE_MS, heldEventLedgerRecorded, ASSIGNED_STRANDED_DEADLINE_MS, STRICT_SESSION_MATCH_TTL_MS;
14480
14690
  var init_mesh_reconcile_loop = __esm({
14481
14691
  "src/mesh/mesh-reconcile-loop.ts"() {
14482
14692
  "use strict";
@@ -14489,6 +14699,7 @@ var init_mesh_reconcile_loop = __esm({
14489
14699
  init_mesh_events_coordinator();
14490
14700
  init_mesh_unresolved_forward_outbox();
14491
14701
  init_mesh_events_utils();
14702
+ init_dist();
14492
14703
  init_mesh_work_queue();
14493
14704
  init_mesh_ledger();
14494
14705
  init_mesh_active_work();
@@ -14497,6 +14708,7 @@ var init_mesh_reconcile_loop = __esm({
14497
14708
  DEFAULT_RECONCILE_INTERVAL_MS = 4e3;
14498
14709
  DEFAULT_AUTO_PRUNE_MIN_AGE_MS = 24 * 60 * 6e4;
14499
14710
  heldEventLedgerRecorded = /* @__PURE__ */ new Set();
14711
+ ASSIGNED_STRANDED_DEADLINE_MS = 5 * 6e4;
14500
14712
  STRICT_SESSION_MATCH_TTL_MS = 6e4;
14501
14713
  }
14502
14714
  });
@@ -14529,6 +14741,84 @@ var init_mesh_events = __esm({
14529
14741
  }
14530
14742
  });
14531
14743
 
14744
+ // src/providers/approval-utils.ts
14745
+ function normalizeApprovalLabel(value) {
14746
+ return String(value || "").toLowerCase().replace(/^[\s\[(<{]*\d+(?:\s*[.)\]}>:-]|\s)+/, "").replace(/[^\p{L}\p{N}]+/gu, " ").trim();
14747
+ }
14748
+ function isNegativeApprovalLabel(value) {
14749
+ const label = normalizeApprovalLabel(value);
14750
+ return /^(no|deny|reject|cancel|skip|exit|stop)\b/.test(label) || /\bwithout\b/.test(label) || /\bdo not\b/.test(label);
14751
+ }
14752
+ function hasNegativeApprovalOption(buttons) {
14753
+ return (buttons || []).some((button) => isNegativeApprovalLabel(String(button || "")));
14754
+ }
14755
+ function getApprovalPositiveHints(provider) {
14756
+ const customHints = Array.isArray(provider?.approvalPositiveHints) ? provider.approvalPositiveHints.map((hint) => normalizeApprovalLabel(String(hint || ""))).filter(Boolean) : [];
14757
+ return customHints.length > 0 ? customHints : DEFAULT_APPROVAL_POSITIVE_HINTS;
14758
+ }
14759
+ function pickApprovalButton(buttons, provider) {
14760
+ const labels = (buttons || []).map((button) => String(button || "").trim()).filter(Boolean);
14761
+ if (labels.length === 0) {
14762
+ return { index: -1, label: "" };
14763
+ }
14764
+ const normalizedButtons = labels.map((label) => normalizeApprovalLabel(label));
14765
+ const hints = getApprovalPositiveHints(provider);
14766
+ for (const hint of hints) {
14767
+ const exactIndex = normalizedButtons.findIndex((label, index) => label === hint && !isNegativeApprovalLabel(labels[index]));
14768
+ if (exactIndex >= 0) return { index: exactIndex, label: labels[exactIndex] };
14769
+ const prefixIndex = normalizedButtons.findIndex((label, index) => label.startsWith(hint) && !isNegativeApprovalLabel(labels[index]));
14770
+ if (prefixIndex >= 0) return { index: prefixIndex, label: labels[prefixIndex] };
14771
+ const includeIndex = normalizedButtons.findIndex((label, index) => label.includes(hint) && !isNegativeApprovalLabel(labels[index]));
14772
+ if (includeIndex >= 0) return { index: includeIndex, label: labels[includeIndex] };
14773
+ }
14774
+ return { index: -1, label: "" };
14775
+ }
14776
+ function pickAutoApprovalButton(buttons) {
14777
+ const labels = (buttons || []).map((button) => String(button || "").trim());
14778
+ const index = labels.findIndex(Boolean);
14779
+ return index >= 0 ? { index, label: labels[index] } : { index: -1, label: "" };
14780
+ }
14781
+ function formatAutoApprovalMessage(modalMessage, buttonLabel) {
14782
+ const lines = [`Auto-approved${buttonLabel ? `: ${buttonLabel}` : ""}`];
14783
+ const cleanMessage = String(modalMessage || "").trim();
14784
+ if (cleanMessage) lines.push(cleanMessage);
14785
+ return lines.join("\n");
14786
+ }
14787
+ function looksLikeActiveApprovalPromptText(content) {
14788
+ const text = content.trim();
14789
+ if (!text || text.length > 2e3) return false;
14790
+ 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);
14791
+ const hasNumberedChoices = /^\s*[❯›>]?\s*1[.)]\s+(?:yes|allow|proceed|run)/im.test(text) || /^\s*1[.)]\s+yes\b/im.test(text);
14792
+ if (hasApprovalQuestion && hasNumberedChoices) return true;
14793
+ const lastLines = text.split(/\r?\n/).slice(-12).join("\n");
14794
+ const hasDontAskAgain = /yes.*don'?t ask again/i.test(lastLines) || /yes.*always allow/i.test(lastLines);
14795
+ const hasNoOption = /^\s*[❯›>]?\s*\d+[.)]\s+no\b/im.test(lastLines);
14796
+ if (hasDontAskAgain && hasNoOption) return true;
14797
+ if (/what do you want to do\?/i.test(text) && /^\s*\d+[.)]\s+\S/m.test(text)) return true;
14798
+ return false;
14799
+ }
14800
+ var DEFAULT_APPROVAL_POSITIVE_HINTS;
14801
+ var init_approval_utils = __esm({
14802
+ "src/providers/approval-utils.ts"() {
14803
+ "use strict";
14804
+ DEFAULT_APPROVAL_POSITIVE_HINTS = [
14805
+ "yes",
14806
+ "allow once",
14807
+ "approve",
14808
+ "accept",
14809
+ "continue",
14810
+ "run",
14811
+ "proceed",
14812
+ "confirm",
14813
+ "save",
14814
+ "ok",
14815
+ "trust",
14816
+ "allow",
14817
+ "always allow"
14818
+ ];
14819
+ }
14820
+ });
14821
+
14532
14822
  // src/logging/debug-config.ts
14533
14823
  function normalizeCategories(categories) {
14534
14824
  if (!Array.isArray(categories)) return [];
@@ -15515,6 +15805,27 @@ function compileSettledPromptMatchers(spec) {
15515
15805
  });
15516
15806
  return { prompt, footers };
15517
15807
  }
15808
+ function extractButtonLabels(spec, text) {
15809
+ if (!text) return [];
15810
+ const flags = spec.buttonFlags && spec.buttonFlags.includes("m") ? spec.buttonFlags : `${spec.buttonFlags ?? ""}m`;
15811
+ const buttonRe = compile2(spec.buttonPattern, flags);
15812
+ const labelGroup = Number.isInteger(spec.buttonLabelGroup) && (spec.buttonLabelGroup ?? 0) > 0 ? spec.buttonLabelGroup : 1;
15813
+ const out = [];
15814
+ for (const line of text.split("\n")) {
15815
+ buttonRe.lastIndex = 0;
15816
+ const m = buttonRe.exec(line);
15817
+ if (!m) continue;
15818
+ const captured = m[labelGroup] ?? (labelGroup === 1 && m.length > 2 ? m[m.length - 1] : void 0);
15819
+ if (captured && captured.trim()) out.push(captured.trim());
15820
+ }
15821
+ return out;
15822
+ }
15823
+ function buttonBlockApprovalCue(spec, text) {
15824
+ const labels = extractButtonLabels(spec, text);
15825
+ if (labels.length < 2) return false;
15826
+ if (pickApprovalButton(labels).index < 0) return false;
15827
+ return hasNegativeApprovalOption(labels);
15828
+ }
15518
15829
  function modalMatches(spec, input) {
15519
15830
  const text = input.screenText ?? "";
15520
15831
  const question = compile2(spec.questionPattern, spec.questionFlags ?? "i");
@@ -15523,6 +15834,7 @@ function modalMatches(spec, input) {
15523
15834
  const re = compile2(variant.regex, variant.flags ?? "i");
15524
15835
  if (re.test(text)) return true;
15525
15836
  }
15837
+ if (buttonBlockApprovalCue(spec, text)) return true;
15526
15838
  return false;
15527
15839
  }
15528
15840
  function evaluateGroup(group, spec, input, compiled) {
@@ -15577,6 +15889,7 @@ var init_detect_status = __esm({
15577
15889
  "src/providers/sdk/v1/builders/cli/detect-status.ts"() {
15578
15890
  "use strict";
15579
15891
  init_visible_region();
15892
+ init_approval_utils();
15580
15893
  DEFAULT_ORDER = ["spinner", "modal", "settled-prompt"];
15581
15894
  }
15582
15895
  });
@@ -21754,6 +22067,7 @@ init_mesh_active_work();
21754
22067
  init_mesh_refine_status();
21755
22068
  init_mesh_host_ownership();
21756
22069
  init_mesh_events();
22070
+ init_mesh_events_utils();
21757
22071
  init_mesh_delivery_policy();
21758
22072
 
21759
22073
  // src/mesh/p2p-relay-failure.ts
@@ -25673,76 +25987,8 @@ function validateReadChatResultPayload(raw, source = "read_chat") {
25673
25987
  return normalized;
25674
25988
  }
25675
25989
 
25676
- // src/providers/approval-utils.ts
25677
- var DEFAULT_APPROVAL_POSITIVE_HINTS = [
25678
- "yes",
25679
- "allow once",
25680
- "approve",
25681
- "accept",
25682
- "continue",
25683
- "run",
25684
- "proceed",
25685
- "confirm",
25686
- "save",
25687
- "ok",
25688
- "trust",
25689
- "allow",
25690
- "always allow"
25691
- ];
25692
- function normalizeApprovalLabel(value) {
25693
- return String(value || "").toLowerCase().replace(/^[\s\[(<{]*\d+(?:\s*[.)\]}>:-]|\s)+/, "").replace(/[^\p{L}\p{N}]+/gu, " ").trim();
25694
- }
25695
- function isNegativeApprovalLabel(value) {
25696
- const label = normalizeApprovalLabel(value);
25697
- return /^(no|deny|reject|cancel|skip|exit|stop)\b/.test(label) || /\bwithout\b/.test(label) || /\bdo not\b/.test(label);
25698
- }
25699
- function getApprovalPositiveHints(provider) {
25700
- const customHints = Array.isArray(provider?.approvalPositiveHints) ? provider.approvalPositiveHints.map((hint) => normalizeApprovalLabel(String(hint || ""))).filter(Boolean) : [];
25701
- return customHints.length > 0 ? customHints : DEFAULT_APPROVAL_POSITIVE_HINTS;
25702
- }
25703
- function pickApprovalButton(buttons, provider) {
25704
- const labels = (buttons || []).map((button) => String(button || "").trim()).filter(Boolean);
25705
- if (labels.length === 0) {
25706
- return { index: -1, label: "" };
25707
- }
25708
- const normalizedButtons = labels.map((label) => normalizeApprovalLabel(label));
25709
- const hints = getApprovalPositiveHints(provider);
25710
- for (const hint of hints) {
25711
- const exactIndex = normalizedButtons.findIndex((label, index) => label === hint && !isNegativeApprovalLabel(labels[index]));
25712
- if (exactIndex >= 0) return { index: exactIndex, label: labels[exactIndex] };
25713
- const prefixIndex = normalizedButtons.findIndex((label, index) => label.startsWith(hint) && !isNegativeApprovalLabel(labels[index]));
25714
- if (prefixIndex >= 0) return { index: prefixIndex, label: labels[prefixIndex] };
25715
- const includeIndex = normalizedButtons.findIndex((label, index) => label.includes(hint) && !isNegativeApprovalLabel(labels[index]));
25716
- if (includeIndex >= 0) return { index: includeIndex, label: labels[includeIndex] };
25717
- }
25718
- return { index: -1, label: "" };
25719
- }
25720
- function pickAutoApprovalButton(buttons) {
25721
- const labels = (buttons || []).map((button) => String(button || "").trim());
25722
- const index = labels.findIndex(Boolean);
25723
- return index >= 0 ? { index, label: labels[index] } : { index: -1, label: "" };
25724
- }
25725
- function formatAutoApprovalMessage(modalMessage, buttonLabel) {
25726
- const lines = [`Auto-approved${buttonLabel ? `: ${buttonLabel}` : ""}`];
25727
- const cleanMessage = String(modalMessage || "").trim();
25728
- if (cleanMessage) lines.push(cleanMessage);
25729
- return lines.join("\n");
25730
- }
25731
- function looksLikeActiveApprovalPromptText(content) {
25732
- const text = content.trim();
25733
- if (!text || text.length > 2e3) return false;
25734
- 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);
25735
- const hasNumberedChoices = /^\s*[❯›>]?\s*1[.)]\s+(?:yes|allow|proceed|run)/im.test(text) || /^\s*1[.)]\s+yes\b/im.test(text);
25736
- if (hasApprovalQuestion && hasNumberedChoices) return true;
25737
- const lastLines = text.split(/\r?\n/).slice(-12).join("\n");
25738
- const hasDontAskAgain = /yes.*don'?t ask again/i.test(lastLines) || /yes.*always allow/i.test(lastLines);
25739
- const hasNoOption = /^\s*[❯›>]?\s*\d+[.)]\s+no\b/im.test(lastLines);
25740
- if (hasDontAskAgain && hasNoOption) return true;
25741
- if (/what do you want to do\?/i.test(text) && /^\s*\d+[.)]\s+\S/m.test(text)) return true;
25742
- return false;
25743
- }
25744
-
25745
25990
  // src/providers/ide-provider-instance.ts
25991
+ init_approval_utils();
25746
25992
  init_provider_patch_state();
25747
25993
  init_chat_message_normalization();
25748
25994
  init_open_panel_support();
@@ -26826,6 +27072,7 @@ import * as fs7 from "fs";
26826
27072
  import * as os10 from "os";
26827
27073
  import * as path16 from "path";
26828
27074
  import { randomUUID as randomUUID11 } from "crypto";
27075
+ init_approval_utils();
26829
27076
  init_coordinator_registry();
26830
27077
  init_logger();
26831
27078
 
@@ -34814,6 +35061,7 @@ function createCliAdapter(provider, workingDir, cliArgs, extraEnv, transportFact
34814
35061
  // src/providers/cli-provider-instance.ts
34815
35062
  init_logger();
34816
35063
  init_control_effects();
35064
+ init_approval_utils();
34817
35065
  init_provider_patch_state();
34818
35066
 
34819
35067
  // src/providers/provider-session-id.ts
@@ -35075,6 +35323,20 @@ var CliProviderInstance = class _CliProviderInstance {
35075
35323
  * keystroke until the modal *content* has settled.
35076
35324
  */
35077
35325
  static AUTO_APPROVE_SETTLE_MS = 600;
35326
+ /**
35327
+ * Busy-side hysteresis for the settle gate. A momentary `generating` flip
35328
+ * while the SAME approval modal's button block is still on screen (its
35329
+ * question line scrolled out of the captured frame, only the buttons + a
35330
+ * residual `esc to interrupt` spinner remain) briefly reports
35331
+ * status!=waiting_approval. Without hysteresis that flip wipes the settle
35332
+ * clock, and the modal→generating→modal flap restarts the 600ms window
35333
+ * every time so auto-approve never fires. We keep the in-progress settle
35334
+ * gate warm across an inactive blip up to this bound; only once the modal
35335
+ * has genuinely stayed gone this long (a real resolution → idle) is the
35336
+ * gate cleared. Bounded so a genuinely new, later approval still re-settles
35337
+ * from scratch rather than firing on a stale timestamp.
35338
+ */
35339
+ static AUTO_APPROVE_GATE_HYSTERESIS_MS = 1500;
35078
35340
  adapter;
35079
35341
  context = null;
35080
35342
  events = [];
@@ -35096,6 +35358,10 @@ var CliProviderInstance = class _CliProviderInstance {
35096
35358
  pendingAutoApprovalSignature = "";
35097
35359
  pendingAutoApprovalSince = 0;
35098
35360
  autoApproveSettleTimer = null;
35361
+ // Wall-clock when auto-approve first observed status!=waiting_approval while
35362
+ // a settle gate was in progress. Drives AUTO_APPROVE_GATE_HYSTERESIS_MS so a
35363
+ // brief generating flip does not immediately wipe the settle clock.
35364
+ autoApproveInactiveSince = 0;
35099
35365
  controlValues = {};
35100
35366
  summaryMetadata = void 0;
35101
35367
  appliedEffectKeys = /* @__PURE__ */ new Set();
@@ -35916,14 +36182,28 @@ var CliProviderInstance = class _CliProviderInstance {
35916
36182
  const autoApproveActive = adapterStatus?.status === "waiting_approval" && this.shouldAutoApprove();
35917
36183
  if (!autoApproveActive) {
35918
36184
  this.lastAutoApprovalSignature = "";
36185
+ if (this.pendingAutoApprovalSince) {
36186
+ if (!this.autoApproveInactiveSince) this.autoApproveInactiveSince = now;
36187
+ const goneForMs = now - this.autoApproveInactiveSince;
36188
+ if (goneForMs < _CliProviderInstance.AUTO_APPROVE_GATE_HYSTERESIS_MS) {
36189
+ if (this.autoApproveSettleTimer) clearTimeout(this.autoApproveSettleTimer);
36190
+ this.autoApproveSettleTimer = setTimeout(() => {
36191
+ this.autoApproveSettleTimer = null;
36192
+ this.recheckAutoApproveSettled();
36193
+ }, _CliProviderInstance.AUTO_APPROVE_GATE_HYSTERESIS_MS - goneForMs + 20);
36194
+ return autoApproveActive;
36195
+ }
36196
+ }
35919
36197
  this.pendingAutoApprovalSignature = "";
35920
36198
  this.pendingAutoApprovalSince = 0;
36199
+ this.autoApproveInactiveSince = 0;
35921
36200
  if (this.autoApproveSettleTimer) {
35922
36201
  clearTimeout(this.autoApproveSettleTimer);
35923
36202
  this.autoApproveSettleTimer = null;
35924
36203
  }
35925
36204
  return autoApproveActive;
35926
36205
  }
36206
+ this.autoApproveInactiveSince = 0;
35927
36207
  const modal = adapterStatus.activeModal;
35928
36208
  const buttons = Array.isArray(modal?.buttons) ? modal.buttons.map((b) => String(b || "").trim()).filter(Boolean) : [];
35929
36209
  if (!modal || buttons.length === 0) {
@@ -35933,18 +36213,18 @@ var CliProviderInstance = class _CliProviderInstance {
35933
36213
  if (buttonIndex < 0) {
35934
36214
  return autoApproveActive;
35935
36215
  }
35936
- const approvalEntrySeq = typeof adapterStatus?.approvalEntrySeq === "number" ? adapterStatus.approvalEntrySeq : 0;
35937
- const signature = [
35938
- approvalEntrySeq,
36216
+ const modalSignature = [
35939
36217
  typeof modal?.message === "string" ? modal.message.trim() : "",
35940
36218
  buttons.join("|"),
35941
36219
  buttonIndex
35942
36220
  ].join("::");
35943
- if (this.autoApproveBusy && signature === this.lastAutoApprovalSignature) {
36221
+ const approvalEntrySeq = typeof adapterStatus?.approvalEntrySeq === "number" ? adapterStatus.approvalEntrySeq : 0;
36222
+ const busySignature = `${approvalEntrySeq}::${modalSignature}`;
36223
+ if (this.autoApproveBusy && busySignature === this.lastAutoApprovalSignature) {
35944
36224
  return autoApproveActive;
35945
36225
  }
35946
- if (signature !== this.pendingAutoApprovalSignature) {
35947
- this.pendingAutoApprovalSignature = signature;
36226
+ if (modalSignature !== this.pendingAutoApprovalSignature) {
36227
+ this.pendingAutoApprovalSignature = modalSignature;
35948
36228
  this.pendingAutoApprovalSince = now;
35949
36229
  }
35950
36230
  const settledForMs = now - this.pendingAutoApprovalSince;
@@ -35961,9 +36241,10 @@ var CliProviderInstance = class _CliProviderInstance {
35961
36241
  this.autoApproveSettleTimer = null;
35962
36242
  }
35963
36243
  this.autoApproveBusy = true;
35964
- this.lastAutoApprovalSignature = signature;
36244
+ this.lastAutoApprovalSignature = busySignature;
35965
36245
  this.pendingAutoApprovalSignature = "";
35966
36246
  this.pendingAutoApprovalSince = 0;
36247
+ this.autoApproveInactiveSince = 0;
35967
36248
  if (this.autoApproveBusyTimer) clearTimeout(this.autoApproveBusyTimer);
35968
36249
  this.autoApproveBusyTimer = setTimeout(() => {
35969
36250
  this.autoApproveBusy = false;
@@ -42855,7 +43136,8 @@ init_logger();
42855
43136
  import * as fs23 from "fs";
42856
43137
  import * as path35 from "path";
42857
43138
  import * as os26 from "os";
42858
- 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");
43139
+ 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");
43140
+ var LOG_DIR2 = path35.join(ADHDEV_HOME2, "logs");
42859
43141
  var MAX_FILE_SIZE = 5 * 1024 * 1024;
42860
43142
  var MAX_DAYS = 7;
42861
43143
  try {
@@ -43315,7 +43597,7 @@ function runGit2(repoRoot, args) {
43315
43597
  return "";
43316
43598
  }
43317
43599
  }
43318
- function readRecord6(repoRoot) {
43600
+ function readRecord5(repoRoot) {
43319
43601
  const path42 = resolve19(repoRoot, PREVIEW_DEPLOY_RECORD);
43320
43602
  if (!existsSync36(path42)) return null;
43321
43603
  try {
@@ -43355,7 +43637,7 @@ function readCurrentMainCommit(repoRoot) {
43355
43637
  }
43356
43638
  function buildPreviewFreshness(repoRoot) {
43357
43639
  const current = readCurrentMainCommit(repoRoot);
43358
- const record = readRecord6(repoRoot);
43640
+ const record = readRecord5(repoRoot);
43359
43641
  const lastPreviewCommit = normalizeCommit(record?.lastPreviewCommit);
43360
43642
  const targets = readTargetFreshness(record, current.currentMainCommit);
43361
43643
  let status = "unknown";
@@ -43710,13 +43992,14 @@ async function waitForPidExit(pid, timeoutMs) {
43710
43992
  }
43711
43993
  }
43712
43994
  }
43713
- function stopSessionHostProcesses(appName) {
43995
+ async function stopSessionHostProcesses(appName) {
43714
43996
  const pidFile = path36.join(os27.homedir(), ".adhdev", `${appName}-session-host.pid`);
43997
+ let killedPid = null;
43715
43998
  try {
43716
43999
  if (fs25.existsSync(pidFile)) {
43717
44000
  const pid = Number.parseInt(fs25.readFileSync(pidFile, "utf8").trim(), 10);
43718
44001
  if (Number.isFinite(pid) && pid !== process.pid && isManagedSessionHostPid(pid)) {
43719
- killPid(pid);
44002
+ if (killPid(pid)) killedPid = pid;
43720
44003
  }
43721
44004
  }
43722
44005
  } catch {
@@ -43726,6 +44009,15 @@ function stopSessionHostProcesses(appName) {
43726
44009
  } catch {
43727
44010
  }
43728
44011
  }
44012
+ if (killedPid !== null) {
44013
+ await waitForPidExit(killedPid, 15e3);
44014
+ }
44015
+ }
44016
+ function isRetriableInstallLockError(error) {
44017
+ const code = error?.code;
44018
+ if (code === "EBUSY" || code === "EPERM") return true;
44019
+ const text = `${error?.message || ""} ${error?.stderr || ""}`;
44020
+ return /\bEBUSY\b|\bEPERM\b|resource busy or locked/i.test(text);
43729
44021
  }
43730
44022
  function removeDaemonPidFile() {
43731
44023
  const pidFile = path36.join(os27.homedir(), ".adhdev", "daemon.pid");
@@ -43805,22 +44097,37 @@ async function runDaemonUpgradeHelper(payload) {
43805
44097
  appendUpgradeLog(`Waiting for parent pid ${payload.parentPid} to exit`);
43806
44098
  await waitForPidExit(payload.parentPid, 15e3);
43807
44099
  }
43808
- stopSessionHostProcesses(sessionHostAppName);
44100
+ await stopSessionHostProcesses(sessionHostAppName);
43809
44101
  removeDaemonPidFile();
43810
44102
  cleanupStaleGlobalInstallDirs(payload.packageName, installCommand.surface);
43811
44103
  const spec = `${payload.packageName}@${payload.targetVersion || "latest"}`;
43812
44104
  appendUpgradeLog(`Installing ${spec}`);
43813
- const installOutput = execFileSync5(
43814
- installCommand.command,
43815
- installCommand.args,
43816
- {
43817
- encoding: "utf8",
43818
- stdio: "pipe",
43819
- maxBuffer: 20 * 1024 * 1024,
43820
- env: buildInstallEnvWithNodeOnPath(),
43821
- ...installCommand.execOptions
44105
+ const maxInstallAttempts = process.platform === "win32" ? 3 : 1;
44106
+ let installOutput = "";
44107
+ for (let attempt = 1; attempt <= maxInstallAttempts; attempt++) {
44108
+ try {
44109
+ installOutput = String(execFileSync5(
44110
+ installCommand.command,
44111
+ installCommand.args,
44112
+ {
44113
+ encoding: "utf8",
44114
+ stdio: "pipe",
44115
+ maxBuffer: 20 * 1024 * 1024,
44116
+ env: buildInstallEnvWithNodeOnPath(),
44117
+ ...installCommand.execOptions
44118
+ }
44119
+ ));
44120
+ break;
44121
+ } catch (error) {
44122
+ if (attempt < maxInstallAttempts && isRetriableInstallLockError(error)) {
44123
+ appendUpgradeLog(`Install attempt ${attempt} hit a file lock (${error?.code || "lock"}); cleaning staging and retrying after backoff`);
44124
+ cleanupStaleGlobalInstallDirs(payload.packageName, installCommand.surface);
44125
+ await new Promise((resolve24) => setTimeout(resolve24, attempt * 1500));
44126
+ continue;
44127
+ }
44128
+ throw error;
43822
44129
  }
43823
- );
44130
+ }
43824
44131
  if (installOutput.trim()) {
43825
44132
  appendUpgradeLog(installOutput.trim());
43826
44133
  }
@@ -52582,6 +52889,7 @@ var DaemonAgentStreamManager = class {
52582
52889
 
52583
52890
  // src/agent-stream/poller.ts
52584
52891
  init_logger();
52892
+ init_approval_utils();
52585
52893
  init_chat_message_normalization();
52586
52894
  var AgentStreamPoller = class {
52587
52895
  deps;
@@ -60283,6 +60591,7 @@ export {
60283
60591
  readLedgerEntries,
60284
60592
  readLedgerSlice,
60285
60593
  readLedgerSliceFromStore,
60594
+ readMeshCompletionSummary,
60286
60595
  reconcileDirectDispatchCompletionFromTranscript,
60287
60596
  recordCompletionConflict,
60288
60597
  recordDebugTrace,
@@ -60308,6 +60617,7 @@ export {
60308
60617
  resolveMeshHostStatus,
60309
60618
  resolveMeshNodeAttribution,
60310
60619
  resolveMeshRefineValidationPlan,
60620
+ resolveMeshSurfacedSessionPreview,
60311
60621
  resolveNodeSchedulingPriority,
60312
60622
  resolveSessionHostAppName,
60313
60623
  resolveSessionHostAppNameResolution,