accs-cli
Version:
ACCS CLI — Full-featured developer tool for scaffolding, running, building, and managing multi-language projects
430 lines (370 loc) • 11.5 kB
JavaScript
/**
* Configuration management command
*/
import chalk from 'chalk';
import inquirer from 'inquirer';
import boxen from 'boxen';
import { logger } from '../utils/logger.js';
import { configManager } from '../config/config-manager.js';
export function configCommand(program) {
program
.command('config')
.argument('[key]', 'Configuration key')
.argument('[value]', 'Configuration value')
.option('-g, --get <key>', 'Get configuration value')
.option('-s, --set <key> <value>', 'Set configuration value')
.option('-d, --delete <key>', 'Delete configuration key')
.option('-l, --list', 'List all configuration')
.option('-r, --reset', 'Reset to defaults')
.option('-e, --edit', 'Interactive configuration editor')
.option('--export <file>', 'Export configuration to file')
.option('--import <file>', 'Import configuration from file')
.description('Manage ACCS configuration')
.action(async (key, value, options) => {
try {
await handleConfigAction(key, value, options);
} catch (error) {
logger.error('Configuration operation failed:', error.message);
process.exit(1);
}
});
}
async function handleConfigAction(key, value, options) {
// Handle specific options first
if (options.get) {
return showConfigValue(options.get);
}
if (options.set) {
return setConfigValue(options.set, options.args?.[0]);
}
if (options.delete) {
return deleteConfigKey(options.delete);
}
if (options.list) {
return listConfiguration();
}
if (options.reset) {
return resetConfiguration();
}
if (options.edit) {
return interactiveConfigEditor();
}
if (options.export) {
return exportConfiguration(options.export);
}
if (options.import) {
return importConfiguration(options.import);
}
// Handle key-value arguments
if (key && value !== undefined) {
return setConfigValue(key, value);
}
if (key && value === undefined) {
return showConfigValue(key);
}
// Default: show help
return showConfigHelp();
}
function showConfigValue(key) {
if (!configManager.has(key)) {
logger.error(`Configuration key "${key}" not found`);
return;
}
const value = configManager.get(key);
logger.info(`${chalk.cyan(key)}: ${chalk.yellow(JSON.stringify(value, null, 2))}`);
}
function setConfigValue(key, value) {
if (!key || value === undefined) {
throw new Error('Both key and value are required');
}
// Parse value as JSON if possible
let parsedValue = value;
try {
parsedValue = JSON.parse(value);
} catch (error) {
// Keep as string if not valid JSON
}
configManager.set(key, parsedValue);
logger.success(`Set ${chalk.cyan(key)} = ${chalk.yellow(JSON.stringify(parsedValue))}`);
}
function deleteConfigKey(key) {
if (!configManager.has(key)) {
logger.error(`Configuration key "${key}" not found`);
return;
}
configManager.delete(key);
logger.success(`Deleted configuration key: ${chalk.cyan(key)}`);
}
function listConfiguration() {
const config = configManager.getAll();
const configPath = configManager.getConfigPath();
console.log(boxen(
chalk.blue.bold('🔧 ACCS Configuration'),
{
padding: 1,
margin: 1,
borderStyle: 'round',
borderColor: 'blue'
}
));
logger.info(`Config file: ${chalk.gray(configPath)}`);
logger.separator();
if (Object.keys(config).length === 0) {
logger.info('No configuration found (using defaults)');
return;
}
// Group configuration by category
const categories = {
'General': ['defaultTemplate', 'verbose', 'autoUpdate', 'theme'],
'Server': ['defaultPort'],
'Build': ['buildDir', 'srcDir'],
'Deploy': ['deployTarget'],
'Plugins': ['plugins'],
'Aliases': ['aliases'],
'Other': []
};
const configEntries = Object.entries(config);
// Categorize config entries
const categorized = {};
configEntries.forEach(([key, value]) => {
let category = 'Other';
for (const [cat, keys] of Object.entries(categories)) {
if (keys.includes(key)) {
category = cat;
break;
}
}
if (!categorized[category]) {
categorized[category] = [];
}
categorized[category].push([key, value]);
});
// Display each category
Object.entries(categorized).forEach(([category, entries]) => {
if (entries.length === 0) return;
logger.section(category);
entries.forEach(([key, value]) => {
displayConfigValue(key, value);
});
});
logger.separator();
logger.info('Configuration commands:');
logger.info(` ${chalk.cyan('accs config <key> <value>')} - Set configuration`);
logger.info(` ${chalk.cyan('accs config <key>')} - Get configuration`);
logger.info(` ${chalk.cyan('accs config --edit')} - Interactive editor`);
logger.info(` ${chalk.cyan('accs config --reset')} - Reset to defaults`);
}
function displayConfigValue(key, value) {
let displayValue;
if (Array.isArray(value)) {
displayValue = value.length > 0 ? value.join(', ') : chalk.gray('(empty array)');
} else if (typeof value === 'object' && value !== null) {
displayValue = Object.keys(value).length > 0
? JSON.stringify(value, null, 2)
: chalk.gray('(empty object)');
} else {
displayValue = String(value);
}
console.log(` ${chalk.cyan(key)}: ${chalk.yellow(displayValue)}`);
}
async function resetConfiguration() {
const { confirm } = await inquirer.prompt([
{
type: 'confirm',
name: 'confirm',
message: 'Are you sure you want to reset all configuration to defaults?',
default: false
}
]);
if (!confirm) {
logger.info('Reset cancelled');
return;
}
configManager.reset();
logger.success('Configuration reset to defaults');
}
async function interactiveConfigEditor() {
const config = configManager.getAll();
console.log(boxen(
chalk.blue.bold('📝 Interactive Configuration Editor'),
{
padding: 1,
margin: 1,
borderStyle: 'round',
borderColor: 'blue'
}
));
const { action } = await inquirer.prompt([
{
type: 'list',
name: 'action',
message: 'What would you like to do?',
choices: [
{ name: 'Edit existing configuration', value: 'edit' },
{ name: 'Add new configuration', value: 'add' },
{ name: 'Remove configuration', value: 'remove' },
{ name: 'Reset to defaults', value: 'reset' },
{ name: 'Exit', value: 'exit' }
]
}
]);
switch (action) {
case 'edit':
await editExistingConfig(config);
break;
case 'add':
await addNewConfig();
break;
case 'remove':
await removeConfig(config);
break;
case 'reset':
await resetConfiguration();
break;
case 'exit':
logger.info('Configuration editor closed');
break;
}
}
async function editExistingConfig(config) {
if (Object.keys(config).length === 0) {
logger.info('No configuration to edit');
return;
}
const { key } = await inquirer.prompt([
{
type: 'list',
name: 'key',
message: 'Select configuration to edit:',
choices: Object.keys(config).map(key => ({
name: `${key}: ${JSON.stringify(config[key])}`,
value: key
}))
}
]);
const currentValue = config[key];
const { newValue } = await inquirer.prompt([
{
type: 'input',
name: 'newValue',
message: `New value for ${key}:`,
default: JSON.stringify(currentValue),
validate: (input) => {
if (!input.trim()) return 'Value cannot be empty';
try {
JSON.parse(input);
return true;
} catch (error) {
return 'Please enter valid JSON or a simple string';
}
}
}
]);
let parsedValue;
try {
parsedValue = JSON.parse(newValue);
} catch (error) {
parsedValue = newValue;
}
configManager.set(key, parsedValue);
logger.success(`Updated ${chalk.cyan(key)} = ${chalk.yellow(JSON.stringify(parsedValue))}`);
}
async function addNewConfig() {
const { key, value } = await inquirer.prompt([
{
type: 'input',
name: 'key',
message: 'Configuration key:',
validate: (input) => input.trim() ? true : 'Key cannot be empty'
},
{
type: 'input',
name: 'value',
message: 'Configuration value (JSON or string):',
validate: (input) => input.trim() ? true : 'Value cannot be empty'
}
]);
let parsedValue;
try {
parsedValue = JSON.parse(value);
} catch (error) {
parsedValue = value;
}
configManager.set(key, parsedValue);
logger.success(`Added ${chalk.cyan(key)} = ${chalk.yellow(JSON.stringify(parsedValue))}`);
}
async function removeConfig(config) {
if (Object.keys(config).length === 0) {
logger.info('No configuration to remove');
return;
}
const { key } = await inquirer.prompt([
{
type: 'list',
name: 'key',
message: 'Select configuration to remove:',
choices: Object.keys(config).map(key => ({
name: `${key}: ${JSON.stringify(config[key])}`,
value: key
}))
}
]);
const { confirm } = await inquirer.prompt([
{
type: 'confirm',
name: 'confirm',
message: `Remove configuration "${key}"?`,
default: false
}
]);
if (confirm) {
configManager.delete(key);
logger.success(`Removed configuration: ${chalk.cyan(key)}`);
}
}
async function exportConfiguration(filePath) {
try {
await configManager.exportConfig(filePath);
logger.success(`Configuration exported to: ${chalk.cyan(filePath)}`);
} catch (error) {
throw new Error(`Export failed: ${error.message}`);
}
}
async function importConfiguration(filePath) {
try {
await configManager.importConfig(filePath);
logger.success(`Configuration imported from: ${chalk.cyan(filePath)}`);
} catch (error) {
throw new Error(`Import failed: ${error.message}`);
}
}
function showConfigHelp() {
console.log(boxen(
chalk.blue.bold('🔧 ACCS Configuration Help'),
{
padding: 1,
margin: 1,
borderStyle: 'round',
borderColor: 'blue'
}
));
logger.info('Configuration commands:');
logger.info(` ${chalk.cyan('accs config --list')} - Show all configuration`);
logger.info(` ${chalk.cyan('accs config <key>')} - Get specific value`);
logger.info(` ${chalk.cyan('accs config <key> <value>')} - Set configuration`);
logger.info(` ${chalk.cyan('accs config --delete <key>')} - Remove configuration`);
logger.info(` ${chalk.cyan('accs config --edit')} - Interactive editor`);
logger.info(` ${chalk.cyan('accs config --reset')} - Reset to defaults`);
logger.separator();
logger.info('Common configuration keys:');
logger.info(` ${chalk.yellow('defaultTemplate')} - Default project template`);
logger.info(` ${chalk.yellow('defaultPort')} - Default server port`);
logger.info(` ${chalk.yellow('buildDir')} - Build output directory`);
logger.info(` ${chalk.yellow('srcDir')} - Source directory`);
logger.info(` ${chalk.yellow('verbose')} - Enable verbose output`);
logger.separator();
logger.info('Examples:');
logger.info(` ${chalk.cyan('accs config defaultTemplate react')}`);
logger.info(` ${chalk.cyan('accs config defaultPort 8080')}`);
logger.info(` ${chalk.cyan('accs config verbose true')}`);
}