feat: add --continue flag to `ao start` for orchestrator conversation continuity
When the orchestrator needs a fresh system prompt (e.g. CLAUDE.local.md was updated), `ao start --continue` kills the existing session and respawns with `claude --continue`, preserving conversation history while reloading prompts. Changes: - Add `continue` option to AgentLaunchConfig and OrchestratorSpawnConfig - Claude Code agent plugin passes --continue to CLI when set - Session manager forwards continue option to agent launch config - `ao start --continue` kills existing orchestrator, respawns with continue flag - Other agent plugins unaffected (optional field, backwards-compatible) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
01a6c56e1b
commit
93ff9341be
|
|
@ -124,6 +124,10 @@ export function registerStart(program: Command): void {
|
|||
.option("--no-dashboard", "Skip starting the dashboard server")
|
||||
.option("--no-orchestrator", "Skip starting the orchestrator agent")
|
||||
.option("--rebuild", "Clean and rebuild dashboard before starting")
|
||||
.option(
|
||||
"--continue",
|
||||
"Continue the most recent orchestrator conversation (kills existing session first, preserves conversation history with fresh system prompt)",
|
||||
)
|
||||
.action(
|
||||
async (
|
||||
projectArg?: string,
|
||||
|
|
@ -131,6 +135,7 @@ export function registerStart(program: Command): void {
|
|||
dashboard?: boolean;
|
||||
orchestrator?: boolean;
|
||||
rebuild?: boolean;
|
||||
continue?: boolean;
|
||||
},
|
||||
) => {
|
||||
try {
|
||||
|
|
@ -180,6 +185,15 @@ export function registerStart(program: Command): void {
|
|||
const existing = await sm.get(sessionId);
|
||||
exists = existing !== null && existing.status !== "killed";
|
||||
|
||||
// --continue: kill existing session so claude --continue picks up
|
||||
// the most recent conversation with a fresh system prompt
|
||||
if (opts?.continue && exists) {
|
||||
spinner.start("Killing existing orchestrator session for --continue");
|
||||
await sm.kill(sessionId);
|
||||
spinner.succeed("Existing orchestrator session killed");
|
||||
exists = false;
|
||||
}
|
||||
|
||||
if (exists) {
|
||||
if (existing?.runtimeHandle?.id) {
|
||||
tmuxTarget = existing.runtimeHandle.id;
|
||||
|
|
@ -191,14 +205,26 @@ export function registerStart(program: Command): void {
|
|||
);
|
||||
} else {
|
||||
try {
|
||||
spinner.start("Creating orchestrator session");
|
||||
spinner.start(
|
||||
opts?.continue
|
||||
? "Continuing orchestrator session"
|
||||
: "Creating orchestrator session",
|
||||
);
|
||||
const systemPrompt = generateOrchestratorPrompt({ config, projectId, project });
|
||||
|
||||
const session = await sm.spawnOrchestrator({ projectId, systemPrompt });
|
||||
const session = await sm.spawnOrchestrator({
|
||||
projectId,
|
||||
systemPrompt,
|
||||
continue: opts?.continue,
|
||||
});
|
||||
if (session.runtimeHandle?.id) {
|
||||
tmuxTarget = session.runtimeHandle.id;
|
||||
}
|
||||
spinner.succeed("Orchestrator session created");
|
||||
spinner.succeed(
|
||||
opts?.continue
|
||||
? "Orchestrator session continued"
|
||||
: "Orchestrator session created",
|
||||
);
|
||||
} catch (err) {
|
||||
spinner.fail("Orchestrator setup failed");
|
||||
// Cleanup dashboard if orchestrator setup fails
|
||||
|
|
|
|||
|
|
@ -641,6 +641,7 @@ export function createSessionManager(deps: SessionManagerDeps): SessionManager {
|
|||
permissions: "skip" as const,
|
||||
model: project.agentConfig?.model,
|
||||
systemPromptFile,
|
||||
continue: orchestratorConfig.continue,
|
||||
};
|
||||
|
||||
const launchCommand = plugins.agent.getLaunchCommand(agentLaunchConfig);
|
||||
|
|
|
|||
|
|
@ -184,6 +184,12 @@ export interface SessionSpawnConfig {
|
|||
export interface OrchestratorSpawnConfig {
|
||||
projectId: string;
|
||||
systemPrompt?: string;
|
||||
/**
|
||||
* Continue the most recent conversation in the project directory.
|
||||
* When true, the agent is launched with --continue (or equivalent),
|
||||
* preserving conversation history while loading fresh system prompts.
|
||||
*/
|
||||
continue?: boolean;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
|
|
@ -352,6 +358,13 @@ export interface AgentLaunchConfig {
|
|||
* - Codex/Aider: similar shell substitution
|
||||
*/
|
||||
systemPromptFile?: string;
|
||||
/**
|
||||
* Continue the most recent conversation in the project directory.
|
||||
* Loads fresh system prompt while preserving conversation history.
|
||||
* - Claude Code: --continue flag
|
||||
* - Other agents: ignored if not supported
|
||||
*/
|
||||
continue?: boolean;
|
||||
}
|
||||
|
||||
export interface WorkspaceHooksConfig {
|
||||
|
|
|
|||
|
|
@ -203,6 +203,24 @@ describe("getLaunchCommand", () => {
|
|||
expect(cmd).not.toMatch(/\s-p\s/);
|
||||
expect(cmd).not.toContain("Do the task");
|
||||
});
|
||||
|
||||
it("includes --continue when continue=true", () => {
|
||||
const cmd = agent.getLaunchCommand(makeLaunchConfig({ continue: true }));
|
||||
expect(cmd).toContain("--continue");
|
||||
expect(cmd).toBe("claude --continue");
|
||||
});
|
||||
|
||||
it("combines --continue with other flags", () => {
|
||||
const cmd = agent.getLaunchCommand(
|
||||
makeLaunchConfig({ continue: true, permissions: "skip", model: "opus" }),
|
||||
);
|
||||
expect(cmd).toBe("claude --continue --dangerously-skip-permissions --model 'opus'");
|
||||
});
|
||||
|
||||
it("omits --continue when continue is not set", () => {
|
||||
const cmd = agent.getLaunchCommand(makeLaunchConfig());
|
||||
expect(cmd).not.toContain("--continue");
|
||||
});
|
||||
});
|
||||
|
||||
// =========================================================================
|
||||
|
|
|
|||
|
|
@ -635,6 +635,10 @@ function createClaudeCodeAgent(): Agent {
|
|||
// This command must be safe for both shell and execFile contexts.
|
||||
const parts: string[] = ["claude"];
|
||||
|
||||
if (config.continue) {
|
||||
parts.push("--continue");
|
||||
}
|
||||
|
||||
if (config.permissions === "skip") {
|
||||
parts.push("--dangerously-skip-permissions");
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue