Reject unknown terminal modes instead of spawning dead terminals#398
Merged
Conversation
new-tab/split-pane via the MCP (and the REST API generally) accepted any `mode` string and passed it straight to the spawn path. For a mode that is neither the built-in 'shell' nor a registered coding CLI, buildSpawnSpec fell back to exec-ing the mode name itself (`cli?.command || mode`), so e.g. `mode: "terminal"` spawned a process literally named "terminal" that died instantly with "execvp(3) failed: No such file or directory" -- leaving a tab whose terminal was already gone. Validate the mode at the authoritative spawn point: buildSpawnSpec now throws UnknownTerminalModeError for any non-shell mode that isn't a registered coding CLI, listing the valid modes. The REST router maps that error to a 400, so the MCP surfaces a clear message instead of a zombie terminal. This mirrors the validation the WebSocket terminal.create path already performs. Adds getKnownTerminalModes/isKnownTerminalMode helpers and regression tests at both the buildSpawnSpec and REST-route layers. Co-Authored-By: Claude Opus 4.8 (1M context) <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.
Problem
new-tab/split-panevia the MCP (and the REST API generally) accepted anymodestring and passed it straight to the spawn path with no validation. For a mode that is neither the built-in'shell'nor a registered coding CLI (claude/codex/opencode/gemini/kimi),buildSpawnSpecfell back to exec-ing the mode name itself:So e.g.
new-tab({ mode: "terminal" })spawned a process literally namedterminalthat died instantly withexecvp(3) failed: No such file or directory, leaving a tab whose terminal was already gone. The WebSocketterminal.createpath already validates modes; the REST/MCP path did not.Fix
Validate at the authoritative spawn point.
buildSpawnSpecnow throwsUnknownTerminalModeErrorfor any non-shell mode that isn't a registered coding CLI, with a message listing the valid modes. The REST router maps that error to a 400, so the MCP surfaces a clear message instead of a zombie terminal. Because the guard sits inbuildSpawnSpec, it covers every caller (MCP, REST, CLI) on all platforms — including the WSL branch, which previously silently fell back to bash for unknown modes.Adds
getKnownTerminalModes()/isKnownTerminalMode()helpers.Tests
buildSpawnSpecthrowsUnknownTerminalModeErrorfor an unknown mode instead of returning a spec that would exec the mode name.POST /api/tabswith an unknown mode returns 400 and rolls back the half-created tab.357 tests pass across the two affected files; server typecheck is clean.
Note
Source-only fix. The running server (
dist/) needs anpm run build:server+ restart for the live MCP to reject invalid modes.🤖 Generated with Claude Code