diff --git a/__tests__/e2e/__snapshots__/happy-path.e2e.ts.snap b/__tests__/e2e/__snapshots__/happy-path.e2e.ts.snap index cbc78e9..413222a 100644 --- a/__tests__/e2e/__snapshots__/happy-path.e2e.ts.snap +++ b/__tests__/e2e/__snapshots__/happy-path.e2e.ts.snap @@ -77,7 +77,8 @@ exports[`happy-path flow > navigates Welcome → SystemCheck → Authenticate warehouse setup, migrations, and onboarding — so it can help ● Sign in to Confidence without searching the docs. ▶ Set up your agent ○ Connect tools - ○ Onboard project + ◆ Cursor and Codex require full file system access to run ○ Onboard project + onboarding. ────────────────────────────────────────────────────────────────────────────────────────────────── diff --git a/__tests__/e2e/__snapshots__/stale-auth.e2e.ts.snap b/__tests__/e2e/__snapshots__/stale-auth.e2e.ts.snap index e3e1911..2f64f2e 100644 --- a/__tests__/e2e/__snapshots__/stale-auth.e2e.ts.snap +++ b/__tests__/e2e/__snapshots__/stale-auth.e2e.ts.snap @@ -9,7 +9,8 @@ exports[`when auth token is stale > allows re-authentication after expired token warehouse setup, migrations, and onboarding — so it can help ● Sign in to Confidence without searching the docs. ▶ Set up your agent ○ Connect tools - ○ Onboard project + ◆ Cursor and Codex require full file system access to run ○ Onboard project + onboarding. ────────────────────────────────────────────────────────────────────────────────────────────────── @@ -31,7 +32,8 @@ exports[`when auth token is stale > allows signing in after failed refresh and p warehouse setup, migrations, and onboarding — so it can help ● Sign in to Confidence without searching the docs. ▶ Set up your agent ○ Connect tools - ○ Onboard project + ◆ Cursor and Codex require full file system access to run ○ Onboard project + onboarding. ────────────────────────────────────────────────────────────────────────────────────────────────── @@ -93,7 +95,8 @@ exports[`when auth token is stale > refreshes and authenticates when choosing ex warehouse setup, migrations, and onboarding — so it can help ● Sign in to Confidence without searching the docs. ▶ Set up your agent ○ Connect tools - ○ Onboard project + ◆ Cursor and Codex require full file system access to run ○ Onboard project + onboarding. ────────────────────────────────────────────────────────────────────────────────────────────────── diff --git a/__tests__/ui/screens/InstallPluginsScreen.test.tsx b/__tests__/ui/screens/InstallPluginsScreen.test.tsx index 9a5f5cd..d4387f0 100644 --- a/__tests__/ui/screens/InstallPluginsScreen.test.tsx +++ b/__tests__/ui/screens/InstallPluginsScreen.test.tsx @@ -34,6 +34,13 @@ describe('InstallPluginsScreen', () => { }); }); + it('shows file system access warning during IDE selection', async () => { + using sut = renderScreen(, { screen: ScreenId.InstallPlugins }); + await waitFor(() => { + expect(sut.lastFrame()).toContain('full file system access'); + }); + }); + it('installs plugin and shows success', async () => { using project = createProjectDir(); using sut = renderScreen(, { diff --git a/__tests__/ui/screens/OnboardingFlow.test.tsx b/__tests__/ui/screens/OnboardingFlow.test.tsx index 7050a55..2befd60 100644 --- a/__tests__/ui/screens/OnboardingFlow.test.tsx +++ b/__tests__/ui/screens/OnboardingFlow.test.tsx @@ -227,6 +227,55 @@ describe('Onboarding flow', () => { }); }); + describe('IDE-specific sandbox warning', () => { + it('shows standard warning when IDE is Claude Code', async () => { + using project = createProjectDir(); + + using sut = renderScreen(, { + screen: ScreenId.OnboardProject, + dir: project.path, + ide: 'claude', + goals: ['feature-flags'], + }); + + await waitFor(() => { + const frame = sut.lastFrame()!; + expect(frame).toContain('run commands, install packages'); + expect(frame).not.toContain('entire file system'); + }); + }); + + it('shows elevated warning when IDE is Cursor', async () => { + using project = createProjectDir(); + + using sut = renderScreen(, { + screen: ScreenId.OnboardProject, + dir: project.path, + ide: 'cursor', + goals: ['feature-flags'], + }); + + await waitFor(() => { + expect(sut.lastFrame()).toContain('entire file system'); + }); + }); + + it('shows elevated warning when IDE is Codex', async () => { + using project = createProjectDir(); + + using sut = renderScreen(, { + screen: ScreenId.OnboardProject, + dir: project.path, + ide: 'codex', + goals: ['feature-flags'], + }); + + await waitFor(() => { + expect(sut.lastFrame()).toContain('entire file system'); + }); + }); + }); + describe('selected goal display', () => { it('shows feature flag steps when goal is feature-flags', async () => { using project = createProjectDir(); diff --git a/src/ui/tui/screens/install-plugins/components/MainContent.tsx b/src/ui/tui/screens/install-plugins/components/MainContent.tsx index 599cee8..474f95a 100644 --- a/src/ui/tui/screens/install-plugins/components/MainContent.tsx +++ b/src/ui/tui/screens/install-plugins/components/MainContent.tsx @@ -31,6 +31,14 @@ export function MainContent({ phase, detected, error }: MainContentProps) { + {phase === 'choose-ide' && ( + + + {Icons.diamond} Cursor and Codex require full file system access to run onboarding. + + + )} + {phase === 'detecting' && } {phase === 'already-installed' && ( diff --git a/src/ui/tui/screens/onboard-project/OnboardProjectScreen.tsx b/src/ui/tui/screens/onboard-project/OnboardProjectScreen.tsx index e8b99ac..9701308 100644 --- a/src/ui/tui/screens/onboard-project/OnboardProjectScreen.tsx +++ b/src/ui/tui/screens/onboard-project/OnboardProjectScreen.tsx @@ -81,6 +81,7 @@ export function OnboardProjectScreen() { statusLines={onboarding.statusLines} error={onboarding.error} goals={session.onboardingGoals} + ide={session.ide} showTips={showTips} tip={tip} /> diff --git a/src/ui/tui/screens/onboard-project/components/OnboardingLeftPanel.tsx b/src/ui/tui/screens/onboard-project/components/OnboardingLeftPanel.tsx index dbd76a0..70369a1 100644 --- a/src/ui/tui/screens/onboard-project/components/OnboardingLeftPanel.tsx +++ b/src/ui/tui/screens/onboard-project/components/OnboardingLeftPanel.tsx @@ -3,21 +3,19 @@ import { Spinner } from '@inkjs/ui'; import { Colors, Emoji, Icons } from '../../../styles.js'; import { StatusFeed } from '../../../components/StatusFeed.js'; import { TipCard } from '../../../components/TipCard.js'; -import type { OnboardingGoal } from '@shared-kernel/types.js'; +import type { IdeId, OnboardingGoal } from '@shared-kernel/types.js'; import type { OnboardingPhase } from '../useOnboardingProcess.js'; import type { StatusLine } from '../../../lib/status-line.js'; import type { Tip } from '../../../lib/tips.js'; export const MAX_VISIBLE_STATUS = 3; -const SANDBOX_WARNING = - 'The AI agent will be able to run commands, install packages, and modify files in your project.'; - type OnboardingLeftPanelProps = { phase: OnboardingPhase; statusLines: StatusLine[]; error: string | null; goals: OnboardingGoal[]; + ide: IdeId | null; showTips: boolean; tip: Tip; }; @@ -27,6 +25,7 @@ export function OnboardingLeftPanel({ statusLines, error, goals, + ide, showTips, tip, }: OnboardingLeftPanelProps) { @@ -50,7 +49,7 @@ export function OnboardingLeftPanel({ - {Icons.diamond} {SANDBOX_WARNING} + {Icons.diamond} {sandboxWarning(ide)} @@ -97,3 +96,14 @@ const GOAL_STEPS: Record = { function onboardingSteps(goals: OnboardingGoal[]): string[] { return ['add the Confidence SDK', ...goals.flatMap((g) => GOAL_STEPS[g])]; } + +const WARNING_MSG = { + sandbox: + 'The AI agent will be able to run commands, install packages, and modify files in your project.', + relaxed: + 'The AI agent will have access to your entire file system as well as run commands and install packages in your project.', +} as const; + +function sandboxWarning(ide: IdeId | null): string { + return ide === 'claude' ? WARNING_MSG.sandbox : WARNING_MSG.relaxed; +}