66 lines
2.0 KiB
TypeScript
66 lines
2.0 KiB
TypeScript
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
import { homedir } from 'node:os';
|
|
import { dirname, resolve } from 'node:path';
|
|
import { type Config, ConfigSchema } from './types.ts';
|
|
|
|
const DEFAULT_CONFIG_PATH = resolve(homedir(), '.nanobot', 'config.json');
|
|
|
|
export function getConfigPath(override?: string): string {
|
|
return override ?? process.env['NANOBOT_CONFIG'] ?? DEFAULT_CONFIG_PATH;
|
|
}
|
|
|
|
export function loadConfig(configPath?: string): Config {
|
|
const path = getConfigPath(configPath);
|
|
|
|
if (!existsSync(path)) {
|
|
return ConfigSchema.parse({});
|
|
}
|
|
|
|
const raw = readFileSync(path, 'utf8');
|
|
let json: unknown;
|
|
try {
|
|
json = JSON.parse(raw);
|
|
} catch {
|
|
console.error(`Failed to parse config at ${path}`);
|
|
return ConfigSchema.parse({});
|
|
}
|
|
|
|
// Apply NANOBOT_ env var overrides before validation
|
|
const merged = applyEnvOverrides(json as Record<string, unknown>);
|
|
return ConfigSchema.parse(merged);
|
|
}
|
|
|
|
export function saveConfig(config: Config, configPath?: string): void {
|
|
const path = getConfigPath(configPath);
|
|
mkdirSync(dirname(path), { recursive: true });
|
|
writeFileSync(path, JSON.stringify(config, null, 2), 'utf8');
|
|
}
|
|
|
|
/** Resolve `~` in workspace path to the real home directory. */
|
|
export function resolveWorkspacePath(raw: string): string {
|
|
if (raw.startsWith('~/') || raw === '~') {
|
|
return resolve(homedir(), raw.slice(2));
|
|
}
|
|
return resolve(raw);
|
|
}
|
|
|
|
function applyEnvOverrides(json: Record<string, unknown>): Record<string, unknown> {
|
|
const out = structuredClone(json);
|
|
|
|
const model = process.env['NANOBOT_MODEL'];
|
|
if (model) {
|
|
const agent = (out['agent'] as Record<string, unknown> | undefined) ?? {};
|
|
agent['model'] = model;
|
|
out['agent'] = agent;
|
|
}
|
|
|
|
const workspace = process.env['NANOBOT_WORKSPACE'];
|
|
if (workspace) {
|
|
const agent = (out['agent'] as Record<string, unknown> | undefined) ?? {};
|
|
agent['workspacePath'] = workspace;
|
|
out['agent'] = agent;
|
|
}
|
|
|
|
return out;
|
|
}
|