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
Fix AI-CLI detection and launch on Windows. mex sync and mex setup never
detected an installed AI CLI on Windows, so they silently
fell back to
copy-paste prompt mode even when Claude Code / Codex were
installed.
Detection used which, which doesn't exist on Windows
(the built-in is where). execSync("which <cmd>") always threw → every
tool reported as not
installed. Added isCliAvailable() (src/cli-tools.ts):
probes with where
on Windows, which elsewhere.
Launch used spawn/spawnSync, which throw ENOENT
on the Windows claude.cmd wrapper. Switched the launch sites to cross-spawn, which
resolves .cmd/.bat wrappers and escapes args correctly
while keeping the
multi-line prompt as a single argv element. (The naive shell: true is worse —
Node concatenates args unescaped, DEP0190, shattering the
prompt.)
Robustness:runToolInteractive treated status === null (a spawn
failure) as success, swallowing launch errors. Now returns
false on result.error and only treats status === 0 as success.
On Windows, the which-based detection made interactive
sync/setup unusable —
users were forced into copy-paste mode regardless of which
AI CLI they had
installed.
Type of change
Bug fix
New feature
Refactor
Docs
CI/Tooling
How to test
On Windows with claude installed and on PATH, run mex sync in a scaffold
with drift → it now detects "Claude Code" instead of
printing
"No supported AI CLI detected. Falling back to prompts
mode."
Choose interactive (1) → Claude Code launches with the
fix prompt (no spawn claude ENOENT).
On macOS/Linux, behavior is unchanged. npm test → all
240 tests pass.
Thanks for this — the diagnosis and fix are spot on, and switching to cross-spawn over shell: true is the right call. Nice that the new error handling also fixes the timeout-reported-as-success bug in runToolInteractive, not just the Windows path.
A few things before merge:
1. Add a test for the runToolInteractive return-value logic. It's the riskiest change in this PR and is currently untested — isCliAvailable has coverage, but the sync return logic doesn't. Mocking crossSpawn.sync to cover:
{ status: 0 } -> true
{ status: 1 } -> false
{ error: new Error(), status: null } -> false (the timeout / ENOENT case)
{ status: null, signal: "SIGINT" } -> false
would lock in the intended semantics.
3. Trim the lockfile churn.package-lock.json picked up a lot of unrelated "peer": true markers on existing packages (react, esbuild, typescript, postcss, vite-node, yaml, ...) beyond the cross-spawn additions — looks like a different npm version re-resolved the tree. Could you regenerate the lockfile with the project's npm version so the diff is limited to the cross-spawn entries, and confirm npm ci still resolves cleanly?
5. Wrap the launchClaude call. In src/setup/index.ts, await launchClaude(prompt) isn't in a try/catch, so a launch failure or a non-zero claude exit rejects and surfaces as an unhandled rejection. Since this PR is specifically about hardening the launch path, catching it to print a friendly message would round things out.
The other points from review (the user-interrupt behavior change, the @types/cross-spawn major-version lag) are non-blocking and fine as-is.
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
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.
What
Fix AI-CLI detection and launch on Windows.
mex syncandmex setupneverdetected an installed AI CLI on Windows, so they silently
fell back to
copy-paste prompt mode even when Claude Code / Codex were
installed.
which, which doesn't exist on Windows(the built-in is
where).execSync("which <cmd>")always threw → everytool reported as not
installed. Added
isCliAvailable()(src/cli-tools.ts):probes with
whereon Windows,
whichelsewhere.spawn/spawnSync, which throwENOENTon the Windows
claude.cmdwrapper. Switched the launch sites tocross-spawn, whichresolves
.cmd/.batwrappers and escapes args correctlywhile keeping the
multi-line prompt as a single argv element. (The naive
shell: trueis worse —Node concatenates args unescaped, DEP0190, shattering the
prompt.)
runToolInteractivetreatedstatus === null(a spawnfailure) as success, swallowing launch errors. Now returns
false on
result.errorand only treatsstatus === 0as success.Why
Closes #85
On Windows, the
which-based detection made interactivesync/setup unusable —
users were forced into copy-paste mode regardless of which
AI CLI they had
installed.
Type of change
How to test
claudeinstalled and on PATH, runmex syncin a scaffoldwith drift → it now detects "Claude Code" instead of
printing
"No supported AI CLI detected. Falling back to prompts
mode."
fix prompt (no
spawn claude ENOENT).npm test→ all240 tests pass.
Checklist
Checklist
npm test)