Commit Graph
324 Commits
Author SHA1 Message Date
naps62 21fc20b30a Merge pull request 'docs(maestro): replace the sidebar's activity dot with a rail' (#130) from indicators into main
ci / web (push) Successful in 3m40s
ci / rust (push) Successful in 5m49s
ci / flake (push) Successful in 6m12s
Reviewed-on: #130
2026-09-02 17:00:58 +01:00
Miguel Palhas abbd15a8b2 feat(maestro): TUI sidebar activity rail
ci / web (pull_request) Successful in 1m20s
ci / rust (pull_request) Successful in 5m47s
ci / flake (pull_request) Successful in 9m14s
Leads the existing indent gutter on both the name row and the meta
row with a one-column block glyph in the state's palette role,
replacing the meta line's inline dot. Folder headers gain a matching
blank column so labels stay aligned under session names.
2026-09-02 16:47:51 +01:00
Miguel Palhas adbf57fc49 Merge remote-tracking branch 'origin/main' into colors
ci / web (push) Successful in 37s
ci / rust (push) Successful in 4m19s
ci / flake (push) Successful in 7m3s
# Conflicts:
#	web/src/catalog.ts
#	web/src/styles.css
2026-09-02 16:31:58 +01:00
Miguel PalhasandClaude Fable 5 bff0eddc12 feat(maestro): graphite TUI default + five accent presets
Replaces the army-green dark/light palettes with neutral graphite and
adds ice-cyan, periwinkle, amber-phosphor, ember and orchid presets.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-02 16:06:31 +01:00
Miguel Palhas 8cb6aeb61e Merge branch 'flugelhorn'
ci / rust (push) Successful in 5m20s
ci / web (push) Successful in 2m11s
ci / flake (push) Successful in 11m49s
2026-09-02 15:58:48 +01:00
Miguel Palhas 247060de68 feat(maestro): open the spawn form on the project picker
The picker now leads the form in both clients and takes focus on open, so
Tab walks from it into the command tiles. Opening the form also preselects
the project of the session you were last on — a worktree session seeds its
base repository — so 'n' then Enter spawns another session there.
2026-09-02 15:56:35 +01:00
Miguel PalhasandClaude Opus 5 29545d15fe feat(maestro): daemon status indicator and restart overlay in the TUI
ci / flake (push) Successful in 9m3s
ci / web (push) Successful in 1m22s
ci / rust (push) Successful in 4m25s
The status bar gains the TUI's half of the same contract the web client got:
a coloured dot plus the release the daemon is running, pinned right so a narrow
terminal truncates the key hints rather than the release.

`DaemonLink` mirrors web/src/daemonLink.ts — the events loop reports its
connects and disconnects, a probe task polls `GET /api/info` while the daemon
is unreachable, and past the grace window a modal covers the frame and locks
the keyboard (quit excepted) until it answers. A daemon that comes back on a
new commit cannot be reloaded into a running TUI binary, so the status bar says
`updated: <hash> (restart tui)` instead.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 15:52:44 +01:00
Miguel PalhasandClaude Opus 5 eaf60d9dac feat(maestro): stamp the daemon with its build commit
`GET /api/info` now carries `build` (commit hash, commit date, dirty flag)
and `instance`, a fresh uuid per daemon process. Together they let a client
name the release it is talking to and, after losing its socket, tell an
upgrade from a plain restart from a network blip.

The stamp comes from `maestro-daemon/build.rs`, which reads the git checkout
it compiles in. The Nix build has no `.git` in the crane-filtered source, so
`flake.nix` passes the flake's own revision and last-modified date through
`MAESTRO_BUILD_*` instead. Neither available leaves the fields empty.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 15:40:41 +01:00
Miguel PalhasandClaude Opus 5 f89be4a716 feat(maestro): spawn form back in a modal in the TUI
ci / web (push) Successful in 37s
ci / rust (push) Successful in 4m52s
ci / flake (push) Successful in 7m12s
`s` (OpenSpawnModal, was NewDraftPane) puts the form up as a centered
overlay instead of taking over the pane. The attached session stays
attached behind it and comes back untouched on Escape; the modal owns
every key while it is up, so `x` and `j` typed into a field no longer
reach the keymap.

Tab::pane is a session id again and PaneRef is gone. The form lives on
App next to the rename buffer, so its loads no longer address a tab
index that could not identify them.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 14:52:36 +01:00
Miguel PalhasandClaude Opus 5 28778b2224 feat(maestro): add maestro send for typing into a session
ci / web (push) Successful in 1m56s
ci / rust (push) Successful in 5m13s
ci / flake (push) Successful in 8m8s
Adds POST /api/sessions/:id/input and a CLI command on top of it, so a
script (or another agent) can hand an instruction to a running session
without attaching to it.

