sillyspec 3.8.0 → 3.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/sillyspec-auto/SKILL.md +52 -103
- package/README.md +2 -0
- package/package.json +1 -1
- package/src/run.js +43 -2
- package/src/stages/execute.js +17 -3
- package/src/stages/plan.js +205 -116
- package/src/stages/quick.js +7 -3
- package/src/stages/verify.js +2 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: 自动模式 —
|
|
2
|
+
description: 自动模式 — 全流程自动推进(通用版)
|
|
3
3
|
argument-hint: "<需求描述>"
|
|
4
4
|
---
|
|
5
5
|
|
|
@@ -12,117 +12,66 @@ $ARGUMENTS
|
|
|
12
12
|
|
|
13
13
|
---
|
|
14
14
|
|
|
15
|
-
## 架构
|
|
16
|
-
|
|
17
|
-
你是编排器,不亲自干活。每个阶段启动专精子代理执行,通过文件契约传递信息。
|
|
18
|
-
|
|
19
|
-
## 阶段 personas
|
|
20
|
-
|
|
21
|
-
### brainstorm — 资深架构师
|
|
22
|
-
```
|
|
23
|
-
你是一位有 15 年经验的系统架构师。
|
|
24
|
-
思维模式:先理解业务本质,再设计技术方案。善于从模糊需求中提炼关键约束。
|
|
25
|
-
关注点:系统边界、模块划分、扩展性、技术选型的 trade-off。
|
|
26
|
-
沟通风格:直接、提问犀利、不给模糊方案。不确定就说不确定,不猜。
|
|
27
|
-
输出习惯:决策要附理由,方案要列 trade-off,不用"可能""也许"。
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
### plan — 技术项目经理
|
|
31
|
-
```
|
|
32
|
-
你是一位经验丰富的技术项目经理。
|
|
33
|
-
思维模式:任务拆解要粒度均匀(每个任务 1-2 小时可完成),依赖关系要明确。
|
|
34
|
-
关注点:任务优先级、风险点、验证标准、里程碑。
|
|
35
|
-
沟通风格:条理清晰,用 checkbox 和编号,不做模糊描述。
|
|
36
|
-
输出习惯:每个任务有明确的完成标准,Wave 间有依赖说明。
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
### execute — 高级工程师
|
|
40
|
-
```
|
|
41
|
-
你是一位严谨的高级工程师。
|
|
42
|
-
思维模式:先读规范再写代码,严格遵循 CONVENTIONS.md。代码要有清晰的职责划分。
|
|
43
|
-
关注点:代码质量、边界处理、错误处理、命名规范。
|
|
44
|
-
沟通风格:少说多做,遇到规范冲突优先问,不自作主张。
|
|
45
|
-
输出习惯:每个函数有注释,改动要解释原因,测试要覆盖边界。
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
### verify — QA 专家
|
|
49
|
-
```
|
|
50
|
-
你是一位吹毛求疵的 QA 专家。
|
|
51
|
-
思维模式:假设所有代码都有 bug,用最坏情况测试。关注边界、异常、并发。
|
|
52
|
-
关注点:规范一致性、边界条件、回归风险、性能隐患。
|
|
53
|
-
沟通风格:有问题直说,不放过任何可疑点,用证据说话。
|
|
54
|
-
输出习惯:bug 要有复现步骤,验证要有具体标准,不写"看起来没问题"。
|
|
55
|
-
```
|
|
56
|
-
|
|
57
15
|
## 执行流程
|
|
58
16
|
|
|
17
|
+
你是全流程编排器,按 brainstorm → plan → execute → verify 顺序自动推进。
|
|
18
|
+
|
|
59
19
|
### 启动
|
|
60
20
|
1. 运行 `sillyspec run auto --input "<用户需求>"`
|
|
61
|
-
2. CLI
|
|
21
|
+
2. 读取 CLI 输出的 step prompt(包含你的角色描述)
|
|
22
|
+
3. 执行 prompt 中的操作
|
|
62
23
|
|
|
63
|
-
###
|
|
24
|
+
### 步骤循环
|
|
25
|
+
重复以下循环直到 CLI 输出"全部流程已完成":
|
|
64
26
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
1. 读取 CLI 输出的 step prompt
|
|
27
|
+
1. **读取 CLI 输出的 step prompt**
|
|
68
28
|
2. **判断是否需要用户确认:**
|
|
69
29
|
- prompt 中包含"请用户选择""等待用户回答""展示给用户""用户确认" → **暂停,等用户回复**
|
|
70
|
-
- 纯内部操作 →
|
|
71
|
-
3.
|
|
72
|
-
4.
|
|
73
|
-
5.
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
-
|
|
88
|
-
-
|
|
89
|
-
-
|
|
90
|
-
|
|
91
|
-
|
|
30
|
+
- 纯内部操作 → **直接执行**
|
|
31
|
+
3. **执行 prompt 要求的操作**
|
|
32
|
+
4. **完成后运行** `sillyspec run auto --done --output "<你的摘要>"`
|
|
33
|
+
5. **读取 CLI 输出的下一步 prompt**,回到步骤 1
|
|
34
|
+
|
|
35
|
+
### 阶段审核门控
|
|
36
|
+
|
|
37
|
+
**brainstorm 完成后:**
|
|
38
|
+
评估需求复杂度(参考 brainstorm Step 5 的判断结果),根据复杂度决定:
|
|
39
|
+
|
|
40
|
+
| 复杂度 | 审核策略 |
|
|
41
|
+
|--------|---------|
|
|
42
|
+
| 简单(无拆分、无批量) | 不审核,直接进入 plan |
|
|
43
|
+
| 中等(有拆分或批量) | 启动 1 个审核子代理(QA 视角)审查 design.md |
|
|
44
|
+
| 复杂(拆分 + 批量/多角色) | 启动 2-3 个审核子代理多角度审查 |
|
|
45
|
+
|
|
46
|
+
多角度审核子代理分工:
|
|
47
|
+
- **架构师** — 审查设计合理性、技术选型 trade-off、模块划分
|
|
48
|
+
- **安全专家** — 审查安全隐患、权限设计、数据校验
|
|
49
|
+
- **QA 专家** — 审查需求覆盖率、边界场景遗漏、验收标准
|
|
50
|
+
|
|
51
|
+
审核流程:
|
|
52
|
+
1. 暂停,提示用户当前复杂度等级和建议审核策略
|
|
53
|
+
2. 用户确认后,启动审核子代理(读取 design.md + requirements.md + tasks.md)
|
|
54
|
+
3. 子代理输出问题清单
|
|
55
|
+
4. 汇总问题,询问用户"是否需要修改后再继续"
|
|
56
|
+
5. 需要修改 → 修复后重新审核;不需要 → 进入下一阶段
|
|
57
|
+
|
|
58
|
+
**plan 完成后:**
|
|
59
|
+
同样评估复杂度,启动审核子代理审查 plan.md:
|
|
60
|
+
- **项目经理** — 审查任务拆解粒度、依赖关系、优先级
|
|
61
|
+
- **工程师** — 审查任务可行性、工作量评估是否合理
|
|
62
|
+
- **QA** — 审查验收标准是否具体可测试
|
|
63
|
+
|
|
64
|
+
### 关键规则
|
|
65
|
+
- 不要跳过任何步骤
|
|
66
|
+
- 不要手动修改 progress.json
|
|
67
|
+
- 不要自动 commit,只 git add
|
|
92
68
|
- 不要使用 npx
|
|
93
69
|
- 不要编造不存在的 CLI 子命令
|
|
94
|
-
-
|
|
95
|
-
- 完成后汇报结果,不要自行推进下一步
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
## 子代理交互协议
|
|
99
|
-
|
|
100
|
-
子代理遇到需要用户确认的问题时,**不要自己猜测**,输出以下标记后暂停:
|
|
101
|
-
|
|
102
|
-
```
|
|
103
|
-
### ❓ 需要用户确认
|
|
104
|
-
**问题:** xxx
|
|
105
|
-
**选项:** A) xxx B) xxx C) xxx
|
|
106
|
-
**建议:** B(因为 xxx)
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
主代理(你)看到 ❓ 标记后:
|
|
110
|
-
1. 暂停当前流程
|
|
111
|
-
2. 把问题转发给用户
|
|
112
|
-
3. 等用户回复
|
|
113
|
-
4. 把用户回复发送给子代理(sessions_send),子代理继续执行
|
|
114
|
-
|
|
115
|
-
### CLI prompt 中的用户确认点
|
|
116
|
-
|
|
117
|
-
sillyspec CLI 的 step prompt 本身可能包含"请用户选择""等待用户回答"等要求。
|
|
118
|
-
主代理(你)在把 prompt 发给子代理前,先扫描这些关键词。
|
|
119
|
-
如果有 → 先自己处理(询问用户),拿到答案后再发给子代理。
|
|
120
|
-
这样子代理不需要处理交互,只管干活。
|
|
70
|
+
- 遇到命令报错 → 展示错误,暂停等用户介入
|
|
121
71
|
|
|
122
|
-
|
|
123
|
-
- 命令执行失败 →
|
|
124
|
-
- 用户说"停止"
|
|
125
|
-
- 子代理失败 → 展示错误,可重试或跳过
|
|
72
|
+
### 异常处理
|
|
73
|
+
- 命令执行失败 → 展示错误信息,暂停等待用户指示
|
|
74
|
+
- 用户说"停止"或"暂停" → 立即停止,报告当前进度
|
|
126
75
|
|
|
127
|
-
|
|
128
|
-
CLI 输出"全部流程已完成"
|
|
76
|
+
### 完成条件
|
|
77
|
+
CLI 输出"全部流程已完成"后,输出完整流程总结,提示用户提交改动。
|
package/README.md
CHANGED
package/package.json
CHANGED
package/src/run.js
CHANGED
|
@@ -8,6 +8,7 @@ import { existsSync, readdirSync, mkdirSync, writeFileSync, appendFileSync, read
|
|
|
8
8
|
import { ProgressManager } from './progress.js'
|
|
9
9
|
import { stageRegistry, getNextStage, auxiliaryStages } from './stages/index.js'
|
|
10
10
|
import { buildExecuteSteps } from './stages/execute.js'
|
|
11
|
+
import { buildPlanSteps } from './stages/plan.js'
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* 获取阶段的步骤定义(execute 需要动态构建)
|
|
@@ -49,6 +50,19 @@ async function getStageSteps(stageName, cwd, progress) {
|
|
|
49
50
|
}
|
|
50
51
|
return buildExecuteSteps(planFile)
|
|
51
52
|
}
|
|
53
|
+
if (stageName === 'plan') {
|
|
54
|
+
const changesDir = join(cwd, '.sillyspec', 'changes')
|
|
55
|
+
let changeDir = null
|
|
56
|
+
if (progress.currentChange) {
|
|
57
|
+
const target = join(changesDir, progress.currentChange)
|
|
58
|
+
if (existsSync(target)) changeDir = target
|
|
59
|
+
}
|
|
60
|
+
if (!changeDir && existsSync(changesDir)) {
|
|
61
|
+
const entries = readdirSync(changesDir, { withFileTypes: true }).filter(e => e.isDirectory() && e.name !== 'archive')
|
|
62
|
+
if (entries.length === 1) changeDir = join(changesDir, entries[0].name)
|
|
63
|
+
}
|
|
64
|
+
return buildPlanSteps(changeDir)
|
|
65
|
+
}
|
|
52
66
|
const def = stageRegistry[stageName]
|
|
53
67
|
return def ? def.steps : null
|
|
54
68
|
}
|
|
@@ -101,9 +115,11 @@ function outputStep(stageName, stepIndex, steps, cwd) {
|
|
|
101
115
|
plan: `### 📋 你的角色:技术项目经理
|
|
102
116
|
你是一位经验丰富的技术项目经理。任务拆解粒度均匀,依赖关系明确。每个任务有完成标准,Wave 间有依赖说明。条理清晰,不做模糊描述。`,
|
|
103
117
|
execute: `### 💻 你的角色:高级工程师
|
|
104
|
-
你是一位严谨的高级工程师。先读规范再写代码,严格遵循 CONVENTIONS.md
|
|
118
|
+
你是一位严谨的高级工程师。先读规范再写代码,严格遵循 CONVENTIONS.md 和 plan.md。**你不是设计师,是执行者——按 plan 搬砖,禁止发散思维。** 发现 plan 不合理就停下来反馈,不要自己改方案。代码有清晰职责划分,边界处理完善。少说多做,遇到规范冲突优先问。`,
|
|
105
119
|
verify: `### 🔍 你的角色:QA 专家
|
|
106
|
-
你是一位吹毛求疵的 QA 专家。假设所有代码都有 bug,用最坏情况测试。关注边界、异常、并发。有问题直说,用证据说话,不写"看起来没问题"
|
|
120
|
+
你是一位吹毛求疵的 QA 专家。假设所有代码都有 bug,用最坏情况测试。关注边界、异常、并发。有问题直说,用证据说话,不写"看起来没问题"。`,
|
|
121
|
+
quick: `### 💻 你的角色:全栈老兵
|
|
122
|
+
你是一位实战经验丰富的全栈工程师。不纠结架构和流程,理解需求就直接干。不确定的地方先问清楚再动手,先读后写,改完就收。问题排查思路开阔,前端报错不一定是前端问题——可能是后端数据、浏览器兼容、甚至设备硬件。解决方案实用接地气,用户描述有误敢于直接指出。`
|
|
107
123
|
}
|
|
108
124
|
|
|
109
125
|
console.log(`---`)
|
|
@@ -335,6 +351,31 @@ async function completeStep(pm, progress, stageName, cwd, outputText, inputText
|
|
|
335
351
|
}
|
|
336
352
|
|
|
337
353
|
// 检查是否还有下一步
|
|
354
|
+
// plan 阶段 Step 4(展开任务)完成后,动态追加 task 蓝图步骤
|
|
355
|
+
if (stageName === 'plan' && currentIdx === 3 && progress.currentChange) {
|
|
356
|
+
const planFile = join(cwd, '.sillyspec', 'changes', progress.currentChange, 'plan.md')
|
|
357
|
+
if (existsSync(planFile)) {
|
|
358
|
+
const planContent = readFileSync(planFile, 'utf8')
|
|
359
|
+
const { buildPlanSteps } = await import('./stages/plan.js')
|
|
360
|
+
const fullSteps = buildPlanSteps(join(cwd, '.sillyspec', 'changes', progress.currentChange), planContent)
|
|
361
|
+
// fullSteps[0..4] = fixedPrefix, fullSteps[-2..-1] = fixedSuffix
|
|
362
|
+
// 中间的是 task 蓝图步骤,插入到当前 steps 中
|
|
363
|
+
// 当前 steps 已有 5 个 fixedPrefix,找到需要插入的 task 步骤
|
|
364
|
+
const taskSteps = fullSteps.slice(5, -2) // 排除 5 个前缀和 2 个后缀
|
|
365
|
+
if (taskSteps.length > 0) {
|
|
366
|
+
// 插入审查一致性 + 保存步骤(后缀)
|
|
367
|
+
const suffixSteps = fullSteps.slice(-2)
|
|
368
|
+
for (const ts of taskSteps) {
|
|
369
|
+
steps.push({ name: ts.name, status: 'pending', prompt: ts.prompt, outputHint: ts.outputHint, optional: false })
|
|
370
|
+
}
|
|
371
|
+
for (const ss of suffixSteps) {
|
|
372
|
+
steps.push({ name: ss.name, status: 'pending', prompt: ss.prompt, outputHint: ss.outputHint, optional: false })
|
|
373
|
+
}
|
|
374
|
+
// 重新查找下一步
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
338
379
|
const nextPendingIdx = steps.findIndex(s => s.status === 'pending')
|
|
339
380
|
|
|
340
381
|
if (nextPendingIdx === -1) {
|
package/src/stages/execute.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from 'fs'
|
|
2
|
+
import path from 'path'
|
|
2
3
|
|
|
3
4
|
export const definition = {
|
|
4
5
|
name: 'execute',
|
|
@@ -167,10 +168,14 @@ function parseWavesFromPlan(planContent) {
|
|
|
167
168
|
/**
|
|
168
169
|
* 为 Wave 生成 prompt
|
|
169
170
|
*/
|
|
170
|
-
function buildWavePrompt(wave, waveIndex) {
|
|
171
|
-
const taskList = wave.tasks.map(t => {
|
|
171
|
+
function buildWavePrompt(wave, waveIndex, changeDir) {
|
|
172
|
+
const taskList = wave.tasks.map((t, ti) => {
|
|
173
|
+
const taskNum = String(t.index || (ti + 1)).padStart(2, '0')
|
|
174
|
+
const taskFile = changeDir ? `${changeDir}/tasks/task-${taskNum}.md` : ''
|
|
172
175
|
let s = `- [ ] ${t.name}`
|
|
173
176
|
if (t.file) s += ` (${t.file})`
|
|
177
|
+
if (taskFile) s += `
|
|
178
|
+
📋 **执行前必须读取任务蓝图:\`cat ${taskFile}\`**`
|
|
174
179
|
if (t.reference) s += `\n 参考: ${t.reference}`
|
|
175
180
|
if (t.steps) s += `\n 步骤: ${t.steps}`
|
|
176
181
|
return s
|
|
@@ -181,6 +186,10 @@ function buildWavePrompt(wave, waveIndex) {
|
|
|
181
186
|
1. 读取 design.md 的「编码铁律」章节(如果存在),严格遵守
|
|
182
187
|
2. 确认本 Wave 的输入/输出契约(前置 Wave 产出了什么,本 Wave 需要消费什么)
|
|
183
188
|
3. 检查前置 Wave 的产出是否完整(文件是否存在、测试是否通过)
|
|
189
|
+
4. **上下文分层加载**:
|
|
190
|
+
- 🔥 热上下文:design.md 编码铁律 + 当前 Wave 任务(必须加载)
|
|
191
|
+
- 🌡️ 温上下文:CONVENTIONS.md + ARCHITECTURE.md(需要时加载)
|
|
192
|
+
- ❄️ 冷上下文:其他变更的 design.md、历史 plan.md(不要主动加载,除非明确需要)
|
|
184
193
|
|
|
185
194
|
### 本 Wave 任务
|
|
186
195
|
${taskList}
|
|
@@ -188,6 +197,8 @@ ${taskList}
|
|
|
188
197
|
### 执行要求
|
|
189
198
|
1. 按任务顺序执行,同一 Wave 内任务可并行
|
|
190
199
|
2. 铁律:先读后写、grep 确认方法存在、不编造、TDD
|
|
200
|
+
3. **禁止发散思维**:你是代码搬运工,严格按 plan 执行,不要自行发挥"更好的方案"。如果发现 plan 不合理,**停下来反馈**,不要自己改方案。问题归因:实现困难 → plan 没做好;plan 做不好 → design 有缺陷。链路可追溯,不要在中途偷偷修设计。
|
|
201
|
+
4. **Reverse Sync**:发现 Bug 或实现与 design.md 不一致时,先检查是代码错了还是 design.md 有遗漏,有遗漏则先修 design.md 再修代码。design.md 是唯一 truth source。
|
|
191
202
|
3. **不要频繁编译!** 编译很慢,只在以下情况运行:
|
|
192
203
|
- 写了大量代码后需要验证语法正确性
|
|
193
204
|
- 最后一个 Wave 完成后做一次全量编译验证
|
|
@@ -209,10 +220,13 @@ ${taskList}
|
|
|
209
220
|
*/
|
|
210
221
|
export function buildExecuteSteps(planFilePath = null) {
|
|
211
222
|
let waves
|
|
223
|
+
let changeDir = null
|
|
212
224
|
|
|
213
225
|
if (planFilePath && existsSync(planFilePath)) {
|
|
214
226
|
const planContent = readFileSync(planFilePath, 'utf8')
|
|
215
227
|
waves = parseWavesFromPlan(planContent)
|
|
228
|
+
// 从 planFilePath 推导 changeDir: .sillyspec/changes/<name>/plan.md
|
|
229
|
+
changeDir = path.dirname(planFilePath)
|
|
216
230
|
}
|
|
217
231
|
|
|
218
232
|
// 如果没解析出 Wave,生成默认 3 个
|
|
@@ -225,7 +239,7 @@ export function buildExecuteSteps(planFilePath = null) {
|
|
|
225
239
|
|
|
226
240
|
const waveSteps = waves.map((wave, i) => ({
|
|
227
241
|
name: `Wave ${i + 1} 执行`,
|
|
228
|
-
prompt: buildWavePrompt(wave, i + 1),
|
|
242
|
+
prompt: buildWavePrompt(wave, i + 1, changeDir),
|
|
229
243
|
outputHint: `Wave ${i + 1} 执行结果`,
|
|
230
244
|
optional: false
|
|
231
245
|
}))
|
package/src/stages/plan.js
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'fs'
|
|
2
|
+
import path from 'path'
|
|
3
|
+
|
|
1
4
|
export const definition = {
|
|
2
5
|
name: 'plan',
|
|
3
6
|
title: '实现计划',
|
|
4
|
-
description: '编写实现计划 — 按 Wave
|
|
5
|
-
steps:
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
description: '编写实现计划 — 按 Wave 分组,每个任务独立文档',
|
|
8
|
+
steps: null // 动态生成
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// 固定前缀步骤
|
|
12
|
+
const fixedPrefix = [
|
|
13
|
+
{
|
|
14
|
+
name: '状态检查',
|
|
15
|
+
prompt: `检查当前状态,确认可以执行 plan。
|
|
9
16
|
|
|
10
17
|
### 操作
|
|
11
18
|
1. 运行 \`sillyspec progress show\`
|
|
@@ -13,12 +20,12 @@ export const definition = {
|
|
|
13
20
|
|
|
14
21
|
### 输出
|
|
15
22
|
当前状态摘要`,
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
23
|
+
outputHint: '状态摘要',
|
|
24
|
+
optional: false
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
name: '加载上下文',
|
|
28
|
+
prompt: `加载所有规范文件和代码库上下文。
|
|
22
29
|
|
|
23
30
|
### 操作
|
|
24
31
|
1. 读取 CODEBASE-OVERVIEW.md + 各子项目上下文
|
|
@@ -28,143 +35,225 @@ export const definition = {
|
|
|
28
35
|
|
|
29
36
|
### 输出
|
|
30
37
|
已加载的文件清单`,
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
38
|
+
outputHint: '文件清单',
|
|
39
|
+
optional: false
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: '锚定确认',
|
|
43
|
+
prompt: `确认已读取的文件。
|
|
37
44
|
|
|
38
45
|
### 操作
|
|
39
46
|
列出已读取的文件,标注存在/不存在。
|
|
40
47
|
|
|
41
48
|
### 输出
|
|
42
49
|
文件加载确认清单`,
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
50
|
+
outputHint: '文件确认清单',
|
|
51
|
+
optional: false
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
name: '展开任务并分组',
|
|
55
|
+
prompt: `把 tasks.md 每个 checkbox 展开为任务描述,按 Wave 分组,产出 plan.md 总览。
|
|
49
56
|
|
|
50
|
-
###
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
每个 Task 必须包含「步骤」字段,列出 TDD 执行顺序:
|
|
55
|
-
1. 写测试 → 2. 运行确认失败 → 3. 写代码 → 4. 运行确认通过
|
|
56
|
-
|
|
57
|
-
纯配置/数据/文档类任务可跳过 TDD,步骤简化为:1. 实现 → 2. 验证
|
|
57
|
+
### plan.md 格式(轻量总览,PM 视角)
|
|
58
|
+
\`\`\`markdown
|
|
59
|
+
# 实现计划
|
|
58
60
|
|
|
59
|
-
|
|
61
|
+
## Wave 1(并行,无依赖)
|
|
62
|
+
- [ ] task-01: 添加用户创建接口
|
|
63
|
+
- [ ] task-02: 添加角色创建接口
|
|
60
64
|
|
|
61
|
-
|
|
65
|
+
## Wave 2(依赖 Wave 1)
|
|
66
|
+
- [ ] task-03: 用户创建接口联调
|
|
62
67
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
- [ ] 添加用户创建接口
|
|
67
|
-
- 修改: \`UserController.java\`、\`UserService.java\`
|
|
68
|
-
- 参考: \`RoleController.createRole\`
|
|
69
|
-
- 步骤:
|
|
70
|
-
1. 写测试 UserControllerTest.testCreateUser
|
|
71
|
-
2. 运行 <test-cmd> 确认失败
|
|
72
|
-
3. 写 UserController.createUser
|
|
73
|
-
4. 运行 <test-cmd> 确认通过
|
|
74
|
-
|
|
75
|
-
- [ ] 添加角色创建接口
|
|
76
|
-
- 修改: \`RoleController.java\`
|
|
77
|
-
- 步骤:
|
|
78
|
-
1. 写测试 RoleControllerTest.testCreateRole
|
|
79
|
-
2. 运行 <test-cmd> 确认失败
|
|
80
|
-
3. 写 RoleController.createRole
|
|
81
|
-
4. 运行 <test-cmd> 确认通过
|
|
82
|
-
|
|
83
|
-
### Wave 2(依赖 Wave 1)
|
|
84
|
-
|
|
85
|
-
- [ ] 用户创建接口联调
|
|
86
|
-
- 修改: \`UserController.java\`
|
|
87
|
-
- 依赖: Wave 1 的用户创建接口 + 角色创建接口
|
|
88
|
-
- 步骤:
|
|
89
|
-
1. 写集成测试 UserControllerTest.testCreateUserIntegration
|
|
90
|
-
2. 运行 <test-cmd> 确认失败
|
|
91
|
-
3. 补充联调逻辑
|
|
92
|
-
4. 运行 <test-cmd> 确认通过
|
|
93
|
-
|
|
94
|
-
### Wave 3(纯配置)
|
|
95
|
-
|
|
96
|
-
- [ ] 配置用户创建接口路由
|
|
97
|
-
- 修改: \`application.yml\`
|
|
98
|
-
- 步骤:
|
|
99
|
-
1. 实现路由配置
|
|
100
|
-
2. 验证: 运行 <test-cmd> 确认通过
|
|
68
|
+
## 全局验收标准
|
|
69
|
+
- [ ] 所有单元测试通过
|
|
101
70
|
\`\`\`
|
|
102
71
|
|
|
103
|
-
###
|
|
104
|
-
-
|
|
105
|
-
-
|
|
106
|
-
-
|
|
107
|
-
- 依赖关系(无依赖可省略)
|
|
108
|
-
|
|
109
|
-
### 分组规则
|
|
110
|
-
1. 分析 Task 间依赖
|
|
111
|
-
2. 无依赖的 Task 归入同一 Wave(可并行)
|
|
112
|
-
3. 有依赖的 Task 按顺序排列
|
|
113
|
-
4. Wave 编号从 1 开始
|
|
72
|
+
### 关键规则
|
|
73
|
+
- plan.md 只放任务列表 + Wave 划分 + 全局验收标准,**不放实现细节**
|
|
74
|
+
- 实现细节写到后续的 tasks/task-NN.md 中
|
|
75
|
+
- 每个任务编号格式:task-01、task-02 ...
|
|
114
76
|
|
|
115
77
|
### 批量模式指引
|
|
116
|
-
如果 design.md 或需求中包含批量特征(关键词:批量/模板/引擎/
|
|
117
|
-
❌
|
|
118
|
-
❌
|
|
119
|
-
✅
|
|
120
|
-
✅
|
|
78
|
+
如果 design.md 或需求中包含批量特征(关键词:批量/模板/引擎/N个相似),按以下原则规划:
|
|
79
|
+
❌ 不要列出每个实例作为独立任务
|
|
80
|
+
❌ 不要在文档中嵌入数据
|
|
81
|
+
✅ 设计通用架构,Wave 1 聚焦架构
|
|
82
|
+
✅ 数据转换用脚本完成,单独一个 Wave
|
|
121
83
|
✅ 总任务数控制在 10 个以内
|
|
122
|
-
✅ 在 design.md 中增加「编码铁律」章节(3-5 条不可违反的约束)
|
|
123
84
|
|
|
124
85
|
### 操作
|
|
125
86
|
1. 读取 tasks.md 获取任务列表
|
|
126
87
|
2. 读取 design.md 获取文件变更清单
|
|
127
|
-
3.
|
|
88
|
+
3. 逐个展开为任务描述
|
|
128
89
|
4. 分析依赖关系,按 Wave 分组
|
|
129
|
-
5.
|
|
90
|
+
5. 保存到 \`.sillyspec/changes/<变更名>/plan.md\`
|
|
130
91
|
|
|
131
92
|
### 输出
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
93
|
+
plan.md 总览内容`,
|
|
94
|
+
outputHint: 'plan.md 总览',
|
|
95
|
+
optional: false
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
name: '自检总览',
|
|
99
|
+
prompt: `自检 plan.md 总览质量。
|
|
139
100
|
|
|
140
101
|
### 操作
|
|
141
102
|
检查以下各项:
|
|
142
|
-
- [ ] 每个 task
|
|
143
|
-
- [ ] 每个 task
|
|
144
|
-
- [ ] 代码类 task 有 TDD 步骤(写测试→确认失败→写代码→确认通过)
|
|
145
|
-
- [ ] 配置/文档类 task 步骤简化为(实现→验证)
|
|
103
|
+
- [ ] 每个 task 有编号(task-01、task-02 ...)
|
|
104
|
+
- [ ] 每个 task 有 checkbox
|
|
146
105
|
- [ ] 已标注 Wave 分组和依赖关系
|
|
147
|
-
- [ ]
|
|
148
|
-
- [ ]
|
|
106
|
+
- [ ] 有全局验收标准
|
|
107
|
+
- [ ] 没有实现细节(接口定义、代码示例等不应该在 plan.md 里)
|
|
108
|
+
- [ ] plan.md 与 design.md 的文件变更清单一致
|
|
149
109
|
|
|
150
110
|
### 输出
|
|
151
111
|
自检通过/不通过`,
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
112
|
+
outputHint: '自检结果',
|
|
113
|
+
optional: false
|
|
114
|
+
}
|
|
115
|
+
]
|
|
116
|
+
|
|
117
|
+
// 固定后缀步骤
|
|
118
|
+
const fixedSuffix = [
|
|
119
|
+
{
|
|
120
|
+
name: '审查一致性',
|
|
121
|
+
prompt: `审查所有 task-N.md 的一致性。
|
|
158
122
|
|
|
159
123
|
### 操作
|
|
160
|
-
1.
|
|
161
|
-
2.
|
|
162
|
-
|
|
124
|
+
1. 读取所有 tasks/task-NN.md
|
|
125
|
+
2. 检查:
|
|
126
|
+
- 文件路径有没有冲突(两个任务改同一个文件)
|
|
127
|
+
- 依赖关系和 plan.md 的 Wave 分组是否一致
|
|
128
|
+
- 验收标准和 plan.md 的全局标准是否矛盾
|
|
129
|
+
- 接口定义是否自洽
|
|
130
|
+
3. 发现问题 → 列出问题清单,暂停等用户决定是否修复
|
|
163
131
|
|
|
164
132
|
### 输出
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
133
|
+
一致性审查结果`,
|
|
134
|
+
outputHint: '审查结果',
|
|
135
|
+
optional: false
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
name: '保存并更新进度',
|
|
139
|
+
prompt: `确认所有文件已保存,更新进度。
|
|
140
|
+
|
|
141
|
+
### 操作
|
|
142
|
+
1. 确认 plan.md 和所有 tasks/task-NN.md 已存在
|
|
143
|
+
2. \`git add .sillyspec/\` — **不要 commit**
|
|
144
|
+
|
|
145
|
+
### 输出
|
|
146
|
+
文件列表 + 下一步命令`,
|
|
147
|
+
outputHint: '文件列表',
|
|
148
|
+
optional: false
|
|
149
|
+
}
|
|
150
|
+
]
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* 解析 plan.md 获取任务数量
|
|
154
|
+
*/
|
|
155
|
+
function parseTaskCount(planContent) {
|
|
156
|
+
const matches = planContent.match(/^[-*]\s*\[[ x]\]\s*task-\d+/gm)
|
|
157
|
+
return matches ? matches.length : 0
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* 生成单个任务的蓝图写作 prompt
|
|
162
|
+
*/
|
|
163
|
+
function buildTaskPrompt(taskNum, taskName, changeDir) {
|
|
164
|
+
return `编写任务蓝图 tasks/task-${String(taskNum).padStart(2, '0')}.md
|
|
165
|
+
|
|
166
|
+
### 任务
|
|
167
|
+
${taskName}
|
|
168
|
+
|
|
169
|
+
### 文件路径
|
|
170
|
+
\`.sillyspec/changes/<变更名>/tasks/task-${String(taskNum).padStart(2, '0')}.md\`
|
|
171
|
+
|
|
172
|
+
### 格式要求(必须严格遵守)
|
|
173
|
+
\`\`\`markdown
|
|
174
|
+
# task-${String(taskNum).padStart(2, '0')}: ${taskName}
|
|
175
|
+
|
|
176
|
+
## 修改文件
|
|
177
|
+
- 具体文件路径列表
|
|
178
|
+
|
|
179
|
+
## 实现要求
|
|
180
|
+
1. 具体做什么,写清楚
|
|
181
|
+
2. ...
|
|
182
|
+
|
|
183
|
+
## 接口定义
|
|
184
|
+
(代码类任务必填,写方法签名、数据结构)
|
|
185
|
+
|
|
186
|
+
## 边界处理
|
|
187
|
+
- 异常场景列表
|
|
188
|
+
|
|
189
|
+
## 参考
|
|
190
|
+
- 已有代码可参考的模式
|
|
191
|
+
- 相关的 CONVENTIONS.md 条目
|
|
192
|
+
|
|
193
|
+
## TDD 步骤
|
|
194
|
+
1. 写测试 ...
|
|
195
|
+
2. 运行 <test-cmd> 确认失败
|
|
196
|
+
3. 写代码 ...
|
|
197
|
+
4. 运行 <test-cmd> 确认通过
|
|
198
|
+
(纯配置/文档类任务简化为:1. 实现 2. 验证)
|
|
199
|
+
|
|
200
|
+
## 验收标准
|
|
201
|
+
- [ ] 具体可测试的验收条件
|
|
202
|
+
\`\`\`
|
|
203
|
+
|
|
204
|
+
### 关键规则
|
|
205
|
+
- task-N.md 必须独立完整,execute 子代理只读这一个文件就能干活
|
|
206
|
+
- 不要依赖其他 task-N.md 的内容
|
|
207
|
+
- 接口定义写到"搬砖工照着做"的程度
|
|
208
|
+
- 写完后保存到文件
|
|
209
|
+
|
|
210
|
+
### 操作
|
|
211
|
+
1. 读取 design.md 和 plan.md 了解上下文
|
|
212
|
+
2. 读取相关源文件了解现有代码
|
|
213
|
+
3. 编写任务蓝图
|
|
214
|
+
4. 保存到 tasks/task-${String(taskNum).padStart(2, '0')}.md
|
|
215
|
+
|
|
216
|
+
### 输出
|
|
217
|
+
任务蓝图内容摘要`
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* 动态构建 plan 步骤列表
|
|
222
|
+
* @param {string|null} changeDir - 变更目录路径
|
|
223
|
+
* @param {string|null} planContent - plan.md 内容(可选,用于解析任务数)
|
|
224
|
+
* @returns {Array} 步骤列表
|
|
225
|
+
*/
|
|
226
|
+
export function buildPlanSteps(changeDir = null, planContent = null) {
|
|
227
|
+
let taskCount = 0
|
|
228
|
+
|
|
229
|
+
// 尝试从 plan.md 解析任务数
|
|
230
|
+
if (planContent) {
|
|
231
|
+
taskCount = parseTaskCount(planContent)
|
|
232
|
+
} else if (changeDir) {
|
|
233
|
+
const planFile = path.join(changeDir, 'plan.md')
|
|
234
|
+
if (existsSync(planFile)) {
|
|
235
|
+
taskCount = parseTaskCount(readFileSync(planFile, 'utf8'))
|
|
168
236
|
}
|
|
169
|
-
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// 没有任务数则用固定步骤(兼容旧流程)
|
|
240
|
+
if (taskCount === 0) {
|
|
241
|
+
return [...fixedPrefix, ...fixedSuffix]
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// 动态生成每个任务的蓝图写作步骤
|
|
245
|
+
const taskSteps = []
|
|
246
|
+
for (let i = 1; i <= taskCount; i++) {
|
|
247
|
+
taskSteps.push({
|
|
248
|
+
name: `写任务蓝图 task-${String(i).padStart(2, '0')}`,
|
|
249
|
+
prompt: `### 注意
|
|
250
|
+
这是第 ${i}/${taskCount} 个任务蓝图。focus 在这一个任务上,不要写其他任务的内容。
|
|
251
|
+
|
|
252
|
+
${buildTaskPrompt(i, '(从 plan.md 读取任务名)', changeDir)}`,
|
|
253
|
+
outputHint: `task-${String(i).padStart(2, '0')} 蓝图`,
|
|
254
|
+
optional: false
|
|
255
|
+
})
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return [...fixedPrefix, ...taskSteps, ...fixedSuffix]
|
|
170
259
|
}
|
package/src/stages/quick.js
CHANGED
|
@@ -11,8 +11,11 @@ export const definition = {
|
|
|
11
11
|
### 操作
|
|
12
12
|
1. 检查是否携带 \`--change <变更名>\`,确定记录方式
|
|
13
13
|
2. 理解任务:模糊则问一个问题确认
|
|
14
|
-
3.
|
|
15
|
-
4.
|
|
14
|
+
3. 加载项目信息:\`cat .sillyspec/projects/*.yaml 2>/dev/null\`(了解项目结构和技术栈)
|
|
15
|
+
4. 加载上下文:\`cat .sillyspec/docs/<project>/scan/CONVENTIONS.md 2>/dev/null\`
|
|
16
|
+
5. 加载本地配置:\`cat .sillyspec/local.yaml 2>/dev/null\`(构建命令、测试命令、环境变量等)
|
|
17
|
+
6. 如有 \`--change\`,加载设计文档:\`cat .sillyspec/changes/<变更名>/design.md 2>/dev/null\`(理解设计意图)
|
|
18
|
+
7. 如有需要,查询知识库:\`cat .sillyspec/knowledge/INDEX.md 2>/dev/null\`
|
|
16
19
|
|
|
17
20
|
### 输出
|
|
18
21
|
任务理解 + 上下文摘要`,
|
|
@@ -34,7 +37,8 @@ export const definition = {
|
|
|
34
37
|
|
|
35
38
|
### 铁律
|
|
36
39
|
- 不要修改无关文件
|
|
37
|
-
- 不要编造不存在的 CLI
|
|
40
|
+
- 不要编造不存在的 CLI 子命令
|
|
41
|
+
- **Reverse Sync**:如果发现 Bug 是 design.md 遗漏导致的,先修 design.md 再修代码`,
|
|
38
42
|
outputHint: '实现摘要',
|
|
39
43
|
optional: false
|
|
40
44
|
},
|
package/src/stages/verify.js
CHANGED
|
@@ -55,13 +55,14 @@ export const definition = {
|
|
|
55
55
|
},
|
|
56
56
|
{
|
|
57
57
|
name: '对照设计检查',
|
|
58
|
-
prompt: `对照 design.md
|
|
58
|
+
prompt: `对照 design.md 检查实现一致性。**design.md 是唯一 truth source,不符合 design.md 的实现 = Bug。**
|
|
59
59
|
|
|
60
60
|
### 操作
|
|
61
61
|
1. 架构决策是否遵循
|
|
62
62
|
2. 文件变更清单是否一致
|
|
63
63
|
3. 数据模型是否符合
|
|
64
64
|
4. API 设计是否符合
|
|
65
|
+
5. **Reverse Sync 检查**:如果发现实现合理但 design.md 未覆盖,先更新 design.md 补充遗漏
|
|
65
66
|
|
|
66
67
|
### 输出
|
|
67
68
|
一致性检查结果`,
|