cc-devflow 4.5.10 → 4.5.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (187) hide show
  1. package/.claude/skills/cc-act/CHANGELOG.md +23 -0
  2. package/.claude/skills/cc-act/PLAYBOOK.md +17 -269
  3. package/.claude/skills/cc-act/SKILL.md +38 -418
  4. package/.claude/skills/cc-act/assets/PROJECT_POSTMORTEM_INDEX_TEMPLATE.md +2 -13
  5. package/.claude/skills/cc-act/assets/PROJECT_POSTMORTEM_TEMPLATE.md +1 -9
  6. package/.claude/skills/cc-act/assets/PR_BRIEF_TEMPLATE.md +21 -177
  7. package/.claude/skills/cc-act/references/closure-contract.md +12 -63
  8. package/.claude/skills/cc-act/references/git-commit-guidelines.md +5 -5
  9. package/.claude/skills/cc-act/scripts/cc-act-common.sh +5 -322
  10. package/.claude/skills/cc-act/scripts/detect-ship-target.sh +11 -2
  11. package/.claude/skills/cc-act/scripts/inspect-git-index.sh +58 -0
  12. package/.claude/skills/cc-act/scripts/render-pr-brief.sh +40 -440
  13. package/.claude/skills/cc-act/scripts/verify-act-gate.sh +10 -50
  14. package/.claude/skills/cc-check/CHANGELOG.md +24 -0
  15. package/.claude/skills/cc-check/PLAYBOOK.md +19 -273
  16. package/.claude/skills/cc-check/SKILL.md +33 -454
  17. package/.claude/skills/cc-check/references/review-contract.md +12 -147
  18. package/.claude/skills/cc-dev/CHANGELOG.md +20 -0
  19. package/.claude/skills/cc-dev/PLAYBOOK.md +1 -1
  20. package/.claude/skills/cc-dev/SKILL.md +52 -130
  21. package/.claude/skills/cc-dev/scripts/resolve-cc-devflow.sh +181 -0
  22. package/.claude/skills/cc-do/CHANGELOG.md +17 -0
  23. package/.claude/skills/cc-do/PLAYBOOK.md +19 -113
  24. package/.claude/skills/cc-do/SKILL.md +39 -236
  25. package/.claude/skills/cc-do/references/execution-recovery.md +15 -109
  26. package/.claude/skills/cc-do/scripts/cc-do-common.sh +5 -57
  27. package/.claude/skills/cc-do/scripts/check-task-status.sh +35 -65
  28. package/.claude/skills/cc-do/scripts/mark-task-complete.sh +9 -46
  29. package/.claude/skills/cc-do/scripts/select-ready-tasks.sh +29 -97
  30. package/.claude/skills/cc-investigate/CHANGELOG.md +23 -0
  31. package/.claude/skills/cc-investigate/PLAYBOOK.md +20 -180
  32. package/.claude/skills/cc-investigate/SKILL.md +65 -513
  33. package/.claude/skills/cc-investigate/assets/TASKS_TEMPLATE.md +48 -95
  34. package/.claude/skills/cc-investigate/references/investigation-contract.md +14 -217
  35. package/.claude/skills/cc-next/CHANGELOG.md +6 -0
  36. package/.claude/skills/cc-next/PLAYBOOK.md +12 -8
  37. package/.claude/skills/cc-next/SKILL.md +34 -140
  38. package/.claude/skills/cc-plan/CHANGELOG.md +29 -0
  39. package/.claude/skills/cc-plan/PLAYBOOK.md +22 -161
  40. package/.claude/skills/cc-plan/SKILL.md +47 -640
  41. package/.claude/skills/cc-plan/assets/TASKS_TEMPLATE.md +30 -225
  42. package/.claude/skills/cc-plan/references/planning-contract.md +24 -160
  43. package/.claude/skills/cc-plan/scripts/next-change-key.sh +8 -44
  44. package/.claude/skills/cc-plan/scripts/parse-task-dependencies.js +2 -2
  45. package/.claude/skills/cc-plan/scripts/validate-scope.sh +1 -1
  46. package/.claude/skills/cc-pr-land/SKILL.md +14 -114
  47. package/.claude/skills/cc-pr-review/CHANGELOG.md +4 -0
  48. package/.claude/skills/cc-pr-review/SKILL.md +20 -103
  49. package/.claude/skills/cc-review/CHANGELOG.md +17 -0
  50. package/.claude/skills/cc-review/PLAYBOOK.md +13 -86
  51. package/.claude/skills/cc-review/SKILL.md +53 -241
  52. package/.claude/skills/cc-review/references/e2e-and-plugin-verification.md +2 -2
  53. package/.claude/skills/cc-review/references/implementation-review-branch.md +7 -147
  54. package/.claude/skills/cc-review/references/plan-review-branch.md +5 -147
  55. package/.claude/skills/cc-review/references/review-methods.md +10 -218
  56. package/.claude/skills/cc-review/scripts/collect-review-context.sh +4 -63
  57. package/.claude/skills/cc-roadmap/PLAYBOOK.md +1 -1
  58. package/.claude/skills/cc-roadmap/SKILL.md +3 -3
  59. package/.claude/skills/cc-simplify/CHANGELOG.md +7 -0
  60. package/.claude/skills/cc-simplify/SKILL.md +26 -21
  61. package/.claude/skills/cc-spec-init/PLAYBOOK.md +12 -48
  62. package/.claude/skills/cc-spec-init/SKILL.md +29 -132
  63. package/.claude/skills/cc-spec-init/references/spec-contract.md +8 -17
  64. package/CHANGELOG.md +27 -0
  65. package/README.md +5 -3
  66. package/README.zh-CN.md +5 -3
  67. package/bin/cc-devflow-cli.js +20 -260
  68. package/bin/cc-devflow.js +44 -7
  69. package/docs/commands/README.md +1 -1
  70. package/docs/commands/README.zh-CN.md +1 -1
  71. package/docs/examples/README.md +1 -1
  72. package/docs/examples/START-HERE.md +14 -14
  73. package/docs/examples/example-bindings.json +11 -11
  74. package/docs/examples/full-design-blocked/README.md +4 -6
  75. package/docs/examples/full-design-blocked/changes/REQ-002-bulk-invite-import/{planning/tasks.md → task.md} +20 -15
  76. package/docs/examples/local-handoff/README.md +8 -11
  77. package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/handoff/pr-brief.md +31 -0
  78. package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/{planning/tasks.md → task.md} +18 -13
  79. package/docs/examples/pdca-loop/README.md +6 -9
  80. package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/handoff/pr-brief.md +9 -11
  81. package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/{planning/tasks.md → task.md} +18 -13
  82. package/docs/examples/scripts/check-example-bindings.sh +11 -62
  83. package/docs/guides/artifact-contract.md +10 -36
  84. package/docs/guides/getting-started.md +8 -7
  85. package/docs/guides/getting-started.zh-CN.md +8 -7
  86. package/docs/guides/minimize-artifacts.md +16 -116
  87. package/docs/guides/project-postmortem.md +14 -71
  88. package/lib/compiler/__tests__/skills-registry.test.js +9 -8
  89. package/lib/compiler/resource-copier.js +29 -0
  90. package/lib/skill-runtime/__tests__/archive-change.test.js +2 -2
  91. package/lib/skill-runtime/__tests__/benchmark-skills.test.js +109 -0
  92. package/lib/skill-runtime/__tests__/cli-bootstrap.integration.test.js +14 -4
  93. package/lib/skill-runtime/errors.js +3 -3
  94. package/lib/skill-runtime/index.js +5 -23
  95. package/lib/skill-runtime/paths.js +5 -52
  96. package/lib/skill-runtime/query-registry.js +4 -4
  97. package/lib/skill-runtime/query.js +89 -201
  98. package/lib/skill-runtime/store.js +4 -40
  99. package/lib/skill-runtime/trace.js +2 -2
  100. package/package.json +5 -7
  101. package/.claude/skills/cc-act/assets/PROJECT_POSTMORTEM_PRINCIPLES_TEMPLATE.md +0 -29
  102. package/.claude/skills/cc-act/assets/RELEASE_NOTE_TEMPLATE.md +0 -54
  103. package/.claude/skills/cc-act/scripts/generate-status-report.sh +0 -92
  104. package/.claude/skills/cc-act/scripts/sync-act-docs.sh +0 -355
  105. package/.claude/skills/cc-check/assets/REPORT_CARD_TEMPLATE.json +0 -234
  106. package/.claude/skills/cc-check/scripts/render-report-card.js +0 -438
  107. package/.claude/skills/cc-check/scripts/verify-gate.sh +0 -85
  108. package/.claude/skills/cc-do/scripts/build-task-context.sh +0 -175
  109. package/.claude/skills/cc-do/scripts/record-review-decision.sh +0 -88
  110. package/.claude/skills/cc-do/scripts/recover-workflow.sh +0 -82
  111. package/.claude/skills/cc-do/scripts/run-problem-analysis.sh +0 -70
  112. package/.claude/skills/cc-do/scripts/verify-task-gates.sh +0 -109
  113. package/.claude/skills/cc-do/scripts/write-task-checkpoint.sh +0 -92
  114. package/.claude/skills/cc-investigate/assets/TASK_MANIFEST_TEMPLATE.json +0 -225
  115. package/.claude/skills/cc-plan/assets/TASK_MANIFEST_TEMPLATE.json +0 -179
  116. package/.claude/skills/cc-spec-init/assets/CHANGE_META_TEMPLATE.json +0 -28
  117. package/.claude/skills/cc-spec-init/scripts/validate-spec-links.sh +0 -45
  118. package/docs/examples/full-design-blocked/changes/REQ-002-bulk-invite-import/planning/design.md +0 -234
  119. package/docs/examples/full-design-blocked/changes/REQ-002-bulk-invite-import/planning/task-manifest.json +0 -488
  120. package/docs/examples/full-design-blocked/changes/REQ-002-bulk-invite-import/review/report-card.json +0 -189
  121. package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/handoff/resume-index.md +0 -39
  122. package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/handoff/status.md +0 -29
  123. package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/planning/design.md +0 -123
  124. package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/planning/task-manifest.json +0 -292
  125. package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/review/report-card.json +0 -136
  126. package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/handoff/status.md +0 -29
  127. package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/planning/design.md +0 -124
  128. package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/planning/task-manifest.json +0 -292
  129. package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/review/report-card.json +0 -136
  130. package/docs/get-shit-done-strategy-audit.md +0 -518
  131. package/docs/skill-runtime-migration.md +0 -46
  132. package/lib/skill-runtime/__tests__/approve.test.js +0 -92
  133. package/lib/skill-runtime/__tests__/autopilot.test.js +0 -253
  134. package/lib/skill-runtime/__tests__/benchmark-artifacts.test.js +0 -165
  135. package/lib/skill-runtime/__tests__/delegation.test.js +0 -97
  136. package/lib/skill-runtime/__tests__/dispatch.test.js +0 -237
  137. package/lib/skill-runtime/__tests__/intent.test.js +0 -203
  138. package/lib/skill-runtime/__tests__/lifecycle.test.js +0 -169
  139. package/lib/skill-runtime/__tests__/planner.tdd.test.js +0 -331
  140. package/lib/skill-runtime/__tests__/prepare-pr.test.js +0 -126
  141. package/lib/skill-runtime/__tests__/query.test.js +0 -860
  142. package/lib/skill-runtime/__tests__/readiness.test.js +0 -53
  143. package/lib/skill-runtime/__tests__/release.test.js +0 -85
  144. package/lib/skill-runtime/__tests__/review-check-integration.test.js +0 -148
  145. package/lib/skill-runtime/__tests__/review-records.test.js +0 -619
  146. package/lib/skill-runtime/__tests__/runtime.integration.test.js +0 -351
  147. package/lib/skill-runtime/__tests__/schemas.test.js +0 -337
  148. package/lib/skill-runtime/__tests__/task-contract-migrate.test.js +0 -137
  149. package/lib/skill-runtime/__tests__/task-contract.test.js +0 -783
  150. package/lib/skill-runtime/__tests__/team-state.test.js +0 -51
  151. package/lib/skill-runtime/__tests__/verify-artifacts.test.js +0 -203
  152. package/lib/skill-runtime/__tests__/worker-run.test.js +0 -275
  153. package/lib/skill-runtime/__tests__/worker.test.js +0 -56
  154. package/lib/skill-runtime/__tests__/workflow-context-legacy-fallback.test.js +0 -31
  155. package/lib/skill-runtime/__tests__/workflow-context.test.js +0 -98
  156. package/lib/skill-runtime/artifacts.js +0 -88
  157. package/lib/skill-runtime/context-index.js +0 -545
  158. package/lib/skill-runtime/delegation.js +0 -533
  159. package/lib/skill-runtime/intent.js +0 -309
  160. package/lib/skill-runtime/lifecycle.js +0 -294
  161. package/lib/skill-runtime/operations/CLAUDE.md +0 -19
  162. package/lib/skill-runtime/operations/approve.js +0 -81
  163. package/lib/skill-runtime/operations/autopilot-core.js +0 -337
  164. package/lib/skill-runtime/operations/autopilot-execution.js +0 -307
  165. package/lib/skill-runtime/operations/autopilot-shared.js +0 -48
  166. package/lib/skill-runtime/operations/autopilot.js +0 -163
  167. package/lib/skill-runtime/operations/dispatch.js +0 -416
  168. package/lib/skill-runtime/operations/init.js +0 -60
  169. package/lib/skill-runtime/operations/janitor.js +0 -61
  170. package/lib/skill-runtime/operations/plan.js +0 -59
  171. package/lib/skill-runtime/operations/prepare-pr.js +0 -25
  172. package/lib/skill-runtime/operations/release.js +0 -99
  173. package/lib/skill-runtime/operations/resume.js +0 -126
  174. package/lib/skill-runtime/operations/review-records.js +0 -265
  175. package/lib/skill-runtime/operations/snapshot.js +0 -45
  176. package/lib/skill-runtime/operations/task-contract.js +0 -524
  177. package/lib/skill-runtime/operations/verify.js +0 -170
  178. package/lib/skill-runtime/operations/worker-run.js +0 -531
  179. package/lib/skill-runtime/operations/worker.js +0 -33
  180. package/lib/skill-runtime/planner.js +0 -539
  181. package/lib/skill-runtime/readiness.js +0 -84
  182. package/lib/skill-runtime/review-records.js +0 -123
  183. package/lib/skill-runtime/review.js +0 -855
  184. package/lib/skill-runtime/schemas.js +0 -746
  185. package/lib/skill-runtime/task-contract.js +0 -187
  186. package/lib/skill-runtime/team-state.js +0 -122
  187. package/lib/skill-runtime/workflow-context.js +0 -748
@@ -1,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
- };