feat: archive 阶段根据 tracked 分支处理

This commit is contained in:
2026-06-10 09:16:57 +08:00
parent 3789d0a7b3
commit 641d23b7c8
2 changed files with 57 additions and 18 deletions

View File

@@ -136,29 +136,30 @@ export async function assembleArchivePrompt(
hint: "请在 .rune/config.yaml 中配置 stages.archive", hint: "请在 .rune/config.yaml 中配置 stages.archive",
}); });
const changeDir = getChangeDir(projectRoot, changeName);
const taskPath = join(changeDir, "task.md");
const parts: string[] = []; const parts: string[] = [];
parts.push(`# 归档阶段:${changeName}\n`); parts.push(`# 归档阶段:${changeName}\n`);
try { if (config.metadata?.tracked) {
const taskContent = await readFile(taskPath, "utf-8"); const changeDir = getChangeDir(projectRoot, changeName);
const tasks = parseTasks(taskContent); const taskPath = join(changeDir, "task.md");
const incompleteTasks = tasks.filter((t) => !t.checked); try {
if (incompleteTasks.length > 0) { const taskContent = await readFile(taskPath, "utf-8");
parts.push("## ⚠️ 警告:存在未完成的任务\n"); const tasks = parseTasks(taskContent);
parts.push(`以下 ${incompleteTasks.length} 个任务尚未完成:`); const incompleteTasks = tasks.filter((t) => !t.checked);
for (const t of incompleteTasks) { if (incompleteTasks.length > 0) {
parts.push(`- [ ] ${t.text}`); 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(""); } catch {
parts.push("请询问用户是否确认在任务未全部完成的情况下归档。"); // task.md 不存在时不追加警告
parts.push("如用户确认,则继续归档;否则中止并返回构建阶段。");
parts.push("");
} }
} catch {
// task.md 不存在时不追加警告
} }
parts.push(archive.prompt); parts.push(archive.prompt);

View File

@@ -204,6 +204,44 @@ describe("assembleArchivePrompt", () => {
expect(prompt).toContain("user-auth"); expect(prompt).toContain("user-auth");
expect(prompt).toContain("归档"); 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("命令前缀替换", () => { describe("命令前缀替换", () => {