import { existsSync } from "node:fs"; import { readFile } from "node:fs/promises"; import { join } from "node:path"; import type { RuneConfig } from "../types.ts"; import { getChangeDir } from "./config.ts"; import { parseTasks } from "./task-parser.ts"; export function assembleDiscussPrompt(config: RuneConfig): string { const discuss = config.stages.discuss; if (!discuss) throw new Error("discuss 阶段未配置"); return discuss.prompt; } export async function assemblePlanPrompt( config: RuneConfig, projectRoot: string, changeName: string, ): Promise { const plan = config.stages.plan; if (!plan) throw new Error("plan 阶段未配置"); const changeDir = getChangeDir(projectRoot, changeName); const parts: string[] = []; parts.push(`# 规划阶段:${changeName}\n`); parts.push("请为当前变更生成以下文档:\n"); for (const doc of plan.documents) { parts.push(`## 文档:${doc.name}.md`); parts.push(doc.prompt); const docPath = join(changeDir, `${doc.name}.md`); if (existsSync(docPath)) { const existing = await readFile(docPath, "utf-8"); parts.push(`\n### 已有内容(请在此基础上修订):\n${existing}`); } if (doc.template) { const rendered = doc.template.replace(/\{\{change-name\}\}/g, changeName); parts.push(`\n### 格式模板:\n${rendered}`); } parts.push(""); } parts.push(`请将文档写入目录:${changeDir}`); return parts.join("\n"); } export async function assembleBuildPrompt( config: RuneConfig, projectRoot: string, changeName: string, ): Promise { const build = config.stages.build; if (!build) throw new Error("build 阶段未配置"); const changeDir = getChangeDir(projectRoot, changeName); const taskPath = join(changeDir, "task.md"); let taskContent: string; try { taskContent = await readFile(taskPath, "utf-8"); } catch { throw new Error(`task.md not found in ${changeDir}`); } const tasks = parseTasks(taskContent); const pendingTasks = tasks.filter((t) => !t.checked); if (pendingTasks.length === 0) { return `所有任务已完成。变更 "${changeName}" 可以归档。`; } const parts: string[] = []; parts.push(`# 构建阶段:${changeName}\n`); parts.push(build.prompt); parts.push(`\n## 任务列表\n`); parts.push(taskContent); parts.push(`\n## 待执行任务(共 ${pendingTasks.length} 项)`); for (const task of pendingTasks) { parts.push(`- [ ] ${task.text}`); } parts.push( `\n请从第一个待执行任务开始。完成后更新 ${taskPath} 中的 checkbox。`, ); return parts.join("\n"); } export function assembleArchivePrompt( config: RuneConfig, changeName: string, ): string { const archive = config.stages.archive; if (!archive) throw new Error("archive 阶段未配置"); const parts: string[] = []; parts.push(`# 归档阶段:${changeName}\n`); parts.push(archive.prompt); return parts.join("\n"); }