diff --git a/src/core/assembler.ts b/src/core/assembler.ts index 9bbff88..eba93f8 100644 --- a/src/core/assembler.ts +++ b/src/core/assembler.ts @@ -136,29 +136,30 @@ export async function assembleArchivePrompt( hint: "请在 .rune/config.yaml 中配置 stages.archive", }); - const changeDir = getChangeDir(projectRoot, changeName); - const taskPath = join(changeDir, "task.md"); - const parts: string[] = []; parts.push(`# 归档阶段:${changeName}\n`); - try { - const taskContent = await readFile(taskPath, "utf-8"); - const tasks = parseTasks(taskContent); - const incompleteTasks = tasks.filter((t) => !t.checked); - if (incompleteTasks.length > 0) { - parts.push("## ⚠️ 警告:存在未完成的任务\n"); - parts.push(`以下 ${incompleteTasks.length} 个任务尚未完成:`); - for (const t of incompleteTasks) { - parts.push(`- [ ] ${t.text}`); + if (config.metadata?.tracked) { + const changeDir = getChangeDir(projectRoot, changeName); + const taskPath = join(changeDir, "task.md"); + try { + const taskContent = await readFile(taskPath, "utf-8"); + const tasks = parseTasks(taskContent); + const incompleteTasks = tasks.filter((t) => !t.checked); + if (incompleteTasks.length > 0) { + parts.push("## ⚠️ 警告:存在未完成的任务\n"); + parts.push(`以下 ${incompleteTasks.length} 个任务尚未完成:`); + for (const t of incompleteTasks) { + parts.push(`- [ ] ${t.text}`); + } + parts.push(""); + parts.push("请询问用户是否确认在任务未全部完成的情况下归档。"); + parts.push("如用户确认,则继续归档;否则中止并返回构建阶段。"); + parts.push(""); } - parts.push(""); - parts.push("请询问用户是否确认在任务未全部完成的情况下归档。"); - parts.push("如用户确认,则继续归档;否则中止并返回构建阶段。"); - parts.push(""); + } catch { + // task.md 不存在时不追加警告 } - } catch { - // task.md 不存在时不追加警告 } parts.push(archive.prompt); diff --git a/tests/core/assembler.test.ts b/tests/core/assembler.test.ts index d87adba..2b56b01 100644 --- a/tests/core/assembler.test.ts +++ b/tests/core/assembler.test.ts @@ -204,6 +204,44 @@ describe("assembleArchivePrompt", () => { expect(prompt).toContain("user-auth"); expect(prompt).toContain("归档"); }); + + it("tracked=false 时不读取 task.md,只输出通用提示词", async () => { + const changeDir = join(TMP_DIR, ".rune", "changes", "user-auth"); + await mkdir(changeDir, { recursive: true }); + await writeFile(join(changeDir, "task.md"), "- [ ] 未完成任务"); + const config: RuneConfig = { + stages: { archive: { prompt: "确认归档" } }, + metadata: { tracked: false }, + }; + const prompt = await assembleArchivePrompt(config, TMP_DIR, "user-auth"); + expect(prompt).toContain("确认归档"); + expect(prompt).not.toContain("未完成"); + }); + + it("tracked=true 时读取 task.md 并注入未完成任务警告", async () => { + const changeDir = join(TMP_DIR, ".rune", "changes", "user-auth"); + await mkdir(changeDir, { recursive: true }); + await writeFile(join(changeDir, "task.md"), "- [ ] 未完成任务"); + const config: RuneConfig = { + stages: { archive: { prompt: "归档阶段" } }, + metadata: { tracked: true }, + }; + const prompt = await assembleArchivePrompt(config, TMP_DIR, "user-auth"); + expect(prompt).toContain("未完成"); + expect(prompt).toContain("未完成任务"); + }); + + it("tracked=true 且所有任务完成时不注入警告", async () => { + const changeDir = join(TMP_DIR, ".rune", "changes", "user-auth"); + await mkdir(changeDir, { recursive: true }); + await writeFile(join(changeDir, "task.md"), "- [x] 已完成任务"); + const config: RuneConfig = { + stages: { archive: { prompt: "归档阶段" } }, + metadata: { tracked: true }, + }; + const prompt = await assembleArchivePrompt(config, TMP_DIR, "user-auth"); + expect(prompt).not.toContain("未完成"); + }); }); describe("命令前缀替换", () => {