Skip to content

Conversation

@AndyMik90
Copy link
Owner

@AndyMik90 AndyMik90 commented Jan 16, 2026

Summary

Fixes a race condition on Windows where terminal recreation fails when switching worktrees.

  • On Windows, PTY process termination is asynchronous and takes longer than macOS/Linux
  • When switching worktrees, the terminal would close but not reopen because the new PTY creation conflicted with the still-shutting-down old PTY
  • This fix adds promise-based wait for PTY exit on Windows only

Changes

  • Add pendingExitPromises map to track terminals being destroyed
  • Add waitForPtyExit() function with platform-specific timeouts (2000ms Windows, 500ms Unix)
  • Modify killPty() to optionally wait for exit
  • Update destroyTerminal() to wait for PTY exit on Windows only
  • macOS/Linux behavior is unchanged

Test plan

  • Build passes
  • ESLint passes on modified files
  • Windows: Test worktree switching - terminal should reopen correctly
  • macOS/Linux: Verify no regression - worktree switching still works
  • Edge cases: Rapid terminal create/destroy cycles

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Option to wait for a terminal process to fully exit during kill/destroy operations.
    • Improved shell selection on Windows and a more robust spawn path with environment sanitization.
  • Bug Fixes

    • Prevented race conditions during terminal destruction and exit handling for more reliable shutdowns.
    • Ensured pending exit handling is cleaned up to avoid stale state; bulk shutdown retains immediate-kill behavior.

✏️ Tip: You can customize this high-level summary in your review settings.

On Windows, PTY process termination is asynchronous and takes longer than
macOS/Linux. When switching worktrees, the terminal would close but not
reopen because the new PTY creation conflicted with the still-shutting-down
old PTY.

This fix adds promise-based wait for PTY exit on Windows:
- Add pendingExitPromises map to track terminals being destroyed
- Add waitForPtyExit() function with platform-specific timeouts
- Modify killPty() to optionally wait for exit
- Update destroyTerminal() to wait for PTY exit on Windows only

The timeout fallback (2000ms Windows, 500ms Unix) ensures no hangs if the
exit event never fires.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@CLAassistant
Copy link

CLAassistant commented Jan 16, 2026

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
1 out of 2 committers have signed the CLA.

✅ AndyMik90
❌ Test User


Test User seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

@github-actions github-actions bot added area/frontend This is frontend only bug Something isn't working size/S Small (10-99 lines) labels Jan 16, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 16, 2026

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

📝 Walkthrough

Walkthrough

Added guarded PTY exit tracking and wait semantics (platform-tuned timeouts), tightened terminal destruction to avoid races, extended killPty to optionally await PTY exit, introduced Windows shell resolution and a spawnPtyProcess export, and updated PTY handlers to resolve pending exit promises before cleanup.

Changes

Cohort / File(s) Summary
PTY Manager Core
apps/frontend/src/main/terminal/pty-manager.ts
Added pendingExitPromises map and waitForPtyExit(terminalId, timeoutMs?). Modified killPty overloads to support waitForExit: true (returns Promise<void>). Added getWindowsShell(...), spawnPtyProcess(...) (exported), ensured exit handlers resolve pending promises before cleanup, and hardened terminal deletion checks.
Terminal Lifecycle Integration
apps/frontend/src/main/terminal/terminal-lifecycle.ts
Import isWindows. Adjusted destroyTerminal() to delete terminal from map before killing PTY and to await PtyManager.killPty(..., true) on Windows (no await on non-Windows). Documented that shutdown does not await PTY exit.

Sequence Diagram(s)

sequenceDiagram
participant Lifecycle as TerminalLifecycle
participant Manager as PtyManager
participant OS as Platform/OS
participant Pty as PTYProcess

Lifecycle->>Manager: destroyTerminal(terminal)
note right of Manager: map delete before kill to avoid race
Lifecycle->>Manager: killPty(terminal, waitForExit=true)
Manager->>Pty: kill()
alt kill throws
    Manager->>Manager: cleanup pending exit state
    Manager-->>Lifecycle: resolve/return
else kill succeeds
    Manager->>Manager: waitForPtyExit(terminalId, timeout)
    par PTY exit path
        Pty-->>Manager: onExit
        Manager->>Manager: resolve pending exit promise
        Manager-->>Lifecycle: exit awaited resolved
    and timeout path
        Manager-->>Lifecycle: timeout resolves
    end
