* Handle spawn operation - creates a new Claude Code instance. * Uses in-process mode when enabled, otherwise uses tmux/iTerm2 split-pane view. * Falls back to in-process if pane backend detection fails (e.g., iTerm2 without * it2 CLI or tmux installed).
( input: SpawnInput, context: ToolUseContext, )
| 1038 | * it2 CLI or tmux installed). |
| 1039 | */ |
| 1040 | async function handleSpawn( |
| 1041 | input: SpawnInput, |
| 1042 | context: ToolUseContext, |
| 1043 | ): Promise<{ data: SpawnOutput }> { |
| 1044 | // Check if in-process mode is enabled via feature flag |
| 1045 | if (isInProcessEnabled()) { |
| 1046 | return handleSpawnInProcess(input, context) |
| 1047 | } |
| 1048 | |
| 1049 | // Pre-flight: ensure a pane backend is available before attempting pane-based spawn. |
| 1050 | // This handles auto-mode cases like iTerm2 without it2 or tmux installed, where |
| 1051 | // isInProcessEnabled() returns false but detectAndGetBackend() has no viable backend. |
| 1052 | // Narrowly scoped so user cancellation and other spawn errors propagate normally. |
| 1053 | try { |
| 1054 | await detectAndGetBackend() |
| 1055 | } catch (error) { |
| 1056 | // Only fall back silently in auto mode. If the user explicitly configured |
| 1057 | // teammateMode: 'tmux', let the error propagate so they see the actionable |
| 1058 | // install instructions from getTmuxInstallInstructions(). |
| 1059 | if (getTeammateModeFromSnapshot() !== 'auto') { |
| 1060 | throw error |
| 1061 | } |
| 1062 | logForDebugging( |
| 1063 | `[handleSpawn] No pane backend available, falling back to in-process: ${errorMessage(error)}`, |
| 1064 | ) |
| 1065 | // Record the fallback so isInProcessEnabled() reflects the actual mode |
| 1066 | // (fixes banner and other UI that would otherwise show tmux attach commands). |
| 1067 | markInProcessFallback() |
| 1068 | return handleSpawnInProcess(input, context) |
| 1069 | } |
| 1070 | |
| 1071 | // Backend is available (and now cached) - proceed with pane spawning. |
| 1072 | // Any errors here (user cancellation, validation, etc.) propagate to the caller. |
| 1073 | const useSplitPane = input.use_splitpane !== false |
| 1074 | if (useSplitPane) { |
| 1075 | return handleSpawnSplitPane(input, context) |
| 1076 | } |
| 1077 | return handleSpawnSeparateWindow(input, context) |
| 1078 | } |
| 1079 | |
| 1080 | // ============================================================================ |
| 1081 | // Main Export |
no test coverage detected