@weareikko/code-review 0.0.1 → 0.8.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 (66) hide show
  1. package/LICENSE +105 -0
  2. package/README.md +221 -0
  3. package/bin/code-review.js +7 -0
  4. package/dist/cli-w8sz3CYl.js +6375 -0
  5. package/dist/cli-w8sz3CYl.js.map +1 -0
  6. package/dist/cli.d.ts +56 -0
  7. package/dist/cli.d.ts.map +1 -0
  8. package/dist/cli.js +2 -0
  9. package/dist/config.d.ts +205 -0
  10. package/dist/config.d.ts.map +1 -0
  11. package/dist/diagnostics.d.ts +118 -0
  12. package/dist/diagnostics.d.ts.map +1 -0
  13. package/dist/diff-lines.d.ts +48 -0
  14. package/dist/diff-lines.d.ts.map +1 -0
  15. package/dist/errors.d.ts +69 -0
  16. package/dist/errors.d.ts.map +1 -0
  17. package/dist/fingerprints.d.ts +22 -0
  18. package/dist/fingerprints.d.ts.map +1 -0
  19. package/dist/git.d.ts +50 -0
  20. package/dist/git.d.ts.map +1 -0
  21. package/dist/github.d.ts +119 -0
  22. package/dist/github.d.ts.map +1 -0
  23. package/dist/gitlab-review.d.ts +210 -0
  24. package/dist/gitlab-review.d.ts.map +1 -0
  25. package/dist/gitlab.d.ts +98 -0
  26. package/dist/gitlab.d.ts.map +1 -0
  27. package/dist/logger.d.ts +10 -0
  28. package/dist/logger.d.ts.map +1 -0
  29. package/dist/otel.d.ts +111 -0
  30. package/dist/otel.d.ts.map +1 -0
  31. package/dist/parser.d.ts +27 -0
  32. package/dist/parser.d.ts.map +1 -0
  33. package/dist/payloads.d.ts +30 -0
  34. package/dist/payloads.d.ts.map +1 -0
  35. package/dist/platform.d.ts +71 -0
  36. package/dist/platform.d.ts.map +1 -0
  37. package/dist/platforms/github.d.ts +115 -0
  38. package/dist/platforms/github.d.ts.map +1 -0
  39. package/dist/platforms/gitlab.d.ts +26 -0
  40. package/dist/platforms/gitlab.d.ts.map +1 -0
  41. package/dist/posting.d.ts +108 -0
  42. package/dist/posting.d.ts.map +1 -0
  43. package/dist/prior-threads.d.ts +40 -0
  44. package/dist/prior-threads.d.ts.map +1 -0
  45. package/dist/product.d.ts +17 -0
  46. package/dist/product.d.ts.map +1 -0
  47. package/dist/review.d.ts +18 -0
  48. package/dist/review.d.ts.map +1 -0
  49. package/dist/review.js +2 -0
  50. package/dist/skills.d.ts +92 -0
  51. package/dist/skills.d.ts.map +1 -0
  52. package/dist/skipped-retrieval.d.ts +26 -0
  53. package/dist/skipped-retrieval.d.ts.map +1 -0
  54. package/dist/summary-carryover.d.ts +48 -0
  55. package/dist/summary-carryover.d.ts.map +1 -0
  56. package/dist/triage.d.ts +37 -0
  57. package/dist/triage.d.ts.map +1 -0
  58. package/dist/types.d.ts +95 -0
  59. package/dist/types.d.ts.map +1 -0
  60. package/dist/verify.d.ts +74 -0
  61. package/dist/verify.d.ts.map +1 -0
  62. package/package.json +90 -2
  63. package/skills/code-review/SKILL.md +112 -0
  64. package/skills/code-review/references/javascript-typescript.md +50 -0
  65. package/skills/code-review/references/php.md +46 -0
  66. package/skills/test-integrity/SKILL.md +76 -0
package/dist/cli.d.ts ADDED
@@ -0,0 +1,56 @@
1
+ import type { Config } from './config.js';
2
+ import { type DiagnosticContext } from './diagnostics.js';
3
+ import type { ReviewUsage } from './gitlab-review.js';
4
+ import type { OtelBridge } from './otel.js';
5
+ import { type ScmResponseInfo } from './platform.js';
6
+ import type { SummaryResult } from './posting.js';
7
+ import type { GeneratedComment, Severity } from './types.js';
8
+ export type { DiagnosticContext, DiagnosticError, DiagnosticPhase, DiagnosticUsage, DiagnosticUsageBreakdown, } from './diagnostics.js';
9
+ export { DIAGNOSTIC_CHANNEL_NAMES, DIAGNOSTIC_CHANNEL_PREFIX, createDiagnosticContext, createDiagnosticRunId, diagnosticChannels, traceDiagnostic, traceDiagnosticPhase, } from './diagnostics.js';
10
+ export type { OtelBridge, OtelBridgeOptions, OtelRuntime } from './otel.js';
11
+ export { isOtelEnabled, startOtelBridge } from './otel.js';
12
+ export interface RunResult {
13
+ generated: GeneratedComment[];
14
+ posted: number;
15
+ usage: ReviewUsage;
16
+ summary: SummaryResult | null;
17
+ skipped?: boolean;
18
+ }
19
+ export interface RunBridges {
20
+ /** Pre-started OTel bridge for per-turn and per-tool-call agent telemetry. */
21
+ otel?: OtelBridge;
22
+ }
23
+ export declare function run(config: Config, bridges?: RunBridges): Promise<RunResult>;
24
+ export declare function formatSkillsFooter(skills: string[]): string | undefined;
25
+ export declare function formatUsageLine(usage: ReviewUsage): string;
26
+ /**
27
+ * Render the per-model usage breakdown for heterogeneous `full`-depth runs: one
28
+ * indented line per pool member with its billable input / output tokens and
29
+ * cost. Returns `undefined` when there is no breakdown (single-model runs), so
30
+ * the caller prints nothing extra. Surfaces model ids and numbers only — never
31
+ * any key or secret.
32
+ */
33
+ export declare function formatPerModelUsage(usage: ReviewUsage): string | undefined;
34
+ /**
35
+ * Wraps a phase operation so the phase context gets HTTP semantic-convention
36
+ * attributes stamped from the most recent platform response — on both success
37
+ * and error paths. `readLastHttp` returns the platform's latest response holder;
38
+ * the wrapper snapshots it before the operation and only stamps when the
39
+ * operation's own request produced a *new* response, so a phase that threw
40
+ * before any HTTP call never inherits a previous phase's URL/status.
41
+ *
42
+ * Used by every traced platform phase, including the write phases
43
+ * (`scm.post_comments`, `scm.upsert_summary`) so a failure like a 500 on
44
+ * `bulk_publish` carries http.response.status_code / url.full / server.address.
45
+ */
46
+ export declare function withHttpStamping<T>(readLastHttp: () => ScmResponseInfo | undefined, operation: (context: DiagnosticContext) => Promise<T>): (context: DiagnosticContext) => Promise<T>;
47
+ /**
48
+ * Count the comments posted to the MR, grouped by severity. Duplicates are
49
+ * excluded since they are never posted. The total equals the new-comment count;
50
+ * in `draft` mode a concurrent run can race-delete some drafts before publish,
51
+ * so the breakdown reflects posted intent and may slightly exceed the published
52
+ * count in that rare case.
53
+ */
54
+ export declare function countPostedBySeverity(generated: GeneratedComment[]): Partial<Record<Severity, number>>;
55
+ export declare function main(argv?: string[]): Promise<void>;
56
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAO1C,OAAO,EAGL,KAAK,iBAAiB,EAEvB,MAAM,kBAAkB,CAAC;AAI1B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAG5C,OAAO,EAAkB,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAIlD,OAAO,KAAK,EAAE,gBAAgB,EAAE,QAAQ,EAAiB,MAAM,YAAY,CAAC;AAE5E,YAAY,EACV,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,eAAe,EACf,wBAAwB,GACzB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,wBAAwB,EACxB,yBAAyB,EACzB,uBAAuB,EACvB,qBAAqB,EACrB,kBAAkB,EAClB,eAAe,EACf,oBAAoB,GACrB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,UAAU,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAuE3D,MAAM,WAAW,SAAS;IACxB,SAAS,EAAE,gBAAgB,EAAE,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,EAAE,aAAa,GAAG,IAAI,CAAC;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAiBD,MAAM,WAAW,UAAU;IACzB,8EAA8E;IAC9E,IAAI,CAAC,EAAE,UAAU,CAAC;CACnB;AAuBD,wBAAsB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CA0SlF;AAaD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAGvE;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAoB1D;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,CAW1E;AAQD;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAChC,YAAY,EAAE,MAAM,eAAe,GAAG,SAAS,EAC/C,SAAS,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,OAAO,CAAC,CAAC,CAAC,GACpD,CAAC,OAAO,EAAE,iBAAiB,KAAK,OAAO,CAAC,CAAC,CAAC,CAU5C;AAsBD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,gBAAgB,EAAE,GAC5B,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAQnC;AAED,wBAAsB,IAAI,CAAC,IAAI,WAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CA2BtE"}
package/dist/cli.js ADDED
@@ -0,0 +1,2 @@
1
+ import { C as createDiagnosticContext, D as traceDiagnosticPhase, E as traceDiagnostic, S as DIAGNOSTIC_CHANNEL_PREFIX, T as diagnosticChannels, a as main, d as startOtelBridge, i as formatUsageLine, n as formatPerModelUsage, o as run, r as formatSkillsFooter, s as withHttpStamping, t as countPostedBySeverity, u as isOtelEnabled, w as createDiagnosticRunId, x as DIAGNOSTIC_CHANNEL_NAMES } from "./cli-w8sz3CYl.js";
2
+ export { DIAGNOSTIC_CHANNEL_NAMES, DIAGNOSTIC_CHANNEL_PREFIX, countPostedBySeverity, createDiagnosticContext, createDiagnosticRunId, diagnosticChannels, formatPerModelUsage, formatSkillsFooter, formatUsageLine, isOtelEnabled, main, run, startOtelBridge, traceDiagnostic, traceDiagnosticPhase, withHttpStamping };
@@ -0,0 +1,205 @@
1
+ import { type PostingMode } from './posting.js';
2
+ import { type ReviewDepth, type Severity, type ThinkingLevel } from './types.js';
3
+ export type GitLabAuthHeader = 'PRIVATE-TOKEN' | 'JOB-TOKEN';
4
+ /** Source-control backends the reviewer can target. */
5
+ export declare const PLATFORMS: readonly ["gitlab", "github"];
6
+ export type Platform = (typeof PLATFORMS)[number];
7
+ /** Default GitHub server (web) URL, honoring `GITHUB_SERVER_URL` on Enterprise. */
8
+ export declare const DEFAULT_GITHUB_SERVER_URL = "https://github.com";
9
+ /**
10
+ * The single source of truth for the tool's own `CODE_REVIEW_*` settings.
11
+ *
12
+ * Each entry is the suffix after the `CODE_REVIEW_` prefix (e.g. `MODEL` for
13
+ * `CODE_REVIEW_MODEL`). These are read directly across `config.ts`/`otel.ts`
14
+ * and must NEVER be de-prefixed by {@link applyCodeReviewEnvPrefix}.
15
+ *
16
+ * Note: `API_KEY` is reserved. `CODE_REVIEW_API_KEY` was intentionally retired
17
+ * as the AI provider key and must not be revived as one.
18
+ */
19
+ export declare const RESERVED_ENV_SUFFIXES: readonly ["API_KEY", "BASE_URL", "DECOMPOSE_HINT_LINES", "MAX_DIFF_CHARS", "MAX_TOKENS", "MIN_SEVERITY", "MODEL", "MODEL_POOL", "PLATFORM", "OTEL", "OTEL_CAPTURE_CONTENT", "POSTING_MODE", "POST_SUMMARY", "FORCE_REVIEW", "VERBOSE", "SKILLS", "REFRESH_SKILLS", "THINKING_LEVEL"];
20
+ /**
21
+ * Optional namespacing shim for provider/infra environment variables.
22
+ *
23
+ * For each `CODE_REVIEW_<NAME>` variable whose `<NAME>` is not a reserved tool
24
+ * setting (see {@link RESERVED_ENV_SUFFIXES}), this exposes `<NAME>` in the same
25
+ * env object. The prefixed value wins when both `CODE_REVIEW_<NAME>` and a
26
+ * plain `<NAME>` are set — the tool's scoped value should override an unrelated
27
+ * CI-wide variable of the same name.
28
+ *
29
+ * This lets credentials and infra vars that `@earendil-works/pi-ai` reads
30
+ * (`ANTHROPIC_API_KEY`, `CLOUDFLARE_API_KEY`, `CLOUDFLARE_ACCOUNT_ID`,
31
+ * `OLLAMA_HOST`, ambient AWS/Vertex creds, …) — and the GitLab tokens — be
32
+ * scoped under `CODE_REVIEW_` in shared CI without enumerating pi-ai's
33
+ * provider list.
34
+ *
35
+ * Must run once at startup BEFORE config/key resolution: `getEnvApiKey` and
36
+ * pi-ai's request-time reads both read `process.env` directly, so mutating it
37
+ * in-process is what makes those reads pick up the de-prefixed values.
38
+ *
39
+ * Empty prefixed values are ignored (treated as unset). Double-prefixed names
40
+ * (e.g. `CODE_REVIEW_CODE_REVIEW_MODEL`) are also skipped so a de-prefixed
41
+ * suffix can never clobber the tool's own reserved `CODE_REVIEW_*` settings.
42
+ *
43
+ * @returns the same `env` object it was given, mutated in place.
44
+ */
45
+ export declare function applyCodeReviewEnvPrefix(env?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
46
+ /**
47
+ * Default pi-ai's prompt-cache retention to `long` when the caller has not set
48
+ * it. pi-ai reads `PI_CACHE_RETENTION` from `process.env` at request time; `long`
49
+ * asks providers that support it (e.g. OpenAI's `openai-responses` API, including
50
+ * via the Cloudflare AI Gateway) to keep the cached system-prompt prefix for up
51
+ * to 24h so reviews spaced hours apart still reuse it. It is a safe no-op for
52
+ * providers/models without long-retention support (e.g. Anthropic), where it
53
+ * behaves exactly like the default `short`.
54
+ *
55
+ * Overridable: an explicit `PI_CACHE_RETENTION` (or `CODE_REVIEW_PI_CACHE_RETENTION`,
56
+ * mapped by {@link applyCodeReviewEnvPrefix} first) is left untouched.
57
+ */
58
+ export declare function applyDefaultCacheRetention(env?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
59
+ export interface Config {
60
+ /**
61
+ * The source-control backend to review against. Auto-detected from the
62
+ * environment by default (see {@link detectPlatform}); `--platform` /
63
+ * `CODE_REVIEW_PLATFORM` is an explicit override that always wins.
64
+ */
65
+ platform: Platform;
66
+ project: string;
67
+ mr: string;
68
+ gitlabUrl: string;
69
+ gitlabToken: string;
70
+ gitlabAuthHeader: GitLabAuthHeader;
71
+ /** `owner/repo` slug of the GitHub repository (`GITHUB_REPOSITORY`). */
72
+ githubRepository: string;
73
+ /** Pull-request number as a string, mirroring {@link Config.mr}. */
74
+ githubPr: string;
75
+ /** Token used for the GitHub REST API (`GITHUB_TOKEN` / `--github-token`). */
76
+ githubToken: string;
77
+ /** GitHub REST API base; defaults to {@link DEFAULT_GITHUB_API_URL}. */
78
+ githubApiUrl: string;
79
+ /** GitHub server (web) URL; defaults to {@link DEFAULT_GITHUB_SERVER_URL}. */
80
+ githubServerUrl: string;
81
+ model: string;
82
+ /**
83
+ * Optional pool of `provider/modelId` models for heterogeneous `full`-depth
84
+ * review. When non-empty, multi-angle Find maps each angle to a pool member and
85
+ * the adversarial verifier prefers a member other than the one that authored a
86
+ * finding. Empty (the default) means the effective pool is just `[model]`, which
87
+ * reproduces single-model behaviour byte-for-byte. Sourced from `--model-pool`
88
+ * or `CODE_REVIEW_MODEL_POOL` (comma-separated).
89
+ */
90
+ modelPool: string[];
91
+ minSeverity: Severity;
92
+ thinkingLevel: ThinkingLevel;
93
+ /**
94
+ * How many stages of the review pipeline run. `single` keeps the legacy
95
+ * single-pass behaviour; `verify` adds an adversarial Verify + Synthesize pass.
96
+ */
97
+ reviewDepth: ReviewDepth;
98
+ /**
99
+ * Optional `provider/modelId` for the Verify stage (`verify`/`full` depth). When
100
+ * set, every adversarial verifier runs on this model instead of the pool's
101
+ * cross-family pick — pairing a cheap, high-recall Find model with a strong,
102
+ * high-precision verifier. Empty (default) keeps the pool-based selection.
103
+ * Sourced from `--verify-model` or `CODE_REVIEW_VERIFY_MODEL`.
104
+ */
105
+ verifyModel: string;
106
+ postingMode: PostingMode;
107
+ apiKey: string;
108
+ /** Custom base URL for the AI provider API (e.g. Ollama or other OpenAI-compatible endpoints). */
109
+ baseUrl: string;
110
+ /** Maximum output tokens to request from the model. 0 uses the model's default. */
111
+ maxTokens: number;
112
+ /**
113
+ * Maximum cumulative diff characters sent to the reviewer. Files past this
114
+ * budget are dropped and surfaced as a size-skip callout. Defaults to 100_000.
115
+ */
116
+ maxDiffChars: number;
117
+ /**
118
+ * When > 0, an MR whose reviewed diff changes more lines than this threshold
119
+ * gets a "consider decomposing this MR" hint in the summary. 0 = off (default).
120
+ */
121
+ decomposeHintLines: number;
122
+ /**
123
+ * Lines of surrounding context per diff hunk (`git diff --unified`). More
124
+ * context helps the model reason about each change but inflates tokens and
125
+ * fits fewer files in the char budget; less context fits more files. 0 uses
126
+ * the built-in default. Sourced from `--diff-context` / `CODE_REVIEW_DIFF_CONTEXT`.
127
+ */
128
+ diffContext: number;
129
+ /**
130
+ * When true, diffs for files dropped by the char budget are staged on disk so
131
+ * the reviewer can read them on demand instead of losing them (retrieval mode).
132
+ * Default false. Sourced from `--retrieve-skipped` / `CODE_REVIEW_RETRIEVE_SKIPPED`.
133
+ */
134
+ retrieveSkipped: boolean;
135
+ reviewFile: string;
136
+ output: string;
137
+ dryRun: boolean;
138
+ noPost: boolean;
139
+ postSummary: boolean;
140
+ forceReview: boolean;
141
+ verbose: boolean;
142
+ cwd: string;
143
+ skills: string[];
144
+ /** Re-clone `git:` / `git+ssh:` skills, bypassing the on-disk clone cache. */
145
+ refreshGitSkills: boolean;
146
+ }
147
+ export type ParsedArgs = Record<string, string | boolean | string[]>;
148
+ export declare function parseArgs(argv: string[]): ParsedArgs;
149
+ /**
150
+ * Extract the provider name from a `"provider/modelId"` model string.
151
+ * Returns an empty string when the model string contains no slash.
152
+ */
153
+ export declare function parseModelProvider(model: string): string;
154
+ /**
155
+ * Resolve the API key for the given model's provider, delegating entirely to
156
+ * `@earendil-works/pi-ai`'s `getEnvApiKey`. That helper reads the provider's
157
+ * standard environment variable (e.g. `ANTHROPIC_API_KEY` / `ANTHROPIC_OAUTH_TOKEN`,
158
+ * `OPENAI_API_KEY`, `GEMINI_API_KEY`, `OPENROUTER_API_KEY`, …) and resolves
159
+ * ambient credentials (Amazon Bedrock, Google Vertex ADC). The key is therefore
160
+ * always provider-specific — a key for provider X is never used for provider Y.
161
+ *
162
+ * Ollama is a local OpenAI-compatible endpoint that needs no key, so a
163
+ * placeholder is returned. The `--api-key` flag takes precedence in
164
+ * `resolveConfig`.
165
+ *
166
+ * NOTE: `getEnvApiKey` reads `process.env` directly (not a passed-in env), so
167
+ * tests stub `process.env` or pass `--api-key` to control the resolved key.
168
+ */
169
+ export declare function resolveProviderApiKey(model: string): string;
170
+ /**
171
+ * Extract a pull-request number from a GitHub Actions event payload JSON string
172
+ * (the file `GITHUB_EVENT_PATH` points at). Prefers `.pull_request.number`, then
173
+ * the top-level `.number` (present on `issue_comment` events). Returns `''` when
174
+ * the JSON is unparsable or carries no number.
175
+ */
176
+ export declare function parsePrNumberFromEvent(json: string): string;
177
+ /**
178
+ * Extract a pull-request number from a `GITHUB_REF` of the form
179
+ * `refs/pull/<N>/merge` (or `/head`). Returns `''` for any other ref shape.
180
+ */
181
+ export declare function parsePrNumberFromRef(ref: string | undefined): string;
182
+ /**
183
+ * Resolve the GitHub pull-request number, in priority order: `--pr` flag, then
184
+ * the `GITHUB_EVENT_PATH` payload (`.pull_request.number` ?? `.number`), then a
185
+ * `refs/pull/<N>/merge` `GITHUB_REF`. Returns `''` when none apply.
186
+ */
187
+ export declare function resolveGitHubPr(args: ParsedArgs, env: NodeJS.ProcessEnv, readEventFile?: (path: string) => string | undefined): string;
188
+ /**
189
+ * Determine the review platform for this run.
190
+ *
191
+ * Precedence:
192
+ * 1. Explicit `--platform` / `CODE_REVIEW_PLATFORM` (throws on an unknown value).
193
+ * 2. CI markers: `GITHUB_ACTIONS === 'true'` → github; `GITLAB_CI === 'true'`
194
+ * or a present `CI_PROJECT_ID` / `CI_SERVER_URL` → gitlab.
195
+ * 3. Inference from which platform's required identifiers are present
196
+ * (`GITHUB_REPOSITORY` + a PR number vs. `CI_PROJECT_ID` + `CI_MERGE_REQUEST_IID`).
197
+ *
198
+ * Throws a {@link ConfigError} when both platforms' identifiers are present
199
+ * (ambiguous) or neither is (undetectable), with a hint to set `--platform`.
200
+ */
201
+ export declare function detectPlatform(args: ParsedArgs, env: NodeJS.ProcessEnv, readEventFile?: (path: string) => string | undefined): Platform;
202
+ export declare function resolveConfig(argv?: string[], env?: NodeJS.ProcessEnv): Config;
203
+ export declare function validateConfig(config: Config): void;
204
+ export { type Severity, type ThinkingLevel };
205
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,118 @@
1
+ import { type TracingChannel } from 'node:diagnostics_channel';
2
+ import type { Config } from './config.js';
3
+ import type { Severity } from './types.js';
4
+ export type DiagnosticPhase = 'run' | 'scm.get_merge_request' | 'scm.get_latest_version' | 'git.prepare_history' | 'git.get_merge_diff' | 'git.get_commit_log' | 'reviewer.run' | 'review.parse' | 'scm.get_discussions' | 'comments.build' | 'artifact.write_output' | 'scm.post_comments' | 'scm.upsert_summary';
5
+ export interface DiagnosticError {
6
+ name?: string;
7
+ message: string;
8
+ code?: string;
9
+ /** True when the failure was a deadline/abort, so the bridge can label it `timeout`. */
10
+ timeout?: boolean;
11
+ /**
12
+ * HTTP status code when the failure came from a GitLab API response (e.g. a
13
+ * 500 on `bulk_publish`). Propagates up the phase chain so the OTel bridge can
14
+ * refine `error.type` and label the error counter with the status.
15
+ */
16
+ status?: number;
17
+ }
18
+ /**
19
+ * Value-based secret redaction: removes the *known* secret values this run holds
20
+ * (the GitLab token and the provider API key) from a string, in every encoding
21
+ * they might appear under. Unlike pattern matching it cannot over-redact ordinary
22
+ * text, cannot miss a token because of its format, and uses literal replacement
23
+ * (no regex), so there is no catastrophic-backtracking risk on large messages.
24
+ */
25
+ export declare function scrubSecrets(input: string, secretValues: readonly string[]): string;
26
+ /** Collects the run's secret values (non-empty) for {@link scrubSecrets}. */
27
+ export declare function collectSecrets(config: Config): string[];
28
+ export interface DiagnosticUsageBreakdown {
29
+ input: number;
30
+ output: number;
31
+ cacheRead: number;
32
+ cacheWrite: number;
33
+ total: number;
34
+ }
35
+ export interface DiagnosticUsage {
36
+ model: string;
37
+ tokens: DiagnosticUsageBreakdown;
38
+ cost: DiagnosticUsageBreakdown;
39
+ }
40
+ export interface DiagnosticContext {
41
+ version: 1;
42
+ runId: string;
43
+ phase: DiagnosticPhase;
44
+ project: string;
45
+ mr: string;
46
+ gitlabUrl: string;
47
+ cwd: string;
48
+ model: string;
49
+ minSeverity: string;
50
+ dryRun: boolean;
51
+ noPost: boolean;
52
+ startedAt: string;
53
+ completedAt?: string;
54
+ durationMs?: number;
55
+ generated?: number;
56
+ newComments?: number;
57
+ duplicateComments?: number;
58
+ posted?: number;
59
+ /**
60
+ * Breakdown of posted comments by severity, populated on the `run` context so
61
+ * the OTel bridge can split `gitlab_review_comments_total` by severity. Counts
62
+ * the non-duplicate (posted-intent) comments; absent on dry-run/skip paths.
63
+ */
64
+ postedBySeverity?: Partial<Record<Severity, number>>;
65
+ warnings?: number;
66
+ /** Why the reviewer JSON could not be parsed, on the `review.parse` phase when it fails. */
67
+ malformedReason?: string;
68
+ reviewFile?: string;
69
+ output?: string;
70
+ /** Number of files in the merge diff (set on the `git.get_merge_diff` phase). */
71
+ diffFilesChanged?: number;
72
+ /** Added content lines in the merge diff. */
73
+ diffLinesAdded?: number;
74
+ /** Removed content lines in the merge diff. */
75
+ diffLinesRemoved?: number;
76
+ /** HTTP method of the GitLab API call traced by this phase. */
77
+ httpRequestMethod?: string;
78
+ /** Full URL of the (last) GitLab API request in this phase; carries no secrets. */
79
+ httpUrl?: string;
80
+ /** HTTP status code of the (last) GitLab API response in this phase. */
81
+ httpStatusCode?: number;
82
+ /** Response Content-Length in bytes, when present. */
83
+ httpResponseBodySize?: number;
84
+ /** Host of the GitLab server the request targeted. */
85
+ serverAddress?: string;
86
+ draftsAbandoned?: number;
87
+ draftsCreated?: number;
88
+ draftsDeletedPrePublish?: number;
89
+ draftsPublished?: number;
90
+ /** Drafts that could not be published on the per-draft fallback path (silent comment drops). */
91
+ draftsPublishFailed?: number;
92
+ summaryAction?: 'created' | 'updated' | 'skipped';
93
+ summaryNoteId?: number;
94
+ usage?: DiagnosticUsage;
95
+ errorInfo?: DiagnosticError;
96
+ }
97
+ export declare const DIAGNOSTIC_CHANNEL_PREFIX = "@weareikko/code-review";
98
+ export declare const DIAGNOSTIC_CHANNEL_NAMES: {
99
+ readonly run: "@weareikko/code-review:run";
100
+ readonly getMergeRequest: "@weareikko/code-review:scm.get_merge_request";
101
+ readonly getLatestVersion: "@weareikko/code-review:scm.get_latest_version";
102
+ readonly prepareGitHistory: "@weareikko/code-review:git.prepare_history";
103
+ readonly getMergeDiff: "@weareikko/code-review:git.get_merge_diff";
104
+ readonly getCommitLog: "@weareikko/code-review:git.get_commit_log";
105
+ readonly runReviewer: "@weareikko/code-review:reviewer.run";
106
+ readonly parseReview: "@weareikko/code-review:review.parse";
107
+ readonly getDiscussions: "@weareikko/code-review:scm.get_discussions";
108
+ readonly buildComments: "@weareikko/code-review:comments.build";
109
+ readonly writeOutput: "@weareikko/code-review:artifact.write_output";
110
+ readonly postComments: "@weareikko/code-review:scm.post_comments";
111
+ readonly upsertSummary: "@weareikko/code-review:scm.upsert_summary";
112
+ };
113
+ export declare const diagnosticChannels: Record<"buildComments" | "getCommitLog" | "getDiscussions" | "getLatestVersion" | "getMergeDiff" | "getMergeRequest" | "parseReview" | "postComments" | "prepareGitHistory" | "run" | "runReviewer" | "upsertSummary" | "writeOutput", TracingChannel<DiagnosticContext, DiagnosticContext>>;
114
+ export declare function createDiagnosticRunId(): string;
115
+ export declare function createDiagnosticContext(phase: DiagnosticPhase, config: Config, runId: string, overrides?: Partial<DiagnosticContext>): DiagnosticContext;
116
+ export declare function traceDiagnostic<T>(channel: TracingChannel<DiagnosticContext>, context: DiagnosticContext, operation: (context: DiagnosticContext) => Promise<T>, secretValues?: readonly string[]): Promise<T>;
117
+ export declare function traceDiagnosticPhase<T>(phase: DiagnosticPhase, config: Config, runId: string, operation: (context: DiagnosticContext) => Promise<T>, overrides?: Partial<DiagnosticContext>): Promise<T>;
118
+ //# sourceMappingURL=diagnostics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnostics.d.ts","sourceRoot":"","sources":["../src/diagnostics.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ import type { Side } from './types.js';
2
+ /**
3
+ * A diff line resolved to the old/new line numbers it maps to. GitLab consumes
4
+ * both (`old_line`/`new_line`); GitHub consumes one plus a `side`. Shared by both
5
+ * platforms so line resolution lives in one place.
6
+ */
7
+ export interface ResolvedDiffLine {
8
+ newLine?: number;
9
+ oldLine?: number;
10
+ }
11
+ /**
12
+ * Classify a target line in a unified diff into the old/new line numbers it maps
13
+ * to, tracking which side(s) apply:
14
+ * - an **added** line resolves to `newLine` only,
15
+ * - a **removed** line resolves to `oldLine` only,
16
+ * - an **unchanged (context)** line resolves to BOTH `oldLine` and `newLine`.
17
+ *
18
+ * GitLab needs both sides for context lines: a one-sided position is accepted by
19
+ * the draft-notes API but makes `bulk_publish` return 500 (GitLab skips position
20
+ * validation on draft creation — gitlab-org/gitlab#579609). GitHub uses a single
21
+ * `line` + `side`, taking `newLine`/`RIGHT` or `oldLine`/`LEFT`. We feed the
22
+ * reviewer ±20 lines of context, so it routinely anchors comments on unchanged
23
+ * lines; resolving them here is what lets both platforms place the comment.
24
+ *
25
+ * Returns `null` when the line is not part of the diff for `file`, so the caller
26
+ * can fall back (GitLab) or drop the comment (GitHub avoids a 422 on off-diff
27
+ * lines) rather than emit a position the platform cannot place.
28
+ */
29
+ export declare function resolveDiffLine(diff: string, file: string, target: number, side: Side): ResolvedDiffLine | null;
30
+ /** Context lines GitHub renders around each hunk change in a PR diff by default. */
31
+ export declare const GITHUB_DIFF_CONTEXT = 3;
32
+ /**
33
+ * True when the context line `target` (on `side`) is within `maxDistance` rows
34
+ * of the nearest added/removed line in its hunk.
35
+ *
36
+ * The reviewer runs against our LOCAL merge diff, generated with a wide context
37
+ * (`--unified=20`, see `git.ts`), so it routinely anchors findings on unchanged
38
+ * lines up to 20 rows from a change. GitHub's PR diff, however, shows only 3
39
+ * context lines: a review comment on a line outside GitHub's diff gets a 422,
40
+ * and because the review is posted as one atomic batch, a single 422 sinks every
41
+ * inline comment. This lets the GitHub payload builder drop such an off-diff
42
+ * context line (returning `null`) instead of 422-ing the whole review.
43
+ *
44
+ * Only meaningful for context lines (added/removed lines are always inside
45
+ * GitHub's diff); the caller checks that before calling.
46
+ */
47
+ export declare function contextLineWithinGitHubDiff(diff: string, file: string, target: number, side: Side, maxDistance?: number): boolean;
48
+ //# sourceMappingURL=diff-lines.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-lines.d.ts","sourceRoot":"","sources":["../src/diff-lines.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAoBD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,IAAI,GACT,gBAAgB,GAAG,IAAI,CAyCzB;AAED,oFAAoF;AACpF,eAAO,MAAM,mBAAmB,IAAI,CAAC;AAErC;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,IAAI,EACV,WAAW,SAAsB,GAChC,OAAO,CAqDT"}
@@ -0,0 +1,69 @@
1
+ export type ErrorCode = 'CONFIG_ERROR' | 'GITLAB_API_ERROR' | 'GITHUB_API_ERROR' | 'GIT_ERROR' | 'REVIEWER_ERROR' | 'PARSE_ERROR' | 'RUNTIME_ERROR';
2
+ export interface GitlabReviewErrorOptions extends ErrorOptions {
3
+ code: ErrorCode;
4
+ hint?: string;
5
+ /**
6
+ * Marks a deadline-exceeded failure. The CLI's `code` taxonomy stays coarse
7
+ * (one code per subsystem), so timeouts are flagged here rather than via a
8
+ * separate code; the OTel bridge reads it to label runs `status=timeout`.
9
+ */
10
+ timeout?: boolean;
11
+ /**
12
+ * Marks a provider credit/quota-exhaustion failure (e.g. HTTP 402). The review
13
+ * could not run for reasons outside the MR's control, so the CLI treats it as
14
+ * a non-fatal skip (warn, exit 0) rather than failing the pipeline.
15
+ */
16
+ quotaExceeded?: boolean;
17
+ }
18
+ export declare class GitlabReviewError extends Error {
19
+ readonly code: ErrorCode;
20
+ readonly hint?: string;
21
+ readonly timeout: boolean;
22
+ readonly quotaExceeded: boolean;
23
+ constructor(message: string, options: GitlabReviewErrorOptions);
24
+ }
25
+ /** True when `message` looks like a provider credit/quota-exhaustion error. */
26
+ export declare function isQuotaExceededMessage(message: string | undefined): boolean;
27
+ /** True when `error` is (or reports) a provider credit/quota-exhaustion failure. */
28
+ export declare function isQuotaExceededError(error: unknown): boolean;
29
+ export declare class ConfigError extends GitlabReviewError {
30
+ constructor(message: string, options?: Omit<GitlabReviewErrorOptions, 'code'>);
31
+ }
32
+ export declare class GitLabApiError extends GitlabReviewError {
33
+ readonly method: string;
34
+ readonly path: string;
35
+ readonly status?: number;
36
+ readonly responseBody?: string;
37
+ constructor(message: string, options: Omit<GitlabReviewErrorOptions, 'code'> & {
38
+ method: string;
39
+ path: string;
40
+ status?: number;
41
+ responseBody?: string;
42
+ });
43
+ }
44
+ export declare class GitHubApiError extends GitlabReviewError {
45
+ readonly method: string;
46
+ readonly path: string;
47
+ readonly status?: number;
48
+ readonly responseBody?: string;
49
+ constructor(message: string, options: Omit<GitlabReviewErrorOptions, 'code'> & {
50
+ method: string;
51
+ path: string;
52
+ status?: number;
53
+ responseBody?: string;
54
+ });
55
+ }
56
+ export declare class GitError extends GitlabReviewError {
57
+ constructor(message: string, options?: Omit<GitlabReviewErrorOptions, 'code'>);
58
+ }
59
+ export declare class ReviewerError extends GitlabReviewError {
60
+ constructor(message: string, options?: Omit<GitlabReviewErrorOptions, 'code'>);
61
+ }
62
+ export declare class ParseError extends GitlabReviewError {
63
+ constructor(message: string, options?: Omit<GitlabReviewErrorOptions, 'code'>);
64
+ }
65
+ export declare class RuntimeError extends GitlabReviewError {
66
+ constructor(message: string, options?: Omit<GitlabReviewErrorOptions, 'code'>);
67
+ }
68
+ export declare function formatError(error: unknown): string;
69
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { Discussion } from './gitlab.js';
2
+ import type { Fingerprints, ReviewComment, Side } from './types.js';
3
+ /**
4
+ * Pattern source for the hidden fingerprint marker, capturing the hash group.
5
+ * Shared with the parser and prior-thread detection so the marker format is
6
+ * defined in one place; each call site builds its own RegExp with the flags it
7
+ * needs (the capture group is harmless when only stripping or testing). This is
8
+ * a stable wire contract — see CLAUDE.md before changing it.
9
+ *
10
+ * Reads match BOTH the current `code-review:` prefix and the legacy
11
+ * `gitlab-review:` prefix so findings posted under the old product identity are
12
+ * still recognised and deduplicated after the rename. Writes emit the current
13
+ * prefix (see {@link appendFingerprintMarkers}).
14
+ */
15
+ export declare const FINGERPRINT_MARKER_PATTERN: string;
16
+ export declare function sha256(input: string): string;
17
+ export declare function normalizeBody(body: string): string;
18
+ export declare function extractDiffHunkContext(diff: string, file: string, line: number, side: Side): string;
19
+ export declare function fingerprints(comment: ReviewComment, hunkContext: string): Fingerprints;
20
+ export declare function appendFingerprintMarkers(body: string, fp: Fingerprints): string;
21
+ export declare function extractExistingFingerprints(discussions: Discussion[]): Set<string>;
22
+ //# sourceMappingURL=fingerprints.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fingerprints.d.ts","sourceRoot":"","sources":["../src/fingerprints.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEpE;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,0BAA0B,QAAuG,CAAC;AAI/I,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE5C;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAsCD,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,IAAI,GACT,MAAM,CAqCR;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,GAAG,YAAY,CAetF;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,YAAY,GAAG,MAAM,CAE/E;AAED,wBAAgB,2BAA2B,CAAC,WAAW,EAAE,UAAU,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC,CAUlF"}
package/dist/git.d.ts ADDED
@@ -0,0 +1,50 @@
1
+ export interface GitOptions {
2
+ cwd?: string;
3
+ }
4
+ export interface PrepareGitHistoryOptions extends GitOptions {
5
+ remote?: string;
6
+ codeQualityArtifacts?: string[];
7
+ }
8
+ export declare function git(args: string[], options?: GitOptions): Promise<string>;
9
+ export declare function getMergeDiffArguments(targetBranch: string, options?: {
10
+ remote?: string;
11
+ context?: number;
12
+ }): string[];
13
+ /**
14
+ * Full git argv for the merge diff. `-c core.quotepath=false` keeps non-ASCII
15
+ * paths literal instead of git's default octal-escaped + double-quoted form
16
+ * (`"a/caf\303\251.ts"`), which the comment-position parser cannot match —
17
+ * leaving such comments with invalid one-sided positions that 500 on
18
+ * `bulk_publish`. Diffing literally also gives the reviewer readable paths.
19
+ */
20
+ export declare function getMergeDiffCommand(targetBranch: string, options?: {
21
+ remote?: string;
22
+ context?: number;
23
+ }): string[];
24
+ export declare function removeGeneratedCodeQualityArtifacts(paths?: string[], options?: GitOptions): Promise<string[]>;
25
+ export declare function prepareGitHistory(sourceBranch: string, targetBranch: string, options?: PrepareGitHistoryOptions): Promise<void>;
26
+ export declare function getMergeDiff(targetBranch: string, options?: GitOptions & {
27
+ remote?: string;
28
+ context?: number;
29
+ }): Promise<string>;
30
+ export declare function getMergeCommitLogArguments(targetBranch: string, options?: {
31
+ remote?: string;
32
+ }): string[];
33
+ export declare function getMergeCommitLog(targetBranch: string, options?: GitOptions & {
34
+ remote?: string;
35
+ }): Promise<string>;
36
+ export interface DiffSummary {
37
+ filesChanged: number;
38
+ linesAdded: number;
39
+ linesRemoved: number;
40
+ }
41
+ /**
42
+ * Summarize a unified diff into file/line counts for telemetry. Counts one file
43
+ * per `diff --git` header and counts `+`/`-` lines only inside a hunk (after a
44
+ * `@@` header), so the `--- a/file` / `+++ b/file` header lines are excluded and
45
+ * a genuine content line whose text starts with `++`/`--` is still counted. Pure
46
+ * and allocation-light so it can run on the full merge diff without an extra git
47
+ * invocation.
48
+ */
49
+ export declare function summarizeDiff(diff: string): DiffSummary;
50
+ //# sourceMappingURL=git.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,UAAU;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,wBAAyB,SAAQ,UAAU;IAC1D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;CACjC;AAgBD,wBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,GAAE,UAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAanF;AAMD,wBAAgB,qBAAqB,CACnC,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GAClD,MAAM,EAAE,CAIV;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GAClD,MAAM,EAAE,CAEV;AAkBD,wBAAsB,mCAAmC,CACvD,KAAK,WAAgC,EACrC,OAAO,GAAE,UAAe,GACvB,OAAO,CAAC,MAAM,EAAE,CAAC,CAanB;AAED,wBAAsB,iBAAiB,CACrC,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,IAAI,CAAC,CAoCf;AAED,wBAAsB,YAAY,CAChC,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE,UAAU,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/D,OAAO,CAAC,MAAM,CAAC,CAEjB;AAED,wBAAgB,0BAA0B,CACxC,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAO,GAChC,MAAM,EAAE,CAQV;AAED,wBAAsB,iBAAiB,CACrC,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE,UAAU,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAO,GAC7C,OAAO,CAAC,MAAM,CAAC,CAEjB;AAED,MAAM,WAAW,WAAW;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAkBvD"}