import { afterEach, describe, expect, it, vi } from 'vitest' import { createCommandCodeOutputStatusDetector } from './command-code-output-status' import { stripTerminalControl } from './terminal-control-stripping' afterEach(() => { vi.restoreAllMocks() }) describe('createCommandCodeOutputStatusDetector', () => { it('marks Command Code working with the submitted prompt when the TUI starts thinking', () => { const onWorking = vi.fn() const detector = createCommandCodeOutputStatusDetector({ startupCommand: 'command-code --trust', onWorking }) expect(detector.observe('❯ Fix the yellow spinner\r\n\x1b[35m✻ Thinking...\x1b[0m')).toBe(true) expect(onWorking).toHaveBeenCalledWith('Fix the yellow spinner') }) it('waits for the Command Code banner before trusting generic status text', () => { const onWorking = vi.fn() const detector = createCommandCodeOutputStatusDetector({ startupCommand: null, onWorking }) expect(detector.observe('Thinking about unrelated shell output')).toBe(false) expect(detector.observe('# Command Code v0.27.2\r\n')).toBe(false) expect(detector.observe('⌘ Parsing...')).toBe(true) expect(onWorking).toHaveBeenCalledWith('') }) it('detects the Command Code banner across PTY chunk boundaries', () => { const onWorking = vi.fn() const detector = createCommandCodeOutputStatusDetector({ startupCommand: null, onWorking }) expect(detector.observe('# Command')).toBe(false) expect(detector.observe(' Code v0.27.2\r\n')).toBe(false) expect(detector.observe('⌘ Parsing...')).toBe(true) expect(onWorking).toHaveBeenCalledWith('') }) it('detects the banner after chunks that carry no banner characters at all', () => { const onWorking = vi.fn() const detector = createCommandCodeOutputStatusDetector({ startupCommand: null, onWorking }) // Ordinary agent output with no '#': the raw prefilter skips these without building a window. expect(detector.observe('Codex is editing the file and rendering a diff\r\n')).toBe(false) expect(detector.observe('Codex wrote 12 lines\r\n')).toBe(false) expect(detector.observe('# Command Code v0.27.2\r\n')).toBe(false) expect(detector.observe('⌘ Parsing...')).toBe(true) expect(onWorking).toHaveBeenCalledWith('') }) it('detects the Command Code banner when ANSI styling splits the words', () => { const onWorking = vi.fn() const detector = createCommandCodeOutputStatusDetector({ startupCommand: null, onWorking }) expect(detector.observe('# C\x1b[35mommand Co\x1b[0mde v0.27.2\r\n')).toBe(false) expect(detector.observe('⌘ Parsing...')).toBe(true) expect(onWorking).toHaveBeenCalledWith('') }) it('does not trust near-miss Command Code banner text', () => { const onWorking = vi.fn() const detector = createCommandCodeOutputStatusDetector({ startupCommand: null, onWorking }) expect(detector.observe('NotCommand CodeX\r\n⌘ Parsing...')).toBe(false) expect(onWorking).not.toHaveBeenCalled() }) it('does not arm when another agent merely discusses Command Code', () => { const onWorking = vi.fn() const detector = createCommandCodeOutputStatusDetector({ startupCommand: null, onWorking }) expect(detector.observe('// Why: Command Code exposes transcript prompts')).toBe(false) expect(detector.observe('\r\n✻ Thinking...')).toBe(false) expect(onWorking).not.toHaveBeenCalled() }) it.each([ '# Command Code v1.2\r\n', '# Command Code v1.2.3.4\r\n', '# Command Code v01.2.3\r\n', '# Command Code v1.2.3suffix\r\n', '#\nCommand Code v1.2.3\r\n' ])('does not arm for noncanonical banner %j', (banner) => { const onWorking = vi.fn() const detector = createCommandCodeOutputStatusDetector({ startupCommand: null, onWorking }) expect(detector.observe(banner)).toBe(false) expect(detector.observe('✻ Thinking...')).toBe(false) expect(onWorking).not.toHaveBeenCalled() }) it('does not arm from a four-part version split at a PTY chunk boundary', () => { const onWorking = vi.fn() const detector = createCommandCodeOutputStatusDetector({ startupCommand: null, onWorking }) expect(detector.observe('# Command Code v1.2.3')).toBe(false) expect(detector.observe('.4\r\n')).toBe(false) expect(detector.observe('✻ Thinking...')).toBe(false) expect(onWorking).not.toHaveBeenCalled() }) it.each(['# Command Code v1.2.3\r\n', '# Command Code v1.2.3-beta.1+build.9\n'])( 'arms for canonical banner %j', (banner) => { const onWorking = vi.fn() const detector = createCommandCodeOutputStatusDetector({ startupCommand: null, onWorking }) expect(detector.observe(banner)).toBe(false) expect(detector.observe('✻ Thinking...')).toBe(true) expect(onWorking).toHaveBeenCalledWith('') } ) it.each([ 'Pondering', 'Contemplating', 'Reasoning', 'Reflecting', 'Considering', 'Deliberating', 'Analyzing', 'Evaluating', 'Examining', 'Inspecting', 'Investigating', 'Reviewing', 'Researching', 'Studying', 'Exploring', 'Mapping', 'Tracing', 'Parsing', 'Processing', 'Calculating', 'Computing', 'Synthesizing', 'Planning', 'Outlining', 'Sketching', 'Drafting', 'Composing', 'Crafting', 'Building', 'Assembling', 'Constructing', 'Designing', 'Formulating', 'Structuring', 'Organizing', 'Preparing', 'Refining', 'Polishing', 'Honing', 'Tuning', 'Aligning', 'Connecting', 'Resolving', 'Weaving', 'Threading', 'Sculpting', 'Crystallizing', 'Channeling', 'Conjuring', 'Brewing', 'Working', 'Cogitating', 'Ruminating', 'Hypothesizing', 'Conceptualizing', 'Philosophizing', 'Deciphering', 'Demystifying', 'Articulating', 'Illuminating', 'Elaborating', 'Orchestrating', 'Choreographing', 'Architecting', 'Calibrating', 'Materializing', 'Visualizing', 'Harmonizing', 'Contemplificating', 'Supercalifragilisting', 'Bibbidibobbidibooing', 'Abracadabraing', 'Hocuspocusing', 'Razzmatazzing' ])('marks Command Code working when the TUI reports %s', (statusText) => { const onWorking = vi.fn() const detector = createCommandCodeOutputStatusDetector({ startupCommand: 'command-code --trust', onWorking }) expect(detector.observe(`❯ Fix the yellow spinner\r\n${statusText}...`)).toBe(true) expect(onWorking).toHaveBeenCalledWith('Fix the yellow spinner') }) it.each(['Executing: sleep 8 && echo done', '⎿ Running (1s | 0)'])( 'marks Command Code working when the TUI reports %s', (statusText) => { const onWorking = vi.fn() const detector = createCommandCodeOutputStatusDetector({ startupCommand: 'command-code --trust', onWorking }) expect(detector.observe(`❯ Fix the yellow spinner\r\n${statusText}`)).toBe(true) expect(onWorking).toHaveBeenCalledWith('Fix the yellow spinner') } ) it('marks Command Code working when active status text is split across PTY chunks', () => { const onWorking = vi.fn() const detector = createCommandCodeOutputStatusDetector({ startupCommand: 'command-code --trust', onWorking }) expect(detector.observe('❯ Fix the yellow spinner\r\nExpl')).toBe(false) expect(detector.observe('oring...')).toBe(true) expect(onWorking).toHaveBeenCalledWith('Fix the yellow spinner') }) it('does not capture a styled idle composer as the submitted prompt', () => { const onWorking = vi.fn() const detector = createCommandCodeOutputStatusDetector({ startupCommand: 'command-code --trust', onWorking }) expect(detector.observe('# Command Code v0.27.3\r\n❯ A\x1b')).toBe(false) expect(detector.observe('[27msk your question...\r\n✻ Thinking...')).toBe(true) expect(onWorking).toHaveBeenCalledWith('') expect(onWorking).not.toHaveBeenCalledWith(expect.stringContaining('[27m')) }) it('captures a submitted prompt when styling is split across PTY chunks', () => { const onWorking = vi.fn() const detector = createCommandCodeOutputStatusDetector({ startupCommand: 'command-code --trust', onWorking }) expect(detector.observe('❯ Fix the \x1b')).toBe(false) expect(detector.observe('[38;2;99;109;131mstatus row\r\n✻ Thinking...')).toBe(true) expect(onWorking).toHaveBeenCalledWith('Fix the status row') }) it('folds whitespace-heavy submitted prompts without whitespace regex replacement', () => { const replaceSpy = vi.spyOn(String.prototype, 'replace') const onWorking = vi.fn() const detector = createCommandCodeOutputStatusDetector({ startupCommand: 'command-code --trust', onWorking }) const nonBreakingSpace = String.fromCharCode(160) const prompt = `❯ Fix\t the${nonBreakingSpace}${nonBreakingSpace}status row\r\n✻ Thinking...` expect(detector.observe(prompt)).toBe(true) expect(onWorking).toHaveBeenCalledWith('Fix the status row') expect( replaceSpy.mock.calls.filter( ([pattern]) => pattern instanceof RegExp && pattern.source === '\\s+' ) ).toHaveLength(0) }) it('marks Command Code done when a no-tool turn returns to the idle prompt', () => { const onWorking = vi.fn() const onDone = vi.fn() const detector = createCommandCodeOutputStatusDetector({ startupCommand: 'command-code --trust', onWorking, onDone }) expect(detector.observe('❯ say hi\r\n✻ Thinking...')).toBe(true) expect( detector.observe( '\r\n✻ Thought for 1 second\r\n:: Hi! How can I help you today?\r\n❯ Ask your question...' ) ).toBe(true) expect(onWorking).toHaveBeenCalledWith('say hi') expect(onDone).toHaveBeenCalledWith('say hi') }) it('does not mark the initial idle composer as done before a submitted prompt', () => { const onDone = vi.fn() const detector = createCommandCodeOutputStatusDetector({ startupCommand: 'command-code --trust', onWorking: vi.fn(), onDone }) expect(detector.observe('# Command Code v0.27.3\r\n❯ Ask your question...')).toBe(false) expect(onDone).not.toHaveBeenCalled() }) it('does not treat completed thought text as a working status', () => { const onWorking = vi.fn() const detector = createCommandCodeOutputStatusDetector({ startupCommand: 'command-code --trust', onWorking }) expect(detector.observe('❯ Fix the yellow spinner\r\nThought for 1 second')).toBe(false) expect(onWorking).not.toHaveBeenCalled() }) it('bounds scan work for large echoed paste output in Command Code terminals', () => { const replaceSpy = vi.spyOn(String.prototype, 'replace') const matchAllSpy = vi.spyOn(String.prototype, 'matchAll') const onWorking = vi.fn() const detector = createCommandCodeOutputStatusDetector({ startupCommand: 'command-code --trust', onWorking }) const largeEchoedPaste = `${'pasted Command Code \x1b[35mnoise\r\n'.repeat(10_000)}❯ Fix bounded scans\r\n✻ Thinking...` expect(detector.observe(largeEchoedPaste)).toBe(true) expect(onWorking).toHaveBeenCalledWith('Fix bounded scans') expect(maxStringContextLength(replaceSpy.mock.contexts)).toBeLessThan(10_000) expect(maxStringContextLength(matchAllSpy.mock.contexts)).toBeLessThan(10_000) }) it('bounds pre-banner scans for large non-Command-Code terminal output', () => { const replaceSpy = vi.spyOn(String.prototype, 'replace') const matchAllSpy = vi.spyOn(String.prototype, 'matchAll') const detector = createCommandCodeOutputStatusDetector({ startupCommand: null, onWorking: vi.fn() }) expect(detector.observe(`${'Coded shell output\r\n'.repeat(10_000)}`)).toBe(false) expect(maxStringContextLength(replaceSpy.mock.contexts)).toBeLessThan(10_000) expect(maxStringContextLength(matchAllSpy.mock.contexts)).toBe(0) }) }) function maxStringContextLength(contexts: unknown[]): number { return Math.max( 0, ...contexts.map((context) => (typeof context === 'string' ? context.length : 0)) ) } describe('terminal control stripping', () => { function promptFrom(raw: string): string | null { let captured: string | null = null const detector = createCommandCodeOutputStatusDetector({ startupCommand: 'command-code', onWorking: (prompt) => { captured = prompt } }) detector.observe(raw) return captured } it('strips control bytes wherever they sit around the prompt text', () => { expect(promptFrom('❯ plain prompt\r\n\x1b[35m✻ Thinking...\x1b[0m')).toBe('plain prompt') expect(promptFrom('\x07❯ leading control\r\n\x1b[35m✻ Thinking...\x1b[0m')).toBe( 'leading control' ) expect(promptFrom('❯ trailing control\x07\r\n\x1b[35m✻ Thinking...\x1b[0m')).toBe( 'trailing control' ) expect(promptFrom('❯ adjacent\x07\x01\x02controls\r\n\x1b[35m✻ Thinking...\x1b[0m')).toBe( 'adjacentcontrols' ) }) it('preserves multi-byte text and newlines while stripping', () => { expect(promptFrom('❯ 日本語 \u{1f389} prompt\r\n\x1b[35m✻ Thinking...\x1b[0m')).toBe( '日本語 \u{1f389} prompt' ) }) it.each([ { data: '', expected: '' }, { data: 'plain text', expected: 'plain text' }, { data: '\x1b[35mstyled\x1b[0m', expected: 'styled' }, { data: 'prompt\x1b[35', expected: 'prompt' }, { data: '\x00leading', expected: 'leading' }, { data: 'trailing\x9f', expected: 'trailing' }, { data: '\x01\x02adjacent\x7f\x80', expected: 'adjacent' }, { data: 'keep\r\nline breaks', expected: 'keep\r\nline breaks' }, { data: '日本語 🎉 \ud83d \ude00', expected: '日本語 🎉 \ud83d \ude00' }, { data: '\x01'.repeat(31) + 'a'.repeat(33), expected: 'a'.repeat(33) }, { data: '\x01'.repeat(32) + 'a'.repeat(32), expected: 'a'.repeat(32) }, { data: `${'a'.repeat(32) + '\x01'.repeat(31)}a`, expected: 'a'.repeat(33) }, { data: `${'\x01'.repeat(31) + 'a'.repeat(33) + '\x01'.repeat(32)}z`, expected: `${'a'.repeat(33)}z` }, { data: `${'a'.repeat(192) + '\x01'.repeat(32)}tail`, expected: `${'a'.repeat(192)}tail` }, { data: `${'a\x01'.repeat(2048)}tail`, expected: `${'a'.repeat(2048)}tail` } ])('strips controls while preserving printable text (case %#)', ({ data, expected }) => { expect(stripTerminalControl(data)).toBe(expected) }) })