behemoth-cli
Version:
🌍 BEHEMOTH CLIv3.760.4 - Level 50+ POST-SINGULARITY Intelligence Trading AI
249 lines (206 loc) • 6.26 kB
text/typescript
import * as fs from 'fs';
import * as path from 'path';
import * as os from 'os';
interface Config {
groqApiKey?: string;
groqApiKeys?: string[]; // Array of API keys for rotation
currentKeyIndex?: number; // Current key being used
defaultModel?: string;
n8nUrl?: string;
n8nApiKey?: string;
}
const CONFIG_DIR = '.groq'; // In home directory
const CONFIG_FILE = 'local-settings.json';
export class ConfigManager {
private configPath: string;
constructor() {
const homeDir = os.homedir();
this.configPath = path.join(homeDir, CONFIG_DIR, CONFIG_FILE);
}
private ensureConfigDir(): void {
const configDir = path.dirname(this.configPath);
if (!fs.existsSync(configDir)) {
fs.mkdirSync(configDir, {recursive: true, mode: 0o700});
}
}
public setApiKey(apiKey: string): void {
try {
this.ensureConfigDir();
let config: Config = {};
if (fs.existsSync(this.configPath)) {
const configData = fs.readFileSync(this.configPath, 'utf8');
config = JSON.parse(configData);
}
config.groqApiKey = apiKey;
fs.writeFileSync(this.configPath, JSON.stringify(config, null, 2), {
mode: 0o600, // Read/write for owner only
});
} catch (error) {
throw new Error(`Failed to save API key: ${error}`);
}
}
public addApiKey(apiKey: string): void {
try {
this.ensureConfigDir();
let config: Config = {};
if (fs.existsSync(this.configPath)) {
const configData = fs.readFileSync(this.configPath, 'utf8');
config = JSON.parse(configData);
}
if (!config.groqApiKeys) {
config.groqApiKeys = [];
}
if (!config.groqApiKeys.includes(apiKey)) {
config.groqApiKeys.push(apiKey);
}
fs.writeFileSync(this.configPath, JSON.stringify(config, null, 2), {
mode: 0o600, // Read/write for owner only
});
} catch (error) {
throw new Error(`Failed to add API key: ${error}`);
}
}
public getApiKey(): string | null {
try {
if (!fs.existsSync(this.configPath)) {
return null;
}
const configData = fs.readFileSync(this.configPath, 'utf8');
const config: Config = JSON.parse(configData);
return config.groqApiKey || null;
} catch (error) {
console.warn('Failed to read API key:', error);
return null;
}
}
public getApiKeys(): string[] {
try {
if (!fs.existsSync(this.configPath)) {
return [];
}
const configData = fs.readFileSync(this.configPath, 'utf8');
const config: Config = JSON.parse(configData);
return config.groqApiKeys || [];
} catch (error) {
console.warn('Failed to read API keys:', error);
return [];
}
}
public setCurrentKeyIndex(index: number): void {
try {
this.ensureConfigDir();
let config: Config = {};
if (fs.existsSync(this.configPath)) {
const configData = fs.readFileSync(this.configPath, 'utf8');
config = JSON.parse(configData);
}
config.currentKeyIndex = index;
fs.writeFileSync(this.configPath, JSON.stringify(config, null, 2), {
mode: 0o600, // Read/write for owner only
});
} catch (error) {
throw new Error(`Failed to save current key index: ${error}`);
}
}
public getCurrentKeyIndex(): number | null {
try {
if (!fs.existsSync(this.configPath)) {
return null;
}
const configData = fs.readFileSync(this.configPath, 'utf8');
const config: Config = JSON.parse(configData);
return config.currentKeyIndex ?? null;
} catch (error) {
console.warn('Failed to read current key index:', error);
return null;
}
}
public getDefaultModel(): string | null {
try {
if (!fs.existsSync(this.configPath)) {
return null;
}
const configData = fs.readFileSync(this.configPath, 'utf8');
const config: Config = JSON.parse(configData);
return config.defaultModel || null;
} catch (error) {
console.warn('Failed to read default model:', error);
return null;
}
}
public setN8nConfig(url: string, apiKey: string): void {
try {
this.ensureConfigDir();
let config: Config = {};
if (fs.existsSync(this.configPath)) {
const configData = fs.readFileSync(this.configPath, 'utf8');
config = JSON.parse(configData);
}
config.n8nUrl = url;
config.n8nApiKey = apiKey;
fs.writeFileSync(this.configPath, JSON.stringify(config, null, 2), {
mode: 0o600,
});
} catch (error) {
throw new Error(`Failed to save n8n config: ${error}`);
}
}
public getN8nConfig(): {url: string; apiKey: string} | null {
try {
if (!fs.existsSync(this.configPath)) {
return null;
}
const configData = fs.readFileSync(this.configPath, 'utf8');
const config: Config = JSON.parse(configData);
if (config.n8nUrl && config.n8nApiKey) {
return {url: config.n8nUrl, apiKey: config.n8nApiKey};
}
return null;
} catch (error) {
console.warn('Failed to read n8n config:', error);
return null;
}
}
public setDefaultModel(model: string): void {
try {
this.ensureConfigDir();
let config: Config = {};
if (fs.existsSync(this.configPath)) {
const configData = fs.readFileSync(this.configPath, 'utf8');
config = JSON.parse(configData);
}
config.defaultModel = model;
fs.writeFileSync(this.configPath, JSON.stringify(config, null, 2), {
mode: 0o600 // Read/write for owner only
});
} catch (error) {
throw new Error(`Failed to save default model: ${error}`);
}
}
public getCurrentApiKey(): string | null {
try {
const keys = this.getApiKeys();
const currentIndex = this.getCurrentKeyIndex() || 0;
if (keys.length === 0) {
return this.getApiKey(); // Fallback to single key
}
return keys[currentIndex % keys.length] || null;
} catch (error) {
console.warn('Failed to get current API key:', error);
return null;
}
}
public rotateApiKey(): void {
try {
const keys = this.getApiKeys();
if (keys.length <= 1) {
return; // No rotation needed for single key or no keys
}
const currentIndex = this.getCurrentKeyIndex() || 0;
const nextIndex = (currentIndex + 1) % keys.length;
this.setCurrentKeyIndex(nextIndex);
} catch (error) {
console.warn('Failed to rotate API key:', error);
}
}
}