cc-devflow 4.5.10 → 4.5.12

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.
Files changed (187) hide show
  1. package/.claude/skills/cc-act/CHANGELOG.md +23 -0
  2. package/.claude/skills/cc-act/PLAYBOOK.md +17 -269
  3. package/.claude/skills/cc-act/SKILL.md +38 -418
  4. package/.claude/skills/cc-act/assets/PROJECT_POSTMORTEM_INDEX_TEMPLATE.md +2 -13
  5. package/.claude/skills/cc-act/assets/PROJECT_POSTMORTEM_TEMPLATE.md +1 -9
  6. package/.claude/skills/cc-act/assets/PR_BRIEF_TEMPLATE.md +21 -177
  7. package/.claude/skills/cc-act/references/closure-contract.md +12 -63
  8. package/.claude/skills/cc-act/references/git-commit-guidelines.md +5 -5
  9. package/.claude/skills/cc-act/scripts/cc-act-common.sh +5 -322
  10. package/.claude/skills/cc-act/scripts/detect-ship-target.sh +11 -2
  11. package/.claude/skills/cc-act/scripts/inspect-git-index.sh +58 -0
  12. package/.claude/skills/cc-act/scripts/render-pr-brief.sh +40 -440
  13. package/.claude/skills/cc-act/scripts/verify-act-gate.sh +10 -50
  14. package/.claude/skills/cc-check/CHANGELOG.md +24 -0
  15. package/.claude/skills/cc-check/PLAYBOOK.md +19 -273
  16. package/.claude/skills/cc-check/SKILL.md +33 -454
  17. package/.claude/skills/cc-check/references/review-contract.md +12 -147
  18. package/.claude/skills/cc-dev/CHANGELOG.md +20 -0
  19. package/.claude/skills/cc-dev/PLAYBOOK.md +1 -1
  20. package/.claude/skills/cc-dev/SKILL.md +52 -130
  21. package/.claude/skills/cc-dev/scripts/resolve-cc-devflow.sh +181 -0
  22. package/.claude/skills/cc-do/CHANGELOG.md +17 -0
  23. package/.claude/skills/cc-do/PLAYBOOK.md +19 -113
  24. package/.claude/skills/cc-do/SKILL.md +39 -236
  25. package/.claude/skills/cc-do/references/execution-recovery.md +15 -109
  26. package/.claude/skills/cc-do/scripts/cc-do-common.sh +5 -57
  27. package/.claude/skills/cc-do/scripts/check-task-status.sh +35 -65
  28. package/.claude/skills/cc-do/scripts/mark-task-complete.sh +9 -46
  29. package/.claude/skills/cc-do/scripts/select-ready-tasks.sh +29 -97
  30. package/.claude/skills/cc-investigate/CHANGELOG.md +23 -0
  31. package/.claude/skills/cc-investigate/PLAYBOOK.md +20 -180
  32. package/.claude/skills/cc-investigate/SKILL.md +65 -513
  33. package/.claude/skills/cc-investigate/assets/TASKS_TEMPLATE.md +48 -95
  34. package/.claude/skills/cc-investigate/references/investigation-contract.md +14 -217
  35. package/.claude/skills/cc-next/CHANGELOG.md +6 -0
  36. package/.claude/skills/cc-next/PLAYBOOK.md +12 -8
  37. package/.claude/skills/cc-next/SKILL.md +34 -140
  38. package/.claude/skills/cc-plan/CHANGELOG.md +29 -0
  39. package/.claude/skills/cc-plan/PLAYBOOK.md +22 -161
  40. package/.claude/skills/cc-plan/SKILL.md +47 -640
  41. package/.claude/skills/cc-plan/assets/TASKS_TEMPLATE.md +30 -225
  42. package/.claude/skills/cc-plan/references/planning-contract.md +24 -160
  43. package/.claude/skills/cc-plan/scripts/next-change-key.sh +8 -44
  44. package/.claude/skills/cc-plan/scripts/parse-task-dependencies.js +2 -2
  45. package/.claude/skills/cc-plan/scripts/validate-scope.sh +1 -1
  46. package/.claude/skills/cc-pr-land/SKILL.md +14 -114
  47. package/.claude/skills/cc-pr-review/CHANGELOG.md +4 -0
  48. package/.claude/skills/cc-pr-review/SKILL.md +20 -103
  49. package/.claude/skills/cc-review/CHANGELOG.md +17 -0
  50. package/.claude/skills/cc-review/PLAYBOOK.md +13 -86
  51. package/.claude/skills/cc-review/SKILL.md +53 -241
  52. package/.claude/skills/cc-review/references/e2e-and-plugin-verification.md +2 -2
  53. package/.claude/skills/cc-review/references/implementation-review-branch.md +7 -147
  54. package/.claude/skills/cc-review/references/plan-review-branch.md +5 -147
  55. package/.claude/skills/cc-review/references/review-methods.md +10 -218
  56. package/.claude/skills/cc-review/scripts/collect-review-context.sh +4 -63
  57. package/.claude/skills/cc-roadmap/PLAYBOOK.md +1 -1
  58. package/.claude/skills/cc-roadmap/SKILL.md +3 -3
  59. package/.claude/skills/cc-simplify/CHANGELOG.md +7 -0
  60. package/.claude/skills/cc-simplify/SKILL.md +26 -21
  61. package/.claude/skills/cc-spec-init/PLAYBOOK.md +12 -48
  62. package/.claude/skills/cc-spec-init/SKILL.md +29 -132
  63. package/.claude/skills/cc-spec-init/references/spec-contract.md +8 -17
  64. package/CHANGELOG.md +27 -0
  65. package/README.md +5 -3
  66. package/README.zh-CN.md +5 -3
  67. package/bin/cc-devflow-cli.js +20 -260
  68. package/bin/cc-devflow.js +44 -7
  69. package/docs/commands/README.md +1 -1
  70. package/docs/commands/README.zh-CN.md +1 -1
  71. package/docs/examples/README.md +1 -1
  72. package/docs/examples/START-HERE.md +14 -14
  73. package/docs/examples/example-bindings.json +11 -11
  74. package/docs/examples/full-design-blocked/README.md +4 -6
  75. package/docs/examples/full-design-blocked/changes/REQ-002-bulk-invite-import/{planning/tasks.md → task.md} +20 -15
  76. package/docs/examples/local-handoff/README.md +8 -11
  77. package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/handoff/pr-brief.md +31 -0
  78. package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/{planning/tasks.md → task.md} +18 -13
  79. package/docs/examples/pdca-loop/README.md +6 -9
  80. package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/handoff/pr-brief.md +9 -11
  81. package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/{planning/tasks.md → task.md} +18 -13
  82. package/docs/examples/scripts/check-example-bindings.sh +11 -62
  83. package/docs/guides/artifact-contract.md +10 -36
  84. package/docs/guides/getting-started.md +8 -7
  85. package/docs/guides/getting-started.zh-CN.md +8 -7
  86. package/docs/guides/minimize-artifacts.md +16 -116
  87. package/docs/guides/project-postmortem.md +14 -71
  88. package/lib/compiler/__tests__/skills-registry.test.js +9 -8
  89. package/lib/compiler/resource-copier.js +29 -0
  90. package/lib/skill-runtime/__tests__/archive-change.test.js +2 -2
  91. package/lib/skill-runtime/__tests__/benchmark-skills.test.js +109 -0
  92. package/lib/skill-runtime/__tests__/cli-bootstrap.integration.test.js +14 -4
  93. package/lib/skill-runtime/errors.js +3 -3
  94. package/lib/skill-runtime/index.js +5 -23
  95. package/lib/skill-runtime/paths.js +5 -52
  96. package/lib/skill-runtime/query-registry.js +4 -4
  97. package/lib/skill-runtime/query.js +89 -201
  98. package/lib/skill-runtime/store.js +4 -40
  99. package/lib/skill-runtime/trace.js +2 -2
  100. package/package.json +5 -7
  101. package/.claude/skills/cc-act/assets/PROJECT_POSTMORTEM_PRINCIPLES_TEMPLATE.md +0 -29
  102. package/.claude/skills/cc-act/assets/RELEASE_NOTE_TEMPLATE.md +0 -54
  103. package/.claude/skills/cc-act/scripts/generate-status-report.sh +0 -92
  104. package/.claude/skills/cc-act/scripts/sync-act-docs.sh +0 -355
  105. package/.claude/skills/cc-check/assets/REPORT_CARD_TEMPLATE.json +0 -234
  106. package/.claude/skills/cc-check/scripts/render-report-card.js +0 -438
  107. package/.claude/skills/cc-check/scripts/verify-gate.sh +0 -85
  108. package/.claude/skills/cc-do/scripts/build-task-context.sh +0 -175
  109. package/.claude/skills/cc-do/scripts/record-review-decision.sh +0 -88
  110. package/.claude/skills/cc-do/scripts/recover-workflow.sh +0 -82
  111. package/.claude/skills/cc-do/scripts/run-problem-analysis.sh +0 -70
  112. package/.claude/skills/cc-do/scripts/verify-task-gates.sh +0 -109
  113. package/.claude/skills/cc-do/scripts/write-task-checkpoint.sh +0 -92
  114. package/.claude/skills/cc-investigate/assets/TASK_MANIFEST_TEMPLATE.json +0 -225
  115. package/.claude/skills/cc-plan/assets/TASK_MANIFEST_TEMPLATE.json +0 -179
  116. package/.claude/skills/cc-spec-init/assets/CHANGE_META_TEMPLATE.json +0 -28
  117. package/.claude/skills/cc-spec-init/scripts/validate-spec-links.sh +0 -45
  118. package/docs/examples/full-design-blocked/changes/REQ-002-bulk-invite-import/planning/design.md +0 -234
  119. package/docs/examples/full-design-blocked/changes/REQ-002-bulk-invite-import/planning/task-manifest.json +0 -488
  120. package/docs/examples/full-design-blocked/changes/REQ-002-bulk-invite-import/review/report-card.json +0 -189
  121. package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/handoff/resume-index.md +0 -39
  122. package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/handoff/status.md +0 -29
  123. package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/planning/design.md +0 -123
  124. package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/planning/task-manifest.json +0 -292
  125. package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/review/report-card.json +0 -136
  126. package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/handoff/status.md +0 -29
  127. package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/planning/design.md +0 -124
  128. package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/planning/task-manifest.json +0 -292
  129. package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/review/report-card.json +0 -136
  130. package/docs/get-shit-done-strategy-audit.md +0 -518
  131. package/docs/skill-runtime-migration.md +0 -46
  132. package/lib/skill-runtime/__tests__/approve.test.js +0 -92
  133. package/lib/skill-runtime/__tests__/autopilot.test.js +0 -253
  134. package/lib/skill-runtime/__tests__/benchmark-artifacts.test.js +0 -165
  135. package/lib/skill-runtime/__tests__/delegation.test.js +0 -97
  136. package/lib/skill-runtime/__tests__/dispatch.test.js +0 -237
  137. package/lib/skill-runtime/__tests__/intent.test.js +0 -203
  138. package/lib/skill-runtime/__tests__/lifecycle.test.js +0 -169
  139. package/lib/skill-runtime/__tests__/planner.tdd.test.js +0 -331
  140. package/lib/skill-runtime/__tests__/prepare-pr.test.js +0 -126
  141. package/lib/skill-runtime/__tests__/query.test.js +0 -860
  142. package/lib/skill-runtime/__tests__/readiness.test.js +0 -53
  143. package/lib/skill-runtime/__tests__/release.test.js +0 -85
  144. package/lib/skill-runtime/__tests__/review-check-integration.test.js +0 -148
  145. package/lib/skill-runtime/__tests__/review-records.test.js +0 -619
  146. package/lib/skill-runtime/__tests__/runtime.integration.test.js +0 -351
  147. package/lib/skill-runtime/__tests__/schemas.test.js +0 -337
  148. package/lib/skill-runtime/__tests__/task-contract-migrate.test.js +0 -137
  149. package/lib/skill-runtime/__tests__/task-contract.test.js +0 -783
  150. package/lib/skill-runtime/__tests__/team-state.test.js +0 -51
  151. package/lib/skill-runtime/__tests__/verify-artifacts.test.js +0 -203
  152. package/lib/skill-runtime/__tests__/worker-run.test.js +0 -275
  153. package/lib/skill-runtime/__tests__/worker.test.js +0 -56
  154. package/lib/skill-runtime/__tests__/workflow-context-legacy-fallback.test.js +0 -31
  155. package/lib/skill-runtime/__tests__/workflow-context.test.js +0 -98
  156. package/lib/skill-runtime/artifacts.js +0 -88
  157. package/lib/skill-runtime/context-index.js +0 -545
  158. package/lib/skill-runtime/delegation.js +0 -533
  159. package/lib/skill-runtime/intent.js +0 -309
  160. package/lib/skill-runtime/lifecycle.js +0 -294
  161. package/lib/skill-runtime/operations/CLAUDE.md +0 -19
  162. package/lib/skill-runtime/operations/approve.js +0 -81
  163. package/lib/skill-runtime/operations/autopilot-core.js +0 -337
  164. package/lib/skill-runtime/operations/autopilot-execution.js +0 -307
  165. package/lib/skill-runtime/operations/autopilot-shared.js +0 -48
  166. package/lib/skill-runtime/operations/autopilot.js +0 -163
  167. package/lib/skill-runtime/operations/dispatch.js +0 -416
  168. package/lib/skill-runtime/operations/init.js +0 -60
  169. package/lib/skill-runtime/operations/janitor.js +0 -61
  170. package/lib/skill-runtime/operations/plan.js +0 -59
  171. package/lib/skill-runtime/operations/prepare-pr.js +0 -25
  172. package/lib/skill-runtime/operations/release.js +0 -99
  173. package/lib/skill-runtime/operations/resume.js +0 -126
  174. package/lib/skill-runtime/operations/review-records.js +0 -265
  175. package/lib/skill-runtime/operations/snapshot.js +0 -45
  176. package/lib/skill-runtime/operations/task-contract.js +0 -524
  177. package/lib/skill-runtime/operations/verify.js +0 -170
  178. package/lib/skill-runtime/operations/worker-run.js +0 -531
  179. package/lib/skill-runtime/operations/worker.js +0 -33
  180. package/lib/skill-runtime/planner.js +0 -539
  181. package/lib/skill-runtime/readiness.js +0 -84
  182. package/lib/skill-runtime/review-records.js +0 -123
  183. package/lib/skill-runtime/review.js +0 -855
  184. package/lib/skill-runtime/schemas.js +0 -746
  185. package/lib/skill-runtime/task-contract.js +0 -187
  186. package/lib/skill-runtime/team-state.js +0 -122
  187. package/lib/skill-runtime/workflow-context.js +0 -748
