feat(maestro): spawn form defaults command to claude + prefills cwd to daemon home dir (NAP-328)

Two web spawn QoL improvements plus the wire support they need:

- Command field now prefills `claude` instead of an empty box.
- Working directory prefills the selected daemon's home dir, updating on
  daemon change unless the user has typed their own value.

The daemon resolves its `$HOME` via `dirs::home_dir()` at startup and
advertises it end-to-end: a new `home_dir` field on `DaemonOutbound::Hello`
flows through the registry's `register` into `DaemonInfo` (served on
`/api/daemons` and `/api/events`). The field is `#[serde(default)]`, so older
daemons that omit it deserialize to an empty string — backward compatible, and
the UI simply skips prefill when it's empty.

Hierarchical `/`-separated labels in the web sidebar already worked
(web/src/catalog.ts); no change there.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-15 18:07:53 +00:00
co-authored by Claude Opus 4.8
parent 906538c776
commit 6d7cd0b4c8
21 changed files with 119 additions and 5 deletions
+16 -1
View File
@@ -25,7 +25,7 @@ export function openSpawnModal(daemons: Map<string, DaemonInfo>): void {
</label>
<label>
Command
<input name="command" type="text" required placeholder="bash" autocomplete="off" />
<input name="command" type="text" required value="claude" placeholder="bash" autocomplete="off" />
</label>
<label>
Name (optional)
@@ -82,6 +82,21 @@ export function openSpawnModal(daemons: Map<string, DaemonInfo>): void {
}
}
// Prefill the working directory with the selected daemon's home dir, and keep
// it in sync when the daemon changes — unless the user has typed their own.
const cwdInput = host.querySelector("input[name=cwd]") as HTMLInputElement;
let cwdEdited = false;
cwdInput.addEventListener("input", () => {
cwdEdited = true;
});
const applyHomeDir = () => {
if (cwdEdited) return;
const home = daemons.get(select.value)?.home_dir;
if (home) cwdInput.value = home;
};
select.addEventListener("change", applyHomeDir);
applyHomeDir();
const close = () => host.remove();
host.querySelector(".close")?.addEventListener("click", close);
host.querySelector(".cancel")?.addEventListener("click", close);
+3
View File
@@ -22,6 +22,9 @@ export interface DaemonInfo {
hostname: string;
version: string;
daemon_url: string;
/** Home dir of the user the daemon runs as; used to prefill the spawn form's
* working directory. Empty/absent for older daemons. */
home_dir?: string;
}
export interface WorktreeSpec {