plumbbob 0.9.3 → 0.9.5

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 (278) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +15 -13
  3. package/dist/cli-core.js +19 -2
  4. package/dist/lib/check.js +46 -13
  5. package/dist/lib/intent.js +1 -1
  6. package/dist/lib/latch.js +3 -3
  7. package/dist/lib/reentry.js +70 -0
  8. package/dist/verbs/agent.js +2 -2
  9. package/dist/verbs/doctor.js +4 -4
  10. package/dist/verbs/finish.js +1 -1
  11. package/dist/verbs/recover.js +297 -0
  12. package/dist/verbs/revert.js +2 -2
  13. package/dist/verbs/spike.js +8 -2
  14. package/hooks/post-edit.sh +4 -4
  15. package/hooks/pre-bash-commit.sh +3 -3
  16. package/node_modules/checkride/.claude-plugin/plugin.json +11 -0
  17. package/node_modules/checkride/CHANGELOG.md +1003 -0
  18. package/node_modules/checkride/LICENSE +201 -21
  19. package/node_modules/checkride/README.md +171 -30
  20. package/node_modules/checkride/dist/__tests__/fixtures/released-stanzas.d.ts +15 -0
  21. package/node_modules/checkride/dist/__tests__/fixtures/released-stanzas.d.ts.map +1 -0
  22. package/node_modules/checkride/dist/__tests__/fixtures/released-stanzas.js +17 -0
  23. package/node_modules/checkride/dist/__tests__/fixtures/released-stanzas.js.map +1 -0
  24. package/node_modules/checkride/dist/adapters.d.ts +18 -6
  25. package/node_modules/checkride/dist/adapters.d.ts.map +1 -1
  26. package/node_modules/checkride/dist/adapters.js +42 -23
  27. package/node_modules/checkride/dist/adapters.js.map +1 -1
  28. package/node_modules/checkride/dist/agent-setup/claude.d.ts +88 -0
  29. package/node_modules/checkride/dist/agent-setup/claude.d.ts.map +1 -0
  30. package/node_modules/checkride/dist/agent-setup/claude.js +305 -0
  31. package/node_modules/checkride/dist/agent-setup/claude.js.map +1 -0
  32. package/node_modules/checkride/dist/agent-setup/command.d.ts +43 -0
  33. package/node_modules/checkride/dist/agent-setup/command.d.ts.map +1 -0
  34. package/node_modules/checkride/dist/agent-setup/command.js +77 -0
  35. package/node_modules/checkride/dist/agent-setup/command.js.map +1 -0
  36. package/node_modules/checkride/dist/agent-setup/cursor.d.ts +61 -0
  37. package/node_modules/checkride/dist/agent-setup/cursor.d.ts.map +1 -0
  38. package/node_modules/checkride/dist/agent-setup/cursor.js +189 -0
  39. package/node_modules/checkride/dist/agent-setup/cursor.js.map +1 -0
  40. package/node_modules/checkride/dist/agent-setup/files.d.ts +50 -0
  41. package/node_modules/checkride/dist/agent-setup/files.d.ts.map +1 -0
  42. package/node_modules/checkride/dist/agent-setup/files.js +80 -0
  43. package/node_modules/checkride/dist/agent-setup/files.js.map +1 -0
  44. package/node_modules/checkride/dist/agent-setup/harness.d.ts +101 -0
  45. package/node_modules/checkride/dist/agent-setup/harness.d.ts.map +1 -0
  46. package/node_modules/checkride/dist/agent-setup/harness.js +84 -0
  47. package/node_modules/checkride/dist/agent-setup/harness.js.map +1 -0
  48. package/node_modules/checkride/dist/agent-setup/hook.d.ts +45 -52
  49. package/node_modules/checkride/dist/agent-setup/hook.d.ts.map +1 -1
  50. package/node_modules/checkride/dist/agent-setup/hook.js +64 -95
  51. package/node_modules/checkride/dist/agent-setup/hook.js.map +1 -1
  52. package/node_modules/checkride/dist/agent-setup/index.d.ts +10 -4
  53. package/node_modules/checkride/dist/agent-setup/index.d.ts.map +1 -1
  54. package/node_modules/checkride/dist/agent-setup/index.js +9 -4
  55. package/node_modules/checkride/dist/agent-setup/index.js.map +1 -1
  56. package/node_modules/checkride/dist/agent-setup/scripts.d.ts +58 -0
  57. package/node_modules/checkride/dist/agent-setup/scripts.d.ts.map +1 -0
  58. package/node_modules/checkride/dist/agent-setup/scripts.js +299 -0
  59. package/node_modules/checkride/dist/agent-setup/scripts.js.map +1 -0
  60. package/node_modules/checkride/dist/agent-setup/skills.d.ts +31 -0
  61. package/node_modules/checkride/dist/agent-setup/skills.d.ts.map +1 -0
  62. package/node_modules/checkride/dist/agent-setup/skills.js +56 -0
  63. package/node_modules/checkride/dist/agent-setup/skills.js.map +1 -0
  64. package/node_modules/checkride/dist/artifacts/configured.d.ts +30 -0
  65. package/node_modules/checkride/dist/artifacts/configured.d.ts.map +1 -0
  66. package/node_modules/checkride/dist/artifacts/configured.js +45 -0
  67. package/node_modules/checkride/dist/artifacts/configured.js.map +1 -0
  68. package/node_modules/checkride/dist/artifacts/format.d.ts +33 -0
  69. package/node_modules/checkride/dist/artifacts/format.d.ts.map +1 -0
  70. package/node_modules/checkride/dist/artifacts/format.js +56 -0
  71. package/node_modules/checkride/dist/artifacts/format.js.map +1 -0
  72. package/node_modules/checkride/dist/artifacts/freshness.d.ts +32 -0
  73. package/node_modules/checkride/dist/artifacts/freshness.d.ts.map +1 -0
  74. package/node_modules/checkride/dist/artifacts/freshness.js +37 -0
  75. package/node_modules/checkride/dist/artifacts/freshness.js.map +1 -0
  76. package/node_modules/checkride/dist/artifacts/index.d.ts +22 -0
  77. package/node_modules/checkride/dist/artifacts/index.d.ts.map +1 -0
  78. package/node_modules/checkride/dist/artifacts/index.js +19 -0
  79. package/node_modules/checkride/dist/artifacts/index.js.map +1 -0
  80. package/node_modules/checkride/dist/artifacts/json.d.ts +31 -0
  81. package/node_modules/checkride/dist/artifacts/json.d.ts.map +1 -0
  82. package/node_modules/checkride/dist/artifacts/json.js +47 -0
  83. package/node_modules/checkride/dist/artifacts/json.js.map +1 -0
  84. package/node_modules/checkride/dist/artifacts/raw.d.ts +60 -0
  85. package/node_modules/checkride/dist/artifacts/raw.d.ts.map +1 -0
  86. package/node_modules/checkride/dist/artifacts/raw.js +91 -0
  87. package/node_modules/checkride/dist/artifacts/raw.js.map +1 -0
  88. package/node_modules/checkride/dist/artifacts/summary.d.ts +69 -0
  89. package/node_modules/checkride/dist/artifacts/summary.d.ts.map +1 -0
  90. package/node_modules/checkride/dist/artifacts/summary.js +108 -0
  91. package/node_modules/checkride/dist/artifacts/summary.js.map +1 -0
  92. package/node_modules/checkride/dist/atomic.d.ts +16 -1
  93. package/node_modules/checkride/dist/atomic.d.ts.map +1 -1
  94. package/node_modules/checkride/dist/atomic.js +25 -3
  95. package/node_modules/checkride/dist/atomic.js.map +1 -1
  96. package/node_modules/checkride/dist/baseline/fallow.d.ts +9 -5
  97. package/node_modules/checkride/dist/baseline/fallow.d.ts.map +1 -1
  98. package/node_modules/checkride/dist/baseline/fallow.js +161 -58
  99. package/node_modules/checkride/dist/baseline/fallow.js.map +1 -1
  100. package/node_modules/checkride/dist/baseline/fingerprint.d.ts +7 -7
  101. package/node_modules/checkride/dist/baseline/fingerprint.d.ts.map +1 -1
  102. package/node_modules/checkride/dist/baseline/fingerprint.js +16 -19
  103. package/node_modules/checkride/dist/baseline/fingerprint.js.map +1 -1
  104. package/node_modules/checkride/dist/baseline/index.d.ts +4 -4
  105. package/node_modules/checkride/dist/baseline/index.d.ts.map +1 -1
  106. package/node_modules/checkride/dist/baseline/index.js +4 -4
  107. package/node_modules/checkride/dist/baseline/index.js.map +1 -1
  108. package/node_modules/checkride/dist/baseline/store.d.ts +12 -4
  109. package/node_modules/checkride/dist/baseline/store.d.ts.map +1 -1
  110. package/node_modules/checkride/dist/baseline/store.js +16 -9
  111. package/node_modules/checkride/dist/baseline/store.js.map +1 -1
  112. package/node_modules/checkride/dist/baseline-command.d.ts +5 -5
  113. package/node_modules/checkride/dist/baseline-command.js +7 -7
  114. package/node_modules/checkride/dist/baseline-command.js.map +1 -1
  115. package/node_modules/checkride/dist/cli.d.ts +17 -4
  116. package/node_modules/checkride/dist/cli.d.ts.map +1 -1
  117. package/node_modules/checkride/dist/cli.js +259 -18
  118. package/node_modules/checkride/dist/cli.js.map +1 -1
  119. package/node_modules/checkride/dist/config.d.ts +84 -8
  120. package/node_modules/checkride/dist/config.d.ts.map +1 -1
  121. package/node_modules/checkride/dist/config.js +122 -18
  122. package/node_modules/checkride/dist/config.js.map +1 -1
  123. package/node_modules/checkride/dist/digest/digest.d.ts +5 -5
  124. package/node_modules/checkride/dist/digest/digest.js +5 -5
  125. package/node_modules/checkride/dist/digest/index.d.ts +2 -2
  126. package/node_modules/checkride/dist/digest/index.js +2 -2
  127. package/node_modules/checkride/dist/doctor.d.ts +25 -6
  128. package/node_modules/checkride/dist/doctor.d.ts.map +1 -1
  129. package/node_modules/checkride/dist/doctor.js +193 -27
  130. package/node_modules/checkride/dist/doctor.js.map +1 -1
  131. package/node_modules/checkride/dist/gate.d.ts +135 -0
  132. package/node_modules/checkride/dist/gate.d.ts.map +1 -0
  133. package/node_modules/checkride/dist/gate.js +490 -0
  134. package/node_modules/checkride/dist/gate.js.map +1 -0
  135. package/node_modules/checkride/dist/init.d.ts +72 -12
  136. package/node_modules/checkride/dist/init.d.ts.map +1 -1
  137. package/node_modules/checkride/dist/init.js +324 -81
  138. package/node_modules/checkride/dist/init.js.map +1 -1
  139. package/node_modules/checkride/dist/json.d.ts +21 -0
  140. package/node_modules/checkride/dist/json.d.ts.map +1 -0
  141. package/node_modules/checkride/dist/json.js +21 -0
  142. package/node_modules/checkride/dist/json.js.map +1 -0
  143. package/node_modules/checkride/dist/links.d.ts +31 -5
  144. package/node_modules/checkride/dist/links.d.ts.map +1 -1
  145. package/node_modules/checkride/dist/links.js +141 -32
  146. package/node_modules/checkride/dist/links.js.map +1 -1
  147. package/node_modules/checkride/dist/node-pin.d.ts +129 -0
  148. package/node_modules/checkride/dist/node-pin.d.ts.map +1 -0
  149. package/node_modules/checkride/dist/node-pin.js +211 -0
  150. package/node_modules/checkride/dist/node-pin.js.map +1 -0
  151. package/node_modules/checkride/dist/orchestrator.d.ts +40 -10
  152. package/node_modules/checkride/dist/orchestrator.d.ts.map +1 -1
  153. package/node_modules/checkride/dist/orchestrator.js +196 -102
  154. package/node_modules/checkride/dist/orchestrator.js.map +1 -1
  155. package/node_modules/checkride/dist/pack.d.ts +8 -9
  156. package/node_modules/checkride/dist/pack.d.ts.map +1 -1
  157. package/node_modules/checkride/dist/pack.js +53 -17
  158. package/node_modules/checkride/dist/pack.js.map +1 -1
  159. package/node_modules/checkride/dist/pm/detect.d.ts +6 -1
  160. package/node_modules/checkride/dist/pm/detect.d.ts.map +1 -1
  161. package/node_modules/checkride/dist/pm/detect.js +6 -1
  162. package/node_modules/checkride/dist/pm/detect.js.map +1 -1
  163. package/node_modules/checkride/dist/pm/index.d.ts +6 -2
  164. package/node_modules/checkride/dist/pm/index.d.ts.map +1 -1
  165. package/node_modules/checkride/dist/pm/index.js +6 -2
  166. package/node_modules/checkride/dist/pm/index.js.map +1 -1
  167. package/node_modules/checkride/dist/pm/launch.d.ts +51 -0
  168. package/node_modules/checkride/dist/pm/launch.d.ts.map +1 -0
  169. package/node_modules/checkride/dist/pm/launch.js +92 -0
  170. package/node_modules/checkride/dist/pm/launch.js.map +1 -0
  171. package/node_modules/checkride/dist/pm/tools.d.ts +73 -0
  172. package/node_modules/checkride/dist/pm/tools.d.ts.map +1 -0
  173. package/node_modules/checkride/dist/pm/tools.js +124 -0
  174. package/node_modules/checkride/dist/pm/tools.js.map +1 -0
  175. package/node_modules/checkride/dist/pm/translate.d.ts +35 -9
  176. package/node_modules/checkride/dist/pm/translate.d.ts.map +1 -1
  177. package/node_modules/checkride/dist/pm/translate.js +78 -18
  178. package/node_modules/checkride/dist/pm/translate.js.map +1 -1
  179. package/node_modules/checkride/dist/proc.d.ts +30 -0
  180. package/node_modules/checkride/dist/proc.d.ts.map +1 -0
  181. package/node_modules/checkride/dist/proc.js +42 -0
  182. package/node_modules/checkride/dist/proc.js.map +1 -0
  183. package/node_modules/checkride/dist/qa/cli.d.ts +20 -0
  184. package/node_modules/checkride/dist/qa/cli.d.ts.map +1 -0
  185. package/node_modules/checkride/dist/qa/cli.js +24 -0
  186. package/node_modules/checkride/dist/qa/cli.js.map +1 -0
  187. package/node_modules/checkride/dist/qa/dead.d.ts +39 -0
  188. package/node_modules/checkride/dist/qa/dead.d.ts.map +1 -0
  189. package/node_modules/checkride/dist/qa/dead.js +88 -0
  190. package/node_modules/checkride/dist/qa/dead.js.map +1 -0
  191. package/node_modules/checkride/dist/qa/dupes.d.ts +45 -0
  192. package/node_modules/checkride/dist/qa/dupes.d.ts.map +1 -0
  193. package/node_modules/checkride/dist/qa/dupes.js +62 -0
  194. package/node_modules/checkride/dist/qa/dupes.js.map +1 -0
  195. package/node_modules/checkride/dist/qa/health.d.ts +85 -0
  196. package/node_modules/checkride/dist/qa/health.d.ts.map +1 -0
  197. package/node_modules/checkride/dist/qa/health.js +109 -0
  198. package/node_modules/checkride/dist/qa/health.js.map +1 -0
  199. package/node_modules/checkride/dist/qa/index.d.ts +23 -0
  200. package/node_modules/checkride/dist/qa/index.d.ts.map +1 -0
  201. package/node_modules/checkride/dist/qa/index.js +22 -0
  202. package/node_modules/checkride/dist/qa/index.js.map +1 -0
  203. package/node_modules/checkride/dist/qa/mutation.d.ts +80 -0
  204. package/node_modules/checkride/dist/qa/mutation.d.ts.map +1 -0
  205. package/node_modules/checkride/dist/qa/mutation.js +195 -0
  206. package/node_modules/checkride/dist/qa/mutation.js.map +1 -0
  207. package/node_modules/checkride/dist/qa/qa.d.ts +71 -0
  208. package/node_modules/checkride/dist/qa/qa.d.ts.map +1 -0
  209. package/node_modules/checkride/dist/qa/qa.js +158 -0
  210. package/node_modules/checkride/dist/qa/qa.js.map +1 -0
  211. package/node_modules/checkride/dist/qa/read.d.ts +40 -0
  212. package/node_modules/checkride/dist/qa/read.d.ts.map +1 -0
  213. package/node_modules/checkride/dist/qa/read.js +47 -0
  214. package/node_modules/checkride/dist/qa/read.js.map +1 -0
  215. package/node_modules/checkride/dist/qa/render.d.ts +26 -0
  216. package/node_modules/checkride/dist/qa/render.d.ts.map +1 -0
  217. package/node_modules/checkride/dist/qa/render.js +310 -0
  218. package/node_modules/checkride/dist/qa/render.js.map +1 -0
  219. package/node_modules/checkride/dist/security.d.ts +45 -0
  220. package/node_modules/checkride/dist/security.d.ts.map +1 -0
  221. package/node_modules/checkride/dist/security.js +86 -0
  222. package/node_modules/checkride/dist/security.js.map +1 -0
  223. package/node_modules/checkride/dist/smoke.d.ts +5 -5
  224. package/node_modules/checkride/dist/smoke.js +5 -5
  225. package/node_modules/checkride/dist/snippets.d.ts +26 -29
  226. package/node_modules/checkride/dist/snippets.d.ts.map +1 -1
  227. package/node_modules/checkride/dist/snippets.js +26 -30
  228. package/node_modules/checkride/dist/snippets.js.map +1 -1
  229. package/node_modules/checkride/dist/tool-json.d.ts +33 -0
  230. package/node_modules/checkride/dist/tool-json.d.ts.map +1 -0
  231. package/node_modules/checkride/dist/tool-json.js +58 -0
  232. package/node_modules/checkride/dist/tool-json.js.map +1 -0
  233. package/node_modules/checkride/dist/triage/cli.d.ts +21 -0
  234. package/node_modules/checkride/dist/triage/cli.d.ts.map +1 -0
  235. package/node_modules/checkride/dist/triage/cli.js +26 -0
  236. package/node_modules/checkride/dist/triage/cli.js.map +1 -0
  237. package/node_modules/checkride/dist/triage/doctor-fold.d.ts +51 -0
  238. package/node_modules/checkride/dist/triage/doctor-fold.d.ts.map +1 -0
  239. package/node_modules/checkride/dist/triage/doctor-fold.js +88 -0
  240. package/node_modules/checkride/dist/triage/doctor-fold.js.map +1 -0
  241. package/node_modules/checkride/dist/triage/env.d.ts +54 -0
  242. package/node_modules/checkride/dist/triage/env.d.ts.map +1 -0
  243. package/node_modules/checkride/dist/triage/env.js +81 -0
  244. package/node_modules/checkride/dist/triage/env.js.map +1 -0
  245. package/node_modules/checkride/dist/triage/gate.d.ts +61 -0
  246. package/node_modules/checkride/dist/triage/gate.d.ts.map +1 -0
  247. package/node_modules/checkride/dist/triage/gate.js +121 -0
  248. package/node_modules/checkride/dist/triage/gate.js.map +1 -0
  249. package/node_modules/checkride/dist/triage/index.d.ts +22 -0
  250. package/node_modules/checkride/dist/triage/index.d.ts.map +1 -0
  251. package/node_modules/checkride/dist/triage/index.js +20 -0
  252. package/node_modules/checkride/dist/triage/index.js.map +1 -0
  253. package/node_modules/checkride/dist/triage/render.d.ts +19 -0
  254. package/node_modules/checkride/dist/triage/render.d.ts.map +1 -0
  255. package/node_modules/checkride/dist/triage/render.js +419 -0
  256. package/node_modules/checkride/dist/triage/render.js.map +1 -0
  257. package/node_modules/checkride/dist/triage/triage.d.ts +83 -0
  258. package/node_modules/checkride/dist/triage/triage.d.ts.map +1 -0
  259. package/node_modules/checkride/dist/triage/triage.js +131 -0
  260. package/node_modules/checkride/dist/triage/triage.js.map +1 -0
  261. package/node_modules/checkride/package.json +17 -15
  262. package/node_modules/checkride/schema/checkride.config.schema.json +62 -5
  263. package/node_modules/checkride/schema/checkride.summary.schema.json +1 -1
  264. package/node_modules/checkride/skills/check/SKILL.md +257 -0
  265. package/node_modules/checkride/skills/qa/SKILL.md +231 -0
  266. package/node_modules/checkride/templates/shared/cspell.json +1 -0
  267. package/node_modules/checkride/templates/shared/oxlintrc.json +1 -1
  268. package/package.json +2 -2
  269. package/skills/build/SKILL.md +23 -19
  270. package/skills/finish/SKILL.md +3 -1
  271. package/skills/harvest/SKILL.md +2 -1
  272. package/skills/plan/SKILL.md +8 -7
  273. package/skills/recover/SKILL.md +28 -0
  274. package/skills/refine/SKILL.md +5 -4
  275. package/skills/spike/SKILL.md +1 -1
  276. package/skills/step/SKILL.md +4 -4
  277. package/skills/verify/SKILL.md +19 -14
  278. package/templates/intent.md +8 -7
@@ -0,0 +1,45 @@
1
+ /**
2
+ * `dupes.json` — fallow's duplication report. The smallest of the four
3
+ * artifacts (483 B when clean here) and the one most able to explode: every
4
+ * clone instance carries a `fragment` holding the duplicated *source text*, so
5
+ * a report with real findings is mostly code.
6
+ *
7
+ * None of that text is extracted. What a reader needs is where the duplication
8
+ * is and how much of it there is — so a family reduces to its file membership
9
+ * and its line and token totals, and the fragments stay on disk.
10
+ *
11
+ * Families, not groups, are the unit: fallow groups clones by content and then
12
+ * collects the groups that span the same files into a family, which is the
13
+ * level a refactor actually happens at. The group count still reports, because
14
+ * that is what checkride gates the slot on.
15
+ *
16
+ * The `../qa` barrel is this module's only public surface.
17
+ */
18
+ /** A set of files sharing duplicated code. */
19
+ export type CloneFamily = {
20
+ files: string[];
21
+ /** Files past {@link FILES_PER_FAMILY}, so the list never implies completeness. */
22
+ omittedFiles: number;
23
+ groups: number;
24
+ lines: number | null;
25
+ tokens: number | null;
26
+ };
27
+ export type DupesExtract = {
28
+ duplicationPercentage: number | null;
29
+ duplicatedLines: number | null;
30
+ totalLines: number | null;
31
+ totalFiles: number | null;
32
+ filesWithClones: number | null;
33
+ /** Clone groups — the count checkride gates the `dupes` slot on. */
34
+ cloneGroups: number;
35
+ totalFamilies: number;
36
+ families: CloneFamily[];
37
+ omittedFamilies: number;
38
+ };
39
+ /**
40
+ * Fold a parsed `dupes.json` into the report model, or `null` when it has no
41
+ * `clone_groups` array — the field checkride's own verdict reads, so a report
42
+ * without it is not a dupes report and must not be summarized as clean.
43
+ */
44
+ export declare function extractDupes(value: Record<string, unknown>): DupesExtract | null;
45
+ //# sourceMappingURL=dupes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dupes.d.ts","sourceRoot":"","sources":["../../src/qa/dupes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AASH,8CAA8C;AAC9C,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,mFAAmF;IACnF,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,oEAAoE;IACpE,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AAwBF;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,YAAY,GAAG,IAAI,CAiBhF"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * `dupes.json` — fallow's duplication report. The smallest of the four
3
+ * artifacts (483 B when clean here) and the one most able to explode: every
4
+ * clone instance carries a `fragment` holding the duplicated *source text*, so
5
+ * a report with real findings is mostly code.
6
+ *
7
+ * None of that text is extracted. What a reader needs is where the duplication
8
+ * is and how much of it there is — so a family reduces to its file membership
9
+ * and its line and token totals, and the fragments stay on disk.
10
+ *
11
+ * Families, not groups, are the unit: fallow groups clones by content and then
12
+ * collects the groups that span the same files into a family, which is the
13
+ * level a refactor actually happens at. The group count still reports, because
14
+ * that is what checkride gates the slot on.
15
+ *
16
+ * The `../qa` barrel is this module's only public surface.
17
+ */
18
+ import { asNumberOrNull, asRecord, asRecordArray } from '../artifacts/index.js';
19
+ /** Families listed; the rest are counted. */
20
+ const TOP_FAMILIES = 6;
21
+ /** Files named per family before the rest collapse to a count. */
22
+ const FILES_PER_FAMILY = 4;
23
+ function readFamily(family) {
24
+ const files = (Array.isArray(family['files']) ? family['files'] : []).filter((file) => typeof file === 'string');
25
+ return {
26
+ files: files.slice(0, FILES_PER_FAMILY),
27
+ omittedFiles: Math.max(0, files.length - FILES_PER_FAMILY),
28
+ groups: asRecordArray(family['groups']).length,
29
+ lines: asNumberOrNull(family['total_duplicated_lines']),
30
+ tokens: asNumberOrNull(family['total_duplicated_tokens']),
31
+ };
32
+ }
33
+ /** Worst first: most duplicated lines, then most files, then by name. */
34
+ function byWeight(a, b) {
35
+ return ((b.lines ?? 0) - (a.lines ?? 0) ||
36
+ b.files.length - a.files.length ||
37
+ (a.files[0] ?? '').localeCompare(b.files[0] ?? ''));
38
+ }
39
+ /**
40
+ * Fold a parsed `dupes.json` into the report model, or `null` when it has no
41
+ * `clone_groups` array — the field checkride's own verdict reads, so a report
42
+ * without it is not a dupes report and must not be summarized as clean.
43
+ */
44
+ export function extractDupes(value) {
45
+ const groups = value['clone_groups'];
46
+ if (!Array.isArray(groups))
47
+ return null;
48
+ const stats = asRecord(value['stats']);
49
+ const families = asRecordArray(value['clone_families']).map(readFamily).toSorted(byWeight);
50
+ return {
51
+ duplicationPercentage: asNumberOrNull(stats['duplication_percentage']),
52
+ duplicatedLines: asNumberOrNull(stats['duplicated_lines']),
53
+ totalLines: asNumberOrNull(stats['total_lines']),
54
+ totalFiles: asNumberOrNull(stats['total_files']),
55
+ filesWithClones: asNumberOrNull(stats['files_with_clones']),
56
+ cloneGroups: groups.length,
57
+ totalFamilies: families.length,
58
+ families: families.slice(0, TOP_FAMILIES),
59
+ omittedFamilies: Math.max(0, families.length - TOP_FAMILIES),
60
+ };
61
+ }
62
+ //# sourceMappingURL=dupes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dupes.js","sourceRoot":"","sources":["../../src/qa/dupes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEhF,6CAA6C;AAC7C,MAAM,YAAY,GAAG,CAAC,CAAC;AACvB,kEAAkE;AAClE,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAyB3B,SAAS,UAAU,CAAC,MAA+B;IACjD,MAAM,KAAK,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAC1E,CAAC,IAAI,EAAkB,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,CACnD,CAAC;IACF,OAAO;QACL,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,gBAAgB,CAAC;QACvC,YAAY,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,gBAAgB,CAAC;QAC1D,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM;QAC9C,KAAK,EAAE,cAAc,CAAC,MAAM,CAAC,wBAAwB,CAAC,CAAC;QACvD,MAAM,EAAE,cAAc,CAAC,MAAM,CAAC,yBAAyB,CAAC,CAAC;KAC1D,CAAC;AACJ,CAAC;AAED,yEAAyE;AACzE,SAAS,QAAQ,CAAC,CAAc,EAAE,CAAc;IAC9C,OAAO,CACL,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;QAC/B,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM;QAC/B,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CACnD,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,KAA8B;IACzD,MAAM,MAAM,GAAG,KAAK,CAAC,cAAc,CAAC,CAAC;IACrC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IAExC,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;IACvC,MAAM,QAAQ,GAAG,aAAa,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC3F,OAAO;QACL,qBAAqB,EAAE,cAAc,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC;QACtE,eAAe,EAAE,cAAc,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;QAC1D,UAAU,EAAE,cAAc,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QAChD,UAAU,EAAE,cAAc,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QAChD,eAAe,EAAE,cAAc,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;QAC3D,WAAW,EAAE,MAAM,CAAC,MAAM;QAC1B,aAAa,EAAE,QAAQ,CAAC,MAAM;QAC9B,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,YAAY,CAAC;QACzC,eAAe,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,MAAM,GAAG,YAAY,CAAC;KAC7D,CAAC;AACJ,CAAC"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * `health.json` — fallow's complexity and maintainability report, ~50 KB of
3
+ * which perhaps twenty numbers are worth an agent's attention.
4
+ *
5
+ * The score is the headline, but a bare `80.7/B` is not actionable: fallow
6
+ * computes it by subtracting named penalties from 100, and the *non-zero*
7
+ * penalties are the whole explanation of the grade. Reporting them ranked, with
8
+ * the zeroes counted rather than listed, turns "the score is B" into "hotspots
9
+ * cost 10 points and unit size cost 8.5" — which names what to fix.
10
+ *
11
+ * Per-function findings are the other half. fallow gates on four independent
12
+ * thresholds (cyclomatic, cognitive, CRAP, unit size) and each finding says in
13
+ * `exceeded` which one it breached, so the findings group by that rather than
14
+ * collapsing into an undifferentiated count: a function over the size threshold
15
+ * and one over CRAP want different fixes.
16
+ *
17
+ * Hotspots (complex *and* frequently changed) are ranked by fallow's own score
18
+ * and capped — they are the input to the fragility judgment the skill makes,
19
+ * not a judgment this reader should be making.
20
+ *
21
+ * The `../qa` barrel is this module's only public surface.
22
+ */
23
+ /** One named penalty subtracted from a perfect 100. */
24
+ export type Penalty = {
25
+ name: string;
26
+ points: number;
27
+ };
28
+ /** One function over one of fallow's four thresholds. */
29
+ export type HealthFinding = {
30
+ path: string;
31
+ name: string;
32
+ line: number | null;
33
+ /** Which threshold it breached: `cyclomatic`, `cognitive`, `crap`, `unit_size`. */
34
+ exceeded: string;
35
+ severity: string;
36
+ cyclomatic: number | null;
37
+ cognitive: number | null;
38
+ lineCount: number | null;
39
+ };
40
+ /** A file that is both complex and frequently changed. */
41
+ export type Hotspot = {
42
+ path: string;
43
+ score: number | null;
44
+ commits: number | null;
45
+ complexityDensity: number | null;
46
+ trend: string;
47
+ };
48
+ /** The four thresholds a `health` finding can breach, as configured. */
49
+ export type Thresholds = {
50
+ cyclomatic: number | null;
51
+ cognitive: number | null;
52
+ crap: number | null;
53
+ unitSize: number | null;
54
+ };
55
+ export type HealthExtract = {
56
+ score: number | null;
57
+ grade: string;
58
+ formulaVersion: number | null;
59
+ /** Non-zero penalties, worst first — the score's actual causes. */
60
+ penalties: Penalty[];
61
+ /** Penalties that scored zero, counted rather than listed. */
62
+ zeroPenalties: number;
63
+ filesAnalyzed: number | null;
64
+ functionsAnalyzed: number | null;
65
+ averageMaintainability: number | null;
66
+ thresholds: Thresholds;
67
+ totalFindings: number;
68
+ findings: HealthFinding[];
69
+ omittedFindings: number;
70
+ /** Findings per breached threshold, worst first — covers the omitted ones too. */
71
+ byThreshold: {
72
+ exceeded: string;
73
+ count: number;
74
+ }[];
75
+ totalHotspots: number;
76
+ hotspots: Hotspot[];
77
+ omittedHotspots: number;
78
+ };
79
+ /**
80
+ * Fold a parsed `health.json` into the report model, or `null` when it carries
81
+ * no `health_score` block — that is not a fallow health report, and saying so
82
+ * beats reporting a zero score that reads like a finding.
83
+ */
84
+ export declare function extractHealth(value: Record<string, unknown>): HealthExtract | null;
85
+ //# sourceMappingURL=health.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../src/qa/health.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AASH,uDAAuD;AACvD,MAAM,MAAM,OAAO,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvD,yDAAyD;AACzD,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,mFAAmF;IACnF,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,CAAC;AAEF,0DAA0D;AAC1D,MAAM,MAAM,OAAO,GAAG;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,wEAAwE;AACxE,MAAM,MAAM,UAAU,GAAG;IACvB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,mEAAmE;IACnE,SAAS,EAAE,OAAO,EAAE,CAAC;IACrB,8DAA8D;IAC9D,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,UAAU,EAAE,UAAU,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,kFAAkF;IAClF,WAAW,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACnD,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AAuDF;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,aAAa,GAAG,IAAI,CA2BlF"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * `health.json` — fallow's complexity and maintainability report, ~50 KB of
3
+ * which perhaps twenty numbers are worth an agent's attention.
4
+ *
5
+ * The score is the headline, but a bare `80.7/B` is not actionable: fallow
6
+ * computes it by subtracting named penalties from 100, and the *non-zero*
7
+ * penalties are the whole explanation of the grade. Reporting them ranked, with
8
+ * the zeroes counted rather than listed, turns "the score is B" into "hotspots
9
+ * cost 10 points and unit size cost 8.5" — which names what to fix.
10
+ *
11
+ * Per-function findings are the other half. fallow gates on four independent
12
+ * thresholds (cyclomatic, cognitive, CRAP, unit size) and each finding says in
13
+ * `exceeded` which one it breached, so the findings group by that rather than
14
+ * collapsing into an undifferentiated count: a function over the size threshold
15
+ * and one over CRAP want different fixes.
16
+ *
17
+ * Hotspots (complex *and* frequently changed) are ranked by fallow's own score
18
+ * and capped — they are the input to the fragility judgment the skill makes,
19
+ * not a judgment this reader should be making.
20
+ *
21
+ * The `../qa` barrel is this module's only public surface.
22
+ */
23
+ import { asNumberOrNull as num, asRecord, asRecordArray, asStringOrNull, isRecord } from '../artifacts/index.js';
24
+ /** Findings listed individually before they collapse to counts by threshold. */
25
+ const TOP_FINDINGS = 8;
26
+ /** Hotspots listed; the rest are counted. */
27
+ const TOP_HOTSPOTS = 6;
28
+ /** Non-zero penalties, worst first, plus how many scored zero. */
29
+ function readPenalties(scoreBlock) {
30
+ const entries = Object.entries(asRecord(scoreBlock['penalties']))
31
+ .map(([name, value]) => ({ name, points: num(value) ?? 0 }));
32
+ return {
33
+ penalties: entries
34
+ .filter((p) => p.points > 0)
35
+ .toSorted((a, b) => b.points - a.points || a.name.localeCompare(b.name)),
36
+ zeroPenalties: entries.filter((p) => p.points <= 0).length,
37
+ };
38
+ }
39
+ function readThresholds(summary) {
40
+ return {
41
+ cyclomatic: num(summary['max_cyclomatic_threshold']),
42
+ cognitive: num(summary['max_cognitive_threshold']),
43
+ crap: num(summary['max_crap_threshold']),
44
+ unitSize: num(summary['max_unit_size_threshold']),
45
+ };
46
+ }
47
+ function readFinding(finding) {
48
+ return {
49
+ path: asStringOrNull(finding['path']) ?? '?',
50
+ name: asStringOrNull(finding['name']) ?? '?',
51
+ line: num(finding['line']),
52
+ exceeded: asStringOrNull(finding['exceeded']) ?? 'unknown',
53
+ severity: asStringOrNull(finding['severity']) ?? 'unknown',
54
+ cyclomatic: num(finding['cyclomatic']),
55
+ cognitive: num(finding['cognitive']),
56
+ lineCount: num(finding['line_count']),
57
+ };
58
+ }
59
+ /** Every finding grouped by the threshold it breached, worst-populated first. */
60
+ function groupByThreshold(findings) {
61
+ const counts = new Map();
62
+ for (const finding of findings)
63
+ counts.set(finding.exceeded, (counts.get(finding.exceeded) ?? 0) + 1);
64
+ return [...counts]
65
+ .map(([exceeded, count]) => ({ exceeded, count }))
66
+ .toSorted((a, b) => b.count - a.count || a.exceeded.localeCompare(b.exceeded));
67
+ }
68
+ function readHotspot(hotspot) {
69
+ return {
70
+ path: asStringOrNull(hotspot['path']) ?? '?',
71
+ score: num(hotspot['score']),
72
+ commits: num(hotspot['commits']),
73
+ complexityDensity: num(hotspot['complexity_density']),
74
+ trend: asStringOrNull(hotspot['trend']) ?? 'unknown',
75
+ };
76
+ }
77
+ /**
78
+ * Fold a parsed `health.json` into the report model, or `null` when it carries
79
+ * no `health_score` block — that is not a fallow health report, and saying so
80
+ * beats reporting a zero score that reads like a finding.
81
+ */
82
+ export function extractHealth(value) {
83
+ const scoreBlock = value['health_score'];
84
+ if (!isRecord(scoreBlock))
85
+ return null;
86
+ const summary = asRecord(value['summary']);
87
+ const { penalties, zeroPenalties } = readPenalties(scoreBlock);
88
+ const findings = asRecordArray(value['findings']).map(readFinding);
89
+ const hotspots = asRecordArray(value['hotspots']).map(readHotspot);
90
+ return {
91
+ score: num(scoreBlock['score']),
92
+ grade: asStringOrNull(scoreBlock['grade']) ?? '?',
93
+ formulaVersion: num(scoreBlock['formula_version']),
94
+ penalties,
95
+ zeroPenalties,
96
+ filesAnalyzed: num(summary['files_analyzed']),
97
+ functionsAnalyzed: num(summary['functions_analyzed']),
98
+ averageMaintainability: num(summary['average_maintainability']),
99
+ thresholds: readThresholds(summary),
100
+ totalFindings: findings.length,
101
+ findings: findings.slice(0, TOP_FINDINGS),
102
+ omittedFindings: Math.max(0, findings.length - TOP_FINDINGS),
103
+ byThreshold: groupByThreshold(findings),
104
+ totalHotspots: hotspots.length,
105
+ hotspots: hotspots.slice(0, TOP_HOTSPOTS),
106
+ omittedHotspots: Math.max(0, hotspots.length - TOP_HOTSPOTS),
107
+ };
108
+ }
109
+ //# sourceMappingURL=health.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/qa/health.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Quality module — the bundled plugin's reader for the four artifacts
3
+ * checkride already writes about code quality: `mutation`, `dead`, `dupes` and
4
+ * `health`. Named for the skill it serves, as `../triage` is.
5
+ *
6
+ * It runs nothing (D2). It opens what a previous run left in `.check/`, folds
7
+ * each artifact to a short, ranked list, and says plainly which of the four is
8
+ * evidence and which is stale, absent, or from a slot the repo never opted into
9
+ * — the normal case, not the edge case, since three of the four are opt-in.
10
+ *
11
+ * `./cli.ts` is the executable form (`node dist/qa/cli.js`); this
12
+ * barrel is the module's programmatic surface, and files inside the module
13
+ * import each other directly rather than through it.
14
+ */
15
+ export { extractDead } from './dead.js';
16
+ export { extractDupes } from './dupes.js';
17
+ export { extractHealth } from './health.js';
18
+ export { extractMutation } from './mutation.js';
19
+ export { qaExtract } from './qa.js';
20
+ export type { QaReport } from './qa.js';
21
+ export { readJsonArtifact } from './read.js';
22
+ export { QA_MAX_BYTES, renderQa } from './render.js';
23
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/qa/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExC,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAE7C,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Quality module — the bundled plugin's reader for the four artifacts
3
+ * checkride already writes about code quality: `mutation`, `dead`, `dupes` and
4
+ * `health`. Named for the skill it serves, as `../triage` is.
5
+ *
6
+ * It runs nothing (D2). It opens what a previous run left in `.check/`, folds
7
+ * each artifact to a short, ranked list, and says plainly which of the four is
8
+ * evidence and which is stale, absent, or from a slot the repo never opted into
9
+ * — the normal case, not the edge case, since three of the four are opt-in.
10
+ *
11
+ * `./cli.ts` is the executable form (`node dist/qa/cli.js`); this
12
+ * barrel is the module's programmatic surface, and files inside the module
13
+ * import each other directly rather than through it.
14
+ */
15
+ export { extractDead } from './dead.js';
16
+ export { extractDupes } from './dupes.js';
17
+ export { extractHealth } from './health.js';
18
+ export { extractMutation } from './mutation.js';
19
+ export { qaExtract } from './qa.js';
20
+ export { readJsonArtifact } from './read.js';
21
+ export { QA_MAX_BYTES, renderQa } from './render.js';
22
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/qa/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAGpC,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAE7C,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * `mutation.json` — 2.3 MB and 4453 mutants in this repo — folded into a short
3
+ * list an agent can act on.
4
+ *
5
+ * The scores are stryker's own, computed the way stryker computes them, so the
6
+ * numbers here match the ones its reporter printed: `Ignored` (and any error
7
+ * status) leaves the denominator entirely, `Killed` and `Timeout` are detected,
8
+ * `Survived` and `NoCoverage` are not. Inventing a differently-defined score
9
+ * than the tool prints is the confidently-wrong answer this reader exists to
10
+ * prevent, so the arithmetic is pinned to the tool's.
11
+ *
12
+ * **The ranking is the judgment here.** 777 survivors is not a list anyone
13
+ * reads, so files rank by *undetected* count (`Survived` + `NoCoverage`)
14
+ * descending — that is what "where would tests buy the most" means — with the
15
+ * per-file score shown beside it so a small badly-tested file is still legible
16
+ * next to a large mostly-tested one. Ranking by score alone would put a
17
+ * two-mutant file at the top of a 4453-mutant report; ranking by count alone
18
+ * would say nothing but "the big files are big". Ties break on the worse score,
19
+ * then the path, so the same report always renders the same bytes.
20
+ *
21
+ * Two further cuts carry most of the signal at almost no byte cost. Splitting
22
+ * `NoCoverage` out from `Survived` separates "no test reaches this line" (add
23
+ * any test) from "a test reaches it and asserts nothing about it" (strengthen
24
+ * an assertion). And tallying undetected mutants *by mutator kind* separates
25
+ * real logic gaps (`ConditionalExpression`, `EqualityOperator`) from the
26
+ * `StringLiteral` churn in error messages that no one intends to assert on.
27
+ *
28
+ * The `../qa` barrel is this module's only public surface.
29
+ */
30
+ /** One mutator kind and how many undetected mutants it accounts for. */
31
+ export type MutatorCount = {
32
+ mutator: string;
33
+ count: number;
34
+ };
35
+ /** An undetected mutant, located — enough to open the file at the right line. */
36
+ export type MutantSample = {
37
+ path: string;
38
+ line: number | null;
39
+ mutator: string;
40
+ status: string;
41
+ /** First line of the replacement, clipped; `…` marks anything left off. */
42
+ replacement: string;
43
+ };
44
+ /** One source file's mutation standing. */
45
+ export type MutationFile = {
46
+ path: string;
47
+ survived: number;
48
+ noCoverage: number;
49
+ /** Mutants that counted toward the score — detected plus undetected. */
50
+ tested: number;
51
+ /** Percentage, or `null` when no mutant in this file was testable. */
52
+ score: number | null;
53
+ mutators: MutatorCount[];
54
+ };
55
+ export type MutationExtract = {
56
+ killed: number;
57
+ timeout: number;
58
+ survived: number;
59
+ noCoverage: number;
60
+ ignored: number;
61
+ /** Compile/runtime errors and any status a future stryker adds. */
62
+ other: number;
63
+ total: number;
64
+ /** Stryker's headline: detected ÷ tested. `null` when nothing was testable. */
65
+ score: number | null;
66
+ /** Stryker's "score covered": the same, ignoring mutants no test reaches. */
67
+ scoreCovered: number | null;
68
+ totalFiles: number;
69
+ files: MutationFile[];
70
+ omittedFiles: number;
71
+ mutators: MutatorCount[];
72
+ samples: MutantSample[];
73
+ };
74
+ /**
75
+ * Fold a parsed `mutation.json` into the report model, or `null` when it is not
76
+ * a stryker report (no `files` object) — the ledger reports that rather than
77
+ * this returning an empty extract that would read as "nothing survived".
78
+ */
79
+ export declare function extractMutation(value: Record<string, unknown>): MutationExtract | null;
80
+ //# sourceMappingURL=mutation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mutation.d.ts","sourceRoot":"","sources":["../../src/qa/mutation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAkBH,wEAAwE;AACxE,MAAM,MAAM,YAAY,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9D,iFAAiF;AACjF,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,2EAA2E;IAC3E,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,2CAA2C;AAC3C,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,wEAAwE;IACxE,MAAM,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,QAAQ,EAAE,YAAY,EAAE,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,+EAA+E;IAC/E,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,6EAA6E;IAC7E,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,OAAO,EAAE,YAAY,EAAE,CAAC;CACzB,CAAC;AAuJF;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,eAAe,GAAG,IAAI,CAsBtF"}