@@ -1,351 +0,0 @@
1
- /**
2
- * [INPUT]: 依赖 skill runtime operations 与临时仓库夹具。
3
- * [OUTPUT]: 验证 plan/do/check/act 共享运行时主链最小可运行性。
4
- * [POS]: lib/skill-runtime/__tests__ 的集成测试入口,保障 skill-first 内核回归。
5
- * [PROTOCOL]: 变更时更新此头部,然后检查 CLAUDE.md
6
- */
7
-
8
- const fs = require('fs');
9
- const os = require('os');
10
- const path = require('path');
11
- const { spawnSync } = require('child_process');
12
-
13
- const REPO_ROOT = path.resolve(__dirname, '../../..');
14
-
15
- const { runInit } = require('../operations/init');
16
- const { runPlanningSnapshot } = require('../operations/snapshot');
17
- const { runPlan } = require('../operations/plan');
18
- const { runApprove } = require('../operations/approve');
19
- const { runDispatch } = require('../operations/dispatch');
20
- const { runVerify } = require('../operations/verify');
21
- const { runRelease } = require('../operations/release');
22
- const {
23
- getTaskManifestPath,
24
- getReportCardPath,
25
- getReleaseNotePath,
26
- getTasksMarkdownPath,
27
- readJson,
28
- readText
29
- } = require('../store');
30
- const { getChangePaths } = require('../paths');
31
-
32
- const WRITE_TASK_CHECKPOINT = path.join(
33
- REPO_ROOT,
34
- '.claude/skills/cc-do/scripts/write-task-checkpoint.sh'
35
- );
36
- const RECORD_REVIEW_DECISION = path.join(
37
- REPO_ROOT,
38
- '.claude/skills/cc-do/scripts/record-review-decision.sh'
39
- );
40
- const VERIFY_TASK_GATES = path.join(
41
- REPO_ROOT,
42
- '.claude/skills/cc-do/scripts/verify-task-gates.sh'
43
- );
44
- const MARK_TASK_COMPLETE = path.join(
45
- REPO_ROOT,
46
- '.claude/skills/cc-do/scripts/mark-task-complete.sh'
47
- );
48
-
49
- jest.setTimeout(20000);
50
-
51
- describe('Skill runtime', () => {
52
- let repoRoot;
53
-
54
- beforeEach(() => {
55
- repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'skill-runtime-'));
56
-
57
- fs.writeFileSync(
58
- path.join(repoRoot, 'package.json'),
59
- JSON.stringify(
60
- {
61
- name: 'tmp-repo',
62
- version: '0.0.0',
63
- scripts: {
64
- lint: 'node -e "process.exit(0)"',
65
- typecheck: 'node -e "process.exit(0)"',
66
- test: 'node -e "process.exit(0)"'
67
- }
68
- },
69
- null,
70
- 2
71
- )
72
- );
73
-
74
- fs.mkdirSync(path.join(repoRoot, '.git'));
75
- });
76
-
77
- afterEach(() => {
78
- fs.rmSync(repoRoot, { recursive: true, force: true });
79
- });
80
-
81
- async function markManifestReviews(changeId, verdict = 'pass') {
82
- const manifestPath = getTaskManifestPath(repoRoot, changeId);
83
- const manifest = await readJson(manifestPath);
84
- manifest.tasks = manifest.tasks.map((task) => ({
85
- ...task,
86
- reviews: {
87
- spec: verdict,
88
- code: verdict
89
- }
90
- }));
91
- fs.writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`);
92
- }
93
-
94
- async function markManifestSpec(changeId) {
95
- const manifestPath = getTaskManifestPath(repoRoot, changeId);
96
- const manifest = await readJson(manifestPath);
97
- manifest.spec = {
98
- primaryCapability: 'skill-runtime-pipeline',
99
- specFiles: ['devflow/specs/skill-runtime.md']
100
- };
101
- fs.writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`);
102
- }
103
-
104
- function writeCleanReviewLedger(changeId) {
105
- const change = getChangePaths(repoRoot, changeId);
106
- const ledgerPath = path.join(change.reviewDir, 'review-ledger.jsonl');
107
- fs.mkdirSync(path.dirname(ledgerPath), { recursive: true });
108
- fs.writeFileSync(ledgerPath, [
109
- JSON.stringify({
110
- schema: 'review-ledger.v2',
111
- change: change.changeKey,
112
- reviewId: 'RVW-20260512-001',
113
- createdAt: '2026-05-12T00:00:00.000Z',
114
- createdBy: 'cc-devflow-cli',
115
- event: 'review-started',
116
- mode: 'implementation',
117
- scope: 'current-diff',
118
- baseSha: 'abc123',
119
- headSha: 'def456',
120
- selectedNodes: [],
121
- skippedNodes: [],
122
- riskLanes: []
123
- }),
124
- JSON.stringify({
125
- schema: 'review-ledger.v2',
126
- change: change.changeKey,
127
- reviewId: 'RVW-20260512-001',
128
- createdAt: '2026-05-12T00:01:00.000Z',
129
- createdBy: 'cc-devflow-cli',
130
- event: 'review-closed',
131
- status: 'clean',
132
- blockingCount: 0,
133
- warningCount: 0,
134
- next: 'cc-check'
135
- })
136
- ].join('\n'));
137
- }
138
-
139
- test('runs init -> snapshot -> plan -> dispatch -> verify -> release', async () => {
140
- const changeId = 'REQ-999';
141
- await runInit({ repoRoot, changeId, goal: 'Test skill runtime pipeline' });
142
-
143
- fs.writeFileSync(
144
- getTasksMarkdownPath(repoRoot, changeId),
145
- [
146
- '- [ ] T001 create scaffolding (src/a.ts)',
147
- '- [ ] T002 [P] add docs (docs/readme.md)',
148
- '- [ ] T003 finalize dependsOn:T001,T002 (src/b.ts)'
149
- ].join('\n')
150
- );
151
-
152
- await runPlanningSnapshot({ repoRoot, changeId });
153
-
154
- const planResult = await runPlan({ repoRoot, changeId, overwrite: true });
155
- expect(planResult.taskCount).toBe(3);
156
- await runApprove({ repoRoot, changeId, executionMode: 'direct' });
157
-
158
- const dispatchResult = await runDispatch({
159
- repoRoot,
160
- changeId,
161
- parallel: 2,
162
- maxRetries: 0
163
- });
164
- expect(dispatchResult.success).toBe(true);
165
-
166
- const manifest = await readJson(getTaskManifestPath(repoRoot, changeId));
167
- expect(manifest.tasks.every((task) => task.status === 'passed')).toBe(true);
168
-
169
- await markManifestSpec(changeId);
170
- await markManifestReviews(changeId, 'pass');
171
- writeCleanReviewLedger(changeId);
172
-
173
- const verifyResult = await runVerify({
174
- repoRoot,
175
- changeId,
176
- strict: false,
177
- skipReview: true
178
- });
179
- expect(verifyResult.overall).toBe('pass');
180
-
181
- const report = await readJson(getReportCardPath(repoRoot, changeId));
182
- expect(report.overall).toBe('pass');
183
- const requirementsMet = report.claimEvidence.find((claim) => claim.claim === 'requirements-met');
184
- expect(requirementsMet).toMatchObject({
185
- status: 'pass',
186
- keyObservation: 'no open task gaps recorded'
187
- });
188
-
189
- const releaseResult = await runRelease({ repoRoot, changeId });
190
- expect(releaseResult.status).toBe('released');
191
-
192
- const releaseNote = await readText(getReleaseNotePath(repoRoot, changeId));
193
- expect(releaseNote).toContain('Release Note - REQ-999');
194
- });
195
-
196
- test('blocks verify when passed tasks are missing native review proof', async () => {
197
- const changeId = 'REQ-1000';
198
- await runInit({ repoRoot, changeId, goal: 'Require task review proof' });
199
-
200
- fs.writeFileSync(
201
- getTasksMarkdownPath(repoRoot, changeId),
202
- [
203
- '- [ ] T001 [TEST] Counter behavior (src/a.test.ts)',
204
- '- [ ] T002 [IMPL] Counter behavior dependsOn:T001 (src/a.ts)'
205
- ].join('\n')
206
- );
207
-
208
- await runPlanningSnapshot({ repoRoot, changeId });
209
- await runPlan({ repoRoot, changeId, overwrite: true });
210
- await runApprove({ repoRoot, changeId, executionMode: 'direct' });
211
- await runDispatch({ repoRoot, changeId, parallel: 1, maxRetries: 0 });
212
-
213
- const verifyResult = await runVerify({
214
- repoRoot,
215
- changeId,
216
- strict: false,
217
- skipReview: true
218
- });
219
-
220
- expect(verifyResult.overall).toBe('fail');
221
-
222
- const report = await readJson(getReportCardPath(repoRoot, changeId));
223
- expect(report.review.status).toBe('blocked');
224
- expect(report.blockingFindings.some((item) => item.includes('missing spec review proof'))).toBe(true);
225
- });
226
-
227
- test('cc-do shell helpers keep task truth in manifest and do not write process files by default', async () => {
228
- const changeId = 'REQ-2001';
229
- await runInit({ repoRoot, changeId, goal: 'Verify shell helper layout' });
230
-
231
- const change = getChangePaths(repoRoot, changeId, { goal: 'Verify shell helper layout' });
232
- const manifestPath = getTaskManifestPath(repoRoot, changeId, { goal: 'Verify shell helper layout' });
233
- fs.writeFileSync(
234
- manifestPath,
235
- `${JSON.stringify(
236
- {
237
- changeId,
238
- tasks: [
239
- {
240
- id: 'T001',
241
- title: 'Verify helper layout',
242
- reviews: { spec: 'pending', code: 'pending' }
243
- }
244
- ]
245
- },
246
- null,
247
- 2
248
- )}\n`
249
- );
250
-
251
- const legacyCheckpoint = spawnSync(WRITE_TASK_CHECKPOINT, [
252
- '--dir',
253
- change.changeDir,
254
- '--task',
255
- 'T001',
256
- '--status',
257
- 'passed',
258
- '--summary',
259
- 'task finished'
260
- ], { encoding: 'utf8' });
261
- expect(legacyCheckpoint.status).toBe(0);
262
-
263
- const specReview = spawnSync(RECORD_REVIEW_DECISION, [
264
- '--dir',
265
- change.changeDir,
266
- '--task',
267
- 'T001',
268
- '--gate',
269
- 'spec',
270
- '--verdict',
271
- 'pass',
272
- '--summary',
273
- 'spec ok'
274
- ], { encoding: 'utf8' });
275
- expect(specReview.status).toBe(0);
276
-
277
- const codeReview = spawnSync(RECORD_REVIEW_DECISION, [
278
- '--dir',
279
- change.changeDir,
280
- '--task',
281
- 'T001',
282
- '--gate',
283
- 'code',
284
- '--verdict',
285
- 'pass',
286
- '--summary',
287
- 'code ok'
288
- ], { encoding: 'utf8' });
289
- expect(codeReview.status).toBe(0);
290
-
291
- const verify = spawnSync(VERIFY_TASK_GATES, [
292
- '--dir',
293
- change.changeDir,
294
- '--task',
295
- 'T001'
296
- ], { encoding: 'utf8' });
297
- expect(verify.status).toBe(0);
298
-
299
- const complete = spawnSync(MARK_TASK_COMPLETE, [
300
- '--manifest',
301
- manifestPath,
302
- '--task',
303
- 'T001'
304
- ], { encoding: 'utf8' });
305
- expect(complete.status).toBe(0);
306
-
307
- const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
308
- expect(manifest.currentTaskId).toBeNull();
309
- expect(manifest.tasks[0]).toMatchObject({
310
- id: 'T001',
311
- status: 'passed',
312
- reviews: { spec: 'pass', code: 'pass' }
313
- });
314
-
315
- expect(fs.existsSync(path.join(change.tasksDir, 'T001', 'checkpoint.json'))).toBe(false);
316
- expect(fs.existsSync(path.join(change.tasksDir, 'T001', 'context.md'))).toBe(false);
317
- expect(fs.existsSync(path.join(change.tasksDir, 'T001', 'events.jsonl'))).toBe(false);
318
- expect(fs.existsSync(path.join(repoRoot, '.harness', 'runtime', changeId))).toBe(false);
319
- expect(fs.existsSync(path.join(change.tasksDir, 'T001', 'checkpoint.md'))).toBe(false);
320
- expect(fs.existsSync(path.join(change.tasksDir, 'T001', 'review-spec.md'))).toBe(false);
321
- expect(fs.existsSync(path.join(change.tasksDir, 'T001', 'review-code.md'))).toBe(false);
322
- });
323
-
324
- test('mark-task-complete updates only the first matching task line on Darwin-compatible userlands', () => {
325
- const tasksPath = path.join(repoRoot, 'tasks.md');
326
- fs.writeFileSync(
327
- tasksPath,
328
- [
329
- '- [ ] **T001** first task',
330
- '- [ ] T001 second task',
331
- '- [ ] T002 untouched'
332
- ].join('\n')
333
- );
334
-
335
- const result = spawnSync(MARK_TASK_COMPLETE, [
336
- '--tasks',
337
- tasksPath,
338
- '--task',
339
- 'T001'
340
- ], { encoding: 'utf8' });
341
-
342
- expect(result.status).toBe(0);
343
- expect(fs.readFileSync(tasksPath, 'utf8').trimEnd()).toBe(
344
- [
345
- '- [x] **T001** first task',
346
- '- [ ] T001 second task',
347
- '- [ ] T002 untouched'
348
- ].join('\n')
349
- );
350
- });
351
- });
@@ -1,337 +0,0 @@
1
- const { parseManifest } = require('../schemas');
2
-
3
- describe('Manifest schema hard constraints', () => {
4
- test('accepts a tasks.md manifest with review and context metadata', () => {
5
- const manifest = parseManifest({
6
- changeId: 'REQ-555',
7
- goal: 'Validate schema contract',
8
- createdAt: '2026-04-10T01:00:00.000Z',
9
- updatedAt: '2026-04-10T01:05:00.000Z',
10
- currentTaskId: 'T001',
11
- tasks: [
12
- {
13
- id: 'T001',
14
- title: '[TEST] Counter behavior',
15
- type: 'TEST',
16
- phase: 1,
17
- parallel: false,
18
- dependsOn: [],
19
- touches: ['src/counter.test.ts'],
20
- files: ['src/counter.test.ts'],
21
- run: ['echo "[TASK T001] Counter behavior"'],
22
- checks: ['npm test -- src/counter.test.ts'],
23
- acceptance: ['Prove counter behavior fails first'],
24
- verification: ['npm test -- src/counter.test.ts'],
25
- evidence: ['failing test output'],
26
- context: {
27
- readFiles: ['design.md', 'tasks.md'],
28
- commands: ['npm test -- src/counter.test.ts'],
29
- notes: ['Start from red']
30
- },
31
- reviews: {
32
- spec: 'pending',
33
- code: 'pending'
34
- },
35
- status: 'pending',
36
- attempts: 0,
37
- maxRetries: 1
38
- },
39
- {
40
- id: 'T002',
41
- title: '[IMPL] Counter behavior',
42
- type: 'IMPL',
43
- phase: 1,
44
- parallel: false,
45
- dependsOn: ['T001'],
46
- touches: ['src/counter.ts'],
47
- files: ['src/counter.ts'],
48
- run: ['echo "[TASK T002] Counter behavior"'],
49
- checks: ['npm test -- src/counter.test.ts'],
50
- acceptance: ['Make counter behavior pass'],
51
- verification: ['npm test -- src/counter.test.ts'],
52
- evidence: ['passing test output'],
53
- context: {
54
- readFiles: ['design.md', 'src/counter.test.ts'],
55
- commands: ['npm test -- src/counter.test.ts'],
56
- notes: ['Smallest green implementation']
57
- },
58
- reviews: {
59
- spec: 'pending',
60
- code: 'pending'
61
- },
62
- status: 'pending',
63
- attempts: 0,
64
- maxRetries: 1
65
- }
66
- ],
67
- metadata: {
68
- source: 'tasks.md',
69
- generatedBy: 'test',
70
- planVersion: 1
71
- }
72
- });
73
-
74
- expect(manifest.currentTaskId).toBe('T001');
75
- expect(manifest.activePhase).toBeUndefined();
76
- });
77
-
78
- test('accepts legacy activePhase input without preserving the retired field', () => {
79
- const manifest = parseManifest({
80
- changeId: 'REQ-560',
81
- goal: 'Validate legacy manifest compatibility',
82
- createdAt: '2026-04-10T01:00:00.000Z',
83
- updatedAt: '2026-04-10T01:05:00.000Z',
84
- currentTaskId: 'T001',
85
- activePhase: 1,
86
- tasks: [
87
- {
88
- id: 'T001',
89
- title: '[TEST] Counter behavior',
90
- type: 'OTHER',
91
- phase: 1,
92
- dependsOn: [],
93
- run: ['echo ok'],
94
- status: 'pending',
95
- attempts: 0,
96
- maxRetries: 1
97
- }
98
- ],
99
- metadata: {
100
- source: 'default',
101
- generatedBy: 'test',
102
- planVersion: 1
103
- }
104
- });
105
-
106
- expect(manifest.currentTaskId).toBe('T001');
107
- expect(manifest.activePhase).toBeUndefined();
108
- });
109
-
110
- test('rejects invalid currentTaskId for tasks.md manifest', () => {
111
- expect(() => parseManifest({
112
- changeId: 'REQ-556',
113
- goal: 'Reject invalid current task',
114
- createdAt: '2026-04-10T01:00:00.000Z',
115
- updatedAt: '2026-04-10T01:05:00.000Z',
116
- currentTaskId: 'T999',
117
- activePhase: 1,
118
- tasks: [
119
- {
120
- id: 'T001',
121
- title: '[TEST] Counter behavior',
122
- type: 'TEST',
123
- phase: 1,
124
- dependsOn: [],
125
- run: ['echo ok'],
126
- checks: ['npm test -- src/counter.test.ts'],
127
- acceptance: ['Prove failure'],
128
- verification: ['npm test -- src/counter.test.ts'],
129
- evidence: ['failing test output'],
130
- context: {
131
- readFiles: ['design.md'],
132
- commands: ['npm test -- src/counter.test.ts'],
133
- notes: []
134
- },
135
- reviews: {
136
- spec: 'pending',
137
- code: 'pending'
138
- },
139
- status: 'pending',
140
- attempts: 0,
141
- maxRetries: 1
142
- }
143
- ],
144
- metadata: {
145
- source: 'tasks.md',
146
- generatedBy: 'test',
147
- planVersion: 1
148
- }
149
- })).toThrow(/currentTaskId T999 is not present/);
150
- });
151
-
152
- test('accepts FIX ids and rejects legacy BUG ids', () => {
153
- const baseManifest = {
154
- goal: 'Validate fix id',
155
- createdAt: '2026-04-10T01:00:00.000Z',
156
- updatedAt: '2026-04-10T01:05:00.000Z',
157
- currentTaskId: 'T001',
158
- activePhase: 1,
159
- tasks: [
160
- {
161
- id: 'T001',
162
- title: 'Bootstrap fix',
163
- type: 'OTHER',
164
- phase: 1,
165
- dependsOn: [],
166
- run: ['echo ok'],
167
- status: 'pending',
168
- attempts: 0,
169
- maxRetries: 1
170
- }
171
- ],
172
- metadata: {
173
- source: 'default',
174
- generatedBy: 'test',
175
- planVersion: 1
176
- }
177
- };
178
-
179
- expect(parseManifest({ ...baseManifest, changeId: 'FIX-556' }).changeId).toBe('FIX-556');
180
- expect(() => parseManifest({ ...baseManifest, changeId: 'BUG-556' })).toThrow(/Invalid changeId format/);
181
- });
182
-
183
- test('accepts current full change keys and review/verification task types', () => {
184
- const manifest = parseManifest({
185
- changeId: 'REQ-001-personal-output-config',
186
- goal: 'Validate current manifest shape',
187
- createdAt: '2026-04-10T01:00:00.000Z',
188
- updatedAt: '2026-04-10T01:05:00.000Z',
189
- currentTaskId: 'T007',
190
- tasks: [
191
- {
192
- id: 'T007',
193
- title: '[REFACTOR] Apply review fixes',
194
- type: 'REFACTOR',
195
- phase: 4,
196
- dependsOn: [],
197
- run: ['echo ok'],
198
- status: 'pending',
199
- attempts: 0,
200
- maxRetries: 1
201
- },
202
- {
203
- id: 'T008',
204
- title: '[VERIFY] Run full gates',
205
- type: 'VERIFY',
206
- phase: 4,
207
- dependsOn: ['T007'],
208
- run: ['npm test'],
209
- status: 'pending',
210
- attempts: 0,
211
- maxRetries: 1
212
- }
213
- ],
214
- metadata: {
215
- source: 'planning/tasks.md',
216
- generatedBy: 'cc-plan',
217
- planVersion: 1
218
- }
219
- });
220
-
221
- expect(manifest.changeId).toBe('REQ-001-personal-output-config');
222
- expect(manifest.tasks.map((task) => task.type)).toEqual(['REFACTOR', 'VERIFY']);
223
- expect(manifest.metadata.source).toBe('planning/tasks.md');
224
- });
225
-
226
- test('rejects conflicting parallel tasks that share touches in same phase', () => {
227
- expect(() => parseManifest({
228
- changeId: 'REQ-557',
229
- goal: 'Reject bad parallel plan',
230
- createdAt: '2026-04-10T01:00:00.000Z',
231
- updatedAt: '2026-04-10T01:05:00.000Z',
232
- currentTaskId: 'T001',
233
- activePhase: 1,
234
- tasks: [
235
- {
236
- id: 'T001',
237
- title: '[TEST] A',
238
- type: 'TEST',
239
- phase: 1,
240
- parallel: true,
241
- dependsOn: [],
242
- touches: ['src/shared.ts'],
243
- run: ['echo ok'],
244
- checks: ['npm test -- a'],
245
- acceptance: ['Prove A fails'],
246
- verification: ['npm test -- a'],
247
- evidence: ['failing output'],
248
- context: { readFiles: ['design.md'], commands: ['npm test -- a'], notes: [] },
249
- reviews: { spec: 'pending', code: 'pending' },
250
- status: 'pending',
251
- attempts: 0,
252
- maxRetries: 1
253
- },
254
- {
255
- id: 'T002',
256
- title: '[TEST] B',
257
- type: 'TEST',
258
- phase: 1,
259
- parallel: true,
260
- dependsOn: [],
261
- touches: ['src/shared.ts'],
262
- run: ['echo ok'],
263
- checks: ['npm test -- b'],
264
- acceptance: ['Prove B fails'],
265
- verification: ['npm test -- b'],
266
- evidence: ['failing output'],
267
- context: { readFiles: ['design.md'], commands: ['npm test -- b'], notes: [] },
268
- reviews: { spec: 'pending', code: 'pending' },
269
- status: 'pending',
270
- attempts: 0,
271
- maxRetries: 1
272
- }
273
- ],
274
- metadata: {
275
- source: 'tasks.md',
276
- generatedBy: 'test',
277
- planVersion: 1
278
- }
279
- })).toThrow(/share touches/);
280
- });
281
-
282
- test('rejects conflicting parallel tasks with nested touches in same phase', () => {
283
- expect(() => parseManifest({
284
- changeId: 'REQ-558',
285
- goal: 'Reject nested parallel plan',
286
- createdAt: '2026-04-10T01:00:00.000Z',
287
- updatedAt: '2026-04-10T01:05:00.000Z',
288
- currentTaskId: 'T001',
289
- activePhase: 1,
290
- tasks: [
291
- {
292
- id: 'T001',
293
- title: '[TEST] A',
294
- type: 'TEST',
295
- phase: 1,
296
- parallel: true,
297
- dependsOn: [],
298
- touches: ['packages/billing'],
299
- run: ['echo ok'],
300
- checks: ['npm test -- a'],
301
- acceptance: ['Prove A fails'],
302
- verification: ['npm test -- a'],
303
- evidence: ['failing output'],
304
- context: { readFiles: ['design.md'], commands: ['npm test -- a'], notes: [] },
305
- reviews: { spec: 'pending', code: 'pending' },
306
- status: 'pending',
307
- attempts: 0,
308
- maxRetries: 1
309
- },
310
- {
311
- id: 'T002',
312
- title: '[TEST] B',
313
- type: 'TEST',
314
- phase: 1,
315
- parallel: true,
316
- dependsOn: [],
317
- touches: ['packages/billing/src/invoices.js'],
318
- run: ['echo ok'],
319
- checks: ['npm test -- b'],
320
- acceptance: ['Prove B fails'],
321
- verification: ['npm test -- b'],
322
- evidence: ['failing output'],
323
- context: { readFiles: ['design.md'], commands: ['npm test -- b'], notes: [] },
324
- reviews: { spec: 'pending', code: 'pending' },
325
- status: 'pending',
326
- attempts: 0,
327
- maxRetries: 1
328
- }
329
- ],
330
- metadata: {
331
- source: 'tasks.md',
332
- generatedBy: 'test',
333
- planVersion: 1
334
- }
335
- })).toThrow(/share touches: packages\/billing/);
336
- });
337
- });