-
Notifications
You must be signed in to change notification settings - Fork 3.6k
tui review #5188
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
olafura
wants to merge
181
commits into
pingdotgg:main
Choose a base branch
from
olafura:olafura/tui-review
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+25,445
−396
Open
tui review #5188
Changes from all commits
Commits
Show all changes
181 commits
Select commit
Hold shift + click to select a range
d6776e7
feat(client-runtime): export pure shell and thread reducers
olafura 67a28d3
feat(server): add `t3 tui` — terminal UI for monitoring threads
olafura 88a456a
chore(tui): add dev scripts and document `t3 tui`
olafura 651d50a
feat(tui): add theme module — status pills + relative time
olafura 904084e
feat(tui): web-parity thread-list design
olafura 1618a38
feat(tui): add @t3tools/tui package with JSX terminal UI
olafura 4c1105c
refactor(server): move TUI out of server into @t3tools/tui
olafura d406787
refactor(tui): expose a declared type boundary, drop server jsx flag
olafura 5355030
feat(tui): migrate the terminal UI to OpenTUI on Bun
olafura 13e21e1
docs(tui): document the Bun requirement; build the package before launch
olafura b4015fc
fix(tui): render with the terminal's own palette
olafura 86306e8
fix(tui): exit cleanly on a single Ctrl+C
olafura 571df61
fix(tui): send prompt input by using onInput, not onChange
olafura 5188b47
refactor(tui): split the monolith into components mirroring the web
olafura 049c6ff
perf(tui): cache thread state with the web's warm-subscription engine
olafura 191409d
fix(tui): theme the embedded terminal with the user's ANSI palette
olafura e24ee27
feat(tui): use the terminal and prompt together, with focus toggle + …
olafura e1f61d4
fix(tui): harden the thread cache (NUL key, deleted-thread retry loop)
olafura 225150e
fix(tui): harden the TUI process lifecycle (IPC, auth, terminal restore)
olafura 5b7b679
fix(tui): code-review UI fixes (new-thread, project list, render timer)
olafura c5e6963
feat(tui): add thread-action client ops to TuiClient
olafura 0b6346c
feat(tui): plan/build toggle, thread-actions menu, and search filter
olafura 2814259
test(tui): add bun:test harness and BDD specs
olafura 13a9f2f
feat(tui): multiline reply editor with paste, no length cap
olafura 62adab0
feat(tui): show tool calls, changed files, and a working indicator
olafura 2ece1f9
feat(tui): show the proposed-plan card
olafura f3b1932
feat(tui): implement a proposed plan with ^Y
olafura 3bff8a2
feat(tui): context-window usage meter in the header
olafura 0190816
feat(tui): cycle through all pending approvals
olafura 31490c4
feat(tui): checkpoint revert picker
olafura 5efa3b1
feat(tui): show plan/build mode on the composer prompt
olafura a8697d2
feat(tui): answer pending user-input requests inline
olafura bbd6eb9
feat(tui): runtime-mode and plan/build options in the new-thread dialog
olafura c6226af
feat(tui): turn diff viewer
olafura ff61a49
feat(tui): model/provider picker
olafura fb1f59a
feat(tui): branch and worktree fields in the new-thread dialog
olafura d781034
feat(tui): typed status line with tone glyph + colour
olafura 05f5e0d
feat(tui): animate the working indicator with a braille spinner
olafura 7e606ca
feat(tui): turn separators in the conversation
olafura b22cfe7
feat(tui): collapsible work log for long tool runs
olafura 1b9c4ff
fix(tui): stop global Ctrl-shortcuts shredding the reply draft
olafura 382f711
feat(tui): resizable, scrollable prompt + edit in $EDITOR (^G)
olafura 9e0be9b
feat(tui): copy and paste in the embedded terminal
olafura a57483d
feat(tui): web-style composer controls row + contextual footer
olafura 50081a4
feat(tui): native <select> pickers for model, access and reasoning
olafura 41e63aa
feat(tui): make the composer controls and pickers mouse-clickable
olafura 771c19e
fix(tui): picker opens into the space above; robust clickable control…
olafura f925cec
fix(tui): apply the terminal's detected palette to the theme
olafura 28f1346
fix(tui): strip NUL bytes from ChatView source
olafura 56f4a36
fix(tui): leave plan mode when implementing a plan
olafura e86de90
feat(tui): red stop button to interrupt a running agent
olafura 660d704
feat(tui): copy-on-select from the conversation timeline
olafura b20e3f3
revert(tui): drop custom copy-on-select from the timeline
olafura 891217e
fix(tui): restore timeline copy-on-select; gate feedback on real OSC5…
olafura 1bdfa4c
fix(tui): let the terminal own text selection/copy (disable mouse mot…
olafura 2123673
feat(tui): show the "T3 Code" wordmark above Projects in the sidebar
olafura d76a41f
fix(tui): theme the embedded terminal with the detected palette again
olafura 802993b
feat(tui): sidebar search box between the wordmark and Projects
olafura 1cbdb2b
fix(tui): order sidebar projects by latest activity like the web
olafura 77d8a90
feat(tui): per-file diff rendering with language highlighting + split…
olafura fb44265
feat(tui): full-thread "all changes" diff + clickable changed-files
olafura 8dc80e0
feat(tui): chat-bubble message layout (user right, assistant left)
olafura 70bcec9
fix(tui): render the user message bubble with markdown + a definite w…
olafura b7e5e77
fix(tui): right-align the user bubble via alignSelf (was collapsing o…
olafura 15c2224
fix(tui): make the user bubble actually render (definite-width right-…
olafura 95090f5
feat(tui): more breathing room around chat messages
olafura 2f18e20
Mirror web work-log collapsing in the TUI timeline
olafura 08dda19
Fold settled turns behind a "Worked for" row in the TUI
olafura e7e6fba
Center icon registry + changed-files directory tree with collapse-all
olafura c3275b4
Move composer controls into the box (model-first) + Shift+Tab plan/build
olafura 4f37156
Add pure git quick-action + menu logic for the TUI
olafura aa46f6f
Wire git VCS status + stacked actions into the TUI client
olafura 118f23b
Add the right-side source-control panel (^L)
olafura 9bfc499
Add web-parity BDD batch (keyboard table + backlog specs)
olafura 1f38a5f
Add commit-message dialog for right-panel git actions
olafura 17cac97
Add thread next/prev (Alt+↑/↓) + jump (Alt+1…9)
olafura bfe36d6
Per-file "View diff" + file-type colored icons in changed files
olafura 7b1d1ad
Add a command palette (^K), replacing the mnemonic actions menu
olafura 44ef583
Trim the dead actions-menu branch (ThreadActionsMenu → ThreadOverlays)
olafura ddf9783
Wire the right-panel Pull action (and hint for publish)
olafura 35fdb35
Support multiple terminals per thread (terminal groups as tabs)
olafura 3d3b344
Keep terminal tabs alive so switching is instant and lossless
olafura 7eb71b9
Show image attachments as a link until OpenTUI renders images inline
olafura 4bd213b
Hardening pass: fix terminal/palette/git/attachment edge cases
olafura 1a0cfcb
Add a workspace file browser (Files surface)
olafura 0fc9ec1
Keep the composer persistent; match the web ChatComposer naming
olafura 85432ca
Let the composer type a custom answer to a pending question
olafura 09439c2
Add a Settings / reference overlay (palette → Settings)
olafura 7109c1e
Float pickers/palette/confirm above the persistent composer
olafura 91cf85d
Reconcile branch with main after rebase
olafura b1f0559
fix(tui): keep pending requests open on transient failures
olafura fb6c654
chore: reconcile branch with main after rebase (pnpm 11 + effect diag…
olafura 6554703
fix(tui): terminal scrollback scrolling + discover server-side termin…
olafura b66f5f9
fix(tui): prevent bracketed-paste injection in the terminal drawer
olafura 023455e
chore(tui): reconcile with upstream/main after rebase
olafura aff2d53
feat(opentui-image): add kitty image extension
olafura 5a2c52e
feat(tui): render image attachments inline
olafura 44306fa
feat(server): support bounded base64 workspace reads
olafura 97cc55e
feat(tui): stage and send workspace images
olafura 870bf9c
test(tui): track remaining web parity gaps
olafura 54aa10d
feat(tui): expand inline images on click
olafura c99dd40
fix(tui): stabilize image preview transitions
olafura bdecb90
fix(tui): wait for composer acknowledgements
olafura 1a29096
feat(tui): pass kitty images through tmux
olafura 93b3bdd
fix(tui): keep kitty images within the viewport
olafura 11b4cd9
fix(tui): restore cursor after kitty placement
olafura 79e657b
fix(tui): stabilize tmux startup and scrolling
olafura 5cfe9ed
test(tui): model new-thread web parity
olafura 5de0404
fix(tui): make new-thread creation atomic
olafura 132aeb6
feat(tui): resolve model option defaults
olafura 7a248b2
fix(tui): apply model and effort on turns
olafura eedd91b
fix(tui): remove unsafe palette probe
olafura 04e2448
test(tui): audit missing server-backed client features
olafura c9bd09a
feat(tui): add terminal clear and restart actions
olafura 7489e61
refactor(shared): share terminal link parsing
olafura cf242ac
feat(tui): link terminal URLs
olafura 424300f
feat(tui): make source control panel usable
olafura 2d7f299
feat(tui): align composer and terminal with web layout
olafura 7ec1fa6
fix(tui): make plan mode selection responsive
olafura ca64c81
feat(opentui-image): add rich clipboard paste protocol
olafura 7fcd839
feat(tui): paste clipboard images into prompts
olafura eb9cdaa
fix(tui): stabilize images while scrolling
olafura b21c5f0
fix(opentui-image): position tmux images with placeholders
olafura 5b9c696
fix(tui): preserve scroll after image preview
olafura eccb87c
feat(tui): reuse composer for new threads
olafura 7d6bfbc
feat(tui): link timeline URLs
olafura 1460896
fix(tui): render visible terminal cursor
olafura bdefda3
fix(tui): keep moved terminal cursor visible
olafura eeb31cb
feat(tui): select workspace and branch for new threads
olafura d9a1d4e
fix(tui): align responsive chat layout with web
olafura 361cfee
fix(tui): keep timeline content in viewport
olafura 113f744
fix(tui): align timeline with composer column
olafura 19cdbc8
feat(tui): support auto runtime mode
olafura c7f2678
feat(tui): personalize new-thread prompt
olafura fb69da4
feat(tui): make new-thread project selectable
olafura 5e24295
fix(tui): use selected project for new threads
olafura 4b7470e
fix(tui): compose immediately for selected projects
olafura ca55cae
fix(tui): fill terminal layout after focus switch
olafura b109109
fix(terminal): sync persisted instances across clients
olafura 8778db1
feat(tui): adopt flat lifecycle sidebar
olafura 2db67b8
fix(tui): restore Markdown visual hierarchy
olafura 62e88df
fix(tui): restore collapsed message expansion
olafura 1cbb91a
fix(tui): sync terminal closures across clients
olafura af27e94
fix(server): broadcast persisted terminal closures
olafura e3210ee
fix(tui): close the final terminal reliably
olafura 7bf2b82
fix(web): sync externally closed terminals
olafura 631d75f
fix(tui): implement VCS ref cache invalidation
olafura c62606f
docs(opentui-image): preserve upstream attribution
olafura 5278975
fix(tui): restore prompt focus and toggle active pickers
olafura 38a3d85
fix(tui): restore project onboarding from flat sidebar
olafura e66ab99
fix(tui): match web project onboarding flow
olafura 2a1ad1a
feat(tui): attach pasted prompt image paths
olafura c124308
fix(tui): expand prompt image paths
olafura 86e34ad
fix(tui): attach image paths embedded in prompts
olafura 3146e57
fix(tui): split muted palette into readable dim and decorative faint
olafura 1fa87a6
fix(tui): drop grey selection backgrounds and adopt faint decoration
olafura adb3299
fix(server): pin TERM/COLORTERM for embedded terminal sessions
olafura 22e4554
fix(tui): advertise truecolor for terminals that drop COLORTERM
olafura 561289d
refactor(tui): route status colours through semantic palette roles
olafura 0266967
chore(tui): log detected colour capabilities at startup
olafura 6464867
fix(tui): forward colour env to the renderer in SSH sessions
olafura 73444c4
feat(tui): settle and un-settle threads from the command palette
olafura 3bac51a
fix(tui): scroll the sidebar like a normal list
olafura 438d3df
refactor(tui): give the sidebar a real scrollbox
olafura 5c2693d
fix(tui): render user image attachments inside the message bubble at …
olafura 138f31b
refactor(opentui-image): drop the scroll-pause caption
olafura 80084e8
fix(tui): double the inline image preview budget
olafura 6eba895
fix(server): gate base64 workspace reads to image extensions
olafura 744053f
fix(tui): stop prose pastes from being read as image paths
olafura 3677a5e
fix(tui): keep diff content lines from clobbering the file path
olafura 2b13371
fix(tui): clip labels by display width, not code units
olafura 4f30e9f
fix(web): deliver every terminal closed event
olafura ce7426f
fix(server): publish closed events for persisted-only terminals
olafura 8ba8b45
fix(opentui-image): report clipboard read failures once
olafura af9f325
perf(tui): skip redundant timeline work per stream delta
olafura eb019cc
fix(server): bundle the TUI in release artifacts
olafura 3211709
fix(server): validate runtime state before TUI launch
olafura e5d091b
perf(web): avoid streaming terminal output for close sync
olafura a445500
perf(tui): bound mounted conversation history
olafura f3298c1
fix(tui): refresh sidebar at time boundaries
olafura 748d9c9
perf(tui): remove the repainting working spinner
olafura File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
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
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
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| import { describe, expect, it } from "vitest"; | ||
|
|
||
| import { findUnresolvedTuiBundleImport } from "./tuiBundle.ts"; | ||
|
|
||
| describe("findUnresolvedTuiBundleImport", () => { | ||
| it("rejects private workspace imports left in the release bundle", () => { | ||
| expect(findUnresolvedTuiBundleImport('import { x } from "@t3tools/contracts";')).toBe( | ||
| "@t3tools/contracts", | ||
| ); | ||
| }); | ||
|
|
||
| it("rejects package lookups hidden behind createRequire", () => { | ||
| expect( | ||
| findUnresolvedTuiBundleImport( | ||
| 'NodeModule.createRequire(import.meta.url)("@xterm/headless");', | ||
| ), | ||
| ).toBe("@xterm/headless"); | ||
| }); | ||
|
|
||
| it("allows explicit public and native runtime imports", () => { | ||
| expect( | ||
| findUnresolvedTuiBundleImport( | ||
| 'import { createCliRenderer } from "@opentui/core";\nimport sharp from "sharp";', | ||
| ), | ||
| ).toBeNull(); | ||
| }); | ||
| }); |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| const PRIVATE_WORKSPACE_IMPORT = /(?:from\s+|import\(|require\()\s*["'](@t3tools\/[^"']+)["']/u; | ||
| const OPAQUE_PACKAGE_REQUIRE = /createRequire\([^)]*\)\(\s*["']((?:@[^/"']+\/)?[^/"']+)["']\s*\)/u; | ||
|
|
||
| /** Find a package lookup that Bun left unresolved in the staged TUI bundle. */ | ||
| export function findUnresolvedTuiBundleImport(source: string): string | null { | ||
| return ( | ||
| source.match(PRIVATE_WORKSPACE_IMPORT)?.[1] ?? source.match(OPAQUE_PACKAGE_REQUIRE)?.[1] ?? null | ||
| ); | ||
| } | ||
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
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
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
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| // @effect-diagnostics nodeBuiltinImport:off - integration test owns a loopback HTTP server. | ||
| import * as NodeHttp from "node:http"; | ||
|
|
||
| import { assert, describe, it } from "@effect/vitest"; | ||
| import * as Effect from "effect/Effect"; | ||
| import { FetchHttpClient } from "effect/unstable/http"; | ||
|
|
||
| import type { PersistedServerRuntimeState } from "../serverRuntimeState.ts"; | ||
| import { isLivePersistedServerRuntimeState } from "./runningServer.ts"; | ||
|
|
||
| const descriptor = { | ||
| environmentId: "running-server-test", | ||
| label: "running-server-test", | ||
| platform: { os: "linux", arch: "x64" }, | ||
| serverVersion: "0.0.1", | ||
| capabilities: { repositoryIdentity: true }, | ||
| }; | ||
|
|
||
| const state = (origin: string, pid = process.pid): PersistedServerRuntimeState => ({ | ||
| version: 1, | ||
| pid, | ||
| port: Number(new URL(origin).port), | ||
| origin, | ||
| startedAt: "2026-08-01T00:00:00.000Z", | ||
| }); | ||
|
|
||
| const withServer = <A, E, R>(run: (origin: string) => Effect.Effect<A, E, R>) => | ||
| Effect.acquireUseRelease( | ||
| Effect.callback<NodeHttp.Server>((resume) => { | ||
| const server = NodeHttp.createServer((request, response) => { | ||
| if (request.url === "/.well-known/t3/environment") { | ||
| response.writeHead(200, { "content-type": "application/json" }); | ||
| response.end(JSON.stringify(descriptor)); | ||
| return; | ||
| } | ||
| response.writeHead(404); | ||
| response.end(); | ||
| }); | ||
| server.listen(0, "127.0.0.1", () => resume(Effect.succeed(server))); | ||
| }), | ||
| (server) => { | ||
| const address = server.address(); | ||
| if (address === null || typeof address === "string") { | ||
| return Effect.die(new Error("Expected a TCP address")); | ||
| } | ||
| return run(`http://127.0.0.1:${String(address.port)}`); | ||
| }, | ||
| (server) => Effect.sync(() => server.close()), | ||
| ); | ||
|
|
||
| describe("live persisted server validation", () => { | ||
| it.effect("accepts a live pid whose origin serves a T3 descriptor", () => | ||
| withServer((origin) => | ||
| Effect.gen(function* () { | ||
| assert.isTrue(yield* isLivePersistedServerRuntimeState(state(origin))); | ||
| }), | ||
| ).pipe(Effect.provide(FetchHttpClient.layer)), | ||
| ); | ||
|
|
||
| it.effect("rejects a dead pid even when the origin was reused by T3", () => | ||
| withServer((origin) => | ||
| Effect.gen(function* () { | ||
| assert.isFalse(yield* isLivePersistedServerRuntimeState(state(origin, 4_194_305))); | ||
| }), | ||
| ).pipe(Effect.provide(FetchHttpClient.layer)), | ||
| ); | ||
|
|
||
| it.effect("rejects a live pid when the recorded origin is unreachable", () => | ||
| Effect.gen(function* () { | ||
| assert.isFalse(yield* isLivePersistedServerRuntimeState(state("http://127.0.0.1:1"))); | ||
| }).pipe(Effect.provide(FetchHttpClient.layer)), | ||
| ); | ||
| }); |
Oops, something went wrong.
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟠 High
scripts/tuiBundle.ts:1OPAQUE_PACKAGE_REQUIRErequires(immediately after the closing)ofcreateRequire(...), so lookups with whitespace between them (e.g.createRequire(import.meta.url) ("@xterm/headless")) are not detected —findUnresolvedTuiBundleImportreturnsnulland the build passes while shipping a runtime dependency on unavailablenode_modules. Additionally,PRIVATE_WORKSPACE_IMPORTonly matchesfrom,import(, andrequire(forms, so bareimport "@t3tools/foo"andexport { x } from "@t3tools/foo"also returnnull, letting unresolved private workspace packages through validation. Consider allowing optional whitespace/newlines betweencreateRequire(...)and(, and addingimport\s+andexport\s+.*from\s+as recognized import forms.🤖 Copy this AI Prompt to have your agent fix this: