* fix: activity detection — fix path encoding, use tail -1 for JSONL
Two tightly coupled infrastructure fixes:
- Fix toClaudeProjectPath(): leading `/` becomes `-` (not stripped),
matching Claude Code's actual project directory naming convention.
- Replace manual 4KB buffer read in readLastJsonlEntry() with
`tail -1` + JSON.parse — handles any file size, any line length,
and eliminates the truncated-line edge case entirely.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add "ready" state, return null when unknown, remove dead code
Behavioral changes to activity detection:
- Add "ready" to ActivityState — separates "alive at prompt" from
"idle/stale". Configurable via readyThresholdMs (default 5 min).
- Agent plugins return null when they can't determine activity
(no workspace, no JSONL, no per-session tracking). Session manager
preserves existing activity instead of overwriting with a guess.
- Remove isProcessing() from Agent interface — zero callers in
production code, fully superseded by getActivityState().
- Remove extractLastMessageType() from claude-code — the field it
populated (lastMessageType) was only consumed by the old inline
CLI mapping, which is now replaced by plugin delegation.
- CLI status delegates to agent.getActivityState() (single source
of truth) with metadata fallback when plugin returns null.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* test: comprehensive activity detection coverage
- activity-detection.test.ts: 42+ tests covering path encoding,
getActivityState edge cases (exited/null/fallback), real Claude Code
JSONL types, agent interface spec types, staleness thresholds,
JSONL file selection, and realistic session sequences.
- status.test.ts: plugin delegation tests — verifies CLI uses
agent.getActivityState() as single source of truth, passes
readyThresholdMs from config, falls back to metadata on null/throw.
- Integration tests: updated type expectations for null returns from
codex, opencode, and aider; added "ready" to valid state lists.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: flaky Linear integration test + missing ready label in SessionDetail
Linear API has eventual consistency — updateIssue state changes don't
propagate instantly. Poll with retries instead of asserting immediately.
Also adds "ready" entry to SessionDetail activityLabel map (was missing,
causing fallback to dim/unstyled rendering).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: pure Node.js readLastJsonlEntry, use pollUntilEqual for Linear test
Replace `tail -1` with pure Node.js implementation that reads backwards
from end of file in 4KB chunks. No external binary dependency — works
on any platform.
Fix flaky Linear integration test by using the existing pollUntilEqual
helper instead of an inline retry loop. Linear API has eventual
consistency; pollUntilEqual retries for up to 5s with 500ms intervals.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: use tail -1 for readLastJsonlEntry, add real-data integration test
Replace over-engineered pure Node.js backward-reading implementation with
simple `tail -1` via execFile. The codebase already shells out to tmux,
git, and ps everywhere — tail is no different.
Add integration test that validates toClaudeProjectPath() and
readLastJsonlEntry() against real ~/.claude/projects/ data on disk.
No API key needed — just requires Claude to have been run once.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>