@adhdev/daemon-core 0.9.82-rc.532 → 0.9.82-rc.533

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.
@@ -149,6 +149,32 @@ export declare class ProviderCliAdapter implements CliAdapter {
149
149
  private clearAllTimers;
150
150
  runParseSession(): ParsedSession | null;
151
151
  runDetectStatus(text: string): string | null;
152
+ /**
153
+ * WRITE-READINESS ONNOMATCH (opencode): resolve whether the session is
154
+ * genuinely idle *for the purpose of opening the PTY write gate*, honoring
155
+ * the manifest's `dispatchOrder.onNoMatch` policy.
156
+ *
157
+ * The split-brain this closes: the engine's settled evaluation runs
158
+ * detectStatus through parseSession, whose builder collapses a null verdict
159
+ * to `'idle'` (buildParseSessionFromTui: `detectStatus(input) ?? 'idle'`),
160
+ * so the dashboard status flips to idle via `script_detect`. But the
161
+ * write-readiness gates (resolveStartupState / sendMessage recovery) call
162
+ * `runDetectStatus` *directly* and require the literal `=== 'idle'` return —
163
+ * they never apply the `onNoMatch` policy. opencode's only idle cue is the
164
+ * `Ask anything` composer placeholder in the last-8-lines scope with
165
+ * `onNoMatch: preserve-last`; when that placeholder is momentarily out of
166
+ * frame the raw detector returns null, the gate stays shut, `this.ready`
167
+ * never flips, and the first queued prompt sits in `not_ready_pending_prompt`
168
+ * forever (no turn ever starts, so no turn-completion drain fires).
169
+ *
170
+ * The fix keeps the raw detector as the primary signal (unchanged behavior
171
+ * for providers whose detector returns a literal idle) and only falls back
172
+ * when BOTH (a) the manifest policy is idle-preserving (`preserve-last` or
173
+ * `idle`) AND (b) the engine has *durably* settled to idle (no in-flight
174
+ * turn, no modal, no parse error). That guard makes the fallback safe: it
175
+ * cannot open the gate mid-turn or while a modal is up.
176
+ */
177
+ private detectIdleHonoringOnNoMatch;
152
178
  runParseApproval(tail: string): {
153
179
  message: string;
154
180
  buttons: string[];
package/dist/index.js CHANGED
@@ -419,10 +419,10 @@ function readInjected(value) {
419
419
  }
420
420
  function getDaemonBuildInfo() {
421
421
  if (cached) return cached;
422
- const commit = readInjected(true ? "2dcb1909a41f2358986e408601c8a1284c6f3685" : void 0) ?? "unknown";
423
- const commitShort = readInjected(true ? "2dcb1909" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
424
- const version = readInjected(true ? "0.9.82-rc.532" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
425
- const builtAt = readInjected(true ? "2026-07-15T07:14:52.163Z" : void 0);
422
+ const commit = readInjected(true ? "4bcba3bd84cc9f4cd08a3d93965f10f43fcf5dad" : void 0) ?? "unknown";
423
+ const commitShort = readInjected(true ? "4bcba3bd" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
424
+ const version = readInjected(true ? "0.9.82-rc.533" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
425
+ const builtAt = readInjected(true ? "2026-07-15T07:45:39.050Z" : void 0);
426
426
  cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
427
427
  return cached;
428
428
  }
@@ -26901,8 +26901,8 @@ ${lastSnapshot}`;
26901
26901
  const stableMs = this.lastScreenChangeAt ? now - this.lastScreenChangeAt : 0;
26902
26902
  if (stableMs < 2e3) return;
26903
26903
  const startupModal = this.runParseApproval(this.recentOutputBuffer);
26904
- const startupStatus = this.runDetectStatus(screenText || this.recentOutputBuffer);
26905
- if (!startupModal && startupStatus !== "idle") {
26904
+ const startupIdle = this.detectIdleHonoringOnNoMatch(screenText || this.recentOutputBuffer);
26905
+ if (!startupModal && !startupIdle) {
26906
26906
  this.scheduleStartupSettleCheck();
26907
26907
  return;
26908
26908
  }
@@ -27038,6 +27038,38 @@ ${lastSnapshot}`;
27038
27038
  tailScreen: buildCliScreenSnapshot(tail)
27039
27039
  });
27040
27040
  }
27041
+ /**
27042
+ * WRITE-READINESS ONNOMATCH (opencode): resolve whether the session is
27043
+ * genuinely idle *for the purpose of opening the PTY write gate*, honoring
27044
+ * the manifest's `dispatchOrder.onNoMatch` policy.
27045
+ *
27046
+ * The split-brain this closes: the engine's settled evaluation runs
27047
+ * detectStatus through parseSession, whose builder collapses a null verdict
27048
+ * to `'idle'` (buildParseSessionFromTui: `detectStatus(input) ?? 'idle'`),
27049
+ * so the dashboard status flips to idle via `script_detect`. But the
27050
+ * write-readiness gates (resolveStartupState / sendMessage recovery) call
27051
+ * `runDetectStatus` *directly* and require the literal `=== 'idle'` return —
27052
+ * they never apply the `onNoMatch` policy. opencode's only idle cue is the
27053
+ * `Ask anything` composer placeholder in the last-8-lines scope with
27054
+ * `onNoMatch: preserve-last`; when that placeholder is momentarily out of
27055
+ * frame the raw detector returns null, the gate stays shut, `this.ready`
27056
+ * never flips, and the first queued prompt sits in `not_ready_pending_prompt`
27057
+ * forever (no turn ever starts, so no turn-completion drain fires).
27058
+ *
27059
+ * The fix keeps the raw detector as the primary signal (unchanged behavior
27060
+ * for providers whose detector returns a literal idle) and only falls back
27061
+ * when BOTH (a) the manifest policy is idle-preserving (`preserve-last` or
27062
+ * `idle`) AND (b) the engine has *durably* settled to idle (no in-flight
27063
+ * turn, no modal, no parse error). That guard makes the fallback safe: it
27064
+ * cannot open the gate mid-turn or while a modal is up.
27065
+ */
27066
+ detectIdleHonoringOnNoMatch(text) {
27067
+ if (this.runDetectStatus(text) === "idle") return true;
27068
+ const dispatchOrder = this.provider.tui?.dispatchOrder;
27069
+ const onNoMatch = dispatchOrder?.onNoMatch;
27070
+ if (onNoMatch !== "preserve-last" && onNoMatch !== "idle") return false;
27071
+ return this.engine.currentStatus === "idle" && !this.engine.isWaitingForResponse && !this.engine.currentTurnScope && !this.engine.activeModal && !this.parseErrorMessage;
27072
+ }
27041
27073
  runParseApproval(tail) {
27042
27074
  const screenText = this.terminalScreen.getText();
27043
27075
  const buffer = screenText || this.accumulatedBuffer;
@@ -27570,7 +27602,7 @@ ${lastSnapshot}`;
27570
27602
  }
27571
27603
  if (!this.ready) {
27572
27604
  this.resolveStartupState("send_precheck");
27573
- if (this.runDetectStatus(this.recentOutputBuffer) === "idle") {
27605
+ if (!this.ready && this.detectIdleHonoringOnNoMatch(this.recentOutputBuffer)) {
27574
27606
  this.ready = true;
27575
27607
  this.startupParseGate = false;
27576
27608
  this.engine.setStatus("idle", "send_message_idle_prompt_recovery");