diff --git a/packages/cli/src/commands/agent/index.ts b/packages/cli/src/commands/agent/index.ts index 9532e3cf4..69afbaf7d 100644 --- a/packages/cli/src/commands/agent/index.ts +++ b/packages/cli/src/commands/agent/index.ts @@ -10,6 +10,7 @@ import { addSendOptions, runSendCommand } from "./send.js"; import { addInspectOptions, runInspectCommand } from "./inspect.js"; import { addWaitOptions, runWaitCommand } from "./wait.js"; import { addAttachOptions, runAttachCommand } from "./attach.js"; +import { addReloadOptions, runReloadCommand } from "./reload.js"; import { runUpdateCommand } from "./update.js"; import { withOutput } from "../../output/index.js"; import { @@ -66,6 +67,10 @@ export function createAgentCommand(): Command { withOutput(runArchiveCommand), ); + addJsonAndDaemonHostOptions(addReloadOptions(agent.command("reload"))).action( + withOutput(runReloadCommand), + ); + addJsonAndDaemonHostOptions( agent .command("update") diff --git a/packages/cli/src/commands/agent/reload.ts b/packages/cli/src/commands/agent/reload.ts new file mode 100644 index 000000000..7693f3b5c --- /dev/null +++ b/packages/cli/src/commands/agent/reload.ts @@ -0,0 +1,106 @@ +import { Command } from "commander"; +import { connectToDaemon, getDaemonHost, resolveAgentId } from "../../utils/client.js"; +import type { + CommandOptions, + SingleResult, + OutputSchema, + CommandError, +} from "../../output/index.js"; + +export interface AgentReloadResult { + agentId: string; + status: "reloaded"; + timelineSize: number; +} + +export const reloadSchema: OutputSchema = { + idField: "agentId", + columns: [ + { header: "AGENT ID", field: "agentId" }, + { header: "STATUS", field: "status" }, + { header: "TIMELINE", field: "timelineSize" }, + ], +}; + +export function addReloadOptions(cmd: Command): Command { + return cmd + .description("Reload an agent (restarts the underlying process)") + .argument("", "Agent ID, prefix, or name"); +} + +export interface AgentReloadOptions extends CommandOptions { + host?: string; +} + +export type AgentReloadCommandResult = SingleResult; + +export async function runReloadCommand( + agentIdArg: string, + options: AgentReloadOptions, + _command: Command, +): Promise { + const host = getDaemonHost({ host: options.host as string | undefined }); + + if (!agentIdArg || agentIdArg.trim().length === 0) { + const error: CommandError = { + code: "MISSING_AGENT_ID", + message: "Agent ID is required", + details: "Usage: paseo agent reload ", + }; + throw error; + } + + let client; + try { + client = await connectToDaemon({ host: options.host as string | undefined }); + } catch (err) { + const message = err instanceof Error ? err.message : String(err); + const error: CommandError = { + code: "DAEMON_NOT_RUNNING", + message: `Cannot connect to daemon at ${host}: ${message}`, + details: "Start the daemon with: paseo daemon start", + }; + throw error; + } + + try { + const agentsPayload = await client.fetchAgents({ filter: { includeArchived: true } }); + const agents = agentsPayload.entries.map((entry) => entry.agent); + const agentId = resolveAgentId(agentIdArg, agents); + if (!agentId) { + const error: CommandError = { + code: "AGENT_NOT_FOUND", + message: `Agent not found: ${agentIdArg}`, + details: 'Use "paseo ls" to list available agents', + }; + throw error; + } + + const result = await client.refreshAgent(agentId); + + await client.close(); + + return { + type: "single", + data: { + agentId: result.agentId, + status: "reloaded", + timelineSize: result.timelineSize ?? 0, + }, + schema: reloadSchema, + }; + } 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: "RELOAD_FAILED", + message: `Failed to reload agent: ${message}`, + }; + throw error; + } +}