@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.js
CHANGED
|
@@ -275,10 +275,10 @@ function readInjected(value) {
|
|
|
275
275
|
}
|
|
276
276
|
function getDaemonBuildInfo() {
|
|
277
277
|
if (cached) return cached;
|
|
278
|
-
const commit = readInjected(true ? "
|
|
279
|
-
const commitShort = readInjected(true ? "
|
|
280
|
-
const version = readInjected(true ? "0.9.82-rc.
|
|
281
|
-
const builtAt = readInjected(true ? "2026-06-
|
|
278
|
+
const commit = readInjected(true ? "473dc8f049daf72ff7977b90e35ddde4e54f1c2f" : void 0) ?? "unknown";
|
|
279
|
+
const commitShort = readInjected(true ? "473dc8f0" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
280
|
+
const version = readInjected(true ? "0.9.82-rc.296" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
281
|
+
const builtAt = readInjected(true ? "2026-06-16T14:24:31.127Z" : void 0);
|
|
282
282
|
cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
|
|
283
283
|
return cached;
|
|
284
284
|
}
|
|
@@ -15644,10 +15644,12 @@ function detectClaudeTuiMultiSelect(screenText) {
|
|
|
15644
15644
|
if (/Space to (?:select|toggle)|toggle selection|select multiple|select all that apply/i.test(screenText)) {
|
|
15645
15645
|
return true;
|
|
15646
15646
|
}
|
|
15647
|
-
const optionCheckbox =
|
|
15647
|
+
const optionCheckbox = `(?:\\[[ xX]\\]|[\u2610\u2612\u25FB\u25FC])`;
|
|
15648
|
+
const beforeNumber = new RegExp(`^\\s*(?:[\u276F\u203A>]\\s*)?${optionCheckbox}\\s*\\d+\\.\\s+\\S`);
|
|
15649
|
+
const afterNumber = new RegExp(`^\\s*(?:[\u276F\u203A>]\\s*)?\\d+\\.\\s*${optionCheckbox}\\s+\\S`);
|
|
15648
15650
|
for (const line of screenText.split(/\r?\n/)) {
|
|
15649
15651
|
if (line.includes("\u2714 Submit")) continue;
|
|
15650
|
-
if (
|
|
15652
|
+
if (beforeNumber.test(line) || afterNumber.test(line)) return true;
|
|
15651
15653
|
}
|
|
15652
15654
|
return false;
|
|
15653
15655
|
}
|
|
@@ -15787,6 +15789,16 @@ function parseClaudeInteractiveTuiQuestion(page, index) {
|
|
|
15787
15789
|
...allowFreeform ? { allowFreeform: true } : {}
|
|
15788
15790
|
};
|
|
15789
15791
|
}
|
|
15792
|
+
function readFocusedClaudeTuiQuestion(screenText) {
|
|
15793
|
+
if (!screenText.includes("Enter to select")) return null;
|
|
15794
|
+
const parsed = parseClaudeInteractiveTuiQuestion({ screenText }, 0);
|
|
15795
|
+
if (!parsed) return null;
|
|
15796
|
+
return {
|
|
15797
|
+
question: parsed.question,
|
|
15798
|
+
...parsed.header ? { header: parsed.header } : {},
|
|
15799
|
+
multiSelect: parsed.multiSelect
|
|
15800
|
+
};
|
|
15801
|
+
}
|
|
15790
15802
|
function detectClaudeAskUserQuestionPromptFromTuiPages(pages, options) {
|
|
15791
15803
|
if (pages.length === 0) return null;
|
|
15792
15804
|
const headers = claudeTuiQuestionHeaders(pages[0].screenText);
|
|
@@ -15810,7 +15822,8 @@ function buildClaudeInteractiveTuiAnswerSteps(prompt, response) {
|
|
|
15810
15822
|
const answer = response.answers[question.questionId];
|
|
15811
15823
|
if (!answer) throw new Error(`Missing answer for ${question.questionId}`);
|
|
15812
15824
|
const freeformText = answer.freeformText?.trim() ?? "";
|
|
15813
|
-
|
|
15825
|
+
const treatAsMultiSelect = question.multiSelect || answer.selectedLabels.length > 1;
|
|
15826
|
+
if (treatAsMultiSelect) {
|
|
15814
15827
|
const labels = answer.selectedLabels;
|
|
15815
15828
|
if (labels.length === 0) {
|
|
15816
15829
|
throw new Error(`Expected at least one selected label for ${question.questionId}`);
|
|
@@ -32137,6 +32150,15 @@ var SpecCliAdapter = class _SpecCliAdapter {
|
|
|
32137
32150
|
* spirit as the approval FSM's `approvalCooldown` modal-lost hysteresis.
|
|
32138
32151
|
*/
|
|
32139
32152
|
static INTERACTIVE_PROMPT_LOST_GRACE_MS = 1500;
|
|
32153
|
+
/**
|
|
32154
|
+
* Multi-question TUI capture: after Tabbing to a page, re-snapshot at this
|
|
32155
|
+
* interval until its checkbox glyph column has settled, up to the timeout.
|
|
32156
|
+
* The interval matches the legacy single fixed wait (120ms); the timeout
|
|
32157
|
+
* bounds total capture time so a single-select page (which never shows
|
|
32158
|
+
* glyphs) doesn't stall the capture indefinitely.
|
|
32159
|
+
*/
|
|
32160
|
+
static CLAUDE_TUI_PAGE_POLL_INTERVAL_MS = 120;
|
|
32161
|
+
static CLAUDE_TUI_PAGE_SETTLE_TIMEOUT_MS = 600;
|
|
32140
32162
|
/**
|
|
32141
32163
|
* Clear a held interactive prompt once the user has resolved it directly
|
|
32142
32164
|
* in the terminal (the choice picker leaves the screen without going
|
|
@@ -32204,12 +32226,20 @@ var SpecCliAdapter = class _SpecCliAdapter {
|
|
|
32204
32226
|
* question to multi-select and re-emit status. Promotion is one-way
|
|
32205
32227
|
* (false→true only) — once a question is known multi-select we never demote
|
|
32206
32228
|
* it, since the glyph column can scroll out of view on later frames.
|
|
32229
|
+
*
|
|
32230
|
+
* For MULTI-question prompts the per-page Tab capture is the actual source
|
|
32231
|
+
* of the bug: pages 2..N are snapshotted ~120ms after the Tab keypress,
|
|
32232
|
+
* before their option-row glyph column has redrawn, so those questions
|
|
32233
|
+
* freeze as single-select while page 1 (already settled) is correct. We
|
|
32234
|
+
* cannot upgrade blindly — the live snapshot shows only ONE focused page —
|
|
32235
|
+
* but we CAN read that page's question text/header and upgrade the matching
|
|
32236
|
+
* question. As the user navigates the picker (or it settles), each page is
|
|
32237
|
+
* eventually re-read and repaired.
|
|
32207
32238
|
*/
|
|
32208
32239
|
maybeUpgradeClaudeTuiMultiSelect() {
|
|
32209
32240
|
if (this.cliType !== "claude-cli" || this.interactivePromptTransport !== "tui" || !this.activeInteractivePrompt) return;
|
|
32210
32241
|
const questions = this.activeInteractivePrompt.questions;
|
|
32211
|
-
if (questions.
|
|
32212
|
-
if (questions[0].multiSelect) return;
|
|
32242
|
+
if (questions.every((q) => q.multiSelect)) return;
|
|
32213
32243
|
let screenText = "";
|
|
32214
32244
|
try {
|
|
32215
32245
|
screenText = this.driver.snapshot();
|
|
@@ -32217,8 +32247,18 @@ var SpecCliAdapter = class _SpecCliAdapter {
|
|
|
32217
32247
|
return;
|
|
32218
32248
|
}
|
|
32219
32249
|
if (!screenText.includes("Enter to select")) return;
|
|
32220
|
-
if (
|
|
32221
|
-
|
|
32250
|
+
if (questions.length === 1) {
|
|
32251
|
+
if (questions[0].multiSelect) return;
|
|
32252
|
+
if (!detectClaudeTuiMultiSelect(screenText)) return;
|
|
32253
|
+
questions[0].multiSelect = true;
|
|
32254
|
+
this.statusCallback?.();
|
|
32255
|
+
return;
|
|
32256
|
+
}
|
|
32257
|
+
const focused = readFocusedClaudeTuiQuestion(screenText);
|
|
32258
|
+
if (!focused || !focused.multiSelect) return;
|
|
32259
|
+
const match = questions.find((q) => focused.header && q.header && q.header === focused.header || q.question === focused.question);
|
|
32260
|
+
if (!match || match.multiSelect) return;
|
|
32261
|
+
match.multiSelect = true;
|
|
32222
32262
|
this.statusCallback?.();
|
|
32223
32263
|
}
|
|
32224
32264
|
readClaudeTuiHeaders(screenText) {
|
|
@@ -32231,16 +32271,43 @@ var SpecCliAdapter = class _SpecCliAdapter {
|
|
|
32231
32271
|
}
|
|
32232
32272
|
return headers;
|
|
32233
32273
|
}
|
|
32274
|
+
/**
|
|
32275
|
+
* Snapshot the currently-focused claude TUI page, polling until its
|
|
32276
|
+
* option-row checkbox glyph column has settled (or a bounded timeout).
|
|
32277
|
+
*
|
|
32278
|
+
* Why poll: right after a Tab keypress the newly-focused page's glyph
|
|
32279
|
+
* column has not redrawn yet, so an immediate snapshot shows the question +
|
|
32280
|
+
* option labels but NO per-option checkbox markers — freezing that page as
|
|
32281
|
+
* single-select. A fixed delay either races (too short) or is wasteful (too
|
|
32282
|
+
* long). Instead we re-snapshot at a fixed interval and stop as soon as the
|
|
32283
|
+
* frame shows multi-select glyphs, falling back to the last frame at the
|
|
32284
|
+
* timeout. Single-select pages never show glyphs, so they always poll to the
|
|
32285
|
+
* timeout — bounded small to keep capture snappy.
|
|
32286
|
+
*/
|
|
32287
|
+
async snapshotSettledClaudeTuiPage() {
|
|
32288
|
+
let screenText = this.driver.snapshot();
|
|
32289
|
+
const deadline = Date.now() + _SpecCliAdapter.CLAUDE_TUI_PAGE_SETTLE_TIMEOUT_MS;
|
|
32290
|
+
while (!detectClaudeTuiMultiSelect(screenText) && Date.now() < deadline) {
|
|
32291
|
+
await new Promise((resolve24) => setTimeout(resolve24, _SpecCliAdapter.CLAUDE_TUI_PAGE_POLL_INTERVAL_MS));
|
|
32292
|
+
screenText = this.driver.snapshot();
|
|
32293
|
+
}
|
|
32294
|
+
return screenText;
|
|
32295
|
+
}
|
|
32234
32296
|
async captureClaudeTuiPrompt(firstScreen, headers) {
|
|
32235
32297
|
const pages = [{ screenText: firstScreen, header: headers[0] }];
|
|
32236
32298
|
for (let index = 1; index < headers.length; index += 1) {
|
|
32237
32299
|
this.driver.dispatch({ kind: "pty_write", data: " " });
|
|
32238
|
-
await new Promise((resolve24) => setTimeout(resolve24,
|
|
32239
|
-
pages.push({ screenText: this.
|
|
32300
|
+
await new Promise((resolve24) => setTimeout(resolve24, _SpecCliAdapter.CLAUDE_TUI_PAGE_POLL_INTERVAL_MS));
|
|
32301
|
+
pages.push({ screenText: await this.snapshotSettledClaudeTuiPage(), header: headers[index] });
|
|
32240
32302
|
}
|
|
32241
32303
|
for (let index = headers.length - 1; index > 0; index -= 1) {
|
|
32242
32304
|
this.driver.dispatch({ kind: "pty_write", data: "\x1B[Z" });
|
|
32243
|
-
await new Promise((resolve24) => setTimeout(resolve24,
|
|
32305
|
+
await new Promise((resolve24) => setTimeout(resolve24, _SpecCliAdapter.CLAUDE_TUI_PAGE_POLL_INTERVAL_MS));
|
|
32306
|
+
const reread = await this.snapshotSettledClaudeTuiPage();
|
|
32307
|
+
const landed = pages[index - 1];
|
|
32308
|
+
if (landed && !detectClaudeTuiMultiSelect(landed.screenText) && detectClaudeTuiMultiSelect(reread)) {
|
|
32309
|
+
landed.screenText = reread;
|
|
32310
|
+
}
|
|
32244
32311
|
}
|
|
32245
32312
|
const prompt = detectClaudeAskUserQuestionPromptFromTuiPages(pages, {
|
|
32246
32313
|
promptId: `ask-user-${this.providerSessionId || "claude"}-${Date.now()}`,
|