mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-01 08:13:37 +00:00
Merge pull request #322 from casiusss/feat/customizable-prompts
feat: customizable prompts
This commit is contained in:
@@ -20,6 +20,7 @@ import { KeyboardShortcutsSection } from './settings-view/keyboard-shortcuts/key
|
||||
import { FeatureDefaultsSection } from './settings-view/feature-defaults/feature-defaults-section';
|
||||
import { DangerZoneSection } from './settings-view/danger-zone/danger-zone-section';
|
||||
import { MCPServersSection } from './settings-view/mcp-servers';
|
||||
import { PromptCustomizationSection } from './settings-view/prompts';
|
||||
import type { Project as SettingsProject, Theme } from './settings-view/shared/types';
|
||||
import type { Project as ElectronProject } from '@/lib/electron';
|
||||
|
||||
@@ -54,6 +55,8 @@ export function SettingsView() {
|
||||
setAutoLoadClaudeMd,
|
||||
enableSandboxMode,
|
||||
setEnableSandboxMode,
|
||||
promptCustomization,
|
||||
setPromptCustomization,
|
||||
} = useAppStore();
|
||||
|
||||
const claudeAuthStatus = useSetupStore((state) => state.claudeAuthStatus);
|
||||
@@ -127,6 +130,13 @@ export function SettingsView() {
|
||||
);
|
||||
case 'mcp-servers':
|
||||
return <MCPServersSection />;
|
||||
case 'prompts':
|
||||
return (
|
||||
<PromptCustomizationSection
|
||||
promptCustomization={promptCustomization}
|
||||
onPromptCustomizationChange={setPromptCustomization}
|
||||
/>
|
||||
);
|
||||
case 'ai-enhancement':
|
||||
return <AIEnhancementSection />;
|
||||
case 'appearance':
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
Trash2,
|
||||
Sparkles,
|
||||
Plug,
|
||||
MessageSquareText,
|
||||
} from 'lucide-react';
|
||||
import type { SettingsViewId } from '../hooks/use-settings-view';
|
||||
|
||||
@@ -24,6 +25,7 @@ export const NAV_ITEMS: NavigationItem[] = [
|
||||
{ id: 'api-keys', label: 'API Keys', icon: Key },
|
||||
{ id: 'claude', label: 'Claude', icon: Terminal },
|
||||
{ id: 'mcp-servers', label: 'MCP Servers', icon: Plug },
|
||||
{ id: 'prompts', label: 'Prompt Customization', icon: MessageSquareText },
|
||||
{ id: 'ai-enhancement', label: 'AI Enhancement', icon: Sparkles },
|
||||
{ id: 'appearance', label: 'Appearance', icon: Palette },
|
||||
{ id: 'terminal', label: 'Terminal', icon: SquareTerminal },
|
||||
|
||||
@@ -4,6 +4,7 @@ export type SettingsViewId =
|
||||
| 'api-keys'
|
||||
| 'claude'
|
||||
| 'mcp-servers'
|
||||
| 'prompts'
|
||||
| 'ai-enhancement'
|
||||
| 'appearance'
|
||||
| 'terminal'
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export { PromptCustomizationSection } from './prompt-customization-section';
|
||||
@@ -0,0 +1,440 @@
|
||||
import { useState } from 'react';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Textarea } from '@/components/ui/textarea';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Switch } from '@/components/ui/switch';
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
import {
|
||||
MessageSquareText,
|
||||
Bot,
|
||||
KanbanSquare,
|
||||
Sparkles,
|
||||
RotateCcw,
|
||||
Info,
|
||||
AlertTriangle,
|
||||
} from 'lucide-react';
|
||||
import { cn } from '@/lib/utils';
|
||||
import type { PromptCustomization, CustomPrompt } from '@automaker/types';
|
||||
import {
|
||||
DEFAULT_AUTO_MODE_PROMPTS,
|
||||
DEFAULT_AGENT_PROMPTS,
|
||||
DEFAULT_BACKLOG_PLAN_PROMPTS,
|
||||
DEFAULT_ENHANCEMENT_PROMPTS,
|
||||
} from '@automaker/prompts';
|
||||
|
||||
interface PromptCustomizationSectionProps {
|
||||
promptCustomization?: PromptCustomization;
|
||||
onPromptCustomizationChange: (customization: PromptCustomization) => void;
|
||||
}
|
||||
|
||||
interface PromptFieldProps {
|
||||
label: string;
|
||||
description: string;
|
||||
defaultValue: string;
|
||||
customValue?: CustomPrompt;
|
||||
onCustomValueChange: (value: CustomPrompt | undefined) => void;
|
||||
critical?: boolean; // Whether this prompt requires strict output format
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate dynamic minimum height based on content length
|
||||
* Ensures long prompts have adequate space
|
||||
*/
|
||||
function calculateMinHeight(text: string): string {
|
||||
const lines = text.split('\n').length;
|
||||
const estimatedLines = Math.max(lines, Math.ceil(text.length / 80));
|
||||
|
||||
// Min 120px, scales up for longer content, max 600px
|
||||
const minHeight = Math.min(Math.max(120, estimatedLines * 20), 600);
|
||||
return `${minHeight}px`;
|
||||
}
|
||||
|
||||
/**
|
||||
* PromptField Component
|
||||
*
|
||||
* Shows a prompt with a toggle to switch between default and custom mode.
|
||||
* - Toggle OFF: Shows default prompt in read-only mode, custom value is preserved but not used
|
||||
* - Toggle ON: Allows editing, custom value is used instead of default
|
||||
*
|
||||
* IMPORTANT: Custom value is ALWAYS preserved, even when toggle is OFF.
|
||||
* This prevents users from losing their work when temporarily switching to default.
|
||||
*/
|
||||
function PromptField({
|
||||
label,
|
||||
description,
|
||||
defaultValue,
|
||||
customValue,
|
||||
onCustomValueChange,
|
||||
critical = false,
|
||||
}: PromptFieldProps) {
|
||||
const isEnabled = customValue?.enabled ?? false;
|
||||
const displayValue = isEnabled ? (customValue?.value ?? defaultValue) : defaultValue;
|
||||
const minHeight = calculateMinHeight(displayValue);
|
||||
|
||||
const handleToggle = (enabled: boolean) => {
|
||||
// When toggling, preserve the existing custom value if it exists,
|
||||
// otherwise initialize with the default value.
|
||||
const value = customValue?.value ?? defaultValue;
|
||||
onCustomValueChange({ value, enabled });
|
||||
};
|
||||
|
||||
const handleTextChange = (newValue: string) => {
|
||||
// Only allow editing when enabled
|
||||
if (isEnabled) {
|
||||
onCustomValueChange({ value: newValue, enabled: true });
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-2">
|
||||
{critical && isEnabled && (
|
||||
<div className="flex items-start gap-2 p-3 rounded-lg bg-amber-500/10 border border-amber-500/20">
|
||||
<AlertTriangle className="w-4 h-4 text-amber-500 mt-0.5 flex-shrink-0" />
|
||||
<div className="flex-1">
|
||||
<p className="text-xs font-medium text-amber-500">Critical Prompt</p>
|
||||
<p className="text-xs text-muted-foreground mt-1">
|
||||
This prompt requires a specific output format. Changing it incorrectly may break
|
||||
functionality. Only modify if you understand the expected structure.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex items-center justify-between">
|
||||
<Label htmlFor={label} className="text-sm font-medium">
|
||||
{label}
|
||||
</Label>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-xs text-muted-foreground">{isEnabled ? 'Custom' : 'Default'}</span>
|
||||
<Switch
|
||||
checked={isEnabled}
|
||||
onCheckedChange={handleToggle}
|
||||
className="data-[state=checked]:bg-brand-500"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<Textarea
|
||||
id={label}
|
||||
value={displayValue}
|
||||
onChange={(e) => handleTextChange(e.target.value)}
|
||||
readOnly={!isEnabled}
|
||||
style={{ minHeight }}
|
||||
className={cn(
|
||||
'font-mono text-xs resize-y',
|
||||
!isEnabled && 'cursor-not-allowed bg-muted/50 text-muted-foreground'
|
||||
)}
|
||||
/>
|
||||
<p className="text-xs text-muted-foreground">{description}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* PromptCustomizationSection Component
|
||||
*
|
||||
* Allows users to customize AI prompts for different parts of the application:
|
||||
* - Auto Mode (feature implementation)
|
||||
* - Agent Runner (interactive chat)
|
||||
* - Backlog Plan (Kanban planning)
|
||||
* - Enhancement (feature description improvement)
|
||||
*/
|
||||
export function PromptCustomizationSection({
|
||||
promptCustomization = {},
|
||||
onPromptCustomizationChange,
|
||||
}: PromptCustomizationSectionProps) {
|
||||
const [activeTab, setActiveTab] = useState('auto-mode');
|
||||
|
||||
const updatePrompt = <T extends keyof PromptCustomization>(
|
||||
category: T,
|
||||
field: keyof NonNullable<PromptCustomization[T]>,
|
||||
value: CustomPrompt | undefined
|
||||
) => {
|
||||
const updated = {
|
||||
...promptCustomization,
|
||||
[category]: {
|
||||
...promptCustomization[category],
|
||||
[field]: value,
|
||||
},
|
||||
};
|
||||
onPromptCustomizationChange(updated);
|
||||
};
|
||||
|
||||
const resetToDefaults = (category: keyof PromptCustomization) => {
|
||||
const updated = {
|
||||
...promptCustomization,
|
||||
[category]: {},
|
||||
};
|
||||
onPromptCustomizationChange(updated);
|
||||
};
|
||||
|
||||
const resetAllToDefaults = () => {
|
||||
onPromptCustomizationChange({});
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'rounded-2xl overflow-hidden',
|
||||
'border border-border/50',
|
||||
'bg-gradient-to-br from-card/90 via-card/70 to-card/80 backdrop-blur-xl',
|
||||
'shadow-sm shadow-black/5'
|
||||
)}
|
||||
data-testid="prompt-customization-section"
|
||||
>
|
||||
{/* Header */}
|
||||
<div className="p-6 border-b border-border/50 bg-gradient-to-r from-transparent via-accent/5 to-transparent">
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-9 h-9 rounded-xl bg-gradient-to-br from-brand-500/20 to-brand-600/10 flex items-center justify-center border border-brand-500/20">
|
||||
<MessageSquareText className="w-5 h-5 text-brand-500" />
|
||||
</div>
|
||||
<h2 className="text-lg font-semibold text-foreground tracking-tight">
|
||||
Prompt Customization
|
||||
</h2>
|
||||
</div>
|
||||
<Button variant="outline" size="sm" onClick={resetAllToDefaults} className="gap-2">
|
||||
<RotateCcw className="w-4 h-4" />
|
||||
Reset All to Defaults
|
||||
</Button>
|
||||
</div>
|
||||
<p className="text-sm text-muted-foreground/80 ml-12">
|
||||
Customize AI prompts for Auto Mode, Agent Runner, and other features.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Info Banner */}
|
||||
<div className="px-6 pt-6">
|
||||
<div className="flex items-start gap-3 p-4 rounded-xl bg-blue-500/10 border border-blue-500/20">
|
||||
<Info className="w-5 h-5 text-blue-500 mt-0.5 flex-shrink-0" />
|
||||
<div className="space-y-1">
|
||||
<p className="text-sm text-foreground font-medium">How to Customize Prompts</p>
|
||||
<p className="text-xs text-muted-foreground/80 leading-relaxed">
|
||||
Toggle the switch to enable custom mode and edit the prompt. When disabled, the
|
||||
default built-in prompt is used. You can use the default as a starting point by
|
||||
enabling the toggle.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Tabs */}
|
||||
<div className="p-6">
|
||||
<Tabs value={activeTab} onValueChange={setActiveTab}>
|
||||
<TabsList className="grid grid-cols-4 w-full">
|
||||
<TabsTrigger value="auto-mode" className="gap-2">
|
||||
<Bot className="w-4 h-4" />
|
||||
Auto Mode
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="agent" className="gap-2">
|
||||
<MessageSquareText className="w-4 h-4" />
|
||||
Agent
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="backlog-plan" className="gap-2">
|
||||
<KanbanSquare className="w-4 h-4" />
|
||||
Backlog Plan
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="enhancement" className="gap-2">
|
||||
<Sparkles className="w-4 h-4" />
|
||||
Enhancement
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
{/* Auto Mode Tab */}
|
||||
<TabsContent value="auto-mode" className="space-y-6 mt-6">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<h3 className="text-sm font-medium text-foreground">Auto Mode Prompts</h3>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => resetToDefaults('autoMode')}
|
||||
className="gap-2"
|
||||
>
|
||||
<RotateCcw className="w-3 h-3" />
|
||||
Reset Section
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Info Banner for Auto Mode */}
|
||||
<div className="flex items-start gap-3 p-4 rounded-xl bg-blue-500/10 border border-blue-500/20">
|
||||
<Info className="w-5 h-5 text-blue-500 mt-0.5 flex-shrink-0" />
|
||||
<div className="space-y-1">
|
||||
<p className="text-sm text-foreground font-medium">Planning Mode Markers</p>
|
||||
<p className="text-xs text-muted-foreground/80 leading-relaxed">
|
||||
Planning prompts use special markers like{' '}
|
||||
<code className="px-1 py-0.5 rounded bg-muted text-xs">[PLAN_GENERATED]</code> and{' '}
|
||||
<code className="px-1 py-0.5 rounded bg-muted text-xs">[SPEC_GENERATED]</code> to
|
||||
control the Auto Mode workflow. These markers must be preserved for proper
|
||||
functionality.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<PromptField
|
||||
label="Planning: Lite Mode"
|
||||
description="Quick planning outline without approval requirement"
|
||||
defaultValue={DEFAULT_AUTO_MODE_PROMPTS.planningLite}
|
||||
customValue={promptCustomization?.autoMode?.planningLite}
|
||||
onCustomValueChange={(value) => updatePrompt('autoMode', 'planningLite', value)}
|
||||
critical={true}
|
||||
/>
|
||||
|
||||
<PromptField
|
||||
label="Planning: Lite with Approval"
|
||||
description="Planning outline that waits for user approval"
|
||||
defaultValue={DEFAULT_AUTO_MODE_PROMPTS.planningLiteWithApproval}
|
||||
customValue={promptCustomization?.autoMode?.planningLiteWithApproval}
|
||||
onCustomValueChange={(value) =>
|
||||
updatePrompt('autoMode', 'planningLiteWithApproval', value)
|
||||
}
|
||||
critical={true}
|
||||
/>
|
||||
|
||||
<PromptField
|
||||
label="Planning: Spec Mode"
|
||||
description="Detailed specification with task breakdown"
|
||||
defaultValue={DEFAULT_AUTO_MODE_PROMPTS.planningSpec}
|
||||
customValue={promptCustomization?.autoMode?.planningSpec}
|
||||
onCustomValueChange={(value) => updatePrompt('autoMode', 'planningSpec', value)}
|
||||
critical={true}
|
||||
/>
|
||||
|
||||
<PromptField
|
||||
label="Planning: Full SDD Mode"
|
||||
description="Comprehensive Software Design Document with phased implementation"
|
||||
defaultValue={DEFAULT_AUTO_MODE_PROMPTS.planningFull}
|
||||
customValue={promptCustomization?.autoMode?.planningFull}
|
||||
onCustomValueChange={(value) => updatePrompt('autoMode', 'planningFull', value)}
|
||||
critical={true}
|
||||
/>
|
||||
</div>
|
||||
</TabsContent>
|
||||
|
||||
{/* Agent Tab */}
|
||||
<TabsContent value="agent" className="space-y-6 mt-6">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<h3 className="text-sm font-medium text-foreground">Agent Runner Prompts</h3>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => resetToDefaults('agent')}
|
||||
className="gap-2"
|
||||
>
|
||||
<RotateCcw className="w-3 h-3" />
|
||||
Reset Section
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<PromptField
|
||||
label="System Prompt"
|
||||
description="Defines the AI's role and behavior in interactive chat sessions"
|
||||
defaultValue={DEFAULT_AGENT_PROMPTS.systemPrompt}
|
||||
customValue={promptCustomization?.agent?.systemPrompt}
|
||||
onCustomValueChange={(value) => updatePrompt('agent', 'systemPrompt', value)}
|
||||
/>
|
||||
</div>
|
||||
</TabsContent>
|
||||
|
||||
{/* Backlog Plan Tab */}
|
||||
<TabsContent value="backlog-plan" className="space-y-6 mt-6">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<h3 className="text-sm font-medium text-foreground">Backlog Planning Prompts</h3>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => resetToDefaults('backlogPlan')}
|
||||
className="gap-2"
|
||||
>
|
||||
<RotateCcw className="w-3 h-3" />
|
||||
Reset Section
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Critical Warning for Backlog Plan */}
|
||||
<div className="flex items-start gap-3 p-4 rounded-xl bg-amber-500/10 border border-amber-500/20">
|
||||
<AlertTriangle className="w-5 h-5 text-amber-500 mt-0.5 flex-shrink-0" />
|
||||
<div className="space-y-1">
|
||||
<p className="text-sm text-foreground font-medium">Warning: Critical Prompts</p>
|
||||
<p className="text-xs text-muted-foreground/80 leading-relaxed">
|
||||
Backlog plan prompts require a strict JSON output format. Modifying these prompts
|
||||
incorrectly can break the backlog planning feature and potentially corrupt your
|
||||
feature data. Only customize if you fully understand the expected output
|
||||
structure.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<PromptField
|
||||
label="System Prompt"
|
||||
description="Defines how the AI modifies the feature backlog (Plan button on Kanban board)"
|
||||
defaultValue={DEFAULT_BACKLOG_PLAN_PROMPTS.systemPrompt}
|
||||
customValue={promptCustomization?.backlogPlan?.systemPrompt}
|
||||
onCustomValueChange={(value) => updatePrompt('backlogPlan', 'systemPrompt', value)}
|
||||
critical={true}
|
||||
/>
|
||||
</div>
|
||||
</TabsContent>
|
||||
|
||||
{/* Enhancement Tab */}
|
||||
<TabsContent value="enhancement" className="space-y-6 mt-6">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<h3 className="text-sm font-medium text-foreground">Enhancement Prompts</h3>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => resetToDefaults('enhancement')}
|
||||
className="gap-2"
|
||||
>
|
||||
<RotateCcw className="w-3 h-3" />
|
||||
Reset Section
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<PromptField
|
||||
label="Improve Mode"
|
||||
description="Transform vague requests into clear, actionable tasks"
|
||||
defaultValue={DEFAULT_ENHANCEMENT_PROMPTS.improveSystemPrompt}
|
||||
customValue={promptCustomization?.enhancement?.improveSystemPrompt}
|
||||
onCustomValueChange={(value) =>
|
||||
updatePrompt('enhancement', 'improveSystemPrompt', value)
|
||||
}
|
||||
/>
|
||||
|
||||
<PromptField
|
||||
label="Technical Mode"
|
||||
description="Add implementation details and technical specifications"
|
||||
defaultValue={DEFAULT_ENHANCEMENT_PROMPTS.technicalSystemPrompt}
|
||||
customValue={promptCustomization?.enhancement?.technicalSystemPrompt}
|
||||
onCustomValueChange={(value) =>
|
||||
updatePrompt('enhancement', 'technicalSystemPrompt', value)
|
||||
}
|
||||
/>
|
||||
|
||||
<PromptField
|
||||
label="Simplify Mode"
|
||||
description="Make verbose descriptions concise and focused"
|
||||
defaultValue={DEFAULT_ENHANCEMENT_PROMPTS.simplifySystemPrompt}
|
||||
customValue={promptCustomization?.enhancement?.simplifySystemPrompt}
|
||||
onCustomValueChange={(value) =>
|
||||
updatePrompt('enhancement', 'simplifySystemPrompt', value)
|
||||
}
|
||||
/>
|
||||
|
||||
<PromptField
|
||||
label="Acceptance Criteria Mode"
|
||||
description="Add testable acceptance criteria to descriptions"
|
||||
defaultValue={DEFAULT_ENHANCEMENT_PROMPTS.acceptanceSystemPrompt}
|
||||
customValue={promptCustomization?.enhancement?.acceptanceSystemPrompt}
|
||||
onCustomValueChange={(value) =>
|
||||
updatePrompt('enhancement', 'acceptanceSystemPrompt', value)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -231,6 +231,7 @@ export async function syncSettingsToServer(): Promise<boolean> {
|
||||
mcpServers: state.mcpServers,
|
||||
mcpAutoApproveTools: state.mcpAutoApproveTools,
|
||||
mcpUnrestrictedTools: state.mcpUnrestrictedTools,
|
||||
promptCustomization: state.promptCustomization,
|
||||
projects: state.projects,
|
||||
trashedProjects: state.trashedProjects,
|
||||
projectHistory: state.projectHistory,
|
||||
|
||||
@@ -11,6 +11,7 @@ import type {
|
||||
FeatureStatusWithPipeline,
|
||||
PipelineConfig,
|
||||
PipelineStep,
|
||||
PromptCustomization,
|
||||
} from '@automaker/types';
|
||||
|
||||
// Re-export ThemeMode for convenience
|
||||
@@ -492,6 +493,9 @@ export interface AppState {
|
||||
mcpAutoApproveTools: boolean; // Auto-approve MCP tool calls without permission prompts
|
||||
mcpUnrestrictedTools: boolean; // Allow unrestricted tools when MCP servers are enabled
|
||||
|
||||
// Prompt Customization
|
||||
promptCustomization: PromptCustomization; // Custom prompts for Auto Mode, Agent, Backlog Plan, Enhancement
|
||||
|
||||
// Project Analysis
|
||||
projectAnalysis: ProjectAnalysis | null;
|
||||
isAnalyzing: boolean;
|
||||
@@ -774,6 +778,9 @@ export interface AppActions {
|
||||
setMcpAutoApproveTools: (enabled: boolean) => Promise<void>;
|
||||
setMcpUnrestrictedTools: (enabled: boolean) => Promise<void>;
|
||||
|
||||
// Prompt Customization actions
|
||||
setPromptCustomization: (customization: PromptCustomization) => Promise<void>;
|
||||
|
||||
// AI Profile actions
|
||||
addAIProfile: (profile: Omit<AIProfile, 'id'>) => void;
|
||||
updateAIProfile: (id: string, updates: Partial<AIProfile>) => void;
|
||||
@@ -972,6 +979,7 @@ const initialState: AppState = {
|
||||
mcpServers: [], // No MCP servers configured by default
|
||||
mcpAutoApproveTools: true, // Default to enabled - bypass permission prompts for MCP tools
|
||||
mcpUnrestrictedTools: true, // Default to enabled - don't filter allowedTools when MCP enabled
|
||||
promptCustomization: {}, // Empty by default - all prompts use built-in defaults
|
||||
aiProfiles: DEFAULT_AI_PROFILES,
|
||||
projectAnalysis: null,
|
||||
isAnalyzing: false,
|
||||
@@ -1628,6 +1636,14 @@ export const useAppStore = create<AppState & AppActions>()(
|
||||
await syncSettingsToServer();
|
||||
},
|
||||
|
||||
// Prompt Customization actions
|
||||
setPromptCustomization: async (customization) => {
|
||||
set({ promptCustomization: customization });
|
||||
// Sync to server settings file
|
||||
const { syncSettingsToServer } = await import('@/hooks/use-settings-migration');
|
||||
await syncSettingsToServer();
|
||||
},
|
||||
|
||||
// AI Profile actions
|
||||
addAIProfile: (profile) => {
|
||||
const id = `profile-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
||||
@@ -2909,6 +2925,8 @@ export const useAppStore = create<AppState & AppActions>()(
|
||||
mcpServers: state.mcpServers,
|
||||
mcpAutoApproveTools: state.mcpAutoApproveTools,
|
||||
mcpUnrestrictedTools: state.mcpUnrestrictedTools,
|
||||
// Prompt customization
|
||||
promptCustomization: state.promptCustomization,
|
||||
// Profiles and sessions
|
||||
aiProfiles: state.aiProfiles,
|
||||
chatSessions: state.chatSessions,
|
||||
|
||||
Reference in New Issue
Block a user