council-review 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +374 -0
- package/dist/bin.d.ts +3 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +19 -0
- package/dist/bin.js.map +1 -0
- package/dist/cli.d.ts +14 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +829 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +61 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +235 -0
- package/dist/config.js.map +1 -0
- package/dist/herdr.d.ts +36 -0
- package/dist/herdr.d.ts.map +1 -0
- package/dist/herdr.js +196 -0
- package/dist/herdr.js.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -0
- package/dist/levels.d.ts +9 -0
- package/dist/levels.d.ts.map +1 -0
- package/dist/levels.js +19 -0
- package/dist/levels.js.map +1 -0
- package/dist/merge.d.ts +90 -0
- package/dist/merge.d.ts.map +1 -0
- package/dist/merge.js +441 -0
- package/dist/merge.js.map +1 -0
- package/dist/node-guard.d.ts +9 -0
- package/dist/node-guard.d.ts.map +1 -0
- package/dist/node-guard.js +21 -0
- package/dist/node-guard.js.map +1 -0
- package/dist/panel.d.ts +89 -0
- package/dist/panel.d.ts.map +1 -0
- package/dist/panel.js +275 -0
- package/dist/panel.js.map +1 -0
- package/dist/picker.d.ts +24 -0
- package/dist/picker.d.ts.map +1 -0
- package/dist/picker.js +182 -0
- package/dist/picker.js.map +1 -0
- package/dist/providers.d.ts +66 -0
- package/dist/providers.d.ts.map +1 -0
- package/dist/providers.js +544 -0
- package/dist/providers.js.map +1 -0
- package/dist/report.d.ts +116 -0
- package/dist/report.d.ts.map +1 -0
- package/dist/report.js +493 -0
- package/dist/report.js.map +1 -0
- package/dist/resolve.d.ts +58 -0
- package/dist/resolve.d.ts.map +1 -0
- package/dist/resolve.js +147 -0
- package/dist/resolve.js.map +1 -0
- package/dist/reviewer-spawn.d.ts +67 -0
- package/dist/reviewer-spawn.d.ts.map +1 -0
- package/dist/reviewer-spawn.js +94 -0
- package/dist/reviewer-spawn.js.map +1 -0
- package/dist/reviewer-tools.d.ts +113 -0
- package/dist/reviewer-tools.d.ts.map +1 -0
- package/dist/reviewer-tools.js +557 -0
- package/dist/reviewer-tools.js.map +1 -0
- package/dist/runner.d.ts +79 -0
- package/dist/runner.d.ts.map +1 -0
- package/dist/runner.js +811 -0
- package/dist/runner.js.map +1 -0
- package/dist/schema.d.ts +63 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +302 -0
- package/dist/schema.js.map +1 -0
- package/dist/scope.d.ts +40 -0
- package/dist/scope.d.ts.map +1 -0
- package/dist/scope.js +372 -0
- package/dist/scope.js.map +1 -0
- package/dist/snapshot.d.ts +57 -0
- package/dist/snapshot.d.ts.map +1 -0
- package/dist/snapshot.js +471 -0
- package/dist/snapshot.js.map +1 -0
- package/dist/status.d.ts +90 -0
- package/dist/status.d.ts.map +1 -0
- package/dist/status.js +336 -0
- package/dist/status.js.map +1 -0
- package/dist/thinking.d.ts +53 -0
- package/dist/thinking.d.ts.map +1 -0
- package/dist/thinking.js +116 -0
- package/dist/thinking.js.map +1 -0
- package/package.json +81 -0
- package/src/bin.ts +20 -0
- package/src/cli.ts +996 -0
- package/src/config.ts +338 -0
- package/src/herdr.ts +231 -0
- package/src/index.ts +30 -0
- package/src/levels.ts +23 -0
- package/src/merge.ts +548 -0
- package/src/node-guard.ts +25 -0
- package/src/panel.ts +354 -0
- package/src/picker.ts +230 -0
- package/src/providers.ts +778 -0
- package/src/report.ts +594 -0
- package/src/resolve.ts +179 -0
- package/src/reviewer-spawn.ts +131 -0
- package/src/reviewer-tools.ts +715 -0
- package/src/runner.ts +1120 -0
- package/src/schema.ts +373 -0
- package/src/scope.ts +448 -0
- package/src/snapshot.ts +536 -0
- package/src/status.ts +470 -0
- package/src/thinking.ts +148 -0
package/dist/picker.js
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Three-stage interactive panel selection: providers, then models scoped to those providers,
|
|
3
|
+
* then a thinking level per selected reasoning model. See `openspec/changes/add-council-review/
|
|
4
|
+
* specs/council-review/panel-selection/spec.md`'s "Staged interactive selection" requirement.
|
|
5
|
+
*
|
|
6
|
+
* This module never writes configuration itself — it only resolves a `Reviewer[]`. The caller
|
|
7
|
+
* (`cli.ts`) is what persists a panel, which is what makes "cancelling writes nothing" true by
|
|
8
|
+
* construction rather than by a save/rollback dance in here. It also never runs the
|
|
9
|
+
* vendor-independence guard: that is `panel.ts`'s `enforceIndependence`, called by the CLI once
|
|
10
|
+
* selection finishes and again immediately before launch.
|
|
11
|
+
*/
|
|
12
|
+
import { PassThrough } from 'node:stream';
|
|
13
|
+
import { checkbox, select } from '@inquirer/prompts';
|
|
14
|
+
import { resolveThinking, supportedLevels } from './thinking.js';
|
|
15
|
+
export class PickerCancelled extends Error {
|
|
16
|
+
exitCode = 2;
|
|
17
|
+
constructor(message = 'selection cancelled; no configuration was written') {
|
|
18
|
+
super(message);
|
|
19
|
+
this.name = 'PickerCancelled';
|
|
20
|
+
Object.setPrototypeOf(this, PickerCancelled.prototype);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export class PickerNonInteractive extends Error {
|
|
24
|
+
exitCode = 2;
|
|
25
|
+
constructor(message) {
|
|
26
|
+
super(message);
|
|
27
|
+
this.name = 'PickerNonInteractive';
|
|
28
|
+
Object.setPrototypeOf(this, PickerNonInteractive.prototype);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* `@inquirer/prompts` rejects with `ExitPromptError` on Ctrl+C / SIGINT / a closed input stream,
|
|
33
|
+
* and with `CancelPromptError` when a prompt's own `context.signal` (not used here) fires. Both
|
|
34
|
+
* are checked by `.name` rather than `instanceof` against an imported class, because
|
|
35
|
+
* `@inquirer/core` is a transitive dependency of `@inquirer/prompts` — this package depends only
|
|
36
|
+
* on the latter, per the contract's "do not edit package.json" rule.
|
|
37
|
+
*/
|
|
38
|
+
function isCancellation(err) {
|
|
39
|
+
return (err instanceof Error && (err.name === 'ExitPromptError' || err.name === 'CancelPromptError'));
|
|
40
|
+
}
|
|
41
|
+
function defaultIO() {
|
|
42
|
+
return {
|
|
43
|
+
input: process.stdin,
|
|
44
|
+
output: process.stdout,
|
|
45
|
+
isTTY: process.stdin.isTTY === true,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function formatTokenCount(n) {
|
|
49
|
+
if (n === null)
|
|
50
|
+
return '?';
|
|
51
|
+
if (n >= 1_000_000)
|
|
52
|
+
return `${(n / 1_000_000).toFixed(1)}M`;
|
|
53
|
+
if (n >= 1_000)
|
|
54
|
+
return `${(n / 1_000).toFixed(1)}K`;
|
|
55
|
+
return String(n);
|
|
56
|
+
}
|
|
57
|
+
function formatCostRate(n) {
|
|
58
|
+
return n === null ? '?' : `$${n}`;
|
|
59
|
+
}
|
|
60
|
+
function providerChoiceLabel(p) {
|
|
61
|
+
const auth = p.authType ?? 'unknown auth';
|
|
62
|
+
const models = p.modelCount === 1 ? '1 model' : `${p.modelCount} models`;
|
|
63
|
+
return `${p.id} (${auth}, ${models})`;
|
|
64
|
+
}
|
|
65
|
+
function modelChoiceLabel(m) {
|
|
66
|
+
return (`${m.provider}/${m.id} — vendor: ${m.vendor}, context: ${formatTokenCount(m.contextWindow)}, ` +
|
|
67
|
+
`in: ${formatCostRate(m.inputCostPerMTok)}/Mtok, out: ${formatCostRate(m.outputCostPerMTok)}/Mtok`);
|
|
68
|
+
}
|
|
69
|
+
// JSON-encoded rather than joined with a separator character, because a host model id may
|
|
70
|
+
// itself contain '/' (or, in principle, anything else) — encoding sidesteps needing a separator
|
|
71
|
+
// character that is provably absent from every id.
|
|
72
|
+
function modelKey(provider, id) {
|
|
73
|
+
return JSON.stringify([provider, id]);
|
|
74
|
+
}
|
|
75
|
+
function splitModelKey(key) {
|
|
76
|
+
const [provider, id] = JSON.parse(key);
|
|
77
|
+
return { provider, id };
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Builds a fresh `{ input, output }` context for one prompt call. Each `@inquirer/prompts` call
|
|
81
|
+
* ends its own internal stream wrapped around whatever `output` it is given as part of normal
|
|
82
|
+
* cleanup, which — unlike `process.stdout`, which silently tolerates `.end()` — would close a
|
|
83
|
+
* caller-supplied stream for good after the very first of this picker's three stages. Relaying
|
|
84
|
+
* through a disposable `PassThrough` with `{ end: false }` on the downstream pipe means only the
|
|
85
|
+
* disposable relay ever gets closed; `io.output` stays open for every later stage.
|
|
86
|
+
*
|
|
87
|
+
* The relay also needs to mirror `io.output`'s `columns`/`rows`/`isTTY`, because that is how
|
|
88
|
+
* inquirer measures the terminal: `@inquirer/core`'s `readlineWidth()` goes through `cli-width`,
|
|
89
|
+
* and node's own `readline.Interface#columns`, both of which end up reading `.columns` off
|
|
90
|
+
* whatever stream inquirer was handed — here, the relay, not the real terminal. A relay that
|
|
91
|
+
* reports no width silently falls back to 80 columns, which hard-wraps long model labels mid-word
|
|
92
|
+
* and makes `ScreenManager` erase the wrong number of lines on every re-render (arrow keys leave
|
|
93
|
+
* stale copies of the list on screen). Defined as getters rather than copied once, so a mid-prompt
|
|
94
|
+
* terminal resize is still reflected on the next render, exactly as it would be against real
|
|
95
|
+
* stdout.
|
|
96
|
+
*/
|
|
97
|
+
function promptContext(io) {
|
|
98
|
+
const relay = new PassThrough();
|
|
99
|
+
Object.defineProperties(relay, {
|
|
100
|
+
columns: { get: () => io.output.columns, configurable: true },
|
|
101
|
+
rows: { get: () => io.output.rows, configurable: true },
|
|
102
|
+
isTTY: { get: () => io.output.isTTY === true, configurable: true },
|
|
103
|
+
});
|
|
104
|
+
relay.pipe(io.output, { end: false });
|
|
105
|
+
return { input: io.input, output: relay };
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Runs the three-stage picker: providers, then models scoped to those providers, then a
|
|
109
|
+
* thinking level per selected reasoning model (non-reasoning selections are shown as "no
|
|
110
|
+
* thinking" and skip the prompt entirely). Throws `PickerNonInteractive` (exit code 2) without a
|
|
111
|
+
* terminal, before any prompt runs, and `PickerCancelled` (exit code 2) if the user cancels at
|
|
112
|
+
* any stage.
|
|
113
|
+
*/
|
|
114
|
+
export async function pickPanel(catalog, io = defaultIO()) {
|
|
115
|
+
if (!io.isTTY) {
|
|
116
|
+
throw new PickerNonInteractive('interactive selection requires a terminal; supply a panel via "council-review init" ' +
|
|
117
|
+
'configuration or the --models flag in a non-interactive environment.');
|
|
118
|
+
}
|
|
119
|
+
try {
|
|
120
|
+
const readyProviders = catalog.providers.filter((p) => p.ready);
|
|
121
|
+
const selectedProviderIds = await checkbox({
|
|
122
|
+
message: 'Select providers to draw reviewers from:',
|
|
123
|
+
required: true,
|
|
124
|
+
choices: readyProviders.map((p) => ({ value: p.id, name: providerChoiceLabel(p) })),
|
|
125
|
+
}, promptContext(io));
|
|
126
|
+
const scopedModels = catalog.models.filter((m) => selectedProviderIds.includes(m.provider));
|
|
127
|
+
const selectedModelKeys = await checkbox({
|
|
128
|
+
message: 'Select models for the panel:',
|
|
129
|
+
required: true,
|
|
130
|
+
choices: scopedModels.map((m) => ({
|
|
131
|
+
value: modelKey(m.provider, m.id),
|
|
132
|
+
name: modelChoiceLabel(m),
|
|
133
|
+
})),
|
|
134
|
+
}, promptContext(io));
|
|
135
|
+
const selectedModels = selectedModelKeys.map((key) => {
|
|
136
|
+
const { provider, id } = splitModelKey(key);
|
|
137
|
+
const found = scopedModels.find((m) => m.provider === provider && m.id === id);
|
|
138
|
+
if (!found) {
|
|
139
|
+
// Unreachable in practice — every choice value is built from `scopedModels` above — but
|
|
140
|
+
// guarded rather than asserted away, since a thrown internal error is safer than a
|
|
141
|
+
// reviewer silently resolving to `undefined`.
|
|
142
|
+
throw new Error(`picker: selected model not found in scope: ${provider}/${id}`);
|
|
143
|
+
}
|
|
144
|
+
return found;
|
|
145
|
+
});
|
|
146
|
+
const reviewers = [];
|
|
147
|
+
for (const model of selectedModels) {
|
|
148
|
+
const supported = supportedLevels(model);
|
|
149
|
+
const label = `${model.provider}/${model.id}`;
|
|
150
|
+
if (supported.length === 0) {
|
|
151
|
+
io.output.write(`${label}: no thinking (model does not support reasoning)\n`);
|
|
152
|
+
reviewers.push({
|
|
153
|
+
provider: model.provider,
|
|
154
|
+
model: model.id,
|
|
155
|
+
vendor: model.vendor,
|
|
156
|
+
catalog: model,
|
|
157
|
+
thinking: resolveThinking(model, {}),
|
|
158
|
+
});
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
const picked = await select({
|
|
162
|
+
message: `Thinking level for ${label}:`,
|
|
163
|
+
choices: supported.map((level) => ({ value: level, name: level })),
|
|
164
|
+
}, promptContext(io));
|
|
165
|
+
reviewers.push({
|
|
166
|
+
provider: model.provider,
|
|
167
|
+
model: model.id,
|
|
168
|
+
vendor: model.vendor,
|
|
169
|
+
catalog: model,
|
|
170
|
+
thinking: resolveThinking(model, { cliPin: picked }),
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
return reviewers;
|
|
174
|
+
}
|
|
175
|
+
catch (err) {
|
|
176
|
+
if (isCancellation(err)) {
|
|
177
|
+
throw new PickerCancelled();
|
|
178
|
+
}
|
|
179
|
+
throw err;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=picker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"picker.js","sourceRoot":"","sources":["../src/picker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Model discovery and vendor mapping.
|
|
3
|
+
*
|
|
4
|
+
* Reads the review agent host's model catalog (or, failing that, its model-listing command) to
|
|
5
|
+
* learn which providers and models are available, without ever making a model call and without
|
|
6
|
+
* ever opening the host's credential store. See `openspec/changes/add-council-review/specs/
|
|
7
|
+
* council-review/model-discovery/spec.md` for the requirements this module satisfies.
|
|
8
|
+
*/
|
|
9
|
+
import type { ThinkingLevel } from './levels.js';
|
|
10
|
+
export interface CatalogModel {
|
|
11
|
+
id: string;
|
|
12
|
+
name: string;
|
|
13
|
+
provider: string;
|
|
14
|
+
vendor: string;
|
|
15
|
+
contextWindow: number | null;
|
|
16
|
+
maxOutputTokens: number | null;
|
|
17
|
+
inputCostPerMTok: number | null;
|
|
18
|
+
outputCostPerMTok: number | null;
|
|
19
|
+
reasoning: boolean;
|
|
20
|
+
thinkingLevelMap: Partial<Record<ThinkingLevel, string | null>> | undefined;
|
|
21
|
+
}
|
|
22
|
+
export interface ProviderInfo {
|
|
23
|
+
id: string;
|
|
24
|
+
ready: boolean;
|
|
25
|
+
authType: string | null;
|
|
26
|
+
reason: string | null;
|
|
27
|
+
modelCount: number;
|
|
28
|
+
}
|
|
29
|
+
export interface Catalog {
|
|
30
|
+
providers: ProviderInfo[];
|
|
31
|
+
models: CatalogModel[];
|
|
32
|
+
skipped: number;
|
|
33
|
+
source: 'store' | 'listing';
|
|
34
|
+
}
|
|
35
|
+
export interface DiscoveryOptions {
|
|
36
|
+
vendorOverrides?: Record<string, string>;
|
|
37
|
+
homeDir?: string;
|
|
38
|
+
piBin?: string;
|
|
39
|
+
}
|
|
40
|
+
export declare class DiscoveryError extends Error {
|
|
41
|
+
readonly exitCode: 2;
|
|
42
|
+
constructor(message: string);
|
|
43
|
+
}
|
|
44
|
+
export declare function deriveVendor(provider: string, modelId: string, overrides: Record<string, string>): string;
|
|
45
|
+
/** vendor -> ['provider/modelId', ...]; only groups with >1 member matter to callers, but return all. */
|
|
46
|
+
export declare function collapsedVendorGroups(models: readonly CatalogModel[]): Map<string, string[]>;
|
|
47
|
+
interface ListedModel {
|
|
48
|
+
provider: string;
|
|
49
|
+
id: string;
|
|
50
|
+
contextWindow: number | null;
|
|
51
|
+
maxOutputTokens: number | null;
|
|
52
|
+
reasoning: boolean;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Parses the plain-text table printed by `pi --list-models`. Only lines matching the exact
|
|
56
|
+
* six-column data shape (provider, model, context, max-out, thinking, images) after the header
|
|
57
|
+
* are treated as models; everything else — the header itself, blank lines, and extension banner
|
|
58
|
+
* lines printed at startup (which happen to also tokenize into a handful of words) — is dropped
|
|
59
|
+
* silently, because banner lines never carry a `yes`/`no` thinking column.
|
|
60
|
+
*/
|
|
61
|
+
export declare function parseListModelsOutput(text: string): ListedModel[];
|
|
62
|
+
export declare function loadCatalog(opts?: DiscoveryOptions): Promise<Catalog>;
|
|
63
|
+
export declare function readyModels(c: Catalog): CatalogModel[];
|
|
64
|
+
export declare function findModel(c: Catalog, provider: string, modelId: string): CatalogModel | undefined;
|
|
65
|
+
export {};
|
|
66
|
+
//# sourceMappingURL=providers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../src/providers.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAQH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGjD,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,SAAS,EAAE,OAAO,CAAC;IACnB,gBAAgB,EAAE,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,GAAG,SAAS,CAAC;CAC7E;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,OAAO;IACtB,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,OAAO,GAAG,SAAS,CAAC;CAC7B;AAED,MAAM,WAAW,gBAAgB;IAC/B,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,cAAe,SAAQ,KAAK;IACvC,QAAQ,CAAC,QAAQ,EAAG,CAAC,CAAU;gBAEnB,OAAO,EAAE,MAAM;CAI5B;AA2DD,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAChC,MAAM,CAgBR;AAED,yGAAyG;AACzG,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAY5F;AA8SD,UAAU,WAAW;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,SAAS,EAAE,OAAO,CAAC;CACpB;AAiBD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,EAAE,CAmCjE;AA2ND,wBAAsB,WAAW,CAAC,IAAI,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC,CA6B3E;AAED,wBAAgB,WAAW,CAAC,CAAC,EAAE,OAAO,GAAG,YAAY,EAAE,CAGtD;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAEjG"}
|