Skip to content

Marketplace install of 0.6.0 ships unbuilt node_modules; cache shadows data-dir binding #11

Description

@brendanwhit

Summary

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

  1. Have a working LGTM install (0.5.0 in my case) — confirms data-dir node_modules/better-sqlite3/build/Release/better_sqlite3.node exists.
  2. /plugin update lgtm → installs 0.6.0.
  3. Open a new Claude Code session — SessionStart hook fires.
  4. 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.
  5. 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.
  6. 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/…)
    
  7. 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:

  1. 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.
  2. 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.
  3. Detect and rebuild on startup. If the cache node_modules exists but better-sqlite3/build/Release/better_sqlite3.node is missing, run npm rebuild better-sqlite3 in 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

  • macOS 15.5 (Darwin 25.5.0, arm64)
  • node 24.12.0
  • lgtm 0.6.0 (fdy-skills marketplace)
  • Claude Code (latest as of 2026-05-26)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions