voyageai-cli
Version:
CLI for Voyage AI embeddings, reranking, and MongoDB Atlas Vector Search
157 lines (142 loc) • 4.27 kB
JavaScript
'use strict';
const fs = require('fs');
const path = require('path');
const os = require('os');
const CONFIG_DIR = path.join(os.homedir(), '.vai');
const CONFIG_PATH = path.join(CONFIG_DIR, 'config.json');
/**
* Resolve the effective config path.
* - Explicit `configPath` argument wins (used heavily in tests).
* - Then `VAI_CONFIG_PATH` env var (for test isolation / power users).
* - Finally the user-global default in the home directory.
*
* @param {string} [configPath]
* @returns {string}
*/
function resolveConfigPath(configPath) {
if (configPath) return configPath;
if (process.env.VAI_CONFIG_PATH) return process.env.VAI_CONFIG_PATH;
return CONFIG_PATH;
}
// Key mapping: CLI key names → internal config keys
const KEY_MAP = {
'api-key': 'apiKey',
'mongodb-uri': 'mongodbUri',
'default-model': 'defaultModel',
'default-dimensions': 'defaultDimensions',
'base-url': 'baseUrl',
'llm-provider': 'llmProvider',
'llm-api-key': 'llmApiKey',
'llm-model': 'llmModel',
'llm-base-url': 'llmBaseUrl',
'default-db': 'defaultDb',
'default-collection': 'defaultCollection',
'show-cost': 'showCost',
'telemetry': 'telemetry',
};
// Keys whose values should be masked in output
const SECRET_KEYS = new Set(['apiKey', 'mongodbUri', 'llmApiKey']);
/**
* Load config from disk. Returns {} if file doesn't exist.
* @param {string} [configPath] - Override config path (for testing)
* @returns {object}
*/
function loadConfig(configPath) {
const p = resolveConfigPath(configPath);
try {
const raw = fs.readFileSync(p, 'utf-8');
return JSON.parse(raw);
} catch (err) {
if (err.code === 'ENOENT') return {};
throw err;
}
}
/**
* Save config to disk. Creates directory if needed, chmod 600 on the file.
* @param {object} config
* @param {string} [configPath] - Override config path (for testing)
*/
function saveConfig(config, configPath) {
const p = resolveConfigPath(configPath);
const dir = path.dirname(p);
fs.mkdirSync(dir, { recursive: true });
fs.writeFileSync(p, JSON.stringify(config, null, 2) + '\n', 'utf-8');
fs.chmodSync(p, 0o600);
}
/**
* Get a single config value.
* @param {string} key - Internal config key (e.g. 'apiKey')
* @param {string} [configPath] - Override config path (for testing)
* @returns {*}
*/
function getConfigValue(key, configPath) {
const config = loadConfig(configPath);
return config[key];
}
/**
* Set a single config value.
* @param {string} key - Internal config key
* @param {*} value
* @param {string} [configPath] - Override config path (for testing)
*/
function setConfigValue(key, value, configPath) {
const config = loadConfig(configPath);
config[key] = value;
saveConfig(config, configPath);
}
/**
* Delete a single config value.
* @param {string} key - Internal config key
* @param {string} [configPath] - Override config path (for testing)
*/
function deleteConfigValue(key, configPath) {
const config = loadConfig(configPath);
delete config[key];
saveConfig(config, configPath);
}
/**
* Mask a secret string: show first 4 + '...' + last 4 chars.
* If < 10 chars, return '****'.
* @param {string} value
* @returns {string}
*/
function maskSecret(value) {
if (typeof value !== 'string') return String(value);
if (value.length < 10) return '****';
return value.slice(0, 4) + '...' + value.slice(-4);
}
/**
* Check whether this is a first run (no config file exists).
* An empty config file still counts as "not first run."
* @param {string} [configPath] - Override config path (for testing)
* @returns {boolean}
*/
function isFirstRun(configPath) {
const p = resolveConfigPath(configPath);
return !fs.existsSync(p);
}
/**
* Check whether the welcome flow is suppressed.
* @param {string} [configPath] - Override config path (for testing)
* @returns {boolean}
*/
function isWelcomeSuppressed(configPath) {
const noWelcome = process.env.VAI_NO_WELCOME;
if (noWelcome === '1' || noWelcome === 'true') return true;
return !isFirstRun(configPath);
}
module.exports = {
CONFIG_DIR,
CONFIG_PATH,
resolveConfigPath,
KEY_MAP,
SECRET_KEYS,
loadConfig,
saveConfig,
getConfigValue,
setConfigValue,
deleteConfigValue,
maskSecret,
isFirstRun,
isWelcomeSuppressed,
};