feat: 提示词拼装使用动态命令前缀
This commit is contained in:
@@ -5,6 +5,7 @@ import type { RuneConfig } from "../types.ts";
|
|||||||
import { CommandError } from "../cli/errors.ts";
|
import { CommandError } from "../cli/errors.ts";
|
||||||
import { getChangeDir } from "./config.ts";
|
import { getChangeDir } from "./config.ts";
|
||||||
import { parseTasks } from "./task-parser.ts";
|
import { parseTasks } from "./task-parser.ts";
|
||||||
|
import { applyCommandPrefix, getPmPrefix } from "./pm.ts";
|
||||||
|
|
||||||
export function assembleDiscussPrompt(config: RuneConfig): string {
|
export function assembleDiscussPrompt(config: RuneConfig): string {
|
||||||
const discuss = config.stages.discuss;
|
const discuss = config.stages.discuss;
|
||||||
@@ -12,7 +13,7 @@ export function assembleDiscussPrompt(config: RuneConfig): string {
|
|||||||
throw new CommandError("讨论阶段未配置", {
|
throw new CommandError("讨论阶段未配置", {
|
||||||
hint: "请在 .rune/config.yaml 中配置 stages.discuss",
|
hint: "请在 .rune/config.yaml 中配置 stages.discuss",
|
||||||
});
|
});
|
||||||
return discuss.prompt;
|
return applyCommandPrefix(discuss.prompt, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function assemblePlanPrompt(
|
export async function assemblePlanPrompt(
|
||||||
@@ -69,7 +70,7 @@ export async function assemblePlanPrompt(
|
|||||||
}
|
}
|
||||||
|
|
||||||
parts.push(`\n请将文档写入目录:${changeDir}`);
|
parts.push(`\n请将文档写入目录:${changeDir}`);
|
||||||
return parts.join("\n");
|
return applyCommandPrefix(parts.join("\n"), config);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function assembleBuildPrompt(
|
export async function assembleBuildPrompt(
|
||||||
@@ -91,8 +92,9 @@ export async function assembleBuildPrompt(
|
|||||||
try {
|
try {
|
||||||
taskContent = await readFile(taskPath, "utf-8");
|
taskContent = await readFile(taskPath, "utf-8");
|
||||||
} catch {
|
} catch {
|
||||||
|
const prefix = getPmPrefix(config);
|
||||||
throw new CommandError(`变更 "${changeName}" 尚未完成规划,task.md 不存在`, {
|
throw new CommandError(`变更 "${changeName}" 尚未完成规划,task.md 不存在`, {
|
||||||
hint: `请先完成规划阶段:rune plan ${changeName} 生成所有规划文档`,
|
hint: `请先完成规划阶段:${prefix} plan ${changeName} 生成所有规划文档`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,7 +116,7 @@ export async function assembleBuildPrompt(
|
|||||||
}
|
}
|
||||||
parts.push(`\n请从第一个待执行任务开始。完成后更新 ${taskPath} 中的 checkbox。`);
|
parts.push(`\n请从第一个待执行任务开始。完成后更新 ${taskPath} 中的 checkbox。`);
|
||||||
|
|
||||||
return parts.join("\n");
|
return applyCommandPrefix(parts.join("\n"), config);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function assembleArchivePrompt(
|
export async function assembleArchivePrompt(
|
||||||
@@ -154,5 +156,5 @@ export async function assembleArchivePrompt(
|
|||||||
}
|
}
|
||||||
|
|
||||||
parts.push(archive.prompt);
|
parts.push(archive.prompt);
|
||||||
return parts.join("\n");
|
return applyCommandPrefix(parts.join("\n"), config);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -149,7 +149,7 @@ describe("assembleBuildPrompt", () => {
|
|||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
expect(e.message).toContain("尚未完成规划");
|
expect(e.message).toContain("尚未完成规划");
|
||||||
expect(e.message).toContain("nonexistent");
|
expect(e.message).toContain("nonexistent");
|
||||||
expect(e.hint).toContain("rune plan");
|
expect(e.hint).toContain("plan nonexistent");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -163,3 +163,47 @@ describe("assembleArchivePrompt", () => {
|
|||||||
expect(prompt).toContain("归档");
|
expect(prompt).toContain("归档");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("命令前缀替换", () => {
|
||||||
|
it("assembleDiscussPrompt 替换 rune 为配置前缀", () => {
|
||||||
|
const config: RuneConfig = {
|
||||||
|
stages: { discuss: { prompt: "执行 rune status 查看状态" } },
|
||||||
|
metadata: { command: "bunx @lanyuanxiaoyao/rune" },
|
||||||
|
};
|
||||||
|
const prompt = assembleDiscussPrompt(config);
|
||||||
|
expect(prompt).toContain("bunx @lanyuanxiaoyao/rune status");
|
||||||
|
expect(prompt).not.toContain("执行 rune ");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("assembleDiscussPrompt 无配置时追加降级说明", () => {
|
||||||
|
const config: RuneConfig = {
|
||||||
|
stages: { discuss: { prompt: "执行 rune status 查看" } },
|
||||||
|
};
|
||||||
|
const prompt = assembleDiscussPrompt(config);
|
||||||
|
expect(prompt).toContain("bunx @lanyuanxiaoyao/rune status");
|
||||||
|
expect(prompt).toContain("如果没有安装 bun");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("assembleBuildPrompt 错误提示使用动态前缀", async () => {
|
||||||
|
const config: RuneConfig = {
|
||||||
|
stages: { build: { prompt: "构建阶段" } },
|
||||||
|
metadata: { command: "pnpx @lanyuanxiaoyao/rune" },
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
await assembleBuildPrompt(config, TMP_DIR, "nonexistent-build");
|
||||||
|
expect.unreachable();
|
||||||
|
} catch (e: any) {
|
||||||
|
expect(e.hint).toContain("pnpx @lanyuanxiaoyao/rune plan nonexistent-build");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("不替换 /rune- 形式", () => {
|
||||||
|
const config: RuneConfig = {
|
||||||
|
stages: { discuss: { prompt: "使用 /rune-plan 进入规划,然后 rune build 构建" } },
|
||||||
|
metadata: { command: "bunx @lanyuanxiaoyao/rune" },
|
||||||
|
};
|
||||||
|
const prompt = assembleDiscussPrompt(config);
|
||||||
|
expect(prompt).toContain("/rune-plan");
|
||||||
|
expect(prompt).toContain("bunx @lanyuanxiaoyao/rune build");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user