start.mjs background install of turndown/better-sqlite3 dies on the #1139 Arborist "edgesOut" crash on macOS — silent, fixed by --legacy-peer-deps

Author: plz12345Created Sep 17, 2026Updated Sep 17, 2026

Summary

The boot-time background installer in start.mjs (added in #634) hits the same npm Arborist edgesOut crash reported in #1139 — on macOS, not just Windows — so turndown, turndown-plugin-gfm and @mixmark-io/domino are never written to disk and ctx_fetch_and_index stays broken for the life of the install. Because the spawn uses stdio: "ignore" and Claude Code discards MCP stderr, there is no signal: the child.on("exit") warning added in #861 goes nowhere.

Passing --legacy-peer-deps makes the install succeed in-place, so the isolated-dir copy of #1139 isn't needed here.

Environment

  • macOS 15 (Darwin 25.6.0), arm64
  • Node v22.23.1, npm 10.9.8 (nvm)
  • context-mode v1.0.169, Claude Code marketplace install (~/.claude/plugins/cache/context-mode/context-mode/1.0.169/, no node_modules/)

Symptom

ctx_fetch_and_index fails with a missing-turndown error. node_modules/ does not exist at all in the plugin root, so better-sqlite3 is missing for the same reason.

Reproduction

In the plugin root, running what start.mjs spawns:

bash
npm install turndown turndown-plugin-gfm @mixmark-io/domino \
  --no-package-lock --no-save --silent --no-audit --no-fund
# npm error Cannot read properties of null (reading 'edgesOut')

The debug log shows Arborist crashing in #loadPeerSet while resolving devDependencies — the last packuments fetched are vitest@*, @vitejs/devtools-vitest, @vitest/browser-playwright:

verbose stack TypeError: Cannot read properties of null (reading 'edgesOut')
    at #loadPeerSet (@npmcli/arborist/lib/arborist/build-ideal-tree.js:1289:38)
    at async #buildDepStep (.../build-ideal-tree.js:904:11)
silly unfinished npm timer idealTree:node_modules/vitest

--omit=dev does not help (arborist still builds the full ideal tree). --legacy-peer-deps does:

bash
npm install turndown turndown-plugin-gfm @mixmark-io/domino \
  --legacy-peer-deps --no-package-lock --no-save --no-audit --no-fund
# added 191 packages in 6s

After that, ctx_fetch_and_index works with no server restart (the sandbox subprocess resolves at call time).

Suggested fixes

  1. Add --legacy-peer-deps to NPM_FLAGS in the start.mjs background installer. The installer only ever adds leaf packages; peer-graph strictness buys nothing there, and the published devDependencies are what trip the crash.
  2. Better: run that install in an isolated dir and copy in (the #1139 workaround), so the plugin's own package.json never enters the ideal tree.
  3. The child.on("error")/child.on("exit") stderr writes from #861 are invisible under Claude Code. Consider recording the failure somewhere the tool can read it, so ctx_fetch_and_index can say "background dependency install failed (exit N)" instead of surfacing a bare module-not-found (cf. #1135).

Related: #1139 (same arborist crash, manual repair path, Windows), #1162 (same deps missing when boot runs start-http.mjs), #1105 (ensure-deps npm resolution).