Feat: Implemented advanced settings for Claude Code AI provider (#872)
* Feat: Implemented advanced settings for Claude Code AI provider - Added new 'claudeCode' property to default config - Added getters and validation functions to 'config-manager.js' - Added new 'isEmpty' utility to 'utils.js' - Added new constants file 'commands.js' for AI_COMMAND_NAMES - Updated Claude Code AI provider to use new config functions - Updated 'claude-code-usage.md' documentation - Added 'config-manager.test.js' tests to cover new settings * chore: run format --------- Co-authored-by: Ralph Khreish <35776126+Crunchyman-ralph@users.noreply.github.com>
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import chalk from 'chalk';
|
||||
import { z } from 'zod';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { log, findProjectRoot, resolveEnvVariable } from './utils.js';
|
||||
import { log, findProjectRoot, resolveEnvVariable, isEmpty } from './utils.js';
|
||||
import { LEGACY_CONFIG_FILE } from '../../src/constants/paths.js';
|
||||
import { findConfigPath } from '../../src/utils/path-utils.js';
|
||||
import {
|
||||
@@ -11,6 +12,7 @@ import {
|
||||
CUSTOM_PROVIDERS_ARRAY,
|
||||
ALL_PROVIDERS
|
||||
} from '../../src/constants/providers.js';
|
||||
import { AI_COMMAND_NAMES } from '../../src/constants/commands.js';
|
||||
|
||||
// Calculate __dirname in ESM
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
@@ -68,7 +70,8 @@ const DEFAULTS = {
|
||||
ollamaBaseURL: 'http://localhost:11434/api',
|
||||
bedrockBaseURL: 'https://bedrock.us-east-1.amazonaws.com',
|
||||
responseLanguage: 'English'
|
||||
}
|
||||
},
|
||||
claudeCode: {}
|
||||
};
|
||||
|
||||
// --- Internal Config Loading ---
|
||||
@@ -129,7 +132,8 @@ function _loadAndValidateConfig(explicitRoot = null) {
|
||||
? { ...defaults.models.fallback, ...parsedConfig.models.fallback }
|
||||
: { ...defaults.models.fallback }
|
||||
},
|
||||
global: { ...defaults.global, ...parsedConfig?.global }
|
||||
global: { ...defaults.global, ...parsedConfig?.global },
|
||||
claudeCode: { ...defaults.claudeCode, ...parsedConfig?.claudeCode }
|
||||
};
|
||||
configSource = `file (${configPath})`; // Update source info
|
||||
|
||||
@@ -172,6 +176,9 @@ function _loadAndValidateConfig(explicitRoot = null) {
|
||||
config.models.fallback.provider = undefined;
|
||||
config.models.fallback.modelId = undefined;
|
||||
}
|
||||
if (config.claudeCode && !isEmpty(config.claudeCode)) {
|
||||
config.claudeCode = validateClaudeCodeSettings(config.claudeCode);
|
||||
}
|
||||
} catch (error) {
|
||||
// Use console.error for actual errors during parsing
|
||||
console.error(
|
||||
@@ -279,6 +286,83 @@ function validateProviderModelCombination(providerName, modelId) {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates Claude Code AI provider custom settings
|
||||
* @param {object} settings The settings to validate
|
||||
* @returns {object} The validated settings
|
||||
*/
|
||||
function validateClaudeCodeSettings(settings) {
|
||||
// Define the base settings schema without commandSpecific first
|
||||
const BaseSettingsSchema = z.object({
|
||||
maxTurns: z.number().int().positive().optional(),
|
||||
customSystemPrompt: z.string().optional(),
|
||||
appendSystemPrompt: z.string().optional(),
|
||||
permissionMode: z
|
||||
.enum(['default', 'acceptEdits', 'plan', 'bypassPermissions'])
|
||||
.optional(),
|
||||
allowedTools: z.array(z.string()).optional(),
|
||||
disallowedTools: z.array(z.string()).optional(),
|
||||
mcpServers: z
|
||||
.record(
|
||||
z.string(),
|
||||
z.object({
|
||||
type: z.enum(['stdio', 'sse']).optional(),
|
||||
command: z.string(),
|
||||
args: z.array(z.string()).optional(),
|
||||
env: z.record(z.string()).optional(),
|
||||
url: z.string().url().optional(),
|
||||
headers: z.record(z.string()).optional()
|
||||
})
|
||||
)
|
||||
.optional()
|
||||
});
|
||||
|
||||
// Define CommandSpecificSchema using the base schema
|
||||
const CommandSpecificSchema = z.record(
|
||||
z.enum(AI_COMMAND_NAMES),
|
||||
BaseSettingsSchema
|
||||
);
|
||||
|
||||
// Define the full settings schema with commandSpecific
|
||||
const SettingsSchema = BaseSettingsSchema.extend({
|
||||
commandSpecific: CommandSpecificSchema.optional()
|
||||
});
|
||||
|
||||
let validatedSettings = {};
|
||||
|
||||
try {
|
||||
validatedSettings = SettingsSchema.parse(settings);
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
chalk.yellow(
|
||||
`Warning: Invalid Claude Code settings in config: ${error.message}. Falling back to default.`
|
||||
)
|
||||
);
|
||||
|
||||
validatedSettings = {};
|
||||
}
|
||||
|
||||
return validatedSettings;
|
||||
}
|
||||
|
||||
// --- Claude Code Settings Getters ---
|
||||
|
||||
function getClaudeCodeSettings(explicitRoot = null, forceReload = false) {
|
||||
const config = getConfig(explicitRoot, forceReload);
|
||||
// Ensure Claude Code defaults are applied if Claude Code section is missing
|
||||
return { ...DEFAULTS.claudeCode, ...(config?.claudeCode || {}) };
|
||||
}
|
||||
|
||||
function getClaudeCodeSettingsForCommand(
|
||||
commandName,
|
||||
explicitRoot = null,
|
||||
forceReload = false
|
||||
) {
|
||||
const settings = getClaudeCodeSettings(explicitRoot, forceReload);
|
||||
const commandSpecific = settings?.commandSpecific || {};
|
||||
return { ...settings, ...commandSpecific[commandName] };
|
||||
}
|
||||
|
||||
// --- Role-Specific Getters ---
|
||||
|
||||
function getModelConfigForRole(role, explicitRoot = null) {
|
||||
@@ -815,9 +899,13 @@ export {
|
||||
writeConfig,
|
||||
ConfigurationError,
|
||||
isConfigFilePresent,
|
||||
// Claude Code settings
|
||||
getClaudeCodeSettings,
|
||||
getClaudeCodeSettingsForCommand,
|
||||
// Validation
|
||||
validateProvider,
|
||||
validateProviderModelCombination,
|
||||
validateClaudeCodeSettings,
|
||||
VALIDATED_PROVIDERS,
|
||||
CUSTOM_PROVIDERS,
|
||||
ALL_PROVIDERS,
|
||||
|
||||
Reference in New Issue
Block a user