@adhdev/daemon-core 1.0.28-rc.12 → 1.0.28-rc.14

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
@@ -786,10 +786,10 @@ function readInjected(value) {
786
786
  }
787
787
  function getDaemonBuildInfo() {
788
788
  if (cached) return cached;
789
- const commit = readInjected(true ? "6f38d1460a02018ef53a3ecdf306004005b44310" : void 0) ?? "unknown";
790
- const commitShort = readInjected(true ? "6f38d146" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
791
- const version = readInjected(true ? "1.0.28-rc.12" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
792
- const builtAt = readInjected(true ? "2026-07-26T08:24:03.072Z" : void 0);
789
+ const commit = readInjected(true ? "a13de2dc4d24bfeb8d0e512a76f5e50d5e7cb05d" : void 0) ?? "unknown";
790
+ const commitShort = readInjected(true ? "a13de2dc" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
791
+ const version = readInjected(true ? "1.0.28-rc.14" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
792
+ const builtAt = readInjected(true ? "2026-07-26T10:04:17.736Z" : void 0);
793
793
  cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
794
794
  return cached;
795
795
  }
@@ -24951,7 +24951,7 @@ async function pollAssignedTaskInTurnProgress(components, mesh, row) {
24951
24951
  return ts2 >= dispatchedAtMs;
24952
24952
  });
24953
24953
  }
24954
- async function pollAssignedTaskTerminalEvidence(components, mesh, row) {
24954
+ async function pollAssignedTaskTerminalEvidence(components, mesh, row, opts) {
24955
24955
  const sessionId = readNonEmptyString(row.assignedSessionId);
24956
24956
  const nodeId = readNonEmptyString(row.assignedNodeId);
24957
24957
  if (!sessionId || !nodeId) return null;
@@ -24968,6 +24968,9 @@ async function pollAssignedTaskTerminalEvidence(components, mesh, row) {
24968
24968
  if (!(Number.isFinite(dispatchedAtMs) && Number.isFinite(transcriptAtMs) && transcriptAtMs >= dispatchedAtMs)) {
24969
24969
  return null;
24970
24970
  }
24971
+ if (typeof opts?.minFinalAssistantAgeMs === "number" && opts.minFinalAssistantAgeMs > 0 && Date.now() - transcriptAtMs < opts.minFinalAssistantAgeMs) {
24972
+ return null;
24973
+ }
24971
24974
  return {
24972
24975
  outcome: "completed",
24973
24976
  finalSummary: evidence.finalSummary,
@@ -25367,7 +25370,9 @@ async function recoverStrandedAssignedDispatches(components, mesh, store, localD
25367
25370
  if (since === void 0) {
25368
25371
  assignedIdleFinalAssistantSince.set(idleTranscriptStreakKey, nowMs);
25369
25372
  } else if (nowMs - since >= ASSIGNED_IDLE_TRANSCRIPT_COMPLETE_MS) {
25370
- const terminalEvidence = await pollAssignedTaskTerminalEvidence(components, mesh, row);
25373
+ const terminalEvidence = await pollAssignedTaskTerminalEvidence(components, mesh, row, {
25374
+ minFinalAssistantAgeMs: ASSIGNED_IDLE_TRANSCRIPT_COMPLETE_MS
25375
+ });
25371
25376
  if (terminalEvidence) {
25372
25377
  assignedIdleFinalAssistantSince.delete(idleTranscriptStreakKey);
25373
25378
  updateTaskStatus(meshId, row.id, terminalEvidence.outcome);
@@ -45962,6 +45967,20 @@ init_transcript_evidence();
45962
45967
 
45963
45968
  // src/providers/transcript-signal-source.ts
45964
45969
  init_logger();
45970
+
45971
+ // src/providers/busy-lease-gate.ts
45972
+ var BUSY_LEASE_BOUND_MS = 18e4;
45973
+ var DEFAULT_CANARY_PROVIDERS = ["kimi", "codex-cli"];
45974
+ function resolveBusyLeaseGate(providerType, env = process.env) {
45975
+ const boundRaw = Number(env.ADHDEV_TX_BUSY_LEASE_BOUND_MS);
45976
+ const boundMs = Number.isFinite(boundRaw) && boundRaw > 0 ? Math.floor(boundRaw) : BUSY_LEASE_BOUND_MS;
45977
+ const listRaw = env.ADHDEV_TX_BUSY_LEASE_PROVIDERS;
45978
+ const list = (typeof listRaw === "string" ? listRaw : DEFAULT_CANARY_PROVIDERS.join(",")).split(",").map((s2) => s2.trim()).filter(Boolean);
45979
+ const type = (providerType ?? "").trim();
45980
+ return { enabled: type.length > 0 && list.includes(type), boundMs };
45981
+ }
45982
+
45983
+ // src/providers/transcript-signal-source.ts
45965
45984
  init_signal_envelope();
45966
45985
  var TranscriptSignalSource = class {
45967
45986
  constructor(opts) {
@@ -45969,6 +45988,10 @@ var TranscriptSignalSource = class {
45969
45988
  }
45970
45989
  /** msgCount seen at the previous update — drives in_turn_progress. */
45971
45990
  prevMsgCount = -1;
45991
+ /** TX-FSM Stage 2: wall-clock of the most recent sample that proved the
45992
+ * transcript live (in_turn_progress === true — a count advance OR mtime
45993
+ * inside the growth-quiet window). -1 = the lease was never issued. */
45994
+ lastLiveSampleAt = -1;
45972
45995
  /** Fingerprint of the last LOGGED snapshot, so the shadow log fires on
45973
45996
  * change only (a quiet session must not spam one line per read). */
45974
45997
  lastLoggedFingerprint = "";
@@ -46017,6 +46040,7 @@ var TranscriptSignalSource = class {
46017
46040
  const inTurnProgress = countAdvanced || fresh;
46018
46041
  const transcriptGrowing = ageMs === null ? null : fresh;
46019
46042
  this.prevMsgCount = msgCount;
46043
+ if (inTurnProgress) this.lastLiveSampleAt = now;
46020
46044
  return {
46021
46045
  kind: SIGNAL_SNAPSHOT_KIND,
46022
46046
  sampledAt: now,
@@ -46030,6 +46054,33 @@ var TranscriptSignalSource = class {
46030
46054
  detail: { msgCount, sourceMtimeMs, ageMs }
46031
46055
  };
46032
46056
  }
46057
+ /**
46058
+ * TX-FSM Stage 2 — the bounded busy lease, derived from the SAME sample
46059
+ * stream that produces the envelope (zero added I/O, pure memory read).
46060
+ *
46061
+ * Semantics: every sample whose in_turn_progress is true (re)issues the
46062
+ * lease at that sample's wall-clock; the lease stays ACTIVE for
46063
+ * leaseBoundMs after the LAST such sample and then EXPIRES. The bound is
46064
+ * the whole point: the lease extends busy across PTY-quiet stretches while
46065
+ * the transcript is demonstrably alive, but it can never hold busy
46066
+ * indefinitely — after expiry the consumer must resume its normal
46067
+ * (pre-lease) judgment, so a finished-but-wedged session escapes on the
46068
+ * bound, not on a transcript event that may never come.
46069
+ *
46070
+ * Fail-open by construction: a non-native-source class, an unresolved
46071
+ * transcript, or a read error never reaches the issuance line, so the
46072
+ * lease is simply never issued (active:false, lastLiveAt:null) — a
46073
+ * missing lease must never wedge a session or fabricate one.
46074
+ */
46075
+ busyLease(now = Date.now()) {
46076
+ if (this.lastLiveSampleAt < 0) {
46077
+ return { active: false, lastLiveAt: null, expiresAt: null, remainingMs: 0 };
46078
+ }
46079
+ const bound = this.opts.leaseBoundMs ?? BUSY_LEASE_BOUND_MS;
46080
+ const expiresAt = this.lastLiveSampleAt + bound;
46081
+ const remainingMs = Math.max(0, expiresAt - now);
46082
+ return { active: remainingMs > 0, lastLiveAt: this.lastLiveSampleAt, expiresAt, remainingMs };
46083
+ }
46033
46084
  /** Stage-0 shadow log: emit one line when the normalized observation
46034
46085
  * CHANGES. This log is the Stage 1-3 judgment input ("which signals were
46035
46086
  * actually observable, and when"), so it carries the full signal set —
@@ -51467,7 +51518,11 @@ var CliProviderInstance = class _CliProviderInstance {
51467
51518
  // final_assistant_present signal rather than duplicating
51468
51519
  // the message scan.
51469
51520
  finalAssistantPresent: (msgs, ts2) => this.completionHasFinalAssistantMessage(msgs, ts2),
51470
- growthQuietMs: MISSING_ASSISTANT_TRANSCRIPT_GROWTH_QUIET_MS
51521
+ growthQuietMs: MISSING_ASSISTANT_TRANSCRIPT_GROWTH_QUIET_MS,
51522
+ // TX-FSM Stage 2: the lease bound follows the rollout gate's
51523
+ // (possibly env-overridden) value; the gate's enabled flag is
51524
+ // consulted per judgment, not here.
51525
+ leaseBoundMs: resolveBusyLeaseGate(this.type).boundMs
51471
51526
  });
51472
51527
  }
51473
51528
  const snapshot = this.transcriptSignalSource.update(
@@ -52068,6 +52123,21 @@ var CliProviderInstance = class _CliProviderInstance {
52068
52123
  }
52069
52124
  return { snapshot: this.lastTranscriptSignalSnapshot, messages };
52070
52125
  }
52126
+ /**
52127
+ * TX-FSM Stage 2: is the bounded busy lease enabled for THIS provider?
52128
+ * This is the canary rollout gate (busy-lease-gate.ts) — a per-provider
52129
+ * feature switch, NOT a classification (transcript class/timing still come
52130
+ * from resolveTranscriptAuthorityProfile only). Resolved per call so an
52131
+ * env-driven rollout change takes effect without rebuilding the instance;
52132
+ * any resolver error fails closed (lease disabled → pre-Stage-2 behavior).
52133
+ */
52134
+ busyLeaseGateEnabled() {
52135
+ try {
52136
+ return resolveBusyLeaseGate(this.type).enabled;
52137
+ } catch {
52138
+ return false;
52139
+ }
52140
+ }
52071
52141
  /**
52072
52142
  * KIMI-MESH-COMPLETION-EMIT (axis 2). Last-chance completion emit for a mesh
52073
52143
  * DELEGATED worker whose PTY has already exited (e.g. killed by a false stall)
@@ -52494,6 +52564,28 @@ var CliProviderInstance = class _CliProviderInstance {
52494
52564
  this.scheduleCompletedDebounceFlush(COMPLETED_FINALIZATION_RETRY_MS);
52495
52565
  return;
52496
52566
  }
52567
+ if (growthSnapshot?.available === true && this.busyLeaseGateEnabled()) {
52568
+ const lease = this.transcriptSignalSource?.busyLease() ?? null;
52569
+ if (lease?.active === true) {
52570
+ if (pending.loggedBlockReason !== "busy_lease_active") {
52571
+ LOG.info("CLI", `[${this.type}] holding pending completed (busy_lease_active: lastLiveAt=${lease.lastLiveAt} expiresIn=${lease.remainingMs}ms) \u2014 transcript live within the lease bound, screen-idle verdict not trusted`);
52572
+ if (this.isMeshWorkerSession()) {
52573
+ traceMeshEventDrop("completion_gate_hold", this.meshTraceCtx(), `busy_lease_active lastLiveAt=${lease.lastLiveAt} expiresIn=${lease.remainingMs}ms`);
52574
+ }
52575
+ if (this.completionTraceOn()) this.recordCompletionGateTrace("hold", {
52576
+ blockReason: "busy_lease_active",
52577
+ latestVisibleStatus,
52578
+ leaseLastLiveAt: lease.lastLiveAt,
52579
+ leaseExpiresAt: lease.expiresAt,
52580
+ leaseRemainingMs: lease.remainingMs,
52581
+ waitedMs
52582
+ });
52583
+ pending.loggedBlockReason = "busy_lease_active";
52584
+ }
52585
+ this.scheduleCompletedDebounceFlush(COMPLETED_FINALIZATION_RETRY_MS);
52586
+ return;
52587
+ }
52588
+ }
52497
52589
  }
52498
52590
  if (!isTranscriptEvidenceGate && (block2.terminal || waitedMs < COMPLETED_FINALIZATION_MAX_WAIT_MS)) {
52499
52591
  if (pending.loggedBlockReason !== blockReason) {