@@ -7,6 +7,8 @@ import { getUsageMonitor } from '../claude-profile/usage-monitor';
77import { TerminalManager } from '../terminal-manager' ;
88import { projectStore } from '../project-store' ;
99import { terminalNameGenerator } from '../terminal-name-generator' ;
10+ import { debugLog , debugError } from '../../shared/utils/debug-logger' ;
11+ import { escapeShellArg } from '../../shared/utils/shell-escape' ;
1012
1113
1214/**
@@ -162,14 +164,108 @@ export function registerTerminalHandlers(
162164 ipcMain . handle (
163165 IPC_CHANNELS . CLAUDE_PROFILE_SET_ACTIVE ,
164166 async ( _ , profileId : string ) : Promise < IPCResult > => {
167+ debugLog ( '[terminal-handlers:CLAUDE_PROFILE_SET_ACTIVE] ========== PROFILE SWITCH START ==========' ) ;
168+ debugLog ( '[terminal-handlers:CLAUDE_PROFILE_SET_ACTIVE] Requested profile ID:' , profileId ) ;
169+
165170 try {
166171 const profileManager = getClaudeProfileManager ( ) ;
172+ const previousProfile = profileManager . getActiveProfile ( ) ;
173+ const previousProfileId = previousProfile . id ;
174+ const newProfile = profileManager . getProfile ( profileId ) ;
175+
176+ debugLog ( '[terminal-handlers:CLAUDE_PROFILE_SET_ACTIVE] Previous profile:' , {
177+ id : previousProfile . id ,
178+ name : previousProfile . name ,
179+ hasOAuthToken : ! ! previousProfile . oauthToken ,
180+ isDefault : previousProfile . isDefault
181+ } ) ;
182+
183+ debugLog ( '[terminal-handlers:CLAUDE_PROFILE_SET_ACTIVE] New profile:' , newProfile ? {
184+ id : newProfile . id ,
185+ name : newProfile . name ,
186+ hasOAuthToken : ! ! newProfile . oauthToken ,
187+ isDefault : newProfile . isDefault
188+ } : 'NOT FOUND' ) ;
189+
167190 const success = profileManager . setActiveProfile ( profileId ) ;
191+ debugLog ( '[terminal-handlers:CLAUDE_PROFILE_SET_ACTIVE] setActiveProfile result:' , success ) ;
192+
168193 if ( ! success ) {
194+ debugError ( '[terminal-handlers:CLAUDE_PROFILE_SET_ACTIVE] Profile not found, aborting' ) ;
169195 return { success : false , error : 'Profile not found' } ;
170196 }
197+
198+ // If the profile actually changed, restart Claude in active terminals
199+ // This ensures existing Claude sessions use the new profile's OAuth token
200+ const profileChanged = previousProfileId !== profileId ;
201+ debugLog ( '[terminal-handlers:CLAUDE_PROFILE_SET_ACTIVE] Profile changed:' , profileChanged , {
202+ previousProfileId,
203+ newProfileId : profileId
204+ } ) ;
205+
206+ if ( profileChanged ) {
207+ const activeTerminalIds = terminalManager . getActiveTerminalIds ( ) ;
208+ debugLog ( '[terminal-handlers:CLAUDE_PROFILE_SET_ACTIVE] Active terminal IDs:' , activeTerminalIds ) ;
209+
210+ const switchPromises : Promise < void > [ ] = [ ] ;
211+ const terminalsInClaudeMode : string [ ] = [ ] ;
212+ const terminalsNotInClaudeMode : string [ ] = [ ] ;
213+
214+ for ( const terminalId of activeTerminalIds ) {
215+ const isClaudeMode = terminalManager . isClaudeMode ( terminalId ) ;
216+ debugLog ( '[terminal-handlers:CLAUDE_PROFILE_SET_ACTIVE] Terminal check:' , {
217+ terminalId,
218+ isClaudeMode
219+ } ) ;
220+
221+ if ( isClaudeMode ) {
222+ terminalsInClaudeMode . push ( terminalId ) ;
223+ debugLog ( '[terminal-handlers:CLAUDE_PROFILE_SET_ACTIVE] Queuing terminal for profile switch:' , terminalId ) ;
224+ switchPromises . push (
225+ terminalManager . switchClaudeProfile ( terminalId , profileId )
226+ . then ( ( ) => {
227+ debugLog ( '[terminal-handlers:CLAUDE_PROFILE_SET_ACTIVE] Terminal profile switch SUCCESS:' , terminalId ) ;
228+ } )
229+ . catch ( ( err ) => {
230+ debugError ( '[terminal-handlers:CLAUDE_PROFILE_SET_ACTIVE] Terminal profile switch FAILED:' , terminalId , err ) ;
231+ throw err ; // Re-throw so Promise.allSettled correctly reports rejections
232+ } )
233+ ) ;
234+ } else {
235+ terminalsNotInClaudeMode . push ( terminalId ) ;
236+ }
237+ }
238+
239+ debugLog ( '[terminal-handlers:CLAUDE_PROFILE_SET_ACTIVE] Terminal summary:' , {
240+ total : activeTerminalIds . length ,
241+ inClaudeMode : terminalsInClaudeMode . length ,
242+ notInClaudeMode : terminalsNotInClaudeMode . length ,
243+ terminalsToSwitch : terminalsInClaudeMode ,
244+ terminalsSkipped : terminalsNotInClaudeMode
245+ } ) ;
246+
247+ // Wait for all switches to complete (but don't fail the main operation if some fail)
248+ if ( switchPromises . length > 0 ) {
249+ debugLog ( '[terminal-handlers:CLAUDE_PROFILE_SET_ACTIVE] Waiting for' , switchPromises . length , 'terminal switches...' ) ;
250+ const results = await Promise . allSettled ( switchPromises ) ;
251+ const fulfilled = results . filter ( r => r . status === 'fulfilled' ) . length ;
252+ const rejected = results . filter ( r => r . status === 'rejected' ) . length ;
253+ debugLog ( '[terminal-handlers:CLAUDE_PROFILE_SET_ACTIVE] Switch results:' , {
254+ total : results . length ,
255+ fulfilled,
256+ rejected
257+ } ) ;
258+ } else {
259+ debugLog ( '[terminal-handlers:CLAUDE_PROFILE_SET_ACTIVE] No terminals in Claude mode to switch' ) ;
260+ }
261+ } else {
262+ debugLog ( '[terminal-handlers:CLAUDE_PROFILE_SET_ACTIVE] Same profile selected, no terminal switches needed' ) ;
263+ }
264+
265+ debugLog ( '[terminal-handlers:CLAUDE_PROFILE_SET_ACTIVE] ========== PROFILE SWITCH COMPLETE ==========' ) ;
171266 return { success : true } ;
172267 } catch ( error ) {
268+ debugError ( '[terminal-handlers:CLAUDE_PROFILE_SET_ACTIVE] EXCEPTION:' , error ) ;
173269 return {
174270 success : false ,
175271 error : error instanceof Error ? error . message : 'Failed to set active Claude profile'
@@ -208,7 +304,7 @@ export function registerTerminalHandlers(
208304 const { mkdirSync, existsSync } = await import ( 'fs' ) ;
209305 if ( ! existsSync ( profile . configDir ) ) {
210306 mkdirSync ( profile . configDir , { recursive : true } ) ;
211- console . warn ( '[IPC] Created config directory:' , profile . configDir ) ;
307+ debugLog ( '[IPC] Created config directory:' , profile . configDir ) ;
212308 }
213309 }
214310
@@ -217,7 +313,7 @@ export function registerTerminalHandlers(
217313 const terminalId = `claude-login-${ profileId } -${ Date . now ( ) } ` ;
218314 const homeDir = process . env . HOME || process . env . USERPROFILE || '/tmp' ;
219315
220- console . warn ( '[IPC] Initializing Claude profile:' , {
316+ debugLog ( '[IPC] Initializing Claude profile:' , {
221317 profileId,
222318 profileName : profile . name ,
223319 configDir : profile . configDir ,
@@ -235,12 +331,14 @@ export function registerTerminalHandlers(
235331 let loginCommand : string ;
236332 if ( ! profile . isDefault && profile . configDir ) {
237333 // Use export and run in subshell to ensure CLAUDE_CONFIG_DIR is properly set
238- loginCommand = `export CLAUDE_CONFIG_DIR="${ profile . configDir } " && echo "Config dir: $CLAUDE_CONFIG_DIR" && claude setup-token` ;
334+ // SECURITY: Use escapeShellArg to prevent command injection via configDir
335+ const escapedConfigDir = escapeShellArg ( profile . configDir ) ;
336+ loginCommand = `export CLAUDE_CONFIG_DIR=${ escapedConfigDir } && echo "Config dir: $CLAUDE_CONFIG_DIR" && claude setup-token` ;
239337 } else {
240338 loginCommand = 'claude setup-token' ;
241339 }
242340
243- console . warn ( '[IPC] Sending login command to terminal:' , loginCommand ) ;
341+ debugLog ( '[IPC] Sending login command to terminal:' , loginCommand ) ;
244342
245343 // Write the login command to the terminal
246344 terminalManager . write ( terminalId , `${ loginCommand } \r` ) ;
@@ -263,7 +361,7 @@ export function registerTerminalHandlers(
263361 }
264362 } ;
265363 } catch ( error ) {
266- console . error ( '[IPC] Failed to initialize Claude profile:' , error ) ;
364+ debugError ( '[IPC] Failed to initialize Claude profile:' , error ) ;
267365 return {
268366 success : false ,
269367 error : error instanceof Error ? error . message : 'Failed to initialize Claude profile'
@@ -284,7 +382,7 @@ export function registerTerminalHandlers(
284382 }
285383 return { success : true } ;
286384 } catch ( error ) {
287- console . error ( '[IPC] Failed to set OAuth token:' , error ) ;
385+ debugError ( '[IPC] Failed to set OAuth token:' , error ) ;
288386 return {
289387 success : false ,
290388 error : error instanceof Error ? error . message : 'Failed to set OAuth token'
@@ -569,5 +667,5 @@ export function initializeUsageMonitorForwarding(mainWindow: BrowserWindow): voi
569667 mainWindow . webContents . send ( IPC_CHANNELS . PROACTIVE_SWAP_NOTIFICATION , notification ) ;
570668 } ) ;
571669
572- console . warn ( '[terminal-handlers] Usage monitor event forwarding initialized' ) ;
670+ debugLog ( '[terminal-handlers] Usage monitor event forwarding initialized' ) ;
573671}
0 commit comments