UNPKG

capsule-ai-cli

Version:

The AI Model Orchestrator - Intelligent multi-model workflows with device-locked licensing

179 lines 5.63 kB
import Conf from 'conf'; import { cosmiconfig } from 'cosmiconfig'; import chalk from 'chalk'; import { z } from 'zod'; const ConfigSchema = z.object({ auth: z.object({ token: z.string().optional(), email: z.string().optional(), tier: z.enum(['base', 'super']).optional(), deviceId: z.string().optional(), remainingRUs: z.number().optional(), validUntil: z.string().optional() }).optional(), providers: z.record(z.string(), z.object({ apiKey: z.string().optional(), baseUrl: z.string().optional(), defaultModel: z.string().optional(), enabled: z.boolean().default(true), useManaged: z.boolean().default(false), isLocal: z.boolean().optional() })).default({}), defaultProvider: z.string().optional(), ui: z.object({ theme: z.enum(['dark', 'light']).default('dark'), showCosts: z.boolean().default(true), animations: z.boolean().default(true) }).default({ theme: 'dark', showCosts: true, animations: true }), tools: z.object({ fileOperations: z.boolean().default(true), shellExecution: z.boolean().default(true), webAccess: z.boolean().default(true) }).default({ fileOperations: true, shellExecution: true, webAccess: true }), costs: z.object({ trackUsage: z.boolean().default(true), budgetAlerts: z.boolean().default(true), monthlyLimit: z.number().optional() }).default({ trackUsage: true, budgetAlerts: true }), services: z.object({ googleSearch: z.object({ apiKey: z.string().optional(), searchEngineId: z.string().optional() }).optional(), serpApi: z.object({ apiKey: z.string().optional() }).optional() }).optional() }); export class ConfigManager { store; fileConfig = null; constructor() { this.store = new Conf({ projectName: 'capsule-ai-cli' }); } async loadConfig() { const explorer = cosmiconfig('capsule', { searchPlaces: [ '.capsulerc', '.capsulerc.json', '.capsulerc.yaml', '.capsulerc.yml', '.capsule/config.yaml', '.capsule/config.json', 'capsule.config.js' ] }); try { const result = await explorer.search(); if (result) { const parsed = ConfigSchema.parse(result.config); this.fileConfig = { ...parsed, providers: parsed.providers || {} }; } } catch (error) { console.warn(chalk.yellow('Warning: Invalid config file'), error); } return this.getConfig(); } getConfig() { const stored = this.store.store; const defaultConfig = { providers: {}, ui: { theme: 'dark', showCosts: true, animations: true }, tools: { fileOperations: true, shellExecution: true, webAccess: true }, costs: { trackUsage: true, budgetAlerts: true } }; const mergedConfig = this.mergeConfigs(defaultConfig, stored); if (this.fileConfig) { return this.mergeConfigs(mergedConfig, this.fileConfig); } return mergedConfig; } setConfig(path, value) { this.store.set(path, value); } getApiKey(provider) { const config = this.getConfig(); const providerConfig = config.providers[provider]; if (providerConfig?.apiKey) { return providerConfig.apiKey; } const envVarMap = { openai: 'OPENAI_API_KEY', anthropic: 'ANTHROPIC_API_KEY', google: 'GOOGLE_API_KEY', gemini: 'GEMINI_API_KEY' }; const envVar = envVarMap[provider]; return envVar ? process.env[envVar] : undefined; } validateProvider(provider) { const apiKey = this.getApiKey(provider); if (!apiKey) { return { valid: false, error: `No API key found for ${provider}. Set it with: capsule config set providers.${provider}.apiKey YOUR_KEY` }; } const config = this.getConfig(); const providerConfig = config.providers[provider]; if (providerConfig && !providerConfig.enabled) { return { valid: false, error: `Provider ${provider} is disabled` }; } return { valid: true }; } mergeConfigs(base, override) { return { ...base, ...override, auth: override.auth || base.auth, providers: { ...base.providers, ...override.providers }, ui: { ...base.ui, ...override.ui }, tools: { ...base.tools, ...override.tools }, costs: { ...base.costs, ...override.costs } }; } isAuthenticated() { const config = this.getConfig(); return !!config.auth?.token; } getUserTier() { const config = this.getConfig(); return config.auth?.tier; } } export const configManager = new ConfigManager(); export async function loadConfig() { return configManager.loadConfig(); } //# sourceMappingURL=config.js.map