Skip to content

fix(init): wire statusline with absolute node path, not bare node (#181) - #203

Merged
dngioidev merged 1 commit into
mainfrom
fix/181-statusline-execpath
Jul 22, 2026
Merged

fix(init): wire statusline with absolute node path, not bare node (#181)#203
dngioidev merged 1 commit into
mainfrom
fix/181-statusline-execpath

Conversation

@dngioidev

Copy link
Copy Markdown
Owner

Closes #181

Problem

init.mjs wired the Claude Code status line with a bare node "<script>". Claude Code spawns the status-line command in a process that may not have node on PATH (e.g. node installed to %LOCALAPPDATA%\node22\current\node.exe, as on the maintainer's machine 2026-07-22). The command then dies with exit 127 and — because the status line fails silent by design — the bar renders completely blank with no error surfaced. Worse, re-running init rewrote the same bare-node command, so the documented /forge:statusline "re-init" remediation was a no-op for this failure mode.

Fix

At init time, wire the absolute node binary via process.execPath (the node currently running init — portable and absolute), quoted alongside the script path so both tolerate spaces:

statusLine: { type: 'command', command: `"${process.execPath}" "${scriptPath}"` }

mergeJson/deepMerge overwrites the statusLine.command string leaf on each run, so a stale bare-node wiring is healed on the next init --statusline.

Acceptance criteria

  • AC-1 — init writes an absolute node path (process.execPath) into settings.local.json statusLine.command, quoted to tolerate spaces.
  • AC-2 — the wired command resolves even when node is absent from the spawning process's PATH. (Behavioural guarantee; unit-verified via the absolute-path + quoting assertions in AC-4 — a PATH-stripped Claude status-line process can't be spawned in a unit test. The command no longer depends on PATH at all: it names the node binary by absolute path.)
  • AC-3 — existing bare-node wirings are healed on the next init --statusline (idempotent overwrite of the statusLine key via mergeJson; new test seeds a stale bare-node command and asserts it is replaced while unrelated keys survive).
  • AC-4 — regression test covers the process.execPath interpolation + quoting (tests/init.test.mjs, two new #181 tests).

Verification

  • pnpm verify (= vitest run): 373/373 pass locally, including 2 new #181 tests.
  • forge:reviewer (full branch): pass, zero findings.
  • forge:security (full branch): pass, zero findings. No new injection surface — both interpolated values are runtime-derived (Node's own binary path, the plugin's own installed file path); written as an encoded JSON string via atomic writeJson; settings.local.json is gitignored so the machine-specific path never lands in a committed file.

Follow-up

Filed #202 (child of epic #182) to revisit the /forge:statusline §1/§2 "re-init" remediation text — re-init is now a real fix rather than a no-op (out of scope for #181 per its Notes).

⚠️ CI note: GitHub Actions minutes are exhausted this run, so all jobs fail at startup (0 steps, startup_failure) — infrastructure, not this diff. Verified green locally.

🤖 Generated with Claude Code

init wired the status line with a bare `node "<script>"`. Claude Code
spawns the status-line command in a process that may not have `node` on
PATH (e.g. node at %LOCALAPPDATA%\node22\current); the command then dies
with exit 127 and the bar renders silently blank with no error surfaced.

Use process.execPath — the absolute path of the node currently running
init — quoted alongside the script path so both tolerate spaces. Re-init
idempotently overwrites the statusLine.command key, so a stale bare-`node`
wiring is healed on the next `init --statusline`.

Closes #181

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@dngioidev
dngioidev merged commit 34ddca4 into main Jul 22, 2026
0 of 4 checks passed
@dngioidev
dngioidev deleted the fix/181-statusline-execpath branch July 22, 2026 19:13
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.

init.mjs wires statusline with bare node — silently blank when node not on PATH

1 participant