fix(setup_nodejs): verify the binaries a package declares, not its name - #21
fix(setup_nodejs): verify the binaries a package declares, not its name#21Lunchb0ne wants to merge 1 commit into
Conversation
The post-install check assumed a package installs a command named after
itself. It does not have to: opencode-ai installs `opencode`, and
single-file-cli installs `single-file`. For those, `command -v <package>`
finds nothing, so a healthy install is reported broken, reinstalled with
--force, and reported broken again:
opencode-ai is installed but not on PATH - reinstalling
opencode-ai is not callable and could not be restored
1 Node.js module(s) failed: ...
install/archivebox-install.sh in ProxmoxVE hits this today with
single-file-cli. Nothing actually breaks - msg_error does not abort - but
the build ends in red and the failure summary is wrong.
Scoped packages had the same problem from the other direction. They were
skipped outright for want of anything reliable to probe, so
@postlight/parser (mercury-parser, postlight-parser) and the rest were
never verified at all.
Read the installed package.json instead. `bin` is either a string, in
which case the command is the package's own unscoped name, or an object
keyed by command name. That resolves both cases and makes scoped
packages checkable for the first time.
When the manifest cannot be read the old guess is kept for unscoped
packages and scoped ones are still skipped, so a degraded npm root
behaves exactly as before.
Try this branchThe engine and the scripts resolve independently, so a production script can COMMUNITY_SCRIPTS_CORE_URL=https://raw.githubusercontent.com/Lunchb0ne/core/fix/nodejs-verify-declared-bins \
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/ct/debian.sh)"Swap Run a script from a fork as wellcurl -fsSL https://raw.githubusercontent.com/Lunchb0ne/core/fix/nodejs-verify-declared-bins/tools/run.sh |
bash -s -- https://raw.githubusercontent.com/YOU/ProxmoxVED/your-branch ct/debian.sh \
https://raw.githubusercontent.com/Lunchb0ne/core/fix/nodejs-verify-declared-binsNote that Useful flags while testing
|
|
Closing — opened prematurely, not ready for review yet. |
There was a problem hiding this comment.
🟡 Changes recommended
The new verification can incorrectly skip checks when a manifest is unreadable/jq fails and can misreport success for packages declaring multiple binaries.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR improves setup_nodejs’s post-install verification by probing the actual executable(s) a global npm package declares via its installed package.json bin field, rather than assuming the command name matches the package name (and previously skipping scoped packages).
Changes:
- Derive the probed command(s) from the installed module manifest’s
binfield (handling scoped packages). - Preserve prior fallback behavior when the manifest cannot be used, and keep the existing reinstall-with-
--forcerepair path.
File summaries
| File | Description |
|---|---|
| lib/runtime.func | Updates the Node.js global module “callability” check to use declared bin entries from installed manifests, including scoped packages. |
Review details
- Files reviewed: 1/1 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| mod_manifest="${npm_global_root}/${mod_name}/package.json" | ||
| if [[ -n "$npm_global_root" && -f "$mod_manifest" ]]; then | ||
| mod_has_manifest=1 | ||
| # `bin` is either a string (one command, named after the package) or an | ||
| # object keyed by command name. | ||
| mod_bins="$(jq -r 'if (.bin | type) == "string" then (.name | split("/") | last) | ||
| elif (.bin | type) == "object" then (.bin | keys[]) | ||
| else empty end' "$mod_manifest" 2>/dev/null)" | ||
| fi |
| mod_missing="" | ||
| while IFS= read -r mod_bin; do | ||
| [[ -z "$mod_bin" ]] && continue | ||
| command -v "$mod_bin" >/dev/null 2>&1 || mod_missing="$mod_bin" | ||
| done <<<"$mod_bins" |
What's wrong
setup_nodejs's post-install check derives the command name from the package name:A package is not required to name its command after itself.
opencode-aiinstallsopencode;single-file-cliinstallssingle-file. For those,command -v <package-name>finds nothing, so a healthy install is reported broken, reinstalled with--force, and reported broken again:Nothing actually breaks —
msg_errorhere doesn't abort — but the install ends in red and the failure summary is wrong. A user watching that reasonably concludes the build failed.Scoped packages had the same problem from the other side. They were skipped outright:
So the check silently didn't apply to them at all.
How it affects other installs
NODE_MODULEappears in 153 files across ProxmoxVE. The overwhelming majority passyarn,pnpm,nextorserve, where the package name and the command match — those are unaffected, before and after.The change matters for two groups:
Packages whose command differs from their name — currently a false failure.
install/archivebox-install.shhits this today:single-file-clideclaresbin: { "single-file": ... }, so every archivebox install prints the "not callable" error and an inflated failed-module count for a package that installed correctly.Scoped packages — currently unverified. In the same line,
@postlight/parserdeclaresmercury-parserandpostlight-parser. It was skipped, so if those commands really were missing, the check that exists to catch exactly that would say nothing.After the change, both are checked correctly:
The fix
Read the installed
package.jsoninstead of guessing.binis either a string — in which case the command is the package's own unscoped name — or an object keyed by command name:That resolves both failure modes and makes scoped packages checkable for the first time.
jqis already in the container base packages, so this adds no dependency.Three behaviours are deliberately preserved:
binis skipped rather than probed for a command it never had.--force, re-check, and count a failure if it still isn't there. Only the name being probed changed.Testing
Found on Proxmox VE 9.2.11 (kernel 7.0.6-2-pve) while installing
t3@latest,@anthropic-ai/claude-code@latest,@openai/codex@latest,opencode-ai@latest—opencode-aiproduced the false failure on every run while/usr/bin/opencodewas present and working (opencode --version→ 1.18.26).The
binresolution was checked against the real published manifests foropencode-ai,t3,@anthropic-ai/claude-code,@openai/codex,single-file-cliand@postlight/parser— all resolve to the correct commands.The patched block was then exercised against fixtures mirroring a real global npm root:
failed_modules=0opencode), not the packagebash -npasses across every.funcin the repo.What I have not verified
lib/runtime.funcfromCOMMUNITY_SCRIPTS_CORE_URL, so a local checkout only covers the host side. Happy to run it against a branch URL if that's useful.lib/, so it should be backend-independent, but I can't claim I ran it.shellcheck/shfmtnot run — neither is installed on my host. Worth a look before merge.No function was added, renamed or removed, so
lib/API.txtis unchanged, and no new file needs listing in_CS_ENGINE_FILES.