@motivation-labs/crosscheck 0.4.0 → 0.4.1-beta.1216e4e.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.
- package/README.md +26 -9
- package/crosscheck.config.example.yml +98 -5
- package/dist/__tests__/backtrace.test.d.ts +2 -0
- package/dist/__tests__/backtrace.test.d.ts.map +1 -0
- package/dist/__tests__/backtrace.test.js +158 -0
- package/dist/__tests__/backtrace.test.js.map +1 -0
- package/dist/__tests__/loader.test.d.ts +2 -0
- package/dist/__tests__/loader.test.d.ts.map +1 -0
- package/dist/__tests__/loader.test.js +131 -0
- package/dist/__tests__/loader.test.js.map +1 -0
- package/dist/__tests__/optimize.test.js +16 -3
- package/dist/__tests__/optimize.test.js.map +1 -1
- package/dist/ck.d.ts +3 -0
- package/dist/ck.d.ts.map +1 -0
- package/dist/ck.js +8 -0
- package/dist/ck.js.map +1 -0
- package/dist/cli.js +12 -4
- package/dist/cli.js.map +1 -1
- package/dist/commands/diagnose.d.ts +1 -0
- package/dist/commands/diagnose.d.ts.map +1 -1
- package/dist/commands/diagnose.js +14 -0
- package/dist/commands/diagnose.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +63 -29
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/review.d.ts.map +1 -1
- package/dist/commands/review.js +12 -6
- package/dist/commands/review.js.map +1 -1
- package/dist/commands/serve.d.ts +7 -1
- package/dist/commands/serve.d.ts.map +1 -1
- package/dist/commands/serve.js +152 -34
- package/dist/commands/serve.js.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +1 -0
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/watch.d.ts +7 -1
- package/dist/commands/watch.d.ts.map +1 -1
- package/dist/commands/watch.js +348 -135
- package/dist/commands/watch.js.map +1 -1
- package/dist/config/loader.d.ts +10 -0
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +196 -0
- package/dist/config/loader.js.map +1 -1
- package/dist/config/schema.d.ts +461 -35
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +72 -5
- package/dist/config/schema.js.map +1 -1
- package/dist/github/client.d.ts +26 -0
- package/dist/github/client.d.ts.map +1 -1
- package/dist/github/client.js +159 -2
- package/dist/github/client.js.map +1 -1
- package/dist/github/detector.d.ts +9 -2
- package/dist/github/detector.d.ts.map +1 -1
- package/dist/github/detector.js +86 -10
- package/dist/github/detector.js.map +1 -1
- package/dist/lib/backtrace.d.ts +20 -0
- package/dist/lib/backtrace.d.ts.map +1 -0
- package/dist/lib/backtrace.js +75 -0
- package/dist/lib/backtrace.js.map +1 -0
- package/dist/lib/board.d.ts +54 -0
- package/dist/lib/board.d.ts.map +1 -0
- package/dist/lib/board.js +406 -0
- package/dist/lib/board.js.map +1 -0
- package/dist/lib/runner.d.ts +10 -1
- package/dist/lib/runner.d.ts.map +1 -1
- package/dist/lib/runner.js +129 -51
- package/dist/lib/runner.js.map +1 -1
- package/dist/lib/verdict.d.ts +1 -0
- package/dist/lib/verdict.d.ts.map +1 -1
- package/dist/lib/verdict.js +27 -7
- package/dist/lib/verdict.js.map +1 -1
- package/dist/lib/workflow.d.ts +14 -14
- package/dist/lib/workflow.d.ts.map +1 -1
- package/dist/lib/workflow.js +22 -5
- package/dist/lib/workflow.js.map +1 -1
- package/dist/reviewers/claude.d.ts +1 -1
- package/dist/reviewers/claude.d.ts.map +1 -1
- package/dist/reviewers/claude.js +4 -6
- package/dist/reviewers/claude.js.map +1 -1
- package/dist/reviewers/codex.d.ts +2 -2
- package/dist/reviewers/codex.d.ts.map +1 -1
- package/dist/reviewers/codex.js +6 -6
- package/dist/reviewers/codex.js.map +1 -1
- package/dist/reviewers/fix.d.ts +5 -0
- package/dist/reviewers/fix.d.ts.map +1 -0
- package/dist/reviewers/fix.js +87 -0
- package/dist/reviewers/fix.js.map +1 -0
- package/get-started.md +202 -23
- package/get-started.zh.md +2 -3
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -74,13 +74,15 @@ crosscheck watch
|
|
|
74
74
|
│ ├── clone PR branch │
|
|
75
75
|
│ ├── run reviewer (cross-vendor assignment) │
|
|
76
76
|
│ ├── post review comment │
|
|
77
|
-
│ └──
|
|
77
|
+
│ └── post-review auto-fix │
|
|
78
|
+
│ ├── authoring vendor reads review comment │
|
|
79
|
+
│ └── opens fix PR targeting original branch │
|
|
78
80
|
└────────────────────────────────────────────────────────────────┘
|
|
79
81
|
```
|
|
80
82
|
|
|
81
|
-
**Routing**
|
|
83
|
+
**Routing** uses a four-signal chain: PR body patterns → commit `Co-Authored-By:` trailers → branch prefix (`claude/` or `codex/`) → `author_routes` config fallback. `Generated with [Claude Code]` → Codex reviews. `Generated with [OpenAI Codex]` → Claude reviews. `allowed_authors` restricts reviews to your agent accounts.
|
|
82
84
|
|
|
83
|
-
**
|
|
85
|
+
**Post-review auto-fix** runs after the review when issues are found. The vendor that authored the PR (`fixer: same-as-author`) reads its own review comment and opens a new fix PR targeting the original branch. You review and merge the fix PR — the original PR then updates automatically. Controlled by `post_review.auto_fix` in your config.
|
|
84
86
|
|
|
85
87
|
**The feedback loop** closes via `crosscheck diagnose` → `crosscheck optimize`. Failure patterns and quality signals from `~/.crosscheck/logs/` feed back into improved reviewer instructions — no manual config editing required.
|
|
86
88
|
|
|
@@ -98,6 +100,7 @@ crosscheck watch
|
|
|
98
100
|
repos your-org/your-repo
|
|
99
101
|
mode cross-vendor
|
|
100
102
|
quality balanced
|
|
103
|
+
auto-fix on_issues · same-as-author · pull_request
|
|
101
104
|
config ./crosscheck.config.yml ← edit to change above
|
|
102
105
|
|
|
103
106
|
✓ tunnel ready: https://abc123.lhr.life
|
|
@@ -110,12 +113,14 @@ PR #47 opened: add retry logic for flaky network calls
|
|
|
110
113
|
review complete (12s)
|
|
111
114
|
posted → github.com/your-org/your-repo/pull/47
|
|
112
115
|
NEEDS WORK
|
|
116
|
+
auto-fix claude fixing...
|
|
117
|
+
fix PR #48 opened → github.com/your-org/your-repo/pull/48
|
|
113
118
|
|
|
114
|
-
PR #
|
|
119
|
+
PR #49 opened: implement caching layer
|
|
115
120
|
origin=codex reviewer=claude
|
|
116
121
|
claude reviewing... (18s)
|
|
117
122
|
review complete (18s)
|
|
118
|
-
posted → github.com/your-org/your-repo/pull/
|
|
123
|
+
posted → github.com/your-org/your-repo/pull/49
|
|
119
124
|
APPROVE
|
|
120
125
|
```
|
|
121
126
|
|
|
@@ -138,7 +143,7 @@ crosscheck impact [--money] # time saved, issues caught, code quality tr
|
|
|
138
143
|
|
|
139
144
|
## Configuration
|
|
140
145
|
|
|
141
|
-
|
|
146
|
+
Config lives at `~/.crosscheck/config.yml` by default — persistent across all projects, no per-repo file needed. Run `crosscheck init` to generate it. Project-local `crosscheck.config.yml` overrides the global config when present.
|
|
142
147
|
|
|
143
148
|
```yaml
|
|
144
149
|
# Which repos/orgs to watch (at least one required)
|
|
@@ -146,10 +151,10 @@ orgs:
|
|
|
146
151
|
- your-org # covers every repo in the org
|
|
147
152
|
|
|
148
153
|
# Only review PRs from these GitHub accounts
|
|
154
|
+
# Auto-filled with your login by `crosscheck init` or first `crosscheck watch`
|
|
149
155
|
routing:
|
|
150
156
|
allowed_authors:
|
|
151
|
-
- your-
|
|
152
|
-
- your-codex-bot-account
|
|
157
|
+
- your-github-login # auto-detected from gh auth
|
|
153
158
|
|
|
154
159
|
# Review depth
|
|
155
160
|
quality:
|
|
@@ -165,6 +170,16 @@ budget:
|
|
|
165
170
|
# smee — stable channel URL, queues events while offline
|
|
166
171
|
tunnel:
|
|
167
172
|
backend: localhost.run
|
|
173
|
+
|
|
174
|
+
# Post-review auto-fix — opens a fix PR when issues are found
|
|
175
|
+
post_review:
|
|
176
|
+
auto_fix:
|
|
177
|
+
enabled: true
|
|
178
|
+
trigger: on_issues # on_issues | always | never
|
|
179
|
+
min_severity: warning # error | warning | info
|
|
180
|
+
fixer: same-as-author # the vendor that wrote the PR also fixes it
|
|
181
|
+
delivery:
|
|
182
|
+
mode: pull_request # pull_request | commit | comment
|
|
168
183
|
```
|
|
169
184
|
|
|
170
185
|
Full configuration reference: [get-started.md](./get-started.md)
|
|
@@ -254,12 +269,14 @@ npm install -g smee-client
|
|
|
254
269
|
```
|
|
255
270
|
|
|
256
271
|
```yaml
|
|
257
|
-
# crosscheck
|
|
272
|
+
# ~/.crosscheck/config.yml
|
|
258
273
|
tunnel:
|
|
259
274
|
backend: smee
|
|
260
275
|
smee_channel: https://smee.io/your-channel-id
|
|
261
276
|
```
|
|
262
277
|
|
|
278
|
+
crosscheck registers the webhook automatically on first `watch` start — no manual webhook setup needed.
|
|
279
|
+
|
|
263
280
|
---
|
|
264
281
|
|
|
265
282
|
## Requirements
|
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
# This file is designed to be easily read and modified by coding agents.
|
|
3
3
|
# All fields are optional — crosscheck uses sensible defaults.
|
|
4
4
|
|
|
5
|
+
# ─── Deployment ──────────────────────────────────────────────────────────────
|
|
6
|
+
# Set automatically on first run of `crosscheck watch` or `crosscheck serve`.
|
|
7
|
+
# personal — monitor your own repos and orgs; review only PRs you author
|
|
8
|
+
# team — monitor org repos only; review all PRs from any author
|
|
9
|
+
# Absent = first-run prompt will ask you to choose.
|
|
10
|
+
# deployment: personal
|
|
11
|
+
|
|
5
12
|
# ─── Mode ────────────────────────────────────────────────────────────────────
|
|
6
13
|
# single-vendor: one AI reviews all PRs
|
|
7
14
|
# cross-vendor: each AI reviews the other's PRs (Claude ↔ Codex)
|
|
@@ -49,6 +56,15 @@ orgs:
|
|
|
49
56
|
- motivation-labs
|
|
50
57
|
- codatta
|
|
51
58
|
|
|
59
|
+
# ─── Users ───────────────────────────────────────────────────────────────────
|
|
60
|
+
# Monitor all repos owned by personal GitHub accounts (non-org).
|
|
61
|
+
# At startup, crosscheck enumerates each user's repos and registers webhooks.
|
|
62
|
+
# Useful when your AI agents open PRs across many personal repos.
|
|
63
|
+
# Combines with `orgs` and `repos` — all configured sources are additive.
|
|
64
|
+
# users:
|
|
65
|
+
# - beingzy # your personal account
|
|
66
|
+
# - my-agent-login # a bot account that pushes to its own repos
|
|
67
|
+
|
|
52
68
|
# ─── Repos ───────────────────────────────────────────────────────────────────
|
|
53
69
|
# Omit entirely to auto-detect from `git remote` (useful in watch mode)
|
|
54
70
|
# repos: still works for monitoring specific repos only
|
|
@@ -62,18 +78,41 @@ repos:
|
|
|
62
78
|
# ─── Routing ─────────────────────────────────────────────────────────────────
|
|
63
79
|
routing:
|
|
64
80
|
# Restrict reviews to PRs opened by these GitHub logins.
|
|
65
|
-
#
|
|
81
|
+
# Auto-filled with your login by `crosscheck init` or first `crosscheck watch`.
|
|
66
82
|
# Empty list = no author restriction (applies body-pattern check only).
|
|
67
83
|
# allowed_authors:
|
|
68
84
|
# - beingzy # your personal account (Claude Code runs as you)
|
|
69
85
|
# - my-org-bot # a dedicated bot account
|
|
70
86
|
|
|
71
|
-
#
|
|
87
|
+
# Author-based routing fallback — maps GitHub login → vendor origin.
|
|
88
|
+
# Used when no body pattern matches. Lets you skip the attribution footer requirement.
|
|
89
|
+
# beingzy: claude → PRs from beingzy treated as Claude-authored → Codex reviews them
|
|
90
|
+
# my-bot: codex → PRs from my-bot treated as Codex-authored → Claude reviews them
|
|
91
|
+
# author_routes:
|
|
92
|
+
# beingzy: claude
|
|
93
|
+
|
|
94
|
+
# Fallback reviewer when origin cannot be determined (no pattern/branch/route matched).
|
|
95
|
+
# 'auto' = pick whichever vendor is currently authenticated (codex first, then claude).
|
|
96
|
+
# 'codex' / 'claude' = always use that vendor.
|
|
97
|
+
# null = skip the PR (legacy cross-vendor behaviour).
|
|
98
|
+
fallback_reviewer: auto
|
|
99
|
+
|
|
100
|
+
# Branch-prefix routing — checked when body and commit patterns don't match.
|
|
101
|
+
# Agents should branch with these prefixes (claude/* and codex/*) so origin is
|
|
102
|
+
# always detectable even without attribution text in the PR body.
|
|
103
|
+
claude_branch_prefixes:
|
|
104
|
+
- "claude/"
|
|
105
|
+
codex_branch_prefixes:
|
|
106
|
+
- "codex/"
|
|
107
|
+
|
|
108
|
+
# Body and commit pattern matching — checked first, before branch prefix.
|
|
109
|
+
# Patterns are matched against both the PR body and commit messages (Co-Authored-By trailers).
|
|
72
110
|
codex_reviews_patterns:
|
|
73
|
-
- "Generated with \\[Claude Code\\]" #
|
|
111
|
+
- "Generated with \\[Claude Code\\]" # PR body attribution footer
|
|
112
|
+
- "Co-Authored-By: Claude" # commit trailer added by Claude Code
|
|
74
113
|
claude_reviews_patterns:
|
|
75
|
-
- "Generated with \\[OpenAI Codex\\]" #
|
|
76
|
-
- "Co-Authored-By: codex"
|
|
114
|
+
- "Generated with \\[OpenAI Codex\\]" # PR body attribution footer
|
|
115
|
+
- "Co-Authored-By: codex" # commit trailer added by Codex
|
|
77
116
|
|
|
78
117
|
# ─── Tunnel (watch mode only) ────────────────────────────────────────────────
|
|
79
118
|
# Controls how crosscheck watch receives GitHub webhook events on your laptop.
|
|
@@ -100,9 +139,63 @@ server:
|
|
|
100
139
|
webhook_path: /webhook
|
|
101
140
|
# pid_file: ~/.crosscheck/crosscheck.pid # for daemon management
|
|
102
141
|
|
|
142
|
+
# ─── Post-Review Auto-Fix ────────────────────────────────────────────────────
|
|
143
|
+
# After a CR completes, optionally dispatch the authoring agent to fix the issues.
|
|
144
|
+
#
|
|
145
|
+
# Complete loop:
|
|
146
|
+
# agent opens PR → opposite vendor reviews → authoring vendor fixes
|
|
147
|
+
# ↓
|
|
148
|
+
# fix PR opened targeting original branch
|
|
149
|
+
# ↓
|
|
150
|
+
# human reviews fix PR → merges → original PR updated
|
|
151
|
+
#
|
|
152
|
+
post_review:
|
|
153
|
+
auto_fix:
|
|
154
|
+
enabled: true
|
|
155
|
+
trigger: on_issues # on_issues | always | never
|
|
156
|
+
min_severity: warning # error | warning | info — skip cosmetic findings
|
|
157
|
+
|
|
158
|
+
# same-as-author: the vendor that wrote the PR also applies the fix (recommended)
|
|
159
|
+
# In cross-vendor mode: Claude wrote it → Claude fixes it, Codex wrote it → Codex fixes it
|
|
160
|
+
fixer: same-as-author # same-as-author | same-as-reviewer | codex | claude
|
|
161
|
+
|
|
162
|
+
delivery:
|
|
163
|
+
mode: pull_request # pull_request | commit | comment
|
|
164
|
+
# pull_request → fix PR targets the original branch; human approves before merge
|
|
165
|
+
# commit → fixes pushed directly onto the original PR branch
|
|
166
|
+
# comment → suggested fixes posted as review comments only
|
|
167
|
+
pr_title: "fix: address CR issues in #{original_pr_title}"
|
|
168
|
+
label: cr-autofix # GitHub label applied to the fix PR
|
|
169
|
+
|
|
170
|
+
# ─── Backtrace ───────────────────────────────────────────────────────────────
|
|
171
|
+
# On startup, scan all open PRs in the monitored scope and review any that have
|
|
172
|
+
# never received a [crosscheck] comment. Ensures coverage for PRs opened while
|
|
173
|
+
# crosscheck was offline or before it was first set up.
|
|
174
|
+
# backtrace:
|
|
175
|
+
# enabled: true # set to false to disable the startup scan entirely
|
|
176
|
+
|
|
103
177
|
# ─── Logs ────────────────────────────────────────────────────────────────────
|
|
104
178
|
# Structured debug logs written to ~/.crosscheck/logs/YYYY-MM-DD.ndjson
|
|
105
179
|
# Each line is a JSON object: { ts, level, event, ...context }
|
|
106
180
|
logs:
|
|
107
181
|
enabled: true
|
|
108
182
|
retention_days: 7 # delete files older than N days (min: 1, max: 30)
|
|
183
|
+
|
|
184
|
+
# ─── Display ─────────────────────────────────────────────────────────────────
|
|
185
|
+
# Terminal output theme for crosscheck watch.
|
|
186
|
+
# Override individual colors using chalk color names (red, green, blue, cyan,
|
|
187
|
+
# yellow, magenta, white, gray, dim, bold) or hex values (#rrggbb).
|
|
188
|
+
# display:
|
|
189
|
+
# theme:
|
|
190
|
+
# bar_fill: blue # filled █ segments on the PR size bar
|
|
191
|
+
# bar_empty: dim # empty ░ segments (all bars)
|
|
192
|
+
# cr_approve: green # CR bar + verdict label when APPROVE
|
|
193
|
+
# cr_needs_work: yellow # CR bar + verdict label when NEEDS WORK
|
|
194
|
+
# cr_block: red # CR bar + verdict label when BLOCK
|
|
195
|
+
# fix_fill: cyan # filled segments on the FIX bar
|
|
196
|
+
|
|
197
|
+
# ─── Backtrace ───────────────────────────────────────────────────────────────
|
|
198
|
+
# On startup, scan all open PRs in the monitored scope and review any that have
|
|
199
|
+
# never received a [crosscheck] comment.
|
|
200
|
+
# backtrace:
|
|
201
|
+
# enabled: true # set to false to disable the startup scan entirely
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backtrace.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/backtrace.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import { scanUnreviewedPRs, buildScopesFromConfig } from '../lib/backtrace.js';
|
|
3
|
+
import { ConfigSchema } from '../config/schema.js';
|
|
4
|
+
vi.mock('../github/client.js', () => ({
|
|
5
|
+
listOpenPRs: vi.fn(),
|
|
6
|
+
listOrgRepos: vi.fn(),
|
|
7
|
+
listUserRepos: vi.fn(),
|
|
8
|
+
prHasCrossCheckComment: vi.fn(),
|
|
9
|
+
}));
|
|
10
|
+
const { listOpenPRs, listOrgRepos, listUserRepos, prHasCrossCheckComment } = await import('../github/client.js');
|
|
11
|
+
const mockListOpenPRs = vi.mocked(listOpenPRs);
|
|
12
|
+
const mockListOrgRepos = vi.mocked(listOrgRepos);
|
|
13
|
+
const mockListUserRepos = vi.mocked(listUserRepos);
|
|
14
|
+
const mockPrHasCrossCheckComment = vi.mocked(prHasCrossCheckComment);
|
|
15
|
+
const defaultConfig = ConfigSchema.parse({});
|
|
16
|
+
function makePR(overrides = {}) {
|
|
17
|
+
return {
|
|
18
|
+
number: overrides.number ?? 1,
|
|
19
|
+
title: 'test PR',
|
|
20
|
+
author: overrides.author ?? 'alice',
|
|
21
|
+
headSha: 'abc123',
|
|
22
|
+
headRef: 'feat/thing',
|
|
23
|
+
headRepo: 'acme/api',
|
|
24
|
+
baseRef: 'main',
|
|
25
|
+
body: null,
|
|
26
|
+
createdAt: overrides.createdAt ?? '2025-01-01T00:00:00Z',
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
beforeEach(() => {
|
|
30
|
+
vi.clearAllMocks();
|
|
31
|
+
});
|
|
32
|
+
describe('scanUnreviewedPRs', () => {
|
|
33
|
+
it('returns empty result for empty scopes without calling any API', async () => {
|
|
34
|
+
const result = await scanUnreviewedPRs([], defaultConfig, 'token');
|
|
35
|
+
expect(result).toEqual({ queued: [], alreadyReviewed: 0, skippedAuthor: 0 });
|
|
36
|
+
expect(mockListOpenPRs).not.toHaveBeenCalled();
|
|
37
|
+
});
|
|
38
|
+
it('includes a PR with no [crosscheck] comment', async () => {
|
|
39
|
+
const scopes = [{ owner: 'acme', repo: 'api' }];
|
|
40
|
+
mockListOpenPRs.mockResolvedValue([makePR()]);
|
|
41
|
+
mockPrHasCrossCheckComment.mockResolvedValue(false);
|
|
42
|
+
const result = await scanUnreviewedPRs(scopes, defaultConfig, 'token');
|
|
43
|
+
expect(result.queued).toHaveLength(1);
|
|
44
|
+
expect(result.queued[0].number).toBe(1);
|
|
45
|
+
expect(result.alreadyReviewed).toBe(0);
|
|
46
|
+
expect(result.skippedAuthor).toBe(0);
|
|
47
|
+
});
|
|
48
|
+
it('excludes a PR that already has a [crosscheck] comment', async () => {
|
|
49
|
+
const scopes = [{ owner: 'acme', repo: 'api' }];
|
|
50
|
+
mockListOpenPRs.mockResolvedValue([makePR()]);
|
|
51
|
+
mockPrHasCrossCheckComment.mockResolvedValue(true);
|
|
52
|
+
const result = await scanUnreviewedPRs(scopes, defaultConfig, 'token');
|
|
53
|
+
expect(result.queued).toHaveLength(0);
|
|
54
|
+
expect(result.alreadyReviewed).toBe(1);
|
|
55
|
+
});
|
|
56
|
+
it('excludes a PR whose author is not in allowed_authors', async () => {
|
|
57
|
+
const config = ConfigSchema.parse({ routing: { allowed_authors: ['bob'] } });
|
|
58
|
+
const scopes = [{ owner: 'acme', repo: 'api' }];
|
|
59
|
+
mockListOpenPRs.mockResolvedValue([makePR({ author: 'alice' })]);
|
|
60
|
+
const result = await scanUnreviewedPRs(scopes, config, 'token');
|
|
61
|
+
expect(result.queued).toHaveLength(0);
|
|
62
|
+
expect(result.skippedAuthor).toBe(1);
|
|
63
|
+
expect(mockPrHasCrossCheckComment).not.toHaveBeenCalled();
|
|
64
|
+
});
|
|
65
|
+
it('includes all authors when allowed_authors is empty', async () => {
|
|
66
|
+
const scopes = [{ owner: 'acme', repo: 'api' }];
|
|
67
|
+
mockListOpenPRs.mockResolvedValue([makePR({ author: 'anyone' })]);
|
|
68
|
+
mockPrHasCrossCheckComment.mockResolvedValue(false);
|
|
69
|
+
const result = await scanUnreviewedPRs(scopes, defaultConfig, 'token');
|
|
70
|
+
expect(result.queued).toHaveLength(1);
|
|
71
|
+
});
|
|
72
|
+
it('sorts queued PRs oldest-first', async () => {
|
|
73
|
+
const scopes = [{ owner: 'acme', repo: 'api' }];
|
|
74
|
+
mockListOpenPRs.mockResolvedValue([
|
|
75
|
+
makePR({ number: 3, createdAt: '2025-03-01T00:00:00Z' }),
|
|
76
|
+
makePR({ number: 1, createdAt: '2025-01-01T00:00:00Z' }),
|
|
77
|
+
makePR({ number: 2, createdAt: '2025-02-01T00:00:00Z' }),
|
|
78
|
+
]);
|
|
79
|
+
mockPrHasCrossCheckComment.mockResolvedValue(false);
|
|
80
|
+
const result = await scanUnreviewedPRs(scopes, defaultConfig, 'token');
|
|
81
|
+
expect(result.queued.map(p => p.number)).toEqual([1, 2, 3]);
|
|
82
|
+
});
|
|
83
|
+
it('expands org scopes to individual repos', async () => {
|
|
84
|
+
const scopes = [{ org: 'acme' }];
|
|
85
|
+
mockListOrgRepos.mockResolvedValue([
|
|
86
|
+
{ owner: 'acme', name: 'api' },
|
|
87
|
+
{ owner: 'acme', name: 'frontend' },
|
|
88
|
+
]);
|
|
89
|
+
mockListOpenPRs.mockResolvedValue([]);
|
|
90
|
+
await scanUnreviewedPRs(scopes, defaultConfig, 'token');
|
|
91
|
+
expect(mockListOrgRepos).toHaveBeenCalledWith('acme', 'token');
|
|
92
|
+
expect(mockListOpenPRs).toHaveBeenCalledWith('acme', 'api', 'token');
|
|
93
|
+
expect(mockListOpenPRs).toHaveBeenCalledWith('acme', 'frontend', 'token');
|
|
94
|
+
});
|
|
95
|
+
it('continues scan when listOpenPRs throws for one repo', async () => {
|
|
96
|
+
const scopes = [
|
|
97
|
+
{ owner: 'acme', repo: 'broken' },
|
|
98
|
+
{ owner: 'acme', repo: 'working' },
|
|
99
|
+
];
|
|
100
|
+
mockListOpenPRs
|
|
101
|
+
.mockRejectedValueOnce(new Error('API error'))
|
|
102
|
+
.mockResolvedValueOnce([makePR()]);
|
|
103
|
+
mockPrHasCrossCheckComment.mockResolvedValue(false);
|
|
104
|
+
const result = await scanUnreviewedPRs(scopes, defaultConfig, 'token');
|
|
105
|
+
expect(result.queued).toHaveLength(1);
|
|
106
|
+
});
|
|
107
|
+
it('skips a PR when prHasCrossCheckComment throws', async () => {
|
|
108
|
+
const scopes = [{ owner: 'acme', repo: 'api' }];
|
|
109
|
+
mockListOpenPRs.mockResolvedValue([makePR()]);
|
|
110
|
+
mockPrHasCrossCheckComment.mockRejectedValue(new Error('API error'));
|
|
111
|
+
const result = await scanUnreviewedPRs(scopes, defaultConfig, 'token');
|
|
112
|
+
expect(result.queued).toHaveLength(0);
|
|
113
|
+
expect(result.alreadyReviewed).toBe(0);
|
|
114
|
+
});
|
|
115
|
+
it('handles mixed queued / already-reviewed / skipped in one scan', async () => {
|
|
116
|
+
const config = ConfigSchema.parse({ routing: { allowed_authors: ['alice', 'bob'] } });
|
|
117
|
+
const scopes = [{ owner: 'acme', repo: 'api' }];
|
|
118
|
+
mockListOpenPRs.mockResolvedValue([
|
|
119
|
+
makePR({ number: 1, author: 'alice' }), // queued
|
|
120
|
+
makePR({ number: 2, author: 'bob' }), // already reviewed
|
|
121
|
+
makePR({ number: 3, author: 'carol' }), // skipped (author)
|
|
122
|
+
]);
|
|
123
|
+
mockPrHasCrossCheckComment
|
|
124
|
+
.mockResolvedValueOnce(false) // PR 1
|
|
125
|
+
.mockResolvedValueOnce(true); // PR 2
|
|
126
|
+
const result = await scanUnreviewedPRs(scopes, config, 'token');
|
|
127
|
+
expect(result.queued).toHaveLength(1);
|
|
128
|
+
expect(result.queued[0].number).toBe(1);
|
|
129
|
+
expect(result.alreadyReviewed).toBe(1);
|
|
130
|
+
expect(result.skippedAuthor).toBe(1);
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
describe('buildScopesFromConfig', () => {
|
|
134
|
+
it('builds org and repo scopes from config', async () => {
|
|
135
|
+
const config = ConfigSchema.parse({
|
|
136
|
+
orgs: ['acme'],
|
|
137
|
+
repos: [{ owner: 'bob', name: 'myrepo' }],
|
|
138
|
+
});
|
|
139
|
+
const scopes = await buildScopesFromConfig(config, 'token');
|
|
140
|
+
expect(scopes).toContainEqual({ org: 'acme' });
|
|
141
|
+
expect(scopes).toContainEqual({ owner: 'bob', repo: 'myrepo' });
|
|
142
|
+
});
|
|
143
|
+
it('expands users to repo scopes', async () => {
|
|
144
|
+
const config = ConfigSchema.parse({ users: ['alice'] });
|
|
145
|
+
mockListUserRepos.mockResolvedValue([{ owner: 'alice', name: 'proj' }]);
|
|
146
|
+
const scopes = await buildScopesFromConfig(config, 'token');
|
|
147
|
+
expect(scopes).toContainEqual({ owner: 'alice', repo: 'proj' });
|
|
148
|
+
expect(mockListUserRepos).toHaveBeenCalledWith('alice', 'token');
|
|
149
|
+
});
|
|
150
|
+
it('continues when listUserRepos throws', async () => {
|
|
151
|
+
const config = ConfigSchema.parse({ users: ['alice'], orgs: ['acme'] });
|
|
152
|
+
mockListUserRepos.mockRejectedValue(new Error('API error'));
|
|
153
|
+
const scopes = await buildScopesFromConfig(config, 'token');
|
|
154
|
+
expect(scopes).toContainEqual({ org: 'acme' });
|
|
155
|
+
expect(scopes).not.toContainEqual(expect.objectContaining({ owner: 'alice' }));
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
//# sourceMappingURL=backtrace.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backtrace.test.js","sourceRoot":"","sources":["../../src/__tests__/backtrace.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/loader.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { mkdtempSync, writeFileSync, readFileSync, rmSync } from 'fs';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
import { tmpdir } from 'os';
|
|
5
|
+
import { patchAllowedAuthors } from '../config/loader.js';
|
|
6
|
+
let tmpDir;
|
|
7
|
+
beforeEach(() => { tmpDir = mkdtempSync(join(tmpdir(), 'crosscheck-loader-test-')); });
|
|
8
|
+
afterEach(() => { rmSync(tmpDir, { recursive: true, force: true }); });
|
|
9
|
+
function write(name, content) {
|
|
10
|
+
const p = join(tmpDir, name);
|
|
11
|
+
writeFileSync(p, content);
|
|
12
|
+
return p;
|
|
13
|
+
}
|
|
14
|
+
function read(p) {
|
|
15
|
+
return readFileSync(p, 'utf8');
|
|
16
|
+
}
|
|
17
|
+
describe('patchAllowedAuthors', () => {
|
|
18
|
+
// ── Case 1: commented-out placeholder ───────────────────────────────────
|
|
19
|
+
it('case 1 — uncomments placeholder block', () => {
|
|
20
|
+
const p = write('c1.yml', [
|
|
21
|
+
'mode: cross-vendor',
|
|
22
|
+
'routing:',
|
|
23
|
+
' # allowed_authors:',
|
|
24
|
+
' # - beingzy',
|
|
25
|
+
'',
|
|
26
|
+
].join('\n'));
|
|
27
|
+
expect(patchAllowedAuthors(p, 'alice')).toBe(true);
|
|
28
|
+
const out = read(p);
|
|
29
|
+
expect(out).toContain(' allowed_authors:\n - alice');
|
|
30
|
+
expect(out).not.toContain('# allowed_authors');
|
|
31
|
+
});
|
|
32
|
+
// ── Case 2: multi-line empty (key present, no entries) ──────────────────
|
|
33
|
+
it('case 2 — fills multi-line empty allowed_authors', () => {
|
|
34
|
+
const p = write('c2.yml', [
|
|
35
|
+
'routing:',
|
|
36
|
+
' allowed_authors:',
|
|
37
|
+
' codex_reviews_patterns: []',
|
|
38
|
+
'',
|
|
39
|
+
].join('\n'));
|
|
40
|
+
expect(patchAllowedAuthors(p, 'alice')).toBe(true);
|
|
41
|
+
expect(read(p)).toContain(' - alice');
|
|
42
|
+
});
|
|
43
|
+
it('case 2 — fills allowed_authors that has only comment lines', () => {
|
|
44
|
+
const p = write('c2b.yml', [
|
|
45
|
+
'routing:',
|
|
46
|
+
' allowed_authors:',
|
|
47
|
+
' # - somebot',
|
|
48
|
+
'',
|
|
49
|
+
].join('\n'));
|
|
50
|
+
expect(patchAllowedAuthors(p, 'alice')).toBe(true);
|
|
51
|
+
expect(read(p)).toContain(' - alice');
|
|
52
|
+
});
|
|
53
|
+
// ── Case 3: inline empty array ──────────────────────────────────────────
|
|
54
|
+
it('case 3 — fills allowed_authors: []', () => {
|
|
55
|
+
const p = write('c3a.yml', [
|
|
56
|
+
'routing:',
|
|
57
|
+
' allowed_authors: []',
|
|
58
|
+
'',
|
|
59
|
+
].join('\n'));
|
|
60
|
+
expect(patchAllowedAuthors(p, 'alice')).toBe(true);
|
|
61
|
+
const out = read(p);
|
|
62
|
+
expect(out).toContain(' allowed_authors:\n - alice');
|
|
63
|
+
expect(out).not.toContain('[]');
|
|
64
|
+
});
|
|
65
|
+
it('case 3 — fills allowed_authors: [ ] (with space)', () => {
|
|
66
|
+
const p = write('c3b.yml', [
|
|
67
|
+
'routing:',
|
|
68
|
+
' allowed_authors: [ ]',
|
|
69
|
+
'',
|
|
70
|
+
].join('\n'));
|
|
71
|
+
expect(patchAllowedAuthors(p, 'alice')).toBe(true);
|
|
72
|
+
expect(read(p)).toContain(' - alice');
|
|
73
|
+
});
|
|
74
|
+
// ── Case 4: routing: exists but no allowed_authors key ──────────────────
|
|
75
|
+
it('case 4 — appends allowed_authors after routing: when key is absent', () => {
|
|
76
|
+
const p = write('c4.yml', [
|
|
77
|
+
'mode: cross-vendor',
|
|
78
|
+
'routing:',
|
|
79
|
+
' codex_reviews_patterns: []',
|
|
80
|
+
'',
|
|
81
|
+
].join('\n'));
|
|
82
|
+
expect(patchAllowedAuthors(p, 'alice')).toBe(true);
|
|
83
|
+
const out = read(p);
|
|
84
|
+
expect(out).toContain(' allowed_authors:\n - alice');
|
|
85
|
+
});
|
|
86
|
+
// ── Case 5 (new): no routing: section at all ────────────────────────────
|
|
87
|
+
it('case 5 — appends routing block when no routing: section exists', () => {
|
|
88
|
+
const p = write('c5.yml', 'mode: cross-vendor\n');
|
|
89
|
+
expect(patchAllowedAuthors(p, 'alice')).toBe(true);
|
|
90
|
+
const out = read(p);
|
|
91
|
+
expect(out).toContain('routing:');
|
|
92
|
+
expect(out).toContain(' allowed_authors:');
|
|
93
|
+
expect(out).toContain(' - alice');
|
|
94
|
+
});
|
|
95
|
+
it('case 5 — works for completely minimal config (no trailing newline)', () => {
|
|
96
|
+
const p = write('c5b.yml', 'mode: cross-vendor');
|
|
97
|
+
expect(patchAllowedAuthors(p, 'bob')).toBe(true);
|
|
98
|
+
const out = read(p);
|
|
99
|
+
expect(out).toContain('routing:');
|
|
100
|
+
expect(out).toContain(' - bob');
|
|
101
|
+
});
|
|
102
|
+
it('case 5 — added routing block is valid YAML structure', () => {
|
|
103
|
+
const p = write('c5c.yml', 'mode: cross-vendor\n');
|
|
104
|
+
patchAllowedAuthors(p, 'alice');
|
|
105
|
+
const out = read(p);
|
|
106
|
+
// routing: must be a top-level key (no leading spaces)
|
|
107
|
+
expect(out).toMatch(/^routing:/m);
|
|
108
|
+
// allowed_authors must be indented under routing
|
|
109
|
+
expect(out).toMatch(/^ allowed_authors:/m);
|
|
110
|
+
// entry must be indented under allowed_authors
|
|
111
|
+
expect(out).toMatch(/^ - alice/m);
|
|
112
|
+
});
|
|
113
|
+
// ── Already-populated: should not modify ────────────────────────────────
|
|
114
|
+
it('returns false when allowed_authors already has entries', () => {
|
|
115
|
+
const p = write('populated.yml', [
|
|
116
|
+
'routing:',
|
|
117
|
+
' allowed_authors:',
|
|
118
|
+
' - existingbot',
|
|
119
|
+
'',
|
|
120
|
+
].join('\n'));
|
|
121
|
+
expect(patchAllowedAuthors(p, 'alice')).toBe(false);
|
|
122
|
+
expect(read(p)).not.toContain('alice');
|
|
123
|
+
});
|
|
124
|
+
// ── Login value ──────────────────────────────────────────────────────────
|
|
125
|
+
it('uses the provided login in the written entry', () => {
|
|
126
|
+
const p = write('login.yml', 'mode: cross-vendor\n');
|
|
127
|
+
patchAllowedAuthors(p, 'mybot');
|
|
128
|
+
expect(read(p)).toContain(' - mybot');
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
//# sourceMappingURL=loader.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.test.js","sourceRoot":"","sources":["../../src/__tests__/loader.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,18 +4,30 @@ function makeConfig(claudeEnabled, codexEnabled) {
|
|
|
4
4
|
return {
|
|
5
5
|
mode: 'cross-vendor',
|
|
6
6
|
orgs: [],
|
|
7
|
+
users: [],
|
|
7
8
|
repos: [],
|
|
8
|
-
routing: { codex_reviews_patterns: [], claude_reviews_patterns: [], allowed_authors: [] },
|
|
9
|
+
routing: { codex_reviews_patterns: [], claude_reviews_patterns: [], claude_branch_prefixes: [], codex_branch_prefixes: [], allowed_authors: [], author_routes: {}, fallback_reviewer: 'auto' },
|
|
9
10
|
server: { port: 7892, webhook_path: '/webhook' },
|
|
10
11
|
quality: { tier: 'balanced', focus: [], custom_prompt: undefined },
|
|
11
12
|
budget: { codex_monthly_usd: null, per_review_usd: 1 },
|
|
12
13
|
vendors: {
|
|
13
|
-
claude: { enabled: claudeEnabled, auth: 'subscription', effort: 'medium' },
|
|
14
|
-
codex: { enabled: codexEnabled, auth: 'subscription', effort: 'medium' },
|
|
14
|
+
claude: { enabled: claudeEnabled, model: null, auth: 'subscription', effort: 'medium' },
|
|
15
|
+
codex: { enabled: codexEnabled, model: null, auth: 'subscription', effort: 'medium', quality: 'medium' },
|
|
15
16
|
},
|
|
16
17
|
logs: { enabled: false, retention_days: 7 },
|
|
17
18
|
tunnel: { backend: 'localhost.run', smee_channel: '' },
|
|
18
19
|
impact: { assumed_human_review_minutes: 60, hourly_rate_usd: 150, defect_cost_usd: 150 },
|
|
20
|
+
backtrace: { enabled: true },
|
|
21
|
+
display: { theme: { bar_fill: 'blue', bar_empty: 'dim', cr_approve: 'green', cr_needs_work: 'yellow', cr_block: 'red', fix_fill: 'cyan' } },
|
|
22
|
+
post_review: {
|
|
23
|
+
auto_fix: {
|
|
24
|
+
enabled: false,
|
|
25
|
+
trigger: 'on_issues',
|
|
26
|
+
min_severity: 'warning',
|
|
27
|
+
fixer: 'same-as-author',
|
|
28
|
+
delivery: { mode: 'pull_request', pr_title: 'fix: address CR issues in #{original_pr_title}', label: 'cr-autofix' },
|
|
29
|
+
},
|
|
30
|
+
},
|
|
19
31
|
};
|
|
20
32
|
}
|
|
21
33
|
function makeReport(claudeAttempts = 0, claudeSuccesses = 0, codexAttempts = 0, codexSuccesses = 0) {
|
|
@@ -39,6 +51,7 @@ function makeReport(claudeAttempts = 0, claudeSuccesses = 0, codexAttempts = 0,
|
|
|
39
51
|
summary: { total_reviews: 0, successful: 0, failed: 0, failure_rate: 0 },
|
|
40
52
|
errors: [],
|
|
41
53
|
verdict_distribution: { APPROVE: 0, NEEDS_WORK: 0, BLOCK: 0 },
|
|
54
|
+
verdict_parse_failures: 0,
|
|
42
55
|
repos_seen: [],
|
|
43
56
|
languages_detected: [],
|
|
44
57
|
reviewer_performance: performance,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"optimize.test.js","sourceRoot":"","sources":["../../src/__tests__/optimize.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAA;AAI7D,SAAS,UAAU,CAAC,aAAsB,EAAE,YAAqB;IAC/D,OAAO;QACL,IAAI,EAAE,cAAc;QACpB,IAAI,EAAE,EAAE;QACR,KAAK,EAAE,EAAE;QACT,OAAO,EAAE,EAAE,sBAAsB,EAAE,EAAE,EAAE,uBAAuB,EAAE,EAAE,EAAE,eAAe,EAAE,EAAE,EAAE;
|
|
1
|
+
{"version":3,"file":"optimize.test.js","sourceRoot":"","sources":["../../src/__tests__/optimize.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAA;AAI7D,SAAS,UAAU,CAAC,aAAsB,EAAE,YAAqB;IAC/D,OAAO;QACL,IAAI,EAAE,cAAc;QACpB,IAAI,EAAE,EAAE;QACR,KAAK,EAAE,EAAE;QACT,KAAK,EAAE,EAAE;QACT,OAAO,EAAE,EAAE,sBAAsB,EAAE,EAAE,EAAE,uBAAuB,EAAE,EAAE,EAAE,sBAAsB,EAAE,EAAE,EAAE,qBAAqB,EAAE,EAAE,EAAE,eAAe,EAAE,EAAE,EAAE,aAAa,EAAE,EAAE,EAAE,iBAAiB,EAAE,MAAM,EAAE;QAC9L,MAAM,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,YAAY,EAAE,UAAU,EAAE;QAChD,OAAO,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,EAAE,aAAa,EAAE,SAAS,EAAE;QAClE,MAAM,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC,EAAE;QACtD,OAAO,EAAE;YACP,MAAM,EAAE,EAAE,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,QAAQ,EAAE;YACvF,KAAK,EAAE,EAAE,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE;SACzG;QACD,IAAI,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,EAAE;QAC3C,MAAM,EAAE,EAAE,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,EAAE,EAAE;QACtD,MAAM,EAAE,EAAE,4BAA4B,EAAE,EAAE,EAAE,eAAe,EAAE,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE;QACxF,SAAS,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;QAC5B,OAAO,EAAE,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE;QAC3I,WAAW,EAAE;YACX,QAAQ,EAAE;gBACR,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,WAAW;gBACpB,YAAY,EAAE,SAAS;gBACvB,KAAK,EAAE,gBAAgB;gBACvB,QAAQ,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,QAAQ,EAAE,gDAAgD,EAAE,KAAK,EAAE,YAAY,EAAE;aACpH;SACF;KACF,CAAA;AACH,CAAC;AAED,SAAS,UAAU,CACjB,cAAc,GAAG,CAAC,EAAE,eAAe,GAAG,CAAC,EACvC,aAAa,GAAG,CAAC,EAAE,cAAc,GAAG,CAAC;IAErC,MAAM,WAAW,GAAkF,EAAE,CAAA;IACrG,IAAI,cAAc,GAAG,CAAC,EAAE,CAAC;QACvB,WAAW,CAAC,QAAQ,CAAC,GAAG;YACtB,QAAQ,EAAE,cAAc;YACxB,SAAS,EAAE,eAAe;YAC1B,YAAY,EAAE,CAAC,cAAc,GAAG,eAAe,CAAC,GAAG,cAAc;SAClE,CAAA;IACH,CAAC;IACD,IAAI,aAAa,GAAG,CAAC,EAAE,CAAC;QACtB,WAAW,CAAC,OAAO,CAAC,GAAG;YACrB,QAAQ,EAAE,aAAa;YACvB,SAAS,EAAE,cAAc;YACzB,YAAY,EAAE,CAAC,aAAa,GAAG,cAAc,CAAC,GAAG,aAAa;SAC/D,CAAA;IACH,CAAC;IACD,OAAO;QACL,MAAM,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,EAAE;QAChD,OAAO,EAAE,EAAE,aAAa,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE;QACxE,MAAM,EAAE,EAAE;QACV,oBAAoB,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE;QAC7D,sBAAsB,EAAE,CAAC;QACzB,UAAU,EAAE,EAAE;QACd,kBAAkB,EAAE,EAAE;QACtB,oBAAoB,EAAE,WAAW;QACjC,WAAW,EAAE,EAAE;KAChB,CAAA;AACH,CAAC;AAED,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;IACnC,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QAClD,MAAM,EAAE,KAAK,EAAE,GAAG,mBAAmB,CAAC,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,UAAU,EAAE,CAAC,CAAA;QAC5E,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IAC7B,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,EAAE,KAAK,EAAE,GAAG,mBAAmB,CAAC,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,UAAU,EAAE,CAAC,CAAA;QAC5E,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IAC9B,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,6DAA6D,EAAE,GAAG,EAAE;QACrE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,mBAAmB,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,UAAU,EAAE,CAAC,CAAA;QACnF,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QAC5B,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;IACnC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,mEAAmE,EAAE,GAAG,EAAE;QAC3E,wBAAwB;QACxB,MAAM,EAAE,KAAK,EAAE,GAAG,mBAAmB,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAA;QACvF,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IAC7B,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,qEAAqE,EAAE,GAAG,EAAE;QAC7E,wBAAwB;QACxB,MAAM,EAAE,KAAK,EAAE,GAAG,mBAAmB,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAA;QACvF,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IAC9B,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,gEAAgE,EAAE,GAAG,EAAE;QACxE,WAAW;QACX,MAAM,EAAE,KAAK,EAAE,GAAG,mBAAmB,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAA;QACvF,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IAC9B,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,MAAM,CAAC,GAAG,EAAE,CAAC,mBAAmB,CAAC,UAAU,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAA;IACzG,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACpE,MAAM,EAAE,MAAM,EAAE,GAAG,mBAAmB,CAAC,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,UAAU,EAAE,CAAC,CAAA;QAC7E,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAA;IAC/C,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;QAClE,MAAM,EAAE,MAAM,EAAE,GAAG,mBAAmB,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAA;QACxF,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;QAC7B,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;IAC/B,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|