Found during Titan RECON (v3.15.0)
Severity: Medium
Command: codegraph embed -m minilm
Regression of: #1175 (closed)
Reproduction
- Install codegraph globally:
npm install -g @optave/codegraph (on a machine where npm's global prefix is Homebrew-managed, e.g. /opt/homebrew).
cd into any target repo, run codegraph build . then codegraph embed -m minilm.
Actual behavior
@huggingface/transformers is not found, so promptInstall() runs. resolveNpmInstallCwd() (src/domain/search/models.ts) computes the install cwd as path.dirname(path.dirname(path.dirname(path.dirname(pkgJsonPath)))) where pkgJsonPath is .../node_modules/@optave/codegraph/package.json. For a global install this resolves to the npm global modules root itself, e.g. /opt/homebrew/lib — the same directory that contains node_modules/npm (npm's own installation).
Running npm install --no-save @huggingface/transformers with cwd: /opt/homebrew/lib fails:
npm error code MODULE_NOT_FOUND
npm error Cannot find module 'node-gyp/bin/node-gyp.js'
npm error Require stack:
npm error - /opt/homebrew/lib/node_modules/npm/node_modules/@npmcli/run-script/lib/make-spawn-args.js
...
Reproduced directly (no codegraph involved) with:
cd /opt/homebrew/lib && npm install --no-save @huggingface/transformers
— same error. This confirms it's npm's own internal lifecycle-script machinery breaking when asked to install into its own global modules root, not something codegraph can control once it targets that directory.
Confirmed the target project's local node_modules/@huggingface/transformers being already present and resolvable (require.resolve succeeds) makes no difference — the globally-installed codegraph binary never looks there, only at its own resolved install root.
Expected behavior
Auto-install for a globally-installed codegraph should not attempt to write into npm's own global modules root. Options:
- Detect the global-install case (e.g.
pkgJsonPath sits under the npm global prefix — compare against npm root -g or check if the resolved dir contains node_modules/npm) and skip straight to the "install it manually" instructions instead of attempting an auto-install.
- Or, when a global install is detected, prefer installing into a per-user cache/support directory added to
NODE_PATH for the transformers dynamic import, rather than colliding with npm's own installation tree.
- At minimum, catch this failure mode and give actionable guidance ("codegraph is installed globally; run
npm install -g @huggingface/transformers yourself") rather than a generic Auto-install ... failed + ENGINE_UNAVAILABLE.
Root cause
resolveNpmInstallCwd() in src/domain/search/models.ts assumes dirname(pkgJsonPath, 4) is always a normal project root. For a global npm install, that directory is the npm global prefix's lib/ (or equivalent), which already contains npm's own installation and is not a safe target for arbitrary npm install side effects.
Impact
Any user who installs codegraph globally via npm install -g (a documented/common install path) on a machine where the global npm prefix has this npm packaging quirk (observed via Homebrew's Node/npm on macOS) cannot use codegraph embed at all — semantic search and DRY-detection features silently degrade to unavailable, with no way to work around it short of manually fixing the global npm installation.
Found during Titan RECON (v3.15.0)
Severity: Medium
Command:
codegraph embed -m minilmRegression of: #1175 (closed)
Reproduction
npm install -g @optave/codegraph(on a machine where npm's global prefix is Homebrew-managed, e.g./opt/homebrew).cdinto any target repo, runcodegraph build .thencodegraph embed -m minilm.Actual behavior
@huggingface/transformersis not found, sopromptInstall()runs.resolveNpmInstallCwd()(src/domain/search/models.ts) computes the install cwd aspath.dirname(path.dirname(path.dirname(path.dirname(pkgJsonPath))))wherepkgJsonPathis.../node_modules/@optave/codegraph/package.json. For a global install this resolves to the npm global modules root itself, e.g./opt/homebrew/lib— the same directory that containsnode_modules/npm(npm's own installation).Running
npm install --no-save @huggingface/transformerswithcwd: /opt/homebrew/libfails:Reproduced directly (no codegraph involved) with:
— same error. This confirms it's npm's own internal lifecycle-script machinery breaking when asked to install into its own global modules root, not something codegraph can control once it targets that directory.
Confirmed the target project's local
node_modules/@huggingface/transformersbeing already present and resolvable (require.resolvesucceeds) makes no difference — the globally-installedcodegraphbinary never looks there, only at its own resolved install root.Expected behavior
Auto-install for a globally-installed codegraph should not attempt to write into npm's own global modules root. Options:
pkgJsonPathsits under the npm global prefix — compare againstnpm root -gor check if the resolved dir containsnode_modules/npm) and skip straight to the "install it manually" instructions instead of attempting an auto-install.NODE_PATHfor the transformers dynamic import, rather than colliding with npm's own installation tree.npm install -g @huggingface/transformersyourself") rather than a genericAuto-install ... failed+ENGINE_UNAVAILABLE.Root cause
resolveNpmInstallCwd()insrc/domain/search/models.tsassumesdirname(pkgJsonPath, 4)is always a normal project root. For a global npm install, that directory is the npm global prefix'slib/(or equivalent), which already contains npm's own installation and is not a safe target for arbitrarynpm installside effects.Impact
Any user who installs codegraph globally via
npm install -g(a documented/common install path) on a machine where the global npm prefix has this npm packaging quirk (observed via Homebrew's Node/npm on macOS) cannot usecodegraph embedat all — semantic search and DRY-detection features silently degrade to unavailable, with no way to work around it short of manually fixing the global npm installation.