From 11ea02867f806f2ee6080f5b8b043dd9d0460ed2 Mon Sep 17 00:00:00 2001 From: jinzelin Date: Mon, 25 May 2026 14:47:13 +0800 Subject: [PATCH] fix: config set support object value --- src/commands/config.ts | 92 ++++++++++++++++++++++++++++-------------- 1 file changed, 62 insertions(+), 30 deletions(-) diff --git a/src/commands/config.ts b/src/commands/config.ts index 42c736d14..946f5f0bf 100644 --- a/src/commands/config.ts +++ b/src/commands/config.ts @@ -292,42 +292,74 @@ export function registerConfigCommand(program: Command): void { .command('set ') .description('Set a value (auto-coerce types)') .option('--string', 'Force value to be stored as string') + .option('--json', 'Parse value as JSON (use for arrays/objects)') .option('--allow-unknown', 'Allow setting unknown keys') - .action((key: string, value: string, options: { string?: boolean; allowUnknown?: boolean }) => { - const allowUnknown = Boolean(options.allowUnknown); - const keyValidation = validateConfigKeyPath(key); - if (!keyValidation.valid && !allowUnknown) { - const reason = keyValidation.reason ? ` ${keyValidation.reason}.` : ''; - console.error(`Error: Invalid configuration key "${key}".${reason}`); - console.error('Use "openspec config list" to see available keys.'); - console.error('Pass --allow-unknown to bypass this check.'); - process.exitCode = 1; - return; - } + .action( + ( + key: string, + value: string, + options: { string?: boolean; json?: boolean; allowUnknown?: boolean } + ) => { + const allowUnknown = Boolean(options.allowUnknown); + const keyValidation = validateConfigKeyPath(key); + if (!keyValidation.valid && !allowUnknown) { + const reason = keyValidation.reason ? ` ${keyValidation.reason}.` : ''; + console.error(`Error: Invalid configuration key "${key}".${reason}`); + console.error('Use "openspec config list" to see available keys.'); + console.error('Pass --allow-unknown to bypass this check.'); + process.exitCode = 1; + return; + } - const config = getGlobalConfig() as Record; - const coercedValue = coerceValue(value, options.string || false); + if (options.string && options.json) { + console.error('Error: --string and --json cannot be combined.'); + process.exitCode = 1; + return; + } - // Create a copy to validate before saving - const newConfig = JSON.parse(JSON.stringify(config)); - setNestedValue(newConfig, key, coercedValue); + let parsedValue: unknown; + if (options.json) { + try { + parsedValue = JSON.parse(value); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + console.error(`Error: --json was provided but value is not valid JSON: ${message}`); + process.exitCode = 1; + return; + } + } else { + parsedValue = coerceValue(value, options.string || false); + } - // Validate the new config - const validation = validateConfig(newConfig); - if (!validation.success) { - console.error(`Error: Invalid configuration - ${validation.error}`); - process.exitCode = 1; - return; - } + const config = getGlobalConfig() as Record; - // Apply changes and save - setNestedValue(config, key, coercedValue); - saveGlobalConfig(config as GlobalConfig); + // Create a copy to validate before saving + const newConfig = JSON.parse(JSON.stringify(config)); + setNestedValue(newConfig, key, parsedValue); - const displayValue = - typeof coercedValue === 'string' ? `"${coercedValue}"` : String(coercedValue); - console.log(`Set ${key} = ${displayValue}`); - }); + // Validate the new config + const validation = validateConfig(newConfig); + if (!validation.success) { + console.error(`Error: Invalid configuration - ${validation.error}`); + process.exitCode = 1; + return; + } + + // Apply changes and save + setNestedValue(config, key, parsedValue); + saveGlobalConfig(config as GlobalConfig); + + let displayValue: string; + if (typeof parsedValue === 'string') { + displayValue = `"${parsedValue}"`; + } else if (typeof parsedValue === 'object' && parsedValue !== null) { + displayValue = JSON.stringify(parsedValue); + } else { + displayValue = String(parsedValue); + } + console.log(`Set ${key} = ${displayValue}`); + } + ); // config unset configCmd