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:
Geoff Hammond
2025-07-03 06:43:46 +10:00
committed by GitHub
parent c99df64f65
commit f7fbdd6755
8 changed files with 426 additions and 90 deletions

View File

@@ -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,