feat: 配置加载模块

This commit is contained in:
2026-06-08 17:20:11 +08:00
parent ca7a86e888
commit a6ab990bf6
2 changed files with 160 additions and 0 deletions

66
src/core/config.ts Normal file
View File

@@ -0,0 +1,66 @@
import { existsSync } from "node:fs";
import { readFile } from "node:fs/promises";
import { join, dirname } from "node:path";
import { parse as parseYaml } from "yaml";
import { defaultConfig } from "../defaults/config.ts";
import type { RuneConfig } from "../types.ts";
import { RUNE_DIR, CONFIG_FILE, CHANGES_DIR, ARCHIVE_DIR } from "../types.ts";
export function findProjectRoot(
startDir: string = process.cwd(),
): string | null {
let dir = startDir;
while (true) {
if (existsSync(join(dir, RUNE_DIR))) {
return dir;
}
const parent = dirname(dir);
if (parent === dir) return null;
dir = parent;
}
}
export async function loadConfig(projectRoot: string): Promise<RuneConfig> {
const configPath = join(projectRoot, RUNE_DIR, CONFIG_FILE);
try {
const content = await readFile(configPath, "utf-8");
const userConfig = parseYaml(content) as Partial<RuneConfig> | null;
if (!userConfig?.stages) {
return structuredClone(defaultConfig);
}
return mergeConfig(userConfig);
} catch {
return structuredClone(defaultConfig);
}
}
function mergeConfig(userConfig: Partial<RuneConfig>): RuneConfig {
const result: RuneConfig = { stages: {} };
const stageKeys = ["discuss", "plan", "build", "archive"] as const;
for (const stage of stageKeys) {
if (userConfig.stages?.[stage]) {
result.stages[stage] = userConfig.stages[stage]!;
} else if (defaultConfig.stages[stage]) {
result.stages[stage] = structuredClone(defaultConfig.stages[stage]!);
}
}
return result;
}
export function getRuneDir(projectRoot: string): string {
return join(projectRoot, RUNE_DIR);
}
export function getChangesDir(projectRoot: string): string {
return join(projectRoot, RUNE_DIR, CHANGES_DIR);
}
export function getArchiveDir(projectRoot: string): string {
return join(projectRoot, RUNE_DIR, ARCHIVE_DIR);
}
export function getChangeDir(projectRoot: string, changeName: string): string {
return join(projectRoot, RUNE_DIR, CHANGES_DIR, changeName);
}