Skip to content

Marketplace hooks fail under nvm #27

Description

Summary: Marketplace install uses bare node, which breaks under nvm (GUI PATH / wrong Node version); add a version-manager-aware launcher.

Description

The recommended install path (Cursor Settings → Plugins → add https://github.com/langchain-ai/langsmith-cursor-plugins) ships a static hooks/hooks.json that runs:

node ./bundle/<hook>.js

On macOS, Cursor launched from the Dock/Finder often resolves a different node than the developer’s interactive shell (or an old nvm default). Hooks that only buffer events can still succeed, while stop.js crashes on import because it requires Node ≥ 22.13 (node:sqlite). Tracing then never reaches LangSmith, and ~/.cursor/langsmith-hook.log may never be created (crash before logger init).

The local installer (scripts/install.mjs) already documents this and pins process.execPath into ~/.cursor/hooks.json, but:

  1. Most users never run that installer (marketplace is the recommended path).
  2. Pinning …/versions/node/vX.Y.Z/bin/node drifts on the next nvm install / nvm alias default.

Observed failure mode

Command: node ./bundle/stop.js (…) exit code: 1
Error [ERR_UNKNOWN_BUILTIN_MODULE]: No such built-in module: node:sqlite
  • Earlier hooks (beforeSubmitPrompt, postToolUse, …) may still write ~/.cursor/langsmith-state.json.
  • turn_count stays 0 (stop never finalizes).
  • No useful lines in ~/.cursor/langsmith-hook.log because the process dies at module load.

Proposal

Add a relative, version-manager-aware launcher in the plugin repo and use it from marketplace hooks.json (Cursor already runs hooks with cwd = plugin root).

1. Add scripts/run-node.sh

Resolve Node in this order (example):

  1. LANGSMITH_CURSOR_NODE / NODE_BINARY override
  2. nvm default ($NVM_DIR/alias/default, follow aliases → $NVM_DIR/versions/node/v…/bin/node)
  3. Optional: fnm / asdf / volta
  4. command -v node
  5. Assert usability, e.g. node -e "require('node:sqlite')" (or version ≥ 22.13), with a clear stderr message if not

Then exec the resolved binary with the hook script args.

2. Update hooks/hooks.json (marketplace path)

Change each hook from:

{ "command": "node ./bundle/stop.js" }

to something like:

{ "command": "/bin/bash ./scripts/run-node.sh ./bundle/stop.js" }

3. Align scripts/install.mjs

Prefer emitting the same launcher (or installing a copy under ~/.cursor/bin/) instead of baking a versioned absolute process.execPath, so upgrades of nvm’s default don’t require re-running the installer.

4. Docs

  • README: Node ≥ 22.13, nvm/GUI PATH caveat, how to set LANGSMITH_CURSOR_NODE.
  • Troubleshooting: if stop exits 1 with node:sqlite, check which Node the launcher selected (log path + version on stderr when check fails).

Related context

scripts/install.mjs already states:

Cursor spawns hooks from a GUI context without your shell PATH / version manager, so the command must use an absolute node binary and absolute bundle paths.

Marketplace install currently ignores that for the node binary itself.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions