diff --git a/apps/ui/src/components/views/settings-view.tsx b/apps/ui/src/components/views/settings-view.tsx
index b888c9b6..a5d420a8 100644
--- a/apps/ui/src/components/views/settings-view.tsx
+++ b/apps/ui/src/components/views/settings-view.tsx
@@ -1,16 +1,13 @@
import { useState } from 'react';
import { useAppStore } from '@/store/app-store';
-import { useCliStatus, useSettingsView } from './settings-view/hooks';
+import { useSettingsView } from './settings-view/hooks';
import { NAV_ITEMS } from './settings-view/config/navigation';
import { SettingsHeader } from './settings-view/components/settings-header';
import { KeyboardMapDialog } from './settings-view/components/keyboard-map-dialog';
import { DeleteProjectDialog } from './settings-view/components/delete-project-dialog';
import { SettingsNavigation } from './settings-view/components/settings-navigation';
import { ApiKeysSection } from './settings-view/api-keys/api-keys-section';
-import { ClaudeUsageSection } from './settings-view/api-keys/claude-usage-section';
-import { ClaudeCliStatus } from './settings-view/cli-status/claude-cli-status';
-import { ClaudeMdSettings } from './settings-view/claude/claude-md-settings';
import { AIEnhancementSection } from './settings-view/ai-enhancement';
import { AppearanceSection } from './settings-view/appearance/appearance-section';
import { TerminalSection } from './settings-view/terminal/terminal-section';
@@ -18,6 +15,7 @@ import { AudioSection } from './settings-view/audio/audio-section';
import { KeyboardShortcutsSection } from './settings-view/keyboard-shortcuts/keyboard-shortcuts-section';
import { FeatureDefaultsSection } from './settings-view/feature-defaults/feature-defaults-section';
import { DangerZoneSection } from './settings-view/danger-zone/danger-zone-section';
+import { ProviderTabs } from './settings-view/providers';
import type { Project as SettingsProject, Theme } from './settings-view/shared/types';
import type { Project as ElectronProject } from '@/lib/electron';
@@ -45,19 +43,10 @@ export function SettingsView() {
defaultAIProfileId,
setDefaultAIProfileId,
aiProfiles,
- apiKeys,
validationModel,
setValidationModel,
- autoLoadClaudeMd,
- setAutoLoadClaudeMd,
} = useAppStore();
- // Hide usage tracking when using API key (only show for Claude Code CLI users)
- // Also hide on Windows for now (CLI usage command not supported)
- const isWindows =
- typeof navigator !== 'undefined' && navigator.platform?.toLowerCase().includes('win');
- const showUsageTracking = !apiKeys.anthropic && !isWindows;
-
// Convert electron Project to settings-view Project type
const convertProject = (project: ElectronProject | null): SettingsProject | null => {
if (!project) return null;
@@ -85,9 +74,6 @@ export function SettingsView() {
}
};
- // Use CLI status hook
- const { claudeCliStatus, isCheckingClaudeCli, handleRefreshClaudeCli } = useCliStatus();
-
// Use settings view navigation hook
const { activeView, navigateTo } = useSettingsView();
@@ -97,21 +83,9 @@ export function SettingsView() {
// Render the active section based on current view
const renderActiveSection = () => {
switch (activeView) {
- case 'claude':
- return (
-
-
-
- {showUsageTracking && }
-
- );
+ case 'providers':
+ case 'claude': // Backwards compatibility
+ return ;
case 'ai-enhancement':
return ;
case 'appearance':
diff --git a/apps/ui/src/components/views/settings-view/config/navigation.ts b/apps/ui/src/components/views/settings-view/config/navigation.ts
index e32c2223..001006c0 100644
--- a/apps/ui/src/components/views/settings-view/config/navigation.ts
+++ b/apps/ui/src/components/views/settings-view/config/navigation.ts
@@ -1,7 +1,7 @@
import type { LucideIcon } from 'lucide-react';
import {
Key,
- Terminal,
+ Bot,
SquareTerminal,
Palette,
Settings2,
@@ -21,7 +21,7 @@ export interface NavigationItem {
// Navigation items for the settings side panel
export const NAV_ITEMS: NavigationItem[] = [
{ id: 'api-keys', label: 'API Keys', icon: Key },
- { id: 'claude', label: 'Claude', icon: Terminal },
+ { id: 'providers', label: 'AI Providers', icon: Bot },
{ id: 'ai-enhancement', label: 'AI Enhancement', icon: Sparkles },
{ id: 'appearance', label: 'Appearance', icon: Palette },
{ id: 'terminal', label: 'Terminal', icon: SquareTerminal },
diff --git a/apps/ui/src/components/views/settings-view/hooks/use-settings-view.ts b/apps/ui/src/components/views/settings-view/hooks/use-settings-view.ts
index 2e3f784f..80ac4fae 100644
--- a/apps/ui/src/components/views/settings-view/hooks/use-settings-view.ts
+++ b/apps/ui/src/components/views/settings-view/hooks/use-settings-view.ts
@@ -3,6 +3,7 @@ import { useState, useCallback } from 'react';
export type SettingsViewId =
| 'api-keys'
| 'claude'
+ | 'providers'
| 'ai-enhancement'
| 'appearance'
| 'terminal'
diff --git a/apps/ui/src/components/views/settings-view/providers/claude-settings-tab.tsx b/apps/ui/src/components/views/settings-view/providers/claude-settings-tab.tsx
new file mode 100644
index 00000000..df69cc82
--- /dev/null
+++ b/apps/ui/src/components/views/settings-view/providers/claude-settings-tab.tsx
@@ -0,0 +1,35 @@
+import { useAppStore } from '@/store/app-store';
+import { useCliStatus } from '../hooks/use-cli-status';
+import { ClaudeCliStatus } from '../cli-status/claude-cli-status';
+import { ClaudeMdSettings } from '../claude/claude-md-settings';
+import { ClaudeUsageSection } from '../api-keys/claude-usage-section';
+
+export function ClaudeSettingsTab() {
+ const { apiKeys, autoLoadClaudeMd, setAutoLoadClaudeMd } = useAppStore();
+
+ // Use CLI status hook
+ const { claudeCliStatus, isCheckingClaudeCli, handleRefreshClaudeCli } = useCliStatus();
+
+ // Hide usage tracking when using API key (only show for Claude Code CLI users)
+ // Also hide on Windows for now (CLI usage command not supported)
+ const isWindows =
+ typeof navigator !== 'undefined' && navigator.platform?.toLowerCase().includes('win');
+ const showUsageTracking = !apiKeys.anthropic && !isWindows;
+
+ return (
+
+
+
+ {showUsageTracking && }
+
+ );
+}
+
+export default ClaudeSettingsTab;
diff --git a/apps/ui/src/components/views/settings-view/providers/cursor-settings-tab.tsx b/apps/ui/src/components/views/settings-view/providers/cursor-settings-tab.tsx
new file mode 100644
index 00000000..56e51da1
--- /dev/null
+++ b/apps/ui/src/components/views/settings-view/providers/cursor-settings-tab.tsx
@@ -0,0 +1,321 @@
+import { useState, useEffect, useCallback } from 'react';
+import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
+import { Button } from '@/components/ui/button';
+import { Label } from '@/components/ui/label';
+import { Badge } from '@/components/ui/badge';
+import { Checkbox } from '@/components/ui/checkbox';
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from '@/components/ui/select';
+import { Terminal, CheckCircle2, XCircle, Loader2, RefreshCw, ExternalLink } from 'lucide-react';
+import { toast } from 'sonner';
+import { getHttpApiClient } from '@/lib/http-api-client';
+import { useAppStore } from '@/store/app-store';
+import type { CursorModelId, CursorModelConfig, CursorCliConfig } from '@automaker/types';
+import { CURSOR_MODEL_MAP } from '@automaker/types';
+
+interface CursorStatus {
+ installed: boolean;
+ version?: string;
+ authenticated: boolean;
+ method?: string;
+}
+
+export function CursorSettingsTab() {
+ const { currentProject } = useAppStore();
+ const [status, setStatus] = useState(null);
+ const [config, setConfig] = useState(null);
+ const [availableModels, setAvailableModels] = useState([]);
+ const [isLoading, setIsLoading] = useState(true);
+ const [isSaving, setIsSaving] = useState(false);
+
+ const loadData = useCallback(async () => {
+ setIsLoading(true);
+ try {
+ const api = getHttpApiClient();
+ const statusResult = await api.setup.getCursorStatus();
+
+ if (statusResult.success) {
+ setStatus({
+ installed: statusResult.installed ?? false,
+ version: statusResult.version ?? undefined,
+ authenticated: statusResult.auth?.authenticated ?? false,
+ method: statusResult.auth?.method,
+ });
+ }
+
+ // Only load config if we have a project path
+ if (currentProject?.path) {
+ const configResult = await api.setup.getCursorConfig(currentProject.path);
+ if (configResult.success) {
+ setConfig({
+ defaultModel: configResult.config?.defaultModel as CursorModelId | undefined,
+ models: configResult.config?.models as CursorModelId[] | undefined,
+ mcpServers: configResult.config?.mcpServers,
+ rules: configResult.config?.rules,
+ });
+ if (configResult.availableModels) {
+ setAvailableModels(configResult.availableModels as CursorModelConfig[]);
+ } else {
+ setAvailableModels(Object.values(CURSOR_MODEL_MAP));
+ }
+ } else {
+ // Set defaults if no config
+ setAvailableModels(Object.values(CURSOR_MODEL_MAP));
+ }
+ } else {
+ // No project, just show available models
+ setAvailableModels(Object.values(CURSOR_MODEL_MAP));
+ }
+ } catch (error) {
+ console.error('Failed to load Cursor settings:', error);
+ toast.error('Failed to load Cursor settings');
+ } finally {
+ setIsLoading(false);
+ }
+ }, [currentProject?.path]);
+
+ useEffect(() => {
+ loadData();
+ }, [loadData]);
+
+ const handleDefaultModelChange = async (model: CursorModelId) => {
+ if (!currentProject?.path) {
+ toast.error('No project selected');
+ return;
+ }
+
+ setIsSaving(true);
+ try {
+ const api = getHttpApiClient();
+ const result = await api.setup.setCursorDefaultModel(currentProject.path, model);
+
+ if (result.success) {
+ setConfig((prev) => (prev ? { ...prev, defaultModel: model } : { defaultModel: model }));
+ toast.success('Default model updated');
+ } else {
+ toast.error(result.error || 'Failed to update default model');
+ }
+ } catch (error) {
+ toast.error('Failed to update default model');
+ } finally {
+ setIsSaving(false);
+ }
+ };
+
+ const handleModelToggle = async (model: CursorModelId, enabled: boolean) => {
+ if (!currentProject?.path) {
+ toast.error('No project selected');
+ return;
+ }
+
+ const currentModels = config?.models || ['auto'];
+ const newModels = enabled
+ ? [...currentModels, model]
+ : currentModels.filter((m) => m !== model);
+
+ setIsSaving(true);
+ try {
+ const api = getHttpApiClient();
+ const result = await api.setup.setCursorModels(currentProject.path, newModels);
+
+ if (result.success) {
+ setConfig((prev) => (prev ? { ...prev, models: newModels } : { models: newModels }));
+ } else {
+ toast.error(result.error || 'Failed to update models');
+ }
+ } catch (error) {
+ toast.error('Failed to update models');
+ } finally {
+ setIsSaving(false);
+ }
+ };
+
+ if (isLoading) {
+ return (
+
+
+
+ );
+ }
+
+ return (
+
+ {/* Status Card */}
+
+
+
+
+ Cursor CLI Status
+
+
+
+ {/* Installation */}
+
+
Installation
+ {status?.installed ? (
+
+
+ v{status.version}
+
+ ) : (
+
+
+ Not installed
+
+ )}
+
+
+ {/* Authentication */}
+
+
Authentication
+ {status?.authenticated ? (
+
+
+
+ {status.method === 'api_key' ? 'API Key' : 'Browser Login'}
+
+
+ ) : (
+
+
+ Not authenticated
+
+ )}
+
+
+ {/* Actions */}
+
+
+
+ Refresh Status
+
+ {!status?.installed && (
+ window.open('https://cursor.com/docs/cli', '_blank')}
+ >
+ Installation Guide
+
+
+ )}
+
+
+
+
+ {/* Model Configuration */}
+ {status?.installed && currentProject && (
+
+
+ Model Configuration
+
+ Configure which Cursor models are available and set the default
+
+
+
+ {/* Default Model */}
+
+
Default Model
+
handleDefaultModelChange(v as CursorModelId)}
+ disabled={isSaving}
+ >
+
+
+
+
+ {(config?.models || ['auto']).map((modelId) => {
+ const model = CURSOR_MODEL_MAP[modelId as CursorModelId];
+ if (!model) return null;
+ return (
+
+
+ {model.label}
+ {model.hasThinking && (
+
+ Thinking
+
+ )}
+
+
+ );
+ })}
+
+
+
+
+ {/* Enabled Models */}
+
+
Available Models
+
+ {availableModels.map((model) => {
+ const isEnabled = config?.models?.includes(model.id) ?? model.id === 'auto';
+ const isAuto = model.id === 'auto';
+
+ return (
+
+
+
handleModelToggle(model.id, !!checked)}
+ disabled={isSaving || isAuto}
+ />
+
+
+ {model.label}
+ {model.hasThinking && (
+
+ Thinking
+
+ )}
+
+
{model.description}
+
+
+
+ {model.tier}
+
+
+ );
+ })}
+
+
+
+
+ )}
+
+ {/* Not Installed State */}
+ {!status?.installed && (
+
+
+
+ Cursor CLI is not installed.
+ Install it to use Cursor models in AutoMaker.
+
+
+ )}
+
+ {/* No Project Selected */}
+ {status?.installed && !currentProject && (
+
+
+
+ No project selected.
+ Select a project to configure Cursor models.
+
+
+ )}
+
+ );
+}
+
+export default CursorSettingsTab;
diff --git a/apps/ui/src/components/views/settings-view/providers/index.ts b/apps/ui/src/components/views/settings-view/providers/index.ts
new file mode 100644
index 00000000..c9284867
--- /dev/null
+++ b/apps/ui/src/components/views/settings-view/providers/index.ts
@@ -0,0 +1,3 @@
+export { ProviderTabs } from './provider-tabs';
+export { ClaudeSettingsTab } from './claude-settings-tab';
+export { CursorSettingsTab } from './cursor-settings-tab';
diff --git a/apps/ui/src/components/views/settings-view/providers/provider-tabs.tsx b/apps/ui/src/components/views/settings-view/providers/provider-tabs.tsx
new file mode 100644
index 00000000..dc97cf2f
--- /dev/null
+++ b/apps/ui/src/components/views/settings-view/providers/provider-tabs.tsx
@@ -0,0 +1,36 @@
+import React from 'react';
+import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
+import { Bot, Terminal } from 'lucide-react';
+import { CursorSettingsTab } from './cursor-settings-tab';
+import { ClaudeSettingsTab } from './claude-settings-tab';
+
+interface ProviderTabsProps {
+ defaultTab?: 'claude' | 'cursor';
+}
+
+export function ProviderTabs({ defaultTab = 'claude' }: ProviderTabsProps) {
+ return (
+
+
+
+
+ Claude
+
+
+
+ Cursor
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default ProviderTabs;
diff --git a/plan/cursor-cli-integration/README.md b/plan/cursor-cli-integration/README.md
index 6fad613f..4e1fd7a1 100644
--- a/plan/cursor-cli-integration/README.md
+++ b/plan/cursor-cli-integration/README.md
@@ -13,7 +13,7 @@
| 4 | [Setup Routes & Status Endpoints](phases/phase-4-routes.md) | `completed` | ✅ |
| 5 | [Log Parser Integration](phases/phase-5-log-parser.md) | `completed` | ✅ |
| 6 | [UI Setup Wizard](phases/phase-6-setup-wizard.md) | `completed` | ✅ |
-| 7 | [Settings View Provider Tabs](phases/phase-7-settings.md) | `pending` | - |
+| 7 | [Settings View Provider Tabs](phases/phase-7-settings.md) | `completed` | ✅ |
| 8 | [AI Profiles Integration](phases/phase-8-profiles.md) | `pending` | - |
| 9 | [Task Execution Integration](phases/phase-9-execution.md) | `pending` | - |
| 10 | [Testing & Validation](phases/phase-10-testing.md) | `pending` | - |
diff --git a/plan/cursor-cli-integration/phases/phase-7-settings.md b/plan/cursor-cli-integration/phases/phase-7-settings.md
index ecbad2b2..46255fef 100644
--- a/plan/cursor-cli-integration/phases/phase-7-settings.md
+++ b/plan/cursor-cli-integration/phases/phase-7-settings.md
@@ -1,6 +1,6 @@
# Phase 7: Settings View Provider Tabs
-**Status:** `pending`
+**Status:** `completed`
**Dependencies:** Phase 4 (Routes)
**Estimated Effort:** Medium (React components)
@@ -16,7 +16,7 @@ Create a tabbed interface in Settings for managing different AI providers (Claud
### Task 7.1: Create Cursor Settings Tab Component
-**Status:** `pending`
+**Status:** `completed`
**File:** `apps/ui/src/components/views/settings-view/providers/cursor-settings-tab.tsx`
@@ -311,7 +311,7 @@ export default CursorSettingsTab;
### Task 7.2: Create Provider Tabs Container
-**Status:** `pending`
+**Status:** `completed`
**File:** `apps/ui/src/components/views/settings-view/providers/provider-tabs.tsx`
@@ -356,7 +356,7 @@ export default ProviderTabs;
### Task 7.3: Create Claude Settings Tab (if not exists)
-**Status:** `pending`
+**Status:** `completed`
**File:** `apps/ui/src/components/views/settings-view/providers/claude-settings-tab.tsx`
@@ -461,7 +461,7 @@ export default ClaudeSettingsTab;
### Task 7.4: Update Settings View Navigation
-**Status:** `pending`
+**Status:** `completed`
**File:** `apps/ui/src/components/views/settings-view/config/navigation.ts`
@@ -482,7 +482,7 @@ export const SETTINGS_NAVIGATION = [
### Task 7.5: Integrate Provider Tabs in Settings
-**Status:** `pending`
+**Status:** `completed`
Update the settings view to render ProviderTabs for the providers section.