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

94
tests/core/config.test.ts Normal file
View File

@@ -0,0 +1,94 @@
import { describe, it, expect, beforeEach, afterEach } from "bun:test";
import { mkdir, writeFile, rm } from "node:fs/promises";
import { join } from "node:path";
import { loadConfig, findProjectRoot, getRuneDir } from "../../src/core/config.ts";
const TMP_DIR = join(import.meta.dir, "__tmp_config_test__");
beforeEach(async () => {
await mkdir(TMP_DIR, { recursive: true });
});
afterEach(async () => {
await rm(TMP_DIR, { recursive: true, force: true });
});
describe("findProjectRoot", () => {
it("当前目录存在 .rune/ 时返回当前目录", async () => {
await mkdir(join(TMP_DIR, ".rune"));
expect(findProjectRoot(TMP_DIR)).toBe(TMP_DIR);
});
it("子目录中向上查找到 .rune/", async () => {
await mkdir(join(TMP_DIR, ".rune"));
const sub = join(TMP_DIR, "src", "commands");
await mkdir(sub, { recursive: true });
expect(findProjectRoot(sub)).toBe(TMP_DIR);
});
it("找不到 .rune/ 时返回 null", () => {
expect(findProjectRoot("/tmp/__nonexistent__")).toBeNull();
});
});
describe("loadConfig", () => {
it("无配置文件时返回默认配置", async () => {
await mkdir(join(TMP_DIR, ".rune"));
const config = await loadConfig(TMP_DIR);
expect(config.stages.discuss).toBeDefined();
expect(config.stages.plan).toBeDefined();
expect(config.stages.build).toBeDefined();
expect(config.stages.archive).toBeDefined();
});
it("用户配置覆盖默认配置(全量替换)", async () => {
const runeDir = join(TMP_DIR, ".rune");
await mkdir(runeDir, { recursive: true });
await writeFile(
join(runeDir, "config.yaml"),
`stages:
discuss:
prompt: 自定义讨论提示词
`,
);
const config = await loadConfig(TMP_DIR);
expect(config.stages.discuss!.prompt).toBe("自定义讨论提示词");
expect(config.stages.plan).toBeDefined();
expect(config.stages.build).toBeDefined();
expect(config.stages.archive).toBeDefined();
});
it("用户配置 plan 时完全替换内置 documents", async () => {
const runeDir = join(TMP_DIR, ".rune");
await mkdir(runeDir, { recursive: true });
await writeFile(
join(runeDir, "config.yaml"),
`stages:
plan:
documents:
- name: spec
prompt: 生成规格文档
`,
);
const config = await loadConfig(TMP_DIR);
expect(config.stages.plan!.documents).toHaveLength(1);
expect(config.stages.plan!.documents[0].name).toBe("spec");
});
it("YAML 解析错误时返回默认配置", async () => {
const runeDir = join(TMP_DIR, ".rune");
await mkdir(runeDir, { recursive: true });
await writeFile(
join(runeDir, "config.yaml"),
`stages: [invalid yaml {{{`,
);
const config = await loadConfig(TMP_DIR);
expect(config.stages.discuss).toBeDefined();
});
});
describe("getRuneDir", () => {
it("返回 .rune 目录路径", () => {
expect(getRuneDir("/project")).toBe("/project/.rune");
});
});