- Extract ensure_homebrew() called from all macOS install functions (prevents crash if Git checked before Node)
- Add dnf/yum fallback in Fedora install functions (fixes Amazon Linux 2 which only has yum)
- Add ensure_sudo to Alpine install functions (consistent with all other distros)
- Update Fedora/SUSE NodeSource setup to use GPG keyring method (replaces deprecated setup_XX.x script)
- Remove dist/ directory from PATH (only use ~/.local/bin symlink)
- Collapse identical fish/non-fish branches in setup_sc_alias
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- TaskTracker.getTaskTreeLight(): strips large `output` strings from tasks
in SSE broadcasts (was serializing 5-10MB every 500ms with many subagents)
- session:created broadcasts now use toLightDetailedState() (consistent with
session:updated which already did)
- GET /api/sessions/:id returns light state (no 2-3MB terminal+text buffers)
- Ralph wizard polls /terminal?tail=2048 instead of full session endpoint
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Local echo now sends every keystroke to the PTY in the background (50ms
debounce) while the overlay continues providing instant visual feedback.
This unlocks Tab completion, preserves PTY state across tab switches,
and protects against input loss on session crashes — making the mobile
typing experience feel as responsive and capable as a native terminal.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previously, when Claude exited inside tmux (exitCode=0 or crash), tmux
destroyed the entire session — losing buffer, history, and causing crash
loops on restart attempts. Now:
- Set remain-on-exit on for all tmux sessions
- Detect dead panes via #{pane_dead} instead of assuming session is gone
- Respawn dead panes with tmux respawn-pane -k (preserves session)
- Applied to both startInteractive and startShell paths
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previously, server.stop() called cleanupSession(killMux=false) for all sessions,
which still tore down session state, removed listeners, killed PTY processes via
node-pty SIGHUP, and broadcast session:deleted. This caused Claude sessions
running inside tmux to be disrupted during COM deploys.
Now server shutdown just persists state, removes listeners, and lets the Node.js
process exit naturally. The tmux sessions survive independently, and
restoreMuxSessions() finds them alive on restart.
Also adds defense-in-depth in session.stop(): when killMux=false, skip PTY kill
entirely (just null the reference). And adds 'detached' lifecycle event type for
accurate audit logging.
When Claude exits inside a tmux session, tmux destroys the session
(remain-on-exit is off), but the _muxSession reference persists.
On restart, startInteractive() treats it as a "restored session" and
tries to attach to the dead tmux — causing instant exit code 1.
Now checks tmux has-session before attaching. If the session is gone,
clears the stale reference and creates a fresh tmux session.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.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>
Highlights zero-latency typing as the headline mobile feature.
Adds comparison table entry and detailed feature breakdown.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
DOM overlay captures keystrokes locally and sends edited text + Enter as separate
events (matching Ink's sendCommand pattern). Block cursor matches Claude Code's
native cursor style. Enabled by default on mobile touch devices.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Move subagent dropdown to top (near badge) instead of bottom on mobile
- Fix iOS double-tap issue: wrap :hover styles in @media(hover:hover)
- Pin dropdown immediately on first tap (prevent mouseleave auto-close)
- Hide subagents panel by default on mobile (floating windows sufficient)
- Revert broken mobile auto-minimize (agents auto-pop up again)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
handleInit() called KeyboardHandler.cleanup() and MobileDetection.cleanup()
on every SSE connect but never re-initialized them, breaking keyboard
scroll-into-view and the /init /clear accessory bar on mobile.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>