autoagent-cli
Version:
Run autonomous AI agents using Claude or Gemini for task execution
329 lines (328 loc) ⢠13.4 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.ConfigManager = void 0;
const fs_1 = require("fs");
const path = __importStar(require("path"));
const os = __importStar(require("os"));
const logger_1 = require("../utils/logger");
class ConfigManager {
constructor(workingDir = process.cwd()) {
this.workingDir = workingDir;
this.globalConfigPath = path.join(ConfigManager.GLOBAL_CONFIG_DIR, ConfigManager.CONFIG_FILE);
this.localConfigPath = path.join(this.workingDir, ConfigManager.LOCAL_CONFIG_DIR, ConfigManager.CONFIG_FILE);
this.globalRateLimitPath = path.join(ConfigManager.GLOBAL_CONFIG_DIR, ConfigManager.RATE_LIMIT_FILE);
this.localRateLimitPath = path.join(this.workingDir, ConfigManager.LOCAL_CONFIG_DIR, ConfigManager.RATE_LIMIT_FILE);
this.config = { ...ConfigManager.DEFAULT_CONFIG };
}
async loadConfig() {
const globalConfig = await this.loadConfigFile(this.globalConfigPath);
const localConfig = await this.loadConfigFile(this.localConfigPath);
this.config = {
...ConfigManager.DEFAULT_CONFIG,
...globalConfig,
...localConfig
};
if (process.env.AUTOAGENT_DEBUG === 'true') {
logger_1.Logger.debug('Configuration loaded:');
logger_1.Logger.debug(` Default providers: ${JSON.stringify(ConfigManager.DEFAULT_CONFIG.providers)}`);
logger_1.Logger.debug(` Global config providers: ${JSON.stringify(globalConfig.providers)}`);
logger_1.Logger.debug(` Local config providers: ${JSON.stringify(localConfig.providers)}`);
logger_1.Logger.debug(` Final providers: ${JSON.stringify(this.config.providers)}`);
}
return this.config;
}
getConfig() {
return { ...this.config };
}
async updateConfig(updates, scope = 'local') {
const configPath = scope === 'global' ? this.globalConfigPath : this.localConfigPath;
const currentConfig = await this.loadConfigFile(configPath);
const updatedConfig = {
...currentConfig,
...updates
};
await this.saveConfigFile(configPath, updatedConfig);
await this.loadConfig();
}
async isProviderRateLimited(provider) {
const rateLimits = await this.loadRateLimits();
const providerData = rateLimits[provider];
if (!providerData || providerData.limitedAt === undefined) {
return false;
}
const timeSinceLimited = Date.now() - providerData.limitedAt;
const cooldownPeriod = this.config.rateLimitCooldown;
return timeSinceLimited < cooldownPeriod;
}
async updateRateLimit(provider, isLimited) {
const rateLimits = await this.loadRateLimits();
if (isLimited) {
rateLimits[provider] = {
limitedAt: Date.now(),
attempts: (rateLimits[provider]?.attempts ?? 0) + 1
};
}
else {
delete rateLimits[provider];
}
await this.saveRateLimits(rateLimits);
}
async getAvailableProviders() {
const availableProviders = [];
for (const provider of this.config.providers) {
const isRateLimited = await this.isProviderRateLimited(provider);
if (!isRateLimited) {
availableProviders.push(provider);
}
}
return availableProviders;
}
async checkRateLimit(provider) {
const rateLimits = await this.loadRateLimits();
const providerData = rateLimits[provider];
if (!providerData || providerData.limitedAt === undefined) {
return { isLimited: false };
}
const timeSinceLimited = Date.now() - providerData.limitedAt;
const cooldownPeriod = this.config.rateLimitCooldown;
const isLimited = timeSinceLimited < cooldownPeriod;
return {
isLimited,
timeRemaining: isLimited ? cooldownPeriod - timeSinceLimited : undefined,
attempts: providerData.attempts
};
}
async loadConfigFile(filePath) {
try {
const content = await fs_1.promises.readFile(filePath, 'utf-8');
try {
const config = JSON.parse(content);
if (process.env.AUTOAGENT_DEBUG === 'true') {
logger_1.Logger.debug(`Loaded config from ${filePath}: ${JSON.stringify(config)}`);
}
return config;
}
catch (parseError) {
logger_1.Logger.warning(`Invalid JSON in config file ${filePath}: ${String(parseError)}`);
return {};
}
}
catch (error) {
if (process.env.AUTOAGENT_DEBUG === 'true') {
logger_1.Logger.debug(`Config file not found: ${filePath}`);
}
return {};
}
}
async saveConfigFile(filePath, config) {
await this.ensureDirectoryExists(path.dirname(filePath));
try {
await fs_1.promises.writeFile(filePath, JSON.stringify(config, null, 2));
}
catch (error) {
if (error.code === 'EACCES' || error.code === 'EPERM') {
throw new Error(`Permission denied: Cannot write to ${filePath}`);
}
throw error;
}
}
async loadRateLimits() {
try {
const content = await fs_1.promises.readFile(this.localRateLimitPath, 'utf-8');
return JSON.parse(content);
}
catch {
try {
const content = await fs_1.promises.readFile(this.globalRateLimitPath, 'utf-8');
return JSON.parse(content);
}
catch {
return {};
}
}
}
async saveRateLimits(rateLimits) {
await this.ensureDirectoryExists(path.dirname(this.localRateLimitPath));
await fs_1.promises.writeFile(this.localRateLimitPath, JSON.stringify(rateLimits, null, 2));
}
async initConfig(global = false) {
const configPath = global ? this.globalConfigPath : this.localConfigPath;
await this.ensureDirectoryExists(path.dirname(configPath));
try {
await fs_1.promises.access(configPath);
throw new Error(`Configuration already exists at ${configPath}`);
}
catch (error) {
if (error.code === 'ENOENT') {
await this.saveConfigFile(configPath, ConfigManager.DEFAULT_CONFIG);
}
else {
throw error;
}
}
}
async setProvider(provider, global = false) {
if (!['claude', 'gemini'].includes(provider)) {
throw new Error(`Invalid provider: ${provider}. Must be 'claude' or 'gemini'`);
}
await this.updateConfig({ providers: [provider] }, global ? 'global' : 'local');
}
async setFailoverProviders(providers, global = false) {
const validProviders = providers.filter(p => ['claude', 'gemini'].includes(p));
if (validProviders.length === 0) {
throw new Error('No valid providers specified. Valid providers are: claude, gemini');
}
await this.updateConfig({ providers: validProviders }, global ? 'global' : 'local');
}
async clearRateLimit(provider) {
const rateLimits = await this.loadRateLimits();
delete rateLimits[provider];
await this.saveRateLimits(rateLimits);
}
async saveConfig(config, global = false) {
const configPath = global ? this.globalConfigPath : this.localConfigPath;
await this.saveConfigFile(configPath, config);
await this.loadConfig();
}
async showConfig() {
await this.loadConfig();
logger_1.Logger.info('\nš Current Configuration:');
logger_1.Logger.info('ā'.repeat(40));
logger_1.Logger.info('\nEffective Configuration:');
logger_1.Logger.info(JSON.stringify(this.config, null, 2));
logger_1.Logger.info('\nš Configuration Sources:');
try {
const globalConfig = await this.loadConfigFile(this.globalConfigPath);
if (Object.keys(globalConfig).length > 0) {
logger_1.Logger.info(`\nGlobal (${this.globalConfigPath}):`);
logger_1.Logger.info(JSON.stringify(globalConfig, null, 2));
}
}
catch {
logger_1.Logger.info('\nGlobal: Not configured');
}
try {
const localConfig = await this.loadConfigFile(this.localConfigPath);
if (Object.keys(localConfig).length > 0) {
logger_1.Logger.info(`\nLocal (${this.localConfigPath}):`);
logger_1.Logger.info(JSON.stringify(localConfig, null, 2));
}
}
catch {
logger_1.Logger.info('\nLocal: Not configured');
}
logger_1.Logger.info('\nā±ļø Rate Limit Status:');
for (const provider of ['claude', 'gemini']) {
const status = await this.checkRateLimit(provider);
if (status.isLimited === true) {
const remainingTime = Math.ceil((status.timeRemaining ?? 0) / 1000 / 60);
logger_1.Logger.info(`${provider}: Rate limited (${remainingTime} minutes remaining)`);
}
else {
logger_1.Logger.info(`${provider}: Not rate limited`);
}
}
}
async ensureDirectoryExists(dirPath) {
try {
await fs_1.promises.mkdir(dirPath, { recursive: true });
}
catch (error) {
if (error.code !== 'EEXIST') {
throw error;
}
}
}
async resolveAdditionalDirectories(configDirs = [], cliDirs = [], basePath = this.workingDir) {
const allDirs = [...configDirs, ...cliDirs];
const resolvedDirs = [];
for (const dir of allDirs) {
try {
const resolvedPath = path.isAbsolute(dir) ? dir : path.resolve(basePath, dir);
const stats = await fs_1.promises.stat(resolvedPath);
if (!stats.isDirectory()) {
logger_1.Logger.error(`Skipping ${dir}: not a directory`);
continue;
}
if (this.isSystemDirectory(resolvedPath)) {
logger_1.Logger.error(`Skipping ${dir}: system directory access not allowed`);
continue;
}
resolvedDirs.push(resolvedPath);
logger_1.Logger.debug(`Added additional directory: ${resolvedPath}`);
}
catch (error) {
logger_1.Logger.error(`Skipping ${dir}: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
return resolvedDirs;
}
isSystemDirectory(dirPath) {
const systemDirs = [
'/etc',
'/usr',
'/var',
'/bin',
'/sbin',
'/boot',
'/root',
'/sys',
'/proc',
'/dev'
];
const normalizedPath = path.resolve(dirPath);
return systemDirs.some(sysDir => normalizedPath.startsWith(sysDir + path.sep) || normalizedPath === sysDir);
}
}
exports.ConfigManager = ConfigManager;
ConfigManager.DEFAULT_CONFIG = {
providers: ['claude', 'gemini'],
failoverDelay: 5000,
retryAttempts: 3,
maxTokens: 100000,
rateLimitCooldown: 3600000,
logLevel: 'info',
customInstructions: '',
additionalDirectories: [],
strictCompletion: false,
completionConfidence: 70,
ignoreToolFailures: false,
maxRetryAttempts: 1
};
ConfigManager.GLOBAL_CONFIG_DIR = path.join(os.homedir(), '.autoagent');
ConfigManager.LOCAL_CONFIG_DIR = '.autoagent';
ConfigManager.CONFIG_FILE = 'config.json';
ConfigManager.RATE_LIMIT_FILE = 'rate-limits.json';