mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-01-30 06:12:03 +00:00
feat: add auto-load CLAUDE.md functionality
- Introduced a new setting to enable automatic loading of CLAUDE.md files from project-specific directories. - Updated relevant services and components to support the new setting, including the AgentService and AutoModeService. - Added UI controls for managing the auto-load setting in the settings view. - Enhanced SDK options to incorporate settingSources for CLAUDE.md loading. - Updated global and project settings interfaces to include autoLoadClaudeMd property.
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -79,4 +79,5 @@ blob-report/
|
||||
# Misc
|
||||
*.pem
|
||||
|
||||
docker-compose.override.yml
|
||||
docker-compose.override.yml
|
||||
.claude/
|
||||
@@ -112,10 +112,11 @@ app.use(express.json({ limit: '50mb' }));
|
||||
const events: EventEmitter = createEventEmitter();
|
||||
|
||||
// Create services
|
||||
const agentService = new AgentService(DATA_DIR, events);
|
||||
const featureLoader = new FeatureLoader();
|
||||
const autoModeService = new AutoModeService(events);
|
||||
// Note: settingsService is created first so it can be injected into other services
|
||||
const settingsService = new SettingsService(DATA_DIR);
|
||||
const agentService = new AgentService(DATA_DIR, events, settingsService);
|
||||
const featureLoader = new FeatureLoader();
|
||||
const autoModeService = new AutoModeService(events, settingsService);
|
||||
const claudeUsageService = new ClaudeUsageService();
|
||||
|
||||
// Initialize services
|
||||
|
||||
@@ -136,6 +136,71 @@ function getBaseOptions(): Partial<Options> {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Build system prompt configuration based on autoLoadClaudeMd setting.
|
||||
* When autoLoadClaudeMd is true:
|
||||
* - Uses preset mode with 'claude_code' to enable CLAUDE.md auto-loading
|
||||
* - If there's a custom systemPrompt, appends it to the preset
|
||||
* - Sets settingSources to ['project'] for SDK to load CLAUDE.md files
|
||||
*
|
||||
* @param config - The SDK options config
|
||||
* @returns Object with systemPrompt and settingSources for SDK options
|
||||
*/
|
||||
function buildClaudeMdOptions(config: CreateSdkOptionsConfig): {
|
||||
systemPrompt?: string | SystemPromptConfig;
|
||||
settingSources?: Array<'user' | 'project' | 'local'>;
|
||||
} {
|
||||
if (!config.autoLoadClaudeMd) {
|
||||
// Standard mode - just pass through the system prompt as-is
|
||||
return config.systemPrompt ? { systemPrompt: config.systemPrompt } : {};
|
||||
}
|
||||
|
||||
// Auto-load CLAUDE.md mode - use preset with settingSources
|
||||
const result: {
|
||||
systemPrompt: SystemPromptConfig;
|
||||
settingSources: Array<'user' | 'project' | 'local'>;
|
||||
} = {
|
||||
systemPrompt: {
|
||||
type: 'preset',
|
||||
preset: 'claude_code',
|
||||
},
|
||||
// Load both user (~/.claude/CLAUDE.md) and project (.claude/CLAUDE.md) settings
|
||||
settingSources: ['user', 'project'],
|
||||
};
|
||||
|
||||
// If there's a custom system prompt, append it to the preset
|
||||
if (config.systemPrompt) {
|
||||
result.systemPrompt.append = config.systemPrompt;
|
||||
}
|
||||
|
||||
console.log(
|
||||
'[SDK Options] CLAUDE.md auto-loading enabled:',
|
||||
JSON.stringify(
|
||||
{
|
||||
systemPrompt: result.systemPrompt,
|
||||
settingSources: result.settingSources,
|
||||
},
|
||||
null,
|
||||
2
|
||||
)
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* System prompt configuration for SDK options
|
||||
* When using preset mode with claude_code, CLAUDE.md files are automatically loaded
|
||||
*/
|
||||
export interface SystemPromptConfig {
|
||||
/** Use preset mode with claude_code to enable CLAUDE.md auto-loading */
|
||||
type: 'preset';
|
||||
/** The preset to use - 'claude_code' enables CLAUDE.md loading */
|
||||
preset: 'claude_code';
|
||||
/** Optional additional prompt to append to the preset */
|
||||
append?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Options configuration for creating SDK options
|
||||
*/
|
||||
@@ -160,6 +225,9 @@ export interface CreateSdkOptionsConfig {
|
||||
type: 'json_schema';
|
||||
schema: Record<string, unknown>;
|
||||
};
|
||||
|
||||
/** Enable auto-loading of CLAUDE.md files via SDK's settingSources */
|
||||
autoLoadClaudeMd?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -169,11 +237,15 @@ export interface CreateSdkOptionsConfig {
|
||||
* - Uses read-only tools for codebase analysis
|
||||
* - Extended turns for thorough exploration
|
||||
* - Opus model by default (can be overridden)
|
||||
* - When autoLoadClaudeMd is true, uses preset mode and settingSources for CLAUDE.md loading
|
||||
*/
|
||||
export function createSpecGenerationOptions(config: CreateSdkOptionsConfig): Options {
|
||||
// Validate working directory before creating options
|
||||
validateWorkingDirectory(config.cwd);
|
||||
|
||||
// Build CLAUDE.md auto-loading options if enabled
|
||||
const claudeMdOptions = buildClaudeMdOptions(config);
|
||||
|
||||
return {
|
||||
...getBaseOptions(),
|
||||
// Override permissionMode - spec generation only needs read-only tools
|
||||
@@ -184,7 +256,7 @@ export function createSpecGenerationOptions(config: CreateSdkOptionsConfig): Opt
|
||||
maxTurns: MAX_TURNS.maximum,
|
||||
cwd: config.cwd,
|
||||
allowedTools: [...TOOL_PRESETS.specGeneration],
|
||||
...(config.systemPrompt && { systemPrompt: config.systemPrompt }),
|
||||
...claudeMdOptions,
|
||||
...(config.abortController && { abortController: config.abortController }),
|
||||
...(config.outputFormat && { outputFormat: config.outputFormat }),
|
||||
};
|
||||
@@ -197,11 +269,15 @@ export function createSpecGenerationOptions(config: CreateSdkOptionsConfig): Opt
|
||||
* - Uses read-only tools (just needs to read the spec)
|
||||
* - Quick turns since it's mostly JSON generation
|
||||
* - Sonnet model by default for speed
|
||||
* - When autoLoadClaudeMd is true, uses preset mode and settingSources for CLAUDE.md loading
|
||||
*/
|
||||
export function createFeatureGenerationOptions(config: CreateSdkOptionsConfig): Options {
|
||||
// Validate working directory before creating options
|
||||
validateWorkingDirectory(config.cwd);
|
||||
|
||||
// Build CLAUDE.md auto-loading options if enabled
|
||||
const claudeMdOptions = buildClaudeMdOptions(config);
|
||||
|
||||
return {
|
||||
...getBaseOptions(),
|
||||
// Override permissionMode - feature generation only needs read-only tools
|
||||
@@ -210,7 +286,7 @@ export function createFeatureGenerationOptions(config: CreateSdkOptionsConfig):
|
||||
maxTurns: MAX_TURNS.quick,
|
||||
cwd: config.cwd,
|
||||
allowedTools: [...TOOL_PRESETS.readOnly],
|
||||
...(config.systemPrompt && { systemPrompt: config.systemPrompt }),
|
||||
...claudeMdOptions,
|
||||
...(config.abortController && { abortController: config.abortController }),
|
||||
};
|
||||
}
|
||||
@@ -222,18 +298,22 @@ export function createFeatureGenerationOptions(config: CreateSdkOptionsConfig):
|
||||
* - Uses read-only tools for analysis
|
||||
* - Standard turns to allow thorough codebase exploration and structured output generation
|
||||
* - Opus model by default for thorough analysis
|
||||
* - When autoLoadClaudeMd is true, uses preset mode and settingSources for CLAUDE.md loading
|
||||
*/
|
||||
export function createSuggestionsOptions(config: CreateSdkOptionsConfig): Options {
|
||||
// Validate working directory before creating options
|
||||
validateWorkingDirectory(config.cwd);
|
||||
|
||||
// Build CLAUDE.md auto-loading options if enabled
|
||||
const claudeMdOptions = buildClaudeMdOptions(config);
|
||||
|
||||
return {
|
||||
...getBaseOptions(),
|
||||
model: getModelForUseCase('suggestions', config.model),
|
||||
maxTurns: MAX_TURNS.extended,
|
||||
cwd: config.cwd,
|
||||
allowedTools: [...TOOL_PRESETS.readOnly],
|
||||
...(config.systemPrompt && { systemPrompt: config.systemPrompt }),
|
||||
...claudeMdOptions,
|
||||
...(config.abortController && { abortController: config.abortController }),
|
||||
...(config.outputFormat && { outputFormat: config.outputFormat }),
|
||||
};
|
||||
@@ -247,6 +327,7 @@ export function createSuggestionsOptions(config: CreateSdkOptionsConfig): Option
|
||||
* - Standard turns for interactive sessions
|
||||
* - Model priority: explicit model > session model > chat default
|
||||
* - Sandbox enabled for bash safety
|
||||
* - When autoLoadClaudeMd is true, uses preset mode and settingSources for CLAUDE.md loading
|
||||
*/
|
||||
export function createChatOptions(config: CreateSdkOptionsConfig): Options {
|
||||
// Validate working directory before creating options
|
||||
@@ -255,6 +336,9 @@ export function createChatOptions(config: CreateSdkOptionsConfig): Options {
|
||||
// Model priority: explicit model > session model > chat default
|
||||
const effectiveModel = config.model || config.sessionModel;
|
||||
|
||||
// Build CLAUDE.md auto-loading options if enabled
|
||||
const claudeMdOptions = buildClaudeMdOptions(config);
|
||||
|
||||
return {
|
||||
...getBaseOptions(),
|
||||
model: getModelForUseCase('chat', effectiveModel),
|
||||
@@ -265,7 +349,7 @@ export function createChatOptions(config: CreateSdkOptionsConfig): Options {
|
||||
enabled: true,
|
||||
autoAllowBashIfSandboxed: true,
|
||||
},
|
||||
...(config.systemPrompt && { systemPrompt: config.systemPrompt }),
|
||||
...claudeMdOptions,
|
||||
...(config.abortController && { abortController: config.abortController }),
|
||||
};
|
||||
}
|
||||
@@ -278,11 +362,15 @@ export function createChatOptions(config: CreateSdkOptionsConfig): Options {
|
||||
* - Extended turns for thorough feature implementation
|
||||
* - Uses default model (can be overridden)
|
||||
* - Sandbox enabled for bash safety
|
||||
* - When autoLoadClaudeMd is true, uses preset mode and settingSources for CLAUDE.md loading
|
||||
*/
|
||||
export function createAutoModeOptions(config: CreateSdkOptionsConfig): Options {
|
||||
// Validate working directory before creating options
|
||||
validateWorkingDirectory(config.cwd);
|
||||
|
||||
// Build CLAUDE.md auto-loading options if enabled
|
||||
const claudeMdOptions = buildClaudeMdOptions(config);
|
||||
|
||||
return {
|
||||
...getBaseOptions(),
|
||||
model: getModelForUseCase('auto', config.model),
|
||||
@@ -293,7 +381,7 @@ export function createAutoModeOptions(config: CreateSdkOptionsConfig): Options {
|
||||
enabled: true,
|
||||
autoAllowBashIfSandboxed: true,
|
||||
},
|
||||
...(config.systemPrompt && { systemPrompt: config.systemPrompt }),
|
||||
...claudeMdOptions,
|
||||
...(config.abortController && { abortController: config.abortController }),
|
||||
};
|
||||
}
|
||||
@@ -302,6 +390,7 @@ export function createAutoModeOptions(config: CreateSdkOptionsConfig): Options {
|
||||
* Create custom SDK options with explicit configuration
|
||||
*
|
||||
* Use this when the preset options don't fit your use case.
|
||||
* When autoLoadClaudeMd is true, uses preset mode and settingSources for CLAUDE.md loading
|
||||
*/
|
||||
export function createCustomOptions(
|
||||
config: CreateSdkOptionsConfig & {
|
||||
@@ -313,6 +402,9 @@ export function createCustomOptions(
|
||||
// Validate working directory before creating options
|
||||
validateWorkingDirectory(config.cwd);
|
||||
|
||||
// Build CLAUDE.md auto-loading options if enabled
|
||||
const claudeMdOptions = buildClaudeMdOptions(config);
|
||||
|
||||
return {
|
||||
...getBaseOptions(),
|
||||
model: getModelForUseCase('default', config.model),
|
||||
@@ -320,7 +412,7 @@ export function createCustomOptions(
|
||||
cwd: config.cwd,
|
||||
allowedTools: config.allowedTools ? [...config.allowedTools] : [...TOOL_PRESETS.readOnly],
|
||||
...(config.sandbox && { sandbox: config.sandbox }),
|
||||
...(config.systemPrompt && { systemPrompt: config.systemPrompt }),
|
||||
...claudeMdOptions,
|
||||
...(config.abortController && { abortController: config.abortController }),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -55,6 +55,8 @@ export class ClaudeProvider extends BaseProvider {
|
||||
...(sdkSessionId && conversationHistory && conversationHistory.length > 0
|
||||
? { resume: sdkSessionId }
|
||||
: {}),
|
||||
// Forward settingSources for CLAUDE.md file loading
|
||||
...(options.settingSources && { settingSources: options.settingSources }),
|
||||
};
|
||||
|
||||
// Build prompt payload
|
||||
|
||||
@@ -26,13 +26,14 @@ export interface ExecuteOptions {
|
||||
prompt: string | Array<{ type: string; text?: string; source?: object }>;
|
||||
model: string;
|
||||
cwd: string;
|
||||
systemPrompt?: string;
|
||||
systemPrompt?: string | { type: 'preset'; preset: 'claude_code'; append?: string };
|
||||
maxTurns?: number;
|
||||
allowedTools?: string[];
|
||||
mcpServers?: Record<string, unknown>;
|
||||
abortController?: AbortController;
|
||||
conversationHistory?: ConversationMessage[]; // Previous messages for context
|
||||
sdkSessionId?: string; // Claude SDK session ID for resuming conversations
|
||||
settingSources?: Array<'user' | 'project' | 'local'>; // Claude filesystem settings to load
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
import { ProviderFactory } from '../providers/provider-factory.js';
|
||||
import { createChatOptions, validateWorkingDirectory } from '../lib/sdk-options.js';
|
||||
import { PathNotAllowedError } from '@automaker/platform';
|
||||
import type { SettingsService } from './settings-service.js';
|
||||
|
||||
interface Message {
|
||||
id: string;
|
||||
@@ -57,11 +58,13 @@ export class AgentService {
|
||||
private stateDir: string;
|
||||
private metadataFile: string;
|
||||
private events: EventEmitter;
|
||||
private settingsService: SettingsService | null = null;
|
||||
|
||||
constructor(dataDir: string, events: EventEmitter) {
|
||||
constructor(dataDir: string, events: EventEmitter, settingsService?: SettingsService) {
|
||||
this.stateDir = path.join(dataDir, 'agent-sessions');
|
||||
this.metadataFile = path.join(dataDir, 'sessions-metadata.json');
|
||||
this.events = events;
|
||||
this.settingsService = settingsService ?? null;
|
||||
}
|
||||
|
||||
async initialize(): Promise<void> {
|
||||
@@ -186,7 +189,11 @@ export class AgentService {
|
||||
// Determine the effective working directory for context loading
|
||||
const effectiveWorkDir = workingDirectory || session.workingDirectory;
|
||||
|
||||
// Load autoLoadClaudeMd setting (project setting takes precedence over global)
|
||||
const autoLoadClaudeMd = await this.getAutoLoadClaudeMdSetting(effectiveWorkDir);
|
||||
|
||||
// Load project context files (CLAUDE.md, CODE_QUALITY.md, etc.)
|
||||
// Note: When autoLoadClaudeMd is enabled, SDK handles CLAUDE.md loading via settingSources
|
||||
const { formattedPrompt: contextFilesPrompt } = await loadContextFiles({
|
||||
projectPath: effectiveWorkDir,
|
||||
fsModule: secureFs as Parameters<typeof loadContextFiles>[0]['fsModule'],
|
||||
@@ -205,6 +212,7 @@ export class AgentService {
|
||||
sessionModel: session.model,
|
||||
systemPrompt: combinedSystemPrompt,
|
||||
abortController: session.abortController!,
|
||||
autoLoadClaudeMd,
|
||||
});
|
||||
|
||||
// Extract model, maxTurns, and allowedTools from SDK options
|
||||
@@ -224,11 +232,12 @@ export class AgentService {
|
||||
prompt: '', // Will be set below based on images
|
||||
model: effectiveModel,
|
||||
cwd: effectiveWorkDir,
|
||||
systemPrompt: combinedSystemPrompt,
|
||||
systemPrompt: sdkOptions.systemPrompt,
|
||||
maxTurns: maxTurns,
|
||||
allowedTools: allowedTools,
|
||||
abortController: session.abortController!,
|
||||
conversationHistory: conversationHistory.length > 0 ? conversationHistory : undefined,
|
||||
settingSources: sdkOptions.settingSources,
|
||||
sdkSessionId: session.sdkSessionId, // Pass SDK session ID for resuming
|
||||
};
|
||||
|
||||
@@ -595,6 +604,37 @@ You have full access to the codebase and can:
|
||||
- Execute tests and builds`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the autoLoadClaudeMd setting, with project settings taking precedence over global.
|
||||
* Returns false if settings service is not available.
|
||||
*/
|
||||
private async getAutoLoadClaudeMdSetting(projectPath: string): Promise<boolean> {
|
||||
if (!this.settingsService) {
|
||||
console.log('[AgentService] SettingsService not available, autoLoadClaudeMd disabled');
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
// Check project settings first (takes precedence)
|
||||
const projectSettings = await this.settingsService.getProjectSettings(projectPath);
|
||||
if (projectSettings.autoLoadClaudeMd !== undefined) {
|
||||
console.log(
|
||||
`[AgentService] autoLoadClaudeMd from project settings: ${projectSettings.autoLoadClaudeMd}`
|
||||
);
|
||||
return projectSettings.autoLoadClaudeMd;
|
||||
}
|
||||
|
||||
// Fall back to global settings
|
||||
const globalSettings = await this.settingsService.getGlobalSettings();
|
||||
const result = globalSettings.autoLoadClaudeMd ?? false;
|
||||
console.log(`[AgentService] autoLoadClaudeMd from global settings: ${result}`);
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error('[AgentService] Failed to load autoLoadClaudeMd setting:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private generateId(): string {
|
||||
return `msg_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import * as secureFs from '../lib/secure-fs.js';
|
||||
import type { EventEmitter } from '../lib/events.js';
|
||||
import { createAutoModeOptions, validateWorkingDirectory } from '../lib/sdk-options.js';
|
||||
import { FeatureLoader } from './feature-loader.js';
|
||||
import type { SettingsService } from './settings-service.js';
|
||||
|
||||
const execAsync = promisify(exec);
|
||||
|
||||
@@ -341,9 +342,11 @@ export class AutoModeService {
|
||||
private autoLoopAbortController: AbortController | null = null;
|
||||
private config: AutoModeConfig | null = null;
|
||||
private pendingApprovals = new Map<string, PendingApproval>();
|
||||
private settingsService: SettingsService | null = null;
|
||||
|
||||
constructor(events: EventEmitter) {
|
||||
constructor(events: EventEmitter, settingsService?: SettingsService) {
|
||||
this.events = events;
|
||||
this.settingsService = settingsService ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1780,11 +1783,15 @@ This mock response was generated because AUTOMAKER_MOCK_AGENT=true was set.
|
||||
return;
|
||||
}
|
||||
|
||||
// Load autoLoadClaudeMd setting (project setting takes precedence over global)
|
||||
const autoLoadClaudeMd = await this.getAutoLoadClaudeMdSetting(finalProjectPath);
|
||||
|
||||
// Build SDK options using centralized configuration for feature implementation
|
||||
const sdkOptions = createAutoModeOptions({
|
||||
cwd: workDir,
|
||||
model: model,
|
||||
abortController,
|
||||
autoLoadClaudeMd,
|
||||
});
|
||||
|
||||
// Extract model, maxTurns, and allowedTools from SDK options
|
||||
@@ -1823,7 +1830,8 @@ This mock response was generated because AUTOMAKER_MOCK_AGENT=true was set.
|
||||
cwd: workDir,
|
||||
allowedTools: allowedTools,
|
||||
abortController,
|
||||
systemPrompt: options?.systemPrompt,
|
||||
systemPrompt: sdkOptions.systemPrompt,
|
||||
settingSources: sdkOptions.settingSources,
|
||||
};
|
||||
|
||||
// Execute via provider
|
||||
@@ -2494,4 +2502,35 @@ Begin implementing task ${task.id} now.`;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the autoLoadClaudeMd setting, with project settings taking precedence over global.
|
||||
* Returns false if settings service is not available.
|
||||
*/
|
||||
private async getAutoLoadClaudeMdSetting(projectPath: string): Promise<boolean> {
|
||||
if (!this.settingsService) {
|
||||
console.log('[AutoMode] SettingsService not available, autoLoadClaudeMd disabled');
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
// Check project settings first (takes precedence)
|
||||
const projectSettings = await this.settingsService.getProjectSettings(projectPath);
|
||||
if (projectSettings.autoLoadClaudeMd !== undefined) {
|
||||
console.log(
|
||||
`[AutoMode] autoLoadClaudeMd from project settings: ${projectSettings.autoLoadClaudeMd}`
|
||||
);
|
||||
return projectSettings.autoLoadClaudeMd;
|
||||
}
|
||||
|
||||
// Fall back to global settings
|
||||
const globalSettings = await this.settingsService.getGlobalSettings();
|
||||
const result = globalSettings.autoLoadClaudeMd ?? false;
|
||||
console.log(`[AutoMode] autoLoadClaudeMd from global settings: ${result}`);
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error('[AutoMode] Failed to load autoLoadClaudeMd setting:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import { SettingsNavigation } from './settings-view/components/settings-navigati
|
||||
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';
|
||||
@@ -47,6 +48,8 @@ export function SettingsView() {
|
||||
apiKeys,
|
||||
validationModel,
|
||||
setValidationModel,
|
||||
autoLoadClaudeMd,
|
||||
setAutoLoadClaudeMd,
|
||||
} = useAppStore();
|
||||
|
||||
// Hide usage tracking when using API key (only show for Claude Code CLI users)
|
||||
@@ -102,6 +105,10 @@ export function SettingsView() {
|
||||
isChecking={isCheckingClaudeCli}
|
||||
onRefresh={handleRefreshClaudeCli}
|
||||
/>
|
||||
<ClaudeMdSettings
|
||||
autoLoadClaudeMd={autoLoadClaudeMd}
|
||||
onAutoLoadClaudeMdChange={setAutoLoadClaudeMd}
|
||||
/>
|
||||
{showUsageTracking && <ClaudeUsageSection />}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import { FileCode } from 'lucide-react';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
interface ClaudeMdSettingsProps {
|
||||
autoLoadClaudeMd: boolean;
|
||||
onAutoLoadClaudeMdChange: (enabled: boolean) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* ClaudeMdSettings Component
|
||||
*
|
||||
* UI control for the autoLoadClaudeMd setting which enables automatic loading
|
||||
* of project instructions from .claude/CLAUDE.md files via the Claude Agent SDK.
|
||||
*
|
||||
* Usage:
|
||||
* ```tsx
|
||||
* <ClaudeMdSettings
|
||||
* autoLoadClaudeMd={autoLoadClaudeMd}
|
||||
* onAutoLoadClaudeMdChange={setAutoLoadClaudeMd}
|
||||
* />
|
||||
* ```
|
||||
*/
|
||||
export function ClaudeMdSettings({
|
||||
autoLoadClaudeMd,
|
||||
onAutoLoadClaudeMdChange,
|
||||
}: ClaudeMdSettingsProps) {
|
||||
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="claude-md-settings"
|
||||
>
|
||||
<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 gap-3 mb-2">
|
||||
<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">
|
||||
<FileCode className="w-5 h-5 text-brand-500" />
|
||||
</div>
|
||||
<h2 className="text-lg font-semibold text-foreground tracking-tight">
|
||||
CLAUDE.md Integration
|
||||
</h2>
|
||||
</div>
|
||||
<p className="text-sm text-muted-foreground/80 ml-12">
|
||||
Configure automatic loading of project-specific instructions.
|
||||
</p>
|
||||
</div>
|
||||
<div className="p-6">
|
||||
<div className="group flex items-start space-x-3 p-3 rounded-xl hover:bg-accent/30 transition-colors duration-200 -mx-3">
|
||||
<Checkbox
|
||||
id="auto-load-claude-md"
|
||||
checked={autoLoadClaudeMd}
|
||||
onCheckedChange={(checked) => onAutoLoadClaudeMdChange(checked === true)}
|
||||
className="mt-1"
|
||||
data-testid="auto-load-claude-md-checkbox"
|
||||
/>
|
||||
<div className="space-y-1.5">
|
||||
<Label
|
||||
htmlFor="auto-load-claude-md"
|
||||
className="text-foreground cursor-pointer font-medium flex items-center gap-2"
|
||||
>
|
||||
<FileCode className="w-4 h-4 text-brand-500" />
|
||||
Auto-load CLAUDE.md Files
|
||||
</Label>
|
||||
<p className="text-xs text-muted-foreground/80 leading-relaxed">
|
||||
Automatically load project instructions from{' '}
|
||||
<code className="text-[10px] px-1 py-0.5 rounded bg-accent/50">
|
||||
.claude/CLAUDE.md
|
||||
</code>{' '}
|
||||
files. When enabled, Claude will read and follow conventions specified in your
|
||||
project's CLAUDE.md file. Project settings override global settings.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -223,6 +223,7 @@ export async function syncSettingsToServer(): Promise<boolean> {
|
||||
muteDoneSound: state.muteDoneSound,
|
||||
enhancementModel: state.enhancementModel,
|
||||
validationModel: state.validationModel,
|
||||
autoLoadClaudeMd: state.autoLoadClaudeMd,
|
||||
keyboardShortcuts: state.keyboardShortcuts,
|
||||
aiProfiles: state.aiProfiles,
|
||||
projects: state.projects,
|
||||
|
||||
@@ -478,6 +478,9 @@ export interface AppState {
|
||||
// Validation Model Settings
|
||||
validationModel: AgentModel; // Model used for GitHub issue validation (default: opus)
|
||||
|
||||
// Claude Agent SDK Settings
|
||||
autoLoadClaudeMd: boolean; // Auto-load CLAUDE.md files using SDK's settingSources option
|
||||
|
||||
// Project Analysis
|
||||
projectAnalysis: ProjectAnalysis | null;
|
||||
isAnalyzing: boolean;
|
||||
@@ -751,6 +754,9 @@ export interface AppActions {
|
||||
// Validation Model actions
|
||||
setValidationModel: (model: AgentModel) => void;
|
||||
|
||||
// Claude Agent SDK Settings actions
|
||||
setAutoLoadClaudeMd: (enabled: boolean) => Promise<void>;
|
||||
|
||||
// AI Profile actions
|
||||
addAIProfile: (profile: Omit<AIProfile, 'id'>) => void;
|
||||
updateAIProfile: (id: string, updates: Partial<AIProfile>) => void;
|
||||
@@ -922,6 +928,7 @@ const initialState: AppState = {
|
||||
muteDoneSound: false, // Default to sound enabled (not muted)
|
||||
enhancementModel: 'sonnet', // Default to sonnet for feature enhancement
|
||||
validationModel: 'opus', // Default to opus for GitHub issue validation
|
||||
autoLoadClaudeMd: false, // Default to disabled (user must opt-in)
|
||||
aiProfiles: DEFAULT_AI_PROFILES,
|
||||
projectAnalysis: null,
|
||||
isAnalyzing: false,
|
||||
@@ -1547,6 +1554,14 @@ export const useAppStore = create<AppState & AppActions>()(
|
||||
// Validation Model actions
|
||||
setValidationModel: (model) => set({ validationModel: model }),
|
||||
|
||||
// Claude Agent SDK Settings actions
|
||||
setAutoLoadClaudeMd: async (enabled) => {
|
||||
set({ autoLoadClaudeMd: enabled });
|
||||
// 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)}`;
|
||||
@@ -2690,6 +2705,7 @@ export const useAppStore = create<AppState & AppActions>()(
|
||||
muteDoneSound: state.muteDoneSound,
|
||||
enhancementModel: state.enhancementModel,
|
||||
validationModel: state.validationModel,
|
||||
autoLoadClaudeMd: state.autoLoadClaudeMd,
|
||||
// Profiles and sessions
|
||||
aiProfiles: state.aiProfiles,
|
||||
chatSessions: state.chatSessions,
|
||||
|
||||
@@ -297,6 +297,10 @@ export interface GlobalSettings {
|
||||
// Window State (Electron only)
|
||||
/** Persisted window bounds for restoring position/size across sessions */
|
||||
windowBounds?: WindowBounds;
|
||||
|
||||
// Claude Agent SDK Settings
|
||||
/** Auto-load CLAUDE.md files using SDK's settingSources option */
|
||||
autoLoadClaudeMd?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -392,6 +396,10 @@ export interface ProjectSettings {
|
||||
// Session Tracking
|
||||
/** Last chat session selected in this project */
|
||||
lastSelectedSessionId?: string;
|
||||
|
||||
// Claude Agent SDK Settings
|
||||
/** Auto-load CLAUDE.md files using SDK's settingSources option (project override) */
|
||||
autoLoadClaudeMd?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -450,6 +458,7 @@ export const DEFAULT_GLOBAL_SETTINGS: GlobalSettings = {
|
||||
recentFolders: [],
|
||||
worktreePanelCollapsed: false,
|
||||
lastSelectedSessionByProject: {},
|
||||
autoLoadClaudeMd: false,
|
||||
};
|
||||
|
||||
/** Default credentials (empty strings - user must provide API keys) */
|
||||
|
||||
Reference in New Issue
Block a user