The text goes in as one write and the Enter follows 150ms later: agents
that run a full-screen prompt coalesce a burst of input into a paste, and
a newline inside that burst becomes a line break instead of sending the
message. `--no-enter` skips the Enter and leaves the text in the prompt.

The session argument takes an ID, a unique ID prefix, or a session name;
names win over prefixes. A session whose pane has exited is refused (409)
rather than silently accepted — unlike a stray keystroke on an attach
socket, a send that goes nowhere is worth hearing about.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-01 15:10:18 +01:00
Miguel Palhas 88b6bba9f2 feat(maestro): show only the program on session cards
ci / web (push) Successful in 34s
ci / rust (push) Successful in 3m56s
ci / flake (push) Successful in 7m8s
The command fragment named the full command line, so a session spawned
with `claude --dangerously-skip-permissions` spent the whole line on a
flag. Cards now name the program only — its icon in the web client, its
bare name in the TUI — and keep the full command line in the tooltip.

Adds `maestro_protocol::display::command_program`, the Rust counterpart
of the web's `splitCommand`.
2026-09-01 11:11:39 +01:00
Miguel PalhasandClaude Opus 5 c9cfdb5668 feat(maestro): one-word handles, quieter project boxes
Session handles are one word from a single 218-entry list — instruments,
forms, notation and theory, tempo and dynamics — replacing the
adjective-noun pair. A batch is shuffled, so it repeats only once the
wordlist runs out.

Project boxes show the parent directory instead of the full path: the
last segment is already the name line above it. The last command is gone
from the box, and picking a project no longer pre-selects it — the
directory and what runs in it are independent choices. Both changes land
in the TUI picker too, which mirrors the web form's rules.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-31 22:40:49 +01:00
Miguel Palhas eb9b4b4ae8 fix(maestro): replay pane mouse modes on attach
A full-screen app enables mouse reporting once, at startup. A client
attaching later never saw those sequences, so the web terminal read the
pane as a plain alternate screen with mouseTrackingMode "none" and its
touch and wheel gestures had nowhere to go — scrolling did nothing in a
browser opened after the session started.

Read the pane's mouse flags in the same display-message call and emit
the matching DECSETs ahead of the screen content. tmux expands an
unknown format name to the empty string, so the parser only trusts the
mouse tail when every field is present.

