mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-24 10:12:44 +00:00
fix(server): keep a new worktree open when its paseo.json cannot be parsed (#6036)
* fix(server): keep workspaces available after setup config errors * refactor(server): drop the archive dependency from worktree setup Setup no longer archives a workspace when it fails, so the setup workflows no longer take archiveWorkspaceRecord. Co-authored-by: Bae Seongmin <83870598+3ae3ae@users.noreply.github.com> * test(server): stop passing the removed archive dependency to the worktree workflow * test(server): check paseo.json survives without comparing line endings Git checks the fixture out with CRLF on Windows, so comparing its exact contents failed there. --------- Co-authored-by: 3ae3ae <ogyshjsm@naver.com> Co-authored-by: Bae Seongmin <83870598+3ae3ae@users.noreply.github.com> Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
This commit is contained in:
co-authored by
3ae3ae
Bae Seongmin
parent
485221b739
commit
409b8f9312
@@ -203,6 +203,41 @@ test.describe("Workspace setup streaming", () => {
|
||||
}
|
||||
});
|
||||
|
||||
test("keeps a workspace usable when its setup config cannot be parsed", async ({ page }) => {
|
||||
const client = await connectWorkspaceSetupClient();
|
||||
const repo = await createTempGitRepo("setup-invalid-config-", {
|
||||
files: [{ path: "paseo.json", content: "{ invalid json\n" }],
|
||||
});
|
||||
|
||||
try {
|
||||
await seedProjectForWorkspaceSetup(client, repo.path);
|
||||
const failed = waitForWorkspaceSetupProgress(
|
||||
client,
|
||||
(payload) => payload.status === "failed",
|
||||
);
|
||||
const workspace = await createWorkspaceThroughDaemon(client, {
|
||||
cwd: repo.path,
|
||||
worktreeSlug: "workspace-setup-invalid-config",
|
||||
});
|
||||
const failedPayload = await failed;
|
||||
expect(failedPayload.error).toContain("Failed to parse paseo.json");
|
||||
expect(failedPayload.detail.commands).toEqual([]);
|
||||
|
||||
await openHomeWithProject(page, repo.path);
|
||||
await navigateToWorkspaceViaSidebar(page, workspace.id);
|
||||
await expectFailedSetupTabSeededInMainPane(page, workspace.id);
|
||||
await expect(page.getByText(/Failed to parse paseo\.json at/)).toBeVisible();
|
||||
await closeSetupTab(page, workspace.id);
|
||||
await clickNewChat(page);
|
||||
await expectComposerVisible(page);
|
||||
await openFileExplorer(page);
|
||||
await expectExplorerEntryVisible(page, "paseo.json");
|
||||
} finally {
|
||||
await client.close();
|
||||
await repo.cleanup();
|
||||
}
|
||||
});
|
||||
|
||||
daemonTest("emits a completed empty snapshot when no setup commands exist", async () => {
|
||||
const client = await connectWorkspaceSetupClient();
|
||||
const repo = await createTempGitRepo("setup-none-");
|
||||
|
||||
@@ -806,7 +806,6 @@ function createPaseoWorktreeForMcpTest(options: {
|
||||
emit: () => {},
|
||||
sessionLogger: createTestLogger(),
|
||||
terminalManager: null,
|
||||
archiveWorkspaceRecord: async () => {},
|
||||
serviceProxy: null,
|
||||
scriptRuntimeStore: null,
|
||||
getDaemonTcpPort: null,
|
||||
|
||||
@@ -1170,7 +1170,6 @@ export async function createPaseoDaemon(
|
||||
emit: emitExternalSessionMessage,
|
||||
sessionLogger: logger,
|
||||
terminalManager,
|
||||
archiveWorkspaceRecord: archiveWorkspaceRecordExternal,
|
||||
serviceProxy,
|
||||
scriptRuntimeStore,
|
||||
getDaemonTcpPort: () => (boundListenTarget?.type === "tcp" ? boundListenTarget.port : null),
|
||||
|
||||
@@ -7253,7 +7253,6 @@ export class Session {
|
||||
emit: (message) => this.emit(message),
|
||||
sessionLogger: this.sessionLogger,
|
||||
terminalManager: this.terminalManager,
|
||||
archiveWorkspaceRecord: (workspaceId) => this.archiveWorkspaceRecord(workspaceId),
|
||||
serviceProxy: this.serviceProxy,
|
||||
scriptRuntimeStore: this.scriptRuntimeStore,
|
||||
getDaemonTcpPort: this.getDaemonTcpPort,
|
||||
@@ -7300,7 +7299,6 @@ export class Session {
|
||||
emit: (message) => this.emit(message),
|
||||
sessionLogger: this.sessionLogger,
|
||||
terminalManager: this.terminalManager,
|
||||
archiveWorkspaceRecord: (workspaceId) => this.archiveWorkspaceRecord(workspaceId),
|
||||
serviceProxy: this.serviceProxy,
|
||||
scriptRuntimeStore: this.scriptRuntimeStore,
|
||||
getDaemonTcpPort: this.getDaemonTcpPort,
|
||||
|
||||
@@ -115,7 +115,6 @@ function createWorkflowForRequestTest(options: {
|
||||
emit: () => {},
|
||||
sessionLogger: createLogger(),
|
||||
terminalManager: null,
|
||||
archiveWorkspaceRecord: async () => {},
|
||||
serviceProxy: null,
|
||||
scriptRuntimeStore: null,
|
||||
getDaemonTcpPort: null,
|
||||
@@ -489,7 +488,6 @@ describe("create-agent worktree setup boundary", () => {
|
||||
emit: (message) => emitted.push(message),
|
||||
sessionLogger: createLogger(),
|
||||
terminalManager: createTerminalManagerStub().manager,
|
||||
archiveWorkspaceRecord: async () => {},
|
||||
serviceProxy: null,
|
||||
scriptRuntimeStore: null,
|
||||
getDaemonTcpPort: null,
|
||||
@@ -540,7 +538,6 @@ describe("create-agent worktree setup boundary", () => {
|
||||
emit: (message) => workspaceSetupEvents.push(message),
|
||||
sessionLogger: createLogger(),
|
||||
terminalManager: null,
|
||||
archiveWorkspaceRecord: async () => {},
|
||||
serviceProxy: null,
|
||||
scriptRuntimeStore: null,
|
||||
getDaemonTcpPort: null,
|
||||
@@ -714,7 +711,6 @@ describe("runWorktreeSetupInBackground", () => {
|
||||
emit: () => {},
|
||||
sessionLogger: createLogger(),
|
||||
terminalManager: null,
|
||||
archiveWorkspaceRecord: async () => {},
|
||||
},
|
||||
{
|
||||
requestCwd: sourceWorkspaceCwd,
|
||||
@@ -759,7 +755,6 @@ describe("runWorktreeSetupInBackground", () => {
|
||||
const logger = createLogger();
|
||||
const terminalManager = createTerminalManagerStub();
|
||||
const emitWorkspaceUpdateForWorkspaceId = vi.fn(async () => {});
|
||||
const archiveWorkspaceRecord = vi.fn(async () => {});
|
||||
|
||||
await runWorktreeSetupInBackground(
|
||||
{
|
||||
@@ -770,7 +765,6 @@ describe("runWorktreeSetupInBackground", () => {
|
||||
emit: (message) => emitted.push(message),
|
||||
sessionLogger: logger,
|
||||
terminalManager: terminalManager.manager,
|
||||
archiveWorkspaceRecord,
|
||||
},
|
||||
{
|
||||
requestCwd: repoDir,
|
||||
@@ -828,11 +822,10 @@ describe("runWorktreeSetupInBackground", () => {
|
||||
});
|
||||
|
||||
expect(terminalManager.terminals).toHaveLength(0);
|
||||
expect(archiveWorkspaceRecord).not.toHaveBeenCalled();
|
||||
expect(emitWorkspaceUpdateForWorkspaceId).toHaveBeenCalledWith("42");
|
||||
});
|
||||
|
||||
test("archives the pending workspace and emits a failed snapshot when setup cannot start", async () => {
|
||||
test("keeps the workspace available and emits a failed snapshot when setup cannot start", async () => {
|
||||
const { tempDir, repoDir } = createGitRepo();
|
||||
cleanupPaths.push(tempDir);
|
||||
|
||||
@@ -857,7 +850,6 @@ describe("runWorktreeSetupInBackground", () => {
|
||||
const snapshots = new Map<string, unknown>();
|
||||
const logger = createLogger();
|
||||
const emitWorkspaceUpdateForWorkspaceId = vi.fn(async () => {});
|
||||
const archiveWorkspaceRecord = vi.fn(async () => {});
|
||||
const workspaceId = "ws-broken-feature";
|
||||
|
||||
await runWorktreeSetupInBackground(
|
||||
@@ -869,7 +861,6 @@ describe("runWorktreeSetupInBackground", () => {
|
||||
emit: (message) => emitted.push(message),
|
||||
sessionLogger: logger,
|
||||
terminalManager: null,
|
||||
archiveWorkspaceRecord,
|
||||
},
|
||||
{
|
||||
requestCwd: repoDir,
|
||||
@@ -901,7 +892,8 @@ describe("runWorktreeSetupInBackground", () => {
|
||||
status: "failed",
|
||||
error: expect.stringMatching(/Failed to parse paseo\.json at .*paseo\.json/),
|
||||
});
|
||||
expect(archiveWorkspaceRecord).toHaveBeenCalledWith(workspaceId);
|
||||
expect(existsSync(worktreePath)).toBe(true);
|
||||
expect(existsSync(path.join(worktreePath, "paseo.json"))).toBe(true);
|
||||
expect(emitWorkspaceUpdateForWorkspaceId).toHaveBeenCalledWith(workspaceId);
|
||||
});
|
||||
|
||||
@@ -932,7 +924,6 @@ describe("runWorktreeSetupInBackground", () => {
|
||||
const snapshots = new Map<string, unknown>();
|
||||
const logger = createLogger();
|
||||
const emitWorkspaceUpdateForWorkspaceId = vi.fn(async () => {});
|
||||
const archiveWorkspaceRecord = vi.fn(async () => {});
|
||||
|
||||
await runWorktreeSetupInBackground(
|
||||
{
|
||||
@@ -943,7 +934,6 @@ describe("runWorktreeSetupInBackground", () => {
|
||||
emit: (message) => emitted.push(message),
|
||||
sessionLogger: logger,
|
||||
terminalManager: null,
|
||||
archiveWorkspaceRecord,
|
||||
},
|
||||
{
|
||||
requestCwd: repoDir,
|
||||
@@ -1056,7 +1046,6 @@ describe("runWorktreeSetupInBackground", () => {
|
||||
const logger = createLogger();
|
||||
const terminalManager = createTerminalManagerStub();
|
||||
const emitWorkspaceUpdateForWorkspaceId = vi.fn(async () => {});
|
||||
const archiveWorkspaceRecord = vi.fn(async () => {});
|
||||
|
||||
await runWorktreeSetupInBackground(
|
||||
{
|
||||
@@ -1067,7 +1056,6 @@ describe("runWorktreeSetupInBackground", () => {
|
||||
emit: (message) => emitted.push(message),
|
||||
sessionLogger: logger,
|
||||
terminalManager: terminalManager.manager,
|
||||
archiveWorkspaceRecord,
|
||||
},
|
||||
{
|
||||
requestCwd: repoDir,
|
||||
@@ -1116,7 +1104,6 @@ describe("runWorktreeSetupInBackground", () => {
|
||||
status: "completed",
|
||||
error: null,
|
||||
});
|
||||
expect(archiveWorkspaceRecord).not.toHaveBeenCalled();
|
||||
expect(emitWorkspaceUpdateForWorkspaceId).toHaveBeenCalledWith("44");
|
||||
});
|
||||
|
||||
@@ -1151,7 +1138,6 @@ describe("runWorktreeSetupInBackground", () => {
|
||||
},
|
||||
});
|
||||
const emitWorkspaceUpdateForWorkspaceId = vi.fn(async () => {});
|
||||
const archiveWorkspaceRecord = vi.fn(async () => {});
|
||||
|
||||
await runWorktreeSetupInBackground(
|
||||
{
|
||||
@@ -1162,7 +1148,6 @@ describe("runWorktreeSetupInBackground", () => {
|
||||
emit: (message) => emitted.push(message),
|
||||
sessionLogger: logger,
|
||||
terminalManager: terminalManager.manager,
|
||||
archiveWorkspaceRecord,
|
||||
},
|
||||
{
|
||||
requestCwd: repoDir,
|
||||
@@ -1202,7 +1187,6 @@ describe("runWorktreeSetupInBackground", () => {
|
||||
status: "completed",
|
||||
error: null,
|
||||
});
|
||||
expect(archiveWorkspaceRecord).not.toHaveBeenCalled();
|
||||
expect(emitWorkspaceUpdateForWorkspaceId).toHaveBeenCalledWith("45");
|
||||
});
|
||||
|
||||
@@ -1233,7 +1217,6 @@ describe("runWorktreeSetupInBackground", () => {
|
||||
const logger = createLogger();
|
||||
const terminalManager = createTerminalManagerStub();
|
||||
const emitWorkspaceUpdateForWorkspaceId = vi.fn(async () => {});
|
||||
const archiveWorkspaceRecord = vi.fn(async () => {});
|
||||
|
||||
await runWorktreeSetupInBackground(
|
||||
{
|
||||
@@ -1244,7 +1227,6 @@ describe("runWorktreeSetupInBackground", () => {
|
||||
emit: (message) => emitted.push(message),
|
||||
sessionLogger: logger,
|
||||
terminalManager: terminalManager.manager,
|
||||
archiveWorkspaceRecord,
|
||||
},
|
||||
{
|
||||
requestCwd: repoDir,
|
||||
@@ -1265,7 +1247,6 @@ describe("runWorktreeSetupInBackground", () => {
|
||||
status: "completed",
|
||||
error: null,
|
||||
});
|
||||
expect(archiveWorkspaceRecord).not.toHaveBeenCalled();
|
||||
expect(emitWorkspaceUpdateForWorkspaceId).toHaveBeenCalledWith("46");
|
||||
});
|
||||
|
||||
@@ -1427,7 +1408,6 @@ describe("runWorktreeSetupInBackground", () => {
|
||||
emit: (message: SessionOutboundMessage) => emitted.push(message),
|
||||
sessionLogger: createLogger(),
|
||||
terminalManager: terminalManager.manager,
|
||||
archiveWorkspaceRecord: vi.fn(async () => {}),
|
||||
serviceProxy: null,
|
||||
scriptRuntimeStore: null,
|
||||
getDaemonTcpPort: null,
|
||||
|
||||
@@ -108,7 +108,6 @@ interface CreatePaseoWorktreeInBackgroundDependencies {
|
||||
emit: EmitSessionMessage;
|
||||
sessionLogger: Logger;
|
||||
terminalManager: TerminalManager | null;
|
||||
archiveWorkspaceRecord: (workspaceId: string) => Promise<void>;
|
||||
serviceProxy: ServiceProxySubsystem | null;
|
||||
scriptRuntimeStore: WorkspaceScriptRuntimeStore | null;
|
||||
getDaemonTcpPort: (() => number | null) | null;
|
||||
@@ -825,7 +824,6 @@ export async function runWorktreeSetupInBackground(
|
||||
): Promise<void> {
|
||||
let worktree: WorktreeConfig = options.worktree;
|
||||
let setupResults: WorktreeSetupCommandResult[] = [];
|
||||
let setupStarted = false;
|
||||
const progressAccumulator = createWorktreeSetupProgressAccumulator();
|
||||
const workspaceId = options.workspaceId;
|
||||
|
||||
@@ -862,7 +860,6 @@ export async function runWorktreeSetupInBackground(
|
||||
const workspaceCwd = options.workspaceCwd ?? worktree.worktreePath;
|
||||
const setupCommands = getWorktreeSetupCommands(workspaceCwd);
|
||||
if (setupCommands.length === 0) {
|
||||
setupStarted = true;
|
||||
emitSetupProgress("completed", null);
|
||||
} else {
|
||||
const runtimeEnv = await resolveWorktreeRuntimeEnv({
|
||||
@@ -874,7 +871,6 @@ export async function runWorktreeSetupInBackground(
|
||||
cwd: workspaceCwd,
|
||||
env: runtimeEnv,
|
||||
});
|
||||
setupStarted = true;
|
||||
setupResults = await runWorktreeSetupCommands({
|
||||
worktreePath: workspaceCwd,
|
||||
branchName: worktree.branchName,
|
||||
@@ -906,10 +902,6 @@ export async function runWorktreeSetupInBackground(
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
emitSetupProgress("failed", message);
|
||||
|
||||
if (!setupStarted) {
|
||||
await dependencies.archiveWorkspaceRecord(options.workspaceId);
|
||||
}
|
||||
|
||||
dependencies.sessionLogger.error(
|
||||
{
|
||||
err: error,
|
||||
@@ -917,7 +909,6 @@ export async function runWorktreeSetupInBackground(
|
||||
repoRoot: options.repoRoot,
|
||||
worktreeSlug: worktree.branchName,
|
||||
worktreePath: worktree.worktreePath,
|
||||
setupStarted,
|
||||
},
|
||||
"Background worktree setup failed",
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user