* add project setup
* add tools to eslint
* remove contributing.md
* update claude md
* chore: simplify CI to single Node.js version (22)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* use node 20
* adjust formatting
* fix linting
* format
* fix layout
* fix: align CI node version to .nvmrc (22), remove redundant gotcha
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: arkon <arkon.85@hotmail.com>
Records every session create, start, exit, delete, recover, stale-clean,
mux-died, and server start/stop with timestamps, names, reasons, and exit
codes. Survives server restarts (unlike in-memory RunSummary).
- New SessionLifecycleLog singleton (src/session-lifecycle-log.ts)
- LifecycleEventType + LifecycleEntry types in types.ts
- GET /api/session-lifecycle endpoint with sessionId/event/since/limit filters
- cleanupSession() now takes reason parameter for audit trail
- state-store cleanupStaleSessions returns cleaned session IDs+names
- UI: lifecycle log modal accessible from header clipboard icon
- Auto-trims to 8k entries when exceeding 10k on server start
chore: bump version to 0.1556
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Bug 1 (CRITICAL): canonicalCount >= 1 always fired on first <promise> tag
(prompt echo). Changed to >= 2 so only 2nd+ occurrence triggers completion.
Bug 2: checkMultiLinePatterns() re-detected complete tags already handled
by processLine(), double-counting. Now only tries completion when partial
buffer is non-empty (cross-chunk scenario).
Bug 3: TodoWrite ✔ patterns required "Task #N" but real Claude Code output
is plain "✔ content". Added TODO_PLAIN_CHECKMARK_PATTERN fallback.
Includes 71 new deep tests + real-life verification.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1. handleInit crash: commit cdc822d removed Map initializations for
teammateTerminals, teammatePanesByName, teams, teamTasks, teammateMap
from the constructor but left cleanup code that iterates them.
cleanupAllFloatingWindows() crashed on "not iterable", preventing
ALL frontend data (sessions, subagents) from loading.
2. claudeSessionId null on recovered sessions: only set inside
startInteractive(), never in constructor or persisted. After server
restart, recovered sessions had null claudeSessionId, so the
hasMatchingTab check always failed → no subagent windows.
Fixes:
- Re-add all 5 missing Map initializations in app.js constructor
- Set _claudeSessionId = this.id in Session constructor (Claudeman
always passes --session-id to Claude, so they always match)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Added IS_TEST_MODE (process.env.VITEST) guards to every method in TmuxManager and
ScreenManager that touches real tmux/screen sessions. Tests can never create, kill,
discover, or send input to real sessions. Removed broken E2E test suite entirely.
Rewrote test/setup.ts from 459 lines to minimal cleanup. Rewrote tmux-related tests
to verify test-mode safety behavior.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- WebServer: Store session listener refs for explicit cleanup on delete
- RespawnController: Fix clearInterval bug (was using clearTimeout)
- RespawnController: Add try/catch to interval callbacks
- PlanOrchestrator: Guarantee progressInterval cleanup with try/finally
- SubagentWatcher: Guard idle timer against deleted agents
- Session: Add threshold validation for auto-clear/compact (1k-500k)
- Session: Add token sum overflow check in restoreTokens
- Session: Use LRUMap for _recentTaskDescriptions auto-eviction
Commit from flight QR118 in an Airbus A350-1000, stable connection thanks to Starlink!
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create src/utils/regex-patterns.ts with ANSI_ESCAPE_PATTERN_FULL,
ANSI_ESCAPE_PATTERN_SIMPLE, TOKEN_PATTERN, and helper functions
- Create src/utils/token-validation.ts with MAX_SESSION_TOKENS and
validation utilities
- Update session.ts, respawn-controller.ts, ai-checker-base.ts,
ralph-tracker.ts, state-store.ts to use shared utilities
- Export all new utilities from src/utils/index.ts
Reduces code duplication while maintaining pre-compiled patterns
for performance.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- execution-bridge: track and cleanup retry timers to prevent memory leaks
- model-selector: add exhaustive type check for ModelTier
- ralph-tracker: fix division by zero when summary.total is 0
- respawn-controller: remove event listeners on stop to prevent memory leaks
- screen-manager: use Promise.allSettled for better error handling in stats
- session-manager: use Promise.allSettled for stopAllSessions resilience
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Replace local BufferAccumulator in session.ts with shared utility
- Replace local BufferAccumulator in respawn-controller.ts with shared utility
- Import buffer constants from config/buffer-limits.ts
- Reduces code duplication and centralizes buffer management
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Smart Respawn Integration (2.5):
- Check circuit breaker OPEN state before respawn (blocks cycle)
- Check RALPH_STATUS EXIT_SIGNAL=true to stop respawn
- Check STATUS=BLOCKED to pause respawn for human intervention
- Use RECOMMENDATION from RALPH_STATUS in update prompt
- Emit respawn:blocked SSE event with reason and details
- Show notification when respawn is blocked
- Visual blocked state with pulsing red indicator
Priority-based Todos (part of 2.3):
- Add RalphTodoPriority type (P0/P1/P2/null)
- Parse priority from todo content (P0:, Critical:, High Priority, etc.)
- Add priority field to RalphTodoItem interface
- Update frontend to display priority badges with colors
- Sort todos by priority (P0 > P1 > P2) then by status
- Add CSS for priority badges and highlighted cards
Bump version to 0.1391
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add 300-char rolling window to catch working patterns split across PTY chunks
- Check completion message BEFORE working patterns (priority fix)
- Clear rolling window on completion message (transition point)
- Increase working pattern absence threshold from 3s to 8s
- Add Session.isWorking safety check before confirming idle
- Add 20+ more working patterns (Compiling, Building, Processing, etc.)
- Make AI idle checker prompt more conservative (err toward WORKING)
- Update documentation
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement multi-phase improvement to respawn controller's idle detection:
Phase 1 - Stop Hook Detection:
- Add signalStopHook() method - definitive signal when Claude finishes
- 3s confirmation timer to handle race conditions
- Skip AI check when hook received (100% confidence)
Phase 2 - idle_prompt Detection:
- Add signalIdlePrompt() method - fires after 60s+ of idle
- Immediately confirms idle (no confirmation timer needed)
Phase 3 - Transcript File Monitoring:
- New TranscriptWatcher class watches session JSONL files
- Detects: completion, tool execution, plan mode, errors
- Signals respawn controller for supporting detection
Web UI Updates:
- Hook indicator with purple styling and pulse animation
- Shows "Stop hook received" or "idle_prompt hook received"
- 100% confidence displayed with hook-confirmed style
This significantly improves idle detection reliability by using
definitive signals from Claude Code rather than parsing terminal output.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Stack timers row vertically (timers on top, action log below)
- Reduce action log height to 60px since it's now full width
- Filter action log to show only important entries:
- Commands sent to console
- Plan-check with action taken
- Step completions
- Skip timer starts/cancels, detection updates, ai-check status
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add restoreTokens() method to Session class for recovery after restart
- Add GlobalStats type for cumulative usage tracking across all sessions
- Accumulate tokens from deleted sessions into global stats
- Track lifetime session count with incrementSessionsCreated()
- Add /api/stats endpoint for global stats
- Include globalStats in /api/status response
- Frontend shows aggregate tokens + cost in header
- Fix respawn controller config to filter undefined values
- Add 7 new tests for global stats functionality (v0.1343)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add state check in startPlanCheck() to prevent Enter if state changed
- sendAutoAcceptEnter() now cancels pending AI idle checks and resets state
- Log auto-accept as [command] type for visibility in action log
- Highlight command entries with blue background in action log
- Show action log row when there are actions (not just timers)
- Increase action log height and opacity for better visibility
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix "enable twice" bug: add enabled:true to getModalRespawnConfig()
- Add timer tracking with countdown display in respawn banner
- New events: timerStarted, timerCancelled, timerCompleted, actionLog
- Show active timers with progress bars and recent action log
- Skip remaining timeouts after AI check returns IDLE/WORKING verdict
- Enhanced DetectionStatus with activeTimers, recentActions, currentPhase
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds a two-stage gate before auto-accepting plan mode prompts:
1. Strict regex pre-filter - checks for numbered options + selector
2. AI confirmation - spawns Opus to classify as PLAN_MODE or NOT_PLAN_MODE
This prevents spurious Enter key presses when Claude is paused mid-thought
or experiencing network lag, rather than showing a plan approval prompt.
New files:
- src/ai-plan-checker.ts: AI checker following ai-idle-checker.ts pattern
Config fields added to RespawnConfig:
- aiPlanCheckEnabled (default: true)
- aiPlanCheckModel (default: claude-opus-4-5-20251101)
- aiPlanCheckMaxContext (default: 8000)
- aiPlanCheckTimeoutMs (default: 60000)
- aiPlanCheckCooldownMs (default: 30000)
New events: planCheckStarted, planCheckCompleted, planCheckFailed
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Two bugs fixed:
1. Respawn controller got stuck after AI check returned WORKING/ERROR.
The pre-filter and no-output timers fired once but were never restarted,
leaving the controller in a dead 'watching' state with no retry mechanism.
Now restarts both timers after any non-IDLE AI check result and on
cooldown expiry. Also seeds the controller's terminal buffer from the
session's existing output so the first AI check has context.
2. AI idle checker couldn't find the claude binary in restricted environments
(systemd service). The spawned screen ran `claude -p` without PATH
augmentation. Now exports getAugmentedPath() from session.ts and prepends
it in the AI checker's bash command.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace the "Worked for Xm Xs" pattern as the sole primary idle
detection signal with a final AI-powered check. When pre-filter
conditions are met (output silence, no working patterns, tokens
stable), a fresh Claude CLI session is spawned in a screen to
analyze terminal output and provide a definitive IDLE/WORKING
verdict before proceeding with the respawn cycle.
New state in state machine: `ai_checking` (between pre-filter
confirmation and `sending_update`). WORKING verdict triggers a
3-minute cooldown. Errors auto-disable after 3 consecutive
failures, falling back to the existing noOutputTimeoutMs safety net.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Three improvements to prevent the respawn controller from sending update
prompts while Claude is still working:
1. Tighten COMPLETION_TIME_PATTERN to require "Worked for" prefix, avoiding
false positives from bare time durations in regular text (e.g., "wait for 5s")
2. Increase completionConfirmMs default from 5s to 10s - Claude regularly
pauses 5-8s between tool calls and during thinking
3. Cancel confirming_idle state when substantial output arrives (stripped of
ANSI codes), instead of passively relying on the timer to self-restart
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The auto-accept feature was too aggressive - it would press Enter for any
silence without a completion message, including AskUserQuestion prompts.
Now uses the elicitation_dialog notification hook to detect when Claude is
asking a question, and blocks auto-accept in that case. Only plan mode
approvals (silence with no completion message AND no elicitation signal)
trigger auto-accept.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When Claude enters plan mode or asks a question (AskUserQuestion), output
stops without a completion message. The new autoAcceptPrompts feature
detects this state and sends Enter after a configurable delay (default 8s)
to accept the plan or select the default option, keeping Claude working
autonomously.
Enabled by default. Adds UI checkbox in the respawn config panel.
Safety: only fires once per silence period, requires prior output,
and won't fire during active respawn cycles.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The web server now persists all per-session settings (name, mode,
auto-compact, auto-clear, respawn config, ralph state, tokens, cost)
to state.json so the CLI status/session commands can display them.
Also removes unused pendingStepConfirm property from respawn controller.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add step confirmation timer for waiting_update, waiting_init, waiting_kickstart states
- After detecting completion in waiting states, wait for completionConfirmMs silence
- Prevents sending next command before Claude finishes processing current one
- Cancel step confirmation when working patterns detected
- Update CLAUDE.md with step confirmation documentation
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update idle detection from legacy '↵ send' to completion message pattern
("for Xm Xs" time patterns like "Worked for 2m 46s")
- Add confirming_idle state for false positive prevention
- Add completionConfirmMs (5s) and noOutputTimeoutMs (30s) config options
- Add multi-layer detection with confidence scoring (0-100%)
- Fix null pointer error in extractTokenCount with guard clause
- Fix respawn controller not stopping on session cleanup (broadcast respawn:stopped)
- Update tests to use new completion message patterns
- Add detection status UI display (confidence level, waiting state)
- Update CLAUDE.md with new detection documentation
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
After sending /clear, if no prompt indicator is detected within 10 seconds,
proceed to send /init anyway. This fixes respawn getting stuck when Claude
doesn't show the expected prompt characters after /clear completes.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove deprecated ANSI_ESCAPE_PATTERN and WHITESPACE_PATTERN from
respawn-controller.ts (were marked as unused)
- Update optimization-todos.md with progress on completed items:
- Item 1: BufferAccumulator implemented
- Item 2: lastIndex resets already in place
- Item 3: Auto-trim via BufferAccumulator
- Item 9: Unused regex patterns removed
- Item 13: Files not dead code (used by CLI)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace string concatenation (+=) with array-based BufferAccumulator
in terminal buffer handling. This reduces garbage collection pressure
during high-throughput terminal streaming.
Changes:
- Add BufferAccumulator class with auto-trim on max size
- Convert _terminalBuffer and _textOutput to BufferAccumulator in session.ts
- Convert terminalBuffer to BufferAccumulator in respawn-controller.ts
- Remove manual trim logic (now handled by BufferAccumulator)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Auto-compact now uses writeViaScreen with \r
- Auto-clear now uses writeViaScreen with \r
- Standardized respawn controller to use \r consistently
- Removed session name input from options modal (use right-click to rename)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Regular user input should go through PTY, only respawn controller
should use screen -X stuff. Added writeViaScreen() method for
programmatic input that needs reliable Enter key delivery.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When writing to an attached PTY connected to screen, the input doesn't
reliably reach Claude CLI. This fix uses `screen -X stuff` command to
send input directly to the screen session, bypassing the PTY attachment.
Research findings:
- Claude CLI uses Ink (React for CLI) for terminal UI
- Ink's parseKeypress detects \r as key.return (Enter)
- screen -X stuff with $'...' syntax reliably sends literal characters
Changes:
- Add ScreenManager.sendInput() using screen -X stuff
- Modify Session.write() to prefer screen -X stuff when available
- Keep \r as Enter key (what Ink expects for key.return)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Screen sessions require \n (line feed) for Enter key input, not \r
(carriage return). This fixes the issue where respawn prompts would
appear in the terminal but not be submitted.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Changed all command writes from \n (newline) to \r (carriage return).
PTY terminals expect \r for Enter key, \n only creates a new line
without executing the command.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The respawn controller was calling removeAllListeners('terminal')
which also removed the server's listener that streams output to
the browser. This made the console appear "blocked" when respawn
was enabled.
Now properly tracks and removes only its own listener.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fixed respawn controller immediately sending commands when Claude
becomes idle, which prevented users from typing. Now waits for
idleTimeoutMs (default 10s) before triggering the respawn cycle.
- Removed Directory field from Session Options modal for cleaner UI
- Compacted CLAUDE.md documentation for better readability
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Kickstart Prompt:
- Remove Idle Timeout setting from respawn UI (uses 10s default)
- Add Kickstart Prompt field sent when /init doesn't trigger work
- New states: monitoring_init, sending_kickstart, waiting_kickstart
- Monitors 3s after /init to detect if Claude started working
Auto-Compact Context:
- Add auto-compact at 110k tokens (sends /compact with optional prompt)
- Preserves summarized context unlike /clear which wipes everything
- Optional focus prompt to guide what compact should preserve
- Blocks auto-clear while compacting to prevent conflicts
Also updates auto-clear default threshold from 100k to 140k tokens.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Primary: Use '↵ send' indicator for immediate response when ready
- Fallback: Use timeout-based detection for prompt patterns
- Add working indicators: Synthesizing, Brewing, ✻, ✽
- Cleaner step completion handlers (checkUpdateComplete, etc.)
The hybrid approach responds immediately when Claude shows the
suggestion indicator, while still having timeout fallback for
reliability.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add '↵ send' as primary idle indicator (suggestion ready)
- Add 'Synthesizing', 'Brewing' to working patterns
- Add '✻', '✽' activity indicators to working patterns
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>