diff --git a/.design-system/src/App.tsx b/.design-system/src/App.tsx index 8891d3c9..fba7cc68 100644 --- a/.design-system/src/App.tsx +++ b/.design-system/src/App.tsx @@ -355,6 +355,7 @@ export default function App() { + diff --git a/auto-claude-ui/src/preload/api/agent-api.ts b/auto-claude-ui/src/preload/api/agent-api.ts index 844bec95..55141018 100644 --- a/auto-claude-ui/src/preload/api/agent-api.ts +++ b/auto-claude-ui/src/preload/api/agent-api.ts @@ -48,9 +48,8 @@ export interface AgentAPI { // Roadmap Operations getRoadmap: (projectId: string) => Promise>; saveRoadmap: (projectId: string, roadmap: Roadmap) => Promise; - generateRoadmap: (projectId: string) => void; - refreshRoadmap: (projectId: string) => void; - updateFeatureStatus: ( + generateRoadmap: (projectId: string, enableCompetitorAnalysis?: boolean) => void; + refreshRoadmap: (projectId: string, enableCompetitorAnalysis?: boolean) => void; updateFeatureStatus: ( projectId: string, featureId: string, status: RoadmapFeatureStatus @@ -177,11 +176,10 @@ export const createAgentAPI = (): AgentAPI => ({ saveRoadmap: (projectId: string, roadmap: Roadmap): Promise => ipcRenderer.invoke(IPC_CHANNELS.ROADMAP_SAVE, projectId, roadmap), - generateRoadmap: (projectId: string): void => - ipcRenderer.send(IPC_CHANNELS.ROADMAP_GENERATE, projectId), - - refreshRoadmap: (projectId: string): void => - ipcRenderer.send(IPC_CHANNELS.ROADMAP_REFRESH, projectId), + generateRoadmap: (projectId: string, enableCompetitorAnalysis?: boolean): void => + ipcRenderer.send(IPC_CHANNELS.ROADMAP_GENERATE, projectId, enableCompetitorAnalysis), + refreshRoadmap: (projectId: string, enableCompetitorAnalysis?: boolean): void => + ipcRenderer.send(IPC_CHANNELS.ROADMAP_REFRESH, projectId, enableCompetitorAnalysis), updateFeatureStatus: ( projectId: string, diff --git a/auto-claude-ui/src/renderer/App.tsx b/auto-claude-ui/src/renderer/App.tsx index 535e1375..a4712a44 100644 --- a/auto-claude-ui/src/renderer/App.tsx +++ b/auto-claude-ui/src/renderer/App.tsx @@ -28,6 +28,7 @@ import { Insights } from './components/Insights'; import { GitHubIssues } from './components/GitHubIssues'; import { Changelog } from './components/Changelog'; import { Worktrees } from './components/Worktrees'; +import { AgentProfiles } from './components/AgentProfiles'; import { WelcomeScreen } from './components/WelcomeScreen'; import { RateLimitModal } from './components/RateLimitModal'; import { SDKRateLimitModal } from './components/SDKRateLimitModal'; @@ -326,6 +327,9 @@ export function App() { {activeView === 'worktrees' && selectedProjectId && ( )} + {activeView === 'agent-profiles' && ( + + )} {activeView === 'agent-tools' && (
diff --git a/auto-claude-ui/src/renderer/components/AgentProfiles.tsx b/auto-claude-ui/src/renderer/components/AgentProfiles.tsx new file mode 100644 index 00000000..e47a5dd0 --- /dev/null +++ b/auto-claude-ui/src/renderer/components/AgentProfiles.tsx @@ -0,0 +1,141 @@ +import { Brain, Scale, Zap, Check } from 'lucide-react'; +import { cn } from '../lib/utils'; +import { DEFAULT_AGENT_PROFILES, AVAILABLE_MODELS, THINKING_LEVELS } from '../../shared/constants'; +import { useSettingsStore, saveSettings } from '../stores/settings-store'; +import type { AgentProfile } from '../../shared/types/settings'; + +/** + * Icon mapping for agent profile icons + */ +const iconMap: Record = { + Brain, + Scale, + Zap +}; + +/** + * Agent Profiles view component + * Displays preset agent profiles for quick model/thinking level configuration + */ +export function AgentProfiles() { + const settings = useSettingsStore((state) => state.settings); + const selectedProfileId = settings.selectedAgentProfile || 'balanced'; + + const handleSelectProfile = async (profileId: string) => { + await saveSettings({ selectedAgentProfile: profileId }); + }; + + /** + * Get human-readable model label + */ + const getModelLabel = (modelValue: string): string => { + const model = AVAILABLE_MODELS.find((m) => m.value === modelValue); + return model?.label || modelValue; + }; + + /** + * Get human-readable thinking level label + */ + const getThinkingLabel = (thinkingValue: string): string => { + const level = THINKING_LEVELS.find((l) => l.value === thinkingValue); + return level?.label || thinkingValue; + }; + + /** + * Render a single profile card + */ + const renderProfileCard = (profile: AgentProfile) => { + const isSelected = selectedProfileId === profile.id; + const Icon = iconMap[profile.icon || 'Brain'] || Brain; + + return ( + + ); + }; + + return ( +
+ {/* Header */} +
+
+
+

Agent Profiles

+

+ Select a preset configuration for model and thinking level +

+
+
+
+ + {/* Content */} +
+
+ {/* Description */} +
+

+ Agent profiles provide preset configurations for Claude model and thinking level. + When you create a new task, these settings will be used as defaults. You can always + override them in the task creation wizard. +

+
+ + {/* Profile cards */} +
+ {DEFAULT_AGENT_PROFILES.map(renderProfileCard)} +
+
+
+
+ ); +} diff --git a/auto-claude-ui/src/renderer/components/Sidebar.tsx b/auto-claude-ui/src/renderer/components/Sidebar.tsx index 11311f0a..bbbd008b 100644 --- a/auto-claude-ui/src/renderer/components/Sidebar.tsx +++ b/auto-claude-ui/src/renderer/components/Sidebar.tsx @@ -18,7 +18,8 @@ import { FileText, Sparkles, GitBranch, - HelpCircle + HelpCircle, + UserCog } from 'lucide-react'; import { Button } from './ui/button'; import { ScrollArea } from './ui/scroll-area'; @@ -57,7 +58,7 @@ import { AddProjectModal } from './AddProjectModal'; import { RateLimitIndicator } from './RateLimitIndicator'; import type { Project, AutoBuildVersionInfo } from '../../shared/types'; -export type SidebarView = 'kanban' | 'terminals' | 'roadmap' | 'context' | 'ideation' | 'github-issues' | 'changelog' | 'insights' | 'worktrees' | 'agent-tools'; +export type SidebarView = 'kanban' | 'terminals' | 'roadmap' | 'context' | 'ideation' | 'github-issues' | 'changelog' | 'insights' | 'worktrees' | 'agent-tools' | 'agent-profiles'; interface SidebarProps { onSettingsClick: () => void; @@ -85,7 +86,8 @@ const projectNavItems: NavItem[] = [ const toolsNavItems: NavItem[] = [ { id: 'github-issues', label: 'GitHub Issues', icon: Github, shortcut: 'G' }, - { id: 'worktrees', label: 'Worktrees', icon: GitBranch, shortcut: 'W' } + { id: 'worktrees', label: 'Worktrees', icon: GitBranch, shortcut: 'W' }, + { id: 'agent-profiles', label: 'Agent Profiles', icon: UserCog, shortcut: 'P' } ]; export function Sidebar({ diff --git a/auto-claude-ui/src/renderer/components/TaskCreationWizard.tsx b/auto-claude-ui/src/renderer/components/TaskCreationWizard.tsx index ce44080e..15711c3e 100644 --- a/auto-claude-ui/src/renderer/components/TaskCreationWizard.tsx +++ b/auto-claude-ui/src/renderer/components/TaskCreationWizard.tsx @@ -30,15 +30,19 @@ import { } from './ImageUpload'; import { createTask, saveDraft, loadDraft, clearDraft, isDraftEmpty } from '../stores/task-store'; import { cn } from '../lib/utils'; -import type { TaskCategory, TaskPriority, TaskComplexity, TaskImpact, TaskMetadata, ImageAttachment, TaskDraft } from '../../shared/types'; +import type { TaskCategory, TaskPriority, TaskComplexity, TaskImpact, TaskMetadata, ImageAttachment, TaskDraft, ModelType, ThinkingLevel } from '../../shared/types'; import { TASK_CATEGORY_LABELS, TASK_PRIORITY_LABELS, TASK_COMPLEXITY_LABELS, TASK_IMPACT_LABELS, MAX_IMAGES_PER_TASK, - ALLOWED_IMAGE_TYPES_DISPLAY + ALLOWED_IMAGE_TYPES_DISPLAY, + DEFAULT_AGENT_PROFILES, + AVAILABLE_MODELS, + THINKING_LEVELS } from '../../shared/constants'; +import { useSettingsStore } from '../stores/settings-store'; interface TaskCreationWizardProps { projectId: string; @@ -51,6 +55,12 @@ export function TaskCreationWizard({ open, onOpenChange }: TaskCreationWizardProps) { + // Get selected agent profile from settings + const { settings } = useSettingsStore(); + const selectedProfile = DEFAULT_AGENT_PROFILES.find( + p => p.id === settings.selectedAgentProfile + ) || DEFAULT_AGENT_PROFILES.find(p => p.id === 'balanced')!; + const [title, setTitle] = useState(''); const [description, setDescription] = useState(''); const [isCreating, setIsCreating] = useState(false); @@ -64,6 +74,10 @@ export function TaskCreationWizard({ const [complexity, setComplexity] = useState(''); const [impact, setImpact] = useState(''); + // Model configuration (initialized from selected agent profile) + const [model, setModel] = useState(selectedProfile.model); + const [thinkingLevel, setThinkingLevel] = useState(selectedProfile.thinkingLevel); + // Image attachments const [images, setImages] = useState([]); @@ -77,7 +91,7 @@ export function TaskCreationWizard({ // Ref for the textarea to handle paste events const descriptionRef = useRef(null); - // Load draft when dialog opens + // Load draft when dialog opens, or initialize from selected profile useEffect(() => { if (open && projectId) { const draft = loadDraft(projectId); @@ -88,6 +102,9 @@ export function TaskCreationWizard({ setPriority(draft.priority); setComplexity(draft.complexity); setImpact(draft.impact); + // Load model/thinkingLevel from draft if present, otherwise use profile defaults + setModel(draft.model || selectedProfile.model); + setThinkingLevel(draft.thinkingLevel || selectedProfile.thinkingLevel); setImages(draft.images); setRequireReviewBeforeCoding(draft.requireReviewBeforeCoding ?? false); setIsDraftRestored(true); @@ -99,9 +116,13 @@ export function TaskCreationWizard({ if (draft.images.length > 0) { setShowImages(true); } + } else { + // No draft - initialize model/thinkingLevel from selected profile + setModel(selectedProfile.model); + setThinkingLevel(selectedProfile.thinkingLevel); } } - }, [open, projectId]); + }, [open, projectId, selectedProfile.model, selectedProfile.thinkingLevel]); /** * Get current form state as a draft @@ -114,10 +135,12 @@ export function TaskCreationWizard({ priority, complexity, impact, + model, + thinkingLevel, images, requireReviewBeforeCoding, savedAt: new Date() - }), [projectId, title, description, category, priority, complexity, impact, images, requireReviewBeforeCoding]); + }), [projectId, title, description, category, priority, complexity, impact, model, thinkingLevel, images, requireReviewBeforeCoding]); /** * Handle paste event for screenshot support @@ -218,6 +241,8 @@ export function TaskCreationWizard({ if (priority) metadata.priority = priority; if (complexity) metadata.complexity = complexity; if (impact) metadata.impact = impact; + if (model) metadata.model = model; + if (thinkingLevel) metadata.thinkingLevel = thinkingLevel; if (images.length > 0) metadata.attachedImages = images; if (requireReviewBeforeCoding) metadata.requireReviewBeforeCoding = true; @@ -246,6 +271,9 @@ export function TaskCreationWizard({ setPriority(''); setComplexity(''); setImpact(''); + // Reset model/thinkingLevel to selected profile defaults + setModel(selectedProfile.model); + setThinkingLevel(selectedProfile.thinkingLevel); setImages([]); setRequireReviewBeforeCoding(false); setError(null); @@ -351,6 +379,58 @@ export function TaskCreationWizard({

+ {/* Model Selection */} +
+ + +

+ The Claude model to use for this task. Defaults to your selected agent profile. +

+
+ + {/* Thinking Level Selection */} +
+ + +

+ Extended thinking depth for complex reasoning. Higher levels use more tokens but provide deeper analysis. +

+
+ {/* Paste Success Indicator */} {pasteSuccess && (
diff --git a/auto-claude-ui/src/shared/constants.ts b/auto-claude-ui/src/shared/constants.ts index b5e5048b..1dc371b4 100644 --- a/auto-claude-ui/src/shared/constants.ts +++ b/auto-claude-ui/src/shared/constants.ts @@ -2,6 +2,8 @@ * Shared constants for Auto Claude UI */ +import type { AgentProfile } from './types/settings'; + // Task status columns in Kanban board order export const TASK_STATUS_COLUMNS = [ 'backlog', @@ -99,7 +101,9 @@ export const DEFAULT_APP_SETTINGS = { }, // Global API keys (used as defaults for all projects) globalClaudeOAuthToken: undefined as string | undefined, - globalOpenAIApiKey: undefined as string | undefined + globalOpenAIApiKey: undefined as string | undefined, + // Selected agent profile - defaults to 'balanced' for good speed/quality balance + selectedAgentProfile: 'balanced' }; // Default project settings @@ -421,6 +425,43 @@ export const AVAILABLE_MODELS = [ { value: 'haiku', label: 'Claude Haiku 3.5' } ] as const; +// Thinking levels for Claude model (budget token allocation) +export const THINKING_LEVELS = [ + { value: 'none', label: 'None', description: 'No extended thinking' }, + { value: 'low', label: 'Low', description: 'Brief consideration' }, + { value: 'medium', label: 'Medium', description: 'Moderate analysis' }, + { value: 'high', label: 'High', description: 'Deep thinking' }, + { value: 'ultrathink', label: 'Ultra Think', description: 'Maximum reasoning depth' } +] as const; + +// Default agent profiles for preset model/thinking configurations +export const DEFAULT_AGENT_PROFILES: AgentProfile[] = [ + { + id: 'complex', + name: 'Complex Tasks', + description: 'For intricate, multi-step implementations requiring deep analysis', + model: 'opus', + thinkingLevel: 'ultrathink', + icon: 'Brain' + }, + { + id: 'balanced', + name: 'Balanced', + description: 'Good balance of speed and quality for most tasks', + model: 'sonnet', + thinkingLevel: 'medium', + icon: 'Scale' + }, + { + id: 'quick', + name: 'Quick Edits', + description: 'Fast iterations for simple changes and quick fixes', + model: 'haiku', + thinkingLevel: 'low', + icon: 'Zap' + } +]; + // Memory backends export const MEMORY_BACKENDS = [ { value: 'file', label: 'File-based (default)' }, diff --git a/auto-claude-ui/src/shared/types/ipc.ts b/auto-claude-ui/src/shared/types/ipc.ts index 099648bb..a4e961ce 100644 --- a/auto-claude-ui/src/shared/types/ipc.ts +++ b/auto-claude-ui/src/shared/types/ipc.ts @@ -221,9 +221,8 @@ export interface ElectronAPI { // Roadmap operations getRoadmap: (projectId: string) => Promise>; saveRoadmap: (projectId: string, roadmap: Roadmap) => Promise; - generateRoadmap: (projectId: string) => void; - refreshRoadmap: (projectId: string) => void; - updateFeatureStatus: ( + generateRoadmap: (projectId: string, enableCompetitorAnalysis?: boolean) => void; + refreshRoadmap: (projectId: string, enableCompetitorAnalysis?: boolean) => void; updateFeatureStatus: ( projectId: string, featureId: string, status: RoadmapFeatureStatus diff --git a/auto-claude-ui/src/shared/types/settings.ts b/auto-claude-ui/src/shared/types/settings.ts index d52d1a3b..2cd64642 100644 --- a/auto-claude-ui/src/shared/types/settings.ts +++ b/auto-claude-ui/src/shared/types/settings.ts @@ -4,6 +4,19 @@ import type { NotificationSettings } from './project'; +// Thinking level for Claude model (budget token allocation) +export type ThinkingLevel = 'none' | 'low' | 'medium' | 'high' | 'ultrathink'; + +// Agent profile for preset model/thinking configurations +export interface AgentProfile { + id: string; + name: string; + description: string; + model: 'haiku' | 'sonnet' | 'opus'; + thinkingLevel: ThinkingLevel; + icon?: string; // Lucide icon name +} + export interface AppSettings { theme: 'light' | 'dark' | 'system'; defaultModel: string; @@ -18,6 +31,8 @@ export interface AppSettings { globalOpenAIApiKey?: string; // Onboarding wizard completion state onboardingCompleted?: boolean; + // Selected agent profile for preset model/thinking configurations + selectedAgentProfile?: string; } // Auto-Claude Source Environment Configuration (for auto-claude repo .env) diff --git a/auto-claude-ui/src/shared/types/task.ts b/auto-claude-ui/src/shared/types/task.ts index f39d4d11..a220ac6e 100644 --- a/auto-claude-ui/src/shared/types/task.ts +++ b/auto-claude-ui/src/shared/types/task.ts @@ -2,6 +2,8 @@ * Task-related types */ +import type { ThinkingLevel } from './settings'; + export type TaskStatus = 'backlog' | 'in_progress' | 'ai_review' | 'human_review' | 'done'; // Reason why a task is in human_review status @@ -125,6 +127,8 @@ export interface TaskDraft { priority: TaskPriority | ''; complexity: TaskComplexity | ''; impact: TaskImpact | ''; + model: ModelType | ''; + thinkingLevel: ThinkingLevel | ''; images: ImageAttachment[]; requireReviewBeforeCoding?: boolean; savedAt: Date; @@ -134,6 +138,9 @@ export interface TaskDraft { export type TaskComplexity = 'trivial' | 'small' | 'medium' | 'large' | 'complex'; export type TaskImpact = 'low' | 'medium' | 'high' | 'critical'; export type TaskPriority = 'low' | 'medium' | 'high' | 'urgent'; +// Re-export ThinkingLevel (defined in settings.ts) for convenience +export type { ThinkingLevel }; +export type ModelType = 'haiku' | 'sonnet' | 'opus'; export type TaskCategory = | 'feature' | 'bug_fix' @@ -188,6 +195,10 @@ export interface TaskMetadata { // Review settings requireReviewBeforeCoding?: boolean; // Require human review of spec/plan before coding starts + // Agent configuration (from agent profile or manual selection) + model?: ModelType; // Claude model to use (haiku, sonnet, opus) + thinkingLevel?: ThinkingLevel; // Thinking budget level (none, low, medium, high, ultrathink) + // Archive status archivedAt?: string; // ISO date when task was archived archivedInVersion?: string; // Version in which task was archived (from changelog)