Skip to content

fix(terminal): quote the sh -c payload so resume survives spaces in paths#406

Merged
graydawnc merged 1 commit into
mainfrom
fix/terminal-resume-quoting
Jul 7, 2026
Merged

fix(terminal): quote the sh -c payload so resume survives spaces in paths#406
graydawnc merged 1 commit into
mainfrom
fix/terminal-resume-quoting

Conversation

@graydawnc

Copy link
Copy Markdown
Collaborator

What

Fixes shell-quoting in the open --args terminal runners (Ghostty / kitty / Alacritty / WezTerm) so the resume command survives cwds and commands that contain spaces or single quotes.

Depends on #405 (stacked — this branch bases on feat/terminal-ghostty). Merge #405 first.

Why

Each runner wrapped the sh -c payload in raw single quotes:

open -a kitty --args sh -c '<payload>'

But withCwd already single-quotes the cwd (cd '<cwd>' && …) and the resume command single-quotes the session id. The nested single quotes cancel out under the outer shell, so it only works when nothing contains a space. A common macOS project path like /Users/x/My Project tokenizes into:

sh -c argument = "cd /Users/x/My"    (+ stray args "Project", "&&", "claude"…)

so sh -c cd just cd's to $HOME and exits — the resume command is dropped and the window opens in the wrong directory (and never runs exec $SHELL).

How it connects

  • Extracts keepAliveArg(cmd, cwd), which shell-quotes the entire "<cmd>; exec $SHELL" payload as one token, and routes all four open --args runners through it. This also removes the fourth byte-for-byte copy of the runner template.
  • The AppleScript runners (Terminal.app / iTerm2) are untouched — they have a separate quoting model and are out of scope here.

Test plan

  • New regression tests tokenize each emitted command with a real /bin/sh and assert the payload survives as a single argument, for both a spaced cwd (/tmp/My Proj) and an embedded single quote. These fail on the pre-fix runners (the spaced path splits into two argv tokens) and pass after.
  • Existing Ghostty string assertions updated to the correctly-escaped form.
  • Full app vitest suite green (290 tests).

Base automatically changed from feat/terminal-ghostty to main July 7, 2026 08:34
…aths

The `open --args` runners (Ghostty/kitty/Alacritty/WezTerm) wrapped the
`sh -c` payload in raw single quotes, but withCwd already single-quotes the
cwd and the resume command single-quotes the session id. The nested quotes
cancel out under the outer shell, so it works only when nothing contains a
space — a cwd like "/Users/x/My Project" splits into "cd /Users/x/My" plus
stray args, the resume command is dropped, and the window opens in the wrong
directory.

Extract keepAliveArg(), which shell-quotes the whole "<cmd>; exec $SHELL"
payload as one token, and route all four runners through it. Adds regression
tests that tokenize each emitted command with a real /bin/sh and assert the
payload survives as a single argument for spaced paths and embedded quotes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@graydawnc
graydawnc force-pushed the fix/terminal-resume-quoting branch from 039957e to e996fcf Compare July 7, 2026 08:37
@graydawnc
graydawnc added this pull request to the merge queue Jul 7, 2026
Merged via the queue into main with commit 31b9261 Jul 7, 2026
8 of 9 checks passed
@graydawnc
graydawnc deleted the fix/terminal-resume-quoting branch July 7, 2026 08:55
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