fix(ssh): preserve git state on disconnect#2661
Conversation
Greptile SummaryThis PR fixes two crash scenarios on SSH disconnect by teaching the
Confidence Score: 5/5Safe to merge — all changes are narrowly scoped to SSH error paths and the PTY exit callback, with no changes to happy-path logic. The fix correctly exploits the LiveModel contract: returning err() from compute() keeps the cached value and routes the failure to onError instead of crashing. The git-service changes only affect previously-silent catch blocks that were already swallowing errors. The PTY change adds defensive error handling with no impact on normal exit flow. New tests cover the two background-refresh scenarios and the onExit handler case. No files require special attention.
|
| Filename | Overview |
|---|---|
| apps/emdash-desktop/src/main/core/ssh/transport-errors.ts | New shared utility that centralises recoverable SSH error detection via error codes and message regex; used by both git-service.ts and ssh-git.ts. |
| apps/emdash-desktop/src/main/core/runtime/legacy/ssh-git.ts | compute() functions changed to return Result<T,E> directly; recoverable SSH errors now return err() so LiveModel keeps last-good state instead of crashing via unhandled microtask rejection. |
| apps/emdash-desktop/src/main/core/git/legacy/git-service.ts | Recoverable SSH errors are re-thrown through previously-silent catch handlers (diff numstat, getHeadInfo, getRemotes) so they propagate up to the LiveModel boundary correctly. |
| apps/emdash-desktop/src/main/core/pty/local-pty.ts | onExit handler invocations are now wrapped in try/catch; errors are logged rather than allowed to propagate through the node-pty callback chain. |
| apps/emdash-desktop/src/main/core/runtime/legacy/ssh-git.test.ts | New test file; covers recoverable SSH error propagation through GitService, background refs refresh (LegacySshGitRepository), and background status refresh (LegacySshGitWorktree). |
| apps/emdash-desktop/src/main/core/pty/local-pty.test.ts | New test case verifies that onExit handler errors are caught and logged rather than thrown. |
Sequence Diagram
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant Timer as Interval Timer
participant Worktree as LegacySshGitWorktree
participant LM as LiveModel
participant CS as computeStatus()
participant GS as GitService
participant TE as isRecoverableSshTransportError
Timer->>Worktree: pollStatus() invalidate()
Worktree->>LM: scheduleBackground()
LM->>CS: compute()
CS->>GS: getFullStatus()
GS-->>CS: throws SSH error
CS->>TE: isRecoverableSshTransportError(error)
TE-->>CS: true
CS-->>LM: return err(error)
Note over LM: completed=false, dirty=true
LM->>LM: onError log.warn (no crash)
Note over LM: cached value preserved, no subscriber update emitted
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant Timer as Interval Timer
participant Worktree as LegacySshGitWorktree
participant LM as LiveModel
participant CS as computeStatus()
participant GS as GitService
participant TE as isRecoverableSshTransportError
Timer->>Worktree: pollStatus() invalidate()
Worktree->>LM: scheduleBackground()
LM->>CS: compute()
CS->>GS: getFullStatus()
GS-->>CS: throws SSH error
CS->>TE: isRecoverableSshTransportError(error)
TE-->>CS: true
CS-->>LM: return err(error)
Note over LM: completed=false, dirty=true
LM->>LM: onError log.warn (no crash)
Note over LM: cached value preserved, no subscriber update emitted
Reviews (2): Last reviewed commit: "refactor(ssh): share transport error rec..." | Re-trigger Greptile
…sh-git-refresh-z4a1n # Conflicts: # apps/emdash-desktop/src/main/core/pty/local-pty.test.ts # apps/emdash-desktop/src/main/core/pty/local-pty.ts
Description
this fixes two crashes i have had yesterday.
Checklist
messages and, when possible, the PR title