diff --git a/aai_cli/code_agent/tui.py b/aai_cli/code_agent/tui.py index 2871038..d5734cf 100644 --- a/aai_cli/code_agent/tui.py +++ b/aai_cli/code_agent/tui.py @@ -48,6 +48,7 @@ VOICE_FRAMES, _spinner_text, _status_text, + copy_note, voicebar_markup, ) from aai_cli.code_agent.voice_ui import _VoiceIO, _VoiceLegs @@ -82,12 +83,11 @@ class CodeAgentApp(_VoiceLegs): #promptmark {{ width: 3; color: {banner.BRAND_HEX}; content-align: center middle; }} #prompt {{ border: none; background: #000000; padding: 0; }} /* Shown in place of the prompt while voice capture is on (Ctrl-V brings the prompt back). */ - #voicebar {{ dock: bottom; height: 3; background: #000000; border: round {banner.BRAND_HEX}; - margin: 1 1; content-align: center middle; display: none; }} + #voicebar {{ dock: bottom; height: 3; background: #000000; border: round {banner.BRAND_HEX}; margin: 1 1; content-align: center middle; display: none; }} /* In normal flow below the 1fr log, so it sits just above the docked prompt bar. */ - #spinner {{ height: 1; background: #000000; padding: 0 2; - color: {banner.BRAND_HEX}; display: none; }} - #status {{ dock: bottom; height: 1; background: #000000; padding: 0 1; }} + #spinner {{ height: 1; background: #000000; padding: 0 2; color: {banner.BRAND_HEX}; display: none; }} + /* Two rows: the mode/cwd/branch/voice line and the dim key-legend below it. */ + #status {{ dock: bottom; height: 2; background: #000000; padding: 0 1; }} """ TITLE = "AssemblyAI Code" # Ctrl-C quits (in addition to Ctrl-Q); the built-in command palette is removed. @@ -245,12 +245,10 @@ def _finalize_reply(self, text: str) -> None: msg.finalize(text) def action_copy_last(self) -> None: - """Copy the most recent assistant reply to the system clipboard.""" + """Copy the most recent assistant reply to the system clipboard, noting the outcome.""" import pyperclip - if self._last_reply: - pyperclip.copy(self._last_reply) - self._note("(copied last reply to clipboard)") + self._note(copy_note(self._last_reply, pyperclip.copy)) def action_toggle_output(self) -> None: """Ctrl-O: expand/collapse the most recent tool output (a no-op if there's none).""" @@ -321,6 +319,7 @@ def action_toggle_voice(self) -> None: self._refresh_status() self._sync_input_mode() # show/hide the text box vs. the listening affordance if self._voice_paused: + self._voice.cancel() # release the mic now, don't leave a capture running unseen self.notify("Voice off — type your request") elif not self._turn_running(): self.notify("Voice on — listening") diff --git a/aai_cli/code_agent/tui_status.py b/aai_cli/code_agent/tui_status.py index e163ea0..95fca7a 100644 --- a/aai_cli/code_agent/tui_status.py +++ b/aai_cli/code_agent/tui_status.py @@ -7,11 +7,16 @@ from __future__ import annotations from pathlib import Path +from typing import TYPE_CHECKING +import pyperclip from rich.markup import escape from aai_cli.ui import theme +if TYPE_CHECKING: + from collections.abc import Callable + # Animated meter for the voice bar — a 3-cell block-char pulse (BMP, single-width, no emoji). # Public: both the `code` and `live` TUIs cycle it for their bar animation. VOICE_FRAMES = ("▁▃▅", "▃▅▇", "▅▇▆", "▆▇▅", "▇▅▃", "▅▃▁") # pragma: no mutate @@ -39,6 +44,38 @@ def _spinner_text(elapsed_s: int, frame: str) -> str: return f"{frame} Working… ({elapsed_s}s)" +def keyhints_text(*, voice: bool) -> str: + """The dim key-legend footer for the `code` TUI — the shortcuts worth surfacing. + + The keyboard chords are otherwise undiscoverable (the app has no Footer widget). The + Ctrl-V voice toggle is only listed when the session has a voice front-end. Caret notation + (``^Y``) keeps the legend short enough to fit a narrow terminal; the chords are bold so + they read against the dim labels. + """ + hints = ["[b]^Y[/b] copy"] + if voice: + hints.append("[b]^V[/b] voice") + hints += ["[b]^O[/b] expand", "[b]esc[/b] interrupt", "[b]^C[/b] quit"] + return f"[dim]{' · '.join(hints)}[/dim]" + + +def copy_note(reply: str, copier: Callable[[str], None]) -> str: + """Copy ``reply`` to the clipboard via ``copier``, returning the transcript note to show. + + Keeps the Ctrl-Y action a one-liner and handles its two non-happy paths so they can't + surprise the user: nothing has been said yet, and a headless/clipboard-less box where + ``pyperclip`` raises (an unhandled raise there would tear down the whole TUI). ``copier`` + is ``pyperclip.copy`` in production, injected so this unit-tests with no real clipboard. + """ + if not reply: + return "(nothing to copy yet)" + try: + copier(reply) + except pyperclip.PyperclipException: + return "(couldn't copy: no clipboard available)" + return "(copied last reply to clipboard)" + + def _abbrev_home(path: Path) -> str: """Render ``path`` with the home directory collapsed to ``~``.""" try: @@ -58,10 +95,12 @@ def _git_branch(start: Path) -> str | None: def _status_text(cwd: Path, *, auto_approve: bool, voice_state: str | None = None) -> str: - """The bottom status line: a mode badge, the working directory, git branch, and voice state. + """The two-row bottom footer: a status line, and a dim key-legend beneath it. - ``voice_state`` is ``"on"``/``"off"`` when the session has a voice front-end (so the - Ctrl-V toggle shows its effect), or ``None`` when voice isn't wired up at all. + Row one is a mode badge, the working directory, the git branch, and voice state; row two + is :func:`keyhints_text`. ``voice_state`` is ``"on"``/``"off"`` when the session has a + voice front-end (so the Ctrl-V toggle shows its effect, and the legend lists it), or + ``None`` when voice isn't wired up at all. """ mode = "auto" if auto_approve else "manual" badge = f"[black on #f59e0b] {mode} [/]" @@ -73,4 +112,4 @@ def _status_text(cwd: Path, *, auto_approve: bool, voice_state: str | None = Non # A filled/hollow dot (BMP glyphs, like the rest of the UI — no double-width emoji). glyph, color = ("●", "#22c55e") if voice_state == "on" else ("○", "#6b7280") parts.append(f"[{color}]{glyph} voice {voice_state}[/]") - return " ".join(parts) + return " ".join(parts) + "\n" + keyhints_text(voice=voice_state is not None) diff --git a/aai_cli/code_agent/voice_ui.py b/aai_cli/code_agent/voice_ui.py index f105fa4..c4b6ad2 100644 --- a/aai_cli/code_agent/voice_ui.py +++ b/aai_cli/code_agent/voice_ui.py @@ -113,7 +113,10 @@ def _capture_voice_turn(self) -> None: self._voice_typed = True self.call_from_thread(self._notice_voice_off, exc.message) return - if transcript: + # Re-check after listen(): the user may have switched to text (Ctrl-V) or interrupted + # (Escape/Ctrl-C) while this capture was blocking, in which case a turn that finalized + # in that window must not be submitted behind their back. + if transcript and self._voice_active(): self.call_from_thread(self._enter_and_submit, transcript) def _notice_voice_off(self, detail: str) -> None: diff --git a/tests/__snapshots__/test_tui_snapshots/test_code_approval_modal.raw b/tests/__snapshots__/test_tui_snapshots/test_code_approval_modal.raw index 9355a4d..aa9e569 100644 --- a/tests/__snapshots__/test_tui_snapshots/test_code_approval_modal.raw +++ b/tests/__snapshots__/test_tui_snapshots/test_code_approval_modal.raw @@ -19,164 +19,164 @@ font-weight: 700; } - .terminal-2623049041-matrix { + .terminal-2084666923-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-2623049041-title { + .terminal-2084666923-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-2623049041-r1 { fill: #e0e0e0 } -.terminal-2623049041-r2 { fill: #c5c8c6 } -.terminal-2623049041-r3 { fill: #614fd2;font-weight: bold } -.terminal-2623049041-r4 { fill: #939393 } -.terminal-2623049041-r5 { fill: #614fd2 } -.terminal-2623049041-r6 { fill: #f59e0b } -.terminal-2623049041-r7 { fill: #f04438;font-weight: bold } -.terminal-2623049041-r8 { fill: #e0e0e0;font-weight: bold } -.terminal-2623049041-r9 { fill: #22c55e;font-weight: bold } -.terminal-2623049041-r10 { fill: #000000 } + .terminal-2084666923-r1 { fill: #e0e0e0 } +.terminal-2084666923-r2 { fill: #c5c8c6 } +.terminal-2084666923-r3 { fill: #614fd2;font-weight: bold } +.terminal-2084666923-r4 { fill: #939393 } +.terminal-2084666923-r5 { fill: #614fd2 } +.terminal-2084666923-r6 { fill: #f59e0b } +.terminal-2084666923-r7 { fill: #f04438;font-weight: bold } +.terminal-2084666923-r8 { fill: #e0e0e0;font-weight: bold } +.terminal-2084666923-r9 { fill: #22c55e;font-weight: bold } +.terminal-2084666923-r10 { fill: #939393;font-weight: bold } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - AssemblyAI Code + AssemblyAI Code - - - - - █████╗  ███████╗ ███████╗ ███████╗ ███╗   ███╗ ██████╗  ██╗      ██╗   ██╗ -██╔══██╗ ██╔════╝ ██╔════╝ ██╔════╝ ████╗ ████║ ██╔══██╗ ██║      ╚██╗ ██╔╝ -███████║ ███████╗ ███████╗ █████╗   ██╔████╔██║ ██████╔╝ ██║       ╚████╔╝  -██╔══██║ ╚════██║ ╚════██║ ██╔══╝   ██║╚██╔╝██║ ██╔══██╗ ██║        ╚██╔╝   -██║  ██║ ███████║ ███████║ ███████╗ ██║ ╚═╝ ██║ ██████╔╝ ███████╗    ██║    -╚═╝  ╚═╝ ╚══════╝ ╚══════╝ ╚══════╝ ╚═╝     ╚═╝ ╚═════╝  ╚══════╝    ╚═╝    -v9.9.9 - -Thread: default - -Ready to code! What would you like to build? -Tip: approve tools as they run, or pass --auto to skip the prompts. - - - - - - - - - - - -╭────────────────────────────────────────────────────────────────────────────────────────────────╮ -⚠ This command deletes files recursively/forcibly. -Run tool execute?  rm -rf build/ -y approve   a auto-approve   n reject   e expand -╰────────────────────────────────────────────────────────────────────────────────────────────────╯ - manual ~/demo↗ main + + + + + █████╗  ███████╗ ███████╗ ███████╗ ███╗   ███╗ ██████╗  ██╗      ██╗   ██╗ +██╔══██╗ ██╔════╝ ██╔════╝ ██╔════╝ ████╗ ████║ ██╔══██╗ ██║      ╚██╗ ██╔╝ +███████║ ███████╗ ███████╗ █████╗   ██╔████╔██║ ██████╔╝ ██║       ╚████╔╝  +██╔══██║ ╚════██║ ╚════██║ ██╔══╝   ██║╚██╔╝██║ ██╔══██╗ ██║        ╚██╔╝   +██║  ██║ ███████║ ███████║ ███████╗ ██║ ╚═╝ ██║ ██████╔╝ ███████╗    ██║    +╚═╝  ╚═╝ ╚══════╝ ╚══════╝ ╚══════╝ ╚═╝     ╚═╝ ╚═════╝  ╚══════╝    ╚═╝    +v9.9.9 + +Thread: default + +Ready to code! What would you like to build? +Tip: approve tools as they run, or pass --auto to skip the prompts. + + + + + + + + + + + +╭────────────────────────────────────────────────────────────────────────────────────────────────╮ +⚠ This command deletes files recursively/forcibly. +Run tool execute?  rm -rf build/ +y approve   a auto-approve   n reject   e expand +╰────────────────────────────────────────────────────────────────────────────────────────────────╯ +^Y copy · ^O expand · esc interrupt · ^C quit diff --git a/tests/__snapshots__/test_tui_snapshots/test_code_approval_modal_benign.raw b/tests/__snapshots__/test_tui_snapshots/test_code_approval_modal_benign.raw index 673aebf..9ebc31b 100644 --- a/tests/__snapshots__/test_tui_snapshots/test_code_approval_modal_benign.raw +++ b/tests/__snapshots__/test_tui_snapshots/test_code_approval_modal_benign.raw @@ -19,164 +19,164 @@ font-weight: 700; } - .terminal-901522975-matrix { + .terminal-1417549561-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-901522975-title { + .terminal-1417549561-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-901522975-r1 { fill: #e0e0e0 } -.terminal-901522975-r2 { fill: #c5c8c6 } -.terminal-901522975-r3 { fill: #614fd2;font-weight: bold } -.terminal-901522975-r4 { fill: #939393 } -.terminal-901522975-r5 { fill: #614fd2 } -.terminal-901522975-r6 { fill: #f59e0b } -.terminal-901522975-r7 { fill: #e0e0e0;font-weight: bold } -.terminal-901522975-r8 { fill: #22c55e;font-weight: bold } -.terminal-901522975-r9 { fill: #f04438;font-weight: bold } -.terminal-901522975-r10 { fill: #000000 } + .terminal-1417549561-r1 { fill: #e0e0e0 } +.terminal-1417549561-r2 { fill: #c5c8c6 } +.terminal-1417549561-r3 { fill: #614fd2;font-weight: bold } +.terminal-1417549561-r4 { fill: #939393 } +.terminal-1417549561-r5 { fill: #614fd2 } +.terminal-1417549561-r6 { fill: #f59e0b } +.terminal-1417549561-r7 { fill: #e0e0e0;font-weight: bold } +.terminal-1417549561-r8 { fill: #22c55e;font-weight: bold } +.terminal-1417549561-r9 { fill: #f04438;font-weight: bold } +.terminal-1417549561-r10 { fill: #939393;font-weight: bold } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - AssemblyAI Code + AssemblyAI Code - - - - - █████╗  ███████╗ ███████╗ ███████╗ ███╗   ███╗ ██████╗  ██╗      ██╗   ██╗ -██╔══██╗ ██╔════╝ ██╔════╝ ██╔════╝ ████╗ ████║ ██╔══██╗ ██║      ╚██╗ ██╔╝ -███████║ ███████╗ ███████╗ █████╗   ██╔████╔██║ ██████╔╝ ██║       ╚████╔╝  -██╔══██║ ╚════██║ ╚════██║ ██╔══╝   ██║╚██╔╝██║ ██╔══██╗ ██║        ╚██╔╝   -██║  ██║ ███████║ ███████║ ███████╗ ██║ ╚═╝ ██║ ██████╔╝ ███████╗    ██║    -╚═╝  ╚═╝ ╚══════╝ ╚══════╝ ╚══════╝ ╚═╝     ╚═╝ ╚═════╝  ╚══════╝    ╚═╝    -v9.9.9 - -Thread: default - -Ready to code! What would you like to build? -Tip: approve tools as they run, or pass --auto to skip the prompts. - - - - - - - - - - - - -╭────────────────────────────────────────────────────────────────────────────────────────────────╮ -Run tool execute?  ls -la -y approve   a auto-approve   n reject   e expand -╰────────────────────────────────────────────────────────────────────────────────────────────────╯ - manual ~/demo↗ main + + + + + █████╗  ███████╗ ███████╗ ███████╗ ███╗   ███╗ ██████╗  ██╗      ██╗   ██╗ +██╔══██╗ ██╔════╝ ██╔════╝ ██╔════╝ ████╗ ████║ ██╔══██╗ ██║      ╚██╗ ██╔╝ +███████║ ███████╗ ███████╗ █████╗   ██╔████╔██║ ██████╔╝ ██║       ╚████╔╝  +██╔══██║ ╚════██║ ╚════██║ ██╔══╝   ██║╚██╔╝██║ ██╔══██╗ ██║        ╚██╔╝   +██║  ██║ ███████║ ███████║ ███████╗ ██║ ╚═╝ ██║ ██████╔╝ ███████╗    ██║    +╚═╝  ╚═╝ ╚══════╝ ╚══════╝ ╚══════╝ ╚═╝     ╚═╝ ╚═════╝  ╚══════╝    ╚═╝    +v9.9.9 + +Thread: default + +Ready to code! What would you like to build? +Tip: approve tools as they run, or pass --auto to skip the prompts. + + + + + + + + + + + + +╭────────────────────────────────────────────────────────────────────────────────────────────────╮ +Run tool execute?  ls -la +y approve   a auto-approve   n reject   e expand +╰────────────────────────────────────────────────────────────────────────────────────────────────╯ +^Y copy · ^O expand · esc interrupt · ^C quit diff --git a/tests/__snapshots__/test_tui_snapshots/test_code_approval_modal_expanded.raw b/tests/__snapshots__/test_tui_snapshots/test_code_approval_modal_expanded.raw index f15782d..1754ee9 100644 --- a/tests/__snapshots__/test_tui_snapshots/test_code_approval_modal_expanded.raw +++ b/tests/__snapshots__/test_tui_snapshots/test_code_approval_modal_expanded.raw @@ -19,164 +19,164 @@ font-weight: 700; } - .terminal-1367203125-matrix { + .terminal-3998338575-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-1367203125-title { + .terminal-3998338575-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-1367203125-r1 { fill: #e0e0e0 } -.terminal-1367203125-r2 { fill: #c5c8c6 } -.terminal-1367203125-r3 { fill: #614fd2;font-weight: bold } -.terminal-1367203125-r4 { fill: #939393 } -.terminal-1367203125-r5 { fill: #614fd2 } -.terminal-1367203125-r6 { fill: #f59e0b } -.terminal-1367203125-r7 { fill: #e0e0e0;font-weight: bold } -.terminal-1367203125-r8 { fill: #22c55e;font-weight: bold } -.terminal-1367203125-r9 { fill: #f04438;font-weight: bold } -.terminal-1367203125-r10 { fill: #000000 } + .terminal-3998338575-r1 { fill: #e0e0e0 } +.terminal-3998338575-r2 { fill: #c5c8c6 } +.terminal-3998338575-r3 { fill: #614fd2;font-weight: bold } +.terminal-3998338575-r4 { fill: #939393 } +.terminal-3998338575-r5 { fill: #614fd2 } +.terminal-3998338575-r6 { fill: #f59e0b } +.terminal-3998338575-r7 { fill: #e0e0e0;font-weight: bold } +.terminal-3998338575-r8 { fill: #22c55e;font-weight: bold } +.terminal-3998338575-r9 { fill: #f04438;font-weight: bold } +.terminal-3998338575-r10 { fill: #939393;font-weight: bold } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - AssemblyAI Code + AssemblyAI Code - - - - - █████╗  ███████╗ ███████╗ ███████╗ ███╗   ███╗ ██████╗  ██╗      ██╗   ██╗ -██╔══██╗ ██╔════╝ ██╔════╝ ██╔════╝ ████╗ ████║ ██╔══██╗ ██║      ╚██╗ ██╔╝ -███████║ ███████╗ ███████╗ █████╗   ██╔████╔██║ ██████╔╝ ██║       ╚████╔╝  -██╔══██║ ╚════██║ ╚════██║ ██╔══╝   ██║╚██╔╝██║ ██╔══██╗ ██║        ╚██╔╝   -██║  ██║ ███████║ ███████║ ███████╗ ██║ ╚═╝ ██║ ██████╔╝ ███████╗    ██║    -╚═╝  ╚═╝ ╚══════╝ ╚══════╝ ╚══════╝ ╚═╝     ╚═╝ ╚═════╝  ╚══════╝    ╚═╝    -v9.9.9 - -Thread: default - -Ready to code! What would you like to build? -Tip: approve tools as they run, or pass --auto to skip the prompts. - - - - - - - - - - -╭────────────────────────────────────────────────────────────────────────────────────────────────╮ -Run tool write_file?  file_path=app.py -content=PORT = 8080 -DEBUG = 1 -y approve   a auto-approve   n reject   e expand -╰────────────────────────────────────────────────────────────────────────────────────────────────╯ - manual ~/demo↗ main + + + + + █████╗  ███████╗ ███████╗ ███████╗ ███╗   ███╗ ██████╗  ██╗      ██╗   ██╗ +██╔══██╗ ██╔════╝ ██╔════╝ ██╔════╝ ████╗ ████║ ██╔══██╗ ██║      ╚██╗ ██╔╝ +███████║ ███████╗ ███████╗ █████╗   ██╔████╔██║ ██████╔╝ ██║       ╚████╔╝  +██╔══██║ ╚════██║ ╚════██║ ██╔══╝   ██║╚██╔╝██║ ██╔══██╗ ██║        ╚██╔╝   +██║  ██║ ███████║ ███████║ ███████╗ ██║ ╚═╝ ██║ ██████╔╝ ███████╗    ██║    +╚═╝  ╚═╝ ╚══════╝ ╚══════╝ ╚══════╝ ╚═╝     ╚═╝ ╚═════╝  ╚══════╝    ╚═╝    +v9.9.9 + +Thread: default + +Ready to code! What would you like to build? +Tip: approve tools as they run, or pass --auto to skip the prompts. + + + + + + + + + + +╭────────────────────────────────────────────────────────────────────────────────────────────────╮ +Run tool write_file?  file_path=app.py +content=PORT = 8080 +DEBUG = 1 +y approve   a auto-approve   n reject   e expand +╰────────────────────────────────────────────────────────────────────────────────────────────────╯ +^Y copy · ^O expand · esc interrupt · ^C quit diff --git a/tests/__snapshots__/test_tui_snapshots/test_code_ask_modal.raw b/tests/__snapshots__/test_tui_snapshots/test_code_ask_modal.raw index 02bbd4f..3eed1ac 100644 --- a/tests/__snapshots__/test_tui_snapshots/test_code_ask_modal.raw +++ b/tests/__snapshots__/test_tui_snapshots/test_code_ask_modal.raw @@ -19,165 +19,166 @@ font-weight: 700; } - .terminal-1386297441-matrix { + .terminal-4063177019-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-1386297441-title { + .terminal-4063177019-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-1386297441-r1 { fill: #e0e0e0 } -.terminal-1386297441-r2 { fill: #c5c8c6 } -.terminal-1386297441-r3 { fill: #614fd2;font-weight: bold } -.terminal-1386297441-r4 { fill: #939393 } -.terminal-1386297441-r5 { fill: #614fd2 } -.terminal-1386297441-r6 { fill: #3a3f55 } -.terminal-1386297441-r7 { fill: #e0e0e0;font-weight: bold } -.terminal-1386297441-r8 { fill: #000000 } -.terminal-1386297441-r9 { fill: #0178d4 } -.terminal-1386297441-r10 { fill: #121212 } -.terminal-1386297441-r11 { fill: #797979 } + .terminal-4063177019-r1 { fill: #e0e0e0 } +.terminal-4063177019-r2 { fill: #c5c8c6 } +.terminal-4063177019-r3 { fill: #614fd2;font-weight: bold } +.terminal-4063177019-r4 { fill: #939393 } +.terminal-4063177019-r5 { fill: #614fd2 } +.terminal-4063177019-r6 { fill: #3a3f55 } +.terminal-4063177019-r7 { fill: #e0e0e0;font-weight: bold } +.terminal-4063177019-r8 { fill: #000000 } +.terminal-4063177019-r9 { fill: #0178d4 } +.terminal-4063177019-r10 { fill: #121212 } +.terminal-4063177019-r11 { fill: #797979 } +.terminal-4063177019-r12 { fill: #939393;font-weight: bold } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - AssemblyAI Code + AssemblyAI Code - - - - - █████╗  ███████╗ ███████╗ ███████╗ ███╗   ███╗ ██████╗  ██╗      ██╗   ██╗ -██╔══██╗ ██╔════╝ ██╔════╝ ██╔════╝ ████╗ ████║ ██╔══██╗ ██║      ╚██╗ ██╔╝ -███████║ ███████╗ ███████╗ █████╗   ██╔████╔██║ ██████╔╝ ██║       ╚████╔╝  -██╔══██║ ╚════██║ ╚════██║ ██╔══╝   ██║╚██╔╝██║ ██╔══██╗ ██║        ╚██╔╝   -██║  ██║ ███████║ ███████║ ███████╗ ██║ ╚═╝ ██║ ██████╔╝ ███████╗    ██║    -╚═╝  ╚═╝ ╚══════╝ ╚══════╝ ╚══════╝ ╚═╝     ╚═╝ ╚═════╝  ╚══════╝    ╚═╝    -v9.9.9 - -Thread: default - -Ready to code! What would you like to build? -Tip: approve tools as they run, or pass --auto to skip the prompts. - - - - - - - - - - -╭────────────────────────────────────────────────────────────────────────────────────────────────╮ -The agent asks: Which port should the dev server use? -▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ -Type your answer and press Enter… -▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ -╰────────────────────────────────────────────────────────────────────────────────────────────────╯ - manual ~/demo↗ main + + + + + █████╗  ███████╗ ███████╗ ███████╗ ███╗   ███╗ ██████╗  ██╗      ██╗   ██╗ +██╔══██╗ ██╔════╝ ██╔════╝ ██╔════╝ ████╗ ████║ ██╔══██╗ ██║      ╚██╗ ██╔╝ +███████║ ███████╗ ███████╗ █████╗   ██╔████╔██║ ██████╔╝ ██║       ╚████╔╝  +██╔══██║ ╚════██║ ╚════██║ ██╔══╝   ██║╚██╔╝██║ ██╔══██╗ ██║        ╚██╔╝   +██║  ██║ ███████║ ███████║ ███████╗ ██║ ╚═╝ ██║ ██████╔╝ ███████╗    ██║    +╚═╝  ╚═╝ ╚══════╝ ╚══════╝ ╚══════╝ ╚═╝     ╚═╝ ╚═════╝  ╚══════╝    ╚═╝    +v9.9.9 + +Thread: default + +Ready to code! What would you like to build? +Tip: approve tools as they run, or pass --auto to skip the prompts. + + + + + + + + + + +╭────────────────────────────────────────────────────────────────────────────────────────────────╮ +The agent asks: Which port should the dev server use? +▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +Type your answer and press Enter… +▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ +╰────────────────────────────────────────────────────────────────────────────────────────────────╯ +^Y copy · ^O expand · esc interrupt · ^C quit diff --git a/tests/__snapshots__/test_tui_snapshots/test_code_error.raw b/tests/__snapshots__/test_tui_snapshots/test_code_error.raw index bb805a7..5a40a2d 100644 --- a/tests/__snapshots__/test_tui_snapshots/test_code_error.raw +++ b/tests/__snapshots__/test_tui_snapshots/test_code_error.raw @@ -19,165 +19,166 @@ font-weight: 700; } - .terminal-1956613797-matrix { + .terminal-2239750680-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-1956613797-title { + .terminal-2239750680-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-1956613797-r1 { fill: #c5c8c6 } -.terminal-1956613797-r2 { fill: #614fd2;font-weight: bold } -.terminal-1956613797-r3 { fill: #939393 } -.terminal-1956613797-r4 { fill: #e0e0e0 } -.terminal-1956613797-r5 { fill: #614fd2 } -.terminal-1956613797-r6 { fill: #38bdf8;font-weight: bold } -.terminal-1956613797-r7 { fill: #f04438 } -.terminal-1956613797-r8 { fill: #3a3f55 } -.terminal-1956613797-r9 { fill: #121212 } -.terminal-1956613797-r10 { fill: #676767 } -.terminal-1956613797-r11 { fill: #000000 } + .terminal-2239750680-r1 { fill: #c5c8c6 } +.terminal-2239750680-r2 { fill: #614fd2;font-weight: bold } +.terminal-2239750680-r3 { fill: #939393 } +.terminal-2239750680-r4 { fill: #e0e0e0 } +.terminal-2239750680-r5 { fill: #614fd2 } +.terminal-2239750680-r6 { fill: #38bdf8;font-weight: bold } +.terminal-2239750680-r7 { fill: #f04438 } +.terminal-2239750680-r8 { fill: #3a3f55 } +.terminal-2239750680-r9 { fill: #121212 } +.terminal-2239750680-r10 { fill: #676767 } +.terminal-2239750680-r11 { fill: #000000 } +.terminal-2239750680-r12 { fill: #939393;font-weight: bold } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - AssemblyAI Code + AssemblyAI Code - - - - - █████╗  ███████╗ ███████╗ ███████╗ ███╗   ███╗ ██████╗  ██╗      ██╗   ██╗ -██╔══██╗ ██╔════╝ ██╔════╝ ██╔════╝ ████╗ ████║ ██╔══██╗ ██║      ╚██╗ ██╔╝ -███████║ ███████╗ ███████╗ █████╗   ██╔████╔██║ ██████╔╝ ██║       ╚████╔╝  -██╔══██║ ╚════██║ ╚════██║ ██╔══╝   ██║╚██╔╝██║ ██╔══██╗ ██║        ╚██╔╝   -██║  ██║ ███████║ ███████║ ███████╗ ██║ ╚═╝ ██║ ██████╔╝ ███████╗    ██║    -╚═╝  ╚═╝ ╚══════╝ ╚══════╝ ╚══════╝ ╚═╝     ╚═╝ ╚═════╝  ╚══════╝    ╚═╝    -v9.9.9 - -Thread: default - -Ready to code! What would you like to build? -Tip: approve tools as they run, or pass --auto to skip the prompts. - -» deploy to prod -✗ gateway unreachable: connection refused - - - - - - - - - - -╭────────────────────────────────────────────────────────────────────────────────────────────────╮ ->Ask the agent to build something… -╰────────────────────────────────────────────────────────────────────────────────────────────────╯ - manual ~/demo↗ main + + + + + █████╗  ███████╗ ███████╗ ███████╗ ███╗   ███╗ ██████╗  ██╗      ██╗   ██╗ +██╔══██╗ ██╔════╝ ██╔════╝ ██╔════╝ ████╗ ████║ ██╔══██╗ ██║      ╚██╗ ██╔╝ +███████║ ███████╗ ███████╗ █████╗   ██╔████╔██║ ██████╔╝ ██║       ╚████╔╝  +██╔══██║ ╚════██║ ╚════██║ ██╔══╝   ██║╚██╔╝██║ ██╔══██╗ ██║        ╚██╔╝   +██║  ██║ ███████║ ███████║ ███████╗ ██║ ╚═╝ ██║ ██████╔╝ ███████╗    ██║    +╚═╝  ╚═╝ ╚══════╝ ╚══════╝ ╚══════╝ ╚═╝     ╚═╝ ╚═════╝  ╚══════╝    ╚═╝    +v9.9.9 + +Thread: default + +Ready to code! What would you like to build? +Tip: approve tools as they run, or pass --auto to skip the prompts. + +» deploy to prod +✗ gateway unreachable: connection refused + + + + + + + + + + +╭────────────────────────────────────────────────────────────────────────────────────────────────╮ +>Ask the agent to build something… + manual ~/demo↗ main +^Y copy · ^O expand · esc interrupt · ^C quit diff --git a/tests/__snapshots__/test_tui_snapshots/test_code_splash.raw b/tests/__snapshots__/test_tui_snapshots/test_code_splash.raw index 770b28c..b9553b2 100644 --- a/tests/__snapshots__/test_tui_snapshots/test_code_splash.raw +++ b/tests/__snapshots__/test_tui_snapshots/test_code_splash.raw @@ -19,163 +19,164 @@ font-weight: 700; } - .terminal-2744299105-matrix { + .terminal-189530595-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-2744299105-title { + .terminal-189530595-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-2744299105-r1 { fill: #c5c8c6 } -.terminal-2744299105-r2 { fill: #614fd2;font-weight: bold } -.terminal-2744299105-r3 { fill: #939393 } -.terminal-2744299105-r4 { fill: #e0e0e0 } -.terminal-2744299105-r5 { fill: #614fd2 } -.terminal-2744299105-r6 { fill: #3a3f55 } -.terminal-2744299105-r7 { fill: #121212 } -.terminal-2744299105-r8 { fill: #676767 } -.terminal-2744299105-r9 { fill: #000000 } + .terminal-189530595-r1 { fill: #c5c8c6 } +.terminal-189530595-r2 { fill: #614fd2;font-weight: bold } +.terminal-189530595-r3 { fill: #939393 } +.terminal-189530595-r4 { fill: #e0e0e0 } +.terminal-189530595-r5 { fill: #614fd2 } +.terminal-189530595-r6 { fill: #3a3f55 } +.terminal-189530595-r7 { fill: #121212 } +.terminal-189530595-r8 { fill: #676767 } +.terminal-189530595-r9 { fill: #000000 } +.terminal-189530595-r10 { fill: #939393;font-weight: bold } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - AssemblyAI Code + AssemblyAI Code - - - - - █████╗  ███████╗ ███████╗ ███████╗ ███╗   ███╗ ██████╗  ██╗      ██╗   ██╗ -██╔══██╗ ██╔════╝ ██╔════╝ ██╔════╝ ████╗ ████║ ██╔══██╗ ██║      ╚██╗ ██╔╝ -███████║ ███████╗ ███████╗ █████╗   ██╔████╔██║ ██████╔╝ ██║       ╚████╔╝  -██╔══██║ ╚════██║ ╚════██║ ██╔══╝   ██║╚██╔╝██║ ██╔══██╗ ██║        ╚██╔╝   -██║  ██║ ███████║ ███████║ ███████╗ ██║ ╚═╝ ██║ ██████╔╝ ███████╗    ██║    -╚═╝  ╚═╝ ╚══════╝ ╚══════╝ ╚══════╝ ╚═╝     ╚═╝ ╚═════╝  ╚══════╝    ╚═╝    -v9.9.9 - -Thread: default - -Ready to code! What would you like to build? -Tip: approve tools as they run, or pass --auto to skip the prompts. - - - - - - - - - - - - - -╭────────────────────────────────────────────────────────────────────────────────────────────────╮ ->Ask the agent to build something… -╰────────────────────────────────────────────────────────────────────────────────────────────────╯ - manual ~/demo↗ main + + + + + █████╗  ███████╗ ███████╗ ███████╗ ███╗   ███╗ ██████╗  ██╗      ██╗   ██╗ +██╔══██╗ ██╔════╝ ██╔════╝ ██╔════╝ ████╗ ████║ ██╔══██╗ ██║      ╚██╗ ██╔╝ +███████║ ███████╗ ███████╗ █████╗   ██╔████╔██║ ██████╔╝ ██║       ╚████╔╝  +██╔══██║ ╚════██║ ╚════██║ ██╔══╝   ██║╚██╔╝██║ ██╔══██╗ ██║        ╚██╔╝   +██║  ██║ ███████║ ███████║ ███████╗ ██║ ╚═╝ ██║ ██████╔╝ ███████╗    ██║    +╚═╝  ╚═╝ ╚══════╝ ╚══════╝ ╚══════╝ ╚═╝     ╚═╝ ╚═════╝  ╚══════╝    ╚═╝    +v9.9.9 + +Thread: default + +Ready to code! What would you like to build? +Tip: approve tools as they run, or pass --auto to skip the prompts. + + + + + + + + + + + + + +╭────────────────────────────────────────────────────────────────────────────────────────────────╮ +>Ask the agent to build something… + manual ~/demo↗ main +^Y copy · ^O expand · esc interrupt · ^C quit diff --git a/tests/__snapshots__/test_tui_snapshots/test_code_status_auto_approve.raw b/tests/__snapshots__/test_tui_snapshots/test_code_status_auto_approve.raw index 71d048f..3932905 100644 --- a/tests/__snapshots__/test_tui_snapshots/test_code_status_auto_approve.raw +++ b/tests/__snapshots__/test_tui_snapshots/test_code_status_auto_approve.raw @@ -19,163 +19,164 @@ font-weight: 700; } - .terminal-2985930204-matrix { + .terminal-3300524382-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-2985930204-title { + .terminal-3300524382-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-2985930204-r1 { fill: #c5c8c6 } -.terminal-2985930204-r2 { fill: #614fd2;font-weight: bold } -.terminal-2985930204-r3 { fill: #939393 } -.terminal-2985930204-r4 { fill: #e0e0e0 } -.terminal-2985930204-r5 { fill: #614fd2 } -.terminal-2985930204-r6 { fill: #3a3f55 } -.terminal-2985930204-r7 { fill: #121212 } -.terminal-2985930204-r8 { fill: #676767 } -.terminal-2985930204-r9 { fill: #000000 } + .terminal-3300524382-r1 { fill: #c5c8c6 } +.terminal-3300524382-r2 { fill: #614fd2;font-weight: bold } +.terminal-3300524382-r3 { fill: #939393 } +.terminal-3300524382-r4 { fill: #e0e0e0 } +.terminal-3300524382-r5 { fill: #614fd2 } +.terminal-3300524382-r6 { fill: #3a3f55 } +.terminal-3300524382-r7 { fill: #121212 } +.terminal-3300524382-r8 { fill: #676767 } +.terminal-3300524382-r9 { fill: #000000 } +.terminal-3300524382-r10 { fill: #939393;font-weight: bold } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - AssemblyAI Code + AssemblyAI Code - - - - - █████╗  ███████╗ ███████╗ ███████╗ ███╗   ███╗ ██████╗  ██╗      ██╗   ██╗ -██╔══██╗ ██╔════╝ ██╔════╝ ██╔════╝ ████╗ ████║ ██╔══██╗ ██║      ╚██╗ ██╔╝ -███████║ ███████╗ ███████╗ █████╗   ██╔████╔██║ ██████╔╝ ██║       ╚████╔╝  -██╔══██║ ╚════██║ ╚════██║ ██╔══╝   ██║╚██╔╝██║ ██╔══██╗ ██║        ╚██╔╝   -██║  ██║ ███████║ ███████║ ███████╗ ██║ ╚═╝ ██║ ██████╔╝ ███████╗    ██║    -╚═╝  ╚═╝ ╚══════╝ ╚══════╝ ╚══════╝ ╚═╝     ╚═╝ ╚═════╝  ╚══════╝    ╚═╝    -v9.9.9 - -Thread: default - -Ready to code! What would you like to build? -Tip: approve tools as they run, or pass --auto to skip the prompts. - - - - - - - - - - - - - -╭────────────────────────────────────────────────────────────────────────────────────────────────╮ ->Ask the agent to build something… -╰────────────────────────────────────────────────────────────────────────────────────────────────╯ - auto ~/demo↗ main + + + + + █████╗  ███████╗ ███████╗ ███████╗ ███╗   ███╗ ██████╗  ██╗      ██╗   ██╗ +██╔══██╗ ██╔════╝ ██╔════╝ ██╔════╝ ████╗ ████║ ██╔══██╗ ██║      ╚██╗ ██╔╝ +███████║ ███████╗ ███████╗ █████╗   ██╔████╔██║ ██████╔╝ ██║       ╚████╔╝  +██╔══██║ ╚════██║ ╚════██║ ██╔══╝   ██║╚██╔╝██║ ██╔══██╗ ██║        ╚██╔╝   +██║  ██║ ███████║ ███████║ ███████╗ ██║ ╚═╝ ██║ ██████╔╝ ███████╗    ██║    +╚═╝  ╚═╝ ╚══════╝ ╚══════╝ ╚══════╝ ╚═╝     ╚═╝ ╚═════╝  ╚══════╝    ╚═╝    +v9.9.9 + +Thread: default + +Ready to code! What would you like to build? +Tip: approve tools as they run, or pass --auto to skip the prompts. + + + + + + + + + + + + + +╭────────────────────────────────────────────────────────────────────────────────────────────────╮ +>Ask the agent to build something… + auto ~/demo↗ main +^Y copy · ^O expand · esc interrupt · ^C quit diff --git a/tests/__snapshots__/test_tui_snapshots/test_code_streaming_reply.raw b/tests/__snapshots__/test_tui_snapshots/test_code_streaming_reply.raw index 95ca020..b3ae8b1 100644 --- a/tests/__snapshots__/test_tui_snapshots/test_code_streaming_reply.raw +++ b/tests/__snapshots__/test_tui_snapshots/test_code_streaming_reply.raw @@ -19,164 +19,165 @@ font-weight: 700; } - .terminal-773362532-matrix { + .terminal-730392279-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-773362532-title { + .terminal-730392279-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-773362532-r1 { fill: #c5c8c6 } -.terminal-773362532-r2 { fill: #614fd2;font-weight: bold } -.terminal-773362532-r3 { fill: #939393 } -.terminal-773362532-r4 { fill: #e0e0e0 } -.terminal-773362532-r5 { fill: #614fd2 } -.terminal-773362532-r6 { fill: #38bdf8;font-weight: bold } -.terminal-773362532-r7 { fill: #3a3f55 } -.terminal-773362532-r8 { fill: #121212 } -.terminal-773362532-r9 { fill: #676767 } -.terminal-773362532-r10 { fill: #000000 } + .terminal-730392279-r1 { fill: #c5c8c6 } +.terminal-730392279-r2 { fill: #614fd2;font-weight: bold } +.terminal-730392279-r3 { fill: #939393 } +.terminal-730392279-r4 { fill: #e0e0e0 } +.terminal-730392279-r5 { fill: #614fd2 } +.terminal-730392279-r6 { fill: #38bdf8;font-weight: bold } +.terminal-730392279-r7 { fill: #3a3f55 } +.terminal-730392279-r8 { fill: #121212 } +.terminal-730392279-r9 { fill: #676767 } +.terminal-730392279-r10 { fill: #000000 } +.terminal-730392279-r11 { fill: #939393;font-weight: bold } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - AssemblyAI Code + AssemblyAI Code - - - - - █████╗  ███████╗ ███████╗ ███████╗ ███╗   ███╗ ██████╗  ██╗      ██╗   ██╗ -██╔══██╗ ██╔════╝ ██╔════╝ ██╔════╝ ████╗ ████║ ██╔══██╗ ██║      ╚██╗ ██╔╝ -███████║ ███████╗ ███████╗ █████╗   ██╔████╔██║ ██████╔╝ ██║       ╚████╔╝  -██╔══██║ ╚════██║ ╚════██║ ██╔══╝   ██║╚██╔╝██║ ██╔══██╗ ██║        ╚██╔╝   -██║  ██║ ███████║ ███████║ ███████╗ ██║ ╚═╝ ██║ ██████╔╝ ███████╗    ██║    -╚═╝  ╚═╝ ╚══════╝ ╚══════╝ ╚══════╝ ╚═╝     ╚═╝ ╚═════╝  ╚══════╝    ╚═╝    -v9.9.9 - -Thread: default - -Ready to code! What would you like to build? -Tip: approve tools as they run, or pass --auto to skip the prompts. - -» explain the plan -Here's the plan. First **scaffold** the project, then wire up the tests. - - - - - - - - - - -╭────────────────────────────────────────────────────────────────────────────────────────────────╮ ->Ask the agent to build something… -╰────────────────────────────────────────────────────────────────────────────────────────────────╯ - manual ~/demo↗ main + + + + + █████╗  ███████╗ ███████╗ ███████╗ ███╗   ███╗ ██████╗  ██╗      ██╗   ██╗ +██╔══██╗ ██╔════╝ ██╔════╝ ██╔════╝ ████╗ ████║ ██╔══██╗ ██║      ╚██╗ ██╔╝ +███████║ ███████╗ ███████╗ █████╗   ██╔████╔██║ ██████╔╝ ██║       ╚████╔╝  +██╔══██║ ╚════██║ ╚════██║ ██╔══╝   ██║╚██╔╝██║ ██╔══██╗ ██║        ╚██╔╝   +██║  ██║ ███████║ ███████║ ███████╗ ██║ ╚═╝ ██║ ██████╔╝ ███████╗    ██║    +╚═╝  ╚═╝ ╚══════╝ ╚══════╝ ╚══════╝ ╚═╝     ╚═╝ ╚═════╝  ╚══════╝    ╚═╝    +v9.9.9 + +Thread: default + +Ready to code! What would you like to build? +Tip: approve tools as they run, or pass --auto to skip the prompts. + +» explain the plan +Here's the plan. First **scaffold** the project, then wire up the tests. + + + + + + + + + + +╭────────────────────────────────────────────────────────────────────────────────────────────────╮ +>Ask the agent to build something… + manual ~/demo↗ main +^Y copy · ^O expand · esc interrupt · ^C quit diff --git a/tests/__snapshots__/test_tui_snapshots/test_code_tool_output_collapsed.raw b/tests/__snapshots__/test_tui_snapshots/test_code_tool_output_collapsed.raw index 705dbe0..62998d0 100644 --- a/tests/__snapshots__/test_tui_snapshots/test_code_tool_output_collapsed.raw +++ b/tests/__snapshots__/test_tui_snapshots/test_code_tool_output_collapsed.raw @@ -19,166 +19,167 @@ font-weight: 700; } - .terminal-2885406642-matrix { + .terminal-246752052-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-2885406642-title { + .terminal-246752052-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-2885406642-r1 { fill: #c5c8c6 } -.terminal-2885406642-r2 { fill: #614fd2;font-weight: bold } -.terminal-2885406642-r3 { fill: #939393 } -.terminal-2885406642-r4 { fill: #e0e0e0 } -.terminal-2885406642-r5 { fill: #614fd2 } -.terminal-2885406642-r6 { fill: #38bdf8;font-weight: bold } -.terminal-2885406642-r7 { fill: #8a8f98 } -.terminal-2885406642-r8 { fill: #8a8f98;font-style: italic; } -.terminal-2885406642-r9 { fill: #3a3f55 } -.terminal-2885406642-r10 { fill: #121212 } -.terminal-2885406642-r11 { fill: #676767 } -.terminal-2885406642-r12 { fill: #000000 } + .terminal-246752052-r1 { fill: #c5c8c6 } +.terminal-246752052-r2 { fill: #614fd2;font-weight: bold } +.terminal-246752052-r3 { fill: #939393 } +.terminal-246752052-r4 { fill: #e0e0e0 } +.terminal-246752052-r5 { fill: #614fd2 } +.terminal-246752052-r6 { fill: #38bdf8;font-weight: bold } +.terminal-246752052-r7 { fill: #8a8f98 } +.terminal-246752052-r8 { fill: #8a8f98;font-style: italic; } +.terminal-246752052-r9 { fill: #3a3f55 } +.terminal-246752052-r10 { fill: #121212 } +.terminal-246752052-r11 { fill: #676767 } +.terminal-246752052-r12 { fill: #000000 } +.terminal-246752052-r13 { fill: #939393;font-weight: bold } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - AssemblyAI Code + AssemblyAI Code - - - - - █████╗  ███████╗ ███████╗ ███████╗ ███╗   ███╗ ██████╗  ██╗      ██╗   ██╗ -██╔══██╗ ██╔════╝ ██╔════╝ ██╔════╝ ████╗ ████║ ██╔══██╗ ██║      ╚██╗ ██╔╝ -███████║ ███████╗ ███████╗ █████╗   ██╔████╔██║ ██████╔╝ ██║       ╚████╔╝  -██╔══██║ ╚════██║ ╚════██║ ██╔══╝   ██║╚██╔╝██║ ██╔══██╗ ██║        ╚██╔╝   -██║  ██║ ███████║ ███████║ ███████╗ ██║ ╚═╝ ██║ ██████╔╝ ███████╗    ██║    -╚═╝  ╚═╝ ╚══════╝ ╚══════╝ ╚══════╝ ╚═╝     ╚═╝ ╚═════╝  ╚══════╝    ╚═╝    -v9.9.9 - -Thread: default - -Ready to code! What would you like to build? -Tip: approve tools as they run, or pass --auto to skip the prompts. - -» run the tests -→ execute(pytest -q) -  execute: tests/test_module_0.py .... [ 0%] -tests/test_module_1.py .... [ 10%] -tests/test_module_2.py .... [ 20%] -tests/test_module_3.py .... [ 30%] … (+4 more lines) (Ctrl+O to expand) - - - - - - -╭────────────────────────────────────────────────────────────────────────────────────────────────╮ ->Ask the agent to build something… -╰────────────────────────────────────────────────────────────────────────────────────────────────╯ - manual ~/demo↗ main + + + + + █████╗  ███████╗ ███████╗ ███████╗ ███╗   ███╗ ██████╗  ██╗      ██╗   ██╗ +██╔══██╗ ██╔════╝ ██╔════╝ ██╔════╝ ████╗ ████║ ██╔══██╗ ██║      ╚██╗ ██╔╝ +███████║ ███████╗ ███████╗ █████╗   ██╔████╔██║ ██████╔╝ ██║       ╚████╔╝  +██╔══██║ ╚════██║ ╚════██║ ██╔══╝   ██║╚██╔╝██║ ██╔══██╗ ██║        ╚██╔╝   +██║  ██║ ███████║ ███████║ ███████╗ ██║ ╚═╝ ██║ ██████╔╝ ███████╗    ██║    +╚═╝  ╚═╝ ╚══════╝ ╚══════╝ ╚══════╝ ╚═╝     ╚═╝ ╚═════╝  ╚══════╝    ╚═╝    +v9.9.9 + +Thread: default + +Ready to code! What would you like to build? +Tip: approve tools as they run, or pass --auto to skip the prompts. + +» run the tests +→ execute(pytest -q) +  execute: tests/test_module_0.py .... [ 0%] +tests/test_module_1.py .... [ 10%] +tests/test_module_2.py .... [ 20%] +tests/test_module_3.py .... [ 30%] … (+4 more lines) (Ctrl+O to expand) + + + + + + +╭────────────────────────────────────────────────────────────────────────────────────────────────╮ +>Ask the agent to build something… + manual ~/demo↗ main +^Y copy · ^O expand · esc interrupt · ^C quit diff --git a/tests/__snapshots__/test_tui_snapshots/test_code_tool_output_expanded.raw b/tests/__snapshots__/test_tui_snapshots/test_code_tool_output_expanded.raw index 8e9a713..1e11c72 100644 --- a/tests/__snapshots__/test_tui_snapshots/test_code_tool_output_expanded.raw +++ b/tests/__snapshots__/test_tui_snapshots/test_code_tool_output_expanded.raw @@ -19,166 +19,167 @@ font-weight: 700; } - .terminal-2213969501-matrix { + .terminal-2792346064-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-2213969501-title { + .terminal-2792346064-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-2213969501-r1 { fill: #c5c8c6 } -.terminal-2213969501-r2 { fill: #614fd2;font-weight: bold } -.terminal-2213969501-r3 { fill: #939393 } -.terminal-2213969501-r4 { fill: #e0e0e0 } -.terminal-2213969501-r5 { fill: #614fd2 } -.terminal-2213969501-r6 { fill: #38bdf8;font-weight: bold } -.terminal-2213969501-r7 { fill: #8a8f98 } -.terminal-2213969501-r8 { fill: #8a8f98;font-style: italic; } -.terminal-2213969501-r9 { fill: #3a3f55 } -.terminal-2213969501-r10 { fill: #121212 } -.terminal-2213969501-r11 { fill: #676767 } -.terminal-2213969501-r12 { fill: #000000 } + .terminal-2792346064-r1 { fill: #c5c8c6 } +.terminal-2792346064-r2 { fill: #614fd2;font-weight: bold } +.terminal-2792346064-r3 { fill: #939393 } +.terminal-2792346064-r4 { fill: #e0e0e0 } +.terminal-2792346064-r5 { fill: #614fd2 } +.terminal-2792346064-r6 { fill: #38bdf8;font-weight: bold } +.terminal-2792346064-r7 { fill: #8a8f98 } +.terminal-2792346064-r8 { fill: #8a8f98;font-style: italic; } +.terminal-2792346064-r9 { fill: #3a3f55 } +.terminal-2792346064-r10 { fill: #121212 } +.terminal-2792346064-r11 { fill: #676767 } +.terminal-2792346064-r12 { fill: #000000 } +.terminal-2792346064-r13 { fill: #939393;font-weight: bold } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - AssemblyAI Code + AssemblyAI Code - - - - - █████╗  ███████╗ ███████╗ ███████╗ ███╗   ███╗ ██████╗  ██╗      ██╗   ██╗ -██╔══██╗ ██╔════╝ ██╔════╝ ██╔════╝ ████╗ ████║ ██╔══██╗ ██║      ╚██╗ ██╔╝ -███████║ ███████╗ ███████╗ █████╗   ██╔████╔██║ ██████╔╝ ██║       ╚████╔╝  -██╔══██║ ╚════██║ ╚════██║ ██╔══╝   ██║╚██╔╝██║ ██╔══██╗ ██║        ╚██╔╝   -██║  ██║ ███████║ ███████║ ███████╗ ██║ ╚═╝ ██║ ██████╔╝ ███████╗    ██║    -╚═╝  ╚═╝ ╚══════╝ ╚══════╝ ╚══════╝ ╚═╝     ╚═╝ ╚═════╝  ╚══════╝    ╚═╝    -v9.9.9 - -Thread: default - -Ready to code! What would you like to build? -Tip: approve tools as they run, or pass --auto to skip the prompts. - -» run the tests -→ execute(pytest -q) -  execute: tests/test_module_0.py .... [ 0%] -tests/test_module_1.py .... [ 10%] -tests/test_module_2.py .... [ 20%] -tests/test_module_3.py .... [ 30%] -tests/test_module_4.py .... [ 40%] -tests/test_module_5.py .... [ 50%] -tests/test_module_6.py .... [ 60%] -tests/test_module_7.py .... [ 70%] (Ctrl+O to collapse) - - -╭────────────────────────────────────────────────────────────────────────────────────────────────╮ ->Ask the agent to build something… -╰────────────────────────────────────────────────────────────────────────────────────────────────╯ - manual ~/demo↗ main + + + + + █████╗  ███████╗ ███████╗ ███████╗ ███╗   ███╗ ██████╗  ██╗      ██╗   ██╗ +██╔══██╗ ██╔════╝ ██╔════╝ ██╔════╝ ████╗ ████║ ██╔══██╗ ██║      ╚██╗ ██╔╝ +███████║ ███████╗ ███████╗ █████╗   ██╔████╔██║ ██████╔╝ ██║       ╚████╔╝  +██╔══██║ ╚════██║ ╚════██║ ██╔══╝   ██║╚██╔╝██║ ██╔══██╗ ██║        ╚██╔╝   +██║  ██║ ███████║ ███████║ ███████╗ ██║ ╚═╝ ██║ ██████╔╝ ███████╗    ██║    +╚═╝  ╚═╝ ╚══════╝ ╚══════╝ ╚══════╝ ╚═╝     ╚═╝ ╚═════╝  ╚══════╝    ╚═╝    +v9.9.9 + +Thread: default + +Ready to code! What would you like to build? +Tip: approve tools as they run, or pass --auto to skip the prompts. + +» run the tests +→ execute(pytest -q) +  execute: tests/test_module_0.py .... [ 0%] +tests/test_module_1.py .... [ 10%] +tests/test_module_2.py .... [ 20%] +tests/test_module_3.py .... [ 30%] +tests/test_module_4.py .... [ 40%] +tests/test_module_5.py .... [ 50%] +tests/test_module_6.py .... [ 60%] +tests/test_module_7.py .... [ 70%] (Ctrl+O to collapse) + + +╭────────────────────────────────────────────────────────────────────────────────────────────────╮ +>Ask the agent to build something… + manual ~/demo↗ main +^Y copy · ^O expand · esc interrupt · ^C quit diff --git a/tests/__snapshots__/test_tui_snapshots/test_code_transcript.raw b/tests/__snapshots__/test_tui_snapshots/test_code_transcript.raw index 152213d..fb3fe8d 100644 --- a/tests/__snapshots__/test_tui_snapshots/test_code_transcript.raw +++ b/tests/__snapshots__/test_tui_snapshots/test_code_transcript.raw @@ -19,167 +19,168 @@ font-weight: 700; } - .terminal-2481357719-matrix { + .terminal-1120851722-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-2481357719-title { + .terminal-1120851722-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-2481357719-r1 { fill: #c5c8c6 } -.terminal-2481357719-r2 { fill: #614fd2;font-weight: bold } -.terminal-2481357719-r3 { fill: #939393 } -.terminal-2481357719-r4 { fill: #e0e0e0 } -.terminal-2481357719-r5 { fill: #614fd2 } -.terminal-2481357719-r6 { fill: #38bdf8;font-weight: bold } -.terminal-2481357719-r7 { fill: #e0e0e0;font-weight: bold } -.terminal-2481357719-r8 { fill: #58d1eb } -.terminal-2481357719-r9 { fill: #8a8f98 } -.terminal-2481357719-r10 { fill: #3a3f55 } -.terminal-2481357719-r11 { fill: #121212 } -.terminal-2481357719-r12 { fill: #676767 } -.terminal-2481357719-r13 { fill: #000000 } + .terminal-1120851722-r1 { fill: #c5c8c6 } +.terminal-1120851722-r2 { fill: #614fd2;font-weight: bold } +.terminal-1120851722-r3 { fill: #939393 } +.terminal-1120851722-r4 { fill: #e0e0e0 } +.terminal-1120851722-r5 { fill: #614fd2 } +.terminal-1120851722-r6 { fill: #38bdf8;font-weight: bold } +.terminal-1120851722-r7 { fill: #e0e0e0;font-weight: bold } +.terminal-1120851722-r8 { fill: #58d1eb } +.terminal-1120851722-r9 { fill: #8a8f98 } +.terminal-1120851722-r10 { fill: #3a3f55 } +.terminal-1120851722-r11 { fill: #121212 } +.terminal-1120851722-r12 { fill: #676767 } +.terminal-1120851722-r13 { fill: #000000 } +.terminal-1120851722-r14 { fill: #939393;font-weight: bold } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - AssemblyAI Code + AssemblyAI Code - - - - - █████╗  ███████╗ ███████╗ ███████╗ ███╗   ███╗ ██████╗  ██╗      ██╗   ██╗ -██╔══██╗ ██╔════╝ ██╔════╝ ██╔════╝ ████╗ ████║ ██╔══██╗ ██║      ╚██╗ ██╔╝ -███████║ ███████╗ ███████╗ █████╗   ██╔████╔██║ ██████╔╝ ██║       ╚████╔╝  -██╔══██║ ╚════██║ ╚════██║ ██╔══╝   ██║╚██╔╝██║ ██╔══██╗ ██║        ╚██╔╝   -██║  ██║ ███████║ ███████║ ███████╗ ██║ ╚═╝ ██║ ██████╔╝ ███████╗    ██║    -╚═╝  ╚═╝ ╚══════╝ ╚══════╝ ╚══════╝ ╚═╝     ╚═╝ ╚═════╝  ╚══════╝    ╚═╝    -v9.9.9 - -Thread: default - -Ready to code! What would you like to build? -Tip: approve tools as they run, or pass --auto to skip the prompts. - -» add a /health endpoint -Adding a health check:                                                                           - - 1 New route                                                                                     - 2 A test                                                                                        -→ write_file(app.py) -  write_file: wrote 8 lines to app.py - - - - - -╭────────────────────────────────────────────────────────────────────────────────────────────────╮ ->Ask the agent to build something… -╰────────────────────────────────────────────────────────────────────────────────────────────────╯ - manual ~/demo↗ main + + + + + █████╗  ███████╗ ███████╗ ███████╗ ███╗   ███╗ ██████╗  ██╗      ██╗   ██╗ +██╔══██╗ ██╔════╝ ██╔════╝ ██╔════╝ ████╗ ████║ ██╔══██╗ ██║      ╚██╗ ██╔╝ +███████║ ███████╗ ███████╗ █████╗   ██╔████╔██║ ██████╔╝ ██║       ╚████╔╝  +██╔══██║ ╚════██║ ╚════██║ ██╔══╝   ██║╚██╔╝██║ ██╔══██╗ ██║        ╚██╔╝   +██║  ██║ ███████║ ███████║ ███████╗ ██║ ╚═╝ ██║ ██████╔╝ ███████╗    ██║    +╚═╝  ╚═╝ ╚══════╝ ╚══════╝ ╚══════╝ ╚═╝     ╚═╝ ╚═════╝  ╚══════╝    ╚═╝    +v9.9.9 + +Thread: default + +Ready to code! What would you like to build? +Tip: approve tools as they run, or pass --auto to skip the prompts. + +» add a /health endpoint +Adding a health check:                                                                           + + 1 New route                                                                                     + 2 A test                                                                                        +→ write_file(app.py) +  write_file: wrote 8 lines to app.py + + + + + +╭────────────────────────────────────────────────────────────────────────────────────────────────╮ +>Ask the agent to build something… + manual ~/demo↗ main +^Y copy · ^O expand · esc interrupt · ^C quit diff --git a/tests/__snapshots__/test_tui_snapshots/test_code_voice_listening.raw b/tests/__snapshots__/test_tui_snapshots/test_code_voice_listening.raw index 310de20..7b0288b 100644 --- a/tests/__snapshots__/test_tui_snapshots/test_code_voice_listening.raw +++ b/tests/__snapshots__/test_tui_snapshots/test_code_voice_listening.raw @@ -19,161 +19,162 @@ font-weight: 700; } - .terminal-1669332747-matrix { + .terminal-3917210796-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-1669332747-title { + .terminal-3917210796-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-1669332747-r1 { fill: #c5c8c6 } -.terminal-1669332747-r2 { fill: #614fd2;font-weight: bold } -.terminal-1669332747-r3 { fill: #939393 } -.terminal-1669332747-r4 { fill: #e0e0e0 } -.terminal-1669332747-r5 { fill: #614fd2 } -.terminal-1669332747-r6 { fill: #000000 } -.terminal-1669332747-r7 { fill: #22c55e } + .terminal-3917210796-r1 { fill: #c5c8c6 } +.terminal-3917210796-r2 { fill: #614fd2;font-weight: bold } +.terminal-3917210796-r3 { fill: #939393 } +.terminal-3917210796-r4 { fill: #e0e0e0 } +.terminal-3917210796-r5 { fill: #614fd2 } +.terminal-3917210796-r6 { fill: #000000 } +.terminal-3917210796-r7 { fill: #22c55e } +.terminal-3917210796-r8 { fill: #939393;font-weight: bold } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - AssemblyAI Code + AssemblyAI Code - - - - - █████╗  ███████╗ ███████╗ ███████╗ ███╗   ███╗ ██████╗  ██╗      ██╗   ██╗ -██╔══██╗ ██╔════╝ ██╔════╝ ██╔════╝ ████╗ ████║ ██╔══██╗ ██║      ╚██╗ ██╔╝ -███████║ ███████╗ ███████╗ █████╗   ██╔████╔██║ ██████╔╝ ██║       ╚████╔╝  -██╔══██║ ╚════██║ ╚════██║ ██╔══╝   ██║╚██╔╝██║ ██╔══██╗ ██║        ╚██╔╝   -██║  ██║ ███████║ ███████║ ███████╗ ██║ ╚═╝ ██║ ██████╔╝ ███████╗    ██║    -╚═╝  ╚═╝ ╚══════╝ ╚══════╝ ╚══════╝ ╚═╝     ╚═╝ ╚═════╝  ╚══════╝    ╚═╝    -v9.9.9 - -Thread: default - -Ready to code! What would you like to build? -Tip: approve tools as they run, or pass --auto to skip the prompts. - - - - - - - - - - - - - -╭────────────────────────────────────────────────────────────────────────────────────────────────╮ -▁▃▅ Listening — speak your request   (Ctrl-V to type) -╰────────────────────────────────────────────────────────────────────────────────────────────────╯ - manual ~/demo↗ main● voice on + + + + + █████╗  ███████╗ ███████╗ ███████╗ ███╗   ███╗ ██████╗  ██╗      ██╗   ██╗ +██╔══██╗ ██╔════╝ ██╔════╝ ██╔════╝ ████╗ ████║ ██╔══██╗ ██║      ╚██╗ ██╔╝ +███████║ ███████╗ ███████╗ █████╗   ██╔████╔██║ ██████╔╝ ██║       ╚████╔╝  +██╔══██║ ╚════██║ ╚════██║ ██╔══╝   ██║╚██╔╝██║ ██╔══██╗ ██║        ╚██╔╝   +██║  ██║ ███████║ ███████║ ███████╗ ██║ ╚═╝ ██║ ██████╔╝ ███████╗    ██║    +╚═╝  ╚═╝ ╚══════╝ ╚══════╝ ╚══════╝ ╚═╝     ╚═╝ ╚═════╝  ╚══════╝    ╚═╝    +v9.9.9 + +Thread: default + +Ready to code! What would you like to build? +Tip: approve tools as they run, or pass --auto to skip the prompts. + + + + + + + + + + + + + +╭────────────────────────────────────────────────────────────────────────────────────────────────╮ +▁▃▅ Listening — speak your request   (Ctrl-V to type) + manual ~/demo↗ main● voice on +^Y copy · ^V voice · ^O expand · esc interrupt · ^C quit diff --git a/tests/__snapshots__/test_tui_snapshots/test_code_working_spinner.raw b/tests/__snapshots__/test_tui_snapshots/test_code_working_spinner.raw index d48171b..6bcc995 100644 --- a/tests/__snapshots__/test_tui_snapshots/test_code_working_spinner.raw +++ b/tests/__snapshots__/test_tui_snapshots/test_code_working_spinner.raw @@ -19,164 +19,165 @@ font-weight: 700; } - .terminal-3063843344-matrix { + .terminal-3227114883-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-3063843344-title { + .terminal-3227114883-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-3063843344-r1 { fill: #c5c8c6 } -.terminal-3063843344-r2 { fill: #614fd2;font-weight: bold } -.terminal-3063843344-r3 { fill: #939393 } -.terminal-3063843344-r4 { fill: #e0e0e0 } -.terminal-3063843344-r5 { fill: #614fd2 } -.terminal-3063843344-r6 { fill: #38bdf8;font-weight: bold } -.terminal-3063843344-r7 { fill: #3a3f55 } -.terminal-3063843344-r8 { fill: #121212 } -.terminal-3063843344-r9 { fill: #676767 } -.terminal-3063843344-r10 { fill: #000000 } + .terminal-3227114883-r1 { fill: #c5c8c6 } +.terminal-3227114883-r2 { fill: #614fd2;font-weight: bold } +.terminal-3227114883-r3 { fill: #939393 } +.terminal-3227114883-r4 { fill: #e0e0e0 } +.terminal-3227114883-r5 { fill: #614fd2 } +.terminal-3227114883-r6 { fill: #38bdf8;font-weight: bold } +.terminal-3227114883-r7 { fill: #3a3f55 } +.terminal-3227114883-r8 { fill: #121212 } +.terminal-3227114883-r9 { fill: #676767 } +.terminal-3227114883-r10 { fill: #000000 } +.terminal-3227114883-r11 { fill: #939393;font-weight: bold } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - AssemblyAI Code + AssemblyAI Code - - - - - █████╗  ███████╗ ███████╗ ███████╗ ███╗   ███╗ ██████╗  ██╗      ██╗   ██╗ -██╔══██╗ ██╔════╝ ██╔════╝ ██╔════╝ ████╗ ████║ ██╔══██╗ ██║      ╚██╗ ██╔╝ -███████║ ███████╗ ███████╗ █████╗   ██╔████╔██║ ██████╔╝ ██║       ╚████╔╝  -██╔══██║ ╚════██║ ╚════██║ ██╔══╝   ██║╚██╔╝██║ ██╔══██╗ ██║        ╚██╔╝   -██║  ██║ ███████║ ███████║ ███████╗ ██║ ╚═╝ ██║ ██████╔╝ ███████╗    ██║    -╚═╝  ╚═╝ ╚══════╝ ╚══════╝ ╚══════╝ ╚═╝     ╚═╝ ╚═════╝  ╚══════╝    ╚═╝    -v9.9.9 - -Thread: default - -Ready to code! What would you like to build? -Tip: approve tools as they run, or pass --auto to skip the prompts. - -» build a web scraper - - - - - - - - - -✶ Working… (7s) - -╭────────────────────────────────────────────────────────────────────────────────────────────────╮ ->Ask the agent to build something… -╰────────────────────────────────────────────────────────────────────────────────────────────────╯ - manual ~/demo↗ main + + + + + █████╗  ███████╗ ███████╗ ███████╗ ███╗   ███╗ ██████╗  ██╗      ██╗   ██╗ +██╔══██╗ ██╔════╝ ██╔════╝ ██╔════╝ ████╗ ████║ ██╔══██╗ ██║      ╚██╗ ██╔╝ +███████║ ███████╗ ███████╗ █████╗   ██╔████╔██║ ██████╔╝ ██║       ╚████╔╝  +██╔══██║ ╚════██║ ╚════██║ ██╔══╝   ██║╚██╔╝██║ ██╔══██╗ ██║        ╚██╔╝   +██║  ██║ ███████║ ███████║ ███████╗ ██║ ╚═╝ ██║ ██████╔╝ ███████╗    ██║    +╚═╝  ╚═╝ ╚══════╝ ╚══════╝ ╚══════╝ ╚═╝     ╚═╝ ╚═════╝  ╚══════╝    ╚═╝    +v9.9.9 + +Thread: default + +Ready to code! What would you like to build? +Tip: approve tools as they run, or pass --auto to skip the prompts. + +» build a web scraper + + + + + + + + + +✶ Working… (7s) + +╭────────────────────────────────────────────────────────────────────────────────────────────────╮ +>Ask the agent to build something… + manual ~/demo↗ main +^Y copy · ^O expand · esc interrupt · ^C quit diff --git a/tests/test_code_tui_status.py b/tests/test_code_tui_status.py index fc53dbc..9d6de03 100644 --- a/tests/test_code_tui_status.py +++ b/tests/test_code_tui_status.py @@ -8,6 +8,8 @@ from pathlib import Path +import pyperclip + from aai_cli.code_agent import tui_status from aai_cli.ui import theme @@ -51,6 +53,56 @@ def test_voicebar_markup_per_phase_carries_label_meter_accent_and_hint() -> None assert "Speaking" in speaking and "#22c55e" in speaking # green +def test_copy_note_copies_and_confirms() -> None: + # The happy path: the reply is handed to the copier and a confirmation note returned. + copied: list[str] = [] + note = tui_status.copy_note("a reply", copied.append) + assert copied == ["a reply"] + assert "copied" in note + + +def test_copy_note_when_nothing_to_copy() -> None: + # No reply yet: don't touch the clipboard, and tell the user there's nothing to copy. + copied: list[str] = [] + note = tui_status.copy_note("", copied.append) + assert copied == [] # copier never called + assert "nothing to copy" in note + + +def test_copy_note_degrades_when_no_clipboard() -> None: + # A headless/clipboard-less box: pyperclip raises; copy_note must absorb it and return a + # note rather than letting the raise propagate (which would tear down the TUI). + def _boom(_text: str) -> None: + raise pyperclip.PyperclipException("no copy/paste mechanism") + + note = tui_status.copy_note("a reply", _boom) + assert "no clipboard available" in note + + +def test_keyhints_lists_shortcuts_and_gates_voice_on_availability() -> None: + # The legend always lists copy/expand/interrupt/quit; the Ctrl-V voice toggle appears + # only when a voice front-end exists, and the whole line is dim. + with_voice = tui_status.keyhints_text(voice=True) + assert "copy" in with_voice and "expand" in with_voice and "quit" in with_voice + assert "voice" in with_voice # the Ctrl-V hint is listed when voice is available + assert with_voice.startswith("[dim]") # rendered as a dim legend + without_voice = tui_status.keyhints_text(voice=False) + assert "voice" not in without_voice # no Ctrl-V hint without a voice front-end + assert "copy" in without_voice and "quit" in without_voice + + +def test_status_text_appends_the_key_legend(tmp_path: Path) -> None: + # The footer is two rows: the status info, then the dim key legend beneath it. + footer = tui_status._status_text(tmp_path, auto_approve=False) + info, _, hints = footer.partition("\n") + assert "manual" in info # row one is the status info + assert "quit" in hints and "copy" in hints # row two is the key legend + assert "voice" not in hints # no voice front-end -> the legend omits the Ctrl-V hint + # With a voice front-end the legend's second row gains the Ctrl-V hint. + voiced = tui_status._status_text(tmp_path, auto_approve=False, voice_state="on") + assert "voice" in voiced.partition("\n")[2] + + def test_status_text_renders_voice_badge(tmp_path: Path) -> None: # No voice front-end -> no voice badge (the dot glyphs are absent); on/off render the # state so the Ctrl-V toggle shows. (Asserts on the dots, not the word — the tmp_path name diff --git a/tests/test_code_tui_voice_switch.py b/tests/test_code_tui_voice_switch.py new file mode 100644 index 0000000..9687b79 --- /dev/null +++ b/tests/test_code_tui_voice_switch.py @@ -0,0 +1,62 @@ +"""Tests for switching between voice and text mode in the `assembly code` TUI. + +Switching input mode (Ctrl-V) and interrupting (Escape / Ctrl-C) both have to stop an +in-flight microphone capture so it neither keeps the mic open behind the text prompt nor +submits a turn the user no longer wants. These cancel-safety cases are split out of +test_code_tui_voice.py to keep each file under the 500-line gate, reusing that module's +app/voice doubles. +""" + +from __future__ import annotations + +import threading + +import pytest + +from aai_cli.code_agent.tui import CodeAgentApp +from tests.test_code_tui_voice import FakeAgent, FakeVoice, _run, _wait_until + + +def test_toggle_voice_off_cancels_in_flight_capture() -> None: + # Switching to text (Ctrl-V) must release the mic now — cancel the blocking listen() + # rather than leaving a capture running unseen behind the text prompt. + async def go() -> None: + voice = FakeVoice() + app = CodeAgentApp(agent=FakeAgent([]), voice=voice) + app._voice_paused = True # start paused so on_mount doesn't race a capture thread + async with app.run_test(size=(100, 30)) as pilot: + await pilot.pause() + app.action_toggle_voice() # voice on + assert voice.cancels == 0 # turning on never cancels + app.action_toggle_voice() # voice off -> must cancel the in-flight capture + assert voice.cancels == 1 + + _run(go()) + + +def test_capture_after_switching_to_text_is_not_submitted(monkeypatch: pytest.MonkeyPatch) -> None: + # A turn that finalizes in the window between the user pressing Ctrl-V and the capture + # unwinding must NOT be submitted — otherwise a spoken phrase lands as a turn after the + # user already switched to typing. + async def go() -> None: + voice = FakeVoice() + app = CodeAgentApp(agent=FakeAgent([]), voice=voice) + app._voice_paused = True # block the on_mount auto-listen + async with app.run_test(size=(100, 30)) as pilot: + await pilot.pause() + submitted: list[str] = [] + monkeypatch.setattr(app, "_submit", submitted.append) # spy: _enter_and_submit calls it + + def listen() -> str: + voice.listens += 1 + app._voice_paused = True # user switched to text DURING the capture + return "late turn" + + monkeypatch.setattr(voice, "listen", listen) + app._voice_paused = False # active when the capture starts + thread = threading.Thread(target=app._capture_voice_turn) + thread.start() + assert await _wait_until(pilot, lambda: not thread.is_alive()) + assert submitted == [] # the late turn was dropped, not submitted + + _run(go())