@vyuhlabs/dxkit 2.4.8 → 2.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (319) hide show
  1. package/CHANGELOG.md +312 -0
  2. package/README.md +360 -439
  3. package/dist/analyzers/security/aggregator.d.ts.map +1 -1
  4. package/dist/analyzers/security/aggregator.js +4 -46
  5. package/dist/analyzers/security/aggregator.js.map +1 -1
  6. package/dist/analyzers/tools/fingerprint.d.ts +91 -26
  7. package/dist/analyzers/tools/fingerprint.d.ts.map +1 -1
  8. package/dist/analyzers/tools/fingerprint.js +111 -22
  9. package/dist/analyzers/tools/fingerprint.js.map +1 -1
  10. package/dist/analyzers/tools/generic.d.ts.map +1 -1
  11. package/dist/analyzers/tools/generic.js +6 -1
  12. package/dist/analyzers/tools/generic.js.map +1 -1
  13. package/dist/analyzers/tools/gitleaks.d.ts +24 -1
  14. package/dist/analyzers/tools/gitleaks.d.ts.map +1 -1
  15. package/dist/analyzers/tools/gitleaks.js +20 -11
  16. package/dist/analyzers/tools/gitleaks.js.map +1 -1
  17. package/dist/analyzers/tools/graphify.d.ts.map +1 -1
  18. package/dist/analyzers/tools/graphify.js +9 -5
  19. package/dist/analyzers/tools/graphify.js.map +1 -1
  20. package/dist/analyzers/tools/tool-registry.d.ts +19 -1
  21. package/dist/analyzers/tools/tool-registry.d.ts.map +1 -1
  22. package/dist/analyzers/tools/tool-registry.js +25 -0
  23. package/dist/analyzers/tools/tool-registry.js.map +1 -1
  24. package/dist/analyzers/types.d.ts +6 -4
  25. package/dist/analyzers/types.d.ts.map +1 -1
  26. package/dist/baseline/baseline-file.d.ts +104 -0
  27. package/dist/baseline/baseline-file.d.ts.map +1 -0
  28. package/dist/baseline/baseline-file.js +110 -0
  29. package/dist/baseline/baseline-file.js.map +1 -0
  30. package/dist/baseline/check-renderers.d.ts +108 -0
  31. package/dist/baseline/check-renderers.d.ts.map +1 -0
  32. package/dist/baseline/check-renderers.js +379 -0
  33. package/dist/baseline/check-renderers.js.map +1 -0
  34. package/dist/baseline/check.d.ts +127 -0
  35. package/dist/baseline/check.d.ts.map +1 -0
  36. package/dist/baseline/check.js +462 -0
  37. package/dist/baseline/check.js.map +1 -0
  38. package/dist/baseline/content-hash.d.ts +83 -0
  39. package/dist/baseline/content-hash.d.ts.map +1 -0
  40. package/dist/baseline/content-hash.js +131 -0
  41. package/dist/baseline/content-hash.js.map +1 -0
  42. package/dist/baseline/create.d.ts +96 -0
  43. package/dist/baseline/create.d.ts.map +1 -0
  44. package/dist/baseline/create.js +339 -0
  45. package/dist/baseline/create.js.map +1 -0
  46. package/dist/baseline/entry-to-located.d.ts +35 -0
  47. package/dist/baseline/entry-to-located.d.ts.map +1 -0
  48. package/dist/baseline/entry-to-located.js +72 -0
  49. package/dist/baseline/entry-to-located.js.map +1 -0
  50. package/dist/baseline/finding-identity.d.ts +47 -0
  51. package/dist/baseline/finding-identity.d.ts.map +1 -0
  52. package/dist/baseline/finding-identity.js +292 -0
  53. package/dist/baseline/finding-identity.js.map +1 -0
  54. package/dist/baseline/git-aware-match.d.ts +146 -0
  55. package/dist/baseline/git-aware-match.d.ts.map +1 -0
  56. package/dist/baseline/git-aware-match.js +439 -0
  57. package/dist/baseline/git-aware-match.js.map +1 -0
  58. package/dist/baseline/policy.d.ts +171 -0
  59. package/dist/baseline/policy.d.ts.map +1 -0
  60. package/dist/baseline/policy.js +206 -0
  61. package/dist/baseline/policy.js.map +1 -0
  62. package/dist/baseline/producers/health.d.ts +30 -0
  63. package/dist/baseline/producers/health.d.ts.map +1 -0
  64. package/dist/baseline/producers/health.js +42 -0
  65. package/dist/baseline/producers/health.js.map +1 -0
  66. package/dist/baseline/producers/index.d.ts +164 -0
  67. package/dist/baseline/producers/index.d.ts.map +1 -0
  68. package/dist/baseline/producers/index.js +200 -0
  69. package/dist/baseline/producers/index.js.map +1 -0
  70. package/dist/baseline/producers/licenses.d.ts +23 -0
  71. package/dist/baseline/producers/licenses.d.ts.map +1 -0
  72. package/dist/baseline/producers/licenses.js +46 -0
  73. package/dist/baseline/producers/licenses.js.map +1 -0
  74. package/dist/baseline/producers/quality.d.ts +39 -0
  75. package/dist/baseline/producers/quality.d.ts.map +1 -0
  76. package/dist/baseline/producers/quality.js +84 -0
  77. package/dist/baseline/producers/quality.js.map +1 -0
  78. package/dist/baseline/producers/secret-hmac.d.ts +45 -0
  79. package/dist/baseline/producers/secret-hmac.d.ts.map +1 -0
  80. package/dist/baseline/producers/secret-hmac.js +70 -0
  81. package/dist/baseline/producers/secret-hmac.js.map +1 -0
  82. package/dist/baseline/producers/security.d.ts +59 -0
  83. package/dist/baseline/producers/security.d.ts.map +1 -0
  84. package/dist/baseline/producers/security.js +135 -0
  85. package/dist/baseline/producers/security.js.map +1 -0
  86. package/dist/baseline/producers/tests.d.ts +36 -0
  87. package/dist/baseline/producers/tests.d.ts.map +1 -0
  88. package/dist/baseline/producers/tests.js +69 -0
  89. package/dist/baseline/producers/tests.js.map +1 -0
  90. package/dist/baseline/salt.d.ts +45 -0
  91. package/dist/baseline/salt.d.ts.map +1 -0
  92. package/dist/baseline/salt.js +113 -0
  93. package/dist/baseline/salt.js.map +1 -0
  94. package/dist/baseline/show.d.ts +79 -0
  95. package/dist/baseline/show.d.ts.map +1 -0
  96. package/dist/baseline/show.js +233 -0
  97. package/dist/baseline/show.js.map +1 -0
  98. package/dist/baseline/types.d.ts +482 -0
  99. package/dist/baseline/types.d.ts.map +1 -0
  100. package/dist/baseline/types.js +53 -0
  101. package/dist/baseline/types.js.map +1 -0
  102. package/dist/cli.d.ts.map +1 -1
  103. package/dist/cli.js +398 -82
  104. package/dist/cli.js.map +1 -1
  105. package/dist/constants.d.ts.map +1 -1
  106. package/dist/constants.js +0 -4
  107. package/dist/constants.js.map +1 -1
  108. package/dist/doctor.d.ts.map +1 -1
  109. package/dist/doctor.js +39 -35
  110. package/dist/doctor.js.map +1 -1
  111. package/dist/fail-on.d.ts +84 -0
  112. package/dist/fail-on.d.ts.map +1 -0
  113. package/dist/fail-on.js +128 -0
  114. package/dist/fail-on.js.map +1 -0
  115. package/dist/generator.d.ts +1 -1
  116. package/dist/generator.d.ts.map +1 -1
  117. package/dist/generator.js +81 -274
  118. package/dist/generator.js.map +1 -1
  119. package/dist/hooks-cli.d.ts +20 -0
  120. package/dist/hooks-cli.d.ts.map +1 -0
  121. package/dist/hooks-cli.js +145 -0
  122. package/dist/hooks-cli.js.map +1 -0
  123. package/dist/languages/csharp.d.ts.map +1 -1
  124. package/dist/languages/csharp.js +4 -9
  125. package/dist/languages/csharp.js.map +1 -1
  126. package/dist/languages/go.d.ts.map +1 -1
  127. package/dist/languages/go.js +3 -14
  128. package/dist/languages/go.js.map +1 -1
  129. package/dist/languages/index.d.ts +19 -1
  130. package/dist/languages/index.d.ts.map +1 -1
  131. package/dist/languages/index.js +32 -0
  132. package/dist/languages/index.js.map +1 -1
  133. package/dist/languages/java.d.ts.map +1 -1
  134. package/dist/languages/java.js +4 -6
  135. package/dist/languages/java.js.map +1 -1
  136. package/dist/languages/kotlin.d.ts.map +1 -1
  137. package/dist/languages/kotlin.js +9 -11
  138. package/dist/languages/kotlin.js.map +1 -1
  139. package/dist/languages/python.d.ts.map +1 -1
  140. package/dist/languages/python.js +4 -15
  141. package/dist/languages/python.js.map +1 -1
  142. package/dist/languages/ruby.d.ts.map +1 -1
  143. package/dist/languages/ruby.js +4 -6
  144. package/dist/languages/ruby.js.map +1 -1
  145. package/dist/languages/rust.d.ts.map +1 -1
  146. package/dist/languages/rust.js +4 -4
  147. package/dist/languages/rust.js.map +1 -1
  148. package/dist/languages/types.d.ts +29 -28
  149. package/dist/languages/types.d.ts.map +1 -1
  150. package/dist/languages/typescript.d.ts.map +1 -1
  151. package/dist/languages/typescript.js +31 -4
  152. package/dist/languages/typescript.js.map +1 -1
  153. package/dist/lib.d.ts +2 -3
  154. package/dist/lib.d.ts.map +1 -1
  155. package/dist/lib.js +3 -6
  156. package/dist/lib.js.map +1 -1
  157. package/dist/prompts.d.ts.map +1 -1
  158. package/dist/prompts.js +0 -10
  159. package/dist/prompts.js.map +1 -1
  160. package/dist/report-schema.d.ts +42 -0
  161. package/dist/report-schema.d.ts.map +1 -0
  162. package/dist/report-schema.js +54 -0
  163. package/dist/report-schema.js.map +1 -0
  164. package/dist/ship-installers.d.ts +112 -0
  165. package/dist/ship-installers.d.ts.map +1 -0
  166. package/dist/ship-installers.js +530 -0
  167. package/dist/ship-installers.js.map +1 -0
  168. package/dist/tools-cli.d.ts.map +1 -1
  169. package/dist/tools-cli.js +45 -9
  170. package/dist/tools-cli.js.map +1 -1
  171. package/dist/types.d.ts +0 -4
  172. package/dist/types.d.ts.map +1 -1
  173. package/dist/update.d.ts.map +1 -1
  174. package/dist/update.js +0 -4
  175. package/dist/update.js.map +1 -1
  176. package/package.json +17 -11
  177. package/templates/.claude/skills/dxkit-action/SKILL.md +150 -0
  178. package/templates/.claude/skills/dxkit-config/SKILL.md +124 -0
  179. package/templates/.claude/skills/dxkit-hooks/SKILL.md +109 -0
  180. package/templates/.claude/skills/dxkit-init/SKILL.md +93 -0
  181. package/templates/.claude/skills/dxkit-learn/SKILL.md +84 -0
  182. package/templates/.claude/skills/dxkit-reports/SKILL.md +111 -0
  183. package/templates/.devcontainer/devcontainer.json +55 -0
  184. package/templates/.devcontainer/install-agent-clis.sh +42 -0
  185. package/templates/.devcontainer/post-create.sh +81 -0
  186. package/templates/.githooks/pre-commit +55 -0
  187. package/templates/.githooks/pre-push +63 -0
  188. package/templates/.github/workflows/dxkit-baseline-refresh.yml +78 -0
  189. package/templates/.github/workflows/dxkit-guardrails.yml +98 -0
  190. package/templates/AGENTS.md.template +137 -0
  191. package/templates/CLAUDE.md.template +16 -245
  192. package/dist/codebase-scanner.d.ts +0 -36
  193. package/dist/codebase-scanner.d.ts.map +0 -1
  194. package/dist/codebase-scanner.js +0 -688
  195. package/dist/codebase-scanner.js.map +0 -1
  196. package/dist/project-yaml.d.ts +0 -13
  197. package/dist/project-yaml.d.ts.map +0 -1
  198. package/dist/project-yaml.js +0 -188
  199. package/dist/project-yaml.js.map +0 -1
  200. package/templates/.ai/README.md +0 -117
  201. package/templates/.ai/prompts/execution-prompt.md +0 -9
  202. package/templates/.ai/prompts/planning-prompt.md +0 -18
  203. package/templates/.ai/prompts/session-end-template.md +0 -182
  204. package/templates/.ai/prompts/session-end.md +0 -132
  205. package/templates/.ai/prompts/session-start.md +0 -109
  206. package/templates/.ai/prompts/step-by-step.md +0 -113
  207. package/templates/.ai/sessions/.gitkeep +0 -0
  208. package/templates/.claude/agents/doc-writer.md +0 -107
  209. package/templates/.claude/agents/knowledge-bot.md +0 -64
  210. package/templates/.claude/agents/onboarding.md +0 -61
  211. package/templates/.claude/agents/quality-reviewer.md +0 -85
  212. package/templates/.claude/agents-available/code-reviewer.md +0 -29
  213. package/templates/.claude/agents-available/codebase-explorer.md +0 -100
  214. package/templates/.claude/agents-available/dashboard-builder.md +0 -433
  215. package/templates/.claude/agents-available/debugger.md +0 -29
  216. package/templates/.claude/agents-available/dependency-mapper.md +0 -80
  217. package/templates/.claude/agents-available/dev-report.md +0 -108
  218. package/templates/.claude/agents-available/doc-writer.md +0 -107
  219. package/templates/.claude/agents-available/feature-builder.md +0 -163
  220. package/templates/.claude/agents-available/feature-planner.md +0 -185
  221. package/templates/.claude/agents-available/health-auditor.md +0 -95
  222. package/templates/.claude/agents-available/hooks-configurator.md +0 -211
  223. package/templates/.claude/agents-available/knowledge-bot.md +0 -62
  224. package/templates/.claude/agents-available/plan-executor.md +0 -133
  225. package/templates/.claude/agents-available/strategic-planner.md +0 -141
  226. package/templates/.claude/agents-available/test-gap-finder.md +0 -67
  227. package/templates/.claude/agents-available/test-writer.md +0 -34
  228. package/templates/.claude/agents-available/vulnerability-scanner.md +0 -173
  229. package/templates/.claude/commands/ask.md +0 -7
  230. package/templates/.claude/commands/build-feature.md +0 -26
  231. package/templates/.claude/commands/build.md.template +0 -30
  232. package/templates/.claude/commands/check.md.template +0 -43
  233. package/templates/.claude/commands/dashboard.md +0 -28
  234. package/templates/.claude/commands/deps.md +0 -15
  235. package/templates/.claude/commands/dev-report.md +0 -50
  236. package/templates/.claude/commands/docs.md +0 -21
  237. package/templates/.claude/commands/doctor.md +0 -21
  238. package/templates/.claude/commands/enable-agent.md +0 -12
  239. package/templates/.claude/commands/execute-plan.md +0 -25
  240. package/templates/.claude/commands/explore-codebase.md +0 -12
  241. package/templates/.claude/commands/export-pdf.md +0 -30
  242. package/templates/.claude/commands/feature.md +0 -25
  243. package/templates/.claude/commands/fix-issue.md +0 -12
  244. package/templates/.claude/commands/fix.md.template +0 -32
  245. package/templates/.claude/commands/health.md +0 -58
  246. package/templates/.claude/commands/help.md +0 -36
  247. package/templates/.claude/commands/learn.md +0 -48
  248. package/templates/.claude/commands/onboarding.md +0 -21
  249. package/templates/.claude/commands/plan.md +0 -20
  250. package/templates/.claude/commands/quality.md.template +0 -65
  251. package/templates/.claude/commands/session-end.md +0 -40
  252. package/templates/.claude/commands/session-start.md +0 -30
  253. package/templates/.claude/commands/setup-hooks.md +0 -18
  254. package/templates/.claude/commands/setup-pr-review.md +0 -72
  255. package/templates/.claude/commands/stealth-mode.md +0 -17
  256. package/templates/.claude/commands/test-gaps.md +0 -49
  257. package/templates/.claude/commands/test.md.template +0 -40
  258. package/templates/.claude/commands/vulnerabilities.md +0 -49
  259. package/templates/.claude/skills/build/SKILL.md.template +0 -98
  260. package/templates/.claude/skills/deploy/SKILL.md.template +0 -131
  261. package/templates/.claude/skills/deploy/references/gotchas.md +0 -5
  262. package/templates/.claude/skills/doctor/SKILL.md +0 -54
  263. package/templates/.claude/skills/gcloud/SKILL.md +0 -66
  264. package/templates/.claude/skills/gcloud/references/gotchas.md +0 -5
  265. package/templates/.claude/skills/learned/SKILL.md +0 -55
  266. package/templates/.claude/skills/learned/references/conventions.md +0 -11
  267. package/templates/.claude/skills/learned/references/deny-recommendations.md +0 -18
  268. package/templates/.claude/skills/learned/references/gotchas.md +0 -11
  269. package/templates/.claude/skills/pulumi/SKILL.md +0 -73
  270. package/templates/.claude/skills/quality/SKILL.md.template +0 -108
  271. package/templates/.claude/skills/quality/references/gotchas.md +0 -5
  272. package/templates/.claude/skills/review/SKILL.md.template +0 -73
  273. package/templates/.claude/skills/scaffold/SKILL.md.template +0 -123
  274. package/templates/.claude/skills/secrets/SKILL.md +0 -52
  275. package/templates/.claude/skills/session/SKILL.md +0 -43
  276. package/templates/.claude/skills/test/SKILL.md.template +0 -122
  277. package/templates/.claude/skills/test/references/gotchas.md +0 -5
  278. package/templates/.devcontainer/Dockerfile.dev.template +0 -89
  279. package/templates/.devcontainer/devcontainer.json.template +0 -184
  280. package/templates/.devcontainer/docker-compose.yml.template +0 -105
  281. package/templates/.devcontainer/init-scripts/01-init.sql.template +0 -12
  282. package/templates/.devcontainer/post-create.sh.template +0 -298
  283. package/templates/.github/workflows/ci.yml.template +0 -399
  284. package/templates/.github/workflows/quality.yml.template +0 -376
  285. package/templates/.pre-commit-config.yaml.template +0 -106
  286. package/templates/.project/config/edit_config.py +0 -275
  287. package/templates/.project/config/project_config.py +0 -894
  288. package/templates/.project/scripts/codegen/generate-all.sh +0 -20
  289. package/templates/.project/scripts/codegen/validate-all.sh +0 -17
  290. package/templates/.project/scripts/docs/generate-all.sh +0 -30
  291. package/templates/.project/scripts/docs/serve.sh +0 -20
  292. package/templates/.project/scripts/quality/fix-all.sh +0 -138
  293. package/templates/.project/scripts/quality/lint-go.sh +0 -34
  294. package/templates/.project/scripts/quality/lint-python.sh +0 -54
  295. package/templates/.project/scripts/quality/run-all.sh +0 -497
  296. package/templates/.project/scripts/session/commit.sh +0 -70
  297. package/templates/.project/scripts/session/create-pr.sh +0 -165
  298. package/templates/.project/scripts/session/end.sh +0 -207
  299. package/templates/.project/scripts/session/start.sh +0 -233
  300. package/templates/.project/scripts/setup/doctor.sh +0 -404
  301. package/templates/.project/scripts/setup/interactive-setup.sh +0 -585
  302. package/templates/.project/scripts/sync/sync-template.sh +0 -328
  303. package/templates/.project/scripts/test/run-all.sh +0 -179
  304. package/templates/.project/scripts/test/run-quick.sh +0 -25
  305. package/templates/Makefile +0 -514
  306. package/templates/config/versions.yaml +0 -57
  307. package/templates/configs/go/.golangci.yml.template +0 -172
  308. package/templates/configs/go/go.mod.template +0 -15
  309. package/templates/configs/java/README.md +0 -6
  310. package/templates/configs/kotlin/README.md +0 -6
  311. package/templates/configs/node/package.json.template +0 -67
  312. package/templates/configs/node/tsconfig.json.template +0 -53
  313. package/templates/configs/python/pyproject.toml.template +0 -92
  314. package/templates/configs/python/pytest.ini.template +0 -64
  315. package/templates/configs/python/ruff.toml.template +0 -79
  316. package/templates/configs/ruby/README.md +0 -6
  317. package/templates/configs/rust/Cargo.toml.template +0 -51
  318. package/templates/configs/shared/.editorconfig +0 -67
  319. package/templates/scripts/validate-templates.sh +0 -449
