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,860 +0,0 @@
1
- const fs = require('fs');
2
- const os = require('os');
3
- const path = require('path');
4
-
5
- const {
6
- getFullState,
7
- getNextTask,
8
- getProgress,
9
- getWorkflowContext,
10
- listQueryIds,
11
- runQuery
12
- } = require('../query');
13
- const {
14
- getRuntimeStatePath,
15
- getTaskManifestPath,
16
- getReportCardPath
17
- } = require('../store');
18
- const { getIntentPrBriefPath } = require('../artifacts');
19
-
20
- function writeJson(filePath, value) {
21
- fs.mkdirSync(path.dirname(filePath), { recursive: true });
22
- fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`);
23
- }
24
-
25
- describe('query helpers', () => {
26
- test('reuses shared lifecycle progress semantics', async () => {
27
- const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'cc-devflow-query-progress-'));
28
-
29
- writeJson(getTaskManifestPath(repoRoot, 'REQ-122'), {
30
- changeId: 'REQ-122',
31
- goal: 'Expose shared progress summary',
32
- createdAt: '2026-03-25T01:05:00.000Z',
33
- updatedAt: '2026-03-25T01:10:00.000Z',
34
- tasks: [
35
- { id: 'T001', status: 'pending' },
36
- { id: 'T002', status: 'running' },
37
- { id: 'T003', status: 'passed' },
38
- { id: 'T004', status: 'failed' },
39
- { id: 'T005', status: 'skipped' },
40
- { id: 'T006', status: 'legacy' }
41
- ],
42
- metadata: {
43
- source: 'default',
44
- generatedBy: 'test',
45
- planVersion: 1
46
- }
47
- });
48
-
49
- await expect(getProgress(repoRoot, 'REQ-122')).resolves.toEqual({
50
- totalTasks: 6,
51
- completedTasks: 1,
52
- failedTasks: 1,
53
- pendingTasks: 1,
54
- runningTasks: 1,
55
- skippedTasks: 1
56
- });
57
- });
58
-
59
- test('reports approve stage when a planned manifest exists without approval', async () => {
60
- const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'cc-devflow-query-approve-'));
61
-
62
- writeJson(getRuntimeStatePath(repoRoot, 'REQ-123'), {
63
- changeId: 'REQ-123',
64
- goal: 'Expose approval gate',
65
- status: 'planned',
66
- initializedAt: '2026-03-25T01:00:00.000Z',
67
- plannedAt: '2026-03-25T01:05:00.000Z',
68
- approval: {
69
- status: 'pending',
70
- executionMode: 'delegate'
71
- },
72
- updatedAt: '2026-03-25T01:05:00.000Z'
73
- });
74
-
75
- writeJson(getTaskManifestPath(repoRoot, 'REQ-123'), {
76
- changeId: 'REQ-123',
77
- goal: 'Expose approval gate',
78
- createdAt: '2026-03-25T01:05:00.000Z',
79
- updatedAt: '2026-03-25T01:10:00.000Z',
80
- tasks: [
81
- {
82
- id: 'T001',
83
- title: 'Pending',
84
- type: 'IMPL',
85
- dependsOn: [],
86
- touches: ['src/a.ts'],
87
- run: ['echo ok'],
88
- checks: [],
89
- status: 'pending',
90
- attempts: 0,
91
- maxRetries: 1
92
- }
93
- ],
94
- metadata: {
95
- source: 'default',
96
- generatedBy: 'test',
97
- planVersion: 1
98
- }
99
- });
100
-
101
- const state = await getFullState(repoRoot, 'REQ-123');
102
-
103
- expect(state.lifecycle.stage).toBe('approve');
104
- expect(state.lifecycle.approval).toMatchObject({
105
- status: 'pending',
106
- executionMode: 'delegate',
107
- planVersion: 1
108
- });
109
- });
110
-
111
- test('reports prepare-pr stage and pr brief path when PR-ready artifact exists', async () => {
112
- const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'cc-devflow-query-'));
113
-
114
- writeJson(getRuntimeStatePath(repoRoot, 'REQ-123'), {
115
- changeId: 'REQ-123',
116
- goal: 'Expose query stage',
117
- status: 'verified',
118
- initializedAt: '2026-03-25T01:00:00.000Z',
119
- plannedAt: '2026-03-25T01:05:00.000Z',
120
- verifiedAt: '2026-03-25T01:10:00.000Z',
121
- updatedAt: '2026-03-25T01:10:00.000Z'
122
- });
123
-
124
- writeJson(getTaskManifestPath(repoRoot, 'REQ-123'), {
125
- changeId: 'REQ-123',
126
- goal: 'Expose query stage',
127
- createdAt: '2026-03-25T01:05:00.000Z',
128
- updatedAt: '2026-03-25T01:10:00.000Z',
129
- tasks: [
130
- {
131
- id: 'T001',
132
- title: 'Done',
133
- type: 'IMPL',
134
- dependsOn: [],
135
- touches: ['src/a.ts'],
136
- run: ['echo ok'],
137
- checks: [],
138
- status: 'passed',
139
- attempts: 1,
140
- maxRetries: 1
141
- }
142
- ],
143
- metadata: {
144
- source: 'default',
145
- generatedBy: 'test',
146
- planVersion: 1
147
- }
148
- });
149
-
150
- writeJson(getReportCardPath(repoRoot, 'REQ-123'), {
151
- changeId: 'REQ-123',
152
- overall: 'pass',
153
- quickGates: [],
154
- strictGates: [],
155
- review: { status: 'pass', details: '' },
156
- blockingFindings: [],
157
- timestamp: '2026-03-25T01:11:00.000Z'
158
- });
159
-
160
- fs.mkdirSync(path.dirname(getIntentPrBriefPath(repoRoot, 'REQ-123')), { recursive: true });
161
- fs.writeFileSync(getIntentPrBriefPath(repoRoot, 'REQ-123'), '# PR Brief: REQ-123\n');
162
-
163
- const state = await getFullState(repoRoot, 'REQ-123');
164
-
165
- expect(state.lifecycle.stage).toBe('prepare-pr');
166
- expect(state.delivery.prBriefPath).toBe(getIntentPrBriefPath(repoRoot, 'REQ-123'));
167
- });
168
-
169
- test('returns the ready task instead of the first pending task', async () => {
170
- const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'cc-devflow-query-next-'));
171
-
172
- writeJson(getTaskManifestPath(repoRoot, 'REQ-124'), {
173
- changeId: 'REQ-124',
174
- goal: 'Expose dependency-aware next task',
175
- createdAt: '2026-03-25T01:05:00.000Z',
176
- updatedAt: '2026-03-25T01:10:00.000Z',
177
- currentTaskId: 'T002',
178
- activePhase: 1,
179
- tasks: [
180
- {
181
- id: 'T001',
182
- title: 'Blocked task',
183
- type: 'OTHER',
184
- phase: 1,
185
- dependsOn: ['T999'],
186
- touches: ['src/a.ts'],
187
- files: [],
188
- run: ['echo blocked'],
189
- checks: [],
190
- acceptance: [],
191
- verification: [],
192
- evidence: [],
193
- context: { readFiles: [], commands: [], notes: [] },
194
- reviews: { spec: 'pending', code: 'pending' },
195
- status: 'pending',
196
- attempts: 0,
197
- maxRetries: 1
198
- },
199
- {
200
- id: 'T002',
201
- title: 'Ready task',
202
- type: 'OTHER',
203
- phase: 1,
204
- dependsOn: [],
205
- touches: ['src/b.ts'],
206
- files: [],
207
- run: ['echo ready'],
208
- checks: [],
209
- acceptance: [],
210
- verification: [],
211
- evidence: [],
212
- context: { readFiles: [], commands: [], notes: [] },
213
- reviews: { spec: 'pending', code: 'pending' },
214
- status: 'pending',
215
- attempts: 0,
216
- maxRetries: 1
217
- }
218
- ],
219
- metadata: {
220
- source: 'default',
221
- generatedBy: 'test',
222
- planVersion: 1
223
- }
224
- });
225
-
226
- const next = await getNextTask(repoRoot, 'REQ-124');
227
-
228
- expect(next.id).toBe('T002');
229
- });
230
-
231
- test('treats legacy passed aliases as completed dependencies via shared lifecycle semantics', async () => {
232
- const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'cc-devflow-query-legacy-next-'));
233
-
234
- writeJson(getTaskManifestPath(repoRoot, 'REQ-125'), {
235
- changeId: 'REQ-125',
236
- goal: 'Reuse shared task completion aliases',
237
- createdAt: '2026-03-25T01:05:00.000Z',
238
- updatedAt: '2026-03-25T01:10:00.000Z',
239
- activePhase: 1,
240
- tasks: [
241
- {
242
- id: 'T001',
243
- title: 'Legacy completed prerequisite',
244
- type: 'OTHER',
245
- phase: 1,
246
- dependsOn: [],
247
- touches: ['src/a.ts'],
248
- files: [],
249
- run: ['echo done'],
250
- checks: [],
251
- acceptance: [],
252
- verification: [],
253
- evidence: [],
254
- context: { readFiles: [], commands: [], notes: [] },
255
- reviews: { spec: 'pending', code: 'pending' },
256
- status: 'verified',
257
- attempts: 1,
258
- maxRetries: 1
259
- },
260
- {
261
- id: 'T002',
262
- title: 'Ready after legacy prerequisite',
263
- type: 'OTHER',
264
- phase: 1,
265
- dependsOn: ['T001'],
266
- touches: ['src/b.ts'],
267
- files: [],
268
- run: ['echo ready'],
269
- checks: [],
270
- acceptance: [],
271
- verification: [],
272
- evidence: [],
273
- context: { readFiles: [], commands: [], notes: [] },
274
- reviews: { spec: 'pending', code: 'pending' },
275
- status: 'pending',
276
- attempts: 0,
277
- maxRetries: 1
278
- }
279
- ],
280
- metadata: {
281
- source: 'default',
282
- generatedBy: 'test',
283
- planVersion: 1
284
- }
285
- });
286
-
287
- const next = await getNextTask(repoRoot, 'REQ-125');
288
-
289
- expect(next.id).toBe('T002');
290
- });
291
-
292
- test('returns compact workflow context for the current ready task', async () => {
293
- const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'cc-devflow-query-workflow-context-'));
294
- const manifestPath = getTaskManifestPath(repoRoot, 'REQ-126');
295
- const planningDir = path.dirname(manifestPath);
296
- const changeDir = path.dirname(planningDir);
297
-
298
- fs.mkdirSync(planningDir, { recursive: true });
299
- fs.writeFileSync(path.join(planningDir, 'design.md'), '# Design\n');
300
- fs.writeFileSync(path.join(planningDir, 'tasks.md'), '# Tasks\n');
301
- writeJson(path.join(changeDir, 'change-meta.json'), {
302
- spec: {
303
- primaryCapability: 'cap-compact-context',
304
- syncStatus: 'planned'
305
- }
306
- });
307
- writeJson(manifestPath, {
308
- changeId: 'REQ-126',
309
- goal: 'Expose compact workflow context',
310
- createdAt: '2026-05-12T01:00:00.000Z',
311
- updatedAt: '2026-05-12T01:05:00.000Z',
312
- currentTaskId: 'T002',
313
- planningMeta: {
314
- reqPlanSkillVersion: '3.8.8'
315
- },
316
- tasks: [
317
- {
318
- id: 'T001',
319
- title: 'Completed test task',
320
- type: 'TEST',
321
- phase: 1,
322
- dependsOn: [],
323
- touches: ['src/feature.test.ts'],
324
- files: ['src/feature.test.ts'],
325
- run: ['npm test -- src/feature.test.ts'],
326
- checks: [],
327
- acceptance: [],
328
- verification: ['npm test -- src/feature.test.ts'],
329
- evidence: ['red output'],
330
- context: { readFiles: ['planning/design.md'], commands: ['npm test -- src/feature.test.ts'], notes: [] },
331
- status: 'passed',
332
- attempts: 1,
333
- maxRetries: 1
334
- },
335
- {
336
- id: 'T002',
337
- title: 'Implement compact context',
338
- type: 'IMPL',
339
- phase: 1,
340
- dependsOn: ['T001'],
341
- touches: ['lib/skill-runtime/query.js'],
342
- files: ['lib/skill-runtime/query.js'],
343
- run: ['npm test -- lib/skill-runtime/__tests__/query.test.js'],
344
- checks: [],
345
- acceptance: [],
346
- verification: ['npm test -- lib/skill-runtime/__tests__/query.test.js'],
347
- evidence: ['green output'],
348
- context: {
349
- readFiles: ['design.md', 'tasks.md', 'change-meta.json', 'lib/skill-runtime/query.js'],
350
- commands: ['npm test -- lib/skill-runtime/__tests__/query.test.js'],
351
- notes: ['Read the context index before opening deep docs']
352
- },
353
- status: 'pending',
354
- attempts: 0,
355
- maxRetries: 1
356
- }
357
- ],
358
- metadata: {
359
- source: 'test',
360
- generatedBy: 'test',
361
- planVersion: 2
362
- }
363
- });
364
-
365
- const context = await getWorkflowContext(repoRoot, 'REQ-126');
366
-
367
- expect(context.nextAction).toMatchObject({
368
- skill: 'cc-do',
369
- action: 'execute-current-task',
370
- taskId: 'T002'
371
- });
372
- expect(context.currentTask).toMatchObject({
373
- id: 'T002',
374
- context: {
375
- readFiles: expect.arrayContaining(['design.md', 'tasks.md', 'change-meta.json', 'lib/skill-runtime/query.js'])
376
- }
377
- });
378
- expect(context.progressiveDisclosure).toMatchObject({
379
- mode: 'compact-first',
380
- rule: expect.stringContaining('context index'),
381
- packetOnly: {
382
- contractDigest: expect.any(String),
383
- manifestDigest: expect.any(String),
384
- currentTaskDigest: expect.any(String),
385
- evidenceDigest: expect.any(String),
386
- mustNotForgetDigest: expect.any(String)
387
- }
388
- });
389
- expect(context.source.manifest).toMatchObject({
390
- path: expect.stringContaining('planning/task-manifest.json'),
391
- hash: expect.stringMatching(/^sha256:/)
392
- });
393
- expect(context.progressiveDisclosure.sourceHashes).toEqual(expect.objectContaining({
394
- [context.source.manifest.path]: expect.stringMatching(/^sha256:/)
395
- }));
396
- expect(context.progressiveDisclosure.mustNotForget).toMatchObject({
397
- goal: {
398
- value: 'Expose compact workflow context',
399
- source: {
400
- ref: expect.stringContaining('planning/task-manifest.json#/goal'),
401
- hash: expect.stringMatching(/^sha256:/)
402
- }
403
- },
404
- nonNegotiables: expect.arrayContaining([
405
- expect.objectContaining({
406
- value: expect.stringContaining('read-only'),
407
- source: expect.objectContaining({ ref: expect.any(String) })
408
- })
409
- ]),
410
- acceptanceGates: expect.arrayContaining([
411
- expect.objectContaining({
412
- value: 'npm test -- lib/skill-runtime/__tests__/query.test.js',
413
- source: expect.objectContaining({ ref: expect.stringContaining('planning/task-manifest.json#/tasks/T002') })
414
- })
415
- ])
416
- });
417
- expect(context.progressiveDisclosure.defaultOpen).toEqual(expect.arrayContaining([
418
- expect.objectContaining({
419
- ref: expect.stringContaining('planning/design.md#design'),
420
- reason: 'primary task contract',
421
- exists: true,
422
- sourceHash: expect.stringMatching(/^sha256:/)
423
- }),
424
- expect.objectContaining({
425
- ref: expect.stringContaining('planning/task-manifest.json#/tasks/T002'),
426
- reason: 'current task source of truth',
427
- sourceHash: expect.stringMatching(/^sha256:/)
428
- }),
429
- expect.objectContaining({
430
- ref: expect.stringContaining('change-meta.json#/spec')
431
- })
432
- ]));
433
- expect(context.progressiveDisclosure.defaultOpen.every((entry) => entry.exists === true)).toBe(true);
434
- expect(context.progressiveDisclosure.defaultRead).toBeUndefined();
435
- expect(context.progressiveDisclosure.deepOpen).toEqual(expect.arrayContaining([
436
- expect.objectContaining({
437
- when: 'scope_or_contract_uncertain',
438
- conditions: expect.arrayContaining(['confidence.scope < 0.85']),
439
- refs: expect.arrayContaining([
440
- expect.objectContaining({ ref: expect.stringContaining('planning/design.md') })
441
- ])
442
- }),
443
- expect.objectContaining({
444
- when: 'implementation_details_needed',
445
- refs: expect.arrayContaining([
446
- expect.objectContaining({ ref: 'lib/skill-runtime/query.js' })
447
- ])
448
- })
449
- ]));
450
- expect(context.progressiveDisclosure.defaultOpen).not.toEqual(expect.arrayContaining([
451
- 'design.md',
452
- 'tasks.md',
453
- 'change-meta.json'
454
- ]));
455
- expect(context.progressiveDisclosure.commandsToTrust).toContain('npm test -- lib/skill-runtime/__tests__/query.test.js');
456
- expect(context.progressiveDisclosure.openWhen).toEqual(expect.arrayContaining([
457
- expect.objectContaining({
458
- trigger: expect.stringContaining('all tasks are complete'),
459
- conditions: expect.arrayContaining(['nextAction.skill == cc-act'])
460
- })
461
- ]));
462
- expect(context.planningMeta).toMatchObject({
463
- reqPlanSkillVersion: '3.8.8',
464
- sourceCapability: 'cap-compact-context',
465
- specSyncStatus: 'planned'
466
- });
467
- });
468
-
469
- test('routes compact workflow context through check and act after execution', async () => {
470
- const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'cc-devflow-query-workflow-terminal-'));
471
-
472
- writeJson(getTaskManifestPath(repoRoot, 'REQ-127'), {
473
- changeId: 'REQ-127',
474
- goal: 'Expose terminal workflow routing',
475
- createdAt: '2026-05-12T01:00:00.000Z',
476
- updatedAt: '2026-05-12T01:05:00.000Z',
477
- tasks: [
478
- {
479
- id: 'T001',
480
- status: 'passed',
481
- verification: ['npm test -- final.test.js'],
482
- context: {
483
- commands: ['npm test -- final.test.js']
484
- }
485
- }
486
- ],
487
- metadata: {
488
- source: 'test',
489
- generatedBy: 'test',
490
- planVersion: 1
491
- }
492
- });
493
-
494
- await expect(getWorkflowContext(repoRoot, 'REQ-127')).resolves.toMatchObject({
495
- nextAction: {
496
- skill: 'cc-check',
497
- action: 'build-fresh-verdict'
498
- },
499
- progressiveDisclosure: {
500
- commandsToTrust: ['npm test -- final.test.js']
501
- }
502
- });
503
-
504
- writeJson(getReportCardPath(repoRoot, 'REQ-127'), {
505
- changeId: 'REQ-127',
506
- verdict: 'pass',
507
- overall: 'pass',
508
- reroute: 'none',
509
- specSyncReady: false,
510
- blockingFindings: [],
511
- timestamp: '2026-05-12T01:10:00.000Z'
512
- });
513
-
514
- await expect(getWorkflowContext(repoRoot, 'REQ-127')).resolves.toMatchObject({
515
- nextAction: {
516
- skill: 'cc-check',
517
- action: 'build-fresh-verdict',
518
- blockers: expect.arrayContaining(['specSyncReady is not true'])
519
- }
520
- });
521
-
522
- writeJson(getReportCardPath(repoRoot, 'REQ-127'), {
523
- changeId: 'REQ-127',
524
- verdict: 'pass',
525
- overall: 'pass',
526
- reroute: 'none',
527
- specSyncReady: true,
528
- blockingFindings: [],
529
- timestamp: '2026-05-12T01:11:00.000Z'
530
- });
531
-
532
- await expect(getWorkflowContext(repoRoot, 'REQ-127')).resolves.toMatchObject({
533
- nextAction: {
534
- skill: 'cc-act',
535
- action: 'ship-or-handoff'
536
- }
537
- });
538
- });
539
-
540
- test('resumes current running task before selecting another ready task', async () => {
541
- const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'cc-devflow-query-workflow-resume-'));
542
-
543
- writeJson(getTaskManifestPath(repoRoot, 'REQ-130'), {
544
- changeId: 'REQ-130',
545
- currentTaskId: 'T002',
546
- tasks: [
547
- { id: 'T001', status: 'passed' },
548
- {
549
- id: 'T002',
550
- status: 'running',
551
- dependsOn: ['T001'],
552
- verification: ['npm test -- src/current.test.ts'],
553
- context: {
554
- commands: ['npm test -- src/current.test.ts']
555
- }
556
- },
557
- {
558
- id: 'T003',
559
- status: 'pending',
560
- dependsOn: ['T001'],
561
- verification: ['npm test -- src/ready.test.ts'],
562
- context: {
563
- commands: ['npm test -- src/ready.test.ts']
564
- }
565
- }
566
- ],
567
- metadata: {
568
- source: 'test',
569
- generatedBy: 'test',
570
- planVersion: 1
571
- }
572
- });
573
-
574
- await expect(getWorkflowContext(repoRoot, 'REQ-130')).resolves.toMatchObject({
575
- nextAction: {
576
- skill: 'cc-do',
577
- action: 'resume-current-task',
578
- taskId: 'T002'
579
- },
580
- currentTask: {
581
- id: 'T002',
582
- status: 'running'
583
- }
584
- });
585
- });
586
-
587
- test('resumes inferred running task before selecting ready task when currentTaskId is missing', async () => {
588
- const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'cc-devflow-query-workflow-inferred-resume-'));
589
-
590
- writeJson(getTaskManifestPath(repoRoot, 'REQ-132'), {
591
- changeId: 'REQ-132',
592
- tasks: [
593
- { id: 'T001', status: 'passed' },
594
- {
595
- id: 'T002',
596
- status: 'running',
597
- dependsOn: ['T001'],
598
- verification: ['npm test -- src/current.test.ts'],
599
- context: {
600
- commands: ['npm test -- src/current.test.ts']
601
- }
602
- },
603
- {
604
- id: 'T003',
605
- status: 'pending',
606
- dependsOn: ['T001'],
607
- verification: ['npm test -- src/ready.test.ts'],
608
- context: {
609
- commands: ['npm test -- src/ready.test.ts']
610
- }
611
- }
612
- ],
613
- metadata: {
614
- source: 'test',
615
- generatedBy: 'test',
616
- planVersion: 1
617
- }
618
- });
619
-
620
- await expect(getWorkflowContext(repoRoot, 'REQ-132')).resolves.toMatchObject({
621
- nextAction: {
622
- skill: 'cc-do',
623
- action: 'resume-current-task',
624
- taskId: 'T002'
625
- },
626
- currentTask: {
627
- id: 'T002',
628
- status: 'running'
629
- }
630
- });
631
- });
632
-
633
- test('reports missing verification commands instead of trusting the query command', async () => {
634
- const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'cc-devflow-query-workflow-missing-commands-'));
635
-
636
- writeJson(getTaskManifestPath(repoRoot, 'REQ-131'), {
637
- changeId: 'REQ-131',
638
- currentTaskId: 'T001',
639
- tasks: [
640
- {
641
- id: 'T001',
642
- status: 'pending',
643
- context: {
644
- readFiles: ['design.md']
645
- }
646
- }
647
- ],
648
- metadata: {
649
- source: 'test',
650
- generatedBy: 'test',
651
- planVersion: 1
652
- }
653
- });
654
-
655
- await expect(getWorkflowContext(repoRoot, 'REQ-131')).resolves.toMatchObject({
656
- nextAction: {
657
- skill: 'cc-plan',
658
- action: 'repair-task-verification',
659
- taskId: 'T001'
660
- },
661
- progressiveDisclosure: {
662
- commandsToTrust: [],
663
- missingVerificationCommands: true,
664
- manifestIssue: 'current task has no executable verification command',
665
- failClosed: expect.arrayContaining([
666
- expect.stringContaining('verification command is missing')
667
- ])
668
- }
669
- });
670
- });
671
-
672
- test('dispatches typed query ids with trace metadata', async () => {
673
- const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'cc-devflow-query-registry-'));
674
-
675
- writeJson(getTaskManifestPath(repoRoot, 'REQ-126'), {
676
- changeId: 'REQ-126',
677
- goal: 'Expose typed query registry',
678
- createdAt: '2026-03-25T01:05:00.000Z',
679
- updatedAt: '2026-03-25T01:10:00.000Z',
680
- tasks: [
681
- { id: 'T001', status: 'pending' }
682
- ],
683
- metadata: {
684
- source: 'default',
685
- generatedBy: 'test',
686
- planVersion: 1
687
- }
688
- });
689
-
690
- await expect(runQuery('progress', { repoRoot, changeId: 'REQ-126' })).resolves.toMatchObject({
691
- ok: true,
692
- queryId: 'progress',
693
- data: {
694
- totalTasks: 1,
695
- pendingTasks: 1
696
- },
697
- trace: {
698
- artifactRefs: expect.arrayContaining([
699
- expect.stringContaining('task-manifest.json')
700
- ]),
701
- nextAction: 'read-query-result'
702
- }
703
- });
704
-
705
- expect(listQueryIds()).toEqual(expect.arrayContaining(['full-state', 'next-task', 'progress', 'workflow-context']));
706
- });
707
-
708
- test('requires a full change key when duplicate local numbers exist', async () => {
709
- const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'cc-devflow-query-duplicate-key-'));
710
- const firstKey = 'REQ-132-first-plan';
711
- const secondKey = 'REQ-132-second-plan';
712
-
713
- fs.mkdirSync(path.join(repoRoot, 'devflow', 'changes', firstKey), { recursive: true });
714
- writeJson(getTaskManifestPath(repoRoot, 'REQ-132', { changeKey: secondKey }), {
715
- changeId: 'REQ-132',
716
- goal: 'Resolve duplicate local numbers',
717
- createdAt: '2026-05-08T01:00:00.000Z',
718
- updatedAt: '2026-05-08T01:05:00.000Z',
719
- tasks: [
720
- { id: 'T001', status: 'passed' },
721
- { id: 'T002', status: 'pending' }
722
- ],
723
- metadata: {
724
- source: 'test',
725
- generatedBy: 'test',
726
- planVersion: 1
727
- }
728
- });
729
-
730
- await expect(runQuery('progress', { repoRoot, changeId: 'REQ-132' })).resolves.toMatchObject({
731
- ok: false,
732
- queryId: 'progress',
733
- error: {
734
- message: expect.stringContaining('Ambiguous changeId "REQ-132"')
735
- },
736
- trace: {
737
- event: 'query.progress.failed',
738
- nextAction: 'inspect-workflow-artifacts'
739
- }
740
- });
741
-
742
- await expect(runQuery('progress', {
743
- repoRoot,
744
- changeId: 'REQ-132',
745
- changeKey: secondKey
746
- })).resolves.toMatchObject({
747
- ok: true,
748
- queryId: 'progress',
749
- data: {
750
- totalTasks: 2,
751
- completedTasks: 1,
752
- pendingTasks: 1
753
- }
754
- });
755
- });
756
-
757
- test('returns a named error for unknown query ids', async () => {
758
- const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'cc-devflow-query-unknown-'));
759
-
760
- await expect(runQuery('unknown-query', { repoRoot, changeId: 'REQ-127' })).resolves.toMatchObject({
761
- ok: false,
762
- queryId: 'unknown-query',
763
- error: {
764
- name: 'UnknownQueryError',
765
- rescueAction: 'use one of: full-state, next-task, progress, ship-readiness, workflow-context'
766
- },
767
- trace: {
768
- nextAction: 'choose-supported-query'
769
- }
770
- });
771
- });
772
-
773
- test('returns a named error when typed queries miss required artifacts', async () => {
774
- const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'cc-devflow-query-missing-manifest-'));
775
-
776
- await expect(runQuery('progress', { repoRoot, changeId: 'REQ-130' })).resolves.toMatchObject({
777
- ok: false,
778
- queryId: 'progress',
779
- error: {
780
- name: 'MissingQueryArtifactError',
781
- artifactRefs: [
782
- expect.stringContaining('task-manifest.json')
783
- ],
784
- rescueAction: 'create required workflow artifacts before running this query'
785
- },
786
- trace: {
787
- event: 'query.progress.failed',
788
- nextAction: 'create required workflow artifacts before running this query'
789
- }
790
- });
791
- });
792
-
793
- test('returns a named error when required query artifacts are malformed', async () => {
794
- const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'cc-devflow-query-invalid-manifest-'));
795
- const manifestPath = getTaskManifestPath(repoRoot, 'REQ-131');
796
- fs.mkdirSync(path.dirname(manifestPath), { recursive: true });
797
- fs.writeFileSync(manifestPath, '{bad json\n');
798
-
799
- await expect(runQuery('progress', { repoRoot, changeId: 'REQ-131' })).resolves.toMatchObject({
800
- ok: false,
801
- queryId: 'progress',
802
- error: {
803
- name: 'InvalidQueryArtifactError',
804
- artifactRefs: [
805
- expect.stringContaining('task-manifest.json')
806
- ],
807
- rescueAction: 'repair or regenerate the invalid workflow artifact before running this query'
808
- },
809
- trace: {
810
- event: 'query.progress.failed',
811
- nextAction: 'repair or regenerate the invalid workflow artifact before running this query'
812
- }
813
- });
814
- });
815
-
816
- test('returns MissingReportCardError for ship readiness without report card', async () => {
817
- const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'cc-devflow-query-missing-report-'));
818
-
819
- await expect(runQuery('ship-readiness', { repoRoot, changeId: 'REQ-128' })).resolves.toMatchObject({
820
- ok: false,
821
- queryId: 'ship-readiness',
822
- error: {
823
- name: 'MissingReportCardError',
824
- artifactRefs: [
825
- expect.stringContaining('report-card.json')
826
- ],
827
- rescueAction: 'run cc-check and create review/report-card.json before cc-act'
828
- },
829
- trace: {
830
- nextAction: 'run cc-check and create review/report-card.json before cc-act'
831
- }
832
- });
833
- });
834
-
835
- test('reports ship readiness from report-card truth', async () => {
836
- const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'cc-devflow-query-ship-ready-'));
837
-
838
- writeJson(getReportCardPath(repoRoot, 'REQ-129'), {
839
- changeId: 'REQ-129',
840
- verdict: 'pass',
841
- overall: 'pass',
842
- reroute: 'none',
843
- specSyncReady: true,
844
- blockingFindings: [],
845
- timestamp: '2026-03-25T01:11:00.000Z'
846
- });
847
-
848
- await expect(runQuery('ship-readiness', { repoRoot, changeId: 'REQ-129' })).resolves.toMatchObject({
849
- ok: true,
850
- queryId: 'ship-readiness',
851
- data: {
852
- ready: true,
853
- verdict: 'pass',
854
- reroute: 'none',
855
- specSyncReady: true,
856
- blockers: []
857
- }
858
- });
859
- });
860
- });