Emit running state when workspace setup begins
This commit is contained in:
@@ -1,10 +1,14 @@
|
|||||||
|
import { rm, writeFile } from "node:fs/promises";
|
||||||
import { test, expect } from "./fixtures";
|
import { test, expect } from "./fixtures";
|
||||||
import { createTempGitRepo } from "./helpers/workspace";
|
import { createTempGitRepo } from "./helpers/workspace";
|
||||||
|
import { waitForWorkspaceTabsVisible } from "./helpers/workspace-tabs";
|
||||||
import {
|
import {
|
||||||
connectWorkspaceSetupClient,
|
connectWorkspaceSetupClient,
|
||||||
createWorkspaceFromSidebar,
|
createWorkspaceFromSidebar,
|
||||||
createWorkspaceThroughDaemon,
|
createWorkspaceThroughDaemon,
|
||||||
|
expectSetupLogContains,
|
||||||
expectSetupPanel,
|
expectSetupPanel,
|
||||||
|
expectSetupStatus,
|
||||||
openHomeWithProject,
|
openHomeWithProject,
|
||||||
seedProjectForWorkspaceSetup,
|
seedProjectForWorkspaceSetup,
|
||||||
waitForWorkspaceSetupProgress,
|
waitForWorkspaceSetupProgress,
|
||||||
@@ -34,6 +38,58 @@ test.describe("Workspace setup streaming", () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("runs setup through the sidebar and leaves the workspace usable", async ({ page }) => {
|
||||||
|
const setupTriggerPath = `/tmp/setup-trigger-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
||||||
|
const client = await connectWorkspaceSetupClient();
|
||||||
|
const repo = await createTempGitRepo("setup-ui-flow-", {
|
||||||
|
paseoConfig: {
|
||||||
|
worktree: {
|
||||||
|
setup: [
|
||||||
|
`sh -c 'while [ ! -f "${setupTriggerPath}" ]; do sleep 0.2; done; echo starting setup; sleep 1; echo loading dependencies; sleep 1; echo setup complete'`,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
files: [{ path: "src/index.ts", content: "export const ready = true;\n" }],
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
await seedProjectForWorkspaceSetup(client, repo.path);
|
||||||
|
await openHomeWithProject(page, repo.path);
|
||||||
|
await createWorkspaceFromSidebar(page, repo.path);
|
||||||
|
|
||||||
|
await expectSetupPanel(page);
|
||||||
|
await expectSetupStatus(page, "Running");
|
||||||
|
await writeFile(setupTriggerPath, "start\n");
|
||||||
|
await expectSetupLogContains(page, "starting setup");
|
||||||
|
await expectSetupLogContains(page, "loading dependencies");
|
||||||
|
await expectSetupStatus(page, "Completed");
|
||||||
|
await expectSetupLogContains(page, "setup complete");
|
||||||
|
|
||||||
|
await waitForWorkspaceTabsVisible(page);
|
||||||
|
await expect(page.getByRole("textbox", { name: "Message agent..." }).first()).toBeVisible({
|
||||||
|
timeout: 30_000,
|
||||||
|
});
|
||||||
|
|
||||||
|
const explorerToggle = page.getByTestId("workspace-explorer-toggle").first();
|
||||||
|
if ((await explorerToggle.getAttribute("aria-expanded")) !== "true") {
|
||||||
|
await explorerToggle.click();
|
||||||
|
}
|
||||||
|
await expect(explorerToggle).toHaveAttribute("aria-expanded", "true", { timeout: 30_000 });
|
||||||
|
await page.getByTestId("explorer-tab-files").click();
|
||||||
|
await expect(page.getByTestId("file-explorer-tree-scroll")).toBeVisible({ timeout: 30_000 });
|
||||||
|
await expect(page.getByText("README.md", { exact: true }).first()).toBeVisible({
|
||||||
|
timeout: 30_000,
|
||||||
|
});
|
||||||
|
await expect(page.getByText("src", { exact: true }).first()).toBeVisible({
|
||||||
|
timeout: 30_000,
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
await rm(setupTriggerPath, { force: true });
|
||||||
|
await client.close();
|
||||||
|
await repo.cleanup();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
test("streams running and completed setup snapshots for a successful setup", async () => {
|
test("streams running and completed setup snapshots for a successful setup", async () => {
|
||||||
const client = await connectWorkspaceSetupClient();
|
const client = await connectWorkspaceSetupClient();
|
||||||
const repo = await createTempGitRepo("setup-success-", {
|
const repo = await createTempGitRepo("setup-success-", {
|
||||||
@@ -46,7 +102,14 @@ test.describe("Workspace setup streaming", () => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await seedProjectForWorkspaceSetup(client, repo.path);
|
await seedProjectForWorkspaceSetup(client, repo.path);
|
||||||
const running = waitForWorkspaceSetupProgress(client, (payload) => payload.status === "running");
|
const initialRunning = waitForWorkspaceSetupProgress(
|
||||||
|
client,
|
||||||
|
(payload) => payload.status === "running" && payload.detail.log === "",
|
||||||
|
);
|
||||||
|
const runningWithOutput = waitForWorkspaceSetupProgress(
|
||||||
|
client,
|
||||||
|
(payload) => payload.status === "running" && payload.detail.log.includes("starting setup"),
|
||||||
|
);
|
||||||
const completed = waitForWorkspaceSetupProgress(
|
const completed = waitForWorkspaceSetupProgress(
|
||||||
client,
|
client,
|
||||||
(payload) => payload.status === "completed" && payload.detail.log.includes("setup complete"),
|
(payload) => payload.status === "completed" && payload.detail.log.includes("setup complete"),
|
||||||
@@ -57,9 +120,11 @@ test.describe("Workspace setup streaming", () => {
|
|||||||
worktreeSlug: "workspace-setup-success",
|
worktreeSlug: "workspace-setup-success",
|
||||||
});
|
});
|
||||||
|
|
||||||
const runningPayload = await running;
|
const initialPayload = await initialRunning;
|
||||||
|
const runningPayload = await runningWithOutput;
|
||||||
const completedPayload = await completed;
|
const completedPayload = await completed;
|
||||||
|
|
||||||
|
expect(initialPayload.detail.log).toBe("");
|
||||||
expect(runningPayload.detail.log).toContain("starting setup");
|
expect(runningPayload.detail.log).toContain("starting setup");
|
||||||
expect(completedPayload.detail.log).toContain("setup complete");
|
expect(completedPayload.detail.log).toContain("setup complete");
|
||||||
expect(completedPayload.error).toBeNull();
|
expect(completedPayload.error).toBeNull();
|
||||||
|
|||||||
@@ -5557,9 +5557,8 @@ export class Session {
|
|||||||
private async createPaseoWorktreeInBackground(options: {
|
private async createPaseoWorktreeInBackground(options: {
|
||||||
requestCwd: string;
|
requestCwd: string;
|
||||||
repoRoot: string;
|
repoRoot: string;
|
||||||
baseBranch: string;
|
worktree: { branchName: string; worktreePath: string };
|
||||||
slug: string;
|
shouldBootstrap: boolean;
|
||||||
worktreePath: string;
|
|
||||||
}): Promise<void> {
|
}): Promise<void> {
|
||||||
return createWorktreeInBackgroundSession(
|
return createWorktreeInBackgroundSession(
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ describe("createPaseoWorktreeInBackground", () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test("emits a single completed snapshot for no-setup workspaces and then launches services", async () => {
|
test("emits running then completed snapshots for no-setup workspaces and then launches services", async () => {
|
||||||
const { tempDir, repoDir } = createGitRepo({
|
const { tempDir, repoDir } = createGitRepo({
|
||||||
paseoConfig: {
|
paseoConfig: {
|
||||||
services: {
|
services: {
|
||||||
@@ -141,8 +141,20 @@ describe("createPaseoWorktreeInBackground", () => {
|
|||||||
(message): message is Extract<SessionOutboundMessage, { type: "workspace_setup_progress" }> =>
|
(message): message is Extract<SessionOutboundMessage, { type: "workspace_setup_progress" }> =>
|
||||||
message.type === "workspace_setup_progress",
|
message.type === "workspace_setup_progress",
|
||||||
);
|
);
|
||||||
expect(progressMessages).toHaveLength(1);
|
expect(progressMessages).toHaveLength(2);
|
||||||
expect(progressMessages[0]?.payload).toMatchObject({
|
expect(progressMessages[0]?.payload).toMatchObject({
|
||||||
|
workspaceId: worktreePath,
|
||||||
|
status: "running",
|
||||||
|
error: null,
|
||||||
|
detail: {
|
||||||
|
type: "worktree_setup",
|
||||||
|
worktreePath,
|
||||||
|
branchName: "feature-no-setup",
|
||||||
|
log: "",
|
||||||
|
commands: [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(progressMessages[1]?.payload).toMatchObject({
|
||||||
workspaceId: worktreePath,
|
workspaceId: worktreePath,
|
||||||
status: "completed",
|
status: "completed",
|
||||||
error: null,
|
error: null,
|
||||||
@@ -200,10 +212,12 @@ describe("createPaseoWorktreeInBackground", () => {
|
|||||||
(message): message is Extract<SessionOutboundMessage, { type: "workspace_setup_progress" }> =>
|
(message): message is Extract<SessionOutboundMessage, { type: "workspace_setup_progress" }> =>
|
||||||
message.type === "workspace_setup_progress",
|
message.type === "workspace_setup_progress",
|
||||||
);
|
);
|
||||||
expect(progressMessages).toHaveLength(1);
|
expect(progressMessages).toHaveLength(2);
|
||||||
expect(progressMessages[0]?.payload.status).toBe("failed");
|
expect(progressMessages[0]?.payload.status).toBe("running");
|
||||||
expect(progressMessages[0]?.payload.error).toContain("does-not-exist");
|
expect(progressMessages[0]?.payload.error).toBeNull();
|
||||||
expect(progressMessages[0]?.payload.detail.commands).toEqual([]);
|
expect(progressMessages[1]?.payload.status).toBe("failed");
|
||||||
|
expect(progressMessages[1]?.payload.error).toContain("does-not-exist");
|
||||||
|
expect(progressMessages[1]?.payload.detail.commands).toEqual([]);
|
||||||
expect(archiveWorkspaceRecord).toHaveBeenCalledWith(worktreePath);
|
expect(archiveWorkspaceRecord).toHaveBeenCalledWith(worktreePath);
|
||||||
expect(emitWorkspaceUpdateForCwd).toHaveBeenCalledWith(worktreePath);
|
expect(emitWorkspaceUpdateForCwd).toHaveBeenCalledWith(worktreePath);
|
||||||
});
|
});
|
||||||
@@ -250,6 +264,18 @@ describe("createPaseoWorktreeInBackground", () => {
|
|||||||
message.type === "workspace_setup_progress",
|
message.type === "workspace_setup_progress",
|
||||||
);
|
);
|
||||||
expect(progressMessages.length).toBeGreaterThan(1);
|
expect(progressMessages.length).toBeGreaterThan(1);
|
||||||
|
expect(progressMessages[0]?.payload).toMatchObject({
|
||||||
|
workspaceId: worktreePath,
|
||||||
|
status: "running",
|
||||||
|
error: null,
|
||||||
|
detail: {
|
||||||
|
type: "worktree_setup",
|
||||||
|
worktreePath,
|
||||||
|
branchName: "feature-running-setup",
|
||||||
|
log: "",
|
||||||
|
commands: [],
|
||||||
|
},
|
||||||
|
});
|
||||||
expect(progressMessages.at(-1)?.payload.status).toBe("completed");
|
expect(progressMessages.at(-1)?.payload.status).toBe("completed");
|
||||||
|
|
||||||
const runningMessages = progressMessages.filter((message) => message.payload.status === "running");
|
const runningMessages = progressMessages.filter((message) => message.payload.status === "running");
|
||||||
@@ -258,8 +284,11 @@ describe("createPaseoWorktreeInBackground", () => {
|
|||||||
progressMessages.findIndex((message) => message.payload.status === "completed"),
|
progressMessages.findIndex((message) => message.payload.status === "completed"),
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(runningMessages[0]?.payload.detail.log).toContain("phase-one");
|
const setupOutputMessage = runningMessages.find((message) =>
|
||||||
expect(runningMessages[0]?.payload.detail.commands[0]).toMatchObject({
|
message.payload.detail.log.includes("phase-one"),
|
||||||
|
);
|
||||||
|
expect(setupOutputMessage?.payload.detail.log).toContain("phase-one");
|
||||||
|
expect(setupOutputMessage?.payload.detail.commands[0]).toMatchObject({
|
||||||
index: 1,
|
index: 1,
|
||||||
command: 'sh -c "printf \'phase-one\\\\n\'; sleep 0.1; printf \'phase-two\\\\n\'"',
|
command: 'sh -c "printf \'phase-one\\\\n\'; sleep 0.1; printf \'phase-two\\\\n\'"',
|
||||||
status: "running",
|
status: "running",
|
||||||
@@ -284,71 +313,7 @@ describe("createPaseoWorktreeInBackground", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test("keeps setup completed when service launch fails afterward", async () => {
|
test("emits completed when reusing an existing worktree without bootstrapping", async () => {
|
||||||
const { tempDir, repoDir } = createGitRepo({
|
|
||||||
paseoConfig: {
|
|
||||||
services: {
|
|
||||||
web: {
|
|
||||||
command: "npm run dev",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
cleanupPaths.push(tempDir);
|
|
||||||
|
|
||||||
const paseoHome = path.join(tempDir, ".paseo");
|
|
||||||
const worktreePath = await computeWorktreePath(repoDir, "feature-service-failure", paseoHome);
|
|
||||||
const emitted: SessionOutboundMessage[] = [];
|
|
||||||
const routeStore = new ServiceRouteStore();
|
|
||||||
const logger = createLogger();
|
|
||||||
const terminalManager = createTerminalManagerStub({
|
|
||||||
createTerminal: async () => {
|
|
||||||
throw new Error("terminal spawn failed");
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const emitWorkspaceUpdateForCwd = vi.fn(async () => {});
|
|
||||||
const archiveWorkspaceRecord = vi.fn(async () => {});
|
|
||||||
|
|
||||||
await createPaseoWorktreeInBackground(
|
|
||||||
{
|
|
||||||
paseoHome,
|
|
||||||
emitWorkspaceUpdateForCwd,
|
|
||||||
emit: (message) => emitted.push(message),
|
|
||||||
sessionLogger: logger,
|
|
||||||
terminalManager: terminalManager.manager,
|
|
||||||
archiveWorkspaceRecord,
|
|
||||||
serviceRouteStore: routeStore,
|
|
||||||
daemonPort: 6767,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
requestCwd: repoDir,
|
|
||||||
repoRoot: repoDir,
|
|
||||||
baseBranch: "main",
|
|
||||||
slug: "feature-service-failure",
|
|
||||||
worktreePath,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
const progressMessages = emitted.filter(
|
|
||||||
(message): message is Extract<SessionOutboundMessage, { type: "workspace_setup_progress" }> =>
|
|
||||||
message.type === "workspace_setup_progress",
|
|
||||||
);
|
|
||||||
expect(progressMessages).toHaveLength(1);
|
|
||||||
expect(progressMessages[0]?.payload.status).toBe("completed");
|
|
||||||
expect(progressMessages[0]?.payload.error).toBeNull();
|
|
||||||
expect(emitted.some((message) => message.type === "workspace_setup_progress" && message.payload.status === "failed")).toBe(false);
|
|
||||||
expect(logger.warn).toHaveBeenCalledWith(
|
|
||||||
expect.objectContaining({
|
|
||||||
err: expect.any(Error),
|
|
||||||
worktreePath,
|
|
||||||
}),
|
|
||||||
"Failed to spawn worktree services after workspace setup completed",
|
|
||||||
);
|
|
||||||
expect(archiveWorkspaceRecord).not.toHaveBeenCalled();
|
|
||||||
expect(emitWorkspaceUpdateForCwd).toHaveBeenCalledWith(worktreePath);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("reused existing worktrees do not rerun setup or spawn services", async () => {
|
|
||||||
const { tempDir, repoDir } = createGitRepo({
|
const { tempDir, repoDir } = createGitRepo({
|
||||||
paseoConfig: {
|
paseoConfig: {
|
||||||
worktree: {
|
worktree: {
|
||||||
@@ -400,9 +365,28 @@ describe("createPaseoWorktreeInBackground", () => {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(
|
const progressMessages = emitted.filter(
|
||||||
emitted.some((message) => message.type === "workspace_setup_progress"),
|
(message): message is Extract<SessionOutboundMessage, { type: "workspace_setup_progress" }> =>
|
||||||
).toBe(false);
|
message.type === "workspace_setup_progress",
|
||||||
|
);
|
||||||
|
expect(progressMessages).toHaveLength(2);
|
||||||
|
expect(progressMessages[0]?.payload).toMatchObject({
|
||||||
|
workspaceId: existingWorktree.worktreePath,
|
||||||
|
status: "running",
|
||||||
|
error: null,
|
||||||
|
});
|
||||||
|
expect(progressMessages[1]?.payload).toMatchObject({
|
||||||
|
workspaceId: existingWorktree.worktreePath,
|
||||||
|
status: "completed",
|
||||||
|
error: null,
|
||||||
|
detail: {
|
||||||
|
type: "worktree_setup",
|
||||||
|
worktreePath: existingWorktree.worktreePath,
|
||||||
|
branchName: "reused-worktree",
|
||||||
|
log: "",
|
||||||
|
commands: [],
|
||||||
|
},
|
||||||
|
});
|
||||||
expect(routeStore.listRoutes()).toEqual([]);
|
expect(routeStore.listRoutes()).toEqual([]);
|
||||||
expect(terminalManager.terminals).toHaveLength(0);
|
expect(terminalManager.terminals).toHaveLength(0);
|
||||||
expect(
|
expect(
|
||||||
@@ -412,4 +396,71 @@ describe("createPaseoWorktreeInBackground", () => {
|
|||||||
expect(archiveWorkspaceRecord).not.toHaveBeenCalled();
|
expect(archiveWorkspaceRecord).not.toHaveBeenCalled();
|
||||||
expect(emitWorkspaceUpdateForCwd).toHaveBeenCalledWith(existingWorktree.worktreePath);
|
expect(emitWorkspaceUpdateForCwd).toHaveBeenCalledWith(existingWorktree.worktreePath);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("keeps setup completed when service launch fails afterward", async () => {
|
||||||
|
const { tempDir, repoDir } = createGitRepo({
|
||||||
|
paseoConfig: {
|
||||||
|
services: {
|
||||||
|
web: {
|
||||||
|
command: "npm run dev",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
cleanupPaths.push(tempDir);
|
||||||
|
|
||||||
|
const paseoHome = path.join(tempDir, ".paseo");
|
||||||
|
const worktreePath = await computeWorktreePath(repoDir, "feature-service-failure", paseoHome);
|
||||||
|
const emitted: SessionOutboundMessage[] = [];
|
||||||
|
const routeStore = new ServiceRouteStore();
|
||||||
|
const logger = createLogger();
|
||||||
|
const terminalManager = createTerminalManagerStub({
|
||||||
|
createTerminal: async () => {
|
||||||
|
throw new Error("terminal spawn failed");
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const emitWorkspaceUpdateForCwd = vi.fn(async () => {});
|
||||||
|
const archiveWorkspaceRecord = vi.fn(async () => {});
|
||||||
|
|
||||||
|
await createPaseoWorktreeInBackground(
|
||||||
|
{
|
||||||
|
paseoHome,
|
||||||
|
emitWorkspaceUpdateForCwd,
|
||||||
|
emit: (message) => emitted.push(message),
|
||||||
|
sessionLogger: logger,
|
||||||
|
terminalManager: terminalManager.manager,
|
||||||
|
archiveWorkspaceRecord,
|
||||||
|
serviceRouteStore: routeStore,
|
||||||
|
daemonPort: 6767,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
requestCwd: repoDir,
|
||||||
|
repoRoot: repoDir,
|
||||||
|
baseBranch: "main",
|
||||||
|
slug: "feature-service-failure",
|
||||||
|
worktreePath,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const progressMessages = emitted.filter(
|
||||||
|
(message): message is Extract<SessionOutboundMessage, { type: "workspace_setup_progress" }> =>
|
||||||
|
message.type === "workspace_setup_progress",
|
||||||
|
);
|
||||||
|
expect(progressMessages).toHaveLength(2);
|
||||||
|
expect(progressMessages[0]?.payload.status).toBe("running");
|
||||||
|
expect(progressMessages[0]?.payload.error).toBeNull();
|
||||||
|
expect(progressMessages[1]?.payload.status).toBe("completed");
|
||||||
|
expect(progressMessages[1]?.payload.error).toBeNull();
|
||||||
|
expect(emitted.some((message) => message.type === "workspace_setup_progress" && message.payload.status === "failed")).toBe(false);
|
||||||
|
expect(logger.warn).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
err: expect.any(Error),
|
||||||
|
worktreePath,
|
||||||
|
}),
|
||||||
|
"Failed to spawn worktree services after workspace setup completed",
|
||||||
|
);
|
||||||
|
expect(archiveWorkspaceRecord).not.toHaveBeenCalled();
|
||||||
|
expect(emitWorkspaceUpdateForCwd).toHaveBeenCalledWith(worktreePath);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import {
|
|||||||
createWorktreeSetupProgressAccumulator,
|
createWorktreeSetupProgressAccumulator,
|
||||||
getWorktreeSetupProgressResults,
|
getWorktreeSetupProgressResults,
|
||||||
spawnWorktreeServices,
|
spawnWorktreeServices,
|
||||||
|
type CreateAgentWorktreeResult,
|
||||||
} from "./worktree-bootstrap.js";
|
} from "./worktree-bootstrap.js";
|
||||||
import type { TerminalManager } from "../terminal/terminal-manager.js";
|
import type { TerminalManager } from "../terminal/terminal-manager.js";
|
||||||
import type { ServiceRouteStore } from "./service-proxy.js";
|
import type { ServiceRouteStore } from "./service-proxy.js";
|
||||||
@@ -139,9 +140,8 @@ type HandleCreatePaseoWorktreeRequestDependencies = {
|
|||||||
createPaseoWorktreeInBackground: (options: {
|
createPaseoWorktreeInBackground: (options: {
|
||||||
requestCwd: string;
|
requestCwd: string;
|
||||||
repoRoot: string;
|
repoRoot: string;
|
||||||
baseBranch: string;
|
worktree: WorktreeConfig;
|
||||||
slug: string;
|
shouldBootstrap: boolean;
|
||||||
worktreePath: string;
|
|
||||||
}) => Promise<void>;
|
}) => Promise<void>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -598,10 +598,17 @@ export async function handleCreatePaseoWorktreeRequest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const worktreePath = await computeWorktreePath(repoRoot, normalizedSlug, dependencies.paseoHome);
|
const worktreePath = await computeWorktreePath(repoRoot, normalizedSlug, dependencies.paseoHome);
|
||||||
|
const createdWorktree = await createAgentWorktree({
|
||||||
|
cwd: repoRoot,
|
||||||
|
branchName: normalizedSlug,
|
||||||
|
baseBranch,
|
||||||
|
worktreeSlug: normalizedSlug,
|
||||||
|
paseoHome: dependencies.paseoHome,
|
||||||
|
});
|
||||||
const workspace = await dependencies.registerPendingWorktreeWorkspace({
|
const workspace = await dependencies.registerPendingWorktreeWorkspace({
|
||||||
repoRoot,
|
repoRoot,
|
||||||
worktreePath,
|
worktreePath: createdWorktree.worktree.worktreePath,
|
||||||
branchName: normalizedSlug,
|
branchName: createdWorktree.worktree.branchName,
|
||||||
});
|
});
|
||||||
const descriptor = await dependencies.describeWorkspaceRecord(workspace);
|
const descriptor = await dependencies.describeWorkspaceRecord(workspace);
|
||||||
dependencies.emit({
|
dependencies.emit({
|
||||||
@@ -617,9 +624,8 @@ export async function handleCreatePaseoWorktreeRequest(
|
|||||||
void dependencies.createPaseoWorktreeInBackground({
|
void dependencies.createPaseoWorktreeInBackground({
|
||||||
requestCwd: request.cwd,
|
requestCwd: request.cwd,
|
||||||
repoRoot,
|
repoRoot,
|
||||||
baseBranch,
|
worktree: createdWorktree.worktree,
|
||||||
slug: normalizedSlug,
|
shouldBootstrap: createdWorktree.shouldBootstrap,
|
||||||
worktreePath,
|
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const message = error instanceof Error ? error.message : "Failed to create worktree";
|
const message = error instanceof Error ? error.message : "Failed to create worktree";
|
||||||
@@ -644,15 +650,11 @@ export async function createPaseoWorktreeInBackground(
|
|||||||
options: {
|
options: {
|
||||||
requestCwd: string;
|
requestCwd: string;
|
||||||
repoRoot: string;
|
repoRoot: string;
|
||||||
baseBranch: string;
|
worktree: WorktreeConfig;
|
||||||
slug: string;
|
shouldBootstrap: boolean;
|
||||||
worktreePath: string;
|
|
||||||
},
|
},
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
let worktree: WorktreeConfig = {
|
let worktree: WorktreeConfig = options.worktree;
|
||||||
branchName: options.slug,
|
|
||||||
worktreePath: options.worktreePath,
|
|
||||||
};
|
|
||||||
let setupResults: WorktreeSetupCommandResult[] = [];
|
let setupResults: WorktreeSetupCommandResult[] = [];
|
||||||
let setupStarted = false;
|
let setupStarted = false;
|
||||||
const progressAccumulator = createWorktreeSetupProgressAccumulator();
|
const progressAccumulator = createWorktreeSetupProgressAccumulator();
|
||||||
@@ -676,16 +678,10 @@ export async function createPaseoWorktreeInBackground(
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
try {
|
try {
|
||||||
const createdWorktree = await createAgentWorktree({
|
emitSetupProgress("running", null);
|
||||||
cwd: options.repoRoot,
|
|
||||||
branchName: options.slug,
|
|
||||||
baseBranch: options.baseBranch,
|
|
||||||
worktreeSlug: options.slug,
|
|
||||||
paseoHome: dependencies.paseoHome,
|
|
||||||
});
|
|
||||||
worktree = createdWorktree.worktree;
|
|
||||||
|
|
||||||
if (!createdWorktree.shouldBootstrap) {
|
if (!options.shouldBootstrap) {
|
||||||
|
emitSetupProgress("completed", null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -725,11 +721,7 @@ export async function createPaseoWorktreeInBackground(
|
|||||||
emitSetupProgress("failed", message);
|
emitSetupProgress("failed", message);
|
||||||
|
|
||||||
if (!setupStarted) {
|
if (!setupStarted) {
|
||||||
await dependencies.archiveWorkspaceRecord(normalizePersistedWorkspaceId(options.worktreePath));
|
await dependencies.archiveWorkspaceRecord(normalizePersistedWorkspaceId(worktree.worktreePath));
|
||||||
worktree = {
|
|
||||||
...worktree,
|
|
||||||
worktreePath: options.worktreePath,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies.sessionLogger.error(
|
dependencies.sessionLogger.error(
|
||||||
@@ -737,8 +729,8 @@ export async function createPaseoWorktreeInBackground(
|
|||||||
err: error,
|
err: error,
|
||||||
cwd: options.requestCwd,
|
cwd: options.requestCwd,
|
||||||
repoRoot: options.repoRoot,
|
repoRoot: options.repoRoot,
|
||||||
worktreeSlug: options.slug,
|
worktreeSlug: worktree.branchName,
|
||||||
worktreePath: options.worktreePath,
|
worktreePath: worktree.worktreePath,
|
||||||
setupStarted,
|
setupStarted,
|
||||||
},
|
},
|
||||||
"Background worktree creation failed",
|
"Background worktree creation failed",
|
||||||
@@ -771,7 +763,7 @@ export async function createPaseoWorktreeInBackground(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
await dependencies.emitWorkspaceUpdateForCwd(options.worktreePath);
|
await dependencies.emitWorkspaceUpdateForCwd(worktree.worktreePath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user