Closes #128
2026-08-31 22:07:22 +01:00
Miguel Palhas 39e8239a7d Merge remote-tracking branch 'origin/main' into sostenuto-bassoon 2026-08-31 15:04:28 +01:00
Miguel Palhas 0421a153c2 fix(maestro): sidebar j/k skips expanded group headers
Group rows are not something to focus; the cards under them are one row
away. A collapsed group still stops the walk — its header is the only row
it has, so skipping it would leave the group unreachable.
2026-08-31 14:58:07 +01:00
Miguel Palhas 1589d58ca0 feat(maestro): sidebar cards show diff stats and tool icons
Line 2 of a session card spelled out its blocked work ("1 uncommitted
file") and its command ("claude"). Both now render as marks: the
breakdown as diff notation, and the command's leading program as its
tool's icon in the web client.

The probe carries the line delta of the tracked changes — staged and
unstaged together, against HEAD — so `git add` never makes the counter
drop. Untracked files stay a file count; counting their lines means
reading every one off disk. A tracked change with no line delta falls
back to `~N` rather than claiming `+0 -0`.

The TUI keeps its command as text: a terminal cannot be assumed to have
a font carrying tool glyphs.
2026-08-31 14:54:54 +01:00
Miguel PalhasandClaude Opus 5 0388f06404 fix(maestro): keep pane background in the attach snapshot
capture-pane trims trailing spaces, so a line's background stopped at its
last glyph and the client's own background showed through the rest as
stripes. -N keeps the padding, and with it the colour.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-31 09:43:21 +01:00
Miguel PalhasandClaude Opus 5 c98c11b5c3 fix(maestro): replay tmux's screen to fresh attaches
A new attach replayed the tail of the raw byte buffer. That tail starts
mid-stream, long after a full-screen program set the modes, colours and
cursor position that give those bytes meaning, so a browser refresh
painted garbage over every agent TUI until something forced a repaint —
which is why opening the same session in the TUI (a resize) fixed it.

Ask tmux for the pane's current screen instead, and fall back to the byte
buffer when there is no pane left to capture, as for a dead session.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-31 09:37:13 +01:00
Miguel Palhas 8110512d5b Merge remote-tracking branch 'origin/main' into brillante-fugue
ci / web (push) Successful in 32s
ci / rust (push) Successful in 2m59s
ci / flake (push) Successful in 5m49s
2026-08-31 09:03:34 +01:00
Miguel PalhasandClaude Opus 5 d39fbdbbfc feat(maestro): drop retained worktrees and header debug toggle
Removes the retained-worktree store end to end: the daemon's state-dir
store, GET/DELETE /api/worktrees, `maestro worktrees list|reclaim`, the
TUI overlay behind `w`, and the web `#/worktrees` view and header link.

The kill guard stays. A forced kill and a dirty natural exit now leave
the worktree on disk untouched instead of parking it in a store, so
removing one is an ordinary `git worktree remove`. A pristine tree is
still removed on exit. DELETE /api/sessions/:id always answers 204.

The header's debug button also goes; Ctrl+Shift+D and `?hud` still
toggle the HUD.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-31 09:00:52 +01:00
Miguel PalhasandClaude Opus 5 d032036542 feat(maestro): move worktree choice behind advanced options
ci / flake (push) Successful in 5m12s
ci / rust (push) Successful in 2m41s
ci / web (push) Successful in 35s
The worktree step ("+ new" plus the repository's existing worktrees) now
lives inside the collapsed "Advanced options" section in both the web form
and the TUI draft pane, so a plain spawn is command, project, name.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-31 08:42:00 +01:00
Miguel PalhasandClaude Opus 5 bdeec6eff5 feat(maestro): rename the highlighted session from the TUI sidebar
`r` opens a prompt pre-filled with the session's own name — empty when it
has none, so Enter cannot pin the command as the name. Enter saves, Escape
cancels, and an emptied field clears the name.

Refs #125

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-30 11:29:05 +01:00
Miguel PalhasandClaude Opus 5 345650172b feat(maestro): rename a session over PATCH /api/sessions/:id
The daemon trims and caps the name, persists it to the sidecar under the
sessions lock, and broadcasts SessionUpdated. A blank name clears
metadata.name so the card falls back to the command, matching the rule the
spawn form already uses.

Refs #125

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-30 11:26:12 +01:00
Miguel Palhas 999dbe3ea3 Merge remote-tracking branch 'origin/main' into themes
ci / web (push) Successful in 1m27s
ci / rust (push) Successful in 5m4s
ci / flake (push) Successful in 6m57s
2026-08-25 18:46:35 +01:00
Miguel Palhas c9d089534b enable session scrolling across clients
ci / web (push) Successful in 59s
ci / rust (push) Successful in 6m8s
ci / flake (push) Successful in 9m52s
2026-08-25 18:46:26 +01:00
Miguel PalhasandClaude Fable 5 573a2b4a07 feat(maestro): add nine editor-theme TUI palettes
Solarized (dark/light), Catppuccin Mocha, GitHub (dark/light),
Tokyo Night, Gruvbox, Nord, Dracula. Colours auto-tuned from the
canonical seeds to clear the palette contrast floors; tests now
assert every RGB preset, not just dark/light.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 18:44:12 +01:00
Miguel Palhas 9ef3547a00 refine TUI navigation and chrome
ci / web (push) Successful in 30s
ci / rust (push) Successful in 4m41s
ci / flake (push) Successful in 7m13s
2026-08-25 15:10:47 +01:00
Miguel Palhas 2ab07c2343 fix(maestro): harden grouped sidebar interactions
ci / web (push) Successful in 1m29s
ci / rust (push) Successful in 5m25s
ci / flake (push) Successful in 7m56s
2026-08-25 13:59:38 +01:00
Miguel Palhas 3205270b51 feat(maestro): group TUI sidebar by project 2026-08-25 13:53:51 +01:00
Miguel Palhas d8e31f2760 fix(maestro): resize PTY to bordered pane content 2026-08-25 13:37:30 +01:00
Miguel Palhas fdf9ea1b31 merge: TUI shell/123 — unmistakable panel focus 2026-08-25 13:31:24 +01:00
Miguel Palhas 8157793282 feat(maestro): add TUI theme presets 2026-08-25 13:30:59 +01:00
Miguel Palhas 839dd27925 feat(maestro): make TUI panel focus unmistakable 2026-08-25 13:26:54 +01:00
Miguel Palhas a1816a0838 fix(maestro): preserve fixed card trailing fragments 2026-08-25 13:18:24 +01:00
Miguel Palhas cc9b027bd1 feat(maestro): make TUI session cards two lines 2026-08-25 13:11:06 +01:00
Miguel Palhas 4c3f65027d fix(maestro): make TUI chrome contrast palette-controlled 2026-08-25 13:02:48 +01:00
Miguel Palhas 76eb3d1386 merge: TUI shell/119 — bare maestro opens the TUI 2026-08-25 12:55:25 +01:00
Miguel Palhas 877f409194 merge: TUI shell/117 — shared path-abbreviation helpers 2026-08-25 12:55:25 +01:00
Miguel Palhas 8e251bf8be feat(maestro): default a missing subcommand to the TUI 2026-08-25 12:34:36 +01:00
Miguel Palhas bc95d16a98 docs(maestro): note PTY colours are passthrough, not palette roles 2026-08-25 12:31:46 +01:00
Miguel Palhas 975f3ef0c5 feat(maestro): move path-abbreviation helpers into maestro-protocol
Port abbreviateCwd, abbreviateFolderName, mergeLinear, and
sessionTreePath from web/src/{types,tree}.ts into a maestro-protocol
display module, so the TUI sidebar can group sessions with the same
labels the web UI uses (#117). abbreviate_folder_name returns the
collapsed stem and last segment separately instead of escaped HTML,
so a ratatui caller can style the stem without parsing markup.

maestro-cli's own abbreviate_dir moves into the new module; the CLI
and the worktrees list now call the shared implementation.

Closes #117
2026-08-25 12:31:43 +01:00
Miguel Palhas c534cee7cc feat(maestro): palette of named colour roles for the TUI
Every colour the TUI painted on its own chrome was a named ratatui
colour spelled out at the use site, so nothing could be themed and the
selected card had broken contrast: the highlighted card's black-on-cyan
base was patched with an activity colour chosen for the dark card
background, leaving AwaitingInput yellow on light blue.

Roles now live in `palette.rs`, named for meaning. A palette holds one
role set per surface — card and selection — plus the panel border in
its focused and unfocused forms, a focus accent, a group-row style for
the sidebar grouping, the status-bar mode indicators and error text.
Each surface carries its own activity colours, so the selected card's
dot keeps carrying state without wearing a colour picked for another
background.

Values are `Color::Rgb`, so contrast is asserted rather than left to
the terminal theme: every role clears WCAG AA on its own surface, and a
sidebar test fails if a card-surface state colour is painted onto the
selection background.

PTY cell colours stay a passthrough of what the program in the pane
emits — they are not chrome and not a palette role.
2026-08-25 12:31:14 +01:00
Miguel Palhas bbafff5a98 fix(maestro): add settle-finished observable for natural-exit test
The no-retained-store test asserts a negative — the tree survives — so
waiting on that negative proves nothing: settle could still remove the
tree one instant after the assertion passes. mark_session_dead now flips
a per-record settled flag once the exit rule has been applied or refused,
exposed as SessionManager::is_settled; the test waits on it before
asserting.

Refs #115
2026-08-24 23:12:46 +01:00
Miguel Palhas 17e1dc4049 merge: sidebar-cards/114-hook-error 2026-08-24 23:01:14 +01:00
Miguel Palhas 6471da2624 feat(maestro): report StopFailure as Error with the error spelling as detail 2026-08-24 22:54:21 +01:00
Miguel Palhas 2a43c76176 feat(maestro): report Active while a long tool call is still running 2026-08-24 22:52:51 +01:00
Miguel Palhas f689c916bf fix(maestro): poll awaiting-input until leaderless state holds
The pipeline leader exits as soon as both stages are forked, which can
beat the surviving stage opening the tty and parking on read — the one-
shot assertion then ran against a group with no parked member yet.
Poll for the answer, accepting it only while the foreground group is
still leaderless so a shell that regained the tty cannot satisfy it.

Fixes #113
2026-08-24 22:50:02 +01:00
Miguel Palhas 88233cb96d fix(maestro): sync watcher re-emit test to real event flow
Two races. First, the watcher updates the snapshot and emits
SessionUpdated as two steps, so the drain could run between them: the
legitimate breakdown emission then arrived inside the quiet window.
Subscribe before the watcher starts and consume through the breakdown
event so the window begins after the last real change.

Second, the assertion treated any SessionUpdated as a failed
suppression, but the activity pass may legitimately announce an
Active→Idle transition in that window (ACTIVE_WINDOW is 3s), carrying
today's blocked_work unchanged. Only a changed indicator counts as a
re-emit now.

Fixes #113
2026-08-24 22:50:02 +01:00
Miguel Palhas efbccb4e11 fix(maestro): wait for settle in pristine natural-exit test
Dead status is observable a moment before the settle step removes the
worktree, so the assertions raced the removal under parallel load. Wait
for the tree to be gone and the store to stay empty, same as the
retained-store wait cfebfd4 added to the guarded sibling.

Fixes #113
2026-08-24 22:41:54 +01:00
Miguel Palhas 41c498401b merge: sidebar-cards/112-detail-render 2026-08-24 22:30:49 +01:00