cclaw-cli 7.7.0 → 8.1.0

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 (282) hide show
  1. package/README.md +210 -134
  2. package/dist/artifact-frontmatter.d.ts +51 -0
  3. package/dist/artifact-frontmatter.js +131 -0
  4. package/dist/artifact-paths.d.ts +7 -27
  5. package/dist/artifact-paths.js +20 -249
  6. package/dist/cancel.d.ts +16 -0
  7. package/dist/cancel.js +66 -0
  8. package/dist/cli.d.ts +2 -27
  9. package/dist/cli.js +90 -508
  10. package/dist/compound.d.ts +26 -0
  11. package/dist/compound.js +96 -0
  12. package/dist/config.d.ts +14 -51
  13. package/dist/config.js +23 -359
  14. package/dist/constants.d.ts +11 -18
  15. package/dist/constants.js +19 -106
  16. package/dist/content/antipatterns.d.ts +1 -0
  17. package/dist/content/antipatterns.js +109 -0
  18. package/dist/content/artifact-templates.d.ts +10 -0
  19. package/dist/content/artifact-templates.js +550 -0
  20. package/dist/content/cancel-command.d.ts +2 -2
  21. package/dist/content/cancel-command.js +25 -17
  22. package/dist/content/core-agents.d.ts +9 -233
  23. package/dist/content/core-agents.js +39 -766
  24. package/dist/content/decision-protocol.d.ts +1 -12
  25. package/dist/content/decision-protocol.js +27 -20
  26. package/dist/content/examples.d.ts +8 -42
  27. package/dist/content/examples.js +293 -425
  28. package/dist/content/idea-command.d.ts +2 -0
  29. package/dist/content/idea-command.js +38 -0
  30. package/dist/content/iron-laws.d.ts +4 -138
  31. package/dist/content/iron-laws.js +18 -197
  32. package/dist/content/meta-skill.d.ts +1 -3
  33. package/dist/content/meta-skill.js +57 -132
  34. package/dist/content/node-hooks.d.ts +12 -8
  35. package/dist/content/node-hooks.js +188 -838
  36. package/dist/content/recovery.d.ts +8 -0
  37. package/dist/content/recovery.js +179 -0
  38. package/dist/content/reference-patterns.d.ts +4 -13
  39. package/dist/content/reference-patterns.js +260 -389
  40. package/dist/content/research-playbooks.d.ts +8 -8
  41. package/dist/content/research-playbooks.js +108 -121
  42. package/dist/content/review-loop.d.ts +6 -192
  43. package/dist/content/review-loop.js +29 -731
  44. package/dist/content/skills.d.ts +8 -38
  45. package/dist/content/skills.js +681 -732
  46. package/dist/content/specialist-prompts/architect.d.ts +1 -0
  47. package/dist/content/specialist-prompts/architect.js +225 -0
  48. package/dist/content/specialist-prompts/brainstormer.d.ts +1 -0
  49. package/dist/content/specialist-prompts/brainstormer.js +168 -0
  50. package/dist/content/specialist-prompts/index.d.ts +2 -0
  51. package/dist/content/specialist-prompts/index.js +14 -0
  52. package/dist/content/specialist-prompts/planner.d.ts +1 -0
  53. package/dist/content/specialist-prompts/planner.js +182 -0
  54. package/dist/content/specialist-prompts/reviewer.d.ts +1 -0
  55. package/dist/content/specialist-prompts/reviewer.js +193 -0
  56. package/dist/content/specialist-prompts/security-reviewer.d.ts +1 -0
  57. package/dist/content/specialist-prompts/security-reviewer.js +133 -0
  58. package/dist/content/specialist-prompts/slice-builder.d.ts +1 -0
  59. package/dist/content/specialist-prompts/slice-builder.js +232 -0
  60. package/dist/content/stage-playbooks.d.ts +8 -0
  61. package/dist/content/stage-playbooks.js +404 -0
  62. package/dist/content/start-command.d.ts +2 -12
  63. package/dist/content/start-command.js +221 -207
  64. package/dist/flow-state.d.ts +21 -178
  65. package/dist/flow-state.js +67 -170
  66. package/dist/fs-utils.d.ts +6 -26
  67. package/dist/fs-utils.js +29 -162
  68. package/dist/gitignore.d.ts +2 -1
  69. package/dist/gitignore.js +51 -34
  70. package/dist/harness-detect.d.ts +10 -0
  71. package/dist/harness-detect.js +29 -0
  72. package/dist/install.d.ts +27 -15
  73. package/dist/install.js +230 -1342
  74. package/dist/knowledge-store.d.ts +19 -163
  75. package/dist/knowledge-store.js +56 -590
  76. package/dist/logger.d.ts +8 -3
  77. package/dist/logger.js +13 -4
  78. package/dist/orchestrator-routing.d.ts +29 -0
  79. package/dist/orchestrator-routing.js +156 -0
  80. package/dist/run-persistence.d.ts +7 -118
  81. package/dist/run-persistence.js +29 -845
  82. package/dist/runtime/run-hook.entry.d.ts +1 -3
  83. package/dist/runtime/run-hook.entry.js +19 -4
  84. package/dist/runtime/run-hook.mjs +13 -1024
  85. package/dist/types.d.ts +25 -261
  86. package/dist/types.js +8 -36
  87. package/package.json +6 -3
  88. package/dist/artifact-linter/brainstorm.d.ts +0 -2
  89. package/dist/artifact-linter/brainstorm.js +0 -353
  90. package/dist/artifact-linter/design.d.ts +0 -18
  91. package/dist/artifact-linter/design.js +0 -444
  92. package/dist/artifact-linter/findings-dedup.d.ts +0 -56
  93. package/dist/artifact-linter/findings-dedup.js +0 -232
  94. package/dist/artifact-linter/plan.d.ts +0 -2
  95. package/dist/artifact-linter/plan.js +0 -826
  96. package/dist/artifact-linter/review-army.d.ts +0 -49
  97. package/dist/artifact-linter/review-army.js +0 -520
  98. package/dist/artifact-linter/review.d.ts +0 -2
  99. package/dist/artifact-linter/review.js +0 -113
  100. package/dist/artifact-linter/scope.d.ts +0 -2
  101. package/dist/artifact-linter/scope.js +0 -158
  102. package/dist/artifact-linter/shared.d.ts +0 -637
  103. package/dist/artifact-linter/shared.js +0 -2163
  104. package/dist/artifact-linter/ship.d.ts +0 -2
  105. package/dist/artifact-linter/ship.js +0 -250
  106. package/dist/artifact-linter/spec.d.ts +0 -2
  107. package/dist/artifact-linter/spec.js +0 -176
  108. package/dist/artifact-linter/tdd.d.ts +0 -118
  109. package/dist/artifact-linter/tdd.js +0 -1404
  110. package/dist/artifact-linter.d.ts +0 -15
  111. package/dist/artifact-linter.js +0 -517
  112. package/dist/codex-feature-flag.d.ts +0 -58
  113. package/dist/codex-feature-flag.js +0 -193
  114. package/dist/content/closeout-guidance.d.ts +0 -14
  115. package/dist/content/closeout-guidance.js +0 -44
  116. package/dist/content/diff-command.d.ts +0 -1
  117. package/dist/content/diff-command.js +0 -43
  118. package/dist/content/harness-doc.d.ts +0 -1
  119. package/dist/content/harness-doc.js +0 -65
  120. package/dist/content/hook-events.d.ts +0 -9
  121. package/dist/content/hook-events.js +0 -23
  122. package/dist/content/hook-manifest.d.ts +0 -81
  123. package/dist/content/hook-manifest.js +0 -156
  124. package/dist/content/hooks.d.ts +0 -11
  125. package/dist/content/hooks.js +0 -1972
  126. package/dist/content/idea.d.ts +0 -60
  127. package/dist/content/idea.js +0 -416
  128. package/dist/content/language-policy.d.ts +0 -2
  129. package/dist/content/language-policy.js +0 -13
  130. package/dist/content/learnings.d.ts +0 -6
  131. package/dist/content/learnings.js +0 -141
  132. package/dist/content/observe.d.ts +0 -19
  133. package/dist/content/observe.js +0 -86
  134. package/dist/content/opencode-plugin.d.ts +0 -1
  135. package/dist/content/opencode-plugin.js +0 -635
  136. package/dist/content/review-prompts.d.ts +0 -1
  137. package/dist/content/review-prompts.js +0 -104
  138. package/dist/content/runtime-shared-snippets.d.ts +0 -8
  139. package/dist/content/runtime-shared-snippets.js +0 -80
  140. package/dist/content/session-hooks.d.ts +0 -7
  141. package/dist/content/session-hooks.js +0 -107
  142. package/dist/content/skills-elicitation.d.ts +0 -1
  143. package/dist/content/skills-elicitation.js +0 -167
  144. package/dist/content/stage-command.d.ts +0 -2
  145. package/dist/content/stage-command.js +0 -17
  146. package/dist/content/stage-schema.d.ts +0 -117
  147. package/dist/content/stage-schema.js +0 -955
  148. package/dist/content/stages/_lint-metadata/index.d.ts +0 -2
  149. package/dist/content/stages/_lint-metadata/index.js +0 -97
  150. package/dist/content/stages/brainstorm.d.ts +0 -2
  151. package/dist/content/stages/brainstorm.js +0 -184
  152. package/dist/content/stages/design.d.ts +0 -2
  153. package/dist/content/stages/design.js +0 -288
  154. package/dist/content/stages/index.d.ts +0 -8
  155. package/dist/content/stages/index.js +0 -11
  156. package/dist/content/stages/plan.d.ts +0 -2
  157. package/dist/content/stages/plan.js +0 -191
  158. package/dist/content/stages/review.d.ts +0 -2
  159. package/dist/content/stages/review.js +0 -240
  160. package/dist/content/stages/schema-types.d.ts +0 -203
  161. package/dist/content/stages/schema-types.js +0 -1
  162. package/dist/content/stages/scope.d.ts +0 -2
  163. package/dist/content/stages/scope.js +0 -254
  164. package/dist/content/stages/ship.d.ts +0 -2
  165. package/dist/content/stages/ship.js +0 -159
  166. package/dist/content/stages/spec.d.ts +0 -2
  167. package/dist/content/stages/spec.js +0 -170
  168. package/dist/content/stages/tdd.d.ts +0 -4
  169. package/dist/content/stages/tdd.js +0 -273
  170. package/dist/content/state-contracts.d.ts +0 -1
  171. package/dist/content/state-contracts.js +0 -63
  172. package/dist/content/status-command.d.ts +0 -4
  173. package/dist/content/status-command.js +0 -109
  174. package/dist/content/subagent-context-skills.d.ts +0 -4
  175. package/dist/content/subagent-context-skills.js +0 -279
  176. package/dist/content/subagents.d.ts +0 -3
  177. package/dist/content/subagents.js +0 -997
  178. package/dist/content/templates.d.ts +0 -26
  179. package/dist/content/templates.js +0 -1692
  180. package/dist/content/track-render-context.d.ts +0 -18
  181. package/dist/content/track-render-context.js +0 -53
  182. package/dist/content/tree-command.d.ts +0 -1
  183. package/dist/content/tree-command.js +0 -64
  184. package/dist/content/utility-skills.d.ts +0 -30
  185. package/dist/content/utility-skills.js +0 -160
  186. package/dist/content/view-command.d.ts +0 -2
  187. package/dist/content/view-command.js +0 -92
  188. package/dist/delegation.d.ts +0 -649
  189. package/dist/delegation.js +0 -1539
  190. package/dist/early-loop.d.ts +0 -70
  191. package/dist/early-loop.js +0 -302
  192. package/dist/execution-topology.d.ts +0 -36
  193. package/dist/execution-topology.js +0 -73
  194. package/dist/gate-evidence.d.ts +0 -85
  195. package/dist/gate-evidence.js +0 -631
  196. package/dist/harness-adapters.d.ts +0 -151
  197. package/dist/harness-adapters.js +0 -756
  198. package/dist/harness-selection.d.ts +0 -31
  199. package/dist/harness-selection.js +0 -214
  200. package/dist/hook-schema.d.ts +0 -6
  201. package/dist/hook-schema.js +0 -114
  202. package/dist/hook-schemas/claude-hooks.v1.json +0 -10
  203. package/dist/hook-schemas/codex-hooks.v1.json +0 -10
  204. package/dist/hook-schemas/cursor-hooks.v1.json +0 -13
  205. package/dist/init-detect.d.ts +0 -2
  206. package/dist/init-detect.js +0 -50
  207. package/dist/internal/advance-stage/advance.d.ts +0 -89
  208. package/dist/internal/advance-stage/advance.js +0 -655
  209. package/dist/internal/advance-stage/cancel-run.d.ts +0 -8
  210. package/dist/internal/advance-stage/cancel-run.js +0 -19
  211. package/dist/internal/advance-stage/flow-state-coercion.d.ts +0 -3
  212. package/dist/internal/advance-stage/flow-state-coercion.js +0 -81
  213. package/dist/internal/advance-stage/helpers.d.ts +0 -14
  214. package/dist/internal/advance-stage/helpers.js +0 -145
  215. package/dist/internal/advance-stage/hook.d.ts +0 -8
  216. package/dist/internal/advance-stage/hook.js +0 -40
  217. package/dist/internal/advance-stage/parsers.d.ts +0 -72
  218. package/dist/internal/advance-stage/parsers.js +0 -357
  219. package/dist/internal/advance-stage/proactive-delegation-trace.d.ts +0 -24
  220. package/dist/internal/advance-stage/proactive-delegation-trace.js +0 -56
  221. package/dist/internal/advance-stage/review-loop.d.ts +0 -16
  222. package/dist/internal/advance-stage/review-loop.js +0 -199
  223. package/dist/internal/advance-stage/rewind.d.ts +0 -14
  224. package/dist/internal/advance-stage/rewind.js +0 -108
  225. package/dist/internal/advance-stage/start-flow.d.ts +0 -13
  226. package/dist/internal/advance-stage/start-flow.js +0 -241
  227. package/dist/internal/advance-stage/verify.d.ts +0 -21
  228. package/dist/internal/advance-stage/verify.js +0 -185
  229. package/dist/internal/advance-stage.d.ts +0 -7
  230. package/dist/internal/advance-stage.js +0 -138
  231. package/dist/internal/cohesion-contract-stub.d.ts +0 -24
  232. package/dist/internal/cohesion-contract-stub.js +0 -148
  233. package/dist/internal/compound-readiness.d.ts +0 -23
  234. package/dist/internal/compound-readiness.js +0 -102
  235. package/dist/internal/detect-public-api-changes.d.ts +0 -5
  236. package/dist/internal/detect-public-api-changes.js +0 -45
  237. package/dist/internal/detect-supply-chain-changes.d.ts +0 -6
  238. package/dist/internal/detect-supply-chain-changes.js +0 -138
  239. package/dist/internal/early-loop-status.d.ts +0 -7
  240. package/dist/internal/early-loop-status.js +0 -93
  241. package/dist/internal/envelope-validate.d.ts +0 -7
  242. package/dist/internal/envelope-validate.js +0 -66
  243. package/dist/internal/flow-state-repair.d.ts +0 -20
  244. package/dist/internal/flow-state-repair.js +0 -104
  245. package/dist/internal/plan-split-waves.d.ts +0 -190
  246. package/dist/internal/plan-split-waves.js +0 -764
  247. package/dist/internal/runtime-integrity.d.ts +0 -7
  248. package/dist/internal/runtime-integrity.js +0 -268
  249. package/dist/internal/slice-commit.d.ts +0 -7
  250. package/dist/internal/slice-commit.js +0 -619
  251. package/dist/internal/tdd-loop-status.d.ts +0 -14
  252. package/dist/internal/tdd-loop-status.js +0 -68
  253. package/dist/internal/tdd-red-evidence.d.ts +0 -7
  254. package/dist/internal/tdd-red-evidence.js +0 -153
  255. package/dist/internal/waiver-grant.d.ts +0 -62
  256. package/dist/internal/waiver-grant.js +0 -294
  257. package/dist/internal/wave-status.d.ts +0 -63
  258. package/dist/internal/wave-status.js +0 -450
  259. package/dist/managed-resources.d.ts +0 -53
  260. package/dist/managed-resources.js +0 -313
  261. package/dist/policy.d.ts +0 -10
  262. package/dist/policy.js +0 -167
  263. package/dist/retro-gate.d.ts +0 -9
  264. package/dist/retro-gate.js +0 -47
  265. package/dist/run-archive.d.ts +0 -61
  266. package/dist/run-archive.js +0 -391
  267. package/dist/runs.d.ts +0 -2
  268. package/dist/runs.js +0 -2
  269. package/dist/stack-detection.d.ts +0 -116
  270. package/dist/stack-detection.js +0 -489
  271. package/dist/streaming/event-stream.d.ts +0 -31
  272. package/dist/streaming/event-stream.js +0 -114
  273. package/dist/tdd-cycle.d.ts +0 -107
  274. package/dist/tdd-cycle.js +0 -289
  275. package/dist/tdd-verification-evidence.d.ts +0 -17
  276. package/dist/tdd-verification-evidence.js +0 -122
  277. package/dist/track-heuristics.d.ts +0 -27
  278. package/dist/track-heuristics.js +0 -154
  279. package/dist/util/slice-id.d.ts +0 -58
  280. package/dist/util/slice-id.js +0 -89
  281. package/dist/worktree-manager.d.ts +0 -20
  282. package/dist/worktree-manager.js +0 -108
