const fs = require("fs"); const path = require("path"); function resolveProjectRoot() { const envRoot = process.env.SGCLAW_PROJECT_ROOT; if (envRoot && fs.existsSync(envRoot)) { return path.resolve(envRoot); } const configPath = resolveConfigPath(); if (configPath && fs.existsSync(configPath)) { return path.dirname(configPath); } return path.resolve(__dirname); } function resolveConfigPath() { const envPath = process.env.SGCLAW_CONFIG_PATH; if (envPath && fs.existsSync(envPath)) { return path.resolve(envPath); } const candidates = [ path.resolve(__dirname, "..", "..", "sgclaw_config.json"), path.resolve(__dirname, "..", "sgclaw_config.json"), path.resolve(__dirname, "sgclaw_config.json"), ]; for (const p of candidates) { if (fs.existsSync(p)) return p; } return null; } function loadConfig() { const configPath = resolveConfigPath(); if (!configPath) { throw new Error( "sgclaw_config.json not found. Set SGCLAW_CONFIG_PATH or place it in the project root." ); } const raw = fs.readFileSync(configPath, "utf-8"); const config = JSON.parse(raw); const apiKey = config.apiKey || ""; const baseUrl = config.baseUrl || ""; const model = config.model || ""; if (!apiKey) throw new Error("sgclaw_config.json: 'apiKey' is required"); if (!baseUrl) throw new Error("sgclaw_config.json: 'baseUrl' is required"); if (!model) throw new Error("sgclaw_config.json: 'model' is required"); return { apiKey, baseUrl: normalizeBaseUrl(baseUrl), model, projectRoot: resolveProjectRoot(), configPath, }; } function normalizeBaseUrl(url) { url = url.replace(/\/+$/, ""); if (!url.endsWith("/v1")) url = url + "/v1"; return url; } function getDefaults() { const config = loadConfig(); const projectRoot = config.projectRoot; return { outputRoot: path.join(projectRoot, "examples", "generated_scene_platform"), lessonsPath: path.join( projectRoot, "docs", "superpowers", "references", "tq-lineloss-lessons-learned.toml" ), llmBaseUrl: config.baseUrl, llmModel: config.model, }; } module.exports = { loadConfig, getDefaults, resolveProjectRoot, resolveConfigPath };