specline 1.3.0 → 1.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/README.md +15 -7
- package/cli.mjs +32 -32
- package/package.json +1 -1
- package/templates/.cursor/skills/specline-pipeline/SKILL.md +58 -600
- package/templates/.cursor/skills/specline-pipeline/references/error-recovery-details.md +49 -0
- package/templates/.cursor/skills/specline-pipeline/references/event-log-spec.md +59 -0
- package/templates/.cursor/skills/specline-pipeline/references/pipeline-state-schema.md +87 -0
- package/templates/.cursor/skills/specline-pipeline/templates/subagent-prompts.md +221 -0
- package/templates/.specline-config.yaml +0 -1
|
@@ -9,40 +9,11 @@ description: >-
|
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
-
## Layer 0: Session
|
|
12
|
+
## Layer 0: Session 绑定
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
### 启动时行为
|
|
19
|
-
|
|
20
|
-
`sessionStart` Hook (`specline-session-start.sh`) 自动处理:
|
|
21
|
-
|
|
22
|
-
1. **已绑定且有效** → 直接使用,注入正确的阶段约束
|
|
23
|
-
2. **无绑定** → 透明放行(`echo '{}'`),不自动扫描活跃 pipeline,不注入任何上下文
|
|
24
|
-
3. **过期绑定清理** → `bound_at` 超过 7 天的绑定自动删除
|
|
25
|
-
4. **脏数据清理** → 绑定指向已归档/不存在的 Pipeline 时自动删除
|
|
26
|
-
|
|
27
|
-
> **重要**:sessionStart 不再自动扫描和绑定活跃 pipeline。要绑定到一个 Pipeline,需要显式执行 `/specline-pipeline --change <name>`。
|
|
28
|
-
|
|
29
|
-
### 用户要求切换 Pipeline 时
|
|
30
|
-
|
|
31
|
-
当用户在对话中说「帮我处理 \<other-change\>」:
|
|
32
|
-
|
|
33
|
-
1. 检查当前 Pipeline 是否在安全切换点(Gate 之后、批次之间)
|
|
34
|
-
2. 如果当前在 CODING 批次中间 → 提示「请先完成当前批次」
|
|
35
|
-
3. 否则执行切换:
|
|
36
|
-
|
|
37
|
-
```bash
|
|
38
|
-
.cursor/hooks/specline-pipeline-gate.sh bind <session_id> <other_change>
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
绑定后,下一个 Hook 调用立即生效。
|
|
42
|
-
|
|
43
|
-
### Pipeline 归档时自动解绑
|
|
44
|
-
|
|
45
|
-
`gate archive --execute` 会自动清理所有绑定到该 Pipeline 的 session 记录,无需手工操作。
|
|
14
|
+
Session 通过 `specline-pipeline-gate.sh bind <session_id> <change>` 绑定到 Pipeline。
|
|
15
|
+
绑定后 sessionStart Hook 自动注入阶段上下文,归档时自动解绑。
|
|
16
|
+
切换 Pipeline 需在安全切换点(Gate 之后、批次之间)执行。
|
|
46
17
|
|
|
47
18
|
---
|
|
48
19
|
|
|
@@ -97,18 +68,7 @@ description: >-
|
|
|
97
68
|
|
|
98
69
|
### Quickfix vs Pipeline 边界判断
|
|
99
70
|
|
|
100
|
-
|
|
101
|
-
|------|-------------------------------|-------------------------------|
|
|
102
|
-
| 文件改动数 | 1-3 个 | 4+ 个 |
|
|
103
|
-
| 关注点 | 单一关注点 | 多关注点/跨模块 |
|
|
104
|
-
| 架构变更 | 无新架构/新组件 | 需要新组件/新 API |
|
|
105
|
-
| 测试 | 不需要新测试 | 需要写新测试 |
|
|
106
|
-
| 典型场景 | 修 bug、改配置、文档微调 | 新增功能、重构 |
|
|
107
|
-
| 产出 | summary.md + files-changed.json | proposal/design/tasks/specs + 全部测试 |
|
|
108
|
-
| 人工确认 | 0 个 | 3 个 |
|
|
109
|
-
| 耗时 | 1-3 分钟 | 10-30 分钟 |
|
|
110
|
-
|
|
111
|
-
**使用建议**:如果不确定,优先用 quickfix。如果需要更严格的流程保证,用 pipeline。
|
|
71
|
+
**Quickfix vs Pipeline**:小改动(1-3 文件、单一关注点)使用 `/specline-quickfix`,多功能/跨模块改动使用 `/specline-pipeline`。详细对比见 `specline-quickfix` Skill。
|
|
112
72
|
|
|
113
73
|
---
|
|
114
74
|
|
|
@@ -175,13 +135,7 @@ specline-spec-reviewer 审核三份文件:
|
|
|
175
135
|
.cursor/hooks/specline-pipeline-gate.sh spec --change "<name>"
|
|
176
136
|
```
|
|
177
137
|
|
|
178
|
-
|
|
179
|
-
- ✓ `proposal.md` 存在
|
|
180
|
-
- ✓ `design.md` 存在
|
|
181
|
-
- ✓ `tasks.md` 存在,且每个任务含 `Type:`、`Depends:`、`Covers:`、`Files:` 标注
|
|
182
|
-
- ✓ 每个 Requirement 至少被 1 个 task 的 `Covers:` 引用(通过 spec-review.json 的 coverage 字段)
|
|
183
|
-
- ✓ 第 1 批次任务的 `Files` 集合互不重叠
|
|
184
|
-
- ✓ 至少 1 个任务 `Depends: (none)`
|
|
138
|
+
校验内容:`proposal.md` + `design.md` + `tasks.md` 存在且每个任务标注完整(Type/Depends/Covers/Files),每个 Requirement 至少被 1 个 task 引用,第 1 批次 Files 无重叠,至少 1 个任务 Depends: (none)。
|
|
185
139
|
|
|
186
140
|
exit code 0 = 通过,写入 passed。exit code != 0 = 失败,读取 stderr 展示给用户。
|
|
187
141
|
|
|
@@ -191,46 +145,7 @@ exit code 0 = 通过,写入 passed。exit code != 0 = 失败,读取 stderr
|
|
|
191
145
|
|
|
192
146
|
Spec Gate 通过后,使用 `AskUserQuestion` 工具请求确认。展示内容包括:需求提案摘要、功能需求列表、任务拆解概览(含并行组)。
|
|
193
147
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
AskUserQuestion 使用模式:
|
|
197
|
-
|
|
198
|
-
```javascript
|
|
199
|
-
AskUserQuestion({
|
|
200
|
-
title: "简洁标题",
|
|
201
|
-
questions: [{
|
|
202
|
-
id: "unique_id",
|
|
203
|
-
prompt: "问题描述",
|
|
204
|
-
options: [
|
|
205
|
-
{ id: "option_a", label: "选项 A 的描述" },
|
|
206
|
-
{ id: "option_b", label: "选项 B 的描述" }
|
|
207
|
-
],
|
|
208
|
-
allow_multiple: false // 单选;需要多选时设为 true
|
|
209
|
-
}]
|
|
210
|
-
})
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
Human Gate 1 具体交互:
|
|
214
|
-
|
|
215
|
-
```javascript
|
|
216
|
-
AskUserQuestion({
|
|
217
|
-
title: "确认 Spec 和任务规划",
|
|
218
|
-
questions: [{
|
|
219
|
-
id: "spec_confirm",
|
|
220
|
-
prompt: "specline-spec-creator 已生成 spec / design / tasks 文件并通过格式校验。请确认:\n" +
|
|
221
|
-
"1. 需求描述是否准确?\n" +
|
|
222
|
-
"2. 任务拆解是否合理?独立任务是否足够?\n" +
|
|
223
|
-
"3. 验收场景是否覆盖核心路径和异常路径?",
|
|
224
|
-
options: [
|
|
225
|
-
{ id: "approve", label: "确认通过,继续编码阶段" },
|
|
226
|
-
{ id: "reject", label: "不通过,手动修改后重新审核" }
|
|
227
|
-
]
|
|
228
|
-
}]
|
|
229
|
-
})
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
- `approve` → 写入 `human_gate_1.passed = true`,进入 Phase 2
|
|
233
|
-
- `reject` → 等待用户修改 spec/tasks 文件后,回到 Step 3 重新审核
|
|
148
|
+
Human Gate 1 具体交互:使用 `AskUserQuestion`,title="确认 Spec 和任务规划",选项:`approve`(确认通过,继续编码)/ `reject`(不通过,手动修改后重新审核)。
|
|
234
149
|
|
|
235
150
|
### Phase 2: CODING
|
|
236
151
|
|
|
@@ -256,30 +171,7 @@ Track A 和 Track B 同时启动,互不阻塞。test-writer 在 Coding 全部
|
|
|
256
171
|
|
|
257
172
|
**6a. 启动 specline-test-writer(与 Coding 阶段 Agent 同时启动)**:
|
|
258
173
|
|
|
259
|
-
|
|
260
|
-
// 在派发 coding agent 的同时,启动 specline-test-writer
|
|
261
|
-
Task({
|
|
262
|
-
subagent_type: "specline-test-writer",
|
|
263
|
-
description: `编写测试: ${changeName}`,
|
|
264
|
-
prompt: `
|
|
265
|
-
你收到一个测试编写任务。请基于 Spec 编写所有测试用例。
|
|
266
|
-
|
|
267
|
-
## 上下文文件(只读参考)
|
|
268
|
-
- Spec: specline/changes/${changeName}/specs/*/spec.md
|
|
269
|
-
- Tasks: specline/changes/${changeName}/tasks.md
|
|
270
|
-
|
|
271
|
-
## 关键约束
|
|
272
|
-
1. 你是黑盒测试工程师,不能读取实现源代码
|
|
273
|
-
2. 先检测项目的测试框架(读配置文件),按项目实际语言和框架编写测试
|
|
274
|
-
3. 每个 Scenario 至少生成 1 个对应的测试函数(命名遵循框架约定)
|
|
275
|
-
4. 基于 Covers 追溯链,确保每个 Scenario 都有测试
|
|
276
|
-
5. 只编写 tests/integration/** 和 tests/e2e/** 目录下的测试,不得编写 tests/unit/** 和 tests/models/** 下的测试(单元测试由 coding agent 的 TDD 流程负责)
|
|
277
|
-
|
|
278
|
-
## 产出报告
|
|
279
|
-
完成后在 specline/changes/${changeName}/.tmp/test-code-result.json 写入状态(含 test_framework / language / test_dir / scenarios_covered 等字段)
|
|
280
|
-
`
|
|
281
|
-
})
|
|
282
|
-
```
|
|
174
|
+
使用 Task 工具,subagent_type="specline-test-writer",prompt 中包含 changeName/Spec/Tasks 路径和黑盒约束。specline-test-writer 只编写 tests/integration/** 和 tests/e2e/** 下的测试,产出 test-code-result.json。
|
|
283
175
|
|
|
284
176
|
**6b. 解析 tasks.md,构建任务 DAG**:
|
|
285
177
|
|
|
@@ -287,58 +179,15 @@ Task({
|
|
|
287
179
|
|
|
288
180
|
> **断点续跑时的任务状态恢复**:解析 tasks.md 时同时读取每个任务的 checkbox 状态(`[x]` 表示已完成,`[ ]` 表示未完成)。已完成的任务在 DAG 中标记为 `status: "completed"`,后续批次派发时自动跳过。
|
|
289
181
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
# 提取每个任务的核心元数据
|
|
296
|
-
# 期望输出格式:TASK_NUM|TYPE|DEPS|COVERS|FILES|TESTABLE
|
|
297
|
-
rg -N --no-line-number '^## \d+\.|^- \*\*Type\*\*:|^- \*\*Depends\*\*:|^- \*\*Covers\*\*:|^- \*\*Files\*\*:|^- \*\*Testable\*\*:' "$TASKS_FILE" | while read -r line; do
|
|
298
|
-
# 解析并按批次分组
|
|
299
|
-
...
|
|
300
|
-
done
|
|
301
|
-
|
|
302
|
-
# 构建任务列表写入状态文件(含 Files 用于冲突检测,Covers 用于追溯,Testable 用于 TDD 判定)
|
|
303
|
-
# Testable 缺失时默认为 false(向后兼容)
|
|
304
|
-
jq --argjson tasks '[
|
|
305
|
-
{"id":"1","type":"backend","deps":[],"batch":1,"status":"pending","testable":true,"covers":"Requirement: 数据模型","files":["server/models.py"]},
|
|
306
|
-
{"id":"2","type":"frontend","deps":[],"batch":1,"status":"pending","testable":false,"covers":"Requirement: 登录页面","files":["src/components/Login.tsx"]}
|
|
307
|
-
]' '.phases.coding.tasks = $tasks' "$STATE_FILE" > tmp && mv tmp "$STATE_FILE"
|
|
308
|
-
```
|
|
309
|
-
|
|
310
|
-
批次划分规则:
|
|
311
|
-
- 批次 1:所有 `Depends: (none)` 的任务
|
|
312
|
-
- 批次 N:所有依赖仅限于 1..N-1 批次内已完成任务的任务
|
|
182
|
+
解析算法:
|
|
183
|
+
1. 用 grep 提取每个任务的 `Type`、`Depends`、`Covers`、`Files`、`Testable` 元数据
|
|
184
|
+
2. 批次划分:批次 1 = 所有 `Depends: (none)` 的任务,批次 N = 依赖仅限于 1..N-1 批次已完成任务的任务
|
|
185
|
+
3. 用 jq 构建任务列表写入状态文件,Testable 缺失默认为 false(向后兼容)
|
|
186
|
+
4. 断点续跑时同步 tasks.md 的 `[x]`/`[ ]` checkbox 状态到状态文件
|
|
313
187
|
|
|
314
188
|
**6c. 文件冲突检测(每批次派发前)**:
|
|
315
189
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
**文件类型分类规则**:
|
|
319
|
-
|
|
320
|
-
| 文件类型 | 路径前缀 | 编写者 | 说明 |
|
|
321
|
-
|---------|---------|--------|------|
|
|
322
|
-
| `implementation` | 不以 `tests/` 开头 | coding agent | 实现代码、配置文件、文档等 |
|
|
323
|
-
| `unit_test` | `tests/unit/` 或 `tests/models/` | coding agent(TDD) | 白盒单元测试 |
|
|
324
|
-
| `other_test` | `tests/integration/` 或 `tests/e2e/` | test-writer | 黑盒集成/E2E 测试 |
|
|
325
|
-
|
|
326
|
-
**冲突判定逻辑**:
|
|
327
|
-
|
|
328
|
-
| 场景 | 判定 |
|
|
329
|
-
|------|------|
|
|
330
|
-
| 同类型文件重叠(均为 `implementation`、`unit_test` 或 `other_test`) | **冲突** |
|
|
331
|
-
| `unit_test` 与 `other_test` 重叠 | **不冲突**(目录隔离保证互不干扰) |
|
|
332
|
-
| `implementation` 与任何测试文件重叠 | **不冲突**(实现和测试天然分离) |
|
|
333
|
-
|
|
334
|
-
```bash
|
|
335
|
-
# 伪代码:基于文件类型的三类冲突检测算法
|
|
336
|
-
# 1. 读取当前批次所有任务的 files 数组
|
|
337
|
-
# 2. 对每个文件按路径前缀分类:implementation / unit_test / other_test
|
|
338
|
-
# 3. 在同类型文件集合内检查是否有交集
|
|
339
|
-
# 4. 如果同类型 files 有交集 → 标记冲突任务对,暂停并报告用户
|
|
340
|
-
# 5. 跨类型重叠不标记为冲突
|
|
341
|
-
```
|
|
190
|
+
将当前批次所有任务的 `Files` 按路径前缀分为三类(`implementation` / `unit_test` / `other_test`),同类型文件重叠视为冲突。跨类型重叠不冲突(测试目录与实现目录天然隔离)。
|
|
342
191
|
|
|
343
192
|
#### Step 7: 按批次并发派发 Coding Agent
|
|
344
193
|
|
|
@@ -357,169 +206,10 @@ Type: docs → subagent_type: "specline-config-dev"(Markdown 文档、Skil
|
|
|
357
206
|
|
|
358
207
|
每个任务启动一个独立的子 Agent:
|
|
359
208
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
switch (task.type) {
|
|
365
|
-
case "frontend": agentType = "specline-frontend-dev"; break;
|
|
366
|
-
case "backend": case "infra": case "db": agentType = "specline-backend-dev"; break;
|
|
367
|
-
case "config": case "docs": agentType = "specline-config-dev"; break;
|
|
368
|
-
default: agentType = "specline-backend-dev";
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
// 根据 Testable 和 Type 构造 Prompt
|
|
372
|
-
let prompt;
|
|
373
|
-
if (task.testable === true) {
|
|
374
|
-
// === TDD prompt(Testable: true) ===
|
|
375
|
-
prompt = `
|
|
376
|
-
你收到一个编码任务(Type: ${task.type}, Testable: true),请按 TDD(测试驱动开发)方式实现本任务范围内的代码。
|
|
377
|
-
|
|
378
|
-
## 上下文文件(只读参考)
|
|
379
|
-
- Spec: specline/changes/${changeName}/specs/${capability}/spec.md
|
|
380
|
-
- Design: specline/changes/${changeName}/design.md
|
|
381
|
-
- Tasks: specline/changes/${changeName}/tasks.md
|
|
382
|
-
|
|
383
|
-
## 当前任务(只实现这个)
|
|
384
|
-
任务 ID: ${task.id}
|
|
385
|
-
覆盖需求: ${task.covers}
|
|
386
|
-
预期文件: ${task.files}
|
|
387
|
-
|
|
388
|
-
从 tasks.md 中提取的任务 ${task.id} 的完整描述:
|
|
389
|
-
---
|
|
390
|
-
${task.content}
|
|
391
|
-
---
|
|
392
|
-
|
|
393
|
-
## TDD 约束(RED-GREEN-REFACTOR)
|
|
394
|
-
|
|
395
|
-
你必须按以下 TDD 循环编写代码:
|
|
396
|
-
|
|
397
|
-
### RED 阶段
|
|
398
|
-
1. 分析 Spec 中本任务覆盖的 Scenario,提取需要测试的逻辑单元
|
|
399
|
-
2. 在 tests/unit/<module>/test_<feature>.{ext} 下编写测试文件
|
|
400
|
-
3. 每个 Scenario 至少 1 个测试函数/方法
|
|
401
|
-
4. 覆盖:Happy Path + 边界条件(空值、极值、边界值)+ 异常路径(错误输入、异常状态)
|
|
402
|
-
5. 运行测试,确认全部 FAIL(RED)
|
|
403
|
-
|
|
404
|
-
### GREEN 阶段
|
|
405
|
-
6. 编写最小实现代码,只使当前测试通过
|
|
406
|
-
7. 不编写测试未覆盖的逻辑
|
|
407
|
-
8. 运行测试,确认全部 PASS(GREEN)
|
|
408
|
-
|
|
409
|
-
### REFACTOR 阶段
|
|
410
|
-
9. 重构实现代码改善结构(提取方法、消除重复、优化命名)
|
|
411
|
-
10. 运行测试,确保持续 PASS
|
|
412
|
-
11. 如果需要,补充缺失的边界条件测试
|
|
413
|
-
|
|
414
|
-
## 关键约束
|
|
415
|
-
1. 只修改本任务 Files 范围内的文件
|
|
416
|
-
2. 不修改其他任务负责的文件
|
|
417
|
-
3. 与已完成任务的接口约定必须遵守(参考已生成的接口/类型定义文件)
|
|
418
|
-
4. 确认过 design.md 中的技术决策后再动手
|
|
419
|
-
5. 测试文件只能写入 tests/unit/ 或 tests/models/ 目录
|
|
420
|
-
6. 不得修改 tests/integration/ 或 tests/e2e/ 目录下的文件(属于 test-writer)
|
|
421
|
-
7. **完成后必须将 tasks.md 中本任务的 \`[ ]\` 改为 \`[x]\`**(方便断点续跑识别进度)
|
|
422
|
-
|
|
423
|
-
## 产出报告
|
|
424
|
-
完成后在 specline/changes/${changeName}/.tmp/task-${task.id}-result.json 写入:
|
|
425
|
-
{
|
|
426
|
-
"task_id": "${task.id}",
|
|
427
|
-
"type": "${task.type}",
|
|
428
|
-
"testable": true,
|
|
429
|
-
"covers": "${task.covers}",
|
|
430
|
-
"status": "completed",
|
|
431
|
-
"files_changed": [...],
|
|
432
|
-
"test_files": ["tests/unit/...", ...],
|
|
433
|
-
"tests_passed": true,
|
|
434
|
-
"summary": "..."
|
|
435
|
-
}
|
|
436
|
-
`;
|
|
437
|
-
} else if (["frontend", "backend", "infra", "db"].includes(task.type)) {
|
|
438
|
-
// === 标准编码 prompt(Testable: false,有代码逻辑) ===
|
|
439
|
-
prompt = `
|
|
440
|
-
你收到一个编码任务(Type: ${task.type}, Testable: false),请只实现本任务范围内的代码。
|
|
441
|
-
|
|
442
|
-
## 上下文文件(只读参考)
|
|
443
|
-
- Spec: specline/changes/${changeName}/specs/${capability}/spec.md
|
|
444
|
-
- Design: specline/changes/${changeName}/design.md
|
|
445
|
-
- Tasks: specline/changes/${changeName}/tasks.md
|
|
446
|
-
|
|
447
|
-
## 当前任务(只实现这个)
|
|
448
|
-
任务 ID: ${task.id}
|
|
449
|
-
覆盖需求: ${task.covers}
|
|
450
|
-
预期文件: ${task.files}
|
|
451
|
-
|
|
452
|
-
从 tasks.md 中提取的任务 ${task.id} 的完整描述:
|
|
453
|
-
---
|
|
454
|
-
${task.content}
|
|
455
|
-
---
|
|
456
|
-
|
|
457
|
-
## 约束
|
|
458
|
-
1. 只修改本任务 Files 范围内的文件
|
|
459
|
-
2. 不修改其他任务负责的文件
|
|
460
|
-
3. 与已完成任务的接口约定必须遵守(参考已生成的接口/类型定义文件)
|
|
461
|
-
4. 确认过 design.md 中的技术决策后再动手
|
|
462
|
-
5. **完成后必须将 tasks.md 中本任务的 \`[ ]\` 改为 \`[x]\`**(方便断点续跑识别进度)
|
|
463
|
-
|
|
464
|
-
## 产出报告
|
|
465
|
-
完成后在 specline/changes/${changeName}/.tmp/task-${task.id}-result.json 写入:
|
|
466
|
-
{
|
|
467
|
-
"task_id": "${task.id}",
|
|
468
|
-
"type": "${task.type}",
|
|
469
|
-
"testable": false,
|
|
470
|
-
"covers": "${task.covers}",
|
|
471
|
-
"status": "completed",
|
|
472
|
-
"files_changed": [...],
|
|
473
|
-
"summary": "..."
|
|
474
|
-
}
|
|
475
|
-
`;
|
|
476
|
-
} else {
|
|
477
|
-
// === 配置/文档 prompt(Type: config/docs) ===
|
|
478
|
-
prompt = `
|
|
479
|
-
你收到一个编码任务(Type: ${task.type}),请只实现本任务范围内的代码。
|
|
480
|
-
|
|
481
|
-
## 上下文文件(只读参考)
|
|
482
|
-
- Spec: specline/changes/${changeName}/specs/${capability}/spec.md
|
|
483
|
-
- Design: specline/changes/${changeName}/design.md
|
|
484
|
-
- Tasks: specline/changes/${changeName}/tasks.md
|
|
485
|
-
|
|
486
|
-
## 当前任务(只实现这个)
|
|
487
|
-
任务 ID: ${task.id}
|
|
488
|
-
覆盖需求: ${task.covers}
|
|
489
|
-
预期文件: ${task.files}
|
|
490
|
-
|
|
491
|
-
从 tasks.md 中提取的任务 ${task.id} 的完整描述:
|
|
492
|
-
---
|
|
493
|
-
${task.content}
|
|
494
|
-
---
|
|
495
|
-
|
|
496
|
-
## 约束
|
|
497
|
-
1. 只修改本任务 Files 范围内的文件
|
|
498
|
-
2. 不修改其他任务负责的文件
|
|
499
|
-
3. 与已完成任务的接口约定必须遵守(参考已生成的接口/类型定义文件)
|
|
500
|
-
4. 确认过 design.md 中的技术决策后再动手
|
|
501
|
-
5. **完成后必须将 tasks.md 中本任务的 \`[ ]\` 改为 \`[x]\`**(方便断点续跑识别进度)
|
|
502
|
-
|
|
503
|
-
## 产出报告
|
|
504
|
-
完成后在 specline/changes/${changeName}/.tmp/task-${task.id}-result.json 写入:
|
|
505
|
-
{
|
|
506
|
-
"task_id": "${task.id}",
|
|
507
|
-
"type": "${task.type}",
|
|
508
|
-
"covers": "${task.covers}",
|
|
509
|
-
"status": "completed",
|
|
510
|
-
"files_changed": [...],
|
|
511
|
-
"summary": "..."
|
|
512
|
-
}
|
|
513
|
-
`;
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
Task({
|
|
517
|
-
subagent_type: agentType,
|
|
518
|
-
description: `实现任务 ${task.id}: ${task.title} [${task.type}]${task.testable ? ' (TDD)' : ''}`,
|
|
519
|
-
prompt: prompt
|
|
520
|
-
})
|
|
521
|
-
}
|
|
522
|
-
```
|
|
209
|
+
根据 task.type 和 task.testable 从 `templates/subagent-prompts.md` 中选择对应模板,填充变量后作为子 Agent prompt。模板选择规则:
|
|
210
|
+
- testable=true → Template 1 (TDD)
|
|
211
|
+
- testable=false 且 frontend/backend/infra/db → Template 2 (Standard)
|
|
212
|
+
- config/docs → Template 3 (Config/Docs)
|
|
523
213
|
|
|
524
214
|
**7b. 等待当前批次所有 Agent 完成后**:
|
|
525
215
|
1. 验证每个 Agent 的产出报告(`specline/changes/<name>/.tmp/task-<id>-result.json`)
|
|
@@ -599,24 +289,7 @@ code-review.json 中 unit test 相关的 finding 标注 `type` 为 `"unit_test_q
|
|
|
599
289
|
|
|
600
290
|
> **策略判断**:读取 `specline/config.yaml` → `pipeline.human_gate_policy`。若为 `minimal` 或 `none` → 跳过此 HG,直接写入 `human_gate_2.passed = true`,进入 Phase 4。
|
|
601
291
|
|
|
602
|
-
仅当 code-review.json 中 warnings > 0 且 errors = 0 时,使用 `AskUserQuestion
|
|
603
|
-
|
|
604
|
-
```javascript
|
|
605
|
-
AskUserQuestion({
|
|
606
|
-
title: "代码审查复核",
|
|
607
|
-
questions: [{
|
|
608
|
-
id: "review_check",
|
|
609
|
-
prompt: "代码审查发现 " + warning_count + " 个警告,0 个错误。是否需要人工复核?",
|
|
610
|
-
options: [
|
|
611
|
-
{ id: "skip", label: "无需复核,自动继续测试阶段" },
|
|
612
|
-
{ id: "review", label: "需要人工复核" }
|
|
613
|
-
]
|
|
614
|
-
}]
|
|
615
|
-
})
|
|
616
|
-
```
|
|
617
|
-
|
|
618
|
-
- `skip`(默认)→ 自动继续
|
|
619
|
-
- `review` → 展示警告详情,等待人工处理
|
|
292
|
+
仅当 code-review.json 中 warnings > 0 且 errors = 0 时,使用 `AskUserQuestion` 询问是否人工复核(`skip` 自动继续 / `review` 展示警告详情)。
|
|
620
293
|
|
|
621
294
|
### Phase 4: TEST
|
|
622
295
|
|
|
@@ -657,24 +330,7 @@ exit code 全 0 = 通过,进入 Phase 5。失败处理见 [Layer 3: 测试失
|
|
|
657
330
|
|
|
658
331
|
> **策略判断**:读取 `specline/config.yaml` → `pipeline.human_gate_policy`。若为 `none` → 跳过此 HG,直接写入 `human_gate_3.passed = true`,执行归档。`minimal` 策略下 HG3 保留人工确认。
|
|
659
332
|
|
|
660
|
-
全部测试通过后,使用 `AskUserQuestion`
|
|
661
|
-
|
|
662
|
-
```javascript
|
|
663
|
-
AskUserQuestion({
|
|
664
|
-
title: "归档确认",
|
|
665
|
-
questions: [{
|
|
666
|
-
id: "archive_confirm",
|
|
667
|
-
prompt: "全部测试通过。变更摘要:新增 " + new_files + " 个文件,修改 " + modified_files + " 个文件。是否归档此变更?",
|
|
668
|
-
options: [
|
|
669
|
-
{ id: "archive", label: "确认归档" },
|
|
670
|
-
{ id: "cancel", label: "暂不归档" }
|
|
671
|
-
]
|
|
672
|
-
}]
|
|
673
|
-
})
|
|
674
|
-
```
|
|
675
|
-
|
|
676
|
-
- `archive` → 执行归档
|
|
677
|
-
- `cancel` → 暂停流水线,保留状态文件待后续继续
|
|
333
|
+
全部测试通过后,使用 `AskUserQuestion` 请求归档确认(`archive` 执行归档 / `cancel` 暂停流水线)。
|
|
678
334
|
|
|
679
335
|
#### Step 15: 归档
|
|
680
336
|
|
|
@@ -687,147 +343,51 @@ specline-pipeline-gate.sh archive --execute --change "<name>"
|
|
|
687
343
|
|
|
688
344
|
---
|
|
689
345
|
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
### Build Gate 失败处理
|
|
693
|
-
|
|
694
|
-
⚠️ Build Gate 失败时,分析失败原因并定位到具体任务:
|
|
695
|
-
|
|
696
|
-
**8a. 单个任务构建失败** → 回对应 coding agent 修复(最多 2 次循环)
|
|
697
|
-
|
|
698
|
-
**8b. 接口不兼容** → 计算影响范围,只重置受影响的下游任务:
|
|
699
|
-
|
|
700
|
-
```bash
|
|
701
|
-
# 影响范围分析:基于 tasks.md 的 Depends 关系,计算受影响的下游任务
|
|
702
|
-
# 例如:Task 1 的 API 签名改了 → Task 3 (Depends: 1)、Task 5 (Depends: 1,3) 需要重跑
|
|
703
|
-
# Task 2 无依赖关系 → 不受影响,保持 completed
|
|
704
|
-
|
|
705
|
-
AFFECTED_TASK_IDS=("3" "5") # 从 DAG 计算得出
|
|
706
|
-
|
|
707
|
-
for tid in "${AFFECTED_TASK_IDS[@]}"; do
|
|
708
|
-
jq --arg tid "$tid" '
|
|
709
|
-
.phases.coding.tasks |= map(
|
|
710
|
-
if .id == $tid then .status = "pending" | .completed_at = null else . end
|
|
711
|
-
)
|
|
712
|
-
' "$STATE_FILE" > tmp && mv tmp "$STATE_FILE"
|
|
713
|
-
done
|
|
714
|
-
```
|
|
715
|
-
|
|
716
|
-
影响范围算法:
|
|
717
|
-
1. 找到被修改的任务 ID 集合 M
|
|
718
|
-
2. 遍历所有任务,如果某任务的 Depends 列表中包含 M 中任一 ID,则加入受影响集合
|
|
719
|
-
3. 递归执行第 2 步直到不再扩展
|
|
720
|
-
|
|
721
|
-
**8c. Build Gate 重置**:
|
|
722
|
-
|
|
723
|
-
```bash
|
|
724
|
-
jq '.phases.coding.gates.build_gate.passed = null' "$STATE_FILE" > tmp && mv tmp "$STATE_FILE"
|
|
725
|
-
```
|
|
726
|
-
|
|
727
|
-
修复后**只重跑受影响的任务**(按原批次顺序),未受影响的任务保持 completed 状态。
|
|
728
|
-
|
|
729
|
-
### 测试失败处理
|
|
730
|
-
|
|
731
|
-
⚠️ 测试失败根据失败文件所在的目录区分处理路径:
|
|
732
|
-
|
|
733
|
-
#### 单元测试失败处理
|
|
734
|
-
|
|
735
|
-
失败文件在 `tests/unit/` 或 `tests/models/` 目录下:
|
|
346
|
+
### 统一失败处理流程
|
|
736
347
|
|
|
737
|
-
|
|
738
|
-
- 回对应 coding agent 修复实现代码或测试代码(最多 2 次循环)
|
|
739
|
-
- `spec_ambiguity`(Spec 模糊)→ **不自动循环修复**,暂停流水线并展示模糊点给用户
|
|
740
|
-
|
|
741
|
-
> **策略判断**:若 `pipeline.human_gate_policy` 为 `minimal` 或 `none` → 不暂停,将 spec_ambiguity 降级为 WARNING 记录到事件日志并继续下一阶段。
|
|
742
|
-
|
|
743
|
-
Gate 重置(仅重置 test_unit_gate):
|
|
744
|
-
|
|
745
|
-
```bash
|
|
746
|
-
jq '.phases.test.sub_phases.unit.gates.test_unit_gate.passed = null' "$STATE_FILE" > tmp && mv tmp "$STATE_FILE"
|
|
747
|
-
```
|
|
748
|
-
|
|
749
|
-
#### 集成/E2E 测试失败处理
|
|
750
|
-
|
|
751
|
-
失败文件在 `tests/integration/` 或 `tests/e2e/` 目录下:
|
|
752
|
-
|
|
753
|
-
- specline-test-runner 分析原因:
|
|
754
|
-
- **测试代码问题** → specline-test-writer 自修(最多 2 次)
|
|
755
|
-
- **实现代码问题** → 利用 `Covers` 追溯链定位到具体任务,回对应 coding agent 修复 → **使用影响范围算法精确重置受影响任务的 Gate**
|
|
756
|
-
- **`spec_ambiguity`**(Spec 模糊)→ **不自动循环修复**,暂停流水线并展示模糊点给用户
|
|
757
|
-
|
|
758
|
-
> **策略判断**:若 `pipeline.human_gate_policy` 为 `minimal` 或 `none` → 不暂停,将 spec_ambiguity 降级为 WARNING 记录到事件日志并继续下一阶段。
|
|
759
|
-
- 循环最多 2 次
|
|
760
|
-
|
|
761
|
-
Gate 重置:
|
|
762
|
-
|
|
763
|
-
```bash
|
|
764
|
-
jq '
|
|
765
|
-
.phases.test.sub_phases.integration.gates.test_integration_gate.passed = null |
|
|
766
|
-
.phases.test.sub_phases.e2e.gates.test_e2e_gate.passed = null
|
|
767
|
-
' "$STATE_FILE" > tmp && mv tmp "$STATE_FILE"
|
|
768
|
-
```
|
|
769
|
-
|
|
770
|
-
#### 优先级规则
|
|
771
|
-
|
|
772
|
-
当单元测试和集成/E2E 测试同时失败时:**优先修复单元测试**(先执行 coding agent 修复循环),单元测试通过后再处理集成/E2E 测试失败。
|
|
773
|
-
|
|
774
|
-
代码修复后 Gate 全部重置(所有测试类型):
|
|
775
|
-
|
|
776
|
-
```bash
|
|
777
|
-
jq '
|
|
778
|
-
.phases.test.sub_phases.unit.gates.test_unit_gate.passed = null |
|
|
779
|
-
.phases.test.sub_phases.integration.gates.test_integration_gate.passed = null |
|
|
780
|
-
.phases.test.sub_phases.e2e.gates.test_e2e_gate.passed = null
|
|
781
|
-
' "$STATE_FILE" > tmp && mv tmp "$STATE_FILE"
|
|
782
|
-
```
|
|
348
|
+
所有 Gate 失败均按以下管道处理:
|
|
783
349
|
|
|
784
|
-
|
|
350
|
+
1. **诊断**:分析 stderr/exit code 确定失败类型(Build/Test/Hook)
|
|
351
|
+
2. **定位**:基于 Covers 追溯链定位到具体任务(Build 失败额外用 Depends 影响范围算法计算下游任务)
|
|
352
|
+
3. **修复**:回对应 agent 修复(最多 2 次循环)
|
|
353
|
+
4. **Gate 重置**:`jq '...gate.passed = null' "$STATE_FILE"`
|
|
354
|
+
5. **特殊规则**:
|
|
355
|
+
- `spec_ambiguity` → 暂停流水线展示模糊点(minimal/none 策略下降级为 WARNING)
|
|
356
|
+
- 接口不兼容 → 只重置受影响的下游任务(保留未受影响任务的状态)
|
|
357
|
+
- Hook 阻断 → 先诊断原因 → 与用户沟通(AskUserQuestion)→ 修复后重试 → 绝不静默降级
|
|
358
|
+
- 测试失败优先级:单元测试优先于集成/E2E
|
|
785
359
|
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
**Step 1: 识别阻断原因**
|
|
360
|
+
---
|
|
789
361
|
|
|
790
|
-
|
|
362
|
+
## Layer 3: 异常与恢复
|
|
791
363
|
|
|
792
|
-
|
|
793
|
-
|---------|---------|---------|
|
|
794
|
-
| 脚本缺少执行权限 | "Permission denied" 或脚本执行失败 | `ls -la .cursor/hooks/specline-agent-guard.sh` |
|
|
795
|
-
| `jq` 未安装 | jq 相关错误 | `which jq` |
|
|
796
|
-
| Agent 名称不在白名单 | "子Agent类型 'xxx' 不在允许列表中" | 检查 `specline-agent-guard.sh` 中 `ALLOWED_AGENTS` 变量 |
|
|
797
|
-
| hooks.json 缺失或不完整 | hook 未触发或配置错误 | 检查 `.cursor/hooks.json` 文件是否存在且内容完整 |
|
|
364
|
+
### Build 失败差异化处理
|
|
798
365
|
|
|
799
|
-
|
|
366
|
+
- 单个任务构建失败 → 回对应 coding agent 修复(最多 2 次循环)
|
|
367
|
+
- 接口不兼容 → 使用影响范围算法(找到修改任务集合 M → 遍历 Depends → 递归扩展),只重置受影响的下游任务(未受影响任务保持 completed)
|
|
368
|
+
- Gate 重置:`jq '.phases.coding.gates.build_gate.passed = null' "$STATE_FILE"`
|
|
369
|
+
- 修复后只重跑受影响的任务(按原批次顺序)
|
|
800
370
|
|
|
801
|
-
|
|
802
|
-
AskUserQuestion({
|
|
803
|
-
title: "Hook 阻断 - 子 Agent 启动失败",
|
|
804
|
-
questions: [{
|
|
805
|
-
id: "hook_fix",
|
|
806
|
-
prompt: `子 Agent **${agentName}** 被 hook 阻止,诊断结果:
|
|
371
|
+
### 测试失败差异化处理
|
|
807
372
|
|
|
808
|
-
|
|
809
|
-
|
|
373
|
+
- **单元测试失败**(`tests/unit/` / `tests/models/`):利用 Covers 追溯链定位 → 回 coding agent 修复(最多 2 次)
|
|
374
|
+
- Gate 重置:`jq '.phases.test.sub_phases.unit.gates.test_unit_gate.passed = null' "$STATE_FILE"`
|
|
375
|
+
- **集成/E2E 测试失败**(`tests/integration/` / `tests/e2e/`):先判断是测试代码还是实现代码问题
|
|
376
|
+
- 测试代码问题 → specline-test-writer 自修(最多 2 次)
|
|
377
|
+
- 实现代码问题 → Covers 追溯定位 → 回 coding agent 修复 → 用影响范围算法重置受影响 Gate
|
|
378
|
+
- Gate 重置:`.phases.test.sub_phases.integration.gates.test_integration_gate.passed = null | .phases.test.sub_phases.e2e.gates.test_e2e_gate.passed = null`
|
|
379
|
+
- **优先级**:单元测试失败优先修复;代码修复后所有测试 Gate 全部重置
|
|
810
380
|
|
|
811
|
-
|
|
381
|
+
### Hook 阻断差异化处理
|
|
812
382
|
|
|
813
|
-
|
|
814
|
-
options: [
|
|
815
|
-
{ id: "auto_fix", label: "自动修复(执行上述修复命令)" },
|
|
816
|
-
{ id: "manual_fix", label: "我手动修复后通知你重试" },
|
|
817
|
-
{ id: "skip_agent", label: "跳过此 Agent,由编排者直接执行(不推荐)" }
|
|
818
|
-
]
|
|
819
|
-
}]
|
|
820
|
-
})
|
|
821
|
-
```
|
|
383
|
+
⚠️ 编排者绝对不允许静默降级为自己直接执行。处理流程:
|
|
822
384
|
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
385
|
+
1. **识别原因**:判断权限/依赖/白名单/hooks.json 等问题
|
|
386
|
+
2. **与用户沟通**:使用 AskUserQuestion 展示诊断结果和修复选项(auto_fix / manual_fix / skip_agent)
|
|
387
|
+
3. **执行修复并重试**:auto_fix → 执行修复命令;manual_fix → 等待用户;skip_agent → 仅用户明确选择时降级(记录到事件日志)
|
|
388
|
+
4. **验证修复结果**:重试子 Agent,失败则重新诊断 → 再次沟通(最多 2 次循环)→ 仍失败则暂停并报告用户
|
|
827
389
|
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
此规范适用于**所有 hook 阻断场景**(`subagentStart`、`beforeShellExecution` 等)。
|
|
390
|
+
此规范适用于所有 hook 阻断场景(`subagentStart`、`beforeShellExecution` 等)。
|
|
831
391
|
|
|
832
392
|
### 断点续跑流程
|
|
833
393
|
|
|
@@ -948,112 +508,10 @@ AskUserQuestion({
|
|
|
948
508
|
|
|
949
509
|
---
|
|
950
510
|
|
|
951
|
-
## Layer 4:
|
|
952
|
-
|
|
953
|
-
> ℹ️ 初次阅读可跳过 — 以下为完整参考信息,首次阅读可略过
|
|
954
|
-
|
|
955
|
-
### 附录 A: .pipeline-state.json 完整 Schema
|
|
956
|
-
|
|
957
|
-
```json
|
|
958
|
-
{
|
|
959
|
-
"version": 1,
|
|
960
|
-
"change_name": "<name>",
|
|
961
|
-
"created_at": "<ISO8601>",
|
|
962
|
-
"updated_at": "<ISO8601>",
|
|
963
|
-
"current_phase": "spec",
|
|
964
|
-
"current_step": "specline-spec-creator",
|
|
965
|
-
"phases": {
|
|
966
|
-
"spec": { "status": "in_progress", "retry_count": 0, "sub_phases": {}, "gates": { "spec_gate": { "passed": null }, "human_gate_1": { "passed": null } } },
|
|
967
|
-
"coding": { "status": "pending", "tasks": [], "sub_phases": {}, "gates": { "build_gate": { "passed": null } } },
|
|
968
|
-
"code_review": { "status": "pending", "retry_count": 0, "gates": { "lint_gate": { "passed": null }, "human_gate_2": { "passed": null } } },
|
|
969
|
-
"test": { "status": "pending", "framework": null, "sub_phases": { "unit": { "status": "pending", "gates": { "test_unit_gate": { "passed": null } } }, "integration": { "status": "pending", "gates": { "test_integration_gate": { "passed": null } } }, "e2e": { "status": "pending", "gates": { "test_e2e_gate": { "passed": null } } } } },
|
|
970
|
-
"archive": { "status": "pending", "gates": { "human_gate_3": { "passed": null }, "archive_gate": { "passed": null } } }
|
|
971
|
-
}
|
|
972
|
-
}
|
|
973
|
-
```
|
|
974
|
-
|
|
975
|
-
### 附录 B: 状态写入规则
|
|
976
|
-
|
|
977
|
-
> ℹ️ 初次阅读可跳过
|
|
978
|
-
|
|
979
|
-
所有状态写入由 Gate 脚本或 Skill 编排逻辑完成,**不使用 LLM 写入状态**:
|
|
980
|
-
|
|
981
|
-
- Gate 脚本通过后自动写入 `gate.passed = true`
|
|
982
|
-
- 子 Agent 完成后 Skill 写入 `completed_at`
|
|
983
|
-
- 代码修复后 Skill 重置相关 gates 为 null
|
|
984
|
-
|
|
985
|
-
### 附录 C: 结构化事件日志
|
|
986
|
-
|
|
987
|
-
> ℹ️ 初次阅读可跳过
|
|
988
|
-
|
|
989
|
-
每个关键事件追加写入 `specline/changes/<name>/pipeline-events.jsonl`(JSON Lines 格式,每行一个事件):
|
|
990
|
-
|
|
991
|
-
```json
|
|
992
|
-
{"ts":"...","event":"pipeline_start","change":"<name>"}
|
|
993
|
-
{"ts":"...","event":"phase_transition","from":"spec","to":"coding"}
|
|
994
|
-
{"ts":"...","event":"agent_start","agent":"specline-spec-creator","task":null}
|
|
995
|
-
{"ts":"...","event":"agent_done","agent":"specline-spec-creator","result":"completed"}
|
|
996
|
-
{"ts":"...","event":"agent_start","agent":"specline-frontend-dev","task":"1","type":"frontend"}
|
|
997
|
-
{"ts":"...","event":"agent_done","agent":"specline-frontend-dev","task":"1","result":"completed","files_changed":["..."],"duration_ms":45200}
|
|
998
|
-
{"ts":"...","event":"gate_run","phase":"build","exit_code":0,"passed":true}
|
|
999
|
-
{"ts":"...","event":"gate_run","phase":"lint","exit_code":1,"passed":false,"stderr":"..."}
|
|
1000
|
-
{"ts":"...","event":"conflict_detected","tasks":["1","2"],"overlap_files":["src/utils/api.ts"]}
|
|
1001
|
-
{"ts":"...","event":"retry","phase":"coding","task":"3","attempt":2,"reason":"build_failure"}
|
|
1002
|
-
{"ts":"...","event":"pipeline_pause","reason":"human_gate_1"}
|
|
1003
|
-
{"ts":"...","event":"pipeline_resume","from_phase":"coding"}
|
|
1004
|
-
{"ts":"...","event":"pipeline_complete","change":"<name>"}
|
|
1005
|
-
```
|
|
1006
|
-
|
|
1007
|
-
**写入原则**:
|
|
1008
|
-
- 每个事件一行,JSON 对象结尾无逗号
|
|
1009
|
-
- 任何编排动作(启动 agent、运行 gate、状态转换)都写入事件日志
|
|
1010
|
-
- Gate 脚本不写事件日志(Gate 是无状态的),仅编排层写入
|
|
1011
|
-
- 事件日志用于人工排查问题和统计分析,不影响流水线决策
|
|
1012
|
-
|
|
1013
|
-
### 附录 D: Hook 约束体系
|
|
1014
|
-
|
|
1015
|
-
> ℹ️ 初次阅读可跳过
|
|
1016
|
-
|
|
1017
|
-
Specline 通过 Cursor Hooks 提供了三层自动约束,确保在长对话中 Agent 不偏离流水线逻辑:
|
|
1018
|
-
|
|
1019
|
-
```
|
|
1020
|
-
sessionStart → specline-session-start.sh
|
|
1021
|
-
新会话启动时检测活跃 pipeline,自动注入阶段上下文到 Agent 系统提示
|
|
1022
|
-
|
|
1023
|
-
preToolUse → specline-phase-guard.sh
|
|
1024
|
-
操作前检查:SPEC 阶段拦截代码编辑、阶段不匹配的子Agent 启动
|
|
1025
|
-
|
|
1026
|
-
postToolUse → specline-reminder.sh
|
|
1027
|
-
关键操作后注入提醒:更新 tasks.md checkbox、运行 Gate 脚本
|
|
1028
|
-
```
|
|
1029
|
-
|
|
1030
|
-
#### 对你(编排者)的影响
|
|
1031
|
-
|
|
1032
|
-
1. **总是先检查** - preToolUse 会阻止不匹配当前阶段的操作,所以你在行动前自然会考虑阶段
|
|
1033
|
-
2. **被提醒下一步** - postToolUse 在子Agent完成后提醒你更新 checkbox 和运行 Gate
|
|
1034
|
-
3. **非流水线会话无影响** - 所有 Hook 的第一步检查「是否有活跃 pipeline」,无则透明放行
|
|
1035
|
-
|
|
1036
|
-
#### 约束策略
|
|
1037
|
-
|
|
1038
|
-
| 场景 | 策略 | 原因 |
|
|
1039
|
-
|------|------|------|
|
|
1040
|
-
| SPEC 阶段编辑代码文件 | **硬拦截 (deny)** | 明确违规 |
|
|
1041
|
-
| SPEC 阶段启动编码 Agent | **硬拦截 (deny)** | 阶段不匹配 |
|
|
1042
|
-
| CODING 阶段直接编辑代码 | **软提醒 (postToolUse)** | Hook 无法区分编排者和子Agent的 Write |
|
|
1043
|
-
| 子Agent完成后忘记 Gate | **软提醒 (postToolUse)** | 操作后注入下一步提醒 |
|
|
1044
|
-
|
|
1045
|
-
> 注意:CODING 阶段 Orchestrator 直接编辑代码文件不会被 Hook 硬拦截(因为子Agent 也需要 Write 权限),但 SKILL 指令和 sessionStart 注入的上下文会持续提醒你「编码应通过子 Agent」。如果你发现自己想直接编辑代码,停一下,改用 Task 工具。
|
|
1046
|
-
|
|
1047
|
-
### 附录 E: 关键约束速查表
|
|
511
|
+
## Layer 4: 参考文档
|
|
1048
512
|
|
|
1049
|
-
>
|
|
513
|
+
> 以下文档为完整参考信息,根据需要查阅:
|
|
1050
514
|
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
| 2 | **所有门禁通过 Gate 脚本** | 调用 `specline-pipeline-gate.sh`,不要自己写 grep/检查逻辑 |
|
|
1055
|
-
| 3 | **状态文件是唯一真相源** | 所有决策基于 `.pipeline-state.json` 的当前值 |
|
|
1056
|
-
| 4 | **人工确认点必须尊重策略** | 根据 `pipeline.human_gate_policy` 配置决定是否暂停,不要无条件跳过或强制暂停 human_gate |
|
|
1057
|
-
| 5 | **测试 Agent 必须黑盒** | 不给 specline-test-writer 传递源代码文件路径 |
|
|
1058
|
-
| 6 | **Hook 阻断绝不静默降级** | 子 Agent 被 hook 阻止时,必须先诊断、沟通、修复后重试 |
|
|
1059
|
-
| 7 | **接受 Hook 约束** | preToolUse/postToolUse/sessionStart Hook 会自动校验和提醒,不要试图绕过 |
|
|
515
|
+
- State Schema → 详见 `references/pipeline-state-schema.md`
|
|
516
|
+
- Event Log → 详见 `references/event-log-spec.md`
|
|
517
|
+
- Hook & Constraints → 详见 `references/error-recovery-details.md`
|