comfyui-mcp 0.43.0 → 0.44.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 +8 -0
- package/dist/config.js +42 -0
- package/dist/config.js.map +1 -1
- package/dist/orchestrator/agent-backend.js +24 -10
- package/dist/orchestrator/agent-backend.js.map +1 -1
- package/dist/orchestrator/antigravity-backend.js +575 -0
- package/dist/orchestrator/antigravity-backend.js.map +1 -0
- package/dist/orchestrator/backend-readiness.js +23 -14
- package/dist/orchestrator/backend-readiness.js.map +1 -1
- package/dist/orchestrator/copilot-backend.js +3 -2
- package/dist/orchestrator/copilot-backend.js.map +1 -1
- package/dist/orchestrator/index.js +267 -147
- package/dist/orchestrator/index.js.map +1 -1
- package/dist/orchestrator/panel-agent.js +138 -18
- package/dist/orchestrator/panel-agent.js.map +1 -1
- package/dist/orchestrator/panel-console-http.js +4 -3
- package/dist/orchestrator/panel-console-http.js.map +1 -1
- package/dist/orchestrator/start-failure-notice.js +63 -0
- package/dist/orchestrator/start-failure-notice.js.map +1 -0
- package/dist/services/code-provider-auth.js +49 -14
- package/dist/services/code-provider-auth.js.map +1 -1
- package/dist/services/job-history.js +50 -0
- package/dist/services/job-history.js.map +1 -1
- package/dist/services/job-watcher.js +2 -0
- package/dist/services/job-watcher.js.map +1 -1
- package/dist/services/openai-provider-registry.js +87 -0
- package/dist/services/openai-provider-registry.js.map +1 -0
- package/dist/services/panel-secrets.js +167 -59
- package/dist/services/panel-secrets.js.map +1 -1
- package/dist/services/queue-manager.js +2 -1
- package/dist/services/queue-manager.js.map +1 -1
- package/dist/services/queue-monitor.js +241 -7
- package/dist/services/queue-monitor.js.map +1 -1
- package/dist/services/queue-monitor.poll.test.js +267 -0
- package/dist/services/queue-monitor.poll.test.js.map +1 -0
- package/dist/services/queue-status-broadcast.js +26 -9
- package/dist/services/queue-status-broadcast.js.map +1 -1
- package/dist/services/queue-status-broadcast.test.js +49 -0
- package/dist/services/queue-status-broadcast.test.js.map +1 -1
- package/dist/services/runpod-client.js +190 -0
- package/dist/services/runpod-client.js.map +1 -0
- package/dist/services/runpod-watch.js +174 -0
- package/dist/services/runpod-watch.js.map +1 -0
- package/dist/tools/diagnostics.js +54 -27
- package/dist/tools/diagnostics.js.map +1 -1
- package/dist/tools/index.js +2 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/queue-management.js +1 -1
- package/dist/tools/queue-management.js.map +1 -1
- package/dist/tools/runpod.js +285 -0
- package/dist/tools/runpod.js.map +1 -0
- package/package.json +1 -1
- package/plugin/skills/ltx-director/SKILL.md +174 -0
- package/dist/orchestrator/glm-backend.js +0 -20
- package/dist/orchestrator/glm-backend.js.map +0 -1
- package/dist/orchestrator/moonshot-backend.js +0 -22
- package/dist/orchestrator/moonshot-backend.js.map +0 -1
|
@@ -0,0 +1,575 @@
|
|
|
1
|
+
// Google Antigravity CLI backend (issue #262) — the provider adapter behind the
|
|
2
|
+
// AgentBackend port for `agy`, the official Antigravity CLI that replaced the
|
|
3
|
+
// individual-tier Gemini CLI subscription path on 2026-06-18 (Google AI Pro /
|
|
4
|
+
// Ultra / free tiers moved to Antigravity; Gemini CLI remains for enterprise +
|
|
5
|
+
// API-key users, and keeps its own separate `gemini` backend here).
|
|
6
|
+
//
|
|
7
|
+
// Unlike the ACP/app-server adapters (gemini/codex), `agy` exposes NO documented
|
|
8
|
+
// machine-readable streaming protocol — only a plain-text non-interactive print
|
|
9
|
+
// mode. So this adapter is a SPAWN-PER-TURN driver over the supported public
|
|
10
|
+
// surface, exactly as requested in #262 ("start with final-text responses"):
|
|
11
|
+
//
|
|
12
|
+
// turn N=1 agy -p "<prompt>" [--model m] --dangerously-skip-permissions
|
|
13
|
+
// turn N>1 agy -c -p "<prompt>" ... (--continue = latest conversation)
|
|
14
|
+
// resume same as N>1 (`-c`); `agy` owns conversation storage
|
|
15
|
+
// interrupt() kill the in-flight child process tree (Windows taskkill /T /F)
|
|
16
|
+
// listModels() parse `agy models` (live account catalog — no static list)
|
|
17
|
+
//
|
|
18
|
+
// stdout is streamed to the panel as assistant deltas as it arrives (agy prints
|
|
19
|
+
// the final answer progressively in -p mode; if a build buffers, the deltas just
|
|
20
|
+
// land at once — still correct). There is no per-turn rewind anchor and no
|
|
21
|
+
// in-process MCP: forkAtAnchor=false, inProcessMcp=false.
|
|
22
|
+
//
|
|
23
|
+
// AUTH: the CLI owns authentication (system keyring + Google Sign-In). Per #262
|
|
24
|
+
// we deliberately do NOT read tokens from the keyring or Antigravity state files
|
|
25
|
+
// — readiness is "the executable exists", and the real auth signal is whether
|
|
26
|
+
// `agy models` answers (the connect ack's model probe). An unauthenticated CLI
|
|
27
|
+
// gets an actionable "run `agy` once and sign in" message.
|
|
28
|
+
//
|
|
29
|
+
// MCP / ComfyUI tools: `agy` reads MCP servers from a per-workspace
|
|
30
|
+
// `.agents/mcp_config.json` (and a global ~/.gemini/config/mcp_config.json we
|
|
31
|
+
// NEVER touch). Before the first turn we MERGE our two servers — the headless
|
|
32
|
+
// `comfyui` stdio MCP and the per-tab `panel` HTTP MCP — into the workspace file
|
|
33
|
+
// under our own names, preserving every other entry byte-for-byte. Scoped,
|
|
34
|
+
// merge-safe, reversible (delete the two keys) — per #262's requirements.
|
|
35
|
+
//
|
|
36
|
+
// LIMITS (flagged honestly, mirrors the issue's "reduced capabilities" ask):
|
|
37
|
+
// - `-p` prints plain text: no structured tool-call events, so the panel shows
|
|
38
|
+
// no per-tool progress for agy turns (onActivity still fires on every stdout
|
|
39
|
+
// chunk, keeping the idle watchdog armed).
|
|
40
|
+
// - `--continue` binds to the account's LATEST conversation; a user running
|
|
41
|
+
// `agy` interactively in parallel can steal continuity. The supported
|
|
42
|
+
// surface offers no way to read the new conversation's id from -p output.
|
|
43
|
+
// - No documented image-input path for -p → vision=false (image refs are
|
|
44
|
+
// already named in the turn text as a fallback).
|
|
45
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
46
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
47
|
+
import { homedir } from "node:os";
|
|
48
|
+
import { join } from "node:path";
|
|
49
|
+
import { logger } from "../utils/logger.js";
|
|
50
|
+
import { ANTIGRAVITY_CAPABILITIES, } from "./agent-backend.js";
|
|
51
|
+
function msgOf(err) {
|
|
52
|
+
return err instanceof Error ? err.message : String(err);
|
|
53
|
+
}
|
|
54
|
+
/** Kill an entire process tree (identical posture to gemini/codex-backend):
|
|
55
|
+
* Windows taskkill /T /F; POSIX negative-pid process-group signal with a
|
|
56
|
+
* single-pid fallback. Best-effort — teardown must never throw. */
|
|
57
|
+
function killProcessTree(pid) {
|
|
58
|
+
if (!Number.isFinite(pid))
|
|
59
|
+
return;
|
|
60
|
+
const p = pid;
|
|
61
|
+
if (process.platform === "win32") {
|
|
62
|
+
try {
|
|
63
|
+
spawnSync("taskkill", ["/PID", String(p), "/T", "/F"], { windowsHide: true });
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
try {
|
|
67
|
+
process.kill(p);
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
// already gone
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
try {
|
|
76
|
+
process.kill(-p, "SIGTERM");
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
try {
|
|
80
|
+
process.kill(p, "SIGTERM");
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
// already gone
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Resolve the `agy` executable. Order: COMFYUI_MCP_ANTIGRAVITY_PATH (explicit
|
|
89
|
+
* escape hatch) → PATH (agy / agy.exe) → the official installers' well-known
|
|
90
|
+
* locations (%LOCALAPPDATA%\agy\bin on Windows, ~/.local/bin elsewhere).
|
|
91
|
+
* Returns an absolute path when found on disk, the bare name as a last resort,
|
|
92
|
+
* or null when clearly absent. We never spawn through a shell — the prompt is
|
|
93
|
+
* user data, and the official installers ship a real executable (a `.cmd` npm
|
|
94
|
+
* shim is NOT supported; Node refuses shell-less .cmd spawns post-CVE-2024-27980,
|
|
95
|
+
* and shell quoting of arbitrary prompt text would be an injection risk).
|
|
96
|
+
*/
|
|
97
|
+
export function resolveAgyBin(home = homedir()) {
|
|
98
|
+
const override = process.env.COMFYUI_MCP_ANTIGRAVITY_PATH?.trim();
|
|
99
|
+
if (override)
|
|
100
|
+
return override;
|
|
101
|
+
const names = process.platform === "win32" ? ["agy.exe", "agy"] : ["agy"];
|
|
102
|
+
const sep = process.platform === "win32" ? ";" : ":";
|
|
103
|
+
for (const dir of (process.env.PATH || "").split(sep).filter(Boolean)) {
|
|
104
|
+
for (const name of names) {
|
|
105
|
+
try {
|
|
106
|
+
const full = join(dir, name);
|
|
107
|
+
if (existsSync(full))
|
|
108
|
+
return full;
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
// unreadable PATH entry — skip
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
const wellKnown = process.platform === "win32"
|
|
116
|
+
? [join(process.env.LOCALAPPDATA || join(home, "AppData", "Local"), "agy", "bin", "agy.exe")]
|
|
117
|
+
: [join(home, ".local", "bin", "agy"), "/usr/local/bin/agy", "/opt/homebrew/bin/agy"];
|
|
118
|
+
for (const p of wellKnown) {
|
|
119
|
+
try {
|
|
120
|
+
if (existsSync(p))
|
|
121
|
+
return p;
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
// skip
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
/** Strip ANSI escape sequences (agy's TUI heritage may color even -p output). */
|
|
130
|
+
function stripAnsi(s) {
|
|
131
|
+
// eslint-disable-next-line no-control-regex
|
|
132
|
+
return s.replace(/\[[0-9;?]*[ -/]*[@-~]/g, "");
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Parse `agy models` output into ModelChoices. The format is not a documented
|
|
136
|
+
* contract, so this is deliberately TOLERANT: strip ANSI, take each non-empty
|
|
137
|
+
* line, drop obvious headers/rules/prose, strip list markers and a
|
|
138
|
+
* "(default)"/"(current)" tag, and keep the first token when it looks like a
|
|
139
|
+
* model id. A `*`-marked or "(default)" row is surfaced first. Returns [] when
|
|
140
|
+
* nothing parses (the panel degrades gracefully on an empty list).
|
|
141
|
+
*/
|
|
142
|
+
export function parseAgyModels(output) {
|
|
143
|
+
const out = [];
|
|
144
|
+
let defaultId = null;
|
|
145
|
+
for (const raw of stripAnsi(output).split(/\r?\n/)) {
|
|
146
|
+
const line = raw.trim();
|
|
147
|
+
if (!line)
|
|
148
|
+
continue;
|
|
149
|
+
// Header / separator / prose rows.
|
|
150
|
+
if (/^[-=─│+|]+$/.test(line))
|
|
151
|
+
continue;
|
|
152
|
+
if (/^(available|models?|name|id|description|usage|use )\b/i.test(line) && !/^[a-z0-9][\w.:/-]*$/i.test(line))
|
|
153
|
+
continue;
|
|
154
|
+
const marked = /^[*✓✔>]/.test(line);
|
|
155
|
+
const cleaned = line.replace(/^[*✓✔>•\-\s]+/, "");
|
|
156
|
+
const isDefault = marked || /\((default|current|active)\)/i.test(cleaned);
|
|
157
|
+
const token = cleaned.split(/\s+/)[0]?.replace(/[,;]$/, "") ?? "";
|
|
158
|
+
// A plausible model id: starts alphanumeric, id-ish charset, has a digit or
|
|
159
|
+
// dash (filters prose words like "Run"), not an obvious column header.
|
|
160
|
+
if (!/^[a-z0-9][\w.:/-]*$/i.test(token))
|
|
161
|
+
continue;
|
|
162
|
+
if (!/[\d-]/.test(token))
|
|
163
|
+
continue;
|
|
164
|
+
if (/^(name|model|models|id)$/i.test(token))
|
|
165
|
+
continue;
|
|
166
|
+
if (out.some((m) => m.id === token))
|
|
167
|
+
continue;
|
|
168
|
+
out.push({ id: token });
|
|
169
|
+
if (isDefault && !defaultId)
|
|
170
|
+
defaultId = token;
|
|
171
|
+
}
|
|
172
|
+
if (defaultId) {
|
|
173
|
+
out.sort((a, b) => (a.id === defaultId ? -1 : b.id === defaultId ? 1 : 0));
|
|
174
|
+
}
|
|
175
|
+
return out;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Merge our MCP servers into a workspace `.agents/mcp_config.json`, preserving
|
|
179
|
+
* every entry we don't own. Antigravity's schema (per the official docs): local
|
|
180
|
+
* servers are { command, args, env: {K:V} }, remote ones { serverUrl }. Handles
|
|
181
|
+
* both the bare { name: {...} } layout and a { mcpServers: { name: {...} } }
|
|
182
|
+
* wrapper, preferring whichever the existing file already uses (wrapper when
|
|
183
|
+
* creating fresh). Returns the merged JSON text it wrote (for tests).
|
|
184
|
+
*/
|
|
185
|
+
export function mergeAgyMcpConfig(existingText, servers) {
|
|
186
|
+
let root = {};
|
|
187
|
+
try {
|
|
188
|
+
if (existingText?.trim())
|
|
189
|
+
root = JSON.parse(existingText);
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
// Unparseable user file: do NOT clobber it — merge into a fresh wrapper and
|
|
193
|
+
// let the caller decide; we keep the unparseable original under a backup key
|
|
194
|
+
// is worse than refusing. Treat as empty but log at the call site.
|
|
195
|
+
root = {};
|
|
196
|
+
}
|
|
197
|
+
const hasWrapper = typeof root.mcpServers === "object" && root.mcpServers !== null && !Array.isArray(root.mcpServers);
|
|
198
|
+
// If the file is bare-layout (top-level server entries, no mcpServers key and
|
|
199
|
+
// at least one object value), keep that layout; otherwise use the wrapper.
|
|
200
|
+
const bareLayout = !hasWrapper && Object.values(root).some((v) => typeof v === "object" && v !== null);
|
|
201
|
+
const target = bareLayout
|
|
202
|
+
? root
|
|
203
|
+
: (root.mcpServers ?? {});
|
|
204
|
+
for (const [name, spec] of Object.entries(servers)) {
|
|
205
|
+
target[name] =
|
|
206
|
+
spec.transport === "stdio"
|
|
207
|
+
? { command: spec.command, args: spec.args ?? [], env: spec.env ?? {} }
|
|
208
|
+
: { serverUrl: spec.url };
|
|
209
|
+
}
|
|
210
|
+
const merged = bareLayout ? target : { ...root, mcpServers: target };
|
|
211
|
+
return `${JSON.stringify(merged, null, 2)}\n`;
|
|
212
|
+
}
|
|
213
|
+
/** Sentinel session id: agy owns conversation storage and -p output carries no
|
|
214
|
+
* conversation id, so "resume" means `--continue` (the account's latest). */
|
|
215
|
+
const AGY_SESSION_SENTINEL = "antigravity-latest";
|
|
216
|
+
/**
|
|
217
|
+
* The Antigravity CLI adapter. One instance per PanelAgent; spawn-per-turn, so
|
|
218
|
+
* there is no persistent child between turns — only the in-flight one.
|
|
219
|
+
*/
|
|
220
|
+
export class AntigravityBackend {
|
|
221
|
+
id = "antigravity";
|
|
222
|
+
capabilities = ANTIGRAVITY_CAPABILITIES;
|
|
223
|
+
deps;
|
|
224
|
+
model;
|
|
225
|
+
bin; // undefined = not yet resolved
|
|
226
|
+
/** The in-flight per-turn child (interrupt/close kill its tree). */
|
|
227
|
+
child = null;
|
|
228
|
+
interrupted = false;
|
|
229
|
+
disposed = false;
|
|
230
|
+
/** False until the first turn of a FRESH conversation completes; resumed
|
|
231
|
+
* sessions start true so every turn continues the latest conversation. */
|
|
232
|
+
continueNext = false;
|
|
233
|
+
needsSystemPreamble = false;
|
|
234
|
+
mcpConfigWritten = false;
|
|
235
|
+
constructor(deps = {}) {
|
|
236
|
+
this.deps = deps;
|
|
237
|
+
this.model = deps.model;
|
|
238
|
+
}
|
|
239
|
+
resolveBin() {
|
|
240
|
+
if (this.bin === undefined)
|
|
241
|
+
this.bin = resolveAgyBin();
|
|
242
|
+
if (!this.bin) {
|
|
243
|
+
throw new Error("Antigravity CLI (`agy`) not found. Install it from https://antigravity.google " +
|
|
244
|
+
"(Windows: `irm https://antigravity.google/cli/install.ps1 | iex`; macOS/Linux: " +
|
|
245
|
+
"`curl -fsSL https://antigravity.google/cli/install.sh | bash`), run `agy` once to " +
|
|
246
|
+
"sign in with your Google account, then reconnect. You can also point " +
|
|
247
|
+
"COMFYUI_MCP_ANTIGRAVITY_PATH at the executable.");
|
|
248
|
+
}
|
|
249
|
+
return this.bin;
|
|
250
|
+
}
|
|
251
|
+
/** One-time preflight: resolve the executable so a missing install fails fast
|
|
252
|
+
* with the actionable message above (mirrors the other CLI backends). */
|
|
253
|
+
async prepare() {
|
|
254
|
+
if (this.disposed)
|
|
255
|
+
throw new Error("antigravity backend is closed.");
|
|
256
|
+
this.resolveBin();
|
|
257
|
+
}
|
|
258
|
+
/** Merge our MCP servers into the workspace .agents/mcp_config.json (once per
|
|
259
|
+
* backend instance). Never touches the global ~/.gemini/config/mcp_config.json.
|
|
260
|
+
* Failure is non-fatal: the agent still answers, just without ComfyUI tools —
|
|
261
|
+
* logged so the gap is visible. */
|
|
262
|
+
ensureMcpConfig(cwd) {
|
|
263
|
+
if (this.mcpConfigWritten || !this.deps.mcpServers || !Object.keys(this.deps.mcpServers).length)
|
|
264
|
+
return;
|
|
265
|
+
const dir = join(cwd, ".agents");
|
|
266
|
+
const file = join(dir, "mcp_config.json");
|
|
267
|
+
try {
|
|
268
|
+
let existing = null;
|
|
269
|
+
try {
|
|
270
|
+
existing = readFileSync(file, "utf8");
|
|
271
|
+
}
|
|
272
|
+
catch {
|
|
273
|
+
existing = null;
|
|
274
|
+
}
|
|
275
|
+
if (existing) {
|
|
276
|
+
try {
|
|
277
|
+
JSON.parse(existing);
|
|
278
|
+
}
|
|
279
|
+
catch {
|
|
280
|
+
logger.warn(`[antigravity-backend] ${file} exists but is not valid JSON — leaving it untouched (ComfyUI MCP tools will be unavailable to agy until it parses)`);
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
mkdirSync(dir, { recursive: true });
|
|
285
|
+
writeFileSync(file, mergeAgyMcpConfig(existing, this.deps.mcpServers), "utf8");
|
|
286
|
+
this.mcpConfigWritten = true;
|
|
287
|
+
logger.info(`[antigravity-backend] merged comfyui/panel MCP servers into ${file}`);
|
|
288
|
+
}
|
|
289
|
+
catch (err) {
|
|
290
|
+
logger.warn(`[antigravity-backend] could not write ${file}: ${msgOf(err)}`);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Drive the session: one `agy -p` child per neutral turn, continuity via
|
|
295
|
+
* `--continue`. The channel async-iteration IS the turn gate (PanelAgent
|
|
296
|
+
* releases one batch per turn).
|
|
297
|
+
*/
|
|
298
|
+
async *run(opts) {
|
|
299
|
+
// Panel may pass the Claude panel model unconditionally — only honor a model
|
|
300
|
+
// that plausibly belongs to this provider (anything not Claude-shaped; the
|
|
301
|
+
// real catalog is the account's own `agy models`).
|
|
302
|
+
if (opts.model && !/^claude/i.test(opts.model))
|
|
303
|
+
this.model = opts.model;
|
|
304
|
+
await this.prepare();
|
|
305
|
+
const cwd = opts.cwd ?? this.deps.cwd ?? process.cwd();
|
|
306
|
+
this.ensureMcpConfig(cwd);
|
|
307
|
+
const resuming = !!(opts.resume ?? opts.sessionId);
|
|
308
|
+
this.continueNext = resuming;
|
|
309
|
+
this.needsSystemPreamble = !resuming && !!this.deps.systemAppend;
|
|
310
|
+
yield {
|
|
311
|
+
type: "session",
|
|
312
|
+
sessionId: AGY_SESSION_SENTINEL,
|
|
313
|
+
...(this.model ? { model: this.model } : {}),
|
|
314
|
+
};
|
|
315
|
+
for await (const turn of opts.channel) {
|
|
316
|
+
yield* this.runTurn(turn, cwd, opts.onActivity);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
/** Run ONE turn = one `agy -p` child. stdout streams as assistant deltas;
|
|
320
|
+
* exit 0 commits the accumulated text and a successful result; a non-zero
|
|
321
|
+
* exit (or spawn failure) surfaces an error + failed result. Exactly one
|
|
322
|
+
* terminal result per turn (PanelAgent's gate depends on it). */
|
|
323
|
+
async *runTurn(turn, cwd, onActivity) {
|
|
324
|
+
let text = turn.text;
|
|
325
|
+
if (this.needsSystemPreamble && this.deps.systemAppend) {
|
|
326
|
+
text =
|
|
327
|
+
`<system>\n${this.deps.systemAppend}\n</system>\n\n` +
|
|
328
|
+
`The user's first message follows.\n\n${turn.text}`;
|
|
329
|
+
this.needsSystemPreamble = false;
|
|
330
|
+
}
|
|
331
|
+
// Image refs: no documented -p image input — the refs are already named in
|
|
332
|
+
// the turn text (vision=false tells the panel up front).
|
|
333
|
+
const bin = this.resolveBin();
|
|
334
|
+
const timeout = process.env.COMFYUI_MCP_ANTIGRAVITY_PRINT_TIMEOUT?.trim() || "45m";
|
|
335
|
+
const args = [
|
|
336
|
+
...(this.continueNext ? ["-c"] : []),
|
|
337
|
+
"-p",
|
|
338
|
+
text,
|
|
339
|
+
"--print-timeout",
|
|
340
|
+
timeout,
|
|
341
|
+
// The panel agent is an isolated background agent (same posture as
|
|
342
|
+
// Claude bypassPermissions / the ACP auto-approve): tool calls must not
|
|
343
|
+
// block on an interactive prompt that nothing will ever answer.
|
|
344
|
+
"--dangerously-skip-permissions",
|
|
345
|
+
...(this.model ? ["--model", this.model] : []),
|
|
346
|
+
];
|
|
347
|
+
// NOTE: `interrupted` is deliberately NOT cleared here. A Stop can land
|
|
348
|
+
// while this turn is still starting up (run() awaits prepare() and the
|
|
349
|
+
// channel before reaching runTurn), and clearing at turn START silently
|
|
350
|
+
// discarded it — the turn then ran with nothing able to stop it. The flag is
|
|
351
|
+
// cleared when a turn SETTLES instead, so it survives setup and the child
|
|
352
|
+
// assignment below acts on it.
|
|
353
|
+
const queue = [];
|
|
354
|
+
let wake = null;
|
|
355
|
+
let done = false;
|
|
356
|
+
const push = (ev) => {
|
|
357
|
+
queue.push(ev);
|
|
358
|
+
wake?.();
|
|
359
|
+
wake = null;
|
|
360
|
+
};
|
|
361
|
+
const finish = () => {
|
|
362
|
+
done = true;
|
|
363
|
+
wake?.();
|
|
364
|
+
wake = null;
|
|
365
|
+
};
|
|
366
|
+
let out = "";
|
|
367
|
+
let errOut = "";
|
|
368
|
+
let streamOpen = false;
|
|
369
|
+
let child;
|
|
370
|
+
try {
|
|
371
|
+
child = spawn(bin, args, {
|
|
372
|
+
cwd,
|
|
373
|
+
env: process.env,
|
|
374
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
375
|
+
windowsHide: true,
|
|
376
|
+
detached: process.platform !== "win32",
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
catch (err) {
|
|
380
|
+
yield { type: "error", message: `Could not start agy: ${msgOf(err)}` };
|
|
381
|
+
yield { type: "result", ok: false, subtype: "error" };
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
this.child = child;
|
|
385
|
+
// LIVENESS heartbeat: agy -p may print NOTHING for minutes while it works
|
|
386
|
+
// (tool calls, long generations) — there is no event stream to observe. The
|
|
387
|
+
// child process being alive is the only honest liveness signal, so bump the
|
|
388
|
+
// idle watchdog on an interval while it runs. A truly hung child is bounded
|
|
389
|
+
// by agy's own --print-timeout, which ends the turn with a non-zero exit.
|
|
390
|
+
const heartbeat = setInterval(() => {
|
|
391
|
+
try {
|
|
392
|
+
onActivity?.();
|
|
393
|
+
}
|
|
394
|
+
catch {
|
|
395
|
+
// watchdog bump must never throw
|
|
396
|
+
}
|
|
397
|
+
}, 15_000);
|
|
398
|
+
heartbeat.unref?.();
|
|
399
|
+
child.stdout.setEncoding("utf8");
|
|
400
|
+
child.stderr.setEncoding("utf8");
|
|
401
|
+
child.stdout.on("data", (chunk) => {
|
|
402
|
+
try {
|
|
403
|
+
onActivity?.();
|
|
404
|
+
}
|
|
405
|
+
catch {
|
|
406
|
+
// watchdog bump must never break the reader
|
|
407
|
+
}
|
|
408
|
+
const clean = stripAnsi(chunk);
|
|
409
|
+
if (!clean)
|
|
410
|
+
return;
|
|
411
|
+
out += clean;
|
|
412
|
+
if (!streamOpen) {
|
|
413
|
+
streamOpen = true;
|
|
414
|
+
push({ type: "stream_start", id: null });
|
|
415
|
+
}
|
|
416
|
+
push({ type: "assistant_delta", text: clean });
|
|
417
|
+
});
|
|
418
|
+
child.stderr.on("data", (chunk) => {
|
|
419
|
+
try {
|
|
420
|
+
onActivity?.();
|
|
421
|
+
}
|
|
422
|
+
catch {
|
|
423
|
+
// ignore
|
|
424
|
+
}
|
|
425
|
+
errOut += chunk;
|
|
426
|
+
});
|
|
427
|
+
let settled = false;
|
|
428
|
+
const settle = (code, spawnErr) => {
|
|
429
|
+
if (settled)
|
|
430
|
+
return;
|
|
431
|
+
settled = true;
|
|
432
|
+
clearInterval(heartbeat);
|
|
433
|
+
if (this.child === child)
|
|
434
|
+
this.child = null;
|
|
435
|
+
if (streamOpen)
|
|
436
|
+
push({ type: "stream_end" });
|
|
437
|
+
const finalText = out.trim();
|
|
438
|
+
if (this.interrupted) {
|
|
439
|
+
if (finalText)
|
|
440
|
+
push({ type: "assistant", text: finalText });
|
|
441
|
+
push({ type: "result", ok: false, subtype: "cancelled" });
|
|
442
|
+
}
|
|
443
|
+
else if (spawnErr || code !== 0) {
|
|
444
|
+
const stderrTail = stripAnsi(errOut).trim().split(/\r?\n/).slice(-3).join(" ").trim();
|
|
445
|
+
const authish = /sign.?in|log.?in|auth|credential|unauthoriz/i.test(stderrTail + finalText);
|
|
446
|
+
const message = spawnErr
|
|
447
|
+
? /ENOENT/i.test(spawnErr.message)
|
|
448
|
+
? "Antigravity CLI (`agy`) could not be launched — it may have been uninstalled. Reinstall from https://antigravity.google and reconnect."
|
|
449
|
+
: `agy failed to start: ${spawnErr.message}`
|
|
450
|
+
: authish
|
|
451
|
+
? `Antigravity CLI is not signed in. Run \`agy\` once in a terminal, complete the Google Sign-In, then send your message again.${stderrTail ? ` (agy: ${stderrTail})` : ""}`
|
|
452
|
+
: `agy exited with code ${code}.${stderrTail ? ` ${stderrTail}` : ""}`;
|
|
453
|
+
push({ type: "error", message });
|
|
454
|
+
push({ type: "result", ok: false, subtype: "error" });
|
|
455
|
+
}
|
|
456
|
+
else {
|
|
457
|
+
if (finalText)
|
|
458
|
+
push({ type: "assistant", text: finalText });
|
|
459
|
+
// From here on, continue the conversation agy just recorded.
|
|
460
|
+
this.continueNext = true;
|
|
461
|
+
push({ type: "result", ok: true, subtype: "end_turn" });
|
|
462
|
+
}
|
|
463
|
+
// Clear the interrupt HERE (turn end), not at turn start — see the note
|
|
464
|
+
// where the queue is set up. The flag has now been consumed to pick this
|
|
465
|
+
// turn's result, so the next turn starts clean.
|
|
466
|
+
this.interrupted = false;
|
|
467
|
+
finish();
|
|
468
|
+
};
|
|
469
|
+
child.on("error", (err) => settle(null, err));
|
|
470
|
+
child.on("exit", (code) => settle(code));
|
|
471
|
+
// An interrupt can arrive while spawn() is in flight — `this.child` was
|
|
472
|
+
// still null then, so interrupt() could only raise the flag. Honor it now.
|
|
473
|
+
// This MUST come after the exit/error listeners above: killing earlier can
|
|
474
|
+
// deliver the child's death before anything is listening, and then the turn
|
|
475
|
+
// never settles (exactly what hung the interrupt test).
|
|
476
|
+
if (this.interrupted)
|
|
477
|
+
killProcessTree(child.pid);
|
|
478
|
+
// Drain the bridged queue until the child settles.
|
|
479
|
+
while (true) {
|
|
480
|
+
while (queue.length)
|
|
481
|
+
yield queue.shift();
|
|
482
|
+
if (done)
|
|
483
|
+
break;
|
|
484
|
+
await new Promise((resolve) => {
|
|
485
|
+
wake = resolve;
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
while (queue.length)
|
|
489
|
+
yield queue.shift();
|
|
490
|
+
}
|
|
491
|
+
/** Stop the current turn: kill the in-flight child's process tree. The next
|
|
492
|
+
* turn continues the conversation (`-c`) with whatever agy recorded. */
|
|
493
|
+
async interrupt() {
|
|
494
|
+
// Set the flag FIRST and UNCONDITIONALLY. `this.child` is only assigned
|
|
495
|
+
// after spawn() returns, so an interrupt landing in that window used to hit
|
|
496
|
+
// the `if (!child) return` below, leave `interrupted` false, and never kill
|
|
497
|
+
// anything — the turn then ran to completion with nothing able to stop it.
|
|
498
|
+
// In the panel that is "hit Stop right after Send and the turn hangs
|
|
499
|
+
// forever"; in CI it was a 5s timeout in the interrupt test. run() re-checks
|
|
500
|
+
// this flag the moment it assigns the child, so a kill is never lost.
|
|
501
|
+
this.interrupted = true;
|
|
502
|
+
const child = this.child;
|
|
503
|
+
if (!child)
|
|
504
|
+
return; // spawn window — run() kills it as soon as it exists
|
|
505
|
+
killProcessTree(child.pid);
|
|
506
|
+
}
|
|
507
|
+
/** Switch the model for subsequent turns (--model is per-spawn, so this is
|
|
508
|
+
* free — no respawn dance). Ignores Claude-shaped ids the panel may pass. */
|
|
509
|
+
async setModel(model) {
|
|
510
|
+
if (/^claude/i.test(model))
|
|
511
|
+
return;
|
|
512
|
+
this.model = model;
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Enumerate the account's models via `agy models` (per #262: parse the live
|
|
516
|
+
* catalog, never ship a static list). Also serves as the safe auth probe: an
|
|
517
|
+
* unauthenticated CLI fails here → the connect ack degrades with sign-in
|
|
518
|
+
* guidance instead of greeting ready.
|
|
519
|
+
*/
|
|
520
|
+
async listModels() {
|
|
521
|
+
const bin = this.resolveBin();
|
|
522
|
+
return await new Promise((resolve, reject) => {
|
|
523
|
+
let out = "";
|
|
524
|
+
let err = "";
|
|
525
|
+
let child;
|
|
526
|
+
try {
|
|
527
|
+
child = spawn(bin, ["models"], {
|
|
528
|
+
cwd: this.deps.cwd ?? process.cwd(),
|
|
529
|
+
env: process.env,
|
|
530
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
531
|
+
windowsHide: true,
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
catch (e) {
|
|
535
|
+
reject(new Error(`Could not run \`agy models\`: ${msgOf(e)}`));
|
|
536
|
+
return;
|
|
537
|
+
}
|
|
538
|
+
const timer = setTimeout(() => {
|
|
539
|
+
killProcessTree(child.pid);
|
|
540
|
+
reject(new Error("`agy models` timed out after 30s."));
|
|
541
|
+
}, 30_000);
|
|
542
|
+
timer.unref?.();
|
|
543
|
+
child.stdout.setEncoding("utf8");
|
|
544
|
+
child.stderr.setEncoding("utf8");
|
|
545
|
+
child.stdout.on("data", (c) => (out += c));
|
|
546
|
+
child.stderr.on("data", (c) => (err += c));
|
|
547
|
+
child.on("error", (e) => {
|
|
548
|
+
clearTimeout(timer);
|
|
549
|
+
reject(new Error(`Could not run \`agy models\`: ${e.message}`));
|
|
550
|
+
});
|
|
551
|
+
child.on("exit", (code) => {
|
|
552
|
+
clearTimeout(timer);
|
|
553
|
+
if (code === 0) {
|
|
554
|
+
resolve(parseAgyModels(out));
|
|
555
|
+
}
|
|
556
|
+
else {
|
|
557
|
+
const tail = stripAnsi(err || out).trim().split(/\r?\n/).slice(-2).join(" ");
|
|
558
|
+
reject(new Error(`\`agy models\` exited with code ${code}${tail ? ` (${tail})` : ""}. ` +
|
|
559
|
+
"If you haven't signed in yet, run `agy` once and complete the Google Sign-In."));
|
|
560
|
+
}
|
|
561
|
+
});
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
/** Dispose: kill any in-flight child tree. Idempotent, safe when never started. */
|
|
565
|
+
async close() {
|
|
566
|
+
this.disposed = true;
|
|
567
|
+
const child = this.child;
|
|
568
|
+
this.child = null;
|
|
569
|
+
if (child) {
|
|
570
|
+
this.interrupted = true;
|
|
571
|
+
killProcessTree(child.pid);
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
//# sourceMappingURL=antigravity-backend.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"antigravity-backend.js","sourceRoot":"","sources":["../../src/orchestrator/antigravity-backend.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,8EAA8E;AAC9E,8EAA8E;AAC9E,+EAA+E;AAC/E,oEAAoE;AACpE,EAAE;AACF,iFAAiF;AACjF,gFAAgF;AAChF,6EAA6E;AAC7E,6EAA6E;AAC7E,EAAE;AACF,iFAAiF;AACjF,uFAAuF;AACvF,wEAAwE;AACxE,mFAAmF;AACnF,+EAA+E;AAC/E,EAAE;AACF,gFAAgF;AAChF,iFAAiF;AACjF,2EAA2E;AAC3E,0DAA0D;AAC1D,EAAE;AACF,gFAAgF;AAChF,iFAAiF;AACjF,8EAA8E;AAC9E,+EAA+E;AAC/E,2DAA2D;AAC3D,EAAE;AACF,oEAAoE;AACpE,8EAA8E;AAC9E,8EAA8E;AAC9E,iFAAiF;AACjF,2EAA2E;AAC3E,0EAA0E;AAC1E,EAAE;AACF,6EAA6E;AAC7E,iFAAiF;AACjF,iFAAiF;AACjF,+CAA+C;AAC/C,8EAA8E;AAC9E,0EAA0E;AAC1E,8EAA8E;AAC9E,2EAA2E;AAC3E,qDAAqD;AAErD,OAAO,EAAE,KAAK,EAAE,SAAS,EAA4B,MAAM,oBAAoB,CAAC;AAMhF,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAML,wBAAwB,GACzB,MAAM,oBAAoB,CAAC;AAG5B,SAAS,KAAK,CAAC,GAAY;IACzB,OAAO,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AAC1D,CAAC;AAED;;oEAEoE;AACpE,SAAS,eAAe,CAAC,GAAuB;IAC9C,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO;IAClC,MAAM,CAAC,GAAG,GAAa,CAAC;IACxB,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,IAAI,CAAC;YACH,SAAS,CAAC,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC;QAChF,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,CAAC;gBACH,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YAAC,MAAM,CAAC;gBACP,eAAe;YACjB,CAAC;QACH,CAAC;QACD,OAAO;IACT,CAAC;IACD,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,IAAI,CAAC;YACH,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;QAC7B,CAAC;QAAC,MAAM,CAAC;YACP,eAAe;QACjB,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,aAAa,CAAC,OAAe,OAAO,EAAE;IACpD,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,4BAA4B,EAAE,IAAI,EAAE,CAAC;IAClE,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC9B,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IAC1E,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;IACrD,KAAK,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;QACtE,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;gBAC7B,IAAI,UAAU,CAAC,IAAI,CAAC;oBAAE,OAAO,IAAI,CAAC;YACpC,CAAC;YAAC,MAAM,CAAC;gBACP,+BAA+B;YACjC,CAAC;QACH,CAAC;IACH,CAAC;IACD,MAAM,SAAS,GACb,OAAO,CAAC,QAAQ,KAAK,OAAO;QAC1B,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;QAC7F,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,CAAC,EAAE,oBAAoB,EAAE,uBAAuB,CAAC,CAAC;IAC1F,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;QAC1B,IAAI,CAAC;YACH,IAAI,UAAU,CAAC,CAAC,CAAC;gBAAE,OAAO,CAAC,CAAC;QAC9B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO;QACT,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,iFAAiF;AACjF,SAAS,SAAS,CAAC,CAAS;IAC1B,4CAA4C;IAC5C,OAAO,CAAC,CAAC,OAAO,CAAC,yBAAyB,EAAE,EAAE,CAAC,CAAC;AAClD,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAC,MAAc;IAC3C,MAAM,GAAG,GAAkB,EAAE,CAAC;IAC9B,IAAI,SAAS,GAAkB,IAAI,CAAC;IACpC,KAAK,MAAM,GAAG,IAAI,SAAS,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QACnD,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;QACxB,IAAI,CAAC,IAAI;YAAE,SAAS;QACpB,mCAAmC;QACnC,IAAI,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,SAAS;QACvC,IAAI,wDAAwD,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,SAAS;QACxH,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC,CAAC;QAClD,MAAM,SAAS,GAAG,MAAM,IAAI,+BAA+B,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC1E,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC;QAClE,4EAA4E;QAC5E,uEAAuE;QACvE,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,KAAK,CAAC;YAAE,SAAS;QAClD,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC;YAAE,SAAS;QACnC,IAAI,2BAA2B,CAAC,IAAI,CAAC,KAAK,CAAC;YAAE,SAAS;QACtD,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,CAAC;YAAE,SAAS;QAC9C,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QACxB,IAAI,SAAS,IAAI,CAAC,SAAS;YAAE,SAAS,GAAG,KAAK,CAAC;IACjD,CAAC;IACD,IAAI,SAAS,EAAE,CAAC;QACd,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7E,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAC/B,YAA2B,EAC3B,OAA4C;IAE5C,IAAI,IAAI,GAA4B,EAAE,CAAC;IACvC,IAAI,CAAC;QACH,IAAI,YAAY,EAAE,IAAI,EAAE;YAAE,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAA4B,CAAC;IACvF,CAAC;IAAC,MAAM,CAAC;QACP,4EAA4E;QAC5E,6EAA6E;QAC7E,mEAAmE;QACnE,IAAI,GAAG,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,UAAU,GACd,OAAO,IAAI,CAAC,UAAU,KAAK,QAAQ,IAAI,IAAI,CAAC,UAAU,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACrG,8EAA8E;IAC9E,2EAA2E;IAC3E,MAAM,UAAU,GACd,CAAC,UAAU,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC;IACtF,MAAM,MAAM,GAA4B,UAAU;QAChD,CAAC,CAAC,IAAI;QACN,CAAC,CAAC,CAAE,IAAI,CAAC,UAAsC,IAAI,EAAE,CAAC,CAAC;IACzD,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACnD,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,CAAC,SAAS,KAAK,OAAO;gBACxB,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,IAAI,EAAE,EAAE;gBACvE,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC;IAChC,CAAC;IACD,MAAM,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC;IACrE,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC;AAChD,CAAC;AAcD;8EAC8E;AAC9E,MAAM,oBAAoB,GAAG,oBAAoB,CAAC;AAElD;;;GAGG;AACH,MAAM,OAAO,kBAAkB;IACpB,EAAE,GAAG,aAAsB,CAAC;IAC5B,YAAY,GAAG,wBAAwB,CAAC;IACzC,IAAI,CAAyB;IAC7B,KAAK,CAAqB;IAC1B,GAAG,CAA4B,CAAC,+BAA+B;IACvE,oEAAoE;IAC5D,KAAK,GAAoB,IAAI,CAAC;IAC9B,WAAW,GAAG,KAAK,CAAC;IACpB,QAAQ,GAAG,KAAK,CAAC;IACzB;+EAC2E;IACnE,YAAY,GAAG,KAAK,CAAC;IACrB,mBAAmB,GAAG,KAAK,CAAC;IAC5B,gBAAgB,GAAG,KAAK,CAAC;IAEjC,YAAY,OAA+B,EAAE;QAC3C,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;IAC1B,CAAC;IAEO,UAAU;QAChB,IAAI,IAAI,CAAC,GAAG,KAAK,SAAS;YAAE,IAAI,CAAC,GAAG,GAAG,aAAa,EAAE,CAAC;QACvD,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CACb,gFAAgF;gBAC9E,iFAAiF;gBACjF,oFAAoF;gBACpF,uEAAuE;gBACvE,iDAAiD,CACpD,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,CAAC,GAAG,CAAC;IAClB,CAAC;IAED;8EAC0E;IAC1E,KAAK,CAAC,OAAO;QACX,IAAI,IAAI,CAAC,QAAQ;YAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;QACrE,IAAI,CAAC,UAAU,EAAE,CAAC;IACpB,CAAC;IAED;;;wCAGoC;IAC5B,eAAe,CAAC,GAAW;QACjC,IAAI,IAAI,CAAC,gBAAgB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM;YAC7F,OAAO;QACT,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QACjC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,iBAAiB,CAAC,CAAC;QAC1C,IAAI,CAAC;YACH,IAAI,QAAQ,GAAkB,IAAI,CAAC;YACnC,IAAI,CAAC;gBACH,QAAQ,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YACxC,CAAC;YAAC,MAAM,CAAC;gBACP,QAAQ,GAAG,IAAI,CAAC;YAClB,CAAC;YACD,IAAI,QAAQ,EAAE,CAAC;gBACb,IAAI,CAAC;oBACH,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;gBACvB,CAAC;gBAAC,MAAM,CAAC;oBACP,MAAM,CAAC,IAAI,CACT,yBAAyB,IAAI,qHAAqH,CACnJ,CAAC;oBACF,OAAO;gBACT,CAAC;YACH,CAAC;YACD,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACpC,aAAa,CAAC,IAAI,EAAE,iBAAiB,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC,CAAC;YAC/E,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;YAC7B,MAAM,CAAC,IAAI,CAAC,+DAA+D,IAAI,EAAE,CAAC,CAAC;QACrF,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,IAAI,CAAC,yCAAyC,IAAI,KAAK,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC9E,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,CAAC,GAAG,CAAC,IAAyB;QAClC,6EAA6E;QAC7E,2EAA2E;QAC3E,mDAAmD;QACnD,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;YAAE,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACxE,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QACrB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;QACvD,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;QAE1B,MAAM,QAAQ,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC;QACnD,IAAI,CAAC,YAAY,GAAG,QAAQ,CAAC;QAC7B,IAAI,CAAC,mBAAmB,GAAG,CAAC,QAAQ,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC;QAEjE,MAAM;YACJ,IAAI,EAAE,SAAS;YACf,SAAS,EAAE,oBAAoB;YAC/B,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC7C,CAAC;QAEF,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACtC,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;IAED;;;sEAGkE;IAC1D,KAAK,CAAC,CAAC,OAAO,CACpB,IAAiB,EACjB,GAAW,EACX,UAAuB;QAEvB,IAAI,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACrB,IAAI,IAAI,CAAC,mBAAmB,IAAI,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;YACvD,IAAI;gBACF,aAAa,IAAI,CAAC,IAAI,CAAC,YAAY,iBAAiB;oBACpD,wCAAwC,IAAI,CAAC,IAAI,EAAE,CAAC;YACtD,IAAI,CAAC,mBAAmB,GAAG,KAAK,CAAC;QACnC,CAAC;QACD,2EAA2E;QAC3E,yDAAyD;QAEzD,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;QAC9B,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,qCAAqC,EAAE,IAAI,EAAE,IAAI,KAAK,CAAC;QACnF,MAAM,IAAI,GAAG;YACX,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACpC,IAAI;YACJ,IAAI;YACJ,iBAAiB;YACjB,OAAO;YACP,mEAAmE;YACnE,wEAAwE;YACxE,gEAAgE;YAChE,gCAAgC;YAChC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;SAC/C,CAAC;QAEF,wEAAwE;QACxE,uEAAuE;QACvE,wEAAwE;QACxE,6EAA6E;QAC7E,0EAA0E;QAC1E,+BAA+B;QAC/B,MAAM,KAAK,GAAiB,EAAE,CAAC;QAC/B,IAAI,IAAI,GAAwB,IAAI,CAAC;QACrC,IAAI,IAAI,GAAG,KAAK,CAAC;QACjB,MAAM,IAAI,GAAG,CAAC,EAAc,EAAE,EAAE;YAC9B,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACf,IAAI,EAAE,EAAE,CAAC;YACT,IAAI,GAAG,IAAI,CAAC;QACd,CAAC,CAAC;QACF,MAAM,MAAM,GAAG,GAAG,EAAE;YAClB,IAAI,GAAG,IAAI,CAAC;YACZ,IAAI,EAAE,EAAE,CAAC;YACT,IAAI,GAAG,IAAI,CAAC;QACd,CAAC,CAAC;QAEF,IAAI,GAAG,GAAG,EAAE,CAAC;QACb,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,IAAI,UAAU,GAAG,KAAK,CAAC;QAEvB,IAAI,KAAe,CAAC;QACpB,IAAI,CAAC;YACH,KAAK,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE;gBACvB,GAAG;gBACH,GAAG,EAAE,OAAO,CAAC,GAAG;gBAChB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;gBACjC,WAAW,EAAE,IAAI;gBACjB,QAAQ,EAAE,OAAO,CAAC,QAAQ,KAAK,OAAO;aACvC,CAAa,CAAC;QACjB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,wBAAwB,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACvE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;YACtD,OAAO;QACT,CAAC;QACD,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QAEnB,0EAA0E;QAC1E,4EAA4E;QAC5E,4EAA4E;QAC5E,4EAA4E;QAC5E,0EAA0E;QAC1E,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE;YACjC,IAAI,CAAC;gBACH,UAAU,EAAE,EAAE,CAAC;YACjB,CAAC;YAAC,MAAM,CAAC;gBACP,iCAAiC;YACnC,CAAC;QACH,CAAC,EAAE,MAAM,CAAC,CAAC;QACX,SAAS,CAAC,KAAK,EAAE,EAAE,CAAC;QAEpB,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QACjC,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QACjC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;YACxC,IAAI,CAAC;gBACH,UAAU,EAAE,EAAE,CAAC;YACjB,CAAC;YAAC,MAAM,CAAC;gBACP,4CAA4C;YAC9C,CAAC;YACD,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;YAC/B,IAAI,CAAC,KAAK;gBAAE,OAAO;YACnB,GAAG,IAAI,KAAK,CAAC;YACb,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,UAAU,GAAG,IAAI,CAAC;gBAClB,IAAI,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;YAC3C,CAAC;YACD,IAAI,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACjD,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;YACxC,IAAI,CAAC;gBACH,UAAU,EAAE,EAAE,CAAC;YACjB,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;YACX,CAAC;YACD,MAAM,IAAI,KAAK,CAAC;QAClB,CAAC,CAAC,CAAC;QAEH,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,MAAM,MAAM,GAAG,CAAC,IAAmB,EAAE,QAAgB,EAAE,EAAE;YACvD,IAAI,OAAO;gBAAE,OAAO;YACpB,OAAO,GAAG,IAAI,CAAC;YACf,aAAa,CAAC,SAAS,CAAC,CAAC;YACzB,IAAI,IAAI,CAAC,KAAK,KAAK,KAAK;gBAAE,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;YAC5C,IAAI,UAAU;gBAAE,IAAI,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC;YAC7C,MAAM,SAAS,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;YAC7B,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;gBACrB,IAAI,SAAS;oBAAE,IAAI,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;gBAC5D,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC;YAC5D,CAAC;iBAAM,IAAI,QAAQ,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;gBAClC,MAAM,UAAU,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;gBACtF,MAAM,OAAO,GAAG,8CAA8C,CAAC,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC,CAAC;gBAC5F,MAAM,OAAO,GAAG,QAAQ;oBACtB,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;wBAChC,CAAC,CAAC,wIAAwI;wBAC1I,CAAC,CAAC,wBAAwB,QAAQ,CAAC,OAAO,EAAE;oBAC9C,CAAC,CAAC,OAAO;wBACP,CAAC,CAAC,+HAA+H,UAAU,CAAC,CAAC,CAAC,UAAU,UAAU,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;wBAC5K,CAAC,CAAC,wBAAwB,IAAI,IAAI,UAAU,CAAC,CAAC,CAAC,IAAI,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;gBAC3E,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;gBACjC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;YACxD,CAAC;iBAAM,CAAC;gBACN,IAAI,SAAS;oBAAE,IAAI,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;gBAC5D,6DAA6D;gBAC7D,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;gBACzB,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC,CAAC;YAC1D,CAAC;YACD,wEAAwE;YACxE,yEAAyE;YACzE,gDAAgD;YAChD,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;YACzB,MAAM,EAAE,CAAC;QACX,CAAC,CAAC;QACF,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC;QAC9C,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;QAEzC,wEAAwE;QACxE,2EAA2E;QAC3E,2EAA2E;QAC3E,4EAA4E;QAC5E,wDAAwD;QACxD,IAAI,IAAI,CAAC,WAAW;YAAE,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAEjD,mDAAmD;QACnD,OAAO,IAAI,EAAE,CAAC;YACZ,OAAO,KAAK,CAAC,MAAM;gBAAE,MAAM,KAAK,CAAC,KAAK,EAAG,CAAC;YAC1C,IAAI,IAAI;gBAAE,MAAM;YAChB,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;gBAClC,IAAI,GAAG,OAAO,CAAC;YACjB,CAAC,CAAC,CAAC;QACL,CAAC;QACD,OAAO,KAAK,CAAC,MAAM;YAAE,MAAM,KAAK,CAAC,KAAK,EAAG,CAAC;IAC5C,CAAC;IAED;6EACyE;IACzE,KAAK,CAAC,SAAS;QACb,wEAAwE;QACxE,4EAA4E;QAC5E,4EAA4E;QAC5E,2EAA2E;QAC3E,qEAAqE;QACrE,6EAA6E;QAC7E,sEAAsE;QACtE,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QACxB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACzB,IAAI,CAAC,KAAK;YAAE,OAAO,CAAC,qDAAqD;QACzE,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAED;kFAC8E;IAC9E,KAAK,CAAC,QAAQ,CAAC,KAAa;QAC1B,IAAI,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC;YAAE,OAAO;QACnC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,UAAU;QACd,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;QAC9B,OAAO,MAAM,IAAI,OAAO,CAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC1D,IAAI,GAAG,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,GAAG,EAAE,CAAC;YACb,IAAI,KAAe,CAAC;YACpB,IAAI,CAAC;gBACH,KAAK,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE;oBAC7B,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE;oBACnC,GAAG,EAAE,OAAO,CAAC,GAAG;oBAChB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;oBACjC,WAAW,EAAE,IAAI;iBAClB,CAAa,CAAC;YACjB,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,MAAM,CAAC,IAAI,KAAK,CAAC,iCAAiC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;gBAC/D,OAAO;YACT,CAAC;YACD,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;gBAC5B,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBAC3B,MAAM,CAAC,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC,CAAC;YACzD,CAAC,EAAE,MAAM,CAAC,CAAC;YACX,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC;YAChB,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;YACjC,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;YACjC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;YACnD,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;YACnD,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE;gBACtB,YAAY,CAAC,KAAK,CAAC,CAAC;gBACpB,MAAM,CAAC,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;YAClE,CAAC,CAAC,CAAC;YACH,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;gBACxB,YAAY,CAAC,KAAK,CAAC,CAAC;gBACpB,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;oBACf,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC;gBAC/B,CAAC;qBAAM,CAAC;oBACN,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;oBAC7E,MAAM,CACJ,IAAI,KAAK,CACP,mCAAmC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI;wBACpE,+EAA+E,CAClF,CACF,CAAC;gBACJ,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED,mFAAmF;IACnF,KAAK,CAAC,KAAK;QACT,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACzB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,IAAI,KAAK,EAAE,CAAC;YACV,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;YACxB,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC;CACF"}
|