Track last-focused per session in the daemon and ship it over the protocol #145

Closed
opened 2026-09-03 13:26:50 +01:00 by naps62-yolo · 1 comment
Collaborator

The command bar's empty query lists sessions most-recently-focused first, and
that ordering is the same in every client — so the daemon owns it, not each
client's local state.

  • Add a last-focused timestamp to the session type in maestro-protocol, and
    ship it in the /api/events snapshot and in session deltas like any other
    field.
  • Add POST /api/sessions/:id/focus for a client to report that the operator
    moved focus to that session.
  • Attaching implies focus — the daemon stamps it when a client opens
    /api/attach/:id. But the web's multiview can refocus an already-open pane
    without a new attach, and the TUI can move focus between panes the same way,
    so the explicit endpoint is what those paths call. Both cases have to end up
    with the same field updated.
  • A session that has never been focused sorts after every session that has.

Semantics are specified in docs/COMMAND-BAR.md under the empty-query
ordering — follow it rather than restating it here.

Non-goals: no client-side use of the field yet (the bars come later), no
persistence of the ordering across daemon restarts beyond whatever the daemon
already keeps for a session.

Depends on: #144


Scope correction (found while writing #144). POST /api/sessions/:id/focus
already exists — crates/maestro-daemon/src/local_api.rs:344, routed at line
50, added for docs/SIDEBAR.md's "focus clears AwaitingInput" rule. This issue
does not need a new endpoint. What it needs is the last-focused timestamp
field on the session type, a stamp in that existing handler, and a stamp on
/api/attach/:id.

The command bar's empty query lists sessions most-recently-focused first, and that ordering is the same in every client — so the daemon owns it, not each client's local state. - Add a last-focused timestamp to the session type in `maestro-protocol`, and ship it in the `/api/events` snapshot and in session deltas like any other field. - Add `POST /api/sessions/:id/focus` for a client to report that the operator moved focus to that session. - Attaching implies focus — the daemon stamps it when a client opens `/api/attach/:id`. But the web's multiview can refocus an already-open pane without a new attach, and the TUI can move focus between panes the same way, so the explicit endpoint is what those paths call. Both cases have to end up with the same field updated. - A session that has never been focused sorts after every session that has. Semantics are specified in `docs/COMMAND-BAR.md` under the empty-query ordering — follow it rather than restating it here. Non-goals: no client-side use of the field yet (the bars come later), no persistence of the ordering across daemon restarts beyond whatever the daemon already keeps for a session. Depends on: #144 --- **Scope correction (found while writing #144).** `POST /api/sessions/:id/focus` already exists — `crates/maestro-daemon/src/local_api.rs:344`, routed at line 50, added for `docs/SIDEBAR.md`'s "focus clears AwaitingInput" rule. This issue does **not** need a new endpoint. What it needs is the last-focused timestamp field on the session type, a stamp in that existing handler, and a stamp on `/api/attach/:id`.
naps62-yolo added this to the Command bar milestone 2026-09-03 13:26:50 +01:00
naps62-yolo added the area/daemondifficulty/mediumtype/feat labels 2026-09-03 13:26:50 +01:00
naps62-yolo added a new dependency 2026-09-03 13:26:52 +01:00
Author
Collaborator

Merged into blitz/command-bar. Full Rust suite re-run on the integration
branch: 734 passed, 0 failed.

#[serde(default)] with Option, matching how blocked_work and the other
late-added fields stay forward-compatible, and the legacy-payload test pins it.
Losing focus deliberately not clearing the stamp is the right call — the bar
sorts by where the operator last was, not by where they are.

One gap this left, fixed on the integration branch rather than bounced:
web/src/types.ts is a hand-kept mirror of the protocol crate, so it did not
learn about last_focused_at. #149 sorts by that field, so it would have hit
it immediately.

Merged into `blitz/command-bar`. Full Rust suite re-run on the integration branch: 734 passed, 0 failed. `#[serde(default)]` with `Option`, matching how `blocked_work` and the other late-added fields stay forward-compatible, and the legacy-payload test pins it. Losing focus deliberately not clearing the stamp is the right call — the bar sorts by where the operator last was, not by where they are. One gap this left, fixed on the integration branch rather than bounced: `web/src/types.ts` is a hand-kept mirror of the protocol crate, so it did not learn about `last_focused_at`. #149 sorts by that field, so it would have hit it immediately.
This repo is archived. You cannot comment on issues.
1 Participants
Due Date
No due date set.
Reference: naps62/maestro#145