feat(cli): add paseo import --provider <name> <id> to resume existing sessions (#632)

Surfaces the daemon's existing resume-from-persistence capability through a
new top-level CLI command so users can pull existing Claude Code, Codex, or
OpenCode sessions into Paseo without losing history. Adds a new additive
`import_agent_request` WebSocket message; no existing schemas change.

Refs #611, #237, #492; partially addresses #268.
This commit is contained in:
Mohamed Boudra
2026-04-30 21:33:44 +08:00
committed by GitHub
parent 2025dee9d0
commit 4bcf98a9e3
8 changed files with 428 additions and 0 deletions
@@ -122,6 +122,13 @@ const perfNow: () => number =
? () => performance.now()
: () => Date.now();
export interface ImportAgentInput {
provider: AgentProvider;
sessionId: string;
cwd?: string;
labels?: Record<string, string>;
}
export type {
DaemonTransport,
DaemonTransportFactory,
@@ -1763,6 +1770,47 @@ export class DaemonClient {
return status.agent;
}
async importAgent(input: ImportAgentInput): Promise<AgentSnapshotPayload> {
const requestId = this.createRequestId();
const message = SessionInboundMessageSchema.parse({
type: "import_agent_request",
requestId,
provider: input.provider,
sessionId: input.sessionId,
...(input.cwd ? { cwd: input.cwd } : {}),
...(input.labels && Object.keys(input.labels).length > 0 ? { labels: input.labels } : {}),
});
const status = await this.sendRequest({
requestId,
message,
timeout: 15000,
options: { skipQueue: true },
select: (msg) => {
if (msg.type !== "status") {
return null;
}
const resumed = AgentResumedStatusPayloadSchema.safeParse(msg.payload);
if (resumed.success && resumed.data.requestId === requestId) {
return resumed.data;
}
const failed = AgentCreateFailedStatusPayloadSchema.safeParse(msg.payload);
if (failed.success && failed.data.requestId === requestId) {
return failed.data;
}
return null;
},
});
if (status.status === "agent_create_failed") {
throw new Error(status.error);
}
return status.agent;
}
async refreshAgent(agentId: string, requestId?: string): Promise<AgentRefreshedStatusPayload> {
const resolvedRequestId = this.createRequestId(requestId);
const message = SessionInboundMessageSchema.parse({