diff --git a/src/renderer/src/store/slices/codex-restart-notice-lifecycle.test.ts b/src/renderer/src/store/slices/codex-restart-notice-lifecycle.test.ts index 194a6696944..3d78a0353c1 100644 --- a/src/renderer/src/store/slices/codex-restart-notice-lifecycle.test.ts +++ b/src/renderer/src/store/slices/codex-restart-notice-lifecycle.test.ts @@ -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']) diff --git a/src/renderer/src/store/slices/terminals.ts b/src/renderer/src/store/slices/terminals.ts index 9b6e5866798..0d5d6930986 100644 --- a/src/renderer/src/store/slices/terminals.ts +++ b/src/renderer/src/store/slices/terminals.ts @@ -2856,9 +2856,15 @@ export const createTerminalSlice: StateCreator 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 {