@adhdev/daemon-core 0.9.82-rc.292 → 0.9.82-rc.294

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.
@@ -31,6 +31,7 @@ import {
31
31
  buildClaudeInteractiveToolResult,
32
32
  detectClaudeAskUserQuestionPromptFromJson,
33
33
  detectClaudeAskUserQuestionPromptFromTuiPages,
34
+ detectClaudeTuiMultiSelect,
34
35
  type ClaudeInteractiveTuiPage,
35
36
  type InteractivePrompt,
36
37
  type InteractivePromptResponse,
@@ -445,12 +446,14 @@ export class SpecCliAdapter implements CliAdapter {
445
446
  }
446
447
  this.maybeClearResolvedClaudeTuiPrompt();
447
448
  this.maybeCaptureClaudeTuiPrompt();
449
+ this.maybeUpgradeClaudeTuiMultiSelect();
448
450
  this.statusCallback?.();
449
451
  return;
450
452
  case 'pty_data':
451
453
  this.detectInteractivePromptFromPtyChunk(ev.chunk);
452
454
  this.maybeClearResolvedClaudeTuiPrompt();
453
455
  this.maybeCaptureClaudeTuiPrompt();
456
+ this.maybeUpgradeClaudeTuiMultiSelect();
454
457
  try { this.ptyDataCallback?.(ev.chunk); } catch { /* ignore */ }
455
458
  return;
456
459
  case 'exit':
@@ -614,6 +617,43 @@ export class SpecCliAdapter implements CliAdapter {
614
617
  });
615
618
  }
616
619
 
620
+ /**
621
+ * The TUI prompt is captured on the FIRST frame that renders the
622
+ * "Enter to select" footer. At that instant the option rows' checkbox
623
+ * column may not have drawn yet, so `detectClaudeTuiMultiSelect` returns
624
+ * false and the prompt is frozen as single-select — the dashboard then
625
+ * renders radio buttons even though the picker is multi-select.
626
+ *
627
+ * While the same TUI prompt is still on screen, re-check the live snapshot:
628
+ * if checkbox glyphs have since appeared, promote any single-select
629
+ * question to multi-select and re-emit status. Promotion is one-way
630
+ * (false→true only) — once a question is known multi-select we never demote
631
+ * it, since the glyph column can scroll out of view on later frames.
632
+ */
633
+ private maybeUpgradeClaudeTuiMultiSelect(): void {
634
+ if (this.cliType !== 'claude-cli'
635
+ || this.interactivePromptTransport !== 'tui'
636
+ || !this.activeInteractivePrompt) return;
637
+ const questions = this.activeInteractivePrompt.questions;
638
+ // The live snapshot only shows the CURRENTLY focused question's rows, so
639
+ // we can only attribute the glyphs to a specific question when there is
640
+ // exactly one. Multi-question prompts are tab-captured per page at
641
+ // capture time and aren't re-evaluated here to avoid cross-contaminating
642
+ // a mixed single/multi prompt.
643
+ if (questions.length !== 1) return;
644
+ if (questions[0].multiSelect) return;
645
+ let screenText = '';
646
+ try {
647
+ screenText = this.driver.snapshot();
648
+ } catch {
649
+ return;
650
+ }
651
+ if (!screenText.includes('Enter to select')) return;
652
+ if (!detectClaudeTuiMultiSelect(screenText)) return;
653
+ questions[0].multiSelect = true;
654
+ this.statusCallback?.();
655
+ }
656
+
617
657
  private readClaudeTuiHeaders(screenText: string): string[] {
618
658
  const navLine = screenText.split(/\r?\n/).find(line => line.includes('✔ Submit') && /[☐☒]/.test(line));
619
659
  if (!navLine) return [];
@@ -180,7 +180,7 @@ function isClaudeTuiSelectFooter(text: string): boolean {
180
180
  * broadened footer patterns ("Space to", "toggle", "select multiple") are kept
181
181
  * as a secondary signal for layouts that render markers differently.
182
182
  */
183
- function detectClaudeTuiMultiSelect(screenText: string): boolean {
183
+ export function detectClaudeTuiMultiSelect(screenText: string): boolean {
184
184
  if (/Space to (?:select|toggle)|toggle selection|select multiple|select all that apply/i.test(screenText)) {
185
185
  return true;
186
186
  }