Skip to content

fix(build): prepare npm git installs without pnpm - #792

Open
pformoso-deus-ai wants to merge 3 commits into
Fission-AI:mainfrom
pabloformoso:fix/npm-git-dep-install
Open

fix(build): prepare npm git installs without pnpm#792
pformoso-deus-ai wants to merge 3 commits into
Fission-AI:mainfrom
pabloformoso:fix/npm-git-dep-install

Conversation

@pformoso-deus-ai

@pformoso-deus-ai pformoso-deus-ai commented Mar 2, 2026

Copy link
Copy Markdown

Status

LGTM; ready for final review. All GitHub checks passed, including Linux, macOS, Windows, Nix, lint/type checking, security, and CodeRabbit. GitHub reports CLEAN/MERGEABLE. This PR has not been merged.

What was wrong

Installing OpenSpec from Git required pnpm because npm invokes the package's prepare script, which ran pnpm run build.

The original patch also skipped builds when node_modules was absent and added prepack. That could silently pack missing or stale output. npm installs Git dependencies' development dependencies before preparation; the extra hook is unnecessary.

How it was fixed

  • Run node build.js directly from prepare.
  • Keep missing dependencies and compilation errors fatal; remove the original skip guard and redundant prepack hook.
  • Extend the existing package-script tests with offline Git installation, tarball installation, executable/declaration checks, stale-output cleanup, and failed-build cases. A failing pnpm sentinel proves these operations do not invoke pnpm.
  • Merge current main and resolve the obsolete postinstall-script conflict without restoring removed install hooks.

The production diff against main is one line in package.json.

Replication / proof

  • A clean snapshot of the complete OpenSpec source installed successfully through npm install --omit=dev git+file://... with pnpm blocked. The installed CLI returned version 1.11.0, displayed help, and loaded the packaged spec-driven schema. JavaScript and declarations were present; TypeScript was not installed in the consumer.
  • Changing only prepare back to pnpm run build made the same Git-install smoke fail at the pnpm sentinel (exit 93).
  • The original skip guard caused both missing-dependency packaging regressions to fail: npm pack returned success with missing or stale output. Both pass after removing the guard.
  • pnpm exec vitest run test/package-install-scripts.test.ts: 8 passed, including 5 new integration cases; independently rerun by a second reviewer.
  • Full pnpm test: 4,234 passed across 145 files.
  • pnpm run build, pnpm exec tsc --noEmit, pnpm lint, and git diff --check: passed.
  • GitHub CI: passed on Linux, macOS, and Windows, with Nix validation and lint/type checking also green.
  • GitHub Security: dependency audits, dependency review, and website lockfile validation passed.

Notes / nits

  • Local verification used macOS arm64, Node 26.7.0, and npm 11.19.0. The full suite used a temporary HOME/USERPROFILE, removed inherited ZSH/ZSH_CUSTOM, and allowed its localhost mock server. The initial environment-related failures were reproduced on unchanged main; no unrelated test fixes are included.
  • Fork workflows were explicitly approved and all checks completed successfully. Independent review found no actionable defects.
  • Published registry installs still have no install lifecycle scripts. Maintainer release scripts remain unchanged. This follows the normal release cadence without a dedicated changeset.

npm v11's git dep preparation runs `prepare` before node_modules exist
in the temp clone directory, causing TypeScript compilation to fail.

Changes:
- build.js: skip build gracefully when node_modules absent
- package.json: use `node build.js` directly in prepare/prepack for
  npm compatibility (avoids pnpm dependency during git dep install)

Note: postinstall.js already handles all errors internally via
main().catch(() => process.exit(0)), so no `|| true` wrapper needed.

Install from GitHub with:
  npm pack github:user/repo#branch
  npm install -g ./fission-ai-openspec-x.y.z.tgz

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Mar 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 1ddb96b4-c3ca-4868-9dd4-cb51b41a8adb

📥 Commits

Reviewing files that changed from the base of the PR and between a0ddb60 and d7bfad5.

📒 Files selected for processing (2)
  • package.json
  • test/package-install-scripts.test.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 5 remain after this review.


📝 Walkthrough

Walkthrough

The package prepare script now runs node build.js. End-to-end tests validate npm source installation, Git dependencies, tarball packaging, stale artifacts, missing build dependencies, and TypeScript compilation failures.

Changes

NPM source installation

Layer / File(s) Summary
NPM-compatible prepare script
package.json
The prepare script now runs node build.js instead of pnpm run build.
Source installation lifecycle tests
test/package-install-scripts.test.ts
The test suite creates isolated package fixtures and validates lifecycle hooks, compiled artifacts, packaging behavior, offline installation, and build failure handling.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: ⚪ Minimal · up to d7bfa

