diff --git a/lara.lock b/lara.lock index 40080338..9387bd6e 100644 --- a/lara.lock +++ b/lara.lock @@ -183,12 +183,12 @@ files: settings.allNotesVisibility.unsupported: 257fe04419c9f6543a43e58b1edf9eb5 settings.allNotesVisibility.unsupportedDescription: a3b8aa66900c742f001cd4533b3df44a settings.aiAgents.title: 27f08387b26e1ceeb1b60bd9c97e7a47 - settings.aiAgents.description: 042a8037f1a4f90c76ce31a49fdff59c + settings.aiAgents.description: 768c138c3432fb159ac58c5a4471e786 settings.aiFeatures.enable: af47a6b2bd32a7b7309bac7bef34f026 settings.aiFeatures.enableDescription: 7d3916f7f9e1bf8b8797f50f4533b9da settings.aiAgents.default: 6af573559fd05d8c35bc57b41cc78e24 settings.aiAgents.defaultTarget: 5acfc74fd97a6dd2d67d15c66de5eed5 - settings.aiAgents.agentGroup: 965530cbbec45b1754ed3ece120399f7 + settings.aiAgents.agentGroup: 11eaa7f817e3f24d54f3cf3025be49b1 settings.aiAgents.localGroup: d34f4b997ce78da5aa57d657a5d6fcb5 settings.aiAgents.apiGroup: 589a257cbd265eaa7de93de8b4084dff settings.aiAgents.installed: 73329564760013a7824ff9d5d1af91ff @@ -199,11 +199,11 @@ files: settings.aiAgents.apiLocalKey: 119de2f31867b273a134f05bc56b9e57 settings.aiAgents.apiEnv: e011db3dff54ed3deae37a9615e31ebf settings.aiAgents.apiNoKey: 5bbccbfcd09b28902bbf5319dd6e6053 - settings.aiAgents.installedTitle: 5cb9b5ae5ebc66652814dff4584705cc - settings.aiAgents.installedDescription: fb9ba9667725fb40fa1e5d58a2c02692 + settings.aiAgents.installedTitle: 0de6536215f76c44351ba4d809804c7a + settings.aiAgents.installedDescription: 27c8ed48439ac4a613409f5303fbca84 settings.aiAgents.noVersion: 89831adb7114946e916b9c31d57a1e33 settings.aiProviders.title: 63eb84d8510f9f086d282ec7d47adaa1 - settings.aiProviders.description: 6c86c013eb6fb198b51e29ec47d66464 + settings.aiProviders.description: d29dfa440713d15de311d29a64a27767 settings.aiProviders.localTitle: c7c20443d8aaf04271df9d713f5c02ce settings.aiProviders.localDescription: 7abed40ef2e46741c64ff47e423cca39 settings.aiProviders.apiTitle: 66537b9e5200ebbbfbd091144d8afbcc diff --git a/src/components/AiAgentsOnboardingPrompt.tsx b/src/components/AiAgentsOnboardingPrompt.tsx index 158a43cc..590e16db 100644 --- a/src/components/AiAgentsOnboardingPrompt.tsx +++ b/src/components/AiAgentsOnboardingPrompt.tsx @@ -21,7 +21,7 @@ function getPromptCopy(statuses: AiAgentsStatus) { if (isAiAgentsStatusChecking(statuses)) { return { accentClassName: 'bg-muted text-muted-foreground', - description: 'Checking coding agents. You can also use a local model or API provider.', + description: 'Checking local agents. You can also use a local model or API provider.', icon: , title: 'Checking AI agents', } @@ -38,7 +38,7 @@ function getPromptCopy(statuses: AiAgentsStatus) { return { accentClassName: 'bg-[var(--feedback-success-bg)] text-[var(--feedback-success-text)]', - description: 'You can use the detected coding agents, or add local/API models in Settings.', + description: 'You can use the detected local agents, or add local/API models in Settings.', icon: , title: 'AI is ready', } @@ -58,7 +58,7 @@ function AiModeChoices() { }, { icon: , - title: 'Coding agent', + title: 'Local agent', description: 'Use Claude Code, Codex, OpenCode, Gemini CLI, or Pi for tool-capable vault editing on desktop.', }, ] diff --git a/src/components/SettingsPanel.test.tsx b/src/components/SettingsPanel.test.tsx index daf90660..f318c244 100644 --- a/src/components/SettingsPanel.test.tsx +++ b/src/components/SettingsPanel.test.tsx @@ -130,7 +130,7 @@ describe('SettingsPanel', () => { expect(screen.getAllByText('Sync & Updates').length).toBeGreaterThan(0) }) - it('separates coding agents, local models, and API models in AI settings', async () => { + it('separates local agents, local models, and API models in AI settings', async () => { const aiAgentsStatus: AiAgentsStatus = { claude_code: { status: 'installed', version: '2.1.18' }, codex: { status: 'missing', version: null }, @@ -148,7 +148,7 @@ describe('SettingsPanel', () => { /> ) - expect(screen.getByText('Recognized coding agents')).toBeInTheDocument() + expect(screen.getByText('Recognized local agents')).toBeInTheDocument() expect(screen.getByText('Claude Code')).toBeInTheDocument() expect(screen.getByText('2.1.18')).toBeInTheDocument() expect(screen.getByRole('tab', { name: 'Local model' })).toBeInTheDocument() @@ -159,7 +159,7 @@ describe('SettingsPanel', () => { fireEvent.click(screen.getByRole('button', { name: 'Test model' })) expect(await screen.findByText('Connection works. The model replied successfully.')).toBeInTheDocument() expect(screen.getByRole('button', { name: 'Add local model' })).toBeInTheDocument() - expect(screen.queryByText('Recognized coding agents')).not.toBeInTheDocument() + expect(screen.queryByText('Recognized local agents')).not.toBeInTheDocument() fireEvent.mouseDown(screen.getByRole('tab', { name: 'API model' }), { button: 0, ctrlKey: false }) expect(screen.getByRole('button', { name: 'Add API model' })).toBeInTheDocument() @@ -182,7 +182,7 @@ describe('SettingsPanel', () => { ) expect(within(screen.getByTestId('settings-ai-features-enabled')).getByRole('switch')).toHaveAttribute('aria-checked', 'false') - expect(screen.queryByText('Recognized coding agents')).not.toBeInTheDocument() + expect(screen.queryByText('Recognized local agents')).not.toBeInTheDocument() fireEvent.click(within(screen.getByTestId('settings-ai-features-enabled')).getByRole('switch')) saveSettingsPanel() diff --git a/src/components/status-bar/AiAgentsBadge.test.tsx b/src/components/status-bar/AiAgentsBadge.test.tsx index 0e391b8d..c737335d 100644 --- a/src/components/status-bar/AiAgentsBadge.test.tsx +++ b/src/components/status-bar/AiAgentsBadge.test.tsx @@ -105,6 +105,25 @@ describe('AiAgentsBadge', () => { expect(screen.getByRole('menuitemradio', { name: /OpenAI.*gpt-5\.5/ })).toHaveAttribute('aria-checked', 'true') }) + it('does not show install actions for missing local agents', () => { + renderBadge({ + statuses: { + claude_code: { status: 'installed', version: '1.0.20' }, + codex: { status: 'missing', version: null }, + opencode: { status: 'missing', version: null }, + pi: { status: 'missing', version: null }, + gemini: { status: 'missing', version: null }, + }, + }) + openAiAgentsMenu() + + expect(screen.queryByText('Install')).not.toBeInTheDocument() + expect(screen.queryByText('Install Codex')).not.toBeInTheDocument() + expect(screen.queryByText('Install OpenCode')).not.toBeInTheDocument() + expect(screen.queryByText('Install Pi')).not.toBeInTheDocument() + expect(screen.queryByText('Install Gemini CLI')).not.toBeInTheDocument() + }) + it('shows the vault guidance summary and restore action', async () => { const onRestoreGuidance = vi.fn() diff --git a/src/components/status-bar/AiAgentsBadge.tsx b/src/components/status-bar/AiAgentsBadge.tsx index 6fdcbde8..cd493e95 100644 --- a/src/components/status-bar/AiAgentsBadge.tsx +++ b/src/components/status-bar/AiAgentsBadge.tsx @@ -26,7 +26,6 @@ import { type VaultAiGuidanceStatus, } from '../../lib/vaultAiGuidance' import { translate, type AppLocale } from '../../lib/i18n' -import { openExternalUrl } from '../../utils/url' import { DropdownMenu, DropdownMenuContent, @@ -82,10 +81,6 @@ function installedAgentDefinitions(statuses: AiAgentsStatus): AiAgentDefinition[ return AI_AGENT_DEFINITIONS.filter((definition) => isAiAgentInstalled(statuses, definition.id)) } -function missingAgentDefinitions(statuses: AiAgentsStatus): AiAgentDefinition[] { - return AI_AGENT_DEFINITIONS.filter((definition) => !isAiAgentInstalled(statuses, definition.id)) -} - function triggerLabel(defaultAgent: AiAgentId): string { return getAiAgentDefinition(defaultAgent).shortLabel } @@ -188,7 +183,6 @@ function AgentMenuContent({ locale = 'en', }: AiAgentsBadgeProps & { selectedTarget: AiTarget; selectedAgentReady: boolean }) { const installedAgents = installedAgentDefinitions(statuses) - const missingAgents = missingAgentDefinitions(statuses) const modelTargets = configuredModelTargets(providers) const selectedAgentValue = selectedTarget.kind === 'agent' && selectedAgentReady ? selectedTarget.agent : undefined @@ -226,20 +220,6 @@ function AgentMenuContent({ locale={locale} onSetDefaultTarget={onSetDefaultTarget} /> - {missingAgents.length > 0 && ( - <> - - {translate(locale, 'status.ai.install')} - {missingAgents.map((definition) => ( - void openExternalUrl(definition.installUrl)} - > - {translate(locale, 'status.ai.installAgent', { agent: definition.label })} - - ))} - - )}