cclaw-cli 7.7.1 → 8.1.1

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 (284) hide show
  1. package/README.md +211 -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 +107 -511
  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 -768
  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 -134
  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/harness-prompt.d.ts +26 -0
  73. package/dist/harness-prompt.js +142 -0
  74. package/dist/install.d.ts +35 -15
  75. package/dist/install.js +238 -1347
  76. package/dist/knowledge-store.d.ts +19 -163
  77. package/dist/knowledge-store.js +56 -590
  78. package/dist/logger.d.ts +8 -3
  79. package/dist/logger.js +13 -4
  80. package/dist/orchestrator-routing.d.ts +29 -0
  81. package/dist/orchestrator-routing.js +156 -0
  82. package/dist/run-persistence.d.ts +7 -118
  83. package/dist/run-persistence.js +29 -845
  84. package/dist/runtime/run-hook.entry.d.ts +1 -3
  85. package/dist/runtime/run-hook.entry.js +19 -4
  86. package/dist/runtime/run-hook.mjs +13 -1024
  87. package/dist/types.d.ts +25 -261
  88. package/dist/types.js +8 -36
  89. package/package.json +6 -3
  90. package/dist/artifact-linter/brainstorm.d.ts +0 -2
  91. package/dist/artifact-linter/brainstorm.js +0 -353
  92. package/dist/artifact-linter/design.d.ts +0 -18
  93. package/dist/artifact-linter/design.js +0 -444
  94. package/dist/artifact-linter/findings-dedup.d.ts +0 -56
  95. package/dist/artifact-linter/findings-dedup.js +0 -232
  96. package/dist/artifact-linter/plan.d.ts +0 -2
  97. package/dist/artifact-linter/plan.js +0 -826
  98. package/dist/artifact-linter/review-army.d.ts +0 -49
  99. package/dist/artifact-linter/review-army.js +0 -520
  100. package/dist/artifact-linter/review.d.ts +0 -2
  101. package/dist/artifact-linter/review.js +0 -113
  102. package/dist/artifact-linter/scope.d.ts +0 -2
  103. package/dist/artifact-linter/scope.js +0 -158
  104. package/dist/artifact-linter/shared.d.ts +0 -637
  105. package/dist/artifact-linter/shared.js +0 -2163
  106. package/dist/artifact-linter/ship.d.ts +0 -2
  107. package/dist/artifact-linter/ship.js +0 -250
  108. package/dist/artifact-linter/spec.d.ts +0 -2
  109. package/dist/artifact-linter/spec.js +0 -176
  110. package/dist/artifact-linter/tdd.d.ts +0 -118
  111. package/dist/artifact-linter/tdd.js +0 -1404
  112. package/dist/artifact-linter.d.ts +0 -15
  113. package/dist/artifact-linter.js +0 -517
  114. package/dist/codex-feature-flag.d.ts +0 -58
  115. package/dist/codex-feature-flag.js +0 -193
  116. package/dist/content/closeout-guidance.d.ts +0 -14
  117. package/dist/content/closeout-guidance.js +0 -44
  118. package/dist/content/diff-command.d.ts +0 -1
  119. package/dist/content/diff-command.js +0 -43
  120. package/dist/content/harness-doc.d.ts +0 -1
  121. package/dist/content/harness-doc.js +0 -65
  122. package/dist/content/hook-events.d.ts +0 -9
  123. package/dist/content/hook-events.js +0 -23
  124. package/dist/content/hook-manifest.d.ts +0 -81
  125. package/dist/content/hook-manifest.js +0 -156
  126. package/dist/content/hooks.d.ts +0 -11
  127. package/dist/content/hooks.js +0 -1972
  128. package/dist/content/idea.d.ts +0 -60
  129. package/dist/content/idea.js +0 -416
  130. package/dist/content/language-policy.d.ts +0 -2
  131. package/dist/content/language-policy.js +0 -13
  132. package/dist/content/learnings.d.ts +0 -6
  133. package/dist/content/learnings.js +0 -141
  134. package/dist/content/observe.d.ts +0 -19
  135. package/dist/content/observe.js +0 -86
  136. package/dist/content/opencode-plugin.d.ts +0 -1
  137. package/dist/content/opencode-plugin.js +0 -635
  138. package/dist/content/review-prompts.d.ts +0 -1
  139. package/dist/content/review-prompts.js +0 -104
  140. package/dist/content/runtime-shared-snippets.d.ts +0 -8
  141. package/dist/content/runtime-shared-snippets.js +0 -80
  142. package/dist/content/session-hooks.d.ts +0 -7
  143. package/dist/content/session-hooks.js +0 -107
  144. package/dist/content/skills-elicitation.d.ts +0 -1
  145. package/dist/content/skills-elicitation.js +0 -167
  146. package/dist/content/stage-command.d.ts +0 -2
  147. package/dist/content/stage-command.js +0 -17
  148. package/dist/content/stage-schema.d.ts +0 -117
  149. package/dist/content/stage-schema.js +0 -955
  150. package/dist/content/stages/_lint-metadata/index.d.ts +0 -2
  151. package/dist/content/stages/_lint-metadata/index.js +0 -97
  152. package/dist/content/stages/brainstorm.d.ts +0 -2
  153. package/dist/content/stages/brainstorm.js +0 -184
  154. package/dist/content/stages/design.d.ts +0 -2
  155. package/dist/content/stages/design.js +0 -288
  156. package/dist/content/stages/index.d.ts +0 -8
  157. package/dist/content/stages/index.js +0 -11
  158. package/dist/content/stages/plan.d.ts +0 -2
  159. package/dist/content/stages/plan.js +0 -191
  160. package/dist/content/stages/review.d.ts +0 -2
  161. package/dist/content/stages/review.js +0 -240
  162. package/dist/content/stages/schema-types.d.ts +0 -203
  163. package/dist/content/stages/schema-types.js +0 -1
  164. package/dist/content/stages/scope.d.ts +0 -2
  165. package/dist/content/stages/scope.js +0 -254
  166. package/dist/content/stages/ship.d.ts +0 -2
  167. package/dist/content/stages/ship.js +0 -159
  168. package/dist/content/stages/spec.d.ts +0 -2
  169. package/dist/content/stages/spec.js +0 -170
  170. package/dist/content/stages/tdd.d.ts +0 -4
  171. package/dist/content/stages/tdd.js +0 -273
  172. package/dist/content/state-contracts.d.ts +0 -1
  173. package/dist/content/state-contracts.js +0 -63
  174. package/dist/content/status-command.d.ts +0 -4
  175. package/dist/content/status-command.js +0 -109
  176. package/dist/content/subagent-context-skills.d.ts +0 -4
  177. package/dist/content/subagent-context-skills.js +0 -279
  178. package/dist/content/subagents.d.ts +0 -3
  179. package/dist/content/subagents.js +0 -997
  180. package/dist/content/templates.d.ts +0 -26
  181. package/dist/content/templates.js +0 -1692
  182. package/dist/content/track-render-context.d.ts +0 -18
  183. package/dist/content/track-render-context.js +0 -53
  184. package/dist/content/tree-command.d.ts +0 -1
  185. package/dist/content/tree-command.js +0 -64
  186. package/dist/content/utility-skills.d.ts +0 -30
  187. package/dist/content/utility-skills.js +0 -160
  188. package/dist/content/view-command.d.ts +0 -2
  189. package/dist/content/view-command.js +0 -92
  190. package/dist/delegation.d.ts +0 -649
  191. package/dist/delegation.js +0 -1539
  192. package/dist/early-loop.d.ts +0 -70
  193. package/dist/early-loop.js +0 -302
  194. package/dist/execution-topology.d.ts +0 -44
  195. package/dist/execution-topology.js +0 -95
  196. package/dist/gate-evidence.d.ts +0 -85
  197. package/dist/gate-evidence.js +0 -631
  198. package/dist/harness-adapters.d.ts +0 -151
  199. package/dist/harness-adapters.js +0 -756
  200. package/dist/harness-selection.d.ts +0 -31
  201. package/dist/harness-selection.js +0 -214
  202. package/dist/hook-schema.d.ts +0 -6
  203. package/dist/hook-schema.js +0 -114
  204. package/dist/hook-schemas/claude-hooks.v1.json +0 -10
  205. package/dist/hook-schemas/codex-hooks.v1.json +0 -10
  206. package/dist/hook-schemas/cursor-hooks.v1.json +0 -13
  207. package/dist/init-detect.d.ts +0 -2
  208. package/dist/init-detect.js +0 -50
  209. package/dist/internal/advance-stage/advance.d.ts +0 -89
  210. package/dist/internal/advance-stage/advance.js +0 -655
  211. package/dist/internal/advance-stage/cancel-run.d.ts +0 -8
  212. package/dist/internal/advance-stage/cancel-run.js +0 -19
  213. package/dist/internal/advance-stage/flow-state-coercion.d.ts +0 -3
  214. package/dist/internal/advance-stage/flow-state-coercion.js +0 -81
  215. package/dist/internal/advance-stage/helpers.d.ts +0 -14
  216. package/dist/internal/advance-stage/helpers.js +0 -145
  217. package/dist/internal/advance-stage/hook.d.ts +0 -8
  218. package/dist/internal/advance-stage/hook.js +0 -40
  219. package/dist/internal/advance-stage/parsers.d.ts +0 -72
  220. package/dist/internal/advance-stage/parsers.js +0 -357
  221. package/dist/internal/advance-stage/proactive-delegation-trace.d.ts +0 -24
  222. package/dist/internal/advance-stage/proactive-delegation-trace.js +0 -56
  223. package/dist/internal/advance-stage/review-loop.d.ts +0 -16
  224. package/dist/internal/advance-stage/review-loop.js +0 -199
  225. package/dist/internal/advance-stage/rewind.d.ts +0 -14
  226. package/dist/internal/advance-stage/rewind.js +0 -108
  227. package/dist/internal/advance-stage/start-flow.d.ts +0 -13
  228. package/dist/internal/advance-stage/start-flow.js +0 -241
  229. package/dist/internal/advance-stage/verify.d.ts +0 -21
  230. package/dist/internal/advance-stage/verify.js +0 -185
  231. package/dist/internal/advance-stage.d.ts +0 -7
  232. package/dist/internal/advance-stage.js +0 -138
  233. package/dist/internal/cohesion-contract-stub.d.ts +0 -24
  234. package/dist/internal/cohesion-contract-stub.js +0 -148
  235. package/dist/internal/compound-readiness.d.ts +0 -23
  236. package/dist/internal/compound-readiness.js +0 -102
  237. package/dist/internal/detect-public-api-changes.d.ts +0 -5
  238. package/dist/internal/detect-public-api-changes.js +0 -45
  239. package/dist/internal/detect-supply-chain-changes.d.ts +0 -6
  240. package/dist/internal/detect-supply-chain-changes.js +0 -138
  241. package/dist/internal/early-loop-status.d.ts +0 -7
  242. package/dist/internal/early-loop-status.js +0 -93
  243. package/dist/internal/envelope-validate.d.ts +0 -7
  244. package/dist/internal/envelope-validate.js +0 -66
  245. package/dist/internal/flow-state-repair.d.ts +0 -20
  246. package/dist/internal/flow-state-repair.js +0 -104
  247. package/dist/internal/plan-split-waves.d.ts +0 -190
  248. package/dist/internal/plan-split-waves.js +0 -764
  249. package/dist/internal/runtime-integrity.d.ts +0 -7
  250. package/dist/internal/runtime-integrity.js +0 -268
  251. package/dist/internal/slice-commit.d.ts +0 -7
  252. package/dist/internal/slice-commit.js +0 -619
  253. package/dist/internal/tdd-loop-status.d.ts +0 -14
  254. package/dist/internal/tdd-loop-status.js +0 -68
  255. package/dist/internal/tdd-red-evidence.d.ts +0 -7
  256. package/dist/internal/tdd-red-evidence.js +0 -153
  257. package/dist/internal/waiver-grant.d.ts +0 -62
  258. package/dist/internal/waiver-grant.js +0 -294
  259. package/dist/internal/wave-status.d.ts +0 -74
  260. package/dist/internal/wave-status.js +0 -506
  261. package/dist/managed-resources.d.ts +0 -53
  262. package/dist/managed-resources.js +0 -313
  263. package/dist/policy.d.ts +0 -10
  264. package/dist/policy.js +0 -167
  265. package/dist/retro-gate.d.ts +0 -9
  266. package/dist/retro-gate.js +0 -47
  267. package/dist/run-archive.d.ts +0 -61
  268. package/dist/run-archive.js +0 -391
  269. package/dist/runs.d.ts +0 -2
  270. package/dist/runs.js +0 -2
  271. package/dist/stack-detection.d.ts +0 -116
  272. package/dist/stack-detection.js +0 -489
  273. package/dist/streaming/event-stream.d.ts +0 -31
  274. package/dist/streaming/event-stream.js +0 -114
  275. package/dist/tdd-cycle.d.ts +0 -107
  276. package/dist/tdd-cycle.js +0 -289
  277. package/dist/tdd-verification-evidence.d.ts +0 -17
  278. package/dist/tdd-verification-evidence.js +0 -122
  279. package/dist/track-heuristics.d.ts +0 -27
  280. package/dist/track-heuristics.js +0 -154
  281. package/dist/util/slice-id.d.ts +0 -58
  282. package/dist/util/slice-id.js +0 -89
  283. package/dist/worktree-manager.d.ts +0 -20
  284. 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>;