import { readFileSync, existsSync } from 'node:fs';
import { resolve } from 'node:path';
function loadEnvFile(): void {
const envPath = resolve(process.cwd(), '.env');
if (!existsSync(envPath)) return;
const content = readFileSync(envPath, 'utf-8');
for (const line of content.split('\n')) {
const trimmed = line.trim();
if (!trimmed || trimmed.startsWith('#')) continue;
const eqIdx = trimmed.indexOf('=');
if (eqIdx === -1) continue;
const key = trimmed.slice(0, eqIdx).trim();
const value = trimmed.slice(eqIdx + 1).trim();
if (!process.env[key]) {
process.env[key] = value;
}
}
}
loadEnvFile();
function env(key: string, fallback: string): string {
return process.env[key] ?? fallback;
}
function envInt(key: string, fallback: number): number {
const v = process.env[key];
return v ? parseInt(v, 10) : fallback;
}
export const config = {
auth: {
token: env('MCP_AUTH_TOKEN', ''),
allowedIps: env('MCP_ALLOWED_IPS', '127.0.0.1,::1')
.split(',')
.map((s) => s.trim())
.filter(Boolean),
},
ollama: {
baseUrl: env('OLLAMA_BASE_URL', 'http://localhost:11434'),
primaryModel: env('PRIMARY_MODEL', 'llama3.1:8b-instruct-q4_K_M'),
fallbackModel: env('FALLBACK_MODEL', 'qwen2.5:7b-instruct-q4_K_M'),
embeddingModel: env('EMBEDDING_MODEL', 'nomic-embed-text:v1.5'),
chatTimeout: envInt('OLLAMA_CHAT_TIMEOUT', 60000),
embedTimeout: envInt('OLLAMA_EMBED_TIMEOUT', 30000),
},
server: {
port: envInt('PORT', 3100),
host: env('HOST', '0.0.0.0'),
},
db: {
path: env('DB_PATH', './data/context-hub.db'),
},
cache: {
ttlMs: envInt('CACHE_TTL_MS', 300000),
maxEntries: envInt('CACHE_MAX_ENTRIES', 100),
},
log: {
level: env('LOG_LEVEL', 'info'),
},
proxy: {
servers: parseProxyServers(env('PROXY_SERVERS', '{}')),
},
dashboard: {
username: env('DASHBOARD_USERNAME', 'admin'),
password: env('DASHBOARD_PASSWORD', ''),
sessionTtlMs: envInt('DASHBOARD_SESSION_TTL_MS', 86400000),
cookieSecure: env('DASHBOARD_COOKIE_SECURE', 'true') === 'true',
metricsSnapshotIntervalMs: envInt('METRICS_SNAPSHOT_INTERVAL_MS', 300000),
},
} as const;
function parseProxyServers(
raw: string
): Record<string, { command: string; args: string[]; env?: Record<string, string> }> {
try {
return JSON.parse(raw);
} catch {
return {};
}
}