cclaw-cli 0.51.29 → 0.55.2

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 (151) hide show
  1. package/README.md +22 -16
  2. package/dist/artifact-linter/brainstorm.d.ts +2 -0
  3. package/dist/artifact-linter/brainstorm.js +245 -0
  4. package/dist/artifact-linter/design.d.ts +2 -0
  5. package/dist/artifact-linter/design.js +323 -0
  6. package/dist/artifact-linter/plan.d.ts +2 -0
  7. package/dist/artifact-linter/plan.js +162 -0
  8. package/dist/artifact-linter/review-army.d.ts +24 -0
  9. package/dist/artifact-linter/review-army.js +365 -0
  10. package/dist/artifact-linter/review.d.ts +2 -0
  11. package/dist/artifact-linter/review.js +65 -0
  12. package/dist/artifact-linter/scope.d.ts +2 -0
  13. package/dist/artifact-linter/scope.js +115 -0
  14. package/dist/artifact-linter/shared.d.ts +246 -0
  15. package/dist/artifact-linter/shared.js +1488 -0
  16. package/dist/artifact-linter/ship.d.ts +2 -0
  17. package/dist/artifact-linter/ship.js +46 -0
  18. package/dist/artifact-linter/spec.d.ts +2 -0
  19. package/dist/artifact-linter/spec.js +108 -0
  20. package/dist/artifact-linter/tdd.d.ts +2 -0
  21. package/dist/artifact-linter/tdd.js +124 -0
  22. package/dist/artifact-linter.d.ts +4 -76
  23. package/dist/artifact-linter.js +56 -2949
  24. package/dist/cli.d.ts +2 -18
  25. package/dist/cli.js +8 -246
  26. package/dist/codex-feature-flag.d.ts +1 -1
  27. package/dist/codex-feature-flag.js +1 -1
  28. package/dist/config.d.ts +3 -2
  29. package/dist/config.js +67 -3
  30. package/dist/constants.d.ts +1 -7
  31. package/dist/constants.js +9 -15
  32. package/dist/content/cancel-command.js +2 -2
  33. package/dist/content/closeout-guidance.js +13 -10
  34. package/dist/content/core-agents.d.ts +18 -0
  35. package/dist/content/core-agents.js +51 -7
  36. package/dist/content/decision-protocol.d.ts +1 -1
  37. package/dist/content/decision-protocol.js +1 -1
  38. package/dist/content/examples.js +6 -6
  39. package/dist/content/harness-doc.js +20 -2
  40. package/dist/content/hook-inline-snippets.d.ts +17 -4
  41. package/dist/content/hook-inline-snippets.js +218 -5
  42. package/dist/content/hook-manifest.d.ts +2 -2
  43. package/dist/content/hook-manifest.js +2 -2
  44. package/dist/content/hooks.d.ts +1 -0
  45. package/dist/content/hooks.js +32 -137
  46. package/dist/content/idea-command.d.ts +8 -0
  47. package/dist/content/{ideate-command.js → idea-command.js} +57 -50
  48. package/dist/content/idea-frames.d.ts +31 -0
  49. package/dist/content/{ideate-frames.js → idea-frames.js} +9 -9
  50. package/dist/content/idea-ranking.d.ts +25 -0
  51. package/dist/content/{ideate-ranking.js → idea-ranking.js} +5 -5
  52. package/dist/content/iron-laws.d.ts +0 -1
  53. package/dist/content/iron-laws.js +31 -16
  54. package/dist/content/learnings.js +1 -1
  55. package/dist/content/meta-skill.js +11 -13
  56. package/dist/content/node-hooks.d.ts +10 -0
  57. package/dist/content/node-hooks.js +45 -11
  58. package/dist/content/opencode-plugin.js +3 -3
  59. package/dist/content/session-hooks.js +1 -1
  60. package/dist/content/skills.js +19 -7
  61. package/dist/content/stage-command.js +1 -1
  62. package/dist/content/stage-schema.js +44 -2
  63. package/dist/content/stages/_lint-metadata/index.js +26 -2
  64. package/dist/content/stages/brainstorm.js +13 -7
  65. package/dist/content/stages/design.js +16 -11
  66. package/dist/content/stages/plan.js +9 -6
  67. package/dist/content/stages/review.js +4 -4
  68. package/dist/content/stages/schema-types.d.ts +1 -1
  69. package/dist/content/stages/scope.js +15 -12
  70. package/dist/content/stages/ship.js +2 -2
  71. package/dist/content/stages/spec.js +9 -3
  72. package/dist/content/stages/tdd.js +14 -4
  73. package/dist/content/start-command.d.ts +2 -2
  74. package/dist/content/start-command.js +24 -21
  75. package/dist/content/status-command.js +8 -8
  76. package/dist/content/subagents.js +61 -7
  77. package/dist/content/templates.d.ts +1 -1
  78. package/dist/content/templates.js +104 -152
  79. package/dist/content/tree-command.js +2 -2
  80. package/dist/content/utility-skills.d.ts +2 -2
  81. package/dist/content/utility-skills.js +2 -2
  82. package/dist/content/view-command.js +4 -2
  83. package/dist/delegation.d.ts +2 -0
  84. package/dist/delegation.js +2 -1
  85. package/dist/early-loop.d.ts +66 -0
  86. package/dist/early-loop.js +275 -0
  87. package/dist/flow-state.d.ts +1 -1
  88. package/dist/flow-state.js +1 -1
  89. package/dist/gate-evidence.d.ts +8 -0
  90. package/dist/gate-evidence.js +141 -5
  91. package/dist/harness-adapters.d.ts +2 -2
  92. package/dist/harness-adapters.js +54 -122
  93. package/dist/harness-selection.d.ts +31 -0
  94. package/dist/harness-selection.js +214 -0
  95. package/dist/install.js +166 -38
  96. package/dist/internal/advance-stage/advance.d.ts +50 -0
  97. package/dist/internal/advance-stage/advance.js +480 -0
  98. package/dist/internal/advance-stage/cancel-run.d.ts +8 -0
  99. package/dist/internal/advance-stage/cancel-run.js +19 -0
  100. package/dist/internal/advance-stage/flow-state-coercion.d.ts +3 -0
  101. package/dist/internal/advance-stage/flow-state-coercion.js +81 -0
  102. package/dist/internal/advance-stage/helpers.d.ts +14 -0
  103. package/dist/internal/advance-stage/helpers.js +145 -0
  104. package/dist/internal/advance-stage/hook.d.ts +8 -0
  105. package/dist/internal/advance-stage/hook.js +40 -0
  106. package/dist/internal/advance-stage/parsers.d.ts +54 -0
  107. package/dist/internal/advance-stage/parsers.js +307 -0
  108. package/dist/internal/advance-stage/review-loop.d.ts +7 -0
  109. package/dist/internal/advance-stage/review-loop.js +170 -0
  110. package/dist/internal/advance-stage/rewind.d.ts +14 -0
  111. package/dist/internal/advance-stage/rewind.js +108 -0
  112. package/dist/internal/advance-stage/start-flow.d.ts +11 -0
  113. package/dist/internal/advance-stage/start-flow.js +136 -0
  114. package/dist/internal/advance-stage/verify.d.ts +29 -0
  115. package/dist/internal/advance-stage/verify.js +225 -0
  116. package/dist/internal/advance-stage.js +21 -1470
  117. package/dist/internal/compound-readiness.d.ts +1 -1
  118. package/dist/internal/compound-readiness.js +2 -2
  119. package/dist/internal/early-loop-status.d.ts +7 -0
  120. package/dist/internal/early-loop-status.js +90 -0
  121. package/dist/internal/runtime-integrity.d.ts +7 -0
  122. package/dist/internal/runtime-integrity.js +288 -0
  123. package/dist/internal/tdd-red-evidence.js +1 -1
  124. package/dist/knowledge-store.d.ts +3 -8
  125. package/dist/knowledge-store.js +16 -29
  126. package/dist/managed-resources.js +24 -2
  127. package/dist/policy.js +5 -7
  128. package/dist/run-archive.d.ts +1 -1
  129. package/dist/run-archive.js +16 -16
  130. package/dist/run-persistence.js +112 -12
  131. package/dist/tdd-cycle.d.ts +3 -3
  132. package/dist/tdd-cycle.js +1 -1
  133. package/dist/types.d.ts +18 -10
  134. package/package.json +1 -1
  135. package/dist/content/finish-command.d.ts +0 -2
  136. package/dist/content/finish-command.js +0 -26
  137. package/dist/content/ideate-command.d.ts +0 -8
  138. package/dist/content/ideate-frames.d.ts +0 -31
  139. package/dist/content/ideate-ranking.d.ts +0 -25
  140. package/dist/content/next-command.d.ts +0 -20
  141. package/dist/content/next-command.js +0 -298
  142. package/dist/content/seed-shelf.d.ts +0 -36
  143. package/dist/content/seed-shelf.js +0 -301
  144. package/dist/content/stage-common-guidance.d.ts +0 -1
  145. package/dist/content/stage-common-guidance.js +0 -106
  146. package/dist/doctor-registry.d.ts +0 -10
  147. package/dist/doctor-registry.js +0 -186
  148. package/dist/doctor.d.ts +0 -17
  149. package/dist/doctor.js +0 -2206
  150. package/dist/internal/hook-manifest.d.ts +0 -16
  151. package/dist/internal/hook-manifest.js +0 -77
