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
Installing lgtm@0.6.0 via the fdy-skills Claude Code marketplace lands a real node_modules/ directory under the plugin's cache root that lacks the compiled better-sqlite3 native binding. ensure-server.sh only symlinks the data-dir's node_modules (where the binding is compiled) when the cache root has no node_modules, so the symlink fallback is skipped and the shipped, binding-less cache copy wins. Result: server crashes on startup with Could not locate the bindings file, port 9900 stays free, and /lgtm MCP tools are unavailable.
This is the same failure mode as #1, but downstream — #1 fixed the in-hook npm rebuild better-sqlite3 so the data-dir copy gets built, but the cache copy now shadows it.
Repro
Have a working LGTM install (0.5.0 in my case) — confirms data-dir node_modules/better-sqlite3/build/Release/better_sqlite3.node exists.
/plugin update lgtm → installs 0.6.0.
Open a new Claude Code session — SessionStart hook fires.
Hook reaches:
if [ !-e\"${CLAUDE_PLUGIN_ROOT}/node_modules\" ];then
ln -s \"${CLAUDE_PLUGIN_DATA}/node_modules\"\"${CLAUDE_PLUGIN_ROOT}/node_modules\"fi
${CLAUDE_PLUGIN_ROOT}/node_modules is the real shipped directory → branch skipped.
Server starts, requires better-sqlite3, walks up from dist/server/store.js to the cache node_modules (real dir, not the data-dir symlink), no compiled .node there.
Server log:
UNCAUGHT_EXCEPTION Error: Could not locate the bindings file. Tried:
→ /…/cache/fdy-skills/lgtm/0.6.0/node_modules/better-sqlite3/build/better_sqlite3.node
→ /…/cache/fdy-skills/lgtm/0.6.0/node_modules/better-sqlite3/build/Release/better_sqlite3.node
(+ 11 more paths, all under cache/…/0.6.0/…)
lsof -nP -iTCP:9900 → nothing listening.
Workaround
rm -rf ~/.claude/plugins/cache/fdy-skills/lgtm/0.6.0/node_modules
# Re-run the hook or restart Claude Code — symlink to data dir is created# and the server starts.
After this, ls -la ~/.claude/plugins/cache/fdy-skills/lgtm/0.6.0/node_modules correctly shows a symlink to …/data/lgtm-fdy-skills/node_modules, the data-dir's compiled .node resolves, and port 9900 binds.
Suggested fix
A few options:
Don't ship node_modules in the marketplace tarball. Let the hook's existing data-dir install + symlink path do the work — it already handles versioning via diff -q package.json.
Make the symlink unconditional / replace existing node_modules. Change the hook to remove or replace ${CLAUDE_PLUGIN_ROOT}/node_modules rather than skip when it exists. Defensible because the data-dir is the install pipeline's source of truth.
Summary
Installing
lgtm@0.6.0via the fdy-skills Claude Code marketplace lands a realnode_modules/directory under the plugin's cache root that lacks the compiledbetter-sqlite3native binding.ensure-server.shonly symlinks the data-dir'snode_modules(where the binding is compiled) when the cache root has nonode_modules, so the symlink fallback is skipped and the shipped, binding-less cache copy wins. Result: server crashes on startup withCould not locate the bindings file, port 9900 stays free, and/lgtmMCP tools are unavailable.This is the same failure mode as #1, but downstream — #1 fixed the in-hook
npm rebuild better-sqlite3so the data-dir copy gets built, but the cache copy now shadows it.Repro
node_modules/better-sqlite3/build/Release/better_sqlite3.nodeexists./plugin update lgtm→ installs 0.6.0.SessionStarthook fires.${CLAUDE_PLUGIN_ROOT}/node_modulesis the real shipped directory → branch skipped.better-sqlite3, walks up fromdist/server/store.jsto the cachenode_modules(real dir, not the data-dir symlink), no compiled.nodethere.lsof -nP -iTCP:9900→ nothing listening.Workaround
After this,
ls -la ~/.claude/plugins/cache/fdy-skills/lgtm/0.6.0/node_modulescorrectly shows a symlink to…/data/lgtm-fdy-skills/node_modules, the data-dir's compiled.noderesolves, and port 9900 binds.Suggested fix
A few options:
node_modulesin the marketplace tarball. Let the hook's existing data-dir install + symlink path do the work — it already handles versioning viadiff -q package.json.${CLAUDE_PLUGIN_ROOT}/node_modulesrather than skip when it exists. Defensible because the data-dir is the install pipeline's source of truth.node_modulesexists butbetter-sqlite3/build/Release/better_sqlite3.nodeis missing, runnpm rebuild better-sqlite3in the cache dir. More fragile than Plugin install via marketplace leaves better-sqlite3 unbuilt; server fails silently #1 or Server crash mid-session loses unsaved comments silently #2.Option 1 is the cleanest if the marketplace publish process allows excluding
node_modules. Option 2 is the smallest patch.Versions