diff --git a/CLAUDE.md b/CLAUDE.md index 5c447cb3..f1232286 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -49,7 +49,7 @@ src/ ### Key Components -- **Session** (`src/session.ts`): Wraps Claude CLI as PTY subprocess. Two modes: `runPrompt(prompt)` for one-shot execution, `startInteractive()` for persistent terminal. Emits `output`, `terminal`, `message`, `completion`, `exit`, `idle`, `working` events. Maintains terminal buffer for reconnections. +- **Session** (`src/session.ts`): Wraps Claude CLI as PTY subprocess. Two modes: `runPrompt(prompt)` for one-shot execution, `startInteractive()` for persistent terminal. Emits `output`, `terminal`, `message`, `completion`, `exit`, `idle`, `working` events. Maintains terminal buffer for reconnections. Includes buffer management for long-running sessions (12-24+ hours) with automatic trimming. - **RespawnController** (`src/respawn-controller.ts`): State machine that keeps interactive sessions productive. Detects idle → sends update prompt → `/clear` → `/init` → repeats. Configurable timeouts and prompts. @@ -79,15 +79,55 @@ Claude CLI outputs newline-delimited JSON. Strip ANSI codes before parsing: ```typescript const cleanLine = line.replace(/\x1b\[[0-9;]*m/g, ''); const msg = JSON.parse(cleanLine) as ClaudeMessage; -// msg.type: 'system' | 'assistant' | 'result' +// msg.type: 'system' | 'assistant' | 'user' | 'result' // msg.message?.content: Array<{ type: 'text', text: string }> // msg.total_cost_usd: number (on result messages) ``` +### PTY Spawn Modes + +**One-shot mode** (prompt execution): +```typescript +pty.spawn('claude', ['-p', '--dangerously-skip-permissions', prompt], { ... }) +``` + +**Interactive mode** (persistent terminal): +```typescript +pty.spawn('claude', ['--dangerously-skip-permissions'], { ... }) +``` + ### Idle Detection Session detects idle by watching for prompt character (`❯` or `\u276f`) and waiting 2 seconds without activity. RespawnController uses the same patterns plus spinner characters to detect working state. +### Long-Running Session Support + +Sessions are optimized for 12-24+ hour runs with automatic buffer management: + +**Buffer Limits:** +- Terminal buffer: 5MB max, trims to 4MB when exceeded +- Text output: 2MB max, trims to 1.5MB when exceeded +- Messages: 1000 max, keeps most recent 800 when exceeded + +**Performance Optimizations:** +- Server-side terminal batching at 60fps (16ms intervals) +- Client-side requestAnimationFrame batching for smooth rendering +- Buffer statistics available via session details for monitoring + +**Buffer Stats Response:** +```typescript +{ + bufferStats: { + terminalBufferSize: number; // Current terminal buffer size in bytes + textOutputSize: number; // Current text output size in bytes + messageCount: number; // Number of parsed messages + maxTerminalBuffer: number; // Max allowed terminal buffer + maxTextOutput: number; // Max allowed text output + maxMessages: number; // Max allowed messages + } +} +``` + ### Respawn Controller State Machine ``` @@ -106,41 +146,63 @@ All events are broadcast to clients connected to `/api/events`. Event format: `{ **Session Events:** | Event | Data | Description | |-------|------|-------------| -| `session:output` | `{ text, raw }` | Parsed output line (ANSI stripped) | -| `session:terminal` | `{ data }` | Raw terminal data with ANSI codes | -| `session:message` | `{ message }` | Parsed Claude JSON message | -| `session:completion` | `{ cost }` | Prompt completed, includes cost | -| `session:exit` | `{ code }` | Session process exited | -| `session:idle` | `{}` | Session is idle (prompt detected) | -| `session:working` | `{}` | Session is working (activity detected) | +| `session:created` | `{ session }` | New session created | +| `session:deleted` | `{ id }` | Session removed | +| `session:output` | `{ id, data }` | Parsed output line (ANSI stripped) | +| `session:terminal` | `{ id, data }` | Raw terminal data with ANSI codes | +| `session:message` | `{ id, message }` | Parsed Claude JSON message | +| `session:running` | `{ id, prompt }` | Prompt execution started | +| `session:interactive` | `{ id }` | Interactive mode started | +| `session:completion` | `{ id, result, cost }` | Prompt completed, includes cost | +| `session:exit` | `{ id, code }` | Session process exited | +| `session:idle` | `{ id }` | Session is idle (prompt detected) | +| `session:working` | `{ id }` | Session is working (activity detected) | +| `session:updated` | `{ session }` | Session state updated | +| `session:error` | `{ id, error }` | Session error occurred | **Respawn Controller Events:** | Event | Data | Description | |-------|------|-------------| -| `respawn:stateChanged` | `{ from, to }` | State machine transition | -| `respawn:cycleStarted` | `{ cycleNumber }` | New update cycle starting | -| `respawn:cycleCompleted` | `{ cycleNumber }` | Update cycle finished | -| `respawn:stepSent` | `{ step }` | Command sent (update/clear/init) | -| `respawn:stepCompleted` | `{ step }` | Command completed | -| `respawn:log` | `{ message, level }` | Debug/info log message | +| `respawn:started` | `{ sessionId, status }` | Respawn controller started | +| `respawn:stopped` | `{ sessionId }` | Respawn controller stopped | +| `respawn:stateChanged` | `{ sessionId, state, prevState }` | State machine transition | +| `respawn:cycleStarted` | `{ sessionId, cycleNumber }` | New update cycle starting | +| `respawn:cycleCompleted` | `{ sessionId, cycleNumber }` | Update cycle finished | +| `respawn:stepSent` | `{ sessionId, step, input }` | Command sent (update/clear/init) | +| `respawn:stepCompleted` | `{ sessionId, step }` | Command completed | +| `respawn:configUpdated` | `{ sessionId, config }` | Configuration changed | +| `respawn:log` | `{ sessionId, message }` | Debug/info log message | +| `respawn:error` | `{ sessionId, error }` | Error occurred | **Scheduled Run Events:** | Event | Data | Description | |-------|------|-------------| -| `scheduled:created` | `{ id, prompt, duration }` | New scheduled run created | -| `scheduled:updated` | `{ id, status, remaining }` | Status/timer update | -| `scheduled:log` | `{ id, message }` | Scheduled run log entry | -| `scheduled:completed` | `{ id, success }` | Scheduled run finished | +| `scheduled:created` | `{ run }` | New scheduled run created | +| `scheduled:updated` | `{ run }` | Status/timer update | +| `scheduled:log` | `{ id, log }` | Scheduled run log entry | +| `scheduled:completed` | `{ run }` | Scheduled run finished | +| `scheduled:stopped` | `{ run }` | Scheduled run stopped by user | + +**Case Events:** +| Event | Data | Description | +|-------|------|-------------| +| `case:created` | `{ name, path }` | New case directory created | + +**Init Event:** +| Event | Data | Description | +|-------|------|-------------| +| `init` | `{ sessions, scheduledRuns, respawnStatus, timestamp }` | Full state sent on SSE connection | ## API Endpoints ### Session Management ``` -GET /api/sessions # List all sessions +GET /api/sessions # List all sessions (includes buffer stats) POST /api/sessions # Create session { workingDir } GET /api/sessions/:id # Get single session details -DELETE /api/sessions/:id # Stop and remove a session +DELETE /api/sessions/:id # Stop and remove a session (kills process + children) +DELETE /api/sessions # Kill all sessions at once GET /api/sessions/:id/output # Get session output buffer GET /api/sessions/:id/terminal # Get terminal buffer (raw ANSI) ``` @@ -173,15 +235,27 @@ GET /api/scheduled/:id # Get scheduled run details DELETE /api/scheduled/:id # Cancel scheduled run ``` -### Cases & Quick Run +### Cases & Quick Start ``` GET /api/cases # List case directories POST /api/cases # Create case { name, description } GET /api/cases/:name # Get case details +POST /api/quick-start # Quick start { caseName? } - creates case + interactive session POST /api/run # Quick run { prompt, workingDir } (no session management) ``` +**Quick Start Response:** +```typescript +{ + success: boolean; + sessionId?: string; // ID of the created session + casePath?: string; // Full path to the case directory + caseName?: string; // Name of the case + error?: string; // Error message if success is false +} +``` + ### Events ``` @@ -189,11 +263,3 @@ GET /api/events # SSE stream (real-time events) GET /api/status # Full state snapshot (sessions + scheduled + respawn) ``` -## Session Log - -| Date | Tasks Completed | Files Changed | Notes | -|------|-----------------|---------------|-------| -| 2026-01-18 | Initial implementation | All files | Core CLI + web interface | -| 2026-01-18 | Add web interface | src/web/* | Fastify + SSE + responsive UI | -| 2026-01-18 | Add RespawnController | src/respawn-controller.ts, src/web/server.ts, src/types.ts | Auto-respawn loop with state machine | -| 2026-01-18 | Update documentation | CLAUDE.md, README.md | Full API docs (20 endpoints), SSE event catalog, interactive terminal docs, respawn controller docs | diff --git a/README.md b/README.md index ffd7aa24..20e7e6e4 100644 --- a/README.md +++ b/README.md @@ -4,18 +4,20 @@ A Claude Code session manager with an autonomous Ralph Loop for task assignment ## Features -- **Web Interface**: Beautiful, responsive web UI with interactive terminal powered by xterm.js -- **Session Management**: Spawn and manage multiple Claude CLI sessions as PTY subprocesses -- **Interactive Terminal**: Full terminal access with resize support and buffer persistence for reconnections +- **Web Interface**: Beautiful, responsive web UI with interactive terminal powered by xterm.js and modern gradient styling +- **Session Management**: Spawn and manage multiple Claude CLI sessions as PTY subprocesses with one-click kill +- **Interactive Terminal**: Full terminal access with resize support, buffer persistence, and 60fps batched rendering - **Respawn Controller**: Autonomous state machine that cycles sessions (update docs → /clear → /init) with configurable prompts -- **Timed Runs**: Schedule Claude to work for a specific duration with live countdown -- **Real-time Output**: Stream Claude's responses in real-time via Server-Sent Events (21 event types) +- **Timed Runs**: Schedule Claude to work for a specific duration with animated live countdown +- **Real-time Output**: Stream Claude's responses in real-time via Server-Sent Events (30 event types) - **Task Queue**: Priority-based task queue with dependency support - **Ralph Loop**: Autonomous control loop that assigns tasks to idle sessions and monitors completion - **Time-Aware Loops**: Extended work sessions with auto-generated follow-up tasks when minimum duration not reached - **Case Management**: Create project workspaces with auto-generated CLAUDE.md templates - **Cost Tracking**: Track total API costs across all sessions - **State Persistence**: All state persisted to `~/.claudeman/state.json` +- **Long-Running Support**: Optimized for 12-24+ hour sessions with automatic buffer trimming +- **Resource Monitoring**: Real-time memory/message usage display for each session ## Installation @@ -37,14 +39,40 @@ claudeman web ``` The web interface provides: -- **Interactive Terminal**: Full xterm.js terminal with resize support +- **Quick Start Button**: One-click to create a case and start an interactive Claude session +- **Interactive Terminal**: Full xterm.js terminal with resize support and 60fps rendering - **Prompt Input**: Enter prompts and optionally set a working directory - **Duration Timer**: Set duration in minutes for timed runs (0 = single run) - **Live Output**: See Claude's response in real-time as it streams -- **Countdown**: Large timer display when running timed jobs -- **Session Monitoring**: View all active sessions with status indicators +- **Countdown**: Animated timer display with shimmer progress bar +- **Session Monitoring**: View all active sessions with status, resource usage, and cost +- **Kill All Button**: One-click to terminate all running sessions and their child processes +- **Resource Display**: Real-time memory usage and message count per session - **Respawn Controls**: Start/stop respawn controller with configurable settings - **Case Management**: Create new project workspaces with CLAUDE.md templates +- **Modern UI**: Gradient backgrounds, smooth animations, and polished styling + +#### Quick Start Button + +The Quick Start feature reduces the typical 5-step workflow to just 1-2 steps: + +**Before (5 steps):** +1. Go to Cases tab +2. Create a case +3. Click the case +4. Switch to Run tab +5. Click Interactive + +**After (1-2 steps):** +1. (Optional) Select a case from dropdown +2. Click "Quick Start" + +The Quick Start button will: +- Create a case folder in `~/claudeman-cases/` if it doesn't exist +- Generate a CLAUDE.md file for the case +- Create a new session pointed to that case directory +- Start an interactive Claude terminal +- Focus the terminal so you can start working immediately ### CLI Usage @@ -227,6 +255,36 @@ When the minimum duration hasn't been reached and all tasks are complete, the Ra - Check for security vulnerabilities - Run linting and fix issues +## Long-Running Sessions + +Claudeman is optimized for extended autonomous sessions (12-24+ hours): + +### Buffer Management + +To prevent memory issues during long runs, buffers are automatically managed: +- **Terminal buffer**: Max 5MB, trims to 4MB when exceeded +- **Text output**: Max 2MB, trims to 1.5MB when exceeded +- **Messages**: Max 1000, keeps most recent 800 when exceeded + +### Performance Optimizations + +- **Server-side batching**: Terminal data batched at 60fps (16ms intervals) +- **Client-side batching**: requestAnimationFrame for smooth rendering +- **Aggressive process cleanup**: SIGKILL with process group termination + +### Resource Monitoring + +Each session displays real-time resource usage: +- Memory usage (terminal + text buffers) +- Message count +- Color-coded warnings (green/yellow/red based on usage) + +### Kill Sessions + +- Click `✕` on individual session cards to terminate +- Click `Kill All` button in sessions panel to terminate all at once +- Sessions are forcefully killed with SIGKILL after SIGTERM timeout + ## State File All state is persisted to `~/.claudeman/state.json`: