specline 1.1.3 → 1.2.1
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 +95 -16
- package/package.json +1 -1
- package/templates/.cursor/agents/specline-explore-assistant.md +81 -0
- package/templates/.cursor/agents/specline-spec-reviewer.md +11 -1
- package/templates/.cursor/commands/specline-explore.md +9 -0
- package/templates/.cursor/commands/specline-quickfix.md +24 -0
- package/templates/.cursor/hooks/specline-pipeline-gate.sh +125 -13
- package/templates/.cursor/hooks/specline-session-start.sh +5 -62
- package/templates/.cursor/skills/specline-explore/SKILL.md +322 -143
- package/templates/.cursor/skills/specline-pipeline/SKILL.md +225 -52
- package/templates/.cursor/skills/specline-propose/SKILL.md +4 -1
- package/templates/.cursor/skills/specline-quickfix/SKILL.md +239 -0
|
@@ -13,42 +13,18 @@ description: >-
|
|
|
13
13
|
|
|
14
14
|
### 概述
|
|
15
15
|
|
|
16
|
-
每个 Cursor 会话通过 `session_id`
|
|
16
|
+
每个 Cursor 会话通过 `session_id` **显式绑定**到特定的 Pipeline(通过 `/specline-pipeline --change <name>` 命令)。Hook 脚本通过查 `specline/.pipeline-sessions.json` 表获得确定性映射。
|
|
17
17
|
|
|
18
|
-
###
|
|
18
|
+
### 启动时行为
|
|
19
19
|
|
|
20
20
|
`sessionStart` Hook (`specline-session-start.sh`) 自动处理:
|
|
21
21
|
|
|
22
22
|
1. **已绑定且有效** → 直接使用,注入正确的阶段约束
|
|
23
|
-
2.
|
|
24
|
-
3.
|
|
25
|
-
4.
|
|
26
|
-
5. **脏数据清理** → 绑定指向已归档/不存在的 Pipeline 时自动删除
|
|
23
|
+
2. **无绑定** → 透明放行(`echo '{}'`),不自动扫描活跃 pipeline,不注入任何上下文
|
|
24
|
+
3. **过期绑定清理** → `bound_at` 超过 7 天的绑定自动删除
|
|
25
|
+
4. **脏数据清理** → 绑定指向已归档/不存在的 Pipeline 时自动删除
|
|
27
26
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
当 sessionStart 注入上下文提示有多个 pipeline 未绑定时,编排者**必须**使用 AskUserQuestion 让用户选择:
|
|
31
|
-
|
|
32
|
-
```javascript
|
|
33
|
-
AskUserQuestion({
|
|
34
|
-
title: "选择 Pipeline",
|
|
35
|
-
questions: [{
|
|
36
|
-
id: "pipeline_select",
|
|
37
|
-
prompt: "当前有 " + count + " 个活跃 Pipeline,请选择要绑定到本会话的:",
|
|
38
|
-
options: [
|
|
39
|
-
{ id: "change-a", label: "change-a (SPEC 阶段)" },
|
|
40
|
-
{ id: "change-b", label: "change-b (CODING 阶段, 3/7 任务)" },
|
|
41
|
-
],
|
|
42
|
-
allow_multiple: false
|
|
43
|
-
}]
|
|
44
|
-
})
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
用户选择后,编排者执行绑定命令:
|
|
48
|
-
|
|
49
|
-
```bash
|
|
50
|
-
.cursor/hooks/specline-pipeline-gate.sh bind <session_id> <selected_change>
|
|
51
|
-
```
|
|
27
|
+
> **重要**:sessionStart 不再自动扫描和绑定活跃 pipeline。要绑定到一个 Pipeline,需要显式执行 `/specline-pipeline --change <name>`。
|
|
52
28
|
|
|
53
29
|
### 用户要求切换 Pipeline 时
|
|
54
30
|
|
|
@@ -105,6 +81,21 @@ AskUserQuestion({
|
|
|
105
81
|
|
|
106
82
|
归档到 `specline/changes/archive/YYYY-MM-DD-<name>/`
|
|
107
83
|
|
|
84
|
+
### Quickfix vs Pipeline 边界判断
|
|
85
|
+
|
|
86
|
+
| 维度 | Quickfix (`/specline-quickfix`) | Pipeline (`/specline-pipeline`) |
|
|
87
|
+
|------|-------------------------------|-------------------------------|
|
|
88
|
+
| 文件改动数 | 1-3 个 | 4+ 个 |
|
|
89
|
+
| 关注点 | 单一关注点 | 多关注点/跨模块 |
|
|
90
|
+
| 架构变更 | 无新架构/新组件 | 需要新组件/新 API |
|
|
91
|
+
| 测试 | 不需要新测试 | 需要写新测试 |
|
|
92
|
+
| 典型场景 | 修 bug、改配置、文档微调 | 新增功能、重构 |
|
|
93
|
+
| 产出 | summary.md + files-changed.json | proposal/design/tasks/specs + 全部测试 |
|
|
94
|
+
| 人工确认 | 0 个 | 3 个 |
|
|
95
|
+
| 耗时 | 1-3 分钟 | 10-30 分钟 |
|
|
96
|
+
|
|
97
|
+
**使用建议**:如果不确定,优先用 quickfix。如果需要更严格的流程保证,用 pipeline。
|
|
98
|
+
|
|
108
99
|
---
|
|
109
100
|
|
|
110
101
|
## Layer 2: Happy Path — 新建流水线
|
|
@@ -266,6 +257,7 @@ Task({
|
|
|
266
257
|
2. 先检测项目的测试框架(读配置文件),按项目实际语言和框架编写测试
|
|
267
258
|
3. 每个 Scenario 至少生成 1 个对应的测试函数(命名遵循框架约定)
|
|
268
259
|
4. 基于 Covers 追溯链,确保每个 Scenario 都有测试
|
|
260
|
+
5. 只编写 tests/integration/** 和 tests/e2e/** 目录下的测试,不得编写 tests/unit/** 和 tests/models/** 下的测试(单元测试由 coding agent 的 TDD 流程负责)
|
|
269
261
|
|
|
270
262
|
## 产出报告
|
|
271
263
|
完成后在 specline/changes/${changeName}/.tmp/test-code-result.json 写入状态(含 test_framework / language / test_dir / scenarios_covered 等字段)
|
|
@@ -285,16 +277,17 @@ Task({
|
|
|
285
277
|
TASKS_FILE="specline/changes/<name>/tasks.md"
|
|
286
278
|
|
|
287
279
|
# 提取每个任务的核心元数据
|
|
288
|
-
# 期望输出格式:TASK_NUM|TYPE|DEPS|COVERS|FILES
|
|
289
|
-
rg -N --no-line-number '^## \d+\.|^- \*\*Type\*\*:|^- \*\*Depends\*\*:|^- \*\*Covers\*\*:|^- \*\*Files\*\*:' "$TASKS_FILE" | while read -r line; do
|
|
280
|
+
# 期望输出格式:TASK_NUM|TYPE|DEPS|COVERS|FILES|TESTABLE
|
|
281
|
+
rg -N --no-line-number '^## \d+\.|^- \*\*Type\*\*:|^- \*\*Depends\*\*:|^- \*\*Covers\*\*:|^- \*\*Files\*\*:|^- \*\*Testable\*\*:' "$TASKS_FILE" | while read -r line; do
|
|
290
282
|
# 解析并按批次分组
|
|
291
283
|
...
|
|
292
284
|
done
|
|
293
285
|
|
|
294
|
-
# 构建任务列表写入状态文件(含 Files 用于冲突检测,Covers
|
|
286
|
+
# 构建任务列表写入状态文件(含 Files 用于冲突检测,Covers 用于追溯,Testable 用于 TDD 判定)
|
|
287
|
+
# Testable 缺失时默认为 false(向后兼容)
|
|
295
288
|
jq --argjson tasks '[
|
|
296
|
-
{"id":"1","type":"backend","deps":[],"batch":1,"status":"pending","covers":"Requirement: 数据模型","files":["server/models.py"]},
|
|
297
|
-
{"id":"2","type":"frontend","deps":[],"batch":1,"status":"pending","covers":"Requirement: 登录页面","files":["src/components/Login.tsx"]}
|
|
289
|
+
{"id":"1","type":"backend","deps":[],"batch":1,"status":"pending","testable":true,"covers":"Requirement: 数据模型","files":["server/models.py"]},
|
|
290
|
+
{"id":"2","type":"frontend","deps":[],"batch":1,"status":"pending","testable":false,"covers":"Requirement: 登录页面","files":["src/components/Login.tsx"]}
|
|
298
291
|
]' '.phases.coding.tasks = $tasks' "$STATE_FILE" > tmp && mv tmp "$STATE_FILE"
|
|
299
292
|
```
|
|
300
293
|
|
|
@@ -304,12 +297,31 @@ jq --argjson tasks '[
|
|
|
304
297
|
|
|
305
298
|
**6c. 文件冲突检测(每批次派发前)**:
|
|
306
299
|
|
|
307
|
-
|
|
300
|
+
在派发每批任务之前,将当前批次所有任务的 `Files` 按路径前缀分为三类进行冲突检测:
|
|
301
|
+
|
|
302
|
+
**文件类型分类规则**:
|
|
303
|
+
|
|
304
|
+
| 文件类型 | 路径前缀 | 编写者 | 说明 |
|
|
305
|
+
|---------|---------|--------|------|
|
|
306
|
+
| `implementation` | 不以 `tests/` 开头 | coding agent | 实现代码、配置文件、文档等 |
|
|
307
|
+
| `unit_test` | `tests/unit/` 或 `tests/models/` | coding agent(TDD) | 白盒单元测试 |
|
|
308
|
+
| `other_test` | `tests/integration/` 或 `tests/e2e/` | test-writer | 黑盒集成/E2E 测试 |
|
|
309
|
+
|
|
310
|
+
**冲突判定逻辑**:
|
|
311
|
+
|
|
312
|
+
| 场景 | 判定 |
|
|
313
|
+
|------|------|
|
|
314
|
+
| 同类型文件重叠(均为 `implementation`、`unit_test` 或 `other_test`) | **冲突** |
|
|
315
|
+
| `unit_test` 与 `other_test` 重叠 | **不冲突**(目录隔离保证互不干扰) |
|
|
316
|
+
| `implementation` 与任何测试文件重叠 | **不冲突**(实现和测试天然分离) |
|
|
308
317
|
|
|
309
318
|
```bash
|
|
310
|
-
#
|
|
311
|
-
# 读取当前批次所有任务的 files 数组
|
|
312
|
-
#
|
|
319
|
+
# 伪代码:基于文件类型的三类冲突检测算法
|
|
320
|
+
# 1. 读取当前批次所有任务的 files 数组
|
|
321
|
+
# 2. 对每个文件按路径前缀分类:implementation / unit_test / other_test
|
|
322
|
+
# 3. 在同类型文件集合内检查是否有交集
|
|
323
|
+
# 4. 如果同类型 files 有交集 → 标记冲突任务对,暂停并报告用户
|
|
324
|
+
# 5. 跨类型重叠不标记为冲突
|
|
313
325
|
```
|
|
314
326
|
|
|
315
327
|
#### Step 7: 按批次并发派发 Coding Agent
|
|
@@ -340,10 +352,114 @@ for (const task of currentBatchTasks) {
|
|
|
340
352
|
default: agentType = "specline-backend-dev";
|
|
341
353
|
}
|
|
342
354
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
prompt:
|
|
355
|
+
// 根据 Testable 和 Type 构造 Prompt
|
|
356
|
+
let prompt;
|
|
357
|
+
if (task.testable === true) {
|
|
358
|
+
// === TDD prompt(Testable: true) ===
|
|
359
|
+
prompt = `
|
|
360
|
+
你收到一个编码任务(Type: ${task.type}, Testable: true),请按 TDD(测试驱动开发)方式实现本任务范围内的代码。
|
|
361
|
+
|
|
362
|
+
## 上下文文件(只读参考)
|
|
363
|
+
- Spec: specline/changes/${changeName}/specs/${capability}/spec.md
|
|
364
|
+
- Design: specline/changes/${changeName}/design.md
|
|
365
|
+
- Tasks: specline/changes/${changeName}/tasks.md
|
|
366
|
+
|
|
367
|
+
## 当前任务(只实现这个)
|
|
368
|
+
任务 ID: ${task.id}
|
|
369
|
+
覆盖需求: ${task.covers}
|
|
370
|
+
预期文件: ${task.files}
|
|
371
|
+
|
|
372
|
+
从 tasks.md 中提取的任务 ${task.id} 的完整描述:
|
|
373
|
+
---
|
|
374
|
+
${task.content}
|
|
375
|
+
---
|
|
376
|
+
|
|
377
|
+
## TDD 约束(RED-GREEN-REFACTOR)
|
|
378
|
+
|
|
379
|
+
你必须按以下 TDD 循环编写代码:
|
|
380
|
+
|
|
381
|
+
### RED 阶段
|
|
382
|
+
1. 分析 Spec 中本任务覆盖的 Scenario,提取需要测试的逻辑单元
|
|
383
|
+
2. 在 tests/unit/<module>/test_<feature>.{ext} 下编写测试文件
|
|
384
|
+
3. 每个 Scenario 至少 1 个测试函数/方法
|
|
385
|
+
4. 覆盖:Happy Path + 边界条件(空值、极值、边界值)+ 异常路径(错误输入、异常状态)
|
|
386
|
+
5. 运行测试,确认全部 FAIL(RED)
|
|
387
|
+
|
|
388
|
+
### GREEN 阶段
|
|
389
|
+
6. 编写最小实现代码,只使当前测试通过
|
|
390
|
+
7. 不编写测试未覆盖的逻辑
|
|
391
|
+
8. 运行测试,确认全部 PASS(GREEN)
|
|
392
|
+
|
|
393
|
+
### REFACTOR 阶段
|
|
394
|
+
9. 重构实现代码改善结构(提取方法、消除重复、优化命名)
|
|
395
|
+
10. 运行测试,确保持续 PASS
|
|
396
|
+
11. 如果需要,补充缺失的边界条件测试
|
|
397
|
+
|
|
398
|
+
## 关键约束
|
|
399
|
+
1. 只修改本任务 Files 范围内的文件
|
|
400
|
+
2. 不修改其他任务负责的文件
|
|
401
|
+
3. 与已完成任务的接口约定必须遵守(参考已生成的接口/类型定义文件)
|
|
402
|
+
4. 确认过 design.md 中的技术决策后再动手
|
|
403
|
+
5. 测试文件只能写入 tests/unit/ 或 tests/models/ 目录
|
|
404
|
+
6. 不得修改 tests/integration/ 或 tests/e2e/ 目录下的文件(属于 test-writer)
|
|
405
|
+
7. **完成后必须将 tasks.md 中本任务的 \`[ ]\` 改为 \`[x]\`**(方便断点续跑识别进度)
|
|
406
|
+
|
|
407
|
+
## 产出报告
|
|
408
|
+
完成后在 specline/changes/${changeName}/.tmp/task-${task.id}-result.json 写入:
|
|
409
|
+
{
|
|
410
|
+
"task_id": "${task.id}",
|
|
411
|
+
"type": "${task.type}",
|
|
412
|
+
"testable": true,
|
|
413
|
+
"covers": "${task.covers}",
|
|
414
|
+
"status": "completed",
|
|
415
|
+
"files_changed": [...],
|
|
416
|
+
"test_files": ["tests/unit/...", ...],
|
|
417
|
+
"tests_passed": true,
|
|
418
|
+
"summary": "..."
|
|
419
|
+
}
|
|
420
|
+
`;
|
|
421
|
+
} else if (["frontend", "backend", "infra", "db"].includes(task.type)) {
|
|
422
|
+
// === 标准编码 prompt(Testable: false,有代码逻辑) ===
|
|
423
|
+
prompt = `
|
|
424
|
+
你收到一个编码任务(Type: ${task.type}, Testable: false),请只实现本任务范围内的代码。
|
|
425
|
+
|
|
426
|
+
## 上下文文件(只读参考)
|
|
427
|
+
- Spec: specline/changes/${changeName}/specs/${capability}/spec.md
|
|
428
|
+
- Design: specline/changes/${changeName}/design.md
|
|
429
|
+
- Tasks: specline/changes/${changeName}/tasks.md
|
|
430
|
+
|
|
431
|
+
## 当前任务(只实现这个)
|
|
432
|
+
任务 ID: ${task.id}
|
|
433
|
+
覆盖需求: ${task.covers}
|
|
434
|
+
预期文件: ${task.files}
|
|
435
|
+
|
|
436
|
+
从 tasks.md 中提取的任务 ${task.id} 的完整描述:
|
|
437
|
+
---
|
|
438
|
+
${task.content}
|
|
439
|
+
---
|
|
440
|
+
|
|
441
|
+
## 约束
|
|
442
|
+
1. 只修改本任务 Files 范围内的文件
|
|
443
|
+
2. 不修改其他任务负责的文件
|
|
444
|
+
3. 与已完成任务的接口约定必须遵守(参考已生成的接口/类型定义文件)
|
|
445
|
+
4. 确认过 design.md 中的技术决策后再动手
|
|
446
|
+
5. **完成后必须将 tasks.md 中本任务的 \`[ ]\` 改为 \`[x]\`**(方便断点续跑识别进度)
|
|
447
|
+
|
|
448
|
+
## 产出报告
|
|
449
|
+
完成后在 specline/changes/${changeName}/.tmp/task-${task.id}-result.json 写入:
|
|
450
|
+
{
|
|
451
|
+
"task_id": "${task.id}",
|
|
452
|
+
"type": "${task.type}",
|
|
453
|
+
"testable": false,
|
|
454
|
+
"covers": "${task.covers}",
|
|
455
|
+
"status": "completed",
|
|
456
|
+
"files_changed": [...],
|
|
457
|
+
"summary": "..."
|
|
458
|
+
}
|
|
459
|
+
`;
|
|
460
|
+
} else {
|
|
461
|
+
// === 配置/文档 prompt(Type: config/docs) ===
|
|
462
|
+
prompt = `
|
|
347
463
|
你收到一个编码任务(Type: ${task.type}),请只实现本任务范围内的代码。
|
|
348
464
|
|
|
349
465
|
## 上下文文件(只读参考)
|
|
@@ -378,15 +494,25 @@ ${task.content}
|
|
|
378
494
|
"files_changed": [...],
|
|
379
495
|
"summary": "..."
|
|
380
496
|
}
|
|
381
|
-
|
|
497
|
+
`;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
Task({
|
|
501
|
+
subagent_type: agentType,
|
|
502
|
+
description: `实现任务 ${task.id}: ${task.title} [${task.type}]${task.testable ? ' (TDD)' : ''}`,
|
|
503
|
+
prompt: prompt
|
|
382
504
|
})
|
|
383
505
|
}
|
|
384
506
|
```
|
|
385
507
|
|
|
386
508
|
**7b. 等待当前批次所有 Agent 完成后**:
|
|
387
509
|
1. 验证每个 Agent 的产出报告(`specline/changes/<name>/.tmp/task-<id>-result.json`)
|
|
388
|
-
2.
|
|
389
|
-
|
|
510
|
+
2. **对 Testable=true 的任务**,验证 `task-<id>-result.json` 中是否包含 `test_files` 字段且其值非空。如果 Testable=true 但 agent 未产出测试文件,标记为 warning 并记录到事件日志:
|
|
511
|
+
```
|
|
512
|
+
{"ts":"...","event":"tdd_warning","task":"<id>","reason":"Testable=true but no test_files produced"}
|
|
513
|
+
```
|
|
514
|
+
3. 更新状态文件中对应 task 的 `status` 和 `completed_at`
|
|
515
|
+
4. **验证 tasks.md 中对应任务的 checkbox 已从 `[ ]` 变为 `[x]`**(如果未标记,自动补标)
|
|
390
516
|
|
|
391
517
|
```bash
|
|
392
518
|
# 更新状态文件
|
|
@@ -411,6 +537,10 @@ sed -i '' "s/^## ${task_id}\. \[ \]/## ${task_id}. [x]/" specline/changes/<name>
|
|
|
411
537
|
.cursor/hooks/specline-pipeline-gate.sh build --change "<name>"
|
|
412
538
|
```
|
|
413
539
|
|
|
540
|
+
Build Gate 校验内容:
|
|
541
|
+
- 编译/语法检查(原有逻辑)
|
|
542
|
+
- **单元测试文件存在性检查**(新增):对 Testable=true 的任务,检查其 `tests/unit/` 和 `tests/models/` 下的单元测试文件是否存在且语法正确。如果 Testable=true 的任务未产出对应测试文件,Build Gate 失败
|
|
543
|
+
|
|
414
544
|
exit code 0 = 通过,进入 Phase 3。失败处理见 [Layer 3: Build Gate 失败处理](#build-gate-失败处理)。
|
|
415
545
|
|
|
416
546
|
### Phase 3: CODE REVIEW
|
|
@@ -423,11 +553,21 @@ exit code 0 = 通过,进入 Phase 3。失败处理见 [Layer 3: Build Gate 失
|
|
|
423
553
|
|
|
424
554
|
审查前端/后端代码变更。审查时利用 tasks.md 的 `Covers` 追溯链:每个 finding 应标注涉及的文件和对应的 Requirement/Scenario。
|
|
425
555
|
|
|
556
|
+
对 Testable=true 的任务,额外审查其 `tests/unit/` 和 `tests/models/` 下的单元测试文件质量,包括:
|
|
557
|
+
- 边界条件覆盖(空值、极值、边界值)
|
|
558
|
+
- 异常路径覆盖(错误输入、异常状态)
|
|
559
|
+
- 测试断言的有效性
|
|
560
|
+
|
|
561
|
+
code-review.json 中 unit test 相关的 finding 标注 `type` 为 `"unit_test_quality"`,示例:
|
|
562
|
+
```json
|
|
563
|
+
{ "severity": "warning", "type": "unit_test_quality", "file": "tests/unit/auth/test_login.py", "covers": "Requirement: Coding Agent Prompt 条件化 TDD 注入", "message": "缺少空密码输入边界条件测试" }
|
|
564
|
+
```
|
|
565
|
+
|
|
426
566
|
**9b. specline-config-reviewer**(有 config/docs 类型任务时):
|
|
427
567
|
|
|
428
568
|
审查 config/docs 变更——shell 脚本安全性、配置文件语法和一致性、Markdown 文档结构完整性。
|
|
429
569
|
|
|
430
|
-
> 两种审查 Agent 可并发启动。产出均为 `specline/changes/<name>/.tmp/code-review.json`(`{ "findings": [{ "severity": "error"|"warning", "file": "...", "covers": "Requirement: xxx", "message": "..." }] }`)。
|
|
570
|
+
> 两种审查 Agent 可并发启动。产出均为 `specline/changes/<name>/.tmp/code-review.json`(`{ "findings": [{ "severity": "error"|"warning", "type": "unit_test_quality"|"style"|"security"|"logic", "file": "...", "covers": "Requirement: xxx", "message": "..." }] }`)。
|
|
431
571
|
|
|
432
572
|
#### Step 10: Lint Gate
|
|
433
573
|
|
|
@@ -568,13 +708,46 @@ jq '.phases.coding.gates.build_gate.passed = null' "$STATE_FILE" > tmp && mv tmp
|
|
|
568
708
|
|
|
569
709
|
### 测试失败处理
|
|
570
710
|
|
|
571
|
-
⚠️
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
711
|
+
⚠️ 测试失败根据失败文件所在的目录区分处理路径:
|
|
712
|
+
|
|
713
|
+
#### 单元测试失败处理
|
|
714
|
+
|
|
715
|
+
失败文件在 `tests/unit/` 或 `tests/models/` 目录下:
|
|
716
|
+
|
|
717
|
+
- 利用 `Covers` 追溯链定位到具体 coding 任务
|
|
718
|
+
- 回对应 coding agent 修复实现代码或测试代码(最多 2 次循环)
|
|
719
|
+
- `spec_ambiguity`(Spec 模糊)→ **不自动循环修复**,暂停流水线并展示模糊点给用户
|
|
720
|
+
|
|
721
|
+
Gate 重置(仅重置 test_unit_gate):
|
|
722
|
+
|
|
723
|
+
```bash
|
|
724
|
+
jq '.phases.test.sub_phases.unit.gates.test_unit_gate.passed = null' "$STATE_FILE" > tmp && mv tmp "$STATE_FILE"
|
|
725
|
+
```
|
|
726
|
+
|
|
727
|
+
#### 集成/E2E 测试失败处理
|
|
728
|
+
|
|
729
|
+
失败文件在 `tests/integration/` 或 `tests/e2e/` 目录下:
|
|
730
|
+
|
|
731
|
+
- specline-test-runner 分析原因:
|
|
732
|
+
- **测试代码问题** → specline-test-writer 自修(最多 2 次)
|
|
733
|
+
- **实现代码问题** → 利用 `Covers` 追溯链定位到具体任务,回对应 coding agent 修复 → **使用影响范围算法精确重置受影响任务的 Gate**
|
|
734
|
+
- **`spec_ambiguity`**(Spec 模糊)→ **不自动循环修复**,暂停流水线并展示模糊点给用户
|
|
575
735
|
- 循环最多 2 次
|
|
576
736
|
|
|
577
|
-
|
|
737
|
+
Gate 重置:
|
|
738
|
+
|
|
739
|
+
```bash
|
|
740
|
+
jq '
|
|
741
|
+
.phases.test.sub_phases.integration.gates.test_integration_gate.passed = null |
|
|
742
|
+
.phases.test.sub_phases.e2e.gates.test_e2e_gate.passed = null
|
|
743
|
+
' "$STATE_FILE" > tmp && mv tmp "$STATE_FILE"
|
|
744
|
+
```
|
|
745
|
+
|
|
746
|
+
#### 优先级规则
|
|
747
|
+
|
|
748
|
+
当单元测试和集成/E2E 测试同时失败时:**优先修复单元测试**(先执行 coding agent 修复循环),单元测试通过后再处理集成/E2E 测试失败。
|
|
749
|
+
|
|
750
|
+
代码修复后 Gate 全部重置(所有测试类型):
|
|
578
751
|
|
|
579
752
|
```bash
|
|
580
753
|
jq '
|
|
@@ -65,6 +65,7 @@ specline-pipeline-gate.sh new --change "<name>"
|
|
|
65
65
|
- **Type**: frontend | backend | infra | db | config | docs
|
|
66
66
|
- **Depends**: (none) | 依赖的任务编号
|
|
67
67
|
- **Covers**: Requirement: xxx, Scenario: xxx
|
|
68
|
+
- **Testable**: true | false
|
|
68
69
|
- **Files**: 任务涉及的文件路径列表
|
|
69
70
|
|
|
70
71
|
任务拆分原则:
|
|
@@ -100,8 +101,9 @@ specline-pipeline-gate.sh artifacts --change "<name>" --json
|
|
|
100
101
|
## 1. 数据模型 [x]
|
|
101
102
|
- Type: backend
|
|
102
103
|
- Depends: (none)
|
|
103
|
-
- Files: server/models/user.py
|
|
104
104
|
- Covers: Requirement: 用户数据模型
|
|
105
|
+
- Testable: true
|
|
106
|
+
- Files: server/models/user.py
|
|
105
107
|
```
|
|
106
108
|
|
|
107
109
|
> 任务粒度适中,Files 范围明确,Covers 可追溯到具体 Requirement。
|
|
@@ -126,6 +128,7 @@ specline-pipeline-gate.sh artifacts --change "<name>" --json
|
|
|
126
128
|
| 独立可测 | 每个任务可独立验证完成状态 |
|
|
127
129
|
| 文件不交叠 | 第 1 批次(Depends: none)任务的文件集合无交集 |
|
|
128
130
|
| 可追溯 | 每个任务必须通过 Covers 追溯到具体 Requirement/Scenario |
|
|
131
|
+
| Testable 标注 | 无依赖 + 有可测代码 + 非 config/docs → Testable: true |
|
|
129
132
|
|
|
130
133
|
---
|
|
131
134
|
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: specline-quickfix
|
|
3
|
+
description: 轻量修改 Skill —— 小改动用 quickfix,大功能用 pipeline
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /specline-quickfix 轻量修改 Skill
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Layer 1: 速览与定位
|
|
11
|
+
|
|
12
|
+
**一句话定位**:小改动用 quickfix,大功能用 pipeline。
|
|
13
|
+
|
|
14
|
+
**入口**:`/specline-quickfix <描述>`
|
|
15
|
+
|
|
16
|
+
**你做:**
|
|
17
|
+
- 读取相关代码理解上下文
|
|
18
|
+
- 直接 Write/StrReplace 编辑文件(不使用子 Agent)
|
|
19
|
+
- ReadLints 自动校验 + 修复(最多 2 次循环)
|
|
20
|
+
- 运行项目已有单元测试(失败修复最多 2 次循环)
|
|
21
|
+
- 生成轻量归档(summary.md + files-changed.json)
|
|
22
|
+
|
|
23
|
+
**你不做:**
|
|
24
|
+
- 创建 proposal.md、design.md、tasks.md、specs/ 等规划文档
|
|
25
|
+
- 启动任何 specline-* 子 Agent
|
|
26
|
+
- 创建 `.pipeline-state.json` 或 `.pipeline-sessions.json`
|
|
27
|
+
- 写新测试、跑集成/E2E 测试
|
|
28
|
+
|
|
29
|
+
### 流程概览
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
UNDERSTAND ──→ IMPLEMENT ──→ REVIEW ──→ TEST ──→ ARCHIVE
|
|
33
|
+
(读代码) (直编辑) (Lint+自审) (现有单测) (轻量归档)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Hook 透明
|
|
37
|
+
|
|
38
|
+
Quickfix 不绑定 Pipeline session,所有 Hook(sessionStart、preToolUse、postToolUse、subagentStart、beforeShellExecution)自动透明放行,不产生任何拦截或提醒。
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Layer 2: Happy Path
|
|
43
|
+
|
|
44
|
+
### Phase 1: UNDERSTAND
|
|
45
|
+
|
|
46
|
+
**目标**:理解变更上下文,明确修改范围。
|
|
47
|
+
|
|
48
|
+
**Steps**:
|
|
49
|
+
|
|
50
|
+
1. 解析用户描述,提取关键词(文件名、函数名、错误信息等)
|
|
51
|
+
2. 使用 Read 工具读取相关源文件,理解当前逻辑
|
|
52
|
+
3. 确认变更范围:
|
|
53
|
+
- 1-3 个文件 ✓
|
|
54
|
+
- 单一关注点 ✓
|
|
55
|
+
- 不涉及架构变更 ✓
|
|
56
|
+
- 不需要新测试 ✓
|
|
57
|
+
4. **意图模糊时**:使用 AskUserQuestion 向用户确认变更范围和目标,不要猜测
|
|
58
|
+
|
|
59
|
+
**准入条件**:变更范围已验证在 quickfix 适用范围内(参见 Layer 3 边界判断)
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
### Phase 2: IMPLEMENT
|
|
64
|
+
|
|
65
|
+
**目标**:直接编辑源文件,完成修改。
|
|
66
|
+
|
|
67
|
+
**Steps**:
|
|
68
|
+
|
|
69
|
+
1. 使用 Write / StrReplace 工具直接编辑文件
|
|
70
|
+
2. **不使用子 Agent**,不调用 Task 工具
|
|
71
|
+
3. 编辑完成后,运行 ReadLints 检查新增的 lint 错误
|
|
72
|
+
|
|
73
|
+
**约束**:
|
|
74
|
+
- 只修改 UNDERSTAND 阶段确认的文件
|
|
75
|
+
- 如果发现需要修改第 4 个文件 → 暂停并建议转 `/specline-pipeline`
|
|
76
|
+
- 保持现有代码风格和命名约定
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
### Phase 3: REVIEW
|
|
81
|
+
|
|
82
|
+
**目标**:通过 Lint 检查和 Agent 自审确保代码质量。
|
|
83
|
+
|
|
84
|
+
**Steps**:
|
|
85
|
+
|
|
86
|
+
1. 运行 ReadLints 收集所有 lint 问题
|
|
87
|
+
2. **如有 lint 错误**:自动修复 → 再次 ReadLints → 最多循环 2 次
|
|
88
|
+
- 第 1 次修复后仍有错误 → 分析原因,再次修复
|
|
89
|
+
- 第 2 次修复后仍有错误 → 报告用户,附错误列表和修复尝试记录,暂停
|
|
90
|
+
3. **Agent 自审**:
|
|
91
|
+
- 变更逻辑是否正确?
|
|
92
|
+
- 是否处理了边界条件?
|
|
93
|
+
- 是否引入了新问题(如未使用的导入、副作用)?
|
|
94
|
+
- 是否破坏现有功能?
|
|
95
|
+
4. 自审通过 → 进入 TEST 阶段
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
### Phase 4: TEST
|
|
100
|
+
|
|
101
|
+
**目标**:运行项目已有单元测试,确保不引入回归。
|
|
102
|
+
|
|
103
|
+
**Steps**:
|
|
104
|
+
|
|
105
|
+
1. **自动检测测试框架**:
|
|
106
|
+
- 检查 `package.json` scripts → Jest / Mocha / Vitest
|
|
107
|
+
- 检查 `pytest` / `go test` / `cargo test` 配置
|
|
108
|
+
2. **有测试配置**:运行现有单元测试
|
|
109
|
+
- 通过 → 进入 ARCHIVE 阶段
|
|
110
|
+
- 失败 → 分析失败原因,修复代码 → 重新运行 → 最多循环 2 次
|
|
111
|
+
- 第 2 次修复后仍失败 → 报告用户(附失败详情和修复尝试记录),暂停
|
|
112
|
+
3. **无测试配置**:跳过 TEST 阶段,进入 ARCHIVE 阶段(在 summary.md 中标注)
|
|
113
|
+
|
|
114
|
+
**不运行**:集成测试、E2E 测试、新编写的测试。
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
### Phase 5: ARCHIVE
|
|
119
|
+
|
|
120
|
+
**目标**:生成轻量归档,提供变更可追溯性。
|
|
121
|
+
|
|
122
|
+
**Steps**:
|
|
123
|
+
|
|
124
|
+
1. 在 `specline/changes/archive/` 下创建归档目录:
|
|
125
|
+
```
|
|
126
|
+
specline/changes/archive/YYYY-MM-DD-<description>/
|
|
127
|
+
├── summary.md
|
|
128
|
+
└── files-changed.json
|
|
129
|
+
```
|
|
130
|
+
2. **summary.md** 内容:
|
|
131
|
+
```markdown
|
|
132
|
+
# <变更标题>
|
|
133
|
+
|
|
134
|
+
## What
|
|
135
|
+
<一句话描述做了什么>
|
|
136
|
+
|
|
137
|
+
## Why
|
|
138
|
+
<为什么要做这个修改>
|
|
139
|
+
|
|
140
|
+
## Files Changed
|
|
141
|
+
- path/to/file1 — <修改简述>
|
|
142
|
+
- path/to/file2 — <修改简述>
|
|
143
|
+
|
|
144
|
+
## Test Result
|
|
145
|
+
- 通过 / 跳过(无现有单元测试)/ 失败(附详情)
|
|
146
|
+
```
|
|
147
|
+
3. **files-changed.json** 内容:
|
|
148
|
+
```json
|
|
149
|
+
{
|
|
150
|
+
"files": ["path/to/file1", "path/to/file2"],
|
|
151
|
+
"change_count": 2,
|
|
152
|
+
"description": "<变更描述>"
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
4. 展示变更摘要,**询问用户**:是否需要 git commit?
|
|
156
|
+
|
|
157
|
+
**无人确认点**:整个 quickfix 流程不暂停等待人工确认(lint + test 是自动质量底线)。
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## Layer 3: 异常与边界
|
|
162
|
+
|
|
163
|
+
### Quickfix vs Pipeline 边界判断
|
|
164
|
+
|
|
165
|
+
使用以下规则判断变更是否适合 quickfix:
|
|
166
|
+
|
|
167
|
+
| 维度 | Quickfix (`/specline-quickfix`) | Pipeline (`/specline-pipeline`) |
|
|
168
|
+
|------|-------------------------------|-------------------------------|
|
|
169
|
+
| 文件改动数 | 1-3 个 | 4+ 个 |
|
|
170
|
+
| 关注点 | 单一关注点 | 多关注点/跨模块 |
|
|
171
|
+
| 架构变更 | 无新架构/新组件 | 需要新组件/新 API |
|
|
172
|
+
| 测试 | 不需要新测试 | 需要写新测试 |
|
|
173
|
+
| 典型场景 | 修 bug、改配置、文档微调 | 新增功能、重构 |
|
|
174
|
+
| 产出 | summary.md + files-changed.json | proposal/design/tasks/specs + 全部测试 |
|
|
175
|
+
| 人工确认 | 0 个 | 3 个 |
|
|
176
|
+
| 耗时 | 1-3 分钟 | 10-30 分钟 |
|
|
177
|
+
|
|
178
|
+
**边界处理规则**:
|
|
179
|
+
|
|
180
|
+
| 异常情况 | 处理方式 |
|
|
181
|
+
|----------|----------|
|
|
182
|
+
| 变更范围 > 3 个文件 | 暂停,建议转 `/specline-pipeline` |
|
|
183
|
+
| 需要写新测试 | 暂停,建议转 `/specline-pipeline` |
|
|
184
|
+
| 涉及架构变更/新 API | 暂停,建议转 `/specline-pipeline` |
|
|
185
|
+
| Lint 修复 2 次后仍有错误 | 报告用户(附错误列表和修复记录),暂停 |
|
|
186
|
+
| 测试失败 2 次后仍失败 | 报告用户(附失败详情和修复记录),暂停 |
|
|
187
|
+
| 实现过程中发现需要额外文件 | 如果总数仍 ≤ 3 → 继续;如果 > 3 → 暂停并建议转 pipeline |
|
|
188
|
+
| 项目无测试配置 | 跳过 TEST 阶段,在 summary.md 中标注 |
|
|
189
|
+
|
|
190
|
+
### 不适合 Quickfix 的典型场景
|
|
191
|
+
|
|
192
|
+
- 新增功能模块(需要 spec/design 规划)
|
|
193
|
+
- 跨 3+ 模块的接口变更
|
|
194
|
+
- 数据库 schema 变更
|
|
195
|
+
- 需要新增测试覆盖的复杂修复
|
|
196
|
+
- 需要多人/多步骤协调的改动
|
|
197
|
+
|
|
198
|
+
**使用建议**:如果不确定,优先用 quickfix。如果需要更严格的流程保证,用 pipeline。
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## Layer 4: 附录
|
|
203
|
+
|
|
204
|
+
### 与 Pipeline 的关系
|
|
205
|
+
|
|
206
|
+
```
|
|
207
|
+
specline-pipeline (完整流程) specline-quickfix (轻量流程)
|
|
208
|
+
SPEC UNDERSTAND
|
|
209
|
+
↓ ↓
|
|
210
|
+
CODING (子 Agent 并发) IMPLEMENT (单 Agent 直编)
|
|
211
|
+
↓ ↓
|
|
212
|
+
CODE REVIEW (review Agent) REVIEW (ReadLints + 自审)
|
|
213
|
+
↓ ↓
|
|
214
|
+
TEST (unit → integration → e2e) TEST (现有单测 only)
|
|
215
|
+
↓ ↓
|
|
216
|
+
ARCHIVE (Delta sync) ARCHIVE (summary + files-changed)
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
两者完全独立,通过边界判断规则选择。不共享状态文件,不互相依赖。
|
|
220
|
+
|
|
221
|
+
### 归档目录结构兼容性
|
|
222
|
+
|
|
223
|
+
Quickfix 归档目录结构与 Pipeline 归档保持一致:
|
|
224
|
+
|
|
225
|
+
```
|
|
226
|
+
specline/changes/archive/
|
|
227
|
+
├── YYYY-MM-DD-<pipeline-change>/ ← Pipeline 归档
|
|
228
|
+
│ ├── proposal.md
|
|
229
|
+
│ ├── design.md
|
|
230
|
+
│ ├── tasks.md
|
|
231
|
+
│ ├── specs/
|
|
232
|
+
│ └── ...
|
|
233
|
+
│
|
|
234
|
+
└── YYYY-MM-DD-<quickfix-description>/ ← Quickfix 归档
|
|
235
|
+
├── summary.md
|
|
236
|
+
└── files-changed.json
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
两种归档方式共存于同一目录,通过内容区分(Pipeline 归档有 proposal.md 等完整文档,Quickfix 归档只有 summary.md + files-changed.json)。
|