From 1fb6178efa8a57417db9415258300b6669262c38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E5=A2=A8?= Date: Tue, 14 Apr 2026 14:29:47 +0000 Subject: [PATCH] chore: migrate package manager from bun to pnpm - Add pnpm-workspace.yaml for monorepo workspace - Add root package.json with packageManager field - Add .npmrc with shamefully-hoist=true - Replace bun.lock with pnpm-lock.yaml - Use workspace:* protocol for @uncaged/pulse dependency - Update init.ts scaffold to use pnpm install - Update CLI commands (tick/dev/deploy) to use pnpm/npx - Update E2E test comments to reference pnpm - Keep bun as TS runtime (bun:sqlite, bun:test still needed) closes #19 --- .npmrc | 1 + package.json | 2 + packages/pulse/bun.lock | 23 --- packages/pulse/package.json | 2 +- packages/upulse/bun.lock | 31 ---- packages/upulse/package.json | 4 +- packages/upulse/src/commands/deploy.ts | 2 +- packages/upulse/src/commands/dev.ts | 2 +- packages/upulse/src/commands/tick.ts | 2 +- packages/upulse/src/e2e/helper.ts | 2 +- .../src/e2e/t1-init-daemon-tick.test.ts | 4 +- packages/upulse/src/e2e/t4-rollback.test.ts | 2 +- packages/upulse/src/init.ts | 20 +- pnpm-lock.yaml | 172 ++++++++++++++++++ pnpm-workspace.yaml | 2 + 15 files changed, 197 insertions(+), 74 deletions(-) create mode 100644 .npmrc delete mode 100644 packages/pulse/bun.lock delete mode 100644 packages/upulse/bun.lock create mode 100644 pnpm-lock.yaml create mode 100644 pnpm-workspace.yaml diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..bf2e764 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +shamefully-hoist=true diff --git a/package.json b/package.json index aa6a9c1..14da117 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,7 @@ { + "name": "pulse-monorepo", "private": true, + "packageManager": "pnpm@10.33.0", "scripts": { "lint": "biome check packages/", "lint:fix": "biome check --write packages/" diff --git a/packages/pulse/bun.lock b/packages/pulse/bun.lock deleted file mode 100644 index 255daac..0000000 --- a/packages/pulse/bun.lock +++ /dev/null @@ -1,23 +0,0 @@ -{ - "lockfileVersion": 1, - "configVersion": 1, - "workspaces": { - "": { - "name": "@uncaged/pulse", - "devDependencies": { - "@types/node": "^25.6.0", - "bun-types": "latest", - "typescript": "^6.0.2", - }, - }, - }, - "packages": { - "@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="], - - "bun-types": ["bun-types@1.3.12", "", { "dependencies": { "@types/node": "*" } }, "sha512-HqOLj5PoFajAQciOMRiIZGNoKxDJSr6qigAttOX40vJuSp6DN/CxWp9s3C1Xwm4oH7ybueITwiaOcWXoYVoRkA=="], - - "typescript": ["typescript@6.0.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ=="], - - "undici-types": ["undici-types@7.19.2", "", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="], - } -} diff --git a/packages/pulse/package.json b/packages/pulse/package.json index b5b0e8a..9d62f34 100644 --- a/packages/pulse/package.json +++ b/packages/pulse/package.json @@ -9,7 +9,7 @@ "dist" ], "scripts": { - "build": "bun run tsc", + "build": "tsc", "test": "bun test" }, "keywords": [ diff --git a/packages/upulse/bun.lock b/packages/upulse/bun.lock deleted file mode 100644 index c64286f..0000000 --- a/packages/upulse/bun.lock +++ /dev/null @@ -1,31 +0,0 @@ -{ - "lockfileVersion": 1, - "configVersion": 1, - "workspaces": { - "": { - "name": "@uncaged/upulse", - "dependencies": { - "@uncaged/pulse": "file:../pulse", - "commander": "^12.0.0", - }, - "devDependencies": { - "@types/node": "^25.6.0", - "bun-types": "latest", - "typescript": "^6.0.2", - }, - }, - }, - "packages": { - "@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="], - - "@uncaged/pulse": ["@uncaged/pulse@file:../pulse", { "devDependencies": { "@types/node": "^25.6.0", "bun-types": "latest", "typescript": "^6.0.2" } }], - - "bun-types": ["bun-types@1.3.12", "", { "dependencies": { "@types/node": "*" } }, "sha512-HqOLj5PoFajAQciOMRiIZGNoKxDJSr6qigAttOX40vJuSp6DN/CxWp9s3C1Xwm4oH7ybueITwiaOcWXoYVoRkA=="], - - "commander": ["commander@12.1.0", "", {}, "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA=="], - - "typescript": ["typescript@6.0.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ=="], - - "undici-types": ["undici-types@7.19.2", "", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="], - } -} diff --git a/packages/upulse/package.json b/packages/upulse/package.json index b3e22aa..ddddca1 100644 --- a/packages/upulse/package.json +++ b/packages/upulse/package.json @@ -11,13 +11,13 @@ "dist" ], "scripts": { - "build": "bun run tsc", + "build": "tsc", "dev": "bun run src/cli.ts", "test": "bun test --timeout 60000", "test:e2e": "bun test --timeout 120000 src/e2e/" }, "dependencies": { - "@uncaged/pulse": "file:../pulse", + "@uncaged/pulse": "workspace:*", "commander": "^12.0.0" }, "devDependencies": { diff --git a/packages/upulse/src/commands/deploy.ts b/packages/upulse/src/commands/deploy.ts index 150d1c7..ca42ddb 100644 --- a/packages/upulse/src/commands/deploy.ts +++ b/packages/upulse/src/commands/deploy.ts @@ -24,7 +24,7 @@ import { function typeCheck(cwd: string): boolean { try { // Pure type checking — no emit, no dist/ needed - execSync('bunx tsc --noEmit', { + execSync('npx tsc --noEmit', { cwd, encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], diff --git a/packages/upulse/src/commands/dev.ts b/packages/upulse/src/commands/dev.ts index 91513e2..4fc5149 100644 --- a/packages/upulse/src/commands/dev.ts +++ b/packages/upulse/src/commands/dev.ts @@ -39,7 +39,7 @@ export function registerDevCommand(program: Command): void { ); console.log(`Compiling staging (${config.staging.path})...`); try { - execSync(`bun ${tscBin}`, { + execSync(`node ${tscBin}`, { cwd: config.staging.path, stdio: 'inherit', }); diff --git a/packages/upulse/src/commands/tick.ts b/packages/upulse/src/commands/tick.ts index a164e5b..384d253 100644 --- a/packages/upulse/src/commands/tick.ts +++ b/packages/upulse/src/commands/tick.ts @@ -50,7 +50,7 @@ export function registerTickCommand(program: Command): void { console.error( 'Error: @uncaged/pulse not found in engine node_modules.', ); - console.error('Run: cd ~/.upulse/engine && bun install'); + console.error('Run: cd ~/.upulse/engine && pnpm install'); process.exit(1); } diff --git a/packages/upulse/src/e2e/helper.ts b/packages/upulse/src/e2e/helper.ts index 714eaf6..3bc2c70 100644 --- a/packages/upulse/src/e2e/helper.ts +++ b/packages/upulse/src/e2e/helper.ts @@ -65,7 +65,7 @@ export function cleanupE2EContext(ctx: E2EContext): void { export interface RunOptions { /** If true, expect the command to exit non-zero. Returns stderr. */ expectFail?: boolean; - /** Timeout in ms (default: 120_000 for npm install during init). */ + /** Timeout in ms (default: 120_000 for pnpm install during init). */ timeout?: number; } diff --git a/packages/upulse/src/e2e/t1-init-daemon-tick.test.ts b/packages/upulse/src/e2e/t1-init-daemon-tick.test.ts index a490169..75d5e12 100644 --- a/packages/upulse/src/e2e/t1-init-daemon-tick.test.ts +++ b/packages/upulse/src/e2e/t1-init-daemon-tick.test.ts @@ -2,7 +2,7 @@ * E2E T1 — Init → Daemon → Tick 完整链路测试 * * Validates the full lifecycle: - * upulse init → creates directories, git repo, bun install + * upulse init → creates directories, git repo, pnpm install * upulse tick → compiles engine, runs one tick, writes to DB * upulse daemon status → reports daemon state * @@ -26,7 +26,7 @@ describe('E2E T1: Init → Daemon → Tick', () => { let ctx: E2EContext; // Use a single context for all tests in this suite because - // `upulse init` runs bun install which is slow (~15-30s). + // `upulse init` runs pnpm install which is slow (~15-30s). // Tests are ordered: init → tick → daemon. beforeAll(() => { ctx = createE2EContext(); diff --git a/packages/upulse/src/e2e/t4-rollback.test.ts b/packages/upulse/src/e2e/t4-rollback.test.ts index 7ff7e2a..9cb8ff0 100644 --- a/packages/upulse/src/e2e/t4-rollback.test.ts +++ b/packages/upulse/src/e2e/t4-rollback.test.ts @@ -80,7 +80,7 @@ describe('E2E T4: Rollback', () => { let v2CodeRev: string; const eventCounts: number[] = []; - // Single context — init + npm install is expensive (~15-30s). + // Single context — init + pnpm install is expensive (~15-30s). // Tests are ordered and build on each other. beforeAll(() => { ctx = createE2EContext(); diff --git a/packages/upulse/src/init.ts b/packages/upulse/src/init.ts index 5730cdb..78367f8 100644 --- a/packages/upulse/src/init.ts +++ b/packages/upulse/src/init.ts @@ -1,7 +1,7 @@ /** * init.ts — upulse init logic * - * Creates ~/.upulse/ with engine scaffold, git init, worktree, bun install + * Creates ~/.upulse/ with engine scaffold, git init, worktree, pnpm install */ import { execSync } from 'node:child_process'; @@ -77,14 +77,14 @@ export function initUpulse(dir?: string): void { gitWorktreeAdd(config.engine.path, config.staging.path, 'staging'); console.log(' ✓ staging worktree created'); - // bun install in engine + // pnpm install in engine console.log('\nInstalling dependencies...'); try { - execSync('bun install', { cwd: config.engine.path, stdio: 'inherit' }); - console.log(' ✓ bun install complete'); + execSync('pnpm install', { cwd: config.engine.path, stdio: 'inherit' }); + console.log(' ✓ pnpm install complete'); } catch { console.error( - 'Warning: bun install failed. Run manually: cd ~/.upulse/engine && bun install', + 'Warning: pnpm install failed. Run manually: cd ~/.upulse/engine && pnpm install', ); } @@ -148,14 +148,14 @@ function writeEnginePackageJson( private: true, type: 'module', scripts: { - typecheck: 'bunx tsc --noEmit', + typecheck: 'npx tsc --noEmit', }, dependencies: { '@uncaged/pulse': pulseDep, }, devDependencies: { typescript: '^6.0.2', - 'bun-types': 'latest', + '@types/node': '^25.6.0', }, }; writeFileSync( @@ -176,7 +176,7 @@ function writeEngineTsConfig(enginePath: string): void { esModuleInterop: true, skipLibCheck: true, forceConsistentCasingInFileNames: true, - types: ['bun-types'], + types: ['node'], }, include: ['*.ts', 'executors/**/*.ts', 'rules/**/*.ts'], }; @@ -230,7 +230,7 @@ type Rule = (prev: S, curr: S) ## 构建和测试 \`\`\`bash -bun run typecheck # tsc --noEmit 类型检查 +pnpm run typecheck # tsc --noEmit 类型检查 upulse dev test # 历史 snapshot 回放 dry-run upulse tick --dry-run # 手动触发一次(不执行 effect) \`\`\` @@ -239,7 +239,7 @@ upulse tick --dry-run # 手动触发一次(不执行 effect) - **不要修改 pulse.config.ts 的 runPulse 调用签名** - **不要删除 types.ts** - **不要引入 node_modules 以外的路径依赖** -- **改 types.ts 后必须 \`bun run typecheck\` 确认所有文件类型检查通过** +- **改 types.ts 后必须 \`pnpm run typecheck\` 确认所有文件类型检查通过** `; writeFileSync(join(enginePath, 'AGENTS.md'), content, 'utf-8'); } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..868159c --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,172 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + devDependencies: + '@biomejs/biome': + specifier: ^2.4.11 + version: 2.4.11 + + packages/pulse: + devDependencies: + '@types/node': + specifier: ^25.6.0 + version: 25.6.0 + bun-types: + specifier: latest + version: 1.3.12 + typescript: + specifier: ^6.0.2 + version: 6.0.2 + + packages/upulse: + dependencies: + '@uncaged/pulse': + specifier: workspace:* + version: link:../pulse + commander: + specifier: ^12.0.0 + version: 12.1.0 + devDependencies: + '@types/node': + specifier: ^25.6.0 + version: 25.6.0 + bun-types: + specifier: latest + version: 1.3.12 + typescript: + specifier: ^6.0.2 + version: 6.0.2 + +packages: + + '@biomejs/biome@2.4.11': + resolution: {integrity: sha512-nWxHX8tf3Opb/qRgZpBbsTOqOodkbrkJ7S+JxJAruxOReaDPPmPuLBAGQ8vigyUgo0QBB+oQltNEAvalLcjggA==} + engines: {node: '>=14.21.3'} + hasBin: true + + '@biomejs/cli-darwin-arm64@2.4.11': + resolution: {integrity: sha512-wOt+ed+L2dgZanWyL6i29qlXMc088N11optzpo10peayObBaAshbTcxKUchzEMp9QSY8rh5h6VfAFE3WTS1rqg==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [darwin] + + '@biomejs/cli-darwin-x64@2.4.11': + resolution: {integrity: sha512-gZ6zR8XmZlExfi/Pz/PffmdpWOQ8Qhy7oBztgkR8/ylSRyLwfRPSadmiVCV8WQ8PoJ2MWUy2fgID9zmtgUUJmw==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [darwin] + + '@biomejs/cli-linux-arm64-musl@2.4.11': + resolution: {integrity: sha512-+Sbo1OAmlegtdwqFE8iOxFIWLh1B3OEgsuZfBpyyN/kWuqZ8dx9ZEes6zVnDMo+zRHF2wLynRVhoQmV7ohxl2Q==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@biomejs/cli-linux-arm64@2.4.11': + resolution: {integrity: sha512-avdJaEElXrKceK0va9FkJ4P5ci3N01TGkc6ni3P8l3BElqbOz42Wg2IyX3gbh0ZLEd4HVKEIrmuVu/AMuSeFFA==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@biomejs/cli-linux-x64-musl@2.4.11': + resolution: {integrity: sha512-bexd2IklK7ZgPhrz6jXzpIL6dEAH9MlJU1xGTrypx+FICxrXUp4CqtwfiuoDKse+UlgAlWtzML3jrMqeEAHEhA==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@biomejs/cli-linux-x64@2.4.11': + resolution: {integrity: sha512-TagWV0iomp5LnEnxWFg4nQO+e52Fow349vaX0Q/PIcX6Zhk4GGBgp3qqZ8PVkpC+cuehRctMf3+6+FgQ8jCEFQ==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@biomejs/cli-win32-arm64@2.4.11': + resolution: {integrity: sha512-RJhaTnY8byzxDt4bDVb7AFPHkPcjOPK3xBip4ZRTrN3TEfyhjLRm3r3mqknqydgVTB74XG8l4jMLwEACEeihVg==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [win32] + + '@biomejs/cli-win32-x64@2.4.11': + resolution: {integrity: sha512-A8D3JM/00C2KQgUV3oj8Ba15EHEYwebAGCy5Sf9GAjr5Y3+kJIYOiESoqRDeuRZueuMdCsbLZIUqmPhpYXJE9A==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [win32] + + '@types/node@25.6.0': + resolution: {integrity: sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==} + + bun-types@1.3.12: + resolution: {integrity: sha512-HqOLj5PoFajAQciOMRiIZGNoKxDJSr6qigAttOX40vJuSp6DN/CxWp9s3C1Xwm4oH7ybueITwiaOcWXoYVoRkA==} + + commander@12.1.0: + resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} + engines: {node: '>=18'} + + typescript@6.0.2: + resolution: {integrity: sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@7.19.2: + resolution: {integrity: sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==} + +snapshots: + + '@biomejs/biome@2.4.11': + optionalDependencies: + '@biomejs/cli-darwin-arm64': 2.4.11 + '@biomejs/cli-darwin-x64': 2.4.11 + '@biomejs/cli-linux-arm64': 2.4.11 + '@biomejs/cli-linux-arm64-musl': 2.4.11 + '@biomejs/cli-linux-x64': 2.4.11 + '@biomejs/cli-linux-x64-musl': 2.4.11 + '@biomejs/cli-win32-arm64': 2.4.11 + '@biomejs/cli-win32-x64': 2.4.11 + + '@biomejs/cli-darwin-arm64@2.4.11': + optional: true + + '@biomejs/cli-darwin-x64@2.4.11': + optional: true + + '@biomejs/cli-linux-arm64-musl@2.4.11': + optional: true + + '@biomejs/cli-linux-arm64@2.4.11': + optional: true + + '@biomejs/cli-linux-x64-musl@2.4.11': + optional: true + + '@biomejs/cli-linux-x64@2.4.11': + optional: true + + '@biomejs/cli-win32-arm64@2.4.11': + optional: true + + '@biomejs/cli-win32-x64@2.4.11': + optional: true + + '@types/node@25.6.0': + dependencies: + undici-types: 7.19.2 + + bun-types@1.3.12: + dependencies: + '@types/node': 25.6.0 + + commander@12.1.0: {} + + typescript@6.0.2: {} + + undici-types@7.19.2: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 0000000..18ec407 --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,2 @@ +packages: + - 'packages/*'