Skip to content

Fix issue #191: Improve config clear command and add documentation ab… #197

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 61 additions & 12 deletions packages/cli/src/commands/config.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import * as path from 'path';

import chalk from 'chalk';
import { Logger } from 'mycoder-agent';

Expand All @@ -8,6 +10,7 @@ import {
updateConfig,
getConfigAtLevel,
clearConfigAtLevel,
clearConfigKey,
ConfigLevel,
} from '../settings/config.js';
import { nameToLogIndex } from '../utils/nameToLogIndex.js';
Expand All @@ -18,7 +21,9 @@ export interface ConfigOptions extends SharedOptions {
command: 'get' | 'set' | 'list' | 'clear';
key?: string;
value?: string;
all?: boolean;
all: boolean; // Has default value in builder, so it's always defined
global: boolean; // Has default value in builder, so it's always defined
verbose: boolean; // Has default value in builder, so it's always defined
}

export const command: CommandModule<SharedOptions, ConfigOptions> = {
Expand All @@ -45,6 +50,18 @@ export const command: CommandModule<SharedOptions, ConfigOptions> = {
type: 'boolean',
default: false,
})
.option('global', {
alias: 'g',
describe: 'Use global configuration instead of project-level',
type: 'boolean',
default: false,
})
.option('verbose', {
alias: 'v',
describe: 'Show detailed information including config file paths',
type: 'boolean',
default: false,
})
.example('$0 config list', 'List all configuration values')
.example(
'$0 config get githubMode',
Expand Down Expand Up @@ -115,6 +132,35 @@ export const command: CommandModule<SharedOptions, ConfigOptions> = {
// Handle 'list' command
if (argv.command === 'list') {
logger.info('Current configuration:');

// Show config file locations
const {
getSettingsDir,
getProjectSettingsDir,
} = require('../settings/settings.js');
const globalConfigPath = path.join(getSettingsDir(), 'config.json');
const projectDir = getProjectSettingsDir();
const projectConfigPath = projectDir
? path.join(projectDir, 'config.json')
: 'Not available';

logger.info(`Global config file: ${chalk.blue(globalConfigPath)}`);
logger.info(`Project config file: ${chalk.blue(projectConfigPath)}`);
logger.info('');

// Show config file paths in verbose mode
if (argv.verbose || argv.v) {
const { getProjectConfigFile } = await import('../settings/config.js');
const { getSettingsDir } = await import('../settings/settings.js');
const globalConfigPath = path.join(getSettingsDir(), 'config.json');
const projectConfigPath = getProjectConfigFile();

logger.info(`Global config: ${chalk.blue(globalConfigPath)}`);
logger.info(
`Project config: ${projectConfigPath ? chalk.blue(projectConfigPath) : chalk.dim('(not set)')}`,
);
logger.info('');
}
const defaultConfig = getDefaultConfig();

// Get all valid config keys
Expand Down Expand Up @@ -276,15 +322,8 @@ export const command: CommandModule<SharedOptions, ConfigOptions> = {
return;
}

// Get the current config, create a new object without the specified key
const currentConfig = getConfig();
const { [argv.key]: _, ...newConfig } = currentConfig as Record<
string,
any
>;

// Update the config file with the new object
updateConfig(newConfig);
// Clear the specified key from the configuration at the current level
clearConfigKey(argv.key, configLevel);

// Get the default value that will now be used
const defaultValue =
Expand All @@ -297,13 +336,23 @@ export const command: CommandModule<SharedOptions, ConfigOptions> = {
// Determine where the new value is coming from
const isDefaultAfterClear =
JSON.stringify(newValue) === JSON.stringify(defaultValue);

// Get the actual config values at each level
const globalConfig = getConfigAtLevel(ConfigLevel.GLOBAL);
const projectConfig = getConfigAtLevel(ConfigLevel.PROJECT);

// Check if key exists AND has a non-default value in each level
const afterClearInGlobal =
!isDefaultAfterClear &&
argv.key in getConfigAtLevel(ConfigLevel.GLOBAL);
argv.key in globalConfig &&
JSON.stringify(globalConfig[argv.key]) !== JSON.stringify(defaultValue);

const afterClearInProject =
!isDefaultAfterClear &&
!afterClearInGlobal &&
argv.key in getConfigAtLevel(ConfigLevel.PROJECT);
argv.key in projectConfig &&
JSON.stringify(projectConfig[argv.key]) !==
JSON.stringify(defaultValue);

let sourceDisplay = '';
if (isDefaultAfterClear) {
Expand Down
10 changes: 9 additions & 1 deletion packages/cli/src/settings/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -275,9 +275,17 @@ export const clearConfigKey = (
}

// Create a new config without the specified key
const { [key]: _, ...newConfig } = currentLevelConfig as Record<string, any>;
const { [key]: removedValue, ...newConfig } = currentLevelConfig as Record<
string,
any
>;
console.log(`Removed value for key ${key}:`, removedValue);

// Write the updated config back to the file
console.log(`Clearing key ${key} from ${targetFile}`);
console.log(`Original config:`, JSON.stringify(currentLevelConfig, null, 2));
console.log(`New config without key:`, JSON.stringify(newConfig, null, 2));

fs.writeFileSync(targetFile, JSON.stringify(newConfig, null, 2));

// Return the new merged configuration
Expand Down