Restrict reusable workspace candidates

This commit is contained in:
Dotta committed 2026-05-23 20:52:41 +00:00
1 parent 4c9219559a
commit e35daf5256
2 files changed
+80 -1

No files matched your search

@@ -343,6 +343,83 @@ describeEmbeddedPostgres("executionWorkspaceService.getCloseReadiness", () => {
expect(readExecutionWorkspaceConfig(byId.get(untouchedWorkspaceId) ?? null)).toBeNull();
});
it("limits reusable summaries to open non-shared execution workspaces", async () => {
const companyId = randomUUID();
const projectId = randomUUID();
const openWorkspaceId = randomUUID();
const sharedWorkspaceId = randomUUID();
const closedWorkspaceId = randomUUID();
await db.insert(companies).values({
id: companyId,
name: "Paperclip",
issuePrefix: "PAP",
requireBoardApprovalForNewAgents: false,
});
await db.insert(projects).values({
id: projectId,
companyId,
name: "Reusable workspaces",
status: "in_progress",
executionWorkspacePolicy: {
enabled: true,
},
});
await db.insert(executionWorkspaces).values([
{
id: openWorkspaceId,
companyId,
projectId,
mode: "isolated_workspace",
strategyType: "git_worktree",
name: "Open isolated workspace",
status: "idle",
providerType: "git_worktree",
cwd: "/tmp/open-workspace",
branchName: "paperclip/open",
},
{
id: sharedWorkspaceId,
companyId,
projectId,
mode: "shared_workspace",
strategyType: "project_primary",
name: "Shared session",
status: "active",
providerType: "local_fs",
cwd: "/tmp/project-primary",
},
{
id: closedWorkspaceId,
companyId,
projectId,
mode: "isolated_workspace",
strategyType: "git_worktree",
name: "Closed isolated workspace",
status: "active",
providerType: "git_worktree",
cwd: "/tmp/closed-workspace",
closedAt: new Date("2026-05-23T20:00:00.000Z"),
},
]);
const summaries = await svc.listSummaries(companyId, {
projectId,
reuseEligible: true,
});
expect(summaries).toEqual([
expect.objectContaining({
id: openWorkspaceId,
name: "Open isolated workspace",
mode: "isolated_workspace",
status: "idle",
cwd: "/tmp/open-workspace",
branchName: "paperclip/open",
}),
]);
});
it("warns about dirty and unmerged git worktrees and reports cleanup actions", async () => {
const repoRoot = await createTempRepo();
tempDirs.add(repoRoot);
+3 -1
View File
@@ -2,7 +2,7 @@ import { execFile } from "node:child_process";
import fs from "node:fs/promises";
import path from "node:path";
import { promisify } from "node:util";
import { and, desc, eq, inArray } from "drizzle-orm";
import { and, desc, eq, inArray, isNull } from "drizzle-orm";
import type { Db } from "@paperclipai/db";
import { executionWorkspaces, issues, projects, projectWorkspaces, workspaceRuntimeServices } from "@paperclipai/db";
import type {
@@ -418,6 +418,8 @@ export function executionWorkspaceService(db: Db) {
}
if (filters?.reuseEligible) {
conditions.push(inArray(executionWorkspaces.status, ["active", "idle", "in_review"]));
conditions.push(isNull(executionWorkspaces.closedAt));
conditions.push(inArray(executionWorkspaces.mode, ["isolated_workspace", "operator_branch", "adapter_managed", "cloud_sandbox"]));
}
return conditions;
}