@adhdev/daemon-core 0.9.82-rc.268 → 0.9.82-rc.269

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
@@ -260,10 +260,10 @@ function readInjected(value) {
260
260
  }
261
261
  function getDaemonBuildInfo() {
262
262
  if (cached) return cached;
263
- const commit = readInjected(true ? "9da2b92afe11e5b813734c9f389479542e25a41f" : void 0) ?? "unknown";
264
- const commitShort = readInjected(true ? "9da2b92a" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
265
- const version = readInjected(true ? "0.9.82-rc.268" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
266
- const builtAt = readInjected(true ? "2026-06-14T21:47:03.827Z" : void 0);
263
+ const commit = readInjected(true ? "025d8bef81a66e7b44a5ba5d5a04e063db46db4e" : void 0) ?? "unknown";
264
+ const commitShort = readInjected(true ? "025d8bef" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
265
+ const version = readInjected(true ? "0.9.82-rc.269" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
266
+ const builtAt = readInjected(true ? "2026-06-14T22:11:38.134Z" : void 0);
267
267
  cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
268
268
  return cached;
269
269
  }
@@ -9496,7 +9496,7 @@ var init_ghostty_vt_backend = __esm({
9496
9496
  "@adhdev/ghostty-vt-node"
9497
9497
  ];
9498
9498
  cachedBindingError = null;
9499
- GhosttyVtTerminalBackend = class {
9499
+ GhosttyVtTerminalBackend = class _GhosttyVtTerminalBackend {
9500
9500
  kind = "ghostty-vt";
9501
9501
  terminal;
9502
9502
  rows;
@@ -9518,17 +9518,30 @@ var init_ghostty_vt_backend = __esm({
9518
9518
  if (!data || this.disposed) return;
9519
9519
  this.terminal.write(data);
9520
9520
  }
9521
+ formatLines() {
9522
+ const raw = this.terminal.formatPlainText({ trim: false }) || "";
9523
+ if (!raw) return [];
9524
+ return raw.split("\n").map((row) => row.replace(/\s+$/, ""));
9525
+ }
9526
+ static trimBlankEnds(lines) {
9527
+ let first = 0;
9528
+ let last = lines.length;
9529
+ while (first < last && !lines[first]) first += 1;
9530
+ while (last > first && !lines[last - 1]) last -= 1;
9531
+ return lines.slice(first, last).join("\n");
9532
+ }
9521
9533
  getText() {
9522
9534
  if (this.disposed) return "";
9523
- const raw = this.terminal.formatPlainText({ trim: false }) || "";
9524
- if (!raw) return "";
9525
- const lines = raw.split("\n").map((row) => row.replace(/\s+$/, ""));
9535
+ const lines = this.formatLines();
9536
+ if (lines.length === 0) return "";
9526
9537
  const viewport = lines.length > this.rows ? lines.slice(-this.rows) : lines;
9527
- let first = 0;
9528
- let last = viewport.length;
9529
- while (first < last && !viewport[first]) first += 1;
9530
- while (last > first && !viewport[last - 1]) last -= 1;
9531
- return viewport.slice(first, last).join("\n");
9538
+ return _GhosttyVtTerminalBackend.trimBlankEnds(viewport);
9539
+ }
9540
+ getTextWithScrollback() {
9541
+ if (this.disposed) return "";
9542
+ const lines = this.formatLines();
9543
+ if (lines.length === 0) return "";
9544
+ return _GhosttyVtTerminalBackend.trimBlankEnds(lines);
9532
9545
  }
9533
9546
  getCursorPosition() {
9534
9547
  if (this.disposed) return { col: 0, row: 0 };
@@ -9581,6 +9594,10 @@ var init_terminal_screen = __esm({
9581
9594
  getText() {
9582
9595
  return this.terminal.getText();
9583
9596
  }
9597
+ /** Full buffer including scrollback history (see backend doc). */
9598
+ getTextWithScrollback() {
9599
+ return this.terminal.getTextWithScrollback();
9600
+ }
9584
9601
  getCursorPosition() {
9585
9602
  return this.terminal.getCursorPosition();
9586
9603
  }
@@ -28985,6 +29002,15 @@ var TerminalAdapter = class {
28985
29002
  snapshot() {
28986
29003
  return this.lastScreen || this.computeScreen();
28987
29004
  }
29005
+ /**
29006
+ * Full-buffer snapshot including scrollback history. Unlike snapshot()
29007
+ * (visible viewport only), this survives a tall prompt whose top has
29008
+ * scrolled off-screen — used for content-pattern extraction (modal
29009
+ * buttons / approval anchors), NOT for cursor-relative conditions.
29010
+ */
29011
+ snapshotWithScrollback() {
29012
+ return this.screen.getTextWithScrollback();
29013
+ }
28988
29014
  getCursorPosition() {
28989
29015
  const pos = this.screen.getCursorPosition();
28990
29016
  return { row: pos.row, col: pos.col };
@@ -29159,6 +29185,18 @@ var FsmDriver = class {
29159
29185
  getScreen() {
29160
29186
  return this.adapter.snapshot();
29161
29187
  }
29188
+ /** Scrollback-inclusive screen as line array — used only for modal/button
29189
+ * content extraction so a tall prompt's off-screen anchors stay matchable.
29190
+ * Falls back to the viewport snapshot if scrollback read is unavailable. */
29191
+ scrollbackLines() {
29192
+ let screen = "";
29193
+ try {
29194
+ screen = this.adapter.snapshotWithScrollback();
29195
+ } catch {
29196
+ }
29197
+ if (!screen) screen = this.adapter.snapshot();
29198
+ return screen.split("\n").map((l) => l.endsWith("\r") ? l.slice(0, -1) : l);
29199
+ }
29162
29200
  getSpecPath() {
29163
29201
  return this.opts.specPath;
29164
29202
  }
@@ -29340,9 +29378,12 @@ var FsmDriver = class {
29340
29378
  const screen = this.adapter.snapshot();
29341
29379
  const lines = screen.split("\n").map((l) => l.endsWith("\r") ? l.slice(0, -1) : l);
29342
29380
  const sections = resolveSections(this.spec.sections ?? {}, lines);
29343
- const modal = this.deriveModal(state, sections, lines.join("\n"));
29381
+ const modalLines = state.modal ? this.scrollbackLines() : lines;
29382
+ const modalSections = state.modal ? resolveSections(this.spec.sections ?? {}, modalLines) : sections;
29383
+ const modalFullScreen = modalLines.join("\n");
29384
+ const modal = this.deriveModal(state, modalSections, modalFullScreen);
29344
29385
  const controls = this.deriveControls(state.id);
29345
- const title = modal?.title ?? this.deriveTitle(state, sections, lines.join("\n"));
29386
+ const title = modal?.title ?? this.deriveTitle(state, modalSections, modalFullScreen);
29346
29387
  const next = {
29347
29388
  // status is derived from the FSM state itself (statusForState), NOT from
29348
29389
  // whether a modal was parsed this frame. A modal state whose buttons briefly
@@ -31213,7 +31254,7 @@ async function waitForCliAdapterReady(adapter, options) {
31213
31254
  }
31214
31255
  throw new Error(`CLI runtime did not become ready within ${timeoutMs}ms`);
31215
31256
  }
31216
- var CliProviderInstance = class {
31257
+ var CliProviderInstance = class _CliProviderInstance {
31217
31258
  constructor(provider, workingDir, cliArgs = [], instanceId, transportFactory, options) {
31218
31259
  this.provider = provider;
31219
31260
  this.workingDir = workingDir;
@@ -31233,6 +31274,18 @@ var CliProviderInstance = class {
31233
31274
  }
31234
31275
  type;
31235
31276
  category = "cli";
31277
+ /**
31278
+ * Quiet period an approval modal's signature must be stable before
31279
+ * auto-approve sends the approve key. Guards against firing on a prompt
31280
+ * that is still streaming into the PTY (the "resolves too fast" symptom):
31281
+ * while the modal text/buttons are still changing, every frame yields a
31282
+ * new signature and the settle clock restarts. Once the prompt finishes
31283
+ * rendering the signature holds and the key is sent after this window.
31284
+ * Bounded + small so genuine approvals stay timely. The FSM is already
31285
+ * authoritative over the `waiting_approval` state; this only delays the
31286
+ * keystroke until the modal *content* has settled.
31287
+ */
31288
+ static AUTO_APPROVE_SETTLE_MS = 600;
31236
31289
  adapter;
31237
31290
  context = null;
31238
31291
  events = [];
@@ -31246,6 +31299,14 @@ var CliProviderInstance = class {
31246
31299
  autoApproveBusy = false;
31247
31300
  autoApproveBusyTimer = null;
31248
31301
  lastAutoApprovalSignature = "";
31302
+ // Settle gate: the approval modal's signature + the wall-clock when this
31303
+ // exact signature was first observed. Auto-approve only fires once the
31304
+ // SAME signature has been stable for AUTO_APPROVE_SETTLE_MS, so a prompt
31305
+ // still streaming into the PTY (its buttons/message changing frame to
31306
+ // frame) keeps resetting the timer and is never approved half-rendered.
31307
+ pendingAutoApprovalSignature = "";
31308
+ pendingAutoApprovalSince = 0;
31309
+ autoApproveSettleTimer = null;
31249
31310
  controlValues = {};
31250
31311
  summaryMetadata = void 0;
31251
31312
  appliedEffectKeys = /* @__PURE__ */ new Set();
@@ -31680,6 +31741,14 @@ var CliProviderInstance = class {
31680
31741
  dispose() {
31681
31742
  this.adapter.shutdown();
31682
31743
  this.monitor.reset();
31744
+ if (this.autoApproveSettleTimer) {
31745
+ clearTimeout(this.autoApproveSettleTimer);
31746
+ this.autoApproveSettleTimer = null;
31747
+ }
31748
+ if (this.autoApproveBusyTimer) {
31749
+ clearTimeout(this.autoApproveBusyTimer);
31750
+ this.autoApproveBusyTimer = null;
31751
+ }
31683
31752
  this.appliedEffectKeys.clear();
31684
31753
  try {
31685
31754
  this.cachedSqliteDb?.close();
@@ -32030,6 +32099,12 @@ var CliProviderInstance = class {
32030
32099
  const autoApproveActive = adapterStatus?.status === "waiting_approval" && this.shouldAutoApprove();
32031
32100
  if (!autoApproveActive) {
32032
32101
  this.lastAutoApprovalSignature = "";
32102
+ this.pendingAutoApprovalSignature = "";
32103
+ this.pendingAutoApprovalSince = 0;
32104
+ if (this.autoApproveSettleTimer) {
32105
+ clearTimeout(this.autoApproveSettleTimer);
32106
+ this.autoApproveSettleTimer = null;
32107
+ }
32033
32108
  return autoApproveActive;
32034
32109
  }
32035
32110
  const modal = adapterStatus.activeModal;
@@ -32048,22 +32123,57 @@ var CliProviderInstance = class {
32048
32123
  buttons.join("|"),
32049
32124
  buttonIndex
32050
32125
  ].join("::");
32051
- if (!this.autoApproveBusy || signature !== this.lastAutoApprovalSignature) {
32052
- this.autoApproveBusy = true;
32053
- this.lastAutoApprovalSignature = signature;
32054
- if (this.autoApproveBusyTimer) clearTimeout(this.autoApproveBusyTimer);
32055
- this.autoApproveBusyTimer = setTimeout(() => {
32056
- this.autoApproveBusy = false;
32057
- this.autoApproveBusyTimer = null;
32058
- this.lastAutoApprovalSignature = "";
32059
- }, 5e3);
32060
- this.recordAutoApproval(modal?.message, buttonLabel, now);
32061
- setTimeout(() => {
32062
- this.adapter.resolveModal(buttonIndex);
32063
- }, 0);
32126
+ if (this.autoApproveBusy && signature === this.lastAutoApprovalSignature) {
32127
+ return autoApproveActive;
32064
32128
  }
32129
+ if (signature !== this.pendingAutoApprovalSignature) {
32130
+ this.pendingAutoApprovalSignature = signature;
32131
+ this.pendingAutoApprovalSince = now;
32132
+ }
32133
+ const settledForMs = now - this.pendingAutoApprovalSince;
32134
+ if (settledForMs < _CliProviderInstance.AUTO_APPROVE_SETTLE_MS) {
32135
+ if (this.autoApproveSettleTimer) clearTimeout(this.autoApproveSettleTimer);
32136
+ this.autoApproveSettleTimer = setTimeout(() => {
32137
+ this.autoApproveSettleTimer = null;
32138
+ this.recheckAutoApproveSettled();
32139
+ }, _CliProviderInstance.AUTO_APPROVE_SETTLE_MS - settledForMs + 20);
32140
+ return autoApproveActive;
32141
+ }
32142
+ if (this.autoApproveSettleTimer) {
32143
+ clearTimeout(this.autoApproveSettleTimer);
32144
+ this.autoApproveSettleTimer = null;
32145
+ }
32146
+ this.autoApproveBusy = true;
32147
+ this.lastAutoApprovalSignature = signature;
32148
+ this.pendingAutoApprovalSignature = "";
32149
+ this.pendingAutoApprovalSince = 0;
32150
+ if (this.autoApproveBusyTimer) clearTimeout(this.autoApproveBusyTimer);
32151
+ this.autoApproveBusyTimer = setTimeout(() => {
32152
+ this.autoApproveBusy = false;
32153
+ this.autoApproveBusyTimer = null;
32154
+ this.lastAutoApprovalSignature = "";
32155
+ }, 5e3);
32156
+ this.recordAutoApproval(modal?.message, buttonLabel, now);
32157
+ setTimeout(() => {
32158
+ this.adapter.resolveModal(buttonIndex);
32159
+ }, 0);
32065
32160
  return autoApproveActive;
32066
32161
  }
32162
+ /**
32163
+ * Re-drive the auto-approve check after the settle quiet window elapses.
32164
+ * The PTY may have gone silent once the approval prompt finished painting,
32165
+ * so no status-change frame is guaranteed to re-enter maybeAutoApproveStatus
32166
+ * — this timer-driven re-check picks up the now-settled modal and fires.
32167
+ * Deliberately lighter than detectStatusTransition(): it only re-evaluates
32168
+ * the approval decision; the next real PTY frame refreshes visible status.
32169
+ */
32170
+ recheckAutoApproveSettled() {
32171
+ try {
32172
+ const adapterStatus = this.adapter.getStatus({ allowParse: false });
32173
+ this.maybeAutoApproveStatus(adapterStatus, Date.now());
32174
+ } catch {
32175
+ }
32176
+ }
32067
32177
  detectStatusTransition() {
32068
32178
  const now = Date.now();
32069
32179
  const adapterStatus = this.adapter.getStatus({ allowParse: false });