@adhdev/daemon-core 1.0.28-rc.13 → 1.0.28-rc.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -791,10 +791,10 @@ function readInjected(value) {
791
791
  }
792
792
  function getDaemonBuildInfo() {
793
793
  if (cached) return cached;
794
- const commit = readInjected(true ? "200c050e12084938c52f329a7531fd59a7cf5064" : void 0) ?? "unknown";
795
- const commitShort = readInjected(true ? "200c050e" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
796
- const version = readInjected(true ? "1.0.28-rc.13" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
797
- const builtAt = readInjected(true ? "2026-07-26T08:47:54.956Z" : void 0);
794
+ const commit = readInjected(true ? "3c6684c9e2549bf7ab1508195857595a89ae9ec1" : void 0) ?? "unknown";
795
+ const commitShort = readInjected(true ? "3c6684c" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
796
+ const version = readInjected(true ? "1.0.28-rc.15" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
797
+ const builtAt = readInjected(true ? "2026-07-26T13:11:34.159Z" : void 0);
798
798
  cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
799
799
  return cached;
800
800
  }
@@ -24943,7 +24943,7 @@ async function pollAssignedTaskInTurnProgress(components, mesh, row) {
24943
24943
  return ts2 >= dispatchedAtMs;
24944
24944
  });
24945
24945
  }
24946
- async function pollAssignedTaskTerminalEvidence(components, mesh, row) {
24946
+ async function pollAssignedTaskTerminalEvidence(components, mesh, row, opts) {
24947
24947
  const sessionId = readNonEmptyString(row.assignedSessionId);
24948
24948
  const nodeId = readNonEmptyString(row.assignedNodeId);
24949
24949
  if (!sessionId || !nodeId) return null;
@@ -24960,6 +24960,9 @@ async function pollAssignedTaskTerminalEvidence(components, mesh, row) {
24960
24960
  if (!(Number.isFinite(dispatchedAtMs) && Number.isFinite(transcriptAtMs) && transcriptAtMs >= dispatchedAtMs)) {
24961
24961
  return null;
24962
24962
  }
24963
+ if (typeof opts?.minFinalAssistantAgeMs === "number" && opts.minFinalAssistantAgeMs > 0 && Date.now() - transcriptAtMs < opts.minFinalAssistantAgeMs) {
24964
+ return null;
24965
+ }
24963
24966
  return {
24964
24967
  outcome: "completed",
24965
24968
  finalSummary: evidence.finalSummary,
@@ -25359,7 +25362,9 @@ async function recoverStrandedAssignedDispatches(components, mesh, store, localD
25359
25362
  if (since === void 0) {
25360
25363
  assignedIdleFinalAssistantSince.set(idleTranscriptStreakKey, nowMs);
25361
25364
  } else if (nowMs - since >= ASSIGNED_IDLE_TRANSCRIPT_COMPLETE_MS) {
25362
- const terminalEvidence = await pollAssignedTaskTerminalEvidence(components, mesh, row);
25365
+ const terminalEvidence = await pollAssignedTaskTerminalEvidence(components, mesh, row, {
25366
+ minFinalAssistantAgeMs: ASSIGNED_IDLE_TRANSCRIPT_COMPLETE_MS
25367
+ });
25363
25368
  if (terminalEvidence) {
25364
25369
  assignedIdleFinalAssistantSince.delete(idleTranscriptStreakKey);
25365
25370
  updateTaskStatus(meshId, row.id, terminalEvidence.outcome);
@@ -46404,6 +46409,20 @@ init_transcript_evidence();
46404
46409
 
46405
46410
  // src/providers/transcript-signal-source.ts
46406
46411
  init_logger();
46412
+
46413
+ // src/providers/busy-lease-gate.ts
46414
+ var BUSY_LEASE_BOUND_MS = 18e4;
46415
+ var DEFAULT_CANARY_PROVIDERS = ["kimi", "codex-cli"];
46416
+ function resolveBusyLeaseGate(providerType, env = process.env) {
46417
+ const boundRaw = Number(env.ADHDEV_TX_BUSY_LEASE_BOUND_MS);
46418
+ const boundMs = Number.isFinite(boundRaw) && boundRaw > 0 ? Math.floor(boundRaw) : BUSY_LEASE_BOUND_MS;
46419
+ const listRaw = env.ADHDEV_TX_BUSY_LEASE_PROVIDERS;
46420
+ const list = (typeof listRaw === "string" ? listRaw : DEFAULT_CANARY_PROVIDERS.join(",")).split(",").map((s2) => s2.trim()).filter(Boolean);
46421
+ const type = (providerType ?? "").trim();
46422
+ return { enabled: type.length > 0 && list.includes(type), boundMs };
46423
+ }
46424
+
46425
+ // src/providers/transcript-signal-source.ts
46407
46426
  init_signal_envelope();
46408
46427
  var TranscriptSignalSource = class {
46409
46428
  constructor(opts) {
@@ -46411,6 +46430,10 @@ var TranscriptSignalSource = class {
46411
46430
  }
46412
46431
  /** msgCount seen at the previous update — drives in_turn_progress. */
46413
46432
  prevMsgCount = -1;
46433
+ /** TX-FSM Stage 2: wall-clock of the most recent sample that proved the
46434
+ * transcript live (in_turn_progress === true — a count advance OR mtime
46435
+ * inside the growth-quiet window). -1 = the lease was never issued. */
46436
+ lastLiveSampleAt = -1;
46414
46437
  /** Fingerprint of the last LOGGED snapshot, so the shadow log fires on
46415
46438
  * change only (a quiet session must not spam one line per read). */
46416
46439
  lastLoggedFingerprint = "";
@@ -46459,6 +46482,7 @@ var TranscriptSignalSource = class {
46459
46482
  const inTurnProgress = countAdvanced || fresh;
46460
46483
  const transcriptGrowing = ageMs === null ? null : fresh;
46461
46484
  this.prevMsgCount = msgCount;
46485
+ if (inTurnProgress) this.lastLiveSampleAt = now;
46462
46486
  return {
46463
46487
  kind: SIGNAL_SNAPSHOT_KIND,
46464
46488
  sampledAt: now,
@@ -46472,6 +46496,33 @@ var TranscriptSignalSource = class {
46472
46496
  detail: { msgCount, sourceMtimeMs, ageMs }
46473
46497
  };
46474
46498
  }
46499
+ /**
46500
+ * TX-FSM Stage 2 — the bounded busy lease, derived from the SAME sample
46501
+ * stream that produces the envelope (zero added I/O, pure memory read).
46502
+ *
46503
+ * Semantics: every sample whose in_turn_progress is true (re)issues the
46504
+ * lease at that sample's wall-clock; the lease stays ACTIVE for
46505
+ * leaseBoundMs after the LAST such sample and then EXPIRES. The bound is
46506
+ * the whole point: the lease extends busy across PTY-quiet stretches while
46507
+ * the transcript is demonstrably alive, but it can never hold busy
46508
+ * indefinitely — after expiry the consumer must resume its normal
46509
+ * (pre-lease) judgment, so a finished-but-wedged session escapes on the
46510
+ * bound, not on a transcript event that may never come.
46511
+ *
46512
+ * Fail-open by construction: a non-native-source class, an unresolved
46513
+ * transcript, or a read error never reaches the issuance line, so the
46514
+ * lease is simply never issued (active:false, lastLiveAt:null) — a
46515
+ * missing lease must never wedge a session or fabricate one.
46516
+ */
46517
+ busyLease(now = Date.now()) {
46518
+ if (this.lastLiveSampleAt < 0) {
46519
+ return { active: false, lastLiveAt: null, expiresAt: null, remainingMs: 0 };
46520
+ }
46521
+ const bound = this.opts.leaseBoundMs ?? BUSY_LEASE_BOUND_MS;
46522
+ const expiresAt = this.lastLiveSampleAt + bound;
46523
+ const remainingMs = Math.max(0, expiresAt - now);
46524
+ return { active: remainingMs > 0, lastLiveAt: this.lastLiveSampleAt, expiresAt, remainingMs };
46525
+ }
46475
46526
  /** Stage-0 shadow log: emit one line when the normalized observation
46476
46527
  * CHANGES. This log is the Stage 1-3 judgment input ("which signals were
46477
46528
  * actually observable, and when"), so it carries the full signal set —
@@ -51909,7 +51960,11 @@ var CliProviderInstance = class _CliProviderInstance {
51909
51960
  // final_assistant_present signal rather than duplicating
51910
51961
  // the message scan.
51911
51962
  finalAssistantPresent: (msgs, ts2) => this.completionHasFinalAssistantMessage(msgs, ts2),
51912
- growthQuietMs: MISSING_ASSISTANT_TRANSCRIPT_GROWTH_QUIET_MS
51963
+ growthQuietMs: MISSING_ASSISTANT_TRANSCRIPT_GROWTH_QUIET_MS,
51964
+ // TX-FSM Stage 2: the lease bound follows the rollout gate's
51965
+ // (possibly env-overridden) value; the gate's enabled flag is
51966
+ // consulted per judgment, not here.
51967
+ leaseBoundMs: resolveBusyLeaseGate(this.type).boundMs
51913
51968
  });
51914
51969
  }
51915
51970
  const snapshot = this.transcriptSignalSource.update(
@@ -52510,6 +52565,21 @@ var CliProviderInstance = class _CliProviderInstance {
52510
52565
  }
52511
52566
  return { snapshot: this.lastTranscriptSignalSnapshot, messages };
52512
52567
  }
52568
+ /**
52569
+ * TX-FSM Stage 2: is the bounded busy lease enabled for THIS provider?
52570
+ * This is the canary rollout gate (busy-lease-gate.ts) — a per-provider
52571
+ * feature switch, NOT a classification (transcript class/timing still come
52572
+ * from resolveTranscriptAuthorityProfile only). Resolved per call so an
52573
+ * env-driven rollout change takes effect without rebuilding the instance;
52574
+ * any resolver error fails closed (lease disabled → pre-Stage-2 behavior).
52575
+ */
52576
+ busyLeaseGateEnabled() {
52577
+ try {
52578
+ return resolveBusyLeaseGate(this.type).enabled;
52579
+ } catch {
52580
+ return false;
52581
+ }
52582
+ }
52513
52583
  /**
52514
52584
  * KIMI-MESH-COMPLETION-EMIT (axis 2). Last-chance completion emit for a mesh
52515
52585
  * DELEGATED worker whose PTY has already exited (e.g. killed by a false stall)
@@ -52936,6 +53006,28 @@ var CliProviderInstance = class _CliProviderInstance {
52936
53006
  this.scheduleCompletedDebounceFlush(COMPLETED_FINALIZATION_RETRY_MS);
52937
53007
  return;
52938
53008
  }
53009
+ if (growthSnapshot?.available === true && this.busyLeaseGateEnabled()) {
53010
+ const lease = this.transcriptSignalSource?.busyLease() ?? null;
53011
+ if (lease?.active === true) {
53012
+ if (pending.loggedBlockReason !== "busy_lease_active") {
53013
+ 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`);
53014
+ if (this.isMeshWorkerSession()) {
53015
+ traceMeshEventDrop("completion_gate_hold", this.meshTraceCtx(), `busy_lease_active lastLiveAt=${lease.lastLiveAt} expiresIn=${lease.remainingMs}ms`);
53016
+ }
53017
+ if (this.completionTraceOn()) this.recordCompletionGateTrace("hold", {
53018
+ blockReason: "busy_lease_active",
53019
+ latestVisibleStatus,
53020
+ leaseLastLiveAt: lease.lastLiveAt,
53021
+ leaseExpiresAt: lease.expiresAt,
53022
+ leaseRemainingMs: lease.remainingMs,
53023
+ waitedMs
53024
+ });
53025
+ pending.loggedBlockReason = "busy_lease_active";
53026
+ }
53027
+ this.scheduleCompletedDebounceFlush(COMPLETED_FINALIZATION_RETRY_MS);
53028
+ return;
53029
+ }
53030
+ }
52939
53031
  }
52940
53032
  if (!isTranscriptEvidenceGate && (block2.terminal || waitedMs < COMPLETED_FINALIZATION_MAX_WAIT_MS)) {
52941
53033
  if (pending.loggedBlockReason !== blockReason) {