end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • fix: windows #1056 — touches the same PTY logic and Windows shell selection helpers; likely closely related.

Suggested labels

🔄 Checking, size/M, Missing AC Approval

Suggested reviewers

  • MikeeBuilds
  • AlexMadera

Poem

🐰 I hop and sniff the PTY track,

I guard exits, watch timeouts slack.
On Windows paths I choose a shell,
I tidy maps and ring the bell—
Clean shutdowns make this bunny swell. 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely describes the main fix: adding Windows-specific PTY exit waiting during terminal recreation to resolve a race condition.
Docstring Coverage ✅ Passed Docstring coverage is 85.71% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing touches
  • 📝 Generate docstrings


📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6777570 and 1067842.

📒 Files selected for processing (2)
  • apps/frontend/src/main/terminal/pty-manager.ts
  • apps/frontend/src/main/terminal/terminal-lifecycle.ts
🧰 Additional context used
📓 Path-based instructions (5)
apps/frontend/src/**/*.{tsx,ts}

📄 CodeRabbit inference engine (CLAUDE.md)

apps/frontend/src/**/*.{tsx,ts}: All user-facing text in the frontend MUST use i18n translation keys from react-i18next, not hardcoded strings
Use translation key format namespace:section.key (e.g., navigation:items.githubPRs) when referencing translations in code
For error messages with dynamic content, use i18n interpolation with syntax like t('errors:task.parseError', { error: errorMessage })

Files:

  • apps/frontend/src/main/terminal/terminal-lifecycle.ts
  • apps/frontend/src/main/terminal/pty-manager.ts
**/*.{ts,tsx,js,py}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,js,py}: Do not check process.platform directly in code - always import platform detection functions from the platform abstraction module
Never hardcode platform-specific paths like C:\Program Files\, /opt/homebrew/bin/, or /usr/local/bin/ directly in code

Files:

  • apps/frontend/src/main/terminal/terminal-lifecycle.ts
  • apps/frontend/src/main/terminal/pty-manager.ts
apps/frontend/src/main/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use platform abstraction functions like isWindows(), isMacOS(), isLinux(), getPathDelimiter(), getExecutableExtension(), findExecutable(), joinPaths() from the platform module instead of hardcoding paths or platform checks

Files:

  • apps/frontend/src/main/terminal/terminal-lifecycle.ts
  • apps/frontend/src/main/terminal/pty-manager.ts
apps/frontend/**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (CLAUDE.md)

Frontend code must be built with Electron, React, and TypeScript

Files:

  • apps/frontend/src/main/terminal/terminal-lifecycle.ts
  • apps/frontend/src/main/terminal/pty-manager.ts
apps/frontend/**/*.{ts,tsx}

⚙️ CodeRabbit configuration file

apps/frontend/**/*.{ts,tsx}: Review React patterns and TypeScript type safety.
Check for proper state management and component composition.

Files:

  • apps/frontend/src/main/terminal/terminal-lifecycle.ts
  • apps/frontend/src/main/terminal/pty-manager.ts
🧠 Learnings (1)
📚 Learning: 2026-01-16T09:10:31.701Z
Learnt from: CR
Repo: AndyMik90/Auto-Claude PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-16T09:10:31.701Z
Learning: Applies to apps/frontend/src/main/**/*.{ts,tsx} : Use platform abstraction functions like `isWindows()`, `isMacOS()`, `isLinux()`, `getPathDelimiter()`, `getExecutableExtension()`, `findExecutable()`, `joinPaths()` from the platform module instead of hardcoding paths or platform checks

Applied to files:

  • apps/frontend/src/main/terminal/terminal-lifecycle.ts
🧬 Code graph analysis (1)
apps/frontend/src/main/terminal/pty-manager.ts (3)
apps/frontend/src/main/platform/index.ts (1)
  • isWindows (40-42)
apps/frontend/scripts/download-python.cjs (1)
  • isWindows (358-358)
