diff --git a/extensions/connector-claude-code/src/extension.ts b/extensions/connector-claude-code/src/extension.ts index fb45489e..ae9d7bb6 100644 --- a/extensions/connector-claude-code/src/extension.ts +++ b/extensions/connector-claude-code/src/extension.ts @@ -35,6 +35,11 @@ export const claudeConnector: Connector = { const args = ["--dangerously-load-development-channels", CHANNEL_REF]; + // Resume a prior conversation into the mesh. `--fork-session` makes claude mint a + // fresh session id from the resumed history, so the original session this id points + // at keeps running untouched (we adopt its context, not its identity). + if (opts.resume) args.push("--resume", opts.resume, "--fork-session"); + // An agent file carries identity (read in-session via COTAL_AGENT_FILE) plus // persona + model, which can only be applied to a `claude` session at launch. if (opts.configPath) { diff --git a/implementations/cli/src/commands/spawn.ts b/implementations/cli/src/commands/spawn.ts index 06a70e22..fbcd5b93 100644 --- a/implementations/cli/src/commands/spawn.ts +++ b/implementations/cli/src/commands/spawn.ts @@ -41,6 +41,7 @@ export async function spawn(argv: string[]): Promise { server: { type: "string" }, agent: { type: "string" }, role: { type: "string" }, + resume: { type: "string" }, }, }); @@ -49,7 +50,7 @@ export async function spawn(argv: string[]): Promise { const ref = values.config ?? positionals[0] ?? values.name; if (!ref) { console.error( - "usage: cotal spawn | --config | --name [--agent ] [--role ] [--space ] [--server ]", + "usage: cotal spawn | --config | --name [--agent ] [--role ] [--resume ] [--space ] [--server ]", ); process.exit(1); } @@ -111,6 +112,7 @@ export async function spawn(argv: string[]): Promise { creds: credsPath, servers: server, configPath: path, + resume: values.resume, }); console.error( diff --git a/implementations/manager/src/commands.ts b/implementations/manager/src/commands.ts index bccf4c73..574ad926 100644 --- a/implementations/manager/src/commands.ts +++ b/implementations/manager/src/commands.ts @@ -30,6 +30,7 @@ function parse(argv: string[]): Values { agent: { type: "string" }, config: { type: "string" }, creds: { type: "string" }, + resume: { type: "string" }, "console-port": { type: "string" }, drive: { type: "boolean" }, }, @@ -98,6 +99,7 @@ async function start(argv: string[]): Promise { role: v.role, agent: v.agent, config: v.config, + resume: v.resume, }, v.creds); failIfNotOk(reply); const d = reply.data as { name: string; role?: string; agent: string; mode: string }; @@ -333,7 +335,7 @@ const managerCommands: Command[] = [ name: "start", group: "Control plane", summary: - "ask the manager to spawn an agent — --name [--role ] [--agent ] [--config ] (auto-discovers .cotal/agents/.md)", + "ask the manager to spawn an agent — --name [--role ] [--agent ] [--config ] [--resume ] (auto-discovers .cotal/agents/.md)", run: start, }, { diff --git a/implementations/manager/src/manager.ts b/implementations/manager/src/manager.ts index 378513d6..5f8b8d62 100644 --- a/implementations/manager/src/manager.ts +++ b/implementations/manager/src/manager.ts @@ -210,6 +210,7 @@ export class Manager { creds: credsPath, servers: this.servers, configPath, + resume: args.resume ? String(args.resume) : undefined, }); handle = this.runtime.spawn(name, spec, this.workspaceRoot); } catch (e) { diff --git a/packages/core/src/connector.ts b/packages/core/src/connector.ts index bddfbe9c..b117bac4 100644 --- a/packages/core/src/connector.ts +++ b/packages/core/src/connector.ts @@ -17,6 +17,11 @@ export interface LaunchOpts { * passes it through (`COTAL_AGENT_FILE`) so the joined session reads its own * card from it, and applies the file's persona/model at launch. */ configPath?: string; + /** Resume a prior session of this agent type instead of starting fresh — the + * connector-specific session id to reattach (claude-code: a `--resume` id, + * forked so the original session isn't hijacked). Connectors that can't resume + * ignore it. */ + resume?: string; } /** A recipe for starting an agent as a mesh node — command, args, and extra env. */