From 89f66a1c25d12b8456c12c4274f4fd5dd32ee9aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E5=91=98=E9=98=BF=E6=B1=9F=28Relakkes?= =?UTF-8?q?=29?= Date: Sun, 24 May 2026 15:48:39 +0800 Subject: [PATCH] fix: align bypass permission path with active tab The bypass-permission confirmation was resolving its displayed workspace from the session list's activeSessionId, while the chat composer sends runtime updates to the currently active tab. When those two UI states diverged after tab restores or project switches, the confirmation could show a parent or stale workspace path even though the chat was operating in another project. Constraint: Desktop tabs and session-list selection can diverge during restore and multi-tab workflows. Rejected: Thread workDir through every chat-composer call site | the selector already has the active tab context needed for uncontrolled usage. Confidence: high Scope-risk: narrow Directive: Keep uncontrolled permission-mode actions keyed to the same active tab used for set_permission_mode. Tested: cd desktop && bun run test -- src/components/controls/PermissionModeSelector.test.tsx --run Tested: cd desktop && bun run lint Not-tested: Live Windows desktop packaging smoke. --- .../controls/PermissionModeSelector.test.tsx | 44 ++++++++++++++++++- .../controls/PermissionModeSelector.tsx | 5 ++- 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/desktop/src/components/controls/PermissionModeSelector.test.tsx b/desktop/src/components/controls/PermissionModeSelector.test.tsx index 0ce66cf0..03dc1efb 100644 --- a/desktop/src/components/controls/PermissionModeSelector.test.tsx +++ b/desktop/src/components/controls/PermissionModeSelector.test.tsx @@ -47,7 +47,7 @@ import { useSettingsStore } from '../../stores/settingsStore' import { useSessionStore } from '../../stores/sessionStore' import { useTabStore } from '../../stores/tabStore' -describe('PermissionModeSelector mobile access', () => { +describe('PermissionModeSelector', () => { beforeEach(() => { viewportMocks.isMobile = false useSettingsStore.setState({ permissionMode: 'default' }) @@ -73,4 +73,46 @@ describe('PermissionModeSelector mobile access', () => { expect(screen.getByRole('button', { name: 'Close' })).toBeInTheDocument() expect(screen.getByRole('menuitem', { name: /Auto accept edits/ })).toBeInTheDocument() }) + + it('uses the active tab workspace when showing the bypass confirmation path', () => { + useSessionStore.setState({ + activeSessionId: 'previous-session', + sessions: [ + { + id: 'previous-session', + title: 'Previous', + createdAt: '2026-05-24T00:00:00.000Z', + modifiedAt: '2026-05-24T00:00:00.000Z', + messageCount: 1, + projectPath: 'C:\\Users\\LinTan', + projectRoot: 'C:\\Users\\LinTan', + workDir: 'C:\\Users\\LinTan', + workDirExists: true, + }, + { + id: 'current-tab', + title: 'Current', + createdAt: '2026-05-24T00:00:00.000Z', + modifiedAt: '2026-05-24T00:00:00.000Z', + messageCount: 1, + projectPath: 'C:\\Users\\LinTan\\MyScript\\test5', + projectRoot: 'C:\\Users\\LinTan\\MyScript\\test5', + workDir: 'C:\\Users\\LinTan\\MyScript\\test5', + workDirExists: true, + }, + ], + }) + useTabStore.setState({ + activeTabId: 'current-tab', + tabs: [{ sessionId: 'current-tab', title: 'Current', type: 'session', status: 'idle' }], + }) + + render() + + fireEvent.click(screen.getByRole('button', { name: 'Ask permissions' })) + fireEvent.click(screen.getByRole('menuitem', { name: /Bypass permissions/ })) + + expect(screen.getByText('C:\\Users\\LinTan\\MyScript\\test5')).toBeInTheDocument() + expect(screen.queryByText('C:\\Users\\LinTan')).not.toBeInTheDocument() + }) }) diff --git a/desktop/src/components/controls/PermissionModeSelector.tsx b/desktop/src/components/controls/PermissionModeSelector.tsx index 1fb2e083..814a1d5e 100644 --- a/desktop/src/components/controls/PermissionModeSelector.tsx +++ b/desktop/src/components/controls/PermissionModeSelector.tsx @@ -35,7 +35,6 @@ export function PermissionModeSelector({ workDir: workDirProp, compact = false, const setSessionPermissionMode = useChatStore((s) => s.setSessionPermissionMode) const activeTabId = useTabStore((s) => s.activeTabId) const sessions = useSessionStore((s) => s.sessions) - const activeSessionId = useSessionStore((s) => s.activeSessionId) const [open, setOpen] = useState(false) const [confirmDialog, setConfirmDialog] = useState(false) const ref = useRef(null) @@ -87,7 +86,9 @@ export function PermissionModeSelector({ workDir: workDirProp, compact = false, dontAsk: t('permMode.label.dontAsk'), } - const activeSession = sessions.find((s) => s.id === activeSessionId) + const activeSession = activeTabId + ? sessions.find((s) => s.id === activeTabId) + : null const workDir = workDirProp || activeSession?.workDir || '~' const compactButtonClass = compact ? isMobile