cc-devflow 4.5.11 → 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 (185) hide show
  1. package/.claude/skills/cc-act/CHANGELOG.md +18 -0
  2. package/.claude/skills/cc-act/PLAYBOOK.md +17 -269
  3. package/.claude/skills/cc-act/SKILL.md +38 -425
  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 +18 -0
  15. package/.claude/skills/cc-check/PLAYBOOK.md +19 -273
  16. package/.claude/skills/cc-check/SKILL.md +33 -456
  17. package/.claude/skills/cc-check/references/review-contract.md +12 -147
  18. package/.claude/skills/cc-dev/CHANGELOG.md +15 -0
  19. package/.claude/skills/cc-dev/PLAYBOOK.md +1 -1
  20. package/.claude/skills/cc-dev/SKILL.md +52 -137
  21. package/.claude/skills/cc-dev/scripts/resolve-cc-devflow.sh +181 -0
  22. package/.claude/skills/cc-do/CHANGELOG.md +11 -0
  23. package/.claude/skills/cc-do/PLAYBOOK.md +19 -113
  24. package/.claude/skills/cc-do/SKILL.md +39 -245
  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 +16 -0
  31. package/.claude/skills/cc-investigate/PLAYBOOK.md +20 -180
  32. package/.claude/skills/cc-investigate/SKILL.md +64 -246
  33. package/.claude/skills/cc-investigate/assets/TASKS_TEMPLATE.md +48 -98
  34. package/.claude/skills/cc-investigate/references/investigation-contract.md +14 -218
  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 +16 -0
  39. package/.claude/skills/cc-plan/PLAYBOOK.md +22 -161
  40. package/.claude/skills/cc-plan/SKILL.md +45 -295
  41. package/.claude/skills/cc-plan/assets/TASKS_TEMPLATE.md +30 -228
  42. package/.claude/skills/cc-plan/references/planning-contract.md +24 -161
  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 +13 -0
  65. package/bin/cc-devflow-cli.js +20 -260
  66. package/bin/cc-devflow.js +44 -7
  67. package/docs/commands/README.md +1 -1
  68. package/docs/commands/README.zh-CN.md +1 -1
  69. package/docs/examples/README.md +1 -1
  70. package/docs/examples/START-HERE.md +14 -15
  71. package/docs/examples/example-bindings.json +11 -11
  72. package/docs/examples/full-design-blocked/README.md +4 -6
  73. package/docs/examples/full-design-blocked/changes/REQ-002-bulk-invite-import/{planning/tasks.md → task.md} +20 -15
  74. package/docs/examples/local-handoff/README.md +8 -11
  75. package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/handoff/pr-brief.md +31 -0
  76. package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/{planning/tasks.md → task.md} +18 -13
  77. package/docs/examples/pdca-loop/README.md +6 -9
  78. package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/handoff/pr-brief.md +9 -11
  79. package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/{planning/tasks.md → task.md} +18 -13
  80. package/docs/examples/scripts/check-example-bindings.sh +11 -62
  81. package/docs/guides/artifact-contract.md +10 -40
  82. package/docs/guides/getting-started.md +8 -8
  83. package/docs/guides/getting-started.zh-CN.md +8 -8
  84. package/docs/guides/minimize-artifacts.md +16 -130
  85. package/docs/guides/project-postmortem.md +14 -71
  86. package/lib/compiler/__tests__/skills-registry.test.js +9 -8
  87. package/lib/compiler/resource-copier.js +29 -0
  88. package/lib/skill-runtime/__tests__/archive-change.test.js +2 -2
  89. package/lib/skill-runtime/__tests__/benchmark-skills.test.js +3 -3
  90. package/lib/skill-runtime/__tests__/cli-bootstrap.integration.test.js +14 -4
  91. package/lib/skill-runtime/errors.js +3 -3
  92. package/lib/skill-runtime/index.js +5 -23
  93. package/lib/skill-runtime/paths.js +5 -52
  94. package/lib/skill-runtime/query-registry.js +4 -4
  95. package/lib/skill-runtime/query.js +89 -201
  96. package/lib/skill-runtime/store.js +4 -40
  97. package/lib/skill-runtime/trace.js +2 -2
  98. package/package.json +2 -5
  99. package/.claude/skills/cc-act/assets/PROJECT_POSTMORTEM_PRINCIPLES_TEMPLATE.md +0 -29
  100. package/.claude/skills/cc-act/assets/RELEASE_NOTE_TEMPLATE.md +0 -54
  101. package/.claude/skills/cc-act/scripts/generate-status-report.sh +0 -92
  102. package/.claude/skills/cc-act/scripts/sync-act-docs.sh +0 -355
  103. package/.claude/skills/cc-check/assets/REPORT_CARD_TEMPLATE.json +0 -234
  104. package/.claude/skills/cc-check/scripts/render-report-card.js +0 -438
  105. package/.claude/skills/cc-check/scripts/verify-gate.sh +0 -85
  106. package/.claude/skills/cc-do/scripts/build-task-context.sh +0 -175
  107. package/.claude/skills/cc-do/scripts/record-review-decision.sh +0 -88
  108. package/.claude/skills/cc-do/scripts/recover-workflow.sh +0 -82
  109. package/.claude/skills/cc-do/scripts/run-problem-analysis.sh +0 -70
  110. package/.claude/skills/cc-do/scripts/verify-task-gates.sh +0 -109
  111. package/.claude/skills/cc-do/scripts/write-task-checkpoint.sh +0 -92
  112. package/.claude/skills/cc-investigate/assets/TASK_MANIFEST_TEMPLATE.json +0 -224
  113. package/.claude/skills/cc-plan/assets/TASK_MANIFEST_TEMPLATE.json +0 -178
  114. package/.claude/skills/cc-spec-init/assets/CHANGE_META_TEMPLATE.json +0 -28
  115. package/.claude/skills/cc-spec-init/scripts/validate-spec-links.sh +0 -45
  116. package/docs/examples/full-design-blocked/changes/REQ-002-bulk-invite-import/planning/design.md +0 -234
  117. package/docs/examples/full-design-blocked/changes/REQ-002-bulk-invite-import/planning/task-manifest.json +0 -488
  118. package/docs/examples/full-design-blocked/changes/REQ-002-bulk-invite-import/review/report-card.json +0 -189
  119. package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/handoff/resume-index.md +0 -39
  120. package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/handoff/status.md +0 -29
  121. package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/planning/design.md +0 -123
  122. package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/planning/task-manifest.json +0 -292
  123. package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/review/report-card.json +0 -136
  124. package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/handoff/status.md +0 -29
  125. package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/planning/design.md +0 -124
  126. package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/planning/task-manifest.json +0 -292
  127. package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/review/report-card.json +0 -136
  128. package/docs/get-shit-done-strategy-audit.md +0 -518
  129. package/docs/skill-runtime-migration.md +0 -46
  130. package/lib/skill-runtime/__tests__/approve.test.js +0 -92
  131. package/lib/skill-runtime/__tests__/autopilot.test.js +0 -253
  132. package/lib/skill-runtime/__tests__/benchmark-artifacts.test.js +0 -165
  133. package/lib/skill-runtime/__tests__/delegation.test.js +0 -97
  134. package/lib/skill-runtime/__tests__/dispatch.test.js +0 -237
  135. package/lib/skill-runtime/__tests__/intent.test.js +0 -203
  136. package/lib/skill-runtime/__tests__/lifecycle.test.js +0 -169
  137. package/lib/skill-runtime/__tests__/planner.tdd.test.js +0 -331
  138. package/lib/skill-runtime/__tests__/prepare-pr.test.js +0 -126
  139. package/lib/skill-runtime/__tests__/query.test.js +0 -860
  140. package/lib/skill-runtime/__tests__/readiness.test.js +0 -53
  141. package/lib/skill-runtime/__tests__/release.test.js +0 -85
  142. package/lib/skill-runtime/__tests__/review-check-integration.test.js +0 -148
  143. package/lib/skill-runtime/__tests__/review-records.test.js +0 -619
  144. package/lib/skill-runtime/__tests__/runtime.integration.test.js +0 -351
  145. package/lib/skill-runtime/__tests__/schemas.test.js +0 -337
  146. package/lib/skill-runtime/__tests__/task-contract-migrate.test.js +0 -137
  147. package/lib/skill-runtime/__tests__/task-contract.test.js +0 -874
  148. package/lib/skill-runtime/__tests__/team-state.test.js +0 -51
  149. package/lib/skill-runtime/__tests__/verify-artifacts.test.js +0 -203
  150. package/lib/skill-runtime/__tests__/worker-run.test.js +0 -275
  151. package/lib/skill-runtime/__tests__/worker.test.js +0 -56
  152. package/lib/skill-runtime/__tests__/workflow-context-legacy-fallback.test.js +0 -31
  153. package/lib/skill-runtime/__tests__/workflow-context.test.js +0 -98
  154. package/lib/skill-runtime/artifacts.js +0 -88
  155. package/lib/skill-runtime/context-index.js +0 -545
  156. package/lib/skill-runtime/delegation.js +0 -533
  157. package/lib/skill-runtime/intent.js +0 -309
  158. package/lib/skill-runtime/lifecycle.js +0 -294
  159. package/lib/skill-runtime/operations/CLAUDE.md +0 -19
  160. package/lib/skill-runtime/operations/approve.js +0 -81
  161. package/lib/skill-runtime/operations/autopilot-core.js +0 -337
  162. package/lib/skill-runtime/operations/autopilot-execution.js +0 -307
  163. package/lib/skill-runtime/operations/autopilot-shared.js +0 -48
  164. package/lib/skill-runtime/operations/autopilot.js +0 -163
  165. package/lib/skill-runtime/operations/dispatch.js +0 -416
  166. package/lib/skill-runtime/operations/init.js +0 -60
  167. package/lib/skill-runtime/operations/janitor.js +0 -61
  168. package/lib/skill-runtime/operations/plan.js +0 -59
  169. package/lib/skill-runtime/operations/prepare-pr.js +0 -25
  170. package/lib/skill-runtime/operations/release.js +0 -99
  171. package/lib/skill-runtime/operations/resume.js +0 -126
  172. package/lib/skill-runtime/operations/review-records.js +0 -265
  173. package/lib/skill-runtime/operations/snapshot.js +0 -45
  174. package/lib/skill-runtime/operations/task-contract.js +0 -593
  175. package/lib/skill-runtime/operations/verify.js +0 -170
  176. package/lib/skill-runtime/operations/worker-run.js +0 -531
  177. package/lib/skill-runtime/operations/worker.js +0 -33
  178. package/lib/skill-runtime/planner.js +0 -539
  179. package/lib/skill-runtime/readiness.js +0 -84
  180. package/lib/skill-runtime/review-records.js +0 -123
  181. package/lib/skill-runtime/review.js +0 -855
  182. package/lib/skill-runtime/schemas.js +0 -746
  183. package/lib/skill-runtime/task-contract.js +0 -188
  184. package/lib/skill-runtime/team-state.js +0 -122
  185. 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
- });