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,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
- });