autoagent-cli
Version:
Run autonomous AI agents using Claude or Gemini for task execution
732 lines (731 loc) • 31.1 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.registerConfigCommand = registerConfigCommand;
const config_manager_1 = require("../../core/config-manager");
const logger_1 = require("../../utils/logger");
const fs = __importStar(require("fs/promises"));
const path = __importStar(require("path"));
function registerConfigCommand(program) {
const config = program
.command('config')
.description('Manage configuration');
config
.command('get [key]')
.description('Get configuration value(s)')
.option('--show-source', 'Show the source of each configuration value')
.action(async (key, options) => {
try {
const configManager = new config_manager_1.ConfigManager();
const localConfigPath = path.join(process.cwd(), '.autoagent', 'config.json');
let hasCorruptedJson = false;
try {
const content = await fs.readFile(localConfigPath, 'utf-8');
JSON.parse(content);
}
catch (error) {
if (error instanceof SyntaxError) {
hasCorruptedJson = true;
}
}
if (hasCorruptedJson) {
logger_1.Logger.error('Failed to parse configuration');
process.exit(1);
}
await configManager.loadConfig();
const currentConfig = configManager.getConfig();
if (key !== null && key !== undefined && key.length > 0) {
const value = getConfigValue(key, currentConfig);
const envValue = getEnvValue(key);
const displayValue = envValue !== undefined ? envValue : value;
if (displayValue === undefined) {
logger_1.Logger.error(`Unknown configuration key: ${key}`);
process.exit(1);
}
let output = `${key}: ${displayValue !== null ? String(displayValue) : 'undefined'}`;
if (options?.showSource === true) {
const source = envValue !== undefined ? 'environment' : 'local';
output += ` (${source})`;
}
logger_1.Logger.info(output);
}
else {
const allKeys = Object.keys(currentConfig);
for (const k of allKeys) {
const value = getConfigValue(k, currentConfig);
const envValue = getEnvValue(k);
const displayValue = envValue !== undefined ? envValue : value;
let output = `${k}: ${displayValue !== null ? String(displayValue) : 'undefined'}`;
if (options?.showSource === true) {
const source = envValue !== undefined ? 'environment' : 'local';
output += ` (${source})`;
}
logger_1.Logger.info(output);
}
}
}
catch (error) {
if (!(error instanceof SyntaxError || (error instanceof Error && error.message.includes('JSON')))) {
logger_1.Logger.error(`Failed: ${error instanceof Error ? error.message : String(error)}`);
}
process.exit(1);
}
});
config
.command('set <key> <value>')
.description('Set configuration value')
.option('-g, --global', 'Set in global configuration')
.action(async (key, value, options) => {
try {
const configManager = new config_manager_1.ConfigManager();
try {
await configManager.loadConfig();
}
catch (error) {
if (error instanceof SyntaxError || (error instanceof Error && error.message.includes('JSON'))) {
logger_1.Logger.error('Failed to parse configuration');
process.exit(1);
}
throw error;
}
const validatedValue = validateConfigValue(key, value);
const updates = {};
setConfigValue(key, validatedValue, updates);
try {
await configManager.updateConfig(updates, options.global === true ? 'global' : 'local');
}
catch (error) {
if (error.code === 'EACCES' || error.code === 'EPERM') {
logger_1.Logger.error('Permission denied: Cannot write to configuration file');
process.exit(1);
}
throw error;
}
logger_1.Logger.success(`Configuration updated: ${key} = ${value}`);
}
catch (error) {
const isJsonError = error instanceof SyntaxError || (error instanceof Error && error.message.includes('JSON'));
const isPermissionError = error.code === 'EACCES' || error.code === 'EPERM';
if (!isJsonError && !isPermissionError) {
logger_1.Logger.error(`Failed: ${error instanceof Error ? error.message : String(error)}`);
}
process.exit(1);
}
});
config
.command('reset')
.description('Reset configuration to defaults')
.option('-g, --global', 'Reset global configuration')
.action(async (options) => {
try {
const configPath = options.global === true
? (() => {
const homeDir = process.env.HOME;
if (homeDir === null || homeDir === undefined || homeDir.length === 0) {
throw new Error('HOME environment variable not found');
}
return path.join(homeDir, '.autoagent', 'config.json');
})()
: path.join(process.cwd(), '.autoagent', 'config.json');
try {
await fs.unlink(configPath);
logger_1.Logger.success(`Configuration reset ${options.global === true ? 'globally' : 'locally'}`);
}
catch (error) {
if (error.code !== 'ENOENT') {
throw error;
}
logger_1.Logger.info('No configuration file to reset');
}
}
catch (error) {
logger_1.Logger.error(`Failed: ${error instanceof Error ? error.message : String(error)}`);
process.exit(1);
}
});
config
.command('export <filename>')
.description('Export configuration to file')
.action(async (filename) => {
try {
const configManager = new config_manager_1.ConfigManager();
try {
await configManager.loadConfig();
}
catch (error) {
if (error instanceof SyntaxError || (error instanceof Error && error.message.includes('JSON'))) {
logger_1.Logger.error('Failed to parse configuration');
process.exit(1);
}
throw error;
}
const currentConfig = configManager.getConfig();
const exportPath = path.resolve(process.cwd(), filename);
await fs.writeFile(exportPath, JSON.stringify(currentConfig, null, 2));
logger_1.Logger.success(`Configuration exported to ${filename}`);
}
catch (error) {
logger_1.Logger.error(`Failed: ${error instanceof Error ? error.message : String(error)}`);
process.exit(1);
}
});
config
.command('import <filename>')
.description('Import configuration from file')
.option('-g, --global', 'Import to global configuration')
.action(async (filename, options) => {
try {
const configManager = new config_manager_1.ConfigManager();
const importPath = path.resolve(process.cwd(), filename);
const content = await fs.readFile(importPath, 'utf-8');
const importedConfig = JSON.parse(content);
for (const [key, value] of Object.entries(importedConfig)) {
validateConfigValue(key, String(value));
}
await configManager.saveConfig(importedConfig, options.global);
logger_1.Logger.success(`Configuration imported from ${filename}`);
}
catch (error) {
logger_1.Logger.error(`Failed: ${error instanceof Error ? error.message : String(error)}`);
process.exit(1);
}
});
config
.command('init')
.description('Initialize configuration')
.option('-g, --global', 'Initialize global configuration')
.action(async (options) => {
try {
const configManager = new config_manager_1.ConfigManager();
await configManager.initConfig(options.global);
logger_1.Logger.success(`Configuration initialized ${options.global === true ? 'globally' : 'locally'}`);
}
catch (error) {
logger_1.Logger.error(`Failed: ${error instanceof Error ? error.message : String(error)}`);
process.exit(1);
}
});
config
.command('set-provider <provider>')
.description('Set default AI provider (claude or gemini)')
.option('-g, --global', 'Set globally')
.action(async (provider, options) => {
try {
const configManager = new config_manager_1.ConfigManager();
try {
await configManager.loadConfig();
}
catch (error) {
if (error instanceof SyntaxError || (error instanceof Error && error.message.includes('JSON'))) {
logger_1.Logger.error('Failed to parse configuration');
process.exit(1);
}
throw error;
}
await configManager.setProvider(provider, options.global);
logger_1.Logger.success(`Default provider set to ${provider}`);
}
catch (error) {
logger_1.Logger.error(`Failed: ${error instanceof Error ? error.message : String(error)}`);
process.exit(1);
}
});
config
.command('set-failover <providers...>')
.description('Set failover providers in order of preference')
.option('-g, --global', 'Set globally')
.action(async (providers, options) => {
try {
const configManager = new config_manager_1.ConfigManager();
try {
await configManager.loadConfig();
}
catch (error) {
if (error instanceof SyntaxError || (error instanceof Error && error.message.includes('JSON'))) {
logger_1.Logger.error('Failed to parse configuration');
process.exit(1);
}
throw error;
}
await configManager.setFailoverProviders(providers, options.global);
logger_1.Logger.success(`Failover providers set to: ${providers.join(', ')}`);
}
catch (error) {
logger_1.Logger.error(`Failed: ${error instanceof Error ? error.message : String(error)}`);
process.exit(1);
}
});
config
.command('set-auto-commit <enabled>')
.description('Enable or disable automatic git commits via hooks (true/false)')
.option('-g, --global', 'Set globally')
.action(async (enabled, options) => {
try {
const configManager = new config_manager_1.ConfigManager();
let userConfig;
try {
userConfig = await configManager.loadConfig();
}
catch (error) {
if (error instanceof SyntaxError || (error instanceof Error && error.message.includes('JSON'))) {
logger_1.Logger.error('Failed to parse configuration');
process.exit(1);
}
throw error;
}
if (!userConfig.hooks) {
userConfig.hooks = {};
}
const hookPoint = 'PostExecutionEnd';
const gitCommitHook = {
type: 'git-commit',
message: 'Complete issue from {{issueFile}}'
};
if (enabled === 'true') {
if (!userConfig.hooks[hookPoint]) {
userConfig.hooks[hookPoint] = [];
}
const existingCommitHook = userConfig.hooks[hookPoint].find(h => h.type === 'git-commit');
if (!existingCommitHook) {
userConfig.hooks[hookPoint].push(gitCommitHook);
}
logger_1.Logger.success('✅ Auto-commit enabled via git-commit hook');
logger_1.Logger.info('ℹ️ Git commits will be created after each successful execution');
}
else {
if (userConfig.hooks[hookPoint]) {
userConfig.hooks[hookPoint] = userConfig.hooks[hookPoint].filter(h => h.type !== 'git-commit');
if (userConfig.hooks[hookPoint].length === 0) {
delete userConfig.hooks[hookPoint];
}
}
logger_1.Logger.success('✅ Auto-commit disabled');
logger_1.Logger.info('ℹ️ Git commits will not be created automatically');
}
await configManager.saveConfig(userConfig, options.global);
}
catch (error) {
logger_1.Logger.error(`Failed: ${error instanceof Error ? error.message : String(error)}`);
process.exit(1);
}
});
config
.command('set-co-authored-by <enabled>')
.description('Include AI co-authorship in commits (true/false)')
.option('-g, --global', 'Set globally')
.action(async (enabled, options) => {
try {
const configManager = new config_manager_1.ConfigManager();
let userConfig;
try {
userConfig = await configManager.loadConfig();
}
catch (error) {
if (error instanceof SyntaxError || (error instanceof Error && error.message.includes('JSON'))) {
logger_1.Logger.error('Failed to parse configuration');
process.exit(1);
}
throw error;
}
userConfig.includeCoAuthoredBy = enabled === 'true';
await configManager.saveConfig(userConfig, options.global);
logger_1.Logger.success(`Co-authorship ${userConfig.includeCoAuthoredBy ? 'enabled' : 'disabled'}`);
}
catch (error) {
logger_1.Logger.error(`Failed: ${error instanceof Error ? error.message : String(error)}`);
process.exit(1);
}
});
config
.command('set-git-no-verify <value>')
.description('Skip git pre-commit and commit-msg hooks when committing (true/false)')
.option('-g, --global', 'Set globally')
.action(async (value, options) => {
try {
const configManager = new config_manager_1.ConfigManager();
let userConfig;
try {
userConfig = await configManager.loadConfig();
}
catch (error) {
if (error instanceof SyntaxError || (error instanceof Error && error.message.includes('JSON'))) {
logger_1.Logger.error('Failed to parse configuration');
process.exit(1);
}
throw error;
}
const normalizedValue = value.toLowerCase();
if (normalizedValue !== 'true' && normalizedValue !== 'false') {
logger_1.Logger.error('Invalid value: must be "true" or "false"');
process.exit(1);
}
const noVerify = normalizedValue === 'true';
if (!userConfig.hooks) {
userConfig.hooks = {};
}
for (const hookPoint in userConfig.hooks) {
const hooks = userConfig.hooks[hookPoint];
if (Array.isArray(hooks)) {
for (const hook of hooks) {
if (hook.type === 'git-commit') {
hook.noVerify = noVerify;
}
}
}
}
await configManager.saveConfig(userConfig, options.global);
logger_1.Logger.success(`Git hooks ${noVerify ? 'disabled (--no-verify)' : 'enabled'} for commits`);
logger_1.Logger.info(noVerify
? 'ℹ️ Pre-commit and commit-msg hooks will be skipped when AutoAgent commits'
: 'ℹ️ Pre-commit and commit-msg hooks will run when AutoAgent commits');
}
catch (error) {
logger_1.Logger.error(`Failed: ${error instanceof Error ? error.message : String(error)}`);
process.exit(1);
}
});
config
.command('set-auto-push <value>')
.description('Enable or disable automatic git push via hooks (true/false)')
.option('-g, --global', 'Set globally')
.action(async (value, options) => {
try {
const configManager = new config_manager_1.ConfigManager();
let userConfig;
try {
userConfig = await configManager.loadConfig();
}
catch (error) {
if (error instanceof SyntaxError || (error instanceof Error && error.message.includes('JSON'))) {
logger_1.Logger.error('Failed to parse configuration');
process.exit(1);
}
throw error;
}
const normalizedValue = value.toLowerCase();
if (normalizedValue !== 'true' && normalizedValue !== 'false') {
logger_1.Logger.error('Invalid value: must be "true" or "false"');
process.exit(1);
}
if (!userConfig.hooks) {
userConfig.hooks = {};
}
const hookPoint = 'PostExecutionEnd';
const gitPushHook = {
type: 'git-push',
remote: 'origin'
};
const autoPush = normalizedValue === 'true';
if (autoPush) {
if (!userConfig.hooks[hookPoint]) {
userConfig.hooks[hookPoint] = [];
}
const existingPushHook = userConfig.hooks[hookPoint].find(h => h.type === 'git-push');
if (!existingPushHook) {
userConfig.hooks[hookPoint].push(gitPushHook);
}
logger_1.Logger.success('✅ Auto-push enabled via git-push hook');
logger_1.Logger.info('ℹ️ Git commits will automatically be pushed to the remote repository');
logger_1.Logger.warning('Make sure you have a git remote configured with proper permissions');
}
else {
if (userConfig.hooks[hookPoint]) {
userConfig.hooks[hookPoint] = userConfig.hooks[hookPoint].filter(h => h.type !== 'git-push');
if (userConfig.hooks[hookPoint].length === 0) {
delete userConfig.hooks[hookPoint];
}
}
logger_1.Logger.success('✅ Auto-push disabled');
logger_1.Logger.info('ℹ️ Git commits will not be pushed automatically');
}
await configManager.saveConfig(userConfig, options.global);
}
catch (error) {
logger_1.Logger.error(`Failed: ${error instanceof Error ? error.message : String(error)}`);
process.exit(1);
}
});
config
.command('set-push-remote <remote>')
.description('Set the git remote for git-push hooks')
.option('-g, --global', 'Set globally')
.action(async (remote, options) => {
try {
const configManager = new config_manager_1.ConfigManager();
let userConfig;
try {
userConfig = await configManager.loadConfig();
}
catch (error) {
if (error instanceof SyntaxError || (error instanceof Error && error.message.includes('JSON'))) {
logger_1.Logger.error('Failed to parse configuration');
process.exit(1);
}
throw error;
}
let hooksUpdated = 0;
if (userConfig.hooks) {
for (const hookPoint of Object.keys(userConfig.hooks)) {
const hooks = userConfig.hooks[hookPoint];
if (hooks) {
for (const hook of hooks) {
if (hook.type === 'git-push') {
hook.remote = remote;
hooksUpdated++;
}
}
}
}
}
await configManager.saveConfig(userConfig, options.global);
logger_1.Logger.success(`✅ Push remote set to: ${remote}`);
if (hooksUpdated > 0) {
logger_1.Logger.info(`ℹ️ Updated ${hooksUpdated} git-push hook${hooksUpdated > 1 ? 's' : ''} to use '${remote}' remote`);
}
else {
logger_1.Logger.info('ℹ️ No git-push hooks found. Run \'autoagent config set-auto-push true\' to enable auto-push');
}
logger_1.Logger.info('ℹ️ Make sure this remote exists in your git repository');
}
catch (error) {
logger_1.Logger.error(`Failed: ${error instanceof Error ? error.message : String(error)}`);
process.exit(1);
}
});
config
.command('show')
.description('Show current configuration')
.action(async () => {
try {
const configManager = new config_manager_1.ConfigManager();
try {
await configManager.loadConfig();
}
catch (error) {
if (error instanceof SyntaxError || (error instanceof Error && error.message.includes('JSON'))) {
logger_1.Logger.error('Failed to parse configuration');
process.exit(1);
}
throw error;
}
await configManager.showConfig();
}
catch (error) {
logger_1.Logger.error(`Failed: ${error instanceof Error ? error.message : String(error)}`);
process.exit(1);
}
});
config
.command('clear-limits')
.description('Clear rate limit records')
.option('-p, --provider <provider>', 'Clear specific provider')
.action(async (options) => {
try {
const configManager = new config_manager_1.ConfigManager();
if (options.provider !== undefined && options.provider !== '') {
await configManager.clearRateLimit(options.provider);
logger_1.Logger.success(`Rate limit cleared for ${options.provider}`);
}
else {
await configManager.clearRateLimit('claude');
await configManager.clearRateLimit('gemini');
logger_1.Logger.success('All rate limits cleared');
}
}
catch (error) {
logger_1.Logger.error(`Failed: ${error instanceof Error ? error.message : String(error)}`);
process.exit(1);
}
});
}
function getConfigValue(key, config) {
switch (key) {
case 'provider':
return config.providers?.[0];
case 'providers':
return config.providers;
case 'verbose':
return config.logLevel === 'debug';
case 'logLevel':
return config.logLevel;
case 'maxTokens':
return config.maxTokens;
case 'retryAttempts':
return config.retryAttempts;
case 'failoverDelay':
return config.failoverDelay;
case 'includeCoAuthoredBy':
return config.includeCoAuthoredBy;
case 'customInstructions':
return config.customInstructions;
case 'rateLimitCooldown':
return config.rateLimitCooldown;
case 'hooks':
return config.hooks;
case 'strictCompletion':
return config.strictCompletion;
case 'completionConfidence':
return config.completionConfidence;
case 'ignoreToolFailures':
return config.ignoreToolFailures;
case 'maxRetryAttempts':
return config.maxRetryAttempts;
default:
return undefined;
}
}
function setConfigValue(key, value, updates) {
switch (key) {
case 'provider':
updates.providers = [value];
break;
case 'providers':
updates.providers = value;
break;
case 'verbose':
updates.logLevel = Boolean(value) === true ? 'debug' : 'info';
break;
case 'logLevel':
updates.logLevel = value;
break;
case 'maxTokens':
updates.maxTokens = value;
break;
case 'retryAttempts':
updates.retryAttempts = value;
break;
case 'failoverDelay':
updates.failoverDelay = value;
break;
case 'includeCoAuthoredBy':
updates.includeCoAuthoredBy = value;
break;
case 'customInstructions':
updates.customInstructions = value;
break;
case 'rateLimitCooldown':
updates.rateLimitCooldown = value;
break;
case 'strictCompletion':
updates.strictCompletion = value;
break;
case 'completionConfidence':
updates.completionConfidence = value;
break;
case 'ignoreToolFailures':
updates.ignoreToolFailures = value;
break;
case 'maxRetryAttempts':
updates.maxRetryAttempts = value;
break;
default:
throw new Error(`Unknown configuration key: ${key}`);
}
}
function getEnvValue(key) {
const envMap = {
'verbose': 'AUTOAGENT_VERBOSE',
'provider': 'AUTOAGENT_PROVIDER',
'logLevel': 'AUTOAGENT_LOG_LEVEL',
'maxTokens': 'AUTOAGENT_MAX_TOKENS',
'retryAttempts': 'AUTOAGENT_RETRY_ATTEMPTS',
'failoverDelay': 'AUTOAGENT_FAILOVER_DELAY',
'includeCoAuthoredBy': 'AUTOAGENT_INCLUDE_CO_AUTHORED_BY',
'customInstructions': 'AUTOAGENT_CUSTOM_INSTRUCTIONS',
'rateLimitCooldown': 'AUTOAGENT_RATE_LIMIT_COOLDOWN',
'strictCompletion': 'AUTOAGENT_STRICT_COMPLETION',
'completionConfidence': 'AUTOAGENT_COMPLETION_CONFIDENCE',
'ignoreToolFailures': 'AUTOAGENT_IGNORE_TOOL_FAILURES',
'maxRetryAttempts': 'AUTOAGENT_MAX_RETRY_ATTEMPTS'
};
const envKey = envMap[key];
if (envKey === null || envKey === undefined || envKey.length === 0 || process.env[envKey] === null || process.env[envKey] === undefined || process.env[envKey] === '') {
return undefined;
}
const envValue = process.env[envKey];
if (key === 'verbose' || key === 'includeCoAuthoredBy' || key === 'strictCompletion' ||
key === 'ignoreToolFailures') {
return envValue === 'true';
}
if (key === 'maxTokens' || key === 'retryAttempts' || key === 'failoverDelay' ||
key === 'rateLimitCooldown' || key === 'completionConfidence' || key === 'maxRetryAttempts') {
return parseInt(envValue, 10);
}
return envValue;
}
function validateConfigValue(key, value) {
switch (key) {
case 'provider':
if (!['claude', 'gemini'].includes(value)) {
throw new Error(`Invalid value for provider: ${value}. Must be 'claude' or 'gemini'`);
}
return value;
case 'verbose':
case 'includeCoAuthoredBy':
case 'strictCompletion':
case 'ignoreToolFailures':
if (!['true', 'false'].includes(value)) {
throw new Error(`Invalid value for ${key}: ${value}. Value must be boolean (true/false)`);
}
return value === 'true';
case 'logLevel':
if (!['debug', 'info', 'warn', 'error'].includes(value)) {
throw new Error(`Invalid value for logLevel: ${value}. Must be one of: debug, info, warn, error`);
}
return value;
case 'maxTokens':
case 'retryAttempts':
case 'failoverDelay':
case 'rateLimitCooldown':
case 'maxRetryAttempts': {
const num = parseInt(value, 10);
if (isNaN(num) || num < 0) {
throw new Error(`Invalid value for ${key}: ${value}. Must be a positive number`);
}
return num;
}
case 'completionConfidence': {
const num = parseInt(value, 10);
if (isNaN(num) || num < 0 || num > 100) {
throw new Error(`Invalid value for completionConfidence: ${value}. Must be a number between 0 and 100`);
}
return num;
}
case 'customInstructions':
return value;
default:
throw new Error(`Unknown configuration key: ${key}`);
}
}