-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Closed
Description
Problem
The Chat tab and Shell tab in Claude Code UI operate as completely separate systems:
- Chat tab uses the
@anthropic-ai/claude-agent-sdkto callquery(). Separate process, separate sessions, separate conversation history. - Shell tab spawns the native
claudeCLI as a PTY process vianode-pty. Full native behavior.
This means:
- Conversations started in Chat cannot be resumed in Shell (or vice versa)
- Permissions granted in the native CLI (
~/.claude/settings.json) are not honored by the Chat tab - MCP servers, plugins, hooks, and CLAUDE.md are loaded differently between the two
- Session history lives in two places (localStorage for Chat,
~/.claude/projects/for Shell/CLI) - Features added to the native CLI require reimplementation in the SDK integration layer
Proposed Solution
Add a Full REPL Mode that, when enabled, makes the Chat tab spawn the native claude CLI (with --output-format stream-json --print) instead of using the SDK. The JSON events are mapped to the same WebSocket message format the Chat UI already expects, so the existing React components render them without changes.
Key features:
- Settings panel toggle under Claude > Permissions to enable/disable Full REPL Mode (persisted in localStorage)
- Native CLI spawning for Chat queries with
--output-format stream-json --verbose --print - Bidirectional session sync between Chat and Shell tabs via a server-side session registry. Sessions started in Chat can be resumed in Shell and vice versa, using
--resume - Permission parity with the native CLI (reads
~/.claude/settings.json) - "Remember" persistence writes approved tools back to
~/.claude/settings.json - MCP server info banner in Chat tab indicating MCP tools are available in Shell (since
--printmode can't efficiently load MCP servers without blocking)
Architecture:
- Chat tab spawns
bash -c 'claude --output-format stream-json ...'vianode-pty - Server parses JSONL output and maps CLI events (
system/init,assistant,user,result) to existing Chat UI WebSocket message types (session-created,claude-response,token-budget,claude-complete) - Session registry (
projectPath -> sessionId) enables seamless handoff: when switching tabs, the active CLI process is killed and the new tab resumes with--resume - MCP servers are skipped in
--printmode (adds 30s+ of timeout for failing servers) but fully available in the Shell tab's interactive REPL
Scope & limitations:
- This implementation covers Claude provider only. Other providers (Cursor, Codex, Gemini) continue using their existing integration and could adopt a similar pattern in the future
- MCP server tools are not available in Chat's
--printmode due to CLI startup overhead. The Shell tab provides full MCP access - The
--printflag means each Chat message spawns a fresh CLI process. A future optimization could use a persistent process with--input-format stream-jsonif the CLI adds support for that mode outside of VS Code's internal SDK
Files Changed
| File | Type | Description |
|---|---|---|
server/utils/settings-reader.js |
New | Reads/caches/writes ~/.claude/settings.json with mtime-based caching |
server/claude-cli-query.js |
New | CLI-based query runner, JSONL parser, session registry, event mapping |
server/claude-sdk.js |
Modified | Full REPL Mode permission overrides in mapCliOptionsToSDK, persist approvals to disk |
server/routes/settings.js |
Modified | /api/settings/repl-mode endpoint for UI config status |
server/index.js |
Modified | Route claude-command to CLI or SDK, session handoff between tabs |
src/components/chat/utils/chatStorage.ts |
Modified | isFullReplModeActive() / setFullReplMode() helpers |
src/components/chat/hooks/useChatComposerState.ts |
Modified | Pass fullReplMode flag in WebSocket messages |
src/components/chat/view/ChatInterface.tsx |
Modified | MCP tools banner when Full REPL Mode active |
src/components/settings/.../PermissionsContent.tsx |
Modified | Full REPL Mode toggle UI with settings.json status display |
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels