feat: 将 task 从 plan 文档提升为独立 SDD 阶段
This commit is contained in:
@@ -6,7 +6,7 @@ import { writeIfChanged } from "./utils.ts";
|
||||
|
||||
const COMMANDS_DIR = ".claude/commands";
|
||||
|
||||
const STAGES_WITH_CHANGE_NAME = new Set(["plan", "build", "archive"]);
|
||||
const STAGES_WITH_CHANGE_NAME = new Set(["plan", "task", "build", "archive"]);
|
||||
|
||||
function buildSmartGuide(command: string): string {
|
||||
return `如果用户没有指定变更名称,请按以下步骤智能识别:
|
||||
@@ -33,6 +33,9 @@ export async function injectClaudeCode(
|
||||
if (stage === "plan") {
|
||||
content += `\n如果变更目录尚不存在(新变更),请先运行 \`${command} create <变更名>\` 创建目录,再开始规划。`;
|
||||
}
|
||||
if (stage === "task") {
|
||||
content += `\n任务拆解前请确认规划文档已全部完成,运行 \`${command} status <变更名>\` 检查。`;
|
||||
}
|
||||
if (stage === "discuss") {
|
||||
content += `\n讨论结束后,如果确定了变更方向,请运行 \`${command} create <变更名>\` 创建变更目录,然后进入规划阶段。`;
|
||||
}
|
||||
@@ -63,6 +66,9 @@ export async function updateClaudeCode(
|
||||
if (stage === "plan") {
|
||||
newContent += `\n如果变更目录尚不存在(新变更),请先运行 \`${command} create <变更名>\` 创建目录,再开始规划。`;
|
||||
}
|
||||
if (stage === "task") {
|
||||
newContent += `\n任务拆解前请确认规划文档已全部完成,运行 \`${command} status <变更名>\` 检查。`;
|
||||
}
|
||||
if (stage === "discuss") {
|
||||
newContent += `\n讨论结束后,如果确定了变更方向,请运行 \`${command} create <变更名>\` 创建变更目录,然后进入规划阶段。`;
|
||||
}
|
||||
@@ -76,11 +82,12 @@ export async function updateClaudeCode(
|
||||
function generateIntroCommand(command: string): string {
|
||||
return `Rune 是基于规格驱动开发(SDD)的 AI 开发辅助工具。SDD 工作流程:
|
||||
|
||||
discuss → plan → build → archive
|
||||
discuss → plan → task → build → archive
|
||||
|
||||
可用命令:
|
||||
- /rune-discuss — 自由讨论需求和方案
|
||||
- /rune-plan — 生成设计文档和任务清单(新变更需先运行 \`${command} create <变更名>\` 创建目录)
|
||||
- /rune-plan — 生成设计文档(新变更需先运行 \`${command} create <变更名>\` 创建目录)
|
||||
- /rune-task — 根据设计文档生成任务清单
|
||||
- /rune-build — 按任务清单逐步实现
|
||||
- /rune-archive — 归档已完成的变更
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import { writeIfChanged } from "./utils.ts";
|
||||
const COMMANDS_DIR = ".opencode/commands";
|
||||
const SKILLS_DIR = ".opencode/skills";
|
||||
|
||||
const STAGES_WITH_CHANGE_NAME = new Set(["plan", "build", "archive"]);
|
||||
const STAGES_WITH_CHANGE_NAME = new Set(["plan", "task", "build", "archive"]);
|
||||
|
||||
export async function injectOpenCode(projectRoot: string, command: string = "rune"): Promise<void> {
|
||||
for (const stage of STAGES) {
|
||||
@@ -67,6 +67,10 @@ function generateSkill(stage: string, command: string): string {
|
||||
extraGuide = `\n规划阶段应先运行 \`${command} status <变更名>\` 获取当前有哪些文档需要编写,再按依赖顺序逐个生成。\n\n如果变更目录尚不存在(新变更),请先运行 \`${command} create <变更名>\` 创建目录,再开始规划。\n`;
|
||||
}
|
||||
|
||||
if (stage === "task") {
|
||||
extraGuide = `\n任务拆解阶段应先运行 \`${command} status <变更名>\` 确认规划文档已全部完成,再生成任务清单。\n`;
|
||||
}
|
||||
|
||||
if (stage === "discuss") {
|
||||
extraGuide = `\n讨论结束后,如果确定了变更方向,请运行 \`${command} create <变更名>\` 创建变更目录,然后进入规划阶段。\n`;
|
||||
}
|
||||
@@ -74,6 +78,7 @@ function generateSkill(stage: string, command: string): string {
|
||||
const descriptionMap: Record<string, string> = {
|
||||
discuss: "Use when 需要进入 SDD 讨论阶段,自由讨论需求和架构方案",
|
||||
plan: "Use when 需要进入 SDD 规划阶段,生成设计文档和任务清单",
|
||||
task: "Use when 需要进入 SDD 任务拆解阶段,根据设计文档生成任务清单",
|
||||
build: "Use when 需要进入 SDD 构建阶段,按任务清单逐步实现变更",
|
||||
archive: "Use when 需要进入 SDD 归档阶段,确认变更完成并归档",
|
||||
};
|
||||
@@ -118,8 +123,8 @@ Rune 是基于规格驱动开发(SDD)的 AI 开发辅助工具。它通过
|
||||
## SDD 工作流程
|
||||
|
||||
\`\`\`
|
||||
discuss → plan → build → archive
|
||||
探索 规划 构建 归档
|
||||
discuss → plan → task → build → archive
|
||||
探索 规划 任务 构建 归档
|
||||
\`\`\`
|
||||
|
||||
## 可用命令
|
||||
@@ -128,6 +133,7 @@ discuss → plan → build → archive
|
||||
|------|-----------|------|
|
||||
| discuss | /rune-discuss | 自由讨论需求和方案 |
|
||||
| plan | /rune-plan | 生成设计文档和任务清单 |
|
||||
| task | /rune-task | 根据设计文档生成任务清单 |
|
||||
| build | /rune-build | 按任务清单逐步实现 |
|
||||
| archive | /rune-archive | 归档已完成的变更 |
|
||||
|
||||
@@ -140,8 +146,9 @@ ${command} status
|
||||
## 快速开始
|
||||
|
||||
1. 使用 /rune-discuss 进入讨论,自由探索需求
|
||||
2. 讨论结束后,运行 \`${command} create <变更名>\` 创建变更目录,然后用 /rune-plan 生成设计文档和任务清单
|
||||
3. 使用 /rune-build 按任务顺序实现功能
|
||||
4. 使用 /rune-archive 归档已完成的变更
|
||||
2. 讨论结束后,运行 \`${command} create <变更名>\` 创建变更目录,然后用 /rune-plan 生成设计文档
|
||||
3. 使用 /rune-task 根据设计文档生成任务清单
|
||||
4. 使用 /rune-build 按任务顺序实现功能
|
||||
5. 使用 /rune-archive 归档已完成的变更
|
||||
`;
|
||||
}
|
||||
|
||||
28
src/cli.ts
28
src/cli.ts
@@ -8,6 +8,7 @@ import { findProjectRoot, loadConfig, getChangeDir, getArchiveDir } from "./core
|
||||
import {
|
||||
assembleDiscussPrompt,
|
||||
assemblePlanPrompt,
|
||||
assembleTaskPrompt,
|
||||
assembleBuildPrompt,
|
||||
assembleArchivePrompt,
|
||||
} from "./core/assembler.ts";
|
||||
@@ -83,15 +84,15 @@ export function suggestNextStep(change: ChangeStatus, config?: RuneConfig): stri
|
||||
return `完成前置依赖后再规划文档`;
|
||||
}
|
||||
|
||||
if (change.taskProgress && change.taskProgress.completed < change.taskProgress.total) {
|
||||
if (!change.taskProgress) {
|
||||
return `${prefix} task ${change.name}`;
|
||||
}
|
||||
|
||||
if (change.taskProgress.completed < change.taskProgress.total) {
|
||||
return `${prefix} build ${change.name}`;
|
||||
}
|
||||
|
||||
if (change.taskProgress && change.taskProgress.completed === change.taskProgress.total) {
|
||||
return `${prefix} archive ${change.name}`;
|
||||
}
|
||||
|
||||
return `${prefix} build ${change.name}`;
|
||||
return `${prefix} archive ${change.name}`;
|
||||
}
|
||||
|
||||
const cli = cac("rune");
|
||||
@@ -257,6 +258,21 @@ cli
|
||||
console.log(prompt);
|
||||
});
|
||||
|
||||
cli.command("task <change-name>", "任务拆解阶段").action(async (changeName: string) => {
|
||||
validateChangeName(changeName);
|
||||
const root = requireProjectRoot();
|
||||
const changeDir = getChangeDir(root, changeName);
|
||||
if (!existsSync(changeDir)) {
|
||||
const prefix = getPmPrefix();
|
||||
throw new CommandError(`变更"${changeName}"不存在`, {
|
||||
hint: `请先运行 ${prefix} create ${changeName} 创建变更`,
|
||||
});
|
||||
}
|
||||
const config = await loadConfig(root);
|
||||
const prompt = await assembleTaskPrompt(config, root, changeName);
|
||||
console.log(prompt);
|
||||
});
|
||||
|
||||
cli.command("build <change-name>", "构建阶段").action(async (changeName: string) => {
|
||||
validateChangeName(changeName);
|
||||
const root = requireProjectRoot();
|
||||
|
||||
@@ -44,11 +44,21 @@ const COMMANDS: Record<string, CommandHelpDef> = {
|
||||
usageTemplate: "plan <change-name> <document-name>",
|
||||
args: [
|
||||
{ name: "<change-name>", desc: '变更名称,如 "add-login"' },
|
||||
{ name: "<document-name>", desc: '文档名称,如 "design"、"task"' },
|
||||
{ name: "<document-name>", desc: '文档名称,如 "design"' },
|
||||
],
|
||||
detail:
|
||||
"生成规划阶段指定文档的提示词。依赖的前置文档必须已完成。可用文档由配置中的 plan.documents 定义。",
|
||||
exampleArgs: ["plan add-user-auth design", "plan add-user-auth task"],
|
||||
exampleArgs: ["plan add-user-auth design", "plan add-user-auth design"],
|
||||
},
|
||||
task: {
|
||||
name: "task",
|
||||
alias: "task <变更>",
|
||||
description: "任务拆解:根据规划文档生成任务清单",
|
||||
usageTemplate: "task <change-name>",
|
||||
args: [{ name: "<change-name>", desc: '变更名称,如 "add-login"' }],
|
||||
detail:
|
||||
"根据规划阶段的文档内容,生成 checkbox 格式的任务清单(task.md)。规划阶段的所有文档必须已完成。",
|
||||
exampleArgs: ["task add-user-auth", "task fix-memory-leak"],
|
||||
},
|
||||
build: {
|
||||
name: "build",
|
||||
@@ -56,7 +66,8 @@ const COMMANDS: Record<string, CommandHelpDef> = {
|
||||
description: "构建:生成构建阶段提示词",
|
||||
usageTemplate: "build <change-name>",
|
||||
args: [{ name: "<change-name>", desc: '变更名称,如 "add-login"' }],
|
||||
detail: "生成构建阶段的提示词。变更目录需已存在(通过 create 创建)。",
|
||||
detail:
|
||||
"按 task.md 中的任务顺序逐步实现。需先完成任务拆解阶段(task)。可多次执行直到全部完成。",
|
||||
exampleArgs: ["build add-user-auth", "build fix-memory-leak"],
|
||||
},
|
||||
archive: {
|
||||
|
||||
@@ -11,12 +11,13 @@ import { parse as parseYaml } from "yaml";
|
||||
const CONFIG_TEMPLATE = `# Rune 配置文件
|
||||
#
|
||||
# 未配置的阶段将使用内置默认配置。
|
||||
# SDD 四阶段:discuss -> plan -> build -> archive
|
||||
# SDD 五阶段:discuss -> plan -> task -> build -> archive
|
||||
# 辅助命令:create(创建变更目录,plan 阶段的前置步骤)
|
||||
#
|
||||
# 可配置阶段:
|
||||
# discuss - 探索阶段:深度思考、调查代码库、对比方案
|
||||
# plan - 规划阶段:生成设计文档和任务清单
|
||||
# plan - 规划阶段:生成设计文档
|
||||
# task - 任务拆解阶段:根据设计文档生成 checkbox 任务清单
|
||||
# build - 构建阶段:按任务清单逐步实现
|
||||
# archive - 归档阶段:确认完成并归档变更
|
||||
#
|
||||
@@ -34,15 +35,9 @@ const CONFIG_TEMPLATE = `# Rune 配置文件
|
||||
# prompt: 生成设计文档
|
||||
# template: |
|
||||
# # 设计文档
|
||||
# - name: task
|
||||
# prompt: 生成任务清单
|
||||
# depend: [design]
|
||||
# template: |
|
||||
# # 任务清单
|
||||
#
|
||||
# metadata 说明:
|
||||
# command - Rune CLI 执行命令(如 bunx @lanyuanxiaoyao/rune),init 时自动检测
|
||||
# tracked - 是否启用任务追踪(默认 true),开启时 plan.documents 必须包含 task 文档
|
||||
`;
|
||||
|
||||
export const SUPPORTED_TOOLS: Record<string, (root: string, command?: string) => Promise<void>> = {
|
||||
|
||||
@@ -71,6 +71,60 @@ export async function assemblePlanPrompt(
|
||||
return applyCommandPrefix(parts.join("\n"), config);
|
||||
}
|
||||
|
||||
export async function assembleTaskPrompt(
|
||||
config: RuneConfig,
|
||||
projectRoot: string,
|
||||
changeName: string,
|
||||
): Promise<string> {
|
||||
const task = config.stages.task;
|
||||
if (!task) {
|
||||
throw new CommandError("任务拆解阶段未配置", {
|
||||
hint: "请在 .rune/config.yaml 中配置 stages.task",
|
||||
});
|
||||
}
|
||||
|
||||
const plan = config.stages.plan;
|
||||
if (!plan) {
|
||||
throw new CommandError("规划阶段未配置", {
|
||||
hint: "请在 .rune/config.yaml 中配置 stages.plan",
|
||||
});
|
||||
}
|
||||
|
||||
const changeDir = getChangeDir(projectRoot, changeName);
|
||||
const missingDocs: string[] = [];
|
||||
|
||||
for (const doc of plan.documents) {
|
||||
const docPath = join(changeDir, `${doc.name}.md`);
|
||||
if (!existsSync(docPath)) {
|
||||
missingDocs.push(`${doc.name}.md`);
|
||||
}
|
||||
}
|
||||
|
||||
if (missingDocs.length > 0) {
|
||||
throw new CommandError(`变更"${changeName}"的规划文档尚未全部完成:${missingDocs.join("、")}`, {
|
||||
hint: `请先完成规划阶段:rune plan ${changeName} ${missingDocs[0].replace(".md", "")}`,
|
||||
});
|
||||
}
|
||||
|
||||
const parts: string[] = [];
|
||||
parts.push(`# 任务拆解阶段:${changeName}\n`);
|
||||
parts.push(task.prompt);
|
||||
|
||||
const planDocPaths = plan.documents.map((d) => join(changeDir, `${d.name}.md`));
|
||||
parts.push(`\n请先读取以下规划文档:`);
|
||||
for (const p of planDocPaths) {
|
||||
parts.push(`- ${p}`);
|
||||
}
|
||||
|
||||
const taskPath = join(changeDir, "task.md");
|
||||
if (existsSync(taskPath)) {
|
||||
parts.push(`\ntask.md 已存在,请先读取 ${taskPath} 查看已有内容,在此基础上修订。`);
|
||||
}
|
||||
|
||||
parts.push(`\n请将任务列表写入 ${taskPath}`);
|
||||
return applyCommandPrefix(parts.join("\n"), config);
|
||||
}
|
||||
|
||||
export async function assembleBuildPrompt(
|
||||
config: RuneConfig,
|
||||
projectRoot: string,
|
||||
@@ -83,10 +137,6 @@ export async function assembleBuildPrompt(
|
||||
});
|
||||
}
|
||||
|
||||
if (!config.metadata?.tracked) {
|
||||
return applyCommandPrefix(build.prompt, config);
|
||||
}
|
||||
|
||||
const changeDir = getChangeDir(projectRoot, changeName);
|
||||
const taskPath = join(changeDir, "task.md");
|
||||
|
||||
@@ -95,8 +145,8 @@ export async function assembleBuildPrompt(
|
||||
taskContent = await readFile(taskPath, "utf-8");
|
||||
} catch {
|
||||
const prefix = getPmPrefix(config);
|
||||
throw new CommandError(`变更"${changeName}"尚未完成规划,task.md 不存在`, {
|
||||
hint: `请先完成规划阶段:${prefix} plan ${changeName} task 生成任务文档`,
|
||||
throw new CommandError(`变更"${changeName}"尚未完成任务拆解,task.md 不存在`, {
|
||||
hint: `请先完成任务拆解阶段:${prefix} task ${changeName}`,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -142,30 +192,28 @@ export async function assembleArchivePrompt(
|
||||
const parts: string[] = [];
|
||||
parts.push(`# 归档阶段:${changeName}\n`);
|
||||
|
||||
if (config.metadata?.tracked) {
|
||||
const changeDir = getChangeDir(projectRoot, changeName);
|
||||
const taskPath = join(changeDir, "task.md");
|
||||
if (existsSync(taskPath)) {
|
||||
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("以下任务尚未完成:");
|
||||
for (const t of incompleteTasks) {
|
||||
parts.push(`- [ ] ${t.text}`);
|
||||
}
|
||||
parts.push("");
|
||||
parts.push("询问用户是否确认在任务未全部完成的情况下归档。");
|
||||
parts.push("如用户确认,则继续执行归档操作;否则中止并返回构建阶段。");
|
||||
parts.push("");
|
||||
}
|
||||
} catch (e) {
|
||||
const code = (e as NodeJS.ErrnoException)?.code;
|
||||
if (code !== "ENOENT" && code !== "ENOTDIR") {
|
||||
throw e;
|
||||
const changeDir = getChangeDir(projectRoot, changeName);
|
||||
const taskPath = join(changeDir, "task.md");
|
||||
if (existsSync(taskPath)) {
|
||||
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("以下任务尚未完成:");
|
||||
for (const t of incompleteTasks) {
|
||||
parts.push(`- [ ] ${t.text}`);
|
||||
}
|
||||
parts.push("");
|
||||
parts.push("询问用户是否确认在任务未全部完成的情况下归档。");
|
||||
parts.push("如用户确认,则继续执行归档操作;否则中止并返回构建阶段。");
|
||||
parts.push("");
|
||||
}
|
||||
} catch (e) {
|
||||
const code = (e as NodeJS.ErrnoException)?.code;
|
||||
if (code !== "ENOENT" && code !== "ENOTDIR") {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,18 +45,6 @@ export function validateConfig(config: RuneConfig): void {
|
||||
const plan = config.stages.plan;
|
||||
if (!plan) return;
|
||||
|
||||
if (config.metadata?.tracked) {
|
||||
const hasTaskDoc = plan.documents.some((d) => d.name === "task");
|
||||
if (!hasTaskDoc) {
|
||||
throw new ConfigError(
|
||||
"配置校验失败:开启了任务追踪(metadata.tracked)但规划阶段的文档列表中没有 task 文档",
|
||||
{
|
||||
hint: `请在 .rune/config.yaml 的 stages.plan.documents 中添加 task 文档:\n - name: task\n prompt: 生成任务清单\n depend: [design]`,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const docNames = new Set(plan.documents.map((d) => d.name));
|
||||
|
||||
for (const doc of plan.documents) {
|
||||
@@ -110,7 +98,7 @@ export function validateConfig(config: RuneConfig): void {
|
||||
|
||||
function mergeConfig(userConfig: Partial<RuneConfig>): RuneConfig {
|
||||
const result: RuneConfig = { stages: {} };
|
||||
const stageKeys = ["discuss", "plan", "build", "archive"] as const;
|
||||
const stageKeys = ["discuss", "plan", "task", "build", "archive"] as const;
|
||||
|
||||
for (const stage of stageKeys) {
|
||||
if (userConfig.stages?.[stage]) {
|
||||
|
||||
@@ -44,16 +44,14 @@ export async function scanChanges(
|
||||
const buildUnlocked = planCompleted;
|
||||
|
||||
let taskProgress: { completed: number; total: number } | null = null;
|
||||
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,
|
||||
};
|
||||
}
|
||||
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({
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import type { RuneConfig } from "../types.ts";
|
||||
|
||||
export const defaultConfig: RuneConfig = {
|
||||
metadata: {
|
||||
tracked: true,
|
||||
},
|
||||
stages: {
|
||||
discuss: {
|
||||
prompt: `进入探索模式。深度思考,自由发散。跟随对话走向。
|
||||
@@ -263,28 +260,23 @@ rune status
|
||||
## 注意事项
|
||||
`,
|
||||
},
|
||||
{
|
||||
name: "task",
|
||||
depend: ["design"],
|
||||
prompt: `请先获取当前规划状态。
|
||||
],
|
||||
},
|
||||
task: {
|
||||
prompt: `你是一位高级软件工程师,擅长将设计文档拆解为可执行的任务列表。
|
||||
|
||||
建议执行: rune status <变更名>
|
||||
请先读取变更目录下所有已有的规划文档(如 design.md),理解设计内容。
|
||||
|
||||
请根据设计文档,生成一份任务列表。
|
||||
然后将设计拆分为一份任务列表,写入 task.md。
|
||||
|
||||
要求:
|
||||
- 将设计拆分为可独立执行的小任务
|
||||
- 每个任务应该足够具体,能直接编码实现
|
||||
- 任务之间有合理的依赖顺序
|
||||
- 使用 checkbox 格式:- [ ] 待完成,- [x] 已完成
|
||||
- 格式固定为 checkbox 列表,不需要模板
|
||||
|
||||
请将文档写入指定路径。`,
|
||||
template: `# 任务列表
|
||||
|
||||
- [ ]
|
||||
`,
|
||||
},
|
||||
],
|
||||
请将任务列表写入指定路径的 task.md 文件。`,
|
||||
},
|
||||
build: {
|
||||
prompt: `你是一位高级软件工程师。
|
||||
@@ -295,7 +287,7 @@ rune status
|
||||
- 每完成一个任务,立即更新 task.md 中对应项为 [x]
|
||||
- 遵循项目现有的代码风格和约定
|
||||
- 编写必要的测试
|
||||
- 完成所有任务后,提示用户可以使用 /archive <变更名> 归档`,
|
||||
- 完成所有任务后,提示用户可以使用 /rune-archive <变更名> 归档`,
|
||||
},
|
||||
archive: {
|
||||
prompt: `当前变更已进入归档阶段。
|
||||
|
||||
@@ -19,6 +19,10 @@ export interface PlanStage {
|
||||
documents: DocumentConfig[];
|
||||
}
|
||||
|
||||
export interface TaskStage {
|
||||
prompt: string;
|
||||
}
|
||||
|
||||
export interface BuildStage {
|
||||
prompt: string;
|
||||
}
|
||||
@@ -30,6 +34,7 @@ export interface ArchiveStage {
|
||||
export interface StagesConfig {
|
||||
discuss?: DiscussStage;
|
||||
plan?: PlanStage;
|
||||
task?: TaskStage;
|
||||
build?: BuildStage;
|
||||
archive?: ArchiveStage;
|
||||
}
|
||||
@@ -38,7 +43,6 @@ export interface RuneConfig {
|
||||
stages: StagesConfig;
|
||||
metadata?: {
|
||||
command?: string;
|
||||
tracked?: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -55,7 +59,7 @@ export interface ChangeStatus {
|
||||
taskProgress: { completed: number; total: number } | null;
|
||||
}
|
||||
|
||||
export const STAGES = ["discuss", "plan", "build", "archive"] as const;
|
||||
export const STAGES = ["discuss", "plan", "task", "build", "archive"] as const;
|
||||
export type Stage = (typeof STAGES)[number];
|
||||
|
||||
export const RUNE_DIR = ".rune";
|
||||
|
||||
Reference in New Issue
Block a user