- Add SubagentWatcher service that discovers and tails Claude Code's subagent
transcript files (~/.claude/projects/.../subagents/agent-*.jsonl)
- Track tool calls, progress events, and messages in real-time via file watching
- Add SSE events for subagent:discovered, subagent:tool_call, subagent:progress,
subagent:message, subagent:completed
- Add REST API endpoints: GET /api/subagents, /api/subagents/:id,
/api/subagents/:id/transcript
- Add subagent panel in Monitor section showing active agents and their activity
- Add floating draggable windows that auto-open for each active agent
- Add standalone CLI tool: scripts/watch-subagents.ts for terminal monitoring
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Added documentation about test cleanup patterns, known issues with
session/case cleanup in specific test files, and manual cleanup commands
for orphaned test resources.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add isTerminalAtBottom() helper and modify batchTerminalWrite() to implement
sticky scroll behavior. When SSE terminal data arrives after tab switch,
terminal now stays scrolled to Claude input if user was already at bottom.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add AiCheckerBase abstract class to eliminate ~700 lines of duplication
between AiIdleChecker and AiPlanChecker
- Fix missing persistence fields (completionConfirmMs, noOutputTimeoutMs)
that caused custom timing values to be lost on server restart
- Extract restoreRespawnController() helper to dedupe session restoration
logic between state.json and screens.json paths
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When /respawn/stop was called, the controller was stopped but remained
in the respawnControllers map. This caused persistSessionState() to
still read config.enabled=true and save respawnEnabled=true to state.json.
On server restart, the respawn controller would be re-enabled because
state.json had respawnEnabled=true.
Fix: Remove controller from map and clear any timed respawn when
/respawn/stop is called, so persistSessionState() correctly sets
respawnEnabled=false.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add ai-plan-checker.ts to CLAUDE.md Key Files table
- Document test utilities (MockSession, MockAiIdleChecker, MockAiPlanChecker)
- Update port allocation (3127 reserved for respawn-integration)
- Add ai_checking state to respawn state diagram
- Document AI Plan Checker in respawn-state-machine.md
- Add references to test documentation files
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The ai-plan-checker.ts was passing the prompt directly as a shell argument,
which can cause E2BIG errors when the terminal buffer is large (8KB+).
This fix applies the same temp file approach already used in ai-idle-checker.ts:
- Write prompt to a temp file instead of passing as shell argument
- Pipe the file to claude via stdin: `cat prompt.txt | claude -p ...`
- Clean up prompt file after check completes
Also fixes a race condition in the cancel() method of both AI checkers where
the poll timer could fire between setting checkCancelled and clearing timers.
Now timers are cleared before resolving the promise to prevent this race.
Includes test utilities and analysis documents for the respawn controller
created by other agents:
- test/respawn-test-utils.ts - MockSession, MockAiIdleChecker utilities
- test/respawn-analysis.md - Code analysis and issue identification
- test/respawn-scenarios.md - Test scenario documentation
- test/respawn-test-plan.md - Testing architecture documentation
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- persistSessionState() now saves respawnEnabled based on config.enabled
(user intent) instead of controller.state (running state)
- cleanupSession() saves respawn config BEFORE removing controller
- AiIdleChecker and AiPlanChecker constructors filter undefined values
to prevent overwriting defaults (fixes "timed out after undefinedms")
- updateConfig() methods also filter undefined values
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When respawn config objects had explicit undefined values for fields like
aiIdleCheckTimeoutMs, the spread operator would overwrite defaults with
undefined, causing "AI check timed out after undefinedms" errors.
- Add default fallbacks when saving pre-config in server.ts
- Filter out undefined values before spreading in RespawnController
- Add tests verifying undefined filtering works correctly
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>
The AI idle checker was passing the prompt (including up to 16KB of terminal
buffer) as a command-line argument to bash -c, which exceeded the Linux
argument size limit causing "spawn E2BIG" errors.
Now writes the prompt to a temp file and pipes it to claude via stdin,
avoiding the argument size limit entirely. Temp file is cleaned up both
in the normal case (by the shell command) and on cancellation/timeout.
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>
- Add 100ms delay between text and carriage return to prevent race conditions
- Add retry logic (up to 3 attempts) for carriage return with increasing delays
- Trim trailing whitespace from text to avoid spurious spaces
- Better error logging for debugging input delivery issues
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- State label now white on green pill for better visibility
- AI check shows detailed status with color-coded badges:
- Blue: Analyzing terminal output
- Green: Idle confirmed
- Yellow: Working detected
- Gray: Disabled
- Shows time since last check when recent (<2min)
- Bump version to 0.1338
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Respawn banner changes:
- Human-friendly state labels (e.g., "Kickstarting..." vs "waiting_kickstart")
- Removed redundant "→ waiting for" text
- Simplified AI check display (only shows when actively checking)
- Shorter cycle counter (#1 vs "Cycle 1")
- Fixed NaN timer bug with validation
- Flatter HTML structure
CLAUDE.md improvements:
- Reorganized Commands section into clear subsections
- Test port allocation in table format
- Simplified TypeScript config section
- Removed duplicate keyboard shortcuts (already in README)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add version 0.1337 to project overview
- Add keyboard shortcuts section for web UI (Ctrl+Enter, Ctrl+W, etc.)
- Add teardown timeout (60s) and coverage excludes to test comments
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Display version number in center of bottom toolbar
- Load version from package.json via server's /api/status
- Version shown on initial load and SSE reconnect
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>
The header-system-stats had its own border-left in addition to the
header-right border-left, creating two vertical lines. Removed the
inner one for a cleaner look.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Reduce header-right gap from 1rem to 0.5rem and remove margin-left
from notification button for tighter grouping.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace gear emoji with SVG icon matching the bell, remove extra margin
between them, and ensure both sit at the same vertical position.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Condense CLAUDE.md by moving detailed state machine diagrams and spawn
protocol specs into docs/respawn-state-machine.md and docs/spawn-protocol.md.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use an inline SVG bell that inherits currentColor, matching the gray
monochrome style of the settings gear icon.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Moved the notifications section to the first position under "What Claudeman Does"
and renamed it to "Notification System" for better visibility.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Default KillMode=control-group kills all processes in the cgroup,
including spawned GNU screen sessions. KillMode=process only kills
the node server, allowing screens to survive restarts and be
reattached via reconcileScreens().
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
attachCustomWheelEventHandler doesn't exist in xterm.js 5.3.0,
causing initTerminal() to crash and abort all app initialization.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Claude's Ink UI enables terminal mouse reporting, causing xterm.js to
forward wheel events to the application. This made scrolling up to read
the plan impossible. Intercept wheel events to always scroll the terminal
viewport directly.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Split the session options modal into three tabs (Respawn, Context,
Ralph/Todo) to reduce vertical height. Removed redundant header and
border from the Respawn section. Also condensed CLAUDE.md and added
AI idle checker documentation.
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>
Document the PATH augmentation behavior in PTY spawn modes, data flow,
screen-aware sessions, and requirements sections. Clarify that claude
does not need to be in the server's PATH as it's auto-discovered.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The previous fix used absolute paths to spawn claude, but the CLI itself
checks if its directory is in PATH and warns if not. Instead, find where
claude is installed and prepend its directory to PATH in the spawn
environment. This ensures both execvp resolution and Claude's own PATH
check are satisfied.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When the web server runs in environments where `claude` isn't in PATH
(e.g., systemd services, non-login shells), node-pty's execvp(3) fails
with "No such file or directory". Fix by resolving the absolute path
to the claude binary using `which` with fallback to common installation
locations (~/.local/bin, /usr/local/bin, etc.). The resolved path is
cached for performance.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- CLAUDE.md: idle detection cancellation on substantial output, API input
limits table, configure() method on RalphTracker, tighter completion
pattern description
- ralph-wiggum-guide: add configure() to tracker methods table
- Both docs: update Last Updated date to 2026-01-24
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- ralph-tracker: add ✓ to native todo pattern + pre-check, add configure() method
- session: remove stale message expectation from interactive endpoint test
- buffer-management: fix trim count expectations (1202 items triggers second trim)
- cli-commands: replace non-existent toStartWith with toMatch regex
- edge-cases: update error expectation for session-not-found on respawn config PUT
- ralph-integration: respawn config PUT without controller now saves as pre-config
- session-state: fix debouncer shouldFlush(0) - pass timestamp >= delayMs
- timing-utilities: attach catch handlers before advancing fake timers
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- task.ts: Cache completion phrase regex in constructor instead of
re-creating on every checkCompletion() call. Add escapeRegex helper
for safe RegExp construction from user-provided phrases.
- ralph-tracker.ts: Remove commented-out COMPLETION_SIGNAL_PATTERN
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The hook commands now read stdin JSON from Claude Code (contains tool_name,
tool_input, etc.) and forward it as the data field to the API. This enables
richer notifications showing actual context (e.g., "Bash: docker push prod").
Previously the curl commands only sent event type and session ID, losing
all hook context data.
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 server was dropping the `data` field from hook-event POST requests,
so notifications always showed generic messages. Now forwards tool name,
command, question text, and reason to the frontend.
Notifications now show:
- permission_prompt: "Bash: docker push prod:latest"
- elicitation_dialog: "Merge PR #42 to main?"
- idle_prompt: custom message if provided
- stop: reason if provided
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add scripts/claudeman-web.service: respawning systemd user service
for `claudeman web --https` (Restart=always, RestartSec=5)
- Slow tab blink animations: red 1s→2.5s, yellow 1.5s→3.5s
with ease-in-out and reduced opacity for less aggressive feel
Install: symlink to ~/.config/systemd/user/, enable, start
Linger: loginctl enable-linger keeps it running after logout
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>