From 287ba4babcb076225aac21c07901630f16600cfc Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Fri, 17 Jul 2026 06:28:31 +0000 Subject: [PATCH] fix(projects): preserve placement reshape compatibility --- .../src/server/agent/mcp-server.test.ts | 86 ++++++++++----- .../src/server/workspace-registry-model.ts | 2 +- .../src/server/worktree-session.test.ts | 100 ++++++++++++------ 3 files changed, 129 insertions(+), 59 deletions(-) diff --git a/packages/server/src/server/agent/mcp-server.test.ts b/packages/server/src/server/agent/mcp-server.test.ts index af00a621b..08ae3b92e 100644 --- a/packages/server/src/server/agent/mcp-server.test.ts +++ b/packages/server/src/server/agent/mcp-server.test.ts @@ -26,6 +26,8 @@ import { createPersistedWorkspaceRecord, type PersistedProjectRecord, type PersistedWorkspaceRecord, + type ProjectRegistry, + type WorkspaceRegistry, } from "../workspace-registry.js"; import type { CreateScheduleInput, @@ -53,6 +55,7 @@ import { PARENT_AGENT_ID_LABEL } from "@getpaseo/protocol/agent-labels"; import type { BrowserToolsBroker, BrowserToolsExecuteInput } from "../browser-tools/broker.js"; import type { BrowserToolsResponsePayload } from "../browser-tools/errors.js"; import { readPaseoWorktreeMetadata } from "../../utils/worktree-metadata.js"; +import { createWorkspaceProvisioningService } from "../session/workspace-provisioning/workspace-provisioning-service.js"; const REPO_CWD = resolvePath("/tmp/repo"); const TARGET_CWD = resolvePath("/tmp/target"); @@ -659,13 +662,68 @@ function createPaseoWorktreeForMcpTest(options: { paseoHome: options.paseoHome, deps: { github }, }); - const workspaceRegistry = { + const projectRegistry: ProjectRegistry = { + initialize: async () => {}, + existsOnDisk: async () => true, + list: async () => Array.from(projects.values()), + get: async (projectId) => projects.get(projectId) ?? null, + getOrCreateActiveByRoot: async (allocation) => { + const existing = Array.from(projects.values()).find( + (project) => + areEquivalentPaths(project.rootPath, allocation.rootPath) && !project.archivedAt, + ); + if (existing) return existing; + const project = createPersistedProjectRecord({ + projectId: `prj_test_${projects.size + 1}`, + rootPath: allocation.rootPath, + kind: allocation.kind, + displayName: allocation.displayName, + createdAt: allocation.timestamp, + updatedAt: allocation.timestamp, + }); + projects.set(project.projectId, project); + return project; + }, + upsert: async (record) => { + projects.set(record.projectId, record); + }, + archive: async (projectId, archivedAt) => { + const project = projects.get(projectId); + if (project) projects.set(projectId, { ...project, archivedAt }); + }, + remove: async (projectId) => { + projects.delete(projectId); + }, + }; + const workspaceRegistry: WorkspaceRegistry = { + initialize: async () => {}, + existsOnDisk: async () => true, get: async (workspaceId: string) => workspaces.get(workspaceId) ?? null, list: async () => Array.from(workspaces.values()), + update: async (workspaceId, updater) => { + const workspace = workspaces.get(workspaceId); + if (!workspace) return null; + const updated = updater(workspace); + workspaces.set(workspaceId, updated); + return updated; + }, upsert: async (record: PersistedWorkspaceRecord) => { workspaces.set(record.workspaceId, record); }, + archive: async (workspaceId, archivedAt) => { + const workspace = workspaces.get(workspaceId); + if (workspace) workspaces.set(workspaceId, { ...workspace, archivedAt }); + }, + remove: async (workspaceId) => { + workspaces.delete(workspaceId); + }, }; + const workspaceProvisioning = createWorkspaceProvisioningService({ + projectRegistry, + workspaceRegistry, + workspaceGitService, + logger: createTestLogger(), + }); const workspaceAutoName = new WorkspaceAutoName({ agentManager: buildAgentManagerSpies() as unknown as AgentManager, workspaceRegistry, @@ -699,32 +757,8 @@ function createPaseoWorktreeForMcpTest(options: { ...(workflowOptions?.resolveDefaultBranch ? { resolveDefaultBranch: workflowOptions.resolveDefaultBranch } : {}), - projectRegistry: { - get: async (projectId) => projects.get(projectId) ?? null, - getOrCreateActiveByRoot: async (allocation) => { - const existing = Array.from(projects.values()).find( - (project) => - areEquivalentPaths(project.rootPath, allocation.rootPath) && - !project.archivedAt, - ); - if (existing) return existing; - const project = createPersistedProjectRecord({ - projectId: `prj_test_${projects.size + 1}`, - rootPath: allocation.rootPath, - kind: allocation.kind, - displayName: allocation.displayName, - createdAt: allocation.timestamp, - updatedAt: allocation.timestamp, - }); - projects.set(project.projectId, project); - return project; - }, - upsert: async (record) => { - projects.set(record.projectId, record); - }, - }, - workspaceRegistry, workspaceGitService, + workspaceProvisioning, }), warmWorkspaceGitData: async () => {}, autoNameWorkspaceBranchForFirstAgent: (autoNameInput) => diff --git a/packages/server/src/server/workspace-registry-model.ts b/packages/server/src/server/workspace-registry-model.ts index 80df80d90..f08be536e 100644 --- a/packages/server/src/server/workspace-registry-model.ts +++ b/packages/server/src/server/workspace-registry-model.ts @@ -179,7 +179,7 @@ export function checkoutFromPersistedWorkspacePlacement(input: { ...checkout, isGit: true, isPaseoOwnedWorktree: false, - mainRepoRoot: workspace.mainRepoRoot, + mainRepoRoot: workspace.mainRepoRoot ?? null, }; } diff --git a/packages/server/src/server/worktree-session.test.ts b/packages/server/src/server/worktree-session.test.ts index ae38d119a..286a93f0a 100644 --- a/packages/server/src/server/worktree-session.test.ts +++ b/packages/server/src/server/worktree-session.test.ts @@ -36,6 +36,8 @@ import { createPersistedProjectRecord, type PersistedProjectRecord, type PersistedWorkspaceRecord, + type ProjectRegistry, + type WorkspaceRegistry, } from "./workspace-registry.js"; import type { GitHubService } from "../services/github-service.js"; import { areEquivalentPaths } from "../utils/path.js"; @@ -46,6 +48,7 @@ import { import { WorkspaceGitServiceImpl } from "./workspace-git-service.js"; import type { WorkspaceGitService } from "./workspace-git-service.js"; import { isPlatform } from "../test-utils/platform.js"; +import { createWorkspaceProvisioningService } from "./session/workspace-provisioning/workspace-provisioning-service.js"; interface LegacyCreateWorktreeTestOptions { branchName: string; @@ -276,6 +279,70 @@ function createPaseoWorktreeForTest(options: { github: createGitHubServiceStub(), }, }); + const projectRegistry: ProjectRegistry = { + initialize: async () => {}, + existsOnDisk: async () => true, + list: async () => Array.from(projects.values()), + get: async (projectId) => projects.get(projectId) ?? null, + getOrCreateActiveByRoot: async (allocation) => { + const existing = Array.from(projects.values()).find( + (project) => + areEquivalentPaths(project.rootPath, allocation.rootPath) && !project.archivedAt, + ); + if (existing) return existing; + const project = createPersistedProjectRecord({ + projectId: `prj_test_${projects.size + 1}`, + rootPath: allocation.rootPath, + kind: allocation.kind, + displayName: allocation.displayName, + createdAt: allocation.timestamp, + updatedAt: allocation.timestamp, + }); + projects.set(project.projectId, project); + return project; + }, + upsert: async (record) => { + options.events?.push(`project:${record.projectId}`); + projects.set(record.projectId, record); + }, + archive: async (projectId, archivedAt) => { + const project = projects.get(projectId); + if (project) projects.set(projectId, { ...project, archivedAt }); + }, + remove: async (projectId) => { + projects.delete(projectId); + }, + }; + const workspaceRegistry: WorkspaceRegistry = { + initialize: async () => {}, + existsOnDisk: async () => true, + list: async () => Array.from(workspaces.values()), + get: async (workspaceId) => workspaces.get(workspaceId) ?? null, + update: async (workspaceId, updater) => { + const workspace = workspaces.get(workspaceId); + if (!workspace) return null; + const updated = updater(workspace); + workspaces.set(workspaceId, updated); + return updated; + }, + upsert: async (record) => { + options.events?.push(`workspace:${record.workspaceId}`); + workspaces.set(record.workspaceId, record); + }, + archive: async (workspaceId, archivedAt) => { + const workspace = workspaces.get(workspaceId); + if (workspace) workspaces.set(workspaceId, { ...workspace, archivedAt }); + }, + remove: async (workspaceId) => { + workspaces.delete(workspaceId); + }, + }; + const workspaceProvisioning = createWorkspaceProvisioningService({ + projectRegistry, + workspaceRegistry, + workspaceGitService, + logger: createLogger(), + }); return (input, serviceOptions) => { return createPaseoWorktreeService(input, { @@ -283,39 +350,8 @@ function createPaseoWorktreeForTest(options: { ...(serviceOptions?.resolveDefaultBranch ? { resolveDefaultBranch: serviceOptions.resolveDefaultBranch } : {}), - projectRegistry: { - get: async (projectId) => projects.get(projectId) ?? null, - getOrCreateActiveByRoot: async (allocation) => { - const existing = Array.from(projects.values()).find( - (project) => - areEquivalentPaths(project.rootPath, allocation.rootPath) && !project.archivedAt, - ); - if (existing) return existing; - const project = createPersistedProjectRecord({ - projectId: `prj_test_${projects.size + 1}`, - rootPath: allocation.rootPath, - kind: allocation.kind, - displayName: allocation.displayName, - createdAt: allocation.timestamp, - updatedAt: allocation.timestamp, - }); - projects.set(project.projectId, project); - return project; - }, - upsert: async (record) => { - options.events?.push(`project:${record.projectId}`); - projects.set(record.projectId, record); - }, - }, - workspaceRegistry: { - get: async (workspaceId) => workspaces.get(workspaceId) ?? null, - list: async () => Array.from(workspaces.values()), - upsert: async (record) => { - options.events?.push(`workspace:${record.workspaceId}`); - workspaces.set(record.workspaceId, record); - }, - }, workspaceGitService, + workspaceProvisioning, }); }; }