Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions build.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ import { execFileSync } from 'child_process';
import { existsSync, rmSync } from 'fs';
import { createRequire } from 'module';

// When npm installs from a git dep (github:user/repo#branch), it runs
// `prepare` before node_modules exist. Skip gracefully and let `prepack`
// handle the build during the pack phase where deps are available.
if (!existsSync('node_modules')) {
console.log('⏭️ Skipping build (node_modules not yet available)');
process.exit(0);
}
Comment on lines +10 to +13
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

node_modules check is CWD-sensitive

existsSync('node_modules') resolves relative to the process's current working directory, not the script's location. npm lifecycle scripts set CWD to the package root, so this is safe in the intended scenarios. However, if build.js is ever invoked via a path like node packages/openspec/build.js from the monorepo root (e.g. in a CI script), node_modules would refer to the root-level directory rather than the package's own deps, making the check unreliable.

Consider anchoring the check to the script's own directory for robustness:

Suggested change
if (!existsSync('node_modules')) {
console.log('⏭️ Skipping build (node_modules not yet available)');
process.exit(0);
}
if (!existsSync(new URL('node_modules', import.meta.url).pathname)) {


const require = createRequire(import.meta.url);

const runTsc = (args = []) => {
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@
"test:ui": "vitest --ui",
"test:coverage": "vitest --coverage",
"test:postinstall": "node scripts/postinstall.js",
"prepare": "pnpm run build",
"prepare": "node build.js",
"prepack": "node build.js",
Comment on lines +51 to +52
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant double build during npm publish

Both prepare and prepack are set to node build.js, and npm publish triggers both hooks (plus prepublishOnly which calls pnpm run build). This means every publish results in 3 full build passes. Since build.js cleans dist first, the result is correct but the extra compilation time is wasted.

If the intent is for prepare to cover local dev installs and prepack to cover the git-dep pack phase, consider guarding prepack to only run when dist is absent (i.e. when prepare was skipped):

"prepare": "node build.js",
"prepack": "node -e \"const {existsSync}=require('fs'); if(!existsSync('dist')) process.exit(0);\" || node build.js",

Or more cleanly, extract the "build if not already built" logic into build.js itself so both hooks share a single idempotent entry point without redundant work.

"prepublishOnly": "pnpm run build",
"postinstall": "node scripts/postinstall.js",
"check:pack-version": "node scripts/pack-version-check.mjs",
Expand Down