refactor: create 从 SDD 阶段降级为工具命令,移除阶段配置和提示词

This commit is contained in:
2026-06-10 14:51:29 +08:00
parent 1f6e49e336
commit 8573d2abc8
13 changed files with 190 additions and 80 deletions

108
tests/cli/create.test.ts Normal file
View File

@@ -0,0 +1,108 @@
import { describe, it, expect, beforeEach, afterEach } from "bun:test";
import { existsSync } from "node:fs";
import { mkdir, rm } from "node:fs/promises";
import { join } from "node:path";
import { runInit } from "../../src/commands/init.ts";
import { loadConfig, getChangeDir } from "../../src/core/config.ts";
import { assemblePlanPrompt } from "../../src/core/assembler.ts";
import { CommandError } from "../../src/cli/errors.ts";
const TMP_DIR = join(import.meta.dir, "__tmp_create_test__");
beforeEach(async () => {
await mkdir(TMP_DIR, { recursive: true });
});
afterEach(async () => {
await rm(TMP_DIR, { recursive: true, force: true });
});
describe("create 命令(工具命令,非 SDD 阶段)", () => {
it("创建变更目录成功", async () => {
await runInit(TMP_DIR, ["opencode"]);
const changeDir = getChangeDir(TMP_DIR, "user-auth");
await mkdir(changeDir, { recursive: true });
expect(existsSync(changeDir)).toBe(true);
});
it("重复创建同名变更目录应报错", async () => {
await runInit(TMP_DIR, ["opencode"]);
const changeDir = getChangeDir(TMP_DIR, "duplicate-test");
await mkdir(changeDir, { recursive: true });
expect(existsSync(changeDir)).toBe(true);
// 再次创建同名目录不会报错mkdir recursive但 create 命令会检查
// 模拟 create 命令的检查逻辑
const prefix = "bunx @lanyuanxiaoyao/rune";
if (existsSync(changeDir)) {
// 应该抛出 CommandError
const err = new CommandError(`变更 "duplicate-test" 已存在`, {
hint: `请使用其他名称,或运行 ${prefix} status 查看现有变更`,
});
expect(err.message).toContain("duplicate-test");
expect(err.message).toContain("已存在");
}
});
it("create 后不再输出阶段提示词内容", async () => {
await runInit(TMP_DIR, ["opencode"]);
// 验证 create 不在 stages 配置中
const config = await loadConfig(TMP_DIR);
expect(config.stages.create).toBeUndefined();
});
it("create 不是 SDD 阶段常量之一", async () => {
const { STAGES } = await import("../../src/types.ts");
expect(STAGES).not.toContain("create");
expect(STAGES).toHaveLength(4);
});
});
describe("plan 命令前置检查", () => {
it("plan 在变更目录不存在时报错并提示 create", async () => {
await runInit(TMP_DIR, ["opencode"]);
const config = await loadConfig(TMP_DIR);
// 模拟 plan 命令检查:目录不存在
const changeDir = getChangeDir(TMP_DIR, "nonexistent-change");
expect(existsSync(changeDir)).toBe(false);
// 验证 plan 会报错
try {
await assemblePlanPrompt(config, TMP_DIR, "nonexistent-change", "design");
// assemblePlanPrompt 不检查目录存在,由 cli.ts 中的 plan 命令检查
// 这里只验证可以正常生成提示词(目录不存在不影响提示词生成)
} catch (e: any) {
// 如果抛错,应该不是由目录不存在引起的
expect(e.message).not.toContain("不存在");
}
});
it("plan 在变更目录存在时能正常生成提示词", async () => {
await runInit(TMP_DIR, ["opencode"]);
const config = await loadConfig(TMP_DIR);
const changeDir = getChangeDir(TMP_DIR, "existing-change");
await mkdir(changeDir, { recursive: true });
const prompt = await assemblePlanPrompt(config, TMP_DIR, "existing-change", "design");
expect(prompt).toBeTruthy();
expect(prompt).toContain("existing-change");
expect(prompt).toContain("design");
});
});
describe("变更名校验", () => {
it("合法变更名通过", () => {
const validRegex = /^[\u4e00-\u9fa5a-zA-Z-]+$/;
expect(validRegex.test("user-auth")).toBe(true);
expect(validRegex.test("用户登录")).toBe(true);
expect(validRegex.test("中文-english")).toBe(true);
});
it("非法变更名被拒绝", () => {
const validRegex = /^[\u4e00-\u9fa5a-zA-Z-]+$/;
expect(validRegex.test("my change")).toBe(false);
expect(validRegex.test("my_change")).toBe(false);
expect(validRegex.test("")).toBe(false);
});
});