apps/frontend/src/main/terminal/types.ts (1)
  • TerminalProcess (8-24)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Seer Code Review
  • GitHub Check: test-python (3.13, windows-latest)
  • GitHub Check: CodeQL (python)
  • GitHub Check: test-frontend (ubuntu-latest)
  • GitHub Check: Cursor Bugbot
🔇 Additional comments (5)
apps/frontend/src/main/terminal/terminal-lifecycle.ts (3)

18-18: Good platform abstraction usage.
Keeps platform checks centralized and avoids direct process.platform usage. As per coding guidelines, platform detection should go through the abstraction helpers.


232-262: Windows PTY wait + pre-delete ordering looks right.
Deleting the terminal before kill and awaiting PTY exit on Windows should prevent the onExit race when IDs are reused.


292-295: Shutdown path remains intentionally non-blocking.
The note clearly documents why PTY exit isn’t awaited during shutdown.

apps/frontend/src/main/terminal/pty-manager.ts (2)

155-176: Exit handling order and object-identity guard look solid.
Resolving pending exits before cleanup and verifying the terminal object prevents accidental deletion of newly created terminals.


281-305: killPty overloads and wait-for-exit path are clear and safe.
The overloads communicate intent well, and the cleanup on kill errors is a good safeguard.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @AndyMik90, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request resolves a critical race condition on Windows that caused terminal recreation to fail, particularly when switching worktrees. The core issue stemmed from the asynchronous nature of PTY process termination on Windows. By introducing a promise-based waiting mechanism, the system now ensures that a PTY has fully exited before attempting to create a new one, thereby stabilizing terminal behavior in scenarios requiring rapid terminal lifecycle management.

Highlights

  • Windows PTY Exit Handling: Introduced a new mechanism to explicitly wait for PTY (pseudo-terminal) process termination on Windows, addressing a race condition where terminal recreation could fail due to asynchronous process shutdown.
  • Platform-Specific Timeouts: Implemented platform-specific timeouts for PTY exit, with a longer duration (2000ms) for Windows to accommodate its slower process termination, compared to Unix-like systems (500ms).
  • Modified Terminal Lifecycle Functions: Updated killPty to optionally return a promise that resolves upon PTY exit and modified destroyTerminal to conditionally await this promise on Windows, ensuring proper cleanup before new terminal creation.
  • Race Condition Mitigation: Adjusted the order of terminal cleanup in destroyTerminal and ptyProcess.onExit handlers to prevent potential race conditions, such as attempting to delete an already removed terminal from the map.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request effectively addresses a race condition on Windows during terminal recreation by introducing a mechanism to wait for the PTY process to exit. The changes are well-structured, with new functions like waitForPtyExit and modifications to killPty and destroyTerminal being clear and platform-specific as intended. The use of a promise-based approach with timeouts is a solid solution. My main feedback is a suggestion to improve the robustness of waitForPtyExit to prevent potential resource leaks in case it's called multiple times for the same terminal, making the implementation more resilient for future changes.

Comment on lines +40 to +54
export function waitForPtyExit(terminalId: string, timeoutMs?: number): Promise<void> {
const timeout = timeoutMs ?? (isWindows() ? PTY_EXIT_TIMEOUT_WINDOWS : PTY_EXIT_TIMEOUT_UNIX);

return new Promise<void>((resolve) => {
// Set up timeout fallback
const timeoutId = setTimeout(() => {
debugLog('[PtyManager] PTY exit timeout for terminal:', terminalId);
pendingExitPromises.delete(terminalId);
resolve();
}, timeout);

// Store the promise resolver
pendingExitPromises.set(terminalId, { resolve, timeoutId });
});
}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

If this function is called multiple times for the same terminalId before the PTY exits, it could lead to a resource leak. Each call creates a new promise and a new timeout, but only the latest one is tracked, orphaning previous promises and their timeouts. To make this more robust, it's good practice to clean up any existing waiters for the same terminal ID before creating a new one.