@@ -0,0 +1,439 @@
1
+ "use strict";
2
+ /**
3
+ * Git-aware match — pairs prior-run identities with current-run
4
+ * identities through the lens of `git diff baseSha headSha`.
5
+ *
6
+ * The line-bucket identity scheme used by code/secret/config/hygiene
7
+ * findings tolerates ±2 lines of vertical drift. Anything past that
8
+ * appears to a naive set-diff as "removed + added" even though
9
+ * semantically the finding hasn't changed — it just moved with the
10
+ * surrounding code. This module closes the gap.
11
+ *
12
+ * Algorithm:
13
+ *
14
+ * 1. Exact identity match — every finding present in both runs
15
+ * under the same fingerprint is `persisted` immediately.
16
+ *
17
+ * 2. For each finding in the `removed` set that carries a file +
18
+ * line locator: ask git to map its base-line through the diff
19
+ * to the corresponding head-line. If the `added` set contains
20
+ * a finding at the same `(file, rule, mappedLine)`, the two
21
+ * represent the same underlying issue moved by the diff —
22
+ * move both to `persisted`.
23
+ *
24
+ * 3. Whatever remains in `added` and `removed` is genuinely new
25
+ * or genuinely gone.
26
+ *
27
+ * Fallback: when git history is unavailable (no `.git`, baseSha not
28
+ * reachable, file deleted, etc.) the module degrades to plain
29
+ * set-diff matching — the same behavior `matchAcrossRuns` produces
30
+ * on its own. Callers in shallow-clone CI or non-git workflows get
31
+ * a working (if less precise) result.
32
+ *
33
+ * Known limitations (Sprint 0 v1):
34
+ * - File renames are not auto-tracked. A renamed file looks like
35
+ * "removed prior + added current"; future iterations will use
36
+ * `git log --follow` or `git diff -M` rename detection to close
37
+ * this gap.
38
+ * - Cross-file refactors (function extracted to a new file) are
39
+ * reported as removed-and-added.
40
+ * - When the line-bucket mapping fails on context edits (tool
41
+ * reports finding at a slightly different line in head than the
42
+ * diff predicts), we fall back to "unmatched." Sprint 0.x adds
43
+ * a content-hash fallback for this class.
44
+ */
45
+ Object.defineProperty(exports, "__esModule", { value: true });
46
+ exports.mapLineThroughDiff = mapLineThroughDiff;
47
+ exports.gitAwareMatch = gitAwareMatch;
48
+ const child_process_1 = require("child_process");
49
+ const finding_identity_1 = require("./finding-identity");
50
+ /** Confidence assigned to a git-mapped pair when the candidate sits
51
+ * on exactly the mapped line. Slightly below 1.0 so consumers can
52
+ * tell apart "exact identity match" (1.0) from "different identity
53
+ * but same finding through diff" (0.95). */
54
+ const CONFIDENCE_GIT_EXACT = 0.95;
55
+ /** Confidence when the candidate sits within ±2 lines of the mapped
56
+ * line — scanners often shift the reported line slightly across
57
+ * re-runs even when nothing semantic changed. */
58
+ const CONFIDENCE_GIT_FUZZ = 0.88;
59
+ /** Range of the line-fuzz lookup window. */
60
+ const LINE_FUZZ_RANGE = 2;
61
+ /** Confidence assigned to a content-hash pair. Below git-line-fuzz
62
+ * so the policy's per-severity confidence thresholds naturally
63
+ * distinguish "matched via git diff" from "matched via context
64
+ * bytes alone." For low-severity findings (default threshold 0.90),
65
+ * a content-hash pair demotes to `'uncertain'`; for critical
66
+ * findings (threshold 0.75), it passes through cleanly. */
67
+ const CONFIDENCE_CONTENT_HASH = 0.8;
68
+ /**
69
+ * Map a 1-based line number in `baseSha`'s version of `file` to its
70
+ * corresponding 1-based line in `headSha`. Returns `null` when the
71
+ * line was deleted, the file was removed, or git couldn't produce a
72
+ * diff for any reason.
73
+ *
74
+ * Implementation runs `git diff --unified=0 baseSha headSha -- file`
75
+ * and walks the resulting `@@ -A,B +C,D @@` hunks. Pure-ish: the
76
+ * only impurity is the git subprocess; the parser is deterministic
77
+ * over its input.
78
+ */
79
+ function mapLineThroughDiff(opts) {
80
+ const oldFile = opts.oldFile ?? opts.file;
81
+ const newFile = opts.newFile ?? opts.file ?? oldFile;
82
+ if (!oldFile || !newFile) {
83
+ throw new Error('mapLineThroughDiff requires `file` or both `oldFile` + `newFile`');
84
+ }
85
+ let diff;
86
+ try {
87
+ diff = (0, child_process_1.execFileSync)('git', [
88
+ 'diff',
89
+ '--unified=0',
90
+ '--no-color',
91
+ '--find-renames',
92
+ opts.baseSha,
93
+ opts.headSha,
94
+ '--',
95
+ oldFile,
96
+ ...(newFile !== oldFile ? [newFile] : []),
97
+ ], { cwd: opts.cwd, encoding: 'utf8' });
98
+ }
99
+ catch {
100
+ // File missing in one revision, git not available, sha unreachable — any
101
+ // of these defeats the mapping. Caller treats null as "unmatched."
102
+ return null;
103
+ }
104
+ if (!diff.trim()) {
105
+ // Identical between revisions: line numbers are 1:1.
106
+ return opts.baseLine;
107
+ }
108
+ return walkHunks(diff, opts.baseLine);
109
+ }
110
+ /**
111
+ * Parse `@@ -oldStart,oldCount +newStart,newCount @@` hunk headers
112
+ * and resolve `baseLine` to its post-diff line number. Pure
113
+ * function over the diff text.
114
+ *
115
+ * A line falls into one of three regions:
116
+ * - Before any hunk that affects it: shifted only by the
117
+ * accumulated net delta of earlier hunks.
118
+ * - Inside a hunk's deletion span: removed by this diff,
119
+ * returns null.
120
+ * - After all hunks: shifted by the full accumulated net delta.
121
+ */
122
+ function walkHunks(diff, baseLine) {
123
+ const hunkRe = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/gm;
124
+ let match;
125
+ let cumulativeShift = 0;
126
+ while ((match = hunkRe.exec(diff)) !== null) {
127
+ const oldStart = parseInt(match[1], 10);
128
+ const oldCount = match[2] !== undefined ? parseInt(match[2], 10) : 1;
129
+ const newCount = match[4] !== undefined ? parseInt(match[4], 10) : 1;
130
+ const oldEnd = oldStart + oldCount - 1;
131
+ if (baseLine < oldStart) {
132
+ // Line lies before this hunk — earlier shifts apply, this hunk doesn't.
133
+ return baseLine + cumulativeShift;
134
+ }
135
+ if (oldCount > 0 && baseLine >= oldStart && baseLine <= oldEnd) {
136
+ // Line was deleted by this hunk.
137
+ return null;
138
+ }
139
+ cumulativeShift += newCount - oldCount;
140
+ }
141
+ return baseLine + cumulativeShift;
142
+ }
143
+ /**
144
+ * Composite matcher. Three passes, decreasing in match strength:
145
+ *
146
+ * 1. Location-aware pairing (when git is available): for each
147
+ * line-anchored prior finding, map its base line to the
148
+ * corresponding head line via `git diff`, then look up a
149
+ * current finding at `(effectivePath, rule, mappedLine)`. The
150
+ * effective path is the prior path translated through the
151
+ * rename map; status is `'relocated'` when the path changed,
152
+ * `'persisted'` when it didn't.
153
+ * Lookups try the exact mapped line first (confidence 0.95),
154
+ * then a ±2 fuzz window (confidence 0.88).
155
+ *
156
+ * 1.5. Content-hash pairing (when both sides carry content
157
+ * hashes): match prior+current by `(canonicalRule,
158
+ * contentHash)`. Runs regardless of git reachability — the
159
+ * hash is file-content-derived and doesn't need git. Catches
160
+ * cases git can't (shallow clone, force-pushed baseline) and
161
+ * cases git misses (line-bucket boundary shifts where the
162
+ * surrounding context survived intact). Confidence 0.80 — the
163
+ * policy's per-severity thresholds naturally tune whether to
164
+ * trust this layer.
165
+ *
166
+ * 2. Multiset exact-identity diff over whatever remains. Catches:
167
+ * - findings without a file-line locator (dep-vuln, license,
168
+ * symbol-based coverage-gap, duplication)
169
+ * - line-anchored findings whose locations didn't survive
170
+ * the diff but whose fingerprints happen to coincide
171
+ * across runs
172
+ * - everything when git history is unreachable (`baseSha`
173
+ * missing) and pass 1 was skipped
174
+ *
175
+ * Why location-first: the line-bucket fingerprint scheme can produce
176
+ * spurious "persisted" matches when two findings of the same rule
177
+ * in the same file naturally shift into each other's buckets. Pass 1
178
+ * pairs them by real diff position, which is what a developer
179
+ * intuitively expects. Pass 1.5 catches the cases where pass 1 isn't
180
+ * available; pass 2 handles content-independent identity kinds.
181
+ */
182
+ function gitAwareMatch(prior, current, opts) {
183
+ const headSha = opts.headSha ?? 'HEAD';
184
+ const reachability = checkShaReachable(opts.cwd, opts.baseSha);
185
+ const pairs = [];
186
+ const priorMatched = new Set();
187
+ const currentMatched = new Set();
188
+ if (reachability.ok) {
189
+ const renames = readRenameMap(opts.cwd, opts.baseSha, headSha);
190
+ // Index current findings by (file, rule, line). One key holds at
191
+ // most one entry — the multiset diff in pass 2 picks up any
192
+ // collisions left after location pairing.
193
+ const currentByLocation = new Map();
194
+ for (const c of current) {
195
+ if (!c.file || c.line === undefined || !c.rule)
196
+ continue;
197
+ const key = locationKey(c.file, c.rule, c.line);
198
+ const bucket = currentByLocation.get(key);
199
+ if (bucket)
200
+ bucket.push(c);
201
+ else
202
+ currentByLocation.set(key, [c]);
203
+ }
204
+ const takeAt = (key) => {
205
+ const bucket = currentByLocation.get(key);
206
+ if (!bucket || bucket.length === 0)
207
+ return undefined;
208
+ const head = bucket.shift();
209
+ if (bucket.length === 0)
210
+ currentByLocation.delete(key);
211
+ return head;
212
+ };
213
+ for (const p of prior) {
214
+ if (!p.file || p.line === undefined || !p.rule)
215
+ continue;
216
+ const effectivePath = renames.get(p.file) ?? p.file;
217
+ const pathChanged = effectivePath !== p.file;
218
+ const mappedLine = mapLineThroughDiff({
219
+ cwd: opts.cwd,
220
+ baseSha: opts.baseSha,
221
+ headSha,
222
+ oldFile: p.file,
223
+ newFile: effectivePath,
224
+ baseLine: p.line,
225
+ });
226
+ if (mappedLine === null)
227
+ continue;
228
+ // Exact mapped line first.
229
+ let candidate = takeAt(locationKey(effectivePath, p.rule, mappedLine));
230
+ let confidence = CONFIDENCE_GIT_EXACT;
231
+ let fuzzDelta = 0;
232
+ // Line-fuzz fallback: scanners drift the reported line by 1-2
233
+ // lines on re-runs. Walk outward from the mapped line.
234
+ if (!candidate) {
235
+ for (let delta = 1; delta <= LINE_FUZZ_RANGE; delta++) {
236
+ for (const offset of [-delta, delta]) {
237
+ const c2 = takeAt(locationKey(effectivePath, p.rule, mappedLine + offset));
238
+ if (c2) {
239
+ candidate = c2;
240
+ confidence = CONFIDENCE_GIT_FUZZ;
241
+ fuzzDelta = offset;
242
+ break;
243
+ }
244
+ }
245
+ if (candidate)
246
+ break;
247
+ }
248
+ }
249
+ if (!candidate)
250
+ continue;
251
+ priorMatched.add(p);
252
+ currentMatched.add(candidate);
253
+ const reasons = [
254
+ {
255
+ code: 'git-line-' + (fuzzDelta === 0 ? 'exact' : 'fuzz'),
256
+ detail: fuzzDelta === 0
257
+ ? `git diff mapped ${p.file}:${p.line} to ${effectivePath}:${mappedLine}`
258
+ : `git diff mapped ${p.file}:${p.line} to ${effectivePath}:${mappedLine}; ` +
259
+ `current finding sits ${fuzzDelta > 0 ? '+' : ''}${fuzzDelta} line(s) off (within fuzz window)`,
260
+ },
261
+ ];
262
+ if (pathChanged) {
263
+ reasons.unshift({
264
+ code: 'git-rename',
265
+ detail: `file renamed: ${p.file} → ${effectivePath}`,
266
+ });
267
+ }
268
+ pairs.push({
269
+ priorId: p.id,
270
+ currentId: candidate.id,
271
+ status: pathChanged ? 'relocated' : 'persisted',
272
+ confidence,
273
+ reasons,
274
+ });
275
+ }
276
+ }
277
+ // Pass 1.5 — content-hash fallback. Pairs prior+current findings
278
+ // by `(canonicalRule, contentHash)` when both sides carry a
279
+ // content hash (stamped by the producer). Runs regardless of git
280
+ // reachability — content hashes are file-content-derived and
281
+ // don't need git to compare. Confidence is below the git-line
282
+ // tier so the policy classifier's per-severity thresholds tune
283
+ // whether to trust the match.
284
+ {
285
+ const currentByContent = new Map();
286
+ for (const c of current) {
287
+ if (currentMatched.has(c))
288
+ continue;
289
+ if (!c.contentHash || !c.rule)
290
+ continue;
291
+ const key = contentKey(c.rule, c.contentHash);
292
+ const bucket = currentByContent.get(key);
293
+ if (bucket)
294
+ bucket.push(c);
295
+ else
296
+ currentByContent.set(key, [c]);
297
+ }
298
+ const takeContent = (key) => {
299
+ const bucket = currentByContent.get(key);
300
+ if (!bucket || bucket.length === 0)
301
+ return undefined;
302
+ const head = bucket.shift();
303
+ if (bucket.length === 0)
304
+ currentByContent.delete(key);
305
+ return head;
306
+ };
307
+ for (const p of prior) {
308
+ if (priorMatched.has(p))
309
+ continue;
310
+ if (!p.contentHash || !p.rule)
311
+ continue;
312
+ const candidate = takeContent(contentKey(p.rule, p.contentHash));
313
+ if (!candidate)
314
+ continue;
315
+ priorMatched.add(p);
316
+ currentMatched.add(candidate);
317
+ const pathChanged = !!(p.file && candidate.file && p.file !== candidate.file);
318
+ pairs.push({
319
+ priorId: p.id,
320
+ currentId: candidate.id,
321
+ status: pathChanged ? 'relocated' : 'persisted',
322
+ confidence: CONFIDENCE_CONTENT_HASH,
323
+ reasons: [
324
+ {
325
+ code: 'content-hash',
326
+ detail: pathChanged
327
+ ? `content-hash match across rename: ${p.file ?? '?'} → ${candidate.file ?? '?'}`
328
+ : 'content-hash match (surrounding code byte-identical after whitespace normalization)',
329
+ },
330
+ ],
331
+ });
332
+ }
333
+ }
334
+ // Pass 2 — multiset exact-id diff over leftovers.
335
+ const priorRemaining = [];
336
+ const currentRemaining = [];
337
+ for (const p of prior)
338
+ if (!priorMatched.has(p))
339
+ priorRemaining.push(p.id);
340
+ for (const c of current)
341
+ if (!currentMatched.has(c))
342
+ currentRemaining.push(c.id);
343
+ const exactRemaining = (0, finding_identity_1.matchAcrossRuns)(priorRemaining, currentRemaining);
344
+ for (const pair of exactRemaining.pairs)
345
+ pairs.push(pair);
346
+ // Flatten the legacy views from the pair list.
347
+ const persisted = [];
348
+ const added = [];
349
+ const removed = [];
350
+ for (const pair of pairs) {
351
+ switch (pair.status) {
352
+ case 'persisted':
353
+ case 'relocated':
354
+ if (pair.priorId)
355
+ persisted.push(pair.priorId);
356
+ if (pair.currentId && pair.currentId !== pair.priorId)
357
+ persisted.push(pair.currentId);
358
+ break;
359
+ case 'added':
360
+ if (pair.currentId)
361
+ added.push(pair.currentId);
362
+ break;
363
+ case 'removed':
364
+ if (pair.priorId)
365
+ removed.push(pair.priorId);
366
+ break;
367
+ }
368
+ }
369
+ return {
370
+ pairs,
371
+ persisted,
372
+ added,
373
+ removed,
374
+ gitAware: reachability.ok,
375
+ degradedReason: reachability.ok ? undefined : reachability.reason,
376
+ };
377
+ }
378
+ function locationKey(file, rule, line) {
379
+ return `${file}\0${rule}\0${line}`;
380
+ }
381
+ function contentKey(rule, contentHash) {
382
+ return `content\0${rule}\0${contentHash}`;
383
+ }
384
+ /**
385
+ * Build a Map<oldPath, newPath> for files renamed between baseSha
386
+ * and headSha. Uses git's rename detection (`--find-renames`,
387
+ * default similarity threshold). Files that weren't renamed don't
388
+ * appear in the map; callers fall back to using the prior path as
389
+ * the effective path.
390
+ */
391
+ function readRenameMap(cwd, baseSha, headSha) {
392
+ const renames = new Map();
393
+ let output;
394
+ try {
395
+ output = (0, child_process_1.execFileSync)('git', ['diff', '--name-status', '--find-renames', baseSha, headSha], {
396
+ cwd,
397
+ encoding: 'utf8',
398
+ });
399
+ }
400
+ catch {
401
+ return renames;
402
+ }
403
+ for (const line of output.split('\n')) {
404
+ // Rename lines look like: R100\told/path\tnew/path
405
+ // M / A / D / C lines have only one path column and are ignored here.
406
+ if (!line.startsWith('R'))
407
+ continue;
408
+ const parts = line.split('\t');
409
+ if (parts.length < 3)
410
+ continue;
411
+ renames.set(parts[1], parts[2]);
412
+ }
413
+ return renames;
414
+ }
415
+ /**
416
+ * Check whether the SHA exists in the repo and return a structured
417
+ * verdict. Distinguishes "not a git repo," "git not installed,"
418
+ * "valid repo but commit unreachable" — every non-ok case produces
419
+ * a human-readable reason for `MatchResult.degradedReason`.
420
+ */
421
+ function checkShaReachable(cwd, sha) {
422
+ try {
423
+ (0, child_process_1.execFileSync)('git', ['rev-parse', '--git-dir'], { cwd, stdio: 'ignore' });
424
+ }
425
+ catch {
426
+ return { ok: false, reason: 'cwd is not a git repository (or git is not installed)' };
427
+ }
428
+ try {
429
+ (0, child_process_1.execFileSync)('git', ['cat-file', '-e', sha], { cwd, stdio: 'ignore' });
430
+ return { ok: true };
431
+ }
432
+ catch {
433
+ return {
434
+ ok: false,
435
+ reason: `baseline commit ${sha} is not reachable in this checkout (shallow clone or force-push?)`,
436
+ };
437
+ }
438
+ }
439
+ //# sourceMappingURL=git-aware-match.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-aware-match.js","sourceRoot":"","sources":["../../src/baseline/git-aware-match.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;;AAwEH,gDAgDC;AA4ED,sCAwLC;AA1XD,iDAA6C;AAC7C,yDAAqD;AAGrD;;;6CAG6C;AAC7C,MAAM,oBAAoB,GAAG,IAAI,CAAC;AAClC;;kDAEkD;AAClD,MAAM,mBAAmB,GAAG,IAAI,CAAC;AACjC,4CAA4C;AAC5C,MAAM,eAAe,GAAG,CAAC,CAAC;AAC1B;;;;;4DAK4D;AAC5D,MAAM,uBAAuB,GAAG,GAAG,CAAC;AAsCpC;;;;;;;;;;GAUG;AACH,SAAgB,kBAAkB,CAAC,IAelC;IACC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC;IAC1C,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,IAAI,IAAI,OAAO,CAAC;IACrD,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,kEAAkE,CAAC,CAAC;IACtF,CAAC;IACD,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QACH,IAAI,GAAG,IAAA,4BAAY,EACjB,KAAK,EACL;YACE,MAAM;YACN,aAAa;YACb,YAAY;YACZ,gBAAgB;YAChB,IAAI,CAAC,OAAO;YACZ,IAAI,CAAC,OAAO;YACZ,IAAI;YACJ,OAAO;YACP,GAAG,CAAC,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;SAC1C,EACD,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,CACpC,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,yEAAyE;QACzE,mEAAmE;QACnE,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;QACjB,qDAAqD;QACrD,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IACD,OAAO,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;AACxC,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAS,SAAS,CAAC,IAAY,EAAE,QAAgB;IAC/C,MAAM,MAAM,GAAG,+CAA+C,CAAC;IAC/D,IAAI,KAA6B,CAAC;IAClC,IAAI,eAAe,GAAG,CAAC,CAAC;IACxB,OAAO,CAAC,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAC5C,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACxC,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACrE,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACrE,MAAM,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,CAAC,CAAC;QAEvC,IAAI,QAAQ,GAAG,QAAQ,EAAE,CAAC;YACxB,wEAAwE;YACxE,OAAO,QAAQ,GAAG,eAAe,CAAC;QACpC,CAAC;QACD,IAAI,QAAQ,GAAG,CAAC,IAAI,QAAQ,IAAI,QAAQ,IAAI,QAAQ,IAAI,MAAM,EAAE,CAAC;YAC/D,iCAAiC;YACjC,OAAO,IAAI,CAAC;QACd,CAAC;QACD,eAAe,IAAI,QAAQ,GAAG,QAAQ,CAAC;IACzC,CAAC;IACD,OAAO,QAAQ,GAAG,eAAe,CAAC;AACpC,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,SAAgB,aAAa,CAC3B,KAAqC,EACrC,OAAuC,EACvC,IAA0B;IAE1B,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,MAAM,CAAC;IACvC,MAAM,YAAY,GAAG,iBAAiB,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IAE/D,MAAM,KAAK,GAAgB,EAAE,CAAC;IAC9B,MAAM,YAAY,GAAG,IAAI,GAAG,EAAmB,CAAC;IAChD,MAAM,cAAc,GAAG,IAAI,GAAG,EAAmB,CAAC;IAElD,IAAI,YAAY,CAAC,EAAE,EAAE,CAAC;QACpB,MAAM,OAAO,GAAG,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAE/D,iEAAiE;QACjE,4DAA4D;QAC5D,0CAA0C;QAC1C,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAA6B,CAAC;QAC/D,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACxB,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS,IAAI,CAAC,CAAC,CAAC,IAAI;gBAAE,SAAS;YACzD,MAAM,GAAG,GAAG,WAAW,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;YAChD,MAAM,MAAM,GAAG,iBAAiB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC1C,IAAI,MAAM;gBAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;;gBACtB,iBAAiB,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACvC,CAAC;QAED,MAAM,MAAM,GAAG,CAAC,GAAW,EAA+B,EAAE;YAC1D,MAAM,MAAM,GAAG,iBAAiB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC1C,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,SAAS,CAAC;YACrD,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,EAAE,CAAC;YAC5B,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;gBAAE,iBAAiB,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACvD,OAAO,IAAI,CAAC;QACd,CAAC,CAAC;QAEF,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;YACtB,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS,IAAI,CAAC,CAAC,CAAC,IAAI;gBAAE,SAAS;YACzD,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC;YACpD,MAAM,WAAW,GAAG,aAAa,KAAK,CAAC,CAAC,IAAI,CAAC;YAC7C,MAAM,UAAU,GAAG,kBAAkB,CAAC;gBACpC,GAAG,EAAE,IAAI,CAAC,GAAG;gBACb,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,OAAO;gBACP,OAAO,EAAE,CAAC,CAAC,IAAI;gBACf,OAAO,EAAE,aAAa;gBACtB,QAAQ,EAAE,CAAC,CAAC,IAAI;aACjB,CAAC,CAAC;YACH,IAAI,UAAU,KAAK,IAAI;gBAAE,SAAS;YAElC,2BAA2B;YAC3B,IAAI,SAAS,GAAG,MAAM,CAAC,WAAW,CAAC,aAAa,EAAE,CAAC,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC;YACvE,IAAI,UAAU,GAAG,oBAAoB,CAAC;YACtC,IAAI,SAAS,GAAG,CAAC,CAAC;YAClB,8DAA8D;YAC9D,uDAAuD;YACvD,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,IAAI,eAAe,EAAE,KAAK,EAAE,EAAE,CAAC;oBACtD,KAAK,MAAM,MAAM,IAAI,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC;wBACrC,MAAM,EAAE,GAAG,MAAM,CAAC,WAAW,CAAC,aAAa,EAAE,CAAC,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAAC,CAAC,CAAC;wBAC3E,IAAI,EAAE,EAAE,CAAC;4BACP,SAAS,GAAG,EAAE,CAAC;4BACf,UAAU,GAAG,mBAAmB,CAAC;4BACjC,SAAS,GAAG,MAAM,CAAC;4BACnB,MAAM;wBACR,CAAC;oBACH,CAAC;oBACD,IAAI,SAAS;wBAAE,MAAM;gBACvB,CAAC;YACH,CAAC;YACD,IAAI,CAAC,SAAS;gBAAE,SAAS;YAEzB,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YACpB,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YAC9B,MAAM,OAAO,GAAkB;gBAC7B;oBACE,IAAI,EAAE,WAAW,GAAG,CAAC,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;oBACxD,MAAM,EACJ,SAAS,KAAK,CAAC;wBACb,CAAC,CAAC,mBAAmB,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,OAAO,aAAa,IAAI,UAAU,EAAE;wBACzE,CAAC,CAAC,mBAAmB,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,OAAO,aAAa,IAAI,UAAU,IAAI;4BACzE,wBAAwB,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,SAAS,mCAAmC;iBACtG;aACF,CAAC;YACF,IAAI,WAAW,EAAE,CAAC;gBAChB,OAAO,CAAC,OAAO,CAAC;oBACd,IAAI,EAAE,YAAY;oBAClB,MAAM,EAAE,iBAAiB,CAAC,CAAC,IAAI,MAAM,aAAa,EAAE;iBACrD,CAAC,CAAC;YACL,CAAC;YACD,KAAK,CAAC,IAAI,CAAC;gBACT,OAAO,EAAE,CAAC,CAAC,EAAE;gBACb,SAAS,EAAE,SAAS,CAAC,EAAE;gBACvB,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW;gBAC/C,UAAU;gBACV,OAAO;aACR,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,iEAAiE;IACjE,4DAA4D;IAC5D,iEAAiE;IACjE,6DAA6D;IAC7D,8DAA8D;IAC9D,+DAA+D;IAC/D,8BAA8B;IAC9B,CAAC;QACC,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAA6B,CAAC;QAC9D,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACxB,IAAI,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC;gBAAE,SAAS;YACpC,IAAI,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC,IAAI;gBAAE,SAAS;YACxC,MAAM,GAAG,GAAG,UAAU,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC;YAC9C,MAAM,MAAM,GAAG,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACzC,IAAI,MAAM;gBAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;;gBACtB,gBAAgB,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACtC,CAAC;QACD,MAAM,WAAW,GAAG,CAAC,GAAW,EAA+B,EAAE;YAC/D,MAAM,MAAM,GAAG,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACzC,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,SAAS,CAAC;YACrD,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,EAAE,CAAC;YAC5B,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;gBAAE,gBAAgB,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACtD,OAAO,IAAI,CAAC;QACd,CAAC,CAAC;QACF,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;YACtB,IAAI,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC;gBAAE,SAAS;YAClC,IAAI,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC,IAAI;gBAAE,SAAS;YACxC,MAAM,SAAS,GAAG,WAAW,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;YACjE,IAAI,CAAC,SAAS;gBAAE,SAAS;YACzB,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YACpB,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YAC9B,MAAM,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,SAAS,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,IAAI,CAAC,CAAC;YAC9E,KAAK,CAAC,IAAI,CAAC;gBACT,OAAO,EAAE,CAAC,CAAC,EAAE;gBACb,SAAS,EAAE,SAAS,CAAC,EAAE;gBACvB,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW;gBAC/C,UAAU,EAAE,uBAAuB;gBACnC,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,cAAc;wBACpB,MAAM,EAAE,WAAW;4BACjB,CAAC,CAAC,qCAAqC,CAAC,CAAC,IAAI,IAAI,GAAG,MAAM,SAAS,CAAC,IAAI,IAAI,GAAG,EAAE;4BACjF,CAAC,CAAC,qFAAqF;qBAC1F;iBACF;aACF,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,kDAAkD;IAClD,MAAM,cAAc,GAAgB,EAAE,CAAC;IACvC,MAAM,gBAAgB,GAAgB,EAAE,CAAC;IACzC,KAAK,MAAM,CAAC,IAAI,KAAK;QAAE,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC;YAAE,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAC3E,KAAK,MAAM,CAAC,IAAI,OAAO;QAAE,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC;YAAE,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACjF,MAAM,cAAc,GAAG,IAAA,kCAAe,EAAC,cAAc,EAAE,gBAAgB,CAAC,CAAC;IACzE,KAAK,MAAM,IAAI,IAAI,cAAc,CAAC,KAAK;QAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAE1D,+CAA+C;IAC/C,MAAM,SAAS,GAAgB,EAAE,CAAC;IAClC,MAAM,KAAK,GAAgB,EAAE,CAAC;IAC9B,MAAM,OAAO,GAAgB,EAAE,CAAC;IAChC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC;YACpB,KAAK,WAAW,CAAC;YACjB,KAAK,WAAW;gBACd,IAAI,IAAI,CAAC,OAAO;oBAAE,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBAC/C,IAAI,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,SAAS,KAAK,IAAI,CAAC,OAAO;oBAAE,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gBACtF,MAAM;YACR,KAAK,OAAO;gBACV,IAAI,IAAI,CAAC,SAAS;oBAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gBAC/C,MAAM;YACR,KAAK,SAAS;gBACZ,IAAI,IAAI,CAAC,OAAO;oBAAE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBAC7C,MAAM;QACV,CAAC;IACH,CAAC;IAED,OAAO;QACL,KAAK;QACL,SAAS;QACT,KAAK;QACL,OAAO;QACP,QAAQ,EAAE,YAAY,CAAC,EAAE;QACzB,cAAc,EAAE,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM;KAClE,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,IAAY,EAAE,IAAY,EAAE,IAAY;IAC3D,OAAO,GAAG,IAAI,KAAK,IAAI,KAAK,IAAI,EAAE,CAAC;AACrC,CAAC;AAED,SAAS,UAAU,CAAC,IAAY,EAAE,WAAmB;IACnD,OAAO,YAAY,IAAI,KAAK,WAAW,EAAE,CAAC;AAC5C,CAAC;AAED;;;;;;GAMG;AACH,SAAS,aAAa,CAAC,GAAW,EAAE,OAAe,EAAE,OAAe;IAClE,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC1C,IAAI,MAAc,CAAC;IACnB,IAAI,CAAC;QACH,MAAM,GAAG,IAAA,4BAAY,EAAC,KAAK,EAAE,CAAC,MAAM,EAAE,eAAe,EAAE,gBAAgB,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE;YAC1F,GAAG;YACH,QAAQ,EAAE,MAAM;SACjB,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACtC,oDAAoD;QACpD,sEAAsE;QACtE,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS;QACpC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;YAAE,SAAS;QAC/B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;GAKG;AACH,SAAS,iBAAiB,CAAC,GAAW,EAAE,GAAW;IACjD,IAAI,CAAC;QACH,IAAA,4BAAY,EAAC,KAAK,EAAE,CAAC,WAAW,EAAE,WAAW,CAAC,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC5E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,uDAAuD,EAAE,CAAC;IACxF,CAAC;IACD,IAAI,CAAC;QACH,IAAA,4BAAY,EAAC,KAAK,EAAE,CAAC,UAAU,EAAE,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QACvE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;IACtB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;YACL,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,mBAAmB,GAAG,mEAAmE;SAClG,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1,171 @@
1
+ /**
2
+ * Brownfield policy + status classifier.
3
+ *
4
+ * The matcher in `git-aware-match.ts` emits raw `MatchPair`s with one
5
+ * of four statuses (persisted / relocated / added / removed) plus a
6
+ * confidence score and structured reasons. The guardrail check needs
7
+ * a richer taxonomy — the difference between "developer introduced
8
+ * a new finding" and "a scanner update surfaced a finding that was
9
+ * always there" matters enormously for whether to block a PR.
10
+ *
11
+ * This module is the bridge. It takes a `MatchPair` plus optional
12
+ * context (severity, scanner-version diff, config diff) and a
13
+ * `BrownfieldPolicy`, then emits a `ClassifyResult` carrying the
14
+ * post-policy `FindingStatus`, the block/warn verdict, and the
15
+ * composed reason chain.
16
+ *
17
+ * Pure module — no I/O, deterministic over its inputs.
18
+ *
19
+ * Producer wiring note: today's classifier emits a subset of the full
20
+ * `FindingStatus` taxonomy. Reservations for `probable_existing`,
21
+ * `newly_detected`, and `fixed` are declared in the type space so
22
+ * Phase 3's baseline-metadata work can light them up incrementally
23
+ * without re-shaping consumer code.
24
+ */
25
+ import type { FindingSeverity, FindingStatus, MatchPair, MatchReason } from './types';
26
+ /**
27
+ * Per-finding-kind overrides that escalate specific guardrail rules
28
+ * beyond the generic `block` / `warn` lists. Each rule maps to a
29
+ * common product-level concern; the classifier checks them when the
30
+ * relevant context fields are present.
31
+ */
32
+ export interface BrownfieldBlockRules {
33
+ /** Block any newly-introduced secret regardless of confidence. */
34
+ readonly newSecret?: boolean;
35
+ /** Block any newly-introduced critical security finding. */
36
+ readonly newCriticalSecurity?: boolean;
37
+ /** Block any newly-introduced high-severity security finding. */
38
+ readonly newHighSecurity?: boolean;
39
+ /** Block any newly-introduced critical dependency vulnerability. */
40
+ readonly newCriticalDependencyVulnerability?: boolean;
41
+ /** Block any newly-introduced high-severity reachable dep vuln. */
42
+ readonly newHighReachableDependencyVulnerability?: boolean;
43
+ /** Block when an untested source file is added in a changed file. */
44
+ readonly newUntestedChangedSource?: boolean;
45
+ /** Block any newly-introduced severe quality issue in changed files. */
46
+ readonly newSevereQualityIssueInChangedFiles?: boolean;
47
+ }
48
+ /**
49
+ * Brownfield-mode policy. The product promise — "existing debt is
50
+ * allowed; new regressions are blocked" — flows from these settings.
51
+ */
52
+ export interface BrownfieldPolicy {
53
+ readonly mode: 'brownfield';
54
+ /** Statuses that fail the guardrail check (non-zero exit code). */
55
+ readonly block: ReadonlyArray<FindingStatus>;
56
+ /** Statuses that emit a warning but don't fail. */
57
+ readonly warn: ReadonlyArray<FindingStatus>;
58
+ /**
59
+ * Per-severity confidence thresholds. A `relocated` or `persisted`
60
+ * match with confidence below the per-severity threshold demotes
61
+ * to `'uncertain'` — the policy can warn rather than silently
62
+ * accept a low-confidence pairing.
63
+ */
64
+ readonly confidence: Readonly<Record<FindingSeverity, number>>;
65
+ /** Per-kind block-on-new overrides. */
66
+ readonly blockRules: BrownfieldBlockRules;
67
+ /**
68
+ * Finding kinds whose `added` classification only blocks when the
69
+ * finding overlaps lines actually changed in the current diff.
70
+ *
71
+ * Some upstream scanners (notably semgrep on large codebases) are
72
+ * non-deterministic across runs — parallel rule execution + per-
73
+ * rule timeouts mean each run discovers a slightly different
74
+ * subset of the full match space. When the baseline missed a real
75
+ * finding and a later scan catches it on UNCHANGED code, the
76
+ * matcher legitimately reports `added` — but the developer
77
+ * didn't introduce it.
78
+ *
79
+ * For kinds listed here, an `added` finding outside the diff's
80
+ * changed lines gets demoted to `uncertain` (a warn status).
81
+ * Findings inside changed lines still block — that's where the
82
+ * developer actually wrote code.
83
+ *
84
+ * Default: `['code', 'hygiene']` — the kinds with confirmed
85
+ * scanner-wobble risk. Customers can extend (`'duplication'`,
86
+ * `'large-file'`) or clear it (block on everything regardless of
87
+ * diff overlap) via `.dxkit/policy.json`.
88
+ */
89
+ readonly addedRequiresChangedLines: ReadonlyArray<string>;
90
+ }
91
+ /**
92
+ * Default brownfield policy. Captures the conservative posture from
93
+ * the agentic-brownfield strategy: block only on high-confidence new
94
+ * regressions; warn on the categories that suggest a problem might
95
+ * be real but might also be drift; legacy debt is permitted.
96
+ *
97
+ * Confidence thresholds: secrets + critical security demand a tight
98
+ * confidence threshold (a low-confidence persisted secret pairing
99
+ * gets demoted to uncertain and warned, not blocked). Lower-severity
100
+ * findings can pair on weaker signal because the cost of a false
101
+ * "secret is new" event is much higher than a false "TODO is new."
102
+ */
103
+ export declare const DEFAULT_BROWNFIELD_POLICY: BrownfieldPolicy;
104
+ /**
105
+ * Contextual signals the classifier reads when available. Every field
106
+ * is optional — pass `{}` for the basic matcher-only classification.
107
+ * Phase 3 baseline-metadata work will populate these from the stored
108
+ * baseline + current scan envelope.
109
+ */
110
+ export interface ClassifyContext {
111
+ /** Severity of the underlying finding. */
112
+ readonly severity?: FindingSeverity;
113
+ /** Kind discriminator from `IdentityInput`, for block-rule checks. */
114
+ readonly kind?: string;
115
+ /** True when the baseline's scanner / advisory-db version differs
116
+ * from the current scan. Reclassifies an `added` finding as
117
+ * `tooling_drift` rather than blocking it as a new regression. */
118
+ readonly scannerVersionDiffers?: boolean;
119
+ /** True when the baseline's `.dxkit-ignore` / policy hash differs
120
+ * from the current scan. Reclassifies `added` as `config_drift`. */
121
+ readonly configDiffers?: boolean;
122
+ /** True when the underlying source file's lines overlap lines
123
+ * changed by the current diff. Used by `newSevereQualityIssueIn
124
+ * ChangedFiles` and similar rules; absent context is treated as
125
+ * "we don't know, assume outside changed lines." */
126
+ readonly overlapsChangedLines?: boolean;
127
+ /** True when an `added` dep-vuln is on a reachable code path. */
128
+ readonly reachable?: boolean;
129
+ }
130
+ /** Verdict + reasoning for one classified pair. */
131
+ export interface ClassifyResult {
132
+ readonly status: FindingStatus;
133
+ /** Whether the policy blocks based on the classified status or a
134
+ * specific block-rule override. */
135
+ readonly blocks: boolean;
136
+ /** Whether the policy warns. */
137
+ readonly warns: boolean;
138
+ /** Reasons backing the status — composed of the matcher's reasons
139
+ * plus any classification-time additions. */
140
+ readonly reasons: ReadonlyArray<MatchReason>;
141
+ }
142
+ /**
143
+ * Classify one match pair against a brownfield policy.
144
+ *
145
+ * Pipeline:
146
+ * 1. Start with the matcher's `pair.status` as the candidate
147
+ * `FindingStatus`.
148
+ * 2. For `added`: check drift context. Scanner-version drift wins
149
+ * (more specific signal) over config drift; both demote to
150
+ * drift-bucket statuses regardless of severity.
151
+ * 3. For `persisted` / `relocated`: check confidence against the
152
+ * per-severity threshold. Below threshold demotes to
153
+ * `'uncertain'`.
154
+ * 4. Apply block-rule overrides: if a block-rule fires for this
155
+ * kind+severity combination AND the candidate status is
156
+ * `'added'`, the result blocks even if `'added'` weren't in the
157
+ * policy's block list.
158
+ * 5. Apply the policy's `block` / `warn` membership to the final
159
+ * status to produce the booleans.
160
+ */
161
+ export declare function classify(pair: MatchPair, policy?: BrownfieldPolicy, context?: ClassifyContext): ClassifyResult;
162
+ /**
163
+ * Convenience: classify every pair in a match result against the
164
+ * same policy. Returns an array aligned with the input pair order
165
+ * so callers can render side-by-side. Per-pair context (severity,
166
+ * kind, drift flags) is supplied via the optional `contextFor`
167
+ * callback — callers map their `FindingId` back to the producer
168
+ * envelope to fill in the fields the classifier reads.
169
+ */
170
+ export declare function classifyAll(pairs: ReadonlyArray<MatchPair>, policy?: BrownfieldPolicy, contextFor?: (pair: MatchPair) => ClassifyContext): ReadonlyArray<ClassifyResult>;
171
+ //# sourceMappingURL=policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../src/baseline/policy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAEtF;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACnC,kEAAkE;IAClE,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAC7B,4DAA4D;IAC5D,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IACvC,iEAAiE;IACjE,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC;IACnC,oEAAoE;IACpE,QAAQ,CAAC,kCAAkC,CAAC,EAAE,OAAO,CAAC;IACtD,mEAAmE;IACnE,QAAQ,CAAC,uCAAuC,CAAC,EAAE,OAAO,CAAC;IAC3D,qEAAqE;IACrE,QAAQ,CAAC,wBAAwB,CAAC,EAAE,OAAO,CAAC;IAC5C,wEAAwE;IACxE,QAAQ,CAAC,mCAAmC,CAAC,EAAE,OAAO,CAAC;CACxD;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,mEAAmE;IACnE,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,aAAa,CAAC,CAAC;IAC7C,mDAAmD;IACnD,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC,aAAa,CAAC,CAAC;IAC5C;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC,CAAC;IAC/D,uCAAuC;IACvC,QAAQ,CAAC,UAAU,EAAE,oBAAoB,CAAC;IAC1C;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,QAAQ,CAAC,yBAAyB,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CAC3D;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,yBAAyB,EAAE,gBA0BtC,CAAC;AAEH;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,0CAA0C;IAC1C,QAAQ,CAAC,QAAQ,CAAC,EAAE,eAAe,CAAC;IACpC,sEAAsE;IACtE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB;;uEAEmE;IACnE,QAAQ,CAAC,qBAAqB,CAAC,EAAE,OAAO,CAAC;IACzC;yEACqE;IACrE,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC;IACjC;;;yDAGqD;IACrD,QAAQ,CAAC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IACxC,iEAAiE;IACjE,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,mDAAmD;AACnD,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B;wCACoC;IACpC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,gCAAgC;IAChC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB;kDAC8C;IAC9C,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC;CAC9C;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,QAAQ,CACtB,IAAI,EAAE,SAAS,EACf,MAAM,GAAE,gBAA4C,EACpD,OAAO,GAAE,eAAoB,GAC5B,cAAc,CAmEhB;AA0DD;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,aAAa,CAAC,SAAS,CAAC,EAC/B,MAAM,GAAE,gBAA4C,EACpD,UAAU,GAAE,CAAC,IAAI,EAAE,SAAS,KAAK,eAA4B,GAC5D,aAAa,CAAC,cAAc,CAAC,CAE/B"}