diff --git a/src/renderer/src/components/settings/DeveloperPermissionsPane.tsx b/src/renderer/src/components/settings/DeveloperPermissionsPane.tsx index abf4507cb59..324039e7437 100644 --- a/src/renderer/src/components/settings/DeveloperPermissionsPane.tsx +++ b/src/renderer/src/components/settings/DeveloperPermissionsPane.tsx @@ -105,7 +105,7 @@ const PERMISSIONS: PermissionDefinition[] = [ get description() { return translate( 'auto.components.settings.DeveloperPermissionsPane.7ca17b62c8', - 'Recommended when projects, worktrees, or symlinked files touch macOS-protected folders.' + "macOS names Orca when the agents it runs read other apps' data, because Orca is the responsible process for terminal commands. Granting this reduces those prompts. Terminals run in a separate helper, so grant Orca Helper too and restart Orca." ) }, actionLabel: 'Open Settings', diff --git a/src/renderer/src/components/sidebar/FullDiskAccessNudge.test.tsx b/src/renderer/src/components/sidebar/FullDiskAccessNudge.test.tsx deleted file mode 100644 index 4a08c24c4e4..00000000000 --- a/src/renderer/src/components/sidebar/FullDiskAccessNudge.test.tsx +++ /dev/null @@ -1,443 +0,0 @@ -// @vitest-environment happy-dom - -import * as React from 'react' -import { act } from 'react' -import { createRoot, type Root } from 'react-dom/client' -import { afterEach, describe, expect, it, vi } from 'vitest' -import { toast } from 'sonner' -import type { - DeveloperPermissionRequestResult, - DeveloperPermissionState, - DeveloperPermissionStatus -} from '../../../../shared/developer-permissions-types' -import { TooltipProvider } from '@/components/ui/tooltip' -import { - FullDiskAccessNudge, - resetFullDiskAccessProbeForTests, - shouldShowFullDiskAccessNudge -} from './FullDiskAccessNudge' - -// Why: without this React skips its "update not wrapped in act" warnings, so a -// state update escaping act() in these async probe paths would pass unnoticed. -globalThis.IS_REACT_ACT_ENVIRONMENT = true - -vi.mock('sonner', () => ({ - toast: { - error: vi.fn(), - message: vi.fn(), - success: vi.fn() - } -})) - -const MAC_UA = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)' -const WINDOWS_UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)' - -function setUserAgent(userAgent: string): void { - Object.defineProperty(window.navigator, 'userAgent', { - value: userAgent, - configurable: true - }) -} - -function installDeveloperPermissionsApi(args: { - getStatus: () => Promise - request?: () => Promise -}): { getStatus: ReturnType; request: ReturnType } { - const getStatus = vi.fn(args.getStatus) - const request = vi.fn( - args.request ?? - (async () => ({ - id: 'full-disk-access', - status: 'unknown', - openedSystemSettings: true - })) - ) - Object.assign(window, { api: { developerPermissions: { getStatus, request } } }) - return { getStatus, request } -} - -function fdaStatus(status: DeveloperPermissionStatus): DeveloperPermissionState[] { - return [{ id: 'full-disk-access', status }] -} - -const mountedRoots: Root[] = [] - -async function renderNudge(): Promise<{ container: HTMLDivElement; root: Root }> { - const container = document.createElement('div') - document.body.appendChild(container) - const root = createRoot(container) - mountedRoots.push(root) - await act(async () => { - root.render( - React.createElement(TooltipProvider, null, React.createElement(FullDiskAccessNudge)) - ) - }) - // Flush the one-shot getStatus() probe microtasks. - await act(async () => { - await Promise.resolve() - await Promise.resolve() - }) - return { container, root } -} - -afterEach(async () => { - // Why: clearing document.body leaves the roots mounted, so their window focus - // listener survives and re-probes during later tests. Unmount them instead. - const roots = mountedRoots.splice(0) - await act(async () => { - for (const root of roots) { - root.unmount() - } - }) - vi.restoreAllMocks() - document.body.innerHTML = '' - resetFullDiskAccessProbeForTests() - try { - window.localStorage.clear() - } catch { - // ignore - } -}) - -describe('shouldShowFullDiskAccessNudge', () => { - it('shows on macOS when Full Disk Access is not yet granted', () => { - expect( - shouldShowFullDiskAccessNudge({ isMac: true, dismissed: false, status: 'unknown' }) - ).toBe(true) - }) - - it('hides when granted, ready, unsupported, or unresolved', () => { - for (const status of ['granted', 'ready', 'unsupported', undefined] as const) { - expect(shouldShowFullDiskAccessNudge({ isMac: true, dismissed: false, status })).toBe(false) - } - }) - - it('hides off macOS and when dismissed', () => { - expect( - shouldShowFullDiskAccessNudge({ isMac: false, dismissed: false, status: 'unknown' }) - ).toBe(false) - expect(shouldShowFullDiskAccessNudge({ isMac: true, dismissed: true, status: 'unknown' })).toBe( - false - ) - }) -}) - -describe('FullDiskAccessNudge', () => { - it('renders the ambient card with honest copy when FDA is ungranted on macOS', async () => { - setUserAgent(MAC_UA) - installDeveloperPermissionsApi({ getStatus: async () => fdaStatus('unknown') }) - const { container } = await renderNudge() - expect(container.textContent).toContain('Reduce macOS permission prompts') - expect(container.textContent).toContain('Full Disk Access') - expect(container.textContent).toContain('Open System Settings') - // The grant covers this app, not the detached PTY daemon that owns terminals. - expect(container.textContent).toContain('may still prompt separately') - expect(container.textContent).not.toContain('stops asking') - // Agent sweeps trigger these prompts; macOS only names Orca as the responsible process. - expect(container.textContent).toContain('agents it runs') - }) - - it('stays hidden while the probe is unresolved (no first-paint flash)', async () => { - setUserAgent(MAC_UA) - // A never-resolving probe leaves status undefined. - installDeveloperPermissionsApi({ getStatus: () => new Promise(() => {}) }) - const { container } = await renderNudge() - expect(container.textContent).toBe('') - }) - - it('hides once Full Disk Access is granted', async () => { - setUserAgent(MAC_UA) - installDeveloperPermissionsApi({ getStatus: async () => fdaStatus('granted') }) - const { container } = await renderNudge() - expect(container.textContent).toBe('') - }) - - it('does not probe permissions off macOS', async () => { - setUserAgent(WINDOWS_UA) - const { getStatus } = installDeveloperPermissionsApi({ - getStatus: async () => fdaStatus('unknown') - }) - const { container } = await renderNudge() - expect(container.textContent).toBe('') - expect(getStatus).not.toHaveBeenCalled() - }) - - it('stays hidden on the web client whose status list is empty', async () => { - setUserAgent(MAC_UA) - installDeveloperPermissionsApi({ getStatus: async () => [] }) - const { container } = await renderNudge() - expect(container.textContent).toBe('') - }) - - it('opens System Settings via the Full Disk Access request', async () => { - setUserAgent(MAC_UA) - const { request } = installDeveloperPermissionsApi({ - getStatus: async () => fdaStatus('unknown') - }) - const { container } = await renderNudge() - const openButton = Array.from(container.querySelectorAll('button')).find((button) => - button.textContent?.includes('Open System Settings') - ) - expect(openButton).toBeTruthy() - await act(async () => { - openButton?.dispatchEvent(new MouseEvent('click', { bubbles: true })) - }) - expect(request).toHaveBeenCalledWith({ id: 'full-disk-access' }) - }) - - it('hides the card when the request reports Full Disk Access was granted', async () => { - setUserAgent(MAC_UA) - installDeveloperPermissionsApi({ - getStatus: async () => fdaStatus('unknown'), - request: async () => ({ - id: 'full-disk-access', - status: 'granted', - openedSystemSettings: false - }) - }) - const { container } = await renderNudge() - const openButton = Array.from(container.querySelectorAll('button')).find((button) => - button.textContent?.includes('Open System Settings') - ) - await act(async () => { - openButton?.dispatchEvent(new MouseEvent('click', { bubbles: true })) - }) - expect(container.textContent).toBe('') - expect(toast.success).toHaveBeenCalled() - }) - - it('re-enables the action and surfaces an error toast when the request rejects', async () => { - setUserAgent(MAC_UA) - installDeveloperPermissionsApi({ - getStatus: async () => fdaStatus('unknown'), - request: async () => { - throw new Error('ipc failure') - } - }) - const { container } = await renderNudge() - const openButton = Array.from(container.querySelectorAll('button')).find((button) => - button.textContent?.includes('Open System Settings') - ) - await act(async () => { - openButton?.dispatchEvent(new MouseEvent('click', { bubbles: true })) - }) - expect(toast.error).toHaveBeenCalled() - // Card stays visible and the button is usable again for a retry. - const retryButton = Array.from(container.querySelectorAll('button')).find((button) => - button.textContent?.includes('Open System Settings') - ) - expect(retryButton).toBeTruthy() - expect((retryButton as HTMLButtonElement).disabled).toBe(false) - }) - - it('probes protected data only once even under React StrictMode', async () => { - setUserAgent(MAC_UA) - const { getStatus } = installDeveloperPermissionsApi({ - getStatus: async () => fdaStatus('unknown') - }) - const container = document.createElement('div') - document.body.appendChild(container) - const root = createRoot(container) - // Why: this test builds its own root instead of renderNudge(), so it has to - // register for the afterEach unmount or it leaks a live component into later tests. - mountedRoots.push(root) - await act(async () => { - root.render( - React.createElement( - React.StrictMode, - null, - React.createElement(TooltipProvider, null, React.createElement(FullDiskAccessNudge)) - ) - ) - }) - await act(async () => { - await Promise.resolve() - await Promise.resolve() - }) - expect(getStatus).toHaveBeenCalledTimes(1) - expect(container.textContent).toContain('Reduce macOS permission prompts') - }) - - it('hides on return-focus once the grant takes effect after the CTA', async () => { - setUserAgent(MAC_UA) - let currentStatus: DeveloperPermissionStatus = 'unknown' - installDeveloperPermissionsApi({ - getStatus: async () => fdaStatus(currentStatus), - request: async () => ({ - id: 'full-disk-access', - status: 'unknown', - openedSystemSettings: true - }) - }) - const { container } = await renderNudge() - const openButton = Array.from(container.querySelectorAll('button')).find((button) => - button.textContent?.includes('Open System Settings') - ) - await act(async () => { - openButton?.dispatchEvent(new MouseEvent('click', { bubbles: true })) - }) - // Opening System Settings alone does not grant, so the card stays. - expect(container.textContent).toContain('Reduce macOS permission prompts') - // The user grants Full Disk Access in System Settings, then returns to Orca. - currentStatus = 'granted' - await act(async () => { - window.dispatchEvent(new Event('focus')) - await Promise.resolve() - await Promise.resolve() - }) - expect(container.textContent).toBe('') - }) - - it('ignores a slow focus refresh that resolves after a newer one saw the grant', async () => { - setUserAgent(MAC_UA) - const pendingResolvers: ((states: DeveloperPermissionState[]) => void)[] = [] - let deferGetStatus = false - installDeveloperPermissionsApi({ - getStatus: () => - deferGetStatus - ? new Promise((resolve) => { - pendingResolvers.push(resolve) - }) - : Promise.resolve(fdaStatus('unknown')), - request: async () => ({ - id: 'full-disk-access', - status: 'unknown', - openedSystemSettings: true - }) - }) - const { container } = await renderNudge() - const openButton = Array.from(container.querySelectorAll('button')).find((button) => - button.textContent?.includes('Open System Settings') - ) - await act(async () => { - openButton?.dispatchEvent(new MouseEvent('click', { bubbles: true })) - }) - // Rapid blur/focus while the first round-trip is still in flight. - deferGetStatus = true - await act(async () => { - window.dispatchEvent(new Event('focus')) - window.dispatchEvent(new Event('focus')) - }) - expect(pendingResolvers.length).toBe(2) - // The newer refresh observes the grant and hides the card. - await act(async () => { - pendingResolvers[1]?.(fdaStatus('granted')) - await Promise.resolve() - await Promise.resolve() - }) - expect(container.textContent).toBe('') - // The older, slower refresh still reports the pre-grant status; it must not win. - await act(async () => { - pendingResolvers[0]?.(fdaStatus('unknown')) - await Promise.resolve() - await Promise.resolve() - }) - expect(container.textContent).toBe('') - // The stale result must not poison the session cache a later mount reads either. - const remount = await renderNudge() - expect(remount.container.textContent).toBe('') - }) - - it('stops watching for the grant once the card is dismissed', async () => { - setUserAgent(MAC_UA) - const { getStatus } = installDeveloperPermissionsApi({ - getStatus: async () => fdaStatus('unknown'), - request: async () => ({ - id: 'full-disk-access', - status: 'unknown', - openedSystemSettings: true - }) - }) - const { container } = await renderNudge() - const openButton = Array.from(container.querySelectorAll('button')).find((button) => - button.textContent?.includes('Open System Settings') - ) - await act(async () => { - openButton?.dispatchEvent(new MouseEvent('click', { bubbles: true })) - }) - const dismissButton = container.querySelector( - 'button[aria-label="Dismiss Full Disk Access suggestion"]' - ) - await act(async () => { - dismissButton?.dispatchEvent(new MouseEvent('click', { bubbles: true })) - }) - expect(container.textContent).toBe('') - const callsAtDismiss = getStatus.mock.calls.length - // A later window focus must not re-probe protected data after dismissal. - await act(async () => { - window.dispatchEvent(new Event('focus')) - await Promise.resolve() - await Promise.resolve() - }) - expect(getStatus.mock.calls.length).toBe(callsAtDismiss) - }) - - it('records a granted request result in the session cache even if unmounted mid-request', async () => { - setUserAgent(MAC_UA) - let resolveRequest: (result: DeveloperPermissionRequestResult) => void = () => {} - const pendingRequest = new Promise((resolve) => { - resolveRequest = resolve - }) - installDeveloperPermissionsApi({ - getStatus: async () => fdaStatus('unknown'), - request: () => pendingRequest - }) - const { container, root } = await renderNudge() - const openButton = Array.from(container.querySelectorAll('button')).find((button) => - button.textContent?.includes('Open System Settings') - ) - await act(async () => { - openButton?.dispatchEvent(new MouseEvent('click', { bubbles: true })) - }) - await act(async () => { - root.unmount() - }) - await act(async () => { - resolveRequest({ id: 'full-disk-access', status: 'granted', openedSystemSettings: false }) - await Promise.resolve() - await Promise.resolve() - }) - // A fresh mount reads the updated session cache and stays hidden (granted). - installDeveloperPermissionsApi({ getStatus: async () => fdaStatus('unknown') }) - const remount = await renderNudge() - expect(remount.container.textContent).toBe('') - }) - - it('dismisses immediately, persists, and does not re-probe after remount', async () => { - setUserAgent(MAC_UA) - const first = installDeveloperPermissionsApi({ getStatus: async () => fdaStatus('unknown') }) - const rendered = await renderNudge() - const dismissButton = rendered.container.querySelector( - 'button[aria-label="Dismiss Full Disk Access suggestion"]' - ) - expect(dismissButton).toBeTruthy() - await act(async () => { - dismissButton?.dispatchEvent(new MouseEvent('click', { bubbles: true })) - }) - expect(rendered.container.textContent).toBe('') - expect(window.localStorage.getItem('orca.fullDiskAccessNudgeDismissed.v1')).toBe('1') - - // Remounting after a permanent dismissal must not render or re-probe. - const second = installDeveloperPermissionsApi({ getStatus: async () => fdaStatus('unknown') }) - const remounted = await renderNudge() - expect(remounted.container.textContent).toBe('') - expect(second.getStatus).not.toHaveBeenCalled() - expect(first.getStatus).toHaveBeenCalledTimes(1) - }) - - it('dismisses for the session even when persistence throws', async () => { - setUserAgent(MAC_UA) - installDeveloperPermissionsApi({ getStatus: async () => fdaStatus('unknown') }) - vi.spyOn(window.localStorage, 'setItem').mockImplementation(() => { - throw new Error('storage unavailable') - }) - const { container } = await renderNudge() - const dismissButton = container.querySelector( - 'button[aria-label="Dismiss Full Disk Access suggestion"]' - ) - await act(async () => { - dismissButton?.dispatchEvent(new MouseEvent('click', { bubbles: true })) - }) - expect(container.textContent).toBe('') - }) -}) diff --git a/src/renderer/src/components/sidebar/FullDiskAccessNudge.tsx b/src/renderer/src/components/sidebar/FullDiskAccessNudge.tsx deleted file mode 100644 index 8315e506f52..00000000000 --- a/src/renderer/src/components/sidebar/FullDiskAccessNudge.tsx +++ /dev/null @@ -1,287 +0,0 @@ -import { useCallback, useEffect, useState } from 'react' -import { ExternalLink, HardDrive, Loader2, X } from 'lucide-react' -import { toast } from 'sonner' -import type { - DeveloperPermissionId, - DeveloperPermissionState, - DeveloperPermissionStatus -} from '../../../../shared/developer-permissions-types' -import { Button } from '@/components/ui/button' -import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip' -import { useMountedRef } from '@/hooks/useMountedRef' -import { isMacUserAgent } from '../terminal-pane/pane-helpers' -import { - isFullDiskAccessReady, - isFullDiskAccessSetupVisible -} from '../feature-wall/FullDiskAccessSetupPrompt' -import { translate } from '@/i18n/i18n' - -const FULL_DISK_ACCESS_PERMISSION_ID: DeveloperPermissionId = 'full-disk-access' -// Why: camelCase segment + .v1 suffix matches sibling one-time sidebar keys -// (orca.workspaceBoardMovedHintSeen.v1); bump the version to re-surface later. -const DISMISS_KEY = 'orca.fullDiskAccessNudgeDismissed.v1' - -// Why: the FDA status probe reads Safari's TCC-protected data — the same "other -// apps' data" read this nudge exists to reduce — so it must run at most once per -// renderer session, shared across StrictMode replay and sidebar remounts (#9756). -let cachedFullDiskAccessStatus: DeveloperPermissionStatus | undefined -let fullDiskAccessProbed = false -let fullDiskAccessProbe: Promise | null = null -let fullDiskAccessRefreshSequence = 0 - -function getFullDiskAccessStatus( - states: readonly DeveloperPermissionState[] -): DeveloperPermissionStatus | undefined { - return states.find((state) => state.id === FULL_DISK_ACCESS_PERMISSION_ID)?.status -} - -function rememberFullDiskAccessStatus(status: DeveloperPermissionStatus | undefined): void { - cachedFullDiskAccessStatus = status - fullDiskAccessProbed = true -} - -function probeFullDiskAccessStatusOnce(): Promise { - if (fullDiskAccessProbed) { - return Promise.resolve(cachedFullDiskAccessStatus) - } - if (!fullDiskAccessProbe) { - fullDiskAccessProbe = window.api.developerPermissions - .getStatus() - .then((states) => { - rememberFullDiskAccessStatus(getFullDiskAccessStatus(states)) - return cachedFullDiskAccessStatus - }) - .catch(() => { - // Inconclusive probe: allow a later mount to retry rather than caching it. - fullDiskAccessProbe = null - return undefined - }) - } - return fullDiskAccessProbe -} - -// Why: a fresh, cache-bypassing probe used only on CTA return-focus so the card -// can hide the moment a Full Disk Access grant takes effect for this process. -function refreshFullDiskAccessStatus(): Promise { - // Why: rapid focus/blur puts several getStatus() round-trips in flight, and an - // earlier pre-grant result resolving last would un-hide the card and poison the - // session cache — same refresh-sequence guard as FullDiskAccessSetupPrompt. - const refreshId = ++fullDiskAccessRefreshSequence - return window.api.developerPermissions - .getStatus() - .then((states) => { - if (refreshId !== fullDiskAccessRefreshSequence) { - return cachedFullDiskAccessStatus - } - const next = getFullDiskAccessStatus(states) - rememberFullDiskAccessStatus(next) - return next - }) - .catch(() => cachedFullDiskAccessStatus) -} - -export function resetFullDiskAccessProbeForTests(): void { - cachedFullDiskAccessStatus = undefined - fullDiskAccessProbed = false - fullDiskAccessProbe = null -} - -function readDismissed(): boolean { - try { - return window.localStorage.getItem(DISMISS_KEY) === '1' - } catch { - return false - } -} - -function persistDismissed(): void { - try { - window.localStorage.setItem(DISMISS_KEY, '1') - } catch { - // Best-effort; if storage is unavailable the nudge returns next launch. - } -} - -export function shouldShowFullDiskAccessNudge(args: { - isMac: boolean - dismissed: boolean - status: DeveloperPermissionStatus | undefined -}): boolean { - return ( - args.isMac && - !args.dismissed && - isFullDiskAccessSetupVisible(args.status) && - !isFullDiskAccessReady(args.status) - ) -} - -/** - * Ambient, dismissable sidebar card that surfaces the durable Full Disk Access - * grant for the recurring macOS "access other apps' data" prompt (#9756) — a TCC - * identity-churn artifact, not a code bug we can otherwise fix. Off macOS renders nothing. - */ -export function FullDiskAccessNudge(): React.JSX.Element | null { - const mountedRef = useMountedRef() - const isMac = isMacUserAgent() - const [dismissed, setDismissed] = useState(() => readDismissed()) - const [status, setStatus] = useState( - () => cachedFullDiskAccessStatus - ) - const [requesting, setRequesting] = useState(false) - const [watchForGrant, setWatchForGrant] = useState(false) - - useEffect(() => { - // Why: probe only when the card could actually show — never off macOS or once - // dismissed. probeFullDiskAccessStatusOnce() reads protected data at most once. - if (!isMac || dismissed) { - return - } - void probeFullDiskAccessStatusOnce().then((next) => { - if (mountedRef.current) { - setStatus(next) - } - }) - }, [isMac, dismissed, mountedRef]) - - useEffect(() => { - // Why: only after the user clicked "Open System Settings" (explicit intent to - // grant), watch return-focus for the grant so the card hides once FDA is - // effective — one gated read per focus. Stops once granted or dismissed so a - // permanently dismissed card never keeps probing protected data. - if (!watchForGrant || dismissed || isFullDiskAccessReady(status)) { - return - } - const onFocus = (): void => { - void refreshFullDiskAccessStatus().then((next) => { - if (mountedRef.current) { - setStatus(next) - } - }) - } - window.addEventListener('focus', onFocus) - return () => window.removeEventListener('focus', onFocus) - }, [watchForGrant, dismissed, status, mountedRef]) - - const handleDismiss = useCallback((): void => { - persistDismissed() - setDismissed(true) - }, []) - - const handleOpenSystemSettings = useCallback(async (): Promise => { - setRequesting(true) - try { - const result = await window.api.developerPermissions.request({ - id: FULL_DISK_ACCESS_PERMISSION_ID - }) - // Why: the request re-probes in main (authoritative); record it in the - // session cache before the mount check so an unmount mid-request can't - // strand a later remount on a stale status. - rememberFullDiskAccessStatus(result.status) - if (!mountedRef.current) { - return - } - // Why: feed it back so a granted result hides the card, and watch return- - // focus for the eventual grant since it opens Settings first. - setStatus(result.status) - setWatchForGrant(true) - if (result.status === 'granted') { - toast.success( - translate( - 'auto.components.sidebar.FullDiskAccessNudge.granted', - 'Full Disk Access granted' - ) - ) - } else if (result.openedSystemSettings) { - toast.message( - translate( - 'auto.components.sidebar.FullDiskAccessNudge.openedPrivacy', - 'Opened macOS Privacy & Security' - ) - ) - } - } catch { - if (mountedRef.current) { - toast.error( - translate( - 'auto.components.sidebar.FullDiskAccessNudge.requestError', - 'Could not open System Settings' - ) - ) - } - } finally { - if (mountedRef.current) { - setRequesting(false) - } - } - }, [mountedRef]) - - // Why: hidden while the probe is unresolved (no first-paint flash) and once FDA - // is already granted; off macOS or after a permanent dismissal it never shows. - if (!shouldShowFullDiskAccessNudge({ isMac, dismissed, status })) { - return null - } - - return ( -
-
-
-
- -

- {translate( - 'auto.components.sidebar.FullDiskAccessNudge.title', - 'Reduce macOS permission prompts' - )} -

-
- - - - - - {translate('auto.components.sidebar.FullDiskAccessNudge.dismiss', 'Dismiss')} - - -
-

- {translate( - 'auto.components.sidebar.FullDiskAccessNudge.body', - "These prompts come from Orca and the agents it runs reading other apps' data. Full Disk Access reduces them; terminal sessions may still prompt separately." - )} -

- -
-
- ) -} diff --git a/src/renderer/src/components/sidebar/index.tsx b/src/renderer/src/components/sidebar/index.tsx index 504e284f70d..b224e594277 100644 --- a/src/renderer/src/components/sidebar/index.tsx +++ b/src/renderer/src/components/sidebar/index.tsx @@ -5,7 +5,6 @@ import { useSidebarResize } from '@/hooks/useSidebarResize' import SidebarHeader from './SidebarHeader' import SidebarNav from './SidebarNav' import SetupScriptPromptCard from './SetupScriptPromptCard' -import { FullDiskAccessNudge } from './FullDiskAccessNudge' import WorktreeList from './WorktreeList' import SidebarToolbar from './SidebarToolbar' import WorkspaceKanbanDrawer from './WorkspaceKanbanDrawer' @@ -157,8 +156,6 @@ function Sidebar({ - - {/* Fixed bottom toolbar */}