feat(maestro): tile-first web spawn form — host/command tiles, recents, worktree-by-branch, generated name (#27)
ci / rust (push) Successful in 4m29s
ci / rust (push) Successful in 4m29s
Rework web/src/spawn.ts from raw text boxes into a low-friction, tile-first flow: pick host tile → pick command tile → pick recent dir → Spawn, name already filled. - Command tiles from the daemon's advertised presets (GET /api/web/info, #26), with built-in fallback; `custom` reveals the free-text command input. - Host tiles replace the <select> (label hostname, sub daemon_id); most- recently-spawned-on host sorts first + pre-selected; overflow behind "More…". - Recent-dirs picker per host (GET /api/daemons/:id/recent-dirs, #26), rows show dir + last command, re-queried on host change; picking a dir can pre-select its last command. Persistent "Other directory…" drops to the raw input + NAP-329 autocomplete; empty history prefills raw with home_dir. - Worktree by branch alone: toggle infers base_repo via /gitroot from the chosen dir (#26); non-repo dir disables the toggle with an inline hint; WorktreeSpec.base_repo filled client-side (wire unchanged). - Name field prefilled with a generated cyberpunk handle (names.ts mirrors the maestro-names wordlists); ↻ rerolls. Adds api.ts getWebInfo/recentDirs/gitRoot, the WebInfo/SpawnPreset/RecentDirs/ GitRoot types, and stubs the new endpoints in the `?mock&spawn` review fixture. Closes #27 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,8 +3,11 @@ import type {
|
||||
CreateSessionRequest,
|
||||
DaemonInfo,
|
||||
DirListing,
|
||||
GitRoot,
|
||||
RecentDirs,
|
||||
Session,
|
||||
Uuid,
|
||||
WebInfo,
|
||||
} from "./types.js";
|
||||
|
||||
async function jsonOrError<T>(res: Response): Promise<T> {
|
||||
@@ -58,6 +61,26 @@ export async function listDir(daemonId: string, path: string): Promise<DirListin
|
||||
return jsonOrError(await fetch(url, { credentials: "same-origin" }));
|
||||
}
|
||||
|
||||
/** Identity + spawn presets of the daemon this web app is connected to (#26). */
|
||||
export async function getWebInfo(): Promise<WebInfo> {
|
||||
return jsonOrError(await fetch("/api/web/info", { credentials: "same-origin" }));
|
||||
}
|
||||
|
||||
/** Recently-used working dirs on `daemonId`'s host, newest-first and deduped by
|
||||
* dir (#26). Drives the spawn form's recents picker. */
|
||||
export async function recentDirs(daemonId: string): Promise<RecentDirs> {
|
||||
const url = `/api/daemons/${encodeURIComponent(daemonId)}/recent-dirs`;
|
||||
return jsonOrError(await fetch(url, { credentials: "same-origin" }));
|
||||
}
|
||||
|
||||
/** Probe the enclosing git repo of `path` on `daemonId`'s host (#26). `root` is
|
||||
* absent when the path isn't inside a repo. `path` may be `~`/relative/absolute;
|
||||
* the daemon resolves it against its home dir. */
|
||||
export async function gitRoot(daemonId: string, path: string): Promise<GitRoot> {
|
||||
const url = `/api/daemons/${encodeURIComponent(daemonId)}/gitroot?path=${encodeURIComponent(path)}`;
|
||||
return jsonOrError(await fetch(url, { credentials: "same-origin" }));
|
||||
}
|
||||
|
||||
export function eventsWsUrl(): string {
|
||||
const proto = location.protocol === "https:" ? "wss:" : "ws:";
|
||||
return `${proto}//${location.host}/api/events`;
|
||||
|
||||
Reference in New Issue
Block a user