UNPKG

codevault

Version:

AI-powered semantic code search via Model Context Protocol

279 lines 10.6 kB
import fs from 'fs'; import path from 'path'; import os from 'os'; const GLOBAL_CONFIG_DIR = path.join(os.homedir(), '.codevault'); const GLOBAL_CONFIG_FILE = path.join(GLOBAL_CONFIG_DIR, 'config.json'); const PROJECT_CONFIG_FILE = '.codevault/config.json'; /** * Read global configuration from ~/.codevault/config.json * @readonly Never modifies files */ export function readGlobalConfig() { try { if (!fs.existsSync(GLOBAL_CONFIG_FILE)) { return null; } const content = fs.readFileSync(GLOBAL_CONFIG_FILE, 'utf8'); return JSON.parse(content); } catch (error) { console.warn(`Warning: Failed to read global config: ${error.message}`); return null; } } /** * Read project-local configuration from .codevault/config.json * @readonly Never modifies files */ export function readProjectConfig(basePath = '.') { try { const configPath = path.join(path.resolve(basePath), PROJECT_CONFIG_FILE); if (!fs.existsSync(configPath)) { return null; } const content = fs.readFileSync(configPath, 'utf8'); return JSON.parse(content); } catch (error) { console.warn(`Warning: Failed to read project config: ${error.message}`); return null; } } /** * Read configuration from environment variables * @readonly Never modifies files or environment */ export function readEnvConfig() { const config = {}; // Provider settings - New variables with backward compatibility if (process.env.CODEVAULT_EMBEDDING_API_KEY || process.env.OPENAI_API_KEY) { config.providers = config.providers || {}; config.providers.openai = config.providers.openai || {}; config.providers.openai.apiKey = process.env.CODEVAULT_EMBEDDING_API_KEY || process.env.OPENAI_API_KEY; } if (process.env.CODEVAULT_EMBEDDING_BASE_URL || process.env.OPENAI_BASE_URL) { config.providers = config.providers || {}; config.providers.openai = config.providers.openai || {}; config.providers.openai.baseUrl = process.env.CODEVAULT_EMBEDDING_BASE_URL || process.env.OPENAI_BASE_URL; } if (process.env.CODEVAULT_EMBEDDING_MODEL || process.env.CODEVAULT_OPENAI_EMBEDDING_MODEL || process.env.OPENAI_MODEL) { config.providers = config.providers || {}; config.providers.openai = config.providers.openai || {}; config.providers.openai.model = process.env.CODEVAULT_EMBEDDING_MODEL || process.env.CODEVAULT_OPENAI_EMBEDDING_MODEL || process.env.OPENAI_MODEL; } // Dimensions - New variable with backward compatibility if (process.env.CODEVAULT_EMBEDDING_DIMENSIONS || process.env.CODEVAULT_DIMENSIONS) { const dims = parseInt(process.env.CODEVAULT_EMBEDDING_DIMENSIONS || process.env.CODEVAULT_DIMENSIONS || '0', 10); if (!isNaN(dims) && dims > 0) { if (config.providers?.openai) { config.providers.openai.dimensions = dims; } } } // Max tokens - New variable with backward compatibility if (process.env.CODEVAULT_EMBEDDING_MAX_TOKENS || process.env.CODEVAULT_MAX_TOKENS) { const tokens = parseInt(process.env.CODEVAULT_EMBEDDING_MAX_TOKENS || process.env.CODEVAULT_MAX_TOKENS || '0', 10); if (!isNaN(tokens) && tokens > 0) { config.maxTokens = tokens; } } // Rate limiting - New variables with backward compatibility if (process.env.CODEVAULT_EMBEDDING_RATE_LIMIT_RPM || process.env.CODEVAULT_RATE_LIMIT_RPM || process.env.CODEVAULT_RATE_LIMIT) { const rpm = parseInt(process.env.CODEVAULT_EMBEDDING_RATE_LIMIT_RPM || process.env.CODEVAULT_RATE_LIMIT_RPM || process.env.CODEVAULT_RATE_LIMIT || '0', 10); if (!isNaN(rpm) && rpm > 0) { config.rateLimit = config.rateLimit || {}; config.rateLimit.rpm = rpm; } } if (process.env.CODEVAULT_EMBEDDING_RATE_LIMIT_TPM || process.env.CODEVAULT_RATE_LIMIT_TPM) { const tpm = parseInt(process.env.CODEVAULT_EMBEDDING_RATE_LIMIT_TPM || process.env.CODEVAULT_RATE_LIMIT_TPM || '0', 10); if (!isNaN(tpm) && tpm > 0) { config.rateLimit = config.rateLimit || {}; config.rateLimit.tpm = tpm; } } // Encryption if (process.env.CODEVAULT_ENCRYPTION_KEY) { config.encryption = config.encryption || {}; config.encryption.key = process.env.CODEVAULT_ENCRYPTION_KEY; config.encryption.enabled = true; } // Reranker if (process.env.CODEVAULT_RERANK_API_URL) { config.reranker = config.reranker || {}; config.reranker.apiUrl = process.env.CODEVAULT_RERANK_API_URL; } if (process.env.CODEVAULT_RERANK_API_KEY) { config.reranker = config.reranker || {}; config.reranker.apiKey = process.env.CODEVAULT_RERANK_API_KEY; } if (process.env.CODEVAULT_RERANK_MODEL) { config.reranker = config.reranker || {}; config.reranker.model = process.env.CODEVAULT_RERANK_MODEL; } // Chat LLM Configuration if (process.env.CODEVAULT_CHAT_API_KEY || process.env.OPENAI_API_KEY) { config.chatLLM = config.chatLLM || {}; config.chatLLM.openai = config.chatLLM.openai || {}; config.chatLLM.openai.apiKey = process.env.CODEVAULT_CHAT_API_KEY || process.env.OPENAI_API_KEY; } if (process.env.CODEVAULT_CHAT_BASE_URL || process.env.OPENAI_BASE_URL) { config.chatLLM = config.chatLLM || {}; config.chatLLM.openai = config.chatLLM.openai || {}; config.chatLLM.openai.baseUrl = process.env.CODEVAULT_CHAT_BASE_URL || process.env.OPENAI_BASE_URL; } if (process.env.CODEVAULT_CHAT_MODEL || process.env.CODEVAULT_OPENAI_CHAT_MODEL) { config.chatLLM = config.chatLLM || {}; config.chatLLM.openai = config.chatLLM.openai || {}; config.chatLLM.openai.model = process.env.CODEVAULT_CHAT_MODEL || process.env.CODEVAULT_OPENAI_CHAT_MODEL; } if (process.env.CODEVAULT_CHAT_MAX_TOKENS) { const maxTokens = parseInt(process.env.CODEVAULT_CHAT_MAX_TOKENS, 10); if (!isNaN(maxTokens) && maxTokens > 0) { config.chatLLM = config.chatLLM || {}; config.chatLLM.openai = config.chatLLM.openai || {}; config.chatLLM.openai.maxTokens = maxTokens; } } if (process.env.CODEVAULT_CHAT_TEMPERATURE) { const temperature = parseFloat(process.env.CODEVAULT_CHAT_TEMPERATURE); if (!isNaN(temperature)) { config.chatLLM = config.chatLLM || {}; config.chatLLM.openai = config.chatLLM.openai || {}; config.chatLLM.openai.temperature = temperature; } } return config; } /** * Deep merge configuration objects * Later configs override earlier ones */ function deepMerge(...configs) { const result = {}; for (const config of configs) { if (!config) continue; if (config.defaultProvider) { result.defaultProvider = config.defaultProvider; } if (config.maxTokens) { result.maxTokens = config.maxTokens; } if (config.providers) { result.providers = result.providers || {}; if (config.providers.openai) { result.providers.openai = { ...result.providers.openai, ...config.providers.openai }; } } if (config.rateLimit) { result.rateLimit = { ...result.rateLimit, ...config.rateLimit }; } if (config.encryption) { result.encryption = { ...result.encryption, ...config.encryption }; } if (config.reranker) { result.reranker = { ...result.reranker, ...config.reranker }; } if (config.chatLLM) { result.chatLLM = result.chatLLM || {}; if (config.chatLLM.openai) { result.chatLLM.openai = { ...result.chatLLM.openai, ...config.chatLLM.openai }; } } } return result; } /** * Load merged configuration from all sources * Priority: env > project > global * * @readonly Never modifies config files * @param basePath Project path for project-local config * @returns Merged configuration (in-memory only) */ export function loadConfig(basePath = '.') { const global = readGlobalConfig(); const project = readProjectConfig(basePath); const env = readEnvConfig(); // Merge with priority: env overrides project overrides global return deepMerge(global, project, env); } /** * Get configuration sources for debugging * @readonly Never modifies files */ export function getConfigSources(basePath = '.') { return { global: readGlobalConfig(), project: readProjectConfig(basePath), env: readEnvConfig() }; } /** * Write global configuration (CLI only) * This is the ONLY function that writes to disk */ export function saveGlobalConfig(config) { // Ensure directory exists if (!fs.existsSync(GLOBAL_CONFIG_DIR)) { fs.mkdirSync(GLOBAL_CONFIG_DIR, { recursive: true }); } // Write config fs.writeFileSync(GLOBAL_CONFIG_FILE, JSON.stringify(config, null, 2)); } /** * Write project-local configuration (CLI only) * This is the ONLY function that writes project config */ export function saveProjectConfig(config, basePath = '.') { const configDir = path.join(path.resolve(basePath), '.codevault'); const configPath = path.join(configDir, 'config.json'); // Ensure directory exists if (!fs.existsSync(configDir)) { fs.mkdirSync(configDir, { recursive: true }); } // Write config fs.writeFileSync(configPath, JSON.stringify(config, null, 2)); } /** * Check if global config exists */ export function hasGlobalConfig() { return fs.existsSync(GLOBAL_CONFIG_FILE); } /** * Check if project config exists */ export function hasProjectConfig(basePath = '.') { const configPath = path.join(path.resolve(basePath), PROJECT_CONFIG_FILE); return fs.existsSync(configPath); } /** * Get global config file path */ export function getGlobalConfigPath() { return GLOBAL_CONFIG_FILE; } /** * Get project config file path */ export function getProjectConfigPath(basePath = '.') { return path.join(path.resolve(basePath), PROJECT_CONFIG_FILE); } //# sourceMappingURL=loader.js.map