From 8f166d1fa51f990d8c243c13bfa05c12d6b6df99 Mon Sep 17 00:00:00 2001 From: Roy Date: Sun, 17 Aug 2025 12:05:55 -0700 Subject: [PATCH] Add an environment variable to configure claude launcher --- README.md | 10 ++++++++++ server/claude-cli.js | 45 +++++++++++++++++++++++++++++++++----------- 2 files changed, 44 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index fcb505cb..6edcccc6 100644 --- a/README.md +++ b/README.md @@ -113,6 +113,16 @@ To use Claude Code's full functionality, you'll need to manually enable tools: ### Core Features +#### Claude CLI alias + +If you use an alternative launcher like claude-code-router, you can set a custom alias for the Claude CLI that this server will spawn. + +- Env var: `CLAUDE_CODE_UI_CLAUDE_SPAWN_ALIAS` +- Default: `claude` +- Example: `CLAUDE_CODE_UI_CLAUDE_SPAWN_ALIAS=ccr code` + +This is honored across all Claude CLI spawns, including MCP routes. + #### Project Management The UI automatically discovers Claude Code projects from `~/.claude/projects/` and provides: - **Visual Project Browser** - All available projects with metadata and session counts diff --git a/server/claude-cli.js b/server/claude-cli.js index c8a5ebbf..101a36ea 100755 --- a/server/claude-cli.js +++ b/server/claude-cli.js @@ -225,17 +225,40 @@ async function spawnClaude(command, options = {}, ws) { console.log('📝 Skip permissions disabled due to plan mode'); } } - - console.log('Spawning Claude CLI:', 'claude', args.map(arg => { - const cleanArg = arg.replace(/\n/g, '\\n').replace(/\r/g, '\\r'); - return cleanArg.includes(' ') ? `"${cleanArg}"` : cleanArg; - }).join(' ')); - console.log('Working directory:', workingDir); - console.log('Session info - Input sessionId:', sessionId, 'Resume:', resume); - console.log('🔍 Full command args:', JSON.stringify(args, null, 2)); - console.log('🔍 Final Claude command will be: claude ' + args.join(' ')); - - const claudeProcess = spawnFunction('claude', args, { + + // Resolve alias at runtime so .env changes are picked up + const CLAUDE_SPAWN_ALIAS = ( + process.env.CLAUDE_CODE_UI_CLAUDE_SPAWN_ALIAS || "claude" + ).trim(); + const [CLAUDE_CMD, ...CLAUDE_PREFIX_ARGS] = + CLAUDE_SPAWN_ALIAS.split(/\s+/).filter(Boolean); + + console.log( + "Spawning Claude CLI:", + CLAUDE_SPAWN_ALIAS, + args + .map((arg) => { + const cleanArg = arg.replace(/\n/g, "\\n").replace(/\r/g, "\\r"); + return cleanArg.includes(" ") ? `"${cleanArg}"` : cleanArg; + }) + .join(" "), + ); + console.log("Working directory:", workingDir); + console.log( + "Session info - Input sessionId:", + sessionId, + "Resume:", + resume, + ); + console.log("🔍 Full command args:", JSON.stringify(args, null, 2)); + console.log( + "🔍 Final Claude command will be:", + CLAUDE_SPAWN_ALIAS + " " + args.join(" "), + ); + + // Prepend any alias prefix args (e.g., when alias is "ccr code") + const finalArgs = [...CLAUDE_PREFIX_ARGS, ...args]; + const claudeProcess = spawnFunction(CLAUDE_CMD, finalArgs, { cwd: workingDir, stdio: ['pipe', 'pipe', 'pipe'], env: { ...process.env } // Inherit all environment variables