fix(projects): preserve symlinked bootstrap roots

This commit is contained in:
Mohamed Boudra
2026-07-28 23:23:39 +00:00
parent 95ceb238ee
commit 34500f30cf
2 changed files with 62 additions and 13 deletions

View File

@@ -1,8 +1,9 @@
import { basename, isAbsolute, relative, resolve, sep } from "node:path";
import { basename, resolve } from "node:path";
import type { ProjectCheckoutLitePayload } from "@getpaseo/protocol/messages";
import { parseGitRevParsePath } from "../utils/git-rev-parse-path.js";
import { getRealpathAwareRelativePath } from "../utils/path.js";
import { deriveProjectGroupKey } from "./project-group-key.js";
import {
deriveProjectKind,
@@ -80,15 +81,8 @@ function deriveProjectRootPath(input: {
? parseGitRevParsePath(input.checkout.worktreeRoot)
: null;
if (!worktreeRoot) return input.checkout.mainRepoRoot;
const selectedPath = relative(resolve(worktreeRoot), resolve(input.cwd));
if (
!selectedPath ||
selectedPath === "." ||
selectedPath === ".." ||
selectedPath.startsWith(`..${sep}`) ||
isAbsolute(selectedPath)
) {
return input.checkout.mainRepoRoot;
}
return resolve(input.checkout.mainRepoRoot, selectedPath);
const selectedPath = getRealpathAwareRelativePath(worktreeRoot, input.cwd);
return selectedPath
? resolve(input.checkout.mainRepoRoot, selectedPath)
: input.checkout.mainRepoRoot;
}

View File

@@ -1,6 +1,6 @@
import os from "node:os";
import path from "node:path";
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
import { mkdirSync, mkdtempSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
import { afterEach, beforeEach, describe, expect, test } from "vitest";
@@ -456,6 +456,61 @@ describe("bootstrapWorkspaceRegistries", () => {
);
});
test.skipIf(process.platform === "win32")(
"maps a symlinked legacy subproject onto the main checkout",
async () => {
const physicalProject = path.join(GIT_WORKTREE, "packages", "app");
const linkedProject = path.join(tmpDir, "app-link");
mkdirSync(physicalProject, { recursive: true });
symlinkSync(physicalProject, linkedProject, "dir");
workspaceGitService = createNoopWorkspaceGitService({
getCheckout: async (cwd) => ({
cwd,
isGit: true,
currentBranch: "main",
remoteUrl: "git@github.com:acme/legacy-project.git",
worktreeRoot: GIT_WORKTREE,
isPaseoOwnedWorktree: false,
mainRepoRoot: GIT_PROJECT,
}),
});
await agentStorage.initialize();
await agentStorage.upsert({
id: "linked-app-agent",
provider: "codex",
cwd: linkedProject,
createdAt: "2026-03-01T00:00:00.000Z",
updatedAt: "2026-03-02T00:00:00.000Z",
lastActivityAt: "2026-03-02T00:00:00.000Z",
lastUserMessageAt: null,
title: null,
labels: {},
lastStatus: "idle",
lastModeId: null,
config: null,
runtimeInfo: { provider: "codex", sessionId: null },
persistence: null,
archivedAt: null,
});
await bootstrapWorkspaceRegistries({
paseoHome,
agentStorage,
projectRegistry,
workspaceRegistry,
workspaceGitService,
logger,
});
expect(await projectRegistry.list()).toEqual([
expect.objectContaining({
projectId: "remote:github.com/acme/legacy-project#subdir:packages/app",
rootPath: path.join(GIT_PROJECT, "packages", "app"),
}),
]);
},
);
test("migrates cwd-only agents to the oldest existing same-cwd workspace", async () => {
await projectRegistry.initialize();
await workspaceRegistry.initialize();