import type { Command } from "commander"; import { connectToDaemon } from "../../utils/client.js"; import { isSameOrDescendantPath } from "../../utils/paths.js"; import type { DaemonClient, FetchAgentHistoryEntry } from "@getpaseo/client/internal/daemon-client"; export function addDeleteOptions(cmd: Command): Command { return cmd .description("Delete an agent (interrupt if running, then hard-delete)") .argument("[id]", "Agent ID (or prefix) - optional if --all or --cwd specified") .option("--all", "Delete all agents") .option("--cwd ", "Delete all agents in directory"); } import type { CommandOptions, SingleResult, OutputSchema, CommandError, } from "../../output/index.js"; export interface DeleteResult { deletedCount: number; agentIds: string[]; } export const deleteSchema: OutputSchema = { idField: (item) => item.agentIds.join("\n"), columns: [{ header: "DELETED", field: "deletedCount" }], }; export interface AgentDeleteOptions extends CommandOptions { all?: boolean; cwd?: string; } export type AgentDeleteResult = SingleResult; // History includes archived agents and agents whose provider is unavailable. async function fetchHistoryAgents(client: DaemonClient) { const agents: FetchAgentHistoryEntry["agent"][] = []; let cursor: string | undefined; do { const payload = await client.fetchAgentHistory({ page: { limit: 200, ...(cursor ? { cursor } : {}) }, }); agents.push(...payload.entries.map((entry) => entry.agent)); cursor = payload.pageInfo.nextCursor ?? undefined; } while (cursor); return agents; } export async function runDeleteCommand( id: string | undefined, options: AgentDeleteOptions, _command: Command, ): Promise { if (!id && !options.all && !options.cwd) { const error: CommandError = { code: "MISSING_ARGUMENT", message: "Agent ID required unless --all or --cwd is specified", details: "Usage: paseo agent delete | --all | --cwd ", }; throw error; } const client = await connectToDaemon({ target: options.daemonTarget }); try { const deletedIds: string[] = []; let agents: FetchAgentHistoryEntry["agent"][]; if (options.all || options.cwd) { agents = await fetchHistoryAgents(client); if (!options.all) { agents = agents.filter((a) => isSameOrDescendantPath(options.cwd!, a.cwd)); } } else { const fetchResult = await client.fetchAgent({ agentId: id! }); if (!fetchResult) { const error: CommandError = { code: "AGENT_NOT_FOUND", message: `No agent found matching: ${id}`, details: "Use `paseo ls` to list available agents", }; throw error; } agents = [fetchResult.agent]; } const deleteResults = await Promise.all( agents.map(async (agent) => { try { if (agent.status === "running") { await client.cancelAgent(agent.id).catch(() => {}); } await client.deleteAgent(agent.id); return { ok: true as const, id: agent.id }; } catch (err) { if (err && typeof err === "object" && "code" in err) throw err; const message = err instanceof Error ? err.message : String(err); return { ok: false as const, id: agent.id, message }; } }), ); for (const result of deleteResults) { if (result.ok) { deletedIds.push(result.id); } else { console.error( `Warning: Failed to delete agent ${result.id.slice(0, 7)}: ${result.message}`, ); } } await client.close(); return { type: "single", data: { deletedCount: deletedIds.length, agentIds: deletedIds, }, schema: deleteSchema, }; } catch (err) { await client.close().catch(() => {}); if (err && typeof err === "object" && "code" in err) { throw err; } const message = err instanceof Error ? err.message : String(err); const error: CommandError = { code: "DELETE_AGENT_FAILED", message: `Failed to delete agent(s): ${message}`, }; throw error; } }