@adhdev/daemon-core 0.9.82-rc.294 → 0.9.82-rc.296
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 +81 -14
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +81 -14
- package/dist/index.mjs.map +1 -1
- package/dist/providers/spec/cli-adapter.d.ts +32 -0
- package/dist/providers/types/interactive-prompt.d.ts +17 -0
- package/package.json +2 -2
- package/src/providers/spec/cli-adapter.ts +80 -12
- package/src/providers/types/interactive-prompt.ts +48 -8
package/dist/index.mjs
CHANGED
|
@@ -270,10 +270,10 @@ function readInjected(value) {
|
|
|
270
270
|
}
|
|
271
271
|
function getDaemonBuildInfo() {
|
|
272
272
|
if (cached) return cached;
|
|
273
|
-
const commit = readInjected(true ? "
|
|
274
|
-
const commitShort = readInjected(true ? "
|
|
275
|
-
const version = readInjected(true ? "0.9.82-rc.
|
|
276
|
-
const builtAt = readInjected(true ? "2026-06-
|
|
273
|
+
const commit = readInjected(true ? "473dc8f049daf72ff7977b90e35ddde4e54f1c2f" : void 0) ?? "unknown";
|
|
274
|
+
const commitShort = readInjected(true ? "473dc8f0" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
275
|
+
const version = readInjected(true ? "0.9.82-rc.296" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
276
|
+
const builtAt = readInjected(true ? "2026-06-16T14:24:31.127Z" : void 0);
|
|
277
277
|
cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
|
|
278
278
|
return cached;
|
|
279
279
|
}
|
|
@@ -15303,10 +15303,12 @@ function detectClaudeTuiMultiSelect(screenText) {
|
|
|
15303
15303
|
if (/Space to (?:select|toggle)|toggle selection|select multiple|select all that apply/i.test(screenText)) {
|
|
15304
15304
|
return true;
|
|
15305
15305
|
}
|
|
15306
|
-
const optionCheckbox =
|
|
15306
|
+
const optionCheckbox = `(?:\\[[ xX]\\]|[\u2610\u2612\u25FB\u25FC])`;
|
|
15307
|
+
const beforeNumber = new RegExp(`^\\s*(?:[\u276F\u203A>]\\s*)?${optionCheckbox}\\s*\\d+\\.\\s+\\S`);
|
|
15308
|
+
const afterNumber = new RegExp(`^\\s*(?:[\u276F\u203A>]\\s*)?\\d+\\.\\s*${optionCheckbox}\\s+\\S`);
|
|
15307
15309
|
for (const line of screenText.split(/\r?\n/)) {
|
|
15308
15310
|
if (line.includes("\u2714 Submit")) continue;
|
|
15309
|
-
if (
|
|
15311
|
+
if (beforeNumber.test(line) || afterNumber.test(line)) return true;
|
|
15310
15312
|
}
|
|
15311
15313
|
return false;
|
|
15312
15314
|
}
|
|
@@ -15446,6 +15448,16 @@ function parseClaudeInteractiveTuiQuestion(page, index) {
|
|
|
15446
15448
|
...allowFreeform ? { allowFreeform: true } : {}
|
|
15447
15449
|
};
|
|
15448
15450
|
}
|
|
15451
|
+
function readFocusedClaudeTuiQuestion(screenText) {
|
|
15452
|
+
if (!screenText.includes("Enter to select")) return null;
|
|
15453
|
+
const parsed = parseClaudeInteractiveTuiQuestion({ screenText }, 0);
|
|
15454
|
+
if (!parsed) return null;
|
|
15455
|
+
return {
|
|
15456
|
+
question: parsed.question,
|
|
15457
|
+
...parsed.header ? { header: parsed.header } : {},
|
|
15458
|
+
multiSelect: parsed.multiSelect
|
|
15459
|
+
};
|
|
15460
|
+
}
|
|
15449
15461
|
function detectClaudeAskUserQuestionPromptFromTuiPages(pages, options) {
|
|
15450
15462
|
if (pages.length === 0) return null;
|
|
15451
15463
|
const headers = claudeTuiQuestionHeaders(pages[0].screenText);
|
|
@@ -15469,7 +15481,8 @@ function buildClaudeInteractiveTuiAnswerSteps(prompt, response) {
|
|
|
15469
15481
|
const answer = response.answers[question.questionId];
|
|
15470
15482
|
if (!answer) throw new Error(`Missing answer for ${question.questionId}`);
|
|
15471
15483
|
const freeformText = answer.freeformText?.trim() ?? "";
|
|
15472
|
-
|
|
15484
|
+
const treatAsMultiSelect = question.multiSelect || answer.selectedLabels.length > 1;
|
|
15485
|
+
if (treatAsMultiSelect) {
|
|
15473
15486
|
const labels = answer.selectedLabels;
|
|
15474
15487
|
if (labels.length === 0) {
|
|
15475
15488
|
throw new Error(`Expected at least one selected label for ${question.questionId}`);
|
|
@@ -31796,6 +31809,15 @@ var SpecCliAdapter = class _SpecCliAdapter {
|
|
|
31796
31809
|
* spirit as the approval FSM's `approvalCooldown` modal-lost hysteresis.
|
|
31797
31810
|
*/
|
|
31798
31811
|
static INTERACTIVE_PROMPT_LOST_GRACE_MS = 1500;
|
|
31812
|
+
/**
|
|
31813
|
+
* Multi-question TUI capture: after Tabbing to a page, re-snapshot at this
|
|
31814
|
+
* interval until its checkbox glyph column has settled, up to the timeout.
|
|
31815
|
+
* The interval matches the legacy single fixed wait (120ms); the timeout
|
|
31816
|
+
* bounds total capture time so a single-select page (which never shows
|
|
31817
|
+
* glyphs) doesn't stall the capture indefinitely.
|
|
31818
|
+
*/
|
|
31819
|
+
static CLAUDE_TUI_PAGE_POLL_INTERVAL_MS = 120;
|
|
31820
|
+
static CLAUDE_TUI_PAGE_SETTLE_TIMEOUT_MS = 600;
|
|
31799
31821
|
/**
|
|
31800
31822
|
* Clear a held interactive prompt once the user has resolved it directly
|
|
31801
31823
|
* in the terminal (the choice picker leaves the screen without going
|
|
@@ -31863,12 +31885,20 @@ var SpecCliAdapter = class _SpecCliAdapter {
|
|
|
31863
31885
|
* question to multi-select and re-emit status. Promotion is one-way
|
|
31864
31886
|
* (false→true only) — once a question is known multi-select we never demote
|
|
31865
31887
|
* it, since the glyph column can scroll out of view on later frames.
|
|
31888
|
+
*
|
|
31889
|
+
* For MULTI-question prompts the per-page Tab capture is the actual source
|
|
31890
|
+
* of the bug: pages 2..N are snapshotted ~120ms after the Tab keypress,
|
|
31891
|
+
* before their option-row glyph column has redrawn, so those questions
|
|
31892
|
+
* freeze as single-select while page 1 (already settled) is correct. We
|
|
31893
|
+
* cannot upgrade blindly — the live snapshot shows only ONE focused page —
|
|
31894
|
+
* but we CAN read that page's question text/header and upgrade the matching
|
|
31895
|
+
* question. As the user navigates the picker (or it settles), each page is
|
|
31896
|
+
* eventually re-read and repaired.
|
|
31866
31897
|
*/
|
|
31867
31898
|
maybeUpgradeClaudeTuiMultiSelect() {
|
|
31868
31899
|
if (this.cliType !== "claude-cli" || this.interactivePromptTransport !== "tui" || !this.activeInteractivePrompt) return;
|
|
31869
31900
|
const questions = this.activeInteractivePrompt.questions;
|
|
31870
|
-
if (questions.
|
|
31871
|
-
if (questions[0].multiSelect) return;
|
|
31901
|
+
if (questions.every((q) => q.multiSelect)) return;
|
|
31872
31902
|
let screenText = "";
|
|
31873
31903
|
try {
|
|
31874
31904
|
screenText = this.driver.snapshot();
|
|
@@ -31876,8 +31906,18 @@ var SpecCliAdapter = class _SpecCliAdapter {
|
|
|
31876
31906
|
return;
|
|
31877
31907
|
}
|
|
31878
31908
|
if (!screenText.includes("Enter to select")) return;
|
|
31879
|
-
if (
|
|
31880
|
-
|
|
31909
|
+
if (questions.length === 1) {
|
|
31910
|
+
if (questions[0].multiSelect) return;
|
|
31911
|
+
if (!detectClaudeTuiMultiSelect(screenText)) return;
|
|
31912
|
+
questions[0].multiSelect = true;
|
|
31913
|
+
this.statusCallback?.();
|
|
31914
|
+
return;
|
|
31915
|
+
}
|
|
31916
|
+
const focused = readFocusedClaudeTuiQuestion(screenText);
|
|
31917
|
+
if (!focused || !focused.multiSelect) return;
|
|
31918
|
+
const match = questions.find((q) => focused.header && q.header && q.header === focused.header || q.question === focused.question);
|
|
31919
|
+
if (!match || match.multiSelect) return;
|
|
31920
|
+
match.multiSelect = true;
|
|
31881
31921
|
this.statusCallback?.();
|
|
31882
31922
|
}
|
|
31883
31923
|
readClaudeTuiHeaders(screenText) {
|
|
@@ -31890,16 +31930,43 @@ var SpecCliAdapter = class _SpecCliAdapter {
|
|
|
31890
31930
|
}
|
|
31891
31931
|
return headers;
|
|
31892
31932
|
}
|
|
31933
|
+
/**
|
|
31934
|
+
* Snapshot the currently-focused claude TUI page, polling until its
|
|
31935
|
+
* option-row checkbox glyph column has settled (or a bounded timeout).
|
|
31936
|
+
*
|
|
31937
|
+
* Why poll: right after a Tab keypress the newly-focused page's glyph
|
|
31938
|
+
* column has not redrawn yet, so an immediate snapshot shows the question +
|
|
31939
|
+
* option labels but NO per-option checkbox markers — freezing that page as
|
|
31940
|
+
* single-select. A fixed delay either races (too short) or is wasteful (too
|
|
31941
|
+
* long). Instead we re-snapshot at a fixed interval and stop as soon as the
|
|
31942
|
+
* frame shows multi-select glyphs, falling back to the last frame at the
|
|
31943
|
+
* timeout. Single-select pages never show glyphs, so they always poll to the
|
|
31944
|
+
* timeout — bounded small to keep capture snappy.
|
|
31945
|
+
*/
|
|
31946
|
+
async snapshotSettledClaudeTuiPage() {
|
|
31947
|
+
let screenText = this.driver.snapshot();
|
|
31948
|
+
const deadline = Date.now() + _SpecCliAdapter.CLAUDE_TUI_PAGE_SETTLE_TIMEOUT_MS;
|
|
31949
|
+
while (!detectClaudeTuiMultiSelect(screenText) && Date.now() < deadline) {
|
|
31950
|
+
await new Promise((resolve24) => setTimeout(resolve24, _SpecCliAdapter.CLAUDE_TUI_PAGE_POLL_INTERVAL_MS));
|
|
31951
|
+
screenText = this.driver.snapshot();
|
|
31952
|
+
}
|
|
31953
|
+
return screenText;
|
|
31954
|
+
}
|
|
31893
31955
|
async captureClaudeTuiPrompt(firstScreen, headers) {
|
|
31894
31956
|
const pages = [{ screenText: firstScreen, header: headers[0] }];
|
|
31895
31957
|
for (let index = 1; index < headers.length; index += 1) {
|
|
31896
31958
|
this.driver.dispatch({ kind: "pty_write", data: " " });
|
|
31897
|
-
await new Promise((resolve24) => setTimeout(resolve24,
|
|
31898
|
-
pages.push({ screenText: this.
|
|
31959
|
+
await new Promise((resolve24) => setTimeout(resolve24, _SpecCliAdapter.CLAUDE_TUI_PAGE_POLL_INTERVAL_MS));
|
|
31960
|
+
pages.push({ screenText: await this.snapshotSettledClaudeTuiPage(), header: headers[index] });
|
|
31899
31961
|
}
|
|
31900
31962
|
for (let index = headers.length - 1; index > 0; index -= 1) {
|
|
31901
31963
|
this.driver.dispatch({ kind: "pty_write", data: "\x1B[Z" });
|
|
31902
|
-
await new Promise((resolve24) => setTimeout(resolve24,
|
|
31964
|
+
await new Promise((resolve24) => setTimeout(resolve24, _SpecCliAdapter.CLAUDE_TUI_PAGE_POLL_INTERVAL_MS));
|
|
31965
|
+
const reread = await this.snapshotSettledClaudeTuiPage();
|
|
31966
|
+
const landed = pages[index - 1];
|
|
31967
|
+
if (landed && !detectClaudeTuiMultiSelect(landed.screenText) && detectClaudeTuiMultiSelect(reread)) {
|
|
31968
|
+
landed.screenText = reread;
|
|
31969
|
+
}
|
|
31903
31970
|
}
|
|
31904
31971
|
const prompt = detectClaudeAskUserQuestionPromptFromTuiPages(pages, {
|
|
31905
31972
|
promptId: `ask-user-${this.providerSessionId || "claude"}-${Date.now()}`,
|