You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Plugin installation via @npmcli/arborist fails on any machine that isn't the build machine. The compiled binary contains a hardcoded absolute path to node-gyp from the build environment.
Error
Cannot find module '/home/runner/work/opencode/node_modules/.bun/node-gyp@12.2.0/node_modules/node-gyp/bin/node-gyp.js' from '/$bunfs/root/src/index.js'
Root Cause
@npmcli/run-script/lib/make-spawn-args.js line 29:
Bun's bundler pre-resolves require.resolve() calls with static string arguments at compile time, baking the build machine's absolute path into the binary. At runtime on any other machine, this path doesn't exist.
This was introduced in #18308 (merged Apr 1) which replaced BunProc.install() (subprocess-based bun add) with bundled @npmcli/arborist. The old approach spawned bun as a child process with no hardcoded paths. The new approach bundles the npm resolver, which brings along @npmcli/run-script and its node-gyp resolution.
Impact
Affects every compiled binary distributed to users (not just self-built)
Will break plugin installation for any plugin whose transitive deps trigger arborist.reify() lifecycle script evaluation
Currently affects: oh-my-opencode, and likely any plugin with native optional dependencies
Fix
Two changes needed:
packages/opencode/src/npm/index.ts: Add ignoreScripts: true to both Arborist constructors. opencode installs packages for plugins/formatters/LSPs — it should not run arbitrary lifecycle scripts. Packages with native deps already ship prebuilt platform binaries via optionalDependencies.
packages/opencode/script/build.ts: Add external: ["node-gyp"] to Bun.build() options to prevent Bun from pre-resolving the require.resolve('node-gyp/...') path at compile time. This is defense-in-depth — even if ignoreScripts is somehow bypassed, the path won't be hardcoded.
Bug
Plugin installation via
@npmcli/arboristfails on any machine that isn't the build machine. The compiled binary contains a hardcoded absolute path tonode-gypfrom the build environment.Error
Root Cause
@npmcli/run-script/lib/make-spawn-args.jsline 29:Bun's bundler pre-resolves
require.resolve()calls with static string arguments at compile time, baking the build machine's absolute path into the binary. At runtime on any other machine, this path doesn't exist.This was introduced in #18308 (merged Apr 1) which replaced
BunProc.install()(subprocess-basedbun add) with bundled@npmcli/arborist. The old approach spawned bun as a child process with no hardcoded paths. The new approach bundles the npm resolver, which brings along@npmcli/run-scriptand itsnode-gypresolution.Impact
arborist.reify()lifecycle script evaluationFix
Two changes needed:
packages/opencode/src/npm/index.ts: AddignoreScripts: trueto bothArboristconstructors. opencode installs packages for plugins/formatters/LSPs — it should not run arbitrary lifecycle scripts. Packages with native deps already ship prebuilt platform binaries viaoptionalDependencies.packages/opencode/script/build.ts: Addexternal: ["node-gyp"]toBun.build()options to prevent Bun from pre-resolving therequire.resolve('node-gyp/...')path at compile time. This is defense-in-depth — even ifignoreScriptsis somehow bypassed, the path won't be hardcoded.Diff
Repro
bun run script/build.ts@sjawhar/oh-my-opencode@latest)opencode --print-logs— observefailed to install pluginwith the hardcoded path errorRelated
@npmcli/arborist@npmcli/run-script— the package containing the problematicrequire.resolve()