Skip to content

Restore claude.exe after an interrupted auto-update on Windows#167

Merged
luckeyfaraday merged 1 commit into
luckeyfaraday:mainfrom
JJPuertas:fix/claude-exe-restore-after-interrupted-update
Jun 20, 2026
Merged

Restore claude.exe after an interrupted auto-update on Windows#167
luckeyfaraday merged 1 commit into
luckeyfaraday:mainfrom
JJPuertas:fix/claude-exe-restore-after-interrupted-update

Conversation

@JJPuertas

Copy link
Copy Markdown
Contributor

Problem

On Windows, launching a Claude pane through Context Workspace / Athena intermittently fails with:

& : El término '...\.npm-global\node_modules\@anthropic-ai\claude-code\bin\claude.exe'
no se reconoce como nombre de un cmdlet, función, archivo de script o programa ejecutable.
... CommandNotFoundException

Claude Code's auto-updater renames the running bin/claude.exe to claude.exe.old.<timestamp> (Windows locks a running binary, so it must be moved aside before the replacement is written), then drops in the new exe. When that second step is interrupted, bin/ is left with only the backup and no claude.exe:

bin/
  claude.exe.old.1781895498242   # previous working binary
  (claude.exe missing)

Get-Command claude still resolves the npm shim (claude.ps1 / claude.cmd), so the existing if (-not $resolvedAgent) { ... not installed or not on PATH } guard passes. The shim then forwards to the missing bin/claude.exe and dies with CommandNotFoundException — and every subsequent pane launch fails identically until the user repairs the install by hand.

Closes #166.

Fix

Add repairClaudeBinaryPowerShell(), wired into both the fresh (launchPowerShellCommand) and resume (launchResumePowerShellCommand) Claude launch paths, right after the agent-resolution guard. When bin/claude.exe is missing but a claude.exe.old.* backup exists, it restores the newest backup (by LastWriteTime) before invoking the shim and prints a yellow status line. A healthy install is untouched — the copy is guarded on the exe being absent.

It probes the package bin/ relative to the resolved shim, the shim dir itself (in case Get-Command resolves the exe directly), and the default %APPDATA%\npm global prefix.

Testing

  • node --test tests/terminal-launch.test.mjs — 21 pass, including two new tests asserting the repair is present in both Claude paths and absent for codex/opencode.
  • Parse-checked the generated PowerShell with [Parser]::ParseFile — no syntax errors.
  • Functional simulation against a fake broken install: restores claude.exe from the backup and prints the message; a second run against a healthy install leaves the real exe untouched.

🤖 Generated with Claude Code

@luckeyfaraday

Copy link
Copy Markdown
Owner

Thanks for this — the diagnosis and the fix itself look solid. The only blocker is that the branch has drifted out of date with main and now reports a conflict. It's a trivial adjacent-edit clash, not a logic conflict.

What conflicts and why

While this PR was open, main picked up the Codex npm-prefix work (#164), which edited the same two PowerShell command arrays you insert into — launchResumePowerShellCommand and launchPowerShellCommand in client/electron/terminal-launch.ts. main now ends those arrays with:

    ...(kind === "opencode" ? [selectOpenCodeBaselinePowerShell()] : []),
    agent.resumePowerShellCommand,
    kind === "codex" ? codexNpmPrefixPowerShellCleanup() : "",
  ].filter(Boolean).join("; ");

Your change adds ...(kind === "claude" ? [repairClaudeBinaryPowerShell()] : []), right after the opencode line. The two edits touch neighbouring lines, so git flags them — but they're fully compatible.

How to resolve

git fetch origin
git checkout fix/claude-exe-restore-after-interrupted-update
git rebase origin/main

When it stops on client/electron/terminal-launch.ts, in both arrays keep main's lines (the codexNpmPrefixPowerShellCleanup() line and the .filter(Boolean).join("; ") ending) and keep your ...(kind === "claude" ? [repairClaudeBinaryPowerShell()] : []), line immediately after the ...(kind === "opencode" ...) line. So each resolved array reads:

    ...(kind === "opencode" ? [selectOpenCodeBaselinePowerShell()] : []),
    ...(kind === "claude" ? [repairClaudeBinaryPowerShell()] : []),
    // ...rest of the array unchanged from main...

repairClaudeBinaryPowerShell() itself (the function body further down) applies cleanly — no conflict there.

Then finish up and re-verify:

git add client/electron/terminal-launch.ts
git rebase --continue
npm --prefix client run build:electron
npm --prefix client run test:electron   # includes your terminal-launch tests
git push --force-with-lease

A quick re-run of your [Parser]::ParseFile check on the generated PowerShell would be good too, since the surrounding array changed. Once it's green and conflict-free I'll take another pass. Thanks again!

Claude Code's auto-updater renames the running bin/claude.exe to
claude.exe.old.<timestamp> (Windows locks a running binary, so it must be
moved aside before the replacement is written) and then drops in the new
exe. If that second step fails, bin/ is left with only the backup and no
claude.exe. Get-Command still resolves the npm shim (claude.ps1/.cmd), so the
existing "not installed or not on PATH" guard passes -- but launching the
shim then dies with CommandNotFoundException because it forwards to the
missing bin/claude.exe, and every subsequent pane launch fails the same way
until the user repairs the install by hand.

Add repairClaudeBinaryPowerShell(), wired into both the fresh and resume
Claude PowerShell launch paths: when bin/claude.exe is missing but a
claude.exe.old.* backup exists, restore the newest backup before invoking the
shim. A healthy install is left untouched (guarded on the exe being absent).

Verified the generated PowerShell parses cleanly and functionally restores a
simulated broken install while leaving a healthy one alone.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@JJPuertas JJPuertas force-pushed the fix/claude-exe-restore-after-interrupted-update branch from ad931e5 to 714e72b Compare June 20, 2026 16:38
@luckeyfaraday luckeyfaraday merged commit 55543e5 into luckeyfaraday:main Jun 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Windows: launch fails with CommandNotFoundException when auto-update leaves bin/ with only claude.exe.old.*

2 participants