diff --git a/.changeset/jolly-pumas-dance.md b/.changeset/jolly-pumas-dance.md new file mode 100644 index 000000000..28b09701e --- /dev/null +++ b/.changeset/jolly-pumas-dance.md @@ -0,0 +1,5 @@ +--- +type: Fixed +pr: 2979 +--- +Managed JS hooks now resolve under GUI/minimal-PATH runtimes — installer emits process.execPath (absolute, quoted, forward-slash-normalized) as the runner for every .js hook command instead of bare node. See #2979. diff --git a/.changeset/zesty-jays-wake.md b/.changeset/zesty-jays-wake.md new file mode 100644 index 000000000..28b09701e --- /dev/null +++ b/.changeset/zesty-jays-wake.md @@ -0,0 +1,5 @@ +--- +type: Fixed +pr: 2979 +--- +Managed JS hooks now resolve under GUI/minimal-PATH runtimes — installer emits process.execPath (absolute, quoted, forward-slash-normalized) as the runner for every .js hook command instead of bare node. See #2979. diff --git a/bin/install.js b/bin/install.js index 390f912d5..1813274d8 100755 --- a/bin/install.js +++ b/bin/install.js @@ -525,6 +525,82 @@ function computePathPrefix({ isGlobal, isOpencode, isWindowsHost: _isWindowsHost return `${resolvedTarget}/`; } +/** + * Resolve the absolute path to the node binary running the installer. + * Used as the runner for .js hooks so they execute in GUI/minimal-PATH + * runtimes (Gemini, Antigravity, Codex CLIs launched from a Finder + * shortcut etc.) where bare `node` is not on `/usr/bin:/bin:/usr/sbin:/sbin` + * and the hook would fail with `node: command not found` (#2979). + * + * Returns a forward-slash-normalized, double-quoted path so the emitted + * command is shell-safe across POSIX and Windows. `process.execPath` + * gives the absolute path of the node binary actively running the + * installer — that is the version the user just installed under, and + * the right default runtime for hooks invoked under the same install. + */ +function resolveNodeRunner() { + const execPath = typeof process.execPath === 'string' ? process.execPath : ''; + if (!execPath) return null; + // JSON.stringify produces a properly escaped double-quoted shell token, + // safe for paths containing spaces or unusual characters. + return JSON.stringify(execPath.replace(/\\/g, '/')); +} + +/** + * Rewrite legacy `node .../gsd-*.js` command strings in settings.hooks to use + * the absolute Node binary path (#2979 follow-up: CR feedback on #3002). + * + * The original #2979 fix only emitted absolute paths for *newly registered* + * hooks. Pre-existing entries kept their bare `node ` prefix on reinstall, + * which left them broken under minimal-PATH GUI runtimes — exactly the + * failure mode the original fix was meant to close. This walker normalizes + * any managed-hook entry whose command starts with bare `node ` to + * `