Skip to content

Commit 0f439dc

Browse files
committed
fix(desktop): close a finished run's leftover pane before forgetting its record
1 parent 8be286d commit 0f439dc

2 files changed

Lines changed: 14 additions & 4 deletions

File tree

‎apps/desktop/src/main/terminal/index.ts‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -537,8 +537,12 @@ export class TerminalService {
537537
const pending = this.pendingRuns.get(terminalId)
538538
if (!pending) return
539539
for (const handle of pending) {
540-
// A finished run needs no record; an untracked one is never stopped, so is not kept either.
541-
if (isRunComplete(handle)) this.forgetRun(handle)
540+
// A finished run's pane may still be open (`remain-on-exit`): it is closed, while still the
541+
// run's, before the record goes. Without the shell's environment the record stays, and the
542+
// next sweep closes it. An untracked run is never stopped, so it is not kept either.
543+
if (isRunComplete(handle) && env) {
544+
void closeRunPane(handle, env).finally(() => this.forgetRun(handle))
545+
}
542546
if (env && handle.runId !== null && !isRunComplete(handle)) this.orphanedRuns.set(handle, env)
543547
this.releaseRun(handle)
544548
}

‎apps/desktop/src/main/terminal/service.test.ts‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -669,9 +669,10 @@ describe('agent commands in tmux', () => {
669669
}
670670
})
671671

672-
it('forgets a run that finished before its terminal closed', async () => {
672+
it('closes and then forgets a run that finished before its terminal closed', async () => {
673673
tmuxFake.on = true
674674
tmuxFake.statusPaths.clear()
675+
tmuxFake.open.clear()
675676
const scratch = mkdtempSync(join(tmpdir(), 'sim-ledger-'))
676677
const ledgerDir = join(scratch, 'terminal-runs')
677678
try {
@@ -684,9 +685,14 @@ describe('agent commands in tmux', () => {
684685
const [[, statusPath = ''] = []] = [...tmuxFake.statusPaths]
685686
writeFileSync(statusPath, '0')
686687

688+
const [pane = ''] = [...tmuxFake.statusPaths.keys()]
689+
// Its dead pane is still open, as with `remain-on-exit`.
690+
expect(tmuxFake.open.has(pane)).toBe(true)
691+
687692
terminal.closeTerminal(activeTerminalId as string)
688693

689-
expect(createRunLedger(ledgerDir).list()).toEqual([])
694+
await vi.waitFor(() => expect(createRunLedger(ledgerDir).list()).toEqual([]))
695+
expect(tmuxFake.open.has(pane)).toBe(false)
690696
} finally {
691697
tmuxFake.on = false
692698
rmSync(scratch, { recursive: true, force: true })

0 commit comments

Comments
 (0)