feat(web): open a project's terminal from the chat header - #5339
feat(web): open a project's terminal from the chat header#5339Brechard wants to merge 3 commits into
Conversation
Opening a project in an editor is one click, but opening a shell in it means leaving the app and cd-ing by hand. This adds a Terminal control next to Open-in that launches the project directory in an installed terminal. It is a separate control rather than a row in the Open-in picker: a terminal opens a shell in the project rather than a file in an app, and choosing one should not move the editor the Open button uses. The preferred terminal is remembered the same way the preferred editor is, and the chevron menu only appears when more than one is installed. Supported: Terminal, iTerm, Warp and Ghostty on macOS through their app bundles, plus Ghostty, WezTerm, kitty, Alacritty and Windows Terminal through their CLIs. macAppName is set only for bundles that open a folder argument in that directory; the rest would silently start in the user's home, so they appear only when their CLI is on PATH. Server-side, EDITORS gains a "working-directory" launch style whose target is resolved to a directory (a `:line:column` suffix is stripped and a file steps up to its containing folder), and the file-manager special case becomes a `kind` discriminator so terminals reuse the same detection and launch path. Generated with Claude Sonnet 5 in Claude Code.
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
ApprovabilityVerdict: Needs human review This PR adds a new feature: terminal launching from the chat header. It introduces a new UI component, 8 terminal definitions, a new launch style, and cross-cutting server logic — new user-facing capability that warrants human review. You can customize Macroscope's approvability policy. Learn more. |
Addresses two review findings: - The macOS app-bundle fallback in the CLI branch was reachable on Linux and Windows, where `open` does not exist. A stray `/Applications/<name>.app` would turn a clean command-not-found into a failed spawn. Guarded with `platform === "darwin"`, matching the no-CLI branch. - `resolveWorkingDirectory` stripped a `:line:column` suffix before testing the target, so a real POSIX directory named `project:12` resolved to its parent. The target is now tested as-is first. Generated with Claude Sonnet 5 in Claude Code.
|
Thanks — both findings were real, fixed in e44db99.
Added a regression test for each. |
`open` detaches with stdio ignored, so launching a CLI-less editor whose bundle is gone (a stale `apple-terminal` preference, say) reported success while nothing opened. Check the bundle first and fail with ExternalLauncherUnsupportedEditorError instead. The existing app-bundle test forced platform "darwin" against the real filesystem, so gating on availability would have tied it to the host having Terminal.app. It now stages the bundle under a temp HOME. Generated with Claude Sonnet 5 in Claude Code.
|
Good catch, fixed in cf08262. The CLI-less branch now calls Worth noting it also caught a latent test problem: the existing app-bundle test forced I did not add a negative test for the missing-bundle path: |
What Changed
Adds a Terminal control to the chat header, next to Open-in, that launches the project directory in an installed terminal.
t3code:last-terminalin localStorage, mirroringusePreferredEditor). The chevron menu only renders when more than one terminal is installed, so the common case is a single button.EDITORSgains aworking-directorylaunch style. Its target is resolved to a directory first: a:line:columnsuffix is stripped, and a file steps up to its containing folder, so the existing "open this file" call sites work unchanged.commands === nullfile-manager special case becomes akinddiscriminator (file-manager|terminal), so terminals reuse the same detection and launch path instead of adding a parallel one.macAppNameis set only for bundles that actually open a folder argument in that directory. The rest would silently start in the user's home, so they appear only when their CLI is on PATH.Why
Opening a project in an editor is one click, but opening a shell in that same directory means leaving the app and
cd-ing by hand.It is a separate control rather than a row in the Open-in picker because a terminal opens a shell in the project rather than a file in an app, and choosing one should not move the editor the Open button uses.
UI Changes
Before — header with no terminal affordance:
After — Terminal control between Add action and Open:
The screenshots are from a machine with only Terminal.app installed, which is why no chevron is shown; with several terminals installed the control gains a chevron menu listing them.
Verification
vp run --filter @t3tools/contracts --filter t3 --filter @t3tools/web typecheckclean.externalLauncher.test.ts(working-directory launch with:line:columnstripping, and the CLI-less macOS app-bundle path) andpackages/contracts/src/editor.test.ts(terminal classification, launch style, ordering after editors).cwdwas the project directory, confirmed withlsof.Checklist
Generated with Claude Sonnet 5 in Claude Code.
Note
Medium Risk
Touches process spawning and path resolution on the server; mistakes could open the wrong directory or mis-detect macOS apps, but scope is limited to external launch helpers with new tests.
Overview
Adds a Terminal control in the chat header (alongside Open-in) that opens the project directory in an installed terminal, with a separate preferred-terminal preference (
t3code:last-terminal) so it does not change the Open-in editor default.Contracts & launcher:
EDITORSgains terminal entries and aworking-directorylaunch style with optionalcwdArgs/macAppName.ExternalLauncherresolves the cwd from file paths (strip:line:column, use parent dir), detects macOS.appbundles only on darwin, and launches GUI-only terminals viaopen -a. File manager is distinguished withkind: "file-manager"instead ofcommands === nullalone.Web:
OpenTerminalPickerfilters installed terminals fromavailableEditors;usePreferredEditor/resolveAndPersistPreferredEditorskip terminal IDs so Open-in never defaults to a terminal.Reviewed by Cursor Bugbot for commit cf08262. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Add terminal launcher to the chat header for opening a project directory
OpenTerminalPickercomponent toChatHeader.tsxthat lets users open a terminal in the current project's working directory, with preference persistence and multi-terminal selection.editor.tsusing a newworking-directorylaunch style and optionalcwdArgstemplates.externalLauncher.tsto resolve the working directory from a file path (stripping:line:colsuffixes), support GUI-only macOS app bundles viaopen -a, and skip macOS bundle fallback on non-darwin platforms.editorPreferences.tsusing a newusePreferredTerminalhook so terminals are never auto-selected as the default editor.Macroscope summarized cf08262.