949 Commits
Author SHA1 Message Date
Miguel Palhas b27dda6c6b Merge remote-tracking branch 'origin/main' into chorale
ci / web (push) Successful in 37s
ci / flake (push) Successful in 3m58s
ci / rust (push) Successful in 7m14s
2026-09-17 11:18:49 +01:00
Miguel PalhasandClaude Opus 4.6 5bdedc8d23 feat(maestro): add elicitation web UI and TUI stub
ElicitationView renders form-mode questions from the agent:
single-property string enums as a button group (the common
multiple-choice case), general schemas as a form with typed
inputs.

Wired into TranscriptRow, StructuredPane, and the model
helpers. TUI renders elicitation rows as plain text for now.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-17 08:32:11 +01:00
Miguel PalhasandClaude Opus 4.6 1e628789fb feat(maestro): add ACP elicitation support (backend)
Advertise `elicitation.form` in the ACP handshake and handle
`elicitation/create` requests end-to-end through the daemon.

Adds `Elicitation` transcript row kind, `pending_elicitation` to
ReducedState, the elicitation pump, persistence, and a new
`POST /api/sessions/:id/structured/elicitations/:nonce` endpoint.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-17 08:22:37 +01:00
Miguel Palhas 3f2473d910 feat(maestro): hide tab bar on mobile, add sidebar button to pane header
ci / web (push) Successful in 38s
ci / flake (push) Successful in 4m2s
ci / rust (push) Successful in 7m23s
On mobile only one session is focused at a time, so the tab bar is
redundant — the sidebar drawer is the canonical way to switch. A ☰
button in the pane header gives tap access without requiring a swipe.

Closes #273
2026-09-17 08:06:44 +01:00
Miguel PalhasandClaude Opus 4.6 b56a35f3ee fix(maestro): simplify tool-group test to match actual grouping
ci / web (push) Successful in 34s
ci / flake (push) Successful in 3m44s
ci / rust (push) Successful in 7m3s
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-15 11:23:28 +01:00
Miguel Palhas b1f6014a6a Merge remote-tracking branch 'origin/main' into tritone-2
ci / web (push) Failing after 6s
ci / flake (push) Successful in 4m3s
ci / rust (push) Successful in 7m55s
2026-09-14 11:07:43 +01:00
Miguel PalhasandClaude Opus 4.6 01db6459cb fix(maestro): block event pump until turn is settled
The adapter returns the session/prompt response before the agent
finishes working.  Late-arriving notifications raced past the turn
marker and leaked into the next turn, making each response appear
one prompt behind.

