bluera-knowledge 0.16.4 → 0.16.5
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/dist/mcp/bootstrap.js +5 -123
- package/dist/mcp/bootstrap.js.map +1 -1
- package/package.json +1 -1
package/dist/mcp/bootstrap.js
CHANGED
|
@@ -2,16 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
// src/mcp/bootstrap.ts
|
|
4
4
|
import { execSync } from "child_process";
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
createWriteStream,
|
|
8
|
-
existsSync,
|
|
9
|
-
mkdirSync,
|
|
10
|
-
readFileSync,
|
|
11
|
-
unlinkSync
|
|
12
|
-
} from "fs";
|
|
13
|
-
import { get } from "https";
|
|
14
|
-
import { arch, homedir, platform } from "os";
|
|
5
|
+
import { appendFileSync, existsSync, mkdirSync, readFileSync } from "fs";
|
|
6
|
+
import { homedir } from "os";
|
|
15
7
|
import { dirname, join } from "path";
|
|
16
8
|
import { fileURLToPath } from "url";
|
|
17
9
|
var logDir = join(homedir(), ".bluera", "bluera-knowledge", "logs");
|
|
@@ -45,113 +37,6 @@ var getVersion = () => {
|
|
|
45
37
|
return "unknown";
|
|
46
38
|
}
|
|
47
39
|
};
|
|
48
|
-
var VERSION = getVersion();
|
|
49
|
-
var MANIFEST_URL = `https://github.com/blueraai/bluera-knowledge/releases/download/${VERSION}/manifest.json`;
|
|
50
|
-
function fetchJSON(url) {
|
|
51
|
-
return new Promise((resolve, reject) => {
|
|
52
|
-
const request = (targetUrl, redirectCount = 0) => {
|
|
53
|
-
if (redirectCount > 5) {
|
|
54
|
-
reject(new Error("Too many redirects"));
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
get(targetUrl, { headers: { "User-Agent": "bluera-knowledge" } }, (res) => {
|
|
58
|
-
const location = res.headers.location;
|
|
59
|
-
if ((res.statusCode === 302 || res.statusCode === 301) && typeof location === "string" && location.length > 0) {
|
|
60
|
-
request(location, redirectCount + 1);
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
const statusCode = res.statusCode ?? 0;
|
|
64
|
-
if (statusCode !== 200) {
|
|
65
|
-
reject(new Error(`HTTP ${String(statusCode)}`));
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
let data = "";
|
|
69
|
-
res.on("data", (chunk) => data += chunk.toString());
|
|
70
|
-
res.on("end", () => {
|
|
71
|
-
try {
|
|
72
|
-
resolve(JSON.parse(data));
|
|
73
|
-
} catch (e) {
|
|
74
|
-
reject(e instanceof Error ? e : new Error(String(e)));
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
}).on("error", reject);
|
|
78
|
-
};
|
|
79
|
-
request(url);
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
function downloadFile(url, destPath) {
|
|
83
|
-
return new Promise((resolve, reject) => {
|
|
84
|
-
const request = (targetUrl, redirectCount = 0) => {
|
|
85
|
-
if (redirectCount > 10) {
|
|
86
|
-
reject(new Error("Too many redirects"));
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
get(targetUrl, { headers: { "User-Agent": "bluera-knowledge" } }, (res) => {
|
|
90
|
-
const location = res.headers.location;
|
|
91
|
-
if ((res.statusCode === 302 || res.statusCode === 301) && typeof location === "string" && location.length > 0) {
|
|
92
|
-
request(location, redirectCount + 1);
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
const statusCode = res.statusCode ?? 0;
|
|
96
|
-
if (statusCode !== 200) {
|
|
97
|
-
reject(new Error(`HTTP ${String(statusCode)}`));
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
const file = createWriteStream(destPath);
|
|
101
|
-
res.pipe(file);
|
|
102
|
-
file.on("finish", () => {
|
|
103
|
-
file.close();
|
|
104
|
-
resolve();
|
|
105
|
-
});
|
|
106
|
-
file.on("error", (err) => {
|
|
107
|
-
file.close();
|
|
108
|
-
reject(err);
|
|
109
|
-
});
|
|
110
|
-
}).on("error", reject);
|
|
111
|
-
};
|
|
112
|
-
request(url);
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
function isManifest(value) {
|
|
116
|
-
return typeof value === "object" && value !== null && "version" in value && "platforms" in value && typeof value.platforms === "object";
|
|
117
|
-
}
|
|
118
|
-
async function downloadPrebuilt() {
|
|
119
|
-
const plat = platform();
|
|
120
|
-
const ar = arch();
|
|
121
|
-
const platformKey = `${plat}-${ar}`;
|
|
122
|
-
try {
|
|
123
|
-
log("info", "Checking for prebuilt binary", { platformKey, version: VERSION });
|
|
124
|
-
const manifestData = await fetchJSON(MANIFEST_URL);
|
|
125
|
-
if (!isManifest(manifestData)) {
|
|
126
|
-
log("info", "Invalid manifest format");
|
|
127
|
-
return false;
|
|
128
|
-
}
|
|
129
|
-
const platformInfo = manifestData.platforms[platformKey];
|
|
130
|
-
if (platformInfo === void 0) {
|
|
131
|
-
log("info", "No prebuilt binary available for platform", { platformKey });
|
|
132
|
-
return false;
|
|
133
|
-
}
|
|
134
|
-
log("info", "Downloading prebuilt binary", { url: platformInfo.url });
|
|
135
|
-
const tmpDir = join(homedir(), ".bluera", "tmp");
|
|
136
|
-
mkdirSync(tmpDir, { recursive: true });
|
|
137
|
-
const tarPath = join(tmpDir, `bluera-knowledge-${platformKey}.tar.gz`);
|
|
138
|
-
await downloadFile(platformInfo.url, tarPath);
|
|
139
|
-
log("info", "Download complete, extracting", { tarPath, destDir: pluginRoot });
|
|
140
|
-
execSync(`tar -xzf "${tarPath}" -C "${pluginRoot}"`, { stdio: "pipe" });
|
|
141
|
-
try {
|
|
142
|
-
unlinkSync(tarPath);
|
|
143
|
-
} catch {
|
|
144
|
-
}
|
|
145
|
-
log("info", "Prebuilt binary installed successfully");
|
|
146
|
-
return true;
|
|
147
|
-
} catch (err) {
|
|
148
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
149
|
-
log("debug", "Prebuilt download failed, will use package manager", {
|
|
150
|
-
error: message
|
|
151
|
-
});
|
|
152
|
-
return false;
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
40
|
function installWithPackageManager() {
|
|
156
41
|
const hasBun = (() => {
|
|
157
42
|
try {
|
|
@@ -166,19 +51,16 @@ function installWithPackageManager() {
|
|
|
166
51
|
execSync(cmd, { cwd: pluginRoot, stdio: "inherit" });
|
|
167
52
|
log("info", "Dependencies installed via package manager");
|
|
168
53
|
}
|
|
169
|
-
|
|
54
|
+
function ensureDependencies() {
|
|
170
55
|
if (existsSync(join(pluginRoot, "node_modules"))) {
|
|
171
56
|
log("info", "Dependencies already installed");
|
|
172
57
|
return;
|
|
173
58
|
}
|
|
174
|
-
const prebuiltSuccess = await downloadPrebuilt();
|
|
175
|
-
if (prebuiltSuccess) {
|
|
176
|
-
return;
|
|
177
|
-
}
|
|
178
59
|
installWithPackageManager();
|
|
179
60
|
}
|
|
61
|
+
var VERSION = getVersion();
|
|
180
62
|
log("info", "Bootstrap starting", { pluginRoot, version: VERSION });
|
|
181
|
-
|
|
63
|
+
ensureDependencies();
|
|
182
64
|
log("info", "Loading server module");
|
|
183
65
|
var { runMCPServer } = await import("./server.js");
|
|
184
66
|
var projectRoot = process.env["PROJECT_ROOT"];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/mcp/bootstrap.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * MCP Server Bootstrap - installs dependencies before starting server.\n *\n * Uses only Node.js built-ins (no external dependencies required).\n * Self-locates plugin root via import.meta.url (doesn't rely on CLAUDE_PLUGIN_ROOT).\n *\n * Dependency installation strategy:\n * 1. Fast path: node_modules already exists → skip\n * 2. Try prebuilt: Download platform-specific tarball from GitHub release\n * 3. Package manager: Run bun install or npm ci if prebuilt unavailable\n *\n * IMPORTANT: MCP servers must NOT log to stderr - Claude Code treats stderr output\n * as an error and may mark the MCP server as failed. All logging goes to file.\n */\nimport { execSync } from 'node:child_process';\nimport {\n appendFileSync,\n createWriteStream,\n existsSync,\n mkdirSync,\n readFileSync,\n unlinkSync,\n} from 'node:fs';\nimport { get } from 'node:https';\nimport { arch, homedir, platform } from 'node:os';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\n// Logging helper - writes to file since MCP servers must NOT use stderr\n// (Claude Code treats stderr as error and may fail the server)\n// JSON format matches pino output for consistency\nconst logDir = join(homedir(), '.bluera', 'bluera-knowledge', 'logs');\nconst logFile = join(logDir, 'app.log');\n\nconst log = (\n level: 'info' | 'error' | 'debug',\n msg: string,\n data?: Record<string, unknown>\n): void => {\n try {\n mkdirSync(logDir, { recursive: true });\n const entry = {\n time: new Date().toISOString(),\n level,\n module: 'bootstrap',\n msg,\n ...data,\n };\n appendFileSync(logFile, `${JSON.stringify(entry)}\\n`);\n } catch {\n // Silently fail - we cannot use stderr for MCP servers\n }\n};\n\n// Self-locate plugin root from this file's path\n// dist/mcp/bootstrap.js -> plugin root (two directories up)\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\nconst pluginRoot = join(__dirname, '..', '..');\n\n// Get version from package.json\nconst getVersion = (): string => {\n try {\n const pkg: unknown = JSON.parse(readFileSync(join(pluginRoot, 'package.json'), 'utf-8'));\n if (\n typeof pkg === 'object' &&\n pkg !== null &&\n 'version' in pkg &&\n typeof pkg.version === 'string'\n ) {\n return `v${pkg.version}`;\n }\n return 'unknown';\n } catch {\n return 'unknown';\n }\n};\n\nconst VERSION = getVersion();\nconst MANIFEST_URL = `https://github.com/blueraai/bluera-knowledge/releases/download/${VERSION}/manifest.json`;\n\n/**\n * Fetch JSON from URL with redirect handling.\n * Uses only Node.js built-ins.\n */\nfunction fetchJSON(url: string): Promise<unknown> {\n return new Promise((resolve, reject) => {\n const request = (targetUrl: string, redirectCount = 0): void => {\n if (redirectCount > 5) {\n reject(new Error('Too many redirects'));\n return;\n }\n\n get(targetUrl, { headers: { 'User-Agent': 'bluera-knowledge' } }, (res) => {\n // Follow redirects\n const location = res.headers.location;\n if (\n (res.statusCode === 302 || res.statusCode === 301) &&\n typeof location === 'string' &&\n location.length > 0\n ) {\n request(location, redirectCount + 1);\n return;\n }\n const statusCode = res.statusCode ?? 0;\n if (statusCode !== 200) {\n reject(new Error(`HTTP ${String(statusCode)}`));\n return;\n }\n let data = '';\n res.on('data', (chunk: Buffer) => (data += chunk.toString()));\n res.on('end', () => {\n try {\n resolve(JSON.parse(data));\n } catch (e) {\n reject(e instanceof Error ? e : new Error(String(e)));\n }\n });\n }).on('error', reject);\n };\n request(url);\n });\n}\n\n/**\n * Download file from URL to destination path.\n * Uses only Node.js built-ins.\n */\nfunction downloadFile(url: string, destPath: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const request = (targetUrl: string, redirectCount = 0): void => {\n if (redirectCount > 10) {\n reject(new Error('Too many redirects'));\n return;\n }\n\n get(targetUrl, { headers: { 'User-Agent': 'bluera-knowledge' } }, (res) => {\n const location = res.headers.location;\n if (\n (res.statusCode === 302 || res.statusCode === 301) &&\n typeof location === 'string' &&\n location.length > 0\n ) {\n request(location, redirectCount + 1);\n return;\n }\n const statusCode = res.statusCode ?? 0;\n if (statusCode !== 200) {\n reject(new Error(`HTTP ${String(statusCode)}`));\n return;\n }\n const file = createWriteStream(destPath);\n res.pipe(file);\n file.on('finish', () => {\n file.close();\n resolve();\n });\n file.on('error', (err) => {\n file.close();\n reject(err);\n });\n }).on('error', reject);\n };\n request(url);\n });\n}\n\ninterface PlatformInfo {\n url: string;\n sha256: string;\n}\n\ninterface Manifest {\n version: string;\n platforms: Record<string, PlatformInfo>;\n}\n\nfunction isManifest(value: unknown): value is Manifest {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'version' in value &&\n 'platforms' in value &&\n typeof value.platforms === 'object'\n );\n}\n\n/**\n * Try to download and extract prebuilt binary for current platform.\n * Returns true if successful, false if prebuilt is not available.\n */\nasync function downloadPrebuilt(): Promise<boolean> {\n const plat = platform(); // 'darwin', 'linux', 'win32'\n const ar = arch(); // 'arm64', 'x64'\n const platformKey = `${plat}-${ar}`;\n\n try {\n log('info', 'Checking for prebuilt binary', { platformKey, version: VERSION });\n\n const manifestData = await fetchJSON(MANIFEST_URL);\n if (!isManifest(manifestData)) {\n log('info', 'Invalid manifest format');\n return false;\n }\n\n const platformInfo = manifestData.platforms[platformKey];\n if (platformInfo === undefined) {\n log('info', 'No prebuilt binary available for platform', { platformKey });\n return false;\n }\n\n log('info', 'Downloading prebuilt binary', { url: platformInfo.url });\n const tmpDir = join(homedir(), '.bluera', 'tmp');\n mkdirSync(tmpDir, { recursive: true });\n const tarPath = join(tmpDir, `bluera-knowledge-${platformKey}.tar.gz`);\n\n await downloadFile(platformInfo.url, tarPath);\n log('info', 'Download complete, extracting', { tarPath, destDir: pluginRoot });\n\n // Use system tar - handles all formats (PAX, GNU, USTAR) correctly\n execSync(`tar -xzf \"${tarPath}\" -C \"${pluginRoot}\"`, { stdio: 'pipe' });\n\n // Cleanup temp file\n try {\n unlinkSync(tarPath);\n } catch {\n // Ignore cleanup errors\n }\n\n log('info', 'Prebuilt binary installed successfully');\n return true;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n log('debug', 'Prebuilt download failed, will use package manager', {\n error: message,\n });\n return false;\n }\n}\n\n/**\n * Install dependencies using bun or npm.\n */\nfunction installWithPackageManager(): void {\n const hasBun = ((): boolean => {\n try {\n execSync('which bun', { stdio: 'ignore' });\n return true;\n } catch {\n return false;\n }\n })();\n\n const cmd = hasBun ? 'bun install --frozen-lockfile' : 'npm ci --silent';\n log('info', 'Installing dependencies with package manager', { hasBun, cmd });\n execSync(cmd, { cwd: pluginRoot, stdio: 'inherit' });\n log('info', 'Dependencies installed via package manager');\n}\n\n/**\n * Ensure dependencies are available.\n * Tries prebuilt first, falls back to package manager.\n */\nasync function ensureDependencies(): Promise<void> {\n // Fast path: already installed\n if (existsSync(join(pluginRoot, 'node_modules'))) {\n log('info', 'Dependencies already installed');\n return;\n }\n\n // Try prebuilt binary first (faster, no npm install needed)\n const prebuiltSuccess = await downloadPrebuilt();\n if (prebuiltSuccess) {\n return;\n }\n\n // Prebuilt not available, use package manager instead\n installWithPackageManager();\n}\n\n// Main entry point\nlog('info', 'Bootstrap starting', { pluginRoot, version: VERSION });\n\nawait ensureDependencies();\n\n// Now that dependencies are installed, import and run the server\n// Dynamic import required because @modelcontextprotocol/sdk wouldn't be available before install\nlog('info', 'Loading server module');\nconst { runMCPServer } = await import('./server.js');\n\nconst projectRoot = process.env['PROJECT_ROOT'];\nif (projectRoot === undefined) {\n throw new Error('PROJECT_ROOT environment variable is required');\n}\n\nlog('info', 'Starting MCP server', {\n projectRoot,\n dataDir: process.env['DATA_DIR'],\n});\n\nawait runMCPServer({\n dataDir: process.env['DATA_DIR'],\n config: process.env['CONFIG_PATH'],\n projectRoot,\n});\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/mcp/bootstrap.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * MCP Server Bootstrap - installs dependencies before starting server.\n *\n * Uses only Node.js built-ins (no external dependencies required).\n * Self-locates plugin root via import.meta.url (doesn't rely on CLAUDE_PLUGIN_ROOT).\n *\n * Dependency installation strategy:\n * 1. Fast path: node_modules already exists → skip\n * 2. Package manager: Run bun install or npm ci\n *\n * IMPORTANT: MCP servers must NOT log to stderr - Claude Code treats stderr output\n * as an error and may mark the MCP server as failed. All logging goes to file.\n */\nimport { execSync } from 'node:child_process';\nimport { appendFileSync, existsSync, mkdirSync, readFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\n// Logging helper - writes to file since MCP servers must NOT use stderr\n// (Claude Code treats stderr as error and may fail the server)\n// JSON format matches pino output for consistency\nconst logDir = join(homedir(), '.bluera', 'bluera-knowledge', 'logs');\nconst logFile = join(logDir, 'app.log');\n\nconst log = (\n level: 'info' | 'error' | 'debug',\n msg: string,\n data?: Record<string, unknown>\n): void => {\n try {\n mkdirSync(logDir, { recursive: true });\n const entry = {\n time: new Date().toISOString(),\n level,\n module: 'bootstrap',\n msg,\n ...data,\n };\n appendFileSync(logFile, `${JSON.stringify(entry)}\\n`);\n } catch {\n // Silently fail - we cannot use stderr for MCP servers\n }\n};\n\n// Self-locate plugin root from this file's path\n// dist/mcp/bootstrap.js -> plugin root (two directories up)\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\nconst pluginRoot = join(__dirname, '..', '..');\n\n// Get version from package.json for logging\nconst getVersion = (): string => {\n try {\n const pkg: unknown = JSON.parse(readFileSync(join(pluginRoot, 'package.json'), 'utf-8'));\n if (\n typeof pkg === 'object' &&\n pkg !== null &&\n 'version' in pkg &&\n typeof pkg.version === 'string'\n ) {\n return `v${pkg.version}`;\n }\n return 'unknown';\n } catch {\n return 'unknown';\n }\n};\n\n/**\n * Install dependencies using bun or npm.\n */\nfunction installWithPackageManager(): void {\n const hasBun = ((): boolean => {\n try {\n execSync('which bun', { stdio: 'ignore' });\n return true;\n } catch {\n return false;\n }\n })();\n\n const cmd = hasBun ? 'bun install --frozen-lockfile' : 'npm ci --silent';\n log('info', 'Installing dependencies with package manager', { hasBun, cmd });\n execSync(cmd, { cwd: pluginRoot, stdio: 'inherit' });\n log('info', 'Dependencies installed via package manager');\n}\n\n/**\n * Ensure dependencies are available.\n */\nfunction ensureDependencies(): void {\n // Fast path: already installed\n if (existsSync(join(pluginRoot, 'node_modules'))) {\n log('info', 'Dependencies already installed');\n return;\n }\n\n // Install via package manager\n installWithPackageManager();\n}\n\n// Main entry point\nconst VERSION = getVersion();\nlog('info', 'Bootstrap starting', { pluginRoot, version: VERSION });\n\nensureDependencies();\n\n// Now that dependencies are installed, import and run the server\n// Dynamic import required because @modelcontextprotocol/sdk wouldn't be available before install\nlog('info', 'Loading server module');\nconst { runMCPServer } = await import('./server.js');\n\nconst projectRoot = process.env['PROJECT_ROOT'];\nif (projectRoot === undefined) {\n throw new Error('PROJECT_ROOT environment variable is required');\n}\n\nlog('info', 'Starting MCP server', {\n projectRoot,\n dataDir: process.env['DATA_DIR'],\n});\n\nawait runMCPServer({\n dataDir: process.env['DATA_DIR'],\n config: process.env['CONFIG_PATH'],\n projectRoot,\n});\n"],"mappings":";;;AAcA,SAAS,gBAAgB;AACzB,SAAS,gBAAgB,YAAY,WAAW,oBAAoB;AACpE,SAAS,eAAe;AACxB,SAAS,SAAS,YAAY;AAC9B,SAAS,qBAAqB;AAK9B,IAAM,SAAS,KAAK,QAAQ,GAAG,WAAW,oBAAoB,MAAM;AACpE,IAAM,UAAU,KAAK,QAAQ,SAAS;AAEtC,IAAM,MAAM,CACV,OACA,KACA,SACS;AACT,MAAI;AACF,cAAU,QAAQ,EAAE,WAAW,KAAK,CAAC;AACrC,UAAM,QAAQ;AAAA,MACZ,OAAM,oBAAI,KAAK,GAAE,YAAY;AAAA,MAC7B;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,MACA,GAAG;AAAA,IACL;AACA,mBAAe,SAAS,GAAG,KAAK,UAAU,KAAK,CAAC;AAAA,CAAI;AAAA,EACtD,QAAQ;AAAA,EAER;AACF;AAIA,IAAM,aAAa,cAAc,YAAY,GAAG;AAChD,IAAM,YAAY,QAAQ,UAAU;AACpC,IAAM,aAAa,KAAK,WAAW,MAAM,IAAI;AAG7C,IAAM,aAAa,MAAc;AAC/B,MAAI;AACF,UAAM,MAAe,KAAK,MAAM,aAAa,KAAK,YAAY,cAAc,GAAG,OAAO,CAAC;AACvF,QACE,OAAO,QAAQ,YACf,QAAQ,QACR,aAAa,OACb,OAAO,IAAI,YAAY,UACvB;AACA,aAAO,IAAI,IAAI,OAAO;AAAA,IACxB;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAKA,SAAS,4BAAkC;AACzC,QAAM,UAAU,MAAe;AAC7B,QAAI;AACF,eAAS,aAAa,EAAE,OAAO,SAAS,CAAC;AACzC,aAAO;AAAA,IACT,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF,GAAG;AAEH,QAAM,MAAM,SAAS,kCAAkC;AACvD,MAAI,QAAQ,gDAAgD,EAAE,QAAQ,IAAI,CAAC;AAC3E,WAAS,KAAK,EAAE,KAAK,YAAY,OAAO,UAAU,CAAC;AACnD,MAAI,QAAQ,4CAA4C;AAC1D;AAKA,SAAS,qBAA2B;AAElC,MAAI,WAAW,KAAK,YAAY,cAAc,CAAC,GAAG;AAChD,QAAI,QAAQ,gCAAgC;AAC5C;AAAA,EACF;AAGA,4BAA0B;AAC5B;AAGA,IAAM,UAAU,WAAW;AAC3B,IAAI,QAAQ,sBAAsB,EAAE,YAAY,SAAS,QAAQ,CAAC;AAElE,mBAAmB;AAInB,IAAI,QAAQ,uBAAuB;AACnC,IAAM,EAAE,aAAa,IAAI,MAAM,OAAO,aAAa;AAEnD,IAAM,cAAc,QAAQ,IAAI,cAAc;AAC9C,IAAI,gBAAgB,QAAW;AAC7B,QAAM,IAAI,MAAM,+CAA+C;AACjE;AAEA,IAAI,QAAQ,uBAAuB;AAAA,EACjC;AAAA,EACA,SAAS,QAAQ,IAAI,UAAU;AACjC,CAAC;AAED,MAAM,aAAa;AAAA,EACjB,SAAS,QAAQ,IAAI,UAAU;AAAA,EAC/B,QAAQ,QAAQ,IAAI,aAAa;AAAA,EACjC;AACF,CAAC;","names":[]}
|