- vmux setup: idempotently adds hooks to ~/.claude/settings.json
- vmux hook: receives Claude Code hook events via env vars and forwards to daemon
- Daemon handles "hook" action on Unix socket (no HTTP server needed)
- Hooks provide instant state detection (permission/question/idle)
- Notifier + FocusTimer fields in Daemon, initialized in NewDaemon
- processHookEvent notifies on Working -> Needs Input only (D-01)
- Focus mode suppresses notifications when active (D-05)
- FocusArgs in protocol, "focus" handler in daemon
- CLI "vmux focus <minutes>" command
- Tests for all notification transitions and focus handler
- Add hookPort, httpServer, lastHookTime, mu to Daemon struct
- startHookServer binds HTTP on hookPort, degrades if port busy
- Stop() closes httpServer before unix listener
- pollLoop uses time.After(currentPollInterval()) instead of fixed ticker
- currentPollInterval returns 20s when hooks active (<60s), 5s otherwise
- processHookEvent records lastHookTime on each hook event
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When Claude requests a tool permission approval, the last JSONL entry is
type=assistant with stop_reason=tool_use. Previously this was always
classified as Working. Now, if the tool_use entry is older than 10s with
no new activity, it's classified as NeedsInput.
Also fix vmux label to accept fuzzy match queries (not just session UUIDs).