fix(codex): keep a dismissal answered when the selection has not moved

Adding a Codex account and reauthenticating the active one both re-mark
every live pane with the active account unchanged. Once a dismissed
notice survives as launch-account memory, that re-mark rebuilt the record
without the marker, resurrecting a prompt the user had answered and
re-blocking the pane's keyboard. Carry `dismissed` forward when the
target account is the one the dismissal already answered.
This commit is contained in:
Brennan Benson
2026-07-26 17:23:38 -07:00
parent 2e9f584a93
commit e576362f58
2 changed files with 25 additions and 3 deletions
@@ -57,6 +57,22 @@ describe('codex restart notice lifecycle', () => {
})
})
it('leaves a dismissal answered when the active account is re-marked unchanged', () => {
switchAccount('pty-1', A, B)
useAppStore.getState().dismissCodexRestartNotices(['pty-1'])
// Why: adding an account and reauthenticating the active one both re-mark
// live panes with the selection unchanged. Nothing about the pane moved, so
// resurrecting the prompt would also re-block a keyboard the user freed.
switchAccount('pty-1', B, B)
expect(useAppStore.getState().codexRestartNoticeByPtyId['pty-1']).toEqual({
previousAccountLabel: A,
nextAccountLabel: B,
dismissed: true
})
})
it('drops a queued restart when the user dismisses the same pane', () => {
switchAccount('pty-1', A, B)
useAppStore.getState().queueCodexPaneRestarts(['pty-1'])
+9 -3
View File
@@ -2856,9 +2856,15 @@ export const createTerminalSlice: StateCreator<AppState, [], [], TerminalSlice>
nextAccountLabel: notice.nextAccountLabel,
// Why: a queued restart relaunches under whatever account is selected
// when it runs, so a later switch does not reopen an answered prompt.
// A dismissal is deliberately not carried over — it answered "keep the
// old account instead of B", which says nothing about a later C.
...(existing?.restartRequested ? { restartRequested: true as const } : {})
...(existing?.restartRequested ? { restartRequested: true as const } : {}),
// Why: a dismissal answered one question — "keep the launch account
// instead of this one". Only a genuinely different target re-asks it,
// so a later C reopens the prompt while adding an account or
// reauthenticating the active one (both re-mark live panes with the
// selection unchanged) must not resurrect it and re-mute the pane.
...(existing?.dismissed && existing.nextAccountLabel === notice.nextAccountLabel
? { dismissed: true as const }
: {})
}
}
return {