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
Restored terminals wedge after an app restart: stale shell session ids are replayed against PTYs that no longer exist, and the resulting write/resize failures were only logged, leaving a dead terminal.
Changes
Stop persisting shell session ids; add a migration that clears saved ids
Recover missing interactive shells on write/resize and replay the triggering input
Emit a shell Exit event (code 130) on explicit destroy so the renderer learns about teardown
Add unit tests for recovery, session id persistence and teardown
Generated targeted recovery checks for interactive terminal write recovery, concurrent writes during one recovery, command terminal missing-session handling, unrelated error handling, and resize-triggered recovery.
Verified the recovery checks completed successfully for the TerminalManager changes.
Generated store migration checks for persisted terminal state; the local test environment could not resolve an existing renderer dependency used by the store tests.
Generated TerminalManager.trex.test.ts with 6 targeted tests for recovery edge cases and ran with pnpm vitest run; all 6 passed.
Demonstrated concurrent write recovery deduplication: 3 writes share one recovery, all 3 retry after recovery completes.
Confirmed recoverMissingSession calls handleExit instead of re-creating the session during the command terminal test.
Confirmed isMissingShellSessionError discriminates unrelated errors during the non-recovery error test.
Generated terminalStore.trex.test.ts with 9 migration edge case tests; blocked by pre-existing @posthog/electron-trpc/renderer resolution failure (same issue affects the existing terminalStore.test.ts).
Code review of ShellService.destroy() identified a potential duplicate exit event race: processTracking.kill(pid) may fire before disposables are cleaned up, risking two Exit events.
Read destroy() and onExit() paths to understand possible double-exit scenarios when kill triggers onExit synchronously.
Generated destroy-race.test.ts with 3 targeted tests; execution blocked by missing @posthog/git/queries in the sandbox (same issue blocks the existing service tests).
Saved the destroy race analysis to trex-artifacts/destroy-race-analysis.md.
Trex analysis summarizing the destroy race findings.
Ran code and verified through T-Rex
Comments Outside Diff (1)
apps/code/src/main/services/shell/service.ts, line 312-318 (link)
Avoid duplicate exits
processTracking.kill(pid) can trigger the PTY onExit callback before this method disposes the listener. In that case the onExit callback emits ShellEvent.Exit, then destroy() continues and emits another exit event with code 130. Renderer subscribers can receive two teardown events for one explicit destroy. Mark or remove the session before killing, or guard the exit listener so only one path emits.
Contains supporting evidence from the run (text/markdown; charset=utf-8).
Ran code and verified through T-Rex
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/code/src/main/services/shell/service.ts
Line: 312-318
Comment:
**Avoid duplicate exits**`processTracking.kill(pid)` can trigger the PTY `onExit` callback before this method disposes the listener. In that case the `onExit` callback emits `ShellEvent.Exit`, then `destroy()` continues and emits another exit event with code `130`. Renderer subscribers can receive two teardown events for one explicit destroy. Mark or remove the session before killing, or guard the exit listener so only one path emits.
<details><summary><strong>Artifacts</strong></summary><br />
**[Destroy race analysis](https://app.greptile.com/trex/artifacts/c75fabd7-b614-4141-8c27-20d7713980fe)**- Contains supporting evidence from the run (text/markdown; charset=utf-8).
**[Generated destroy race test](https://app.greptile.com/trex/artifacts/3d88f434-8a4d-4b8e-a61d-e6263daa4876)**- Contains supporting evidence from the run (text/typescript; charset=utf-8).
**[Destroy exitPromise analysis](https://app.greptile.com/trex/artifacts/c75fabd7-b614-4141-8c27-20d7713980fe)**- Contains supporting evidence from the run (text/markdown; charset=utf-8).
</details>
<sub><ahref="https://www.greptile.com/trex"><imgalt="T-Rex"src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg"height="14"align="absmiddle"></a> Ran code and verified through T-Rex</sub>
How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.
---### Issue 1 of 2
apps/code/src/main/services/shell/service.ts:312-318
**Avoid duplicate exits**`processTracking.kill(pid)` can trigger the PTY `onExit` callback before this method disposes the listener. In that case the `onExit` callback emits `ShellEvent.Exit`, then `destroy()` continues and emits another exit event with code `130`. Renderer subscribers can receive two teardown events for one explicit destroy. Mark or remove the session before killing, or guard the exit listener so only one path emits.
### Issue 2 of 2
apps/code/src/main/services/shell/service.ts:318-321
**Resolve destroyed sessions**
This explicit destroy path now emits an exit event, but it does not resolve the session's `exitPromise`. The only resolver is inside the PTY `onExit` callback, so if that callback does not fire before the listener is disposed, callers holding the `ShellSession` from `createSession()` can wait forever for a session that has already been torn down. Store the resolver on the session or route destroy through the same exit-completion path.
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.
Problem
Restored terminals wedge after an app restart: stale shell session ids are replayed against PTYs that no longer exist, and the resulting write/resize failures were only logged, leaving a dead terminal.
Changes
How did you test this?
Manually
Automatic notifications