Stop Button Issue Analysis and Proposed Solutions
Issue Description
The stop button in the Sasha Studio chat interface is non-functional. When clicked, it doesn't abort the active Claude process as expected.
Root Cause Analysis
The Problem Flow
- User clicks the stop button in
SashaStatus.jsx - This triggers
handleAbortSession()inChatInterface.jsx - The function sends an
abort-sessionmessage via WebSocket with asessionId - Server receives the message and tries to abort using
abortClaudeSession(sessionId) - FAILURE: The lookup
activeClaudeProcesses.get(sessionId)returns undefined
Why It Fails
Session ID Mismatch Timeline
- New conversation starts:
currentSessionIdisnullin the client - Process spawned: Server creates process with key =
Date.now().toString() - Claude responds: Server captures real session ID from Claude CLI output
- Server updates: Process key changes from timestamp to actual session ID
- Client tries abort: Sends
nullor wrong session ID - Lookup fails: Server can't find process with that key
Code Locations
- Client Side:
src/components/SashaStatus.jsx:102-109- Stop button UIsrc/components/ChatInterface.jsx-handleAbortSession()function
- Server Side:
server/claude-cli.js-activeClaudeProcessesMap andabortClaudeSession()functionserver/index.js- WebSocket handler forabort-sessionmessage
Proposed Solutions
Solution 1: WebSocket-Based Process Tracking (Recommended)
Concept: Store the active Claude process directly on the WebSocket connection object instead of in a separate Map.
Implementation:
// In claude-cli.js - after spawning
ws.activeClaudeProcess = claudeProcess;
// In index.js - abort handler
if (data.type === 'abort-session') {
if (ws.activeClaudeProcess) {
ws.activeClaudeProcess.kill('SIGTERM');
ws.activeClaudeProcess = null;
}
}
Pros:
- No session ID dependencies
- Simple 1:1 relationship between connection and process
- No risk of key mismatches
- Doesn't touch critical session ID logic
Cons:
- Requires WebSocket connection to be maintained
Solution 2: Dual-Key Process Tracking
Concept: Store process under multiple keys for redundant lookup.
Implementation:
// Store under both temporary and real IDs
activeClaudeProcesses.set(tempKey, claudeProcess);
activeClaudeProcesses.set(capturedSessionId, claudeProcess);
Pros:
- Works with existing architecture
- Handles ID transitions
Cons:
- More complex
- Risk of memory leaks if not cleaned properly
- Still depends on session ID logic
Solution 3: Process ID Tracking
Concept: Track by process PID and send that to client.
Pros:
- Unique identifier that never changes
- OS-level guarantee
Cons:
- Requires client to track additional state
- Security considerations of exposing PIDs
Recommendation
Use Solution 1 (WebSocket-Based) because:
- It's the simplest and most reliable
- Doesn't interfere with critical session ID handling
- Natural cleanup when WebSocket disconnects
- Minimal code changes required
Testing Plan
- Start a new conversation
- Click stop button while Claude is processing
- Verify process is killed
- Start conversation with existing session
- Click stop button and verify it works
- Test with multiple concurrent sessions
Related Files
src/components/SashaStatus.jsx- UI component with stop buttonsrc/components/ChatInterface.jsx- Chat interface logicserver/claude-cli.js- Claude process managementserver/index.js- WebSocket message handling
Notes
- Session ID handling is critical to the application and should be modified with extreme caution
- The current architecture has session ID state managed in multiple places which creates synchronization challenges
- Any solution should be thoroughly tested with both new and existing sessions