@miller-tech/uap 1.222.0 → 2.1.4

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 (234) hide show
  1. package/README.md +19 -9
  2. package/config/exl3-profiles/qwen38-27b-exl3.env +68 -0
  3. package/config/llama-profiles/qwen38-27b-dflash2.env +6 -1
  4. package/dist/.tsbuildinfo +1 -1
  5. package/dist/benchmarks/paired/adapter.d.ts +15 -0
  6. package/dist/benchmarks/paired/adapter.d.ts.map +1 -1
  7. package/dist/benchmarks/paired/adapter.js +22 -1
  8. package/dist/benchmarks/paired/adapter.js.map +1 -1
  9. package/dist/bin/cli.js +20 -24
  10. package/dist/bin/cli.js.map +1 -1
  11. package/dist/cli/deliver.d.ts +34 -0
  12. package/dist/cli/deliver.d.ts.map +1 -1
  13. package/dist/cli/deliver.js +147 -20
  14. package/dist/cli/deliver.js.map +1 -1
  15. package/dist/cli/guided-setup.d.ts.map +1 -1
  16. package/dist/cli/guided-setup.js +15 -0
  17. package/dist/cli/guided-setup.js.map +1 -1
  18. package/dist/cli/init.d.ts.map +1 -1
  19. package/dist/cli/init.js +3 -0
  20. package/dist/cli/init.js.map +1 -1
  21. package/dist/cli/plan.d.ts.map +1 -1
  22. package/dist/cli/plan.js +8 -2
  23. package/dist/cli/plan.js.map +1 -1
  24. package/dist/cli/policy.d.ts.map +1 -1
  25. package/dist/cli/policy.js +104 -2
  26. package/dist/cli/policy.js.map +1 -1
  27. package/dist/cli/quality.d.ts +11 -0
  28. package/dist/cli/quality.d.ts.map +1 -0
  29. package/dist/cli/quality.js +213 -0
  30. package/dist/cli/quality.js.map +1 -0
  31. package/dist/cli/wizard-config.d.ts.map +1 -1
  32. package/dist/cli/wizard-config.js +19 -9
  33. package/dist/cli/wizard-config.js.map +1 -1
  34. package/dist/cli/worktree.d.ts.map +1 -1
  35. package/dist/cli/worktree.js +8 -1
  36. package/dist/cli/worktree.js.map +1 -1
  37. package/dist/dashboard/savings.d.ts +1 -4
  38. package/dist/dashboard/savings.d.ts.map +1 -1
  39. package/dist/dashboard/savings.js +2 -52
  40. package/dist/dashboard/savings.js.map +1 -1
  41. package/dist/delivery/acceptance-judge.d.ts +10 -0
  42. package/dist/delivery/acceptance-judge.d.ts.map +1 -1
  43. package/dist/delivery/acceptance-judge.js +45 -3
  44. package/dist/delivery/acceptance-judge.js.map +1 -1
  45. package/dist/delivery/agentic-executor.d.ts +12 -1
  46. package/dist/delivery/agentic-executor.d.ts.map +1 -1
  47. package/dist/delivery/agentic-executor.js +25 -5
  48. package/dist/delivery/agentic-executor.js.map +1 -1
  49. package/dist/delivery/bash-sweep.d.ts +12 -0
  50. package/dist/delivery/bash-sweep.d.ts.map +1 -1
  51. package/dist/delivery/bash-sweep.js +8 -1
  52. package/dist/delivery/bash-sweep.js.map +1 -1
  53. package/dist/delivery/convergence-loop.d.ts.map +1 -1
  54. package/dist/delivery/convergence-loop.js +6 -4
  55. package/dist/delivery/convergence-loop.js.map +1 -1
  56. package/dist/delivery/execution-gate.d.ts +1 -1
  57. package/dist/delivery/execution-gate.d.ts.map +1 -1
  58. package/dist/delivery/execution-gate.js +248 -5
  59. package/dist/delivery/execution-gate.js.map +1 -1
  60. package/dist/delivery/snapshot.d.ts +16 -0
  61. package/dist/delivery/snapshot.d.ts.map +1 -1
  62. package/dist/delivery/snapshot.js +113 -2
  63. package/dist/delivery/snapshot.js.map +1 -1
  64. package/dist/delivery/user-validation.d.ts.map +1 -1
  65. package/dist/delivery/user-validation.js +55 -10
  66. package/dist/delivery/user-validation.js.map +1 -1
  67. package/dist/delivery/verifier-ladder.d.ts +24 -0
  68. package/dist/delivery/verifier-ladder.d.ts.map +1 -1
  69. package/dist/delivery/verifier-ladder.js +119 -2
  70. package/dist/delivery/verifier-ladder.js.map +1 -1
  71. package/dist/generators/claude-md.js +17 -4
  72. package/dist/generators/claude-md.js.map +1 -1
  73. package/dist/policies/liveness.d.ts +105 -0
  74. package/dist/policies/liveness.d.ts.map +1 -0
  75. package/dist/policies/liveness.js +251 -0
  76. package/dist/policies/liveness.js.map +1 -0
  77. package/dist/policies/policy-memory.d.ts.map +1 -1
  78. package/dist/policies/policy-memory.js +3 -4
  79. package/dist/policies/policy-memory.js.map +1 -1
  80. package/dist/quality/baseline.d.ts +29 -0
  81. package/dist/quality/baseline.d.ts.map +1 -0
  82. package/dist/quality/baseline.js +79 -0
  83. package/dist/quality/baseline.js.map +1 -0
  84. package/dist/quality/complexity.d.ts +38 -0
  85. package/dist/quality/complexity.d.ts.map +1 -0
  86. package/dist/quality/complexity.js +239 -0
  87. package/dist/quality/complexity.js.map +1 -0
  88. package/dist/quality/config.d.ts +40 -0
  89. package/dist/quality/config.d.ts.map +1 -0
  90. package/dist/quality/config.js +77 -0
  91. package/dist/quality/config.js.map +1 -0
  92. package/dist/quality/crap.d.ts +11 -0
  93. package/dist/quality/crap.d.ts.map +1 -0
  94. package/dist/quality/crap.js +54 -0
  95. package/dist/quality/crap.js.map +1 -0
  96. package/dist/quality/languages.d.ts +25 -0
  97. package/dist/quality/languages.d.ts.map +1 -0
  98. package/dist/quality/languages.js +150 -0
  99. package/dist/quality/languages.js.map +1 -0
  100. package/dist/quality/report.d.ts +38 -0
  101. package/dist/quality/report.d.ts.map +1 -0
  102. package/dist/quality/report.js +251 -0
  103. package/dist/quality/report.js.map +1 -0
  104. package/dist/quality/scanner.d.ts +32 -0
  105. package/dist/quality/scanner.d.ts.map +1 -0
  106. package/dist/quality/scanner.js +127 -0
  107. package/dist/quality/scanner.js.map +1 -0
  108. package/dist/quality/tools.d.ts +28 -0
  109. package/dist/quality/tools.d.ts.map +1 -0
  110. package/dist/quality/tools.js +189 -0
  111. package/dist/quality/tools.js.map +1 -0
  112. package/dist/types/config.d.ts +148 -0
  113. package/dist/types/config.d.ts.map +1 -1
  114. package/dist/types/config.js +35 -0
  115. package/dist/types/config.js.map +1 -1
  116. package/docs/ATTRIBUTION.md +0 -1
  117. package/docs/INDEX.md +38 -4
  118. package/docs/analysis/MARKET_POSITION.md +179 -0
  119. package/docs/architecture/OVERVIEW.md +82 -18
  120. package/docs/architecture/PROTOCOL.md +1 -1
  121. package/docs/benchmarks/PAIRED_FINDINGS.md +106 -0
  122. package/docs/benchmarks/PAIRED_HARNESS.md +16 -0
  123. package/docs/benchmarks/README.md +59 -0
  124. package/docs/design/UAP_REACTOR.md +0 -1
  125. package/docs/getting-started/INSTALLATION.md +1 -1
  126. package/docs/guides/AUTOMATIC.md +0 -14
  127. package/docs/guides/AUTOMATIC_FEATURES.md +1 -9
  128. package/docs/guides/COORDINATION.md +1 -1
  129. package/docs/guides/DELIVERY_PIPELINE.md +5 -0
  130. package/docs/guides/DEPLOY_BATCHING.md +1 -1
  131. package/docs/guides/DROIDS_AND_SKILLS.md +1 -1
  132. package/docs/guides/LOCAL_MODELS.md +6 -1
  133. package/docs/guides/MCP_ROUTER.md +1 -1
  134. package/docs/guides/MEMORY.md +1 -1
  135. package/docs/guides/MULTI_MODEL.md +1 -1
  136. package/docs/guides/ORCHESTRATOR.md +1 -1
  137. package/docs/guides/POLICIES.md +19 -3
  138. package/docs/guides/QWEN38_EXL3.md +114 -0
  139. package/docs/guides/WORKTREE_WORKFLOW.md +45 -1
  140. package/docs/integrations/MCP_ROUTER.md +1 -4
  141. package/docs/plans/deliver-hardening-plan-2026-07-13.md +173 -0
  142. package/docs/plans/deliver-hardening-review-response-2026-07-13.md +180 -0
  143. package/docs/plans/k3-uap-uplift-validation.md +216 -0
  144. package/docs/plans/qwen38-uap-retest-plan.md +196 -0
  145. package/docs/reference/API.md +1 -1
  146. package/docs/reference/CLI.md +49 -14
  147. package/docs/reference/COMPARISON.md +248 -0
  148. package/docs/reference/CONFIGURATION.md +1 -3
  149. package/docs/reference/DATABASE_SCHEMA.md +1 -1
  150. package/docs/reference/FEATURES.md +3 -3
  151. package/docs/reference/PATTERNS.md +1 -1
  152. package/docs/reference/PLATFORMS.md +1 -1
  153. package/package.json +2 -2
  154. package/scripts/maintenance/update-skills.py +0 -22
  155. package/scripts/maintenance/verify-compliance.sh +3 -3
  156. package/src/policies/enforcers/__pycache__/_common.cpython-312.pyc +0 -0
  157. package/src/policies/enforcers/__pycache__/quality_metrics_gate.cpython-312.pyc +0 -0
  158. package/src/policies/enforcers/adr_guard.py +0 -0
  159. package/src/policies/enforcers/bearer_lockdown.py +0 -0
  160. package/src/policies/enforcers/branch_freshness.py +0 -0
  161. package/src/policies/enforcers/design_token_gate.py +0 -0
  162. package/src/policies/enforcers/enforcement_self_protect.py +70 -0
  163. package/src/policies/enforcers/expert_review_required.py +22 -0
  164. package/src/policies/enforcers/iac_plan_destruction_check.py +0 -0
  165. package/src/policies/enforcers/quality_metrics_gate.py +447 -0
  166. package/src/policies/enforcers/ship_loop_gate.py +0 -0
  167. package/src/policies/enforcers/validate_plan_on_change.py +0 -0
  168. package/src/policies/enforcers/visual_verification.py +0 -0
  169. package/src/policies/enforcers/workdir_scope.py +0 -0
  170. package/src/policies/schemas/policies/expert-review-required.md +9 -1
  171. package/src/policies/schemas/policies/quality-metrics-gate.md +74 -0
  172. package/templates/CLAUDE.template.md +1 -1
  173. package/templates/hooks/__pycache__/deliver_autoroute.cpython-312.pyc +0 -0
  174. package/templates/hooks/pre-tool-use-bash.sh +50 -3
  175. package/templates/hooks/pre-tool-use-edit-write.sh +31 -0
  176. package/templates/hooks/session-start.sh +15 -0
  177. package/templates/hooks/uap-policy-gate.sh +187 -5
  178. package/templates/stryker.config.json +14 -0
  179. package/tools/agents/scripts/__pycache__/toolcall_path_normalizer.cpython-312.pyc +0 -0
  180. package/tools/agents/scripts/anthropic_proxy.py +254 -28
  181. package/tools/agents/tests/run_acceptance.py +0 -0
  182. package/tools/agents/tests/test_client_disconnect.py +0 -0
  183. package/tools/agents/tests/test_cycle_break_exploration.py +0 -0
  184. package/tools/agents/tests/test_deferral_break.py +0 -0
  185. package/tools/agents/tests/test_delivery_enforcement_all_langs.py +0 -0
  186. package/tools/agents/tests/test_delivery_enforcement_exemptions.py +0 -0
  187. package/tools/agents/tests/test_delivery_enforcement_filepath.py +0 -0
  188. package/tools/agents/tests/test_delivery_enforcement_web_and_bash.py +0 -0
  189. package/tools/agents/tests/test_delivery_enforcement_worktree.py +0 -0
  190. package/tools/agents/tests/test_delivery_enforcement_write_complexity.py +0 -0
  191. package/tools/agents/tests/test_disconnect_watcher.py +0 -0
  192. package/tools/agents/tests/test_doubling_break.py +0 -0
  193. package/tools/agents/tests/test_empty_maxtokens_recovery.py +0 -0
  194. package/tools/agents/tests/test_empty_tool_loop_break.py +0 -0
  195. package/tools/agents/tests/test_enforcement_self_protect.py +90 -0
  196. package/tools/agents/tests/test_enforcer_escape_hatches.py +0 -0
  197. package/tools/agents/tests/test_error_loop_break.py +0 -0
  198. package/tools/agents/tests/test_expert_review_pr_scope.py +13 -5
  199. package/tools/agents/tests/test_fastpath_config.py +0 -0
  200. package/tools/agents/tests/test_finalize_suppression.py +0 -0
  201. package/tools/agents/tests/test_gate_evidence.py +0 -0
  202. package/tools/agents/tests/test_gate_failclosed_indirection.py +0 -0
  203. package/tools/agents/tests/test_gate_integrity.py +0 -0
  204. package/tools/agents/tests/test_live_deliver_kill.py +0 -0
  205. package/tools/agents/tests/test_malformed_unclosed_think.py +0 -0
  206. package/tools/agents/tests/test_mandate_beats_recon.py +0 -0
  207. package/tools/agents/tests/test_mandate_deliver.py +0 -0
  208. package/tools/agents/tests/test_non_stream_resp_log.py +0 -0
  209. package/tools/agents/tests/test_output_token_ceilings.py +0 -0
  210. package/tools/agents/tests/test_overflow_truncate_count_tokens.py +0 -0
  211. package/tools/agents/tests/test_path_containment.py +0 -0
  212. package/tools/agents/tests/test_path_normalizer_hardened.py +0 -0
  213. package/tools/agents/tests/test_repeat_call_guard.py +0 -0
  214. package/tools/agents/tests/test_repeat_guard.py +0 -0
  215. package/tools/agents/tests/test_session_admission.py +0 -0
  216. package/tools/agents/tests/test_stream_heartbeat.py +0 -0
  217. package/tools/agents/tests/test_stream_thinking_deltas.py +405 -0
  218. package/tools/agents/tests/test_stuck_break_hard.py +0 -0
  219. package/tools/agents/tests/test_stuck_break_reattach.py +0 -0
  220. package/tools/agents/tests/test_turn_count_breaker_periodic.py +0 -0
  221. package/tools/agents/tests/test_upstream_chokepoint.py +0 -0
  222. package/tools/agents/tests/test_upstream_model_aliases.py +0 -0
  223. package/tools/agents/tests/test_validate_plan_gate.py +0 -0
  224. package/tools/agents/tests/test_vision_passthrough.py +0 -0
  225. package/tools/agents/tests/test_workdir_scope_enforcer.py +0 -0
  226. package/dist/cli/rtk.d.ts +0 -34
  227. package/dist/cli/rtk.d.ts.map +0 -1
  228. package/dist/cli/rtk.js +0 -401
  229. package/dist/cli/rtk.js.map +0 -1
  230. package/docs/integrations/RTK.md +0 -113
  231. package/scripts/setup/install-rtk.sh +0 -184
  232. package/src/policies/enforcers/rtk_wrap.py +0 -205
  233. package/src/policies/schemas/policies/rtk-wrap.md +0 -50
  234. package/tools/agents/tests/test_rtk_wrap.py +0 -151
