import fs from 'fs/promises'; import path from 'path'; import os from 'os'; import ini from 'ini'; import { fileExists } from './fs.js'; import { KnownError } from './error.js'; const { hasOwnProperty } = Object.prototype; const hasOwn = (object: unknown, key: PropertyKey) => hasOwnProperty.call(object, key); const parseAssert = ( name: string, condition: any, message: string, ) => { if (!condition) { throw new KnownError(`Invalid config property ${name}: ${message}`); } }; const configParsers = { OPENAI_KEY(key: string) { parseAssert('OPENAI_KEY', key, 'Cannot be empty'); parseAssert('OPENAI_KEY', key.startsWith('sk-'), 'Must start with "sk-"'); parseAssert('OPENAI_KEY', key.length === 51, 'Must be 51 characters long'); return key; }, generate(key: string) { parseAssert('generate', key, 'Cannot be empty'); parseAssert('generate', /^\d+$/.test(key), 'Must be an integer'); const parsed = Number(key); parseAssert('generate', parsed > 0, 'Must be greater than 0'); parseAssert('generate', parsed <= 5, 'Must be less or equal to 5'); return parsed; }, } as const; type ValidKeys = keyof typeof configParsers; type ConfigType = { [key in ValidKeys]?: ReturnType; }; const configPath = path.join(os.homedir(), '.aicommits'); export const getConfig = async (): Promise => { const configExists = await fileExists(configPath); if (!configExists) { return {}; } const configString = await fs.readFile(configPath, 'utf8'); const config = ini.parse(configString); for (const key of Object.keys(config)) { if (hasOwn(configParsers, key)) { const parsed = configParsers[key as ValidKeys](config[key]); config[key as ValidKeys] = parsed; } else { console.warn(`\n⚠️ Unknown config property "${key}" found in ${configPath}`); } } return config; }; export const setConfigs = async ( keyValues: [key: string, value: string][], ) => { const config = await getConfig(); for (const [key, value] of keyValues) { if (!hasOwn(configParsers, key)) { throw new KnownError(`Invalid config property: ${key}`); } const parsed = configParsers[key as ValidKeys](value); config[key as ValidKeys] = parsed as any; } await fs.writeFile(configPath, ini.stringify(config), 'utf8'); };