From 3789d0a7b32dbfe0f227e17807587ba66e54f581 Mon Sep 17 00:00:00 2001 From: lanyuanxiaoyao Date: Wed, 10 Jun 2026 09:10:17 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20status=20=E5=91=BD=E4=BB=A4=E6=A0=B9?= =?UTF-8?q?=E6=8D=AE=20tracked=20=E5=86=B3=E5=AE=9A=E6=98=AF=E5=90=A6?= =?UTF-8?q?=E6=89=AB=E6=8F=8F=20task.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/scanner.ts | 18 +++++----- tests/core/scanner.test.ts | 70 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 77 insertions(+), 11 deletions(-) diff --git a/src/core/scanner.ts b/src/core/scanner.ts index 13c8217..e15e211 100644 --- a/src/core/scanner.ts +++ b/src/core/scanner.ts @@ -44,14 +44,16 @@ export async function scanChanges( const buildUnlocked = planCompleted; let taskProgress: { completed: number; total: number } | null = null; - const taskFile = files.find((d) => d === "task.md"); - if (taskFile) { - const content = await readFile(join(entryPath, taskFile), "utf-8"); - const tasks = parseTasks(content); - taskProgress = { - completed: tasks.filter((t) => t.checked).length, - total: tasks.length, - }; + if (config?.metadata?.tracked) { + const taskFile = files.find((d) => d === "task.md"); + if (taskFile) { + const content = await readFile(join(entryPath, taskFile), "utf-8"); + const tasks = parseTasks(content); + taskProgress = { + completed: tasks.filter((t) => t.checked).length, + total: tasks.length, + }; + } } results.push({ diff --git a/tests/core/scanner.test.ts b/tests/core/scanner.test.ts index 8e3b56c..79c633a 100644 --- a/tests/core/scanner.test.ts +++ b/tests/core/scanner.test.ts @@ -27,14 +27,25 @@ describe("scanChanges", () => { await writeFile(join(changesDir, "user-auth", "design.md"), "# 设计"); await writeFile(join(changesDir, "user-auth", "task.md"), `- [x] 任务一\n- [ ] 任务二`); - const changes = await scanChanges(TMP_DIR); + const config: RuneConfig = { + stages: { + plan: { + documents: [ + { name: "design", prompt: "生成设计" }, + { name: "task", prompt: "生成任务" }, + ], + }, + }, + metadata: { tracked: true }, + }; + const changes = await scanChanges(TMP_DIR, config); expect(changes).toHaveLength(1); expect(changes[0].name).toBe("user-auth"); 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].planCompleted).toBe(true); + expect(changes[0].buildUnlocked).toBe(true); expect(changes[0].taskProgress).toEqual({ completed: 1, total: 2 }); }); @@ -145,6 +156,59 @@ describe("scanChanges", () => { expect(changes[0].planCompleted).toBe(false); expect(changes[0].buildUnlocked).toBe(false); }); + + it("tracked=false 时不扫描 task.md,taskProgress 为 null", async () => { + const changesDir = join(TMP_DIR, ".rune", "changes"); + await mkdir(join(changesDir, "test-change"), { recursive: true }); + await writeFile(join(changesDir, "test-change", "design.md"), "# 设计"); + await writeFile(join(changesDir, "test-change", "task.md"), "- [x] 完成\n- [ ] 未完成"); + const config: RuneConfig = { + stages: { + plan: { + documents: [{ name: "design", prompt: "生成设计" }], + }, + }, + metadata: { tracked: false }, + }; + const results = await scanChanges(TMP_DIR, config); + expect(results[0].taskProgress).toBeNull(); + }); + + it("tracked=true 时扫描 task.md,taskProgress 有值", async () => { + const changesDir = join(TMP_DIR, ".rune", "changes"); + await mkdir(join(changesDir, "test-change2"), { recursive: true }); + await writeFile(join(changesDir, "test-change2", "design.md"), "# 设计"); + await writeFile(join(changesDir, "test-change2", "task.md"), "- [x] 完成\n- [ ] 未完成"); + const config: RuneConfig = { + stages: { + plan: { + documents: [ + { name: "design", prompt: "生成设计" }, + { name: "task", prompt: "生成任务" }, + ], + }, + }, + metadata: { tracked: true }, + }; + const results = await scanChanges(TMP_DIR, config); + expect(results[0].taskProgress).toEqual({ completed: 1, total: 2 }); + }); + + it("tracked 未配置(undefined)时不扫描 task.md", async () => { + const changesDir = join(TMP_DIR, ".rune", "changes"); + await mkdir(join(changesDir, "test-change3"), { recursive: true }); + await writeFile(join(changesDir, "test-change3", "design.md"), "# 设计"); + await writeFile(join(changesDir, "test-change3", "task.md"), "- [x] 完成"); + const config: RuneConfig = { + stages: { + plan: { + documents: [{ name: "design", prompt: "生成设计" }], + }, + }, + }; + const results = await scanChanges(TMP_DIR, config); + expect(results[0].taskProgress).toBeNull(); + }); }); describe("scanArchives", () => {