@@ -1,15 +0,0 @@
1
- import type { FlowStage, FlowTrack } from "./types.js";
2
- import { type LintResult } from "./artifact-linter/shared.js";
3
- export { validateReviewArmy, checkReviewVerdictConsistency, checkReviewSecurityNoChangeAttestation, checkReviewTddNoCrossArtifactDuplication, type ReviewVerdictConsistencyResult, type ReviewSecurityNoChangeAttestationResult, type ReviewTddDuplicationConflict, type ReviewTddDuplicationResult } from "./artifact-linter/review-army.js";
4
- export { type LintFinding, type LintResult, type LearningEntryType, type LearningConfidence, type LearningSeverity, type LearningSource, type LearningSeedEntry, type LearningsParseResult, extractAuthoredBody, formatLearningsErrorsBullets, learningsParseFailureHumanSummary, extractMarkdownSectionBody, parseLearningsSection } from "./artifact-linter/shared.js";
5
- export interface LintArtifactOptions {
6
- /**
7
- * Stage-level flags supplied by the caller (typically `advance-stage`)
8
- * that augment whatever flow-state.json says. Used so the linter sees
9
- * `--skip-questions` even before flow-state is updated for the current
10
- * stage (advance-stage applies the hint to the successor stage only,
11
- * but the linter must respect the current-call intent).
12
- */
13
- extraStageFlags?: string[];
14
- }
15
- export declare function lintArtifact(projectRoot: string, stage: FlowStage, track?: FlowTrack, options?: LintArtifactOptions): Promise<LintResult>;
@@ -1,517 +0,0 @@
1
- import fs from "node:fs/promises";
2
- import path from "node:path";
3
- import { resolveArtifactPath as resolveStageArtifactPath } from "./artifact-paths.js";
4
- import { exists } from "./fs-utils.js";
5
- import { stageSchema } from "./content/stage-schema.js";
6
- import { readFlowState } from "./run-persistence.js";
7
- import { duplicateH2Headings, extractEvidencePointers, extractH2Sections, extractRequirementIdsFromMarkdown, isShortCircuitActivated, normalizeHeadingTitle, parseFrontmatter, parseLearningsSection, sectionBodyByAnyName, sectionBodyByHeadingPrefix, sectionBodyByName, validateSectionBody, formatLearningsErrorsBullets } from "./artifact-linter/shared.js";
8
- import { shouldDemoteArtifactValidationByTrack } from "./content/stage-schema.js";
9
- import { readDelegationLedger, recordArtifactValidationDemotedByTrack } from "./delegation.js";
10
- import { classifyAndPersistFindings } from "./artifact-linter/findings-dedup.js";
11
- import { lintBrainstormStage } from "./artifact-linter/brainstorm.js";
12
- import { lintDesignStage } from "./artifact-linter/design.js";
13
- import { lintPlanStage } from "./artifact-linter/plan.js";
14
- import { lintScopeStage } from "./artifact-linter/scope.js";
15
- import { lintSpecStage } from "./artifact-linter/spec.js";
16
- import { lintTddStage } from "./artifact-linter/tdd.js";
17
- import { lintReviewStage } from "./artifact-linter/review.js";
18
- import { lintShipStage } from "./artifact-linter/ship.js";
19
- export { validateReviewArmy, checkReviewVerdictConsistency, checkReviewSecurityNoChangeAttestation, checkReviewTddNoCrossArtifactDuplication } from "./artifact-linter/review-army.js";
20
- export { extractAuthoredBody, formatLearningsErrorsBullets, learningsParseFailureHumanSummary, extractMarkdownSectionBody, parseLearningsSection } from "./artifact-linter/shared.js";
21
- const FRONTMATTER_REQUIRED_KEYS = [
22
- "stage",
23
- "schema_version",
24
- "version",
25
- "locked_decisions",
26
- "inputs_hash"
27
- ];
28
- export async function lintArtifact(projectRoot, stage, track = "standard", options = {}) {
29
- const schema = stageSchema(stage, track);
30
- const { absPath: absFile, relPath: relFile } = await resolveStageArtifactPath(stage, {
31
- projectRoot,
32
- track,
33
- intent: "read"
34
- });
35
- const findings = [];
36
- if (!(await exists(absFile))) {
37
- for (const v of schema.artifactValidation) {
38
- findings.push({
39
- section: v.section,
40
- required: v.required,
41
- rule: v.validationRule,
42
- found: false,
43
- details: `Artifact file missing: ${relFile}`
44
- });
45
- }
46
- return {
47
- stage,
48
- file: relFile,
49
- passed: schema.artifactValidation.every((v) => !v.required),
50
- findings
51
- };
52
- }
53
- const raw = await fs.readFile(absFile, "utf8");
54
- const sections = extractH2Sections(raw);
55
- const duplicateHeadings = duplicateH2Headings(raw);
56
- if (duplicateHeadings.length > 0) {
57
- findings.push({
58
- section: "duplicate_h2_heading",
59
- required: false,
60
- rule: "[P3] keep each `##` heading unique within an artifact; append updates to the existing section instead of cloning headings.",
61
- found: false,
62
- details: `Duplicate H2 heading(s): ${duplicateHeadings.join(", ")}. Merge edits into the existing heading to avoid split contracts.`
63
- });
64
- }
65
- const parsedFrontmatter = parseFrontmatter(raw);
66
- const frontmatterMissingKeys = FRONTMATTER_REQUIRED_KEYS.filter((key) => {
67
- const value = parsedFrontmatter.values[key];
68
- return typeof value !== "string" || value.trim().length === 0;
69
- });
70
- if (parsedFrontmatter.hasFrontmatter &&
71
- typeof parsedFrontmatter.values.run !== "string" &&
72
- typeof parsedFrontmatter.values.feature !== "string") {
73
- frontmatterMissingKeys.push("run");
74
- }
75
- const frontmatterStage = parsedFrontmatter.values.stage?.replace(/^['"]|['"]$/gu, "");
76
- const frontmatterSchemaVersion = parsedFrontmatter.values.schema_version?.replace(/^['"]|['"]$/gu, "");
77
- const frontmatterInputsHash = parsedFrontmatter.values.inputs_hash?.replace(/^['"]|['"]$/gu, "");
78
- const frontmatterValid = parsedFrontmatter.hasFrontmatter &&
79
- frontmatterMissingKeys.length === 0 &&
80
- frontmatterStage === stage &&
81
- frontmatterSchemaVersion === "1" &&
82
- /^sha256:(?:pending|[a-f0-9]{64})$/iu.test(frontmatterInputsHash ?? "");
83
- const requireFrontmatter = parsedFrontmatter.hasFrontmatter;
84
- findings.push({
85
- section: "Frontmatter",
86
- required: requireFrontmatter,
87
- rule: "Artifact must include frontmatter keys (stage, schema_version=1, version, run, locked_decisions, inputs_hash=sha256:pending|sha256:<64hex>). Legacy feature is accepted during migration.",
88
- found: parsedFrontmatter.hasFrontmatter ? frontmatterValid : true,
89
- details: !parsedFrontmatter.hasFrontmatter
90
- ? "Legacy artifact without YAML frontmatter (allowed for backward compatibility)."
91
- : frontmatterMissingKeys.length > 0
92
- ? `Frontmatter missing required key(s): ${frontmatterMissingKeys.join(", ")}.`
93
- : frontmatterStage !== stage
94
- ? `Frontmatter stage must be "${stage}" (found "${frontmatterStage ?? "(missing)"}").`
95
- : frontmatterSchemaVersion !== "1"
96
- ? `Frontmatter schema_version must be "1" (found "${frontmatterSchemaVersion ?? "(missing)"}").`
97
- : !/^sha256:(?:pending|[a-f0-9]{64})$/iu.test(frontmatterInputsHash ?? "")
98
- ? "Frontmatter inputs_hash must be sha256:pending or sha256:<64 hex chars>."
99
- : "Frontmatter integrity checks passed."
100
- });
101
- const brainstormShortCircuitBody = stage === "brainstorm" ? sectionBodyByName(sections, "Short-Circuit Decision") : null;
102
- const brainstormShortCircuitActivated = stage === "brainstorm" && isShortCircuitActivated(brainstormShortCircuitBody);
103
- const scopePreAuditEnabled = true;
104
- const staleDiagramAuditEnabled = true;
105
- const isTrivialOverride = Boolean(schema.trivialOverrideSections &&
106
- schema.trivialOverrideSections.length > 0 &&
107
- (/trivial.change|mini.design|escape.hatch/iu.test(raw) ||
108
- brainstormShortCircuitActivated));
109
- const overrideSet = isTrivialOverride
110
- ? new Set(schema.trivialOverrideSections.map((s) => normalizeHeadingTitle(s).toLowerCase()))
111
- : null;
112
- // Precompute the lite-tier signal so the per-section
113
- // validators (Interaction Edge Case matrix today, others tomorrow)
114
- // can relax network-dependent mandatory rows for lite/quick/bugfix
115
- // runs without each validator having to re-derive the predicate.
116
- // Same flow-state read powers the post-loop demotion + audit log
117
- // below; we cache the result here to avoid two disk reads.
118
- let activeStageFlags = [];
119
- let discoveryMode = "guided";
120
- let taskClass = null;
121
- let packageVersion;
122
- let activeRunId = null;
123
- let completedStagesForAudit = [];
124
- let completedStageMetaForAudit;
125
- try {
126
- const flowState = await readFlowState(projectRoot);
127
- const hint = flowState.interactionHints?.[stage];
128
- if (hint?.skipQuestions === true)
129
- activeStageFlags.push("--skip-questions");
130
- discoveryMode = flowState.discoveryMode ?? "guided";
131
- taskClass = flowState.taskClass ?? null;
132
- packageVersion = flowState.packageVersion;
133
- activeRunId = flowState.activeRunId ?? null;
134
- completedStagesForAudit = flowState.completedStages;
135
- completedStageMetaForAudit = flowState.completedStageMeta;
136
- }
137
- catch {
138
- activeStageFlags = [];
139
- discoveryMode = "guided";
140
- taskClass = null;
141
- packageVersion = undefined;
142
- activeRunId = null;
143
- completedStagesForAudit = [];
144
- completedStageMetaForAudit = undefined;
145
- }
146
- for (const extra of options.extraStageFlags ?? []) {
147
- if (typeof extra === "string" && extra.length > 0 && !activeStageFlags.includes(extra)) {
148
- activeStageFlags.push(extra);
149
- }
150
- }
151
- const liteTierForValidators = shouldDemoteArtifactValidationByTrack(track, taskClass);
152
- // pre-resolve RED/GREEN Evidence pointers AND
153
- // delegation phase events so `validateSectionBody` (sync) can
154
- // short-circuit. The Evidence: pointer mode (T3) stays as a
155
- // fallback alongside legacy markdown content; phase events with a
156
- // `phase=red`/`phase=green` row plus non-empty evidenceRefs auto-pass
157
- // the corresponding markdown validator.
158
- const tddEvidenceContext = stage === "tdd"
159
- ? await resolveTddEvidencePointerContext({
160
- projectRoot,
161
- sections
162
- })
163
- : { red: {}, green: {} };
164
- for (const v of schema.artifactValidation) {
165
- const sectionKey = normalizeHeadingTitle(v.section).toLowerCase();
166
- const scopeBoundaryAlias = stage === "scope" && sectionKey === "in scope / out of scope";
167
- const body = scopeBoundaryAlias
168
- ? sectionBodyByAnyName(sections, ["In Scope / Out of Scope", "In Scope", "Out of Scope"])
169
- : sectionBodyByName(sections, v.section);
170
- const hasHeading = body !== null;
171
- const effectiveRequiredFromOverride = overrideSet
172
- ? overrideSet.has(sectionKey) ? true : false
173
- : v.required;
174
- const effectiveRequired = stage === "design" && sectionKey === "data flow" && hasHeading
175
- ? true
176
- : stage === "scope" && sectionKey === "pre-scope system audit" && scopePreAuditEnabled
177
- ? true
178
- : effectiveRequiredFromOverride;
179
- const validation = body === null
180
- ? { ok: false, details: `No ## heading matching required section "${v.section}".` }
181
- : validateSectionBody(body, v.validationRule, v.section, {
182
- sections,
183
- liteTier: liteTierForValidators,
184
- tddEvidence: stage === "tdd" ? tddEvidenceContext : undefined
185
- });
186
- const found = hasHeading && validation.ok;
187
- findings.push({
188
- section: v.section,
189
- required: effectiveRequired,
190
- rule: v.validationRule,
191
- found,
192
- details: found
193
- ? validation.details
194
- : validation.details
195
- });
196
- }
197
- const learningsBody = sectionBodyByName(sections, "Learnings");
198
- const requireLearnings = parsedFrontmatter.hasFrontmatter;
199
- if (learningsBody === null) {
200
- findings.push({
201
- section: "Learnings",
202
- required: requireLearnings,
203
- rule: "Required for schema-v1 artifacts: include `## Learnings` with bullets of strict JSON objects compatible with knowledge.jsonl schema, or a single `- None this stage.` sentinel.",
204
- found: false,
205
- details: "No ## heading matching required section \"Learnings\"."
206
- });
207
- }
208
- else {
209
- const learnings = parseLearningsSection(learningsBody);
210
- const meaningfulStageNoneWarning = learnings.ok && learnings.none && ["design", "tdd", "review"].includes(stage)
211
- ? " Warning: design/tdd/review usually produce reusable decisions, test patterns, or review lessons; keep `None this stage` only for truly mechanical work."
212
- : "";
213
- const learningsErrorBlock = !learnings.ok && learnings.errors.length > 0
214
- ? `\n${formatLearningsErrorsBullets(learnings.errors)}`
215
- : "";
216
- findings.push({
217
- section: "Learnings",
218
- required: requireLearnings,
219
- rule: "`## Learnings` must contain either a single `- None this stage.` bullet or JSON bullets compatible with knowledge.jsonl fields (type/trigger/action/confidence required).",
220
- found: learnings.ok,
221
- details: `${learnings.details}${learningsErrorBlock}${meaningfulStageNoneWarning}`
222
- });
223
- }
224
- for (const doneStage of completedStagesForAudit) {
225
- const completionIso = completedStageMetaForAudit?.[doneStage]?.completedAt;
226
- if (!completionIso)
227
- continue;
228
- const completedMs = Date.parse(completionIso);
229
- if (!Number.isFinite(completedMs))
230
- continue;
231
- try {
232
- const resolvedDone = await resolveStageArtifactPath(doneStage, {
233
- projectRoot,
234
- track,
235
- intent: "read"
236
- });
237
- if (!(await exists(resolvedDone.absPath)))
238
- continue;
239
- const artifactStat = await fs.stat(resolvedDone.absPath);
240
- if (artifactStat.mtimeMs <= completedMs)
241
- continue;
242
- const priorRaw = await fs.readFile(resolvedDone.absPath, "utf8");
243
- const priorSections = extractH2Sections(priorRaw);
244
- const amendBody = sectionBodyByName(priorSections, "Amendments");
245
- const trimmedAmend = amendBody === null
246
- ? ""
247
- : amendBody.replace(/<!--[\s\S]*?-->/gu, "").replace(/\s+/gu, " ").trim();
248
- if (trimmedAmend.length > 0)
249
- continue;
250
- findings.push({
251
- section: "stage_artifact_post_closure_mutation",
252
- required: false,
253
- rule: "stage_artifact_post_closure_mutation — substantive post-closure edit without `## Amendments` (advisory)",
254
- found: false,
255
- details: `Completed stage "${doneStage}" snapshot closed at ${completionIso}, but ${resolvedDone.relPath} has a newer mtime without nonempty \`## Amendments\`. ` +
256
- "Append dated bullets describing each drift fix, or restore the archived copy."
257
- });
258
- }
259
- catch {
260
- continue;
261
- }
262
- }
263
- const stageContext = {
264
- projectRoot,
265
- stage,
266
- track,
267
- discoveryMode,
268
- raw,
269
- absFile,
270
- sections,
271
- findings,
272
- parsedFrontmatter,
273
- brainstormShortCircuitBody,
274
- brainstormShortCircuitActivated,
275
- scopePreAuditEnabled,
276
- staleDiagramAuditEnabled,
277
- isTrivialOverride,
278
- overrideSet,
279
- activeStageFlags,
280
- taskClass,
281
- packageVersion
282
- };
283
- switch (stage) {
284
- case "brainstorm":
285
- await lintBrainstormStage(stageContext);
286
- break;
287
- case "design":
288
- await lintDesignStage(stageContext);
289
- break;
290
- case "plan":
291
- await lintPlanStage(stageContext);
292
- break;
293
- case "scope":
294
- await lintScopeStage(stageContext);
295
- break;
296
- case "spec":
297
- await lintSpecStage(stageContext);
298
- break;
299
- case "tdd":
300
- await lintTddStage(stageContext);
301
- break;
302
- case "review":
303
- await lintReviewStage(stageContext);
304
- break;
305
- case "ship":
306
- await lintShipStage(stageContext);
307
- break;
308
- default:
309
- break;
310
- }
311
- if (["design", "spec", "plan", "review"].includes(stage)) {
312
- const scopeArtifact = await resolveStageArtifactPath("scope", {
313
- projectRoot,
314
- track,
315
- intent: "read"
316
- });
317
- if (await exists(scopeArtifact.absPath)) {
318
- const scopeRaw = await fs.readFile(scopeArtifact.absPath, "utf8");
319
- const scopeSections = extractH2Sections(scopeRaw);
320
- const requirementsBody = sectionBodyByHeadingPrefix(scopeSections, "Requirements") ?? "";
321
- const lockedDecisionsBody = sectionBodyByHeadingPrefix(scopeSections, "Locked Decisions") ?? "";
322
- const requirementIds = extractRequirementIdsFromMarkdown(requirementsBody);
323
- const decisionIds = Array.from(new Set((lockedDecisionsBody.match(/\bD-\d+\b/giu) ?? []).map((id) => id.toUpperCase())));
324
- const missingRequirementRefs = requirementIds.filter((id) => !raw.includes(id));
325
- const missingDecisionRefs = decisionIds.filter((id) => !raw.toUpperCase().includes(id));
326
- findings.push({
327
- section: "Scope Requirement Reference Integrity",
328
- required: requirementIds.length > 0,
329
- rule: "Every R# requirement ID from scope must be referenced by downstream artifacts.",
330
- found: missingRequirementRefs.length === 0,
331
- details: requirementIds.length === 0
332
- ? "No R# requirement IDs found in scope artifact; reference check skipped."
333
- : missingRequirementRefs.length === 0
334
- ? `All ${requirementIds.length} scope requirement ID(s) are referenced.`
335
- : `Missing scope requirement reference(s): ${missingRequirementRefs.join(", ")}.`
336
- });
337
- findings.push({
338
- section: "Locked Decision Reference Integrity",
339
- required: decisionIds.length > 0,
340
- rule: "Every D-XX locked decision ID from scope must be referenced by downstream artifacts.",
341
- found: missingDecisionRefs.length === 0,
342
- details: decisionIds.length === 0
343
- ? "No D-XX decision IDs found in scope artifact; reference check skipped."
344
- : missingDecisionRefs.length === 0
345
- ? `All ${decisionIds.length} locked decision ID(s) are referenced.`
346
- : `Missing locked decision reference(s): ${missingDecisionRefs.join(", ")}.`
347
- });
348
- }
349
- }
350
- try {
351
- const delegationLedger = await readDelegationLedger(projectRoot);
352
- const legacyWaivers = delegationLedger.entries.filter((entry) => entry.status === "waived" &&
353
- entry.mode === "proactive" &&
354
- entry.stage === stage &&
355
- (typeof entry.approvalToken !== "string" || entry.approvalToken.trim().length === 0));
356
- if (legacyWaivers.length > 0) {
357
- const descriptors = legacyWaivers
358
- .map((entry) => [entry.agent, entry.spanId].filter((value) => typeof value === "string").join("@"))
359
- .filter((value) => value.length > 0);
360
- findings.push({
361
- section: "waiver_legacy_provenance",
362
- required: false,
363
- rule: "waiver_legacy_provenance — proactive waiver(s) without approvalToken. Issue new waivers via `cclaw-cli internal waiver-grant --stage <stage> --reason <slug>` so the provenance trail is signed. Legacy waivers remain valid (advisory).",
364
- found: false,
365
- details: `Found ${legacyWaivers.length} proactive waiver(s) on stage="${stage}" without approvalToken` +
366
- (descriptors.length > 0 ? ` (${descriptors.join(", ")})` : "") +
367
- ". Next waiver should be issued with `cclaw-cli internal waiver-grant` and consumed via `--accept-proactive-waiver=<token>`."
368
- });
369
- }
370
- }
371
- catch {
372
- // Ledger absent or unreadable: no advisory to emit.
373
- }
374
- const demote = shouldDemoteArtifactValidationByTrack(track, taskClass);
375
- const demotedSections = [];
376
- if (demote) {
377
- for (const finding of findings) {
378
- if (!ARTIFACT_VALIDATION_LITE_DEMOTE_SECTIONS.has(finding.section))
379
- continue;
380
- if (finding.found)
381
- continue;
382
- if (!finding.required)
383
- continue;
384
- finding.required = false;
385
- finding.details =
386
- `${finding.details} (demoted to advisory by track="${track}"` +
387
- (taskClass ? `, taskClass="${taskClass}"` : "") +
388
- ").";
389
- demotedSections.push(finding.section);
390
- }
391
- if (demotedSections.length > 0 && activeRunId) {
392
- await recordArtifactValidationDemotedByTrack(projectRoot, {
393
- stage,
394
- track,
395
- taskClass: taskClass ?? null,
396
- runId: activeRunId,
397
- sections: demotedSections
398
- }).catch(() => { });
399
- }
400
- }
401
- const passed = findings.every((f) => !f.required || f.found);
402
- let dedup;
403
- try {
404
- const dedupResult = await classifyAndPersistFindings(projectRoot, stage, findings);
405
- const statusByFingerprint = new Map(dedupResult.classified.map(({ fingerprint, status }) => [fingerprint, status]));
406
- const statuses = dedupResult.classified.map(({ status }) => status);
407
- void statusByFingerprint;
408
- dedup = {
409
- newCount: dedupResult.summary.newCount,
410
- repeatCount: dedupResult.summary.repeatCount,
411
- resolvedCount: dedupResult.summary.resolvedCount,
412
- header: dedupResult.header,
413
- statuses
414
- };
415
- }
416
- catch {
417
- dedup = undefined;
418
- }
419
- return { stage, file: relFile, passed, findings, ...(dedup ? { dedup } : {}) };
420
- }
421
- /**
422
- * section names whose required-finding outcome is
423
- * demoted from blocking → advisory when
424
- * `shouldDemoteArtifactValidationByTrack(track, taskClass)` returns
425
- * `true`. Mirrors the user-reported quick-tier failure modes:
426
- *
427
- * - `Architecture Diagram` — sync/async + failure-edge enforcement
428
- * - `Data Flow` — Interaction Edge Case mandatory rows
429
- * - `Stale Diagram Drift Check` — blast-radius file mtime audit
430
- * - `Product Discovery Delegation (Strategist Mode)` — product-discovery delegation
431
- *
432
- * Findings remain in the result so the caller can surface them as
433
- * advisory hints; only `required` flips to `false`.
434
- */
435
- const ARTIFACT_VALIDATION_LITE_DEMOTE_SECTIONS = new Set([
436
- "Architecture Diagram",
437
- "Data Flow",
438
- "Stale Diagram Drift Check",
439
- "Product Discovery Delegation (Strategist Mode)"
440
- ]);
441
- /**
442
- * pre-resolve `Evidence:` pointers and delegation
443
- * phase-event auto-satisfy state for the TDD stage's RED/GREEN
444
- * Evidence rows so `validateSectionBody` (sync) can short-circuit.
445
- *
446
- * - `<path>` pointer is satisfied when the path exists on disk relative
447
- * to the project root.
448
- * - `spanId:<id>` pointer is satisfied when any delegation ledger row
449
- * carries that span id.
450
- * - Phase-event auto-satisfy fires when `delegation-events.jsonl`
451
- * carries at least one slice-tagged event for the active run with
452
- * `phase=red`/`phase=green` and non-empty `evidenceRefs`. This is the
453
- replacement for the sidecar auto-satisfy hook —
454
- * slice events are now the source of truth, the RED/GREEN markdown
455
- * tables are auto-rendered from them, and the validators MUST NOT
456
- * demand pasted stdout when the events already prove RED/GREEN.
457
- */
458
- async function resolveTddEvidencePointerContext(input) {
459
- const { projectRoot, sections } = input;
460
- const redSection = sectionBodyByName(sections, "RED Evidence") ?? "";
461
- const greenSection = sectionBodyByName(sections, "GREEN Evidence") ?? "";
462
- const redPointers = extractEvidencePointers(redSection);
463
- const greenPointers = extractEvidencePointers(greenSection);
464
- let knownSpanIds = new Set();
465
- let phaseEventsAutoSatisfy = { red: false, green: false };
466
- try {
467
- const ledger = await readDelegationLedger(projectRoot);
468
- knownSpanIds = new Set(ledger.entries
469
- .map((entry) => entry.spanId)
470
- .filter((id) => typeof id === "string" && id.length > 0));
471
- const runId = ledger.runId;
472
- const slicePhaseRows = ledger.entries.filter((entry) => entry.runId === runId &&
473
- entry.stage === "tdd" &&
474
- typeof entry.sliceId === "string" &&
475
- entry.sliceId.length > 0 &&
476
- typeof entry.phase === "string");
477
- const redOk = slicePhaseRows.some((entry) => entry.phase === "red" &&
478
- Array.isArray(entry.evidenceRefs) &&
479
- entry.evidenceRefs.some((ref) => typeof ref === "string" && ref.trim().length > 0));
480
- const greenOk = slicePhaseRows.some((entry) => entry.phase === "green" &&
481
- Array.isArray(entry.evidenceRefs) &&
482
- entry.evidenceRefs.some((ref) => typeof ref === "string" && ref.trim().length > 0));
483
- phaseEventsAutoSatisfy = { red: redOk, green: greenOk };
484
- }
485
- catch {
486
- knownSpanIds = new Set();
487
- phaseEventsAutoSatisfy = { red: false, green: false };
488
- }
489
- async function pointerResolves(value) {
490
- const trimmed = value.replace(/[`*_]/gu, "").trim();
491
- if (trimmed.length === 0)
492
- return false;
493
- if (/^spanid\s*:/iu.test(trimmed)) {
494
- const id = trimmed.replace(/^spanid\s*:\s*/iu, "").trim();
495
- return id.length > 0 && knownSpanIds.has(id);
496
- }
497
- const candidate = path.isAbsolute(trimmed) ? trimmed : path.join(projectRoot, trimmed);
498
- return exists(candidate);
499
- }
500
- async function anyResolved(values) {
501
- for (const value of values) {
502
- if (await pointerResolves(value))
503
- return true;
504
- }
505
- return false;
506
- }
507
- return {
508
- red: {
509
- pointerSatisfied: await anyResolved(redPointers),
510
- phaseEventsSatisfied: phaseEventsAutoSatisfy.red
511
- },
512
- green: {
513
- pointerSatisfied: await anyResolved(greenPointers),
514
- phaseEventsSatisfied: phaseEventsAutoSatisfy.green
515
- }
516
- };
517
- }
@@ -1,58 +0,0 @@
1
- /**
2
- * Manage the `codex_hooks` feature flag in `~/.codex/config.toml`.
3
- *
4
- * Codex CLI ≥ v0.114 (Mar 2026) exposes lifecycle hooks via
5
- * `.codex/hooks.json`, but the hooks engine is inert unless the user has
6
- * opted into it with:
7
- *
8
- * ```toml
9
- * [features]
10
- * codex_hooks = true
11
- * ```
12
- *
13
- * in `$CODEX_HOME/config.toml` (default: `~/.codex/config.toml`).
14
- * cclaw init/sync can prompt the user to flip this flag for them; sync/runtime diagnostics report the concrete repair when it is missing;
15
- * this module owns the detection / mutation code so the prompt logic in
16
- * `cli.ts` stays small and testable.
17
- *
18
- * The TOML mutations here are intentionally surgical — we never reparse
19
- * or rewrite the whole document. A deliberately narrow regex based
20
- * approach lets the function stay dependency-free and preserves the
21
- * user's comments, whitespace, and custom key ordering.
22
- */
23
- /**
24
- * Absolute path of the Codex config file. Respects `$CODEX_HOME` when
25
- * present (the only override Codex CLI documents); falls back to
26
- * `~/.codex/config.toml` otherwise.
27
- */
28
- export declare function codexConfigPath(env?: NodeJS.ProcessEnv): string;
29
- export type CodexHooksFlagState = "enabled" | "disabled" | "missing-key" | "missing-section" | "missing-file";
30
- /**
31
- * Inspect a TOML document and decide which of the five canonical states
32
- * it represents. Comments and blank lines are ignored. Only the first
33
- * `[features]` section is considered — duplicates are technically invalid
34
- * TOML and Codex rejects them, so cclaw does not try to be clever there.
35
- */
36
- export declare function classifyCodexHooksFlag(toml: string | null): CodexHooksFlagState;
37
- /**
38
- * Return a TOML document with `[features] codex_hooks = true` set.
39
- * Preserves all other content verbatim:
40
- * - If the document lacks a `[features]` section, we append one at the
41
- * end of the file (separated by a blank line).
42
- * - If `[features]` exists without `codex_hooks`, we insert the key
43
- * immediately after the header.
44
- * - If `codex_hooks` exists with any non-`true` value, we rewrite
45
- * just that line.
46
- * - If the flag is already `true`, the input is returned unchanged.
47
- */
48
- export declare function patchCodexHooksFlag(toml: string | null): {
49
- updated: string;
50
- changed: boolean;
51
- };
52
- /**
53
- * Read the Codex config, return `null` when the file does not exist.
54
- * All other read errors propagate so callers can surface a useful
55
- * message instead of silently degrading.
56
- */
57
- export declare function readCodexConfig(configPath: string): Promise<string | null>;
58
- export declare function writeCodexConfig(configPath: string, content: string): Promise<void>;