export function waitForPtyExit(terminalId: string, timeoutMs?: number): Promise<void> {
  const timeout = timeoutMs ?? (isWindows() ? PTY_EXIT_TIMEOUT_WINDOWS : PTY_EXIT_TIMEOUT_UNIX);

  // If we are already waiting for this terminal, clear the old timeout to prevent leaks.
  const existing = pendingExitPromises.get(terminalId);
  if (existing) {
    debugLog('[PtyManager] PTY exit already being awaited, overwriting for terminal:', terminalId);
    clearTimeout(existing.timeoutId);
  }

  return new Promise<void>((resolve) => {
    // Set up timeout fallback
    const timeoutId = setTimeout(() => {
      debugLog('[PtyManager] PTY exit timeout for terminal:', terminalId);
      pendingExitPromises.delete(terminalId);
      resolve();
    }, timeout);

    // Store the promise resolver
    pendingExitPromises.set(terminalId, { resolve, timeoutId });
  });
}

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

@AndyMik90 AndyMik90 self-assigned this Jan 16, 2026
Copy link
Owner Author

@AndyMik90 AndyMik90 left a comment

Choose a reason for hiding this comment

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

🤖 Auto Claude PR Review

Merge Verdict: 🟠 NEEDS REVISION

🟠 Needs revision - 2 issue(s) require attention.

2 issue(s) must be addressed (0 required, 2 recommended), 2 suggestions

Risk Assessment

Factor Level Notes
Complexity Low Based on lines changed
Security Impact None Based on security findings
Scope Coherence Good Based on structural review

Findings Summary

  • Medium: 2 issue(s)
  • Low: 2 issue(s)

Generated by Auto Claude PR Review

Findings (4 selected of 4 total)

🟡 [0cd9931b91f7] [MEDIUM] Race condition: onExit handler may delete newly created terminal with same ID

📁 apps/frontend/src/main/terminal/pty-manager.ts:171

On Windows, destroyTerminal() awaits PTY exit. During this await, if createTerminal() is called with the same ID, a new terminal is added to the map. When the old PTY's onExit fires, it checks terminals.has(id) which returns true for the NEW terminal, incorrectly deleting it. The race window exists because JavaScript yields to the event loop during await.

Suggested fix:

Store a reference to the specific terminal object (not just ID) in the onExit closure, then compare before deleting: `if (terminals.get(id) === terminal) { terminals.delete(id); }`

🟡 [9484a6ff608d] [MEDIUM] Union return type 'Promise | void' is error-prone for callers

📁 apps/frontend/src/main/terminal/pty-manager.ts:284

The killPty function returns Promise | void based on the waitForExit parameter. This conditional return type is error-prone because callers must remember to await when waitForExit=true. TypeScript does not enforce awaiting promises, making this easy to misuse. A forgotten await would cause the promise to be silently dropped.

Suggested fix:

