diff --git a/auto-claude-ui/src/main/ipc-handlers/settings-handlers.ts b/auto-claude-ui/src/main/ipc-handlers/settings-handlers.ts index 30f06a7d..25b1a763 100644 --- a/auto-claude-ui/src/main/ipc-handlers/settings-handlers.ts +++ b/auto-claude-ui/src/main/ipc-handlers/settings-handlers.ts @@ -94,7 +94,7 @@ export function registerSettingsHandlers( ipcMain.handle( IPC_CHANNELS.SETTINGS_GET, async (): Promise> => { - let settings = { ...DEFAULT_APP_SETTINGS }; + let settings: AppSettings = { ...DEFAULT_APP_SETTINGS }; let needsSave = false; if (existsSync(settingsPath)) { @@ -106,12 +106,15 @@ export function registerSettingsHandlers( } } - // Migration: Reset agent profile to 'auto' for existing users (one-time) - // This ensures all users get the optimized 'auto' profile as the default - const settingsAny = settings as Record; - if (!settingsAny._migratedAgentProfileToAuto) { - settings.selectedAgentProfile = 'auto'; - settingsAny._migratedAgentProfileToAuto = true; + // Migration: Set agent profile to 'auto' for users who haven't made a selection (one-time) + // This ensures new users get the optimized 'auto' profile as the default + // while preserving existing user preferences + if (!settings._migratedAgentProfileToAuto) { + // Only set 'auto' if user hasn't made a selection yet + if (!settings.selectedAgentProfile) { + settings.selectedAgentProfile = 'auto'; + } + settings._migratedAgentProfileToAuto = true; needsSave = true; } @@ -127,8 +130,9 @@ export function registerSettingsHandlers( if (needsSave) { try { writeFileSync(settingsPath, JSON.stringify(settings, null, 2)); - } catch { - // Ignore write errors during migration + } catch (error) { + console.error('[SETTINGS_GET] Failed to persist migration:', error); + // Continue anyway - settings will be migrated in-memory for this session } } diff --git a/auto-claude-ui/src/renderer/components/TaskCreationWizard.tsx b/auto-claude-ui/src/renderer/components/TaskCreationWizard.tsx index 6aaa57d9..58b4c449 100644 --- a/auto-claude-ui/src/renderer/components/TaskCreationWizard.tsx +++ b/auto-claude-ui/src/renderer/components/TaskCreationWizard.tsx @@ -102,11 +102,12 @@ export function TaskCreationWizard({ const [model, setModel] = useState(selectedProfile.model); const [thinkingLevel, setThinkingLevel] = useState(selectedProfile.thinkingLevel); // Auto profile - per-phase configuration + // Use custom settings from app settings if available, otherwise fall back to defaults const [phaseModels, setPhaseModels] = useState( - selectedProfile.phaseModels || DEFAULT_PHASE_MODELS + settings.customPhaseModels || selectedProfile.phaseModels || DEFAULT_PHASE_MODELS ); const [phaseThinking, setPhaseThinking] = useState( - selectedProfile.phaseThinking || DEFAULT_PHASE_THINKING + settings.customPhaseThinking || selectedProfile.phaseThinking || DEFAULT_PHASE_THINKING ); // Image attachments @@ -143,8 +144,8 @@ export function TaskCreationWizard({ setProfileId(draft.profileId || settings.selectedAgentProfile || 'auto'); setModel(draft.model || selectedProfile.model); setThinkingLevel(draft.thinkingLevel || selectedProfile.thinkingLevel); - setPhaseModels(draft.phaseModels || selectedProfile.phaseModels || DEFAULT_PHASE_MODELS); - setPhaseThinking(draft.phaseThinking || selectedProfile.phaseThinking || DEFAULT_PHASE_THINKING); + setPhaseModels(draft.phaseModels || settings.customPhaseModels || selectedProfile.phaseModels || DEFAULT_PHASE_MODELS); + setPhaseThinking(draft.phaseThinking || settings.customPhaseThinking || selectedProfile.phaseThinking || DEFAULT_PHASE_THINKING); setImages(draft.images); setReferencedFiles(draft.referencedFiles ?? []); setRequireReviewBeforeCoding(draft.requireReviewBeforeCoding ?? false); @@ -159,15 +160,15 @@ export function TaskCreationWizard({ } // Note: Referenced Files section is always visible, no need to expand } else { - // No draft - initialize from selected profile + // No draft - initialize from selected profile and custom settings setProfileId(settings.selectedAgentProfile || 'auto'); setModel(selectedProfile.model); setThinkingLevel(selectedProfile.thinkingLevel); - setPhaseModels(selectedProfile.phaseModels || DEFAULT_PHASE_MODELS); - setPhaseThinking(selectedProfile.phaseThinking || DEFAULT_PHASE_THINKING); + setPhaseModels(settings.customPhaseModels || selectedProfile.phaseModels || DEFAULT_PHASE_MODELS); + setPhaseThinking(settings.customPhaseThinking || selectedProfile.phaseThinking || DEFAULT_PHASE_THINKING); } } - }, [open, projectId, settings.selectedAgentProfile, selectedProfile.model, selectedProfile.thinkingLevel]); + }, [open, projectId, settings.selectedAgentProfile, settings.customPhaseModels, settings.customPhaseThinking, selectedProfile.model, selectedProfile.thinkingLevel]); // Fetch branches and project default branch when dialog opens useEffect(() => { @@ -542,12 +543,12 @@ export function TaskCreationWizard({ setPriority(''); setComplexity(''); setImpact(''); - // Reset to selected profile defaults + // Reset to selected profile defaults and custom settings setProfileId(settings.selectedAgentProfile || 'auto'); setModel(selectedProfile.model); setThinkingLevel(selectedProfile.thinkingLevel); - setPhaseModels(selectedProfile.phaseModels || DEFAULT_PHASE_MODELS); - setPhaseThinking(selectedProfile.phaseThinking || DEFAULT_PHASE_THINKING); + setPhaseModels(settings.customPhaseModels || selectedProfile.phaseModels || DEFAULT_PHASE_MODELS); + setPhaseThinking(settings.customPhaseThinking || selectedProfile.phaseThinking || DEFAULT_PHASE_THINKING); setImages([]); setReferencedFiles([]); setRequireReviewBeforeCoding(false); diff --git a/auto-claude-ui/src/renderer/components/settings/AgentProfileSettings.tsx b/auto-claude-ui/src/renderer/components/settings/AgentProfileSettings.tsx index eb119815..08a51f32 100644 --- a/auto-claude-ui/src/renderer/components/settings/AgentProfileSettings.tsx +++ b/auto-claude-ui/src/renderer/components/settings/AgentProfileSettings.tsx @@ -1,9 +1,25 @@ -import { Brain, Scale, Zap, Check, Sparkles } from 'lucide-react'; +import { useState } from 'react'; +import { Brain, Scale, Zap, Check, Sparkles, ChevronDown, ChevronUp, RotateCcw } from 'lucide-react'; import { cn } from '../../lib/utils'; -import { DEFAULT_AGENT_PROFILES, AVAILABLE_MODELS, THINKING_LEVELS } from '../../../shared/constants'; +import { + DEFAULT_AGENT_PROFILES, + AVAILABLE_MODELS, + THINKING_LEVELS, + DEFAULT_PHASE_MODELS, + DEFAULT_PHASE_THINKING +} from '../../../shared/constants'; import { useSettingsStore, saveSettings } from '../../stores/settings-store'; import { SettingsSection } from './SettingsSection'; -import type { AgentProfile } from '../../../shared/types/settings'; +import { Label } from '../ui/label'; +import { Button } from '../ui/button'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue +} from '../ui/select'; +import type { AgentProfile, PhaseModelConfig, PhaseThinkingConfig, ModelTypeShort, ThinkingLevel } from '../../../shared/types/settings'; /** * Icon mapping for agent profile icons @@ -15,6 +31,13 @@ const iconMap: Record = { Sparkles }; +const PHASE_LABELS: Record = { + spec: { label: 'Spec Creation', description: 'Discovery, requirements, context gathering' }, + planning: { label: 'Planning', description: 'Implementation planning and architecture' }, + coding: { label: 'Coding', description: 'Actual code implementation' }, + qa: { label: 'QA Review', description: 'Quality assurance and validation' } +}; + /** * Agent Profile Settings component * Displays preset agent profiles for quick model/thinking level configuration @@ -23,9 +46,40 @@ const iconMap: Record = { export function AgentProfileSettings() { const settings = useSettingsStore((state) => state.settings); const selectedProfileId = settings.selectedAgentProfile || 'auto'; + const [showPhaseConfig, setShowPhaseConfig] = useState(selectedProfileId === 'auto'); + + // Get current phase config from settings or defaults + const currentPhaseModels: PhaseModelConfig = settings.customPhaseModels || DEFAULT_PHASE_MODELS; + const currentPhaseThinking: PhaseThinkingConfig = settings.customPhaseThinking || DEFAULT_PHASE_THINKING; const handleSelectProfile = async (profileId: string) => { - await saveSettings({ selectedAgentProfile: profileId }); + const success = await saveSettings({ selectedAgentProfile: profileId }); + if (!success) { + // Log error for debugging - in future could show user toast notification + console.error('Failed to save agent profile selection'); + return; + } + // Auto-expand phase config when Auto profile is selected + if (profileId === 'auto') { + setShowPhaseConfig(true); + } + }; + + const handlePhaseModelChange = async (phase: keyof PhaseModelConfig, value: ModelTypeShort) => { + const newPhaseModels = { ...currentPhaseModels, [phase]: value }; + await saveSettings({ customPhaseModels: newPhaseModels }); + }; + + const handlePhaseThinkingChange = async (phase: keyof PhaseThinkingConfig, value: ThinkingLevel) => { + const newPhaseThinking = { ...currentPhaseThinking, [phase]: value }; + await saveSettings({ customPhaseThinking: newPhaseThinking }); + }; + + const handleResetToDefaults = async () => { + await saveSettings({ + customPhaseModels: DEFAULT_PHASE_MODELS, + customPhaseThinking: DEFAULT_PHASE_THINKING + }); }; /** @@ -44,6 +98,18 @@ export function AgentProfileSettings() { return level?.label || thinkingValue; }; + /** + * Check if current config differs from defaults + */ + const hasCustomConfig = (): boolean => { + const phases: Array = ['spec', 'planning', 'coding', 'qa']; + return phases.some( + phase => + currentPhaseModels[phase] !== DEFAULT_PHASE_MODELS[phase] || + currentPhaseThinking[phase] !== DEFAULT_PHASE_THINKING[phase] + ); + }; + /** * Render a single profile card */ @@ -126,6 +192,112 @@ export function AgentProfileSettings() {
{DEFAULT_AGENT_PROFILES.map(renderProfileCard)}
+ + {/* Phase Configuration (only for Auto profile) */} + {selectedProfileId === 'auto' && ( +
+ {/* Header - Collapsible */} + + + {/* Phase Configuration Content */} + {showPhaseConfig && ( +
+ {/* Reset button */} + {hasCustomConfig() && ( +
+ +
+ )} + + {/* Phase Configuration Grid */} +
+ {(Object.keys(PHASE_LABELS) as Array).map((phase) => ( +
+
+ + + {PHASE_LABELS[phase].description} + +
+
+ {/* Model Select */} +
+ + +
+ {/* Thinking Level Select */} +
+ + +
+
+
+ ))} +
+ + {/* Info note */} +

+ These settings will be used as defaults when creating new tasks with the Auto profile. + You can override them per-task in the task creation wizard. +

+
+ )} +
+ )} ); diff --git a/auto-claude-ui/src/shared/types/settings.ts b/auto-claude-ui/src/shared/types/settings.ts index 0ff41b41..2f06f569 100644 --- a/auto-claude-ui/src/shared/types/settings.ts +++ b/auto-claude-ui/src/shared/types/settings.ts @@ -82,10 +82,15 @@ export interface AppSettings { onboardingCompleted?: boolean; // Selected agent profile for preset model/thinking configurations selectedAgentProfile?: string; + // Custom phase configuration for Auto profile (overrides defaults) + customPhaseModels?: PhaseModelConfig; + customPhaseThinking?: PhaseThinkingConfig; // Changelog preferences changelogFormat?: ChangelogFormat; changelogAudience?: ChangelogAudience; changelogEmojiLevel?: ChangelogEmojiLevel; + // Migration flags (internal use) + _migratedAgentProfileToAuto?: boolean; } // Auto-Claude Source Environment Configuration (for auto-claude repo .env)