claude-crap 0.1.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 (202) hide show
  1. package/CHANGELOG.md +308 -0
  2. package/LICENSE +21 -0
  3. package/README.md +550 -0
  4. package/bin/claude-crap.mjs +141 -0
  5. package/dist/adapters/bandit.d.ts +48 -0
  6. package/dist/adapters/bandit.d.ts.map +1 -0
  7. package/dist/adapters/bandit.js +145 -0
  8. package/dist/adapters/bandit.js.map +1 -0
  9. package/dist/adapters/common.d.ts +73 -0
  10. package/dist/adapters/common.d.ts.map +1 -0
  11. package/dist/adapters/common.js +78 -0
  12. package/dist/adapters/common.js.map +1 -0
  13. package/dist/adapters/eslint.d.ts +52 -0
  14. package/dist/adapters/eslint.d.ts.map +1 -0
  15. package/dist/adapters/eslint.js +142 -0
  16. package/dist/adapters/eslint.js.map +1 -0
  17. package/dist/adapters/index.d.ts +47 -0
  18. package/dist/adapters/index.d.ts.map +1 -0
  19. package/dist/adapters/index.js +64 -0
  20. package/dist/adapters/index.js.map +1 -0
  21. package/dist/adapters/semgrep.d.ts +30 -0
  22. package/dist/adapters/semgrep.d.ts.map +1 -0
  23. package/dist/adapters/semgrep.js +130 -0
  24. package/dist/adapters/semgrep.js.map +1 -0
  25. package/dist/adapters/stryker.d.ts +55 -0
  26. package/dist/adapters/stryker.d.ts.map +1 -0
  27. package/dist/adapters/stryker.js +165 -0
  28. package/dist/adapters/stryker.js.map +1 -0
  29. package/dist/ast/cyclomatic.d.ts +48 -0
  30. package/dist/ast/cyclomatic.d.ts.map +1 -0
  31. package/dist/ast/cyclomatic.js +106 -0
  32. package/dist/ast/cyclomatic.js.map +1 -0
  33. package/dist/ast/index.d.ts +26 -0
  34. package/dist/ast/index.d.ts.map +1 -0
  35. package/dist/ast/index.js +23 -0
  36. package/dist/ast/index.js.map +1 -0
  37. package/dist/ast/language-config.d.ts +70 -0
  38. package/dist/ast/language-config.d.ts.map +1 -0
  39. package/dist/ast/language-config.js +192 -0
  40. package/dist/ast/language-config.js.map +1 -0
  41. package/dist/ast/tree-sitter-engine.d.ts +133 -0
  42. package/dist/ast/tree-sitter-engine.d.ts.map +1 -0
  43. package/dist/ast/tree-sitter-engine.js +270 -0
  44. package/dist/ast/tree-sitter-engine.js.map +1 -0
  45. package/dist/config.d.ts +57 -0
  46. package/dist/config.d.ts.map +1 -0
  47. package/dist/config.js +78 -0
  48. package/dist/config.js.map +1 -0
  49. package/dist/crap-config.d.ts +97 -0
  50. package/dist/crap-config.d.ts.map +1 -0
  51. package/dist/crap-config.js +144 -0
  52. package/dist/crap-config.js.map +1 -0
  53. package/dist/dashboard/server.d.ts +65 -0
  54. package/dist/dashboard/server.d.ts.map +1 -0
  55. package/dist/dashboard/server.js +147 -0
  56. package/dist/dashboard/server.js.map +1 -0
  57. package/dist/index.d.ts +32 -0
  58. package/dist/index.d.ts.map +1 -0
  59. package/dist/index.js +574 -0
  60. package/dist/index.js.map +1 -0
  61. package/dist/metrics/crap.d.ts +71 -0
  62. package/dist/metrics/crap.d.ts.map +1 -0
  63. package/dist/metrics/crap.js +67 -0
  64. package/dist/metrics/crap.js.map +1 -0
  65. package/dist/metrics/index.d.ts +31 -0
  66. package/dist/metrics/index.d.ts.map +1 -0
  67. package/dist/metrics/index.js +27 -0
  68. package/dist/metrics/index.js.map +1 -0
  69. package/dist/metrics/score.d.ts +143 -0
  70. package/dist/metrics/score.d.ts.map +1 -0
  71. package/dist/metrics/score.js +224 -0
  72. package/dist/metrics/score.js.map +1 -0
  73. package/dist/metrics/tdr.d.ts +106 -0
  74. package/dist/metrics/tdr.d.ts.map +1 -0
  75. package/dist/metrics/tdr.js +117 -0
  76. package/dist/metrics/tdr.js.map +1 -0
  77. package/dist/metrics/workspace-walker.d.ts +43 -0
  78. package/dist/metrics/workspace-walker.d.ts.map +1 -0
  79. package/dist/metrics/workspace-walker.js +137 -0
  80. package/dist/metrics/workspace-walker.js.map +1 -0
  81. package/dist/sarif/index.d.ts +21 -0
  82. package/dist/sarif/index.d.ts.map +1 -0
  83. package/dist/sarif/index.js +19 -0
  84. package/dist/sarif/index.js.map +1 -0
  85. package/dist/sarif/sarif-builder.d.ts +128 -0
  86. package/dist/sarif/sarif-builder.d.ts.map +1 -0
  87. package/dist/sarif/sarif-builder.js +79 -0
  88. package/dist/sarif/sarif-builder.js.map +1 -0
  89. package/dist/sarif/sarif-store.d.ts +205 -0
  90. package/dist/sarif/sarif-store.d.ts.map +1 -0
  91. package/dist/sarif/sarif-store.js +246 -0
  92. package/dist/sarif/sarif-store.js.map +1 -0
  93. package/dist/sarif/sarif-validator.d.ts +45 -0
  94. package/dist/sarif/sarif-validator.d.ts.map +1 -0
  95. package/dist/sarif/sarif-validator.js +138 -0
  96. package/dist/sarif/sarif-validator.js.map +1 -0
  97. package/dist/schemas/tool-schemas.d.ts +216 -0
  98. package/dist/schemas/tool-schemas.d.ts.map +1 -0
  99. package/dist/schemas/tool-schemas.js +208 -0
  100. package/dist/schemas/tool-schemas.js.map +1 -0
  101. package/dist/sdk.d.ts +45 -0
  102. package/dist/sdk.d.ts.map +1 -0
  103. package/dist/sdk.js +44 -0
  104. package/dist/sdk.js.map +1 -0
  105. package/dist/tools/index.d.ts +24 -0
  106. package/dist/tools/index.d.ts.map +1 -0
  107. package/dist/tools/index.js +23 -0
  108. package/dist/tools/index.js.map +1 -0
  109. package/dist/tools/test-harness.d.ts +75 -0
  110. package/dist/tools/test-harness.d.ts.map +1 -0
  111. package/dist/tools/test-harness.js +137 -0
  112. package/dist/tools/test-harness.js.map +1 -0
  113. package/dist/workspace-guard.d.ts +53 -0
  114. package/dist/workspace-guard.d.ts.map +1 -0
  115. package/dist/workspace-guard.js +61 -0
  116. package/dist/workspace-guard.js.map +1 -0
  117. package/package.json +133 -0
  118. package/plugin/.claude-plugin/plugin.json +29 -0
  119. package/plugin/.mcp.json +18 -0
  120. package/plugin/CLAUDE.md +143 -0
  121. package/plugin/bundle/dashboard/public/index.html +368 -0
  122. package/plugin/bundle/dashboard/public/vendor/vue.global.prod.js +9 -0
  123. package/plugin/bundle/mcp-server.mjs +8718 -0
  124. package/plugin/bundle/mcp-server.mjs.map +7 -0
  125. package/plugin/bundle/tdr-engine.mjs +50 -0
  126. package/plugin/bundle/tdr-engine.mjs.map +7 -0
  127. package/plugin/hooks/hooks.json +62 -0
  128. package/plugin/hooks/lib/crap-config.mjs +152 -0
  129. package/plugin/hooks/lib/gatekeeper-rules.mjs +257 -0
  130. package/plugin/hooks/lib/hook-io.mjs +151 -0
  131. package/plugin/hooks/lib/quality-gate.mjs +329 -0
  132. package/plugin/hooks/lib/test-harness.mjs +152 -0
  133. package/plugin/hooks/post-tool-use.mjs +245 -0
  134. package/plugin/hooks/pre-tool-use.mjs +290 -0
  135. package/plugin/hooks/session-start.mjs +109 -0
  136. package/plugin/hooks/stop-quality-gate.mjs +226 -0
  137. package/plugin/package.json +18 -0
  138. package/plugin/skills/adopt/SKILL.md +74 -0
  139. package/plugin/skills/analyze/SKILL.md +77 -0
  140. package/plugin/skills/check-test/SKILL.md +50 -0
  141. package/plugin/skills/score/SKILL.md +31 -0
  142. package/scripts/bug-report.mjs +328 -0
  143. package/scripts/build-fast.mjs +130 -0
  144. package/scripts/bundle-plugin.mjs +74 -0
  145. package/scripts/doctor.mjs +320 -0
  146. package/scripts/install.mjs +192 -0
  147. package/scripts/lib/cli-ui.mjs +122 -0
  148. package/scripts/postinstall.mjs +127 -0
  149. package/scripts/run-tests.mjs +95 -0
  150. package/scripts/status.mjs +110 -0
  151. package/scripts/uninstall.mjs +72 -0
  152. package/src/adapters/bandit.ts +191 -0
  153. package/src/adapters/common.ts +133 -0
  154. package/src/adapters/eslint.ts +187 -0
  155. package/src/adapters/index.ts +78 -0
  156. package/src/adapters/semgrep.ts +150 -0
  157. package/src/adapters/stryker.ts +218 -0
  158. package/src/ast/cyclomatic.ts +131 -0
  159. package/src/ast/index.ts +33 -0
  160. package/src/ast/language-config.ts +231 -0
  161. package/src/ast/tree-sitter-engine.ts +385 -0
  162. package/src/config.ts +109 -0
  163. package/src/crap-config.ts +196 -0
  164. package/src/dashboard/public/index.html +368 -0
  165. package/src/dashboard/public/vendor/vue.global.prod.js +9 -0
  166. package/src/dashboard/server.ts +205 -0
  167. package/src/index.ts +696 -0
  168. package/src/metrics/crap.ts +101 -0
  169. package/src/metrics/index.ts +51 -0
  170. package/src/metrics/score.ts +329 -0
  171. package/src/metrics/tdr.ts +155 -0
  172. package/src/metrics/workspace-walker.ts +146 -0
  173. package/src/sarif/index.ts +31 -0
  174. package/src/sarif/sarif-builder.ts +139 -0
  175. package/src/sarif/sarif-store.ts +347 -0
  176. package/src/sarif/sarif-validator.ts +145 -0
  177. package/src/schemas/tool-schemas.ts +225 -0
  178. package/src/sdk.ts +110 -0
  179. package/src/tests/adapters/bandit.test.ts +111 -0
  180. package/src/tests/adapters/dispatch.test.ts +100 -0
  181. package/src/tests/adapters/eslint.test.ts +138 -0
  182. package/src/tests/adapters/semgrep.test.ts +125 -0
  183. package/src/tests/adapters/stryker.test.ts +103 -0
  184. package/src/tests/crap-config.test.ts +228 -0
  185. package/src/tests/crap.test.ts +59 -0
  186. package/src/tests/cyclomatic.test.ts +87 -0
  187. package/src/tests/dashboard-http.test.ts +108 -0
  188. package/src/tests/dashboard-integrity.test.ts +128 -0
  189. package/src/tests/integration/mcp-server.integration.test.ts +352 -0
  190. package/src/tests/pre-tool-use-hook.test.ts +178 -0
  191. package/src/tests/sarif-store.test.ts +241 -0
  192. package/src/tests/sarif-validator.test.ts +164 -0
  193. package/src/tests/score.test.ts +260 -0
  194. package/src/tests/skills-frontmatter.test.ts +172 -0
  195. package/src/tests/stop-quality-gate-strictness.test.ts +243 -0
  196. package/src/tests/tdr.test.ts +86 -0
  197. package/src/tests/test-harness.test.ts +153 -0
  198. package/src/tests/workspace-guard.test.ts +111 -0
  199. package/src/tools/index.ts +24 -0
  200. package/src/tools/test-harness.ts +158 -0
  201. package/src/workspace-guard.ts +64 -0
  202. package/tsconfig.json +27 -0
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Technical Debt Ratio (TDR) — deterministic computation and rating.
3
+ *
4
+ * The Technical Debt Ratio expresses how expensive it would be to remediate
5
+ * all known issues in a scope, relative to how much it would have cost to
6
+ * write the code in the first place. Formally (see docs/quality-gate.md):
7
+ *
8
+ * TDR = remediationCost / (costPerLine × totalLinesOfCode)
9
+ *
10
+ * Where the remediation cost is the sum (in minutes) of every linter /
11
+ * scanner / mutator finding's individual estimated effort, and the per-line
12
+ * cost is assumed to be a constant `minutesPerLoc` (industry default: 30
13
+ * minutes per line of code, including design, writing and review).
14
+ *
15
+ * The resulting ratio is converted to a percentage and mapped to a letter
16
+ * grade A..E. The thresholds are strict and non-negotiable:
17
+ *
18
+ * | Rating | TDR % | Meaning |
19
+ * |--------|--------------|-------------------------------------------|
20
+ * | A | 0..5% | Excellent — remediation cost is noise |
21
+ * | B | >5..10% | Low risk |
22
+ * | C | >10..20% | Moderate, watch closely |
23
+ * | D | >20..50% | Critical, remediation plan required |
24
+ * | E | >50% | Unmaintainable — halt feature work |
25
+ *
26
+ * Rating E always halts the workflow at the Stop quality gate, regardless
27
+ * of the configured `TDR_MAX_RATING` tolerance.
28
+ *
29
+ * @module metrics/tdr
30
+ */
31
+ import type { MaintainabilityRating } from "../config.js";
32
+ /**
33
+ * Inputs required to compute a Technical Debt Ratio over any scope
34
+ * (project, module, or file).
35
+ */
36
+ export interface TdrInput {
37
+ /** Sum of all finding remediation estimates, in minutes. Must be ≥ 0. */
38
+ readonly remediationMinutes: number;
39
+ /** Total lines of code in the scope. Must be > 0 (division denominator). */
40
+ readonly totalLinesOfCode: number;
41
+ /** Assumed development cost per LOC, in minutes. Must be > 0. */
42
+ readonly minutesPerLoc: number;
43
+ }
44
+ /**
45
+ * Result of a TDR computation with both the raw ratio and the letter grade.
46
+ */
47
+ export interface TdrResult {
48
+ /** Raw ratio (remediation / development), rounded to 6 decimals. */
49
+ readonly ratio: number;
50
+ /** Same ratio expressed as a percentage, rounded to 4 decimals. */
51
+ readonly percent: number;
52
+ /** Letter grade derived from `percent` via {@link classifyTdr}. */
53
+ readonly rating: MaintainabilityRating;
54
+ /** Remediation input, echoed for traceability. */
55
+ readonly remediationMinutes: number;
56
+ /** LOC input, echoed for traceability. */
57
+ readonly totalLinesOfCode: number;
58
+ /** Computed `minutesPerLoc × totalLinesOfCode`, useful for the dashboard. */
59
+ readonly developmentCostMinutes: number;
60
+ }
61
+ /**
62
+ * Convert a letter rating to its numeric rank (A=0, E=4). Useful when
63
+ * comparing two ratings without relying on lexical order.
64
+ *
65
+ * @param rating The rating letter.
66
+ * @returns Its rank in `[0, 4]`.
67
+ */
68
+ export declare function ratingToRank(rating: MaintainabilityRating): number;
69
+ /**
70
+ * Return `true` when `actual` is strictly worse than `limit`, false otherwise.
71
+ * Used by the Stop quality gate to decide whether to block task completion.
72
+ *
73
+ * @param actual Rating currently achieved by the project.
74
+ * @param limit Maximum tolerated rating (worst allowed).
75
+ * @returns `true` if `actual` should trigger a block.
76
+ *
77
+ * @example
78
+ * ratingIsWorseThan("D", "C") // → true
79
+ * ratingIsWorseThan("B", "C") // → false
80
+ * ratingIsWorseThan("C", "C") // → false (equal, not worse)
81
+ */
82
+ export declare function ratingIsWorseThan(actual: MaintainabilityRating, limit: MaintainabilityRating): boolean;
83
+ /**
84
+ * Map a TDR percentage to its letter rating. The boundaries are inclusive
85
+ * on the upper end (5% is still an A, 10% is still a B, etc.).
86
+ *
87
+ * @param percent TDR expressed as a percentage. Must be ≥ 0.
88
+ * @returns Letter rating A..E.
89
+ * @throws When `percent` is negative or not finite.
90
+ */
91
+ export declare function classifyTdr(percent: number): MaintainabilityRating;
92
+ /**
93
+ * Compute the Technical Debt Ratio for a scope and return the full result.
94
+ * This function is pure and deterministic.
95
+ *
96
+ * @param input Remediation minutes, total LOC and the cost-per-line assumption.
97
+ * @returns A {@link TdrResult} ready to be serialized to SARIF properties.
98
+ * @throws When any numeric input is out of range.
99
+ *
100
+ * @example
101
+ * // 240 minutes of remediation across 500 LOC at 30 min/LOC
102
+ * computeTdr({ remediationMinutes: 240, totalLinesOfCode: 500, minutesPerLoc: 30 })
103
+ * // → { ratio: 0.016, percent: 1.6, rating: "A", ... }
104
+ */
105
+ export declare function computeTdr(input: TdrInput): TdrResult;
106
+ //# sourceMappingURL=tdr.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tdr.d.ts","sourceRoot":"","sources":["../../src/metrics/tdr.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAE1D;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACvB,yEAAyE;IACzE,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,4EAA4E;IAC5E,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,iEAAiE;IACjE,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAChC;AAED;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,oEAAoE;IACpE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,mEAAmE;IACnE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,mEAAmE;IACnE,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAC;IACvC,kDAAkD;IAClD,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,0CAA0C;IAC1C,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,6EAA6E;IAC7E,QAAQ,CAAC,sBAAsB,EAAE,MAAM,CAAC;CACzC;AAKD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,qBAAqB,GAAG,MAAM,CAElE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,qBAAqB,EAC7B,KAAK,EAAE,qBAAqB,GAC3B,OAAO,CAET;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,qBAAqB,CASlE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,QAAQ,GAAG,SAAS,CAwBrD"}
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Technical Debt Ratio (TDR) — deterministic computation and rating.
3
+ *
4
+ * The Technical Debt Ratio expresses how expensive it would be to remediate
5
+ * all known issues in a scope, relative to how much it would have cost to
6
+ * write the code in the first place. Formally (see docs/quality-gate.md):
7
+ *
8
+ * TDR = remediationCost / (costPerLine × totalLinesOfCode)
9
+ *
10
+ * Where the remediation cost is the sum (in minutes) of every linter /
11
+ * scanner / mutator finding's individual estimated effort, and the per-line
12
+ * cost is assumed to be a constant `minutesPerLoc` (industry default: 30
13
+ * minutes per line of code, including design, writing and review).
14
+ *
15
+ * The resulting ratio is converted to a percentage and mapped to a letter
16
+ * grade A..E. The thresholds are strict and non-negotiable:
17
+ *
18
+ * | Rating | TDR % | Meaning |
19
+ * |--------|--------------|-------------------------------------------|
20
+ * | A | 0..5% | Excellent — remediation cost is noise |
21
+ * | B | >5..10% | Low risk |
22
+ * | C | >10..20% | Moderate, watch closely |
23
+ * | D | >20..50% | Critical, remediation plan required |
24
+ * | E | >50% | Unmaintainable — halt feature work |
25
+ *
26
+ * Rating E always halts the workflow at the Stop quality gate, regardless
27
+ * of the configured `TDR_MAX_RATING` tolerance.
28
+ *
29
+ * @module metrics/tdr
30
+ */
31
+ /** Canonical ordering used by {@link ratingToRank}. */
32
+ const RATING_ORDER = ["A", "B", "C", "D", "E"];
33
+ /**
34
+ * Convert a letter rating to its numeric rank (A=0, E=4). Useful when
35
+ * comparing two ratings without relying on lexical order.
36
+ *
37
+ * @param rating The rating letter.
38
+ * @returns Its rank in `[0, 4]`.
39
+ */
40
+ export function ratingToRank(rating) {
41
+ return RATING_ORDER.indexOf(rating);
42
+ }
43
+ /**
44
+ * Return `true` when `actual` is strictly worse than `limit`, false otherwise.
45
+ * Used by the Stop quality gate to decide whether to block task completion.
46
+ *
47
+ * @param actual Rating currently achieved by the project.
48
+ * @param limit Maximum tolerated rating (worst allowed).
49
+ * @returns `true` if `actual` should trigger a block.
50
+ *
51
+ * @example
52
+ * ratingIsWorseThan("D", "C") // → true
53
+ * ratingIsWorseThan("B", "C") // → false
54
+ * ratingIsWorseThan("C", "C") // → false (equal, not worse)
55
+ */
56
+ export function ratingIsWorseThan(actual, limit) {
57
+ return ratingToRank(actual) > ratingToRank(limit);
58
+ }
59
+ /**
60
+ * Map a TDR percentage to its letter rating. The boundaries are inclusive
61
+ * on the upper end (5% is still an A, 10% is still a B, etc.).
62
+ *
63
+ * @param percent TDR expressed as a percentage. Must be ≥ 0.
64
+ * @returns Letter rating A..E.
65
+ * @throws When `percent` is negative or not finite.
66
+ */
67
+ export function classifyTdr(percent) {
68
+ if (!Number.isFinite(percent) || percent < 0) {
69
+ throw new Error(`[tdr] percent is invalid: ${percent}`);
70
+ }
71
+ if (percent <= 5)
72
+ return "A";
73
+ if (percent <= 10)
74
+ return "B";
75
+ if (percent <= 20)
76
+ return "C";
77
+ if (percent <= 50)
78
+ return "D";
79
+ return "E";
80
+ }
81
+ /**
82
+ * Compute the Technical Debt Ratio for a scope and return the full result.
83
+ * This function is pure and deterministic.
84
+ *
85
+ * @param input Remediation minutes, total LOC and the cost-per-line assumption.
86
+ * @returns A {@link TdrResult} ready to be serialized to SARIF properties.
87
+ * @throws When any numeric input is out of range.
88
+ *
89
+ * @example
90
+ * // 240 minutes of remediation across 500 LOC at 30 min/LOC
91
+ * computeTdr({ remediationMinutes: 240, totalLinesOfCode: 500, minutesPerLoc: 30 })
92
+ * // → { ratio: 0.016, percent: 1.6, rating: "A", ... }
93
+ */
94
+ export function computeTdr(input) {
95
+ if (input.totalLinesOfCode <= 0) {
96
+ throw new Error(`[tdr] totalLinesOfCode must be > 0, got ${input.totalLinesOfCode}`);
97
+ }
98
+ if (input.minutesPerLoc <= 0) {
99
+ throw new Error(`[tdr] minutesPerLoc must be > 0, got ${input.minutesPerLoc}`);
100
+ }
101
+ if (input.remediationMinutes < 0) {
102
+ throw new Error(`[tdr] remediationMinutes must be ≥ 0, got ${input.remediationMinutes}`);
103
+ }
104
+ const developmentCostMinutes = input.minutesPerLoc * input.totalLinesOfCode;
105
+ const ratio = input.remediationMinutes / developmentCostMinutes;
106
+ const percent = ratio * 100;
107
+ const rating = classifyTdr(percent);
108
+ return {
109
+ ratio: Number(ratio.toFixed(6)),
110
+ percent: Number(percent.toFixed(4)),
111
+ rating,
112
+ remediationMinutes: input.remediationMinutes,
113
+ totalLinesOfCode: input.totalLinesOfCode,
114
+ developmentCostMinutes,
115
+ };
116
+ }
117
+ //# sourceMappingURL=tdr.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tdr.js","sourceRoot":"","sources":["../../src/metrics/tdr.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAmCH,uDAAuD;AACvD,MAAM,YAAY,GAAyC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAErF;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,MAA6B;IACxD,OAAO,YAAY,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;AACtC,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,iBAAiB,CAC/B,MAA6B,EAC7B,KAA4B;IAE5B,OAAO,YAAY,CAAC,MAAM,CAAC,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;AACpD,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CAAC,OAAe;IACzC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;QAC7C,MAAM,IAAI,KAAK,CAAC,6BAA6B,OAAO,EAAE,CAAC,CAAC;IAC1D,CAAC;IACD,IAAI,OAAO,IAAI,CAAC;QAAE,OAAO,GAAG,CAAC;IAC7B,IAAI,OAAO,IAAI,EAAE;QAAE,OAAO,GAAG,CAAC;IAC9B,IAAI,OAAO,IAAI,EAAE;QAAE,OAAO,GAAG,CAAC;IAC9B,IAAI,OAAO,IAAI,EAAE;QAAE,OAAO,GAAG,CAAC;IAC9B,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,UAAU,CAAC,KAAe;IACxC,IAAI,KAAK,CAAC,gBAAgB,IAAI,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,2CAA2C,KAAK,CAAC,gBAAgB,EAAE,CAAC,CAAC;IACvF,CAAC;IACD,IAAI,KAAK,CAAC,aAAa,IAAI,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,wCAAwC,KAAK,CAAC,aAAa,EAAE,CAAC,CAAC;IACjF,CAAC;IACD,IAAI,KAAK,CAAC,kBAAkB,GAAG,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,6CAA6C,KAAK,CAAC,kBAAkB,EAAE,CAAC,CAAC;IAC3F,CAAC;IAED,MAAM,sBAAsB,GAAG,KAAK,CAAC,aAAa,GAAG,KAAK,CAAC,gBAAgB,CAAC;IAC5E,MAAM,KAAK,GAAG,KAAK,CAAC,kBAAkB,GAAG,sBAAsB,CAAC;IAChE,MAAM,OAAO,GAAG,KAAK,GAAG,GAAG,CAAC;IAC5B,MAAM,MAAM,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;IAEpC,OAAO;QACL,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAC/B,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACnC,MAAM;QACN,kBAAkB,EAAE,KAAK,CAAC,kBAAkB;QAC5C,gBAAgB,EAAE,KAAK,CAAC,gBAAgB;QACxC,sBAAsB;KACvB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Bounded workspace walker.
3
+ *
4
+ * Counts physical lines of code across a workspace, skipping directories
5
+ * that should not contribute to the Technical Debt Ratio (dependency
6
+ * caches, build artifacts, VCS metadata, etc.) and capping the file
7
+ * count to keep the walk well under the Stop hook's 120-second budget
8
+ * even on pathological repositories.
9
+ *
10
+ * This is the TypeScript twin of `hooks/lib/quality-gate.mjs#estimateWorkspaceLoc`.
11
+ * The two are independent so neither side has to import files from outside
12
+ * its own project tree.
13
+ *
14
+ * @module metrics/workspace-walker
15
+ */
16
+ /**
17
+ * Result returned by {@link estimateWorkspaceLoc}.
18
+ */
19
+ export interface WorkspaceWalkResult {
20
+ /** Total physical lines of code across every file the walker read. */
21
+ readonly physicalLoc: number;
22
+ /** Number of code files the walker visited. */
23
+ readonly fileCount: number;
24
+ /** `true` when the walker hit {@link MAX_FILES_WALKED} and stopped early. */
25
+ readonly truncated: boolean;
26
+ }
27
+ /**
28
+ * Hard cap on the number of files the walker will read. Protects against
29
+ * pathological repositories where the walk would otherwise dominate the
30
+ * Stop hook's budget. When hit, the walker returns the partial count
31
+ * with `truncated: true` and the caller may decide how to react.
32
+ */
33
+ export declare const MAX_FILES_WALKED = 20000;
34
+ /**
35
+ * Walk a workspace and return its physical LOC + file count. Never
36
+ * follows symbolic links. Skips hidden directories except `.claude-plugin`
37
+ * (which is tiny and contains the manifest).
38
+ *
39
+ * @param workspaceRoot Absolute path to the workspace root.
40
+ * @returns A {@link WorkspaceWalkResult} snapshot.
41
+ */
42
+ export declare function estimateWorkspaceLoc(workspaceRoot: string): Promise<WorkspaceWalkResult>;
43
+ //# sourceMappingURL=workspace-walker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace-walker.d.ts","sourceRoot":"","sources":["../../src/metrics/workspace-walker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,sEAAsE;IACtE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,+CAA+C;IAC/C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,6EAA6E;IAC7E,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC7B;AAkDD;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,QAAS,CAAC;AAEvC;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAkD9F"}
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Bounded workspace walker.
3
+ *
4
+ * Counts physical lines of code across a workspace, skipping directories
5
+ * that should not contribute to the Technical Debt Ratio (dependency
6
+ * caches, build artifacts, VCS metadata, etc.) and capping the file
7
+ * count to keep the walk well under the Stop hook's 120-second budget
8
+ * even on pathological repositories.
9
+ *
10
+ * This is the TypeScript twin of `hooks/lib/quality-gate.mjs#estimateWorkspaceLoc`.
11
+ * The two are independent so neither side has to import files from outside
12
+ * its own project tree.
13
+ *
14
+ * @module metrics/workspace-walker
15
+ */
16
+ import { promises as fs } from "node:fs";
17
+ import { join } from "node:path";
18
+ /**
19
+ * Directories that should never contribute to the LOC count. Dependency
20
+ * caches, build artifacts, VCS metadata, claude-crap's own state.
21
+ */
22
+ const SKIP_DIRS = new Set([
23
+ "node_modules",
24
+ ".git",
25
+ "dist",
26
+ "build",
27
+ "out",
28
+ "target",
29
+ ".venv",
30
+ "venv",
31
+ "__pycache__",
32
+ ".cache",
33
+ ".next",
34
+ ".nuxt",
35
+ ".claude-crap",
36
+ ".codesight",
37
+ ]);
38
+ /**
39
+ * Extensions the walker treats as "code". Anything else is ignored,
40
+ * including markdown, JSON, YAML, lockfiles, and binaries.
41
+ */
42
+ const CODE_EXTENSIONS = new Set([
43
+ ".ts",
44
+ ".tsx",
45
+ ".mts",
46
+ ".cts",
47
+ ".js",
48
+ ".jsx",
49
+ ".mjs",
50
+ ".cjs",
51
+ ".py",
52
+ ".java",
53
+ ".cs",
54
+ ".go",
55
+ ".rs",
56
+ ".rb",
57
+ ".php",
58
+ ".swift",
59
+ ".kt",
60
+ ".scala",
61
+ ".dart",
62
+ ".vue",
63
+ ]);
64
+ /**
65
+ * Hard cap on the number of files the walker will read. Protects against
66
+ * pathological repositories where the walk would otherwise dominate the
67
+ * Stop hook's budget. When hit, the walker returns the partial count
68
+ * with `truncated: true` and the caller may decide how to react.
69
+ */
70
+ export const MAX_FILES_WALKED = 20_000;
71
+ /**
72
+ * Walk a workspace and return its physical LOC + file count. Never
73
+ * follows symbolic links. Skips hidden directories except `.claude-plugin`
74
+ * (which is tiny and contains the manifest).
75
+ *
76
+ * @param workspaceRoot Absolute path to the workspace root.
77
+ * @returns A {@link WorkspaceWalkResult} snapshot.
78
+ */
79
+ export async function estimateWorkspaceLoc(workspaceRoot) {
80
+ let physicalLoc = 0;
81
+ let fileCount = 0;
82
+ let truncated = false;
83
+ async function walk(dir) {
84
+ if (truncated)
85
+ return;
86
+ let entries;
87
+ try {
88
+ entries = await fs.readdir(dir, { withFileTypes: true });
89
+ }
90
+ catch {
91
+ return;
92
+ }
93
+ for (const entry of entries) {
94
+ if (truncated)
95
+ return;
96
+ // Skip hidden files except the plugin manifest dir.
97
+ if (entry.name.startsWith(".") && entry.name !== ".claude-plugin")
98
+ continue;
99
+ const full = join(dir, entry.name);
100
+ if (entry.isDirectory()) {
101
+ if (SKIP_DIRS.has(entry.name))
102
+ continue;
103
+ await walk(full);
104
+ continue;
105
+ }
106
+ if (!entry.isFile())
107
+ continue;
108
+ const lower = entry.name.toLowerCase();
109
+ const dot = lower.lastIndexOf(".");
110
+ if (dot < 0)
111
+ continue;
112
+ const ext = lower.substring(dot);
113
+ if (!CODE_EXTENSIONS.has(ext))
114
+ continue;
115
+ fileCount += 1;
116
+ if (fileCount > MAX_FILES_WALKED) {
117
+ truncated = true;
118
+ return;
119
+ }
120
+ try {
121
+ const content = await fs.readFile(full, "utf8");
122
+ if (content.length > 0) {
123
+ // Subtract 1 for trailing newline, matching what most editors
124
+ // report as the file's line count.
125
+ const lines = content.split(/\r?\n/).length;
126
+ physicalLoc += content.endsWith("\n") ? lines - 1 : lines;
127
+ }
128
+ }
129
+ catch {
130
+ // Unreadable file (permissions, binary). Skip silently.
131
+ }
132
+ }
133
+ }
134
+ await walk(workspaceRoot);
135
+ return { physicalLoc, fileCount, truncated };
136
+ }
137
+ //# sourceMappingURL=workspace-walker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace-walker.js","sourceRoot":"","sources":["../../src/metrics/workspace-walker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Public SDK entry point for the SARIF 2.1.0 builder and store.
3
+ *
4
+ * Usage:
5
+ *
6
+ * ```ts
7
+ * import {
8
+ * SarifStore,
9
+ * buildSarifDocument,
10
+ * type SarifFinding,
11
+ * type SarifLevel,
12
+ * } from "claude-crap/sarif";
13
+ * ```
14
+ *
15
+ * @module sarif
16
+ */
17
+ export { buildSarifDocument } from "./sarif-builder.js";
18
+ export type { SarifFinding, SarifLevel, SarifLocation, SarifToolInfo, } from "./sarif-builder.js";
19
+ export { SarifStore } from "./sarif-store.js";
20
+ export type { IngestedFinding, PersistedSarif, SarifStoreOptions, } from "./sarif-store.js";
21
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sarif/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,YAAY,EACV,YAAY,EACZ,UAAU,EACV,aAAa,EACb,aAAa,GACd,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,YAAY,EACV,eAAe,EACf,cAAc,EACd,iBAAiB,GAClB,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Public SDK entry point for the SARIF 2.1.0 builder and store.
3
+ *
4
+ * Usage:
5
+ *
6
+ * ```ts
7
+ * import {
8
+ * SarifStore,
9
+ * buildSarifDocument,
10
+ * type SarifFinding,
11
+ * type SarifLevel,
12
+ * } from "claude-crap/sarif";
13
+ * ```
14
+ *
15
+ * @module sarif
16
+ */
17
+ export { buildSarifDocument } from "./sarif-builder.js";
18
+ export { SarifStore } from "./sarif-store.js";
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sarif/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAQxD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Minimal SARIF 2.1.0 document builder.
3
+ *
4
+ * Every report that leaves the MCP server on its way to the agent is
5
+ * normalized to SARIF 2.1.0 first. This module provides the typed
6
+ * helpers used to wrap raw findings in the canonical
7
+ * `tool → runs → results` taxonomy with exact file coordinates.
8
+ *
9
+ * Per-scanner adapters (Semgrep, ESLint, Bandit, Stryker) live under
10
+ * `src/adapters/` and call into `buildSarifDocument` through the
11
+ * `wrapResultsInSarif` helper in `src/adapters/common.ts`. The
12
+ * on-disk deduplication store lives in `./sarif-store.ts`.
13
+ *
14
+ * The SARIF 2.1.0 spec lives at:
15
+ * https://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html
16
+ *
17
+ * @module sarif/sarif-builder
18
+ */
19
+ /**
20
+ * Severity levels supported by SARIF 2.1.0. They map 1:1 to the
21
+ * `result.level` field. `"error"` is the strongest, `"none"` is informational.
22
+ */
23
+ export type SarifLevel = "none" | "note" | "warning" | "error";
24
+ /**
25
+ * Physical location of a finding inside a source artifact. `startLine` and
26
+ * `startColumn` are 1-based, matching the SARIF spec. `endLine` and
27
+ * `endColumn` are optional — omit them for point-like findings.
28
+ */
29
+ export interface SarifLocation {
30
+ /** Artifact URI, typically a file path relative to the workspace root. */
31
+ readonly uri: string;
32
+ /** 1-based line number where the finding starts. */
33
+ readonly startLine: number;
34
+ /** 1-based column number where the finding starts. */
35
+ readonly startColumn: number;
36
+ /** Optional 1-based line number where the finding ends. */
37
+ readonly endLine?: number;
38
+ /** Optional 1-based column number where the finding ends. */
39
+ readonly endColumn?: number;
40
+ }
41
+ /**
42
+ * A single finding ready to be embedded in a SARIF run. This is the
43
+ * internal shape used by claude-crap adapters; it is converted into the
44
+ * official SARIF `result` object by {@link buildSarifDocument}.
45
+ */
46
+ export interface SarifFinding {
47
+ /** Stable rule identifier (e.g. `"SONAR-CRAP-001"`, `"semgrep.python.sqli"`). */
48
+ readonly ruleId: string;
49
+ /** Severity level for this finding. */
50
+ readonly level: SarifLevel;
51
+ /** Human-readable message describing the finding. */
52
+ readonly message: string;
53
+ /** Physical location where the finding was detected. */
54
+ readonly location: SarifLocation;
55
+ /** Optional extra metadata stored in the SARIF `properties` bag. */
56
+ readonly properties?: Record<string, unknown>;
57
+ }
58
+ /**
59
+ * Metadata describing the tool that produced a SARIF run. The `name` is
60
+ * required by the spec; `version` is strongly recommended so that dashboard
61
+ * diffs can distinguish between scanner releases.
62
+ */
63
+ export interface SarifToolInfo {
64
+ /** Tool display name (e.g. `"claude-crap"`, `"semgrep"`). */
65
+ readonly name: string;
66
+ /** Tool semantic version. */
67
+ readonly version: string;
68
+ /** Optional URL pointing to the tool's documentation or home page. */
69
+ readonly informationUri?: string;
70
+ }
71
+ /**
72
+ * Build a minimal but valid SARIF 2.1.0 document from a list of findings.
73
+ *
74
+ * The returned object conforms to the SARIF JSON schema hosted at:
75
+ * https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0.json
76
+ *
77
+ * Rules are deduplicated by `ruleId` and emitted in the `tool.driver.rules`
78
+ * array so that downstream consumers (Claude Code, the dashboard, or any
79
+ * third-party SARIF viewer) can render a rule index.
80
+ *
81
+ * @param tool Metadata about the producing tool.
82
+ * @param findings Findings to include in the single run.
83
+ * @returns A SARIF 2.1.0 document literal (frozen by `as const`).
84
+ */
85
+ export declare function buildSarifDocument(tool: SarifToolInfo, findings: ReadonlyArray<SarifFinding>): {
86
+ readonly $schema: "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0.json";
87
+ readonly version: "2.1.0";
88
+ readonly runs: readonly [{
89
+ readonly tool: {
90
+ readonly driver: {
91
+ readonly name: string;
92
+ readonly version: string;
93
+ readonly informationUri: string;
94
+ readonly rules: {
95
+ id: string;
96
+ shortDescription: {
97
+ text: string;
98
+ };
99
+ defaultConfiguration: {
100
+ level: SarifLevel;
101
+ };
102
+ }[];
103
+ };
104
+ };
105
+ readonly results: {
106
+ properties?: Record<string, unknown>;
107
+ ruleId: string;
108
+ level: SarifLevel;
109
+ message: {
110
+ text: string;
111
+ };
112
+ locations: {
113
+ physicalLocation: {
114
+ artifactLocation: {
115
+ uri: string;
116
+ };
117
+ region: {
118
+ endColumn?: number;
119
+ endLine?: number;
120
+ startLine: number;
121
+ startColumn: number;
122
+ };
123
+ };
124
+ }[];
125
+ }[];
126
+ }];
127
+ };
128
+ //# sourceMappingURL=sarif-builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sarif-builder.d.ts","sourceRoot":"","sources":["../../src/sarif/sarif-builder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;AAE/D;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,0EAA0E;IAC1E,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,oDAAoD;IACpD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,sDAAsD;IACtD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,2DAA2D;IAC3D,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,6DAA6D;IAC7D,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,iFAAiF;IACjF,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,uCAAuC;IACvC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,qDAAqD;IACrD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,wDAAwD;IACxD,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;IACjC,oEAAoE;IACpE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/C;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,6DAA6D;IAC7D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,6BAA6B;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,sEAAsE;IACtE,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;CAClC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,aAAa,CAAC,YAAY,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiD5F"}