diff --git a/test/helpers/claude-pty-runner.ts b/test/helpers/claude-pty-runner.ts index faa0b6d38..435ac23ce 100644 --- a/test/helpers/claude-pty-runner.ts +++ b/test/helpers/claude-pty-runner.ts @@ -519,10 +519,13 @@ export function isProseAUQVisible(visible: string): boolean { } if (letteredHits.size >= 2) return true; - // Pattern 2: 3+ distinct numbered options at line starts, AND no `❯1.` - // cursor anywhere in the FULL visible buffer (which would mean - // isNumberedOptionListVisible already covers the case via the native UI). - if (/❯\s*1\./.test(visible)) return false; + // Pattern 2: 3+ distinct numbered options at line starts, AND no + // `❯1.` cursor IN THE RECENT TAIL (not the full buffer — a + // trust-dialog `❯ 1. Yes` at boot is in scrollback forever and + // would otherwise suppress this path for the rest of the run). + // The native-UI deferral only applies when the cursor list is + // currently rendered, not historically. + if (/❯\s*1\./.test(tail)) return false; const numberedRe = /(?:^|\n)[ \t❯]*([1-9])\./g; const numberedHits = new Set(); let nm: RegExpExecArray | null; diff --git a/test/helpers/claude-pty-runner.unit.test.ts b/test/helpers/claude-pty-runner.unit.test.ts index 1e79ca137..12c51875e 100644 --- a/test/helpers/claude-pty-runner.unit.test.ts +++ b/test/helpers/claude-pty-runner.unit.test.ts @@ -226,7 +226,7 @@ What's the task? A few options: expect(isProseAUQVisible(sample)).toBe(true); }); - test('returns false when ❯ 1. cursor is present (native UI handled by isNumberedOptionListVisible)', () => { + test('returns false when ❯ 1. cursor is present in the recent tail (native UI handled by isNumberedOptionListVisible)', () => { const sample = ` ❯ 1. First option 2. Second option @@ -235,6 +235,18 @@ What's the task? A few options: expect(isProseAUQVisible(sample)).toBe(false); }); + test('does NOT suppress numbered-prose detection when ❯ 1. is only in early scrollback (trust dialog)', () => { + // Boot trust dialog rendered ❯ 1. Yes at startup, then a long body of + // model output, then prose-rendered numbered options now. The historic + // ❯ 1. is in the full buffer but NOT in the recent tail. Should detect + // the prose AUQ. + const trustHeader = '❯ 1. Yes, trust\n 2. No\n'; + const filler = 'x'.repeat(5000); // pushes trust dialog out of last 4KB tail + const proseAUQ = `\n 1. Review the docs\n 2. Investigate the code\n 3. Defer to next session\n❯ \n`; + const sample = trustHeader + filler + proseAUQ; + expect(isProseAUQVisible(sample)).toBe(true); + }); + test('returns false on single lettered option', () => { const sample = ` A) Only one option mentioned in passing.