feat: transcription history + output polish - #20
Merged
Conversation
Replace unconditional RichUI with _select_ui helper (PipeUI when not a TTY, QuietUI on --quiet/quiet_mode, RichUI otherwise). Add --no-history flag threaded through to RecordingService.transcribe_and_format.
CLAUDE.md updates: - Tech stack: add prompt_toolkit (transitive via ipython). - Architecture diagram: surface PipeUI and the history picker. - Directory tree: adapters/history/, commands/history.py, the three UI implementations. - Config JSON: add history_enabled, history_retention. - UI Output Layer: document the TTY-aware _select_ui priority. - New section "Transcription History": store, model, persistence policy, --no-history, picker, shh history / shh history clear. - CLI entry point: note Whisper verbose_json detected_lang flow.
The previous _wait_for_enter used sys.stdin.readline in canonical mode, so the terminal echoed a newline the moment the user pressed Enter to stop recording. That newline moved the cursor below rich.live.Live's anchor, breaking transient cleanup — the "Recording …" line stayed on screen and subsequent processing-step spinners rendered on new lines instead of morphing in place. Put stdin in cbreak mode while waiting, read one character at a time, and return on \n or \r. Original terminal settings are restored in finally. Non-TTY stdin (tests, pipes) falls back to readline so existing tests keep passing.
- Track CLAUDE.md (remove from .gitignore) so the doc is shared. - Rewrite CLAUDE.md to match the current code: services layer, Protocol-based UI (RichUI/QuietUI), Textual TUI, --quiet/--verbose, 4o-mini formatter, untracked TUI note. - Declare textual>=7.0 as a [tui] optional extra and pull it into [dev] (uv.lock updated accordingly) so `pip install shh-cli[tui]` resolves.
The Textual TUI was incomplete: `shh tui` was never wired into the Typer app, and the recording screen only animated a fake waveform (no real audio capture or Whisper call - see the TODO at shh/tui/screens/recording.py finish_recording). Remove rather than finish, since the CLI covers the same use cases. - Delete shh/tui/, shh/cli/commands/tui.py, TUI_README.md (all untracked, nothing to revert from git history). - Drop the [tui] optional extra and textual from [dev] in pyproject.toml; re-resolve uv.lock (removes textual + linkify-it-py + mdit-py-plugins + uc-micro-py). - Strip TUI sections from CLAUDE.md. Keep the services layer and UIOutput Protocol docs - both remain valid CLI-only patterns.
Spec covers two coordinated changes: - Output polish: single morphing spinner in RichUI, fix duplicate "Recording" line, drop the result Panel for a text + dim confirmation line, auto-route to a new PipeUI when stdout is not a TTY. - History feature: JSONL store at <config_dir>/history.jsonl with rotation, mandatory HistoryStore in RecordingService, a new `shh history` interactive picker built on prompt_toolkit (already transitive via ipython), `shh history clear`, and a --no-history flag on record. Replay was considered and dropped (lossy chain-of-LLM trade-off was not worth the added storage complexity).
14 bite-sized tasks with TDD steps, exact code, and commit boundaries. Covers settings, models, Whisper verbose_json refactor, HistoryStore, RecordingService refactor (mandatory ui + history_store), PipeUI, RichUI single-Live refactor, prompt_toolkit picker, history command group, TTY-aware UI selection, --no-history flag, config exposure, CLAUDE.md update via revise-claude-md, and final verification.
|
helPRs session created for this PR. Skill: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
shh historyinteractive picker (prompt_toolkit) with substring filter and preview;shh history clearto purge.PipeUIforshh | …and redirects (raw text only, no spinner, no colors); RichUI / QuietUI selection unchanged for TTY.--no-historyflag on the record path to skip persisting a single transcription.What changed
RecordingServicenow takesui+history_storeas mandatory deps, emits processing steps, gates the Formatting step on real LLM work, persists aHistoryEntryon success (logs + continues onOSError).HistoryStore(JSONL, size-bounded rotation, default retention 200). Whisper client switched toverbose_jsonto exposedetected_lang.shh historyTyper subcommand group;_select_uihelper picks Pipe/Quiet/Rich based onsys.stdout.isatty()+ flags + config.history_enabled(bool, default true) andhistory_retention(int, 1–10_000, default 200) exposed throughshh config set/get/show.Live(transient=True)morphs through phases, drops the result Panel; final output is text + dim✓ copied to clipboard.Test plan
uv run poe check— 95 tests pass, mypy strict + ruff cleanshh history,shh history clear) — single morphing spinner, panel removed, clipboard confirmation, picker copies on Entershh | catandshh > out.txt(raw text only) — to verify on a fresh checkout--no-historyskips the entry — to verify on a fresh checkout