Skip to content

fix(install): fail fast when MCP parent respawns tempyr.exe#39

Merged
cleak merged 2 commits into
masterfrom
claude/install-respawn-fix
May 1, 2026
Merged

fix(install): fail fast when MCP parent respawns tempyr.exe#39
cleak merged 2 commits into
masterfrom
claude/install-respawn-fix

Conversation

@cleak
Copy link
Copy Markdown
Owner

@cleak cleak commented May 1, 2026

Summary

install.ps1's lock-recovery path could feel hung for several minutes when a parent process (another Claude Code session, an IDE with tempyr registered as an MCP server, etc.) respawned tempyr --mcp children faster than we could kill them. Two fixes:

  • Shorter per-PID wait — cut Wait-Process -Timeout 15 to -Timeout 2. Force-kill is synchronous; the long timeout only stalled when Stop-Process silently failed (e.g. access denied), turning four PIDs into 60s of silence per attempt.
  • Respawn detectionStop-TargetProcesses now returns {Cleared, Respawned}. If post-kill PIDs differ from the ones we killed, a parent is winning the race and retrying cargo will too. We now throw immediately with a clear message: close those clients and re-run.

Test plan

  • .\install.ps1 with no other tempyr clients running → installs cleanly in one pass.
  • .\install.ps1 while another Claude Code session has tempyr MCP wired up → fails fast with the "close those clients" message instead of grinding through four cargo retries.
  • .\install.ps1 against a binary locked by a non-respawning process → kills it on first attempt and proceeds.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved detection of processes blocking installation, including cases where they restart under new IDs.
    • Immediate, clearer error when a blocking process respawns during install attempts.
    • Retry behavior refined: installation retries only proceed when the target is confirmed unlocked; otherwise standard delay-and-retry is followed.

The lock-recovery path silently retried cargo install up to four times
when a parent process (another Claude Code session, an IDE, etc.)
respawned `tempyr --mcp` children faster than we could kill them. Each
attempt also stalled up to 60s on `Wait-Process -Timeout 15` per PID
when Stop-Process silently failed, making the script feel hung.

- Cut per-PID Wait-Process timeout from 15s to 2s. Force-kill is
  synchronous; the long wait only ever stalled when the kill failed.
- `Stop-TargetProcesses` now returns `{Cleared, Respawned}`. If the
  post-kill PIDs differ from what we killed, a parent is respawning
  them and `Invoke-CargoInstallWithLockRecovery` throws with a clear
  message telling the user to close other Claude Code / IDE sessions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 1, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0e30ba45-4cb0-4880-908e-461a4da2c719

📥 Commits

Reviewing files that changed from the base of the PR and between 4c9d1ad and 356776f.

📒 Files selected for processing (1)
  • install.ps1

📝 Walkthrough

Walkthrough

install.ps1 changes replace a boolean stop result with a structured object (PidsCleared, IsUnlocked, Respawned). The installer rechecks processes and file lock state after force-stop, gates cargo retry on IsUnlocked, and immediately errors when Respawned is true.

Changes

Cohort / File(s) Summary
Lock recovery & install flow
install.ps1
Stop-TargetProcesses now returns a structured object (PidsCleared, IsUnlocked, Respawned) and re-detects matching Tempyr processes post-stop; Invoke-CargoInstallWithLockRecovery consumes this object, only retries cargo when IsUnlocked=true, and throws a clear error when Respawned=true. IsUnlocked is additionally gated by Test-FileLocked for fast-retry decisions.

Sequence Diagram(s)

sequenceDiagram
  participant Installer as Installer Script
  participant StopFn as Stop-TargetProcesses
  participant OS as Operating System / Processes
  participant LockChk as Test-FileLocked
  participant Cargo as cargo installer

  Installer->>StopFn: request stop of Tempyr PIDs
  StopFn->>OS: force-stop targeted processes
  OS-->>StopFn: remaining matching processes (new PIDs?)
  StopFn->>StopFn: compare original vs remaining PIDs -> set Respawned
  StopFn->>LockChk: check file lock state
  LockChk-->>StopFn: IsUnlocked (true/false)
  StopFn-->>Installer: return {PidsCleared, IsUnlocked, Respawned}
  alt Respawned = true
    Installer->>Installer: throw instructive error (abort)
  else IsUnlocked = true
    Installer->>Cargo: attempt cargo install (retry)
  else
    Installer->>Installer: follow delay-and-retry loop (no immediate retry)
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 I nudged the locks and watched PIDs hop,
I counted new feet where the old ones stopped—
If they respawn, I shout "Abort!" with glee,
Otherwise I wait and let cargo be. ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically identifies the main change: implementing fast-fail behavior when parent processes respawn tempyr.exe, which is the core objective of this PR.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Review rate limit: 3/5 reviews remaining, refill in 13 minutes and 57 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@install.ps1`:
- Around line 89-105: Stop-TargetProcesses currently returns Cleared = $true
when matching tempyr PIDs disappear even if the file remains locked; update
Stop-TargetProcesses to re-check the actual file lock (call Test-FileLocked
-BinaryPath $BinaryPath or equivalent) before returning Cleared = $true and only
set Cleared = $true when Test-FileLocked reports unlocked; alternatively, if you
prefer a rename approach, change the return field (e.g., PidsCleared) to
indicate only PID removal and add a separate IsUnlocked boolean driven by
Test-FileLocked so callers (the retry logic at the cargo re-run site) gate fast
retries on IsUnlocked rather than the PID-only flag.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 86b6ec2d-799b-409a-a078-f7e2595b6fc3

📥 Commits

Reviewing files that changed from the base of the PR and between 6fb679c and 4c9d1ad.

📒 Files selected for processing (1)
  • install.ps1

Comment thread install.ps1 Outdated
Stop-TargetProcesses previously signaled Cleared=true whenever matching
tempyr.exe PIDs were gone, even if the binary stayed locked by something
else (AV scan mid-flight, Explorer preview, stale kernel handle). The
caller would then fast-retry cargo without the file-in-use cause having
actually cleared.

Split the return into PidsCleared (kill worked) and IsUnlocked
(Test-FileLocked confirms the binary is now writable). Caller's
fast-retry branch now gates on IsUnlocked; PIDs-cleared-but-still-locked
falls through to the delay-and-retry path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@cleak cleak merged commit 3b82415 into master May 1, 2026
1 check passed
@cleak cleak deleted the claude/install-respawn-fix branch May 1, 2026 06:21
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.

1 participant