@@ -0,0 +1,54 @@
1
+ /**
2
+ * CRAP (Change Risk Anti-Patterns) score: cc^2 * (1 - cov)^3 + cc
3
+ * where cc is cyclomatic complexity and cov is the line-coverage fraction.
4
+ *
5
+ * Function-level coverage is not reliably available from every provider, so
6
+ * the gate computes CRAP per function using the FILE's line-coverage fraction
7
+ * — an approximation documented in the policy. A file with 0% coverage makes
8
+ * CRAP = cc^2 + cc, so untested complex functions blow past the threshold
9
+ * fast, which is exactly the pressure the metric exists to apply.
10
+ */
11
+ import { existsSync, readFileSync } from 'fs';
12
+ import { join } from 'path';
13
+ export function crapScore(cyclomatic, coverageFraction) {
14
+ const c = Math.min(1, Math.max(0, coverageFraction));
15
+ return cyclomatic * cyclomatic * Math.pow(1 - c, 3) + cyclomatic;
16
+ }
17
+ /**
18
+ * Parse per-file line-coverage fractions from a vitest/istanbul
19
+ * coverage-summary.json (`<root>/coverage/coverage-summary.json`).
20
+ * Returns null when absent — coverage metrics are then skipped (fail-open
21
+ * with a logged warning), matching the missing-tool policy.
22
+ */
23
+ export function loadCoverageSummary(root) {
24
+ const p = join(root, 'coverage', 'coverage-summary.json');
25
+ if (!existsSync(p))
26
+ return null;
27
+ try {
28
+ const raw = JSON.parse(readFileSync(p, 'utf-8'));
29
+ const out = new Map();
30
+ for (const [file, data] of Object.entries(raw)) {
31
+ if (file === 'total')
32
+ continue;
33
+ const pct = data?.lines?.pct;
34
+ if (typeof pct === 'number')
35
+ out.set(file, pct / 100);
36
+ }
37
+ return out;
38
+ }
39
+ catch {
40
+ return null;
41
+ }
42
+ }
43
+ /** Resolve the coverage fraction for a scanned file, tolerating path shape. */
44
+ export function coverageFor(coverage, root, file) {
45
+ const norm = file.replace(/\\/g, '/');
46
+ for (const [covFile, pct] of coverage) {
47
+ const cf = covFile.replace(/\\/g, '/');
48
+ if (cf === norm || cf === join(root, norm).replace(/\\/g, '/') || cf.endsWith(`/${norm}`)) {
49
+ return pct;
50
+ }
51
+ }
52
+ return null;
53
+ }
54
+ //# sourceMappingURL=crap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crap.js","sourceRoot":"","sources":["../../src/quality/crap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAC9C,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,MAAM,UAAU,SAAS,CAAC,UAAkB,EAAE,gBAAwB;IACpE,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC,CAAC;IACrD,OAAO,UAAU,GAAG,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,UAAU,CAAC;AACnE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,UAAU,EAAE,uBAAuB,CAAC,CAAC;IAC1D,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAChC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,EAAE,OAAO,CAAC,CAG9C,CAAC;QACF,MAAM,GAAG,GAAG,IAAI,GAAG,EAAkB,CAAC;QACtC,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YAC/C,IAAI,IAAI,KAAK,OAAO;gBAAE,SAAS;YAC/B,MAAM,GAAG,GAAG,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC;YAC7B,IAAI,OAAO,GAAG,KAAK,QAAQ;gBAAE,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,GAAG,GAAG,CAAC,CAAC;QACxD,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,WAAW,CAAC,QAA6B,EAAE,IAAY,EAAE,IAAY;IACnF,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACtC,KAAK,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,IAAI,QAAQ,EAAE,CAAC;QACtC,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QACvC,IAAI,EAAE,KAAK,IAAI,IAAI,EAAE,KAAK,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,IAAI,IAAI,EAAE,CAAC,EAAE,CAAC;YAC1F,OAAO,GAAG,CAAC;QACb,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Language detection + lexical facts for the built-in scanner.
3
+ *
4
+ * The scanner is a *fallback*: when lizard / rust-code-analysis are installed
5
+ * their (authoritative) numbers win. Without them the gate still needs teeth,
6
+ * so we approximate with a generic brace/indent model driven by the facts
7
+ * below. Heuristic by design — documented as such in the policy.
8
+ */
9
+ export type CommentStyle = 'c' | 'hash';
10
+ export interface LanguageFacts {
11
+ name: string;
12
+ commentStyle: CommentStyle;
13
+ /** True for indent-delimited languages (python): no braces delimit blocks. */
14
+ indentBased: boolean;
15
+ /**
16
+ * Decision keywords counted for cyclomatic complexity. Word-boundary matched
17
+ * against code with strings/comments stripped.
18
+ */
19
+ decisionWords: string[];
20
+ /** Operator decision tokens (counted like keywords): `&&`, `||`, `?` etc. */
21
+ decisionOps: string[];
22
+ }
23
+ export declare function languageForFile(path: string): LanguageFacts | null;
24
+ export declare function stripNoise(content: string, style: CommentStyle): string;
25
+ //# sourceMappingURL=languages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"languages.d.ts","sourceRoot":"","sources":["../../src/quality/languages.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,MAAM,YAAY,GAAG,GAAG,GAAG,MAAM,CAAC;AAExC,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,YAAY,CAAC;IAC3B,8EAA8E;IAC9E,WAAW,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,6EAA6E;IAC7E,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAmED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAKlE;AAqDD,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,MAAM,CAiBvE"}
@@ -0,0 +1,150 @@
1
+ /**
2
+ * Language detection + lexical facts for the built-in scanner.
3
+ *
4
+ * The scanner is a *fallback*: when lizard / rust-code-analysis are installed
5
+ * their (authoritative) numbers win. Without them the gate still needs teeth,
6
+ * so we approximate with a generic brace/indent model driven by the facts
7
+ * below. Heuristic by design — documented as such in the policy.
8
+ */
9
+ const C_FAMILY = {
10
+ commentStyle: 'c',
11
+ indentBased: false,
12
+ decisionWords: ['if', 'for', 'while', 'case', 'catch', 'elif'],
13
+ decisionOps: ['&&', '||', '?'],
14
+ };
15
+ const FACTS = {
16
+ typescript: { name: 'typescript', ...C_FAMILY },
17
+ javascript: { name: 'javascript', ...C_FAMILY },
18
+ java: { name: 'java', ...C_FAMILY },
19
+ csharp: { name: 'csharp', ...C_FAMILY },
20
+ cpp: { name: 'cpp', ...C_FAMILY },
21
+ c: { name: 'c', ...C_FAMILY },
22
+ go: {
23
+ name: 'go',
24
+ commentStyle: 'c',
25
+ indentBased: false,
26
+ decisionWords: ['if', 'for', 'case', 'select'],
27
+ decisionOps: ['&&', '||'],
28
+ },
29
+ rust: {
30
+ name: 'rust',
31
+ commentStyle: 'c',
32
+ indentBased: false,
33
+ decisionWords: ['if', 'for', 'while', 'loop', 'match', 'catch'],
34
+ decisionOps: ['&&', '||', '?'],
35
+ },
36
+ python: {
37
+ name: 'python',
38
+ commentStyle: 'hash',
39
+ indentBased: true,
40
+ decisionWords: ['if', 'elif', 'for', 'while', 'except', 'with', 'assert'],
41
+ decisionOps: ['and', 'or'],
42
+ },
43
+ ruby: {
44
+ name: 'ruby',
45
+ commentStyle: 'hash',
46
+ indentBased: false,
47
+ decisionWords: ['if', 'elsif', 'unless', 'while', 'until', 'when', 'rescue'],
48
+ decisionOps: ['&&', '||'],
49
+ },
50
+ php: { name: 'php', ...C_FAMILY },
51
+ swift: { name: 'swift', ...C_FAMILY },
52
+ kotlin: { name: 'kotlin', ...C_FAMILY },
53
+ scala: { name: 'scala', ...C_FAMILY },
54
+ };
55
+ const EXT_MAP = {
56
+ '.ts': 'typescript', '.tsx': 'typescript', '.mts': 'typescript', '.cts': 'typescript',
57
+ '.js': 'javascript', '.jsx': 'javascript', '.mjs': 'javascript', '.cjs': 'javascript',
58
+ '.py': 'python',
59
+ '.java': 'java',
60
+ '.cs': 'csharp',
61
+ '.cpp': 'cpp', '.cc': 'cpp', '.cxx': 'cpp', '.hpp': 'cpp', '.hxx': 'cpp',
62
+ '.c': 'c', '.h': 'c',
63
+ '.rs': 'rust',
64
+ '.go': 'go',
65
+ '.rb': 'ruby',
66
+ '.php': 'php',
67
+ '.swift': 'swift',
68
+ '.kt': 'kotlin', '.kts': 'kotlin',
69
+ '.scala': 'scala',
70
+ };
71
+ export function languageForFile(path) {
72
+ const m = /\.[^./\\]+$/.exec(path);
73
+ if (!m)
74
+ return null;
75
+ const key = EXT_MAP[m[0].toLowerCase()];
76
+ return key ? FACTS[key] : null;
77
+ }
78
+ const QUOTE_OF = { sq: "'", dq: '"', tpl: '`' };
79
+ function codeStep(ch, next, style, out, i) {
80
+ if (ch === '/' && next === '/')
81
+ return { next: i + 2, state: 'line' };
82
+ if (ch === '/' && next === '*')
83
+ return { next: i + 2, state: 'block' };
84
+ if (style === 'hash' && ch === '#')
85
+ return { next: i + 1, state: 'line' };
86
+ if (ch === "'") {
87
+ out.push(' ');
88
+ return { next: i + 1, state: 'sq' };
89
+ }
90
+ if (ch === '"') {
91
+ out.push(' ');
92
+ return { next: i + 1, state: 'dq' };
93
+ }
94
+ if (ch === '`') {
95
+ out.push(' ');
96
+ return { next: i + 1, state: 'tpl' };
97
+ }
98
+ out.push(ch);
99
+ return { next: i + 1, state: 'code' };
100
+ }
101
+ function lineStep(ch, out, i) {
102
+ if (ch === '\n') {
103
+ out.push('\n');
104
+ return { next: i + 1, state: 'code' };
105
+ }
106
+ return { next: i + 1, state: 'line' };
107
+ }
108
+ function blockStep(ch, next, out, i) {
109
+ if (ch === '*' && next === '/')
110
+ return { next: i + 2, state: 'code' };
111
+ if (ch === '\n')
112
+ out.push('\n'); // keep line numbers stable
113
+ return { next: i + 1, state: 'block' };
114
+ }
115
+ function stringStep(ch, state, out, i) {
116
+ if (ch === '\\')
117
+ return { next: i + 2, state };
118
+ if (ch === QUOTE_OF[state])
119
+ return { next: i + 1, state: 'code' };
120
+ if (ch === '\n') {
121
+ out.push('\n');
122
+ // Unterminated single/double-quoted string ends at the newline; template
123
+ // literals span lines.
124
+ return { next: i + 1, state: state === 'tpl' ? 'tpl' : 'code' };
125
+ }
126
+ return { next: i + 1, state };
127
+ }
128
+ export function stripNoise(content, style) {
129
+ const out = [];
130
+ let state = 'code';
131
+ let i = 0;
132
+ const n = content.length;
133
+ while (i < n) {
134
+ const ch = content[i];
135
+ const next = i + 1 < n ? content[i + 1] : '';
136
+ let step;
137
+ if (state === 'code')
138
+ step = codeStep(ch, next, style, out, i);
139
+ else if (state === 'line')
140
+ step = lineStep(ch, out, i);
141
+ else if (state === 'block')
142
+ step = blockStep(ch, next, out, i);
143
+ else
144
+ step = stringStep(ch, state, out, i);
145
+ i = step.next;
146
+ state = step.state;
147
+ }
148
+ return out.join('');
149
+ }
150
+ //# sourceMappingURL=languages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"languages.js","sourceRoot":"","sources":["../../src/quality/languages.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ import { QualityConfig } from './config.js';
2
+ import { Violation, MetricId } from './scanner.js';
3
+ import { ToolStatus } from './tools.js';
4
+ export interface QualityReport {
5
+ root: string;
6
+ filesScanned: number;
7
+ violations: Violation[];
8
+ blocking: Violation[];
9
+ grandfathered: Violation[];
10
+ improved: Array<{
11
+ violation: Violation;
12
+ baselineValue: number;
13
+ }>;
14
+ /** Metrics skipped because their tool/data source is unavailable. */
15
+ skipped: Array<{
16
+ metric: string;
17
+ reason: string;
18
+ }>;
19
+ tools: ToolStatus[];
20
+ pass: boolean;
21
+ baselinePresent: boolean;
22
+ }
23
+ /** Recursively collect scannable source files under root/src (or root). */
24
+ export declare function collectSourceFiles(root: string, config: QualityConfig): string[];
25
+ /** Files changed vs the upstream base PLUS staged/unstaged/untracked work —
26
+ * a per-commit gate that only sees committed diffs would miss the commit's
27
+ * actual content. */
28
+ export declare function changedFiles(root: string, config: QualityConfig): string[];
29
+ export interface ReportOptions {
30
+ /** Explicit relative file list; default: full scan of collectSourceFiles. */
31
+ files?: string[];
32
+ /** Skip external tools even when installed (fast path / tests). */
33
+ builtinOnly?: boolean;
34
+ }
35
+ /** Build the full quality report for a set of files. */
36
+ export declare function buildReport(root: string, config: QualityConfig, options?: ReportOptions): QualityReport;
37
+ export type { MetricId };
38
+ //# sourceMappingURL=report.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../src/quality/report.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAkC,QAAQ,EAAE,MAAM,cAAc,CAAC;AAInF,OAAO,EACL,UAAU,EACX,MAAM,YAAY,CAAC;AAGpB,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,QAAQ,EAAE,SAAS,EAAE,CAAC;IACtB,aAAa,EAAE,SAAS,EAAE,CAAC;IAC3B,QAAQ,EAAE,KAAK,CAAC;QAAE,SAAS,EAAE,SAAS,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjE,qEAAqE;IACrE,OAAO,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnD,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,IAAI,EAAE,OAAO,CAAC;IACd,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,2EAA2E;AAC3E,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,MAAM,EAAE,CA6BhF;AAED;;qBAEqB;AACrB,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,MAAM,EAAE,CA6B1E;AAED,MAAM,WAAW,aAAa;IAC5B,6EAA6E;IAC7E,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,mEAAmE;IACnE,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAkJD,wDAAwD;AACxD,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,aAAa,EACrB,OAAO,GAAE,aAAkB,GAC1B,aAAa,CA4Bf;AAED,YAAY,EAAE,QAAQ,EAAE,CAAC"}
@@ -0,0 +1,251 @@
1
+ /**
2
+ * Quality report orchestration: collect files, run every available metric,
3
+ * merge external-tool numbers over built-in heuristics, compute CRAP from
4
+ * coverage, and split violations into blocking vs grandfathered via the
5
+ * ratchet baseline.
6
+ */
7
+ import { existsSync, readFileSync, readdirSync, statSync } from 'fs';
8
+ import { join, relative } from 'path';
9
+ import { execSync } from 'child_process';
10
+ import { isScannableSource, scanContent } from './scanner.js';
11
+ import { analyzeComplexity } from './complexity.js';
12
+ import { languageForFile } from './languages.js';
13
+ import { crapScore, coverageFor, loadCoverageSummary } from './crap.js';
14
+ import { jscpdViolations, lizardViolations, probeTools, rcaViolations, } from './tools.js';
15
+ import { loadBaseline, ratchet } from './baseline.js';
16
+ /** Recursively collect scannable source files under root/src (or root). */
17
+ export function collectSourceFiles(root, config) {
18
+ const seeds = ['src', 'tools', 'scripts', 'web'].filter((d) => existsSync(join(root, d)));
19
+ const dirs = seeds.length > 0 ? seeds : ['.'];
20
+ const out = [];
21
+ const walk = (dir) => {
22
+ let entries;
23
+ try {
24
+ entries = readdirSync(dir);
25
+ }
26
+ catch {
27
+ return;
28
+ }
29
+ for (const name of entries) {
30
+ const p = join(dir, name);
31
+ let st;
32
+ try {
33
+ st = statSync(p);
34
+ }
35
+ catch {
36
+ continue;
37
+ }
38
+ if (st.isDirectory()) {
39
+ if (!config.excludeDirs.includes(name))
40
+ walk(p);
41
+ continue;
42
+ }
43
+ const rel = relative(root, p).replace(/\\/g, '/');
44
+ if (isScannableSource(rel, config))
45
+ out.push(rel);
46
+ }
47
+ };
48
+ for (const d of dirs)
49
+ walk(join(root, d));
50
+ return out.sort();
51
+ }
52
+ /** Files changed vs the upstream base PLUS staged/unstaged/untracked work —
53
+ * a per-commit gate that only sees committed diffs would miss the commit's
54
+ * actual content. */
55
+ export function changedFiles(root, config) {
56
+ const found = new Set();
57
+ const tryGit = (args) => {
58
+ try {
59
+ const out = execSync(`git ${args}`, { cwd: root, encoding: 'utf-8', timeout: 10_000 });
60
+ for (const l of out.split('\n')) {
61
+ const f = l.trim();
62
+ if (f)
63
+ found.add(f);
64
+ }
65
+ return true;
66
+ }
67
+ catch {
68
+ return false;
69
+ }
70
+ };
71
+ let baseResolved = false;
72
+ for (const base of ['origin/master', 'origin/main', 'master', 'main']) {
73
+ if (tryGit(`diff --name-only ${base}...HEAD`)) {
74
+ baseResolved = true;
75
+ break;
76
+ }
77
+ }
78
+ // Uncommitted work: staged, unstaged, and untracked source files.
79
+ tryGit('diff --name-only --cached');
80
+ tryGit('diff --name-only');
81
+ tryGit('ls-files --others --exclude-standard');
82
+ if (!baseResolved && found.size === 0) {
83
+ console.error('quality: no upstream base resolvable and no working-tree changes — scanning nothing');
84
+ }
85
+ return [...found].filter((f) => isScannableSource(f, config)).sort();
86
+ }
87
+ /** Stage 1: the always-available built-in scan. */
88
+ function builtinScan(root, files, config) {
89
+ const out = [];
90
+ for (const f of files) {
91
+ let content = '';
92
+ try {
93
+ content = readFileSync(join(root, f), 'utf-8');
94
+ }
95
+ catch {
96
+ continue;
97
+ }
98
+ out.push(...scanContent(f, content, config));
99
+ }
100
+ return out;
101
+ }
102
+ function hasTool(tools, name) {
103
+ return tools.some((t) => t.name === name && t.available);
104
+ }
105
+ /** Stage 2a: lizard's authoritative cyclomatic/NLOC numbers replace the
106
+ * built-in ones when lizard is installed. */
107
+ function applyLizard(violations, files, root, config, options, skipped) {
108
+ if (options.builtinOnly)
109
+ return violations;
110
+ if (!hasTool(probeCached(options), 'lizard')) {
111
+ skipped.push({ metric: 'cyclomatic(authoritative)', reason: 'lizard not installed — built-in heuristic used' });
112
+ return violations;
113
+ }
114
+ const lv = lizardViolations(files.map((f) => join(root, f)), root, config);
115
+ if (!lv)
116
+ return violations;
117
+ return [...violations.filter((v) => v.metric !== 'cyclomatic' && v.metric !== 'locPerFile'), ...lv];
118
+ }
119
+ /** Stage 2b: rust-code-analysis cognitive/Halstead replaces built-in
120
+ * cognitive when installed. */
121
+ function applyRca(violations, files, root, config, options, skipped) {
122
+ if (options.builtinOnly)
123
+ return violations;
124
+ if (!hasTool(probeCached(options), 'rust-code-analysis')) {
125
+ skipped.push({ metric: 'halsteadDifficulty', reason: 'rust-code-analysis not installed' });
126
+ return violations;
127
+ }
128
+ const rv = rcaViolations(files.map((f) => join(root, f)), root, config);
129
+ if (!rv)
130
+ return violations;
131
+ return [...violations.filter((v) => v.metric !== 'cognitive'), ...rv];
132
+ }
133
+ /** Stage 3: coverage deficit + per-function CRAP, from vitest's
134
+ * coverage/coverage-summary.json. */
135
+ function coverageStage(root, files, config, skipped) {
136
+ const coverage = loadCoverageSummary(root);
137
+ if (!coverage) {
138
+ skipped.push({ metric: 'coverage', reason: 'no coverage/coverage-summary.json (run npm run test:coverage)' });
139
+ skipped.push({ metric: 'crap', reason: 'needs coverage data' });
140
+ return [];
141
+ }
142
+ const t = config.thresholds;
143
+ const out = [];
144
+ for (const f of files) {
145
+ const cov = coverageFor(coverage, root, f);
146
+ if (cov === null)
147
+ continue;
148
+ if (cov * 100 < t.minCoveragePct) {
149
+ // The ratchet treats HIGHER value as worse, but coverage is better
150
+ // when higher — store the DEFICIT (threshold − pct) so a coverage
151
+ // regression ratchets up and an improvement ratchets down, like
152
+ // every other metric.
153
+ const deficit = Math.round((t.minCoveragePct - cov * 100) * 10) / 10;
154
+ out.push({
155
+ file: f,
156
+ metric: 'coverage',
157
+ value: deficit,
158
+ threshold: t.minCoveragePct,
159
+ signature: `${f}::coverage::<file>`,
160
+ message: `${f}: ${(cov * 100).toFixed(1)}% line coverage below min ${t.minCoveragePct}% (deficit ${deficit})`,
161
+ });
162
+ }
163
+ out.push(...crapViolations(root, f, cov, t.maxCrap));
164
+ }
165
+ return out;
166
+ }
167
+ /** CRAP per function: file coverage × function complexity. */
168
+ function crapViolations(root, f, cov, maxCrap) {
169
+ const lang = languageForFile(f);
170
+ if (!lang)
171
+ return [];
172
+ let content = '';
173
+ try {
174
+ content = readFileSync(join(root, f), 'utf-8');
175
+ }
176
+ catch {
177
+ return [];
178
+ }
179
+ const out = [];
180
+ for (const fn of analyzeComplexity(content, lang).functions) {
181
+ const score = crapScore(fn.cyclomatic, cov);
182
+ if (score > maxCrap) {
183
+ out.push({
184
+ file: f,
185
+ metric: 'crap',
186
+ value: Math.round(score * 10) / 10,
187
+ threshold: maxCrap,
188
+ signature: `${f}::crap::${fn.name}@${fn.line}`,
189
+ message: `${f}:${fn.line} ${fn.name}() CRAP ${score.toFixed(1)} (cc=${fn.cyclomatic}, cov=${(cov * 100).toFixed(0)}%) exceeds max ${maxCrap}`,
190
+ });
191
+ }
192
+ }
193
+ return out;
194
+ }
195
+ /** Stage 4: jscpd duplication. */
196
+ function duplicationStage(root, config, options, skipped) {
197
+ if (options.builtinOnly)
198
+ return [];
199
+ if (!hasTool(probeCached(options), 'jscpd')) {
200
+ skipped.push({ metric: 'duplicateBlocks', reason: 'jscpd not installed' });
201
+ return [];
202
+ }
203
+ return jscpdViolations(root, config) ?? [];
204
+ }
205
+ /** Stage 5: note metrics that are report-only or have no available tool. */
206
+ function noteUnavailable(options, skipped) {
207
+ if (options.builtinOnly)
208
+ return;
209
+ if (!hasTool(probeCached(options), 'knip') && !hasTool(probeCached(options), 'vulture')) {
210
+ skipped.push({ metric: 'deadCode', reason: 'knip/vulture not installed' });
211
+ }
212
+ skipped.push({ metric: 'survivingMutants', reason: 'run `uap quality mutate` (changed-files incremental)' });
213
+ }
214
+ /** Probe tools once per report; stage helpers read the cached list. */
215
+ const probeCache = new WeakMap();
216
+ function probeCached(options) {
217
+ let t = probeCache.get(options);
218
+ if (!t) {
219
+ t = options.builtinOnly ? [] : probeTools();
220
+ probeCache.set(options, t);
221
+ }
222
+ return t;
223
+ }
224
+ /** Build the full quality report for a set of files. */
225
+ export function buildReport(root, config, options = {}) {
226
+ const files = options.files ?? collectSourceFiles(root, config);
227
+ const skipped = [];
228
+ const tools = probeCached(options);
229
+ let violations = builtinScan(root, files, config);
230
+ violations = applyLizard(violations, files, root, config, options, skipped);
231
+ violations = applyRca(violations, files, root, config, options, skipped);
232
+ violations.push(...coverageStage(root, files, config, skipped));
233
+ violations.push(...duplicationStage(root, config, options, skipped));
234
+ noteUnavailable(options, skipped);
235
+ // Ratchet against the baseline.
236
+ const baseline = loadBaseline(root);
237
+ const r = ratchet(violations, baseline);
238
+ return {
239
+ root,
240
+ filesScanned: files.length,
241
+ violations,
242
+ blocking: r.blocking,
243
+ grandfathered: r.grandfathered,
244
+ improved: r.improved,
245
+ skipped,
246
+ tools,
247
+ pass: r.blocking.length === 0,
248
+ baselinePresent: baseline !== null,
249
+ };
250
+ }
251
+ //# sourceMappingURL=report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/quality/report.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import { QualityConfig } from './config.js';
2
+ export type MetricId = 'cyclomatic' | 'cognitive' | 'halsteadDifficulty' | 'locPerFile' | 'coverage' | 'crap' | 'survivingMutants' | 'duplicateBlocks' | 'deadCode' | 'anyTypes';
3
+ export interface Violation {
4
+ file: string;
5
+ metric: MetricId;
6
+ /** Measured value (count, complexity, or percent depending on metric). */
7
+ value: number;
8
+ /** Configured threshold that was crossed. */
9
+ threshold: number;
10
+ /**
11
+ * Stable identity for baseline ratcheting: file + metric + the function or
12
+ * site the violation belongs to. Function renames intentionally re-identify
13
+ * a violation (a renamed complex function is reviewed as if new).
14
+ */
15
+ signature: string;
16
+ message: string;
17
+ }
18
+ /** Count explicit any/unknown usages in one file's content. */
19
+ export declare function countAnyTypes(content: string, file: string): {
20
+ count: number;
21
+ lines: number[];
22
+ };
23
+ /**
24
+ * Scan one file's content for the always-available metrics:
25
+ * LOC/file, per-function cyclomatic + cognitive complexity, any-types.
26
+ * Halstead/CRAP/coverage/mutation/duplication/dead-code need external data
27
+ * and are merged later by report.ts.
28
+ */
29
+ export declare function scanContent(file: string, content: string, config: QualityConfig): Violation[];
30
+ /** True when `file` is a scannable source path under the config's rules. */
31
+ export declare function isScannableSource(file: string, config: QualityConfig): boolean;
32
+ //# sourceMappingURL=scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../src/quality/scanner.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAI5C,MAAM,MAAM,QAAQ,GAChB,YAAY,GACZ,WAAW,GACX,oBAAoB,GACpB,YAAY,GACZ,UAAU,GACV,MAAM,GACN,kBAAkB,GAClB,iBAAiB,GACjB,UAAU,GACV,UAAU,CAAC;AAEf,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,QAAQ,CAAC;IACjB,0EAA0E;IAC1E,KAAK,EAAE,MAAM,CAAC;IACd,6CAA6C;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAyBD,+DAA+D;AAC/D,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,CAkB/F;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,SAAS,EAAE,CAuD7F;AAED,4EAA4E;AAC5E,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,CAQ9E"}