feat: scanChanges 扩展返回 DocumentStatus、planCompleted、buildUnlocked

This commit is contained in:
2026-06-09 10:43:25 +08:00
parent 0d2b117680
commit 1c7a8b3322
2 changed files with 129 additions and 7 deletions

View File

@@ -2,6 +2,7 @@ import { describe, it, expect, beforeEach, afterEach } from "bun:test";
import { mkdir, writeFile, rm } from "node:fs/promises";
import { join } from "node:path";
import { scanChanges, scanArchives } from "../../src/core/scanner.ts";
import type { RuneConfig } from "../../src/types.ts";
const TMP_DIR = join(import.meta.dir, "__tmp_scanner_test__");
@@ -32,8 +33,11 @@ describe("scanChanges", () => {
const changes = await scanChanges(TMP_DIR);
expect(changes).toHaveLength(1);
expect(changes[0].name).toBe("user-auth");
expect(changes[0].documents).toContain("design.md");
expect(changes[0].documents).toContain("task.md");
const docNames = changes[0].documents.map((d) => `${d.name}.md`);
expect(docNames).toContain("design.md");
expect(docNames).toContain("task.md");
expect(changes[0].planCompleted).toBe(false);
expect(changes[0].buildUnlocked).toBe(false);
expect(changes[0].taskProgress).toEqual({ completed: 1, total: 2 });
});
@@ -57,6 +61,93 @@ describe("scanChanges", () => {
const changes = await scanChanges(TMP_DIR);
expect(changes).toHaveLength(2);
});
it("返回 DocumentStatus 含 completed 和 dependMet", async () => {
const changesDir = join(TMP_DIR, ".rune", "changes");
await mkdir(join(changesDir, "user-auth"), { recursive: true });
await writeFile(join(changesDir, "user-auth", "design.md"), "# 设计");
const config: RuneConfig = {
stages: {
plan: {
documents: [
{ name: "design", prompt: "生成设计" },
{ name: "task", prompt: "生成任务", depend: ["design"] },
],
},
},
};
const changes = await scanChanges(TMP_DIR, config);
expect(changes).toHaveLength(1);
expect(changes[0].documents).toHaveLength(2);
expect(changes[0].documents[0]).toEqual({
name: "design",
completed: true,
dependMet: true,
});
expect(changes[0].documents[1]).toEqual({
name: "task",
completed: false,
dependMet: true,
});
expect(changes[0].planCompleted).toBe(false);
expect(changes[0].buildUnlocked).toBe(false);
});
it("depend 未满足时 dependMet 为 false", async () => {
const changesDir = join(TMP_DIR, ".rune", "changes");
await mkdir(join(changesDir, "user-auth"), { recursive: true });
const config: RuneConfig = {
stages: {
plan: {
documents: [
{ name: "design", prompt: "生成设计" },
{ name: "task", prompt: "生成任务", depend: ["design"] },
],
},
},
};
const changes = await scanChanges(TMP_DIR, config);
expect(changes[0].documents[1].dependMet).toBe(false);
});
it("所有文档完成时 planCompleted 和 buildUnlocked 为 true", async () => {
const changesDir = join(TMP_DIR, ".rune", "changes");
await mkdir(join(changesDir, "user-auth"), { recursive: true });
await writeFile(join(changesDir, "user-auth", "design.md"), "# 设计");
await writeFile(join(changesDir, "user-auth", "task.md"), "- [ ] 任务");
const config: RuneConfig = {
stages: {
plan: {
documents: [
{ name: "design", prompt: "生成设计" },
{ name: "task", prompt: "生成任务" },
],
},
},
};
const changes = await scanChanges(TMP_DIR, config);
expect(changes[0].planCompleted).toBe(true);
expect(changes[0].buildUnlocked).toBe(true);
});
it("无 config 时使用文件扫描兼容模式", async () => {
const changesDir = join(TMP_DIR, ".rune", "changes");
await mkdir(join(changesDir, "feature-a"), { recursive: true });
await writeFile(join(changesDir, "feature-a", "design.md"), "# 设计");
const changes = await scanChanges(TMP_DIR);
expect(changes).toHaveLength(1);
expect(changes[0].documents[0].name).toBe("design");
expect(changes[0].documents[0].completed).toBe(true);
expect(changes[0].planCompleted).toBe(false);
expect(changes[0].buildUnlocked).toBe(false);
});
});
describe("scanArchives", () => {