@adhdev/daemon-core 0.9.82-rc.430 → 0.9.82-rc.432

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
@@ -404,10 +404,10 @@ function readInjected(value) {
404
404
  }
405
405
  function getDaemonBuildInfo() {
406
406
  if (cached) return cached;
407
- const commit = readInjected(true ? "c7dba412b544423c5eee2bac9e1004739ecab503" : void 0) ?? "unknown";
408
- const commitShort = readInjected(true ? "c7dba412" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
409
- const version = readInjected(true ? "0.9.82-rc.430" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
410
- const builtAt = readInjected(true ? "2026-06-30T05:29:05.430Z" : void 0);
407
+ const commit = readInjected(true ? "818d857089de19d818903a7a416b3f84ccb594e3" : void 0) ?? "unknown";
408
+ const commitShort = readInjected(true ? "818d8570" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
409
+ const version = readInjected(true ? "0.9.82-rc.432" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
410
+ const builtAt = readInjected(true ? "2026-06-30T07:51:07.054Z" : void 0);
411
411
  cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
412
412
  return cached;
413
413
  }
@@ -16777,7 +16777,9 @@ function flushPendingForMeshIdleCoordinators(components, meshId) {
16777
16777
  if (readNonEmptyString2(settings.meshCoordinatorFor) !== meshId) continue;
16778
16778
  const status = readNonEmptyString2(state.status).toLowerCase();
16779
16779
  const modalParked = typeof inst.isModalParked === "function" ? inst.isModalParked() === true : status === "waiting_choice" || status === "waiting_approval";
16780
- if (status === "idle" && !modalParked) {
16780
+ const drainStatus = typeof inst.getDrainStatus === "function" ? inst.getDrainStatus() : null;
16781
+ const idle = drainStatus !== null ? drainStatus === "idle" : status === "idle";
16782
+ if (idle && !modalParked) {
16781
16783
  idleCoordinators.push({ instance: inst, sessionId: readNonEmptyString2(state.instanceId) });
16782
16784
  }
16783
16785
  }
@@ -16950,6 +16952,9 @@ function resolveAutoPruneMinAgeMs() {
16950
16952
  }
16951
16953
  return DEFAULT_AUTO_PRUNE_MIN_AGE_MS;
16952
16954
  }
16955
+ function resolvePendingHeldDrainEscalateMs() {
16956
+ return resolveTunedReconcileMs("MESH_PENDING_HELD_DRAIN_ESCALATE_MS", DEFAULT_PENDING_HELD_DRAIN_ESCALATE_MS, 4e3, 5 * 6e4);
16957
+ }
16953
16958
  function resolveReconcileIntervalMs() {
16954
16959
  const raw = readNonEmptyString2(process.env.MESH_RECONCILE_INTERVAL_MS);
16955
16960
  if (raw) {
@@ -17012,6 +17017,8 @@ function findLiveCoordinators(components) {
17012
17017
  if (!meshId) continue;
17013
17018
  const status = readNonEmptyString2(state.status).toLowerCase();
17014
17019
  const modalParked = typeof inst.isModalParked === "function" ? inst.isModalParked() === true : status === "waiting_choice" || status === "waiting_approval";
17020
+ const drainStatus = typeof inst.getDrainStatus === "function" ? inst.getDrainStatus() : null;
17021
+ const idle = drainStatus !== null ? drainStatus === "idle" : status === "idle";
17015
17022
  const sessionId = readNonEmptyString2(state.instanceId);
17016
17023
  if (getLogLevel() === "debug") {
17017
17024
  let adapterRaw = "?";
@@ -17026,7 +17033,7 @@ function findLiveCoordinators(components) {
17026
17033
  const lastStatus = readNonEmptyString2(inst.lastStatus) || "?";
17027
17034
  const autoApproveBusy = inst.autoApproveBusy;
17028
17035
  const maskSince = inst.autoApproveMaskSince;
17029
- LOG.debug("MeshReconcile", `coordDiag sess=${sessionId || "?"} mesh=${meshId} getState=${status || "?"} lastStatus=${lastStatus} adapterRaw=${adapterRaw} autoApproveBusy=${autoApproveBusy === true} maskSince=${maskSince || 0}`);
17036
+ LOG.debug("MeshReconcile", `coordDiag sess=${sessionId || "?"} mesh=${meshId} getState=${status || "?"} drainStatus=${drainStatus || "n/a"} lastStatus=${lastStatus} adapterRaw=${adapterRaw} autoApproveBusy=${autoApproveBusy === true} maskSince=${maskSince || 0}`);
17030
17037
  }
17031
17038
  const stateKey = `${meshId}::${sessionId || "?"}`;
17032
17039
  const prevParked = coordinatorModalParkState.get(stateKey);
@@ -17038,7 +17045,7 @@ function findLiveCoordinators(components) {
17038
17045
  LOG.info("MeshReconcile", `Coordinator ${sessionId || "?"} (mesh ${meshId}) left modal-park (status=${status}) \u2014 held events will drain on this/next tick`);
17039
17046
  }
17040
17047
  }
17041
- out.push({ meshId, instance: inst, sessionId, idle: status === "idle", modalParked });
17048
+ out.push({ meshId, instance: inst, sessionId, idle, modalParked });
17042
17049
  }
17043
17050
  return out;
17044
17051
  }
@@ -17133,6 +17140,63 @@ function recordHeldTerminalEventsToLedger(meshId, drainDaemonIds, reason, heldFo
17133
17140
  }
17134
17141
  }
17135
17142
  }
17143
+ function oldestHeldTerminalEventAgeMs(meshId, drainDaemonIds) {
17144
+ let pending;
17145
+ try {
17146
+ pending = getPendingMeshCoordinatorEvents(meshId, drainDaemonIds.length > 0 ? drainDaemonIds : void 0);
17147
+ } catch {
17148
+ return 0;
17149
+ }
17150
+ const now = Date.now();
17151
+ let maxAge = 0;
17152
+ for (const event of pending) {
17153
+ if (!shouldForceInjectMeshEvent(event.event)) continue;
17154
+ const queuedAt = typeof event.queuedAt === "number" ? event.queuedAt : now;
17155
+ const age = now - queuedAt;
17156
+ if (age > maxAge) maxAge = age;
17157
+ }
17158
+ return maxAge;
17159
+ }
17160
+ function reconfirmGenuinelyIdleCoordinators(generating) {
17161
+ const out = [];
17162
+ for (const c of generating) {
17163
+ const inst = c.instance;
17164
+ const drainStatus = typeof inst?.getDrainStatus === "function" ? inst.getDrainStatus() : null;
17165
+ const genuinelyIdle = drainStatus !== null ? drainStatus === "idle" : c.idle;
17166
+ if (genuinelyIdle) out.push({ ...c, idle: true });
17167
+ }
17168
+ return out;
17169
+ }
17170
+ function drainAndInjectIntoTargets(meshId, drainDaemonIds, localDaemonId, targetCoordinators, logLabel) {
17171
+ let pendingEvents = [];
17172
+ try {
17173
+ pendingEvents = drainPendingMeshCoordinatorEvents(
17174
+ meshId,
17175
+ drainDaemonIds.length > 0 ? drainDaemonIds : localDaemonId
17176
+ );
17177
+ } catch (e) {
17178
+ LOG.warn("MeshReconcile", `Drain failed for mesh ${meshId}: ${e?.message || e}`);
17179
+ return 0;
17180
+ }
17181
+ if (pendingEvents.length === 0) return 0;
17182
+ LOG.info("MeshReconcile", `Reconcile inject \u2192 ${logLabel}: ${pendingEvents.length} pending event(s) \u2192 ${targetCoordinators.length} coordinator(s) for mesh ${meshId}`);
17183
+ for (const pending of pendingEvents) {
17184
+ const wantSession = readNonEmptyString2(pending.targetCoordinatorSessionId);
17185
+ if (wantSession) {
17186
+ const matched = targetCoordinators.filter((c) => c.sessionId === wantSession);
17187
+ if (matched.length === 0) {
17188
+ holdOrExpireStrictUnmatchedEvent(pending, wantSession, meshId);
17189
+ continue;
17190
+ }
17191
+ for (const c of matched) injectPendingIntoCoordinator(c.instance, pending);
17192
+ continue;
17193
+ }
17194
+ for (const c of targetCoordinators) {
17195
+ injectPendingIntoCoordinator(c.instance, pending);
17196
+ }
17197
+ }
17198
+ return pendingEvents.length;
17199
+ }
17136
17200
  function recoverStrandedAssignedDispatches(meshId, store) {
17137
17201
  const assigned = getQueue(meshId, { status: ["assigned"] });
17138
17202
  if (!assigned.length) return;
@@ -17344,6 +17408,19 @@ async function runMeshReconcileTick(components) {
17344
17408
  }
17345
17409
  }
17346
17410
  if (hasPending) {
17411
+ const escalateMs = resolvePendingHeldDrainEscalateMs();
17412
+ const heldAgeMs = oldestHeldTerminalEventAgeMs(
17413
+ meshId,
17414
+ drainDaemonIds.length > 0 ? drainDaemonIds : localDaemonId ? [localDaemonId] : []
17415
+ );
17416
+ if (heldAgeMs >= escalateMs) {
17417
+ const escapeTargets = reconfirmGenuinelyIdleCoordinators(generatingCoordinators);
17418
+ if (escapeTargets.length > 0) {
17419
+ LOG.info("MeshReconcile", `Reconcile age-escape \u2192 generating-hold: held terminal event(s) for mesh ${meshId} aged ${Math.round(heldAgeMs / 1e3)}s (\u2265 ${Math.round(escalateMs / 1e3)}s) and ${escapeTargets.length} coordinator(s) re-confirmed genuinely idle on the raw adapter \u2014 draining once`);
17420
+ const drained = drainAndInjectIntoTargets(meshId, drainDaemonIds, localDaemonId, escapeTargets, "age-escape");
17421
+ if (drained > 0) continue;
17422
+ }
17423
+ }
17347
17424
  LOG.info("MeshReconcile", `Reconcile skip \u2192 generating: holding pending event(s) for mesh ${meshId} (${generatingCoordinators.length} coordinator(s) busy; events left queued for the next idle tick)`);
17348
17425
  if (getLogLevel() === "debug") {
17349
17426
  LOG.debug("MeshReconcile", `coordHoldGenerating mesh=${meshId} heldFor=[${generatingCoordinators.map((c) => c.sessionId || "?").join(",")}] (these were classified busy; cross-ref same-tick coordDiag by sessionId)`);
@@ -17364,33 +17441,7 @@ async function runMeshReconcileTick(components) {
17364
17441
  } catch {
17365
17442
  }
17366
17443
  }
17367
- let pendingEvents = [];
17368
- try {
17369
- pendingEvents = drainPendingMeshCoordinatorEvents(
17370
- meshId,
17371
- drainDaemonIds.length > 0 ? drainDaemonIds : localDaemonId
17372
- );
17373
- } catch (e) {
17374
- LOG.warn("MeshReconcile", `Drain failed for mesh ${meshId}: ${e?.message || e}`);
17375
- continue;
17376
- }
17377
- if (pendingEvents.length === 0) continue;
17378
- LOG.info("MeshReconcile", `Reconcile inject \u2192 idle: ${pendingEvents.length} pending event(s) \u2192 ${targetCoordinators.length} coordinator(s) for mesh ${meshId}`);
17379
- for (const pending of pendingEvents) {
17380
- const wantSession = readNonEmptyString2(pending.targetCoordinatorSessionId);
17381
- if (wantSession) {
17382
- const matched = targetCoordinators.filter((c) => c.sessionId === wantSession);
17383
- if (matched.length === 0) {
17384
- holdOrExpireStrictUnmatchedEvent(pending, wantSession, meshId);
17385
- continue;
17386
- }
17387
- for (const c of matched) injectPendingIntoCoordinator(c.instance, pending);
17388
- continue;
17389
- }
17390
- for (const c of targetCoordinators) {
17391
- injectPendingIntoCoordinator(c.instance, pending);
17392
- }
17393
- }
17444
+ drainAndInjectIntoTargets(meshId, drainDaemonIds, localDaemonId, targetCoordinators, "idle");
17394
17445
  }
17395
17446
  }
17396
17447
  function holdOrExpireStrictUnmatchedEvent(pending, wantSession, meshId) {
@@ -17840,7 +17891,7 @@ function setupMeshReconcileLoop(components) {
17840
17891
  }
17841
17892
  };
17842
17893
  }
17843
- var DEFAULT_RECONCILE_INTERVAL_MS, DEFAULT_AUTO_PRUNE_MIN_AGE_MS, ACKED_DEATH_CONSECUTIVE_READ_FAILURES, inFlightAckedHoldState, coordinatorModalParkState, heldEventLedgerRecorded, ASSIGNED_STRANDED_DEADLINE_MS, STRICT_SESSION_MATCH_TTL_MS, unresolvedForwardRejectionCounts, MAX_FORWARD_REJECTIONS;
17894
+ var DEFAULT_RECONCILE_INTERVAL_MS, DEFAULT_AUTO_PRUNE_MIN_AGE_MS, DEFAULT_PENDING_HELD_DRAIN_ESCALATE_MS, ACKED_DEATH_CONSECUTIVE_READ_FAILURES, inFlightAckedHoldState, coordinatorModalParkState, heldEventLedgerRecorded, ASSIGNED_STRANDED_DEADLINE_MS, STRICT_SESSION_MATCH_TTL_MS, unresolvedForwardRejectionCounts, MAX_FORWARD_REJECTIONS;
17844
17895
  var init_mesh_reconcile_loop = __esm({
17845
17896
  "src/mesh/mesh-reconcile-loop.ts"() {
17846
17897
  "use strict";
@@ -17862,6 +17913,7 @@ var init_mesh_reconcile_loop = __esm({
17862
17913
  init_chat_message_normalization();
17863
17914
  DEFAULT_RECONCILE_INTERVAL_MS = 4e3;
17864
17915
  DEFAULT_AUTO_PRUNE_MIN_AGE_MS = 24 * 60 * 6e4;
17916
+ DEFAULT_PENDING_HELD_DRAIN_ESCALATE_MS = 12e3;
17865
17917
  ACKED_DEATH_CONSECUTIVE_READ_FAILURES = 3;
17866
17918
  inFlightAckedHoldState = /* @__PURE__ */ new Map();
17867
17919
  coordinatorModalParkState = /* @__PURE__ */ new Map();
@@ -40840,6 +40892,49 @@ var CliProviderInstance = class _CliProviderInstance {
40840
40892
  isModalParked() {
40841
40893
  return this.resolveModalParkStatus() !== null;
40842
40894
  }
40895
+ /**
40896
+ * PTY-OVERTRUST-DRAIN (Defect B). The deliverability/drain status the mesh
40897
+ * reconcile loop must consult — the RAW adapter turn-state, with the
40898
+ * auto-approve "hold-idle" visual mask STRIPPED.
40899
+ *
40900
+ * getState().status overlays `autoApproveHoldIdle`/`autoApproveActive` to paint a
40901
+ * genuinely-idle adapter as `generating` (a UI-flicker suppression while an
40902
+ * auto-approve key-press settles — see getState() ~:800). That mask is correct
40903
+ * for the dashboard, but the reconcile loop trusts it as "the coordinator is
40904
+ * busy" and therefore HOLDS a worker's completion under
40905
+ * `generating_no_idle_coordinator` even though the coordinator's PTY is at a real
40906
+ * turn end and would accept the inject as a turn — the completion is stranded.
40907
+ *
40908
+ * This accessor reports the drain truth instead:
40909
+ * - 'modal_parked' — a GENUINE human-await modal (AskUserQuestion / a non-
40910
+ * transient tool-consent). Still excluded from drain (a force-inject here
40911
+ * writes raw keystrokes the modal eats → data corruption). Mirrors
40912
+ * isModalParked(), evaluated first so a parked session never reads idle.
40913
+ * - 'idle' — the RAW adapter is at a turn end (adapter.getStatus(allowParse:false)
40914
+ * === 'idle') and the session is not modal-parked. Drain-eligible REGARDLESS
40915
+ * of the auto-approve mask. This is the case the mask used to hide.
40916
+ * - 'generating' — the raw adapter is genuinely mid-turn. Held (a raw PTY write
40917
+ * into a generating claude-cli is not consumed as a turn → data loss). The
40918
+ * intentional removal of force-inject-into-generating is preserved.
40919
+ * - 'other' — any other raw status (error / starting / waiting_choice handled by
40920
+ * modal-park above). Not a drain target.
40921
+ *
40922
+ * Uses allowParse:false (engine.activeModal only, side-effect-free) so it never
40923
+ * mutates the very auto-approve mask state the diagnostics read.
40924
+ */
40925
+ getDrainStatus() {
40926
+ if (this.isModalParked()) return "modal_parked";
40927
+ let rawStatus;
40928
+ try {
40929
+ const raw = this.adapter.getStatus({ allowParse: false })?.status;
40930
+ rawStatus = typeof raw === "string" ? raw.trim() : "";
40931
+ } catch {
40932
+ return "other";
40933
+ }
40934
+ if (rawStatus === "idle") return "idle";
40935
+ if (isCliGeneratingLikeStatus(rawStatus)) return "generating";
40936
+ return "other";
40937
+ }
40843
40938
  onEvent(event, data) {
40844
40939
  if (event === "send_message") {
40845
40940
  const input = normalizeInputEnvelope(data);