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,748 +0,0 @@
1
- /**
2
- * [INPUT]: 依赖 task-manifest/report/change-meta/runtime-state 等已有 artifact,接收 repoRoot/changeId/changeKey。
3
- * [OUTPUT]: 生成 compact workflow context,告诉 PDCA/IDCA 下一步、默认读取集、可信命令与深层展开条件。
4
- * [POS]: skill runtime 的渐进式披露查询层,只读派生状态,不拥有 workflow 规则本身。
5
- * [PROTOCOL]: 变更时更新此头部,然后检查 CLAUDE.md
6
- */
7
-
8
- const path = require('path');
9
-
10
- const {
11
- getRuntimeStatePath,
12
- getTaskManifestPath,
13
- getReportCardPath,
14
- getTasksMarkdownPath,
15
- exists,
16
- readJson,
17
- readText
18
- } = require('./store');
19
- const { getIntentPrBriefPath } = require('./artifacts');
20
- const { getChangePaths } = require('./paths');
21
- const { deriveManifestExecutionState } = require('./planner');
22
- const {
23
- getApprovalState,
24
- deriveLifecycleStage,
25
- deriveTaskProgress,
26
- isTaskCompletedStatus
27
- } = require('./lifecycle');
28
- const { namedError } = require('./errors');
29
- const { deriveShipReadiness } = require('./readiness');
30
- const {
31
- buildDefaultOpenRefs,
32
- buildMustNotForget,
33
- buildPacketOnly,
34
- buildSourceHashes,
35
- buildSourceIndex,
36
- dedupeOpenRefs,
37
- deepOpenGroup,
38
- openRef,
39
- validateDeepOpenGroups,
40
- validateOpenRefs,
41
- withFragment
42
- } = require('./context-index');
43
-
44
- const RESUMABLE_TASK_STATUSES = new Set([
45
- 'pending',
46
- 'running',
47
- 'in_progress',
48
- 'active',
49
- 'blocked',
50
- 'needs_fix',
51
- 'failed'
52
- ]);
53
-
54
- async function readWorkflowArtifact(filePath, { required = true } = {}) {
55
- try {
56
- const value = await readJson(filePath, null);
57
-
58
- if (required && value === null) {
59
- throw namedError(
60
- 'MissingQueryArtifactError',
61
- `Missing required query artifact: ${filePath}`,
62
- {
63
- artifactRefs: [filePath],
64
- rescueAction: 'create required workflow artifacts before running this query'
65
- }
66
- );
67
- }
68
-
69
- return value;
70
- } catch (error) {
71
- if (error.name === 'MissingQueryArtifactError') {
72
- throw error;
73
- }
74
-
75
- throw namedError(
76
- 'InvalidQueryArtifactError',
77
- `Invalid query artifact ${filePath}: ${error.message}`,
78
- {
79
- artifactRefs: [filePath],
80
- rescueAction: 'repair or regenerate the invalid workflow artifact before running this query',
81
- details: {
82
- cause: error.name || 'Error'
83
- }
84
- }
85
- );
86
- }
87
- }
88
-
89
- function relativePath(repoRoot, filePath) {
90
- return path.relative(repoRoot, filePath) || filePath;
91
- }
92
-
93
- async function maybeRelativePath(repoRoot, filePath) {
94
- return (await exists(filePath)) ? relativePath(repoRoot, filePath) : null;
95
- }
96
-
97
- function dedupe(values) {
98
- return [...new Set((values || []).filter(Boolean))];
99
- }
100
-
101
- function normalizeTaskReadFile(filePath, refs) {
102
- const value = String(filePath || '').trim().replace(/^\.\//, '');
103
- if (!value) {
104
- return null;
105
- }
106
-
107
- if (path.isAbsolute(value)) {
108
- return relativePath(refs.repoRoot, value);
109
- }
110
-
111
- const artifactAliases = new Map([
112
- ['design.md', refs.relativeDesignPath],
113
- ['analysis.md', refs.relativeAnalysisPath],
114
- ['tasks.md', refs.relativeTasksPath],
115
- ['task-manifest.json', refs.relativeManifestPath],
116
- ['change-meta.json', refs.relativeChangeMetaPath],
117
- ['report-card.json', refs.relativeReportPath],
118
- ['change-state.json', refs.relativeStatePath]
119
- ]);
120
- const normalizedDir = path.dirname(value).replace(/\\/g, '/');
121
- const basename = path.basename(value);
122
-
123
- if (normalizedDir === '.' && artifactAliases.has(value)) {
124
- return artifactAliases.get(value) || null;
125
- }
126
-
127
- if (normalizedDir === 'planning' && artifactAliases.has(basename)) {
128
- return artifactAliases.get(basename) || null;
129
- }
130
-
131
- if (normalizedDir === 'review' && basename === 'report-card.json') {
132
- return refs.relativeReportPath || null;
133
- }
134
-
135
- if (normalizedDir === 'meta' && basename === 'change-state.json') {
136
- return refs.relativeStatePath || null;
137
- }
138
-
139
- return value;
140
- }
141
-
142
- function normalizeTaskReadFiles(readFiles, refs) {
143
- return dedupe((readFiles || []).map((filePath) => normalizeTaskReadFile(filePath, refs)));
144
- }
145
-
146
- function isArtifactReadFile(filePath, refs) {
147
- return [
148
- refs.relativeDesignPath,
149
- refs.relativeAnalysisPath,
150
- refs.relativeTasksPath,
151
- refs.relativeManifestPath,
152
- refs.relativeChangeMetaPath,
153
- refs.relativeStatePath,
154
- refs.relativeReportPath
155
- ].filter(Boolean).includes(filePath);
156
- }
157
-
158
- function summarizeTask(task) {
159
- if (!task) {
160
- return null;
161
- }
162
-
163
- return {
164
- id: task.id,
165
- title: task.title || task.id,
166
- type: task.type || 'OTHER',
167
- phase: task.phase || 1,
168
- status: task.status || 'pending',
169
- tddPhase: task.tddPhase || null,
170
- dependsOn: task.dependsOn || [],
171
- parallel: Boolean(task.parallel),
172
- touches: task.touches || task.files || [],
173
- files: task.files || [],
174
- verification: task.verification || [],
175
- evidence: task.evidence || [],
176
- context: {
177
- readFiles: task.context?.readFiles || [],
178
- commands: task.context?.commands || [],
179
- notes: task.context?.notes || []
180
- }
181
- };
182
- }
183
-
184
- function deriveTaskQueues(manifest) {
185
- const tasks = manifest.tasks || [];
186
- const executionState = deriveManifestExecutionState(tasks);
187
- const activePhase = executionState.activePhase;
188
- const completedIds = new Set(
189
- tasks.filter((task) => isTaskCompletedStatus(task.status)).map((task) => task.id)
190
- );
191
- const unfinished = tasks.filter((task) => !isTaskCompletedStatus(task.status));
192
-
193
- function waitingOn(task) {
194
- return (task.dependsOn || []).filter((depId) => !completedIds.has(depId));
195
- }
196
-
197
- const activeTasks = unfinished.filter((task) => (
198
- activePhase === null || activePhase === undefined || (task.phase || 1) === activePhase
199
- ));
200
-
201
- return {
202
- activePhase,
203
- readyTasks: activeTasks
204
- .filter((task) => (task.status || 'pending') === 'pending' && waitingOn(task).length === 0)
205
- .map((task) => ({
206
- ...summarizeTask(task),
207
- waitingOn: []
208
- })),
209
- runningTasks: activeTasks
210
- .filter((task) => (task.status || 'pending') === 'running')
211
- .map(summarizeTask),
212
- blockedTasks: activeTasks
213
- .filter((task) => !['pending', 'running'].includes(task.status || 'pending') || waitingOn(task).length > 0)
214
- .map((task) => ({
215
- ...summarizeTask(task),
216
- waitingOn: waitingOn(task)
217
- })),
218
- deferredTasks: unfinished
219
- .filter((task) => activePhase !== null && activePhase !== undefined && (task.phase || 1) !== activePhase)
220
- .map(summarizeTask)
221
- };
222
- }
223
-
224
- function selectNextTask(manifest, queues) {
225
- const currentTaskId = manifest.currentTaskId;
226
-
227
- if (currentTaskId) {
228
- const currentTask = (manifest.tasks || []).find((task) => task.id === currentTaskId);
229
- if (currentTask && RESUMABLE_TASK_STATUSES.has(currentTask.status || 'pending')) {
230
- return currentTask;
231
- }
232
- }
233
-
234
- const runningTask = queues.runningTasks[0]
235
- || queues.blockedTasks.find((task) => RESUMABLE_TASK_STATUSES.has(task.status) && task.status !== 'pending');
236
- if (runningTask) {
237
- return (manifest.tasks || []).find((task) => task.id === runningTask.id) || runningTask;
238
- }
239
-
240
- const nextReady = queues.readyTasks[0];
241
- if (!nextReady) {
242
- return null;
243
- }
244
-
245
- return (manifest.tasks || []).find((task) => task.id === nextReady.id) || null;
246
- }
247
-
248
- function verificationCommandsForTask(task) {
249
- return dedupe([
250
- ...(task?.context?.commands || []),
251
- ...(task?.verification || []),
252
- ...(task?.run || [])
253
- ]);
254
- }
255
-
256
- function deriveCommandsToTrust({ manifest, nextTask, progress }) {
257
- if (nextTask) {
258
- return verificationCommandsForTask(nextTask);
259
- }
260
-
261
- if (progress.totalTasks > 0 && progress.completedTasks === progress.totalTasks) {
262
- return dedupe(
263
- (manifest.tasks || [])
264
- .filter((task) => isTaskCompletedStatus(task.status))
265
- .flatMap(verificationCommandsForTask)
266
- );
267
- }
268
-
269
- return [];
270
- }
271
-
272
- function markdownHasHeading(markdown, heading) {
273
- const escaped = heading.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
274
- return new RegExp(`(^|\\n)${escaped}\\s*(\\n|$)`, 'i').test(String(markdown || ''));
275
- }
276
-
277
- function resolveLegacyContractFragment(markdown) {
278
- const candidates = [
279
- ['## Progressive Disclosure Index', 'progressive-disclosure-index'],
280
- ['## Frozen Design Card', 'frozen-design-card'],
281
- ['## Approved Direction', 'approved-direction'],
282
- ['## Requirement Snapshot', 'requirement-snapshot'],
283
- ['## Success Criteria', 'success-criteria'],
284
- ['## Validation Strategy', 'validation-strategy'],
285
- ['## Review Gate', 'review-gate'],
286
- ['# DESIGN', 'design'],
287
- ['# ANALYSIS', 'analysis']
288
- ];
289
-
290
- const match = candidates.find(([heading]) => markdownHasHeading(markdown, heading));
291
- return match ? match[1] : '';
292
- }
293
-
294
- async function resolveCanonicalContractPath({ changeId, tasksPath, designPath, analysisPath }) {
295
- const isFix = changeId.startsWith('FIX-');
296
- const primaryHeading = isFix ? '## Root Cause Contract' : '## Contract Summary';
297
- const primaryFragment = isFix ? 'root-cause-contract' : 'contract-summary';
298
- const tasksText = await readText(tasksPath, '');
299
-
300
- if (markdownHasHeading(tasksText, primaryHeading)) {
301
- return {
302
- path: tasksPath,
303
- fragment: primaryFragment,
304
- usesTaskContract: true
305
- };
306
- }
307
-
308
- const preferredContractPaths = isFix
309
- ? [analysisPath, designPath]
310
- : [designPath, analysisPath];
311
- const legacyPath = (await Promise.all(
312
- preferredContractPaths.map(async (candidate) => ((await exists(candidate)) ? candidate : null))
313
- )).find(Boolean);
314
- const legacyText = legacyPath ? await readText(legacyPath, '') : '';
315
-
316
- return {
317
- path: legacyPath,
318
- fragment: resolveLegacyContractFragment(legacyText),
319
- usesTaskContract: false
320
- };
321
- }
322
-
323
- function deriveWorkflowNextAction({ progress, nextTask, report, reportPath, missingVerificationCommands }) {
324
- if (missingVerificationCommands) {
325
- return {
326
- skill: 'cc-plan',
327
- action: 'repair-task-verification',
328
- taskId: nextTask.id,
329
- reason: 'current task has no executable verification command',
330
- mustOpen: ['planning/task-manifest.json']
331
- };
332
- }
333
-
334
- if (nextTask) {
335
- const status = nextTask.status || 'pending';
336
- return {
337
- skill: 'cc-do',
338
- action: status === 'pending' ? 'execute-current-task' : 'resume-current-task',
339
- taskId: nextTask.id,
340
- reason: status === 'pending'
341
- ? 'a dependency-ready task is still pending'
342
- : `current task ${nextTask.id} is ${status} and should be resumed before selecting new work`
343
- };
344
- }
345
-
346
- if (progress.totalTasks > 0 && progress.completedTasks === progress.totalTasks) {
347
- const readiness = report ? deriveShipReadiness(report, { reportPath }) : null;
348
- if (readiness?.ready) {
349
- return {
350
- skill: 'cc-act',
351
- action: 'ship-or-handoff',
352
- reason: 'all tasks are complete and ship-readiness is ready'
353
- };
354
- }
355
-
356
- return {
357
- skill: 'cc-check',
358
- action: 'build-fresh-verdict',
359
- reason: report
360
- ? 'all tasks are complete but ship-readiness is blocked'
361
- : 'all tasks are complete but no report card exists',
362
- blockers: readiness?.blockers || ['missing report-card']
363
- };
364
- }
365
-
366
- return {
367
- skill: 'cc-plan',
368
- action: 'repair-task-graph',
369
- reason: 'no ready task can be selected from the current manifest'
370
- };
371
- }
372
-
373
- function getWorkflowContextArtifactRefs(repoRoot, changeId, options = {}) {
374
- const change = getChangePaths(repoRoot, changeId, options);
375
- return [
376
- getTasksMarkdownPath(repoRoot, changeId, options),
377
- path.join(change.planningDir, 'design.md'),
378
- path.join(change.planningDir, 'analysis.md'),
379
- getTaskManifestPath(repoRoot, changeId, options),
380
- path.join(change.changeDir, 'change-meta.json'),
381
- getRuntimeStatePath(repoRoot, changeId, options),
382
- getReportCardPath(repoRoot, changeId, options)
383
- ];
384
- }
385
-
386
- function getWorkflowContextRequiredArtifactRefs(repoRoot, changeId, options = {}) {
387
- return [
388
- getTaskManifestPath(repoRoot, changeId, options)
389
- ];
390
- }
391
-
392
- async function getWorkflowContext(repoRoot, changeId, options = {}) {
393
- const change = getChangePaths(repoRoot, changeId, options);
394
- const manifestPath = getTaskManifestPath(repoRoot, changeId, options);
395
- const reportPath = getReportCardPath(repoRoot, changeId, options);
396
- const statePath = getRuntimeStatePath(repoRoot, changeId, options);
397
- const tasksPath = getTasksMarkdownPath(repoRoot, changeId, options);
398
- const changeMetaPath = path.join(change.changeDir, 'change-meta.json');
399
- const designPath = path.join(change.planningDir, 'design.md');
400
- const analysisPath = path.join(change.planningDir, 'analysis.md');
401
- const contractResolution = await resolveCanonicalContractPath({
402
- changeId,
403
- tasksPath,
404
- designPath,
405
- analysisPath
406
- });
407
- const canonicalContractPath = contractResolution.path;
408
-
409
- const [manifest, report, state, changeMeta] = await Promise.all([
410
- readWorkflowArtifact(manifestPath),
411
- readWorkflowArtifact(reportPath, { required: false }),
412
- readWorkflowArtifact(statePath, { required: false }),
413
- readWorkflowArtifact(changeMetaPath, { required: false })
414
- ]);
415
- const progress = deriveTaskProgress(manifest.tasks || []);
416
- const queues = deriveTaskQueues(manifest);
417
- const nextTask = selectNextTask(manifest, queues);
418
- const relativeContractPath = canonicalContractPath ? relativePath(repoRoot, canonicalContractPath) : null;
419
- const relativeDesignPath = await maybeRelativePath(repoRoot, designPath);
420
- const relativeAnalysisPath = await maybeRelativePath(repoRoot, analysisPath);
421
- const relativeManifestPath = relativePath(repoRoot, manifestPath);
422
- const relativeTasksPath = await maybeRelativePath(repoRoot, tasksPath);
423
- const relativeChangeMetaPath = await maybeRelativePath(repoRoot, changeMetaPath);
424
- const relativeStatePath = await maybeRelativePath(repoRoot, statePath);
425
- const relativeReportPath = await maybeRelativePath(repoRoot, reportPath);
426
- const relativePrimaryContractRef = relativeContractPath && contractResolution.fragment
427
- ? withFragment(relativeContractPath, contractResolution.fragment)
428
- : relativeContractPath;
429
- const relativeContractRef = relativeContractPath && contractResolution.fragment
430
- ? withFragment(relativeContractPath, contractResolution.fragment)
431
- : relativeContractPath;
432
- const relativeContractIndexRef = contractResolution.usesTaskContract && relativeContractPath
433
- ? withFragment(relativeContractPath, 'progressive-disclosure-index')
434
- : relativeContractRef;
435
- const refs = {
436
- repoRoot,
437
- relativeContractPath,
438
- relativeContractRef,
439
- relativeContractIndexRef,
440
- relativePrimaryContractRef,
441
- relativeDesignPath,
442
- relativeAnalysisPath,
443
- relativeTasksPath,
444
- relativeManifestPath,
445
- relativeChangeMetaPath,
446
- relativeStatePath,
447
- relativeReportPath
448
- };
449
- const queryCommand = [
450
- 'cc-devflow query workflow-context',
451
- `--change ${changeId}`,
452
- options.changeKey ? `--change-key ${change.changeKey}` : '',
453
- '--cwd <repo-root>'
454
- ].filter(Boolean).join(' ');
455
- const taskReadFiles = normalizeTaskReadFiles(nextTask?.context?.readFiles || [], refs);
456
- const taskDeepOpen = taskReadFiles.filter((filePath) => !isArtifactReadFile(filePath, refs));
457
- const source = await buildSourceIndex({
458
- manifestPath,
459
- canonicalContractPath,
460
- tasksPath,
461
- changeMetaPath,
462
- reportPath,
463
- refs
464
- });
465
- const defaultOpen = await validateOpenRefs(
466
- buildDefaultOpenRefs({ nextTask, refs, source }),
467
- { repoRoot }
468
- );
469
- const taskCommands = deriveCommandsToTrust({ manifest, nextTask, progress });
470
- const missingVerificationCommands = Boolean(nextTask && taskCommands.length === 0);
471
- const currentTaskSummary = summarizeTask(nextTask);
472
- const mustNotForget = await buildMustNotForget({
473
- manifest,
474
- nextTask,
475
- report,
476
- source,
477
- refs,
478
- canonicalContractPath,
479
- missingVerificationCommands
480
- });
481
- const packetOnly = await buildPacketOnly({
482
- canonicalContractPath,
483
- manifest,
484
- currentTaskSummary,
485
- nextTask,
486
- report,
487
- mustNotForget
488
- });
489
- const deepOpen = await validateDeepOpenGroups([
490
- deepOpenGroup({
491
- when: 'scope_or_contract_uncertain',
492
- conditions: [
493
- 'confidence.scope < 0.85',
494
- "task.type in ['ARCH', 'SECURITY', 'DATA_MIGRATION']",
495
- 'user_request_changes_scope == true',
496
- 'do_not_redecide_missing == true'
497
- ],
498
- refs: [
499
- { ref: relativeContractPath, reason: 'full contract for scope and do-not-redecide disputes' },
500
- { ref: withFragment(relativeContractPath, 'approved-direction'), reason: 'approved direction section' },
501
- { ref: relativeTasksPath, reason: 'task protocol and handoff context' },
502
- { ref: withFragment(relativeChangeMetaPath, '/risk'), reason: 'risk and spec sync context' }
503
- ].filter((entry) => entry.ref),
504
- source
505
- }),
506
- deepOpenGroup({
507
- when: 'task_or_dependency_uncertain',
508
- conditions: [
509
- 'currentTask == null',
510
- 'dependency_state_unclear == true',
511
- 'active_phase_unclear == true'
512
- ],
513
- refs: [
514
- { ref: withFragment(relativeManifestPath, nextTask ? `/tasks/${nextTask.id}` : '/summary'), reason: 'task graph source of truth' },
515
- { ref: withFragment(relativeTasksPath, nextTask ? `task.${nextTask.id}` : 'execution-handoff'), reason: 'human task block and execution protocol' }
516
- ],
517
- source,
518
- command: queryCommand
519
- }),
520
- deepOpenGroup({
521
- when: 'parallel_or_touch_ownership_uncertain',
522
- conditions: [
523
- 'task.touches.length > 3',
524
- 'parallel_candidates.length > 1',
525
- 'current_file_not_listed_in_task_files == true',
526
- 'touch_paths_overlap == true'
527
- ],
528
- refs: [
529
- { ref: relativeTasksPath, reason: 'task ownership and slicing details' },
530
- { ref: relativeManifestPath, reason: 'machine task graph and touched files' }
531
- ],
532
- source,
533
- command: `bash .claude/skills/cc-do/scripts/select-ready-tasks.sh --manifest ${relativeManifestPath}`
534
- }),
535
- deepOpenGroup({
536
- when: 'verification_or_recovery_needed',
537
- conditions: [
538
- 'verification_failed == true',
539
- 'missingVerificationCommands == true',
540
- 'report.reroute != none',
541
- 'runtime_log_needed == true'
542
- ],
543
- refs: [
544
- { ref: relativeTasksPath, reason: 'current task status and completion marks' },
545
- { ref: relativeReportPath, reason: 'latest review gate verdict' },
546
- { ref: relativeManifestPath, reason: 'verification command source' }
547
- ].filter((entry) => entry.ref),
548
- source
549
- }),
550
- deepOpenGroup({
551
- when: 'implementation_details_needed',
552
- conditions: [
553
- 'agent_needs_code_context == true',
554
- 'current_file_not_listed_in_task_files == true'
555
- ],
556
- refs: taskDeepOpen.map((ref) => ({ ref, reason: 'selected task implementation context' })),
557
- source
558
- }),
559
- deepOpenGroup({
560
- when: 'delivery_or_ship_readiness_needed',
561
- conditions: [
562
- 'progress.completedTasks == progress.totalTasks',
563
- 'nextAction.skill == cc-act',
564
- 'ship_mode_unclear == true'
565
- ],
566
- refs: [
567
- { ref: relativeReportPath, reason: 'ship-readiness verdict input' },
568
- { ref: 'devflow/changes/<change-key>/handoff/', reason: 'delivery handoff artifacts' }
569
- ],
570
- source,
571
- command: `cc-devflow query ship-readiness --change ${changeId}${options.changeKey ? ` --change-key ${change.changeKey}` : ''} --cwd <repo-root>`
572
- })
573
- ], { repoRoot });
574
- const nextAction = deriveWorkflowNextAction({
575
- progress,
576
- nextTask,
577
- report,
578
- reportPath,
579
- missingVerificationCommands
580
- });
581
- const sourceHashes = buildSourceHashes(source);
582
-
583
- return {
584
- schemaVersion: 'workflow-context.v2',
585
- changeId: manifest.changeId || changeId,
586
- changeKey: change.changeKey,
587
- generatedAt: new Date().toISOString(),
588
- source,
589
- legacyFallback: contractResolution.usesTaskContract ? false : Boolean(canonicalContractPath),
590
- goal: manifest.goal || state?.goal || '',
591
- route: changeId.startsWith('FIX-') ? 'IDCA' : 'PDCA',
592
- lifecycle: {
593
- stage: state ? deriveLifecycleStage({
594
- state,
595
- manifest,
596
- report,
597
- hasPrBrief: await exists(getIntentPrBriefPath(repoRoot, changeId, options))
598
- }) : null,
599
- status: state?.status || null,
600
- approval: state ? getApprovalState(state, manifest) : null
601
- },
602
- progress,
603
- nextAction,
604
- currentTask: currentTaskSummary,
605
- queues,
606
- progressiveDisclosure: {
607
- mode: 'compact-first',
608
- rule: 'Use this as a context index: packetOnly routes, mustNotForget guards judgment, source artifacts decide disputed facts. If you need to guess, open the referenced source first.',
609
- contextBudget: {
610
- packetFields: Object.keys(packetOnly).length,
611
- defaultRefs: defaultOpen.length,
612
- defaultCommands: taskCommands.length,
613
- deepOpenGroups: deepOpen.length,
614
- deepOpeners: 6
615
- },
616
- packetOnly,
617
- mustNotForget,
618
- sourceHashes,
619
- stalenessCheck: {
620
- policy: 'if any source hash differs from sourceHashes, rerun workflow-context before acting',
621
- command: queryCommand
622
- },
623
- defaultOpen,
624
- deepOpen,
625
- commandsToTrust: taskCommands,
626
- missingVerificationCommands,
627
- manifestIssue: missingVerificationCommands
628
- ? 'current task has no executable verification command'
629
- : null,
630
- failClosed: [
631
- 'If manifest, contract, change-meta, report-card, tasks, or Git state changed after packet generation, rerun workflow-context.',
632
- 'If current task status is running, in_progress, active, blocked, needs_fix, or failed, resume it before selecting another ready task.',
633
- 'If verification command is missing, route to cc-plan repair-task-verification instead of cc-do.',
634
- 'If scope, ownership, dependency, or source confidence is uncertain, open the source artifact before acting.'
635
- ],
636
- uncertaintyPolicy: {
637
- mode: 'open-source-before-acting',
638
- openOn: [
639
- 'scope uncertainty',
640
- 'task ambiguity',
641
- 'dependency ambiguity',
642
- 'missing verification',
643
- 'changed files outside manifest',
644
- 'test failure',
645
- 'user changes requirement',
646
- 'security or data migration impact'
647
- ]
648
- },
649
- openWhen: await Promise.all([
650
- {
651
- trigger: 'the current task, dependency state, or active phase is unclear',
652
- conditions: [
653
- 'currentTask == null',
654
- 'dependency_state_unclear == true',
655
- 'active_phase_unclear == true'
656
- ],
657
- open: dedupeOpenRefs([
658
- openRef(nextTask ? withFragment(relativeManifestPath, `/tasks/${nextTask.id}`) : withFragment(relativeManifestPath, '/summary'), 'task graph source of truth', source),
659
- openRef(withFragment(relativeTasksPath, nextTask ? `task.${nextTask.id}` : 'execution-handoff'), 'task block and execution handoff', source)
660
- ]),
661
- command: queryCommand
662
- },
663
- {
664
- trigger: 'scope, design, root cause, or do-not-redecide contract is disputed',
665
- conditions: [
666
- 'confidence.scope < 0.85',
667
- 'user_request_changes_scope == true',
668
- 'do_not_redecide_missing == true'
669
- ],
670
- open: dedupeOpenRefs([
671
- openRef(relativeContractPath, 'full contract for scope and do-not-redecide disputes', source),
672
- openRef(relativeTasksPath, 'task protocol and handoff context', source),
673
- openRef(withFragment(relativeChangeMetaPath, '/risk'), 'risk and spec sync context', source)
674
- ])
675
- },
676
- {
677
- trigger: 'parallel dispatch, touched-path ownership, or task slicing is disputed',
678
- conditions: [
679
- 'parallel_candidates.length > 1',
680
- 'touch_paths_overlap == true',
681
- 'current_file_not_listed_in_task_files == true'
682
- ],
683
- open: dedupeOpenRefs([
684
- openRef(relativeTasksPath, 'task ownership and slicing details', source),
685
- openRef(relativeManifestPath, 'machine task graph and touched files', source)
686
- ]),
687
- command: `bash .claude/skills/cc-do/scripts/select-ready-tasks.sh --manifest ${relativeManifestPath}`
688
- },
689
- {
690
- trigger: 'task evidence, review gates, or recovery state is needed',
691
- conditions: [
692
- 'verification_failed == true',
693
- 'report.reroute != none',
694
- 'runtime_log_needed == true'
695
- ],
696
- open: dedupeOpenRefs([
697
- openRef(relativeTasksPath, 'current task status and completion marks', source),
698
- openRef(relativeReportPath, 'latest review gate verdict', source),
699
- openRef(relativeManifestPath, 'verification command source', source)
700
- ])
701
- },
702
- {
703
- trigger: 'implementation file details are needed for the selected task',
704
- conditions: [
705
- 'agent_needs_code_context == true',
706
- 'current_file_not_listed_in_task_files == true'
707
- ],
708
- open: dedupeOpenRefs(taskDeepOpen.map((ref) => openRef(ref, 'selected task implementation context', source)))
709
- },
710
- {
711
- trigger: 'all tasks are complete and delivery can start',
712
- conditions: [
713
- 'progress.completedTasks == progress.totalTasks',
714
- 'nextAction.skill == cc-act',
715
- 'ship_mode_unclear == true'
716
- ],
717
- open: dedupeOpenRefs([
718
- openRef(relativeReportPath, 'ship-readiness verdict input', source),
719
- openRef('devflow/changes/<change-key>/handoff/', 'delivery handoff artifacts', source)
720
- ]),
721
- command: `cc-devflow query ship-readiness --change ${changeId}${options.changeKey ? ` --change-key ${change.changeKey}` : ''} --cwd <repo-root>`
722
- }
723
- ].map(async (entry) => ({
724
- ...entry,
725
- open: await validateOpenRefs(entry.open, { repoRoot })
726
- })))
727
- },
728
- artifactRefs: dedupe([
729
- relativeContractPath,
730
- relativeTasksPath,
731
- relativeManifestPath,
732
- relativeChangeMetaPath,
733
- relativeReportPath
734
- ]),
735
- planningMeta: {
736
- planVersion: manifest.metadata?.planVersion || null,
737
- reqPlanSkillVersion: manifest.planningMeta?.reqPlanSkillVersion || null,
738
- sourceCapability: changeMeta?.spec?.primaryCapability || null,
739
- specSyncStatus: changeMeta?.spec?.syncStatus || null
740
- }
741
- };
742
- }
743
-
744
- module.exports = {
745
- getWorkflowContext,
746
- getWorkflowContextArtifactRefs,
747
- getWorkflowContextRequiredArtifactRefs
748
- };