Commit graph

6 commits

Author SHA1 Message Date
jedarden
114dc5bf35 feat(tmux-detector): implement automatic poller with @tb- prefix opt-in
Implements the tmux detector poller module based on the design in
docs/notes/tmux-detector-design.md.

Features:
- Auto-discovers opted-in panes via @tb- prefix in window title
- Polls every 2s (configurable via TRAILBOSS_POLL_INTERVAL_MS)
- Detects stuck sessions: quiet for 30s with prompt-like last line
- Detects unstuck: any output change after being stuck
- Emits normalized events to /event/normalized endpoint
- Synthetic session IDs: tmux-%446-{timestamp}
- Graceful shutdown with SIGINT/SIGTERM handling

Configuration:
- TRAILBOSS_POLL_INTERVAL_MS (default: 2000)
- TRAILBOSS_QUIET_THRESHOLD_MS (default: 30000)
- TRAILBOSS_OPT_IN_PREFIX (default: @tb-)
- TRAILBOSS_DAEMON_URL (default: http://127.0.0.1:4000/event/normalized)

Usage: bun run daemon/tmux-detector.ts

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-02 09:47:31 -04:00
jedarden
116464fe30 feat(security): tighten ingest trust boundary and add invariant tests
- Remove CORS headers and OPTIONS preflight from daemon
- CORS was enabling cross-origin browser POSTs to loopback endpoint
- No legitimate consumer is a browser (emitter uses curl, TUI uses Go http)

Add invariant test script test-invariants.sh:
- Daemon listens on 127.0.0.1 only (loopback-only binding)
- No synthesized input: verify no tmux send-keys in daemon sources
- OPTIONS preflight is no longer honored (returns 404)

Validates trust boundary specified in docs/plan/plan.md section
'Failure modes & invariants'.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-02 09:03:55 -04:00
jedarden
59096c49d6 feat(reconcile): implement stuck-direction reconcile for dropped Stop events
- Add reconcileStuckDirection() to scan transcripts and recover sessions that became stuck while daemon was down
- Add paneExists() to verify tmux pane still exists before enqueuing
- Add detectStuckFromTranscriptTail() to detect stuck state from transcript tail
- Add getSessionsNotInQueue() to DB layer for finding non-queued sessions
- Call reconcileStuckDirection() on daemon startup to recover dropped events
- Remove duplicate AS-4 test code

Acceptance criteria:
- Extended test-walking-skeleton.sh AS-4 to full plan scenario (daemon restart with transcript tail scan)
- All AS-1..AS-7 tests pass
- Session appears in /queue within one sweep after daemon restart

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-02 08:45:26 -04:00
jedarden
ac3c332cbd fix(reconcile): parse real Claude Code transcript format
- Parse ISO-8601 timestamps via Date.parse(), handle both strings and numbers
- Recognize real entry shape: type='user'|'assistant' with nested message.role
- Ignore non-message lines (attachments, queue-operations, etc.)
- Remove duplicate TranscriptEntry interface (import was not exported)
- Add AS-8 test validating real-format JSONL behavior
- Update fixtures to use real Claude Code format

Fixes tb-67q
2026-07-02 07:48:11 -04:00
jedarden
4e593de16d feat(trail-boss): phase 6 complete - all 7 acceptance scenarios passing
Walking skeleton test suite passes end-to-end:
- AS-1: Permission block enqueue/dequeue
- AS-2: FIFO ordering
- AS-3: Answered-in-pane reconcile
- AS-4: Dropped-event recovery
- AS-5: Skip + cooldown
- AS-6: No forced focus-steal
- AS-7: Pane reuse regression

Phase 6 exit criterion met (AS-1 through AS-6 pass).
Phase 6 complete (AS-7 also passes).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 12:55:37 -04:00
jedarden
fbaf1d86ab feat(trail-boss): commit phase 3 daemon code (previously untracked)
daemon/ (index.ts, types.ts, claude-adapter.ts, db.ts, reconcile.ts, schema.sql),
package.json, and test scripts were implemented but never staged. Phase 3 exit
criteria verified per PROGRESS.md.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 22:57:51 -04:00