Create agents in worktrees with auto-archive (#1120)

* Add daemon worktree auto-archive spawning

* Refactor create agent lifecycle dispatch

* Stabilize Claude autonomous turn test
This commit is contained in:
Mohamed Boudra
2026-05-20 22:41:15 +08:00
committed by GitHub
parent 68d88f0928
commit 3bca1a72e8
10 changed files with 722 additions and 9 deletions
+56 -1
View File
@@ -252,6 +252,7 @@ import {
handleWorkspaceSetupStatusRequest as handleWorkspaceSetupStatusRequestMessage,
} from "./worktree-session.js";
import { toWorktreeWireError } from "./worktree-errors.js";
import { CreateAgentLifecycleDispatch } from "./agent/create-agent-lifecycle-dispatch.js";
const WORKSPACE_GIT_WATCH_REMOVED_STATE_KEY = "__removed__";
@@ -826,6 +827,7 @@ export class Session {
private readonly serverId: string | undefined;
private readonly daemonVersion: string | undefined;
private readonly daemonRuntimeConfig: SessionOptions["daemonRuntimeConfig"];
private readonly createAgentLifecycleDispatch: CreateAgentLifecycleDispatch;
private voiceModeAgentId: string | null = null;
private voiceModeBaseConfig: VoiceModeBaseConfig | null = null;
@@ -911,6 +913,35 @@ export class Session {
isPathWithinRoot: (rootPath, candidatePath) => this.isPathWithinRoot(rootPath, candidatePath),
sessionLogger: this.sessionLogger,
});
this.createAgentLifecycleDispatch = new CreateAgentLifecycleDispatch({
paseoHome: this.paseoHome,
agentManager: this.agentManager,
agentStorage: this.agentStorage,
github: this.github,
workspaceGitService: this.workspaceGitService,
createPaseoWorktreeWorkflow: (input, workflowOptions) =>
this.createPaseoWorktreeWorkflow(input, workflowOptions),
archiveAgentForClose: (agentId) => this.archiveAgentForClose(agentId),
archiveWorkspaceRecord: (workspaceId) => this.archiveWorkspaceRecord(workspaceId),
emit: (message) => this.emit(message),
emitAgentRemove: (agentId) => {
if (this.agentUpdatesSubscription) {
this.bufferOrEmitAgentUpdate(this.agentUpdatesSubscription, {
kind: "remove",
agentId,
});
}
},
emitWorkspaceUpdatesForWorkspaceIds: (workspaceIds) =>
this.emitWorkspaceUpdatesForWorkspaceIds(workspaceIds),
markWorkspaceArchiving: (workspaceIds, archivingAt) =>
this.markWorkspaceArchiving(workspaceIds, archivingAt),
clearWorkspaceArchiving: (workspaceIds) => this.clearWorkspaceArchiving(workspaceIds),
isPathWithinRoot: (rootPath, candidatePath) => this.isPathWithinRoot(rootPath, candidatePath),
killTerminalsUnderPath: (rootPath) =>
this.terminalController.killTerminalsUnderPath(rootPath),
logger: this.sessionLogger,
});
this.providerSnapshotManager = providerSnapshotManager ?? null;
this.scriptRouteStore = scriptRouteStore ?? null;
this.scriptRuntimeStore = scriptRuntimeStore ?? null;
@@ -3081,6 +3112,8 @@ export class Session {
clientMessageId,
outputSchema,
git,
worktree,
autoArchive,
images,
attachments,
labels,
@@ -3093,6 +3126,8 @@ export class Session {
}`,
);
let createdWorktreeForCleanup: CreatePaseoWorktreeWorkflowResult | null = null;
let createdAgentId: string | null = null;
try {
const trimmedPrompt = initialPrompt?.trim();
const { explicitTitle, provisionalTitle } = resolveCreateAgentTitles({
@@ -3108,8 +3143,18 @@ export class Session {
...(trimmedPrompt ? { prompt: trimmedPrompt } : {}),
...(attachments && attachments.length > 0 ? { attachments } : {}),
};
const createdWorktree = await this.createAgentLifecycleDispatch.createWorktreeForRequest({
cwd: config.cwd,
target: worktree,
firstAgentContext,
hasLegacyGitOptions: Boolean(git),
});
createdWorktreeForCleanup = createdWorktree;
const createAgentConfig: AgentSessionConfig = createdWorktree
? { ...resolvedConfig, cwd: createdWorktree.worktree.worktreePath }
: resolvedConfig;
const { sessionConfig, setupContinuation } = await this.buildAgentSessionConfig(
resolvedConfig,
createAgentConfig,
git,
worktreeName,
firstAgentContext,
@@ -3127,7 +3172,13 @@ export class Session {
initialPrompt: trimmedPrompt,
env,
});
createdAgentId = snapshot.id;
await this.forwardAgentUpdate(snapshot);
this.createAgentLifecycleDispatch.registerAutoArchiveIfRequested({
autoArchive,
agentId: snapshot.id,
createdWorktree,
});
await this.sendInitialCreateAgentPrompt({
snapshot,
@@ -3161,6 +3212,10 @@ export class Session {
`Created agent ${snapshot.id} (${snapshot.provider})`,
);
} catch (error) {
await this.createAgentLifecycleDispatch.cleanupCreatedWorktreeAfterFailedAgentCreate({
createdWorktree: createdWorktreeForCleanup,
createdAgentId,
});
const wireError = toWorktreeWireError(error);
this.sessionLogger.error({ err: error }, "Failed to create agent");
if (requestId) {