diff --git a/package.json b/package.json index ec02b62a..58ffa103 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,6 @@ "private": true, "type": "module", "scripts": { - "preflight:workspace-links": "pnpm --filter @paperclipai/server exec tsx ../scripts/ensure-workspace-package-links.ts", "dev": "pnpm --filter @paperclipai/server exec tsx ../scripts/dev-runner.ts watch", "dev:watch": "pnpm --filter @paperclipai/server exec tsx ../scripts/dev-runner.ts watch", "dev:once": "pnpm --filter @paperclipai/server exec tsx ../scripts/dev-runner.ts dev", @@ -11,10 +10,10 @@ "dev:stop": "pnpm --filter @paperclipai/server exec tsx ../scripts/dev-service.ts stop", "dev:server": "pnpm --filter @paperclipai/server dev", "dev:ui": "pnpm --filter @paperclipai/ui dev", - "build": "pnpm run preflight:workspace-links && pnpm -r build", - "typecheck": "pnpm run preflight:workspace-links && pnpm -r typecheck", - "test": "pnpm run preflight:workspace-links && vitest", - "test:run": "pnpm run preflight:workspace-links && vitest run", + "build": "pnpm -r build", + "typecheck": "pnpm -r typecheck", + "test": "vitest", + "test:run": "vitest run", "db:generate": "pnpm --filter @paperclipai/db generate", "db:migrate": "pnpm --filter @paperclipai/db migrate", "secrets:migrate-inline-env": "tsx scripts/migrate-inline-env-secrets.ts", diff --git a/scripts/ensure-workspace-package-links.ts b/scripts/ensure-workspace-package-links.ts deleted file mode 100644 index 17a99909..00000000 --- a/scripts/ensure-workspace-package-links.ts +++ /dev/null @@ -1,126 +0,0 @@ -#!/usr/bin/env -S node --import tsx -import fs from "node:fs/promises"; -import { existsSync, lstatSync, readdirSync, readFileSync, realpathSync } from "node:fs"; -import path from "node:path"; -import { repoRoot } from "./dev-service-profile.ts"; - -type WorkspaceLinkMismatch = { - workspaceDir: string; - packageName: string; - expectedPath: string; - actualPath: string | null; -}; - -function readJsonFile(filePath: string): Record { - return JSON.parse(readFileSync(filePath, "utf8")) as Record; -} - -function discoverWorkspacePackagePaths(rootDir: string): Map { - const packagePaths = new Map(); - const ignoredDirNames = new Set([".git", ".paperclip", "dist", "node_modules"]); - - function visit(dirPath: string) { - const packageJsonPath = path.join(dirPath, "package.json"); - if (existsSync(packageJsonPath)) { - const packageJson = readJsonFile(packageJsonPath); - if (typeof packageJson.name === "string" && packageJson.name.length > 0) { - packagePaths.set(packageJson.name, dirPath); - } - } - - for (const entry of readdirSync(dirPath, { withFileTypes: true })) { - if (!entry.isDirectory()) continue; - if (ignoredDirNames.has(entry.name)) continue; - visit(path.join(dirPath, entry.name)); - } - } - - visit(path.join(rootDir, "packages")); - visit(path.join(rootDir, "server")); - visit(path.join(rootDir, "ui")); - visit(path.join(rootDir, "cli")); - - return packagePaths; -} - -function isLinkedGitWorktreeCheckout(rootDir: string) { - const gitMetadataPath = path.join(rootDir, ".git"); - if (!existsSync(gitMetadataPath)) return false; - - const stat = lstatSync(gitMetadataPath); - if (!stat.isFile()) return false; - - return readFileSync(gitMetadataPath, "utf8").trimStart().startsWith("gitdir:"); -} - -if (!isLinkedGitWorktreeCheckout(repoRoot)) { - process.exit(0); -} - -const workspacePackagePaths = discoverWorkspacePackagePaths(repoRoot); -const workspaceDirs = Array.from( - new Set( - Array.from(workspacePackagePaths.values()) - .map((packagePath) => path.relative(repoRoot, packagePath)) - .filter((workspaceDir) => workspaceDir.length > 0), - ), -).sort(); - -function findWorkspaceLinkMismatches(workspaceDir: string): WorkspaceLinkMismatch[] { - const packageJson = readJsonFile(path.join(repoRoot, workspaceDir, "package.json")); - const dependencies = { - ...(packageJson.dependencies as Record | undefined), - ...(packageJson.devDependencies as Record | undefined), - }; - const mismatches: WorkspaceLinkMismatch[] = []; - - for (const [packageName, version] of Object.entries(dependencies)) { - if (typeof version !== "string" || !version.startsWith("workspace:")) continue; - - const expectedPath = workspacePackagePaths.get(packageName); - if (!expectedPath) continue; - - const linkPath = path.join(repoRoot, workspaceDir, "node_modules", ...packageName.split("/")); - const actualPath = existsSync(linkPath) ? path.resolve(realpathSync(linkPath)) : null; - if (actualPath === path.resolve(expectedPath)) continue; - - mismatches.push({ - workspaceDir, - packageName, - expectedPath: path.resolve(expectedPath), - actualPath, - }); - } - - return mismatches; -} - -async function ensureWorkspaceLinksCurrent(workspaceDir: string) { - const mismatches = findWorkspaceLinkMismatches(workspaceDir); - if (mismatches.length === 0) return; - - console.log(`[paperclip] detected stale workspace package links for ${workspaceDir}; relinking dependencies...`); - for (const mismatch of mismatches) { - console.log( - `[paperclip] ${mismatch.packageName}: ${mismatch.actualPath ?? "missing"} -> ${mismatch.expectedPath}`, - ); - } - - for (const mismatch of mismatches) { - const linkPath = path.join(repoRoot, mismatch.workspaceDir, "node_modules", ...mismatch.packageName.split("/")); - await fs.mkdir(path.dirname(linkPath), { recursive: true }); - await fs.rm(linkPath, { recursive: true, force: true }); - await fs.symlink(mismatch.expectedPath, linkPath); - } - - const remainingMismatches = findWorkspaceLinkMismatches(workspaceDir); - if (remainingMismatches.length === 0) return; - - throw new Error( - `Workspace relink did not repair all ${workspaceDir} package links: ${remainingMismatches.map((item) => item.packageName).join(", ")}`, - ); -} - -for (const workspaceDir of workspaceDirs) { - await ensureWorkspaceLinksCurrent(workspaceDir); -} diff --git a/server/package.json b/server/package.json index a4d1407d..dac65fa7 100644 --- a/server/package.json +++ b/server/package.json @@ -32,16 +32,15 @@ "skills" ], "scripts": { - "preflight:workspace-links": "tsx ../scripts/ensure-workspace-package-links.ts", - "dev": "pnpm run preflight:workspace-links && tsx src/index.ts", - "dev:watch": "pnpm run preflight:workspace-links && cross-env PAPERCLIP_MIGRATION_PROMPT=never PAPERCLIP_MIGRATION_AUTO_APPLY=true tsx ./scripts/dev-watch.ts", + "dev": "tsx src/index.ts", + "dev:watch": "cross-env PAPERCLIP_MIGRATION_PROMPT=never PAPERCLIP_MIGRATION_AUTO_APPLY=true tsx ./scripts/dev-watch.ts", "prepare:ui-dist": "bash ../scripts/prepare-server-ui-dist.sh", - "build": "pnpm run preflight:workspace-links && tsc && mkdir -p dist/onboarding-assets && cp -R src/onboarding-assets/. dist/onboarding-assets/", + "build": "tsc && mkdir -p dist/onboarding-assets && cp -R src/onboarding-assets/. dist/onboarding-assets/", "prepack": "pnpm run prepare:ui-dist", "postpack": "rm -rf ui-dist", "clean": "rm -rf dist", "start": "node dist/index.js", - "typecheck": "pnpm run preflight:workspace-links && pnpm --filter @paperclipai/plugin-sdk build && tsc --noEmit" + "typecheck": "pnpm --filter @paperclipai/plugin-sdk build && tsc --noEmit" }, "dependencies": { "@aws-sdk/client-s3": "^3.888.0",