Repository navigation
terminal: run a program in a pane for another plugin (terminal.run) - #18
Merged
Merged
Conversation
Registers the internal command `terminal.run` that fizzyedit/chat#18 defined, so the chat's terminal sign-in (Claude Code's ACP adapter offers only `claude /login`) works. The program runs in a bottom-panel pane of its own with the request's argv, env and cwd; on exit the pane keeps its output with the exit code and a Close button, and the caller's `done` command gets `.{ tag, code }`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Registers the internal command
terminal.runthat fizzyedit/chat#18 defined (chat'ssrc/auth.zig,TerminalRun/Exited), so the chat's terminal sign-in works: Claude Code's ACP adapter offers only a terminal method (claude /login). The plugins meet only at the host's commands; neither imports the other.What it does
terminal.run .{ .title, .argv, .env, .cwd, .done, .tag }opens a bottom-panel pane of its own (ghostty.run.<n>, titledtitle) and reveals it (host.revealSurface). The command fails, so the chat says it could not open a terminal, when the arguments don't parse,argvis empty, or the app has no place to show the pane.PATH(core.shell_env, resolved off the GUI thread: a Dock-started fizzy has only the system's) under the request'senv, incwd(empty: the project folder, else home),TERM=xterm-256color.waitidwithWNOWAIT, then a reap under the lock that guards signalling, so a hangup never reaches a recycled pid), not the terminal closing: a helper it left holding the tty can't hide the exit. It gives the reader up to 250 ms to drain, and the next frame callsdonewith.{ .tag, .code }: 128 + signal when a signal ended it, 127 when it could not start.done129. A plugin unload does the same for every run whose caller is still loaded. The pane stays after the exit until it is closed.Pty.opentakes aCommand(argv + env) or null for the shell. On unix the child's argv, environment and resolved path are all built beforeforkpty, so the child onlychdirs andexecves (the shell had asetenvafter fork before). The shell is now reaped when it exits. On Windows a command's program is found onPATHwithPATHEXT. A batch file (npx.cmd) runs throughcmd.exe /d /c, and an argument cmd would read as syntax (% & | < > ^ ( ) ! ") is refused rather than escaped. The environment block always carriesTERM, and a waiter thread reports the exit, since ConPTY keeps the output pipe open after it. Windows has only been cross-compiled (x86_64 and aarch64).The chat already checks for the command at runtime:
initializesendsauth.terminal: host.hasCommand("terminal.run"), and the sign-in buttons offer a terminal method only while that holds. Nothing has to change in chat.No SDK seam was missing.
registerSurface/revealSurface/unregisterSurfaceat runtime, plus an internalrunWithcommand, cover it.Verified
zig build test(new step, run by CI on each OS): parses the request as the chat writes it and ignores unknown fields; writesExitedback as the chat reads it; puts the login PATH under the request's env. The unix PTY test runsshfromPATHwith an argument, an env var and a cwd and gets them back with exit code 3, and checks that a signal gives 128+15 and a missing program 127. It also checks that an exit is heard while a backgroundedsleepholds the tty, and that closing a program which traps HUP returns.zig buildfor native,x86_64-windows-gnuandx86_64-linux-gnu.--quietfizzy (main + this plugin + chat main) in its own profile and a stand-in ACP agent that is logged out and offers a terminal method (--login,LOGIN_MODE=interactive). The chat gotauth.terminal: true;session/newwas refused, and the sign-in button opened a "Sign in: Log in in a terminal" pane runningagent.py --loginwith the env andTERM. Typingyesinto the pane (a demo tape) made it exit 0. The pane showedexited with code 0, the chat started the agent again,session/newsucceeded, and the chat said "Connected." Close removed the pane. In a second run (after the review fixes), Close on a pane still waiting for input killed the login. The chat said "ended without signing in (exit 129)" and offered the button again, and the next sign-in went through.🤖 Generated with Claude Code