The PR routes package preparation through the existing Node build script for npm Git installs without adding a new runtime or deployment path. No actionable merge-blocking risk remains beyond normal checks and review.

Suggested reviewers: tabishb, clay-good

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 3 functions across 1 files. (1 skipped: 1 … Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: fixing npm Git dependency installation by running the prepare build without pnpm.
Full details: Docstring Coverage

Explanation

Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 3 functions across 1 files. (1 skipped: 1 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Mar 2, 2026

Copy link
Copy Markdown

Greptile Summary

This PR fixes npm v11 git-dep installation by making the build lifecycle hooks pnpm-agnostic and adding a graceful skip in build.js when node_modules doesn't yet exist (npm v11 runs prepare before installing deps). The approach is sound and directly addresses the reported install failure.

Key changes:

  • build.js gains a top-level guard that exits 0 when node_modules is absent, deferring the actual build to prepack where deps are guaranteed to be present
  • prepare is switched from pnpm run buildnode build.js, removing the pnpm hard dependency for git-dep consumers
  • A new prepack hook (node build.js) is added to ensure the build runs before any tarball is packed

Minor concerns:

  • Both prepare and prepack call node build.js, and npm publish triggers both, resulting in a redundant double (actually triple, including prepublishOnly) build
  • The existsSync('node_modules') guard is CWD-relative; safe for lifecycle scripts but fragile if build.js is invoked from a non-root path
  • prepublishOnly still references pnpm run build, leaving a small inconsistency with the other hooks

Confidence Score: 4/5

  • Safe to merge — the fix correctly handles the npm v11 git-dep lifecycle edge case with no functional regressions.
  • The changes are minimal, well-scoped, and solve a real npm v11 compatibility issue. The early-exit guard in build.js is idiomatic and the postinstall error handling is already in place. The only non-trivial concern is a redundant double build during npm publish introduced by having both prepare and prepack call node build.js, but this does not affect correctness.
  • package.json — the prepare/prepack duplication causes redundant builds on publish; prepublishOnly is also inconsistent in still using pnpm run build.

Important Files Changed

Filename Overview
build.js Adds an early-exit guard when node_modules is absent, enabling graceful skip during npm v11 git-dep prepare phase. The guard uses a CWD-relative path which is correct for lifecycle scripts but could misbehave if the script is invoked from a non-root directory.
package.json Replaces pnpm run build with node build.js in prepare and adds a new prepack hook — both pointing to the same script. Both hooks fire during npm publish, causing redundant double builds. prepublishOnly still references pnpm run build, leaving an inconsistency.

Sequence Diagram

sequenceDiagram
    participant npm as npm v11
    participant prep as prepare hook
    participant build as build.js
    participant deps as dep installer
    participant prepack as prepack hook

    Note over npm: git dep install flow
    npm->>prep: run prepare
    prep->>build: node build.js
    build->>build: existsSync('node_modules')?
    alt node_modules absent
        build-->>prep: exit 0 (skip gracefully)
    end
    npm->>deps: install dependencies
    deps-->>npm: node_modules ready
    npm->>prepack: run prepack
    prepack->>build: node build.js
    build->>build: existsSync('node_modules') → true
    build->>build: clean dist/, compile TypeScript
    build-->>prepack: exit 0 (build success)
    npm->>npm: pack tarball & install

    Note over npm: npm publish flow
    npm->>prep: run prepare
    prep->>build: node build.js → build #1
    npm->>prepack: run prepack
    prepack->>build: node build.js → build #2 (redundant)
Loading

Last reviewed commit: 7473589

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

2 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

Comment thread package.json Outdated
Comment on lines +51 to +52
"prepare": "node build.js",
"prepack": "node build.js",

Copy link
Copy Markdown

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.

Comment thread build.js Outdated
Comment on lines +10 to +13
if (!existsSync('node_modules')) {
console.log('⏭️ Skipping build (node_modules not yet available)');
process.exit(0);
}

Copy link
Copy Markdown

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)) {

@clay-good
clay-good requested a review from a team as a code owner August 27, 2026 19:04
@coderabbitai

coderabbitai Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@clay-good clay-good changed the title fix: handle npm git dep installation for GitHub installs fix(build): prepare npm git installs without pnpm Aug 27, 2026

@alfred-openspec alfred-openspec left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed at d7bfad5. The production change is limited to invoking build.js directly from prepare. Local verification passed all eight npm source-install and package lifecycle tests, build, TypeScript checking, and diff checking. Hosted fork CI remains pending, but the exact head is clean.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants