@spikedpunch/align-core 0.1.0

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 (203) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +27 -0
  3. package/dist/baseline/fingerprint.d.ts +19 -0
  4. package/dist/baseline/fingerprint.d.ts.map +1 -0
  5. package/dist/baseline/fingerprint.js +0 -0
  6. package/dist/baseline/fingerprint.js.map +1 -0
  7. package/dist/baseline/store.d.ts +81 -0
  8. package/dist/baseline/store.d.ts.map +1 -0
  9. package/dist/baseline/store.js +111 -0
  10. package/dist/baseline/store.js.map +1 -0
  11. package/dist/build/diff.d.ts +22 -0
  12. package/dist/build/diff.d.ts.map +1 -0
  13. package/dist/build/diff.js +61 -0
  14. package/dist/build/diff.js.map +1 -0
  15. package/dist/build/export-ir.d.ts +11 -0
  16. package/dist/build/export-ir.d.ts.map +1 -0
  17. package/dist/build/export-ir.js +4 -0
  18. package/dist/build/export-ir.js.map +1 -0
  19. package/dist/build/ground.d.ts +32 -0
  20. package/dist/build/ground.d.ts.map +1 -0
  21. package/dist/build/ground.js +162 -0
  22. package/dist/build/ground.js.map +1 -0
  23. package/dist/build/hash.d.ts +10 -0
  24. package/dist/build/hash.d.ts.map +1 -0
  25. package/dist/build/hash.js +13 -0
  26. package/dist/build/hash.js.map +1 -0
  27. package/dist/build/impact.d.ts +20 -0
  28. package/dist/build/impact.d.ts.map +1 -0
  29. package/dist/build/impact.js +15 -0
  30. package/dist/build/impact.js.map +1 -0
  31. package/dist/build/index.d.ts +14 -0
  32. package/dist/build/index.d.ts.map +1 -0
  33. package/dist/build/index.js +14 -0
  34. package/dist/build/index.js.map +1 -0
  35. package/dist/build/merge.d.ts +27 -0
  36. package/dist/build/merge.d.ts.map +1 -0
  37. package/dist/build/merge.js +85 -0
  38. package/dist/build/merge.js.map +1 -0
  39. package/dist/build/propose.d.ts +16 -0
  40. package/dist/build/propose.d.ts.map +1 -0
  41. package/dist/build/propose.js +126 -0
  42. package/dist/build/propose.js.map +1 -0
  43. package/dist/build/provenance.d.ts +19 -0
  44. package/dist/build/provenance.d.ts.map +1 -0
  45. package/dist/build/provenance.js +23 -0
  46. package/dist/build/provenance.js.map +1 -0
  47. package/dist/build/schema.d.ts +1825 -0
  48. package/dist/build/schema.d.ts.map +1 -0
  49. package/dist/build/schema.js +128 -0
  50. package/dist/build/schema.js.map +1 -0
  51. package/dist/build/sections.d.ts +30 -0
  52. package/dist/build/sections.d.ts.map +1 -0
  53. package/dist/build/sections.js +58 -0
  54. package/dist/build/sections.js.map +1 -0
  55. package/dist/build/tier1.d.ts +24 -0
  56. package/dist/build/tier1.d.ts.map +1 -0
  57. package/dist/build/tier1.js +68 -0
  58. package/dist/build/tier1.js.map +1 -0
  59. package/dist/build/tier2.d.ts +42 -0
  60. package/dist/build/tier2.d.ts.map +1 -0
  61. package/dist/build/tier2.js +187 -0
  62. package/dist/build/tier2.js.map +1 -0
  63. package/dist/build/types.d.ts +42 -0
  64. package/dist/build/types.d.ts.map +1 -0
  65. package/dist/build/types.js +2 -0
  66. package/dist/build/types.js.map +1 -0
  67. package/dist/components/glob.d.ts +10 -0
  68. package/dist/components/glob.d.ts.map +1 -0
  69. package/dist/components/glob.js +52 -0
  70. package/dist/components/glob.js.map +1 -0
  71. package/dist/components/registry.d.ts +51 -0
  72. package/dist/components/registry.d.ts.map +1 -0
  73. package/dist/components/registry.js +121 -0
  74. package/dist/components/registry.js.map +1 -0
  75. package/dist/dsl/factories.d.ts +86 -0
  76. package/dist/dsl/factories.d.ts.map +1 -0
  77. package/dist/dsl/factories.js +145 -0
  78. package/dist/dsl/factories.js.map +1 -0
  79. package/dist/dsl/index.d.ts +46 -0
  80. package/dist/dsl/index.d.ts.map +1 -0
  81. package/dist/dsl/index.js +67 -0
  82. package/dist/dsl/index.js.map +1 -0
  83. package/dist/dsl/reserved-names.typecheck.d.ts +2 -0
  84. package/dist/dsl/reserved-names.typecheck.d.ts.map +1 -0
  85. package/dist/dsl/reserved-names.typecheck.js +16 -0
  86. package/dist/dsl/reserved-names.typecheck.js.map +1 -0
  87. package/dist/dsl/verb-manifest.d.ts +12 -0
  88. package/dist/dsl/verb-manifest.d.ts.map +1 -0
  89. package/dist/dsl/verb-manifest.js +101 -0
  90. package/dist/dsl/verb-manifest.js.map +1 -0
  91. package/dist/fix/apply.d.ts +67 -0
  92. package/dist/fix/apply.d.ts.map +1 -0
  93. package/dist/fix/apply.js +163 -0
  94. package/dist/fix/apply.js.map +1 -0
  95. package/dist/fix/index.d.ts +3 -0
  96. package/dist/fix/index.d.ts.map +1 -0
  97. package/dist/fix/index.js +3 -0
  98. package/dist/fix/index.js.map +1 -0
  99. package/dist/fix/schema.d.ts +180 -0
  100. package/dist/fix/schema.d.ts.map +1 -0
  101. package/dist/fix/schema.js +41 -0
  102. package/dist/fix/schema.js.map +1 -0
  103. package/dist/gates/advisories.d.ts +11 -0
  104. package/dist/gates/advisories.d.ts.map +1 -0
  105. package/dist/gates/advisories.js +27 -0
  106. package/dist/gates/advisories.js.map +1 -0
  107. package/dist/gates/types.d.ts +36 -0
  108. package/dist/gates/types.d.ts.map +1 -0
  109. package/dist/gates/types.js +8 -0
  110. package/dist/gates/types.js.map +1 -0
  111. package/dist/index.d.ts +17 -0
  112. package/dist/index.d.ts.map +1 -0
  113. package/dist/index.js +17 -0
  114. package/dist/index.js.map +1 -0
  115. package/dist/orchestrator.d.ts +51 -0
  116. package/dist/orchestrator.d.ts.map +1 -0
  117. package/dist/orchestrator.js +304 -0
  118. package/dist/orchestrator.js.map +1 -0
  119. package/dist/payload/builder.d.ts +49 -0
  120. package/dist/payload/builder.d.ts.map +1 -0
  121. package/dist/payload/builder.js +61 -0
  122. package/dist/payload/builder.js.map +1 -0
  123. package/dist/payload/mermaid.d.ts +22 -0
  124. package/dist/payload/mermaid.d.ts.map +1 -0
  125. package/dist/payload/mermaid.js +89 -0
  126. package/dist/payload/mermaid.js.map +1 -0
  127. package/dist/plugin/registry.d.ts +24 -0
  128. package/dist/plugin/registry.d.ts.map +1 -0
  129. package/dist/plugin/registry.js +24 -0
  130. package/dist/plugin/registry.js.map +1 -0
  131. package/dist/rules/component-refs.d.ts +26 -0
  132. package/dist/rules/component-refs.d.ts.map +1 -0
  133. package/dist/rules/component-refs.js +81 -0
  134. package/dist/rules/component-refs.js.map +1 -0
  135. package/dist/rules/evaluators.d.ts +50 -0
  136. package/dist/rules/evaluators.d.ts.map +1 -0
  137. package/dist/rules/evaluators.js +236 -0
  138. package/dist/rules/evaluators.js.map +1 -0
  139. package/dist/rules/host-rules.d.ts +109 -0
  140. package/dist/rules/host-rules.d.ts.map +1 -0
  141. package/dist/rules/host-rules.js +152 -0
  142. package/dist/rules/host-rules.js.map +1 -0
  143. package/dist/rules/index.d.ts +7 -0
  144. package/dist/rules/index.d.ts.map +1 -0
  145. package/dist/rules/index.js +7 -0
  146. package/dist/rules/index.js.map +1 -0
  147. package/dist/rules/manifest-evaluators.d.ts +32 -0
  148. package/dist/rules/manifest-evaluators.d.ts.map +1 -0
  149. package/dist/rules/manifest-evaluators.js +124 -0
  150. package/dist/rules/manifest-evaluators.js.map +1 -0
  151. package/dist/rules/rule-category.d.ts +13 -0
  152. package/dist/rules/rule-category.d.ts.map +1 -0
  153. package/dist/rules/rule-category.js +27 -0
  154. package/dist/rules/rule-category.js.map +1 -0
  155. package/dist/rules/tarjan.d.ts +9 -0
  156. package/dist/rules/tarjan.d.ts.map +1 -0
  157. package/dist/rules/tarjan.js +102 -0
  158. package/dist/rules/tarjan.js.map +1 -0
  159. package/dist/scanner.d.ts +12 -0
  160. package/dist/scanner.d.ts.map +1 -0
  161. package/dist/scanner.js +2 -0
  162. package/dist/scanner.js.map +1 -0
  163. package/dist/telemetry/diff.d.ts +27 -0
  164. package/dist/telemetry/diff.d.ts.map +1 -0
  165. package/dist/telemetry/diff.js +54 -0
  166. package/dist/telemetry/diff.js.map +1 -0
  167. package/dist/telemetry/index.d.ts +4 -0
  168. package/dist/telemetry/index.d.ts.map +1 -0
  169. package/dist/telemetry/index.js +4 -0
  170. package/dist/telemetry/index.js.map +1 -0
  171. package/dist/telemetry/serialize.d.ts +10 -0
  172. package/dist/telemetry/serialize.d.ts.map +1 -0
  173. package/dist/telemetry/serialize.js +11 -0
  174. package/dist/telemetry/serialize.js.map +1 -0
  175. package/dist/telemetry/types.d.ts +138 -0
  176. package/dist/telemetry/types.d.ts.map +1 -0
  177. package/dist/telemetry/types.js +3 -0
  178. package/dist/telemetry/types.js.map +1 -0
  179. package/dist/types/branded.d.ts +26 -0
  180. package/dist/types/branded.d.ts.map +1 -0
  181. package/dist/types/branded.js +24 -0
  182. package/dist/types/branded.js.map +1 -0
  183. package/dist/types/graph.d.ts +46 -0
  184. package/dist/types/graph.d.ts.map +1 -0
  185. package/dist/types/graph.js +2 -0
  186. package/dist/types/graph.js.map +1 -0
  187. package/dist/types/index.d.ts +6 -0
  188. package/dist/types/index.d.ts.map +1 -0
  189. package/dist/types/index.js +6 -0
  190. package/dist/types/index.js.map +1 -0
  191. package/dist/types/ir.d.ts +1747 -0
  192. package/dist/types/ir.d.ts.map +1 -0
  193. package/dist/types/ir.js +120 -0
  194. package/dist/types/ir.js.map +1 -0
  195. package/dist/types/manifest.d.ts +58 -0
  196. package/dist/types/manifest.d.ts.map +1 -0
  197. package/dist/types/manifest.js +2 -0
  198. package/dist/types/manifest.js.map +1 -0
  199. package/dist/types/violation.d.ts +94 -0
  200. package/dist/types/violation.d.ts.map +1 -0
  201. package/dist/types/violation.js +56 -0
  202. package/dist/types/violation.js.map +1 -0
  203. package/package.json +58 -0
@@ -0,0 +1,61 @@
1
+ // Priority sort before pagination/truncation (ADR 007 rule 3): architecture > security > types >
2
+ // lint > format. v1 only ever populates 'architecture', but the ordering contract is fixed now.
3
+ const CATEGORY_PRIORITY = {
4
+ architecture: 0,
5
+ security: 1,
6
+ types: 2,
7
+ lint: 3,
8
+ format: 4,
9
+ };
10
+ /**
11
+ * Priority sort, cap-per-rule, and page the violations from a `CheckRun` into the structured-only
12
+ * MCP payload shape (ADR 007). Passing gates contribute counts only — never per-item text.
13
+ */
14
+ export function buildMcpCheckPayload(run, options = {}) {
15
+ const maxPerRule = options.maxPerRule ?? 10;
16
+ const pageSize = options.pageSize ?? 50;
17
+ const offset = options.cursor === undefined ? 0 : Number.parseInt(options.cursor, 10) || 0;
18
+ const allViolations = run.gates.flatMap((g) => g.violations);
19
+ const sorted = sortViolations(allViolations);
20
+ const capped = capPerRule(sorted, maxPerRule);
21
+ const page = capped.slice(offset, offset + pageSize);
22
+ const hasMore = offset + pageSize < capped.length;
23
+ return {
24
+ verdict: run.verdict,
25
+ gates: run.gates.map((g) => ({
26
+ gate: g.gate,
27
+ status: g.status,
28
+ violationCount: g.violations.length,
29
+ baselinedCount: g.baselinedCount,
30
+ ...(g.passCount === undefined ? {} : { passCount: g.passCount }),
31
+ })),
32
+ violations: page,
33
+ ...(capped.length > pageSize ? { pagination: { cursor: String(offset + pageSize), hasMore } } : {}),
34
+ advisories: run.advisories,
35
+ ungroundedComponents: run.ungroundedComponents,
36
+ };
37
+ }
38
+ function sortViolations(violations) {
39
+ return [...violations].sort((a, b) => {
40
+ const byCategory = CATEGORY_PRIORITY[a.category] - CATEGORY_PRIORITY[b.category];
41
+ if (byCategory !== 0)
42
+ return byCategory;
43
+ const byRule = a.ruleId.localeCompare(b.ruleId);
44
+ if (byRule !== 0)
45
+ return byRule;
46
+ return a.file.localeCompare(b.file);
47
+ });
48
+ }
49
+ function capPerRule(violations, maxPerRule) {
50
+ const seenPerRule = new Map();
51
+ const out = [];
52
+ for (const v of violations) {
53
+ const count = seenPerRule.get(v.ruleId) ?? 0;
54
+ if (count >= maxPerRule)
55
+ continue;
56
+ seenPerRule.set(v.ruleId, count + 1);
57
+ out.push(v);
58
+ }
59
+ return out;
60
+ }
61
+ //# sourceMappingURL=builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builder.js","sourceRoot":"","sources":["../../src/payload/builder.ts"],"names":[],"mappings":"AAOA,iGAAiG;AACjG,gGAAgG;AAChG,MAAM,iBAAiB,GAAuC;IAC5D,YAAY,EAAE,CAAC;IACf,QAAQ,EAAE,CAAC;IACX,KAAK,EAAE,CAAC;IACR,IAAI,EAAE,CAAC;IACP,MAAM,EAAE,CAAC;CACV,CAAC;AA4BF;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,GAAa,EAAE,UAAoC,EAAE;IACxF,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,EAAE,CAAC;IAC5C,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC;IACxC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;IAE3F,MAAM,aAAa,GAAG,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;IAC7D,MAAM,MAAM,GAAG,cAAc,CAAC,aAAa,CAAC,CAAC;IAC7C,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAE9C,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,CAAC,CAAC;IACrD,MAAM,OAAO,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC;IAElD,OAAO;QACL,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC3B,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,cAAc,EAAE,CAAC,CAAC,UAAU,CAAC,MAAM;YACnC,cAAc,EAAE,CAAC,CAAC,cAAc;YAChC,GAAG,CAAC,CAAC,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC;SACjE,CAAC,CAAC;QACH,UAAU,EAAE,IAAI;QAChB,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,GAAG,QAAQ,CAAC,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACnG,UAAU,EAAE,GAAG,CAAC,UAAU;QAC1B,oBAAoB,EAAE,GAAG,CAAC,oBAAoB;KAC/C,CAAC;AACJ,CAAC;AAED,SAAS,cAAc,CAAC,UAAgC;IACtD,OAAO,CAAC,GAAG,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACnC,MAAM,UAAU,GAAG,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;QACjF,IAAI,UAAU,KAAK,CAAC;YAAE,OAAO,UAAU,CAAC;QACxC,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QAChD,IAAI,MAAM,KAAK,CAAC;YAAE,OAAO,MAAM,CAAC;QAChC,OAAO,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,UAAU,CAAC,UAAgC,EAAE,UAAkB;IACtE,MAAM,WAAW,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC9C,MAAM,GAAG,GAAgB,EAAE,CAAC;IAC5B,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QAC3B,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC7C,IAAI,KAAK,IAAI,UAAU;YAAE,SAAS;QAClC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QACrC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACd,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,22 @@
1
+ import type { Violation } from '../types/violation.js';
2
+ /**
3
+ * Fenced Mermaid `graph LR` diagram for one architecture violation instance — an `explain`-only
4
+ * surface (ADR 007: pull-on-demand prose/diagram, never included in the terse `align_check` /
5
+ * `align_violations` machine payloads). One violation's diagram, not the whole rule's violation
6
+ * set — explain answers "why did THIS fire and how do I read it", not a full survey.
7
+ *
8
+ * - `no-cycles`: the cycle's chain, with the suggested break edge drawn as a dashed link labeled
9
+ * `BREAK: <specifier>` instead of a normal solid arrow.
10
+ * - `no-dependency` / `layers`: the two-node offending edge, component/layer names alongside the
11
+ * concrete files, labeled with the forbidden specifier.
12
+ * - `metric`: a single node (there is no offending edge — the violation is file-level, not
13
+ * import-direction-level) labeled with the component, file, and measured-vs-max lines.
14
+ * - `custom`: a single node (a host predicate's violation is whatever shape the predicate chose —
15
+ * there's no structural edge/chain align itself derived) labeled with the file and the
16
+ * predicate's own message.
17
+ * - `manifest-source-hygiene` / `manifest-new-dependency`: a single node (ADR 013 — the manifest
18
+ * scan domain has no import-graph edges to draw) labeled with the declaring manifest, the
19
+ * dependency name, and its specifier.
20
+ */
21
+ export declare function buildViolationMermaid(violation: Violation): string;
22
+ //# sourceMappingURL=mermaid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mermaid.d.ts","sourceRoot":"","sources":["../../src/payload/mermaid.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElE;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,SAAS,GAAG,MAAM,CAuBlE"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Fenced Mermaid `graph LR` diagram for one architecture violation instance — an `explain`-only
3
+ * surface (ADR 007: pull-on-demand prose/diagram, never included in the terse `align_check` /
4
+ * `align_violations` machine payloads). One violation's diagram, not the whole rule's violation
5
+ * set — explain answers "why did THIS fire and how do I read it", not a full survey.
6
+ *
7
+ * - `no-cycles`: the cycle's chain, with the suggested break edge drawn as a dashed link labeled
8
+ * `BREAK: <specifier>` instead of a normal solid arrow.
9
+ * - `no-dependency` / `layers`: the two-node offending edge, component/layer names alongside the
10
+ * concrete files, labeled with the forbidden specifier.
11
+ * - `metric`: a single node (there is no offending edge — the violation is file-level, not
12
+ * import-direction-level) labeled with the component, file, and measured-vs-max lines.
13
+ * - `custom`: a single node (a host predicate's violation is whatever shape the predicate chose —
14
+ * there's no structural edge/chain align itself derived) labeled with the file and the
15
+ * predicate's own message.
16
+ * - `manifest-source-hygiene` / `manifest-new-dependency`: a single node (ADR 013 — the manifest
17
+ * scan domain has no import-graph edges to draw) labeled with the declaring manifest, the
18
+ * dependency name, and its specifier.
19
+ */
20
+ export function buildViolationMermaid(violation) {
21
+ switch (violation.kind) {
22
+ case 'no-cycles':
23
+ return fence(cycleDiagram(violation.chain, violation.suggestedBreakEdge));
24
+ case 'no-dependency':
25
+ return fence(edgeDiagram(violation.fromComponent, violation.fromFile, violation.toComponent, violation.toFile, violation.specifier));
26
+ case 'layers':
27
+ return fence(edgeDiagram(violation.fromLayer, violation.fromFile, violation.toLayer, violation.toFile, violation.specifier));
28
+ case 'metric':
29
+ return fence(metricDiagram(violation.component, violation.file, violation.value, violation.threshold));
30
+ case 'custom':
31
+ return fence(customDiagram(violation.file, violation.hostRuleName, violation.detail));
32
+ case 'manifest-source-hygiene':
33
+ return fence(manifestDiagram(violation.file, violation.depName, violation.specifier));
34
+ case 'manifest-new-dependency':
35
+ return fence(manifestDiagram(violation.file, violation.depName, violation.specifier));
36
+ default: {
37
+ const exhaustive = violation;
38
+ throw new Error(`unhandled violation kind: ${JSON.stringify(exhaustive)}`);
39
+ }
40
+ }
41
+ }
42
+ function fence(body) {
43
+ return `\`\`\`mermaid\n${body}\n\`\`\``;
44
+ }
45
+ function cycleDiagram(chain, suggestedBreakEdge) {
46
+ const ids = new Map();
47
+ const lines = ['graph LR'];
48
+ const idFor = (file) => {
49
+ const existing = ids.get(file);
50
+ if (existing !== undefined)
51
+ return existing;
52
+ const id = `n${ids.size}`;
53
+ ids.set(file, id);
54
+ lines.push(` ${id}["${escapeLabel(file)}"]`);
55
+ return id;
56
+ };
57
+ for (const hop of chain) {
58
+ const fromId = idFor(hop.from);
59
+ const toId = idFor(hop.to);
60
+ lines.push(sameEdge(hop, suggestedBreakEdge)
61
+ ? ` ${fromId} -. "BREAK: ${escapeLabel(hop.specifier)}" .-> ${toId}`
62
+ : ` ${fromId} -->|"${escapeLabel(hop.specifier)}"| ${toId}`);
63
+ }
64
+ return lines.join('\n');
65
+ }
66
+ function sameEdge(a, b) {
67
+ return a.from === b.from && a.to === b.to && a.specifier === b.specifier;
68
+ }
69
+ function edgeDiagram(fromLabel, fromFile, toLabel, toFile, specifier) {
70
+ return [
71
+ 'graph LR',
72
+ ` a["${escapeLabel(fromLabel)}<br/>${escapeLabel(fromFile)}"]`,
73
+ ` b["${escapeLabel(toLabel)}<br/>${escapeLabel(toFile)}"]`,
74
+ ` a -->|"${escapeLabel(specifier)} (forbidden)"| b`,
75
+ ].join('\n');
76
+ }
77
+ function metricDiagram(component, file, value, threshold) {
78
+ return ['graph LR', ` a["${escapeLabel(component)}<br/>${escapeLabel(file)}<br/>${value} lines (max ${threshold})"]`].join('\n');
79
+ }
80
+ function customDiagram(file, hostRuleName, detail) {
81
+ return ['graph LR', ` a["${escapeLabel(file)}<br/>predicate: ${escapeLabel(hostRuleName)}<br/>${escapeLabel(detail)}"]`].join('\n');
82
+ }
83
+ function manifestDiagram(file, depName, specifier) {
84
+ return ['graph LR', ` a["${escapeLabel(file)}<br/>${escapeLabel(depName)}: ${escapeLabel(specifier)}"]`].join('\n');
85
+ }
86
+ function escapeLabel(s) {
87
+ return s.replace(/"/g, '\\"');
88
+ }
89
+ //# sourceMappingURL=mermaid.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mermaid.js","sourceRoot":"","sources":["../../src/payload/mermaid.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import type { RepoRelativePath } from '../types/branded.js';
2
+ import type { Scanner } from '../scanner.js';
3
+ export interface LanguagePlugin {
4
+ readonly id: string;
5
+ readonly fileMatch: readonly string[];
6
+ readonly scanner: Scanner;
7
+ }
8
+ export interface PluginRegistry {
9
+ getPluginForFile(file: RepoRelativePath): LanguagePlugin | undefined;
10
+ getAllPlugins(): readonly LanguagePlugin[];
11
+ }
12
+ /**
13
+ * v1's registry implementation is a one-element static list — no cross-plugin file-match
14
+ * conflict resolution, no priority ordering, no merged-graph logic across plugins. Those are
15
+ * real problems only a second `LanguagePlugin` creates; the interface is written generically so
16
+ * adding one is additive at the CLI composition root, not an interface rewrite.
17
+ */
18
+ export declare class StaticPluginRegistry implements PluginRegistry {
19
+ private readonly plugins;
20
+ constructor(plugins: readonly LanguagePlugin[]);
21
+ getPluginForFile(file: RepoRelativePath): LanguagePlugin | undefined;
22
+ getAllPlugins(): readonly LanguagePlugin[];
23
+ }
24
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/plugin/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAG7C,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,cAAc;IAC7B,gBAAgB,CAAC,IAAI,EAAE,gBAAgB,GAAG,cAAc,GAAG,SAAS,CAAC;IACrE,aAAa,IAAI,SAAS,cAAc,EAAE,CAAC;CAC5C;AAED;;;;;GAKG;AACH,qBAAa,oBAAqB,YAAW,cAAc;IAC7C,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,SAAS,cAAc,EAAE;IAE/D,gBAAgB,CAAC,IAAI,EAAE,gBAAgB,GAAG,cAAc,GAAG,SAAS;IAOpE,aAAa,IAAI,SAAS,cAAc,EAAE;CAG3C"}
@@ -0,0 +1,24 @@
1
+ import { globMatch } from '../components/glob.js';
2
+ /**
3
+ * v1's registry implementation is a one-element static list — no cross-plugin file-match
4
+ * conflict resolution, no priority ordering, no merged-graph logic across plugins. Those are
5
+ * real problems only a second `LanguagePlugin` creates; the interface is written generically so
6
+ * adding one is additive at the CLI composition root, not an interface rewrite.
7
+ */
8
+ export class StaticPluginRegistry {
9
+ plugins;
10
+ constructor(plugins) {
11
+ this.plugins = plugins;
12
+ }
13
+ getPluginForFile(file) {
14
+ for (const plugin of this.plugins) {
15
+ if (plugin.fileMatch.some((pattern) => globMatch(pattern, file)))
16
+ return plugin;
17
+ }
18
+ return undefined;
19
+ }
20
+ getAllPlugins() {
21
+ return this.plugins;
22
+ }
23
+ }
24
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/plugin/registry.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAalD;;;;;GAKG;AACH,MAAM,OAAO,oBAAoB;IACF;IAA7B,YAA6B,OAAkC;QAAlC,YAAO,GAAP,OAAO,CAA2B;IAAG,CAAC;IAEnE,gBAAgB,CAAC,IAAsB;QACrC,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAClC,IAAI,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;gBAAE,OAAO,MAAM,CAAC;QAClF,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,aAAa;QACX,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;CACF"}
@@ -0,0 +1,26 @@
1
+ import type { ComponentName } from '../types/branded.js';
2
+ import type { ComponentDefinitionIR, RuleIR } from '../types/ir.js';
3
+ /** Thrown when a rule (hand-authored in `align.config.ts` or machine-written in
4
+ * `.align/generated-rules.json`) references a component name absent from the current components
5
+ * registry — a config-load-time hard error (ADR 003's empty-selector-fails-by-default doctrine
6
+ * extended to the symmetric case: a *ComponentRef* naming a component that no longer exists).
7
+ * Without this check, `evaluateRule` (`rules/evaluators.ts`) simply never matches a component
8
+ * name absent from the graph, so the rule silently evaluates to zero violations — a false-green,
9
+ * severity-zero bug class (ARCHITECTURE.md's stated invariant), most commonly triggered by a
10
+ * component rename/removal in `align.config.ts` leaving a stale reference behind in generated
11
+ * or hand-authored rules. */
12
+ export declare class UnknownComponentRefError extends Error {
13
+ readonly ruleId: string;
14
+ readonly componentName: string;
15
+ constructor(ruleId: string, componentName: string);
16
+ }
17
+ /**
18
+ * Load-time validation (companion to `components/registry.ts`'s `validateComponents`, which
19
+ * checks components against files; this checks rules against components): every `ComponentRef`
20
+ * embedded in every rule — merged generated + hand-authored alike, since both share one
21
+ * `RuleIR[]` by the time this runs (`build/merge.ts`) — must name a component present in the
22
+ * registry. Throws `UnknownComponentRefError` on the first offender found (fail-fast, same
23
+ * convention as `validateComponents`), not a collected list — one bad ref is enough to halt.
24
+ */
25
+ export declare function validateRuleComponentRefs(rules: readonly RuleIR[], components: Readonly<Record<ComponentName, ComponentDefinitionIR>>): void;
26
+ //# sourceMappingURL=component-refs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"component-refs.d.ts","sourceRoot":"","sources":["../../src/rules/component-refs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAEpE;;;;;;;;6BAQ6B;AAC7B,qBAAa,wBAAyB,SAAQ,KAAK;aAI/B,MAAM,EAAE,MAAM;aACd,aAAa,EAAE,MAAM;gBADrB,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,MAAM;CAUxC;AAwCD;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,aAAa,EAAE,qBAAqB,CAAC,CAAC,GACjE,IAAI,CAQN"}
@@ -0,0 +1,81 @@
1
+ /** Thrown when a rule (hand-authored in `align.config.ts` or machine-written in
2
+ * `.align/generated-rules.json`) references a component name absent from the current components
3
+ * registry — a config-load-time hard error (ADR 003's empty-selector-fails-by-default doctrine
4
+ * extended to the symmetric case: a *ComponentRef* naming a component that no longer exists).
5
+ * Without this check, `evaluateRule` (`rules/evaluators.ts`) simply never matches a component
6
+ * name absent from the graph, so the rule silently evaluates to zero violations — a false-green,
7
+ * severity-zero bug class (ARCHITECTURE.md's stated invariant), most commonly triggered by a
8
+ * component rename/removal in `align.config.ts` leaving a stale reference behind in generated
9
+ * or hand-authored rules. */
10
+ export class UnknownComponentRefError extends Error {
11
+ ruleId;
12
+ componentName;
13
+ constructor(
14
+ // Matches `RuleIR['id']`'s actual (unbranded) type — same convention as
15
+ // `GeneratedRuleCollisionError` in `build/merge.ts`.
16
+ ruleId, componentName) {
17
+ super(`Rule '${ruleId}' references unknown component '${componentName}', which is not defined in ` +
18
+ `the components registry. Likely cause: the component was renamed or removed since this rule ` +
19
+ `was written — if this is a generated rule, re-run \`align build\` to refresh ` +
20
+ `.align/generated-rules.json; if hand-authored, update align.config.ts.`);
21
+ this.ruleId = ruleId;
22
+ this.componentName = componentName;
23
+ this.name = 'UnknownComponentRefError';
24
+ }
25
+ }
26
+ /** Every `ComponentRef` a rule embeds, in a fixed, deterministic order — one generator per IR
27
+ * kind, exhaustively switched (a new `RuleIR` kind missing a case here is a compile error, same
28
+ * discipline as `evaluateRule`'s dispatcher). `custom.host` carries no `ComponentRef` — it
29
+ * references a host predicate by name (`hostRuleName`), validated by `rules/host-rules.ts`'s
30
+ * `validateHostRules`, not by this component-reference guard. */
31
+ function* componentRefsOf(rule) {
32
+ switch (rule.kind) {
33
+ case 'arch.no-dependency':
34
+ yield rule.from;
35
+ yield rule.to;
36
+ return;
37
+ case 'arch.no-cycles':
38
+ if (rule.scope !== 'repo')
39
+ yield rule.scope;
40
+ return;
41
+ case 'arch.layers':
42
+ for (const layerDef of rule.layers) {
43
+ yield layerDef.layer;
44
+ yield* layerDef.canDependOn;
45
+ }
46
+ return;
47
+ case 'arch.metric':
48
+ yield rule.target;
49
+ return;
50
+ case 'custom.host':
51
+ return;
52
+ // `security.manifest.*` (ADR 013) carries no `ComponentRef` — the manifest scan domain has no
53
+ // notion of align's file-classified components (same no-op shape as `custom.host`, which
54
+ // references a host predicate by name instead).
55
+ case 'security.manifest.source-hygiene':
56
+ case 'security.manifest.new-dependency':
57
+ return;
58
+ default: {
59
+ const exhaustive = rule;
60
+ throw new Error(`unhandled rule kind: ${JSON.stringify(exhaustive)}`);
61
+ }
62
+ }
63
+ }
64
+ /**
65
+ * Load-time validation (companion to `components/registry.ts`'s `validateComponents`, which
66
+ * checks components against files; this checks rules against components): every `ComponentRef`
67
+ * embedded in every rule — merged generated + hand-authored alike, since both share one
68
+ * `RuleIR[]` by the time this runs (`build/merge.ts`) — must name a component present in the
69
+ * registry. Throws `UnknownComponentRefError` on the first offender found (fail-fast, same
70
+ * convention as `validateComponents`), not a collected list — one bad ref is enough to halt.
71
+ */
72
+ export function validateRuleComponentRefs(rules, components) {
73
+ for (const rule of rules) {
74
+ for (const ref of componentRefsOf(rule)) {
75
+ if (!(ref in components)) {
76
+ throw new UnknownComponentRefError(rule.id, ref);
77
+ }
78
+ }
79
+ }
80
+ }
81
+ //# sourceMappingURL=component-refs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"component-refs.js","sourceRoot":"","sources":["../../src/rules/component-refs.ts"],"names":[],"mappings":"AAGA;;;;;;;;6BAQ6B;AAC7B,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IAI/B;IACA;IAJlB;IACE,wEAAwE;IACxE,qDAAqD;IACrC,MAAc,EACd,aAAqB;QAErC,KAAK,CACH,SAAS,MAAM,mCAAmC,aAAa,6BAA6B;YAC1F,8FAA8F;YAC9F,+EAA+E;YAC/E,wEAAwE,CAC3E,CAAC;QARc,WAAM,GAAN,MAAM,CAAQ;QACd,kBAAa,GAAb,aAAa,CAAQ;QAQrC,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;IACzC,CAAC;CACF;AAED;;;;iEAIiE;AACjE,QAAQ,CAAC,CAAC,eAAe,CAAC,IAAY;IACpC,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;QAClB,KAAK,oBAAoB;YACvB,MAAM,IAAI,CAAC,IAAI,CAAC;YAChB,MAAM,IAAI,CAAC,EAAE,CAAC;YACd,OAAO;QACT,KAAK,gBAAgB;YACnB,IAAI,IAAI,CAAC,KAAK,KAAK,MAAM;gBAAE,MAAM,IAAI,CAAC,KAAK,CAAC;YAC5C,OAAO;QACT,KAAK,aAAa;YAChB,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;gBACnC,MAAM,QAAQ,CAAC,KAAK,CAAC;gBACrB,KAAK,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC;YAC9B,CAAC;YACD,OAAO;QACT,KAAK,aAAa;YAChB,MAAM,IAAI,CAAC,MAAM,CAAC;YAClB,OAAO;QACT,KAAK,aAAa;YAChB,OAAO;QACT,8FAA8F;QAC9F,yFAAyF;QACzF,gDAAgD;QAChD,KAAK,kCAAkC,CAAC;QACxC,KAAK,kCAAkC;YACrC,OAAO;QACT,OAAO,CAAC,CAAC,CAAC;YACR,MAAM,UAAU,GAAU,IAAI,CAAC;YAC/B,MAAM,IAAI,KAAK,CAAC,wBAAwB,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QACxE,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,yBAAyB,CACvC,KAAwB,EACxB,UAAkE;IAElE,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,KAAK,MAAM,GAAG,IAAI,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;YACxC,IAAI,CAAC,CAAC,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC;gBACzB,MAAM,IAAI,wBAAwB,CAAC,IAAI,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;YACnD,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,50 @@
1
+ import type { ComponentName } from '../types/branded.js';
2
+ import type { ArchLayersRule, ArchMetricRule, ArchNoCyclesRule, ArchNoDependencyRule, ComponentDefinitionIR, RuleIR } from '../types/ir.js';
3
+ import type { DependencyGraph } from '../types/graph.js';
4
+ import type { Violation } from '../types/violation.js';
5
+ import { type HostPredicateRegistry } from './host-rules.js';
6
+ /**
7
+ * Pure function: (rule, graph, components) -> violations. No I/O, no mutation, fully testable
8
+ * with plain data (CODING_BEST_PRACTICES.md §14). One evaluator per RuleIR kind; `evaluateRule`
9
+ * dispatches by `kind` through an exhaustive switch so a new IR kind missing an evaluator is a
10
+ * compile error, not a silent no-op.
11
+ */
12
+ export type RuleEvaluator<TRule extends RuleIR = RuleIR> = (rule: TRule, graph: DependencyGraph, components: Readonly<Record<ComponentName, ComponentDefinitionIR>>) => readonly Violation[];
13
+ export declare function becauseField(because: string | undefined): {
14
+ readonly because: string;
15
+ } | Record<string, never>;
16
+ export declare const evaluateNoDependency: RuleEvaluator<ArchNoDependencyRule>;
17
+ export declare const evaluateNoCycles: RuleEvaluator<ArchNoCyclesRule>;
18
+ export declare const evaluateLayers: RuleEvaluator<ArchLayersRule>;
19
+ /**
20
+ * `arch.metric` (max-LOC only, promoted 2026-07-12 on kluster ruleset evidence —
21
+ * IMPLEMENTATION_PLAN.md's Promotion log: two 2,100+-line files were structurally invisible to
22
+ * every dependency/cycle rule). One violation per file classified to `rule.target` whose `loc`
23
+ * exceeds `rule.max` — `loc` is already on every `DependencyGraphNode` (no new scanning).
24
+ */
25
+ export declare const evaluateMetric: RuleEvaluator<ArchMetricRule>;
26
+ /**
27
+ * Exhaustive dispatcher: a new `RuleIR` discriminant without a case here is a compile error
28
+ * (never-check, CODING_BEST_PRACTICES.md §17.2), not a silent no-op.
29
+ *
30
+ * `hostPredicates` defaults to the empty registry — every `arch.*` evaluator ignores it entirely
31
+ * (they never took it before registration existed); only `custom.host` reads it. A predicate that
32
+ * throws propagates out of this function uncaught (`HostPredicateExecutionError`) exactly like a
33
+ * malformed rule would — the orchestrator's evaluation-loop guard is what turns that into gate
34
+ * `error` (`orchestrator.ts`), not this function, which stays a pure dispatcher.
35
+ *
36
+ * `security.manifest.*` kinds (ADR 013) return `[]` here, deliberately: this dispatcher only ever
37
+ * receives a `DependencyGraph` (TS-source scan output), and manifest rules evaluate against a
38
+ * disjoint scan domain (`ManifestInventory`) that this function never has access to. They are real
39
+ * `RuleIR` members (needed so the DSL/tier-2/build pipeline can author and round-trip them), but
40
+ * their actual evaluation always goes through `evaluateManifestRule`
41
+ * (`rules/manifest-evaluators.ts`) against real manifest data — `GateOrchestrator`'s `security` gate
42
+ * calls it directly and never routes these kinds through this function (`ruleCategoryOf` partitions
43
+ * `RulesetIR.rules` before either dispatcher runs, `rules/rule-category.ts`). Returning `[]` here
44
+ * (rather than throwing) keeps `align build`/`align explain`'s generic graph-based preview paths
45
+ * working without a manifest scan available to them — see ADR 013's follow-up ladder for the known
46
+ * gap this leaves (their impact-delta preview under-reports manifest-rule violations; `align check`
47
+ * remains authoritative).
48
+ */
49
+ export declare function evaluateRule(rule: RuleIR, graph: DependencyGraph, components: Readonly<Record<ComponentName, ComponentDefinitionIR>>, hostPredicates?: HostPredicateRegistry): readonly Violation[];
50
+ //# sourceMappingURL=evaluators.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evaluators.d.ts","sourceRoot":"","sources":["../../src/rules/evaluators.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAoB,MAAM,qBAAqB,CAAC;AAE3E,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAC5I,OAAO,KAAK,EAAE,eAAe,EAAiC,MAAM,mBAAmB,CAAC;AACxF,OAAO,KAAK,EAAa,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAGlE,OAAO,EAAsB,KAAK,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAQjF;;;;;GAKG;AACH,MAAM,MAAM,aAAa,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,IAAI,CACzD,IAAI,EAAE,KAAK,EACX,KAAK,EAAE,eAAe,EACtB,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,aAAa,EAAE,qBAAqB,CAAC,CAAC,KAC/D,SAAS,SAAS,EAAE,CAAC;AAO1B,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAE9G;AAED,eAAO,MAAM,oBAAoB,EAAE,aAAa,CAAC,oBAAoB,CA8BpE,CAAC;AAKF,eAAO,MAAM,gBAAgB,EAAE,aAAa,CAAC,gBAAgB,CA+D5D,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,aAAa,CAAC,cAAc,CAoCxD,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,cAAc,EAAE,aAAa,CAAC,cAAc,CAyBxD,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,eAAe,EACtB,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,aAAa,EAAE,qBAAqB,CAAC,CAAC,EAClE,cAAc,GAAE,qBAA0C,GACzD,SAAS,SAAS,EAAE,CAoBtB"}