feat: add config-loader.js and initial server test
Add config-loader.js module for loading sgclaw_config.json credentials and resolving project root directory. Add initial Rust source-guard test to verify server file paths exist. 🤖 Generated with [Qoder][https://qoder.com]
This commit is contained in:
89
frontend/scene-generator/config-loader.js
Normal file
89
frontend/scene-generator/config-loader.js
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
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 };
|
||||||
39
tests/scene_generator_server_test.rs
Normal file
39
tests/scene_generator_server_test.rs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
use std::fs;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn scene_generator_server_files_exist() {
|
||||||
|
let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||||
|
let server_js = manifest_dir
|
||||||
|
.join("frontend")
|
||||||
|
.join("scene-generator")
|
||||||
|
.join("server.js");
|
||||||
|
let config_loader = manifest_dir
|
||||||
|
.join("frontend")
|
||||||
|
.join("scene-generator")
|
||||||
|
.join("config-loader.js");
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
server_js.exists(),
|
||||||
|
"server.js not found at {:?}",
|
||||||
|
server_js
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
config_loader.exists(),
|
||||||
|
"config-loader.js not found at {:?}",
|
||||||
|
config_loader
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sgclaw_config_is_readable() {
|
||||||
|
let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||||
|
let config_path = manifest_dir.join("sgclaw_config.json");
|
||||||
|
let content = fs::read_to_string(&config_path)
|
||||||
|
.unwrap_or_else(|err| panic!("sgclaw_config.json not found: {}", err));
|
||||||
|
let parsed: serde_json::Value =
|
||||||
|
serde_json::from_str(&content).expect("should be valid JSON");
|
||||||
|
assert!(parsed.get("apiKey").is_some(), "missing apiKey");
|
||||||
|
assert!(parsed.get("baseUrl").is_some(), "missing baseUrl");
|
||||||
|
assert!(parsed.get("model").is_some(), "missing model");
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user