The event pump now sends a settled oneshot through the done payload
and awaits it before processing further messages.
finish_queued_acp_turn fires it after persisting the turn marker and
dispatching any queued prompt.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-13 12:22:59 +01:00
Miguel PalhasandClaude Opus 4.6 d332c43a9f fix(maestro): handle 202 as no-body response in jsonOrError
ci / web (push) Failing after 26s
ci / flake (push) Successful in 4m8s
ci / rust (push) Successful in 7m57s
The daemon returns 202 Accepted when a structured prompt is queued.
jsonOrError only skipped res.json() for 204, so the empty 202 body
caused a JSON parse error.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-13 12:13:35 +01:00
Miguel Palhas 1cc05af323 feat(maestro): add just apk recipe for the Android debug build
ci / web (push) Failing after 32s
ci / flake (push) Successful in 4m30s
ci / rust (push) Successful in 8m7s
Runs ./gradlew assembleDebug and copies app-debug.apk next to the
android/ project root.
2026-09-13 02:43:07 +01:00
Miguel Palhas 6eb048575c feat(maestro): match adaptive icon to web PWA mark
Replaces the default Android Studio placeholder icon with the same
concentric-circle mark as web/public/icon.svg, scaled into the
existing 108x108 adaptive-icon vectors.
2026-09-13 02:43:04 +01:00
Miguel Palhas 5cdc6135f5 feat(maestro): match activity rail blink/flash to web timings
Replaces the tween/Reverse pulse with keyframe animations mirroring
web/src/components/sidebar/sidebar.css exactly: a hard 1200ms on/off
blink for AwaitingInput (steps(1), no crossfade) and a 1400ms
ease-out double-flash for Error.
2026-09-13 02:43:00 +01:00
Miguel Palhas f6be34ae48 feat(maestro): bundle JetBrains Mono and match web's type scale
Bundles JetBrainsMono Regular/Medium/Bold (SIL OFL, see
android/licenses/) so terminal and code content render the same face
as the web SPA's --font-mono instead of falling back to the device's
system mono. Typography now steps through the same sizes as the web
--fs-* tokens, using the platform sans for UI chrome.
2026-09-13 02:42:55 +01:00
Miguel Palhas 4f06d1fc8f feat(maestro): translate web OKLCH tokens to Material 3 color scheme
Maps bg/surface/ink/muted/faint/accent/live/danger/warn from
web/src/styles.css to background/surface/onSurface/onSurfaceVariant/
outline/primary/tertiary/error/secondary, for both dark (default) and
light Material 3 schemes. Drops the redundant statusBarColor override
in themes.xml now that MainActivity's enableEdgeToEdge() owns it.
2026-09-13 02:42:51 +01:00
Miguel Palhas d1b8b0abc1 feat(maestro): add Android command bar (#270)
Bottom-sheet ctrl-k-style search over sessions, a `>` command
registry and `~` directories (docs/COMMAND-BAR.md), with a
long-press action menu for rename/kill/spawn-similar. v1 uses a
simple weighted substring/fuzzy matcher rather than the scored
matcher web/#146 and the TUI/#147 share. Wires an FAB and a
best-effort hardware Ctrl-K into MaestroApp.
2026-09-13 02:20:46 +01:00
Miguel PalhasandClaude Opus 4.6 d8030b59f9 feat(maestro): add app shell with navigation (#268)
MaestroApp root composable with ModalNavigationDrawer,
NavHost (Welcome/Terminal/Structured routes), WelcomeScreen,
connection status, back press handling, spawn form integration.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-13 01:58:44 +01:00
Miguel PalhasandClaude Opus 4.6 0ab4ac3e4b feat(maestro): add structured session pane (#267)
Transcript view for ACP structured sessions (Claude Code, Codex).
Renders all 8 row kinds, collapsible tool groups, approval cards,
composer with send/cancel, turn state strip.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-13 01:47:16 +01:00
Miguel Palhas c90bdfbe42 feat(maestro): open terminal pane from a tapped sidebar session
Tapping a session in the sidebar now opens TerminalScreen full-screen
instead of just closing the drawer. windowSoftInputMode=adjustResize
lets WindowInsets.isImeVisible drive the key bar's visibility.
2026-09-13 01:07:32 +01:00
Miguel Palhas 27b6e647c1 feat(maestro): add Android terminal pane composable
TerminalWebView wraps a WebView around the bundled xterm.js page, with
a JS bridge (maestroKey/maestroToggleMod/maestroFocus) the native key
bar drives; onModifierConsumed reports back when the page's own JS
folds an armed Ctrl/Alt into a soft-keyboard keystroke, so the native
toggle stays in sync. TerminalScreen composes the WebView with the key
bar, showing the bar only while WindowInsets.isImeVisible.
2026-09-13 01:07:23 +01:00
Miguel Palhas 0631e69ef0 feat(maestro): add Android terminal extra key bar composable
Termux-style row for the soft keyboard (issue #266): Tab, Esc, one-shot
Ctrl/Alt modifiers, and the four cursor arrows, scrollable horizontally
for narrow screens.
2026-09-13 01:07:15 +01:00
Miguel Palhas f98c637cd9 feat(maestro): add Android terminal attach URL builder
TerminalPageUrl builds the file:///android_asset/terminal/index.html
URL for one session, with the WS /api/attach/:id URL Routes already
knows how to build passed through as an encoded query param.
2026-09-13 01:07:07 +01:00
Miguel Palhas 554182d956 feat(maestro): bundle xterm.js terminal page for Android WebView pane
Vendors @xterm/xterm 5.5.0 and @xterm/addon-fit 0.10.0 as static assets
plus a small HTML/JS page that owns the WS /api/attach/:id connection
directly, the same shape as the web SPA's TerminalPane.tsx. Bundled
locally so the pane only needs LAN reachability to the daemon, not
internet access to a CDN.
2026-09-13 01:06:59 +01:00
Miguel Palhas 391efc72d2 feat(maestro): add SpawnSheet bottom sheet composable (#269)
Preset chip row, searchable project list, debounced directory
autocomplete, and a branch/worktree picker matching the web spawn
modal, wired to SpawnViewModel and a self-contained snackbar for
submit errors.
2026-09-13 00:54:02 +01:00
Miguel Palhas cf582be306 feat(maestro): add spawn form model and view model (#269)
Pure request-building logic ported from web/src/components/spawn/model.ts,
plus a testable SpawnViewModel wiring presets, projects, debounced dir
autocomplete, branch loading, and session creation to MaestroClient.
2026-09-13 00:49:55 +01:00
Miguel Palhas 3403224dec feat(maestro): wire sidebar drawer into MainActivity
ModalNavigationDrawer opened by a hamburger button in the top bar,
holding SidebarContent bound to the app's DaemonLink.catalog.
2026-09-13 00:39:15 +01:00
Miguel Palhas a9c3cfe6d0 feat(maestro): add sidebar composables (#265)
ActivityRail (coloured gutter bar, blink on AwaitingInput, flash on
Error), SessionCard (two-line card with a long-press context menu for
rename/kill/spawn-similar), FolderNode (collapsible repo group), and
SidebarContent assembling the drawer's session list from the
CatalogStore built in #264.
2026-09-13 00:39:13 +01:00
Miguel Palhas 3ef1decbdd feat(maestro): add sidebar session formatting helpers
Pure Kotlin ports of the web/TUI SIDEBAR.md logic for the Android
sidebar: duration floor-format, program-name extraction (env/sudo/env
wrappers, npx/pnpm/yarn dlx, path), diff-stat notation, and
name/name_source/provisional-name reads. Covered by unit tests so they
run without an Android SDK.
2026-09-13 00:39:09 +01:00
Miguel Palhas b22539bd5b feat(maestro): wire DaemonLink into MainActivity, allow cleartext traffic
Reads the EXTRA_DAEMON_URL intent extra, starts DaemonLink, and shows its
LinkState in the placeholder screen so the connection indicator has
something to bind to. usesCleartextTraffic is required for the daemon's
plain-HTTP LAN endpoint; ACCESS_NETWORK_STATE is required for
ConnectivityManager.registerNetworkCallback.
2026-09-13 00:24:41 +01:00
Miguel Palhas 8f0d73d89c feat(maestro): add Android daemon connection state machine
Ports the DaemonLink state machine from web/src/components/daemon/DaemonLink.tsx
and crates/maestro-tui/src/daemon_link.rs to Android: LinkState (Connecting,
Online, Reconnecting, Down, Updating), build-stamp identity comparison, a
session catalog folded from the events WebSocket, and exponential backoff
(500ms-10s) in place of the flat poll the LAN clients use, since a phone's
network changes are bigger and longer-lived than a wifi blip.

DaemonLink reacts to ProcessLifecycleOwner (foreground resume) and
ConnectivityManager (network change) to re-probe and reconnect. DaemonPrefs
persists the daemon base URL via SharedPreferences and exposes an intent
extra key for overriding it at launch.
2026-09-13 00:24:36 +01:00
Miguel Palhas c3e2faa7ee feat(maestro): add Android REST and WebSocket API clients
MaestroClient covers the daemon's REST surface: sessions CRUD, rename,
kill (with force), focus reporting, dirs/recent-dirs/projects/gitroot/
names/branches lookups, and the structured-session endpoints (prompt,
attachment upload, cancel, config, approval).

MaestroWebSocket covers all three WS connections — /api/events
(catalog deltas), /api/attach/:id (binary PTY frames both directions
plus ClientControl text frames for resize/ping), and
/api/structured/:id (transcript/state projections) — each exposing a
Flow of decoded events behind a connection handle.

Adds kotlinx-coroutines-android explicitly rather than relying on it
being pulled in transitively via lifecycle-runtime-ktx.

Compiled and exercised standalone against the same library versions
(no Android SDK available in this environment to run the app module
itself) to verify wire-format handling before landing.
2026-09-13 00:07:30 +01:00
Miguel Palhas 6ccd79baa0 feat(maestro): add Android wire-format data types
Kotlin data classes mirroring maestro-protocol's wire types (Session,
CatalogEvent, ClientControl, structured-session projections, etc.),
@Serializable with kotlinx-serialization. ActivityState and NameSource
carry custom lenient deserializers matching the Rust side's forward-
compat behavior: an unknown variant degrades to the neutral default
instead of failing the whole payload.

Verified against fixtures mirrored from maestro-protocol's own test
suite (tag placement, snake_case renames, legacy-payload defaults).
2026-09-13 00:07:19 +01:00
Miguel Palhas 4932cbf3b3 feat(maestro): scaffold Android project (Kotlin, Compose, Material 3)
Greenfield Gradle project under android/ — single-activity, Compose-only
UI, Kotlin DSL + version catalog throughout. MainActivity shows a
placeholder screen; no daemon connection yet (#262).

minSdk 26, targetSdk 34. OkHttp and kotlinx-serialization-json wired in
for the upcoming daemon client. Debug signing config uses a committed
debug.keystore so the APK installs without extra setup.
2026-09-12 23:46:55 +01:00
Miguel PalhasandClaude Opus 4.6 1ea463f6cf fix(maestro): collapse mobile drawer after spawning a session
ci / web (push) Failing after 28s
ci / flake (push) Successful in 4m6s
ci / rust (push) Successful in 7m37s
mountSpawned now fires a CLOSE_DRAWER_EVENT so the sidebar gets out of
the way once the new session lands. Covers fast-forward, modal, and
command-bar spawn paths.

Closes #261

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-12 23:31:52 +01:00
Miguel PalhasandClaude Opus 4.6 7c27a897ac feat(maestro): optimistic session kill in sidebar
ci / web (push) Failing after 6s
ci / flake (push) Successful in 4m13s
ci / rust (push) Successful in 7m25s
Close the kill dialog and remove the session card immediately on
confirm instead of waiting for the DELETE round-trip. Restores the
session if the daemon refuses with kill_guarded and re-opens the
dialog in force mode.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-12 21:21:36 +01:00
Miguel Palhas a9717d01c8 Merge remote-tracking branch 'origin/main' into animato-2
ci / web (push) Failing after 27s
ci / flake (push) Successful in 4m15s
ci / rust (push) Successful in 7m30s
2026-09-12 20:50:52 +01:00
Miguel PalhasandClaude Opus 4.6 35a6ff9d0f fix(maestro): force-replace pane sockets on mobile resume
Mobile browsers report readyState === OPEN after background suspension
even though the OS killed the TCP connection. The per-pane visibility
handlers skipped reconnection in that case, leaving the pane frozen
until TCP keepalive fired (30–120 s on cellular).

Remove the readyState guard and unconditionally replace the socket on
visibility return — same pattern the events socket already uses. Also
let pageshow/online fire recovery without the visibilityState gate,
since some mobile browsers fire pageshow before updating that property.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-12 20:50:48 +01:00
Miguel PalhasandClaude Opus 4.6 474000935a fix(maestro): box AcpUpdate::Notification and fix test unwrapping
ci / web (push) Failing after 33s
ci / flake (push) Successful in 4m42s
ci / rust (pull_request) Failing after 8s
ci / web (pull_request) Failing after 32s
ci / flake (pull_request) Successful in 1m13s
ci / rust (push) Successful in 8m25s
Box the Notification variant to satisfy clippy's large_enum_variant
lint, fix paren mismatches from the boxing pass, and update test
helpers to unwrap AcpUpdate before inspecting the notification.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-12 19:59:03 +01:00
Miguel PalhasandClaude Opus 4.6 5f8cc2a140 fix(maestro): drain notifications before signaling turn-done
The event pump now handles AcpUpdate::TurnDone markers that arrive
in the same FIFO as notifications.  It fires the done oneshot only
after persisting every preceding notification, so finish_queued_acp_turn
can no longer race ahead of the transcript.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-12 19:54:00 +01:00
Miguel PalhasandClaude Opus 4.6 432967fe64 feat(maestro): route turn-done through ACP updates channel
The prompt response callback now sends an AcpUpdate::TurnDone marker
through the same unbounded channel as notifications instead of
signaling the done oneshot directly.  Since notifications and the
prompt response both run in the ACP dispatch loop in wire order,
TurnDone lands after every notification chunk for the turn.

The event pump (next commit) will fire the done oneshot only after
persisting all preceding notifications, closing the race where
finish_queued_acp_turn ran before the transcript was complete.

Closes #259

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-12 19:53:18 +01:00
Miguel PalhasandClaude Opus 4.6 2512b8be42 fix(maestro): apply tool-arg truncation fix to styles.css duplicate
ci / web (push) Failing after 6s
ci / flake (push) Successful in 4m24s
ci / rust (push) Successful in 7m49s
The previous fix (e3556bd) added `flex: 1 1 0` to `.st-tool-arg` in
`structured.css`, but `styles.css` has a duplicate copy of the same
rules that was left stale. Because both load, the unfixed copy in
`styles.css` can override the fix and re-enable horizontal scroll.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-12 19:42:44 +01:00
Miguel PalhasandClaude Opus 4.6 e3556bd847 fix(maestro): truncate long commands in tool call header
ci / web (push) Failing after 30s
ci / flake (push) Successful in 4m5s
ci / rust (push) Successful in 7m30s
Same root cause as the tool-group-title fix — .st-tool-arg
defaulted to flex: 0 1 auto, so long commands pushed the row
past the container. Adding flex: 1 1 0 lets the ellipsis
truncation work.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-12 19:03:06 +01:00
Miguel Palhas ce0e4e6820 Merge remote-tracking branch 'origin/main' into mandolin
ci / web (push) Failing after 45s
ci / flake (push) Successful in 4m17s
ci / rust (push) Successful in 8m4s
# Conflicts:
#	crates/maestro-daemon/src/local_api.rs
#	crates/maestro-daemon/src/session.rs
2026-09-12 17:54:13 +01:00
Miguel Palhas fa3d6c82b2 Merge remote-tracking branch 'origin/main' into chord
ci / web (push) Failing after 26s
ci / flake (push) Successful in 4m6s
ci / rust (push) Successful in 7m29s
2026-09-12 14:10:59 +01:00
Miguel PalhasandClaude Opus 4.6 ebe25a1a55 feat(maestro): server-side prompt queue for structured sessions
Prompts sent while a turn is active are queued on the daemon instead of
in the browser's React state. The queue is persisted in the session
sidecar and drained as the next turn when the current one completes.

Fixes the bug where queued messages were delivered to the wrong session
when switching focus in the UI: the client-side queue captured the new
sessionId in its drain closure.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-12 14:10:55 +01:00
Miguel PalhasandClaude Opus 4.6 923911f631 feat(maestro): auto-continue ACP sessions after restart
After a graceful daemon restart, recovered structured sessions now
receive a synthetic continue prompt so the agent resumes without
manual intervention. The User row carries `"maestro": {"type":
"restart_continue"}` metadata for future UI differentiation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-12 11:30:36 +01:00
naps62-yolo 8cbe8510ac fix(maestro): truncate long commands in tool group header (#258)
ci / web (push) Failing after 56s
ci / flake (push) Successful in 5m2s
ci / rust (push) Successful in 9m34s
2026-09-12 11:08:04 +01:00
Miguel Palhas cd5bbcfcb1 Merge remote-tracking branch 'origin/main' into timbre-2
ci / web (push) Failing after 1m7s
ci / flake (push) Successful in 3m55s
ci / rust (push) Has been cancelled
2026-09-12 10:59:49 +01:00
Miguel PalhasandClaude Opus 4.6 cbbf526fc4 fix(maestro): persist auto_approve across daemon restarts
Structured sessions spawned with auto_approve lost the flag on daemon
restart because it lived only in the in-memory SessionRecord. Add it to
the Session struct (sidecar JSON) so recovery reads it back instead of
hardcoding false.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-12 10:59:44 +01:00
Miguel Palhas 9f5b71d563 Merge remote-tracking branch 'origin/main' into aeolian
ci / web (push) Failing after 29s
ci / rust (push) Failing after 51s
ci / flake (push) Successful in 3m9s
2026-09-12 10:42:10 +01:00
Miguel PalhasandClaude Opus 4.6 de603ccd20 feat(maestro): split tool groups on text boundaries
Tool rows interleaved with agent text now produce separate
collapsed groups instead of one per turn. The timeline reads
text → group → text → group, matching chronological order.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-09-12 10:42:06 +01:00
Miguel Palhas c6af78e9dd feat(maestro): concatenate queued structured prompts into one turn
ci / web (push) Failing after 6s
ci / rust (push) Failing after 54s
ci / flake (push) Successful in 2m59s
Closes #257
2026-09-12 10:12:36 +01:00