@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/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +3 -0
- package/dist/cli-adapters/terminal-backends/types.d.ts +9 -0
- package/dist/cli-adapters/terminal-screen.d.ts +2 -0
- package/dist/index.js +139 -29
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +139 -29
- package/dist/index.mjs.map +1 -1
- package/dist/providers/cli-provider-instance.d.ts +24 -0
- package/dist/providers/spec/adapter.d.ts +7 -0
- package/dist/providers/spec/fsm-driver.d.ts +4 -0
- package/package.json +2 -2
- package/src/cli-adapters/terminal-backends/ghostty-vt-backend.ts +28 -10
- package/src/cli-adapters/terminal-backends/types.ts +9 -0
- package/src/cli-adapters/terminal-screen.ts +5 -0
- package/src/providers/cli-provider-instance.ts +87 -13
- package/src/providers/spec/adapter.ts +10 -0
- package/src/providers/spec/fsm-driver.ts +31 -2
|
@@ -7,7 +7,10 @@ export declare class GhosttyVtTerminalBackend implements TerminalViewportBackend
|
|
|
7
7
|
constructor(options: TerminalViewportBackendOptions);
|
|
8
8
|
resize(rows: number, cols: number): void;
|
|
9
9
|
write(data: string): void;
|
|
10
|
+
private formatLines;
|
|
11
|
+
private static trimBlankEnds;
|
|
10
12
|
getText(): string;
|
|
13
|
+
getTextWithScrollback(): string;
|
|
11
14
|
getCursorPosition(): {
|
|
12
15
|
col: number;
|
|
13
16
|
row: number;
|
|
@@ -9,6 +9,15 @@ export interface TerminalViewportBackend {
|
|
|
9
9
|
resize(rows: number, cols: number): void;
|
|
10
10
|
write(data: string): void;
|
|
11
11
|
getText(): string;
|
|
12
|
+
/**
|
|
13
|
+
* Like getText() but includes scrollback history (the lines that have
|
|
14
|
+
* scrolled above the visible viewport). Used by content-pattern matching
|
|
15
|
+
* (e.g. approval/modal button extraction) that must stay correct when a
|
|
16
|
+
* tall prompt — a big diff or long explanation — pushes part of the
|
|
17
|
+
* prompt box above the viewport. NOT for cursor-relative / stable_ms
|
|
18
|
+
* conditions, whose row indices are viewport-relative.
|
|
19
|
+
*/
|
|
20
|
+
getTextWithScrollback(): string;
|
|
12
21
|
getCursorPosition(): {
|
|
13
22
|
col: number;
|
|
14
23
|
row: number;
|
|
@@ -15,6 +15,8 @@ export declare class TerminalScreen {
|
|
|
15
15
|
resize(rows: number, cols: number): void;
|
|
16
16
|
write(data: string): void;
|
|
17
17
|
getText(): string;
|
|
18
|
+
/** Full buffer including scrollback history (see backend doc). */
|
|
19
|
+
getTextWithScrollback(): string;
|
|
18
20
|
getCursorPosition(): {
|
|
19
21
|
col: number;
|
|
20
22
|
row: number;
|
package/dist/index.js
CHANGED
|
@@ -265,10 +265,10 @@ function readInjected(value) {
|
|
|
265
265
|
}
|
|
266
266
|
function getDaemonBuildInfo() {
|
|
267
267
|
if (cached) return cached;
|
|
268
|
-
const commit = readInjected(true ? "
|
|
269
|
-
const commitShort = readInjected(true ? "
|
|
270
|
-
const version = readInjected(true ? "0.9.82-rc.
|
|
271
|
-
const builtAt = readInjected(true ? "2026-06-
|
|
268
|
+
const commit = readInjected(true ? "025d8bef81a66e7b44a5ba5d5a04e063db46db4e" : void 0) ?? "unknown";
|
|
269
|
+
const commitShort = readInjected(true ? "025d8bef" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
270
|
+
const version = readInjected(true ? "0.9.82-rc.269" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
271
|
+
const builtAt = readInjected(true ? "2026-06-14T22:11:38.134Z" : void 0);
|
|
272
272
|
cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
|
|
273
273
|
return cached;
|
|
274
274
|
}
|
|
@@ -9503,7 +9503,7 @@ var init_ghostty_vt_backend = __esm({
|
|
|
9503
9503
|
"@adhdev/ghostty-vt-node"
|
|
9504
9504
|
];
|
|
9505
9505
|
cachedBindingError = null;
|
|
9506
|
-
GhosttyVtTerminalBackend = class {
|
|
9506
|
+
GhosttyVtTerminalBackend = class _GhosttyVtTerminalBackend {
|
|
9507
9507
|
kind = "ghostty-vt";
|
|
9508
9508
|
terminal;
|
|
9509
9509
|
rows;
|
|
@@ -9525,17 +9525,30 @@ var init_ghostty_vt_backend = __esm({
|
|
|
9525
9525
|
if (!data || this.disposed) return;
|
|
9526
9526
|
this.terminal.write(data);
|
|
9527
9527
|
}
|
|
9528
|
+
formatLines() {
|
|
9529
|
+
const raw = this.terminal.formatPlainText({ trim: false }) || "";
|
|
9530
|
+
if (!raw) return [];
|
|
9531
|
+
return raw.split("\n").map((row) => row.replace(/\s+$/, ""));
|
|
9532
|
+
}
|
|
9533
|
+
static trimBlankEnds(lines) {
|
|
9534
|
+
let first = 0;
|
|
9535
|
+
let last = lines.length;
|
|
9536
|
+
while (first < last && !lines[first]) first += 1;
|
|
9537
|
+
while (last > first && !lines[last - 1]) last -= 1;
|
|
9538
|
+
return lines.slice(first, last).join("\n");
|
|
9539
|
+
}
|
|
9528
9540
|
getText() {
|
|
9529
9541
|
if (this.disposed) return "";
|
|
9530
|
-
const
|
|
9531
|
-
if (
|
|
9532
|
-
const lines = raw.split("\n").map((row) => row.replace(/\s+$/, ""));
|
|
9542
|
+
const lines = this.formatLines();
|
|
9543
|
+
if (lines.length === 0) return "";
|
|
9533
9544
|
const viewport = lines.length > this.rows ? lines.slice(-this.rows) : lines;
|
|
9534
|
-
|
|
9535
|
-
|
|
9536
|
-
|
|
9537
|
-
|
|
9538
|
-
|
|
9545
|
+
return _GhosttyVtTerminalBackend.trimBlankEnds(viewport);
|
|
9546
|
+
}
|
|
9547
|
+
getTextWithScrollback() {
|
|
9548
|
+
if (this.disposed) return "";
|
|
9549
|
+
const lines = this.formatLines();
|
|
9550
|
+
if (lines.length === 0) return "";
|
|
9551
|
+
return _GhosttyVtTerminalBackend.trimBlankEnds(lines);
|
|
9539
9552
|
}
|
|
9540
9553
|
getCursorPosition() {
|
|
9541
9554
|
if (this.disposed) return { col: 0, row: 0 };
|
|
@@ -9588,6 +9601,10 @@ var init_terminal_screen = __esm({
|
|
|
9588
9601
|
getText() {
|
|
9589
9602
|
return this.terminal.getText();
|
|
9590
9603
|
}
|
|
9604
|
+
/** Full buffer including scrollback history (see backend doc). */
|
|
9605
|
+
getTextWithScrollback() {
|
|
9606
|
+
return this.terminal.getTextWithScrollback();
|
|
9607
|
+
}
|
|
9591
9608
|
getCursorPosition() {
|
|
9592
9609
|
return this.terminal.getCursorPosition();
|
|
9593
9610
|
}
|
|
@@ -29325,6 +29342,15 @@ var TerminalAdapter = class {
|
|
|
29325
29342
|
snapshot() {
|
|
29326
29343
|
return this.lastScreen || this.computeScreen();
|
|
29327
29344
|
}
|
|
29345
|
+
/**
|
|
29346
|
+
* Full-buffer snapshot including scrollback history. Unlike snapshot()
|
|
29347
|
+
* (visible viewport only), this survives a tall prompt whose top has
|
|
29348
|
+
* scrolled off-screen — used for content-pattern extraction (modal
|
|
29349
|
+
* buttons / approval anchors), NOT for cursor-relative conditions.
|
|
29350
|
+
*/
|
|
29351
|
+
snapshotWithScrollback() {
|
|
29352
|
+
return this.screen.getTextWithScrollback();
|
|
29353
|
+
}
|
|
29328
29354
|
getCursorPosition() {
|
|
29329
29355
|
const pos = this.screen.getCursorPosition();
|
|
29330
29356
|
return { row: pos.row, col: pos.col };
|
|
@@ -29499,6 +29525,18 @@ var FsmDriver = class {
|
|
|
29499
29525
|
getScreen() {
|
|
29500
29526
|
return this.adapter.snapshot();
|
|
29501
29527
|
}
|
|
29528
|
+
/** Scrollback-inclusive screen as line array — used only for modal/button
|
|
29529
|
+
* content extraction so a tall prompt's off-screen anchors stay matchable.
|
|
29530
|
+
* Falls back to the viewport snapshot if scrollback read is unavailable. */
|
|
29531
|
+
scrollbackLines() {
|
|
29532
|
+
let screen = "";
|
|
29533
|
+
try {
|
|
29534
|
+
screen = this.adapter.snapshotWithScrollback();
|
|
29535
|
+
} catch {
|
|
29536
|
+
}
|
|
29537
|
+
if (!screen) screen = this.adapter.snapshot();
|
|
29538
|
+
return screen.split("\n").map((l) => l.endsWith("\r") ? l.slice(0, -1) : l);
|
|
29539
|
+
}
|
|
29502
29540
|
getSpecPath() {
|
|
29503
29541
|
return this.opts.specPath;
|
|
29504
29542
|
}
|
|
@@ -29680,9 +29718,12 @@ var FsmDriver = class {
|
|
|
29680
29718
|
const screen = this.adapter.snapshot();
|
|
29681
29719
|
const lines = screen.split("\n").map((l) => l.endsWith("\r") ? l.slice(0, -1) : l);
|
|
29682
29720
|
const sections = resolveSections(this.spec.sections ?? {}, lines);
|
|
29683
|
-
const
|
|
29721
|
+
const modalLines = state.modal ? this.scrollbackLines() : lines;
|
|
29722
|
+
const modalSections = state.modal ? resolveSections(this.spec.sections ?? {}, modalLines) : sections;
|
|
29723
|
+
const modalFullScreen = modalLines.join("\n");
|
|
29724
|
+
const modal = this.deriveModal(state, modalSections, modalFullScreen);
|
|
29684
29725
|
const controls = this.deriveControls(state.id);
|
|
29685
|
-
const title = modal?.title ?? this.deriveTitle(state,
|
|
29726
|
+
const title = modal?.title ?? this.deriveTitle(state, modalSections, modalFullScreen);
|
|
29686
29727
|
const next = {
|
|
29687
29728
|
// status is derived from the FSM state itself (statusForState), NOT from
|
|
29688
29729
|
// whether a modal was parsed this frame. A modal state whose buttons briefly
|
|
@@ -31553,7 +31594,7 @@ async function waitForCliAdapterReady(adapter, options) {
|
|
|
31553
31594
|
}
|
|
31554
31595
|
throw new Error(`CLI runtime did not become ready within ${timeoutMs}ms`);
|
|
31555
31596
|
}
|
|
31556
|
-
var CliProviderInstance = class {
|
|
31597
|
+
var CliProviderInstance = class _CliProviderInstance {
|
|
31557
31598
|
constructor(provider, workingDir, cliArgs = [], instanceId, transportFactory, options) {
|
|
31558
31599
|
this.provider = provider;
|
|
31559
31600
|
this.workingDir = workingDir;
|
|
@@ -31573,6 +31614,18 @@ var CliProviderInstance = class {
|
|
|
31573
31614
|
}
|
|
31574
31615
|
type;
|
|
31575
31616
|
category = "cli";
|
|
31617
|
+
/**
|
|
31618
|
+
* Quiet period an approval modal's signature must be stable before
|
|
31619
|
+
* auto-approve sends the approve key. Guards against firing on a prompt
|
|
31620
|
+
* that is still streaming into the PTY (the "resolves too fast" symptom):
|
|
31621
|
+
* while the modal text/buttons are still changing, every frame yields a
|
|
31622
|
+
* new signature and the settle clock restarts. Once the prompt finishes
|
|
31623
|
+
* rendering the signature holds and the key is sent after this window.
|
|
31624
|
+
* Bounded + small so genuine approvals stay timely. The FSM is already
|
|
31625
|
+
* authoritative over the `waiting_approval` state; this only delays the
|
|
31626
|
+
* keystroke until the modal *content* has settled.
|
|
31627
|
+
*/
|
|
31628
|
+
static AUTO_APPROVE_SETTLE_MS = 600;
|
|
31576
31629
|
adapter;
|
|
31577
31630
|
context = null;
|
|
31578
31631
|
events = [];
|
|
@@ -31586,6 +31639,14 @@ var CliProviderInstance = class {
|
|
|
31586
31639
|
autoApproveBusy = false;
|
|
31587
31640
|
autoApproveBusyTimer = null;
|
|
31588
31641
|
lastAutoApprovalSignature = "";
|
|
31642
|
+
// Settle gate: the approval modal's signature + the wall-clock when this
|
|
31643
|
+
// exact signature was first observed. Auto-approve only fires once the
|
|
31644
|
+
// SAME signature has been stable for AUTO_APPROVE_SETTLE_MS, so a prompt
|
|
31645
|
+
// still streaming into the PTY (its buttons/message changing frame to
|
|
31646
|
+
// frame) keeps resetting the timer and is never approved half-rendered.
|
|
31647
|
+
pendingAutoApprovalSignature = "";
|
|
31648
|
+
pendingAutoApprovalSince = 0;
|
|
31649
|
+
autoApproveSettleTimer = null;
|
|
31589
31650
|
controlValues = {};
|
|
31590
31651
|
summaryMetadata = void 0;
|
|
31591
31652
|
appliedEffectKeys = /* @__PURE__ */ new Set();
|
|
@@ -32020,6 +32081,14 @@ var CliProviderInstance = class {
|
|
|
32020
32081
|
dispose() {
|
|
32021
32082
|
this.adapter.shutdown();
|
|
32022
32083
|
this.monitor.reset();
|
|
32084
|
+
if (this.autoApproveSettleTimer) {
|
|
32085
|
+
clearTimeout(this.autoApproveSettleTimer);
|
|
32086
|
+
this.autoApproveSettleTimer = null;
|
|
32087
|
+
}
|
|
32088
|
+
if (this.autoApproveBusyTimer) {
|
|
32089
|
+
clearTimeout(this.autoApproveBusyTimer);
|
|
32090
|
+
this.autoApproveBusyTimer = null;
|
|
32091
|
+
}
|
|
32023
32092
|
this.appliedEffectKeys.clear();
|
|
32024
32093
|
try {
|
|
32025
32094
|
this.cachedSqliteDb?.close();
|
|
@@ -32370,6 +32439,12 @@ var CliProviderInstance = class {
|
|
|
32370
32439
|
const autoApproveActive = adapterStatus?.status === "waiting_approval" && this.shouldAutoApprove();
|
|
32371
32440
|
if (!autoApproveActive) {
|
|
32372
32441
|
this.lastAutoApprovalSignature = "";
|
|
32442
|
+
this.pendingAutoApprovalSignature = "";
|
|
32443
|
+
this.pendingAutoApprovalSince = 0;
|
|
32444
|
+
if (this.autoApproveSettleTimer) {
|
|
32445
|
+
clearTimeout(this.autoApproveSettleTimer);
|
|
32446
|
+
this.autoApproveSettleTimer = null;
|
|
32447
|
+
}
|
|
32373
32448
|
return autoApproveActive;
|
|
32374
32449
|
}
|
|
32375
32450
|
const modal = adapterStatus.activeModal;
|
|
@@ -32388,22 +32463,57 @@ var CliProviderInstance = class {
|
|
|
32388
32463
|
buttons.join("|"),
|
|
32389
32464
|
buttonIndex
|
|
32390
32465
|
].join("::");
|
|
32391
|
-
if (
|
|
32392
|
-
|
|
32393
|
-
this.lastAutoApprovalSignature = signature;
|
|
32394
|
-
if (this.autoApproveBusyTimer) clearTimeout(this.autoApproveBusyTimer);
|
|
32395
|
-
this.autoApproveBusyTimer = setTimeout(() => {
|
|
32396
|
-
this.autoApproveBusy = false;
|
|
32397
|
-
this.autoApproveBusyTimer = null;
|
|
32398
|
-
this.lastAutoApprovalSignature = "";
|
|
32399
|
-
}, 5e3);
|
|
32400
|
-
this.recordAutoApproval(modal?.message, buttonLabel, now);
|
|
32401
|
-
setTimeout(() => {
|
|
32402
|
-
this.adapter.resolveModal(buttonIndex);
|
|
32403
|
-
}, 0);
|
|
32466
|
+
if (this.autoApproveBusy && signature === this.lastAutoApprovalSignature) {
|
|
32467
|
+
return autoApproveActive;
|
|
32404
32468
|
}
|
|
32469
|
+
if (signature !== this.pendingAutoApprovalSignature) {
|
|
32470
|
+
this.pendingAutoApprovalSignature = signature;
|
|
32471
|
+
this.pendingAutoApprovalSince = now;
|
|
32472
|
+
}
|
|
32473
|
+
const settledForMs = now - this.pendingAutoApprovalSince;
|
|
32474
|
+
if (settledForMs < _CliProviderInstance.AUTO_APPROVE_SETTLE_MS) {
|
|
32475
|
+
if (this.autoApproveSettleTimer) clearTimeout(this.autoApproveSettleTimer);
|
|
32476
|
+
this.autoApproveSettleTimer = setTimeout(() => {
|
|
32477
|
+
this.autoApproveSettleTimer = null;
|
|
32478
|
+
this.recheckAutoApproveSettled();
|
|
32479
|
+
}, _CliProviderInstance.AUTO_APPROVE_SETTLE_MS - settledForMs + 20);
|
|
32480
|
+
return autoApproveActive;
|
|
32481
|
+
}
|
|
32482
|
+
if (this.autoApproveSettleTimer) {
|
|
32483
|
+
clearTimeout(this.autoApproveSettleTimer);
|
|
32484
|
+
this.autoApproveSettleTimer = null;
|
|
32485
|
+
}
|
|
32486
|
+
this.autoApproveBusy = true;
|
|
32487
|
+
this.lastAutoApprovalSignature = signature;
|
|
32488
|
+
this.pendingAutoApprovalSignature = "";
|
|
32489
|
+
this.pendingAutoApprovalSince = 0;
|
|
32490
|
+
if (this.autoApproveBusyTimer) clearTimeout(this.autoApproveBusyTimer);
|
|
32491
|
+
this.autoApproveBusyTimer = setTimeout(() => {
|
|
32492
|
+
this.autoApproveBusy = false;
|
|
32493
|
+
this.autoApproveBusyTimer = null;
|
|
32494
|
+
this.lastAutoApprovalSignature = "";
|
|
32495
|
+
}, 5e3);
|
|
32496
|
+
this.recordAutoApproval(modal?.message, buttonLabel, now);
|
|
32497
|
+
setTimeout(() => {
|
|
32498
|
+
this.adapter.resolveModal(buttonIndex);
|
|
32499
|
+
}, 0);
|
|
32405
32500
|
return autoApproveActive;
|
|
32406
32501
|
}
|
|
32502
|
+
/**
|
|
32503
|
+
* Re-drive the auto-approve check after the settle quiet window elapses.
|
|
32504
|
+
* The PTY may have gone silent once the approval prompt finished painting,
|
|
32505
|
+
* so no status-change frame is guaranteed to re-enter maybeAutoApproveStatus
|
|
32506
|
+
* — this timer-driven re-check picks up the now-settled modal and fires.
|
|
32507
|
+
* Deliberately lighter than detectStatusTransition(): it only re-evaluates
|
|
32508
|
+
* the approval decision; the next real PTY frame refreshes visible status.
|
|
32509
|
+
*/
|
|
32510
|
+
recheckAutoApproveSettled() {
|
|
32511
|
+
try {
|
|
32512
|
+
const adapterStatus = this.adapter.getStatus({ allowParse: false });
|
|
32513
|
+
this.maybeAutoApproveStatus(adapterStatus, Date.now());
|
|
32514
|
+
} catch {
|
|
32515
|
+
}
|
|
32516
|
+
}
|
|
32407
32517
|
detectStatusTransition() {
|
|
32408
32518
|
const now = Date.now();
|
|
32409
32519
|
const adapterStatus = this.adapter.getStatus({ allowParse: false });
|