Last updated: Sep 1, 2025, 01:10 PM UTC

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

  1. User clicks the stop button in SashaStatus.jsx
  2. This triggers handleAbortSession() in ChatInterface.jsx
  3. The function sends an abort-session message via WebSocket with a sessionId
  4. Server receives the message and tries to abort using abortClaudeSession(sessionId)
  5. FAILURE: The lookup activeClaudeProcesses.get(sessionId) returns undefined

Why It Fails

Session ID Mismatch Timeline

  1. New conversation starts: currentSessionId is null in the client
  2. Process spawned: Server creates process with key = Date.now().toString()
  3. Claude responds: Server captures real session ID from Claude CLI output
  4. Server updates: Process key changes from timestamp to actual session ID
  5. Client tries abort: Sends null or wrong session ID
  6. Lookup fails: Server can't find process with that key

Code Locations

  • Client Side:
    • src/components/SashaStatus.jsx:102-109 - Stop button UI
    • src/components/ChatInterface.jsx - handleAbortSession() function
  • Server Side:
    • server/claude-cli.js - activeClaudeProcesses Map and abortClaudeSession() function
    • server/index.js - WebSocket handler for abort-session message

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:

  1. It's the simplest and most reliable
  2. Doesn't interfere with critical session ID handling
  3. Natural cleanup when WebSocket disconnects
  4. Minimal code changes required

Testing Plan

  1. Start a new conversation
  2. Click stop button while Claude is processing
  3. Verify process is killed
  4. Start conversation with existing session
  5. Click stop button and verify it works
  6. Test with multiple concurrent sessions

Related Files

  • src/components/SashaStatus.jsx - UI component with stop button
  • src/components/ChatInterface.jsx - Chat interface logic
  • server/claude-cli.js - Claude process management
  • server/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