cc-devflow 4.2.0 → 4.3.0
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/commands/flow/CLAUDE.md +0 -4
- package/.claude/docs/examples/design-inspiration-pool.md +59 -0
- package/.claude/docs/examples/ui-prototype-constitution-checklist.md +75 -0
- package/.claude/docs/implementation-summary-v7.md +449 -0
- package/.claude/docs/spec-format-guide.md +349 -0
- package/.claude/docs/state-consolidation-design.md +323 -0
- package/.claude/docs/templates/ARCHITECTURE_TEMPLATE.md +85 -386
- package/.claude/docs/templates/DESIGN_TEMPLATE.md +157 -0
- package/.claude/docs/templates/PROPOSAL_TEMPLATE.md +91 -0
- package/.claude/docs/templates/SPEC_TEMPLATE_DELTA.md +139 -0
- package/.claude/docs/templates/SPEC_TEMPLATE_PROJECT.md +93 -0
- package/.claude/docs/templates/STYLE_TEMPLATE.md +114 -901
- package/.claude/docs/templates/UI_PROTOTYPE_TEMPLATE.md +143 -1205
- package/.claude/hooks/inject-agent-context.ts +9 -9
- package/.claude/scripts/.claude/commands/flow/export-openspec.md +221 -0
- package/.claude/scripts/.claude/commands/flow/import-openspec.md +171 -0
- package/.claude/scripts/__tests__/openspec.test.js +212 -0
- package/.claude/scripts/delta-parser.ts +112 -2
- package/.claude/scripts/export-openspec.js +222 -0
- package/.claude/scripts/import-openspec.js +272 -0
- package/.claude/scripts/validate-scope.sh +200 -0
- package/.claude/skills/{workflow/flow-init → flow-init}/SKILL.md +25 -4
- package/.claude/skills/{workflow/flow-release → flow-release}/SKILL.md +14 -3
- package/.claude/skills/{workflow/flow-spec → flow-spec}/SKILL.md +30 -2
- package/.claude/skills/utility/npm-release/CLAUDE.md +55 -0
- package/.claude/skills/utility/npm-release/SKILL.md +111 -46
- package/.claude/skills/utility/npm-release/references/version-decision-guide.md +134 -0
- package/.claude/skills/utility/npm-release/scripts/atomic-version-bump.sh +95 -0
- package/.claude/skills/utility/npm-release/scripts/validate-version-sync.sh +82 -0
- package/.claude/skills/utility/npm-release/scripts/version-decision-tree.sh +44 -0
- package/.claude/tsc-cache/70d2fc6d-2936-429b-b529-429f1aae8c88/affected-repos.txt +1 -0
- package/.claude/tsc-cache/70d2fc6d-2936-429b-b529-429f1aae8c88/edited-files.log +2 -0
- package/CHANGELOG.md +40 -0
- package/README.md +2 -1
- package/README.zh-CN.md +2 -1
- package/docs/v4.3.0-migration-guide.md +276 -0
- package/lib/harness/CLAUDE.md +5 -4
- package/lib/harness/__tests__/planner.tdd.test.js +125 -0
- package/lib/harness/index.js +4 -2
- package/lib/harness/operations/dispatch.js +13 -0
- package/lib/harness/operations/plan.js +55 -1
- package/lib/harness/operations/release.js +87 -0
- package/lib/harness/operations/verify.js +14 -0
- package/lib/harness/planner.js +131 -0
- package/lib/harness/query.js +126 -0
- package/lib/harness/schemas.js +22 -1
- package/package.json +1 -1
- package/.claude/commands/flow/checklist.md +0 -18
- package/.claude/commands/flow/clarify.md +0 -18
- package/.claude/commands/flow/new.md +0 -23
- package/.claude/commands/flow/quality.md +0 -21
- package/.claude/docs/templates/EPIC_TEMPLATE.md +0 -805
- package/.claude/docs/templates/PRD_TEMPLATE.md +0 -562
- package/.claude/docs/templates/TASKS_TEMPLATE.md +0 -523
- package/.claude/docs/templates/TECH_DESIGN_TEMPLATE.md +0 -1019
- package/.claude/skills/workflow/CLAUDE.md +0 -24
- /package/.claude/skills/{domain/attention-refresh → attention-refresh}/SKILL.md +0 -0
- /package/.claude/skills/{domain/brainstorming → brainstorming}/SKILL.md +0 -0
- /package/.claude/skills/{guardrail/constitution-guardian → constitution-guardian}/SKILL.md +0 -0
- /package/.claude/skills/{utility/constitution-quick-ref → constitution-quick-ref}/SKILL.md +0 -0
- /package/.claude/skills/{domain/debugging → debugging}/SKILL.md +0 -0
- /package/.claude/skills/{utility/file-standards → file-standards}/SKILL.md +0 -0
- /package/.claude/skills/{domain/finishing-branch → finishing-branch}/SKILL.md +0 -0
- /package/.claude/skills/{workflow/flow-dev → flow-dev}/CLAUDE.md +0 -0
- /package/.claude/skills/{workflow/flow-dev → flow-dev}/SKILL.md +0 -0
- /package/.claude/skills/{workflow/flow-dev → flow-dev}/assets/IMPLEMENTATION_PLAN_TEMPLATE.md +0 -0
- /package/.claude/skills/{workflow/flow-dev → flow-dev}/context.jsonl +0 -0
- /package/.claude/skills/{workflow/flow-dev → flow-dev}/dev-implementer.jsonl +0 -0
- /package/.claude/skills/{workflow/flow-dev → flow-dev}/scripts/entry-gate.sh +0 -0
- /package/.claude/skills/{workflow/flow-dev → flow-dev}/scripts/exit-gate.sh +0 -0
- /package/.claude/skills/{workflow/flow-dev → flow-dev}/scripts/task-orchestrator.sh +0 -0
- /package/.claude/skills/{workflow/flow-fix → flow-fix}/SKILL.md +0 -0
- /package/.claude/skills/{workflow/flow-fix → flow-fix}/context.jsonl +0 -0
- /package/.claude/skills/{workflow/flow-fix → flow-fix}/references/bug-analyzer.md +0 -0
- /package/.claude/skills/{workflow/flow-init → flow-init}/assets/BRAINSTORM_TEMPLATE.md +0 -0
- /package/.claude/skills/{workflow/flow-init → flow-init}/assets/INIT_FLOW_TEMPLATE.md +0 -0
- /package/.claude/skills/{workflow/flow-init → flow-init}/assets/RESEARCH_TEMPLATE.md +0 -0
- /package/.claude/skills/{workflow/flow-init → flow-init}/context.jsonl +0 -0
- /package/.claude/skills/{workflow/flow-init → flow-init}/references/flow-researcher.md +0 -0
- /package/.claude/skills/{workflow/flow-init → flow-init}/scripts/check-prerequisites.sh +0 -0
- /package/.claude/skills/{workflow/flow-init → flow-init}/scripts/consolidate-research.sh +0 -0
- /package/.claude/skills/{workflow/flow-init → flow-init}/scripts/create-requirement.sh +0 -0
- /package/.claude/skills/{workflow/flow-init → flow-init}/scripts/generate-research-tasks.sh +0 -0
- /package/.claude/skills/{workflow/flow-init → flow-init}/scripts/populate-research-tasks.sh +0 -0
- /package/.claude/skills/{workflow/flow-init → flow-init}/scripts/validate-research.sh +0 -0
- /package/.claude/skills/{workflow/flow-quality → flow-quality}/SKILL.md +0 -0
- /package/.claude/skills/{workflow/flow-quality → flow-quality}/context.jsonl +0 -0
- /package/.claude/skills/{workflow/flow-quality → flow-quality}/references/code-quality-reviewer.md +0 -0
- /package/.claude/skills/{workflow/flow-quality → flow-quality}/references/qa-tester.md +0 -0
- /package/.claude/skills/{workflow/flow-quality → flow-quality}/references/security-reviewer.md +0 -0
- /package/.claude/skills/{workflow/flow-quality → flow-quality}/references/spec-reviewer.md +0 -0
- /package/.claude/skills/{workflow/flow-release → flow-release}/context.jsonl +0 -0
- /package/.claude/skills/{workflow/flow-release → flow-release}/references/release-manager.md +0 -0
- /package/.claude/skills/{workflow/flow-spec → flow-spec}/CLAUDE.md +0 -0
- /package/.claude/skills/{workflow/flow-spec → flow-spec}/context.jsonl +0 -0
- /package/.claude/skills/{workflow/flow-spec → flow-spec}/scripts/entry-gate.sh +0 -0
- /package/.claude/skills/{workflow/flow-spec → flow-spec}/scripts/exit-gate.sh +0 -0
- /package/.claude/skills/{workflow/flow-spec → flow-spec}/scripts/parallel-orchestrator.sh +0 -0
- /package/.claude/skills/{workflow/flow-spec → flow-spec}/scripts/team-communication.sh +0 -0
- /package/.claude/skills/{workflow/flow-spec → flow-spec}/scripts/team-init.sh +0 -0
- /package/.claude/skills/{workflow/flow-spec → flow-spec}/scripts/test-team-mode.sh +0 -0
- /package/.claude/skills/{workflow/flow-spec → flow-spec}/team-config.json +0 -0
- /package/.claude/skills/{workflow/flow-verify → flow-verify}/CLAUDE.md +0 -0
- /package/.claude/skills/{workflow/flow-verify → flow-verify}/SKILL.md +0 -0
- /package/.claude/skills/{workflow/flow-verify → flow-verify}/context.jsonl +0 -0
- /package/.claude/skills/{utility/fractal-docs → fractal-docs}/SKILL.md +0 -0
- /package/.claude/skills/{utility/journey-checker → journey-checker}/SKILL.md +0 -0
- /package/.claude/skills/{utility/journey-checker → journey-checker}/pressure-scenarios.md +0 -0
- /package/.claude/skills/{domain/receiving-review → receiving-review}/SKILL.md +0 -0
- /package/.claude/skills/{utility/skill-creator → skill-creator}/LICENSE.txt +0 -0
- /package/.claude/skills/{utility/skill-creator → skill-creator}/SKILL.md +0 -0
- /package/.claude/skills/{utility/skill-creator → skill-creator}/references/output-patterns.md +0 -0
- /package/.claude/skills/{utility/skill-creator → skill-creator}/references/workflows.md +0 -0
- /package/.claude/skills/{utility/skill-creator → skill-creator}/scripts/init_skill.py +0 -0
- /package/.claude/skills/{utility/skill-creator → skill-creator}/scripts/package_skill.py +0 -0
- /package/.claude/skills/{utility/skill-creator → skill-creator}/scripts/quick_validate.py +0 -0
- /package/.claude/skills/{domain/tdd → tdd}/SKILL.md +0 -0
- /package/.claude/skills/{guardrail/tdd-enforcer → tdd-enforcer}/SKILL.md +0 -0
- /package/.claude/skills/{domain/verification → verification}/SKILL.md +0 -0
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
# CC-DevFlow v4.3.0 Migration Guide
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
CC-DevFlow v4.3.0 introduces automatic TDD order validation and OpenSpec interoperability to solve requirement drift problems. This guide helps you migrate from v4.2.x to v4.3.0.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## What's New in v4.3.0
|
|
10
|
+
|
|
11
|
+
### 1. Automatic TDD Order Validation
|
|
12
|
+
|
|
13
|
+
**Feature**: The harness planner now automatically validates TDD order when parsing TASKS.md.
|
|
14
|
+
|
|
15
|
+
**Impact**:
|
|
16
|
+
- [IMPL] tasks MUST depend on corresponding [TEST] tasks
|
|
17
|
+
- [TEST] tasks CANNOT depend on [IMPL] tasks
|
|
18
|
+
- Violations throw detailed error messages at `harness:plan` time
|
|
19
|
+
|
|
20
|
+
**Example Error**:
|
|
21
|
+
```
|
|
22
|
+
TDD Order Validation Failed (Constitution Article VI):
|
|
23
|
+
|
|
24
|
+
1. Task T002 (用户登录实现) missing corresponding TEST task.
|
|
25
|
+
Constitution Article VI requires: NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST.
|
|
26
|
+
|
|
27
|
+
2. Task T004 (用户注册实现) must depend on T003 (用户注册测试).
|
|
28
|
+
TDD violation: Implementation must come AFTER test.
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Migration Steps**:
|
|
32
|
+
1. Review your existing TASKS.md files
|
|
33
|
+
2. Ensure all [IMPL] tasks have corresponding [TEST] tasks
|
|
34
|
+
3. Add `dependsOn` to [IMPL] tasks pointing to [TEST] tasks
|
|
35
|
+
4. Use `[P]` marker for parallel tasks that don't follow TEST→IMPL pattern
|
|
36
|
+
|
|
37
|
+
**Example Fix**:
|
|
38
|
+
```markdown
|
|
39
|
+
<!-- Before (INVALID) -->
|
|
40
|
+
- [ ] T001 [IMPL] 用户登录实现
|
|
41
|
+
- [ ] T002 [TEST] 用户登录测试
|
|
42
|
+
|
|
43
|
+
<!-- After (VALID) -->
|
|
44
|
+
- [ ] T001 [TEST] 用户登录测试
|
|
45
|
+
- [ ] T002 [IMPL] 用户登录实现 (dependsOn:T001)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 2. OpenSpec Interoperability
|
|
49
|
+
|
|
50
|
+
**Feature**: Bidirectional conversion between OpenSpec and CC-DevFlow formats.
|
|
51
|
+
|
|
52
|
+
**New Commands**:
|
|
53
|
+
- `/flow:import-openspec` - Import OpenSpec spec.md to CC-DevFlow
|
|
54
|
+
- `/flow:export-openspec` - Export CC-DevFlow spec.md to OpenSpec
|
|
55
|
+
|
|
56
|
+
**Use Cases**:
|
|
57
|
+
|
|
58
|
+
#### Import from OpenSpec
|
|
59
|
+
```bash
|
|
60
|
+
/flow:import-openspec "/path/to/openspec/specs/auth/spec.md" \
|
|
61
|
+
--req-id "REQ-123" \
|
|
62
|
+
--title "用户认证系统"
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**What happens**:
|
|
66
|
+
1. Parses OpenSpec format (Purpose + Requirements + BDD scenarios)
|
|
67
|
+
2. Generates CC-DevFlow spec.md with YAML frontmatter
|
|
68
|
+
3. Auto-generates TDD tasks (TEST + IMPL pairs with correct dependencies)
|
|
69
|
+
4. Adds Design section with [NEEDS CLARIFICATION] markers
|
|
70
|
+
5. Generates Verification checklist
|
|
71
|
+
|
|
72
|
+
#### Export to OpenSpec
|
|
73
|
+
```bash
|
|
74
|
+
/flow:export-openspec "REQ-123" \
|
|
75
|
+
--output "/path/to/openspec/specs/auth/spec.md"
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**What happens**:
|
|
79
|
+
1. Parses CC-DevFlow spec.md
|
|
80
|
+
2. Strips YAML frontmatter and metadata
|
|
81
|
+
3. Removes Design, Tasks, Verification sections
|
|
82
|
+
4. Removes [NEEDS CLARIFICATION] markers
|
|
83
|
+
5. Outputs pure Requirements in OpenSpec format
|
|
84
|
+
|
|
85
|
+
**Round-Trip Guarantee**: Requirements are preserved through import→export→import cycles.
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Breaking Changes
|
|
90
|
+
|
|
91
|
+
### 1. TASKS.md Validation
|
|
92
|
+
|
|
93
|
+
**Before v4.3.0**: TDD order was recommended but not enforced.
|
|
94
|
+
|
|
95
|
+
**After v4.3.0**: TDD order is enforced at `harness:plan` time.
|
|
96
|
+
|
|
97
|
+
**Migration**: Update existing TASKS.md files to follow TDD order.
|
|
98
|
+
|
|
99
|
+
### 2. Task Type Detection
|
|
100
|
+
|
|
101
|
+
**Before v4.3.0**: Task types were not tracked.
|
|
102
|
+
|
|
103
|
+
**After v4.3.0**: Tasks are classified as TEST/IMPL/OTHER based on markers.
|
|
104
|
+
|
|
105
|
+
**Migration**: Ensure your TASKS.md uses `[TEST]` and `[IMPL]` markers consistently.
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## Feature Name Matching Algorithm
|
|
110
|
+
|
|
111
|
+
The TDD validator uses intelligent fuzzy matching to pair TEST and IMPL tasks:
|
|
112
|
+
|
|
113
|
+
**Normalization Rules**:
|
|
114
|
+
- Removes suffixes: "测试", "实现", "功能", "开发", "编写"
|
|
115
|
+
- Trims whitespace
|
|
116
|
+
- Compares core feature names
|
|
117
|
+
|
|
118
|
+
**Examples**:
|
|
119
|
+
```
|
|
120
|
+
"用户登录功能测试" ↔ "用户登录功能实现" ✅ Match
|
|
121
|
+
"用户登录测试" ↔ "用户登录实现" ✅ Match
|
|
122
|
+
"用户登录" ↔ "用户登录功能" ✅ Match
|
|
123
|
+
"用户登录" ↔ "用户注册" ❌ No match
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Parallel Tasks
|
|
129
|
+
|
|
130
|
+
For tasks that don't follow TEST→IMPL pattern, use the `[P]` marker:
|
|
131
|
+
|
|
132
|
+
```markdown
|
|
133
|
+
- [ ] T001 [TEST] 用户登录测试
|
|
134
|
+
- [ ] T002 [IMPL] 用户登录实现 (dependsOn:T001)
|
|
135
|
+
- [ ] T003 [OTHER] 数据库迁移 [P]
|
|
136
|
+
- [ ] T004 [OTHER] 配置文件更新 [P]
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
The `[P]` marker tells the validator to skip dependency checks for that task.
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## OpenSpec Format Reference
|
|
144
|
+
|
|
145
|
+
### OpenSpec Format (Input)
|
|
146
|
+
```markdown
|
|
147
|
+
# Authentication Module
|
|
148
|
+
|
|
149
|
+
## Purpose
|
|
150
|
+
Provides secure authentication and session management.
|
|
151
|
+
|
|
152
|
+
## Requirements
|
|
153
|
+
|
|
154
|
+
### Requirement: User Login
|
|
155
|
+
The system SHALL allow users to log in with email and password.
|
|
156
|
+
|
|
157
|
+
#### Scenario: Valid credentials
|
|
158
|
+
- GIVEN a registered user
|
|
159
|
+
- WHEN the user submits valid email and password
|
|
160
|
+
- THEN a JWT token is issued
|
|
161
|
+
- AND the user is redirected to dashboard
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### CC-DevFlow Format (Output)
|
|
165
|
+
```markdown
|
|
166
|
+
---
|
|
167
|
+
req_id: "REQ-123"
|
|
168
|
+
title: "用户认证系统"
|
|
169
|
+
created_at: "2026-03-13T10:00:00Z"
|
|
170
|
+
version: "1.0.0"
|
|
171
|
+
status: "draft"
|
|
172
|
+
source: "openspec"
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
# Authentication Module
|
|
176
|
+
|
|
177
|
+
## Purpose
|
|
178
|
+
Provides secure authentication and session management.
|
|
179
|
+
|
|
180
|
+
## Requirements
|
|
181
|
+
|
|
182
|
+
### Requirement: User Login
|
|
183
|
+
The system SHALL allow users to log in with email and password.
|
|
184
|
+
|
|
185
|
+
#### Scenario: Valid credentials
|
|
186
|
+
- GIVEN a registered user
|
|
187
|
+
- WHEN the user submits valid email and password
|
|
188
|
+
- THEN a JWT token is issued
|
|
189
|
+
- AND the user is redirected to dashboard
|
|
190
|
+
|
|
191
|
+
## Design
|
|
192
|
+
[NEEDS CLARIFICATION: 技术实现方案]
|
|
193
|
+
|
|
194
|
+
## Tasks
|
|
195
|
+
- [ ] T001 [TEST] User Login - 测试
|
|
196
|
+
- [ ] T002 [IMPL] User Login - 实现 (dependsOn:T001)
|
|
197
|
+
|
|
198
|
+
## Verification
|
|
199
|
+
- [ ] User Login
|
|
200
|
+
- [ ] Valid credentials
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## Testing
|
|
206
|
+
|
|
207
|
+
All v4.3.0 features are covered by automated tests:
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
# Run all tests
|
|
211
|
+
npm test
|
|
212
|
+
|
|
213
|
+
# Run TDD validation tests only
|
|
214
|
+
npm test -- planner.tdd.test.js
|
|
215
|
+
|
|
216
|
+
# Run OpenSpec interop tests only
|
|
217
|
+
npm test -- openspec.test.js
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
**Test Coverage**:
|
|
221
|
+
- TDD validation: 10 tests (all passing)
|
|
222
|
+
- OpenSpec interop: 5 tests (all passing)
|
|
223
|
+
- Total: 233 tests (all passing)
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## Troubleshooting
|
|
228
|
+
|
|
229
|
+
### Error: "Task T002 missing corresponding TEST task"
|
|
230
|
+
|
|
231
|
+
**Cause**: An [IMPL] task has no matching [TEST] task.
|
|
232
|
+
|
|
233
|
+
**Solution**: Add a [TEST] task with similar feature name before the [IMPL] task.
|
|
234
|
+
|
|
235
|
+
### Error: "Task T002 must depend on T001"
|
|
236
|
+
|
|
237
|
+
**Cause**: An [IMPL] task doesn't depend on its corresponding [TEST] task.
|
|
238
|
+
|
|
239
|
+
**Solution**: Add `(dependsOn:T001)` to the [IMPL] task.
|
|
240
|
+
|
|
241
|
+
### Error: "Task T001 depends on IMPL tasks"
|
|
242
|
+
|
|
243
|
+
**Cause**: A [TEST] task depends on an [IMPL] task (reverse TDD order).
|
|
244
|
+
|
|
245
|
+
**Solution**: Remove the dependency or reorder tasks.
|
|
246
|
+
|
|
247
|
+
### Feature Name Mismatch
|
|
248
|
+
|
|
249
|
+
**Cause**: TEST and IMPL tasks have very different feature names.
|
|
250
|
+
|
|
251
|
+
**Solution**: Rename tasks to have similar core feature names, or use `[P]` marker if they're truly independent.
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## Rollback
|
|
256
|
+
|
|
257
|
+
If you need to rollback to v4.2.0:
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
npm install cc-devflow@4.2.0
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
Note: v4.2.0 does not have TDD validation or OpenSpec interop features.
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
## Support
|
|
268
|
+
|
|
269
|
+
- GitHub Issues: https://github.com/anthropics/cc-devflow/issues
|
|
270
|
+
- Documentation: https://github.com/anthropics/cc-devflow/tree/main/docs
|
|
271
|
+
- Constitution: `.claude/rules/project-constitution.md`
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
**Last Updated**: 2026-03-13
|
|
276
|
+
**Version**: 4.3.0
|
package/lib/harness/CLAUDE.md
CHANGED
|
@@ -3,16 +3,17 @@
|
|
|
3
3
|
|
|
4
4
|
成员清单
|
|
5
5
|
index.js: 聚合导出 harness 基础模块,供 CLI 与测试统一引用。
|
|
6
|
-
schemas.js: 定义 manifest/report/checkpoint 的 Zod 契约,阻断脏数据进入执行层。
|
|
6
|
+
schemas.js: 定义 manifest/report/checkpoint/harness-state 的 Zod 契约,阻断脏数据进入执行层。
|
|
7
7
|
store.js: 提供路径规范、JSON/文本读写、JSONL 事件记录与 shell 命令执行。
|
|
8
8
|
planner.js: 将 TASKS.md 解析为 dependency-aware 的 task-manifest.json。
|
|
9
|
+
query.js: 聚合分散状态文件,提供 getProgress/getNextTask/getFullState 查询函数。
|
|
9
10
|
cli.js: 解析命令参数并分发到 operations 子模块。
|
|
10
11
|
operations/init.js: 初始化 requirement 与 runtime 目录并写入 harness-state。
|
|
11
12
|
operations/pack.js: 采集 git 与脚本事实,生成 context-package.md。
|
|
12
|
-
operations/plan.js: 调用 planner 生成 task-manifest.json。
|
|
13
|
-
operations/dispatch.js: 依据依赖图与文件冲突并行执行任务,写 checkpoint 与 events。
|
|
13
|
+
operations/plan.js: 调用 planner 生成 task-manifest.json,更新 harness-state 为 planned。
|
|
14
|
+
operations/dispatch.js: 依据依赖图与文件冲突并行执行任务,写 checkpoint 与 events,更新 harness-state 为 in_progress。
|
|
14
15
|
operations/resume.js: 恢复中断任务并复用 dispatch 继续执行。
|
|
15
|
-
operations/verify.js: 执行 quick/strict 质量门禁并输出 report-card.json。
|
|
16
|
+
operations/verify.js: 执行 quick/strict 质量门禁并输出 report-card.json,通过时更新 harness-state 为 verified。
|
|
16
17
|
operations/release.js: 读取通过的 report-card,生成 RELEASE_NOTE 并标记 released。
|
|
17
18
|
operations/janitor.js: 清理过期 runtime 工件,保留运行中任务状态。
|
|
18
19
|
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TDD Order Validation Tests
|
|
3
|
+
*
|
|
4
|
+
* Tests for Constitution Article VI enforcement in planner.js
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { parseTasksMarkdown } = require('../planner');
|
|
8
|
+
|
|
9
|
+
describe('TDD Order Validation', () => {
|
|
10
|
+
describe('Valid TDD sequences', () => {
|
|
11
|
+
test('should accept TEST before IMPL with correct dependency', () => {
|
|
12
|
+
const markdown = `
|
|
13
|
+
- [ ] T001 [TEST] 用户登录功能测试
|
|
14
|
+
- [ ] T002 [IMPL] 用户登录功能实现 (dependsOn:T001)
|
|
15
|
+
`.trim();
|
|
16
|
+
|
|
17
|
+
expect(() => parseTasksMarkdown(markdown)).not.toThrow();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test('should accept multiple TEST-IMPL pairs', () => {
|
|
21
|
+
const markdown = `
|
|
22
|
+
- [ ] T001 [TEST] 用户登录测试
|
|
23
|
+
- [ ] T002 [IMPL] 用户登录实现 (dependsOn:T001)
|
|
24
|
+
- [ ] T003 [TEST] 用户注册测试 [P]
|
|
25
|
+
- [ ] T004 [IMPL] 用户注册实现 (dependsOn:T003)
|
|
26
|
+
`.trim();
|
|
27
|
+
|
|
28
|
+
expect(() => parseTasksMarkdown(markdown)).not.toThrow();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test('should accept tasks without TEST/IMPL markers', () => {
|
|
32
|
+
const markdown = `
|
|
33
|
+
- [ ] T001 初始化项目结构
|
|
34
|
+
- [ ] T002 配置开发环境
|
|
35
|
+
`.trim();
|
|
36
|
+
|
|
37
|
+
expect(() => parseTasksMarkdown(markdown)).not.toThrow();
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
describe('TDD violations', () => {
|
|
42
|
+
test('should reject IMPL without corresponding TEST', () => {
|
|
43
|
+
const markdown = `
|
|
44
|
+
- [ ] T001 [IMPL] 用户登录功能实现
|
|
45
|
+
`.trim();
|
|
46
|
+
|
|
47
|
+
expect(() => parseTasksMarkdown(markdown)).toThrow(
|
|
48
|
+
/missing corresponding TEST task/
|
|
49
|
+
);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test('should reject IMPL not depending on TEST', () => {
|
|
53
|
+
const markdown = `
|
|
54
|
+
- [ ] T001 [TEST] 用户登录功能测试
|
|
55
|
+
- [ ] T002 [IMPL] 用户登录功能实现 [P]
|
|
56
|
+
`.trim();
|
|
57
|
+
|
|
58
|
+
expect(() => parseTasksMarkdown(markdown)).toThrow(
|
|
59
|
+
/must depend on T001/
|
|
60
|
+
);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test('should reject TEST depending on IMPL', () => {
|
|
64
|
+
const markdown = `
|
|
65
|
+
- [ ] T001 [IMPL] 用户登录功能实现
|
|
66
|
+
- [ ] T002 [TEST] 用户登录功能测试 (dependsOn:T001)
|
|
67
|
+
`.trim();
|
|
68
|
+
|
|
69
|
+
expect(() => parseTasksMarkdown(markdown)).toThrow(
|
|
70
|
+
/Tests must be written BEFORE implementation/
|
|
71
|
+
);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test('should reject IMPL depending on wrong TEST', () => {
|
|
75
|
+
const markdown = `
|
|
76
|
+
- [ ] T001 [TEST] 用户注册测试
|
|
77
|
+
- [ ] T002 [IMPL] 用户登录实现 (dependsOn:T001)
|
|
78
|
+
`.trim();
|
|
79
|
+
|
|
80
|
+
expect(() => parseTasksMarkdown(markdown)).toThrow(
|
|
81
|
+
/missing corresponding TEST task/
|
|
82
|
+
);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
describe('Feature name extraction', () => {
|
|
87
|
+
test('should match TEST and IMPL with same feature name', () => {
|
|
88
|
+
const markdown = `
|
|
89
|
+
- [ ] T001 [TEST] 实现用户认证功能
|
|
90
|
+
- [ ] T002 [IMPL] 实现用户认证功能 (dependsOn:T001)
|
|
91
|
+
`.trim();
|
|
92
|
+
|
|
93
|
+
expect(() => parseTasksMarkdown(markdown)).not.toThrow();
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
test('should handle case-insensitive markers', () => {
|
|
97
|
+
const markdown = `
|
|
98
|
+
- [ ] T001 [test] 用户登录
|
|
99
|
+
- [ ] T002 [impl] 用户登录 (dependsOn:T001)
|
|
100
|
+
`.trim();
|
|
101
|
+
|
|
102
|
+
expect(() => parseTasksMarkdown(markdown)).not.toThrow();
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
describe('Error messages', () => {
|
|
107
|
+
test('should provide clear violation details', () => {
|
|
108
|
+
const markdown = `
|
|
109
|
+
- [ ] T001 [IMPL] 功能A
|
|
110
|
+
- [ ] T002 [TEST] 功能B
|
|
111
|
+
- [ ] T003 [IMPL] 功能B
|
|
112
|
+
`.trim();
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
parseTasksMarkdown(markdown);
|
|
116
|
+
fail('Should have thrown TDD violation error');
|
|
117
|
+
} catch (error) {
|
|
118
|
+
expect(error.message).toContain('TDD Order Validation Failed');
|
|
119
|
+
expect(error.message).toContain('Constitution Article VI');
|
|
120
|
+
expect(error.message).toContain('T001');
|
|
121
|
+
expect(error.message).toContain('missing corresponding TEST task');
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
});
|
package/lib/harness/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* [INPUT]: 依赖 harness 各模块。
|
|
3
|
-
* [OUTPUT]: 统一导出 schema/store/planner 与 operations 入口。
|
|
3
|
+
* [OUTPUT]: 统一导出 schema/store/planner/query 与 operations 入口。
|
|
4
4
|
* [POS]: harness 模块聚合出口,被 bin 与测试代码使用。
|
|
5
5
|
* [PROTOCOL]: 变更时更新此头部,然后检查 CLAUDE.md
|
|
6
6
|
*/
|
|
@@ -8,9 +8,11 @@
|
|
|
8
8
|
const store = require('./store');
|
|
9
9
|
const schemas = require('./schemas');
|
|
10
10
|
const planner = require('./planner');
|
|
11
|
+
const query = require('./query');
|
|
11
12
|
|
|
12
13
|
module.exports = {
|
|
13
14
|
...store,
|
|
14
15
|
...schemas,
|
|
15
|
-
...planner
|
|
16
|
+
...planner,
|
|
17
|
+
...query
|
|
16
18
|
};
|
|
@@ -13,6 +13,7 @@ const {
|
|
|
13
13
|
readJson,
|
|
14
14
|
runCommand,
|
|
15
15
|
getTaskManifestPath,
|
|
16
|
+
getHarnessStatePath,
|
|
16
17
|
getRuntimeTaskDir,
|
|
17
18
|
getEventsPath,
|
|
18
19
|
getCheckpointPath
|
|
@@ -203,6 +204,18 @@ async function runDispatch({ repoRoot, changeId, parallel = 3, maxRetries, resum
|
|
|
203
204
|
const manifestPath = getTaskManifestPath(repoRoot, changeId);
|
|
204
205
|
const manifest = parseManifest(await readJson(manifestPath));
|
|
205
206
|
|
|
207
|
+
// Update harness-state.json to in_progress on first dispatch
|
|
208
|
+
const statePath = getHarnessStatePath(repoRoot, changeId);
|
|
209
|
+
const stateExists = require('fs').existsSync(statePath);
|
|
210
|
+
if (stateExists) {
|
|
211
|
+
const state = await readJson(statePath);
|
|
212
|
+
if (state.status === 'planned' || state.status === 'initialized') {
|
|
213
|
+
state.status = 'in_progress';
|
|
214
|
+
state.updatedAt = nowIso();
|
|
215
|
+
await writeJson(statePath, state);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
206
219
|
if (resume) {
|
|
207
220
|
for (const task of manifest.tasks) {
|
|
208
221
|
if (task.status === 'running') {
|
|
@@ -6,9 +6,53 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
const { createTaskManifest } = require('../planner');
|
|
9
|
-
const { getTaskManifestPath } = require('../store');
|
|
9
|
+
const { getTaskManifestPath, getHarnessStatePath, exists, readText, readJson, writeJson } = require('../store');
|
|
10
|
+
const path = require('path');
|
|
11
|
+
const { execSync } = require('child_process');
|
|
10
12
|
|
|
11
13
|
async function runPlan({ repoRoot, changeId, goal, overwrite }) {
|
|
14
|
+
// v4.3: 检查是否存在 proposal.md(新架构)
|
|
15
|
+
const reqDir = path.join(repoRoot, 'devflow', 'requirements', changeId);
|
|
16
|
+
const proposalPath = path.join(reqDir, 'proposal.md');
|
|
17
|
+
const hasProposal = await exists(proposalPath);
|
|
18
|
+
|
|
19
|
+
if (hasProposal) {
|
|
20
|
+
console.log(`[v4.3] Detected proposal.md, generating design.md and Delta specs...`);
|
|
21
|
+
|
|
22
|
+
// 注意:实际的 design.md 和 Delta specs 生成由 Claude Agent 在 /flow:spec 中完成
|
|
23
|
+
// 这里只是检测并提示,不执行生成逻辑
|
|
24
|
+
// 生成逻辑在 .claude/skills/flow-spec/SKILL.md 的 Execution Steps 中定义
|
|
25
|
+
|
|
26
|
+
const designPath = path.join(reqDir, 'design.md');
|
|
27
|
+
const specsDir = path.join(reqDir, 'specs');
|
|
28
|
+
const scopeReportPath = path.join(reqDir, 'scope-creep-report.md');
|
|
29
|
+
|
|
30
|
+
// 检查必需产物是否存在
|
|
31
|
+
const hasDesign = await exists(designPath);
|
|
32
|
+
const hasSpecs = await exists(specsDir);
|
|
33
|
+
const hasScopeReport = await exists(scopeReportPath);
|
|
34
|
+
|
|
35
|
+
if (!hasDesign) {
|
|
36
|
+
console.warn(`[v4.3] WARNING: design.md not found. Expected at ${designPath}`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (!hasSpecs) {
|
|
40
|
+
console.warn(`[v4.3] WARNING: specs/ directory not found. Expected at ${specsDir}`);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (!hasScopeReport) {
|
|
44
|
+
console.warn(`[v4.3] WARNING: scope-creep-report.md not found. Run validate-scope.sh`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// 如果存在 scope-creep-report.md,检查是否有阻塞性警告
|
|
48
|
+
if (hasScopeReport) {
|
|
49
|
+
const reportContent = await readText(scopeReportPath);
|
|
50
|
+
if (reportContent.includes('⚠️') && reportContent.includes('Potential scope creep')) {
|
|
51
|
+
console.warn(`[v4.3] WARNING: Scope creep detected. Review ${scopeReportPath}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
12
56
|
const manifest = await createTaskManifest({
|
|
13
57
|
repoRoot,
|
|
14
58
|
changeId,
|
|
@@ -16,6 +60,16 @@ async function runPlan({ repoRoot, changeId, goal, overwrite }) {
|
|
|
16
60
|
overwrite
|
|
17
61
|
});
|
|
18
62
|
|
|
63
|
+
// Update harness-state.json with plannedAt timestamp
|
|
64
|
+
const statePath = getHarnessStatePath(repoRoot, changeId);
|
|
65
|
+
if (await exists(statePath)) {
|
|
66
|
+
const state = await readJson(statePath);
|
|
67
|
+
state.status = 'planned';
|
|
68
|
+
state.plannedAt = new Date().toISOString();
|
|
69
|
+
state.updatedAt = new Date().toISOString();
|
|
70
|
+
await writeJson(statePath, state);
|
|
71
|
+
}
|
|
72
|
+
|
|
19
73
|
return {
|
|
20
74
|
changeId,
|
|
21
75
|
manifestPath: getTaskManifestPath(repoRoot, changeId),
|
|
@@ -10,12 +10,16 @@ const {
|
|
|
10
10
|
readJson,
|
|
11
11
|
writeText,
|
|
12
12
|
writeJson,
|
|
13
|
+
exists,
|
|
13
14
|
getReportCardPath,
|
|
14
15
|
getTaskManifestPath,
|
|
15
16
|
getReleaseNotePath,
|
|
16
17
|
getHarnessStatePath
|
|
17
18
|
} = require('../store');
|
|
18
19
|
const { parseReportCard, parseManifest } = require('../schemas');
|
|
20
|
+
const path = require('path');
|
|
21
|
+
const { execSync } = require('child_process');
|
|
22
|
+
const fs = require('fs').promises;
|
|
19
23
|
|
|
20
24
|
function formatReleaseNote({ changeId, manifest, report }) {
|
|
21
25
|
const passedTasks = manifest.tasks.filter((task) => task.status === 'passed');
|
|
@@ -59,6 +63,89 @@ async function runRelease({ repoRoot, changeId }) {
|
|
|
59
63
|
throw new Error('Release blocked: report-card overall is not pass');
|
|
60
64
|
}
|
|
61
65
|
|
|
66
|
+
// v4.3: 合并 Delta specs 到项目级 specs/
|
|
67
|
+
const reqDir = path.join(repoRoot, 'devflow', 'requirements', changeId);
|
|
68
|
+
const deltaSpecsDir = path.join(reqDir, 'specs');
|
|
69
|
+
const projectSpecsDir = path.join(repoRoot, 'devflow', 'specs');
|
|
70
|
+
const hasDeltaSpecs = await exists(deltaSpecsDir);
|
|
71
|
+
|
|
72
|
+
if (hasDeltaSpecs) {
|
|
73
|
+
console.log(`[v4.3] Merging Delta specs to project-level specs/...`);
|
|
74
|
+
|
|
75
|
+
try {
|
|
76
|
+
// 遍历所有 Delta spec.md 文件
|
|
77
|
+
const modules = await fs.readdir(deltaSpecsDir);
|
|
78
|
+
const mergeResults = [];
|
|
79
|
+
|
|
80
|
+
for (const module of modules) {
|
|
81
|
+
const deltaSpecPath = path.join(deltaSpecsDir, module, 'spec.md');
|
|
82
|
+
const projectSpecPath = path.join(projectSpecsDir, module, 'spec.md');
|
|
83
|
+
|
|
84
|
+
if (!(await exists(deltaSpecPath))) {
|
|
85
|
+
console.warn(`[v4.3] WARNING: Delta spec not found: ${deltaSpecPath}`);
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (!(await exists(projectSpecPath))) {
|
|
90
|
+
console.warn(`[v4.3] WARNING: Project spec not found: ${projectSpecPath}`);
|
|
91
|
+
console.log(`[v4.3] Creating new project spec for module: ${module}`);
|
|
92
|
+
|
|
93
|
+
// 如果项目级 spec 不存在,创建目录并复制 Delta 作为初始版本
|
|
94
|
+
await fs.mkdir(path.dirname(projectSpecPath), { recursive: true });
|
|
95
|
+
await fs.copyFile(deltaSpecPath, projectSpecPath);
|
|
96
|
+
|
|
97
|
+
mergeResults.push({ module, status: 'created', newVersion: '1.0.0' });
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// 调用 delta-parser.ts merge 命令
|
|
102
|
+
const deltaParserPath = path.join(repoRoot, '.claude', 'scripts', 'delta-parser.ts');
|
|
103
|
+
|
|
104
|
+
try {
|
|
105
|
+
const output = execSync(
|
|
106
|
+
`npx ts-node "${deltaParserPath}" merge "${projectSpecPath}" "${deltaSpecPath}"`,
|
|
107
|
+
{ cwd: repoRoot, encoding: 'utf-8' }
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
// 解析输出获取新版本号
|
|
111
|
+
const versionMatch = output.match(/New version: ([\d.]+)/);
|
|
112
|
+
const newVersion = versionMatch ? versionMatch[1] : 'unknown';
|
|
113
|
+
|
|
114
|
+
mergeResults.push({ module, status: 'merged', newVersion });
|
|
115
|
+
console.log(`[v4.3] ✅ Merged ${module}: ${newVersion}`);
|
|
116
|
+
} catch (mergeError) {
|
|
117
|
+
console.error(`[v4.3] ❌ Failed to merge ${module}:`, mergeError.message);
|
|
118
|
+
mergeResults.push({ module, status: 'failed', error: mergeError.message });
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// 记录合并结果到 RELEASE_NOTE
|
|
123
|
+
const mergeReport = mergeResults
|
|
124
|
+
.map(r => {
|
|
125
|
+
if (r.status === 'merged') {
|
|
126
|
+
return `- ✅ ${r.module}: merged to v${r.newVersion}`;
|
|
127
|
+
} else if (r.status === 'created') {
|
|
128
|
+
return `- 🆕 ${r.module}: created v${r.newVersion}`;
|
|
129
|
+
} else {
|
|
130
|
+
return `- ❌ ${r.module}: ${r.error}`;
|
|
131
|
+
}
|
|
132
|
+
})
|
|
133
|
+
.join('\n');
|
|
134
|
+
|
|
135
|
+
console.log(`[v4.3] Delta merge summary:\n${mergeReport}`);
|
|
136
|
+
|
|
137
|
+
// 将合并结果添加到 release note
|
|
138
|
+
manifest.metadata = manifest.metadata || {};
|
|
139
|
+
manifest.metadata.deltaMergeResults = mergeResults;
|
|
140
|
+
|
|
141
|
+
} catch (error) {
|
|
142
|
+
console.error(`[v4.3] ERROR during Delta merge:`, error);
|
|
143
|
+
throw new Error(`Delta merge failed: ${error.message}`);
|
|
144
|
+
}
|
|
145
|
+
} else {
|
|
146
|
+
console.log(`[v4.3] No Delta specs found, skipping merge.`);
|
|
147
|
+
}
|
|
148
|
+
|
|
62
149
|
const note = formatReleaseNote({ changeId, manifest, report });
|
|
63
150
|
const releaseNotePath = getReleaseNotePath(repoRoot, changeId);
|
|
64
151
|
|
|
@@ -12,6 +12,7 @@ const {
|
|
|
12
12
|
writeJson,
|
|
13
13
|
runCommand,
|
|
14
14
|
getTaskManifestPath,
|
|
15
|
+
getHarnessStatePath,
|
|
15
16
|
getReportCardPath
|
|
16
17
|
} = require('../store');
|
|
17
18
|
const { parseManifest, parseReportCard } = require('../schemas');
|
|
@@ -150,6 +151,19 @@ async function runVerify({ repoRoot, changeId, strict = false, skipReview = fals
|
|
|
150
151
|
const outputPath = getReportCardPath(repoRoot, changeId);
|
|
151
152
|
await writeJson(outputPath, report);
|
|
152
153
|
|
|
154
|
+
// Update harness-state.json with verifiedAt timestamp if passed
|
|
155
|
+
if (!hasFailures) {
|
|
156
|
+
const statePath = getHarnessStatePath(repoRoot, changeId);
|
|
157
|
+
const stateExists = require('fs').existsSync(statePath);
|
|
158
|
+
if (stateExists) {
|
|
159
|
+
const state = await readJson(statePath);
|
|
160
|
+
state.status = 'verified';
|
|
161
|
+
state.verifiedAt = nowIso();
|
|
162
|
+
state.updatedAt = nowIso();
|
|
163
|
+
await writeJson(statePath, state);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
153
167
|
return {
|
|
154
168
|
changeId,
|
|
155
169
|
outputPath,
|