Skip to content

feat(tui): print session transcript to scrollback on exit - #134

Merged
quickbeard merged 4 commits into
mainfrom
exit-transcript
Jul 30, 2026
Merged

quickbeard merged 4 commits into
mainfrom
exit-transcript

Conversation

@quickbeard

@quickbeard quickbeard commented Jul 30, 2026 •

Copy link
Copy Markdown
Owner

What

Quitting the TUI restored the alternate screen and threw the conversation away, leaving only the logo + Session/Continue epilogue. Now the exit path prints a compact, Claude Code-style transcript of the session to the normal terminal scrollback first: user prompts prefixed with > , assistant replies as plain text, and tool calls as dim one-line summaries like ⏺ Bash(bun test) (no thinking, no tool output), followed by the usual epilogue. The transcript is painted with the session's active theme colors — text, muted, and error (failed tool calls) — as truecolor ANSI, and assistant replies get a line-based markdown approximation of the session's renderer: headings, bold, italic, inline code, code fences, list bullets, and links styled with the theme's markdown colors. Empty sessions keep the current epilogue-only behavior.

How

  • The epilogue value can now be a lazy thunk (string | (() => string)). The session route sets a thunk that builds transcript + epilogue; app.tsx materializes it in its renderer.once("destroy") listener, which fires before @opentui/solid's dispose listener — so the sync store is still alive, and message updates during the session never rebuild the transcript.
  • New fork-only formatter packages/tui/src/util/exit-transcript.ts maps each tool to its primary argument (bash → command, read/edit/write → relative path via the path formatter, glob/grep → pattern, …) with a first-string-input fallback.

Bug fixes along the way

  • Teardown race: the session route's onCleanup(() => setEpilogue()) ran during Solid dispose and clobbered the epilogue before run() printed it. The provider setter now ignores writes once renderer.isDestroyed.
  • Broken lifecycle test: the epilogue test's session id dummy collides with the fork's pre-navigation placeholder route id, so the Session route never mounted and the test could never pass. Renamed to ses_demo, stubbed the session-scoped endpoints + a paid model (keeps the first-run configure dialog closed), and the test now asserts the transcript end-to-end after a deterministic wait for the session view.

Bookkeeping

  • DIVERGENCES.md: combined row for the four edited upstream files (app.tsx, context/epilogue.tsx, routes/session/index.tsx, test/app-lifecycle.test.tsx); the formatter + its test are fork-only.
  • CHANGELOG.md: Unreleased → TUI entry.

Verification

  • bun typecheck clean (full turbo run via pre-push hook).
  • New unit tests for the formatter; lifecycle test passes 5/5 consecutive runs; full packages/tui suite green (241 pass, 0 fail).
  • Manual tmux run from packages/opencode: a real turn with bash + read tools, then Ctrl+D — scrollback shows the > prompt line, ⏺ Bash(cat README.md), the assistant reply, then the wordmark epilogue; an empty session prints only the epilogue.

🤖 Generated with Claude Code

quickbeard and others added 4 commits July 30, 2026 09:31
Quitting the TUI restored the alternate screen and threw the
conversation away. The exit epilogue can now be a lazy thunk,
materialized in the renderer destroy listener while the reactive tree
is still alive; the session route's thunk prepends a compact
Claude-Code-style transcript (user "> " prompts, assistant text, dim
one-line tool calls) to the logo/session epilogue.

Also fixes a teardown race where the route onCleanup cleared the
epilogue during Solid dispose before it printed, and repairs the
epilogue lifecycle test: its session id "dummy" collided with the
fork's placeholder route id, so the session route never mounted and
the test could never pass.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The exit transcript takes optional theme colors (text, textMuted,
error) and emits truecolor ANSI: user/assistant text in the theme text
color, tool one-liners muted, error-status tools in the error color.
The session route passes the active theme; without colors the
formatter keeps the plain dim fallback.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Assistant text printed at quit was raw markdown in a single color.
Approximate the session's <markdown> renderable line by line using the
theme's markdown* colors: headings bold in markdownHeading, bold/italic
spans in markdownStrong/markdownEmph, inline code and fenced blocks in
markdownCode, list bullets in markdownListItem, blockquotes in
markdownBlockQuote, links underlined in markdownLink with the URL muted.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Drop the codev wordmark banner and the "Session <title>" line from
sessionEpilogue; the exit transcript already shows the conversation, so
only the "Continue codev -s <id>" resume hint remains. Removes the now
unused title input.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@quickbeard
quickbeard merged commit 54c43ff into main Jul 30, 2026
0 of 5 checks passed
@quickbeard
quickbeard deleted the exit-transcript branch July 30, 2026 03:46
quickbeard added a commit that referenced this pull request Aug 2, 2026
The exit-transcript and custom-provider-name entries in 1.18.4-5 shipped
without their PR links; git log -S traces both texts to #134 and #137.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant