@dragonshorn-studios/elyseum-cli 1.0.12 → 1.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 (43) hide show
  1. package/README.md +137 -49
  2. package/dist/adapters/clover.d.ts +10 -0
  3. package/dist/adapters/clover.d.ts.map +1 -0
  4. package/dist/adapters/go-coverprofile.d.ts +15 -0
  5. package/dist/adapters/go-coverprofile.d.ts.map +1 -0
  6. package/dist/adapters/go-test-json.d.ts +15 -0
  7. package/dist/adapters/go-test-json.d.ts.map +1 -0
  8. package/dist/adapters/index.d.ts +18 -0
  9. package/dist/adapters/index.d.ts.map +1 -0
  10. package/dist/adapters/junit.d.ts +15 -0
  11. package/dist/adapters/junit.d.ts.map +1 -0
  12. package/dist/adapters/types.d.ts +66 -0
  13. package/dist/adapters/types.d.ts.map +1 -0
  14. package/dist/adapters/vitest-json.d.ts +12 -0
  15. package/dist/adapters/vitest-json.d.ts.map +1 -0
  16. package/dist/commands/command.d.ts +1 -1
  17. package/dist/commands/command.d.ts.map +1 -1
  18. package/dist/commands/coverage-command.d.ts +3 -3
  19. package/dist/commands/coverage-command.d.ts.map +1 -1
  20. package/dist/commands/diff-coverage-command.d.ts +4 -4
  21. package/dist/commands/diff-coverage-command.d.ts.map +1 -1
  22. package/dist/commands/emit-envelope-command.d.ts +43 -0
  23. package/dist/commands/emit-envelope-command.d.ts.map +1 -0
  24. package/dist/config.d.ts +1 -0
  25. package/dist/config.d.ts.map +1 -1
  26. package/dist/core/ci-env.d.ts +27 -0
  27. package/dist/core/ci-env.d.ts.map +1 -0
  28. package/dist/core/envelope.d.ts +69 -0
  29. package/dist/core/envelope.d.ts.map +1 -0
  30. package/dist/core/errors.d.ts +30 -0
  31. package/dist/core/errors.d.ts.map +1 -0
  32. package/dist/core/exit-codes.d.ts +21 -0
  33. package/dist/core/exit-codes.d.ts.map +1 -0
  34. package/dist/core/git-diff.d.ts +80 -0
  35. package/dist/core/git-diff.d.ts.map +1 -0
  36. package/dist/core/lcov.d.ts +56 -0
  37. package/dist/core/lcov.d.ts.map +1 -0
  38. package/dist/core/quality-gate.d.ts +15 -0
  39. package/dist/core/quality-gate.d.ts.map +1 -0
  40. package/dist/index.js +12591 -4442
  41. package/dist/index.js.map +1 -1
  42. package/dist/utils/logger.d.ts.map +1 -1
  43. package/package.json +17 -10
package/README.md CHANGED
@@ -1,84 +1,172 @@
1
- # Elyseum CLI
1
+ <div align="center">
2
+ <img src=".github/logo.svg" alt="Elyseum — CI quality ledger" width="720">
3
+ </div>
2
4
 
3
- > **Notice:** This is a work-in-progress personal package. Use at your own risk.
5
+ # Elyseum CLI
4
6
 
5
- Elyseum CLI is a command-line tool for coverage reporting. It provides various reporters to display coverage information in different formats.
7
+ The producer half of the Elyseum suite: a command-line coverage engine —
8
+ total & diff coverage from LCOV reports, terminal and PR reporters, quality
9
+ gates — plus adapters that turn JUnit, Clover, Go, and LCOV reports into the
10
+ versioned result envelope the
11
+ [Elyseum](https://github.com/Dragonshorn-Studios/elyseum) host stores. Run it
12
+ directly or through the
13
+ [elyseum-coverage-reporter-action](https://github.com/Dragonshorn-Studios/elyseum-coverage-reporter-action).
6
14
 
7
15
  ## Installation
8
16
 
9
- You can install the package globally using npm:
17
+ The canonical npm package is `@dragonshorn-studios/elyseum-cli`:
10
18
 
11
19
  ```bash
12
- npm install -g @dragonshorn/elyseum-cli
20
+ npm install -g @dragonshorn-studios/elyseum-cli
13
21
  ```
14
22
 
15
- ## Usage
23
+ Requires Node >= 20.
16
24
 
17
- ### Commands
25
+ ## Commands
18
26
 
19
- - `diff-coverage`: Calculate coverage for changed files.
20
- - `coverage`: Calculate coverage for all files.
27
+ ### `diff-coverage`
21
28
 
22
- ### Options
29
+ Computes coverage for changed lines between two refs (or an explicit changed-file list) and reports it.
23
30
 
24
- - `--reporter.coverage`: Coverage reporter(s), separated by commas. Available reporters: `cli-table`, `github-pr-comment`.
25
- - `--reporter.coverage.colors`: Use colors in coverage reporter (if supported).
26
- - `--reporter.coverage.details`: Show coverage details.
27
- - `--reporter.coverage.quality-gate`: Coverage quality gate.
31
+ | Option | Default | Description |
32
+ | --- | --- | --- |
33
+ | `--diff-coverage.base` | `origin/main` (or `origin/$GITHUB_BASE_REF`) | Base branch/SHA |
34
+ | `--diff-coverage.head` | `HEAD` (or `$GITHUB_SHA`) | Head branch/SHA |
35
+ | `--diff-coverage.dynamic` | | Set to `gh` to resolve the base SHA from the GitHub pull request |
36
+ | `--diff-coverage.changed-files` | | Comma-separated file list; skips git entirely |
37
+ | `--diff-coverage.lcov-path` | `coverage/lcov.info` | LCOV report location |
28
38
 
29
- ### Examples
39
+ ### `coverage`
30
40
 
31
- #### Calculate Coverage for Changed Files
41
+ Aggregated coverage over the whole report.
32
42
 
33
- ```bash
34
- elyseum-cli diff-coverage --head <HEAD_COMMIT> --base <BASE_COMMIT>
35
- ```
43
+ | Option | Default | Description |
44
+ | --- | --- | --- |
45
+ | `--coverage.lcov-path` | `coverage/lcov.info` | LCOV report location |
36
46
 
37
- #### Calculate Coverage for All Files
47
+ ### Reporters
38
48
 
39
- ```bash
40
- elyseum-cli coverage
41
- ```
49
+ - `--reporter.coverage cli-table,markdown-table,github-pr-comment` (comma separated)
50
+ - `--reporter.coverage.details` — per-file breakdown
51
+ - `--reporter.coverage.quality-gate <n>` — changed-line coverage below `n` warns
52
+ - `--reporter.coverage.quality-gate-fail <n>` — coverage at or below `n` fails the command (exit 1)
42
53
 
43
- #### Use Multiple Reporters
54
+ ## Configuration (`.elyseum.yml`)
44
55
 
45
- ```bash
46
- elyseum-cli diff-coverage --reporter.coverage=cli-table,github-pr-comment
47
- ```
56
+ Precedence: CLI arguments (when explicitly given) beat the environment
57
+ block, which beats the default block. Keys use the same names as the CLI
58
+ options (nested with dots flattened):
48
59
 
49
- #### Use Colors in Coverage Reporter
60
+ ```yaml
61
+ default-environment: auto
50
62
 
51
- ```bash
52
- elyseum-cli diff-coverage --reporter.coverage.colors
63
+ config:
64
+ coverage:
65
+ lcov-path: coverage/lcov.info
66
+ diff-coverage:
67
+ base: origin/main
68
+
69
+ environments:
70
+ github:
71
+ reporter:
72
+ coverage:
73
+ quality-gate: 80
74
+ quality-gate-fail: 50
75
+ local: {}
53
76
  ```
54
77
 
55
- #### Show Coverage Details
78
+ Validation lists every schema violation and exits with code 2. Note that a
79
+ changed-file list given without a diff counts **every** coverable line of
80
+ the listed file as changed — gates are therefore stricter in that mode.
81
+
82
+ ## Exit codes
83
+
84
+ | Code | Meaning |
85
+ | --- | --- |
86
+ | 0 | Success |
87
+ | 1 | A configured quality gate failed |
88
+ | 2 | Invalid configuration |
89
+ | 3 | No git repository found (and no explicit changed-file list) |
90
+ | 4 | LCOV report not found |
91
+ | 5 | Any other calculation or runtime error |
92
+
93
+ ## Input adapters (`emit-envelope`)
94
+
95
+ Adapters translate tool-specific reports into the versioned v1 envelope
96
+ (pinned from the host: `schemas/envelope.v1.json`). Format selection is
97
+ explicit — no auto-detection.
98
+
99
+ | Option | Values | Reads |
100
+ | --- | --- | --- |
101
+ | `--emit-envelope.tests-format` | `vitest-json` \| `junit` \| `go-test-json` | test report |
102
+ | `--emit-envelope.tests-input` | path or `-` (stdin) | test report |
103
+ | `--emit-envelope.coverage-format` | `lcov` \| `clover` \| `go-coverprofile` | coverage report |
104
+ | `--emit-envelope.coverage-input` | path or `-` (stdin) | coverage report |
105
+
106
+ Example (Vitest + LCOV, i.e. Maomao):
56
107
 
57
108
  ```bash
58
- elyseum-cli diff-coverage --reporter.coverage.details
109
+ elyseum-cli emit-envelope \
110
+ --emit-envelope.tests-format vitest-json \
111
+ --emit-envelope.tests-input tests/vitest.json \
112
+ --emit-envelope.coverage-format lcov \
113
+ --emit-envelope.coverage-input coverage/lcov.info \
114
+ --emit-envelope.out envelope.json
59
115
  ```
60
116
 
61
- #### Set Coverage Quality Gate
117
+ Marller (Go): `--emit-envelope.tests-format go-test-json` with
118
+ `go test -json ./...` output, and `--emit-envelope.coverage-format
119
+ go-coverprofile` with `go test -coverprofile`. Laravel:
120
+ `--emit-envelope.tests-format junit` with `--log-junit` output and
121
+ `--emit-envelope.coverage-format clover` with `--coverage-clover`.
122
+
123
+ Semantics:
124
+
125
+ - Missing metrics are `null`/unknown, never zero (Go coverage provides no
126
+ function/branch data — those stay null).
127
+ - Coverage absence does not invalidate test facts: with no coverage input,
128
+ the `coverage` section is omitted.
129
+ - Failed tests (500), coverage files (2000), names (512), failure messages
130
+ (2048 chars) and coverage paths (1024 chars) are bounded before
131
+ serialization.
132
+ - XML is parsed without external entity or DTD resolution; input is never
133
+ executed.
134
+ - Malformed or truncated input fails with exit code 5 and an actionable
135
+ diagnostic.
136
+ - Provenance (formats, CLI version) is recorded in the envelope's
137
+ `provenance` field.
138
+
139
+ ## Behavior notes
140
+
141
+ - Percentages are always finite: a metric with zero eligible items (zero
142
+ changed lines, zero coverable lines, zero branches) reports 100%, never NaN.
143
+ - Only added lines (`+`) count as changed; removed lines, context lines, and
144
+ comment-only/blank additions are excluded.
145
+ - File paths are compared with leading slashes stripped.
146
+ - Supported Node versions: >= 20 (CI tests Node 20 and 22).
147
+
148
+ ## Development
62
149
 
63
150
  ```bash
64
- elyseum-cli diff-coverage --reporter.coverage.quality-gate=80
151
+ npm install
152
+ npm run build # rollup bundle into dist/
153
+ npm test # vitest unit + integration suites
154
+ npm run pack:smoke # npm pack + run the packed binary
155
+ npm run ci # build + test + pack smoke
65
156
  ```
66
157
 
67
- ## Configuration
68
-
69
- You can also configure the CLI using a `.elyseum.yml` file. Here is an example configuration:
158
+ Integration tests run the built CLI against a real fixture git repository and
159
+ LCOV files; the pack smoke test verifies the published tarball contains the
160
+ executable with its shebang.
70
161
 
71
- ```yaml
72
- reporter:
73
- coverage:
74
- cli-table:
75
- color: true
76
- diff: true
77
- github-pr-comment:
78
- file: "github.pr.coverage.md"
79
- qualityGate: 80
80
- ```
162
+ ## Repository roles
81
163
 
82
- ## License
164
+ | Repository | Role |
165
+ | --- | --- |
166
+ | [elyseum] | Host: users/projects/authz, ingest API, CI history UI. Source of truth for the versioned CI result envelope. |
167
+ | [elyseum-cli] (this repo) | Producer CLI: reads local CI artifacts and emits the versioned envelope. |
168
+ | [elyseum-coverage-reporter-action] | Thin GitHub Action wrapping this CLI; optional upload to Elyseum. |
83
169
 
84
- This project is licensed under the MIT License.
170
+ [elyseum]: https://github.com/Dragonshorn-Studios/elyseum
171
+ [elyseum-cli]: https://github.com/Dragonshorn-Studios/elyseum-cli
172
+ [elyseum-coverage-reporter-action]: https://github.com/Dragonshorn-Studios/elyseum-coverage-reporter-action
@@ -0,0 +1,10 @@
1
+ import { CoverageFacts } from "./types";
2
+ /**
3
+ * Clover XML coverage adapter (PHP `--coverage-clover`).
4
+ *
5
+ * Mapping, kept honest to what Clover provides: statements → line
6
+ * coverage, methods → function coverage, conditionals → branch coverage.
7
+ * A file with zero statements reports 100% (nothing to cover), never NaN.
8
+ */
9
+ export declare function parseCloverXml(raw: string): CoverageFacts;
10
+ //# sourceMappingURL=clover.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clover.d.ts","sourceRoot":"","sources":["../../src/adapters/clover.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAExC;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,CAkEzD"}
@@ -0,0 +1,15 @@
1
+ import { CoverageFacts } from "./types";
2
+ /**
3
+ * Go coverprofile adapter (`go test -coverprofile=c.out ./...`).
4
+ *
5
+ * Go reports per-block statement sets with a hit count of 0 or 1, which we
6
+ * aggregate honestly: block counts map to statement counts, and coverage
7
+ * percentages are covered blocks / total blocks per file. Go provides no
8
+ * function or branch coverage, so those stay null — never zero.
9
+ *
10
+ * A profile with a `mode:` header and no blocks is an empty profile: the
11
+ * result is zero files with null percentages (unknown), not fabricated
12
+ * coverage.
13
+ */
14
+ export declare function parseGoCoverprofile(raw: string): CoverageFacts;
15
+ //# sourceMappingURL=go-coverprofile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"go-coverprofile.d.ts","sourceRoot":"","sources":["../../src/adapters/go-coverprofile.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAExC;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,CAmE9D"}
@@ -0,0 +1,15 @@
1
+ import { TestFacts } from "./types";
2
+ /**
3
+ * Go test JSON adapter (`go test -json ./...`): a newline-delimited stream
4
+ * of events.
5
+ *
6
+ * - Leaf tests (pass/fail/skip) each count once; subtests are their own
7
+ * leaves. Duration sums only top-level tests (subtest Elapsed would
8
+ * double count), so duration_ms is approximate.
9
+ * - A package-level failure (panic, setup) becomes one failed identity with
10
+ * bounded captured output.
11
+ * - Build failures (Action build-fail / build-output) become one failed
12
+ * identity per package with bounded build output.
13
+ */
14
+ export declare function parseGoTestJson(raw: string): TestFacts;
15
+ //# sourceMappingURL=go-test-json.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"go-test-json.d.ts","sourceRoot":"","sources":["../../src/adapters/go-test-json.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiD,SAAS,EAAE,MAAM,SAAS,CAAC;AAKnF;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CA4HtD"}
@@ -0,0 +1,18 @@
1
+ import { CoverageFacts, TestFacts } from "./types";
2
+ import { parseGoCoverprofile } from "./go-coverprofile";
3
+ import { parseCloverXml } from "./clover";
4
+ import { parseGoTestJson } from "./go-test-json";
5
+ import { parseJunitXml } from "./junit";
6
+ import { parseVitestJson } from "./vitest-json";
7
+ export * from "./types";
8
+ /**
9
+ * Adapter registry (elyseum-cli#7). Explicit format selection only — there
10
+ * is no auto-detection. Adding an adapter means adding a parser, a format
11
+ * literal here, and fixtures; the envelope and commands do not change.
12
+ */
13
+ export type TestsParser = (raw: string) => TestFacts;
14
+ export type CoverageParser = (raw: string) => CoverageFacts | Promise<CoverageFacts>;
15
+ export declare function testsParserFor(format: string): TestsParser;
16
+ export declare function coverageParserFor(format: string): CoverageParser;
17
+ export { parseGoCoverprofile, parseCloverXml, parseGoTestJson, parseJunitXml, parseVitestJson };
18
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD,cAAc,SAAS,CAAC;AAExB;;;;GAIG;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,SAAS,CAAC;AACrD,MAAM,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;AAoDrF,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,CAQ1D;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,CAQhE;AAED,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,eAAe,EAAE,aAAa,EAAE,eAAe,EAAE,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { TestFacts } from "./types";
2
+ /**
3
+ * JUnit XML adapter (Pest/PHPUnit `--log-junit`, and JUnit-compatible
4
+ * output from other runners).
5
+ *
6
+ * Semantics: a <failure> child → failed; an <error> child → failed (the
7
+ * distinction is preserved in the message text); a <skipped> child →
8
+ * skipped; otherwise passed. Counts come from the <testcase> elements
9
+ * themselves, so they stay consistent even when suite attributes disagree.
10
+ *
11
+ * XML is parsed with fast-xml-parser, which performs no external entity or
12
+ * DTD resolution — the input is untrusted by contract.
13
+ */
14
+ export declare function parseJunitXml(raw: string): TestFacts;
15
+ //# sourceMappingURL=junit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"junit.d.ts","sourceRoot":"","sources":["../../src/adapters/junit.ts"],"names":[],"mappings":"AACA,OAAO,EAAiD,SAAS,EAAE,MAAM,SAAS,CAAC;AAGnF;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAiGpD"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Provider-neutral adapter contract (elyseum-cli#7). Adapters translate
3
+ * tool-specific test/coverage outputs into normalized facts consumed by the
4
+ * v1 envelope writer. Parsing is separate from orchestration and upload;
5
+ * adapters never execute project commands and treat all input as untrusted.
6
+ *
7
+ * Normalization semantics (docs/design notes in README):
8
+ * - Missing metrics are null/unknown, never fabricated as zero.
9
+ * - Zero tests, missing coverage, and zero executable lines are separate
10
+ * states.
11
+ * - Failed-test names/messages and coverage paths are bounded here, before
12
+ * serialization, so the envelope can never exceed the v1 limits.
13
+ */
14
+ export interface NormalizedFailedTest {
15
+ name: string;
16
+ message: string | null;
17
+ file: string | null;
18
+ line: number | null;
19
+ }
20
+ export interface TestFacts {
21
+ total: number;
22
+ passed: number | null;
23
+ failed: number | null;
24
+ skipped: number | null;
25
+ duration_ms: number | null;
26
+ failed_tests: NormalizedFailedTest[];
27
+ }
28
+ export interface CoverageFacts {
29
+ line_percent: number | null;
30
+ function_percent: number | null;
31
+ branch_percent: number | null;
32
+ files: {
33
+ path: string;
34
+ line_percent: number | null;
35
+ function_percent: number | null;
36
+ branch_percent: number | null;
37
+ }[];
38
+ }
39
+ /** Bounded provenance metadata (top-level envelope additive field). */
40
+ export interface Provenance {
41
+ tests_format?: string;
42
+ coverage_format?: string;
43
+ tool_versions?: Record<string, string>;
44
+ }
45
+ export declare const BOUNDS: {
46
+ readonly failed_tests: 500;
47
+ readonly coverage_files: 2000;
48
+ readonly failed_test_name: 512;
49
+ readonly failed_test_message: 2048;
50
+ readonly failed_test_file: 512;
51
+ readonly coverage_path: 1024;
52
+ readonly provenance_value: 64;
53
+ };
54
+ export declare const TESTS_FORMATS: readonly ["vitest-json", "junit", "go-test-json"];
55
+ export declare const COVERAGE_FORMATS: readonly ["lcov", "clover", "go-coverprofile"];
56
+ export type TestsFormat = (typeof TESTS_FORMATS)[number];
57
+ export type CoverageFormat = (typeof COVERAGE_FORMATS)[number];
58
+ export declare function isTestsFormat(value: string): value is TestsFormat;
59
+ export declare function isCoverageFormat(value: string): value is CoverageFormat;
60
+ /** Bounds a failed-test name to the documented length. */
61
+ export declare function boundName(name: string): string;
62
+ /** Bounds a failure message to the documented length. */
63
+ export declare function boundMessage(message: string | null): string | null;
64
+ /** Bounds a file path to the documented length. */
65
+ export declare function boundPath(path: string): string;
66
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/adapters/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,YAAY,EAAE,oBAAoB,EAAE,CAAC;CACtC;AAED,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,KAAK,EAAE;QACL,IAAI,EAAE,MAAM,CAAC;QACb,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;QAC5B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;QAChC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;KAC/B,EAAE,CAAC;CACL;AAED,uEAAuE;AACvE,MAAM,WAAW,UAAU;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACxC;AAED,eAAO,MAAM,MAAM;;;;;;;;CAQT,CAAC;AAEX,eAAO,MAAM,aAAa,mDAAoD,CAAC;AAC/E,eAAO,MAAM,gBAAgB,gDAAiD,CAAC;AAE/E,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AACzD,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE/D,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,WAAW,CAEjE;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,cAAc,CAEvE;AAED,0DAA0D;AAC1D,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI9C;AAED,yDAAyD;AACzD,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAOlE;AAED,mDAAmD;AACnD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI9C"}
@@ -0,0 +1,12 @@
1
+ import { TestFacts } from "./types";
2
+ /**
3
+ * Vitest JSON reporter adapter (also consumes Jest-compatible JSON:
4
+ * numTotalTests / testResults[].assertionResults[]).
5
+ *
6
+ * Status mapping: passed → passed; failed → failed; skipped, pending and
7
+ * todo → skipped (numTodoTests folds into the skipped count). Only failed
8
+ * tests carry identity details. Vitest JSON reports no total duration, so
9
+ * duration_ms is null.
10
+ */
11
+ export declare function parseVitestJson(raw: string): TestFacts;
12
+ //# sourceMappingURL=vitest-json.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vitest-json.d.ts","sourceRoot":"","sources":["../../src/adapters/vitest-json.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiD,SAAS,EAAE,MAAM,SAAS,CAAC;AAGnF;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CA2CtD"}
@@ -1,6 +1,6 @@
1
1
  import { CustomConfig } from "../config";
2
2
  export interface Command {
3
- run(args: any): Promise<void>;
3
+ run(args: any): Promise<number>;
4
4
  config?: CustomConfig;
5
5
  name: string;
6
6
  }
@@ -1 +1 @@
1
- {"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../src/commands/command.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAIzC,MAAM,WAAW,OAAO;IACtB,GAAG,CAAC,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,UAAU;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,qBAAa,cAAc;IACzB,QAAQ,EAAE,UAAU,CAAM;;IAQ1B,UAAU,CAAC,IAAI,EAAE,GAAG,GAAG,OAAO,GAAG,SAAS;IAU1C,oBAAoB;IASpB,cAAc,CAAC,KAAK,EAAE,GAAG,GAAG,IAAI;CAiBjC"}
1
+ {"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../src/commands/command.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAIzC,MAAM,WAAW,OAAO;IACtB,GAAG,CAAC,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAChC,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,UAAU;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,qBAAa,cAAc;IACzB,QAAQ,EAAE,UAAU,CAAM;;IAS1B,UAAU,CAAC,IAAI,EAAE,GAAG,GAAG,OAAO,GAAG,SAAS;IAK1C,oBAAoB;IASpB,cAAc,CAAC,KAAK,EAAE,GAAG,GAAG,IAAI;CAiBjC"}
@@ -1,9 +1,9 @@
1
1
  import { Command, CommandMap } from "./command";
2
+ import { CustomConfig } from "../config";
2
3
  export declare class CoverageCommand implements Command {
3
4
  name: string;
5
+ config?: CustomConfig;
4
6
  constructor(commands: CommandMap);
5
- run(args: any): Promise<void>;
6
- private calculateCoverage;
7
- private getCoverageReport;
7
+ run(args: any): Promise<number>;
8
8
  }
9
9
  //# sourceMappingURL=coverage-command.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"coverage-command.d.ts","sourceRoot":"","sources":["../../src/commands/coverage-command.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEhD,qBAAa,eAAgB,YAAW,OAAO;IAC7C,IAAI,EAAE,MAAM,CAAc;gBACd,QAAQ,EAAE,UAAU;IAInB,GAAG,CAAC,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;YAoB5B,iBAAiB;YA8DjB,iBAAiB;CAWhC"}
1
+ {"version":3,"file":"coverage-command.d.ts","sourceRoot":"","sources":["../../src/commands/coverage-command.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAChD,OAAe,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAKjD,qBAAa,eAAgB,YAAW,OAAO;IAC7C,IAAI,EAAE,MAAM,CAAc;IAC1B,MAAM,CAAC,EAAE,YAAY,CAOnB;gBAEU,QAAQ,EAAE,UAAU;IAInB,GAAG,CAAC,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC;CA0B7C"}
@@ -4,9 +4,9 @@ export declare class DiffCoverageCommand implements Command {
4
4
  name: string;
5
5
  config?: CustomConfig;
6
6
  constructor(commands: CommandMap);
7
- run(args: any): Promise<void>;
8
- private calculateDiffCoverage;
9
- private getCoverageReport;
10
- private getChangedFiles;
7
+ run(args: any): Promise<number>;
8
+ private numberOption;
9
+ private resolveBaseSha;
10
+ private baseShaFromGithub;
11
11
  }
12
12
  //# sourceMappingURL=diff-coverage-command.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"diff-coverage-command.d.ts","sourceRoot":"","sources":["../../src/commands/diff-coverage-command.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAChD,OAAe,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAMjD,qBAAa,mBAAoB,YAAW,OAAO;IACjD,IAAI,EAAE,MAAM,CAAmB;IAC/B,MAAM,CAAC,EAAE,YAAY,CA2BnB;gBACU,QAAQ,EAAE,UAAU;IAInB,GAAG,CAAC,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;YAqI5B,qBAAqB;YAuLrB,iBAAiB;YAajB,eAAe;CA4E9B"}
1
+ {"version":3,"file":"diff-coverage-command.d.ts","sourceRoot":"","sources":["../../src/commands/diff-coverage-command.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAChD,OAAe,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAyBjD,qBAAa,mBAAoB,YAAW,OAAO;IACjD,IAAI,EAAE,MAAM,CAAmB;IAC/B,MAAM,CAAC,EAAE,YAAY,CAiCnB;gBAEU,QAAQ,EAAE,UAAU;IAInB,GAAG,CAAC,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC;IA8F5C,OAAO,CAAC,YAAY;YAKN,cAAc;YAkBd,iBAAiB;CAgChC"}
@@ -0,0 +1,43 @@
1
+ import { Command, CommandMap } from "./command";
2
+ import { CustomConfig } from "../config";
3
+ /**
4
+ * Builds the versioned CI result envelope from the facts this CLI can
5
+ * observe (LCOV coverage, git commit, CI environment) and writes it to a
6
+ * file or stdout. The envelope is validated against the pinned v1 schema
7
+ * before it is written — an invalid envelope is a CLI bug, not a user
8
+ * error, so it fails loudly with exit code 5.
9
+ */
10
+ export declare class EmitEnvelopeCommand implements Command {
11
+ name: string;
12
+ config?: CustomConfig;
13
+ constructor(commands: CommandMap);
14
+ run(args: any): Promise<number>;
15
+ /**
16
+ * Reads an emit-envelope option from the merged config (CLI flag beats
17
+ * .elyseum.yml, which beats the declared default). Null/empty means the
18
+ * option was not given.
19
+ */
20
+ private option;
21
+ private intOption;
22
+ /**
23
+ * Collects normalized test facts from an explicit --tests-format +
24
+ * --tests-input pair. Auto-detection is deliberately not offered: an
25
+ * ambiguous format is a contract violation, not a convenience.
26
+ */
27
+ /**
28
+ * Manual test facts from the --tests-* flags (used when no adapter input
29
+ * is given). All absent means no tests section at all.
30
+ */
31
+ private testsFromFlags;
32
+ private collectTestsFacts;
33
+ /**
34
+ * Collects coverage facts. With --coverage-format, the explicit adapter
35
+ * path applies; otherwise the default LCOV report is used (backwards
36
+ * compatible with the plain coverage/diff-coverage flows).
37
+ */
38
+ private collectCoverageFacts;
39
+ private readInput;
40
+ private cliVersion;
41
+ private r4;
42
+ }
43
+ //# sourceMappingURL=emit-envelope-command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit-envelope-command.d.ts","sourceRoot":"","sources":["../../src/commands/emit-envelope-command.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAChD,OAAe,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AA8BjD;;;;;;GAMG;AACH,qBAAa,mBAAoB,YAAW,OAAO;IACjD,IAAI,EAAE,MAAM,CAAmB;IAC/B,MAAM,CAAC,EAAE,YAAY,CAqFnB;gBAEU,QAAQ,EAAE,UAAU;IAInB,GAAG,CAAC,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC;IAwL5C;;;;OAIG;IACH,OAAO,CAAC,MAAM;IAQd,OAAO,CAAC,SAAS;IAgBjB;;;;OAIG;IACH;;;OAGG;IACH,OAAO,CAAC,cAAc;YAkCR,iBAAiB;IA0B/B;;;;OAIG;YACW,oBAAoB;YAiDpB,SAAS;IAevB,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,EAAE;CAGX"}
package/dist/config.d.ts CHANGED
@@ -14,6 +14,7 @@ declare class Config {
14
14
  private config;
15
15
  private constructor();
16
16
  private isSet;
17
+ private isObject;
17
18
  static getInstance(args?: any): Config;
18
19
  get(key: string, defaultValue?: any): any;
19
20
  getFirst(keys: string[], defaultValue?: any, converter?: any): any;
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,GAAG,CAAC;IACb,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,CAAC;CAC9B;AAED,cAAM,MAAM;IACV,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAS;IAChC,OAAO,CAAC,MAAM,CAAM;IAEpB,OAAO;IA6EP,OAAO,CAAC,KAAK;WAIC,WAAW,CAAC,IAAI,GAAE,GAAQ,GAAG,MAAM;IAO1C,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,GAAE,GAAU,GAAG,GAAG;IAa/C,QAAQ,CACb,IAAI,EAAE,MAAM,EAAE,EACd,YAAY,GAAE,GAAU,EACxB,SAAS,GAAE,GAAmB,GAC7B,GAAG;WAUQ,GAAG,CACf,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,EACvB,YAAY,GAAE,GAAU,GACvB,GAAG;WAUQ,SAAS,IAAI,GAAG;WAIhB,eAAe,IAAI,MAAM,EAAE;CAa1C;AAED,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,GAAG,CAAC;IACb,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,CAAC;CAC9B;AAED,cAAM,MAAM;IACV,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAS;IAChC,OAAO,CAAC,MAAM,CAAM;IAEpB,OAAO;IA4FP,OAAO,CAAC,KAAK;IAOb,OAAO,CAAC,QAAQ;WAIF,WAAW,CAAC,IAAI,GAAE,GAAQ,GAAG,MAAM;IAO1C,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,GAAE,GAAU,GAAG,GAAG;IAa/C,QAAQ,CACb,IAAI,EAAE,MAAM,EAAE,EACd,YAAY,GAAE,GAAU,EACxB,SAAS,GAAE,GAAmB,GAC7B,GAAG;WAUQ,GAAG,CACf,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,EACvB,YAAY,GAAE,GAAU,GACvB,GAAG;WAUQ,SAAS,IAAI,GAAG;WAIhB,eAAe,IAAI,MAAM,EAAE;CAmB1C;AAED,eAAe,MAAM,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Resolves the CI run identity from well-known environment variables, with
3
+ * a documented generic-CI fallback:
4
+ *
5
+ * - GitHub Actions: provider "github", run_id from GITHUB_RUN_ID, job_id
6
+ * from GITHUB_JOB (the job's key; matrix legs share it — pass
7
+ * --emit-envelope.run-job-id to disambiguate), attempt from
8
+ * GITHUB_RUN_ATTEMPT, url from the canonical run URL.
9
+ * - Any other CI / local runs: provider "generic", run_id = the git HEAD
10
+ * SHA, job_id null, attempt 1. The idempotency key is then the commit —
11
+ * a rerun of the same commit overwrites the same logical run.
12
+ */
13
+ export interface RunIdentity {
14
+ provider: string;
15
+ run_id: string;
16
+ job_id: string | null;
17
+ attempt: number;
18
+ url: string | null;
19
+ }
20
+ export declare function resolveRunIdentity(env: NodeJS.ProcessEnv, headSha: string): RunIdentity;
21
+ /** Commit facts from the git checkout. Requires a git repository. */
22
+ export declare function resolveCommitFacts(dir: string, headRef: string): Promise<{
23
+ sha: string;
24
+ branch: string;
25
+ committed_at: string | null;
26
+ }>;
27
+ //# sourceMappingURL=ci-env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ci-env.d.ts","sourceRoot":"","sources":["../../src/core/ci-env.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CACpB;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,EAAE,OAAO,EAAE,MAAM,GAAG,WAAW,CAqBvF;AAED,qEAAqE;AACrE,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,GACd,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,CA+BvE"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * The pinned copy of the canonical Elyseum v1 CI result envelope contract.
3
+ * The schema and fixtures are owned by the elyseum host repository and
4
+ * pinned here per the workspace pairing rule; `validateEnvelope` is the
5
+ * self-check every emitted envelope passes before it is written.
6
+ *
7
+ * Drift between this copy and the host's canonical file is a contract
8
+ * violation; the planned cross-repo contract checks (elyseum#14) will
9
+ * catch it in CI.
10
+ */
11
+ export declare const SUPPORTED_SCHEMA_VERSION = "1";
12
+ export interface EnvelopeV1 {
13
+ schema_version: "1";
14
+ producer: {
15
+ name: string;
16
+ version: string;
17
+ };
18
+ run: {
19
+ provider: string;
20
+ run_id: string;
21
+ job_id?: string | null;
22
+ attempt: number;
23
+ url?: string | null;
24
+ started_at?: string | null;
25
+ finished_at?: string | null;
26
+ };
27
+ commit: {
28
+ sha: string;
29
+ branch: string;
30
+ base_sha?: string | null;
31
+ committed_at?: string | null;
32
+ };
33
+ tests?: {
34
+ total?: number | null;
35
+ passed?: number | null;
36
+ failed?: number | null;
37
+ skipped?: number | null;
38
+ duration_ms?: number | null;
39
+ failed_tests?: {
40
+ name: string;
41
+ message?: string | null;
42
+ file?: string | null;
43
+ line?: number | null;
44
+ }[];
45
+ };
46
+ coverage?: {
47
+ line_percent?: number | null;
48
+ function_percent?: number | null;
49
+ branch_percent?: number | null;
50
+ diff_percent?: number | null;
51
+ files?: {
52
+ path: string;
53
+ line_percent?: number | null;
54
+ function_percent?: number | null;
55
+ branch_percent?: number | null;
56
+ }[];
57
+ };
58
+ quality_gate?: {
59
+ conclusion: "passed" | "failed" | "unknown";
60
+ };
61
+ [key: string]: unknown;
62
+ }
63
+ export interface EnvelopeIssue {
64
+ pointer: string;
65
+ message: string;
66
+ }
67
+ /** Validates an envelope against the pinned v1 schema. Pure. */
68
+ export declare function validateEnvelope(envelope: EnvelopeV1): EnvelopeIssue[];
69
+ //# sourceMappingURL=envelope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../../src/core/envelope.ts"],"names":[],"mappings":"AAGA;;;;;;;;;GASG;AAEH,eAAO,MAAM,wBAAwB,MAAM,CAAC;AAU5C,MAAM,WAAW,UAAU;IACzB,cAAc,EAAE,GAAG,CAAC;IACpB,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5C,GAAG,EAAE;QACH,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACvB,OAAO,EAAE,MAAM,CAAC;QAChB,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACpB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KAC7B,CAAC;IACF,MAAM,EAAE;QACN,GAAG,EAAE,MAAM,CAAC;QACZ,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KAC9B,CAAC;IACF,KAAK,CAAC,EAAE;QACN,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACvB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACvB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACxB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC5B,YAAY,CAAC,EAAE;YACb,IAAI,EAAE,MAAM,CAAC;YACb,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;YACxB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;YACrB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;SACtB,EAAE,CAAC;KACL,CAAC;IACF,QAAQ,CAAC,EAAE;QACT,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC7B,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACjC,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC/B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC7B,KAAK,CAAC,EAAE;YACN,IAAI,EAAE,MAAM,CAAC;YACb,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;YAC7B,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;YACjC,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;SAChC,EAAE,CAAC;KACL,CAAC;IACF,YAAY,CAAC,EAAE;QAAE,UAAU,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAA;KAAE,CAAC;IAC/D,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,gEAAgE;AAChE,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,UAAU,GAAG,aAAa,EAAE,CAUtE"}