@@ -0,0 +1,2 @@
1
+ import { type StageLintContext } from "./shared.js";
2
+ export declare function lintShipStage(ctx: StageLintContext): Promise<void>;
@@ -0,0 +1,46 @@
1
+ import { sectionBodyByName } from "./shared.js";
2
+ export async function lintShipStage(ctx) {
3
+ const { projectRoot, track, raw, absFile, sections, findings, parsedFrontmatter, brainstormShortCircuitBody, brainstormShortCircuitActivated, staleDiagramAuditEnabled, isTrivialOverride } = ctx;
4
+ // Universal Layer 2.8 structural checks (superpowers finishing-a-development-branch).
5
+ const optionsBody = sectionBodyByName(sections, "Finalization Options");
6
+ if (optionsBody !== null) {
7
+ const required = ["MERGE_LOCAL", "OPEN_PR", "KEEP_BRANCH", "DISCARD"];
8
+ const missing = required.filter((token) => !optionsBody.includes(token));
9
+ findings.push({
10
+ section: "Finalization Options Coverage",
11
+ required: true,
12
+ rule: "Finalization Options must surface all four canonical options (MERGE_LOCAL, OPEN_PR, KEEP_BRANCH, DISCARD).",
13
+ found: missing.length === 0,
14
+ details: missing.length === 0
15
+ ? "All four finalization options surfaced."
16
+ : `Finalization Options is missing token(s): ${missing.join(", ")}.`
17
+ });
18
+ }
19
+ const prBody = sectionBodyByName(sections, "Structured PR Body");
20
+ if (prBody !== null) {
21
+ const required = ["## Summary", "## Test Plan", "## Commits Included"];
22
+ const missing = required.filter((token) => !prBody.includes(token));
23
+ findings.push({
24
+ section: "Structured PR Body Shape",
25
+ required: true,
26
+ rule: "Structured PR Body must include `## Summary`, `## Test Plan`, and `## Commits Included` subsections.",
27
+ found: missing.length === 0,
28
+ details: missing.length === 0
29
+ ? "Structured PR Body covers all required subsections."
30
+ : `Structured PR Body is missing subsection(s): ${missing.join(", ")}.`
31
+ });
32
+ }
33
+ const verifyBody = sectionBodyByName(sections, "Verify Tests Gate");
34
+ if (verifyBody !== null) {
35
+ const ok = /\bResult:\s*(PASS|FAIL)\b/iu.test(verifyBody);
36
+ findings.push({
37
+ section: "Verify Tests Gate Result",
38
+ required: true,
39
+ rule: "Verify Tests Gate must declare a Result of PASS or FAIL.",
40
+ found: ok,
41
+ details: ok
42
+ ? "Verify Tests Gate result declared."
43
+ : "Verify Tests Gate is missing a `Result: PASS|FAIL` line."
44
+ });
45
+ }
46
+ }
@@ -0,0 +1,2 @@
1
+ import { type StageLintContext } from "./shared.js";
2
+ export declare function lintSpecStage(ctx: StageLintContext): Promise<void>;
@@ -0,0 +1,108 @@
1
+ import { sectionBodyByName, SPEC_MAX_MODULES } from "./shared.js";
2
+ export async function lintSpecStage(ctx) {
3
+ const { projectRoot, track, raw, absFile, sections, findings, parsedFrontmatter, brainstormShortCircuitBody, brainstormShortCircuitActivated, staleDiagramAuditEnabled, isTrivialOverride } = ctx;
4
+ // Universal Layer 2.4 structural checks (evanflow-prd + superpowers).
5
+ // All checks fire only when the matching section is present so legacy
6
+ // fixtures keep working while v3-template artifacts are validated.
7
+ const synthesisBody = sectionBodyByName(sections, "Synthesis Sources");
8
+ if (synthesisBody !== null) {
9
+ const tableRows = synthesisBody
10
+ .split("\n")
11
+ .filter((line) => /^\|/u.test(line));
12
+ const dataRows = tableRows.length >= 3 ? tableRows.slice(2) : [];
13
+ const populatedRows = dataRows.filter((row) => row
14
+ .split("|")
15
+ .slice(1, -1)
16
+ .some((cell) => cell.trim().length > 0));
17
+ const hasRow = populatedRows.length >= 1;
18
+ findings.push({
19
+ section: "Synthesis Sources Coverage",
20
+ required: true,
21
+ rule: "Synthesis Sources must cite at least one source artifact (synthesize-not-interview).",
22
+ found: hasRow,
23
+ details: hasRow
24
+ ? `Detected ${populatedRows.length} populated source row(s).`
25
+ : "Synthesis Sources is empty; spec must cite at least one upstream artifact or context file."
26
+ });
27
+ }
28
+ const behaviorBody = sectionBodyByName(sections, "Behavior Contract");
29
+ if (behaviorBody !== null) {
30
+ const optedOut = /(^|\n)\s*-\s*None\b/iu.test(behaviorBody);
31
+ const userStoryRegex = /(^|\n)\s*-\s*as\s+a\b[\s\S]*?,\s*i\s+can\b[\s\S]*?,\s*so that\b/imu;
32
+ const givenWhenThenRegex = /(^|\n)\s*-\s*given\b[\s\S]*?,\s*when\b[\s\S]*?,\s*then\b/imu;
33
+ const matches = [
34
+ ...behaviorBody.matchAll(/(^|\n)\s*-\s*as\s+a\b[\s\S]*?,\s*i\s+can\b[\s\S]*?,\s*so that\b/gimu),
35
+ ...behaviorBody.matchAll(/(^|\n)\s*-\s*given\b[\s\S]*?,\s*when\b[\s\S]*?,\s*then\b/gimu)
36
+ ];
37
+ const ok = optedOut || matches.length >= 3;
38
+ findings.push({
39
+ section: "Behavior Contract Shape",
40
+ required: true,
41
+ rule: "Behavior Contract must list ≥3 behaviors in user-story (As a/I can/so that) or Given/When/Then form, or declare `- None.` for single-step specs.",
42
+ found: ok,
43
+ details: optedOut
44
+ ? "Single-step spec; behaviors opted out via `- None.`."
45
+ : ok
46
+ ? `Detected ${matches.length} behavior(s) in canonical form.`
47
+ : `Detected ${matches.length} behavior(s) in canonical form; need ≥3 (or `
48
+ + "`- None.`).",
49
+ });
50
+ // Bonus: detect if at least one user-story OR given/when/then form is present
51
+ // (mirrors existing helpers).
52
+ void userStoryRegex;
53
+ void givenWhenThenRegex;
54
+ }
55
+ const archModulesBody = sectionBodyByName(sections, "Architecture Modules");
56
+ if (archModulesBody !== null) {
57
+ const codeFenceCount = (archModulesBody.match(/```/gu) ?? []).length;
58
+ const fnSignatureRegex = /\b(function|class|def|fn|method)\b\s+[A-Za-z_]/u;
59
+ const noCode = codeFenceCount === 0 && !fnSignatureRegex.test(archModulesBody);
60
+ findings.push({
61
+ section: "Architecture Modules No-Code",
62
+ required: true,
63
+ rule: "Architecture Modules must not contain code blocks, function signatures, or class definitions — modules listed by responsibility only.",
64
+ found: noCode,
65
+ details: noCode
66
+ ? "Architecture Modules is free of code blocks and function/class signatures."
67
+ : "Architecture Modules contains a code fence or function/class signature; remove code-level details."
68
+ });
69
+ const tableRows = archModulesBody.split("\n").filter((line) => /^\|/u.test(line));
70
+ const dataRows = tableRows.length >= 3 ? tableRows.slice(2) : [];
71
+ const moduleNames = dataRows
72
+ .map((row) => row.split("|").slice(1, -1)[0]?.trim() ?? "")
73
+ .filter((name) => name.length > 0 && name !== "-" && !/^module$/iu.test(name));
74
+ const uniqueModuleCount = new Set(moduleNames).size;
75
+ findings.push({
76
+ section: "Single-Subsystem Scope",
77
+ required: false,
78
+ rule: `Architecture Modules should stay within one coherent subsystem boundary (<= ${SPEC_MAX_MODULES} named modules).`,
79
+ found: uniqueModuleCount <= SPEC_MAX_MODULES,
80
+ details: uniqueModuleCount <= SPEC_MAX_MODULES
81
+ ? `Module count (${uniqueModuleCount}) stays within single-subsystem guidance.`
82
+ : `Architecture Modules lists ${uniqueModuleCount} modules (> ${SPEC_MAX_MODULES}); split into sub-specs or narrow scope before plan handoff.`
83
+ });
84
+ }
85
+ const selfReviewBody = sectionBodyByName(sections, "Spec Self-Review");
86
+ if (selfReviewBody === null) {
87
+ findings.push({
88
+ section: "Spec Self-Review Coverage",
89
+ required: true,
90
+ rule: "Spec Self-Review must cover placeholder/consistency/scope/ambiguity checks.",
91
+ found: false,
92
+ details: "No ## heading matching required section \"Spec Self-Review\"."
93
+ });
94
+ }
95
+ else {
96
+ const required = ["placeholder", "consistency", "scope", "ambiguity"];
97
+ const missing = required.filter((token) => !new RegExp(token, "iu").test(selfReviewBody));
98
+ findings.push({
99
+ section: "Spec Self-Review Coverage",
100
+ required: true,
101
+ rule: "Spec Self-Review must cover placeholder/consistency/scope/ambiguity checks.",
102
+ found: missing.length === 0,
103
+ details: missing.length === 0
104
+ ? "Spec Self-Review covers all required checks."
105
+ : `Spec Self-Review is missing check(s): ${missing.join(", ")}.`
106
+ });
107
+ }
108
+ }
@@ -0,0 +1,2 @@
1
+ import { type StageLintContext } from "./shared.js";
2
+ export declare function lintTddStage(ctx: StageLintContext): Promise<void>;
@@ -0,0 +1,124 @@
1
+ import { sectionBodyByName } from "./shared.js";
2
+ export async function lintTddStage(ctx) {
3
+ const { projectRoot, track, raw, absFile, sections, findings, parsedFrontmatter, brainstormShortCircuitBody, brainstormShortCircuitActivated, staleDiagramAuditEnabled, isTrivialOverride } = ctx;
4
+ // Universal Layer 2.6 structural checks (superpowers TDD + evanflow vertical slices).
5
+ const ironLawBody = sectionBodyByName(sections, "Iron Law Acknowledgement");
6
+ if (ironLawBody === null) {
7
+ findings.push({
8
+ section: "TDD Iron Law Acknowledgement",
9
+ required: true,
10
+ rule: "Iron Law Acknowledgement must affirm `Acknowledged: yes`.",
11
+ found: false,
12
+ details: "No ## heading matching required section \"Iron Law Acknowledgement\"."
13
+ });
14
+ }
15
+ else {
16
+ const ack = /acknowledged:\s*(yes|true|y)\b/iu.test(ironLawBody);
17
+ findings.push({
18
+ section: "TDD Iron Law Acknowledgement",
19
+ required: true,
20
+ rule: "Iron Law Acknowledgement must affirm `Acknowledged: yes`.",
21
+ found: ack,
22
+ details: ack
23
+ ? "TDD Iron Law acknowledged."
24
+ : "Iron Law Acknowledgement is missing explicit `Acknowledged: yes`."
25
+ });
26
+ }
27
+ const watchedRedBody = sectionBodyByName(sections, "Watched-RED Proof");
28
+ if (watchedRedBody === null) {
29
+ findings.push({
30
+ section: "Watched-RED Proof Shape",
31
+ required: true,
32
+ rule: "Watched-RED Proof must include at least one populated row, and each row must include an ISO timestamp showing when the test was observed failing.",
33
+ found: false,
34
+ details: "No ## heading matching required section \"Watched-RED Proof\"."
35
+ });
36
+ }
37
+ else {
38
+ const rows = watchedRedBody.split("\n").filter((line) => /^\|/u.test(line));
39
+ const dataRows = rows.length >= 3 ? rows.slice(2) : [];
40
+ const populatedRows = dataRows.filter((row) => row
41
+ .split("|")
42
+ .slice(1, -1)
43
+ .filter((_, idx) => idx !== 0) // skip slice column
44
+ .some((cell) => cell.trim().length > 0));
45
+ // Each populated row must include an ISO timestamp in column 3.
46
+ const isoRegex = /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}/u;
47
+ const validProofRows = populatedRows.filter((row) => isoRegex.test(row));
48
+ const hasPopulatedRows = populatedRows.length > 0;
49
+ const allRowsHaveIso = validProofRows.length === populatedRows.length;
50
+ findings.push({
51
+ section: "Watched-RED Proof Shape",
52
+ required: true,
53
+ rule: "Watched-RED Proof must include at least one populated row, and each row must include an ISO timestamp showing when the test was observed failing.",
54
+ found: hasPopulatedRows && allRowsHaveIso,
55
+ details: !hasPopulatedRows
56
+ ? "Watched-RED Proof has no populated rows; add at least one slice row with observed RED evidence."
57
+ : allRowsHaveIso
58
+ ? `All ${populatedRows.length} watched-RED proof row(s) include an ISO timestamp.`
59
+ : `${populatedRows.length - validProofRows.length} watched-RED proof row(s) lack an ISO timestamp.`
60
+ });
61
+ }
62
+ const sliceCycleBody = sectionBodyByName(sections, "Vertical Slice Cycle");
63
+ if (sliceCycleBody === null) {
64
+ findings.push({
65
+ section: "Vertical Slice Cycle Coverage",
66
+ required: true,
67
+ rule: "Vertical Slice Cycle must include RED, GREEN, and REFACTOR per slice (refactor may be deferred with rationale).",
68
+ found: false,
69
+ details: "No ## heading matching required section \"Vertical Slice Cycle\"."
70
+ });
71
+ }
72
+ else {
73
+ const required = ["RED", "GREEN", "REFACTOR"];
74
+ const missing = required.filter((token) => !new RegExp(token, "u").test(sliceCycleBody));
75
+ findings.push({
76
+ section: "Vertical Slice Cycle Coverage",
77
+ required: true,
78
+ rule: "Vertical Slice Cycle must include RED, GREEN, and REFACTOR per slice (refactor may be deferred with rationale).",
79
+ found: missing.length === 0,
80
+ details: missing.length === 0
81
+ ? "Vertical Slice Cycle references RED/GREEN/REFACTOR."
82
+ : `Vertical Slice Cycle is missing phase token(s): ${missing.join(", ")}.`
83
+ });
84
+ }
85
+ const assertionBody = sectionBodyByName(sections, "Assertion Correctness Notes");
86
+ if (assertionBody !== null) {
87
+ const tableRows = assertionBody.split("\n").filter((line) => /^\|/u.test(line));
88
+ const dataRows = tableRows.length >= 3 ? tableRows.slice(2) : [];
89
+ const ok = dataRows.length === 0 || dataRows.some((row) => row
90
+ .split("|")
91
+ .slice(1, -1)
92
+ .some((cell) => cell.trim().length > 0));
93
+ findings.push({
94
+ section: "Assertion Correctness Notes Shape",
95
+ required: true,
96
+ rule: "Assertion Correctness Notes must include at least one populated row when the slice has new assertions.",
97
+ found: ok,
98
+ details: ok
99
+ ? "Assertion Correctness Notes is populated or absent (single-step slice)."
100
+ : "Assertion Correctness Notes table has no populated rows."
101
+ });
102
+ }
103
+ const testDiscoveryBody = sectionBodyByName(sections, "Test Discovery") ?? "";
104
+ const redEvidenceBody = sectionBodyByName(sections, "RED Evidence") ?? "";
105
+ const mockPreferenceScanBody = `${testDiscoveryBody}\n${redEvidenceBody}`;
106
+ const mockTokenRegex = /\b(jest\.mock|vi\.mock|sinon\.stub|mock\.patch|unittest\.mock|magicmock|spyon|tohavebeencalled)\b/iu;
107
+ if (mockTokenRegex.test(mockPreferenceScanBody)) {
108
+ const boundaryJustificationRegex = /\b(justified\s+by\s+boundary|boundary:\s*[A-Za-z0-9/_ -]*(network|fs|filesystem|time|clock|external)|network|filesystem|clock|external\s+service)\b/iu;
109
+ const hasBoundaryJustification = boundaryJustificationRegex.test(mockPreferenceScanBody);
110
+ const realPathRegex = /\b(?:src|lib|packages|apps)\/[A-Za-z0-9_./-]+\b/u;
111
+ const hasRealPathHint = realPathRegex.test(mockPreferenceScanBody);
112
+ findings.push({
113
+ section: "Mock Preference Heuristic",
114
+ required: false,
115
+ rule: "When mocks/spies appear in Test Discovery or RED Evidence, prefer Real > Fake > Stub > Mock. Mock-heavy slices need explicit boundary justification (network/fs/time/external).",
116
+ found: hasBoundaryJustification,
117
+ details: hasBoundaryJustification
118
+ ? "Mock usage is explicitly justified by boundary constraints."
119
+ : hasRealPathHint
120
+ ? "Mocks/spies detected while real implementation paths are listed; prefer Real > Fake > Stub > Mock unless a boundary justification is added."
121
+ : "Mocks/spies detected without boundary justification; add explicit trust-boundary rationale or replace with real/fake/stub coverage."
122
+ });
123
+ }
124
+ }
@@ -1,77 +1,5 @@
1
- import { type FlowStage, type FlowTrack } from "./types.js";
2
- export interface LintFinding {
3
- section: string;
4
- required: boolean;
5
- rule: string;
6
- found: boolean;
7
- details: string;
8
- }
9
- export interface LintResult {
10
- stage: string;
11
- file: string;
12
- passed: boolean;
13
- findings: LintFinding[];
14
- }
15
- export declare function extractMarkdownSectionBody(markdown: string, section: string): string | null;
16
- export type LearningEntryType = "rule" | "pattern" | "lesson" | "compound";
17
- export type LearningConfidence = "high" | "medium" | "low";
18
- export type LearningSeverity = "critical" | "important" | "suggestion";
19
- export type LearningUniversality = "project" | "personal" | "universal";
20
- export type LearningMaturity = "raw" | "lifted-to-rule" | "lifted-to-enforcement";
21
- export type LearningSource = "stage" | "retro" | "compound" | "ideate" | "manual";
22
- export interface LearningSeedEntry {
23
- type: LearningEntryType;
24
- trigger: string;
25
- action: string;
26
- confidence: LearningConfidence;
27
- severity?: LearningSeverity;
28
- domain?: string | null;
29
- stage?: FlowStage | null;
30
- origin_stage?: FlowStage | null;
31
- origin_run?: string | null;
32
- /** @deprecated Use `origin_run`. Accepted only for legacy learning bullets. */
33
- origin_feature?: string | null;
34
- frequency?: number;
35
- universality?: LearningUniversality;
36
- maturity?: LearningMaturity;
37
- created?: string;
38
- first_seen_ts?: string;
39
- last_seen_ts?: string;
40
- project?: string | null;
41
- source?: LearningSource | null;
42
- supersedes?: string[];
43
- superseded_by?: string;
44
- }
45
- export interface LearningsParseResult {
46
- ok: boolean;
47
- none: boolean;
48
- entries: LearningSeedEntry[];
49
- errors: string[];
50
- details: string;
51
- }
52
- export declare function parseLearningsSection(sectionBody: string): LearningsParseResult;
1
+ import type { FlowStage, FlowTrack } from "./types.js";
2
+ import { type LintResult } from "./artifact-linter/shared.js";
3
+ export { validateReviewArmy, checkReviewVerdictConsistency, checkReviewSecurityNoChangeAttestation, type ReviewVerdictConsistencyResult, type ReviewSecurityNoChangeAttestationResult } from "./artifact-linter/review-army.js";
4
+ export { type LintFinding, type LintResult, type LearningEntryType, type LearningConfidence, type LearningSeverity, type LearningUniversality, type LearningMaturity, type LearningSource, type LearningSeedEntry, type LearningsParseResult, extractMarkdownSectionBody, parseLearningsSection } from "./artifact-linter/shared.js";
53
5
  export declare function lintArtifact(projectRoot: string, stage: FlowStage, track?: FlowTrack): Promise<LintResult>;
54
- export declare function validateReviewArmy(projectRoot: string): Promise<{
55
- valid: boolean;
56
- errors: string[];
57
- }>;
58
- export interface ReviewVerdictConsistencyResult {
59
- ok: boolean;
60
- errors: string[];
61
- finalVerdict: "APPROVED" | "APPROVED_WITH_CONCERNS" | "BLOCKED" | "UNKNOWN";
62
- openCriticalCount: number;
63
- shipBlockerCount: number;
64
- }
65
- export interface ReviewSecurityNoChangeAttestationResult {
66
- ok: boolean;
67
- errors: string[];
68
- hasSecurityFinding: boolean;
69
- hasNoChangeAttestation: boolean;
70
- }
71
- /**
72
- * Ensure the narrative verdict in 07-review.md is consistent with the
73
- * structured review-army reconciliation. A review cannot declare
74
- * APPROVED while open Critical findings or shipBlockers remain.
75
- */
76
- export declare function checkReviewVerdictConsistency(projectRoot: string): Promise<ReviewVerdictConsistencyResult>;
77
- export declare function checkReviewSecurityNoChangeAttestation(projectRoot: string): Promise<ReviewSecurityNoChangeAttestationResult>;