diff --git a/packages/cli/package.json b/packages/cli/package.json index 0352f96c..fefd9283 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@openrouter/spawn", - "version": "0.26.11", + "version": "0.26.12", "type": "module", "bin": { "spawn": "cli.js" diff --git a/packages/cli/src/commands/delete.ts b/packages/cli/src/commands/delete.ts index 3146158e..c3db4a38 100644 --- a/packages/cli/src/commands/delete.ts +++ b/packages/cli/src/commands/delete.ts @@ -352,7 +352,12 @@ export async function cascadeDelete(record: SpawnRecord, manifest: Manifest | nu return confirmAndDelete(record, manifest); } -export async function cmdDelete(agentFilter?: string, cloudFilter?: string): Promise { +export async function cmdDelete( + agentFilter?: string, + cloudFilter?: string, + nameFilter?: string, + forceYes?: boolean, +): Promise { const resolved = await resolveListFilters(agentFilter, cloudFilter); agentFilter = resolved.agentFilter; cloudFilter = resolved.cloudFilter; @@ -368,6 +373,15 @@ export async function cmdDelete(agentFilter?: string, cloudFilter?: string): Pro const lower = cloudFilter.toLowerCase(); filtered = filtered.filter((r) => r.cloud.toLowerCase() === lower); } + if (nameFilter) { + const lower = nameFilter.toLowerCase(); + filtered = filtered.filter( + (r) => + (r.name ?? "").toLowerCase() === lower || + (r.connection?.server_name ?? "").toLowerCase() === lower || + r.id === nameFilter, + ); + } if (filtered.length === 0) { p.log.info("No active servers to delete."); @@ -387,10 +401,22 @@ export async function cmdDelete(agentFilter?: string, cloudFilter?: string): Pro const manifestResult = await asyncTryCatchIf(isNetworkError, loadManifest); const manifest: Manifest | null = manifestResult.ok ? manifestResult.data : null; + // Non-interactive headless delete: --name + --yes skips the picker if (!isInteractiveTTY()) { - p.log.error("spawn delete requires an interactive terminal."); - p.log.info(`Use ${pc.cyan("spawn list")} to see your servers.`); - process.exit(1); + if (!forceYes) { + p.log.error("spawn delete requires --yes in non-interactive mode."); + p.log.info(`Usage: ${pc.cyan("spawn delete --name --yes")}`); + process.exit(1); + } + for (const record of filtered) { + const label = record.connection?.server_name || record.name || record.id; + await ensureDeleteCredentials(record); + const ok = await execDeleteServer(record); + if (ok) { + p.log.success(`Server "${label}" deleted`); + } + } + return; } await activeServerPicker(filtered, manifest); diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index 77990eba..049e77a9 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -613,8 +613,16 @@ async function dispatchDeleteCommand(filteredArgs: string[]): Promise { cmdHelp(); return; } - const { agentFilter, cloudFilter } = parseListFilters(filteredArgs.slice(1)); - await cmdDelete(agentFilter, cloudFilter); + const args = filteredArgs.slice(1); + const forceYes = args.includes("--yes") || args.includes("-y"); + let nameFilter: string | undefined; + const nameIdx = args.indexOf("--name"); + if (nameIdx !== -1 && args[nameIdx + 1]) { + nameFilter = args[nameIdx + 1]; + } + const cleanArgs = args.filter((a) => a !== "--yes" && a !== "-y" && a !== "--name" && a !== nameFilter); + const { agentFilter, cloudFilter } = parseListFilters(cleanArgs); + await cmdDelete(agentFilter, cloudFilter, nameFilter, forceYes); } /** Handle status/ps commands with --prune and --json flags */ diff --git a/packages/cli/src/shared/spawn-skill.ts b/packages/cli/src/shared/spawn-skill.ts index 0cb58a95..c04a09f1 100644 --- a/packages/cli/src/shared/spawn-skill.ts +++ b/packages/cli/src/shared/spawn-skill.ts @@ -44,7 +44,7 @@ Returns JSON: \`{"status":"success","ip_address":"...","ssh_user":"root","server ## Managing Children - \`spawn list --json\` — see running children -- \`spawn delete\` — tear down a child VM +- \`spawn delete --name --yes\` — tear down a child VM (headless) - \`spawn tree\` — see the full spawn tree ## Context diff --git a/skills/claude/SKILL.md b/skills/claude/SKILL.md index 5918846d..92e4ee65 100644 --- a/skills/claude/SKILL.md +++ b/skills/claude/SKILL.md @@ -28,7 +28,7 @@ Returns JSON: `{"status":"success","ip_address":"...","ssh_user":"root","server_ ## Managing Children - `spawn list --json` — see running children -- `spawn delete` — tear down a child VM +- `spawn delete --name --yes` — tear down a child VM - `spawn tree` — see the full spawn tree ## Context diff --git a/skills/codex/SKILL.md b/skills/codex/SKILL.md index 5918846d..92e4ee65 100644 --- a/skills/codex/SKILL.md +++ b/skills/codex/SKILL.md @@ -28,7 +28,7 @@ Returns JSON: `{"status":"success","ip_address":"...","ssh_user":"root","server_ ## Managing Children - `spawn list --json` — see running children -- `spawn delete` — tear down a child VM +- `spawn delete --name --yes` — tear down a child VM - `spawn tree` — see the full spawn tree ## Context diff --git a/skills/junie/AGENTS.md b/skills/junie/AGENTS.md index c0f13a22..cf8db3a6 100644 --- a/skills/junie/AGENTS.md +++ b/skills/junie/AGENTS.md @@ -22,7 +22,7 @@ Returns JSON: `{"status":"success","ip_address":"...","ssh_user":"root","server_ ## Managing Children - `spawn list --json` — see running children -- `spawn delete` — tear down a child VM +- `spawn delete --name --yes` — tear down a child VM - `spawn tree` — see the full spawn tree ## Context diff --git a/skills/kilocode/spawn.md b/skills/kilocode/spawn.md index c0f13a22..cf8db3a6 100644 --- a/skills/kilocode/spawn.md +++ b/skills/kilocode/spawn.md @@ -22,7 +22,7 @@ Returns JSON: `{"status":"success","ip_address":"...","ssh_user":"root","server_ ## Managing Children - `spawn list --json` — see running children -- `spawn delete` — tear down a child VM +- `spawn delete --name --yes` — tear down a child VM - `spawn tree` — see the full spawn tree ## Context diff --git a/skills/openclaw/SKILL.md b/skills/openclaw/SKILL.md index 5918846d..92e4ee65 100644 --- a/skills/openclaw/SKILL.md +++ b/skills/openclaw/SKILL.md @@ -28,7 +28,7 @@ Returns JSON: `{"status":"success","ip_address":"...","ssh_user":"root","server_ ## Managing Children - `spawn list --json` — see running children -- `spawn delete` — tear down a child VM +- `spawn delete --name --yes` — tear down a child VM - `spawn tree` — see the full spawn tree ## Context diff --git a/skills/opencode/AGENTS.md b/skills/opencode/AGENTS.md index c0f13a22..cf8db3a6 100644 --- a/skills/opencode/AGENTS.md +++ b/skills/opencode/AGENTS.md @@ -22,7 +22,7 @@ Returns JSON: `{"status":"success","ip_address":"...","ssh_user":"root","server_ ## Managing Children - `spawn list --json` — see running children -- `spawn delete` — tear down a child VM +- `spawn delete --name --yes` — tear down a child VM - `spawn tree` — see the full spawn tree ## Context diff --git a/skills/zeroclaw/AGENTS.md b/skills/zeroclaw/AGENTS.md index c0f13a22..cf8db3a6 100644 --- a/skills/zeroclaw/AGENTS.md +++ b/skills/zeroclaw/AGENTS.md @@ -22,7 +22,7 @@ Returns JSON: `{"status":"success","ip_address":"...","ssh_user":"root","server_ ## Managing Children - `spawn list --json` — see running children -- `spawn delete` — tear down a child VM +- `spawn delete --name --yes` — tear down a child VM - `spawn tree` — see the full spawn tree ## Context