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,545 +0,0 @@
1
- /**
2
- * [INPUT]: workflow-context 的源 artifact 路径、manifest、当前 task、report。
3
- * [OUTPUT]: 生成 context index 所需的 source hash、must-not-forget、open refs 与 digest。
4
- * [POS]: skill runtime 的上下文索引构造层;只做只读索引,不决定 workflow 路由。
5
- * [PROTOCOL]: 变更时更新此头部,然后检查 CLAUDE.md
6
- */
7
-
8
- const crypto = require('crypto');
9
- const fs = require('fs');
10
- const path = require('path');
11
-
12
- function dedupe(values) {
13
- return [...new Set((values || []).filter(Boolean))];
14
- }
15
-
16
- function stableStringify(value) {
17
- if (Array.isArray(value)) {
18
- return `[${value.map(stableStringify).join(',')}]`;
19
- }
20
-
21
- if (value && typeof value === 'object') {
22
- return `{${Object.keys(value).sort().map((key) => (
23
- `${JSON.stringify(key)}:${stableStringify(value[key])}`
24
- )).join(',')}}`;
25
- }
26
-
27
- return JSON.stringify(value);
28
- }
29
-
30
- function digestValue(value) {
31
- if (value === null || value === undefined) {
32
- return null;
33
- }
34
-
35
- return crypto
36
- .createHash('sha256')
37
- .update(stableStringify(value))
38
- .digest('hex')
39
- .slice(0, 16);
40
- }
41
-
42
- async function fileExists(filePath) {
43
- if (!filePath) {
44
- return false;
45
- }
46
-
47
- try {
48
- await fs.promises.access(filePath);
49
- return true;
50
- } catch {
51
- return false;
52
- }
53
- }
54
-
55
- async function hashFile(filePath) {
56
- if (!(await fileExists(filePath))) {
57
- return null;
58
- }
59
-
60
- const bytes = await fs.promises.readFile(filePath);
61
- return `sha256:${crypto
62
- .createHash('sha256')
63
- .update(bytes)
64
- .digest('hex')}`;
65
- }
66
-
67
- async function digestFile(filePath) {
68
- const hash = await hashFile(filePath);
69
- return hash ? hash.replace(/^sha256:/, '').slice(0, 16) : null;
70
- }
71
-
72
- function withFragment(filePath, fragment) {
73
- return filePath && fragment ? `${filePath}#${fragment}` : filePath;
74
- }
75
-
76
- function splitRef(ref) {
77
- const [filePath, fragment = ''] = String(ref || '').split('#');
78
- return { filePath, fragment };
79
- }
80
-
81
- function limitList(values, limit = 6) {
82
- return dedupe(values)
83
- .map((value) => String(value || '').trim())
84
- .filter(Boolean)
85
- .slice(0, limit);
86
- }
87
-
88
- function stripMarkdownBullet(line) {
89
- return String(line || '')
90
- .replace(/^\s*[-*]\s+/, '')
91
- .replace(/`/g, '')
92
- .trim();
93
- }
94
-
95
- async function readTextIfExists(filePath) {
96
- if (!(await fileExists(filePath))) {
97
- return '';
98
- }
99
-
100
- return fs.promises.readFile(filePath, 'utf8');
101
- }
102
-
103
- function extractHeadingSection(markdown, headingPattern) {
104
- const lines = String(markdown || '').split('\n');
105
- const start = lines.findIndex((line) => headingPattern.test(line));
106
- if (start === -1) {
107
- return '';
108
- }
109
-
110
- const level = (lines[start].match(/^#+/) || [''])[0].length;
111
- const end = lines.findIndex((line, index) => (
112
- index > start
113
- && /^#+\s/.test(line)
114
- && (line.match(/^#+/) || [''])[0].length <= level
115
- ));
116
-
117
- return lines.slice(start, end === -1 ? lines.length : end).join('\n');
118
- }
119
-
120
- function extractBulletsFromSections(markdown, headingPatterns, limit = 6) {
121
- const bullets = [];
122
- for (const pattern of headingPatterns) {
123
- const section = extractHeadingSection(markdown, pattern);
124
- if (!section) {
125
- continue;
126
- }
127
-
128
- for (const line of section.split('\n')) {
129
- if (/^\s*[-*]\s+/.test(line)) {
130
- bullets.push(stripMarkdownBullet(line));
131
- }
132
- }
133
- }
134
-
135
- return limitList(bullets, limit);
136
- }
137
-
138
- function extractNestedBulletsAfterMarker(markdown, markerPattern, limit = 6) {
139
- const lines = String(markdown || '').split('\n');
140
- const markerIndex = lines.findIndex((line) => markerPattern.test(line));
141
- if (markerIndex === -1) {
142
- return [];
143
- }
144
-
145
- const bullets = [];
146
- for (let index = markerIndex + 1; index < lines.length; index += 1) {
147
- const line = lines[index];
148
- if (/^#+\s/.test(line)) {
149
- break;
150
- }
151
- if (!/^\s*[-*]\s+/.test(line)) {
152
- continue;
153
- }
154
- if (/^\s{2,}[-*]\s+/.test(line)) {
155
- bullets.push(stripMarkdownBullet(line));
156
- continue;
157
- }
158
- if (bullets.length > 0) {
159
- break;
160
- }
161
- }
162
-
163
- return limitList(bullets, limit);
164
- }
165
-
166
- function sourceHashForRef(source, ref) {
167
- const { filePath } = splitRef(ref);
168
- const match = Object.values(source || {}).find((entry) => entry?.path === filePath);
169
- return match?.hash || null;
170
- }
171
-
172
- function openRef(ref, reason, source) {
173
- if (!ref) {
174
- return null;
175
- }
176
-
177
- return {
178
- ref,
179
- reason,
180
- sourceHash: sourceHashForRef(source, ref)
181
- };
182
- }
183
-
184
- function slugifyHeading(value) {
185
- return String(value || '')
186
- .trim()
187
- .toLowerCase()
188
- .replace(/`/g, '')
189
- .replace(/[^\p{L}\p{N}\s-]/gu, '')
190
- .replace(/\s+/g, '-');
191
- }
192
-
193
- function markdownHeadings(markdown) {
194
- return String(markdown || '')
195
- .split('\n')
196
- .map((line) => {
197
- const match = line.match(/^#+\s+(.+?)\s*$/);
198
- return match ? match[1].trim() : null;
199
- })
200
- .filter(Boolean);
201
- }
202
-
203
- function jsonPointerExists(value, pointer) {
204
- if (!pointer) {
205
- return true;
206
- }
207
-
208
- if (pointer === '/summary') {
209
- return true;
210
- }
211
-
212
- if (pointer.startsWith('/tasks/')) {
213
- const taskId = pointer.slice('/tasks/'.length);
214
- return Array.isArray(value?.tasks) && value.tasks.some((task) => task.id === taskId);
215
- }
216
-
217
- return pointer
218
- .split('/')
219
- .filter(Boolean)
220
- .reduce((current, segment) => {
221
- if (current === undefined || current === null) {
222
- return undefined;
223
- }
224
-
225
- const key = segment.replace(/~1/g, '/').replace(/~0/g, '~');
226
- return current[key];
227
- }, value) !== undefined;
228
- }
229
-
230
- function fallbackMarkdownRef(relativePath, headings) {
231
- const preferred = [
232
- 'Progressive Disclosure Index',
233
- 'Frozen Design Card',
234
- 'Approved Direction',
235
- 'Requirement Snapshot',
236
- 'Validation',
237
- 'Main Risk'
238
- ];
239
- const heading = preferred.find((candidate) => (
240
- headings.some((actual) => slugifyHeading(actual) === slugifyHeading(candidate))
241
- )) || headings[0];
242
-
243
- return heading ? withFragment(relativePath, slugifyHeading(heading)) : relativePath;
244
- }
245
-
246
- async function validateRef(entry, repoRoot) {
247
- if (!entry?.ref || entry.ref.includes('<change-key>')) {
248
- return entry;
249
- }
250
-
251
- const { filePath, fragment } = splitRef(entry.ref);
252
- const absolutePath = path.join(repoRoot, filePath);
253
- if (!(await fileExists(absolutePath))) {
254
- return {
255
- ...entry,
256
- exists: false,
257
- manifestIssue: `missing referenced artifact: ${filePath}`
258
- };
259
- }
260
-
261
- if (!fragment) {
262
- return { ...entry, exists: true };
263
- }
264
-
265
- if (filePath.endsWith('.json')) {
266
- try {
267
- const value = JSON.parse(await fs.promises.readFile(absolutePath, 'utf8'));
268
- const exists = jsonPointerExists(value, fragment);
269
- return exists ? { ...entry, exists: true } : {
270
- ...entry,
271
- exists: false,
272
- fallbackRef: filePath,
273
- manifestIssue: `missing JSON pointer ${fragment} in ${filePath}`
274
- };
275
- } catch {
276
- return {
277
- ...entry,
278
- exists: false,
279
- fallbackRef: filePath,
280
- manifestIssue: `invalid JSON while validating ${entry.ref}`
281
- };
282
- }
283
- }
284
-
285
- if (filePath.endsWith('.md')) {
286
- const text = await fs.promises.readFile(absolutePath, 'utf8');
287
- const headings = markdownHeadings(text);
288
- const exists = headings.some((heading) => slugifyHeading(heading) === slugifyHeading(fragment));
289
- return exists ? { ...entry, exists: true } : {
290
- ...entry,
291
- exists: false,
292
- fallbackRef: fallbackMarkdownRef(filePath, headings),
293
- manifestIssue: `missing markdown section ${fragment} in ${filePath}`
294
- };
295
- }
296
-
297
- return { ...entry, exists: true };
298
- }
299
-
300
- async function validateOpenRefs(entries, { repoRoot }) {
301
- return Promise.all((entries || []).map((entry) => validateRef(entry, repoRoot)));
302
- }
303
-
304
- async function validateDeepOpenGroups(groups, { repoRoot }) {
305
- return Promise.all((groups || []).map(async (group) => ({
306
- ...group,
307
- refs: await validateOpenRefs(group.refs, { repoRoot })
308
- })));
309
- }
310
-
311
- function dedupeOpenRefs(entries) {
312
- const seen = new Set();
313
- return (entries || []).filter((entry) => {
314
- if (!entry?.ref || seen.has(entry.ref)) {
315
- return false;
316
- }
317
- seen.add(entry.ref);
318
- return true;
319
- });
320
- }
321
-
322
- function buildDefaultOpenRefs({ nextTask, refs, source }) {
323
- const taskId = nextTask?.id || null;
324
- return dedupeOpenRefs([
325
- openRef(
326
- refs.relativePrimaryContractRef,
327
- 'primary task contract',
328
- source
329
- ),
330
- openRef(
331
- taskId ? withFragment(refs.relativeManifestPath, `/tasks/${taskId}`) : withFragment(refs.relativeManifestPath, '/summary'),
332
- taskId ? 'current task source of truth' : 'task graph summary source of truth',
333
- source
334
- ),
335
- openRef(
336
- refs.relativeContractIndexRef
337
- || (refs.relativeContractPath ? withFragment(refs.relativeContractPath, 'progressive-disclosure-index') : null),
338
- 'contract index for non-negotiable design constraints',
339
- source
340
- ),
341
- openRef(
342
- refs.relativeChangeMetaPath ? withFragment(refs.relativeChangeMetaPath, '/spec') : null,
343
- 'scope and spec-sync status',
344
- source
345
- ),
346
- openRef(
347
- refs.relativeReportPath ? withFragment(refs.relativeReportPath, '/verdict') : null,
348
- 'latest verification verdict',
349
- source
350
- )
351
- ]);
352
- }
353
-
354
- function deepOpenGroup({ when, conditions, refs: openRefs, source, command }) {
355
- const group = {
356
- when,
357
- conditions,
358
- refs: dedupeOpenRefs(openRefs.map((entry) => (
359
- typeof entry === 'string'
360
- ? openRef(entry, when, source)
361
- : openRef(entry.ref, entry.reason || when, source)
362
- )))
363
- };
364
-
365
- if (command) {
366
- group.command = command;
367
- }
368
-
369
- return group;
370
- }
371
-
372
- function summarizeManifestForDigest(manifest) {
373
- return {
374
- changeId: manifest.changeId || null,
375
- currentTaskId: manifest.currentTaskId || null,
376
- tasks: (manifest.tasks || []).map((task) => ({
377
- id: task.id,
378
- status: task.status || 'pending',
379
- phase: task.phase || 0,
380
- dependsOn: task.dependsOn || [],
381
- files: task.files || [],
382
- verification: task.verification || []
383
- }))
384
- };
385
- }
386
-
387
- function summarizeEvidenceForDigest({ nextTask, report }) {
388
- return {
389
- currentTaskEvidence: nextTask?.evidence || [],
390
- report: report ? {
391
- overall: report.overall || null,
392
- verdict: report.verdict || null,
393
- reroute: report.reroute || null,
394
- specSyncReady: report.specSyncReady === true,
395
- blockingFindings: report.blockingFindings || [],
396
- gaps: report.gaps || []
397
- } : null
398
- };
399
- }
400
-
401
- async function buildPacketOnly({
402
- canonicalContractPath,
403
- manifest,
404
- currentTaskSummary,
405
- nextTask,
406
- report,
407
- mustNotForget
408
- }) {
409
- return {
410
- contractDigest: await digestFile(canonicalContractPath),
411
- manifestDigest: digestValue(summarizeManifestForDigest(manifest)),
412
- currentTaskDigest: digestValue(currentTaskSummary),
413
- evidenceDigest: digestValue(summarizeEvidenceForDigest({ nextTask, report })),
414
- mustNotForgetDigest: digestValue(mustNotForget)
415
- };
416
- }
417
-
418
- async function buildSourceIndex({
419
- manifestPath,
420
- canonicalContractPath,
421
- tasksPath,
422
- changeMetaPath,
423
- reportPath,
424
- refs
425
- }) {
426
- const entries = {
427
- manifest: {
428
- path: refs.relativeManifestPath,
429
- hash: await hashFile(manifestPath)
430
- },
431
- contract: refs.relativeContractPath ? {
432
- path: refs.relativeContractPath,
433
- hash: await hashFile(canonicalContractPath)
434
- } : null,
435
- tasks: refs.relativeTasksPath ? {
436
- path: refs.relativeTasksPath,
437
- hash: await hashFile(tasksPath)
438
- } : null,
439
- changeMeta: refs.relativeChangeMetaPath ? {
440
- path: refs.relativeChangeMetaPath,
441
- hash: await hashFile(changeMetaPath)
442
- } : null,
443
- reportCard: refs.relativeReportPath ? {
444
- path: refs.relativeReportPath,
445
- hash: await hashFile(reportPath)
446
- } : null
447
- };
448
-
449
- return Object.fromEntries(Object.entries(entries).filter(([, value]) => value));
450
- }
451
-
452
- function buildSourceHashes(source) {
453
- return Object.fromEntries(
454
- Object.values(source || {})
455
- .filter((entry) => entry?.path && entry.hash)
456
- .map((entry) => [entry.path, entry.hash])
457
- );
458
- }
459
-
460
- function sourcePointer(ref, source) {
461
- return {
462
- ref,
463
- hash: sourceHashForRef(source, ref)
464
- };
465
- }
466
-
467
- function sourcedValue(value, ref, source) {
468
- return {
469
- value,
470
- source: sourcePointer(ref, source)
471
- };
472
- }
473
-
474
- async function buildMustNotForget({
475
- manifest,
476
- nextTask,
477
- report,
478
- source,
479
- refs,
480
- canonicalContractPath,
481
- missingVerificationCommands
482
- }) {
483
- const contractText = await readTextIfExists(canonicalContractPath);
484
- const taskRef = nextTask
485
- ? withFragment(refs.relativeManifestPath, `/tasks/${nextTask.id}`)
486
- : withFragment(refs.relativeManifestPath, '/summary');
487
- const contractRef = refs.relativeContractPath
488
- ? (refs.relativeContractRef || withFragment(refs.relativeContractPath, 'contract-index'))
489
- : taskRef;
490
- const goal = manifest.goal || 'Deliver planned requirement changes safely.';
491
- const taskContract = nextTask?.contract || {};
492
- const taskNotes = nextTask?.context?.notes || [];
493
- const designDecisions = [
494
- ...extractNestedBulletsAfterMarker(contractText, /must not re-decide|Frozen decisions/i),
495
- ...extractBulletsFromSections(contractText, [/^##\s+Approved Direction/i, /^##\s+Frozen Design Card/i], 6)
496
- ];
497
- const risks = [
498
- ...extractBulletsFromSections(contractText, [/^##\s+Main Risk/i, /^##\s+Success Criteria/i], 6),
499
- ...(report?.blockingFindings || []),
500
- ...(report?.gaps || [])
501
- ];
502
- const nonNegotiables = limitList([
503
- 'workflow-context is read-only and must not mutate source artifacts',
504
- 'source-of-truth artifacts remain authoritative; chat memory never replaces them',
505
- 'ship-readiness remains the source of truth for cc-act routing',
506
- 'current task state comes from task-manifest.json, not the ready queue alone',
507
- missingVerificationCommands ? 'verification commands are required before execution can continue' : null,
508
- ...taskNotes.filter((note) => /do not|must|keep|only|without/i.test(note))
509
- ]);
510
- const doNotRedecide = limitList([
511
- ...(taskContract.doNotRedecide || []),
512
- ...designDecisions
513
- ]);
514
- const acceptanceGates = limitList([
515
- ...(nextTask?.acceptance || []),
516
- ...(nextTask?.verification || []),
517
- nextTask?.testSeam?.publicVerificationPath || null
518
- ]);
519
- const knownRisks = limitList([
520
- ...risks,
521
- 'if scope, task ownership, or source hashes are uncertain, open the source artifact before acting'
522
- ]);
523
-
524
- return {
525
- goal: sourcedValue(goal, withFragment(refs.relativeManifestPath, '/goal'), source),
526
- nonNegotiables: nonNegotiables.map((value) => sourcedValue(value, contractRef, source)),
527
- doNotRedecide: doNotRedecide.map((value) => sourcedValue(value, contractRef, source)),
528
- acceptanceGates: acceptanceGates.map((value) => sourcedValue(value, taskRef, source)),
529
- knownRisks: knownRisks.map((value) => sourcedValue(value, contractRef, source))
530
- };
531
- }
532
-
533
- module.exports = {
534
- buildDefaultOpenRefs,
535
- buildMustNotForget,
536
- buildPacketOnly,
537
- buildSourceHashes,
538
- buildSourceIndex,
539
- dedupeOpenRefs,
540
- deepOpenGroup,
541
- openRef,
542
- validateDeepOpenGroups,
543
- validateOpenRefs,
544
- withFragment
545
- };