@nookplot/mcp 0.4.101 → 0.4.103
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 +3 -3
- package/SKILL.md +2 -2
- package/dist/applyConfig.d.ts +85 -0
- package/dist/applyConfig.d.ts.map +1 -0
- package/dist/applyConfig.js +601 -0
- package/dist/applyConfig.js.map +1 -0
- package/dist/auth.d.ts +112 -5
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +294 -53
- package/dist/auth.js.map +1 -1
- package/dist/gateway.d.ts.map +1 -1
- package/dist/gateway.js +5 -1
- package/dist/gateway.js.map +1 -1
- package/dist/index.d.ts +12 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +580 -18
- package/dist/index.js.map +1 -1
- package/dist/profileName.d.ts +65 -0
- package/dist/profileName.d.ts.map +1 -0
- package/dist/profileName.js +114 -0
- package/dist/profileName.js.map +1 -0
- package/dist/setup.d.ts +28 -1
- package/dist/setup.d.ts.map +1 -1
- package/dist/setup.js +204 -6
- package/dist/setup.js.map +1 -1
- package/dist/syncSessions.d.ts +84 -0
- package/dist/syncSessions.d.ts.map +1 -0
- package/dist/syncSessions.js +260 -0
- package/dist/syncSessions.js.map +1 -0
- package/dist/syncSessionsExtractor.d.ts +123 -0
- package/dist/syncSessionsExtractor.d.ts.map +1 -0
- package/dist/syncSessionsExtractor.js +362 -0
- package/dist/syncSessionsExtractor.js.map +1 -0
- package/dist/syncSessionsState.d.ts +89 -0
- package/dist/syncSessionsState.d.ts.map +1 -0
- package/dist/syncSessionsState.js +145 -0
- package/dist/syncSessionsState.js.map +1 -0
- package/dist/tools/ecosystem.d.ts.map +1 -1
- package/dist/tools/ecosystem.js +1 -5
- package/dist/tools/ecosystem.js.map +1 -1
- package/dist/tools/forgePresets.d.ts +7 -2
- package/dist/tools/forgePresets.d.ts.map +1 -1
- package/dist/tools/forgePresets.js +133 -3
- package/dist/tools/forgePresets.js.map +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +2 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/knowledgeGraph.js +1 -1
- package/dist/tools/knowledgeGraph.js.map +1 -1
- package/dist/tools/memory.d.ts.map +1 -1
- package/dist/tools/memory.js +0 -33
- package/dist/tools/memory.js.map +1 -1
- package/dist/tools/miningPipeline.d.ts +6 -2
- package/dist/tools/miningPipeline.d.ts.map +1 -1
- package/dist/tools/miningPipeline.js +392 -3
- package/dist/tools/miningPipeline.js.map +1 -1
- package/dist/tools/onchain.d.ts.map +1 -1
- package/dist/tools/onchain.js +11 -0
- package/dist/tools/onchain.js.map +1 -1
- package/dist/tools/papers.d.ts.map +1 -1
- package/dist/tools/papers.js +16 -0
- package/dist/tools/papers.js.map +1 -1
- package/dist/tools/read.d.ts.map +1 -1
- package/dist/tools/read.js +27 -6
- package/dist/tools/read.js.map +1 -1
- package/dist/tools/reasoningWork.js +1 -1
- package/dist/tools/reppo.d.ts +18 -0
- package/dist/tools/reppo.d.ts.map +1 -0
- package/dist/tools/reppo.js +148 -0
- package/dist/tools/reppo.js.map +1 -0
- package/dist/tools/swarms.d.ts.map +1 -1
- package/dist/tools/swarms.js +21 -1
- package/dist/tools/swarms.js.map +1 -1
- package/package.json +1 -1
- package/skills/hermes/nookplot/DESCRIPTION.md +59 -0
- package/skills/hermes/nookplot/daemon/SKILL.md +103 -0
- package/skills/hermes/nookplot/learn/SKILL.md +131 -0
- package/skills/hermes/nookplot/mine/SKILL.md +111 -0
- package/skills/hermes/nookplot/social/SKILL.md +104 -0
- package/skills/hermes/nookplot/sync/SKILL.md +110 -0
|
@@ -0,0 +1,601 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `nookplot-mcp apply-config` — redeem + decrypt + apply a Nookplot config
|
|
3
|
+
* bundle to the user's local Hermes installation.
|
|
4
|
+
*
|
|
5
|
+
* This is the final mile of the one-stop-shop installer flow:
|
|
6
|
+
*
|
|
7
|
+
* 1. User configured BYOK / model / messaging on the Nookplot web UI.
|
|
8
|
+
* 2. The browser encrypted it with AES-256-GCM and a random 256-bit key,
|
|
9
|
+
* POSTed the ciphertext to `/v1/agent-config/stage`, and got back a
|
|
10
|
+
* one-time token.
|
|
11
|
+
* 3. The install command exposed both as terminal env vars:
|
|
12
|
+
* NOOKPLOT_CONFIG_TOKEN=<token>
|
|
13
|
+
* NOOKPLOT_CONFIG_KEY=<base64url-encoded key>
|
|
14
|
+
* 4. The installer bash script calls this command with those values.
|
|
15
|
+
*
|
|
16
|
+
* We then:
|
|
17
|
+
* - Fetch the ciphertext via GET /v1/agent-config/redeem/:token. The
|
|
18
|
+
* gateway deletes the row as it returns the payload, so replays fail.
|
|
19
|
+
* - Decrypt locally using the key (which never left the terminal).
|
|
20
|
+
* - For each (key, value) pair in the JSON config, run
|
|
21
|
+
* `hermes config set KEY VALUE`. Hermes auto-routes secrets (API keys,
|
|
22
|
+
* bot tokens) to ~/.hermes/.env and other settings to ~/.hermes/config.yaml.
|
|
23
|
+
*
|
|
24
|
+
* @module applyConfig
|
|
25
|
+
*/
|
|
26
|
+
import { createDecipheriv } from "node:crypto";
|
|
27
|
+
import { execFileSync } from "node:child_process";
|
|
28
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync, chmodSync } from "node:fs";
|
|
29
|
+
import { homedir } from "node:os";
|
|
30
|
+
import { join } from "node:path";
|
|
31
|
+
import { Wallet } from "ethers";
|
|
32
|
+
/**
|
|
33
|
+
* Decode a base64url string (`-` `_`, no padding) to a Buffer.
|
|
34
|
+
* Web Crypto emits base64url by default, so our browser-side encryption
|
|
35
|
+
* produces keys in this form.
|
|
36
|
+
*/
|
|
37
|
+
function fromBase64Url(value) {
|
|
38
|
+
// Convert base64url → base64 by replacing URL-safe chars and
|
|
39
|
+
// re-padding to a multiple of 4.
|
|
40
|
+
let b64 = value.replace(/-/g, "+").replace(/_/g, "/");
|
|
41
|
+
const pad = b64.length % 4;
|
|
42
|
+
if (pad)
|
|
43
|
+
b64 += "=".repeat(4 - pad);
|
|
44
|
+
return Buffer.from(b64, "base64");
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Redeem the ciphertext from the gateway. The endpoint deletes the row as
|
|
48
|
+
* it returns the payload, so replays will 404.
|
|
49
|
+
*/
|
|
50
|
+
async function redeemCiphertext(gatewayUrl, token, fetchFn, timeoutMs) {
|
|
51
|
+
const url = `${gatewayUrl.replace(/\/$/, "")}/v1/agent-config/redeem/${encodeURIComponent(token)}`;
|
|
52
|
+
// AbortController gives us a hard ceiling on wait time so a hung
|
|
53
|
+
// gateway can't freeze the installer.
|
|
54
|
+
const controller = new AbortController();
|
|
55
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
56
|
+
try {
|
|
57
|
+
const res = await fetchFn(url, { signal: controller.signal });
|
|
58
|
+
if (!res.ok) {
|
|
59
|
+
const body = await res.text().catch(() => "");
|
|
60
|
+
if (res.status === 404) {
|
|
61
|
+
throw new Error("Config token not found, already used, or expired. " +
|
|
62
|
+
"Regenerate the install command on your agent's Nookplot page.");
|
|
63
|
+
}
|
|
64
|
+
throw new Error(`Gateway returned ${res.status}: ${body.slice(0, 200)}`);
|
|
65
|
+
}
|
|
66
|
+
const payload = (await res.json());
|
|
67
|
+
if (typeof payload.ciphertext !== "string" ||
|
|
68
|
+
typeof payload.iv !== "string" ||
|
|
69
|
+
typeof payload.authTag !== "string" ||
|
|
70
|
+
typeof payload.agentAddress !== "string") {
|
|
71
|
+
throw new Error("Gateway returned an unexpected payload shape.");
|
|
72
|
+
}
|
|
73
|
+
return payload;
|
|
74
|
+
}
|
|
75
|
+
finally {
|
|
76
|
+
clearTimeout(timer);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Decrypt an AES-256-GCM ciphertext. Throws on auth-tag mismatch (i.e.
|
|
81
|
+
* wrong key or tampered ciphertext).
|
|
82
|
+
*/
|
|
83
|
+
function decryptBundle(stage, key) {
|
|
84
|
+
if (key.length !== 32) {
|
|
85
|
+
throw new Error(`AES-256 key must be 32 bytes (got ${key.length}). ` +
|
|
86
|
+
`Check NOOKPLOT_CONFIG_KEY is the full base64url value.`);
|
|
87
|
+
}
|
|
88
|
+
const iv = Buffer.from(stage.iv, "base64");
|
|
89
|
+
const authTag = Buffer.from(stage.authTag, "base64");
|
|
90
|
+
const ciphertext = Buffer.from(stage.ciphertext, "base64");
|
|
91
|
+
if (iv.length !== 12) {
|
|
92
|
+
throw new Error(`Invalid IV length (${iv.length}) — expected 12 bytes.`);
|
|
93
|
+
}
|
|
94
|
+
if (authTag.length !== 16) {
|
|
95
|
+
throw new Error(`Invalid auth tag length (${authTag.length}) — expected 16 bytes.`);
|
|
96
|
+
}
|
|
97
|
+
const decipher = createDecipheriv("aes-256-gcm", key, iv);
|
|
98
|
+
decipher.setAuthTag(authTag);
|
|
99
|
+
let plaintext;
|
|
100
|
+
try {
|
|
101
|
+
plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
// Auth-tag failure → either wrong key or tampered bytes. In practice
|
|
105
|
+
// the first is common (user pasted the wrong install command), the
|
|
106
|
+
// second means someone was intercepting — either way, bail loud.
|
|
107
|
+
throw new Error("Decryption failed — auth tag mismatch. " +
|
|
108
|
+
"This usually means NOOKPLOT_CONFIG_KEY doesn't match the token " +
|
|
109
|
+
"(regenerate the install command on your agent page).");
|
|
110
|
+
}
|
|
111
|
+
let parsed;
|
|
112
|
+
try {
|
|
113
|
+
parsed = JSON.parse(plaintext.toString("utf8"));
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
throw new Error("Decrypted payload was not valid JSON.");
|
|
117
|
+
}
|
|
118
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
119
|
+
throw new Error("Decrypted payload was not a JSON object.");
|
|
120
|
+
}
|
|
121
|
+
return parsed;
|
|
122
|
+
}
|
|
123
|
+
// ---------------------------------------------------------------------------
|
|
124
|
+
// Apply to Hermes
|
|
125
|
+
// ---------------------------------------------------------------------------
|
|
126
|
+
/**
|
|
127
|
+
* Valid Hermes config key shape.
|
|
128
|
+
*
|
|
129
|
+
* Hermes accepts:
|
|
130
|
+
* - Dotted lowercase keys (e.g. `model.default`, `terminal.backend`)
|
|
131
|
+
* - SCREAMING_SNAKE_CASE (auto-routed to ~/.hermes/.env, for API keys)
|
|
132
|
+
* - Simple `a-z0-9_` keys for top-level settings
|
|
133
|
+
*
|
|
134
|
+
* We gate strictly here because we're about to exec a subprocess: anything
|
|
135
|
+
* that smells like a shell metachar gets dropped with a recorded failure
|
|
136
|
+
* rather than quietly becoming an argv surprise.
|
|
137
|
+
*/
|
|
138
|
+
function isValidHermesKey(key) {
|
|
139
|
+
return /^[A-Za-z][A-Za-z0-9_.]{0,127}$/.test(key);
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Run `hermes config set <key> <value>` for each entry in the config.
|
|
143
|
+
*
|
|
144
|
+
* We skip — and record — anything whose value isn't serializable as a flat
|
|
145
|
+
* string, as well as anything whose key fails our whitelist. The Hermes
|
|
146
|
+
* CLI itself does the routing between config.yaml (plain settings) and
|
|
147
|
+
* .env (API keys), so we don't have to duplicate that logic here.
|
|
148
|
+
*/
|
|
149
|
+
function applyToHermes(config, hermesBin, execFn, profile) {
|
|
150
|
+
let applied = 0;
|
|
151
|
+
const failures = [];
|
|
152
|
+
// When a profile is set, every `hermes config set` call is prefixed
|
|
153
|
+
// with `--profile <name>` so the writes land in
|
|
154
|
+
// ~/.hermes/profiles/<name>/config.yaml rather than the default
|
|
155
|
+
// ~/.hermes/config.yaml. This is how multi-agent installs stay
|
|
156
|
+
// isolated: Agent A's BYOK keys don't clobber Agent B's.
|
|
157
|
+
const profilePrefix = profile ? ["--profile", profile] : [];
|
|
158
|
+
for (const [key, rawValue] of Object.entries(config)) {
|
|
159
|
+
if (!isValidHermesKey(key)) {
|
|
160
|
+
failures.push({ key, error: "Invalid key format (must match /^[A-Za-z][A-Za-z0-9_.]*$/)" });
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
// Flatten to string. Booleans/numbers become their textual form;
|
|
164
|
+
// nested objects are rejected — Hermes uses dotted keys for nesting.
|
|
165
|
+
let value;
|
|
166
|
+
if (typeof rawValue === "string") {
|
|
167
|
+
value = rawValue;
|
|
168
|
+
}
|
|
169
|
+
else if (typeof rawValue === "number" || typeof rawValue === "boolean") {
|
|
170
|
+
value = String(rawValue);
|
|
171
|
+
}
|
|
172
|
+
else if (rawValue === null || rawValue === undefined) {
|
|
173
|
+
failures.push({ key, error: "Value is null or undefined" });
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
failures.push({
|
|
178
|
+
key,
|
|
179
|
+
error: "Value must be a string, number, or boolean (use dotted keys for nesting)",
|
|
180
|
+
});
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
try {
|
|
184
|
+
// We pass each arg as a separate argv element — no shell involved,
|
|
185
|
+
// so there's no shell-injection surface even if `value` contains
|
|
186
|
+
// funky characters. (Which it will, for API keys.)
|
|
187
|
+
execFn(hermesBin, [...profilePrefix, "config", "set", key, value]);
|
|
188
|
+
applied += 1;
|
|
189
|
+
}
|
|
190
|
+
catch (err) {
|
|
191
|
+
failures.push({
|
|
192
|
+
key,
|
|
193
|
+
error: err instanceof Error ? err.message : String(err),
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return { applied, failures };
|
|
198
|
+
}
|
|
199
|
+
// ---------------------------------------------------------------------------
|
|
200
|
+
// Entry point
|
|
201
|
+
// ---------------------------------------------------------------------------
|
|
202
|
+
// ---------------------------------------------------------------------------
|
|
203
|
+
// Platform-mode expansion
|
|
204
|
+
// ---------------------------------------------------------------------------
|
|
205
|
+
/**
|
|
206
|
+
* Expand a "platform" mode bundle into concrete Hermes inference config.
|
|
207
|
+
*
|
|
208
|
+
* When the user picked "Fast & cheap" or "Smart max-effort" on Forge, the
|
|
209
|
+
* bundle from the web UI doesn't carry a real API key — those presets use
|
|
210
|
+
* Nookplot's gateway proxy (OpenAI-compat at /v1/openai/v1/chat/completions),
|
|
211
|
+
* which charges the user's NOOK balance. The bundle instead carries SENTINEL
|
|
212
|
+
* keys that signal "expand me locally":
|
|
213
|
+
*
|
|
214
|
+
* __nookplot_inference_mode = "platform"
|
|
215
|
+
* __nookplot_platform_model = "hermes-3-llama-3.1-8b" (or whichever model)
|
|
216
|
+
* __nookplot_gateway_base = "https://gateway.nookplot.com" (optional)
|
|
217
|
+
*
|
|
218
|
+
* This function:
|
|
219
|
+
* 1. Detects the platform-mode marker.
|
|
220
|
+
* 2. Reads the user's Nookplot API key from local ~/.nookplot/credentials.json.
|
|
221
|
+
* The API key NEVER touches the bundle (so it never lands on the gateway
|
|
222
|
+
* staging table or in transit). The web-staged bundle only has the
|
|
223
|
+
* metadata above; expansion happens at install time on the user's machine.
|
|
224
|
+
* 3. Returns a NEW config object with sentinels stripped + gateway-proxy
|
|
225
|
+
* Hermes config keys added (model.base_url, OPENAI_API_KEY, model.default).
|
|
226
|
+
*
|
|
227
|
+
* Returns the original config unchanged when no platform marker is present —
|
|
228
|
+
* BYOK + messaging-only bundles continue to work exactly as before.
|
|
229
|
+
*
|
|
230
|
+
* Why the indirection vs. just including the API key in the bundle:
|
|
231
|
+
* - Bundle ciphertext lands on the gateway briefly (15-minute TTL). Even
|
|
232
|
+
* though it's encrypted client-side, fewer copies of the user's API key
|
|
233
|
+
* in transit = less attack surface.
|
|
234
|
+
* - Bundle is one-time-use; a user re-installing on a new machine would
|
|
235
|
+
* need a new bundle. Reading from local creds avoids that round-trip.
|
|
236
|
+
* - Future per-agent scoped tokens slot in here without changing the
|
|
237
|
+
* bundle protocol.
|
|
238
|
+
*/
|
|
239
|
+
/**
|
|
240
|
+
* Whitelist of trusted gateway origins for the `__nookplot_gateway_base`
|
|
241
|
+
* override. This guards against bundle-tamper key exfiltration.
|
|
242
|
+
*
|
|
243
|
+
* The installer's own `gatewayUrl` argument is always trusted (it was
|
|
244
|
+
* baked into the install script by the gateway that served it), so we
|
|
245
|
+
* also accept any URL whose origin matches `gatewayUrl`'s origin —
|
|
246
|
+
* that covers staging environments transparently.
|
|
247
|
+
*/
|
|
248
|
+
const TRUSTED_GATEWAY_ORIGINS = new Set([
|
|
249
|
+
"https://gateway.nookplot.com",
|
|
250
|
+
"https://gateway-dev.nookplot.com",
|
|
251
|
+
"http://localhost:8080",
|
|
252
|
+
"http://localhost:3000",
|
|
253
|
+
"http://127.0.0.1:8080",
|
|
254
|
+
"http://127.0.0.1:3000",
|
|
255
|
+
]);
|
|
256
|
+
export function isAllowedGatewayBase(candidate, installerGatewayUrl) {
|
|
257
|
+
let candidateOrigin;
|
|
258
|
+
try {
|
|
259
|
+
candidateOrigin = new URL(candidate).origin;
|
|
260
|
+
}
|
|
261
|
+
catch {
|
|
262
|
+
return false; // malformed URL
|
|
263
|
+
}
|
|
264
|
+
if (TRUSTED_GATEWAY_ORIGINS.has(candidateOrigin))
|
|
265
|
+
return true;
|
|
266
|
+
// Also accept anything matching the installer's own gateway origin.
|
|
267
|
+
try {
|
|
268
|
+
if (new URL(installerGatewayUrl).origin === candidateOrigin)
|
|
269
|
+
return true;
|
|
270
|
+
}
|
|
271
|
+
catch {
|
|
272
|
+
/* fall through */
|
|
273
|
+
}
|
|
274
|
+
return false;
|
|
275
|
+
}
|
|
276
|
+
function expandPlatformInference(config, gatewayUrl, credentialsReader) {
|
|
277
|
+
const mode = config["__nookplot_inference_mode"];
|
|
278
|
+
if (mode !== "platform") {
|
|
279
|
+
// Fast path: nothing to expand. Strip any rogue __nookplot_* keys
|
|
280
|
+
// anyway so they never reach the Hermes key-validity check.
|
|
281
|
+
const stripped = {};
|
|
282
|
+
for (const [k, v] of Object.entries(config)) {
|
|
283
|
+
if (!k.startsWith("__nookplot_"))
|
|
284
|
+
stripped[k] = v;
|
|
285
|
+
}
|
|
286
|
+
return stripped;
|
|
287
|
+
}
|
|
288
|
+
const model = typeof config["__nookplot_platform_model"] === "string"
|
|
289
|
+
? config["__nookplot_platform_model"]
|
|
290
|
+
: null;
|
|
291
|
+
// The bundle MAY override the gateway base for staging / dev contexts, but
|
|
292
|
+
// we whitelist the host because this URL becomes `model.base_url` in Hermes
|
|
293
|
+
// — which means the user's freshly-written `OPENAI_API_KEY` (read from
|
|
294
|
+
// local credentials) will be sent there on every inference. A bundle that
|
|
295
|
+
// smuggles `__nookplot_gateway_base: "https://evil.example/..."` would
|
|
296
|
+
// exfiltrate the user's API key on first call.
|
|
297
|
+
//
|
|
298
|
+
// Trust set: production gateway, dev gateway, localhost (development),
|
|
299
|
+
// plus whatever was passed as `gatewayUrl` (the installer's argument —
|
|
300
|
+
// already validated upstream). Anything else is silently ignored, falling
|
|
301
|
+
// back to `gatewayUrl`.
|
|
302
|
+
const rawBaseOverride = typeof config["__nookplot_gateway_base"] === "string"
|
|
303
|
+
? config["__nookplot_gateway_base"]
|
|
304
|
+
: null;
|
|
305
|
+
const baseOverride = rawBaseOverride && isAllowedGatewayBase(rawBaseOverride, gatewayUrl)
|
|
306
|
+
? rawBaseOverride
|
|
307
|
+
: null;
|
|
308
|
+
if (rawBaseOverride && !baseOverride) {
|
|
309
|
+
console.error(`[nookplot-mcp] Ignoring untrusted __nookplot_gateway_base override (${rawBaseOverride}). Using ${gatewayUrl} instead. ` +
|
|
310
|
+
`This protects your API key from being sent to an attacker-controlled gateway.`);
|
|
311
|
+
}
|
|
312
|
+
// Read local API key. If not found, abort the expansion — the user needs
|
|
313
|
+
// to register first via `nookplot register` or by deploying their first
|
|
314
|
+
// agent through the web flow.
|
|
315
|
+
const creds = credentialsReader();
|
|
316
|
+
if (!creds || !creds.apiKey) {
|
|
317
|
+
throw new Error("Platform inference mode requires a registered Nookplot account, " +
|
|
318
|
+
"but no credentials were found at ~/.nookplot/credentials.json. " +
|
|
319
|
+
"Run `nookplot register` first, or deploy your first agent on nookplot.com.");
|
|
320
|
+
}
|
|
321
|
+
// Build the expanded config. Strip ALL __nookplot_* sentinels so the
|
|
322
|
+
// downstream Hermes-key validator never sees them.
|
|
323
|
+
const expanded = {};
|
|
324
|
+
for (const [k, v] of Object.entries(config)) {
|
|
325
|
+
if (!k.startsWith("__nookplot_"))
|
|
326
|
+
expanded[k] = v;
|
|
327
|
+
}
|
|
328
|
+
// Trailing-slash-safe base URL. Hermes will append /chat/completions to
|
|
329
|
+
// model.base_url, so we end at /v1/openai/v1 (path includes the inner /v1
|
|
330
|
+
// because OpenAI-compat clients expect it — see openaiAdapter.ts mounting).
|
|
331
|
+
const base = (baseOverride ?? gatewayUrl).replace(/\/+$/, "");
|
|
332
|
+
expanded["model.base_url"] = `${base}/v1/openai/v1`;
|
|
333
|
+
// Use OPENAI_API_KEY because the gateway adapter speaks OpenAI's protocol;
|
|
334
|
+
// Hermes routes auth via the OpenAI provider config when model.base_url
|
|
335
|
+
// is set. Hermes auto-routes SCREAMING_SNAKE_CASE keys to ~/.hermes/.env
|
|
336
|
+
// (or the per-profile .env).
|
|
337
|
+
expanded["OPENAI_API_KEY"] = creds.apiKey;
|
|
338
|
+
// Default model — only set if the bundle specified one. (Forge always
|
|
339
|
+
// does, but we don't blow up if it's missing.)
|
|
340
|
+
if (model && !expanded["model.default"]) {
|
|
341
|
+
expanded["model.default"] = model;
|
|
342
|
+
}
|
|
343
|
+
return expanded;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* If the bundle includes a spawned child agent's keystore (privateKey +
|
|
347
|
+
* address as `__nookplot_child_*` keys), sign in as the child via
|
|
348
|
+
* /v1/auth/wallet-session and write the resulting session API key to
|
|
349
|
+
* ~/.nookplot/agents/<profile>/credentials.json.
|
|
350
|
+
*
|
|
351
|
+
* This is what makes the install command "just work" without users having
|
|
352
|
+
* to download a keystore.json file at spawn time and pass it via
|
|
353
|
+
* NOOKPLOT_CHILD_KEYSTORE=path. The MCP server's auth resolver
|
|
354
|
+
* (auth.ts::resolveCredentialsPath) prefers per-profile credentials when
|
|
355
|
+
* NOOKPLOT_PROFILE is set, so tools authenticate AS the child rather than
|
|
356
|
+
* as the parent who pasted the install command.
|
|
357
|
+
*
|
|
358
|
+
* Without this branch, the agent's KG / mining / messaging / on-chain
|
|
359
|
+
* actions all get attributed to the parent's address — which is fine for
|
|
360
|
+
* reads/discovery but breaks the "child agent owns its own work" property
|
|
361
|
+
* of the spawn flow.
|
|
362
|
+
*
|
|
363
|
+
* Mirrors the existing bash branch in installAgent.ts (the
|
|
364
|
+
* NOOKPLOT_CHILD_KEYSTORE=path-prefixed install). Apply-config doing it
|
|
365
|
+
* directly means the path doesn't depend on a temp file the user has to
|
|
366
|
+
* point at — the keystore travels through the same encrypted bundle as
|
|
367
|
+
* the inference config.
|
|
368
|
+
*/
|
|
369
|
+
async function applyChildKeystore(config, opts) {
|
|
370
|
+
const privateKey = typeof config["__nookplot_child_private_key"] === "string"
|
|
371
|
+
? config["__nookplot_child_private_key"]
|
|
372
|
+
: null;
|
|
373
|
+
const address = typeof config["__nookplot_child_address"] === "string"
|
|
374
|
+
? config["__nookplot_child_address"]
|
|
375
|
+
: null;
|
|
376
|
+
const displayName = typeof config["__nookplot_child_display_name"] === "string"
|
|
377
|
+
? config["__nookplot_child_display_name"]
|
|
378
|
+
: null;
|
|
379
|
+
if (!privateKey || !address) {
|
|
380
|
+
return { applied: false, address: null };
|
|
381
|
+
}
|
|
382
|
+
// We need a profile to know where to write the per-agent credentials.
|
|
383
|
+
// Without one, hermes would default to ~/.nookplot/credentials.json which
|
|
384
|
+
// would clobber the parent's session — so refuse rather than silently
|
|
385
|
+
// overwrite. The install bash always passes --profile, so this only
|
|
386
|
+
// trips for hand-rolled invocations.
|
|
387
|
+
if (!opts.profile) {
|
|
388
|
+
return {
|
|
389
|
+
applied: false,
|
|
390
|
+
address,
|
|
391
|
+
reason: "Bundle contains a child keystore but no --profile was set. Refusing to write to the parent's credentials path.",
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
// Sanity check the keypair before spending a network round-trip on it.
|
|
395
|
+
// A typo or copy-paste glitch in the bundle would otherwise show up as
|
|
396
|
+
// a confusing 4xx from the gateway.
|
|
397
|
+
let wallet;
|
|
398
|
+
try {
|
|
399
|
+
wallet = new Wallet(privateKey);
|
|
400
|
+
}
|
|
401
|
+
catch (err) {
|
|
402
|
+
return {
|
|
403
|
+
applied: false,
|
|
404
|
+
address,
|
|
405
|
+
reason: `Invalid privateKey in bundle: ${err instanceof Error ? err.message : String(err)}`,
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
if (wallet.address.toLowerCase() !== address.toLowerCase()) {
|
|
409
|
+
return {
|
|
410
|
+
applied: false,
|
|
411
|
+
address,
|
|
412
|
+
reason: `Bundle privateKey derives ${wallet.address} but bundle.address is ${address} — mismatch.`,
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
// Sign the EIP-191 sign-in message — same shape the gateway's wallet-
|
|
416
|
+
// session endpoint expects (ts in ms, plaintext "Sign in to Nookplot\n
|
|
417
|
+
// \nTimestamp: <ts>"). Replays bounded by the gateway's timestamp window.
|
|
418
|
+
const ts = Date.now();
|
|
419
|
+
const msg = `Sign in to Nookplot\n\nTimestamp: ${ts}`;
|
|
420
|
+
const signature = await wallet.signMessage(msg);
|
|
421
|
+
// Hit /v1/auth/wallet-session. On success the gateway sets a cookie
|
|
422
|
+
// `nk_session=<apiKey>` — we extract the key from the Set-Cookie header
|
|
423
|
+
// since fetch in node doesn't expose a cookie jar.
|
|
424
|
+
const url = `${opts.gatewayUrl.replace(/\/$/, "")}/v1/auth/wallet-session`;
|
|
425
|
+
const controller = new AbortController();
|
|
426
|
+
const timer = setTimeout(() => controller.abort(), opts.timeoutMs);
|
|
427
|
+
let apiKey;
|
|
428
|
+
try {
|
|
429
|
+
const res = await opts.fetchFn(url, {
|
|
430
|
+
method: "POST",
|
|
431
|
+
headers: { "Content-Type": "application/json" },
|
|
432
|
+
body: JSON.stringify({ address, signature, timestamp: ts }),
|
|
433
|
+
signal: controller.signal,
|
|
434
|
+
});
|
|
435
|
+
if (!res.ok) {
|
|
436
|
+
const body = await res.text().catch(() => "");
|
|
437
|
+
return {
|
|
438
|
+
applied: false,
|
|
439
|
+
address,
|
|
440
|
+
reason: `wallet-session sign-in failed: ${res.status} ${body.slice(0, 200)}`,
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
const setCookie = res.headers.get("set-cookie") ?? "";
|
|
444
|
+
const m = /nk_session=([^;]+)/.exec(setCookie);
|
|
445
|
+
if (!m) {
|
|
446
|
+
return {
|
|
447
|
+
applied: false,
|
|
448
|
+
address,
|
|
449
|
+
reason: "wallet-session response missing nk_session cookie.",
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
apiKey = m[1];
|
|
453
|
+
}
|
|
454
|
+
finally {
|
|
455
|
+
clearTimeout(timer);
|
|
456
|
+
}
|
|
457
|
+
// Write credentials.json — same shape the install bash writes, same
|
|
458
|
+
// 0600 perms (private key on disk, treat as a secret). Path matches
|
|
459
|
+
// what the MCP auth resolver looks for when NOOKPLOT_PROFILE is set.
|
|
460
|
+
const agentsDir = join(homedir(), ".nookplot", "agents", opts.profile);
|
|
461
|
+
try {
|
|
462
|
+
mkdirSync(agentsDir, { recursive: true });
|
|
463
|
+
chmodSync(join(homedir(), ".nookplot", "agents"), 0o700);
|
|
464
|
+
}
|
|
465
|
+
catch {
|
|
466
|
+
// chmod failing is non-fatal (might already be 700, or platform doesn't
|
|
467
|
+
// support modes). The mkdir failure WILL break the write below.
|
|
468
|
+
}
|
|
469
|
+
const credsPath = join(agentsDir, "credentials.json");
|
|
470
|
+
const out = {
|
|
471
|
+
apiKey,
|
|
472
|
+
privateKey,
|
|
473
|
+
address,
|
|
474
|
+
gatewayUrl: opts.gatewayUrl,
|
|
475
|
+
displayName: displayName ?? null,
|
|
476
|
+
};
|
|
477
|
+
writeFileSync(credsPath, JSON.stringify(out, null, 2) + "\n", { mode: 0o600 });
|
|
478
|
+
try {
|
|
479
|
+
chmodSync(credsPath, 0o600);
|
|
480
|
+
}
|
|
481
|
+
catch {
|
|
482
|
+
/* same as above — best effort */
|
|
483
|
+
}
|
|
484
|
+
return { applied: true, address };
|
|
485
|
+
}
|
|
486
|
+
/**
|
|
487
|
+
* Strip child-keystore sentinels from a config dict. Used after
|
|
488
|
+
* applyChildKeystore so the keys don't get forwarded to hermes (which
|
|
489
|
+
* would just reject them as unknown config).
|
|
490
|
+
*/
|
|
491
|
+
function stripChildKeystoreKeys(config) {
|
|
492
|
+
const out = {};
|
|
493
|
+
for (const [k, v] of Object.entries(config)) {
|
|
494
|
+
if (k === "__nookplot_child_private_key")
|
|
495
|
+
continue;
|
|
496
|
+
if (k === "__nookplot_child_address")
|
|
497
|
+
continue;
|
|
498
|
+
if (k === "__nookplot_child_display_name")
|
|
499
|
+
continue;
|
|
500
|
+
out[k] = v;
|
|
501
|
+
}
|
|
502
|
+
return out;
|
|
503
|
+
}
|
|
504
|
+
/**
|
|
505
|
+
* Default credentials reader — reads ~/.nookplot/credentials.json and returns
|
|
506
|
+
* { apiKey } or null. Isolated from applyConfig main logic so tests can
|
|
507
|
+
* inject a stub without filesystem access.
|
|
508
|
+
*/
|
|
509
|
+
function defaultCredentialsReader() {
|
|
510
|
+
try {
|
|
511
|
+
const credsPath = join(homedir(), ".nookplot", "credentials.json");
|
|
512
|
+
if (!existsSync(credsPath))
|
|
513
|
+
return null;
|
|
514
|
+
const raw = readFileSync(credsPath, "utf-8");
|
|
515
|
+
const parsed = JSON.parse(raw);
|
|
516
|
+
if (typeof parsed.apiKey !== "string" || !parsed.apiKey)
|
|
517
|
+
return null;
|
|
518
|
+
return { apiKey: parsed.apiKey };
|
|
519
|
+
}
|
|
520
|
+
catch {
|
|
521
|
+
return null;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
/**
|
|
525
|
+
* Main orchestration: fetch → decrypt → apply. Returns a result with per-key
|
|
526
|
+
* success/failure so the caller can surface what happened to the user.
|
|
527
|
+
*/
|
|
528
|
+
export async function applyConfig(opts) {
|
|
529
|
+
if (!opts.token || !/^[a-f0-9]{64}$/i.test(opts.token)) {
|
|
530
|
+
throw new Error("Invalid NOOKPLOT_CONFIG_TOKEN (must be 64 hex chars). " +
|
|
531
|
+
"Regenerate the install command on your agent's Nookplot page.");
|
|
532
|
+
}
|
|
533
|
+
if (!opts.key) {
|
|
534
|
+
throw new Error("Missing NOOKPLOT_CONFIG_KEY env var.");
|
|
535
|
+
}
|
|
536
|
+
const gatewayUrl = opts.gatewayUrl ?? "https://gateway.nookplot.com";
|
|
537
|
+
const timeoutMs = opts.timeoutMs ?? 15_000;
|
|
538
|
+
const hermesBin = opts.hermesBin ?? "hermes";
|
|
539
|
+
const fetchFn = opts._fetch ?? fetch;
|
|
540
|
+
const execFn = opts._exec ??
|
|
541
|
+
((bin, args) => {
|
|
542
|
+
execFileSync(bin, args, { stdio: "pipe" });
|
|
543
|
+
});
|
|
544
|
+
// Parse the key from base64url.
|
|
545
|
+
let keyBytes;
|
|
546
|
+
try {
|
|
547
|
+
keyBytes = fromBase64Url(opts.key);
|
|
548
|
+
}
|
|
549
|
+
catch (err) {
|
|
550
|
+
throw new Error(`Could not decode NOOKPLOT_CONFIG_KEY as base64url: ${err instanceof Error ? err.message : String(err)}`);
|
|
551
|
+
}
|
|
552
|
+
// 1. Fetch the encrypted bundle (one-time-use token — gateway deletes
|
|
553
|
+
// the row as it responds).
|
|
554
|
+
const stage = await redeemCiphertext(gatewayUrl, opts.token, fetchFn, timeoutMs);
|
|
555
|
+
// 2. Decrypt locally. Auth-tag failures are surfaced as a clear error
|
|
556
|
+
// so the user can regenerate the install command.
|
|
557
|
+
const config = decryptBundle(stage, keyBytes);
|
|
558
|
+
// 2b. Apply child keystore (if present) BEFORE expanding inference
|
|
559
|
+
// config. The bundle may carry the spawned child agent's
|
|
560
|
+
// privateKey + address — when present we sign in as the child via
|
|
561
|
+
// /v1/auth/wallet-session and write credentials.json to
|
|
562
|
+
// ~/.nookplot/agents/<profile>/. This replaces the old workflow
|
|
563
|
+
// where users had to download keystore.json at spawn time and
|
|
564
|
+
// pass NOOKPLOT_CHILD_KEYSTORE=path to the install command.
|
|
565
|
+
// Strip the keystore keys after applying so they don't reach
|
|
566
|
+
// hermes (which would reject them as unknown config).
|
|
567
|
+
const childKeystoreResult = await applyChildKeystore(config, {
|
|
568
|
+
gatewayUrl,
|
|
569
|
+
profile: opts.profile,
|
|
570
|
+
fetchFn,
|
|
571
|
+
timeoutMs,
|
|
572
|
+
});
|
|
573
|
+
if (childKeystoreResult.applied) {
|
|
574
|
+
console.error(`[nookplot-mcp] Imported child agent identity (${childKeystoreResult.address}) — ` +
|
|
575
|
+
`tools will authenticate as the child rather than the parent.`);
|
|
576
|
+
}
|
|
577
|
+
else if (childKeystoreResult.reason) {
|
|
578
|
+
console.error(`[nookplot-mcp] Child keystore not applied: ${childKeystoreResult.reason}`);
|
|
579
|
+
}
|
|
580
|
+
const configWithoutKeystore = stripChildKeystoreKeys(config);
|
|
581
|
+
// 2c. Expand platform-mode bundles. For Fast/Smart presets, the bundle
|
|
582
|
+
// contains __nookplot_* sentinel keys that we resolve locally —
|
|
583
|
+
// fetching the user's API key from ~/.nookplot/credentials.json
|
|
584
|
+
// (NEVER from the bundle) and rewriting to concrete model.base_url
|
|
585
|
+
// + OPENAI_API_KEY + model.default config that points Hermes at
|
|
586
|
+
// our gateway's OpenAI-compat adapter.
|
|
587
|
+
//
|
|
588
|
+
// For BYOK + messaging-only bundles this is a no-op (just strips
|
|
589
|
+
// any rogue __nookplot_* keys defensively).
|
|
590
|
+
const credsReader = opts._credentialsReader ?? defaultCredentialsReader;
|
|
591
|
+
const expanded = expandPlatformInference(configWithoutKeystore, gatewayUrl, credsReader);
|
|
592
|
+
// 3. Apply each entry via `hermes config set`. Hermes routes secrets
|
|
593
|
+
// to .env and other settings to config.yaml.
|
|
594
|
+
const { applied, failures } = applyToHermes(expanded, hermesBin, execFn, opts.profile);
|
|
595
|
+
return {
|
|
596
|
+
applied,
|
|
597
|
+
failures,
|
|
598
|
+
agentAddress: stage.agentAddress,
|
|
599
|
+
};
|
|
600
|
+
}
|
|
601
|
+
//# sourceMappingURL=applyConfig.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"applyConfig.js","sourceRoot":"","sources":["../src/applyConfig.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACxF,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAuDhC;;;;GAIG;AACH,SAAS,aAAa,CAAC,KAAa;IAClC,6DAA6D;IAC7D,iCAAiC;IACjC,IAAI,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACtD,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC;IAC3B,IAAI,GAAG;QAAE,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;IACpC,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;AACpC,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,gBAAgB,CAC7B,UAAkB,EAClB,KAAa,EACb,OAAqB,EACrB,SAAiB;IAEjB,MAAM,GAAG,GAAG,GAAG,UAAU,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,2BAA2B,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;IAEnG,iEAAiE;IACjE,sCAAsC;IACtC,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,SAAS,CAAC,CAAC;IAC9D,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;QAC9D,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;YAC9C,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;gBACvB,MAAM,IAAI,KAAK,CACb,oDAAoD;oBACpD,+DAA+D,CAChE,CAAC;YACJ,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,oBAAoB,GAAG,CAAC,MAAM,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;QAC3E,CAAC;QACD,MAAM,OAAO,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAkB,CAAC;QACpD,IACE,OAAO,OAAO,CAAC,UAAU,KAAK,QAAQ;YACtC,OAAO,OAAO,CAAC,EAAE,KAAK,QAAQ;YAC9B,OAAO,OAAO,CAAC,OAAO,KAAK,QAAQ;YACnC,OAAO,OAAO,CAAC,YAAY,KAAK,QAAQ,EACxC,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;QACnE,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,aAAa,CACpB,KAAoB,EACpB,GAAW;IAEX,IAAI,GAAG,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CACb,qCAAqC,GAAG,CAAC,MAAM,KAAK;YACpD,wDAAwD,CACzD,CAAC;IACJ,CAAC;IAED,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;IAC3C,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IACrD,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IAE3D,IAAI,EAAE,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,sBAAsB,EAAE,CAAC,MAAM,wBAAwB,CAAC,CAAC;IAC3E,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,4BAA4B,OAAO,CAAC,MAAM,wBAAwB,CAAC,CAAC;IACtF,CAAC;IAED,MAAM,QAAQ,GAAG,gBAAgB,CAAC,aAAa,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;IAC1D,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IAE7B,IAAI,SAAiB,CAAC;IACtB,IAAI,CAAC;QACH,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IAC7E,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,qEAAqE;QACrE,mEAAmE;QACnE,iEAAiE;QACjE,MAAM,IAAI,KAAK,CACb,yCAAyC;YACzC,iEAAiE;YACjE,sDAAsD,CACvD,CAAC;IACJ,CAAC;IAED,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;IAClD,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC3D,CAAC;IAED,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACnE,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;IAC9D,CAAC;IAED,OAAO,MAAiC,CAAC;AAC3C,CAAC;AAED,8EAA8E;AAC9E,mBAAmB;AACnB,8EAA8E;AAE9E;;;;;;;;;;;GAWG;AACH,SAAS,gBAAgB,CAAC,GAAW;IACnC,OAAO,gCAAgC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACpD,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,aAAa,CACpB,MAA+B,EAC/B,SAAiB,EACjB,MAA6C,EAC7C,OAAgB;IAEhB,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,MAAM,QAAQ,GAA0C,EAAE,CAAC;IAE3D,oEAAoE;IACpE,gDAAgD;IAChD,gEAAgE;IAChE,+DAA+D;IAC/D,yDAAyD;IACzD,MAAM,aAAa,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAE5D,KAAK,MAAM,CAAC,GAAG,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACrD,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,EAAE,CAAC;YAC3B,QAAQ,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,4DAA4D,EAAE,CAAC,CAAC;YAC5F,SAAS;QACX,CAAC;QAED,iEAAiE;QACjE,qEAAqE;QACrE,IAAI,KAAa,CAAC;QAClB,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;YACjC,KAAK,GAAG,QAAQ,CAAC;QACnB,CAAC;aAAM,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,OAAO,QAAQ,KAAK,SAAS,EAAE,CAAC;YACzE,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC3B,CAAC;aAAM,IAAI,QAAQ,KAAK,IAAI,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YACvD,QAAQ,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,4BAA4B,EAAE,CAAC,CAAC;YAC5D,SAAS;QACX,CAAC;aAAM,CAAC;YACN,QAAQ,CAAC,IAAI,CAAC;gBACZ,GAAG;gBACH,KAAK,EAAE,0EAA0E;aAClF,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QAED,IAAI,CAAC;YACH,mEAAmE;YACnE,iEAAiE;YACjE,mDAAmD;YACnD,MAAM,CAAC,SAAS,EAAE,CAAC,GAAG,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC;YACnE,OAAO,IAAI,CAAC,CAAC;QACf,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,QAAQ,CAAC,IAAI,CAAC;gBACZ,GAAG;gBACH,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;aACxD,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;AAC/B,CAAC;AAED,8EAA8E;AAC9E,eAAe;AACf,8EAA8E;AAE9E,8EAA8E;AAC9E,2BAA2B;AAC3B,8EAA8E;AAE9E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH;;;;;;;;GAQG;AACH,MAAM,uBAAuB,GAAG,IAAI,GAAG,CAAS;IAC9C,8BAA8B;IAC9B,kCAAkC;IAClC,uBAAuB;IACvB,uBAAuB;IACvB,uBAAuB;IACvB,uBAAuB;CACxB,CAAC,CAAC;AAEH,MAAM,UAAU,oBAAoB,CAAC,SAAiB,EAAE,mBAA2B;IACjF,IAAI,eAAuB,CAAC;IAC5B,IAAI,CAAC;QACH,eAAe,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC;IAC9C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC,CAAC,gBAAgB;IAChC,CAAC;IACD,IAAI,uBAAuB,CAAC,GAAG,CAAC,eAAe,CAAC;QAAE,OAAO,IAAI,CAAC;IAC9D,oEAAoE;IACpE,IAAI,CAAC;QACH,IAAI,IAAI,GAAG,CAAC,mBAAmB,CAAC,CAAC,MAAM,KAAK,eAAe;YAAE,OAAO,IAAI,CAAC;IAC3E,CAAC;IAAC,MAAM,CAAC;QACP,kBAAkB;IACpB,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,uBAAuB,CAC9B,MAA+B,EAC/B,UAAkB,EAClB,iBAAkD;IAElD,MAAM,IAAI,GAAG,MAAM,CAAC,2BAA2B,CAAC,CAAC;IACjD,IAAI,IAAI,KAAK,UAAU,EAAE,CAAC;QACxB,kEAAkE;QAClE,4DAA4D;QAC5D,MAAM,QAAQ,GAA4B,EAAE,CAAC;QAC7C,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAC5C,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,aAAa,CAAC;gBAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACpD,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,MAAM,KAAK,GAAG,OAAO,MAAM,CAAC,2BAA2B,CAAC,KAAK,QAAQ;QACnE,CAAC,CAAE,MAAM,CAAC,2BAA2B,CAAY;QACjD,CAAC,CAAC,IAAI,CAAC;IACT,2EAA2E;IAC3E,4EAA4E;IAC5E,uEAAuE;IACvE,0EAA0E;IAC1E,uEAAuE;IACvE,+CAA+C;IAC/C,EAAE;IACF,uEAAuE;IACvE,uEAAuE;IACvE,0EAA0E;IAC1E,wBAAwB;IACxB,MAAM,eAAe,GAAG,OAAO,MAAM,CAAC,yBAAyB,CAAC,KAAK,QAAQ;QAC3E,CAAC,CAAE,MAAM,CAAC,yBAAyB,CAAY;QAC/C,CAAC,CAAC,IAAI,CAAC;IACT,MAAM,YAAY,GAAG,eAAe,IAAI,oBAAoB,CAAC,eAAe,EAAE,UAAU,CAAC;QACvF,CAAC,CAAC,eAAe;QACjB,CAAC,CAAC,IAAI,CAAC;IACT,IAAI,eAAe,IAAI,CAAC,YAAY,EAAE,CAAC;QACrC,OAAO,CAAC,KAAK,CACX,uEAAuE,eAAe,YAAY,UAAU,YAAY;YACxH,+EAA+E,CAChF,CAAC;IACJ,CAAC;IAED,yEAAyE;IACzE,wEAAwE;IACxE,8BAA8B;IAC9B,MAAM,KAAK,GAAG,iBAAiB,EAAE,CAAC;IAClC,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CACb,kEAAkE;YAClE,iEAAiE;YACjE,4EAA4E,CAC7E,CAAC;IACJ,CAAC;IAED,qEAAqE;IACrE,mDAAmD;IACnD,MAAM,QAAQ,GAA4B,EAAE,CAAC;IAC7C,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC5C,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,aAAa,CAAC;YAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACpD,CAAC;IAED,wEAAwE;IACxE,0EAA0E;IAC1E,4EAA4E;IAC5E,MAAM,IAAI,GAAG,CAAC,YAAY,IAAI,UAAU,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC9D,QAAQ,CAAC,gBAAgB,CAAC,GAAG,GAAG,IAAI,eAAe,CAAC;IAEpD,2EAA2E;IAC3E,wEAAwE;IACxE,yEAAyE;IACzE,6BAA6B;IAC7B,QAAQ,CAAC,gBAAgB,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC;IAE1C,sEAAsE;IACtE,+CAA+C;IAC/C,IAAI,KAAK,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC;QACxC,QAAQ,CAAC,eAAe,CAAC,GAAG,KAAK,CAAC;IACpC,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAmBD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,KAAK,UAAU,kBAAkB,CAC/B,MAA+B,EAC/B,IAKC;IAED,MAAM,UAAU,GAAG,OAAO,MAAM,CAAC,8BAA8B,CAAC,KAAK,QAAQ;QAC3E,CAAC,CAAE,MAAM,CAAC,8BAA8B,CAAY;QACpD,CAAC,CAAC,IAAI,CAAC;IACT,MAAM,OAAO,GAAG,OAAO,MAAM,CAAC,0BAA0B,CAAC,KAAK,QAAQ;QACpE,CAAC,CAAE,MAAM,CAAC,0BAA0B,CAAY;QAChD,CAAC,CAAC,IAAI,CAAC;IACT,MAAM,WAAW,GAAG,OAAO,MAAM,CAAC,+BAA+B,CAAC,KAAK,QAAQ;QAC7E,CAAC,CAAE,MAAM,CAAC,+BAA+B,CAAY;QACrD,CAAC,CAAC,IAAI,CAAC;IAET,IAAI,CAAC,UAAU,IAAI,CAAC,OAAO,EAAE,CAAC;QAC5B,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC3C,CAAC;IAED,sEAAsE;IACtE,0EAA0E;IAC1E,sEAAsE;IACtE,oEAAoE;IACpE,qCAAqC;IACrC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QAClB,OAAO;YACL,OAAO,EAAE,KAAK;YACd,OAAO;YACP,MAAM,EAAE,gHAAgH;SACzH,CAAC;IACJ,CAAC;IAED,uEAAuE;IACvE,uEAAuE;IACvE,oCAAoC;IACpC,IAAI,MAAc,CAAC;IACnB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,MAAM,CAAC,UAAU,CAAC,CAAC;IAClC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,OAAO,EAAE,KAAK;YACd,OAAO;YACP,MAAM,EAAE,iCAAiC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE;SAC5F,CAAC;IACJ,CAAC;IACD,IAAI,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC;QAC3D,OAAO;YACL,OAAO,EAAE,KAAK;YACd,OAAO;YACP,MAAM,EAAE,6BAA6B,MAAM,CAAC,OAAO,0BAA0B,OAAO,cAAc;SACnG,CAAC;IACJ,CAAC;IAED,sEAAsE;IACtE,uEAAuE;IACvE,0EAA0E;IAC1E,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACtB,MAAM,GAAG,GAAG,qCAAqC,EAAE,EAAE,CAAC;IACtD,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAEhD,oEAAoE;IACpE,wEAAwE;IACxE,mDAAmD;IACnD,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,yBAAyB,CAAC;IAC3E,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;IACnE,IAAI,MAAc,CAAC;IACnB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE;YAClC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;YAC3D,MAAM,EAAE,UAAU,CAAC,MAAM;SAC1B,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;YAC9C,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,OAAO;gBACP,MAAM,EAAE,kCAAkC,GAAG,CAAC,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;aAC7E,CAAC;QACJ,CAAC;QACD,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;QACtD,MAAM,CAAC,GAAG,oBAAoB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC/C,IAAI,CAAC,CAAC,EAAE,CAAC;YACP,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,OAAO;gBACP,MAAM,EAAE,oDAAoD;aAC7D,CAAC;QACJ,CAAC;QACD,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAChB,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;IAED,oEAAoE;IACpE,oEAAoE;IACpE,qEAAqE;IACrE,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,WAAW,EAAE,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IACvE,IAAI,CAAC;QACH,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1C,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,WAAW,EAAE,QAAQ,CAAC,EAAE,KAAK,CAAC,CAAC;IAC3D,CAAC;IAAC,MAAM,CAAC;QACP,wEAAwE;QACxE,gEAAgE;IAClE,CAAC;IACD,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,EAAE,kBAAkB,CAAC,CAAC;IACtD,MAAM,GAAG,GAAG;QACV,MAAM;QACN,UAAU;QACV,OAAO;QACP,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,WAAW,EAAE,WAAW,IAAI,IAAI;KACjC,CAAC;IACF,aAAa,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC/E,IAAI,CAAC;QACH,SAAS,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,iCAAiC;IACnC,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AACpC,CAAC;AAED;;;;GAIG;AACH,SAAS,sBAAsB,CAAC,MAA+B;IAC7D,MAAM,GAAG,GAA4B,EAAE,CAAC;IACxC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC5C,IAAI,CAAC,KAAK,8BAA8B;YAAE,SAAS;QACnD,IAAI,CAAC,KAAK,0BAA0B;YAAE,SAAS;QAC/C,IAAI,CAAC,KAAK,+BAA+B;YAAE,SAAS;QACpD,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACb,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;GAIG;AACH,SAAS,wBAAwB;IAC/B,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,WAAW,EAAE,kBAAkB,CAAC,CAAC;QACnE,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;YAAE,OAAO,IAAI,CAAC;QACxC,MAAM,GAAG,GAAG,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAC7C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAyB,CAAC;QACvD,IAAI,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC;QACrE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,IAAwB;IAExB,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACvD,MAAM,IAAI,KAAK,CACb,wDAAwD;YACxD,+DAA+D,CAChE,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,8BAA8B,CAAC;IACrE,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,MAAM,CAAC;IAC3C,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,QAAQ,CAAC;IAC7C,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,IAAI,KAAK,CAAC;IACrC,MAAM,MAAM,GACV,IAAI,CAAC,KAAK;QACV,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE;YACb,YAAY,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;IAEL,gCAAgC;IAChC,IAAI,QAAgB,CAAC;IACrB,IAAI,CAAC;QACH,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACrC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,sDAAsD,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CACzG,CAAC;IACJ,CAAC;IAED,sEAAsE;IACtE,8BAA8B;IAC9B,MAAM,KAAK,GAAG,MAAM,gBAAgB,CAAC,UAAU,EAAE,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;IAEjF,sEAAsE;IACtE,qDAAqD;IACrD,MAAM,MAAM,GAAG,aAAa,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IAE9C,mEAAmE;IACnE,6DAA6D;IAC7D,sEAAsE;IACtE,4DAA4D;IAC5D,oEAAoE;IACpE,kEAAkE;IAClE,gEAAgE;IAChE,iEAAiE;IACjE,0DAA0D;IAC1D,MAAM,mBAAmB,GAAG,MAAM,kBAAkB,CAAC,MAAM,EAAE;QAC3D,UAAU;QACV,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,OAAO;QACP,SAAS;KACV,CAAC,CAAC;IACH,IAAI,mBAAmB,CAAC,OAAO,EAAE,CAAC;QAChC,OAAO,CAAC,KAAK,CACX,iDAAiD,mBAAmB,CAAC,OAAO,MAAM;YAClF,8DAA8D,CAC/D,CAAC;IACJ,CAAC;SAAM,IAAI,mBAAmB,CAAC,MAAM,EAAE,CAAC;QACtC,OAAO,CAAC,KAAK,CAAC,8CAA8C,mBAAmB,CAAC,MAAM,EAAE,CAAC,CAAC;IAC5F,CAAC;IACD,MAAM,qBAAqB,GAAG,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAE7D,uEAAuE;IACvE,oEAAoE;IACpE,oEAAoE;IACpE,uEAAuE;IACvE,oEAAoE;IACpE,2CAA2C;IAC3C,EAAE;IACF,qEAAqE;IACrE,gDAAgD;IAChD,MAAM,WAAW,GAAG,IAAI,CAAC,kBAAkB,IAAI,wBAAwB,CAAC;IACxE,MAAM,QAAQ,GAAG,uBAAuB,CAAC,qBAAqB,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC;IAEzF,qEAAqE;IACrE,gDAAgD;IAChD,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,aAAa,CAAC,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IAEvF,OAAO;QACL,OAAO;QACP,QAAQ;QACR,YAAY,EAAE,KAAK,CAAC,YAAY;KACjC,CAAC;AACJ,CAAC"}
|