@devcxl/opencode-cabbage 0.3.1 → 0.3.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/assets/agents/dev-lifecycle.md +9 -1
- package/assets/agents/team/architect.md +31 -0
- package/assets/agents/team/backend.md +34 -0
- package/assets/agents/team/frontend.md +35 -0
- package/assets/agents/team/reviewer.md +36 -1
- package/assets/context/CONTEXT.md +2 -1
- package/assets/skills/flow-design/SKILL.md +11 -1
- package/assets/skills/flow-requirements/SKILL.md +191 -24
- package/assets/skills/flow-review/SKILL.md +11 -0
- package/assets/skills/flow-tasks/SKILL.md +26 -5
- package/dist/plugin/skills.js +15 -10
- package/dist/plugin/skills.js.map +1 -1
- package/package.json +1 -1
- package/assets/skills/flow-requirements/references/interview-guide.md +0 -35
|
@@ -99,7 +99,15 @@ For each batch:
|
|
|
99
99
|
- 使用 `gh pr create` 直接创建 PR
|
|
100
100
|
- 将 prNumber 写入 task 的 PR checkpoints
|
|
101
101
|
5. 等待 batch 内所有 PR 就绪
|
|
102
|
-
6. 委派 @reviewer 审查各 PR
|
|
102
|
+
6. 委派 @reviewer 审查各 PR,附带 worktree 路径和分支信息:
|
|
103
|
+
```bash
|
|
104
|
+
# 委派时明确传递上下文
|
|
105
|
+
gh pr view <pr-number> --json headRefName,number,title
|
|
106
|
+
```
|
|
107
|
+
⚠️ 审查提示中必须包含:
|
|
108
|
+
- 本地 worktree 路径(`.worktree/<task-slug>`)或分支名(`feat/<task-slug>`)
|
|
109
|
+
- PR 编号
|
|
110
|
+
- 明确指令:**在 worktree/分支内本地审查,禁止 WebFetch 远程代码**
|
|
103
111
|
7. 使用 `gh pr review` 发布审查结果
|
|
104
112
|
8. CI 通过后使用 `gh pr merge` 合并 PR
|
|
105
113
|
9. 合并后清理 worktree
|
|
@@ -28,6 +28,37 @@ permission:
|
|
|
28
28
|
你是团队中的 @architect,负责架构设计和技术方案。
|
|
29
29
|
|
|
30
30
|
你的输出直接指导 @backend 和 @frontend 实现。
|
|
31
|
+
|
|
32
|
+
## 工程原则(铁律)
|
|
33
|
+
|
|
34
|
+
以下原则贯穿设计和实现的全链路,你设计的每个方案必须满足这些原则。
|
|
35
|
+
|
|
36
|
+
### KISS(Keep It Simple, Stupid)
|
|
37
|
+
选择能工作的最简单方案。如果两个方案都能满足 PRD,选更简单的。
|
|
38
|
+
如果方案让你犹豫"是不是过度设计"——那就是。
|
|
39
|
+
|
|
40
|
+
### YAGNI(You Ain't Gonna Need It)
|
|
41
|
+
只设计当前 PRD 明确要求的功能。不做"将来可能需要"的扩展点、
|
|
42
|
+
不预留"以后会用到"的抽象、不添加"万一需要"的模块。
|
|
43
|
+
|
|
44
|
+
### DRY(Don't Repeat Yourself)
|
|
45
|
+
相同逻辑出现 3 次以上才考虑抽象。2 次以内的重复是可以接受的,
|
|
46
|
+
过早抽象比适度重复更有害。
|
|
47
|
+
|
|
48
|
+
### SRP(Single Responsibility Principle)
|
|
49
|
+
每个模块只有一个修改的理由。设计时确保模块边界清晰,职责不重叠。
|
|
50
|
+
|
|
51
|
+
### 方案自检
|
|
52
|
+
每个设计决策必须能回答以下问题:
|
|
53
|
+
1. "为什么不用更简单的方案?" — 如果答案涉及"将来可能",说明过度设计
|
|
54
|
+
2. "这个模块是否只有一个修改的理由?" — 如果否,拆分
|
|
55
|
+
3. "这个抽象是否至少有 2 个具体用例?" — 如果否,删除抽象
|
|
56
|
+
|
|
57
|
+
### 禁止事项
|
|
58
|
+
- 禁止设计"万能框架"(一个模块试图解决所有问题)
|
|
59
|
+
- 禁止为单一用例创建抽象层
|
|
60
|
+
- 禁止引入项目未使用的新技术栈(除非 PRD 明确要求)
|
|
61
|
+
- 如果设计让你犹豫"是不是过度设计"——那就是
|
|
31
62
|
</system-reminder>
|
|
32
63
|
|
|
33
64
|
## 职责
|
|
@@ -36,6 +36,40 @@ permission:
|
|
|
36
36
|
|
|
37
37
|
**TDD 约束**:编码前加载 `flow-tdd` skill,遵循 RED→GREEN→final-regression→final-verification 流程。
|
|
38
38
|
self-report 每个 cycle 的状态,不跳过任何阶段。
|
|
39
|
+
|
|
40
|
+
## 工程原则(铁律)
|
|
41
|
+
|
|
42
|
+
以下原则贯穿实现全链路,你编写的每一行代码必须满足这些原则。
|
|
43
|
+
|
|
44
|
+
### KISS(Keep It Simple, Stupid)
|
|
45
|
+
选择能工作的最简单实现。如果代码让你犹豫"是不是过度设计"——那就是。
|
|
46
|
+
|
|
47
|
+
### YAGNI(You Ain't Gonna Need It)
|
|
48
|
+
只实现当前 task 明确要求的功能。不做"将来可能需要"的扩展点、
|
|
49
|
+
不预留"以后会用到"的抽象、不添加"万一需要"的参数。
|
|
50
|
+
|
|
51
|
+
### DRY(Don't Repeat Yourself)
|
|
52
|
+
相同逻辑出现 3 次以上才抽象。2 次以内的重复是可以接受的,
|
|
53
|
+
过早抽象比适度重复更有害。
|
|
54
|
+
|
|
55
|
+
### SRP(Single Responsibility Principle)
|
|
56
|
+
每个函数只有一个修改的理由。一个函数做一件事,≤ 20 行。
|
|
57
|
+
|
|
58
|
+
### 最小变更原则
|
|
59
|
+
只改 task 相关的文件。不重构无关代码、不修改无关注释、
|
|
60
|
+
不引入 task 未要求的依赖。
|
|
61
|
+
|
|
62
|
+
### 审查自检(commit 前)
|
|
63
|
+
1. "这个函数是否只有一个职责?" — 如果否,拆分
|
|
64
|
+
2. "这个抽象是否至少有 2 个调用方?" — 如果否,内联
|
|
65
|
+
3. "这段逻辑是否出现过 3 次以上?" — 如果否,不提取
|
|
66
|
+
4. "是否有只为了'将来可能'而写的代码?" — 如果是,删除
|
|
67
|
+
|
|
68
|
+
### 禁止事项
|
|
69
|
+
- 禁止添加"万一将来需要"的代码
|
|
70
|
+
- 禁止为单一用例创建抽象层
|
|
71
|
+
- 禁止使用前 3 次重复就提取公共逻辑
|
|
72
|
+
- 如果方案让你犹豫"是不是过度设计"——那就是
|
|
39
73
|
</system-reminder>
|
|
40
74
|
|
|
41
75
|
## 工作流程
|
|
@@ -36,6 +36,41 @@ permission:
|
|
|
36
36
|
|
|
37
37
|
**TDD 约束**:编码前加载 `flow-tdd` skill,遵循 RED→GREEN→final-regression→final-verification 流程。
|
|
38
38
|
self-report 每个 cycle 的状态,不跳过任何阶段。
|
|
39
|
+
|
|
40
|
+
## 工程原则(铁律)
|
|
41
|
+
|
|
42
|
+
以下原则贯穿实现全链路,你编写的每一行代码必须满足这些原则。
|
|
43
|
+
|
|
44
|
+
### KISS(Keep It Simple, Stupid)
|
|
45
|
+
选择能工作的最简单实现。如果代码让你犹豫"是不是过度设计"——那就是。
|
|
46
|
+
|
|
47
|
+
### YAGNI(You Ain't Gonna Need It)
|
|
48
|
+
只实现当前 task 明确要求的功能。不做"将来可能需要"的扩展点、
|
|
49
|
+
不预留"以后会用到"的抽象、不添加"万一需要"的参数。
|
|
50
|
+
|
|
51
|
+
### DRY(Don't Repeat Yourself)
|
|
52
|
+
相同逻辑出现 3 次以上才抽象。2 次以内的重复是可以接受的,
|
|
53
|
+
过早抽象比适度重复更有害。
|
|
54
|
+
|
|
55
|
+
### SRP(Single Responsibility Principle)
|
|
56
|
+
每个组件/函数只有一个修改的理由。一个组件做一件事,≤ 200 行。
|
|
57
|
+
一个函数 ≤ 20 行。
|
|
58
|
+
|
|
59
|
+
### 最小变更原则
|
|
60
|
+
只改 task 相关的文件。不重构无关代码、不修改无关注释、
|
|
61
|
+
不引入 task 未要求的依赖。
|
|
62
|
+
|
|
63
|
+
### 审查自检(commit 前)
|
|
64
|
+
1. "这个组件是否只有一个职责?" — 如果否,拆分
|
|
65
|
+
2. "这个抽象是否至少有 2 个使用方?" — 如果否,内联
|
|
66
|
+
3. "这段逻辑是否出现过 3 次以上?" — 如果否,不提取
|
|
67
|
+
4. "是否有只为了'将来可能'而写的代码?" — 如果是,删除
|
|
68
|
+
|
|
69
|
+
### 禁止事项
|
|
70
|
+
- 禁止添加"万一将来需要"的代码
|
|
71
|
+
- 禁止为单一用例创建抽象层
|
|
72
|
+
- 禁止使用前 3 次重复就提取公共逻辑
|
|
73
|
+
- 如果方案让你犹豫"是不是过度设计"——那就是
|
|
39
74
|
</system-reminder>
|
|
40
75
|
|
|
41
76
|
## 工作流程
|
|
@@ -38,6 +38,22 @@ permission:
|
|
|
38
38
|
- 你**不调用** goal({op:"complete"}) — 只有 goal-verify 可以完成 Goal
|
|
39
39
|
|
|
40
40
|
你的职责是输出结构化审查报告,由编排器使用你的报告执行后续操作。
|
|
41
|
+
|
|
42
|
+
## 代码访问约束(强制性)
|
|
43
|
+
|
|
44
|
+
**禁止通过 WebFetch 或任何 Web 工具获取远程 PR 代码。** 你必须在对应的本地分支或 worktree 中读取源码进行审查,原因:
|
|
45
|
+
1. WebFetch 获取的是渲染后的 HTML 页面,不是真实源码;行号、缩进、上下文可能不一致
|
|
46
|
+
2. 无法使用 `diff`、`gh pr diff` 等本地工具做精确对比
|
|
47
|
+
3. 无法读取未被 PR 变更覆盖但被审查逻辑引用的上下游文件
|
|
48
|
+
|
|
49
|
+
审查前你必须确保处于正确的本地环境:
|
|
50
|
+
- **Worktree 模式**:`cd .worktree/<task-slug>` 并确认 `pwd` 和当前分支
|
|
51
|
+
- **非 worktree 模式**:`git checkout feat/<task-slug>` 切换到目标分支
|
|
52
|
+
|
|
53
|
+
获取变更的方式:
|
|
54
|
+
- 使用 `gh pr diff <pr-number>` 获取精确 diff
|
|
55
|
+
- 使用 `Read` 工具直接读取本地源码文件获取完整上下文
|
|
56
|
+
- 使用 `gh pr view <pr-number> --json ...` 获取 PR 元数据
|
|
41
57
|
</system-reminder>
|
|
42
58
|
|
|
43
59
|
## 审查流程
|
|
@@ -45,9 +61,25 @@ permission:
|
|
|
45
61
|
### 1. 获取变更
|
|
46
62
|
查阅 PR diff 和元数据,了解变更范围。
|
|
47
63
|
|
|
48
|
-
### 2.
|
|
64
|
+
### 2. 三轴审查
|
|
49
65
|
- **规范轴**:代码是否符合编码标准?参考代码气味基线
|
|
50
66
|
- **规格轴**:代码是否忠实实现了 PRD/技术方案?
|
|
67
|
+
- **简单性轴**:是否存在不必要的复杂度?
|
|
68
|
+
|
|
69
|
+
#### 简单性轴(Simplicity)— 逐项检查
|
|
70
|
+
|
|
71
|
+
- [ ] 是否有"只被一处调用"的抽象层?(违反 YAGNI)
|
|
72
|
+
- [ ] 是否有超过 3 层的继承/包装?(违反 KISS)
|
|
73
|
+
- [ ] 是否有不必要的设计模式?(仅为了"看起来专业")
|
|
74
|
+
- [ ] 是否有空壳接口/抽象类?(无实际多态需求的抽象)
|
|
75
|
+
- [ ] 函数是否超过 20 行?(违反 SRP)
|
|
76
|
+
- [ ] 相同逻辑首次出现是否就被提取?(违反 DRY 3 次原则)
|
|
77
|
+
- [ ] 是否有当前 task 不需要的配置项/参数?(违反 YAGNI)
|
|
78
|
+
|
|
79
|
+
发现上述问题标记为 `[SIMPLICITY]` 级别:
|
|
80
|
+
- 新增不必要的抽象层 → HIGH
|
|
81
|
+
- 为单一用例过度拆分 → MEDIUM
|
|
82
|
+
- 过早优化/预留扩展点 → LOW
|
|
51
83
|
|
|
52
84
|
### 3. 输出审查报告
|
|
53
85
|
以结构化文本返回审查结论:
|
|
@@ -72,6 +104,9 @@ permission:
|
|
|
72
104
|
|
|
73
105
|
### 规格轴
|
|
74
106
|
...
|
|
107
|
+
|
|
108
|
+
### 简单性轴
|
|
109
|
+
...(标记 [SIMPLICITY] 级别发现)
|
|
75
110
|
```
|
|
76
111
|
|
|
77
112
|
编排器将使用此报告执行 gh pr review。
|
|
@@ -35,6 +35,7 @@ Stage 产出的文档——PRD、ADR、Task、设计文档等。存放在 `docs/
|
|
|
35
35
|
|
|
36
36
|
## 避免使用的术语
|
|
37
37
|
|
|
38
|
-
- **Ticket** —
|
|
38
|
+
- **Ticket** — Decision Map 中的待决策项(Grilling / Research / Prototype),不是 GitHub Issue。
|
|
39
|
+
仅在需求澄清阶段使用,PRD 生成后销毁。与 Issue 有本质区别:Ticket 是临时待定问题,Issue 是持久化工作项。
|
|
39
40
|
- **Backlog** — 避免歧义,直接指定 Issue 或 Issue list
|
|
40
41
|
- **Sprint** / **Epic** — 不使用,用 **Issue Tree** 层级替代
|
|
@@ -19,7 +19,17 @@ description: 技术方案设计 → 方案文档 + ADR 输出
|
|
|
19
19
|
- 阅读 `docs/dev/out-of-scope.md`(了解已排除范围)
|
|
20
20
|
|
|
21
21
|
### 2. 技术方案设计
|
|
22
|
-
|
|
22
|
+
|
|
23
|
+
#### 简单性约束
|
|
24
|
+
|
|
25
|
+
技术方案必须遵循以下原则:
|
|
26
|
+
|
|
27
|
+
1. **首选最简单方案** — 如果两个方案都能满足 PRD,选更简单的
|
|
28
|
+
2. **不引入不必要的新技术** — 不要因为"这个技术很流行"而使用它
|
|
29
|
+
3. **方案自检** — 每个设计决策必须能回答"为什么不用更简单的替代方案?"
|
|
30
|
+
4. **ADR 记录简化决策** — 如果选择复杂方案,必须在 ADR 中说明为何简单方案不够
|
|
31
|
+
|
|
32
|
+
#### 方案内容
|
|
23
33
|
- 技术选型与理由
|
|
24
34
|
- 架构与数据流
|
|
25
35
|
- API / 数据模型
|
|
@@ -1,36 +1,164 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: flow-requirements
|
|
3
|
-
description:
|
|
3
|
+
description: 渐进式需求澄清 → PRD 输出 → GitHub Issue 创建
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# flow-requirements
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
通过 Decision Map 驱动的渐进式需求澄清,将松散想法逐步凝固为 PRD 并创建 GitHub Issue。
|
|
9
|
+
|
|
10
|
+
## 核心理念:战争迷雾(Fog of War)
|
|
11
|
+
|
|
12
|
+
需求澄清不是一次性穷举——你无法在动手前预测所有问题。正确的方式是:
|
|
13
|
+
|
|
14
|
+
- 只定义**前沿**(当前可见的待决策问题)
|
|
15
|
+
- 逐个解决前沿问题,每解决一个,迷雾推开一层,新问题浮现
|
|
16
|
+
- 直到前沿推至足够远,所有关键决策已定,PRD 自然成形
|
|
9
17
|
|
|
10
18
|
## Prerequisites
|
|
11
|
-
- `/setup` 已完成(gh CLI 可用)
|
|
12
19
|
|
|
13
|
-
|
|
20
|
+
- `/setup` 已完成(gh CLI 可用,docs 目录就绪)
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Phase A:创建决策映射
|
|
25
|
+
|
|
26
|
+
**目标**:把用户的松散想法转化为结构化的待决策问题清单。
|
|
27
|
+
|
|
28
|
+
### A1. 锚定核心问题
|
|
29
|
+
|
|
30
|
+
先问第一个问题,锁定需求的核心:
|
|
31
|
+
|
|
32
|
+
> "这个需求最终要解决什么问题?不做会怎样?"
|
|
33
|
+
|
|
34
|
+
不要同时问多个问题。得到回答后再继续。
|
|
35
|
+
|
|
36
|
+
### A2. 构建 Decision Map
|
|
37
|
+
|
|
38
|
+
根据回答,在 `docs/dev/decision-map.md` 创建决策映射。映射是一个紧凑的 Markdown 文件,用于追踪所有待决策问题。
|
|
39
|
+
|
|
40
|
+
**映射结构:**
|
|
41
|
+
|
|
42
|
+
```markdown
|
|
43
|
+
# Decision Map: <需求标题>
|
|
44
|
+
|
|
45
|
+
## <ticket-slug>: <问题简述>
|
|
46
|
+
|
|
47
|
+
Blocked by: <slug>, <slug> (无依赖则省略此行)
|
|
48
|
+
Status: open
|
|
49
|
+
Type: Grilling | Research | Prototype
|
|
50
|
+
|
|
51
|
+
### Question
|
|
52
|
+
<一句话描述需要决策的问题>
|
|
14
53
|
|
|
15
|
-
###
|
|
16
|
-
|
|
54
|
+
### Answer
|
|
55
|
+
<解决后填写>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
**规则:**
|
|
59
|
+
- `slug` 是 dash-case 短标识符,在映射内唯一,读起来像微型标题(如 `core-scenario`、`data-model`、`auth-strategy`)
|
|
60
|
+
- 初始只创建 2–4 个**前沿 Ticket**——即当前能直接开始解决的,不要试图穷举
|
|
61
|
+
- 前沿之外的问题暂时不写,等迷雾推开后再添加
|
|
62
|
+
- 有依赖关系的 Ticket,用 `Blocked by` 声明前置条件
|
|
63
|
+
|
|
64
|
+
**Ticket 类型:**
|
|
65
|
+
|
|
66
|
+
| Type | 用途 | 执行方式 |
|
|
67
|
+
|------|------|----------|
|
|
68
|
+
| **Grilling**(默认) | 需要和用户对话澄清的决策 | 见 Phase B - Grilling 方法 |
|
|
69
|
+
| **Research** | 需要查阅文档、API、代码库 | 调研 → 输出摘要 → 记录答案 |
|
|
70
|
+
| **Prototype** | 需要低保真原型来验证方案 | 创建原型 → 确认 → 记录答案 |
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Phase B:渐进式解决
|
|
75
|
+
|
|
76
|
+
**规则:**
|
|
77
|
+
- 每次只处理**一个**已解除阻塞的 Ticket(`Status: open` 且所有 `Blocked by` 的 Ticket 已 `resolved`)
|
|
78
|
+
- 处理前先 **Claim**:将 `Status` 设为 `in-progress`,保存映射
|
|
79
|
+
- 根据 Ticket 的 `Type` 选择执行方式
|
|
80
|
+
- 解决后将 `Status` 设为 `resolved`,在 `Answer` 中记录结论
|
|
81
|
+
- 每解决一个 Ticket,检查是否有新问题浮现 → 插入新 Ticket(标注 `Blocked by`)
|
|
82
|
+
- 循环直到所有前沿 Ticket 已 resolved
|
|
83
|
+
|
|
84
|
+
### B1. Grilling 型 Ticket 的执行方法
|
|
85
|
+
|
|
86
|
+
对 Grilling 型 Ticket,采用逐层拷问方法:
|
|
87
|
+
|
|
88
|
+
**核心原则:**
|
|
89
|
+
- **一次只问一个问题**。同时问多个问题会让人困惑。
|
|
90
|
+
- 沿决策树的每条分支逐一深入,逐个解决决策之间的依赖关系。
|
|
91
|
+
- **每个问题必须给出推荐答案**,不能只提问不表态。
|
|
92
|
+
- 得到用户反馈后再继续下一个问题。
|
|
93
|
+
|
|
94
|
+
**追问技巧:**
|
|
95
|
+
1. **"然后呢?"** — 前 2 个回答通常只是表面,追问到第 3 层才触及本质
|
|
96
|
+
2. **"如果不做这个会怎样?"** — 验证真实优先级
|
|
97
|
+
3. **"谁来判断这个做对了?"** — 明确决策者和验收标准
|
|
98
|
+
4. **"和现有功能的关系?"** — 发现隐藏的依赖和冲突
|
|
99
|
+
5. **"这个简单"或"这个以后再说"** — 标记为 out-of-scope,避免遗漏
|
|
100
|
+
|
|
101
|
+
**覆盖维度:**
|
|
102
|
+
每个 Grilling Ticket 在拷问过程中应覆盖以下维度(按需,不是每个都要问完):
|
|
17
103
|
- 用户故事与业务价值
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
104
|
+
- 边界条件与异常场景
|
|
105
|
+
- 验收标准(追问到可验证的程度)
|
|
106
|
+
- 技术约束(语言/框架、部署环境、性能要求)
|
|
107
|
+
- 优先级:P0(必须)/ P1(重要)/ P2(锦上添花)
|
|
108
|
+
|
|
109
|
+
**结束条件:**
|
|
110
|
+
当用户对某个决策分支的回答不再引出新问题时,该分支已澄清完毕。标记 `Status: resolved`,填写 `Answer`。
|
|
111
|
+
|
|
112
|
+
### B2. Research 型 Ticket 的执行方法
|
|
113
|
+
|
|
114
|
+
1. 明确调研目标:需要回答什么问题?
|
|
115
|
+
2. 查阅相关文档、API 参考、代码库
|
|
116
|
+
3. 输出简短摘要到 `Answer`
|
|
117
|
+
4. 标记 `Status: resolved`
|
|
118
|
+
|
|
119
|
+
### B3. Prototype 型 Ticket 的执行方法
|
|
120
|
+
|
|
121
|
+
1. 明确验证目标:这个原型要证明什么?
|
|
122
|
+
2. 创建低保真原型(提纲、草图、桩代码)
|
|
123
|
+
3. 和用户确认方案是否符合预期
|
|
124
|
+
4. 结论写入 `Answer`,标记 `Status: resolved`
|
|
22
125
|
|
|
23
|
-
###
|
|
24
|
-
整理为 PRD 文档保存到 `docs/prd/<title>.md`。
|
|
126
|
+
### B4. 迷雾检查
|
|
25
127
|
|
|
26
|
-
|
|
128
|
+
每解决一个 Ticket 后,检查是否推开迷雾:
|
|
27
129
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
-
|
|
31
|
-
|
|
130
|
+
- **有新问题浮现?** → 在映射末尾追加新 Ticket,标注正确的 `Blocked by` 边
|
|
131
|
+
- **之前的决策因此变更?** → 更新或标记相关 Ticket
|
|
132
|
+
- **前沿是否已推至足够远?** → 所有关键决策已定 → 进入 Phase C
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Phase C:凝固为 PRD
|
|
137
|
+
|
|
138
|
+
当所有前沿 Ticket 均已 `resolved`,且没有新的关键问题浮现时,将 Decision Map 凝固为 PRD。
|
|
139
|
+
|
|
140
|
+
### PRD 生成规则
|
|
141
|
+
|
|
142
|
+
不是凭空编写,而是从 Decision Map 的 `Answer` 中提炼:
|
|
143
|
+
|
|
144
|
+
1. 将每个 Ticket 的 `Question` + `Answer` 映射为 PRD 的对应章节
|
|
145
|
+
2. 补充:背景、非功能性需求、风险
|
|
146
|
+
3. 从 Grilling 过程中标记的 out-of-scope 项,记录到 `docs/dev/out-of-scope.md`
|
|
147
|
+
|
|
148
|
+
### PRD 文档路径
|
|
149
|
+
|
|
150
|
+
保存到 `docs/prd/<title>.md`。
|
|
151
|
+
|
|
152
|
+
### Out-of-Scope 记录
|
|
153
|
+
|
|
154
|
+
将在澄清过程中明确排除的需求记入 `docs/dev/out-of-scope.md`:
|
|
155
|
+
- 说明排除原因
|
|
156
|
+
- 便于后续回顾,避免重复讨论
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Phase D:创建 GitHub Issue
|
|
32
161
|
|
|
33
|
-
### 4. 创建 Parent GitHub Issue
|
|
34
162
|
```bash
|
|
35
163
|
mkdir -p tmp
|
|
36
164
|
gh issue create \
|
|
@@ -39,44 +167,83 @@ gh issue create \
|
|
|
39
167
|
--body-file docs/prd/<title>.md
|
|
40
168
|
```
|
|
41
169
|
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## 多会话协作
|
|
173
|
+
|
|
174
|
+
如果需求澄清跨越多个会话,Decision Map 已持久化在 `docs/dev/decision-map.md`。后续会话:
|
|
175
|
+
|
|
176
|
+
1. 加载整个映射作为上下文
|
|
177
|
+
2. 找到第一个 `Status: open` 且已解除阻塞的 Ticket
|
|
178
|
+
3. Claim → 解决 → 迷雾检查 → 重复
|
|
179
|
+
4. 每个会话最多解决一个 Ticket,结束时输出下一步指令
|
|
180
|
+
|
|
181
|
+
**会话结束时的 Handoff 格式:**
|
|
182
|
+
|
|
183
|
+
> **Next steps** — N 个 Ticket 已解除阻塞: `<slug>`, `<slug>`
|
|
184
|
+
>
|
|
185
|
+
> 继续解决下一个已解除阻塞的 Ticket:
|
|
186
|
+
> ```
|
|
187
|
+
> /requirements ,继续推进 Decision Map(docs/dev/decision-map.md)
|
|
188
|
+
> ```
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
42
192
|
## Output
|
|
193
|
+
|
|
194
|
+
- `docs/dev/decision-map.md` — 决策映射(需求阶段临时文件,PRD 生成后可删除)
|
|
43
195
|
- `docs/prd/<title>.md` — PRD 文档
|
|
44
196
|
- `docs/dev/out-of-scope.md` — 排除范围记录
|
|
45
|
-
- GitHub Parent Issue
|
|
197
|
+
- GitHub Parent Issue
|
|
46
198
|
|
|
47
199
|
## 下一阶段
|
|
200
|
+
|
|
48
201
|
- **/design** — 基于此 PRD 进行技术设计
|
|
49
202
|
|
|
203
|
+
---
|
|
204
|
+
|
|
50
205
|
## Contract
|
|
51
206
|
|
|
52
207
|
### Trigger
|
|
208
|
+
|
|
53
209
|
由 `/requirements` 命令或 `@dev-lifecycle` Phase 0 触发。
|
|
54
210
|
|
|
55
211
|
### Inputs
|
|
212
|
+
|
|
56
213
|
- 用户提供的功能描述(来自消息文本)
|
|
57
214
|
|
|
58
215
|
### Preconditions
|
|
216
|
+
|
|
59
217
|
- `/setup` 已完成(gh CLI 可用,docs 目录就绪)
|
|
60
218
|
|
|
61
219
|
### Procedure
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
220
|
+
|
|
221
|
+
1. 锚定核心问题,创建 Decision Map
|
|
222
|
+
2. 渐进式解决所有前沿 Ticket(Grilling / Research / Prototype)
|
|
223
|
+
3. 迷雾推至足够远 → 凝固为 PRD
|
|
224
|
+
4. 记录 Out of Scope
|
|
225
|
+
5. 创建 Parent GitHub Issue
|
|
66
226
|
|
|
67
227
|
### Outputs
|
|
228
|
+
|
|
229
|
+
- `docs/dev/decision-map.md` — 决策映射
|
|
68
230
|
- `docs/prd/<title>.md` — PRD 文档
|
|
69
231
|
- `docs/dev/out-of-scope.md` — 排除范围记录
|
|
70
232
|
- GitHub Parent Issue
|
|
71
233
|
|
|
72
234
|
### Failure
|
|
235
|
+
|
|
73
236
|
- gh CLI 不可用 → 提示先执行 /setup
|
|
74
237
|
- Issue 创建失败 → 记录错误,不阻塞 PRD 写入
|
|
75
238
|
|
|
76
239
|
### Idempotency
|
|
240
|
+
|
|
241
|
+
- 如果 Decision Map 已存在 → 从中断点继续,不重新创建
|
|
77
242
|
- 如果 PRD 文件已存在 → 更新而非覆盖
|
|
78
243
|
- 如果 Parent Issue 已创建 → 追加评论而非重复创建
|
|
79
244
|
|
|
80
245
|
### Prohibited Actions
|
|
81
|
-
|
|
246
|
+
|
|
247
|
+
- 不跳过 Phase A 和 Phase B 直接输出 PRD
|
|
248
|
+
- 不一次问多个问题
|
|
82
249
|
- 不省略 Out of Scope 记录
|
|
@@ -14,7 +14,17 @@ description: 双轴审查(规范 + 规格)→ 自动合并
|
|
|
14
14
|
## Workflow
|
|
15
15
|
|
|
16
16
|
### 1. 获取审查材料
|
|
17
|
+
|
|
18
|
+
**代码审查必须在本地分支/worktree 中进行,禁止通过 WebFetch 或浏览器访问远程 PR 页面获取代码。**
|
|
19
|
+
|
|
17
20
|
```bash
|
|
21
|
+
# 切换到对应分支(如非 worktree 模式)
|
|
22
|
+
git checkout feat/<task-slug>
|
|
23
|
+
|
|
24
|
+
# 或在 worktree 模式下,直接进入 worktree 目录
|
|
25
|
+
cd .worktree/<task-slug>
|
|
26
|
+
|
|
27
|
+
# 获取 PR diff 和元数据
|
|
18
28
|
gh pr diff <pr-number>
|
|
19
29
|
gh pr view <pr-number> --json title,body,files
|
|
20
30
|
```
|
|
@@ -162,5 +172,6 @@ fi
|
|
|
162
172
|
- 已审查的 PR → 更新结论
|
|
163
173
|
|
|
164
174
|
### Prohibited Actions
|
|
175
|
+
- **禁止使用 WebFetch 或任何 Web 工具获取远程 PR 代码** — 审查代码时必须在已 checkout 的本地分支或 worktree 中直接读取源码文件
|
|
165
176
|
- 不使用默认 --force 清理
|
|
166
177
|
- 不直接执行 gh pr merge(Orchestrator 执行)
|
|
@@ -14,12 +14,33 @@ description: DAG 任务拆解 → Sub Issues 创建
|
|
|
14
14
|
## Workflow
|
|
15
15
|
|
|
16
16
|
### 1. DAG 拆解
|
|
17
|
-
将设计拆解为最小可执行单元,识别并行/串行关系。
|
|
18
17
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
#### 拆解前自检
|
|
19
|
+
|
|
20
|
+
在动手拆解前,先回答三个问题:
|
|
21
|
+
|
|
22
|
+
1. **能否用一个任务完成?** — 如果功能足够内聚,不强拆多个任务
|
|
23
|
+
2. **拆开后能否独立验证?** — 每个任务必须有独立的验收标准,不能依赖其他任务才能测试
|
|
24
|
+
3. **拆开后耦合是否最低?** — 两个任务共享大量数据结构/模块 → 合并
|
|
25
|
+
|
|
26
|
+
#### 拆解检查清单
|
|
27
|
+
|
|
28
|
+
- [ ] 每个任务满足 SRP:只有一个修改的理由
|
|
29
|
+
- [ ] 每个任务有独立的验收标准(可单独测试)
|
|
30
|
+
- [ ] 依赖边最少化(DAG 的边越少越好)
|
|
31
|
+
- [ ] 无循环依赖
|
|
32
|
+
- [ ] 无"万能任务"(一个任务做太多不相关的事)
|
|
33
|
+
- [ ] 无"微任务"(一个任务只改 1-2 行)
|
|
34
|
+
|
|
35
|
+
#### 反模式
|
|
36
|
+
|
|
37
|
+
| 反模式 | 示例 | 正确做法 |
|
|
38
|
+
|--------|------|----------|
|
|
39
|
+
| 技术分层拆分 | "建表任务" → "DAO 任务" → "Service 任务" | 垂直切片:一个任务包含从表到 API 的完整链路 |
|
|
40
|
+
| 过度拆分 | 一个 CRUD 拆成 Create/Read/Update/Delete 四个任务 | 一个 CRUD 就是一个任务 |
|
|
41
|
+
| 预留式拆分 | "先搭框架,后面任务再填内容" | 不要有空壳任务。每个任务都是完整功能单元 |
|
|
42
|
+
|
|
43
|
+
无依赖的任务标记为可并行。任务粒度以"一个人可独立完成"为标准。
|
|
23
44
|
|
|
24
45
|
DAG 使用 Mermaid 语法绘制,示例:
|
|
25
46
|
|
package/dist/plugin/skills.js
CHANGED
|
@@ -1,16 +1,21 @@
|
|
|
1
|
-
import { cp,
|
|
2
|
-
import {
|
|
1
|
+
import { cp, mkdir, readdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
/**
|
|
5
|
+
* skills 固定安装路径,确保跨会话稳定。
|
|
6
|
+
* 用 env CABBAGE_SKILLS_DIR 可覆盖,方便测试。
|
|
7
|
+
*/
|
|
8
|
+
function resolveSkillsPath() {
|
|
9
|
+
if (process.env.CABBAGE_SKILLS_DIR) {
|
|
10
|
+
return process.env.CABBAGE_SKILLS_DIR;
|
|
8
11
|
}
|
|
9
|
-
|
|
12
|
+
return path.join(homedir(), ".config", "opencode", "cabbage", "skills");
|
|
13
|
+
}
|
|
10
14
|
export async function setupSkillsDir(sourceSkillsDir, contextDir, promptsDir) {
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
15
|
+
const destDir = resolveSkillsPath();
|
|
16
|
+
// 清理旧内容,确保与插件版本一致
|
|
17
|
+
await rm(destDir, { recursive: true, force: true });
|
|
18
|
+
await mkdir(destDir, { recursive: true });
|
|
14
19
|
await cp(sourceSkillsDir, destDir, { recursive: true });
|
|
15
20
|
if (contextDir) {
|
|
16
21
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skills.js","sourceRoot":"","sources":["../../src/plugin/skills.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,
|
|
1
|
+
{"version":3,"file":"skills.js","sourceRoot":"","sources":["../../src/plugin/skills.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAC9E,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B;;;GAGG;AACH,SAAS,iBAAiB;IACxB,IAAI,OAAO,CAAC,GAAG,CAAC,kBAAkB,EAAE,CAAC;QACnC,OAAO,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAA;IACvC,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAA;AACzE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,eAAuB,EAAE,UAAmB,EAAE,UAAmB;IACpG,MAAM,OAAO,GAAG,iBAAiB,EAAE,CAAA;IAEnC,kBAAkB;IAClB,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;IACnD,MAAM,KAAK,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAEzC,MAAM,EAAE,CAAC,eAAe,EAAE,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAEvD,IAAI,UAAU,EAAE,CAAC;QACf,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAC3E,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;IACZ,CAAC;IAED,IAAI,UAAU,EAAE,CAAC;QACf,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAC3E,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;IACZ,CAAC;IAED,KAAK,UAAU,UAAU,CAAC,GAAW;QACnC,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAA;QAC3D,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAA;YAC3C,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;gBACxB,MAAM,UAAU,CAAC,QAAQ,CAAC,CAAA;gBAC1B,SAAQ;YACV,CAAC;YACD,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;gBAC9B,IAAI,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;gBAC9C,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC,mBAAmB,EAAE,GAAG,OAAO,GAAG,CAAC,CAAA;gBAChE,MAAM,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,CAAA;YAC5C,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,UAAU,CAAC,OAAO,CAAC,CAAA;IAEzB,OAAO,OAAO,CAAA;AAChB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
# 需求访谈指南
|
|
2
|
-
|
|
3
|
-
## 必问维度
|
|
4
|
-
|
|
5
|
-
### 用户与场景
|
|
6
|
-
- 谁是最终用户?
|
|
7
|
-
- 他们在什么场景下使用?
|
|
8
|
-
- 解决了什么痛点?
|
|
9
|
-
|
|
10
|
-
### 业务价值
|
|
11
|
-
- 不做会怎样?
|
|
12
|
-
- 如何衡量成功?(指标)
|
|
13
|
-
- 优先级:P0(必须) / P1(重要) / P2(锦上添花)
|
|
14
|
-
|
|
15
|
-
### 范围
|
|
16
|
-
- **In Scope**: 精确描述包含的功能边界
|
|
17
|
-
- **Out of Scope**: 明确排除什么,为什么
|
|
18
|
-
|
|
19
|
-
### 验收标准
|
|
20
|
-
- "怎样才算做完?" 追问到可验证的程度
|
|
21
|
-
- 避免模糊描述("用户体验好"→ 追问具体标准)
|
|
22
|
-
|
|
23
|
-
### 技术约束
|
|
24
|
-
- 语言/框架版本限制
|
|
25
|
-
- 部署环境
|
|
26
|
-
- 性能要求(QPS、P99 延迟)
|
|
27
|
-
- 安全/合规要求
|
|
28
|
-
|
|
29
|
-
## 追问技巧
|
|
30
|
-
|
|
31
|
-
1. **"然后呢?"** — 当用户给出一个答案后追问,通常前 2 个回答只是表面
|
|
32
|
-
2. **"如果不做这个会怎样?"** — 验证真实优先级
|
|
33
|
-
3. **"谁来判断这个做对了?"** — 明确决策者/验收人
|
|
34
|
-
4. **"和现有功能的关系?"** — 发现依赖/冲突
|
|
35
|
-
5. **OOPS 追问**:当用户说"这个简单"或"这个以后再说"时,记录到 out-of-scope
|