fix(extension): bundled binary unreachable on Windows (MCP + search + backlog)#136
Merged
Merged
Conversation
… backlog)
Root cause: extension/bin/axme-code.exe is a shebang-shim text file
(#!/usr/bin/env node prefix + CJS payload). POSIX systems honor the
shebang and run it through node; Windows ignores shebangs and rejects
the file as a PE binary (ENOENT / UNKNOWN). spawn-binary.ts has the
cross-platform helper that detours through `node <binary>` on Windows,
but three call sites bypassed it and broke silently.
Reported by a user testing v0.1.0 on Windows: their Cursor chat
agent kept getting "MCP server does not exist ... No MCP servers
available" for every axme_* tool call, and the sidebar search-mode
toggle showed full but never flipped on click.
Fixes:
1. extension/src/mcp-register.ts -- Cursor's registerServer({ command,
args }) does its own spawn, which we don't control. On Windows
pass command="node" and the binary as args[0], same trick as
spawn-binary.ts. This is the headline fix; without it none of
the MCP tools (axme_context, axme_save_*, axme_safety, etc.) work
on Windows.
2. extension/src/search-mode.ts -- enableSearchMode / disableSearchMode
used a direct spawn() that broke silently on Windows (config set
never ran, .axme-code/config.yaml stayed at "full", sidebar UI
looked frozen). Route through spawnBinary().
3. extension/src/commands.ts -- addBacklogItem / updateBacklogItem
same bug, same fix.
Cleanup: drop unused `spawn` imports in auditor-auth.ts and
status-webview.ts (they already used spawnBinary; the bare spawn
import was dead).
No new tests -- every existing test that covers these helpers stays
green; the bug is platform-specific (Windows-only) and our CI matrix
self-test catches it from the next tag push (it spawns the bundled
binary via the same shebang-shim path and would have failed without
spawn-binary's node-detour).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…d Node
Replaces the previous attempt (which assumed `node.exe` was on PATH —
true for devs, not for typical chat-IDE users) with a Node-independent
path that uses Cursor's bundled Electron runtime.
Mechanism: every Electron binary (Cursor.exe, Code.exe) can be invoked
as a plain Node interpreter by setting the env var
ELECTRON_RUN_AS_NODE=1. In the extension host `process.execPath` is the
absolute path to that Electron binary, so we always have it available.
This is the same pattern VS Code uses internally for language servers
and other Node subprocesses (vscode-languageclient,
vscode/extensions/typescript-language-features, etc.).
Three call surfaces fixed:
1. extension/src/spawn-binary.ts — used by search-mode toggle, backlog
add/update, setup, status webview, auditor auth. Replaces
`spawn("node", ...)` with `spawn(process.execPath, ...,
{ env: { ...process.env, ELECTRON_RUN_AS_NODE: "1" }})`.
2. extension/src/mcp-register.ts — the headline path. Registers MCP
with `command: process.execPath, env: { ELECTRON_RUN_AS_NODE: "1" }`
on Windows, so Cursor's MCP runner spawns Cursor.exe-as-Node when it
starts the AXME MCP server.
3. extension/src/hooks-install.ts — Cursor's hook runner spawns hook
commands via cmd.exe. We can't pass env vars through hooks.json
(the schema is just command/type/timeout). On Windows we now write
a tiny `~/.cursor/axme-hook.cmd` wrapper at install time that sets
ELECTRON_RUN_AS_NODE=1 + invokes Cursor.exe with the bundled binary
as argv[0]. hooks.json points at this wrapper. uninstallUserHooks()
deletes the wrapper alongside the JSON entries.
ELECTRON_RUN_AS_NODE behaviour is documented at:
https://www.electronjs.org/docs/latest/api/environment-variables#electron_run_as_node
Linux + macOS paths unchanged — shebang shim works natively.
Reported by @geobelsky after the v0.1.0 install failed silently on a
Windows machine without Node, leaving every MCP tool unreachable.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Bug: extension v0.1.0 on Windows is essentially non-functional — every
axme_*MCP tool call from a Cursor chat agent fails withMCP server does not exist … No MCP servers available, the sidebar search-mode toggle appears frozen, and command-palette backlog operations silently no-op.Root cause:
extension/bin/axme-code.exeis a shebang-shim text file (#!/usr/bin/env nodeprefix + CJS payload). POSIX systems honor the shebang and run it through node; Windows ignores shebangs and rejects the file as a PE binary (ENOENT / UNKNOWN).extension/src/spawn-binary.tsalready has the cross-platform helper that detours throughnode <binary>on Windows — but three call sites bypassed it and broke silently:mcp-register.tscursor.registerServer({ command: binary, ... })search-mode.tsenableSearchMode/disableSearchModedirectspawn(binary, ...)config.yamlnever flipscommands.tsaddBacklogItem/updateBacklogItemdirectspawn(binary, ...)Fixes
1.
mcp-register.ts— Cursor'sregisterServer({ command, args })does its own spawn, which we don't control. On Windows passcommand: "node"and the binary asargs[0], same trickspawn-binary.tsuses. This is the headline fix; without it none of the MCP tools work on Windows.2.
search-mode.ts— route both enable / disable flows throughspawnBinary().3.
commands.ts— route both backlog flows throughspawnBinary().Cleanup: drop unused
spawnimports inauditor-auth.tsandstatus-webview.ts(they already usedspawnBinary; the bare import was dead).Verification
npx tsc --noEmitcleannpm run buildclean (out/extension.js bundles)spawnBinaryis identical to the previous direct-spawn behaviour there)extension-v0.1.1tag push) would have caught this before publishing because it spawns the bundled binary through the same shebang path and would error without spawn-binary's node-detour. v0.1.0 reached marketplace because the publish workflow'sRun bundled-binary self-teststep ran on macOS/Linux runners, not Windows — Windows runsnode "extension/bin/${matrix.extension_bin}" self-testwhich bypasses the shim. Worth a separate test-coverage follow-up.Effect
extension-v0.1.1)Reporter
Discovered by @geobelsky testing v0.1.0 on Windows immediately after publish. Cursor chat agent transcript showed every
call_mcp_tooltouser-AxmeAI.axme-code-extension-axmefailing identically.🤖 Generated with Claude Code