feat(maestro): infer session activity state + foreground (Active/Idle/AwaitingInput) (#18)
ci / rust (push) Failing after 2m15s

Add an orthogonal activity dimension to sessions, inferred entirely from
structured tmux/`/proc` state — no PTY byte-stream parsing, no work on the
attach hot path.

Protocol: `ActivityState` enum (Active/Idle/AwaitingInput) + three additive,
serde-defaulted `Session` fields (`foreground`, `activity`, `last_activity_at`)
so the snapshot/diff flow stays forward-compatible with older daemons.

Detection (piggybacks the existing ~2s liveness tick, no new timer):
- foreground command via `tmux list-panes -F '#{pane_pid} #{pane_current_command}
  #{pane_tty}'`;
- quiescence from a per-`PtyBridge` last-read `Instant`, bumped in `run_reader`;
- AwaitingInput via best-effort `/proc` walk to the deepest descendant: state
  `S` + a non-timer `wchan` + an stdio fd on the pane tty. (`/proc/pid/syscall`
  is ptrace-gated and unreadable for own sessions, so `wchan` distinguishes a
  blocking read from a plain `sleep`.)
- combine: recent output → Active; else input-blocked → AwaitingInput; else
  Idle. Emit `SessionUpdated` only on (activity, foreground) change — no diff
  storms at steady state.

`maestro list` gains an ACTIVITY column and shows the live foreground. Pure
combine/parse logic is unit-tested; an e2e asserts `cat` → AwaitingInput and
`sleep` → Idle with correct foreground against real tmux.

Closes #18
Closes #8

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-21 14:51:08 +00:00
co-authored by Claude Opus 4.8
parent c8bf240624
commit fd80ae152a
21 changed files with 580 additions and 9 deletions
+11
View File
@@ -6,6 +6,10 @@ export type IsoTimestamp = string;
export type SessionStatus = "Running" | "Dead";
/** Daemon-inferred activity dimension, orthogonal to `SessionStatus` (NAP-340).
* Absent on payloads from daemons that predate the field. */
export type ActivityState = "Active" | "Idle" | "AwaitingInput";
export interface Session {
id: Uuid;
daemon_id: string;
@@ -15,6 +19,13 @@ export interface Session {
metadata: Record<string, unknown>;
status: SessionStatus;
created_at: IsoTimestamp;
/** Current foreground command in the pane (e.g. `claude`, `bash`), as the
* daemon's activity watcher observed it. Absent until observed (NAP-340). */
foreground?: string | null;
/** Inferred activity. Defaults to `Idle` on the wire when omitted. */
activity?: ActivityState;
/** Wall-clock of the most recent observed PTY output (NAP-340). */
last_activity_at?: IsoTimestamp;
}
export interface DaemonInfo {