fix: simplify local agent setup surfaces
This commit is contained in:
@@ -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: <Loader2 className="size-7 animate-spin" />,
|
||||
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: <CheckCircle2 className="size-7" />,
|
||||
title: 'AI is ready',
|
||||
}
|
||||
@@ -58,7 +58,7 @@ function AiModeChoices() {
|
||||
},
|
||||
{
|
||||
icon: <Terminal className="size-4" />,
|
||||
title: 'Coding agent',
|
||||
title: 'Local agent',
|
||||
description: 'Use Claude Code, Codex, OpenCode, Gemini CLI, or Pi for tool-capable vault editing on desktop.',
|
||||
},
|
||||
]
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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 && (
|
||||
<>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuLabel>{translate(locale, 'status.ai.install')}</DropdownMenuLabel>
|
||||
{missingAgents.map((definition) => (
|
||||
<DropdownMenuItem
|
||||
key={definition.id}
|
||||
onSelect={() => void openExternalUrl(definition.installUrl)}
|
||||
>
|
||||
{translate(locale, 'status.ai.installAgent', { agent: definition.label })}
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
<GuidanceMenuSection
|
||||
guidanceStatus={guidanceStatus}
|
||||
locale={locale}
|
||||
|
||||
Reference in New Issue
Block a user