Use function overloads for type-safe return types:
```typescript
export function killPty(terminal: TerminalProcess, waitForExit: true): Promise<void>;
export function killPty(terminal: TerminalProcess, waitForExit?: false): void;
export function killPty(terminal: TerminalProcess, waitForExit?: boolean): Promise<void> | void { ... }

#### 🔵 [a5a464bd3c5e] [LOW] No error cleanup if terminal.pty.kill() throws with waitForExit=true
📁 `apps/frontend/src/main/terminal/pty-manager.ts:286`

When waitForExit=true, the code creates the exit promise first, then calls kill(). If kill() throws, the promise from waitForPtyExit() will never resolve (only times out after 2000ms), and the pendingExitPromises map entry is left orphaned until timeout. The caller's try/catch handles the exception, but the delayed timeout could cause subtle timing issues.

**Suggested fix:**

Wrap kill() in try/catch and clean up the pending promise on error:

try {
  terminal.pty.kill();
} catch (error) {
  const pending = pendingExitPromises.get(terminal.id);
  if (pending) {
    clearTimeout(pending.timeoutId);
    pendingExitPromises.delete(terminal.id);
    pending.resolve();
  }
  throw error;
}

#### 🔵 [6048dfc70b60] [LOW] destroyAllTerminals does not wait for PTY exit on Windows (inconsistent)
📁 `apps/frontend/src/main/terminal/terminal-lifecycle.ts:292`

The destroyAllTerminals() function calls killPty(terminal) without waitForExit=true even on Windows, unlike the single-terminal destroyTerminal() which correctly waits. This inconsistency could cause the same race condition if terminals are recreated after destroyAllTerminals(). However, this function is only called during app shutdown where recreation is unlikely.

**Suggested fix:**

Add a comment explaining the intentional difference, or apply the same pattern for consistency:

// Note: No need to wait for exit here since this is only called during
// app shutdown when no terminals will be recreated.

---
*This review was generated by Auto Claude.*

Test User and others added 2 commits January 16, 2026 15:13
- Fix race condition: compare terminal object reference (not just ID) in
  onExit handler to prevent deleting newly created terminals with same ID
- Add function overloads for killPty() for type-safe return types
- Add error cleanup: wrap kill() in try/catch to clean up pending promise
  if kill() throws
- Add comment explaining why destroyAllTerminals() doesn't wait for PTY exit

Co-Authored-By: Claude Opus 4.5 <[email protected]>
}, timeout);

// Store the promise resolver
pendingExitPromises.set(terminalId, { resolve, timeoutId });

This comment was marked as outdated.

@AndyMik90 AndyMik90 merged commit d5d5697 into develop Jan 16, 2026
17 of 18 checks passed
@AndyMik90 AndyMik90 deleted the terminal/windows-terminals branch January 16, 2026 14:28
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

}, timeout);

// Store the promise resolver
pendingExitPromises.set(terminalId, { resolve, timeoutId });
Copy link

Choose a reason for hiding this comment

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

Concurrent destroy with same ID causes wrong promise resolution

Medium Severity

The pendingExitPromises map is keyed only by terminal ID. If terminal A is being destroyed and a new terminal B is created with the same ID during the await, then B is also destroyed, B's promise resolver overwrites A's. When A's PTY exits, it resolves B's promise instead of A's - causing destroyTerminal(B) to return before B's PTY has actually exited. This recreates the race condition the PR is trying to fix. The terminals map handles this with an object identity check, but pendingExitPromises lacks equivalent protection.

Additional Locations (1)

Fix in Cursor Fix in Web

StillKnotKnown pushed a commit to StillKnotKnown/Auto-Claude that referenced this pull request Jan 16, 2026
AndyMik90#1184)

* fix(terminal): wait for PTY exit on Windows before recreating terminal

On Windows, PTY process termination is asynchronous and takes longer than
macOS/Linux. When switching worktrees, the terminal would close but not
reopen because the new PTY creation conflicted with the still-shutting-down
old PTY.

This fix adds promise-based wait for PTY exit on Windows:
- Add pendingExitPromises map to track terminals being destroyed
- Add waitForPtyExit() function with platform-specific timeouts
- Modify killPty() to optionally wait for exit
- Update destroyTerminal() to wait for PTY exit on Windows only

The timeout fallback (2000ms Windows, 500ms Unix) ensures no hangs if the
exit event never fires.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): address PR review feedback

- Fix race condition: compare terminal object reference (not just ID) in
  onExit handler to prevent deleting newly created terminals with same ID
- Add function overloads for killPty() for type-safe return types
- Add error cleanup: wrap kill() in try/catch to clean up pending promise
  if kill() throws
- Add comment explaining why destroyAllTerminals() doesn't wait for PTY exit

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Test User <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>
StillKnotKnown pushed a commit to StillKnotKnown/Auto-Claude that referenced this pull request Jan 16, 2026
AndyMik90#1184)

* fix(terminal): wait for PTY exit on Windows before recreating terminal

On Windows, PTY process termination is asynchronous and takes longer than
macOS/Linux. When switching worktrees, the terminal would close but not
reopen because the new PTY creation conflicted with the still-shutting-down
old PTY.

This fix adds promise-based wait for PTY exit on Windows:
- Add pendingExitPromises map to track terminals being destroyed
- Add waitForPtyExit() function with platform-specific timeouts
- Modify killPty() to optionally wait for exit
- Update destroyTerminal() to wait for PTY exit on Windows only

The timeout fallback (2000ms Windows, 500ms Unix) ensures no hangs if the
exit event never fires.

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(terminal): address PR review feedback

- Fix race condition: compare terminal object reference (not just ID) in
  onExit handler to prevent deleting newly created terminals with same ID
- Add function overloads for killPty() for type-safe return types
- Add error cleanup: wrap kill() in try/catch to clean up pending promise
  if kill() throws
- Add comment explaining why destroyAllTerminals() doesn't wait for PTY exit

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Test User <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/frontend This is frontend only bug Something isn't working size/S Small (10-99 lines)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants