@yoooclaw/phone-notifications 1.11.12 → 1.11.13

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/host.ts","../src/auth/credentials.ts","../src/env.ts","../src/recording/transcript-document.ts","../src/recording/whisper-local.ts","../src/recording/asr.ts","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/constants.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/buffer-util.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/limiter.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/permessage-deflate.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/validation.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/receiver.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/sender.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/event-target.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/extension.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/websocket.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/stream.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/subprotocol.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/websocket-server.js","../src/index.ts","../src/logger.ts","../src/version.ts","../src/light/repeat.ts","../src/cli/helpers.ts","../src/light/validators.ts","../src/light-rules/names.ts","../src/light-rules/storage.ts","../src/light-rules/gateway.ts","../src/light-rules/registry.ts","../src/light/protocol.ts","../src/plugin/light-rules-tools.ts","../src/light-rules/inline-evaluator.ts","../src/light/sender.ts","../src/light-rules/evaluation-scheduler.ts","../src/light-rules/pi-invoker.ts","../src/plugin/auto-update.ts","../src/update/channel.ts","../src/update/index.ts","../src/plugin/runtime-state.ts","../src/plugin/shared.ts","../src/update/checker.ts","../src/update/executor.ts","../src/update/restart.ts","../src/plugin/cli.ts","../src/cli/auth.ts","../src/cli/ntf-query.ts","../src/cli/ntf-search.ts","../src/cli/ntf-summary.ts","../src/cli/ntf-stats.ts","../src/cli/ntf-sync.ts","../src/cli/ntf-monitor.ts","../src/monitor/fetch-gen.ts","../src/cli/light-send.ts","../src/cli/light-setup-tools.ts","../src/cli/tunnel-status.ts","../src/tunnel/status.ts","../src/cli/ntf-storage-path.ts","../src/cli/log-search.ts","../src/cli/env.ts","../src/cli/doctor.ts","../src/cli/doctor/check-dangerous-flags.ts","../src/cli/doctor/check-trusted-proxy.ts","../src/cli/doctor/check-state-dir-perms.ts","../src/cli/doctor/check-tool-policy.ts","../src/cli/doctor/check-credentials.ts","../src/cli/doctor/check-tunnel.ts","../src/cli/doctor/check-node-version.ts","../src/cli/doctor/check-plugin-version.ts","../src/cli/doctor/checkers.ts","../src/cli/rec-list.ts","../src/cli/rec-status.ts","../src/cli/rec-storage-path.ts","../src/cli/rec-setup.ts","../src/cli/update.ts","../src/cli/index.ts","../src/plugin/light-control.ts","../src/plugin/lifecycle.ts","../src/notification/app-name-map.ts","../src/notification/storage.ts","../src/notification/feishu-normalize.ts","../src/recording/storage.ts","../src/recording/state-machine.ts","../src/recording/index.ts","../src/recording/downloader.ts","../src/recording/handler.ts","../src/recording/account-oss.ts","../src/tunnel/service.ts","../src/tunnel/relay-client.ts","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/wrapper.mjs","../src/tunnel/proxy.ts","../src/tunnel/utils.ts","../src/tunnel/device-identity.ts","../src/tunnel/http-proxy.ts","../src/tunnel/ws-proxy.ts","../src/plugin/notifications.ts","../src/plugin/recordings.ts","../src/plugin/runtime-mode.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\n\nexport type HostKind = \"openclaw\" | \"qclaw\";\n\ninterface QClawMeta {\n stateDir?: string;\n configPath?: string;\n}\n\nfunction trimToUndefined(value: unknown): string | undefined {\n if (typeof value !== \"string\") {\n return undefined;\n }\n const trimmed = value.trim();\n return trimmed || undefined;\n}\n\nfunction homeDir(): string {\n return process.env.HOME || process.env.USERPROFILE || \"/tmp\";\n}\n\nfunction expandUserPath(value: string | undefined): string | undefined {\n if (!value) {\n return undefined;\n }\n if (value === \"~\") {\n return homeDir();\n }\n if (value.startsWith(\"~/\")) {\n return join(homeDir(), value.slice(2));\n }\n return value;\n}\n\nfunction detectHostKindFromPath(value: string | undefined): HostKind | undefined {\n if (!value) {\n return undefined;\n }\n const normalized = value.replace(/\\\\/g, \"/\").toLowerCase();\n if (\n normalized.endsWith(\"/.qclaw\") ||\n normalized.includes(\"/.qclaw/\") ||\n normalized.endsWith(\"/.qclow\") ||\n normalized.includes(\"/.qclow/\")\n ) {\n return \"qclaw\";\n }\n if (\n normalized.endsWith(\"/.openclaw\") ||\n normalized.includes(\"/.openclaw/\")\n ) {\n return \"openclaw\";\n }\n return undefined;\n}\n\nfunction candidateMetaPaths(): string[] {\n const home = homeDir();\n return [\n join(home, \".qclaw\", \"qclaw.json\"),\n join(home, \".qclow\", \"qclaw.json\"),\n ];\n}\n\nfunction loadQClawMeta(): QClawMeta | undefined {\n for (const metaPath of candidateMetaPaths()) {\n if (!existsSync(metaPath)) {\n continue;\n }\n try {\n const parsed = JSON.parse(readFileSync(metaPath, \"utf-8\")) as QClawMeta;\n return {\n stateDir: expandUserPath(trimToUndefined(parsed?.stateDir)),\n configPath: expandUserPath(trimToUndefined(parsed?.configPath)),\n };\n } catch {\n // ignore invalid metadata and keep trying\n }\n }\n return undefined;\n}\n\nfunction resolveStateDirFromEnv(): string | undefined {\n return expandUserPath(\n trimToUndefined(process.env.OPENCLAW_STATE_DIR) ??\n trimToUndefined(process.env.QCLAW_STATE_DIR) ??\n trimToUndefined(process.env.OPENCLAW_ROOT) ??\n trimToUndefined(process.env.OPENCLAW_HOME) ??\n trimToUndefined(process.env.QCLAW_HOME),\n );\n}\n\nfunction resolveConfigPathFromEnv(): string | undefined {\n return expandUserPath(\n trimToUndefined(process.env.OPENCLAW_CONFIG_PATH) ??\n trimToUndefined(process.env.QCLAW_CONFIG_PATH),\n );\n}\n\nfunction hasOpenClawMarkers(): boolean {\n const baseDir = join(homeDir(), \".openclaw\");\n return [\n join(baseDir, \"openclaw.json\"),\n join(baseDir, \"credentials.json\"),\n join(baseDir, \"extensions\"),\n ].some((candidate) => existsSync(candidate));\n}\n\nexport function detectHostKind(): HostKind {\n if (\n trimToUndefined(process.env.QCLAW_STATE_DIR) ||\n trimToUndefined(process.env.QCLAW_CONFIG_PATH) ||\n trimToUndefined(process.env.QCLAW_HOME)\n ) {\n return \"qclaw\";\n }\n\n const pathHintKind =\n detectHostKindFromPath(resolveStateDirFromEnv()) ??\n detectHostKindFromPath(resolveConfigPathFromEnv());\n if (pathHintKind) {\n return pathHintKind;\n }\n\n if (hasOpenClawMarkers()) {\n return \"openclaw\";\n }\n\n if (loadQClawMeta()) {\n return \"qclaw\";\n }\n\n return \"openclaw\";\n}\n\nexport function resolveStateDir(): string {\n const envDir = resolveStateDirFromEnv();\n if (envDir) {\n return envDir;\n }\n\n if (hasOpenClawMarkers()) {\n return join(homeDir(), \".openclaw\");\n }\n\n const meta = loadQClawMeta();\n if (meta?.stateDir) {\n return meta.stateDir;\n }\n if (meta?.configPath) {\n return dirname(meta.configPath);\n }\n\n return join(homeDir(), \".openclaw\");\n}\n\nexport function resolveConfigPath(stateDir = resolveStateDir()): string {\n const envConfigPath = resolveConfigPathFromEnv();\n if (envConfigPath) {\n return envConfigPath;\n }\n\n const meta = loadQClawMeta();\n if (\n meta?.configPath &&\n (!meta.stateDir || !stateDir || meta.stateDir === stateDir)\n ) {\n return meta.configPath;\n }\n\n return join(stateDir, \"openclaw.json\");\n}\n\nexport function resolveStateFile(filename: string): string {\n return join(resolveStateDir(), filename);\n}\n","import {\n existsSync,\n mkdirSync,\n readFileSync,\n writeFileSync,\n watch,\n} from \"node:fs\";\nimport { dirname, basename } from \"node:path\";\nimport { resolveStateFile } from \"../host.js\";\n\ninterface Credentials {\n /**\n * 推荐:API Key 明文(例如 ock_xxx)\n */\n apiKey?: string;\n /**\n * 兼容旧字段:历史上这里存的是 token;现在等价于 apiKey\n */\n token?: string;\n /**\n * 当前环境(development / production),由 ntf env switch 写入\n */\n env?: string;\n}\n\nexport function credentialsPath(): string {\n return resolveStateFile(\"credentials.json\");\n}\n\nexport function readCredentials(): Credentials {\n const path = credentialsPath();\n if (!existsSync(path)) return {};\n try {\n return JSON.parse(readFileSync(path, \"utf-8\"));\n } catch {\n return {};\n }\n}\n\nexport function writeCredentials(creds: Credentials): void {\n const path = credentialsPath();\n mkdirSync(dirname(path), { recursive: true, mode: 0o700 });\n writeFileSync(path, JSON.stringify(creds, null, 2), {\n encoding: \"utf-8\",\n mode: 0o600,\n });\n}\n\nexport function loadApiKey(): string | undefined {\n const creds = readCredentials();\n return creds.apiKey ?? creds.token;\n}\n\nexport function requireApiKey(): string {\n const apiKey = loadApiKey();\n if (!apiKey) {\n throw new Error(\n `API Key 未设置,请先写入 ${credentialsPath()},或通过宿主 CLI 执行 ntf auth set-api-key <apiKey>`,\n );\n }\n return apiKey;\n}\n\n// ---- Backward-compatible exports (旧代码仍可编译;语义等价于 apiKey) ----\nexport function loadToken(): string | undefined {\n return loadApiKey();\n}\n\nexport function requireToken(): string {\n return requireApiKey();\n}\n\n/** 监听 credentials 文件变化(如 set-token 后)触发 callback;返回取消监听的函数 */\nexport function watchCredentials(onChange: () => void): () => void {\n const path = credentialsPath();\n const dir = dirname(path);\n const filename = basename(path);\n let debounceTimer: ReturnType<typeof setTimeout> | null = null;\n const delayMs = 200;\n\n const listener = (_event: string, changedName: string | null) => {\n if (!changedName || (changedName !== filename && !changedName.endsWith(filename))) return;\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n debounceTimer = null;\n onChange();\n }, delayMs);\n };\n\n let watcher: ReturnType<typeof watch> | null = null;\n try {\n watcher = watch(dir, { persistent: false }, listener);\n } catch {\n // 目录可能不存在\n }\n\n return () => {\n if (debounceTimer) clearTimeout(debounceTimer);\n watcher?.close();\n };\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { readCredentials } from \"./auth/credentials.js\";\nimport { resolveStateFile } from \"./host.js\";\n\nfunction writeDotEnv(key: string, value: string): void {\n const path = resolveStateFile(\".env\");\n mkdirSync(dirname(path), { recursive: true });\n const existing = existsSync(path) ? readFileSync(path, \"utf-8\") : \"\";\n const lines = existing.split(\"\\n\");\n const prefix = `${key}=`;\n const idx = lines.findIndex((l) => l.startsWith(prefix));\n const newLine = `${prefix}${value}`;\n if (idx >= 0) {\n lines[idx] = newLine;\n } else {\n if (existing && !existing.endsWith(\"\\n\")) lines.push(\"\");\n lines.push(newLine);\n }\n writeFileSync(path, lines.join(\"\\n\"), \"utf-8\");\n}\n\nexport type EnvName = \"development\" | \"test\" | \"production\";\n\ninterface EnvUrls {\n lightApiUrl: string;\n appNameMapUrl: string;\n relayTunnelUrl: string;\n modelProxyLongRecordingSubmitTaskUrl: string;\n modelProxyLongRecordingQueryTaskResultBaseUrl: string;\n accountFileDeleteUrl: string;\n}\n\nconst ENV_HOSTS: Record<EnvName, string> = {\n development: \"openclaw-service-dev.yoooclaw.com\",\n test: \"openclaw-service-test.yoooclaw.com\",\n production: \"openclaw-service.yoooclaw.com\",\n};\n\nfunction buildEnvUrls(host: string): EnvUrls {\n const https = `https://${host}`;\n const wss = `wss://${host}`;\n return {\n lightApiUrl: `${https}/api/message/tob/sendMessage`,\n relayTunnelUrl: `${wss}/message/messages/ws/plugin`,\n appNameMapUrl: `${https}/api/application-config/app-package/config-all`,\n modelProxyLongRecordingSubmitTaskUrl: `${https}/api/model-proxy/long-recording/submit-task`,\n modelProxyLongRecordingQueryTaskResultBaseUrl: `${https}/api/model-proxy/long-recording/query-task-result`,\n accountFileDeleteUrl: `${https}/api/account/file/delete`,\n };\n}\n\nconst ENV_CONFIG: Record<EnvName, EnvUrls> = {\n development: buildEnvUrls(ENV_HOSTS.development),\n test: buildEnvUrls(ENV_HOSTS.test),\n production: buildEnvUrls(ENV_HOSTS.production),\n};\n\nconst VALID_ENVS: ReadonlySet<string> = new Set(Object.keys(ENV_CONFIG));\n\nfunction readDotEnv(): Record<string, string> {\n const path = resolveStateFile(\".env\");\n if (!existsSync(path)) return {};\n return Object.fromEntries(\n readFileSync(path, \"utf-8\")\n .split(\"\\n\")\n .flatMap((line) => {\n const eq = line.indexOf(\"=\");\n if (eq < 1) return [];\n return [[line.slice(0, eq).trim(), line.slice(eq + 1).trim()]];\n }),\n );\n}\n\n/** 读取持久化到 .env 的环境名称;仅反映本地配置,不考虑进程环境变量。 */\nexport function readPersistedEnvName(): EnvName | undefined {\n const fromDotEnv = readDotEnv()[\"PHONE_NOTIFICATIONS_ENV\"]?.trim();\n if (fromDotEnv && VALID_ENVS.has(fromDotEnv)) return fromDotEnv as EnvName;\n return undefined;\n}\n\n/** 读取当前环境名称。优先级:PHONE_NOTIFICATIONS_ENV 环境变量 > .env > credentials.json > 默认 production */\nexport function loadEnvName(): EnvName {\n const fromEnvVar = process.env.PHONE_NOTIFICATIONS_ENV?.trim();\n if (fromEnvVar && VALID_ENVS.has(fromEnvVar)) return fromEnvVar as EnvName;\n\n const fromDotEnv = readPersistedEnvName();\n if (fromDotEnv) return fromDotEnv;\n\n const { env } = readCredentials();\n if (env && VALID_ENVS.has(env)) return env as EnvName;\n\n return \"production\";\n}\n\n/** 持久化当前环境到 .env */\nexport function saveEnvName(env: EnvName): void {\n if (!VALID_ENVS.has(env)) {\n throw new Error(\n `无效的环境名称: ${env},可选值: ${[...VALID_ENVS].join(\", \")}`,\n );\n }\n writeDotEnv(\"PHONE_NOTIFICATIONS_ENV\", env);\n}\n\n/** 获取当前环境的 URL 配置 */\nexport function getEnvUrls(env?: EnvName): EnvUrls {\n return ENV_CONFIG[env ?? loadEnvName()];\n}\n\n/** 获取所有可用环境名称 */\nexport function getAvailableEnvs(): EnvName[] {\n return Object.keys(ENV_CONFIG) as EnvName[];\n}\n","export const TRANSCRIPT_DOCUMENT_SCHEMA_VERSION = 1;\n\nexport interface TranscriptDocumentSource {\n provider: string;\n taskId?: string;\n requestId?: string;\n status?: string;\n}\n\nexport interface TranscriptDocumentSegment {\n text: string;\n startMs?: number;\n endMs?: number;\n speakerId?: number;\n}\n\nexport interface TranscriptDocumentContentItem {\n content: string;\n speakerId?: number;\n startTime?: number;\n endTime?: number;\n}\n\nexport interface TranscriptDocumentNormalized {\n title?: string;\n category?: string;\n summary?: string;\n text: string;\n segments: TranscriptDocumentSegment[];\n}\n\nexport interface TranscriptDocument {\n schemaVersion: number;\n recordingId: string;\n generatedAt: string;\n source: TranscriptDocumentSource;\n normalized: TranscriptDocumentNormalized;\n raw?: unknown;\n}\n\nexport function buildTranscriptDataFilename(recordingId: string): string {\n return `${recordingId}.json`;\n}\n\nexport function buildTranscriptDocument(params: {\n recordingId: string;\n generatedAt?: string;\n source: TranscriptDocumentSource;\n title?: string;\n category?: string;\n summary?: string;\n text?: string;\n segments?: TranscriptDocumentSegment[];\n raw?: unknown;\n}): TranscriptDocument {\n const segments = normalizeSegments(params.segments);\n const text = normalizePossiblyEmptyText(params.text) ?? joinSegmentsText(segments) ?? \"\";\n\n return {\n schemaVersion: TRANSCRIPT_DOCUMENT_SCHEMA_VERSION,\n recordingId: params.recordingId,\n generatedAt: params.generatedAt ?? new Date().toISOString(),\n source: {\n provider: params.source.provider,\n taskId: normalizeOptionalText(params.source.taskId),\n requestId: normalizeOptionalText(params.source.requestId),\n status: normalizeOptionalText(params.source.status),\n },\n normalized: {\n title: normalizeOptionalText(params.title),\n category: normalizeOptionalText(params.category),\n summary: normalizePossiblyEmptyText(params.summary),\n text,\n segments,\n },\n raw: params.raw,\n };\n}\n\nexport function parseTranscriptDocument(\n value: string | unknown,\n): TranscriptDocument | undefined {\n const parsed = typeof value === \"string\"\n ? parseJson(value)\n : value;\n\n if (!parsed || typeof parsed !== \"object\") {\n return undefined;\n }\n\n const doc = parsed as Record<string, unknown>;\n const recordingId = normalizeOptionalText(doc.recordingId);\n const generatedAt = normalizeOptionalText(doc.generatedAt);\n const source = normalizeSource(doc.source);\n const normalized = normalizeDocumentBody(doc.normalized);\n\n if (!recordingId || !generatedAt || !source || !normalized) {\n return undefined;\n }\n\n return {\n schemaVersion:\n typeof doc.schemaVersion === \"number\"\n ? doc.schemaVersion\n : TRANSCRIPT_DOCUMENT_SCHEMA_VERSION,\n recordingId,\n generatedAt,\n source,\n normalized,\n raw: doc.raw,\n };\n}\n\nexport function extractTranscriptTextFromDocument(\n doc: TranscriptDocument | undefined,\n): string | undefined {\n if (!doc) return undefined;\n return normalizePossiblyEmptyText(doc.normalized.text)\n ?? joinSegmentsText(doc.normalized.segments);\n}\n\nexport function extractTranscriptSummaryFromDocument(\n doc: TranscriptDocument | undefined,\n): string | undefined {\n if (!doc) return undefined;\n return normalizePossiblyEmptyText(doc.normalized.summary);\n}\n\nexport function extractTranscriptTitleFromDocument(\n doc: TranscriptDocument | undefined,\n): string | undefined {\n if (!doc) return undefined;\n return normalizeOptionalText(doc.normalized.title);\n}\n\nexport function extractSourceTextListFromDocument(\n doc: TranscriptDocument | undefined,\n): TranscriptDocumentContentItem[] | undefined {\n if (!doc) return undefined;\n\n const fromNormalized = doc.normalized.segments\n .map((segment) => ({\n content: segment.text,\n speakerId: segment.speakerId,\n startTime: segment.startMs,\n endTime: segment.endMs,\n }))\n .filter((segment) => normalizeOptionalText(segment.content));\n\n if (fromNormalized.length > 0) {\n return fromNormalized;\n }\n\n const rawList = extractRawSourceTextList(doc.raw);\n if (rawList.length > 0) {\n return rawList;\n }\n\n const normalizedText = normalizeOptionalText(doc.normalized.text);\n return normalizedText\n ? [{ content: normalizedText }]\n : undefined;\n}\n\nfunction parseJson(value: string): unknown {\n try {\n return JSON.parse(value);\n } catch {\n return undefined;\n }\n}\n\nfunction normalizeSource(value: unknown): TranscriptDocumentSource | undefined {\n if (!value || typeof value !== \"object\") {\n return undefined;\n }\n\n const source = value as Record<string, unknown>;\n const provider = normalizeOptionalText(source.provider);\n if (!provider) {\n return undefined;\n }\n\n return {\n provider,\n taskId: normalizeOptionalText(source.taskId),\n requestId: normalizeOptionalText(source.requestId),\n status: normalizeOptionalText(source.status),\n };\n}\n\nfunction normalizeDocumentBody(\n value: unknown,\n): TranscriptDocumentNormalized | undefined {\n if (!value || typeof value !== \"object\") {\n return undefined;\n }\n\n const normalized = value as Record<string, unknown>;\n const segments = normalizeSegments(normalized.segments);\n const text = normalizePossiblyEmptyText(normalized.text) ?? joinSegmentsText(segments);\n if (text === undefined) {\n return undefined;\n }\n\n return {\n title: normalizeOptionalText(normalized.title),\n category: normalizeOptionalText(normalized.category),\n summary: normalizePossiblyEmptyText(normalized.summary),\n text,\n segments,\n };\n}\n\nfunction normalizeSegments(value: unknown): TranscriptDocumentSegment[] {\n if (!Array.isArray(value)) {\n return [];\n }\n\n return value\n .map((item) => normalizeSegment(item))\n .filter((item): item is TranscriptDocumentSegment => !!item);\n}\n\nfunction normalizeSegment(value: unknown): TranscriptDocumentSegment | undefined {\n if (!value || typeof value !== \"object\") {\n return undefined;\n }\n\n const segment = value as Record<string, unknown>;\n const text = normalizeOptionalText(segment.text);\n if (!text) {\n return undefined;\n }\n\n return {\n text,\n startMs: normalizeOptionalNumber(segment.startMs),\n endMs: normalizeOptionalNumber(segment.endMs),\n speakerId: normalizeOptionalInteger(segment.speakerId),\n };\n}\n\nfunction joinSegmentsText(\n segments: TranscriptDocumentSegment[],\n): string | undefined {\n const parts = segments\n .map((segment) => normalizeOptionalText(segment.text))\n .filter((segment): segment is string => !!segment);\n\n if (parts.length === 0) {\n return undefined;\n }\n\n return parts.join(\"\\n\\n\");\n}\n\nfunction extractRawSourceTextList(raw: unknown): TranscriptDocumentContentItem[] {\n if (!raw || typeof raw !== \"object\") {\n return [];\n }\n\n const recordResult = (raw as { recordResult?: unknown }).recordResult;\n if (!recordResult || typeof recordResult !== \"object\") {\n return [];\n }\n\n const sourceTextList = (recordResult as { sourceTextList?: unknown }).sourceTextList;\n if (!Array.isArray(sourceTextList)) {\n return [];\n }\n\n return sourceTextList\n .flatMap((item) => {\n if (!item || typeof item !== \"object\") {\n return [];\n }\n\n const value = item as Record<string, unknown>;\n const content = normalizeOptionalText(value.content);\n if (!content) {\n return [];\n }\n\n return [{\n content,\n speakerId: normalizeOptionalInteger(value.speakerId),\n startTime: normalizeOptionalNumber(value.startTime),\n endTime: normalizeOptionalNumber(value.endTime),\n }];\n });\n}\n\nfunction normalizeOptionalText(value: unknown): string | undefined {\n return typeof value === \"string\" && value.trim()\n ? value.trim()\n : undefined;\n}\n\nfunction normalizePossiblyEmptyText(value: unknown): string | undefined {\n return typeof value === \"string\"\n ? value.trim()\n : undefined;\n}\n\nfunction normalizeOptionalNumber(value: unknown): number | undefined {\n return typeof value === \"number\" && Number.isFinite(value)\n ? value\n : undefined;\n}\n\nfunction normalizeOptionalInteger(value: unknown): number | undefined {\n return Number.isInteger(value)\n ? Number(value)\n : undefined;\n}\n","/**\n * 本地 Whisper 转写模块(arc-long-recording §6.4)\n *\n * 插件内置 Whisper 推理能力:\n * 1. 自动检测运行环境与硬件配置(§6.4.1)\n * 2. 选择最优推理后端(§6.4.2)\n * 3. 根据可用内存自动选择模型规格(§6.4.3)\n * 4. 首次使用时下载模型文件(§6.4.5)\n * 5. 通过 whisper.cpp CLI 执行本地离线转写\n */\n\nimport { execSync, execFileSync, spawnSync, type SpawnSyncReturns } from \"node:child_process\";\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n statSync,\n createWriteStream,\n unlinkSync,\n copyFileSync,\n openSync,\n readSync,\n closeSync,\n} from \"node:fs\";\nimport { join, dirname, basename } from \"node:path\";\nimport { pipeline } from \"node:stream/promises\";\nimport { Readable } from \"node:stream\";\nimport { platform, arch, totalmem, cpus, freemem } from \"node:os\";\nimport type {\n WhisperLocalConfig,\n WhisperModelSize,\n WhisperModelSource,\n WhisperBackend,\n WhisperEnvironmentInfo,\n} from \"../types.js\";\nimport type { Logger } from \"../logger.js\";\nimport type { TranscriptionResult, TranscriptSegment } from \"./asr.js\";\n\n// ─── Constants ───\n\nconst WHISPER_MODELS_DIR = \"whisper-models\";\nconst WHISPER_BIN_DIR = \"whisper-bin\";\n\n/** Hugging Face GGML 模型下载 URL 模板(海外) */\nconst HF_MODEL_URL_TEMPLATE =\n \"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-{model}.bin\";\n\n/** 国内 ModelScope 镜像 URL 模板(lihuoo/whisper.cpp-asr-model-collection) */\nconst MODELSCOPE_MODEL_URL_TEMPLATE =\n \"https://modelscope.cn/models/lihuoo/whisper.cpp-asr-model-collection/resolve/master/{model}.bin\";\n\n/** 连通性探测超时(ms) */\nconst PROBE_TIMEOUT_MS = 5_000;\n\n/** 模型规格 → 文件名映射 */\nconst MODEL_FILENAMES: Record<WhisperModelSize, string> = {\n tiny: \"ggml-tiny.bin\",\n base: \"ggml-base.bin\",\n small: \"ggml-small.bin\",\n medium: \"ggml-medium.bin\",\n \"large-v3\": \"ggml-large-v3.bin\",\n};\n\n/** 模型规格 → 推理内存需求 GB(§6.4.3) */\nconst MODEL_MEMORY_REQUIREMENTS: Record<WhisperModelSize, number> = {\n tiny: 1,\n base: 1.5,\n small: 3,\n medium: 6,\n \"large-v3\": 11,\n};\n\n/** 模型规格 → 磁盘占用(字节,近似值) */\nconst MODEL_DISK_SIZES: Record<WhisperModelSize, number> = {\n tiny: 75 * 1024 * 1024,\n base: 140 * 1024 * 1024,\n small: 460 * 1024 * 1024,\n medium: 1500 * 1024 * 1024,\n \"large-v3\": 3000 * 1024 * 1024,\n};\n\n/** whisper.cpp JSON 输出格式 */\ninterface WhisperCppJsonOutput {\n transcription?: Array<{\n timestamps?: { from: string; to: string };\n offsets?: { from: number; to: number };\n text: string;\n }>;\n}\n\n// ─── Public API ───\n\n/**\n * 检测运行环境与硬件配置(§6.4.1)\n *\n * 检测操作系统、CPU 架构、GPU、可用内存,\n * 推荐最优推理后端与模型规格。\n */\nexport function detectEnvironment(logger: Logger): WhisperEnvironmentInfo {\n const os = platform() as \"darwin\" | \"linux\" | \"win32\";\n const cpuArch = arch() as \"arm64\" | \"x64\";\n const isAppleSilicon = os === \"darwin\" && cpuArch === \"arm64\";\n const hasCuda = detectCuda(logger);\n\n // 推荐后端(§6.4.2)\n let recommendedBackend: WhisperBackend;\n if (isAppleSilicon) {\n recommendedBackend = \"coreml\";\n } else if (hasCuda) {\n recommendedBackend = \"cuda\";\n } else {\n recommendedBackend = \"cpu\";\n }\n\n // 可用内存\n const availableMemoryGB = getAvailableMemoryGB(recommendedBackend, logger);\n const physicalCores = getPhysicalCoreCount();\n\n // 推荐模型\n const recommendedModel = selectModelByMemory(availableMemoryGB, isAppleSilicon);\n\n const info: WhisperEnvironmentInfo = {\n os,\n arch: cpuArch,\n isAppleSilicon,\n hasCuda,\n recommendedBackend,\n availableMemoryGB: Math.round(availableMemoryGB * 10) / 10,\n recommendedModel,\n physicalCores,\n };\n\n logger.info(\n `[whisper-local] 环境检测完成: os=${os}, arch=${cpuArch}, ` +\n `appleSilicon=${isAppleSilicon}, cuda=${hasCuda}, ` +\n `backend=${recommendedBackend}, memory=${info.availableMemoryGB}GB, ` +\n `model=${recommendedModel}, cores=${physicalCores}`,\n );\n\n return info;\n}\n\n/**\n * 根据可用内存自动选择模型规格(§6.4.3)\n *\n * 策略:优先匹配可用内存最大能承载的模型(向下取最近档位)。\n * Apple Silicon CoreML 后端内存效率更高,同档位需求降低 ~30%。\n */\nexport function selectModelByMemory(\n availableGB: number,\n isAppleSilicon: boolean = false,\n): WhisperModelSize {\n // Apple Silicon CoreML 内存效率提升约 30%\n const effectiveGB = isAppleSilicon ? availableGB / 0.7 : availableGB;\n\n if (effectiveGB >= 12) return \"large-v3\";\n if (effectiveGB >= 8) return \"medium\";\n if (effectiveGB >= 6) return \"small\";\n if (effectiveGB >= 4) return \"base\";\n return \"tiny\";\n}\n\n/**\n * 解析模型存储目录\n */\nexport function resolveModelsDir(dataDir: string): string {\n const dir = join(dataDir, WHISPER_MODELS_DIR);\n mkdirSync(dir, { recursive: true });\n return dir;\n}\n\n/**\n * 解析 whisper.cpp 二进制目录\n */\nexport function resolveBinDir(dataDir: string): string {\n const dir = join(dataDir, WHISPER_BIN_DIR);\n mkdirSync(dir, { recursive: true });\n return dir;\n}\n\n/**\n * 检查模型文件是否已下载(§6.4.5)\n */\nexport function isModelDownloaded(modelsDir: string, modelSize: WhisperModelSize): boolean {\n const modelPath = join(modelsDir, MODEL_FILENAMES[modelSize]);\n if (!existsSync(modelPath)) return false;\n\n // 简单校验:文件大小至少为预期大小的 80%(防止下载不完整)\n try {\n const stat = statSync(modelPath);\n const expectedSize = MODEL_DISK_SIZES[modelSize];\n return stat.size >= expectedSize * 0.8;\n } catch {\n return false;\n }\n}\n\n/**\n * 下载 Whisper 模型文件(§6.4.5)\n *\n * 下载源选择策略:\n * - modelMirrorUrl 存在 → 使用自定义 URL\n * - modelSource = \"huggingface\" → 直接使用 Hugging Face\n * - modelSource = \"domestic\" → 直接使用国内镜像(ModelScope)\n * - modelSource = \"auto\"(默认)→ 先探测 Hugging Face 连通性(5s 超时),\n * 可达则用 HF,不可达则回退国内镜像\n */\nexport async function downloadModel(\n modelsDir: string,\n modelSize: WhisperModelSize,\n logger: Logger,\n modelSource?: WhisperModelSource,\n mirrorUrl?: string,\n): Promise<{ ok: boolean; modelPath: string; error?: string }> {\n const filename = MODEL_FILENAMES[modelSize];\n const modelPath = join(modelsDir, filename);\n\n // 已存在且完整 → 跳过\n if (isModelDownloaded(modelsDir, modelSize)) {\n logger.info(`[whisper-local] 模型已存在,跳过下载: ${filename}`);\n return { ok: true, modelPath };\n }\n\n // 解析下载 URL\n const url = await resolveModelUrl(modelSize, modelSource, mirrorUrl, logger);\n\n logger.info(\n `[whisper-local] 开始下载模型: ${modelSize} (${formatBytes(MODEL_DISK_SIZES[modelSize])})`,\n );\n logger.info(`[whisper-local] 下载 URL: ${url}`);\n\n const result = await downloadFromUrl(url, modelPath, logger);\n\n // auto 模式且 HF 失败 → 尝试国内镜像回退\n if (\n !result.ok &&\n !mirrorUrl &&\n (modelSource === \"auto\" || !modelSource) &&\n url.includes(\"huggingface.co\")\n ) {\n const fallbackUrl = MODELSCOPE_MODEL_URL_TEMPLATE.replace(\"{model}\", modelSize);\n logger.info(\n `[whisper-local] Hugging Face 下载失败,回退至国内镜像(ModelScope): ${fallbackUrl}`,\n );\n return downloadFromUrl(fallbackUrl, modelPath, logger);\n }\n\n return result;\n}\n\n/**\n * 解析模型下载 URL\n */\nasync function resolveModelUrl(\n modelSize: WhisperModelSize,\n modelSource: WhisperModelSource | undefined,\n mirrorUrl: string | undefined,\n logger: Logger,\n): Promise<string> {\n // 自定义 URL 优先级最高\n if (mirrorUrl) {\n return `${mirrorUrl.replace(/\\/$/, \"\")}/${MODEL_FILENAMES[modelSize]}`;\n }\n\n const source = modelSource ?? \"auto\";\n\n switch (source) {\n case \"huggingface\":\n return HF_MODEL_URL_TEMPLATE.replace(\"{model}\", modelSize);\n case \"domestic\":\n return MODELSCOPE_MODEL_URL_TEMPLATE.replace(\"{model}\", modelSize);\n case \"auto\": {\n // 探测 Hugging Face 连通性\n const hfReachable = await probeUrl(\"https://huggingface.co\", logger);\n if (hfReachable) {\n logger.info(\"[whisper-local] Hugging Face 可达,使用海外源\");\n return HF_MODEL_URL_TEMPLATE.replace(\"{model}\", modelSize);\n }\n logger.info(\"[whisper-local] Hugging Face 不可达,使用国内镜像(ModelScope)\");\n return MODELSCOPE_MODEL_URL_TEMPLATE.replace(\"{model}\", modelSize);\n }\n default:\n return HF_MODEL_URL_TEMPLATE.replace(\"{model}\", modelSize);\n }\n}\n\n/**\n * 探测 URL 连通性(HEAD 请求,短超时)\n */\nasync function probeUrl(url: string, logger: Logger): Promise<boolean> {\n try {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), PROBE_TIMEOUT_MS);\n try {\n const res = await fetch(url, {\n method: \"HEAD\",\n signal: controller.signal,\n });\n return res.ok || res.status === 301 || res.status === 302;\n } finally {\n clearTimeout(timer);\n }\n } catch (err: any) {\n logger.info(\n `[whisper-local] 连通性探测失败: ${url} (${err?.name ?? err?.message ?? \"unknown\"})`,\n );\n return false;\n }\n}\n\n/**\n * 从指定 URL 下载模型文件至本地\n */\nasync function downloadFromUrl(\n url: string,\n modelPath: string,\n logger: Logger,\n): Promise<{ ok: boolean; modelPath: string; error?: string }> {\n const tmpPath = `${modelPath}.downloading`;\n\n try {\n mkdirSync(dirname(modelPath), { recursive: true });\n\n const controller = new AbortController();\n // 模型下载超时:30 分钟(large-v3 约 3GB)\n const timer = setTimeout(() => controller.abort(), 30 * 60 * 1000);\n\n try {\n const res = await fetch(url, { signal: controller.signal });\n\n if (!res.ok) {\n return {\n ok: false,\n modelPath,\n error: `模型下载失败: HTTP ${res.status} ${res.statusText}`,\n };\n }\n\n if (!res.body) {\n return { ok: false, modelPath, error: \"模型下载失败: 响应体为空\" };\n }\n\n const contentLength = Number(res.headers.get(\"content-length\") ?? 0);\n const writeStream = createWriteStream(tmpPath);\n const readable = Readable.fromWeb(res.body as any);\n\n // 下载进度日志\n let downloaded = 0;\n let lastLogPercent = 0;\n readable.on(\"data\", (chunk: Buffer) => {\n downloaded += chunk.length;\n if (contentLength > 0) {\n const percent = Math.floor((downloaded / contentLength) * 100);\n if (percent >= lastLogPercent + 10) {\n logger.info(\n `[whisper-local] 下载进度: ${percent}% (${formatBytes(downloaded)} / ${formatBytes(contentLength)})`,\n );\n lastLogPercent = percent;\n }\n }\n });\n\n await pipeline(readable, writeStream);\n } finally {\n clearTimeout(timer);\n }\n\n // 重命名为正式文件\n const { renameSync } = await import(\"node:fs\");\n renameSync(tmpPath, modelPath);\n\n const fileSize = statSync(modelPath).size;\n logger.info(\n `[whisper-local] 模型下载完成: ${basename(modelPath)} (${formatBytes(fileSize)})`,\n );\n\n return { ok: true, modelPath };\n } catch (err: any) {\n // 清理临时文件\n try {\n if (existsSync(tmpPath)) unlinkSync(tmpPath);\n } catch { /* ignore */ }\n\n const msg = err?.name === \"AbortError\"\n ? \"模型下载超时(30 分钟)\"\n : (err?.message ?? String(err));\n logger.error(`[whisper-local] 模型下载失败: ${msg}`);\n return { ok: false, modelPath, error: msg };\n }\n}\n\n/**\n * 查找 whisper.cpp CLI 二进制文件\n *\n * 按以下优先级查找:\n * 1. 插件数据目录下的 whisper-bin/\n * 2. 系统 PATH 中的 whisper-cli / whisper-cpp / whisper\n */\nexport function findWhisperBinary(dataDir: string, logger: Logger): string | null {\n // 1. 检查插件 bin 目录\n const binDir = resolveBinDir(dataDir);\n const binNames = platform() === \"win32\"\n ? [\"whisper-cli.exe\", \"whisper.exe\", \"main.exe\"]\n : [\"whisper-cli\", \"whisper\", \"main\"];\n\n for (const name of binNames) {\n const binPath = join(binDir, name);\n if (existsSync(binPath)) {\n logger.info(`[whisper-local] 找到本地二进制: ${binPath}`);\n return binPath;\n }\n }\n\n // 2. 检查系统 PATH\n const pathNames = platform() === \"win32\"\n ? [\"whisper-cli\", \"whisper-cpp\", \"whisper\"]\n : [\"whisper-cli\", \"whisper-cpp\", \"whisper\"];\n\n for (const name of pathNames) {\n try {\n const cmd = platform() === \"win32\" ? \"where\" : \"which\";\n const result = execSync(`${cmd} ${name}`, { encoding: \"utf-8\", stdio: \"pipe\" }).trim();\n if (result) {\n logger.info(`[whisper-local] 找到系统 PATH 二进制: ${result}`);\n return result.split(\"\\n\")[0].trim();\n }\n } catch {\n // not found, continue\n }\n }\n\n logger.warn(\"[whisper-local] 未找到 whisper.cpp 二进制文件\");\n return null;\n}\n\n/**\n * 使用本地 Whisper 执行转写(§6.4)\n *\n * @param audioFilePath 本地音频文件绝对路径\n * @param localConfig 本地 Whisper 配置\n * @param dataDir 插件数据目录(存放模型和二进制)\n * @param logger 日志\n */\nexport async function transcribeWithWhisperLocal(\n audioFilePath: string,\n localConfig: WhisperLocalConfig,\n dataDir: string,\n logger: Logger,\n): Promise<TranscriptionResult> {\n // 1. 检测环境\n const env = detectEnvironment(logger);\n\n // 2. 确定后端、模型、线程数\n const backend = localConfig.backend ?? env.recommendedBackend;\n const modelSize = localConfig.model ?? env.recommendedModel;\n const threads = localConfig.threads ?? env.physicalCores;\n const language = localConfig.language ?? \"auto\";\n const translate = localConfig.translate ?? false;\n\n logger.info(\n `[whisper-local] 转写参数: backend=${backend}, model=${modelSize}, ` +\n `threads=${threads}, language=${language}, translate=${translate}`,\n );\n\n // 3. 查找 whisper.cpp 二进制\n const whisperBin = findWhisperBinary(dataDir, logger);\n if (!whisperBin) {\n return {\n ok: false,\n error:\n \"未找到 whisper.cpp 二进制文件。请安装 whisper.cpp 并确保 whisper-cli 在 PATH 中,\" +\n `或将二进制文件放入 ${resolveBinDir(dataDir)}`,\n };\n }\n\n // 4. 确保模型已下载\n const modelsDir = resolveModelsDir(dataDir);\n if (!isModelDownloaded(modelsDir, modelSize)) {\n logger.info(`[whisper-local] 模型 ${modelSize} 未下载,开始下载...`);\n const downloadResult = await downloadModel(\n modelsDir,\n modelSize,\n logger,\n localConfig.modelSource,\n localConfig.modelMirrorUrl,\n );\n if (!downloadResult.ok) {\n return { ok: false, error: `模型下载失败: ${downloadResult.error}` };\n }\n }\n\n const modelPath = join(modelsDir, MODEL_FILENAMES[modelSize]);\n\n // 5. 音频格式转换(whisper.cpp 仅支持 16kHz mono WAV)\n // 通过 magic bytes 判断真实格式,不依赖扩展名\n let inputPath = audioFilePath;\n let tmpWavPath: string | null = null;\n\n const actualFmt = detectAudioFormat(audioFilePath);\n if (actualFmt !== \".wav\") {\n tmpWavPath = audioFilePath.replace(/\\.[^.]+$/, \".whisper.wav\");\n logger.info(\n `[whisper-local] 转换音频格式: ${audioFilePath} (${actualFmt ?? \"未知\"}) → WAV (16kHz mono)`,\n );\n\n const convertResult = convertToWav(audioFilePath, tmpWavPath, actualFmt, logger);\n if (!convertResult.ok) {\n return { ok: false, error: convertResult.error! };\n }\n inputPath = tmpWavPath;\n }\n\n // 6. 构建 whisper.cpp CLI 参数\n const args = buildWhisperArgs({\n audioFilePath: inputPath,\n modelPath,\n language,\n translate,\n threads,\n backend,\n });\n\n logger.info(`[whisper-local] 执行: ${whisperBin} ${args.join(\" \")}`);\n\n // 7. 执行转写\n try {\n const startMs = Date.now();\n let result: SpawnSyncReturns<string>;\n\n try {\n result = spawnSync(whisperBin, args, {\n encoding: \"utf-8\" as const,\n timeout: 60 * 60 * 1000, // 1 小时超时(5 小时录音)\n maxBuffer: 100 * 1024 * 1024, // 100MB stdout buffer\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n } catch (err: any) {\n cleanupTmpWav(tmpWavPath);\n return { ok: false, error: `whisper.cpp 执行失败: ${err?.message ?? err}` };\n }\n\n if (result.status !== 0) {\n cleanupTmpWav(tmpWavPath);\n const stderr = result.stderr?.slice(0, 500) ?? \"\";\n return {\n ok: false,\n error: `whisper.cpp 退出码 ${result.status}: ${stderr}`,\n };\n }\n\n const elapsed = Date.now() - startMs;\n logger.info(`[whisper-local] 转写耗时: ${Math.round(elapsed / 1000)}s`);\n\n // 8. 读取 JSON 输出文件(--output-json 将结果写入 {inputPath}.json)\n const jsonPath = inputPath + \".json\";\n let jsonContent: string;\n\n if (existsSync(jsonPath)) {\n jsonContent = readFileSync(jsonPath, \"utf-8\");\n // 清理 JSON 文件\n try { unlinkSync(jsonPath); } catch { /* ignore */ }\n } else {\n // 回退:尝试解析 stdout(部分 whisper.cpp 版本可能输出到 stdout)\n jsonContent = result.stdout;\n }\n\n cleanupTmpWav(tmpWavPath);\n\n return parseWhisperOutput(jsonContent, logger);\n } catch (err: any) {\n cleanupTmpWav(tmpWavPath);\n return { ok: false, error: `whisper.cpp 转写异常: ${err?.message ?? err}` };\n }\n}\n\n/**\n * 获取本地 Whisper 状态信息(供 App 查询环境检测结果)\n */\nexport function getWhisperLocalStatus(\n dataDir: string,\n logger: Logger,\n): {\n environment: WhisperEnvironmentInfo;\n binaryFound: boolean;\n binaryPath: string | null;\n downloadedModels: WhisperModelSize[];\n} {\n const env = detectEnvironment(logger);\n const binaryPath = findWhisperBinary(dataDir, logger);\n const modelsDir = resolveModelsDir(dataDir);\n\n const allModels: WhisperModelSize[] = [\"tiny\", \"base\", \"small\", \"medium\", \"large-v3\"];\n const downloadedModels = allModels.filter((m) => isModelDownloaded(modelsDir, m));\n\n return {\n environment: env,\n binaryFound: binaryPath !== null,\n binaryPath,\n downloadedModels,\n };\n}\n\n// ─── Internal Helpers ───\n\n/**\n * 检测 CUDA 是否可用(§6.4.1)\n */\nfunction detectCuda(logger: Logger): boolean {\n try {\n // 尝试运行 nvidia-smi\n execSync(\"nvidia-smi\", { encoding: \"utf-8\", stdio: \"pipe\", timeout: 5000 });\n logger.info(\"[whisper-local] 检测到 NVIDIA GPU (nvidia-smi)\");\n return true;\n } catch {\n // nvidia-smi 不存在或执行失败\n }\n\n // 检查 CUDA runtime 库\n if (platform() === \"linux\") {\n try {\n const ldconfig = execSync(\"ldconfig -p 2>/dev/null | grep libcudart\", {\n encoding: \"utf-8\",\n stdio: \"pipe\",\n timeout: 5000,\n });\n if (ldconfig.includes(\"libcudart\")) {\n logger.info(\"[whisper-local] 检测到 CUDA runtime (ldconfig)\");\n return true;\n }\n } catch { /* ignore */ }\n }\n\n return false;\n}\n\n/**\n * 获取可用内存(GB)\n *\n * CUDA 后端使用 VRAM,其余使用系统 RAM。\n */\nfunction getAvailableMemoryGB(backend: WhisperBackend, logger: Logger): number {\n if (backend === \"cuda\") {\n // 尝试获取 GPU VRAM\n try {\n const output = execSync(\n \"nvidia-smi --query-gpu=memory.free --format=csv,noheader,nounits\",\n { encoding: \"utf-8\", stdio: \"pipe\", timeout: 5000 },\n );\n const freeVramMB = parseInt(output.trim().split(\"\\n\")[0], 10);\n if (!Number.isNaN(freeVramMB) && freeVramMB > 0) {\n return freeVramMB / 1024;\n }\n } catch {\n logger.warn(\"[whisper-local] 无法获取 GPU VRAM,使用系统 RAM 代替\");\n }\n }\n\n // 使用系统可用内存(取 total 的 80% 和 free 的较大值作为可用估计)\n const totalGB = totalmem() / (1024 * 1024 * 1024);\n const freeGB = freemem() / (1024 * 1024 * 1024);\n return Math.max(freeGB, totalGB * 0.6);\n}\n\n/**\n * 获取物理 CPU 核心数\n */\nfunction getPhysicalCoreCount(): number {\n const cpuList = cpus();\n if (cpuList.length === 0) return 4; // fallback\n\n // 简单估算:逻辑核 / 2(假设超线程)\n // macOS ARM 无超线程,直接使用逻辑核数\n if (platform() === \"darwin\" && arch() === \"arm64\") {\n // Apple Silicon: P-cores only (exclude E-cores for inference)\n // 简化处理:使用总核数\n return cpuList.length;\n }\n\n return Math.max(1, Math.floor(cpuList.length / 2));\n}\n\n/**\n * 通过文件头 magic bytes 检测音频的真实格式\n * @returns 正确的文件扩展名(如 .aiff, .wav, .m4a),或 null\n */\nfunction detectAudioFormat(filePath: string): string | null {\n try {\n const fd = openSync(filePath, \"r\");\n const buf = Buffer.alloc(12);\n readSync(fd, buf, 0, 12, 0);\n closeSync(fd);\n\n const header = buf.toString(\"ascii\", 0, 4);\n const header8 = buf.toString(\"ascii\", 0, 8);\n\n // RIFF....WAVE = WAV\n if (header === \"RIFF\" && buf.toString(\"ascii\", 8, 12) === \"WAVE\") return \".wav\";\n // FORM....AIFF / FORM....AIFC = AIFF\n if (header === \"FORM\") {\n const sub = buf.toString(\"ascii\", 8, 12);\n if (sub === \"AIFF\" || sub === \"AIFC\") return \".aiff\";\n }\n // ftyp = MP4/M4A/AAC container\n if (buf.toString(\"ascii\", 4, 8) === \"ftyp\") return \".m4a\";\n // ID3 or 0xFF 0xFB = MP3\n if (header.startsWith(\"ID3\") || (buf[0] === 0xff && (buf[1] & 0xe0) === 0xe0)) return \".mp3\";\n // OggS = Ogg (Vorbis/Opus)\n if (header === \"OggS\") return \".ogg\";\n // fLaC = FLAC\n if (header === \"fLaC\") return \".flac\";\n\n return null;\n } catch {\n return null;\n }\n}\n\n/**\n * 将音频文件转换为 whisper.cpp 所需的 16kHz mono WAV 格式\n *\n * 转换链(按优先级):\n * 1. ffmpeg — 支持全格式,含 OGG/Opus\n * 2. opusdec — 专用于 OGG/Opus(来自 brew install opus-tools)\n * 3. afconvert — macOS 内置,支持 AIFF/M4A/AAC;需正确文件扩展名\n *\n * @param actualFmt detectAudioFormat 检测到的真实格式(如 \".ogg\", \".aiff\"),可为 null\n */\nfunction convertToWav(\n inputPath: string,\n outputPath: string,\n actualFmt: string | null,\n logger: Logger,\n): { ok: boolean; error?: string } {\n // 尝试 ffmpeg(可自动检测格式,不依赖扩展名)\n try {\n const ffmpegResult = spawnSync(\"ffmpeg\", [\n \"-y\", \"-i\", inputPath,\n \"-ar\", \"16000\", \"-ac\", \"1\", \"-c:a\", \"pcm_s16le\",\n outputPath,\n ], {\n encoding: \"utf-8\",\n timeout: 120_000,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n\n if (ffmpegResult.status === 0 && existsSync(outputPath)) {\n logger.info(`[whisper-local] ffmpeg 转换完成: ${outputPath}`);\n return { ok: true };\n }\n } catch {\n // ffmpeg 不可用,继续尝试其他方式\n }\n\n // 2. opusdec — 专用于 OGG/Opus(ffmpeg 不可用时)\n if (actualFmt === \".ogg\") {\n try {\n const opusResult = spawnSync(\n \"opusdec\",\n [\"--rate\", \"16000\", \"--mono\", inputPath, outputPath],\n { encoding: \"utf-8\", timeout: 120_000, stdio: [\"pipe\", \"pipe\", \"pipe\"] },\n );\n if (opusResult.status === 0 && existsSync(outputPath)) {\n logger.info(`[whisper-local] opusdec 转换完成: ${outputPath}`);\n return { ok: true };\n }\n } catch { /* opusdec 不可用,继续 */ }\n }\n\n // 3. macOS afconvert — 支持 AIFF/M4A/AAC,不支持 OGG\n if (process.platform === \"darwin\" && actualFmt !== \".ogg\") {\n // afconvert 依赖扩展名判断输入格式,先确保扩展名正确\n let actualInputPath = inputPath;\n let tmpCopy: string | null = null;\n const detectedExt = actualFmt;\n\n if (detectedExt && !inputPath.endsWith(detectedExt)) {\n // 扩展名不匹配,创建带正确扩展名的临时副本\n tmpCopy = inputPath + \".detected\" + detectedExt;\n try {\n copyFileSync(inputPath, tmpCopy);\n actualInputPath = tmpCopy;\n logger.info(\n `[whisper-local] 检测到实际格式 ${detectedExt},临时重命名`,\n );\n } catch {\n tmpCopy = null;\n }\n }\n\n try {\n const afResult = spawnSync(\"afconvert\", [\n \"-f\", \"WAVE\", \"-d\", \"LEI16@16000\", \"-c\", \"1\",\n actualInputPath, outputPath,\n ], {\n encoding: \"utf-8\",\n timeout: 120_000,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n\n // 清理临时副本\n if (tmpCopy && existsSync(tmpCopy)) {\n try { unlinkSync(tmpCopy); } catch { /* ignore */ }\n }\n\n if (afResult.status === 0 && existsSync(outputPath)) {\n logger.info(`[whisper-local] afconvert 转换完成: ${outputPath}`);\n return { ok: true };\n }\n\n const stderr = afResult.stderr?.slice(0, 200) ?? \"\";\n return { ok: false, error: `afconvert 转换失败 (exit ${afResult.status}): ${stderr}` };\n } catch (err: any) {\n // 清理临时副本\n if (tmpCopy && existsSync(tmpCopy)) {\n try { unlinkSync(tmpCopy); } catch { /* ignore */ }\n }\n return { ok: false, error: `afconvert 不可用: ${err?.message}` };\n }\n }\n\n const fmtHint = actualFmt === \".ogg\"\n ? \"OGG/Opus 格式需要 ffmpeg 或 opus-tools(brew install opus-tools)\"\n : \"请安装 ffmpeg(brew install ffmpeg)或确保音频文件为 WAV 格式\";\n return { ok: false, error: `无法将音频转换为 WAV 格式。${fmtHint}` };\n}\n\n/** 清理临时 WAV 文件 */\nfunction cleanupTmpWav(path: string | null): void {\n if (path && existsSync(path)) {\n try { unlinkSync(path); } catch { /* ignore */ }\n }\n}\n\n/**\n * 构建 whisper.cpp CLI 参数\n */\nfunction buildWhisperArgs(params: {\n audioFilePath: string;\n modelPath: string;\n language: string;\n translate: boolean;\n threads: number;\n backend: WhisperBackend;\n}): string[] {\n const args: string[] = [\n \"--model\", params.modelPath,\n \"--file\", params.audioFilePath,\n \"--output-json\", // JSON 格式输出到 {audioFilePath}.json\n \"--no-prints\", // 抑制模型信息输出\n \"--threads\", String(params.threads),\n ];\n\n // 语言\n if (params.language && params.language !== \"auto\") {\n args.push(\"--language\", params.language);\n } else {\n args.push(\"--language\", \"auto\");\n }\n\n // 翻译为英文\n if (params.translate) {\n args.push(\"--translate\");\n }\n\n return args;\n}\n\n/**\n * 解析 whisper.cpp JSON 输出\n */\nfunction parseWhisperOutput(\n stdout: string,\n logger: Logger,\n): TranscriptionResult {\n if (!stdout || !stdout.trim()) {\n return { ok: false, error: \"whisper.cpp 无输出\" };\n }\n\n try {\n const data = JSON.parse(stdout.trim()) as WhisperCppJsonOutput;\n\n if (!data.transcription || !Array.isArray(data.transcription)) {\n // 可能是纯文本输出\n return {\n ok: true,\n text: stdout.trim(),\n segments: [],\n };\n }\n\n const segments: TranscriptSegment[] = [];\n const textParts: string[] = [];\n\n for (const item of data.transcription) {\n const text = item.text?.trim() ?? \"\";\n if (!text) continue;\n\n textParts.push(text);\n\n const startMs = item.offsets?.from ?? parseTimestamp(item.timestamps?.from);\n const endMs = item.offsets?.to ?? parseTimestamp(item.timestamps?.to);\n\n segments.push({\n start_ms: startMs,\n end_ms: endMs,\n text,\n });\n }\n\n const fullText = textParts.join(\" \");\n\n logger.info(\n `[whisper-local] 转写完成: ${fullText.length} 字, ${segments.length} 段`,\n );\n\n return {\n ok: true,\n text: fullText,\n segments,\n };\n } catch (err: any) {\n logger.warn(`[whisper-local] JSON 解析失败,尝试纯文本: ${err?.message}`);\n\n // Fallback: 将 stdout 视为纯文本\n return {\n ok: true,\n text: stdout.trim(),\n segments: [],\n };\n }\n}\n\n/**\n * 解析 whisper.cpp 时间戳字符串 \"HH:MM:SS,mmm\" → 毫秒\n */\nfunction parseTimestamp(ts?: string): number {\n if (!ts) return 0;\n // \"00:00:05,000\" or \"00:00:05.000\"\n const match = ts.match(/^(\\d+):(\\d+):(\\d+)[,.](\\d+)$/);\n if (!match) return 0;\n const [, h, m, s, ms] = match;\n return (\n parseInt(h, 10) * 3600000 +\n parseInt(m, 10) * 60000 +\n parseInt(s, 10) * 1000 +\n parseInt(ms, 10)\n );\n}\n\n/**\n * 格式化字节数\n */\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes}B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;\n if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;\n return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)}GB`;\n}\n","/**\n * ASR 转写调度器(§6 / §7)\n *\n * 按 arc-long-recording §6.2 定义的两层配置结构调度 ASR:\n * - mode = \"api\":YoooClaw 托管云端 ASR(经 model-proxy 长录音接口调用)\n * - mode = \"local\":本地 Whisper 转写(§6.4,内置 whisper.cpp 推理)\n * - mode = \"yoooclaw\":YoooClaw 自建 ASR(P2,预留接口)\n *\n * 转写流程:\n * 1. 读取录音 OSS URL 与本地文件\n * 2. 调用云端 model-proxy 或本地 Whisper 获取转写文本\n * 3. 将关键点以 [关键点 MM:SS] 内嵌转写文本\n * 4. 自动生成摘要标题(≤ 10 字)\n * 5. 写入 /recordings/transcripts/日期_时间_摘要.md\n */\n\nimport { existsSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type {\n AsrConfig,\n AsrApiConfig,\n RecordingMarker,\n RecordingAsrInitResult,\n RecordingTranscriptItem,\n} from \"../types.js\";\nimport type { Logger } from \"../logger.js\";\nimport { requireApiKey, loadApiKey } from \"../auth/credentials.js\";\nimport { getEnvUrls } from \"../env.js\";\nimport {\n buildTranscriptDataFilename,\n buildTranscriptDocument,\n extractSourceTextListFromDocument,\n} from \"./transcript-document.js\";\n\nconst DEFAULT_LONG_RECORDING_POLL_INTERVAL_MS = 2000;\nconst DEFAULT_LONG_RECORDING_MAX_POLL_ATTEMPTS = 3600;\nconst LONG_RECORDING_RUNNING_STATUSES = new Set([\"PENDING\", \"RUNNING\", \"SUSPENDED\"]);\nconst LONG_RECORDING_TERMINAL_FAILURE_STATUSES = new Set([\"FAILED\", \"CANCELED\", \"UNKNOWN\"]);\n\nconst DEFAULT_HTTP_MAX_ATTEMPTS = 3;\nconst DEFAULT_HTTP_RETRY_BACKOFF_MS = 2000;\n\n// ─── Types ───\n\nexport interface TranscriptionResult {\n ok: boolean;\n /** 转写全文 */\n text?: string;\n /** 带时间戳的分段(如 ASR 支持) */\n segments?: TranscriptSegment[];\n /** 自动生成的摘要标题 */\n summary?: string;\n /** 给客户端展示的摘要文本 */\n summaryText?: string;\n /** 分类信息(如会议纪要、采访) */\n category?: string;\n /** 转写来源信息 */\n sourceInfo?: {\n provider: string;\n taskId?: string;\n requestId?: string;\n status?: string;\n };\n /** Provider 原始响应,供后续兼容字段演进 */\n rawResponse?: unknown;\n /** 错误信息 */\n error?: string;\n}\n\nexport interface TranscriptSegment {\n /** 开始时间(毫秒) */\n start_ms: number;\n /** 结束时间(毫秒) */\n end_ms: number;\n /** 文本内容 */\n text: string;\n /** 说话人 ID(如云端 ASR 返回) */\n speaker_id?: number;\n}\n\ninterface ModelProxyLongRecordingSubmitRequest {\n audioOssUrl: string;\n language?: string;\n enableNormalization?: boolean;\n}\n\ninterface ModelProxyLongRecordingResult {\n sourceText?: string | null;\n sourceTextList?: ModelProxyLongRecordingSourceTextItem[] | null;\n summaryResult?: string | null;\n category?: string | null;\n title?: string | null;\n}\n\ninterface ModelProxyLongRecordingSourceTextItem {\n content?: string | null;\n speakerId?: number | null;\n startTime?: number | null;\n endTime?: number | null;\n}\n\ninterface ModelProxyLongRecordingStatusResponse {\n taskId?: string;\n status?: string;\n requestId?: string;\n errorMessage?: string | null;\n recordResult?: ModelProxyLongRecordingResult | null;\n}\n\ninterface ResponseEnvelope<T> {\n success?: boolean;\n code?: number | string;\n message?: string | null;\n e?: unknown;\n data?: T | null;\n}\n\n// ─── Public API ───\n\n/**\n * 判断 ASR 是否已配置\n */\nexport function isAsrConfigured(config?: AsrConfig): boolean {\n return !!config && !validateAsrConfig(config);\n}\n\n/**\n * 校验客户端下发的 ASR 配置。\n * 返回 undefined 表示配置可用;返回字符串表示错误原因。\n */\nexport function validateAsrConfig(config?: AsrConfig): string | undefined {\n if (!config?.mode) {\n return \"asr.mode is required\";\n }\n\n switch (config.mode) {\n case \"local\":\n case \"api\":\n return undefined;\n case \"yoooclaw\":\n return \"YoooClaw ASR 尚未实现(P2)\";\n default:\n return `未知的 ASR mode: ${(config as { mode: string }).mode}`;\n }\n}\n\n/**\n * 显式初始化 ASR 能力。\n * - mode=api:校验插件本地 API Key 是否存在,并返回最终使用的 model-proxy submit-task endpoint\n * - mode=local:按配置预下载模型,并返回本地环境状态\n */\nexport async function initializeAsr(\n config: AsrConfig,\n dataDir: string,\n logger: Logger,\n): Promise<RecordingAsrInitResult> {\n const validationError = validateAsrConfig(config);\n if (validationError) {\n return {\n ok: false,\n mode: config.mode,\n error: validationError,\n };\n }\n\n switch (config.mode) {\n case \"api\": {\n const endpoint = resolveModelProxyLongRecordingSubmitEndpoint(config.api);\n const keyConfigured = hasText(config.api?.apiKey) || hasText(loadApiKey());\n\n if (!keyConfigured) {\n return {\n ok: false,\n mode: \"api\",\n provider: \"model-proxy\",\n endpoint,\n language: config.api?.language ?? \"auto\",\n keyConfigured: false,\n error:\n \"API Key 未设置,请在本次 asr.api.apiKey 中传入,或先写入 credentials.json / 执行 ntf auth set-api-key <apiKey>\",\n };\n }\n\n return {\n ok: true,\n mode: \"api\",\n provider: \"model-proxy\",\n endpoint,\n language: config.api?.language ?? \"auto\",\n keyConfigured: true,\n };\n }\n case \"local\": {\n const localConfig = config.local ?? {};\n const {\n getWhisperLocalStatus,\n downloadModel,\n resolveModelsDir,\n } = await import(\"./whisper-local.js\");\n\n const initialStatus = getWhisperLocalStatus(dataDir, logger);\n const requestedModel = localConfig.model ?? initialStatus.environment.recommendedModel;\n\n const modelsDir = resolveModelsDir(dataDir);\n const downloadResult = await downloadModel(\n modelsDir,\n requestedModel,\n logger,\n localConfig.modelSource,\n localConfig.modelMirrorUrl,\n );\n if (!downloadResult.ok) {\n return {\n ok: false,\n mode: \"local\",\n model: requestedModel,\n localStatus: {\n ...initialStatus,\n requestedModel,\n },\n error: `模型下载失败: ${downloadResult.error}`,\n };\n }\n\n const finalStatus = getWhisperLocalStatus(dataDir, logger);\n if (!finalStatus.binaryFound) {\n return {\n ok: false,\n mode: \"local\",\n model: requestedModel,\n localStatus: {\n ...finalStatus,\n requestedModel,\n },\n error:\n \"模型已就绪,但未找到 whisper.cpp 二进制文件。请安装 whisper.cpp 并确保 whisper-cli 在 PATH 中。\",\n };\n }\n\n return {\n ok: true,\n mode: \"local\",\n model: requestedModel,\n language: localConfig.language ?? \"auto\",\n localStatus: {\n ...finalStatus,\n requestedModel,\n },\n };\n }\n case \"yoooclaw\":\n return {\n ok: false,\n mode: \"yoooclaw\",\n error: \"YoooClaw ASR 尚未实现(P2)\",\n };\n default:\n return {\n ok: false,\n mode: config.mode,\n error: `未知的 ASR mode: ${config.mode}`,\n };\n }\n}\n\n/**\n * 执行 ASR 转写\n *\n * @param audioFilePath 本地音频文件绝对路径\n * @param config ASR 配置(两层结构:mode + api/local)\n * @param logger 日志\n * @param options 额外上下文(云端 ASR 需要 OSS URL)\n */\nexport async function transcribeAudio(\n audioFilePath: string,\n config: AsrConfig,\n logger: Logger,\n options: {\n audioOssUrl?: string;\n audioDurationMs?: number;\n } = {},\n): Promise<TranscriptionResult> {\n if (!existsSync(audioFilePath)) {\n return { ok: false, error: `音频文件不存在: ${audioFilePath}` };\n }\n\n logger.info(\n `[asr] 开始转写: mode=${config.mode}, file=${audioFilePath}`,\n );\n\n try {\n switch (config.mode) {\n case \"api\":\n return await transcribeWithModelProxy(\n options.audioOssUrl,\n options.audioDurationMs,\n config.api,\n logger,\n );\n case \"local\":\n return await transcribeWithWhisperLocal(audioFilePath, config, logger);\n case \"yoooclaw\":\n return { ok: false, error: \"YoooClaw ASR 尚未实现(P2)\" };\n default:\n return {\n ok: false,\n error: `未知的 ASR mode: ${config.mode}`,\n };\n }\n } catch (err: any) {\n const msg = err?.message ?? String(err);\n logger.error(`[asr] 转写异常: ${msg}`);\n return { ok: false, error: msg };\n }\n}\n\n/**\n * 将转写结果与关键点标记合并,生成最终 Markdown 转写文本\n *\n * @param result 转写结果\n * @param markers 关键点列表\n * @param recordingName 录音名称\n * @param durationSec 录音总时长(秒)\n * @param createdAt 录音创建时间\n */\nexport function buildTranscriptMarkdown(\n result: TranscriptionResult,\n markers: RecordingMarker[],\n recordingName: string,\n durationSec: number,\n createdAt: string,\n): string { \n const summary = result.summary ?? recordingName.slice(0, 10);\n const lines: string[] = [];\n\n // 元数据头\n lines.push(`# ${summary}`);\n lines.push(\"\");\n lines.push(`> 录音名称:${recordingName}`);\n lines.push(`> 时长:${formatDuration(durationSec)}`);\n lines.push(`> 创建时间:${createdAt}`);\n if (markers.length > 0) {\n lines.push(`> 关键点数:${markers.length}`);\n }\n lines.push(\"\");\n lines.push(\"---\");\n lines.push(\"\");\n\n if (result.segments && result.segments.length > 0) {\n // 有分段的转写文本:在合适的位置插入关键点标记\n const sortedMarkers = [...markers].sort(\n (a, b) => a.timestamp_ms - b.timestamp_ms,\n );\n let markerIdx = 0;\n\n for (const seg of result.segments) {\n // 在当前段之前插入所有对应的关键点\n while (\n markerIdx < sortedMarkers.length &&\n sortedMarkers[markerIdx].timestamp_ms <= seg.start_ms\n ) {\n const m = sortedMarkers[markerIdx];\n lines.push(\n `**[关键点 ${formatTimestamp(m.timestamp_ms)}]**`,\n );\n lines.push(\"\");\n markerIdx++;\n }\n\n const segmentText = formatTranscriptSegmentText(seg);\n if (segmentText) {\n lines.push(segmentText);\n lines.push(\"\");\n }\n }\n\n // 追加剩余关键点\n while (markerIdx < sortedMarkers.length) {\n const m = sortedMarkers[markerIdx];\n lines.push(\n `**[关键点 ${formatTimestamp(m.timestamp_ms)}]**`,\n );\n lines.push(\"\");\n markerIdx++;\n }\n } else if (result.text) {\n // 纯文本转写:在文本头部集中列出关键点\n if (markers.length > 0) {\n lines.push(\"### 关键点\");\n lines.push(\"\");\n for (const m of markers) {\n lines.push(`- **[关键点 ${formatTimestamp(m.timestamp_ms)}]**`);\n }\n lines.push(\"\");\n lines.push(\"---\");\n lines.push(\"\");\n }\n lines.push(result.text);\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * 从转写文本中提取摘要标题(≤ 10 字)\n */\nexport function extractSummary(text: string): string {\n // 取第一句话,截断到 10 字\n const firstLine = text.split(/[。!?\\n]/).find((s) => s.trim().length > 0);\n if (!firstLine) return \"录音转写\";\n const trimmed = firstLine.trim();\n return trimmed.length <= 10 ? trimmed : trimmed.slice(0, 10);\n}\n\n/**\n * 完整的转写工作流:转写 → 生成 Markdown → 写入文件\n */\nexport async function runTranscriptionWorkflow(params: {\n audioFilePath: string;\n audioOssUrl?: string;\n config: AsrConfig;\n markers: RecordingMarker[];\n recordingName: string;\n durationSec: number;\n createdAt: string;\n transcriptsDir: string;\n transcriptDataDir: string;\n summariesDir: string;\n recordingId: string;\n logger: Logger;\n}): Promise<{\n ok: boolean;\n transcriptFilename?: string;\n transcriptDataFilename?: string;\n summaryFilename?: string;\n transcript?: RecordingTranscriptItem[];\n summary?: string;\n title?: string;\n error?: string;\n}> {\n const {\n audioFilePath,\n audioOssUrl,\n config,\n markers,\n recordingName,\n durationSec,\n createdAt,\n transcriptsDir,\n transcriptDataDir,\n summariesDir,\n recordingId,\n logger,\n } = params;\n\n // 1. ASR 转写\n const result = await transcribeAudio(audioFilePath, config, logger, {\n audioOssUrl,\n audioDurationMs: Math.max(0, Math.round(durationSec * 1000)),\n });\n if (!result.ok) {\n return { ok: false, error: result.error };\n }\n\n // 2. 提取摘要\n const title = normalizeOptionalText(result.summary)\n ? normalizeOptionalText(result.summary)!\n : extractSummary(result.text ?? \"\");\n const summary = result.summaryText ?? \"\";\n result.summary = title;\n const transcriptData = buildTranscriptDocument({\n recordingId,\n generatedAt: new Date().toISOString(),\n source: result.sourceInfo ?? {\n provider: config.mode === \"api\" ? \"model-proxy\" : config.mode,\n },\n title,\n category: result.category,\n summary,\n text: result.text,\n segments: (result.segments ?? []).map((segment) => ({\n text: segment.text,\n startMs: segment.start_ms,\n endMs: segment.end_ms,\n speakerId: segment.speaker_id,\n })),\n raw: result.rawResponse,\n });\n\n // 3. 生成 Markdown\n const markdown = buildTranscriptMarkdown(\n result,\n markers,\n recordingName,\n durationSec,\n createdAt,\n );\n\n // 4. 写入文件\n const transcriptDataFilename = buildTranscriptDataFilename(recordingId);\n const transcriptDataPath = join(transcriptDataDir, transcriptDataFilename);\n writeFileSync(\n transcriptDataPath,\n JSON.stringify(transcriptData, null, 2),\n \"utf-8\",\n );\n logger.info(`[asr] 转写 JSON 已写入: ${transcriptDataPath}`);\n\n const safeSummary = title\n .replace(/[/\\\\:*?\"<>|]/g, \"\")\n .trim()\n .slice(0, 20);\n const filename = safeSummary\n ? `${recordingId}_${safeSummary}.md`\n : `${recordingId}.md`;\n const filePath = join(transcriptsDir, filename);\n writeFileSync(filePath, markdown, \"utf-8\");\n logger.info(`[asr] 转写文本已写入: ${filePath}`);\n\n let summaryFilename: string | undefined;\n if (summary) {\n summaryFilename = `${recordingId}.md`;\n const summaryFilePath = join(summariesDir, summaryFilename);\n writeFileSync(summaryFilePath, summary, \"utf-8\");\n logger.info(`[asr] 摘要文本已写入: ${summaryFilePath}`);\n }\n\n return {\n ok: true,\n transcriptFilename: filename,\n transcriptDataFilename,\n summaryFilename,\n transcript: extractSourceTextListFromDocument(transcriptData),\n summary,\n title,\n };\n}\n\n// ─── ASR Provider Implementations ───\n\n/**\n * 通过 model-proxy 的长录音接口执行云端转写。\n */\nasync function transcribeWithModelProxy(\n audioOssUrl: string | undefined,\n audioDurationMs: number | undefined,\n apiConfig: AsrApiConfig | undefined,\n logger: Logger,\n): Promise<TranscriptionResult> {\n const normalizedAudioOssUrl = normalizeOptionalText(audioOssUrl);\n if (!normalizedAudioOssUrl) {\n return { ok: false, error: \"API 模式缺少 audioOssUrl,无法调用 model-proxy\" };\n }\n\n const apiKey = resolveModelProxyApiKey(apiConfig);\n const submitEndpoint = resolveModelProxyLongRecordingSubmitEndpoint(apiConfig);\n const submitBody = buildLongRecordingSubmitRequest(normalizedAudioOssUrl, apiConfig);\n\n logger.info(\n `[asr-submit] 提交长录音任务: endpoint=${submitEndpoint}, body=${stringifyForLog(submitBody) ?? \"{}\"}`,\n );\n\n let res: Response;\n try {\n res = await fetchWithRetry(\n submitEndpoint,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Api-Key-Id\": apiKey,\n },\n body: JSON.stringify(submitBody),\n },\n { logger, context: \"asr-submit\" },\n );\n } catch (err: any) {\n const msg = err?.message ?? String(err);\n logger.error(`[asr-submit] 提交长录音任务网络异常 (已重试): ${msg}`);\n return {\n ok: false,\n error: `Model Proxy ASR submit network error: ${msg}`,\n };\n }\n\n if (!res.ok) {\n const errText = await res.text();\n logger.error(\n `[asr-submit-response] 提交长录音任务失败: status=${res.status}, body=${errText.slice(0, 500)}`,\n );\n return {\n ok: false,\n error: `Model Proxy ASR error: ${res.status} ${errText.slice(0, 200)}`,\n };\n }\n\n const raw = (await res.json()) as\n | ModelProxyLongRecordingStatusResponse\n | ResponseEnvelope<ModelProxyLongRecordingStatusResponse>;\n logger.info(\n `[asr-submit-response] 提交长录音任务响应: ${stringifyForLog(raw) ?? \"{}\"}`,\n );\n const submitEnvelopeError = buildModelProxyEnvelopeError(raw);\n if (submitEnvelopeError) {\n logger.error(\n `[asr-submit-response] 提交长录音任务失败: ${submitEnvelopeError}`,\n );\n return {\n ok: false,\n error: `Model Proxy ASR 提交失败: ${submitEnvelopeError}`,\n };\n }\n\n const data = unwrapResponse(raw);\n const taskId = normalizeOptionalText(data?.taskId);\n const requestId = normalizeOptionalText(data?.requestId);\n const status = normalizeLongRecordingStatus(data?.status);\n\n if (!taskId) {\n return {\n ok: false,\n error: \"Model Proxy ASR 响应缺少 taskId\",\n };\n }\n\n logger.info(\n `[asr] Model Proxy 长录音任务已提交: taskId=${taskId}, status=${status ?? \"UNKNOWN\"}, requestId=${requestId ?? \"n/a\"}`,\n );\n\n if (status && LONG_RECORDING_TERMINAL_FAILURE_STATUSES.has(status)) {\n return {\n ok: false,\n error: buildLongRecordingStatusError(data, status),\n };\n }\n\n return await pollLongRecordingTaskResult({\n apiKey,\n taskId,\n initialRequestId: requestId,\n audioDurationMs,\n apiConfig,\n logger,\n });\n}\n\n/**\n * 本地 Whisper 转写(§6.4 — 内置 whisper.cpp 推理)\n */\nasync function transcribeWithWhisperLocal(\n audioFilePath: string,\n config: AsrConfig,\n logger: Logger,\n): Promise<TranscriptionResult> {\n const { transcribeWithWhisperLocal: runLocal } = await import(\"./whisper-local.js\");\n\n // 解析插件数据目录(与模型/二进制存放位置)\n // 优先使用环境变量指定的目录,否则使用音频文件所在目录的上两级(recordings 的父目录)\n const dataDir =\n process.env.OPENCLAW_STATE_DIR ??\n process.env.QCLAW_STATE_DIR ??\n join(audioFilePath, \"..\", \"..\", \"..\");\n\n const localConfig = config.local ?? {};\n\n const result = await runLocal(\n audioFilePath,\n localConfig,\n dataDir,\n logger,\n );\n\n if (result.ok && result.text) {\n const { extractSummary: extract } = await import(\"./asr.js\");\n result.summary = extract(result.text);\n result.sourceInfo = {\n provider: \"whisper-local\",\n status: \"SUCCEEDED\",\n };\n }\n\n return result;\n}\n\n// ─── Helpers ───\n\nfunction resolveModelProxyLongRecordingSubmitEndpoint(apiConfig?: AsrApiConfig): string {\n return apiConfig?.endpoint?.trim() || getEnvUrls().modelProxyLongRecordingSubmitTaskUrl;\n}\n\nfunction resolveModelProxyApiKey(apiConfig?: AsrApiConfig): string {\n const requestApiKey = normalizeOptionalText(apiConfig?.apiKey);\n return normalizeApiKeyHeaderValue(requestApiKey ?? requireApiKey());\n}\n\nfunction resolveModelProxyLongRecordingQueryTaskResultBaseUrl(\n apiConfig?: AsrApiConfig,\n): string {\n const customEndpoint = apiConfig?.endpoint?.trim();\n if (customEndpoint) {\n return deriveLongRecordingQueryTaskResultBaseUrl(customEndpoint);\n }\n return getEnvUrls().modelProxyLongRecordingQueryTaskResultBaseUrl;\n}\n\nfunction deriveLongRecordingQueryTaskResultBaseUrl(endpoint: string): string {\n const trimmed = endpoint.replace(/\\/+$/, \"\");\n if (trimmed.endsWith(\"/submit-task\")) {\n return `${trimmed.slice(0, -\"/submit-task\".length)}/query-task-result`;\n }\n return trimmed;\n}\n\nfunction buildLongRecordingSubmitRequest(\n audioOssUrl: string,\n apiConfig?: AsrApiConfig,\n): ModelProxyLongRecordingSubmitRequest {\n const body: ModelProxyLongRecordingSubmitRequest = {\n audioOssUrl,\n };\n\n if (apiConfig?.language?.trim()) {\n body.language = apiConfig.language.trim();\n }\n if (typeof apiConfig?.enableNormalization === \"boolean\") {\n body.enableNormalization = apiConfig.enableNormalization;\n }\n\n return body;\n}\n\nasync function pollLongRecordingTaskResult(params: {\n apiKey: string;\n taskId: string;\n initialRequestId?: string;\n audioDurationMs?: number;\n apiConfig?: AsrApiConfig;\n logger: Logger;\n}): Promise<TranscriptionResult> {\n const {\n apiKey,\n taskId,\n initialRequestId,\n audioDurationMs,\n apiConfig,\n logger,\n } = params;\n const queryBaseUrl = resolveModelProxyLongRecordingQueryTaskResultBaseUrl(apiConfig);\n let lastStatus: string | undefined;\n\n const pollIntervalMs = getPollIntervalMs();\n\n for (let attempt = 1; attempt <= DEFAULT_LONG_RECORDING_MAX_POLL_ATTEMPTS; attempt++) {\n const queryUrl = `${queryBaseUrl}/${encodeURIComponent(taskId)}`;\n let res: Response;\n try {\n res = await fetch(queryUrl, {\n method: \"GET\",\n headers: {\n \"X-Api-Key-Id\": apiKey,\n },\n });\n } catch (err: any) {\n const msg = err?.message ?? String(err);\n logger.warn(\n `[asr-query] 长录音任务查询网络异常: taskId=${taskId}, attempt=${attempt}, error=${msg} — 等待下次轮询`,\n );\n if (attempt < DEFAULT_LONG_RECORDING_MAX_POLL_ATTEMPTS) {\n await sleep(pollIntervalMs);\n continue;\n }\n return {\n ok: false,\n error: `Model Proxy ASR query network error: ${msg}`,\n };\n }\n\n if (!res.ok) {\n const errText = await res.text().catch(() => \"\");\n if (isRetryableHttpStatus(res.status)) {\n logger.warn(\n `[asr-query] 长录音任务查询暂时失败: taskId=${taskId}, attempt=${attempt}, status=${res.status}, body=${errText.slice(0, 200)} — 等待下次轮询`,\n );\n if (attempt < DEFAULT_LONG_RECORDING_MAX_POLL_ATTEMPTS) {\n await sleep(pollIntervalMs);\n continue;\n }\n } else {\n logger.error(\n `[asr-query-response] 长录音任务查询失败: taskId=${taskId}, attempt=${attempt}, status=${res.status}, body=${errText.slice(0, 500)}`,\n );\n }\n return {\n ok: false,\n error: `Model Proxy ASR query error: ${res.status} ${errText.slice(0, 200)}`,\n };\n }\n\n const raw = (await res.json()) as\n | ModelProxyLongRecordingStatusResponse\n | ResponseEnvelope<ModelProxyLongRecordingStatusResponse>;\n const queryEnvelopeError = buildModelProxyEnvelopeError(raw);\n if (queryEnvelopeError) {\n logger.error(\n `[asr-query-response] 长录音任务查询失败: taskId=${taskId}, attempt=${attempt}, ${queryEnvelopeError}`,\n );\n return {\n ok: false,\n error: `Model Proxy ASR 查询失败: ${queryEnvelopeError}`,\n };\n }\n\n const data = unwrapResponse(raw);\n const status = normalizeLongRecordingStatus(data?.status) ?? \"UNKNOWN\";\n const requestId = normalizeOptionalText(data?.requestId) ?? initialRequestId;\n\n if (status !== lastStatus) {\n logger.info(\n `[asr-query-response] 长录音任务查询响应: taskId=${taskId}, attempt=${attempt}, body=${stringifyForLog(raw) ?? \"{}\"}`,\n );\n logger.info(\n `[asr] Model Proxy 长录音任务状态: taskId=${taskId}, status=${status}, attempt=${attempt}, requestId=${requestId ?? \"n/a\"}`,\n );\n lastStatus = status;\n }\n\n if (status === \"SUCCEEDED\") {\n return buildLongRecordingSuccessResult(\n taskId,\n requestId,\n data,\n audioDurationMs,\n logger,\n );\n }\n\n if (LONG_RECORDING_TERMINAL_FAILURE_STATUSES.has(status)) {\n return {\n ok: false,\n error: buildLongRecordingStatusError(data, status),\n };\n }\n\n if (!LONG_RECORDING_RUNNING_STATUSES.has(status)) {\n return {\n ok: false,\n error: `Model Proxy ASR 返回未知任务状态: ${status}`,\n };\n }\n\n if (attempt < DEFAULT_LONG_RECORDING_MAX_POLL_ATTEMPTS) {\n await sleep(pollIntervalMs);\n }\n }\n\n return {\n ok: false,\n error:\n `Model Proxy ASR 轮询超时: taskId=${taskId}, waited=${DEFAULT_LONG_RECORDING_MAX_POLL_ATTEMPTS * pollIntervalMs}ms`,\n };\n}\n\nfunction buildLongRecordingSuccessResult(\n taskId: string,\n requestId: string | undefined,\n data: ModelProxyLongRecordingStatusResponse | undefined,\n audioDurationMs: number | undefined,\n logger: Logger,\n): TranscriptionResult {\n const sourceTextList = normalizeLongRecordingSourceTextList(\n data?.recordResult?.sourceTextList,\n );\n const listResult = extractLongRecordingTextFromList(sourceTextList, audioDurationMs);\n const sourceText = normalizeOptionalText(data?.recordResult?.sourceText);\n const summaryText = normalizeOptionalText(data?.recordResult?.summaryResult) ?? \"\";\n const title = normalizeOptionalText(data?.recordResult?.title);\n const category = normalizeOptionalText(data?.recordResult?.category);\n const text = listResult.text ?? sourceText ?? summaryText;\n const status = normalizeLongRecordingStatus(data?.status) ?? \"SUCCEEDED\";\n\n if (!listResult.text && !sourceText && summaryText) {\n logger.warn(\n `[asr] Model Proxy 长录音结果缺少 sourceTextList/sourceText,已回退使用 summaryResult 作为转写文本: taskId=${taskId}`,\n );\n }\n\n logger.info(\n `[asr] Model Proxy 长录音转写完成: taskId=${taskId}, requestId=${requestId ?? \"n/a\"}, chars=${text.length}`,\n );\n\n return {\n ok: true,\n text,\n segments: listResult.segments,\n summary: title,\n summaryText,\n category,\n sourceInfo: {\n provider: \"model-proxy\",\n taskId,\n requestId,\n status,\n },\n rawResponse: data,\n };\n}\n\nfunction buildLongRecordingStatusError(\n data: ModelProxyLongRecordingStatusResponse | undefined,\n status: string,\n): string {\n const errorMessage = normalizeOptionalText(data?.errorMessage);\n return errorMessage\n ? `Model Proxy ASR ${status}: ${errorMessage}`\n : `Model Proxy ASR ${status}`;\n}\n\nfunction buildModelProxyEnvelopeError(\n payload:\n | ModelProxyLongRecordingStatusResponse\n | ResponseEnvelope<ModelProxyLongRecordingStatusResponse>,\n): string | undefined {\n if (!payload || typeof payload !== \"object\" || !(\"data\" in payload)) {\n return undefined;\n }\n\n const envelope = payload as ResponseEnvelope<ModelProxyLongRecordingStatusResponse>;\n const explicitFailure = envelope.success === false;\n const message = normalizeOptionalText(envelope.message);\n if (!explicitFailure && (!message || envelope.data)) {\n return undefined;\n }\n\n const code = normalizeOptionalCode(envelope.code);\n if (code && message) {\n return `${code} ${message}`;\n }\n return message ?? code ?? \"response envelope indicates failure\";\n}\n\nfunction unwrapResponse(\n payload:\n | ModelProxyLongRecordingStatusResponse\n | ResponseEnvelope<ModelProxyLongRecordingStatusResponse>,\n): ModelProxyLongRecordingStatusResponse | undefined {\n if (\n payload &&\n typeof payload === \"object\" &&\n \"data\" in payload &&\n payload.data &&\n typeof payload.data === \"object\"\n ) {\n return payload.data;\n }\n\n return payload as ModelProxyLongRecordingStatusResponse;\n}\n\nfunction normalizeApiKeyHeaderValue(apiKey: string): string {\n return apiKey.startsWith(\"Bearer \")\n ? apiKey.slice(\"Bearer \".length)\n : apiKey;\n}\n\nfunction normalizeLongRecordingStatus(status: unknown): string | undefined {\n return typeof status === \"string\" && status.trim()\n ? status.trim().toUpperCase()\n : undefined;\n}\n\nfunction normalizeOptionalText(value: unknown): string | undefined {\n return typeof value === \"string\" && value.trim()\n ? value.trim()\n : undefined;\n}\n\nfunction normalizeOptionalCode(value: unknown): string | undefined {\n if (typeof value === \"string\" && value.trim()) {\n return value.trim();\n }\n if (typeof value === \"number\" && Number.isFinite(value)) {\n return String(value);\n }\n return undefined;\n}\n\nfunction normalizeOptionalInteger(value: unknown): number | undefined {\n return Number.isInteger(value)\n ? Number(value)\n : undefined;\n}\n\nfunction normalizeOptionalNonNegativeNumber(value: unknown): number | undefined {\n return typeof value === \"number\" && Number.isFinite(value) && value >= 0\n ? value\n : undefined;\n}\n\nfunction normalizeLongRecordingSourceTextList(\n value: unknown,\n): Array<{\n content: string;\n speakerId?: number;\n startTime?: number;\n endTime?: number;\n}> {\n if (!Array.isArray(value)) {\n return [];\n }\n\n return value\n .flatMap((item) => {\n if (!item || typeof item !== \"object\") {\n return [];\n }\n\n const record = item as Record<string, unknown>;\n const content = normalizeOptionalText(record.content);\n if (!content) {\n return [];\n }\n\n return [{\n content,\n speakerId: normalizeOptionalInteger(record.speakerId),\n startTime: normalizeOptionalNonNegativeNumber(record.startTime),\n endTime: normalizeOptionalNonNegativeNumber(record.endTime),\n }];\n });\n}\n\nfunction extractLongRecordingTextFromList(\n items: Array<{\n content: string;\n speakerId?: number;\n startTime?: number;\n endTime?: number;\n }>,\n finalFallbackEndMs?: number,\n): {\n text?: string;\n segments: TranscriptSegment[];\n} {\n if (items.length === 0) {\n return {\n segments: [],\n };\n }\n\n const segments = items.map((item, index) => {\n const startMs = item.startTime ?? 0;\n const explicitEndMs = item.endTime;\n const nextStart = items[index + 1]?.startTime;\n const fallbackEndMs = index === items.length - 1\n ? normalizeOptionalNonNegativeNumber(finalFallbackEndMs)\n : undefined;\n const endMs = explicitEndMs ?? nextStart ?? fallbackEndMs ?? startMs;\n\n return {\n start_ms: startMs,\n end_ms: Math.max(startMs, endMs),\n text: item.content,\n speaker_id: item.speakerId,\n };\n });\n\n return {\n text: items.map((item) => item.content).join(\"\\n\\n\"),\n segments,\n };\n}\n\nfunction stringifyForLog(value: unknown, maxLength = 500): string | undefined {\n if (value == null) {\n return undefined;\n }\n\n if (typeof value === \"string\") {\n const trimmed = value.trim();\n return trimmed ? trimmed.slice(0, maxLength) : undefined;\n }\n\n try {\n const serialized = JSON.stringify(value);\n return serialized ? serialized.slice(0, maxLength) : undefined;\n } catch {\n return String(value).slice(0, maxLength);\n }\n}\n\nasync function sleep(ms: number): Promise<void> {\n await new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction isRetryableHttpStatus(status: number): boolean {\n return status === 429 || status >= 500;\n}\n\nfunction getHttpRetryBackoffMs(): number {\n const raw = process.env.OPENCLAW_ASR_HTTP_RETRY_BACKOFF_MS;\n if (raw) {\n const parsed = Number(raw);\n if (Number.isFinite(parsed) && parsed >= 0) {\n return parsed;\n }\n }\n return DEFAULT_HTTP_RETRY_BACKOFF_MS;\n}\n\nfunction getPollIntervalMs(): number {\n const raw = process.env.OPENCLAW_ASR_POLL_INTERVAL_MS;\n if (raw) {\n const parsed = Number(raw);\n if (Number.isFinite(parsed) && parsed >= 0) {\n return parsed;\n }\n }\n return DEFAULT_LONG_RECORDING_POLL_INTERVAL_MS;\n}\n\n/**\n * 带重试的 fetch 包装:\n * - HTTP 5xx / 429:按指数退避重试\n * - 网络异常(fetch throw):按指数退避重试\n * - HTTP 4xx(除 429)/ 2xx / 3xx:直接返回,由调用方处理\n *\n * 用于 ASR submit 这类一次性请求;polling 走自己的节奏,无需此包装。\n */\nasync function fetchWithRetry(\n url: string,\n init: RequestInit,\n options: {\n logger: Logger;\n context: string;\n maxAttempts?: number;\n backoffMs?: number;\n },\n): Promise<Response> {\n const maxAttempts = options.maxAttempts ?? DEFAULT_HTTP_MAX_ATTEMPTS;\n const baseBackoff = options.backoffMs ?? getHttpRetryBackoffMs();\n let lastError: unknown;\n\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n try {\n const res = await fetch(url, init);\n if (isRetryableHttpStatus(res.status) && attempt < maxAttempts) {\n const errText = await res.text().catch(() => \"\");\n const delay = baseBackoff * Math.pow(2, attempt - 1);\n options.logger.warn(\n `[${options.context}] HTTP ${res.status} (attempt ${attempt}/${maxAttempts}), ${delay}ms 后重试, body=${errText.slice(0, 200)}`,\n );\n await sleep(delay);\n continue;\n }\n return res;\n } catch (err) {\n lastError = err;\n if (attempt < maxAttempts) {\n const delay = baseBackoff * Math.pow(2, attempt - 1);\n const msg = (err as any)?.message ?? String(err);\n options.logger.warn(\n `[${options.context}] 网络异常 (attempt ${attempt}/${maxAttempts}): ${msg}, ${delay}ms 后重试`,\n );\n await sleep(delay);\n continue;\n }\n }\n }\n\n throw lastError instanceof Error ? lastError : new Error(String(lastError));\n}\n\nfunction extractTranscriptSummary(text: string): string {\n const normalized = text.replace(/\\s+/g, \" \").trim();\n if (!normalized) {\n return \"\";\n }\n\n const sentence = normalized\n .split(/[。!?!?]/)\n .map((part) => part.trim())\n .find((part) => part.length > 0);\n\n const candidate = sentence || normalized;\n return candidate.length <= 120\n ? candidate\n : `${candidate.slice(0, 117).trimEnd()}...`;\n}\n/** 毫秒 → \"MM:SS\" */\nfunction formatTimestamp(ms: number): string {\n const totalSeconds = Math.floor(ms / 1000);\n const minutes = Math.floor(totalSeconds / 60);\n const seconds = totalSeconds % 60;\n return `${String(minutes).padStart(2, \"0\")}:${String(seconds).padStart(2, \"0\")}`;\n}\n\n/** 秒 → \"HH:MM:SS\" 或 \"MM:SS\" */\nfunction formatDuration(seconds: number): string {\n const h = Math.floor(seconds / 3600);\n const m = Math.floor((seconds % 3600) / 60);\n const s = Math.floor(seconds % 60);\n if (h > 0) {\n return `${h}:${String(m).padStart(2, \"0\")}:${String(s).padStart(2, \"0\")}`;\n }\n return `${String(m).padStart(2, \"0\")}:${String(s).padStart(2, \"0\")}`;\n}\n\nfunction hasText(value: unknown): boolean {\n return typeof value === \"string\" && value.trim().length > 0;\n}\n\nfunction formatTranscriptSegmentText(segment: TranscriptSegment): string {\n const text = segment.text.trim();\n if (!text) {\n return text;\n }\n\n if (typeof segment.speaker_id === \"number\") {\n return `说话人${segment.speaker_id}:${text}`;\n }\n\n return text;\n}\n","'use strict';\n\nconst BINARY_TYPES = ['nodebuffer', 'arraybuffer', 'fragments'];\nconst hasBlob = typeof Blob !== 'undefined';\n\nif (hasBlob) BINARY_TYPES.push('blob');\n\nmodule.exports = {\n BINARY_TYPES,\n CLOSE_TIMEOUT: 30000,\n EMPTY_BUFFER: Buffer.alloc(0),\n GUID: '258EAFA5-E914-47DA-95CA-C5AB0DC85B11',\n hasBlob,\n kForOnEventAttribute: Symbol('kIsForOnEventAttribute'),\n kListener: Symbol('kListener'),\n kStatusCode: Symbol('status-code'),\n kWebSocket: Symbol('websocket'),\n NOOP: () => {}\n};\n","'use strict';\n\nconst { EMPTY_BUFFER } = require('./constants');\n\nconst FastBuffer = Buffer[Symbol.species];\n\n/**\n * Merges an array of buffers into a new buffer.\n *\n * @param {Buffer[]} list The array of buffers to concat\n * @param {Number} totalLength The total length of buffers in the list\n * @return {Buffer} The resulting buffer\n * @public\n */\nfunction concat(list, totalLength) {\n if (list.length === 0) return EMPTY_BUFFER;\n if (list.length === 1) return list[0];\n\n const target = Buffer.allocUnsafe(totalLength);\n let offset = 0;\n\n for (let i = 0; i < list.length; i++) {\n const buf = list[i];\n target.set(buf, offset);\n offset += buf.length;\n }\n\n if (offset < totalLength) {\n return new FastBuffer(target.buffer, target.byteOffset, offset);\n }\n\n return target;\n}\n\n/**\n * Masks a buffer using the given mask.\n *\n * @param {Buffer} source The buffer to mask\n * @param {Buffer} mask The mask to use\n * @param {Buffer} output The buffer where to store the result\n * @param {Number} offset The offset at which to start writing\n * @param {Number} length The number of bytes to mask.\n * @public\n */\nfunction _mask(source, mask, output, offset, length) {\n for (let i = 0; i < length; i++) {\n output[offset + i] = source[i] ^ mask[i & 3];\n }\n}\n\n/**\n * Unmasks a buffer using the given mask.\n *\n * @param {Buffer} buffer The buffer to unmask\n * @param {Buffer} mask The mask to use\n * @public\n */\nfunction _unmask(buffer, mask) {\n for (let i = 0; i < buffer.length; i++) {\n buffer[i] ^= mask[i & 3];\n }\n}\n\n/**\n * Converts a buffer to an `ArrayBuffer`.\n *\n * @param {Buffer} buf The buffer to convert\n * @return {ArrayBuffer} Converted buffer\n * @public\n */\nfunction toArrayBuffer(buf) {\n if (buf.length === buf.buffer.byteLength) {\n return buf.buffer;\n }\n\n return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.length);\n}\n\n/**\n * Converts `data` to a `Buffer`.\n *\n * @param {*} data The data to convert\n * @return {Buffer} The buffer\n * @throws {TypeError}\n * @public\n */\nfunction toBuffer(data) {\n toBuffer.readOnly = true;\n\n if (Buffer.isBuffer(data)) return data;\n\n let buf;\n\n if (data instanceof ArrayBuffer) {\n buf = new FastBuffer(data);\n } else if (ArrayBuffer.isView(data)) {\n buf = new FastBuffer(data.buffer, data.byteOffset, data.byteLength);\n } else {\n buf = Buffer.from(data);\n toBuffer.readOnly = false;\n }\n\n return buf;\n}\n\nmodule.exports = {\n concat,\n mask: _mask,\n toArrayBuffer,\n toBuffer,\n unmask: _unmask\n};\n\n/* istanbul ignore else */\nif (!process.env.WS_NO_BUFFER_UTIL) {\n try {\n const bufferUtil = require('bufferutil');\n\n module.exports.mask = function (source, mask, output, offset, length) {\n if (length < 48) _mask(source, mask, output, offset, length);\n else bufferUtil.mask(source, mask, output, offset, length);\n };\n\n module.exports.unmask = function (buffer, mask) {\n if (buffer.length < 32) _unmask(buffer, mask);\n else bufferUtil.unmask(buffer, mask);\n };\n } catch (e) {\n // Continue regardless of the error.\n }\n}\n","'use strict';\n\nconst kDone = Symbol('kDone');\nconst kRun = Symbol('kRun');\n\n/**\n * A very simple job queue with adjustable concurrency. Adapted from\n * https://github.com/STRML/async-limiter\n */\nclass Limiter {\n /**\n * Creates a new `Limiter`.\n *\n * @param {Number} [concurrency=Infinity] The maximum number of jobs allowed\n * to run concurrently\n */\n constructor(concurrency) {\n this[kDone] = () => {\n this.pending--;\n this[kRun]();\n };\n this.concurrency = concurrency || Infinity;\n this.jobs = [];\n this.pending = 0;\n }\n\n /**\n * Adds a job to the queue.\n *\n * @param {Function} job The job to run\n * @public\n */\n add(job) {\n this.jobs.push(job);\n this[kRun]();\n }\n\n /**\n * Removes a job from the queue and runs it if possible.\n *\n * @private\n */\n [kRun]() {\n if (this.pending === this.concurrency) return;\n\n if (this.jobs.length) {\n const job = this.jobs.shift();\n\n this.pending++;\n job(this[kDone]);\n }\n }\n}\n\nmodule.exports = Limiter;\n","'use strict';\n\nconst zlib = require('zlib');\n\nconst bufferUtil = require('./buffer-util');\nconst Limiter = require('./limiter');\nconst { kStatusCode } = require('./constants');\n\nconst FastBuffer = Buffer[Symbol.species];\nconst TRAILER = Buffer.from([0x00, 0x00, 0xff, 0xff]);\nconst kPerMessageDeflate = Symbol('permessage-deflate');\nconst kTotalLength = Symbol('total-length');\nconst kCallback = Symbol('callback');\nconst kBuffers = Symbol('buffers');\nconst kError = Symbol('error');\n\n//\n// We limit zlib concurrency, which prevents severe memory fragmentation\n// as documented in https://github.com/nodejs/node/issues/8871#issuecomment-250915913\n// and https://github.com/websockets/ws/issues/1202\n//\n// Intentionally global; it's the global thread pool that's an issue.\n//\nlet zlibLimiter;\n\n/**\n * permessage-deflate implementation.\n */\nclass PerMessageDeflate {\n /**\n * Creates a PerMessageDeflate instance.\n *\n * @param {Object} [options] Configuration options\n * @param {(Boolean|Number)} [options.clientMaxWindowBits] Advertise support\n * for, or request, a custom client window size\n * @param {Boolean} [options.clientNoContextTakeover=false] Advertise/\n * acknowledge disabling of client context takeover\n * @param {Number} [options.concurrencyLimit=10] The number of concurrent\n * calls to zlib\n * @param {(Boolean|Number)} [options.serverMaxWindowBits] Request/confirm the\n * use of a custom server window size\n * @param {Boolean} [options.serverNoContextTakeover=false] Request/accept\n * disabling of server context takeover\n * @param {Number} [options.threshold=1024] Size (in bytes) below which\n * messages should not be compressed if context takeover is disabled\n * @param {Object} [options.zlibDeflateOptions] Options to pass to zlib on\n * deflate\n * @param {Object} [options.zlibInflateOptions] Options to pass to zlib on\n * inflate\n * @param {Boolean} [isServer=false] Create the instance in either server or\n * client mode\n * @param {Number} [maxPayload=0] The maximum allowed message length\n */\n constructor(options, isServer, maxPayload) {\n this._maxPayload = maxPayload | 0;\n this._options = options || {};\n this._threshold =\n this._options.threshold !== undefined ? this._options.threshold : 1024;\n this._isServer = !!isServer;\n this._deflate = null;\n this._inflate = null;\n\n this.params = null;\n\n if (!zlibLimiter) {\n const concurrency =\n this._options.concurrencyLimit !== undefined\n ? this._options.concurrencyLimit\n : 10;\n zlibLimiter = new Limiter(concurrency);\n }\n }\n\n /**\n * @type {String}\n */\n static get extensionName() {\n return 'permessage-deflate';\n }\n\n /**\n * Create an extension negotiation offer.\n *\n * @return {Object} Extension parameters\n * @public\n */\n offer() {\n const params = {};\n\n if (this._options.serverNoContextTakeover) {\n params.server_no_context_takeover = true;\n }\n if (this._options.clientNoContextTakeover) {\n params.client_no_context_takeover = true;\n }\n if (this._options.serverMaxWindowBits) {\n params.server_max_window_bits = this._options.serverMaxWindowBits;\n }\n if (this._options.clientMaxWindowBits) {\n params.client_max_window_bits = this._options.clientMaxWindowBits;\n } else if (this._options.clientMaxWindowBits == null) {\n params.client_max_window_bits = true;\n }\n\n return params;\n }\n\n /**\n * Accept an extension negotiation offer/response.\n *\n * @param {Array} configurations The extension negotiation offers/reponse\n * @return {Object} Accepted configuration\n * @public\n */\n accept(configurations) {\n configurations = this.normalizeParams(configurations);\n\n this.params = this._isServer\n ? this.acceptAsServer(configurations)\n : this.acceptAsClient(configurations);\n\n return this.params;\n }\n\n /**\n * Releases all resources used by the extension.\n *\n * @public\n */\n cleanup() {\n if (this._inflate) {\n this._inflate.close();\n this._inflate = null;\n }\n\n if (this._deflate) {\n const callback = this._deflate[kCallback];\n\n this._deflate.close();\n this._deflate = null;\n\n if (callback) {\n callback(\n new Error(\n 'The deflate stream was closed while data was being processed'\n )\n );\n }\n }\n }\n\n /**\n * Accept an extension negotiation offer.\n *\n * @param {Array} offers The extension negotiation offers\n * @return {Object} Accepted configuration\n * @private\n */\n acceptAsServer(offers) {\n const opts = this._options;\n const accepted = offers.find((params) => {\n if (\n (opts.serverNoContextTakeover === false &&\n params.server_no_context_takeover) ||\n (params.server_max_window_bits &&\n (opts.serverMaxWindowBits === false ||\n (typeof opts.serverMaxWindowBits === 'number' &&\n opts.serverMaxWindowBits > params.server_max_window_bits))) ||\n (typeof opts.clientMaxWindowBits === 'number' &&\n !params.client_max_window_bits)\n ) {\n return false;\n }\n\n return true;\n });\n\n if (!accepted) {\n throw new Error('None of the extension offers can be accepted');\n }\n\n if (opts.serverNoContextTakeover) {\n accepted.server_no_context_takeover = true;\n }\n if (opts.clientNoContextTakeover) {\n accepted.client_no_context_takeover = true;\n }\n if (typeof opts.serverMaxWindowBits === 'number') {\n accepted.server_max_window_bits = opts.serverMaxWindowBits;\n }\n if (typeof opts.clientMaxWindowBits === 'number') {\n accepted.client_max_window_bits = opts.clientMaxWindowBits;\n } else if (\n accepted.client_max_window_bits === true ||\n opts.clientMaxWindowBits === false\n ) {\n delete accepted.client_max_window_bits;\n }\n\n return accepted;\n }\n\n /**\n * Accept the extension negotiation response.\n *\n * @param {Array} response The extension negotiation response\n * @return {Object} Accepted configuration\n * @private\n */\n acceptAsClient(response) {\n const params = response[0];\n\n if (\n this._options.clientNoContextTakeover === false &&\n params.client_no_context_takeover\n ) {\n throw new Error('Unexpected parameter \"client_no_context_takeover\"');\n }\n\n if (!params.client_max_window_bits) {\n if (typeof this._options.clientMaxWindowBits === 'number') {\n params.client_max_window_bits = this._options.clientMaxWindowBits;\n }\n } else if (\n this._options.clientMaxWindowBits === false ||\n (typeof this._options.clientMaxWindowBits === 'number' &&\n params.client_max_window_bits > this._options.clientMaxWindowBits)\n ) {\n throw new Error(\n 'Unexpected or invalid parameter \"client_max_window_bits\"'\n );\n }\n\n return params;\n }\n\n /**\n * Normalize parameters.\n *\n * @param {Array} configurations The extension negotiation offers/reponse\n * @return {Array} The offers/response with normalized parameters\n * @private\n */\n normalizeParams(configurations) {\n configurations.forEach((params) => {\n Object.keys(params).forEach((key) => {\n let value = params[key];\n\n if (value.length > 1) {\n throw new Error(`Parameter \"${key}\" must have only a single value`);\n }\n\n value = value[0];\n\n if (key === 'client_max_window_bits') {\n if (value !== true) {\n const num = +value;\n if (!Number.isInteger(num) || num < 8 || num > 15) {\n throw new TypeError(\n `Invalid value for parameter \"${key}\": ${value}`\n );\n }\n value = num;\n } else if (!this._isServer) {\n throw new TypeError(\n `Invalid value for parameter \"${key}\": ${value}`\n );\n }\n } else if (key === 'server_max_window_bits') {\n const num = +value;\n if (!Number.isInteger(num) || num < 8 || num > 15) {\n throw new TypeError(\n `Invalid value for parameter \"${key}\": ${value}`\n );\n }\n value = num;\n } else if (\n key === 'client_no_context_takeover' ||\n key === 'server_no_context_takeover'\n ) {\n if (value !== true) {\n throw new TypeError(\n `Invalid value for parameter \"${key}\": ${value}`\n );\n }\n } else {\n throw new Error(`Unknown parameter \"${key}\"`);\n }\n\n params[key] = value;\n });\n });\n\n return configurations;\n }\n\n /**\n * Decompress data. Concurrency limited.\n *\n * @param {Buffer} data Compressed data\n * @param {Boolean} fin Specifies whether or not this is the last fragment\n * @param {Function} callback Callback\n * @public\n */\n decompress(data, fin, callback) {\n zlibLimiter.add((done) => {\n this._decompress(data, fin, (err, result) => {\n done();\n callback(err, result);\n });\n });\n }\n\n /**\n * Compress data. Concurrency limited.\n *\n * @param {(Buffer|String)} data Data to compress\n * @param {Boolean} fin Specifies whether or not this is the last fragment\n * @param {Function} callback Callback\n * @public\n */\n compress(data, fin, callback) {\n zlibLimiter.add((done) => {\n this._compress(data, fin, (err, result) => {\n done();\n callback(err, result);\n });\n });\n }\n\n /**\n * Decompress data.\n *\n * @param {Buffer} data Compressed data\n * @param {Boolean} fin Specifies whether or not this is the last fragment\n * @param {Function} callback Callback\n * @private\n */\n _decompress(data, fin, callback) {\n const endpoint = this._isServer ? 'client' : 'server';\n\n if (!this._inflate) {\n const key = `${endpoint}_max_window_bits`;\n const windowBits =\n typeof this.params[key] !== 'number'\n ? zlib.Z_DEFAULT_WINDOWBITS\n : this.params[key];\n\n this._inflate = zlib.createInflateRaw({\n ...this._options.zlibInflateOptions,\n windowBits\n });\n this._inflate[kPerMessageDeflate] = this;\n this._inflate[kTotalLength] = 0;\n this._inflate[kBuffers] = [];\n this._inflate.on('error', inflateOnError);\n this._inflate.on('data', inflateOnData);\n }\n\n this._inflate[kCallback] = callback;\n\n this._inflate.write(data);\n if (fin) this._inflate.write(TRAILER);\n\n this._inflate.flush(() => {\n const err = this._inflate[kError];\n\n if (err) {\n this._inflate.close();\n this._inflate = null;\n callback(err);\n return;\n }\n\n const data = bufferUtil.concat(\n this._inflate[kBuffers],\n this._inflate[kTotalLength]\n );\n\n if (this._inflate._readableState.endEmitted) {\n this._inflate.close();\n this._inflate = null;\n } else {\n this._inflate[kTotalLength] = 0;\n this._inflate[kBuffers] = [];\n\n if (fin && this.params[`${endpoint}_no_context_takeover`]) {\n this._inflate.reset();\n }\n }\n\n callback(null, data);\n });\n }\n\n /**\n * Compress data.\n *\n * @param {(Buffer|String)} data Data to compress\n * @param {Boolean} fin Specifies whether or not this is the last fragment\n * @param {Function} callback Callback\n * @private\n */\n _compress(data, fin, callback) {\n const endpoint = this._isServer ? 'server' : 'client';\n\n if (!this._deflate) {\n const key = `${endpoint}_max_window_bits`;\n const windowBits =\n typeof this.params[key] !== 'number'\n ? zlib.Z_DEFAULT_WINDOWBITS\n : this.params[key];\n\n this._deflate = zlib.createDeflateRaw({\n ...this._options.zlibDeflateOptions,\n windowBits\n });\n\n this._deflate[kTotalLength] = 0;\n this._deflate[kBuffers] = [];\n\n this._deflate.on('data', deflateOnData);\n }\n\n this._deflate[kCallback] = callback;\n\n this._deflate.write(data);\n this._deflate.flush(zlib.Z_SYNC_FLUSH, () => {\n if (!this._deflate) {\n //\n // The deflate stream was closed while data was being processed.\n //\n return;\n }\n\n let data = bufferUtil.concat(\n this._deflate[kBuffers],\n this._deflate[kTotalLength]\n );\n\n if (fin) {\n data = new FastBuffer(data.buffer, data.byteOffset, data.length - 4);\n }\n\n //\n // Ensure that the callback will not be called again in\n // `PerMessageDeflate#cleanup()`.\n //\n this._deflate[kCallback] = null;\n\n this._deflate[kTotalLength] = 0;\n this._deflate[kBuffers] = [];\n\n if (fin && this.params[`${endpoint}_no_context_takeover`]) {\n this._deflate.reset();\n }\n\n callback(null, data);\n });\n }\n}\n\nmodule.exports = PerMessageDeflate;\n\n/**\n * The listener of the `zlib.DeflateRaw` stream `'data'` event.\n *\n * @param {Buffer} chunk A chunk of data\n * @private\n */\nfunction deflateOnData(chunk) {\n this[kBuffers].push(chunk);\n this[kTotalLength] += chunk.length;\n}\n\n/**\n * The listener of the `zlib.InflateRaw` stream `'data'` event.\n *\n * @param {Buffer} chunk A chunk of data\n * @private\n */\nfunction inflateOnData(chunk) {\n this[kTotalLength] += chunk.length;\n\n if (\n this[kPerMessageDeflate]._maxPayload < 1 ||\n this[kTotalLength] <= this[kPerMessageDeflate]._maxPayload\n ) {\n this[kBuffers].push(chunk);\n return;\n }\n\n this[kError] = new RangeError('Max payload size exceeded');\n this[kError].code = 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH';\n this[kError][kStatusCode] = 1009;\n this.removeListener('data', inflateOnData);\n\n //\n // The choice to employ `zlib.reset()` over `zlib.close()` is dictated by the\n // fact that in Node.js versions prior to 13.10.0, the callback for\n // `zlib.flush()` is not called if `zlib.close()` is used. Utilizing\n // `zlib.reset()` ensures that either the callback is invoked or an error is\n // emitted.\n //\n this.reset();\n}\n\n/**\n * The listener of the `zlib.InflateRaw` stream `'error'` event.\n *\n * @param {Error} err The emitted error\n * @private\n */\nfunction inflateOnError(err) {\n //\n // There is no need to call `Zlib#close()` as the handle is automatically\n // closed when an error is emitted.\n //\n this[kPerMessageDeflate]._inflate = null;\n\n if (this[kError]) {\n this[kCallback](this[kError]);\n return;\n }\n\n err[kStatusCode] = 1007;\n this[kCallback](err);\n}\n","'use strict';\n\nconst { isUtf8 } = require('buffer');\n\nconst { hasBlob } = require('./constants');\n\n//\n// Allowed token characters:\n//\n// '!', '#', '$', '%', '&', ''', '*', '+', '-',\n// '.', 0-9, A-Z, '^', '_', '`', a-z, '|', '~'\n//\n// tokenChars[32] === 0 // ' '\n// tokenChars[33] === 1 // '!'\n// tokenChars[34] === 0 // '\"'\n// ...\n//\n// prettier-ignore\nconst tokenChars = [\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 15\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 31\n 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, // 32 - 47\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 48 - 63\n 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64 - 79\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, // 80 - 95\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96 - 111\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0 // 112 - 127\n];\n\n/**\n * Checks if a status code is allowed in a close frame.\n *\n * @param {Number} code The status code\n * @return {Boolean} `true` if the status code is valid, else `false`\n * @public\n */\nfunction isValidStatusCode(code) {\n return (\n (code >= 1000 &&\n code <= 1014 &&\n code !== 1004 &&\n code !== 1005 &&\n code !== 1006) ||\n (code >= 3000 && code <= 4999)\n );\n}\n\n/**\n * Checks if a given buffer contains only correct UTF-8.\n * Ported from https://www.cl.cam.ac.uk/%7Emgk25/ucs/utf8_check.c by\n * Markus Kuhn.\n *\n * @param {Buffer} buf The buffer to check\n * @return {Boolean} `true` if `buf` contains only correct UTF-8, else `false`\n * @public\n */\nfunction _isValidUTF8(buf) {\n const len = buf.length;\n let i = 0;\n\n while (i < len) {\n if ((buf[i] & 0x80) === 0) {\n // 0xxxxxxx\n i++;\n } else if ((buf[i] & 0xe0) === 0xc0) {\n // 110xxxxx 10xxxxxx\n if (\n i + 1 === len ||\n (buf[i + 1] & 0xc0) !== 0x80 ||\n (buf[i] & 0xfe) === 0xc0 // Overlong\n ) {\n return false;\n }\n\n i += 2;\n } else if ((buf[i] & 0xf0) === 0xe0) {\n // 1110xxxx 10xxxxxx 10xxxxxx\n if (\n i + 2 >= len ||\n (buf[i + 1] & 0xc0) !== 0x80 ||\n (buf[i + 2] & 0xc0) !== 0x80 ||\n (buf[i] === 0xe0 && (buf[i + 1] & 0xe0) === 0x80) || // Overlong\n (buf[i] === 0xed && (buf[i + 1] & 0xe0) === 0xa0) // Surrogate (U+D800 - U+DFFF)\n ) {\n return false;\n }\n\n i += 3;\n } else if ((buf[i] & 0xf8) === 0xf0) {\n // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx\n if (\n i + 3 >= len ||\n (buf[i + 1] & 0xc0) !== 0x80 ||\n (buf[i + 2] & 0xc0) !== 0x80 ||\n (buf[i + 3] & 0xc0) !== 0x80 ||\n (buf[i] === 0xf0 && (buf[i + 1] & 0xf0) === 0x80) || // Overlong\n (buf[i] === 0xf4 && buf[i + 1] > 0x8f) ||\n buf[i] > 0xf4 // > U+10FFFF\n ) {\n return false;\n }\n\n i += 4;\n } else {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * Determines whether a value is a `Blob`.\n *\n * @param {*} value The value to be tested\n * @return {Boolean} `true` if `value` is a `Blob`, else `false`\n * @private\n */\nfunction isBlob(value) {\n return (\n hasBlob &&\n typeof value === 'object' &&\n typeof value.arrayBuffer === 'function' &&\n typeof value.type === 'string' &&\n typeof value.stream === 'function' &&\n (value[Symbol.toStringTag] === 'Blob' ||\n value[Symbol.toStringTag] === 'File')\n );\n}\n\nmodule.exports = {\n isBlob,\n isValidStatusCode,\n isValidUTF8: _isValidUTF8,\n tokenChars\n};\n\nif (isUtf8) {\n module.exports.isValidUTF8 = function (buf) {\n return buf.length < 24 ? _isValidUTF8(buf) : isUtf8(buf);\n };\n} /* istanbul ignore else */ else if (!process.env.WS_NO_UTF_8_VALIDATE) {\n try {\n const isValidUTF8 = require('utf-8-validate');\n\n module.exports.isValidUTF8 = function (buf) {\n return buf.length < 32 ? _isValidUTF8(buf) : isValidUTF8(buf);\n };\n } catch (e) {\n // Continue regardless of the error.\n }\n}\n","'use strict';\n\nconst { Writable } = require('stream');\n\nconst PerMessageDeflate = require('./permessage-deflate');\nconst {\n BINARY_TYPES,\n EMPTY_BUFFER,\n kStatusCode,\n kWebSocket\n} = require('./constants');\nconst { concat, toArrayBuffer, unmask } = require('./buffer-util');\nconst { isValidStatusCode, isValidUTF8 } = require('./validation');\n\nconst FastBuffer = Buffer[Symbol.species];\n\nconst GET_INFO = 0;\nconst GET_PAYLOAD_LENGTH_16 = 1;\nconst GET_PAYLOAD_LENGTH_64 = 2;\nconst GET_MASK = 3;\nconst GET_DATA = 4;\nconst INFLATING = 5;\nconst DEFER_EVENT = 6;\n\n/**\n * HyBi Receiver implementation.\n *\n * @extends Writable\n */\nclass Receiver extends Writable {\n /**\n * Creates a Receiver instance.\n *\n * @param {Object} [options] Options object\n * @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether\n * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted\n * multiple times in the same tick\n * @param {String} [options.binaryType=nodebuffer] The type for binary data\n * @param {Object} [options.extensions] An object containing the negotiated\n * extensions\n * @param {Boolean} [options.isServer=false] Specifies whether to operate in\n * client or server mode\n * @param {Number} [options.maxPayload=0] The maximum allowed message length\n * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or\n * not to skip UTF-8 validation for text and close messages\n */\n constructor(options = {}) {\n super();\n\n this._allowSynchronousEvents =\n options.allowSynchronousEvents !== undefined\n ? options.allowSynchronousEvents\n : true;\n this._binaryType = options.binaryType || BINARY_TYPES[0];\n this._extensions = options.extensions || {};\n this._isServer = !!options.isServer;\n this._maxPayload = options.maxPayload | 0;\n this._skipUTF8Validation = !!options.skipUTF8Validation;\n this[kWebSocket] = undefined;\n\n this._bufferedBytes = 0;\n this._buffers = [];\n\n this._compressed = false;\n this._payloadLength = 0;\n this._mask = undefined;\n this._fragmented = 0;\n this._masked = false;\n this._fin = false;\n this._opcode = 0;\n\n this._totalPayloadLength = 0;\n this._messageLength = 0;\n this._fragments = [];\n\n this._errored = false;\n this._loop = false;\n this._state = GET_INFO;\n }\n\n /**\n * Implements `Writable.prototype._write()`.\n *\n * @param {Buffer} chunk The chunk of data to write\n * @param {String} encoding The character encoding of `chunk`\n * @param {Function} cb Callback\n * @private\n */\n _write(chunk, encoding, cb) {\n if (this._opcode === 0x08 && this._state == GET_INFO) return cb();\n\n this._bufferedBytes += chunk.length;\n this._buffers.push(chunk);\n this.startLoop(cb);\n }\n\n /**\n * Consumes `n` bytes from the buffered data.\n *\n * @param {Number} n The number of bytes to consume\n * @return {Buffer} The consumed bytes\n * @private\n */\n consume(n) {\n this._bufferedBytes -= n;\n\n if (n === this._buffers[0].length) return this._buffers.shift();\n\n if (n < this._buffers[0].length) {\n const buf = this._buffers[0];\n this._buffers[0] = new FastBuffer(\n buf.buffer,\n buf.byteOffset + n,\n buf.length - n\n );\n\n return new FastBuffer(buf.buffer, buf.byteOffset, n);\n }\n\n const dst = Buffer.allocUnsafe(n);\n\n do {\n const buf = this._buffers[0];\n const offset = dst.length - n;\n\n if (n >= buf.length) {\n dst.set(this._buffers.shift(), offset);\n } else {\n dst.set(new Uint8Array(buf.buffer, buf.byteOffset, n), offset);\n this._buffers[0] = new FastBuffer(\n buf.buffer,\n buf.byteOffset + n,\n buf.length - n\n );\n }\n\n n -= buf.length;\n } while (n > 0);\n\n return dst;\n }\n\n /**\n * Starts the parsing loop.\n *\n * @param {Function} cb Callback\n * @private\n */\n startLoop(cb) {\n this._loop = true;\n\n do {\n switch (this._state) {\n case GET_INFO:\n this.getInfo(cb);\n break;\n case GET_PAYLOAD_LENGTH_16:\n this.getPayloadLength16(cb);\n break;\n case GET_PAYLOAD_LENGTH_64:\n this.getPayloadLength64(cb);\n break;\n case GET_MASK:\n this.getMask();\n break;\n case GET_DATA:\n this.getData(cb);\n break;\n case INFLATING:\n case DEFER_EVENT:\n this._loop = false;\n return;\n }\n } while (this._loop);\n\n if (!this._errored) cb();\n }\n\n /**\n * Reads the first two bytes of a frame.\n *\n * @param {Function} cb Callback\n * @private\n */\n getInfo(cb) {\n if (this._bufferedBytes < 2) {\n this._loop = false;\n return;\n }\n\n const buf = this.consume(2);\n\n if ((buf[0] & 0x30) !== 0x00) {\n const error = this.createError(\n RangeError,\n 'RSV2 and RSV3 must be clear',\n true,\n 1002,\n 'WS_ERR_UNEXPECTED_RSV_2_3'\n );\n\n cb(error);\n return;\n }\n\n const compressed = (buf[0] & 0x40) === 0x40;\n\n if (compressed && !this._extensions[PerMessageDeflate.extensionName]) {\n const error = this.createError(\n RangeError,\n 'RSV1 must be clear',\n true,\n 1002,\n 'WS_ERR_UNEXPECTED_RSV_1'\n );\n\n cb(error);\n return;\n }\n\n this._fin = (buf[0] & 0x80) === 0x80;\n this._opcode = buf[0] & 0x0f;\n this._payloadLength = buf[1] & 0x7f;\n\n if (this._opcode === 0x00) {\n if (compressed) {\n const error = this.createError(\n RangeError,\n 'RSV1 must be clear',\n true,\n 1002,\n 'WS_ERR_UNEXPECTED_RSV_1'\n );\n\n cb(error);\n return;\n }\n\n if (!this._fragmented) {\n const error = this.createError(\n RangeError,\n 'invalid opcode 0',\n true,\n 1002,\n 'WS_ERR_INVALID_OPCODE'\n );\n\n cb(error);\n return;\n }\n\n this._opcode = this._fragmented;\n } else if (this._opcode === 0x01 || this._opcode === 0x02) {\n if (this._fragmented) {\n const error = this.createError(\n RangeError,\n `invalid opcode ${this._opcode}`,\n true,\n 1002,\n 'WS_ERR_INVALID_OPCODE'\n );\n\n cb(error);\n return;\n }\n\n this._compressed = compressed;\n } else if (this._opcode > 0x07 && this._opcode < 0x0b) {\n if (!this._fin) {\n const error = this.createError(\n RangeError,\n 'FIN must be set',\n true,\n 1002,\n 'WS_ERR_EXPECTED_FIN'\n );\n\n cb(error);\n return;\n }\n\n if (compressed) {\n const error = this.createError(\n RangeError,\n 'RSV1 must be clear',\n true,\n 1002,\n 'WS_ERR_UNEXPECTED_RSV_1'\n );\n\n cb(error);\n return;\n }\n\n if (\n this._payloadLength > 0x7d ||\n (this._opcode === 0x08 && this._payloadLength === 1)\n ) {\n const error = this.createError(\n RangeError,\n `invalid payload length ${this._payloadLength}`,\n true,\n 1002,\n 'WS_ERR_INVALID_CONTROL_PAYLOAD_LENGTH'\n );\n\n cb(error);\n return;\n }\n } else {\n const error = this.createError(\n RangeError,\n `invalid opcode ${this._opcode}`,\n true,\n 1002,\n 'WS_ERR_INVALID_OPCODE'\n );\n\n cb(error);\n return;\n }\n\n if (!this._fin && !this._fragmented) this._fragmented = this._opcode;\n this._masked = (buf[1] & 0x80) === 0x80;\n\n if (this._isServer) {\n if (!this._masked) {\n const error = this.createError(\n RangeError,\n 'MASK must be set',\n true,\n 1002,\n 'WS_ERR_EXPECTED_MASK'\n );\n\n cb(error);\n return;\n }\n } else if (this._masked) {\n const error = this.createError(\n RangeError,\n 'MASK must be clear',\n true,\n 1002,\n 'WS_ERR_UNEXPECTED_MASK'\n );\n\n cb(error);\n return;\n }\n\n if (this._payloadLength === 126) this._state = GET_PAYLOAD_LENGTH_16;\n else if (this._payloadLength === 127) this._state = GET_PAYLOAD_LENGTH_64;\n else this.haveLength(cb);\n }\n\n /**\n * Gets extended payload length (7+16).\n *\n * @param {Function} cb Callback\n * @private\n */\n getPayloadLength16(cb) {\n if (this._bufferedBytes < 2) {\n this._loop = false;\n return;\n }\n\n this._payloadLength = this.consume(2).readUInt16BE(0);\n this.haveLength(cb);\n }\n\n /**\n * Gets extended payload length (7+64).\n *\n * @param {Function} cb Callback\n * @private\n */\n getPayloadLength64(cb) {\n if (this._bufferedBytes < 8) {\n this._loop = false;\n return;\n }\n\n const buf = this.consume(8);\n const num = buf.readUInt32BE(0);\n\n //\n // The maximum safe integer in JavaScript is 2^53 - 1. An error is returned\n // if payload length is greater than this number.\n //\n if (num > Math.pow(2, 53 - 32) - 1) {\n const error = this.createError(\n RangeError,\n 'Unsupported WebSocket frame: payload length > 2^53 - 1',\n false,\n 1009,\n 'WS_ERR_UNSUPPORTED_DATA_PAYLOAD_LENGTH'\n );\n\n cb(error);\n return;\n }\n\n this._payloadLength = num * Math.pow(2, 32) + buf.readUInt32BE(4);\n this.haveLength(cb);\n }\n\n /**\n * Payload length has been read.\n *\n * @param {Function} cb Callback\n * @private\n */\n haveLength(cb) {\n if (this._payloadLength && this._opcode < 0x08) {\n this._totalPayloadLength += this._payloadLength;\n if (this._totalPayloadLength > this._maxPayload && this._maxPayload > 0) {\n const error = this.createError(\n RangeError,\n 'Max payload size exceeded',\n false,\n 1009,\n 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH'\n );\n\n cb(error);\n return;\n }\n }\n\n if (this._masked) this._state = GET_MASK;\n else this._state = GET_DATA;\n }\n\n /**\n * Reads mask bytes.\n *\n * @private\n */\n getMask() {\n if (this._bufferedBytes < 4) {\n this._loop = false;\n return;\n }\n\n this._mask = this.consume(4);\n this._state = GET_DATA;\n }\n\n /**\n * Reads data bytes.\n *\n * @param {Function} cb Callback\n * @private\n */\n getData(cb) {\n let data = EMPTY_BUFFER;\n\n if (this._payloadLength) {\n if (this._bufferedBytes < this._payloadLength) {\n this._loop = false;\n return;\n }\n\n data = this.consume(this._payloadLength);\n\n if (\n this._masked &&\n (this._mask[0] | this._mask[1] | this._mask[2] | this._mask[3]) !== 0\n ) {\n unmask(data, this._mask);\n }\n }\n\n if (this._opcode > 0x07) {\n this.controlMessage(data, cb);\n return;\n }\n\n if (this._compressed) {\n this._state = INFLATING;\n this.decompress(data, cb);\n return;\n }\n\n if (data.length) {\n //\n // This message is not compressed so its length is the sum of the payload\n // length of all fragments.\n //\n this._messageLength = this._totalPayloadLength;\n this._fragments.push(data);\n }\n\n this.dataMessage(cb);\n }\n\n /**\n * Decompresses data.\n *\n * @param {Buffer} data Compressed data\n * @param {Function} cb Callback\n * @private\n */\n decompress(data, cb) {\n const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];\n\n perMessageDeflate.decompress(data, this._fin, (err, buf) => {\n if (err) return cb(err);\n\n if (buf.length) {\n this._messageLength += buf.length;\n if (this._messageLength > this._maxPayload && this._maxPayload > 0) {\n const error = this.createError(\n RangeError,\n 'Max payload size exceeded',\n false,\n 1009,\n 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH'\n );\n\n cb(error);\n return;\n }\n\n this._fragments.push(buf);\n }\n\n this.dataMessage(cb);\n if (this._state === GET_INFO) this.startLoop(cb);\n });\n }\n\n /**\n * Handles a data message.\n *\n * @param {Function} cb Callback\n * @private\n */\n dataMessage(cb) {\n if (!this._fin) {\n this._state = GET_INFO;\n return;\n }\n\n const messageLength = this._messageLength;\n const fragments = this._fragments;\n\n this._totalPayloadLength = 0;\n this._messageLength = 0;\n this._fragmented = 0;\n this._fragments = [];\n\n if (this._opcode === 2) {\n let data;\n\n if (this._binaryType === 'nodebuffer') {\n data = concat(fragments, messageLength);\n } else if (this._binaryType === 'arraybuffer') {\n data = toArrayBuffer(concat(fragments, messageLength));\n } else if (this._binaryType === 'blob') {\n data = new Blob(fragments);\n } else {\n data = fragments;\n }\n\n if (this._allowSynchronousEvents) {\n this.emit('message', data, true);\n this._state = GET_INFO;\n } else {\n this._state = DEFER_EVENT;\n setImmediate(() => {\n this.emit('message', data, true);\n this._state = GET_INFO;\n this.startLoop(cb);\n });\n }\n } else {\n const buf = concat(fragments, messageLength);\n\n if (!this._skipUTF8Validation && !isValidUTF8(buf)) {\n const error = this.createError(\n Error,\n 'invalid UTF-8 sequence',\n true,\n 1007,\n 'WS_ERR_INVALID_UTF8'\n );\n\n cb(error);\n return;\n }\n\n if (this._state === INFLATING || this._allowSynchronousEvents) {\n this.emit('message', buf, false);\n this._state = GET_INFO;\n } else {\n this._state = DEFER_EVENT;\n setImmediate(() => {\n this.emit('message', buf, false);\n this._state = GET_INFO;\n this.startLoop(cb);\n });\n }\n }\n }\n\n /**\n * Handles a control message.\n *\n * @param {Buffer} data Data to handle\n * @return {(Error|RangeError|undefined)} A possible error\n * @private\n */\n controlMessage(data, cb) {\n if (this._opcode === 0x08) {\n if (data.length === 0) {\n this._loop = false;\n this.emit('conclude', 1005, EMPTY_BUFFER);\n this.end();\n } else {\n const code = data.readUInt16BE(0);\n\n if (!isValidStatusCode(code)) {\n const error = this.createError(\n RangeError,\n `invalid status code ${code}`,\n true,\n 1002,\n 'WS_ERR_INVALID_CLOSE_CODE'\n );\n\n cb(error);\n return;\n }\n\n const buf = new FastBuffer(\n data.buffer,\n data.byteOffset + 2,\n data.length - 2\n );\n\n if (!this._skipUTF8Validation && !isValidUTF8(buf)) {\n const error = this.createError(\n Error,\n 'invalid UTF-8 sequence',\n true,\n 1007,\n 'WS_ERR_INVALID_UTF8'\n );\n\n cb(error);\n return;\n }\n\n this._loop = false;\n this.emit('conclude', code, buf);\n this.end();\n }\n\n this._state = GET_INFO;\n return;\n }\n\n if (this._allowSynchronousEvents) {\n this.emit(this._opcode === 0x09 ? 'ping' : 'pong', data);\n this._state = GET_INFO;\n } else {\n this._state = DEFER_EVENT;\n setImmediate(() => {\n this.emit(this._opcode === 0x09 ? 'ping' : 'pong', data);\n this._state = GET_INFO;\n this.startLoop(cb);\n });\n }\n }\n\n /**\n * Builds an error object.\n *\n * @param {function(new:Error|RangeError)} ErrorCtor The error constructor\n * @param {String} message The error message\n * @param {Boolean} prefix Specifies whether or not to add a default prefix to\n * `message`\n * @param {Number} statusCode The status code\n * @param {String} errorCode The exposed error code\n * @return {(Error|RangeError)} The error\n * @private\n */\n createError(ErrorCtor, message, prefix, statusCode, errorCode) {\n this._loop = false;\n this._errored = true;\n\n const err = new ErrorCtor(\n prefix ? `Invalid WebSocket frame: ${message}` : message\n );\n\n Error.captureStackTrace(err, this.createError);\n err.code = errorCode;\n err[kStatusCode] = statusCode;\n return err;\n }\n}\n\nmodule.exports = Receiver;\n","/* eslint no-unused-vars: [\"error\", { \"varsIgnorePattern\": \"^Duplex\" }] */\n\n'use strict';\n\nconst { Duplex } = require('stream');\nconst { randomFillSync } = require('crypto');\n\nconst PerMessageDeflate = require('./permessage-deflate');\nconst { EMPTY_BUFFER, kWebSocket, NOOP } = require('./constants');\nconst { isBlob, isValidStatusCode } = require('./validation');\nconst { mask: applyMask, toBuffer } = require('./buffer-util');\n\nconst kByteLength = Symbol('kByteLength');\nconst maskBuffer = Buffer.alloc(4);\nconst RANDOM_POOL_SIZE = 8 * 1024;\nlet randomPool;\nlet randomPoolPointer = RANDOM_POOL_SIZE;\n\nconst DEFAULT = 0;\nconst DEFLATING = 1;\nconst GET_BLOB_DATA = 2;\n\n/**\n * HyBi Sender implementation.\n */\nclass Sender {\n /**\n * Creates a Sender instance.\n *\n * @param {Duplex} socket The connection socket\n * @param {Object} [extensions] An object containing the negotiated extensions\n * @param {Function} [generateMask] The function used to generate the masking\n * key\n */\n constructor(socket, extensions, generateMask) {\n this._extensions = extensions || {};\n\n if (generateMask) {\n this._generateMask = generateMask;\n this._maskBuffer = Buffer.alloc(4);\n }\n\n this._socket = socket;\n\n this._firstFragment = true;\n this._compress = false;\n\n this._bufferedBytes = 0;\n this._queue = [];\n this._state = DEFAULT;\n this.onerror = NOOP;\n this[kWebSocket] = undefined;\n }\n\n /**\n * Frames a piece of data according to the HyBi WebSocket protocol.\n *\n * @param {(Buffer|String)} data The data to frame\n * @param {Object} options Options object\n * @param {Boolean} [options.fin=false] Specifies whether or not to set the\n * FIN bit\n * @param {Function} [options.generateMask] The function used to generate the\n * masking key\n * @param {Boolean} [options.mask=false] Specifies whether or not to mask\n * `data`\n * @param {Buffer} [options.maskBuffer] The buffer used to store the masking\n * key\n * @param {Number} options.opcode The opcode\n * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be\n * modified\n * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the\n * RSV1 bit\n * @return {(Buffer|String)[]} The framed data\n * @public\n */\n static frame(data, options) {\n let mask;\n let merge = false;\n let offset = 2;\n let skipMasking = false;\n\n if (options.mask) {\n mask = options.maskBuffer || maskBuffer;\n\n if (options.generateMask) {\n options.generateMask(mask);\n } else {\n if (randomPoolPointer === RANDOM_POOL_SIZE) {\n /* istanbul ignore else */\n if (randomPool === undefined) {\n //\n // This is lazily initialized because server-sent frames must not\n // be masked so it may never be used.\n //\n randomPool = Buffer.alloc(RANDOM_POOL_SIZE);\n }\n\n randomFillSync(randomPool, 0, RANDOM_POOL_SIZE);\n randomPoolPointer = 0;\n }\n\n mask[0] = randomPool[randomPoolPointer++];\n mask[1] = randomPool[randomPoolPointer++];\n mask[2] = randomPool[randomPoolPointer++];\n mask[3] = randomPool[randomPoolPointer++];\n }\n\n skipMasking = (mask[0] | mask[1] | mask[2] | mask[3]) === 0;\n offset = 6;\n }\n\n let dataLength;\n\n if (typeof data === 'string') {\n if (\n (!options.mask || skipMasking) &&\n options[kByteLength] !== undefined\n ) {\n dataLength = options[kByteLength];\n } else {\n data = Buffer.from(data);\n dataLength = data.length;\n }\n } else {\n dataLength = data.length;\n merge = options.mask && options.readOnly && !skipMasking;\n }\n\n let payloadLength = dataLength;\n\n if (dataLength >= 65536) {\n offset += 8;\n payloadLength = 127;\n } else if (dataLength > 125) {\n offset += 2;\n payloadLength = 126;\n }\n\n const target = Buffer.allocUnsafe(merge ? dataLength + offset : offset);\n\n target[0] = options.fin ? options.opcode | 0x80 : options.opcode;\n if (options.rsv1) target[0] |= 0x40;\n\n target[1] = payloadLength;\n\n if (payloadLength === 126) {\n target.writeUInt16BE(dataLength, 2);\n } else if (payloadLength === 127) {\n target[2] = target[3] = 0;\n target.writeUIntBE(dataLength, 4, 6);\n }\n\n if (!options.mask) return [target, data];\n\n target[1] |= 0x80;\n target[offset - 4] = mask[0];\n target[offset - 3] = mask[1];\n target[offset - 2] = mask[2];\n target[offset - 1] = mask[3];\n\n if (skipMasking) return [target, data];\n\n if (merge) {\n applyMask(data, mask, target, offset, dataLength);\n return [target];\n }\n\n applyMask(data, mask, data, 0, dataLength);\n return [target, data];\n }\n\n /**\n * Sends a close message to the other peer.\n *\n * @param {Number} [code] The status code component of the body\n * @param {(String|Buffer)} [data] The message component of the body\n * @param {Boolean} [mask=false] Specifies whether or not to mask the message\n * @param {Function} [cb] Callback\n * @public\n */\n close(code, data, mask, cb) {\n let buf;\n\n if (code === undefined) {\n buf = EMPTY_BUFFER;\n } else if (typeof code !== 'number' || !isValidStatusCode(code)) {\n throw new TypeError('First argument must be a valid error code number');\n } else if (data === undefined || !data.length) {\n buf = Buffer.allocUnsafe(2);\n buf.writeUInt16BE(code, 0);\n } else {\n const length = Buffer.byteLength(data);\n\n if (length > 123) {\n throw new RangeError('The message must not be greater than 123 bytes');\n }\n\n buf = Buffer.allocUnsafe(2 + length);\n buf.writeUInt16BE(code, 0);\n\n if (typeof data === 'string') {\n buf.write(data, 2);\n } else {\n buf.set(data, 2);\n }\n }\n\n const options = {\n [kByteLength]: buf.length,\n fin: true,\n generateMask: this._generateMask,\n mask,\n maskBuffer: this._maskBuffer,\n opcode: 0x08,\n readOnly: false,\n rsv1: false\n };\n\n if (this._state !== DEFAULT) {\n this.enqueue([this.dispatch, buf, false, options, cb]);\n } else {\n this.sendFrame(Sender.frame(buf, options), cb);\n }\n }\n\n /**\n * Sends a ping message to the other peer.\n *\n * @param {*} data The message to send\n * @param {Boolean} [mask=false] Specifies whether or not to mask `data`\n * @param {Function} [cb] Callback\n * @public\n */\n ping(data, mask, cb) {\n let byteLength;\n let readOnly;\n\n if (typeof data === 'string') {\n byteLength = Buffer.byteLength(data);\n readOnly = false;\n } else if (isBlob(data)) {\n byteLength = data.size;\n readOnly = false;\n } else {\n data = toBuffer(data);\n byteLength = data.length;\n readOnly = toBuffer.readOnly;\n }\n\n if (byteLength > 125) {\n throw new RangeError('The data size must not be greater than 125 bytes');\n }\n\n const options = {\n [kByteLength]: byteLength,\n fin: true,\n generateMask: this._generateMask,\n mask,\n maskBuffer: this._maskBuffer,\n opcode: 0x09,\n readOnly,\n rsv1: false\n };\n\n if (isBlob(data)) {\n if (this._state !== DEFAULT) {\n this.enqueue([this.getBlobData, data, false, options, cb]);\n } else {\n this.getBlobData(data, false, options, cb);\n }\n } else if (this._state !== DEFAULT) {\n this.enqueue([this.dispatch, data, false, options, cb]);\n } else {\n this.sendFrame(Sender.frame(data, options), cb);\n }\n }\n\n /**\n * Sends a pong message to the other peer.\n *\n * @param {*} data The message to send\n * @param {Boolean} [mask=false] Specifies whether or not to mask `data`\n * @param {Function} [cb] Callback\n * @public\n */\n pong(data, mask, cb) {\n let byteLength;\n let readOnly;\n\n if (typeof data === 'string') {\n byteLength = Buffer.byteLength(data);\n readOnly = false;\n } else if (isBlob(data)) {\n byteLength = data.size;\n readOnly = false;\n } else {\n data = toBuffer(data);\n byteLength = data.length;\n readOnly = toBuffer.readOnly;\n }\n\n if (byteLength > 125) {\n throw new RangeError('The data size must not be greater than 125 bytes');\n }\n\n const options = {\n [kByteLength]: byteLength,\n fin: true,\n generateMask: this._generateMask,\n mask,\n maskBuffer: this._maskBuffer,\n opcode: 0x0a,\n readOnly,\n rsv1: false\n };\n\n if (isBlob(data)) {\n if (this._state !== DEFAULT) {\n this.enqueue([this.getBlobData, data, false, options, cb]);\n } else {\n this.getBlobData(data, false, options, cb);\n }\n } else if (this._state !== DEFAULT) {\n this.enqueue([this.dispatch, data, false, options, cb]);\n } else {\n this.sendFrame(Sender.frame(data, options), cb);\n }\n }\n\n /**\n * Sends a data message to the other peer.\n *\n * @param {*} data The message to send\n * @param {Object} options Options object\n * @param {Boolean} [options.binary=false] Specifies whether `data` is binary\n * or text\n * @param {Boolean} [options.compress=false] Specifies whether or not to\n * compress `data`\n * @param {Boolean} [options.fin=false] Specifies whether the fragment is the\n * last one\n * @param {Boolean} [options.mask=false] Specifies whether or not to mask\n * `data`\n * @param {Function} [cb] Callback\n * @public\n */\n send(data, options, cb) {\n const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];\n let opcode = options.binary ? 2 : 1;\n let rsv1 = options.compress;\n\n let byteLength;\n let readOnly;\n\n if (typeof data === 'string') {\n byteLength = Buffer.byteLength(data);\n readOnly = false;\n } else if (isBlob(data)) {\n byteLength = data.size;\n readOnly = false;\n } else {\n data = toBuffer(data);\n byteLength = data.length;\n readOnly = toBuffer.readOnly;\n }\n\n if (this._firstFragment) {\n this._firstFragment = false;\n if (\n rsv1 &&\n perMessageDeflate &&\n perMessageDeflate.params[\n perMessageDeflate._isServer\n ? 'server_no_context_takeover'\n : 'client_no_context_takeover'\n ]\n ) {\n rsv1 = byteLength >= perMessageDeflate._threshold;\n }\n this._compress = rsv1;\n } else {\n rsv1 = false;\n opcode = 0;\n }\n\n if (options.fin) this._firstFragment = true;\n\n const opts = {\n [kByteLength]: byteLength,\n fin: options.fin,\n generateMask: this._generateMask,\n mask: options.mask,\n maskBuffer: this._maskBuffer,\n opcode,\n readOnly,\n rsv1\n };\n\n if (isBlob(data)) {\n if (this._state !== DEFAULT) {\n this.enqueue([this.getBlobData, data, this._compress, opts, cb]);\n } else {\n this.getBlobData(data, this._compress, opts, cb);\n }\n } else if (this._state !== DEFAULT) {\n this.enqueue([this.dispatch, data, this._compress, opts, cb]);\n } else {\n this.dispatch(data, this._compress, opts, cb);\n }\n }\n\n /**\n * Gets the contents of a blob as binary data.\n *\n * @param {Blob} blob The blob\n * @param {Boolean} [compress=false] Specifies whether or not to compress\n * the data\n * @param {Object} options Options object\n * @param {Boolean} [options.fin=false] Specifies whether or not to set the\n * FIN bit\n * @param {Function} [options.generateMask] The function used to generate the\n * masking key\n * @param {Boolean} [options.mask=false] Specifies whether or not to mask\n * `data`\n * @param {Buffer} [options.maskBuffer] The buffer used to store the masking\n * key\n * @param {Number} options.opcode The opcode\n * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be\n * modified\n * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the\n * RSV1 bit\n * @param {Function} [cb] Callback\n * @private\n */\n getBlobData(blob, compress, options, cb) {\n this._bufferedBytes += options[kByteLength];\n this._state = GET_BLOB_DATA;\n\n blob\n .arrayBuffer()\n .then((arrayBuffer) => {\n if (this._socket.destroyed) {\n const err = new Error(\n 'The socket was closed while the blob was being read'\n );\n\n //\n // `callCallbacks` is called in the next tick to ensure that errors\n // that might be thrown in the callbacks behave like errors thrown\n // outside the promise chain.\n //\n process.nextTick(callCallbacks, this, err, cb);\n return;\n }\n\n this._bufferedBytes -= options[kByteLength];\n const data = toBuffer(arrayBuffer);\n\n if (!compress) {\n this._state = DEFAULT;\n this.sendFrame(Sender.frame(data, options), cb);\n this.dequeue();\n } else {\n this.dispatch(data, compress, options, cb);\n }\n })\n .catch((err) => {\n //\n // `onError` is called in the next tick for the same reason that\n // `callCallbacks` above is.\n //\n process.nextTick(onError, this, err, cb);\n });\n }\n\n /**\n * Dispatches a message.\n *\n * @param {(Buffer|String)} data The message to send\n * @param {Boolean} [compress=false] Specifies whether or not to compress\n * `data`\n * @param {Object} options Options object\n * @param {Boolean} [options.fin=false] Specifies whether or not to set the\n * FIN bit\n * @param {Function} [options.generateMask] The function used to generate the\n * masking key\n * @param {Boolean} [options.mask=false] Specifies whether or not to mask\n * `data`\n * @param {Buffer} [options.maskBuffer] The buffer used to store the masking\n * key\n * @param {Number} options.opcode The opcode\n * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be\n * modified\n * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the\n * RSV1 bit\n * @param {Function} [cb] Callback\n * @private\n */\n dispatch(data, compress, options, cb) {\n if (!compress) {\n this.sendFrame(Sender.frame(data, options), cb);\n return;\n }\n\n const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];\n\n this._bufferedBytes += options[kByteLength];\n this._state = DEFLATING;\n perMessageDeflate.compress(data, options.fin, (_, buf) => {\n if (this._socket.destroyed) {\n const err = new Error(\n 'The socket was closed while data was being compressed'\n );\n\n callCallbacks(this, err, cb);\n return;\n }\n\n this._bufferedBytes -= options[kByteLength];\n this._state = DEFAULT;\n options.readOnly = false;\n this.sendFrame(Sender.frame(buf, options), cb);\n this.dequeue();\n });\n }\n\n /**\n * Executes queued send operations.\n *\n * @private\n */\n dequeue() {\n while (this._state === DEFAULT && this._queue.length) {\n const params = this._queue.shift();\n\n this._bufferedBytes -= params[3][kByteLength];\n Reflect.apply(params[0], this, params.slice(1));\n }\n }\n\n /**\n * Enqueues a send operation.\n *\n * @param {Array} params Send operation parameters.\n * @private\n */\n enqueue(params) {\n this._bufferedBytes += params[3][kByteLength];\n this._queue.push(params);\n }\n\n /**\n * Sends a frame.\n *\n * @param {(Buffer | String)[]} list The frame to send\n * @param {Function} [cb] Callback\n * @private\n */\n sendFrame(list, cb) {\n if (list.length === 2) {\n this._socket.cork();\n this._socket.write(list[0]);\n this._socket.write(list[1], cb);\n this._socket.uncork();\n } else {\n this._socket.write(list[0], cb);\n }\n }\n}\n\nmodule.exports = Sender;\n\n/**\n * Calls queued callbacks with an error.\n *\n * @param {Sender} sender The `Sender` instance\n * @param {Error} err The error to call the callbacks with\n * @param {Function} [cb] The first callback\n * @private\n */\nfunction callCallbacks(sender, err, cb) {\n if (typeof cb === 'function') cb(err);\n\n for (let i = 0; i < sender._queue.length; i++) {\n const params = sender._queue[i];\n const callback = params[params.length - 1];\n\n if (typeof callback === 'function') callback(err);\n }\n}\n\n/**\n * Handles a `Sender` error.\n *\n * @param {Sender} sender The `Sender` instance\n * @param {Error} err The error\n * @param {Function} [cb] The first pending callback\n * @private\n */\nfunction onError(sender, err, cb) {\n callCallbacks(sender, err, cb);\n sender.onerror(err);\n}\n","'use strict';\n\nconst { kForOnEventAttribute, kListener } = require('./constants');\n\nconst kCode = Symbol('kCode');\nconst kData = Symbol('kData');\nconst kError = Symbol('kError');\nconst kMessage = Symbol('kMessage');\nconst kReason = Symbol('kReason');\nconst kTarget = Symbol('kTarget');\nconst kType = Symbol('kType');\nconst kWasClean = Symbol('kWasClean');\n\n/**\n * Class representing an event.\n */\nclass Event {\n /**\n * Create a new `Event`.\n *\n * @param {String} type The name of the event\n * @throws {TypeError} If the `type` argument is not specified\n */\n constructor(type) {\n this[kTarget] = null;\n this[kType] = type;\n }\n\n /**\n * @type {*}\n */\n get target() {\n return this[kTarget];\n }\n\n /**\n * @type {String}\n */\n get type() {\n return this[kType];\n }\n}\n\nObject.defineProperty(Event.prototype, 'target', { enumerable: true });\nObject.defineProperty(Event.prototype, 'type', { enumerable: true });\n\n/**\n * Class representing a close event.\n *\n * @extends Event\n */\nclass CloseEvent extends Event {\n /**\n * Create a new `CloseEvent`.\n *\n * @param {String} type The name of the event\n * @param {Object} [options] A dictionary object that allows for setting\n * attributes via object members of the same name\n * @param {Number} [options.code=0] The status code explaining why the\n * connection was closed\n * @param {String} [options.reason=''] A human-readable string explaining why\n * the connection was closed\n * @param {Boolean} [options.wasClean=false] Indicates whether or not the\n * connection was cleanly closed\n */\n constructor(type, options = {}) {\n super(type);\n\n this[kCode] = options.code === undefined ? 0 : options.code;\n this[kReason] = options.reason === undefined ? '' : options.reason;\n this[kWasClean] = options.wasClean === undefined ? false : options.wasClean;\n }\n\n /**\n * @type {Number}\n */\n get code() {\n return this[kCode];\n }\n\n /**\n * @type {String}\n */\n get reason() {\n return this[kReason];\n }\n\n /**\n * @type {Boolean}\n */\n get wasClean() {\n return this[kWasClean];\n }\n}\n\nObject.defineProperty(CloseEvent.prototype, 'code', { enumerable: true });\nObject.defineProperty(CloseEvent.prototype, 'reason', { enumerable: true });\nObject.defineProperty(CloseEvent.prototype, 'wasClean', { enumerable: true });\n\n/**\n * Class representing an error event.\n *\n * @extends Event\n */\nclass ErrorEvent extends Event {\n /**\n * Create a new `ErrorEvent`.\n *\n * @param {String} type The name of the event\n * @param {Object} [options] A dictionary object that allows for setting\n * attributes via object members of the same name\n * @param {*} [options.error=null] The error that generated this event\n * @param {String} [options.message=''] The error message\n */\n constructor(type, options = {}) {\n super(type);\n\n this[kError] = options.error === undefined ? null : options.error;\n this[kMessage] = options.message === undefined ? '' : options.message;\n }\n\n /**\n * @type {*}\n */\n get error() {\n return this[kError];\n }\n\n /**\n * @type {String}\n */\n get message() {\n return this[kMessage];\n }\n}\n\nObject.defineProperty(ErrorEvent.prototype, 'error', { enumerable: true });\nObject.defineProperty(ErrorEvent.prototype, 'message', { enumerable: true });\n\n/**\n * Class representing a message event.\n *\n * @extends Event\n */\nclass MessageEvent extends Event {\n /**\n * Create a new `MessageEvent`.\n *\n * @param {String} type The name of the event\n * @param {Object} [options] A dictionary object that allows for setting\n * attributes via object members of the same name\n * @param {*} [options.data=null] The message content\n */\n constructor(type, options = {}) {\n super(type);\n\n this[kData] = options.data === undefined ? null : options.data;\n }\n\n /**\n * @type {*}\n */\n get data() {\n return this[kData];\n }\n}\n\nObject.defineProperty(MessageEvent.prototype, 'data', { enumerable: true });\n\n/**\n * This provides methods for emulating the `EventTarget` interface. It's not\n * meant to be used directly.\n *\n * @mixin\n */\nconst EventTarget = {\n /**\n * Register an event listener.\n *\n * @param {String} type A string representing the event type to listen for\n * @param {(Function|Object)} handler The listener to add\n * @param {Object} [options] An options object specifies characteristics about\n * the event listener\n * @param {Boolean} [options.once=false] A `Boolean` indicating that the\n * listener should be invoked at most once after being added. If `true`,\n * the listener would be automatically removed when invoked.\n * @public\n */\n addEventListener(type, handler, options = {}) {\n for (const listener of this.listeners(type)) {\n if (\n !options[kForOnEventAttribute] &&\n listener[kListener] === handler &&\n !listener[kForOnEventAttribute]\n ) {\n return;\n }\n }\n\n let wrapper;\n\n if (type === 'message') {\n wrapper = function onMessage(data, isBinary) {\n const event = new MessageEvent('message', {\n data: isBinary ? data : data.toString()\n });\n\n event[kTarget] = this;\n callListener(handler, this, event);\n };\n } else if (type === 'close') {\n wrapper = function onClose(code, message) {\n const event = new CloseEvent('close', {\n code,\n reason: message.toString(),\n wasClean: this._closeFrameReceived && this._closeFrameSent\n });\n\n event[kTarget] = this;\n callListener(handler, this, event);\n };\n } else if (type === 'error') {\n wrapper = function onError(error) {\n const event = new ErrorEvent('error', {\n error,\n message: error.message\n });\n\n event[kTarget] = this;\n callListener(handler, this, event);\n };\n } else if (type === 'open') {\n wrapper = function onOpen() {\n const event = new Event('open');\n\n event[kTarget] = this;\n callListener(handler, this, event);\n };\n } else {\n return;\n }\n\n wrapper[kForOnEventAttribute] = !!options[kForOnEventAttribute];\n wrapper[kListener] = handler;\n\n if (options.once) {\n this.once(type, wrapper);\n } else {\n this.on(type, wrapper);\n }\n },\n\n /**\n * Remove an event listener.\n *\n * @param {String} type A string representing the event type to remove\n * @param {(Function|Object)} handler The listener to remove\n * @public\n */\n removeEventListener(type, handler) {\n for (const listener of this.listeners(type)) {\n if (listener[kListener] === handler && !listener[kForOnEventAttribute]) {\n this.removeListener(type, listener);\n break;\n }\n }\n }\n};\n\nmodule.exports = {\n CloseEvent,\n ErrorEvent,\n Event,\n EventTarget,\n MessageEvent\n};\n\n/**\n * Call an event listener\n *\n * @param {(Function|Object)} listener The listener to call\n * @param {*} thisArg The value to use as `this`` when calling the listener\n * @param {Event} event The event to pass to the listener\n * @private\n */\nfunction callListener(listener, thisArg, event) {\n if (typeof listener === 'object' && listener.handleEvent) {\n listener.handleEvent.call(listener, event);\n } else {\n listener.call(thisArg, event);\n }\n}\n","'use strict';\n\nconst { tokenChars } = require('./validation');\n\n/**\n * Adds an offer to the map of extension offers or a parameter to the map of\n * parameters.\n *\n * @param {Object} dest The map of extension offers or parameters\n * @param {String} name The extension or parameter name\n * @param {(Object|Boolean|String)} elem The extension parameters or the\n * parameter value\n * @private\n */\nfunction push(dest, name, elem) {\n if (dest[name] === undefined) dest[name] = [elem];\n else dest[name].push(elem);\n}\n\n/**\n * Parses the `Sec-WebSocket-Extensions` header into an object.\n *\n * @param {String} header The field value of the header\n * @return {Object} The parsed object\n * @public\n */\nfunction parse(header) {\n const offers = Object.create(null);\n let params = Object.create(null);\n let mustUnescape = false;\n let isEscaping = false;\n let inQuotes = false;\n let extensionName;\n let paramName;\n let start = -1;\n let code = -1;\n let end = -1;\n let i = 0;\n\n for (; i < header.length; i++) {\n code = header.charCodeAt(i);\n\n if (extensionName === undefined) {\n if (end === -1 && tokenChars[code] === 1) {\n if (start === -1) start = i;\n } else if (\n i !== 0 &&\n (code === 0x20 /* ' ' */ || code === 0x09) /* '\\t' */\n ) {\n if (end === -1 && start !== -1) end = i;\n } else if (code === 0x3b /* ';' */ || code === 0x2c /* ',' */) {\n if (start === -1) {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n\n if (end === -1) end = i;\n const name = header.slice(start, end);\n if (code === 0x2c) {\n push(offers, name, params);\n params = Object.create(null);\n } else {\n extensionName = name;\n }\n\n start = end = -1;\n } else {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n } else if (paramName === undefined) {\n if (end === -1 && tokenChars[code] === 1) {\n if (start === -1) start = i;\n } else if (code === 0x20 || code === 0x09) {\n if (end === -1 && start !== -1) end = i;\n } else if (code === 0x3b || code === 0x2c) {\n if (start === -1) {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n\n if (end === -1) end = i;\n push(params, header.slice(start, end), true);\n if (code === 0x2c) {\n push(offers, extensionName, params);\n params = Object.create(null);\n extensionName = undefined;\n }\n\n start = end = -1;\n } else if (code === 0x3d /* '=' */ && start !== -1 && end === -1) {\n paramName = header.slice(start, i);\n start = end = -1;\n } else {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n } else {\n //\n // The value of a quoted-string after unescaping must conform to the\n // token ABNF, so only token characters are valid.\n // Ref: https://tools.ietf.org/html/rfc6455#section-9.1\n //\n if (isEscaping) {\n if (tokenChars[code] !== 1) {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n if (start === -1) start = i;\n else if (!mustUnescape) mustUnescape = true;\n isEscaping = false;\n } else if (inQuotes) {\n if (tokenChars[code] === 1) {\n if (start === -1) start = i;\n } else if (code === 0x22 /* '\"' */ && start !== -1) {\n inQuotes = false;\n end = i;\n } else if (code === 0x5c /* '\\' */) {\n isEscaping = true;\n } else {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n } else if (code === 0x22 && header.charCodeAt(i - 1) === 0x3d) {\n inQuotes = true;\n } else if (end === -1 && tokenChars[code] === 1) {\n if (start === -1) start = i;\n } else if (start !== -1 && (code === 0x20 || code === 0x09)) {\n if (end === -1) end = i;\n } else if (code === 0x3b || code === 0x2c) {\n if (start === -1) {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n\n if (end === -1) end = i;\n let value = header.slice(start, end);\n if (mustUnescape) {\n value = value.replace(/\\\\/g, '');\n mustUnescape = false;\n }\n push(params, paramName, value);\n if (code === 0x2c) {\n push(offers, extensionName, params);\n params = Object.create(null);\n extensionName = undefined;\n }\n\n paramName = undefined;\n start = end = -1;\n } else {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n }\n }\n\n if (start === -1 || inQuotes || code === 0x20 || code === 0x09) {\n throw new SyntaxError('Unexpected end of input');\n }\n\n if (end === -1) end = i;\n const token = header.slice(start, end);\n if (extensionName === undefined) {\n push(offers, token, params);\n } else {\n if (paramName === undefined) {\n push(params, token, true);\n } else if (mustUnescape) {\n push(params, paramName, token.replace(/\\\\/g, ''));\n } else {\n push(params, paramName, token);\n }\n push(offers, extensionName, params);\n }\n\n return offers;\n}\n\n/**\n * Builds the `Sec-WebSocket-Extensions` header field value.\n *\n * @param {Object} extensions The map of extensions and parameters to format\n * @return {String} A string representing the given object\n * @public\n */\nfunction format(extensions) {\n return Object.keys(extensions)\n .map((extension) => {\n let configurations = extensions[extension];\n if (!Array.isArray(configurations)) configurations = [configurations];\n return configurations\n .map((params) => {\n return [extension]\n .concat(\n Object.keys(params).map((k) => {\n let values = params[k];\n if (!Array.isArray(values)) values = [values];\n return values\n .map((v) => (v === true ? k : `${k}=${v}`))\n .join('; ');\n })\n )\n .join('; ');\n })\n .join(', ');\n })\n .join(', ');\n}\n\nmodule.exports = { format, parse };\n","/* eslint no-unused-vars: [\"error\", { \"varsIgnorePattern\": \"^Duplex|Readable$\", \"caughtErrors\": \"none\" }] */\n\n'use strict';\n\nconst EventEmitter = require('events');\nconst https = require('https');\nconst http = require('http');\nconst net = require('net');\nconst tls = require('tls');\nconst { randomBytes, createHash } = require('crypto');\nconst { Duplex, Readable } = require('stream');\nconst { URL } = require('url');\n\nconst PerMessageDeflate = require('./permessage-deflate');\nconst Receiver = require('./receiver');\nconst Sender = require('./sender');\nconst { isBlob } = require('./validation');\n\nconst {\n BINARY_TYPES,\n CLOSE_TIMEOUT,\n EMPTY_BUFFER,\n GUID,\n kForOnEventAttribute,\n kListener,\n kStatusCode,\n kWebSocket,\n NOOP\n} = require('./constants');\nconst {\n EventTarget: { addEventListener, removeEventListener }\n} = require('./event-target');\nconst { format, parse } = require('./extension');\nconst { toBuffer } = require('./buffer-util');\n\nconst kAborted = Symbol('kAborted');\nconst protocolVersions = [8, 13];\nconst readyStates = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED'];\nconst subprotocolRegex = /^[!#$%&'*+\\-.0-9A-Z^_`|a-z~]+$/;\n\n/**\n * Class representing a WebSocket.\n *\n * @extends EventEmitter\n */\nclass WebSocket extends EventEmitter {\n /**\n * Create a new `WebSocket`.\n *\n * @param {(String|URL)} address The URL to which to connect\n * @param {(String|String[])} [protocols] The subprotocols\n * @param {Object} [options] Connection options\n */\n constructor(address, protocols, options) {\n super();\n\n this._binaryType = BINARY_TYPES[0];\n this._closeCode = 1006;\n this._closeFrameReceived = false;\n this._closeFrameSent = false;\n this._closeMessage = EMPTY_BUFFER;\n this._closeTimer = null;\n this._errorEmitted = false;\n this._extensions = {};\n this._paused = false;\n this._protocol = '';\n this._readyState = WebSocket.CONNECTING;\n this._receiver = null;\n this._sender = null;\n this._socket = null;\n\n if (address !== null) {\n this._bufferedAmount = 0;\n this._isServer = false;\n this._redirects = 0;\n\n if (protocols === undefined) {\n protocols = [];\n } else if (!Array.isArray(protocols)) {\n if (typeof protocols === 'object' && protocols !== null) {\n options = protocols;\n protocols = [];\n } else {\n protocols = [protocols];\n }\n }\n\n initAsClient(this, address, protocols, options);\n } else {\n this._autoPong = options.autoPong;\n this._closeTimeout = options.closeTimeout;\n this._isServer = true;\n }\n }\n\n /**\n * For historical reasons, the custom \"nodebuffer\" type is used by the default\n * instead of \"blob\".\n *\n * @type {String}\n */\n get binaryType() {\n return this._binaryType;\n }\n\n set binaryType(type) {\n if (!BINARY_TYPES.includes(type)) return;\n\n this._binaryType = type;\n\n //\n // Allow to change `binaryType` on the fly.\n //\n if (this._receiver) this._receiver._binaryType = type;\n }\n\n /**\n * @type {Number}\n */\n get bufferedAmount() {\n if (!this._socket) return this._bufferedAmount;\n\n return this._socket._writableState.length + this._sender._bufferedBytes;\n }\n\n /**\n * @type {String}\n */\n get extensions() {\n return Object.keys(this._extensions).join();\n }\n\n /**\n * @type {Boolean}\n */\n get isPaused() {\n return this._paused;\n }\n\n /**\n * @type {Function}\n */\n /* istanbul ignore next */\n get onclose() {\n return null;\n }\n\n /**\n * @type {Function}\n */\n /* istanbul ignore next */\n get onerror() {\n return null;\n }\n\n /**\n * @type {Function}\n */\n /* istanbul ignore next */\n get onopen() {\n return null;\n }\n\n /**\n * @type {Function}\n */\n /* istanbul ignore next */\n get onmessage() {\n return null;\n }\n\n /**\n * @type {String}\n */\n get protocol() {\n return this._protocol;\n }\n\n /**\n * @type {Number}\n */\n get readyState() {\n return this._readyState;\n }\n\n /**\n * @type {String}\n */\n get url() {\n return this._url;\n }\n\n /**\n * Set up the socket and the internal resources.\n *\n * @param {Duplex} socket The network socket between the server and client\n * @param {Buffer} head The first packet of the upgraded stream\n * @param {Object} options Options object\n * @param {Boolean} [options.allowSynchronousEvents=false] Specifies whether\n * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted\n * multiple times in the same tick\n * @param {Function} [options.generateMask] The function used to generate the\n * masking key\n * @param {Number} [options.maxPayload=0] The maximum allowed message size\n * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or\n * not to skip UTF-8 validation for text and close messages\n * @private\n */\n setSocket(socket, head, options) {\n const receiver = new Receiver({\n allowSynchronousEvents: options.allowSynchronousEvents,\n binaryType: this.binaryType,\n extensions: this._extensions,\n isServer: this._isServer,\n maxPayload: options.maxPayload,\n skipUTF8Validation: options.skipUTF8Validation\n });\n\n const sender = new Sender(socket, this._extensions, options.generateMask);\n\n this._receiver = receiver;\n this._sender = sender;\n this._socket = socket;\n\n receiver[kWebSocket] = this;\n sender[kWebSocket] = this;\n socket[kWebSocket] = this;\n\n receiver.on('conclude', receiverOnConclude);\n receiver.on('drain', receiverOnDrain);\n receiver.on('error', receiverOnError);\n receiver.on('message', receiverOnMessage);\n receiver.on('ping', receiverOnPing);\n receiver.on('pong', receiverOnPong);\n\n sender.onerror = senderOnError;\n\n //\n // These methods may not be available if `socket` is just a `Duplex`.\n //\n if (socket.setTimeout) socket.setTimeout(0);\n if (socket.setNoDelay) socket.setNoDelay();\n\n if (head.length > 0) socket.unshift(head);\n\n socket.on('close', socketOnClose);\n socket.on('data', socketOnData);\n socket.on('end', socketOnEnd);\n socket.on('error', socketOnError);\n\n this._readyState = WebSocket.OPEN;\n this.emit('open');\n }\n\n /**\n * Emit the `'close'` event.\n *\n * @private\n */\n emitClose() {\n if (!this._socket) {\n this._readyState = WebSocket.CLOSED;\n this.emit('close', this._closeCode, this._closeMessage);\n return;\n }\n\n if (this._extensions[PerMessageDeflate.extensionName]) {\n this._extensions[PerMessageDeflate.extensionName].cleanup();\n }\n\n this._receiver.removeAllListeners();\n this._readyState = WebSocket.CLOSED;\n this.emit('close', this._closeCode, this._closeMessage);\n }\n\n /**\n * Start a closing handshake.\n *\n * +----------+ +-----------+ +----------+\n * - - -|ws.close()|-->|close frame|-->|ws.close()|- - -\n * | +----------+ +-----------+ +----------+ |\n * +----------+ +-----------+ |\n * CLOSING |ws.close()|<--|close frame|<--+-----+ CLOSING\n * +----------+ +-----------+ |\n * | | | +---+ |\n * +------------------------+-->|fin| - - - -\n * | +---+ | +---+\n * - - - - -|fin|<---------------------+\n * +---+\n *\n * @param {Number} [code] Status code explaining why the connection is closing\n * @param {(String|Buffer)} [data] The reason why the connection is\n * closing\n * @public\n */\n close(code, data) {\n if (this.readyState === WebSocket.CLOSED) return;\n if (this.readyState === WebSocket.CONNECTING) {\n const msg = 'WebSocket was closed before the connection was established';\n abortHandshake(this, this._req, msg);\n return;\n }\n\n if (this.readyState === WebSocket.CLOSING) {\n if (\n this._closeFrameSent &&\n (this._closeFrameReceived || this._receiver._writableState.errorEmitted)\n ) {\n this._socket.end();\n }\n\n return;\n }\n\n this._readyState = WebSocket.CLOSING;\n this._sender.close(code, data, !this._isServer, (err) => {\n //\n // This error is handled by the `'error'` listener on the socket. We only\n // want to know if the close frame has been sent here.\n //\n if (err) return;\n\n this._closeFrameSent = true;\n\n if (\n this._closeFrameReceived ||\n this._receiver._writableState.errorEmitted\n ) {\n this._socket.end();\n }\n });\n\n setCloseTimer(this);\n }\n\n /**\n * Pause the socket.\n *\n * @public\n */\n pause() {\n if (\n this.readyState === WebSocket.CONNECTING ||\n this.readyState === WebSocket.CLOSED\n ) {\n return;\n }\n\n this._paused = true;\n this._socket.pause();\n }\n\n /**\n * Send a ping.\n *\n * @param {*} [data] The data to send\n * @param {Boolean} [mask] Indicates whether or not to mask `data`\n * @param {Function} [cb] Callback which is executed when the ping is sent\n * @public\n */\n ping(data, mask, cb) {\n if (this.readyState === WebSocket.CONNECTING) {\n throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');\n }\n\n if (typeof data === 'function') {\n cb = data;\n data = mask = undefined;\n } else if (typeof mask === 'function') {\n cb = mask;\n mask = undefined;\n }\n\n if (typeof data === 'number') data = data.toString();\n\n if (this.readyState !== WebSocket.OPEN) {\n sendAfterClose(this, data, cb);\n return;\n }\n\n if (mask === undefined) mask = !this._isServer;\n this._sender.ping(data || EMPTY_BUFFER, mask, cb);\n }\n\n /**\n * Send a pong.\n *\n * @param {*} [data] The data to send\n * @param {Boolean} [mask] Indicates whether or not to mask `data`\n * @param {Function} [cb] Callback which is executed when the pong is sent\n * @public\n */\n pong(data, mask, cb) {\n if (this.readyState === WebSocket.CONNECTING) {\n throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');\n }\n\n if (typeof data === 'function') {\n cb = data;\n data = mask = undefined;\n } else if (typeof mask === 'function') {\n cb = mask;\n mask = undefined;\n }\n\n if (typeof data === 'number') data = data.toString();\n\n if (this.readyState !== WebSocket.OPEN) {\n sendAfterClose(this, data, cb);\n return;\n }\n\n if (mask === undefined) mask = !this._isServer;\n this._sender.pong(data || EMPTY_BUFFER, mask, cb);\n }\n\n /**\n * Resume the socket.\n *\n * @public\n */\n resume() {\n if (\n this.readyState === WebSocket.CONNECTING ||\n this.readyState === WebSocket.CLOSED\n ) {\n return;\n }\n\n this._paused = false;\n if (!this._receiver._writableState.needDrain) this._socket.resume();\n }\n\n /**\n * Send a data message.\n *\n * @param {*} data The message to send\n * @param {Object} [options] Options object\n * @param {Boolean} [options.binary] Specifies whether `data` is binary or\n * text\n * @param {Boolean} [options.compress] Specifies whether or not to compress\n * `data`\n * @param {Boolean} [options.fin=true] Specifies whether the fragment is the\n * last one\n * @param {Boolean} [options.mask] Specifies whether or not to mask `data`\n * @param {Function} [cb] Callback which is executed when data is written out\n * @public\n */\n send(data, options, cb) {\n if (this.readyState === WebSocket.CONNECTING) {\n throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');\n }\n\n if (typeof options === 'function') {\n cb = options;\n options = {};\n }\n\n if (typeof data === 'number') data = data.toString();\n\n if (this.readyState !== WebSocket.OPEN) {\n sendAfterClose(this, data, cb);\n return;\n }\n\n const opts = {\n binary: typeof data !== 'string',\n mask: !this._isServer,\n compress: true,\n fin: true,\n ...options\n };\n\n if (!this._extensions[PerMessageDeflate.extensionName]) {\n opts.compress = false;\n }\n\n this._sender.send(data || EMPTY_BUFFER, opts, cb);\n }\n\n /**\n * Forcibly close the connection.\n *\n * @public\n */\n terminate() {\n if (this.readyState === WebSocket.CLOSED) return;\n if (this.readyState === WebSocket.CONNECTING) {\n const msg = 'WebSocket was closed before the connection was established';\n abortHandshake(this, this._req, msg);\n return;\n }\n\n if (this._socket) {\n this._readyState = WebSocket.CLOSING;\n this._socket.destroy();\n }\n }\n}\n\n/**\n * @constant {Number} CONNECTING\n * @memberof WebSocket\n */\nObject.defineProperty(WebSocket, 'CONNECTING', {\n enumerable: true,\n value: readyStates.indexOf('CONNECTING')\n});\n\n/**\n * @constant {Number} CONNECTING\n * @memberof WebSocket.prototype\n */\nObject.defineProperty(WebSocket.prototype, 'CONNECTING', {\n enumerable: true,\n value: readyStates.indexOf('CONNECTING')\n});\n\n/**\n * @constant {Number} OPEN\n * @memberof WebSocket\n */\nObject.defineProperty(WebSocket, 'OPEN', {\n enumerable: true,\n value: readyStates.indexOf('OPEN')\n});\n\n/**\n * @constant {Number} OPEN\n * @memberof WebSocket.prototype\n */\nObject.defineProperty(WebSocket.prototype, 'OPEN', {\n enumerable: true,\n value: readyStates.indexOf('OPEN')\n});\n\n/**\n * @constant {Number} CLOSING\n * @memberof WebSocket\n */\nObject.defineProperty(WebSocket, 'CLOSING', {\n enumerable: true,\n value: readyStates.indexOf('CLOSING')\n});\n\n/**\n * @constant {Number} CLOSING\n * @memberof WebSocket.prototype\n */\nObject.defineProperty(WebSocket.prototype, 'CLOSING', {\n enumerable: true,\n value: readyStates.indexOf('CLOSING')\n});\n\n/**\n * @constant {Number} CLOSED\n * @memberof WebSocket\n */\nObject.defineProperty(WebSocket, 'CLOSED', {\n enumerable: true,\n value: readyStates.indexOf('CLOSED')\n});\n\n/**\n * @constant {Number} CLOSED\n * @memberof WebSocket.prototype\n */\nObject.defineProperty(WebSocket.prototype, 'CLOSED', {\n enumerable: true,\n value: readyStates.indexOf('CLOSED')\n});\n\n[\n 'binaryType',\n 'bufferedAmount',\n 'extensions',\n 'isPaused',\n 'protocol',\n 'readyState',\n 'url'\n].forEach((property) => {\n Object.defineProperty(WebSocket.prototype, property, { enumerable: true });\n});\n\n//\n// Add the `onopen`, `onerror`, `onclose`, and `onmessage` attributes.\n// See https://html.spec.whatwg.org/multipage/comms.html#the-websocket-interface\n//\n['open', 'error', 'close', 'message'].forEach((method) => {\n Object.defineProperty(WebSocket.prototype, `on${method}`, {\n enumerable: true,\n get() {\n for (const listener of this.listeners(method)) {\n if (listener[kForOnEventAttribute]) return listener[kListener];\n }\n\n return null;\n },\n set(handler) {\n for (const listener of this.listeners(method)) {\n if (listener[kForOnEventAttribute]) {\n this.removeListener(method, listener);\n break;\n }\n }\n\n if (typeof handler !== 'function') return;\n\n this.addEventListener(method, handler, {\n [kForOnEventAttribute]: true\n });\n }\n });\n});\n\nWebSocket.prototype.addEventListener = addEventListener;\nWebSocket.prototype.removeEventListener = removeEventListener;\n\nmodule.exports = WebSocket;\n\n/**\n * Initialize a WebSocket client.\n *\n * @param {WebSocket} websocket The client to initialize\n * @param {(String|URL)} address The URL to which to connect\n * @param {Array} protocols The subprotocols\n * @param {Object} [options] Connection options\n * @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether any\n * of the `'message'`, `'ping'`, and `'pong'` events can be emitted multiple\n * times in the same tick\n * @param {Boolean} [options.autoPong=true] Specifies whether or not to\n * automatically send a pong in response to a ping\n * @param {Number} [options.closeTimeout=30000] Duration in milliseconds to wait\n * for the closing handshake to finish after `websocket.close()` is called\n * @param {Function} [options.finishRequest] A function which can be used to\n * customize the headers of each http request before it is sent\n * @param {Boolean} [options.followRedirects=false] Whether or not to follow\n * redirects\n * @param {Function} [options.generateMask] The function used to generate the\n * masking key\n * @param {Number} [options.handshakeTimeout] Timeout in milliseconds for the\n * handshake request\n * @param {Number} [options.maxPayload=104857600] The maximum allowed message\n * size\n * @param {Number} [options.maxRedirects=10] The maximum number of redirects\n * allowed\n * @param {String} [options.origin] Value of the `Origin` or\n * `Sec-WebSocket-Origin` header\n * @param {(Boolean|Object)} [options.perMessageDeflate=true] Enable/disable\n * permessage-deflate\n * @param {Number} [options.protocolVersion=13] Value of the\n * `Sec-WebSocket-Version` header\n * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or\n * not to skip UTF-8 validation for text and close messages\n * @private\n */\nfunction initAsClient(websocket, address, protocols, options) {\n const opts = {\n allowSynchronousEvents: true,\n autoPong: true,\n closeTimeout: CLOSE_TIMEOUT,\n protocolVersion: protocolVersions[1],\n maxPayload: 100 * 1024 * 1024,\n skipUTF8Validation: false,\n perMessageDeflate: true,\n followRedirects: false,\n maxRedirects: 10,\n ...options,\n socketPath: undefined,\n hostname: undefined,\n protocol: undefined,\n timeout: undefined,\n method: 'GET',\n host: undefined,\n path: undefined,\n port: undefined\n };\n\n websocket._autoPong = opts.autoPong;\n websocket._closeTimeout = opts.closeTimeout;\n\n if (!protocolVersions.includes(opts.protocolVersion)) {\n throw new RangeError(\n `Unsupported protocol version: ${opts.protocolVersion} ` +\n `(supported versions: ${protocolVersions.join(', ')})`\n );\n }\n\n let parsedUrl;\n\n if (address instanceof URL) {\n parsedUrl = address;\n } else {\n try {\n parsedUrl = new URL(address);\n } catch (e) {\n throw new SyntaxError(`Invalid URL: ${address}`);\n }\n }\n\n if (parsedUrl.protocol === 'http:') {\n parsedUrl.protocol = 'ws:';\n } else if (parsedUrl.protocol === 'https:') {\n parsedUrl.protocol = 'wss:';\n }\n\n websocket._url = parsedUrl.href;\n\n const isSecure = parsedUrl.protocol === 'wss:';\n const isIpcUrl = parsedUrl.protocol === 'ws+unix:';\n let invalidUrlMessage;\n\n if (parsedUrl.protocol !== 'ws:' && !isSecure && !isIpcUrl) {\n invalidUrlMessage =\n 'The URL\\'s protocol must be one of \"ws:\", \"wss:\", ' +\n '\"http:\", \"https:\", or \"ws+unix:\"';\n } else if (isIpcUrl && !parsedUrl.pathname) {\n invalidUrlMessage = \"The URL's pathname is empty\";\n } else if (parsedUrl.hash) {\n invalidUrlMessage = 'The URL contains a fragment identifier';\n }\n\n if (invalidUrlMessage) {\n const err = new SyntaxError(invalidUrlMessage);\n\n if (websocket._redirects === 0) {\n throw err;\n } else {\n emitErrorAndClose(websocket, err);\n return;\n }\n }\n\n const defaultPort = isSecure ? 443 : 80;\n const key = randomBytes(16).toString('base64');\n const request = isSecure ? https.request : http.request;\n const protocolSet = new Set();\n let perMessageDeflate;\n\n opts.createConnection =\n opts.createConnection || (isSecure ? tlsConnect : netConnect);\n opts.defaultPort = opts.defaultPort || defaultPort;\n opts.port = parsedUrl.port || defaultPort;\n opts.host = parsedUrl.hostname.startsWith('[')\n ? parsedUrl.hostname.slice(1, -1)\n : parsedUrl.hostname;\n opts.headers = {\n ...opts.headers,\n 'Sec-WebSocket-Version': opts.protocolVersion,\n 'Sec-WebSocket-Key': key,\n Connection: 'Upgrade',\n Upgrade: 'websocket'\n };\n opts.path = parsedUrl.pathname + parsedUrl.search;\n opts.timeout = opts.handshakeTimeout;\n\n if (opts.perMessageDeflate) {\n perMessageDeflate = new PerMessageDeflate(\n opts.perMessageDeflate !== true ? opts.perMessageDeflate : {},\n false,\n opts.maxPayload\n );\n opts.headers['Sec-WebSocket-Extensions'] = format({\n [PerMessageDeflate.extensionName]: perMessageDeflate.offer()\n });\n }\n if (protocols.length) {\n for (const protocol of protocols) {\n if (\n typeof protocol !== 'string' ||\n !subprotocolRegex.test(protocol) ||\n protocolSet.has(protocol)\n ) {\n throw new SyntaxError(\n 'An invalid or duplicated subprotocol was specified'\n );\n }\n\n protocolSet.add(protocol);\n }\n\n opts.headers['Sec-WebSocket-Protocol'] = protocols.join(',');\n }\n if (opts.origin) {\n if (opts.protocolVersion < 13) {\n opts.headers['Sec-WebSocket-Origin'] = opts.origin;\n } else {\n opts.headers.Origin = opts.origin;\n }\n }\n if (parsedUrl.username || parsedUrl.password) {\n opts.auth = `${parsedUrl.username}:${parsedUrl.password}`;\n }\n\n if (isIpcUrl) {\n const parts = opts.path.split(':');\n\n opts.socketPath = parts[0];\n opts.path = parts[1];\n }\n\n let req;\n\n if (opts.followRedirects) {\n if (websocket._redirects === 0) {\n websocket._originalIpc = isIpcUrl;\n websocket._originalSecure = isSecure;\n websocket._originalHostOrSocketPath = isIpcUrl\n ? opts.socketPath\n : parsedUrl.host;\n\n const headers = options && options.headers;\n\n //\n // Shallow copy the user provided options so that headers can be changed\n // without mutating the original object.\n //\n options = { ...options, headers: {} };\n\n if (headers) {\n for (const [key, value] of Object.entries(headers)) {\n options.headers[key.toLowerCase()] = value;\n }\n }\n } else if (websocket.listenerCount('redirect') === 0) {\n const isSameHost = isIpcUrl\n ? websocket._originalIpc\n ? opts.socketPath === websocket._originalHostOrSocketPath\n : false\n : websocket._originalIpc\n ? false\n : parsedUrl.host === websocket._originalHostOrSocketPath;\n\n if (!isSameHost || (websocket._originalSecure && !isSecure)) {\n //\n // Match curl 7.77.0 behavior and drop the following headers. These\n // headers are also dropped when following a redirect to a subdomain.\n //\n delete opts.headers.authorization;\n delete opts.headers.cookie;\n\n if (!isSameHost) delete opts.headers.host;\n\n opts.auth = undefined;\n }\n }\n\n //\n // Match curl 7.77.0 behavior and make the first `Authorization` header win.\n // If the `Authorization` header is set, then there is nothing to do as it\n // will take precedence.\n //\n if (opts.auth && !options.headers.authorization) {\n options.headers.authorization =\n 'Basic ' + Buffer.from(opts.auth).toString('base64');\n }\n\n req = websocket._req = request(opts);\n\n if (websocket._redirects) {\n //\n // Unlike what is done for the `'upgrade'` event, no early exit is\n // triggered here if the user calls `websocket.close()` or\n // `websocket.terminate()` from a listener of the `'redirect'` event. This\n // is because the user can also call `request.destroy()` with an error\n // before calling `websocket.close()` or `websocket.terminate()` and this\n // would result in an error being emitted on the `request` object with no\n // `'error'` event listeners attached.\n //\n websocket.emit('redirect', websocket.url, req);\n }\n } else {\n req = websocket._req = request(opts);\n }\n\n if (opts.timeout) {\n req.on('timeout', () => {\n abortHandshake(websocket, req, 'Opening handshake has timed out');\n });\n }\n\n req.on('error', (err) => {\n if (req === null || req[kAborted]) return;\n\n req = websocket._req = null;\n emitErrorAndClose(websocket, err);\n });\n\n req.on('response', (res) => {\n const location = res.headers.location;\n const statusCode = res.statusCode;\n\n if (\n location &&\n opts.followRedirects &&\n statusCode >= 300 &&\n statusCode < 400\n ) {\n if (++websocket._redirects > opts.maxRedirects) {\n abortHandshake(websocket, req, 'Maximum redirects exceeded');\n return;\n }\n\n req.abort();\n\n let addr;\n\n try {\n addr = new URL(location, address);\n } catch (e) {\n const err = new SyntaxError(`Invalid URL: ${location}`);\n emitErrorAndClose(websocket, err);\n return;\n }\n\n initAsClient(websocket, addr, protocols, options);\n } else if (!websocket.emit('unexpected-response', req, res)) {\n abortHandshake(\n websocket,\n req,\n `Unexpected server response: ${res.statusCode}`\n );\n }\n });\n\n req.on('upgrade', (res, socket, head) => {\n websocket.emit('upgrade', res);\n\n //\n // The user may have closed the connection from a listener of the\n // `'upgrade'` event.\n //\n if (websocket.readyState !== WebSocket.CONNECTING) return;\n\n req = websocket._req = null;\n\n const upgrade = res.headers.upgrade;\n\n if (upgrade === undefined || upgrade.toLowerCase() !== 'websocket') {\n abortHandshake(websocket, socket, 'Invalid Upgrade header');\n return;\n }\n\n const digest = createHash('sha1')\n .update(key + GUID)\n .digest('base64');\n\n if (res.headers['sec-websocket-accept'] !== digest) {\n abortHandshake(websocket, socket, 'Invalid Sec-WebSocket-Accept header');\n return;\n }\n\n const serverProt = res.headers['sec-websocket-protocol'];\n let protError;\n\n if (serverProt !== undefined) {\n if (!protocolSet.size) {\n protError = 'Server sent a subprotocol but none was requested';\n } else if (!protocolSet.has(serverProt)) {\n protError = 'Server sent an invalid subprotocol';\n }\n } else if (protocolSet.size) {\n protError = 'Server sent no subprotocol';\n }\n\n if (protError) {\n abortHandshake(websocket, socket, protError);\n return;\n }\n\n if (serverProt) websocket._protocol = serverProt;\n\n const secWebSocketExtensions = res.headers['sec-websocket-extensions'];\n\n if (secWebSocketExtensions !== undefined) {\n if (!perMessageDeflate) {\n const message =\n 'Server sent a Sec-WebSocket-Extensions header but no extension ' +\n 'was requested';\n abortHandshake(websocket, socket, message);\n return;\n }\n\n let extensions;\n\n try {\n extensions = parse(secWebSocketExtensions);\n } catch (err) {\n const message = 'Invalid Sec-WebSocket-Extensions header';\n abortHandshake(websocket, socket, message);\n return;\n }\n\n const extensionNames = Object.keys(extensions);\n\n if (\n extensionNames.length !== 1 ||\n extensionNames[0] !== PerMessageDeflate.extensionName\n ) {\n const message = 'Server indicated an extension that was not requested';\n abortHandshake(websocket, socket, message);\n return;\n }\n\n try {\n perMessageDeflate.accept(extensions[PerMessageDeflate.extensionName]);\n } catch (err) {\n const message = 'Invalid Sec-WebSocket-Extensions header';\n abortHandshake(websocket, socket, message);\n return;\n }\n\n websocket._extensions[PerMessageDeflate.extensionName] =\n perMessageDeflate;\n }\n\n websocket.setSocket(socket, head, {\n allowSynchronousEvents: opts.allowSynchronousEvents,\n generateMask: opts.generateMask,\n maxPayload: opts.maxPayload,\n skipUTF8Validation: opts.skipUTF8Validation\n });\n });\n\n if (opts.finishRequest) {\n opts.finishRequest(req, websocket);\n } else {\n req.end();\n }\n}\n\n/**\n * Emit the `'error'` and `'close'` events.\n *\n * @param {WebSocket} websocket The WebSocket instance\n * @param {Error} The error to emit\n * @private\n */\nfunction emitErrorAndClose(websocket, err) {\n websocket._readyState = WebSocket.CLOSING;\n //\n // The following assignment is practically useless and is done only for\n // consistency.\n //\n websocket._errorEmitted = true;\n websocket.emit('error', err);\n websocket.emitClose();\n}\n\n/**\n * Create a `net.Socket` and initiate a connection.\n *\n * @param {Object} options Connection options\n * @return {net.Socket} The newly created socket used to start the connection\n * @private\n */\nfunction netConnect(options) {\n options.path = options.socketPath;\n return net.connect(options);\n}\n\n/**\n * Create a `tls.TLSSocket` and initiate a connection.\n *\n * @param {Object} options Connection options\n * @return {tls.TLSSocket} The newly created socket used to start the connection\n * @private\n */\nfunction tlsConnect(options) {\n options.path = undefined;\n\n if (!options.servername && options.servername !== '') {\n options.servername = net.isIP(options.host) ? '' : options.host;\n }\n\n return tls.connect(options);\n}\n\n/**\n * Abort the handshake and emit an error.\n *\n * @param {WebSocket} websocket The WebSocket instance\n * @param {(http.ClientRequest|net.Socket|tls.Socket)} stream The request to\n * abort or the socket to destroy\n * @param {String} message The error message\n * @private\n */\nfunction abortHandshake(websocket, stream, message) {\n websocket._readyState = WebSocket.CLOSING;\n\n const err = new Error(message);\n Error.captureStackTrace(err, abortHandshake);\n\n if (stream.setHeader) {\n stream[kAborted] = true;\n stream.abort();\n\n if (stream.socket && !stream.socket.destroyed) {\n //\n // On Node.js >= 14.3.0 `request.abort()` does not destroy the socket if\n // called after the request completed. See\n // https://github.com/websockets/ws/issues/1869.\n //\n stream.socket.destroy();\n }\n\n process.nextTick(emitErrorAndClose, websocket, err);\n } else {\n stream.destroy(err);\n stream.once('error', websocket.emit.bind(websocket, 'error'));\n stream.once('close', websocket.emitClose.bind(websocket));\n }\n}\n\n/**\n * Handle cases where the `ping()`, `pong()`, or `send()` methods are called\n * when the `readyState` attribute is `CLOSING` or `CLOSED`.\n *\n * @param {WebSocket} websocket The WebSocket instance\n * @param {*} [data] The data to send\n * @param {Function} [cb] Callback\n * @private\n */\nfunction sendAfterClose(websocket, data, cb) {\n if (data) {\n const length = isBlob(data) ? data.size : toBuffer(data).length;\n\n //\n // The `_bufferedAmount` property is used only when the peer is a client and\n // the opening handshake fails. Under these circumstances, in fact, the\n // `setSocket()` method is not called, so the `_socket` and `_sender`\n // properties are set to `null`.\n //\n if (websocket._socket) websocket._sender._bufferedBytes += length;\n else websocket._bufferedAmount += length;\n }\n\n if (cb) {\n const err = new Error(\n `WebSocket is not open: readyState ${websocket.readyState} ` +\n `(${readyStates[websocket.readyState]})`\n );\n process.nextTick(cb, err);\n }\n}\n\n/**\n * The listener of the `Receiver` `'conclude'` event.\n *\n * @param {Number} code The status code\n * @param {Buffer} reason The reason for closing\n * @private\n */\nfunction receiverOnConclude(code, reason) {\n const websocket = this[kWebSocket];\n\n websocket._closeFrameReceived = true;\n websocket._closeMessage = reason;\n websocket._closeCode = code;\n\n if (websocket._socket[kWebSocket] === undefined) return;\n\n websocket._socket.removeListener('data', socketOnData);\n process.nextTick(resume, websocket._socket);\n\n if (code === 1005) websocket.close();\n else websocket.close(code, reason);\n}\n\n/**\n * The listener of the `Receiver` `'drain'` event.\n *\n * @private\n */\nfunction receiverOnDrain() {\n const websocket = this[kWebSocket];\n\n if (!websocket.isPaused) websocket._socket.resume();\n}\n\n/**\n * The listener of the `Receiver` `'error'` event.\n *\n * @param {(RangeError|Error)} err The emitted error\n * @private\n */\nfunction receiverOnError(err) {\n const websocket = this[kWebSocket];\n\n if (websocket._socket[kWebSocket] !== undefined) {\n websocket._socket.removeListener('data', socketOnData);\n\n //\n // On Node.js < 14.0.0 the `'error'` event is emitted synchronously. See\n // https://github.com/websockets/ws/issues/1940.\n //\n process.nextTick(resume, websocket._socket);\n\n websocket.close(err[kStatusCode]);\n }\n\n if (!websocket._errorEmitted) {\n websocket._errorEmitted = true;\n websocket.emit('error', err);\n }\n}\n\n/**\n * The listener of the `Receiver` `'finish'` event.\n *\n * @private\n */\nfunction receiverOnFinish() {\n this[kWebSocket].emitClose();\n}\n\n/**\n * The listener of the `Receiver` `'message'` event.\n *\n * @param {Buffer|ArrayBuffer|Buffer[])} data The message\n * @param {Boolean} isBinary Specifies whether the message is binary or not\n * @private\n */\nfunction receiverOnMessage(data, isBinary) {\n this[kWebSocket].emit('message', data, isBinary);\n}\n\n/**\n * The listener of the `Receiver` `'ping'` event.\n *\n * @param {Buffer} data The data included in the ping frame\n * @private\n */\nfunction receiverOnPing(data) {\n const websocket = this[kWebSocket];\n\n if (websocket._autoPong) websocket.pong(data, !this._isServer, NOOP);\n websocket.emit('ping', data);\n}\n\n/**\n * The listener of the `Receiver` `'pong'` event.\n *\n * @param {Buffer} data The data included in the pong frame\n * @private\n */\nfunction receiverOnPong(data) {\n this[kWebSocket].emit('pong', data);\n}\n\n/**\n * Resume a readable stream\n *\n * @param {Readable} stream The readable stream\n * @private\n */\nfunction resume(stream) {\n stream.resume();\n}\n\n/**\n * The `Sender` error event handler.\n *\n * @param {Error} The error\n * @private\n */\nfunction senderOnError(err) {\n const websocket = this[kWebSocket];\n\n if (websocket.readyState === WebSocket.CLOSED) return;\n if (websocket.readyState === WebSocket.OPEN) {\n websocket._readyState = WebSocket.CLOSING;\n setCloseTimer(websocket);\n }\n\n //\n // `socket.end()` is used instead of `socket.destroy()` to allow the other\n // peer to finish sending queued data. There is no need to set a timer here\n // because `CLOSING` means that it is already set or not needed.\n //\n this._socket.end();\n\n if (!websocket._errorEmitted) {\n websocket._errorEmitted = true;\n websocket.emit('error', err);\n }\n}\n\n/**\n * Set a timer to destroy the underlying raw socket of a WebSocket.\n *\n * @param {WebSocket} websocket The WebSocket instance\n * @private\n */\nfunction setCloseTimer(websocket) {\n websocket._closeTimer = setTimeout(\n websocket._socket.destroy.bind(websocket._socket),\n websocket._closeTimeout\n );\n}\n\n/**\n * The listener of the socket `'close'` event.\n *\n * @private\n */\nfunction socketOnClose() {\n const websocket = this[kWebSocket];\n\n this.removeListener('close', socketOnClose);\n this.removeListener('data', socketOnData);\n this.removeListener('end', socketOnEnd);\n\n websocket._readyState = WebSocket.CLOSING;\n\n //\n // The close frame might not have been received or the `'end'` event emitted,\n // for example, if the socket was destroyed due to an error. Ensure that the\n // `receiver` stream is closed after writing any remaining buffered data to\n // it. If the readable side of the socket is in flowing mode then there is no\n // buffered data as everything has been already written. If instead, the\n // socket is paused, any possible buffered data will be read as a single\n // chunk.\n //\n if (\n !this._readableState.endEmitted &&\n !websocket._closeFrameReceived &&\n !websocket._receiver._writableState.errorEmitted &&\n this._readableState.length !== 0\n ) {\n const chunk = this.read(this._readableState.length);\n\n websocket._receiver.write(chunk);\n }\n\n websocket._receiver.end();\n\n this[kWebSocket] = undefined;\n\n clearTimeout(websocket._closeTimer);\n\n if (\n websocket._receiver._writableState.finished ||\n websocket._receiver._writableState.errorEmitted\n ) {\n websocket.emitClose();\n } else {\n websocket._receiver.on('error', receiverOnFinish);\n websocket._receiver.on('finish', receiverOnFinish);\n }\n}\n\n/**\n * The listener of the socket `'data'` event.\n *\n * @param {Buffer} chunk A chunk of data\n * @private\n */\nfunction socketOnData(chunk) {\n if (!this[kWebSocket]._receiver.write(chunk)) {\n this.pause();\n }\n}\n\n/**\n * The listener of the socket `'end'` event.\n *\n * @private\n */\nfunction socketOnEnd() {\n const websocket = this[kWebSocket];\n\n websocket._readyState = WebSocket.CLOSING;\n websocket._receiver.end();\n this.end();\n}\n\n/**\n * The listener of the socket `'error'` event.\n *\n * @private\n */\nfunction socketOnError() {\n const websocket = this[kWebSocket];\n\n this.removeListener('error', socketOnError);\n this.on('error', NOOP);\n\n if (websocket) {\n websocket._readyState = WebSocket.CLOSING;\n this.destroy();\n }\n}\n","/* eslint no-unused-vars: [\"error\", { \"varsIgnorePattern\": \"^WebSocket$\" }] */\n'use strict';\n\nconst WebSocket = require('./websocket');\nconst { Duplex } = require('stream');\n\n/**\n * Emits the `'close'` event on a stream.\n *\n * @param {Duplex} stream The stream.\n * @private\n */\nfunction emitClose(stream) {\n stream.emit('close');\n}\n\n/**\n * The listener of the `'end'` event.\n *\n * @private\n */\nfunction duplexOnEnd() {\n if (!this.destroyed && this._writableState.finished) {\n this.destroy();\n }\n}\n\n/**\n * The listener of the `'error'` event.\n *\n * @param {Error} err The error\n * @private\n */\nfunction duplexOnError(err) {\n this.removeListener('error', duplexOnError);\n this.destroy();\n if (this.listenerCount('error') === 0) {\n // Do not suppress the throwing behavior.\n this.emit('error', err);\n }\n}\n\n/**\n * Wraps a `WebSocket` in a duplex stream.\n *\n * @param {WebSocket} ws The `WebSocket` to wrap\n * @param {Object} [options] The options for the `Duplex` constructor\n * @return {Duplex} The duplex stream\n * @public\n */\nfunction createWebSocketStream(ws, options) {\n let terminateOnDestroy = true;\n\n const duplex = new Duplex({\n ...options,\n autoDestroy: false,\n emitClose: false,\n objectMode: false,\n writableObjectMode: false\n });\n\n ws.on('message', function message(msg, isBinary) {\n const data =\n !isBinary && duplex._readableState.objectMode ? msg.toString() : msg;\n\n if (!duplex.push(data)) ws.pause();\n });\n\n ws.once('error', function error(err) {\n if (duplex.destroyed) return;\n\n // Prevent `ws.terminate()` from being called by `duplex._destroy()`.\n //\n // - If the `'error'` event is emitted before the `'open'` event, then\n // `ws.terminate()` is a noop as no socket is assigned.\n // - Otherwise, the error is re-emitted by the listener of the `'error'`\n // event of the `Receiver` object. The listener already closes the\n // connection by calling `ws.close()`. This allows a close frame to be\n // sent to the other peer. If `ws.terminate()` is called right after this,\n // then the close frame might not be sent.\n terminateOnDestroy = false;\n duplex.destroy(err);\n });\n\n ws.once('close', function close() {\n if (duplex.destroyed) return;\n\n duplex.push(null);\n });\n\n duplex._destroy = function (err, callback) {\n if (ws.readyState === ws.CLOSED) {\n callback(err);\n process.nextTick(emitClose, duplex);\n return;\n }\n\n let called = false;\n\n ws.once('error', function error(err) {\n called = true;\n callback(err);\n });\n\n ws.once('close', function close() {\n if (!called) callback(err);\n process.nextTick(emitClose, duplex);\n });\n\n if (terminateOnDestroy) ws.terminate();\n };\n\n duplex._final = function (callback) {\n if (ws.readyState === ws.CONNECTING) {\n ws.once('open', function open() {\n duplex._final(callback);\n });\n return;\n }\n\n // If the value of the `_socket` property is `null` it means that `ws` is a\n // client websocket and the handshake failed. In fact, when this happens, a\n // socket is never assigned to the websocket. Wait for the `'error'` event\n // that will be emitted by the websocket.\n if (ws._socket === null) return;\n\n if (ws._socket._writableState.finished) {\n callback();\n if (duplex._readableState.endEmitted) duplex.destroy();\n } else {\n ws._socket.once('finish', function finish() {\n // `duplex` is not destroyed here because the `'end'` event will be\n // emitted on `duplex` after this `'finish'` event. The EOF signaling\n // `null` chunk is, in fact, pushed when the websocket emits `'close'`.\n callback();\n });\n ws.close();\n }\n };\n\n duplex._read = function () {\n if (ws.isPaused) ws.resume();\n };\n\n duplex._write = function (chunk, encoding, callback) {\n if (ws.readyState === ws.CONNECTING) {\n ws.once('open', function open() {\n duplex._write(chunk, encoding, callback);\n });\n return;\n }\n\n ws.send(chunk, callback);\n };\n\n duplex.on('end', duplexOnEnd);\n duplex.on('error', duplexOnError);\n return duplex;\n}\n\nmodule.exports = createWebSocketStream;\n","'use strict';\n\nconst { tokenChars } = require('./validation');\n\n/**\n * Parses the `Sec-WebSocket-Protocol` header into a set of subprotocol names.\n *\n * @param {String} header The field value of the header\n * @return {Set} The subprotocol names\n * @public\n */\nfunction parse(header) {\n const protocols = new Set();\n let start = -1;\n let end = -1;\n let i = 0;\n\n for (i; i < header.length; i++) {\n const code = header.charCodeAt(i);\n\n if (end === -1 && tokenChars[code] === 1) {\n if (start === -1) start = i;\n } else if (\n i !== 0 &&\n (code === 0x20 /* ' ' */ || code === 0x09) /* '\\t' */\n ) {\n if (end === -1 && start !== -1) end = i;\n } else if (code === 0x2c /* ',' */) {\n if (start === -1) {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n\n if (end === -1) end = i;\n\n const protocol = header.slice(start, end);\n\n if (protocols.has(protocol)) {\n throw new SyntaxError(`The \"${protocol}\" subprotocol is duplicated`);\n }\n\n protocols.add(protocol);\n start = end = -1;\n } else {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n }\n\n if (start === -1 || end !== -1) {\n throw new SyntaxError('Unexpected end of input');\n }\n\n const protocol = header.slice(start, i);\n\n if (protocols.has(protocol)) {\n throw new SyntaxError(`The \"${protocol}\" subprotocol is duplicated`);\n }\n\n protocols.add(protocol);\n return protocols;\n}\n\nmodule.exports = { parse };\n","/* eslint no-unused-vars: [\"error\", { \"varsIgnorePattern\": \"^Duplex$\", \"caughtErrors\": \"none\" }] */\n\n'use strict';\n\nconst EventEmitter = require('events');\nconst http = require('http');\nconst { Duplex } = require('stream');\nconst { createHash } = require('crypto');\n\nconst extension = require('./extension');\nconst PerMessageDeflate = require('./permessage-deflate');\nconst subprotocol = require('./subprotocol');\nconst WebSocket = require('./websocket');\nconst { CLOSE_TIMEOUT, GUID, kWebSocket } = require('./constants');\n\nconst keyRegex = /^[+/0-9A-Za-z]{22}==$/;\n\nconst RUNNING = 0;\nconst CLOSING = 1;\nconst CLOSED = 2;\n\n/**\n * Class representing a WebSocket server.\n *\n * @extends EventEmitter\n */\nclass WebSocketServer extends EventEmitter {\n /**\n * Create a `WebSocketServer` instance.\n *\n * @param {Object} options Configuration options\n * @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether\n * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted\n * multiple times in the same tick\n * @param {Boolean} [options.autoPong=true] Specifies whether or not to\n * automatically send a pong in response to a ping\n * @param {Number} [options.backlog=511] The maximum length of the queue of\n * pending connections\n * @param {Boolean} [options.clientTracking=true] Specifies whether or not to\n * track clients\n * @param {Number} [options.closeTimeout=30000] Duration in milliseconds to\n * wait for the closing handshake to finish after `websocket.close()` is\n * called\n * @param {Function} [options.handleProtocols] A hook to handle protocols\n * @param {String} [options.host] The hostname where to bind the server\n * @param {Number} [options.maxPayload=104857600] The maximum allowed message\n * size\n * @param {Boolean} [options.noServer=false] Enable no server mode\n * @param {String} [options.path] Accept only connections matching this path\n * @param {(Boolean|Object)} [options.perMessageDeflate=false] Enable/disable\n * permessage-deflate\n * @param {Number} [options.port] The port where to bind the server\n * @param {(http.Server|https.Server)} [options.server] A pre-created HTTP/S\n * server to use\n * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or\n * not to skip UTF-8 validation for text and close messages\n * @param {Function} [options.verifyClient] A hook to reject connections\n * @param {Function} [options.WebSocket=WebSocket] Specifies the `WebSocket`\n * class to use. It must be the `WebSocket` class or class that extends it\n * @param {Function} [callback] A listener for the `listening` event\n */\n constructor(options, callback) {\n super();\n\n options = {\n allowSynchronousEvents: true,\n autoPong: true,\n maxPayload: 100 * 1024 * 1024,\n skipUTF8Validation: false,\n perMessageDeflate: false,\n handleProtocols: null,\n clientTracking: true,\n closeTimeout: CLOSE_TIMEOUT,\n verifyClient: null,\n noServer: false,\n backlog: null, // use default (511 as implemented in net.js)\n server: null,\n host: null,\n path: null,\n port: null,\n WebSocket,\n ...options\n };\n\n if (\n (options.port == null && !options.server && !options.noServer) ||\n (options.port != null && (options.server || options.noServer)) ||\n (options.server && options.noServer)\n ) {\n throw new TypeError(\n 'One and only one of the \"port\", \"server\", or \"noServer\" options ' +\n 'must be specified'\n );\n }\n\n if (options.port != null) {\n this._server = http.createServer((req, res) => {\n const body = http.STATUS_CODES[426];\n\n res.writeHead(426, {\n 'Content-Length': body.length,\n 'Content-Type': 'text/plain'\n });\n res.end(body);\n });\n this._server.listen(\n options.port,\n options.host,\n options.backlog,\n callback\n );\n } else if (options.server) {\n this._server = options.server;\n }\n\n if (this._server) {\n const emitConnection = this.emit.bind(this, 'connection');\n\n this._removeListeners = addListeners(this._server, {\n listening: this.emit.bind(this, 'listening'),\n error: this.emit.bind(this, 'error'),\n upgrade: (req, socket, head) => {\n this.handleUpgrade(req, socket, head, emitConnection);\n }\n });\n }\n\n if (options.perMessageDeflate === true) options.perMessageDeflate = {};\n if (options.clientTracking) {\n this.clients = new Set();\n this._shouldEmitClose = false;\n }\n\n this.options = options;\n this._state = RUNNING;\n }\n\n /**\n * Returns the bound address, the address family name, and port of the server\n * as reported by the operating system if listening on an IP socket.\n * If the server is listening on a pipe or UNIX domain socket, the name is\n * returned as a string.\n *\n * @return {(Object|String|null)} The address of the server\n * @public\n */\n address() {\n if (this.options.noServer) {\n throw new Error('The server is operating in \"noServer\" mode');\n }\n\n if (!this._server) return null;\n return this._server.address();\n }\n\n /**\n * Stop the server from accepting new connections and emit the `'close'` event\n * when all existing connections are closed.\n *\n * @param {Function} [cb] A one-time listener for the `'close'` event\n * @public\n */\n close(cb) {\n if (this._state === CLOSED) {\n if (cb) {\n this.once('close', () => {\n cb(new Error('The server is not running'));\n });\n }\n\n process.nextTick(emitClose, this);\n return;\n }\n\n if (cb) this.once('close', cb);\n\n if (this._state === CLOSING) return;\n this._state = CLOSING;\n\n if (this.options.noServer || this.options.server) {\n if (this._server) {\n this._removeListeners();\n this._removeListeners = this._server = null;\n }\n\n if (this.clients) {\n if (!this.clients.size) {\n process.nextTick(emitClose, this);\n } else {\n this._shouldEmitClose = true;\n }\n } else {\n process.nextTick(emitClose, this);\n }\n } else {\n const server = this._server;\n\n this._removeListeners();\n this._removeListeners = this._server = null;\n\n //\n // The HTTP/S server was created internally. Close it, and rely on its\n // `'close'` event.\n //\n server.close(() => {\n emitClose(this);\n });\n }\n }\n\n /**\n * See if a given request should be handled by this server instance.\n *\n * @param {http.IncomingMessage} req Request object to inspect\n * @return {Boolean} `true` if the request is valid, else `false`\n * @public\n */\n shouldHandle(req) {\n if (this.options.path) {\n const index = req.url.indexOf('?');\n const pathname = index !== -1 ? req.url.slice(0, index) : req.url;\n\n if (pathname !== this.options.path) return false;\n }\n\n return true;\n }\n\n /**\n * Handle a HTTP Upgrade request.\n *\n * @param {http.IncomingMessage} req The request object\n * @param {Duplex} socket The network socket between the server and client\n * @param {Buffer} head The first packet of the upgraded stream\n * @param {Function} cb Callback\n * @public\n */\n handleUpgrade(req, socket, head, cb) {\n socket.on('error', socketOnError);\n\n const key = req.headers['sec-websocket-key'];\n const upgrade = req.headers.upgrade;\n const version = +req.headers['sec-websocket-version'];\n\n if (req.method !== 'GET') {\n const message = 'Invalid HTTP method';\n abortHandshakeOrEmitwsClientError(this, req, socket, 405, message);\n return;\n }\n\n if (upgrade === undefined || upgrade.toLowerCase() !== 'websocket') {\n const message = 'Invalid Upgrade header';\n abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);\n return;\n }\n\n if (key === undefined || !keyRegex.test(key)) {\n const message = 'Missing or invalid Sec-WebSocket-Key header';\n abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);\n return;\n }\n\n if (version !== 13 && version !== 8) {\n const message = 'Missing or invalid Sec-WebSocket-Version header';\n abortHandshakeOrEmitwsClientError(this, req, socket, 400, message, {\n 'Sec-WebSocket-Version': '13, 8'\n });\n return;\n }\n\n if (!this.shouldHandle(req)) {\n abortHandshake(socket, 400);\n return;\n }\n\n const secWebSocketProtocol = req.headers['sec-websocket-protocol'];\n let protocols = new Set();\n\n if (secWebSocketProtocol !== undefined) {\n try {\n protocols = subprotocol.parse(secWebSocketProtocol);\n } catch (err) {\n const message = 'Invalid Sec-WebSocket-Protocol header';\n abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);\n return;\n }\n }\n\n const secWebSocketExtensions = req.headers['sec-websocket-extensions'];\n const extensions = {};\n\n if (\n this.options.perMessageDeflate &&\n secWebSocketExtensions !== undefined\n ) {\n const perMessageDeflate = new PerMessageDeflate(\n this.options.perMessageDeflate,\n true,\n this.options.maxPayload\n );\n\n try {\n const offers = extension.parse(secWebSocketExtensions);\n\n if (offers[PerMessageDeflate.extensionName]) {\n perMessageDeflate.accept(offers[PerMessageDeflate.extensionName]);\n extensions[PerMessageDeflate.extensionName] = perMessageDeflate;\n }\n } catch (err) {\n const message =\n 'Invalid or unacceptable Sec-WebSocket-Extensions header';\n abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);\n return;\n }\n }\n\n //\n // Optionally call external client verification handler.\n //\n if (this.options.verifyClient) {\n const info = {\n origin:\n req.headers[`${version === 8 ? 'sec-websocket-origin' : 'origin'}`],\n secure: !!(req.socket.authorized || req.socket.encrypted),\n req\n };\n\n if (this.options.verifyClient.length === 2) {\n this.options.verifyClient(info, (verified, code, message, headers) => {\n if (!verified) {\n return abortHandshake(socket, code || 401, message, headers);\n }\n\n this.completeUpgrade(\n extensions,\n key,\n protocols,\n req,\n socket,\n head,\n cb\n );\n });\n return;\n }\n\n if (!this.options.verifyClient(info)) return abortHandshake(socket, 401);\n }\n\n this.completeUpgrade(extensions, key, protocols, req, socket, head, cb);\n }\n\n /**\n * Upgrade the connection to WebSocket.\n *\n * @param {Object} extensions The accepted extensions\n * @param {String} key The value of the `Sec-WebSocket-Key` header\n * @param {Set} protocols The subprotocols\n * @param {http.IncomingMessage} req The request object\n * @param {Duplex} socket The network socket between the server and client\n * @param {Buffer} head The first packet of the upgraded stream\n * @param {Function} cb Callback\n * @throws {Error} If called more than once with the same socket\n * @private\n */\n completeUpgrade(extensions, key, protocols, req, socket, head, cb) {\n //\n // Destroy the socket if the client has already sent a FIN packet.\n //\n if (!socket.readable || !socket.writable) return socket.destroy();\n\n if (socket[kWebSocket]) {\n throw new Error(\n 'server.handleUpgrade() was called more than once with the same ' +\n 'socket, possibly due to a misconfiguration'\n );\n }\n\n if (this._state > RUNNING) return abortHandshake(socket, 503);\n\n const digest = createHash('sha1')\n .update(key + GUID)\n .digest('base64');\n\n const headers = [\n 'HTTP/1.1 101 Switching Protocols',\n 'Upgrade: websocket',\n 'Connection: Upgrade',\n `Sec-WebSocket-Accept: ${digest}`\n ];\n\n const ws = new this.options.WebSocket(null, undefined, this.options);\n\n if (protocols.size) {\n //\n // Optionally call external protocol selection handler.\n //\n const protocol = this.options.handleProtocols\n ? this.options.handleProtocols(protocols, req)\n : protocols.values().next().value;\n\n if (protocol) {\n headers.push(`Sec-WebSocket-Protocol: ${protocol}`);\n ws._protocol = protocol;\n }\n }\n\n if (extensions[PerMessageDeflate.extensionName]) {\n const params = extensions[PerMessageDeflate.extensionName].params;\n const value = extension.format({\n [PerMessageDeflate.extensionName]: [params]\n });\n headers.push(`Sec-WebSocket-Extensions: ${value}`);\n ws._extensions = extensions;\n }\n\n //\n // Allow external modification/inspection of handshake headers.\n //\n this.emit('headers', headers, req);\n\n socket.write(headers.concat('\\r\\n').join('\\r\\n'));\n socket.removeListener('error', socketOnError);\n\n ws.setSocket(socket, head, {\n allowSynchronousEvents: this.options.allowSynchronousEvents,\n maxPayload: this.options.maxPayload,\n skipUTF8Validation: this.options.skipUTF8Validation\n });\n\n if (this.clients) {\n this.clients.add(ws);\n ws.on('close', () => {\n this.clients.delete(ws);\n\n if (this._shouldEmitClose && !this.clients.size) {\n process.nextTick(emitClose, this);\n }\n });\n }\n\n cb(ws, req);\n }\n}\n\nmodule.exports = WebSocketServer;\n\n/**\n * Add event listeners on an `EventEmitter` using a map of <event, listener>\n * pairs.\n *\n * @param {EventEmitter} server The event emitter\n * @param {Object.<String, Function>} map The listeners to add\n * @return {Function} A function that will remove the added listeners when\n * called\n * @private\n */\nfunction addListeners(server, map) {\n for (const event of Object.keys(map)) server.on(event, map[event]);\n\n return function removeListeners() {\n for (const event of Object.keys(map)) {\n server.removeListener(event, map[event]);\n }\n };\n}\n\n/**\n * Emit a `'close'` event on an `EventEmitter`.\n *\n * @param {EventEmitter} server The event emitter\n * @private\n */\nfunction emitClose(server) {\n server._state = CLOSED;\n server.emit('close');\n}\n\n/**\n * Handle socket errors.\n *\n * @private\n */\nfunction socketOnError() {\n this.destroy();\n}\n\n/**\n * Close the connection when preconditions are not fulfilled.\n *\n * @param {Duplex} socket The socket of the upgrade request\n * @param {Number} code The HTTP response status code\n * @param {String} [message] The HTTP response body\n * @param {Object} [headers] Additional HTTP response headers\n * @private\n */\nfunction abortHandshake(socket, code, message, headers) {\n //\n // The socket is writable unless the user destroyed or ended it before calling\n // `server.handleUpgrade()` or in the `verifyClient` function, which is a user\n // error. Handling this does not make much sense as the worst that can happen\n // is that some of the data written by the user might be discarded due to the\n // call to `socket.end()` below, which triggers an `'error'` event that in\n // turn causes the socket to be destroyed.\n //\n message = message || http.STATUS_CODES[code];\n headers = {\n Connection: 'close',\n 'Content-Type': 'text/html',\n 'Content-Length': Buffer.byteLength(message),\n ...headers\n };\n\n socket.once('finish', socket.destroy);\n\n socket.end(\n `HTTP/1.1 ${code} ${http.STATUS_CODES[code]}\\r\\n` +\n Object.keys(headers)\n .map((h) => `${h}: ${headers[h]}`)\n .join('\\r\\n') +\n '\\r\\n\\r\\n' +\n message\n );\n}\n\n/**\n * Emit a `'wsClientError'` event on a `WebSocketServer` if there is at least\n * one listener for it, otherwise call `abortHandshake()`.\n *\n * @param {WebSocketServer} server The WebSocket server\n * @param {http.IncomingMessage} req The request object\n * @param {Duplex} socket The socket of the upgrade request\n * @param {Number} code The HTTP response status code\n * @param {String} message The HTTP response body\n * @param {Object} [headers] The HTTP response headers\n * @private\n */\nfunction abortHandshakeOrEmitwsClientError(\n server,\n req,\n socket,\n code,\n message,\n headers\n) {\n if (server.listenerCount('wsClientError')) {\n const err = new Error(message);\n Error.captureStackTrace(err, abortHandshakeOrEmitwsClientError);\n\n server.emit('wsClientError', err, socket, req);\n } else {\n abortHandshake(socket, code, message, headers);\n }\n}\n","import type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport type { Logger } from \"./logger.js\";\nimport {\n createVersionAwareLogger,\n PluginFileLogger as PluginLogger,\n} from \"./logger.js\";\nimport {\n RecordingStorage,\n type RecordingStatusEvent,\n} from \"./recording/index.js\";\nimport type { NotificationStorage } from \"./notification/storage.js\";\nimport { registerLightRulesGateway } from \"./light-rules/gateway.js\";\nimport {\n LIGHT_RULE_GATEWAY_METHOD_LIST,\n LIGHT_RULE_TOOL_NAME_LIST,\n LIGHT_RULE_TOOL_NAMES,\n} from \"./light-rules/names.js\";\nimport { registerLightRulesTools } from \"./plugin/light-rules-tools.js\";\nimport { InlineLightRuleEvaluator } from \"./light-rules/inline-evaluator.js\";\nimport { LightRuleEvaluationScheduler } from \"./light-rules/evaluation-scheduler.js\";\nimport { PiAiInvoker } from \"./light-rules/pi-invoker.js\";\nimport { LightRuleRegistry } from \"./light-rules/registry.js\";\nimport { registerAutoUpdateLifecycle } from \"./plugin/auto-update.js\";\nimport { registerPluginCli } from \"./plugin/cli.js\";\nimport { registerLightControlTool } from \"./plugin/light-control.js\";\nimport {\n registerRelayTunnelLifecycle,\n registerStorageLifecycle,\n} from \"./plugin/lifecycle.js\";\nimport { registerNotificationInterfaces } from \"./plugin/notifications.js\";\nimport { registerRecordingInterfaces } from \"./plugin/recordings.js\";\nimport { isPluginCliInvocation } from \"./plugin/runtime-mode.js\";\nimport { resolvePluginStateDir } from \"./plugin/runtime-state.js\";\nimport type { GatewayHandler } from \"./plugin/shared.js\";\nimport { RELAY_TUNNEL_GATEWAY_CLIENT_INSTANCE_ID } from \"./tunnel/proxy.js\";\nimport type { PluginConfig, RawNotification } from \"./types.js\";\nimport type { BroadcastFn } from \"./update/types.js\";\n\nconst LIGHT_RULE_PROMPT_GUIDANCE = [\n \"灯效规则路由提示:\",\n `- 当用户表达“收到/当/如果/有某类通知或消息时,亮灯/闪灯/变成某种灯效”时,这是持久灯效规则请求,必须调用 ${LIGHT_RULE_TOOL_NAMES.create} 或 ${LIGHT_RULE_TOOL_NAMES.update}。`,\n \"- 不要为这类通知触发规则直接调用 light_control;light_control 只用于当前立即执行的一次性灯效、测试或预览。\",\n \"- 不要手写或编辑 tasks/*/meta.json;灯效规则的创建、修改、删除和查询都走 lightrules_* 工具。\",\n].join(\"\\n\");\n\nexport default {\n id: \"phone-notifications\",\n name: \"Phone Notifications & Light Control\",\n\n register(api: OpenClawPluginApi) {\n const config = (api.pluginConfig ?? {}) as PluginConfig;\n const ignoredApps = new Set(config.ignoredApps ?? []);\n\n let storage: NotificationStorage | null = null;\n let recordingStorage: RecordingStorage | null = null;\n let broadcastFn: BroadcastFn | null = null;\n let autoUpdateLifecycle: ReturnType<typeof registerAutoUpdateLifecycle> | null = null;\n let tunnelService: ReturnType<typeof registerRelayTunnelLifecycle> = null;\n\n const openclawDir = resolvePluginStateDir(api);\n const logger: Logger = openclawDir\n ? new PluginLogger(api.logger, openclawDir)\n : createVersionAwareLogger(api.logger);\n\n const lightRuleCtx: { workspaceDir?: string; stateDir?: string } = {\n stateDir: openclawDir,\n };\n const asrDataDir =\n openclawDir ??\n process.env.OPENCLAW_STATE_DIR ??\n process.env.QCLAW_STATE_DIR ??\n process.cwd();\n\n if (isPluginCliInvocation()) {\n registerPluginCli(api, {\n logger,\n openclawDir,\n });\n logger.info(\n \"检测到插件 CLI 命令执行上下文,仅注册 CLI,跳过后台服务以避免影响 Relay tunnel 常驻连接\",\n );\n return;\n }\n\n api.on(\"before_prompt_build\", () => ({\n appendSystemContext: LIGHT_RULE_PROMPT_GUIDANCE,\n }));\n\n function cacheBroadcast(broadcast: BroadcastFn | undefined): void {\n if (!broadcast) {\n return;\n }\n\n const changed = broadcastFn !== broadcast;\n broadcastFn = broadcast;\n if (changed) {\n autoUpdateLifecycle?.notifyBroadcastReady();\n }\n }\n\n function isDirectMobileGatewayRequest(\n opts: Parameters<GatewayHandler>[0],\n ): boolean {\n const client = opts.client?.connect?.client;\n if (!client) return false;\n if (client.instanceId === RELAY_TUNNEL_GATEWAY_CLIENT_INSTANCE_ID) {\n return false;\n }\n return client.id === \"openclaw-ios\" || client.id === \"openclaw-android\";\n }\n\n async function deactivateRelayForDirectGatewayRequest(\n method: string,\n opts: Parameters<GatewayHandler>[0],\n ): Promise<void> {\n if (!tunnelService || !isDirectMobileGatewayRequest(opts)) return;\n\n const client = opts.client?.connect?.client;\n try {\n await tunnelService.deactivateForExternalTunnel(\n `gateway method ${method} from ${client?.id ?? \"unknown\"}`,\n );\n } catch (err: any) {\n logger.warn(\n `Relay tunnel: failed to deactivate after direct gateway method ${method}: ${err?.message ?? String(err)}`,\n );\n }\n }\n\n function registerGatewayMethodWithBroadcastCapture(\n method: string,\n handler: GatewayHandler,\n ): void {\n api.registerGatewayMethod(method, async (opts) => {\n cacheBroadcast(opts.context?.broadcast);\n await deactivateRelayForDirectGatewayRequest(method, opts);\n return handler(opts);\n });\n }\n\n function filterNotifications(items: RawNotification[]): RawNotification[] {\n return items.filter((notification) => !ignoredApps.has(notification.app));\n }\n\n function notifyRecordingStatus(event: RecordingStatusEvent): void {\n if (!broadcastFn) {\n logger.warn(\n `[recording.status] broadcast 不可用,跳过状态事件: ${event.recordingId} -> ${event.transfer_status}`,\n );\n return;\n }\n\n broadcastFn(\"recording.status\", event);\n }\n\n const lightRuleRegistry = new LightRuleRegistry(lightRuleCtx);\n const lightRuleInvoker = new PiAiInvoker(api, logger);\n const inlineLightRuleEvaluator = new InlineLightRuleEvaluator({\n logger,\n registry: lightRuleRegistry,\n invoker: lightRuleInvoker,\n });\n const lightRuleEvaluationScheduler = new LightRuleEvaluationScheduler({\n evaluator: inlineLightRuleEvaluator,\n logger,\n });\n\n registerStorageLifecycle({\n api,\n config,\n logger,\n lightRuleCtx,\n setStorage(nextStorage) {\n storage = nextStorage;\n },\n setRecordingStorage(nextRecordingStorage) {\n recordingStorage = nextRecordingStorage;\n },\n onStorageReady() {\n // storage service start 完成后 lightRuleCtx 才被回填到真实的 workspaceDir,\n // 此时重新扫盘加载已有规则。\n lightRuleRegistry.reload();\n },\n });\n\n tunnelService = registerRelayTunnelLifecycle({\n api,\n config,\n logger,\n openclawDir,\n });\n\n registerNotificationInterfaces({\n api,\n logger,\n getStorage: () => storage,\n filterNotifications,\n registerGatewayMethod: registerGatewayMethodWithBroadcastCapture,\n tunnelService,\n onAfterIngest(inserted, ingestId) {\n lightRuleEvaluationScheduler.enqueue(inserted, ingestId);\n },\n });\n\n registerLightControlTool(api, logger);\n\n registerRecordingInterfaces({\n api,\n logger,\n asrDataDir,\n getRecordingStorage: () => recordingStorage,\n notifyRecordingStatus,\n registerGatewayMethod: registerGatewayMethodWithBroadcastCapture,\n shouldBroadcastStatusOnHttp: () => !!broadcastFn,\n tunnelService,\n });\n\n registerLightRulesGateway(api, lightRuleRegistry, logger, cacheBroadcast);\n registerLightRulesTools(api, lightRuleRegistry, logger);\n logger.info(\n `灯效规则方法已注册: gateway=${LIGHT_RULE_GATEWAY_METHOD_LIST.join(\", \")}; tools=${LIGHT_RULE_TOOL_NAME_LIST.join(\", \")}`,\n );\n\n autoUpdateLifecycle = registerAutoUpdateLifecycle({\n api,\n config,\n logger,\n getBroadcastFn: () => broadcastFn,\n cacheBroadcast,\n tunnelService,\n });\n\n registerPluginCli(api, {\n logger,\n openclawDir,\n });\n },\n};\n","import { appendFileSync, mkdirSync, readdirSync, rmSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { PLUGIN_VERSION } from \"./version.js\";\n\nexport interface Logger {\n info: (msg: string) => void;\n warn: (msg: string) => void;\n error: (msg: string) => void;\n}\n\nconst DEFAULT_LOG_RETENTION_DAYS = 30;\nconst DAY_MS = 24 * 60 * 60 * 1000;\n\nexport interface PluginFileLoggerOptions {\n version?: string;\n retentionDays?: number;\n}\n\nconst REDACTED = \"[redacted]\";\nconst REDACTED_SECRET = \"[redacted-secret]\";\nconst REDACTED_URL = \"[redacted-url]\";\n\nconst SECRET_KEYS = [\n \"apiKey\",\n \"api_key\",\n \"appKey\",\n \"authorization\",\n \"password\",\n \"secret\",\n \"token\",\n \"accessToken\",\n \"refreshToken\",\n \"gatewayToken\",\n \"gatewayPassword\",\n \"apnsToken\",\n \"deviceToken\",\n \"X-Api-Key-Id\",\n \"x-api-key-id\",\n \"x-openclaw-password\",\n];\n\nconst USER_TEXT_KEYS = [\n \"accountId\",\n \"body\",\n \"content\",\n \"conversationName\",\n \"deviceId\",\n \"loginAccount\",\n \"metadata\",\n \"name\",\n \"raw\",\n \"rawResponse\",\n \"reason\",\n \"recordResult\",\n \"recordingName\",\n \"resBody\",\n \"response\",\n \"senderName\",\n \"sourceText\",\n \"sourceTextList\",\n \"summary\",\n \"summaryResult\",\n \"summaryText\",\n \"text\",\n \"title\",\n \"transcript\",\n \"transcriptData\",\n \"userId\",\n];\n\nconst USER_URL_KEYS = [\n \"audio\",\n \"audioOssUrl\",\n \"fileUrl\",\n \"oss_audio_url\",\n \"oss_srt_url\",\n \"srt\",\n \"url\",\n];\n\nconst SENSITIVE_QUERY_KEYS = [\n \"access_token\",\n \"api_key\",\n \"apikey\",\n \"authorization\",\n \"fileUrl\",\n \"password\",\n \"refresh_token\",\n \"secret\",\n \"signature\",\n \"token\",\n \"x-api-key-id\",\n \"x-oss-security-token\",\n];\n\nexport function isBetaPluginVersion(version = PLUGIN_VERSION): boolean {\n return /\\bbeta\\b/i.test(version);\n}\n\nexport function createVersionAwareLogger(\n upstream: Logger,\n options: Pick<PluginFileLoggerOptions, \"version\"> = {},\n): Logger {\n if (isBetaPluginVersion(options.version ?? PLUGIN_VERSION)) {\n return upstream;\n }\n\n return {\n info(msg: string) {\n upstream.info(redactLogMessage(msg));\n },\n warn(msg: string) {\n upstream.warn(redactLogMessage(msg));\n },\n error(msg: string) {\n upstream.error(redactLogMessage(msg));\n },\n };\n}\n\n/**\n * 插件级文件 Logger。\n * 在调用原始 api.logger 的同时,把日志追加写入\n * `<stateDir>/plugins/phone-notifications/logs/YYYY-MM-DD.log`。\n * beta 版本保留原始日志;正式版保留 INFO,并对日志里的用户数据做兜底脱敏。\n */\nexport class PluginFileLogger implements Logger {\n private readonly logsDir: string;\n private readonly redactLogs: boolean;\n private readonly retentionDays: number;\n private lastPruneDateKey: string | null = null;\n\n constructor(\n private readonly upstream: Logger,\n stateDir: string,\n options: PluginFileLoggerOptions = {},\n ) {\n this.logsDir = join(stateDir, \"plugins\", \"phone-notifications\", \"logs\");\n this.redactLogs = !isBetaPluginVersion(options.version ?? PLUGIN_VERSION);\n this.retentionDays =\n Number.isFinite(options.retentionDays) && (options.retentionDays ?? 0) > 0\n ? options.retentionDays!\n : DEFAULT_LOG_RETENTION_DAYS;\n\n mkdirSync(this.logsDir, { recursive: true });\n const now = new Date();\n this.pruneExpiredLogs(now);\n this.lastPruneDateKey = formatDate(now);\n }\n\n info(msg: string): void {\n this.prepareLogDate(new Date());\n const safeMsg = this.formatLogMessage(msg);\n this.upstream.info(safeMsg);\n this.append(\"INFO\", safeMsg);\n }\n\n warn(msg: string): void {\n const safeMsg = this.formatLogMessage(msg);\n this.upstream.warn(safeMsg);\n this.append(\"WARN\", safeMsg);\n }\n\n error(msg: string): void {\n const safeMsg = this.formatLogMessage(msg);\n this.upstream.error(safeMsg);\n this.append(\"ERROR\", safeMsg);\n }\n\n private formatLogMessage(msg: string): string {\n return this.redactLogs ? redactLogMessage(msg) : msg;\n }\n\n private append(level: string, msg: string): void {\n const now = new Date();\n const dateKey = this.prepareLogDate(now);\n const time = formatLocalTimestamp(now);\n const line = `${time} [${level}] ${msg}\\n`;\n try {\n appendFileSync(join(this.logsDir, `${dateKey}.log`), line);\n } catch {\n // 写文件失败不影响主流程\n }\n }\n\n private prepareLogDate(now: Date): string {\n const dateKey = formatDate(now);\n if (this.lastPruneDateKey !== dateKey) {\n this.pruneExpiredLogs(now);\n this.lastPruneDateKey = dateKey;\n }\n return dateKey;\n }\n\n private pruneExpiredLogs(now: Date): void {\n const cutoffMs = now.getTime() - this.retentionDays * DAY_MS;\n const cutoffDate = formatDate(new Date(cutoffMs));\n\n try {\n for (const entry of readdirSync(this.logsDir, { withFileTypes: true })) {\n if (!entry.isFile()) continue;\n const match = /^(\\d{4}-\\d{2}-\\d{2})\\.log$/.exec(entry.name);\n if (match && match[1] < cutoffDate) {\n rmSync(join(this.logsDir, entry.name), { force: true });\n }\n }\n } catch {\n // 清理失败不影响主流程\n }\n }\n}\n\nexport function redactLogMessage(msg: string): string {\n let redacted = String(msg);\n\n redacted = redactQuotedObjectFields(redacted, SECRET_KEYS, REDACTED_SECRET);\n redacted = redactQuotedObjectFields(redacted, USER_TEXT_KEYS, REDACTED);\n redacted = redactQuotedObjectFields(redacted, USER_URL_KEYS, REDACTED_URL);\n\n redacted = redactStructuredKeyValueFields(\n redacted,\n SECRET_KEYS,\n REDACTED_SECRET,\n );\n redacted = redactStructuredKeyValueFields(redacted, USER_TEXT_KEYS, REDACTED);\n redacted = redactStructuredKeyValueFields(redacted, USER_URL_KEYS, REDACTED_URL);\n\n redacted = redactKeyValueFields(redacted, SECRET_KEYS, REDACTED_SECRET);\n redacted = redactKeyValueFields(redacted, USER_TEXT_KEYS, REDACTED);\n redacted = redactKeyValueFields(redacted, USER_URL_KEYS, REDACTED_URL);\n\n redacted = redactColonTextFields(redacted, SECRET_KEYS, REDACTED_SECRET);\n redacted = redactColonTextFields(redacted, USER_TEXT_KEYS, REDACTED);\n redacted = redactQueryParams(redacted, SENSITIVE_QUERY_KEYS);\n redacted = redactBearerTokens(redacted);\n redacted = redactLikelyUserUrls(redacted);\n redacted = redactEmails(redacted);\n redacted = redactPhoneNumbers(redacted);\n redacted = redactJwtTokens(redacted);\n redacted = redactLongHexTokens(redacted);\n\n return redacted;\n}\n\nfunction redactQuotedObjectFields(\n input: string,\n keys: string[],\n placeholder: string,\n): string {\n const keyPattern = buildKeyPattern(keys);\n return input.replace(\n new RegExp(\n `([\"'])(${keyPattern})\\\\1\\\\s*:\\\\s*(?:\"(?:\\\\\\\\.|[^\"\\\\\\\\])*\"|'(?:\\\\\\\\.|[^'\\\\\\\\])*'|[^,}\\\\]]+)`,\n \"gi\",\n ),\n (_match, quote: string, key: string) =>\n `${quote}${key}${quote}: \"${placeholder}\"`,\n );\n}\n\nfunction redactKeyValueFields(\n input: string,\n keys: string[],\n placeholder: string,\n): string {\n const keyPattern = buildKeyPattern(keys);\n return input.replace(\n new RegExp(\n `(?<![?&])\\\\b(${keyPattern})\\\\s*=\\\\s*(?:Bearer\\\\s+[^,\\\\s)]+|\"(?:\\\\\\\\.|[^\"\\\\\\\\])*\"|'(?:\\\\\\\\.|[^'\\\\\\\\])*'|[^,\\\\s)]+)`,\n \"gi\",\n ),\n (_match, key: string) => `${key}=${placeholder}`,\n );\n}\n\nfunction redactStructuredKeyValueFields(\n input: string,\n keys: string[],\n placeholder: string,\n): string {\n const keyPattern = buildKeyPattern(keys);\n const regex = new RegExp(`\\\\b(${keyPattern})\\\\s*=\\\\s*([\\\\[{])`, \"gi\");\n let result = \"\";\n let lastIndex = 0;\n let match: RegExpExecArray | null;\n\n while ((match = regex.exec(input))) {\n const valueStart = regex.lastIndex - 1;\n const valueEnd = findStructuredValueEnd(input, valueStart);\n if (valueEnd === null) {\n continue;\n }\n\n result += input.slice(lastIndex, match.index);\n result += `${match[1]}=${placeholder}`;\n lastIndex = valueEnd;\n regex.lastIndex = valueEnd;\n }\n\n if (lastIndex === 0) {\n return input;\n }\n\n return result + input.slice(lastIndex);\n}\n\nfunction findStructuredValueEnd(input: string, start: number): number | null {\n const open = input[start];\n const close = open === \"{\" ? \"}\" : \"]\";\n const stack: string[] = [close];\n let quote: string | null = null;\n let escaped = false;\n\n for (let i = start + 1; i < input.length; i++) {\n const ch = input[i];\n\n if (quote) {\n if (escaped) {\n escaped = false;\n } else if (ch === \"\\\\\") {\n escaped = true;\n } else if (ch === quote) {\n quote = null;\n }\n continue;\n }\n\n if (ch === \"\\\"\" || ch === \"'\") {\n quote = ch;\n continue;\n }\n\n if (ch === \"{\" || ch === \"[\") {\n stack.push(ch === \"{\" ? \"}\" : \"]\");\n continue;\n }\n\n if (ch === stack[stack.length - 1]) {\n stack.pop();\n if (stack.length === 0) {\n return i + 1;\n }\n }\n }\n\n return null;\n}\n\nfunction redactColonTextFields(\n input: string,\n keys: string[],\n placeholder: string,\n): string {\n const keyPattern = buildKeyPattern(keys);\n return input.replace(\n new RegExp(`\\\\b(${keyPattern})\\\\s*:\\\\s*([^,\\\\n]+)`, \"gi\"),\n (_match, key: string) => `${key}: ${placeholder}`,\n );\n}\n\nfunction redactQueryParams(input: string, keys: string[]): string {\n const keyPattern = buildKeyPattern(keys);\n return input.replace(\n new RegExp(`([?&](${keyPattern})=)([^&#\\\\s]+)`, \"gi\"),\n (_match, prefix: string) => `${prefix}${encodeURIComponent(REDACTED)}`,\n );\n}\n\nfunction redactBearerTokens(input: string): string {\n return input.replace(\n /\\b(Bearer\\s+)[A-Za-z0-9._~+/=-]+/gi,\n `$1${REDACTED_SECRET}`,\n );\n}\n\nfunction redactJwtTokens(input: string): string {\n return input.replace(\n /\\beyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\b/g,\n REDACTED_SECRET,\n );\n}\n\nfunction redactLongHexTokens(input: string): string {\n return input.replace(/\\b[a-f0-9]{32,}\\b/gi, REDACTED_SECRET);\n}\n\nfunction redactEmails(input: string): string {\n return input.replace(\n /\\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}\\b/gi,\n \"[redacted-email]\",\n );\n}\n\nfunction redactPhoneNumbers(input: string): string {\n return input.replace(\n /\\b1[3-9]\\d{9}\\b/g,\n (phone) => `${phone.slice(0, 3)}****${phone.slice(-4)}`,\n );\n}\n\nfunction redactLikelyUserUrls(input: string): string {\n return input.replace(/https?:\\/\\/[^\\s\"',)]+/gi, (rawUrl) =>\n redactUrl(rawUrl),\n );\n}\n\nfunction redactUrl(rawUrl: string): string {\n try {\n const url = new URL(rawUrl);\n for (const key of Array.from(url.searchParams.keys())) {\n if (\n SENSITIVE_QUERY_KEYS.some(\n (sensitiveKey) => sensitiveKey.toLowerCase() === key.toLowerCase(),\n )\n ) {\n url.searchParams.set(key, REDACTED);\n }\n }\n\n if (shouldRedactUrlPath(url)) {\n return `${url.origin}/${REDACTED_URL}`;\n }\n\n return url.toString();\n } catch {\n return rawUrl;\n }\n}\n\nfunction shouldRedactUrlPath(url: URL): boolean {\n const host = url.hostname.toLowerCase();\n const path = decodeURIComponent(url.pathname).toLowerCase();\n if (\n /(^|\\.)((oss|cos|s3|storage|cdn)[.-])/.test(host)\n || /(aliyuncs|myqcloud|amazonaws|oss|storage|cdn)/.test(host)\n ) {\n return true;\n }\n return (\n /\\/(audio|avatar|feedback|log|logs|recording|recordings)\\//.test(path)\n || /\\.(aac|flac|json|m4a|md|mp3|ogg|opus|srt|wav|zip)$/i.test(path)\n );\n}\n\nfunction buildKeyPattern(keys: string[]): string {\n return keys.map(escapeRegExp).join(\"|\");\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nfunction formatDate(d: Date): string {\n const y = d.getFullYear();\n const m = String(d.getMonth() + 1).padStart(2, \"0\");\n const day = String(d.getDate()).padStart(2, \"0\");\n return `${y}-${m}-${day}`;\n}\n\nexport function formatLocalTimestamp(d: Date): string {\n const y = d.getFullYear();\n const m = String(d.getMonth() + 1).padStart(2, \"0\");\n const day = String(d.getDate()).padStart(2, \"0\");\n const hh = String(d.getHours()).padStart(2, \"0\");\n const mm = String(d.getMinutes()).padStart(2, \"0\");\n const ss = String(d.getSeconds()).padStart(2, \"0\");\n const ms = String(d.getMilliseconds()).padStart(3, \"0\");\n\n const offsetMinutes = -d.getTimezoneOffset();\n const sign = offsetMinutes >= 0 ? \"+\" : \"-\";\n const absOffsetMinutes = Math.abs(offsetMinutes);\n const offsetHours = String(Math.floor(absOffsetMinutes / 60)).padStart(2, \"0\");\n const offsetMins = String(absOffsetMinutes % 60).padStart(2, \"0\");\n\n return `${y}-${m}-${day}T${hh}:${mm}:${ss}.${ms}${sign}${offsetHours}:${offsetMins}`;\n}\n","import { readFileSync } from \"node:fs\";\n\ndeclare const __PLUGIN_VERSION__: string | undefined;\n\ninterface PackageJson {\n version?: string;\n}\n\nfunction readBuildInjectedVersion(): string | undefined {\n if (typeof __PLUGIN_VERSION__ !== \"string\") {\n return undefined;\n }\n\n const version = __PLUGIN_VERSION__.trim();\n return version || undefined;\n}\n\nfunction readPluginVersionFromPackageJson(): string | undefined {\n try {\n const packageJsonUrl = new URL(\"../package.json\", import.meta.url);\n const packageJson = JSON.parse(\n readFileSync(packageJsonUrl, \"utf-8\"),\n ) as PackageJson;\n const version = packageJson.version?.trim();\n return version || undefined;\n } catch {\n return undefined;\n }\n}\n\nexport const PLUGIN_VERSION =\n readBuildInjectedVersion() ??\n readPluginVersionFromPackageJson() ??\n \"unknown\";\n","export interface RepeatConfig {\n repeat?: boolean;\n repeat_times?: number;\n}\n\nexport type RepeatArgument = RepeatConfig | boolean | number | undefined;\n\nexport function normalizeRepeatTimes(input?: RepeatArgument): number {\n if (typeof input === \"boolean\") {\n return input ? 0 : 1;\n }\n\n if (typeof input === \"number\") {\n return validateRepeatTimes(input);\n }\n\n if (!input) {\n return 1;\n }\n\n if (input.repeat_times !== undefined) {\n return validateRepeatTimes(input.repeat_times);\n }\n\n if (input.repeat !== undefined) {\n return input.repeat ? 0 : 1;\n }\n\n return 1;\n}\n\nexport function assertAncsRepeatTimes(repeatTimes: number): void {\n if (repeatTimes !== 0 && repeatTimes !== 1) {\n throw new Error(\n \"当前 ANCS 路径仅支持 repeat_times=0(无限循环)或 1(播放一轮);N>=2 需非 ANCS 路径\",\n );\n }\n}\n\nfunction validateRepeatTimes(value: number): number {\n if (!Number.isInteger(value) || value < 0) {\n throw new Error(\"repeat_times 必须是 >=0 的整数\");\n }\n\n return value;\n}\n","import { existsSync, readFileSync, readdirSync, mkdirSync } from \"node:fs\";\nimport { readdir, readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type { StoredNotification } from \"../notification/storage.js\";\n\n/**\n * Minimal Commander.js Command interface.\n * The real `Command` instance comes from the openclaw runtime at registration time;\n * we only declare the subset we use so that `commander` need not be a direct dep.\n */\nexport interface CliCommand {\n command(nameAndArgs: string): CliCommand;\n description(str: string): CliCommand;\n version(str: string, flags?: string, description?: string): CliCommand;\n option(flags: string, description: string, defaultValue?: string): CliCommand;\n requiredOption(flags: string, description: string): CliCommand;\n action(fn: (...args: any[]) => void | Promise<void>): CliCommand;\n}\n\nexport interface CliContext {\n workspaceDir?: string;\n stateDir?: string;\n}\n\n/** Resolve the notifications storage directory (stateDir → workspace fallback) */\nexport function resolveNotificationsDir(ctx: CliContext): string | null {\n if (ctx.stateDir) {\n const dir = join(\n ctx.stateDir,\n \"plugins\",\n \"phone-notifications\",\n \"notifications\",\n );\n if (existsSync(dir)) return dir;\n }\n if (ctx.workspaceDir) {\n const dir = join(ctx.workspaceDir, \"notifications\");\n if (existsSync(dir)) return dir;\n }\n return null;\n}\n\n/** List available date keys (YYYY-MM-DD) sorted descending */\nexport function listDateKeys(dir: string): string[] {\n const pattern = /^(\\d{4}-\\d{2}-\\d{2})\\.json$/;\n const keys: string[] = [];\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n if (!entry.isFile()) continue;\n const m = pattern.exec(entry.name);\n if (m) keys.push(m[1]);\n }\n return keys.sort().reverse();\n}\n\n/** Read notifications for a specific date */\nexport function readDateFile(\n dir: string,\n dateKey: string,\n): StoredNotification[] {\n const filePath = join(dir, `${dateKey}.json`);\n if (!existsSync(filePath)) return [];\n try {\n return JSON.parse(readFileSync(filePath, \"utf-8\"));\n } catch {\n return [];\n }\n}\n\n/** Format today as YYYY-MM-DD */\nexport function today(): string {\n return formatDate(new Date());\n}\n\n/** Format a Date as YYYY-MM-DD */\nexport function formatDate(d: Date): string {\n const y = d.getFullYear();\n const m = String(d.getMonth() + 1).padStart(2, \"0\");\n const day = String(d.getDate()).padStart(2, \"0\");\n return `${y}-${m}-${day}`;\n}\n\n/** Get date N days ago as YYYY-MM-DD */\nexport function daysAgo(n: number): string {\n const d = new Date();\n d.setDate(d.getDate() - n);\n return formatDate(d);\n}\n\n/** Filter date keys to a [from, to] range (inclusive) */\nexport function filterDateRange(\n keys: string[],\n from: string,\n to: string,\n): string[] {\n return keys.filter((k) => k >= from && k <= to);\n}\n\n/** Parse an ISO 8601 timestamp and exit with a CLI error on invalid input */\nexport function parseIsoTime(\n value: string,\n optionName: \"--from\" | \"--to\",\n): number {\n const isoPattern =\n /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}(?::\\d{2}(?:\\.\\d{1,3})?)?(Z|[+-]\\d{2}:\\d{2})$/;\n if (!isoPattern.test(value)) {\n exitError(\n \"INVALID_TIME\",\n `${optionName} 必须是 ISO 8601 时间,例如 2026-03-01T09:00:00+08:00`,\n );\n }\n\n const ts = Date.parse(value);\n if (Number.isNaN(ts)) {\n exitError(\n \"INVALID_TIME\",\n `${optionName} 不是合法时间,例如 2026-03-01T09:00:00+08:00`,\n );\n }\n return ts;\n}\n\n/** Sort notifications by timestamp descending (newest first) */\nexport function sortNotificationsByTimestampDesc(\n items: StoredNotification[],\n): StoredNotification[] {\n return items.sort((a, b) => Date.parse(b.timestamp) - Date.parse(a.timestamp));\n}\n\nconst APP_ALIAS_GROUPS = [\n [\"微信\", \"wechat\", \"weixin\", \"com.tencent.mm\", \"com.tencent.xin\"],\n [\"企业微信\", \"wecom\", \"wxwork\", \"com.tencent.wework\"],\n [\"飞书\", \"feishu\", \"lark\", \"com.ss.android.lark\", \"com.bytedance.ee.lark\", \"com.larksuite.suite\"],\n [\"钉钉\", \"dingtalk\", \"com.alibaba.android.rimet\"],\n [\"qq\", \"腾讯qq\", \"com.tencent.mobileqq\"],\n];\n\nfunction normalizeLookupText(value: string): string {\n return value.trim().toLowerCase();\n}\n\nfunction appAliasGroup(value: string): string[] | null {\n const normalized = normalizeLookupText(value);\n if (!normalized) return null;\n return APP_ALIAS_GROUPS.find((group) =>\n group.some((candidate) => normalizeLookupText(candidate) === normalized),\n ) ?? null;\n}\n\nexport function matchesNotificationAppFilter(\n item: StoredNotification,\n app: string,\n): boolean {\n const filter = normalizeLookupText(app);\n if (!filter) return true;\n\n const candidates = [item.appName, item.appDisplayName]\n .filter((value): value is string => typeof value === \"string\" && value.length > 0);\n if (candidates.some((candidate) => normalizeLookupText(candidate) === filter)) {\n return true;\n }\n\n const filterGroup = appAliasGroup(app);\n if (!filterGroup) return false;\n return candidates.some((candidate) => appAliasGroup(candidate) === filterGroup);\n}\n\n/** Async version of listDateKeys */\nexport async function listDateKeysAsync(dir: string): Promise<string[]> {\n const pattern = /^(\\d{4}-\\d{2}-\\d{2})\\.json$/;\n const keys: string[] = [];\n const entries = await readdir(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (!entry.isFile()) continue;\n const m = pattern.exec(entry.name);\n if (m) keys.push(m[1]);\n }\n return keys.sort().reverse();\n}\n\n/** Async version of readDateFile */\nexport async function readDateFileAsync(\n dir: string,\n dateKey: string,\n): Promise<StoredNotification[]> {\n const filePath = join(dir, `${dateKey}.json`);\n if (!existsSync(filePath)) return [];\n try {\n const content = await readFile(filePath, \"utf-8\");\n return JSON.parse(content);\n } catch {\n return [];\n }\n}\n\n/** Write progress message to stderr (visible to caller, won't pollute JSON stdout) */\nexport function progress(message: string): void {\n process.stderr.write(message + \"\\n\");\n}\n\n/** Print JSON result to stdout */\nexport function output(data: unknown): void {\n process.stdout.write(JSON.stringify(data, null, 2) + \"\\n\");\n}\n\n/** Print error JSON and exit with code 1 */\nexport function exitError(code: string, message: string): never {\n output({ ok: false, error: { code, message } });\n process.exit(1);\n}\n\n/** Resolve the recordings storage directory (stateDir → workspace fallback) */\nexport function resolveRecordingsDir(ctx: CliContext): string | null {\n if (ctx.stateDir) {\n const dir = join(\n ctx.stateDir,\n \"plugins\",\n \"phone-notifications\",\n \"recordings\",\n );\n if (existsSync(dir)) return dir;\n }\n if (ctx.workspaceDir) {\n const dir = join(ctx.workspaceDir, \"recordings\");\n if (existsSync(dir)) return dir;\n }\n return null;\n}\n\n/** Recording index entry (mirrors RecordingIndexEntry from storage.ts) */\nexport interface CliRecordingEntry {\n id: string;\n metadata: {\n name: string;\n duration_sec: number;\n file_size_bytes: number;\n created_at: string;\n transfer_status: string;\n [key: string]: unknown;\n };\n status: string;\n audioFile?: string;\n srtFile?: string;\n transcriptDataFile?: string;\n transcriptFile?: string;\n summaryFile?: string;\n title?: string;\n lastError?: string;\n ingestedAt: string;\n updatedAt: string;\n}\n\n/** Resolve the asr-config.json path; creates parent dirs if needed */\nexport function resolveAsrConfigPath(ctx: CliContext): string {\n let base: string;\n if (ctx.stateDir) {\n base = join(ctx.stateDir, \"plugins\", \"phone-notifications\", \"recordings\");\n } else if (ctx.workspaceDir) {\n base = join(ctx.workspaceDir, \"recordings\");\n } else {\n exitError(\n \"STORAGE_UNAVAILABLE\",\n \"无法确定录音存储目录:stateDir 和 workspaceDir 均未设置\",\n );\n }\n mkdirSync(base, { recursive: true });\n return join(base, \"asr-config.json\");\n}\n\n/** Mask an API key, keeping first 4 and last 4 chars */\nexport function maskApiKey(key: string): string {\n if (key.length <= 8) return \"***\";\n return `${key.slice(0, 4)}***${key.slice(-4)}`;\n}\n\n/** Read recording index.json */\nexport function readRecordingIndex(\n dir: string,\n): CliRecordingEntry[] {\n const indexPath = join(dir, \"index.json\");\n if (!existsSync(indexPath)) return [];\n try {\n const raw = JSON.parse(readFileSync(indexPath, \"utf-8\"));\n return Array.isArray(raw?.recordings) ? raw.recordings : [];\n } catch {\n return [];\n }\n}\n","import type { LightPixelFramePixel, LightSegment } from \"../types.js\";\nimport { output, exitError } from \"../cli/helpers.js\";\n\nexport const VALID_MODES = [\n \"wave\",\n \"breath\",\n \"strobe\",\n \"steady\",\n \"color_flow\",\n \"pixel_frame\",\n] as const;\nexport const MAX_SEGMENTS = 12;\n\nexport interface ValidationError {\n field: string;\n message: string;\n}\n\nexport interface ValidationWarning {\n field: string;\n code: string;\n message: string;\n}\n\nexport type ValidationResult =\n | { valid: true; segments: LightSegment[]; warnings: ValidationWarning[] }\n | { valid: false; errors: ValidationError[] };\n\nexport function validateSegments(segments: unknown): ValidationResult {\n if (!Array.isArray(segments)) {\n return { valid: false, errors: [{ field: \"segments\", message: \"必须是数组\" }] };\n }\n if (segments.length === 0) {\n return { valid: false, errors: [{ field: \"segments\", message: \"不能为空\" }] };\n }\n if (segments.length > MAX_SEGMENTS) {\n return {\n valid: false,\n errors: [{ field: \"segments\", message: `最多 ${MAX_SEGMENTS} 段` }],\n };\n }\n\n const errors: ValidationError[] = [];\n const warnings: ValidationWarning[] = [];\n for (let i = 0; i < segments.length; i++) {\n validateSegment(segments[i], `segments[${i}]`, errors, warnings);\n }\n\n if (errors.length > 0) return { valid: false, errors };\n return { valid: true, segments: segments as LightSegment[], warnings };\n}\n\n/**\n * 解析 JSON 字符串并校验 segments,失败时直接 exitError。\n * 适用于 CLI action 中的统一入口。\n */\nexport function parseAndValidateSegments(json: string): LightSegment[] {\n let parsed: unknown;\n try {\n parsed = JSON.parse(json);\n } catch {\n exitError(\"VALIDATION_FAILED\", \"segments 必须是合法的 JSON\");\n }\n\n const result = validateSegments(parsed);\n if (!result.valid) {\n output({ ok: false, error: { code: \"VALIDATION_FAILED\", details: result.errors } });\n process.exit(1);\n }\n\n return result.segments;\n}\n\nfunction validateSegment(\n seg: unknown,\n prefix: string,\n errors: ValidationError[],\n warnings: ValidationWarning[],\n): void {\n if (!isRecord(seg)) {\n errors.push({ field: prefix, message: \"必须是对象\" });\n return;\n }\n\n const mode = seg.mode;\n if (!VALID_MODES.includes(mode as (typeof VALID_MODES)[number])) {\n errors.push({\n field: `${prefix}.mode`,\n message: `不支持的模式 '${String(mode)}',可选:${VALID_MODES.join(\"/\")}`,\n });\n }\n\n validateNonNegativeNumber(seg.duration_s, `${prefix}.duration_s`, errors, \"必须是 ≥0 的数字(0 表示无限时长)\");\n\n switch (mode) {\n case \"wave\":\n validateForegroundSegment(seg, prefix, errors);\n validateOptionalNonNegativeNumber(seg.interval_ms, `${prefix}.interval_ms`, errors);\n validateOptionalDirection(seg.direction, `${prefix}.direction`, errors);\n validateOptionalWindow(seg.window, `${prefix}.window`, errors);\n validateOptionalBackground(seg.background, `${prefix}.background`, errors);\n break;\n case \"color_flow\":\n validateForegroundSegment(seg, prefix, errors);\n validateOptionalNonNegativeNumber(seg.interval_ms, `${prefix}.interval_ms`, errors);\n validateOptionalDirection(seg.direction, `${prefix}.direction`, errors);\n validateOptionalWindow(seg.window, `${prefix}.window`, errors);\n validateOptionalBackground(seg.background, `${prefix}.background`, errors);\n type RgbLike = Parameters<typeof hasNonZeroRgb>[0];\n if (!hasNonZeroRgb(seg.color as RgbLike) && !hasNonZeroRgb(seg.background as RgbLike)) {\n errors.push({\n field: prefix,\n message: \"color_flow 至少需要一组非零颜色锚点(color 或 background)\",\n });\n }\n detectColorFlowSingleAnchorMisuse(seg, prefix, warnings);\n break;\n case \"breath\":\n validateForegroundSegment(seg, prefix, errors);\n validateOptionalBreathTiming(seg.breath_timing, `${prefix}.breath_timing`, errors);\n break;\n case \"strobe\":\n validateForegroundSegment(seg, prefix, errors);\n validateOptionalNonNegativeNumber(seg.interval_ms, `${prefix}.interval_ms`, errors);\n break;\n case \"steady\":\n validateForegroundSegment(seg, prefix, errors);\n break;\n case \"pixel_frame\":\n validatePixelFrame(seg.pixels, `${prefix}.pixels`, errors);\n break;\n default:\n validateOptionalNonNegativeNumber(seg.brightness, `${prefix}.brightness`, errors);\n validateOptionalColor(seg.color, `${prefix}.color`, errors);\n validateOptionalNonNegativeNumber(seg.interval_ms, `${prefix}.interval_ms`, errors);\n validateOptionalDirection(seg.direction, `${prefix}.direction`, errors);\n validateOptionalWindow(seg.window, `${prefix}.window`, errors);\n validateOptionalBreathTiming(seg.breath_timing, `${prefix}.breath_timing`, errors);\n validateOptionalBackground(seg.background, `${prefix}.background`, errors);\n }\n}\n\nfunction validateForegroundSegment(\n seg: Record<string, unknown>,\n prefix: string,\n errors: ValidationError[],\n): void {\n validateNumberInRange(\n seg.brightness,\n `${prefix}.brightness`,\n errors,\n 0,\n 255,\n \"必须是 0–255 的数字\",\n );\n validateColor(seg.color, `${prefix}.color`, errors);\n\n if (seg.mode !== \"steady\" && seg.brightness === 0) {\n errors.push({\n field: `${prefix}.brightness`,\n message: \"brightness=0 仅 steady 模式允许;其它模式会在固件侧被过滤\",\n });\n }\n}\n\nfunction validatePixelFrame(\n value: unknown,\n field: string,\n errors: ValidationError[],\n): void {\n if (!Array.isArray(value)) {\n errors.push({ field, message: \"pixel_frame 必须提供 pixels 数组(1–7 项)\" });\n return;\n }\n\n if (value.length < 1 || value.length > 7) {\n errors.push({ field, message: \"pixels 必须为 1–7 项\" });\n }\n\n const seen = new Set<number>();\n for (let i = 0; i < value.length; i++) {\n const pixel = value[i];\n const prefix = `${field}[${i}]`;\n if (!isRecord(pixel)) {\n errors.push({ field: prefix, message: \"必须是对象\" });\n continue;\n }\n\n const idx = pixel.index;\n if (!Number.isInteger(idx) || (idx as number) < 0 || (idx as number) > 6) {\n errors.push({ field: `${prefix}.index`, message: \"index 必须是 0–6 的整数\" });\n } else if (seen.has(idx as number)) {\n errors.push({ field: `${prefix}.index`, message: `index=${idx} 重复` });\n } else {\n seen.add(idx as number);\n }\n\n validateNumberInRange(\n pixel.brightness,\n `${prefix}.brightness`,\n errors,\n 0,\n 255,\n \"必须是 0–255 的数字\",\n );\n validateColor(pixel.color, `${prefix}.color`, errors);\n }\n}\n\nfunction validateOptionalBreathTiming(\n value: unknown,\n field: string,\n errors: ValidationError[],\n): void {\n if (value === undefined) return;\n if (!isRecord(value)) {\n errors.push({ field, message: \"必须是对象\" });\n return;\n }\n\n validatePositiveNumber(\n value.rise_ms,\n `${field}.rise_ms`,\n errors,\n \"rise_ms 必须是 >0 的数字(不支持 0ms)\",\n );\n validateNonNegativeNumber(\n value.hold_ms,\n `${field}.hold_ms`,\n errors,\n \"hold_ms 必须是 ≥0 的数字\",\n );\n validatePositiveNumber(\n value.fall_ms,\n `${field}.fall_ms`,\n errors,\n \"fall_ms 必须是 >0 的数字(不支持 0ms)\",\n );\n validateNonNegativeNumber(\n value.off_ms,\n `${field}.off_ms`,\n errors,\n \"off_ms 必须是 ≥0 的数字\",\n );\n}\n\nfunction validateOptionalBackground(\n value: unknown,\n field: string,\n errors: ValidationError[],\n): void {\n if (value === undefined) return;\n if (!isRecord(value)) {\n errors.push({ field, message: \"必须包含 r/g/b/brightness 数值\" });\n return;\n }\n\n validateColor(value, field, errors);\n validateNumberInRange(\n value.brightness,\n `${field}.brightness`,\n errors,\n 0,\n 255,\n \"必须是 0–255 的数字\",\n );\n}\n\nfunction validateOptionalColor(\n value: unknown,\n field: string,\n errors: ValidationError[],\n): void {\n if (value === undefined) return;\n validateColor(value, field, errors);\n}\n\nfunction validateColor(\n value: unknown,\n field: string,\n errors: ValidationError[],\n): void {\n if (!isRecord(value)) {\n errors.push({ field, message: \"必须包含 r/g/b 数值\" });\n return;\n }\n\n validateNumberInRange(value.r, `${field}.r`, errors, 0, 255, \"必须是 0–255 的数字\");\n validateNumberInRange(value.g, `${field}.g`, errors, 0, 255, \"必须是 0–255 的数字\");\n validateNumberInRange(value.b, `${field}.b`, errors, 0, 255, \"必须是 0–255 的数字\");\n}\n\nfunction validateOptionalDirection(\n value: unknown,\n field: string,\n errors: ValidationError[],\n): void {\n if (value === undefined) return;\n if (value !== \"ltr\" && value !== \"rtl\") {\n errors.push({ field, message: \"direction 必须是 ltr 或 rtl\" });\n }\n}\n\nfunction validateOptionalWindow(\n value: unknown,\n field: string,\n errors: ValidationError[],\n): void {\n if (value === undefined) return;\n if (value !== 1 && value !== 2 && value !== 3) {\n errors.push({ field, message: \"window 仅支持 1/2/3\" });\n }\n}\n\nfunction validateOptionalNonNegativeNumber(\n value: unknown,\n field: string,\n errors: ValidationError[],\n): void {\n if (value === undefined) return;\n validateNonNegativeNumber(value, field, errors, \"必须是 ≥0 的数字\");\n}\n\nfunction validatePositiveNumber(\n value: unknown,\n field: string,\n errors: ValidationError[],\n message: string,\n): void {\n if (value === undefined) return;\n if (!isFiniteNumber(value) || value <= 0) {\n errors.push({ field, message });\n }\n}\n\nfunction validateNonNegativeNumber(\n value: unknown,\n field: string,\n errors: ValidationError[],\n message: string,\n): void {\n if (!isFiniteNumber(value) || value < 0) {\n errors.push({ field, message });\n }\n}\n\nfunction validateNumberInRange(\n value: unknown,\n field: string,\n errors: ValidationError[],\n min: number,\n max: number,\n message: string,\n): void {\n if (!isFiniteNumber(value) || value < min || value > max) {\n errors.push({ field, message });\n }\n}\n\nfunction hasNonZeroRgb(\n value: Pick<LightPixelFramePixel[\"color\"], \"r\" | \"g\" | \"b\"> | { r?: unknown; g?: unknown; b?: unknown } | undefined,\n): boolean {\n if (!value) return false;\n return [value.r, value.g, value.b].some((channel) => isFiniteNumber(channel) && channel > 0);\n}\n\n/**\n * color_flow 是「调色板沿圆周流动」,由 1~2 个颜色锚点插值得到。\n * 当用户/模型只给单一极端纯色锚点(如纯红 R=255、G=B=0)且没有底色锚点时,\n * 实际效果是「同色系亮暗环状流动」(红→暗红),而不是多色调色板流动。\n * 这是已知的 bug 模式(详见 imp-custom-led-ai-read.md「模式选择易错对照」):\n * 上层往往是把用户的\"单色波浪\"误映射到 color_flow,应该改用 wave 模式。\n * 此处不阻塞,只 push 一条 warning 让前端/审计可见。\n */\nfunction detectColorFlowSingleAnchorMisuse(\n seg: Record<string, unknown>,\n prefix: string,\n warnings: ValidationWarning[],\n): void {\n const color = seg.color as { r?: unknown; g?: unknown; b?: unknown } | undefined;\n const background = seg.background as\n | { r?: unknown; g?: unknown; b?: unknown; brightness?: unknown }\n | undefined;\n\n const fgChannels = extractChannels(color);\n const bgChannels = extractChannels(background);\n if (!fgChannels) return;\n\n const bgBrightnessRaw = background?.brightness;\n const bgBrightness = isFiniteNumber(bgBrightnessRaw) ? bgBrightnessRaw : 0;\n const bgActive = !!bgChannels && bgChannels.some((c) => c > 0) && bgBrightness > 0;\n if (bgActive) return;\n\n const fgActiveChannels = fgChannels.filter((c) => c > 0);\n if (fgActiveChannels.length !== 1) return;\n if (fgActiveChannels[0] < 192) return;\n\n warnings.push({\n field: prefix,\n code: \"COLOR_FLOW_SINGLE_ANCHOR_MISUSE\",\n message:\n \"color_flow 仅设置了单一极端纯色前景锚点(无有效底色锚点),实际效果是同色系亮暗环状流动,不是多色调色板流动。\" +\n \"若用户期望的是\\\"单色波浪\\\",请改用 mode='wave';若期望多色流动,请同时设置 background 作为第二锚点。\",\n });\n}\n\nfunction extractChannels(\n value: { r?: unknown; g?: unknown; b?: unknown } | undefined,\n): [number, number, number] | null {\n if (!value) return null;\n const r = isFiniteNumber(value.r) ? value.r : 0;\n const g = isFiniteNumber(value.g) ? value.g : 0;\n const b = isFiniteNumber(value.b) ? value.b : 0;\n return [r, g, b];\n}\n\nfunction isFiniteNumber(value: unknown): value is number {\n return typeof value === \"number\" && Number.isFinite(value);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n","export const LIGHT_RULE_GATEWAY_METHODS = {\n list: \"lightrules.list\",\n create: \"lightrules.create\",\n update: \"lightrules.update\",\n delete: \"lightrules.delete\",\n} as const;\n\nexport const LIGHT_RULE_GATEWAY_METHOD_LIST = [\n LIGHT_RULE_GATEWAY_METHODS.list,\n LIGHT_RULE_GATEWAY_METHODS.create,\n LIGHT_RULE_GATEWAY_METHODS.update,\n LIGHT_RULE_GATEWAY_METHODS.delete,\n] as const;\n\nexport const LIGHT_RULE_TOOL_NAMES = {\n list: \"lightrules_list\",\n create: \"lightrules_create\",\n update: \"lightrules_update\",\n delete: \"lightrules_delete\",\n} as const;\n\nexport const LIGHT_RULE_TOOL_NAME_LIST = [\n LIGHT_RULE_TOOL_NAMES.list,\n LIGHT_RULE_TOOL_NAMES.create,\n LIGHT_RULE_TOOL_NAMES.update,\n LIGHT_RULE_TOOL_NAMES.delete,\n] as const;\n","import {\n existsSync,\n mkdirSync,\n readFileSync,\n writeFileSync,\n rmSync,\n readdirSync,\n statSync,\n} from \"node:fs\";\nimport { basename, join } from \"node:path\";\nimport type { LightSegment } from \"../types.js\";\nimport type { LightRuleMeta } from \"./types.js\";\nimport { assertAncsRepeatTimes, normalizeRepeatTimes } from \"../light/repeat.js\";\n\nexport interface LightRuleStorageContext {\n workspaceDir?: string;\n stateDir?: string;\n}\n\nfunction resolveBaseDir(ctx: LightRuleStorageContext): string {\n if (ctx.workspaceDir) return ctx.workspaceDir;\n\n if (ctx.stateDir) {\n const inferredWorkspaceDir = join(ctx.stateDir, \"workspace\");\n if (existsSync(inferredWorkspaceDir)) return inferredWorkspaceDir;\n return ctx.stateDir;\n }\n\n throw new Error(\"workspaceDir and stateDir both unavailable\");\n}\n\nfunction tasksDir(ctx: LightRuleStorageContext): string {\n return join(resolveBaseDir(ctx), \"tasks\");\n}\n\nfunction normalizeLightRuleLookupName(name: string): string {\n return name.trim().replace(/\\.json$/i, \"\");\n}\n\nfunction resolveLightRuleTask(\n ctx: LightRuleStorageContext,\n name: string,\n): { taskDir: string; meta: LightRuleMeta } | null {\n const dir = tasksDir(ctx);\n const normalizedName = normalizeLightRuleLookupName(name);\n if (!normalizedName) return null;\n\n const directTaskDir = join(dir, normalizedName);\n const directMeta = readMeta(directTaskDir);\n if (directMeta) {\n return {\n taskDir: directTaskDir,\n meta: directMeta,\n };\n }\n\n if (!existsSync(dir)) return null;\n\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n\n const taskDir = join(dir, entry.name);\n const meta = readMeta(taskDir);\n if (meta?.name === normalizedName) {\n return {\n taskDir,\n meta,\n };\n }\n }\n\n return null;\n}\n\nfunction readOptionalString(value: unknown): string | undefined {\n if (typeof value !== \"string\") return undefined;\n const trimmed = value.trim();\n return trimmed || undefined;\n}\n\nfunction readMeta(taskDir: string): LightRuleMeta | null {\n const metaPath = join(taskDir, \"meta.json\");\n if (!existsSync(metaPath)) return null;\n try {\n const raw = JSON.parse(readFileSync(metaPath, \"utf-8\"));\n if (!raw || typeof raw !== \"object\" || Array.isArray(raw)) return null;\n if (raw.type !== \"light-rule\") return null;\n if (!Array.isArray(raw.segments)) return null;\n const name = readOptionalString(raw.name) ?? basename(taskDir);\n const title = readOptionalString(raw.title) ?? name;\n const description = readOptionalString(raw.description) ?? name;\n const createdAt =\n readOptionalString(raw.createdAt) ?? statSync(metaPath).birthtime.toISOString();\n const enabled = typeof raw.enabled === \"boolean\" ? raw.enabled : true;\n const repeatTimes = normalizeRepeatTimes({\n repeat: raw.repeat,\n repeat_times: raw.repeat_times,\n });\n assertAncsRepeatTimes(repeatTimes);\n return {\n ...raw,\n name,\n title,\n type: \"light-rule\",\n description,\n segments: raw.segments,\n repeat_times: repeatTimes,\n enabled,\n createdAt,\n } as LightRuleMeta;\n } catch {\n return null;\n }\n}\n\nfunction writeMeta(taskDir: string, meta: LightRuleMeta): void {\n writeFileSync(join(taskDir, \"meta.json\"), JSON.stringify(meta, null, 2), \"utf-8\");\n}\n\nexport function listLightRules(ctx: LightRuleStorageContext): LightRuleMeta[] {\n const dir = tasksDir(ctx);\n if (!existsSync(dir)) return [];\n\n const rules: LightRuleMeta[] = [];\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n const meta = readMeta(join(dir, entry.name));\n if (meta) rules.push(meta);\n }\n return rules;\n}\n\nexport function getLightRule(\n ctx: LightRuleStorageContext,\n name: string,\n): LightRuleMeta | null {\n return resolveLightRuleTask(ctx, name)?.meta ?? null;\n}\n\nexport function createLightRule(\n ctx: LightRuleStorageContext,\n params: {\n name: string;\n title: string;\n description: string;\n segments: LightSegment[];\n repeat_times?: number;\n repeat?: boolean;\n },\n): { meta: LightRuleMeta } {\n const dir = tasksDir(ctx);\n const taskDir = join(dir, params.name);\n\n if (existsSync(taskDir)) {\n throw new LightRuleError(\"ALREADY_EXISTS\", `灯效规则 '${params.name}' 已存在`);\n }\n\n mkdirSync(taskDir, { recursive: true });\n\n const repeatTimes = normalizeRepeatTimes({\n repeat: params.repeat,\n repeat_times: params.repeat_times,\n });\n assertAncsRepeatTimes(repeatTimes);\n\n const meta: LightRuleMeta = {\n name: params.name,\n title: params.title,\n type: \"light-rule\",\n description: params.description,\n segments: params.segments,\n repeat_times: repeatTimes,\n enabled: true,\n createdAt: new Date().toISOString(),\n };\n\n writeMeta(taskDir, meta);\n\n return { meta };\n}\n\nexport function updateLightRule(\n ctx: LightRuleStorageContext,\n params: {\n name: string;\n title?: string;\n description?: string;\n segments?: LightSegment[];\n repeat_times?: number;\n repeat?: boolean;\n enabled?: boolean;\n },\n): { meta: LightRuleMeta } {\n const resolved = resolveLightRuleTask(ctx, params.name);\n const taskDir = resolved?.taskDir;\n const meta = resolved?.meta;\n\n if (!taskDir || !meta) {\n throw new LightRuleError(\"NOT_FOUND\", `灯效规则 '${params.name}' 不存在`);\n }\n\n if (params.description !== undefined) {\n meta.description = params.description;\n }\n if (params.title !== undefined) {\n meta.title = params.title;\n }\n if (params.segments !== undefined) {\n meta.segments = params.segments;\n }\n if (params.repeat !== undefined || params.repeat_times !== undefined) {\n meta.repeat_times = normalizeRepeatTimes({\n repeat: params.repeat,\n repeat_times: params.repeat_times,\n });\n assertAncsRepeatTimes(meta.repeat_times);\n }\n if (params.enabled !== undefined) {\n meta.enabled = params.enabled;\n }\n\n meta.updatedAt = new Date().toISOString();\n writeMeta(taskDir, meta);\n\n return { meta };\n}\n\nexport function deleteLightRule(\n ctx: LightRuleStorageContext,\n name: string,\n): { name: string } {\n const resolved = resolveLightRuleTask(ctx, name);\n const taskDir = resolved?.taskDir;\n const meta = resolved?.meta;\n\n if (!taskDir || !meta) {\n throw new LightRuleError(\"NOT_FOUND\", `灯效规则 '${name}' 不存在`);\n }\n\n rmSync(taskDir, { recursive: true, force: true });\n\n return { name: meta.name };\n}\n\nexport class LightRuleError extends Error {\n constructor(\n public code: string,\n message: string,\n ) {\n super(message);\n this.name = \"LightRuleError\";\n }\n}\n","import type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport type { Logger } from \"../logger.js\";\nimport { assertAncsRepeatTimes, normalizeRepeatTimes } from \"../light/repeat.js\";\nimport { validateSegments } from \"../light/validators.js\";\nimport { LIGHT_RULE_GATEWAY_METHODS } from \"./names.js\";\nimport type { LightSegment } from \"../types.js\";\nimport type { BroadcastFn } from \"../update/types.js\";\nimport type {\n LightRuleCreateParams,\n LightRuleUpdateParams,\n LightRuleDeleteParams,\n} from \"./types.js\";\nimport { LightRuleError } from \"./storage.js\";\nimport type { LightRuleRegistry } from \"./registry.js\";\n\nfunction resolveRuleIdentifier(params: unknown): string | undefined {\n if (!params || typeof params !== \"object\") return undefined;\n\n const raw = params as Record<string, unknown>;\n const candidates = [raw.name, raw.id, raw.ruleId, raw.ruleName];\n for (const candidate of candidates) {\n if (typeof candidate !== \"string\") continue;\n const normalized = candidate.trim().replace(/\\.json$/i, \"\");\n if (normalized) return normalized;\n }\n\n return undefined;\n}\n\nexport function registerLightRulesGateway(\n api: OpenClawPluginApi,\n registry: LightRuleRegistry,\n logger: Pick<Logger, \"info\" | \"warn\">,\n rememberBroadcast?: (broadcast: BroadcastFn | undefined) => void,\n): void {\n type GatewayHandler = Parameters<OpenClawPluginApi[\"registerGatewayMethod\"]>[1];\n\n const registerGatewayMethodWithBroadcastCapture = (\n method: string,\n handler: GatewayHandler,\n ): void => {\n api.registerGatewayMethod(method, (opts) => {\n rememberBroadcast?.(opts.context?.broadcast);\n return handler(opts);\n });\n };\n\n // lightrules.list\n registerGatewayMethodWithBroadcastCapture(LIGHT_RULE_GATEWAY_METHODS.list, async ({ respond }) => {\n try {\n registry.reload();\n const rules = registry.list().map((rule) => ({\n ...rule,\n id: rule.name,\n }));\n respond(true, { ok: true, rules });\n } catch (err: any) {\n logger.warn(`${LIGHT_RULE_GATEWAY_METHODS.list} failed: ${err?.message}`);\n respond(false, null, {\n code: \"INTERNAL_ERROR\",\n message: err?.message ?? \"Unknown error\",\n });\n }\n });\n\n // lightrules.create\n registerGatewayMethodWithBroadcastCapture(\n LIGHT_RULE_GATEWAY_METHODS.create,\n async ({ params, respond }) => {\n const { name, title, description, segments, repeat, repeat_times } =\n params as unknown as LightRuleCreateParams;\n const resolvedTitle = typeof title === \"string\" && title.trim() ? title.trim() : name;\n\n if (!name || typeof name !== \"string\") {\n respond(false, null, { code: \"INVALID_PARAMS\", message: \"name is required\" });\n return;\n }\n if (!description || typeof description !== \"string\") {\n respond(false, null, { code: \"INVALID_PARAMS\", message: \"description is required\" });\n return;\n }\n\n const validation = validateSegments(segments);\n if (!validation.valid) {\n respond(false, null, {\n code: \"VALIDATION_FAILED\",\n message: JSON.stringify(validation.errors),\n });\n return;\n }\n\n let repeatTimes: number;\n try {\n repeatTimes = normalizeRepeatTimes({ repeat, repeat_times });\n assertAncsRepeatTimes(repeatTimes);\n } catch (err: any) {\n respond(false, null, {\n code: \"VALIDATION_FAILED\",\n message: err?.message ?? \"Unknown error\",\n });\n return;\n }\n\n try {\n const result = await registry.create({\n name,\n title: resolvedTitle,\n description,\n segments: validation.segments,\n repeat_times: repeatTimes,\n });\n logger.info(`Light rule created: ${name}`);\n respond(true, {\n ok: true,\n id: result.meta.name,\n name: result.meta.name,\n title: result.meta.title,\n rule: result.meta,\n });\n } catch (err: any) {\n if (err instanceof LightRuleError) {\n respond(false, null, { code: err.code, message: err.message });\n } else {\n logger.warn(`${LIGHT_RULE_GATEWAY_METHODS.create} failed: ${err?.message}`);\n respond(false, null, {\n code: \"INTERNAL_ERROR\",\n message: err?.message ?? \"Unknown error\",\n });\n }\n }\n },\n );\n\n // lightrules.update\n registerGatewayMethodWithBroadcastCapture(\n LIGHT_RULE_GATEWAY_METHODS.update,\n async ({ params, respond }) => {\n const { title, description, segments, repeat, repeat_times, enabled } =\n params as unknown as LightRuleUpdateParams;\n const name = resolveRuleIdentifier(params);\n const resolvedTitle = typeof title === \"string\" ? title.trim() : undefined;\n\n if (!name) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"name is required (or provide id/ruleId/ruleName)\",\n });\n return;\n }\n if (title !== undefined && !resolvedTitle) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"title must be a non-empty string\",\n });\n return;\n }\n if (description !== undefined && typeof description !== \"string\") {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"description must be a string\",\n });\n return;\n }\n\n let validatedSegments: LightSegment[] | undefined;\n if (segments !== undefined) {\n const validation = validateSegments(segments);\n if (!validation.valid) {\n respond(false, null, {\n code: \"VALIDATION_FAILED\",\n message: JSON.stringify(validation.errors),\n });\n return;\n }\n validatedSegments = validation.segments;\n }\n\n let repeatTimes: number | undefined;\n if (repeat !== undefined || repeat_times !== undefined) {\n try {\n repeatTimes = normalizeRepeatTimes({ repeat, repeat_times });\n assertAncsRepeatTimes(repeatTimes);\n } catch (err: any) {\n respond(false, null, {\n code: \"VALIDATION_FAILED\",\n message: err?.message ?? \"Unknown error\",\n });\n return;\n }\n }\n\n try {\n const result = await registry.update({\n name,\n title: resolvedTitle,\n description,\n segments: validatedSegments,\n repeat_times: repeatTimes,\n enabled,\n });\n logger.info(`Light rule updated: ${name}`);\n respond(true, {\n ok: true,\n id: result.meta.name,\n name: result.meta.name,\n title: result.meta.title,\n updated: true,\n rule: result.meta,\n });\n } catch (err: any) {\n if (err instanceof LightRuleError) {\n respond(false, null, { code: err.code, message: err.message });\n } else {\n logger.warn(`${LIGHT_RULE_GATEWAY_METHODS.update} failed: ${err?.message}`);\n respond(false, null, {\n code: \"INTERNAL_ERROR\",\n message: err?.message ?? \"Unknown error\",\n });\n }\n }\n },\n );\n\n // lightrules.delete\n registerGatewayMethodWithBroadcastCapture(\n LIGHT_RULE_GATEWAY_METHODS.delete,\n async ({ params, respond }) => {\n const name = resolveRuleIdentifier(params as unknown as LightRuleDeleteParams);\n\n if (!name) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"name is required (or provide id/ruleId/ruleName)\",\n });\n return;\n }\n try {\n const result = await registry.delete(name);\n logger.info(`Light rule deleted: ${result.name}`);\n respond(true, {\n ok: true,\n id: result.name,\n name: result.name,\n deleted: true,\n });\n } catch (err: any) {\n if (err instanceof LightRuleError) {\n respond(false, null, { code: err.code, message: err.message });\n } else {\n logger.warn(`${LIGHT_RULE_GATEWAY_METHODS.delete} failed: ${err?.message}`);\n respond(false, null, {\n code: \"INTERNAL_ERROR\",\n message: err?.message ?? \"Unknown error\",\n });\n }\n }\n },\n );\n}\n","/**\n * LightRuleRegistry —— 灯效规则的内存索引 + CRUD 包装\n *\n * 角色定位:\n * - 在事件驱动重构方案下,每条通知到达时都需要拿到\"当前 enabled 的全部规则\"\n * 用来拼装 Agent 的 system prompt。如果每次都扫盘 N 个 meta.json,\n * 5 秒延迟预算会被磨穿,所以引入这个常驻内存的 index。\n * - 同时它是 storage.ts 的 CRUD 包装:所有 create/update/delete 都会先落盘、\n * 再更新内存 Map,保证两者一致。\n *\n * 本类**不**做规则匹配 —— 匹配交给 Agent。registry 只负责\"有哪些规则\"和\n * \"按需拼装 prompt\"。\n *\n * 写路径用一个 promise 链做串行化(最朴素的 mutex),保证并发 CRUD\n * 不会出现\"内存和磁盘交错\"的状态。\n *\n * 见 prd-lightrules-event-driven-refactor.md §数据模型 / §触发流程\n */\n\nimport {\n createLightRule,\n deleteLightRule,\n listLightRules,\n updateLightRule,\n type LightRuleStorageContext,\n} from \"./storage.js\";\nimport type { LightRuleMeta } from \"./types.js\";\n\nexport { LightRuleError } from \"./storage.js\";\n\ntype CreateParams = Parameters<typeof createLightRule>[1];\ntype UpdateParams = Parameters<typeof updateLightRule>[1];\ntype CreateResult = ReturnType<typeof createLightRule>;\ntype UpdateResult = ReturnType<typeof updateLightRule>;\ntype DeleteResult = ReturnType<typeof deleteLightRule>;\n\nexport class LightRuleRegistry {\n private readonly ctx: LightRuleStorageContext;\n /** name → meta 的内存索引;落盘成功后才更新 */\n private readonly index = new Map<string, LightRuleMeta>();\n /** 写路径串行化锁:每次 mutate 都 chain 在前一次之后 */\n private writeChain: Promise<unknown> = Promise.resolve();\n\n constructor(ctx: LightRuleStorageContext) {\n this.ctx = ctx;\n this.reload();\n }\n\n /**\n * 从磁盘重新加载全部规则到内存。仅在构造时和外部显式触发时使用。\n * 正常 CRUD 路径不应该调用本方法 —— 通过 create/update/delete 增量维护即可。\n */\n reload(): void {\n this.index.clear();\n for (const meta of listLightRules(this.ctx)) {\n this.index.set(meta.name, meta);\n }\n }\n\n /** 全部规则(包含 disabled),调用方不要改返回值。 */\n list(): LightRuleMeta[] {\n return Array.from(this.index.values());\n }\n\n /** 仅 enabled 的规则。事件驱动评估链路使用。 */\n getEnabled(): LightRuleMeta[] {\n return this.list().filter((rule) => rule.enabled);\n }\n\n /** 按名字精确查找;不存在返回 null。 */\n get(name: string): LightRuleMeta | null {\n return this.index.get(name) ?? null;\n }\n\n /**\n * 创建规则。落盘成功后再写入内存索引。\n * 失败时 storage 抛 LightRuleError,内存索引保持不变。\n */\n async create(params: CreateParams): Promise<CreateResult> {\n return this.runExclusive(() => {\n const result = createLightRule(this.ctx, params);\n this.index.set(result.meta.name, result.meta);\n return result;\n });\n }\n\n /**\n * 更新规则。落盘成功后再刷新内存条目。\n */\n async update(params: UpdateParams): Promise<UpdateResult> {\n return this.runExclusive(() => {\n const result = updateLightRule(this.ctx, params);\n this.index.set(result.meta.name, result.meta);\n return result;\n });\n }\n\n /**\n * 删除规则。落盘成功后再从内存索引移除。\n */\n async delete(name: string): Promise<DeleteResult> {\n return this.runExclusive(() => {\n const result = deleteLightRule(this.ctx, name);\n this.index.delete(result.name);\n return result;\n });\n }\n\n /**\n * 拼装 Agent 评估用的 system prompt。\n *\n * 当前实现是一个最小可用骨架:列出全部 enabled 规则的 title + name + description。\n * M3 接入真实 Agent 链路时,会按 prd-lightrules-event-driven-refactor.md §Prompt 拼装\n * 的模板补齐\"任务说明 / 输出约束\"等段落。\n *\n * 现在先把方法签名冻结,避免后续散落在多个调用点。\n */\n buildSystemPrompt(): string {\n const enabled = this.getEnabled();\n if (enabled.length === 0) {\n return \"当前没有启用任何灯效规则。\";\n }\n\n const lines: string[] = [\n '你是一个判断\"通知 → 灯效规则\"是否命中的助手。',\n \"\",\n \"下面是用户当前启用的全部灯效规则(按创建时间倒序):\",\n \"\",\n ];\n\n const sorted = [...enabled].sort((a, b) =>\n (b.createdAt ?? \"\").localeCompare(a.createdAt ?? \"\"),\n );\n\n sorted.forEach((rule, idx) => {\n lines.push(\n `[${idx + 1}] title: ${rule.title}`,\n ` name: ${rule.name}`,\n ` description: ${rule.description}`,\n \"\",\n );\n });\n\n lines.push(\n '任务:根据用户接下来发给你的\"通知\"内容,判断哪些规则被命中。',\n \"- 命中 0 条:不调用任何工具,直接结束。\",\n \"- 命中 1 条或多条:对每一条命中的规则调用一次 trigger_light(rule_name)。\",\n \"- 不要回复任何自由文本;判定结果**只**通过 tool calling 表达。\",\n '- 拿不准的时候倾向于\"不触发\",避免骚扰用户。',\n );\n\n return lines.join(\"\\n\");\n }\n\n /**\n * 把一段同步操作排队进 write chain,保证 mutate 串行执行。\n *\n * 用 promise 链做 mutex 是最简单的方案:每次 runExclusive 都把\n * `writeChain` 推进一步。即使前一个任务失败,链也会继续往下走,\n * 后续任务不会被永久阻塞。\n */\n private runExclusive<T>(fn: () => T): Promise<T> {\n const next = this.writeChain.then(\n () => fn(),\n () => fn(),\n );\n // 不让链上的失败传播下去(已在 then 的 onRejected 回调里吸收)\n this.writeChain = next.catch(() => undefined);\n return next;\n }\n}\n","import type { LightSegment } from \"../types.js\";\nimport { assertAncsRepeatTimes, normalizeRepeatTimes, type RepeatArgument } from \"./repeat.js\";\nimport { validateSegments } from \"./validators.js\";\n\nexport const MAX_LIGHT_SEGMENTS = 12;\n\nconst PROTOCOL_DIGITS = [\n \"\\u0080\",\n \"\\u0081\",\n \"\\u0082\",\n \"\\u0083\",\n \"\\u0084\",\n \"\\u0091\",\n \"\\u0092\",\n \"\\u0093\",\n \"\\u0094\",\n \"\\u0095\",\n \"\\u0096\",\n \"\\u0097\",\n] as const;\n\n/** \\u009A = play once, \\u009B = infinite loop */\nconst LED_SEPARATOR_ONCE = \"\\u009A\";\nconst LED_SEPARATOR_LOOP = \"\\u009B\";\n\n/** v0–v10 mapped by index; duration_s=0 is special-cased to v11 (infinite) */\nconst DURATION_STEPS_S = [0.5, 1, 2, 3, 5, 6, 8, 16, 24, 32, 48] as const;\n/** v0–v10 mapped by index; removed 400ms, added 50ms */\nconst INTERVAL_STEPS_MS = [50, 100, 200, 300, 500, 600, 800, 1600, 2400, 3200, 4800] as const;\nconst BREATH_STEPS_MS = [1040, 1560, 2080, 2600, 3100, 4160] as const;\nconst BRIGHTNESS_STEPS = [32, 64, 96, 128, 192, 255] as const;\nconst COLOR_STEPS = [0, 32, 64, 128, 192, 255] as const;\nconst BACKGROUND_BRIGHTNESS_STEPS = [0, 32, 64, 96, 128, 192, 255] as const;\nconst MULTI_CHANNEL_COLOR_COEFFICIENTS = { r: 1, g: 0.25, b: 0.25 } as const;\nconst PURE_WHITE_COLOR_COEFFICIENTS = { r: 1, g: 0.35, b: 0.35 } as const;\n\n/**\n * mode → wire-protocol M value.\n * color_flow encodes to M=v4 (firmware enum APP_LED_CUSTOM_MODE_WAVE_RAINBOW).\n * \"WAVE_RAINBOW\" is a legacy firmware name and does NOT imply rainbow/multi-color semantics;\n * the TS-side enum uses color_flow to avoid that confusion. See imp-custom-led-ai-read.md\n * \"模式选择易错对照\" for the mapping rules.\n */\nconst MODE_TO_INDEX: Record<LightSegment[\"mode\"], number> = {\n wave: 0,\n breath: 1,\n strobe: 2,\n steady: 3,\n color_flow: 4,\n pixel_frame: 5,\n};\n\nexport function buildLightEffectApnsBody(\n segments: LightSegment[],\n repeatInput?: RepeatArgument,\n visibleTextOverride?: string,\n): string {\n assertSegmentCount(segments);\n assertSegmentsValid(segments);\n\n const repeatTimes = normalizeRepeatTimes(repeatInput);\n assertAncsRepeatTimes(repeatTimes);\n\n const visibleText = resolveVisibleText(visibleTextOverride, segments);\n const separator = repeatTimes === 0 ? LED_SEPARATOR_LOOP : LED_SEPARATOR_ONCE;\n const payload = segments.map((segment) => encodeSegment(segment)).join(\"\");\n return `${visibleText}${separator}${payload}`;\n}\n\nfunction resolveVisibleText(\n override: string | undefined,\n segments: LightSegment[],\n): string {\n const trimmed = override?.trim();\n if (trimmed) return trimmed;\n return summarizeSegments(segments);\n}\n\nfunction assertSegmentCount(segments: LightSegment[]): void {\n if (segments.length < 1 || segments.length > MAX_LIGHT_SEGMENTS) {\n throw new Error(`light_control supports 1-${MAX_LIGHT_SEGMENTS} segments`);\n }\n}\n\nfunction summarizeSegments(segments: LightSegment[]): string {\n const modeDesc = segments.map((segment) => segment.mode).join(\"+\");\n return `Effect: ${modeDesc} (${segments.length} segment${segments.length > 1 ? \"s\" : \"\"})`;\n}\n\nfunction assertSegmentsValid(segments: LightSegment[]): void {\n const validation = validateSegments(segments);\n if (!validation.valid) {\n throw new Error(\n validation.errors.map((error) => `${error.field}: ${error.message}`).join(\"; \"),\n );\n }\n}\n\nfunction encodeSegment(segment: LightSegment): string {\n const common = [\n MODE_TO_INDEX[segment.mode],\n quantizeDuration(segment.duration_s),\n ];\n\n let values: number[];\n switch (segment.mode) {\n case \"wave\":\n case \"color_flow\":\n const color = normalizeProtocolColor(segment.color);\n const background = normalizeProtocolColor(segment.background);\n values = [\n ...common,\n quantize(segment.interval_ms ?? 200, INTERVAL_STEPS_MS),\n quantizeBrightnessValue(segment.brightness ?? 0),\n quantize(color.r, COLOR_STEPS),\n quantize(color.g, COLOR_STEPS),\n quantize(color.b, COLOR_STEPS),\n segment.direction === \"rtl\" ? 1 : 0,\n quantizeWindow(segment.window ?? 2),\n quantize(background.r, COLOR_STEPS),\n quantize(background.g, COLOR_STEPS),\n quantize(background.b, COLOR_STEPS),\n quantize(segment.background?.brightness ?? 0, BACKGROUND_BRIGHTNESS_STEPS),\n ];\n break;\n case \"breath\":\n const breathColor = normalizeProtocolColor(segment.color);\n values = [\n ...common,\n quantizeBreathRiseFall(segment.breath_timing?.rise_ms),\n quantizeBreathHoldOff(segment.breath_timing?.hold_ms),\n quantizeBreathRiseFall(segment.breath_timing?.fall_ms),\n quantizeBreathHoldOff(segment.breath_timing?.off_ms),\n quantizeBrightnessValue(segment.brightness ?? 0),\n quantize(breathColor.r, COLOR_STEPS),\n quantize(breathColor.g, COLOR_STEPS),\n quantize(breathColor.b, COLOR_STEPS),\n ];\n break;\n case \"strobe\":\n const strobeColor = normalizeProtocolColor(segment.color);\n values = [\n ...common,\n quantize(segment.interval_ms ?? 200, INTERVAL_STEPS_MS),\n quantizeBrightnessValue(segment.brightness ?? 0),\n quantize(strobeColor.r, COLOR_STEPS),\n quantize(strobeColor.g, COLOR_STEPS),\n quantize(strobeColor.b, COLOR_STEPS),\n ];\n break;\n case \"steady\":\n const steadyColor = normalizeProtocolColor(segment.color);\n values = [\n ...common,\n quantizeBrightnessValue(segment.brightness ?? 0),\n quantize(steadyColor.r, COLOR_STEPS),\n quantize(steadyColor.g, COLOR_STEPS),\n quantize(steadyColor.b, COLOR_STEPS),\n ];\n break;\n case \"pixel_frame\":\n values = encodePixelFrameValues(common, segment);\n break;\n }\n\n return values.map((value) => PROTOCOL_DIGITS[value]).join(\"\");\n}\n\nfunction encodePixelFrameValues(common: number[], segment: LightSegment): number[] {\n const pixels = segment.pixels ?? [];\n return [\n ...common,\n pixels.length - 1,\n ...pixels.flatMap((pixel) => {\n const color = normalizeProtocolColor(pixel.color);\n return [\n pixel.index,\n quantize(color.r, COLOR_STEPS),\n quantize(color.g, COLOR_STEPS),\n quantize(color.b, COLOR_STEPS),\n quantizeBrightnessValue(pixel.brightness),\n ];\n }),\n ];\n}\n\nexport function normalizeProtocolColor(\n color:\n | Pick<NonNullable<LightSegment[\"color\"]>, \"r\" | \"g\" | \"b\">\n | Pick<NonNullable<LightSegment[\"background\"]>, \"r\" | \"g\" | \"b\">\n | undefined,\n): { r: number; g: number; b: number } {\n const normalized = {\n r: color?.r ?? 0,\n g: color?.g ?? 0,\n b: color?.b ?? 0,\n };\n\n if (isPureWhiteProtocolColor(normalized)) {\n return applyProtocolColorCoefficients(normalized, PURE_WHITE_COLOR_COEFFICIENTS);\n }\n\n if (countActiveProtocolColorChannels(normalized) <= 1) {\n return normalized;\n }\n\n return applyProtocolColorCoefficients(normalized, MULTI_CHANNEL_COLOR_COEFFICIENTS);\n}\n\nfunction countActiveProtocolColorChannels(color: { r: number; g: number; b: number }): number {\n return Number(color.r > 0) + Number(color.g > 0) + Number(color.b > 0);\n}\n\nfunction isPureWhiteProtocolColor(color: { r: number; g: number; b: number }): boolean {\n return color.r === 255 && color.g === 255 && color.b === 255;\n}\n\nfunction applyProtocolColorCoefficients(\n color: { r: number; g: number; b: number },\n coefficients: { r: number; g: number; b: number },\n): { r: number; g: number; b: number } {\n return {\n r: scaleProtocolColorChannel(color.r, coefficients.r),\n g: scaleProtocolColorChannel(color.g, coefficients.g),\n b: scaleProtocolColorChannel(color.b, coefficients.b),\n };\n}\n\nfunction scaleProtocolColorChannel(value: number, coefficient: number): number {\n return Math.max(0, Math.min(255, Math.round(value * coefficient)));\n}\n\nfunction quantize(value: number, steps: readonly number[]): number {\n let bestIndex = 0;\n let bestDistance = Number.POSITIVE_INFINITY;\n\n for (const [index, step] of steps.entries()) {\n const distance = Math.abs(value - step);\n if (distance < bestDistance) {\n bestIndex = index;\n bestDistance = distance;\n }\n }\n\n return bestIndex;\n}\n\n/** duration_s=0 maps to v11 (infinite); otherwise quantize to DURATION_STEPS_S */\nfunction quantizeDuration(duration_s: number): number {\n if (duration_s === 0) return 11;\n return quantize(duration_s, DURATION_STEPS_S);\n}\n\n/**\n * brightness=0 maps to v11 (explicit off / pixel-off).\n * Otherwise quantize to BRIGHTNESS_STEPS (v0–v5).\n */\nfunction quantizeBrightnessValue(brightness: number): number {\n if (brightness === 0) return 11;\n return quantize(brightness, BRIGHTNESS_STEPS);\n}\n\nfunction quantizeBreathRiseFall(value: number | undefined): number {\n return quantize(value ?? 1040, BREATH_STEPS_MS);\n}\n\nfunction quantizeBreathHoldOff(value: number | undefined): number {\n if (value === 0) {\n return 5;\n }\n\n return quantize(value ?? 1040, BREATH_STEPS_MS.slice(0, 5));\n}\n\nfunction quantizeWindow(value: 1 | 2 | 3): number {\n return value - 1;\n}\n","import type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport type { Logger } from \"../logger.js\";\nimport { assertAncsRepeatTimes, normalizeRepeatTimes } from \"../light/repeat.js\";\nimport { validateSegments, type ValidationWarning } from \"../light/validators.js\";\nimport { LightRuleError } from \"../light-rules/registry.js\";\nimport { LIGHT_RULE_TOOL_NAMES } from \"../light-rules/names.js\";\nimport type { LightRuleRegistry } from \"../light-rules/registry.js\";\nimport type { LightRuleCreateParams, LightRuleUpdateParams } from \"../light-rules/types.js\";\nimport { MAX_LIGHT_SEGMENTS } from \"../light/protocol.js\";\n\nconst segmentItemSchema = {\n type: \"object\",\n required: [\"mode\", \"duration_s\"],\n additionalProperties: false,\n properties: {\n mode: {\n type: \"string\",\n enum: [\"wave\", \"breath\", \"strobe\", \"steady\", \"color_flow\", \"pixel_frame\"],\n description:\n \"灯效模式:wave 波浪(单色跑马)/ breath 呼吸 / strobe 频闪 / steady 常亮 / \" +\n \"color_flow 流光(1~2 锚点调色板流动;**不是彩虹**,无法生成 7 色彩虹波浪)/ \" +\n \"pixel_frame 逐组像素帧。\" +\n \"易错对照:用户说\\\"红色/蓝色波浪\\\"等单一颜色波浪 → 必须用 wave;用户说\\\"彩虹/七彩/rainbow\\\" → 固件不支持,需告知限制。\",\n },\n duration_s: { type: \"number\", minimum: 0, description: \"持续时长(秒),0 表示无限\" },\n brightness: { type: \"number\", minimum: 0, maximum: 255 },\n color: {\n type: \"object\",\n required: [\"r\", \"g\", \"b\"],\n additionalProperties: false,\n properties: {\n r: { type: \"number\", minimum: 0, maximum: 255 },\n g: { type: \"number\", minimum: 0, maximum: 255 },\n b: { type: \"number\", minimum: 0, maximum: 255 },\n },\n },\n interval_ms: { type: \"number\", minimum: 0 },\n direction: { type: \"string\", enum: [\"ltr\", \"rtl\"] },\n window: { type: \"number\", enum: [1, 2, 3] },\n breath_timing: {\n type: \"object\",\n additionalProperties: false,\n properties: {\n rise_ms: { type: \"number\", minimum: 0 },\n hold_ms: { type: \"number\", minimum: 0 },\n fall_ms: { type: \"number\", minimum: 0 },\n off_ms: { type: \"number\", minimum: 0 },\n },\n },\n frames: { type: \"array\", items: { type: \"array\", items: { type: \"number\" } } },\n frame_duration_ms: { type: \"number\", minimum: 0 },\n background: {\n type: \"object\",\n required: [\"r\", \"g\", \"b\"],\n additionalProperties: false,\n properties: {\n r: { type: \"number\", minimum: 0, maximum: 255 },\n g: { type: \"number\", minimum: 0, maximum: 255 },\n b: { type: \"number\", minimum: 0, maximum: 255 },\n },\n },\n },\n} as const;\n\nconst segmentsSchema = {\n type: \"array\",\n description: \"灯效段序列,1–12 段,按顺序播放\",\n minItems: 1,\n maxItems: MAX_LIGHT_SEGMENTS,\n items: segmentItemSchema,\n} as const;\n\nfunction ok(data: object): { content: [{ type: \"text\"; text: string }]; details: object } {\n return { content: [{ type: \"text\" as const, text: JSON.stringify(data) }], details: data };\n}\n\nfunction err(\n code: string,\n message: string,\n): { content: [{ type: \"text\"; text: string }]; details: object } {\n const data = { ok: false, error: { code, message } };\n return { content: [{ type: \"text\" as const, text: JSON.stringify(data) }], details: data };\n}\n\nexport function registerLightRulesTools(\n api: OpenClawPluginApi,\n registry: LightRuleRegistry,\n logger: Pick<Logger, \"info\" | \"warn\">,\n): void {\n // lightrules_list\n api.registerTool({\n name: LIGHT_RULE_TOOL_NAMES.list,\n label: \"List Light Rules\",\n description:\n '列出所有灯效规则(包含 enabled/disabled 状态)。当用户说\"列出灯效规则\"、\"有哪些灯效规则\"、\"查看规则\"等时调用。' +\n \"注意:灯效规则的所有 CRUD 操作必须通过 lightrules_* 工具完成,禁止直接用 write/edit 修改 tasks/*/meta.json。\",\n parameters: { type: \"object\", properties: {}, additionalProperties: false },\n async execute(_toolCallId, _params) {\n try {\n registry.reload();\n const rules = registry.list().map((rule) => ({ ...rule, id: rule.name }));\n return ok({ ok: true, rules });\n } catch (e: any) {\n logger.warn(`${LIGHT_RULE_TOOL_NAMES.list} tool failed: ${e?.message}`);\n return err(\"INTERNAL_ERROR\", e?.message ?? \"Unknown error\");\n }\n },\n });\n\n // lightrules_create\n api.registerTool({\n name: LIGHT_RULE_TOOL_NAMES.create,\n label: \"Create Light Rule\",\n description:\n '创建一条持久灯效规则,指定内部标识 name、展示名 title、自然语言触发描述和灯效参数。规则会保存到 tasks/<name>/meta.json,并由通知到达后的事件驱动评估触发。' +\n '当用户说\"收到某类通知/消息时亮灯/闪灯/变灯效\"、\"当老板发消息亮红灯\"、\"新增/创建灯效规则\"等时调用。' +\n \"不要直接调用 light_control 代替创建规则;light_control 只会立即亮一次灯,不会出现在灯效规则查询中。\",\n parameters: {\n type: \"object\",\n required: [\"name\", \"title\", \"description\", \"segments\"],\n additionalProperties: false,\n properties: {\n name: {\n type: \"string\",\n description: \"规则的内部唯一标识符(英文 slug,如 red_light_on_wechat)\",\n },\n title: {\n type: \"string\",\n description:\n \"规则的展示名/短标题,应是对 description 的总结凝练,例如“老板微信红灯”\",\n },\n description: {\n type: \"string\",\n description:\n \"自然语言触发条件,同时作为规则用途说明。Agent 按此字段判断是否命中,必须清晰描述「何时触发」\",\n },\n segments: segmentsSchema,\n repeat_times: {\n type: \"number\",\n description: \"整条灯效序列重复次数,0=无限循环,1=播放一次(默认)\",\n },\n },\n },\n async execute(_toolCallId, params) {\n const { name, title, description, segments, repeat_times } =\n params as LightRuleCreateParams;\n const resolvedTitle = typeof title === \"string\" && title.trim() ? title.trim() : name;\n\n if (!name || typeof name !== \"string\")\n return err(\"INVALID_PARAMS\", \"name is required\");\n if (!description || typeof description !== \"string\")\n return err(\"INVALID_PARAMS\", \"description is required\");\n\n const validation = validateSegments(segments);\n if (!validation.valid) return err(\"VALIDATION_FAILED\", JSON.stringify(validation.errors));\n\n let repeatTimes: number;\n try {\n repeatTimes = normalizeRepeatTimes({ repeat_times });\n assertAncsRepeatTimes(repeatTimes);\n } catch (e: any) {\n return err(\"VALIDATION_FAILED\", e?.message ?? \"Unknown error\");\n }\n\n try {\n const result = await registry.create({\n name,\n title: resolvedTitle,\n description,\n segments: validation.segments,\n repeat_times: repeatTimes,\n });\n logger.info(`${LIGHT_RULE_TOOL_NAMES.create} tool: created ${name}`);\n for (const warning of validation.warnings) {\n logger.warn(\n `${LIGHT_RULE_TOOL_NAMES.create} validation warning [${warning.code}] ${warning.field}: ${warning.message}`,\n );\n }\n return ok({\n ok: true,\n id: result.meta.name,\n name: result.meta.name,\n title: result.meta.title,\n rule: result.meta,\n ...(validation.warnings.length > 0 ? { warnings: validation.warnings } : {}),\n });\n } catch (e: any) {\n if (e instanceof LightRuleError) return err(e.code, e.message);\n logger.warn(`${LIGHT_RULE_TOOL_NAMES.create} tool failed: ${e?.message}`);\n return err(\"INTERNAL_ERROR\", e?.message ?? \"Unknown error\");\n }\n },\n });\n\n // lightrules_update\n api.registerTool({\n name: LIGHT_RULE_TOOL_NAMES.update,\n label: \"Update Light Rule\",\n description:\n '修改灯效规则(启用/禁用、改 title、改描述、改灯效参数)。当用户说\"禁用某条规则\"、\"启用规则\"、\"修改灯效规则\"等时调用。' +\n \"必须传入要修改的规则标识 name;如果只知道展示名、序号或不确定 name,先调用 lightrules_list 获取规则列表后再更新。\",\n parameters: {\n type: \"object\",\n required: [\"name\"],\n additionalProperties: false,\n properties: {\n name: { type: \"string\", description: \"要修改的规则名称(唯一标识符)\" },\n title: {\n type: \"string\",\n description: \"新的展示名/短标题(可选)\",\n },\n description: { type: \"string\", description: \"新的触发条件描述(可选)\" },\n enabled: { type: \"boolean\", description: \"true=启用,false=禁用\" },\n segments: { ...segmentsSchema, description: \"新的灯效段序列(可选,不填则保持不变)\" },\n repeat_times: { type: \"number\", description: \"新的重复次数(可选)\" },\n },\n },\n async execute(_toolCallId, params) {\n const { name, title, description, enabled, segments, repeat_times } =\n params as LightRuleUpdateParams;\n const resolvedTitle = typeof title === \"string\" ? title.trim() : undefined;\n\n if (!name || typeof name !== \"string\")\n return err(\n \"INVALID_PARAMS\",\n \"name is required; call lightrules_list first if you do not know the rule name\",\n );\n if (title !== undefined && !resolvedTitle)\n return err(\"INVALID_PARAMS\", \"title must be a non-empty string\");\n if (description !== undefined && typeof description !== \"string\")\n return err(\"INVALID_PARAMS\", \"description must be a string\");\n\n let validatedSegments;\n let segmentWarnings: ValidationWarning[] = [];\n if (segments !== undefined) {\n const validation = validateSegments(segments);\n if (!validation.valid) return err(\"VALIDATION_FAILED\", JSON.stringify(validation.errors));\n validatedSegments = validation.segments;\n segmentWarnings = validation.warnings;\n }\n\n let repeatTimes: number | undefined;\n if (repeat_times !== undefined) {\n try {\n repeatTimes = normalizeRepeatTimes({ repeat_times });\n assertAncsRepeatTimes(repeatTimes);\n } catch (e: any) {\n return err(\"VALIDATION_FAILED\", e?.message ?? \"Unknown error\");\n }\n }\n\n try {\n const result = await registry.update({\n name,\n title: resolvedTitle,\n description,\n segments: validatedSegments,\n repeat_times: repeatTimes,\n enabled,\n });\n logger.info(`${LIGHT_RULE_TOOL_NAMES.update} tool: updated ${name}`);\n for (const warning of segmentWarnings) {\n logger.warn(\n `${LIGHT_RULE_TOOL_NAMES.update} validation warning [${warning.code}] ${warning.field}: ${warning.message}`,\n );\n }\n return ok({\n ok: true,\n name: result.meta.name,\n title: result.meta.title,\n updated: true,\n rule: result.meta,\n ...(segmentWarnings.length > 0 ? { warnings: segmentWarnings } : {}),\n });\n } catch (e: any) {\n if (e instanceof LightRuleError) return err(e.code, e.message);\n logger.warn(`${LIGHT_RULE_TOOL_NAMES.update} tool failed: ${e?.message}`);\n return err(\"INTERNAL_ERROR\", e?.message ?? \"Unknown error\");\n }\n },\n });\n\n // lightrules_delete\n api.registerTool({\n name: LIGHT_RULE_TOOL_NAMES.delete,\n label: \"Delete Light Rule\",\n description:\n '删除一条灯效规则(不可恢复)。当用户说\"删除灯效规则\"、\"移除规则\"等时调用。',\n parameters: {\n type: \"object\",\n required: [\"name\"],\n additionalProperties: false,\n properties: {\n name: { type: \"string\", description: \"要删除的规则名称\" },\n },\n },\n async execute(_toolCallId, params) {\n const { name } = params as { name: string };\n\n if (!name || typeof name !== \"string\")\n return err(\"INVALID_PARAMS\", \"name is required\");\n\n try {\n const result = await registry.delete(name);\n logger.info(`${LIGHT_RULE_TOOL_NAMES.delete} tool: deleted ${name}`);\n return ok({ ok: true, name: result.name, deleted: true });\n } catch (e: any) {\n if (e instanceof LightRuleError) return err(e.code, e.message);\n logger.warn(`${LIGHT_RULE_TOOL_NAMES.delete} tool failed: ${e?.message}`);\n return err(\"INTERNAL_ERROR\", e?.message ?? \"Unknown error\");\n }\n },\n });\n}\n","/**\n * InlineLightRuleEvaluator —— 进程内灯效规则评估器\n *\n * 事件驱动重构的\"轻量路径\"实现:收到一批新通知后,通过 PiAiInvoker 做一次\n * LLM 匹配,再对命中的规则直接调用 `sendLightEffect`。全流程在插件进程内\n * 完成,不走 cron job / subagent session / agent turn。\n *\n * 与旧路径的关键差异:\n * - 旧:每条通知 → 一次完整 OpenClaw agent session(高 overhead + 贵模型)\n * - 新:每批通知 → 一次 Haiku complete()(数百 token 输入 / 数十 token 输出)\n *\n * 返回值语义:\n * - true:评估链路完整跑完(可能 0 命中、可能触发了 N 次灯效)\n * - false:invoker 调用失败,调用方据此决定是否回退 legacy 路径\n */\n\nimport { requireApiKey } from \"../auth/credentials.js\";\nimport { sendLightEffect } from \"../light/sender.js\";\nimport type { Logger } from \"../logger.js\";\nimport type { StoredNotification } from \"../notification/storage.js\";\nimport type { LightRuleEvaluationTrace } from \"./evaluation-scheduler.js\";\nimport type { PiAiInvoker } from \"./pi-invoker.js\";\nimport type { LightRuleRegistry } from \"./registry.js\";\nimport type { LightRuleMeta } from \"./types.js\";\n\nexport class InlineLightRuleEvaluator {\n private readonly logger: Pick<Logger, \"info\" | \"warn\">;\n private readonly registry: LightRuleRegistry;\n private readonly invoker: PiAiInvoker;\n\n constructor(deps: {\n logger: Pick<Logger, \"info\" | \"warn\">;\n registry: LightRuleRegistry;\n invoker: PiAiInvoker;\n }) {\n this.logger = deps.logger;\n this.registry = deps.registry;\n this.invoker = deps.invoker;\n }\n\n /**\n * 评估一批新通知。\n *\n * @returns true 表示评估流程正常结束;false 表示 invoker 失败,调用方可选择回退。\n */\n async evaluate(\n notifications: StoredNotification[],\n trace?: LightRuleEvaluationTrace,\n ): Promise<boolean> {\n if (notifications.length === 0) return true;\n\n const traceTag = trace?.flushId ?? \"flush_none\";\n\n this.reloadRegistry(\"before evaluation\", traceTag);\n const rules = this.registry.getEnabled();\n if (rules.length === 0) {\n this.logger.info(\n `lightrules[${traceTag}]: no enabled rules (notifications=${notifications.length})`,\n );\n return true;\n }\n\n this.logger.info(\n `lightrules[${traceTag}]: evaluating notifications=${notifications.length} rules=${rules.length}`,\n );\n\n const matchStartedAtMs = Date.now();\n const matches = await this.invoker.matchNotifications(\n notifications,\n rules,\n trace?.flushId,\n );\n const matchElapsedMs = Date.now() - matchStartedAtMs;\n if (matches === null) {\n this.logger.warn(\n `lightrules[${traceTag}]: match failed (notifications=${notifications.length}, rules=${rules.length}, elapsedMs=${matchElapsedMs})`,\n );\n return false;\n }\n\n if (matches.length === 0) {\n this.logger.info(\n `lightrules[${traceTag}]: 0 matches (notifications=${notifications.length}, rules=${rules.length}, elapsedMs=${matchElapsedMs})`,\n );\n return true;\n }\n\n this.logger.info(\n `lightrules[${traceTag}]: matched ${matches.length} hit(s) in ${matchElapsedMs}ms`,\n );\n\n // 同一批里同一条规则只触发一次:多条通知撞同一个规则,按\"一次提醒\"处理,\n // 避免灯效反复抢占,且节省下游 HTTP 调用。\n const firedRules = new Set<string>();\n this.reloadRegistry(\"before triggering\", traceTag);\n for (const match of matches) {\n if (firedRules.has(match.ruleName)) continue;\n const rule = this.registry.get(match.ruleName);\n if (!rule) {\n this.logger.warn(\n `lightrules[${traceTag}]: matched rule '${match.ruleName}' skipped - not found after reload`,\n );\n continue;\n }\n if (!rule.enabled) {\n this.logger.info(\n `lightrules[${traceTag}]: matched rule '${match.ruleName}' skipped - disabled after reload`,\n );\n continue;\n }\n firedRules.add(match.ruleName);\n const notification = notifications[match.notificationIndex];\n await this.triggerLight(rule, notification, traceTag);\n }\n\n this.logger.info(\n `lightrules[${traceTag}]: fired ${firedRules.size} rule(s): ${[...firedRules].join(\", \")} ` +\n `(from ${matches.length} match(es) across ${notifications.length} notification(s))`,\n );\n return true;\n }\n\n private reloadRegistry(stage: string, traceTag: string): void {\n try {\n this.registry.reload();\n } catch (err: any) {\n this.logger.warn(\n `lightrules[${traceTag}]: registry reload failed ${stage}: ${err?.message ?? err}`,\n );\n }\n }\n\n private async triggerLight(\n rule: LightRuleMeta,\n notification: StoredNotification | undefined,\n traceTag: string,\n ): Promise<void> {\n let apiKey: string;\n try {\n apiKey = requireApiKey();\n } catch (err: any) {\n this.logger.warn(\n `lightrules[${traceTag}]: trigger '${rule.name}' skipped - no API key: ${err?.message ?? err}`,\n );\n return;\n }\n\n const reason = buildTriggerReason(rule, notification);\n this.logger.info(\n `lightrules[${traceTag}]: trigger rule='${rule.name}' ` +\n `notificationTs=${notification?.timestamp ?? \"-\"} ` +\n `app=${notification?.appDisplayName ?? notification?.appName ?? \"-\"}`,\n );\n\n const startedAtMs = Date.now();\n try {\n const result = await sendLightEffect(\n apiKey,\n rule.segments,\n this.logger,\n { repeat_times: rule.repeat_times },\n reason,\n rule.title,\n );\n if (result.ok) {\n this.logger.info(\n `lightrules[${traceTag}]: trigger '${rule.name}' ok bizUniqueId=${result.bizUniqueId ?? \"-\"} elapsedMs=${Date.now() - startedAtMs}`,\n );\n } else {\n this.logger.warn(\n `lightrules[${traceTag}]: trigger '${rule.name}' http-failed (${result.status ?? \"?\"}) ` +\n `elapsedMs=${Date.now() - startedAtMs}: ${result.error}`,\n );\n }\n } catch (err: any) {\n this.logger.warn(\n `lightrules[${traceTag}]: trigger '${rule.name}' exception elapsedMs=${Date.now() - startedAtMs}: ${err?.message ?? err}`,\n );\n }\n }\n}\n\nconst REASON_CONTENT_MAX = 40;\n\nfunction buildTriggerReason(\n rule: LightRuleMeta,\n notification: StoredNotification | undefined,\n): string {\n const ruleLabel = rule.title?.trim() || rule.name;\n if (!notification) {\n return `触发\"${ruleLabel}\"灯效`;\n }\n\n const app = notification.appDisplayName?.trim() || notification.appName.trim();\n const sender = notification.senderName?.trim() || notification.title?.trim();\n const conversation = notification.conversationName?.trim();\n const isGroup = notification.conversationType === \"group\";\n\n let where = app;\n if (isGroup) {\n where = conversation ? `${app}群聊\"${conversation}\"` : `${app}群聊`;\n }\n\n const action = sender ? `${sender}发来消息` : \"收到新消息\";\n const snippet = summarizeContent(notification.content);\n const detail = snippet ? `:${snippet}` : \"\";\n\n return `检测到${where}中${action}${detail},触发\"${ruleLabel}\"灯效`;\n}\n\nfunction summarizeContent(content: string | undefined): string {\n const trimmed = content?.trim();\n if (!trimmed) return \"\";\n if (trimmed.length <= REASON_CONTENT_MAX) return trimmed;\n return `${trimmed.slice(0, REASON_CONTENT_MAX)}…`;\n}\n","import { randomUUID } from \"node:crypto\";\nimport { buildLightEffectApnsBody } from \"./protocol.js\";\nimport { getEnvUrls } from \"../env.js\";\nimport type { LightSegment } from \"../types.js\";\nimport type { RepeatArgument } from \"./repeat.js\";\n\nexport interface SendLightResult {\n ok: boolean;\n bizUniqueId?: string;\n response?: unknown;\n status?: number;\n error?: string;\n}\n\nexport async function sendLightEffect(\n apiKey: string,\n segments: LightSegment[],\n logger?: { info: (msg: string) => void; warn: (msg: string) => void },\n repeatInput?: RepeatArgument,\n reason?: string,\n title?: string,\n): Promise<SendLightResult> {\n const apiUrl = getEnvUrls().lightApiUrl;\n const appKey = process.env.LIGHT_APP_KEY;\n const templateId = process.env.LIGHT_TEMPLATE_ID;\n const resolvedTitle = resolveLightTitle(title, reason, segments);\n\n logger?.info(\n `Light sender: apiUrl=${apiUrl ?? \"UNSET\"}, appKey=${appKey ? appKey.substring(0, 8) + \"…\" : \"UNSET\"}, templateId=${templateId ?? \"UNSET\"}, apiKey=${apiKey ? apiKey.substring(0, 20) + \"…\" : \"EMPTY\"}, title=${resolvedTitle}, reason=${reason ?? \"\"}, segments=${JSON.stringify(segments)}`,\n );\n\n if (!apiUrl || !appKey || !templateId) {\n return {\n ok: false,\n error:\n \"灯效 API 未配置,请设置环境变量 LIGHT_API_URL / LIGHT_APP_KEY / LIGHT_TEMPLATE_ID\",\n };\n }\n\n let bizContent: string;\n try {\n bizContent = buildLightEffectApnsBody(segments, repeatInput, reason);\n } catch (error: any) {\n return { ok: false, error: error?.message ?? String(error) };\n }\n const bizUniqueId = randomUUID();\n\n const requestBody = {\n appKey,\n bizMap: { noticeType: \"APP_NOTIFICATION_IMPORTANT\", title: resolvedTitle, reason },\n bizUniqueId,\n paramsMap: { bizContent },\n pushType: \"SPECIFY_PUSH\",\n templateId,\n };\n\n logger?.info(\n `Light sender: POST ${apiUrl}, bizUniqueId=${bizUniqueId}, body=${JSON.stringify(requestBody).substring(0, 500)}`,\n );\n\n const res = await fetch(apiUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Api-Key-Id\": apiKey.startsWith(\"Bearer \")\n ? apiKey.slice(\"Bearer \".length)\n : apiKey,\n },\n body: JSON.stringify(requestBody),\n });\n\n const resBody = await res.text();\n if (!res.ok) {\n logger?.warn(\n `Light sender: FAILED ${res.status}, url=${apiUrl}, resBody=${resBody.substring(0, 500)}`,\n );\n return { ok: false, status: res.status, error: resBody };\n }\n\n logger?.info(`Light sender: OK bizUniqueId=${bizUniqueId}, resBody=${resBody.substring(0, 200)}`);\n return { ok: true, bizUniqueId, response: JSON.parse(resBody) };\n}\n\nfunction resolveLightTitle(\n title: string | undefined,\n reason: string | undefined,\n segments: LightSegment[],\n): string {\n const trimmedTitle = title?.trim();\n if (trimmedTitle) return trimmedTitle;\n\n const trimmedReason = reason?.trim();\n if (trimmedReason) return trimmedReason;\n\n const modeDesc = segments.map((segment) => segment.mode).join(\"+\");\n return `Effect: ${modeDesc || \"custom\"}`;\n}\n","import { randomBytes } from \"node:crypto\";\nimport type { Logger } from \"../logger.js\";\nimport type { StoredNotification } from \"../notification/storage.js\";\n\nexport const DEFAULT_LIGHT_RULE_EVALUATION_DEBOUNCE_MS = 1_000;\n\nexport interface LightRuleEvaluationTrace {\n /** 本批 evaluate 的唯一 id,用于跨模块串联日志。 */\n flushId: string;\n /** 本批 evaluate 涵盖的所有 ingest 来源 id(按入队顺序)。 */\n ingestIds: string[];\n}\n\nexport interface LightRuleEvaluator {\n evaluate(\n notifications: StoredNotification[],\n trace?: LightRuleEvaluationTrace,\n ): Promise<boolean>;\n}\n\nexport interface LightRuleEvaluationSchedulerOptions {\n debounceMs?: number;\n}\n\ninterface PendingEntry {\n notification: StoredNotification;\n ingestId: string;\n enqueuedAtMs: number;\n}\n\nexport class LightRuleEvaluationScheduler {\n private readonly evaluator: LightRuleEvaluator;\n private readonly logger: Pick<Logger, \"info\" | \"warn\">;\n private readonly debounceMs: number;\n private readonly pending: PendingEntry[] = [];\n private timer: ReturnType<typeof setTimeout> | null = null;\n private running = false;\n private flushRequestedWhileRunning = false;\n\n constructor(deps: {\n evaluator: LightRuleEvaluator;\n logger: Pick<Logger, \"info\" | \"warn\">;\n options?: LightRuleEvaluationSchedulerOptions;\n }) {\n this.evaluator = deps.evaluator;\n this.logger = deps.logger;\n const debounceMs =\n deps.options?.debounceMs ?? DEFAULT_LIGHT_RULE_EVALUATION_DEBOUNCE_MS;\n this.debounceMs = Number.isFinite(debounceMs) && debounceMs >= 0\n ? debounceMs\n : DEFAULT_LIGHT_RULE_EVALUATION_DEBOUNCE_MS;\n }\n\n enqueue(\n notifications: StoredNotification[],\n ingestId: string = \"ing_unknown\",\n ): void {\n if (notifications.length === 0) return;\n const enqueuedAtMs = Date.now();\n for (const n of notifications) {\n this.pending.push({ notification: n, ingestId, enqueuedAtMs });\n }\n this.logger.info(\n `lightrules[${ingestId}]: scheduler enqueue ${notifications.length} item(s), ` +\n `pending=${this.pending.length}, debounceMs=${this.debounceMs}, running=${this.running}`,\n );\n this.scheduleFlush();\n }\n\n private scheduleFlush(): void {\n if (this.timer !== null) return;\n\n this.timer = setTimeout(() => {\n this.timer = null;\n void this.drain().catch((err) => {\n this.logger.warn(\n `lightrules: scheduled evaluation failed: ${err?.message ?? err}`,\n );\n });\n }, this.debounceMs);\n\n const maybeNodeTimer = this.timer as { unref?: () => void };\n maybeNodeTimer.unref?.();\n }\n\n private async drain(): Promise<void> {\n if (this.running) {\n this.flushRequestedWhileRunning = true;\n return;\n }\n\n const batch = this.pending.splice(0);\n if (batch.length === 0) return;\n\n const flushId = `flush_${randomBytes(4).toString(\"hex\")}`;\n const ingestIds = uniqueOrdered(batch.map((b) => b.ingestId));\n const firstEnqueuedAtMs = batch[0].enqueuedAtMs;\n const waitedMs = Date.now() - firstEnqueuedAtMs;\n const notifications = batch.map((b) => b.notification);\n\n this.logger.info(\n `lightrules[${flushId}]: drain start batch=${batch.length} ` +\n `ingestIds=[${ingestIds.join(\",\")}] waitedMs=${waitedMs}`,\n );\n\n this.running = true;\n const startedAtMs = Date.now();\n try {\n await this.evaluator.evaluate(notifications, { flushId, ingestIds });\n this.logger.info(\n `lightrules[${flushId}]: drain end elapsedMs=${Date.now() - startedAtMs}`,\n );\n } catch (err: any) {\n this.logger.warn(\n `lightrules[${flushId}]: evaluation failed (notifications=${batch.length}) ` +\n `elapsedMs=${Date.now() - startedAtMs}: ${err?.message ?? err}`,\n );\n } finally {\n this.running = false;\n if (this.pending.length > 0) {\n if (this.flushRequestedWhileRunning) {\n this.flushRequestedWhileRunning = false;\n void this.drain().catch((err) => {\n this.logger.warn(\n `lightrules: queued evaluation failed: ${err?.message ?? err}`,\n );\n });\n } else {\n this.scheduleFlush();\n }\n } else {\n this.flushRequestedWhileRunning = false;\n }\n }\n }\n}\n\nfunction uniqueOrdered(items: string[]): string[] {\n const seen = new Set<string>();\n const out: string[] = [];\n for (const item of items) {\n if (seen.has(item)) continue;\n seen.add(item);\n out.push(item);\n }\n return out;\n}\n","/**\n * PiAiInvoker —— 灯效规则事件驱动评估的\"轻量 LLM 调用\"实现\n *\n * 替代原先的 `sessionTarget: \"isolated\"` agent turn / subagent session 路径:\n * 每条通知到达后,仅发起一次 pi-ai `complete()` 请求,让模型直接输出 JSON\n * 命中结果。不启动 OpenClaw agent 循环,不加载工具 / skill / system prompt 栈。\n *\n * 模型默认跟随 OpenClaw 主 Agent 当前配置。鉴权 / provider 解析全部\n * 由 `prepareSimpleCompletionModelForAgent` 走 OpenClaw agent config 统一路径。\n *\n * 失败策略:任何环节失败(auth / network / 解析)都返回 null,调用方决定是否\n * 回退到 legacy agent session 路径;本类不抛。\n */\n\nimport {\n prepareSimpleCompletionModel,\n prepareSimpleCompletionModelForAgent,\n completeWithPreparedSimpleCompletionModel,\n} from \"openclaw/plugin-sdk/agent-runtime\";\nimport type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport type { StoredNotification } from \"../notification/storage.js\";\nimport type { LightRuleMeta } from \"./types.js\";\n\nconst DEFAULT_PROVIDER = \"anthropic\";\nconst DEFAULT_MODEL_ID = \"claude-haiku-4-5-20251001\";\nconst DEFAULT_AGENT_ID = \"main\";\nconst DEFAULT_TIMEOUT_MS = 30_000;\nconst DEFAULT_MAX_ATTEMPTS = 2;\nconst MAX_OUTPUT_TOKENS = 512;\n\nexport interface LlmMatchResult {\n /** 命中通知在入参数组中的下标 */\n notificationIndex: number;\n /** 命中规则名 */\n ruleName: string;\n}\n\nexport interface PiAiInvokerOptions {\n /** Optional explicit provider/model override. Omit to follow the OpenClaw agent default. */\n provider?: string;\n modelId?: string;\n /** Optional full model ref override for the selected agent, e.g. \"openrouter/auto\". */\n modelRef?: string;\n /** Agent whose configured model should be used when no explicit provider/model is set. */\n agentId?: string;\n timeoutMs?: number;\n maxAttempts?: number;\n}\n\ntype PreparedCompletion =\n | Awaited<ReturnType<typeof prepareSimpleCompletionModel>>\n | Awaited<ReturnType<typeof prepareSimpleCompletionModelForAgent>>;\n\nexport class PiAiInvoker {\n constructor(\n private readonly api: OpenClawPluginApi,\n private readonly logger: { info: (m: string) => void; warn: (m: string) => void },\n private readonly options: PiAiInvokerOptions = {},\n ) {}\n\n /**\n * 对一批通知和当前启用的规则做一次 LLM 匹配。\n *\n * 返回:\n * - `LlmMatchResult[]`:匹配成功(可能为空数组,即 0 命中)\n * - `null`:调用失败(模型准备失败 / 网络 / 解析)。调用方据此决定是否回退。\n */\n async matchNotifications(\n notifications: StoredNotification[],\n rules: LightRuleMeta[],\n flushId: string = \"flush_none\",\n ): Promise<LlmMatchResult[] | null> {\n if (notifications.length === 0 || rules.length === 0) return [];\n\n const traceTag = flushId;\n\n let label: string;\n let prepared: PreparedCompletion;\n try {\n ({ label, prepared } = await this.prepareCompletionModel());\n } catch (err: any) {\n this.logger.warn(\n `PiAiInvoker[${traceTag}]: prepare failed: ${err?.message ?? String(err)}`,\n );\n return null;\n }\n if (\"error\" in prepared) {\n this.logger.warn(\n `PiAiInvoker[${traceTag}]: prepare ${label} failed: ${prepared.error}`,\n );\n return null;\n }\n\n const systemPrompt = buildSystemPrompt(rules);\n const userMessage = buildUserMessage(notifications);\n const baseTimeoutMs = this.options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const maxAttempts = Math.max(1, this.options.maxAttempts ?? DEFAULT_MAX_ATTEMPTS);\n\n for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {\n const timeoutMs = baseTimeoutMs * attempt;\n const startedAtMs = Date.now();\n this.logger.info(\n `PiAiInvoker[${traceTag}]: complete attempt ${attempt}/${maxAttempts} ` +\n `model=${label} timeoutMs=${timeoutMs} notifications=${notifications.length} rules=${rules.length}`,\n );\n try {\n const resp = await completeWithPreparedSimpleCompletionModel({\n model: prepared.model,\n auth: prepared.auth,\n context: {\n systemPrompt,\n messages: [\n { role: \"user\", content: userMessage, timestamp: Date.now() },\n ],\n },\n options: {\n temperature: 0,\n maxTokens: MAX_OUTPUT_TOKENS,\n signal: AbortSignal.timeout(timeoutMs),\n cacheRetention: \"short\",\n },\n });\n\n const elapsedMs = Date.now() - startedAtMs;\n\n if (resp.stopReason === \"error\" || resp.stopReason === \"aborted\") {\n const retryable = resp.stopReason === \"aborted\" && attempt < maxAttempts;\n this.logger.warn(\n `PiAiInvoker[${traceTag}]: complete stopped with ${resp.stopReason}: ${resp.errorMessage ?? \"n/a\"} ` +\n `(attempt ${attempt}/${maxAttempts}, timeoutMs=${timeoutMs}, elapsedMs=${elapsedMs}${retryable ? \", retrying\" : \"\"})`,\n );\n if (retryable) {\n continue;\n }\n return null;\n }\n\n const text = extractText(resp.content);\n const parsed = parseMatchResult(text, notifications.length, rules);\n this.logger.info(\n `PiAiInvoker[${traceTag}]: complete ok attempt ${attempt}/${maxAttempts} ` +\n `stopReason=${resp.stopReason} elapsedMs=${elapsedMs} matches=${parsed.length}`,\n );\n return parsed;\n } catch (err: any) {\n const message = err?.message ?? String(err);\n const elapsedMs = Date.now() - startedAtMs;\n const retryable =\n attempt < maxAttempts\n && (err?.name === \"AbortError\" || /\\babort(?:ed)?\\b/i.test(message));\n this.logger.warn(\n `PiAiInvoker[${traceTag}]: complete failed: ${message} ` +\n `(attempt ${attempt}/${maxAttempts}, elapsedMs=${elapsedMs}${retryable ? \", retrying\" : \"\"})`,\n );\n if (retryable) {\n continue;\n }\n return null;\n }\n }\n\n return null;\n }\n\n private async prepareCompletionModel(): Promise<{\n label: string;\n prepared: PreparedCompletion;\n }> {\n if (this.options.provider || this.options.modelId) {\n const provider = this.options.provider ?? DEFAULT_PROVIDER;\n const modelId = this.options.modelId ?? DEFAULT_MODEL_ID;\n const prepared = await prepareSimpleCompletionModel({\n cfg: this.api.config,\n provider,\n modelId,\n });\n return { label: `${provider}/${modelId}`, prepared };\n }\n\n const agentId = this.options.agentId?.trim() || DEFAULT_AGENT_ID;\n const modelRef = this.options.modelRef?.trim();\n const prepared = await prepareSimpleCompletionModelForAgent({\n cfg: this.api.config,\n agentId,\n ...(modelRef ? { modelRef } : {}),\n });\n const label =\n \"selection\" in prepared && prepared.selection\n ? `${prepared.selection.provider}/${prepared.selection.modelId} (agent=${agentId})`\n : `agent=${agentId} default model`;\n return { label, prepared };\n }\n}\n\nfunction extractText(content: unknown): string {\n if (!Array.isArray(content)) return \"\";\n const parts: string[] = [];\n for (const c of content) {\n if (c && typeof c === \"object\" && (c as any).type === \"text\") {\n const t = (c as any).text;\n if (typeof t === \"string\") parts.push(t);\n }\n }\n return parts.join(\"\");\n}\n\nfunction buildSystemPrompt(rules: LightRuleMeta[]): string {\n const lines: string[] = [\n '你是\"手机通知 → 灯效规则\"命中匹配助手。',\n \"只根据规则 description 和通知字段判断,不要猜测。\",\n \"拿不准就不触发。\",\n \"输出必须是纯 JSON,格式固定为:\",\n '{\"matches\":[{\"i\":<通知下标>,\"rule\":\"<规则name>\"}]}',\n '0 命中输出 {\"matches\":[]}; rule 必须精确等于下方 name。',\n \"\",\n \"匹配要点:\",\n \"- 发件人/联系人规则:优先看 sender,其次 conversation_name、title、content 开头的 \\\"X:\\\"/\\\"X:\\\" 前缀;忽略空白、emoji 和中英文标点差异。\",\n \"- App 通知规则:看 app/appDisplayName 是否符合 description。\",\n \"- 关键词规则:看 title + content 是否包含或语义等价于 description 指定的关键词。\",\n \"- 语义规则:综合 title + content 判断;不要把正文里随便提到的人名当发件人。\",\n \"\",\n \"当前启用规则:\",\n ];\n const sorted = [...rules].sort(\n (a, b) => (b.createdAt ?? \"\").localeCompare(a.createdAt ?? \"\"),\n );\n sorted.forEach((rule, idx) => {\n lines.push(\n `[${idx + 1}] name=${rule.name}`,\n `title=${rule.title}`,\n `description=${rule.description}`,\n );\n });\n return lines.join(\"\\n\");\n}\n\nfunction buildUserMessage(notifications: StoredNotification[]): string {\n const lines: string[] = [\n `以下 ${notifications.length} 条新手机通知,按顺序编号:`,\n \"\",\n ];\n notifications.forEach((n, i) => {\n const app = n.appDisplayName ?? n.appName;\n lines.push(`[${i}] app=${app} time=${n.timestamp}`);\n if (n.senderName) {\n lines.push(` sender: ${n.senderName}`);\n }\n if (n.conversationType) {\n lines.push(` conversation_type: ${n.conversationType}`);\n }\n if (n.conversationName) {\n lines.push(` conversation_name: ${n.conversationName}`);\n }\n lines.push(` title: ${n.title}`, ` content: ${n.content}`, \"\");\n });\n lines.push(\"请判断每条通知命中了哪些规则,按约定格式输出 JSON。\");\n return lines.join(\"\\n\");\n}\n\nfunction parseMatchResult(\n rawText: string,\n notificationCount: number,\n rules: LightRuleMeta[],\n): LlmMatchResult[] {\n if (!rawText) return [];\n // 容错:模型有时会套 ```json ... ```,剥掉代码块围栏\n const text = rawText\n .trim()\n .replace(/^```(?:json)?\\s*/i, \"\")\n .replace(/\\s*```$/i, \"\")\n .trim();\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch {\n return [];\n }\n if (!parsed || typeof parsed !== \"object\") return [];\n\n const raw = (parsed as { matches?: unknown }).matches;\n if (!Array.isArray(raw)) return [];\n\n const validRuleNames = new Set(rules.map((r) => r.name));\n const results: LlmMatchResult[] = [];\n for (const m of raw) {\n if (!m || typeof m !== \"object\") continue;\n const entry = m as { i?: unknown; index?: unknown; rule?: unknown };\n const i =\n typeof entry.i === \"number\"\n ? entry.i\n : typeof entry.index === \"number\"\n ? entry.index\n : -1;\n const ruleName = typeof entry.rule === \"string\" ? entry.rule : null;\n if (!Number.isInteger(i) || i < 0 || i >= notificationCount) continue;\n if (!ruleName || !validRuleNames.has(ruleName)) continue;\n results.push({ notificationIndex: i, ruleName });\n }\n return results;\n}\n","import type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport { loadEnvName } from \"../env.js\";\nimport type { Logger } from \"../logger.js\";\nimport { createTunnelService } from \"../tunnel/service.js\";\nimport type { PluginConfig } from \"../types.js\";\nimport { resolveUpdateChannel } from \"../update/channel.js\";\nimport { registerAutoUpdate } from \"../update/index.js\";\nimport type { BroadcastFn } from \"../update/types.js\";\n\ninterface AutoUpdateDeps {\n api: OpenClawPluginApi;\n config: PluginConfig;\n logger: Logger;\n getBroadcastFn: () => BroadcastFn | null;\n cacheBroadcast: (broadcast: BroadcastFn | undefined) => void;\n tunnelService: ReturnType<typeof createTunnelService> | null;\n}\n\nexport function registerAutoUpdateLifecycle(\n deps: AutoUpdateDeps,\n): ReturnType<typeof registerAutoUpdate> {\n const {\n api,\n config,\n logger,\n getBroadcastFn,\n cacheBroadcast,\n tunnelService,\n } = deps;\n\n const autoUpdateConfig = {\n ...config.autoUpdate,\n channel: resolveUpdateChannel({\n configuredChannel: config.autoUpdate?.channel,\n envName: loadEnvName(),\n }),\n };\n\n const autoUpdateLifecycle = registerAutoUpdate(\n api,\n logger,\n autoUpdateConfig,\n getBroadcastFn,\n cacheBroadcast,\n tunnelService\n ? {\n notifyUpdateAvailable: (update) => tunnelService.notifyUpdateAvailable(update),\n clearPendingUpdate: () => tunnelService.clearPendingUpdate(),\n }\n : undefined,\n );\n\n api.registerService({\n id: \"update-checker\",\n start() {\n autoUpdateLifecycle.start();\n },\n stop() {\n autoUpdateLifecycle.stop();\n },\n });\n\n logger.info(\"自动更新检查服务已注册\");\n return autoUpdateLifecycle;\n}\n","import type { EnvName } from \"../env.js\";\nimport type { AutoUpdateConfig } from \"./types.js\";\n\n/**\n * 解析自动更新频道。\n *\n * 默认规则:\n * - 生产环境始终走 latest,避免正式客户端收到 beta 更新推送\n * - 非生产环境用户显式配置时,以配置为准\n * - 非生产环境默认走 beta\n */\nexport function resolveUpdateChannel(params: {\n configuredChannel?: AutoUpdateConfig[\"channel\"];\n envName: EnvName;\n}): \"latest\" | \"beta\" {\n if (params.envName === \"production\") {\n return \"latest\";\n }\n\n if (params.configuredChannel) {\n return params.configuredChannel;\n }\n\n return \"beta\";\n}\n","import { join } from \"node:path\";\nimport type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport type { Logger } from \"../logger.js\";\nimport { resolvePluginStateDir } from \"../plugin/runtime-state.js\";\nimport type {\n AutoUpdateConfig,\n BroadcastFn,\n ExternalUpdateNotifier,\n UpdateInfo,\n} from \"./types.js\";\nimport { UpdateChecker } from \"./checker.js\";\nimport { executeUpdate } from \"./executor.js\";\nimport { scheduleGatewayRestart } from \"./restart.js\";\n\nconst PLUGIN_ID = \"phone-notifications\";\n\nfunction resolveTargetDir(api: OpenClawPluginApi): string {\n try {\n const cfg = (api.runtime as any).config?.loadConfig?.();\n const installPath = cfg?.plugins?.installs?.[PLUGIN_ID]?.installPath;\n if (installPath) return installPath;\n } catch { /* ignore */ }\n return join(resolvePluginStateDir(api), \"extensions\", PLUGIN_ID);\n}\n\nasync function updateConfigRecord(\n api: OpenClawPluginApi,\n version: string,\n targetDir: string,\n tgzUrl: string,\n): Promise<void> {\n const configApi = (api.runtime as any).config;\n if (!configApi) return;\n const cfg = configApi.loadConfig();\n if (!cfg.plugins) cfg.plugins = {};\n if (!cfg.plugins.installs) cfg.plugins.installs = {};\n cfg.plugins.installs[PLUGIN_ID] = {\n ...cfg.plugins.installs[PLUGIN_ID],\n source: \"archive\" as const,\n sourcePath: tgzUrl,\n installPath: targetDir,\n version,\n installedAt: new Date().toISOString(),\n };\n await configApi.writeConfigFile(cfg);\n}\n\nfunction finalizeUpdateResult(\n api: OpenClawPluginApi,\n logger: Logger,\n result: Awaited<ReturnType<typeof executeUpdate>>,\n): Awaited<ReturnType<typeof executeUpdate>> {\n if (!result.success) {\n return result;\n }\n\n const restart = scheduleGatewayRestart(logger, {\n loadConfig: () => {\n const configApi = (api.runtime as any).config;\n return configApi?.loadConfig?.();\n },\n });\n\n const version = result.version ?? \"目标版本\";\n return {\n ...result,\n restartScheduled: restart.scheduled,\n message: restart.scheduled\n ? `已更新到 ${version},已触发 gateway 重启`\n : `已更新到 ${version},请手动重启 gateway 生效`,\n };\n}\n\n/**\n * 注册插件自动更新能力:\n * - 定时版本检查(UpdateChecker)\n * - 对话通道:before_prompt_build hook + plugin-update tool\n * - 网关通道:broadcast 推送 + plugin.update gateway method\n *\n * 返回 start/stop 供 registerService 管理生命周期。\n */\nexport function registerAutoUpdate(\n api: OpenClawPluginApi,\n logger: Logger,\n config: AutoUpdateConfig,\n getBroadcast: () => BroadcastFn | null,\n rememberBroadcast?: (broadcast: BroadcastFn | undefined) => void,\n externalUpdateNotifier?: ExternalUpdateNotifier,\n): {\n start: () => void;\n stop: () => void;\n notifyBroadcastReady: () => void;\n} {\n if (config.enabled === false) {\n logger.info(\"自动更新已禁用 (autoUpdate.enabled = false)\");\n return { start() {}, stop() {}, notifyBroadcastReady() {} };\n }\n\n let pendingUpdate: UpdateInfo | null = null;\n let pendingGatewayUpdate: UpdateInfo | null = null;\n\n function tryBroadcastUpdate(update: UpdateInfo): boolean {\n const broadcast = getBroadcast();\n if (!broadcast) return false;\n\n broadcast(\"plugin.updateAvailable\", {\n pluginId: \"phone-notifications\",\n pluginName: \"消息通知\",\n current: update.current,\n latest: update.latest,\n });\n pendingGatewayUpdate = null;\n return true;\n }\n\n // ── 对话通道:hook 注入 system prompt ──\n\n api.on(\"before_prompt_build\", () => {\n if (!pendingUpdate) return;\n return {\n appendSystemContext:\n `[系统通知] phone-notifications 插件有新版本 ${pendingUpdate.latest} 可用` +\n `(当前版本 ${pendingUpdate.current})。\\n` +\n `请用自然语言在合适时机告知用户,若用户同意更新,` +\n `调用 plugin-update tool 并传入 version 参数。` +\n `若用户拒绝,不再重复提醒。`,\n };\n });\n\n // ── 对话通道:plugin-update tool ──\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n api.registerTool({\n name: \"plugin-update\",\n label: \"Plugin Update\",\n description:\n \"将 phone-notifications 插件更新到指定版本。\" +\n \"仅在用户明确同意更新后调用。更新完成后会自动尝试重启 gateway;如宿主不支持,则需手动重启。\",\n parameters: {\n type: \"object\",\n required: [\"version\"],\n additionalProperties: false,\n properties: {\n version: {\n type: \"string\",\n description: \"目标版本号,如 1.11.0\",\n },\n },\n },\n async execute(_toolCallId: string, params: unknown) {\n const { version } = params as { version: string };\n const targetDir = resolveTargetDir(api);\n const result = await executeUpdate(\n version,\n api.runtime.system.runCommandWithTimeout,\n logger,\n targetDir,\n (v, url) => updateConfigRecord(api, v, targetDir, url),\n );\n const finalResult = finalizeUpdateResult(api, logger, result);\n if (finalResult.success) {\n pendingUpdate = null;\n externalUpdateNotifier?.clearPendingUpdate();\n }\n return {\n content: [{ type: \"text\" as const, text: finalResult.message }],\n details: finalResult,\n };\n },\n } as any);\n\n // ── 网关通道:plugin.update gateway method ──\n\n api.registerGatewayMethod(\"plugin.update\", async ({ params, respond, context }) => {\n rememberBroadcast?.(context?.broadcast);\n\n const version = (params as { version?: string }).version;\n if (!version) {\n respond(false, undefined, {\n code: \"MISSING_VERSION\",\n message: \"version is required\",\n });\n return;\n }\n const targetDir = resolveTargetDir(api);\n const result = await executeUpdate(\n version,\n api.runtime.system.runCommandWithTimeout,\n logger,\n targetDir,\n (v, url) => updateConfigRecord(api, v, targetDir, url),\n );\n const finalResult = finalizeUpdateResult(api, logger, result);\n if (finalResult.success) {\n pendingUpdate = null;\n externalUpdateNotifier?.clearPendingUpdate();\n }\n if (finalResult.success) {\n respond(true, {\n message: finalResult.message,\n restartScheduled: finalResult.restartScheduled === true,\n });\n } else {\n respond(false, undefined, {\n code: \"UPDATE_FAILED\",\n message: finalResult.message,\n });\n }\n });\n\n // ── 版本检查器 ──\n\n const intervalMs = (config.checkIntervalHours ?? 4) * 3_600_000;\n const channel = config.channel ?? \"latest\";\n\n logger.info(\n `自动更新已启用: channel=${channel}, checkIntervalHours=${config.checkIntervalHours ?? 4}`,\n );\n\n const checker = new UpdateChecker(\n logger,\n (update) => {\n pendingUpdate = update;\n\n const broadcasted = tryBroadcastUpdate(update);\n if (!broadcasted) pendingGatewayUpdate = update;\n if (!broadcasted) {\n externalUpdateNotifier?.notifyUpdateAvailable(update);\n }\n\n logger.info(\n `已通知更新 ${update.current} → ${update.latest}` +\n (broadcasted\n ? \"(对话 + 网关)\"\n : \"(对话通道已生效,等待下次 gateway 请求时补发客户端事件)\"),\n );\n },\n intervalMs,\n channel,\n );\n\n return {\n start: () => checker.start(),\n stop: () => checker.stop(),\n notifyBroadcastReady() {\n const update = pendingGatewayUpdate;\n if (!update) return;\n if (!tryBroadcastUpdate(update)) return;\n logger.info(`已补发插件更新事件 ${update.current} → ${update.latest}`);\n },\n };\n}\n","import type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport { resolveStateDir as resolveHostStateDir } from \"../host.js\";\nimport { trimToUndefined } from \"./shared.js\";\n\nexport function tryResolveRuntimeStateDir(\n api: Pick<OpenClawPluginApi, \"runtime\">,\n): string | undefined {\n const runtimeState = (api as any)?.runtime?.state;\n const resolveStateDir = runtimeState?.resolveStateDir;\n if (typeof resolveStateDir !== \"function\") {\n return undefined;\n }\n\n try {\n return trimToUndefined(resolveStateDir.call(runtimeState));\n } catch {\n return undefined;\n }\n}\n\nexport function resolvePluginStateDir(\n api: Pick<OpenClawPluginApi, \"runtime\">,\n): string {\n return tryResolveRuntimeStateDir(api) ?? resolveHostStateDir();\n}\n","import type { IncomingMessage } from \"node:http\";\nimport type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\n\nexport type GatewayHandler = Parameters<OpenClawPluginApi[\"registerGatewayMethod\"]>[1];\n\nexport type GatewayMethodRegistrar = (\n method: string,\n handler: GatewayHandler,\n) => void;\n\nexport function readBody(req: IncomingMessage): Promise<string> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n req.on(\"data\", (chunk: Buffer) => chunks.push(chunk));\n req.on(\"end\", () => resolve(Buffer.concat(chunks).toString()));\n req.on(\"error\", reject);\n });\n}\n\nexport function trimToUndefined(value: unknown): string | undefined {\n if (typeof value !== \"string\") {\n return undefined;\n }\n\n const trimmed = value.trim();\n return trimmed || undefined;\n}\n","import { PLUGIN_VERSION } from \"../version.js\";\nimport type { Logger } from \"../logger.js\";\nimport type { UpdateInfo } from \"./types.js\";\n\nfunction parseSemver(v: string): { major: number; minor: number; patch: number; pre: string | null } {\n const [main, pre = null] = v.split(\"-\", 2) as [string, string | undefined];\n const [major = 0, minor = 0, patch = 0] = main.split(\".\").map(Number);\n return { major, minor, patch, pre: pre ?? null };\n}\n\nfunction comparePreRelease(a: string, b: string): number {\n const aParts = a.split(\".\");\n const bParts = b.split(\".\");\n for (let i = 0; i < Math.max(aParts.length, bParts.length); i++) {\n const ap = aParts[i] ?? \"\";\n const bp = bParts[i] ?? \"\";\n const an = Number(ap);\n const bn = Number(bp);\n let diff: number;\n if (!Number.isNaN(an) && !Number.isNaN(bn)) {\n diff = an - bn;\n } else if (ap < bp) {\n diff = -1;\n } else if (ap > bp) {\n diff = 1;\n } else {\n diff = 0;\n }\n if (diff !== 0) return diff;\n }\n return 0;\n}\n\n/** Returns true if `candidate` is strictly newer than `current` per semver rules. */\nfunction isNewerVersion(candidate: string, current: string): boolean {\n const a = parseSemver(candidate);\n const b = parseSemver(current);\n\n if (a.major !== b.major) return a.major > b.major;\n if (a.minor !== b.minor) return a.minor > b.minor;\n if (a.patch !== b.patch) return a.patch > b.patch;\n\n // Same major.minor.patch: stable > pre-release\n if (a.pre === null) return b.pre !== null;\n if (b.pre === null) return false;\n\n return comparePreRelease(a.pre, b.pre) > 0;\n}\n\nconst CDN_BASE_URL = \"https://artifact.yoooclaw.com/plugin\";\nconst NPM_BASE_URL =\n \"https://registry.npmjs.org/@yoooclaw/phone-notifications\";\nconst FETCH_TIMEOUT_MS = 5_000;\n\nexport class UpdateChecker {\n private timer: ReturnType<typeof setTimeout> | null = null;\n private notifiedVersion: string | null = null;\n\n constructor(\n private readonly logger: Logger,\n private readonly onUpdateFound: (info: UpdateInfo) => void,\n private readonly intervalMs: number,\n private readonly channel: \"latest\" | \"beta\",\n ) {}\n\n start(): void {\n // 首次延迟 1 分钟,避免影响插件启动\n this.timer = setTimeout(() => {\n void this.check();\n this.timer = setInterval(() => void this.check(), this.intervalMs);\n }, 60_000);\n }\n\n stop(): void {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n }\n\n async check(): Promise<void> {\n const latest = await this.fetchLatestVersion();\n if (!latest || latest === PLUGIN_VERSION) return;\n if (latest === this.notifiedVersion) return;\n\n // latest 通道只能提示正式版,避免生产环境收到 prerelease 推送。\n if (this.channel !== \"beta\" && latest.includes(\"-\")) return;\n\n // 只有 latest 严格大于当前版本才提示;同版本 stable 会被视为比 prerelease 新。\n if (!isNewerVersion(latest, PLUGIN_VERSION)) return;\n\n this.notifiedVersion = latest;\n this.logger.info(`发现新版本: ${PLUGIN_VERSION} → ${latest}`);\n this.onUpdateFound({ current: PLUGIN_VERSION, latest });\n }\n\n private async fetchLatestVersion(): Promise<string | null> {\n const tag = this.channel === \"beta\" ? \"beta\" : \"latest\";\n\n // 优先 CDN(轻量 plain text)\n try {\n const res = await fetch(`${CDN_BASE_URL}/${tag}`, {\n signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),\n });\n if (res.ok) {\n const text = (await res.text()).trim();\n if (text) return text;\n }\n } catch {\n // CDN 不可达,回退 npm\n }\n\n // 回退 npm registry\n try {\n const res = await fetch(`${NPM_BASE_URL}/${tag}`, {\n signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),\n });\n if (res.ok) {\n const data = (await res.json()) as { version?: string };\n return data.version ?? null;\n }\n } catch {\n this.logger.info(\"版本检查失败(CDN + npm 均不可达),跳过\");\n }\n\n return null;\n }\n}\n","import { mkdirSync, mkdtempSync, renameSync, rmSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { tmpdir } from \"node:os\";\nimport type { Logger } from \"../logger.js\";\n\nconst VERSION_PATTERN = /^\\d+\\.\\d+\\.\\d+(-[\\w.]+)?$/;\nconst BASE_URL = \"https://artifact.yoooclaw.com/plugin\";\n\nexport interface UpdateResult {\n success: boolean;\n message: string;\n version?: string;\n restartScheduled?: boolean;\n}\n\ntype RunCommandFn = (\n argv: string[],\n opts: { timeoutMs: number },\n) => Promise<{ code: number | null; stdout: string; stderr: string }>;\n\n/**\n * 执行插件更新:直接下载 tgz 并替换插件目录,避免依赖 `openclaw extension install`。\n * `openclaw extension install` 要求 plugins.allow 包含 \"extension\",许多用户环境缺此配置。\n */\nexport async function executeUpdate(\n version: string,\n runCommand: RunCommandFn,\n logger: Logger,\n targetDir: string,\n updateConfigRecord: (version: string, tgzUrl: string) => Promise<void>,\n): Promise<UpdateResult> {\n if (!VERSION_PATTERN.test(version)) {\n return { success: false, message: `非法版本号: ${version}` };\n }\n\n const tgzUrl = `${BASE_URL}/v${version}/yoooclaw-phone-notifications-${version}.tgz`;\n logger.info(`执行更新: ${tgzUrl} → ${targetDir}`);\n\n const workDir = mkdtempSync(join(tmpdir(), \".openclaw-plugin-update-\"));\n const tgzPath = join(workDir, \"plugin.tgz\");\n const stagingDir = join(workDir, \"staged\");\n let backupDir: string | null = null;\n\n try {\n logger.info(\"下载插件包...\");\n const response = await fetch(tgzUrl, { signal: AbortSignal.timeout(60_000) });\n if (!response.ok) {\n return { success: false, message: `下载失败 (HTTP ${response.status}): ${tgzUrl}` };\n }\n const buffer = Buffer.from(await response.arrayBuffer());\n writeFileSync(tgzPath, buffer);\n logger.info(`下载完成 (${buffer.length} bytes)`);\n\n mkdirSync(stagingDir, { recursive: true });\n const tarResult = await runCommand(\n [\"tar\", \"-xzf\", tgzPath, \"-C\", stagingDir, \"--strip-components=1\"],\n { timeoutMs: 30_000 },\n );\n if (tarResult.code !== 0) {\n const err = tarResult.stderr || tarResult.stdout || \"unknown error\";\n return { success: false, message: `解压失败: ${err}` };\n }\n\n mkdirSync(dirname(targetDir), { recursive: true });\n try {\n backupDir = `${targetDir}.bak.${Date.now()}`;\n renameSync(targetDir, backupDir);\n } catch {\n backupDir = null;\n }\n renameSync(stagingDir, targetDir);\n\n try {\n await updateConfigRecord(version, tgzUrl);\n } catch (err) {\n logger.warn(`配置记录更新失败(插件文件已就位): ${String(err)}`);\n }\n\n if (backupDir) {\n try { rmSync(backupDir, { force: true, recursive: true }); } catch { /* ignore */ }\n }\n\n const msg = `已更新到 ${version}`;\n logger.info(msg);\n return { success: true, message: msg, version };\n\n } catch (err) {\n if (backupDir) {\n try {\n rmSync(targetDir, { force: true, recursive: true });\n renameSync(backupDir, targetDir);\n logger.info(\"已回滚到之前版本\");\n } catch (rollbackErr) {\n logger.error(`回滚失败: ${String(rollbackErr)}`);\n }\n }\n const errMsg = `更新执行异常: ${String(err)}`;\n logger.error(errMsg);\n return { success: false, message: errMsg };\n\n } finally {\n try { rmSync(workDir, { force: true, recursive: true }); } catch { /* ignore */ }\n }\n}\n","import type { Logger } from \"../logger.js\";\n\ntype CommandsConfigLike = {\n commands?: {\n restart?: boolean;\n };\n};\n\nexport interface GatewayRestartScheduleDeps {\n loadConfig?: () => CommandsConfigLike | undefined;\n getListenerCount?: (signal: NodeJS.Signals) => number;\n emitSignal?: (signal: NodeJS.Signals) => boolean;\n schedule?: (task: () => void) => void;\n}\n\nexport interface GatewayRestartScheduleResult {\n scheduled: boolean;\n}\n\nexport function scheduleGatewayRestart(\n logger: Logger,\n deps: GatewayRestartScheduleDeps = {},\n): GatewayRestartScheduleResult {\n try {\n const cfg = deps.loadConfig?.();\n if (cfg?.commands?.restart === false) {\n logger.warn(\"更新后跳过 gateway 重启: commands.restart=false\");\n return { scheduled: false };\n }\n } catch (err) {\n logger.warn(`更新后检查 gateway 重启配置失败: ${String(err)}`);\n }\n\n const getListenerCount =\n deps.getListenerCount ?? ((signal: NodeJS.Signals) => process.listenerCount(signal));\n if (getListenerCount(\"SIGUSR1\") < 1) {\n logger.warn(\"更新后跳过 gateway 重启: 当前进程未注册 SIGUSR1 监听器\");\n return { scheduled: false };\n }\n\n const emitSignal =\n deps.emitSignal ?? ((signal: NodeJS.Signals) => process.emit(signal));\n const schedule =\n deps.schedule ?? ((task: () => void) => { setTimeout(task, 0); });\n\n schedule(() => {\n try {\n const accepted = emitSignal(\"SIGUSR1\");\n if (accepted) {\n logger.info(\"更新完成,已触发 gateway SIGUSR1 重启\");\n } else {\n logger.warn(\"更新完成,但 gateway SIGUSR1 信号未被处理\");\n }\n } catch (err) {\n logger.warn(`更新后触发 gateway 重启失败: ${String(err)}`);\n }\n });\n\n return { scheduled: true };\n}\n","import { basename, dirname } from \"node:path\";\nimport type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport { registerAllCli } from \"../cli/index.js\";\nimport type { Logger } from \"../logger.js\";\n\nfunction inferOpenClawRootDir(workspaceDir?: string): string | undefined {\n if (!workspaceDir) {\n return undefined;\n }\n\n if (basename(workspaceDir) !== \"workspace\") {\n return undefined;\n }\n\n return dirname(workspaceDir);\n}\n\nexport function registerPluginCli(\n api: OpenClawPluginApi,\n params: {\n logger: Logger;\n openclawDir?: string;\n },\n): void {\n const { logger, openclawDir } = params;\n\n const registerAlias = (command: \"ntf\" | \"phone-notifications\"): void => {\n api.registerCli(\n (ctx) => {\n const ctxStateDir = (ctx as { stateDir?: unknown }).stateDir;\n const effectiveStateDir =\n openclawDir ??\n (typeof ctxStateDir === \"string\" ? ctxStateDir : undefined) ??\n inferOpenClawRootDir(ctx.workspaceDir);\n registerAllCli(\n ctx.program,\n {\n stateDir: effectiveStateDir,\n workspaceDir: ctx.workspaceDir,\n },\n command,\n );\n },\n { commands: [command] },\n );\n };\n\n registerAlias(\"ntf\");\n registerAlias(\"phone-notifications\");\n logger.info(\"CLI 命令已注册: ntf, phone-notifications\");\n}\n","import { existsSync, rmSync } from \"node:fs\";\nimport type { CliCommand } from \"./helpers.js\";\nimport { output } from \"./helpers.js\";\nimport {\n credentialsPath,\n readCredentials,\n writeCredentials,\n} from \"../auth/credentials.js\";\n\nexport function registerAuthCli(program: CliCommand): void {\n const auth = program\n .command(\"auth\")\n .description(\"用户认证管理\");\n\n auth\n .command(\"set-api-key <apiKey>\")\n .description(\"设置用户 API Key(持久化到本地配置)\")\n .action((apiKey: string) => {\n writeCredentials({ ...readCredentials(), apiKey, token: undefined });\n output({\n ok: true,\n apiKey: apiKey.slice(0, 8) + \"…\",\n storedAt: credentialsPath(),\n });\n });\n\n // 兼容旧命令:set-token <token>,现在等价于 set-api-key\n auth\n .command(\"set-token <token>\")\n .description(\"(兼容)设置用户 API Key(旧命令名)\")\n .action((token: string) => {\n writeCredentials({ ...readCredentials(), apiKey: token, token: undefined });\n output({\n ok: true,\n apiKey: token.slice(0, 8) + \"…\",\n storedAt: credentialsPath(),\n });\n });\n\n auth\n .command(\"show\")\n .description(\"查看当前认证状态\")\n .action(() => {\n const creds = readCredentials();\n const apiKey = creds.apiKey ?? creds.token;\n if (apiKey) {\n output({\n ok: true,\n hasApiKey: true,\n apiKey: apiKey.slice(0, 8) + \"…\",\n storedAt: credentialsPath(),\n });\n } else {\n output({ ok: true, hasApiKey: false });\n }\n });\n\n auth\n .command(\"clear\")\n .description(\"清除已保存的认证信息\")\n .action(() => {\n const path = credentialsPath();\n if (existsSync(path)) {\n const creds = readCredentials();\n delete creds.apiKey;\n delete creds.token;\n if (Object.keys(creds).length === 0) {\n rmSync(path, { force: true });\n } else {\n writeCredentials(creds);\n }\n }\n output({ ok: true, cleared: true });\n });\n}\n","import type { StoredNotification } from \"../notification/storage.js\";\nimport {\n exitError,\n listDateKeysAsync,\n parseIsoTime,\n readDateFileAsync,\n sortNotificationsByTimestampDesc,\n matchesNotificationAppFilter,\n} from \"./helpers.js\";\n\nexport interface RawNotificationQueryOptions {\n from?: string;\n to?: string;\n app?: string;\n sender?: string;\n conversationType?: string;\n keyword?: string;\n limit?: string;\n}\n\nexport interface NotificationQueryOptions {\n from?: string;\n to?: string;\n app?: string;\n sender?: string;\n conversationType?: string;\n keyword?: string;\n limit: number;\n fromTs: number | null;\n toTs: number | null;\n fromDateKey: string | null;\n toDateKey: string | null;\n}\n\nexport function parsePositiveIntegerOption(\n rawValue: string | undefined,\n defaultValue: number,\n optionName: string,\n errorCode: string,\n): number {\n const value = rawValue && rawValue.length > 0 ? rawValue : String(defaultValue);\n if (!/^\\d+$/.test(value)) {\n exitError(errorCode, `${optionName} 必须是大于 0 的整数`);\n }\n\n const parsed = Number.parseInt(value, 10);\n if (parsed <= 0) {\n exitError(errorCode, `${optionName} 必须是大于 0 的整数`);\n }\n return parsed;\n}\n\nexport function parseNotificationQueryOptions(\n opts: RawNotificationQueryOptions,\n defaultLimit = 100,\n): NotificationQueryOptions {\n const limit = parsePositiveIntegerOption(\n opts.limit,\n defaultLimit,\n \"--limit\",\n \"INVALID_LIMIT\",\n );\n\n if (\n opts.conversationType\n && opts.conversationType !== \"group\"\n && opts.conversationType !== \"private\"\n ) {\n exitError(\n \"INVALID_CONVERSATION_TYPE\",\n \"--conversation-type 只能是 group 或 private\",\n );\n }\n\n const hasFrom = typeof opts.from === \"string\" && opts.from.length > 0;\n const hasTo = typeof opts.to === \"string\" && opts.to.length > 0;\n const fromTs = hasFrom ? parseIsoTime(opts.from!, \"--from\") : null;\n const toTs = hasTo ? parseIsoTime(opts.to!, \"--to\") : null;\n\n if (fromTs !== null && toTs !== null && fromTs > toTs) {\n exitError(\"INVALID_TIME_RANGE\", \"--from 不能晚于 --to\");\n }\n\n return {\n from: opts.from,\n to: opts.to,\n app: opts.app,\n sender: opts.sender,\n conversationType: opts.conversationType,\n keyword: opts.keyword,\n limit,\n fromTs,\n toTs,\n fromDateKey: hasFrom ? opts.from!.slice(0, 10) : null,\n toDateKey: hasTo ? opts.to!.slice(0, 10) : null,\n };\n}\n\nexport function matchesNotificationQuery(\n item: StoredNotification,\n opts: NotificationQueryOptions,\n): boolean {\n if (opts.app && !matchesNotificationAppFilter(item, opts.app)) return false;\n if (\n opts.conversationType\n && item.conversationType !== opts.conversationType\n ) {\n return false;\n }\n\n const senderHaystack = [item.senderName, item.title]\n .filter((value): value is string => typeof value === \"string\" && value.length > 0)\n .join(\"\\n\");\n if (opts.sender && !senderHaystack.includes(opts.sender)) return false;\n\n const keywordHaystack = [\n item.title,\n item.content,\n item.senderName,\n item.conversationName,\n ]\n .filter((value): value is string => typeof value === \"string\" && value.length > 0)\n .join(\"\\n\");\n if (opts.keyword && !keywordHaystack.includes(opts.keyword)) return false;\n\n const itemTs = Date.parse(item.timestamp);\n if (Number.isNaN(itemTs)) return false;\n if (opts.fromTs !== null && itemTs < opts.fromTs) return false;\n if (opts.toTs !== null && itemTs > opts.toTs) return false;\n\n return true;\n}\n\nexport async function collectMatchingNotifications(\n dir: string,\n opts: NotificationQueryOptions,\n): Promise<StoredNotification[]> {\n const keys = await listDateKeysAsync(dir);\n const results: StoredNotification[] = [];\n const canStopAfterLimit = opts.fromTs === null && opts.toTs === null;\n\n for (const dateKey of keys) {\n if (opts.fromDateKey && dateKey < opts.fromDateKey) continue;\n if (opts.toDateKey && dateKey > opts.toDateKey) continue;\n\n const items = sortNotificationsByTimestampDesc([\n ...(await readDateFileAsync(dir, dateKey)),\n ]);\n for (const item of items) {\n if (!matchesNotificationQuery(item, opts)) continue;\n results.push(item);\n if (canStopAfterLimit && results.length >= opts.limit) {\n return results;\n }\n }\n }\n\n return sortNotificationsByTimestampDesc(results).slice(0, opts.limit);\n}\n","import {\n type CliCommand,\n type CliContext,\n resolveNotificationsDir,\n output,\n exitError,\n progress,\n} from \"./helpers.js\";\nimport {\n collectMatchingNotifications,\n parseNotificationQueryOptions,\n} from \"./ntf-query.js\";\n\nexport function registerNtfSearch(ntf: CliCommand, ctx: CliContext): void {\n ntf\n .command(\"search\")\n .description(\"查询通知(按时间/应用/发送人/关键词筛选)\")\n .option(\"--from <time>\", \"开始时间 ISO 8601,例如 2026-03-01T09:00:00+08:00\")\n .option(\"--to <time>\", \"结束时间 ISO 8601,例如 2026-03-01T18:00:00+08:00\")\n .option(\"--app <name>\", \"按应用名过滤\")\n .option(\"--sender <name>\", \"按发送人过滤\")\n .option(\n \"--conversation-type <type>\",\n \"按会话类型过滤(group/private)\",\n )\n .option(\"--keyword <text>\", \"在标题和内容中搜索关键词\")\n .option(\"--limit <n>\", \"最大返回条数\", \"100\")\n .action(\n async (opts: {\n from?: string;\n to?: string;\n app?: string;\n sender?: string;\n conversationType?: string;\n keyword?: string;\n limit: string;\n }) => {\n const dir = resolveNotificationsDir(ctx);\n if (!dir) exitError(\"STORAGE_UNAVAILABLE\", \"通知存储目录不可用\");\n\n progress(\"正在搜索通知...\");\n\n const query = parseNotificationQueryOptions(opts);\n const notifications = await collectMatchingNotifications(dir, query);\n\n output({\n ok: true,\n total: notifications.length,\n notifications,\n });\n },\n );\n}\n","import type { StoredNotification } from \"../notification/storage.js\";\nimport {\n type CliCommand,\n type CliContext,\n exitError,\n output,\n progress,\n resolveNotificationsDir,\n} from \"./helpers.js\";\nimport {\n collectMatchingNotifications,\n parseNotificationQueryOptions,\n parsePositiveIntegerOption,\n} from \"./ntf-query.js\";\n\ntype CountRow<T extends Record<string, unknown>> = T & { count: number };\n\ninterface CompactNotification {\n appName: string;\n appDisplayName?: string;\n title: string;\n content: string;\n timestamp: string;\n senderName?: string;\n conversationType?: string;\n conversationName?: string;\n}\n\nfunction compactNotification(item: StoredNotification): CompactNotification {\n const result: CompactNotification = {\n appName: item.appName,\n title: item.title,\n content: item.content,\n timestamp: item.timestamp,\n };\n if (item.appDisplayName) result.appDisplayName = item.appDisplayName;\n if (item.senderName) result.senderName = item.senderName;\n if (item.conversationType) result.conversationType = item.conversationType;\n if (item.conversationName) result.conversationName = item.conversationName;\n return result;\n}\n\nfunction truncate(value: string, maxLength = 120): string {\n if (value.length <= maxLength) return value;\n return `${value.slice(0, maxLength - 1)}…`;\n}\n\nfunction increment<T extends Record<string, unknown>>(\n map: Map<string, CountRow<T>>,\n key: string,\n seed: T,\n): void {\n const existing = map.get(key);\n if (existing) {\n existing.count += 1;\n return;\n }\n map.set(key, { ...seed, count: 1 });\n}\n\nfunction topRows<T extends Record<string, unknown>>(\n map: Map<string, CountRow<T>>,\n limit: number,\n): CountRow<T>[] {\n return [...map.values()].sort((a, b) => b.count - a.count).slice(0, limit);\n}\n\nfunction hourBucket(timestamp: string): string | null {\n const match = /^(\\d{4}-\\d{2}-\\d{2})T(\\d{2}):/.exec(timestamp);\n if (!match) return null;\n return `${match[1]} ${match[2]}:00`;\n}\n\nfunction buildSamplesBySender(\n notifications: StoredNotification[],\n senderRows: CountRow<{ sender: string }>[],\n): Array<{ sender: string; count: number; samples: string[] }> {\n return senderRows.map((row) => {\n const samples: string[] = [];\n for (const item of notifications) {\n const sender = item.senderName?.trim() || item.title?.trim() || \"(unknown)\";\n if (sender !== row.sender) continue;\n const content = truncate(item.content.trim());\n if (content && !samples.includes(content)) samples.push(content);\n if (samples.length >= 5) break;\n }\n return { sender: row.sender, count: row.count, samples };\n });\n}\n\nexport function registerNtfSummary(ntf: CliCommand, ctx: CliContext): void {\n ntf\n .command(\"summary\")\n .description(\"生成通知摘要输入(聚合统计 + 样例,供 Agent 快速总结)\")\n .option(\"--from <time>\", \"开始时间 ISO 8601,例如 2026-03-01T09:00:00+08:00\")\n .option(\"--to <time>\", \"结束时间 ISO 8601,例如 2026-03-01T18:00:00+08:00\")\n .option(\"--app <name>\", \"按应用名过滤\")\n .option(\"--sender <name>\", \"按发送人过滤\")\n .option(\n \"--conversation-type <type>\",\n \"按会话类型过滤(group/private)\",\n )\n .option(\"--keyword <text>\", \"在标题和内容中搜索关键词\")\n .option(\"--limit <n>\", \"纳入摘要的最大通知条数\", \"100\")\n .option(\"--sample <n>\", \"返回最近样例条数\", \"30\")\n .option(\"--top <n>\", \"返回聚合榜单条数\", \"10\")\n .action(\n async (opts: {\n from?: string;\n to?: string;\n app?: string;\n sender?: string;\n conversationType?: string;\n keyword?: string;\n limit: string;\n sample: string;\n top: string;\n }) => {\n const dir = resolveNotificationsDir(ctx);\n if (!dir) exitError(\"STORAGE_UNAVAILABLE\", \"通知存储目录不可用\");\n\n progress(\"正在生成通知摘要输入...\");\n\n const query = parseNotificationQueryOptions(opts);\n const sampleLimit = parsePositiveIntegerOption(\n opts.sample,\n 30,\n \"--sample\",\n \"INVALID_SAMPLE\",\n );\n const topLimit = parsePositiveIntegerOption(\n opts.top,\n 10,\n \"--top\",\n \"INVALID_TOP\",\n );\n\n const notifications = await collectMatchingNotifications(dir, query);\n const byApp = new Map<\n string,\n CountRow<{ appName: string; appDisplayName?: string }>\n >();\n const bySender = new Map<string, CountRow<{ sender: string }>>();\n const byConversation = new Map<\n string,\n CountRow<{ conversationName: string; conversationType?: string }>\n >();\n const byHour = new Map<string, CountRow<{ hour: string }>>();\n\n for (const item of notifications) {\n const appKey = `${item.appName}\\0${item.appDisplayName ?? \"\"}`;\n increment(byApp, appKey, {\n appName: item.appName,\n ...(item.appDisplayName ? { appDisplayName: item.appDisplayName } : {}),\n });\n\n const sender = item.senderName?.trim() || item.title?.trim() || \"(unknown)\";\n increment(bySender, sender, { sender });\n\n const conversationName =\n item.conversationName?.trim() || item.title?.trim() || \"(unknown)\";\n const conversationKey = `${conversationName}\\0${item.conversationType ?? \"\"}`;\n increment(byConversation, conversationKey, {\n conversationName,\n ...(item.conversationType\n ? { conversationType: item.conversationType }\n : {}),\n });\n\n const hour = hourBucket(item.timestamp);\n if (hour) increment(byHour, hour, { hour });\n }\n\n const senderRows = topRows(bySender, topLimit);\n output({\n ok: true,\n limit: query.limit,\n total: notifications.length,\n range: {\n newest: notifications[0]?.timestamp ?? null,\n oldest: notifications[notifications.length - 1]?.timestamp ?? null,\n },\n byApp: topRows(byApp, topLimit),\n bySender: senderRows,\n byConversation: topRows(byConversation, topLimit),\n byHour: topRows(byHour, topLimit),\n latest: notifications.slice(0, sampleLimit).map(compactNotification),\n samplesBySender: buildSamplesBySender(notifications, senderRows),\n });\n },\n );\n}\n","import {\n type CliCommand,\n type CliContext,\n resolveNotificationsDir,\n listDateKeys,\n readDateFile,\n filterDateRange,\n matchesNotificationAppFilter,\n today,\n daysAgo,\n output,\n exitError,\n} from \"./helpers.js\";\n\ntype Dimension = \"date\" | \"app\" | \"sender\" | \"hour\" | \"all\";\n\nexport function registerNtfStats(ntf: CliCommand, ctx: CliContext): void {\n ntf\n .command(\"stats\")\n .description(\"通知统计分析(按日期/应用/发送人/时段聚合)\")\n .option(\"--from <date>\", \"开始日期 YYYY-MM-DD\", daysAgo(7))\n .option(\"--to <date>\", \"结束日期 YYYY-MM-DD\", today())\n .option(\"--app <name>\", \"只统计指定应用\")\n .option(\"--dim <dimension>\", \"统计维度:date/app/sender/hour/all\", \"all\")\n .action(\n (opts: { from: string; to: string; app?: string; dim: string }) => {\n const dir = resolveNotificationsDir(ctx);\n if (!dir) exitError(\"STORAGE_UNAVAILABLE\", \"通知存储目录不可用\");\n\n const dim = opts.dim as Dimension;\n const keys = filterDateRange(listDateKeys(dir), opts.from, opts.to);\n\n const byDate: Record<string, number> = {};\n const byApp: Record<string, number> = {};\n const bySender: Record<string, number> = {};\n const byHour: Record<string, number> = {};\n let total = 0;\n\n for (const dateKey of keys) {\n const items = readDateFile(dir, dateKey);\n let dateCount = 0;\n for (const item of items) {\n if (opts.app && !matchesNotificationAppFilter(item, opts.app)) continue;\n total++;\n dateCount++;\n\n byApp[item.appName] = (byApp[item.appName] || 0) + 1;\n\n const sender = item.senderName?.trim() || item.title?.trim();\n if (sender) {\n bySender[sender] = (bySender[sender] || 0) + 1;\n }\n\n const hourMatch = /T(\\d{2}):/.exec(item.timestamp);\n if (hourMatch) {\n const h = hourMatch[1];\n byHour[h] = (byHour[h] || 0) + 1;\n }\n }\n byDate[dateKey] = dateCount;\n }\n\n const result: Record<string, unknown> = {\n ok: true,\n range: { from: opts.from, to: opts.to },\n total,\n };\n\n if (dim === \"date\" || dim === \"all\") {\n result.byDate = byDate;\n }\n if (dim === \"app\" || dim === \"all\") {\n result.byApp = byApp;\n }\n if (dim === \"sender\" || dim === \"all\") {\n // Sort by count descending, return top 20\n const sorted = Object.entries(bySender)\n .sort((a, b) => b[1] - a[1])\n .slice(0, 20)\n .map(([sender, count]) => ({ sender, count }));\n result.bySender = sorted;\n }\n if (dim === \"hour\" || dim === \"all\") {\n result.byHour = byHour;\n }\n\n output(result);\n },\n );\n}\n","import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport {\n type CliCommand,\n type CliContext,\n resolveNotificationsDir,\n listDateKeys,\n readDateFile,\n output,\n exitError,\n} from \"./helpers.js\";\n\ninterface CheckpointData {\n [dateKey: string]: { lastIndex: number };\n}\n\nconst SYNC_FETCH_LIMIT = 300;\n\nfunction checkpointPath(dir: string): string {\n return join(dir, \".checkpoint.json\");\n}\n\nfunction readCheckpoint(dir: string): CheckpointData {\n const p = checkpointPath(dir);\n if (!existsSync(p)) return {};\n try {\n return JSON.parse(readFileSync(p, \"utf-8\"));\n } catch {\n return {};\n }\n}\n\nfunction writeCheckpoint(dir: string, data: CheckpointData): void {\n writeFileSync(checkpointPath(dir), JSON.stringify(data, null, 2), \"utf-8\");\n}\n\nexport function registerNtfSync(ntf: CliCommand, ctx: CliContext): void {\n const sync = ntf.command(\"sync\").description(\"同步通知到记忆系统\");\n\n sync\n .command(\"scan\")\n .description(\"扫描未处理的通知,返回待同步摘要\")\n .action(() => {\n const dir = resolveNotificationsDir(ctx);\n if (!dir) exitError(\"STORAGE_UNAVAILABLE\", \"通知存储目录不可用\");\n\n const checkpoint = readCheckpoint(dir);\n const keys = listDateKeys(dir); // descending\n const pending: { date: string; count: number; startIndex: number }[] = [];\n let totalPending = 0;\n\n for (const dateKey of keys) {\n const items = readDateFile(dir, dateKey);\n const lastIndex = checkpoint[dateKey]?.lastIndex ?? -1;\n const unprocessed = items.length - (lastIndex + 1);\n if (unprocessed > 0) {\n pending.push({\n date: dateKey,\n count: unprocessed,\n startIndex: lastIndex + 1,\n });\n totalPending += unprocessed;\n }\n }\n\n output({ ok: true, pending, totalPending });\n });\n\n sync\n .command(\"fetch\")\n .description(\"获取指定日期的未处理通知详情\")\n .requiredOption(\"--date <date>\", \"目标日期 YYYY-MM-DD\")\n .option(\"--max-end-index <index>\", \"本次同步快照允许读取的最大 endIndex\")\n .action((opts: { date: string; maxEndIndex?: string }) => {\n const dir = resolveNotificationsDir(ctx);\n if (!dir) exitError(\"STORAGE_UNAVAILABLE\", \"通知存储目录不可用\");\n\n const items = readDateFile(dir, opts.date);\n if (items.length === 0) {\n exitError(\"NO_DATA\", `日期 ${opts.date} 无通知数据`);\n }\n\n const checkpoint = readCheckpoint(dir);\n const lastIndex = checkpoint[opts.date]?.lastIndex ?? -1;\n const startIndex = lastIndex + 1;\n let maxEndIndex = items.length - 1;\n if (typeof opts.maxEndIndex === \"string\" && opts.maxEndIndex.length > 0) {\n maxEndIndex = Number.parseInt(opts.maxEndIndex, 10);\n if (!Number.isInteger(maxEndIndex) || String(maxEndIndex) !== opts.maxEndIndex) {\n exitError(\"INVALID_MAX_END_INDEX\", \"--max-end-index 必须是非负整数\");\n }\n if (maxEndIndex < 0) {\n exitError(\"INVALID_MAX_END_INDEX\", \"--max-end-index 必须是非负整数\");\n }\n maxEndIndex = Math.min(maxEndIndex, items.length - 1);\n }\n const snapshotEndExclusive = Math.max(startIndex, maxEndIndex + 1);\n const unprocessed = items.slice(startIndex, snapshotEndExclusive);\n const notifications = unprocessed.slice(0, SYNC_FETCH_LIMIT);\n const endIndex =\n notifications.length > 0 ? startIndex + notifications.length - 1 : lastIndex;\n const hasMore = unprocessed.length > notifications.length;\n\n if (unprocessed.length === 0) {\n output({\n ok: true,\n date: opts.date,\n startIndex,\n endIndex,\n nextStartIndex: null,\n limit: SYNC_FETCH_LIMIT,\n maxEndIndex,\n returned: 0,\n totalUnprocessed: 0,\n hasMore: false,\n notifications: [],\n });\n return;\n }\n\n output({\n ok: true,\n date: opts.date,\n startIndex,\n endIndex,\n nextStartIndex: hasMore ? endIndex + 1 : null,\n limit: SYNC_FETCH_LIMIT,\n maxEndIndex,\n returned: notifications.length,\n totalUnprocessed: unprocessed.length,\n hasMore,\n notifications,\n });\n });\n\n sync\n .command(\"commit\")\n .description(\"标记指定日期当前批次处理完成,更新 checkpoint\")\n .requiredOption(\"--date <date>\", \"目标日期 YYYY-MM-DD\")\n .option(\"--end-index <index>\", \"本批次 fetch 返回的 endIndex\")\n .action((opts: { date: string; endIndex?: string }) => {\n const dir = resolveNotificationsDir(ctx);\n if (!dir) exitError(\"STORAGE_UNAVAILABLE\", \"通知存储目录不可用\");\n\n const items = readDateFile(dir, opts.date);\n if (items.length === 0) {\n exitError(\"NO_DATA\", `日期 ${opts.date} 无通知数据`);\n }\n\n const checkpoint = readCheckpoint(dir);\n const lastIndex = checkpoint[opts.date]?.lastIndex ?? -1;\n let committedIndex: number;\n if (typeof opts.endIndex === \"string\" && opts.endIndex.length > 0) {\n committedIndex = Number.parseInt(opts.endIndex, 10);\n if (!Number.isInteger(committedIndex) || String(committedIndex) !== opts.endIndex) {\n exitError(\"INVALID_END_INDEX\", \"--end-index 必须是非负整数\");\n }\n if (committedIndex < 0 || committedIndex >= items.length) {\n exitError(\n \"INVALID_END_INDEX\",\n \"--end-index 必须落在当前日期通知文件范围内\",\n );\n }\n if (committedIndex < lastIndex) {\n exitError(\n \"STALE_END_INDEX\",\n \"--end-index 早于当前 checkpoint,不能回退消费进度\",\n );\n }\n if (committedIndex > lastIndex + SYNC_FETCH_LIMIT) {\n exitError(\n \"INVALID_END_INDEX\",\n \"--end-index 超出单批 fetch 上限,不能跳过未处理通知\",\n );\n }\n } else {\n committedIndex = Math.min(items.length - 1, lastIndex + SYNC_FETCH_LIMIT);\n }\n const hasMore = committedIndex < items.length - 1;\n checkpoint[opts.date] = { lastIndex: committedIndex };\n writeCheckpoint(dir, checkpoint);\n\n output({\n ok: true,\n date: opts.date,\n committedIndex,\n commitMode:\n typeof opts.endIndex === \"string\" && opts.endIndex.length > 0\n ? \"exact-end-index\"\n : \"legacy-batch-limit\",\n limit: SYNC_FETCH_LIMIT,\n hasMore,\n nextStartIndex: hasMore ? committedIndex + 1 : null,\n });\n });\n}\n","import {\n existsSync,\n mkdirSync,\n readFileSync,\n writeFileSync,\n rmSync,\n readdirSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\nimport { type CliCommand, type CliContext, output, exitError } from \"./helpers.js\";\nimport { generateFetchPy } from \"../monitor/fetch-gen.js\";\n\ninterface MonitorMeta {\n name: string;\n type?: \"monitor\" | \"light-rule\";\n description: string;\n matchRules: Record<string, unknown>;\n cronSchedule: string;\n enabled: boolean;\n createdAt: string;\n updatedAt?: string;\n}\n\nfunction tasksDir(ctx: CliContext): string {\n const base = ctx.workspaceDir || ctx.stateDir;\n if (!base) throw new Error(\"workspaceDir and stateDir both unavailable\");\n return join(base, \"tasks\");\n}\n\nfunction readMeta(taskDir: string): MonitorMeta | null {\n const metaPath = join(taskDir, \"meta.json\");\n if (!existsSync(metaPath)) return null;\n try {\n return JSON.parse(readFileSync(metaPath, \"utf-8\"));\n } catch {\n return null;\n }\n}\n\nfunction writeMeta(taskDir: string, meta: MonitorMeta): void {\n writeFileSync(join(taskDir, \"meta.json\"), JSON.stringify(meta, null, 2), \"utf-8\");\n}\n\nfunction generateReadme(name: string, description: string): string {\n return `# Monitor Task: ${name}\n\n## 描述\n${description}\n\n## 处理指南\n当 fetch.py 输出匹配的通知时,请:\n1. 阅读匹配到的通知内容\n2. 根据任务描述判断是否需要通知用户\n3. 如需通知用户,使用 message 工具发送摘要\n`;\n}\n\nexport function registerNtfMonitor(ntf: CliCommand, ctx: CliContext): void {\n const monitor = ntf.command(\"monitor\").description(\"通知监控任务管理\");\n\n monitor\n .command(\"list\")\n .description(\"列出所有监控任务\")\n .action(() => {\n const dir = tasksDir(ctx);\n if (!existsSync(dir)) {\n output({ ok: true, tasks: [] });\n return;\n }\n\n const tasks: MonitorMeta[] = [];\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n const meta = readMeta(join(dir, entry.name));\n if (meta) tasks.push(meta);\n }\n\n output({ ok: true, tasks });\n });\n\n monitor\n .command(\"show <name>\")\n .description(\"查看监控任务详情\")\n .action((name: string) => {\n const taskDir = join(tasksDir(ctx), name);\n const meta = readMeta(taskDir);\n if (!meta) exitError(\"NOT_FOUND\", `监控任务 '${name}' 不存在`);\n\n const checkpointPath = join(taskDir, \"checkpoint.json\");\n let checkpoint = {};\n if (existsSync(checkpointPath)) {\n try {\n checkpoint = JSON.parse(readFileSync(checkpointPath, \"utf-8\"));\n } catch {\n // ignore\n }\n }\n\n output({\n ok: true,\n ...meta,\n matchScript: `tasks/${name}/fetch.py`,\n readme: `tasks/${name}/README.md`,\n checkpoint,\n });\n });\n\n monitor\n .command(\"create <name>\")\n .description(\"创建监控任务\")\n .requiredOption(\"--description <text>\", \"任务描述\")\n .requiredOption(\"--match-rules <json>\", \"匹配规则 JSON\")\n .requiredOption(\"--schedule <cron>\", \"cron 表达式\")\n .action(\n (\n name: string,\n opts: {\n description: string;\n matchRules: string;\n schedule: string;\n },\n ) => {\n const dir = tasksDir(ctx);\n const taskDir = join(dir, name);\n\n if (existsSync(taskDir)) {\n exitError(\"ALREADY_EXISTS\", `监控任务 '${name}' 已存在`);\n }\n\n let matchRules: Record<string, unknown>;\n try {\n matchRules = JSON.parse(opts.matchRules);\n } catch {\n exitError(\n \"VALIDATION_FAILED\",\n \"match-rules 必须是合法的 JSON\",\n );\n }\n\n mkdirSync(taskDir, { recursive: true });\n\n const meta: MonitorMeta = {\n name,\n description: opts.description,\n matchRules,\n cronSchedule: opts.schedule,\n enabled: true,\n createdAt: new Date().toISOString(),\n };\n writeMeta(taskDir, meta);\n writeFileSync(\n join(taskDir, \"fetch.py\"),\n generateFetchPy(name, matchRules),\n \"utf-8\",\n );\n writeFileSync(\n join(taskDir, \"README.md\"),\n generateReadme(name, opts.description),\n \"utf-8\",\n );\n\n output({\n ok: true,\n name,\n created: {\n script: `tasks/${name}/fetch.py`,\n readme: `tasks/${name}/README.md`,\n cronJob: `notif-${name}`,\n },\n cronHint: {\n action: \"add\",\n job: {\n name: `notif-${name}`,\n schedule: opts.schedule,\n sessionTarget: \"isolated\",\n message: `手机通知已由独立服务实时捕获到 notifications/ 目录的 JSON 文件中。\\n执行:python3 tasks/${name}/fetch.py --notifications-dir notifications\\n- NO_CHANGE 或 NO_MATCH → 不回复,直接结束。\\n- 有输出 → 读 tasks/${name}/README.md 了解如何处理数据并通知用户。`,\n },\n },\n });\n },\n );\n\n monitor\n .command(\"delete <name>\")\n .description(\"删除监控任务\")\n .option(\"--yes\", \"跳过确认\")\n .action((name: string, opts: { yes?: boolean }) => {\n const taskDir = join(tasksDir(ctx), name);\n if (!existsSync(taskDir)) {\n exitError(\"NOT_FOUND\", `监控任务 '${name}' 不存在`);\n }\n\n if (!opts.yes) {\n output({\n ok: false,\n error: {\n code: \"CONFIRMATION_REQUIRED\",\n message: `确认删除监控任务 '${name}'?添加 --yes 跳过确认`,\n },\n });\n process.exit(1);\n }\n\n rmSync(taskDir, { recursive: true, force: true });\n output({\n ok: true,\n name,\n deleted: true,\n cronHint: {\n action: \"remove\",\n name: `notif-${name}`,\n },\n });\n });\n\n monitor\n .command(\"enable <name>\")\n .description(\"启用监控任务\")\n .action((name: string) => {\n const taskDir = join(tasksDir(ctx), name);\n const meta = readMeta(taskDir);\n if (!meta) exitError(\"NOT_FOUND\", `监控任务 '${name}' 不存在`);\n\n meta.enabled = true;\n writeMeta(taskDir, meta);\n output({ ok: true, name, enabled: true });\n });\n\n monitor\n .command(\"disable <name>\")\n .description(\"暂停监控任务\")\n .action((name: string) => {\n const taskDir = join(tasksDir(ctx), name);\n const meta = readMeta(taskDir);\n if (!meta) exitError(\"NOT_FOUND\", `监控任务 '${name}' 不存在`);\n\n meta.enabled = false;\n writeMeta(taskDir, meta);\n output({ ok: true, name, enabled: false });\n });\n}\n","/**\n * 共享的 fetch.py 生成逻辑,供 ntf-monitor CLI 和 light-rules gateway 复用。\n */\nexport function generateFetchPy(\n name: string,\n matchRules: Record<string, unknown>,\n): string {\n const appName = typeof matchRules.appName === \"string\" ? matchRules.appName : \"\";\n const senderKeywords = stringArray(matchRules.senderKeywords);\n const contentKeywords = stringArray(matchRules.contentKeywords);\n\n return `#!/usr/bin/env python3\n\"\"\"Auto-generated fetch script for monitor task: ${name}\"\"\"\nimport json, sys, os\nfrom pathlib import Path\n\ndef matches(notification: dict) -> bool:\n app = str(notification.get(\"appName\", \"\") or \"\")\n title = str(notification.get(\"title\", \"\") or \"\")\n content = str(notification.get(\"content\", \"\") or \"\")\n body = str(notification.get(\"body\", \"\") or \"\")\n\n app_name = ${pyLiteral(appName)}\n if app_name and app != app_name:\n return False\n\n sender_keywords = ${pyLiteral(senderKeywords)}\n sender_haystack = f\"{title}\\\\n{content}\\\\n{body}\"\n if sender_keywords and not any(keyword in sender_haystack for keyword in sender_keywords):\n return False\n\n content_keywords = ${pyLiteral(contentKeywords)}\n content_haystack = f\"{content}\\\\n{body}\"\n if content_keywords and not any(keyword in content_haystack for keyword in content_keywords):\n return False\n\n return True\n\ndef main():\n import argparse\n parser = argparse.ArgumentParser()\n parser.add_argument(\"--notifications-dir\", required=True)\n args = parser.parse_args()\n\n checkpoint_path = Path(__file__).parent / \"checkpoint.json\"\n checkpoint = {}\n if checkpoint_path.exists():\n checkpoint = json.loads(checkpoint_path.read_text())\n\n ntf_dir = Path(args.notifications_dir)\n matched = []\n new_checkpoint = dict(checkpoint)\n\n for f in sorted(ntf_dir.glob(\"*.json\")):\n date_key = f.stem\n items = json.loads(f.read_text())\n last_idx = checkpoint.get(date_key, {}).get(\"lastIndex\", -1)\n for i, item in enumerate(items):\n if i <= last_idx:\n continue\n if matches(item):\n matched.append(item)\n new_checkpoint[date_key] = {\"lastIndex\": len(items) - 1}\n\n checkpoint_path.write_text(json.dumps(new_checkpoint, indent=2))\n\n if not matched:\n print(\"NO_MATCH\")\n return\n\n for m in matched:\n print(json.dumps(m, ensure_ascii=False))\n\nif __name__ == \"__main__\":\n main()\n`;\n}\n\nfunction stringArray(value: unknown): string[] {\n if (!Array.isArray(value)) return [];\n return value.filter((item): item is string => typeof item === \"string\" && item.length > 0);\n}\n\nfunction pyLiteral(value: string | string[]): string {\n return JSON.stringify(value);\n}\n","import { type CliCommand, output, exitError } from \"./helpers.js\";\nimport { requireApiKey } from \"../auth/credentials.js\";\nimport { sendLightEffect } from \"../light/sender.js\";\nimport { parseAndValidateSegments } from \"../light/validators.js\";\nimport { assertAncsRepeatTimes, normalizeRepeatTimes } from \"../light/repeat.js\";\n\nexport function registerLightSend(light: CliCommand): void {\n light\n .command(\"send\")\n .description(\"发送灯效指令到硬件设备\")\n .requiredOption(\"--segments <json>\", \"灯效参数 JSON\")\n .option(\"--repeat\", \"无限循环播放(默认仅播放一轮)\")\n .option(\"--repeat-times <n>\", \"整条组合重复次数:0=无限,1=一轮;当前 ANCS 路径不支持 >=2\")\n .action(async (opts: { segments: string; repeat?: boolean; repeatTimes?: string }) => {\n let apiKey: string;\n try {\n apiKey = requireApiKey();\n } catch (e: any) {\n exitError(\"AUTH_REQUIRED\", e.message);\n }\n\n const segments = parseAndValidateSegments(opts.segments);\n let repeatTimes: number;\n try {\n repeatTimes = normalizeRepeatTimes({\n repeat: opts.repeat,\n repeat_times: opts.repeatTimes === undefined ? undefined : Number(opts.repeatTimes),\n });\n assertAncsRepeatTimes(repeatTimes);\n } catch (e: any) {\n exitError(\"VALIDATION_FAILED\", e.message);\n }\n\n const result = await sendLightEffect(\n apiKey,\n segments,\n undefined,\n { repeat_times: repeatTimes },\n );\n\n if (!result.ok) {\n exitError(\"HTTP_ERROR\", `请求失败: ${result.status} ${result.error}`);\n }\n\n output({ ok: true, bizUniqueId: result.bizUniqueId, response: result.response });\n });\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { LIGHT_RULE_TOOL_NAME_LIST } from \"../light-rules/names.js\";\nimport { type CliCommand, output, exitError } from \"./helpers.js\";\n\ntype JsonObject = Record<string, unknown>;\n\nfunction isObject(value: unknown): value is JsonObject {\n return !!value && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction ensureArray(obj: JsonObject, key: string): unknown[] {\n const current = obj[key];\n if (Array.isArray(current)) return current;\n const next: unknown[] = [];\n obj[key] = next;\n return next;\n}\n\nfunction resolveConfigPath(): string {\n const fromEnv = process.env.OPENCLAW_CONFIG_PATH?.trim();\n if (fromEnv) return fromEnv;\n return join(homedir(), \".openclaw\", \"openclaw.json\");\n}\n\nconst LIGHT_TOOLS = [\"light_control\", ...LIGHT_RULE_TOOL_NAME_LIST] as const;\n\nfunction upsertLightControlAlsoAllow(cfg: JsonObject): {\n globalChanged: boolean;\n mainAgentChanged: boolean;\n} {\n if (!isObject(cfg.tools)) cfg.tools = {};\n const toolsAlsoAllow = ensureArray(cfg.tools as JsonObject, \"alsoAllow\");\n let globalChanged = false;\n for (const tool of LIGHT_TOOLS) {\n if (!toolsAlsoAllow.includes(tool)) {\n toolsAlsoAllow.push(tool);\n globalChanged = true;\n }\n }\n\n if (!isObject(cfg.agents)) cfg.agents = {};\n const agents = cfg.agents as JsonObject;\n const list = ensureArray(agents, \"list\");\n let mainAgent = list.find(\n (item) => isObject(item) && item.id === \"main\",\n ) as JsonObject | undefined;\n if (!mainAgent) {\n mainAgent = { id: \"main\" };\n list.push(mainAgent);\n }\n if (!isObject(mainAgent.tools)) mainAgent.tools = {};\n const mainAlsoAllow = ensureArray(mainAgent.tools as JsonObject, \"alsoAllow\");\n let mainAgentChanged = false;\n for (const tool of LIGHT_TOOLS) {\n if (!mainAlsoAllow.includes(tool)) {\n mainAlsoAllow.push(tool);\n mainAgentChanged = true;\n }\n }\n\n return { globalChanged, mainAgentChanged };\n}\n\nexport function registerLightSetupTools(light: CliCommand): void {\n light\n .command(\"setup\")\n .description(\"自动放行 light_control(写入 tools.alsoAllow 与 agents.main.tools.alsoAllow)\")\n .action(() => {\n const configPath = resolveConfigPath();\n if (!existsSync(configPath)) {\n exitError(\"CONFIG_NOT_FOUND\", `未找到配置文件: ${configPath}`);\n }\n\n let cfg: JsonObject = {};\n try {\n const raw = readFileSync(configPath, \"utf-8\");\n const parsed = JSON.parse(raw);\n if (isObject(parsed)) cfg = parsed;\n } catch (err: any) {\n exitError(\"CONFIG_INVALID\", `读取/解析配置失败: ${err?.message ?? String(err)}`);\n }\n\n const result = upsertLightControlAlsoAllow(cfg);\n try {\n mkdirSync(dirname(configPath), { recursive: true });\n writeFileSync(configPath, JSON.stringify(cfg, null, 2) + \"\\n\", \"utf-8\");\n } catch (err: any) {\n exitError(\"WRITE_FAILED\", `写入配置失败: ${err?.message ?? String(err)}`);\n }\n\n output({\n ok: true,\n configPath,\n changed: result.globalChanged || result.mainAgentChanged,\n updates: {\n toolsAlsoAllow: result.globalChanged ? \"added\" : \"already_exists\",\n mainAgentAlsoAllow: result.mainAgentChanged ? \"added\" : \"already_exists\",\n },\n next: \"请执行: openclaw gateway restart\",\n });\n });\n}\n","import { loadApiKey } from \"../auth/credentials.js\";\nimport { getEnvUrls } from \"../env.js\";\nimport { output, exitError } from \"./helpers.js\";\nimport type { CliCommand, CliContext } from \"./helpers.js\";\nimport type { TunnelStatusInfo } from \"../tunnel/relay-client.js\";\nimport { assessTunnelStatus } from \"../tunnel/status.js\";\n\nfunction formatMessage(status: TunnelStatusInfo): string {\n switch (status.state) {\n case \"connected\":\n return `隧道已连接(自 ${status.since})`;\n case \"connecting\":\n return `隧道正在连接(自 ${status.since},第 ${status.reconnectAttempt} 次重连)`;\n case \"disconnected\":\n return `隧道已断开(自 ${status.since})${status.lastDisconnectReason ? `,原因: ${status.lastDisconnectReason}` : \"\"},等待重连(第 ${status.reconnectAttempt} 次)`;\n case \"stopped\":\n return `隧道服务已停止(自 ${status.since})`;\n default:\n return `未知状态: ${status.state}`;\n }\n}\n\nexport function registerTunnelStatus(ntf: CliCommand, ctx: CliContext): void {\n ntf\n .command(\"tunnel-status\")\n .description(\"检查 Relay Tunnel 隧道连接状态(读取运行中服务的状态文件,不影响已有连接)\")\n .action(async () => {\n const tunnelUrl = getEnvUrls().relayTunnelUrl;\n const apiKey = loadApiKey();\n\n if (!tunnelUrl) {\n exitError(\n \"TUNNEL_NOT_CONFIGURED\",\n \"RELAY_TUNNEL_URL 未配置,隧道功能未启用。请在构建时设置 RELAY_TUNNEL_URL 环境变量。\",\n );\n }\n\n if (!apiKey) {\n exitError(\n \"TOKEN_MISSING\",\n \"API Key 未设置,隧道无法连接。请执行 openclaw ntf auth set-api-key <apiKey>\",\n );\n }\n\n if (!ctx.stateDir) {\n exitError(\n \"STATE_DIR_UNAVAILABLE\",\n \"无法确定状态目录,无法检查隧道状态。请在 openclaw 主环境中执行该命令。\",\n );\n }\n\n const assessment = assessTunnelStatus(ctx.stateDir);\n const status = assessment.status;\n\n if (!status) {\n exitError(\n assessment.issueCode ?? \"STATUS_NOT_FOUND\",\n assessment.issueMessage ??\n \"未找到隧道状态文件,隧道服务可能尚未启动过。请确认 openclaw 主进程正在运行。\",\n );\n }\n\n if (assessment.issueCode) {\n exitError(assessment.issueCode, assessment.issueMessage ?? formatMessage(status));\n }\n\n const ok = status.state === \"connected\";\n output({\n ok,\n tunnelUrl,\n connection: {\n state: status.state,\n since: status.since,\n reconnectAttempt: status.reconnectAttempt,\n lastDisconnectReason: status.lastDisconnectReason,\n },\n runtime: {\n lockOwnerPid: assessment.lock.pid,\n lockOwnerStartedAt: assessment.lock.startedAt,\n lockOwnerActive: assessment.lock.active,\n },\n message: formatMessage(status),\n });\n\n if (!ok) process.exit(1);\n });\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { TunnelStatusInfo } from \"./relay-client.js\";\n\nexport const TUNNEL_STATUS_REL_PATH = join(\n \"plugins\",\n \"phone-notifications\",\n \"tunnel-status.json\",\n);\nexport const TUNNEL_LOCK_REL_PATH = join(\n \"plugins\",\n \"phone-notifications\",\n \"relay-tunnel.lock\",\n);\n\ntype TunnelState = TunnelStatusInfo[\"state\"];\n\ninterface TunnelLockInfo {\n pid: number;\n startedAt: string;\n}\n\nexport interface TunnelStatusAssessment {\n status: TunnelStatusInfo | null;\n issueCode: \"STATUS_NOT_FOUND\" | \"STATUS_INVALID\" | \"STATUS_STALE\" | null;\n issueMessage: string | null;\n statusFilePath: string;\n lockFilePath: string;\n lock: {\n exists: boolean;\n pid: number | null;\n startedAt: string | null;\n active: boolean | null;\n };\n}\n\nfunction isTunnelState(value: unknown): value is TunnelState {\n return (\n value === \"connected\" ||\n value === \"connecting\" ||\n value === \"disconnected\" ||\n value === \"stopped\"\n );\n}\n\nfunction isTunnelStatusInfo(value: unknown): value is TunnelStatusInfo {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return false;\n const obj = value as Record<string, unknown>;\n return (\n isTunnelState(obj.state) &&\n typeof obj.since === \"string\" &&\n typeof obj.reconnectAttempt === \"number\" &&\n (obj.lastDisconnectReason === undefined ||\n typeof obj.lastDisconnectReason === \"string\")\n );\n}\n\nfunction parseTunnelLockInfo(value: unknown): TunnelLockInfo | null {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return null;\n const obj = value as Record<string, unknown>;\n return typeof obj.pid === \"number\" && typeof obj.startedAt === \"string\"\n ? { pid: obj.pid, startedAt: obj.startedAt }\n : null;\n}\n\nfunction isProcessAlive(pid: number): boolean {\n if (!Number.isInteger(pid) || pid <= 0) return false;\n if (pid === process.pid) return true;\n try {\n process.kill(pid, 0);\n return true;\n } catch (err: any) {\n return err?.code === \"EPERM\";\n }\n}\n\nfunction isStatusOlderThanLock(\n statusSince: string,\n lockStartedAt: string,\n): boolean {\n const statusTs = Date.parse(statusSince);\n const lockTs = Date.parse(lockStartedAt);\n if (Number.isNaN(statusTs) || Number.isNaN(lockTs)) return false;\n return statusTs + 1000 < lockTs;\n}\n\nfunction staleStatusMessage(\n status: TunnelStatusInfo,\n lock: TunnelStatusAssessment[\"lock\"],\n): string {\n const prefix = `隧道状态文件显示已连接(自 ${status.since})`;\n\n if (!lock.exists) {\n return `${prefix},但未找到本地运行锁,状态可能已过期。请重启 openclaw 主进程。`;\n }\n\n if (lock.pid === null || lock.startedAt === null) {\n return `${prefix},但本地运行锁内容不完整,无法确认当前连接是否仍然有效。请重启 openclaw 主进程。`;\n }\n\n if (lock.active === false) {\n return `${prefix},但本地运行锁仍指向已退出的进程 pid=${lock.pid},状态可能已过期。请重启 openclaw 主进程。`;\n }\n\n return `${prefix},但当前运行锁启动于 ${lock.startedAt},晚于状态时间,说明状态未随新进程刷新。请重启 openclaw 主进程。`;\n}\n\nexport function assessTunnelStatus(stateDir: string): TunnelStatusAssessment {\n const statusFilePath = join(stateDir, TUNNEL_STATUS_REL_PATH);\n const lockFilePath = join(stateDir, TUNNEL_LOCK_REL_PATH);\n\n if (!existsSync(statusFilePath)) {\n return {\n status: null,\n issueCode: \"STATUS_NOT_FOUND\",\n issueMessage:\n \"未找到隧道状态文件,隧道服务可能尚未启动过。请确认 openclaw 主进程正在运行。\",\n statusFilePath,\n lockFilePath,\n lock: {\n exists: existsSync(lockFilePath),\n pid: null,\n startedAt: null,\n active: null,\n },\n };\n }\n\n let rawStatus: unknown;\n try {\n rawStatus = JSON.parse(readFileSync(statusFilePath, \"utf-8\"));\n } catch {\n return {\n status: null,\n issueCode: \"STATUS_INVALID\",\n issueMessage: \"隧道状态文件解析失败,文件内容损坏或格式不正确。请重启 openclaw 主进程。\",\n statusFilePath,\n lockFilePath,\n lock: {\n exists: existsSync(lockFilePath),\n pid: null,\n startedAt: null,\n active: null,\n },\n };\n }\n\n if (!isTunnelStatusInfo(rawStatus)) {\n return {\n status: null,\n issueCode: \"STATUS_INVALID\",\n issueMessage: \"隧道状态文件缺少必要字段或字段类型不正确。请重启 openclaw 主进程。\",\n statusFilePath,\n lockFilePath,\n lock: {\n exists: existsSync(lockFilePath),\n pid: null,\n startedAt: null,\n active: null,\n },\n };\n }\n\n const status = rawStatus;\n const lockExists = existsSync(lockFilePath);\n let lockInfo: TunnelLockInfo | null = null;\n\n if (lockExists) {\n try {\n lockInfo = parseTunnelLockInfo(JSON.parse(readFileSync(lockFilePath, \"utf-8\")));\n } catch {\n lockInfo = null;\n }\n }\n\n const lock = {\n exists: lockExists,\n pid: lockInfo?.pid ?? null,\n startedAt: lockInfo?.startedAt ?? null,\n active: lockInfo ? isProcessAlive(lockInfo.pid) : null,\n };\n\n if (status.state === \"connected\") {\n const isStale =\n !lock.exists ||\n lock.pid === null ||\n lock.startedAt === null ||\n lock.active === false ||\n isStatusOlderThanLock(status.since, lock.startedAt);\n\n if (isStale) {\n return {\n status,\n issueCode: \"STATUS_STALE\",\n issueMessage: staleStatusMessage(status, lock),\n statusFilePath,\n lockFilePath,\n lock,\n };\n }\n }\n\n return {\n status,\n issueCode: null,\n issueMessage: null,\n statusFilePath,\n lockFilePath,\n lock,\n };\n}\n","import {\n type CliCommand,\n type CliContext,\n resolveNotificationsDir,\n output,\n exitError,\n} from \"./helpers.js\";\n\nexport function registerNtfStoragePath(ntf: CliCommand, ctx: CliContext): void {\n ntf\n .command(\"storage-path\")\n .description(\"查询通知存储路径\")\n .action(() => {\n const dir = resolveNotificationsDir(ctx);\n if (!dir) exitError(\"STORAGE_UNAVAILABLE\", \"通知存储目录不可用\");\n output({ ok: true, path: dir });\n });\n}\n","import { existsSync, readFileSync, readdirSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport {\n type CliCommand,\n type CliContext,\n filterDateRange,\n today,\n daysAgo,\n output,\n exitError,\n} from \"./helpers.js\";\n\n/** Resolve the plugin logs directory from stateDir */\nfunction resolveLogsDir(ctx: CliContext): string | null {\n if (ctx.stateDir) {\n const dir = join(\n ctx.stateDir,\n \"plugins\",\n \"phone-notifications\",\n \"logs\",\n );\n if (existsSync(dir)) return dir;\n }\n return null;\n}\n\n/** List available log date keys (YYYY-MM-DD) sorted descending */\nfunction listLogDateKeys(dir: string): string[] {\n const pattern = /^(\\d{4}-\\d{2}-\\d{2})\\.log$/;\n const keys: string[] = [];\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n if (!entry.isFile()) continue;\n const m = pattern.exec(entry.name);\n if (m) keys.push(m[1]);\n }\n return keys.sort().reverse();\n}\n\n/** Read log lines from a date file, optionally filtering by keyword */\nfunction collectLogLines(\n dir: string,\n dateKey: string,\n keyword: string | undefined,\n limit: number,\n collected: string[],\n): void {\n const filePath = join(dir, `${dateKey}.log`);\n if (!existsSync(filePath)) return;\n\n const content = readFileSync(filePath, \"utf-8\");\n const lowerKeyword = keyword?.toLowerCase();\n\n for (const line of content.split(\"\\n\")) {\n if (collected.length >= limit) return;\n if (!line) continue;\n if (lowerKeyword && !line.toLowerCase().includes(lowerKeyword)) continue;\n collected.push(`[${dateKey}] ${line}`);\n }\n}\n\nexport function registerLogSearch(ntf: CliCommand, ctx: CliContext): void {\n ntf\n .command(\"log\")\n .description(\"查看/搜索插件日志\")\n .option(\"--keyword <text>\", \"按关键词过滤日志\")\n .option(\"--from <date>\", \"开始日期 YYYY-MM-DD\", daysAgo(7))\n .option(\"--to <date>\", \"结束日期 YYYY-MM-DD\", today())\n .option(\"--limit <n>\", \"最大返回条数\", \"50\")\n .action(\n (opts: {\n keyword?: string;\n from: string;\n to: string;\n limit: string;\n }) => {\n const dir = resolveLogsDir(ctx);\n if (!dir) exitError(\"LOGS_UNAVAILABLE\", \"日志目录不可用\");\n\n const keys = filterDateRange(listLogDateKeys(dir), opts.from, opts.to);\n const limit = parseInt(opts.limit, 10) || 50;\n const results: string[] = [];\n\n for (const dateKey of keys) {\n if (results.length >= limit) break;\n collectLogLines(dir, dateKey, opts.keyword, limit, results);\n }\n\n output({\n ok: true,\n keyword: opts.keyword ?? null,\n total: results.length,\n lines: results,\n });\n },\n );\n}\n","import { spawnSync } from \"node:child_process\";\nimport {\n readPersistedEnvName,\n saveEnvName,\n getEnvUrls,\n getAvailableEnvs,\n type EnvName,\n} from \"../env.js\";\nimport { detectHostKind } from \"../host.js\";\nimport { output, exitError } from \"./helpers.js\";\nimport type { CliCommand } from \"./helpers.js\";\nimport { scheduleGatewayRestart } from \"../update/restart.js\";\n\nconst GATEWAY_RESTART_TIMEOUT_MS = 30_000;\n\nconst NOOP_LOGGER = {\n info() {\n // noop\n },\n warn() {\n // noop\n },\n error() {\n // noop\n },\n};\n\nexport interface EnvShowPayload {\n ok: true;\n env: EnvName;\n source: \".env\" | \"default\";\n lightApiUrl: string;\n relayTunnelUrl: string;\n availableEnvs: EnvName[];\n}\n\nexport interface EnvReloadResult {\n attempted: boolean;\n ok: boolean;\n method: \"signal\" | \"cli\" | \"skipped\";\n command?: string;\n message: string;\n detail?: string;\n}\n\nexport interface EnvSwitchPayload {\n ok: true;\n message: string;\n env: EnvName;\n lightApiUrl: string;\n relayTunnelUrl: string;\n reload: EnvReloadResult;\n}\n\nexport interface EnvCliDeps {\n readPersistedEnvName?: () => EnvName | undefined;\n scheduleGatewayRestart?: () => { scheduled: boolean };\n detectHostKind?: () => \"openclaw\" | \"qclaw\";\n spawnSync?: typeof spawnSync;\n hostCli?: string;\n}\n\nexport function buildEnvShowPayload(deps: EnvCliDeps = {}): EnvShowPayload {\n const persistedEnv = deps.readPersistedEnvName?.() ?? readPersistedEnvName();\n const env = persistedEnv ?? \"production\";\n const urls = getEnvUrls(env);\n\n return {\n ok: true,\n env,\n source: persistedEnv ? \".env\" : \"default\",\n lightApiUrl: urls.lightApiUrl,\n relayTunnelUrl: urls.relayTunnelUrl,\n availableEnvs: getAvailableEnvs(),\n };\n}\n\nexport function triggerGatewayReloadAfterEnvSwitch(\n deps: EnvCliDeps = {},\n): EnvReloadResult {\n const scheduleRestart =\n deps.scheduleGatewayRestart ??\n (() => scheduleGatewayRestart(NOOP_LOGGER));\n const scheduled = scheduleRestart();\n if (scheduled.scheduled) {\n return {\n attempted: true,\n ok: true,\n method: \"signal\",\n message: \"已自动触发 gateway 进程内重载\",\n };\n }\n\n const hostKind = deps.detectHostKind?.() ?? detectHostKind();\n if (hostKind === \"qclaw\") {\n return {\n attempted: false,\n ok: false,\n method: \"skipped\",\n message: \"当前宿主为 QClaw,请重启 QClaw 桌面应用后使环境切换生效\",\n };\n }\n\n const hostCli = deps.hostCli?.trim() || process.env.HOST_CLI?.trim() || \"openclaw\";\n const command = `${hostCli} gateway restart`;\n const run = deps.spawnSync ?? spawnSync;\n const result = run(hostCli, [\"gateway\", \"restart\"], {\n encoding: \"utf-8\",\n stdio: \"pipe\",\n timeout: GATEWAY_RESTART_TIMEOUT_MS,\n });\n\n if (!result.error && result.status === 0) {\n return {\n attempted: true,\n ok: true,\n method: \"cli\",\n command,\n message: `已自动触发 ${command}`,\n };\n }\n\n const stderr =\n typeof result.stderr === \"string\" ? result.stderr.trim() : \"\";\n const errorMessage = result.error?.message?.trim();\n return {\n attempted: true,\n ok: false,\n method: \"cli\",\n command,\n message: `已切换环境,但自动重载未完成,请手动运行: ${command}`,\n detail:\n stderr ||\n errorMessage ||\n (typeof result.status === \"number\"\n ? `exit status=${result.status}`\n : undefined),\n };\n}\n\nexport function buildEnvSwitchPayload(\n envName: EnvName,\n deps: EnvCliDeps = {},\n): EnvSwitchPayload {\n saveEnvName(envName);\n const urls = getEnvUrls(envName);\n const reload = triggerGatewayReloadAfterEnvSwitch(deps);\n\n return {\n ok: true,\n message: reload.ok\n ? `已切换到 ${envName} 环境,并已触发重载`\n : `已切换到 ${envName} 环境`,\n env: envName,\n lightApiUrl: urls.lightApiUrl,\n relayTunnelUrl: urls.relayTunnelUrl,\n reload,\n };\n}\n\nexport function registerEnvCli(ntf: CliCommand, deps: EnvCliDeps = {}): void {\n const env = ntf.command(\"env\").description(\"环境管理(切换 test / production)\");\n\n env\n .command(\"show\")\n .description(\"显示当前环境及对应的接口地址\")\n .action(() => {\n output(buildEnvShowPayload(deps));\n });\n\n env\n .command(\"switch <env>\")\n .description(\"切换环境(test / production)\")\n .action((envName: string) => {\n const available = getAvailableEnvs();\n if (!available.includes(envName as any)) {\n exitError(\n \"INVALID_ENV\",\n `无效的环境名称: ${envName},可选值: ${available.join(\", \")}`,\n );\n }\n output(buildEnvSwitchPayload(envName as EnvName, deps));\n });\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { createInterface } from \"node:readline\";\nimport { resolveConfigPath, resolveStateDir } from \"../host.js\";\nimport { output } from \"./helpers.js\";\nimport type { CliCommand, CliContext } from \"./helpers.js\";\nimport type { CheckResult, JsonObject, Severity } from \"./doctor/types.js\";\nimport { allCheckers } from \"./doctor/checkers.js\";\n\nfunction isObject(v: unknown): v is JsonObject {\n return !!v && typeof v === \"object\" && !Array.isArray(v);\n}\n\nfunction readConfig(configPath: string): JsonObject {\n if (!existsSync(configPath)) return {};\n try {\n const parsed = JSON.parse(readFileSync(configPath, \"utf-8\"));\n return isObject(parsed) ? parsed : {};\n } catch {\n return {};\n }\n}\n\nfunction severityIcon(s: Severity): string {\n switch (s) {\n case \"critical\":\n return \"\\x1b[31m[CRITICAL]\\x1b[0m\";\n case \"warn\":\n return \"\\x1b[33m[WARN]\\x1b[0m\";\n case \"info\":\n return \"\\x1b[36m[INFO]\\x1b[0m\";\n }\n}\n\nfunction severityOrder(s: Severity): number {\n switch (s) {\n case \"critical\":\n return 0;\n case \"warn\":\n return 1;\n case \"info\":\n return 2;\n }\n}\n\nfunction confirm(question: string): Promise<boolean> {\n const rl = createInterface({ input: process.stdin, output: process.stderr });\n return new Promise((resolve) => {\n rl.question(question, (answer) => {\n rl.close();\n resolve(answer.trim().toLowerCase() === \"y\");\n });\n });\n}\n\nasync function runDoctor(ctx: CliContext, json: boolean, fix?: boolean): Promise<void> {\n const stateDir = ctx.stateDir ?? resolveStateDir();\n const configPath = resolveConfigPath(stateDir);\n const cfg = readConfig(configPath);\n\n const checkCtx = { cfg, configPath, stateDir };\n\n // 执行所有 checker\n const issues: CheckResult[] = [];\n for (const checker of allCheckers) {\n const result = await checker(checkCtx);\n if (result) issues.push(result);\n }\n\n // 按严重级别排序\n issues.sort((a, b) => severityOrder(a.severity) - severityOrder(b.severity));\n\n // 统计\n const summary = { critical: 0, warn: 0, info: 0 };\n for (const issue of issues) {\n summary[issue.severity]++;\n }\n\n // --json 模式\n if (json) {\n output({\n ok: issues.length === 0,\n summary,\n checks: issues.map((i) => ({\n id: i.id,\n severity: i.severity,\n title: i.title,\n detail: i.detail,\n autoFixable: i.fix !== null,\n fixDescription: i.fixDescription,\n })),\n });\n if (issues.length > 0) process.exit(1);\n return;\n }\n\n // 人类可读输出\n const log = console.error; // stderr,不污染 stdout\n log(\"\\n\\x1b[1m🔍 正在检查环境...\\x1b[0m\\n\");\n\n if (issues.length === 0) {\n log(\"\\x1b[32m✅ 所有检查通过,未发现问题。\\x1b[0m\\n\");\n output({ ok: true, summary });\n return;\n }\n\n for (const issue of issues) {\n log(`${severityIcon(issue.severity)} ${issue.title}`);\n log(` ↳ ${issue.detail}`);\n log(` ↳ 修复: ${issue.fixDescription}`);\n log();\n }\n\n log(\n `检测完成: \\x1b[31m${summary.critical} critical\\x1b[0m · ` +\n `\\x1b[33m${summary.warn} warn\\x1b[0m · ` +\n `\\x1b[36m${summary.info} info\\x1b[0m\\n`,\n );\n\n // 找出可自动修复的\n const fixable = issues.filter((i) => i.fix !== null);\n\n if (fixable.length === 0) {\n log(\"以上问题均需手动修复,请参考上方提示。\\n\");\n output({ ok: false, summary });\n process.exit(1);\n return;\n }\n\n log(`发现 ${fixable.length} 个可自动修复的问题:`);\n for (const issue of fixable) {\n log(` • ${issue.title} → ${issue.fixDescription}`);\n }\n log();\n\n const yes = fix === true || await confirm(\"是否执行自动修复?[y/N]: \");\n if (!yes) {\n log(\"\\n已取消。\\n\");\n output({ ok: false, summary, fixed: 0 });\n process.exit(1);\n return;\n }\n\n log();\n let fixed = 0;\n for (const issue of fixable) {\n try {\n await issue.fix!();\n log(`\\x1b[32m✅\\x1b[0m ${issue.title} → ${issue.fixDescription}`);\n fixed++;\n } catch (err: any) {\n log(\n `\\x1b[31m❌\\x1b[0m ${issue.title} 修复失败: ${err?.message ?? String(err)}`,\n );\n }\n }\n\n const manualCount = issues.length - fixable.length;\n if (manualCount > 0) {\n log(`\\n⚠️ 还有 ${manualCount} 个问题需要手动处理,请参考上方提示。`);\n }\n\n log(`\\n修复完成 (${fixed}/${fixable.length})。建议执行: openclaw gateway restart\\n`);\n output({ ok: fixed === fixable.length && manualCount === 0, summary, fixed });\n if (fixed < fixable.length || manualCount > 0) process.exit(1);\n}\n\nexport function registerDoctor(ntf: CliCommand, ctx: CliContext): void {\n ntf\n .command(\"doctor\")\n .description(\"自检环境配置,检测安全风险和常见问题\")\n .option(\"--json\", \"以 JSON 格式输出结果(供脚本调用)\")\n .option(\"--fix\", \"自动修复可修复的问题(跳过确认提示)\")\n .action((opts: { json?: boolean; fix?: boolean }) => {\n return runDoctor(ctx, opts.json === true, opts.fix);\n });\n}\n","import { readFileSync, writeFileSync, copyFileSync } from \"node:fs\";\nimport type { Checker, JsonObject } from \"./types.js\";\n\nfunction isObject(v: unknown): v is JsonObject {\n return !!v && typeof v === \"object\" && !Array.isArray(v);\n}\n\nexport const checkDangerousFlags: Checker = ({ cfg, configPath }) => {\n const gateway = cfg.gateway;\n if (!isObject(gateway)) return null;\n\n const controlUi = gateway.controlUi;\n if (!isObject(controlUi)) return null;\n\n if (controlUi.dangerouslyDisableDeviceAuth !== true) return null;\n\n return {\n id: \"dangerous-flags\",\n severity: \"critical\",\n title: \"gateway.controlUi.dangerouslyDisableDeviceAuth 已启用\",\n detail: \"这会关闭 Control UI 的设备身份验证,任何人都可以访问控制面板。\",\n fixDescription: \"设为 false\",\n fix: () => {\n const raw = readFileSync(configPath, \"utf-8\");\n const config = JSON.parse(raw) as JsonObject;\n const gw = config.gateway as JsonObject;\n const cui = gw.controlUi as JsonObject;\n cui.dangerouslyDisableDeviceAuth = false;\n copyFileSync(configPath, configPath + \".bak\");\n writeFileSync(configPath, JSON.stringify(config, null, 2) + \"\\n\", \"utf-8\");\n },\n };\n};\n","import type { Checker, JsonObject } from \"./types.js\";\n\nfunction isObject(v: unknown): v is JsonObject {\n return !!v && typeof v === \"object\" && !Array.isArray(v);\n}\n\nexport const checkTrustedProxy: Checker = ({ cfg }) => {\n const gateway = cfg.gateway;\n if (!isObject(gateway)) return null;\n\n const auth = gateway.auth;\n if (!isObject(auth)) return null;\n\n if (auth.mode !== \"trusted-proxy\") return null;\n\n return {\n id: \"trusted-proxy\",\n severity: \"critical\",\n title: \"gateway.auth.mode 为 trusted-proxy\",\n detail:\n \"认证委托给了反向代理。请确保: (1) 代理终止 TLS 并认证用户; \" +\n \"(2) gateway.trustedProxies 仅限代理 IP; \" +\n \"(3) 防火墙阻止直接访问 Gateway 端口。\",\n fixDescription: \"此项需手动检查代理配置,无法自动修复\",\n fix: null,\n };\n};\n\nexport const checkTrustedProxyAllowUsers: Checker = ({ cfg }) => {\n const gateway = cfg.gateway;\n if (!isObject(gateway)) return null;\n\n const auth = gateway.auth;\n if (!isObject(auth)) return null;\n\n if (auth.mode !== \"trusted-proxy\") return null;\n\n const tp = auth.trustedProxy;\n if (!isObject(tp)) return warnEmpty();\n\n const allowUsers = tp.allowUsers;\n if (!Array.isArray(allowUsers) || allowUsers.length === 0) return warnEmpty();\n\n return null;\n};\n\nfunction warnEmpty() {\n return {\n id: \"trusted-proxy-allow-users\",\n severity: \"warn\" as const,\n title: \"trusted-proxy 模式下 allowUsers 为空\",\n detail: \"任何通过代理认证的用户都可以访问 Gateway。\",\n fixDescription:\n '请编辑 openclaw.json,在 gateway.auth.trustedProxy.allowUsers 中添加允许的用户邮箱,例如 [\"nick@example.com\"]',\n fix: null,\n };\n}\n","import { statSync, chmodSync } from \"node:fs\";\nimport type { Checker } from \"./types.js\";\n\nexport const checkStateDirPerms: Checker = ({ stateDir }) => {\n let mode: number;\n try {\n mode = statSync(stateDir).mode;\n } catch {\n return null;\n }\n\n // 检查 group 和 other 是否有任何权限\n const otherBits = mode & 0o077;\n if (otherBits === 0) return null;\n\n const modeStr = \"0\" + (mode & 0o777).toString(8);\n\n return {\n id: \"state-dir-perms\",\n severity: \"warn\",\n title: `状态目录权限过于宽松 (${stateDir} mode=${modeStr})`,\n detail: \"其他用户可以读取该目录下的凭证和配置文件。\",\n fixDescription: \"chmod 700 \" + stateDir,\n fix: () => {\n chmodSync(stateDir, 0o700);\n },\n };\n};\n","import type { Checker, JsonObject } from \"./types.js\";\n\nfunction isObject(v: unknown): v is JsonObject {\n return !!v && typeof v === \"object\" && !Array.isArray(v);\n}\n\nexport const checkToolPolicy: Checker = ({ cfg }) => {\n const agents = cfg.agents;\n if (!isObject(agents)) return null;\n\n const list = agents.list;\n if (!Array.isArray(list)) return null;\n\n const permissiveAgents: string[] = [];\n\n for (const agent of list) {\n if (!isObject(agent)) continue;\n const id = String(agent.id ?? \"unknown\");\n\n // 如果 agent 没有设置 toolPolicy / profile,则视为使用 default(宽松)\n const tools = agent.tools;\n if (!isObject(tools)) {\n permissiveAgents.push(id);\n continue;\n }\n\n const profile = tools.profile;\n if (!profile || profile === \"default\") {\n permissiveAgents.push(id);\n }\n }\n\n if (permissiveAgents.length === 0) return null;\n\n return {\n id: \"tool-policy\",\n severity: \"warn\",\n title: \"扩展插件 tool policy 宽松\",\n detail: `以下 agent 使用了 default 策略: ${permissiveAgents.join(\", \")}。插件工具可能被未授权调用。`,\n fixDescription:\n \"建议为处理不可信输入的 agent 使用 minimal 或 coding profile,或配置明确的 tool allowlist。\",\n fix: null,\n };\n};\n","import { loadApiKey } from \"../../auth/credentials.js\";\nimport type { Checker } from \"./types.js\";\n\nexport const checkCredentials: Checker = () => {\n const apiKey = loadApiKey();\n if (apiKey) return null;\n\n return {\n id: \"credentials\",\n severity: \"critical\",\n title: \"API Key 未配置\",\n detail:\n \"未在 credentials.json 中找到 apiKey,隧道和推送等功能无法正常工作。\",\n fixDescription:\n \"请执行: openclaw ntf auth set-api-key <your-api-key>\",\n fix: null,\n };\n};\n","import type { Checker } from \"./types.js\";\nimport { assessTunnelStatus } from \"../../tunnel/status.js\";\n\nexport const checkTunnel: Checker = ({ stateDir }) => {\n const assessment = assessTunnelStatus(stateDir);\n const status = assessment.status;\n\n if (assessment.issueCode === \"STATUS_NOT_FOUND\") {\n return {\n id: \"tunnel\",\n severity: \"warn\",\n title: \"隧道状态文件不存在\",\n detail: assessment.issueMessage ?? \"隧道服务可能尚未启动过,或状态文件已被删除。\",\n fixDescription: \"请确认 openclaw 主进程正在运行\",\n fix: null,\n };\n }\n\n if (assessment.issueCode === \"STATUS_INVALID\") {\n return {\n id: \"tunnel\",\n severity: \"warn\",\n title: \"隧道状态文件解析失败\",\n detail: assessment.issueMessage ?? \"文件内容损坏或格式不正确。\",\n fixDescription: \"请重启 openclaw 主进程\",\n fix: null,\n };\n }\n\n if (assessment.issueCode === \"STATUS_STALE\") {\n return {\n id: \"tunnel\",\n severity: \"warn\",\n title: \"隧道状态已过期\",\n detail: assessment.issueMessage ?? \"隧道状态文件仍显示已连接,但运行时状态已失效。\",\n fixDescription: \"请重启 openclaw 主进程\",\n fix: null,\n };\n }\n\n if (!status || status.state === \"connected\") return null;\n\n const reasonSuffix = status.lastDisconnectReason\n ? `,原因: ${status.lastDisconnectReason}`\n : \"\";\n\n return {\n id: \"tunnel\",\n severity: \"warn\",\n title: `隧道未连接 (state=${status.state})`,\n detail: `隧道自 ${status.since} 处于 ${status.state} 状态${reasonSuffix},重连次数: ${status.reconnectAttempt}`,\n fixDescription: \"请检查网络连接或重启 openclaw 主进程\",\n fix: null,\n };\n};\n","import type { Checker } from \"./types.js\";\n\nconst MIN_MAJOR = 22;\nconst MIN_MINOR = 12;\n\nexport const checkNodeVersion: Checker = () => {\n const version = process.versions.node;\n const [major, minor] = version.split(\".\").map(Number);\n\n if (major > MIN_MAJOR || (major === MIN_MAJOR && minor >= MIN_MINOR)) {\n return null;\n }\n\n return {\n id: \"node-version\",\n severity: \"warn\",\n title: `Node.js 版本过低 (v${version})`,\n detail: `要求 >= ${MIN_MAJOR}.${MIN_MINOR}.0,当前为 v${version}。`,\n fixDescription: `请升级 Node.js 到 ${MIN_MAJOR}.${MIN_MINOR}.0 或更高版本`,\n fix: null,\n };\n};\n","import { loadEnvName } from \"../../env.js\";\nimport { resolveUpdateChannel } from \"../../update/channel.js\";\nimport { PLUGIN_VERSION } from \"../../version.js\";\nimport type { Checker } from \"./types.js\";\n\nexport const checkPluginVersion: Checker = async () => {\n const channel = resolveUpdateChannel({\n envName: loadEnvName(),\n });\n\n let latest: string;\n try {\n const res = await fetch(\n `https://registry.npmjs.org/@yoooclaw/phone-notifications/${channel}`,\n { signal: AbortSignal.timeout(5000) },\n );\n if (!res.ok) return null;\n const data = (await res.json()) as { version?: string };\n latest = data.version ?? \"\";\n } catch {\n // 网络不可用时跳过\n return null;\n }\n\n if (!latest || latest === PLUGIN_VERSION) return null;\n\n return {\n id: \"plugin-version\",\n severity: \"info\",\n title: `插件版本可更新 (当前 ${PLUGIN_VERSION} → 最新 ${latest})`,\n detail: \"有新版本可用,建议更新以获取最新功能和修复。\",\n fixDescription: `请执行: openclaw extension install @yoooclaw/phone-notifications@${latest}`,\n fix: null,\n };\n};\n","import type { Checker } from \"./types.js\";\nimport { checkDangerousFlags } from \"./check-dangerous-flags.js\";\nimport { checkTrustedProxy, checkTrustedProxyAllowUsers } from \"./check-trusted-proxy.js\";\nimport { checkStateDirPerms } from \"./check-state-dir-perms.js\";\nimport { checkToolPolicy } from \"./check-tool-policy.js\";\nimport { checkCredentials } from \"./check-credentials.js\";\nimport { checkTunnel } from \"./check-tunnel.js\";\nimport { checkNodeVersion } from \"./check-node-version.js\";\nimport { checkPluginVersion } from \"./check-plugin-version.js\";\n\n/** 所有 checker,按优先级排列 */\nexport const allCheckers: Checker[] = [\n // critical\n checkDangerousFlags,\n checkTrustedProxy,\n checkCredentials,\n // warn\n checkTrustedProxyAllowUsers,\n checkStateDirPerms,\n checkToolPolicy,\n checkTunnel,\n // info\n checkNodeVersion,\n checkPluginVersion,\n];\n","import {\n type CliCommand,\n type CliContext,\n resolveRecordingsDir,\n readRecordingIndex,\n output,\n exitError,\n} from \"./helpers.js\";\n\nexport function registerRecList(rec: CliCommand, ctx: CliContext): void {\n rec\n .command(\"list\")\n .description(\"列出所有录音(可按状态过滤)\")\n .option(\"--status <status>\", \"按传输状态过滤(如 synced, transcribed)\")\n .action((opts: { status?: string }) => {\n const dir = resolveRecordingsDir(ctx);\n if (!dir) exitError(\"STORAGE_UNAVAILABLE\", \"录音存储目录不可用\");\n\n let recordings = readRecordingIndex(dir);\n\n if (opts.status) {\n recordings = recordings.filter((r) => r.status === opts.status);\n }\n\n const items = recordings.map((r) => ({\n id: r.id,\n name: r.metadata.name,\n duration_sec: r.metadata.duration_sec,\n status: r.status,\n file_size_bytes: r.metadata.file_size_bytes,\n has_audio: !!r.audioFile,\n has_transcript: !!r.transcriptFile,\n created_at: r.metadata.created_at,\n updated_at: r.updatedAt,\n error: r.lastError ?? null,\n }));\n\n output({ ok: true, total: items.length, recordings: items });\n });\n}\n","import {\n type CliCommand,\n type CliContext,\n resolveRecordingsDir,\n readRecordingIndex,\n output,\n exitError,\n} from \"./helpers.js\";\n\nexport function registerRecStatus(rec: CliCommand, ctx: CliContext): void {\n rec\n .command(\"status <id>\")\n .description(\"查看单条录音详情\")\n .action((id: string) => {\n const dir = resolveRecordingsDir(ctx);\n if (!dir) exitError(\"STORAGE_UNAVAILABLE\", \"录音存储目录不可用\");\n\n const recordings = readRecordingIndex(dir);\n const entry = recordings.find((r) => r.id === id);\n\n if (!entry) {\n exitError(\"NOT_FOUND\", `录音不存在: ${id}`);\n }\n\n output({\n ok: true,\n recording: {\n id: entry.id,\n name: entry.metadata.name,\n duration_sec: entry.metadata.duration_sec,\n file_size_bytes: entry.metadata.file_size_bytes,\n status: entry.status,\n created_at: entry.metadata.created_at,\n location: entry.metadata.location ?? null,\n markers: entry.metadata.markers ?? [],\n audioFile: entry.audioFile ?? null,\n srtFile: entry.srtFile ?? null,\n transcriptDataFile: entry.transcriptDataFile ?? null,\n transcriptFile: entry.transcriptFile ?? null,\n summaryFile: entry.summaryFile ?? null,\n title: entry.title ?? null,\n error: entry.lastError ?? null,\n ingestedAt: entry.ingestedAt,\n updatedAt: entry.updatedAt,\n },\n });\n });\n}\n","import {\n type CliCommand,\n type CliContext,\n resolveRecordingsDir,\n output,\n exitError,\n} from \"./helpers.js\";\n\nexport function registerRecStoragePath(\n rec: CliCommand,\n ctx: CliContext,\n): void {\n rec\n .command(\"storage-path\")\n .description(\"查询录音存储路径\")\n .action(() => {\n const dir = resolveRecordingsDir(ctx);\n if (!dir) exitError(\"STORAGE_UNAVAILABLE\", \"录音存储目录不可用\");\n output({ ok: true, path: dir });\n });\n}\n","import { createInterface } from \"node:readline\";\nimport { writeFileSync, existsSync, readFileSync } from \"node:fs\";\nimport type { CliCommand, CliContext } from \"./helpers.js\";\nimport { resolveAsrConfigPath, output } from \"./helpers.js\";\nimport type { AsrConfig, WhisperModelSize, WhisperBackend, WhisperModelSource } from \"../types.js\";\n\n// ─── Prompt helpers ───\n\ntype Rl = ReturnType<typeof createInterface>;\n\nfunction ask(rl: Rl, question: string): Promise<string> {\n return new Promise((resolve) => rl.question(question, resolve));\n}\n\n/**\n * Ask for a single choice from a numbered list.\n * Writes the list and prompt to stderr; returns the 0-based index of the chosen item.\n */\nasync function askChoice(\n rl: Rl,\n prompt: string,\n choices: readonly string[],\n defaultIdx = 0,\n): Promise<number> {\n choices.forEach((c, i) => {\n const marker = i === defaultIdx ? \"●\" : \"○\";\n process.stderr.write(` ${marker} ${i + 1}. ${c}\\n`);\n });\n while (true) {\n const ans = (await ask(rl, `${prompt} [1-${choices.length},默认 ${defaultIdx + 1}]: `)).trim();\n if (!ans) return defaultIdx;\n const n = parseInt(ans, 10);\n if (!isNaN(n) && n >= 1 && n <= choices.length) return n - 1;\n process.stderr.write(` 请输入 1-${choices.length} 之间的数字\\n`);\n }\n}\n\n/** Ask for a value; returns undefined if user presses Enter with no input. */\nasync function askOptional(rl: Rl, prompt: string): Promise<string | undefined> {\n const ans = (await ask(rl, `${prompt} [可选,直接回车跳过]: `)).trim();\n return ans || undefined;\n}\n\n// ─── Mode-specific setup flows ───\n\nasync function setupApi(rl: Rl): Promise<AsrConfig> {\n process.stderr.write(\"\\n─── 云端 ASR(model-proxy)配置 ───\\n\\n\");\n process.stderr.write(\"说明:不再填写第三方 API Key,插件会复用当前账号的 API Key 调用 model-proxy 长录音接口。\\n\\n\");\n\n const endpoint = await askOptional(rl, \"自定义 model-proxy submit-task 端点 URL\");\n const language = await askOptional(rl, \"语言提示(如 zh / en)\");\n const enableNormalizationInput = await askOptional(rl, \"启用文本规范化 ITN?(y/N)\");\n const normalized = enableNormalizationInput?.trim().toLowerCase();\n const enableNormalization =\n normalized === \"y\" || normalized === \"yes\" || normalized === \"true\";\n\n return {\n mode: \"api\",\n api: {\n ...(endpoint ? { endpoint } : {}),\n ...(language ? { language } : {}),\n ...(enableNormalizationInput ? { enableNormalization } : {}),\n },\n };\n}\n\nasync function setupLocal(rl: Rl): Promise<AsrConfig> {\n process.stderr.write(\"\\n─── 本地 Whisper 转写配置 ───\\n\\n\");\n\n process.stderr.write(\"模型大小:\\n\");\n const modelChoices = [\n \"自动选择(根据可用内存推荐)\",\n \"tiny\",\n \"base\",\n \"small\",\n \"medium\",\n \"large-v3\",\n ] as const;\n const modelIdx = await askChoice(rl, \"选择模型\", modelChoices);\n const model: WhisperModelSize | undefined =\n modelIdx === 0 ? undefined : (modelChoices[modelIdx] as WhisperModelSize);\n\n const language = await askOptional(rl, \"语言提示(如 zh / en,留空自动检测)\");\n\n process.stderr.write(\"\\n推理后端:\\n\");\n const backendChoices = [\n \"自动选择(根据运行环境推荐)\",\n \"coreml(Apple Silicon 推荐)\",\n \"cuda(NVIDIA GPU)\",\n \"cpu\",\n ] as const;\n const backendIdx = await askChoice(rl, \"选择后端\", backendChoices);\n const backend: WhisperBackend | undefined =\n backendIdx === 0 ? undefined : ([\"coreml\", \"cuda\", \"cpu\"] as const)[backendIdx - 1];\n\n process.stderr.write(\"\\n模型下载源:\\n\");\n const sourceChoices = [\n \"auto(自动探测,优先 HuggingFace,失败回退国内镜像)\",\n \"huggingface(海外直连)\",\n \"domestic(国内镜像)\",\n ] as const;\n const sourceIdx = await askChoice(rl, \"选择下载源\", sourceChoices);\n const modelSource: WhisperModelSource = ([\"auto\", \"huggingface\", \"domestic\"] as const)[sourceIdx];\n\n const modelMirrorUrl = await askOptional(rl, \"自定义模型下载地址(覆盖下载源)\");\n\n return {\n mode: \"local\",\n local: {\n ...(model ? { model } : {}),\n ...(language ? { language } : {}),\n ...(backend ? { backend } : {}),\n modelSource,\n ...(modelMirrorUrl ? { modelMirrorUrl } : {}),\n },\n };\n}\n\n// ─── Command registration ───\n\nexport function registerRecSetup(rec: CliCommand, ctx: CliContext): void {\n rec\n .command(\"setup\")\n .description(\"交互式配置 ASR 转写参数,保存到本地配置文件\")\n .action(async () => {\n const configPath = resolveAsrConfigPath(ctx);\n\n // Show existing config hint if present\n if (existsSync(configPath)) {\n try {\n const existing = JSON.parse(readFileSync(configPath, \"utf-8\")) as AsrConfig & { updatedAt?: string };\n process.stderr.write(`当前已有配置:mode = ${existing.mode}`);\n if (existing.updatedAt) process.stderr.write(`,更新于 ${existing.updatedAt}`);\n process.stderr.write(\"\\n\");\n } catch {\n // ignore parse errors\n }\n }\n\n const rl = createInterface({ input: process.stdin, output: process.stderr, terminal: true });\n\n try {\n process.stderr.write(\"\\n转写模式:\\n\");\n const modeIdx = await askChoice(rl, \"选择模式\", [\"api(云端 model-proxy 长录音)\", \"local(本地 Whisper)\"]);\n\n const config: AsrConfig = modeIdx === 0 ? await setupApi(rl) : await setupLocal(rl);\n const stored = { ...config, updatedAt: new Date().toISOString() };\n\n writeFileSync(configPath, JSON.stringify(stored, null, 2), \"utf-8\");\n process.stderr.write(`\\n✓ 配置已保存到 ${configPath}\\n\\n`);\n\n output({ ok: true, ...stored });\n } finally {\n rl.close();\n }\n });\n}\n","import { spawnSync } from \"node:child_process\";\nimport { writeFileSync, unlinkSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport os from \"node:os\";\nimport { resolveStateDir } from \"../host.js\";\nimport { PLUGIN_VERSION } from \"../version.js\";\nimport { output } from \"./helpers.js\";\nimport type { CliCommand, CliContext } from \"./helpers.js\";\n\nconst BASE_URL = \"https://artifact.yoooclaw.com/plugin\";\n\nasync function fetchText(url: string): Promise<string> {\n const res = await fetch(url, { signal: AbortSignal.timeout(30_000) });\n if (!res.ok) {\n throw new Error(`请求失败: ${url} (HTTP ${res.status})`);\n }\n return res.text();\n}\n\nasync function runUpdate(\n ctx: CliContext,\n opts: { json?: boolean; force?: boolean; beta?: boolean },\n): Promise<void> {\n const json = opts.json === true;\n const force = opts.force === true;\n const beta = opts.beta === true;\n const channel = beta ? \"beta\" : \"latest\";\n const log = (msg: string) => {\n if (!json) process.stderr.write(`${msg}\\n`);\n };\n\n log(`检查${beta ? \" beta\" : \"\"}最新版本 ...`);\n\n let latest: string;\n try {\n latest = (await fetchText(`${BASE_URL}/${channel}`)).trim();\n } catch (err: any) {\n const msg = `无法获取最新版本: ${err?.message ?? String(err)}`;\n if (json) {\n output({ ok: false, error: { code: \"FETCH_FAILED\", message: msg } });\n process.exit(1);\n }\n process.stderr.write(`\\x1b[31m[update] ERROR:\\x1b[0m ${msg}\\n`);\n process.exit(1);\n }\n\n const current = PLUGIN_VERSION;\n\n if (!force && current === latest) {\n log(`\\x1b[32m已是最新${beta ? \" beta\" : \"\"}版本 v${current}\\x1b[0m`);\n output({ ok: true, current, latest, channel, updated: false });\n return;\n }\n\n if (force) {\n log(`\\x1b[36m强制更新: v${current} → v${latest}\\x1b[0m`);\n } else {\n log(`\\x1b[36m发现新版本: v${current} → v${latest},开始更新 ...\\x1b[0m`);\n }\n\n // 下载 install-core.mjs\n log(\"下载安装脚本 ...\");\n let installScript: string;\n try {\n installScript = await fetchText(`${BASE_URL}/install-core.mjs`);\n } catch (err: any) {\n const msg = `下载安装脚本失败: ${err?.message ?? String(err)}`;\n if (json) {\n output({ ok: false, error: { code: \"DOWNLOAD_FAILED\", message: msg } });\n process.exit(1);\n }\n process.stderr.write(`\\x1b[31m[update] ERROR:\\x1b[0m ${msg}\\n`);\n process.exit(1);\n }\n\n // 写入临时文件\n const tmpScript = join(os.tmpdir(), `openclaw-install-${Date.now()}.mjs`);\n try {\n writeFileSync(tmpScript, installScript, \"utf-8\");\n } catch (err: any) {\n const msg = `写入临时文件失败: ${err?.message ?? String(err)}`;\n if (json) {\n output({ ok: false, error: { code: \"WRITE_FAILED\", message: msg } });\n process.exit(1);\n }\n process.stderr.write(`\\x1b[31m[update] ERROR:\\x1b[0m ${msg}\\n`);\n process.exit(1);\n }\n\n const stateDir = ctx.stateDir ?? resolveStateDir();\n\n // 执行安装脚本(同步,保证日志有序输出)\n const result = spawnSync(\n process.execPath,\n [tmpScript, \"--version\", latest, \"--state-dir\", stateDir],\n { stdio: \"inherit\" },\n );\n\n try {\n unlinkSync(tmpScript);\n } catch {\n // 清理失败不影响结果\n }\n\n if (result.error) {\n const msg = `安装脚本执行失败: ${result.error.message}`;\n if (json) {\n output({ ok: false, error: { code: \"SPAWN_FAILED\", message: msg } });\n } else {\n process.stderr.write(`\\x1b[31m[update] ERROR:\\x1b[0m ${msg}\\n`);\n }\n process.exit(1);\n }\n\n if (result.status !== 0) {\n if (json) {\n output({\n ok: false,\n error: {\n code: \"INSTALL_FAILED\",\n message: `安装脚本退出码: ${result.status}`,\n },\n });\n }\n process.exit(result.status ?? 1);\n }\n\n if (json) {\n output({ ok: true, current, latest, channel, updated: true });\n }\n}\n\nexport function registerUpdate(ntf: CliCommand, ctx: CliContext): void {\n ntf\n .command(\"update\")\n .description(\"检查并更新插件到最新版本,更新后自动重启\")\n .option(\"--json\", \"以 JSON 格式输出结果(供脚本调用)\")\n .option(\"--force\", \"强制重新安装当前最新版本,即使版本号相同\")\n .option(\"--beta\", \"安装最新 beta 版本\")\n .action((opts: { json?: boolean; force?: boolean; beta?: boolean }) => {\n return runUpdate(ctx, opts);\n });\n}\n","import type { CliCommand, CliContext } from \"./helpers.js\";\nimport { registerAuthCli } from \"./auth.js\";\nimport { registerNtfSearch } from \"./ntf-search.js\";\nimport { registerNtfSummary } from \"./ntf-summary.js\";\nimport { registerNtfStats } from \"./ntf-stats.js\";\nimport { registerNtfSync } from \"./ntf-sync.js\";\nimport { registerNtfMonitor } from \"./ntf-monitor.js\";\nimport { registerLightSend } from \"./light-send.js\";\nimport { registerLightSetupTools } from \"./light-setup-tools.js\";\nimport { registerTunnelStatus } from \"./tunnel-status.js\";\nimport { registerNtfStoragePath } from \"./ntf-storage-path.js\";\nimport { registerLogSearch } from \"./log-search.js\";\nimport { registerEnvCli } from \"./env.js\";\nimport { registerDoctor } from \"./doctor.js\";\nimport { registerRecList } from \"./rec-list.js\";\nimport { registerRecStatus } from \"./rec-status.js\";\nimport { registerRecStoragePath } from \"./rec-storage-path.js\";\nimport { registerRecSetup } from \"./rec-setup.js\";\nimport { registerUpdate } from \"./update.js\";\nimport { PLUGIN_VERSION } from \"../version.js\";\n\nexport function registerAllCli(\n program: CliCommand,\n ctx: CliContext,\n rootCommandName = \"ntf\",\n): void {\n const ntf = program\n .command(rootCommandName)\n .description(\"手机通知数据管理\")\n .version(PLUGIN_VERSION, \"-v, --version\", \"显示插件版本\");\n\n // openclaw ntf auth ...\n registerAuthCli(ntf);\n\n // openclaw ntf search / stats / sync / monitor ...\n registerNtfSearch(ntf, ctx);\n registerNtfSummary(ntf, ctx);\n registerNtfStats(ntf, ctx);\n registerNtfSync(ntf, ctx);\n registerNtfMonitor(ntf, ctx);\n\n // openclaw ntf light send / setup-tools ...\n const light = ntf.command(\"light\").description(\"灯效管理\");\n registerLightSend(light);\n registerLightSetupTools(light);\n\n // openclaw ntf storage-path\n registerNtfStoragePath(ntf, ctx);\n\n // openclaw ntf log <keyword>\n registerLogSearch(ntf, ctx);\n\n // openclaw ntf tunnel-status\n registerTunnelStatus(ntf, ctx);\n\n // openclaw ntf env show / switch\n registerEnvCli(ntf);\n\n // openclaw ntf doctor\n registerDoctor(ntf, ctx);\n\n // openclaw ntf rec list / status / storage-path / setup\n const rec = ntf.command(\"rec\").description(\"录音管理\");\n registerRecList(rec, ctx);\n registerRecStatus(rec, ctx);\n registerRecStoragePath(rec, ctx);\n registerRecSetup(rec, ctx);\n\n // openclaw ntf update\n registerUpdate(ntf, ctx);\n}\n","import type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport { requireApiKey } from \"../auth/credentials.js\";\nimport { LIGHT_RULE_TOOL_NAMES } from \"../light-rules/names.js\";\nimport type { Logger } from \"../logger.js\";\nimport { MAX_LIGHT_SEGMENTS } from \"../light/protocol.js\";\nimport { assertAncsRepeatTimes, normalizeRepeatTimes } from \"../light/repeat.js\";\nimport { sendLightEffect } from \"../light/sender.js\";\nimport { validateSegments } from \"../light/validators.js\";\nimport type { LightControlInput } from \"../types.js\";\n\nconst lightControlParameters = {\n type: \"object\",\n required: [\"segments\", \"reason\"],\n additionalProperties: false,\n properties: {\n segments: {\n type: \"array\",\n description: \"灯效段序列,1–12 段,按顺序播放\",\n minItems: 1,\n maxItems: MAX_LIGHT_SEGMENTS,\n items: {\n type: \"object\",\n required: [\"mode\", \"duration_s\"],\n additionalProperties: false,\n properties: {\n mode: {\n type: \"string\",\n enum: [\"wave\", \"breath\", \"strobe\", \"steady\", \"color_flow\", \"pixel_frame\"],\n description:\n \"灯效模式:wave 波浪(单色跑马,前景色+可选底色)/ breath 呼吸 / strobe 频闪 / steady 常亮 / \" +\n \"color_flow 流光(调色板沿圆周流动,1~2 个颜色锚点插值;**不是彩虹**,无法生成 7 色彩虹波浪)/ \" +\n \"pixel_frame 逐组像素帧。\" +\n \"易错对照:用户说\\\"红色/蓝色波浪\\\"等单一颜色波浪 → 必须用 wave,不要用 color_flow;\" +\n \"用户说\\\"彩虹/七彩/rainbow\\\" → 固件不支持真正的 7 色彩虹,需告知限制并给出近似方案(双锚点 color_flow 或多段 wave 轮播),\" +\n \"禁止静默用 color_flow 单锚点冒充彩虹。\",\n },\n duration_s: {\n type: \"number\",\n minimum: 0,\n description:\n \"本段持续时长(秒),0 表示无限时长。推荐离散值:0.5/1/2/3/5/6/8/16/24/32/48,建议单段 ≤8s 省电\",\n },\n brightness: {\n type: \"number\",\n minimum: 0,\n maximum: 255,\n description:\n \"前景亮度 0–255。非 pixel_frame 模式必填;brightness=0 仅 steady 模式有效(显式灭灯)\",\n },\n color: {\n type: \"object\",\n required: [\"r\", \"g\", \"b\"],\n additionalProperties: false,\n properties: {\n r: { type: \"number\", minimum: 0, maximum: 255 },\n g: { type: \"number\", minimum: 0, maximum: 255 },\n b: { type: \"number\", minimum: 0, maximum: 255 },\n },\n description:\n \"前景色 RGB。非 pixel_frame 模式必填;color_flow 下作为第一颜色锚点,至少 color/background 其一非零\",\n },\n interval_ms: {\n type: \"number\",\n minimum: 0,\n description:\n \"步进间隔(ms),wave/strobe/color_flow 有效,默认 200。量化档位:50/100/200/300/500/600/800/1600/2400/3200/4800\",\n },\n direction: {\n type: \"string\",\n enum: [\"ltr\", \"rtl\"],\n description: \"波浪/流光方向,wave/color_flow 有效,默认 ltr\",\n },\n window: {\n type: \"number\",\n enum: [1, 2, 3],\n description:\n \"wave:窗口灯数,默认 2;color_flow:调色板平移步幅(速度)\",\n },\n breath_timing: {\n type: \"object\",\n additionalProperties: false,\n properties: {\n rise_ms: {\n type: \"number\",\n minimum: 0,\n description:\n \"上升时间(ms),量化到 1040/1560/2080/2600/3100/4160\",\n },\n hold_ms: {\n type: \"number\",\n minimum: 0,\n description: \"保持最高亮度时间(ms),支持 0ms\",\n },\n fall_ms: {\n type: \"number\",\n minimum: 0,\n description:\n \"下降时间(ms),量化到 1040/1560/2080/2600/3100/4160\",\n },\n off_ms: {\n type: \"number\",\n minimum: 0,\n description: \"熄灭时间(ms),支持 0ms\",\n },\n },\n description:\n \"呼吸四段时间,仅 breath 有效;rise/fall 量化档位:1040/1560/2080/2600/3100/4160,hold/off 额外支持 0ms\",\n },\n background: {\n type: \"object\",\n required: [\"r\", \"g\", \"b\", \"brightness\"],\n additionalProperties: false,\n properties: {\n r: { type: \"number\", minimum: 0, maximum: 255 },\n g: { type: \"number\", minimum: 0, maximum: 255 },\n b: { type: \"number\", minimum: 0, maximum: 255 },\n brightness: {\n type: \"number\",\n minimum: 0,\n maximum: 255,\n description: \"底色亮度,量化档位:0/32/64/96/128/192/255\",\n },\n },\n description:\n \"底色 RGB + 亮度,wave 有效为底色层;color_flow 有效为第二颜色锚点(与前景色插值生成多色调色板)\",\n },\n pixels: {\n type: \"array\",\n minItems: 1,\n maxItems: 7,\n items: {\n type: \"object\",\n required: [\"index\", \"color\", \"brightness\"],\n additionalProperties: false,\n properties: {\n index: {\n type: \"number\",\n minimum: 0,\n maximum: 6,\n description: \"LED 组索引,0–6\",\n },\n color: {\n type: \"object\",\n required: [\"r\", \"g\", \"b\"],\n additionalProperties: false,\n properties: {\n r: { type: \"number\", minimum: 0, maximum: 255 },\n g: { type: \"number\", minimum: 0, maximum: 255 },\n b: { type: \"number\", minimum: 0, maximum: 255 },\n },\n description: \"该像素的 RGB\",\n },\n brightness: {\n type: \"number\",\n minimum: 0,\n maximum: 255,\n description: \"该像素亮度 0–255;0 会编码为像素熄灭\",\n },\n },\n },\n description:\n \"仅 pixel_frame 有效:播放前先清 7 组,再按此列表写入 (Idx,R,G,B,Br)\",\n },\n },\n },\n },\n reason: {\n type: \"string\",\n description:\n \"结合对话上下文,简要说明为什么要亮灯(例如:用户心情低落想要温暖氛围、庆祝生日、提醒喝水等)。\" +\n \"这个字段帮助记录每次亮灯的意图和动机。\",\n },\n title: {\n type: \"string\",\n description:\n \"对本次亮灯的简短标题/摘要(例如:温暖氛围、生日庆祝、喝水提醒)。不填时默认回退到 reason。\",\n },\n repeat: {\n type: \"boolean\",\n description:\n \"兼容旧参数。true = 无限循环,false/不填 = 一轮;若同时提供 repeat_times,则以后者为准\",\n },\n repeat_times: {\n type: \"number\",\n minimum: 0,\n description:\n \"整条组合重复次数:0 = 无限循环,1 = 播放一轮。当前 ANCS 路径不支持 N>=2\",\n },\n },\n} as const;\n\nexport function registerLightControlTool(\n api: OpenClawPluginApi,\n logger: Logger,\n): void {\n api.registerTool({\n name: \"light_control\",\n label: \"Light Control\",\n description:\n \"立即控制硬件灯效(一次性执行,不会创建或保存通知触发规则),支持 1–12 段顺序灯效,每段独立参数(6 种模式:波浪/呼吸/频闪/常亮/流光/逐组像素帧)。\" +\n \"Tool 内部自动量化为嵌入式协议定义的离散档位,并按模式精简为变长 ANCS 控制序列,通过 HTTP 接口下发灯效指令。\" +\n '当用户说\"开灯\"、\"换个灯效\"、\"把灯调成红色\"、\"营造氛围\"、\"测试/预览灯效\"等与当前即时灯光控制相关的表达时调用。' +\n `如果用户说\"收到某类通知/消息时亮灯/闪灯/变灯效\",那是持久灯效规则,改用 ${LIGHT_RULE_TOOL_NAMES.create} 或 ${LIGHT_RULE_TOOL_NAMES.update}。`,\n parameters: lightControlParameters,\n async execute(_toolCallId: string, params: unknown) {\n let apiKey: string;\n try {\n apiKey = requireApiKey();\n } catch (e: any) {\n return {\n content: [{ type: \"text\" as const, text: e.message }],\n details: { ok: false, error: { code: \"AUTH_REQUIRED\", message: e.message } },\n };\n }\n\n const { segments, title, reason, repeat, repeat_times } = params as LightControlInput;\n const validation = validateSegments(segments);\n if (!validation.valid) {\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify(validation.errors) }],\n details: {\n ok: false,\n error: { code: \"VALIDATION_FAILED\", details: validation.errors },\n },\n };\n }\n\n let repeatTimes: number;\n try {\n repeatTimes = normalizeRepeatTimes({ repeat, repeat_times });\n assertAncsRepeatTimes(repeatTimes);\n } catch (error: any) {\n return {\n content: [{ type: \"text\" as const, text: error?.message ?? String(error) }],\n details: {\n ok: false,\n error: { code: \"VALIDATION_FAILED\", message: error?.message ?? String(error) },\n },\n };\n }\n\n logger.info(`Light control title: ${title ?? \"\"}, reason: ${reason}`);\n for (const warning of validation.warnings) {\n logger.warn(\n `Light control validation warning [${warning.code}] ${warning.field}: ${warning.message}`,\n );\n }\n const result = await sendLightEffect(\n apiKey,\n validation.segments,\n logger,\n { repeat_times: repeatTimes },\n reason,\n title,\n );\n\n if (!result.ok) {\n logger.warn(\n `Light control HTTP request failed: ${result.status} ${result.error}`,\n );\n } else {\n logger.info(`Light control sent, bizUniqueId=${result.bizUniqueId}`);\n }\n\n const details =\n validation.warnings.length > 0 ? { ...result, warnings: validation.warnings } : result;\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify(details) }],\n details,\n };\n },\n } as any);\n}\n","import { readFileSync } from \"node:fs\";\nimport type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport { resolveConfigPath } from \"../host.js\";\nimport type { Logger } from \"../logger.js\";\nimport { createAppNameMapProvider } from \"../notification/app-name-map.js\";\nimport {\n NotificationStorage,\n resolveNotificationStorageDir,\n} from \"../notification/storage.js\";\nimport {\n RecordingStorage,\n resolveRecordingStorageDir,\n} from \"../recording/index.js\";\nimport {\n createTunnelService,\n type RelayTunnelService,\n} from \"../tunnel/service.js\";\nimport type { PluginConfig } from \"../types.js\";\nimport { getEnvUrls } from \"../env.js\";\nimport { trimToUndefined } from \"./shared.js\";\n\ninterface LightRuleContext {\n workspaceDir?: string;\n stateDir?: string;\n}\n\ninterface StorageLifecycleDeps {\n api: OpenClawPluginApi;\n config: PluginConfig;\n logger: Logger;\n lightRuleCtx: LightRuleContext;\n setStorage: (storage: NotificationStorage | null) => void;\n setRecordingStorage: (storage: RecordingStorage | null) => void;\n /**\n * 在 storage service 完成 start 之后触发,此时 lightRuleCtx 已被回填。\n * 用于让 LightRuleRegistry 等下游组件在拿到真实 workspaceDir 后重新加载状态。\n */\n onStorageReady?: () => void;\n}\n\nexport function registerStorageLifecycle(\n deps: StorageLifecycleDeps,\n): void {\n const {\n api,\n config,\n logger,\n lightRuleCtx,\n setStorage,\n setRecordingStorage,\n onStorageReady,\n } = deps;\n\n let storage: NotificationStorage | null = null;\n let recordingStorage: RecordingStorage | null = null;\n let appNameMapProvider: ReturnType<typeof createAppNameMapProvider> | null = null;\n\n api.registerService({\n id: \"notification-storage\",\n async start(ctx) {\n const storageDir = resolveNotificationStorageDir(ctx, logger);\n\n appNameMapProvider = createAppNameMapProvider({\n stateDir: ctx.stateDir,\n logger,\n });\n await appNameMapProvider.start();\n\n const resolveDisplayName = appNameMapProvider.resolveDisplayName.bind(appNameMapProvider);\n storage = new NotificationStorage(storageDir, config, logger, resolveDisplayName);\n await storage.init();\n setStorage(storage);\n logger.info(`通知存储服务已启动: ${storageDir}`);\n\n const recDir = resolveRecordingStorageDir(ctx, logger);\n recordingStorage = new RecordingStorage(recDir, logger);\n await recordingStorage.init();\n setRecordingStorage(recordingStorage);\n logger.info(`录音存储服务已启动: ${recDir}`);\n\n lightRuleCtx.workspaceDir = ctx.workspaceDir;\n if (ctx.stateDir) {\n lightRuleCtx.stateDir = ctx.stateDir;\n }\n\n onStorageReady?.();\n },\n async stop() {\n await storage?.close();\n storage = null;\n setStorage(null);\n\n await recordingStorage?.close();\n recordingStorage = null;\n setRecordingStorage(null);\n\n appNameMapProvider?.stop();\n appNameMapProvider = null;\n logger.info(\"通知/录音存储服务已停止\");\n },\n });\n}\n\nfunction readHostGatewayConfig(params: {\n stateDir?: string;\n logger: Pick<Logger, \"warn\">;\n}) {\n const configPath = params.stateDir\n ? resolveConfigPath(params.stateDir)\n : undefined;\n\n let configData: any;\n\n if (configPath) {\n try {\n configData = JSON.parse(readFileSync(configPath, \"utf-8\"));\n } catch (err: any) {\n if (err?.code !== \"ENOENT\") {\n params.logger.warn(\n `Relay tunnel: 无法读取 gateway 鉴权配置 (${configPath})`,\n );\n }\n }\n }\n\n return configData;\n}\n\nfunction resolveLocalGatewayAuth(params: {\n stateDir?: string;\n logger: Pick<Logger, \"warn\">;\n}): {\n gatewayAuthMode?: \"token\" | \"password\";\n gatewayToken?: string;\n gatewayPassword?: string;\n} {\n const envGatewayToken =\n trimToUndefined(process.env.OPENCLAW_GATEWAY_TOKEN) ??\n trimToUndefined(process.env.QCLAW_GATEWAY_TOKEN);\n const envGatewayPassword =\n trimToUndefined(process.env.OPENCLAW_GATEWAY_PASSWORD) ??\n trimToUndefined(process.env.QCLAW_GATEWAY_PASSWORD);\n\n const configData = readHostGatewayConfig(params);\n let configGatewayAuthMode: \"token\" | \"password\" | undefined;\n const rawGatewayAuthMode = trimToUndefined(configData?.gateway?.auth?.mode);\n if (rawGatewayAuthMode === \"token\" || rawGatewayAuthMode === \"password\") {\n configGatewayAuthMode = rawGatewayAuthMode;\n }\n const configGatewayToken = trimToUndefined(configData?.gateway?.auth?.token);\n const configGatewayPassword = trimToUndefined(configData?.gateway?.auth?.password);\n\n return {\n gatewayAuthMode: configGatewayAuthMode,\n gatewayToken: envGatewayToken ?? configGatewayToken,\n gatewayPassword: envGatewayPassword ?? configGatewayPassword,\n };\n}\n\nfunction resolveExclusiveTunnelHint(params: {\n stateDir?: string;\n logger: Pick<Logger, \"warn\">;\n}): string | undefined {\n const configData = readHostGatewayConfig(params);\n const tailscaleMode = trimToUndefined(configData?.gateway?.tailscale?.mode);\n if (tailscaleMode) {\n return `gateway.tailscale.mode=${tailscaleMode}`;\n }\n\n const remoteUrl = trimToUndefined(configData?.gateway?.remote?.url);\n if (remoteUrl && isExternalGatewayRemoteUrl(remoteUrl)) {\n return `gateway.remote.url=${remoteUrl}`;\n }\n\n return undefined;\n}\n\nfunction isExternalGatewayRemoteUrl(rawUrl: string): boolean {\n let host: string;\n try {\n host = new URL(rawUrl).hostname.toLowerCase();\n } catch {\n return false;\n }\n\n if (host === \"localhost\" || host === \"::1\" || host === \"[::1]\") {\n return false;\n }\n\n return !/^127(?:\\.\\d{1,3}){0,3}$/.test(host);\n}\n\ninterface RelayTunnelDeps {\n api: OpenClawPluginApi;\n config: PluginConfig;\n logger: Logger;\n openclawDir?: string;\n}\n\nexport function registerRelayTunnelLifecycle(\n deps: RelayTunnelDeps,\n): RelayTunnelService | null {\n const {\n api,\n config,\n logger,\n openclawDir,\n } = deps;\n\n const tunnelUrl = getEnvUrls().relayTunnelUrl;\n if (!tunnelUrl) {\n return null;\n }\n\n const exclusiveTunnelHint = resolveExclusiveTunnelHint({\n stateDir: openclawDir,\n logger,\n });\n if (exclusiveTunnelHint) {\n logger.info(\n `Relay tunnel: detected ${exclusiveTunnelHint} in host gateway config, skipping relay startup to keep ingress mutually exclusive`,\n );\n return null;\n }\n\n const gatewayPort =\n process.env.OPENCLAW_GATEWAY_PORT ??\n process.env.QCLAW_GATEWAY_PORT ??\n \"18789\";\n const { gatewayAuthMode, gatewayToken, gatewayPassword } =\n resolveLocalGatewayAuth({\n stateDir: openclawDir,\n logger,\n });\n\n const tunnelService = createTunnelService({\n tunnelUrl,\n heartbeatSec: config.relay?.heartbeatSec,\n reconnectBackoffMs: config.relay?.reconnectBackoffMs,\n gatewayBaseUrl: `http://localhost:${gatewayPort}`,\n gatewayAuthMode,\n gatewayToken,\n gatewayPassword,\n logger,\n });\n\n api.registerService(tunnelService);\n logger.info(\"Relay tunnel 服务已注册\");\n return tunnelService;\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { loadApiKey, watchCredentials } from \"../auth/credentials.js\";\nimport { getEnvUrls } from \"../env.js\";\n\nconst PLUGIN_STATE_DIR = \"phone-notifications\";\nconst CACHE_FILE = \"app-name-map.json\";\n\n/** 包名→应用名映射 API 地址(默认随环境变化;可用 APP_NAME_MAP_URL 覆盖;需鉴权) */\nconst BUILTIN_APP_NAME_MAP_URL = getEnvUrls().appNameMapUrl;\nconst APP_NAME_MAP_URL =\n (typeof process.env.APP_NAME_MAP_URL === \"string\" && process.env.APP_NAME_MAP_URL.trim()\n ? process.env.APP_NAME_MAP_URL.trim()\n : undefined) ?? BUILTIN_APP_NAME_MAP_URL;\n/** 映射刷新间隔(小时) */\nconst APP_NAME_MAP_REFRESH_HOURS = 12;\n\ninterface Logger {\n info: (message: string) => void;\n warn: (message: string) => void;\n}\n\nfunction isRecordOfStrings(v: unknown): v is Record<string, string> {\n if (v === null || typeof v !== \"object\") return false;\n for (const val of Object.values(v)) if (typeof val !== \"string\") return false;\n return true;\n}\n\n/** API 返回的单项 */\ninterface AppPackageItem {\n appName: string;\n packageName: string;\n iconUrl?: string | null;\n platform?: string | null;\n jumpUrl?: string | null;\n urlParams?: string | null;\n description?: string | null;\n}\n\n/** API 响应格式 */\ninterface AppNameMapApiResponse {\n success?: boolean;\n code?: string;\n message?: string;\n data?: AppPackageItem[];\n}\n\nfunction isAppNameMapApiResponse(v: unknown): v is AppNameMapApiResponse {\n if (v === null || typeof v !== \"object\") return false;\n const o = v as Record<string, unknown>;\n return Array.isArray(o.data) && o.data.every(\n (item: unknown) =>\n item !== null &&\n typeof item === \"object\" &&\n typeof (item as AppPackageItem).packageName === \"string\" &&\n typeof (item as AppPackageItem).appName === \"string\"\n );\n}\n\nfunction getCachePath(stateDir: string): string {\n return join(stateDir, \"plugins\", PLUGIN_STATE_DIR, CACHE_FILE);\n}\n\nexport interface AppNameMapProvider {\n /** 解析包名为显示名(未命中时拉取一次再返回,保证当前落库即有值) */\n resolveDisplayName(packageName: string): Promise<string>;\n start(): Promise<void>;\n stop(): void;\n}\n\nexport function createAppNameMapProvider(opts: {\n stateDir: string;\n logger: Logger;\n}): AppNameMapProvider {\n const { stateDir, logger } = opts;\n const url = APP_NAME_MAP_URL;\n const refreshHours = APP_NAME_MAP_REFRESH_HOURS;\n\n const map = new Map<string, string>();\n let refreshTimer: ReturnType<typeof setInterval> | null = null;\n let stopWatching: (() => void) | null = null;\n let inFlightFetch: Promise<void> | null = null;\n\n function loadFromDisk(): void {\n const path = getCachePath(stateDir);\n if (!existsSync(path)) return;\n try {\n const raw = JSON.parse(readFileSync(path, \"utf-8\"));\n if (!isRecordOfStrings(raw)) return;\n map.clear();\n for (const [k, v] of Object.entries(raw)) map.set(k, v);\n logger.info(`[app-name-map] loaded ${map.size} entries from cache: ${path}`);\n } catch {\n /* ignore */\n }\n }\n\n async function fetchFromServer(): Promise<void> {\n const apiKey = loadApiKey();\n if (!url) {\n logger.warn(\"[app-name-map] APP_NAME_MAP_URL is empty, skip refresh\");\n return;\n }\n if (!apiKey) {\n logger.info(\"[app-name-map] api key missing, skip refresh\");\n return;\n }\n\n const rawApiKey = apiKey.startsWith(\"Bearer \")\n ? apiKey.slice(\"Bearer \".length)\n : apiKey;\n try {\n const res = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\", \"X-Api-Key-Id\": rawApiKey },\n body: JSON.stringify({\n platform: \"\"\n })\n });\n if (!res.ok) {\n logger.warn(`[app-name-map] refresh failed: HTTP ${res.status} ${res.statusText}`);\n return;\n }\n const body = await res.json() as unknown;\n if (!isAppNameMapApiResponse(body) || !body.success || !body.data?.length) {\n logger.warn(\"[app-name-map] refresh failed: unexpected response shape or empty data\");\n return;\n }\n map.clear();\n for (const item of body.data) {\n if (item.packageName && item.appName) map.set(item.packageName, item.appName);\n }\n if (map.size === 0) {\n logger.warn(\"[app-name-map] refresh succeeded but got 0 entries\");\n return;\n }\n const dir = join(stateDir, \"plugins\", PLUGIN_STATE_DIR);\n\n mkdirSync(dir, { recursive: true });\n const cachePath = getCachePath(stateDir);\n writeFileSync(cachePath, JSON.stringify(Object.fromEntries(map), null, 2), \"utf-8\");\n logger.info(`[app-name-map] refreshed ${map.size} entries from server and saved: ${cachePath}`);\n } catch (e) {\n const message = e instanceof Error ? e.message : String(e);\n logger.warn(`[app-name-map] refresh error: ${message}`);\n }\n }\n\n async function ensureOneFetch(): Promise<void> {\n if (inFlightFetch) return inFlightFetch;\n inFlightFetch = fetchFromServer().finally(() => {\n inFlightFetch = null;\n });\n return inFlightFetch;\n }\n\n return {\n async resolveDisplayName(packageName: string): Promise<string> {\n // 临时策略:仅使用内存/磁盘中已有的映射,缺少时不主动触发拉取\n if (map.has(packageName)) return map.get(packageName)!;\n return packageName;\n // 如需在缺少应用名时触发一次拉取再返回,可恢复为:\n // if (!url || !loadApiKey()) return packageName;\n // await ensureOneFetch();\n // return map.get(packageName) ?? packageName;\n },\n\n async start(): Promise<void> {\n loadFromDisk();\n await fetchFromServer();\n\n if (!url) return;\n\n if (refreshHours > 0) {\n const ms = refreshHours * 60 * 60 * 1000;\n refreshTimer = setInterval(() => fetchFromServer().catch(() => { }), ms);\n }\n stopWatching = watchCredentials(() => fetchFromServer().catch(() => { }));\n },\n\n stop(): void {\n stopWatching?.();\n stopWatching = null;\n if (refreshTimer) {\n clearInterval(refreshTimer);\n refreshTimer = null;\n }\n map.clear();\n },\n };\n}\n","import {\n accessSync,\n mkdirSync,\n appendFileSync,\n readdirSync,\n readFileSync,\n writeFileSync,\n existsSync,\n rmSync,\n constants,\n} from \"node:fs\";\nimport { createHash } from \"node:crypto\";\nimport { join } from \"node:path\";\nimport type { PluginConfig, RawNotification } from \"../types.js\";\nimport { normalizeFeishuFields } from \"./feishu-normalize.js\";\n\ninterface Logger {\n info: (message: string) => void;\n warn: (message: string) => void;\n}\n\nexport type NotificationConversationType = \"private\" | \"group\";\n\nexport interface StorageContext {\n stateDir: string;\n workspaceDir?: string;\n}\n\n/** Stored notification entry (JSON format, append-only) */\nexport interface StoredNotification {\n /** 包名 */\n appName: string;\n /** 应用显示名(由映射补全),缺省时与 appName 一致 */\n appDisplayName?: string;\n title: string;\n content: string;\n /** ISO 8601 with timezone, e.g. \"2026-03-02T08:30:00+08:00\" */\n timestamp: string;\n /**\n * 结构化发送人。当前主要用于飞书消息:\n * iOS 通知里 title 通常是发送人,subtitle 用来区分群聊名。\n */\n senderName?: string;\n /** 结构化会话类型。当前主要用于飞书消息区分群聊/私聊。 */\n conversationType?: NotificationConversationType;\n /** 结构化会话名。当前主要用于飞书群聊名(通常来自 subtitle)。 */\n conversationName?: string;\n}\n\nconst NOTIFICATION_DIR_NAME = \"notifications\";\nconst ID_INDEX_DIR_NAME = \".ids\";\nconst CONTENT_KEY_INDEX_DIR_NAME = \".keys\";\n\nexport interface NotificationIngestResult {\n received: number;\n ingested: number;\n dedupedById: number;\n dedupedByContent: number;\n invalid: number;\n /**\n * 本次 ingest 实际新写入的条目(去重 / 非法之后的产物)。\n * 用于后续事件驱动链路(如 light-rule agent 评估)拿到本次新增的通知列表,\n * 不需要重新读盘。\n */\n inserted: StoredNotification[];\n}\n\ntype WriteOutcome =\n | { kind: \"ingested\"; entry: StoredNotification }\n | { kind: \"dedupedById\" }\n | { kind: \"dedupedByContent\" }\n | { kind: \"invalid\" };\n\nexport function getStateFallbackNotificationDir(stateDir: string): string {\n return join(stateDir, \"plugins\", \"phone-notifications\", NOTIFICATION_DIR_NAME);\n}\n\nfunction computeLagMs(timestamp: string | undefined): number | null {\n if (!timestamp) return null;\n const t = new Date(timestamp).getTime();\n if (Number.isNaN(t)) return null;\n return Date.now() - t;\n}\n\nfunction buildFallbackContent(n: RawNotification): string {\n const body = n.body?.trim();\n if (body) {\n return body;\n }\n\n const fallback: string[] = [];\n if (n.category) {\n fallback.push(`category:${n.category}`);\n }\n if (n.metadata && Object.keys(n.metadata).length > 0) {\n fallback.push(`metadata:${JSON.stringify(n.metadata)}`);\n }\n return fallback.join(\" ; \") || \"-\";\n}\n\nfunction ensureWritableDirectory(dir: string): boolean {\n try {\n mkdirSync(dir, { recursive: true });\n accessSync(dir, constants.R_OK | constants.W_OK);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function resolveNotificationStorageDir(\n ctx: StorageContext,\n logger: Pick<Logger, \"info\" | \"warn\">,\n): string {\n // 优先使用 stateDir(插件私有稳定路径),避免通知随 workspace 切换而分散\n const stateNotifDir = getStateFallbackNotificationDir(ctx.stateDir);\n\n if (ensureWritableDirectory(stateNotifDir)) {\n logger.info(`通知将写入 stateDir 路径: ${stateNotifDir}`);\n return stateNotifDir;\n }\n\n // stateDir 不可用时回退到 workspaceDir\n if (ctx.workspaceDir) {\n const workspaceDir = join(ctx.workspaceDir, NOTIFICATION_DIR_NAME);\n if (ensureWritableDirectory(workspaceDir)) {\n logger.warn(\n `stateDir 不可用,通知已回退到 workspace 路径: ${workspaceDir}`,\n );\n return workspaceDir;\n }\n }\n\n throw new Error(`通知存储目录不可用: ${stateNotifDir}`);\n}\n\n/** 包名 → 应用显示名(异步,未命中时内部可拉取后返回);不提供则落库仅用 appName */\nexport type ResolveDisplayName = (packageName: string) => Promise<string>;\n\nexport class NotificationStorage {\n private dir: string;\n private idIndexDir: string;\n private contentKeyIndexDir: string;\n private idCache = new Map<string, Set<string>>();\n private contentKeyCache = new Map<string, Set<string>>();\n private dateWriteChains = new Map<string, Promise<void>>();\n private resolveDisplayName: ResolveDisplayName | undefined;\n\n constructor(\n dir: string,\n private config: PluginConfig,\n private logger: Logger,\n resolveDisplayName?: ResolveDisplayName,\n ) {\n this.dir = dir;\n this.idIndexDir = join(dir, ID_INDEX_DIR_NAME);\n this.contentKeyIndexDir = join(dir, CONTENT_KEY_INDEX_DIR_NAME);\n this.resolveDisplayName = resolveDisplayName;\n }\n\n async init() {\n mkdirSync(this.dir, { recursive: true });\n mkdirSync(this.idIndexDir, { recursive: true });\n rmSync(this.contentKeyIndexDir, { recursive: true, force: true });\n mkdirSync(this.contentKeyIndexDir, { recursive: true });\n }\n\n async ingest(\n items: RawNotification[],\n ingestId?: string,\n ): Promise<NotificationIngestResult> {\n const result: NotificationIngestResult = {\n received: items.length,\n ingested: 0,\n dedupedById: 0,\n dedupedByContent: 0,\n invalid: 0,\n inserted: [],\n };\n\n const traceTag = ingestId ? `[${ingestId}]` : \"\";\n for (const n of items) {\n const outcome = await this.writeNotification(n);\n const lagMs = computeLagMs(n.timestamp);\n const lagPart = lagMs === null ? \"lag=?\" : `lag=${lagMs}ms`;\n this.logger.info(\n `ingest${traceTag}: app=${n.app ?? \"Unknown\"} id=${n.id ?? \"-\"} ts=${n.timestamp} ${lagPart} outcome=${outcome.kind}`,\n );\n switch (outcome.kind) {\n case \"ingested\":\n result.ingested += 1;\n result.inserted.push(outcome.entry);\n break;\n case \"dedupedById\":\n result.dedupedById += 1;\n break;\n case \"dedupedByContent\":\n result.dedupedByContent += 1;\n break;\n case \"invalid\":\n result.invalid += 1;\n break;\n }\n }\n this.prune();\n return result;\n }\n\n private async writeNotification(n: RawNotification): Promise<WriteOutcome> {\n const ts = new Date(n.timestamp);\n if (Number.isNaN(ts.getTime())) {\n this.logger.warn(`忽略非法 timestamp 的通知: ${n.id}`);\n return { kind: \"invalid\" };\n }\n\n const dateKey = this.formatDate(ts);\n const filePath = join(this.dir, `${dateKey}.json`);\n const normalizedId = typeof n.id === \"string\" ? n.id.trim() : \"\";\n const entry = this.buildStoredNotification(n);\n\n return this.withDateWriteLock(dateKey, async () => {\n if (normalizedId && this.hasNotificationId(dateKey, normalizedId)) {\n return { kind: \"dedupedById\" };\n }\n\n if (this.hasNotificationContentKey(dateKey, filePath, entry)) {\n return { kind: \"dedupedByContent\" };\n }\n\n const appDisplayName = this.resolveDisplayName\n ? await this.resolveDisplayName(entry.appName)\n : entry.appName;\n\n const storedEntry: StoredNotification = {\n ...entry,\n appDisplayName,\n };\n\n const arr = this.readStoredNotifications(filePath);\n arr.push(storedEntry);\n writeFileSync(filePath, JSON.stringify(arr, null, 2), \"utf-8\");\n\n if (normalizedId) {\n this.recordNotificationId(dateKey, normalizedId);\n }\n this.recordNotificationContentKey(dateKey, filePath, storedEntry);\n return { kind: \"ingested\", entry: storedEntry };\n });\n }\n\n private buildStoredNotification(n: RawNotification): StoredNotification {\n const appName = typeof n.app === \"string\" && n.app ? n.app : \"Unknown\";\n const feishu = normalizeFeishuFields(n);\n if (feishu) {\n return {\n appName,\n title: feishu.title,\n content: feishu.content || buildFallbackContent(n),\n timestamp: n.timestamp,\n ...feishu.structured,\n };\n }\n return {\n appName,\n title: typeof n.title === \"string\" ? n.title : \"\",\n content: buildFallbackContent(n),\n timestamp: n.timestamp,\n };\n }\n\n private formatDate(d: Date): string {\n const year = d.getFullYear();\n const month = String(d.getMonth() + 1).padStart(2, \"0\");\n const day = String(d.getDate()).padStart(2, \"0\");\n return `${year}-${month}-${day}`;\n }\n\n private getIdIndexPath(dateKey: string): string {\n return join(this.idIndexDir, `${dateKey}.ids`);\n }\n\n private getIdSet(dateKey: string): Set<string> {\n const cached = this.idCache.get(dateKey);\n if (cached) {\n return cached;\n }\n\n const idPath = this.getIdIndexPath(dateKey);\n const ids = new Set<string>();\n if (existsSync(idPath)) {\n const lines = readFileSync(idPath, \"utf-8\").split(/\\r?\\n/);\n for (const line of lines) {\n const id = line.trim();\n if (id) {\n ids.add(id);\n }\n }\n }\n\n this.idCache.set(dateKey, ids);\n return ids;\n }\n\n private hasNotificationId(dateKey: string, id: string): boolean {\n return this.getIdSet(dateKey).has(id);\n }\n\n private getContentKeyIndexPath(dateKey: string): string {\n return join(this.contentKeyIndexDir, `${dateKey}.keys`);\n }\n\n private getContentKeySet(dateKey: string, filePath: string): Set<string> {\n const cached = this.contentKeyCache.get(dateKey);\n if (cached) {\n return cached;\n }\n\n const keyPath = this.getContentKeyIndexPath(dateKey);\n const keys = new Set<string>();\n\n if (existsSync(filePath)) {\n for (const item of this.readStoredNotifications(filePath)) {\n keys.add(this.buildNotificationContentKey(item));\n }\n }\n\n if (keys.size > 0) {\n writeFileSync(keyPath, `${Array.from(keys).join(\"\\n\")}\\n`, \"utf-8\");\n } else if (existsSync(keyPath)) {\n rmSync(keyPath, { force: true });\n }\n\n this.contentKeyCache.set(dateKey, keys);\n return keys;\n }\n\n private hasNotificationContentKey(\n dateKey: string,\n filePath: string,\n entry: Pick<StoredNotification, \"appName\" | \"title\" | \"content\" | \"timestamp\">,\n ): boolean {\n return this.getContentKeySet(dateKey, filePath).has(\n this.buildNotificationContentKey(entry),\n );\n }\n\n private recordNotificationId(dateKey: string, id: string) {\n const ids = this.getIdSet(dateKey);\n if (ids.has(id)) {\n return;\n }\n\n appendFileSync(this.getIdIndexPath(dateKey), `${id}\\n`, \"utf-8\");\n ids.add(id);\n }\n\n private recordNotificationContentKey(\n dateKey: string,\n filePath: string,\n entry: Pick<StoredNotification, \"appName\" | \"title\" | \"content\" | \"timestamp\">,\n ) {\n const keys = this.getContentKeySet(dateKey, filePath);\n const key = this.buildNotificationContentKey(entry);\n\n if (keys.has(key)) {\n return;\n }\n\n appendFileSync(this.getContentKeyIndexPath(dateKey), `${key}\\n`, \"utf-8\");\n keys.add(key);\n }\n\n private buildNotificationContentKey(\n entry: Pick<StoredNotification, \"appName\" | \"title\" | \"content\" | \"timestamp\">,\n ): string {\n return createHash(\"sha256\")\n .update(entry.appName)\n .update(\"\\x1f\")\n .update(entry.title)\n .update(\"\\x1f\")\n .update(entry.content)\n .update(\"\\x1f\")\n .update(entry.timestamp)\n .digest(\"hex\");\n }\n\n private readStoredNotifications(filePath: string): StoredNotification[] {\n if (!existsSync(filePath)) {\n return [];\n }\n\n try {\n const parsed = JSON.parse(readFileSync(filePath, \"utf-8\"));\n return Array.isArray(parsed) ? parsed : [];\n } catch {\n return [];\n }\n }\n\n private async withDateWriteLock<T>(\n dateKey: string,\n task: () => Promise<T>,\n ): Promise<T> {\n const previous = this.dateWriteChains.get(dateKey) ?? Promise.resolve();\n let release!: () => void;\n const current = new Promise<void>((resolve) => {\n release = resolve;\n });\n const chain = previous.then(() => current);\n this.dateWriteChains.set(dateKey, chain);\n\n await previous;\n try {\n return await task();\n } finally {\n release();\n if (this.dateWriteChains.get(dateKey) === chain) {\n this.dateWriteChains.delete(dateKey);\n }\n }\n }\n\n private prune() {\n const retentionDays = this.config.retentionDays;\n if (retentionDays === undefined) {\n return;\n }\n\n const cutoffMs = Date.now() - retentionDays * 24 * 60 * 60 * 1000;\n const cutoffDate = this.formatDate(new Date(cutoffMs));\n\n this.pruneDataFiles(cutoffDate);\n this.pruneIdIndex(cutoffDate);\n this.pruneContentKeyIndex(cutoffDate);\n }\n\n /** Remove expired .json, legacy .md files, and legacy date directories */\n private pruneDataFiles(cutoffDate: string) {\n const dateFilePattern = /^(\\d{4}-\\d{2}-\\d{2})\\.(json|md)$/;\n const dateDirPattern = /^\\d{4}-\\d{2}-\\d{2}$/;\n\n try {\n for (const entry of readdirSync(this.dir, { withFileTypes: true })) {\n if (entry.isFile()) {\n const match = dateFilePattern.exec(entry.name);\n if (match && match[1] < cutoffDate) {\n rmSync(join(this.dir, entry.name), { force: true });\n }\n } else if (entry.isDirectory() && dateDirPattern.test(entry.name) && entry.name < cutoffDate) {\n rmSync(join(this.dir, entry.name), { recursive: true, force: true });\n }\n }\n } catch {\n // ignore\n }\n }\n\n /** Remove expired .ids index files */\n private pruneIdIndex(cutoffDate: string) {\n try {\n for (const entry of readdirSync(this.idIndexDir, { withFileTypes: true })) {\n if (!entry.isFile()) continue;\n const match = /^(\\d{4}-\\d{2}-\\d{2})\\.ids$/.exec(entry.name);\n if (match && match[1] < cutoffDate) {\n rmSync(join(this.idIndexDir, entry.name), { force: true });\n this.idCache.delete(match[1]);\n }\n }\n } catch {\n // ignore\n }\n }\n\n private pruneContentKeyIndex(cutoffDate: string) {\n try {\n for (const entry of readdirSync(this.contentKeyIndexDir, { withFileTypes: true })) {\n if (!entry.isFile()) continue;\n const match = /^(\\d{4}-\\d{2}-\\d{2})\\.keys$/.exec(entry.name);\n if (match && match[1] < cutoffDate) {\n rmSync(join(this.contentKeyIndexDir, entry.name), { force: true });\n this.contentKeyCache.delete(match[1]);\n }\n }\n } catch {\n // ignore\n }\n }\n\n async close() {\n this.idCache.clear();\n this.contentKeyCache.clear();\n this.dateWriteChains.clear();\n }\n}\n","import type { RawNotification } from \"../types.js\";\nimport type { NotificationConversationType } from \"./storage.js\";\n\nexport interface FeishuStructuredFields {\n senderName?: string;\n conversationType?: NotificationConversationType;\n conversationName?: string;\n}\n\nexport interface FeishuNormalizedNotification {\n title: string;\n content: string;\n structured: FeishuStructuredFields;\n}\n\nfunction normalizeOptionalText(value: unknown): string | undefined {\n if (typeof value !== \"string\") {\n return undefined;\n }\n const trimmed = value.trim();\n return trimmed ? trimmed : undefined;\n}\n\nfunction isFeishuApp(appName: string): boolean {\n const normalized = appName.trim().toLowerCase();\n if (!normalized) {\n return false;\n }\n return (\n normalized === \"飞书\"\n || normalized === \"feishu\"\n || normalized === \"lark\"\n || normalized === \"com.ss.android.lark\"\n || normalized === \"com.bytedance.ee.lark\"\n || normalized === \"com.larksuite.suite\"\n || normalized.includes(\"feishu\")\n || normalized.includes(\"lark\")\n || normalized.includes(\"飞书\")\n );\n}\n\nfunction isFeishuAppLabel(text: string): boolean {\n const t = text.trim().toLowerCase();\n return t === \"飞书\" || t === \"lark\" || t === \"feishu\";\n}\n\nfunction extractColonSender(body: string): string | undefined {\n if (!body) return undefined;\n const candidates = [body.indexOf(\":\"), body.indexOf(\":\")].filter((i) => i > 0);\n if (candidates.length === 0) return undefined;\n const idx = Math.min(...candidates);\n const senderName = body.slice(0, idx).trim();\n return senderName || undefined;\n}\n\nfunction findMetadataTextByKey(\n value: unknown,\n targetKey: string,\n depth = 0,\n): { found: boolean; value?: string } {\n if (!value || typeof value !== \"object\" || depth > 4) {\n return { found: false };\n }\n\n if (Array.isArray(value)) {\n for (const item of value) {\n const match = findMetadataTextByKey(item, targetKey, depth + 1);\n if (match.found) {\n return match;\n }\n }\n return { found: false };\n }\n\n for (const [key, child] of Object.entries(value as Record<string, unknown>)) {\n if (key.trim().toLowerCase() === targetKey) {\n return { found: true, value: normalizeOptionalText(child) };\n }\n }\n\n for (const child of Object.values(value as Record<string, unknown>)) {\n const match = findMetadataTextByKey(child, targetKey, depth + 1);\n if (match.found) {\n return match;\n }\n }\n\n return { found: false };\n}\n\nfunction deriveStructured(n: RawNotification): FeishuStructuredFields {\n const subtitle = findMetadataTextByKey(n.metadata, \"subtitle\");\n\n // iOS 路径:通知元数据带 subtitle key(群聊为群名,私聊为空)。\n if (subtitle.found) {\n const senderName = normalizeOptionalText(n.title);\n const structured: FeishuStructuredFields = {\n conversationType: subtitle.value ? \"group\" : \"private\",\n };\n if (senderName) {\n structured.senderName = senderName;\n }\n if (subtitle.value) {\n structured.conversationName = subtitle.value;\n }\n return structured;\n }\n\n // Android 路径:title 退化为 app 名(如 \"飞书\"),实际发送人在 body 里以 \"name: content\" 形式出现。\n const rawTitle = typeof n.title === \"string\" ? n.title : \"\";\n if (isFeishuAppLabel(rawTitle)) {\n const senderName = extractColonSender(n.body ?? \"\");\n if (senderName) {\n return {\n senderName,\n conversationType: \"private\",\n };\n }\n }\n\n return {};\n}\n\nfunction buildTitle(n: RawNotification, structured: FeishuStructuredFields): string {\n if (structured.conversationType === \"group\" && structured.conversationName) {\n return structured.conversationName;\n }\n // Android 私聊 title 是 app 名,用 body 解析出的 senderName 顶上去,跟 iOS 对齐。\n if (structured.conversationType === \"private\" && structured.senderName) {\n return structured.senderName;\n }\n return typeof n.title === \"string\" ? n.title : \"\";\n}\n\nfunction buildContent(n: RawNotification, structured: FeishuStructuredFields): string {\n const body = n.body?.trim();\n\n if (structured.conversationType === \"group\" && structured.senderName && body) {\n const half = `${structured.senderName}:`;\n const full = `${structured.senderName}:`;\n return body.startsWith(half) || body.startsWith(full)\n ? body\n : `${structured.senderName}: ${body}`;\n }\n\n if (structured.conversationType === \"private\" && structured.senderName && body) {\n const half = `${structured.senderName}:`;\n const full = `${structured.senderName}:`;\n if (body.startsWith(half)) return body.slice(half.length).trimStart();\n if (body.startsWith(full)) return body.slice(full.length).trimStart();\n return body;\n }\n\n return body ?? \"\";\n}\n\nexport function normalizeFeishuFields(\n n: RawNotification,\n): FeishuNormalizedNotification | undefined {\n const appName = typeof n.app === \"string\" ? n.app : \"\";\n if (!isFeishuApp(appName)) {\n return undefined;\n }\n\n const structured = deriveStructured(n);\n\n // Feishu 通知但任何规则都没命中:让 caller 走默认归一化路径,避免与非 Feishu 通知行为分裂。\n if (\n structured.senderName === undefined\n && structured.conversationType === undefined\n && structured.conversationName === undefined\n ) {\n return undefined;\n }\n\n return {\n title: buildTitle(n, structured),\n content: buildContent(n, structured),\n structured,\n };\n}\n","/**\n * 录音本地存储管理(§5.2)\n *\n * 目录结构:\n * <storageDir>/recordings/\n * ├── audio/ # 原始音频 + 打点文件\n * │ ├── 2026-03-23_14-32.ogg\n * │ └── 2026-03-23_14-32.srt\n * ├── transcript-data/ # 转写 JSON(主存储)\n * │ └── 2026-03-23_14-32.json\n * ├── transcripts/ # 转写文本\n * │ └── 2026-03-23_14-32_与王总沟通产品方向.md\n * ├── summaries/ # 转写摘要\n * │ └── 2026-03-23_14-32.md\n * └── index.json # 元数据索引\n */\n\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n writeFileSync,\n rmSync,\n readdirSync,\n statSync,\n} from \"node:fs\";\nimport { join, basename } from \"node:path\";\nimport type {\n RecordingMetadata,\n RecordingTransferStatus,\n} from \"../types.js\";\nimport { transition } from \"./state-machine.js\";\nimport type { Logger } from \"../logger.js\";\nimport {\n buildTranscriptDataFilename as buildTranscriptDataJsonFilename,\n buildTranscriptDocument,\n extractTranscriptSummaryFromDocument,\n extractTranscriptTextFromDocument,\n extractTranscriptTitleFromDocument,\n parseTranscriptDocument,\n} from \"./transcript-document.js\";\n\n/**\n * 从 OSS URL 中提取音频文件扩展名(含点号,如 \".ogg\")\n * 默认返回 \".ogg\"(小硬件录音为 Opus/OGG 格式)\n */\nfunction extractAudioExt(ossUrl: string): string {\n try {\n const pathname = new URL(ossUrl).pathname;\n const m = pathname.match(/(\\.[a-z0-9]+)(?:\\?|$)/i);\n if (m) return m[1].toLowerCase();\n } catch {\n const m = ossUrl.match(/(\\.[a-z0-9]+)(?:\\?|$)/i);\n if (m) return m[1].toLowerCase();\n }\n return \".ogg\"; // 硬件默认录音格式(Opus/OGG)\n}\n\n// ─── Types ───\n\n/** 持久化到 index.json 的单条录音记录 */\nexport interface RecordingIndexEntry {\n /** 录音 ID,基于文件名(如 \"2026-03-23_14-32\") */\n id: string;\n /** 原始元数据 */\n metadata: RecordingMetadata;\n /** 当前插件侧状态 */\n status: RecordingTransferStatus;\n /** 本地音频文件相对路径 */\n audioFile?: string;\n /** 本地打点文件相对路径 */\n srtFile?: string;\n /** 本地转写文件相对路径 */\n transcriptFile?: string;\n /** 本地转写 JSON 文件相对路径 */\n transcriptDataFile?: string;\n /** 本地摘要文件相对路径 */\n summaryFile?: string;\n /** 转写标题 */\n title?: string;\n /** 最近一次失败原因(同步失败 / 转写失败) */\n lastError?: string;\n /** 入库时间 ISO 8601 */\n ingestedAt: string;\n /** 最后更新时间 ISO 8601 */\n updatedAt: string;\n}\n\n/** 录音存储索引(整个 index.json) */\ninterface RecordingIndex {\n recordings: RecordingIndexEntry[];\n}\n\nexport interface RecordingStorageContext {\n stateDir: string;\n workspaceDir?: string;\n}\n\n// ─── Constants ───\n\nconst RECORDINGS_DIR = \"recordings\";\nconst AUDIO_DIR = \"audio\";\nconst TRANSCRIPT_DATA_DIR = \"transcript-data\";\nconst TRANSCRIPTS_DIR = \"transcripts\";\nconst SUMMARIES_DIR = \"summaries\";\nconst INDEX_FILE = \"index.json\";\n\nfunction stripMarkdownFence(markdown: string): string {\n return markdown.replace(/\\r\\n/g, \"\\n\");\n}\n\nfunction deriveTitleFromTranscriptPath(\n transcriptFile: string | undefined,\n recordingId: string,\n): string | undefined {\n if (!transcriptFile) return undefined;\n const name = basename(transcriptFile, \".md\");\n const prefix = `${recordingId}_`;\n if (name.startsWith(prefix)) {\n const derived = name.slice(prefix.length).trim();\n return derived || undefined;\n }\n return undefined;\n}\n\nfunction extractTranscriptContent(markdown: string): string {\n const normalized = stripMarkdownFence(markdown);\n const firstDivider = normalized.indexOf(\"\\n---\\n\");\n let body = firstDivider >= 0\n ? normalized.slice(firstDivider + \"\\n---\\n\".length)\n : normalized;\n\n if (body.startsWith(\"\\n\")) {\n body = body.slice(1);\n }\n\n if (body.startsWith(\"### 关键点\")) {\n const secondDivider = body.indexOf(\"\\n---\\n\");\n if (secondDivider >= 0) {\n body = body.slice(secondDivider + \"\\n---\\n\".length);\n if (body.startsWith(\"\\n\")) {\n body = body.slice(1);\n }\n }\n }\n\n const lines = body\n .split(\"\\n\")\n .filter((line) => !/^\\*\\*\\[关键点 .+\\]\\*\\*$/.test(line.trim()))\n .filter((line) => !/^- \\*\\*\\[关键点 .+\\]\\*\\*$/.test(line.trim()));\n\n return lines.join(\"\\n\").replace(/\\n{3,}/g, \"\\n\\n\").trim();\n}\n\n// ─── Public Functions ───\n\n/**\n * 解析录音存储根目录(复用通知同级的 stateDir 路径)\n */\nexport function resolveRecordingStorageDir(\n ctx: RecordingStorageContext,\n logger: Pick<Logger, \"info\" | \"warn\">,\n): string {\n const stateRecDir = join(\n ctx.stateDir,\n \"plugins\",\n \"phone-notifications\",\n RECORDINGS_DIR,\n );\n\n try {\n mkdirSync(stateRecDir, { recursive: true });\n logger.info(`录音将写入 stateDir 路径: ${stateRecDir}`);\n return stateRecDir;\n } catch {\n // fallback\n }\n\n if (ctx.workspaceDir) {\n const wsRecDir = join(ctx.workspaceDir, RECORDINGS_DIR);\n try {\n mkdirSync(wsRecDir, { recursive: true });\n logger.warn(`stateDir 不可用,录音已回退到 workspace 路径: ${wsRecDir}`);\n return wsRecDir;\n } catch {\n // fallthrough\n }\n }\n\n throw new Error(`录音存储目录不可用: ${stateRecDir}`);\n}\n\n// ─── RecordingStorage Class ───\n\nexport class RecordingStorage {\n private readonly dir: string;\n private readonly audioDir: string;\n private readonly transcriptDataDir: string;\n private readonly transcriptsDir: string;\n private readonly summariesDir: string;\n private readonly indexPath: string;\n private index: RecordingIndex = { recordings: [] };\n\n constructor(\n dir: string,\n private readonly logger: Logger,\n ) {\n this.dir = dir;\n this.audioDir = join(dir, AUDIO_DIR);\n this.transcriptDataDir = join(dir, TRANSCRIPT_DATA_DIR);\n this.transcriptsDir = join(dir, TRANSCRIPTS_DIR);\n this.summariesDir = join(dir, SUMMARIES_DIR);\n this.indexPath = join(dir, INDEX_FILE);\n }\n\n /** 初始化目录结构并加载索引 */\n async init(): Promise<void> {\n mkdirSync(this.audioDir, { recursive: true });\n mkdirSync(this.transcriptDataDir, { recursive: true });\n mkdirSync(this.transcriptsDir, { recursive: true });\n mkdirSync(this.summariesDir, { recursive: true });\n this.loadIndex();\n this.logger.info(\n `录音存储已初始化: ${this.dir}(共 ${this.index.recordings.length} 条记录)`,\n );\n }\n\n /** 获取音频目录路径 */\n getAudioDir(): string {\n return this.audioDir;\n }\n\n /** 获取转写 JSON 目录路径 */\n getTranscriptDataDir(): string {\n return this.transcriptDataDir;\n }\n\n /** 获取转写目录路径 */\n getTranscriptsDir(): string {\n return this.transcriptsDir;\n }\n\n /** 获取摘要目录路径 */\n getSummariesDir(): string {\n return this.summariesDir;\n }\n\n // ─── 录音入库 ───\n\n /**\n * 收到 recordings.sync 后,将元数据写入索引。\n * 如果同 ID 录音已存在则更新,否则新建。\n * 返回录音 ID。\n */\n ingest(recordingId: string, metadata: RecordingMetadata): string {\n const id = recordingId;\n const existing = this.findById(id);\n\n if (existing) {\n const sameAudioUrl = existing.metadata.oss_audio_url === metadata.oss_audio_url;\n const canPreserveSyncState =\n sameAudioUrl\n && !!existing.audioFile\n && existing.status !== \"syncing_openclaw\"\n && existing.status !== \"sync_failed\";\n\n if (canPreserveSyncState) {\n existing.metadata = metadata;\n existing.updatedAt = new Date().toISOString();\n this.saveIndex();\n this.logger.info(\n `录音元数据已更新: ${id}(同音频,保留状态 ${existing.status})`,\n );\n return id;\n }\n\n // 更新已有记录(覆盖上传/本地文件缺失场景)\n if (existing.transcriptDataFile) {\n rmSync(join(this.dir, existing.transcriptDataFile), { force: true });\n }\n if (existing.transcriptFile) {\n rmSync(join(this.dir, existing.transcriptFile), { force: true });\n }\n if (existing.summaryFile) {\n rmSync(join(this.dir, existing.summaryFile), { force: true });\n }\n existing.metadata = metadata;\n existing.status = \"syncing_openclaw\";\n existing.transcriptDataFile = undefined;\n existing.transcriptFile = undefined;\n existing.summaryFile = undefined;\n existing.title = undefined;\n existing.lastError = undefined;\n existing.updatedAt = new Date().toISOString();\n this.logger.info(`录音元数据已更新: ${id}`);\n } else {\n const entry: RecordingIndexEntry = {\n id,\n metadata,\n status: \"syncing_openclaw\",\n ingestedAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n };\n this.index.recordings.push(entry);\n this.logger.info(`录音元数据已入库: ${id}`);\n }\n\n this.saveIndex();\n return id;\n }\n\n // ─── 状态管理 ───\n\n /**\n * 更新录音传输状态(严格状态机校验)\n */\n updateStatus(\n recordingId: string,\n newStatus: RecordingTransferStatus,\n ): RecordingIndexEntry {\n const entry = this.findById(recordingId);\n if (!entry) {\n throw new Error(`录音不存在: ${recordingId}`);\n }\n\n const validatedStatus = transition(entry.status, newStatus);\n entry.status = validatedStatus;\n entry.updatedAt = new Date().toISOString();\n this.saveIndex();\n this.logger.info(`录音状态更新: ${recordingId} → ${newStatus}`);\n return entry;\n }\n\n /**\n * 记录本地音频文件已下载\n */\n setAudioFile(recordingId: string, filename: string): void {\n const entry = this.findById(recordingId);\n if (!entry) return;\n entry.audioFile = `${AUDIO_DIR}/${filename}`;\n entry.updatedAt = new Date().toISOString();\n this.saveIndex();\n }\n\n /**\n * 记录本地打点文件已下载\n */\n setSrtFile(recordingId: string, filename: string): void {\n const entry = this.findById(recordingId);\n if (!entry) return;\n entry.srtFile = `${AUDIO_DIR}/${filename}`;\n entry.updatedAt = new Date().toISOString();\n this.saveIndex();\n }\n\n /**\n * 记录转写 JSON 文件路径\n */\n setTranscriptDataFile(recordingId: string, filename: string): void {\n const entry = this.findById(recordingId);\n if (!entry) return;\n const nextTranscriptDataFile = `${TRANSCRIPT_DATA_DIR}/${filename}`;\n if (entry.transcriptDataFile && entry.transcriptDataFile !== nextTranscriptDataFile) {\n rmSync(join(this.dir, entry.transcriptDataFile), { force: true });\n }\n entry.transcriptDataFile = nextTranscriptDataFile;\n entry.updatedAt = new Date().toISOString();\n this.saveIndex();\n }\n\n /**\n * 记录转写文件路径\n */\n setTranscriptFile(recordingId: string, filename: string): void {\n const entry = this.findById(recordingId);\n if (!entry) return;\n const nextTranscriptFile = `${TRANSCRIPTS_DIR}/${filename}`;\n if (entry.transcriptFile && entry.transcriptFile !== nextTranscriptFile) {\n rmSync(join(this.dir, entry.transcriptFile), { force: true });\n }\n entry.transcriptFile = nextTranscriptFile;\n entry.updatedAt = new Date().toISOString();\n this.saveIndex();\n }\n\n /**\n * 记录摘要文件路径\n */\n setSummaryFile(recordingId: string, filename: string): void {\n const entry = this.findById(recordingId);\n if (!entry) return;\n const nextSummaryFile = `${SUMMARIES_DIR}/${filename}`;\n if (entry.summaryFile && entry.summaryFile !== nextSummaryFile) {\n rmSync(join(this.dir, entry.summaryFile), { force: true });\n }\n entry.summaryFile = nextSummaryFile;\n entry.updatedAt = new Date().toISOString();\n this.saveIndex();\n }\n\n /**\n * 记录转写标题\n */\n setTitle(recordingId: string, title?: string): void {\n const entry = this.findById(recordingId);\n if (!entry) return;\n entry.title = title?.trim() || undefined;\n entry.updatedAt = new Date().toISOString();\n this.saveIndex();\n }\n\n /**\n * 记录最近一次失败原因;传 undefined 表示清除错误\n */\n setLastError(recordingId: string, error?: string): void {\n const entry = this.findById(recordingId);\n if (!entry) return;\n entry.lastError = error?.trim() || undefined;\n entry.updatedAt = new Date().toISOString();\n this.saveIndex();\n }\n\n /**\n * 读取摘要文本\n */\n readSummary(recordingId: string): string | undefined {\n const entry = this.findById(recordingId);\n if (!entry) return undefined;\n\n if (entry.summaryFile) {\n const summary = this.readRelativeTextFile(entry.summaryFile);\n if (summary?.trim()) {\n return summary.trim();\n }\n }\n\n const transcriptDoc = entry.transcriptDataFile\n ? this.readRelativeTranscriptDocument(entry.transcriptDataFile)\n : undefined;\n return extractTranscriptSummaryFromDocument(transcriptDoc);\n }\n\n /**\n * 优先从 transcript JSON 中读取正文,旧数据回退读取 Markdown。\n */\n readTranscript(recordingId: string): string | undefined {\n const entry = this.findById(recordingId);\n if (!entry) return undefined;\n\n if (entry.transcriptDataFile) {\n const transcriptDoc = this.readRelativeTranscriptDocument(entry.transcriptDataFile);\n const transcriptFromJson = extractTranscriptTextFromDocument(transcriptDoc);\n if (transcriptFromJson !== undefined) {\n return transcriptFromJson;\n }\n }\n\n if (!entry.transcriptFile) return undefined;\n const markdown = this.readRelativeTextFile(entry.transcriptFile);\n if (!markdown) return undefined;\n const transcript = extractTranscriptContent(markdown);\n return transcript || undefined;\n }\n\n /**\n * 读取结构化 transcript JSON。\n */\n readTranscriptDocument(recordingId: string) {\n const entry = this.findById(recordingId);\n if (!entry?.transcriptDataFile) {\n return undefined;\n }\n return this.readRelativeTranscriptDocument(entry.transcriptDataFile);\n }\n\n // ─── 查询 ───\n\n findById(id: string): RecordingIndexEntry | undefined {\n return this.index.recordings.find((r) => r.id === id);\n }\n\n listAll(): RecordingIndexEntry[] {\n return [...this.index.recordings].sort(\n (a, b) => b.metadata.created_at.localeCompare(a.metadata.created_at),\n );\n }\n\n listByStatus(status: RecordingTransferStatus): RecordingIndexEntry[] {\n return this.listAll().filter((r) => r.status === status);\n }\n\n rename(recordingId: string, name: string): RecordingIndexEntry {\n const entry = this.findById(recordingId);\n if (!entry) {\n throw new Error(`录音不存在: ${recordingId}`);\n }\n\n entry.metadata = {\n ...entry.metadata,\n name,\n };\n entry.updatedAt = new Date().toISOString();\n this.saveIndex();\n this.logger.info(`录音名称已更新: ${recordingId} → ${name}`);\n return entry;\n }\n\n // ─── 删除 ───\n\n /**\n * 删除录音及其本地文件(约束 R-4 安全删除)\n *\n * @param opts.localOnly 仅删除本地文件(音频/打点/转写),保留索引条目。\n * App 端\"仅删除本地\"时使用此模式,插件侧保留元数据记录。\n * 默认 false — 完整删除(文件 + 索引)。\n */\n delete(\n recordingId: string,\n opts?: { localOnly?: boolean },\n ): boolean {\n const entry = this.findById(recordingId);\n if (!entry) return false;\n\n // 删除本地文件\n if (entry.audioFile) {\n const audioPath = join(this.dir, entry.audioFile);\n rmSync(audioPath, { force: true });\n }\n if (entry.srtFile) {\n const srtPath = join(this.dir, entry.srtFile);\n rmSync(srtPath, { force: true });\n }\n if (entry.transcriptDataFile) {\n const transcriptDataPath = join(this.dir, entry.transcriptDataFile);\n rmSync(transcriptDataPath, { force: true });\n }\n if (entry.transcriptFile) {\n const transcriptPath = join(this.dir, entry.transcriptFile);\n rmSync(transcriptPath, { force: true });\n }\n if (entry.summaryFile) {\n const summaryPath = join(this.dir, entry.summaryFile);\n rmSync(summaryPath, { force: true });\n }\n\n if (opts?.localOnly) {\n // 保留索引条目,清除文件引用\n entry.audioFile = undefined;\n entry.srtFile = undefined;\n entry.transcriptDataFile = undefined;\n entry.transcriptFile = undefined;\n entry.summaryFile = undefined;\n entry.updatedAt = new Date().toISOString();\n this.saveIndex();\n this.logger.info(`录音本地文件已删除(保留索引): ${recordingId}`);\n } else {\n // 从索引中移除\n this.index.recordings = this.index.recordings.filter(\n (r) => r.id !== recordingId,\n );\n this.saveIndex();\n this.logger.info(`录音已完整删除: ${recordingId}`);\n }\n return true;\n }\n\n // ─── Helpers ───\n\n /**\n * 生成音频文件名。扩展名从 OSS URL 中提取,未提供时默认 .ogg(硬件录音格式)\n */\n buildAudioFilename(recordingId: string, ossUrl?: string): string {\n const ext = ossUrl ? extractAudioExt(ossUrl) : \".ogg\";\n return `${recordingId}${ext}`;\n }\n\n /**\n * 生成打点文件名\n */\n buildSrtFilename(recordingId: string): string {\n return `${recordingId}.srt`;\n }\n\n /**\n * 生成转写 JSON 文件名\n */\n buildTranscriptDataFilename(recordingId: string): string {\n return buildTranscriptDataJsonFilename(recordingId);\n }\n\n /**\n * 生成转写文件名\n * @param summary 摘要标题(≤ 10 字)\n */\n buildTranscriptFilename(recordingId: string, summary: string): string {\n // 清理文件名中的非法字符\n const safeSummary = summary\n .replace(/[/\\\\:*?\"<>|]/g, \"\")\n .trim()\n .slice(0, 20);\n return safeSummary\n ? `${recordingId}_${safeSummary}.md`\n : `${recordingId}.md`;\n }\n\n /**\n * 生成摘要文件名\n */\n buildSummaryFilename(recordingId: string): string {\n return `${recordingId}.md`;\n }\n\n /**\n * 获取音频文件的绝对路径。ossUrl 用于推断文件扩展名\n */\n getAudioFilePath(recordingId: string, ossUrl?: string): string {\n return join(this.audioDir, this.buildAudioFilename(recordingId, ossUrl));\n }\n\n /**\n * 获取打点文件的绝对路径\n */\n getSrtFilePath(recordingId: string): string {\n return join(this.audioDir, this.buildSrtFilename(recordingId));\n }\n\n /**\n * 获取转写 JSON 文件的绝对路径\n */\n getTranscriptDataFilePath(recordingId: string): string {\n return join(this.transcriptDataDir, this.buildTranscriptDataFilename(recordingId));\n }\n\n /**\n * 获取摘要文件的绝对路径\n */\n getSummaryFilePath(recordingId: string): string {\n return join(this.summariesDir, this.buildSummaryFilename(recordingId));\n }\n\n // ─── Persistence ───\n\n private loadIndex(): void {\n if (!existsSync(this.indexPath)) {\n this.index = { recordings: [] };\n return;\n }\n try {\n const raw = JSON.parse(readFileSync(this.indexPath, \"utf-8\"));\n if (raw && Array.isArray(raw.recordings)) {\n let needsRewrite = false;\n const normalized = raw.recordings\n .filter((entry: unknown) => entry && typeof entry === \"object\")\n .map((entry: any) => {\n const compacted: RecordingIndexEntry = {\n id: entry.id,\n metadata: entry.metadata,\n status: entry.status,\n ingestedAt: entry.ingestedAt,\n updatedAt: entry.updatedAt,\n };\n if (typeof entry.audioFile === \"string\") compacted.audioFile = entry.audioFile;\n if (typeof entry.srtFile === \"string\") compacted.srtFile = entry.srtFile;\n if (typeof entry.transcriptFile === \"string\") {\n compacted.transcriptFile = entry.transcriptFile;\n }\n let transcriptDoc = typeof entry.transcriptDataFile === \"string\"\n ? this.readRelativeTranscriptDocument(entry.transcriptDataFile)\n : undefined;\n if (typeof entry.transcriptDataFile === \"string\" && transcriptDoc) {\n compacted.transcriptDataFile = entry.transcriptDataFile;\n } else {\n const legacyTranscriptText = typeof entry.transcript === \"string\" && entry.transcript.trim()\n ? entry.transcript.trim()\n : compacted.transcriptFile\n ? extractTranscriptContent(\n this.readRelativeTextFile(compacted.transcriptFile) ?? \"\",\n ) || undefined\n : undefined;\n const legacyTitle = typeof entry.title === \"string\" && entry.title.trim()\n ? entry.title.trim()\n : deriveTitleFromTranscriptPath(compacted.transcriptFile, compacted.id);\n const legacySummary = typeof entry.summary === \"string\" && entry.summary.trim()\n ? entry.summary.trim()\n : undefined;\n\n if (legacyTranscriptText) {\n transcriptDoc = buildTranscriptDocument({\n recordingId: compacted.id,\n generatedAt: compacted.updatedAt,\n source: {\n provider: \"legacy-markdown\",\n },\n title: legacyTitle,\n summary: legacySummary,\n text: legacyTranscriptText,\n segments: [],\n });\n const transcriptDataFilename = this.buildTranscriptDataFilename(compacted.id);\n writeFileSync(\n join(this.transcriptDataDir, transcriptDataFilename),\n JSON.stringify(transcriptDoc, null, 2),\n \"utf-8\",\n );\n compacted.transcriptDataFile = `${TRANSCRIPT_DATA_DIR}/${transcriptDataFilename}`;\n needsRewrite = true;\n }\n }\n\n if (typeof entry.summaryFile === \"string\") {\n compacted.summaryFile = entry.summaryFile;\n } else if (typeof entry.summary === \"string\" && entry.summary.trim()) {\n const summaryFilename = this.buildSummaryFilename(entry.id);\n writeFileSync(\n join(this.summariesDir, summaryFilename),\n entry.summary.trim(),\n \"utf-8\",\n );\n compacted.summaryFile = `${SUMMARIES_DIR}/${summaryFilename}`;\n needsRewrite = true;\n } else {\n const summaryFromDocument = extractTranscriptSummaryFromDocument(transcriptDoc);\n if (summaryFromDocument) {\n const summaryFilename = this.buildSummaryFilename(entry.id);\n writeFileSync(\n join(this.summariesDir, summaryFilename),\n summaryFromDocument,\n \"utf-8\",\n );\n compacted.summaryFile = `${SUMMARIES_DIR}/${summaryFilename}`;\n needsRewrite = true;\n }\n }\n if (typeof entry.title === \"string\" && entry.title.trim()) {\n compacted.title = entry.title.trim();\n } else {\n const titleFromDocument = extractTranscriptTitleFromDocument(transcriptDoc);\n const derivedTitle = titleFromDocument ?? deriveTitleFromTranscriptPath(\n compacted.transcriptFile,\n compacted.id,\n );\n if (derivedTitle) {\n compacted.title = derivedTitle;\n needsRewrite = true;\n }\n }\n if (typeof entry.lastError === \"string\" && entry.lastError.trim()) {\n compacted.lastError = entry.lastError.trim();\n }\n if (compacted.status === \"transcribing\") {\n compacted.status = \"transcribe_failed\";\n compacted.lastError = compacted.lastError\n ?? \"转写任务已中断,请重新发起转写\";\n compacted.updatedAt = new Date().toISOString();\n needsRewrite = true;\n }\n return compacted;\n });\n const hadLargeFields = raw.recordings.some(\n (entry: any) => entry && typeof entry === \"object\" && (\"transcript\" in entry || \"summary\" in entry),\n );\n this.index = { recordings: normalized };\n if (hadLargeFields || needsRewrite) {\n this.saveIndex();\n }\n } else {\n this.index = { recordings: [] };\n }\n } catch {\n this.logger.warn(`录音索引文件损坏,已重建: ${this.indexPath}`);\n this.index = { recordings: [] };\n }\n }\n\n private readRelativeTextFile(relativePath: string): string | undefined {\n try {\n return readFileSync(join(this.dir, relativePath), \"utf-8\");\n } catch {\n return undefined;\n }\n }\n\n private readRelativeTranscriptDocument(relativePath: string) {\n const raw = this.readRelativeTextFile(relativePath);\n if (!raw) {\n return undefined;\n }\n return parseTranscriptDocument(raw);\n }\n\n private saveIndex(): void {\n writeFileSync(\n this.indexPath,\n JSON.stringify(this.index, null, 2),\n \"utf-8\",\n );\n }\n\n async close(): Promise<void> {\n // 当前无需额外清理\n }\n}\n","/**\n * 录音传输状态机(约束 R-3)\n *\n * 状态流转严格不可跳跃:\n * receiving_failed → receiving\n * receiving → pending_oss_upload\n * pending_oss_upload → uploading_oss\n * uploading_oss → oss_uploaded\n * oss_uploaded → syncing_openclaw\n * syncing_openclaw → synced | sync_failed\n * sync_failed → syncing_openclaw\n * synced → transcribing(仅当已配置 ASR)\n * transcribing → transcribed | transcribe_failed\n * transcribe_failed → transcribing\n * transcribed → transcribing(手动强制重新转写)\n */\n\nimport type { RecordingTransferStatus } from \"../types.js\";\n\n/** 合法的状态转换表:from → Set<to> */\nconst VALID_TRANSITIONS: ReadonlyMap<\n RecordingTransferStatus,\n ReadonlySet<RecordingTransferStatus>\n> = new Map<RecordingTransferStatus, ReadonlySet<RecordingTransferStatus>>([\n [\"receiving_failed\", new Set([\"receiving\"])],\n [\"receiving\", new Set([\"pending_oss_upload\"])],\n [\"pending_oss_upload\", new Set([\"uploading_oss\"])],\n [\"uploading_oss\", new Set([\"oss_uploaded\"])],\n [\"oss_uploaded\", new Set([\"syncing_openclaw\"])],\n [\"syncing_openclaw\", new Set([\"synced\", \"sync_failed\"])],\n [\"sync_failed\", new Set([\"syncing_openclaw\"])],\n [\"synced\", new Set([\"transcribing\"])],\n [\"transcribing\", new Set([\"transcribed\", \"transcribe_failed\"])],\n [\"transcribe_failed\", new Set([\"transcribing\"])],\n [\"transcribed\", new Set([\"transcribing\"])],\n]);\n\n/** 插件侧关注的状态:从 syncing_openclaw 开始 */\nexport type PluginSideStatus = Extract<\n RecordingTransferStatus,\n | \"syncing_openclaw\"\n | \"sync_failed\"\n | \"synced\"\n | \"transcribing\"\n | \"transcribe_failed\"\n | \"transcribed\"\n>;\n\n/**\n * 校验状态转换是否合法\n */\nexport function isValidTransition(\n from: RecordingTransferStatus,\n to: RecordingTransferStatus,\n): boolean {\n const allowed = VALID_TRANSITIONS.get(from);\n return allowed ? allowed.has(to) : false;\n}\n\n/**\n * 尝试执行状态转换,非法转换抛出 Error\n */\nexport function transition(\n from: RecordingTransferStatus,\n to: RecordingTransferStatus,\n): RecordingTransferStatus {\n if (!isValidTransition(from, to)) {\n throw new TransitionError(from, to);\n }\n return to;\n}\n\n/**\n * 状态是否为终态(没有后续合法转换)\n */\nexport function isTerminalStatus(status: RecordingTransferStatus): boolean {\n const allowed = VALID_TRANSITIONS.get(status);\n return !allowed || allowed.size === 0;\n}\n\n/**\n * 状态是否允许触发 ASR 转写\n */\nexport function canStartTranscription(status: RecordingTransferStatus): boolean {\n return (\n status === \"synced\"\n || status === \"transcribe_failed\"\n || status === \"transcribed\"\n );\n}\n\n/**\n * 获取当前状态的所有合法后续状态\n */\nexport function getNextStatuses(\n status: RecordingTransferStatus,\n): RecordingTransferStatus[] {\n const allowed = VALID_TRANSITIONS.get(status);\n return allowed ? [...allowed] : [];\n}\n\nexport class TransitionError extends Error {\n constructor(\n public readonly from: RecordingTransferStatus,\n public readonly to: RecordingTransferStatus,\n ) {\n super(`非法状态转换: ${from} → ${to}`);\n this.name = \"TransitionError\";\n }\n}\n","export {\n RecordingStorage,\n resolveRecordingStorageDir,\n type RecordingIndexEntry,\n type RecordingStorageContext,\n} from \"./storage.js\";\n\nexport {\n TRANSCRIPT_DOCUMENT_SCHEMA_VERSION,\n buildTranscriptDataFilename,\n buildTranscriptDocument,\n parseTranscriptDocument,\n extractTranscriptTextFromDocument,\n extractTranscriptSummaryFromDocument,\n extractTranscriptTitleFromDocument,\n extractSourceTextListFromDocument,\n type TranscriptDocument,\n type TranscriptDocumentContentItem,\n type TranscriptDocumentNormalized,\n type TranscriptDocumentSegment,\n type TranscriptDocumentSource,\n} from \"./transcript-document.js\";\n\nexport {\n isValidTransition,\n transition,\n isTerminalStatus,\n canStartTranscription,\n getNextStatuses,\n TransitionError,\n} from \"./state-machine.js\";\n\nexport {\n downloadFile,\n downloadRecordingFiles,\n type DownloadResult,\n type DownloadOptions,\n} from \"./downloader.js\";\n\nexport {\n isAsrConfigured,\n validateAsrConfig,\n initializeAsr,\n transcribeAudio,\n buildTranscriptMarkdown,\n extractSummary,\n runTranscriptionWorkflow,\n type TranscriptionResult,\n type TranscriptSegment,\n} from \"./asr.js\";\n\nexport {\n detectEnvironment,\n selectModelByMemory,\n isModelDownloaded,\n downloadModel,\n findWhisperBinary,\n transcribeWithWhisperLocal,\n getWhisperLocalStatus,\n} from \"./whisper-local.js\";\n\nexport {\n handleRecordingSync,\n triggerTranscription,\n type RecordingStatusEvent,\n type RecordingSyncOptions,\n} from \"./handler.js\";\n","/**\n * OSS 文件下载器(约束 R-6)\n *\n * 从 OSS URL 下载原始音频(mp3)和打点文件(srt)到本地。\n * 支持重试、超时控制、下载进度日志。\n */\n\nimport { createWriteStream, existsSync, mkdirSync, statSync, unlinkSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { pipeline } from \"node:stream/promises\";\nimport { Readable } from \"node:stream\";\nimport type { Logger } from \"../logger.js\";\n\n// ─── Types ───\n\nexport interface DownloadOptions {\n /** 下载超时(毫秒),默认 5 分钟 */\n timeoutMs?: number;\n /** 最大重试次数,默认 3 */\n maxRetries?: number;\n /** 重试间隔基数(毫秒),默认 2000 */\n retryBackoffMs?: number;\n}\n\nexport interface DownloadResult {\n ok: boolean;\n /** 下载的文件大小(字节) */\n sizeBytes?: number;\n /** 耗时(毫秒) */\n elapsedMs?: number;\n /** 错误信息 */\n error?: string;\n}\n\nconst DEFAULT_TIMEOUT_MS = 5 * 60 * 1000; // 5 分钟(最大 ~56MB 文件)\nconst DEFAULT_MAX_RETRIES = 3;\nconst DEFAULT_RETRY_BACKOFF_MS = 2000;\n\n// ─── Public API ───\n\n/**\n * 从 URL 下载文件到本地路径\n */\nexport async function downloadFile(\n url: string,\n destPath: string,\n logger: Logger,\n options?: DownloadOptions,\n): Promise<DownloadResult> {\n const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const maxRetries = options?.maxRetries ?? DEFAULT_MAX_RETRIES;\n const retryBackoffMs = options?.retryBackoffMs ?? DEFAULT_RETRY_BACKOFF_MS;\n\n mkdirSync(dirname(destPath), { recursive: true });\n\n let lastError: string | undefined;\n\n for (let attempt = 1; attempt <= maxRetries; attempt++) {\n const startMs = Date.now();\n try {\n logger.info(\n `[downloader] 开始下载 (attempt ${attempt}/${maxRetries}): ${url}`,\n );\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n\n try {\n const res = await fetch(url, { signal: controller.signal });\n\n if (!res.ok) {\n throw new Error(`HTTP ${res.status} ${res.statusText}`);\n }\n\n if (!res.body) {\n throw new Error(\"响应体为空\");\n }\n\n // 写入文件\n const writeStream = createWriteStream(destPath);\n const readable = Readable.fromWeb(res.body as any);\n await pipeline(readable, writeStream);\n\n const elapsed = Date.now() - startMs;\n const fileSize = existsSync(destPath)\n ? statSync(destPath).size\n : 0;\n\n logger.info(\n `[downloader] 下载完成: ${destPath} (${formatBytes(fileSize)}, ${elapsed}ms)`,\n );\n\n return { ok: true, sizeBytes: fileSize, elapsedMs: elapsed };\n } finally {\n clearTimeout(timer);\n }\n } catch (err: any) {\n lastError = err?.message ?? String(err);\n\n // 清理可能写了一半的文件\n try {\n if (existsSync(destPath)) unlinkSync(destPath);\n } catch {\n // ignore\n }\n\n const isAbort = err?.name === \"AbortError\";\n logger.warn(\n `[downloader] 下载失败 (attempt ${attempt}/${maxRetries}): ${isAbort ? \"超时\" : lastError}`,\n );\n\n if (attempt < maxRetries) {\n const delay = retryBackoffMs * Math.pow(2, attempt - 1);\n logger.info(`[downloader] ${delay}ms 后重试...`);\n await sleep(delay);\n }\n }\n }\n\n return { ok: false, error: lastError ?? \"下载失败\" };\n}\n\n/**\n * 下载录音的音频文件和打点文件\n */\nexport async function downloadRecordingFiles(\n ossAudioUrl: string,\n ossSrtUrl: string | undefined,\n audioDestPath: string,\n srtDestPath: string,\n logger: Logger,\n options?: DownloadOptions,\n): Promise<{\n audio: DownloadResult;\n srt: DownloadResult | null;\n}> {\n // 下载音频(必须)\n const audio = await downloadFile(ossAudioUrl, audioDestPath, logger, options);\n\n // 下载打点文件(可选)\n let srt: DownloadResult | null = null;\n if (ossSrtUrl) {\n srt = await downloadFile(ossSrtUrl, srtDestPath, logger, options);\n if (!srt.ok) {\n // 打点文件下载失败不阻断主流程,仅警告\n logger.warn(`[downloader] 打点文件下载失败(非致命): ${srt.error}`);\n }\n }\n\n return { audio, srt };\n}\n\n// ─── Helpers ───\n\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes}B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","/**\n * 录音同步处理器(§2 阶段 4–5)\n *\n * 统一处理 recordings.sync 请求:\n * 1. 元数据入库\n * 2. 从 OSS 下载音频 + 打点文件\n * 3. 更新状态 → synced\n * 4. 如已配置 ASR → 自动触发转写\n */\n\nimport type {\n RecordingMetadata,\n RecordingSyncResult,\n AsrConfig,\n RecordingTranscriptItem,\n RecordingTransferStatus,\n} from \"../types.js\";\nimport type { Logger } from \"../logger.js\";\nimport { RecordingStorage } from \"./storage.js\";\nimport { downloadRecordingFiles } from \"./downloader.js\";\nimport { isAsrConfigured, runTranscriptionWorkflow } from \"./asr.js\";\nimport { canStartTranscription } from \"./state-machine.js\";\nimport { deleteAccountOssFile } from \"./account-oss.js\";\n\nexport interface RecordingStatusEvent {\n recordingId: string;\n transfer_status: RecordingTransferStatus;\n audioFile?: string;\n srtFile?: string;\n transcriptDataFile?: string;\n transcriptFile?: string;\n transcript?: RecordingTranscriptItem[];\n summary?: string;\n title: string;\n updatedAt: string;\n error?: string;\n}\n\nexport interface RecordingSyncOptions {\n notifyStatus?: (event: RecordingStatusEvent) => void;\n}\n\nfunction emitRecordingStatus(\n recordingId: string,\n storage: RecordingStorage,\n logger: Logger,\n notifyStatus?: RecordingSyncOptions[\"notifyStatus\"],\n error?: string,\n extras?: Pick<RecordingStatusEvent, \"transcript\" | \"summary\" | \"title\">,\n): void {\n if (!notifyStatus) {\n return;\n }\n\n const entry = storage.findById(recordingId);\n if (!entry) {\n return;\n }\n\n const title = extras?.title?.trim()\n || entry.title?.trim()\n || entry.metadata.name?.trim()\n || entry.id;\n const persistedError = entry.lastError?.trim() || undefined;\n\n try {\n notifyStatus({\n recordingId: entry.id,\n transfer_status: entry.status,\n audioFile: entry.audioFile,\n srtFile: entry.srtFile,\n transcriptDataFile: entry.transcriptDataFile,\n transcriptFile: entry.transcriptFile,\n transcript: extras?.transcript,\n summary: extras?.summary,\n title,\n updatedAt: entry.updatedAt,\n error: error ?? persistedError,\n });\n } catch (err: any) {\n logger.error(\n `[recording-status] 状态事件发送失败: ${recordingId}, ${err?.message ?? err}`,\n );\n }\n}\n\nasync function runRecordingSyncInBackground(\n metadata: RecordingMetadata,\n recordingId: string,\n storage: RecordingStorage,\n asrConfig: AsrConfig | undefined,\n logger: Logger,\n options: RecordingSyncOptions,\n): Promise<void> {\n const audioDestPath = storage.getAudioFilePath(\n recordingId,\n metadata.oss_audio_url,\n );\n const srtDestPath = storage.getSrtFilePath(recordingId);\n\n logger.info(\n `[recording-sync] 开始下载录音文件: ${recordingId}, audio=${metadata.oss_audio_url}`,\n );\n\n const downloadResult = await downloadRecordingFiles(\n metadata.oss_audio_url,\n metadata.oss_srt_url,\n audioDestPath,\n srtDestPath,\n logger,\n );\n\n if (!downloadResult.audio.ok) {\n const error = `音频下载失败: ${downloadResult.audio.error}`;\n logger.error(`[recording-sync] ${error}: ${recordingId}`);\n storage.updateStatus(recordingId, \"sync_failed\");\n storage.setLastError(recordingId, error);\n emitRecordingStatus(\n recordingId,\n storage,\n logger,\n options.notifyStatus,\n error,\n );\n return;\n }\n\n storage.setLastError(recordingId, undefined);\n storage.setAudioFile(\n recordingId,\n storage.buildAudioFilename(recordingId, metadata.oss_audio_url),\n );\n if (downloadResult.srt?.ok) {\n storage.setSrtFile(recordingId, storage.buildSrtFilename(recordingId));\n }\n\n storage.updateStatus(recordingId, \"synced\");\n logger.info(`[recording-sync] 录音已同步: ${recordingId}`);\n emitRecordingStatus(recordingId, storage, logger, options.notifyStatus);\n\n if (isAsrConfigured(asrConfig) && canStartTranscription(\"synced\")) {\n await triggerTranscription(\n recordingId,\n storage,\n asrConfig!,\n logger,\n options,\n );\n }\n}\n\n/**\n * 处理 recordings.sync 请求的核心逻辑\n */\nexport async function handleRecordingSync(\n recordingId: string,\n metadata: RecordingMetadata,\n storage: RecordingStorage,\n asrConfig: AsrConfig | undefined,\n logger: Logger,\n options: RecordingSyncOptions = {},\n): Promise<RecordingSyncResult> {\n const existing = storage.findById(recordingId);\n const shouldDownloadAndSync =\n !existing\n || existing.metadata.oss_audio_url !== metadata.oss_audio_url\n || !existing.audioFile\n || existing.status === \"syncing_openclaw\"\n || existing.status === \"sync_failed\";\n\n storage.ingest(recordingId, metadata);\n if (shouldDownloadAndSync) {\n runRecordingSyncInBackground(\n metadata,\n recordingId,\n storage,\n asrConfig,\n logger,\n options,\n ).catch((err) => {\n const error = `录音同步失败: ${err?.message ?? err}`;\n logger.error(`[recording-sync] ${error}: ${recordingId}`);\n const current = storage.findById(recordingId);\n if (current?.status === \"syncing_openclaw\") {\n storage.updateStatus(recordingId, \"sync_failed\");\n }\n storage.setLastError(recordingId, error);\n emitRecordingStatus(\n recordingId,\n storage,\n logger,\n options.notifyStatus,\n error,\n );\n });\n } else {\n logger.info(\n `[recording-sync] 录音已存在且音频未变化,跳过重复下载: ${recordingId}`,\n );\n emitRecordingStatus(recordingId, storage, logger, options.notifyStatus);\n\n const current = storage.findById(recordingId);\n if (current?.status === \"synced\" && isAsrConfigured(asrConfig)) {\n triggerTranscription(\n recordingId,\n storage,\n asrConfig!,\n logger,\n options,\n ).catch((err) => {\n logger.error(\n `[asr-trigger] 转写触发失败: ${recordingId}, ${err?.message ?? err}`,\n );\n });\n }\n }\n\n const current = storage.findById(recordingId);\n return {\n ok: true,\n recordingId,\n transfer_status: current?.status ?? \"syncing_openclaw\",\n ...(current?.lastError ? { error: current.lastError } : {}),\n };\n}\n\n/**\n * 触发 ASR 转写(可从 sync handler 自动触发或手动重试调用)\n */\nexport async function triggerTranscription(\n recordingId: string,\n storage: RecordingStorage,\n asrConfig: AsrConfig,\n logger: Logger,\n options: RecordingSyncOptions = {},\n): Promise<void> {\n const entry = storage.findById(recordingId);\n if (!entry) {\n logger.warn(`[asr-trigger] 录音不存在: ${recordingId}`);\n return;\n }\n\n if (!canStartTranscription(entry.status)) {\n logger.warn(\n `[asr-trigger] 当前状态不允许转写: ${recordingId} (status=${entry.status})`,\n );\n return;\n }\n\n // 状态 → transcribing\n storage.updateStatus(recordingId, \"transcribing\");\n storage.setLastError(recordingId, undefined);\n emitRecordingStatus(recordingId, storage, logger, options.notifyStatus);\n\n const audioFilePath = storage.getAudioFilePath(recordingId);\n\n let result: Awaited<ReturnType<typeof runTranscriptionWorkflow>>;\n try {\n result = await runTranscriptionWorkflow({\n audioFilePath,\n audioOssUrl: entry.metadata.oss_audio_url,\n config: asrConfig,\n markers: entry.metadata.markers ?? [],\n recordingName: entry.metadata.name,\n durationSec: entry.metadata.duration_sec,\n createdAt: entry.metadata.created_at,\n transcriptDataDir: storage.getTranscriptDataDir(),\n transcriptsDir: storage.getTranscriptsDir(),\n summariesDir: storage.getSummariesDir(),\n recordingId,\n logger,\n });\n } catch (err: any) {\n const error = `转写任务异常: ${err?.message ?? err}`;\n logger.error(`[asr-trigger] ${error}: ${recordingId}`);\n result = { ok: false, error };\n }\n\n if (result.ok && result.transcriptFilename) {\n if (result.transcriptDataFilename) {\n storage.setTranscriptDataFile(recordingId, result.transcriptDataFilename);\n }\n storage.setTranscriptFile(recordingId, result.transcriptFilename);\n if (result.summaryFilename) {\n storage.setSummaryFile(recordingId, result.summaryFilename);\n }\n storage.setTitle(recordingId, result.title);\n storage.updateStatus(recordingId, \"transcribed\");\n emitRecordingStatus(\n recordingId,\n storage,\n logger,\n options.notifyStatus,\n undefined,\n {\n transcript: result.transcript ?? [],\n summary: result.summary,\n title: result.title ?? \"\",\n },\n );\n logger.info(\n `[asr-trigger] 转写完成: ${recordingId}, summary=\"${result.summary}\"`,\n );\n\n // ASR 成功后删除 OSS 上的音频文件(imp-account-user-controllers-api §5.7)\n const ossAudioUrl = entry.metadata.oss_audio_url?.trim();\n if (ossAudioUrl) {\n void deleteAccountOssFile(ossAudioUrl, logger).catch((err) => {\n logger.warn(\n `[asr-trigger] OSS 音频清理异常 (非致命): ${recordingId}, ${err?.message ?? err}`,\n );\n });\n }\n } else {\n const error = result.error ?? \"ASR 转写失败\";\n storage.updateStatus(recordingId, \"transcribe_failed\");\n storage.setLastError(recordingId, error);\n emitRecordingStatus(\n recordingId,\n storage,\n logger,\n options.notifyStatus,\n error,\n );\n logger.error(\n `[asr-trigger] 转写失败: ${recordingId}, error=${error}`,\n );\n }\n}\n","/**\n * Account Service OSS 文件删除(imp-account-user-controllers-api §5.7)\n *\n * 调用 `POST /account/file/delete?fileUrl=...`,`fileUrl` 通过查询串传递\n * (后端确认的传参方式,form-urlencoded / multipart 经网关都会丢字段)。\n */\n\nimport type { Logger } from \"../logger.js\";\nimport { loadApiKey } from \"../auth/credentials.js\";\nimport { getEnvUrls } from \"../env.js\";\n\ninterface AccountServiceResponse {\n code?: string | number;\n msg?: string | null;\n data?: unknown;\n}\n\nexport interface DeleteOssFileResult {\n ok: boolean;\n error?: string;\n}\n\n/**\n * 删除 account-service 上传到 OSS 的文件。\n * 只接受形如 `https://{bucket}.{endpoint}/{objectKey}` 的完整 URL(即上传接口返回值)。\n * 失败不抛异常,由调用方按场景决定是否致命。\n */\nexport async function deleteAccountOssFile(\n fileUrl: string,\n logger: Logger,\n): Promise<DeleteOssFileResult> {\n const trimmed = fileUrl?.trim();\n if (!trimmed) {\n return { ok: false, error: \"fileUrl is empty\" };\n }\n\n const apiKey = loadApiKey();\n if (!apiKey) {\n return { ok: false, error: \"API Key 未设置,跳过 OSS 文件删除\" };\n }\n\n const baseEndpoint = getEnvUrls().accountFileDeleteUrl;\n const headerKey = apiKey.startsWith(\"Bearer \")\n ? apiKey.slice(\"Bearer \".length)\n : apiKey;\n\n const url = new URL(baseEndpoint);\n url.searchParams.set(\"fileUrl\", trimmed);\n const endpoint = url.toString();\n\n logger.info(`[account-oss-delete] 提交 OSS 文件删除: endpoint=${endpoint}`);\n\n let res: Response;\n try {\n res = await fetch(endpoint, {\n method: \"POST\",\n headers: {\n \"X-Api-Key-Id\": headerKey,\n },\n });\n } catch (err: any) {\n const error = err?.message ?? String(err);\n logger.warn(`[account-oss-delete] 网络异常: ${error}`);\n return { ok: false, error };\n }\n\n const text = await res.text();\n if (!res.ok) {\n logger.warn(\n `[account-oss-delete] HTTP 错误: status=${res.status}, body=${text.slice(0, 300)}`,\n );\n return { ok: false, error: `HTTP ${res.status} ${text.slice(0, 200)}` };\n }\n\n let payload: AccountServiceResponse | undefined;\n try {\n payload = text ? (JSON.parse(text) as AccountServiceResponse) : undefined;\n } catch {\n logger.warn(`[account-oss-delete] 响应非 JSON: body=${text.slice(0, 300)}`);\n return { ok: false, error: \"response is not JSON\" };\n }\n\n const code = typeof payload?.code === \"number\" ? String(payload.code) : payload?.code?.trim?.();\n if (code !== \"000000\") {\n const msg = payload?.msg?.trim?.() || text.slice(0, 200);\n logger.warn(`[account-oss-delete] 业务失败: code=${code ?? \"n/a\"}, msg=${msg}`);\n return { ok: false, error: `${code ?? \"unknown\"} ${msg}`.trim() };\n }\n\n logger.info(`[account-oss-delete] OSS 文件已删除: fileUrl=${trimmed}`);\n return { ok: true };\n}\n","import {\n closeSync,\n mkdirSync,\n openSync,\n readFileSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { loadApiKey } from \"../auth/credentials.js\";\nimport { RelayClient } from \"./relay-client.js\";\nimport { TunnelProxy } from \"./proxy.js\";\nimport type { UpdateInfo } from \"../update/types.js\";\n\nconst DEFAULT_HEARTBEAT_SEC = 10;\nconst DEFAULT_RECONNECT_BACKOFF_MS = 2000;\n\ninterface TunnelServiceOptions {\n /** Relay Server WebSocket 地址(构建时从 RELAY_TUNNEL_URL 注入) */\n tunnelUrl: string;\n gatewayBaseUrl: string;\n /** Gateway 鉴权模式 */\n gatewayAuthMode?: \"token\" | \"password\";\n /** Gateway 鉴权 token */\n gatewayToken?: string;\n /** Gateway 鉴权密码 */\n gatewayPassword?: string;\n /** 心跳间隔(秒),默认 10 */\n heartbeatSec?: number;\n /** 重连基础退避时间(毫秒),默认 2000 */\n reconnectBackoffMs?: number;\n logger: {\n info: (msg: string) => void;\n warn: (msg: string) => void;\n error: (msg: string) => void;\n };\n}\n\nexport interface RelayTunnelService {\n id: string;\n start(ctx: { stateDir: string }): Promise<void>;\n stop(): Promise<void>;\n notifyUpdateAvailable(update: UpdateInfo): void;\n clearPendingUpdate(): void;\n deactivateForExternalTunnel(reason: string): Promise<void>;\n}\n\n/**\n * 隧道服务:组装 RelayClient + TunnelProxy,作为 registerService 的入口。\n */\nexport function createTunnelService(\n opts: TunnelServiceOptions,\n): RelayTunnelService {\n let client: RelayClient | null = null;\n let proxy: TunnelProxy | null = null;\n let abortController: AbortController | null = null;\n let lockFilePath: string | null = null;\n let lockFd: number | null = null;\n let pendingPluginUpdate: UpdateInfo | null = null;\n let suppressedByExternalTunnel = false;\n\n function emitPendingPluginUpdate(reason: string): void {\n const update = pendingPluginUpdate;\n if (!update || !client?.isConnected()) return;\n\n const frame = JSON.stringify({\n type: \"event\",\n event: \"plugin.updateAvailable\",\n payload: {\n pluginId: \"phone-notifications\",\n pluginName: \"消息通知\",\n current: update.current,\n latest: update.latest,\n },\n });\n opts.logger.info(\n `Relay tunnel: sending plugin.updateAvailable ${update.current} → ${update.latest} (${reason})`,\n );\n client.sendRaw(frame);\n }\n\n function isProcessAlive(pid: number): boolean {\n if (!Number.isInteger(pid) || pid <= 0) return false;\n if (pid === process.pid) return true;\n try {\n process.kill(pid, 0);\n return true;\n } catch (err: any) {\n return err?.code === \"EPERM\";\n }\n }\n\n function readLockOwner(filePath: string): number | null {\n try {\n const parsed = JSON.parse(readFileSync(filePath, \"utf-8\")) as {\n pid?: unknown;\n };\n return typeof parsed.pid === \"number\" ? parsed.pid : null;\n } catch {\n return null;\n }\n }\n\n function releaseLock(): void {\n const filePath = lockFilePath;\n const fd = lockFd;\n lockFilePath = null;\n lockFd = null;\n\n if (fd !== null) {\n try {\n closeSync(fd);\n } catch {\n // ignore\n }\n }\n if (filePath) {\n try {\n unlinkSync(filePath);\n } catch {\n // ignore\n }\n }\n }\n\n function acquireLock(filePath: string): boolean {\n mkdirSync(dirname(filePath), { recursive: true });\n\n for (let attempt = 0; attempt < 2; attempt++) {\n try {\n const fd = openSync(filePath, \"wx\", 0o600);\n writeFileSync(\n fd,\n JSON.stringify({\n pid: process.pid,\n startedAt: new Date().toISOString(),\n tunnelUrl: opts.tunnelUrl,\n }) + \"\\n\",\n );\n lockFilePath = filePath;\n lockFd = fd;\n return true;\n } catch (err: any) {\n if (err?.code !== \"EEXIST\") {\n opts.logger.error(\n `Relay tunnel: failed to acquire local lock ${filePath}: ${String(err)}`,\n );\n return false;\n }\n\n const ownerPid = readLockOwner(filePath);\n if (ownerPid && !isProcessAlive(ownerPid)) {\n opts.logger.warn(\n `Relay tunnel: removing stale local lock owned by dead pid=${ownerPid}`,\n );\n try {\n unlinkSync(filePath);\n } catch {\n // ignore, retry below will fail if lock is still present\n }\n continue;\n }\n\n opts.logger.warn(\n `Relay tunnel: another local process already owns the tunnel lock${ownerPid ? ` (pid=${ownerPid})` : \"\"}; skipping connection to avoid duplicate token sessions`,\n );\n return false;\n }\n }\n\n return false;\n }\n\n async function shutdownRuntime(reason: string): Promise<void> {\n await client?.stop(reason);\n if (abortController) {\n abortController.abort();\n abortController = null;\n }\n releaseLock();\n proxy?.cleanup();\n proxy = null;\n client = null;\n }\n\n return {\n id: \"relay-tunnel\",\n\n async start(ctx: { stateDir: string }) {\n if (suppressedByExternalTunnel) {\n opts.logger.info(\n \"Relay tunnel: external tunnel currently owns ingress; skipping relay startup\",\n );\n return;\n }\n\n // 先清理上一轮连接,防止 start() 被重复调用时产生多个 RelayClient 互踢\n if (abortController) {\n opts.logger.info(\"Relay tunnel: aborting previous connection before restart\");\n await shutdownRuntime(\"service restarting\");\n }\n\n const apiKey = loadApiKey();\n if (!apiKey) {\n opts.logger.warn(\n \"Relay tunnel: apiKey 未设置,跳过隧道连接。请执行 openclaw ntf auth set-api-key <apiKey>\",\n );\n return;\n }\n\n const { logger } = opts;\n const baseStateDir = join(ctx.stateDir, \"plugins\", \"phone-notifications\");\n logger.info(\n `Relay tunnel: starting (pid=${process.pid}, url=${opts.tunnelUrl}, heartbeat=${opts.heartbeatSec ?? DEFAULT_HEARTBEAT_SEC}s, backoff=${opts.reconnectBackoffMs ?? DEFAULT_RECONNECT_BACKOFF_MS}ms, gateway=${opts.gatewayBaseUrl}, hasGatewayToken=${!!opts.gatewayToken}, hasGatewayPwd=${!!opts.gatewayPassword})`,\n );\n const statusFilePath = join(baseStateDir, \"tunnel-status.json\");\n const lockPath = join(baseStateDir, \"relay-tunnel.lock\");\n\n if (!acquireLock(lockPath)) {\n return;\n }\n\n try {\n client = new RelayClient({\n tunnelUrl: opts.tunnelUrl,\n apiKey,\n heartbeatSec: opts.heartbeatSec ?? DEFAULT_HEARTBEAT_SEC,\n reconnectBackoffMs: opts.reconnectBackoffMs ?? DEFAULT_RECONNECT_BACKOFF_MS,\n statusFilePath,\n logger,\n });\n\n proxy = new TunnelProxy({\n stateDir: baseStateDir,\n hostStateDir: ctx.stateDir,\n gatewayBaseUrl: opts.gatewayBaseUrl,\n gatewayAuthMode: opts.gatewayAuthMode,\n gatewayToken: opts.gatewayToken,\n gatewayPassword: opts.gatewayPassword,\n client,\n logger,\n });\n\n client.onInbound((frame) => proxy!.handleFrame(frame));\n client.onConnected(() => {\n emitPendingPluginUpdate(\"relay connected\");\n });\n\n abortController = new AbortController();\n // 非阻塞启动,connectWithAutoReconnect 内部会保持运行\n client.connectWithAutoReconnect(abortController.signal).catch((err) => {\n releaseLock();\n logger.error(`Relay tunnel: unexpected error: ${err}`);\n });\n\n logger.info(\"Relay tunnel 服务已启动\");\n } catch (err) {\n releaseLock();\n throw err;\n }\n },\n\n async stop() {\n suppressedByExternalTunnel = false;\n await shutdownRuntime(\"service stopping\");\n opts.logger.info(\"Relay tunnel 服务已停止\");\n },\n\n async deactivateForExternalTunnel(reason: string) {\n if (suppressedByExternalTunnel && !client && !proxy && !abortController) {\n return;\n }\n\n suppressedByExternalTunnel = true;\n opts.logger.info(\n `Relay tunnel: external tunnel claimed ingress (${reason}), shutting down relay connection`,\n );\n await shutdownRuntime(\"external tunnel active\");\n },\n\n notifyUpdateAvailable(update: UpdateInfo) {\n pendingPluginUpdate = update;\n emitPendingPluginUpdate(\"update detected\");\n },\n\n clearPendingUpdate() {\n pendingPluginUpdate = null;\n },\n };\n}\n","import { writeFileSync, mkdirSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport WebSocket from \"ws\";\nimport type { InboundFrame, OutboundFrame } from \"./types.js\";\n\nfunction previewText(text: string, max = 500): string {\n return text.length <= max ? text : `${text.substring(0, max)}…`;\n}\n\n/** WebSocket Upgrade 握手超时(毫秒)。云上常见 NAT/中间盒吞包场景下兜底用。 */\nconst HANDSHAKE_TIMEOUT_MS = 15_000;\n/** 兜底 watchdog:如果握手超时也没触发,强制 terminate 进入重连路径。 */\nconst CONNECT_WATCHDOG_MS = 20_000;\n\nfunction maskSecret(value: string): string {\n if (!value) return \"empty\";\n if (value.length <= 8) {\n return `${value.slice(0, 2)}…${value.slice(-2)}`;\n }\n return `${value.slice(0, 4)}…${value.slice(-4)}`;\n}\n\n/** 持久化到磁盘的隧道连接状态 */\nexport interface TunnelStatusInfo {\n /** 当前连接状态 */\n state: \"connected\" | \"disconnected\" | \"connecting\" | \"stopped\";\n /** 状态变更时间 ISO */\n since: string;\n /** 累计重连次数 */\n reconnectAttempt: number;\n /** 上次断开原因(仅 disconnected 时有值) */\n lastDisconnectReason?: string;\n}\n\nexport interface RelayClientOptions {\n tunnelUrl: string;\n apiKey: string;\n heartbeatSec: number;\n reconnectBackoffMs: number;\n /** 状态文件路径,设置后会在连接状态变更时写入 */\n statusFilePath?: string;\n logger: {\n info: (msg: string) => void;\n warn: (msg: string) => void;\n error: (msg: string) => void;\n };\n}\n\nexport type InboundHandler = (frame: InboundFrame) => void | Promise<void>;\nexport type ConnectedHandler = () => void | Promise<void>;\n\n/**\n * Relay WebSocket 客户端。\n * 负责建连、token 认证、心跳保活、断线指数退避重连。\n */\nexport class RelayClient {\n private ws: WebSocket | null = null;\n private heartbeatTimer: ReturnType<typeof setInterval> | null = null;\n private reconnectAttempt = 0;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private handlers: InboundHandler[] = [];\n private connectedHandlers: ConnectedHandler[] = [];\n private aborted = false;\n private lastInboundAt = 0;\n private stopPromise: Promise<void> | null = null;\n\n constructor(private readonly opts: RelayClientOptions) {}\n\n /** 写连接状态到磁盘 */\n private writeStatus(\n state: TunnelStatusInfo[\"state\"],\n lastDisconnectReason?: string,\n ): void {\n if (!this.opts.statusFilePath) return;\n const info: TunnelStatusInfo = {\n state,\n since: new Date().toISOString(),\n reconnectAttempt: this.reconnectAttempt,\n lastDisconnectReason,\n };\n try {\n mkdirSync(dirname(this.opts.statusFilePath), { recursive: true });\n writeFileSync(this.opts.statusFilePath, JSON.stringify(info, null, 2));\n } catch {\n // 写状态文件失败不影响主流程\n }\n }\n\n /** 注册入站帧处理函数 */\n onInbound(handler: InboundHandler): void {\n this.handlers.push(handler);\n }\n\n /** 注册连接成功后的回调 */\n onConnected(handler: ConnectedHandler): void {\n this.connectedHandlers.push(handler);\n }\n\n /** 当前是否已连上 Relay */\n isConnected(): boolean {\n return this.ws?.readyState === WebSocket.OPEN;\n }\n\n /** 优雅停止客户端,优先发送 close 帧,超时后再强制 terminate */\n async stop(reason = \"client stopping\"): Promise<void> {\n if (this.stopPromise) {\n return this.stopPromise;\n }\n\n this.aborted = true;\n this.writeStatus(\"stopped\");\n this.stopHeartbeat();\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n\n const ws = this.ws;\n this.ws = null;\n if (!ws) {\n return;\n }\n\n this.opts.logger.info(\n `Relay tunnel: stopping client (readyState=${ws.readyState}, reason=${reason})`,\n );\n\n if (\n ws.readyState === WebSocket.CLOSED ||\n ws.readyState === WebSocket.CLOSING\n ) {\n return;\n }\n\n if (ws.readyState !== WebSocket.OPEN) {\n try {\n ws.terminate();\n } catch {\n // ignore\n }\n return;\n }\n\n this.stopPromise = new Promise<void>((resolve) => {\n let finished = false;\n let fallbackTimer: ReturnType<typeof setTimeout> | null = null;\n\n const finish = () => {\n if (finished) return;\n finished = true;\n if (fallbackTimer) {\n clearTimeout(fallbackTimer);\n fallbackTimer = null;\n }\n ws.off(\"close\", handleClose);\n ws.off(\"error\", handleError);\n this.stopPromise = null;\n resolve();\n };\n\n const handleClose = () => finish();\n const handleError = () => finish();\n\n ws.once(\"close\", handleClose);\n ws.once(\"error\", handleError);\n\n fallbackTimer = setTimeout(() => {\n this.opts.logger.warn(\n \"Relay tunnel: graceful close timed out, forcing terminate\",\n );\n try {\n ws.terminate();\n } catch {\n // ignore\n }\n finish();\n }, 1500);\n\n try {\n ws.close(1000, reason);\n } catch {\n finish();\n }\n });\n\n await this.stopPromise;\n }\n\n /** 发送出站帧 */\n send(frame: OutboundFrame): void {\n if (this.ws?.readyState === WebSocket.OPEN) {\n const payload = JSON.stringify(frame);\n this.opts.logger.info(\n `Relay tunnel: ▶ send frame type=${frame.type}, id=${\"id\" in frame ? frame.id : \"N/A\"} (${payload.length} chars)`,\n );\n this.ws.send(payload);\n } else {\n this.opts.logger.warn(\n `Relay tunnel: ▶ send skipped, ws not open (readyState=${this.ws?.readyState ?? \"null\"}), frame type=${frame.type}`,\n );\n }\n }\n\n /** 原样透传文本到 Relay(用于 Gateway WS 响应直接回传) */\n sendRaw(text: string): void {\n if (this.ws?.readyState === WebSocket.OPEN) {\n this.opts.logger.info(\n `Relay tunnel: ▶ sendRaw (${text.length} chars): ${text.length <= 500 ? text : text.substring(0, 500) + \"…\"}`,\n );\n this.ws.send(text);\n } else {\n this.opts.logger.warn(\n `Relay tunnel: ▶ sendRaw skipped, ws not open (readyState=${this.ws?.readyState ?? \"null\"})`,\n );\n }\n }\n\n /** 启动连接,带自动重连,直到 abortSignal 触发 */\n async connectWithAutoReconnect(abortSignal?: AbortSignal): Promise<void> {\n if (abortSignal) {\n abortSignal.addEventListener(\n \"abort\",\n () => {\n void this.stop();\n },\n { once: true },\n );\n }\n\n await this.connect();\n\n // 保持运行直到 abort\n return new Promise<void>((resolve) => {\n if (abortSignal) {\n abortSignal.addEventListener(\"abort\", () => resolve(), { once: true });\n }\n });\n }\n\n private async connect(): Promise<void> {\n if (this.aborted) return;\n\n // 确保旧连接和定时器都被清理,防止重复连接\n this.cleanup(true);\n\n const rawApiKey = this.opts.apiKey.startsWith(\"Bearer \")\n ? this.opts.apiKey.slice(\"Bearer \".length)\n : this.opts.apiKey;\n\n this.opts.logger.info(\n `Relay tunnel: connecting to ${this.opts.tunnelUrl} (attempt=${this.reconnectAttempt}, heartbeat=${this.opts.heartbeatSec}s, apiKey=${maskSecret(rawApiKey)})`,\n );\n this.writeStatus(\"connecting\");\n\n return new Promise<void>((resolve) => {\n let settled = false;\n const settle = () => {\n if (!settled) {\n settled = true;\n resolve();\n }\n };\n\n const wsUrl = new URL(this.opts.tunnelUrl);\n // 推荐使用 query 传 apiKey;暂时用 token 代替 apiKey 明文\n if (!wsUrl.searchParams.get(\"apiKey\")) {\n wsUrl.searchParams.set(\"apiKey\", rawApiKey);\n }\n\n const ws = new WebSocket(wsUrl.toString(), {\n headers: {\n \"X-Api-Key-Id\": rawApiKey,\n },\n // 防止 TCP 通但 HTTP Upgrade 响应被吞导致永久挂在 CONNECTING\n handshakeTimeout: HANDSHAKE_TIMEOUT_MS,\n });\n // 将握手中的 socket 也记为当前连接,确保首连失败/握手前断开也能触发重连。\n this.ws = ws;\n\n // 兜底 watchdog:即使 handshakeTimeout 因某些原因失效,也强制 terminate 走重连路径。\n let connectWatchdog: ReturnType<typeof setTimeout> | null = setTimeout(() => {\n connectWatchdog = null;\n if (this.ws !== ws || ws.readyState === WebSocket.OPEN) {\n return;\n }\n this.opts.logger.warn(\n `Relay tunnel: connect watchdog fired (readyState=${ws.readyState}, attempt=${this.reconnectAttempt}), forcing terminate`,\n );\n try {\n ws.terminate();\n } catch {\n // 让 close 事件接管重连;若 close 也没来,下面 error 路径也会触发 scheduleReconnect\n }\n // 兜底:极端情况下 terminate 没触发 close(不应发生,但保险起见)\n if (this.ws === ws) {\n setTimeout(() => {\n if (this.ws === ws) {\n this.opts.logger.warn(\n \"Relay tunnel: terminate did not emit close, forcing reconnect\",\n );\n this.stopHeartbeat();\n this.ws = null;\n this.writeStatus(\"disconnected\", \"watchdog-force\");\n this.scheduleReconnect();\n settle();\n }\n }, 1000);\n }\n }, CONNECT_WATCHDOG_MS);\n\n const clearConnectWatchdog = () => {\n if (connectWatchdog) {\n clearTimeout(connectWatchdog);\n connectWatchdog = null;\n }\n };\n\n ws.on(\"open\", () => {\n clearConnectWatchdog();\n if (this.aborted || this.ws !== ws) {\n this.opts.logger.warn(\n `Relay tunnel: open fired but aborted=${this.aborted}, stale=${this.ws !== ws}, closing`,\n );\n try {\n ws.terminate();\n } catch {\n // ignore\n }\n settle();\n return;\n }\n this.reconnectAttempt = 0;\n this.lastInboundAt = Date.now();\n this.startHeartbeat();\n this.opts.logger.info(\"Relay tunnel: ✔ connected, heartbeat started\");\n this.writeStatus(\"connected\");\n this.emitConnected();\n settle();\n });\n\n ws.on(\"pong\", () => {\n if (this.ws === ws) {\n this.opts.logger.info(\"Relay tunnel: ← pong received\");\n this.markInboundActivity();\n }\n });\n\n ws.on(\"message\", (data: WebSocket.RawData) => {\n if (this.ws !== ws) {\n return;\n }\n this.handleMessage(data);\n });\n\n ws.on(\"close\", (code: number, reason: Buffer) => {\n clearConnectWatchdog();\n const reasonStr = reason.toString();\n const lastInboundAgoMs = this.lastInboundAt\n ? Date.now() - this.lastInboundAt\n : null;\n const isCurrentSocket = this.ws === ws;\n const logMessage =\n `Relay tunnel: disconnected (code=${code}, reason=${previewText(reasonStr, 200)}, lastInboundAgoMs=${lastInboundAgoMs ?? \"N/A\"}, reconnectAttempt=${this.reconnectAttempt})`;\n if (this.aborted || !isCurrentSocket) {\n this.opts.logger.info(logMessage);\n } else {\n this.opts.logger.warn(logMessage);\n }\n if (isCurrentSocket) {\n this.stopHeartbeat();\n this.ws = null;\n this.writeStatus(\"disconnected\", `code=${code}, reason=${reasonStr}`);\n this.scheduleReconnect();\n }\n settle();\n });\n\n ws.on(\"error\", (err: Error) => {\n this.opts.logger.error(\n `Relay tunnel: WebSocket error: ${err.message} (readyState=${ws.readyState}, reconnectAttempt=${this.reconnectAttempt}, url=${wsUrl.toString()})`,\n );\n // 多数情况 error 后 ws 会再触发 close;但部分底层错误只 error 不 close,\n // 这里幂等地兜底一次 scheduleReconnect,scheduleReconnect 内部对已排程的重连会跳过。\n if (this.ws === ws) {\n this.scheduleReconnect();\n }\n settle();\n });\n });\n }\n\n private emitConnected(): void {\n for (const handler of this.connectedHandlers) {\n Promise.resolve(handler()).catch((err) => {\n this.opts.logger.warn(\n `Relay tunnel: onConnected handler failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n });\n }\n }\n\n private handleMessage(data: WebSocket.RawData): void {\n const text =\n typeof data === \"string\"\n ? data\n : Buffer.isBuffer(data)\n ? data.toString()\n : String(data);\n\n this.markInboundActivity();\n\n // 应用层心跳 pong 直接消费,不走帧解析\n if (text === \"pong\") {\n return;\n }\n\n this.opts.logger.info(\n `Relay tunnel: ★ received message (${text.length} chars): ${previewText(text)}`,\n );\n\n let frame: InboundFrame;\n try {\n frame = JSON.parse(text) as InboundFrame;\n } catch {\n this.opts.logger.warn(\n `Relay tunnel: received invalid frame, ignoring (preview=${previewText(text, 200)})`,\n );\n return;\n }\n\n this.opts.logger.info(`Relay tunnel: parsed frame type=${frame.type}, id=${\"id\" in frame ? frame.id : \"N/A\"}`);\n\n for (const handler of this.handlers) {\n try {\n const result = handler(frame);\n if (result instanceof Promise) {\n result.catch((err) => {\n this.opts.logger.error(`Relay tunnel: handler error: ${err}`);\n });\n }\n } catch (err) {\n this.opts.logger.error(`Relay tunnel: handler error: ${err}`);\n }\n }\n }\n\n private startHeartbeat(): void {\n this.stopHeartbeat();\n const intervalMs = this.opts.heartbeatSec * 1000;\n this.sendHeartbeat();\n this.heartbeatTimer = setInterval(() => {\n this.sendHeartbeat();\n }, intervalMs);\n }\n\n private stopHeartbeat(): void {\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\n }\n\n private getHeartbeatTimeoutMs(): number {\n return this.opts.heartbeatSec * 3 * 1000;\n }\n\n private sendHeartbeat(): void {\n if (this.ws?.readyState !== WebSocket.OPEN) {\n return;\n }\n\n const idleMs = Date.now() - this.lastInboundAt;\n const timeoutMs = this.getHeartbeatTimeoutMs();\n if (idleMs >= timeoutMs) {\n this.opts.logger.warn(\n `Relay tunnel: heartbeat timeout, no inbound activity for ${idleMs}ms (threshold=${timeoutMs}ms)`,\n );\n try {\n this.ws.terminate();\n } catch {\n // ignore, close/error path will handle reconnect\n }\n return;\n }\n\n this.opts.logger.info('Relay tunnel: → heartbeat \"ping\"');\n try {\n this.ws.send(\"ping\");\n } catch {\n // ignore, close/error path will handle reconnect\n }\n try {\n this.ws.ping();\n } catch {\n // ignore, close/error path will handle reconnect\n }\n }\n\n private markInboundActivity(): void {\n this.lastInboundAt = Date.now();\n }\n\n private cleanup(force = false): void {\n this.opts.logger.info(\n `Relay tunnel: cleanup (ws=${this.ws ? \"open\" : \"null\"}, heartbeat=${!!this.heartbeatTimer}, reconnect=${!!this.reconnectTimer})`,\n );\n this.stopHeartbeat();\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n if (this.ws) {\n try {\n if (force) {\n this.ws.terminate();\n } else {\n this.ws.close();\n }\n } catch {\n // ignore\n }\n this.ws = null;\n }\n }\n\n private scheduleReconnect(): void {\n if (this.aborted) return;\n\n // 已经排了一次重连就不再重排,避免 error+close 双触发或 watchdog 与 close 双触发时\n // attempt 被多扣、退避被无意义重置。\n if (this.reconnectTimer) {\n return;\n }\n\n const baseMs = this.opts.reconnectBackoffMs;\n const delayMs = Math.min(\n baseMs * Math.pow(2, this.reconnectAttempt),\n 60_000,\n );\n this.reconnectAttempt++;\n\n this.opts.logger.info(\n `Relay tunnel: reconnecting in ${delayMs}ms (attempt ${this.reconnectAttempt})`,\n );\n\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n if (!this.aborted) {\n this.connect().catch((err) => {\n this.opts.logger.error(`Relay tunnel: reconnect failed: ${err}`);\n });\n }\n }, delayMs);\n }\n}\n","import createWebSocketStream from './lib/stream.js';\nimport Receiver from './lib/receiver.js';\nimport Sender from './lib/sender.js';\nimport WebSocket from './lib/websocket.js';\nimport WebSocketServer from './lib/websocket-server.js';\n\nexport { createWebSocketStream, Receiver, Sender, WebSocket, WebSocketServer };\nexport default WebSocket;\n","import { randomUUID } from \"node:crypto\";\nimport WebSocket from \"ws\";\nimport type { RelayClient } from \"./relay-client.js\";\nimport type { ReqFrame, InboundFrame } from \"./types.js\";\nimport { previewText } from \"./utils.js\";\nimport { resolveStateDir as resolveHostStateDir } from \"../host.js\";\nimport {\n type DeviceIdentity,\n resolveClientStateDir,\n loadOrCreateDeviceIdentity,\n loadDeviceAuthToken,\n storeDeviceAuthToken,\n clearDeviceAuthToken,\n buildDeviceAuthPayload,\n signDevicePayload,\n publicKeyRawBase64UrlFromPem,\n} from \"./device-identity.js\";\nimport { handleHttpRequest } from \"./http-proxy.js\";\nimport { WsProxy } from \"./ws-proxy.js\";\n\n// ─── Types ───\n\nexport const RELAY_TUNNEL_GATEWAY_CLIENT_INSTANCE_ID =\n \"phone-notifications-relay-tunnel\";\n\ninterface ProxyOptions {\n stateDir?: string;\n hostStateDir?: string;\n gatewayBaseUrl: string;\n /** Gateway 鉴权模式 */\n gatewayAuthMode?: \"token\" | \"password\";\n /** Gateway 鉴权 token,代理请求到本地 gateway 时使用 */\n gatewayToken?: string;\n /** Gateway 鉴权密码,代理请求到本地 gateway 时使用 */\n gatewayPassword?: string;\n client: RelayClient;\n logger: {\n info: (msg: string) => void;\n warn: (msg: string) => void;\n error: (msg: string) => void;\n };\n}\n\nconst MAX_AUTO_PAIRING_APPROVALS = 3;\nconst RECENT_ABORTED_CHAT_RUN_TTL_MS = 60_000;\n\ninterface PendingGatewayReqMeta {\n method: string;\n sessionKey?: string;\n}\n\ninterface RecentAbortedChatRun {\n sessionKey: string;\n abortedAtMs: number;\n}\n\ntype ApproveDevicePairingFn = (\n requestId: string,\n hostStateDir?: string,\n) => Promise<unknown>;\n\nlet approveDevicePairingPromise: Promise<ApproveDevicePairingFn | null> | null =\n null;\nlet approveDevicePairingWarned = false;\n\nfunction formatErrorMessage(err: unknown): string {\n if (err instanceof Error && err.message) return err.message;\n return String(err);\n}\n\nasync function loadApproveDevicePairing(\n logger: ProxyOptions[\"logger\"],\n): Promise<ApproveDevicePairingFn | null> {\n if (!approveDevicePairingPromise) {\n approveDevicePairingPromise = import(\"openclaw/plugin-sdk/device-bootstrap\")\n .then((mod) =>\n typeof mod.approveDevicePairing === \"function\"\n ? (mod.approveDevicePairing as ApproveDevicePairingFn)\n : null,\n )\n .catch((err: unknown) => {\n if (!approveDevicePairingWarned) {\n approveDevicePairingWarned = true;\n logger.warn(\n `TunnelProxy: local gateway auto-pairing disabled because current OpenClaw runtime does not expose device bootstrap SDK (${formatErrorMessage(err)})`,\n );\n }\n return null;\n });\n }\n\n const approveDevicePairing = await approveDevicePairingPromise;\n if (!approveDevicePairing && !approveDevicePairingWarned) {\n approveDevicePairingWarned = true;\n logger.warn(\n \"TunnelProxy: local gateway auto-pairing disabled because current OpenClaw runtime does not expose device bootstrap SDK\",\n );\n }\n return approveDevicePairing;\n}\n\n/**\n * 透明代理:接收 Relay 转发的请求帧,代理到本地 gateway,回传响应帧。\n * 支持 HTTP 请求代理和 WebSocket 连接代理。\n */\nexport class TunnelProxy {\n /** 到本地 Gateway 的持久 RPC WebSocket 连接 */\n private gatewayWs: WebSocket | null = null;\n private gatewayWsConnecting = false;\n /** 握手是否已完成(收到 hello-ok) */\n private gatewayWsReady = false;\n /** 收到本地自动配对成功后,在 close 回调里触发重连 */\n private gatewayWsReconnectRequested = false;\n /** 防止配对失败时无限重连 */\n private gatewayWsAutoPairingApprovals = 0;\n /** 等待 Gateway WS 握手完成后发送的帧队列 */\n private gatewayWsPending: string[] = [];\n /** 记录已转发到 Gateway 的 req 元信息,便于回包时做定向处理。 */\n private gatewayReqMetaById = new Map<string, PendingGatewayReqMeta>();\n /** 最近由用户手动中断的 chat.run,用于过滤 runtime 误补发的 synthetic failure。 */\n private recentAbortedChatRuns = new Map<string, RecentAbortedChatRun>();\n\n /** 设备身份,用于 Gateway connect 握手 */\n private deviceIdentity: DeviceIdentity;\n\n private readonly stateDir: string;\n private readonly hostStateDir: string;\n private readonly wsProxy: WsProxy;\n\n constructor(private readonly opts: ProxyOptions) {\n this.stateDir = resolveClientStateDir(opts.stateDir);\n this.hostStateDir = opts.hostStateDir ?? resolveHostStateDir();\n this.deviceIdentity = loadOrCreateDeviceIdentity(this.stateDir);\n opts.logger.info(\n `TunnelProxy: loaded device identity (deviceId=${this.deviceIdentity.deviceId})`,\n );\n this.wsProxy = new WsProxy({\n gatewayBaseUrl: opts.gatewayBaseUrl,\n client: opts.client,\n logger: opts.logger,\n });\n }\n\n // ─── Frame dispatcher ───\n\n /** 处理从 Relay 收到的入站帧 */\n async handleFrame(frame: InboundFrame): Promise<void> {\n this.opts.logger.info(\n `TunnelProxy: handling frame type=${frame.type}, id=${\"id\" in frame ? frame.id : \"N/A\"}`,\n );\n switch (frame.type) {\n case \"request\":\n await handleHttpRequest(this.opts, frame);\n break;\n case \"req\":\n this.handleReqFrame(frame);\n break;\n case \"ws_open\":\n this.wsProxy.handleWsOpen(frame);\n break;\n case \"ws_data\":\n this.wsProxy.handleWsData(frame);\n break;\n case \"ws_close\":\n this.wsProxy.handleWsClose(frame);\n break;\n default:\n this.opts.logger.warn(\n `TunnelProxy: unknown frame type=\"${(frame as any).type}\", id=${\"id\" in frame ? (frame as any).id : \"N/A\"}, forwarding raw to gateway`,\n );\n // 未知帧类型也尝试通过 RPC WS 转发,避免静默丢弃\n this.forwardRawToGateway(JSON.stringify(frame));\n break;\n }\n }\n\n /** 清理所有代理的 WebSocket 连接 */\n cleanup(): void {\n this.opts.logger.info(\n `TunnelProxy: cleanup, closing ${this.wsProxy.activeCount} active WS connections, gatewayWs=${!!this.gatewayWs}`,\n );\n this.wsProxy.cleanup();\n\n if (this.gatewayWs) {\n try {\n this.gatewayWs.close();\n } catch {\n // ignore\n }\n this.gatewayWs = null;\n }\n this.gatewayWsReady = false;\n this.gatewayWsConnecting = false;\n this.gatewayWsReconnectRequested = false;\n this.gatewayWsAutoPairingApprovals = 0;\n this.gatewayWsPending = [];\n this.gatewayReqMetaById.clear();\n this.recentAbortedChatRuns.clear();\n }\n\n // ─── Gateway RPC WebSocket ───\n\n private pushGatewayPending(payload: string, reason: string): void {\n this.gatewayWsPending.push(payload);\n this.opts.logger.info(\n `TunnelProxy: gateway WS pending queue size=${this.gatewayWsPending.length} (${reason})`,\n );\n }\n\n /** 将未知帧原样转发到 Gateway WS */\n private forwardRawToGateway(payload: string): void {\n this.ensureGatewayWs();\n if (this.gatewayWsReady && this.gatewayWs?.readyState === WebSocket.OPEN) {\n this.gatewayWs.send(payload);\n } else {\n this.pushGatewayPending(payload, \"raw frame queued before gateway WS ready\");\n }\n }\n\n /** 处理 Relay 转发的 Gateway RPC 请求帧,原样通过 WebSocket 发给本地 Gateway */\n private handleReqFrame(frame: ReqFrame): void {\n const payload = JSON.stringify(frame);\n this.gatewayReqMetaById.set(frame.id, {\n method: frame.method,\n sessionKey: this.normalizeSessionKey(frame.params?.sessionKey),\n });\n this.opts.logger.info(\n `TunnelProxy: req id=${frame.id} method=${frame.method} → gateway WS (${payload.length} chars)`,\n );\n\n this.ensureGatewayWs();\n\n if (this.gatewayWsReady && this.gatewayWs?.readyState === WebSocket.OPEN) {\n this.gatewayWs.send(payload);\n } else {\n this.opts.logger.info(\n `TunnelProxy: req id=${frame.id} queued, gateway WS not ready yet`,\n );\n this.pushGatewayPending(\n payload,\n `req id=${frame.id} queued before gateway WS handshake`,\n );\n }\n }\n\n // ─── Gateway connect auth helpers ───\n\n private resolveGatewayConnectAuth():\n | { token?: string; password?: string }\n | undefined {\n const token = this.opts.gatewayToken?.trim() || undefined;\n const password = this.opts.gatewayPassword?.trim() || undefined;\n if (!token && !password) return undefined;\n return { token, password };\n }\n\n private loadStoredDeviceToken(role: string): string | undefined {\n return (\n loadDeviceAuthToken({\n stateDir: this.stateDir,\n deviceId: this.deviceIdentity.deviceId,\n role,\n })?.token ?? undefined\n );\n }\n\n private buildGatewayConnectAuth(role: string): {\n auth?: { token?: string; deviceToken?: string; password?: string };\n authToken?: string;\n authPassword?: string;\n deviceToken?: string;\n } {\n const explicitAuth = this.resolveGatewayConnectAuth();\n const authPassword = explicitAuth?.password?.trim() || undefined;\n const explicitGatewayToken = explicitAuth?.token?.trim() || undefined;\n const deviceToken = explicitGatewayToken\n ? undefined\n : this.loadStoredDeviceToken(role);\n const authToken = explicitGatewayToken ?? deviceToken;\n const auth =\n authToken || authPassword || deviceToken\n ? { token: authToken, deviceToken, password: authPassword }\n : undefined;\n return { auth, authToken, authPassword, deviceToken };\n }\n\n private storeIssuedDeviceToken(params: {\n fallbackRole: string;\n fallbackScopes: string[];\n authInfo: any;\n }): void {\n const token = params.authInfo?.deviceToken;\n if (typeof token !== \"string\" || !token.trim()) return;\n const role =\n typeof params.authInfo?.role === \"string\" && params.authInfo.role.trim()\n ? params.authInfo.role.trim()\n : params.fallbackRole;\n const scopes = Array.isArray(params.authInfo?.scopes)\n ? params.authInfo.scopes.filter(\n (scope: unknown): scope is string =>\n typeof scope === \"string\" && !!scope.trim(),\n )\n : params.fallbackScopes;\n storeDeviceAuthToken({\n stateDir: this.stateDir,\n deviceId: this.deviceIdentity.deviceId,\n role,\n token: token.trim(),\n scopes,\n });\n }\n\n private maybeClearStoredDeviceTokenOnMismatch(code: number, reason: string): void {\n const explicitAuth = this.resolveGatewayConnectAuth();\n if (explicitAuth?.token || explicitAuth?.password) return;\n if (code !== 1008 || !reason.toLowerCase().includes(\"device token mismatch\")) return;\n clearDeviceAuthToken({\n stateDir: this.stateDir,\n deviceId: this.deviceIdentity.deviceId,\n role: \"operator\",\n });\n this.opts.logger.warn(\n `TunnelProxy: cleared stale stored device token after gateway mismatch (deviceId=${this.deviceIdentity.deviceId})`,\n );\n }\n\n private async maybeAutoApproveGatewayPairing(frame: any): Promise<boolean> {\n const errorCode =\n typeof frame?.error?.code === \"string\" ? frame.error.code : undefined;\n const detailsCode =\n typeof frame?.error?.details?.code === \"string\"\n ? frame.error.details.code\n : undefined;\n if (errorCode !== \"NOT_PAIRED\" && detailsCode !== \"PAIRING_REQUIRED\") {\n return false;\n }\n\n const requestId =\n typeof frame?.error?.details?.requestId === \"string\"\n ? frame.error.details.requestId.trim()\n : \"\";\n const reason =\n typeof frame?.error?.details?.reason === \"string\"\n ? frame.error.details.reason.trim()\n : \"\";\n\n if (!requestId) {\n this.opts.logger.warn(\n \"TunnelProxy: gateway pairing required but requestId missing; unable to auto-approve\",\n );\n return false;\n }\n\n if (\n reason &&\n reason !== \"not-paired\" &&\n reason !== \"scope-upgrade\"\n ) {\n this.opts.logger.warn(\n `TunnelProxy: gateway pairing required with unsupported reason=${reason}; skipping auto-approve`,\n );\n return false;\n }\n\n if (this.gatewayWsAutoPairingApprovals >= MAX_AUTO_PAIRING_APPROVALS) {\n this.opts.logger.warn(\n `TunnelProxy: reached auto-pairing retry limit (${MAX_AUTO_PAIRING_APPROVALS}); requestId=${requestId}`,\n );\n return false;\n }\n\n try {\n const approveDevicePairing = await loadApproveDevicePairing(this.opts.logger);\n if (!approveDevicePairing) {\n return false;\n }\n const approved = await approveDevicePairing(requestId, this.hostStateDir);\n if (!approved) {\n this.opts.logger.warn(\n `TunnelProxy: gateway pairing request ${requestId} not found in host state ${this.hostStateDir}`,\n );\n return false;\n }\n this.gatewayWsAutoPairingApprovals += 1;\n this.gatewayWsReconnectRequested = true;\n this.opts.logger.info(\n `TunnelProxy: auto-approved local gateway pairing request ${requestId} (reason=${reason || \"not-paired\"}, hostStateDir=${this.hostStateDir}, approval=${this.gatewayWsAutoPairingApprovals}/${MAX_AUTO_PAIRING_APPROVALS})`,\n );\n return true;\n } catch (err: any) {\n this.opts.logger.warn(\n `TunnelProxy: failed to auto-approve gateway pairing request ${requestId}: ${err?.message ?? String(err)}`,\n );\n return false;\n }\n }\n\n // ─── Gateway RPC WebSocket lifecycle ───\n\n private normalizeSessionKey(value: unknown): string | undefined {\n return typeof value === \"string\" && value.trim() ? value.trim() : undefined;\n }\n\n private normalizeRunId(value: unknown): string | undefined {\n return typeof value === \"string\" && value.trim() ? value.trim() : undefined;\n }\n\n private pruneRecentAbortedChatRuns(now = Date.now()): void {\n for (const [runId, entry] of this.recentAbortedChatRuns) {\n if (now - entry.abortedAtMs > RECENT_ABORTED_CHAT_RUN_TTL_MS) {\n this.recentAbortedChatRuns.delete(runId);\n }\n }\n }\n\n private rememberRecentAbortedChatRun(runId: unknown, sessionKey: unknown): void {\n const normalizedRunId = this.normalizeRunId(runId);\n const normalizedSessionKey = this.normalizeSessionKey(sessionKey);\n if (!normalizedRunId || !normalizedSessionKey) return;\n this.pruneRecentAbortedChatRuns();\n this.recentAbortedChatRuns.set(normalizedRunId, {\n sessionKey: normalizedSessionKey,\n abortedAtMs: Date.now(),\n });\n }\n\n private getAssistantMessageText(message: any): string {\n if (!message || typeof message !== \"object\") return \"\";\n if (typeof message.text === \"string\") return message.text;\n if (!Array.isArray(message.content)) return \"\";\n return message.content\n .filter(\n (item: any) =>\n item &&\n typeof item === \"object\" &&\n item.type === \"text\" &&\n typeof item.text === \"string\",\n )\n .map((item: any) => item.text)\n .join(\"\");\n }\n\n private looksLikeSyntheticAbortFailureText(text: string): boolean {\n const normalized = text.trim().toLowerCase();\n if (!normalized) return false;\n return (\n normalized.includes(\"agent failed before reply:\") &&\n normalized.includes(\"aborted\") &&\n normalized.includes(\"openclaw logs --follow\")\n );\n }\n\n private isSyntheticAbortHistoryMessage(\n message: any,\n sessionKey: string,\n ): boolean {\n const text = this.getAssistantMessageText(message);\n if (!this.looksLikeSyntheticAbortFailureText(text)) return false;\n const messageTimestamp =\n typeof message?.timestamp === \"number\" ? message.timestamp : null;\n const now = Date.now();\n this.pruneRecentAbortedChatRuns(now);\n for (const entry of this.recentAbortedChatRuns.values()) {\n if (entry.sessionKey !== sessionKey) continue;\n if (messageTimestamp === null) return true;\n if (Math.abs(messageTimestamp - entry.abortedAtMs) <= RECENT_ABORTED_CHAT_RUN_TTL_MS) {\n return true;\n }\n }\n return false;\n }\n\n private maybeRewriteGatewayFrame(text: string, frame: any): string | null {\n this.pruneRecentAbortedChatRuns();\n\n if (\n frame?.type === \"event\" &&\n frame?.event === \"chat\" &&\n frame?.payload?.state === \"aborted\"\n ) {\n this.rememberRecentAbortedChatRun(\n frame.payload?.runId,\n frame.payload?.sessionKey,\n );\n return text;\n }\n\n if (frame?.type === \"ack\" && frame?.ok === false && typeof frame?.id === \"string\") {\n this.gatewayReqMetaById.delete(frame.id);\n return text;\n }\n\n let reqMeta: PendingGatewayReqMeta | undefined;\n if (frame?.type === \"res\" && typeof frame?.id === \"string\") {\n reqMeta = this.gatewayReqMetaById.get(frame.id);\n this.gatewayReqMetaById.delete(frame.id);\n }\n\n if (\n frame?.type === \"res\" &&\n frame?.ok === true &&\n reqMeta?.method === \"chat.abort\"\n ) {\n const runIds = Array.isArray(frame?.payload?.runIds)\n ? frame.payload.runIds\n : [];\n for (const runId of runIds) {\n this.rememberRecentAbortedChatRun(runId, reqMeta.sessionKey);\n }\n return text;\n }\n\n if (\n frame?.type === \"event\" &&\n frame?.event === \"chat\" &&\n frame?.payload?.state === \"final\"\n ) {\n const runId = this.normalizeRunId(frame?.payload?.runId);\n const assistantText = this.getAssistantMessageText(frame?.payload?.message);\n const recentAbort = runId ? this.recentAbortedChatRuns.get(runId) : undefined;\n if (\n recentAbort &&\n this.looksLikeSyntheticAbortFailureText(assistantText)\n ) {\n this.opts.logger.info(\n `TunnelProxy: suppressing synthetic abort failure final for runId=${runId}`,\n );\n return null;\n }\n return text;\n }\n\n if (\n frame?.type === \"res\" &&\n frame?.ok === true &&\n reqMeta?.method === \"chat.history\" &&\n Array.isArray(frame?.payload?.messages)\n ) {\n const sessionKey =\n this.normalizeSessionKey(frame?.payload?.sessionKey) ?? reqMeta.sessionKey;\n if (!sessionKey) return text;\n const filteredMessages = frame.payload.messages.filter(\n (message: any) =>\n !this.isSyntheticAbortHistoryMessage(message, sessionKey),\n );\n if (filteredMessages.length === frame.payload.messages.length) {\n return text;\n }\n this.opts.logger.info(\n `TunnelProxy: removed ${frame.payload.messages.length - filteredMessages.length} synthetic abort history message(s) for session=${sessionKey}`,\n );\n return JSON.stringify({\n ...frame,\n payload: {\n ...frame.payload,\n messages: filteredMessages,\n },\n });\n }\n\n return text;\n }\n\n /** 确保到本地 Gateway 的 RPC WebSocket 已连接且握手完成 */\n private ensureGatewayWs(): void {\n if (this.gatewayWsReady && this.gatewayWs?.readyState === WebSocket.OPEN)\n return;\n if (this.gatewayWsConnecting) return;\n\n this.gatewayWsConnecting = true;\n this.gatewayWsReady = false;\n const wsUrl = this.opts.gatewayBaseUrl.replace(/^http/, \"ws\");\n\n this.opts.logger.info(\n `TunnelProxy: RPC WS connecting to gateway ${wsUrl} (pending=${this.gatewayWsPending.length})`,\n );\n\n const ws = new WebSocket(wsUrl);\n\n ws.on(\"open\", () => {\n this.gatewayWs = ws;\n this.opts.logger.info(\n `TunnelProxy: RPC WS tcp connected, waiting for connect.challenge (pending=${this.gatewayWsPending.length})`,\n );\n });\n\n ws.on(\"message\", async (data: WebSocket.RawData) => {\n let text: string;\n if (typeof data === \"string\") {\n text = data;\n } else if (Buffer.isBuffer(data)) {\n text = data.toString();\n } else {\n text = Buffer.from(data as ArrayBuffer).toString();\n }\n\n const preview = text.length <= 500 ? text : text.substring(0, 500) + \"…\";\n this.opts.logger.info(\n `TunnelProxy: RPC WS ← gateway (${text.length} chars): ${preview}`,\n );\n\n let frame: any;\n try {\n frame = JSON.parse(text);\n } catch {\n this.opts.logger.warn(\n \"TunnelProxy: RPC WS received non-JSON, ignoring\",\n );\n return;\n }\n\n // 1) 收到 connect.challenge → 回复 connect 请求(带设备身份签名)\n if (frame.type === \"event\" && frame.event === \"connect.challenge\") {\n this.handleConnectChallenge(ws, frame);\n return;\n }\n\n // 2) 收到 connect 的 hello-ok 响应 → 握手完成,flush 待发帧\n if (\n frame.type === \"res\" &&\n frame.ok === true &&\n frame.payload?.type === \"hello-ok\"\n ) {\n this.storeIssuedDeviceToken({\n fallbackRole: \"operator\",\n fallbackScopes: [\"operator.admin\"],\n authInfo: frame.payload?.auth,\n });\n this.gatewayWsAutoPairingApprovals = 0;\n this.gatewayWsReconnectRequested = false;\n this.gatewayWsReady = true;\n this.gatewayWsConnecting = false;\n this.opts.logger.info(\n `TunnelProxy: RPC WS handshake done (hello-ok), flushing ${this.gatewayWsPending.length} pending frames`,\n );\n for (const pending of this.gatewayWsPending) {\n ws.send(pending);\n }\n this.gatewayWsPending = [];\n return;\n }\n\n // 3) 收到 connect 失败响应 → 关闭连接\n if (frame.type === \"res\" && frame.ok === false && !this.gatewayWsReady) {\n const autoApproved = await this.maybeAutoApproveGatewayPairing(frame);\n if (autoApproved) {\n const wsAlreadyClosed =\n ws.readyState === WebSocket.CLOSING ||\n ws.readyState === WebSocket.CLOSED ||\n this.gatewayWs !== ws;\n this.opts.logger.info(\n `TunnelProxy: RPC WS handshake requested local pairing approval, reconnecting${wsAlreadyClosed ? \" immediately\" : \" after close\"} (pending=${this.gatewayWsPending.length})`,\n );\n if (wsAlreadyClosed) {\n this.gatewayWsReconnectRequested = false;\n this.ensureGatewayWs();\n return;\n }\n ws.close(1000, \"pairing approved, reconnecting\");\n return;\n }\n this.opts.logger.error(\n `TunnelProxy: RPC WS handshake failed (pending=${this.gatewayWsPending.length}): ${previewText(JSON.stringify(frame.error), 500)}`,\n );\n ws.close();\n return;\n }\n\n // 4) 握手后的普通消息 → 透传回 Relay\n const rewritten = this.maybeRewriteGatewayFrame(text, frame);\n if (rewritten !== null) {\n this.opts.client.sendRaw(rewritten);\n }\n });\n\n ws.on(\"close\", (code: number, reason: Buffer) => {\n const wasReady = this.gatewayWsReady;\n const pendingCount = this.gatewayWsPending.length;\n const reasonText = reason.toString();\n const shouldReconnect =\n this.gatewayWsReconnectRequested && pendingCount > 0;\n this.opts.logger.info(\n `TunnelProxy: RPC WS closed by gateway (code=${code}, reason=${reasonText}, ready=${wasReady}, pending=${pendingCount}, activeWs=${this.wsProxy.activeCount})`,\n );\n if (this.gatewayWs === ws) {\n this.gatewayWs = null;\n this.gatewayWsReady = false;\n }\n this.gatewayWsConnecting = false;\n this.maybeClearStoredDeviceTokenOnMismatch(code, reasonText);\n if (shouldReconnect) {\n this.gatewayWsReconnectRequested = false;\n this.opts.logger.info(\n `TunnelProxy: retrying RPC WS after local pairing approval (pending=${this.gatewayWsPending.length})`,\n );\n queueMicrotask(() => this.ensureGatewayWs());\n }\n });\n\n ws.on(\"error\", (err: Error) => {\n this.opts.logger.warn(\n `TunnelProxy: RPC WS error: ${err.message} (ready=${this.gatewayWsReady}, pending=${this.gatewayWsPending.length}, activeWs=${this.wsProxy.activeCount})`,\n );\n this.gatewayWsConnecting = false;\n if (this.gatewayWs === ws) {\n this.gatewayWs = null;\n this.gatewayWsReady = false;\n }\n });\n }\n\n private handleConnectChallenge(ws: WebSocket, frame: any): void {\n const challengeNonce: string = frame.payload?.nonce ?? \"\";\n const connectRequestId = `tunnel-connect-${randomUUID()}`;\n const role = \"operator\";\n const scopes = [\"operator.admin\"];\n const gatewayConnectAuth = this.buildGatewayConnectAuth(role);\n this.opts.logger.info(\n `TunnelProxy: received connect.challenge (nonce=${challengeNonce}, connectReqId=${connectRequestId}, hasToken=${!!gatewayConnectAuth.authToken}, hasPassword=${!!gatewayConnectAuth.authPassword}, hasDeviceToken=${!!gatewayConnectAuth.deviceToken}), sending connect request with device identity`,\n );\n\n const signedAtMs = Date.now();\n const clientId = \"gateway-client\";\n const clientMode = \"backend\";\n\n const authPayload = buildDeviceAuthPayload({\n deviceId: this.deviceIdentity.deviceId,\n clientId,\n clientMode,\n role,\n scopes,\n signedAtMs,\n token: gatewayConnectAuth.authToken ?? null,\n nonce: challengeNonce,\n });\n const signature = signDevicePayload(\n this.deviceIdentity.privateKeyPem,\n authPayload,\n );\n\n const connectReq = {\n type: \"req\",\n id: connectRequestId,\n method: \"connect\",\n params: {\n minProtocol: 3,\n maxProtocol: 3,\n client: {\n id: clientId,\n version: \"1.0.0\",\n platform: process.platform,\n mode: clientMode,\n instanceId: RELAY_TUNNEL_GATEWAY_CLIENT_INSTANCE_ID,\n },\n role,\n scopes,\n ...(gatewayConnectAuth.auth ? { auth: gatewayConnectAuth.auth } : {}),\n device: {\n id: this.deviceIdentity.deviceId,\n publicKey: publicKeyRawBase64UrlFromPem(\n this.deviceIdentity.publicKeyPem,\n ),\n signature,\n signedAt: signedAtMs,\n nonce: challengeNonce,\n },\n },\n };\n ws.send(JSON.stringify(connectReq));\n }\n}\n","export function previewText(text: string | undefined, max = 200): string {\n if (!text) return \"\";\n return text.length <= max ? text : `${text.substring(0, max)}…`;\n}\n\nexport function findHeaderValue(\n headers: Record<string, string> | undefined,\n key: string,\n): string | undefined {\n if (!headers) return undefined;\n const lowerKey = key.toLowerCase();\n for (const [headerKey, headerValue] of Object.entries(headers)) {\n if (headerKey.toLowerCase() === lowerKey) {\n return headerValue;\n }\n }\n return undefined;\n}\n\nexport function summarizeRequestHeaders(headers: Record<string, string> | undefined): string {\n const contentType = findHeaderValue(headers, \"content-type\");\n const requestId = findHeaderValue(headers, \"x-request-id\");\n const parts: string[] = [];\n if (contentType) {\n parts.push(`contentType=${contentType}`);\n }\n if (requestId) {\n parts.push(`xRequestId=${previewText(requestId, 120)}`);\n }\n return parts.length ? `, ${parts.join(\", \")}` : \"\";\n}\n","import crypto from \"node:crypto\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { resolveStateDir as resolveHostStateDir } from \"../host.js\";\n\n// ─── Types ───\n\nexport interface DeviceIdentity {\n deviceId: string;\n publicKeyPem: string;\n privateKeyPem: string;\n}\n\nexport interface DeviceAuthEntry {\n token: string;\n role: string;\n scopes: string[];\n updatedAtMs: number;\n}\n\ninterface DeviceAuthStore {\n version: 1;\n deviceId: string;\n tokens: Record<string, DeviceAuthEntry>;\n}\n\n// ─── Crypto helpers ───\n\nconst ED25519_SPKI_PREFIX = Buffer.from(\"302a300506032b6570032100\", \"hex\");\n\nexport function base64UrlEncode(buf: Buffer): string {\n return buf\n .toString(\"base64\")\n .replaceAll(\"+\", \"-\")\n .replaceAll(\"/\", \"_\")\n .replace(/=+$/g, \"\");\n}\n\nexport function derivePublicKeyRaw(publicKeyPem: string): Buffer {\n const spki = crypto.createPublicKey(publicKeyPem).export({\n type: \"spki\",\n format: \"der\",\n });\n if (\n spki.length === ED25519_SPKI_PREFIX.length + 32 &&\n spki.subarray(0, ED25519_SPKI_PREFIX.length).equals(ED25519_SPKI_PREFIX)\n )\n return spki.subarray(ED25519_SPKI_PREFIX.length);\n return spki;\n}\n\nexport function fingerprintPublicKey(publicKeyPem: string): string {\n const raw = derivePublicKeyRaw(publicKeyPem);\n return crypto.createHash(\"sha256\").update(raw).digest(\"hex\");\n}\n\nexport function publicKeyRawBase64UrlFromPem(publicKeyPem: string): string {\n return base64UrlEncode(derivePublicKeyRaw(publicKeyPem));\n}\n\nexport function signDevicePayload(privateKeyPem: string, payload: string): string {\n const key = crypto.createPrivateKey(privateKeyPem);\n return base64UrlEncode(crypto.sign(null, Buffer.from(payload, \"utf8\"), key));\n}\n\nexport function buildDeviceAuthPayload(params: {\n deviceId: string;\n clientId: string;\n clientMode: string;\n role: string;\n scopes: string[];\n signedAtMs: number;\n token: string | null;\n nonce: string;\n}): string {\n const scopes = params.scopes.join(\",\");\n const token = params.token ?? \"\";\n return [\n \"v2\",\n params.deviceId,\n params.clientId,\n params.clientMode,\n params.role,\n scopes,\n String(params.signedAtMs),\n token,\n params.nonce,\n ].join(\"|\");\n}\n\n// ─── File I/O helpers ───\n\nexport function resolveClientStateDir(stateDir: string | undefined): string {\n return stateDir ?? resolveHostStateDir();\n}\n\nfunction ensureDir(filePath: string): void {\n fs.mkdirSync(path.dirname(filePath), { recursive: true });\n}\n\nfunction resolveIdentityPath(stateDir: string): string {\n return path.join(stateDir, \"identity\", \"device.json\");\n}\n\nfunction normalizeDeviceAuthRole(role: string): string {\n return role.trim();\n}\n\nfunction normalizeDeviceAuthScopes(scopes: string[]): string[] {\n const out = new Set<string>();\n for (const scope of scopes) {\n const trimmed = scope.trim();\n if (trimmed) {\n out.add(trimmed);\n }\n }\n return [...out].sort();\n}\n\nfunction resolveDeviceAuthPath(stateDir: string): string {\n return path.join(stateDir, \"identity\", \"device-auth.json\");\n}\n\nfunction readDeviceAuthStore(filePath: string): DeviceAuthStore | null {\n try {\n if (!fs.existsSync(filePath)) return null;\n const raw = fs.readFileSync(filePath, \"utf8\");\n const parsed = JSON.parse(raw);\n if (parsed?.version !== 1 || typeof parsed.deviceId !== \"string\") return null;\n if (!parsed.tokens || typeof parsed.tokens !== \"object\") return null;\n return parsed as DeviceAuthStore;\n } catch {\n return null;\n }\n}\n\nfunction writeDeviceAuthStore(filePath: string, store: DeviceAuthStore): void {\n ensureDir(filePath);\n fs.writeFileSync(filePath, `${JSON.stringify(store, null, 2)}\\n`, {\n mode: 0o600,\n });\n try {\n fs.chmodSync(filePath, 0o600);\n } catch {\n // ignore chmod errors on unsupported filesystems\n }\n}\n\n// ─── Token CRUD ───\n\nexport function loadDeviceAuthToken(params: {\n stateDir: string;\n deviceId: string;\n role: string;\n}): DeviceAuthEntry | null {\n const store = readDeviceAuthStore(resolveDeviceAuthPath(params.stateDir));\n if (!store || store.deviceId !== params.deviceId) return null;\n const entry = store.tokens[normalizeDeviceAuthRole(params.role)];\n if (!entry || typeof entry.token !== \"string\") return null;\n return entry;\n}\n\nexport function storeDeviceAuthToken(params: {\n stateDir: string;\n deviceId: string;\n role: string;\n token: string;\n scopes: string[];\n}): DeviceAuthEntry {\n const filePath = resolveDeviceAuthPath(params.stateDir);\n const existing = readDeviceAuthStore(filePath);\n const role = normalizeDeviceAuthRole(params.role);\n const next: DeviceAuthStore = {\n version: 1,\n deviceId: params.deviceId,\n tokens:\n existing && existing.deviceId === params.deviceId && existing.tokens\n ? { ...existing.tokens }\n : {},\n };\n const entry: DeviceAuthEntry = {\n token: params.token,\n role,\n scopes: normalizeDeviceAuthScopes(params.scopes),\n updatedAtMs: Date.now(),\n };\n next.tokens[role] = entry;\n writeDeviceAuthStore(filePath, next);\n return entry;\n}\n\nexport function clearDeviceAuthToken(params: {\n stateDir: string;\n deviceId: string;\n role: string;\n}): void {\n const filePath = resolveDeviceAuthPath(params.stateDir);\n const store = readDeviceAuthStore(filePath);\n if (!store || store.deviceId !== params.deviceId) return;\n const role = normalizeDeviceAuthRole(params.role);\n if (!store.tokens[role]) return;\n const next: DeviceAuthStore = {\n version: 1,\n deviceId: store.deviceId,\n tokens: { ...store.tokens },\n };\n delete next.tokens[role];\n writeDeviceAuthStore(filePath, next);\n}\n\n// ─── Identity lifecycle ───\n\nexport function loadOrCreateDeviceIdentity(stateDir: string): DeviceIdentity {\n const filePath = resolveIdentityPath(stateDir);\n try {\n if (fs.existsSync(filePath)) {\n const raw = fs.readFileSync(filePath, \"utf8\");\n const parsed = JSON.parse(raw);\n if (\n parsed?.version === 1 &&\n typeof parsed.deviceId === \"string\" &&\n typeof parsed.publicKeyPem === \"string\" &&\n typeof parsed.privateKeyPem === \"string\"\n ) {\n const derivedId = fingerprintPublicKey(parsed.publicKeyPem);\n return {\n deviceId: derivedId,\n publicKeyPem: parsed.publicKeyPem,\n privateKeyPem: parsed.privateKeyPem,\n };\n }\n }\n } catch {\n // fall through to generate\n }\n // Generate new identity\n const { publicKey, privateKey } = crypto.generateKeyPairSync(\"ed25519\");\n const publicKeyPem = publicKey\n .export({ type: \"spki\", format: \"pem\" })\n .toString();\n const privateKeyPem = privateKey\n .export({ type: \"pkcs8\", format: \"pem\" })\n .toString();\n const identity: DeviceIdentity = {\n deviceId: fingerprintPublicKey(publicKeyPem),\n publicKeyPem,\n privateKeyPem,\n };\n fs.mkdirSync(path.dirname(filePath), { recursive: true });\n const stored = {\n version: 1,\n ...identity,\n createdAtMs: Date.now(),\n };\n ensureDir(filePath);\n fs.writeFileSync(filePath, `${JSON.stringify(stored, null, 2)}\\n`, {\n mode: 0o600,\n });\n return identity;\n}\n","import type { RelayClient } from \"./relay-client.js\";\nimport type { RequestFrame } from \"./types.js\";\nimport { previewText, summarizeRequestHeaders } from \"./utils.js\";\n\nexport const RELAY_INTERNAL_HTTP_HEADER = \"x-openclaw-relay-internal\";\n\nexport interface HttpProxyOptions {\n gatewayBaseUrl: string;\n gatewayAuthMode?: \"token\" | \"password\";\n gatewayToken?: string;\n gatewayPassword?: string;\n client: RelayClient;\n logger: {\n info: (msg: string) => void;\n warn: (msg: string) => void;\n error: (msg: string) => void;\n };\n}\n\n// ─── 路径映射 ───\n\nconst PATH_MAP: Record<string, string> = {\n \"/api/message/messageBridge/send\": \"/notifications\",\n};\n\nexport function mapPath(p: string): string {\n return PATH_MAP[p] ?? p;\n}\n\n// ─── Auth helpers ───\n\nfunction resolveGatewayConnectAuth(opts: HttpProxyOptions):\n | { token?: string; password?: string }\n | undefined {\n const token = opts.gatewayToken?.trim() || undefined;\n const password = opts.gatewayPassword?.trim() || undefined;\n if (!token && !password) return undefined;\n return { token, password };\n}\n\nexport function buildLocalGatewayAuthAttempts(\n opts: HttpProxyOptions,\n baseHeaders: Record<string, string>,\n): Array<{ label: string; headers: Record<string, string> }> {\n const auth = resolveGatewayConnectAuth(opts);\n const attempts: Array<{ label: string; headers: Record<string, string> }> = [];\n const seen = new Set<string>();\n const authMode = opts.gatewayAuthMode;\n\n const addAttempt = (kind: \"token\" | \"password\", secret?: string): void => {\n if (!secret) return;\n\n const dedupeKey = `${kind}:${secret}`;\n if (seen.has(dedupeKey)) return;\n seen.add(dedupeKey);\n\n const headers = { ...baseHeaders };\n headers.authorization = `Bearer ${secret}`;\n\n if (kind === \"password\") {\n headers[\"x-openclaw-password\"] = secret;\n } else {\n delete headers[\"x-openclaw-password\"];\n }\n\n attempts.push({\n label: kind === \"token\" ? \"gateway-token\" : \"gateway-password\",\n headers,\n });\n };\n\n if (authMode === \"password\") {\n addAttempt(\"password\", auth?.password);\n addAttempt(\"token\", auth?.token);\n } else {\n addAttempt(\"token\", auth?.token);\n addAttempt(\"password\", auth?.password);\n }\n\n if (attempts.length === 0) {\n attempts.push({\n label: \"no-auth\",\n headers: { ...baseHeaders },\n });\n }\n\n return attempts;\n}\n\n// ─── HTTP request proxy ───\n\nexport async function handleHttpRequest(\n opts: HttpProxyOptions,\n frame: RequestFrame,\n): Promise<void> {\n const mappedPath = mapPath(frame.path);\n const url = new URL(mappedPath, opts.gatewayBaseUrl);\n const startedAtMs = Date.now();\n\n // 代理到本地 gateway 时,替换外部鉴权头为本地 gateway token/password。\n const localHeaders: Record<string, string> = {};\n for (const [k, v] of Object.entries(frame.headers ?? {})) {\n const lower = k.toLowerCase();\n if (lower !== \"authorization\" && lower !== \"x-openclaw-password\") {\n localHeaders[k] = v;\n }\n }\n localHeaders[RELAY_INTERNAL_HTTP_HEADER] = \"1\";\n\n const authAttempts = buildLocalGatewayAuthAttempts(opts, localHeaders);\n opts.logger.info(\n `TunnelProxy: HTTP id=${frame.id} ${frame.method} ${frame.path} → ${url.toString()}${summarizeRequestHeaders(frame.headers)}, authAttempts=${authAttempts.map((a) => a.label).join(\" -> \")}, body=${previewText(frame.body)}`,\n );\n\n try {\n for (let attemptIndex = 0; attemptIndex < authAttempts.length; attemptIndex++) {\n const attempt = authAttempts[attemptIndex];\n opts.logger.info(\n `TunnelProxy: HTTP id=${frame.id} attempt ${attemptIndex + 1}/${authAttempts.length} auth=${attempt.label}`,\n );\n const res = await fetch(url.toString(), {\n method: frame.method,\n headers: attempt.headers,\n body:\n frame.method !== \"GET\" && frame.method !== \"HEAD\"\n ? frame.body\n : undefined,\n });\n\n const hasFallback = attemptIndex < authAttempts.length - 1;\n if (res.status === 401 && hasFallback) {\n const body = await res.text();\n opts.logger.warn(\n `TunnelProxy: HTTP id=${frame.id} local gateway auth via ${attempt.label} returned 401 after ${Date.now() - startedAtMs}ms, retrying next credential${body ? `, body=${previewText(body)}` : \"\"}`,\n );\n continue;\n }\n\n await sendHttpResponse(opts, {\n frameId: frame.id,\n method: frame.method,\n path: mappedPath,\n authLabel: attempt.label,\n startedAtMs,\n res,\n });\n return;\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n opts.logger.error(\n `TunnelProxy: HTTP id=${frame.id} ${frame.method} ${mappedPath} failed after ${Date.now() - startedAtMs}ms: ${message}`,\n );\n opts.client.send({\n type: \"proxy_error\",\n id: frame.id,\n status: 502,\n message: `gateway unreachable: ${message}`,\n });\n }\n}\n\n// ─── Response helpers ───\n\nasync function sendHttpResponse(\n opts: HttpProxyOptions,\n params: {\n frameId: string;\n method: string;\n path: string;\n authLabel: string;\n startedAtMs: number;\n res: Response;\n },\n): Promise<void> {\n const { frameId, method, path, authLabel, startedAtMs, res } = params;\n const contentType = res.headers.get(\"content-type\") ?? \"\";\n const isStreaming = contentType.includes(\"text/event-stream\");\n const elapsedMs = Date.now() - startedAtMs;\n\n opts.logger.info(\n `TunnelProxy: HTTP id=${frameId} ${method} ${path} <= ${res.status} (${elapsedMs}ms, auth=${authLabel}, content-type=${contentType}, streaming=${isStreaming})`,\n );\n\n if (isStreaming && res.body) {\n await streamResponse(opts, frameId, res, startedAtMs);\n return;\n }\n\n const body = await res.text();\n opts.logger.info(\n `TunnelProxy: HTTP id=${frameId} response body=${previewText(body)}`,\n );\n const headers: Record<string, string> = {};\n res.headers.forEach((value, key) => {\n headers[key] = value;\n });\n\n opts.client.send({\n type: \"proxy_response\",\n id: frameId,\n status: res.status,\n headers,\n body,\n });\n}\n\nasync function streamResponse(\n opts: HttpProxyOptions,\n requestId: string,\n res: Response,\n startedAtMs: number,\n): Promise<void> {\n const reader = res.body!.getReader();\n const decoder = new TextDecoder();\n let chunkCount = 0;\n\n opts.logger.info(`TunnelProxy: stream start id=${requestId}`);\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n chunkCount++;\n const chunk = decoder.decode(value, { stream: true });\n opts.logger.info(\n `TunnelProxy: stream delta id=${requestId} chunk#${chunkCount} (${chunk.length} chars)`,\n );\n opts.client.send({\n type: \"stream\",\n id: requestId,\n state: \"delta\",\n data: chunk,\n });\n }\n\n opts.logger.info(\n `TunnelProxy: stream end id=${requestId}, total chunks=${chunkCount}, totalElapsedMs=${Date.now() - startedAtMs}`,\n );\n opts.client.send({\n type: \"stream\",\n id: requestId,\n state: \"end\",\n data: \"\",\n });\n } catch (err) {\n opts.logger.error(\n `TunnelProxy: stream error id=${requestId} after ${chunkCount} chunks and ${Date.now() - startedAtMs}ms: ${err instanceof Error ? err.message : String(err)}`,\n );\n opts.client.send({\n type: \"proxy_error\",\n id: requestId,\n status: 502,\n message: `stream error: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n}\n","import WebSocket from \"ws\";\nimport type { RelayClient } from \"./relay-client.js\";\nimport type { WsOpenFrame, WsDataFrame, WsCloseFrame } from \"./types.js\";\nimport { mapPath } from \"./http-proxy.js\";\n\nexport interface WsProxyOptions {\n gatewayBaseUrl: string;\n client: RelayClient;\n logger: {\n info: (msg: string) => void;\n warn: (msg: string) => void;\n error: (msg: string) => void;\n };\n}\n\nexport class WsProxy {\n /** 活跃的 WebSocket 代理连接,按帧 id 索引 */\n private connections = new Map<string, WebSocket>();\n\n constructor(private readonly opts: WsProxyOptions) {}\n\n get activeCount(): number {\n return this.connections.size;\n }\n\n cleanup(): void {\n for (const [id, ws] of this.connections) {\n this.opts.logger.info(`WsProxy: closing WS id=${id}`);\n try {\n ws.close();\n } catch {\n // ignore\n }\n }\n this.connections.clear();\n }\n\n handleWsOpen(frame: WsOpenFrame): void {\n const wsUrl =\n this.opts.gatewayBaseUrl.replace(/^http/, \"ws\") +\n mapPath(frame.path);\n this.opts.logger.info(\n `TunnelProxy: WS open id=${frame.id}, path=${frame.path} → ${wsUrl}`,\n );\n\n try {\n const ws = new WebSocket(wsUrl, {\n headers: frame.headers,\n });\n\n ws.on(\"open\", () => {\n this.connections.set(frame.id, ws);\n this.opts.logger.info(\n `TunnelProxy: WS id=${frame.id} connected to gateway, active=${this.connections.size}`,\n );\n this.opts.client.send({\n type: \"ws_opened\",\n id: frame.id,\n });\n });\n\n ws.on(\"message\", (data: WebSocket.RawData) => {\n const text =\n typeof data === \"string\"\n ? data\n : Buffer.isBuffer(data)\n ? data.toString()\n : String(data);\n\n this.opts.logger.info(\n `TunnelProxy: WS id=${frame.id} ← gateway data (${text.length} chars): ${text.substring(0, 200)}`,\n );\n this.opts.client.send({\n type: \"ws_data\",\n id: frame.id,\n data: text,\n });\n });\n\n ws.on(\"close\", (code: number, reason: Buffer) => {\n this.connections.delete(frame.id);\n this.opts.logger.info(\n `TunnelProxy: WS id=${frame.id} closed by gateway (code=${code}, reason=${reason.toString()}), active=${this.connections.size}`,\n );\n this.opts.client.send({\n type: \"ws_close\",\n id: frame.id,\n code,\n reason: reason.toString(),\n });\n });\n\n ws.on(\"error\", (err: Error) => {\n this.opts.logger.warn(\n `TunnelProxy: WS id=${frame.id} error: ${err.message}, active=${this.connections.size}`,\n );\n this.connections.delete(frame.id);\n this.opts.client.send({\n type: \"ws_close\",\n id: frame.id,\n code: 1011,\n reason: err.message,\n });\n });\n } catch (err) {\n this.opts.logger.error(\n `TunnelProxy: WS id=${frame.id} failed to connect: ${err instanceof Error ? err.message : String(err)}`,\n );\n this.opts.client.send({\n type: \"ws_close\",\n id: frame.id,\n code: 1011,\n reason: `failed to connect: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n handleWsData(frame: WsDataFrame): void {\n const ws = this.connections.get(frame.id);\n if (ws?.readyState === WebSocket.OPEN) {\n this.opts.logger.info(\n `TunnelProxy: WS id=${frame.id} → gateway data (${frame.data.length} chars): ${frame.data.substring(0, 200)}`,\n );\n ws.send(frame.data);\n } else {\n this.opts.logger.warn(\n `TunnelProxy: WS id=${frame.id} data dropped, ws not open (exists=${!!ws}, readyState=${ws?.readyState ?? \"N/A\"})`,\n );\n }\n }\n\n handleWsClose(frame: WsCloseFrame): void {\n const ws = this.connections.get(frame.id);\n if (ws) {\n this.opts.logger.info(\n `TunnelProxy: WS id=${frame.id} close requested by relay (code=${frame.code ?? 1000}, reason=${frame.reason ?? \"\"})`,\n );\n this.connections.delete(frame.id);\n try {\n ws.close(frame.code ?? 1000, frame.reason ?? \"\");\n } catch {\n // ignore\n }\n } else {\n this.opts.logger.warn(\n `TunnelProxy: WS id=${frame.id} close requested but connection not found`,\n );\n }\n }\n}\n","import { randomBytes } from \"node:crypto\";\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\nimport type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport type { Logger } from \"../logger.js\";\nimport {\n type NotificationIngestResult,\n NotificationStorage,\n type StoredNotification,\n} from \"../notification/storage.js\";\nimport { RELAY_INTERNAL_HTTP_HEADER } from \"../tunnel/http-proxy.js\";\nimport type { RelayTunnelService } from \"../tunnel/service.js\";\nimport type {\n HttpNotificationBody,\n NotificationPushParams,\n RawNotification,\n} from \"../types.js\";\nimport {\n readBody,\n type GatewayMethodRegistrar,\n} from \"./shared.js\";\n\nfunction newIngestId(): string {\n return `ing_${randomBytes(4).toString(\"hex\")}`;\n}\n\nfunction summarizeIncomingBatch(items: RawNotification[]): string {\n const total = items.length;\n if (total === 0) return \"items=0\";\n const now = Date.now();\n let earliest = Number.POSITIVE_INFINITY;\n let latest = Number.NEGATIVE_INFINITY;\n for (const n of items) {\n const t = new Date(n.timestamp).getTime();\n if (Number.isNaN(t)) continue;\n if (t < earliest) earliest = t;\n if (t > latest) latest = t;\n }\n if (!Number.isFinite(earliest)) {\n return `items=${total} (all ts invalid)`;\n }\n const maxLag = now - earliest;\n const minLag = now - latest;\n return `items=${total} earliestTs=${new Date(earliest).toISOString()} lag=${minLag}..${maxLag}ms`;\n}\n\nfunction createEmptyIngestResult(): NotificationIngestResult {\n return {\n received: 0,\n ingested: 0,\n dedupedById: 0,\n dedupedByContent: 0,\n invalid: 0,\n inserted: [],\n };\n}\n\nfunction isRelayInternalHttpRequest(req: IncomingMessage): boolean {\n const header = req.headers?.[RELAY_INTERNAL_HTTP_HEADER];\n if (Array.isArray(header)) {\n return header.includes(\"1\");\n }\n return header === \"1\";\n}\n\n/**\n * 将 ingest 内部结果转成对外响应:丢弃 `inserted` 字段,\n * 它只供插件内部下游链路(如 light-rule agent 评估)使用,\n * 不应该出现在 gateway / HTTP 响应里。\n */\nfunction toIngestResponse(\n result: NotificationIngestResult,\n): Omit<NotificationIngestResult, \"inserted\"> {\n const { inserted: _inserted, ...rest } = result;\n return rest;\n}\n\ninterface NotificationInterfaceDeps {\n api: OpenClawPluginApi;\n logger: Logger;\n getStorage: () => NotificationStorage | null;\n filterNotifications: (items: RawNotification[]) => RawNotification[];\n registerGatewayMethod: GatewayMethodRegistrar;\n tunnelService?: RelayTunnelService | null;\n /** 通知落盘后的钩子,用于触发灯效规则评估。 */\n onAfterIngest?: (\n inserted: StoredNotification[],\n ingestId: string,\n ) => void | Promise<void>;\n}\n\nexport function registerNotificationInterfaces(\n deps: NotificationInterfaceDeps,\n): void {\n const {\n api,\n logger,\n getStorage,\n filterNotifications,\n registerGatewayMethod,\n tunnelService,\n onAfterIngest,\n } = deps;\n\n function triggerAfterIngest(\n inserted: StoredNotification[],\n ingestId: string,\n ): void {\n if (inserted.length === 0 || !onAfterIngest) return;\n logger.info(\n `notifications[${ingestId}]: enqueue ${inserted.length} for light-rule evaluation`,\n );\n void Promise.resolve()\n .then(() => onAfterIngest(inserted, ingestId))\n .catch((err) =>\n logger.warn(\n `notifications[${ingestId}]: onAfterIngest failed: ${err?.message ?? err}`,\n ),\n );\n }\n\n registerGatewayMethod(\n \"notifications.push\",\n async ({ params, respond }) => {\n const storage = getStorage();\n if (!storage) {\n respond(false, null, {\n code: \"NOT_READY\",\n message: \"Storage service not ready\",\n });\n return;\n }\n\n const { items } = params as unknown as NotificationPushParams;\n if (!Array.isArray(items)) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"items must be an array\",\n });\n return;\n }\n\n const ingestId = newIngestId();\n const startMs = Date.now();\n logger.info(\n `notifications[${ingestId}]: gateway notifications.push received ${summarizeIncomingBatch(items)}`,\n );\n\n const filtered = filterNotifications(items);\n if (filtered.length !== items.length) {\n logger.info(\n `notifications[${ingestId}]: filtered ${items.length - filtered.length} ignored-app item(s), kept=${filtered.length}`,\n );\n }\n const result = filtered.length\n ? await storage.ingest(filtered, ingestId)\n : createEmptyIngestResult();\n\n logger.info(\n `notifications[${ingestId}]: ingest done in ${Date.now() - startMs}ms ` +\n `(received=${result.received} ingested=${result.ingested} ` +\n `dedupedById=${result.dedupedById} dedupedByContent=${result.dedupedByContent} invalid=${result.invalid})`,\n );\n\n // 主响应先返回,不阻塞灯效评估\n respond(true, toIngestResponse(result));\n\n // 落盘后异步触发灯效评估(fire-and-forget)\n triggerAfterIngest(result.inserted, ingestId);\n },\n );\n\n api.registerHttpRoute({\n path: \"/notifications\",\n auth: \"gateway\",\n async handler(req: IncomingMessage, res: ServerResponse) {\n if (req.method !== \"POST\") {\n res.writeHead(405, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: \"Method Not Allowed\" }));\n return;\n }\n\n if (!isRelayInternalHttpRequest(req)) {\n await tunnelService?.deactivateForExternalTunnel(\"POST /notifications\");\n }\n\n const storage = getStorage();\n if (!storage) {\n res.writeHead(503, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: \"Service Not Ready\" }));\n return;\n }\n\n let body: HttpNotificationBody;\n try {\n const raw = await readBody(req);\n body = JSON.parse(raw);\n } catch {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: \"Invalid JSON\" }));\n return;\n }\n\n if (!Array.isArray(body.notifications)) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n ok: false,\n error: \"notifications must be an array\",\n }),\n );\n return;\n }\n\n const ingestId = newIngestId();\n const startMs = Date.now();\n logger.info(\n `notifications[${ingestId}]: HTTP POST /notifications received ${summarizeIncomingBatch(body.notifications)}`,\n );\n\n const filtered = filterNotifications(body.notifications);\n if (filtered.length !== body.notifications.length) {\n logger.info(\n `notifications[${ingestId}]: filtered ${body.notifications.length - filtered.length} ignored-app item(s), kept=${filtered.length}`,\n );\n }\n const result = filtered.length\n ? await storage.ingest(filtered, ingestId)\n : createEmptyIngestResult();\n\n logger.info(\n `notifications[${ingestId}]: ingest done in ${Date.now() - startMs}ms ` +\n `(received=${result.received} ingested=${result.ingested} ` +\n `dedupedById=${result.dedupedById} dedupedByContent=${result.dedupedByContent} invalid=${result.invalid})`,\n );\n\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: true, ...toIngestResponse(result) }));\n\n // Relay tunnel 会把手机通知转发到 HTTP 端点;这里也要触发事件驱动灯效评估。\n triggerAfterIngest(result.inserted, ingestId);\n },\n });\n\n logger.info(\"Gateway 通知方法已注册: notifications.push\");\n logger.info(\"HTTP 通知端点已注册: POST /notifications\");\n}\n","import type { IncomingMessage, ServerResponse } from \"node:http\";\nimport type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport type { Logger } from \"../logger.js\";\nimport {\n RecordingStorage,\n canStartTranscription,\n extractSourceTextListFromDocument,\n extractTranscriptTitleFromDocument,\n handleRecordingSync,\n initializeAsr,\n triggerTranscription,\n type RecordingIndexEntry,\n type RecordingStatusEvent,\n validateAsrConfig,\n} from \"../recording/index.js\";\nimport { RELAY_INTERNAL_HTTP_HEADER } from \"../tunnel/http-proxy.js\";\nimport type { RelayTunnelService } from \"../tunnel/service.js\";\nimport type {\n HttpRecordingBody,\n RecordingAsrInitParams,\n RecordingDetail,\n RecordingListItem,\n RecordingListParams,\n RecordingRenameParams,\n RecordingRetranscribeParams,\n RecordingStatusParams,\n RecordingSyncParams,\n RecordingTransferStatus,\n} from \"../types.js\";\nimport {\n readBody,\n trimToUndefined,\n type GatewayMethodRegistrar,\n} from \"./shared.js\";\n\nconst RECORDING_TRANSFER_STATUSES = new Set<RecordingTransferStatus>([\n \"receiving_failed\",\n \"receiving\",\n \"pending_oss_upload\",\n \"uploading_oss\",\n \"oss_uploaded\",\n \"syncing_openclaw\",\n \"sync_failed\",\n \"synced\",\n \"transcribing\",\n \"transcribe_failed\",\n \"transcribed\",\n]);\n\nfunction isRecordingTransferStatus(\n value: string,\n): value is RecordingTransferStatus {\n return RECORDING_TRANSFER_STATUSES.has(value as RecordingTransferStatus);\n}\n\nfunction buildRecordingListItem(entry: RecordingIndexEntry): RecordingListItem {\n return {\n recordingId: entry.id,\n name: entry.metadata.name,\n duration_sec: entry.metadata.duration_sec,\n file_size_bytes: entry.metadata.file_size_bytes,\n created_at: entry.metadata.created_at,\n transfer_status: entry.status,\n marker_count: entry.metadata.markers?.length ?? 0,\n has_audio: !!entry.audioFile,\n has_srt: !!entry.srtFile,\n has_transcript: !!entry.transcriptFile,\n audioFile: entry.audioFile,\n transcriptDataFile: entry.transcriptDataFile,\n transcriptFile: entry.transcriptFile,\n updatedAt: entry.updatedAt,\n ...(entry.lastError ? { error: entry.lastError } : {}),\n };\n}\n\nfunction isRelayInternalHttpRequest(req: IncomingMessage): boolean {\n const header = req.headers?.[RELAY_INTERNAL_HTTP_HEADER];\n if (Array.isArray(header)) {\n return header.includes(\"1\");\n }\n return header === \"1\";\n}\n\nfunction buildRecordingDetail(\n entry: RecordingIndexEntry,\n extras?: Partial<Pick<\n RecordingDetail,\n \"summary\" | \"title\" | \"transcript\" | \"transcriptData\"\n >>,\n): RecordingDetail {\n const title = entry.title?.trim()\n || extras?.title?.trim()\n || entry.metadata.name?.trim()\n || entry.id;\n\n return {\n recordingId: entry.id,\n name: entry.metadata.name,\n duration_sec: entry.metadata.duration_sec,\n file_size_bytes: entry.metadata.file_size_bytes,\n created_at: entry.metadata.created_at,\n location: entry.metadata.location,\n oss_audio_url: entry.metadata.oss_audio_url,\n oss_srt_url: entry.metadata.oss_srt_url,\n markers: entry.metadata.markers ?? [],\n transfer_status: entry.status,\n audioFile: entry.audioFile,\n srtFile: entry.srtFile,\n transcriptDataFile: entry.transcriptDataFile,\n transcriptFile: entry.transcriptFile,\n summaryFile: entry.summaryFile,\n title,\n summary: extras?.summary,\n transcript: extras?.transcript,\n transcriptData: extras?.transcriptData,\n ingestedAt: entry.ingestedAt,\n updatedAt: entry.updatedAt,\n ...(entry.lastError ? { error: entry.lastError } : {}),\n };\n}\n\ninterface RecordingInterfaceDeps {\n api: OpenClawPluginApi;\n logger: Logger;\n asrDataDir: string;\n getRecordingStorage: () => RecordingStorage | null;\n notifyRecordingStatus: (event: RecordingStatusEvent) => void;\n registerGatewayMethod: GatewayMethodRegistrar;\n shouldBroadcastStatusOnHttp: () => boolean;\n tunnelService?: RelayTunnelService | null;\n}\n\nexport function registerRecordingInterfaces(\n deps: RecordingInterfaceDeps,\n): void {\n const {\n api,\n logger,\n asrDataDir,\n getRecordingStorage,\n notifyRecordingStatus,\n registerGatewayMethod,\n shouldBroadcastStatusOnHttp,\n tunnelService,\n } = deps;\n\n registerGatewayMethod(\"recordings.sync\", async ({ params, respond }) => {\n const recordingStorage = getRecordingStorage();\n if (!recordingStorage) {\n respond(false, null, {\n code: \"NOT_READY\",\n message: \"Recording storage service not ready\",\n });\n return;\n }\n\n const {\n recordingId: rawRecordingId,\n recording,\n asr,\n } = params as unknown as RecordingSyncParams;\n const recordingId = trimToUndefined(rawRecordingId);\n if (!recordingId) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"recordingId is required\",\n });\n return;\n }\n\n if (!recording || !recording.oss_audio_url || !recording.created_at) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"recording with oss_audio_url and created_at is required\",\n });\n return;\n }\n\n const asrError = asr ? validateAsrConfig(asr) : undefined;\n if (asrError) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: asrError,\n });\n return;\n }\n\n const result = await handleRecordingSync(\n recordingId,\n recording,\n recordingStorage,\n asr,\n logger,\n { notifyStatus: notifyRecordingStatus },\n );\n respond(\n result.ok,\n result,\n result.ok\n ? undefined\n : {\n code: \"SYNC_FAILED\",\n message: result.error ?? \"Unknown error\",\n },\n );\n });\n\n registerGatewayMethod(\"recordings.list\", async ({ params, respond }) => {\n const recordingStorage = getRecordingStorage();\n if (!recordingStorage) {\n respond(false, null, {\n code: \"NOT_READY\",\n message: \"Recording storage service not ready\",\n });\n return;\n }\n\n const rawStatus = trimToUndefined(\n (params as RecordingListParams | undefined)?.status,\n );\n if (rawStatus && !isRecordingTransferStatus(rawStatus)) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: `invalid recording status: ${rawStatus}`,\n });\n return;\n }\n\n const status = rawStatus as RecordingTransferStatus | undefined;\n const entries = status\n ? recordingStorage.listByStatus(status)\n : recordingStorage.listAll();\n\n respond(true, {\n total: entries.length,\n recordings: entries.map(buildRecordingListItem),\n });\n });\n\n registerGatewayMethod(\"recordings.status\", async ({ params, respond }) => {\n const recordingStorage = getRecordingStorage();\n if (!recordingStorage) {\n respond(false, null, {\n code: \"NOT_READY\",\n message: \"Recording storage service not ready\",\n });\n return;\n }\n\n const { recordingId } = params as unknown as RecordingStatusParams;\n if (!recordingId) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"recordingId is required\",\n });\n return;\n }\n\n const entry = recordingStorage.findById(recordingId);\n if (!entry) {\n respond(false, null, {\n code: \"NOT_FOUND\",\n message: `Recording not found: ${recordingId}`,\n });\n return;\n }\n\n respond(\n true,\n (() => {\n const transcriptDocument =\n recordingStorage.readTranscriptDocument(recordingId);\n\n return buildRecordingDetail(entry, {\n summary: recordingStorage.readSummary(recordingId),\n title: extractTranscriptTitleFromDocument(transcriptDocument),\n transcript: extractSourceTextListFromDocument(transcriptDocument),\n transcriptData: transcriptDocument,\n });\n })(),\n );\n });\n\n registerGatewayMethod(\"recordings.rename\", async ({ params, respond }) => {\n const recordingStorage = getRecordingStorage();\n if (!recordingStorage) {\n respond(false, null, {\n code: \"NOT_READY\",\n message: \"Recording storage service not ready\",\n });\n return;\n }\n\n const { recordingId: rawRecordingId, name: rawName } =\n params as unknown as RecordingRenameParams;\n const recordingId = trimToUndefined(rawRecordingId);\n const name = trimToUndefined(rawName);\n if (!recordingId) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"recordingId is required\",\n });\n return;\n }\n if (!name) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"name is required\",\n });\n return;\n }\n\n const entry = recordingStorage.findById(recordingId);\n if (!entry) {\n respond(false, null, {\n code: \"NOT_FOUND\",\n message: `Recording not found: ${recordingId}`,\n });\n return;\n }\n\n const updated = recordingStorage.rename(recordingId, name);\n respond(true, buildRecordingDetail(updated));\n });\n\n registerGatewayMethod(\"recordings.delete\", async ({ params, respond }) => {\n const recordingStorage = getRecordingStorage();\n if (!recordingStorage) {\n respond(false, null, {\n code: \"NOT_READY\",\n message: \"Recording storage service not ready\",\n });\n return;\n }\n\n const { recordingId, deleteRemote } = params as {\n recordingId: string;\n deleteRemote?: boolean;\n };\n if (!recordingId) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"recordingId is required\",\n });\n return;\n }\n\n if (deleteRemote) {\n const deleted = recordingStorage.delete(recordingId);\n respond(\n deleted,\n { ok: deleted, recordingId, deletedRemote: true },\n deleted\n ? undefined\n : {\n code: \"NOT_FOUND\",\n message: `Recording not found: ${recordingId}`,\n },\n );\n return;\n }\n\n const deleted = recordingStorage.delete(recordingId, {\n localOnly: true,\n });\n respond(\n deleted,\n { ok: deleted, recordingId, deletedRemote: false },\n deleted\n ? undefined\n : {\n code: \"NOT_FOUND\",\n message: `Recording not found: ${recordingId}`,\n },\n );\n });\n\n registerGatewayMethod(\n \"recordings.retranscribe\",\n async ({ params, respond }) => {\n const recordingStorage = getRecordingStorage();\n if (!recordingStorage) {\n respond(false, null, {\n code: \"NOT_READY\",\n message: \"Recording storage service not ready\",\n });\n return;\n }\n\n const { recordingId, asr } =\n params as unknown as RecordingRetranscribeParams;\n if (!recordingId) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"recordingId is required\",\n });\n return;\n }\n\n const asrError = validateAsrConfig(asr);\n if (asrError) {\n respond(false, null, {\n code: \"ASR_NOT_CONFIGURED\",\n message: asrError,\n });\n return;\n }\n\n const entry = recordingStorage.findById(recordingId);\n if (!entry) {\n respond(false, null, {\n code: \"NOT_FOUND\",\n message: `Recording not found: ${recordingId}`,\n });\n return;\n }\n\n if (!canStartTranscription(entry.status)) {\n respond(false, null, {\n code: \"INVALID_STATE\",\n message: `Recording status does not allow retranscribe: ${entry.status}`,\n });\n return;\n }\n\n triggerTranscription(recordingId, recordingStorage, asr, logger, {\n notifyStatus: notifyRecordingStatus,\n }).catch((err) => {\n logger.error(\n `[recordings.retranscribe] 重试转写失败: ${recordingId}, ${err?.message ?? err}`,\n );\n });\n\n respond(true, { ok: true, recordingId, message: \"转写已重新触发\" });\n },\n );\n\n registerGatewayMethod(\"recordings.asr.init\", async ({ params, respond }) => {\n const { asr } = params as unknown as RecordingAsrInitParams;\n const asrError = validateAsrConfig(asr);\n if (asrError) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: asrError,\n });\n return;\n }\n\n const result = await initializeAsr(asr, asrDataDir, logger);\n respond(\n result.ok,\n result,\n result.ok\n ? undefined\n : {\n code: \"ASR_INIT_FAILED\",\n message: result.error ?? \"ASR init failed\",\n },\n );\n });\n\n api.registerHttpRoute({\n path: \"/recordings\",\n auth: \"gateway\",\n async handler(req: IncomingMessage, res: ServerResponse) {\n if (req.method !== \"POST\") {\n res.writeHead(405, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: \"Method Not Allowed\" }));\n return;\n }\n\n if (!isRelayInternalHttpRequest(req)) {\n await tunnelService?.deactivateForExternalTunnel(\"POST /recordings\");\n }\n\n const recordingStorage = getRecordingStorage();\n if (!recordingStorage) {\n res.writeHead(503, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: \"Service Not Ready\" }));\n return;\n }\n\n let body: HttpRecordingBody;\n try {\n const raw = await readBody(req);\n body = JSON.parse(raw);\n } catch {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: \"Invalid JSON\" }));\n return;\n }\n\n const recordingId = trimToUndefined(body.recordingId);\n if (!recordingId) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n ok: false,\n error: \"recordingId is required\",\n }),\n );\n return;\n }\n\n if (!body.recording || !body.recording.oss_audio_url) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n ok: false,\n error: \"recording with oss_audio_url is required\",\n }),\n );\n return;\n }\n\n const asrError = body.asr ? validateAsrConfig(body.asr) : undefined;\n if (asrError) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: asrError }));\n return;\n }\n\n const result = await handleRecordingSync(\n recordingId,\n body.recording,\n recordingStorage,\n body.asr,\n logger,\n shouldBroadcastStatusOnHttp()\n ? { notifyStatus: notifyRecordingStatus }\n : undefined,\n );\n\n res.writeHead(result.ok ? 200 : 500, {\n \"Content-Type\": \"application/json\",\n });\n res.end(JSON.stringify(result));\n },\n } as any);\n\n logger.info(\n \"Gateway 录音方法已注册: recordings.sync / recordings.list / recordings.status / recordings.rename / recordings.delete / recordings.retranscribe / recordings.asr.init\",\n );\n logger.info(\"HTTP 录音端点已注册: POST /recordings\");\n}\n","const PLUGIN_CLI_COMMANDS = new Set([\"ntf\", \"phone-notifications\"]);\nconst GLOBAL_OPTIONS_WITH_VALUE = [\n \"--container\",\n \"--log-level\",\n \"--profile\",\n] as const;\nconst GLOBAL_OPTIONS_WITH_VALUE_SET = new Set<string>(GLOBAL_OPTIONS_WITH_VALUE);\n\nfunction resolvePrimaryCommand(argv = process.argv): string | undefined {\n const args = argv.slice(2);\n\n for (let index = 0; index < args.length; index++) {\n const arg = args[index];\n if (!arg || arg === \"--\") {\n return undefined;\n }\n\n if (GLOBAL_OPTIONS_WITH_VALUE_SET.has(arg)) {\n index++;\n continue;\n }\n\n if (\n GLOBAL_OPTIONS_WITH_VALUE.some((option) => arg.startsWith(`${option}=`))\n ) {\n continue;\n }\n\n if (arg.startsWith(\"-\")) {\n continue;\n }\n\n return arg;\n }\n\n return undefined;\n}\n\nexport function isPluginCliInvocation(argv = process.argv): boolean {\n const primaryCommand = resolvePrimaryCommand(argv);\n return primaryCommand ? PLUGIN_CLI_COMMANDS.has(primaryCommand) : false;\n}\n"],"mappings":"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","names":["import_node_fs","import_node_path","path","import_node_fs","import_node_path","path","import_node_fs","import_node_path","normalizeOptionalText","os","formatBytes","err","renameSync","output","path","import_node_child_process","import_node_fs","import_node_path","import_promises","import_node_stream","import_node_os","getWhisperLocalStatus","downloadModel","resolveModelsDir","transcribeWithWhisperLocal","err","normalizeOptionalText","sleep","normalizeOptionalInteger","import_node_fs","import_node_path","exports","module","exports","module","output","exports","module","exports","module","err","data","exports","module","exports","module","Receiver","err","exports","module","Sender","err","exports","module","exports","module","exports","module","randomBytes","createHash","Readable","URL","Receiver","Sender","WebSocket","err","key","exports","module","WebSocket","err","createWebSocketStream","exports","module","protocol","exports","module","createHash","WebSocket","WebSocketServer","err","import_node_fs","path","import_node_fs","import_node_path","formatDate","import_node_fs","import_node_path","err","err","import_node_crypto","err","err","prepared","import_node_path","trimToUndefined","resolveStateDir","trimToUndefined","import_node_fs","import_node_path","updateConfigRecord","err","err","import_node_path","import_node_fs","path","import_node_fs","import_node_path","import_node_fs","import_node_path","tasksDir","readMeta","writeMeta","checkpointPath","import_node_fs","import_node_os","import_node_path","resolveConfigPath","err","import_node_fs","import_node_path","err","ok","import_node_fs","import_node_path","import_node_fs","import_node_fs","isObject","isObject","import_node_fs","isObject","isObject","err","import_node_readline","import_node_fs","import_node_child_process","import_node_fs","import_node_path","import_node_os","BASE_URL","err","os","import_node_fs","import_node_fs","import_node_path","path","import_node_fs","import_node_crypto","import_node_path","import_node_fs","import_node_path","import_node_fs","import_node_path","import_promises","DEFAULT_TIMEOUT_MS","err","err","err","current","import_node_fs","import_node_path","import_node_fs","import_node_path","import_sender","WebSocket","err","import_node_crypto","previewText","import_node_crypto","import_node_fs","import_node_path","crypto","fs","path","previewText","err","path","err","err","previewText","isProcessAlive","err","err","trimToUndefined","import_node_crypto","err","isRelayInternalHttpRequest","trimToUndefined","deleted","err","err"]}
1
+ {"version":3,"sources":["../src/host.ts","../src/auth/credentials.ts","../src/env.ts","../src/recording/transcript-document.ts","../src/recording/whisper-local.ts","../src/recording/asr.ts","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/constants.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/buffer-util.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/limiter.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/permessage-deflate.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/validation.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/receiver.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/sender.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/event-target.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/extension.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/websocket.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/stream.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/subprotocol.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/websocket-server.js","../src/index.ts","../src/logger.ts","../src/version.ts","../src/light/repeat.ts","../src/cli/helpers.ts","../src/light/validators.ts","../src/light-rules/names.ts","../src/light-rules/storage.ts","../src/light-rules/gateway.ts","../src/light-rules/registry.ts","../src/light/protocol.ts","../src/plugin/light-rules-tools.ts","../src/light-rules/inline-evaluator.ts","../src/light/sender.ts","../src/light-rules/evaluation-scheduler.ts","../src/light-rules/pi-invoker.ts","../src/plugin/auto-update.ts","../src/update/channel.ts","../src/update/index.ts","../src/plugin/runtime-state.ts","../src/plugin/shared.ts","../src/update/checker.ts","../src/update/executor.ts","../src/update/restart.ts","../src/plugin/cli.ts","../src/cli/auth.ts","../src/cli/ntf-query.ts","../src/cli/ntf-search.ts","../src/cli/ntf-summary.ts","../src/cli/ntf-stats.ts","../src/cli/ntf-sync.ts","../src/cli/ntf-monitor.ts","../src/monitor/fetch-gen.ts","../src/cli/light-send.ts","../src/cli/light-setup-tools.ts","../src/cli/tunnel-status.ts","../src/tunnel/status.ts","../src/cli/ntf-storage-path.ts","../src/cli/log-search.ts","../src/cli/env.ts","../src/cli/doctor.ts","../src/cli/doctor/check-dangerous-flags.ts","../src/cli/doctor/check-trusted-proxy.ts","../src/cli/doctor/check-state-dir-perms.ts","../src/cli/doctor/check-tool-policy.ts","../src/cli/doctor/check-credentials.ts","../src/cli/doctor/check-tunnel.ts","../src/cli/doctor/check-node-version.ts","../src/cli/doctor/check-plugin-version.ts","../src/cli/doctor/checkers.ts","../src/cli/rec-list.ts","../src/cli/rec-status.ts","../src/cli/rec-storage-path.ts","../src/cli/rec-setup.ts","../src/cli/update.ts","../src/cli/index.ts","../src/plugin/light-control.ts","../src/plugin/lifecycle.ts","../src/notification/app-name-map.ts","../src/notification/storage.ts","../src/notification/feishu-normalize.ts","../src/recording/storage.ts","../src/recording/state-machine.ts","../src/recording/index.ts","../src/recording/downloader.ts","../src/recording/handler.ts","../src/recording/account-oss.ts","../src/tunnel/service.ts","../src/tunnel/relay-client.ts","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/wrapper.mjs","../src/tunnel/utils.ts","../src/tunnel/proxy.ts","../src/tunnel/device-identity.ts","../src/tunnel/http-proxy.ts","../src/tunnel/ws-proxy.ts","../src/plugin/notifications.ts","../src/plugin/recordings.ts","../src/plugin/runtime-mode.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\n\nexport type HostKind = \"openclaw\" | \"qclaw\";\n\ninterface QClawMeta {\n stateDir?: string;\n configPath?: string;\n}\n\nfunction trimToUndefined(value: unknown): string | undefined {\n if (typeof value !== \"string\") {\n return undefined;\n }\n const trimmed = value.trim();\n return trimmed || undefined;\n}\n\nfunction homeDir(): string {\n return process.env.HOME || process.env.USERPROFILE || \"/tmp\";\n}\n\nfunction expandUserPath(value: string | undefined): string | undefined {\n if (!value) {\n return undefined;\n }\n if (value === \"~\") {\n return homeDir();\n }\n if (value.startsWith(\"~/\")) {\n return join(homeDir(), value.slice(2));\n }\n return value;\n}\n\nfunction detectHostKindFromPath(value: string | undefined): HostKind | undefined {\n if (!value) {\n return undefined;\n }\n const normalized = value.replace(/\\\\/g, \"/\").toLowerCase();\n if (\n normalized.endsWith(\"/.qclaw\") ||\n normalized.includes(\"/.qclaw/\") ||\n normalized.endsWith(\"/.qclow\") ||\n normalized.includes(\"/.qclow/\")\n ) {\n return \"qclaw\";\n }\n if (\n normalized.endsWith(\"/.openclaw\") ||\n normalized.includes(\"/.openclaw/\")\n ) {\n return \"openclaw\";\n }\n return undefined;\n}\n\nfunction candidateMetaPaths(): string[] {\n const home = homeDir();\n return [\n join(home, \".qclaw\", \"qclaw.json\"),\n join(home, \".qclow\", \"qclaw.json\"),\n ];\n}\n\nfunction loadQClawMeta(): QClawMeta | undefined {\n for (const metaPath of candidateMetaPaths()) {\n if (!existsSync(metaPath)) {\n continue;\n }\n try {\n const parsed = JSON.parse(readFileSync(metaPath, \"utf-8\")) as QClawMeta;\n return {\n stateDir: expandUserPath(trimToUndefined(parsed?.stateDir)),\n configPath: expandUserPath(trimToUndefined(parsed?.configPath)),\n };\n } catch {\n // ignore invalid metadata and keep trying\n }\n }\n return undefined;\n}\n\nfunction resolveStateDirFromEnv(): string | undefined {\n return expandUserPath(\n trimToUndefined(process.env.OPENCLAW_STATE_DIR) ??\n trimToUndefined(process.env.QCLAW_STATE_DIR) ??\n trimToUndefined(process.env.OPENCLAW_ROOT) ??\n trimToUndefined(process.env.OPENCLAW_HOME) ??\n trimToUndefined(process.env.QCLAW_HOME),\n );\n}\n\nfunction resolveConfigPathFromEnv(): string | undefined {\n return expandUserPath(\n trimToUndefined(process.env.OPENCLAW_CONFIG_PATH) ??\n trimToUndefined(process.env.QCLAW_CONFIG_PATH),\n );\n}\n\nfunction hasOpenClawMarkers(): boolean {\n const baseDir = join(homeDir(), \".openclaw\");\n return [\n join(baseDir, \"openclaw.json\"),\n join(baseDir, \"credentials.json\"),\n join(baseDir, \"extensions\"),\n ].some((candidate) => existsSync(candidate));\n}\n\nexport function detectHostKind(): HostKind {\n if (\n trimToUndefined(process.env.QCLAW_STATE_DIR) ||\n trimToUndefined(process.env.QCLAW_CONFIG_PATH) ||\n trimToUndefined(process.env.QCLAW_HOME)\n ) {\n return \"qclaw\";\n }\n\n const pathHintKind =\n detectHostKindFromPath(resolveStateDirFromEnv()) ??\n detectHostKindFromPath(resolveConfigPathFromEnv());\n if (pathHintKind) {\n return pathHintKind;\n }\n\n if (hasOpenClawMarkers()) {\n return \"openclaw\";\n }\n\n if (loadQClawMeta()) {\n return \"qclaw\";\n }\n\n return \"openclaw\";\n}\n\nexport function resolveStateDir(): string {\n const envDir = resolveStateDirFromEnv();\n if (envDir) {\n return envDir;\n }\n\n if (hasOpenClawMarkers()) {\n return join(homeDir(), \".openclaw\");\n }\n\n const meta = loadQClawMeta();\n if (meta?.stateDir) {\n return meta.stateDir;\n }\n if (meta?.configPath) {\n return dirname(meta.configPath);\n }\n\n return join(homeDir(), \".openclaw\");\n}\n\nexport function resolveConfigPath(stateDir = resolveStateDir()): string {\n const envConfigPath = resolveConfigPathFromEnv();\n if (envConfigPath) {\n return envConfigPath;\n }\n\n const meta = loadQClawMeta();\n if (\n meta?.configPath &&\n (!meta.stateDir || !stateDir || meta.stateDir === stateDir)\n ) {\n return meta.configPath;\n }\n\n return join(stateDir, \"openclaw.json\");\n}\n\nexport function resolveStateFile(filename: string): string {\n return join(resolveStateDir(), filename);\n}\n","import {\n existsSync,\n mkdirSync,\n readFileSync,\n writeFileSync,\n watch,\n} from \"node:fs\";\nimport { dirname, basename } from \"node:path\";\nimport { resolveStateFile } from \"../host.js\";\n\ninterface Credentials {\n /**\n * 推荐:API Key 明文(例如 ock_xxx)\n */\n apiKey?: string;\n /**\n * 兼容旧字段:历史上这里存的是 token;现在等价于 apiKey\n */\n token?: string;\n /**\n * 当前环境(development / production),由 ntf env switch 写入\n */\n env?: string;\n}\n\nexport function credentialsPath(): string {\n return resolveStateFile(\"credentials.json\");\n}\n\nexport function readCredentials(): Credentials {\n const path = credentialsPath();\n if (!existsSync(path)) return {};\n try {\n return JSON.parse(readFileSync(path, \"utf-8\"));\n } catch {\n return {};\n }\n}\n\nexport function writeCredentials(creds: Credentials): void {\n const path = credentialsPath();\n mkdirSync(dirname(path), { recursive: true, mode: 0o700 });\n writeFileSync(path, JSON.stringify(creds, null, 2), {\n encoding: \"utf-8\",\n mode: 0o600,\n });\n}\n\nexport function loadApiKey(): string | undefined {\n const creds = readCredentials();\n return creds.apiKey ?? creds.token;\n}\n\nexport function requireApiKey(): string {\n const apiKey = loadApiKey();\n if (!apiKey) {\n throw new Error(\n `API Key 未设置,请先写入 ${credentialsPath()},或通过宿主 CLI 执行 ntf auth set-api-key <apiKey>`,\n );\n }\n return apiKey;\n}\n\n// ---- Backward-compatible exports (旧代码仍可编译;语义等价于 apiKey) ----\nexport function loadToken(): string | undefined {\n return loadApiKey();\n}\n\nexport function requireToken(): string {\n return requireApiKey();\n}\n\n/** 监听 credentials 文件变化(如 set-token 后)触发 callback;返回取消监听的函数 */\nexport function watchCredentials(onChange: () => void): () => void {\n const path = credentialsPath();\n const dir = dirname(path);\n const filename = basename(path);\n let debounceTimer: ReturnType<typeof setTimeout> | null = null;\n const delayMs = 200;\n\n const listener = (_event: string, changedName: string | null) => {\n if (!changedName || (changedName !== filename && !changedName.endsWith(filename))) return;\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n debounceTimer = null;\n onChange();\n }, delayMs);\n };\n\n let watcher: ReturnType<typeof watch> | null = null;\n try {\n watcher = watch(dir, { persistent: false }, listener);\n } catch {\n // 目录可能不存在\n }\n\n return () => {\n if (debounceTimer) clearTimeout(debounceTimer);\n watcher?.close();\n };\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { readCredentials } from \"./auth/credentials.js\";\nimport { resolveStateFile } from \"./host.js\";\n\nfunction writeDotEnv(key: string, value: string): void {\n const path = resolveStateFile(\".env\");\n mkdirSync(dirname(path), { recursive: true });\n const existing = existsSync(path) ? readFileSync(path, \"utf-8\") : \"\";\n const lines = existing.split(\"\\n\");\n const prefix = `${key}=`;\n const idx = lines.findIndex((l) => l.startsWith(prefix));\n const newLine = `${prefix}${value}`;\n if (idx >= 0) {\n lines[idx] = newLine;\n } else {\n if (existing && !existing.endsWith(\"\\n\")) lines.push(\"\");\n lines.push(newLine);\n }\n writeFileSync(path, lines.join(\"\\n\"), \"utf-8\");\n}\n\nexport type EnvName = \"development\" | \"test\" | \"production\";\n\ninterface EnvUrls {\n lightApiUrl: string;\n appNameMapUrl: string;\n relayTunnelUrl: string;\n modelProxyLongRecordingSubmitTaskUrl: string;\n modelProxyLongRecordingQueryTaskResultBaseUrl: string;\n accountFileDeleteUrl: string;\n}\n\nconst ENV_HOSTS: Record<EnvName, string> = {\n development: \"openclaw-service-dev.yoooclaw.com\",\n test: \"openclaw-service-test.yoooclaw.com\",\n production: \"openclaw-service.yoooclaw.com\",\n};\n\nfunction buildEnvUrls(host: string): EnvUrls {\n const https = `https://${host}`;\n const wss = `wss://${host}`;\n return {\n lightApiUrl: `${https}/api/message/tob/sendMessage`,\n relayTunnelUrl: `${wss}/message/messages/ws/plugin`,\n appNameMapUrl: `${https}/api/application-config/app-package/config-all`,\n modelProxyLongRecordingSubmitTaskUrl: `${https}/api/model-proxy/long-recording/submit-task`,\n modelProxyLongRecordingQueryTaskResultBaseUrl: `${https}/api/model-proxy/long-recording/query-task-result`,\n accountFileDeleteUrl: `${https}/api/account/file/delete`,\n };\n}\n\nconst ENV_CONFIG: Record<EnvName, EnvUrls> = {\n development: buildEnvUrls(ENV_HOSTS.development),\n test: buildEnvUrls(ENV_HOSTS.test),\n production: buildEnvUrls(ENV_HOSTS.production),\n};\n\nconst VALID_ENVS: ReadonlySet<string> = new Set(Object.keys(ENV_CONFIG));\n\nfunction readDotEnv(): Record<string, string> {\n const path = resolveStateFile(\".env\");\n if (!existsSync(path)) return {};\n return Object.fromEntries(\n readFileSync(path, \"utf-8\")\n .split(\"\\n\")\n .flatMap((line) => {\n const eq = line.indexOf(\"=\");\n if (eq < 1) return [];\n return [[line.slice(0, eq).trim(), line.slice(eq + 1).trim()]];\n }),\n );\n}\n\n/** 读取持久化到 .env 的环境名称;仅反映本地配置,不考虑进程环境变量。 */\nexport function readPersistedEnvName(): EnvName | undefined {\n const fromDotEnv = readDotEnv()[\"PHONE_NOTIFICATIONS_ENV\"]?.trim();\n if (fromDotEnv && VALID_ENVS.has(fromDotEnv)) return fromDotEnv as EnvName;\n return undefined;\n}\n\n/** 读取当前环境名称。优先级:PHONE_NOTIFICATIONS_ENV 环境变量 > .env > credentials.json > 默认 production */\nexport function loadEnvName(): EnvName {\n const fromEnvVar = process.env.PHONE_NOTIFICATIONS_ENV?.trim();\n if (fromEnvVar && VALID_ENVS.has(fromEnvVar)) return fromEnvVar as EnvName;\n\n const fromDotEnv = readPersistedEnvName();\n if (fromDotEnv) return fromDotEnv;\n\n const { env } = readCredentials();\n if (env && VALID_ENVS.has(env)) return env as EnvName;\n\n return \"production\";\n}\n\n/** 持久化当前环境到 .env */\nexport function saveEnvName(env: EnvName): void {\n if (!VALID_ENVS.has(env)) {\n throw new Error(\n `无效的环境名称: ${env},可选值: ${[...VALID_ENVS].join(\", \")}`,\n );\n }\n writeDotEnv(\"PHONE_NOTIFICATIONS_ENV\", env);\n}\n\n/** 获取当前环境的 URL 配置 */\nexport function getEnvUrls(env?: EnvName): EnvUrls {\n return ENV_CONFIG[env ?? loadEnvName()];\n}\n\n/** 获取所有可用环境名称 */\nexport function getAvailableEnvs(): EnvName[] {\n return Object.keys(ENV_CONFIG) as EnvName[];\n}\n","export const TRANSCRIPT_DOCUMENT_SCHEMA_VERSION = 1;\n\nexport interface TranscriptDocumentSource {\n provider: string;\n taskId?: string;\n requestId?: string;\n status?: string;\n}\n\nexport interface TranscriptDocumentSegment {\n text: string;\n startMs?: number;\n endMs?: number;\n speakerId?: number;\n}\n\nexport interface TranscriptDocumentContentItem {\n content: string;\n speakerId?: number;\n startTime?: number;\n endTime?: number;\n}\n\nexport interface TranscriptDocumentNormalized {\n title?: string;\n category?: string;\n summary?: string;\n text: string;\n segments: TranscriptDocumentSegment[];\n}\n\nexport interface TranscriptDocument {\n schemaVersion: number;\n recordingId: string;\n generatedAt: string;\n source: TranscriptDocumentSource;\n normalized: TranscriptDocumentNormalized;\n raw?: unknown;\n}\n\nexport function buildTranscriptDataFilename(recordingId: string): string {\n return `${recordingId}.json`;\n}\n\nexport function buildTranscriptDocument(params: {\n recordingId: string;\n generatedAt?: string;\n source: TranscriptDocumentSource;\n title?: string;\n category?: string;\n summary?: string;\n text?: string;\n segments?: TranscriptDocumentSegment[];\n raw?: unknown;\n}): TranscriptDocument {\n const segments = normalizeSegments(params.segments);\n const text = normalizePossiblyEmptyText(params.text) ?? joinSegmentsText(segments) ?? \"\";\n\n return {\n schemaVersion: TRANSCRIPT_DOCUMENT_SCHEMA_VERSION,\n recordingId: params.recordingId,\n generatedAt: params.generatedAt ?? new Date().toISOString(),\n source: {\n provider: params.source.provider,\n taskId: normalizeOptionalText(params.source.taskId),\n requestId: normalizeOptionalText(params.source.requestId),\n status: normalizeOptionalText(params.source.status),\n },\n normalized: {\n title: normalizeOptionalText(params.title),\n category: normalizeOptionalText(params.category),\n summary: normalizePossiblyEmptyText(params.summary),\n text,\n segments,\n },\n raw: params.raw,\n };\n}\n\nexport function parseTranscriptDocument(\n value: string | unknown,\n): TranscriptDocument | undefined {\n const parsed = typeof value === \"string\"\n ? parseJson(value)\n : value;\n\n if (!parsed || typeof parsed !== \"object\") {\n return undefined;\n }\n\n const doc = parsed as Record<string, unknown>;\n const recordingId = normalizeOptionalText(doc.recordingId);\n const generatedAt = normalizeOptionalText(doc.generatedAt);\n const source = normalizeSource(doc.source);\n const normalized = normalizeDocumentBody(doc.normalized);\n\n if (!recordingId || !generatedAt || !source || !normalized) {\n return undefined;\n }\n\n return {\n schemaVersion:\n typeof doc.schemaVersion === \"number\"\n ? doc.schemaVersion\n : TRANSCRIPT_DOCUMENT_SCHEMA_VERSION,\n recordingId,\n generatedAt,\n source,\n normalized,\n raw: doc.raw,\n };\n}\n\nexport function extractTranscriptTextFromDocument(\n doc: TranscriptDocument | undefined,\n): string | undefined {\n if (!doc) return undefined;\n return normalizePossiblyEmptyText(doc.normalized.text)\n ?? joinSegmentsText(doc.normalized.segments);\n}\n\nexport function extractTranscriptSummaryFromDocument(\n doc: TranscriptDocument | undefined,\n): string | undefined {\n if (!doc) return undefined;\n return normalizePossiblyEmptyText(doc.normalized.summary);\n}\n\nexport function extractTranscriptTitleFromDocument(\n doc: TranscriptDocument | undefined,\n): string | undefined {\n if (!doc) return undefined;\n return normalizeOptionalText(doc.normalized.title);\n}\n\nexport function extractSourceTextListFromDocument(\n doc: TranscriptDocument | undefined,\n): TranscriptDocumentContentItem[] | undefined {\n if (!doc) return undefined;\n\n const fromNormalized = doc.normalized.segments\n .map((segment) => ({\n content: segment.text,\n speakerId: segment.speakerId,\n startTime: segment.startMs,\n endTime: segment.endMs,\n }))\n .filter((segment) => normalizeOptionalText(segment.content));\n\n if (fromNormalized.length > 0) {\n return fromNormalized;\n }\n\n const rawList = extractRawSourceTextList(doc.raw);\n if (rawList.length > 0) {\n return rawList;\n }\n\n const normalizedText = normalizeOptionalText(doc.normalized.text);\n return normalizedText\n ? [{ content: normalizedText }]\n : undefined;\n}\n\nfunction parseJson(value: string): unknown {\n try {\n return JSON.parse(value);\n } catch {\n return undefined;\n }\n}\n\nfunction normalizeSource(value: unknown): TranscriptDocumentSource | undefined {\n if (!value || typeof value !== \"object\") {\n return undefined;\n }\n\n const source = value as Record<string, unknown>;\n const provider = normalizeOptionalText(source.provider);\n if (!provider) {\n return undefined;\n }\n\n return {\n provider,\n taskId: normalizeOptionalText(source.taskId),\n requestId: normalizeOptionalText(source.requestId),\n status: normalizeOptionalText(source.status),\n };\n}\n\nfunction normalizeDocumentBody(\n value: unknown,\n): TranscriptDocumentNormalized | undefined {\n if (!value || typeof value !== \"object\") {\n return undefined;\n }\n\n const normalized = value as Record<string, unknown>;\n const segments = normalizeSegments(normalized.segments);\n const text = normalizePossiblyEmptyText(normalized.text) ?? joinSegmentsText(segments);\n if (text === undefined) {\n return undefined;\n }\n\n return {\n title: normalizeOptionalText(normalized.title),\n category: normalizeOptionalText(normalized.category),\n summary: normalizePossiblyEmptyText(normalized.summary),\n text,\n segments,\n };\n}\n\nfunction normalizeSegments(value: unknown): TranscriptDocumentSegment[] {\n if (!Array.isArray(value)) {\n return [];\n }\n\n return value\n .map((item) => normalizeSegment(item))\n .filter((item): item is TranscriptDocumentSegment => !!item);\n}\n\nfunction normalizeSegment(value: unknown): TranscriptDocumentSegment | undefined {\n if (!value || typeof value !== \"object\") {\n return undefined;\n }\n\n const segment = value as Record<string, unknown>;\n const text = normalizeOptionalText(segment.text);\n if (!text) {\n return undefined;\n }\n\n return {\n text,\n startMs: normalizeOptionalNumber(segment.startMs),\n endMs: normalizeOptionalNumber(segment.endMs),\n speakerId: normalizeOptionalInteger(segment.speakerId),\n };\n}\n\nfunction joinSegmentsText(\n segments: TranscriptDocumentSegment[],\n): string | undefined {\n const parts = segments\n .map((segment) => normalizeOptionalText(segment.text))\n .filter((segment): segment is string => !!segment);\n\n if (parts.length === 0) {\n return undefined;\n }\n\n return parts.join(\"\\n\\n\");\n}\n\nfunction extractRawSourceTextList(raw: unknown): TranscriptDocumentContentItem[] {\n if (!raw || typeof raw !== \"object\") {\n return [];\n }\n\n const recordResult = (raw as { recordResult?: unknown }).recordResult;\n if (!recordResult || typeof recordResult !== \"object\") {\n return [];\n }\n\n const sourceTextList = (recordResult as { sourceTextList?: unknown }).sourceTextList;\n if (!Array.isArray(sourceTextList)) {\n return [];\n }\n\n return sourceTextList\n .flatMap((item) => {\n if (!item || typeof item !== \"object\") {\n return [];\n }\n\n const value = item as Record<string, unknown>;\n const content = normalizeOptionalText(value.content);\n if (!content) {\n return [];\n }\n\n return [{\n content,\n speakerId: normalizeOptionalInteger(value.speakerId),\n startTime: normalizeOptionalNumber(value.startTime),\n endTime: normalizeOptionalNumber(value.endTime),\n }];\n });\n}\n\nfunction normalizeOptionalText(value: unknown): string | undefined {\n return typeof value === \"string\" && value.trim()\n ? value.trim()\n : undefined;\n}\n\nfunction normalizePossiblyEmptyText(value: unknown): string | undefined {\n return typeof value === \"string\"\n ? value.trim()\n : undefined;\n}\n\nfunction normalizeOptionalNumber(value: unknown): number | undefined {\n return typeof value === \"number\" && Number.isFinite(value)\n ? value\n : undefined;\n}\n\nfunction normalizeOptionalInteger(value: unknown): number | undefined {\n return Number.isInteger(value)\n ? Number(value)\n : undefined;\n}\n","/**\n * 本地 Whisper 转写模块(arc-long-recording §6.4)\n *\n * 插件内置 Whisper 推理能力:\n * 1. 自动检测运行环境与硬件配置(§6.4.1)\n * 2. 选择最优推理后端(§6.4.2)\n * 3. 根据可用内存自动选择模型规格(§6.4.3)\n * 4. 首次使用时下载模型文件(§6.4.5)\n * 5. 通过 whisper.cpp CLI 执行本地离线转写\n */\n\nimport { execSync, execFileSync, spawnSync, type SpawnSyncReturns } from \"node:child_process\";\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n statSync,\n createWriteStream,\n unlinkSync,\n copyFileSync,\n openSync,\n readSync,\n closeSync,\n} from \"node:fs\";\nimport { join, dirname, basename } from \"node:path\";\nimport { pipeline } from \"node:stream/promises\";\nimport { Readable } from \"node:stream\";\nimport { platform, arch, totalmem, cpus, freemem } from \"node:os\";\nimport type {\n WhisperLocalConfig,\n WhisperModelSize,\n WhisperModelSource,\n WhisperBackend,\n WhisperEnvironmentInfo,\n} from \"../types.js\";\nimport type { Logger } from \"../logger.js\";\nimport type { TranscriptionResult, TranscriptSegment } from \"./asr.js\";\n\n// ─── Constants ───\n\nconst WHISPER_MODELS_DIR = \"whisper-models\";\nconst WHISPER_BIN_DIR = \"whisper-bin\";\n\n/** Hugging Face GGML 模型下载 URL 模板(海外) */\nconst HF_MODEL_URL_TEMPLATE =\n \"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-{model}.bin\";\n\n/** 国内 ModelScope 镜像 URL 模板(lihuoo/whisper.cpp-asr-model-collection) */\nconst MODELSCOPE_MODEL_URL_TEMPLATE =\n \"https://modelscope.cn/models/lihuoo/whisper.cpp-asr-model-collection/resolve/master/{model}.bin\";\n\n/** 连通性探测超时(ms) */\nconst PROBE_TIMEOUT_MS = 5_000;\n\n/** 模型规格 → 文件名映射 */\nconst MODEL_FILENAMES: Record<WhisperModelSize, string> = {\n tiny: \"ggml-tiny.bin\",\n base: \"ggml-base.bin\",\n small: \"ggml-small.bin\",\n medium: \"ggml-medium.bin\",\n \"large-v3\": \"ggml-large-v3.bin\",\n};\n\n/** 模型规格 → 推理内存需求 GB(§6.4.3) */\nconst MODEL_MEMORY_REQUIREMENTS: Record<WhisperModelSize, number> = {\n tiny: 1,\n base: 1.5,\n small: 3,\n medium: 6,\n \"large-v3\": 11,\n};\n\n/** 模型规格 → 磁盘占用(字节,近似值) */\nconst MODEL_DISK_SIZES: Record<WhisperModelSize, number> = {\n tiny: 75 * 1024 * 1024,\n base: 140 * 1024 * 1024,\n small: 460 * 1024 * 1024,\n medium: 1500 * 1024 * 1024,\n \"large-v3\": 3000 * 1024 * 1024,\n};\n\n/** whisper.cpp JSON 输出格式 */\ninterface WhisperCppJsonOutput {\n transcription?: Array<{\n timestamps?: { from: string; to: string };\n offsets?: { from: number; to: number };\n text: string;\n }>;\n}\n\n// ─── Public API ───\n\n/**\n * 检测运行环境与硬件配置(§6.4.1)\n *\n * 检测操作系统、CPU 架构、GPU、可用内存,\n * 推荐最优推理后端与模型规格。\n */\nexport function detectEnvironment(logger: Logger): WhisperEnvironmentInfo {\n const os = platform() as \"darwin\" | \"linux\" | \"win32\";\n const cpuArch = arch() as \"arm64\" | \"x64\";\n const isAppleSilicon = os === \"darwin\" && cpuArch === \"arm64\";\n const hasCuda = detectCuda(logger);\n\n // 推荐后端(§6.4.2)\n let recommendedBackend: WhisperBackend;\n if (isAppleSilicon) {\n recommendedBackend = \"coreml\";\n } else if (hasCuda) {\n recommendedBackend = \"cuda\";\n } else {\n recommendedBackend = \"cpu\";\n }\n\n // 可用内存\n const availableMemoryGB = getAvailableMemoryGB(recommendedBackend, logger);\n const physicalCores = getPhysicalCoreCount();\n\n // 推荐模型\n const recommendedModel = selectModelByMemory(availableMemoryGB, isAppleSilicon);\n\n const info: WhisperEnvironmentInfo = {\n os,\n arch: cpuArch,\n isAppleSilicon,\n hasCuda,\n recommendedBackend,\n availableMemoryGB: Math.round(availableMemoryGB * 10) / 10,\n recommendedModel,\n physicalCores,\n };\n\n logger.info(\n `[whisper-local] 环境检测完成: os=${os}, arch=${cpuArch}, ` +\n `appleSilicon=${isAppleSilicon}, cuda=${hasCuda}, ` +\n `backend=${recommendedBackend}, memory=${info.availableMemoryGB}GB, ` +\n `model=${recommendedModel}, cores=${physicalCores}`,\n );\n\n return info;\n}\n\n/**\n * 根据可用内存自动选择模型规格(§6.4.3)\n *\n * 策略:优先匹配可用内存最大能承载的模型(向下取最近档位)。\n * Apple Silicon CoreML 后端内存效率更高,同档位需求降低 ~30%。\n */\nexport function selectModelByMemory(\n availableGB: number,\n isAppleSilicon: boolean = false,\n): WhisperModelSize {\n // Apple Silicon CoreML 内存效率提升约 30%\n const effectiveGB = isAppleSilicon ? availableGB / 0.7 : availableGB;\n\n if (effectiveGB >= 12) return \"large-v3\";\n if (effectiveGB >= 8) return \"medium\";\n if (effectiveGB >= 6) return \"small\";\n if (effectiveGB >= 4) return \"base\";\n return \"tiny\";\n}\n\n/**\n * 解析模型存储目录\n */\nexport function resolveModelsDir(dataDir: string): string {\n const dir = join(dataDir, WHISPER_MODELS_DIR);\n mkdirSync(dir, { recursive: true });\n return dir;\n}\n\n/**\n * 解析 whisper.cpp 二进制目录\n */\nexport function resolveBinDir(dataDir: string): string {\n const dir = join(dataDir, WHISPER_BIN_DIR);\n mkdirSync(dir, { recursive: true });\n return dir;\n}\n\n/**\n * 检查模型文件是否已下载(§6.4.5)\n */\nexport function isModelDownloaded(modelsDir: string, modelSize: WhisperModelSize): boolean {\n const modelPath = join(modelsDir, MODEL_FILENAMES[modelSize]);\n if (!existsSync(modelPath)) return false;\n\n // 简单校验:文件大小至少为预期大小的 80%(防止下载不完整)\n try {\n const stat = statSync(modelPath);\n const expectedSize = MODEL_DISK_SIZES[modelSize];\n return stat.size >= expectedSize * 0.8;\n } catch {\n return false;\n }\n}\n\n/**\n * 下载 Whisper 模型文件(§6.4.5)\n *\n * 下载源选择策略:\n * - modelMirrorUrl 存在 → 使用自定义 URL\n * - modelSource = \"huggingface\" → 直接使用 Hugging Face\n * - modelSource = \"domestic\" → 直接使用国内镜像(ModelScope)\n * - modelSource = \"auto\"(默认)→ 先探测 Hugging Face 连通性(5s 超时),\n * 可达则用 HF,不可达则回退国内镜像\n */\nexport async function downloadModel(\n modelsDir: string,\n modelSize: WhisperModelSize,\n logger: Logger,\n modelSource?: WhisperModelSource,\n mirrorUrl?: string,\n): Promise<{ ok: boolean; modelPath: string; error?: string }> {\n const filename = MODEL_FILENAMES[modelSize];\n const modelPath = join(modelsDir, filename);\n\n // 已存在且完整 → 跳过\n if (isModelDownloaded(modelsDir, modelSize)) {\n logger.info(`[whisper-local] 模型已存在,跳过下载: ${filename}`);\n return { ok: true, modelPath };\n }\n\n // 解析下载 URL\n const url = await resolveModelUrl(modelSize, modelSource, mirrorUrl, logger);\n\n logger.info(\n `[whisper-local] 开始下载模型: ${modelSize} (${formatBytes(MODEL_DISK_SIZES[modelSize])})`,\n );\n logger.info(`[whisper-local] 下载 URL: ${url}`);\n\n const result = await downloadFromUrl(url, modelPath, logger);\n\n // auto 模式且 HF 失败 → 尝试国内镜像回退\n if (\n !result.ok &&\n !mirrorUrl &&\n (modelSource === \"auto\" || !modelSource) &&\n url.includes(\"huggingface.co\")\n ) {\n const fallbackUrl = MODELSCOPE_MODEL_URL_TEMPLATE.replace(\"{model}\", modelSize);\n logger.info(\n `[whisper-local] Hugging Face 下载失败,回退至国内镜像(ModelScope): ${fallbackUrl}`,\n );\n return downloadFromUrl(fallbackUrl, modelPath, logger);\n }\n\n return result;\n}\n\n/**\n * 解析模型下载 URL\n */\nasync function resolveModelUrl(\n modelSize: WhisperModelSize,\n modelSource: WhisperModelSource | undefined,\n mirrorUrl: string | undefined,\n logger: Logger,\n): Promise<string> {\n // 自定义 URL 优先级最高\n if (mirrorUrl) {\n return `${mirrorUrl.replace(/\\/$/, \"\")}/${MODEL_FILENAMES[modelSize]}`;\n }\n\n const source = modelSource ?? \"auto\";\n\n switch (source) {\n case \"huggingface\":\n return HF_MODEL_URL_TEMPLATE.replace(\"{model}\", modelSize);\n case \"domestic\":\n return MODELSCOPE_MODEL_URL_TEMPLATE.replace(\"{model}\", modelSize);\n case \"auto\": {\n // 探测 Hugging Face 连通性\n const hfReachable = await probeUrl(\"https://huggingface.co\", logger);\n if (hfReachable) {\n logger.info(\"[whisper-local] Hugging Face 可达,使用海外源\");\n return HF_MODEL_URL_TEMPLATE.replace(\"{model}\", modelSize);\n }\n logger.info(\"[whisper-local] Hugging Face 不可达,使用国内镜像(ModelScope)\");\n return MODELSCOPE_MODEL_URL_TEMPLATE.replace(\"{model}\", modelSize);\n }\n default:\n return HF_MODEL_URL_TEMPLATE.replace(\"{model}\", modelSize);\n }\n}\n\n/**\n * 探测 URL 连通性(HEAD 请求,短超时)\n */\nasync function probeUrl(url: string, logger: Logger): Promise<boolean> {\n try {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), PROBE_TIMEOUT_MS);\n try {\n const res = await fetch(url, {\n method: \"HEAD\",\n signal: controller.signal,\n });\n return res.ok || res.status === 301 || res.status === 302;\n } finally {\n clearTimeout(timer);\n }\n } catch (err: any) {\n logger.info(\n `[whisper-local] 连通性探测失败: ${url} (${err?.name ?? err?.message ?? \"unknown\"})`,\n );\n return false;\n }\n}\n\n/**\n * 从指定 URL 下载模型文件至本地\n */\nasync function downloadFromUrl(\n url: string,\n modelPath: string,\n logger: Logger,\n): Promise<{ ok: boolean; modelPath: string; error?: string }> {\n const tmpPath = `${modelPath}.downloading`;\n\n try {\n mkdirSync(dirname(modelPath), { recursive: true });\n\n const controller = new AbortController();\n // 模型下载超时:30 分钟(large-v3 约 3GB)\n const timer = setTimeout(() => controller.abort(), 30 * 60 * 1000);\n\n try {\n const res = await fetch(url, { signal: controller.signal });\n\n if (!res.ok) {\n return {\n ok: false,\n modelPath,\n error: `模型下载失败: HTTP ${res.status} ${res.statusText}`,\n };\n }\n\n if (!res.body) {\n return { ok: false, modelPath, error: \"模型下载失败: 响应体为空\" };\n }\n\n const contentLength = Number(res.headers.get(\"content-length\") ?? 0);\n const writeStream = createWriteStream(tmpPath);\n const readable = Readable.fromWeb(res.body as any);\n\n // 下载进度日志\n let downloaded = 0;\n let lastLogPercent = 0;\n readable.on(\"data\", (chunk: Buffer) => {\n downloaded += chunk.length;\n if (contentLength > 0) {\n const percent = Math.floor((downloaded / contentLength) * 100);\n if (percent >= lastLogPercent + 10) {\n logger.info(\n `[whisper-local] 下载进度: ${percent}% (${formatBytes(downloaded)} / ${formatBytes(contentLength)})`,\n );\n lastLogPercent = percent;\n }\n }\n });\n\n await pipeline(readable, writeStream);\n } finally {\n clearTimeout(timer);\n }\n\n // 重命名为正式文件\n const { renameSync } = await import(\"node:fs\");\n renameSync(tmpPath, modelPath);\n\n const fileSize = statSync(modelPath).size;\n logger.info(\n `[whisper-local] 模型下载完成: ${basename(modelPath)} (${formatBytes(fileSize)})`,\n );\n\n return { ok: true, modelPath };\n } catch (err: any) {\n // 清理临时文件\n try {\n if (existsSync(tmpPath)) unlinkSync(tmpPath);\n } catch { /* ignore */ }\n\n const msg = err?.name === \"AbortError\"\n ? \"模型下载超时(30 分钟)\"\n : (err?.message ?? String(err));\n logger.error(`[whisper-local] 模型下载失败: ${msg}`);\n return { ok: false, modelPath, error: msg };\n }\n}\n\n/**\n * 查找 whisper.cpp CLI 二进制文件\n *\n * 按以下优先级查找:\n * 1. 插件数据目录下的 whisper-bin/\n * 2. 系统 PATH 中的 whisper-cli / whisper-cpp / whisper\n */\nexport function findWhisperBinary(dataDir: string, logger: Logger): string | null {\n // 1. 检查插件 bin 目录\n const binDir = resolveBinDir(dataDir);\n const binNames = platform() === \"win32\"\n ? [\"whisper-cli.exe\", \"whisper.exe\", \"main.exe\"]\n : [\"whisper-cli\", \"whisper\", \"main\"];\n\n for (const name of binNames) {\n const binPath = join(binDir, name);\n if (existsSync(binPath)) {\n logger.info(`[whisper-local] 找到本地二进制: ${binPath}`);\n return binPath;\n }\n }\n\n // 2. 检查系统 PATH\n const pathNames = platform() === \"win32\"\n ? [\"whisper-cli\", \"whisper-cpp\", \"whisper\"]\n : [\"whisper-cli\", \"whisper-cpp\", \"whisper\"];\n\n for (const name of pathNames) {\n try {\n const cmd = platform() === \"win32\" ? \"where\" : \"which\";\n const result = execSync(`${cmd} ${name}`, { encoding: \"utf-8\", stdio: \"pipe\" }).trim();\n if (result) {\n logger.info(`[whisper-local] 找到系统 PATH 二进制: ${result}`);\n return result.split(\"\\n\")[0].trim();\n }\n } catch {\n // not found, continue\n }\n }\n\n logger.warn(\"[whisper-local] 未找到 whisper.cpp 二进制文件\");\n return null;\n}\n\n/**\n * 使用本地 Whisper 执行转写(§6.4)\n *\n * @param audioFilePath 本地音频文件绝对路径\n * @param localConfig 本地 Whisper 配置\n * @param dataDir 插件数据目录(存放模型和二进制)\n * @param logger 日志\n */\nexport async function transcribeWithWhisperLocal(\n audioFilePath: string,\n localConfig: WhisperLocalConfig,\n dataDir: string,\n logger: Logger,\n): Promise<TranscriptionResult> {\n // 1. 检测环境\n const env = detectEnvironment(logger);\n\n // 2. 确定后端、模型、线程数\n const backend = localConfig.backend ?? env.recommendedBackend;\n const modelSize = localConfig.model ?? env.recommendedModel;\n const threads = localConfig.threads ?? env.physicalCores;\n const language = localConfig.language ?? \"auto\";\n const translate = localConfig.translate ?? false;\n\n logger.info(\n `[whisper-local] 转写参数: backend=${backend}, model=${modelSize}, ` +\n `threads=${threads}, language=${language}, translate=${translate}`,\n );\n\n // 3. 查找 whisper.cpp 二进制\n const whisperBin = findWhisperBinary(dataDir, logger);\n if (!whisperBin) {\n return {\n ok: false,\n error:\n \"未找到 whisper.cpp 二进制文件。请安装 whisper.cpp 并确保 whisper-cli 在 PATH 中,\" +\n `或将二进制文件放入 ${resolveBinDir(dataDir)}`,\n };\n }\n\n // 4. 确保模型已下载\n const modelsDir = resolveModelsDir(dataDir);\n if (!isModelDownloaded(modelsDir, modelSize)) {\n logger.info(`[whisper-local] 模型 ${modelSize} 未下载,开始下载...`);\n const downloadResult = await downloadModel(\n modelsDir,\n modelSize,\n logger,\n localConfig.modelSource,\n localConfig.modelMirrorUrl,\n );\n if (!downloadResult.ok) {\n return { ok: false, error: `模型下载失败: ${downloadResult.error}` };\n }\n }\n\n const modelPath = join(modelsDir, MODEL_FILENAMES[modelSize]);\n\n // 5. 音频格式转换(whisper.cpp 仅支持 16kHz mono WAV)\n // 通过 magic bytes 判断真实格式,不依赖扩展名\n let inputPath = audioFilePath;\n let tmpWavPath: string | null = null;\n\n const actualFmt = detectAudioFormat(audioFilePath);\n if (actualFmt !== \".wav\") {\n tmpWavPath = audioFilePath.replace(/\\.[^.]+$/, \".whisper.wav\");\n logger.info(\n `[whisper-local] 转换音频格式: ${audioFilePath} (${actualFmt ?? \"未知\"}) → WAV (16kHz mono)`,\n );\n\n const convertResult = convertToWav(audioFilePath, tmpWavPath, actualFmt, logger);\n if (!convertResult.ok) {\n return { ok: false, error: convertResult.error! };\n }\n inputPath = tmpWavPath;\n }\n\n // 6. 构建 whisper.cpp CLI 参数\n const args = buildWhisperArgs({\n audioFilePath: inputPath,\n modelPath,\n language,\n translate,\n threads,\n backend,\n });\n\n logger.info(`[whisper-local] 执行: ${whisperBin} ${args.join(\" \")}`);\n\n // 7. 执行转写\n try {\n const startMs = Date.now();\n let result: SpawnSyncReturns<string>;\n\n try {\n result = spawnSync(whisperBin, args, {\n encoding: \"utf-8\" as const,\n timeout: 60 * 60 * 1000, // 1 小时超时(5 小时录音)\n maxBuffer: 100 * 1024 * 1024, // 100MB stdout buffer\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n } catch (err: any) {\n cleanupTmpWav(tmpWavPath);\n return { ok: false, error: `whisper.cpp 执行失败: ${err?.message ?? err}` };\n }\n\n if (result.status !== 0) {\n cleanupTmpWav(tmpWavPath);\n const stderr = result.stderr?.slice(0, 500) ?? \"\";\n return {\n ok: false,\n error: `whisper.cpp 退出码 ${result.status}: ${stderr}`,\n };\n }\n\n const elapsed = Date.now() - startMs;\n logger.info(`[whisper-local] 转写耗时: ${Math.round(elapsed / 1000)}s`);\n\n // 8. 读取 JSON 输出文件(--output-json 将结果写入 {inputPath}.json)\n const jsonPath = inputPath + \".json\";\n let jsonContent: string;\n\n if (existsSync(jsonPath)) {\n jsonContent = readFileSync(jsonPath, \"utf-8\");\n // 清理 JSON 文件\n try { unlinkSync(jsonPath); } catch { /* ignore */ }\n } else {\n // 回退:尝试解析 stdout(部分 whisper.cpp 版本可能输出到 stdout)\n jsonContent = result.stdout;\n }\n\n cleanupTmpWav(tmpWavPath);\n\n return parseWhisperOutput(jsonContent, logger);\n } catch (err: any) {\n cleanupTmpWav(tmpWavPath);\n return { ok: false, error: `whisper.cpp 转写异常: ${err?.message ?? err}` };\n }\n}\n\n/**\n * 获取本地 Whisper 状态信息(供 App 查询环境检测结果)\n */\nexport function getWhisperLocalStatus(\n dataDir: string,\n logger: Logger,\n): {\n environment: WhisperEnvironmentInfo;\n binaryFound: boolean;\n binaryPath: string | null;\n downloadedModels: WhisperModelSize[];\n} {\n const env = detectEnvironment(logger);\n const binaryPath = findWhisperBinary(dataDir, logger);\n const modelsDir = resolveModelsDir(dataDir);\n\n const allModels: WhisperModelSize[] = [\"tiny\", \"base\", \"small\", \"medium\", \"large-v3\"];\n const downloadedModels = allModels.filter((m) => isModelDownloaded(modelsDir, m));\n\n return {\n environment: env,\n binaryFound: binaryPath !== null,\n binaryPath,\n downloadedModels,\n };\n}\n\n// ─── Internal Helpers ───\n\n/**\n * 检测 CUDA 是否可用(§6.4.1)\n */\nfunction detectCuda(logger: Logger): boolean {\n try {\n // 尝试运行 nvidia-smi\n execSync(\"nvidia-smi\", { encoding: \"utf-8\", stdio: \"pipe\", timeout: 5000 });\n logger.info(\"[whisper-local] 检测到 NVIDIA GPU (nvidia-smi)\");\n return true;\n } catch {\n // nvidia-smi 不存在或执行失败\n }\n\n // 检查 CUDA runtime 库\n if (platform() === \"linux\") {\n try {\n const ldconfig = execSync(\"ldconfig -p 2>/dev/null | grep libcudart\", {\n encoding: \"utf-8\",\n stdio: \"pipe\",\n timeout: 5000,\n });\n if (ldconfig.includes(\"libcudart\")) {\n logger.info(\"[whisper-local] 检测到 CUDA runtime (ldconfig)\");\n return true;\n }\n } catch { /* ignore */ }\n }\n\n return false;\n}\n\n/**\n * 获取可用内存(GB)\n *\n * CUDA 后端使用 VRAM,其余使用系统 RAM。\n */\nfunction getAvailableMemoryGB(backend: WhisperBackend, logger: Logger): number {\n if (backend === \"cuda\") {\n // 尝试获取 GPU VRAM\n try {\n const output = execSync(\n \"nvidia-smi --query-gpu=memory.free --format=csv,noheader,nounits\",\n { encoding: \"utf-8\", stdio: \"pipe\", timeout: 5000 },\n );\n const freeVramMB = parseInt(output.trim().split(\"\\n\")[0], 10);\n if (!Number.isNaN(freeVramMB) && freeVramMB > 0) {\n return freeVramMB / 1024;\n }\n } catch {\n logger.warn(\"[whisper-local] 无法获取 GPU VRAM,使用系统 RAM 代替\");\n }\n }\n\n // 使用系统可用内存(取 total 的 80% 和 free 的较大值作为可用估计)\n const totalGB = totalmem() / (1024 * 1024 * 1024);\n const freeGB = freemem() / (1024 * 1024 * 1024);\n return Math.max(freeGB, totalGB * 0.6);\n}\n\n/**\n * 获取物理 CPU 核心数\n */\nfunction getPhysicalCoreCount(): number {\n const cpuList = cpus();\n if (cpuList.length === 0) return 4; // fallback\n\n // 简单估算:逻辑核 / 2(假设超线程)\n // macOS ARM 无超线程,直接使用逻辑核数\n if (platform() === \"darwin\" && arch() === \"arm64\") {\n // Apple Silicon: P-cores only (exclude E-cores for inference)\n // 简化处理:使用总核数\n return cpuList.length;\n }\n\n return Math.max(1, Math.floor(cpuList.length / 2));\n}\n\n/**\n * 通过文件头 magic bytes 检测音频的真实格式\n * @returns 正确的文件扩展名(如 .aiff, .wav, .m4a),或 null\n */\nfunction detectAudioFormat(filePath: string): string | null {\n try {\n const fd = openSync(filePath, \"r\");\n const buf = Buffer.alloc(12);\n readSync(fd, buf, 0, 12, 0);\n closeSync(fd);\n\n const header = buf.toString(\"ascii\", 0, 4);\n const header8 = buf.toString(\"ascii\", 0, 8);\n\n // RIFF....WAVE = WAV\n if (header === \"RIFF\" && buf.toString(\"ascii\", 8, 12) === \"WAVE\") return \".wav\";\n // FORM....AIFF / FORM....AIFC = AIFF\n if (header === \"FORM\") {\n const sub = buf.toString(\"ascii\", 8, 12);\n if (sub === \"AIFF\" || sub === \"AIFC\") return \".aiff\";\n }\n // ftyp = MP4/M4A/AAC container\n if (buf.toString(\"ascii\", 4, 8) === \"ftyp\") return \".m4a\";\n // ID3 or 0xFF 0xFB = MP3\n if (header.startsWith(\"ID3\") || (buf[0] === 0xff && (buf[1] & 0xe0) === 0xe0)) return \".mp3\";\n // OggS = Ogg (Vorbis/Opus)\n if (header === \"OggS\") return \".ogg\";\n // fLaC = FLAC\n if (header === \"fLaC\") return \".flac\";\n\n return null;\n } catch {\n return null;\n }\n}\n\n/**\n * 将音频文件转换为 whisper.cpp 所需的 16kHz mono WAV 格式\n *\n * 转换链(按优先级):\n * 1. ffmpeg — 支持全格式,含 OGG/Opus\n * 2. opusdec — 专用于 OGG/Opus(来自 brew install opus-tools)\n * 3. afconvert — macOS 内置,支持 AIFF/M4A/AAC;需正确文件扩展名\n *\n * @param actualFmt detectAudioFormat 检测到的真实格式(如 \".ogg\", \".aiff\"),可为 null\n */\nfunction convertToWav(\n inputPath: string,\n outputPath: string,\n actualFmt: string | null,\n logger: Logger,\n): { ok: boolean; error?: string } {\n // 尝试 ffmpeg(可自动检测格式,不依赖扩展名)\n try {\n const ffmpegResult = spawnSync(\"ffmpeg\", [\n \"-y\", \"-i\", inputPath,\n \"-ar\", \"16000\", \"-ac\", \"1\", \"-c:a\", \"pcm_s16le\",\n outputPath,\n ], {\n encoding: \"utf-8\",\n timeout: 120_000,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n\n if (ffmpegResult.status === 0 && existsSync(outputPath)) {\n logger.info(`[whisper-local] ffmpeg 转换完成: ${outputPath}`);\n return { ok: true };\n }\n } catch {\n // ffmpeg 不可用,继续尝试其他方式\n }\n\n // 2. opusdec — 专用于 OGG/Opus(ffmpeg 不可用时)\n if (actualFmt === \".ogg\") {\n try {\n const opusResult = spawnSync(\n \"opusdec\",\n [\"--rate\", \"16000\", \"--mono\", inputPath, outputPath],\n { encoding: \"utf-8\", timeout: 120_000, stdio: [\"pipe\", \"pipe\", \"pipe\"] },\n );\n if (opusResult.status === 0 && existsSync(outputPath)) {\n logger.info(`[whisper-local] opusdec 转换完成: ${outputPath}`);\n return { ok: true };\n }\n } catch { /* opusdec 不可用,继续 */ }\n }\n\n // 3. macOS afconvert — 支持 AIFF/M4A/AAC,不支持 OGG\n if (process.platform === \"darwin\" && actualFmt !== \".ogg\") {\n // afconvert 依赖扩展名判断输入格式,先确保扩展名正确\n let actualInputPath = inputPath;\n let tmpCopy: string | null = null;\n const detectedExt = actualFmt;\n\n if (detectedExt && !inputPath.endsWith(detectedExt)) {\n // 扩展名不匹配,创建带正确扩展名的临时副本\n tmpCopy = inputPath + \".detected\" + detectedExt;\n try {\n copyFileSync(inputPath, tmpCopy);\n actualInputPath = tmpCopy;\n logger.info(\n `[whisper-local] 检测到实际格式 ${detectedExt},临时重命名`,\n );\n } catch {\n tmpCopy = null;\n }\n }\n\n try {\n const afResult = spawnSync(\"afconvert\", [\n \"-f\", \"WAVE\", \"-d\", \"LEI16@16000\", \"-c\", \"1\",\n actualInputPath, outputPath,\n ], {\n encoding: \"utf-8\",\n timeout: 120_000,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n\n // 清理临时副本\n if (tmpCopy && existsSync(tmpCopy)) {\n try { unlinkSync(tmpCopy); } catch { /* ignore */ }\n }\n\n if (afResult.status === 0 && existsSync(outputPath)) {\n logger.info(`[whisper-local] afconvert 转换完成: ${outputPath}`);\n return { ok: true };\n }\n\n const stderr = afResult.stderr?.slice(0, 200) ?? \"\";\n return { ok: false, error: `afconvert 转换失败 (exit ${afResult.status}): ${stderr}` };\n } catch (err: any) {\n // 清理临时副本\n if (tmpCopy && existsSync(tmpCopy)) {\n try { unlinkSync(tmpCopy); } catch { /* ignore */ }\n }\n return { ok: false, error: `afconvert 不可用: ${err?.message}` };\n }\n }\n\n const fmtHint = actualFmt === \".ogg\"\n ? \"OGG/Opus 格式需要 ffmpeg 或 opus-tools(brew install opus-tools)\"\n : \"请安装 ffmpeg(brew install ffmpeg)或确保音频文件为 WAV 格式\";\n return { ok: false, error: `无法将音频转换为 WAV 格式。${fmtHint}` };\n}\n\n/** 清理临时 WAV 文件 */\nfunction cleanupTmpWav(path: string | null): void {\n if (path && existsSync(path)) {\n try { unlinkSync(path); } catch { /* ignore */ }\n }\n}\n\n/**\n * 构建 whisper.cpp CLI 参数\n */\nfunction buildWhisperArgs(params: {\n audioFilePath: string;\n modelPath: string;\n language: string;\n translate: boolean;\n threads: number;\n backend: WhisperBackend;\n}): string[] {\n const args: string[] = [\n \"--model\", params.modelPath,\n \"--file\", params.audioFilePath,\n \"--output-json\", // JSON 格式输出到 {audioFilePath}.json\n \"--no-prints\", // 抑制模型信息输出\n \"--threads\", String(params.threads),\n ];\n\n // 语言\n if (params.language && params.language !== \"auto\") {\n args.push(\"--language\", params.language);\n } else {\n args.push(\"--language\", \"auto\");\n }\n\n // 翻译为英文\n if (params.translate) {\n args.push(\"--translate\");\n }\n\n return args;\n}\n\n/**\n * 解析 whisper.cpp JSON 输出\n */\nfunction parseWhisperOutput(\n stdout: string,\n logger: Logger,\n): TranscriptionResult {\n if (!stdout || !stdout.trim()) {\n return { ok: false, error: \"whisper.cpp 无输出\" };\n }\n\n try {\n const data = JSON.parse(stdout.trim()) as WhisperCppJsonOutput;\n\n if (!data.transcription || !Array.isArray(data.transcription)) {\n // 可能是纯文本输出\n return {\n ok: true,\n text: stdout.trim(),\n segments: [],\n };\n }\n\n const segments: TranscriptSegment[] = [];\n const textParts: string[] = [];\n\n for (const item of data.transcription) {\n const text = item.text?.trim() ?? \"\";\n if (!text) continue;\n\n textParts.push(text);\n\n const startMs = item.offsets?.from ?? parseTimestamp(item.timestamps?.from);\n const endMs = item.offsets?.to ?? parseTimestamp(item.timestamps?.to);\n\n segments.push({\n start_ms: startMs,\n end_ms: endMs,\n text,\n });\n }\n\n const fullText = textParts.join(\" \");\n\n logger.info(\n `[whisper-local] 转写完成: ${fullText.length} 字, ${segments.length} 段`,\n );\n\n return {\n ok: true,\n text: fullText,\n segments,\n };\n } catch (err: any) {\n logger.warn(`[whisper-local] JSON 解析失败,尝试纯文本: ${err?.message}`);\n\n // Fallback: 将 stdout 视为纯文本\n return {\n ok: true,\n text: stdout.trim(),\n segments: [],\n };\n }\n}\n\n/**\n * 解析 whisper.cpp 时间戳字符串 \"HH:MM:SS,mmm\" → 毫秒\n */\nfunction parseTimestamp(ts?: string): number {\n if (!ts) return 0;\n // \"00:00:05,000\" or \"00:00:05.000\"\n const match = ts.match(/^(\\d+):(\\d+):(\\d+)[,.](\\d+)$/);\n if (!match) return 0;\n const [, h, m, s, ms] = match;\n return (\n parseInt(h, 10) * 3600000 +\n parseInt(m, 10) * 60000 +\n parseInt(s, 10) * 1000 +\n parseInt(ms, 10)\n );\n}\n\n/**\n * 格式化字节数\n */\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes}B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;\n if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;\n return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)}GB`;\n}\n","/**\n * ASR 转写调度器(§6 / §7)\n *\n * 按 arc-long-recording §6.2 定义的两层配置结构调度 ASR:\n * - mode = \"api\":YoooClaw 托管云端 ASR(经 model-proxy 长录音接口调用)\n * - mode = \"local\":本地 Whisper 转写(§6.4,内置 whisper.cpp 推理)\n * - mode = \"yoooclaw\":YoooClaw 自建 ASR(P2,预留接口)\n *\n * 转写流程:\n * 1. 读取录音 OSS URL 与本地文件\n * 2. 调用云端 model-proxy 或本地 Whisper 获取转写文本\n * 3. 将关键点以 [关键点 MM:SS] 内嵌转写文本\n * 4. 自动生成摘要标题(≤ 10 字)\n * 5. 写入 /recordings/transcripts/日期_时间_摘要.md\n */\n\nimport { existsSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type {\n AsrConfig,\n AsrApiConfig,\n RecordingMarker,\n RecordingAsrInitResult,\n RecordingTranscriptItem,\n} from \"../types.js\";\nimport type { Logger } from \"../logger.js\";\nimport { requireApiKey, loadApiKey } from \"../auth/credentials.js\";\nimport { getEnvUrls } from \"../env.js\";\nimport {\n buildTranscriptDataFilename,\n buildTranscriptDocument,\n extractSourceTextListFromDocument,\n} from \"./transcript-document.js\";\n\nconst DEFAULT_LONG_RECORDING_POLL_INTERVAL_MS = 2000;\nconst DEFAULT_LONG_RECORDING_MAX_POLL_ATTEMPTS = 3600;\nconst LONG_RECORDING_RUNNING_STATUSES = new Set([\"PENDING\", \"RUNNING\", \"SUSPENDED\"]);\nconst LONG_RECORDING_TERMINAL_FAILURE_STATUSES = new Set([\"FAILED\", \"CANCELED\", \"UNKNOWN\"]);\n\nconst DEFAULT_HTTP_MAX_ATTEMPTS = 3;\nconst DEFAULT_HTTP_RETRY_BACKOFF_MS = 2000;\n\n// ─── Types ───\n\nexport interface TranscriptionResult {\n ok: boolean;\n /** 转写全文 */\n text?: string;\n /** 带时间戳的分段(如 ASR 支持) */\n segments?: TranscriptSegment[];\n /** 自动生成的摘要标题 */\n summary?: string;\n /** 给客户端展示的摘要文本 */\n summaryText?: string;\n /** 分类信息(如会议纪要、采访) */\n category?: string;\n /** 转写来源信息 */\n sourceInfo?: {\n provider: string;\n taskId?: string;\n requestId?: string;\n status?: string;\n };\n /** Provider 原始响应,供后续兼容字段演进 */\n rawResponse?: unknown;\n /** 错误信息 */\n error?: string;\n}\n\nexport interface TranscriptSegment {\n /** 开始时间(毫秒) */\n start_ms: number;\n /** 结束时间(毫秒) */\n end_ms: number;\n /** 文本内容 */\n text: string;\n /** 说话人 ID(如云端 ASR 返回) */\n speaker_id?: number;\n}\n\ninterface ModelProxyLongRecordingSubmitRequest {\n audioOssUrl: string;\n language?: string;\n enableNormalization?: boolean;\n}\n\ninterface ModelProxyLongRecordingResult {\n sourceText?: string | null;\n sourceTextList?: ModelProxyLongRecordingSourceTextItem[] | null;\n summaryResult?: string | null;\n category?: string | null;\n title?: string | null;\n}\n\ninterface ModelProxyLongRecordingSourceTextItem {\n content?: string | null;\n speakerId?: number | null;\n startTime?: number | null;\n endTime?: number | null;\n}\n\ninterface ModelProxyLongRecordingStatusResponse {\n taskId?: string;\n status?: string;\n requestId?: string;\n errorMessage?: string | null;\n recordResult?: ModelProxyLongRecordingResult | null;\n}\n\ninterface ResponseEnvelope<T> {\n success?: boolean;\n code?: number | string;\n message?: string | null;\n e?: unknown;\n data?: T | null;\n}\n\n// ─── Public API ───\n\n/**\n * 判断 ASR 是否已配置\n */\nexport function isAsrConfigured(config?: AsrConfig): boolean {\n return !!config && !validateAsrConfig(config);\n}\n\n/**\n * 校验客户端下发的 ASR 配置。\n * 返回 undefined 表示配置可用;返回字符串表示错误原因。\n */\nexport function validateAsrConfig(config?: AsrConfig): string | undefined {\n if (!config?.mode) {\n return \"asr.mode is required\";\n }\n\n switch (config.mode) {\n case \"local\":\n case \"api\":\n return undefined;\n case \"yoooclaw\":\n return \"YoooClaw ASR 尚未实现(P2)\";\n default:\n return `未知的 ASR mode: ${(config as { mode: string }).mode}`;\n }\n}\n\n/**\n * 显式初始化 ASR 能力。\n * - mode=api:校验插件本地 API Key 是否存在,并返回最终使用的 model-proxy submit-task endpoint\n * - mode=local:按配置预下载模型,并返回本地环境状态\n */\nexport async function initializeAsr(\n config: AsrConfig,\n dataDir: string,\n logger: Logger,\n): Promise<RecordingAsrInitResult> {\n const validationError = validateAsrConfig(config);\n if (validationError) {\n return {\n ok: false,\n mode: config.mode,\n error: validationError,\n };\n }\n\n switch (config.mode) {\n case \"api\": {\n const endpoint = resolveModelProxyLongRecordingSubmitEndpoint(config.api);\n const keyConfigured = hasText(config.api?.apiKey) || hasText(loadApiKey());\n\n if (!keyConfigured) {\n return {\n ok: false,\n mode: \"api\",\n provider: \"model-proxy\",\n endpoint,\n language: config.api?.language ?? \"auto\",\n keyConfigured: false,\n error:\n \"API Key 未设置,请在本次 asr.api.apiKey 中传入,或先写入 credentials.json / 执行 ntf auth set-api-key <apiKey>\",\n };\n }\n\n return {\n ok: true,\n mode: \"api\",\n provider: \"model-proxy\",\n endpoint,\n language: config.api?.language ?? \"auto\",\n keyConfigured: true,\n };\n }\n case \"local\": {\n const localConfig = config.local ?? {};\n const {\n getWhisperLocalStatus,\n downloadModel,\n resolveModelsDir,\n } = await import(\"./whisper-local.js\");\n\n const initialStatus = getWhisperLocalStatus(dataDir, logger);\n const requestedModel = localConfig.model ?? initialStatus.environment.recommendedModel;\n\n const modelsDir = resolveModelsDir(dataDir);\n const downloadResult = await downloadModel(\n modelsDir,\n requestedModel,\n logger,\n localConfig.modelSource,\n localConfig.modelMirrorUrl,\n );\n if (!downloadResult.ok) {\n return {\n ok: false,\n mode: \"local\",\n model: requestedModel,\n localStatus: {\n ...initialStatus,\n requestedModel,\n },\n error: `模型下载失败: ${downloadResult.error}`,\n };\n }\n\n const finalStatus = getWhisperLocalStatus(dataDir, logger);\n if (!finalStatus.binaryFound) {\n return {\n ok: false,\n mode: \"local\",\n model: requestedModel,\n localStatus: {\n ...finalStatus,\n requestedModel,\n },\n error:\n \"模型已就绪,但未找到 whisper.cpp 二进制文件。请安装 whisper.cpp 并确保 whisper-cli 在 PATH 中。\",\n };\n }\n\n return {\n ok: true,\n mode: \"local\",\n model: requestedModel,\n language: localConfig.language ?? \"auto\",\n localStatus: {\n ...finalStatus,\n requestedModel,\n },\n };\n }\n case \"yoooclaw\":\n return {\n ok: false,\n mode: \"yoooclaw\",\n error: \"YoooClaw ASR 尚未实现(P2)\",\n };\n default:\n return {\n ok: false,\n mode: config.mode,\n error: `未知的 ASR mode: ${config.mode}`,\n };\n }\n}\n\n/**\n * 执行 ASR 转写\n *\n * @param audioFilePath 本地音频文件绝对路径\n * @param config ASR 配置(两层结构:mode + api/local)\n * @param logger 日志\n * @param options 额外上下文(云端 ASR 需要 OSS URL)\n */\nexport async function transcribeAudio(\n audioFilePath: string,\n config: AsrConfig,\n logger: Logger,\n options: {\n audioOssUrl?: string;\n audioDurationMs?: number;\n } = {},\n): Promise<TranscriptionResult> {\n if (!existsSync(audioFilePath)) {\n return { ok: false, error: `音频文件不存在: ${audioFilePath}` };\n }\n\n logger.info(\n `[asr] 开始转写: mode=${config.mode}, file=${audioFilePath}`,\n );\n\n try {\n switch (config.mode) {\n case \"api\":\n return await transcribeWithModelProxy(\n options.audioOssUrl,\n options.audioDurationMs,\n config.api,\n logger,\n );\n case \"local\":\n return await transcribeWithWhisperLocal(audioFilePath, config, logger);\n case \"yoooclaw\":\n return { ok: false, error: \"YoooClaw ASR 尚未实现(P2)\" };\n default:\n return {\n ok: false,\n error: `未知的 ASR mode: ${config.mode}`,\n };\n }\n } catch (err: any) {\n const msg = err?.message ?? String(err);\n logger.error(`[asr] 转写异常: ${msg}`);\n return { ok: false, error: msg };\n }\n}\n\n/**\n * 将转写结果与关键点标记合并,生成最终 Markdown 转写文本\n *\n * @param result 转写结果\n * @param markers 关键点列表\n * @param recordingName 录音名称\n * @param durationSec 录音总时长(秒)\n * @param createdAt 录音创建时间\n */\nexport function buildTranscriptMarkdown(\n result: TranscriptionResult,\n markers: RecordingMarker[],\n recordingName: string,\n durationSec: number,\n createdAt: string,\n): string { \n const summary = result.summary ?? recordingName.slice(0, 10);\n const lines: string[] = [];\n\n // 元数据头\n lines.push(`# ${summary}`);\n lines.push(\"\");\n lines.push(`> 录音名称:${recordingName}`);\n lines.push(`> 时长:${formatDuration(durationSec)}`);\n lines.push(`> 创建时间:${createdAt}`);\n if (markers.length > 0) {\n lines.push(`> 关键点数:${markers.length}`);\n }\n lines.push(\"\");\n lines.push(\"---\");\n lines.push(\"\");\n\n if (result.segments && result.segments.length > 0) {\n // 有分段的转写文本:在合适的位置插入关键点标记\n const sortedMarkers = [...markers].sort(\n (a, b) => a.timestamp_ms - b.timestamp_ms,\n );\n let markerIdx = 0;\n\n for (const seg of result.segments) {\n // 在当前段之前插入所有对应的关键点\n while (\n markerIdx < sortedMarkers.length &&\n sortedMarkers[markerIdx].timestamp_ms <= seg.start_ms\n ) {\n const m = sortedMarkers[markerIdx];\n lines.push(\n `**[关键点 ${formatTimestamp(m.timestamp_ms)}]**`,\n );\n lines.push(\"\");\n markerIdx++;\n }\n\n const segmentText = formatTranscriptSegmentText(seg);\n if (segmentText) {\n lines.push(segmentText);\n lines.push(\"\");\n }\n }\n\n // 追加剩余关键点\n while (markerIdx < sortedMarkers.length) {\n const m = sortedMarkers[markerIdx];\n lines.push(\n `**[关键点 ${formatTimestamp(m.timestamp_ms)}]**`,\n );\n lines.push(\"\");\n markerIdx++;\n }\n } else if (result.text) {\n // 纯文本转写:在文本头部集中列出关键点\n if (markers.length > 0) {\n lines.push(\"### 关键点\");\n lines.push(\"\");\n for (const m of markers) {\n lines.push(`- **[关键点 ${formatTimestamp(m.timestamp_ms)}]**`);\n }\n lines.push(\"\");\n lines.push(\"---\");\n lines.push(\"\");\n }\n lines.push(result.text);\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * 从转写文本中提取摘要标题(≤ 10 字)\n */\nexport function extractSummary(text: string): string {\n // 取第一句话,截断到 10 字\n const firstLine = text.split(/[。!?\\n]/).find((s) => s.trim().length > 0);\n if (!firstLine) return \"录音转写\";\n const trimmed = firstLine.trim();\n return trimmed.length <= 10 ? trimmed : trimmed.slice(0, 10);\n}\n\n/**\n * 完整的转写工作流:转写 → 生成 Markdown → 写入文件\n */\nexport async function runTranscriptionWorkflow(params: {\n audioFilePath: string;\n audioOssUrl?: string;\n config: AsrConfig;\n markers: RecordingMarker[];\n recordingName: string;\n durationSec: number;\n createdAt: string;\n transcriptsDir: string;\n transcriptDataDir: string;\n summariesDir: string;\n recordingId: string;\n logger: Logger;\n}): Promise<{\n ok: boolean;\n transcriptFilename?: string;\n transcriptDataFilename?: string;\n summaryFilename?: string;\n transcript?: RecordingTranscriptItem[];\n summary?: string;\n title?: string;\n error?: string;\n}> {\n const {\n audioFilePath,\n audioOssUrl,\n config,\n markers,\n recordingName,\n durationSec,\n createdAt,\n transcriptsDir,\n transcriptDataDir,\n summariesDir,\n recordingId,\n logger,\n } = params;\n\n // 1. ASR 转写\n const result = await transcribeAudio(audioFilePath, config, logger, {\n audioOssUrl,\n audioDurationMs: Math.max(0, Math.round(durationSec * 1000)),\n });\n if (!result.ok) {\n return { ok: false, error: result.error };\n }\n\n // 2. 提取摘要\n const title = normalizeOptionalText(result.summary)\n ? normalizeOptionalText(result.summary)!\n : extractSummary(result.text ?? \"\");\n const summary = result.summaryText ?? \"\";\n result.summary = title;\n const transcriptData = buildTranscriptDocument({\n recordingId,\n generatedAt: new Date().toISOString(),\n source: result.sourceInfo ?? {\n provider: config.mode === \"api\" ? \"model-proxy\" : config.mode,\n },\n title,\n category: result.category,\n summary,\n text: result.text,\n segments: (result.segments ?? []).map((segment) => ({\n text: segment.text,\n startMs: segment.start_ms,\n endMs: segment.end_ms,\n speakerId: segment.speaker_id,\n })),\n raw: result.rawResponse,\n });\n\n // 3. 生成 Markdown\n const markdown = buildTranscriptMarkdown(\n result,\n markers,\n recordingName,\n durationSec,\n createdAt,\n );\n\n // 4. 写入文件\n const transcriptDataFilename = buildTranscriptDataFilename(recordingId);\n const transcriptDataPath = join(transcriptDataDir, transcriptDataFilename);\n writeFileSync(\n transcriptDataPath,\n JSON.stringify(transcriptData, null, 2),\n \"utf-8\",\n );\n logger.info(`[asr] 转写 JSON 已写入: ${transcriptDataPath}`);\n\n const safeSummary = title\n .replace(/[/\\\\:*?\"<>|]/g, \"\")\n .trim()\n .slice(0, 20);\n const filename = safeSummary\n ? `${recordingId}_${safeSummary}.md`\n : `${recordingId}.md`;\n const filePath = join(transcriptsDir, filename);\n writeFileSync(filePath, markdown, \"utf-8\");\n logger.info(`[asr] 转写文本已写入: ${filePath}`);\n\n let summaryFilename: string | undefined;\n if (summary) {\n summaryFilename = `${recordingId}.md`;\n const summaryFilePath = join(summariesDir, summaryFilename);\n writeFileSync(summaryFilePath, summary, \"utf-8\");\n logger.info(`[asr] 摘要文本已写入: ${summaryFilePath}`);\n }\n\n return {\n ok: true,\n transcriptFilename: filename,\n transcriptDataFilename,\n summaryFilename,\n transcript: extractSourceTextListFromDocument(transcriptData),\n summary,\n title,\n };\n}\n\n// ─── ASR Provider Implementations ───\n\n/**\n * 通过 model-proxy 的长录音接口执行云端转写。\n */\nasync function transcribeWithModelProxy(\n audioOssUrl: string | undefined,\n audioDurationMs: number | undefined,\n apiConfig: AsrApiConfig | undefined,\n logger: Logger,\n): Promise<TranscriptionResult> {\n const normalizedAudioOssUrl = normalizeOptionalText(audioOssUrl);\n if (!normalizedAudioOssUrl) {\n return { ok: false, error: \"API 模式缺少 audioOssUrl,无法调用 model-proxy\" };\n }\n\n const apiKey = resolveModelProxyApiKey(apiConfig);\n const submitEndpoint = resolveModelProxyLongRecordingSubmitEndpoint(apiConfig);\n const submitBody = buildLongRecordingSubmitRequest(normalizedAudioOssUrl, apiConfig);\n\n logger.info(\n `[asr-submit] 提交长录音任务: endpoint=${submitEndpoint}, body=${stringifyForLog(submitBody) ?? \"{}\"}`,\n );\n\n let res: Response;\n try {\n res = await fetchWithRetry(\n submitEndpoint,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Api-Key-Id\": apiKey,\n },\n body: JSON.stringify(submitBody),\n },\n { logger, context: \"asr-submit\" },\n );\n } catch (err: any) {\n const msg = err?.message ?? String(err);\n logger.error(`[asr-submit] 提交长录音任务网络异常 (已重试): ${msg}`);\n return {\n ok: false,\n error: `Model Proxy ASR submit network error: ${msg}`,\n };\n }\n\n if (!res.ok) {\n const errText = await res.text();\n logger.error(\n `[asr-submit-response] 提交长录音任务失败: status=${res.status}, body=${errText.slice(0, 500)}`,\n );\n return {\n ok: false,\n error: `Model Proxy ASR error: ${res.status} ${errText.slice(0, 200)}`,\n };\n }\n\n const raw = (await res.json()) as\n | ModelProxyLongRecordingStatusResponse\n | ResponseEnvelope<ModelProxyLongRecordingStatusResponse>;\n logger.info(\n `[asr-submit-response] 提交长录音任务响应: ${stringifyForLog(raw) ?? \"{}\"}`,\n );\n const submitEnvelopeError = buildModelProxyEnvelopeError(raw);\n if (submitEnvelopeError) {\n logger.error(\n `[asr-submit-response] 提交长录音任务失败: ${submitEnvelopeError}`,\n );\n return {\n ok: false,\n error: `Model Proxy ASR 提交失败: ${submitEnvelopeError}`,\n };\n }\n\n const data = unwrapResponse(raw);\n const taskId = normalizeOptionalText(data?.taskId);\n const requestId = normalizeOptionalText(data?.requestId);\n const status = normalizeLongRecordingStatus(data?.status);\n\n if (!taskId) {\n return {\n ok: false,\n error: \"Model Proxy ASR 响应缺少 taskId\",\n };\n }\n\n logger.info(\n `[asr] Model Proxy 长录音任务已提交: taskId=${taskId}, status=${status ?? \"UNKNOWN\"}, requestId=${requestId ?? \"n/a\"}`,\n );\n\n if (status && LONG_RECORDING_TERMINAL_FAILURE_STATUSES.has(status)) {\n return {\n ok: false,\n error: buildLongRecordingStatusError(data, status),\n };\n }\n\n return await pollLongRecordingTaskResult({\n apiKey,\n taskId,\n initialRequestId: requestId,\n audioDurationMs,\n apiConfig,\n logger,\n });\n}\n\n/**\n * 本地 Whisper 转写(§6.4 — 内置 whisper.cpp 推理)\n */\nasync function transcribeWithWhisperLocal(\n audioFilePath: string,\n config: AsrConfig,\n logger: Logger,\n): Promise<TranscriptionResult> {\n const { transcribeWithWhisperLocal: runLocal } = await import(\"./whisper-local.js\");\n\n // 解析插件数据目录(与模型/二进制存放位置)\n // 优先使用环境变量指定的目录,否则使用音频文件所在目录的上两级(recordings 的父目录)\n const dataDir =\n process.env.OPENCLAW_STATE_DIR ??\n process.env.QCLAW_STATE_DIR ??\n join(audioFilePath, \"..\", \"..\", \"..\");\n\n const localConfig = config.local ?? {};\n\n const result = await runLocal(\n audioFilePath,\n localConfig,\n dataDir,\n logger,\n );\n\n if (result.ok && result.text) {\n const { extractSummary: extract } = await import(\"./asr.js\");\n result.summary = extract(result.text);\n result.sourceInfo = {\n provider: \"whisper-local\",\n status: \"SUCCEEDED\",\n };\n }\n\n return result;\n}\n\n// ─── Helpers ───\n\nfunction resolveModelProxyLongRecordingSubmitEndpoint(apiConfig?: AsrApiConfig): string {\n return apiConfig?.endpoint?.trim() || getEnvUrls().modelProxyLongRecordingSubmitTaskUrl;\n}\n\nfunction resolveModelProxyApiKey(apiConfig?: AsrApiConfig): string {\n const requestApiKey = normalizeOptionalText(apiConfig?.apiKey);\n return normalizeApiKeyHeaderValue(requestApiKey ?? requireApiKey());\n}\n\nfunction resolveModelProxyLongRecordingQueryTaskResultBaseUrl(\n apiConfig?: AsrApiConfig,\n): string {\n const customEndpoint = apiConfig?.endpoint?.trim();\n if (customEndpoint) {\n return deriveLongRecordingQueryTaskResultBaseUrl(customEndpoint);\n }\n return getEnvUrls().modelProxyLongRecordingQueryTaskResultBaseUrl;\n}\n\nfunction deriveLongRecordingQueryTaskResultBaseUrl(endpoint: string): string {\n const trimmed = endpoint.replace(/\\/+$/, \"\");\n if (trimmed.endsWith(\"/submit-task\")) {\n return `${trimmed.slice(0, -\"/submit-task\".length)}/query-task-result`;\n }\n return trimmed;\n}\n\nfunction buildLongRecordingSubmitRequest(\n audioOssUrl: string,\n apiConfig?: AsrApiConfig,\n): ModelProxyLongRecordingSubmitRequest {\n const body: ModelProxyLongRecordingSubmitRequest = {\n audioOssUrl,\n };\n\n if (apiConfig?.language?.trim()) {\n body.language = apiConfig.language.trim();\n }\n if (typeof apiConfig?.enableNormalization === \"boolean\") {\n body.enableNormalization = apiConfig.enableNormalization;\n }\n\n return body;\n}\n\nasync function pollLongRecordingTaskResult(params: {\n apiKey: string;\n taskId: string;\n initialRequestId?: string;\n audioDurationMs?: number;\n apiConfig?: AsrApiConfig;\n logger: Logger;\n}): Promise<TranscriptionResult> {\n const {\n apiKey,\n taskId,\n initialRequestId,\n audioDurationMs,\n apiConfig,\n logger,\n } = params;\n const queryBaseUrl = resolveModelProxyLongRecordingQueryTaskResultBaseUrl(apiConfig);\n let lastStatus: string | undefined;\n\n const pollIntervalMs = getPollIntervalMs();\n\n for (let attempt = 1; attempt <= DEFAULT_LONG_RECORDING_MAX_POLL_ATTEMPTS; attempt++) {\n const queryUrl = `${queryBaseUrl}/${encodeURIComponent(taskId)}`;\n let res: Response;\n try {\n res = await fetch(queryUrl, {\n method: \"GET\",\n headers: {\n \"X-Api-Key-Id\": apiKey,\n },\n });\n } catch (err: any) {\n const msg = err?.message ?? String(err);\n logger.warn(\n `[asr-query] 长录音任务查询网络异常: taskId=${taskId}, attempt=${attempt}, error=${msg} — 等待下次轮询`,\n );\n if (attempt < DEFAULT_LONG_RECORDING_MAX_POLL_ATTEMPTS) {\n await sleep(pollIntervalMs);\n continue;\n }\n return {\n ok: false,\n error: `Model Proxy ASR query network error: ${msg}`,\n };\n }\n\n if (!res.ok) {\n const errText = await res.text().catch(() => \"\");\n if (isRetryableHttpStatus(res.status)) {\n logger.warn(\n `[asr-query] 长录音任务查询暂时失败: taskId=${taskId}, attempt=${attempt}, status=${res.status}, body=${errText.slice(0, 200)} — 等待下次轮询`,\n );\n if (attempt < DEFAULT_LONG_RECORDING_MAX_POLL_ATTEMPTS) {\n await sleep(pollIntervalMs);\n continue;\n }\n } else {\n logger.error(\n `[asr-query-response] 长录音任务查询失败: taskId=${taskId}, attempt=${attempt}, status=${res.status}, body=${errText.slice(0, 500)}`,\n );\n }\n return {\n ok: false,\n error: `Model Proxy ASR query error: ${res.status} ${errText.slice(0, 200)}`,\n };\n }\n\n const raw = (await res.json()) as\n | ModelProxyLongRecordingStatusResponse\n | ResponseEnvelope<ModelProxyLongRecordingStatusResponse>;\n const queryEnvelopeError = buildModelProxyEnvelopeError(raw);\n if (queryEnvelopeError) {\n logger.error(\n `[asr-query-response] 长录音任务查询失败: taskId=${taskId}, attempt=${attempt}, ${queryEnvelopeError}`,\n );\n return {\n ok: false,\n error: `Model Proxy ASR 查询失败: ${queryEnvelopeError}`,\n };\n }\n\n const data = unwrapResponse(raw);\n const status = normalizeLongRecordingStatus(data?.status) ?? \"UNKNOWN\";\n const requestId = normalizeOptionalText(data?.requestId) ?? initialRequestId;\n\n if (status !== lastStatus) {\n logger.info(\n `[asr-query-response] 长录音任务查询响应: taskId=${taskId}, attempt=${attempt}, body=${stringifyForLog(raw) ?? \"{}\"}`,\n );\n logger.info(\n `[asr] Model Proxy 长录音任务状态: taskId=${taskId}, status=${status}, attempt=${attempt}, requestId=${requestId ?? \"n/a\"}`,\n );\n lastStatus = status;\n }\n\n if (status === \"SUCCEEDED\") {\n return buildLongRecordingSuccessResult(\n taskId,\n requestId,\n data,\n audioDurationMs,\n logger,\n );\n }\n\n if (LONG_RECORDING_TERMINAL_FAILURE_STATUSES.has(status)) {\n return {\n ok: false,\n error: buildLongRecordingStatusError(data, status),\n };\n }\n\n if (!LONG_RECORDING_RUNNING_STATUSES.has(status)) {\n return {\n ok: false,\n error: `Model Proxy ASR 返回未知任务状态: ${status}`,\n };\n }\n\n if (attempt < DEFAULT_LONG_RECORDING_MAX_POLL_ATTEMPTS) {\n await sleep(pollIntervalMs);\n }\n }\n\n return {\n ok: false,\n error:\n `Model Proxy ASR 轮询超时: taskId=${taskId}, waited=${DEFAULT_LONG_RECORDING_MAX_POLL_ATTEMPTS * pollIntervalMs}ms`,\n };\n}\n\nfunction buildLongRecordingSuccessResult(\n taskId: string,\n requestId: string | undefined,\n data: ModelProxyLongRecordingStatusResponse | undefined,\n audioDurationMs: number | undefined,\n logger: Logger,\n): TranscriptionResult {\n const sourceTextList = normalizeLongRecordingSourceTextList(\n data?.recordResult?.sourceTextList,\n );\n const listResult = extractLongRecordingTextFromList(sourceTextList, audioDurationMs);\n const sourceText = normalizeOptionalText(data?.recordResult?.sourceText);\n const summaryText = normalizeOptionalText(data?.recordResult?.summaryResult) ?? \"\";\n const title = normalizeOptionalText(data?.recordResult?.title);\n const category = normalizeOptionalText(data?.recordResult?.category);\n const text = listResult.text ?? sourceText ?? summaryText;\n const status = normalizeLongRecordingStatus(data?.status) ?? \"SUCCEEDED\";\n\n if (!listResult.text && !sourceText && summaryText) {\n logger.warn(\n `[asr] Model Proxy 长录音结果缺少 sourceTextList/sourceText,已回退使用 summaryResult 作为转写文本: taskId=${taskId}`,\n );\n }\n\n logger.info(\n `[asr] Model Proxy 长录音转写完成: taskId=${taskId}, requestId=${requestId ?? \"n/a\"}, chars=${text.length}`,\n );\n\n return {\n ok: true,\n text,\n segments: listResult.segments,\n summary: title,\n summaryText,\n category,\n sourceInfo: {\n provider: \"model-proxy\",\n taskId,\n requestId,\n status,\n },\n rawResponse: data,\n };\n}\n\nfunction buildLongRecordingStatusError(\n data: ModelProxyLongRecordingStatusResponse | undefined,\n status: string,\n): string {\n const errorMessage = normalizeOptionalText(data?.errorMessage);\n return errorMessage\n ? `Model Proxy ASR ${status}: ${errorMessage}`\n : `Model Proxy ASR ${status}`;\n}\n\nfunction buildModelProxyEnvelopeError(\n payload:\n | ModelProxyLongRecordingStatusResponse\n | ResponseEnvelope<ModelProxyLongRecordingStatusResponse>,\n): string | undefined {\n if (!payload || typeof payload !== \"object\" || !(\"data\" in payload)) {\n return undefined;\n }\n\n const envelope = payload as ResponseEnvelope<ModelProxyLongRecordingStatusResponse>;\n const explicitFailure = envelope.success === false;\n const message = normalizeOptionalText(envelope.message);\n if (!explicitFailure && (!message || envelope.data)) {\n return undefined;\n }\n\n const code = normalizeOptionalCode(envelope.code);\n if (code && message) {\n return `${code} ${message}`;\n }\n return message ?? code ?? \"response envelope indicates failure\";\n}\n\nfunction unwrapResponse(\n payload:\n | ModelProxyLongRecordingStatusResponse\n | ResponseEnvelope<ModelProxyLongRecordingStatusResponse>,\n): ModelProxyLongRecordingStatusResponse | undefined {\n if (\n payload &&\n typeof payload === \"object\" &&\n \"data\" in payload &&\n payload.data &&\n typeof payload.data === \"object\"\n ) {\n return payload.data;\n }\n\n return payload as ModelProxyLongRecordingStatusResponse;\n}\n\nfunction normalizeApiKeyHeaderValue(apiKey: string): string {\n return apiKey.startsWith(\"Bearer \")\n ? apiKey.slice(\"Bearer \".length)\n : apiKey;\n}\n\nfunction normalizeLongRecordingStatus(status: unknown): string | undefined {\n return typeof status === \"string\" && status.trim()\n ? status.trim().toUpperCase()\n : undefined;\n}\n\nfunction normalizeOptionalText(value: unknown): string | undefined {\n return typeof value === \"string\" && value.trim()\n ? value.trim()\n : undefined;\n}\n\nfunction normalizeOptionalCode(value: unknown): string | undefined {\n if (typeof value === \"string\" && value.trim()) {\n return value.trim();\n }\n if (typeof value === \"number\" && Number.isFinite(value)) {\n return String(value);\n }\n return undefined;\n}\n\nfunction normalizeOptionalInteger(value: unknown): number | undefined {\n return Number.isInteger(value)\n ? Number(value)\n : undefined;\n}\n\nfunction normalizeOptionalNonNegativeNumber(value: unknown): number | undefined {\n return typeof value === \"number\" && Number.isFinite(value) && value >= 0\n ? value\n : undefined;\n}\n\nfunction normalizeLongRecordingSourceTextList(\n value: unknown,\n): Array<{\n content: string;\n speakerId?: number;\n startTime?: number;\n endTime?: number;\n}> {\n if (!Array.isArray(value)) {\n return [];\n }\n\n return value\n .flatMap((item) => {\n if (!item || typeof item !== \"object\") {\n return [];\n }\n\n const record = item as Record<string, unknown>;\n const content = normalizeOptionalText(record.content);\n if (!content) {\n return [];\n }\n\n return [{\n content,\n speakerId: normalizeOptionalInteger(record.speakerId),\n startTime: normalizeOptionalNonNegativeNumber(record.startTime),\n endTime: normalizeOptionalNonNegativeNumber(record.endTime),\n }];\n });\n}\n\nfunction extractLongRecordingTextFromList(\n items: Array<{\n content: string;\n speakerId?: number;\n startTime?: number;\n endTime?: number;\n }>,\n finalFallbackEndMs?: number,\n): {\n text?: string;\n segments: TranscriptSegment[];\n} {\n if (items.length === 0) {\n return {\n segments: [],\n };\n }\n\n const segments = items.map((item, index) => {\n const startMs = item.startTime ?? 0;\n const explicitEndMs = item.endTime;\n const nextStart = items[index + 1]?.startTime;\n const fallbackEndMs = index === items.length - 1\n ? normalizeOptionalNonNegativeNumber(finalFallbackEndMs)\n : undefined;\n const endMs = explicitEndMs ?? nextStart ?? fallbackEndMs ?? startMs;\n\n return {\n start_ms: startMs,\n end_ms: Math.max(startMs, endMs),\n text: item.content,\n speaker_id: item.speakerId,\n };\n });\n\n return {\n text: items.map((item) => item.content).join(\"\\n\\n\"),\n segments,\n };\n}\n\nfunction stringifyForLog(value: unknown, maxLength = 500): string | undefined {\n if (value == null) {\n return undefined;\n }\n\n if (typeof value === \"string\") {\n const trimmed = value.trim();\n return trimmed ? trimmed.slice(0, maxLength) : undefined;\n }\n\n try {\n const serialized = JSON.stringify(value);\n return serialized ? serialized.slice(0, maxLength) : undefined;\n } catch {\n return String(value).slice(0, maxLength);\n }\n}\n\nasync function sleep(ms: number): Promise<void> {\n await new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction isRetryableHttpStatus(status: number): boolean {\n return status === 429 || status >= 500;\n}\n\nfunction getHttpRetryBackoffMs(): number {\n const raw = process.env.OPENCLAW_ASR_HTTP_RETRY_BACKOFF_MS;\n if (raw) {\n const parsed = Number(raw);\n if (Number.isFinite(parsed) && parsed >= 0) {\n return parsed;\n }\n }\n return DEFAULT_HTTP_RETRY_BACKOFF_MS;\n}\n\nfunction getPollIntervalMs(): number {\n const raw = process.env.OPENCLAW_ASR_POLL_INTERVAL_MS;\n if (raw) {\n const parsed = Number(raw);\n if (Number.isFinite(parsed) && parsed >= 0) {\n return parsed;\n }\n }\n return DEFAULT_LONG_RECORDING_POLL_INTERVAL_MS;\n}\n\n/**\n * 带重试的 fetch 包装:\n * - HTTP 5xx / 429:按指数退避重试\n * - 网络异常(fetch throw):按指数退避重试\n * - HTTP 4xx(除 429)/ 2xx / 3xx:直接返回,由调用方处理\n *\n * 用于 ASR submit 这类一次性请求;polling 走自己的节奏,无需此包装。\n */\nasync function fetchWithRetry(\n url: string,\n init: RequestInit,\n options: {\n logger: Logger;\n context: string;\n maxAttempts?: number;\n backoffMs?: number;\n },\n): Promise<Response> {\n const maxAttempts = options.maxAttempts ?? DEFAULT_HTTP_MAX_ATTEMPTS;\n const baseBackoff = options.backoffMs ?? getHttpRetryBackoffMs();\n let lastError: unknown;\n\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n try {\n const res = await fetch(url, init);\n if (isRetryableHttpStatus(res.status) && attempt < maxAttempts) {\n const errText = await res.text().catch(() => \"\");\n const delay = baseBackoff * Math.pow(2, attempt - 1);\n options.logger.warn(\n `[${options.context}] HTTP ${res.status} (attempt ${attempt}/${maxAttempts}), ${delay}ms 后重试, body=${errText.slice(0, 200)}`,\n );\n await sleep(delay);\n continue;\n }\n return res;\n } catch (err) {\n lastError = err;\n if (attempt < maxAttempts) {\n const delay = baseBackoff * Math.pow(2, attempt - 1);\n const msg = (err as any)?.message ?? String(err);\n options.logger.warn(\n `[${options.context}] 网络异常 (attempt ${attempt}/${maxAttempts}): ${msg}, ${delay}ms 后重试`,\n );\n await sleep(delay);\n continue;\n }\n }\n }\n\n throw lastError instanceof Error ? lastError : new Error(String(lastError));\n}\n\nfunction extractTranscriptSummary(text: string): string {\n const normalized = text.replace(/\\s+/g, \" \").trim();\n if (!normalized) {\n return \"\";\n }\n\n const sentence = normalized\n .split(/[。!?!?]/)\n .map((part) => part.trim())\n .find((part) => part.length > 0);\n\n const candidate = sentence || normalized;\n return candidate.length <= 120\n ? candidate\n : `${candidate.slice(0, 117).trimEnd()}...`;\n}\n/** 毫秒 → \"MM:SS\" */\nfunction formatTimestamp(ms: number): string {\n const totalSeconds = Math.floor(ms / 1000);\n const minutes = Math.floor(totalSeconds / 60);\n const seconds = totalSeconds % 60;\n return `${String(minutes).padStart(2, \"0\")}:${String(seconds).padStart(2, \"0\")}`;\n}\n\n/** 秒 → \"HH:MM:SS\" 或 \"MM:SS\" */\nfunction formatDuration(seconds: number): string {\n const h = Math.floor(seconds / 3600);\n const m = Math.floor((seconds % 3600) / 60);\n const s = Math.floor(seconds % 60);\n if (h > 0) {\n return `${h}:${String(m).padStart(2, \"0\")}:${String(s).padStart(2, \"0\")}`;\n }\n return `${String(m).padStart(2, \"0\")}:${String(s).padStart(2, \"0\")}`;\n}\n\nfunction hasText(value: unknown): boolean {\n return typeof value === \"string\" && value.trim().length > 0;\n}\n\nfunction formatTranscriptSegmentText(segment: TranscriptSegment): string {\n const text = segment.text.trim();\n if (!text) {\n return text;\n }\n\n if (typeof segment.speaker_id === \"number\") {\n return `说话人${segment.speaker_id}:${text}`;\n }\n\n return text;\n}\n","'use strict';\n\nconst BINARY_TYPES = ['nodebuffer', 'arraybuffer', 'fragments'];\nconst hasBlob = typeof Blob !== 'undefined';\n\nif (hasBlob) BINARY_TYPES.push('blob');\n\nmodule.exports = {\n BINARY_TYPES,\n CLOSE_TIMEOUT: 30000,\n EMPTY_BUFFER: Buffer.alloc(0),\n GUID: '258EAFA5-E914-47DA-95CA-C5AB0DC85B11',\n hasBlob,\n kForOnEventAttribute: Symbol('kIsForOnEventAttribute'),\n kListener: Symbol('kListener'),\n kStatusCode: Symbol('status-code'),\n kWebSocket: Symbol('websocket'),\n NOOP: () => {}\n};\n","'use strict';\n\nconst { EMPTY_BUFFER } = require('./constants');\n\nconst FastBuffer = Buffer[Symbol.species];\n\n/**\n * Merges an array of buffers into a new buffer.\n *\n * @param {Buffer[]} list The array of buffers to concat\n * @param {Number} totalLength The total length of buffers in the list\n * @return {Buffer} The resulting buffer\n * @public\n */\nfunction concat(list, totalLength) {\n if (list.length === 0) return EMPTY_BUFFER;\n if (list.length === 1) return list[0];\n\n const target = Buffer.allocUnsafe(totalLength);\n let offset = 0;\n\n for (let i = 0; i < list.length; i++) {\n const buf = list[i];\n target.set(buf, offset);\n offset += buf.length;\n }\n\n if (offset < totalLength) {\n return new FastBuffer(target.buffer, target.byteOffset, offset);\n }\n\n return target;\n}\n\n/**\n * Masks a buffer using the given mask.\n *\n * @param {Buffer} source The buffer to mask\n * @param {Buffer} mask The mask to use\n * @param {Buffer} output The buffer where to store the result\n * @param {Number} offset The offset at which to start writing\n * @param {Number} length The number of bytes to mask.\n * @public\n */\nfunction _mask(source, mask, output, offset, length) {\n for (let i = 0; i < length; i++) {\n output[offset + i] = source[i] ^ mask[i & 3];\n }\n}\n\n/**\n * Unmasks a buffer using the given mask.\n *\n * @param {Buffer} buffer The buffer to unmask\n * @param {Buffer} mask The mask to use\n * @public\n */\nfunction _unmask(buffer, mask) {\n for (let i = 0; i < buffer.length; i++) {\n buffer[i] ^= mask[i & 3];\n }\n}\n\n/**\n * Converts a buffer to an `ArrayBuffer`.\n *\n * @param {Buffer} buf The buffer to convert\n * @return {ArrayBuffer} Converted buffer\n * @public\n */\nfunction toArrayBuffer(buf) {\n if (buf.length === buf.buffer.byteLength) {\n return buf.buffer;\n }\n\n return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.length);\n}\n\n/**\n * Converts `data` to a `Buffer`.\n *\n * @param {*} data The data to convert\n * @return {Buffer} The buffer\n * @throws {TypeError}\n * @public\n */\nfunction toBuffer(data) {\n toBuffer.readOnly = true;\n\n if (Buffer.isBuffer(data)) return data;\n\n let buf;\n\n if (data instanceof ArrayBuffer) {\n buf = new FastBuffer(data);\n } else if (ArrayBuffer.isView(data)) {\n buf = new FastBuffer(data.buffer, data.byteOffset, data.byteLength);\n } else {\n buf = Buffer.from(data);\n toBuffer.readOnly = false;\n }\n\n return buf;\n}\n\nmodule.exports = {\n concat,\n mask: _mask,\n toArrayBuffer,\n toBuffer,\n unmask: _unmask\n};\n\n/* istanbul ignore else */\nif (!process.env.WS_NO_BUFFER_UTIL) {\n try {\n const bufferUtil = require('bufferutil');\n\n module.exports.mask = function (source, mask, output, offset, length) {\n if (length < 48) _mask(source, mask, output, offset, length);\n else bufferUtil.mask(source, mask, output, offset, length);\n };\n\n module.exports.unmask = function (buffer, mask) {\n if (buffer.length < 32) _unmask(buffer, mask);\n else bufferUtil.unmask(buffer, mask);\n };\n } catch (e) {\n // Continue regardless of the error.\n }\n}\n","'use strict';\n\nconst kDone = Symbol('kDone');\nconst kRun = Symbol('kRun');\n\n/**\n * A very simple job queue with adjustable concurrency. Adapted from\n * https://github.com/STRML/async-limiter\n */\nclass Limiter {\n /**\n * Creates a new `Limiter`.\n *\n * @param {Number} [concurrency=Infinity] The maximum number of jobs allowed\n * to run concurrently\n */\n constructor(concurrency) {\n this[kDone] = () => {\n this.pending--;\n this[kRun]();\n };\n this.concurrency = concurrency || Infinity;\n this.jobs = [];\n this.pending = 0;\n }\n\n /**\n * Adds a job to the queue.\n *\n * @param {Function} job The job to run\n * @public\n */\n add(job) {\n this.jobs.push(job);\n this[kRun]();\n }\n\n /**\n * Removes a job from the queue and runs it if possible.\n *\n * @private\n */\n [kRun]() {\n if (this.pending === this.concurrency) return;\n\n if (this.jobs.length) {\n const job = this.jobs.shift();\n\n this.pending++;\n job(this[kDone]);\n }\n }\n}\n\nmodule.exports = Limiter;\n","'use strict';\n\nconst zlib = require('zlib');\n\nconst bufferUtil = require('./buffer-util');\nconst Limiter = require('./limiter');\nconst { kStatusCode } = require('./constants');\n\nconst FastBuffer = Buffer[Symbol.species];\nconst TRAILER = Buffer.from([0x00, 0x00, 0xff, 0xff]);\nconst kPerMessageDeflate = Symbol('permessage-deflate');\nconst kTotalLength = Symbol('total-length');\nconst kCallback = Symbol('callback');\nconst kBuffers = Symbol('buffers');\nconst kError = Symbol('error');\n\n//\n// We limit zlib concurrency, which prevents severe memory fragmentation\n// as documented in https://github.com/nodejs/node/issues/8871#issuecomment-250915913\n// and https://github.com/websockets/ws/issues/1202\n//\n// Intentionally global; it's the global thread pool that's an issue.\n//\nlet zlibLimiter;\n\n/**\n * permessage-deflate implementation.\n */\nclass PerMessageDeflate {\n /**\n * Creates a PerMessageDeflate instance.\n *\n * @param {Object} [options] Configuration options\n * @param {(Boolean|Number)} [options.clientMaxWindowBits] Advertise support\n * for, or request, a custom client window size\n * @param {Boolean} [options.clientNoContextTakeover=false] Advertise/\n * acknowledge disabling of client context takeover\n * @param {Number} [options.concurrencyLimit=10] The number of concurrent\n * calls to zlib\n * @param {(Boolean|Number)} [options.serverMaxWindowBits] Request/confirm the\n * use of a custom server window size\n * @param {Boolean} [options.serverNoContextTakeover=false] Request/accept\n * disabling of server context takeover\n * @param {Number} [options.threshold=1024] Size (in bytes) below which\n * messages should not be compressed if context takeover is disabled\n * @param {Object} [options.zlibDeflateOptions] Options to pass to zlib on\n * deflate\n * @param {Object} [options.zlibInflateOptions] Options to pass to zlib on\n * inflate\n * @param {Boolean} [isServer=false] Create the instance in either server or\n * client mode\n * @param {Number} [maxPayload=0] The maximum allowed message length\n */\n constructor(options, isServer, maxPayload) {\n this._maxPayload = maxPayload | 0;\n this._options = options || {};\n this._threshold =\n this._options.threshold !== undefined ? this._options.threshold : 1024;\n this._isServer = !!isServer;\n this._deflate = null;\n this._inflate = null;\n\n this.params = null;\n\n if (!zlibLimiter) {\n const concurrency =\n this._options.concurrencyLimit !== undefined\n ? this._options.concurrencyLimit\n : 10;\n zlibLimiter = new Limiter(concurrency);\n }\n }\n\n /**\n * @type {String}\n */\n static get extensionName() {\n return 'permessage-deflate';\n }\n\n /**\n * Create an extension negotiation offer.\n *\n * @return {Object} Extension parameters\n * @public\n */\n offer() {\n const params = {};\n\n if (this._options.serverNoContextTakeover) {\n params.server_no_context_takeover = true;\n }\n if (this._options.clientNoContextTakeover) {\n params.client_no_context_takeover = true;\n }\n if (this._options.serverMaxWindowBits) {\n params.server_max_window_bits = this._options.serverMaxWindowBits;\n }\n if (this._options.clientMaxWindowBits) {\n params.client_max_window_bits = this._options.clientMaxWindowBits;\n } else if (this._options.clientMaxWindowBits == null) {\n params.client_max_window_bits = true;\n }\n\n return params;\n }\n\n /**\n * Accept an extension negotiation offer/response.\n *\n * @param {Array} configurations The extension negotiation offers/reponse\n * @return {Object} Accepted configuration\n * @public\n */\n accept(configurations) {\n configurations = this.normalizeParams(configurations);\n\n this.params = this._isServer\n ? this.acceptAsServer(configurations)\n : this.acceptAsClient(configurations);\n\n return this.params;\n }\n\n /**\n * Releases all resources used by the extension.\n *\n * @public\n */\n cleanup() {\n if (this._inflate) {\n this._inflate.close();\n this._inflate = null;\n }\n\n if (this._deflate) {\n const callback = this._deflate[kCallback];\n\n this._deflate.close();\n this._deflate = null;\n\n if (callback) {\n callback(\n new Error(\n 'The deflate stream was closed while data was being processed'\n )\n );\n }\n }\n }\n\n /**\n * Accept an extension negotiation offer.\n *\n * @param {Array} offers The extension negotiation offers\n * @return {Object} Accepted configuration\n * @private\n */\n acceptAsServer(offers) {\n const opts = this._options;\n const accepted = offers.find((params) => {\n if (\n (opts.serverNoContextTakeover === false &&\n params.server_no_context_takeover) ||\n (params.server_max_window_bits &&\n (opts.serverMaxWindowBits === false ||\n (typeof opts.serverMaxWindowBits === 'number' &&\n opts.serverMaxWindowBits > params.server_max_window_bits))) ||\n (typeof opts.clientMaxWindowBits === 'number' &&\n !params.client_max_window_bits)\n ) {\n return false;\n }\n\n return true;\n });\n\n if (!accepted) {\n throw new Error('None of the extension offers can be accepted');\n }\n\n if (opts.serverNoContextTakeover) {\n accepted.server_no_context_takeover = true;\n }\n if (opts.clientNoContextTakeover) {\n accepted.client_no_context_takeover = true;\n }\n if (typeof opts.serverMaxWindowBits === 'number') {\n accepted.server_max_window_bits = opts.serverMaxWindowBits;\n }\n if (typeof opts.clientMaxWindowBits === 'number') {\n accepted.client_max_window_bits = opts.clientMaxWindowBits;\n } else if (\n accepted.client_max_window_bits === true ||\n opts.clientMaxWindowBits === false\n ) {\n delete accepted.client_max_window_bits;\n }\n\n return accepted;\n }\n\n /**\n * Accept the extension negotiation response.\n *\n * @param {Array} response The extension negotiation response\n * @return {Object} Accepted configuration\n * @private\n */\n acceptAsClient(response) {\n const params = response[0];\n\n if (\n this._options.clientNoContextTakeover === false &&\n params.client_no_context_takeover\n ) {\n throw new Error('Unexpected parameter \"client_no_context_takeover\"');\n }\n\n if (!params.client_max_window_bits) {\n if (typeof this._options.clientMaxWindowBits === 'number') {\n params.client_max_window_bits = this._options.clientMaxWindowBits;\n }\n } else if (\n this._options.clientMaxWindowBits === false ||\n (typeof this._options.clientMaxWindowBits === 'number' &&\n params.client_max_window_bits > this._options.clientMaxWindowBits)\n ) {\n throw new Error(\n 'Unexpected or invalid parameter \"client_max_window_bits\"'\n );\n }\n\n return params;\n }\n\n /**\n * Normalize parameters.\n *\n * @param {Array} configurations The extension negotiation offers/reponse\n * @return {Array} The offers/response with normalized parameters\n * @private\n */\n normalizeParams(configurations) {\n configurations.forEach((params) => {\n Object.keys(params).forEach((key) => {\n let value = params[key];\n\n if (value.length > 1) {\n throw new Error(`Parameter \"${key}\" must have only a single value`);\n }\n\n value = value[0];\n\n if (key === 'client_max_window_bits') {\n if (value !== true) {\n const num = +value;\n if (!Number.isInteger(num) || num < 8 || num > 15) {\n throw new TypeError(\n `Invalid value for parameter \"${key}\": ${value}`\n );\n }\n value = num;\n } else if (!this._isServer) {\n throw new TypeError(\n `Invalid value for parameter \"${key}\": ${value}`\n );\n }\n } else if (key === 'server_max_window_bits') {\n const num = +value;\n if (!Number.isInteger(num) || num < 8 || num > 15) {\n throw new TypeError(\n `Invalid value for parameter \"${key}\": ${value}`\n );\n }\n value = num;\n } else if (\n key === 'client_no_context_takeover' ||\n key === 'server_no_context_takeover'\n ) {\n if (value !== true) {\n throw new TypeError(\n `Invalid value for parameter \"${key}\": ${value}`\n );\n }\n } else {\n throw new Error(`Unknown parameter \"${key}\"`);\n }\n\n params[key] = value;\n });\n });\n\n return configurations;\n }\n\n /**\n * Decompress data. Concurrency limited.\n *\n * @param {Buffer} data Compressed data\n * @param {Boolean} fin Specifies whether or not this is the last fragment\n * @param {Function} callback Callback\n * @public\n */\n decompress(data, fin, callback) {\n zlibLimiter.add((done) => {\n this._decompress(data, fin, (err, result) => {\n done();\n callback(err, result);\n });\n });\n }\n\n /**\n * Compress data. Concurrency limited.\n *\n * @param {(Buffer|String)} data Data to compress\n * @param {Boolean} fin Specifies whether or not this is the last fragment\n * @param {Function} callback Callback\n * @public\n */\n compress(data, fin, callback) {\n zlibLimiter.add((done) => {\n this._compress(data, fin, (err, result) => {\n done();\n callback(err, result);\n });\n });\n }\n\n /**\n * Decompress data.\n *\n * @param {Buffer} data Compressed data\n * @param {Boolean} fin Specifies whether or not this is the last fragment\n * @param {Function} callback Callback\n * @private\n */\n _decompress(data, fin, callback) {\n const endpoint = this._isServer ? 'client' : 'server';\n\n if (!this._inflate) {\n const key = `${endpoint}_max_window_bits`;\n const windowBits =\n typeof this.params[key] !== 'number'\n ? zlib.Z_DEFAULT_WINDOWBITS\n : this.params[key];\n\n this._inflate = zlib.createInflateRaw({\n ...this._options.zlibInflateOptions,\n windowBits\n });\n this._inflate[kPerMessageDeflate] = this;\n this._inflate[kTotalLength] = 0;\n this._inflate[kBuffers] = [];\n this._inflate.on('error', inflateOnError);\n this._inflate.on('data', inflateOnData);\n }\n\n this._inflate[kCallback] = callback;\n\n this._inflate.write(data);\n if (fin) this._inflate.write(TRAILER);\n\n this._inflate.flush(() => {\n const err = this._inflate[kError];\n\n if (err) {\n this._inflate.close();\n this._inflate = null;\n callback(err);\n return;\n }\n\n const data = bufferUtil.concat(\n this._inflate[kBuffers],\n this._inflate[kTotalLength]\n );\n\n if (this._inflate._readableState.endEmitted) {\n this._inflate.close();\n this._inflate = null;\n } else {\n this._inflate[kTotalLength] = 0;\n this._inflate[kBuffers] = [];\n\n if (fin && this.params[`${endpoint}_no_context_takeover`]) {\n this._inflate.reset();\n }\n }\n\n callback(null, data);\n });\n }\n\n /**\n * Compress data.\n *\n * @param {(Buffer|String)} data Data to compress\n * @param {Boolean} fin Specifies whether or not this is the last fragment\n * @param {Function} callback Callback\n * @private\n */\n _compress(data, fin, callback) {\n const endpoint = this._isServer ? 'server' : 'client';\n\n if (!this._deflate) {\n const key = `${endpoint}_max_window_bits`;\n const windowBits =\n typeof this.params[key] !== 'number'\n ? zlib.Z_DEFAULT_WINDOWBITS\n : this.params[key];\n\n this._deflate = zlib.createDeflateRaw({\n ...this._options.zlibDeflateOptions,\n windowBits\n });\n\n this._deflate[kTotalLength] = 0;\n this._deflate[kBuffers] = [];\n\n this._deflate.on('data', deflateOnData);\n }\n\n this._deflate[kCallback] = callback;\n\n this._deflate.write(data);\n this._deflate.flush(zlib.Z_SYNC_FLUSH, () => {\n if (!this._deflate) {\n //\n // The deflate stream was closed while data was being processed.\n //\n return;\n }\n\n let data = bufferUtil.concat(\n this._deflate[kBuffers],\n this._deflate[kTotalLength]\n );\n\n if (fin) {\n data = new FastBuffer(data.buffer, data.byteOffset, data.length - 4);\n }\n\n //\n // Ensure that the callback will not be called again in\n // `PerMessageDeflate#cleanup()`.\n //\n this._deflate[kCallback] = null;\n\n this._deflate[kTotalLength] = 0;\n this._deflate[kBuffers] = [];\n\n if (fin && this.params[`${endpoint}_no_context_takeover`]) {\n this._deflate.reset();\n }\n\n callback(null, data);\n });\n }\n}\n\nmodule.exports = PerMessageDeflate;\n\n/**\n * The listener of the `zlib.DeflateRaw` stream `'data'` event.\n *\n * @param {Buffer} chunk A chunk of data\n * @private\n */\nfunction deflateOnData(chunk) {\n this[kBuffers].push(chunk);\n this[kTotalLength] += chunk.length;\n}\n\n/**\n * The listener of the `zlib.InflateRaw` stream `'data'` event.\n *\n * @param {Buffer} chunk A chunk of data\n * @private\n */\nfunction inflateOnData(chunk) {\n this[kTotalLength] += chunk.length;\n\n if (\n this[kPerMessageDeflate]._maxPayload < 1 ||\n this[kTotalLength] <= this[kPerMessageDeflate]._maxPayload\n ) {\n this[kBuffers].push(chunk);\n return;\n }\n\n this[kError] = new RangeError('Max payload size exceeded');\n this[kError].code = 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH';\n this[kError][kStatusCode] = 1009;\n this.removeListener('data', inflateOnData);\n\n //\n // The choice to employ `zlib.reset()` over `zlib.close()` is dictated by the\n // fact that in Node.js versions prior to 13.10.0, the callback for\n // `zlib.flush()` is not called if `zlib.close()` is used. Utilizing\n // `zlib.reset()` ensures that either the callback is invoked or an error is\n // emitted.\n //\n this.reset();\n}\n\n/**\n * The listener of the `zlib.InflateRaw` stream `'error'` event.\n *\n * @param {Error} err The emitted error\n * @private\n */\nfunction inflateOnError(err) {\n //\n // There is no need to call `Zlib#close()` as the handle is automatically\n // closed when an error is emitted.\n //\n this[kPerMessageDeflate]._inflate = null;\n\n if (this[kError]) {\n this[kCallback](this[kError]);\n return;\n }\n\n err[kStatusCode] = 1007;\n this[kCallback](err);\n}\n","'use strict';\n\nconst { isUtf8 } = require('buffer');\n\nconst { hasBlob } = require('./constants');\n\n//\n// Allowed token characters:\n//\n// '!', '#', '$', '%', '&', ''', '*', '+', '-',\n// '.', 0-9, A-Z, '^', '_', '`', a-z, '|', '~'\n//\n// tokenChars[32] === 0 // ' '\n// tokenChars[33] === 1 // '!'\n// tokenChars[34] === 0 // '\"'\n// ...\n//\n// prettier-ignore\nconst tokenChars = [\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 15\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 31\n 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, // 32 - 47\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 48 - 63\n 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64 - 79\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, // 80 - 95\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96 - 111\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0 // 112 - 127\n];\n\n/**\n * Checks if a status code is allowed in a close frame.\n *\n * @param {Number} code The status code\n * @return {Boolean} `true` if the status code is valid, else `false`\n * @public\n */\nfunction isValidStatusCode(code) {\n return (\n (code >= 1000 &&\n code <= 1014 &&\n code !== 1004 &&\n code !== 1005 &&\n code !== 1006) ||\n (code >= 3000 && code <= 4999)\n );\n}\n\n/**\n * Checks if a given buffer contains only correct UTF-8.\n * Ported from https://www.cl.cam.ac.uk/%7Emgk25/ucs/utf8_check.c by\n * Markus Kuhn.\n *\n * @param {Buffer} buf The buffer to check\n * @return {Boolean} `true` if `buf` contains only correct UTF-8, else `false`\n * @public\n */\nfunction _isValidUTF8(buf) {\n const len = buf.length;\n let i = 0;\n\n while (i < len) {\n if ((buf[i] & 0x80) === 0) {\n // 0xxxxxxx\n i++;\n } else if ((buf[i] & 0xe0) === 0xc0) {\n // 110xxxxx 10xxxxxx\n if (\n i + 1 === len ||\n (buf[i + 1] & 0xc0) !== 0x80 ||\n (buf[i] & 0xfe) === 0xc0 // Overlong\n ) {\n return false;\n }\n\n i += 2;\n } else if ((buf[i] & 0xf0) === 0xe0) {\n // 1110xxxx 10xxxxxx 10xxxxxx\n if (\n i + 2 >= len ||\n (buf[i + 1] & 0xc0) !== 0x80 ||\n (buf[i + 2] & 0xc0) !== 0x80 ||\n (buf[i] === 0xe0 && (buf[i + 1] & 0xe0) === 0x80) || // Overlong\n (buf[i] === 0xed && (buf[i + 1] & 0xe0) === 0xa0) // Surrogate (U+D800 - U+DFFF)\n ) {\n return false;\n }\n\n i += 3;\n } else if ((buf[i] & 0xf8) === 0xf0) {\n // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx\n if (\n i + 3 >= len ||\n (buf[i + 1] & 0xc0) !== 0x80 ||\n (buf[i + 2] & 0xc0) !== 0x80 ||\n (buf[i + 3] & 0xc0) !== 0x80 ||\n (buf[i] === 0xf0 && (buf[i + 1] & 0xf0) === 0x80) || // Overlong\n (buf[i] === 0xf4 && buf[i + 1] > 0x8f) ||\n buf[i] > 0xf4 // > U+10FFFF\n ) {\n return false;\n }\n\n i += 4;\n } else {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * Determines whether a value is a `Blob`.\n *\n * @param {*} value The value to be tested\n * @return {Boolean} `true` if `value` is a `Blob`, else `false`\n * @private\n */\nfunction isBlob(value) {\n return (\n hasBlob &&\n typeof value === 'object' &&\n typeof value.arrayBuffer === 'function' &&\n typeof value.type === 'string' &&\n typeof value.stream === 'function' &&\n (value[Symbol.toStringTag] === 'Blob' ||\n value[Symbol.toStringTag] === 'File')\n );\n}\n\nmodule.exports = {\n isBlob,\n isValidStatusCode,\n isValidUTF8: _isValidUTF8,\n tokenChars\n};\n\nif (isUtf8) {\n module.exports.isValidUTF8 = function (buf) {\n return buf.length < 24 ? _isValidUTF8(buf) : isUtf8(buf);\n };\n} /* istanbul ignore else */ else if (!process.env.WS_NO_UTF_8_VALIDATE) {\n try {\n const isValidUTF8 = require('utf-8-validate');\n\n module.exports.isValidUTF8 = function (buf) {\n return buf.length < 32 ? _isValidUTF8(buf) : isValidUTF8(buf);\n };\n } catch (e) {\n // Continue regardless of the error.\n }\n}\n","'use strict';\n\nconst { Writable } = require('stream');\n\nconst PerMessageDeflate = require('./permessage-deflate');\nconst {\n BINARY_TYPES,\n EMPTY_BUFFER,\n kStatusCode,\n kWebSocket\n} = require('./constants');\nconst { concat, toArrayBuffer, unmask } = require('./buffer-util');\nconst { isValidStatusCode, isValidUTF8 } = require('./validation');\n\nconst FastBuffer = Buffer[Symbol.species];\n\nconst GET_INFO = 0;\nconst GET_PAYLOAD_LENGTH_16 = 1;\nconst GET_PAYLOAD_LENGTH_64 = 2;\nconst GET_MASK = 3;\nconst GET_DATA = 4;\nconst INFLATING = 5;\nconst DEFER_EVENT = 6;\n\n/**\n * HyBi Receiver implementation.\n *\n * @extends Writable\n */\nclass Receiver extends Writable {\n /**\n * Creates a Receiver instance.\n *\n * @param {Object} [options] Options object\n * @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether\n * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted\n * multiple times in the same tick\n * @param {String} [options.binaryType=nodebuffer] The type for binary data\n * @param {Object} [options.extensions] An object containing the negotiated\n * extensions\n * @param {Boolean} [options.isServer=false] Specifies whether to operate in\n * client or server mode\n * @param {Number} [options.maxPayload=0] The maximum allowed message length\n * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or\n * not to skip UTF-8 validation for text and close messages\n */\n constructor(options = {}) {\n super();\n\n this._allowSynchronousEvents =\n options.allowSynchronousEvents !== undefined\n ? options.allowSynchronousEvents\n : true;\n this._binaryType = options.binaryType || BINARY_TYPES[0];\n this._extensions = options.extensions || {};\n this._isServer = !!options.isServer;\n this._maxPayload = options.maxPayload | 0;\n this._skipUTF8Validation = !!options.skipUTF8Validation;\n this[kWebSocket] = undefined;\n\n this._bufferedBytes = 0;\n this._buffers = [];\n\n this._compressed = false;\n this._payloadLength = 0;\n this._mask = undefined;\n this._fragmented = 0;\n this._masked = false;\n this._fin = false;\n this._opcode = 0;\n\n this._totalPayloadLength = 0;\n this._messageLength = 0;\n this._fragments = [];\n\n this._errored = false;\n this._loop = false;\n this._state = GET_INFO;\n }\n\n /**\n * Implements `Writable.prototype._write()`.\n *\n * @param {Buffer} chunk The chunk of data to write\n * @param {String} encoding The character encoding of `chunk`\n * @param {Function} cb Callback\n * @private\n */\n _write(chunk, encoding, cb) {\n if (this._opcode === 0x08 && this._state == GET_INFO) return cb();\n\n this._bufferedBytes += chunk.length;\n this._buffers.push(chunk);\n this.startLoop(cb);\n }\n\n /**\n * Consumes `n` bytes from the buffered data.\n *\n * @param {Number} n The number of bytes to consume\n * @return {Buffer} The consumed bytes\n * @private\n */\n consume(n) {\n this._bufferedBytes -= n;\n\n if (n === this._buffers[0].length) return this._buffers.shift();\n\n if (n < this._buffers[0].length) {\n const buf = this._buffers[0];\n this._buffers[0] = new FastBuffer(\n buf.buffer,\n buf.byteOffset + n,\n buf.length - n\n );\n\n return new FastBuffer(buf.buffer, buf.byteOffset, n);\n }\n\n const dst = Buffer.allocUnsafe(n);\n\n do {\n const buf = this._buffers[0];\n const offset = dst.length - n;\n\n if (n >= buf.length) {\n dst.set(this._buffers.shift(), offset);\n } else {\n dst.set(new Uint8Array(buf.buffer, buf.byteOffset, n), offset);\n this._buffers[0] = new FastBuffer(\n buf.buffer,\n buf.byteOffset + n,\n buf.length - n\n );\n }\n\n n -= buf.length;\n } while (n > 0);\n\n return dst;\n }\n\n /**\n * Starts the parsing loop.\n *\n * @param {Function} cb Callback\n * @private\n */\n startLoop(cb) {\n this._loop = true;\n\n do {\n switch (this._state) {\n case GET_INFO:\n this.getInfo(cb);\n break;\n case GET_PAYLOAD_LENGTH_16:\n this.getPayloadLength16(cb);\n break;\n case GET_PAYLOAD_LENGTH_64:\n this.getPayloadLength64(cb);\n break;\n case GET_MASK:\n this.getMask();\n break;\n case GET_DATA:\n this.getData(cb);\n break;\n case INFLATING:\n case DEFER_EVENT:\n this._loop = false;\n return;\n }\n } while (this._loop);\n\n if (!this._errored) cb();\n }\n\n /**\n * Reads the first two bytes of a frame.\n *\n * @param {Function} cb Callback\n * @private\n */\n getInfo(cb) {\n if (this._bufferedBytes < 2) {\n this._loop = false;\n return;\n }\n\n const buf = this.consume(2);\n\n if ((buf[0] & 0x30) !== 0x00) {\n const error = this.createError(\n RangeError,\n 'RSV2 and RSV3 must be clear',\n true,\n 1002,\n 'WS_ERR_UNEXPECTED_RSV_2_3'\n );\n\n cb(error);\n return;\n }\n\n const compressed = (buf[0] & 0x40) === 0x40;\n\n if (compressed && !this._extensions[PerMessageDeflate.extensionName]) {\n const error = this.createError(\n RangeError,\n 'RSV1 must be clear',\n true,\n 1002,\n 'WS_ERR_UNEXPECTED_RSV_1'\n );\n\n cb(error);\n return;\n }\n\n this._fin = (buf[0] & 0x80) === 0x80;\n this._opcode = buf[0] & 0x0f;\n this._payloadLength = buf[1] & 0x7f;\n\n if (this._opcode === 0x00) {\n if (compressed) {\n const error = this.createError(\n RangeError,\n 'RSV1 must be clear',\n true,\n 1002,\n 'WS_ERR_UNEXPECTED_RSV_1'\n );\n\n cb(error);\n return;\n }\n\n if (!this._fragmented) {\n const error = this.createError(\n RangeError,\n 'invalid opcode 0',\n true,\n 1002,\n 'WS_ERR_INVALID_OPCODE'\n );\n\n cb(error);\n return;\n }\n\n this._opcode = this._fragmented;\n } else if (this._opcode === 0x01 || this._opcode === 0x02) {\n if (this._fragmented) {\n const error = this.createError(\n RangeError,\n `invalid opcode ${this._opcode}`,\n true,\n 1002,\n 'WS_ERR_INVALID_OPCODE'\n );\n\n cb(error);\n return;\n }\n\n this._compressed = compressed;\n } else if (this._opcode > 0x07 && this._opcode < 0x0b) {\n if (!this._fin) {\n const error = this.createError(\n RangeError,\n 'FIN must be set',\n true,\n 1002,\n 'WS_ERR_EXPECTED_FIN'\n );\n\n cb(error);\n return;\n }\n\n if (compressed) {\n const error = this.createError(\n RangeError,\n 'RSV1 must be clear',\n true,\n 1002,\n 'WS_ERR_UNEXPECTED_RSV_1'\n );\n\n cb(error);\n return;\n }\n\n if (\n this._payloadLength > 0x7d ||\n (this._opcode === 0x08 && this._payloadLength === 1)\n ) {\n const error = this.createError(\n RangeError,\n `invalid payload length ${this._payloadLength}`,\n true,\n 1002,\n 'WS_ERR_INVALID_CONTROL_PAYLOAD_LENGTH'\n );\n\n cb(error);\n return;\n }\n } else {\n const error = this.createError(\n RangeError,\n `invalid opcode ${this._opcode}`,\n true,\n 1002,\n 'WS_ERR_INVALID_OPCODE'\n );\n\n cb(error);\n return;\n }\n\n if (!this._fin && !this._fragmented) this._fragmented = this._opcode;\n this._masked = (buf[1] & 0x80) === 0x80;\n\n if (this._isServer) {\n if (!this._masked) {\n const error = this.createError(\n RangeError,\n 'MASK must be set',\n true,\n 1002,\n 'WS_ERR_EXPECTED_MASK'\n );\n\n cb(error);\n return;\n }\n } else if (this._masked) {\n const error = this.createError(\n RangeError,\n 'MASK must be clear',\n true,\n 1002,\n 'WS_ERR_UNEXPECTED_MASK'\n );\n\n cb(error);\n return;\n }\n\n if (this._payloadLength === 126) this._state = GET_PAYLOAD_LENGTH_16;\n else if (this._payloadLength === 127) this._state = GET_PAYLOAD_LENGTH_64;\n else this.haveLength(cb);\n }\n\n /**\n * Gets extended payload length (7+16).\n *\n * @param {Function} cb Callback\n * @private\n */\n getPayloadLength16(cb) {\n if (this._bufferedBytes < 2) {\n this._loop = false;\n return;\n }\n\n this._payloadLength = this.consume(2).readUInt16BE(0);\n this.haveLength(cb);\n }\n\n /**\n * Gets extended payload length (7+64).\n *\n * @param {Function} cb Callback\n * @private\n */\n getPayloadLength64(cb) {\n if (this._bufferedBytes < 8) {\n this._loop = false;\n return;\n }\n\n const buf = this.consume(8);\n const num = buf.readUInt32BE(0);\n\n //\n // The maximum safe integer in JavaScript is 2^53 - 1. An error is returned\n // if payload length is greater than this number.\n //\n if (num > Math.pow(2, 53 - 32) - 1) {\n const error = this.createError(\n RangeError,\n 'Unsupported WebSocket frame: payload length > 2^53 - 1',\n false,\n 1009,\n 'WS_ERR_UNSUPPORTED_DATA_PAYLOAD_LENGTH'\n );\n\n cb(error);\n return;\n }\n\n this._payloadLength = num * Math.pow(2, 32) + buf.readUInt32BE(4);\n this.haveLength(cb);\n }\n\n /**\n * Payload length has been read.\n *\n * @param {Function} cb Callback\n * @private\n */\n haveLength(cb) {\n if (this._payloadLength && this._opcode < 0x08) {\n this._totalPayloadLength += this._payloadLength;\n if (this._totalPayloadLength > this._maxPayload && this._maxPayload > 0) {\n const error = this.createError(\n RangeError,\n 'Max payload size exceeded',\n false,\n 1009,\n 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH'\n );\n\n cb(error);\n return;\n }\n }\n\n if (this._masked) this._state = GET_MASK;\n else this._state = GET_DATA;\n }\n\n /**\n * Reads mask bytes.\n *\n * @private\n */\n getMask() {\n if (this._bufferedBytes < 4) {\n this._loop = false;\n return;\n }\n\n this._mask = this.consume(4);\n this._state = GET_DATA;\n }\n\n /**\n * Reads data bytes.\n *\n * @param {Function} cb Callback\n * @private\n */\n getData(cb) {\n let data = EMPTY_BUFFER;\n\n if (this._payloadLength) {\n if (this._bufferedBytes < this._payloadLength) {\n this._loop = false;\n return;\n }\n\n data = this.consume(this._payloadLength);\n\n if (\n this._masked &&\n (this._mask[0] | this._mask[1] | this._mask[2] | this._mask[3]) !== 0\n ) {\n unmask(data, this._mask);\n }\n }\n\n if (this._opcode > 0x07) {\n this.controlMessage(data, cb);\n return;\n }\n\n if (this._compressed) {\n this._state = INFLATING;\n this.decompress(data, cb);\n return;\n }\n\n if (data.length) {\n //\n // This message is not compressed so its length is the sum of the payload\n // length of all fragments.\n //\n this._messageLength = this._totalPayloadLength;\n this._fragments.push(data);\n }\n\n this.dataMessage(cb);\n }\n\n /**\n * Decompresses data.\n *\n * @param {Buffer} data Compressed data\n * @param {Function} cb Callback\n * @private\n */\n decompress(data, cb) {\n const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];\n\n perMessageDeflate.decompress(data, this._fin, (err, buf) => {\n if (err) return cb(err);\n\n if (buf.length) {\n this._messageLength += buf.length;\n if (this._messageLength > this._maxPayload && this._maxPayload > 0) {\n const error = this.createError(\n RangeError,\n 'Max payload size exceeded',\n false,\n 1009,\n 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH'\n );\n\n cb(error);\n return;\n }\n\n this._fragments.push(buf);\n }\n\n this.dataMessage(cb);\n if (this._state === GET_INFO) this.startLoop(cb);\n });\n }\n\n /**\n * Handles a data message.\n *\n * @param {Function} cb Callback\n * @private\n */\n dataMessage(cb) {\n if (!this._fin) {\n this._state = GET_INFO;\n return;\n }\n\n const messageLength = this._messageLength;\n const fragments = this._fragments;\n\n this._totalPayloadLength = 0;\n this._messageLength = 0;\n this._fragmented = 0;\n this._fragments = [];\n\n if (this._opcode === 2) {\n let data;\n\n if (this._binaryType === 'nodebuffer') {\n data = concat(fragments, messageLength);\n } else if (this._binaryType === 'arraybuffer') {\n data = toArrayBuffer(concat(fragments, messageLength));\n } else if (this._binaryType === 'blob') {\n data = new Blob(fragments);\n } else {\n data = fragments;\n }\n\n if (this._allowSynchronousEvents) {\n this.emit('message', data, true);\n this._state = GET_INFO;\n } else {\n this._state = DEFER_EVENT;\n setImmediate(() => {\n this.emit('message', data, true);\n this._state = GET_INFO;\n this.startLoop(cb);\n });\n }\n } else {\n const buf = concat(fragments, messageLength);\n\n if (!this._skipUTF8Validation && !isValidUTF8(buf)) {\n const error = this.createError(\n Error,\n 'invalid UTF-8 sequence',\n true,\n 1007,\n 'WS_ERR_INVALID_UTF8'\n );\n\n cb(error);\n return;\n }\n\n if (this._state === INFLATING || this._allowSynchronousEvents) {\n this.emit('message', buf, false);\n this._state = GET_INFO;\n } else {\n this._state = DEFER_EVENT;\n setImmediate(() => {\n this.emit('message', buf, false);\n this._state = GET_INFO;\n this.startLoop(cb);\n });\n }\n }\n }\n\n /**\n * Handles a control message.\n *\n * @param {Buffer} data Data to handle\n * @return {(Error|RangeError|undefined)} A possible error\n * @private\n */\n controlMessage(data, cb) {\n if (this._opcode === 0x08) {\n if (data.length === 0) {\n this._loop = false;\n this.emit('conclude', 1005, EMPTY_BUFFER);\n this.end();\n } else {\n const code = data.readUInt16BE(0);\n\n if (!isValidStatusCode(code)) {\n const error = this.createError(\n RangeError,\n `invalid status code ${code}`,\n true,\n 1002,\n 'WS_ERR_INVALID_CLOSE_CODE'\n );\n\n cb(error);\n return;\n }\n\n const buf = new FastBuffer(\n data.buffer,\n data.byteOffset + 2,\n data.length - 2\n );\n\n if (!this._skipUTF8Validation && !isValidUTF8(buf)) {\n const error = this.createError(\n Error,\n 'invalid UTF-8 sequence',\n true,\n 1007,\n 'WS_ERR_INVALID_UTF8'\n );\n\n cb(error);\n return;\n }\n\n this._loop = false;\n this.emit('conclude', code, buf);\n this.end();\n }\n\n this._state = GET_INFO;\n return;\n }\n\n if (this._allowSynchronousEvents) {\n this.emit(this._opcode === 0x09 ? 'ping' : 'pong', data);\n this._state = GET_INFO;\n } else {\n this._state = DEFER_EVENT;\n setImmediate(() => {\n this.emit(this._opcode === 0x09 ? 'ping' : 'pong', data);\n this._state = GET_INFO;\n this.startLoop(cb);\n });\n }\n }\n\n /**\n * Builds an error object.\n *\n * @param {function(new:Error|RangeError)} ErrorCtor The error constructor\n * @param {String} message The error message\n * @param {Boolean} prefix Specifies whether or not to add a default prefix to\n * `message`\n * @param {Number} statusCode The status code\n * @param {String} errorCode The exposed error code\n * @return {(Error|RangeError)} The error\n * @private\n */\n createError(ErrorCtor, message, prefix, statusCode, errorCode) {\n this._loop = false;\n this._errored = true;\n\n const err = new ErrorCtor(\n prefix ? `Invalid WebSocket frame: ${message}` : message\n );\n\n Error.captureStackTrace(err, this.createError);\n err.code = errorCode;\n err[kStatusCode] = statusCode;\n return err;\n }\n}\n\nmodule.exports = Receiver;\n","/* eslint no-unused-vars: [\"error\", { \"varsIgnorePattern\": \"^Duplex\" }] */\n\n'use strict';\n\nconst { Duplex } = require('stream');\nconst { randomFillSync } = require('crypto');\n\nconst PerMessageDeflate = require('./permessage-deflate');\nconst { EMPTY_BUFFER, kWebSocket, NOOP } = require('./constants');\nconst { isBlob, isValidStatusCode } = require('./validation');\nconst { mask: applyMask, toBuffer } = require('./buffer-util');\n\nconst kByteLength = Symbol('kByteLength');\nconst maskBuffer = Buffer.alloc(4);\nconst RANDOM_POOL_SIZE = 8 * 1024;\nlet randomPool;\nlet randomPoolPointer = RANDOM_POOL_SIZE;\n\nconst DEFAULT = 0;\nconst DEFLATING = 1;\nconst GET_BLOB_DATA = 2;\n\n/**\n * HyBi Sender implementation.\n */\nclass Sender {\n /**\n * Creates a Sender instance.\n *\n * @param {Duplex} socket The connection socket\n * @param {Object} [extensions] An object containing the negotiated extensions\n * @param {Function} [generateMask] The function used to generate the masking\n * key\n */\n constructor(socket, extensions, generateMask) {\n this._extensions = extensions || {};\n\n if (generateMask) {\n this._generateMask = generateMask;\n this._maskBuffer = Buffer.alloc(4);\n }\n\n this._socket = socket;\n\n this._firstFragment = true;\n this._compress = false;\n\n this._bufferedBytes = 0;\n this._queue = [];\n this._state = DEFAULT;\n this.onerror = NOOP;\n this[kWebSocket] = undefined;\n }\n\n /**\n * Frames a piece of data according to the HyBi WebSocket protocol.\n *\n * @param {(Buffer|String)} data The data to frame\n * @param {Object} options Options object\n * @param {Boolean} [options.fin=false] Specifies whether or not to set the\n * FIN bit\n * @param {Function} [options.generateMask] The function used to generate the\n * masking key\n * @param {Boolean} [options.mask=false] Specifies whether or not to mask\n * `data`\n * @param {Buffer} [options.maskBuffer] The buffer used to store the masking\n * key\n * @param {Number} options.opcode The opcode\n * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be\n * modified\n * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the\n * RSV1 bit\n * @return {(Buffer|String)[]} The framed data\n * @public\n */\n static frame(data, options) {\n let mask;\n let merge = false;\n let offset = 2;\n let skipMasking = false;\n\n if (options.mask) {\n mask = options.maskBuffer || maskBuffer;\n\n if (options.generateMask) {\n options.generateMask(mask);\n } else {\n if (randomPoolPointer === RANDOM_POOL_SIZE) {\n /* istanbul ignore else */\n if (randomPool === undefined) {\n //\n // This is lazily initialized because server-sent frames must not\n // be masked so it may never be used.\n //\n randomPool = Buffer.alloc(RANDOM_POOL_SIZE);\n }\n\n randomFillSync(randomPool, 0, RANDOM_POOL_SIZE);\n randomPoolPointer = 0;\n }\n\n mask[0] = randomPool[randomPoolPointer++];\n mask[1] = randomPool[randomPoolPointer++];\n mask[2] = randomPool[randomPoolPointer++];\n mask[3] = randomPool[randomPoolPointer++];\n }\n\n skipMasking = (mask[0] | mask[1] | mask[2] | mask[3]) === 0;\n offset = 6;\n }\n\n let dataLength;\n\n if (typeof data === 'string') {\n if (\n (!options.mask || skipMasking) &&\n options[kByteLength] !== undefined\n ) {\n dataLength = options[kByteLength];\n } else {\n data = Buffer.from(data);\n dataLength = data.length;\n }\n } else {\n dataLength = data.length;\n merge = options.mask && options.readOnly && !skipMasking;\n }\n\n let payloadLength = dataLength;\n\n if (dataLength >= 65536) {\n offset += 8;\n payloadLength = 127;\n } else if (dataLength > 125) {\n offset += 2;\n payloadLength = 126;\n }\n\n const target = Buffer.allocUnsafe(merge ? dataLength + offset : offset);\n\n target[0] = options.fin ? options.opcode | 0x80 : options.opcode;\n if (options.rsv1) target[0] |= 0x40;\n\n target[1] = payloadLength;\n\n if (payloadLength === 126) {\n target.writeUInt16BE(dataLength, 2);\n } else if (payloadLength === 127) {\n target[2] = target[3] = 0;\n target.writeUIntBE(dataLength, 4, 6);\n }\n\n if (!options.mask) return [target, data];\n\n target[1] |= 0x80;\n target[offset - 4] = mask[0];\n target[offset - 3] = mask[1];\n target[offset - 2] = mask[2];\n target[offset - 1] = mask[3];\n\n if (skipMasking) return [target, data];\n\n if (merge) {\n applyMask(data, mask, target, offset, dataLength);\n return [target];\n }\n\n applyMask(data, mask, data, 0, dataLength);\n return [target, data];\n }\n\n /**\n * Sends a close message to the other peer.\n *\n * @param {Number} [code] The status code component of the body\n * @param {(String|Buffer)} [data] The message component of the body\n * @param {Boolean} [mask=false] Specifies whether or not to mask the message\n * @param {Function} [cb] Callback\n * @public\n */\n close(code, data, mask, cb) {\n let buf;\n\n if (code === undefined) {\n buf = EMPTY_BUFFER;\n } else if (typeof code !== 'number' || !isValidStatusCode(code)) {\n throw new TypeError('First argument must be a valid error code number');\n } else if (data === undefined || !data.length) {\n buf = Buffer.allocUnsafe(2);\n buf.writeUInt16BE(code, 0);\n } else {\n const length = Buffer.byteLength(data);\n\n if (length > 123) {\n throw new RangeError('The message must not be greater than 123 bytes');\n }\n\n buf = Buffer.allocUnsafe(2 + length);\n buf.writeUInt16BE(code, 0);\n\n if (typeof data === 'string') {\n buf.write(data, 2);\n } else {\n buf.set(data, 2);\n }\n }\n\n const options = {\n [kByteLength]: buf.length,\n fin: true,\n generateMask: this._generateMask,\n mask,\n maskBuffer: this._maskBuffer,\n opcode: 0x08,\n readOnly: false,\n rsv1: false\n };\n\n if (this._state !== DEFAULT) {\n this.enqueue([this.dispatch, buf, false, options, cb]);\n } else {\n this.sendFrame(Sender.frame(buf, options), cb);\n }\n }\n\n /**\n * Sends a ping message to the other peer.\n *\n * @param {*} data The message to send\n * @param {Boolean} [mask=false] Specifies whether or not to mask `data`\n * @param {Function} [cb] Callback\n * @public\n */\n ping(data, mask, cb) {\n let byteLength;\n let readOnly;\n\n if (typeof data === 'string') {\n byteLength = Buffer.byteLength(data);\n readOnly = false;\n } else if (isBlob(data)) {\n byteLength = data.size;\n readOnly = false;\n } else {\n data = toBuffer(data);\n byteLength = data.length;\n readOnly = toBuffer.readOnly;\n }\n\n if (byteLength > 125) {\n throw new RangeError('The data size must not be greater than 125 bytes');\n }\n\n const options = {\n [kByteLength]: byteLength,\n fin: true,\n generateMask: this._generateMask,\n mask,\n maskBuffer: this._maskBuffer,\n opcode: 0x09,\n readOnly,\n rsv1: false\n };\n\n if (isBlob(data)) {\n if (this._state !== DEFAULT) {\n this.enqueue([this.getBlobData, data, false, options, cb]);\n } else {\n this.getBlobData(data, false, options, cb);\n }\n } else if (this._state !== DEFAULT) {\n this.enqueue([this.dispatch, data, false, options, cb]);\n } else {\n this.sendFrame(Sender.frame(data, options), cb);\n }\n }\n\n /**\n * Sends a pong message to the other peer.\n *\n * @param {*} data The message to send\n * @param {Boolean} [mask=false] Specifies whether or not to mask `data`\n * @param {Function} [cb] Callback\n * @public\n */\n pong(data, mask, cb) {\n let byteLength;\n let readOnly;\n\n if (typeof data === 'string') {\n byteLength = Buffer.byteLength(data);\n readOnly = false;\n } else if (isBlob(data)) {\n byteLength = data.size;\n readOnly = false;\n } else {\n data = toBuffer(data);\n byteLength = data.length;\n readOnly = toBuffer.readOnly;\n }\n\n if (byteLength > 125) {\n throw new RangeError('The data size must not be greater than 125 bytes');\n }\n\n const options = {\n [kByteLength]: byteLength,\n fin: true,\n generateMask: this._generateMask,\n mask,\n maskBuffer: this._maskBuffer,\n opcode: 0x0a,\n readOnly,\n rsv1: false\n };\n\n if (isBlob(data)) {\n if (this._state !== DEFAULT) {\n this.enqueue([this.getBlobData, data, false, options, cb]);\n } else {\n this.getBlobData(data, false, options, cb);\n }\n } else if (this._state !== DEFAULT) {\n this.enqueue([this.dispatch, data, false, options, cb]);\n } else {\n this.sendFrame(Sender.frame(data, options), cb);\n }\n }\n\n /**\n * Sends a data message to the other peer.\n *\n * @param {*} data The message to send\n * @param {Object} options Options object\n * @param {Boolean} [options.binary=false] Specifies whether `data` is binary\n * or text\n * @param {Boolean} [options.compress=false] Specifies whether or not to\n * compress `data`\n * @param {Boolean} [options.fin=false] Specifies whether the fragment is the\n * last one\n * @param {Boolean} [options.mask=false] Specifies whether or not to mask\n * `data`\n * @param {Function} [cb] Callback\n * @public\n */\n send(data, options, cb) {\n const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];\n let opcode = options.binary ? 2 : 1;\n let rsv1 = options.compress;\n\n let byteLength;\n let readOnly;\n\n if (typeof data === 'string') {\n byteLength = Buffer.byteLength(data);\n readOnly = false;\n } else if (isBlob(data)) {\n byteLength = data.size;\n readOnly = false;\n } else {\n data = toBuffer(data);\n byteLength = data.length;\n readOnly = toBuffer.readOnly;\n }\n\n if (this._firstFragment) {\n this._firstFragment = false;\n if (\n rsv1 &&\n perMessageDeflate &&\n perMessageDeflate.params[\n perMessageDeflate._isServer\n ? 'server_no_context_takeover'\n : 'client_no_context_takeover'\n ]\n ) {\n rsv1 = byteLength >= perMessageDeflate._threshold;\n }\n this._compress = rsv1;\n } else {\n rsv1 = false;\n opcode = 0;\n }\n\n if (options.fin) this._firstFragment = true;\n\n const opts = {\n [kByteLength]: byteLength,\n fin: options.fin,\n generateMask: this._generateMask,\n mask: options.mask,\n maskBuffer: this._maskBuffer,\n opcode,\n readOnly,\n rsv1\n };\n\n if (isBlob(data)) {\n if (this._state !== DEFAULT) {\n this.enqueue([this.getBlobData, data, this._compress, opts, cb]);\n } else {\n this.getBlobData(data, this._compress, opts, cb);\n }\n } else if (this._state !== DEFAULT) {\n this.enqueue([this.dispatch, data, this._compress, opts, cb]);\n } else {\n this.dispatch(data, this._compress, opts, cb);\n }\n }\n\n /**\n * Gets the contents of a blob as binary data.\n *\n * @param {Blob} blob The blob\n * @param {Boolean} [compress=false] Specifies whether or not to compress\n * the data\n * @param {Object} options Options object\n * @param {Boolean} [options.fin=false] Specifies whether or not to set the\n * FIN bit\n * @param {Function} [options.generateMask] The function used to generate the\n * masking key\n * @param {Boolean} [options.mask=false] Specifies whether or not to mask\n * `data`\n * @param {Buffer} [options.maskBuffer] The buffer used to store the masking\n * key\n * @param {Number} options.opcode The opcode\n * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be\n * modified\n * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the\n * RSV1 bit\n * @param {Function} [cb] Callback\n * @private\n */\n getBlobData(blob, compress, options, cb) {\n this._bufferedBytes += options[kByteLength];\n this._state = GET_BLOB_DATA;\n\n blob\n .arrayBuffer()\n .then((arrayBuffer) => {\n if (this._socket.destroyed) {\n const err = new Error(\n 'The socket was closed while the blob was being read'\n );\n\n //\n // `callCallbacks` is called in the next tick to ensure that errors\n // that might be thrown in the callbacks behave like errors thrown\n // outside the promise chain.\n //\n process.nextTick(callCallbacks, this, err, cb);\n return;\n }\n\n this._bufferedBytes -= options[kByteLength];\n const data = toBuffer(arrayBuffer);\n\n if (!compress) {\n this._state = DEFAULT;\n this.sendFrame(Sender.frame(data, options), cb);\n this.dequeue();\n } else {\n this.dispatch(data, compress, options, cb);\n }\n })\n .catch((err) => {\n //\n // `onError` is called in the next tick for the same reason that\n // `callCallbacks` above is.\n //\n process.nextTick(onError, this, err, cb);\n });\n }\n\n /**\n * Dispatches a message.\n *\n * @param {(Buffer|String)} data The message to send\n * @param {Boolean} [compress=false] Specifies whether or not to compress\n * `data`\n * @param {Object} options Options object\n * @param {Boolean} [options.fin=false] Specifies whether or not to set the\n * FIN bit\n * @param {Function} [options.generateMask] The function used to generate the\n * masking key\n * @param {Boolean} [options.mask=false] Specifies whether or not to mask\n * `data`\n * @param {Buffer} [options.maskBuffer] The buffer used to store the masking\n * key\n * @param {Number} options.opcode The opcode\n * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be\n * modified\n * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the\n * RSV1 bit\n * @param {Function} [cb] Callback\n * @private\n */\n dispatch(data, compress, options, cb) {\n if (!compress) {\n this.sendFrame(Sender.frame(data, options), cb);\n return;\n }\n\n const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];\n\n this._bufferedBytes += options[kByteLength];\n this._state = DEFLATING;\n perMessageDeflate.compress(data, options.fin, (_, buf) => {\n if (this._socket.destroyed) {\n const err = new Error(\n 'The socket was closed while data was being compressed'\n );\n\n callCallbacks(this, err, cb);\n return;\n }\n\n this._bufferedBytes -= options[kByteLength];\n this._state = DEFAULT;\n options.readOnly = false;\n this.sendFrame(Sender.frame(buf, options), cb);\n this.dequeue();\n });\n }\n\n /**\n * Executes queued send operations.\n *\n * @private\n */\n dequeue() {\n while (this._state === DEFAULT && this._queue.length) {\n const params = this._queue.shift();\n\n this._bufferedBytes -= params[3][kByteLength];\n Reflect.apply(params[0], this, params.slice(1));\n }\n }\n\n /**\n * Enqueues a send operation.\n *\n * @param {Array} params Send operation parameters.\n * @private\n */\n enqueue(params) {\n this._bufferedBytes += params[3][kByteLength];\n this._queue.push(params);\n }\n\n /**\n * Sends a frame.\n *\n * @param {(Buffer | String)[]} list The frame to send\n * @param {Function} [cb] Callback\n * @private\n */\n sendFrame(list, cb) {\n if (list.length === 2) {\n this._socket.cork();\n this._socket.write(list[0]);\n this._socket.write(list[1], cb);\n this._socket.uncork();\n } else {\n this._socket.write(list[0], cb);\n }\n }\n}\n\nmodule.exports = Sender;\n\n/**\n * Calls queued callbacks with an error.\n *\n * @param {Sender} sender The `Sender` instance\n * @param {Error} err The error to call the callbacks with\n * @param {Function} [cb] The first callback\n * @private\n */\nfunction callCallbacks(sender, err, cb) {\n if (typeof cb === 'function') cb(err);\n\n for (let i = 0; i < sender._queue.length; i++) {\n const params = sender._queue[i];\n const callback = params[params.length - 1];\n\n if (typeof callback === 'function') callback(err);\n }\n}\n\n/**\n * Handles a `Sender` error.\n *\n * @param {Sender} sender The `Sender` instance\n * @param {Error} err The error\n * @param {Function} [cb] The first pending callback\n * @private\n */\nfunction onError(sender, err, cb) {\n callCallbacks(sender, err, cb);\n sender.onerror(err);\n}\n","'use strict';\n\nconst { kForOnEventAttribute, kListener } = require('./constants');\n\nconst kCode = Symbol('kCode');\nconst kData = Symbol('kData');\nconst kError = Symbol('kError');\nconst kMessage = Symbol('kMessage');\nconst kReason = Symbol('kReason');\nconst kTarget = Symbol('kTarget');\nconst kType = Symbol('kType');\nconst kWasClean = Symbol('kWasClean');\n\n/**\n * Class representing an event.\n */\nclass Event {\n /**\n * Create a new `Event`.\n *\n * @param {String} type The name of the event\n * @throws {TypeError} If the `type` argument is not specified\n */\n constructor(type) {\n this[kTarget] = null;\n this[kType] = type;\n }\n\n /**\n * @type {*}\n */\n get target() {\n return this[kTarget];\n }\n\n /**\n * @type {String}\n */\n get type() {\n return this[kType];\n }\n}\n\nObject.defineProperty(Event.prototype, 'target', { enumerable: true });\nObject.defineProperty(Event.prototype, 'type', { enumerable: true });\n\n/**\n * Class representing a close event.\n *\n * @extends Event\n */\nclass CloseEvent extends Event {\n /**\n * Create a new `CloseEvent`.\n *\n * @param {String} type The name of the event\n * @param {Object} [options] A dictionary object that allows for setting\n * attributes via object members of the same name\n * @param {Number} [options.code=0] The status code explaining why the\n * connection was closed\n * @param {String} [options.reason=''] A human-readable string explaining why\n * the connection was closed\n * @param {Boolean} [options.wasClean=false] Indicates whether or not the\n * connection was cleanly closed\n */\n constructor(type, options = {}) {\n super(type);\n\n this[kCode] = options.code === undefined ? 0 : options.code;\n this[kReason] = options.reason === undefined ? '' : options.reason;\n this[kWasClean] = options.wasClean === undefined ? false : options.wasClean;\n }\n\n /**\n * @type {Number}\n */\n get code() {\n return this[kCode];\n }\n\n /**\n * @type {String}\n */\n get reason() {\n return this[kReason];\n }\n\n /**\n * @type {Boolean}\n */\n get wasClean() {\n return this[kWasClean];\n }\n}\n\nObject.defineProperty(CloseEvent.prototype, 'code', { enumerable: true });\nObject.defineProperty(CloseEvent.prototype, 'reason', { enumerable: true });\nObject.defineProperty(CloseEvent.prototype, 'wasClean', { enumerable: true });\n\n/**\n * Class representing an error event.\n *\n * @extends Event\n */\nclass ErrorEvent extends Event {\n /**\n * Create a new `ErrorEvent`.\n *\n * @param {String} type The name of the event\n * @param {Object} [options] A dictionary object that allows for setting\n * attributes via object members of the same name\n * @param {*} [options.error=null] The error that generated this event\n * @param {String} [options.message=''] The error message\n */\n constructor(type, options = {}) {\n super(type);\n\n this[kError] = options.error === undefined ? null : options.error;\n this[kMessage] = options.message === undefined ? '' : options.message;\n }\n\n /**\n * @type {*}\n */\n get error() {\n return this[kError];\n }\n\n /**\n * @type {String}\n */\n get message() {\n return this[kMessage];\n }\n}\n\nObject.defineProperty(ErrorEvent.prototype, 'error', { enumerable: true });\nObject.defineProperty(ErrorEvent.prototype, 'message', { enumerable: true });\n\n/**\n * Class representing a message event.\n *\n * @extends Event\n */\nclass MessageEvent extends Event {\n /**\n * Create a new `MessageEvent`.\n *\n * @param {String} type The name of the event\n * @param {Object} [options] A dictionary object that allows for setting\n * attributes via object members of the same name\n * @param {*} [options.data=null] The message content\n */\n constructor(type, options = {}) {\n super(type);\n\n this[kData] = options.data === undefined ? null : options.data;\n }\n\n /**\n * @type {*}\n */\n get data() {\n return this[kData];\n }\n}\n\nObject.defineProperty(MessageEvent.prototype, 'data', { enumerable: true });\n\n/**\n * This provides methods for emulating the `EventTarget` interface. It's not\n * meant to be used directly.\n *\n * @mixin\n */\nconst EventTarget = {\n /**\n * Register an event listener.\n *\n * @param {String} type A string representing the event type to listen for\n * @param {(Function|Object)} handler The listener to add\n * @param {Object} [options] An options object specifies characteristics about\n * the event listener\n * @param {Boolean} [options.once=false] A `Boolean` indicating that the\n * listener should be invoked at most once after being added. If `true`,\n * the listener would be automatically removed when invoked.\n * @public\n */\n addEventListener(type, handler, options = {}) {\n for (const listener of this.listeners(type)) {\n if (\n !options[kForOnEventAttribute] &&\n listener[kListener] === handler &&\n !listener[kForOnEventAttribute]\n ) {\n return;\n }\n }\n\n let wrapper;\n\n if (type === 'message') {\n wrapper = function onMessage(data, isBinary) {\n const event = new MessageEvent('message', {\n data: isBinary ? data : data.toString()\n });\n\n event[kTarget] = this;\n callListener(handler, this, event);\n };\n } else if (type === 'close') {\n wrapper = function onClose(code, message) {\n const event = new CloseEvent('close', {\n code,\n reason: message.toString(),\n wasClean: this._closeFrameReceived && this._closeFrameSent\n });\n\n event[kTarget] = this;\n callListener(handler, this, event);\n };\n } else if (type === 'error') {\n wrapper = function onError(error) {\n const event = new ErrorEvent('error', {\n error,\n message: error.message\n });\n\n event[kTarget] = this;\n callListener(handler, this, event);\n };\n } else if (type === 'open') {\n wrapper = function onOpen() {\n const event = new Event('open');\n\n event[kTarget] = this;\n callListener(handler, this, event);\n };\n } else {\n return;\n }\n\n wrapper[kForOnEventAttribute] = !!options[kForOnEventAttribute];\n wrapper[kListener] = handler;\n\n if (options.once) {\n this.once(type, wrapper);\n } else {\n this.on(type, wrapper);\n }\n },\n\n /**\n * Remove an event listener.\n *\n * @param {String} type A string representing the event type to remove\n * @param {(Function|Object)} handler The listener to remove\n * @public\n */\n removeEventListener(type, handler) {\n for (const listener of this.listeners(type)) {\n if (listener[kListener] === handler && !listener[kForOnEventAttribute]) {\n this.removeListener(type, listener);\n break;\n }\n }\n }\n};\n\nmodule.exports = {\n CloseEvent,\n ErrorEvent,\n Event,\n EventTarget,\n MessageEvent\n};\n\n/**\n * Call an event listener\n *\n * @param {(Function|Object)} listener The listener to call\n * @param {*} thisArg The value to use as `this`` when calling the listener\n * @param {Event} event The event to pass to the listener\n * @private\n */\nfunction callListener(listener, thisArg, event) {\n if (typeof listener === 'object' && listener.handleEvent) {\n listener.handleEvent.call(listener, event);\n } else {\n listener.call(thisArg, event);\n }\n}\n","'use strict';\n\nconst { tokenChars } = require('./validation');\n\n/**\n * Adds an offer to the map of extension offers or a parameter to the map of\n * parameters.\n *\n * @param {Object} dest The map of extension offers or parameters\n * @param {String} name The extension or parameter name\n * @param {(Object|Boolean|String)} elem The extension parameters or the\n * parameter value\n * @private\n */\nfunction push(dest, name, elem) {\n if (dest[name] === undefined) dest[name] = [elem];\n else dest[name].push(elem);\n}\n\n/**\n * Parses the `Sec-WebSocket-Extensions` header into an object.\n *\n * @param {String} header The field value of the header\n * @return {Object} The parsed object\n * @public\n */\nfunction parse(header) {\n const offers = Object.create(null);\n let params = Object.create(null);\n let mustUnescape = false;\n let isEscaping = false;\n let inQuotes = false;\n let extensionName;\n let paramName;\n let start = -1;\n let code = -1;\n let end = -1;\n let i = 0;\n\n for (; i < header.length; i++) {\n code = header.charCodeAt(i);\n\n if (extensionName === undefined) {\n if (end === -1 && tokenChars[code] === 1) {\n if (start === -1) start = i;\n } else if (\n i !== 0 &&\n (code === 0x20 /* ' ' */ || code === 0x09) /* '\\t' */\n ) {\n if (end === -1 && start !== -1) end = i;\n } else if (code === 0x3b /* ';' */ || code === 0x2c /* ',' */) {\n if (start === -1) {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n\n if (end === -1) end = i;\n const name = header.slice(start, end);\n if (code === 0x2c) {\n push(offers, name, params);\n params = Object.create(null);\n } else {\n extensionName = name;\n }\n\n start = end = -1;\n } else {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n } else if (paramName === undefined) {\n if (end === -1 && tokenChars[code] === 1) {\n if (start === -1) start = i;\n } else if (code === 0x20 || code === 0x09) {\n if (end === -1 && start !== -1) end = i;\n } else if (code === 0x3b || code === 0x2c) {\n if (start === -1) {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n\n if (end === -1) end = i;\n push(params, header.slice(start, end), true);\n if (code === 0x2c) {\n push(offers, extensionName, params);\n params = Object.create(null);\n extensionName = undefined;\n }\n\n start = end = -1;\n } else if (code === 0x3d /* '=' */ && start !== -1 && end === -1) {\n paramName = header.slice(start, i);\n start = end = -1;\n } else {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n } else {\n //\n // The value of a quoted-string after unescaping must conform to the\n // token ABNF, so only token characters are valid.\n // Ref: https://tools.ietf.org/html/rfc6455#section-9.1\n //\n if (isEscaping) {\n if (tokenChars[code] !== 1) {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n if (start === -1) start = i;\n else if (!mustUnescape) mustUnescape = true;\n isEscaping = false;\n } else if (inQuotes) {\n if (tokenChars[code] === 1) {\n if (start === -1) start = i;\n } else if (code === 0x22 /* '\"' */ && start !== -1) {\n inQuotes = false;\n end = i;\n } else if (code === 0x5c /* '\\' */) {\n isEscaping = true;\n } else {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n } else if (code === 0x22 && header.charCodeAt(i - 1) === 0x3d) {\n inQuotes = true;\n } else if (end === -1 && tokenChars[code] === 1) {\n if (start === -1) start = i;\n } else if (start !== -1 && (code === 0x20 || code === 0x09)) {\n if (end === -1) end = i;\n } else if (code === 0x3b || code === 0x2c) {\n if (start === -1) {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n\n if (end === -1) end = i;\n let value = header.slice(start, end);\n if (mustUnescape) {\n value = value.replace(/\\\\/g, '');\n mustUnescape = false;\n }\n push(params, paramName, value);\n if (code === 0x2c) {\n push(offers, extensionName, params);\n params = Object.create(null);\n extensionName = undefined;\n }\n\n paramName = undefined;\n start = end = -1;\n } else {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n }\n }\n\n if (start === -1 || inQuotes || code === 0x20 || code === 0x09) {\n throw new SyntaxError('Unexpected end of input');\n }\n\n if (end === -1) end = i;\n const token = header.slice(start, end);\n if (extensionName === undefined) {\n push(offers, token, params);\n } else {\n if (paramName === undefined) {\n push(params, token, true);\n } else if (mustUnescape) {\n push(params, paramName, token.replace(/\\\\/g, ''));\n } else {\n push(params, paramName, token);\n }\n push(offers, extensionName, params);\n }\n\n return offers;\n}\n\n/**\n * Builds the `Sec-WebSocket-Extensions` header field value.\n *\n * @param {Object} extensions The map of extensions and parameters to format\n * @return {String} A string representing the given object\n * @public\n */\nfunction format(extensions) {\n return Object.keys(extensions)\n .map((extension) => {\n let configurations = extensions[extension];\n if (!Array.isArray(configurations)) configurations = [configurations];\n return configurations\n .map((params) => {\n return [extension]\n .concat(\n Object.keys(params).map((k) => {\n let values = params[k];\n if (!Array.isArray(values)) values = [values];\n return values\n .map((v) => (v === true ? k : `${k}=${v}`))\n .join('; ');\n })\n )\n .join('; ');\n })\n .join(', ');\n })\n .join(', ');\n}\n\nmodule.exports = { format, parse };\n","/* eslint no-unused-vars: [\"error\", { \"varsIgnorePattern\": \"^Duplex|Readable$\", \"caughtErrors\": \"none\" }] */\n\n'use strict';\n\nconst EventEmitter = require('events');\nconst https = require('https');\nconst http = require('http');\nconst net = require('net');\nconst tls = require('tls');\nconst { randomBytes, createHash } = require('crypto');\nconst { Duplex, Readable } = require('stream');\nconst { URL } = require('url');\n\nconst PerMessageDeflate = require('./permessage-deflate');\nconst Receiver = require('./receiver');\nconst Sender = require('./sender');\nconst { isBlob } = require('./validation');\n\nconst {\n BINARY_TYPES,\n CLOSE_TIMEOUT,\n EMPTY_BUFFER,\n GUID,\n kForOnEventAttribute,\n kListener,\n kStatusCode,\n kWebSocket,\n NOOP\n} = require('./constants');\nconst {\n EventTarget: { addEventListener, removeEventListener }\n} = require('./event-target');\nconst { format, parse } = require('./extension');\nconst { toBuffer } = require('./buffer-util');\n\nconst kAborted = Symbol('kAborted');\nconst protocolVersions = [8, 13];\nconst readyStates = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED'];\nconst subprotocolRegex = /^[!#$%&'*+\\-.0-9A-Z^_`|a-z~]+$/;\n\n/**\n * Class representing a WebSocket.\n *\n * @extends EventEmitter\n */\nclass WebSocket extends EventEmitter {\n /**\n * Create a new `WebSocket`.\n *\n * @param {(String|URL)} address The URL to which to connect\n * @param {(String|String[])} [protocols] The subprotocols\n * @param {Object} [options] Connection options\n */\n constructor(address, protocols, options) {\n super();\n\n this._binaryType = BINARY_TYPES[0];\n this._closeCode = 1006;\n this._closeFrameReceived = false;\n this._closeFrameSent = false;\n this._closeMessage = EMPTY_BUFFER;\n this._closeTimer = null;\n this._errorEmitted = false;\n this._extensions = {};\n this._paused = false;\n this._protocol = '';\n this._readyState = WebSocket.CONNECTING;\n this._receiver = null;\n this._sender = null;\n this._socket = null;\n\n if (address !== null) {\n this._bufferedAmount = 0;\n this._isServer = false;\n this._redirects = 0;\n\n if (protocols === undefined) {\n protocols = [];\n } else if (!Array.isArray(protocols)) {\n if (typeof protocols === 'object' && protocols !== null) {\n options = protocols;\n protocols = [];\n } else {\n protocols = [protocols];\n }\n }\n\n initAsClient(this, address, protocols, options);\n } else {\n this._autoPong = options.autoPong;\n this._closeTimeout = options.closeTimeout;\n this._isServer = true;\n }\n }\n\n /**\n * For historical reasons, the custom \"nodebuffer\" type is used by the default\n * instead of \"blob\".\n *\n * @type {String}\n */\n get binaryType() {\n return this._binaryType;\n }\n\n set binaryType(type) {\n if (!BINARY_TYPES.includes(type)) return;\n\n this._binaryType = type;\n\n //\n // Allow to change `binaryType` on the fly.\n //\n if (this._receiver) this._receiver._binaryType = type;\n }\n\n /**\n * @type {Number}\n */\n get bufferedAmount() {\n if (!this._socket) return this._bufferedAmount;\n\n return this._socket._writableState.length + this._sender._bufferedBytes;\n }\n\n /**\n * @type {String}\n */\n get extensions() {\n return Object.keys(this._extensions).join();\n }\n\n /**\n * @type {Boolean}\n */\n get isPaused() {\n return this._paused;\n }\n\n /**\n * @type {Function}\n */\n /* istanbul ignore next */\n get onclose() {\n return null;\n }\n\n /**\n * @type {Function}\n */\n /* istanbul ignore next */\n get onerror() {\n return null;\n }\n\n /**\n * @type {Function}\n */\n /* istanbul ignore next */\n get onopen() {\n return null;\n }\n\n /**\n * @type {Function}\n */\n /* istanbul ignore next */\n get onmessage() {\n return null;\n }\n\n /**\n * @type {String}\n */\n get protocol() {\n return this._protocol;\n }\n\n /**\n * @type {Number}\n */\n get readyState() {\n return this._readyState;\n }\n\n /**\n * @type {String}\n */\n get url() {\n return this._url;\n }\n\n /**\n * Set up the socket and the internal resources.\n *\n * @param {Duplex} socket The network socket between the server and client\n * @param {Buffer} head The first packet of the upgraded stream\n * @param {Object} options Options object\n * @param {Boolean} [options.allowSynchronousEvents=false] Specifies whether\n * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted\n * multiple times in the same tick\n * @param {Function} [options.generateMask] The function used to generate the\n * masking key\n * @param {Number} [options.maxPayload=0] The maximum allowed message size\n * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or\n * not to skip UTF-8 validation for text and close messages\n * @private\n */\n setSocket(socket, head, options) {\n const receiver = new Receiver({\n allowSynchronousEvents: options.allowSynchronousEvents,\n binaryType: this.binaryType,\n extensions: this._extensions,\n isServer: this._isServer,\n maxPayload: options.maxPayload,\n skipUTF8Validation: options.skipUTF8Validation\n });\n\n const sender = new Sender(socket, this._extensions, options.generateMask);\n\n this._receiver = receiver;\n this._sender = sender;\n this._socket = socket;\n\n receiver[kWebSocket] = this;\n sender[kWebSocket] = this;\n socket[kWebSocket] = this;\n\n receiver.on('conclude', receiverOnConclude);\n receiver.on('drain', receiverOnDrain);\n receiver.on('error', receiverOnError);\n receiver.on('message', receiverOnMessage);\n receiver.on('ping', receiverOnPing);\n receiver.on('pong', receiverOnPong);\n\n sender.onerror = senderOnError;\n\n //\n // These methods may not be available if `socket` is just a `Duplex`.\n //\n if (socket.setTimeout) socket.setTimeout(0);\n if (socket.setNoDelay) socket.setNoDelay();\n\n if (head.length > 0) socket.unshift(head);\n\n socket.on('close', socketOnClose);\n socket.on('data', socketOnData);\n socket.on('end', socketOnEnd);\n socket.on('error', socketOnError);\n\n this._readyState = WebSocket.OPEN;\n this.emit('open');\n }\n\n /**\n * Emit the `'close'` event.\n *\n * @private\n */\n emitClose() {\n if (!this._socket) {\n this._readyState = WebSocket.CLOSED;\n this.emit('close', this._closeCode, this._closeMessage);\n return;\n }\n\n if (this._extensions[PerMessageDeflate.extensionName]) {\n this._extensions[PerMessageDeflate.extensionName].cleanup();\n }\n\n this._receiver.removeAllListeners();\n this._readyState = WebSocket.CLOSED;\n this.emit('close', this._closeCode, this._closeMessage);\n }\n\n /**\n * Start a closing handshake.\n *\n * +----------+ +-----------+ +----------+\n * - - -|ws.close()|-->|close frame|-->|ws.close()|- - -\n * | +----------+ +-----------+ +----------+ |\n * +----------+ +-----------+ |\n * CLOSING |ws.close()|<--|close frame|<--+-----+ CLOSING\n * +----------+ +-----------+ |\n * | | | +---+ |\n * +------------------------+-->|fin| - - - -\n * | +---+ | +---+\n * - - - - -|fin|<---------------------+\n * +---+\n *\n * @param {Number} [code] Status code explaining why the connection is closing\n * @param {(String|Buffer)} [data] The reason why the connection is\n * closing\n * @public\n */\n close(code, data) {\n if (this.readyState === WebSocket.CLOSED) return;\n if (this.readyState === WebSocket.CONNECTING) {\n const msg = 'WebSocket was closed before the connection was established';\n abortHandshake(this, this._req, msg);\n return;\n }\n\n if (this.readyState === WebSocket.CLOSING) {\n if (\n this._closeFrameSent &&\n (this._closeFrameReceived || this._receiver._writableState.errorEmitted)\n ) {\n this._socket.end();\n }\n\n return;\n }\n\n this._readyState = WebSocket.CLOSING;\n this._sender.close(code, data, !this._isServer, (err) => {\n //\n // This error is handled by the `'error'` listener on the socket. We only\n // want to know if the close frame has been sent here.\n //\n if (err) return;\n\n this._closeFrameSent = true;\n\n if (\n this._closeFrameReceived ||\n this._receiver._writableState.errorEmitted\n ) {\n this._socket.end();\n }\n });\n\n setCloseTimer(this);\n }\n\n /**\n * Pause the socket.\n *\n * @public\n */\n pause() {\n if (\n this.readyState === WebSocket.CONNECTING ||\n this.readyState === WebSocket.CLOSED\n ) {\n return;\n }\n\n this._paused = true;\n this._socket.pause();\n }\n\n /**\n * Send a ping.\n *\n * @param {*} [data] The data to send\n * @param {Boolean} [mask] Indicates whether or not to mask `data`\n * @param {Function} [cb] Callback which is executed when the ping is sent\n * @public\n */\n ping(data, mask, cb) {\n if (this.readyState === WebSocket.CONNECTING) {\n throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');\n }\n\n if (typeof data === 'function') {\n cb = data;\n data = mask = undefined;\n } else if (typeof mask === 'function') {\n cb = mask;\n mask = undefined;\n }\n\n if (typeof data === 'number') data = data.toString();\n\n if (this.readyState !== WebSocket.OPEN) {\n sendAfterClose(this, data, cb);\n return;\n }\n\n if (mask === undefined) mask = !this._isServer;\n this._sender.ping(data || EMPTY_BUFFER, mask, cb);\n }\n\n /**\n * Send a pong.\n *\n * @param {*} [data] The data to send\n * @param {Boolean} [mask] Indicates whether or not to mask `data`\n * @param {Function} [cb] Callback which is executed when the pong is sent\n * @public\n */\n pong(data, mask, cb) {\n if (this.readyState === WebSocket.CONNECTING) {\n throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');\n }\n\n if (typeof data === 'function') {\n cb = data;\n data = mask = undefined;\n } else if (typeof mask === 'function') {\n cb = mask;\n mask = undefined;\n }\n\n if (typeof data === 'number') data = data.toString();\n\n if (this.readyState !== WebSocket.OPEN) {\n sendAfterClose(this, data, cb);\n return;\n }\n\n if (mask === undefined) mask = !this._isServer;\n this._sender.pong(data || EMPTY_BUFFER, mask, cb);\n }\n\n /**\n * Resume the socket.\n *\n * @public\n */\n resume() {\n if (\n this.readyState === WebSocket.CONNECTING ||\n this.readyState === WebSocket.CLOSED\n ) {\n return;\n }\n\n this._paused = false;\n if (!this._receiver._writableState.needDrain) this._socket.resume();\n }\n\n /**\n * Send a data message.\n *\n * @param {*} data The message to send\n * @param {Object} [options] Options object\n * @param {Boolean} [options.binary] Specifies whether `data` is binary or\n * text\n * @param {Boolean} [options.compress] Specifies whether or not to compress\n * `data`\n * @param {Boolean} [options.fin=true] Specifies whether the fragment is the\n * last one\n * @param {Boolean} [options.mask] Specifies whether or not to mask `data`\n * @param {Function} [cb] Callback which is executed when data is written out\n * @public\n */\n send(data, options, cb) {\n if (this.readyState === WebSocket.CONNECTING) {\n throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');\n }\n\n if (typeof options === 'function') {\n cb = options;\n options = {};\n }\n\n if (typeof data === 'number') data = data.toString();\n\n if (this.readyState !== WebSocket.OPEN) {\n sendAfterClose(this, data, cb);\n return;\n }\n\n const opts = {\n binary: typeof data !== 'string',\n mask: !this._isServer,\n compress: true,\n fin: true,\n ...options\n };\n\n if (!this._extensions[PerMessageDeflate.extensionName]) {\n opts.compress = false;\n }\n\n this._sender.send(data || EMPTY_BUFFER, opts, cb);\n }\n\n /**\n * Forcibly close the connection.\n *\n * @public\n */\n terminate() {\n if (this.readyState === WebSocket.CLOSED) return;\n if (this.readyState === WebSocket.CONNECTING) {\n const msg = 'WebSocket was closed before the connection was established';\n abortHandshake(this, this._req, msg);\n return;\n }\n\n if (this._socket) {\n this._readyState = WebSocket.CLOSING;\n this._socket.destroy();\n }\n }\n}\n\n/**\n * @constant {Number} CONNECTING\n * @memberof WebSocket\n */\nObject.defineProperty(WebSocket, 'CONNECTING', {\n enumerable: true,\n value: readyStates.indexOf('CONNECTING')\n});\n\n/**\n * @constant {Number} CONNECTING\n * @memberof WebSocket.prototype\n */\nObject.defineProperty(WebSocket.prototype, 'CONNECTING', {\n enumerable: true,\n value: readyStates.indexOf('CONNECTING')\n});\n\n/**\n * @constant {Number} OPEN\n * @memberof WebSocket\n */\nObject.defineProperty(WebSocket, 'OPEN', {\n enumerable: true,\n value: readyStates.indexOf('OPEN')\n});\n\n/**\n * @constant {Number} OPEN\n * @memberof WebSocket.prototype\n */\nObject.defineProperty(WebSocket.prototype, 'OPEN', {\n enumerable: true,\n value: readyStates.indexOf('OPEN')\n});\n\n/**\n * @constant {Number} CLOSING\n * @memberof WebSocket\n */\nObject.defineProperty(WebSocket, 'CLOSING', {\n enumerable: true,\n value: readyStates.indexOf('CLOSING')\n});\n\n/**\n * @constant {Number} CLOSING\n * @memberof WebSocket.prototype\n */\nObject.defineProperty(WebSocket.prototype, 'CLOSING', {\n enumerable: true,\n value: readyStates.indexOf('CLOSING')\n});\n\n/**\n * @constant {Number} CLOSED\n * @memberof WebSocket\n */\nObject.defineProperty(WebSocket, 'CLOSED', {\n enumerable: true,\n value: readyStates.indexOf('CLOSED')\n});\n\n/**\n * @constant {Number} CLOSED\n * @memberof WebSocket.prototype\n */\nObject.defineProperty(WebSocket.prototype, 'CLOSED', {\n enumerable: true,\n value: readyStates.indexOf('CLOSED')\n});\n\n[\n 'binaryType',\n 'bufferedAmount',\n 'extensions',\n 'isPaused',\n 'protocol',\n 'readyState',\n 'url'\n].forEach((property) => {\n Object.defineProperty(WebSocket.prototype, property, { enumerable: true });\n});\n\n//\n// Add the `onopen`, `onerror`, `onclose`, and `onmessage` attributes.\n// See https://html.spec.whatwg.org/multipage/comms.html#the-websocket-interface\n//\n['open', 'error', 'close', 'message'].forEach((method) => {\n Object.defineProperty(WebSocket.prototype, `on${method}`, {\n enumerable: true,\n get() {\n for (const listener of this.listeners(method)) {\n if (listener[kForOnEventAttribute]) return listener[kListener];\n }\n\n return null;\n },\n set(handler) {\n for (const listener of this.listeners(method)) {\n if (listener[kForOnEventAttribute]) {\n this.removeListener(method, listener);\n break;\n }\n }\n\n if (typeof handler !== 'function') return;\n\n this.addEventListener(method, handler, {\n [kForOnEventAttribute]: true\n });\n }\n });\n});\n\nWebSocket.prototype.addEventListener = addEventListener;\nWebSocket.prototype.removeEventListener = removeEventListener;\n\nmodule.exports = WebSocket;\n\n/**\n * Initialize a WebSocket client.\n *\n * @param {WebSocket} websocket The client to initialize\n * @param {(String|URL)} address The URL to which to connect\n * @param {Array} protocols The subprotocols\n * @param {Object} [options] Connection options\n * @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether any\n * of the `'message'`, `'ping'`, and `'pong'` events can be emitted multiple\n * times in the same tick\n * @param {Boolean} [options.autoPong=true] Specifies whether or not to\n * automatically send a pong in response to a ping\n * @param {Number} [options.closeTimeout=30000] Duration in milliseconds to wait\n * for the closing handshake to finish after `websocket.close()` is called\n * @param {Function} [options.finishRequest] A function which can be used to\n * customize the headers of each http request before it is sent\n * @param {Boolean} [options.followRedirects=false] Whether or not to follow\n * redirects\n * @param {Function} [options.generateMask] The function used to generate the\n * masking key\n * @param {Number} [options.handshakeTimeout] Timeout in milliseconds for the\n * handshake request\n * @param {Number} [options.maxPayload=104857600] The maximum allowed message\n * size\n * @param {Number} [options.maxRedirects=10] The maximum number of redirects\n * allowed\n * @param {String} [options.origin] Value of the `Origin` or\n * `Sec-WebSocket-Origin` header\n * @param {(Boolean|Object)} [options.perMessageDeflate=true] Enable/disable\n * permessage-deflate\n * @param {Number} [options.protocolVersion=13] Value of the\n * `Sec-WebSocket-Version` header\n * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or\n * not to skip UTF-8 validation for text and close messages\n * @private\n */\nfunction initAsClient(websocket, address, protocols, options) {\n const opts = {\n allowSynchronousEvents: true,\n autoPong: true,\n closeTimeout: CLOSE_TIMEOUT,\n protocolVersion: protocolVersions[1],\n maxPayload: 100 * 1024 * 1024,\n skipUTF8Validation: false,\n perMessageDeflate: true,\n followRedirects: false,\n maxRedirects: 10,\n ...options,\n socketPath: undefined,\n hostname: undefined,\n protocol: undefined,\n timeout: undefined,\n method: 'GET',\n host: undefined,\n path: undefined,\n port: undefined\n };\n\n websocket._autoPong = opts.autoPong;\n websocket._closeTimeout = opts.closeTimeout;\n\n if (!protocolVersions.includes(opts.protocolVersion)) {\n throw new RangeError(\n `Unsupported protocol version: ${opts.protocolVersion} ` +\n `(supported versions: ${protocolVersions.join(', ')})`\n );\n }\n\n let parsedUrl;\n\n if (address instanceof URL) {\n parsedUrl = address;\n } else {\n try {\n parsedUrl = new URL(address);\n } catch (e) {\n throw new SyntaxError(`Invalid URL: ${address}`);\n }\n }\n\n if (parsedUrl.protocol === 'http:') {\n parsedUrl.protocol = 'ws:';\n } else if (parsedUrl.protocol === 'https:') {\n parsedUrl.protocol = 'wss:';\n }\n\n websocket._url = parsedUrl.href;\n\n const isSecure = parsedUrl.protocol === 'wss:';\n const isIpcUrl = parsedUrl.protocol === 'ws+unix:';\n let invalidUrlMessage;\n\n if (parsedUrl.protocol !== 'ws:' && !isSecure && !isIpcUrl) {\n invalidUrlMessage =\n 'The URL\\'s protocol must be one of \"ws:\", \"wss:\", ' +\n '\"http:\", \"https:\", or \"ws+unix:\"';\n } else if (isIpcUrl && !parsedUrl.pathname) {\n invalidUrlMessage = \"The URL's pathname is empty\";\n } else if (parsedUrl.hash) {\n invalidUrlMessage = 'The URL contains a fragment identifier';\n }\n\n if (invalidUrlMessage) {\n const err = new SyntaxError(invalidUrlMessage);\n\n if (websocket._redirects === 0) {\n throw err;\n } else {\n emitErrorAndClose(websocket, err);\n return;\n }\n }\n\n const defaultPort = isSecure ? 443 : 80;\n const key = randomBytes(16).toString('base64');\n const request = isSecure ? https.request : http.request;\n const protocolSet = new Set();\n let perMessageDeflate;\n\n opts.createConnection =\n opts.createConnection || (isSecure ? tlsConnect : netConnect);\n opts.defaultPort = opts.defaultPort || defaultPort;\n opts.port = parsedUrl.port || defaultPort;\n opts.host = parsedUrl.hostname.startsWith('[')\n ? parsedUrl.hostname.slice(1, -1)\n : parsedUrl.hostname;\n opts.headers = {\n ...opts.headers,\n 'Sec-WebSocket-Version': opts.protocolVersion,\n 'Sec-WebSocket-Key': key,\n Connection: 'Upgrade',\n Upgrade: 'websocket'\n };\n opts.path = parsedUrl.pathname + parsedUrl.search;\n opts.timeout = opts.handshakeTimeout;\n\n if (opts.perMessageDeflate) {\n perMessageDeflate = new PerMessageDeflate(\n opts.perMessageDeflate !== true ? opts.perMessageDeflate : {},\n false,\n opts.maxPayload\n );\n opts.headers['Sec-WebSocket-Extensions'] = format({\n [PerMessageDeflate.extensionName]: perMessageDeflate.offer()\n });\n }\n if (protocols.length) {\n for (const protocol of protocols) {\n if (\n typeof protocol !== 'string' ||\n !subprotocolRegex.test(protocol) ||\n protocolSet.has(protocol)\n ) {\n throw new SyntaxError(\n 'An invalid or duplicated subprotocol was specified'\n );\n }\n\n protocolSet.add(protocol);\n }\n\n opts.headers['Sec-WebSocket-Protocol'] = protocols.join(',');\n }\n if (opts.origin) {\n if (opts.protocolVersion < 13) {\n opts.headers['Sec-WebSocket-Origin'] = opts.origin;\n } else {\n opts.headers.Origin = opts.origin;\n }\n }\n if (parsedUrl.username || parsedUrl.password) {\n opts.auth = `${parsedUrl.username}:${parsedUrl.password}`;\n }\n\n if (isIpcUrl) {\n const parts = opts.path.split(':');\n\n opts.socketPath = parts[0];\n opts.path = parts[1];\n }\n\n let req;\n\n if (opts.followRedirects) {\n if (websocket._redirects === 0) {\n websocket._originalIpc = isIpcUrl;\n websocket._originalSecure = isSecure;\n websocket._originalHostOrSocketPath = isIpcUrl\n ? opts.socketPath\n : parsedUrl.host;\n\n const headers = options && options.headers;\n\n //\n // Shallow copy the user provided options so that headers can be changed\n // without mutating the original object.\n //\n options = { ...options, headers: {} };\n\n if (headers) {\n for (const [key, value] of Object.entries(headers)) {\n options.headers[key.toLowerCase()] = value;\n }\n }\n } else if (websocket.listenerCount('redirect') === 0) {\n const isSameHost = isIpcUrl\n ? websocket._originalIpc\n ? opts.socketPath === websocket._originalHostOrSocketPath\n : false\n : websocket._originalIpc\n ? false\n : parsedUrl.host === websocket._originalHostOrSocketPath;\n\n if (!isSameHost || (websocket._originalSecure && !isSecure)) {\n //\n // Match curl 7.77.0 behavior and drop the following headers. These\n // headers are also dropped when following a redirect to a subdomain.\n //\n delete opts.headers.authorization;\n delete opts.headers.cookie;\n\n if (!isSameHost) delete opts.headers.host;\n\n opts.auth = undefined;\n }\n }\n\n //\n // Match curl 7.77.0 behavior and make the first `Authorization` header win.\n // If the `Authorization` header is set, then there is nothing to do as it\n // will take precedence.\n //\n if (opts.auth && !options.headers.authorization) {\n options.headers.authorization =\n 'Basic ' + Buffer.from(opts.auth).toString('base64');\n }\n\n req = websocket._req = request(opts);\n\n if (websocket._redirects) {\n //\n // Unlike what is done for the `'upgrade'` event, no early exit is\n // triggered here if the user calls `websocket.close()` or\n // `websocket.terminate()` from a listener of the `'redirect'` event. This\n // is because the user can also call `request.destroy()` with an error\n // before calling `websocket.close()` or `websocket.terminate()` and this\n // would result in an error being emitted on the `request` object with no\n // `'error'` event listeners attached.\n //\n websocket.emit('redirect', websocket.url, req);\n }\n } else {\n req = websocket._req = request(opts);\n }\n\n if (opts.timeout) {\n req.on('timeout', () => {\n abortHandshake(websocket, req, 'Opening handshake has timed out');\n });\n }\n\n req.on('error', (err) => {\n if (req === null || req[kAborted]) return;\n\n req = websocket._req = null;\n emitErrorAndClose(websocket, err);\n });\n\n req.on('response', (res) => {\n const location = res.headers.location;\n const statusCode = res.statusCode;\n\n if (\n location &&\n opts.followRedirects &&\n statusCode >= 300 &&\n statusCode < 400\n ) {\n if (++websocket._redirects > opts.maxRedirects) {\n abortHandshake(websocket, req, 'Maximum redirects exceeded');\n return;\n }\n\n req.abort();\n\n let addr;\n\n try {\n addr = new URL(location, address);\n } catch (e) {\n const err = new SyntaxError(`Invalid URL: ${location}`);\n emitErrorAndClose(websocket, err);\n return;\n }\n\n initAsClient(websocket, addr, protocols, options);\n } else if (!websocket.emit('unexpected-response', req, res)) {\n abortHandshake(\n websocket,\n req,\n `Unexpected server response: ${res.statusCode}`\n );\n }\n });\n\n req.on('upgrade', (res, socket, head) => {\n websocket.emit('upgrade', res);\n\n //\n // The user may have closed the connection from a listener of the\n // `'upgrade'` event.\n //\n if (websocket.readyState !== WebSocket.CONNECTING) return;\n\n req = websocket._req = null;\n\n const upgrade = res.headers.upgrade;\n\n if (upgrade === undefined || upgrade.toLowerCase() !== 'websocket') {\n abortHandshake(websocket, socket, 'Invalid Upgrade header');\n return;\n }\n\n const digest = createHash('sha1')\n .update(key + GUID)\n .digest('base64');\n\n if (res.headers['sec-websocket-accept'] !== digest) {\n abortHandshake(websocket, socket, 'Invalid Sec-WebSocket-Accept header');\n return;\n }\n\n const serverProt = res.headers['sec-websocket-protocol'];\n let protError;\n\n if (serverProt !== undefined) {\n if (!protocolSet.size) {\n protError = 'Server sent a subprotocol but none was requested';\n } else if (!protocolSet.has(serverProt)) {\n protError = 'Server sent an invalid subprotocol';\n }\n } else if (protocolSet.size) {\n protError = 'Server sent no subprotocol';\n }\n\n if (protError) {\n abortHandshake(websocket, socket, protError);\n return;\n }\n\n if (serverProt) websocket._protocol = serverProt;\n\n const secWebSocketExtensions = res.headers['sec-websocket-extensions'];\n\n if (secWebSocketExtensions !== undefined) {\n if (!perMessageDeflate) {\n const message =\n 'Server sent a Sec-WebSocket-Extensions header but no extension ' +\n 'was requested';\n abortHandshake(websocket, socket, message);\n return;\n }\n\n let extensions;\n\n try {\n extensions = parse(secWebSocketExtensions);\n } catch (err) {\n const message = 'Invalid Sec-WebSocket-Extensions header';\n abortHandshake(websocket, socket, message);\n return;\n }\n\n const extensionNames = Object.keys(extensions);\n\n if (\n extensionNames.length !== 1 ||\n extensionNames[0] !== PerMessageDeflate.extensionName\n ) {\n const message = 'Server indicated an extension that was not requested';\n abortHandshake(websocket, socket, message);\n return;\n }\n\n try {\n perMessageDeflate.accept(extensions[PerMessageDeflate.extensionName]);\n } catch (err) {\n const message = 'Invalid Sec-WebSocket-Extensions header';\n abortHandshake(websocket, socket, message);\n return;\n }\n\n websocket._extensions[PerMessageDeflate.extensionName] =\n perMessageDeflate;\n }\n\n websocket.setSocket(socket, head, {\n allowSynchronousEvents: opts.allowSynchronousEvents,\n generateMask: opts.generateMask,\n maxPayload: opts.maxPayload,\n skipUTF8Validation: opts.skipUTF8Validation\n });\n });\n\n if (opts.finishRequest) {\n opts.finishRequest(req, websocket);\n } else {\n req.end();\n }\n}\n\n/**\n * Emit the `'error'` and `'close'` events.\n *\n * @param {WebSocket} websocket The WebSocket instance\n * @param {Error} The error to emit\n * @private\n */\nfunction emitErrorAndClose(websocket, err) {\n websocket._readyState = WebSocket.CLOSING;\n //\n // The following assignment is practically useless and is done only for\n // consistency.\n //\n websocket._errorEmitted = true;\n websocket.emit('error', err);\n websocket.emitClose();\n}\n\n/**\n * Create a `net.Socket` and initiate a connection.\n *\n * @param {Object} options Connection options\n * @return {net.Socket} The newly created socket used to start the connection\n * @private\n */\nfunction netConnect(options) {\n options.path = options.socketPath;\n return net.connect(options);\n}\n\n/**\n * Create a `tls.TLSSocket` and initiate a connection.\n *\n * @param {Object} options Connection options\n * @return {tls.TLSSocket} The newly created socket used to start the connection\n * @private\n */\nfunction tlsConnect(options) {\n options.path = undefined;\n\n if (!options.servername && options.servername !== '') {\n options.servername = net.isIP(options.host) ? '' : options.host;\n }\n\n return tls.connect(options);\n}\n\n/**\n * Abort the handshake and emit an error.\n *\n * @param {WebSocket} websocket The WebSocket instance\n * @param {(http.ClientRequest|net.Socket|tls.Socket)} stream The request to\n * abort or the socket to destroy\n * @param {String} message The error message\n * @private\n */\nfunction abortHandshake(websocket, stream, message) {\n websocket._readyState = WebSocket.CLOSING;\n\n const err = new Error(message);\n Error.captureStackTrace(err, abortHandshake);\n\n if (stream.setHeader) {\n stream[kAborted] = true;\n stream.abort();\n\n if (stream.socket && !stream.socket.destroyed) {\n //\n // On Node.js >= 14.3.0 `request.abort()` does not destroy the socket if\n // called after the request completed. See\n // https://github.com/websockets/ws/issues/1869.\n //\n stream.socket.destroy();\n }\n\n process.nextTick(emitErrorAndClose, websocket, err);\n } else {\n stream.destroy(err);\n stream.once('error', websocket.emit.bind(websocket, 'error'));\n stream.once('close', websocket.emitClose.bind(websocket));\n }\n}\n\n/**\n * Handle cases where the `ping()`, `pong()`, or `send()` methods are called\n * when the `readyState` attribute is `CLOSING` or `CLOSED`.\n *\n * @param {WebSocket} websocket The WebSocket instance\n * @param {*} [data] The data to send\n * @param {Function} [cb] Callback\n * @private\n */\nfunction sendAfterClose(websocket, data, cb) {\n if (data) {\n const length = isBlob(data) ? data.size : toBuffer(data).length;\n\n //\n // The `_bufferedAmount` property is used only when the peer is a client and\n // the opening handshake fails. Under these circumstances, in fact, the\n // `setSocket()` method is not called, so the `_socket` and `_sender`\n // properties are set to `null`.\n //\n if (websocket._socket) websocket._sender._bufferedBytes += length;\n else websocket._bufferedAmount += length;\n }\n\n if (cb) {\n const err = new Error(\n `WebSocket is not open: readyState ${websocket.readyState} ` +\n `(${readyStates[websocket.readyState]})`\n );\n process.nextTick(cb, err);\n }\n}\n\n/**\n * The listener of the `Receiver` `'conclude'` event.\n *\n * @param {Number} code The status code\n * @param {Buffer} reason The reason for closing\n * @private\n */\nfunction receiverOnConclude(code, reason) {\n const websocket = this[kWebSocket];\n\n websocket._closeFrameReceived = true;\n websocket._closeMessage = reason;\n websocket._closeCode = code;\n\n if (websocket._socket[kWebSocket] === undefined) return;\n\n websocket._socket.removeListener('data', socketOnData);\n process.nextTick(resume, websocket._socket);\n\n if (code === 1005) websocket.close();\n else websocket.close(code, reason);\n}\n\n/**\n * The listener of the `Receiver` `'drain'` event.\n *\n * @private\n */\nfunction receiverOnDrain() {\n const websocket = this[kWebSocket];\n\n if (!websocket.isPaused) websocket._socket.resume();\n}\n\n/**\n * The listener of the `Receiver` `'error'` event.\n *\n * @param {(RangeError|Error)} err The emitted error\n * @private\n */\nfunction receiverOnError(err) {\n const websocket = this[kWebSocket];\n\n if (websocket._socket[kWebSocket] !== undefined) {\n websocket._socket.removeListener('data', socketOnData);\n\n //\n // On Node.js < 14.0.0 the `'error'` event is emitted synchronously. See\n // https://github.com/websockets/ws/issues/1940.\n //\n process.nextTick(resume, websocket._socket);\n\n websocket.close(err[kStatusCode]);\n }\n\n if (!websocket._errorEmitted) {\n websocket._errorEmitted = true;\n websocket.emit('error', err);\n }\n}\n\n/**\n * The listener of the `Receiver` `'finish'` event.\n *\n * @private\n */\nfunction receiverOnFinish() {\n this[kWebSocket].emitClose();\n}\n\n/**\n * The listener of the `Receiver` `'message'` event.\n *\n * @param {Buffer|ArrayBuffer|Buffer[])} data The message\n * @param {Boolean} isBinary Specifies whether the message is binary or not\n * @private\n */\nfunction receiverOnMessage(data, isBinary) {\n this[kWebSocket].emit('message', data, isBinary);\n}\n\n/**\n * The listener of the `Receiver` `'ping'` event.\n *\n * @param {Buffer} data The data included in the ping frame\n * @private\n */\nfunction receiverOnPing(data) {\n const websocket = this[kWebSocket];\n\n if (websocket._autoPong) websocket.pong(data, !this._isServer, NOOP);\n websocket.emit('ping', data);\n}\n\n/**\n * The listener of the `Receiver` `'pong'` event.\n *\n * @param {Buffer} data The data included in the pong frame\n * @private\n */\nfunction receiverOnPong(data) {\n this[kWebSocket].emit('pong', data);\n}\n\n/**\n * Resume a readable stream\n *\n * @param {Readable} stream The readable stream\n * @private\n */\nfunction resume(stream) {\n stream.resume();\n}\n\n/**\n * The `Sender` error event handler.\n *\n * @param {Error} The error\n * @private\n */\nfunction senderOnError(err) {\n const websocket = this[kWebSocket];\n\n if (websocket.readyState === WebSocket.CLOSED) return;\n if (websocket.readyState === WebSocket.OPEN) {\n websocket._readyState = WebSocket.CLOSING;\n setCloseTimer(websocket);\n }\n\n //\n // `socket.end()` is used instead of `socket.destroy()` to allow the other\n // peer to finish sending queued data. There is no need to set a timer here\n // because `CLOSING` means that it is already set or not needed.\n //\n this._socket.end();\n\n if (!websocket._errorEmitted) {\n websocket._errorEmitted = true;\n websocket.emit('error', err);\n }\n}\n\n/**\n * Set a timer to destroy the underlying raw socket of a WebSocket.\n *\n * @param {WebSocket} websocket The WebSocket instance\n * @private\n */\nfunction setCloseTimer(websocket) {\n websocket._closeTimer = setTimeout(\n websocket._socket.destroy.bind(websocket._socket),\n websocket._closeTimeout\n );\n}\n\n/**\n * The listener of the socket `'close'` event.\n *\n * @private\n */\nfunction socketOnClose() {\n const websocket = this[kWebSocket];\n\n this.removeListener('close', socketOnClose);\n this.removeListener('data', socketOnData);\n this.removeListener('end', socketOnEnd);\n\n websocket._readyState = WebSocket.CLOSING;\n\n //\n // The close frame might not have been received or the `'end'` event emitted,\n // for example, if the socket was destroyed due to an error. Ensure that the\n // `receiver` stream is closed after writing any remaining buffered data to\n // it. If the readable side of the socket is in flowing mode then there is no\n // buffered data as everything has been already written. If instead, the\n // socket is paused, any possible buffered data will be read as a single\n // chunk.\n //\n if (\n !this._readableState.endEmitted &&\n !websocket._closeFrameReceived &&\n !websocket._receiver._writableState.errorEmitted &&\n this._readableState.length !== 0\n ) {\n const chunk = this.read(this._readableState.length);\n\n websocket._receiver.write(chunk);\n }\n\n websocket._receiver.end();\n\n this[kWebSocket] = undefined;\n\n clearTimeout(websocket._closeTimer);\n\n if (\n websocket._receiver._writableState.finished ||\n websocket._receiver._writableState.errorEmitted\n ) {\n websocket.emitClose();\n } else {\n websocket._receiver.on('error', receiverOnFinish);\n websocket._receiver.on('finish', receiverOnFinish);\n }\n}\n\n/**\n * The listener of the socket `'data'` event.\n *\n * @param {Buffer} chunk A chunk of data\n * @private\n */\nfunction socketOnData(chunk) {\n if (!this[kWebSocket]._receiver.write(chunk)) {\n this.pause();\n }\n}\n\n/**\n * The listener of the socket `'end'` event.\n *\n * @private\n */\nfunction socketOnEnd() {\n const websocket = this[kWebSocket];\n\n websocket._readyState = WebSocket.CLOSING;\n websocket._receiver.end();\n this.end();\n}\n\n/**\n * The listener of the socket `'error'` event.\n *\n * @private\n */\nfunction socketOnError() {\n const websocket = this[kWebSocket];\n\n this.removeListener('error', socketOnError);\n this.on('error', NOOP);\n\n if (websocket) {\n websocket._readyState = WebSocket.CLOSING;\n this.destroy();\n }\n}\n","/* eslint no-unused-vars: [\"error\", { \"varsIgnorePattern\": \"^WebSocket$\" }] */\n'use strict';\n\nconst WebSocket = require('./websocket');\nconst { Duplex } = require('stream');\n\n/**\n * Emits the `'close'` event on a stream.\n *\n * @param {Duplex} stream The stream.\n * @private\n */\nfunction emitClose(stream) {\n stream.emit('close');\n}\n\n/**\n * The listener of the `'end'` event.\n *\n * @private\n */\nfunction duplexOnEnd() {\n if (!this.destroyed && this._writableState.finished) {\n this.destroy();\n }\n}\n\n/**\n * The listener of the `'error'` event.\n *\n * @param {Error} err The error\n * @private\n */\nfunction duplexOnError(err) {\n this.removeListener('error', duplexOnError);\n this.destroy();\n if (this.listenerCount('error') === 0) {\n // Do not suppress the throwing behavior.\n this.emit('error', err);\n }\n}\n\n/**\n * Wraps a `WebSocket` in a duplex stream.\n *\n * @param {WebSocket} ws The `WebSocket` to wrap\n * @param {Object} [options] The options for the `Duplex` constructor\n * @return {Duplex} The duplex stream\n * @public\n */\nfunction createWebSocketStream(ws, options) {\n let terminateOnDestroy = true;\n\n const duplex = new Duplex({\n ...options,\n autoDestroy: false,\n emitClose: false,\n objectMode: false,\n writableObjectMode: false\n });\n\n ws.on('message', function message(msg, isBinary) {\n const data =\n !isBinary && duplex._readableState.objectMode ? msg.toString() : msg;\n\n if (!duplex.push(data)) ws.pause();\n });\n\n ws.once('error', function error(err) {\n if (duplex.destroyed) return;\n\n // Prevent `ws.terminate()` from being called by `duplex._destroy()`.\n //\n // - If the `'error'` event is emitted before the `'open'` event, then\n // `ws.terminate()` is a noop as no socket is assigned.\n // - Otherwise, the error is re-emitted by the listener of the `'error'`\n // event of the `Receiver` object. The listener already closes the\n // connection by calling `ws.close()`. This allows a close frame to be\n // sent to the other peer. If `ws.terminate()` is called right after this,\n // then the close frame might not be sent.\n terminateOnDestroy = false;\n duplex.destroy(err);\n });\n\n ws.once('close', function close() {\n if (duplex.destroyed) return;\n\n duplex.push(null);\n });\n\n duplex._destroy = function (err, callback) {\n if (ws.readyState === ws.CLOSED) {\n callback(err);\n process.nextTick(emitClose, duplex);\n return;\n }\n\n let called = false;\n\n ws.once('error', function error(err) {\n called = true;\n callback(err);\n });\n\n ws.once('close', function close() {\n if (!called) callback(err);\n process.nextTick(emitClose, duplex);\n });\n\n if (terminateOnDestroy) ws.terminate();\n };\n\n duplex._final = function (callback) {\n if (ws.readyState === ws.CONNECTING) {\n ws.once('open', function open() {\n duplex._final(callback);\n });\n return;\n }\n\n // If the value of the `_socket` property is `null` it means that `ws` is a\n // client websocket and the handshake failed. In fact, when this happens, a\n // socket is never assigned to the websocket. Wait for the `'error'` event\n // that will be emitted by the websocket.\n if (ws._socket === null) return;\n\n if (ws._socket._writableState.finished) {\n callback();\n if (duplex._readableState.endEmitted) duplex.destroy();\n } else {\n ws._socket.once('finish', function finish() {\n // `duplex` is not destroyed here because the `'end'` event will be\n // emitted on `duplex` after this `'finish'` event. The EOF signaling\n // `null` chunk is, in fact, pushed when the websocket emits `'close'`.\n callback();\n });\n ws.close();\n }\n };\n\n duplex._read = function () {\n if (ws.isPaused) ws.resume();\n };\n\n duplex._write = function (chunk, encoding, callback) {\n if (ws.readyState === ws.CONNECTING) {\n ws.once('open', function open() {\n duplex._write(chunk, encoding, callback);\n });\n return;\n }\n\n ws.send(chunk, callback);\n };\n\n duplex.on('end', duplexOnEnd);\n duplex.on('error', duplexOnError);\n return duplex;\n}\n\nmodule.exports = createWebSocketStream;\n","'use strict';\n\nconst { tokenChars } = require('./validation');\n\n/**\n * Parses the `Sec-WebSocket-Protocol` header into a set of subprotocol names.\n *\n * @param {String} header The field value of the header\n * @return {Set} The subprotocol names\n * @public\n */\nfunction parse(header) {\n const protocols = new Set();\n let start = -1;\n let end = -1;\n let i = 0;\n\n for (i; i < header.length; i++) {\n const code = header.charCodeAt(i);\n\n if (end === -1 && tokenChars[code] === 1) {\n if (start === -1) start = i;\n } else if (\n i !== 0 &&\n (code === 0x20 /* ' ' */ || code === 0x09) /* '\\t' */\n ) {\n if (end === -1 && start !== -1) end = i;\n } else if (code === 0x2c /* ',' */) {\n if (start === -1) {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n\n if (end === -1) end = i;\n\n const protocol = header.slice(start, end);\n\n if (protocols.has(protocol)) {\n throw new SyntaxError(`The \"${protocol}\" subprotocol is duplicated`);\n }\n\n protocols.add(protocol);\n start = end = -1;\n } else {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n }\n\n if (start === -1 || end !== -1) {\n throw new SyntaxError('Unexpected end of input');\n }\n\n const protocol = header.slice(start, i);\n\n if (protocols.has(protocol)) {\n throw new SyntaxError(`The \"${protocol}\" subprotocol is duplicated`);\n }\n\n protocols.add(protocol);\n return protocols;\n}\n\nmodule.exports = { parse };\n","/* eslint no-unused-vars: [\"error\", { \"varsIgnorePattern\": \"^Duplex$\", \"caughtErrors\": \"none\" }] */\n\n'use strict';\n\nconst EventEmitter = require('events');\nconst http = require('http');\nconst { Duplex } = require('stream');\nconst { createHash } = require('crypto');\n\nconst extension = require('./extension');\nconst PerMessageDeflate = require('./permessage-deflate');\nconst subprotocol = require('./subprotocol');\nconst WebSocket = require('./websocket');\nconst { CLOSE_TIMEOUT, GUID, kWebSocket } = require('./constants');\n\nconst keyRegex = /^[+/0-9A-Za-z]{22}==$/;\n\nconst RUNNING = 0;\nconst CLOSING = 1;\nconst CLOSED = 2;\n\n/**\n * Class representing a WebSocket server.\n *\n * @extends EventEmitter\n */\nclass WebSocketServer extends EventEmitter {\n /**\n * Create a `WebSocketServer` instance.\n *\n * @param {Object} options Configuration options\n * @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether\n * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted\n * multiple times in the same tick\n * @param {Boolean} [options.autoPong=true] Specifies whether or not to\n * automatically send a pong in response to a ping\n * @param {Number} [options.backlog=511] The maximum length of the queue of\n * pending connections\n * @param {Boolean} [options.clientTracking=true] Specifies whether or not to\n * track clients\n * @param {Number} [options.closeTimeout=30000] Duration in milliseconds to\n * wait for the closing handshake to finish after `websocket.close()` is\n * called\n * @param {Function} [options.handleProtocols] A hook to handle protocols\n * @param {String} [options.host] The hostname where to bind the server\n * @param {Number} [options.maxPayload=104857600] The maximum allowed message\n * size\n * @param {Boolean} [options.noServer=false] Enable no server mode\n * @param {String} [options.path] Accept only connections matching this path\n * @param {(Boolean|Object)} [options.perMessageDeflate=false] Enable/disable\n * permessage-deflate\n * @param {Number} [options.port] The port where to bind the server\n * @param {(http.Server|https.Server)} [options.server] A pre-created HTTP/S\n * server to use\n * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or\n * not to skip UTF-8 validation for text and close messages\n * @param {Function} [options.verifyClient] A hook to reject connections\n * @param {Function} [options.WebSocket=WebSocket] Specifies the `WebSocket`\n * class to use. It must be the `WebSocket` class or class that extends it\n * @param {Function} [callback] A listener for the `listening` event\n */\n constructor(options, callback) {\n super();\n\n options = {\n allowSynchronousEvents: true,\n autoPong: true,\n maxPayload: 100 * 1024 * 1024,\n skipUTF8Validation: false,\n perMessageDeflate: false,\n handleProtocols: null,\n clientTracking: true,\n closeTimeout: CLOSE_TIMEOUT,\n verifyClient: null,\n noServer: false,\n backlog: null, // use default (511 as implemented in net.js)\n server: null,\n host: null,\n path: null,\n port: null,\n WebSocket,\n ...options\n };\n\n if (\n (options.port == null && !options.server && !options.noServer) ||\n (options.port != null && (options.server || options.noServer)) ||\n (options.server && options.noServer)\n ) {\n throw new TypeError(\n 'One and only one of the \"port\", \"server\", or \"noServer\" options ' +\n 'must be specified'\n );\n }\n\n if (options.port != null) {\n this._server = http.createServer((req, res) => {\n const body = http.STATUS_CODES[426];\n\n res.writeHead(426, {\n 'Content-Length': body.length,\n 'Content-Type': 'text/plain'\n });\n res.end(body);\n });\n this._server.listen(\n options.port,\n options.host,\n options.backlog,\n callback\n );\n } else if (options.server) {\n this._server = options.server;\n }\n\n if (this._server) {\n const emitConnection = this.emit.bind(this, 'connection');\n\n this._removeListeners = addListeners(this._server, {\n listening: this.emit.bind(this, 'listening'),\n error: this.emit.bind(this, 'error'),\n upgrade: (req, socket, head) => {\n this.handleUpgrade(req, socket, head, emitConnection);\n }\n });\n }\n\n if (options.perMessageDeflate === true) options.perMessageDeflate = {};\n if (options.clientTracking) {\n this.clients = new Set();\n this._shouldEmitClose = false;\n }\n\n this.options = options;\n this._state = RUNNING;\n }\n\n /**\n * Returns the bound address, the address family name, and port of the server\n * as reported by the operating system if listening on an IP socket.\n * If the server is listening on a pipe or UNIX domain socket, the name is\n * returned as a string.\n *\n * @return {(Object|String|null)} The address of the server\n * @public\n */\n address() {\n if (this.options.noServer) {\n throw new Error('The server is operating in \"noServer\" mode');\n }\n\n if (!this._server) return null;\n return this._server.address();\n }\n\n /**\n * Stop the server from accepting new connections and emit the `'close'` event\n * when all existing connections are closed.\n *\n * @param {Function} [cb] A one-time listener for the `'close'` event\n * @public\n */\n close(cb) {\n if (this._state === CLOSED) {\n if (cb) {\n this.once('close', () => {\n cb(new Error('The server is not running'));\n });\n }\n\n process.nextTick(emitClose, this);\n return;\n }\n\n if (cb) this.once('close', cb);\n\n if (this._state === CLOSING) return;\n this._state = CLOSING;\n\n if (this.options.noServer || this.options.server) {\n if (this._server) {\n this._removeListeners();\n this._removeListeners = this._server = null;\n }\n\n if (this.clients) {\n if (!this.clients.size) {\n process.nextTick(emitClose, this);\n } else {\n this._shouldEmitClose = true;\n }\n } else {\n process.nextTick(emitClose, this);\n }\n } else {\n const server = this._server;\n\n this._removeListeners();\n this._removeListeners = this._server = null;\n\n //\n // The HTTP/S server was created internally. Close it, and rely on its\n // `'close'` event.\n //\n server.close(() => {\n emitClose(this);\n });\n }\n }\n\n /**\n * See if a given request should be handled by this server instance.\n *\n * @param {http.IncomingMessage} req Request object to inspect\n * @return {Boolean} `true` if the request is valid, else `false`\n * @public\n */\n shouldHandle(req) {\n if (this.options.path) {\n const index = req.url.indexOf('?');\n const pathname = index !== -1 ? req.url.slice(0, index) : req.url;\n\n if (pathname !== this.options.path) return false;\n }\n\n return true;\n }\n\n /**\n * Handle a HTTP Upgrade request.\n *\n * @param {http.IncomingMessage} req The request object\n * @param {Duplex} socket The network socket between the server and client\n * @param {Buffer} head The first packet of the upgraded stream\n * @param {Function} cb Callback\n * @public\n */\n handleUpgrade(req, socket, head, cb) {\n socket.on('error', socketOnError);\n\n const key = req.headers['sec-websocket-key'];\n const upgrade = req.headers.upgrade;\n const version = +req.headers['sec-websocket-version'];\n\n if (req.method !== 'GET') {\n const message = 'Invalid HTTP method';\n abortHandshakeOrEmitwsClientError(this, req, socket, 405, message);\n return;\n }\n\n if (upgrade === undefined || upgrade.toLowerCase() !== 'websocket') {\n const message = 'Invalid Upgrade header';\n abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);\n return;\n }\n\n if (key === undefined || !keyRegex.test(key)) {\n const message = 'Missing or invalid Sec-WebSocket-Key header';\n abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);\n return;\n }\n\n if (version !== 13 && version !== 8) {\n const message = 'Missing or invalid Sec-WebSocket-Version header';\n abortHandshakeOrEmitwsClientError(this, req, socket, 400, message, {\n 'Sec-WebSocket-Version': '13, 8'\n });\n return;\n }\n\n if (!this.shouldHandle(req)) {\n abortHandshake(socket, 400);\n return;\n }\n\n const secWebSocketProtocol = req.headers['sec-websocket-protocol'];\n let protocols = new Set();\n\n if (secWebSocketProtocol !== undefined) {\n try {\n protocols = subprotocol.parse(secWebSocketProtocol);\n } catch (err) {\n const message = 'Invalid Sec-WebSocket-Protocol header';\n abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);\n return;\n }\n }\n\n const secWebSocketExtensions = req.headers['sec-websocket-extensions'];\n const extensions = {};\n\n if (\n this.options.perMessageDeflate &&\n secWebSocketExtensions !== undefined\n ) {\n const perMessageDeflate = new PerMessageDeflate(\n this.options.perMessageDeflate,\n true,\n this.options.maxPayload\n );\n\n try {\n const offers = extension.parse(secWebSocketExtensions);\n\n if (offers[PerMessageDeflate.extensionName]) {\n perMessageDeflate.accept(offers[PerMessageDeflate.extensionName]);\n extensions[PerMessageDeflate.extensionName] = perMessageDeflate;\n }\n } catch (err) {\n const message =\n 'Invalid or unacceptable Sec-WebSocket-Extensions header';\n abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);\n return;\n }\n }\n\n //\n // Optionally call external client verification handler.\n //\n if (this.options.verifyClient) {\n const info = {\n origin:\n req.headers[`${version === 8 ? 'sec-websocket-origin' : 'origin'}`],\n secure: !!(req.socket.authorized || req.socket.encrypted),\n req\n };\n\n if (this.options.verifyClient.length === 2) {\n this.options.verifyClient(info, (verified, code, message, headers) => {\n if (!verified) {\n return abortHandshake(socket, code || 401, message, headers);\n }\n\n this.completeUpgrade(\n extensions,\n key,\n protocols,\n req,\n socket,\n head,\n cb\n );\n });\n return;\n }\n\n if (!this.options.verifyClient(info)) return abortHandshake(socket, 401);\n }\n\n this.completeUpgrade(extensions, key, protocols, req, socket, head, cb);\n }\n\n /**\n * Upgrade the connection to WebSocket.\n *\n * @param {Object} extensions The accepted extensions\n * @param {String} key The value of the `Sec-WebSocket-Key` header\n * @param {Set} protocols The subprotocols\n * @param {http.IncomingMessage} req The request object\n * @param {Duplex} socket The network socket between the server and client\n * @param {Buffer} head The first packet of the upgraded stream\n * @param {Function} cb Callback\n * @throws {Error} If called more than once with the same socket\n * @private\n */\n completeUpgrade(extensions, key, protocols, req, socket, head, cb) {\n //\n // Destroy the socket if the client has already sent a FIN packet.\n //\n if (!socket.readable || !socket.writable) return socket.destroy();\n\n if (socket[kWebSocket]) {\n throw new Error(\n 'server.handleUpgrade() was called more than once with the same ' +\n 'socket, possibly due to a misconfiguration'\n );\n }\n\n if (this._state > RUNNING) return abortHandshake(socket, 503);\n\n const digest = createHash('sha1')\n .update(key + GUID)\n .digest('base64');\n\n const headers = [\n 'HTTP/1.1 101 Switching Protocols',\n 'Upgrade: websocket',\n 'Connection: Upgrade',\n `Sec-WebSocket-Accept: ${digest}`\n ];\n\n const ws = new this.options.WebSocket(null, undefined, this.options);\n\n if (protocols.size) {\n //\n // Optionally call external protocol selection handler.\n //\n const protocol = this.options.handleProtocols\n ? this.options.handleProtocols(protocols, req)\n : protocols.values().next().value;\n\n if (protocol) {\n headers.push(`Sec-WebSocket-Protocol: ${protocol}`);\n ws._protocol = protocol;\n }\n }\n\n if (extensions[PerMessageDeflate.extensionName]) {\n const params = extensions[PerMessageDeflate.extensionName].params;\n const value = extension.format({\n [PerMessageDeflate.extensionName]: [params]\n });\n headers.push(`Sec-WebSocket-Extensions: ${value}`);\n ws._extensions = extensions;\n }\n\n //\n // Allow external modification/inspection of handshake headers.\n //\n this.emit('headers', headers, req);\n\n socket.write(headers.concat('\\r\\n').join('\\r\\n'));\n socket.removeListener('error', socketOnError);\n\n ws.setSocket(socket, head, {\n allowSynchronousEvents: this.options.allowSynchronousEvents,\n maxPayload: this.options.maxPayload,\n skipUTF8Validation: this.options.skipUTF8Validation\n });\n\n if (this.clients) {\n this.clients.add(ws);\n ws.on('close', () => {\n this.clients.delete(ws);\n\n if (this._shouldEmitClose && !this.clients.size) {\n process.nextTick(emitClose, this);\n }\n });\n }\n\n cb(ws, req);\n }\n}\n\nmodule.exports = WebSocketServer;\n\n/**\n * Add event listeners on an `EventEmitter` using a map of <event, listener>\n * pairs.\n *\n * @param {EventEmitter} server The event emitter\n * @param {Object.<String, Function>} map The listeners to add\n * @return {Function} A function that will remove the added listeners when\n * called\n * @private\n */\nfunction addListeners(server, map) {\n for (const event of Object.keys(map)) server.on(event, map[event]);\n\n return function removeListeners() {\n for (const event of Object.keys(map)) {\n server.removeListener(event, map[event]);\n }\n };\n}\n\n/**\n * Emit a `'close'` event on an `EventEmitter`.\n *\n * @param {EventEmitter} server The event emitter\n * @private\n */\nfunction emitClose(server) {\n server._state = CLOSED;\n server.emit('close');\n}\n\n/**\n * Handle socket errors.\n *\n * @private\n */\nfunction socketOnError() {\n this.destroy();\n}\n\n/**\n * Close the connection when preconditions are not fulfilled.\n *\n * @param {Duplex} socket The socket of the upgrade request\n * @param {Number} code The HTTP response status code\n * @param {String} [message] The HTTP response body\n * @param {Object} [headers] Additional HTTP response headers\n * @private\n */\nfunction abortHandshake(socket, code, message, headers) {\n //\n // The socket is writable unless the user destroyed or ended it before calling\n // `server.handleUpgrade()` or in the `verifyClient` function, which is a user\n // error. Handling this does not make much sense as the worst that can happen\n // is that some of the data written by the user might be discarded due to the\n // call to `socket.end()` below, which triggers an `'error'` event that in\n // turn causes the socket to be destroyed.\n //\n message = message || http.STATUS_CODES[code];\n headers = {\n Connection: 'close',\n 'Content-Type': 'text/html',\n 'Content-Length': Buffer.byteLength(message),\n ...headers\n };\n\n socket.once('finish', socket.destroy);\n\n socket.end(\n `HTTP/1.1 ${code} ${http.STATUS_CODES[code]}\\r\\n` +\n Object.keys(headers)\n .map((h) => `${h}: ${headers[h]}`)\n .join('\\r\\n') +\n '\\r\\n\\r\\n' +\n message\n );\n}\n\n/**\n * Emit a `'wsClientError'` event on a `WebSocketServer` if there is at least\n * one listener for it, otherwise call `abortHandshake()`.\n *\n * @param {WebSocketServer} server The WebSocket server\n * @param {http.IncomingMessage} req The request object\n * @param {Duplex} socket The socket of the upgrade request\n * @param {Number} code The HTTP response status code\n * @param {String} message The HTTP response body\n * @param {Object} [headers] The HTTP response headers\n * @private\n */\nfunction abortHandshakeOrEmitwsClientError(\n server,\n req,\n socket,\n code,\n message,\n headers\n) {\n if (server.listenerCount('wsClientError')) {\n const err = new Error(message);\n Error.captureStackTrace(err, abortHandshakeOrEmitwsClientError);\n\n server.emit('wsClientError', err, socket, req);\n } else {\n abortHandshake(socket, code, message, headers);\n }\n}\n","import type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport type { Logger } from \"./logger.js\";\nimport {\n createVersionAwareLogger,\n PluginFileLogger as PluginLogger,\n} from \"./logger.js\";\nimport {\n RecordingStorage,\n type RecordingStatusEvent,\n} from \"./recording/index.js\";\nimport type { NotificationStorage } from \"./notification/storage.js\";\nimport { registerLightRulesGateway } from \"./light-rules/gateway.js\";\nimport {\n LIGHT_RULE_GATEWAY_METHOD_LIST,\n LIGHT_RULE_TOOL_NAME_LIST,\n LIGHT_RULE_TOOL_NAMES,\n} from \"./light-rules/names.js\";\nimport { registerLightRulesTools } from \"./plugin/light-rules-tools.js\";\nimport { InlineLightRuleEvaluator } from \"./light-rules/inline-evaluator.js\";\nimport { LightRuleEvaluationScheduler } from \"./light-rules/evaluation-scheduler.js\";\nimport { PiAiInvoker } from \"./light-rules/pi-invoker.js\";\nimport { LightRuleRegistry } from \"./light-rules/registry.js\";\nimport { registerAutoUpdateLifecycle } from \"./plugin/auto-update.js\";\nimport { registerPluginCli } from \"./plugin/cli.js\";\nimport { registerLightControlTool } from \"./plugin/light-control.js\";\nimport {\n registerRelayTunnelLifecycle,\n registerStorageLifecycle,\n} from \"./plugin/lifecycle.js\";\nimport { registerNotificationInterfaces } from \"./plugin/notifications.js\";\nimport { registerRecordingInterfaces } from \"./plugin/recordings.js\";\nimport { isPluginCliInvocation } from \"./plugin/runtime-mode.js\";\nimport { resolvePluginStateDir } from \"./plugin/runtime-state.js\";\nimport type { GatewayHandler } from \"./plugin/shared.js\";\nimport { RELAY_TUNNEL_GATEWAY_CLIENT_INSTANCE_ID } from \"./tunnel/proxy.js\";\nimport type { PluginConfig, RawNotification } from \"./types.js\";\nimport type { BroadcastFn } from \"./update/types.js\";\n\nconst LIGHT_RULE_PROMPT_GUIDANCE = [\n \"灯效规则路由提示:\",\n `- 当用户表达“收到/当/如果/有某类通知或消息时,亮灯/闪灯/变成某种灯效”时,这是持久灯效规则请求,必须调用 ${LIGHT_RULE_TOOL_NAMES.create} 或 ${LIGHT_RULE_TOOL_NAMES.update}。`,\n \"- 不要为这类通知触发规则直接调用 light_control;light_control 只用于当前立即执行的一次性灯效、测试或预览。\",\n \"- 不要手写或编辑 tasks/*/meta.json;灯效规则的创建、修改、删除和查询都走 lightrules_* 工具。\",\n].join(\"\\n\");\n\nexport default {\n id: \"phone-notifications\",\n name: \"Phone Notifications & Light Control\",\n\n register(api: OpenClawPluginApi) {\n const config = (api.pluginConfig ?? {}) as PluginConfig;\n const ignoredApps = new Set(config.ignoredApps ?? []);\n\n let storage: NotificationStorage | null = null;\n let recordingStorage: RecordingStorage | null = null;\n let broadcastFn: BroadcastFn | null = null;\n let autoUpdateLifecycle: ReturnType<typeof registerAutoUpdateLifecycle> | null = null;\n let tunnelService: ReturnType<typeof registerRelayTunnelLifecycle> = null;\n\n const openclawDir = resolvePluginStateDir(api);\n const logger: Logger = openclawDir\n ? new PluginLogger(api.logger, openclawDir)\n : createVersionAwareLogger(api.logger);\n\n const lightRuleCtx: { workspaceDir?: string; stateDir?: string } = {\n stateDir: openclawDir,\n };\n const asrDataDir =\n openclawDir ??\n process.env.OPENCLAW_STATE_DIR ??\n process.env.QCLAW_STATE_DIR ??\n process.cwd();\n\n if (isPluginCliInvocation()) {\n registerPluginCli(api, {\n logger,\n openclawDir,\n });\n logger.info(\n \"检测到插件 CLI 命令执行上下文,仅注册 CLI,跳过后台服务以避免影响 Relay tunnel 常驻连接\",\n );\n return;\n }\n\n api.on(\"before_prompt_build\", () => ({\n appendSystemContext: LIGHT_RULE_PROMPT_GUIDANCE,\n }));\n\n function cacheBroadcast(broadcast: BroadcastFn | undefined): void {\n if (!broadcast) {\n return;\n }\n\n const changed = broadcastFn !== broadcast;\n broadcastFn = broadcast;\n if (changed) {\n autoUpdateLifecycle?.notifyBroadcastReady();\n }\n }\n\n function isDirectMobileGatewayRequest(\n opts: Parameters<GatewayHandler>[0],\n ): boolean {\n const client = opts.client?.connect?.client;\n if (!client) return false;\n if (client.instanceId === RELAY_TUNNEL_GATEWAY_CLIENT_INSTANCE_ID) {\n return false;\n }\n return client.id === \"openclaw-ios\" || client.id === \"openclaw-android\";\n }\n\n async function deactivateRelayForDirectGatewayRequest(\n method: string,\n opts: Parameters<GatewayHandler>[0],\n ): Promise<void> {\n if (!tunnelService || !isDirectMobileGatewayRequest(opts)) return;\n\n const client = opts.client?.connect?.client;\n try {\n await tunnelService.deactivateForExternalTunnel(\n `gateway method ${method} from ${client?.id ?? \"unknown\"}`,\n );\n } catch (err: any) {\n logger.warn(\n `Relay tunnel: failed to deactivate after direct gateway method ${method}: ${err?.message ?? String(err)}`,\n );\n }\n }\n\n function registerGatewayMethodWithBroadcastCapture(\n method: string,\n handler: GatewayHandler,\n ): void {\n api.registerGatewayMethod(method, async (opts) => {\n cacheBroadcast(opts.context?.broadcast);\n await deactivateRelayForDirectGatewayRequest(method, opts);\n return handler(opts);\n });\n }\n\n function filterNotifications(items: RawNotification[]): RawNotification[] {\n return items.filter((notification) => !ignoredApps.has(notification.app));\n }\n\n function notifyRecordingStatus(event: RecordingStatusEvent): void {\n if (!broadcastFn) {\n logger.warn(\n `[recording.status] broadcast 不可用,跳过状态事件: ${event.recordingId} -> ${event.transfer_status}`,\n );\n return;\n }\n\n broadcastFn(\"recording.status\", event);\n }\n\n const lightRuleRegistry = new LightRuleRegistry(lightRuleCtx);\n const lightRuleInvoker = new PiAiInvoker(api, logger);\n const inlineLightRuleEvaluator = new InlineLightRuleEvaluator({\n logger,\n registry: lightRuleRegistry,\n invoker: lightRuleInvoker,\n });\n const lightRuleEvaluationScheduler = new LightRuleEvaluationScheduler({\n evaluator: inlineLightRuleEvaluator,\n logger,\n });\n\n registerStorageLifecycle({\n api,\n config,\n logger,\n lightRuleCtx,\n setStorage(nextStorage) {\n storage = nextStorage;\n },\n setRecordingStorage(nextRecordingStorage) {\n recordingStorage = nextRecordingStorage;\n },\n onStorageReady() {\n // storage service start 完成后 lightRuleCtx 才被回填到真实的 workspaceDir,\n // 此时重新扫盘加载已有规则。\n lightRuleRegistry.reload();\n },\n });\n\n tunnelService = registerRelayTunnelLifecycle({\n api,\n config,\n logger,\n openclawDir,\n });\n\n registerNotificationInterfaces({\n api,\n logger,\n getStorage: () => storage,\n filterNotifications,\n registerGatewayMethod: registerGatewayMethodWithBroadcastCapture,\n tunnelService,\n onAfterIngest(inserted, ingestId) {\n lightRuleEvaluationScheduler.enqueue(inserted, ingestId);\n },\n });\n\n registerLightControlTool(api, logger);\n\n registerRecordingInterfaces({\n api,\n logger,\n asrDataDir,\n getRecordingStorage: () => recordingStorage,\n notifyRecordingStatus,\n registerGatewayMethod: registerGatewayMethodWithBroadcastCapture,\n shouldBroadcastStatusOnHttp: () => !!broadcastFn,\n tunnelService,\n });\n\n registerLightRulesGateway(api, lightRuleRegistry, logger, cacheBroadcast);\n registerLightRulesTools(api, lightRuleRegistry, logger);\n logger.info(\n `灯效规则方法已注册: gateway=${LIGHT_RULE_GATEWAY_METHOD_LIST.join(\", \")}; tools=${LIGHT_RULE_TOOL_NAME_LIST.join(\", \")}`,\n );\n\n autoUpdateLifecycle = registerAutoUpdateLifecycle({\n api,\n config,\n logger,\n getBroadcastFn: () => broadcastFn,\n cacheBroadcast,\n tunnelService,\n });\n\n registerPluginCli(api, {\n logger,\n openclawDir,\n });\n },\n};\n","import { appendFileSync, mkdirSync, readdirSync, rmSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { PLUGIN_VERSION } from \"./version.js\";\n\nexport interface Logger {\n info: (msg: string) => void;\n warn: (msg: string) => void;\n error: (msg: string) => void;\n}\n\nconst DEFAULT_LOG_RETENTION_DAYS = 30;\nconst DAY_MS = 24 * 60 * 60 * 1000;\n\nexport interface PluginFileLoggerOptions {\n version?: string;\n retentionDays?: number;\n}\n\nconst REDACTED = \"[redacted]\";\nconst REDACTED_SECRET = \"[redacted-secret]\";\nconst REDACTED_URL = \"[redacted-url]\";\n\nconst SECRET_KEYS = [\n \"apiKey\",\n \"api_key\",\n \"appKey\",\n \"authorization\",\n \"password\",\n \"secret\",\n \"token\",\n \"accessToken\",\n \"refreshToken\",\n \"gatewayToken\",\n \"gatewayPassword\",\n \"apnsToken\",\n \"deviceToken\",\n \"X-Api-Key-Id\",\n \"x-api-key-id\",\n \"x-openclaw-password\",\n];\n\nconst USER_TEXT_KEYS = [\n \"accountId\",\n \"body\",\n \"content\",\n \"conversationName\",\n \"deviceId\",\n \"loginAccount\",\n \"metadata\",\n \"name\",\n \"raw\",\n \"rawResponse\",\n \"reason\",\n \"recordResult\",\n \"recordingName\",\n \"resBody\",\n \"response\",\n \"senderName\",\n \"sourceText\",\n \"sourceTextList\",\n \"summary\",\n \"summaryResult\",\n \"summaryText\",\n \"text\",\n \"title\",\n \"transcript\",\n \"transcriptData\",\n \"userId\",\n];\n\nconst USER_URL_KEYS = [\n \"audio\",\n \"audioOssUrl\",\n \"fileUrl\",\n \"oss_audio_url\",\n \"oss_srt_url\",\n \"srt\",\n \"url\",\n];\n\nconst SENSITIVE_QUERY_KEYS = [\n \"access_token\",\n \"api_key\",\n \"apikey\",\n \"authorization\",\n \"fileUrl\",\n \"password\",\n \"refresh_token\",\n \"secret\",\n \"signature\",\n \"token\",\n \"x-api-key-id\",\n \"x-oss-security-token\",\n];\n\nexport function isBetaPluginVersion(version = PLUGIN_VERSION): boolean {\n return /\\bbeta\\b/i.test(version);\n}\n\nexport function createVersionAwareLogger(\n upstream: Logger,\n options: Pick<PluginFileLoggerOptions, \"version\"> = {},\n): Logger {\n if (isBetaPluginVersion(options.version ?? PLUGIN_VERSION)) {\n return upstream;\n }\n\n return {\n info(msg: string) {\n upstream.info(redactLogMessage(msg));\n },\n warn(msg: string) {\n upstream.warn(redactLogMessage(msg));\n },\n error(msg: string) {\n upstream.error(redactLogMessage(msg));\n },\n };\n}\n\n/**\n * 插件级文件 Logger。\n * 在调用原始 api.logger 的同时,把日志追加写入\n * `<stateDir>/plugins/phone-notifications/logs/YYYY-MM-DD.log`。\n * beta 版本保留原始日志;正式版保留 INFO,并对日志里的用户数据做兜底脱敏。\n */\nexport class PluginFileLogger implements Logger {\n private readonly logsDir: string;\n private readonly redactLogs: boolean;\n private readonly retentionDays: number;\n private lastPruneDateKey: string | null = null;\n\n constructor(\n private readonly upstream: Logger,\n stateDir: string,\n options: PluginFileLoggerOptions = {},\n ) {\n this.logsDir = join(stateDir, \"plugins\", \"phone-notifications\", \"logs\");\n this.redactLogs = !isBetaPluginVersion(options.version ?? PLUGIN_VERSION);\n this.retentionDays =\n Number.isFinite(options.retentionDays) && (options.retentionDays ?? 0) > 0\n ? options.retentionDays!\n : DEFAULT_LOG_RETENTION_DAYS;\n\n mkdirSync(this.logsDir, { recursive: true });\n const now = new Date();\n this.pruneExpiredLogs(now);\n this.lastPruneDateKey = formatDate(now);\n }\n\n info(msg: string): void {\n this.prepareLogDate(new Date());\n const safeMsg = this.formatLogMessage(msg);\n this.upstream.info(safeMsg);\n this.append(\"INFO\", safeMsg);\n }\n\n warn(msg: string): void {\n const safeMsg = this.formatLogMessage(msg);\n this.upstream.warn(safeMsg);\n this.append(\"WARN\", safeMsg);\n }\n\n error(msg: string): void {\n const safeMsg = this.formatLogMessage(msg);\n this.upstream.error(safeMsg);\n this.append(\"ERROR\", safeMsg);\n }\n\n private formatLogMessage(msg: string): string {\n return this.redactLogs ? redactLogMessage(msg) : msg;\n }\n\n private append(level: string, msg: string): void {\n const now = new Date();\n const dateKey = this.prepareLogDate(now);\n const time = formatLocalTimestamp(now);\n const line = `${time} [${level}] ${msg}\\n`;\n try {\n appendFileSync(join(this.logsDir, `${dateKey}.log`), line);\n } catch {\n // 写文件失败不影响主流程\n }\n }\n\n private prepareLogDate(now: Date): string {\n const dateKey = formatDate(now);\n if (this.lastPruneDateKey !== dateKey) {\n this.pruneExpiredLogs(now);\n this.lastPruneDateKey = dateKey;\n }\n return dateKey;\n }\n\n private pruneExpiredLogs(now: Date): void {\n const cutoffMs = now.getTime() - this.retentionDays * DAY_MS;\n const cutoffDate = formatDate(new Date(cutoffMs));\n\n try {\n for (const entry of readdirSync(this.logsDir, { withFileTypes: true })) {\n if (!entry.isFile()) continue;\n const match = /^(\\d{4}-\\d{2}-\\d{2})\\.log$/.exec(entry.name);\n if (match && match[1] < cutoffDate) {\n rmSync(join(this.logsDir, entry.name), { force: true });\n }\n }\n } catch {\n // 清理失败不影响主流程\n }\n }\n}\n\nexport function redactLogMessage(msg: string): string {\n let redacted = String(msg);\n\n redacted = redactQuotedObjectFields(redacted, SECRET_KEYS, REDACTED_SECRET);\n redacted = redactQuotedObjectFields(redacted, USER_TEXT_KEYS, REDACTED);\n redacted = redactQuotedObjectFields(redacted, USER_URL_KEYS, REDACTED_URL);\n\n redacted = redactStructuredKeyValueFields(\n redacted,\n SECRET_KEYS,\n REDACTED_SECRET,\n );\n redacted = redactStructuredKeyValueFields(redacted, USER_TEXT_KEYS, REDACTED);\n redacted = redactStructuredKeyValueFields(redacted, USER_URL_KEYS, REDACTED_URL);\n\n redacted = redactKeyValueFields(redacted, SECRET_KEYS, REDACTED_SECRET);\n redacted = redactKeyValueFields(redacted, USER_TEXT_KEYS, REDACTED);\n redacted = redactKeyValueFields(redacted, USER_URL_KEYS, REDACTED_URL);\n\n redacted = redactColonTextFields(redacted, SECRET_KEYS, REDACTED_SECRET);\n redacted = redactColonTextFields(redacted, USER_TEXT_KEYS, REDACTED);\n redacted = redactQueryParams(redacted, SENSITIVE_QUERY_KEYS);\n redacted = redactBearerTokens(redacted);\n redacted = redactLikelyUserUrls(redacted);\n redacted = redactEmails(redacted);\n redacted = redactPhoneNumbers(redacted);\n redacted = redactJwtTokens(redacted);\n redacted = redactLongHexTokens(redacted);\n\n return redacted;\n}\n\nfunction redactQuotedObjectFields(\n input: string,\n keys: string[],\n placeholder: string,\n): string {\n const keyPattern = buildKeyPattern(keys);\n return input.replace(\n new RegExp(\n `([\"'])(${keyPattern})\\\\1\\\\s*:\\\\s*(?:\"(?:\\\\\\\\.|[^\"\\\\\\\\])*\"|'(?:\\\\\\\\.|[^'\\\\\\\\])*'|[^,}\\\\]]+)`,\n \"gi\",\n ),\n (_match, quote: string, key: string) =>\n `${quote}${key}${quote}: \"${placeholder}\"`,\n );\n}\n\nfunction redactKeyValueFields(\n input: string,\n keys: string[],\n placeholder: string,\n): string {\n const keyPattern = buildKeyPattern(keys);\n return input.replace(\n new RegExp(\n `(?<![?&])\\\\b(${keyPattern})\\\\s*=\\\\s*(?:Bearer\\\\s+[^,\\\\s)]+|\"(?:\\\\\\\\.|[^\"\\\\\\\\])*\"|'(?:\\\\\\\\.|[^'\\\\\\\\])*'|[^,\\\\s)]+)`,\n \"gi\",\n ),\n (_match, key: string) => `${key}=${placeholder}`,\n );\n}\n\nfunction redactStructuredKeyValueFields(\n input: string,\n keys: string[],\n placeholder: string,\n): string {\n const keyPattern = buildKeyPattern(keys);\n const regex = new RegExp(`\\\\b(${keyPattern})\\\\s*=\\\\s*([\\\\[{])`, \"gi\");\n let result = \"\";\n let lastIndex = 0;\n let match: RegExpExecArray | null;\n\n while ((match = regex.exec(input))) {\n const valueStart = regex.lastIndex - 1;\n const valueEnd = findStructuredValueEnd(input, valueStart);\n if (valueEnd === null) {\n continue;\n }\n\n result += input.slice(lastIndex, match.index);\n result += `${match[1]}=${placeholder}`;\n lastIndex = valueEnd;\n regex.lastIndex = valueEnd;\n }\n\n if (lastIndex === 0) {\n return input;\n }\n\n return result + input.slice(lastIndex);\n}\n\nfunction findStructuredValueEnd(input: string, start: number): number | null {\n const open = input[start];\n const close = open === \"{\" ? \"}\" : \"]\";\n const stack: string[] = [close];\n let quote: string | null = null;\n let escaped = false;\n\n for (let i = start + 1; i < input.length; i++) {\n const ch = input[i];\n\n if (quote) {\n if (escaped) {\n escaped = false;\n } else if (ch === \"\\\\\") {\n escaped = true;\n } else if (ch === quote) {\n quote = null;\n }\n continue;\n }\n\n if (ch === \"\\\"\" || ch === \"'\") {\n quote = ch;\n continue;\n }\n\n if (ch === \"{\" || ch === \"[\") {\n stack.push(ch === \"{\" ? \"}\" : \"]\");\n continue;\n }\n\n if (ch === stack[stack.length - 1]) {\n stack.pop();\n if (stack.length === 0) {\n return i + 1;\n }\n }\n }\n\n return null;\n}\n\nfunction redactColonTextFields(\n input: string,\n keys: string[],\n placeholder: string,\n): string {\n const keyPattern = buildKeyPattern(keys);\n return input.replace(\n new RegExp(`\\\\b(${keyPattern})\\\\s*:\\\\s*([^,\\\\n]+)`, \"gi\"),\n (_match, key: string) => `${key}: ${placeholder}`,\n );\n}\n\nfunction redactQueryParams(input: string, keys: string[]): string {\n const keyPattern = buildKeyPattern(keys);\n return input.replace(\n new RegExp(`([?&](${keyPattern})=)([^&#\\\\s]+)`, \"gi\"),\n (_match, prefix: string) => `${prefix}${encodeURIComponent(REDACTED)}`,\n );\n}\n\nfunction redactBearerTokens(input: string): string {\n return input.replace(\n /\\b(Bearer\\s+)[A-Za-z0-9._~+/=-]+/gi,\n `$1${REDACTED_SECRET}`,\n );\n}\n\nfunction redactJwtTokens(input: string): string {\n return input.replace(\n /\\beyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\b/g,\n REDACTED_SECRET,\n );\n}\n\nfunction redactLongHexTokens(input: string): string {\n return input.replace(/\\b[a-f0-9]{32,}\\b/gi, REDACTED_SECRET);\n}\n\nfunction redactEmails(input: string): string {\n return input.replace(\n /\\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}\\b/gi,\n \"[redacted-email]\",\n );\n}\n\nfunction redactPhoneNumbers(input: string): string {\n return input.replace(\n /\\b1[3-9]\\d{9}\\b/g,\n (phone) => `${phone.slice(0, 3)}****${phone.slice(-4)}`,\n );\n}\n\nfunction redactLikelyUserUrls(input: string): string {\n return input.replace(/https?:\\/\\/[^\\s\"',)]+/gi, (rawUrl) =>\n redactUrl(rawUrl),\n );\n}\n\nfunction redactUrl(rawUrl: string): string {\n try {\n const url = new URL(rawUrl);\n for (const key of Array.from(url.searchParams.keys())) {\n if (\n SENSITIVE_QUERY_KEYS.some(\n (sensitiveKey) => sensitiveKey.toLowerCase() === key.toLowerCase(),\n )\n ) {\n url.searchParams.set(key, REDACTED);\n }\n }\n\n if (shouldRedactUrlPath(url)) {\n return `${url.origin}/${REDACTED_URL}`;\n }\n\n return url.toString();\n } catch {\n return rawUrl;\n }\n}\n\nfunction shouldRedactUrlPath(url: URL): boolean {\n const host = url.hostname.toLowerCase();\n const path = decodeURIComponent(url.pathname).toLowerCase();\n if (\n /(^|\\.)((oss|cos|s3|storage|cdn)[.-])/.test(host)\n || /(aliyuncs|myqcloud|amazonaws|oss|storage|cdn)/.test(host)\n ) {\n return true;\n }\n return (\n /\\/(audio|avatar|feedback|log|logs|recording|recordings)\\//.test(path)\n || /\\.(aac|flac|json|m4a|md|mp3|ogg|opus|srt|wav|zip)$/i.test(path)\n );\n}\n\nfunction buildKeyPattern(keys: string[]): string {\n return keys.map(escapeRegExp).join(\"|\");\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nfunction formatDate(d: Date): string {\n const y = d.getFullYear();\n const m = String(d.getMonth() + 1).padStart(2, \"0\");\n const day = String(d.getDate()).padStart(2, \"0\");\n return `${y}-${m}-${day}`;\n}\n\nexport function formatLocalTimestamp(d: Date): string {\n const y = d.getFullYear();\n const m = String(d.getMonth() + 1).padStart(2, \"0\");\n const day = String(d.getDate()).padStart(2, \"0\");\n const hh = String(d.getHours()).padStart(2, \"0\");\n const mm = String(d.getMinutes()).padStart(2, \"0\");\n const ss = String(d.getSeconds()).padStart(2, \"0\");\n const ms = String(d.getMilliseconds()).padStart(3, \"0\");\n\n const offsetMinutes = -d.getTimezoneOffset();\n const sign = offsetMinutes >= 0 ? \"+\" : \"-\";\n const absOffsetMinutes = Math.abs(offsetMinutes);\n const offsetHours = String(Math.floor(absOffsetMinutes / 60)).padStart(2, \"0\");\n const offsetMins = String(absOffsetMinutes % 60).padStart(2, \"0\");\n\n return `${y}-${m}-${day}T${hh}:${mm}:${ss}.${ms}${sign}${offsetHours}:${offsetMins}`;\n}\n","import { readFileSync } from \"node:fs\";\n\ndeclare const __PLUGIN_VERSION__: string | undefined;\n\ninterface PackageJson {\n version?: string;\n}\n\nfunction readBuildInjectedVersion(): string | undefined {\n if (typeof __PLUGIN_VERSION__ !== \"string\") {\n return undefined;\n }\n\n const version = __PLUGIN_VERSION__.trim();\n return version || undefined;\n}\n\nfunction readPluginVersionFromPackageJson(): string | undefined {\n try {\n const packageJsonUrl = new URL(\"../package.json\", import.meta.url);\n const packageJson = JSON.parse(\n readFileSync(packageJsonUrl, \"utf-8\"),\n ) as PackageJson;\n const version = packageJson.version?.trim();\n return version || undefined;\n } catch {\n return undefined;\n }\n}\n\nexport const PLUGIN_VERSION =\n readBuildInjectedVersion() ??\n readPluginVersionFromPackageJson() ??\n \"unknown\";\n","export interface RepeatConfig {\n repeat?: boolean;\n repeat_times?: number;\n}\n\nexport type RepeatArgument = RepeatConfig | boolean | number | undefined;\n\nexport function normalizeRepeatTimes(input?: RepeatArgument): number {\n if (typeof input === \"boolean\") {\n return input ? 0 : 1;\n }\n\n if (typeof input === \"number\") {\n return validateRepeatTimes(input);\n }\n\n if (!input) {\n return 1;\n }\n\n if (input.repeat_times !== undefined) {\n return validateRepeatTimes(input.repeat_times);\n }\n\n if (input.repeat !== undefined) {\n return input.repeat ? 0 : 1;\n }\n\n return 1;\n}\n\nexport function assertAncsRepeatTimes(repeatTimes: number): void {\n if (repeatTimes !== 0 && repeatTimes !== 1) {\n throw new Error(\n \"当前 ANCS 路径仅支持 repeat_times=0(无限循环)或 1(播放一轮);N>=2 需非 ANCS 路径\",\n );\n }\n}\n\nfunction validateRepeatTimes(value: number): number {\n if (!Number.isInteger(value) || value < 0) {\n throw new Error(\"repeat_times 必须是 >=0 的整数\");\n }\n\n return value;\n}\n","import { existsSync, readFileSync, readdirSync, mkdirSync } from \"node:fs\";\nimport { readdir, readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type { StoredNotification } from \"../notification/storage.js\";\n\n/**\n * Minimal Commander.js Command interface.\n * The real `Command` instance comes from the openclaw runtime at registration time;\n * we only declare the subset we use so that `commander` need not be a direct dep.\n */\nexport interface CliCommand {\n command(nameAndArgs: string): CliCommand;\n description(str: string): CliCommand;\n version(str: string, flags?: string, description?: string): CliCommand;\n option(flags: string, description: string, defaultValue?: string): CliCommand;\n requiredOption(flags: string, description: string): CliCommand;\n action(fn: (...args: any[]) => void | Promise<void>): CliCommand;\n}\n\nexport interface CliContext {\n workspaceDir?: string;\n stateDir?: string;\n}\n\n/** Resolve the notifications storage directory (stateDir → workspace fallback) */\nexport function resolveNotificationsDir(ctx: CliContext): string | null {\n if (ctx.stateDir) {\n const dir = join(\n ctx.stateDir,\n \"plugins\",\n \"phone-notifications\",\n \"notifications\",\n );\n if (existsSync(dir)) return dir;\n }\n if (ctx.workspaceDir) {\n const dir = join(ctx.workspaceDir, \"notifications\");\n if (existsSync(dir)) return dir;\n }\n return null;\n}\n\n/** List available date keys (YYYY-MM-DD) sorted descending */\nexport function listDateKeys(dir: string): string[] {\n const pattern = /^(\\d{4}-\\d{2}-\\d{2})\\.json$/;\n const keys: string[] = [];\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n if (!entry.isFile()) continue;\n const m = pattern.exec(entry.name);\n if (m) keys.push(m[1]);\n }\n return keys.sort().reverse();\n}\n\n/** Read notifications for a specific date */\nexport function readDateFile(\n dir: string,\n dateKey: string,\n): StoredNotification[] {\n const filePath = join(dir, `${dateKey}.json`);\n if (!existsSync(filePath)) return [];\n try {\n return JSON.parse(readFileSync(filePath, \"utf-8\"));\n } catch {\n return [];\n }\n}\n\n/** Format today as YYYY-MM-DD */\nexport function today(): string {\n return formatDate(new Date());\n}\n\n/** Format a Date as YYYY-MM-DD */\nexport function formatDate(d: Date): string {\n const y = d.getFullYear();\n const m = String(d.getMonth() + 1).padStart(2, \"0\");\n const day = String(d.getDate()).padStart(2, \"0\");\n return `${y}-${m}-${day}`;\n}\n\n/** Get date N days ago as YYYY-MM-DD */\nexport function daysAgo(n: number): string {\n const d = new Date();\n d.setDate(d.getDate() - n);\n return formatDate(d);\n}\n\n/** Filter date keys to a [from, to] range (inclusive) */\nexport function filterDateRange(\n keys: string[],\n from: string,\n to: string,\n): string[] {\n return keys.filter((k) => k >= from && k <= to);\n}\n\n/** Parse an ISO 8601 timestamp and exit with a CLI error on invalid input */\nexport function parseIsoTime(\n value: string,\n optionName: \"--from\" | \"--to\",\n): number {\n const isoPattern =\n /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}(?::\\d{2}(?:\\.\\d{1,3})?)?(Z|[+-]\\d{2}:\\d{2})$/;\n if (!isoPattern.test(value)) {\n exitError(\n \"INVALID_TIME\",\n `${optionName} 必须是 ISO 8601 时间,例如 2026-03-01T09:00:00+08:00`,\n );\n }\n\n const ts = Date.parse(value);\n if (Number.isNaN(ts)) {\n exitError(\n \"INVALID_TIME\",\n `${optionName} 不是合法时间,例如 2026-03-01T09:00:00+08:00`,\n );\n }\n return ts;\n}\n\n/** Sort notifications by timestamp descending (newest first) */\nexport function sortNotificationsByTimestampDesc(\n items: StoredNotification[],\n): StoredNotification[] {\n return items.sort((a, b) => Date.parse(b.timestamp) - Date.parse(a.timestamp));\n}\n\nconst APP_ALIAS_GROUPS = [\n [\"微信\", \"wechat\", \"weixin\", \"com.tencent.mm\", \"com.tencent.xin\"],\n [\"企业微信\", \"wecom\", \"wxwork\", \"com.tencent.wework\"],\n [\"飞书\", \"feishu\", \"lark\", \"com.ss.android.lark\", \"com.bytedance.ee.lark\", \"com.larksuite.suite\"],\n [\"钉钉\", \"dingtalk\", \"com.alibaba.android.rimet\"],\n [\"qq\", \"腾讯qq\", \"com.tencent.mobileqq\"],\n];\n\nfunction normalizeLookupText(value: string): string {\n return value.trim().toLowerCase();\n}\n\nfunction appAliasGroup(value: string): string[] | null {\n const normalized = normalizeLookupText(value);\n if (!normalized) return null;\n return APP_ALIAS_GROUPS.find((group) =>\n group.some((candidate) => normalizeLookupText(candidate) === normalized),\n ) ?? null;\n}\n\nexport function matchesNotificationAppFilter(\n item: StoredNotification,\n app: string,\n): boolean {\n const filter = normalizeLookupText(app);\n if (!filter) return true;\n\n const candidates = [item.appName, item.appDisplayName]\n .filter((value): value is string => typeof value === \"string\" && value.length > 0);\n if (candidates.some((candidate) => normalizeLookupText(candidate) === filter)) {\n return true;\n }\n\n const filterGroup = appAliasGroup(app);\n if (!filterGroup) return false;\n return candidates.some((candidate) => appAliasGroup(candidate) === filterGroup);\n}\n\n/** Async version of listDateKeys */\nexport async function listDateKeysAsync(dir: string): Promise<string[]> {\n const pattern = /^(\\d{4}-\\d{2}-\\d{2})\\.json$/;\n const keys: string[] = [];\n const entries = await readdir(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (!entry.isFile()) continue;\n const m = pattern.exec(entry.name);\n if (m) keys.push(m[1]);\n }\n return keys.sort().reverse();\n}\n\n/** Async version of readDateFile */\nexport async function readDateFileAsync(\n dir: string,\n dateKey: string,\n): Promise<StoredNotification[]> {\n const filePath = join(dir, `${dateKey}.json`);\n if (!existsSync(filePath)) return [];\n try {\n const content = await readFile(filePath, \"utf-8\");\n return JSON.parse(content);\n } catch {\n return [];\n }\n}\n\n/** Write progress message to stderr (visible to caller, won't pollute JSON stdout) */\nexport function progress(message: string): void {\n process.stderr.write(message + \"\\n\");\n}\n\n/** Print JSON result to stdout */\nexport function output(data: unknown): void {\n process.stdout.write(JSON.stringify(data, null, 2) + \"\\n\");\n}\n\n/** Print error JSON and exit with code 1 */\nexport function exitError(code: string, message: string): never {\n output({ ok: false, error: { code, message } });\n process.exit(1);\n}\n\n/** Resolve the recordings storage directory (stateDir → workspace fallback) */\nexport function resolveRecordingsDir(ctx: CliContext): string | null {\n if (ctx.stateDir) {\n const dir = join(\n ctx.stateDir,\n \"plugins\",\n \"phone-notifications\",\n \"recordings\",\n );\n if (existsSync(dir)) return dir;\n }\n if (ctx.workspaceDir) {\n const dir = join(ctx.workspaceDir, \"recordings\");\n if (existsSync(dir)) return dir;\n }\n return null;\n}\n\n/** Recording index entry (mirrors RecordingIndexEntry from storage.ts) */\nexport interface CliRecordingEntry {\n id: string;\n metadata: {\n name: string;\n duration_sec: number;\n file_size_bytes: number;\n created_at: string;\n transfer_status: string;\n [key: string]: unknown;\n };\n status: string;\n audioFile?: string;\n srtFile?: string;\n transcriptDataFile?: string;\n transcriptFile?: string;\n summaryFile?: string;\n title?: string;\n lastError?: string;\n ingestedAt: string;\n updatedAt: string;\n}\n\n/** Resolve the asr-config.json path; creates parent dirs if needed */\nexport function resolveAsrConfigPath(ctx: CliContext): string {\n let base: string;\n if (ctx.stateDir) {\n base = join(ctx.stateDir, \"plugins\", \"phone-notifications\", \"recordings\");\n } else if (ctx.workspaceDir) {\n base = join(ctx.workspaceDir, \"recordings\");\n } else {\n exitError(\n \"STORAGE_UNAVAILABLE\",\n \"无法确定录音存储目录:stateDir 和 workspaceDir 均未设置\",\n );\n }\n mkdirSync(base, { recursive: true });\n return join(base, \"asr-config.json\");\n}\n\n/** Mask an API key, keeping first 4 and last 4 chars */\nexport function maskApiKey(key: string): string {\n if (key.length <= 8) return \"***\";\n return `${key.slice(0, 4)}***${key.slice(-4)}`;\n}\n\n/** Read recording index.json */\nexport function readRecordingIndex(\n dir: string,\n): CliRecordingEntry[] {\n const indexPath = join(dir, \"index.json\");\n if (!existsSync(indexPath)) return [];\n try {\n const raw = JSON.parse(readFileSync(indexPath, \"utf-8\"));\n return Array.isArray(raw?.recordings) ? raw.recordings : [];\n } catch {\n return [];\n }\n}\n","import type { LightPixelFramePixel, LightSegment } from \"../types.js\";\nimport { output, exitError } from \"../cli/helpers.js\";\n\nexport const VALID_MODES = [\n \"wave\",\n \"breath\",\n \"strobe\",\n \"steady\",\n \"color_flow\",\n \"pixel_frame\",\n] as const;\nexport const MAX_SEGMENTS = 12;\n\nexport interface ValidationError {\n field: string;\n message: string;\n}\n\nexport interface ValidationWarning {\n field: string;\n code: string;\n message: string;\n}\n\nexport type ValidationResult =\n | { valid: true; segments: LightSegment[]; warnings: ValidationWarning[] }\n | { valid: false; errors: ValidationError[] };\n\nexport function validateSegments(segments: unknown): ValidationResult {\n if (!Array.isArray(segments)) {\n return { valid: false, errors: [{ field: \"segments\", message: \"必须是数组\" }] };\n }\n if (segments.length === 0) {\n return { valid: false, errors: [{ field: \"segments\", message: \"不能为空\" }] };\n }\n if (segments.length > MAX_SEGMENTS) {\n return {\n valid: false,\n errors: [{ field: \"segments\", message: `最多 ${MAX_SEGMENTS} 段` }],\n };\n }\n\n const errors: ValidationError[] = [];\n const warnings: ValidationWarning[] = [];\n for (let i = 0; i < segments.length; i++) {\n validateSegment(segments[i], `segments[${i}]`, errors, warnings);\n }\n\n if (errors.length > 0) return { valid: false, errors };\n return { valid: true, segments: segments as LightSegment[], warnings };\n}\n\n/**\n * 解析 JSON 字符串并校验 segments,失败时直接 exitError。\n * 适用于 CLI action 中的统一入口。\n */\nexport function parseAndValidateSegments(json: string): LightSegment[] {\n let parsed: unknown;\n try {\n parsed = JSON.parse(json);\n } catch {\n exitError(\"VALIDATION_FAILED\", \"segments 必须是合法的 JSON\");\n }\n\n const result = validateSegments(parsed);\n if (!result.valid) {\n output({ ok: false, error: { code: \"VALIDATION_FAILED\", details: result.errors } });\n process.exit(1);\n }\n\n return result.segments;\n}\n\nfunction validateSegment(\n seg: unknown,\n prefix: string,\n errors: ValidationError[],\n warnings: ValidationWarning[],\n): void {\n if (!isRecord(seg)) {\n errors.push({ field: prefix, message: \"必须是对象\" });\n return;\n }\n\n const mode = seg.mode;\n if (!VALID_MODES.includes(mode as (typeof VALID_MODES)[number])) {\n errors.push({\n field: `${prefix}.mode`,\n message: `不支持的模式 '${String(mode)}',可选:${VALID_MODES.join(\"/\")}`,\n });\n }\n\n validateNonNegativeNumber(seg.duration_s, `${prefix}.duration_s`, errors, \"必须是 ≥0 的数字(0 表示无限时长)\");\n\n switch (mode) {\n case \"wave\":\n validateForegroundSegment(seg, prefix, errors);\n validateOptionalNonNegativeNumber(seg.interval_ms, `${prefix}.interval_ms`, errors);\n validateOptionalDirection(seg.direction, `${prefix}.direction`, errors);\n validateOptionalWindow(seg.window, `${prefix}.window`, errors);\n validateOptionalBackground(seg.background, `${prefix}.background`, errors);\n break;\n case \"color_flow\":\n validateForegroundSegment(seg, prefix, errors);\n validateOptionalNonNegativeNumber(seg.interval_ms, `${prefix}.interval_ms`, errors);\n validateOptionalDirection(seg.direction, `${prefix}.direction`, errors);\n validateOptionalWindow(seg.window, `${prefix}.window`, errors);\n validateOptionalBackground(seg.background, `${prefix}.background`, errors);\n type RgbLike = Parameters<typeof hasNonZeroRgb>[0];\n if (!hasNonZeroRgb(seg.color as RgbLike) && !hasNonZeroRgb(seg.background as RgbLike)) {\n errors.push({\n field: prefix,\n message: \"color_flow 至少需要一组非零颜色锚点(color 或 background)\",\n });\n }\n detectColorFlowSingleAnchorMisuse(seg, prefix, warnings);\n break;\n case \"breath\":\n validateForegroundSegment(seg, prefix, errors);\n validateOptionalBreathTiming(seg.breath_timing, `${prefix}.breath_timing`, errors);\n break;\n case \"strobe\":\n validateForegroundSegment(seg, prefix, errors);\n validateOptionalNonNegativeNumber(seg.interval_ms, `${prefix}.interval_ms`, errors);\n break;\n case \"steady\":\n validateForegroundSegment(seg, prefix, errors);\n break;\n case \"pixel_frame\":\n validatePixelFrame(seg.pixels, `${prefix}.pixels`, errors);\n break;\n default:\n validateOptionalNonNegativeNumber(seg.brightness, `${prefix}.brightness`, errors);\n validateOptionalColor(seg.color, `${prefix}.color`, errors);\n validateOptionalNonNegativeNumber(seg.interval_ms, `${prefix}.interval_ms`, errors);\n validateOptionalDirection(seg.direction, `${prefix}.direction`, errors);\n validateOptionalWindow(seg.window, `${prefix}.window`, errors);\n validateOptionalBreathTiming(seg.breath_timing, `${prefix}.breath_timing`, errors);\n validateOptionalBackground(seg.background, `${prefix}.background`, errors);\n }\n}\n\nfunction validateForegroundSegment(\n seg: Record<string, unknown>,\n prefix: string,\n errors: ValidationError[],\n): void {\n validateNumberInRange(\n seg.brightness,\n `${prefix}.brightness`,\n errors,\n 0,\n 255,\n \"必须是 0–255 的数字\",\n );\n validateColor(seg.color, `${prefix}.color`, errors);\n\n if (seg.mode !== \"steady\" && seg.brightness === 0) {\n errors.push({\n field: `${prefix}.brightness`,\n message: \"brightness=0 仅 steady 模式允许;其它模式会在固件侧被过滤\",\n });\n }\n}\n\nfunction validatePixelFrame(\n value: unknown,\n field: string,\n errors: ValidationError[],\n): void {\n if (!Array.isArray(value)) {\n errors.push({ field, message: \"pixel_frame 必须提供 pixels 数组(1–7 项)\" });\n return;\n }\n\n if (value.length < 1 || value.length > 7) {\n errors.push({ field, message: \"pixels 必须为 1–7 项\" });\n }\n\n const seen = new Set<number>();\n for (let i = 0; i < value.length; i++) {\n const pixel = value[i];\n const prefix = `${field}[${i}]`;\n if (!isRecord(pixel)) {\n errors.push({ field: prefix, message: \"必须是对象\" });\n continue;\n }\n\n const idx = pixel.index;\n if (!Number.isInteger(idx) || (idx as number) < 0 || (idx as number) > 6) {\n errors.push({ field: `${prefix}.index`, message: \"index 必须是 0–6 的整数\" });\n } else if (seen.has(idx as number)) {\n errors.push({ field: `${prefix}.index`, message: `index=${idx} 重复` });\n } else {\n seen.add(idx as number);\n }\n\n validateNumberInRange(\n pixel.brightness,\n `${prefix}.brightness`,\n errors,\n 0,\n 255,\n \"必须是 0–255 的数字\",\n );\n validateColor(pixel.color, `${prefix}.color`, errors);\n }\n}\n\nfunction validateOptionalBreathTiming(\n value: unknown,\n field: string,\n errors: ValidationError[],\n): void {\n if (value === undefined) return;\n if (!isRecord(value)) {\n errors.push({ field, message: \"必须是对象\" });\n return;\n }\n\n validatePositiveNumber(\n value.rise_ms,\n `${field}.rise_ms`,\n errors,\n \"rise_ms 必须是 >0 的数字(不支持 0ms)\",\n );\n validateNonNegativeNumber(\n value.hold_ms,\n `${field}.hold_ms`,\n errors,\n \"hold_ms 必须是 ≥0 的数字\",\n );\n validatePositiveNumber(\n value.fall_ms,\n `${field}.fall_ms`,\n errors,\n \"fall_ms 必须是 >0 的数字(不支持 0ms)\",\n );\n validateNonNegativeNumber(\n value.off_ms,\n `${field}.off_ms`,\n errors,\n \"off_ms 必须是 ≥0 的数字\",\n );\n}\n\nfunction validateOptionalBackground(\n value: unknown,\n field: string,\n errors: ValidationError[],\n): void {\n if (value === undefined) return;\n if (!isRecord(value)) {\n errors.push({ field, message: \"必须包含 r/g/b/brightness 数值\" });\n return;\n }\n\n validateColor(value, field, errors);\n validateNumberInRange(\n value.brightness,\n `${field}.brightness`,\n errors,\n 0,\n 255,\n \"必须是 0–255 的数字\",\n );\n}\n\nfunction validateOptionalColor(\n value: unknown,\n field: string,\n errors: ValidationError[],\n): void {\n if (value === undefined) return;\n validateColor(value, field, errors);\n}\n\nfunction validateColor(\n value: unknown,\n field: string,\n errors: ValidationError[],\n): void {\n if (!isRecord(value)) {\n errors.push({ field, message: \"必须包含 r/g/b 数值\" });\n return;\n }\n\n validateNumberInRange(value.r, `${field}.r`, errors, 0, 255, \"必须是 0–255 的数字\");\n validateNumberInRange(value.g, `${field}.g`, errors, 0, 255, \"必须是 0–255 的数字\");\n validateNumberInRange(value.b, `${field}.b`, errors, 0, 255, \"必须是 0–255 的数字\");\n}\n\nfunction validateOptionalDirection(\n value: unknown,\n field: string,\n errors: ValidationError[],\n): void {\n if (value === undefined) return;\n if (value !== \"ltr\" && value !== \"rtl\") {\n errors.push({ field, message: \"direction 必须是 ltr 或 rtl\" });\n }\n}\n\nfunction validateOptionalWindow(\n value: unknown,\n field: string,\n errors: ValidationError[],\n): void {\n if (value === undefined) return;\n if (value !== 1 && value !== 2 && value !== 3) {\n errors.push({ field, message: \"window 仅支持 1/2/3\" });\n }\n}\n\nfunction validateOptionalNonNegativeNumber(\n value: unknown,\n field: string,\n errors: ValidationError[],\n): void {\n if (value === undefined) return;\n validateNonNegativeNumber(value, field, errors, \"必须是 ≥0 的数字\");\n}\n\nfunction validatePositiveNumber(\n value: unknown,\n field: string,\n errors: ValidationError[],\n message: string,\n): void {\n if (value === undefined) return;\n if (!isFiniteNumber(value) || value <= 0) {\n errors.push({ field, message });\n }\n}\n\nfunction validateNonNegativeNumber(\n value: unknown,\n field: string,\n errors: ValidationError[],\n message: string,\n): void {\n if (!isFiniteNumber(value) || value < 0) {\n errors.push({ field, message });\n }\n}\n\nfunction validateNumberInRange(\n value: unknown,\n field: string,\n errors: ValidationError[],\n min: number,\n max: number,\n message: string,\n): void {\n if (!isFiniteNumber(value) || value < min || value > max) {\n errors.push({ field, message });\n }\n}\n\nfunction hasNonZeroRgb(\n value: Pick<LightPixelFramePixel[\"color\"], \"r\" | \"g\" | \"b\"> | { r?: unknown; g?: unknown; b?: unknown } | undefined,\n): boolean {\n if (!value) return false;\n return [value.r, value.g, value.b].some((channel) => isFiniteNumber(channel) && channel > 0);\n}\n\n/**\n * color_flow 是「调色板沿圆周流动」,由 1~2 个颜色锚点插值得到。\n * 当用户/模型只给单一极端纯色锚点(如纯红 R=255、G=B=0)且没有底色锚点时,\n * 实际效果是「同色系亮暗环状流动」(红→暗红),而不是多色调色板流动。\n * 这是已知的 bug 模式(详见 imp-custom-led-ai-read.md「模式选择易错对照」):\n * 上层往往是把用户的\"单色波浪\"误映射到 color_flow,应该改用 wave 模式。\n * 此处不阻塞,只 push 一条 warning 让前端/审计可见。\n */\nfunction detectColorFlowSingleAnchorMisuse(\n seg: Record<string, unknown>,\n prefix: string,\n warnings: ValidationWarning[],\n): void {\n const color = seg.color as { r?: unknown; g?: unknown; b?: unknown } | undefined;\n const background = seg.background as\n | { r?: unknown; g?: unknown; b?: unknown; brightness?: unknown }\n | undefined;\n\n const fgChannels = extractChannels(color);\n const bgChannels = extractChannels(background);\n if (!fgChannels) return;\n\n const bgBrightnessRaw = background?.brightness;\n const bgBrightness = isFiniteNumber(bgBrightnessRaw) ? bgBrightnessRaw : 0;\n const bgActive = !!bgChannels && bgChannels.some((c) => c > 0) && bgBrightness > 0;\n if (bgActive) return;\n\n const fgActiveChannels = fgChannels.filter((c) => c > 0);\n if (fgActiveChannels.length !== 1) return;\n if (fgActiveChannels[0] < 192) return;\n\n warnings.push({\n field: prefix,\n code: \"COLOR_FLOW_SINGLE_ANCHOR_MISUSE\",\n message:\n \"color_flow 仅设置了单一极端纯色前景锚点(无有效底色锚点),实际效果是同色系亮暗环状流动,不是多色调色板流动。\" +\n \"若用户期望的是\\\"单色波浪\\\",请改用 mode='wave';若期望多色流动,请同时设置 background 作为第二锚点。\",\n });\n}\n\nfunction extractChannels(\n value: { r?: unknown; g?: unknown; b?: unknown } | undefined,\n): [number, number, number] | null {\n if (!value) return null;\n const r = isFiniteNumber(value.r) ? value.r : 0;\n const g = isFiniteNumber(value.g) ? value.g : 0;\n const b = isFiniteNumber(value.b) ? value.b : 0;\n return [r, g, b];\n}\n\nfunction isFiniteNumber(value: unknown): value is number {\n return typeof value === \"number\" && Number.isFinite(value);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n","export const LIGHT_RULE_GATEWAY_METHODS = {\n list: \"lightrules.list\",\n create: \"lightrules.create\",\n update: \"lightrules.update\",\n delete: \"lightrules.delete\",\n} as const;\n\nexport const LIGHT_RULE_GATEWAY_METHOD_LIST = [\n LIGHT_RULE_GATEWAY_METHODS.list,\n LIGHT_RULE_GATEWAY_METHODS.create,\n LIGHT_RULE_GATEWAY_METHODS.update,\n LIGHT_RULE_GATEWAY_METHODS.delete,\n] as const;\n\nexport const LIGHT_RULE_TOOL_NAMES = {\n list: \"lightrules_list\",\n create: \"lightrules_create\",\n update: \"lightrules_update\",\n delete: \"lightrules_delete\",\n} as const;\n\nexport const LIGHT_RULE_TOOL_NAME_LIST = [\n LIGHT_RULE_TOOL_NAMES.list,\n LIGHT_RULE_TOOL_NAMES.create,\n LIGHT_RULE_TOOL_NAMES.update,\n LIGHT_RULE_TOOL_NAMES.delete,\n] as const;\n","import {\n existsSync,\n mkdirSync,\n readFileSync,\n writeFileSync,\n rmSync,\n readdirSync,\n statSync,\n} from \"node:fs\";\nimport { basename, join } from \"node:path\";\nimport type { LightSegment } from \"../types.js\";\nimport type { LightRuleMeta } from \"./types.js\";\nimport { assertAncsRepeatTimes, normalizeRepeatTimes } from \"../light/repeat.js\";\n\nexport interface LightRuleStorageContext {\n workspaceDir?: string;\n stateDir?: string;\n}\n\nfunction resolveBaseDir(ctx: LightRuleStorageContext): string {\n if (ctx.workspaceDir) return ctx.workspaceDir;\n\n if (ctx.stateDir) {\n const inferredWorkspaceDir = join(ctx.stateDir, \"workspace\");\n if (existsSync(inferredWorkspaceDir)) return inferredWorkspaceDir;\n return ctx.stateDir;\n }\n\n throw new Error(\"workspaceDir and stateDir both unavailable\");\n}\n\nfunction tasksDir(ctx: LightRuleStorageContext): string {\n return join(resolveBaseDir(ctx), \"tasks\");\n}\n\nfunction normalizeLightRuleLookupName(name: string): string {\n return name.trim().replace(/\\.json$/i, \"\");\n}\n\nfunction resolveLightRuleTask(\n ctx: LightRuleStorageContext,\n name: string,\n): { taskDir: string; meta: LightRuleMeta } | null {\n const dir = tasksDir(ctx);\n const normalizedName = normalizeLightRuleLookupName(name);\n if (!normalizedName) return null;\n\n const directTaskDir = join(dir, normalizedName);\n const directMeta = readMeta(directTaskDir);\n if (directMeta) {\n return {\n taskDir: directTaskDir,\n meta: directMeta,\n };\n }\n\n if (!existsSync(dir)) return null;\n\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n\n const taskDir = join(dir, entry.name);\n const meta = readMeta(taskDir);\n if (meta?.name === normalizedName) {\n return {\n taskDir,\n meta,\n };\n }\n }\n\n return null;\n}\n\nfunction readOptionalString(value: unknown): string | undefined {\n if (typeof value !== \"string\") return undefined;\n const trimmed = value.trim();\n return trimmed || undefined;\n}\n\nfunction readMeta(taskDir: string): LightRuleMeta | null {\n const metaPath = join(taskDir, \"meta.json\");\n if (!existsSync(metaPath)) return null;\n try {\n const raw = JSON.parse(readFileSync(metaPath, \"utf-8\"));\n if (!raw || typeof raw !== \"object\" || Array.isArray(raw)) return null;\n if (raw.type !== \"light-rule\") return null;\n if (!Array.isArray(raw.segments)) return null;\n const name = readOptionalString(raw.name) ?? basename(taskDir);\n const title = readOptionalString(raw.title) ?? name;\n const description = readOptionalString(raw.description) ?? name;\n const createdAt =\n readOptionalString(raw.createdAt) ?? statSync(metaPath).birthtime.toISOString();\n const enabled = typeof raw.enabled === \"boolean\" ? raw.enabled : true;\n const repeatTimes = normalizeRepeatTimes({\n repeat: raw.repeat,\n repeat_times: raw.repeat_times,\n });\n assertAncsRepeatTimes(repeatTimes);\n return {\n ...raw,\n name,\n title,\n type: \"light-rule\",\n description,\n segments: raw.segments,\n repeat_times: repeatTimes,\n enabled,\n createdAt,\n } as LightRuleMeta;\n } catch {\n return null;\n }\n}\n\nfunction writeMeta(taskDir: string, meta: LightRuleMeta): void {\n writeFileSync(join(taskDir, \"meta.json\"), JSON.stringify(meta, null, 2), \"utf-8\");\n}\n\nexport function listLightRules(ctx: LightRuleStorageContext): LightRuleMeta[] {\n const dir = tasksDir(ctx);\n if (!existsSync(dir)) return [];\n\n const rules: LightRuleMeta[] = [];\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n const meta = readMeta(join(dir, entry.name));\n if (meta) rules.push(meta);\n }\n return rules;\n}\n\nexport function getLightRule(\n ctx: LightRuleStorageContext,\n name: string,\n): LightRuleMeta | null {\n return resolveLightRuleTask(ctx, name)?.meta ?? null;\n}\n\nexport function createLightRule(\n ctx: LightRuleStorageContext,\n params: {\n name: string;\n title: string;\n description: string;\n segments: LightSegment[];\n repeat_times?: number;\n repeat?: boolean;\n },\n): { meta: LightRuleMeta } {\n const dir = tasksDir(ctx);\n const taskDir = join(dir, params.name);\n\n if (existsSync(taskDir)) {\n throw new LightRuleError(\"ALREADY_EXISTS\", `灯效规则 '${params.name}' 已存在`);\n }\n\n mkdirSync(taskDir, { recursive: true });\n\n const repeatTimes = normalizeRepeatTimes({\n repeat: params.repeat,\n repeat_times: params.repeat_times,\n });\n assertAncsRepeatTimes(repeatTimes);\n\n const meta: LightRuleMeta = {\n name: params.name,\n title: params.title,\n type: \"light-rule\",\n description: params.description,\n segments: params.segments,\n repeat_times: repeatTimes,\n enabled: true,\n createdAt: new Date().toISOString(),\n };\n\n writeMeta(taskDir, meta);\n\n return { meta };\n}\n\nexport function updateLightRule(\n ctx: LightRuleStorageContext,\n params: {\n name: string;\n title?: string;\n description?: string;\n segments?: LightSegment[];\n repeat_times?: number;\n repeat?: boolean;\n enabled?: boolean;\n },\n): { meta: LightRuleMeta } {\n const resolved = resolveLightRuleTask(ctx, params.name);\n const taskDir = resolved?.taskDir;\n const meta = resolved?.meta;\n\n if (!taskDir || !meta) {\n throw new LightRuleError(\"NOT_FOUND\", `灯效规则 '${params.name}' 不存在`);\n }\n\n if (params.description !== undefined) {\n meta.description = params.description;\n }\n if (params.title !== undefined) {\n meta.title = params.title;\n }\n if (params.segments !== undefined) {\n meta.segments = params.segments;\n }\n if (params.repeat !== undefined || params.repeat_times !== undefined) {\n meta.repeat_times = normalizeRepeatTimes({\n repeat: params.repeat,\n repeat_times: params.repeat_times,\n });\n assertAncsRepeatTimes(meta.repeat_times);\n }\n if (params.enabled !== undefined) {\n meta.enabled = params.enabled;\n }\n\n meta.updatedAt = new Date().toISOString();\n writeMeta(taskDir, meta);\n\n return { meta };\n}\n\nexport function deleteLightRule(\n ctx: LightRuleStorageContext,\n name: string,\n): { name: string } {\n const resolved = resolveLightRuleTask(ctx, name);\n const taskDir = resolved?.taskDir;\n const meta = resolved?.meta;\n\n if (!taskDir || !meta) {\n throw new LightRuleError(\"NOT_FOUND\", `灯效规则 '${name}' 不存在`);\n }\n\n rmSync(taskDir, { recursive: true, force: true });\n\n return { name: meta.name };\n}\n\nexport class LightRuleError extends Error {\n constructor(\n public code: string,\n message: string,\n ) {\n super(message);\n this.name = \"LightRuleError\";\n }\n}\n","import type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport type { Logger } from \"../logger.js\";\nimport { assertAncsRepeatTimes, normalizeRepeatTimes } from \"../light/repeat.js\";\nimport { validateSegments } from \"../light/validators.js\";\nimport { LIGHT_RULE_GATEWAY_METHODS } from \"./names.js\";\nimport type { LightSegment } from \"../types.js\";\nimport type { BroadcastFn } from \"../update/types.js\";\nimport type {\n LightRuleCreateParams,\n LightRuleUpdateParams,\n LightRuleDeleteParams,\n} from \"./types.js\";\nimport { LightRuleError } from \"./storage.js\";\nimport type { LightRuleRegistry } from \"./registry.js\";\n\nfunction resolveRuleIdentifier(params: unknown): string | undefined {\n if (!params || typeof params !== \"object\") return undefined;\n\n const raw = params as Record<string, unknown>;\n const candidates = [raw.name, raw.id, raw.ruleId, raw.ruleName];\n for (const candidate of candidates) {\n if (typeof candidate !== \"string\") continue;\n const normalized = candidate.trim().replace(/\\.json$/i, \"\");\n if (normalized) return normalized;\n }\n\n return undefined;\n}\n\nexport function registerLightRulesGateway(\n api: OpenClawPluginApi,\n registry: LightRuleRegistry,\n logger: Pick<Logger, \"info\" | \"warn\">,\n rememberBroadcast?: (broadcast: BroadcastFn | undefined) => void,\n): void {\n type GatewayHandler = Parameters<OpenClawPluginApi[\"registerGatewayMethod\"]>[1];\n\n const registerGatewayMethodWithBroadcastCapture = (\n method: string,\n handler: GatewayHandler,\n ): void => {\n api.registerGatewayMethod(method, (opts) => {\n rememberBroadcast?.(opts.context?.broadcast);\n return handler(opts);\n });\n };\n\n // lightrules.list\n registerGatewayMethodWithBroadcastCapture(LIGHT_RULE_GATEWAY_METHODS.list, async ({ respond }) => {\n try {\n registry.reload();\n const rules = registry.list().map((rule) => ({\n ...rule,\n id: rule.name,\n }));\n respond(true, { ok: true, rules });\n } catch (err: any) {\n logger.warn(`${LIGHT_RULE_GATEWAY_METHODS.list} failed: ${err?.message}`);\n respond(false, null, {\n code: \"INTERNAL_ERROR\",\n message: err?.message ?? \"Unknown error\",\n });\n }\n });\n\n // lightrules.create\n registerGatewayMethodWithBroadcastCapture(\n LIGHT_RULE_GATEWAY_METHODS.create,\n async ({ params, respond }) => {\n const { name, title, description, segments, repeat, repeat_times } =\n params as unknown as LightRuleCreateParams;\n const resolvedTitle = typeof title === \"string\" && title.trim() ? title.trim() : name;\n\n if (!name || typeof name !== \"string\") {\n respond(false, null, { code: \"INVALID_PARAMS\", message: \"name is required\" });\n return;\n }\n if (!description || typeof description !== \"string\") {\n respond(false, null, { code: \"INVALID_PARAMS\", message: \"description is required\" });\n return;\n }\n\n const validation = validateSegments(segments);\n if (!validation.valid) {\n respond(false, null, {\n code: \"VALIDATION_FAILED\",\n message: JSON.stringify(validation.errors),\n });\n return;\n }\n\n let repeatTimes: number;\n try {\n repeatTimes = normalizeRepeatTimes({ repeat, repeat_times });\n assertAncsRepeatTimes(repeatTimes);\n } catch (err: any) {\n respond(false, null, {\n code: \"VALIDATION_FAILED\",\n message: err?.message ?? \"Unknown error\",\n });\n return;\n }\n\n try {\n const result = await registry.create({\n name,\n title: resolvedTitle,\n description,\n segments: validation.segments,\n repeat_times: repeatTimes,\n });\n logger.info(`Light rule created: ${name}`);\n respond(true, {\n ok: true,\n id: result.meta.name,\n name: result.meta.name,\n title: result.meta.title,\n rule: result.meta,\n });\n } catch (err: any) {\n if (err instanceof LightRuleError) {\n respond(false, null, { code: err.code, message: err.message });\n } else {\n logger.warn(`${LIGHT_RULE_GATEWAY_METHODS.create} failed: ${err?.message}`);\n respond(false, null, {\n code: \"INTERNAL_ERROR\",\n message: err?.message ?? \"Unknown error\",\n });\n }\n }\n },\n );\n\n // lightrules.update\n registerGatewayMethodWithBroadcastCapture(\n LIGHT_RULE_GATEWAY_METHODS.update,\n async ({ params, respond }) => {\n const { title, description, segments, repeat, repeat_times, enabled } =\n params as unknown as LightRuleUpdateParams;\n const name = resolveRuleIdentifier(params);\n const resolvedTitle = typeof title === \"string\" ? title.trim() : undefined;\n\n if (!name) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"name is required (or provide id/ruleId/ruleName)\",\n });\n return;\n }\n if (title !== undefined && !resolvedTitle) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"title must be a non-empty string\",\n });\n return;\n }\n if (description !== undefined && typeof description !== \"string\") {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"description must be a string\",\n });\n return;\n }\n\n let validatedSegments: LightSegment[] | undefined;\n if (segments !== undefined) {\n const validation = validateSegments(segments);\n if (!validation.valid) {\n respond(false, null, {\n code: \"VALIDATION_FAILED\",\n message: JSON.stringify(validation.errors),\n });\n return;\n }\n validatedSegments = validation.segments;\n }\n\n let repeatTimes: number | undefined;\n if (repeat !== undefined || repeat_times !== undefined) {\n try {\n repeatTimes = normalizeRepeatTimes({ repeat, repeat_times });\n assertAncsRepeatTimes(repeatTimes);\n } catch (err: any) {\n respond(false, null, {\n code: \"VALIDATION_FAILED\",\n message: err?.message ?? \"Unknown error\",\n });\n return;\n }\n }\n\n try {\n const result = await registry.update({\n name,\n title: resolvedTitle,\n description,\n segments: validatedSegments,\n repeat_times: repeatTimes,\n enabled,\n });\n logger.info(`Light rule updated: ${name}`);\n respond(true, {\n ok: true,\n id: result.meta.name,\n name: result.meta.name,\n title: result.meta.title,\n updated: true,\n rule: result.meta,\n });\n } catch (err: any) {\n if (err instanceof LightRuleError) {\n respond(false, null, { code: err.code, message: err.message });\n } else {\n logger.warn(`${LIGHT_RULE_GATEWAY_METHODS.update} failed: ${err?.message}`);\n respond(false, null, {\n code: \"INTERNAL_ERROR\",\n message: err?.message ?? \"Unknown error\",\n });\n }\n }\n },\n );\n\n // lightrules.delete\n registerGatewayMethodWithBroadcastCapture(\n LIGHT_RULE_GATEWAY_METHODS.delete,\n async ({ params, respond }) => {\n const name = resolveRuleIdentifier(params as unknown as LightRuleDeleteParams);\n\n if (!name) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"name is required (or provide id/ruleId/ruleName)\",\n });\n return;\n }\n try {\n const result = await registry.delete(name);\n logger.info(`Light rule deleted: ${result.name}`);\n respond(true, {\n ok: true,\n id: result.name,\n name: result.name,\n deleted: true,\n });\n } catch (err: any) {\n if (err instanceof LightRuleError) {\n respond(false, null, { code: err.code, message: err.message });\n } else {\n logger.warn(`${LIGHT_RULE_GATEWAY_METHODS.delete} failed: ${err?.message}`);\n respond(false, null, {\n code: \"INTERNAL_ERROR\",\n message: err?.message ?? \"Unknown error\",\n });\n }\n }\n },\n );\n}\n","/**\n * LightRuleRegistry —— 灯效规则的内存索引 + CRUD 包装\n *\n * 角色定位:\n * - 在事件驱动重构方案下,每条通知到达时都需要拿到\"当前 enabled 的全部规则\"\n * 用来拼装 Agent 的 system prompt。如果每次都扫盘 N 个 meta.json,\n * 5 秒延迟预算会被磨穿,所以引入这个常驻内存的 index。\n * - 同时它是 storage.ts 的 CRUD 包装:所有 create/update/delete 都会先落盘、\n * 再更新内存 Map,保证两者一致。\n *\n * 本类**不**做规则匹配 —— 匹配交给 Agent。registry 只负责\"有哪些规则\"和\n * \"按需拼装 prompt\"。\n *\n * 写路径用一个 promise 链做串行化(最朴素的 mutex),保证并发 CRUD\n * 不会出现\"内存和磁盘交错\"的状态。\n *\n * 见 prd-lightrules-event-driven-refactor.md §数据模型 / §触发流程\n */\n\nimport {\n createLightRule,\n deleteLightRule,\n listLightRules,\n updateLightRule,\n type LightRuleStorageContext,\n} from \"./storage.js\";\nimport type { LightRuleMeta } from \"./types.js\";\n\nexport { LightRuleError } from \"./storage.js\";\n\ntype CreateParams = Parameters<typeof createLightRule>[1];\ntype UpdateParams = Parameters<typeof updateLightRule>[1];\ntype CreateResult = ReturnType<typeof createLightRule>;\ntype UpdateResult = ReturnType<typeof updateLightRule>;\ntype DeleteResult = ReturnType<typeof deleteLightRule>;\n\nexport class LightRuleRegistry {\n private readonly ctx: LightRuleStorageContext;\n /** name → meta 的内存索引;落盘成功后才更新 */\n private readonly index = new Map<string, LightRuleMeta>();\n /** 写路径串行化锁:每次 mutate 都 chain 在前一次之后 */\n private writeChain: Promise<unknown> = Promise.resolve();\n\n constructor(ctx: LightRuleStorageContext) {\n this.ctx = ctx;\n this.reload();\n }\n\n /**\n * 从磁盘重新加载全部规则到内存。仅在构造时和外部显式触发时使用。\n * 正常 CRUD 路径不应该调用本方法 —— 通过 create/update/delete 增量维护即可。\n */\n reload(): void {\n this.index.clear();\n for (const meta of listLightRules(this.ctx)) {\n this.index.set(meta.name, meta);\n }\n }\n\n /** 全部规则(包含 disabled),调用方不要改返回值。 */\n list(): LightRuleMeta[] {\n return Array.from(this.index.values());\n }\n\n /** 仅 enabled 的规则。事件驱动评估链路使用。 */\n getEnabled(): LightRuleMeta[] {\n return this.list().filter((rule) => rule.enabled);\n }\n\n /** 按名字精确查找;不存在返回 null。 */\n get(name: string): LightRuleMeta | null {\n return this.index.get(name) ?? null;\n }\n\n /**\n * 创建规则。落盘成功后再写入内存索引。\n * 失败时 storage 抛 LightRuleError,内存索引保持不变。\n */\n async create(params: CreateParams): Promise<CreateResult> {\n return this.runExclusive(() => {\n const result = createLightRule(this.ctx, params);\n this.index.set(result.meta.name, result.meta);\n return result;\n });\n }\n\n /**\n * 更新规则。落盘成功后再刷新内存条目。\n */\n async update(params: UpdateParams): Promise<UpdateResult> {\n return this.runExclusive(() => {\n const result = updateLightRule(this.ctx, params);\n this.index.set(result.meta.name, result.meta);\n return result;\n });\n }\n\n /**\n * 删除规则。落盘成功后再从内存索引移除。\n */\n async delete(name: string): Promise<DeleteResult> {\n return this.runExclusive(() => {\n const result = deleteLightRule(this.ctx, name);\n this.index.delete(result.name);\n return result;\n });\n }\n\n /**\n * 拼装 Agent 评估用的 system prompt。\n *\n * 当前实现是一个最小可用骨架:列出全部 enabled 规则的 title + name + description。\n * M3 接入真实 Agent 链路时,会按 prd-lightrules-event-driven-refactor.md §Prompt 拼装\n * 的模板补齐\"任务说明 / 输出约束\"等段落。\n *\n * 现在先把方法签名冻结,避免后续散落在多个调用点。\n */\n buildSystemPrompt(): string {\n const enabled = this.getEnabled();\n if (enabled.length === 0) {\n return \"当前没有启用任何灯效规则。\";\n }\n\n const lines: string[] = [\n '你是一个判断\"通知 → 灯效规则\"是否命中的助手。',\n \"\",\n \"下面是用户当前启用的全部灯效规则(按创建时间倒序):\",\n \"\",\n ];\n\n const sorted = [...enabled].sort((a, b) =>\n (b.createdAt ?? \"\").localeCompare(a.createdAt ?? \"\"),\n );\n\n sorted.forEach((rule, idx) => {\n lines.push(\n `[${idx + 1}] title: ${rule.title}`,\n ` name: ${rule.name}`,\n ` description: ${rule.description}`,\n \"\",\n );\n });\n\n lines.push(\n '任务:根据用户接下来发给你的\"通知\"内容,判断哪些规则被命中。',\n \"- 命中 0 条:不调用任何工具,直接结束。\",\n \"- 命中 1 条或多条:对每一条命中的规则调用一次 trigger_light(rule_name)。\",\n \"- 不要回复任何自由文本;判定结果**只**通过 tool calling 表达。\",\n '- 拿不准的时候倾向于\"不触发\",避免骚扰用户。',\n );\n\n return lines.join(\"\\n\");\n }\n\n /**\n * 把一段同步操作排队进 write chain,保证 mutate 串行执行。\n *\n * 用 promise 链做 mutex 是最简单的方案:每次 runExclusive 都把\n * `writeChain` 推进一步。即使前一个任务失败,链也会继续往下走,\n * 后续任务不会被永久阻塞。\n */\n private runExclusive<T>(fn: () => T): Promise<T> {\n const next = this.writeChain.then(\n () => fn(),\n () => fn(),\n );\n // 不让链上的失败传播下去(已在 then 的 onRejected 回调里吸收)\n this.writeChain = next.catch(() => undefined);\n return next;\n }\n}\n","import type { LightSegment } from \"../types.js\";\nimport { assertAncsRepeatTimes, normalizeRepeatTimes, type RepeatArgument } from \"./repeat.js\";\nimport { validateSegments } from \"./validators.js\";\n\nexport const MAX_LIGHT_SEGMENTS = 12;\n\nconst PROTOCOL_DIGITS = [\n \"\\u0080\",\n \"\\u0081\",\n \"\\u0082\",\n \"\\u0083\",\n \"\\u0084\",\n \"\\u0091\",\n \"\\u0092\",\n \"\\u0093\",\n \"\\u0094\",\n \"\\u0095\",\n \"\\u0096\",\n \"\\u0097\",\n] as const;\n\n/** \\u009A = play once, \\u009B = infinite loop */\nconst LED_SEPARATOR_ONCE = \"\\u009A\";\nconst LED_SEPARATOR_LOOP = \"\\u009B\";\n\n/** v0–v10 mapped by index; duration_s=0 is special-cased to v11 (infinite) */\nconst DURATION_STEPS_S = [0.5, 1, 2, 3, 5, 6, 8, 16, 24, 32, 48] as const;\n/** v0–v10 mapped by index; removed 400ms, added 50ms */\nconst INTERVAL_STEPS_MS = [50, 100, 200, 300, 500, 600, 800, 1600, 2400, 3200, 4800] as const;\nconst BREATH_STEPS_MS = [1040, 1560, 2080, 2600, 3100, 4160] as const;\nconst BRIGHTNESS_STEPS = [32, 64, 96, 128, 192, 255] as const;\nconst COLOR_STEPS = [0, 32, 64, 128, 192, 255] as const;\nconst BACKGROUND_BRIGHTNESS_STEPS = [0, 32, 64, 96, 128, 192, 255] as const;\nconst MULTI_CHANNEL_COLOR_COEFFICIENTS = { r: 1, g: 0.25, b: 0.25 } as const;\nconst PURE_WHITE_COLOR_COEFFICIENTS = { r: 1, g: 0.35, b: 0.35 } as const;\n\n/**\n * mode → wire-protocol M value.\n * color_flow encodes to M=v4 (firmware enum APP_LED_CUSTOM_MODE_WAVE_RAINBOW).\n * \"WAVE_RAINBOW\" is a legacy firmware name and does NOT imply rainbow/multi-color semantics;\n * the TS-side enum uses color_flow to avoid that confusion. See imp-custom-led-ai-read.md\n * \"模式选择易错对照\" for the mapping rules.\n */\nconst MODE_TO_INDEX: Record<LightSegment[\"mode\"], number> = {\n wave: 0,\n breath: 1,\n strobe: 2,\n steady: 3,\n color_flow: 4,\n pixel_frame: 5,\n};\n\nexport function buildLightEffectApnsBody(\n segments: LightSegment[],\n repeatInput?: RepeatArgument,\n visibleTextOverride?: string,\n): string {\n assertSegmentCount(segments);\n assertSegmentsValid(segments);\n\n const repeatTimes = normalizeRepeatTimes(repeatInput);\n assertAncsRepeatTimes(repeatTimes);\n\n const visibleText = resolveVisibleText(visibleTextOverride, segments);\n const separator = repeatTimes === 0 ? LED_SEPARATOR_LOOP : LED_SEPARATOR_ONCE;\n const payload = segments.map((segment) => encodeSegment(segment)).join(\"\");\n return `${visibleText}${separator}${payload}`;\n}\n\nfunction resolveVisibleText(\n override: string | undefined,\n segments: LightSegment[],\n): string {\n const trimmed = override?.trim();\n if (trimmed) return trimmed;\n return summarizeSegments(segments);\n}\n\nfunction assertSegmentCount(segments: LightSegment[]): void {\n if (segments.length < 1 || segments.length > MAX_LIGHT_SEGMENTS) {\n throw new Error(`light_control supports 1-${MAX_LIGHT_SEGMENTS} segments`);\n }\n}\n\nfunction summarizeSegments(segments: LightSegment[]): string {\n const modeDesc = segments.map((segment) => segment.mode).join(\"+\");\n return `Effect: ${modeDesc} (${segments.length} segment${segments.length > 1 ? \"s\" : \"\"})`;\n}\n\nfunction assertSegmentsValid(segments: LightSegment[]): void {\n const validation = validateSegments(segments);\n if (!validation.valid) {\n throw new Error(\n validation.errors.map((error) => `${error.field}: ${error.message}`).join(\"; \"),\n );\n }\n}\n\nfunction encodeSegment(segment: LightSegment): string {\n const common = [\n MODE_TO_INDEX[segment.mode],\n quantizeDuration(segment.duration_s),\n ];\n\n let values: number[];\n switch (segment.mode) {\n case \"wave\":\n case \"color_flow\":\n const color = normalizeProtocolColor(segment.color);\n const background = normalizeProtocolColor(segment.background);\n values = [\n ...common,\n quantize(segment.interval_ms ?? 200, INTERVAL_STEPS_MS),\n quantizeBrightnessValue(segment.brightness ?? 0),\n quantize(color.r, COLOR_STEPS),\n quantize(color.g, COLOR_STEPS),\n quantize(color.b, COLOR_STEPS),\n segment.direction === \"rtl\" ? 1 : 0,\n quantizeWindow(segment.window ?? 2),\n quantize(background.r, COLOR_STEPS),\n quantize(background.g, COLOR_STEPS),\n quantize(background.b, COLOR_STEPS),\n quantize(segment.background?.brightness ?? 0, BACKGROUND_BRIGHTNESS_STEPS),\n ];\n break;\n case \"breath\":\n const breathColor = normalizeProtocolColor(segment.color);\n values = [\n ...common,\n quantizeBreathRiseFall(segment.breath_timing?.rise_ms),\n quantizeBreathHoldOff(segment.breath_timing?.hold_ms),\n quantizeBreathRiseFall(segment.breath_timing?.fall_ms),\n quantizeBreathHoldOff(segment.breath_timing?.off_ms),\n quantizeBrightnessValue(segment.brightness ?? 0),\n quantize(breathColor.r, COLOR_STEPS),\n quantize(breathColor.g, COLOR_STEPS),\n quantize(breathColor.b, COLOR_STEPS),\n ];\n break;\n case \"strobe\":\n const strobeColor = normalizeProtocolColor(segment.color);\n values = [\n ...common,\n quantize(segment.interval_ms ?? 200, INTERVAL_STEPS_MS),\n quantizeBrightnessValue(segment.brightness ?? 0),\n quantize(strobeColor.r, COLOR_STEPS),\n quantize(strobeColor.g, COLOR_STEPS),\n quantize(strobeColor.b, COLOR_STEPS),\n ];\n break;\n case \"steady\":\n const steadyColor = normalizeProtocolColor(segment.color);\n values = [\n ...common,\n quantizeBrightnessValue(segment.brightness ?? 0),\n quantize(steadyColor.r, COLOR_STEPS),\n quantize(steadyColor.g, COLOR_STEPS),\n quantize(steadyColor.b, COLOR_STEPS),\n ];\n break;\n case \"pixel_frame\":\n values = encodePixelFrameValues(common, segment);\n break;\n }\n\n return values.map((value) => PROTOCOL_DIGITS[value]).join(\"\");\n}\n\nfunction encodePixelFrameValues(common: number[], segment: LightSegment): number[] {\n const pixels = segment.pixels ?? [];\n return [\n ...common,\n pixels.length - 1,\n ...pixels.flatMap((pixel) => {\n const color = normalizeProtocolColor(pixel.color);\n return [\n pixel.index,\n quantize(color.r, COLOR_STEPS),\n quantize(color.g, COLOR_STEPS),\n quantize(color.b, COLOR_STEPS),\n quantizeBrightnessValue(pixel.brightness),\n ];\n }),\n ];\n}\n\nexport function normalizeProtocolColor(\n color:\n | Pick<NonNullable<LightSegment[\"color\"]>, \"r\" | \"g\" | \"b\">\n | Pick<NonNullable<LightSegment[\"background\"]>, \"r\" | \"g\" | \"b\">\n | undefined,\n): { r: number; g: number; b: number } {\n const normalized = {\n r: color?.r ?? 0,\n g: color?.g ?? 0,\n b: color?.b ?? 0,\n };\n\n if (isPureWhiteProtocolColor(normalized)) {\n return applyProtocolColorCoefficients(normalized, PURE_WHITE_COLOR_COEFFICIENTS);\n }\n\n if (countActiveProtocolColorChannels(normalized) <= 1) {\n return normalized;\n }\n\n return applyProtocolColorCoefficients(normalized, MULTI_CHANNEL_COLOR_COEFFICIENTS);\n}\n\nfunction countActiveProtocolColorChannels(color: { r: number; g: number; b: number }): number {\n return Number(color.r > 0) + Number(color.g > 0) + Number(color.b > 0);\n}\n\nfunction isPureWhiteProtocolColor(color: { r: number; g: number; b: number }): boolean {\n return color.r === 255 && color.g === 255 && color.b === 255;\n}\n\nfunction applyProtocolColorCoefficients(\n color: { r: number; g: number; b: number },\n coefficients: { r: number; g: number; b: number },\n): { r: number; g: number; b: number } {\n return {\n r: scaleProtocolColorChannel(color.r, coefficients.r),\n g: scaleProtocolColorChannel(color.g, coefficients.g),\n b: scaleProtocolColorChannel(color.b, coefficients.b),\n };\n}\n\nfunction scaleProtocolColorChannel(value: number, coefficient: number): number {\n return Math.max(0, Math.min(255, Math.round(value * coefficient)));\n}\n\nfunction quantize(value: number, steps: readonly number[]): number {\n let bestIndex = 0;\n let bestDistance = Number.POSITIVE_INFINITY;\n\n for (const [index, step] of steps.entries()) {\n const distance = Math.abs(value - step);\n if (distance < bestDistance) {\n bestIndex = index;\n bestDistance = distance;\n }\n }\n\n return bestIndex;\n}\n\n/** duration_s=0 maps to v11 (infinite); otherwise quantize to DURATION_STEPS_S */\nfunction quantizeDuration(duration_s: number): number {\n if (duration_s === 0) return 11;\n return quantize(duration_s, DURATION_STEPS_S);\n}\n\n/**\n * brightness=0 maps to v11 (explicit off / pixel-off).\n * Otherwise quantize to BRIGHTNESS_STEPS (v0–v5).\n */\nfunction quantizeBrightnessValue(brightness: number): number {\n if (brightness === 0) return 11;\n return quantize(brightness, BRIGHTNESS_STEPS);\n}\n\nfunction quantizeBreathRiseFall(value: number | undefined): number {\n return quantize(value ?? 1040, BREATH_STEPS_MS);\n}\n\nfunction quantizeBreathHoldOff(value: number | undefined): number {\n if (value === 0) {\n return 5;\n }\n\n return quantize(value ?? 1040, BREATH_STEPS_MS.slice(0, 5));\n}\n\nfunction quantizeWindow(value: 1 | 2 | 3): number {\n return value - 1;\n}\n","import type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport type { Logger } from \"../logger.js\";\nimport { assertAncsRepeatTimes, normalizeRepeatTimes } from \"../light/repeat.js\";\nimport { validateSegments, type ValidationWarning } from \"../light/validators.js\";\nimport { LightRuleError } from \"../light-rules/registry.js\";\nimport { LIGHT_RULE_TOOL_NAMES } from \"../light-rules/names.js\";\nimport type { LightRuleRegistry } from \"../light-rules/registry.js\";\nimport type { LightRuleCreateParams, LightRuleUpdateParams } from \"../light-rules/types.js\";\nimport { MAX_LIGHT_SEGMENTS } from \"../light/protocol.js\";\n\nconst segmentItemSchema = {\n type: \"object\",\n required: [\"mode\", \"duration_s\"],\n additionalProperties: false,\n properties: {\n mode: {\n type: \"string\",\n enum: [\"wave\", \"breath\", \"strobe\", \"steady\", \"color_flow\", \"pixel_frame\"],\n description:\n \"灯效模式:wave 波浪(单色跑马)/ breath 呼吸 / strobe 频闪 / steady 常亮 / \" +\n \"color_flow 流光(1~2 锚点调色板流动;**不是彩虹**,无法生成 7 色彩虹波浪)/ \" +\n \"pixel_frame 逐组像素帧。\" +\n \"易错对照:用户说\\\"红色/蓝色波浪\\\"等单一颜色波浪 → 必须用 wave;用户说\\\"彩虹/七彩/rainbow\\\" → 固件不支持,需告知限制。\",\n },\n duration_s: { type: \"number\", minimum: 0, description: \"持续时长(秒),0 表示无限\" },\n brightness: { type: \"number\", minimum: 0, maximum: 255 },\n color: {\n type: \"object\",\n required: [\"r\", \"g\", \"b\"],\n additionalProperties: false,\n properties: {\n r: { type: \"number\", minimum: 0, maximum: 255 },\n g: { type: \"number\", minimum: 0, maximum: 255 },\n b: { type: \"number\", minimum: 0, maximum: 255 },\n },\n },\n interval_ms: { type: \"number\", minimum: 0 },\n direction: { type: \"string\", enum: [\"ltr\", \"rtl\"] },\n window: { type: \"number\", enum: [1, 2, 3] },\n breath_timing: {\n type: \"object\",\n additionalProperties: false,\n properties: {\n rise_ms: { type: \"number\", minimum: 0 },\n hold_ms: { type: \"number\", minimum: 0 },\n fall_ms: { type: \"number\", minimum: 0 },\n off_ms: { type: \"number\", minimum: 0 },\n },\n },\n frames: { type: \"array\", items: { type: \"array\", items: { type: \"number\" } } },\n frame_duration_ms: { type: \"number\", minimum: 0 },\n background: {\n type: \"object\",\n required: [\"r\", \"g\", \"b\"],\n additionalProperties: false,\n properties: {\n r: { type: \"number\", minimum: 0, maximum: 255 },\n g: { type: \"number\", minimum: 0, maximum: 255 },\n b: { type: \"number\", minimum: 0, maximum: 255 },\n },\n },\n },\n} as const;\n\nconst segmentsSchema = {\n type: \"array\",\n description: \"灯效段序列,1–12 段,按顺序播放\",\n minItems: 1,\n maxItems: MAX_LIGHT_SEGMENTS,\n items: segmentItemSchema,\n} as const;\n\nfunction ok(data: object): { content: [{ type: \"text\"; text: string }]; details: object } {\n return { content: [{ type: \"text\" as const, text: JSON.stringify(data) }], details: data };\n}\n\nfunction err(\n code: string,\n message: string,\n): { content: [{ type: \"text\"; text: string }]; details: object } {\n const data = { ok: false, error: { code, message } };\n return { content: [{ type: \"text\" as const, text: JSON.stringify(data) }], details: data };\n}\n\nexport function registerLightRulesTools(\n api: OpenClawPluginApi,\n registry: LightRuleRegistry,\n logger: Pick<Logger, \"info\" | \"warn\">,\n): void {\n // lightrules_list\n api.registerTool({\n name: LIGHT_RULE_TOOL_NAMES.list,\n label: \"List Light Rules\",\n description:\n '列出所有灯效规则(包含 enabled/disabled 状态)。当用户说\"列出灯效规则\"、\"有哪些灯效规则\"、\"查看规则\"等时调用。' +\n \"注意:灯效规则的所有 CRUD 操作必须通过 lightrules_* 工具完成,禁止直接用 write/edit 修改 tasks/*/meta.json。\",\n parameters: { type: \"object\", properties: {}, additionalProperties: false },\n async execute(_toolCallId, _params) {\n try {\n registry.reload();\n const rules = registry.list().map((rule) => ({ ...rule, id: rule.name }));\n return ok({ ok: true, rules });\n } catch (e: any) {\n logger.warn(`${LIGHT_RULE_TOOL_NAMES.list} tool failed: ${e?.message}`);\n return err(\"INTERNAL_ERROR\", e?.message ?? \"Unknown error\");\n }\n },\n });\n\n // lightrules_create\n api.registerTool({\n name: LIGHT_RULE_TOOL_NAMES.create,\n label: \"Create Light Rule\",\n description:\n '创建一条持久灯效规则,指定内部标识 name、展示名 title、自然语言触发描述和灯效参数。规则会保存到 tasks/<name>/meta.json,并由通知到达后的事件驱动评估触发。' +\n '当用户说\"收到某类通知/消息时亮灯/闪灯/变灯效\"、\"当老板发消息亮红灯\"、\"新增/创建灯效规则\"等时调用。' +\n \"不要直接调用 light_control 代替创建规则;light_control 只会立即亮一次灯,不会出现在灯效规则查询中。\",\n parameters: {\n type: \"object\",\n required: [\"name\", \"title\", \"description\", \"segments\"],\n additionalProperties: false,\n properties: {\n name: {\n type: \"string\",\n description: \"规则的内部唯一标识符(英文 slug,如 red_light_on_wechat)\",\n },\n title: {\n type: \"string\",\n description:\n \"规则的展示名/短标题,应是对 description 的总结凝练,例如“老板微信红灯”\",\n },\n description: {\n type: \"string\",\n description:\n \"自然语言触发条件,同时作为规则用途说明。Agent 按此字段判断是否命中,必须清晰描述「何时触发」\",\n },\n segments: segmentsSchema,\n repeat_times: {\n type: \"number\",\n description: \"整条灯效序列重复次数,0=无限循环,1=播放一次(默认)\",\n },\n },\n },\n async execute(_toolCallId, params) {\n const { name, title, description, segments, repeat_times } =\n params as LightRuleCreateParams;\n const resolvedTitle = typeof title === \"string\" && title.trim() ? title.trim() : name;\n\n if (!name || typeof name !== \"string\")\n return err(\"INVALID_PARAMS\", \"name is required\");\n if (!description || typeof description !== \"string\")\n return err(\"INVALID_PARAMS\", \"description is required\");\n\n const validation = validateSegments(segments);\n if (!validation.valid) return err(\"VALIDATION_FAILED\", JSON.stringify(validation.errors));\n\n let repeatTimes: number;\n try {\n repeatTimes = normalizeRepeatTimes({ repeat_times });\n assertAncsRepeatTimes(repeatTimes);\n } catch (e: any) {\n return err(\"VALIDATION_FAILED\", e?.message ?? \"Unknown error\");\n }\n\n try {\n const result = await registry.create({\n name,\n title: resolvedTitle,\n description,\n segments: validation.segments,\n repeat_times: repeatTimes,\n });\n logger.info(`${LIGHT_RULE_TOOL_NAMES.create} tool: created ${name}`);\n for (const warning of validation.warnings) {\n logger.warn(\n `${LIGHT_RULE_TOOL_NAMES.create} validation warning [${warning.code}] ${warning.field}: ${warning.message}`,\n );\n }\n return ok({\n ok: true,\n id: result.meta.name,\n name: result.meta.name,\n title: result.meta.title,\n rule: result.meta,\n ...(validation.warnings.length > 0 ? { warnings: validation.warnings } : {}),\n });\n } catch (e: any) {\n if (e instanceof LightRuleError) return err(e.code, e.message);\n logger.warn(`${LIGHT_RULE_TOOL_NAMES.create} tool failed: ${e?.message}`);\n return err(\"INTERNAL_ERROR\", e?.message ?? \"Unknown error\");\n }\n },\n });\n\n // lightrules_update\n api.registerTool({\n name: LIGHT_RULE_TOOL_NAMES.update,\n label: \"Update Light Rule\",\n description:\n '修改灯效规则(启用/禁用、改 title、改描述、改灯效参数)。当用户说\"禁用某条规则\"、\"启用规则\"、\"修改灯效规则\"等时调用。' +\n \"必须传入要修改的规则标识 name;如果只知道展示名、序号或不确定 name,先调用 lightrules_list 获取规则列表后再更新。\",\n parameters: {\n type: \"object\",\n required: [\"name\"],\n additionalProperties: false,\n properties: {\n name: { type: \"string\", description: \"要修改的规则名称(唯一标识符)\" },\n title: {\n type: \"string\",\n description: \"新的展示名/短标题(可选)\",\n },\n description: { type: \"string\", description: \"新的触发条件描述(可选)\" },\n enabled: { type: \"boolean\", description: \"true=启用,false=禁用\" },\n segments: { ...segmentsSchema, description: \"新的灯效段序列(可选,不填则保持不变)\" },\n repeat_times: { type: \"number\", description: \"新的重复次数(可选)\" },\n },\n },\n async execute(_toolCallId, params) {\n const { name, title, description, enabled, segments, repeat_times } =\n params as LightRuleUpdateParams;\n const resolvedTitle = typeof title === \"string\" ? title.trim() : undefined;\n\n if (!name || typeof name !== \"string\")\n return err(\n \"INVALID_PARAMS\",\n \"name is required; call lightrules_list first if you do not know the rule name\",\n );\n if (title !== undefined && !resolvedTitle)\n return err(\"INVALID_PARAMS\", \"title must be a non-empty string\");\n if (description !== undefined && typeof description !== \"string\")\n return err(\"INVALID_PARAMS\", \"description must be a string\");\n\n let validatedSegments;\n let segmentWarnings: ValidationWarning[] = [];\n if (segments !== undefined) {\n const validation = validateSegments(segments);\n if (!validation.valid) return err(\"VALIDATION_FAILED\", JSON.stringify(validation.errors));\n validatedSegments = validation.segments;\n segmentWarnings = validation.warnings;\n }\n\n let repeatTimes: number | undefined;\n if (repeat_times !== undefined) {\n try {\n repeatTimes = normalizeRepeatTimes({ repeat_times });\n assertAncsRepeatTimes(repeatTimes);\n } catch (e: any) {\n return err(\"VALIDATION_FAILED\", e?.message ?? \"Unknown error\");\n }\n }\n\n try {\n const result = await registry.update({\n name,\n title: resolvedTitle,\n description,\n segments: validatedSegments,\n repeat_times: repeatTimes,\n enabled,\n });\n logger.info(`${LIGHT_RULE_TOOL_NAMES.update} tool: updated ${name}`);\n for (const warning of segmentWarnings) {\n logger.warn(\n `${LIGHT_RULE_TOOL_NAMES.update} validation warning [${warning.code}] ${warning.field}: ${warning.message}`,\n );\n }\n return ok({\n ok: true,\n name: result.meta.name,\n title: result.meta.title,\n updated: true,\n rule: result.meta,\n ...(segmentWarnings.length > 0 ? { warnings: segmentWarnings } : {}),\n });\n } catch (e: any) {\n if (e instanceof LightRuleError) return err(e.code, e.message);\n logger.warn(`${LIGHT_RULE_TOOL_NAMES.update} tool failed: ${e?.message}`);\n return err(\"INTERNAL_ERROR\", e?.message ?? \"Unknown error\");\n }\n },\n });\n\n // lightrules_delete\n api.registerTool({\n name: LIGHT_RULE_TOOL_NAMES.delete,\n label: \"Delete Light Rule\",\n description:\n '删除一条灯效规则(不可恢复)。当用户说\"删除灯效规则\"、\"移除规则\"等时调用。',\n parameters: {\n type: \"object\",\n required: [\"name\"],\n additionalProperties: false,\n properties: {\n name: { type: \"string\", description: \"要删除的规则名称\" },\n },\n },\n async execute(_toolCallId, params) {\n const { name } = params as { name: string };\n\n if (!name || typeof name !== \"string\")\n return err(\"INVALID_PARAMS\", \"name is required\");\n\n try {\n const result = await registry.delete(name);\n logger.info(`${LIGHT_RULE_TOOL_NAMES.delete} tool: deleted ${name}`);\n return ok({ ok: true, name: result.name, deleted: true });\n } catch (e: any) {\n if (e instanceof LightRuleError) return err(e.code, e.message);\n logger.warn(`${LIGHT_RULE_TOOL_NAMES.delete} tool failed: ${e?.message}`);\n return err(\"INTERNAL_ERROR\", e?.message ?? \"Unknown error\");\n }\n },\n });\n}\n","/**\n * InlineLightRuleEvaluator —— 进程内灯效规则评估器\n *\n * 事件驱动重构的\"轻量路径\"实现:收到一批新通知后,通过 PiAiInvoker 做一次\n * LLM 匹配,再对命中的规则直接调用 `sendLightEffect`。全流程在插件进程内\n * 完成,不走 cron job / subagent session / agent turn。\n *\n * 与旧路径的关键差异:\n * - 旧:每条通知 → 一次完整 OpenClaw agent session(高 overhead + 贵模型)\n * - 新:每批通知 → 一次 Haiku complete()(数百 token 输入 / 数十 token 输出)\n *\n * 返回值语义:\n * - true:评估链路完整跑完(可能 0 命中、可能触发了 N 次灯效)\n * - false:invoker 调用失败,调用方据此决定是否回退 legacy 路径\n */\n\nimport { requireApiKey } from \"../auth/credentials.js\";\nimport { sendLightEffect } from \"../light/sender.js\";\nimport type { Logger } from \"../logger.js\";\nimport type { StoredNotification } from \"../notification/storage.js\";\nimport type { LightRuleEvaluationTrace } from \"./evaluation-scheduler.js\";\nimport type { PiAiInvoker } from \"./pi-invoker.js\";\nimport type { LightRuleRegistry } from \"./registry.js\";\nimport type { LightRuleMeta } from \"./types.js\";\n\nexport class InlineLightRuleEvaluator {\n private readonly logger: Pick<Logger, \"info\" | \"warn\">;\n private readonly registry: LightRuleRegistry;\n private readonly invoker: PiAiInvoker;\n\n constructor(deps: {\n logger: Pick<Logger, \"info\" | \"warn\">;\n registry: LightRuleRegistry;\n invoker: PiAiInvoker;\n }) {\n this.logger = deps.logger;\n this.registry = deps.registry;\n this.invoker = deps.invoker;\n }\n\n /**\n * 评估一批新通知。\n *\n * @returns true 表示评估流程正常结束;false 表示 invoker 失败,调用方可选择回退。\n */\n async evaluate(\n notifications: StoredNotification[],\n trace?: LightRuleEvaluationTrace,\n ): Promise<boolean> {\n if (notifications.length === 0) return true;\n\n const traceTag = trace?.flushId ?? \"flush_none\";\n\n this.reloadRegistry(\"before evaluation\", traceTag);\n const rules = this.registry.getEnabled();\n if (rules.length === 0) {\n this.logger.info(\n `lightrules[${traceTag}]: no enabled rules (notifications=${notifications.length})`,\n );\n return true;\n }\n\n this.logger.info(\n `lightrules[${traceTag}]: evaluating notifications=${notifications.length} rules=${rules.length}`,\n );\n\n const matchStartedAtMs = Date.now();\n const matches = await this.invoker.matchNotifications(\n notifications,\n rules,\n trace?.flushId,\n );\n const matchElapsedMs = Date.now() - matchStartedAtMs;\n if (matches === null) {\n this.logger.warn(\n `lightrules[${traceTag}]: match failed (notifications=${notifications.length}, rules=${rules.length}, elapsedMs=${matchElapsedMs})`,\n );\n return false;\n }\n\n if (matches.length === 0) {\n this.logger.info(\n `lightrules[${traceTag}]: 0 matches (notifications=${notifications.length}, rules=${rules.length}, elapsedMs=${matchElapsedMs})`,\n );\n return true;\n }\n\n this.logger.info(\n `lightrules[${traceTag}]: matched ${matches.length} hit(s) in ${matchElapsedMs}ms`,\n );\n\n // 同一批里同一条规则只触发一次:多条通知撞同一个规则,按\"一次提醒\"处理,\n // 避免灯效反复抢占,且节省下游 HTTP 调用。\n const firedRules = new Set<string>();\n this.reloadRegistry(\"before triggering\", traceTag);\n for (const match of matches) {\n if (firedRules.has(match.ruleName)) continue;\n const rule = this.registry.get(match.ruleName);\n if (!rule) {\n this.logger.warn(\n `lightrules[${traceTag}]: matched rule '${match.ruleName}' skipped - not found after reload`,\n );\n continue;\n }\n if (!rule.enabled) {\n this.logger.info(\n `lightrules[${traceTag}]: matched rule '${match.ruleName}' skipped - disabled after reload`,\n );\n continue;\n }\n firedRules.add(match.ruleName);\n const notification = notifications[match.notificationIndex];\n await this.triggerLight(rule, notification, traceTag);\n }\n\n this.logger.info(\n `lightrules[${traceTag}]: fired ${firedRules.size} rule(s): ${[...firedRules].join(\", \")} ` +\n `(from ${matches.length} match(es) across ${notifications.length} notification(s))`,\n );\n return true;\n }\n\n private reloadRegistry(stage: string, traceTag: string): void {\n try {\n this.registry.reload();\n } catch (err: any) {\n this.logger.warn(\n `lightrules[${traceTag}]: registry reload failed ${stage}: ${err?.message ?? err}`,\n );\n }\n }\n\n private async triggerLight(\n rule: LightRuleMeta,\n notification: StoredNotification | undefined,\n traceTag: string,\n ): Promise<void> {\n let apiKey: string;\n try {\n apiKey = requireApiKey();\n } catch (err: any) {\n this.logger.warn(\n `lightrules[${traceTag}]: trigger '${rule.name}' skipped - no API key: ${err?.message ?? err}`,\n );\n return;\n }\n\n const reason = buildTriggerReason(rule, notification);\n this.logger.info(\n `lightrules[${traceTag}]: trigger rule='${rule.name}' ` +\n `notificationTs=${notification?.timestamp ?? \"-\"} ` +\n `app=${notification?.appDisplayName ?? notification?.appName ?? \"-\"}`,\n );\n\n const startedAtMs = Date.now();\n try {\n const result = await sendLightEffect(\n apiKey,\n rule.segments,\n this.logger,\n { repeat_times: rule.repeat_times },\n reason,\n rule.title,\n );\n if (result.ok) {\n this.logger.info(\n `lightrules[${traceTag}]: trigger '${rule.name}' ok bizUniqueId=${result.bizUniqueId ?? \"-\"} elapsedMs=${Date.now() - startedAtMs}`,\n );\n } else {\n this.logger.warn(\n `lightrules[${traceTag}]: trigger '${rule.name}' http-failed (${result.status ?? \"?\"}) ` +\n `elapsedMs=${Date.now() - startedAtMs}: ${result.error}`,\n );\n }\n } catch (err: any) {\n this.logger.warn(\n `lightrules[${traceTag}]: trigger '${rule.name}' exception elapsedMs=${Date.now() - startedAtMs}: ${err?.message ?? err}`,\n );\n }\n }\n}\n\nconst REASON_CONTENT_MAX = 40;\n\nfunction buildTriggerReason(\n rule: LightRuleMeta,\n notification: StoredNotification | undefined,\n): string {\n const ruleLabel = rule.title?.trim() || rule.name;\n if (!notification) {\n return `触发\"${ruleLabel}\"灯效`;\n }\n\n const app = notification.appDisplayName?.trim() || notification.appName.trim();\n const sender = notification.senderName?.trim() || notification.title?.trim();\n const conversation = notification.conversationName?.trim();\n const isGroup = notification.conversationType === \"group\";\n\n let where = app;\n if (isGroup) {\n where = conversation ? `${app}群聊\"${conversation}\"` : `${app}群聊`;\n }\n\n const action = sender ? `${sender}发来消息` : \"收到新消息\";\n const snippet = summarizeContent(notification.content);\n const detail = snippet ? `:${snippet}` : \"\";\n\n return `检测到${where}中${action}${detail},触发\"${ruleLabel}\"灯效`;\n}\n\nfunction summarizeContent(content: string | undefined): string {\n const trimmed = content?.trim();\n if (!trimmed) return \"\";\n if (trimmed.length <= REASON_CONTENT_MAX) return trimmed;\n return `${trimmed.slice(0, REASON_CONTENT_MAX)}…`;\n}\n","import { randomUUID } from \"node:crypto\";\nimport { buildLightEffectApnsBody } from \"./protocol.js\";\nimport { getEnvUrls } from \"../env.js\";\nimport type { LightSegment } from \"../types.js\";\nimport type { RepeatArgument } from \"./repeat.js\";\n\nexport interface SendLightResult {\n ok: boolean;\n bizUniqueId?: string;\n response?: unknown;\n status?: number;\n error?: string;\n}\n\nexport async function sendLightEffect(\n apiKey: string,\n segments: LightSegment[],\n logger?: { info: (msg: string) => void; warn: (msg: string) => void },\n repeatInput?: RepeatArgument,\n reason?: string,\n title?: string,\n): Promise<SendLightResult> {\n const apiUrl = getEnvUrls().lightApiUrl;\n const appKey = process.env.LIGHT_APP_KEY;\n const templateId = process.env.LIGHT_TEMPLATE_ID;\n const resolvedTitle = resolveLightTitle(title, reason, segments);\n\n logger?.info(\n `Light sender: apiUrl=${apiUrl ?? \"UNSET\"}, appKey=${appKey ? appKey.substring(0, 8) + \"…\" : \"UNSET\"}, templateId=${templateId ?? \"UNSET\"}, apiKey=${apiKey ? apiKey.substring(0, 20) + \"…\" : \"EMPTY\"}, title=${resolvedTitle}, reason=${reason ?? \"\"}, segments=${JSON.stringify(segments)}`,\n );\n\n if (!apiUrl || !appKey || !templateId) {\n return {\n ok: false,\n error:\n \"灯效 API 未配置,请设置环境变量 LIGHT_API_URL / LIGHT_APP_KEY / LIGHT_TEMPLATE_ID\",\n };\n }\n\n let bizContent: string;\n try {\n bizContent = buildLightEffectApnsBody(segments, repeatInput, reason);\n } catch (error: any) {\n return { ok: false, error: error?.message ?? String(error) };\n }\n const bizUniqueId = randomUUID();\n\n const requestBody = {\n appKey,\n bizMap: { noticeType: \"APP_NOTIFICATION_IMPORTANT\", title: resolvedTitle, reason },\n bizUniqueId,\n paramsMap: { bizContent },\n pushType: \"SPECIFY_PUSH\",\n templateId,\n };\n\n logger?.info(\n `Light sender: POST ${apiUrl}, bizUniqueId=${bizUniqueId}, body=${JSON.stringify(requestBody).substring(0, 500)}`,\n );\n\n const res = await fetch(apiUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Api-Key-Id\": apiKey.startsWith(\"Bearer \")\n ? apiKey.slice(\"Bearer \".length)\n : apiKey,\n },\n body: JSON.stringify(requestBody),\n });\n\n const resBody = await res.text();\n if (!res.ok) {\n logger?.warn(\n `Light sender: FAILED ${res.status}, url=${apiUrl}, resBody=${resBody.substring(0, 500)}`,\n );\n return { ok: false, status: res.status, error: resBody };\n }\n\n logger?.info(`Light sender: OK bizUniqueId=${bizUniqueId}, resBody=${resBody.substring(0, 200)}`);\n return { ok: true, bizUniqueId, response: JSON.parse(resBody) };\n}\n\nfunction resolveLightTitle(\n title: string | undefined,\n reason: string | undefined,\n segments: LightSegment[],\n): string {\n const trimmedTitle = title?.trim();\n if (trimmedTitle) return trimmedTitle;\n\n const trimmedReason = reason?.trim();\n if (trimmedReason) return trimmedReason;\n\n const modeDesc = segments.map((segment) => segment.mode).join(\"+\");\n return `Effect: ${modeDesc || \"custom\"}`;\n}\n","import { randomBytes } from \"node:crypto\";\nimport type { Logger } from \"../logger.js\";\nimport type { StoredNotification } from \"../notification/storage.js\";\n\nexport const DEFAULT_LIGHT_RULE_EVALUATION_DEBOUNCE_MS = 1_000;\n\nexport interface LightRuleEvaluationTrace {\n /** 本批 evaluate 的唯一 id,用于跨模块串联日志。 */\n flushId: string;\n /** 本批 evaluate 涵盖的所有 ingest 来源 id(按入队顺序)。 */\n ingestIds: string[];\n}\n\nexport interface LightRuleEvaluator {\n evaluate(\n notifications: StoredNotification[],\n trace?: LightRuleEvaluationTrace,\n ): Promise<boolean>;\n}\n\nexport interface LightRuleEvaluationSchedulerOptions {\n debounceMs?: number;\n}\n\ninterface PendingEntry {\n notification: StoredNotification;\n ingestId: string;\n enqueuedAtMs: number;\n}\n\nexport class LightRuleEvaluationScheduler {\n private readonly evaluator: LightRuleEvaluator;\n private readonly logger: Pick<Logger, \"info\" | \"warn\">;\n private readonly debounceMs: number;\n private readonly pending: PendingEntry[] = [];\n private timer: ReturnType<typeof setTimeout> | null = null;\n private running = false;\n private flushRequestedWhileRunning = false;\n\n constructor(deps: {\n evaluator: LightRuleEvaluator;\n logger: Pick<Logger, \"info\" | \"warn\">;\n options?: LightRuleEvaluationSchedulerOptions;\n }) {\n this.evaluator = deps.evaluator;\n this.logger = deps.logger;\n const debounceMs =\n deps.options?.debounceMs ?? DEFAULT_LIGHT_RULE_EVALUATION_DEBOUNCE_MS;\n this.debounceMs = Number.isFinite(debounceMs) && debounceMs >= 0\n ? debounceMs\n : DEFAULT_LIGHT_RULE_EVALUATION_DEBOUNCE_MS;\n }\n\n enqueue(\n notifications: StoredNotification[],\n ingestId: string = \"ing_unknown\",\n ): void {\n if (notifications.length === 0) return;\n const enqueuedAtMs = Date.now();\n for (const n of notifications) {\n this.pending.push({ notification: n, ingestId, enqueuedAtMs });\n }\n this.logger.info(\n `lightrules[${ingestId}]: scheduler enqueue ${notifications.length} item(s), ` +\n `pending=${this.pending.length}, debounceMs=${this.debounceMs}, running=${this.running}`,\n );\n this.scheduleFlush();\n }\n\n private scheduleFlush(): void {\n if (this.timer !== null) return;\n\n this.timer = setTimeout(() => {\n this.timer = null;\n void this.drain().catch((err) => {\n this.logger.warn(\n `lightrules: scheduled evaluation failed: ${err?.message ?? err}`,\n );\n });\n }, this.debounceMs);\n\n const maybeNodeTimer = this.timer as { unref?: () => void };\n maybeNodeTimer.unref?.();\n }\n\n private async drain(): Promise<void> {\n if (this.running) {\n this.flushRequestedWhileRunning = true;\n return;\n }\n\n const batch = this.pending.splice(0);\n if (batch.length === 0) return;\n\n const flushId = `flush_${randomBytes(4).toString(\"hex\")}`;\n const ingestIds = uniqueOrdered(batch.map((b) => b.ingestId));\n const firstEnqueuedAtMs = batch[0].enqueuedAtMs;\n const waitedMs = Date.now() - firstEnqueuedAtMs;\n const notifications = batch.map((b) => b.notification);\n\n this.logger.info(\n `lightrules[${flushId}]: drain start batch=${batch.length} ` +\n `ingestIds=[${ingestIds.join(\",\")}] waitedMs=${waitedMs}`,\n );\n\n this.running = true;\n const startedAtMs = Date.now();\n try {\n await this.evaluator.evaluate(notifications, { flushId, ingestIds });\n this.logger.info(\n `lightrules[${flushId}]: drain end elapsedMs=${Date.now() - startedAtMs}`,\n );\n } catch (err: any) {\n this.logger.warn(\n `lightrules[${flushId}]: evaluation failed (notifications=${batch.length}) ` +\n `elapsedMs=${Date.now() - startedAtMs}: ${err?.message ?? err}`,\n );\n } finally {\n this.running = false;\n if (this.pending.length > 0) {\n if (this.flushRequestedWhileRunning) {\n this.flushRequestedWhileRunning = false;\n void this.drain().catch((err) => {\n this.logger.warn(\n `lightrules: queued evaluation failed: ${err?.message ?? err}`,\n );\n });\n } else {\n this.scheduleFlush();\n }\n } else {\n this.flushRequestedWhileRunning = false;\n }\n }\n }\n}\n\nfunction uniqueOrdered(items: string[]): string[] {\n const seen = new Set<string>();\n const out: string[] = [];\n for (const item of items) {\n if (seen.has(item)) continue;\n seen.add(item);\n out.push(item);\n }\n return out;\n}\n","/**\n * PiAiInvoker —— 灯效规则事件驱动评估的\"轻量 LLM 调用\"实现\n *\n * 替代原先的 `sessionTarget: \"isolated\"` agent turn / subagent session 路径:\n * 每条通知到达后,仅发起一次 pi-ai `complete()` 请求,让模型直接输出 JSON\n * 命中结果。不启动 OpenClaw agent 循环,不加载工具 / skill / system prompt 栈。\n *\n * 模型默认跟随 OpenClaw 主 Agent 当前配置。鉴权 / provider 解析全部\n * 由 `prepareSimpleCompletionModelForAgent` 走 OpenClaw agent config 统一路径。\n *\n * 失败策略:任何环节失败(auth / network / 解析)都返回 null,调用方决定是否\n * 回退到 legacy agent session 路径;本类不抛。\n */\n\nimport {\n prepareSimpleCompletionModel,\n prepareSimpleCompletionModelForAgent,\n completeWithPreparedSimpleCompletionModel,\n} from \"openclaw/plugin-sdk/agent-runtime\";\nimport type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport type { StoredNotification } from \"../notification/storage.js\";\nimport type { LightRuleMeta } from \"./types.js\";\n\nconst DEFAULT_PROVIDER = \"anthropic\";\nconst DEFAULT_MODEL_ID = \"claude-haiku-4-5-20251001\";\nconst DEFAULT_AGENT_ID = \"main\";\nconst DEFAULT_TIMEOUT_MS = 30_000;\nconst DEFAULT_MAX_ATTEMPTS = 2;\nconst MAX_OUTPUT_TOKENS = 512;\n\nexport interface LlmMatchResult {\n /** 命中通知在入参数组中的下标 */\n notificationIndex: number;\n /** 命中规则名 */\n ruleName: string;\n}\n\nexport interface PiAiInvokerOptions {\n /** Optional explicit provider/model override. Omit to follow the OpenClaw agent default. */\n provider?: string;\n modelId?: string;\n /** Optional full model ref override for the selected agent, e.g. \"openrouter/auto\". */\n modelRef?: string;\n /** Agent whose configured model should be used when no explicit provider/model is set. */\n agentId?: string;\n timeoutMs?: number;\n maxAttempts?: number;\n}\n\ntype PreparedCompletion =\n | Awaited<ReturnType<typeof prepareSimpleCompletionModel>>\n | Awaited<ReturnType<typeof prepareSimpleCompletionModelForAgent>>;\n\nexport class PiAiInvoker {\n constructor(\n private readonly api: OpenClawPluginApi,\n private readonly logger: { info: (m: string) => void; warn: (m: string) => void },\n private readonly options: PiAiInvokerOptions = {},\n ) {}\n\n /**\n * 对一批通知和当前启用的规则做一次 LLM 匹配。\n *\n * 返回:\n * - `LlmMatchResult[]`:匹配成功(可能为空数组,即 0 命中)\n * - `null`:调用失败(模型准备失败 / 网络 / 解析)。调用方据此决定是否回退。\n */\n async matchNotifications(\n notifications: StoredNotification[],\n rules: LightRuleMeta[],\n flushId: string = \"flush_none\",\n ): Promise<LlmMatchResult[] | null> {\n if (notifications.length === 0 || rules.length === 0) return [];\n\n const traceTag = flushId;\n\n let label: string;\n let prepared: PreparedCompletion;\n try {\n ({ label, prepared } = await this.prepareCompletionModel());\n } catch (err: any) {\n this.logger.warn(\n `PiAiInvoker[${traceTag}]: prepare failed: ${err?.message ?? String(err)}`,\n );\n return null;\n }\n if (\"error\" in prepared) {\n this.logger.warn(\n `PiAiInvoker[${traceTag}]: prepare ${label} failed: ${prepared.error}`,\n );\n return null;\n }\n\n const systemPrompt = buildSystemPrompt(rules);\n const userMessage = buildUserMessage(notifications);\n const baseTimeoutMs = this.options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const maxAttempts = Math.max(1, this.options.maxAttempts ?? DEFAULT_MAX_ATTEMPTS);\n\n for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {\n const timeoutMs = baseTimeoutMs * attempt;\n const startedAtMs = Date.now();\n this.logger.info(\n `PiAiInvoker[${traceTag}]: complete attempt ${attempt}/${maxAttempts} ` +\n `model=${label} timeoutMs=${timeoutMs} notifications=${notifications.length} rules=${rules.length}`,\n );\n try {\n const resp = await completeWithPreparedSimpleCompletionModel({\n model: prepared.model,\n auth: prepared.auth,\n context: {\n systemPrompt,\n messages: [\n { role: \"user\", content: userMessage, timestamp: Date.now() },\n ],\n },\n options: {\n temperature: 0,\n maxTokens: MAX_OUTPUT_TOKENS,\n signal: AbortSignal.timeout(timeoutMs),\n cacheRetention: \"short\",\n },\n });\n\n const elapsedMs = Date.now() - startedAtMs;\n\n if (resp.stopReason === \"error\" || resp.stopReason === \"aborted\") {\n const retryable = resp.stopReason === \"aborted\" && attempt < maxAttempts;\n this.logger.warn(\n `PiAiInvoker[${traceTag}]: complete stopped with ${resp.stopReason}: ${resp.errorMessage ?? \"n/a\"} ` +\n `(attempt ${attempt}/${maxAttempts}, timeoutMs=${timeoutMs}, elapsedMs=${elapsedMs}${retryable ? \", retrying\" : \"\"})`,\n );\n if (retryable) {\n continue;\n }\n return null;\n }\n\n const text = extractText(resp.content);\n const parsed = parseMatchResult(text, notifications.length, rules);\n this.logger.info(\n `PiAiInvoker[${traceTag}]: complete ok attempt ${attempt}/${maxAttempts} ` +\n `stopReason=${resp.stopReason} elapsedMs=${elapsedMs} matches=${parsed.length}`,\n );\n return parsed;\n } catch (err: any) {\n const message = err?.message ?? String(err);\n const elapsedMs = Date.now() - startedAtMs;\n const retryable =\n attempt < maxAttempts\n && (err?.name === \"AbortError\" || /\\babort(?:ed)?\\b/i.test(message));\n this.logger.warn(\n `PiAiInvoker[${traceTag}]: complete failed: ${message} ` +\n `(attempt ${attempt}/${maxAttempts}, elapsedMs=${elapsedMs}${retryable ? \", retrying\" : \"\"})`,\n );\n if (retryable) {\n continue;\n }\n return null;\n }\n }\n\n return null;\n }\n\n private async prepareCompletionModel(): Promise<{\n label: string;\n prepared: PreparedCompletion;\n }> {\n if (this.options.provider || this.options.modelId) {\n const provider = this.options.provider ?? DEFAULT_PROVIDER;\n const modelId = this.options.modelId ?? DEFAULT_MODEL_ID;\n const prepared = await prepareSimpleCompletionModel({\n cfg: this.api.config,\n provider,\n modelId,\n });\n return { label: `${provider}/${modelId}`, prepared };\n }\n\n const agentId = this.options.agentId?.trim() || DEFAULT_AGENT_ID;\n const modelRef = this.options.modelRef?.trim();\n const prepared = await prepareSimpleCompletionModelForAgent({\n cfg: this.api.config,\n agentId,\n ...(modelRef ? { modelRef } : {}),\n });\n const label =\n \"selection\" in prepared && prepared.selection\n ? `${prepared.selection.provider}/${prepared.selection.modelId} (agent=${agentId})`\n : `agent=${agentId} default model`;\n return { label, prepared };\n }\n}\n\nfunction extractText(content: unknown): string {\n if (!Array.isArray(content)) return \"\";\n const parts: string[] = [];\n for (const c of content) {\n if (c && typeof c === \"object\" && (c as any).type === \"text\") {\n const t = (c as any).text;\n if (typeof t === \"string\") parts.push(t);\n }\n }\n return parts.join(\"\");\n}\n\nfunction buildSystemPrompt(rules: LightRuleMeta[]): string {\n const lines: string[] = [\n '你是\"手机通知 → 灯效规则\"命中匹配助手。',\n \"只根据规则 description 和通知字段判断,不要猜测。\",\n \"拿不准就不触发。\",\n \"输出必须是纯 JSON,格式固定为:\",\n '{\"matches\":[{\"i\":<通知下标>,\"rule\":\"<规则name>\"}]}',\n '0 命中输出 {\"matches\":[]}; rule 必须精确等于下方 name。',\n \"\",\n \"匹配要点:\",\n \"- 发件人/联系人规则:优先看 sender,其次 conversation_name、title、content 开头的 \\\"X:\\\"/\\\"X:\\\" 前缀;忽略空白、emoji 和中英文标点差异。\",\n \"- App 通知规则:看 app/appDisplayName 是否符合 description。\",\n \"- 关键词规则:看 title + content 是否包含或语义等价于 description 指定的关键词。\",\n \"- 语义规则:综合 title + content 判断;不要把正文里随便提到的人名当发件人。\",\n \"\",\n \"当前启用规则:\",\n ];\n const sorted = [...rules].sort(\n (a, b) => (b.createdAt ?? \"\").localeCompare(a.createdAt ?? \"\"),\n );\n sorted.forEach((rule, idx) => {\n lines.push(\n `[${idx + 1}] name=${rule.name}`,\n `title=${rule.title}`,\n `description=${rule.description}`,\n );\n });\n return lines.join(\"\\n\");\n}\n\nfunction buildUserMessage(notifications: StoredNotification[]): string {\n const lines: string[] = [\n `以下 ${notifications.length} 条新手机通知,按顺序编号:`,\n \"\",\n ];\n notifications.forEach((n, i) => {\n const app = n.appDisplayName ?? n.appName;\n lines.push(`[${i}] app=${app} time=${n.timestamp}`);\n if (n.senderName) {\n lines.push(` sender: ${n.senderName}`);\n }\n if (n.conversationType) {\n lines.push(` conversation_type: ${n.conversationType}`);\n }\n if (n.conversationName) {\n lines.push(` conversation_name: ${n.conversationName}`);\n }\n lines.push(` title: ${n.title}`, ` content: ${n.content}`, \"\");\n });\n lines.push(\"请判断每条通知命中了哪些规则,按约定格式输出 JSON。\");\n return lines.join(\"\\n\");\n}\n\nfunction parseMatchResult(\n rawText: string,\n notificationCount: number,\n rules: LightRuleMeta[],\n): LlmMatchResult[] {\n if (!rawText) return [];\n // 容错:模型有时会套 ```json ... ```,剥掉代码块围栏\n const text = rawText\n .trim()\n .replace(/^```(?:json)?\\s*/i, \"\")\n .replace(/\\s*```$/i, \"\")\n .trim();\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch {\n return [];\n }\n if (!parsed || typeof parsed !== \"object\") return [];\n\n const raw = (parsed as { matches?: unknown }).matches;\n if (!Array.isArray(raw)) return [];\n\n const validRuleNames = new Set(rules.map((r) => r.name));\n const results: LlmMatchResult[] = [];\n for (const m of raw) {\n if (!m || typeof m !== \"object\") continue;\n const entry = m as { i?: unknown; index?: unknown; rule?: unknown };\n const i =\n typeof entry.i === \"number\"\n ? entry.i\n : typeof entry.index === \"number\"\n ? entry.index\n : -1;\n const ruleName = typeof entry.rule === \"string\" ? entry.rule : null;\n if (!Number.isInteger(i) || i < 0 || i >= notificationCount) continue;\n if (!ruleName || !validRuleNames.has(ruleName)) continue;\n results.push({ notificationIndex: i, ruleName });\n }\n return results;\n}\n","import type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport { loadEnvName } from \"../env.js\";\nimport type { Logger } from \"../logger.js\";\nimport { createTunnelService } from \"../tunnel/service.js\";\nimport type { PluginConfig } from \"../types.js\";\nimport { resolveUpdateChannel } from \"../update/channel.js\";\nimport { registerAutoUpdate } from \"../update/index.js\";\nimport type { BroadcastFn } from \"../update/types.js\";\n\ninterface AutoUpdateDeps {\n api: OpenClawPluginApi;\n config: PluginConfig;\n logger: Logger;\n getBroadcastFn: () => BroadcastFn | null;\n cacheBroadcast: (broadcast: BroadcastFn | undefined) => void;\n tunnelService: ReturnType<typeof createTunnelService> | null;\n}\n\nexport function registerAutoUpdateLifecycle(\n deps: AutoUpdateDeps,\n): ReturnType<typeof registerAutoUpdate> {\n const {\n api,\n config,\n logger,\n getBroadcastFn,\n cacheBroadcast,\n tunnelService,\n } = deps;\n\n const autoUpdateConfig = {\n ...config.autoUpdate,\n channel: resolveUpdateChannel({\n configuredChannel: config.autoUpdate?.channel,\n envName: loadEnvName(),\n }),\n };\n\n const autoUpdateLifecycle = registerAutoUpdate(\n api,\n logger,\n autoUpdateConfig,\n getBroadcastFn,\n cacheBroadcast,\n tunnelService\n ? {\n notifyUpdateAvailable: (update) => tunnelService.notifyUpdateAvailable(update),\n clearPendingUpdate: () => tunnelService.clearPendingUpdate(),\n }\n : undefined,\n );\n\n api.registerService({\n id: \"update-checker\",\n start() {\n autoUpdateLifecycle.start();\n },\n stop() {\n autoUpdateLifecycle.stop();\n },\n });\n\n logger.info(\"自动更新检查服务已注册\");\n return autoUpdateLifecycle;\n}\n","import type { EnvName } from \"../env.js\";\nimport type { AutoUpdateConfig } from \"./types.js\";\n\n/**\n * 解析自动更新频道。\n *\n * 默认规则:\n * - 生产环境始终走 latest,避免正式客户端收到 beta 更新推送\n * - 非生产环境用户显式配置时,以配置为准\n * - 非生产环境默认走 beta\n */\nexport function resolveUpdateChannel(params: {\n configuredChannel?: AutoUpdateConfig[\"channel\"];\n envName: EnvName;\n}): \"latest\" | \"beta\" {\n if (params.envName === \"production\") {\n return \"latest\";\n }\n\n if (params.configuredChannel) {\n return params.configuredChannel;\n }\n\n return \"beta\";\n}\n","import { join } from \"node:path\";\nimport type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport type { Logger } from \"../logger.js\";\nimport { resolvePluginStateDir } from \"../plugin/runtime-state.js\";\nimport type {\n AutoUpdateConfig,\n BroadcastFn,\n ExternalUpdateNotifier,\n UpdateInfo,\n} from \"./types.js\";\nimport { UpdateChecker } from \"./checker.js\";\nimport { executeUpdate } from \"./executor.js\";\nimport { scheduleGatewayRestart } from \"./restart.js\";\n\nconst PLUGIN_ID = \"phone-notifications\";\n\nfunction resolveTargetDir(api: OpenClawPluginApi): string {\n try {\n const cfg = (api.runtime as any).config?.loadConfig?.();\n const installPath = cfg?.plugins?.installs?.[PLUGIN_ID]?.installPath;\n if (installPath) return installPath;\n } catch { /* ignore */ }\n return join(resolvePluginStateDir(api), \"extensions\", PLUGIN_ID);\n}\n\nasync function updateConfigRecord(\n api: OpenClawPluginApi,\n version: string,\n targetDir: string,\n tgzUrl: string,\n): Promise<void> {\n const configApi = (api.runtime as any).config;\n if (!configApi) return;\n const cfg = configApi.loadConfig();\n if (!cfg.plugins) cfg.plugins = {};\n if (!cfg.plugins.installs) cfg.plugins.installs = {};\n cfg.plugins.installs[PLUGIN_ID] = {\n ...cfg.plugins.installs[PLUGIN_ID],\n source: \"archive\" as const,\n sourcePath: tgzUrl,\n installPath: targetDir,\n version,\n installedAt: new Date().toISOString(),\n };\n await configApi.writeConfigFile(cfg);\n}\n\nfunction finalizeUpdateResult(\n api: OpenClawPluginApi,\n logger: Logger,\n result: Awaited<ReturnType<typeof executeUpdate>>,\n): Awaited<ReturnType<typeof executeUpdate>> {\n if (!result.success) {\n return result;\n }\n\n const restart = scheduleGatewayRestart(logger, {\n loadConfig: () => {\n const configApi = (api.runtime as any).config;\n return configApi?.loadConfig?.();\n },\n });\n\n const version = result.version ?? \"目标版本\";\n return {\n ...result,\n restartScheduled: restart.scheduled,\n message: restart.scheduled\n ? `已更新到 ${version},已触发 gateway 重启`\n : `已更新到 ${version},请手动重启 gateway 生效`,\n };\n}\n\n/**\n * 注册插件自动更新能力:\n * - 定时版本检查(UpdateChecker)\n * - 对话通道:before_prompt_build hook + plugin-update tool\n * - 网关通道:broadcast 推送 + plugin.update gateway method\n *\n * 返回 start/stop 供 registerService 管理生命周期。\n */\nexport function registerAutoUpdate(\n api: OpenClawPluginApi,\n logger: Logger,\n config: AutoUpdateConfig,\n getBroadcast: () => BroadcastFn | null,\n rememberBroadcast?: (broadcast: BroadcastFn | undefined) => void,\n externalUpdateNotifier?: ExternalUpdateNotifier,\n): {\n start: () => void;\n stop: () => void;\n notifyBroadcastReady: () => void;\n} {\n if (config.enabled === false) {\n logger.info(\"自动更新已禁用 (autoUpdate.enabled = false)\");\n return { start() {}, stop() {}, notifyBroadcastReady() {} };\n }\n\n let pendingUpdate: UpdateInfo | null = null;\n let pendingGatewayUpdate: UpdateInfo | null = null;\n\n function tryBroadcastUpdate(update: UpdateInfo): boolean {\n const broadcast = getBroadcast();\n if (!broadcast) return false;\n\n broadcast(\"plugin.updateAvailable\", {\n pluginId: \"phone-notifications\",\n pluginName: \"消息通知\",\n current: update.current,\n latest: update.latest,\n });\n pendingGatewayUpdate = null;\n return true;\n }\n\n // ── 对话通道:hook 注入 system prompt ──\n\n api.on(\"before_prompt_build\", () => {\n if (!pendingUpdate) return;\n return {\n appendSystemContext:\n `[系统通知] phone-notifications 插件有新版本 ${pendingUpdate.latest} 可用` +\n `(当前版本 ${pendingUpdate.current})。\\n` +\n `请用自然语言在合适时机告知用户,若用户同意更新,` +\n `调用 plugin-update tool 并传入 version 参数。` +\n `若用户拒绝,不再重复提醒。`,\n };\n });\n\n // ── 对话通道:plugin-update tool ──\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n api.registerTool({\n name: \"plugin-update\",\n label: \"Plugin Update\",\n description:\n \"将 phone-notifications 插件更新到指定版本。\" +\n \"仅在用户明确同意更新后调用。更新完成后会自动尝试重启 gateway;如宿主不支持,则需手动重启。\",\n parameters: {\n type: \"object\",\n required: [\"version\"],\n additionalProperties: false,\n properties: {\n version: {\n type: \"string\",\n description: \"目标版本号,如 1.11.0\",\n },\n },\n },\n async execute(_toolCallId: string, params: unknown) {\n const { version } = params as { version: string };\n const targetDir = resolveTargetDir(api);\n const result = await executeUpdate(\n version,\n api.runtime.system.runCommandWithTimeout,\n logger,\n targetDir,\n (v, url) => updateConfigRecord(api, v, targetDir, url),\n );\n const finalResult = finalizeUpdateResult(api, logger, result);\n if (finalResult.success) {\n pendingUpdate = null;\n externalUpdateNotifier?.clearPendingUpdate();\n }\n return {\n content: [{ type: \"text\" as const, text: finalResult.message }],\n details: finalResult,\n };\n },\n } as any);\n\n // ── 网关通道:plugin.update gateway method ──\n\n api.registerGatewayMethod(\"plugin.update\", async ({ params, respond, context }) => {\n rememberBroadcast?.(context?.broadcast);\n\n const version = (params as { version?: string }).version;\n if (!version) {\n respond(false, undefined, {\n code: \"MISSING_VERSION\",\n message: \"version is required\",\n });\n return;\n }\n const targetDir = resolveTargetDir(api);\n const result = await executeUpdate(\n version,\n api.runtime.system.runCommandWithTimeout,\n logger,\n targetDir,\n (v, url) => updateConfigRecord(api, v, targetDir, url),\n );\n const finalResult = finalizeUpdateResult(api, logger, result);\n if (finalResult.success) {\n pendingUpdate = null;\n externalUpdateNotifier?.clearPendingUpdate();\n }\n if (finalResult.success) {\n respond(true, {\n message: finalResult.message,\n restartScheduled: finalResult.restartScheduled === true,\n });\n } else {\n respond(false, undefined, {\n code: \"UPDATE_FAILED\",\n message: finalResult.message,\n });\n }\n });\n\n // ── 版本检查器 ──\n\n const intervalMs = (config.checkIntervalHours ?? 4) * 3_600_000;\n const channel = config.channel ?? \"latest\";\n\n logger.info(\n `自动更新已启用: channel=${channel}, checkIntervalHours=${config.checkIntervalHours ?? 4}`,\n );\n\n const checker = new UpdateChecker(\n logger,\n (update) => {\n pendingUpdate = update;\n\n const broadcasted = tryBroadcastUpdate(update);\n if (!broadcasted) pendingGatewayUpdate = update;\n if (!broadcasted) {\n externalUpdateNotifier?.notifyUpdateAvailable(update);\n }\n\n logger.info(\n `已通知更新 ${update.current} → ${update.latest}` +\n (broadcasted\n ? \"(对话 + 网关)\"\n : \"(对话通道已生效,等待下次 gateway 请求时补发客户端事件)\"),\n );\n },\n intervalMs,\n channel,\n );\n\n return {\n start: () => checker.start(),\n stop: () => checker.stop(),\n notifyBroadcastReady() {\n const update = pendingGatewayUpdate;\n if (!update) return;\n if (!tryBroadcastUpdate(update)) return;\n logger.info(`已补发插件更新事件 ${update.current} → ${update.latest}`);\n },\n };\n}\n","import type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport { resolveStateDir as resolveHostStateDir } from \"../host.js\";\nimport { trimToUndefined } from \"./shared.js\";\n\nexport function tryResolveRuntimeStateDir(\n api: Pick<OpenClawPluginApi, \"runtime\">,\n): string | undefined {\n const runtimeState = (api as any)?.runtime?.state;\n const resolveStateDir = runtimeState?.resolveStateDir;\n if (typeof resolveStateDir !== \"function\") {\n return undefined;\n }\n\n try {\n return trimToUndefined(resolveStateDir.call(runtimeState));\n } catch {\n return undefined;\n }\n}\n\nexport function resolvePluginStateDir(\n api: Pick<OpenClawPluginApi, \"runtime\">,\n): string {\n return tryResolveRuntimeStateDir(api) ?? resolveHostStateDir();\n}\n","import type { IncomingMessage } from \"node:http\";\nimport type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\n\nexport type GatewayHandler = Parameters<OpenClawPluginApi[\"registerGatewayMethod\"]>[1];\n\nexport type GatewayMethodRegistrar = (\n method: string,\n handler: GatewayHandler,\n) => void;\n\nexport function readBody(req: IncomingMessage): Promise<string> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n req.on(\"data\", (chunk: Buffer) => chunks.push(chunk));\n req.on(\"end\", () => resolve(Buffer.concat(chunks).toString()));\n req.on(\"error\", reject);\n });\n}\n\nexport function trimToUndefined(value: unknown): string | undefined {\n if (typeof value !== \"string\") {\n return undefined;\n }\n\n const trimmed = value.trim();\n return trimmed || undefined;\n}\n","import { PLUGIN_VERSION } from \"../version.js\";\nimport type { Logger } from \"../logger.js\";\nimport type { UpdateInfo } from \"./types.js\";\n\nfunction parseSemver(v: string): { major: number; minor: number; patch: number; pre: string | null } {\n const [main, pre = null] = v.split(\"-\", 2) as [string, string | undefined];\n const [major = 0, minor = 0, patch = 0] = main.split(\".\").map(Number);\n return { major, minor, patch, pre: pre ?? null };\n}\n\nfunction comparePreRelease(a: string, b: string): number {\n const aParts = a.split(\".\");\n const bParts = b.split(\".\");\n for (let i = 0; i < Math.max(aParts.length, bParts.length); i++) {\n const ap = aParts[i] ?? \"\";\n const bp = bParts[i] ?? \"\";\n const an = Number(ap);\n const bn = Number(bp);\n let diff: number;\n if (!Number.isNaN(an) && !Number.isNaN(bn)) {\n diff = an - bn;\n } else if (ap < bp) {\n diff = -1;\n } else if (ap > bp) {\n diff = 1;\n } else {\n diff = 0;\n }\n if (diff !== 0) return diff;\n }\n return 0;\n}\n\n/** Returns true if `candidate` is strictly newer than `current` per semver rules. */\nfunction isNewerVersion(candidate: string, current: string): boolean {\n const a = parseSemver(candidate);\n const b = parseSemver(current);\n\n if (a.major !== b.major) return a.major > b.major;\n if (a.minor !== b.minor) return a.minor > b.minor;\n if (a.patch !== b.patch) return a.patch > b.patch;\n\n // Same major.minor.patch: stable > pre-release\n if (a.pre === null) return b.pre !== null;\n if (b.pre === null) return false;\n\n return comparePreRelease(a.pre, b.pre) > 0;\n}\n\nconst CDN_BASE_URL = \"https://artifact.yoooclaw.com/plugin\";\nconst NPM_BASE_URL =\n \"https://registry.npmjs.org/@yoooclaw/phone-notifications\";\nconst FETCH_TIMEOUT_MS = 5_000;\n\nexport class UpdateChecker {\n private timer: ReturnType<typeof setTimeout> | null = null;\n private notifiedVersion: string | null = null;\n\n constructor(\n private readonly logger: Logger,\n private readonly onUpdateFound: (info: UpdateInfo) => void,\n private readonly intervalMs: number,\n private readonly channel: \"latest\" | \"beta\",\n ) {}\n\n start(): void {\n // 首次延迟 1 分钟,避免影响插件启动\n this.timer = setTimeout(() => {\n void this.check();\n this.timer = setInterval(() => void this.check(), this.intervalMs);\n }, 60_000);\n }\n\n stop(): void {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n }\n\n async check(): Promise<void> {\n const latest = await this.fetchLatestVersion();\n if (!latest || latest === PLUGIN_VERSION) return;\n if (latest === this.notifiedVersion) return;\n\n // latest 通道只能提示正式版,避免生产环境收到 prerelease 推送。\n if (this.channel !== \"beta\" && latest.includes(\"-\")) return;\n\n // 只有 latest 严格大于当前版本才提示;同版本 stable 会被视为比 prerelease 新。\n if (!isNewerVersion(latest, PLUGIN_VERSION)) return;\n\n this.notifiedVersion = latest;\n this.logger.info(`发现新版本: ${PLUGIN_VERSION} → ${latest}`);\n this.onUpdateFound({ current: PLUGIN_VERSION, latest });\n }\n\n private async fetchLatestVersion(): Promise<string | null> {\n const tag = this.channel === \"beta\" ? \"beta\" : \"latest\";\n\n // 优先 CDN(轻量 plain text)\n try {\n const res = await fetch(`${CDN_BASE_URL}/${tag}`, {\n signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),\n });\n if (res.ok) {\n const text = (await res.text()).trim();\n if (text) return text;\n }\n } catch {\n // CDN 不可达,回退 npm\n }\n\n // 回退 npm registry\n try {\n const res = await fetch(`${NPM_BASE_URL}/${tag}`, {\n signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),\n });\n if (res.ok) {\n const data = (await res.json()) as { version?: string };\n return data.version ?? null;\n }\n } catch {\n this.logger.info(\"版本检查失败(CDN + npm 均不可达),跳过\");\n }\n\n return null;\n }\n}\n","import { mkdirSync, mkdtempSync, renameSync, rmSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { tmpdir } from \"node:os\";\nimport type { Logger } from \"../logger.js\";\n\nconst VERSION_PATTERN = /^\\d+\\.\\d+\\.\\d+(-[\\w.]+)?$/;\nconst BASE_URL = \"https://artifact.yoooclaw.com/plugin\";\n\nexport interface UpdateResult {\n success: boolean;\n message: string;\n version?: string;\n restartScheduled?: boolean;\n}\n\ntype RunCommandFn = (\n argv: string[],\n opts: { timeoutMs: number },\n) => Promise<{ code: number | null; stdout: string; stderr: string }>;\n\n/**\n * 执行插件更新:直接下载 tgz 并替换插件目录,避免依赖 `openclaw extension install`。\n * `openclaw extension install` 要求 plugins.allow 包含 \"extension\",许多用户环境缺此配置。\n */\nexport async function executeUpdate(\n version: string,\n runCommand: RunCommandFn,\n logger: Logger,\n targetDir: string,\n updateConfigRecord: (version: string, tgzUrl: string) => Promise<void>,\n): Promise<UpdateResult> {\n if (!VERSION_PATTERN.test(version)) {\n return { success: false, message: `非法版本号: ${version}` };\n }\n\n const tgzUrl = `${BASE_URL}/v${version}/yoooclaw-phone-notifications-${version}.tgz`;\n logger.info(`执行更新: ${tgzUrl} → ${targetDir}`);\n\n const workDir = mkdtempSync(join(tmpdir(), \".openclaw-plugin-update-\"));\n const tgzPath = join(workDir, \"plugin.tgz\");\n const stagingDir = join(workDir, \"staged\");\n let backupDir: string | null = null;\n\n try {\n logger.info(\"下载插件包...\");\n const response = await fetch(tgzUrl, { signal: AbortSignal.timeout(60_000) });\n if (!response.ok) {\n return { success: false, message: `下载失败 (HTTP ${response.status}): ${tgzUrl}` };\n }\n const buffer = Buffer.from(await response.arrayBuffer());\n writeFileSync(tgzPath, buffer);\n logger.info(`下载完成 (${buffer.length} bytes)`);\n\n mkdirSync(stagingDir, { recursive: true });\n const tarResult = await runCommand(\n [\"tar\", \"-xzf\", tgzPath, \"-C\", stagingDir, \"--strip-components=1\"],\n { timeoutMs: 30_000 },\n );\n if (tarResult.code !== 0) {\n const err = tarResult.stderr || tarResult.stdout || \"unknown error\";\n return { success: false, message: `解压失败: ${err}` };\n }\n\n mkdirSync(dirname(targetDir), { recursive: true });\n try {\n backupDir = `${targetDir}.bak.${Date.now()}`;\n renameSync(targetDir, backupDir);\n } catch {\n backupDir = null;\n }\n renameSync(stagingDir, targetDir);\n\n try {\n await updateConfigRecord(version, tgzUrl);\n } catch (err) {\n logger.warn(`配置记录更新失败(插件文件已就位): ${String(err)}`);\n }\n\n if (backupDir) {\n try { rmSync(backupDir, { force: true, recursive: true }); } catch { /* ignore */ }\n }\n\n const msg = `已更新到 ${version}`;\n logger.info(msg);\n return { success: true, message: msg, version };\n\n } catch (err) {\n if (backupDir) {\n try {\n rmSync(targetDir, { force: true, recursive: true });\n renameSync(backupDir, targetDir);\n logger.info(\"已回滚到之前版本\");\n } catch (rollbackErr) {\n logger.error(`回滚失败: ${String(rollbackErr)}`);\n }\n }\n const errMsg = `更新执行异常: ${String(err)}`;\n logger.error(errMsg);\n return { success: false, message: errMsg };\n\n } finally {\n try { rmSync(workDir, { force: true, recursive: true }); } catch { /* ignore */ }\n }\n}\n","import type { Logger } from \"../logger.js\";\n\ntype CommandsConfigLike = {\n commands?: {\n restart?: boolean;\n };\n};\n\nexport interface GatewayRestartScheduleDeps {\n loadConfig?: () => CommandsConfigLike | undefined;\n getListenerCount?: (signal: NodeJS.Signals) => number;\n emitSignal?: (signal: NodeJS.Signals) => boolean;\n schedule?: (task: () => void) => void;\n}\n\nexport interface GatewayRestartScheduleResult {\n scheduled: boolean;\n}\n\nexport function scheduleGatewayRestart(\n logger: Logger,\n deps: GatewayRestartScheduleDeps = {},\n): GatewayRestartScheduleResult {\n try {\n const cfg = deps.loadConfig?.();\n if (cfg?.commands?.restart === false) {\n logger.warn(\"更新后跳过 gateway 重启: commands.restart=false\");\n return { scheduled: false };\n }\n } catch (err) {\n logger.warn(`更新后检查 gateway 重启配置失败: ${String(err)}`);\n }\n\n const getListenerCount =\n deps.getListenerCount ?? ((signal: NodeJS.Signals) => process.listenerCount(signal));\n if (getListenerCount(\"SIGUSR1\") < 1) {\n logger.warn(\"更新后跳过 gateway 重启: 当前进程未注册 SIGUSR1 监听器\");\n return { scheduled: false };\n }\n\n const emitSignal =\n deps.emitSignal ?? ((signal: NodeJS.Signals) => process.emit(signal));\n const schedule =\n deps.schedule ?? ((task: () => void) => { setTimeout(task, 0); });\n\n schedule(() => {\n try {\n const accepted = emitSignal(\"SIGUSR1\");\n if (accepted) {\n logger.info(\"更新完成,已触发 gateway SIGUSR1 重启\");\n } else {\n logger.warn(\"更新完成,但 gateway SIGUSR1 信号未被处理\");\n }\n } catch (err) {\n logger.warn(`更新后触发 gateway 重启失败: ${String(err)}`);\n }\n });\n\n return { scheduled: true };\n}\n","import { basename, dirname } from \"node:path\";\nimport type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport { registerAllCli } from \"../cli/index.js\";\nimport type { Logger } from \"../logger.js\";\n\nfunction inferOpenClawRootDir(workspaceDir?: string): string | undefined {\n if (!workspaceDir) {\n return undefined;\n }\n\n if (basename(workspaceDir) !== \"workspace\") {\n return undefined;\n }\n\n return dirname(workspaceDir);\n}\n\nexport function registerPluginCli(\n api: OpenClawPluginApi,\n params: {\n logger: Logger;\n openclawDir?: string;\n },\n): void {\n const { logger, openclawDir } = params;\n\n const registerAlias = (command: \"ntf\" | \"phone-notifications\"): void => {\n api.registerCli(\n (ctx) => {\n const ctxStateDir = (ctx as { stateDir?: unknown }).stateDir;\n const effectiveStateDir =\n openclawDir ??\n (typeof ctxStateDir === \"string\" ? ctxStateDir : undefined) ??\n inferOpenClawRootDir(ctx.workspaceDir);\n registerAllCli(\n ctx.program,\n {\n stateDir: effectiveStateDir,\n workspaceDir: ctx.workspaceDir,\n },\n command,\n );\n },\n { commands: [command] },\n );\n };\n\n registerAlias(\"ntf\");\n registerAlias(\"phone-notifications\");\n logger.info(\"CLI 命令已注册: ntf, phone-notifications\");\n}\n","import { existsSync, rmSync } from \"node:fs\";\nimport type { CliCommand } from \"./helpers.js\";\nimport { output } from \"./helpers.js\";\nimport {\n credentialsPath,\n readCredentials,\n writeCredentials,\n} from \"../auth/credentials.js\";\n\nexport function registerAuthCli(program: CliCommand): void {\n const auth = program\n .command(\"auth\")\n .description(\"用户认证管理\");\n\n auth\n .command(\"set-api-key <apiKey>\")\n .description(\"设置用户 API Key(持久化到本地配置)\")\n .action((apiKey: string) => {\n writeCredentials({ ...readCredentials(), apiKey, token: undefined });\n output({\n ok: true,\n apiKey: apiKey.slice(0, 8) + \"…\",\n storedAt: credentialsPath(),\n });\n });\n\n // 兼容旧命令:set-token <token>,现在等价于 set-api-key\n auth\n .command(\"set-token <token>\")\n .description(\"(兼容)设置用户 API Key(旧命令名)\")\n .action((token: string) => {\n writeCredentials({ ...readCredentials(), apiKey: token, token: undefined });\n output({\n ok: true,\n apiKey: token.slice(0, 8) + \"…\",\n storedAt: credentialsPath(),\n });\n });\n\n auth\n .command(\"show\")\n .description(\"查看当前认证状态\")\n .action(() => {\n const creds = readCredentials();\n const apiKey = creds.apiKey ?? creds.token;\n if (apiKey) {\n output({\n ok: true,\n hasApiKey: true,\n apiKey: apiKey.slice(0, 8) + \"…\",\n storedAt: credentialsPath(),\n });\n } else {\n output({ ok: true, hasApiKey: false });\n }\n });\n\n auth\n .command(\"clear\")\n .description(\"清除已保存的认证信息\")\n .action(() => {\n const path = credentialsPath();\n if (existsSync(path)) {\n const creds = readCredentials();\n delete creds.apiKey;\n delete creds.token;\n if (Object.keys(creds).length === 0) {\n rmSync(path, { force: true });\n } else {\n writeCredentials(creds);\n }\n }\n output({ ok: true, cleared: true });\n });\n}\n","import type { StoredNotification } from \"../notification/storage.js\";\nimport {\n exitError,\n listDateKeysAsync,\n parseIsoTime,\n readDateFileAsync,\n sortNotificationsByTimestampDesc,\n matchesNotificationAppFilter,\n} from \"./helpers.js\";\n\nexport interface RawNotificationQueryOptions {\n from?: string;\n to?: string;\n app?: string;\n sender?: string;\n conversationType?: string;\n keyword?: string;\n limit?: string;\n}\n\nexport interface NotificationQueryOptions {\n from?: string;\n to?: string;\n app?: string;\n sender?: string;\n conversationType?: string;\n keyword?: string;\n limit: number;\n fromTs: number | null;\n toTs: number | null;\n fromDateKey: string | null;\n toDateKey: string | null;\n}\n\nexport function parsePositiveIntegerOption(\n rawValue: string | undefined,\n defaultValue: number,\n optionName: string,\n errorCode: string,\n): number {\n const value = rawValue && rawValue.length > 0 ? rawValue : String(defaultValue);\n if (!/^\\d+$/.test(value)) {\n exitError(errorCode, `${optionName} 必须是大于 0 的整数`);\n }\n\n const parsed = Number.parseInt(value, 10);\n if (parsed <= 0) {\n exitError(errorCode, `${optionName} 必须是大于 0 的整数`);\n }\n return parsed;\n}\n\nexport function parseNotificationQueryOptions(\n opts: RawNotificationQueryOptions,\n defaultLimit = 100,\n): NotificationQueryOptions {\n const limit = parsePositiveIntegerOption(\n opts.limit,\n defaultLimit,\n \"--limit\",\n \"INVALID_LIMIT\",\n );\n\n if (\n opts.conversationType\n && opts.conversationType !== \"group\"\n && opts.conversationType !== \"private\"\n ) {\n exitError(\n \"INVALID_CONVERSATION_TYPE\",\n \"--conversation-type 只能是 group 或 private\",\n );\n }\n\n const hasFrom = typeof opts.from === \"string\" && opts.from.length > 0;\n const hasTo = typeof opts.to === \"string\" && opts.to.length > 0;\n const fromTs = hasFrom ? parseIsoTime(opts.from!, \"--from\") : null;\n const toTs = hasTo ? parseIsoTime(opts.to!, \"--to\") : null;\n\n if (fromTs !== null && toTs !== null && fromTs > toTs) {\n exitError(\"INVALID_TIME_RANGE\", \"--from 不能晚于 --to\");\n }\n\n return {\n from: opts.from,\n to: opts.to,\n app: opts.app,\n sender: opts.sender,\n conversationType: opts.conversationType,\n keyword: opts.keyword,\n limit,\n fromTs,\n toTs,\n fromDateKey: hasFrom ? opts.from!.slice(0, 10) : null,\n toDateKey: hasTo ? opts.to!.slice(0, 10) : null,\n };\n}\n\nexport function matchesNotificationQuery(\n item: StoredNotification,\n opts: NotificationQueryOptions,\n): boolean {\n if (opts.app && !matchesNotificationAppFilter(item, opts.app)) return false;\n if (\n opts.conversationType\n && item.conversationType !== opts.conversationType\n ) {\n return false;\n }\n\n const senderHaystack = [item.senderName, item.title]\n .filter((value): value is string => typeof value === \"string\" && value.length > 0)\n .join(\"\\n\");\n if (opts.sender && !senderHaystack.includes(opts.sender)) return false;\n\n const keywordHaystack = [\n item.title,\n item.content,\n item.senderName,\n item.conversationName,\n ]\n .filter((value): value is string => typeof value === \"string\" && value.length > 0)\n .join(\"\\n\");\n if (opts.keyword && !keywordHaystack.includes(opts.keyword)) return false;\n\n const itemTs = Date.parse(item.timestamp);\n if (Number.isNaN(itemTs)) return false;\n if (opts.fromTs !== null && itemTs < opts.fromTs) return false;\n if (opts.toTs !== null && itemTs > opts.toTs) return false;\n\n return true;\n}\n\nexport async function collectMatchingNotifications(\n dir: string,\n opts: NotificationQueryOptions,\n): Promise<StoredNotification[]> {\n const keys = await listDateKeysAsync(dir);\n const results: StoredNotification[] = [];\n const canStopAfterLimit = opts.fromTs === null && opts.toTs === null;\n\n for (const dateKey of keys) {\n if (opts.fromDateKey && dateKey < opts.fromDateKey) continue;\n if (opts.toDateKey && dateKey > opts.toDateKey) continue;\n\n const items = sortNotificationsByTimestampDesc([\n ...(await readDateFileAsync(dir, dateKey)),\n ]);\n for (const item of items) {\n if (!matchesNotificationQuery(item, opts)) continue;\n results.push(item);\n if (canStopAfterLimit && results.length >= opts.limit) {\n return results;\n }\n }\n }\n\n return sortNotificationsByTimestampDesc(results).slice(0, opts.limit);\n}\n","import {\n type CliCommand,\n type CliContext,\n resolveNotificationsDir,\n output,\n exitError,\n progress,\n} from \"./helpers.js\";\nimport {\n collectMatchingNotifications,\n parseNotificationQueryOptions,\n} from \"./ntf-query.js\";\n\nexport function registerNtfSearch(ntf: CliCommand, ctx: CliContext): void {\n ntf\n .command(\"search\")\n .description(\"查询通知(按时间/应用/发送人/关键词筛选)\")\n .option(\"--from <time>\", \"开始时间 ISO 8601,例如 2026-03-01T09:00:00+08:00\")\n .option(\"--to <time>\", \"结束时间 ISO 8601,例如 2026-03-01T18:00:00+08:00\")\n .option(\"--app <name>\", \"按应用名过滤\")\n .option(\"--sender <name>\", \"按发送人过滤\")\n .option(\n \"--conversation-type <type>\",\n \"按会话类型过滤(group/private)\",\n )\n .option(\"--keyword <text>\", \"在标题和内容中搜索关键词\")\n .option(\"--limit <n>\", \"最大返回条数\", \"100\")\n .action(\n async (opts: {\n from?: string;\n to?: string;\n app?: string;\n sender?: string;\n conversationType?: string;\n keyword?: string;\n limit: string;\n }) => {\n const dir = resolveNotificationsDir(ctx);\n if (!dir) exitError(\"STORAGE_UNAVAILABLE\", \"通知存储目录不可用\");\n\n progress(\"正在搜索通知...\");\n\n const query = parseNotificationQueryOptions(opts);\n const notifications = await collectMatchingNotifications(dir, query);\n\n output({\n ok: true,\n total: notifications.length,\n notifications,\n });\n },\n );\n}\n","import type { StoredNotification } from \"../notification/storage.js\";\nimport {\n type CliCommand,\n type CliContext,\n exitError,\n output,\n progress,\n resolveNotificationsDir,\n} from \"./helpers.js\";\nimport {\n collectMatchingNotifications,\n parseNotificationQueryOptions,\n parsePositiveIntegerOption,\n} from \"./ntf-query.js\";\n\ntype CountRow<T extends Record<string, unknown>> = T & { count: number };\n\ninterface CompactNotification {\n appName: string;\n appDisplayName?: string;\n title: string;\n content: string;\n timestamp: string;\n senderName?: string;\n conversationType?: string;\n conversationName?: string;\n}\n\nfunction compactNotification(item: StoredNotification): CompactNotification {\n const result: CompactNotification = {\n appName: item.appName,\n title: item.title,\n content: item.content,\n timestamp: item.timestamp,\n };\n if (item.appDisplayName) result.appDisplayName = item.appDisplayName;\n if (item.senderName) result.senderName = item.senderName;\n if (item.conversationType) result.conversationType = item.conversationType;\n if (item.conversationName) result.conversationName = item.conversationName;\n return result;\n}\n\nfunction truncate(value: string, maxLength = 120): string {\n if (value.length <= maxLength) return value;\n return `${value.slice(0, maxLength - 1)}…`;\n}\n\nfunction increment<T extends Record<string, unknown>>(\n map: Map<string, CountRow<T>>,\n key: string,\n seed: T,\n): void {\n const existing = map.get(key);\n if (existing) {\n existing.count += 1;\n return;\n }\n map.set(key, { ...seed, count: 1 });\n}\n\nfunction topRows<T extends Record<string, unknown>>(\n map: Map<string, CountRow<T>>,\n limit: number,\n): CountRow<T>[] {\n return [...map.values()].sort((a, b) => b.count - a.count).slice(0, limit);\n}\n\nfunction hourBucket(timestamp: string): string | null {\n const match = /^(\\d{4}-\\d{2}-\\d{2})T(\\d{2}):/.exec(timestamp);\n if (!match) return null;\n return `${match[1]} ${match[2]}:00`;\n}\n\nfunction buildSamplesBySender(\n notifications: StoredNotification[],\n senderRows: CountRow<{ sender: string }>[],\n): Array<{ sender: string; count: number; samples: string[] }> {\n return senderRows.map((row) => {\n const samples: string[] = [];\n for (const item of notifications) {\n const sender = item.senderName?.trim() || item.title?.trim() || \"(unknown)\";\n if (sender !== row.sender) continue;\n const content = truncate(item.content.trim());\n if (content && !samples.includes(content)) samples.push(content);\n if (samples.length >= 5) break;\n }\n return { sender: row.sender, count: row.count, samples };\n });\n}\n\nexport function registerNtfSummary(ntf: CliCommand, ctx: CliContext): void {\n ntf\n .command(\"summary\")\n .description(\"生成通知摘要输入(聚合统计 + 样例,供 Agent 快速总结)\")\n .option(\"--from <time>\", \"开始时间 ISO 8601,例如 2026-03-01T09:00:00+08:00\")\n .option(\"--to <time>\", \"结束时间 ISO 8601,例如 2026-03-01T18:00:00+08:00\")\n .option(\"--app <name>\", \"按应用名过滤\")\n .option(\"--sender <name>\", \"按发送人过滤\")\n .option(\n \"--conversation-type <type>\",\n \"按会话类型过滤(group/private)\",\n )\n .option(\"--keyword <text>\", \"在标题和内容中搜索关键词\")\n .option(\"--limit <n>\", \"纳入摘要的最大通知条数\", \"100\")\n .option(\"--sample <n>\", \"返回最近样例条数\", \"30\")\n .option(\"--top <n>\", \"返回聚合榜单条数\", \"10\")\n .action(\n async (opts: {\n from?: string;\n to?: string;\n app?: string;\n sender?: string;\n conversationType?: string;\n keyword?: string;\n limit: string;\n sample: string;\n top: string;\n }) => {\n const dir = resolveNotificationsDir(ctx);\n if (!dir) exitError(\"STORAGE_UNAVAILABLE\", \"通知存储目录不可用\");\n\n progress(\"正在生成通知摘要输入...\");\n\n const query = parseNotificationQueryOptions(opts);\n const sampleLimit = parsePositiveIntegerOption(\n opts.sample,\n 30,\n \"--sample\",\n \"INVALID_SAMPLE\",\n );\n const topLimit = parsePositiveIntegerOption(\n opts.top,\n 10,\n \"--top\",\n \"INVALID_TOP\",\n );\n\n const notifications = await collectMatchingNotifications(dir, query);\n const byApp = new Map<\n string,\n CountRow<{ appName: string; appDisplayName?: string }>\n >();\n const bySender = new Map<string, CountRow<{ sender: string }>>();\n const byConversation = new Map<\n string,\n CountRow<{ conversationName: string; conversationType?: string }>\n >();\n const byHour = new Map<string, CountRow<{ hour: string }>>();\n\n for (const item of notifications) {\n const appKey = `${item.appName}\\0${item.appDisplayName ?? \"\"}`;\n increment(byApp, appKey, {\n appName: item.appName,\n ...(item.appDisplayName ? { appDisplayName: item.appDisplayName } : {}),\n });\n\n const sender = item.senderName?.trim() || item.title?.trim() || \"(unknown)\";\n increment(bySender, sender, { sender });\n\n const conversationName =\n item.conversationName?.trim() || item.title?.trim() || \"(unknown)\";\n const conversationKey = `${conversationName}\\0${item.conversationType ?? \"\"}`;\n increment(byConversation, conversationKey, {\n conversationName,\n ...(item.conversationType\n ? { conversationType: item.conversationType }\n : {}),\n });\n\n const hour = hourBucket(item.timestamp);\n if (hour) increment(byHour, hour, { hour });\n }\n\n const senderRows = topRows(bySender, topLimit);\n output({\n ok: true,\n limit: query.limit,\n total: notifications.length,\n range: {\n newest: notifications[0]?.timestamp ?? null,\n oldest: notifications[notifications.length - 1]?.timestamp ?? null,\n },\n byApp: topRows(byApp, topLimit),\n bySender: senderRows,\n byConversation: topRows(byConversation, topLimit),\n byHour: topRows(byHour, topLimit),\n latest: notifications.slice(0, sampleLimit).map(compactNotification),\n samplesBySender: buildSamplesBySender(notifications, senderRows),\n });\n },\n );\n}\n","import {\n type CliCommand,\n type CliContext,\n resolveNotificationsDir,\n listDateKeys,\n readDateFile,\n filterDateRange,\n matchesNotificationAppFilter,\n today,\n daysAgo,\n output,\n exitError,\n} from \"./helpers.js\";\n\ntype Dimension = \"date\" | \"app\" | \"sender\" | \"hour\" | \"all\";\n\nexport function registerNtfStats(ntf: CliCommand, ctx: CliContext): void {\n ntf\n .command(\"stats\")\n .description(\"通知统计分析(按日期/应用/发送人/时段聚合)\")\n .option(\"--from <date>\", \"开始日期 YYYY-MM-DD\", daysAgo(7))\n .option(\"--to <date>\", \"结束日期 YYYY-MM-DD\", today())\n .option(\"--app <name>\", \"只统计指定应用\")\n .option(\"--dim <dimension>\", \"统计维度:date/app/sender/hour/all\", \"all\")\n .action(\n (opts: { from: string; to: string; app?: string; dim: string }) => {\n const dir = resolveNotificationsDir(ctx);\n if (!dir) exitError(\"STORAGE_UNAVAILABLE\", \"通知存储目录不可用\");\n\n const dim = opts.dim as Dimension;\n const keys = filterDateRange(listDateKeys(dir), opts.from, opts.to);\n\n const byDate: Record<string, number> = {};\n const byApp: Record<string, number> = {};\n const bySender: Record<string, number> = {};\n const byHour: Record<string, number> = {};\n let total = 0;\n\n for (const dateKey of keys) {\n const items = readDateFile(dir, dateKey);\n let dateCount = 0;\n for (const item of items) {\n if (opts.app && !matchesNotificationAppFilter(item, opts.app)) continue;\n total++;\n dateCount++;\n\n byApp[item.appName] = (byApp[item.appName] || 0) + 1;\n\n const sender = item.senderName?.trim() || item.title?.trim();\n if (sender) {\n bySender[sender] = (bySender[sender] || 0) + 1;\n }\n\n const hourMatch = /T(\\d{2}):/.exec(item.timestamp);\n if (hourMatch) {\n const h = hourMatch[1];\n byHour[h] = (byHour[h] || 0) + 1;\n }\n }\n byDate[dateKey] = dateCount;\n }\n\n const result: Record<string, unknown> = {\n ok: true,\n range: { from: opts.from, to: opts.to },\n total,\n };\n\n if (dim === \"date\" || dim === \"all\") {\n result.byDate = byDate;\n }\n if (dim === \"app\" || dim === \"all\") {\n result.byApp = byApp;\n }\n if (dim === \"sender\" || dim === \"all\") {\n // Sort by count descending, return top 20\n const sorted = Object.entries(bySender)\n .sort((a, b) => b[1] - a[1])\n .slice(0, 20)\n .map(([sender, count]) => ({ sender, count }));\n result.bySender = sorted;\n }\n if (dim === \"hour\" || dim === \"all\") {\n result.byHour = byHour;\n }\n\n output(result);\n },\n );\n}\n","import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport {\n type CliCommand,\n type CliContext,\n resolveNotificationsDir,\n listDateKeys,\n readDateFile,\n output,\n exitError,\n} from \"./helpers.js\";\n\ninterface CheckpointData {\n [dateKey: string]: { lastIndex: number };\n}\n\nconst SYNC_FETCH_LIMIT = 300;\n\nfunction checkpointPath(dir: string): string {\n return join(dir, \".checkpoint.json\");\n}\n\nfunction readCheckpoint(dir: string): CheckpointData {\n const p = checkpointPath(dir);\n if (!existsSync(p)) return {};\n try {\n return JSON.parse(readFileSync(p, \"utf-8\"));\n } catch {\n return {};\n }\n}\n\nfunction writeCheckpoint(dir: string, data: CheckpointData): void {\n writeFileSync(checkpointPath(dir), JSON.stringify(data, null, 2), \"utf-8\");\n}\n\nexport function registerNtfSync(ntf: CliCommand, ctx: CliContext): void {\n const sync = ntf.command(\"sync\").description(\"同步通知到记忆系统\");\n\n sync\n .command(\"scan\")\n .description(\"扫描未处理的通知,返回待同步摘要\")\n .action(() => {\n const dir = resolveNotificationsDir(ctx);\n if (!dir) exitError(\"STORAGE_UNAVAILABLE\", \"通知存储目录不可用\");\n\n const checkpoint = readCheckpoint(dir);\n const keys = listDateKeys(dir); // descending\n const pending: { date: string; count: number; startIndex: number }[] = [];\n let totalPending = 0;\n\n for (const dateKey of keys) {\n const items = readDateFile(dir, dateKey);\n const lastIndex = checkpoint[dateKey]?.lastIndex ?? -1;\n const unprocessed = items.length - (lastIndex + 1);\n if (unprocessed > 0) {\n pending.push({\n date: dateKey,\n count: unprocessed,\n startIndex: lastIndex + 1,\n });\n totalPending += unprocessed;\n }\n }\n\n output({ ok: true, pending, totalPending });\n });\n\n sync\n .command(\"fetch\")\n .description(\"获取指定日期的未处理通知详情\")\n .requiredOption(\"--date <date>\", \"目标日期 YYYY-MM-DD\")\n .option(\"--max-end-index <index>\", \"本次同步快照允许读取的最大 endIndex\")\n .action((opts: { date: string; maxEndIndex?: string }) => {\n const dir = resolveNotificationsDir(ctx);\n if (!dir) exitError(\"STORAGE_UNAVAILABLE\", \"通知存储目录不可用\");\n\n const items = readDateFile(dir, opts.date);\n if (items.length === 0) {\n exitError(\"NO_DATA\", `日期 ${opts.date} 无通知数据`);\n }\n\n const checkpoint = readCheckpoint(dir);\n const lastIndex = checkpoint[opts.date]?.lastIndex ?? -1;\n const startIndex = lastIndex + 1;\n let maxEndIndex = items.length - 1;\n if (typeof opts.maxEndIndex === \"string\" && opts.maxEndIndex.length > 0) {\n maxEndIndex = Number.parseInt(opts.maxEndIndex, 10);\n if (!Number.isInteger(maxEndIndex) || String(maxEndIndex) !== opts.maxEndIndex) {\n exitError(\"INVALID_MAX_END_INDEX\", \"--max-end-index 必须是非负整数\");\n }\n if (maxEndIndex < 0) {\n exitError(\"INVALID_MAX_END_INDEX\", \"--max-end-index 必须是非负整数\");\n }\n maxEndIndex = Math.min(maxEndIndex, items.length - 1);\n }\n const snapshotEndExclusive = Math.max(startIndex, maxEndIndex + 1);\n const unprocessed = items.slice(startIndex, snapshotEndExclusive);\n const notifications = unprocessed.slice(0, SYNC_FETCH_LIMIT);\n const endIndex =\n notifications.length > 0 ? startIndex + notifications.length - 1 : lastIndex;\n const hasMore = unprocessed.length > notifications.length;\n\n if (unprocessed.length === 0) {\n output({\n ok: true,\n date: opts.date,\n startIndex,\n endIndex,\n nextStartIndex: null,\n limit: SYNC_FETCH_LIMIT,\n maxEndIndex,\n returned: 0,\n totalUnprocessed: 0,\n hasMore: false,\n notifications: [],\n });\n return;\n }\n\n output({\n ok: true,\n date: opts.date,\n startIndex,\n endIndex,\n nextStartIndex: hasMore ? endIndex + 1 : null,\n limit: SYNC_FETCH_LIMIT,\n maxEndIndex,\n returned: notifications.length,\n totalUnprocessed: unprocessed.length,\n hasMore,\n notifications,\n });\n });\n\n sync\n .command(\"commit\")\n .description(\"标记指定日期当前批次处理完成,更新 checkpoint\")\n .requiredOption(\"--date <date>\", \"目标日期 YYYY-MM-DD\")\n .option(\"--end-index <index>\", \"本批次 fetch 返回的 endIndex\")\n .action((opts: { date: string; endIndex?: string }) => {\n const dir = resolveNotificationsDir(ctx);\n if (!dir) exitError(\"STORAGE_UNAVAILABLE\", \"通知存储目录不可用\");\n\n const items = readDateFile(dir, opts.date);\n if (items.length === 0) {\n exitError(\"NO_DATA\", `日期 ${opts.date} 无通知数据`);\n }\n\n const checkpoint = readCheckpoint(dir);\n const lastIndex = checkpoint[opts.date]?.lastIndex ?? -1;\n let committedIndex: number;\n if (typeof opts.endIndex === \"string\" && opts.endIndex.length > 0) {\n committedIndex = Number.parseInt(opts.endIndex, 10);\n if (!Number.isInteger(committedIndex) || String(committedIndex) !== opts.endIndex) {\n exitError(\"INVALID_END_INDEX\", \"--end-index 必须是非负整数\");\n }\n if (committedIndex < 0 || committedIndex >= items.length) {\n exitError(\n \"INVALID_END_INDEX\",\n \"--end-index 必须落在当前日期通知文件范围内\",\n );\n }\n if (committedIndex < lastIndex) {\n exitError(\n \"STALE_END_INDEX\",\n \"--end-index 早于当前 checkpoint,不能回退消费进度\",\n );\n }\n if (committedIndex > lastIndex + SYNC_FETCH_LIMIT) {\n exitError(\n \"INVALID_END_INDEX\",\n \"--end-index 超出单批 fetch 上限,不能跳过未处理通知\",\n );\n }\n } else {\n committedIndex = Math.min(items.length - 1, lastIndex + SYNC_FETCH_LIMIT);\n }\n const hasMore = committedIndex < items.length - 1;\n checkpoint[opts.date] = { lastIndex: committedIndex };\n writeCheckpoint(dir, checkpoint);\n\n output({\n ok: true,\n date: opts.date,\n committedIndex,\n commitMode:\n typeof opts.endIndex === \"string\" && opts.endIndex.length > 0\n ? \"exact-end-index\"\n : \"legacy-batch-limit\",\n limit: SYNC_FETCH_LIMIT,\n hasMore,\n nextStartIndex: hasMore ? committedIndex + 1 : null,\n });\n });\n}\n","import {\n existsSync,\n mkdirSync,\n readFileSync,\n writeFileSync,\n rmSync,\n readdirSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\nimport { type CliCommand, type CliContext, output, exitError } from \"./helpers.js\";\nimport { generateFetchPy } from \"../monitor/fetch-gen.js\";\n\ninterface MonitorMeta {\n name: string;\n type?: \"monitor\" | \"light-rule\";\n description: string;\n matchRules: Record<string, unknown>;\n cronSchedule: string;\n enabled: boolean;\n createdAt: string;\n updatedAt?: string;\n}\n\nfunction tasksDir(ctx: CliContext): string {\n const base = ctx.workspaceDir || ctx.stateDir;\n if (!base) throw new Error(\"workspaceDir and stateDir both unavailable\");\n return join(base, \"tasks\");\n}\n\nfunction readMeta(taskDir: string): MonitorMeta | null {\n const metaPath = join(taskDir, \"meta.json\");\n if (!existsSync(metaPath)) return null;\n try {\n return JSON.parse(readFileSync(metaPath, \"utf-8\"));\n } catch {\n return null;\n }\n}\n\nfunction writeMeta(taskDir: string, meta: MonitorMeta): void {\n writeFileSync(join(taskDir, \"meta.json\"), JSON.stringify(meta, null, 2), \"utf-8\");\n}\n\nfunction generateReadme(name: string, description: string): string {\n return `# Monitor Task: ${name}\n\n## 描述\n${description}\n\n## 处理指南\n当 fetch.py 输出匹配的通知时,请:\n1. 阅读匹配到的通知内容\n2. 根据任务描述判断是否需要通知用户\n3. 如需通知用户,使用 message 工具发送摘要\n`;\n}\n\nexport function registerNtfMonitor(ntf: CliCommand, ctx: CliContext): void {\n const monitor = ntf.command(\"monitor\").description(\"通知监控任务管理\");\n\n monitor\n .command(\"list\")\n .description(\"列出所有监控任务\")\n .action(() => {\n const dir = tasksDir(ctx);\n if (!existsSync(dir)) {\n output({ ok: true, tasks: [] });\n return;\n }\n\n const tasks: MonitorMeta[] = [];\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n const meta = readMeta(join(dir, entry.name));\n if (meta) tasks.push(meta);\n }\n\n output({ ok: true, tasks });\n });\n\n monitor\n .command(\"show <name>\")\n .description(\"查看监控任务详情\")\n .action((name: string) => {\n const taskDir = join(tasksDir(ctx), name);\n const meta = readMeta(taskDir);\n if (!meta) exitError(\"NOT_FOUND\", `监控任务 '${name}' 不存在`);\n\n const checkpointPath = join(taskDir, \"checkpoint.json\");\n let checkpoint = {};\n if (existsSync(checkpointPath)) {\n try {\n checkpoint = JSON.parse(readFileSync(checkpointPath, \"utf-8\"));\n } catch {\n // ignore\n }\n }\n\n output({\n ok: true,\n ...meta,\n matchScript: `tasks/${name}/fetch.py`,\n readme: `tasks/${name}/README.md`,\n checkpoint,\n });\n });\n\n monitor\n .command(\"create <name>\")\n .description(\"创建监控任务\")\n .requiredOption(\"--description <text>\", \"任务描述\")\n .requiredOption(\"--match-rules <json>\", \"匹配规则 JSON\")\n .requiredOption(\"--schedule <cron>\", \"cron 表达式\")\n .action(\n (\n name: string,\n opts: {\n description: string;\n matchRules: string;\n schedule: string;\n },\n ) => {\n const dir = tasksDir(ctx);\n const taskDir = join(dir, name);\n\n if (existsSync(taskDir)) {\n exitError(\"ALREADY_EXISTS\", `监控任务 '${name}' 已存在`);\n }\n\n let matchRules: Record<string, unknown>;\n try {\n matchRules = JSON.parse(opts.matchRules);\n } catch {\n exitError(\n \"VALIDATION_FAILED\",\n \"match-rules 必须是合法的 JSON\",\n );\n }\n\n mkdirSync(taskDir, { recursive: true });\n\n const meta: MonitorMeta = {\n name,\n description: opts.description,\n matchRules,\n cronSchedule: opts.schedule,\n enabled: true,\n createdAt: new Date().toISOString(),\n };\n writeMeta(taskDir, meta);\n writeFileSync(\n join(taskDir, \"fetch.py\"),\n generateFetchPy(name, matchRules),\n \"utf-8\",\n );\n writeFileSync(\n join(taskDir, \"README.md\"),\n generateReadme(name, opts.description),\n \"utf-8\",\n );\n\n output({\n ok: true,\n name,\n created: {\n script: `tasks/${name}/fetch.py`,\n readme: `tasks/${name}/README.md`,\n cronJob: `notif-${name}`,\n },\n cronHint: {\n action: \"add\",\n job: {\n name: `notif-${name}`,\n schedule: opts.schedule,\n sessionTarget: \"isolated\",\n message: `手机通知已由独立服务实时捕获到 notifications/ 目录的 JSON 文件中。\\n执行:python3 tasks/${name}/fetch.py --notifications-dir notifications\\n- NO_CHANGE 或 NO_MATCH → 不回复,直接结束。\\n- 有输出 → 读 tasks/${name}/README.md 了解如何处理数据并通知用户。`,\n },\n },\n });\n },\n );\n\n monitor\n .command(\"delete <name>\")\n .description(\"删除监控任务\")\n .option(\"--yes\", \"跳过确认\")\n .action((name: string, opts: { yes?: boolean }) => {\n const taskDir = join(tasksDir(ctx), name);\n if (!existsSync(taskDir)) {\n exitError(\"NOT_FOUND\", `监控任务 '${name}' 不存在`);\n }\n\n if (!opts.yes) {\n output({\n ok: false,\n error: {\n code: \"CONFIRMATION_REQUIRED\",\n message: `确认删除监控任务 '${name}'?添加 --yes 跳过确认`,\n },\n });\n process.exit(1);\n }\n\n rmSync(taskDir, { recursive: true, force: true });\n output({\n ok: true,\n name,\n deleted: true,\n cronHint: {\n action: \"remove\",\n name: `notif-${name}`,\n },\n });\n });\n\n monitor\n .command(\"enable <name>\")\n .description(\"启用监控任务\")\n .action((name: string) => {\n const taskDir = join(tasksDir(ctx), name);\n const meta = readMeta(taskDir);\n if (!meta) exitError(\"NOT_FOUND\", `监控任务 '${name}' 不存在`);\n\n meta.enabled = true;\n writeMeta(taskDir, meta);\n output({ ok: true, name, enabled: true });\n });\n\n monitor\n .command(\"disable <name>\")\n .description(\"暂停监控任务\")\n .action((name: string) => {\n const taskDir = join(tasksDir(ctx), name);\n const meta = readMeta(taskDir);\n if (!meta) exitError(\"NOT_FOUND\", `监控任务 '${name}' 不存在`);\n\n meta.enabled = false;\n writeMeta(taskDir, meta);\n output({ ok: true, name, enabled: false });\n });\n}\n","/**\n * 共享的 fetch.py 生成逻辑,供 ntf-monitor CLI 和 light-rules gateway 复用。\n */\nexport function generateFetchPy(\n name: string,\n matchRules: Record<string, unknown>,\n): string {\n const appName = typeof matchRules.appName === \"string\" ? matchRules.appName : \"\";\n const senderKeywords = stringArray(matchRules.senderKeywords);\n const contentKeywords = stringArray(matchRules.contentKeywords);\n\n return `#!/usr/bin/env python3\n\"\"\"Auto-generated fetch script for monitor task: ${name}\"\"\"\nimport json, sys, os\nfrom pathlib import Path\n\ndef matches(notification: dict) -> bool:\n app = str(notification.get(\"appName\", \"\") or \"\")\n title = str(notification.get(\"title\", \"\") or \"\")\n content = str(notification.get(\"content\", \"\") or \"\")\n body = str(notification.get(\"body\", \"\") or \"\")\n\n app_name = ${pyLiteral(appName)}\n if app_name and app != app_name:\n return False\n\n sender_keywords = ${pyLiteral(senderKeywords)}\n sender_haystack = f\"{title}\\\\n{content}\\\\n{body}\"\n if sender_keywords and not any(keyword in sender_haystack for keyword in sender_keywords):\n return False\n\n content_keywords = ${pyLiteral(contentKeywords)}\n content_haystack = f\"{content}\\\\n{body}\"\n if content_keywords and not any(keyword in content_haystack for keyword in content_keywords):\n return False\n\n return True\n\ndef main():\n import argparse\n parser = argparse.ArgumentParser()\n parser.add_argument(\"--notifications-dir\", required=True)\n args = parser.parse_args()\n\n checkpoint_path = Path(__file__).parent / \"checkpoint.json\"\n checkpoint = {}\n if checkpoint_path.exists():\n checkpoint = json.loads(checkpoint_path.read_text())\n\n ntf_dir = Path(args.notifications_dir)\n matched = []\n new_checkpoint = dict(checkpoint)\n\n for f in sorted(ntf_dir.glob(\"*.json\")):\n date_key = f.stem\n items = json.loads(f.read_text())\n last_idx = checkpoint.get(date_key, {}).get(\"lastIndex\", -1)\n for i, item in enumerate(items):\n if i <= last_idx:\n continue\n if matches(item):\n matched.append(item)\n new_checkpoint[date_key] = {\"lastIndex\": len(items) - 1}\n\n checkpoint_path.write_text(json.dumps(new_checkpoint, indent=2))\n\n if not matched:\n print(\"NO_MATCH\")\n return\n\n for m in matched:\n print(json.dumps(m, ensure_ascii=False))\n\nif __name__ == \"__main__\":\n main()\n`;\n}\n\nfunction stringArray(value: unknown): string[] {\n if (!Array.isArray(value)) return [];\n return value.filter((item): item is string => typeof item === \"string\" && item.length > 0);\n}\n\nfunction pyLiteral(value: string | string[]): string {\n return JSON.stringify(value);\n}\n","import { type CliCommand, output, exitError } from \"./helpers.js\";\nimport { requireApiKey } from \"../auth/credentials.js\";\nimport { sendLightEffect } from \"../light/sender.js\";\nimport { parseAndValidateSegments } from \"../light/validators.js\";\nimport { assertAncsRepeatTimes, normalizeRepeatTimes } from \"../light/repeat.js\";\n\nexport function registerLightSend(light: CliCommand): void {\n light\n .command(\"send\")\n .description(\"发送灯效指令到硬件设备\")\n .requiredOption(\"--segments <json>\", \"灯效参数 JSON\")\n .option(\"--repeat\", \"无限循环播放(默认仅播放一轮)\")\n .option(\"--repeat-times <n>\", \"整条组合重复次数:0=无限,1=一轮;当前 ANCS 路径不支持 >=2\")\n .action(async (opts: { segments: string; repeat?: boolean; repeatTimes?: string }) => {\n let apiKey: string;\n try {\n apiKey = requireApiKey();\n } catch (e: any) {\n exitError(\"AUTH_REQUIRED\", e.message);\n }\n\n const segments = parseAndValidateSegments(opts.segments);\n let repeatTimes: number;\n try {\n repeatTimes = normalizeRepeatTimes({\n repeat: opts.repeat,\n repeat_times: opts.repeatTimes === undefined ? undefined : Number(opts.repeatTimes),\n });\n assertAncsRepeatTimes(repeatTimes);\n } catch (e: any) {\n exitError(\"VALIDATION_FAILED\", e.message);\n }\n\n const result = await sendLightEffect(\n apiKey,\n segments,\n undefined,\n { repeat_times: repeatTimes },\n );\n\n if (!result.ok) {\n exitError(\"HTTP_ERROR\", `请求失败: ${result.status} ${result.error}`);\n }\n\n output({ ok: true, bizUniqueId: result.bizUniqueId, response: result.response });\n });\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { LIGHT_RULE_TOOL_NAME_LIST } from \"../light-rules/names.js\";\nimport { type CliCommand, output, exitError } from \"./helpers.js\";\n\ntype JsonObject = Record<string, unknown>;\n\nfunction isObject(value: unknown): value is JsonObject {\n return !!value && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction ensureArray(obj: JsonObject, key: string): unknown[] {\n const current = obj[key];\n if (Array.isArray(current)) return current;\n const next: unknown[] = [];\n obj[key] = next;\n return next;\n}\n\nfunction resolveConfigPath(): string {\n const fromEnv = process.env.OPENCLAW_CONFIG_PATH?.trim();\n if (fromEnv) return fromEnv;\n return join(homedir(), \".openclaw\", \"openclaw.json\");\n}\n\nconst LIGHT_TOOLS = [\"light_control\", ...LIGHT_RULE_TOOL_NAME_LIST] as const;\n\nfunction upsertLightControlAlsoAllow(cfg: JsonObject): {\n globalChanged: boolean;\n mainAgentChanged: boolean;\n} {\n if (!isObject(cfg.tools)) cfg.tools = {};\n const toolsAlsoAllow = ensureArray(cfg.tools as JsonObject, \"alsoAllow\");\n let globalChanged = false;\n for (const tool of LIGHT_TOOLS) {\n if (!toolsAlsoAllow.includes(tool)) {\n toolsAlsoAllow.push(tool);\n globalChanged = true;\n }\n }\n\n if (!isObject(cfg.agents)) cfg.agents = {};\n const agents = cfg.agents as JsonObject;\n const list = ensureArray(agents, \"list\");\n let mainAgent = list.find(\n (item) => isObject(item) && item.id === \"main\",\n ) as JsonObject | undefined;\n if (!mainAgent) {\n mainAgent = { id: \"main\" };\n list.push(mainAgent);\n }\n if (!isObject(mainAgent.tools)) mainAgent.tools = {};\n const mainAlsoAllow = ensureArray(mainAgent.tools as JsonObject, \"alsoAllow\");\n let mainAgentChanged = false;\n for (const tool of LIGHT_TOOLS) {\n if (!mainAlsoAllow.includes(tool)) {\n mainAlsoAllow.push(tool);\n mainAgentChanged = true;\n }\n }\n\n return { globalChanged, mainAgentChanged };\n}\n\nexport function registerLightSetupTools(light: CliCommand): void {\n light\n .command(\"setup\")\n .description(\"自动放行 light_control(写入 tools.alsoAllow 与 agents.main.tools.alsoAllow)\")\n .action(() => {\n const configPath = resolveConfigPath();\n if (!existsSync(configPath)) {\n exitError(\"CONFIG_NOT_FOUND\", `未找到配置文件: ${configPath}`);\n }\n\n let cfg: JsonObject = {};\n try {\n const raw = readFileSync(configPath, \"utf-8\");\n const parsed = JSON.parse(raw);\n if (isObject(parsed)) cfg = parsed;\n } catch (err: any) {\n exitError(\"CONFIG_INVALID\", `读取/解析配置失败: ${err?.message ?? String(err)}`);\n }\n\n const result = upsertLightControlAlsoAllow(cfg);\n try {\n mkdirSync(dirname(configPath), { recursive: true });\n writeFileSync(configPath, JSON.stringify(cfg, null, 2) + \"\\n\", \"utf-8\");\n } catch (err: any) {\n exitError(\"WRITE_FAILED\", `写入配置失败: ${err?.message ?? String(err)}`);\n }\n\n output({\n ok: true,\n configPath,\n changed: result.globalChanged || result.mainAgentChanged,\n updates: {\n toolsAlsoAllow: result.globalChanged ? \"added\" : \"already_exists\",\n mainAgentAlsoAllow: result.mainAgentChanged ? \"added\" : \"already_exists\",\n },\n next: \"请执行: openclaw gateway restart\",\n });\n });\n}\n","import { loadApiKey } from \"../auth/credentials.js\";\nimport { getEnvUrls } from \"../env.js\";\nimport { output, exitError } from \"./helpers.js\";\nimport type { CliCommand, CliContext } from \"./helpers.js\";\nimport type { TunnelStatusInfo } from \"../tunnel/relay-client.js\";\nimport { assessTunnelStatus } from \"../tunnel/status.js\";\n\nfunction formatMessage(status: TunnelStatusInfo): string {\n switch (status.state) {\n case \"connected\":\n return `隧道已连接(自 ${status.since})`;\n case \"connecting\":\n return `隧道正在连接(自 ${status.since},第 ${status.reconnectAttempt} 次重连)`;\n case \"disconnected\":\n return `隧道已断开(自 ${status.since})${status.lastDisconnectReason ? `,原因: ${status.lastDisconnectReason}` : \"\"},等待重连(第 ${status.reconnectAttempt} 次)`;\n case \"stopped\":\n return `隧道服务已停止(自 ${status.since})`;\n default:\n return `未知状态: ${status.state}`;\n }\n}\n\nexport function registerTunnelStatus(ntf: CliCommand, ctx: CliContext): void {\n ntf\n .command(\"tunnel-status\")\n .description(\"检查 Relay Tunnel 隧道连接状态(读取运行中服务的状态文件,不影响已有连接)\")\n .action(async () => {\n const tunnelUrl = getEnvUrls().relayTunnelUrl;\n const apiKey = loadApiKey();\n\n if (!tunnelUrl) {\n exitError(\n \"TUNNEL_NOT_CONFIGURED\",\n \"RELAY_TUNNEL_URL 未配置,隧道功能未启用。请在构建时设置 RELAY_TUNNEL_URL 环境变量。\",\n );\n }\n\n if (!apiKey) {\n exitError(\n \"TOKEN_MISSING\",\n \"API Key 未设置,隧道无法连接。请执行 openclaw ntf auth set-api-key <apiKey>\",\n );\n }\n\n if (!ctx.stateDir) {\n exitError(\n \"STATE_DIR_UNAVAILABLE\",\n \"无法确定状态目录,无法检查隧道状态。请在 openclaw 主环境中执行该命令。\",\n );\n }\n\n const assessment = assessTunnelStatus(ctx.stateDir);\n const status = assessment.status;\n\n if (!status) {\n exitError(\n assessment.issueCode ?? \"STATUS_NOT_FOUND\",\n assessment.issueMessage ??\n \"未找到隧道状态文件,隧道服务可能尚未启动过。请确认 openclaw 主进程正在运行。\",\n );\n }\n\n if (assessment.issueCode) {\n exitError(assessment.issueCode, assessment.issueMessage ?? formatMessage(status));\n }\n\n const ok = status.state === \"connected\";\n output({\n ok,\n tunnelUrl,\n connection: {\n state: status.state,\n since: status.since,\n reconnectAttempt: status.reconnectAttempt,\n lastDisconnectReason: status.lastDisconnectReason,\n },\n runtime: {\n lockOwnerPid: assessment.lock.pid,\n lockOwnerStartedAt: assessment.lock.startedAt,\n lockOwnerActive: assessment.lock.active,\n },\n message: formatMessage(status),\n });\n\n if (!ok) process.exit(1);\n });\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { TunnelStatusInfo } from \"./relay-client.js\";\n\nexport const TUNNEL_STATUS_REL_PATH = join(\n \"plugins\",\n \"phone-notifications\",\n \"tunnel-status.json\",\n);\nexport const TUNNEL_LOCK_REL_PATH = join(\n \"plugins\",\n \"phone-notifications\",\n \"relay-tunnel.lock\",\n);\n\ntype TunnelState = TunnelStatusInfo[\"state\"];\n\ninterface TunnelLockInfo {\n pid: number;\n startedAt: string;\n}\n\nexport interface TunnelStatusAssessment {\n status: TunnelStatusInfo | null;\n issueCode: \"STATUS_NOT_FOUND\" | \"STATUS_INVALID\" | \"STATUS_STALE\" | null;\n issueMessage: string | null;\n statusFilePath: string;\n lockFilePath: string;\n lock: {\n exists: boolean;\n pid: number | null;\n startedAt: string | null;\n active: boolean | null;\n };\n}\n\nfunction isTunnelState(value: unknown): value is TunnelState {\n return (\n value === \"connected\" ||\n value === \"connecting\" ||\n value === \"disconnected\" ||\n value === \"stopped\"\n );\n}\n\nfunction isTunnelStatusInfo(value: unknown): value is TunnelStatusInfo {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return false;\n const obj = value as Record<string, unknown>;\n return (\n isTunnelState(obj.state) &&\n typeof obj.since === \"string\" &&\n typeof obj.reconnectAttempt === \"number\" &&\n (obj.lastDisconnectReason === undefined ||\n typeof obj.lastDisconnectReason === \"string\")\n );\n}\n\nfunction parseTunnelLockInfo(value: unknown): TunnelLockInfo | null {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return null;\n const obj = value as Record<string, unknown>;\n return typeof obj.pid === \"number\" && typeof obj.startedAt === \"string\"\n ? { pid: obj.pid, startedAt: obj.startedAt }\n : null;\n}\n\nfunction isProcessAlive(pid: number): boolean {\n if (!Number.isInteger(pid) || pid <= 0) return false;\n if (pid === process.pid) return true;\n try {\n process.kill(pid, 0);\n return true;\n } catch (err: any) {\n return err?.code === \"EPERM\";\n }\n}\n\nfunction isStatusOlderThanLock(\n statusSince: string,\n lockStartedAt: string,\n): boolean {\n const statusTs = Date.parse(statusSince);\n const lockTs = Date.parse(lockStartedAt);\n if (Number.isNaN(statusTs) || Number.isNaN(lockTs)) return false;\n return statusTs + 1000 < lockTs;\n}\n\nfunction staleStatusMessage(\n status: TunnelStatusInfo,\n lock: TunnelStatusAssessment[\"lock\"],\n): string {\n const prefix = `隧道状态文件显示已连接(自 ${status.since})`;\n\n if (!lock.exists) {\n return `${prefix},但未找到本地运行锁,状态可能已过期。请重启 openclaw 主进程。`;\n }\n\n if (lock.pid === null || lock.startedAt === null) {\n return `${prefix},但本地运行锁内容不完整,无法确认当前连接是否仍然有效。请重启 openclaw 主进程。`;\n }\n\n if (lock.active === false) {\n return `${prefix},但本地运行锁仍指向已退出的进程 pid=${lock.pid},状态可能已过期。请重启 openclaw 主进程。`;\n }\n\n return `${prefix},但当前运行锁启动于 ${lock.startedAt},晚于状态时间,说明状态未随新进程刷新。请重启 openclaw 主进程。`;\n}\n\nexport function assessTunnelStatus(stateDir: string): TunnelStatusAssessment {\n const statusFilePath = join(stateDir, TUNNEL_STATUS_REL_PATH);\n const lockFilePath = join(stateDir, TUNNEL_LOCK_REL_PATH);\n\n if (!existsSync(statusFilePath)) {\n return {\n status: null,\n issueCode: \"STATUS_NOT_FOUND\",\n issueMessage:\n \"未找到隧道状态文件,隧道服务可能尚未启动过。请确认 openclaw 主进程正在运行。\",\n statusFilePath,\n lockFilePath,\n lock: {\n exists: existsSync(lockFilePath),\n pid: null,\n startedAt: null,\n active: null,\n },\n };\n }\n\n let rawStatus: unknown;\n try {\n rawStatus = JSON.parse(readFileSync(statusFilePath, \"utf-8\"));\n } catch {\n return {\n status: null,\n issueCode: \"STATUS_INVALID\",\n issueMessage: \"隧道状态文件解析失败,文件内容损坏或格式不正确。请重启 openclaw 主进程。\",\n statusFilePath,\n lockFilePath,\n lock: {\n exists: existsSync(lockFilePath),\n pid: null,\n startedAt: null,\n active: null,\n },\n };\n }\n\n if (!isTunnelStatusInfo(rawStatus)) {\n return {\n status: null,\n issueCode: \"STATUS_INVALID\",\n issueMessage: \"隧道状态文件缺少必要字段或字段类型不正确。请重启 openclaw 主进程。\",\n statusFilePath,\n lockFilePath,\n lock: {\n exists: existsSync(lockFilePath),\n pid: null,\n startedAt: null,\n active: null,\n },\n };\n }\n\n const status = rawStatus;\n const lockExists = existsSync(lockFilePath);\n let lockInfo: TunnelLockInfo | null = null;\n\n if (lockExists) {\n try {\n lockInfo = parseTunnelLockInfo(JSON.parse(readFileSync(lockFilePath, \"utf-8\")));\n } catch {\n lockInfo = null;\n }\n }\n\n const lock = {\n exists: lockExists,\n pid: lockInfo?.pid ?? null,\n startedAt: lockInfo?.startedAt ?? null,\n active: lockInfo ? isProcessAlive(lockInfo.pid) : null,\n };\n\n if (status.state === \"connected\") {\n const isStale =\n !lock.exists ||\n lock.pid === null ||\n lock.startedAt === null ||\n lock.active === false ||\n isStatusOlderThanLock(status.since, lock.startedAt);\n\n if (isStale) {\n return {\n status,\n issueCode: \"STATUS_STALE\",\n issueMessage: staleStatusMessage(status, lock),\n statusFilePath,\n lockFilePath,\n lock,\n };\n }\n }\n\n return {\n status,\n issueCode: null,\n issueMessage: null,\n statusFilePath,\n lockFilePath,\n lock,\n };\n}\n","import {\n type CliCommand,\n type CliContext,\n resolveNotificationsDir,\n output,\n exitError,\n} from \"./helpers.js\";\n\nexport function registerNtfStoragePath(ntf: CliCommand, ctx: CliContext): void {\n ntf\n .command(\"storage-path\")\n .description(\"查询通知存储路径\")\n .action(() => {\n const dir = resolveNotificationsDir(ctx);\n if (!dir) exitError(\"STORAGE_UNAVAILABLE\", \"通知存储目录不可用\");\n output({ ok: true, path: dir });\n });\n}\n","import { existsSync, readFileSync, readdirSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport {\n type CliCommand,\n type CliContext,\n filterDateRange,\n today,\n daysAgo,\n output,\n exitError,\n} from \"./helpers.js\";\n\n/** Resolve the plugin logs directory from stateDir */\nfunction resolveLogsDir(ctx: CliContext): string | null {\n if (ctx.stateDir) {\n const dir = join(\n ctx.stateDir,\n \"plugins\",\n \"phone-notifications\",\n \"logs\",\n );\n if (existsSync(dir)) return dir;\n }\n return null;\n}\n\n/** List available log date keys (YYYY-MM-DD) sorted descending */\nfunction listLogDateKeys(dir: string): string[] {\n const pattern = /^(\\d{4}-\\d{2}-\\d{2})\\.log$/;\n const keys: string[] = [];\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n if (!entry.isFile()) continue;\n const m = pattern.exec(entry.name);\n if (m) keys.push(m[1]);\n }\n return keys.sort().reverse();\n}\n\n/** Read log lines from a date file, optionally filtering by keyword */\nfunction collectLogLines(\n dir: string,\n dateKey: string,\n keyword: string | undefined,\n limit: number,\n collected: string[],\n): void {\n const filePath = join(dir, `${dateKey}.log`);\n if (!existsSync(filePath)) return;\n\n const content = readFileSync(filePath, \"utf-8\");\n const lowerKeyword = keyword?.toLowerCase();\n\n for (const line of content.split(\"\\n\")) {\n if (collected.length >= limit) return;\n if (!line) continue;\n if (lowerKeyword && !line.toLowerCase().includes(lowerKeyword)) continue;\n collected.push(`[${dateKey}] ${line}`);\n }\n}\n\nexport function registerLogSearch(ntf: CliCommand, ctx: CliContext): void {\n ntf\n .command(\"log\")\n .description(\"查看/搜索插件日志\")\n .option(\"--keyword <text>\", \"按关键词过滤日志\")\n .option(\"--from <date>\", \"开始日期 YYYY-MM-DD\", daysAgo(7))\n .option(\"--to <date>\", \"结束日期 YYYY-MM-DD\", today())\n .option(\"--limit <n>\", \"最大返回条数\", \"50\")\n .action(\n (opts: {\n keyword?: string;\n from: string;\n to: string;\n limit: string;\n }) => {\n const dir = resolveLogsDir(ctx);\n if (!dir) exitError(\"LOGS_UNAVAILABLE\", \"日志目录不可用\");\n\n const keys = filterDateRange(listLogDateKeys(dir), opts.from, opts.to);\n const limit = parseInt(opts.limit, 10) || 50;\n const results: string[] = [];\n\n for (const dateKey of keys) {\n if (results.length >= limit) break;\n collectLogLines(dir, dateKey, opts.keyword, limit, results);\n }\n\n output({\n ok: true,\n keyword: opts.keyword ?? null,\n total: results.length,\n lines: results,\n });\n },\n );\n}\n","import { spawnSync } from \"node:child_process\";\nimport {\n readPersistedEnvName,\n saveEnvName,\n getEnvUrls,\n getAvailableEnvs,\n type EnvName,\n} from \"../env.js\";\nimport { detectHostKind } from \"../host.js\";\nimport { output, exitError } from \"./helpers.js\";\nimport type { CliCommand } from \"./helpers.js\";\nimport { scheduleGatewayRestart } from \"../update/restart.js\";\n\nconst GATEWAY_RESTART_TIMEOUT_MS = 30_000;\n\nconst NOOP_LOGGER = {\n info() {\n // noop\n },\n warn() {\n // noop\n },\n error() {\n // noop\n },\n};\n\nexport interface EnvShowPayload {\n ok: true;\n env: EnvName;\n source: \".env\" | \"default\";\n lightApiUrl: string;\n relayTunnelUrl: string;\n availableEnvs: EnvName[];\n}\n\nexport interface EnvReloadResult {\n attempted: boolean;\n ok: boolean;\n method: \"signal\" | \"cli\" | \"skipped\";\n command?: string;\n message: string;\n detail?: string;\n}\n\nexport interface EnvSwitchPayload {\n ok: true;\n message: string;\n env: EnvName;\n lightApiUrl: string;\n relayTunnelUrl: string;\n reload: EnvReloadResult;\n}\n\nexport interface EnvCliDeps {\n readPersistedEnvName?: () => EnvName | undefined;\n scheduleGatewayRestart?: () => { scheduled: boolean };\n detectHostKind?: () => \"openclaw\" | \"qclaw\";\n spawnSync?: typeof spawnSync;\n hostCli?: string;\n}\n\nexport function buildEnvShowPayload(deps: EnvCliDeps = {}): EnvShowPayload {\n const persistedEnv = deps.readPersistedEnvName?.() ?? readPersistedEnvName();\n const env = persistedEnv ?? \"production\";\n const urls = getEnvUrls(env);\n\n return {\n ok: true,\n env,\n source: persistedEnv ? \".env\" : \"default\",\n lightApiUrl: urls.lightApiUrl,\n relayTunnelUrl: urls.relayTunnelUrl,\n availableEnvs: getAvailableEnvs(),\n };\n}\n\nexport function triggerGatewayReloadAfterEnvSwitch(\n deps: EnvCliDeps = {},\n): EnvReloadResult {\n const scheduleRestart =\n deps.scheduleGatewayRestart ??\n (() => scheduleGatewayRestart(NOOP_LOGGER));\n const scheduled = scheduleRestart();\n if (scheduled.scheduled) {\n return {\n attempted: true,\n ok: true,\n method: \"signal\",\n message: \"已自动触发 gateway 进程内重载\",\n };\n }\n\n const hostKind = deps.detectHostKind?.() ?? detectHostKind();\n if (hostKind === \"qclaw\") {\n return {\n attempted: false,\n ok: false,\n method: \"skipped\",\n message: \"当前宿主为 QClaw,请重启 QClaw 桌面应用后使环境切换生效\",\n };\n }\n\n const hostCli = deps.hostCli?.trim() || process.env.HOST_CLI?.trim() || \"openclaw\";\n const command = `${hostCli} gateway restart`;\n const run = deps.spawnSync ?? spawnSync;\n const result = run(hostCli, [\"gateway\", \"restart\"], {\n encoding: \"utf-8\",\n stdio: \"pipe\",\n timeout: GATEWAY_RESTART_TIMEOUT_MS,\n });\n\n if (!result.error && result.status === 0) {\n return {\n attempted: true,\n ok: true,\n method: \"cli\",\n command,\n message: `已自动触发 ${command}`,\n };\n }\n\n const stderr =\n typeof result.stderr === \"string\" ? result.stderr.trim() : \"\";\n const errorMessage = result.error?.message?.trim();\n return {\n attempted: true,\n ok: false,\n method: \"cli\",\n command,\n message: `已切换环境,但自动重载未完成,请手动运行: ${command}`,\n detail:\n stderr ||\n errorMessage ||\n (typeof result.status === \"number\"\n ? `exit status=${result.status}`\n : undefined),\n };\n}\n\nexport function buildEnvSwitchPayload(\n envName: EnvName,\n deps: EnvCliDeps = {},\n): EnvSwitchPayload {\n saveEnvName(envName);\n const urls = getEnvUrls(envName);\n const reload = triggerGatewayReloadAfterEnvSwitch(deps);\n\n return {\n ok: true,\n message: reload.ok\n ? `已切换到 ${envName} 环境,并已触发重载`\n : `已切换到 ${envName} 环境`,\n env: envName,\n lightApiUrl: urls.lightApiUrl,\n relayTunnelUrl: urls.relayTunnelUrl,\n reload,\n };\n}\n\nexport function registerEnvCli(ntf: CliCommand, deps: EnvCliDeps = {}): void {\n const env = ntf.command(\"env\").description(\"环境管理(切换 test / production)\");\n\n env\n .command(\"show\")\n .description(\"显示当前环境及对应的接口地址\")\n .action(() => {\n output(buildEnvShowPayload(deps));\n });\n\n env\n .command(\"switch <env>\")\n .description(\"切换环境(test / production)\")\n .action((envName: string) => {\n const available = getAvailableEnvs();\n if (!available.includes(envName as any)) {\n exitError(\n \"INVALID_ENV\",\n `无效的环境名称: ${envName},可选值: ${available.join(\", \")}`,\n );\n }\n output(buildEnvSwitchPayload(envName as EnvName, deps));\n });\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { createInterface } from \"node:readline\";\nimport { resolveConfigPath, resolveStateDir } from \"../host.js\";\nimport { output } from \"./helpers.js\";\nimport type { CliCommand, CliContext } from \"./helpers.js\";\nimport type { CheckResult, JsonObject, Severity } from \"./doctor/types.js\";\nimport { allCheckers } from \"./doctor/checkers.js\";\n\nfunction isObject(v: unknown): v is JsonObject {\n return !!v && typeof v === \"object\" && !Array.isArray(v);\n}\n\nfunction readConfig(configPath: string): JsonObject {\n if (!existsSync(configPath)) return {};\n try {\n const parsed = JSON.parse(readFileSync(configPath, \"utf-8\"));\n return isObject(parsed) ? parsed : {};\n } catch {\n return {};\n }\n}\n\nfunction severityIcon(s: Severity): string {\n switch (s) {\n case \"critical\":\n return \"\\x1b[31m[CRITICAL]\\x1b[0m\";\n case \"warn\":\n return \"\\x1b[33m[WARN]\\x1b[0m\";\n case \"info\":\n return \"\\x1b[36m[INFO]\\x1b[0m\";\n }\n}\n\nfunction severityOrder(s: Severity): number {\n switch (s) {\n case \"critical\":\n return 0;\n case \"warn\":\n return 1;\n case \"info\":\n return 2;\n }\n}\n\nfunction confirm(question: string): Promise<boolean> {\n const rl = createInterface({ input: process.stdin, output: process.stderr });\n return new Promise((resolve) => {\n rl.question(question, (answer) => {\n rl.close();\n resolve(answer.trim().toLowerCase() === \"y\");\n });\n });\n}\n\nasync function runDoctor(ctx: CliContext, json: boolean, fix?: boolean): Promise<void> {\n const stateDir = ctx.stateDir ?? resolveStateDir();\n const configPath = resolveConfigPath(stateDir);\n const cfg = readConfig(configPath);\n\n const checkCtx = { cfg, configPath, stateDir };\n\n // 执行所有 checker\n const issues: CheckResult[] = [];\n for (const checker of allCheckers) {\n const result = await checker(checkCtx);\n if (result) issues.push(result);\n }\n\n // 按严重级别排序\n issues.sort((a, b) => severityOrder(a.severity) - severityOrder(b.severity));\n\n // 统计\n const summary = { critical: 0, warn: 0, info: 0 };\n for (const issue of issues) {\n summary[issue.severity]++;\n }\n\n // --json 模式\n if (json) {\n output({\n ok: issues.length === 0,\n summary,\n checks: issues.map((i) => ({\n id: i.id,\n severity: i.severity,\n title: i.title,\n detail: i.detail,\n autoFixable: i.fix !== null,\n fixDescription: i.fixDescription,\n })),\n });\n if (issues.length > 0) process.exit(1);\n return;\n }\n\n // 人类可读输出\n const log = console.error; // stderr,不污染 stdout\n log(\"\\n\\x1b[1m🔍 正在检查环境...\\x1b[0m\\n\");\n\n if (issues.length === 0) {\n log(\"\\x1b[32m✅ 所有检查通过,未发现问题。\\x1b[0m\\n\");\n output({ ok: true, summary });\n return;\n }\n\n for (const issue of issues) {\n log(`${severityIcon(issue.severity)} ${issue.title}`);\n log(` ↳ ${issue.detail}`);\n log(` ↳ 修复: ${issue.fixDescription}`);\n log();\n }\n\n log(\n `检测完成: \\x1b[31m${summary.critical} critical\\x1b[0m · ` +\n `\\x1b[33m${summary.warn} warn\\x1b[0m · ` +\n `\\x1b[36m${summary.info} info\\x1b[0m\\n`,\n );\n\n // 找出可自动修复的\n const fixable = issues.filter((i) => i.fix !== null);\n\n if (fixable.length === 0) {\n log(\"以上问题均需手动修复,请参考上方提示。\\n\");\n output({ ok: false, summary });\n process.exit(1);\n return;\n }\n\n log(`发现 ${fixable.length} 个可自动修复的问题:`);\n for (const issue of fixable) {\n log(` • ${issue.title} → ${issue.fixDescription}`);\n }\n log();\n\n const yes = fix === true || await confirm(\"是否执行自动修复?[y/N]: \");\n if (!yes) {\n log(\"\\n已取消。\\n\");\n output({ ok: false, summary, fixed: 0 });\n process.exit(1);\n return;\n }\n\n log();\n let fixed = 0;\n for (const issue of fixable) {\n try {\n await issue.fix!();\n log(`\\x1b[32m✅\\x1b[0m ${issue.title} → ${issue.fixDescription}`);\n fixed++;\n } catch (err: any) {\n log(\n `\\x1b[31m❌\\x1b[0m ${issue.title} 修复失败: ${err?.message ?? String(err)}`,\n );\n }\n }\n\n const manualCount = issues.length - fixable.length;\n if (manualCount > 0) {\n log(`\\n⚠️ 还有 ${manualCount} 个问题需要手动处理,请参考上方提示。`);\n }\n\n log(`\\n修复完成 (${fixed}/${fixable.length})。建议执行: openclaw gateway restart\\n`);\n output({ ok: fixed === fixable.length && manualCount === 0, summary, fixed });\n if (fixed < fixable.length || manualCount > 0) process.exit(1);\n}\n\nexport function registerDoctor(ntf: CliCommand, ctx: CliContext): void {\n ntf\n .command(\"doctor\")\n .description(\"自检环境配置,检测安全风险和常见问题\")\n .option(\"--json\", \"以 JSON 格式输出结果(供脚本调用)\")\n .option(\"--fix\", \"自动修复可修复的问题(跳过确认提示)\")\n .action((opts: { json?: boolean; fix?: boolean }) => {\n return runDoctor(ctx, opts.json === true, opts.fix);\n });\n}\n","import { readFileSync, writeFileSync, copyFileSync } from \"node:fs\";\nimport type { Checker, JsonObject } from \"./types.js\";\n\nfunction isObject(v: unknown): v is JsonObject {\n return !!v && typeof v === \"object\" && !Array.isArray(v);\n}\n\nexport const checkDangerousFlags: Checker = ({ cfg, configPath }) => {\n const gateway = cfg.gateway;\n if (!isObject(gateway)) return null;\n\n const controlUi = gateway.controlUi;\n if (!isObject(controlUi)) return null;\n\n if (controlUi.dangerouslyDisableDeviceAuth !== true) return null;\n\n return {\n id: \"dangerous-flags\",\n severity: \"critical\",\n title: \"gateway.controlUi.dangerouslyDisableDeviceAuth 已启用\",\n detail: \"这会关闭 Control UI 的设备身份验证,任何人都可以访问控制面板。\",\n fixDescription: \"设为 false\",\n fix: () => {\n const raw = readFileSync(configPath, \"utf-8\");\n const config = JSON.parse(raw) as JsonObject;\n const gw = config.gateway as JsonObject;\n const cui = gw.controlUi as JsonObject;\n cui.dangerouslyDisableDeviceAuth = false;\n copyFileSync(configPath, configPath + \".bak\");\n writeFileSync(configPath, JSON.stringify(config, null, 2) + \"\\n\", \"utf-8\");\n },\n };\n};\n","import type { Checker, JsonObject } from \"./types.js\";\n\nfunction isObject(v: unknown): v is JsonObject {\n return !!v && typeof v === \"object\" && !Array.isArray(v);\n}\n\nexport const checkTrustedProxy: Checker = ({ cfg }) => {\n const gateway = cfg.gateway;\n if (!isObject(gateway)) return null;\n\n const auth = gateway.auth;\n if (!isObject(auth)) return null;\n\n if (auth.mode !== \"trusted-proxy\") return null;\n\n return {\n id: \"trusted-proxy\",\n severity: \"critical\",\n title: \"gateway.auth.mode 为 trusted-proxy\",\n detail:\n \"认证委托给了反向代理。请确保: (1) 代理终止 TLS 并认证用户; \" +\n \"(2) gateway.trustedProxies 仅限代理 IP; \" +\n \"(3) 防火墙阻止直接访问 Gateway 端口。\",\n fixDescription: \"此项需手动检查代理配置,无法自动修复\",\n fix: null,\n };\n};\n\nexport const checkTrustedProxyAllowUsers: Checker = ({ cfg }) => {\n const gateway = cfg.gateway;\n if (!isObject(gateway)) return null;\n\n const auth = gateway.auth;\n if (!isObject(auth)) return null;\n\n if (auth.mode !== \"trusted-proxy\") return null;\n\n const tp = auth.trustedProxy;\n if (!isObject(tp)) return warnEmpty();\n\n const allowUsers = tp.allowUsers;\n if (!Array.isArray(allowUsers) || allowUsers.length === 0) return warnEmpty();\n\n return null;\n};\n\nfunction warnEmpty() {\n return {\n id: \"trusted-proxy-allow-users\",\n severity: \"warn\" as const,\n title: \"trusted-proxy 模式下 allowUsers 为空\",\n detail: \"任何通过代理认证的用户都可以访问 Gateway。\",\n fixDescription:\n '请编辑 openclaw.json,在 gateway.auth.trustedProxy.allowUsers 中添加允许的用户邮箱,例如 [\"nick@example.com\"]',\n fix: null,\n };\n}\n","import { statSync, chmodSync } from \"node:fs\";\nimport type { Checker } from \"./types.js\";\n\nexport const checkStateDirPerms: Checker = ({ stateDir }) => {\n let mode: number;\n try {\n mode = statSync(stateDir).mode;\n } catch {\n return null;\n }\n\n // 检查 group 和 other 是否有任何权限\n const otherBits = mode & 0o077;\n if (otherBits === 0) return null;\n\n const modeStr = \"0\" + (mode & 0o777).toString(8);\n\n return {\n id: \"state-dir-perms\",\n severity: \"warn\",\n title: `状态目录权限过于宽松 (${stateDir} mode=${modeStr})`,\n detail: \"其他用户可以读取该目录下的凭证和配置文件。\",\n fixDescription: \"chmod 700 \" + stateDir,\n fix: () => {\n chmodSync(stateDir, 0o700);\n },\n };\n};\n","import type { Checker, JsonObject } from \"./types.js\";\n\nfunction isObject(v: unknown): v is JsonObject {\n return !!v && typeof v === \"object\" && !Array.isArray(v);\n}\n\nexport const checkToolPolicy: Checker = ({ cfg }) => {\n const agents = cfg.agents;\n if (!isObject(agents)) return null;\n\n const list = agents.list;\n if (!Array.isArray(list)) return null;\n\n const permissiveAgents: string[] = [];\n\n for (const agent of list) {\n if (!isObject(agent)) continue;\n const id = String(agent.id ?? \"unknown\");\n\n // 如果 agent 没有设置 toolPolicy / profile,则视为使用 default(宽松)\n const tools = agent.tools;\n if (!isObject(tools)) {\n permissiveAgents.push(id);\n continue;\n }\n\n const profile = tools.profile;\n if (!profile || profile === \"default\") {\n permissiveAgents.push(id);\n }\n }\n\n if (permissiveAgents.length === 0) return null;\n\n return {\n id: \"tool-policy\",\n severity: \"warn\",\n title: \"扩展插件 tool policy 宽松\",\n detail: `以下 agent 使用了 default 策略: ${permissiveAgents.join(\", \")}。插件工具可能被未授权调用。`,\n fixDescription:\n \"建议为处理不可信输入的 agent 使用 minimal 或 coding profile,或配置明确的 tool allowlist。\",\n fix: null,\n };\n};\n","import { loadApiKey } from \"../../auth/credentials.js\";\nimport type { Checker } from \"./types.js\";\n\nexport const checkCredentials: Checker = () => {\n const apiKey = loadApiKey();\n if (apiKey) return null;\n\n return {\n id: \"credentials\",\n severity: \"critical\",\n title: \"API Key 未配置\",\n detail:\n \"未在 credentials.json 中找到 apiKey,隧道和推送等功能无法正常工作。\",\n fixDescription:\n \"请执行: openclaw ntf auth set-api-key <your-api-key>\",\n fix: null,\n };\n};\n","import type { Checker } from \"./types.js\";\nimport { assessTunnelStatus } from \"../../tunnel/status.js\";\n\nexport const checkTunnel: Checker = ({ stateDir }) => {\n const assessment = assessTunnelStatus(stateDir);\n const status = assessment.status;\n\n if (assessment.issueCode === \"STATUS_NOT_FOUND\") {\n return {\n id: \"tunnel\",\n severity: \"warn\",\n title: \"隧道状态文件不存在\",\n detail: assessment.issueMessage ?? \"隧道服务可能尚未启动过,或状态文件已被删除。\",\n fixDescription: \"请确认 openclaw 主进程正在运行\",\n fix: null,\n };\n }\n\n if (assessment.issueCode === \"STATUS_INVALID\") {\n return {\n id: \"tunnel\",\n severity: \"warn\",\n title: \"隧道状态文件解析失败\",\n detail: assessment.issueMessage ?? \"文件内容损坏或格式不正确。\",\n fixDescription: \"请重启 openclaw 主进程\",\n fix: null,\n };\n }\n\n if (assessment.issueCode === \"STATUS_STALE\") {\n return {\n id: \"tunnel\",\n severity: \"warn\",\n title: \"隧道状态已过期\",\n detail: assessment.issueMessage ?? \"隧道状态文件仍显示已连接,但运行时状态已失效。\",\n fixDescription: \"请重启 openclaw 主进程\",\n fix: null,\n };\n }\n\n if (!status || status.state === \"connected\") return null;\n\n const reasonSuffix = status.lastDisconnectReason\n ? `,原因: ${status.lastDisconnectReason}`\n : \"\";\n\n return {\n id: \"tunnel\",\n severity: \"warn\",\n title: `隧道未连接 (state=${status.state})`,\n detail: `隧道自 ${status.since} 处于 ${status.state} 状态${reasonSuffix},重连次数: ${status.reconnectAttempt}`,\n fixDescription: \"请检查网络连接或重启 openclaw 主进程\",\n fix: null,\n };\n};\n","import type { Checker } from \"./types.js\";\n\nconst MIN_MAJOR = 22;\nconst MIN_MINOR = 12;\n\nexport const checkNodeVersion: Checker = () => {\n const version = process.versions.node;\n const [major, minor] = version.split(\".\").map(Number);\n\n if (major > MIN_MAJOR || (major === MIN_MAJOR && minor >= MIN_MINOR)) {\n return null;\n }\n\n return {\n id: \"node-version\",\n severity: \"warn\",\n title: `Node.js 版本过低 (v${version})`,\n detail: `要求 >= ${MIN_MAJOR}.${MIN_MINOR}.0,当前为 v${version}。`,\n fixDescription: `请升级 Node.js 到 ${MIN_MAJOR}.${MIN_MINOR}.0 或更高版本`,\n fix: null,\n };\n};\n","import { loadEnvName } from \"../../env.js\";\nimport { resolveUpdateChannel } from \"../../update/channel.js\";\nimport { PLUGIN_VERSION } from \"../../version.js\";\nimport type { Checker } from \"./types.js\";\n\nexport const checkPluginVersion: Checker = async () => {\n const channel = resolveUpdateChannel({\n envName: loadEnvName(),\n });\n\n let latest: string;\n try {\n const res = await fetch(\n `https://registry.npmjs.org/@yoooclaw/phone-notifications/${channel}`,\n { signal: AbortSignal.timeout(5000) },\n );\n if (!res.ok) return null;\n const data = (await res.json()) as { version?: string };\n latest = data.version ?? \"\";\n } catch {\n // 网络不可用时跳过\n return null;\n }\n\n if (!latest || latest === PLUGIN_VERSION) return null;\n\n return {\n id: \"plugin-version\",\n severity: \"info\",\n title: `插件版本可更新 (当前 ${PLUGIN_VERSION} → 最新 ${latest})`,\n detail: \"有新版本可用,建议更新以获取最新功能和修复。\",\n fixDescription: `请执行: openclaw extension install @yoooclaw/phone-notifications@${latest}`,\n fix: null,\n };\n};\n","import type { Checker } from \"./types.js\";\nimport { checkDangerousFlags } from \"./check-dangerous-flags.js\";\nimport { checkTrustedProxy, checkTrustedProxyAllowUsers } from \"./check-trusted-proxy.js\";\nimport { checkStateDirPerms } from \"./check-state-dir-perms.js\";\nimport { checkToolPolicy } from \"./check-tool-policy.js\";\nimport { checkCredentials } from \"./check-credentials.js\";\nimport { checkTunnel } from \"./check-tunnel.js\";\nimport { checkNodeVersion } from \"./check-node-version.js\";\nimport { checkPluginVersion } from \"./check-plugin-version.js\";\n\n/** 所有 checker,按优先级排列 */\nexport const allCheckers: Checker[] = [\n // critical\n checkDangerousFlags,\n checkTrustedProxy,\n checkCredentials,\n // warn\n checkTrustedProxyAllowUsers,\n checkStateDirPerms,\n checkToolPolicy,\n checkTunnel,\n // info\n checkNodeVersion,\n checkPluginVersion,\n];\n","import {\n type CliCommand,\n type CliContext,\n resolveRecordingsDir,\n readRecordingIndex,\n output,\n exitError,\n} from \"./helpers.js\";\n\nexport function registerRecList(rec: CliCommand, ctx: CliContext): void {\n rec\n .command(\"list\")\n .description(\"列出所有录音(可按状态过滤)\")\n .option(\"--status <status>\", \"按传输状态过滤(如 synced, transcribed)\")\n .action((opts: { status?: string }) => {\n const dir = resolveRecordingsDir(ctx);\n if (!dir) exitError(\"STORAGE_UNAVAILABLE\", \"录音存储目录不可用\");\n\n let recordings = readRecordingIndex(dir);\n\n if (opts.status) {\n recordings = recordings.filter((r) => r.status === opts.status);\n }\n\n const items = recordings.map((r) => ({\n id: r.id,\n name: r.metadata.name,\n duration_sec: r.metadata.duration_sec,\n status: r.status,\n file_size_bytes: r.metadata.file_size_bytes,\n has_audio: !!r.audioFile,\n has_transcript: !!r.transcriptFile,\n created_at: r.metadata.created_at,\n updated_at: r.updatedAt,\n error: r.lastError ?? null,\n }));\n\n output({ ok: true, total: items.length, recordings: items });\n });\n}\n","import {\n type CliCommand,\n type CliContext,\n resolveRecordingsDir,\n readRecordingIndex,\n output,\n exitError,\n} from \"./helpers.js\";\n\nexport function registerRecStatus(rec: CliCommand, ctx: CliContext): void {\n rec\n .command(\"status <id>\")\n .description(\"查看单条录音详情\")\n .action((id: string) => {\n const dir = resolveRecordingsDir(ctx);\n if (!dir) exitError(\"STORAGE_UNAVAILABLE\", \"录音存储目录不可用\");\n\n const recordings = readRecordingIndex(dir);\n const entry = recordings.find((r) => r.id === id);\n\n if (!entry) {\n exitError(\"NOT_FOUND\", `录音不存在: ${id}`);\n }\n\n output({\n ok: true,\n recording: {\n id: entry.id,\n name: entry.metadata.name,\n duration_sec: entry.metadata.duration_sec,\n file_size_bytes: entry.metadata.file_size_bytes,\n status: entry.status,\n created_at: entry.metadata.created_at,\n location: entry.metadata.location ?? null,\n markers: entry.metadata.markers ?? [],\n audioFile: entry.audioFile ?? null,\n srtFile: entry.srtFile ?? null,\n transcriptDataFile: entry.transcriptDataFile ?? null,\n transcriptFile: entry.transcriptFile ?? null,\n summaryFile: entry.summaryFile ?? null,\n title: entry.title ?? null,\n error: entry.lastError ?? null,\n ingestedAt: entry.ingestedAt,\n updatedAt: entry.updatedAt,\n },\n });\n });\n}\n","import {\n type CliCommand,\n type CliContext,\n resolveRecordingsDir,\n output,\n exitError,\n} from \"./helpers.js\";\n\nexport function registerRecStoragePath(\n rec: CliCommand,\n ctx: CliContext,\n): void {\n rec\n .command(\"storage-path\")\n .description(\"查询录音存储路径\")\n .action(() => {\n const dir = resolveRecordingsDir(ctx);\n if (!dir) exitError(\"STORAGE_UNAVAILABLE\", \"录音存储目录不可用\");\n output({ ok: true, path: dir });\n });\n}\n","import { createInterface } from \"node:readline\";\nimport { writeFileSync, existsSync, readFileSync } from \"node:fs\";\nimport type { CliCommand, CliContext } from \"./helpers.js\";\nimport { resolveAsrConfigPath, output } from \"./helpers.js\";\nimport type { AsrConfig, WhisperModelSize, WhisperBackend, WhisperModelSource } from \"../types.js\";\n\n// ─── Prompt helpers ───\n\ntype Rl = ReturnType<typeof createInterface>;\n\nfunction ask(rl: Rl, question: string): Promise<string> {\n return new Promise((resolve) => rl.question(question, resolve));\n}\n\n/**\n * Ask for a single choice from a numbered list.\n * Writes the list and prompt to stderr; returns the 0-based index of the chosen item.\n */\nasync function askChoice(\n rl: Rl,\n prompt: string,\n choices: readonly string[],\n defaultIdx = 0,\n): Promise<number> {\n choices.forEach((c, i) => {\n const marker = i === defaultIdx ? \"●\" : \"○\";\n process.stderr.write(` ${marker} ${i + 1}. ${c}\\n`);\n });\n while (true) {\n const ans = (await ask(rl, `${prompt} [1-${choices.length},默认 ${defaultIdx + 1}]: `)).trim();\n if (!ans) return defaultIdx;\n const n = parseInt(ans, 10);\n if (!isNaN(n) && n >= 1 && n <= choices.length) return n - 1;\n process.stderr.write(` 请输入 1-${choices.length} 之间的数字\\n`);\n }\n}\n\n/** Ask for a value; returns undefined if user presses Enter with no input. */\nasync function askOptional(rl: Rl, prompt: string): Promise<string | undefined> {\n const ans = (await ask(rl, `${prompt} [可选,直接回车跳过]: `)).trim();\n return ans || undefined;\n}\n\n// ─── Mode-specific setup flows ───\n\nasync function setupApi(rl: Rl): Promise<AsrConfig> {\n process.stderr.write(\"\\n─── 云端 ASR(model-proxy)配置 ───\\n\\n\");\n process.stderr.write(\"说明:不再填写第三方 API Key,插件会复用当前账号的 API Key 调用 model-proxy 长录音接口。\\n\\n\");\n\n const endpoint = await askOptional(rl, \"自定义 model-proxy submit-task 端点 URL\");\n const language = await askOptional(rl, \"语言提示(如 zh / en)\");\n const enableNormalizationInput = await askOptional(rl, \"启用文本规范化 ITN?(y/N)\");\n const normalized = enableNormalizationInput?.trim().toLowerCase();\n const enableNormalization =\n normalized === \"y\" || normalized === \"yes\" || normalized === \"true\";\n\n return {\n mode: \"api\",\n api: {\n ...(endpoint ? { endpoint } : {}),\n ...(language ? { language } : {}),\n ...(enableNormalizationInput ? { enableNormalization } : {}),\n },\n };\n}\n\nasync function setupLocal(rl: Rl): Promise<AsrConfig> {\n process.stderr.write(\"\\n─── 本地 Whisper 转写配置 ───\\n\\n\");\n\n process.stderr.write(\"模型大小:\\n\");\n const modelChoices = [\n \"自动选择(根据可用内存推荐)\",\n \"tiny\",\n \"base\",\n \"small\",\n \"medium\",\n \"large-v3\",\n ] as const;\n const modelIdx = await askChoice(rl, \"选择模型\", modelChoices);\n const model: WhisperModelSize | undefined =\n modelIdx === 0 ? undefined : (modelChoices[modelIdx] as WhisperModelSize);\n\n const language = await askOptional(rl, \"语言提示(如 zh / en,留空自动检测)\");\n\n process.stderr.write(\"\\n推理后端:\\n\");\n const backendChoices = [\n \"自动选择(根据运行环境推荐)\",\n \"coreml(Apple Silicon 推荐)\",\n \"cuda(NVIDIA GPU)\",\n \"cpu\",\n ] as const;\n const backendIdx = await askChoice(rl, \"选择后端\", backendChoices);\n const backend: WhisperBackend | undefined =\n backendIdx === 0 ? undefined : ([\"coreml\", \"cuda\", \"cpu\"] as const)[backendIdx - 1];\n\n process.stderr.write(\"\\n模型下载源:\\n\");\n const sourceChoices = [\n \"auto(自动探测,优先 HuggingFace,失败回退国内镜像)\",\n \"huggingface(海外直连)\",\n \"domestic(国内镜像)\",\n ] as const;\n const sourceIdx = await askChoice(rl, \"选择下载源\", sourceChoices);\n const modelSource: WhisperModelSource = ([\"auto\", \"huggingface\", \"domestic\"] as const)[sourceIdx];\n\n const modelMirrorUrl = await askOptional(rl, \"自定义模型下载地址(覆盖下载源)\");\n\n return {\n mode: \"local\",\n local: {\n ...(model ? { model } : {}),\n ...(language ? { language } : {}),\n ...(backend ? { backend } : {}),\n modelSource,\n ...(modelMirrorUrl ? { modelMirrorUrl } : {}),\n },\n };\n}\n\n// ─── Command registration ───\n\nexport function registerRecSetup(rec: CliCommand, ctx: CliContext): void {\n rec\n .command(\"setup\")\n .description(\"交互式配置 ASR 转写参数,保存到本地配置文件\")\n .action(async () => {\n const configPath = resolveAsrConfigPath(ctx);\n\n // Show existing config hint if present\n if (existsSync(configPath)) {\n try {\n const existing = JSON.parse(readFileSync(configPath, \"utf-8\")) as AsrConfig & { updatedAt?: string };\n process.stderr.write(`当前已有配置:mode = ${existing.mode}`);\n if (existing.updatedAt) process.stderr.write(`,更新于 ${existing.updatedAt}`);\n process.stderr.write(\"\\n\");\n } catch {\n // ignore parse errors\n }\n }\n\n const rl = createInterface({ input: process.stdin, output: process.stderr, terminal: true });\n\n try {\n process.stderr.write(\"\\n转写模式:\\n\");\n const modeIdx = await askChoice(rl, \"选择模式\", [\"api(云端 model-proxy 长录音)\", \"local(本地 Whisper)\"]);\n\n const config: AsrConfig = modeIdx === 0 ? await setupApi(rl) : await setupLocal(rl);\n const stored = { ...config, updatedAt: new Date().toISOString() };\n\n writeFileSync(configPath, JSON.stringify(stored, null, 2), \"utf-8\");\n process.stderr.write(`\\n✓ 配置已保存到 ${configPath}\\n\\n`);\n\n output({ ok: true, ...stored });\n } finally {\n rl.close();\n }\n });\n}\n","import { spawnSync } from \"node:child_process\";\nimport { writeFileSync, unlinkSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport os from \"node:os\";\nimport { resolveStateDir } from \"../host.js\";\nimport { PLUGIN_VERSION } from \"../version.js\";\nimport { output } from \"./helpers.js\";\nimport type { CliCommand, CliContext } from \"./helpers.js\";\n\nconst BASE_URL = \"https://artifact.yoooclaw.com/plugin\";\n\nasync function fetchText(url: string): Promise<string> {\n const res = await fetch(url, { signal: AbortSignal.timeout(30_000) });\n if (!res.ok) {\n throw new Error(`请求失败: ${url} (HTTP ${res.status})`);\n }\n return res.text();\n}\n\nasync function runUpdate(\n ctx: CliContext,\n opts: { json?: boolean; force?: boolean; beta?: boolean },\n): Promise<void> {\n const json = opts.json === true;\n const force = opts.force === true;\n const beta = opts.beta === true;\n const channel = beta ? \"beta\" : \"latest\";\n const log = (msg: string) => {\n if (!json) process.stderr.write(`${msg}\\n`);\n };\n\n log(`检查${beta ? \" beta\" : \"\"}最新版本 ...`);\n\n let latest: string;\n try {\n latest = (await fetchText(`${BASE_URL}/${channel}`)).trim();\n } catch (err: any) {\n const msg = `无法获取最新版本: ${err?.message ?? String(err)}`;\n if (json) {\n output({ ok: false, error: { code: \"FETCH_FAILED\", message: msg } });\n process.exit(1);\n }\n process.stderr.write(`\\x1b[31m[update] ERROR:\\x1b[0m ${msg}\\n`);\n process.exit(1);\n }\n\n const current = PLUGIN_VERSION;\n\n if (!force && current === latest) {\n log(`\\x1b[32m已是最新${beta ? \" beta\" : \"\"}版本 v${current}\\x1b[0m`);\n output({ ok: true, current, latest, channel, updated: false });\n return;\n }\n\n if (force) {\n log(`\\x1b[36m强制更新: v${current} → v${latest}\\x1b[0m`);\n } else {\n log(`\\x1b[36m发现新版本: v${current} → v${latest},开始更新 ...\\x1b[0m`);\n }\n\n // 下载 install-core.mjs\n log(\"下载安装脚本 ...\");\n let installScript: string;\n try {\n installScript = await fetchText(`${BASE_URL}/install-core.mjs`);\n } catch (err: any) {\n const msg = `下载安装脚本失败: ${err?.message ?? String(err)}`;\n if (json) {\n output({ ok: false, error: { code: \"DOWNLOAD_FAILED\", message: msg } });\n process.exit(1);\n }\n process.stderr.write(`\\x1b[31m[update] ERROR:\\x1b[0m ${msg}\\n`);\n process.exit(1);\n }\n\n // 写入临时文件\n const tmpScript = join(os.tmpdir(), `openclaw-install-${Date.now()}.mjs`);\n try {\n writeFileSync(tmpScript, installScript, \"utf-8\");\n } catch (err: any) {\n const msg = `写入临时文件失败: ${err?.message ?? String(err)}`;\n if (json) {\n output({ ok: false, error: { code: \"WRITE_FAILED\", message: msg } });\n process.exit(1);\n }\n process.stderr.write(`\\x1b[31m[update] ERROR:\\x1b[0m ${msg}\\n`);\n process.exit(1);\n }\n\n const stateDir = ctx.stateDir ?? resolveStateDir();\n\n // 执行安装脚本(同步,保证日志有序输出)\n const result = spawnSync(\n process.execPath,\n [tmpScript, \"--version\", latest, \"--state-dir\", stateDir],\n { stdio: \"inherit\" },\n );\n\n try {\n unlinkSync(tmpScript);\n } catch {\n // 清理失败不影响结果\n }\n\n if (result.error) {\n const msg = `安装脚本执行失败: ${result.error.message}`;\n if (json) {\n output({ ok: false, error: { code: \"SPAWN_FAILED\", message: msg } });\n } else {\n process.stderr.write(`\\x1b[31m[update] ERROR:\\x1b[0m ${msg}\\n`);\n }\n process.exit(1);\n }\n\n if (result.status !== 0) {\n if (json) {\n output({\n ok: false,\n error: {\n code: \"INSTALL_FAILED\",\n message: `安装脚本退出码: ${result.status}`,\n },\n });\n }\n process.exit(result.status ?? 1);\n }\n\n if (json) {\n output({ ok: true, current, latest, channel, updated: true });\n }\n}\n\nexport function registerUpdate(ntf: CliCommand, ctx: CliContext): void {\n ntf\n .command(\"update\")\n .description(\"检查并更新插件到最新版本,更新后自动重启\")\n .option(\"--json\", \"以 JSON 格式输出结果(供脚本调用)\")\n .option(\"--force\", \"强制重新安装当前最新版本,即使版本号相同\")\n .option(\"--beta\", \"安装最新 beta 版本\")\n .action((opts: { json?: boolean; force?: boolean; beta?: boolean }) => {\n return runUpdate(ctx, opts);\n });\n}\n","import type { CliCommand, CliContext } from \"./helpers.js\";\nimport { registerAuthCli } from \"./auth.js\";\nimport { registerNtfSearch } from \"./ntf-search.js\";\nimport { registerNtfSummary } from \"./ntf-summary.js\";\nimport { registerNtfStats } from \"./ntf-stats.js\";\nimport { registerNtfSync } from \"./ntf-sync.js\";\nimport { registerNtfMonitor } from \"./ntf-monitor.js\";\nimport { registerLightSend } from \"./light-send.js\";\nimport { registerLightSetupTools } from \"./light-setup-tools.js\";\nimport { registerTunnelStatus } from \"./tunnel-status.js\";\nimport { registerNtfStoragePath } from \"./ntf-storage-path.js\";\nimport { registerLogSearch } from \"./log-search.js\";\nimport { registerEnvCli } from \"./env.js\";\nimport { registerDoctor } from \"./doctor.js\";\nimport { registerRecList } from \"./rec-list.js\";\nimport { registerRecStatus } from \"./rec-status.js\";\nimport { registerRecStoragePath } from \"./rec-storage-path.js\";\nimport { registerRecSetup } from \"./rec-setup.js\";\nimport { registerUpdate } from \"./update.js\";\nimport { PLUGIN_VERSION } from \"../version.js\";\n\nexport function registerAllCli(\n program: CliCommand,\n ctx: CliContext,\n rootCommandName = \"ntf\",\n): void {\n const ntf = program\n .command(rootCommandName)\n .description(\"手机通知数据管理\")\n .version(PLUGIN_VERSION, \"-v, --version\", \"显示插件版本\");\n\n // openclaw ntf auth ...\n registerAuthCli(ntf);\n\n // openclaw ntf search / stats / sync / monitor ...\n registerNtfSearch(ntf, ctx);\n registerNtfSummary(ntf, ctx);\n registerNtfStats(ntf, ctx);\n registerNtfSync(ntf, ctx);\n registerNtfMonitor(ntf, ctx);\n\n // openclaw ntf light send / setup-tools ...\n const light = ntf.command(\"light\").description(\"灯效管理\");\n registerLightSend(light);\n registerLightSetupTools(light);\n\n // openclaw ntf storage-path\n registerNtfStoragePath(ntf, ctx);\n\n // openclaw ntf log <keyword>\n registerLogSearch(ntf, ctx);\n\n // openclaw ntf tunnel-status\n registerTunnelStatus(ntf, ctx);\n\n // openclaw ntf env show / switch\n registerEnvCli(ntf);\n\n // openclaw ntf doctor\n registerDoctor(ntf, ctx);\n\n // openclaw ntf rec list / status / storage-path / setup\n const rec = ntf.command(\"rec\").description(\"录音管理\");\n registerRecList(rec, ctx);\n registerRecStatus(rec, ctx);\n registerRecStoragePath(rec, ctx);\n registerRecSetup(rec, ctx);\n\n // openclaw ntf update\n registerUpdate(ntf, ctx);\n}\n","import type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport { requireApiKey } from \"../auth/credentials.js\";\nimport { LIGHT_RULE_TOOL_NAMES } from \"../light-rules/names.js\";\nimport type { Logger } from \"../logger.js\";\nimport { MAX_LIGHT_SEGMENTS } from \"../light/protocol.js\";\nimport { assertAncsRepeatTimes, normalizeRepeatTimes } from \"../light/repeat.js\";\nimport { sendLightEffect } from \"../light/sender.js\";\nimport { validateSegments } from \"../light/validators.js\";\nimport type { LightControlInput } from \"../types.js\";\n\nconst lightControlParameters = {\n type: \"object\",\n required: [\"segments\", \"reason\"],\n additionalProperties: false,\n properties: {\n segments: {\n type: \"array\",\n description: \"灯效段序列,1–12 段,按顺序播放\",\n minItems: 1,\n maxItems: MAX_LIGHT_SEGMENTS,\n items: {\n type: \"object\",\n required: [\"mode\", \"duration_s\"],\n additionalProperties: false,\n properties: {\n mode: {\n type: \"string\",\n enum: [\"wave\", \"breath\", \"strobe\", \"steady\", \"color_flow\", \"pixel_frame\"],\n description:\n \"灯效模式:wave 波浪(单色跑马,前景色+可选底色)/ breath 呼吸 / strobe 频闪 / steady 常亮 / \" +\n \"color_flow 流光(调色板沿圆周流动,1~2 个颜色锚点插值;**不是彩虹**,无法生成 7 色彩虹波浪)/ \" +\n \"pixel_frame 逐组像素帧。\" +\n \"易错对照:用户说\\\"红色/蓝色波浪\\\"等单一颜色波浪 → 必须用 wave,不要用 color_flow;\" +\n \"用户说\\\"彩虹/七彩/rainbow\\\" → 固件不支持真正的 7 色彩虹,需告知限制并给出近似方案(双锚点 color_flow 或多段 wave 轮播),\" +\n \"禁止静默用 color_flow 单锚点冒充彩虹。\",\n },\n duration_s: {\n type: \"number\",\n minimum: 0,\n description:\n \"本段持续时长(秒),0 表示无限时长。推荐离散值:0.5/1/2/3/5/6/8/16/24/32/48,建议单段 ≤8s 省电\",\n },\n brightness: {\n type: \"number\",\n minimum: 0,\n maximum: 255,\n description:\n \"前景亮度 0–255。非 pixel_frame 模式必填;brightness=0 仅 steady 模式有效(显式灭灯)\",\n },\n color: {\n type: \"object\",\n required: [\"r\", \"g\", \"b\"],\n additionalProperties: false,\n properties: {\n r: { type: \"number\", minimum: 0, maximum: 255 },\n g: { type: \"number\", minimum: 0, maximum: 255 },\n b: { type: \"number\", minimum: 0, maximum: 255 },\n },\n description:\n \"前景色 RGB。非 pixel_frame 模式必填;color_flow 下作为第一颜色锚点,至少 color/background 其一非零\",\n },\n interval_ms: {\n type: \"number\",\n minimum: 0,\n description:\n \"步进间隔(ms),wave/strobe/color_flow 有效,默认 200。量化档位:50/100/200/300/500/600/800/1600/2400/3200/4800\",\n },\n direction: {\n type: \"string\",\n enum: [\"ltr\", \"rtl\"],\n description: \"波浪/流光方向,wave/color_flow 有效,默认 ltr\",\n },\n window: {\n type: \"number\",\n enum: [1, 2, 3],\n description:\n \"wave:窗口灯数,默认 2;color_flow:调色板平移步幅(速度)\",\n },\n breath_timing: {\n type: \"object\",\n additionalProperties: false,\n properties: {\n rise_ms: {\n type: \"number\",\n minimum: 0,\n description:\n \"上升时间(ms),量化到 1040/1560/2080/2600/3100/4160\",\n },\n hold_ms: {\n type: \"number\",\n minimum: 0,\n description: \"保持最高亮度时间(ms),支持 0ms\",\n },\n fall_ms: {\n type: \"number\",\n minimum: 0,\n description:\n \"下降时间(ms),量化到 1040/1560/2080/2600/3100/4160\",\n },\n off_ms: {\n type: \"number\",\n minimum: 0,\n description: \"熄灭时间(ms),支持 0ms\",\n },\n },\n description:\n \"呼吸四段时间,仅 breath 有效;rise/fall 量化档位:1040/1560/2080/2600/3100/4160,hold/off 额外支持 0ms\",\n },\n background: {\n type: \"object\",\n required: [\"r\", \"g\", \"b\", \"brightness\"],\n additionalProperties: false,\n properties: {\n r: { type: \"number\", minimum: 0, maximum: 255 },\n g: { type: \"number\", minimum: 0, maximum: 255 },\n b: { type: \"number\", minimum: 0, maximum: 255 },\n brightness: {\n type: \"number\",\n minimum: 0,\n maximum: 255,\n description: \"底色亮度,量化档位:0/32/64/96/128/192/255\",\n },\n },\n description:\n \"底色 RGB + 亮度,wave 有效为底色层;color_flow 有效为第二颜色锚点(与前景色插值生成多色调色板)\",\n },\n pixels: {\n type: \"array\",\n minItems: 1,\n maxItems: 7,\n items: {\n type: \"object\",\n required: [\"index\", \"color\", \"brightness\"],\n additionalProperties: false,\n properties: {\n index: {\n type: \"number\",\n minimum: 0,\n maximum: 6,\n description: \"LED 组索引,0–6\",\n },\n color: {\n type: \"object\",\n required: [\"r\", \"g\", \"b\"],\n additionalProperties: false,\n properties: {\n r: { type: \"number\", minimum: 0, maximum: 255 },\n g: { type: \"number\", minimum: 0, maximum: 255 },\n b: { type: \"number\", minimum: 0, maximum: 255 },\n },\n description: \"该像素的 RGB\",\n },\n brightness: {\n type: \"number\",\n minimum: 0,\n maximum: 255,\n description: \"该像素亮度 0–255;0 会编码为像素熄灭\",\n },\n },\n },\n description:\n \"仅 pixel_frame 有效:播放前先清 7 组,再按此列表写入 (Idx,R,G,B,Br)\",\n },\n },\n },\n },\n reason: {\n type: \"string\",\n description:\n \"结合对话上下文,简要说明为什么要亮灯(例如:用户心情低落想要温暖氛围、庆祝生日、提醒喝水等)。\" +\n \"这个字段帮助记录每次亮灯的意图和动机。\",\n },\n title: {\n type: \"string\",\n description:\n \"对本次亮灯的简短标题/摘要(例如:温暖氛围、生日庆祝、喝水提醒)。不填时默认回退到 reason。\",\n },\n repeat: {\n type: \"boolean\",\n description:\n \"兼容旧参数。true = 无限循环,false/不填 = 一轮;若同时提供 repeat_times,则以后者为准\",\n },\n repeat_times: {\n type: \"number\",\n minimum: 0,\n description:\n \"整条组合重复次数:0 = 无限循环,1 = 播放一轮。当前 ANCS 路径不支持 N>=2\",\n },\n },\n} as const;\n\nexport function registerLightControlTool(\n api: OpenClawPluginApi,\n logger: Logger,\n): void {\n api.registerTool({\n name: \"light_control\",\n label: \"Light Control\",\n description:\n \"立即控制硬件灯效(一次性执行,不会创建或保存通知触发规则),支持 1–12 段顺序灯效,每段独立参数(6 种模式:波浪/呼吸/频闪/常亮/流光/逐组像素帧)。\" +\n \"Tool 内部自动量化为嵌入式协议定义的离散档位,并按模式精简为变长 ANCS 控制序列,通过 HTTP 接口下发灯效指令。\" +\n '当用户说\"开灯\"、\"换个灯效\"、\"把灯调成红色\"、\"营造氛围\"、\"测试/预览灯效\"等与当前即时灯光控制相关的表达时调用。' +\n `如果用户说\"收到某类通知/消息时亮灯/闪灯/变灯效\",那是持久灯效规则,改用 ${LIGHT_RULE_TOOL_NAMES.create} 或 ${LIGHT_RULE_TOOL_NAMES.update}。`,\n parameters: lightControlParameters,\n async execute(_toolCallId: string, params: unknown) {\n let apiKey: string;\n try {\n apiKey = requireApiKey();\n } catch (e: any) {\n return {\n content: [{ type: \"text\" as const, text: e.message }],\n details: { ok: false, error: { code: \"AUTH_REQUIRED\", message: e.message } },\n };\n }\n\n const { segments, title, reason, repeat, repeat_times } = params as LightControlInput;\n const validation = validateSegments(segments);\n if (!validation.valid) {\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify(validation.errors) }],\n details: {\n ok: false,\n error: { code: \"VALIDATION_FAILED\", details: validation.errors },\n },\n };\n }\n\n let repeatTimes: number;\n try {\n repeatTimes = normalizeRepeatTimes({ repeat, repeat_times });\n assertAncsRepeatTimes(repeatTimes);\n } catch (error: any) {\n return {\n content: [{ type: \"text\" as const, text: error?.message ?? String(error) }],\n details: {\n ok: false,\n error: { code: \"VALIDATION_FAILED\", message: error?.message ?? String(error) },\n },\n };\n }\n\n logger.info(`Light control title: ${title ?? \"\"}, reason: ${reason}`);\n for (const warning of validation.warnings) {\n logger.warn(\n `Light control validation warning [${warning.code}] ${warning.field}: ${warning.message}`,\n );\n }\n const result = await sendLightEffect(\n apiKey,\n validation.segments,\n logger,\n { repeat_times: repeatTimes },\n reason,\n title,\n );\n\n if (!result.ok) {\n logger.warn(\n `Light control HTTP request failed: ${result.status} ${result.error}`,\n );\n } else {\n logger.info(`Light control sent, bizUniqueId=${result.bizUniqueId}`);\n }\n\n const details =\n validation.warnings.length > 0 ? { ...result, warnings: validation.warnings } : result;\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify(details) }],\n details,\n };\n },\n } as any);\n}\n","import { readFileSync } from \"node:fs\";\nimport type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport { resolveConfigPath } from \"../host.js\";\nimport type { Logger } from \"../logger.js\";\nimport { createAppNameMapProvider } from \"../notification/app-name-map.js\";\nimport {\n NotificationStorage,\n resolveNotificationStorageDir,\n} from \"../notification/storage.js\";\nimport {\n RecordingStorage,\n resolveRecordingStorageDir,\n} from \"../recording/index.js\";\nimport {\n createTunnelService,\n type RelayTunnelService,\n} from \"../tunnel/service.js\";\nimport type { PluginConfig } from \"../types.js\";\nimport { getEnvUrls } from \"../env.js\";\nimport { trimToUndefined } from \"./shared.js\";\n\ninterface LightRuleContext {\n workspaceDir?: string;\n stateDir?: string;\n}\n\ninterface StorageLifecycleDeps {\n api: OpenClawPluginApi;\n config: PluginConfig;\n logger: Logger;\n lightRuleCtx: LightRuleContext;\n setStorage: (storage: NotificationStorage | null) => void;\n setRecordingStorage: (storage: RecordingStorage | null) => void;\n /**\n * 在 storage service 完成 start 之后触发,此时 lightRuleCtx 已被回填。\n * 用于让 LightRuleRegistry 等下游组件在拿到真实 workspaceDir 后重新加载状态。\n */\n onStorageReady?: () => void;\n}\n\nexport function registerStorageLifecycle(\n deps: StorageLifecycleDeps,\n): void {\n const {\n api,\n config,\n logger,\n lightRuleCtx,\n setStorage,\n setRecordingStorage,\n onStorageReady,\n } = deps;\n\n let storage: NotificationStorage | null = null;\n let recordingStorage: RecordingStorage | null = null;\n let appNameMapProvider: ReturnType<typeof createAppNameMapProvider> | null = null;\n\n api.registerService({\n id: \"notification-storage\",\n async start(ctx) {\n const storageDir = resolveNotificationStorageDir(ctx, logger);\n\n appNameMapProvider = createAppNameMapProvider({\n stateDir: ctx.stateDir,\n logger,\n });\n await appNameMapProvider.start();\n\n const resolveDisplayName = appNameMapProvider.resolveDisplayName.bind(appNameMapProvider);\n storage = new NotificationStorage(storageDir, config, logger, resolveDisplayName);\n await storage.init();\n setStorage(storage);\n logger.info(`通知存储服务已启动: ${storageDir}`);\n\n const recDir = resolveRecordingStorageDir(ctx, logger);\n recordingStorage = new RecordingStorage(recDir, logger);\n await recordingStorage.init();\n setRecordingStorage(recordingStorage);\n logger.info(`录音存储服务已启动: ${recDir}`);\n\n lightRuleCtx.workspaceDir = ctx.workspaceDir;\n if (ctx.stateDir) {\n lightRuleCtx.stateDir = ctx.stateDir;\n }\n\n onStorageReady?.();\n },\n async stop() {\n await storage?.close();\n storage = null;\n setStorage(null);\n\n await recordingStorage?.close();\n recordingStorage = null;\n setRecordingStorage(null);\n\n appNameMapProvider?.stop();\n appNameMapProvider = null;\n logger.info(\"通知/录音存储服务已停止\");\n },\n });\n}\n\nfunction readHostGatewayConfig(params: {\n stateDir?: string;\n logger: Pick<Logger, \"warn\">;\n}) {\n const configPath = params.stateDir\n ? resolveConfigPath(params.stateDir)\n : undefined;\n\n let configData: any;\n\n if (configPath) {\n try {\n configData = JSON.parse(readFileSync(configPath, \"utf-8\"));\n } catch (err: any) {\n if (err?.code !== \"ENOENT\") {\n params.logger.warn(\n `Relay tunnel: 无法读取 gateway 鉴权配置 (${configPath})`,\n );\n }\n }\n }\n\n return configData;\n}\n\nfunction resolveLocalGatewayAuth(params: {\n stateDir?: string;\n logger: Pick<Logger, \"warn\">;\n}): {\n gatewayAuthMode?: \"token\" | \"password\";\n gatewayToken?: string;\n gatewayPassword?: string;\n} {\n const envGatewayToken =\n trimToUndefined(process.env.OPENCLAW_GATEWAY_TOKEN) ??\n trimToUndefined(process.env.QCLAW_GATEWAY_TOKEN);\n const envGatewayPassword =\n trimToUndefined(process.env.OPENCLAW_GATEWAY_PASSWORD) ??\n trimToUndefined(process.env.QCLAW_GATEWAY_PASSWORD);\n\n const configData = readHostGatewayConfig(params);\n let configGatewayAuthMode: \"token\" | \"password\" | undefined;\n const rawGatewayAuthMode = trimToUndefined(configData?.gateway?.auth?.mode);\n if (rawGatewayAuthMode === \"token\" || rawGatewayAuthMode === \"password\") {\n configGatewayAuthMode = rawGatewayAuthMode;\n }\n const configGatewayToken = trimToUndefined(configData?.gateway?.auth?.token);\n const configGatewayPassword = trimToUndefined(configData?.gateway?.auth?.password);\n\n return {\n gatewayAuthMode: configGatewayAuthMode,\n gatewayToken: envGatewayToken ?? configGatewayToken,\n gatewayPassword: envGatewayPassword ?? configGatewayPassword,\n };\n}\n\nfunction resolveExclusiveTunnelHint(params: {\n stateDir?: string;\n logger: Pick<Logger, \"warn\">;\n}): string | undefined {\n const configData = readHostGatewayConfig(params);\n const tailscaleMode = trimToUndefined(configData?.gateway?.tailscale?.mode);\n if (tailscaleMode) {\n return `gateway.tailscale.mode=${tailscaleMode}`;\n }\n\n const remoteUrl = trimToUndefined(configData?.gateway?.remote?.url);\n if (remoteUrl && isExternalGatewayRemoteUrl(remoteUrl)) {\n return `gateway.remote.url=${remoteUrl}`;\n }\n\n return undefined;\n}\n\nfunction isExternalGatewayRemoteUrl(rawUrl: string): boolean {\n let host: string;\n try {\n host = new URL(rawUrl).hostname.toLowerCase();\n } catch {\n return false;\n }\n\n if (host === \"localhost\" || host === \"::1\" || host === \"[::1]\") {\n return false;\n }\n\n return !/^127(?:\\.\\d{1,3}){0,3}$/.test(host);\n}\n\ninterface RelayTunnelDeps {\n api: OpenClawPluginApi;\n config: PluginConfig;\n logger: Logger;\n openclawDir?: string;\n}\n\nexport function registerRelayTunnelLifecycle(\n deps: RelayTunnelDeps,\n): RelayTunnelService | null {\n const {\n api,\n config,\n logger,\n openclawDir,\n } = deps;\n\n const tunnelUrl = getEnvUrls().relayTunnelUrl;\n if (!tunnelUrl) {\n return null;\n }\n\n const exclusiveTunnelHint = resolveExclusiveTunnelHint({\n stateDir: openclawDir,\n logger,\n });\n if (exclusiveTunnelHint) {\n logger.info(\n `Relay tunnel: detected ${exclusiveTunnelHint} in host gateway config, skipping relay startup to keep ingress mutually exclusive`,\n );\n return null;\n }\n\n const gatewayPort =\n process.env.OPENCLAW_GATEWAY_PORT ??\n process.env.QCLAW_GATEWAY_PORT ??\n \"18789\";\n const { gatewayAuthMode, gatewayToken, gatewayPassword } =\n resolveLocalGatewayAuth({\n stateDir: openclawDir,\n logger,\n });\n\n const tunnelService = createTunnelService({\n tunnelUrl,\n heartbeatSec: config.relay?.heartbeatSec,\n reconnectBackoffMs: config.relay?.reconnectBackoffMs,\n gatewayBaseUrl: `http://localhost:${gatewayPort}`,\n gatewayAuthMode,\n gatewayToken,\n gatewayPassword,\n logger,\n });\n\n api.registerService(tunnelService);\n logger.info(\"Relay tunnel 服务已注册\");\n return tunnelService;\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { loadApiKey, watchCredentials } from \"../auth/credentials.js\";\nimport { getEnvUrls } from \"../env.js\";\n\nconst PLUGIN_STATE_DIR = \"phone-notifications\";\nconst CACHE_FILE = \"app-name-map.json\";\n\n/** 包名→应用名映射 API 地址(默认随环境变化;可用 APP_NAME_MAP_URL 覆盖;需鉴权) */\nconst BUILTIN_APP_NAME_MAP_URL = getEnvUrls().appNameMapUrl;\nconst APP_NAME_MAP_URL =\n (typeof process.env.APP_NAME_MAP_URL === \"string\" && process.env.APP_NAME_MAP_URL.trim()\n ? process.env.APP_NAME_MAP_URL.trim()\n : undefined) ?? BUILTIN_APP_NAME_MAP_URL;\n/** 映射刷新间隔(小时) */\nconst APP_NAME_MAP_REFRESH_HOURS = 12;\n\ninterface Logger {\n info: (message: string) => void;\n warn: (message: string) => void;\n}\n\nfunction isRecordOfStrings(v: unknown): v is Record<string, string> {\n if (v === null || typeof v !== \"object\") return false;\n for (const val of Object.values(v)) if (typeof val !== \"string\") return false;\n return true;\n}\n\n/** API 返回的单项 */\ninterface AppPackageItem {\n appName: string;\n packageName: string;\n iconUrl?: string | null;\n platform?: string | null;\n jumpUrl?: string | null;\n urlParams?: string | null;\n description?: string | null;\n}\n\n/** API 响应格式 */\ninterface AppNameMapApiResponse {\n success?: boolean;\n code?: string;\n message?: string;\n data?: AppPackageItem[];\n}\n\nfunction isAppNameMapApiResponse(v: unknown): v is AppNameMapApiResponse {\n if (v === null || typeof v !== \"object\") return false;\n const o = v as Record<string, unknown>;\n return Array.isArray(o.data) && o.data.every(\n (item: unknown) =>\n item !== null &&\n typeof item === \"object\" &&\n typeof (item as AppPackageItem).packageName === \"string\" &&\n typeof (item as AppPackageItem).appName === \"string\"\n );\n}\n\nfunction getCachePath(stateDir: string): string {\n return join(stateDir, \"plugins\", PLUGIN_STATE_DIR, CACHE_FILE);\n}\n\nexport interface AppNameMapProvider {\n /** 解析包名为显示名(未命中时拉取一次再返回,保证当前落库即有值) */\n resolveDisplayName(packageName: string): Promise<string>;\n start(): Promise<void>;\n stop(): void;\n}\n\nexport function createAppNameMapProvider(opts: {\n stateDir: string;\n logger: Logger;\n}): AppNameMapProvider {\n const { stateDir, logger } = opts;\n const url = APP_NAME_MAP_URL;\n const refreshHours = APP_NAME_MAP_REFRESH_HOURS;\n\n const map = new Map<string, string>();\n let refreshTimer: ReturnType<typeof setInterval> | null = null;\n let stopWatching: (() => void) | null = null;\n let inFlightFetch: Promise<void> | null = null;\n\n function loadFromDisk(): void {\n const path = getCachePath(stateDir);\n if (!existsSync(path)) return;\n try {\n const raw = JSON.parse(readFileSync(path, \"utf-8\"));\n if (!isRecordOfStrings(raw)) return;\n map.clear();\n for (const [k, v] of Object.entries(raw)) map.set(k, v);\n logger.info(`[app-name-map] loaded ${map.size} entries from cache: ${path}`);\n } catch {\n /* ignore */\n }\n }\n\n async function fetchFromServer(): Promise<void> {\n const apiKey = loadApiKey();\n if (!url) {\n logger.warn(\"[app-name-map] APP_NAME_MAP_URL is empty, skip refresh\");\n return;\n }\n if (!apiKey) {\n logger.info(\"[app-name-map] api key missing, skip refresh\");\n return;\n }\n\n const rawApiKey = apiKey.startsWith(\"Bearer \")\n ? apiKey.slice(\"Bearer \".length)\n : apiKey;\n try {\n const res = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\", \"X-Api-Key-Id\": rawApiKey },\n body: JSON.stringify({\n platform: \"\"\n })\n });\n if (!res.ok) {\n logger.warn(`[app-name-map] refresh failed: HTTP ${res.status} ${res.statusText}`);\n return;\n }\n const body = await res.json() as unknown;\n if (!isAppNameMapApiResponse(body) || !body.success || !body.data?.length) {\n logger.warn(\"[app-name-map] refresh failed: unexpected response shape or empty data\");\n return;\n }\n map.clear();\n for (const item of body.data) {\n if (item.packageName && item.appName) map.set(item.packageName, item.appName);\n }\n if (map.size === 0) {\n logger.warn(\"[app-name-map] refresh succeeded but got 0 entries\");\n return;\n }\n const dir = join(stateDir, \"plugins\", PLUGIN_STATE_DIR);\n\n mkdirSync(dir, { recursive: true });\n const cachePath = getCachePath(stateDir);\n writeFileSync(cachePath, JSON.stringify(Object.fromEntries(map), null, 2), \"utf-8\");\n logger.info(`[app-name-map] refreshed ${map.size} entries from server and saved: ${cachePath}`);\n } catch (e) {\n const message = e instanceof Error ? e.message : String(e);\n logger.warn(`[app-name-map] refresh error: ${message}`);\n }\n }\n\n async function ensureOneFetch(): Promise<void> {\n if (inFlightFetch) return inFlightFetch;\n inFlightFetch = fetchFromServer().finally(() => {\n inFlightFetch = null;\n });\n return inFlightFetch;\n }\n\n return {\n async resolveDisplayName(packageName: string): Promise<string> {\n // 临时策略:仅使用内存/磁盘中已有的映射,缺少时不主动触发拉取\n if (map.has(packageName)) return map.get(packageName)!;\n return packageName;\n // 如需在缺少应用名时触发一次拉取再返回,可恢复为:\n // if (!url || !loadApiKey()) return packageName;\n // await ensureOneFetch();\n // return map.get(packageName) ?? packageName;\n },\n\n async start(): Promise<void> {\n loadFromDisk();\n await fetchFromServer();\n\n if (!url) return;\n\n if (refreshHours > 0) {\n const ms = refreshHours * 60 * 60 * 1000;\n refreshTimer = setInterval(() => fetchFromServer().catch(() => { }), ms);\n }\n stopWatching = watchCredentials(() => fetchFromServer().catch(() => { }));\n },\n\n stop(): void {\n stopWatching?.();\n stopWatching = null;\n if (refreshTimer) {\n clearInterval(refreshTimer);\n refreshTimer = null;\n }\n map.clear();\n },\n };\n}\n","import {\n accessSync,\n mkdirSync,\n appendFileSync,\n readdirSync,\n readFileSync,\n writeFileSync,\n existsSync,\n rmSync,\n constants,\n} from \"node:fs\";\nimport { createHash } from \"node:crypto\";\nimport { join } from \"node:path\";\nimport type { PluginConfig, RawNotification } from \"../types.js\";\nimport { normalizeFeishuFields } from \"./feishu-normalize.js\";\n\ninterface Logger {\n info: (message: string) => void;\n warn: (message: string) => void;\n}\n\nexport type NotificationConversationType = \"private\" | \"group\";\n\nexport interface StorageContext {\n stateDir: string;\n workspaceDir?: string;\n}\n\n/** Stored notification entry (JSON format, append-only) */\nexport interface StoredNotification {\n /** 包名 */\n appName: string;\n /** 应用显示名(由映射补全),缺省时与 appName 一致 */\n appDisplayName?: string;\n title: string;\n content: string;\n /** ISO 8601 with timezone, e.g. \"2026-03-02T08:30:00+08:00\" */\n timestamp: string;\n /**\n * 结构化发送人。当前主要用于飞书消息:\n * iOS 通知里 title 通常是发送人,subtitle 用来区分群聊名。\n */\n senderName?: string;\n /** 结构化会话类型。当前主要用于飞书消息区分群聊/私聊。 */\n conversationType?: NotificationConversationType;\n /** 结构化会话名。当前主要用于飞书群聊名(通常来自 subtitle)。 */\n conversationName?: string;\n}\n\nconst NOTIFICATION_DIR_NAME = \"notifications\";\nconst ID_INDEX_DIR_NAME = \".ids\";\nconst CONTENT_KEY_INDEX_DIR_NAME = \".keys\";\n\nexport interface NotificationIngestResult {\n received: number;\n ingested: number;\n dedupedById: number;\n dedupedByContent: number;\n invalid: number;\n /**\n * 本次 ingest 实际新写入的条目(去重 / 非法之后的产物)。\n * 用于后续事件驱动链路(如 light-rule agent 评估)拿到本次新增的通知列表,\n * 不需要重新读盘。\n */\n inserted: StoredNotification[];\n}\n\ntype WriteOutcome =\n | { kind: \"ingested\"; entry: StoredNotification }\n | { kind: \"dedupedById\" }\n | { kind: \"dedupedByContent\" }\n | { kind: \"invalid\" };\n\nexport function getStateFallbackNotificationDir(stateDir: string): string {\n return join(stateDir, \"plugins\", \"phone-notifications\", NOTIFICATION_DIR_NAME);\n}\n\nfunction computeLagMs(timestamp: string | undefined): number | null {\n if (!timestamp) return null;\n const t = new Date(timestamp).getTime();\n if (Number.isNaN(t)) return null;\n return Date.now() - t;\n}\n\nfunction buildFallbackContent(n: RawNotification): string {\n const body = n.body?.trim();\n if (body) {\n return body;\n }\n\n const fallback: string[] = [];\n if (n.category) {\n fallback.push(`category:${n.category}`);\n }\n if (n.metadata && Object.keys(n.metadata).length > 0) {\n fallback.push(`metadata:${JSON.stringify(n.metadata)}`);\n }\n return fallback.join(\" ; \") || \"-\";\n}\n\nfunction ensureWritableDirectory(dir: string): boolean {\n try {\n mkdirSync(dir, { recursive: true });\n accessSync(dir, constants.R_OK | constants.W_OK);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function resolveNotificationStorageDir(\n ctx: StorageContext,\n logger: Pick<Logger, \"info\" | \"warn\">,\n): string {\n // 优先使用 stateDir(插件私有稳定路径),避免通知随 workspace 切换而分散\n const stateNotifDir = getStateFallbackNotificationDir(ctx.stateDir);\n\n if (ensureWritableDirectory(stateNotifDir)) {\n logger.info(`通知将写入 stateDir 路径: ${stateNotifDir}`);\n return stateNotifDir;\n }\n\n // stateDir 不可用时回退到 workspaceDir\n if (ctx.workspaceDir) {\n const workspaceDir = join(ctx.workspaceDir, NOTIFICATION_DIR_NAME);\n if (ensureWritableDirectory(workspaceDir)) {\n logger.warn(\n `stateDir 不可用,通知已回退到 workspace 路径: ${workspaceDir}`,\n );\n return workspaceDir;\n }\n }\n\n throw new Error(`通知存储目录不可用: ${stateNotifDir}`);\n}\n\n/** 包名 → 应用显示名(异步,未命中时内部可拉取后返回);不提供则落库仅用 appName */\nexport type ResolveDisplayName = (packageName: string) => Promise<string>;\n\nexport class NotificationStorage {\n private dir: string;\n private idIndexDir: string;\n private contentKeyIndexDir: string;\n private idCache = new Map<string, Set<string>>();\n private contentKeyCache = new Map<string, Set<string>>();\n private dateWriteChains = new Map<string, Promise<void>>();\n private resolveDisplayName: ResolveDisplayName | undefined;\n\n constructor(\n dir: string,\n private config: PluginConfig,\n private logger: Logger,\n resolveDisplayName?: ResolveDisplayName,\n ) {\n this.dir = dir;\n this.idIndexDir = join(dir, ID_INDEX_DIR_NAME);\n this.contentKeyIndexDir = join(dir, CONTENT_KEY_INDEX_DIR_NAME);\n this.resolveDisplayName = resolveDisplayName;\n }\n\n async init() {\n mkdirSync(this.dir, { recursive: true });\n mkdirSync(this.idIndexDir, { recursive: true });\n rmSync(this.contentKeyIndexDir, { recursive: true, force: true });\n mkdirSync(this.contentKeyIndexDir, { recursive: true });\n }\n\n async ingest(\n items: RawNotification[],\n ingestId?: string,\n ): Promise<NotificationIngestResult> {\n const result: NotificationIngestResult = {\n received: items.length,\n ingested: 0,\n dedupedById: 0,\n dedupedByContent: 0,\n invalid: 0,\n inserted: [],\n };\n\n const traceTag = ingestId ? `[${ingestId}]` : \"\";\n for (const n of items) {\n const outcome = await this.writeNotification(n);\n const lagMs = computeLagMs(n.timestamp);\n const lagPart = lagMs === null ? \"lag=?\" : `lag=${lagMs}ms`;\n this.logger.info(\n `ingest${traceTag}: app=${n.app ?? \"Unknown\"} id=${n.id ?? \"-\"} ts=${n.timestamp} ${lagPart} outcome=${outcome.kind}`,\n );\n switch (outcome.kind) {\n case \"ingested\":\n result.ingested += 1;\n result.inserted.push(outcome.entry);\n break;\n case \"dedupedById\":\n result.dedupedById += 1;\n break;\n case \"dedupedByContent\":\n result.dedupedByContent += 1;\n break;\n case \"invalid\":\n result.invalid += 1;\n break;\n }\n }\n this.prune();\n return result;\n }\n\n private async writeNotification(n: RawNotification): Promise<WriteOutcome> {\n const ts = new Date(n.timestamp);\n if (Number.isNaN(ts.getTime())) {\n this.logger.warn(`忽略非法 timestamp 的通知: ${n.id}`);\n return { kind: \"invalid\" };\n }\n\n const dateKey = this.formatDate(ts);\n const filePath = join(this.dir, `${dateKey}.json`);\n const normalizedId = typeof n.id === \"string\" ? n.id.trim() : \"\";\n const entry = this.buildStoredNotification(n);\n\n return this.withDateWriteLock(dateKey, async () => {\n if (normalizedId && this.hasNotificationId(dateKey, normalizedId)) {\n return { kind: \"dedupedById\" };\n }\n\n if (this.hasNotificationContentKey(dateKey, filePath, entry)) {\n return { kind: \"dedupedByContent\" };\n }\n\n const appDisplayName = this.resolveDisplayName\n ? await this.resolveDisplayName(entry.appName)\n : entry.appName;\n\n const storedEntry: StoredNotification = {\n ...entry,\n appDisplayName,\n };\n\n const arr = this.readStoredNotifications(filePath);\n arr.push(storedEntry);\n writeFileSync(filePath, JSON.stringify(arr, null, 2), \"utf-8\");\n\n if (normalizedId) {\n this.recordNotificationId(dateKey, normalizedId);\n }\n this.recordNotificationContentKey(dateKey, filePath, storedEntry);\n return { kind: \"ingested\", entry: storedEntry };\n });\n }\n\n private buildStoredNotification(n: RawNotification): StoredNotification {\n const appName = typeof n.app === \"string\" && n.app ? n.app : \"Unknown\";\n const feishu = normalizeFeishuFields(n);\n if (feishu) {\n return {\n appName,\n title: feishu.title,\n content: feishu.content || buildFallbackContent(n),\n timestamp: n.timestamp,\n ...feishu.structured,\n };\n }\n return {\n appName,\n title: typeof n.title === \"string\" ? n.title : \"\",\n content: buildFallbackContent(n),\n timestamp: n.timestamp,\n };\n }\n\n private formatDate(d: Date): string {\n const year = d.getFullYear();\n const month = String(d.getMonth() + 1).padStart(2, \"0\");\n const day = String(d.getDate()).padStart(2, \"0\");\n return `${year}-${month}-${day}`;\n }\n\n private getIdIndexPath(dateKey: string): string {\n return join(this.idIndexDir, `${dateKey}.ids`);\n }\n\n private getIdSet(dateKey: string): Set<string> {\n const cached = this.idCache.get(dateKey);\n if (cached) {\n return cached;\n }\n\n const idPath = this.getIdIndexPath(dateKey);\n const ids = new Set<string>();\n if (existsSync(idPath)) {\n const lines = readFileSync(idPath, \"utf-8\").split(/\\r?\\n/);\n for (const line of lines) {\n const id = line.trim();\n if (id) {\n ids.add(id);\n }\n }\n }\n\n this.idCache.set(dateKey, ids);\n return ids;\n }\n\n private hasNotificationId(dateKey: string, id: string): boolean {\n return this.getIdSet(dateKey).has(id);\n }\n\n private getContentKeyIndexPath(dateKey: string): string {\n return join(this.contentKeyIndexDir, `${dateKey}.keys`);\n }\n\n private getContentKeySet(dateKey: string, filePath: string): Set<string> {\n const cached = this.contentKeyCache.get(dateKey);\n if (cached) {\n return cached;\n }\n\n const keyPath = this.getContentKeyIndexPath(dateKey);\n const keys = new Set<string>();\n\n if (existsSync(filePath)) {\n for (const item of this.readStoredNotifications(filePath)) {\n keys.add(this.buildNotificationContentKey(item));\n }\n }\n\n if (keys.size > 0) {\n writeFileSync(keyPath, `${Array.from(keys).join(\"\\n\")}\\n`, \"utf-8\");\n } else if (existsSync(keyPath)) {\n rmSync(keyPath, { force: true });\n }\n\n this.contentKeyCache.set(dateKey, keys);\n return keys;\n }\n\n private hasNotificationContentKey(\n dateKey: string,\n filePath: string,\n entry: Pick<StoredNotification, \"appName\" | \"title\" | \"content\" | \"timestamp\">,\n ): boolean {\n return this.getContentKeySet(dateKey, filePath).has(\n this.buildNotificationContentKey(entry),\n );\n }\n\n private recordNotificationId(dateKey: string, id: string) {\n const ids = this.getIdSet(dateKey);\n if (ids.has(id)) {\n return;\n }\n\n appendFileSync(this.getIdIndexPath(dateKey), `${id}\\n`, \"utf-8\");\n ids.add(id);\n }\n\n private recordNotificationContentKey(\n dateKey: string,\n filePath: string,\n entry: Pick<StoredNotification, \"appName\" | \"title\" | \"content\" | \"timestamp\">,\n ) {\n const keys = this.getContentKeySet(dateKey, filePath);\n const key = this.buildNotificationContentKey(entry);\n\n if (keys.has(key)) {\n return;\n }\n\n appendFileSync(this.getContentKeyIndexPath(dateKey), `${key}\\n`, \"utf-8\");\n keys.add(key);\n }\n\n private buildNotificationContentKey(\n entry: Pick<StoredNotification, \"appName\" | \"title\" | \"content\" | \"timestamp\">,\n ): string {\n return createHash(\"sha256\")\n .update(entry.appName)\n .update(\"\\x1f\")\n .update(entry.title)\n .update(\"\\x1f\")\n .update(entry.content)\n .update(\"\\x1f\")\n .update(entry.timestamp)\n .digest(\"hex\");\n }\n\n private readStoredNotifications(filePath: string): StoredNotification[] {\n if (!existsSync(filePath)) {\n return [];\n }\n\n try {\n const parsed = JSON.parse(readFileSync(filePath, \"utf-8\"));\n return Array.isArray(parsed) ? parsed : [];\n } catch {\n return [];\n }\n }\n\n private async withDateWriteLock<T>(\n dateKey: string,\n task: () => Promise<T>,\n ): Promise<T> {\n const previous = this.dateWriteChains.get(dateKey) ?? Promise.resolve();\n let release!: () => void;\n const current = new Promise<void>((resolve) => {\n release = resolve;\n });\n const chain = previous.then(() => current);\n this.dateWriteChains.set(dateKey, chain);\n\n await previous;\n try {\n return await task();\n } finally {\n release();\n if (this.dateWriteChains.get(dateKey) === chain) {\n this.dateWriteChains.delete(dateKey);\n }\n }\n }\n\n private prune() {\n const retentionDays = this.config.retentionDays;\n if (retentionDays === undefined) {\n return;\n }\n\n const cutoffMs = Date.now() - retentionDays * 24 * 60 * 60 * 1000;\n const cutoffDate = this.formatDate(new Date(cutoffMs));\n\n this.pruneDataFiles(cutoffDate);\n this.pruneIdIndex(cutoffDate);\n this.pruneContentKeyIndex(cutoffDate);\n }\n\n /** Remove expired .json, legacy .md files, and legacy date directories */\n private pruneDataFiles(cutoffDate: string) {\n const dateFilePattern = /^(\\d{4}-\\d{2}-\\d{2})\\.(json|md)$/;\n const dateDirPattern = /^\\d{4}-\\d{2}-\\d{2}$/;\n\n try {\n for (const entry of readdirSync(this.dir, { withFileTypes: true })) {\n if (entry.isFile()) {\n const match = dateFilePattern.exec(entry.name);\n if (match && match[1] < cutoffDate) {\n rmSync(join(this.dir, entry.name), { force: true });\n }\n } else if (entry.isDirectory() && dateDirPattern.test(entry.name) && entry.name < cutoffDate) {\n rmSync(join(this.dir, entry.name), { recursive: true, force: true });\n }\n }\n } catch {\n // ignore\n }\n }\n\n /** Remove expired .ids index files */\n private pruneIdIndex(cutoffDate: string) {\n try {\n for (const entry of readdirSync(this.idIndexDir, { withFileTypes: true })) {\n if (!entry.isFile()) continue;\n const match = /^(\\d{4}-\\d{2}-\\d{2})\\.ids$/.exec(entry.name);\n if (match && match[1] < cutoffDate) {\n rmSync(join(this.idIndexDir, entry.name), { force: true });\n this.idCache.delete(match[1]);\n }\n }\n } catch {\n // ignore\n }\n }\n\n private pruneContentKeyIndex(cutoffDate: string) {\n try {\n for (const entry of readdirSync(this.contentKeyIndexDir, { withFileTypes: true })) {\n if (!entry.isFile()) continue;\n const match = /^(\\d{4}-\\d{2}-\\d{2})\\.keys$/.exec(entry.name);\n if (match && match[1] < cutoffDate) {\n rmSync(join(this.contentKeyIndexDir, entry.name), { force: true });\n this.contentKeyCache.delete(match[1]);\n }\n }\n } catch {\n // ignore\n }\n }\n\n async close() {\n this.idCache.clear();\n this.contentKeyCache.clear();\n this.dateWriteChains.clear();\n }\n}\n","import type { RawNotification } from \"../types.js\";\nimport type { NotificationConversationType } from \"./storage.js\";\n\nexport interface FeishuStructuredFields {\n senderName?: string;\n conversationType?: NotificationConversationType;\n conversationName?: string;\n}\n\nexport interface FeishuNormalizedNotification {\n title: string;\n content: string;\n structured: FeishuStructuredFields;\n}\n\nfunction normalizeOptionalText(value: unknown): string | undefined {\n if (typeof value !== \"string\") {\n return undefined;\n }\n const trimmed = value.trim();\n return trimmed ? trimmed : undefined;\n}\n\nfunction isFeishuApp(appName: string): boolean {\n const normalized = appName.trim().toLowerCase();\n if (!normalized) {\n return false;\n }\n return (\n normalized === \"飞书\"\n || normalized === \"feishu\"\n || normalized === \"lark\"\n || normalized === \"com.ss.android.lark\"\n || normalized === \"com.bytedance.ee.lark\"\n || normalized === \"com.larksuite.suite\"\n || normalized.includes(\"feishu\")\n || normalized.includes(\"lark\")\n || normalized.includes(\"飞书\")\n );\n}\n\nfunction isFeishuAppLabel(text: string): boolean {\n const t = text.trim().toLowerCase();\n return t === \"飞书\" || t === \"lark\" || t === \"feishu\";\n}\n\nfunction extractColonSender(body: string): string | undefined {\n if (!body) return undefined;\n const candidates = [body.indexOf(\":\"), body.indexOf(\":\")].filter((i) => i > 0);\n if (candidates.length === 0) return undefined;\n const idx = Math.min(...candidates);\n const senderName = body.slice(0, idx).trim();\n return senderName || undefined;\n}\n\nfunction findMetadataTextByKey(\n value: unknown,\n targetKey: string,\n depth = 0,\n): { found: boolean; value?: string } {\n if (!value || typeof value !== \"object\" || depth > 4) {\n return { found: false };\n }\n\n if (Array.isArray(value)) {\n for (const item of value) {\n const match = findMetadataTextByKey(item, targetKey, depth + 1);\n if (match.found) {\n return match;\n }\n }\n return { found: false };\n }\n\n for (const [key, child] of Object.entries(value as Record<string, unknown>)) {\n if (key.trim().toLowerCase() === targetKey) {\n return { found: true, value: normalizeOptionalText(child) };\n }\n }\n\n for (const child of Object.values(value as Record<string, unknown>)) {\n const match = findMetadataTextByKey(child, targetKey, depth + 1);\n if (match.found) {\n return match;\n }\n }\n\n return { found: false };\n}\n\nfunction deriveStructured(n: RawNotification): FeishuStructuredFields {\n const subtitle = findMetadataTextByKey(n.metadata, \"subtitle\");\n\n // iOS 路径:通知元数据带 subtitle key(群聊为群名,私聊为空)。\n if (subtitle.found) {\n const senderName = normalizeOptionalText(n.title);\n const structured: FeishuStructuredFields = {\n conversationType: subtitle.value ? \"group\" : \"private\",\n };\n if (senderName) {\n structured.senderName = senderName;\n }\n if (subtitle.value) {\n structured.conversationName = subtitle.value;\n }\n return structured;\n }\n\n // Android 路径:title 退化为 app 名(如 \"飞书\"),实际发送人在 body 里以 \"name: content\" 形式出现。\n const rawTitle = typeof n.title === \"string\" ? n.title : \"\";\n if (isFeishuAppLabel(rawTitle)) {\n const senderName = extractColonSender(n.body ?? \"\");\n if (senderName) {\n return {\n senderName,\n conversationType: \"private\",\n };\n }\n }\n\n return {};\n}\n\nfunction buildTitle(n: RawNotification, structured: FeishuStructuredFields): string {\n if (structured.conversationType === \"group\" && structured.conversationName) {\n return structured.conversationName;\n }\n // Android 私聊 title 是 app 名,用 body 解析出的 senderName 顶上去,跟 iOS 对齐。\n if (structured.conversationType === \"private\" && structured.senderName) {\n return structured.senderName;\n }\n return typeof n.title === \"string\" ? n.title : \"\";\n}\n\nfunction buildContent(n: RawNotification, structured: FeishuStructuredFields): string {\n const body = n.body?.trim();\n\n if (structured.conversationType === \"group\" && structured.senderName && body) {\n const half = `${structured.senderName}:`;\n const full = `${structured.senderName}:`;\n return body.startsWith(half) || body.startsWith(full)\n ? body\n : `${structured.senderName}: ${body}`;\n }\n\n if (structured.conversationType === \"private\" && structured.senderName && body) {\n const half = `${structured.senderName}:`;\n const full = `${structured.senderName}:`;\n if (body.startsWith(half)) return body.slice(half.length).trimStart();\n if (body.startsWith(full)) return body.slice(full.length).trimStart();\n return body;\n }\n\n return body ?? \"\";\n}\n\nexport function normalizeFeishuFields(\n n: RawNotification,\n): FeishuNormalizedNotification | undefined {\n const appName = typeof n.app === \"string\" ? n.app : \"\";\n if (!isFeishuApp(appName)) {\n return undefined;\n }\n\n const structured = deriveStructured(n);\n\n // Feishu 通知但任何规则都没命中:让 caller 走默认归一化路径,避免与非 Feishu 通知行为分裂。\n if (\n structured.senderName === undefined\n && structured.conversationType === undefined\n && structured.conversationName === undefined\n ) {\n return undefined;\n }\n\n return {\n title: buildTitle(n, structured),\n content: buildContent(n, structured),\n structured,\n };\n}\n","/**\n * 录音本地存储管理(§5.2)\n *\n * 目录结构:\n * <storageDir>/recordings/\n * ├── audio/ # 原始音频 + 打点文件\n * │ ├── 2026-03-23_14-32.ogg\n * │ └── 2026-03-23_14-32.srt\n * ├── transcript-data/ # 转写 JSON(主存储)\n * │ └── 2026-03-23_14-32.json\n * ├── transcripts/ # 转写文本\n * │ └── 2026-03-23_14-32_与王总沟通产品方向.md\n * ├── summaries/ # 转写摘要\n * │ └── 2026-03-23_14-32.md\n * └── index.json # 元数据索引\n */\n\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n writeFileSync,\n rmSync,\n readdirSync,\n statSync,\n} from \"node:fs\";\nimport { join, basename } from \"node:path\";\nimport type {\n RecordingMetadata,\n RecordingTransferStatus,\n} from \"../types.js\";\nimport { transition } from \"./state-machine.js\";\nimport type { Logger } from \"../logger.js\";\nimport {\n buildTranscriptDataFilename as buildTranscriptDataJsonFilename,\n buildTranscriptDocument,\n extractTranscriptSummaryFromDocument,\n extractTranscriptTextFromDocument,\n extractTranscriptTitleFromDocument,\n parseTranscriptDocument,\n} from \"./transcript-document.js\";\n\n/**\n * 从 OSS URL 中提取音频文件扩展名(含点号,如 \".ogg\")\n * 默认返回 \".ogg\"(小硬件录音为 Opus/OGG 格式)\n */\nfunction extractAudioExt(ossUrl: string): string {\n try {\n const pathname = new URL(ossUrl).pathname;\n const m = pathname.match(/(\\.[a-z0-9]+)(?:\\?|$)/i);\n if (m) return m[1].toLowerCase();\n } catch {\n const m = ossUrl.match(/(\\.[a-z0-9]+)(?:\\?|$)/i);\n if (m) return m[1].toLowerCase();\n }\n return \".ogg\"; // 硬件默认录音格式(Opus/OGG)\n}\n\n// ─── Types ───\n\n/** 持久化到 index.json 的单条录音记录 */\nexport interface RecordingIndexEntry {\n /** 录音 ID,基于文件名(如 \"2026-03-23_14-32\") */\n id: string;\n /** 原始元数据 */\n metadata: RecordingMetadata;\n /** 当前插件侧状态 */\n status: RecordingTransferStatus;\n /** 本地音频文件相对路径 */\n audioFile?: string;\n /** 本地打点文件相对路径 */\n srtFile?: string;\n /** 本地转写文件相对路径 */\n transcriptFile?: string;\n /** 本地转写 JSON 文件相对路径 */\n transcriptDataFile?: string;\n /** 本地摘要文件相对路径 */\n summaryFile?: string;\n /** 转写标题 */\n title?: string;\n /** 最近一次失败原因(同步失败 / 转写失败) */\n lastError?: string;\n /** 入库时间 ISO 8601 */\n ingestedAt: string;\n /** 最后更新时间 ISO 8601 */\n updatedAt: string;\n}\n\n/** 录音存储索引(整个 index.json) */\ninterface RecordingIndex {\n recordings: RecordingIndexEntry[];\n}\n\nexport interface RecordingStorageContext {\n stateDir: string;\n workspaceDir?: string;\n}\n\n// ─── Constants ───\n\nconst RECORDINGS_DIR = \"recordings\";\nconst AUDIO_DIR = \"audio\";\nconst TRANSCRIPT_DATA_DIR = \"transcript-data\";\nconst TRANSCRIPTS_DIR = \"transcripts\";\nconst SUMMARIES_DIR = \"summaries\";\nconst INDEX_FILE = \"index.json\";\n\nfunction stripMarkdownFence(markdown: string): string {\n return markdown.replace(/\\r\\n/g, \"\\n\");\n}\n\nfunction deriveTitleFromTranscriptPath(\n transcriptFile: string | undefined,\n recordingId: string,\n): string | undefined {\n if (!transcriptFile) return undefined;\n const name = basename(transcriptFile, \".md\");\n const prefix = `${recordingId}_`;\n if (name.startsWith(prefix)) {\n const derived = name.slice(prefix.length).trim();\n return derived || undefined;\n }\n return undefined;\n}\n\nfunction extractTranscriptContent(markdown: string): string {\n const normalized = stripMarkdownFence(markdown);\n const firstDivider = normalized.indexOf(\"\\n---\\n\");\n let body = firstDivider >= 0\n ? normalized.slice(firstDivider + \"\\n---\\n\".length)\n : normalized;\n\n if (body.startsWith(\"\\n\")) {\n body = body.slice(1);\n }\n\n if (body.startsWith(\"### 关键点\")) {\n const secondDivider = body.indexOf(\"\\n---\\n\");\n if (secondDivider >= 0) {\n body = body.slice(secondDivider + \"\\n---\\n\".length);\n if (body.startsWith(\"\\n\")) {\n body = body.slice(1);\n }\n }\n }\n\n const lines = body\n .split(\"\\n\")\n .filter((line) => !/^\\*\\*\\[关键点 .+\\]\\*\\*$/.test(line.trim()))\n .filter((line) => !/^- \\*\\*\\[关键点 .+\\]\\*\\*$/.test(line.trim()));\n\n return lines.join(\"\\n\").replace(/\\n{3,}/g, \"\\n\\n\").trim();\n}\n\n// ─── Public Functions ───\n\n/**\n * 解析录音存储根目录(复用通知同级的 stateDir 路径)\n */\nexport function resolveRecordingStorageDir(\n ctx: RecordingStorageContext,\n logger: Pick<Logger, \"info\" | \"warn\">,\n): string {\n const stateRecDir = join(\n ctx.stateDir,\n \"plugins\",\n \"phone-notifications\",\n RECORDINGS_DIR,\n );\n\n try {\n mkdirSync(stateRecDir, { recursive: true });\n logger.info(`录音将写入 stateDir 路径: ${stateRecDir}`);\n return stateRecDir;\n } catch {\n // fallback\n }\n\n if (ctx.workspaceDir) {\n const wsRecDir = join(ctx.workspaceDir, RECORDINGS_DIR);\n try {\n mkdirSync(wsRecDir, { recursive: true });\n logger.warn(`stateDir 不可用,录音已回退到 workspace 路径: ${wsRecDir}`);\n return wsRecDir;\n } catch {\n // fallthrough\n }\n }\n\n throw new Error(`录音存储目录不可用: ${stateRecDir}`);\n}\n\n// ─── RecordingStorage Class ───\n\nexport class RecordingStorage {\n private readonly dir: string;\n private readonly audioDir: string;\n private readonly transcriptDataDir: string;\n private readonly transcriptsDir: string;\n private readonly summariesDir: string;\n private readonly indexPath: string;\n private index: RecordingIndex = { recordings: [] };\n\n constructor(\n dir: string,\n private readonly logger: Logger,\n ) {\n this.dir = dir;\n this.audioDir = join(dir, AUDIO_DIR);\n this.transcriptDataDir = join(dir, TRANSCRIPT_DATA_DIR);\n this.transcriptsDir = join(dir, TRANSCRIPTS_DIR);\n this.summariesDir = join(dir, SUMMARIES_DIR);\n this.indexPath = join(dir, INDEX_FILE);\n }\n\n /** 初始化目录结构并加载索引 */\n async init(): Promise<void> {\n mkdirSync(this.audioDir, { recursive: true });\n mkdirSync(this.transcriptDataDir, { recursive: true });\n mkdirSync(this.transcriptsDir, { recursive: true });\n mkdirSync(this.summariesDir, { recursive: true });\n this.loadIndex();\n this.logger.info(\n `录音存储已初始化: ${this.dir}(共 ${this.index.recordings.length} 条记录)`,\n );\n }\n\n /** 获取音频目录路径 */\n getAudioDir(): string {\n return this.audioDir;\n }\n\n /** 获取转写 JSON 目录路径 */\n getTranscriptDataDir(): string {\n return this.transcriptDataDir;\n }\n\n /** 获取转写目录路径 */\n getTranscriptsDir(): string {\n return this.transcriptsDir;\n }\n\n /** 获取摘要目录路径 */\n getSummariesDir(): string {\n return this.summariesDir;\n }\n\n // ─── 录音入库 ───\n\n /**\n * 收到 recordings.sync 后,将元数据写入索引。\n * 如果同 ID 录音已存在则更新,否则新建。\n * 返回录音 ID。\n */\n ingest(recordingId: string, metadata: RecordingMetadata): string {\n const id = recordingId;\n const existing = this.findById(id);\n\n if (existing) {\n const sameAudioUrl = existing.metadata.oss_audio_url === metadata.oss_audio_url;\n const canPreserveSyncState =\n sameAudioUrl\n && !!existing.audioFile\n && existing.status !== \"syncing_openclaw\"\n && existing.status !== \"sync_failed\";\n\n if (canPreserveSyncState) {\n existing.metadata = metadata;\n existing.updatedAt = new Date().toISOString();\n this.saveIndex();\n this.logger.info(\n `录音元数据已更新: ${id}(同音频,保留状态 ${existing.status})`,\n );\n return id;\n }\n\n // 更新已有记录(覆盖上传/本地文件缺失场景)\n if (existing.transcriptDataFile) {\n rmSync(join(this.dir, existing.transcriptDataFile), { force: true });\n }\n if (existing.transcriptFile) {\n rmSync(join(this.dir, existing.transcriptFile), { force: true });\n }\n if (existing.summaryFile) {\n rmSync(join(this.dir, existing.summaryFile), { force: true });\n }\n existing.metadata = metadata;\n existing.status = \"syncing_openclaw\";\n existing.transcriptDataFile = undefined;\n existing.transcriptFile = undefined;\n existing.summaryFile = undefined;\n existing.title = undefined;\n existing.lastError = undefined;\n existing.updatedAt = new Date().toISOString();\n this.logger.info(`录音元数据已更新: ${id}`);\n } else {\n const entry: RecordingIndexEntry = {\n id,\n metadata,\n status: \"syncing_openclaw\",\n ingestedAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n };\n this.index.recordings.push(entry);\n this.logger.info(`录音元数据已入库: ${id}`);\n }\n\n this.saveIndex();\n return id;\n }\n\n // ─── 状态管理 ───\n\n /**\n * 更新录音传输状态(严格状态机校验)\n */\n updateStatus(\n recordingId: string,\n newStatus: RecordingTransferStatus,\n ): RecordingIndexEntry {\n const entry = this.findById(recordingId);\n if (!entry) {\n throw new Error(`录音不存在: ${recordingId}`);\n }\n\n const validatedStatus = transition(entry.status, newStatus);\n entry.status = validatedStatus;\n entry.updatedAt = new Date().toISOString();\n this.saveIndex();\n this.logger.info(`录音状态更新: ${recordingId} → ${newStatus}`);\n return entry;\n }\n\n /**\n * 记录本地音频文件已下载\n */\n setAudioFile(recordingId: string, filename: string): void {\n const entry = this.findById(recordingId);\n if (!entry) return;\n entry.audioFile = `${AUDIO_DIR}/${filename}`;\n entry.updatedAt = new Date().toISOString();\n this.saveIndex();\n }\n\n /**\n * 记录本地打点文件已下载\n */\n setSrtFile(recordingId: string, filename: string): void {\n const entry = this.findById(recordingId);\n if (!entry) return;\n entry.srtFile = `${AUDIO_DIR}/${filename}`;\n entry.updatedAt = new Date().toISOString();\n this.saveIndex();\n }\n\n /**\n * 记录转写 JSON 文件路径\n */\n setTranscriptDataFile(recordingId: string, filename: string): void {\n const entry = this.findById(recordingId);\n if (!entry) return;\n const nextTranscriptDataFile = `${TRANSCRIPT_DATA_DIR}/${filename}`;\n if (entry.transcriptDataFile && entry.transcriptDataFile !== nextTranscriptDataFile) {\n rmSync(join(this.dir, entry.transcriptDataFile), { force: true });\n }\n entry.transcriptDataFile = nextTranscriptDataFile;\n entry.updatedAt = new Date().toISOString();\n this.saveIndex();\n }\n\n /**\n * 记录转写文件路径\n */\n setTranscriptFile(recordingId: string, filename: string): void {\n const entry = this.findById(recordingId);\n if (!entry) return;\n const nextTranscriptFile = `${TRANSCRIPTS_DIR}/${filename}`;\n if (entry.transcriptFile && entry.transcriptFile !== nextTranscriptFile) {\n rmSync(join(this.dir, entry.transcriptFile), { force: true });\n }\n entry.transcriptFile = nextTranscriptFile;\n entry.updatedAt = new Date().toISOString();\n this.saveIndex();\n }\n\n /**\n * 记录摘要文件路径\n */\n setSummaryFile(recordingId: string, filename: string): void {\n const entry = this.findById(recordingId);\n if (!entry) return;\n const nextSummaryFile = `${SUMMARIES_DIR}/${filename}`;\n if (entry.summaryFile && entry.summaryFile !== nextSummaryFile) {\n rmSync(join(this.dir, entry.summaryFile), { force: true });\n }\n entry.summaryFile = nextSummaryFile;\n entry.updatedAt = new Date().toISOString();\n this.saveIndex();\n }\n\n /**\n * 记录转写标题\n */\n setTitle(recordingId: string, title?: string): void {\n const entry = this.findById(recordingId);\n if (!entry) return;\n entry.title = title?.trim() || undefined;\n entry.updatedAt = new Date().toISOString();\n this.saveIndex();\n }\n\n /**\n * 记录最近一次失败原因;传 undefined 表示清除错误\n */\n setLastError(recordingId: string, error?: string): void {\n const entry = this.findById(recordingId);\n if (!entry) return;\n entry.lastError = error?.trim() || undefined;\n entry.updatedAt = new Date().toISOString();\n this.saveIndex();\n }\n\n /**\n * 读取摘要文本\n */\n readSummary(recordingId: string): string | undefined {\n const entry = this.findById(recordingId);\n if (!entry) return undefined;\n\n if (entry.summaryFile) {\n const summary = this.readRelativeTextFile(entry.summaryFile);\n if (summary?.trim()) {\n return summary.trim();\n }\n }\n\n const transcriptDoc = entry.transcriptDataFile\n ? this.readRelativeTranscriptDocument(entry.transcriptDataFile)\n : undefined;\n return extractTranscriptSummaryFromDocument(transcriptDoc);\n }\n\n /**\n * 优先从 transcript JSON 中读取正文,旧数据回退读取 Markdown。\n */\n readTranscript(recordingId: string): string | undefined {\n const entry = this.findById(recordingId);\n if (!entry) return undefined;\n\n if (entry.transcriptDataFile) {\n const transcriptDoc = this.readRelativeTranscriptDocument(entry.transcriptDataFile);\n const transcriptFromJson = extractTranscriptTextFromDocument(transcriptDoc);\n if (transcriptFromJson !== undefined) {\n return transcriptFromJson;\n }\n }\n\n if (!entry.transcriptFile) return undefined;\n const markdown = this.readRelativeTextFile(entry.transcriptFile);\n if (!markdown) return undefined;\n const transcript = extractTranscriptContent(markdown);\n return transcript || undefined;\n }\n\n /**\n * 读取结构化 transcript JSON。\n */\n readTranscriptDocument(recordingId: string) {\n const entry = this.findById(recordingId);\n if (!entry?.transcriptDataFile) {\n return undefined;\n }\n return this.readRelativeTranscriptDocument(entry.transcriptDataFile);\n }\n\n // ─── 查询 ───\n\n findById(id: string): RecordingIndexEntry | undefined {\n return this.index.recordings.find((r) => r.id === id);\n }\n\n listAll(): RecordingIndexEntry[] {\n return [...this.index.recordings].sort(\n (a, b) => b.metadata.created_at.localeCompare(a.metadata.created_at),\n );\n }\n\n listByStatus(status: RecordingTransferStatus): RecordingIndexEntry[] {\n return this.listAll().filter((r) => r.status === status);\n }\n\n rename(recordingId: string, name: string): RecordingIndexEntry {\n const entry = this.findById(recordingId);\n if (!entry) {\n throw new Error(`录音不存在: ${recordingId}`);\n }\n\n entry.metadata = {\n ...entry.metadata,\n name,\n };\n entry.updatedAt = new Date().toISOString();\n this.saveIndex();\n this.logger.info(`录音名称已更新: ${recordingId} → ${name}`);\n return entry;\n }\n\n // ─── 删除 ───\n\n /**\n * 删除录音及其本地文件(约束 R-4 安全删除)\n *\n * @param opts.localOnly 仅删除本地文件(音频/打点/转写),保留索引条目。\n * App 端\"仅删除本地\"时使用此模式,插件侧保留元数据记录。\n * 默认 false — 完整删除(文件 + 索引)。\n */\n delete(\n recordingId: string,\n opts?: { localOnly?: boolean },\n ): boolean {\n const entry = this.findById(recordingId);\n if (!entry) return false;\n\n // 删除本地文件\n if (entry.audioFile) {\n const audioPath = join(this.dir, entry.audioFile);\n rmSync(audioPath, { force: true });\n }\n if (entry.srtFile) {\n const srtPath = join(this.dir, entry.srtFile);\n rmSync(srtPath, { force: true });\n }\n if (entry.transcriptDataFile) {\n const transcriptDataPath = join(this.dir, entry.transcriptDataFile);\n rmSync(transcriptDataPath, { force: true });\n }\n if (entry.transcriptFile) {\n const transcriptPath = join(this.dir, entry.transcriptFile);\n rmSync(transcriptPath, { force: true });\n }\n if (entry.summaryFile) {\n const summaryPath = join(this.dir, entry.summaryFile);\n rmSync(summaryPath, { force: true });\n }\n\n if (opts?.localOnly) {\n // 保留索引条目,清除文件引用\n entry.audioFile = undefined;\n entry.srtFile = undefined;\n entry.transcriptDataFile = undefined;\n entry.transcriptFile = undefined;\n entry.summaryFile = undefined;\n entry.updatedAt = new Date().toISOString();\n this.saveIndex();\n this.logger.info(`录音本地文件已删除(保留索引): ${recordingId}`);\n } else {\n // 从索引中移除\n this.index.recordings = this.index.recordings.filter(\n (r) => r.id !== recordingId,\n );\n this.saveIndex();\n this.logger.info(`录音已完整删除: ${recordingId}`);\n }\n return true;\n }\n\n // ─── Helpers ───\n\n /**\n * 生成音频文件名。扩展名从 OSS URL 中提取,未提供时默认 .ogg(硬件录音格式)\n */\n buildAudioFilename(recordingId: string, ossUrl?: string): string {\n const ext = ossUrl ? extractAudioExt(ossUrl) : \".ogg\";\n return `${recordingId}${ext}`;\n }\n\n /**\n * 生成打点文件名\n */\n buildSrtFilename(recordingId: string): string {\n return `${recordingId}.srt`;\n }\n\n /**\n * 生成转写 JSON 文件名\n */\n buildTranscriptDataFilename(recordingId: string): string {\n return buildTranscriptDataJsonFilename(recordingId);\n }\n\n /**\n * 生成转写文件名\n * @param summary 摘要标题(≤ 10 字)\n */\n buildTranscriptFilename(recordingId: string, summary: string): string {\n // 清理文件名中的非法字符\n const safeSummary = summary\n .replace(/[/\\\\:*?\"<>|]/g, \"\")\n .trim()\n .slice(0, 20);\n return safeSummary\n ? `${recordingId}_${safeSummary}.md`\n : `${recordingId}.md`;\n }\n\n /**\n * 生成摘要文件名\n */\n buildSummaryFilename(recordingId: string): string {\n return `${recordingId}.md`;\n }\n\n /**\n * 获取音频文件的绝对路径。ossUrl 用于推断文件扩展名\n */\n getAudioFilePath(recordingId: string, ossUrl?: string): string {\n return join(this.audioDir, this.buildAudioFilename(recordingId, ossUrl));\n }\n\n /**\n * 获取打点文件的绝对路径\n */\n getSrtFilePath(recordingId: string): string {\n return join(this.audioDir, this.buildSrtFilename(recordingId));\n }\n\n /**\n * 获取转写 JSON 文件的绝对路径\n */\n getTranscriptDataFilePath(recordingId: string): string {\n return join(this.transcriptDataDir, this.buildTranscriptDataFilename(recordingId));\n }\n\n /**\n * 获取摘要文件的绝对路径\n */\n getSummaryFilePath(recordingId: string): string {\n return join(this.summariesDir, this.buildSummaryFilename(recordingId));\n }\n\n // ─── Persistence ───\n\n private loadIndex(): void {\n if (!existsSync(this.indexPath)) {\n this.index = { recordings: [] };\n return;\n }\n try {\n const raw = JSON.parse(readFileSync(this.indexPath, \"utf-8\"));\n if (raw && Array.isArray(raw.recordings)) {\n let needsRewrite = false;\n const normalized = raw.recordings\n .filter((entry: unknown) => entry && typeof entry === \"object\")\n .map((entry: any) => {\n const compacted: RecordingIndexEntry = {\n id: entry.id,\n metadata: entry.metadata,\n status: entry.status,\n ingestedAt: entry.ingestedAt,\n updatedAt: entry.updatedAt,\n };\n if (typeof entry.audioFile === \"string\") compacted.audioFile = entry.audioFile;\n if (typeof entry.srtFile === \"string\") compacted.srtFile = entry.srtFile;\n if (typeof entry.transcriptFile === \"string\") {\n compacted.transcriptFile = entry.transcriptFile;\n }\n let transcriptDoc = typeof entry.transcriptDataFile === \"string\"\n ? this.readRelativeTranscriptDocument(entry.transcriptDataFile)\n : undefined;\n if (typeof entry.transcriptDataFile === \"string\" && transcriptDoc) {\n compacted.transcriptDataFile = entry.transcriptDataFile;\n } else {\n const legacyTranscriptText = typeof entry.transcript === \"string\" && entry.transcript.trim()\n ? entry.transcript.trim()\n : compacted.transcriptFile\n ? extractTranscriptContent(\n this.readRelativeTextFile(compacted.transcriptFile) ?? \"\",\n ) || undefined\n : undefined;\n const legacyTitle = typeof entry.title === \"string\" && entry.title.trim()\n ? entry.title.trim()\n : deriveTitleFromTranscriptPath(compacted.transcriptFile, compacted.id);\n const legacySummary = typeof entry.summary === \"string\" && entry.summary.trim()\n ? entry.summary.trim()\n : undefined;\n\n if (legacyTranscriptText) {\n transcriptDoc = buildTranscriptDocument({\n recordingId: compacted.id,\n generatedAt: compacted.updatedAt,\n source: {\n provider: \"legacy-markdown\",\n },\n title: legacyTitle,\n summary: legacySummary,\n text: legacyTranscriptText,\n segments: [],\n });\n const transcriptDataFilename = this.buildTranscriptDataFilename(compacted.id);\n writeFileSync(\n join(this.transcriptDataDir, transcriptDataFilename),\n JSON.stringify(transcriptDoc, null, 2),\n \"utf-8\",\n );\n compacted.transcriptDataFile = `${TRANSCRIPT_DATA_DIR}/${transcriptDataFilename}`;\n needsRewrite = true;\n }\n }\n\n if (typeof entry.summaryFile === \"string\") {\n compacted.summaryFile = entry.summaryFile;\n } else if (typeof entry.summary === \"string\" && entry.summary.trim()) {\n const summaryFilename = this.buildSummaryFilename(entry.id);\n writeFileSync(\n join(this.summariesDir, summaryFilename),\n entry.summary.trim(),\n \"utf-8\",\n );\n compacted.summaryFile = `${SUMMARIES_DIR}/${summaryFilename}`;\n needsRewrite = true;\n } else {\n const summaryFromDocument = extractTranscriptSummaryFromDocument(transcriptDoc);\n if (summaryFromDocument) {\n const summaryFilename = this.buildSummaryFilename(entry.id);\n writeFileSync(\n join(this.summariesDir, summaryFilename),\n summaryFromDocument,\n \"utf-8\",\n );\n compacted.summaryFile = `${SUMMARIES_DIR}/${summaryFilename}`;\n needsRewrite = true;\n }\n }\n if (typeof entry.title === \"string\" && entry.title.trim()) {\n compacted.title = entry.title.trim();\n } else {\n const titleFromDocument = extractTranscriptTitleFromDocument(transcriptDoc);\n const derivedTitle = titleFromDocument ?? deriveTitleFromTranscriptPath(\n compacted.transcriptFile,\n compacted.id,\n );\n if (derivedTitle) {\n compacted.title = derivedTitle;\n needsRewrite = true;\n }\n }\n if (typeof entry.lastError === \"string\" && entry.lastError.trim()) {\n compacted.lastError = entry.lastError.trim();\n }\n if (compacted.status === \"transcribing\") {\n compacted.status = \"transcribe_failed\";\n compacted.lastError = compacted.lastError\n ?? \"转写任务已中断,请重新发起转写\";\n compacted.updatedAt = new Date().toISOString();\n needsRewrite = true;\n }\n return compacted;\n });\n const hadLargeFields = raw.recordings.some(\n (entry: any) => entry && typeof entry === \"object\" && (\"transcript\" in entry || \"summary\" in entry),\n );\n this.index = { recordings: normalized };\n if (hadLargeFields || needsRewrite) {\n this.saveIndex();\n }\n } else {\n this.index = { recordings: [] };\n }\n } catch {\n this.logger.warn(`录音索引文件损坏,已重建: ${this.indexPath}`);\n this.index = { recordings: [] };\n }\n }\n\n private readRelativeTextFile(relativePath: string): string | undefined {\n try {\n return readFileSync(join(this.dir, relativePath), \"utf-8\");\n } catch {\n return undefined;\n }\n }\n\n private readRelativeTranscriptDocument(relativePath: string) {\n const raw = this.readRelativeTextFile(relativePath);\n if (!raw) {\n return undefined;\n }\n return parseTranscriptDocument(raw);\n }\n\n private saveIndex(): void {\n writeFileSync(\n this.indexPath,\n JSON.stringify(this.index, null, 2),\n \"utf-8\",\n );\n }\n\n async close(): Promise<void> {\n // 当前无需额外清理\n }\n}\n","/**\n * 录音传输状态机(约束 R-3)\n *\n * 状态流转严格不可跳跃:\n * receiving_failed → receiving\n * receiving → pending_oss_upload\n * pending_oss_upload → uploading_oss\n * uploading_oss → oss_uploaded\n * oss_uploaded → syncing_openclaw\n * syncing_openclaw → synced | sync_failed\n * sync_failed → syncing_openclaw\n * synced → transcribing(仅当已配置 ASR)\n * transcribing → transcribed | transcribe_failed\n * transcribe_failed → transcribing\n * transcribed → transcribing(手动强制重新转写)\n */\n\nimport type { RecordingTransferStatus } from \"../types.js\";\n\n/** 合法的状态转换表:from → Set<to> */\nconst VALID_TRANSITIONS: ReadonlyMap<\n RecordingTransferStatus,\n ReadonlySet<RecordingTransferStatus>\n> = new Map<RecordingTransferStatus, ReadonlySet<RecordingTransferStatus>>([\n [\"receiving_failed\", new Set([\"receiving\"])],\n [\"receiving\", new Set([\"pending_oss_upload\"])],\n [\"pending_oss_upload\", new Set([\"uploading_oss\"])],\n [\"uploading_oss\", new Set([\"oss_uploaded\"])],\n [\"oss_uploaded\", new Set([\"syncing_openclaw\"])],\n [\"syncing_openclaw\", new Set([\"synced\", \"sync_failed\"])],\n [\"sync_failed\", new Set([\"syncing_openclaw\"])],\n [\"synced\", new Set([\"transcribing\"])],\n [\"transcribing\", new Set([\"transcribed\", \"transcribe_failed\"])],\n [\"transcribe_failed\", new Set([\"transcribing\"])],\n [\"transcribed\", new Set([\"transcribing\"])],\n]);\n\n/** 插件侧关注的状态:从 syncing_openclaw 开始 */\nexport type PluginSideStatus = Extract<\n RecordingTransferStatus,\n | \"syncing_openclaw\"\n | \"sync_failed\"\n | \"synced\"\n | \"transcribing\"\n | \"transcribe_failed\"\n | \"transcribed\"\n>;\n\n/**\n * 校验状态转换是否合法\n */\nexport function isValidTransition(\n from: RecordingTransferStatus,\n to: RecordingTransferStatus,\n): boolean {\n const allowed = VALID_TRANSITIONS.get(from);\n return allowed ? allowed.has(to) : false;\n}\n\n/**\n * 尝试执行状态转换,非法转换抛出 Error\n */\nexport function transition(\n from: RecordingTransferStatus,\n to: RecordingTransferStatus,\n): RecordingTransferStatus {\n if (!isValidTransition(from, to)) {\n throw new TransitionError(from, to);\n }\n return to;\n}\n\n/**\n * 状态是否为终态(没有后续合法转换)\n */\nexport function isTerminalStatus(status: RecordingTransferStatus): boolean {\n const allowed = VALID_TRANSITIONS.get(status);\n return !allowed || allowed.size === 0;\n}\n\n/**\n * 状态是否允许触发 ASR 转写\n */\nexport function canStartTranscription(status: RecordingTransferStatus): boolean {\n return (\n status === \"synced\"\n || status === \"transcribe_failed\"\n || status === \"transcribed\"\n );\n}\n\n/**\n * 获取当前状态的所有合法后续状态\n */\nexport function getNextStatuses(\n status: RecordingTransferStatus,\n): RecordingTransferStatus[] {\n const allowed = VALID_TRANSITIONS.get(status);\n return allowed ? [...allowed] : [];\n}\n\nexport class TransitionError extends Error {\n constructor(\n public readonly from: RecordingTransferStatus,\n public readonly to: RecordingTransferStatus,\n ) {\n super(`非法状态转换: ${from} → ${to}`);\n this.name = \"TransitionError\";\n }\n}\n","export {\n RecordingStorage,\n resolveRecordingStorageDir,\n type RecordingIndexEntry,\n type RecordingStorageContext,\n} from \"./storage.js\";\n\nexport {\n TRANSCRIPT_DOCUMENT_SCHEMA_VERSION,\n buildTranscriptDataFilename,\n buildTranscriptDocument,\n parseTranscriptDocument,\n extractTranscriptTextFromDocument,\n extractTranscriptSummaryFromDocument,\n extractTranscriptTitleFromDocument,\n extractSourceTextListFromDocument,\n type TranscriptDocument,\n type TranscriptDocumentContentItem,\n type TranscriptDocumentNormalized,\n type TranscriptDocumentSegment,\n type TranscriptDocumentSource,\n} from \"./transcript-document.js\";\n\nexport {\n isValidTransition,\n transition,\n isTerminalStatus,\n canStartTranscription,\n getNextStatuses,\n TransitionError,\n} from \"./state-machine.js\";\n\nexport {\n downloadFile,\n downloadRecordingFiles,\n type DownloadResult,\n type DownloadOptions,\n} from \"./downloader.js\";\n\nexport {\n isAsrConfigured,\n validateAsrConfig,\n initializeAsr,\n transcribeAudio,\n buildTranscriptMarkdown,\n extractSummary,\n runTranscriptionWorkflow,\n type TranscriptionResult,\n type TranscriptSegment,\n} from \"./asr.js\";\n\nexport {\n detectEnvironment,\n selectModelByMemory,\n isModelDownloaded,\n downloadModel,\n findWhisperBinary,\n transcribeWithWhisperLocal,\n getWhisperLocalStatus,\n} from \"./whisper-local.js\";\n\nexport {\n handleRecordingSync,\n triggerTranscription,\n type RecordingStatusEvent,\n type RecordingSyncOptions,\n} from \"./handler.js\";\n","/**\n * OSS 文件下载器(约束 R-6)\n *\n * 从 OSS URL 下载原始音频(mp3)和打点文件(srt)到本地。\n * 支持重试、超时控制、下载进度日志。\n */\n\nimport { createWriteStream, existsSync, mkdirSync, statSync, unlinkSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { pipeline } from \"node:stream/promises\";\nimport { Readable } from \"node:stream\";\nimport type { Logger } from \"../logger.js\";\n\n// ─── Types ───\n\nexport interface DownloadOptions {\n /** 下载超时(毫秒),默认 5 分钟 */\n timeoutMs?: number;\n /** 最大重试次数,默认 3 */\n maxRetries?: number;\n /** 重试间隔基数(毫秒),默认 2000 */\n retryBackoffMs?: number;\n}\n\nexport interface DownloadResult {\n ok: boolean;\n /** 下载的文件大小(字节) */\n sizeBytes?: number;\n /** 耗时(毫秒) */\n elapsedMs?: number;\n /** 错误信息 */\n error?: string;\n}\n\nconst DEFAULT_TIMEOUT_MS = 5 * 60 * 1000; // 5 分钟(最大 ~56MB 文件)\nconst DEFAULT_MAX_RETRIES = 3;\nconst DEFAULT_RETRY_BACKOFF_MS = 2000;\n\n// ─── Public API ───\n\n/**\n * 从 URL 下载文件到本地路径\n */\nexport async function downloadFile(\n url: string,\n destPath: string,\n logger: Logger,\n options?: DownloadOptions,\n): Promise<DownloadResult> {\n const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const maxRetries = options?.maxRetries ?? DEFAULT_MAX_RETRIES;\n const retryBackoffMs = options?.retryBackoffMs ?? DEFAULT_RETRY_BACKOFF_MS;\n\n mkdirSync(dirname(destPath), { recursive: true });\n\n let lastError: string | undefined;\n\n for (let attempt = 1; attempt <= maxRetries; attempt++) {\n const startMs = Date.now();\n try {\n logger.info(\n `[downloader] 开始下载 (attempt ${attempt}/${maxRetries}): ${url}`,\n );\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n\n try {\n const res = await fetch(url, { signal: controller.signal });\n\n if (!res.ok) {\n throw new Error(`HTTP ${res.status} ${res.statusText}`);\n }\n\n if (!res.body) {\n throw new Error(\"响应体为空\");\n }\n\n // 写入文件\n const writeStream = createWriteStream(destPath);\n const readable = Readable.fromWeb(res.body as any);\n await pipeline(readable, writeStream);\n\n const elapsed = Date.now() - startMs;\n const fileSize = existsSync(destPath)\n ? statSync(destPath).size\n : 0;\n\n logger.info(\n `[downloader] 下载完成: ${destPath} (${formatBytes(fileSize)}, ${elapsed}ms)`,\n );\n\n return { ok: true, sizeBytes: fileSize, elapsedMs: elapsed };\n } finally {\n clearTimeout(timer);\n }\n } catch (err: any) {\n lastError = err?.message ?? String(err);\n\n // 清理可能写了一半的文件\n try {\n if (existsSync(destPath)) unlinkSync(destPath);\n } catch {\n // ignore\n }\n\n const isAbort = err?.name === \"AbortError\";\n logger.warn(\n `[downloader] 下载失败 (attempt ${attempt}/${maxRetries}): ${isAbort ? \"超时\" : lastError}`,\n );\n\n if (attempt < maxRetries) {\n const delay = retryBackoffMs * Math.pow(2, attempt - 1);\n logger.info(`[downloader] ${delay}ms 后重试...`);\n await sleep(delay);\n }\n }\n }\n\n return { ok: false, error: lastError ?? \"下载失败\" };\n}\n\n/**\n * 下载录音的音频文件和打点文件\n */\nexport async function downloadRecordingFiles(\n ossAudioUrl: string,\n ossSrtUrl: string | undefined,\n audioDestPath: string,\n srtDestPath: string,\n logger: Logger,\n options?: DownloadOptions,\n): Promise<{\n audio: DownloadResult;\n srt: DownloadResult | null;\n}> {\n // 下载音频(必须)\n const audio = await downloadFile(ossAudioUrl, audioDestPath, logger, options);\n\n // 下载打点文件(可选)\n let srt: DownloadResult | null = null;\n if (ossSrtUrl) {\n srt = await downloadFile(ossSrtUrl, srtDestPath, logger, options);\n if (!srt.ok) {\n // 打点文件下载失败不阻断主流程,仅警告\n logger.warn(`[downloader] 打点文件下载失败(非致命): ${srt.error}`);\n }\n }\n\n return { audio, srt };\n}\n\n// ─── Helpers ───\n\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes}B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","/**\n * 录音同步处理器(§2 阶段 4–5)\n *\n * 统一处理 recordings.sync 请求:\n * 1. 元数据入库\n * 2. 从 OSS 下载音频 + 打点文件\n * 3. 更新状态 → synced\n * 4. 如已配置 ASR → 自动触发转写\n */\n\nimport type {\n RecordingMetadata,\n RecordingSyncResult,\n AsrConfig,\n RecordingTranscriptItem,\n RecordingTransferStatus,\n} from \"../types.js\";\nimport type { Logger } from \"../logger.js\";\nimport { RecordingStorage } from \"./storage.js\";\nimport { downloadRecordingFiles } from \"./downloader.js\";\nimport { isAsrConfigured, runTranscriptionWorkflow } from \"./asr.js\";\nimport { canStartTranscription } from \"./state-machine.js\";\nimport { deleteAccountOssFile } from \"./account-oss.js\";\n\nexport interface RecordingStatusEvent {\n recordingId: string;\n transfer_status: RecordingTransferStatus;\n audioFile?: string;\n srtFile?: string;\n transcriptDataFile?: string;\n transcriptFile?: string;\n transcript?: RecordingTranscriptItem[];\n summary?: string;\n title: string;\n updatedAt: string;\n error?: string;\n}\n\nexport interface RecordingSyncOptions {\n notifyStatus?: (event: RecordingStatusEvent) => void;\n}\n\nfunction emitRecordingStatus(\n recordingId: string,\n storage: RecordingStorage,\n logger: Logger,\n notifyStatus?: RecordingSyncOptions[\"notifyStatus\"],\n error?: string,\n extras?: Pick<RecordingStatusEvent, \"transcript\" | \"summary\" | \"title\">,\n): void {\n if (!notifyStatus) {\n return;\n }\n\n const entry = storage.findById(recordingId);\n if (!entry) {\n return;\n }\n\n const title = extras?.title?.trim()\n || entry.title?.trim()\n || entry.metadata.name?.trim()\n || entry.id;\n const persistedError = entry.lastError?.trim() || undefined;\n\n try {\n notifyStatus({\n recordingId: entry.id,\n transfer_status: entry.status,\n audioFile: entry.audioFile,\n srtFile: entry.srtFile,\n transcriptDataFile: entry.transcriptDataFile,\n transcriptFile: entry.transcriptFile,\n transcript: extras?.transcript,\n summary: extras?.summary,\n title,\n updatedAt: entry.updatedAt,\n error: error ?? persistedError,\n });\n } catch (err: any) {\n logger.error(\n `[recording-status] 状态事件发送失败: ${recordingId}, ${err?.message ?? err}`,\n );\n }\n}\n\nasync function runRecordingSyncInBackground(\n metadata: RecordingMetadata,\n recordingId: string,\n storage: RecordingStorage,\n asrConfig: AsrConfig | undefined,\n logger: Logger,\n options: RecordingSyncOptions,\n): Promise<void> {\n const audioDestPath = storage.getAudioFilePath(\n recordingId,\n metadata.oss_audio_url,\n );\n const srtDestPath = storage.getSrtFilePath(recordingId);\n\n logger.info(\n `[recording-sync] 开始下载录音文件: ${recordingId}, audio=${metadata.oss_audio_url}`,\n );\n\n const downloadResult = await downloadRecordingFiles(\n metadata.oss_audio_url,\n metadata.oss_srt_url,\n audioDestPath,\n srtDestPath,\n logger,\n );\n\n if (!downloadResult.audio.ok) {\n const error = `音频下载失败: ${downloadResult.audio.error}`;\n logger.error(`[recording-sync] ${error}: ${recordingId}`);\n storage.updateStatus(recordingId, \"sync_failed\");\n storage.setLastError(recordingId, error);\n emitRecordingStatus(\n recordingId,\n storage,\n logger,\n options.notifyStatus,\n error,\n );\n return;\n }\n\n storage.setLastError(recordingId, undefined);\n storage.setAudioFile(\n recordingId,\n storage.buildAudioFilename(recordingId, metadata.oss_audio_url),\n );\n if (downloadResult.srt?.ok) {\n storage.setSrtFile(recordingId, storage.buildSrtFilename(recordingId));\n }\n\n storage.updateStatus(recordingId, \"synced\");\n logger.info(`[recording-sync] 录音已同步: ${recordingId}`);\n emitRecordingStatus(recordingId, storage, logger, options.notifyStatus);\n\n if (isAsrConfigured(asrConfig) && canStartTranscription(\"synced\")) {\n await triggerTranscription(\n recordingId,\n storage,\n asrConfig!,\n logger,\n options,\n );\n }\n}\n\n/**\n * 处理 recordings.sync 请求的核心逻辑\n */\nexport async function handleRecordingSync(\n recordingId: string,\n metadata: RecordingMetadata,\n storage: RecordingStorage,\n asrConfig: AsrConfig | undefined,\n logger: Logger,\n options: RecordingSyncOptions = {},\n): Promise<RecordingSyncResult> {\n const existing = storage.findById(recordingId);\n const shouldDownloadAndSync =\n !existing\n || existing.metadata.oss_audio_url !== metadata.oss_audio_url\n || !existing.audioFile\n || existing.status === \"syncing_openclaw\"\n || existing.status === \"sync_failed\";\n\n storage.ingest(recordingId, metadata);\n if (shouldDownloadAndSync) {\n runRecordingSyncInBackground(\n metadata,\n recordingId,\n storage,\n asrConfig,\n logger,\n options,\n ).catch((err) => {\n const error = `录音同步失败: ${err?.message ?? err}`;\n logger.error(`[recording-sync] ${error}: ${recordingId}`);\n const current = storage.findById(recordingId);\n if (current?.status === \"syncing_openclaw\") {\n storage.updateStatus(recordingId, \"sync_failed\");\n }\n storage.setLastError(recordingId, error);\n emitRecordingStatus(\n recordingId,\n storage,\n logger,\n options.notifyStatus,\n error,\n );\n });\n } else {\n logger.info(\n `[recording-sync] 录音已存在且音频未变化,跳过重复下载: ${recordingId}`,\n );\n emitRecordingStatus(recordingId, storage, logger, options.notifyStatus);\n\n const current = storage.findById(recordingId);\n if (current?.status === \"synced\" && isAsrConfigured(asrConfig)) {\n triggerTranscription(\n recordingId,\n storage,\n asrConfig!,\n logger,\n options,\n ).catch((err) => {\n logger.error(\n `[asr-trigger] 转写触发失败: ${recordingId}, ${err?.message ?? err}`,\n );\n });\n }\n }\n\n const current = storage.findById(recordingId);\n return {\n ok: true,\n recordingId,\n transfer_status: current?.status ?? \"syncing_openclaw\",\n ...(current?.lastError ? { error: current.lastError } : {}),\n };\n}\n\n/**\n * 触发 ASR 转写(可从 sync handler 自动触发或手动重试调用)\n */\nexport async function triggerTranscription(\n recordingId: string,\n storage: RecordingStorage,\n asrConfig: AsrConfig,\n logger: Logger,\n options: RecordingSyncOptions = {},\n): Promise<void> {\n const entry = storage.findById(recordingId);\n if (!entry) {\n logger.warn(`[asr-trigger] 录音不存在: ${recordingId}`);\n return;\n }\n\n if (!canStartTranscription(entry.status)) {\n logger.warn(\n `[asr-trigger] 当前状态不允许转写: ${recordingId} (status=${entry.status})`,\n );\n return;\n }\n\n // 状态 → transcribing\n storage.updateStatus(recordingId, \"transcribing\");\n storage.setLastError(recordingId, undefined);\n emitRecordingStatus(recordingId, storage, logger, options.notifyStatus);\n\n const audioFilePath = storage.getAudioFilePath(recordingId);\n\n let result: Awaited<ReturnType<typeof runTranscriptionWorkflow>>;\n try {\n result = await runTranscriptionWorkflow({\n audioFilePath,\n audioOssUrl: entry.metadata.oss_audio_url,\n config: asrConfig,\n markers: entry.metadata.markers ?? [],\n recordingName: entry.metadata.name,\n durationSec: entry.metadata.duration_sec,\n createdAt: entry.metadata.created_at,\n transcriptDataDir: storage.getTranscriptDataDir(),\n transcriptsDir: storage.getTranscriptsDir(),\n summariesDir: storage.getSummariesDir(),\n recordingId,\n logger,\n });\n } catch (err: any) {\n const error = `转写任务异常: ${err?.message ?? err}`;\n logger.error(`[asr-trigger] ${error}: ${recordingId}`);\n result = { ok: false, error };\n }\n\n if (result.ok && result.transcriptFilename) {\n if (result.transcriptDataFilename) {\n storage.setTranscriptDataFile(recordingId, result.transcriptDataFilename);\n }\n storage.setTranscriptFile(recordingId, result.transcriptFilename);\n if (result.summaryFilename) {\n storage.setSummaryFile(recordingId, result.summaryFilename);\n }\n storage.setTitle(recordingId, result.title);\n storage.updateStatus(recordingId, \"transcribed\");\n emitRecordingStatus(\n recordingId,\n storage,\n logger,\n options.notifyStatus,\n undefined,\n {\n transcript: result.transcript ?? [],\n summary: result.summary,\n title: result.title ?? \"\",\n },\n );\n logger.info(\n `[asr-trigger] 转写完成: ${recordingId}, summary=\"${result.summary}\"`,\n );\n\n // ASR 成功后删除 OSS 上的音频文件(imp-account-user-controllers-api §5.7)\n const ossAudioUrl = entry.metadata.oss_audio_url?.trim();\n if (ossAudioUrl) {\n void deleteAccountOssFile(ossAudioUrl, logger).catch((err) => {\n logger.warn(\n `[asr-trigger] OSS 音频清理异常 (非致命): ${recordingId}, ${err?.message ?? err}`,\n );\n });\n }\n } else {\n const error = result.error ?? \"ASR 转写失败\";\n storage.updateStatus(recordingId, \"transcribe_failed\");\n storage.setLastError(recordingId, error);\n emitRecordingStatus(\n recordingId,\n storage,\n logger,\n options.notifyStatus,\n error,\n );\n logger.error(\n `[asr-trigger] 转写失败: ${recordingId}, error=${error}`,\n );\n }\n}\n","/**\n * Account Service OSS 文件删除(imp-account-user-controllers-api §5.7)\n *\n * 调用 `POST /account/file/delete?fileUrl=...`,`fileUrl` 通过查询串传递\n * (后端确认的传参方式,form-urlencoded / multipart 经网关都会丢字段)。\n */\n\nimport type { Logger } from \"../logger.js\";\nimport { loadApiKey } from \"../auth/credentials.js\";\nimport { getEnvUrls } from \"../env.js\";\n\ninterface AccountServiceResponse {\n code?: string | number;\n msg?: string | null;\n data?: unknown;\n}\n\nexport interface DeleteOssFileResult {\n ok: boolean;\n error?: string;\n}\n\n/**\n * 删除 account-service 上传到 OSS 的文件。\n * 只接受形如 `https://{bucket}.{endpoint}/{objectKey}` 的完整 URL(即上传接口返回值)。\n * 失败不抛异常,由调用方按场景决定是否致命。\n */\nexport async function deleteAccountOssFile(\n fileUrl: string,\n logger: Logger,\n): Promise<DeleteOssFileResult> {\n const trimmed = fileUrl?.trim();\n if (!trimmed) {\n return { ok: false, error: \"fileUrl is empty\" };\n }\n\n const apiKey = loadApiKey();\n if (!apiKey) {\n return { ok: false, error: \"API Key 未设置,跳过 OSS 文件删除\" };\n }\n\n const baseEndpoint = getEnvUrls().accountFileDeleteUrl;\n const headerKey = apiKey.startsWith(\"Bearer \")\n ? apiKey.slice(\"Bearer \".length)\n : apiKey;\n\n const url = new URL(baseEndpoint);\n url.searchParams.set(\"fileUrl\", trimmed);\n const endpoint = url.toString();\n\n logger.info(`[account-oss-delete] 提交 OSS 文件删除: endpoint=${endpoint}`);\n\n let res: Response;\n try {\n res = await fetch(endpoint, {\n method: \"POST\",\n headers: {\n \"X-Api-Key-Id\": headerKey,\n },\n });\n } catch (err: any) {\n const error = err?.message ?? String(err);\n logger.warn(`[account-oss-delete] 网络异常: ${error}`);\n return { ok: false, error };\n }\n\n const text = await res.text();\n if (!res.ok) {\n logger.warn(\n `[account-oss-delete] HTTP 错误: status=${res.status}, body=${text.slice(0, 300)}`,\n );\n return { ok: false, error: `HTTP ${res.status} ${text.slice(0, 200)}` };\n }\n\n let payload: AccountServiceResponse | undefined;\n try {\n payload = text ? (JSON.parse(text) as AccountServiceResponse) : undefined;\n } catch {\n logger.warn(`[account-oss-delete] 响应非 JSON: body=${text.slice(0, 300)}`);\n return { ok: false, error: \"response is not JSON\" };\n }\n\n const code = typeof payload?.code === \"number\" ? String(payload.code) : payload?.code?.trim?.();\n if (code !== \"000000\") {\n const msg = payload?.msg?.trim?.() || text.slice(0, 200);\n logger.warn(`[account-oss-delete] 业务失败: code=${code ?? \"n/a\"}, msg=${msg}`);\n return { ok: false, error: `${code ?? \"unknown\"} ${msg}`.trim() };\n }\n\n logger.info(`[account-oss-delete] OSS 文件已删除: fileUrl=${trimmed}`);\n return { ok: true };\n}\n","import {\n closeSync,\n mkdirSync,\n openSync,\n readFileSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { loadApiKey } from \"../auth/credentials.js\";\nimport { RelayClient } from \"./relay-client.js\";\nimport { TunnelProxy } from \"./proxy.js\";\nimport type { UpdateInfo } from \"../update/types.js\";\nimport { redactUrlSecrets } from \"./utils.js\";\n\nconst DEFAULT_HEARTBEAT_SEC = 10;\nconst DEFAULT_RECONNECT_BACKOFF_MS = 2000;\n\ninterface TunnelServiceOptions {\n /** Relay Server WebSocket 地址(构建时从 RELAY_TUNNEL_URL 注入) */\n tunnelUrl: string;\n gatewayBaseUrl: string;\n /** Gateway 鉴权模式 */\n gatewayAuthMode?: \"token\" | \"password\";\n /** Gateway 鉴权 token */\n gatewayToken?: string;\n /** Gateway 鉴权密码 */\n gatewayPassword?: string;\n /** 心跳间隔(秒),默认 10 */\n heartbeatSec?: number;\n /** 重连基础退避时间(毫秒),默认 2000 */\n reconnectBackoffMs?: number;\n logger: {\n info: (msg: string) => void;\n warn: (msg: string) => void;\n error: (msg: string) => void;\n };\n}\n\nexport interface RelayTunnelService {\n id: string;\n start(ctx: { stateDir: string }): Promise<void>;\n stop(): Promise<void>;\n notifyUpdateAvailable(update: UpdateInfo): void;\n clearPendingUpdate(): void;\n deactivateForExternalTunnel(reason: string): Promise<void>;\n}\n\n/**\n * 隧道服务:组装 RelayClient + TunnelProxy,作为 registerService 的入口。\n */\nexport function createTunnelService(\n opts: TunnelServiceOptions,\n): RelayTunnelService {\n let client: RelayClient | null = null;\n let proxy: TunnelProxy | null = null;\n let abortController: AbortController | null = null;\n let lockFilePath: string | null = null;\n let lockFd: number | null = null;\n let pendingPluginUpdate: UpdateInfo | null = null;\n let suppressedByExternalTunnel = false;\n\n function emitPendingPluginUpdate(reason: string): void {\n const update = pendingPluginUpdate;\n if (!update || !client?.isConnected()) return;\n\n const frame = JSON.stringify({\n type: \"event\",\n event: \"plugin.updateAvailable\",\n payload: {\n pluginId: \"phone-notifications\",\n pluginName: \"消息通知\",\n current: update.current,\n latest: update.latest,\n },\n });\n opts.logger.info(\n `Relay tunnel: sending plugin.updateAvailable ${update.current} → ${update.latest} (${reason})`,\n );\n client.sendRaw(frame);\n }\n\n function isProcessAlive(pid: number): boolean {\n if (!Number.isInteger(pid) || pid <= 0) return false;\n if (pid === process.pid) return true;\n try {\n process.kill(pid, 0);\n return true;\n } catch (err: any) {\n return err?.code === \"EPERM\";\n }\n }\n\n function readLockOwner(filePath: string): number | null {\n try {\n const parsed = JSON.parse(readFileSync(filePath, \"utf-8\")) as {\n pid?: unknown;\n };\n return typeof parsed.pid === \"number\" ? parsed.pid : null;\n } catch {\n return null;\n }\n }\n\n function releaseLock(): void {\n const filePath = lockFilePath;\n const fd = lockFd;\n lockFilePath = null;\n lockFd = null;\n\n if (fd !== null) {\n try {\n closeSync(fd);\n } catch {\n // ignore\n }\n }\n if (filePath) {\n try {\n unlinkSync(filePath);\n } catch {\n // ignore\n }\n }\n }\n\n function acquireLock(filePath: string): boolean {\n mkdirSync(dirname(filePath), { recursive: true });\n\n for (let attempt = 0; attempt < 2; attempt++) {\n try {\n const fd = openSync(filePath, \"wx\", 0o600);\n writeFileSync(\n fd,\n JSON.stringify({\n pid: process.pid,\n startedAt: new Date().toISOString(),\n tunnelUrl: redactUrlSecrets(opts.tunnelUrl),\n }) + \"\\n\",\n );\n lockFilePath = filePath;\n lockFd = fd;\n return true;\n } catch (err: any) {\n if (err?.code !== \"EEXIST\") {\n opts.logger.error(\n `Relay tunnel: failed to acquire local lock ${filePath}: ${String(err)}`,\n );\n return false;\n }\n\n const ownerPid = readLockOwner(filePath);\n if (ownerPid && !isProcessAlive(ownerPid)) {\n opts.logger.warn(\n `Relay tunnel: removing stale local lock owned by dead pid=${ownerPid}`,\n );\n try {\n unlinkSync(filePath);\n } catch {\n // ignore, retry below will fail if lock is still present\n }\n continue;\n }\n\n opts.logger.warn(\n `Relay tunnel: another local process already owns the tunnel lock${ownerPid ? ` (pid=${ownerPid})` : \"\"}; skipping connection to avoid duplicate token sessions`,\n );\n return false;\n }\n }\n\n return false;\n }\n\n async function shutdownRuntime(reason: string): Promise<void> {\n await client?.stop(reason);\n if (abortController) {\n abortController.abort();\n abortController = null;\n }\n releaseLock();\n proxy?.cleanup();\n proxy = null;\n client = null;\n }\n\n return {\n id: \"relay-tunnel\",\n\n async start(ctx: { stateDir: string }) {\n if (suppressedByExternalTunnel) {\n opts.logger.info(\n \"Relay tunnel: external tunnel currently owns ingress; skipping relay startup\",\n );\n return;\n }\n\n // 先清理上一轮连接,防止 start() 被重复调用时产生多个 RelayClient 互踢\n if (abortController) {\n opts.logger.info(\"Relay tunnel: aborting previous connection before restart\");\n await shutdownRuntime(\"service restarting\");\n }\n\n const apiKey = loadApiKey();\n if (!apiKey) {\n opts.logger.warn(\n \"Relay tunnel: apiKey 未设置,跳过隧道连接。请执行 openclaw ntf auth set-api-key <apiKey>\",\n );\n return;\n }\n\n const { logger } = opts;\n const baseStateDir = join(ctx.stateDir, \"plugins\", \"phone-notifications\");\n logger.info(\n `Relay tunnel: starting (pid=${process.pid}, url=${redactUrlSecrets(opts.tunnelUrl)}, heartbeat=${opts.heartbeatSec ?? DEFAULT_HEARTBEAT_SEC}s, backoff=${opts.reconnectBackoffMs ?? DEFAULT_RECONNECT_BACKOFF_MS}ms, gateway=${opts.gatewayBaseUrl}, hasGatewayToken=${!!opts.gatewayToken}, hasGatewayPwd=${!!opts.gatewayPassword})`,\n );\n const statusFilePath = join(baseStateDir, \"tunnel-status.json\");\n const lockPath = join(baseStateDir, \"relay-tunnel.lock\");\n\n if (!acquireLock(lockPath)) {\n return;\n }\n\n try {\n client = new RelayClient({\n tunnelUrl: opts.tunnelUrl,\n apiKey,\n heartbeatSec: opts.heartbeatSec ?? DEFAULT_HEARTBEAT_SEC,\n reconnectBackoffMs: opts.reconnectBackoffMs ?? DEFAULT_RECONNECT_BACKOFF_MS,\n statusFilePath,\n logger,\n });\n\n proxy = new TunnelProxy({\n stateDir: baseStateDir,\n hostStateDir: ctx.stateDir,\n gatewayBaseUrl: opts.gatewayBaseUrl,\n gatewayAuthMode: opts.gatewayAuthMode,\n gatewayToken: opts.gatewayToken,\n gatewayPassword: opts.gatewayPassword,\n client,\n logger,\n });\n\n client.onInbound((frame) => proxy!.handleFrame(frame));\n client.onConnected(() => {\n emitPendingPluginUpdate(\"relay connected\");\n });\n\n abortController = new AbortController();\n // 非阻塞启动,connectWithAutoReconnect 内部会保持运行\n client.connectWithAutoReconnect(abortController.signal).catch((err) => {\n releaseLock();\n logger.error(`Relay tunnel: unexpected error: ${err}`);\n });\n\n logger.info(\"Relay tunnel 服务已启动\");\n } catch (err) {\n releaseLock();\n throw err;\n }\n },\n\n async stop() {\n suppressedByExternalTunnel = false;\n await shutdownRuntime(\"service stopping\");\n opts.logger.info(\"Relay tunnel 服务已停止\");\n },\n\n async deactivateForExternalTunnel(reason: string) {\n if (suppressedByExternalTunnel && !client && !proxy && !abortController) {\n return;\n }\n\n suppressedByExternalTunnel = true;\n opts.logger.info(\n `Relay tunnel: external tunnel claimed ingress (${reason}), shutting down relay connection`,\n );\n await shutdownRuntime(\"external tunnel active\");\n },\n\n notifyUpdateAvailable(update: UpdateInfo) {\n pendingPluginUpdate = update;\n emitPendingPluginUpdate(\"update detected\");\n },\n\n clearPendingUpdate() {\n pendingPluginUpdate = null;\n },\n };\n}\n","import { writeFileSync, mkdirSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport WebSocket from \"ws\";\nimport type { InboundFrame, OutboundFrame } from \"./types.js\";\nimport { maskSecret, redactUrlSecrets } from \"./utils.js\";\n\nfunction previewText(text: string, max = 500): string {\n return text.length <= max ? text : `${text.substring(0, max)}…`;\n}\n\n/** WebSocket Upgrade 握手超时(毫秒)。云上常见 NAT/中间盒吞包场景下兜底用。 */\nconst HANDSHAKE_TIMEOUT_MS = 15_000;\n/** 兜底 watchdog:如果握手超时也没触发,强制 terminate 进入重连路径。 */\nconst CONNECT_WATCHDOG_MS = 20_000;\n/** 断线期间发送会非常密集,限频避免把真正的断线原因刷掉。 */\nconst SEND_SKIPPED_LOG_INTERVAL_MS = 30_000;\n\n/** 持久化到磁盘的隧道连接状态 */\nexport interface TunnelStatusInfo {\n /** 当前连接状态 */\n state: \"connected\" | \"disconnected\" | \"connecting\" | \"stopped\";\n /** 状态变更时间 ISO */\n since: string;\n /** 累计重连次数 */\n reconnectAttempt: number;\n /** 上次断开原因(仅 disconnected 时有值) */\n lastDisconnectReason?: string;\n}\n\nexport interface RelayClientOptions {\n tunnelUrl: string;\n apiKey: string;\n heartbeatSec: number;\n reconnectBackoffMs: number;\n /** 状态文件路径,设置后会在连接状态变更时写入 */\n statusFilePath?: string;\n logger: {\n info: (msg: string) => void;\n warn: (msg: string) => void;\n error: (msg: string) => void;\n };\n}\n\nexport type InboundHandler = (frame: InboundFrame) => void | Promise<void>;\nexport type ConnectedHandler = () => void | Promise<void>;\n\n/**\n * Relay WebSocket 客户端。\n * 负责建连、token 认证、心跳保活、断线指数退避重连。\n */\nexport class RelayClient {\n private ws: WebSocket | null = null;\n private heartbeatTimer: ReturnType<typeof setInterval> | null = null;\n private reconnectAttempt = 0;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private handlers: InboundHandler[] = [];\n private connectedHandlers: ConnectedHandler[] = [];\n private aborted = false;\n private lastInboundAt = 0;\n private stopPromise: Promise<void> | null = null;\n private skippedSendLogLastAt: number | null = null;\n private skippedSendLogSuppressed = 0;\n\n constructor(private readonly opts: RelayClientOptions) {}\n\n /** 写连接状态到磁盘 */\n private writeStatus(\n state: TunnelStatusInfo[\"state\"],\n lastDisconnectReason?: string,\n ): void {\n if (!this.opts.statusFilePath) return;\n const info: TunnelStatusInfo = {\n state,\n since: new Date().toISOString(),\n reconnectAttempt: this.reconnectAttempt,\n lastDisconnectReason,\n };\n try {\n mkdirSync(dirname(this.opts.statusFilePath), { recursive: true });\n writeFileSync(this.opts.statusFilePath, JSON.stringify(info, null, 2));\n } catch {\n // 写状态文件失败不影响主流程\n }\n }\n\n /** 注册入站帧处理函数 */\n onInbound(handler: InboundHandler): void {\n this.handlers.push(handler);\n }\n\n /** 注册连接成功后的回调 */\n onConnected(handler: ConnectedHandler): void {\n this.connectedHandlers.push(handler);\n }\n\n /** 当前是否已连上 Relay */\n isConnected(): boolean {\n return this.ws?.readyState === WebSocket.OPEN;\n }\n\n /** 优雅停止客户端,优先发送 close 帧,超时后再强制 terminate */\n async stop(reason = \"client stopping\"): Promise<void> {\n if (this.stopPromise) {\n return this.stopPromise;\n }\n\n this.aborted = true;\n this.writeStatus(\"stopped\");\n this.stopHeartbeat();\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n\n const ws = this.ws;\n this.ws = null;\n if (!ws) {\n return;\n }\n\n this.opts.logger.info(\n `Relay tunnel: stopping client (readyState=${ws.readyState}, reason=${reason})`,\n );\n\n if (\n ws.readyState === WebSocket.CLOSED ||\n ws.readyState === WebSocket.CLOSING\n ) {\n return;\n }\n\n if (ws.readyState !== WebSocket.OPEN) {\n try {\n ws.terminate();\n } catch {\n // ignore\n }\n return;\n }\n\n this.stopPromise = new Promise<void>((resolve) => {\n let finished = false;\n let fallbackTimer: ReturnType<typeof setTimeout> | null = null;\n\n const finish = () => {\n if (finished) return;\n finished = true;\n if (fallbackTimer) {\n clearTimeout(fallbackTimer);\n fallbackTimer = null;\n }\n ws.off(\"close\", handleClose);\n ws.off(\"error\", handleError);\n this.stopPromise = null;\n resolve();\n };\n\n const handleClose = () => finish();\n const handleError = () => finish();\n\n ws.once(\"close\", handleClose);\n ws.once(\"error\", handleError);\n\n fallbackTimer = setTimeout(() => {\n this.opts.logger.warn(\n \"Relay tunnel: graceful close timed out, forcing terminate\",\n );\n try {\n ws.terminate();\n } catch {\n // ignore\n }\n finish();\n }, 1500);\n\n try {\n ws.close(1000, reason);\n } catch {\n finish();\n }\n });\n\n await this.stopPromise;\n }\n\n /** 发送出站帧 */\n send(frame: OutboundFrame): void {\n if (this.ws?.readyState === WebSocket.OPEN) {\n const payload = JSON.stringify(frame);\n this.opts.logger.info(\n `Relay tunnel: ▶ send frame type=${frame.type}, id=${\"id\" in frame ? frame.id : \"N/A\"} (${payload.length} chars)`,\n );\n this.ws.send(payload);\n } else {\n this.logSendSkipped(\"send\", `frame type=${frame.type}`);\n }\n }\n\n /** 原样透传文本到 Relay(用于 Gateway WS 响应直接回传) */\n sendRaw(text: string): void {\n if (this.ws?.readyState === WebSocket.OPEN) {\n this.opts.logger.info(\n `Relay tunnel: ▶ sendRaw (${text.length} chars): ${text.length <= 500 ? text : text.substring(0, 500) + \"…\"}`,\n );\n this.ws.send(text);\n } else {\n this.logSendSkipped(\"sendRaw\");\n }\n }\n\n /** 启动连接,带自动重连,直到 abortSignal 触发 */\n async connectWithAutoReconnect(abortSignal?: AbortSignal): Promise<void> {\n if (abortSignal) {\n abortSignal.addEventListener(\n \"abort\",\n () => {\n void this.stop();\n },\n { once: true },\n );\n }\n\n await this.connect();\n\n // 保持运行直到 abort\n return new Promise<void>((resolve) => {\n if (abortSignal) {\n abortSignal.addEventListener(\"abort\", () => resolve(), { once: true });\n }\n });\n }\n\n private async connect(): Promise<void> {\n if (this.aborted) return;\n\n // 确保旧连接和定时器都被清理,防止重复连接\n this.cleanup(true);\n\n const rawApiKey = this.opts.apiKey.startsWith(\"Bearer \")\n ? this.opts.apiKey.slice(\"Bearer \".length)\n : this.opts.apiKey;\n\n this.opts.logger.info(\n `Relay tunnel: connecting to ${redactUrlSecrets(this.opts.tunnelUrl)} (attempt=${this.reconnectAttempt}, heartbeat=${this.opts.heartbeatSec}s, apiKey=${maskSecret(rawApiKey)})`,\n );\n this.writeStatus(\"connecting\");\n\n return new Promise<void>((resolve) => {\n let settled = false;\n const settle = () => {\n if (!settled) {\n settled = true;\n resolve();\n }\n };\n\n const wsUrl = new URL(this.opts.tunnelUrl);\n // 推荐使用 query 传 apiKey;暂时用 token 代替 apiKey 明文\n if (!wsUrl.searchParams.get(\"apiKey\")) {\n wsUrl.searchParams.set(\"apiKey\", rawApiKey);\n }\n\n const ws = new WebSocket(wsUrl.toString(), {\n headers: {\n \"X-Api-Key-Id\": rawApiKey,\n },\n // 防止 TCP 通但 HTTP Upgrade 响应被吞导致永久挂在 CONNECTING\n handshakeTimeout: HANDSHAKE_TIMEOUT_MS,\n });\n // 将握手中的 socket 也记为当前连接,确保首连失败/握手前断开也能触发重连。\n this.ws = ws;\n\n // 兜底 watchdog:即使 handshakeTimeout 因某些原因失效,也强制 terminate 走重连路径。\n let connectWatchdog: ReturnType<typeof setTimeout> | null = setTimeout(() => {\n connectWatchdog = null;\n if (this.ws !== ws || ws.readyState === WebSocket.OPEN) {\n return;\n }\n this.opts.logger.warn(\n `Relay tunnel: connect watchdog fired (readyState=${ws.readyState}, attempt=${this.reconnectAttempt}), forcing terminate`,\n );\n try {\n ws.terminate();\n } catch {\n // 让 close 事件接管重连;若 close 也没来,下面 error 路径也会触发 scheduleReconnect\n }\n // 兜底:极端情况下 terminate 没触发 close(不应发生,但保险起见)\n if (this.ws === ws) {\n setTimeout(() => {\n if (this.ws === ws) {\n this.opts.logger.warn(\n \"Relay tunnel: terminate did not emit close, forcing reconnect\",\n );\n this.stopHeartbeat();\n this.ws = null;\n this.writeStatus(\"disconnected\", \"watchdog-force\");\n this.scheduleReconnect();\n settle();\n }\n }, 1000);\n }\n }, CONNECT_WATCHDOG_MS);\n\n const clearConnectWatchdog = () => {\n if (connectWatchdog) {\n clearTimeout(connectWatchdog);\n connectWatchdog = null;\n }\n };\n\n ws.on(\"open\", () => {\n clearConnectWatchdog();\n if (this.aborted || this.ws !== ws) {\n this.opts.logger.warn(\n `Relay tunnel: open fired but aborted=${this.aborted}, stale=${this.ws !== ws}, closing`,\n );\n try {\n ws.terminate();\n } catch {\n // ignore\n }\n settle();\n return;\n }\n this.reconnectAttempt = 0;\n this.lastInboundAt = Date.now();\n this.startHeartbeat();\n this.opts.logger.info(\"Relay tunnel: ✔ connected, heartbeat started\");\n this.writeStatus(\"connected\");\n this.emitConnected();\n settle();\n });\n\n ws.on(\"pong\", () => {\n if (this.ws === ws) {\n this.opts.logger.info(\"Relay tunnel: ← pong received\");\n this.markInboundActivity();\n }\n });\n\n ws.on(\"message\", (data: WebSocket.RawData) => {\n if (this.ws !== ws) {\n return;\n }\n this.handleMessage(data);\n });\n\n ws.on(\"close\", (code: number, reason: Buffer) => {\n clearConnectWatchdog();\n const reasonStr = reason.toString();\n const lastInboundAgoMs = this.lastInboundAt\n ? Date.now() - this.lastInboundAt\n : null;\n const isCurrentSocket = this.ws === ws;\n const logMessage =\n `Relay tunnel: disconnected (code=${code}, reason=${previewText(reasonStr, 200)}, lastInboundAgoMs=${lastInboundAgoMs ?? \"N/A\"}, reconnectAttempt=${this.reconnectAttempt})`;\n if (this.aborted || !isCurrentSocket) {\n this.opts.logger.info(logMessage);\n } else {\n this.opts.logger.warn(logMessage);\n }\n if (isCurrentSocket) {\n this.stopHeartbeat();\n this.ws = null;\n this.writeStatus(\"disconnected\", `code=${code}, reason=${reasonStr}`);\n this.scheduleReconnect();\n }\n settle();\n });\n\n ws.on(\"error\", (err: Error) => {\n clearConnectWatchdog();\n this.opts.logger.error(\n `Relay tunnel: WebSocket error: ${err.message} (readyState=${ws.readyState}, reconnectAttempt=${this.reconnectAttempt}, url=${redactUrlSecrets(wsUrl.toString())})`,\n );\n // 多数情况 error 后 ws 会再触发 close;但部分底层错误只 error 不 close,\n // 这里幂等地兜底一次 scheduleReconnect,scheduleReconnect 内部对已排程的重连会跳过。\n if (this.ws === ws) {\n this.forceReconnectFromSocket(ws, `error: ${err.message}`);\n }\n settle();\n });\n });\n }\n\n private emitConnected(): void {\n for (const handler of this.connectedHandlers) {\n Promise.resolve(handler()).catch((err) => {\n this.opts.logger.warn(\n `Relay tunnel: onConnected handler failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n });\n }\n }\n\n private handleMessage(data: WebSocket.RawData): void {\n const text =\n typeof data === \"string\"\n ? data\n : Buffer.isBuffer(data)\n ? data.toString()\n : String(data);\n\n this.markInboundActivity();\n\n // 应用层心跳 pong 直接消费,不走帧解析\n if (text === \"pong\") {\n return;\n }\n\n this.opts.logger.info(\n `Relay tunnel: ★ received message (${text.length} chars): ${previewText(text)}`,\n );\n\n let frame: InboundFrame;\n try {\n frame = JSON.parse(text) as InboundFrame;\n } catch {\n this.opts.logger.warn(\n `Relay tunnel: received invalid frame, ignoring (preview=${previewText(text, 200)})`,\n );\n return;\n }\n\n this.opts.logger.info(`Relay tunnel: parsed frame type=${frame.type}, id=${\"id\" in frame ? frame.id : \"N/A\"}`);\n\n for (const handler of this.handlers) {\n try {\n const result = handler(frame);\n if (result instanceof Promise) {\n result.catch((err) => {\n this.opts.logger.error(`Relay tunnel: handler error: ${err}`);\n });\n }\n } catch (err) {\n this.opts.logger.error(`Relay tunnel: handler error: ${err}`);\n }\n }\n }\n\n private startHeartbeat(): void {\n this.stopHeartbeat();\n const intervalMs = this.opts.heartbeatSec * 1000;\n this.sendHeartbeat();\n this.heartbeatTimer = setInterval(() => {\n this.sendHeartbeat();\n }, intervalMs);\n }\n\n private stopHeartbeat(): void {\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\n }\n\n private getHeartbeatTimeoutMs(): number {\n return this.opts.heartbeatSec * 3 * 1000;\n }\n\n private sendHeartbeat(): void {\n const ws = this.ws;\n if (ws?.readyState !== WebSocket.OPEN) {\n return;\n }\n\n const idleMs = Date.now() - this.lastInboundAt;\n const timeoutMs = this.getHeartbeatTimeoutMs();\n if (idleMs >= timeoutMs) {\n this.opts.logger.warn(\n `Relay tunnel: heartbeat timeout, no inbound activity for ${idleMs}ms (threshold=${timeoutMs}ms)`,\n );\n this.forceReconnectFromSocket(ws, `heartbeat-timeout idleMs=${idleMs}`);\n return;\n }\n\n this.opts.logger.info('Relay tunnel: → heartbeat \"ping\"');\n try {\n ws.send(\"ping\");\n } catch {\n // ignore, close/error path will handle reconnect\n }\n try {\n ws.ping();\n } catch {\n // ignore, close/error path will handle reconnect\n }\n }\n\n private markInboundActivity(): void {\n this.lastInboundAt = Date.now();\n }\n\n private cleanup(force = false): void {\n this.opts.logger.info(\n `Relay tunnel: cleanup (ws=${this.ws ? \"open\" : \"null\"}, heartbeat=${!!this.heartbeatTimer}, reconnect=${!!this.reconnectTimer})`,\n );\n this.stopHeartbeat();\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n if (this.ws) {\n try {\n if (force) {\n this.ws.terminate();\n } else {\n this.ws.close();\n }\n } catch {\n // ignore\n }\n this.ws = null;\n }\n }\n\n private forceReconnectFromSocket(ws: WebSocket, reason: string): void {\n if (this.aborted || this.ws !== ws) return;\n\n this.stopHeartbeat();\n this.ws = null;\n this.writeStatus(\"disconnected\", reason);\n this.scheduleReconnect();\n\n try {\n if (ws.readyState !== WebSocket.CLOSED) {\n ws.terminate();\n }\n } catch {\n // ignore\n }\n }\n\n private logSendSkipped(kind: \"send\" | \"sendRaw\", detail?: string): void {\n const now = Date.now();\n const shouldLog =\n this.skippedSendLogLastAt === null ||\n now - this.skippedSendLogLastAt >= SEND_SKIPPED_LOG_INTERVAL_MS;\n\n if (!shouldLog) {\n this.skippedSendLogSuppressed++;\n return;\n }\n\n const suppressedSuffix =\n this.skippedSendLogSuppressed > 0\n ? `, suppressed=${this.skippedSendLogSuppressed}`\n : \"\";\n const detailSuffix = detail ? `, ${detail}` : \"\";\n this.opts.logger.warn(\n `Relay tunnel: ▶ ${kind} skipped, ws not open (readyState=${this.ws?.readyState ?? \"null\"}${detailSuffix}${suppressedSuffix})`,\n );\n this.skippedSendLogLastAt = now;\n this.skippedSendLogSuppressed = 0;\n }\n\n private scheduleReconnect(): void {\n if (this.aborted) return;\n\n // 已经排了一次重连就不再重排,避免 error+close 双触发或 watchdog 与 close 双触发时\n // attempt 被多扣、退避被无意义重置。\n if (this.reconnectTimer) {\n return;\n }\n\n const baseMs = this.opts.reconnectBackoffMs;\n const delayMs = Math.min(\n baseMs * Math.pow(2, this.reconnectAttempt),\n 60_000,\n );\n this.reconnectAttempt++;\n\n this.opts.logger.info(\n `Relay tunnel: reconnecting in ${delayMs}ms (attempt ${this.reconnectAttempt})`,\n );\n\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n if (!this.aborted) {\n this.connect().catch((err) => {\n this.opts.logger.error(`Relay tunnel: reconnect failed: ${err}`);\n });\n }\n }, delayMs);\n }\n}\n","import createWebSocketStream from './lib/stream.js';\nimport Receiver from './lib/receiver.js';\nimport Sender from './lib/sender.js';\nimport WebSocket from './lib/websocket.js';\nimport WebSocketServer from './lib/websocket-server.js';\n\nexport { createWebSocketStream, Receiver, Sender, WebSocket, WebSocketServer };\nexport default WebSocket;\n","export function previewText(text: string | undefined, max = 200): string {\n if (!text) return \"\";\n return text.length <= max ? text : `${text.substring(0, max)}…`;\n}\n\nexport function maskSecret(value: string | undefined): string {\n if (!value) return \"empty\";\n if (value.length <= 8) {\n return `${value.slice(0, 2)}...${value.slice(-2)}`;\n }\n return `${value.slice(0, 4)}...${value.slice(-4)}`;\n}\n\nexport function redactUrlSecrets(rawUrl: string): string {\n try {\n const url = new URL(rawUrl);\n for (const key of [\"apiKey\", \"token\", \"access_token\"]) {\n const value = url.searchParams.get(key);\n if (value) {\n url.searchParams.set(key, maskSecret(value));\n }\n }\n return url.toString();\n } catch {\n return rawUrl.replace(\n /([?&](?:apiKey|token|access_token)=)([^&]+)/gi,\n (_match, prefix: string, value: string) => {\n let decoded = value;\n try {\n decoded = decodeURIComponent(value);\n } catch {\n // Keep the original value when the URL is malformed.\n }\n return `${prefix}${maskSecret(decoded)}`;\n },\n );\n }\n}\n\nexport function findHeaderValue(\n headers: Record<string, string> | undefined,\n key: string,\n): string | undefined {\n if (!headers) return undefined;\n const lowerKey = key.toLowerCase();\n for (const [headerKey, headerValue] of Object.entries(headers)) {\n if (headerKey.toLowerCase() === lowerKey) {\n return headerValue;\n }\n }\n return undefined;\n}\n\nexport function summarizeRequestHeaders(headers: Record<string, string> | undefined): string {\n const contentType = findHeaderValue(headers, \"content-type\");\n const requestId = findHeaderValue(headers, \"x-request-id\");\n const parts: string[] = [];\n if (contentType) {\n parts.push(`contentType=${contentType}`);\n }\n if (requestId) {\n parts.push(`xRequestId=${previewText(requestId, 120)}`);\n }\n return parts.length ? `, ${parts.join(\", \")}` : \"\";\n}\n","import { randomUUID } from \"node:crypto\";\nimport WebSocket from \"ws\";\nimport type { RelayClient } from \"./relay-client.js\";\nimport type { ReqFrame, InboundFrame } from \"./types.js\";\nimport { previewText } from \"./utils.js\";\nimport { resolveStateDir as resolveHostStateDir } from \"../host.js\";\nimport {\n type DeviceIdentity,\n resolveClientStateDir,\n loadOrCreateDeviceIdentity,\n loadDeviceAuthToken,\n storeDeviceAuthToken,\n clearDeviceAuthToken,\n buildDeviceAuthPayload,\n signDevicePayload,\n publicKeyRawBase64UrlFromPem,\n} from \"./device-identity.js\";\nimport { handleHttpRequest } from \"./http-proxy.js\";\nimport { WsProxy } from \"./ws-proxy.js\";\n\n// ─── Types ───\n\nexport const RELAY_TUNNEL_GATEWAY_CLIENT_INSTANCE_ID =\n \"phone-notifications-relay-tunnel\";\n\ninterface ProxyOptions {\n stateDir?: string;\n hostStateDir?: string;\n gatewayBaseUrl: string;\n /** Gateway 鉴权模式 */\n gatewayAuthMode?: \"token\" | \"password\";\n /** Gateway 鉴权 token,代理请求到本地 gateway 时使用 */\n gatewayToken?: string;\n /** Gateway 鉴权密码,代理请求到本地 gateway 时使用 */\n gatewayPassword?: string;\n client: RelayClient;\n logger: {\n info: (msg: string) => void;\n warn: (msg: string) => void;\n error: (msg: string) => void;\n };\n}\n\nconst MAX_AUTO_PAIRING_APPROVALS = 3;\nconst RECENT_ABORTED_CHAT_RUN_TTL_MS = 60_000;\n\ninterface PendingGatewayReqMeta {\n method: string;\n sessionKey?: string;\n}\n\ninterface RecentAbortedChatRun {\n sessionKey: string;\n abortedAtMs: number;\n}\n\ntype ApproveDevicePairingFn = (\n requestId: string,\n hostStateDir?: string,\n) => Promise<unknown>;\n\nlet approveDevicePairingPromise: Promise<ApproveDevicePairingFn | null> | null =\n null;\nlet approveDevicePairingWarned = false;\n\nfunction formatErrorMessage(err: unknown): string {\n if (err instanceof Error && err.message) return err.message;\n return String(err);\n}\n\nasync function loadApproveDevicePairing(\n logger: ProxyOptions[\"logger\"],\n): Promise<ApproveDevicePairingFn | null> {\n if (!approveDevicePairingPromise) {\n approveDevicePairingPromise = import(\"openclaw/plugin-sdk/device-bootstrap\")\n .then((mod) =>\n typeof mod.approveDevicePairing === \"function\"\n ? (mod.approveDevicePairing as ApproveDevicePairingFn)\n : null,\n )\n .catch((err: unknown) => {\n if (!approveDevicePairingWarned) {\n approveDevicePairingWarned = true;\n logger.warn(\n `TunnelProxy: local gateway auto-pairing disabled because current OpenClaw runtime does not expose device bootstrap SDK (${formatErrorMessage(err)})`,\n );\n }\n return null;\n });\n }\n\n const approveDevicePairing = await approveDevicePairingPromise;\n if (!approveDevicePairing && !approveDevicePairingWarned) {\n approveDevicePairingWarned = true;\n logger.warn(\n \"TunnelProxy: local gateway auto-pairing disabled because current OpenClaw runtime does not expose device bootstrap SDK\",\n );\n }\n return approveDevicePairing;\n}\n\n/**\n * 透明代理:接收 Relay 转发的请求帧,代理到本地 gateway,回传响应帧。\n * 支持 HTTP 请求代理和 WebSocket 连接代理。\n */\nexport class TunnelProxy {\n /** 到本地 Gateway 的持久 RPC WebSocket 连接 */\n private gatewayWs: WebSocket | null = null;\n private gatewayWsConnecting = false;\n /** 握手是否已完成(收到 hello-ok) */\n private gatewayWsReady = false;\n /** 收到本地自动配对成功后,在 close 回调里触发重连 */\n private gatewayWsReconnectRequested = false;\n /** 防止配对失败时无限重连 */\n private gatewayWsAutoPairingApprovals = 0;\n /** 等待 Gateway WS 握手完成后发送的帧队列 */\n private gatewayWsPending: string[] = [];\n /** 记录已转发到 Gateway 的 req 元信息,便于回包时做定向处理。 */\n private gatewayReqMetaById = new Map<string, PendingGatewayReqMeta>();\n /** 最近由用户手动中断的 chat.run,用于过滤 runtime 误补发的 synthetic failure。 */\n private recentAbortedChatRuns = new Map<string, RecentAbortedChatRun>();\n\n /** 设备身份,用于 Gateway connect 握手 */\n private deviceIdentity: DeviceIdentity;\n\n private readonly stateDir: string;\n private readonly hostStateDir: string;\n private readonly wsProxy: WsProxy;\n\n constructor(private readonly opts: ProxyOptions) {\n this.stateDir = resolveClientStateDir(opts.stateDir);\n this.hostStateDir = opts.hostStateDir ?? resolveHostStateDir();\n this.deviceIdentity = loadOrCreateDeviceIdentity(this.stateDir);\n opts.logger.info(\n `TunnelProxy: loaded device identity (deviceId=${this.deviceIdentity.deviceId})`,\n );\n this.wsProxy = new WsProxy({\n gatewayBaseUrl: opts.gatewayBaseUrl,\n client: opts.client,\n logger: opts.logger,\n });\n }\n\n // ─── Frame dispatcher ───\n\n /** 处理从 Relay 收到的入站帧 */\n async handleFrame(frame: InboundFrame): Promise<void> {\n this.opts.logger.info(\n `TunnelProxy: handling frame type=${frame.type}, id=${\"id\" in frame ? frame.id : \"N/A\"}`,\n );\n switch (frame.type) {\n case \"request\":\n await handleHttpRequest(this.opts, frame);\n break;\n case \"req\":\n this.handleReqFrame(frame);\n break;\n case \"ws_open\":\n this.wsProxy.handleWsOpen(frame);\n break;\n case \"ws_data\":\n this.wsProxy.handleWsData(frame);\n break;\n case \"ws_close\":\n this.wsProxy.handleWsClose(frame);\n break;\n default:\n this.opts.logger.warn(\n `TunnelProxy: unknown frame type=\"${(frame as any).type}\", id=${\"id\" in frame ? (frame as any).id : \"N/A\"}, forwarding raw to gateway`,\n );\n // 未知帧类型也尝试通过 RPC WS 转发,避免静默丢弃\n this.forwardRawToGateway(JSON.stringify(frame));\n break;\n }\n }\n\n /** 清理所有代理的 WebSocket 连接 */\n cleanup(): void {\n this.opts.logger.info(\n `TunnelProxy: cleanup, closing ${this.wsProxy.activeCount} active WS connections, gatewayWs=${!!this.gatewayWs}`,\n );\n this.wsProxy.cleanup();\n\n if (this.gatewayWs) {\n try {\n this.gatewayWs.close();\n } catch {\n // ignore\n }\n this.gatewayWs = null;\n }\n this.gatewayWsReady = false;\n this.gatewayWsConnecting = false;\n this.gatewayWsReconnectRequested = false;\n this.gatewayWsAutoPairingApprovals = 0;\n this.gatewayWsPending = [];\n this.gatewayReqMetaById.clear();\n this.recentAbortedChatRuns.clear();\n }\n\n // ─── Gateway RPC WebSocket ───\n\n private pushGatewayPending(payload: string, reason: string): void {\n this.gatewayWsPending.push(payload);\n this.opts.logger.info(\n `TunnelProxy: gateway WS pending queue size=${this.gatewayWsPending.length} (${reason})`,\n );\n }\n\n /** 将未知帧原样转发到 Gateway WS */\n private forwardRawToGateway(payload: string): void {\n this.ensureGatewayWs();\n if (this.gatewayWsReady && this.gatewayWs?.readyState === WebSocket.OPEN) {\n this.gatewayWs.send(payload);\n } else {\n this.pushGatewayPending(payload, \"raw frame queued before gateway WS ready\");\n }\n }\n\n /** 处理 Relay 转发的 Gateway RPC 请求帧,原样通过 WebSocket 发给本地 Gateway */\n private handleReqFrame(frame: ReqFrame): void {\n const payload = JSON.stringify(frame);\n this.gatewayReqMetaById.set(frame.id, {\n method: frame.method,\n sessionKey: this.normalizeSessionKey(frame.params?.sessionKey),\n });\n this.opts.logger.info(\n `TunnelProxy: req id=${frame.id} method=${frame.method} → gateway WS (${payload.length} chars)`,\n );\n\n this.ensureGatewayWs();\n\n if (this.gatewayWsReady && this.gatewayWs?.readyState === WebSocket.OPEN) {\n this.gatewayWs.send(payload);\n } else {\n this.opts.logger.info(\n `TunnelProxy: req id=${frame.id} queued, gateway WS not ready yet`,\n );\n this.pushGatewayPending(\n payload,\n `req id=${frame.id} queued before gateway WS handshake`,\n );\n }\n }\n\n // ─── Gateway connect auth helpers ───\n\n private resolveGatewayConnectAuth():\n | { token?: string; password?: string }\n | undefined {\n const token = this.opts.gatewayToken?.trim() || undefined;\n const password = this.opts.gatewayPassword?.trim() || undefined;\n if (!token && !password) return undefined;\n return { token, password };\n }\n\n private loadStoredDeviceToken(role: string): string | undefined {\n return (\n loadDeviceAuthToken({\n stateDir: this.stateDir,\n deviceId: this.deviceIdentity.deviceId,\n role,\n })?.token ?? undefined\n );\n }\n\n private buildGatewayConnectAuth(role: string): {\n auth?: { token?: string; deviceToken?: string; password?: string };\n authToken?: string;\n authPassword?: string;\n deviceToken?: string;\n } {\n const explicitAuth = this.resolveGatewayConnectAuth();\n const authPassword = explicitAuth?.password?.trim() || undefined;\n const explicitGatewayToken = explicitAuth?.token?.trim() || undefined;\n const deviceToken = explicitGatewayToken\n ? undefined\n : this.loadStoredDeviceToken(role);\n const authToken = explicitGatewayToken ?? deviceToken;\n const auth =\n authToken || authPassword || deviceToken\n ? { token: authToken, deviceToken, password: authPassword }\n : undefined;\n return { auth, authToken, authPassword, deviceToken };\n }\n\n private storeIssuedDeviceToken(params: {\n fallbackRole: string;\n fallbackScopes: string[];\n authInfo: any;\n }): void {\n const token = params.authInfo?.deviceToken;\n if (typeof token !== \"string\" || !token.trim()) return;\n const role =\n typeof params.authInfo?.role === \"string\" && params.authInfo.role.trim()\n ? params.authInfo.role.trim()\n : params.fallbackRole;\n const scopes = Array.isArray(params.authInfo?.scopes)\n ? params.authInfo.scopes.filter(\n (scope: unknown): scope is string =>\n typeof scope === \"string\" && !!scope.trim(),\n )\n : params.fallbackScopes;\n storeDeviceAuthToken({\n stateDir: this.stateDir,\n deviceId: this.deviceIdentity.deviceId,\n role,\n token: token.trim(),\n scopes,\n });\n }\n\n private maybeClearStoredDeviceTokenOnMismatch(code: number, reason: string): void {\n const explicitAuth = this.resolveGatewayConnectAuth();\n if (explicitAuth?.token || explicitAuth?.password) return;\n if (code !== 1008 || !reason.toLowerCase().includes(\"device token mismatch\")) return;\n clearDeviceAuthToken({\n stateDir: this.stateDir,\n deviceId: this.deviceIdentity.deviceId,\n role: \"operator\",\n });\n this.opts.logger.warn(\n `TunnelProxy: cleared stale stored device token after gateway mismatch (deviceId=${this.deviceIdentity.deviceId})`,\n );\n }\n\n private async maybeAutoApproveGatewayPairing(frame: any): Promise<boolean> {\n const errorCode =\n typeof frame?.error?.code === \"string\" ? frame.error.code : undefined;\n const detailsCode =\n typeof frame?.error?.details?.code === \"string\"\n ? frame.error.details.code\n : undefined;\n if (errorCode !== \"NOT_PAIRED\" && detailsCode !== \"PAIRING_REQUIRED\") {\n return false;\n }\n\n const requestId =\n typeof frame?.error?.details?.requestId === \"string\"\n ? frame.error.details.requestId.trim()\n : \"\";\n const reason =\n typeof frame?.error?.details?.reason === \"string\"\n ? frame.error.details.reason.trim()\n : \"\";\n\n if (!requestId) {\n this.opts.logger.warn(\n \"TunnelProxy: gateway pairing required but requestId missing; unable to auto-approve\",\n );\n return false;\n }\n\n if (\n reason &&\n reason !== \"not-paired\" &&\n reason !== \"scope-upgrade\"\n ) {\n this.opts.logger.warn(\n `TunnelProxy: gateway pairing required with unsupported reason=${reason}; skipping auto-approve`,\n );\n return false;\n }\n\n if (this.gatewayWsAutoPairingApprovals >= MAX_AUTO_PAIRING_APPROVALS) {\n this.opts.logger.warn(\n `TunnelProxy: reached auto-pairing retry limit (${MAX_AUTO_PAIRING_APPROVALS}); requestId=${requestId}`,\n );\n return false;\n }\n\n try {\n const approveDevicePairing = await loadApproveDevicePairing(this.opts.logger);\n if (!approveDevicePairing) {\n return false;\n }\n const approved = await approveDevicePairing(requestId, this.hostStateDir);\n if (!approved) {\n this.opts.logger.warn(\n `TunnelProxy: gateway pairing request ${requestId} not found in host state ${this.hostStateDir}`,\n );\n return false;\n }\n this.gatewayWsAutoPairingApprovals += 1;\n this.gatewayWsReconnectRequested = true;\n this.opts.logger.info(\n `TunnelProxy: auto-approved local gateway pairing request ${requestId} (reason=${reason || \"not-paired\"}, hostStateDir=${this.hostStateDir}, approval=${this.gatewayWsAutoPairingApprovals}/${MAX_AUTO_PAIRING_APPROVALS})`,\n );\n return true;\n } catch (err: any) {\n this.opts.logger.warn(\n `TunnelProxy: failed to auto-approve gateway pairing request ${requestId}: ${err?.message ?? String(err)}`,\n );\n return false;\n }\n }\n\n // ─── Gateway RPC WebSocket lifecycle ───\n\n private normalizeSessionKey(value: unknown): string | undefined {\n return typeof value === \"string\" && value.trim() ? value.trim() : undefined;\n }\n\n private normalizeRunId(value: unknown): string | undefined {\n return typeof value === \"string\" && value.trim() ? value.trim() : undefined;\n }\n\n private pruneRecentAbortedChatRuns(now = Date.now()): void {\n for (const [runId, entry] of this.recentAbortedChatRuns) {\n if (now - entry.abortedAtMs > RECENT_ABORTED_CHAT_RUN_TTL_MS) {\n this.recentAbortedChatRuns.delete(runId);\n }\n }\n }\n\n private rememberRecentAbortedChatRun(runId: unknown, sessionKey: unknown): void {\n const normalizedRunId = this.normalizeRunId(runId);\n const normalizedSessionKey = this.normalizeSessionKey(sessionKey);\n if (!normalizedRunId || !normalizedSessionKey) return;\n this.pruneRecentAbortedChatRuns();\n this.recentAbortedChatRuns.set(normalizedRunId, {\n sessionKey: normalizedSessionKey,\n abortedAtMs: Date.now(),\n });\n }\n\n private getAssistantMessageText(message: any): string {\n if (!message || typeof message !== \"object\") return \"\";\n if (typeof message.text === \"string\") return message.text;\n if (!Array.isArray(message.content)) return \"\";\n return message.content\n .filter(\n (item: any) =>\n item &&\n typeof item === \"object\" &&\n item.type === \"text\" &&\n typeof item.text === \"string\",\n )\n .map((item: any) => item.text)\n .join(\"\");\n }\n\n private looksLikeSyntheticAbortFailureText(text: string): boolean {\n const normalized = text.trim().toLowerCase();\n if (!normalized) return false;\n return (\n normalized.includes(\"agent failed before reply:\") &&\n normalized.includes(\"aborted\") &&\n normalized.includes(\"openclaw logs --follow\")\n );\n }\n\n private isSyntheticAbortHistoryMessage(\n message: any,\n sessionKey: string,\n ): boolean {\n const text = this.getAssistantMessageText(message);\n if (!this.looksLikeSyntheticAbortFailureText(text)) return false;\n const messageTimestamp =\n typeof message?.timestamp === \"number\" ? message.timestamp : null;\n const now = Date.now();\n this.pruneRecentAbortedChatRuns(now);\n for (const entry of this.recentAbortedChatRuns.values()) {\n if (entry.sessionKey !== sessionKey) continue;\n if (messageTimestamp === null) return true;\n if (Math.abs(messageTimestamp - entry.abortedAtMs) <= RECENT_ABORTED_CHAT_RUN_TTL_MS) {\n return true;\n }\n }\n return false;\n }\n\n private maybeRewriteGatewayFrame(text: string, frame: any): string | null {\n this.pruneRecentAbortedChatRuns();\n\n if (\n frame?.type === \"event\" &&\n frame?.event === \"chat\" &&\n frame?.payload?.state === \"aborted\"\n ) {\n this.rememberRecentAbortedChatRun(\n frame.payload?.runId,\n frame.payload?.sessionKey,\n );\n return text;\n }\n\n if (frame?.type === \"ack\" && frame?.ok === false && typeof frame?.id === \"string\") {\n this.gatewayReqMetaById.delete(frame.id);\n return text;\n }\n\n let reqMeta: PendingGatewayReqMeta | undefined;\n if (frame?.type === \"res\" && typeof frame?.id === \"string\") {\n reqMeta = this.gatewayReqMetaById.get(frame.id);\n this.gatewayReqMetaById.delete(frame.id);\n }\n\n if (\n frame?.type === \"res\" &&\n frame?.ok === true &&\n reqMeta?.method === \"chat.abort\"\n ) {\n const runIds = Array.isArray(frame?.payload?.runIds)\n ? frame.payload.runIds\n : [];\n for (const runId of runIds) {\n this.rememberRecentAbortedChatRun(runId, reqMeta.sessionKey);\n }\n return text;\n }\n\n if (\n frame?.type === \"event\" &&\n frame?.event === \"chat\" &&\n frame?.payload?.state === \"final\"\n ) {\n const runId = this.normalizeRunId(frame?.payload?.runId);\n const assistantText = this.getAssistantMessageText(frame?.payload?.message);\n const recentAbort = runId ? this.recentAbortedChatRuns.get(runId) : undefined;\n if (\n recentAbort &&\n this.looksLikeSyntheticAbortFailureText(assistantText)\n ) {\n this.opts.logger.info(\n `TunnelProxy: suppressing synthetic abort failure final for runId=${runId}`,\n );\n return null;\n }\n return text;\n }\n\n if (\n frame?.type === \"res\" &&\n frame?.ok === true &&\n reqMeta?.method === \"chat.history\" &&\n Array.isArray(frame?.payload?.messages)\n ) {\n const sessionKey =\n this.normalizeSessionKey(frame?.payload?.sessionKey) ?? reqMeta.sessionKey;\n if (!sessionKey) return text;\n const filteredMessages = frame.payload.messages.filter(\n (message: any) =>\n !this.isSyntheticAbortHistoryMessage(message, sessionKey),\n );\n if (filteredMessages.length === frame.payload.messages.length) {\n return text;\n }\n this.opts.logger.info(\n `TunnelProxy: removed ${frame.payload.messages.length - filteredMessages.length} synthetic abort history message(s) for session=${sessionKey}`,\n );\n return JSON.stringify({\n ...frame,\n payload: {\n ...frame.payload,\n messages: filteredMessages,\n },\n });\n }\n\n return text;\n }\n\n /** 确保到本地 Gateway 的 RPC WebSocket 已连接且握手完成 */\n private ensureGatewayWs(): void {\n if (this.gatewayWsReady && this.gatewayWs?.readyState === WebSocket.OPEN)\n return;\n if (this.gatewayWsConnecting) return;\n\n this.gatewayWsConnecting = true;\n this.gatewayWsReady = false;\n const wsUrl = this.opts.gatewayBaseUrl.replace(/^http/, \"ws\");\n\n this.opts.logger.info(\n `TunnelProxy: RPC WS connecting to gateway ${wsUrl} (pending=${this.gatewayWsPending.length})`,\n );\n\n const ws = new WebSocket(wsUrl);\n\n ws.on(\"open\", () => {\n this.gatewayWs = ws;\n this.opts.logger.info(\n `TunnelProxy: RPC WS tcp connected, waiting for connect.challenge (pending=${this.gatewayWsPending.length})`,\n );\n });\n\n ws.on(\"message\", async (data: WebSocket.RawData) => {\n let text: string;\n if (typeof data === \"string\") {\n text = data;\n } else if (Buffer.isBuffer(data)) {\n text = data.toString();\n } else {\n text = Buffer.from(data as ArrayBuffer).toString();\n }\n\n const preview = text.length <= 500 ? text : text.substring(0, 500) + \"…\";\n this.opts.logger.info(\n `TunnelProxy: RPC WS ← gateway (${text.length} chars): ${preview}`,\n );\n\n let frame: any;\n try {\n frame = JSON.parse(text);\n } catch {\n this.opts.logger.warn(\n \"TunnelProxy: RPC WS received non-JSON, ignoring\",\n );\n return;\n }\n\n // 1) 收到 connect.challenge → 回复 connect 请求(带设备身份签名)\n if (frame.type === \"event\" && frame.event === \"connect.challenge\") {\n this.handleConnectChallenge(ws, frame);\n return;\n }\n\n // 2) 收到 connect 的 hello-ok 响应 → 握手完成,flush 待发帧\n if (\n frame.type === \"res\" &&\n frame.ok === true &&\n frame.payload?.type === \"hello-ok\"\n ) {\n this.storeIssuedDeviceToken({\n fallbackRole: \"operator\",\n fallbackScopes: [\"operator.admin\"],\n authInfo: frame.payload?.auth,\n });\n this.gatewayWsAutoPairingApprovals = 0;\n this.gatewayWsReconnectRequested = false;\n this.gatewayWsReady = true;\n this.gatewayWsConnecting = false;\n this.opts.logger.info(\n `TunnelProxy: RPC WS handshake done (hello-ok), flushing ${this.gatewayWsPending.length} pending frames`,\n );\n for (const pending of this.gatewayWsPending) {\n ws.send(pending);\n }\n this.gatewayWsPending = [];\n return;\n }\n\n // 3) 收到 connect 失败响应 → 关闭连接\n if (frame.type === \"res\" && frame.ok === false && !this.gatewayWsReady) {\n const autoApproved = await this.maybeAutoApproveGatewayPairing(frame);\n if (autoApproved) {\n const wsAlreadyClosed =\n ws.readyState === WebSocket.CLOSING ||\n ws.readyState === WebSocket.CLOSED ||\n this.gatewayWs !== ws;\n this.opts.logger.info(\n `TunnelProxy: RPC WS handshake requested local pairing approval, reconnecting${wsAlreadyClosed ? \" immediately\" : \" after close\"} (pending=${this.gatewayWsPending.length})`,\n );\n if (wsAlreadyClosed) {\n this.gatewayWsReconnectRequested = false;\n this.ensureGatewayWs();\n return;\n }\n ws.close(1000, \"pairing approved, reconnecting\");\n return;\n }\n this.opts.logger.error(\n `TunnelProxy: RPC WS handshake failed (pending=${this.gatewayWsPending.length}): ${previewText(JSON.stringify(frame.error), 500)}`,\n );\n ws.close();\n return;\n }\n\n // 4) 握手后的普通消息 → 透传回 Relay\n const rewritten = this.maybeRewriteGatewayFrame(text, frame);\n if (rewritten !== null) {\n this.opts.client.sendRaw(rewritten);\n }\n });\n\n ws.on(\"close\", (code: number, reason: Buffer) => {\n const wasReady = this.gatewayWsReady;\n const pendingCount = this.gatewayWsPending.length;\n const reasonText = reason.toString();\n const shouldReconnect =\n this.gatewayWsReconnectRequested && pendingCount > 0;\n this.opts.logger.info(\n `TunnelProxy: RPC WS closed by gateway (code=${code}, reason=${reasonText}, ready=${wasReady}, pending=${pendingCount}, activeWs=${this.wsProxy.activeCount})`,\n );\n if (this.gatewayWs === ws) {\n this.gatewayWs = null;\n this.gatewayWsReady = false;\n }\n this.gatewayWsConnecting = false;\n this.maybeClearStoredDeviceTokenOnMismatch(code, reasonText);\n if (shouldReconnect) {\n this.gatewayWsReconnectRequested = false;\n this.opts.logger.info(\n `TunnelProxy: retrying RPC WS after local pairing approval (pending=${this.gatewayWsPending.length})`,\n );\n queueMicrotask(() => this.ensureGatewayWs());\n }\n });\n\n ws.on(\"error\", (err: Error) => {\n this.opts.logger.warn(\n `TunnelProxy: RPC WS error: ${err.message} (ready=${this.gatewayWsReady}, pending=${this.gatewayWsPending.length}, activeWs=${this.wsProxy.activeCount})`,\n );\n this.gatewayWsConnecting = false;\n if (this.gatewayWs === ws) {\n this.gatewayWs = null;\n this.gatewayWsReady = false;\n }\n });\n }\n\n private handleConnectChallenge(ws: WebSocket, frame: any): void {\n const challengeNonce: string = frame.payload?.nonce ?? \"\";\n const connectRequestId = `tunnel-connect-${randomUUID()}`;\n const role = \"operator\";\n const scopes = [\"operator.admin\"];\n const gatewayConnectAuth = this.buildGatewayConnectAuth(role);\n this.opts.logger.info(\n `TunnelProxy: received connect.challenge (nonce=${challengeNonce}, connectReqId=${connectRequestId}, hasToken=${!!gatewayConnectAuth.authToken}, hasPassword=${!!gatewayConnectAuth.authPassword}, hasDeviceToken=${!!gatewayConnectAuth.deviceToken}), sending connect request with device identity`,\n );\n\n const signedAtMs = Date.now();\n const clientId = \"gateway-client\";\n const clientMode = \"backend\";\n\n const authPayload = buildDeviceAuthPayload({\n deviceId: this.deviceIdentity.deviceId,\n clientId,\n clientMode,\n role,\n scopes,\n signedAtMs,\n token: gatewayConnectAuth.authToken ?? null,\n nonce: challengeNonce,\n });\n const signature = signDevicePayload(\n this.deviceIdentity.privateKeyPem,\n authPayload,\n );\n\n const connectReq = {\n type: \"req\",\n id: connectRequestId,\n method: \"connect\",\n params: {\n minProtocol: 3,\n maxProtocol: 3,\n client: {\n id: clientId,\n version: \"1.0.0\",\n platform: process.platform,\n mode: clientMode,\n instanceId: RELAY_TUNNEL_GATEWAY_CLIENT_INSTANCE_ID,\n },\n role,\n scopes,\n ...(gatewayConnectAuth.auth ? { auth: gatewayConnectAuth.auth } : {}),\n device: {\n id: this.deviceIdentity.deviceId,\n publicKey: publicKeyRawBase64UrlFromPem(\n this.deviceIdentity.publicKeyPem,\n ),\n signature,\n signedAt: signedAtMs,\n nonce: challengeNonce,\n },\n },\n };\n ws.send(JSON.stringify(connectReq));\n }\n}\n","import crypto from \"node:crypto\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { resolveStateDir as resolveHostStateDir } from \"../host.js\";\n\n// ─── Types ───\n\nexport interface DeviceIdentity {\n deviceId: string;\n publicKeyPem: string;\n privateKeyPem: string;\n}\n\nexport interface DeviceAuthEntry {\n token: string;\n role: string;\n scopes: string[];\n updatedAtMs: number;\n}\n\ninterface DeviceAuthStore {\n version: 1;\n deviceId: string;\n tokens: Record<string, DeviceAuthEntry>;\n}\n\n// ─── Crypto helpers ───\n\nconst ED25519_SPKI_PREFIX = Buffer.from(\"302a300506032b6570032100\", \"hex\");\n\nexport function base64UrlEncode(buf: Buffer): string {\n return buf\n .toString(\"base64\")\n .replaceAll(\"+\", \"-\")\n .replaceAll(\"/\", \"_\")\n .replace(/=+$/g, \"\");\n}\n\nexport function derivePublicKeyRaw(publicKeyPem: string): Buffer {\n const spki = crypto.createPublicKey(publicKeyPem).export({\n type: \"spki\",\n format: \"der\",\n });\n if (\n spki.length === ED25519_SPKI_PREFIX.length + 32 &&\n spki.subarray(0, ED25519_SPKI_PREFIX.length).equals(ED25519_SPKI_PREFIX)\n )\n return spki.subarray(ED25519_SPKI_PREFIX.length);\n return spki;\n}\n\nexport function fingerprintPublicKey(publicKeyPem: string): string {\n const raw = derivePublicKeyRaw(publicKeyPem);\n return crypto.createHash(\"sha256\").update(raw).digest(\"hex\");\n}\n\nexport function publicKeyRawBase64UrlFromPem(publicKeyPem: string): string {\n return base64UrlEncode(derivePublicKeyRaw(publicKeyPem));\n}\n\nexport function signDevicePayload(privateKeyPem: string, payload: string): string {\n const key = crypto.createPrivateKey(privateKeyPem);\n return base64UrlEncode(crypto.sign(null, Buffer.from(payload, \"utf8\"), key));\n}\n\nexport function buildDeviceAuthPayload(params: {\n deviceId: string;\n clientId: string;\n clientMode: string;\n role: string;\n scopes: string[];\n signedAtMs: number;\n token: string | null;\n nonce: string;\n}): string {\n const scopes = params.scopes.join(\",\");\n const token = params.token ?? \"\";\n return [\n \"v2\",\n params.deviceId,\n params.clientId,\n params.clientMode,\n params.role,\n scopes,\n String(params.signedAtMs),\n token,\n params.nonce,\n ].join(\"|\");\n}\n\n// ─── File I/O helpers ───\n\nexport function resolveClientStateDir(stateDir: string | undefined): string {\n return stateDir ?? resolveHostStateDir();\n}\n\nfunction ensureDir(filePath: string): void {\n fs.mkdirSync(path.dirname(filePath), { recursive: true });\n}\n\nfunction resolveIdentityPath(stateDir: string): string {\n return path.join(stateDir, \"identity\", \"device.json\");\n}\n\nfunction normalizeDeviceAuthRole(role: string): string {\n return role.trim();\n}\n\nfunction normalizeDeviceAuthScopes(scopes: string[]): string[] {\n const out = new Set<string>();\n for (const scope of scopes) {\n const trimmed = scope.trim();\n if (trimmed) {\n out.add(trimmed);\n }\n }\n return [...out].sort();\n}\n\nfunction resolveDeviceAuthPath(stateDir: string): string {\n return path.join(stateDir, \"identity\", \"device-auth.json\");\n}\n\nfunction readDeviceAuthStore(filePath: string): DeviceAuthStore | null {\n try {\n if (!fs.existsSync(filePath)) return null;\n const raw = fs.readFileSync(filePath, \"utf8\");\n const parsed = JSON.parse(raw);\n if (parsed?.version !== 1 || typeof parsed.deviceId !== \"string\") return null;\n if (!parsed.tokens || typeof parsed.tokens !== \"object\") return null;\n return parsed as DeviceAuthStore;\n } catch {\n return null;\n }\n}\n\nfunction writeDeviceAuthStore(filePath: string, store: DeviceAuthStore): void {\n ensureDir(filePath);\n fs.writeFileSync(filePath, `${JSON.stringify(store, null, 2)}\\n`, {\n mode: 0o600,\n });\n try {\n fs.chmodSync(filePath, 0o600);\n } catch {\n // ignore chmod errors on unsupported filesystems\n }\n}\n\n// ─── Token CRUD ───\n\nexport function loadDeviceAuthToken(params: {\n stateDir: string;\n deviceId: string;\n role: string;\n}): DeviceAuthEntry | null {\n const store = readDeviceAuthStore(resolveDeviceAuthPath(params.stateDir));\n if (!store || store.deviceId !== params.deviceId) return null;\n const entry = store.tokens[normalizeDeviceAuthRole(params.role)];\n if (!entry || typeof entry.token !== \"string\") return null;\n return entry;\n}\n\nexport function storeDeviceAuthToken(params: {\n stateDir: string;\n deviceId: string;\n role: string;\n token: string;\n scopes: string[];\n}): DeviceAuthEntry {\n const filePath = resolveDeviceAuthPath(params.stateDir);\n const existing = readDeviceAuthStore(filePath);\n const role = normalizeDeviceAuthRole(params.role);\n const next: DeviceAuthStore = {\n version: 1,\n deviceId: params.deviceId,\n tokens:\n existing && existing.deviceId === params.deviceId && existing.tokens\n ? { ...existing.tokens }\n : {},\n };\n const entry: DeviceAuthEntry = {\n token: params.token,\n role,\n scopes: normalizeDeviceAuthScopes(params.scopes),\n updatedAtMs: Date.now(),\n };\n next.tokens[role] = entry;\n writeDeviceAuthStore(filePath, next);\n return entry;\n}\n\nexport function clearDeviceAuthToken(params: {\n stateDir: string;\n deviceId: string;\n role: string;\n}): void {\n const filePath = resolveDeviceAuthPath(params.stateDir);\n const store = readDeviceAuthStore(filePath);\n if (!store || store.deviceId !== params.deviceId) return;\n const role = normalizeDeviceAuthRole(params.role);\n if (!store.tokens[role]) return;\n const next: DeviceAuthStore = {\n version: 1,\n deviceId: store.deviceId,\n tokens: { ...store.tokens },\n };\n delete next.tokens[role];\n writeDeviceAuthStore(filePath, next);\n}\n\n// ─── Identity lifecycle ───\n\nexport function loadOrCreateDeviceIdentity(stateDir: string): DeviceIdentity {\n const filePath = resolveIdentityPath(stateDir);\n try {\n if (fs.existsSync(filePath)) {\n const raw = fs.readFileSync(filePath, \"utf8\");\n const parsed = JSON.parse(raw);\n if (\n parsed?.version === 1 &&\n typeof parsed.deviceId === \"string\" &&\n typeof parsed.publicKeyPem === \"string\" &&\n typeof parsed.privateKeyPem === \"string\"\n ) {\n const derivedId = fingerprintPublicKey(parsed.publicKeyPem);\n return {\n deviceId: derivedId,\n publicKeyPem: parsed.publicKeyPem,\n privateKeyPem: parsed.privateKeyPem,\n };\n }\n }\n } catch {\n // fall through to generate\n }\n // Generate new identity\n const { publicKey, privateKey } = crypto.generateKeyPairSync(\"ed25519\");\n const publicKeyPem = publicKey\n .export({ type: \"spki\", format: \"pem\" })\n .toString();\n const privateKeyPem = privateKey\n .export({ type: \"pkcs8\", format: \"pem\" })\n .toString();\n const identity: DeviceIdentity = {\n deviceId: fingerprintPublicKey(publicKeyPem),\n publicKeyPem,\n privateKeyPem,\n };\n fs.mkdirSync(path.dirname(filePath), { recursive: true });\n const stored = {\n version: 1,\n ...identity,\n createdAtMs: Date.now(),\n };\n ensureDir(filePath);\n fs.writeFileSync(filePath, `${JSON.stringify(stored, null, 2)}\\n`, {\n mode: 0o600,\n });\n return identity;\n}\n","import type { RelayClient } from \"./relay-client.js\";\nimport type { RequestFrame } from \"./types.js\";\nimport { previewText, summarizeRequestHeaders } from \"./utils.js\";\n\nexport const RELAY_INTERNAL_HTTP_HEADER = \"x-openclaw-relay-internal\";\n\nexport interface HttpProxyOptions {\n gatewayBaseUrl: string;\n gatewayAuthMode?: \"token\" | \"password\";\n gatewayToken?: string;\n gatewayPassword?: string;\n client: RelayClient;\n logger: {\n info: (msg: string) => void;\n warn: (msg: string) => void;\n error: (msg: string) => void;\n };\n}\n\n// ─── 路径映射 ───\n\nconst PATH_MAP: Record<string, string> = {\n \"/api/message/messageBridge/send\": \"/notifications\",\n};\n\nexport function mapPath(p: string): string {\n return PATH_MAP[p] ?? p;\n}\n\n// ─── Auth helpers ───\n\nfunction resolveGatewayConnectAuth(opts: HttpProxyOptions):\n | { token?: string; password?: string }\n | undefined {\n const token = opts.gatewayToken?.trim() || undefined;\n const password = opts.gatewayPassword?.trim() || undefined;\n if (!token && !password) return undefined;\n return { token, password };\n}\n\nexport function buildLocalGatewayAuthAttempts(\n opts: HttpProxyOptions,\n baseHeaders: Record<string, string>,\n): Array<{ label: string; headers: Record<string, string> }> {\n const auth = resolveGatewayConnectAuth(opts);\n const attempts: Array<{ label: string; headers: Record<string, string> }> = [];\n const seen = new Set<string>();\n const authMode = opts.gatewayAuthMode;\n\n const addAttempt = (kind: \"token\" | \"password\", secret?: string): void => {\n if (!secret) return;\n\n const dedupeKey = `${kind}:${secret}`;\n if (seen.has(dedupeKey)) return;\n seen.add(dedupeKey);\n\n const headers = { ...baseHeaders };\n headers.authorization = `Bearer ${secret}`;\n\n if (kind === \"password\") {\n headers[\"x-openclaw-password\"] = secret;\n } else {\n delete headers[\"x-openclaw-password\"];\n }\n\n attempts.push({\n label: kind === \"token\" ? \"gateway-token\" : \"gateway-password\",\n headers,\n });\n };\n\n if (authMode === \"password\") {\n addAttempt(\"password\", auth?.password);\n addAttempt(\"token\", auth?.token);\n } else {\n addAttempt(\"token\", auth?.token);\n addAttempt(\"password\", auth?.password);\n }\n\n if (attempts.length === 0) {\n attempts.push({\n label: \"no-auth\",\n headers: { ...baseHeaders },\n });\n }\n\n return attempts;\n}\n\n// ─── HTTP request proxy ───\n\nexport async function handleHttpRequest(\n opts: HttpProxyOptions,\n frame: RequestFrame,\n): Promise<void> {\n const mappedPath = mapPath(frame.path);\n const url = new URL(mappedPath, opts.gatewayBaseUrl);\n const startedAtMs = Date.now();\n\n // 代理到本地 gateway 时,替换外部鉴权头为本地 gateway token/password。\n const localHeaders: Record<string, string> = {};\n for (const [k, v] of Object.entries(frame.headers ?? {})) {\n const lower = k.toLowerCase();\n if (lower !== \"authorization\" && lower !== \"x-openclaw-password\") {\n localHeaders[k] = v;\n }\n }\n localHeaders[RELAY_INTERNAL_HTTP_HEADER] = \"1\";\n\n const authAttempts = buildLocalGatewayAuthAttempts(opts, localHeaders);\n opts.logger.info(\n `TunnelProxy: HTTP id=${frame.id} ${frame.method} ${frame.path} → ${url.toString()}${summarizeRequestHeaders(frame.headers)}, authAttempts=${authAttempts.map((a) => a.label).join(\" -> \")}, body=${previewText(frame.body)}`,\n );\n\n try {\n for (let attemptIndex = 0; attemptIndex < authAttempts.length; attemptIndex++) {\n const attempt = authAttempts[attemptIndex];\n opts.logger.info(\n `TunnelProxy: HTTP id=${frame.id} attempt ${attemptIndex + 1}/${authAttempts.length} auth=${attempt.label}`,\n );\n const res = await fetch(url.toString(), {\n method: frame.method,\n headers: attempt.headers,\n body:\n frame.method !== \"GET\" && frame.method !== \"HEAD\"\n ? frame.body\n : undefined,\n });\n\n const hasFallback = attemptIndex < authAttempts.length - 1;\n if (res.status === 401 && hasFallback) {\n const body = await res.text();\n opts.logger.warn(\n `TunnelProxy: HTTP id=${frame.id} local gateway auth via ${attempt.label} returned 401 after ${Date.now() - startedAtMs}ms, retrying next credential${body ? `, body=${previewText(body)}` : \"\"}`,\n );\n continue;\n }\n\n await sendHttpResponse(opts, {\n frameId: frame.id,\n method: frame.method,\n path: mappedPath,\n authLabel: attempt.label,\n startedAtMs,\n res,\n });\n return;\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n opts.logger.error(\n `TunnelProxy: HTTP id=${frame.id} ${frame.method} ${mappedPath} failed after ${Date.now() - startedAtMs}ms: ${message}`,\n );\n opts.client.send({\n type: \"proxy_error\",\n id: frame.id,\n status: 502,\n message: `gateway unreachable: ${message}`,\n });\n }\n}\n\n// ─── Response helpers ───\n\nasync function sendHttpResponse(\n opts: HttpProxyOptions,\n params: {\n frameId: string;\n method: string;\n path: string;\n authLabel: string;\n startedAtMs: number;\n res: Response;\n },\n): Promise<void> {\n const { frameId, method, path, authLabel, startedAtMs, res } = params;\n const contentType = res.headers.get(\"content-type\") ?? \"\";\n const isStreaming = contentType.includes(\"text/event-stream\");\n const elapsedMs = Date.now() - startedAtMs;\n\n opts.logger.info(\n `TunnelProxy: HTTP id=${frameId} ${method} ${path} <= ${res.status} (${elapsedMs}ms, auth=${authLabel}, content-type=${contentType}, streaming=${isStreaming})`,\n );\n\n if (isStreaming && res.body) {\n await streamResponse(opts, frameId, res, startedAtMs);\n return;\n }\n\n const body = await res.text();\n opts.logger.info(\n `TunnelProxy: HTTP id=${frameId} response body=${previewText(body)}`,\n );\n const headers: Record<string, string> = {};\n res.headers.forEach((value, key) => {\n headers[key] = value;\n });\n\n opts.client.send({\n type: \"proxy_response\",\n id: frameId,\n status: res.status,\n headers,\n body,\n });\n}\n\nasync function streamResponse(\n opts: HttpProxyOptions,\n requestId: string,\n res: Response,\n startedAtMs: number,\n): Promise<void> {\n const reader = res.body!.getReader();\n const decoder = new TextDecoder();\n let chunkCount = 0;\n\n opts.logger.info(`TunnelProxy: stream start id=${requestId}`);\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n chunkCount++;\n const chunk = decoder.decode(value, { stream: true });\n opts.logger.info(\n `TunnelProxy: stream delta id=${requestId} chunk#${chunkCount} (${chunk.length} chars)`,\n );\n opts.client.send({\n type: \"stream\",\n id: requestId,\n state: \"delta\",\n data: chunk,\n });\n }\n\n opts.logger.info(\n `TunnelProxy: stream end id=${requestId}, total chunks=${chunkCount}, totalElapsedMs=${Date.now() - startedAtMs}`,\n );\n opts.client.send({\n type: \"stream\",\n id: requestId,\n state: \"end\",\n data: \"\",\n });\n } catch (err) {\n opts.logger.error(\n `TunnelProxy: stream error id=${requestId} after ${chunkCount} chunks and ${Date.now() - startedAtMs}ms: ${err instanceof Error ? err.message : String(err)}`,\n );\n opts.client.send({\n type: \"proxy_error\",\n id: requestId,\n status: 502,\n message: `stream error: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n}\n","import WebSocket from \"ws\";\nimport type { RelayClient } from \"./relay-client.js\";\nimport type { WsOpenFrame, WsDataFrame, WsCloseFrame } from \"./types.js\";\nimport { mapPath } from \"./http-proxy.js\";\n\nexport interface WsProxyOptions {\n gatewayBaseUrl: string;\n client: RelayClient;\n logger: {\n info: (msg: string) => void;\n warn: (msg: string) => void;\n error: (msg: string) => void;\n };\n}\n\nexport class WsProxy {\n /** 活跃的 WebSocket 代理连接,按帧 id 索引 */\n private connections = new Map<string, WebSocket>();\n\n constructor(private readonly opts: WsProxyOptions) {}\n\n get activeCount(): number {\n return this.connections.size;\n }\n\n cleanup(): void {\n for (const [id, ws] of this.connections) {\n this.opts.logger.info(`WsProxy: closing WS id=${id}`);\n try {\n ws.close();\n } catch {\n // ignore\n }\n }\n this.connections.clear();\n }\n\n handleWsOpen(frame: WsOpenFrame): void {\n const wsUrl =\n this.opts.gatewayBaseUrl.replace(/^http/, \"ws\") +\n mapPath(frame.path);\n this.opts.logger.info(\n `TunnelProxy: WS open id=${frame.id}, path=${frame.path} → ${wsUrl}`,\n );\n\n try {\n const ws = new WebSocket(wsUrl, {\n headers: frame.headers,\n });\n\n ws.on(\"open\", () => {\n this.connections.set(frame.id, ws);\n this.opts.logger.info(\n `TunnelProxy: WS id=${frame.id} connected to gateway, active=${this.connections.size}`,\n );\n this.opts.client.send({\n type: \"ws_opened\",\n id: frame.id,\n });\n });\n\n ws.on(\"message\", (data: WebSocket.RawData) => {\n const text =\n typeof data === \"string\"\n ? data\n : Buffer.isBuffer(data)\n ? data.toString()\n : String(data);\n\n this.opts.logger.info(\n `TunnelProxy: WS id=${frame.id} ← gateway data (${text.length} chars): ${text.substring(0, 200)}`,\n );\n this.opts.client.send({\n type: \"ws_data\",\n id: frame.id,\n data: text,\n });\n });\n\n ws.on(\"close\", (code: number, reason: Buffer) => {\n this.connections.delete(frame.id);\n this.opts.logger.info(\n `TunnelProxy: WS id=${frame.id} closed by gateway (code=${code}, reason=${reason.toString()}), active=${this.connections.size}`,\n );\n this.opts.client.send({\n type: \"ws_close\",\n id: frame.id,\n code,\n reason: reason.toString(),\n });\n });\n\n ws.on(\"error\", (err: Error) => {\n this.opts.logger.warn(\n `TunnelProxy: WS id=${frame.id} error: ${err.message}, active=${this.connections.size}`,\n );\n this.connections.delete(frame.id);\n this.opts.client.send({\n type: \"ws_close\",\n id: frame.id,\n code: 1011,\n reason: err.message,\n });\n });\n } catch (err) {\n this.opts.logger.error(\n `TunnelProxy: WS id=${frame.id} failed to connect: ${err instanceof Error ? err.message : String(err)}`,\n );\n this.opts.client.send({\n type: \"ws_close\",\n id: frame.id,\n code: 1011,\n reason: `failed to connect: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n handleWsData(frame: WsDataFrame): void {\n const ws = this.connections.get(frame.id);\n if (ws?.readyState === WebSocket.OPEN) {\n this.opts.logger.info(\n `TunnelProxy: WS id=${frame.id} → gateway data (${frame.data.length} chars): ${frame.data.substring(0, 200)}`,\n );\n ws.send(frame.data);\n } else {\n this.opts.logger.warn(\n `TunnelProxy: WS id=${frame.id} data dropped, ws not open (exists=${!!ws}, readyState=${ws?.readyState ?? \"N/A\"})`,\n );\n }\n }\n\n handleWsClose(frame: WsCloseFrame): void {\n const ws = this.connections.get(frame.id);\n if (ws) {\n this.opts.logger.info(\n `TunnelProxy: WS id=${frame.id} close requested by relay (code=${frame.code ?? 1000}, reason=${frame.reason ?? \"\"})`,\n );\n this.connections.delete(frame.id);\n try {\n ws.close(frame.code ?? 1000, frame.reason ?? \"\");\n } catch {\n // ignore\n }\n } else {\n this.opts.logger.warn(\n `TunnelProxy: WS id=${frame.id} close requested but connection not found`,\n );\n }\n }\n}\n","import { randomBytes } from \"node:crypto\";\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\nimport type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport type { Logger } from \"../logger.js\";\nimport {\n type NotificationIngestResult,\n NotificationStorage,\n type StoredNotification,\n} from \"../notification/storage.js\";\nimport { RELAY_INTERNAL_HTTP_HEADER } from \"../tunnel/http-proxy.js\";\nimport type { RelayTunnelService } from \"../tunnel/service.js\";\nimport type {\n HttpNotificationBody,\n NotificationPushParams,\n RawNotification,\n} from \"../types.js\";\nimport {\n readBody,\n type GatewayMethodRegistrar,\n} from \"./shared.js\";\n\nfunction newIngestId(): string {\n return `ing_${randomBytes(4).toString(\"hex\")}`;\n}\n\nfunction summarizeIncomingBatch(items: RawNotification[]): string {\n const total = items.length;\n if (total === 0) return \"items=0\";\n const now = Date.now();\n let earliest = Number.POSITIVE_INFINITY;\n let latest = Number.NEGATIVE_INFINITY;\n for (const n of items) {\n const t = new Date(n.timestamp).getTime();\n if (Number.isNaN(t)) continue;\n if (t < earliest) earliest = t;\n if (t > latest) latest = t;\n }\n if (!Number.isFinite(earliest)) {\n return `items=${total} (all ts invalid)`;\n }\n const maxLag = now - earliest;\n const minLag = now - latest;\n return `items=${total} earliestTs=${new Date(earliest).toISOString()} lag=${minLag}..${maxLag}ms`;\n}\n\nfunction createEmptyIngestResult(): NotificationIngestResult {\n return {\n received: 0,\n ingested: 0,\n dedupedById: 0,\n dedupedByContent: 0,\n invalid: 0,\n inserted: [],\n };\n}\n\nfunction isRelayInternalHttpRequest(req: IncomingMessage): boolean {\n const header = req.headers?.[RELAY_INTERNAL_HTTP_HEADER];\n if (Array.isArray(header)) {\n return header.includes(\"1\");\n }\n return header === \"1\";\n}\n\n/**\n * 将 ingest 内部结果转成对外响应:丢弃 `inserted` 字段,\n * 它只供插件内部下游链路(如 light-rule agent 评估)使用,\n * 不应该出现在 gateway / HTTP 响应里。\n */\nfunction toIngestResponse(\n result: NotificationIngestResult,\n): Omit<NotificationIngestResult, \"inserted\"> {\n const { inserted: _inserted, ...rest } = result;\n return rest;\n}\n\ninterface NotificationInterfaceDeps {\n api: OpenClawPluginApi;\n logger: Logger;\n getStorage: () => NotificationStorage | null;\n filterNotifications: (items: RawNotification[]) => RawNotification[];\n registerGatewayMethod: GatewayMethodRegistrar;\n tunnelService?: RelayTunnelService | null;\n /** 通知落盘后的钩子,用于触发灯效规则评估。 */\n onAfterIngest?: (\n inserted: StoredNotification[],\n ingestId: string,\n ) => void | Promise<void>;\n}\n\nexport function registerNotificationInterfaces(\n deps: NotificationInterfaceDeps,\n): void {\n const {\n api,\n logger,\n getStorage,\n filterNotifications,\n registerGatewayMethod,\n tunnelService,\n onAfterIngest,\n } = deps;\n\n function triggerAfterIngest(\n inserted: StoredNotification[],\n ingestId: string,\n ): void {\n if (inserted.length === 0 || !onAfterIngest) return;\n logger.info(\n `notifications[${ingestId}]: enqueue ${inserted.length} for light-rule evaluation`,\n );\n void Promise.resolve()\n .then(() => onAfterIngest(inserted, ingestId))\n .catch((err) =>\n logger.warn(\n `notifications[${ingestId}]: onAfterIngest failed: ${err?.message ?? err}`,\n ),\n );\n }\n\n registerGatewayMethod(\n \"notifications.push\",\n async ({ params, respond }) => {\n const storage = getStorage();\n if (!storage) {\n respond(false, null, {\n code: \"NOT_READY\",\n message: \"Storage service not ready\",\n });\n return;\n }\n\n const { items } = params as unknown as NotificationPushParams;\n if (!Array.isArray(items)) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"items must be an array\",\n });\n return;\n }\n\n const ingestId = newIngestId();\n const startMs = Date.now();\n logger.info(\n `notifications[${ingestId}]: gateway notifications.push received ${summarizeIncomingBatch(items)}`,\n );\n\n const filtered = filterNotifications(items);\n if (filtered.length !== items.length) {\n logger.info(\n `notifications[${ingestId}]: filtered ${items.length - filtered.length} ignored-app item(s), kept=${filtered.length}`,\n );\n }\n const result = filtered.length\n ? await storage.ingest(filtered, ingestId)\n : createEmptyIngestResult();\n\n logger.info(\n `notifications[${ingestId}]: ingest done in ${Date.now() - startMs}ms ` +\n `(received=${result.received} ingested=${result.ingested} ` +\n `dedupedById=${result.dedupedById} dedupedByContent=${result.dedupedByContent} invalid=${result.invalid})`,\n );\n\n // 主响应先返回,不阻塞灯效评估\n respond(true, toIngestResponse(result));\n\n // 落盘后异步触发灯效评估(fire-and-forget)\n triggerAfterIngest(result.inserted, ingestId);\n },\n );\n\n api.registerHttpRoute({\n path: \"/notifications\",\n auth: \"gateway\",\n async handler(req: IncomingMessage, res: ServerResponse) {\n if (req.method !== \"POST\") {\n res.writeHead(405, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: \"Method Not Allowed\" }));\n return;\n }\n\n if (!isRelayInternalHttpRequest(req)) {\n await tunnelService?.deactivateForExternalTunnel(\"POST /notifications\");\n }\n\n const storage = getStorage();\n if (!storage) {\n res.writeHead(503, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: \"Service Not Ready\" }));\n return;\n }\n\n let body: HttpNotificationBody;\n try {\n const raw = await readBody(req);\n body = JSON.parse(raw);\n } catch {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: \"Invalid JSON\" }));\n return;\n }\n\n if (!Array.isArray(body.notifications)) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n ok: false,\n error: \"notifications must be an array\",\n }),\n );\n return;\n }\n\n const ingestId = newIngestId();\n const startMs = Date.now();\n logger.info(\n `notifications[${ingestId}]: HTTP POST /notifications received ${summarizeIncomingBatch(body.notifications)}`,\n );\n\n const filtered = filterNotifications(body.notifications);\n if (filtered.length !== body.notifications.length) {\n logger.info(\n `notifications[${ingestId}]: filtered ${body.notifications.length - filtered.length} ignored-app item(s), kept=${filtered.length}`,\n );\n }\n const result = filtered.length\n ? await storage.ingest(filtered, ingestId)\n : createEmptyIngestResult();\n\n logger.info(\n `notifications[${ingestId}]: ingest done in ${Date.now() - startMs}ms ` +\n `(received=${result.received} ingested=${result.ingested} ` +\n `dedupedById=${result.dedupedById} dedupedByContent=${result.dedupedByContent} invalid=${result.invalid})`,\n );\n\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: true, ...toIngestResponse(result) }));\n\n // Relay tunnel 会把手机通知转发到 HTTP 端点;这里也要触发事件驱动灯效评估。\n triggerAfterIngest(result.inserted, ingestId);\n },\n });\n\n logger.info(\"Gateway 通知方法已注册: notifications.push\");\n logger.info(\"HTTP 通知端点已注册: POST /notifications\");\n}\n","import type { IncomingMessage, ServerResponse } from \"node:http\";\nimport type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport type { Logger } from \"../logger.js\";\nimport {\n RecordingStorage,\n canStartTranscription,\n extractSourceTextListFromDocument,\n extractTranscriptTitleFromDocument,\n handleRecordingSync,\n initializeAsr,\n triggerTranscription,\n type RecordingIndexEntry,\n type RecordingStatusEvent,\n validateAsrConfig,\n} from \"../recording/index.js\";\nimport { RELAY_INTERNAL_HTTP_HEADER } from \"../tunnel/http-proxy.js\";\nimport type { RelayTunnelService } from \"../tunnel/service.js\";\nimport type {\n HttpRecordingBody,\n RecordingAsrInitParams,\n RecordingDetail,\n RecordingListItem,\n RecordingListParams,\n RecordingRenameParams,\n RecordingRetranscribeParams,\n RecordingStatusParams,\n RecordingSyncParams,\n RecordingTransferStatus,\n} from \"../types.js\";\nimport {\n readBody,\n trimToUndefined,\n type GatewayMethodRegistrar,\n} from \"./shared.js\";\n\nconst RECORDING_TRANSFER_STATUSES = new Set<RecordingTransferStatus>([\n \"receiving_failed\",\n \"receiving\",\n \"pending_oss_upload\",\n \"uploading_oss\",\n \"oss_uploaded\",\n \"syncing_openclaw\",\n \"sync_failed\",\n \"synced\",\n \"transcribing\",\n \"transcribe_failed\",\n \"transcribed\",\n]);\n\nfunction isRecordingTransferStatus(\n value: string,\n): value is RecordingTransferStatus {\n return RECORDING_TRANSFER_STATUSES.has(value as RecordingTransferStatus);\n}\n\nfunction buildRecordingListItem(entry: RecordingIndexEntry): RecordingListItem {\n return {\n recordingId: entry.id,\n name: entry.metadata.name,\n duration_sec: entry.metadata.duration_sec,\n file_size_bytes: entry.metadata.file_size_bytes,\n created_at: entry.metadata.created_at,\n transfer_status: entry.status,\n marker_count: entry.metadata.markers?.length ?? 0,\n has_audio: !!entry.audioFile,\n has_srt: !!entry.srtFile,\n has_transcript: !!entry.transcriptFile,\n audioFile: entry.audioFile,\n transcriptDataFile: entry.transcriptDataFile,\n transcriptFile: entry.transcriptFile,\n updatedAt: entry.updatedAt,\n ...(entry.lastError ? { error: entry.lastError } : {}),\n };\n}\n\nfunction isRelayInternalHttpRequest(req: IncomingMessage): boolean {\n const header = req.headers?.[RELAY_INTERNAL_HTTP_HEADER];\n if (Array.isArray(header)) {\n return header.includes(\"1\");\n }\n return header === \"1\";\n}\n\nfunction buildRecordingDetail(\n entry: RecordingIndexEntry,\n extras?: Partial<Pick<\n RecordingDetail,\n \"summary\" | \"title\" | \"transcript\" | \"transcriptData\"\n >>,\n): RecordingDetail {\n const title = entry.title?.trim()\n || extras?.title?.trim()\n || entry.metadata.name?.trim()\n || entry.id;\n\n return {\n recordingId: entry.id,\n name: entry.metadata.name,\n duration_sec: entry.metadata.duration_sec,\n file_size_bytes: entry.metadata.file_size_bytes,\n created_at: entry.metadata.created_at,\n location: entry.metadata.location,\n oss_audio_url: entry.metadata.oss_audio_url,\n oss_srt_url: entry.metadata.oss_srt_url,\n markers: entry.metadata.markers ?? [],\n transfer_status: entry.status,\n audioFile: entry.audioFile,\n srtFile: entry.srtFile,\n transcriptDataFile: entry.transcriptDataFile,\n transcriptFile: entry.transcriptFile,\n summaryFile: entry.summaryFile,\n title,\n summary: extras?.summary,\n transcript: extras?.transcript,\n transcriptData: extras?.transcriptData,\n ingestedAt: entry.ingestedAt,\n updatedAt: entry.updatedAt,\n ...(entry.lastError ? { error: entry.lastError } : {}),\n };\n}\n\ninterface RecordingInterfaceDeps {\n api: OpenClawPluginApi;\n logger: Logger;\n asrDataDir: string;\n getRecordingStorage: () => RecordingStorage | null;\n notifyRecordingStatus: (event: RecordingStatusEvent) => void;\n registerGatewayMethod: GatewayMethodRegistrar;\n shouldBroadcastStatusOnHttp: () => boolean;\n tunnelService?: RelayTunnelService | null;\n}\n\nexport function registerRecordingInterfaces(\n deps: RecordingInterfaceDeps,\n): void {\n const {\n api,\n logger,\n asrDataDir,\n getRecordingStorage,\n notifyRecordingStatus,\n registerGatewayMethod,\n shouldBroadcastStatusOnHttp,\n tunnelService,\n } = deps;\n\n registerGatewayMethod(\"recordings.sync\", async ({ params, respond }) => {\n const recordingStorage = getRecordingStorage();\n if (!recordingStorage) {\n respond(false, null, {\n code: \"NOT_READY\",\n message: \"Recording storage service not ready\",\n });\n return;\n }\n\n const {\n recordingId: rawRecordingId,\n recording,\n asr,\n } = params as unknown as RecordingSyncParams;\n const recordingId = trimToUndefined(rawRecordingId);\n if (!recordingId) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"recordingId is required\",\n });\n return;\n }\n\n if (!recording || !recording.oss_audio_url || !recording.created_at) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"recording with oss_audio_url and created_at is required\",\n });\n return;\n }\n\n const asrError = asr ? validateAsrConfig(asr) : undefined;\n if (asrError) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: asrError,\n });\n return;\n }\n\n const result = await handleRecordingSync(\n recordingId,\n recording,\n recordingStorage,\n asr,\n logger,\n { notifyStatus: notifyRecordingStatus },\n );\n respond(\n result.ok,\n result,\n result.ok\n ? undefined\n : {\n code: \"SYNC_FAILED\",\n message: result.error ?? \"Unknown error\",\n },\n );\n });\n\n registerGatewayMethod(\"recordings.list\", async ({ params, respond }) => {\n const recordingStorage = getRecordingStorage();\n if (!recordingStorage) {\n respond(false, null, {\n code: \"NOT_READY\",\n message: \"Recording storage service not ready\",\n });\n return;\n }\n\n const rawStatus = trimToUndefined(\n (params as RecordingListParams | undefined)?.status,\n );\n if (rawStatus && !isRecordingTransferStatus(rawStatus)) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: `invalid recording status: ${rawStatus}`,\n });\n return;\n }\n\n const status = rawStatus as RecordingTransferStatus | undefined;\n const entries = status\n ? recordingStorage.listByStatus(status)\n : recordingStorage.listAll();\n\n respond(true, {\n total: entries.length,\n recordings: entries.map(buildRecordingListItem),\n });\n });\n\n registerGatewayMethod(\"recordings.status\", async ({ params, respond }) => {\n const recordingStorage = getRecordingStorage();\n if (!recordingStorage) {\n respond(false, null, {\n code: \"NOT_READY\",\n message: \"Recording storage service not ready\",\n });\n return;\n }\n\n const { recordingId } = params as unknown as RecordingStatusParams;\n if (!recordingId) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"recordingId is required\",\n });\n return;\n }\n\n const entry = recordingStorage.findById(recordingId);\n if (!entry) {\n respond(false, null, {\n code: \"NOT_FOUND\",\n message: `Recording not found: ${recordingId}`,\n });\n return;\n }\n\n respond(\n true,\n (() => {\n const transcriptDocument =\n recordingStorage.readTranscriptDocument(recordingId);\n\n return buildRecordingDetail(entry, {\n summary: recordingStorage.readSummary(recordingId),\n title: extractTranscriptTitleFromDocument(transcriptDocument),\n transcript: extractSourceTextListFromDocument(transcriptDocument),\n transcriptData: transcriptDocument,\n });\n })(),\n );\n });\n\n registerGatewayMethod(\"recordings.rename\", async ({ params, respond }) => {\n const recordingStorage = getRecordingStorage();\n if (!recordingStorage) {\n respond(false, null, {\n code: \"NOT_READY\",\n message: \"Recording storage service not ready\",\n });\n return;\n }\n\n const { recordingId: rawRecordingId, name: rawName } =\n params as unknown as RecordingRenameParams;\n const recordingId = trimToUndefined(rawRecordingId);\n const name = trimToUndefined(rawName);\n if (!recordingId) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"recordingId is required\",\n });\n return;\n }\n if (!name) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"name is required\",\n });\n return;\n }\n\n const entry = recordingStorage.findById(recordingId);\n if (!entry) {\n respond(false, null, {\n code: \"NOT_FOUND\",\n message: `Recording not found: ${recordingId}`,\n });\n return;\n }\n\n const updated = recordingStorage.rename(recordingId, name);\n respond(true, buildRecordingDetail(updated));\n });\n\n registerGatewayMethod(\"recordings.delete\", async ({ params, respond }) => {\n const recordingStorage = getRecordingStorage();\n if (!recordingStorage) {\n respond(false, null, {\n code: \"NOT_READY\",\n message: \"Recording storage service not ready\",\n });\n return;\n }\n\n const { recordingId, deleteRemote } = params as {\n recordingId: string;\n deleteRemote?: boolean;\n };\n if (!recordingId) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"recordingId is required\",\n });\n return;\n }\n\n if (deleteRemote) {\n const deleted = recordingStorage.delete(recordingId);\n respond(\n deleted,\n { ok: deleted, recordingId, deletedRemote: true },\n deleted\n ? undefined\n : {\n code: \"NOT_FOUND\",\n message: `Recording not found: ${recordingId}`,\n },\n );\n return;\n }\n\n const deleted = recordingStorage.delete(recordingId, {\n localOnly: true,\n });\n respond(\n deleted,\n { ok: deleted, recordingId, deletedRemote: false },\n deleted\n ? undefined\n : {\n code: \"NOT_FOUND\",\n message: `Recording not found: ${recordingId}`,\n },\n );\n });\n\n registerGatewayMethod(\n \"recordings.retranscribe\",\n async ({ params, respond }) => {\n const recordingStorage = getRecordingStorage();\n if (!recordingStorage) {\n respond(false, null, {\n code: \"NOT_READY\",\n message: \"Recording storage service not ready\",\n });\n return;\n }\n\n const { recordingId, asr } =\n params as unknown as RecordingRetranscribeParams;\n if (!recordingId) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"recordingId is required\",\n });\n return;\n }\n\n const asrError = validateAsrConfig(asr);\n if (asrError) {\n respond(false, null, {\n code: \"ASR_NOT_CONFIGURED\",\n message: asrError,\n });\n return;\n }\n\n const entry = recordingStorage.findById(recordingId);\n if (!entry) {\n respond(false, null, {\n code: \"NOT_FOUND\",\n message: `Recording not found: ${recordingId}`,\n });\n return;\n }\n\n if (!canStartTranscription(entry.status)) {\n respond(false, null, {\n code: \"INVALID_STATE\",\n message: `Recording status does not allow retranscribe: ${entry.status}`,\n });\n return;\n }\n\n triggerTranscription(recordingId, recordingStorage, asr, logger, {\n notifyStatus: notifyRecordingStatus,\n }).catch((err) => {\n logger.error(\n `[recordings.retranscribe] 重试转写失败: ${recordingId}, ${err?.message ?? err}`,\n );\n });\n\n respond(true, { ok: true, recordingId, message: \"转写已重新触发\" });\n },\n );\n\n registerGatewayMethod(\"recordings.asr.init\", async ({ params, respond }) => {\n const { asr } = params as unknown as RecordingAsrInitParams;\n const asrError = validateAsrConfig(asr);\n if (asrError) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: asrError,\n });\n return;\n }\n\n const result = await initializeAsr(asr, asrDataDir, logger);\n respond(\n result.ok,\n result,\n result.ok\n ? undefined\n : {\n code: \"ASR_INIT_FAILED\",\n message: result.error ?? \"ASR init failed\",\n },\n );\n });\n\n api.registerHttpRoute({\n path: \"/recordings\",\n auth: \"gateway\",\n async handler(req: IncomingMessage, res: ServerResponse) {\n if (req.method !== \"POST\") {\n res.writeHead(405, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: \"Method Not Allowed\" }));\n return;\n }\n\n if (!isRelayInternalHttpRequest(req)) {\n await tunnelService?.deactivateForExternalTunnel(\"POST /recordings\");\n }\n\n const recordingStorage = getRecordingStorage();\n if (!recordingStorage) {\n res.writeHead(503, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: \"Service Not Ready\" }));\n return;\n }\n\n let body: HttpRecordingBody;\n try {\n const raw = await readBody(req);\n body = JSON.parse(raw);\n } catch {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: \"Invalid JSON\" }));\n return;\n }\n\n const recordingId = trimToUndefined(body.recordingId);\n if (!recordingId) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n ok: false,\n error: \"recordingId is required\",\n }),\n );\n return;\n }\n\n if (!body.recording || !body.recording.oss_audio_url) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n ok: false,\n error: \"recording with oss_audio_url is required\",\n }),\n );\n return;\n }\n\n const asrError = body.asr ? validateAsrConfig(body.asr) : undefined;\n if (asrError) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: asrError }));\n return;\n }\n\n const result = await handleRecordingSync(\n recordingId,\n body.recording,\n recordingStorage,\n body.asr,\n logger,\n shouldBroadcastStatusOnHttp()\n ? { notifyStatus: notifyRecordingStatus }\n : undefined,\n );\n\n res.writeHead(result.ok ? 200 : 500, {\n \"Content-Type\": \"application/json\",\n });\n res.end(JSON.stringify(result));\n },\n } as any);\n\n logger.info(\n \"Gateway 录音方法已注册: recordings.sync / recordings.list / recordings.status / recordings.rename / recordings.delete / recordings.retranscribe / recordings.asr.init\",\n );\n logger.info(\"HTTP 录音端点已注册: POST /recordings\");\n}\n","const PLUGIN_CLI_COMMANDS = new Set([\"ntf\", \"phone-notifications\"]);\nconst GLOBAL_OPTIONS_WITH_VALUE = [\n \"--container\",\n \"--log-level\",\n \"--profile\",\n] as const;\nconst GLOBAL_OPTIONS_WITH_VALUE_SET = new Set<string>(GLOBAL_OPTIONS_WITH_VALUE);\n\nfunction resolvePrimaryCommand(argv = process.argv): string | undefined {\n const args = argv.slice(2);\n\n for (let index = 0; index < args.length; index++) {\n const arg = args[index];\n if (!arg || arg === \"--\") {\n return undefined;\n }\n\n if (GLOBAL_OPTIONS_WITH_VALUE_SET.has(arg)) {\n index++;\n continue;\n }\n\n if (\n GLOBAL_OPTIONS_WITH_VALUE.some((option) => arg.startsWith(`${option}=`))\n ) {\n continue;\n }\n\n if (arg.startsWith(\"-\")) {\n continue;\n }\n\n return arg;\n }\n\n return undefined;\n}\n\nexport function isPluginCliInvocation(argv = process.argv): boolean {\n const primaryCommand = resolvePrimaryCommand(argv);\n return primaryCommand ? PLUGIN_CLI_COMMANDS.has(primaryCommand) : false;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAUA,SAAS,gBAAgB,OAAoC;AAC3D,MAAI,OAAO,UAAU,UAAU;AAC7B,WAAO;AAAA,EACT;AACA,QAAM,UAAU,MAAM,KAAK;AAC3B,SAAO,WAAW;AACpB;AAEA,SAAS,UAAkB;AACzB,SAAO,QAAQ,IAAI,QAAQ,QAAQ,IAAI,eAAe;AACxD;AAEA,SAAS,eAAe,OAA+C;AACrE,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AACA,MAAI,UAAU,KAAK;AACjB,WAAO,QAAQ;AAAA,EACjB;AACA,MAAI,MAAM,WAAW,IAAI,GAAG;AAC1B,eAAO,wBAAK,QAAQ,GAAG,MAAM,MAAM,CAAC,CAAC;AAAA,EACvC;AACA,SAAO;AACT;AAEA,SAAS,uBAAuB,OAAiD;AAC/E,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AACA,QAAM,aAAa,MAAM,QAAQ,OAAO,GAAG,EAAE,YAAY;AACzD,MACE,WAAW,SAAS,SAAS,KAC7B,WAAW,SAAS,UAAU,KAC9B,WAAW,SAAS,SAAS,KAC7B,WAAW,SAAS,UAAU,GAC9B;AACA,WAAO;AAAA,EACT;AACA,MACE,WAAW,SAAS,YAAY,KAChC,WAAW,SAAS,aAAa,GACjC;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,SAAS,qBAA+B;AACtC,QAAM,OAAO,QAAQ;AACrB,SAAO;AAAA,QACL,wBAAK,MAAM,UAAU,YAAY;AAAA,QACjC,wBAAK,MAAM,UAAU,YAAY;AAAA,EACnC;AACF;AAEA,SAAS,gBAAuC;AAC9C,aAAW,YAAY,mBAAmB,GAAG;AAC3C,QAAI,KAAC,4BAAW,QAAQ,GAAG;AACzB;AAAA,IACF;AACA,QAAI;AACF,YAAM,SAAS,KAAK,UAAM,8BAAa,UAAU,OAAO,CAAC;AACzD,aAAO;AAAA,QACL,UAAU,eAAe,gBAAgB,QAAQ,QAAQ,CAAC;AAAA,QAC1D,YAAY,eAAe,gBAAgB,QAAQ,UAAU,CAAC;AAAA,MAChE;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,yBAA6C;AACpD,SAAO;AAAA,IACL,gBAAgB,QAAQ,IAAI,kBAAkB,KAC9C,gBAAgB,QAAQ,IAAI,eAAe,KAC3C,gBAAgB,QAAQ,IAAI,aAAa,KACzC,gBAAgB,QAAQ,IAAI,aAAa,KACzC,gBAAgB,QAAQ,IAAI,UAAU;AAAA,EACxC;AACF;AAEA,SAAS,2BAA+C;AACtD,SAAO;AAAA,IACL,gBAAgB,QAAQ,IAAI,oBAAoB,KAChD,gBAAgB,QAAQ,IAAI,iBAAiB;AAAA,EAC/C;AACF;AAEA,SAAS,qBAA8B;AACrC,QAAM,cAAU,wBAAK,QAAQ,GAAG,WAAW;AAC3C,SAAO;AAAA,QACL,wBAAK,SAAS,eAAe;AAAA,QAC7B,wBAAK,SAAS,kBAAkB;AAAA,QAChC,wBAAK,SAAS,YAAY;AAAA,EAC5B,EAAE,KAAK,CAAC,kBAAc,4BAAW,SAAS,CAAC;AAC7C;AAEO,SAAS,iBAA2B;AACzC,MACE,gBAAgB,QAAQ,IAAI,eAAe,KAC3C,gBAAgB,QAAQ,IAAI,iBAAiB,KAC7C,gBAAgB,QAAQ,IAAI,UAAU,GACtC;AACA,WAAO;AAAA,EACT;AAEA,QAAM,eACJ,uBAAuB,uBAAuB,CAAC,KAC/C,uBAAuB,yBAAyB,CAAC;AACnD,MAAI,cAAc;AAChB,WAAO;AAAA,EACT;AAEA,MAAI,mBAAmB,GAAG;AACxB,WAAO;AAAA,EACT;AAEA,MAAI,cAAc,GAAG;AACnB,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEO,SAAS,kBAA0B;AACxC,QAAM,SAAS,uBAAuB;AACtC,MAAI,QAAQ;AACV,WAAO;AAAA,EACT;AAEA,MAAI,mBAAmB,GAAG;AACxB,eAAO,wBAAK,QAAQ,GAAG,WAAW;AAAA,EACpC;AAEA,QAAM,OAAO,cAAc;AAC3B,MAAI,MAAM,UAAU;AAClB,WAAO,KAAK;AAAA,EACd;AACA,MAAI,MAAM,YAAY;AACpB,eAAO,2BAAQ,KAAK,UAAU;AAAA,EAChC;AAEA,aAAO,wBAAK,QAAQ,GAAG,WAAW;AACpC;AAEO,SAAS,kBAAkB,WAAW,gBAAgB,GAAW;AACtE,QAAM,gBAAgB,yBAAyB;AAC/C,MAAI,eAAe;AACjB,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,cAAc;AAC3B,MACE,MAAM,eACL,CAAC,KAAK,YAAY,CAAC,YAAY,KAAK,aAAa,WAClD;AACA,WAAO,KAAK;AAAA,EACd;AAEA,aAAO,wBAAK,UAAU,eAAe;AACvC;AAEO,SAAS,iBAAiB,UAA0B;AACzD,aAAO,wBAAK,gBAAgB,GAAG,QAAQ;AACzC;AAhLA,IAAAA,iBACAC;AADA;AAAA;AAAA;AAAA,IAAAD,kBAAyC;AACzC,IAAAC,oBAA8B;AAAA;AAAA;;;ACwBvB,SAAS,kBAA0B;AACxC,SAAO,iBAAiB,kBAAkB;AAC5C;AAEO,SAAS,kBAA+B;AAC7C,QAAMC,QAAO,gBAAgB;AAC7B,MAAI,KAAC,4BAAWA,KAAI,EAAG,QAAO,CAAC;AAC/B,MAAI;AACF,WAAO,KAAK,UAAM,8BAAaA,OAAM,OAAO,CAAC;AAAA,EAC/C,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEO,SAAS,iBAAiB,OAA0B;AACzD,QAAMA,QAAO,gBAAgB;AAC7B,qCAAU,2BAAQA,KAAI,GAAG,EAAE,WAAW,MAAM,MAAM,IAAM,CAAC;AACzD,qCAAcA,OAAM,KAAK,UAAU,OAAO,MAAM,CAAC,GAAG;AAAA,IAClD,UAAU;AAAA,IACV,MAAM;AAAA,EACR,CAAC;AACH;AAEO,SAAS,aAAiC;AAC/C,QAAM,QAAQ,gBAAgB;AAC9B,SAAO,MAAM,UAAU,MAAM;AAC/B;AAEO,SAAS,gBAAwB;AACtC,QAAM,SAAS,WAAW;AAC1B,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI;AAAA,MACR,4DAAoB,gBAAgB,CAAC;AAAA,IACvC;AAAA,EACF;AACA,SAAO;AACT;AAYO,SAAS,iBAAiB,UAAkC;AACjE,QAAMA,QAAO,gBAAgB;AAC7B,QAAM,UAAM,2BAAQA,KAAI;AACxB,QAAM,eAAW,4BAASA,KAAI;AAC9B,MAAI,gBAAsD;AAC1D,QAAM,UAAU;AAEhB,QAAM,WAAW,CAAC,QAAgB,gBAA+B;AAC/D,QAAI,CAAC,eAAgB,gBAAgB,YAAY,CAAC,YAAY,SAAS,QAAQ,EAAI;AACnF,QAAI,cAAe,cAAa,aAAa;AAC7C,oBAAgB,WAAW,MAAM;AAC/B,sBAAgB;AAChB,eAAS;AAAA,IACX,GAAG,OAAO;AAAA,EACZ;AAEA,MAAI,UAA2C;AAC/C,MAAI;AACF,kBAAU,uBAAM,KAAK,EAAE,YAAY,MAAM,GAAG,QAAQ;AAAA,EACtD,QAAQ;AAAA,EAER;AAEA,SAAO,MAAM;AACX,QAAI,cAAe,cAAa,aAAa;AAC7C,aAAS,MAAM;AAAA,EACjB;AACF;AApGA,IAAAC,iBAOAC;AAPA;AAAA;AAAA;AAAA,IAAAD,kBAMO;AACP,IAAAC,oBAAkC;AAClC;AAAA;AAAA;;;ACHA,SAAS,YAAY,KAAa,OAAqB;AACrD,QAAMC,QAAO,iBAAiB,MAAM;AACpC,qCAAU,2BAAQA,KAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AAC5C,QAAM,eAAW,4BAAWA,KAAI,QAAI,8BAAaA,OAAM,OAAO,IAAI;AAClE,QAAM,QAAQ,SAAS,MAAM,IAAI;AACjC,QAAM,SAAS,GAAG,GAAG;AACrB,QAAM,MAAM,MAAM,UAAU,CAAC,MAAM,EAAE,WAAW,MAAM,CAAC;AACvD,QAAM,UAAU,GAAG,MAAM,GAAG,KAAK;AACjC,MAAI,OAAO,GAAG;AACZ,UAAM,GAAG,IAAI;AAAA,EACf,OAAO;AACL,QAAI,YAAY,CAAC,SAAS,SAAS,IAAI,EAAG,OAAM,KAAK,EAAE;AACvD,UAAM,KAAK,OAAO;AAAA,EACpB;AACA,qCAAcA,OAAM,MAAM,KAAK,IAAI,GAAG,OAAO;AAC/C;AAmBA,SAAS,aAAa,MAAuB;AAC3C,QAAM,QAAQ,WAAW,IAAI;AAC7B,QAAM,MAAM,SAAS,IAAI;AACzB,SAAO;AAAA,IACL,aAAa,GAAG,KAAK;AAAA,IACrB,gBAAgB,GAAG,GAAG;AAAA,IACtB,eAAe,GAAG,KAAK;AAAA,IACvB,sCAAsC,GAAG,KAAK;AAAA,IAC9C,+CAA+C,GAAG,KAAK;AAAA,IACvD,sBAAsB,GAAG,KAAK;AAAA,EAChC;AACF;AAUA,SAAS,aAAqC;AAC5C,QAAMA,QAAO,iBAAiB,MAAM;AACpC,MAAI,KAAC,4BAAWA,KAAI,EAAG,QAAO,CAAC;AAC/B,SAAO,OAAO;AAAA,QACZ,8BAAaA,OAAM,OAAO,EACvB,MAAM,IAAI,EACV,QAAQ,CAAC,SAAS;AACjB,YAAM,KAAK,KAAK,QAAQ,GAAG;AAC3B,UAAI,KAAK,EAAG,QAAO,CAAC;AACpB,aAAO,CAAC,CAAC,KAAK,MAAM,GAAG,EAAE,EAAE,KAAK,GAAG,KAAK,MAAM,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC;AAAA,IAC/D,CAAC;AAAA,EACL;AACF;AAGO,SAAS,uBAA4C;AAC1D,QAAM,aAAa,WAAW,EAAE,yBAAyB,GAAG,KAAK;AACjE,MAAI,cAAc,WAAW,IAAI,UAAU,EAAG,QAAO;AACrD,SAAO;AACT;AAGO,SAAS,cAAuB;AACrC,QAAM,aAAa,QAAQ,IAAI,yBAAyB,KAAK;AAC7D,MAAI,cAAc,WAAW,IAAI,UAAU,EAAG,QAAO;AAErD,QAAM,aAAa,qBAAqB;AACxC,MAAI,WAAY,QAAO;AAEvB,QAAM,EAAE,IAAI,IAAI,gBAAgB;AAChC,MAAI,OAAO,WAAW,IAAI,GAAG,EAAG,QAAO;AAEvC,SAAO;AACT;AAGO,SAAS,YAAY,KAAoB;AAC9C,MAAI,CAAC,WAAW,IAAI,GAAG,GAAG;AACxB,UAAM,IAAI;AAAA,MACR,+CAAY,GAAG,6BAAS,CAAC,GAAG,UAAU,EAAE,KAAK,IAAI,CAAC;AAAA,IACpD;AAAA,EACF;AACA,cAAY,2BAA2B,GAAG;AAC5C;AAGO,SAAS,WAAW,KAAwB;AACjD,SAAO,WAAW,OAAO,YAAY,CAAC;AACxC;AAGO,SAAS,mBAA8B;AAC5C,SAAO,OAAO,KAAK,UAAU;AAC/B;AAjHA,IAAAC,iBACAC,mBAgCM,WAmBA,YAMA;AA1DN;AAAA;AAAA;AAAA,IAAAD,kBAAmE;AACnE,IAAAC,oBAAwB;AACxB;AACA;AA8BA,IAAM,YAAqC;AAAA,MACzC,aAAa;AAAA,MACb,MAAM;AAAA,MACN,YAAY;AAAA,IACd;AAeA,IAAM,aAAuC;AAAA,MAC3C,aAAa,aAAa,UAAU,WAAW;AAAA,MAC/C,MAAM,aAAa,UAAU,IAAI;AAAA,MACjC,YAAY,aAAa,UAAU,UAAU;AAAA,IAC/C;AAEA,IAAM,aAAkC,IAAI,IAAI,OAAO,KAAK,UAAU,CAAC;AAAA;AAAA;;;AClBhE,SAAS,4BAA4B,aAA6B;AACvE,SAAO,GAAG,WAAW;AACvB;AAEO,SAAS,wBAAwB,QAUjB;AACrB,QAAM,WAAW,kBAAkB,OAAO,QAAQ;AAClD,QAAM,OAAO,2BAA2B,OAAO,IAAI,KAAK,iBAAiB,QAAQ,KAAK;AAEtF,SAAO;AAAA,IACL,eAAe;AAAA,IACf,aAAa,OAAO;AAAA,IACpB,aAAa,OAAO,gBAAe,oBAAI,KAAK,GAAE,YAAY;AAAA,IAC1D,QAAQ;AAAA,MACN,UAAU,OAAO,OAAO;AAAA,MACxB,QAAQC,uBAAsB,OAAO,OAAO,MAAM;AAAA,MAClD,WAAWA,uBAAsB,OAAO,OAAO,SAAS;AAAA,MACxD,QAAQA,uBAAsB,OAAO,OAAO,MAAM;AAAA,IACpD;AAAA,IACA,YAAY;AAAA,MACV,OAAOA,uBAAsB,OAAO,KAAK;AAAA,MACzC,UAAUA,uBAAsB,OAAO,QAAQ;AAAA,MAC/C,SAAS,2BAA2B,OAAO,OAAO;AAAA,MAClD;AAAA,MACA;AAAA,IACF;AAAA,IACA,KAAK,OAAO;AAAA,EACd;AACF;AAEO,SAAS,wBACd,OACgC;AAChC,QAAM,SAAS,OAAO,UAAU,WAC5B,UAAU,KAAK,IACf;AAEJ,MAAI,CAAC,UAAU,OAAO,WAAW,UAAU;AACzC,WAAO;AAAA,EACT;AAEA,QAAM,MAAM;AACZ,QAAM,cAAcA,uBAAsB,IAAI,WAAW;AACzD,QAAM,cAAcA,uBAAsB,IAAI,WAAW;AACzD,QAAM,SAAS,gBAAgB,IAAI,MAAM;AACzC,QAAM,aAAa,sBAAsB,IAAI,UAAU;AAEvD,MAAI,CAAC,eAAe,CAAC,eAAe,CAAC,UAAU,CAAC,YAAY;AAC1D,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL,eACE,OAAO,IAAI,kBAAkB,WACzB,IAAI,gBACJ;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,KAAK,IAAI;AAAA,EACX;AACF;AAEO,SAAS,kCACd,KACoB;AACpB,MAAI,CAAC,IAAK,QAAO;AACjB,SAAO,2BAA2B,IAAI,WAAW,IAAI,KAChD,iBAAiB,IAAI,WAAW,QAAQ;AAC/C;AAEO,SAAS,qCACd,KACoB;AACpB,MAAI,CAAC,IAAK,QAAO;AACjB,SAAO,2BAA2B,IAAI,WAAW,OAAO;AAC1D;AAEO,SAAS,mCACd,KACoB;AACpB,MAAI,CAAC,IAAK,QAAO;AACjB,SAAOA,uBAAsB,IAAI,WAAW,KAAK;AACnD;AAEO,SAAS,kCACd,KAC6C;AAC7C,MAAI,CAAC,IAAK,QAAO;AAEjB,QAAM,iBAAiB,IAAI,WAAW,SACnC,IAAI,CAAC,aAAa;AAAA,IACjB,SAAS,QAAQ;AAAA,IACjB,WAAW,QAAQ;AAAA,IACnB,WAAW,QAAQ;AAAA,IACnB,SAAS,QAAQ;AAAA,EACnB,EAAE,EACD,OAAO,CAAC,YAAYA,uBAAsB,QAAQ,OAAO,CAAC;AAE7D,MAAI,eAAe,SAAS,GAAG;AAC7B,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,yBAAyB,IAAI,GAAG;AAChD,MAAI,QAAQ,SAAS,GAAG;AACtB,WAAO;AAAA,EACT;AAEA,QAAM,iBAAiBA,uBAAsB,IAAI,WAAW,IAAI;AAChE,SAAO,iBACH,CAAC,EAAE,SAAS,eAAe,CAAC,IAC5B;AACN;AAEA,SAAS,UAAU,OAAwB;AACzC,MAAI;AACF,WAAO,KAAK,MAAM,KAAK;AAAA,EACzB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,gBAAgB,OAAsD;AAC7E,MAAI,CAAC,SAAS,OAAO,UAAU,UAAU;AACvC,WAAO;AAAA,EACT;AAEA,QAAM,SAAS;AACf,QAAM,WAAWA,uBAAsB,OAAO,QAAQ;AACtD,MAAI,CAAC,UAAU;AACb,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL;AAAA,IACA,QAAQA,uBAAsB,OAAO,MAAM;AAAA,IAC3C,WAAWA,uBAAsB,OAAO,SAAS;AAAA,IACjD,QAAQA,uBAAsB,OAAO,MAAM;AAAA,EAC7C;AACF;AAEA,SAAS,sBACP,OAC0C;AAC1C,MAAI,CAAC,SAAS,OAAO,UAAU,UAAU;AACvC,WAAO;AAAA,EACT;AAEA,QAAM,aAAa;AACnB,QAAM,WAAW,kBAAkB,WAAW,QAAQ;AACtD,QAAM,OAAO,2BAA2B,WAAW,IAAI,KAAK,iBAAiB,QAAQ;AACrF,MAAI,SAAS,QAAW;AACtB,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL,OAAOA,uBAAsB,WAAW,KAAK;AAAA,IAC7C,UAAUA,uBAAsB,WAAW,QAAQ;AAAA,IACnD,SAAS,2BAA2B,WAAW,OAAO;AAAA,IACtD;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,kBAAkB,OAA6C;AACtE,MAAI,CAAC,MAAM,QAAQ,KAAK,GAAG;AACzB,WAAO,CAAC;AAAA,EACV;AAEA,SAAO,MACJ,IAAI,CAAC,SAAS,iBAAiB,IAAI,CAAC,EACpC,OAAO,CAAC,SAA4C,CAAC,CAAC,IAAI;AAC/D;AAEA,SAAS,iBAAiB,OAAuD;AAC/E,MAAI,CAAC,SAAS,OAAO,UAAU,UAAU;AACvC,WAAO;AAAA,EACT;AAEA,QAAM,UAAU;AAChB,QAAM,OAAOA,uBAAsB,QAAQ,IAAI;AAC/C,MAAI,CAAC,MAAM;AACT,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL;AAAA,IACA,SAAS,wBAAwB,QAAQ,OAAO;AAAA,IAChD,OAAO,wBAAwB,QAAQ,KAAK;AAAA,IAC5C,WAAW,yBAAyB,QAAQ,SAAS;AAAA,EACvD;AACF;AAEA,SAAS,iBACP,UACoB;AACpB,QAAM,QAAQ,SACX,IAAI,CAAC,YAAYA,uBAAsB,QAAQ,IAAI,CAAC,EACpD,OAAO,CAAC,YAA+B,CAAC,CAAC,OAAO;AAEnD,MAAI,MAAM,WAAW,GAAG;AACtB,WAAO;AAAA,EACT;AAEA,SAAO,MAAM,KAAK,MAAM;AAC1B;AAEA,SAAS,yBAAyB,KAA+C;AAC/E,MAAI,CAAC,OAAO,OAAO,QAAQ,UAAU;AACnC,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,eAAgB,IAAmC;AACzD,MAAI,CAAC,gBAAgB,OAAO,iBAAiB,UAAU;AACrD,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,iBAAkB,aAA8C;AACtE,MAAI,CAAC,MAAM,QAAQ,cAAc,GAAG;AAClC,WAAO,CAAC;AAAA,EACV;AAEA,SAAO,eACJ,QAAQ,CAAC,SAAS;AACjB,QAAI,CAAC,QAAQ,OAAO,SAAS,UAAU;AACrC,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,QAAQ;AACd,UAAM,UAAUA,uBAAsB,MAAM,OAAO;AACnD,QAAI,CAAC,SAAS;AACZ,aAAO,CAAC;AAAA,IACV;AAEA,WAAO,CAAC;AAAA,MACN;AAAA,MACA,WAAW,yBAAyB,MAAM,SAAS;AAAA,MACnD,WAAW,wBAAwB,MAAM,SAAS;AAAA,MAClD,SAAS,wBAAwB,MAAM,OAAO;AAAA,IAChD,CAAC;AAAA,EACH,CAAC;AACL;AAEA,SAASA,uBAAsB,OAAoC;AACjE,SAAO,OAAO,UAAU,YAAY,MAAM,KAAK,IAC3C,MAAM,KAAK,IACX;AACN;AAEA,SAAS,2BAA2B,OAAoC;AACtE,SAAO,OAAO,UAAU,WACpB,MAAM,KAAK,IACX;AACN;AAEA,SAAS,wBAAwB,OAAoC;AACnE,SAAO,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,IACrD,QACA;AACN;AAEA,SAAS,yBAAyB,OAAoC;AACpE,SAAO,OAAO,UAAU,KAAK,IACzB,OAAO,KAAK,IACZ;AACN;AA3TA,IAAa;AAAb;AAAA;AAAA;AAAO,IAAM,qCAAqC;AAAA;AAAA;;;ACAlD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkGO,SAAS,kBAAkB,QAAwC;AACxE,QAAMC,UAAK,0BAAS;AACpB,QAAM,cAAU,sBAAK;AACrB,QAAM,iBAAiBA,QAAO,YAAY,YAAY;AACtD,QAAM,UAAU,WAAW,MAAM;AAGjC,MAAI;AACJ,MAAI,gBAAgB;AAClB,yBAAqB;AAAA,EACvB,WAAW,SAAS;AAClB,yBAAqB;AAAA,EACvB,OAAO;AACL,yBAAqB;AAAA,EACvB;AAGA,QAAM,oBAAoB,qBAAqB,oBAAoB,MAAM;AACzE,QAAM,gBAAgB,qBAAqB;AAG3C,QAAM,mBAAmB,oBAAoB,mBAAmB,cAAc;AAE9E,QAAM,OAA+B;AAAA,IACnC,IAAAA;AAAA,IACA,MAAM;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA,mBAAmB,KAAK,MAAM,oBAAoB,EAAE,IAAI;AAAA,IACxD;AAAA,IACA;AAAA,EACF;AAEA,SAAO;AAAA,IACL,4DAA8BA,GAAE,UAAU,OAAO,kBACjC,cAAc,UAAU,OAAO,aACpC,kBAAkB,YAAY,KAAK,iBAAiB,aACtD,gBAAgB,WAAW,aAAa;AAAA,EACnD;AAEA,SAAO;AACT;AAQO,SAAS,oBACd,aACA,iBAA0B,OACR;AAElB,QAAM,cAAc,iBAAiB,cAAc,MAAM;AAEzD,MAAI,eAAe,GAAI,QAAO;AAC9B,MAAI,eAAe,EAAG,QAAO;AAC7B,MAAI,eAAe,EAAG,QAAO;AAC7B,MAAI,eAAe,EAAG,QAAO;AAC7B,SAAO;AACT;AAKO,SAAS,iBAAiB,SAAyB;AACxD,QAAM,UAAM,yBAAK,SAAS,kBAAkB;AAC5C,kCAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAClC,SAAO;AACT;AAKO,SAAS,cAAc,SAAyB;AACrD,QAAM,UAAM,yBAAK,SAAS,eAAe;AACzC,kCAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAClC,SAAO;AACT;AAKO,SAAS,kBAAkB,WAAmB,WAAsC;AACzF,QAAM,gBAAY,yBAAK,WAAW,gBAAgB,SAAS,CAAC;AAC5D,MAAI,KAAC,6BAAW,SAAS,EAAG,QAAO;AAGnC,MAAI;AACF,UAAM,WAAO,2BAAS,SAAS;AAC/B,UAAM,eAAe,iBAAiB,SAAS;AAC/C,WAAO,KAAK,QAAQ,eAAe;AAAA,EACrC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAYA,eAAsB,cACpB,WACA,WACA,QACA,aACA,WAC6D;AAC7D,QAAM,WAAW,gBAAgB,SAAS;AAC1C,QAAM,gBAAY,yBAAK,WAAW,QAAQ;AAG1C,MAAI,kBAAkB,WAAW,SAAS,GAAG;AAC3C,WAAO,KAAK,iFAA+B,QAAQ,EAAE;AACrD,WAAO,EAAE,IAAI,MAAM,UAAU;AAAA,EAC/B;AAGA,QAAM,MAAM,MAAM,gBAAgB,WAAW,aAAa,WAAW,MAAM;AAE3E,SAAO;AAAA,IACL,yDAA2B,SAAS,KAAKC,aAAY,iBAAiB,SAAS,CAAC,CAAC;AAAA,EACnF;AACA,SAAO,KAAK,qCAA2B,GAAG,EAAE;AAE5C,QAAM,SAAS,MAAM,gBAAgB,KAAK,WAAW,MAAM;AAG3D,MACE,CAAC,OAAO,MACR,CAAC,cACA,gBAAgB,UAAU,CAAC,gBAC5B,IAAI,SAAS,gBAAgB,GAC7B;AACA,UAAM,cAAc,8BAA8B,QAAQ,WAAW,SAAS;AAC9E,WAAO;AAAA,MACL,gIAA0D,WAAW;AAAA,IACvE;AACA,WAAO,gBAAgB,aAAa,WAAW,MAAM;AAAA,EACvD;AAEA,SAAO;AACT;AAKA,eAAe,gBACb,WACA,aACA,WACA,QACiB;AAEjB,MAAI,WAAW;AACb,WAAO,GAAG,UAAU,QAAQ,OAAO,EAAE,CAAC,IAAI,gBAAgB,SAAS,CAAC;AAAA,EACtE;AAEA,QAAM,SAAS,eAAe;AAE9B,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO,sBAAsB,QAAQ,WAAW,SAAS;AAAA,IAC3D,KAAK;AACH,aAAO,8BAA8B,QAAQ,WAAW,SAAS;AAAA,IACnE,KAAK,QAAQ;AAEX,YAAM,cAAc,MAAM,SAAS,0BAA0B,MAAM;AACnE,UAAI,aAAa;AACf,eAAO,KAAK,+EAAuC;AACnD,eAAO,sBAAsB,QAAQ,WAAW,SAAS;AAAA,MAC3D;AACA,aAAO,KAAK,iHAAqD;AACjE,aAAO,8BAA8B,QAAQ,WAAW,SAAS;AAAA,IACnE;AAAA,IACA;AACE,aAAO,sBAAsB,QAAQ,WAAW,SAAS;AAAA,EAC7D;AACF;AAKA,eAAe,SAAS,KAAa,QAAkC;AACrE,MAAI;AACF,UAAM,aAAa,IAAI,gBAAgB;AACvC,UAAM,QAAQ,WAAW,MAAM,WAAW,MAAM,GAAG,gBAAgB;AACnE,QAAI;AACF,YAAM,MAAM,MAAM,MAAM,KAAK;AAAA,QAC3B,QAAQ;AAAA,QACR,QAAQ,WAAW;AAAA,MACrB,CAAC;AACD,aAAO,IAAI,MAAM,IAAI,WAAW,OAAO,IAAI,WAAW;AAAA,IACxD,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF,SAASC,MAAU;AACjB,WAAO;AAAA,MACL,+DAA4B,GAAG,KAAKA,MAAK,QAAQA,MAAK,WAAW,SAAS;AAAA,IAC5E;AACA,WAAO;AAAA,EACT;AACF;AAKA,eAAe,gBACb,KACA,WACA,QAC6D;AAC7D,QAAM,UAAU,GAAG,SAAS;AAE5B,MAAI;AACF,wCAAU,4BAAQ,SAAS,GAAG,EAAE,WAAW,KAAK,CAAC;AAEjD,UAAM,aAAa,IAAI,gBAAgB;AAEvC,UAAM,QAAQ,WAAW,MAAM,WAAW,MAAM,GAAG,KAAK,KAAK,GAAI;AAEjE,QAAI;AACF,YAAM,MAAM,MAAM,MAAM,KAAK,EAAE,QAAQ,WAAW,OAAO,CAAC;AAE1D,UAAI,CAAC,IAAI,IAAI;AACX,eAAO;AAAA,UACL,IAAI;AAAA,UACJ;AAAA,UACA,OAAO,8CAAgB,IAAI,MAAM,IAAI,IAAI,UAAU;AAAA,QACrD;AAAA,MACF;AAEA,UAAI,CAAC,IAAI,MAAM;AACb,eAAO,EAAE,IAAI,OAAO,WAAW,OAAO,uEAAgB;AAAA,MACxD;AAEA,YAAM,gBAAgB,OAAO,IAAI,QAAQ,IAAI,gBAAgB,KAAK,CAAC;AACnE,YAAM,kBAAc,oCAAkB,OAAO;AAC7C,YAAM,WAAW,6BAAS,QAAQ,IAAI,IAAW;AAGjD,UAAI,aAAa;AACjB,UAAI,iBAAiB;AACrB,eAAS,GAAG,QAAQ,CAAC,UAAkB;AACrC,sBAAc,MAAM;AACpB,YAAI,gBAAgB,GAAG;AACrB,gBAAM,UAAU,KAAK,MAAO,aAAa,gBAAiB,GAAG;AAC7D,cAAI,WAAW,iBAAiB,IAAI;AAClC,mBAAO;AAAA,cACL,6CAAyB,OAAO,MAAMD,aAAY,UAAU,CAAC,MAAMA,aAAY,aAAa,CAAC;AAAA,YAC/F;AACA,6BAAiB;AAAA,UACnB;AAAA,QACF;AAAA,MACF,CAAC;AAED,gBAAM,2BAAS,UAAU,WAAW;AAAA,IACtC,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAGA,UAAM,EAAE,YAAAE,YAAW,IAAI,MAAM,OAAO,IAAS;AAC7C,IAAAA,YAAW,SAAS,SAAS;AAE7B,UAAM,eAAW,2BAAS,SAAS,EAAE;AACrC,WAAO;AAAA,MACL,6DAA2B,6BAAS,SAAS,CAAC,KAAKF,aAAY,QAAQ,CAAC;AAAA,IAC1E;AAEA,WAAO,EAAE,IAAI,MAAM,UAAU;AAAA,EAC/B,SAASC,MAAU;AAEjB,QAAI;AACF,cAAI,6BAAW,OAAO,EAAG,kCAAW,OAAO;AAAA,IAC7C,QAAQ;AAAA,IAAe;AAEvB,UAAM,MAAMA,MAAK,SAAS,eACtB,oEACCA,MAAK,WAAW,OAAOA,IAAG;AAC/B,WAAO,MAAM,yDAA2B,GAAG,EAAE;AAC7C,WAAO,EAAE,IAAI,OAAO,WAAW,OAAO,IAAI;AAAA,EAC5C;AACF;AASO,SAAS,kBAAkB,SAAiB,QAA+B;AAEhF,QAAM,SAAS,cAAc,OAAO;AACpC,QAAM,eAAW,0BAAS,MAAM,UAC5B,CAAC,mBAAmB,eAAe,UAAU,IAC7C,CAAC,eAAe,WAAW,MAAM;AAErC,aAAW,QAAQ,UAAU;AAC3B,UAAM,cAAU,yBAAK,QAAQ,IAAI;AACjC,YAAI,6BAAW,OAAO,GAAG;AACvB,aAAO,KAAK,+DAA4B,OAAO,EAAE;AACjD,aAAO;AAAA,IACT;AAAA,EACF;AAGA,QAAM,gBAAY,0BAAS,MAAM,UAC7B,CAAC,eAAe,eAAe,SAAS,IACxC,CAAC,eAAe,eAAe,SAAS;AAE5C,aAAW,QAAQ,WAAW;AAC5B,QAAI;AACF,YAAM,UAAM,0BAAS,MAAM,UAAU,UAAU;AAC/C,YAAM,aAAS,qCAAS,GAAG,GAAG,IAAI,IAAI,IAAI,EAAE,UAAU,SAAS,OAAO,OAAO,CAAC,EAAE,KAAK;AACrF,UAAI,QAAQ;AACV,eAAO,KAAK,qEAAkC,MAAM,EAAE;AACtD,eAAO,OAAO,MAAM,IAAI,EAAE,CAAC,EAAE,KAAK;AAAA,MACpC;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,SAAO,KAAK,+EAAuC;AACnD,SAAO;AACT;AAUA,eAAsB,2BACpB,eACA,aACA,SACA,QAC8B;AAE9B,QAAM,MAAM,kBAAkB,MAAM;AAGpC,QAAM,UAAU,YAAY,WAAW,IAAI;AAC3C,QAAM,YAAY,YAAY,SAAS,IAAI;AAC3C,QAAM,UAAU,YAAY,WAAW,IAAI;AAC3C,QAAM,WAAW,YAAY,YAAY;AACzC,QAAM,YAAY,YAAY,aAAa;AAE3C,SAAO;AAAA,IACL,qDAAiC,OAAO,WAAW,SAAS,aACjD,OAAO,cAAc,QAAQ,eAAe,SAAS;AAAA,EAClE;AAGA,QAAM,aAAa,kBAAkB,SAAS,MAAM;AACpD,MAAI,CAAC,YAAY;AACf,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,OACE,mNACa,cAAc,OAAO,CAAC;AAAA,IACvC;AAAA,EACF;AAGA,QAAM,YAAY,iBAAiB,OAAO;AAC1C,MAAI,CAAC,kBAAkB,WAAW,SAAS,GAAG;AAC5C,WAAO,KAAK,gCAAsB,SAAS,sDAAc;AACzD,UAAM,iBAAiB,MAAM;AAAA,MAC3B;AAAA,MACA;AAAA,MACA;AAAA,MACA,YAAY;AAAA,MACZ,YAAY;AAAA,IACd;AACA,QAAI,CAAC,eAAe,IAAI;AACtB,aAAO,EAAE,IAAI,OAAO,OAAO,yCAAW,eAAe,KAAK,GAAG;AAAA,IAC/D;AAAA,EACF;AAEA,QAAM,gBAAY,yBAAK,WAAW,gBAAgB,SAAS,CAAC;AAI5D,MAAI,YAAY;AAChB,MAAI,aAA4B;AAEhC,QAAM,YAAY,kBAAkB,aAAa;AACjD,MAAI,cAAc,QAAQ;AACxB,iBAAa,cAAc,QAAQ,YAAY,cAAc;AAC7D,WAAO;AAAA,MACL,yDAA2B,aAAa,KAAK,aAAa,cAAI;AAAA,IAChE;AAEA,UAAM,gBAAgB,aAAa,eAAe,YAAY,WAAW,MAAM;AAC/E,QAAI,CAAC,cAAc,IAAI;AACrB,aAAO,EAAE,IAAI,OAAO,OAAO,cAAc,MAAO;AAAA,IAClD;AACA,gBAAY;AAAA,EACd;AAGA,QAAM,OAAO,iBAAiB;AAAA,IAC5B,eAAe;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,SAAO,KAAK,iCAAuB,UAAU,IAAI,KAAK,KAAK,GAAG,CAAC,EAAE;AAGjE,MAAI;AACF,UAAM,UAAU,KAAK,IAAI;AACzB,QAAI;AAEJ,QAAI;AACF,mBAAS,sCAAU,YAAY,MAAM;AAAA,QACnC,UAAU;AAAA,QACV,SAAS,KAAK,KAAK;AAAA;AAAA,QACnB,WAAW,MAAM,OAAO;AAAA;AAAA,QACxB,OAAO,CAAC,QAAQ,QAAQ,MAAM;AAAA,MAChC,CAAC;AAAA,IACH,SAASA,MAAU;AACjB,oBAAc,UAAU;AACxB,aAAO,EAAE,IAAI,OAAO,OAAO,yCAAqBA,MAAK,WAAWA,IAAG,GAAG;AAAA,IACxE;AAEA,QAAI,OAAO,WAAW,GAAG;AACvB,oBAAc,UAAU;AACxB,YAAM,SAAS,OAAO,QAAQ,MAAM,GAAG,GAAG,KAAK;AAC/C,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,OAAO,kCAAmB,OAAO,MAAM,KAAK,MAAM;AAAA,MACpD;AAAA,IACF;AAEA,UAAM,UAAU,KAAK,IAAI,IAAI;AAC7B,WAAO,KAAK,6CAAyB,KAAK,MAAM,UAAU,GAAI,CAAC,GAAG;AAGlE,UAAM,WAAW,YAAY;AAC7B,QAAI;AAEJ,YAAI,6BAAW,QAAQ,GAAG;AACxB,wBAAc,+BAAa,UAAU,OAAO;AAE5C,UAAI;AAAE,yCAAW,QAAQ;AAAA,MAAG,QAAQ;AAAA,MAAe;AAAA,IACrD,OAAO;AAEL,oBAAc,OAAO;AAAA,IACvB;AAEA,kBAAc,UAAU;AAExB,WAAO,mBAAmB,aAAa,MAAM;AAAA,EAC/C,SAASA,MAAU;AACjB,kBAAc,UAAU;AACxB,WAAO,EAAE,IAAI,OAAO,OAAO,yCAAqBA,MAAK,WAAWA,IAAG,GAAG;AAAA,EACxE;AACF;AAKO,SAAS,sBACd,SACA,QAMA;AACA,QAAM,MAAM,kBAAkB,MAAM;AACpC,QAAM,aAAa,kBAAkB,SAAS,MAAM;AACpD,QAAM,YAAY,iBAAiB,OAAO;AAE1C,QAAM,YAAgC,CAAC,QAAQ,QAAQ,SAAS,UAAU,UAAU;AACpF,QAAM,mBAAmB,UAAU,OAAO,CAAC,MAAM,kBAAkB,WAAW,CAAC,CAAC;AAEhF,SAAO;AAAA,IACL,aAAa;AAAA,IACb,aAAa,eAAe;AAAA,IAC5B;AAAA,IACA;AAAA,EACF;AACF;AAOA,SAAS,WAAW,QAAyB;AAC3C,MAAI;AAEF,6CAAS,cAAc,EAAE,UAAU,SAAS,OAAO,QAAQ,SAAS,IAAK,CAAC;AAC1E,WAAO,KAAK,4DAA6C;AACzD,WAAO;AAAA,EACT,QAAQ;AAAA,EAER;AAGA,UAAI,0BAAS,MAAM,SAAS;AAC1B,QAAI;AACF,YAAM,eAAW,qCAAS,4CAA4C;AAAA,QACpE,UAAU;AAAA,QACV,OAAO;AAAA,QACP,SAAS;AAAA,MACX,CAAC;AACD,UAAI,SAAS,SAAS,WAAW,GAAG;AAClC,eAAO,KAAK,4DAA6C;AACzD,eAAO;AAAA,MACT;AAAA,IACF,QAAQ;AAAA,IAAe;AAAA,EACzB;AAEA,SAAO;AACT;AAOA,SAAS,qBAAqB,SAAyB,QAAwB;AAC7E,MAAI,YAAY,QAAQ;AAEtB,QAAI;AACF,YAAME,cAAS;AAAA,QACb;AAAA,QACA,EAAE,UAAU,SAAS,OAAO,QAAQ,SAAS,IAAK;AAAA,MACpD;AACA,YAAM,aAAa,SAASA,QAAO,KAAK,EAAE,MAAM,IAAI,EAAE,CAAC,GAAG,EAAE;AAC5D,UAAI,CAAC,OAAO,MAAM,UAAU,KAAK,aAAa,GAAG;AAC/C,eAAO,aAAa;AAAA,MACtB;AAAA,IACF,QAAQ;AACN,aAAO,KAAK,kGAA2C;AAAA,IACzD;AAAA,EACF;AAGA,QAAM,cAAU,0BAAS,KAAK,OAAO,OAAO;AAC5C,QAAM,aAAS,yBAAQ,KAAK,OAAO,OAAO;AAC1C,SAAO,KAAK,IAAI,QAAQ,UAAU,GAAG;AACvC;AAKA,SAAS,uBAA+B;AACtC,QAAM,cAAU,sBAAK;AACrB,MAAI,QAAQ,WAAW,EAAG,QAAO;AAIjC,UAAI,0BAAS,MAAM,gBAAY,sBAAK,MAAM,SAAS;AAGjD,WAAO,QAAQ;AAAA,EACjB;AAEA,SAAO,KAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,SAAS,CAAC,CAAC;AACnD;AAMA,SAAS,kBAAkB,UAAiC;AAC1D,MAAI;AACF,UAAM,SAAK,2BAAS,UAAU,GAAG;AACjC,UAAM,MAAM,OAAO,MAAM,EAAE;AAC3B,mCAAS,IAAI,KAAK,GAAG,IAAI,CAAC;AAC1B,oCAAU,EAAE;AAEZ,UAAM,SAAS,IAAI,SAAS,SAAS,GAAG,CAAC;AACzC,UAAM,UAAU,IAAI,SAAS,SAAS,GAAG,CAAC;AAG1C,QAAI,WAAW,UAAU,IAAI,SAAS,SAAS,GAAG,EAAE,MAAM,OAAQ,QAAO;AAEzE,QAAI,WAAW,QAAQ;AACrB,YAAM,MAAM,IAAI,SAAS,SAAS,GAAG,EAAE;AACvC,UAAI,QAAQ,UAAU,QAAQ,OAAQ,QAAO;AAAA,IAC/C;AAEA,QAAI,IAAI,SAAS,SAAS,GAAG,CAAC,MAAM,OAAQ,QAAO;AAEnD,QAAI,OAAO,WAAW,KAAK,KAAM,IAAI,CAAC,MAAM,QAAS,IAAI,CAAC,IAAI,SAAU,IAAO,QAAO;AAEtF,QAAI,WAAW,OAAQ,QAAO;AAE9B,QAAI,WAAW,OAAQ,QAAO;AAE9B,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAYA,SAAS,aACP,WACA,YACA,WACA,QACiC;AAEjC,MAAI;AACF,UAAM,mBAAe,sCAAU,UAAU;AAAA,MACvC;AAAA,MAAM;AAAA,MAAM;AAAA,MACZ;AAAA,MAAO;AAAA,MAAS;AAAA,MAAO;AAAA,MAAK;AAAA,MAAQ;AAAA,MACpC;AAAA,IACF,GAAG;AAAA,MACD,UAAU;AAAA,MACV,SAAS;AAAA,MACT,OAAO,CAAC,QAAQ,QAAQ,MAAM;AAAA,IAChC,CAAC;AAED,QAAI,aAAa,WAAW,SAAK,6BAAW,UAAU,GAAG;AACvD,aAAO,KAAK,oDAAgC,UAAU,EAAE;AACxD,aAAO,EAAE,IAAI,KAAK;AAAA,IACpB;AAAA,EACF,QAAQ;AAAA,EAER;AAGA,MAAI,cAAc,QAAQ;AACxB,QAAI;AACF,YAAM,iBAAa;AAAA,QACjB;AAAA,QACA,CAAC,UAAU,SAAS,UAAU,WAAW,UAAU;AAAA,QACnD,EAAE,UAAU,SAAS,SAAS,MAAS,OAAO,CAAC,QAAQ,QAAQ,MAAM,EAAE;AAAA,MACzE;AACA,UAAI,WAAW,WAAW,SAAK,6BAAW,UAAU,GAAG;AACrD,eAAO,KAAK,qDAAiC,UAAU,EAAE;AACzD,eAAO,EAAE,IAAI,KAAK;AAAA,MACpB;AAAA,IACF,QAAQ;AAAA,IAAuB;AAAA,EACjC;AAGA,MAAI,QAAQ,aAAa,YAAY,cAAc,QAAQ;AAEzD,QAAI,kBAAkB;AACtB,QAAI,UAAyB;AAC7B,UAAM,cAAc;AAEpB,QAAI,eAAe,CAAC,UAAU,SAAS,WAAW,GAAG;AAEnD,gBAAU,YAAY,cAAc;AACpC,UAAI;AACF,2CAAa,WAAW,OAAO;AAC/B,0BAAkB;AAClB,eAAO;AAAA,UACL,8DAA2B,WAAW;AAAA,QACxC;AAAA,MACF,QAAQ;AACN,kBAAU;AAAA,MACZ;AAAA,IACF;AAEA,QAAI;AACF,YAAM,eAAW,sCAAU,aAAa;AAAA,QACtC;AAAA,QAAM;AAAA,QAAQ;AAAA,QAAM;AAAA,QAAe;AAAA,QAAM;AAAA,QACzC;AAAA,QAAiB;AAAA,MACnB,GAAG;AAAA,QACD,UAAU;AAAA,QACV,SAAS;AAAA,QACT,OAAO,CAAC,QAAQ,QAAQ,MAAM;AAAA,MAChC,CAAC;AAGD,UAAI,eAAW,6BAAW,OAAO,GAAG;AAClC,YAAI;AAAE,2CAAW,OAAO;AAAA,QAAG,QAAQ;AAAA,QAAe;AAAA,MACpD;AAEA,UAAI,SAAS,WAAW,SAAK,6BAAW,UAAU,GAAG;AACnD,eAAO,KAAK,uDAAmC,UAAU,EAAE;AAC3D,eAAO,EAAE,IAAI,KAAK;AAAA,MACpB;AAEA,YAAM,SAAS,SAAS,QAAQ,MAAM,GAAG,GAAG,KAAK;AACjD,aAAO,EAAE,IAAI,OAAO,OAAO,4CAAwB,SAAS,MAAM,MAAM,MAAM,GAAG;AAAA,IACnF,SAASF,MAAU;AAEjB,UAAI,eAAW,6BAAW,OAAO,GAAG;AAClC,YAAI;AAAE,2CAAW,OAAO;AAAA,QAAG,QAAQ;AAAA,QAAe;AAAA,MACpD;AACA,aAAO,EAAE,IAAI,OAAO,OAAO,iCAAkBA,MAAK,OAAO,GAAG;AAAA,IAC9D;AAAA,EACF;AAEA,QAAM,UAAU,cAAc,SAC1B,kGACA;AACJ,SAAO,EAAE,IAAI,OAAO,OAAO,0EAAmB,OAAO,GAAG;AAC1D;AAGA,SAAS,cAAcG,OAA2B;AAChD,MAAIA,aAAQ,6BAAWA,KAAI,GAAG;AAC5B,QAAI;AAAE,uCAAWA,KAAI;AAAA,IAAG,QAAQ;AAAA,IAAe;AAAA,EACjD;AACF;AAKA,SAAS,iBAAiB,QAOb;AACX,QAAM,OAAiB;AAAA,IACrB;AAAA,IAAW,OAAO;AAAA,IAClB;AAAA,IAAU,OAAO;AAAA,IACjB;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA,IAAa,OAAO,OAAO,OAAO;AAAA,EACpC;AAGA,MAAI,OAAO,YAAY,OAAO,aAAa,QAAQ;AACjD,SAAK,KAAK,cAAc,OAAO,QAAQ;AAAA,EACzC,OAAO;AACL,SAAK,KAAK,cAAc,MAAM;AAAA,EAChC;AAGA,MAAI,OAAO,WAAW;AACpB,SAAK,KAAK,aAAa;AAAA,EACzB;AAEA,SAAO;AACT;AAKA,SAAS,mBACP,QACA,QACqB;AACrB,MAAI,CAAC,UAAU,CAAC,OAAO,KAAK,GAAG;AAC7B,WAAO,EAAE,IAAI,OAAO,OAAO,iCAAkB;AAAA,EAC/C;AAEA,MAAI;AACF,UAAM,OAAO,KAAK,MAAM,OAAO,KAAK,CAAC;AAErC,QAAI,CAAC,KAAK,iBAAiB,CAAC,MAAM,QAAQ,KAAK,aAAa,GAAG;AAE7D,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,MAAM,OAAO,KAAK;AAAA,QAClB,UAAU,CAAC;AAAA,MACb;AAAA,IACF;AAEA,UAAM,WAAgC,CAAC;AACvC,UAAM,YAAsB,CAAC;AAE7B,eAAW,QAAQ,KAAK,eAAe;AACrC,YAAM,OAAO,KAAK,MAAM,KAAK,KAAK;AAClC,UAAI,CAAC,KAAM;AAEX,gBAAU,KAAK,IAAI;AAEnB,YAAM,UAAU,KAAK,SAAS,QAAQ,eAAe,KAAK,YAAY,IAAI;AAC1E,YAAM,QAAQ,KAAK,SAAS,MAAM,eAAe,KAAK,YAAY,EAAE;AAEpE,eAAS,KAAK;AAAA,QACZ,UAAU;AAAA,QACV,QAAQ;AAAA,QACR;AAAA,MACF,CAAC;AAAA,IACH;AAEA,UAAM,WAAW,UAAU,KAAK,GAAG;AAEnC,WAAO;AAAA,MACL,6CAAyB,SAAS,MAAM,YAAO,SAAS,MAAM;AAAA,IAChE;AAEA,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,MAAM;AAAA,MACN;AAAA,IACF;AAAA,EACF,SAASH,MAAU;AACjB,WAAO,KAAK,sFAAoCA,MAAK,OAAO,EAAE;AAG9D,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,MAAM,OAAO,KAAK;AAAA,MAClB,UAAU,CAAC;AAAA,IACb;AAAA,EACF;AACF;AAKA,SAAS,eAAe,IAAqB;AAC3C,MAAI,CAAC,GAAI,QAAO;AAEhB,QAAM,QAAQ,GAAG,MAAM,8BAA8B;AACrD,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,CAAC,EAAE,GAAG,GAAG,GAAG,EAAE,IAAI;AACxB,SACE,SAAS,GAAG,EAAE,IAAI,OAClB,SAAS,GAAG,EAAE,IAAI,MAClB,SAAS,GAAG,EAAE,IAAI,MAClB,SAAS,IAAI,EAAE;AAEnB;AAKA,SAASD,aAAY,OAAuB;AAC1C,MAAI,QAAQ,KAAM,QAAO,GAAG,KAAK;AACjC,MAAI,QAAQ,OAAO,KAAM,QAAO,IAAI,QAAQ,MAAM,QAAQ,CAAC,CAAC;AAC5D,MAAI,QAAQ,OAAO,OAAO,KAAM,QAAO,IAAI,SAAS,OAAO,OAAO,QAAQ,CAAC,CAAC;AAC5E,SAAO,IAAI,SAAS,OAAO,OAAO,OAAO,QAAQ,CAAC,CAAC;AACrD;AA77BA,IAWAK,4BACAC,kBAYAC,oBACAC,kBACAC,qBACAC,iBAaM,oBACA,iBAGA,uBAIA,+BAIA,kBAGA,iBAkBA;AAzEN;AAAA;AAAA;AAWA,IAAAL,6BAAyE;AACzE,IAAAC,mBAWO;AACP,IAAAC,qBAAwC;AACxC,IAAAC,mBAAyB;AACzB,IAAAC,sBAAyB;AACzB,IAAAC,kBAAwD;AAaxD,IAAM,qBAAqB;AAC3B,IAAM,kBAAkB;AAGxB,IAAM,wBACJ;AAGF,IAAM,gCACJ;AAGF,IAAM,mBAAmB;AAGzB,IAAM,kBAAoD;AAAA,MACxD,MAAM;AAAA,MACN,MAAM;AAAA,MACN,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,YAAY;AAAA,IACd;AAYA,IAAM,mBAAqD;AAAA,MACzD,MAAM,KAAK,OAAO;AAAA,MAClB,MAAM,MAAM,OAAO;AAAA,MACnB,OAAO,MAAM,OAAO;AAAA,MACpB,QAAQ,OAAO,OAAO;AAAA,MACtB,YAAY,MAAO,OAAO;AAAA,IAC5B;AAAA;AAAA;;;AC/EA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA0HO,SAAS,gBAAgB,QAA6B;AAC3D,SAAO,CAAC,CAAC,UAAU,CAAC,kBAAkB,MAAM;AAC9C;AAMO,SAAS,kBAAkB,QAAwC;AACxE,MAAI,CAAC,QAAQ,MAAM;AACjB,WAAO;AAAA,EACT;AAEA,UAAQ,OAAO,MAAM;AAAA,IACnB,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO,gCAAkB,OAA4B,IAAI;AAAA,EAC7D;AACF;AAOA,eAAsB,cACpB,QACA,SACA,QACiC;AACjC,QAAM,kBAAkB,kBAAkB,MAAM;AAChD,MAAI,iBAAiB;AACnB,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,MAAM,OAAO;AAAA,MACb,OAAO;AAAA,IACT;AAAA,EACF;AAEA,UAAQ,OAAO,MAAM;AAAA,IACnB,KAAK,OAAO;AACV,YAAM,WAAW,6CAA6C,OAAO,GAAG;AACxE,YAAM,gBAAgB,QAAQ,OAAO,KAAK,MAAM,KAAK,QAAQ,WAAW,CAAC;AAEzE,UAAI,CAAC,eAAe;AAClB,eAAO;AAAA,UACL,IAAI;AAAA,UACJ,MAAM;AAAA,UACN,UAAU;AAAA,UACV;AAAA,UACA,UAAU,OAAO,KAAK,YAAY;AAAA,UAClC,eAAe;AAAA,UACf,OACE;AAAA,QACJ;AAAA,MACF;AAEA,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,UAAU;AAAA,QACV;AAAA,QACA,UAAU,OAAO,KAAK,YAAY;AAAA,QAClC,eAAe;AAAA,MACjB;AAAA,IACF;AAAA,IACA,KAAK,SAAS;AACZ,YAAM,cAAc,OAAO,SAAS,CAAC;AACrC,YAAM;AAAA,QACJ,uBAAAC;AAAA,QACA,eAAAC;AAAA,QACA,kBAAAC;AAAA,MACF,IAAI,MAAM;AAEV,YAAM,gBAAgBF,uBAAsB,SAAS,MAAM;AAC3D,YAAM,iBAAiB,YAAY,SAAS,cAAc,YAAY;AAEtE,YAAM,YAAYE,kBAAiB,OAAO;AAC1C,YAAM,iBAAiB,MAAMD;AAAA,QAC3B;AAAA,QACA;AAAA,QACA;AAAA,QACA,YAAY;AAAA,QACZ,YAAY;AAAA,MACd;AACA,UAAI,CAAC,eAAe,IAAI;AACtB,eAAO;AAAA,UACL,IAAI;AAAA,UACJ,MAAM;AAAA,UACN,OAAO;AAAA,UACP,aAAa;AAAA,YACX,GAAG;AAAA,YACH;AAAA,UACF;AAAA,UACA,OAAO,yCAAW,eAAe,KAAK;AAAA,QACxC;AAAA,MACF;AAEA,YAAM,cAAcD,uBAAsB,SAAS,MAAM;AACzD,UAAI,CAAC,YAAY,aAAa;AAC5B,eAAO;AAAA,UACL,IAAI;AAAA,UACJ,MAAM;AAAA,UACN,OAAO;AAAA,UACP,aAAa;AAAA,YACX,GAAG;AAAA,YACH;AAAA,UACF;AAAA,UACA,OACE;AAAA,QACJ;AAAA,MACF;AAEA,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,OAAO;AAAA,QACP,UAAU,YAAY,YAAY;AAAA,QAClC,aAAa;AAAA,UACX,GAAG;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IACA,KAAK;AACH,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,OAAO;AAAA,MACT;AAAA,IACF;AACE,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,MAAM,OAAO;AAAA,QACb,OAAO,gCAAiB,OAAO,IAAI;AAAA,MACrC;AAAA,EACJ;AACF;AAUA,eAAsB,gBACpB,eACA,QACA,QACA,UAGI,CAAC,GACyB;AAC9B,MAAI,KAAC,6BAAW,aAAa,GAAG;AAC9B,WAAO,EAAE,IAAI,OAAO,OAAO,+CAAY,aAAa,GAAG;AAAA,EACzD;AAEA,SAAO;AAAA,IACL,wCAAoB,OAAO,IAAI,UAAU,aAAa;AAAA,EACxD;AAEA,MAAI;AACF,YAAQ,OAAO,MAAM;AAAA,MACnB,KAAK;AACH,eAAO,MAAM;AAAA,UACX,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR,OAAO;AAAA,UACP;AAAA,QACF;AAAA,MACF,KAAK;AACH,eAAO,MAAMG,4BAA2B,eAAe,QAAQ,MAAM;AAAA,MACvE,KAAK;AACH,eAAO,EAAE,IAAI,OAAO,OAAO,sDAAwB;AAAA,MACrD;AACE,eAAO;AAAA,UACL,IAAI;AAAA,UACJ,OAAO,gCAAiB,OAAO,IAAI;AAAA,QACrC;AAAA,IACJ;AAAA,EACF,SAASC,MAAU;AACjB,UAAM,MAAMA,MAAK,WAAW,OAAOA,IAAG;AACtC,WAAO,MAAM,mCAAe,GAAG,EAAE;AACjC,WAAO,EAAE,IAAI,OAAO,OAAO,IAAI;AAAA,EACjC;AACF;AAWO,SAAS,wBACd,QACA,SACA,eACA,aACA,WACQ;AACR,QAAM,UAAU,OAAO,WAAW,cAAc,MAAM,GAAG,EAAE;AAC3D,QAAM,QAAkB,CAAC;AAGzB,QAAM,KAAK,KAAK,OAAO,EAAE;AACzB,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,mCAAU,aAAa,EAAE;AACpC,QAAM,KAAK,uBAAQ,eAAe,WAAW,CAAC,EAAE;AAChD,QAAM,KAAK,mCAAU,SAAS,EAAE;AAChC,MAAI,QAAQ,SAAS,GAAG;AACtB,UAAM,KAAK,mCAAU,QAAQ,MAAM,EAAE;AAAA,EACvC;AACA,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,KAAK;AAChB,QAAM,KAAK,EAAE;AAEb,MAAI,OAAO,YAAY,OAAO,SAAS,SAAS,GAAG;AAEjD,UAAM,gBAAgB,CAAC,GAAG,OAAO,EAAE;AAAA,MACjC,CAAC,GAAG,MAAM,EAAE,eAAe,EAAE;AAAA,IAC/B;AACA,QAAI,YAAY;AAEhB,eAAW,OAAO,OAAO,UAAU;AAEjC,aACE,YAAY,cAAc,UAC1B,cAAc,SAAS,EAAE,gBAAgB,IAAI,UAC7C;AACA,cAAM,IAAI,cAAc,SAAS;AACjC,cAAM;AAAA,UACJ,yBAAU,gBAAgB,EAAE,YAAY,CAAC;AAAA,QAC3C;AACA,cAAM,KAAK,EAAE;AACb;AAAA,MACF;AAEA,YAAM,cAAc,4BAA4B,GAAG;AACnD,UAAI,aAAa;AACf,cAAM,KAAK,WAAW;AACtB,cAAM,KAAK,EAAE;AAAA,MACf;AAAA,IACF;AAGA,WAAO,YAAY,cAAc,QAAQ;AACvC,YAAM,IAAI,cAAc,SAAS;AACjC,YAAM;AAAA,QACJ,yBAAU,gBAAgB,EAAE,YAAY,CAAC;AAAA,MAC3C;AACA,YAAM,KAAK,EAAE;AACb;AAAA,IACF;AAAA,EACF,WAAW,OAAO,MAAM;AAEtB,QAAI,QAAQ,SAAS,GAAG;AACtB,YAAM,KAAK,wBAAS;AACpB,YAAM,KAAK,EAAE;AACb,iBAAW,KAAK,SAAS;AACvB,cAAM,KAAK,2BAAY,gBAAgB,EAAE,YAAY,CAAC,KAAK;AAAA,MAC7D;AACA,YAAM,KAAK,EAAE;AACb,YAAM,KAAK,KAAK;AAChB,YAAM,KAAK,EAAE;AAAA,IACf;AACA,UAAM,KAAK,OAAO,IAAI;AACtB,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,SAAO,MAAM,KAAK,IAAI;AACxB;AAKO,SAAS,eAAe,MAAsB;AAEnD,QAAM,YAAY,KAAK,MAAM,SAAS,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,SAAS,CAAC;AACvE,MAAI,CAAC,UAAW,QAAO;AACvB,QAAM,UAAU,UAAU,KAAK;AAC/B,SAAO,QAAQ,UAAU,KAAK,UAAU,QAAQ,MAAM,GAAG,EAAE;AAC7D;AAKA,eAAsB,yBAAyB,QAsB5C;AACD,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AAGJ,QAAM,SAAS,MAAM,gBAAgB,eAAe,QAAQ,QAAQ;AAAA,IAClE;AAAA,IACA,iBAAiB,KAAK,IAAI,GAAG,KAAK,MAAM,cAAc,GAAI,CAAC;AAAA,EAC7D,CAAC;AACD,MAAI,CAAC,OAAO,IAAI;AACd,WAAO,EAAE,IAAI,OAAO,OAAO,OAAO,MAAM;AAAA,EAC1C;AAGA,QAAM,QAAQC,uBAAsB,OAAO,OAAO,IAC9CA,uBAAsB,OAAO,OAAO,IACpC,eAAe,OAAO,QAAQ,EAAE;AACpC,QAAM,UAAU,OAAO,eAAe;AACtC,SAAO,UAAU;AACjB,QAAM,iBAAiB,wBAAwB;AAAA,IAC7C;AAAA,IACA,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,IACpC,QAAQ,OAAO,cAAc;AAAA,MAC3B,UAAU,OAAO,SAAS,QAAQ,gBAAgB,OAAO;AAAA,IAC3D;AAAA,IACA;AAAA,IACA,UAAU,OAAO;AAAA,IACjB;AAAA,IACA,MAAM,OAAO;AAAA,IACb,WAAW,OAAO,YAAY,CAAC,GAAG,IAAI,CAAC,aAAa;AAAA,MAClD,MAAM,QAAQ;AAAA,MACd,SAAS,QAAQ;AAAA,MACjB,OAAO,QAAQ;AAAA,MACf,WAAW,QAAQ;AAAA,IACrB,EAAE;AAAA,IACF,KAAK,OAAO;AAAA,EACd,CAAC;AAGD,QAAM,WAAW;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAGA,QAAM,yBAAyB,4BAA4B,WAAW;AACtE,QAAM,yBAAqB,yBAAK,mBAAmB,sBAAsB;AACzE;AAAA,IACE;AAAA,IACA,KAAK,UAAU,gBAAgB,MAAM,CAAC;AAAA,IACtC;AAAA,EACF;AACA,SAAO,KAAK,+CAAsB,kBAAkB,EAAE;AAEtD,QAAM,cAAc,MACjB,QAAQ,iBAAiB,EAAE,EAC3B,KAAK,EACL,MAAM,GAAG,EAAE;AACd,QAAM,WAAW,cACb,GAAG,WAAW,IAAI,WAAW,QAC7B,GAAG,WAAW;AAClB,QAAM,eAAW,yBAAK,gBAAgB,QAAQ;AAC9C,sCAAc,UAAU,UAAU,OAAO;AACzC,SAAO,KAAK,qDAAkB,QAAQ,EAAE;AAExC,MAAI;AACJ,MAAI,SAAS;AACX,sBAAkB,GAAG,WAAW;AAChC,UAAM,sBAAkB,yBAAK,cAAc,eAAe;AAC1D,wCAAc,iBAAiB,SAAS,OAAO;AAC/C,WAAO,KAAK,qDAAkB,eAAe,EAAE;AAAA,EACjD;AAEA,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,oBAAoB;AAAA,IACpB;AAAA,IACA;AAAA,IACA,YAAY,kCAAkC,cAAc;AAAA,IAC5D;AAAA,IACA;AAAA,EACF;AACF;AAOA,eAAe,yBACb,aACA,iBACA,WACA,QAC8B;AAC9B,QAAM,wBAAwBA,uBAAsB,WAAW;AAC/D,MAAI,CAAC,uBAAuB;AAC1B,WAAO,EAAE,IAAI,OAAO,OAAO,qFAAwC;AAAA,EACrE;AAEA,QAAM,SAAS,wBAAwB,SAAS;AAChD,QAAM,iBAAiB,6CAA6C,SAAS;AAC7E,QAAM,aAAa,gCAAgC,uBAAuB,SAAS;AAEnF,SAAO;AAAA,IACL,qEAAkC,cAAc,UAAU,gBAAgB,UAAU,KAAK,IAAI;AAAA,EAC/F;AAEA,MAAI;AACJ,MAAI;AACF,UAAM,MAAM;AAAA,MACV;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,gBAAgB;AAAA,QAClB;AAAA,QACA,MAAM,KAAK,UAAU,UAAU;AAAA,MACjC;AAAA,MACA,EAAE,QAAQ,SAAS,aAAa;AAAA,IAClC;AAAA,EACF,SAASD,MAAU;AACjB,UAAM,MAAMA,MAAK,WAAW,OAAOA,IAAG;AACtC,WAAO,MAAM,yGAAmC,GAAG,EAAE;AACrD,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,OAAO,yCAAyC,GAAG;AAAA,IACrD;AAAA,EACF;AAEA,MAAI,CAAC,IAAI,IAAI;AACX,UAAM,UAAU,MAAM,IAAI,KAAK;AAC/B,WAAO;AAAA,MACL,wFAA2C,IAAI,MAAM,UAAU,QAAQ,MAAM,GAAG,GAAG,CAAC;AAAA,IACtF;AACA,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,OAAO,0BAA0B,IAAI,MAAM,IAAI,QAAQ,MAAM,GAAG,GAAG,CAAC;AAAA,IACtE;AAAA,EACF;AAEA,QAAM,MAAO,MAAM,IAAI,KAAK;AAG5B,SAAO;AAAA,IACL,iFAAoC,gBAAgB,GAAG,KAAK,IAAI;AAAA,EAClE;AACA,QAAM,sBAAsB,6BAA6B,GAAG;AAC5D,MAAI,qBAAqB;AACvB,WAAO;AAAA,MACL,iFAAoC,mBAAmB;AAAA,IACzD;AACA,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,OAAO,6CAAyB,mBAAmB;AAAA,IACrD;AAAA,EACF;AAEA,QAAM,OAAO,eAAe,GAAG;AAC/B,QAAM,SAASC,uBAAsB,MAAM,MAAM;AACjD,QAAM,YAAYA,uBAAsB,MAAM,SAAS;AACvD,QAAM,SAAS,6BAA6B,MAAM,MAAM;AAExD,MAAI,CAAC,QAAQ;AACX,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,OAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AAAA,IACL,8EAAsC,MAAM,YAAY,UAAU,SAAS,eAAe,aAAa,KAAK;AAAA,EAC9G;AAEA,MAAI,UAAU,yCAAyC,IAAI,MAAM,GAAG;AAClE,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,OAAO,8BAA8B,MAAM,MAAM;AAAA,IACnD;AAAA,EACF;AAEA,SAAO,MAAM,4BAA4B;AAAA,IACvC;AAAA,IACA;AAAA,IACA,kBAAkB;AAAA,IAClB;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AACH;AAKA,eAAeF,4BACb,eACA,QACA,QAC8B;AAC9B,QAAM,EAAE,4BAA4B,SAAS,IAAI,MAAM;AAIvD,QAAM,UACJ,QAAQ,IAAI,sBACZ,QAAQ,IAAI,uBACZ,yBAAK,eAAe,MAAM,MAAM,IAAI;AAEtC,QAAM,cAAc,OAAO,SAAS,CAAC;AAErC,QAAM,SAAS,MAAM;AAAA,IACnB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,MAAI,OAAO,MAAM,OAAO,MAAM;AAC5B,UAAM,EAAE,gBAAgB,QAAQ,IAAI,MAAM;AAC1C,WAAO,UAAU,QAAQ,OAAO,IAAI;AACpC,WAAO,aAAa;AAAA,MAClB,UAAU;AAAA,MACV,QAAQ;AAAA,IACV;AAAA,EACF;AAEA,SAAO;AACT;AAIA,SAAS,6CAA6C,WAAkC;AACtF,SAAO,WAAW,UAAU,KAAK,KAAK,WAAW,EAAE;AACrD;AAEA,SAAS,wBAAwB,WAAkC;AACjE,QAAM,gBAAgBE,uBAAsB,WAAW,MAAM;AAC7D,SAAO,2BAA2B,iBAAiB,cAAc,CAAC;AACpE;AAEA,SAAS,qDACP,WACQ;AACR,QAAM,iBAAiB,WAAW,UAAU,KAAK;AACjD,MAAI,gBAAgB;AAClB,WAAO,0CAA0C,cAAc;AAAA,EACjE;AACA,SAAO,WAAW,EAAE;AACtB;AAEA,SAAS,0CAA0C,UAA0B;AAC3E,QAAM,UAAU,SAAS,QAAQ,QAAQ,EAAE;AAC3C,MAAI,QAAQ,SAAS,cAAc,GAAG;AACpC,WAAO,GAAG,QAAQ,MAAM,GAAG,CAAC,eAAe,MAAM,CAAC;AAAA,EACpD;AACA,SAAO;AACT;AAEA,SAAS,gCACP,aACA,WACsC;AACtC,QAAM,OAA6C;AAAA,IACjD;AAAA,EACF;AAEA,MAAI,WAAW,UAAU,KAAK,GAAG;AAC/B,SAAK,WAAW,UAAU,SAAS,KAAK;AAAA,EAC1C;AACA,MAAI,OAAO,WAAW,wBAAwB,WAAW;AACvD,SAAK,sBAAsB,UAAU;AAAA,EACvC;AAEA,SAAO;AACT;AAEA,eAAe,4BAA4B,QAOV;AAC/B,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AACJ,QAAM,eAAe,qDAAqD,SAAS;AACnF,MAAI;AAEJ,QAAM,iBAAiB,kBAAkB;AAEzC,WAAS,UAAU,GAAG,WAAW,0CAA0C,WAAW;AACpF,UAAM,WAAW,GAAG,YAAY,IAAI,mBAAmB,MAAM,CAAC;AAC9D,QAAI;AACJ,QAAI;AACF,YAAM,MAAM,MAAM,UAAU;AAAA,QAC1B,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,QAClB;AAAA,MACF,CAAC;AAAA,IACH,SAASD,MAAU;AACjB,YAAM,MAAMA,MAAK,WAAW,OAAOA,IAAG;AACtC,aAAO;AAAA,QACL,0FAAmC,MAAM,aAAa,OAAO,WAAW,GAAG;AAAA,MAC7E;AACA,UAAI,UAAU,0CAA0C;AACtD,cAAME,OAAM,cAAc;AAC1B;AAAA,MACF;AACA,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,OAAO,wCAAwC,GAAG;AAAA,MACpD;AAAA,IACF;AAEA,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,UAAU,MAAM,IAAI,KAAK,EAAE,MAAM,MAAM,EAAE;AAC/C,UAAI,sBAAsB,IAAI,MAAM,GAAG;AACrC,eAAO;AAAA,UACL,0FAAmC,MAAM,aAAa,OAAO,YAAY,IAAI,MAAM,UAAU,QAAQ,MAAM,GAAG,GAAG,CAAC;AAAA,QACpH;AACA,YAAI,UAAU,0CAA0C;AACtD,gBAAMA,OAAM,cAAc;AAC1B;AAAA,QACF;AAAA,MACF,OAAO;AACL,eAAO;AAAA,UACL,uFAA0C,MAAM,aAAa,OAAO,YAAY,IAAI,MAAM,UAAU,QAAQ,MAAM,GAAG,GAAG,CAAC;AAAA,QAC3H;AAAA,MACF;AACA,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,OAAO,gCAAgC,IAAI,MAAM,IAAI,QAAQ,MAAM,GAAG,GAAG,CAAC;AAAA,MAC5E;AAAA,IACF;AAEA,UAAM,MAAO,MAAM,IAAI,KAAK;AAG5B,UAAM,qBAAqB,6BAA6B,GAAG;AAC3D,QAAI,oBAAoB;AACtB,aAAO;AAAA,QACL,uFAA0C,MAAM,aAAa,OAAO,KAAK,kBAAkB;AAAA,MAC7F;AACA,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,OAAO,6CAAyB,kBAAkB;AAAA,MACpD;AAAA,IACF;AAEA,UAAM,OAAO,eAAe,GAAG;AAC/B,UAAM,SAAS,6BAA6B,MAAM,MAAM,KAAK;AAC7D,UAAM,YAAYD,uBAAsB,MAAM,SAAS,KAAK;AAE5D,QAAI,WAAW,YAAY;AACzB,aAAO;AAAA,QACL,uFAA0C,MAAM,aAAa,OAAO,UAAU,gBAAgB,GAAG,KAAK,IAAI;AAAA,MAC5G;AACA,aAAO;AAAA,QACL,wEAAqC,MAAM,YAAY,MAAM,aAAa,OAAO,eAAe,aAAa,KAAK;AAAA,MACpH;AACA,mBAAa;AAAA,IACf;AAEA,QAAI,WAAW,aAAa;AAC1B,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,QAAI,yCAAyC,IAAI,MAAM,GAAG;AACxD,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,OAAO,8BAA8B,MAAM,MAAM;AAAA,MACnD;AAAA,IACF;AAEA,QAAI,CAAC,gCAAgC,IAAI,MAAM,GAAG;AAChD,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,OAAO,qEAA6B,MAAM;AAAA,MAC5C;AAAA,IACF;AAEA,QAAI,UAAU,0CAA0C;AACtD,YAAMC,OAAM,cAAc;AAAA,IAC5B;AAAA,EACF;AAEA,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,OACE,oDAAgC,MAAM,YAAY,2CAA2C,cAAc;AAAA,EAC/G;AACF;AAEA,SAAS,gCACP,QACA,WACA,MACA,iBACA,QACqB;AACrB,QAAM,iBAAiB;AAAA,IACrB,MAAM,cAAc;AAAA,EACtB;AACA,QAAM,aAAa,iCAAiC,gBAAgB,eAAe;AACnF,QAAM,aAAaD,uBAAsB,MAAM,cAAc,UAAU;AACvE,QAAM,cAAcA,uBAAsB,MAAM,cAAc,aAAa,KAAK;AAChF,QAAM,QAAQA,uBAAsB,MAAM,cAAc,KAAK;AAC7D,QAAM,WAAWA,uBAAsB,MAAM,cAAc,QAAQ;AACnE,QAAM,OAAO,WAAW,QAAQ,cAAc;AAC9C,QAAM,SAAS,6BAA6B,MAAM,MAAM,KAAK;AAE7D,MAAI,CAAC,WAAW,QAAQ,CAAC,cAAc,aAAa;AAClD,WAAO;AAAA,MACL,yLAA0F,MAAM;AAAA,IAClG;AAAA,EACF;AAEA,SAAO;AAAA,IACL,wEAAqC,MAAM,eAAe,aAAa,KAAK,WAAW,KAAK,MAAM;AAAA,EACpG;AAEA,SAAO;AAAA,IACL,IAAI;AAAA,IACJ;AAAA,IACA,UAAU,WAAW;AAAA,IACrB,SAAS;AAAA,IACT;AAAA,IACA;AAAA,IACA,YAAY;AAAA,MACV,UAAU;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,aAAa;AAAA,EACf;AACF;AAEA,SAAS,8BACP,MACA,QACQ;AACR,QAAM,eAAeA,uBAAsB,MAAM,YAAY;AAC7D,SAAO,eACH,mBAAmB,MAAM,KAAK,YAAY,KAC1C,mBAAmB,MAAM;AAC/B;AAEA,SAAS,6BACP,SAGoB;AACpB,MAAI,CAAC,WAAW,OAAO,YAAY,YAAY,EAAE,UAAU,UAAU;AACnE,WAAO;AAAA,EACT;AAEA,QAAM,WAAW;AACjB,QAAM,kBAAkB,SAAS,YAAY;AAC7C,QAAM,UAAUA,uBAAsB,SAAS,OAAO;AACtD,MAAI,CAAC,oBAAoB,CAAC,WAAW,SAAS,OAAO;AACnD,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,sBAAsB,SAAS,IAAI;AAChD,MAAI,QAAQ,SAAS;AACnB,WAAO,GAAG,IAAI,IAAI,OAAO;AAAA,EAC3B;AACA,SAAO,WAAW,QAAQ;AAC5B;AAEA,SAAS,eACP,SAGmD;AACnD,MACE,WACA,OAAO,YAAY,YACnB,UAAU,WACV,QAAQ,QACR,OAAO,QAAQ,SAAS,UACxB;AACA,WAAO,QAAQ;AAAA,EACjB;AAEA,SAAO;AACT;AAEA,SAAS,2BAA2B,QAAwB;AAC1D,SAAO,OAAO,WAAW,SAAS,IAC9B,OAAO,MAAM,UAAU,MAAM,IAC7B;AACN;AAEA,SAAS,6BAA6B,QAAqC;AACzE,SAAO,OAAO,WAAW,YAAY,OAAO,KAAK,IAC7C,OAAO,KAAK,EAAE,YAAY,IAC1B;AACN;AAEA,SAASA,uBAAsB,OAAoC;AACjE,SAAO,OAAO,UAAU,YAAY,MAAM,KAAK,IAC3C,MAAM,KAAK,IACX;AACN;AAEA,SAAS,sBAAsB,OAAoC;AACjE,MAAI,OAAO,UAAU,YAAY,MAAM,KAAK,GAAG;AAC7C,WAAO,MAAM,KAAK;AAAA,EACpB;AACA,MAAI,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,GAAG;AACvD,WAAO,OAAO,KAAK;AAAA,EACrB;AACA,SAAO;AACT;AAEA,SAASE,0BAAyB,OAAoC;AACpE,SAAO,OAAO,UAAU,KAAK,IACzB,OAAO,KAAK,IACZ;AACN;AAEA,SAAS,mCAAmC,OAAoC;AAC9E,SAAO,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,KAAK,SAAS,IACnE,QACA;AACN;AAEA,SAAS,qCACP,OAMC;AACD,MAAI,CAAC,MAAM,QAAQ,KAAK,GAAG;AACzB,WAAO,CAAC;AAAA,EACV;AAEA,SAAO,MACJ,QAAQ,CAAC,SAAS;AACjB,QAAI,CAAC,QAAQ,OAAO,SAAS,UAAU;AACrC,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,SAAS;AACf,UAAM,UAAUF,uBAAsB,OAAO,OAAO;AACpD,QAAI,CAAC,SAAS;AACZ,aAAO,CAAC;AAAA,IACV;AAEA,WAAO,CAAC;AAAA,MACN;AAAA,MACA,WAAWE,0BAAyB,OAAO,SAAS;AAAA,MACpD,WAAW,mCAAmC,OAAO,SAAS;AAAA,MAC9D,SAAS,mCAAmC,OAAO,OAAO;AAAA,IAC5D,CAAC;AAAA,EACH,CAAC;AACL;AAEA,SAAS,iCACP,OAMA,oBAIA;AACA,MAAI,MAAM,WAAW,GAAG;AACtB,WAAO;AAAA,MACL,UAAU,CAAC;AAAA,IACb;AAAA,EACF;AAEA,QAAM,WAAW,MAAM,IAAI,CAAC,MAAM,UAAU;AAC1C,UAAM,UAAU,KAAK,aAAa;AAClC,UAAM,gBAAgB,KAAK;AAC3B,UAAM,YAAY,MAAM,QAAQ,CAAC,GAAG;AACpC,UAAM,gBAAgB,UAAU,MAAM,SAAS,IAC3C,mCAAmC,kBAAkB,IACrD;AACJ,UAAM,QAAQ,iBAAiB,aAAa,iBAAiB;AAE7D,WAAO;AAAA,MACL,UAAU;AAAA,MACV,QAAQ,KAAK,IAAI,SAAS,KAAK;AAAA,MAC/B,MAAM,KAAK;AAAA,MACX,YAAY,KAAK;AAAA,IACnB;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL,MAAM,MAAM,IAAI,CAAC,SAAS,KAAK,OAAO,EAAE,KAAK,MAAM;AAAA,IACnD;AAAA,EACF;AACF;AAEA,SAAS,gBAAgB,OAAgB,YAAY,KAAyB;AAC5E,MAAI,SAAS,MAAM;AACjB,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,UAAU,UAAU;AAC7B,UAAM,UAAU,MAAM,KAAK;AAC3B,WAAO,UAAU,QAAQ,MAAM,GAAG,SAAS,IAAI;AAAA,EACjD;AAEA,MAAI;AACF,UAAM,aAAa,KAAK,UAAU,KAAK;AACvC,WAAO,aAAa,WAAW,MAAM,GAAG,SAAS,IAAI;AAAA,EACvD,QAAQ;AACN,WAAO,OAAO,KAAK,EAAE,MAAM,GAAG,SAAS;AAAA,EACzC;AACF;AAEA,eAAeD,OAAM,IAA2B;AAC9C,QAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;AACxD;AAEA,SAAS,sBAAsB,QAAyB;AACtD,SAAO,WAAW,OAAO,UAAU;AACrC;AAEA,SAAS,wBAAgC;AACvC,QAAM,MAAM,QAAQ,IAAI;AACxB,MAAI,KAAK;AACP,UAAM,SAAS,OAAO,GAAG;AACzB,QAAI,OAAO,SAAS,MAAM,KAAK,UAAU,GAAG;AAC1C,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,oBAA4B;AACnC,QAAM,MAAM,QAAQ,IAAI;AACxB,MAAI,KAAK;AACP,UAAM,SAAS,OAAO,GAAG;AACzB,QAAI,OAAO,SAAS,MAAM,KAAK,UAAU,GAAG;AAC1C,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAUA,eAAe,eACb,KACA,MACA,SAMmB;AACnB,QAAM,cAAc,QAAQ,eAAe;AAC3C,QAAM,cAAc,QAAQ,aAAa,sBAAsB;AAC/D,MAAI;AAEJ,WAAS,UAAU,GAAG,WAAW,aAAa,WAAW;AACvD,QAAI;AACF,YAAM,MAAM,MAAM,MAAM,KAAK,IAAI;AACjC,UAAI,sBAAsB,IAAI,MAAM,KAAK,UAAU,aAAa;AAC9D,cAAM,UAAU,MAAM,IAAI,KAAK,EAAE,MAAM,MAAM,EAAE;AAC/C,cAAM,QAAQ,cAAc,KAAK,IAAI,GAAG,UAAU,CAAC;AACnD,gBAAQ,OAAO;AAAA,UACb,IAAI,QAAQ,OAAO,UAAU,IAAI,MAAM,aAAa,OAAO,IAAI,WAAW,MAAM,KAAK,+BAAgB,QAAQ,MAAM,GAAG,GAAG,CAAC;AAAA,QAC5H;AACA,cAAMA,OAAM,KAAK;AACjB;AAAA,MACF;AACA,aAAO;AAAA,IACT,SAASF,MAAK;AACZ,kBAAYA;AACZ,UAAI,UAAU,aAAa;AACzB,cAAM,QAAQ,cAAc,KAAK,IAAI,GAAG,UAAU,CAAC;AACnD,cAAM,MAAOA,MAAa,WAAW,OAAOA,IAAG;AAC/C,gBAAQ,OAAO;AAAA,UACb,IAAI,QAAQ,OAAO,uCAAmB,OAAO,IAAI,WAAW,MAAM,GAAG,KAAK,KAAK;AAAA,QACjF;AACA,cAAME,OAAM,KAAK;AACjB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,qBAAqB,QAAQ,YAAY,IAAI,MAAM,OAAO,SAAS,CAAC;AAC5E;AAmBA,SAAS,gBAAgB,IAAoB;AAC3C,QAAM,eAAe,KAAK,MAAM,KAAK,GAAI;AACzC,QAAM,UAAU,KAAK,MAAM,eAAe,EAAE;AAC5C,QAAM,UAAU,eAAe;AAC/B,SAAO,GAAG,OAAO,OAAO,EAAE,SAAS,GAAG,GAAG,CAAC,IAAI,OAAO,OAAO,EAAE,SAAS,GAAG,GAAG,CAAC;AAChF;AAGA,SAAS,eAAe,SAAyB;AAC/C,QAAM,IAAI,KAAK,MAAM,UAAU,IAAI;AACnC,QAAM,IAAI,KAAK,MAAO,UAAU,OAAQ,EAAE;AAC1C,QAAM,IAAI,KAAK,MAAM,UAAU,EAAE;AACjC,MAAI,IAAI,GAAG;AACT,WAAO,GAAG,CAAC,IAAI,OAAO,CAAC,EAAE,SAAS,GAAG,GAAG,CAAC,IAAI,OAAO,CAAC,EAAE,SAAS,GAAG,GAAG,CAAC;AAAA,EACzE;AACA,SAAO,GAAG,OAAO,CAAC,EAAE,SAAS,GAAG,GAAG,CAAC,IAAI,OAAO,CAAC,EAAE,SAAS,GAAG,GAAG,CAAC;AACpE;AAEA,SAAS,QAAQ,OAAyB;AACxC,SAAO,OAAO,UAAU,YAAY,MAAM,KAAK,EAAE,SAAS;AAC5D;AAEA,SAAS,4BAA4B,SAAoC;AACvE,QAAM,OAAO,QAAQ,KAAK,KAAK;AAC/B,MAAI,CAAC,MAAM;AACT,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,QAAQ,eAAe,UAAU;AAC1C,WAAO,qBAAM,QAAQ,UAAU,SAAI,IAAI;AAAA,EACzC;AAEA,SAAO;AACT;AAvsCA,IAgBAE,kBACAC,oBAiBM,yCACA,0CACA,iCACA,0CAEA,2BACA;AAxCN;AAAA;AAAA;AAgBA,IAAAD,mBAA0C;AAC1C,IAAAC,qBAAqB;AASrB;AACA;AACA;AAMA,IAAM,0CAA0C;AAChD,IAAM,2CAA2C;AACjD,IAAM,kCAAkC,oBAAI,IAAI,CAAC,WAAW,WAAW,WAAW,CAAC;AACnF,IAAM,2CAA2C,oBAAI,IAAI,CAAC,UAAU,YAAY,SAAS,CAAC;AAE1F,IAAM,4BAA4B;AAClC,IAAM,gCAAgC;AAAA;AAAA;;;ACxCtC;AAAA,kEAAAC,UAAAC,SAAA;AAAA;AAEA,QAAM,eAAe,CAAC,cAAc,eAAe,WAAW;AAC9D,QAAM,UAAU,OAAO,SAAS;AAEhC,QAAI,QAAS,cAAa,KAAK,MAAM;AAErC,IAAAA,QAAO,UAAU;AAAA,MACf;AAAA,MACA,eAAe;AAAA,MACf,cAAc,OAAO,MAAM,CAAC;AAAA,MAC5B,MAAM;AAAA,MACN;AAAA,MACA,sBAAsB,uBAAO,wBAAwB;AAAA,MACrD,WAAW,uBAAO,WAAW;AAAA,MAC7B,aAAa,uBAAO,aAAa;AAAA,MACjC,YAAY,uBAAO,WAAW;AAAA,MAC9B,MAAM,MAAM;AAAA,MAAC;AAAA,IACf;AAAA;AAAA;;;AClBA;AAAA,oEAAAC,UAAAC,SAAA;AAAA;AAEA,QAAM,EAAE,aAAa,IAAI;AAEzB,QAAM,aAAa,OAAO,OAAO,OAAO;AAUxC,aAAS,OAAO,MAAM,aAAa;AACjC,UAAI,KAAK,WAAW,EAAG,QAAO;AAC9B,UAAI,KAAK,WAAW,EAAG,QAAO,KAAK,CAAC;AAEpC,YAAM,SAAS,OAAO,YAAY,WAAW;AAC7C,UAAI,SAAS;AAEb,eAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,cAAM,MAAM,KAAK,CAAC;AAClB,eAAO,IAAI,KAAK,MAAM;AACtB,kBAAU,IAAI;AAAA,MAChB;AAEA,UAAI,SAAS,aAAa;AACxB,eAAO,IAAI,WAAW,OAAO,QAAQ,OAAO,YAAY,MAAM;AAAA,MAChE;AAEA,aAAO;AAAA,IACT;AAYA,aAAS,MAAM,QAAQ,MAAMC,SAAQ,QAAQ,QAAQ;AACnD,eAAS,IAAI,GAAG,IAAI,QAAQ,KAAK;AAC/B,QAAAA,QAAO,SAAS,CAAC,IAAI,OAAO,CAAC,IAAI,KAAK,IAAI,CAAC;AAAA,MAC7C;AAAA,IACF;AASA,aAAS,QAAQ,QAAQ,MAAM;AAC7B,eAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,eAAO,CAAC,KAAK,KAAK,IAAI,CAAC;AAAA,MACzB;AAAA,IACF;AASA,aAAS,cAAc,KAAK;AAC1B,UAAI,IAAI,WAAW,IAAI,OAAO,YAAY;AACxC,eAAO,IAAI;AAAA,MACb;AAEA,aAAO,IAAI,OAAO,MAAM,IAAI,YAAY,IAAI,aAAa,IAAI,MAAM;AAAA,IACrE;AAUA,aAAS,SAAS,MAAM;AACtB,eAAS,WAAW;AAEpB,UAAI,OAAO,SAAS,IAAI,EAAG,QAAO;AAElC,UAAI;AAEJ,UAAI,gBAAgB,aAAa;AAC/B,cAAM,IAAI,WAAW,IAAI;AAAA,MAC3B,WAAW,YAAY,OAAO,IAAI,GAAG;AACnC,cAAM,IAAI,WAAW,KAAK,QAAQ,KAAK,YAAY,KAAK,UAAU;AAAA,MACpE,OAAO;AACL,cAAM,OAAO,KAAK,IAAI;AACtB,iBAAS,WAAW;AAAA,MACtB;AAEA,aAAO;AAAA,IACT;AAEA,IAAAD,QAAO,UAAU;AAAA,MACf;AAAA,MACA,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,IACV;AAGA,QAAI,CAAC,QAAQ,IAAI,mBAAmB;AAClC,UAAI;AACF,cAAM,aAAa,QAAQ,YAAY;AAEvC,QAAAA,QAAO,QAAQ,OAAO,SAAU,QAAQ,MAAMC,SAAQ,QAAQ,QAAQ;AACpE,cAAI,SAAS,GAAI,OAAM,QAAQ,MAAMA,SAAQ,QAAQ,MAAM;AAAA,cACtD,YAAW,KAAK,QAAQ,MAAMA,SAAQ,QAAQ,MAAM;AAAA,QAC3D;AAEA,QAAAD,QAAO,QAAQ,SAAS,SAAU,QAAQ,MAAM;AAC9C,cAAI,OAAO,SAAS,GAAI,SAAQ,QAAQ,IAAI;AAAA,cACvC,YAAW,OAAO,QAAQ,IAAI;AAAA,QACrC;AAAA,MACF,SAAS,GAAG;AAAA,MAEZ;AAAA,IACF;AAAA;AAAA;;;AClIA;AAAA,gEAAAE,UAAAC,SAAA;AAAA;AAEA,QAAM,QAAQ,uBAAO,OAAO;AAC5B,QAAM,OAAO,uBAAO,MAAM;AAM1B,QAAM,UAAN,MAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAOZ,YAAY,aAAa;AACvB,aAAK,KAAK,IAAI,MAAM;AAClB,eAAK;AACL,eAAK,IAAI,EAAE;AAAA,QACb;AACA,aAAK,cAAc,eAAe;AAClC,aAAK,OAAO,CAAC;AACb,aAAK,UAAU;AAAA,MACjB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQA,IAAI,KAAK;AACP,aAAK,KAAK,KAAK,GAAG;AAClB,aAAK,IAAI,EAAE;AAAA,MACb;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAOA,CAAC,IAAI,IAAI;AACP,YAAI,KAAK,YAAY,KAAK,YAAa;AAEvC,YAAI,KAAK,KAAK,QAAQ;AACpB,gBAAM,MAAM,KAAK,KAAK,MAAM;AAE5B,eAAK;AACL,cAAI,KAAK,KAAK,CAAC;AAAA,QACjB;AAAA,MACF;AAAA,IACF;AAEA,IAAAA,QAAO,UAAU;AAAA;AAAA;;;ACtDjB;AAAA,2EAAAC,UAAAC,SAAA;AAAA;AAEA,QAAM,OAAO,QAAQ,MAAM;AAE3B,QAAM,aAAa;AACnB,QAAM,UAAU;AAChB,QAAM,EAAE,YAAY,IAAI;AAExB,QAAM,aAAa,OAAO,OAAO,OAAO;AACxC,QAAM,UAAU,OAAO,KAAK,CAAC,GAAM,GAAM,KAAM,GAAI,CAAC;AACpD,QAAM,qBAAqB,uBAAO,oBAAoB;AACtD,QAAM,eAAe,uBAAO,cAAc;AAC1C,QAAM,YAAY,uBAAO,UAAU;AACnC,QAAM,WAAW,uBAAO,SAAS;AACjC,QAAM,SAAS,uBAAO,OAAO;AAS7B,QAAI;AAKJ,QAAM,oBAAN,MAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAyBtB,YAAY,SAAS,UAAU,YAAY;AACzC,aAAK,cAAc,aAAa;AAChC,aAAK,WAAW,WAAW,CAAC;AAC5B,aAAK,aACH,KAAK,SAAS,cAAc,SAAY,KAAK,SAAS,YAAY;AACpE,aAAK,YAAY,CAAC,CAAC;AACnB,aAAK,WAAW;AAChB,aAAK,WAAW;AAEhB,aAAK,SAAS;AAEd,YAAI,CAAC,aAAa;AAChB,gBAAM,cACJ,KAAK,SAAS,qBAAqB,SAC/B,KAAK,SAAS,mBACd;AACN,wBAAc,IAAI,QAAQ,WAAW;AAAA,QACvC;AAAA,MACF;AAAA;AAAA;AAAA;AAAA,MAKA,WAAW,gBAAgB;AACzB,eAAO;AAAA,MACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQA,QAAQ;AACN,cAAM,SAAS,CAAC;AAEhB,YAAI,KAAK,SAAS,yBAAyB;AACzC,iBAAO,6BAA6B;AAAA,QACtC;AACA,YAAI,KAAK,SAAS,yBAAyB;AACzC,iBAAO,6BAA6B;AAAA,QACtC;AACA,YAAI,KAAK,SAAS,qBAAqB;AACrC,iBAAO,yBAAyB,KAAK,SAAS;AAAA,QAChD;AACA,YAAI,KAAK,SAAS,qBAAqB;AACrC,iBAAO,yBAAyB,KAAK,SAAS;AAAA,QAChD,WAAW,KAAK,SAAS,uBAAuB,MAAM;AACpD,iBAAO,yBAAyB;AAAA,QAClC;AAEA,eAAO;AAAA,MACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MASA,OAAO,gBAAgB;AACrB,yBAAiB,KAAK,gBAAgB,cAAc;AAEpD,aAAK,SAAS,KAAK,YACf,KAAK,eAAe,cAAc,IAClC,KAAK,eAAe,cAAc;AAEtC,eAAO,KAAK;AAAA,MACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAOA,UAAU;AACR,YAAI,KAAK,UAAU;AACjB,eAAK,SAAS,MAAM;AACpB,eAAK,WAAW;AAAA,QAClB;AAEA,YAAI,KAAK,UAAU;AACjB,gBAAM,WAAW,KAAK,SAAS,SAAS;AAExC,eAAK,SAAS,MAAM;AACpB,eAAK,WAAW;AAEhB,cAAI,UAAU;AACZ;AAAA,cACE,IAAI;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MASA,eAAe,QAAQ;AACrB,cAAM,OAAO,KAAK;AAClB,cAAM,WAAW,OAAO,KAAK,CAAC,WAAW;AACvC,cACG,KAAK,4BAA4B,SAChC,OAAO,8BACR,OAAO,2BACL,KAAK,wBAAwB,SAC3B,OAAO,KAAK,wBAAwB,YACnC,KAAK,sBAAsB,OAAO,2BACvC,OAAO,KAAK,wBAAwB,YACnC,CAAC,OAAO,wBACV;AACA,mBAAO;AAAA,UACT;AAEA,iBAAO;AAAA,QACT,CAAC;AAED,YAAI,CAAC,UAAU;AACb,gBAAM,IAAI,MAAM,8CAA8C;AAAA,QAChE;AAEA,YAAI,KAAK,yBAAyB;AAChC,mBAAS,6BAA6B;AAAA,QACxC;AACA,YAAI,KAAK,yBAAyB;AAChC,mBAAS,6BAA6B;AAAA,QACxC;AACA,YAAI,OAAO,KAAK,wBAAwB,UAAU;AAChD,mBAAS,yBAAyB,KAAK;AAAA,QACzC;AACA,YAAI,OAAO,KAAK,wBAAwB,UAAU;AAChD,mBAAS,yBAAyB,KAAK;AAAA,QACzC,WACE,SAAS,2BAA2B,QACpC,KAAK,wBAAwB,OAC7B;AACA,iBAAO,SAAS;AAAA,QAClB;AAEA,eAAO;AAAA,MACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MASA,eAAe,UAAU;AACvB,cAAM,SAAS,SAAS,CAAC;AAEzB,YACE,KAAK,SAAS,4BAA4B,SAC1C,OAAO,4BACP;AACA,gBAAM,IAAI,MAAM,mDAAmD;AAAA,QACrE;AAEA,YAAI,CAAC,OAAO,wBAAwB;AAClC,cAAI,OAAO,KAAK,SAAS,wBAAwB,UAAU;AACzD,mBAAO,yBAAyB,KAAK,SAAS;AAAA,UAChD;AAAA,QACF,WACE,KAAK,SAAS,wBAAwB,SACrC,OAAO,KAAK,SAAS,wBAAwB,YAC5C,OAAO,yBAAyB,KAAK,SAAS,qBAChD;AACA,gBAAM,IAAI;AAAA,YACR;AAAA,UACF;AAAA,QACF;AAEA,eAAO;AAAA,MACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MASA,gBAAgB,gBAAgB;AAC9B,uBAAe,QAAQ,CAAC,WAAW;AACjC,iBAAO,KAAK,MAAM,EAAE,QAAQ,CAAC,QAAQ;AACnC,gBAAI,QAAQ,OAAO,GAAG;AAEtB,gBAAI,MAAM,SAAS,GAAG;AACpB,oBAAM,IAAI,MAAM,cAAc,GAAG,iCAAiC;AAAA,YACpE;AAEA,oBAAQ,MAAM,CAAC;AAEf,gBAAI,QAAQ,0BAA0B;AACpC,kBAAI,UAAU,MAAM;AAClB,sBAAM,MAAM,CAAC;AACb,oBAAI,CAAC,OAAO,UAAU,GAAG,KAAK,MAAM,KAAK,MAAM,IAAI;AACjD,wBAAM,IAAI;AAAA,oBACR,gCAAgC,GAAG,MAAM,KAAK;AAAA,kBAChD;AAAA,gBACF;AACA,wBAAQ;AAAA,cACV,WAAW,CAAC,KAAK,WAAW;AAC1B,sBAAM,IAAI;AAAA,kBACR,gCAAgC,GAAG,MAAM,KAAK;AAAA,gBAChD;AAAA,cACF;AAAA,YACF,WAAW,QAAQ,0BAA0B;AAC3C,oBAAM,MAAM,CAAC;AACb,kBAAI,CAAC,OAAO,UAAU,GAAG,KAAK,MAAM,KAAK,MAAM,IAAI;AACjD,sBAAM,IAAI;AAAA,kBACR,gCAAgC,GAAG,MAAM,KAAK;AAAA,gBAChD;AAAA,cACF;AACA,sBAAQ;AAAA,YACV,WACE,QAAQ,gCACR,QAAQ,8BACR;AACA,kBAAI,UAAU,MAAM;AAClB,sBAAM,IAAI;AAAA,kBACR,gCAAgC,GAAG,MAAM,KAAK;AAAA,gBAChD;AAAA,cACF;AAAA,YACF,OAAO;AACL,oBAAM,IAAI,MAAM,sBAAsB,GAAG,GAAG;AAAA,YAC9C;AAEA,mBAAO,GAAG,IAAI;AAAA,UAChB,CAAC;AAAA,QACH,CAAC;AAED,eAAO;AAAA,MACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAUA,WAAW,MAAM,KAAK,UAAU;AAC9B,oBAAY,IAAI,CAAC,SAAS;AACxB,eAAK,YAAY,MAAM,KAAK,CAACC,MAAK,WAAW;AAC3C,iBAAK;AACL,qBAASA,MAAK,MAAM;AAAA,UACtB,CAAC;AAAA,QACH,CAAC;AAAA,MACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAUA,SAAS,MAAM,KAAK,UAAU;AAC5B,oBAAY,IAAI,CAAC,SAAS;AACxB,eAAK,UAAU,MAAM,KAAK,CAACA,MAAK,WAAW;AACzC,iBAAK;AACL,qBAASA,MAAK,MAAM;AAAA,UACtB,CAAC;AAAA,QACH,CAAC;AAAA,MACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAUA,YAAY,MAAM,KAAK,UAAU;AAC/B,cAAM,WAAW,KAAK,YAAY,WAAW;AAE7C,YAAI,CAAC,KAAK,UAAU;AAClB,gBAAM,MAAM,GAAG,QAAQ;AACvB,gBAAM,aACJ,OAAO,KAAK,OAAO,GAAG,MAAM,WACxB,KAAK,uBACL,KAAK,OAAO,GAAG;AAErB,eAAK,WAAW,KAAK,iBAAiB;AAAA,YACpC,GAAG,KAAK,SAAS;AAAA,YACjB;AAAA,UACF,CAAC;AACD,eAAK,SAAS,kBAAkB,IAAI;AACpC,eAAK,SAAS,YAAY,IAAI;AAC9B,eAAK,SAAS,QAAQ,IAAI,CAAC;AAC3B,eAAK,SAAS,GAAG,SAAS,cAAc;AACxC,eAAK,SAAS,GAAG,QAAQ,aAAa;AAAA,QACxC;AAEA,aAAK,SAAS,SAAS,IAAI;AAE3B,aAAK,SAAS,MAAM,IAAI;AACxB,YAAI,IAAK,MAAK,SAAS,MAAM,OAAO;AAEpC,aAAK,SAAS,MAAM,MAAM;AACxB,gBAAMA,OAAM,KAAK,SAAS,MAAM;AAEhC,cAAIA,MAAK;AACP,iBAAK,SAAS,MAAM;AACpB,iBAAK,WAAW;AAChB,qBAASA,IAAG;AACZ;AAAA,UACF;AAEA,gBAAMC,QAAO,WAAW;AAAA,YACtB,KAAK,SAAS,QAAQ;AAAA,YACtB,KAAK,SAAS,YAAY;AAAA,UAC5B;AAEA,cAAI,KAAK,SAAS,eAAe,YAAY;AAC3C,iBAAK,SAAS,MAAM;AACpB,iBAAK,WAAW;AAAA,UAClB,OAAO;AACL,iBAAK,SAAS,YAAY,IAAI;AAC9B,iBAAK,SAAS,QAAQ,IAAI,CAAC;AAE3B,gBAAI,OAAO,KAAK,OAAO,GAAG,QAAQ,sBAAsB,GAAG;AACzD,mBAAK,SAAS,MAAM;AAAA,YACtB;AAAA,UACF;AAEA,mBAAS,MAAMA,KAAI;AAAA,QACrB,CAAC;AAAA,MACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAUA,UAAU,MAAM,KAAK,UAAU;AAC7B,cAAM,WAAW,KAAK,YAAY,WAAW;AAE7C,YAAI,CAAC,KAAK,UAAU;AAClB,gBAAM,MAAM,GAAG,QAAQ;AACvB,gBAAM,aACJ,OAAO,KAAK,OAAO,GAAG,MAAM,WACxB,KAAK,uBACL,KAAK,OAAO,GAAG;AAErB,eAAK,WAAW,KAAK,iBAAiB;AAAA,YACpC,GAAG,KAAK,SAAS;AAAA,YACjB;AAAA,UACF,CAAC;AAED,eAAK,SAAS,YAAY,IAAI;AAC9B,eAAK,SAAS,QAAQ,IAAI,CAAC;AAE3B,eAAK,SAAS,GAAG,QAAQ,aAAa;AAAA,QACxC;AAEA,aAAK,SAAS,SAAS,IAAI;AAE3B,aAAK,SAAS,MAAM,IAAI;AACxB,aAAK,SAAS,MAAM,KAAK,cAAc,MAAM;AAC3C,cAAI,CAAC,KAAK,UAAU;AAIlB;AAAA,UACF;AAEA,cAAIA,QAAO,WAAW;AAAA,YACpB,KAAK,SAAS,QAAQ;AAAA,YACtB,KAAK,SAAS,YAAY;AAAA,UAC5B;AAEA,cAAI,KAAK;AACP,YAAAA,QAAO,IAAI,WAAWA,MAAK,QAAQA,MAAK,YAAYA,MAAK,SAAS,CAAC;AAAA,UACrE;AAMA,eAAK,SAAS,SAAS,IAAI;AAE3B,eAAK,SAAS,YAAY,IAAI;AAC9B,eAAK,SAAS,QAAQ,IAAI,CAAC;AAE3B,cAAI,OAAO,KAAK,OAAO,GAAG,QAAQ,sBAAsB,GAAG;AACzD,iBAAK,SAAS,MAAM;AAAA,UACtB;AAEA,mBAAS,MAAMA,KAAI;AAAA,QACrB,CAAC;AAAA,MACH;AAAA,IACF;AAEA,IAAAF,QAAO,UAAU;AAQjB,aAAS,cAAc,OAAO;AAC5B,WAAK,QAAQ,EAAE,KAAK,KAAK;AACzB,WAAK,YAAY,KAAK,MAAM;AAAA,IAC9B;AAQA,aAAS,cAAc,OAAO;AAC5B,WAAK,YAAY,KAAK,MAAM;AAE5B,UACE,KAAK,kBAAkB,EAAE,cAAc,KACvC,KAAK,YAAY,KAAK,KAAK,kBAAkB,EAAE,aAC/C;AACA,aAAK,QAAQ,EAAE,KAAK,KAAK;AACzB;AAAA,MACF;AAEA,WAAK,MAAM,IAAI,IAAI,WAAW,2BAA2B;AACzD,WAAK,MAAM,EAAE,OAAO;AACpB,WAAK,MAAM,EAAE,WAAW,IAAI;AAC5B,WAAK,eAAe,QAAQ,aAAa;AASzC,WAAK,MAAM;AAAA,IACb;AAQA,aAAS,eAAeC,MAAK;AAK3B,WAAK,kBAAkB,EAAE,WAAW;AAEpC,UAAI,KAAK,MAAM,GAAG;AAChB,aAAK,SAAS,EAAE,KAAK,MAAM,CAAC;AAC5B;AAAA,MACF;AAEA,MAAAA,KAAI,WAAW,IAAI;AACnB,WAAK,SAAS,EAAEA,IAAG;AAAA,IACrB;AAAA;AAAA;;;AC/gBA;AAAA,mEAAAE,UAAAC,SAAA;AAAA;AAEA,QAAM,EAAE,OAAO,IAAI,QAAQ,QAAQ;AAEnC,QAAM,EAAE,QAAQ,IAAI;AAcpB,QAAM,aAAa;AAAA,MACjB;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA;AAAA,MAC7C;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA;AAAA,MAC7C;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA;AAAA,MAC7C;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA;AAAA,MAC7C;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA;AAAA,MAC7C;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA;AAAA,MAC7C;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA;AAAA,MAC7C;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA,MAAG;AAAA;AAAA,IAC/C;AASA,aAAS,kBAAkB,MAAM;AAC/B,aACG,QAAQ,OACP,QAAQ,QACR,SAAS,QACT,SAAS,QACT,SAAS,QACV,QAAQ,OAAQ,QAAQ;AAAA,IAE7B;AAWA,aAAS,aAAa,KAAK;AACzB,YAAM,MAAM,IAAI;AAChB,UAAI,IAAI;AAER,aAAO,IAAI,KAAK;AACd,aAAK,IAAI,CAAC,IAAI,SAAU,GAAG;AAEzB;AAAA,QACF,YAAY,IAAI,CAAC,IAAI,SAAU,KAAM;AAEnC,cACE,IAAI,MAAM,QACT,IAAI,IAAI,CAAC,IAAI,SAAU,QACvB,IAAI,CAAC,IAAI,SAAU,KACpB;AACA,mBAAO;AAAA,UACT;AAEA,eAAK;AAAA,QACP,YAAY,IAAI,CAAC,IAAI,SAAU,KAAM;AAEnC,cACE,IAAI,KAAK,QACR,IAAI,IAAI,CAAC,IAAI,SAAU,QACvB,IAAI,IAAI,CAAC,IAAI,SAAU,OACvB,IAAI,CAAC,MAAM,QAAS,IAAI,IAAI,CAAC,IAAI,SAAU;AAAA,UAC3C,IAAI,CAAC,MAAM,QAAS,IAAI,IAAI,CAAC,IAAI,SAAU,KAC5C;AACA,mBAAO;AAAA,UACT;AAEA,eAAK;AAAA,QACP,YAAY,IAAI,CAAC,IAAI,SAAU,KAAM;AAEnC,cACE,IAAI,KAAK,QACR,IAAI,IAAI,CAAC,IAAI,SAAU,QACvB,IAAI,IAAI,CAAC,IAAI,SAAU,QACvB,IAAI,IAAI,CAAC,IAAI,SAAU,OACvB,IAAI,CAAC,MAAM,QAAS,IAAI,IAAI,CAAC,IAAI,SAAU;AAAA,UAC3C,IAAI,CAAC,MAAM,OAAQ,IAAI,IAAI,CAAC,IAAI,OACjC,IAAI,CAAC,IAAI,KACT;AACA,mBAAO;AAAA,UACT;AAEA,eAAK;AAAA,QACP,OAAO;AACL,iBAAO;AAAA,QACT;AAAA,MACF;AAEA,aAAO;AAAA,IACT;AASA,aAAS,OAAO,OAAO;AACrB,aACE,WACA,OAAO,UAAU,YACjB,OAAO,MAAM,gBAAgB,cAC7B,OAAO,MAAM,SAAS,YACtB,OAAO,MAAM,WAAW,eACvB,MAAM,OAAO,WAAW,MAAM,UAC7B,MAAM,OAAO,WAAW,MAAM;AAAA,IAEpC;AAEA,IAAAA,QAAO,UAAU;AAAA,MACf;AAAA,MACA;AAAA,MACA,aAAa;AAAA,MACb;AAAA,IACF;AAEA,QAAI,QAAQ;AACV,MAAAA,QAAO,QAAQ,cAAc,SAAU,KAAK;AAC1C,eAAO,IAAI,SAAS,KAAK,aAAa,GAAG,IAAI,OAAO,GAAG;AAAA,MACzD;AAAA,IACF,WAAuC,CAAC,QAAQ,IAAI,sBAAsB;AACxE,UAAI;AACF,cAAM,cAAc,QAAQ,gBAAgB;AAE5C,QAAAA,QAAO,QAAQ,cAAc,SAAU,KAAK;AAC1C,iBAAO,IAAI,SAAS,KAAK,aAAa,GAAG,IAAI,YAAY,GAAG;AAAA,QAC9D;AAAA,MACF,SAAS,GAAG;AAAA,MAEZ;AAAA,IACF;AAAA;AAAA;;;ACvJA;AAAA,iEAAAC,UAAAC,SAAA;AAAA;AAEA,QAAM,EAAE,SAAS,IAAI,QAAQ,QAAQ;AAErC,QAAM,oBAAoB;AAC1B,QAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,IAAI;AACJ,QAAM,EAAE,QAAQ,eAAe,OAAO,IAAI;AAC1C,QAAM,EAAE,mBAAmB,YAAY,IAAI;AAE3C,QAAM,aAAa,OAAO,OAAO,OAAO;AAExC,QAAM,WAAW;AACjB,QAAM,wBAAwB;AAC9B,QAAM,wBAAwB;AAC9B,QAAM,WAAW;AACjB,QAAM,WAAW;AACjB,QAAM,YAAY;AAClB,QAAM,cAAc;AAOpB,QAAMC,YAAN,cAAuB,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAiB9B,YAAY,UAAU,CAAC,GAAG;AACxB,cAAM;AAEN,aAAK,0BACH,QAAQ,2BAA2B,SAC/B,QAAQ,yBACR;AACN,aAAK,cAAc,QAAQ,cAAc,aAAa,CAAC;AACvD,aAAK,cAAc,QAAQ,cAAc,CAAC;AAC1C,aAAK,YAAY,CAAC,CAAC,QAAQ;AAC3B,aAAK,cAAc,QAAQ,aAAa;AACxC,aAAK,sBAAsB,CAAC,CAAC,QAAQ;AACrC,aAAK,UAAU,IAAI;AAEnB,aAAK,iBAAiB;AACtB,aAAK,WAAW,CAAC;AAEjB,aAAK,cAAc;AACnB,aAAK,iBAAiB;AACtB,aAAK,QAAQ;AACb,aAAK,cAAc;AACnB,aAAK,UAAU;AACf,aAAK,OAAO;AACZ,aAAK,UAAU;AAEf,aAAK,sBAAsB;AAC3B,aAAK,iBAAiB;AACtB,aAAK,aAAa,CAAC;AAEnB,aAAK,WAAW;AAChB,aAAK,QAAQ;AACb,aAAK,SAAS;AAAA,MAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAUA,OAAO,OAAO,UAAU,IAAI;AAC1B,YAAI,KAAK,YAAY,KAAQ,KAAK,UAAU,SAAU,QAAO,GAAG;AAEhE,aAAK,kBAAkB,MAAM;AAC7B,aAAK,SAAS,KAAK,KAAK;AACxB,aAAK,UAAU,EAAE;AAAA,MACnB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MASA,QAAQ,GAAG;AACT,aAAK,kBAAkB;AAEvB,YAAI,MAAM,KAAK,SAAS,CAAC,EAAE,OAAQ,QAAO,KAAK,SAAS,MAAM;AAE9D,YAAI,IAAI,KAAK,SAAS,CAAC,EAAE,QAAQ;AAC/B,gBAAM,MAAM,KAAK,SAAS,CAAC;AAC3B,eAAK,SAAS,CAAC,IAAI,IAAI;AAAA,YACrB,IAAI;AAAA,YACJ,IAAI,aAAa;AAAA,YACjB,IAAI,SAAS;AAAA,UACf;AAEA,iBAAO,IAAI,WAAW,IAAI,QAAQ,IAAI,YAAY,CAAC;AAAA,QACrD;AAEA,cAAM,MAAM,OAAO,YAAY,CAAC;AAEhC,WAAG;AACD,gBAAM,MAAM,KAAK,SAAS,CAAC;AAC3B,gBAAM,SAAS,IAAI,SAAS;AAE5B,cAAI,KAAK,IAAI,QAAQ;AACnB,gBAAI,IAAI,KAAK,SAAS,MAAM,GAAG,MAAM;AAAA,UACvC,OAAO;AACL,gBAAI,IAAI,IAAI,WAAW,IAAI,QAAQ,IAAI,YAAY,CAAC,GAAG,MAAM;AAC7D,iBAAK,SAAS,CAAC,IAAI,IAAI;AAAA,cACrB,IAAI;AAAA,cACJ,IAAI,aAAa;AAAA,cACjB,IAAI,SAAS;AAAA,YACf;AAAA,UACF;AAEA,eAAK,IAAI;AAAA,QACX,SAAS,IAAI;AAEb,eAAO;AAAA,MACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQA,UAAU,IAAI;AACZ,aAAK,QAAQ;AAEb,WAAG;AACD,kBAAQ,KAAK,QAAQ;AAAA,YACnB,KAAK;AACH,mBAAK,QAAQ,EAAE;AACf;AAAA,YACF,KAAK;AACH,mBAAK,mBAAmB,EAAE;AAC1B;AAAA,YACF,KAAK;AACH,mBAAK,mBAAmB,EAAE;AAC1B;AAAA,YACF,KAAK;AACH,mBAAK,QAAQ;AACb;AAAA,YACF,KAAK;AACH,mBAAK,QAAQ,EAAE;AACf;AAAA,YACF,KAAK;AAAA,YACL,KAAK;AACH,mBAAK,QAAQ;AACb;AAAA,UACJ;AAAA,QACF,SAAS,KAAK;AAEd,YAAI,CAAC,KAAK,SAAU,IAAG;AAAA,MACzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQA,QAAQ,IAAI;AACV,YAAI,KAAK,iBAAiB,GAAG;AAC3B,eAAK,QAAQ;AACb;AAAA,QACF;AAEA,cAAM,MAAM,KAAK,QAAQ,CAAC;AAE1B,aAAK,IAAI,CAAC,IAAI,QAAU,GAAM;AAC5B,gBAAM,QAAQ,KAAK;AAAA,YACjB;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAEA,aAAG,KAAK;AACR;AAAA,QACF;AAEA,cAAM,cAAc,IAAI,CAAC,IAAI,QAAU;AAEvC,YAAI,cAAc,CAAC,KAAK,YAAY,kBAAkB,aAAa,GAAG;AACpE,gBAAM,QAAQ,KAAK;AAAA,YACjB;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAEA,aAAG,KAAK;AACR;AAAA,QACF;AAEA,aAAK,QAAQ,IAAI,CAAC,IAAI,SAAU;AAChC,aAAK,UAAU,IAAI,CAAC,IAAI;AACxB,aAAK,iBAAiB,IAAI,CAAC,IAAI;AAE/B,YAAI,KAAK,YAAY,GAAM;AACzB,cAAI,YAAY;AACd,kBAAM,QAAQ,KAAK;AAAA,cACjB;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,YACF;AAEA,eAAG,KAAK;AACR;AAAA,UACF;AAEA,cAAI,CAAC,KAAK,aAAa;AACrB,kBAAM,QAAQ,KAAK;AAAA,cACjB;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,YACF;AAEA,eAAG,KAAK;AACR;AAAA,UACF;AAEA,eAAK,UAAU,KAAK;AAAA,QACtB,WAAW,KAAK,YAAY,KAAQ,KAAK,YAAY,GAAM;AACzD,cAAI,KAAK,aAAa;AACpB,kBAAM,QAAQ,KAAK;AAAA,cACjB;AAAA,cACA,kBAAkB,KAAK,OAAO;AAAA,cAC9B;AAAA,cACA;AAAA,cACA;AAAA,YACF;AAEA,eAAG,KAAK;AACR;AAAA,UACF;AAEA,eAAK,cAAc;AAAA,QACrB,WAAW,KAAK,UAAU,KAAQ,KAAK,UAAU,IAAM;AACrD,cAAI,CAAC,KAAK,MAAM;AACd,kBAAM,QAAQ,KAAK;AAAA,cACjB;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,YACF;AAEA,eAAG,KAAK;AACR;AAAA,UACF;AAEA,cAAI,YAAY;AACd,kBAAM,QAAQ,KAAK;AAAA,cACjB;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,YACF;AAEA,eAAG,KAAK;AACR;AAAA,UACF;AAEA,cACE,KAAK,iBAAiB,OACrB,KAAK,YAAY,KAAQ,KAAK,mBAAmB,GAClD;AACA,kBAAM,QAAQ,KAAK;AAAA,cACjB;AAAA,cACA,0BAA0B,KAAK,cAAc;AAAA,cAC7C;AAAA,cACA;AAAA,cACA;AAAA,YACF;AAEA,eAAG,KAAK;AACR;AAAA,UACF;AAAA,QACF,OAAO;AACL,gBAAM,QAAQ,KAAK;AAAA,YACjB;AAAA,YACA,kBAAkB,KAAK,OAAO;AAAA,YAC9B;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAEA,aAAG,KAAK;AACR;AAAA,QACF;AAEA,YAAI,CAAC,KAAK,QAAQ,CAAC,KAAK,YAAa,MAAK,cAAc,KAAK;AAC7D,aAAK,WAAW,IAAI,CAAC,IAAI,SAAU;AAEnC,YAAI,KAAK,WAAW;AAClB,cAAI,CAAC,KAAK,SAAS;AACjB,kBAAM,QAAQ,KAAK;AAAA,cACjB;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,YACF;AAEA,eAAG,KAAK;AACR;AAAA,UACF;AAAA,QACF,WAAW,KAAK,SAAS;AACvB,gBAAM,QAAQ,KAAK;AAAA,YACjB;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAEA,aAAG,KAAK;AACR;AAAA,QACF;AAEA,YAAI,KAAK,mBAAmB,IAAK,MAAK,SAAS;AAAA,iBACtC,KAAK,mBAAmB,IAAK,MAAK,SAAS;AAAA,YAC/C,MAAK,WAAW,EAAE;AAAA,MACzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQA,mBAAmB,IAAI;AACrB,YAAI,KAAK,iBAAiB,GAAG;AAC3B,eAAK,QAAQ;AACb;AAAA,QACF;AAEA,aAAK,iBAAiB,KAAK,QAAQ,CAAC,EAAE,aAAa,CAAC;AACpD,aAAK,WAAW,EAAE;AAAA,MACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQA,mBAAmB,IAAI;AACrB,YAAI,KAAK,iBAAiB,GAAG;AAC3B,eAAK,QAAQ;AACb;AAAA,QACF;AAEA,cAAM,MAAM,KAAK,QAAQ,CAAC;AAC1B,cAAM,MAAM,IAAI,aAAa,CAAC;AAM9B,YAAI,MAAM,KAAK,IAAI,GAAG,KAAK,EAAE,IAAI,GAAG;AAClC,gBAAM,QAAQ,KAAK;AAAA,YACjB;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAEA,aAAG,KAAK;AACR;AAAA,QACF;AAEA,aAAK,iBAAiB,MAAM,KAAK,IAAI,GAAG,EAAE,IAAI,IAAI,aAAa,CAAC;AAChE,aAAK,WAAW,EAAE;AAAA,MACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQA,WAAW,IAAI;AACb,YAAI,KAAK,kBAAkB,KAAK,UAAU,GAAM;AAC9C,eAAK,uBAAuB,KAAK;AACjC,cAAI,KAAK,sBAAsB,KAAK,eAAe,KAAK,cAAc,GAAG;AACvE,kBAAM,QAAQ,KAAK;AAAA,cACjB;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,YACF;AAEA,eAAG,KAAK;AACR;AAAA,UACF;AAAA,QACF;AAEA,YAAI,KAAK,QAAS,MAAK,SAAS;AAAA,YAC3B,MAAK,SAAS;AAAA,MACrB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAOA,UAAU;AACR,YAAI,KAAK,iBAAiB,GAAG;AAC3B,eAAK,QAAQ;AACb;AAAA,QACF;AAEA,aAAK,QAAQ,KAAK,QAAQ,CAAC;AAC3B,aAAK,SAAS;AAAA,MAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQA,QAAQ,IAAI;AACV,YAAI,OAAO;AAEX,YAAI,KAAK,gBAAgB;AACvB,cAAI,KAAK,iBAAiB,KAAK,gBAAgB;AAC7C,iBAAK,QAAQ;AACb;AAAA,UACF;AAEA,iBAAO,KAAK,QAAQ,KAAK,cAAc;AAEvC,cACE,KAAK,YACJ,KAAK,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,OAAO,GACpE;AACA,mBAAO,MAAM,KAAK,KAAK;AAAA,UACzB;AAAA,QACF;AAEA,YAAI,KAAK,UAAU,GAAM;AACvB,eAAK,eAAe,MAAM,EAAE;AAC5B;AAAA,QACF;AAEA,YAAI,KAAK,aAAa;AACpB,eAAK,SAAS;AACd,eAAK,WAAW,MAAM,EAAE;AACxB;AAAA,QACF;AAEA,YAAI,KAAK,QAAQ;AAKf,eAAK,iBAAiB,KAAK;AAC3B,eAAK,WAAW,KAAK,IAAI;AAAA,QAC3B;AAEA,aAAK,YAAY,EAAE;AAAA,MACrB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MASA,WAAW,MAAM,IAAI;AACnB,cAAM,oBAAoB,KAAK,YAAY,kBAAkB,aAAa;AAE1E,0BAAkB,WAAW,MAAM,KAAK,MAAM,CAACC,MAAK,QAAQ;AAC1D,cAAIA,KAAK,QAAO,GAAGA,IAAG;AAEtB,cAAI,IAAI,QAAQ;AACd,iBAAK,kBAAkB,IAAI;AAC3B,gBAAI,KAAK,iBAAiB,KAAK,eAAe,KAAK,cAAc,GAAG;AAClE,oBAAM,QAAQ,KAAK;AAAA,gBACjB;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA;AAAA,cACF;AAEA,iBAAG,KAAK;AACR;AAAA,YACF;AAEA,iBAAK,WAAW,KAAK,GAAG;AAAA,UAC1B;AAEA,eAAK,YAAY,EAAE;AACnB,cAAI,KAAK,WAAW,SAAU,MAAK,UAAU,EAAE;AAAA,QACjD,CAAC;AAAA,MACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQA,YAAY,IAAI;AACd,YAAI,CAAC,KAAK,MAAM;AACd,eAAK,SAAS;AACd;AAAA,QACF;AAEA,cAAM,gBAAgB,KAAK;AAC3B,cAAM,YAAY,KAAK;AAEvB,aAAK,sBAAsB;AAC3B,aAAK,iBAAiB;AACtB,aAAK,cAAc;AACnB,aAAK,aAAa,CAAC;AAEnB,YAAI,KAAK,YAAY,GAAG;AACtB,cAAI;AAEJ,cAAI,KAAK,gBAAgB,cAAc;AACrC,mBAAO,OAAO,WAAW,aAAa;AAAA,UACxC,WAAW,KAAK,gBAAgB,eAAe;AAC7C,mBAAO,cAAc,OAAO,WAAW,aAAa,CAAC;AAAA,UACvD,WAAW,KAAK,gBAAgB,QAAQ;AACtC,mBAAO,IAAI,KAAK,SAAS;AAAA,UAC3B,OAAO;AACL,mBAAO;AAAA,UACT;AAEA,cAAI,KAAK,yBAAyB;AAChC,iBAAK,KAAK,WAAW,MAAM,IAAI;AAC/B,iBAAK,SAAS;AAAA,UAChB,OAAO;AACL,iBAAK,SAAS;AACd,yBAAa,MAAM;AACjB,mBAAK,KAAK,WAAW,MAAM,IAAI;AAC/B,mBAAK,SAAS;AACd,mBAAK,UAAU,EAAE;AAAA,YACnB,CAAC;AAAA,UACH;AAAA,QACF,OAAO;AACL,gBAAM,MAAM,OAAO,WAAW,aAAa;AAE3C,cAAI,CAAC,KAAK,uBAAuB,CAAC,YAAY,GAAG,GAAG;AAClD,kBAAM,QAAQ,KAAK;AAAA,cACjB;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,YACF;AAEA,eAAG,KAAK;AACR;AAAA,UACF;AAEA,cAAI,KAAK,WAAW,aAAa,KAAK,yBAAyB;AAC7D,iBAAK,KAAK,WAAW,KAAK,KAAK;AAC/B,iBAAK,SAAS;AAAA,UAChB,OAAO;AACL,iBAAK,SAAS;AACd,yBAAa,MAAM;AACjB,mBAAK,KAAK,WAAW,KAAK,KAAK;AAC/B,mBAAK,SAAS;AACd,mBAAK,UAAU,EAAE;AAAA,YACnB,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MASA,eAAe,MAAM,IAAI;AACvB,YAAI,KAAK,YAAY,GAAM;AACzB,cAAI,KAAK,WAAW,GAAG;AACrB,iBAAK,QAAQ;AACb,iBAAK,KAAK,YAAY,MAAM,YAAY;AACxC,iBAAK,IAAI;AAAA,UACX,OAAO;AACL,kBAAM,OAAO,KAAK,aAAa,CAAC;AAEhC,gBAAI,CAAC,kBAAkB,IAAI,GAAG;AAC5B,oBAAM,QAAQ,KAAK;AAAA,gBACjB;AAAA,gBACA,uBAAuB,IAAI;AAAA,gBAC3B;AAAA,gBACA;AAAA,gBACA;AAAA,cACF;AAEA,iBAAG,KAAK;AACR;AAAA,YACF;AAEA,kBAAM,MAAM,IAAI;AAAA,cACd,KAAK;AAAA,cACL,KAAK,aAAa;AAAA,cAClB,KAAK,SAAS;AAAA,YAChB;AAEA,gBAAI,CAAC,KAAK,uBAAuB,CAAC,YAAY,GAAG,GAAG;AAClD,oBAAM,QAAQ,KAAK;AAAA,gBACjB;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA;AAAA,cACF;AAEA,iBAAG,KAAK;AACR;AAAA,YACF;AAEA,iBAAK,QAAQ;AACb,iBAAK,KAAK,YAAY,MAAM,GAAG;AAC/B,iBAAK,IAAI;AAAA,UACX;AAEA,eAAK,SAAS;AACd;AAAA,QACF;AAEA,YAAI,KAAK,yBAAyB;AAChC,eAAK,KAAK,KAAK,YAAY,IAAO,SAAS,QAAQ,IAAI;AACvD,eAAK,SAAS;AAAA,QAChB,OAAO;AACL,eAAK,SAAS;AACd,uBAAa,MAAM;AACjB,iBAAK,KAAK,KAAK,YAAY,IAAO,SAAS,QAAQ,IAAI;AACvD,iBAAK,SAAS;AACd,iBAAK,UAAU,EAAE;AAAA,UACnB,CAAC;AAAA,QACH;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAcA,YAAY,WAAW,SAAS,QAAQ,YAAY,WAAW;AAC7D,aAAK,QAAQ;AACb,aAAK,WAAW;AAEhB,cAAMA,OAAM,IAAI;AAAA,UACd,SAAS,4BAA4B,OAAO,KAAK;AAAA,QACnD;AAEA,cAAM,kBAAkBA,MAAK,KAAK,WAAW;AAC7C,QAAAA,KAAI,OAAO;AACX,QAAAA,KAAI,WAAW,IAAI;AACnB,eAAOA;AAAA,MACT;AAAA,IACF;AAEA,IAAAF,QAAO,UAAUC;AAAA;AAAA;;;ACjsBjB;AAAA,+DAAAE,UAAAC,SAAA;AAAA;AAIA,QAAM,EAAE,OAAO,IAAI,QAAQ,QAAQ;AACnC,QAAM,EAAE,eAAe,IAAI,QAAQ,QAAQ;AAE3C,QAAM,oBAAoB;AAC1B,QAAM,EAAE,cAAc,YAAY,KAAK,IAAI;AAC3C,QAAM,EAAE,QAAQ,kBAAkB,IAAI;AACtC,QAAM,EAAE,MAAM,WAAW,SAAS,IAAI;AAEtC,QAAM,cAAc,uBAAO,aAAa;AACxC,QAAM,aAAa,OAAO,MAAM,CAAC;AACjC,QAAM,mBAAmB,IAAI;AAC7B,QAAI;AACJ,QAAI,oBAAoB;AAExB,QAAM,UAAU;AAChB,QAAM,YAAY;AAClB,QAAM,gBAAgB;AAKtB,QAAMC,UAAN,MAAM,QAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MASX,YAAY,QAAQ,YAAY,cAAc;AAC5C,aAAK,cAAc,cAAc,CAAC;AAElC,YAAI,cAAc;AAChB,eAAK,gBAAgB;AACrB,eAAK,cAAc,OAAO,MAAM,CAAC;AAAA,QACnC;AAEA,aAAK,UAAU;AAEf,aAAK,iBAAiB;AACtB,aAAK,YAAY;AAEjB,aAAK,iBAAiB;AACtB,aAAK,SAAS,CAAC;AACf,aAAK,SAAS;AACd,aAAK,UAAU;AACf,aAAK,UAAU,IAAI;AAAA,MACrB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAuBA,OAAO,MAAM,MAAM,SAAS;AAC1B,YAAI;AACJ,YAAI,QAAQ;AACZ,YAAI,SAAS;AACb,YAAI,cAAc;AAElB,YAAI,QAAQ,MAAM;AAChB,iBAAO,QAAQ,cAAc;AAE7B,cAAI,QAAQ,cAAc;AACxB,oBAAQ,aAAa,IAAI;AAAA,UAC3B,OAAO;AACL,gBAAI,sBAAsB,kBAAkB;AAE1C,kBAAI,eAAe,QAAW;AAK5B,6BAAa,OAAO,MAAM,gBAAgB;AAAA,cAC5C;AAEA,6BAAe,YAAY,GAAG,gBAAgB;AAC9C,kCAAoB;AAAA,YACtB;AAEA,iBAAK,CAAC,IAAI,WAAW,mBAAmB;AACxC,iBAAK,CAAC,IAAI,WAAW,mBAAmB;AACxC,iBAAK,CAAC,IAAI,WAAW,mBAAmB;AACxC,iBAAK,CAAC,IAAI,WAAW,mBAAmB;AAAA,UAC1C;AAEA,yBAAe,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,CAAC,OAAO;AAC1D,mBAAS;AAAA,QACX;AAEA,YAAI;AAEJ,YAAI,OAAO,SAAS,UAAU;AAC5B,eACG,CAAC,QAAQ,QAAQ,gBAClB,QAAQ,WAAW,MAAM,QACzB;AACA,yBAAa,QAAQ,WAAW;AAAA,UAClC,OAAO;AACL,mBAAO,OAAO,KAAK,IAAI;AACvB,yBAAa,KAAK;AAAA,UACpB;AAAA,QACF,OAAO;AACL,uBAAa,KAAK;AAClB,kBAAQ,QAAQ,QAAQ,QAAQ,YAAY,CAAC;AAAA,QAC/C;AAEA,YAAI,gBAAgB;AAEpB,YAAI,cAAc,OAAO;AACvB,oBAAU;AACV,0BAAgB;AAAA,QAClB,WAAW,aAAa,KAAK;AAC3B,oBAAU;AACV,0BAAgB;AAAA,QAClB;AAEA,cAAM,SAAS,OAAO,YAAY,QAAQ,aAAa,SAAS,MAAM;AAEtE,eAAO,CAAC,IAAI,QAAQ,MAAM,QAAQ,SAAS,MAAO,QAAQ;AAC1D,YAAI,QAAQ,KAAM,QAAO,CAAC,KAAK;AAE/B,eAAO,CAAC,IAAI;AAEZ,YAAI,kBAAkB,KAAK;AACzB,iBAAO,cAAc,YAAY,CAAC;AAAA,QACpC,WAAW,kBAAkB,KAAK;AAChC,iBAAO,CAAC,IAAI,OAAO,CAAC,IAAI;AACxB,iBAAO,YAAY,YAAY,GAAG,CAAC;AAAA,QACrC;AAEA,YAAI,CAAC,QAAQ,KAAM,QAAO,CAAC,QAAQ,IAAI;AAEvC,eAAO,CAAC,KAAK;AACb,eAAO,SAAS,CAAC,IAAI,KAAK,CAAC;AAC3B,eAAO,SAAS,CAAC,IAAI,KAAK,CAAC;AAC3B,eAAO,SAAS,CAAC,IAAI,KAAK,CAAC;AAC3B,eAAO,SAAS,CAAC,IAAI,KAAK,CAAC;AAE3B,YAAI,YAAa,QAAO,CAAC,QAAQ,IAAI;AAErC,YAAI,OAAO;AACT,oBAAU,MAAM,MAAM,QAAQ,QAAQ,UAAU;AAChD,iBAAO,CAAC,MAAM;AAAA,QAChB;AAEA,kBAAU,MAAM,MAAM,MAAM,GAAG,UAAU;AACzC,eAAO,CAAC,QAAQ,IAAI;AAAA,MACtB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAWA,MAAM,MAAM,MAAM,MAAM,IAAI;AAC1B,YAAI;AAEJ,YAAI,SAAS,QAAW;AACtB,gBAAM;AAAA,QACR,WAAW,OAAO,SAAS,YAAY,CAAC,kBAAkB,IAAI,GAAG;AAC/D,gBAAM,IAAI,UAAU,kDAAkD;AAAA,QACxE,WAAW,SAAS,UAAa,CAAC,KAAK,QAAQ;AAC7C,gBAAM,OAAO,YAAY,CAAC;AAC1B,cAAI,cAAc,MAAM,CAAC;AAAA,QAC3B,OAAO;AACL,gBAAM,SAAS,OAAO,WAAW,IAAI;AAErC,cAAI,SAAS,KAAK;AAChB,kBAAM,IAAI,WAAW,gDAAgD;AAAA,UACvE;AAEA,gBAAM,OAAO,YAAY,IAAI,MAAM;AACnC,cAAI,cAAc,MAAM,CAAC;AAEzB,cAAI,OAAO,SAAS,UAAU;AAC5B,gBAAI,MAAM,MAAM,CAAC;AAAA,UACnB,OAAO;AACL,gBAAI,IAAI,MAAM,CAAC;AAAA,UACjB;AAAA,QACF;AAEA,cAAM,UAAU;AAAA,UACd,CAAC,WAAW,GAAG,IAAI;AAAA,UACnB,KAAK;AAAA,UACL,cAAc,KAAK;AAAA,UACnB;AAAA,UACA,YAAY,KAAK;AAAA,UACjB,QAAQ;AAAA,UACR,UAAU;AAAA,UACV,MAAM;AAAA,QACR;AAEA,YAAI,KAAK,WAAW,SAAS;AAC3B,eAAK,QAAQ,CAAC,KAAK,UAAU,KAAK,OAAO,SAAS,EAAE,CAAC;AAAA,QACvD,OAAO;AACL,eAAK,UAAU,QAAO,MAAM,KAAK,OAAO,GAAG,EAAE;AAAA,QAC/C;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAUA,KAAK,MAAM,MAAM,IAAI;AACnB,YAAI;AACJ,YAAI;AAEJ,YAAI,OAAO,SAAS,UAAU;AAC5B,uBAAa,OAAO,WAAW,IAAI;AACnC,qBAAW;AAAA,QACb,WAAW,OAAO,IAAI,GAAG;AACvB,uBAAa,KAAK;AAClB,qBAAW;AAAA,QACb,OAAO;AACL,iBAAO,SAAS,IAAI;AACpB,uBAAa,KAAK;AAClB,qBAAW,SAAS;AAAA,QACtB;AAEA,YAAI,aAAa,KAAK;AACpB,gBAAM,IAAI,WAAW,kDAAkD;AAAA,QACzE;AAEA,cAAM,UAAU;AAAA,UACd,CAAC,WAAW,GAAG;AAAA,UACf,KAAK;AAAA,UACL,cAAc,KAAK;AAAA,UACnB;AAAA,UACA,YAAY,KAAK;AAAA,UACjB,QAAQ;AAAA,UACR;AAAA,UACA,MAAM;AAAA,QACR;AAEA,YAAI,OAAO,IAAI,GAAG;AAChB,cAAI,KAAK,WAAW,SAAS;AAC3B,iBAAK,QAAQ,CAAC,KAAK,aAAa,MAAM,OAAO,SAAS,EAAE,CAAC;AAAA,UAC3D,OAAO;AACL,iBAAK,YAAY,MAAM,OAAO,SAAS,EAAE;AAAA,UAC3C;AAAA,QACF,WAAW,KAAK,WAAW,SAAS;AAClC,eAAK,QAAQ,CAAC,KAAK,UAAU,MAAM,OAAO,SAAS,EAAE,CAAC;AAAA,QACxD,OAAO;AACL,eAAK,UAAU,QAAO,MAAM,MAAM,OAAO,GAAG,EAAE;AAAA,QAChD;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAUA,KAAK,MAAM,MAAM,IAAI;AACnB,YAAI;AACJ,YAAI;AAEJ,YAAI,OAAO,SAAS,UAAU;AAC5B,uBAAa,OAAO,WAAW,IAAI;AACnC,qBAAW;AAAA,QACb,WAAW,OAAO,IAAI,GAAG;AACvB,uBAAa,KAAK;AAClB,qBAAW;AAAA,QACb,OAAO;AACL,iBAAO,SAAS,IAAI;AACpB,uBAAa,KAAK;AAClB,qBAAW,SAAS;AAAA,QACtB;AAEA,YAAI,aAAa,KAAK;AACpB,gBAAM,IAAI,WAAW,kDAAkD;AAAA,QACzE;AAEA,cAAM,UAAU;AAAA,UACd,CAAC,WAAW,GAAG;AAAA,UACf,KAAK;AAAA,UACL,cAAc,KAAK;AAAA,UACnB;AAAA,UACA,YAAY,KAAK;AAAA,UACjB,QAAQ;AAAA,UACR;AAAA,UACA,MAAM;AAAA,QACR;AAEA,YAAI,OAAO,IAAI,GAAG;AAChB,cAAI,KAAK,WAAW,SAAS;AAC3B,iBAAK,QAAQ,CAAC,KAAK,aAAa,MAAM,OAAO,SAAS,EAAE,CAAC;AAAA,UAC3D,OAAO;AACL,iBAAK,YAAY,MAAM,OAAO,SAAS,EAAE;AAAA,UAC3C;AAAA,QACF,WAAW,KAAK,WAAW,SAAS;AAClC,eAAK,QAAQ,CAAC,KAAK,UAAU,MAAM,OAAO,SAAS,EAAE,CAAC;AAAA,QACxD,OAAO;AACL,eAAK,UAAU,QAAO,MAAM,MAAM,OAAO,GAAG,EAAE;AAAA,QAChD;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAkBA,KAAK,MAAM,SAAS,IAAI;AACtB,cAAM,oBAAoB,KAAK,YAAY,kBAAkB,aAAa;AAC1E,YAAI,SAAS,QAAQ,SAAS,IAAI;AAClC,YAAI,OAAO,QAAQ;AAEnB,YAAI;AACJ,YAAI;AAEJ,YAAI,OAAO,SAAS,UAAU;AAC5B,uBAAa,OAAO,WAAW,IAAI;AACnC,qBAAW;AAAA,QACb,WAAW,OAAO,IAAI,GAAG;AACvB,uBAAa,KAAK;AAClB,qBAAW;AAAA,QACb,OAAO;AACL,iBAAO,SAAS,IAAI;AACpB,uBAAa,KAAK;AAClB,qBAAW,SAAS;AAAA,QACtB;AAEA,YAAI,KAAK,gBAAgB;AACvB,eAAK,iBAAiB;AACtB,cACE,QACA,qBACA,kBAAkB,OAChB,kBAAkB,YACd,+BACA,4BACN,GACA;AACA,mBAAO,cAAc,kBAAkB;AAAA,UACzC;AACA,eAAK,YAAY;AAAA,QACnB,OAAO;AACL,iBAAO;AACP,mBAAS;AAAA,QACX;AAEA,YAAI,QAAQ,IAAK,MAAK,iBAAiB;AAEvC,cAAM,OAAO;AAAA,UACX,CAAC,WAAW,GAAG;AAAA,UACf,KAAK,QAAQ;AAAA,UACb,cAAc,KAAK;AAAA,UACnB,MAAM,QAAQ;AAAA,UACd,YAAY,KAAK;AAAA,UACjB;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAEA,YAAI,OAAO,IAAI,GAAG;AAChB,cAAI,KAAK,WAAW,SAAS;AAC3B,iBAAK,QAAQ,CAAC,KAAK,aAAa,MAAM,KAAK,WAAW,MAAM,EAAE,CAAC;AAAA,UACjE,OAAO;AACL,iBAAK,YAAY,MAAM,KAAK,WAAW,MAAM,EAAE;AAAA,UACjD;AAAA,QACF,WAAW,KAAK,WAAW,SAAS;AAClC,eAAK,QAAQ,CAAC,KAAK,UAAU,MAAM,KAAK,WAAW,MAAM,EAAE,CAAC;AAAA,QAC9D,OAAO;AACL,eAAK,SAAS,MAAM,KAAK,WAAW,MAAM,EAAE;AAAA,QAC9C;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAyBA,YAAY,MAAM,UAAU,SAAS,IAAI;AACvC,aAAK,kBAAkB,QAAQ,WAAW;AAC1C,aAAK,SAAS;AAEd,aACG,YAAY,EACZ,KAAK,CAAC,gBAAgB;AACrB,cAAI,KAAK,QAAQ,WAAW;AAC1B,kBAAMC,OAAM,IAAI;AAAA,cACd;AAAA,YACF;AAOA,oBAAQ,SAAS,eAAe,MAAMA,MAAK,EAAE;AAC7C;AAAA,UACF;AAEA,eAAK,kBAAkB,QAAQ,WAAW;AAC1C,gBAAM,OAAO,SAAS,WAAW;AAEjC,cAAI,CAAC,UAAU;AACb,iBAAK,SAAS;AACd,iBAAK,UAAU,QAAO,MAAM,MAAM,OAAO,GAAG,EAAE;AAC9C,iBAAK,QAAQ;AAAA,UACf,OAAO;AACL,iBAAK,SAAS,MAAM,UAAU,SAAS,EAAE;AAAA,UAC3C;AAAA,QACF,CAAC,EACA,MAAM,CAACA,SAAQ;AAKd,kBAAQ,SAAS,SAAS,MAAMA,MAAK,EAAE;AAAA,QACzC,CAAC;AAAA,MACL;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAyBA,SAAS,MAAM,UAAU,SAAS,IAAI;AACpC,YAAI,CAAC,UAAU;AACb,eAAK,UAAU,QAAO,MAAM,MAAM,OAAO,GAAG,EAAE;AAC9C;AAAA,QACF;AAEA,cAAM,oBAAoB,KAAK,YAAY,kBAAkB,aAAa;AAE1E,aAAK,kBAAkB,QAAQ,WAAW;AAC1C,aAAK,SAAS;AACd,0BAAkB,SAAS,MAAM,QAAQ,KAAK,CAAC,GAAG,QAAQ;AACxD,cAAI,KAAK,QAAQ,WAAW;AAC1B,kBAAMA,OAAM,IAAI;AAAA,cACd;AAAA,YACF;AAEA,0BAAc,MAAMA,MAAK,EAAE;AAC3B;AAAA,UACF;AAEA,eAAK,kBAAkB,QAAQ,WAAW;AAC1C,eAAK,SAAS;AACd,kBAAQ,WAAW;AACnB,eAAK,UAAU,QAAO,MAAM,KAAK,OAAO,GAAG,EAAE;AAC7C,eAAK,QAAQ;AAAA,QACf,CAAC;AAAA,MACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAOA,UAAU;AACR,eAAO,KAAK,WAAW,WAAW,KAAK,OAAO,QAAQ;AACpD,gBAAM,SAAS,KAAK,OAAO,MAAM;AAEjC,eAAK,kBAAkB,OAAO,CAAC,EAAE,WAAW;AAC5C,kBAAQ,MAAM,OAAO,CAAC,GAAG,MAAM,OAAO,MAAM,CAAC,CAAC;AAAA,QAChD;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQA,QAAQ,QAAQ;AACd,aAAK,kBAAkB,OAAO,CAAC,EAAE,WAAW;AAC5C,aAAK,OAAO,KAAK,MAAM;AAAA,MACzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MASA,UAAU,MAAM,IAAI;AAClB,YAAI,KAAK,WAAW,GAAG;AACrB,eAAK,QAAQ,KAAK;AAClB,eAAK,QAAQ,MAAM,KAAK,CAAC,CAAC;AAC1B,eAAK,QAAQ,MAAM,KAAK,CAAC,GAAG,EAAE;AAC9B,eAAK,QAAQ,OAAO;AAAA,QACtB,OAAO;AACL,eAAK,QAAQ,MAAM,KAAK,CAAC,GAAG,EAAE;AAAA,QAChC;AAAA,MACF;AAAA,IACF;AAEA,IAAAF,QAAO,UAAUC;AAUjB,aAAS,cAAc,QAAQC,MAAK,IAAI;AACtC,UAAI,OAAO,OAAO,WAAY,IAAGA,IAAG;AAEpC,eAAS,IAAI,GAAG,IAAI,OAAO,OAAO,QAAQ,KAAK;AAC7C,cAAM,SAAS,OAAO,OAAO,CAAC;AAC9B,cAAM,WAAW,OAAO,OAAO,SAAS,CAAC;AAEzC,YAAI,OAAO,aAAa,WAAY,UAASA,IAAG;AAAA,MAClD;AAAA,IACF;AAUA,aAAS,QAAQ,QAAQA,MAAK,IAAI;AAChC,oBAAc,QAAQA,MAAK,EAAE;AAC7B,aAAO,QAAQA,IAAG;AAAA,IACpB;AAAA;AAAA;;;ACzlBA;AAAA,qEAAAC,UAAAC,SAAA;AAAA;AAEA,QAAM,EAAE,sBAAsB,UAAU,IAAI;AAE5C,QAAM,QAAQ,uBAAO,OAAO;AAC5B,QAAM,QAAQ,uBAAO,OAAO;AAC5B,QAAM,SAAS,uBAAO,QAAQ;AAC9B,QAAM,WAAW,uBAAO,UAAU;AAClC,QAAM,UAAU,uBAAO,SAAS;AAChC,QAAM,UAAU,uBAAO,SAAS;AAChC,QAAM,QAAQ,uBAAO,OAAO;AAC5B,QAAM,YAAY,uBAAO,WAAW;AAKpC,QAAM,QAAN,MAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAOV,YAAY,MAAM;AAChB,aAAK,OAAO,IAAI;AAChB,aAAK,KAAK,IAAI;AAAA,MAChB;AAAA;AAAA;AAAA;AAAA,MAKA,IAAI,SAAS;AACX,eAAO,KAAK,OAAO;AAAA,MACrB;AAAA;AAAA;AAAA;AAAA,MAKA,IAAI,OAAO;AACT,eAAO,KAAK,KAAK;AAAA,MACnB;AAAA,IACF;AAEA,WAAO,eAAe,MAAM,WAAW,UAAU,EAAE,YAAY,KAAK,CAAC;AACrE,WAAO,eAAe,MAAM,WAAW,QAAQ,EAAE,YAAY,KAAK,CAAC;AAOnE,QAAM,aAAN,cAAyB,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAc7B,YAAY,MAAM,UAAU,CAAC,GAAG;AAC9B,cAAM,IAAI;AAEV,aAAK,KAAK,IAAI,QAAQ,SAAS,SAAY,IAAI,QAAQ;AACvD,aAAK,OAAO,IAAI,QAAQ,WAAW,SAAY,KAAK,QAAQ;AAC5D,aAAK,SAAS,IAAI,QAAQ,aAAa,SAAY,QAAQ,QAAQ;AAAA,MACrE;AAAA;AAAA;AAAA;AAAA,MAKA,IAAI,OAAO;AACT,eAAO,KAAK,KAAK;AAAA,MACnB;AAAA;AAAA;AAAA;AAAA,MAKA,IAAI,SAAS;AACX,eAAO,KAAK,OAAO;AAAA,MACrB;AAAA;AAAA;AAAA;AAAA,MAKA,IAAI,WAAW;AACb,eAAO,KAAK,SAAS;AAAA,MACvB;AAAA,IACF;AAEA,WAAO,eAAe,WAAW,WAAW,QAAQ,EAAE,YAAY,KAAK,CAAC;AACxE,WAAO,eAAe,WAAW,WAAW,UAAU,EAAE,YAAY,KAAK,CAAC;AAC1E,WAAO,eAAe,WAAW,WAAW,YAAY,EAAE,YAAY,KAAK,CAAC;AAO5E,QAAM,aAAN,cAAyB,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAU7B,YAAY,MAAM,UAAU,CAAC,GAAG;AAC9B,cAAM,IAAI;AAEV,aAAK,MAAM,IAAI,QAAQ,UAAU,SAAY,OAAO,QAAQ;AAC5D,aAAK,QAAQ,IAAI,QAAQ,YAAY,SAAY,KAAK,QAAQ;AAAA,MAChE;AAAA;AAAA;AAAA;AAAA,MAKA,IAAI,QAAQ;AACV,eAAO,KAAK,MAAM;AAAA,MACpB;AAAA;AAAA;AAAA;AAAA,MAKA,IAAI,UAAU;AACZ,eAAO,KAAK,QAAQ;AAAA,MACtB;AAAA,IACF;AAEA,WAAO,eAAe,WAAW,WAAW,SAAS,EAAE,YAAY,KAAK,CAAC;AACzE,WAAO,eAAe,WAAW,WAAW,WAAW,EAAE,YAAY,KAAK,CAAC;AAO3E,QAAM,eAAN,cAA2B,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAS/B,YAAY,MAAM,UAAU,CAAC,GAAG;AAC9B,cAAM,IAAI;AAEV,aAAK,KAAK,IAAI,QAAQ,SAAS,SAAY,OAAO,QAAQ;AAAA,MAC5D;AAAA;AAAA;AAAA;AAAA,MAKA,IAAI,OAAO;AACT,eAAO,KAAK,KAAK;AAAA,MACnB;AAAA,IACF;AAEA,WAAO,eAAe,aAAa,WAAW,QAAQ,EAAE,YAAY,KAAK,CAAC;AAQ1E,QAAM,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAalB,iBAAiB,MAAM,SAAS,UAAU,CAAC,GAAG;AAC5C,mBAAW,YAAY,KAAK,UAAU,IAAI,GAAG;AAC3C,cACE,CAAC,QAAQ,oBAAoB,KAC7B,SAAS,SAAS,MAAM,WACxB,CAAC,SAAS,oBAAoB,GAC9B;AACA;AAAA,UACF;AAAA,QACF;AAEA,YAAI;AAEJ,YAAI,SAAS,WAAW;AACtB,oBAAU,SAAS,UAAU,MAAM,UAAU;AAC3C,kBAAM,QAAQ,IAAI,aAAa,WAAW;AAAA,cACxC,MAAM,WAAW,OAAO,KAAK,SAAS;AAAA,YACxC,CAAC;AAED,kBAAM,OAAO,IAAI;AACjB,yBAAa,SAAS,MAAM,KAAK;AAAA,UACnC;AAAA,QACF,WAAW,SAAS,SAAS;AAC3B,oBAAU,SAAS,QAAQ,MAAM,SAAS;AACxC,kBAAM,QAAQ,IAAI,WAAW,SAAS;AAAA,cACpC;AAAA,cACA,QAAQ,QAAQ,SAAS;AAAA,cACzB,UAAU,KAAK,uBAAuB,KAAK;AAAA,YAC7C,CAAC;AAED,kBAAM,OAAO,IAAI;AACjB,yBAAa,SAAS,MAAM,KAAK;AAAA,UACnC;AAAA,QACF,WAAW,SAAS,SAAS;AAC3B,oBAAU,SAAS,QAAQ,OAAO;AAChC,kBAAM,QAAQ,IAAI,WAAW,SAAS;AAAA,cACpC;AAAA,cACA,SAAS,MAAM;AAAA,YACjB,CAAC;AAED,kBAAM,OAAO,IAAI;AACjB,yBAAa,SAAS,MAAM,KAAK;AAAA,UACnC;AAAA,QACF,WAAW,SAAS,QAAQ;AAC1B,oBAAU,SAAS,SAAS;AAC1B,kBAAM,QAAQ,IAAI,MAAM,MAAM;AAE9B,kBAAM,OAAO,IAAI;AACjB,yBAAa,SAAS,MAAM,KAAK;AAAA,UACnC;AAAA,QACF,OAAO;AACL;AAAA,QACF;AAEA,gBAAQ,oBAAoB,IAAI,CAAC,CAAC,QAAQ,oBAAoB;AAC9D,gBAAQ,SAAS,IAAI;AAErB,YAAI,QAAQ,MAAM;AAChB,eAAK,KAAK,MAAM,OAAO;AAAA,QACzB,OAAO;AACL,eAAK,GAAG,MAAM,OAAO;AAAA,QACvB;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MASA,oBAAoB,MAAM,SAAS;AACjC,mBAAW,YAAY,KAAK,UAAU,IAAI,GAAG;AAC3C,cAAI,SAAS,SAAS,MAAM,WAAW,CAAC,SAAS,oBAAoB,GAAG;AACtE,iBAAK,eAAe,MAAM,QAAQ;AAClC;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,IAAAA,QAAO,UAAU;AAAA,MACf;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAUA,aAAS,aAAa,UAAU,SAAS,OAAO;AAC9C,UAAI,OAAO,aAAa,YAAY,SAAS,aAAa;AACxD,iBAAS,YAAY,KAAK,UAAU,KAAK;AAAA,MAC3C,OAAO;AACL,iBAAS,KAAK,SAAS,KAAK;AAAA,MAC9B;AAAA,IACF;AAAA;AAAA;;;ACnSA;AAAA,kEAAAC,UAAAC,SAAA;AAAA;AAEA,QAAM,EAAE,WAAW,IAAI;AAYvB,aAAS,KAAK,MAAM,MAAM,MAAM;AAC9B,UAAI,KAAK,IAAI,MAAM,OAAW,MAAK,IAAI,IAAI,CAAC,IAAI;AAAA,UAC3C,MAAK,IAAI,EAAE,KAAK,IAAI;AAAA,IAC3B;AASA,aAAS,MAAM,QAAQ;AACrB,YAAM,SAAS,uBAAO,OAAO,IAAI;AACjC,UAAI,SAAS,uBAAO,OAAO,IAAI;AAC/B,UAAI,eAAe;AACnB,UAAI,aAAa;AACjB,UAAI,WAAW;AACf,UAAI;AACJ,UAAI;AACJ,UAAI,QAAQ;AACZ,UAAI,OAAO;AACX,UAAI,MAAM;AACV,UAAI,IAAI;AAER,aAAO,IAAI,OAAO,QAAQ,KAAK;AAC7B,eAAO,OAAO,WAAW,CAAC;AAE1B,YAAI,kBAAkB,QAAW;AAC/B,cAAI,QAAQ,MAAM,WAAW,IAAI,MAAM,GAAG;AACxC,gBAAI,UAAU,GAAI,SAAQ;AAAA,UAC5B,WACE,MAAM,MACL,SAAS,MAAkB,SAAS,IACrC;AACA,gBAAI,QAAQ,MAAM,UAAU,GAAI,OAAM;AAAA,UACxC,WAAW,SAAS,MAAkB,SAAS,IAAgB;AAC7D,gBAAI,UAAU,IAAI;AAChB,oBAAM,IAAI,YAAY,iCAAiC,CAAC,EAAE;AAAA,YAC5D;AAEA,gBAAI,QAAQ,GAAI,OAAM;AACtB,kBAAM,OAAO,OAAO,MAAM,OAAO,GAAG;AACpC,gBAAI,SAAS,IAAM;AACjB,mBAAK,QAAQ,MAAM,MAAM;AACzB,uBAAS,uBAAO,OAAO,IAAI;AAAA,YAC7B,OAAO;AACL,8BAAgB;AAAA,YAClB;AAEA,oBAAQ,MAAM;AAAA,UAChB,OAAO;AACL,kBAAM,IAAI,YAAY,iCAAiC,CAAC,EAAE;AAAA,UAC5D;AAAA,QACF,WAAW,cAAc,QAAW;AAClC,cAAI,QAAQ,MAAM,WAAW,IAAI,MAAM,GAAG;AACxC,gBAAI,UAAU,GAAI,SAAQ;AAAA,UAC5B,WAAW,SAAS,MAAQ,SAAS,GAAM;AACzC,gBAAI,QAAQ,MAAM,UAAU,GAAI,OAAM;AAAA,UACxC,WAAW,SAAS,MAAQ,SAAS,IAAM;AACzC,gBAAI,UAAU,IAAI;AAChB,oBAAM,IAAI,YAAY,iCAAiC,CAAC,EAAE;AAAA,YAC5D;AAEA,gBAAI,QAAQ,GAAI,OAAM;AACtB,iBAAK,QAAQ,OAAO,MAAM,OAAO,GAAG,GAAG,IAAI;AAC3C,gBAAI,SAAS,IAAM;AACjB,mBAAK,QAAQ,eAAe,MAAM;AAClC,uBAAS,uBAAO,OAAO,IAAI;AAC3B,8BAAgB;AAAA,YAClB;AAEA,oBAAQ,MAAM;AAAA,UAChB,WAAW,SAAS,MAAkB,UAAU,MAAM,QAAQ,IAAI;AAChE,wBAAY,OAAO,MAAM,OAAO,CAAC;AACjC,oBAAQ,MAAM;AAAA,UAChB,OAAO;AACL,kBAAM,IAAI,YAAY,iCAAiC,CAAC,EAAE;AAAA,UAC5D;AAAA,QACF,OAAO;AAML,cAAI,YAAY;AACd,gBAAI,WAAW,IAAI,MAAM,GAAG;AAC1B,oBAAM,IAAI,YAAY,iCAAiC,CAAC,EAAE;AAAA,YAC5D;AACA,gBAAI,UAAU,GAAI,SAAQ;AAAA,qBACjB,CAAC,aAAc,gBAAe;AACvC,yBAAa;AAAA,UACf,WAAW,UAAU;AACnB,gBAAI,WAAW,IAAI,MAAM,GAAG;AAC1B,kBAAI,UAAU,GAAI,SAAQ;AAAA,YAC5B,WAAW,SAAS,MAAkB,UAAU,IAAI;AAClD,yBAAW;AACX,oBAAM;AAAA,YACR,WAAW,SAAS,IAAgB;AAClC,2BAAa;AAAA,YACf,OAAO;AACL,oBAAM,IAAI,YAAY,iCAAiC,CAAC,EAAE;AAAA,YAC5D;AAAA,UACF,WAAW,SAAS,MAAQ,OAAO,WAAW,IAAI,CAAC,MAAM,IAAM;AAC7D,uBAAW;AAAA,UACb,WAAW,QAAQ,MAAM,WAAW,IAAI,MAAM,GAAG;AAC/C,gBAAI,UAAU,GAAI,SAAQ;AAAA,UAC5B,WAAW,UAAU,OAAO,SAAS,MAAQ,SAAS,IAAO;AAC3D,gBAAI,QAAQ,GAAI,OAAM;AAAA,UACxB,WAAW,SAAS,MAAQ,SAAS,IAAM;AACzC,gBAAI,UAAU,IAAI;AAChB,oBAAM,IAAI,YAAY,iCAAiC,CAAC,EAAE;AAAA,YAC5D;AAEA,gBAAI,QAAQ,GAAI,OAAM;AACtB,gBAAI,QAAQ,OAAO,MAAM,OAAO,GAAG;AACnC,gBAAI,cAAc;AAChB,sBAAQ,MAAM,QAAQ,OAAO,EAAE;AAC/B,6BAAe;AAAA,YACjB;AACA,iBAAK,QAAQ,WAAW,KAAK;AAC7B,gBAAI,SAAS,IAAM;AACjB,mBAAK,QAAQ,eAAe,MAAM;AAClC,uBAAS,uBAAO,OAAO,IAAI;AAC3B,8BAAgB;AAAA,YAClB;AAEA,wBAAY;AACZ,oBAAQ,MAAM;AAAA,UAChB,OAAO;AACL,kBAAM,IAAI,YAAY,iCAAiC,CAAC,EAAE;AAAA,UAC5D;AAAA,QACF;AAAA,MACF;AAEA,UAAI,UAAU,MAAM,YAAY,SAAS,MAAQ,SAAS,GAAM;AAC9D,cAAM,IAAI,YAAY,yBAAyB;AAAA,MACjD;AAEA,UAAI,QAAQ,GAAI,OAAM;AACtB,YAAM,QAAQ,OAAO,MAAM,OAAO,GAAG;AACrC,UAAI,kBAAkB,QAAW;AAC/B,aAAK,QAAQ,OAAO,MAAM;AAAA,MAC5B,OAAO;AACL,YAAI,cAAc,QAAW;AAC3B,eAAK,QAAQ,OAAO,IAAI;AAAA,QAC1B,WAAW,cAAc;AACvB,eAAK,QAAQ,WAAW,MAAM,QAAQ,OAAO,EAAE,CAAC;AAAA,QAClD,OAAO;AACL,eAAK,QAAQ,WAAW,KAAK;AAAA,QAC/B;AACA,aAAK,QAAQ,eAAe,MAAM;AAAA,MACpC;AAEA,aAAO;AAAA,IACT;AASA,aAAS,OAAO,YAAY;AAC1B,aAAO,OAAO,KAAK,UAAU,EAC1B,IAAI,CAAC,cAAc;AAClB,YAAI,iBAAiB,WAAW,SAAS;AACzC,YAAI,CAAC,MAAM,QAAQ,cAAc,EAAG,kBAAiB,CAAC,cAAc;AACpE,eAAO,eACJ,IAAI,CAAC,WAAW;AACf,iBAAO,CAAC,SAAS,EACd;AAAA,YACC,OAAO,KAAK,MAAM,EAAE,IAAI,CAAC,MAAM;AAC7B,kBAAI,SAAS,OAAO,CAAC;AACrB,kBAAI,CAAC,MAAM,QAAQ,MAAM,EAAG,UAAS,CAAC,MAAM;AAC5C,qBAAO,OACJ,IAAI,CAAC,MAAO,MAAM,OAAO,IAAI,GAAG,CAAC,IAAI,CAAC,EAAG,EACzC,KAAK,IAAI;AAAA,YACd,CAAC;AAAA,UACH,EACC,KAAK,IAAI;AAAA,QACd,CAAC,EACA,KAAK,IAAI;AAAA,MACd,CAAC,EACA,KAAK,IAAI;AAAA,IACd;AAEA,IAAAA,QAAO,UAAU,EAAE,QAAQ,MAAM;AAAA;AAAA;;;AC1MjC;AAAA,kEAAAC,UAAAC,SAAA;AAAA;AAIA,QAAM,eAAe,QAAQ,QAAQ;AACrC,QAAM,QAAQ,QAAQ,OAAO;AAC7B,QAAM,OAAO,QAAQ,MAAM;AAC3B,QAAM,MAAM,QAAQ,KAAK;AACzB,QAAM,MAAM,QAAQ,KAAK;AACzB,QAAM,EAAE,aAAAC,cAAa,YAAAC,YAAW,IAAI,QAAQ,QAAQ;AACpD,QAAM,EAAE,QAAQ,UAAAC,UAAS,IAAI,QAAQ,QAAQ;AAC7C,QAAM,EAAE,KAAAC,KAAI,IAAI,QAAQ,KAAK;AAE7B,QAAM,oBAAoB;AAC1B,QAAMC,YAAW;AACjB,QAAMC,UAAS;AACf,QAAM,EAAE,OAAO,IAAI;AAEnB,QAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,IAAI;AACJ,QAAM;AAAA,MACJ,aAAa,EAAE,kBAAkB,oBAAoB;AAAA,IACvD,IAAI;AACJ,QAAM,EAAE,QAAQ,MAAM,IAAI;AAC1B,QAAM,EAAE,SAAS,IAAI;AAErB,QAAM,WAAW,uBAAO,UAAU;AAClC,QAAM,mBAAmB,CAAC,GAAG,EAAE;AAC/B,QAAM,cAAc,CAAC,cAAc,QAAQ,WAAW,QAAQ;AAC9D,QAAM,mBAAmB;AAOzB,QAAMC,aAAN,MAAM,mBAAkB,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQnC,YAAY,SAAS,WAAW,SAAS;AACvC,cAAM;AAEN,aAAK,cAAc,aAAa,CAAC;AACjC,aAAK,aAAa;AAClB,aAAK,sBAAsB;AAC3B,aAAK,kBAAkB;AACvB,aAAK,gBAAgB;AACrB,aAAK,cAAc;AACnB,aAAK,gBAAgB;AACrB,aAAK,cAAc,CAAC;AACpB,aAAK,UAAU;AACf,aAAK,YAAY;AACjB,aAAK,cAAc,WAAU;AAC7B,aAAK,YAAY;AACjB,aAAK,UAAU;AACf,aAAK,UAAU;AAEf,YAAI,YAAY,MAAM;AACpB,eAAK,kBAAkB;AACvB,eAAK,YAAY;AACjB,eAAK,aAAa;AAElB,cAAI,cAAc,QAAW;AAC3B,wBAAY,CAAC;AAAA,UACf,WAAW,CAAC,MAAM,QAAQ,SAAS,GAAG;AACpC,gBAAI,OAAO,cAAc,YAAY,cAAc,MAAM;AACvD,wBAAU;AACV,0BAAY,CAAC;AAAA,YACf,OAAO;AACL,0BAAY,CAAC,SAAS;AAAA,YACxB;AAAA,UACF;AAEA,uBAAa,MAAM,SAAS,WAAW,OAAO;AAAA,QAChD,OAAO;AACL,eAAK,YAAY,QAAQ;AACzB,eAAK,gBAAgB,QAAQ;AAC7B,eAAK,YAAY;AAAA,QACnB;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQA,IAAI,aAAa;AACf,eAAO,KAAK;AAAA,MACd;AAAA,MAEA,IAAI,WAAW,MAAM;AACnB,YAAI,CAAC,aAAa,SAAS,IAAI,EAAG;AAElC,aAAK,cAAc;AAKnB,YAAI,KAAK,UAAW,MAAK,UAAU,cAAc;AAAA,MACnD;AAAA;AAAA;AAAA;AAAA,MAKA,IAAI,iBAAiB;AACnB,YAAI,CAAC,KAAK,QAAS,QAAO,KAAK;AAE/B,eAAO,KAAK,QAAQ,eAAe,SAAS,KAAK,QAAQ;AAAA,MAC3D;AAAA;AAAA;AAAA;AAAA,MAKA,IAAI,aAAa;AACf,eAAO,OAAO,KAAK,KAAK,WAAW,EAAE,KAAK;AAAA,MAC5C;AAAA;AAAA;AAAA;AAAA,MAKA,IAAI,WAAW;AACb,eAAO,KAAK;AAAA,MACd;AAAA;AAAA;AAAA;AAAA;AAAA,MAMA,IAAI,UAAU;AACZ,eAAO;AAAA,MACT;AAAA;AAAA;AAAA;AAAA;AAAA,MAMA,IAAI,UAAU;AACZ,eAAO;AAAA,MACT;AAAA;AAAA;AAAA;AAAA;AAAA,MAMA,IAAI,SAAS;AACX,eAAO;AAAA,MACT;AAAA;AAAA;AAAA;AAAA;AAAA,MAMA,IAAI,YAAY;AACd,eAAO;AAAA,MACT;AAAA;AAAA;AAAA;AAAA,MAKA,IAAI,WAAW;AACb,eAAO,KAAK;AAAA,MACd;AAAA;AAAA;AAAA;AAAA,MAKA,IAAI,aAAa;AACf,eAAO,KAAK;AAAA,MACd;AAAA;AAAA;AAAA;AAAA,MAKA,IAAI,MAAM;AACR,eAAO,KAAK;AAAA,MACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAkBA,UAAU,QAAQ,MAAM,SAAS;AAC/B,cAAM,WAAW,IAAIF,UAAS;AAAA,UAC5B,wBAAwB,QAAQ;AAAA,UAChC,YAAY,KAAK;AAAA,UACjB,YAAY,KAAK;AAAA,UACjB,UAAU,KAAK;AAAA,UACf,YAAY,QAAQ;AAAA,UACpB,oBAAoB,QAAQ;AAAA,QAC9B,CAAC;AAED,cAAM,SAAS,IAAIC,QAAO,QAAQ,KAAK,aAAa,QAAQ,YAAY;AAExE,aAAK,YAAY;AACjB,aAAK,UAAU;AACf,aAAK,UAAU;AAEf,iBAAS,UAAU,IAAI;AACvB,eAAO,UAAU,IAAI;AACrB,eAAO,UAAU,IAAI;AAErB,iBAAS,GAAG,YAAY,kBAAkB;AAC1C,iBAAS,GAAG,SAAS,eAAe;AACpC,iBAAS,GAAG,SAAS,eAAe;AACpC,iBAAS,GAAG,WAAW,iBAAiB;AACxC,iBAAS,GAAG,QAAQ,cAAc;AAClC,iBAAS,GAAG,QAAQ,cAAc;AAElC,eAAO,UAAU;AAKjB,YAAI,OAAO,WAAY,QAAO,WAAW,CAAC;AAC1C,YAAI,OAAO,WAAY,QAAO,WAAW;AAEzC,YAAI,KAAK,SAAS,EAAG,QAAO,QAAQ,IAAI;AAExC,eAAO,GAAG,SAAS,aAAa;AAChC,eAAO,GAAG,QAAQ,YAAY;AAC9B,eAAO,GAAG,OAAO,WAAW;AAC5B,eAAO,GAAG,SAAS,aAAa;AAEhC,aAAK,cAAc,WAAU;AAC7B,aAAK,KAAK,MAAM;AAAA,MAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAOA,YAAY;AACV,YAAI,CAAC,KAAK,SAAS;AACjB,eAAK,cAAc,WAAU;AAC7B,eAAK,KAAK,SAAS,KAAK,YAAY,KAAK,aAAa;AACtD;AAAA,QACF;AAEA,YAAI,KAAK,YAAY,kBAAkB,aAAa,GAAG;AACrD,eAAK,YAAY,kBAAkB,aAAa,EAAE,QAAQ;AAAA,QAC5D;AAEA,aAAK,UAAU,mBAAmB;AAClC,aAAK,cAAc,WAAU;AAC7B,aAAK,KAAK,SAAS,KAAK,YAAY,KAAK,aAAa;AAAA,MACxD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAsBA,MAAM,MAAM,MAAM;AAChB,YAAI,KAAK,eAAe,WAAU,OAAQ;AAC1C,YAAI,KAAK,eAAe,WAAU,YAAY;AAC5C,gBAAM,MAAM;AACZ,yBAAe,MAAM,KAAK,MAAM,GAAG;AACnC;AAAA,QACF;AAEA,YAAI,KAAK,eAAe,WAAU,SAAS;AACzC,cACE,KAAK,oBACJ,KAAK,uBAAuB,KAAK,UAAU,eAAe,eAC3D;AACA,iBAAK,QAAQ,IAAI;AAAA,UACnB;AAEA;AAAA,QACF;AAEA,aAAK,cAAc,WAAU;AAC7B,aAAK,QAAQ,MAAM,MAAM,MAAM,CAAC,KAAK,WAAW,CAACE,SAAQ;AAKvD,cAAIA,KAAK;AAET,eAAK,kBAAkB;AAEvB,cACE,KAAK,uBACL,KAAK,UAAU,eAAe,cAC9B;AACA,iBAAK,QAAQ,IAAI;AAAA,UACnB;AAAA,QACF,CAAC;AAED,sBAAc,IAAI;AAAA,MACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAOA,QAAQ;AACN,YACE,KAAK,eAAe,WAAU,cAC9B,KAAK,eAAe,WAAU,QAC9B;AACA;AAAA,QACF;AAEA,aAAK,UAAU;AACf,aAAK,QAAQ,MAAM;AAAA,MACrB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAUA,KAAK,MAAM,MAAM,IAAI;AACnB,YAAI,KAAK,eAAe,WAAU,YAAY;AAC5C,gBAAM,IAAI,MAAM,kDAAkD;AAAA,QACpE;AAEA,YAAI,OAAO,SAAS,YAAY;AAC9B,eAAK;AACL,iBAAO,OAAO;AAAA,QAChB,WAAW,OAAO,SAAS,YAAY;AACrC,eAAK;AACL,iBAAO;AAAA,QACT;AAEA,YAAI,OAAO,SAAS,SAAU,QAAO,KAAK,SAAS;AAEnD,YAAI,KAAK,eAAe,WAAU,MAAM;AACtC,yBAAe,MAAM,MAAM,EAAE;AAC7B;AAAA,QACF;AAEA,YAAI,SAAS,OAAW,QAAO,CAAC,KAAK;AACrC,aAAK,QAAQ,KAAK,QAAQ,cAAc,MAAM,EAAE;AAAA,MAClD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAUA,KAAK,MAAM,MAAM,IAAI;AACnB,YAAI,KAAK,eAAe,WAAU,YAAY;AAC5C,gBAAM,IAAI,MAAM,kDAAkD;AAAA,QACpE;AAEA,YAAI,OAAO,SAAS,YAAY;AAC9B,eAAK;AACL,iBAAO,OAAO;AAAA,QAChB,WAAW,OAAO,SAAS,YAAY;AACrC,eAAK;AACL,iBAAO;AAAA,QACT;AAEA,YAAI,OAAO,SAAS,SAAU,QAAO,KAAK,SAAS;AAEnD,YAAI,KAAK,eAAe,WAAU,MAAM;AACtC,yBAAe,MAAM,MAAM,EAAE;AAC7B;AAAA,QACF;AAEA,YAAI,SAAS,OAAW,QAAO,CAAC,KAAK;AACrC,aAAK,QAAQ,KAAK,QAAQ,cAAc,MAAM,EAAE;AAAA,MAClD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAOA,SAAS;AACP,YACE,KAAK,eAAe,WAAU,cAC9B,KAAK,eAAe,WAAU,QAC9B;AACA;AAAA,QACF;AAEA,aAAK,UAAU;AACf,YAAI,CAAC,KAAK,UAAU,eAAe,UAAW,MAAK,QAAQ,OAAO;AAAA,MACpE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAiBA,KAAK,MAAM,SAAS,IAAI;AACtB,YAAI,KAAK,eAAe,WAAU,YAAY;AAC5C,gBAAM,IAAI,MAAM,kDAAkD;AAAA,QACpE;AAEA,YAAI,OAAO,YAAY,YAAY;AACjC,eAAK;AACL,oBAAU,CAAC;AAAA,QACb;AAEA,YAAI,OAAO,SAAS,SAAU,QAAO,KAAK,SAAS;AAEnD,YAAI,KAAK,eAAe,WAAU,MAAM;AACtC,yBAAe,MAAM,MAAM,EAAE;AAC7B;AAAA,QACF;AAEA,cAAM,OAAO;AAAA,UACX,QAAQ,OAAO,SAAS;AAAA,UACxB,MAAM,CAAC,KAAK;AAAA,UACZ,UAAU;AAAA,UACV,KAAK;AAAA,UACL,GAAG;AAAA,QACL;AAEA,YAAI,CAAC,KAAK,YAAY,kBAAkB,aAAa,GAAG;AACtD,eAAK,WAAW;AAAA,QAClB;AAEA,aAAK,QAAQ,KAAK,QAAQ,cAAc,MAAM,EAAE;AAAA,MAClD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAOA,YAAY;AACV,YAAI,KAAK,eAAe,WAAU,OAAQ;AAC1C,YAAI,KAAK,eAAe,WAAU,YAAY;AAC5C,gBAAM,MAAM;AACZ,yBAAe,MAAM,KAAK,MAAM,GAAG;AACnC;AAAA,QACF;AAEA,YAAI,KAAK,SAAS;AAChB,eAAK,cAAc,WAAU;AAC7B,eAAK,QAAQ,QAAQ;AAAA,QACvB;AAAA,MACF;AAAA,IACF;AAMA,WAAO,eAAeD,YAAW,cAAc;AAAA,MAC7C,YAAY;AAAA,MACZ,OAAO,YAAY,QAAQ,YAAY;AAAA,IACzC,CAAC;AAMD,WAAO,eAAeA,WAAU,WAAW,cAAc;AAAA,MACvD,YAAY;AAAA,MACZ,OAAO,YAAY,QAAQ,YAAY;AAAA,IACzC,CAAC;AAMD,WAAO,eAAeA,YAAW,QAAQ;AAAA,MACvC,YAAY;AAAA,MACZ,OAAO,YAAY,QAAQ,MAAM;AAAA,IACnC,CAAC;AAMD,WAAO,eAAeA,WAAU,WAAW,QAAQ;AAAA,MACjD,YAAY;AAAA,MACZ,OAAO,YAAY,QAAQ,MAAM;AAAA,IACnC,CAAC;AAMD,WAAO,eAAeA,YAAW,WAAW;AAAA,MAC1C,YAAY;AAAA,MACZ,OAAO,YAAY,QAAQ,SAAS;AAAA,IACtC,CAAC;AAMD,WAAO,eAAeA,WAAU,WAAW,WAAW;AAAA,MACpD,YAAY;AAAA,MACZ,OAAO,YAAY,QAAQ,SAAS;AAAA,IACtC,CAAC;AAMD,WAAO,eAAeA,YAAW,UAAU;AAAA,MACzC,YAAY;AAAA,MACZ,OAAO,YAAY,QAAQ,QAAQ;AAAA,IACrC,CAAC;AAMD,WAAO,eAAeA,WAAU,WAAW,UAAU;AAAA,MACnD,YAAY;AAAA,MACZ,OAAO,YAAY,QAAQ,QAAQ;AAAA,IACrC,CAAC;AAED;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,QAAQ,CAAC,aAAa;AACtB,aAAO,eAAeA,WAAU,WAAW,UAAU,EAAE,YAAY,KAAK,CAAC;AAAA,IAC3E,CAAC;AAMD,KAAC,QAAQ,SAAS,SAAS,SAAS,EAAE,QAAQ,CAAC,WAAW;AACxD,aAAO,eAAeA,WAAU,WAAW,KAAK,MAAM,IAAI;AAAA,QACxD,YAAY;AAAA,QACZ,MAAM;AACJ,qBAAW,YAAY,KAAK,UAAU,MAAM,GAAG;AAC7C,gBAAI,SAAS,oBAAoB,EAAG,QAAO,SAAS,SAAS;AAAA,UAC/D;AAEA,iBAAO;AAAA,QACT;AAAA,QACA,IAAI,SAAS;AACX,qBAAW,YAAY,KAAK,UAAU,MAAM,GAAG;AAC7C,gBAAI,SAAS,oBAAoB,GAAG;AAClC,mBAAK,eAAe,QAAQ,QAAQ;AACpC;AAAA,YACF;AAAA,UACF;AAEA,cAAI,OAAO,YAAY,WAAY;AAEnC,eAAK,iBAAiB,QAAQ,SAAS;AAAA,YACrC,CAAC,oBAAoB,GAAG;AAAA,UAC1B,CAAC;AAAA,QACH;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAED,IAAAA,WAAU,UAAU,mBAAmB;AACvC,IAAAA,WAAU,UAAU,sBAAsB;AAE1C,IAAAP,QAAO,UAAUO;AAsCjB,aAAS,aAAa,WAAW,SAAS,WAAW,SAAS;AAC5D,YAAM,OAAO;AAAA,QACX,wBAAwB;AAAA,QACxB,UAAU;AAAA,QACV,cAAc;AAAA,QACd,iBAAiB,iBAAiB,CAAC;AAAA,QACnC,YAAY,MAAM,OAAO;AAAA,QACzB,oBAAoB;AAAA,QACpB,mBAAmB;AAAA,QACnB,iBAAiB;AAAA,QACjB,cAAc;AAAA,QACd,GAAG;AAAA,QACH,YAAY;AAAA,QACZ,UAAU;AAAA,QACV,UAAU;AAAA,QACV,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,MAAM;AAAA,QACN,MAAM;AAAA,MACR;AAEA,gBAAU,YAAY,KAAK;AAC3B,gBAAU,gBAAgB,KAAK;AAE/B,UAAI,CAAC,iBAAiB,SAAS,KAAK,eAAe,GAAG;AACpD,cAAM,IAAI;AAAA,UACR,iCAAiC,KAAK,eAAe,yBAC3B,iBAAiB,KAAK,IAAI,CAAC;AAAA,QACvD;AAAA,MACF;AAEA,UAAI;AAEJ,UAAI,mBAAmBH,MAAK;AAC1B,oBAAY;AAAA,MACd,OAAO;AACL,YAAI;AACF,sBAAY,IAAIA,KAAI,OAAO;AAAA,QAC7B,SAAS,GAAG;AACV,gBAAM,IAAI,YAAY,gBAAgB,OAAO,EAAE;AAAA,QACjD;AAAA,MACF;AAEA,UAAI,UAAU,aAAa,SAAS;AAClC,kBAAU,WAAW;AAAA,MACvB,WAAW,UAAU,aAAa,UAAU;AAC1C,kBAAU,WAAW;AAAA,MACvB;AAEA,gBAAU,OAAO,UAAU;AAE3B,YAAM,WAAW,UAAU,aAAa;AACxC,YAAM,WAAW,UAAU,aAAa;AACxC,UAAI;AAEJ,UAAI,UAAU,aAAa,SAAS,CAAC,YAAY,CAAC,UAAU;AAC1D,4BACE;AAAA,MAEJ,WAAW,YAAY,CAAC,UAAU,UAAU;AAC1C,4BAAoB;AAAA,MACtB,WAAW,UAAU,MAAM;AACzB,4BAAoB;AAAA,MACtB;AAEA,UAAI,mBAAmB;AACrB,cAAMI,OAAM,IAAI,YAAY,iBAAiB;AAE7C,YAAI,UAAU,eAAe,GAAG;AAC9B,gBAAMA;AAAA,QACR,OAAO;AACL,4BAAkB,WAAWA,IAAG;AAChC;AAAA,QACF;AAAA,MACF;AAEA,YAAM,cAAc,WAAW,MAAM;AACrC,YAAM,MAAMP,aAAY,EAAE,EAAE,SAAS,QAAQ;AAC7C,YAAM,UAAU,WAAW,MAAM,UAAU,KAAK;AAChD,YAAM,cAAc,oBAAI,IAAI;AAC5B,UAAI;AAEJ,WAAK,mBACH,KAAK,qBAAqB,WAAW,aAAa;AACpD,WAAK,cAAc,KAAK,eAAe;AACvC,WAAK,OAAO,UAAU,QAAQ;AAC9B,WAAK,OAAO,UAAU,SAAS,WAAW,GAAG,IACzC,UAAU,SAAS,MAAM,GAAG,EAAE,IAC9B,UAAU;AACd,WAAK,UAAU;AAAA,QACb,GAAG,KAAK;AAAA,QACR,yBAAyB,KAAK;AAAA,QAC9B,qBAAqB;AAAA,QACrB,YAAY;AAAA,QACZ,SAAS;AAAA,MACX;AACA,WAAK,OAAO,UAAU,WAAW,UAAU;AAC3C,WAAK,UAAU,KAAK;AAEpB,UAAI,KAAK,mBAAmB;AAC1B,4BAAoB,IAAI;AAAA,UACtB,KAAK,sBAAsB,OAAO,KAAK,oBAAoB,CAAC;AAAA,UAC5D;AAAA,UACA,KAAK;AAAA,QACP;AACA,aAAK,QAAQ,0BAA0B,IAAI,OAAO;AAAA,UAChD,CAAC,kBAAkB,aAAa,GAAG,kBAAkB,MAAM;AAAA,QAC7D,CAAC;AAAA,MACH;AACA,UAAI,UAAU,QAAQ;AACpB,mBAAW,YAAY,WAAW;AAChC,cACE,OAAO,aAAa,YACpB,CAAC,iBAAiB,KAAK,QAAQ,KAC/B,YAAY,IAAI,QAAQ,GACxB;AACA,kBAAM,IAAI;AAAA,cACR;AAAA,YACF;AAAA,UACF;AAEA,sBAAY,IAAI,QAAQ;AAAA,QAC1B;AAEA,aAAK,QAAQ,wBAAwB,IAAI,UAAU,KAAK,GAAG;AAAA,MAC7D;AACA,UAAI,KAAK,QAAQ;AACf,YAAI,KAAK,kBAAkB,IAAI;AAC7B,eAAK,QAAQ,sBAAsB,IAAI,KAAK;AAAA,QAC9C,OAAO;AACL,eAAK,QAAQ,SAAS,KAAK;AAAA,QAC7B;AAAA,MACF;AACA,UAAI,UAAU,YAAY,UAAU,UAAU;AAC5C,aAAK,OAAO,GAAG,UAAU,QAAQ,IAAI,UAAU,QAAQ;AAAA,MACzD;AAEA,UAAI,UAAU;AACZ,cAAM,QAAQ,KAAK,KAAK,MAAM,GAAG;AAEjC,aAAK,aAAa,MAAM,CAAC;AACzB,aAAK,OAAO,MAAM,CAAC;AAAA,MACrB;AAEA,UAAI;AAEJ,UAAI,KAAK,iBAAiB;AACxB,YAAI,UAAU,eAAe,GAAG;AAC9B,oBAAU,eAAe;AACzB,oBAAU,kBAAkB;AAC5B,oBAAU,4BAA4B,WAClC,KAAK,aACL,UAAU;AAEd,gBAAM,UAAU,WAAW,QAAQ;AAMnC,oBAAU,EAAE,GAAG,SAAS,SAAS,CAAC,EAAE;AAEpC,cAAI,SAAS;AACX,uBAAW,CAACQ,MAAK,KAAK,KAAK,OAAO,QAAQ,OAAO,GAAG;AAClD,sBAAQ,QAAQA,KAAI,YAAY,CAAC,IAAI;AAAA,YACvC;AAAA,UACF;AAAA,QACF,WAAW,UAAU,cAAc,UAAU,MAAM,GAAG;AACpD,gBAAM,aAAa,WACf,UAAU,eACR,KAAK,eAAe,UAAU,4BAC9B,QACF,UAAU,eACR,QACA,UAAU,SAAS,UAAU;AAEnC,cAAI,CAAC,cAAe,UAAU,mBAAmB,CAAC,UAAW;AAK3D,mBAAO,KAAK,QAAQ;AACpB,mBAAO,KAAK,QAAQ;AAEpB,gBAAI,CAAC,WAAY,QAAO,KAAK,QAAQ;AAErC,iBAAK,OAAO;AAAA,UACd;AAAA,QACF;AAOA,YAAI,KAAK,QAAQ,CAAC,QAAQ,QAAQ,eAAe;AAC/C,kBAAQ,QAAQ,gBACd,WAAW,OAAO,KAAK,KAAK,IAAI,EAAE,SAAS,QAAQ;AAAA,QACvD;AAEA,cAAM,UAAU,OAAO,QAAQ,IAAI;AAEnC,YAAI,UAAU,YAAY;AAUxB,oBAAU,KAAK,YAAY,UAAU,KAAK,GAAG;AAAA,QAC/C;AAAA,MACF,OAAO;AACL,cAAM,UAAU,OAAO,QAAQ,IAAI;AAAA,MACrC;AAEA,UAAI,KAAK,SAAS;AAChB,YAAI,GAAG,WAAW,MAAM;AACtB,yBAAe,WAAW,KAAK,iCAAiC;AAAA,QAClE,CAAC;AAAA,MACH;AAEA,UAAI,GAAG,SAAS,CAACD,SAAQ;AACvB,YAAI,QAAQ,QAAQ,IAAI,QAAQ,EAAG;AAEnC,cAAM,UAAU,OAAO;AACvB,0BAAkB,WAAWA,IAAG;AAAA,MAClC,CAAC;AAED,UAAI,GAAG,YAAY,CAAC,QAAQ;AAC1B,cAAM,WAAW,IAAI,QAAQ;AAC7B,cAAM,aAAa,IAAI;AAEvB,YACE,YACA,KAAK,mBACL,cAAc,OACd,aAAa,KACb;AACA,cAAI,EAAE,UAAU,aAAa,KAAK,cAAc;AAC9C,2BAAe,WAAW,KAAK,4BAA4B;AAC3D;AAAA,UACF;AAEA,cAAI,MAAM;AAEV,cAAI;AAEJ,cAAI;AACF,mBAAO,IAAIJ,KAAI,UAAU,OAAO;AAAA,UAClC,SAAS,GAAG;AACV,kBAAMI,OAAM,IAAI,YAAY,gBAAgB,QAAQ,EAAE;AACtD,8BAAkB,WAAWA,IAAG;AAChC;AAAA,UACF;AAEA,uBAAa,WAAW,MAAM,WAAW,OAAO;AAAA,QAClD,WAAW,CAAC,UAAU,KAAK,uBAAuB,KAAK,GAAG,GAAG;AAC3D;AAAA,YACE;AAAA,YACA;AAAA,YACA,+BAA+B,IAAI,UAAU;AAAA,UAC/C;AAAA,QACF;AAAA,MACF,CAAC;AAED,UAAI,GAAG,WAAW,CAAC,KAAK,QAAQ,SAAS;AACvC,kBAAU,KAAK,WAAW,GAAG;AAM7B,YAAI,UAAU,eAAeD,WAAU,WAAY;AAEnD,cAAM,UAAU,OAAO;AAEvB,cAAM,UAAU,IAAI,QAAQ;AAE5B,YAAI,YAAY,UAAa,QAAQ,YAAY,MAAM,aAAa;AAClE,yBAAe,WAAW,QAAQ,wBAAwB;AAC1D;AAAA,QACF;AAEA,cAAM,SAASL,YAAW,MAAM,EAC7B,OAAO,MAAM,IAAI,EACjB,OAAO,QAAQ;AAElB,YAAI,IAAI,QAAQ,sBAAsB,MAAM,QAAQ;AAClD,yBAAe,WAAW,QAAQ,qCAAqC;AACvE;AAAA,QACF;AAEA,cAAM,aAAa,IAAI,QAAQ,wBAAwB;AACvD,YAAI;AAEJ,YAAI,eAAe,QAAW;AAC5B,cAAI,CAAC,YAAY,MAAM;AACrB,wBAAY;AAAA,UACd,WAAW,CAAC,YAAY,IAAI,UAAU,GAAG;AACvC,wBAAY;AAAA,UACd;AAAA,QACF,WAAW,YAAY,MAAM;AAC3B,sBAAY;AAAA,QACd;AAEA,YAAI,WAAW;AACb,yBAAe,WAAW,QAAQ,SAAS;AAC3C;AAAA,QACF;AAEA,YAAI,WAAY,WAAU,YAAY;AAEtC,cAAM,yBAAyB,IAAI,QAAQ,0BAA0B;AAErE,YAAI,2BAA2B,QAAW;AACxC,cAAI,CAAC,mBAAmB;AACtB,kBAAM,UACJ;AAEF,2BAAe,WAAW,QAAQ,OAAO;AACzC;AAAA,UACF;AAEA,cAAI;AAEJ,cAAI;AACF,yBAAa,MAAM,sBAAsB;AAAA,UAC3C,SAASM,MAAK;AACZ,kBAAM,UAAU;AAChB,2BAAe,WAAW,QAAQ,OAAO;AACzC;AAAA,UACF;AAEA,gBAAM,iBAAiB,OAAO,KAAK,UAAU;AAE7C,cACE,eAAe,WAAW,KAC1B,eAAe,CAAC,MAAM,kBAAkB,eACxC;AACA,kBAAM,UAAU;AAChB,2BAAe,WAAW,QAAQ,OAAO;AACzC;AAAA,UACF;AAEA,cAAI;AACF,8BAAkB,OAAO,WAAW,kBAAkB,aAAa,CAAC;AAAA,UACtE,SAASA,MAAK;AACZ,kBAAM,UAAU;AAChB,2BAAe,WAAW,QAAQ,OAAO;AACzC;AAAA,UACF;AAEA,oBAAU,YAAY,kBAAkB,aAAa,IACnD;AAAA,QACJ;AAEA,kBAAU,UAAU,QAAQ,MAAM;AAAA,UAChC,wBAAwB,KAAK;AAAA,UAC7B,cAAc,KAAK;AAAA,UACnB,YAAY,KAAK;AAAA,UACjB,oBAAoB,KAAK;AAAA,QAC3B,CAAC;AAAA,MACH,CAAC;AAED,UAAI,KAAK,eAAe;AACtB,aAAK,cAAc,KAAK,SAAS;AAAA,MACnC,OAAO;AACL,YAAI,IAAI;AAAA,MACV;AAAA,IACF;AASA,aAAS,kBAAkB,WAAWA,MAAK;AACzC,gBAAU,cAAcD,WAAU;AAKlC,gBAAU,gBAAgB;AAC1B,gBAAU,KAAK,SAASC,IAAG;AAC3B,gBAAU,UAAU;AAAA,IACtB;AASA,aAAS,WAAW,SAAS;AAC3B,cAAQ,OAAO,QAAQ;AACvB,aAAO,IAAI,QAAQ,OAAO;AAAA,IAC5B;AASA,aAAS,WAAW,SAAS;AAC3B,cAAQ,OAAO;AAEf,UAAI,CAAC,QAAQ,cAAc,QAAQ,eAAe,IAAI;AACpD,gBAAQ,aAAa,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,QAAQ;AAAA,MAC7D;AAEA,aAAO,IAAI,QAAQ,OAAO;AAAA,IAC5B;AAWA,aAAS,eAAe,WAAW,QAAQ,SAAS;AAClD,gBAAU,cAAcD,WAAU;AAElC,YAAMC,OAAM,IAAI,MAAM,OAAO;AAC7B,YAAM,kBAAkBA,MAAK,cAAc;AAE3C,UAAI,OAAO,WAAW;AACpB,eAAO,QAAQ,IAAI;AACnB,eAAO,MAAM;AAEb,YAAI,OAAO,UAAU,CAAC,OAAO,OAAO,WAAW;AAM7C,iBAAO,OAAO,QAAQ;AAAA,QACxB;AAEA,gBAAQ,SAAS,mBAAmB,WAAWA,IAAG;AAAA,MACpD,OAAO;AACL,eAAO,QAAQA,IAAG;AAClB,eAAO,KAAK,SAAS,UAAU,KAAK,KAAK,WAAW,OAAO,CAAC;AAC5D,eAAO,KAAK,SAAS,UAAU,UAAU,KAAK,SAAS,CAAC;AAAA,MAC1D;AAAA,IACF;AAWA,aAAS,eAAe,WAAW,MAAM,IAAI;AAC3C,UAAI,MAAM;AACR,cAAM,SAAS,OAAO,IAAI,IAAI,KAAK,OAAO,SAAS,IAAI,EAAE;AAQzD,YAAI,UAAU,QAAS,WAAU,QAAQ,kBAAkB;AAAA,YACtD,WAAU,mBAAmB;AAAA,MACpC;AAEA,UAAI,IAAI;AACN,cAAMA,OAAM,IAAI;AAAA,UACd,qCAAqC,UAAU,UAAU,KACnD,YAAY,UAAU,UAAU,CAAC;AAAA,QACzC;AACA,gBAAQ,SAAS,IAAIA,IAAG;AAAA,MAC1B;AAAA,IACF;AASA,aAAS,mBAAmB,MAAM,QAAQ;AACxC,YAAM,YAAY,KAAK,UAAU;AAEjC,gBAAU,sBAAsB;AAChC,gBAAU,gBAAgB;AAC1B,gBAAU,aAAa;AAEvB,UAAI,UAAU,QAAQ,UAAU,MAAM,OAAW;AAEjD,gBAAU,QAAQ,eAAe,QAAQ,YAAY;AACrD,cAAQ,SAAS,QAAQ,UAAU,OAAO;AAE1C,UAAI,SAAS,KAAM,WAAU,MAAM;AAAA,UAC9B,WAAU,MAAM,MAAM,MAAM;AAAA,IACnC;AAOA,aAAS,kBAAkB;AACzB,YAAM,YAAY,KAAK,UAAU;AAEjC,UAAI,CAAC,UAAU,SAAU,WAAU,QAAQ,OAAO;AAAA,IACpD;AAQA,aAAS,gBAAgBA,MAAK;AAC5B,YAAM,YAAY,KAAK,UAAU;AAEjC,UAAI,UAAU,QAAQ,UAAU,MAAM,QAAW;AAC/C,kBAAU,QAAQ,eAAe,QAAQ,YAAY;AAMrD,gBAAQ,SAAS,QAAQ,UAAU,OAAO;AAE1C,kBAAU,MAAMA,KAAI,WAAW,CAAC;AAAA,MAClC;AAEA,UAAI,CAAC,UAAU,eAAe;AAC5B,kBAAU,gBAAgB;AAC1B,kBAAU,KAAK,SAASA,IAAG;AAAA,MAC7B;AAAA,IACF;AAOA,aAAS,mBAAmB;AAC1B,WAAK,UAAU,EAAE,UAAU;AAAA,IAC7B;AASA,aAAS,kBAAkB,MAAM,UAAU;AACzC,WAAK,UAAU,EAAE,KAAK,WAAW,MAAM,QAAQ;AAAA,IACjD;AAQA,aAAS,eAAe,MAAM;AAC5B,YAAM,YAAY,KAAK,UAAU;AAEjC,UAAI,UAAU,UAAW,WAAU,KAAK,MAAM,CAAC,KAAK,WAAW,IAAI;AACnE,gBAAU,KAAK,QAAQ,IAAI;AAAA,IAC7B;AAQA,aAAS,eAAe,MAAM;AAC5B,WAAK,UAAU,EAAE,KAAK,QAAQ,IAAI;AAAA,IACpC;AAQA,aAAS,OAAO,QAAQ;AACtB,aAAO,OAAO;AAAA,IAChB;AAQA,aAAS,cAAcA,MAAK;AAC1B,YAAM,YAAY,KAAK,UAAU;AAEjC,UAAI,UAAU,eAAeD,WAAU,OAAQ;AAC/C,UAAI,UAAU,eAAeA,WAAU,MAAM;AAC3C,kBAAU,cAAcA,WAAU;AAClC,sBAAc,SAAS;AAAA,MACzB;AAOA,WAAK,QAAQ,IAAI;AAEjB,UAAI,CAAC,UAAU,eAAe;AAC5B,kBAAU,gBAAgB;AAC1B,kBAAU,KAAK,SAASC,IAAG;AAAA,MAC7B;AAAA,IACF;AAQA,aAAS,cAAc,WAAW;AAChC,gBAAU,cAAc;AAAA,QACtB,UAAU,QAAQ,QAAQ,KAAK,UAAU,OAAO;AAAA,QAChD,UAAU;AAAA,MACZ;AAAA,IACF;AAOA,aAAS,gBAAgB;AACvB,YAAM,YAAY,KAAK,UAAU;AAEjC,WAAK,eAAe,SAAS,aAAa;AAC1C,WAAK,eAAe,QAAQ,YAAY;AACxC,WAAK,eAAe,OAAO,WAAW;AAEtC,gBAAU,cAAcD,WAAU;AAWlC,UACE,CAAC,KAAK,eAAe,cACrB,CAAC,UAAU,uBACX,CAAC,UAAU,UAAU,eAAe,gBACpC,KAAK,eAAe,WAAW,GAC/B;AACA,cAAM,QAAQ,KAAK,KAAK,KAAK,eAAe,MAAM;AAElD,kBAAU,UAAU,MAAM,KAAK;AAAA,MACjC;AAEA,gBAAU,UAAU,IAAI;AAExB,WAAK,UAAU,IAAI;AAEnB,mBAAa,UAAU,WAAW;AAElC,UACE,UAAU,UAAU,eAAe,YACnC,UAAU,UAAU,eAAe,cACnC;AACA,kBAAU,UAAU;AAAA,MACtB,OAAO;AACL,kBAAU,UAAU,GAAG,SAAS,gBAAgB;AAChD,kBAAU,UAAU,GAAG,UAAU,gBAAgB;AAAA,MACnD;AAAA,IACF;AAQA,aAAS,aAAa,OAAO;AAC3B,UAAI,CAAC,KAAK,UAAU,EAAE,UAAU,MAAM,KAAK,GAAG;AAC5C,aAAK,MAAM;AAAA,MACb;AAAA,IACF;AAOA,aAAS,cAAc;AACrB,YAAM,YAAY,KAAK,UAAU;AAEjC,gBAAU,cAAcA,WAAU;AAClC,gBAAU,UAAU,IAAI;AACxB,WAAK,IAAI;AAAA,IACX;AAOA,aAAS,gBAAgB;AACvB,YAAM,YAAY,KAAK,UAAU;AAEjC,WAAK,eAAe,SAAS,aAAa;AAC1C,WAAK,GAAG,SAAS,IAAI;AAErB,UAAI,WAAW;AACb,kBAAU,cAAcA,WAAU;AAClC,aAAK,QAAQ;AAAA,MACf;AAAA,IACF;AAAA;AAAA;;;ACh3CA;AAAA,+DAAAG,UAAAC,SAAA;AAAA;AAGA,QAAMC,aAAY;AAClB,QAAM,EAAE,OAAO,IAAI,QAAQ,QAAQ;AAQnC,aAAS,UAAU,QAAQ;AACzB,aAAO,KAAK,OAAO;AAAA,IACrB;AAOA,aAAS,cAAc;AACrB,UAAI,CAAC,KAAK,aAAa,KAAK,eAAe,UAAU;AACnD,aAAK,QAAQ;AAAA,MACf;AAAA,IACF;AAQA,aAAS,cAAcC,MAAK;AAC1B,WAAK,eAAe,SAAS,aAAa;AAC1C,WAAK,QAAQ;AACb,UAAI,KAAK,cAAc,OAAO,MAAM,GAAG;AAErC,aAAK,KAAK,SAASA,IAAG;AAAA,MACxB;AAAA,IACF;AAUA,aAASC,uBAAsB,IAAI,SAAS;AAC1C,UAAI,qBAAqB;AAEzB,YAAM,SAAS,IAAI,OAAO;AAAA,QACxB,GAAG;AAAA,QACH,aAAa;AAAA,QACb,WAAW;AAAA,QACX,YAAY;AAAA,QACZ,oBAAoB;AAAA,MACtB,CAAC;AAED,SAAG,GAAG,WAAW,SAAS,QAAQ,KAAK,UAAU;AAC/C,cAAM,OACJ,CAAC,YAAY,OAAO,eAAe,aAAa,IAAI,SAAS,IAAI;AAEnE,YAAI,CAAC,OAAO,KAAK,IAAI,EAAG,IAAG,MAAM;AAAA,MACnC,CAAC;AAED,SAAG,KAAK,SAAS,SAAS,MAAMD,MAAK;AACnC,YAAI,OAAO,UAAW;AAWtB,6BAAqB;AACrB,eAAO,QAAQA,IAAG;AAAA,MACpB,CAAC;AAED,SAAG,KAAK,SAAS,SAAS,QAAQ;AAChC,YAAI,OAAO,UAAW;AAEtB,eAAO,KAAK,IAAI;AAAA,MAClB,CAAC;AAED,aAAO,WAAW,SAAUA,MAAK,UAAU;AACzC,YAAI,GAAG,eAAe,GAAG,QAAQ;AAC/B,mBAASA,IAAG;AACZ,kBAAQ,SAAS,WAAW,MAAM;AAClC;AAAA,QACF;AAEA,YAAI,SAAS;AAEb,WAAG,KAAK,SAAS,SAAS,MAAMA,MAAK;AACnC,mBAAS;AACT,mBAASA,IAAG;AAAA,QACd,CAAC;AAED,WAAG,KAAK,SAAS,SAAS,QAAQ;AAChC,cAAI,CAAC,OAAQ,UAASA,IAAG;AACzB,kBAAQ,SAAS,WAAW,MAAM;AAAA,QACpC,CAAC;AAED,YAAI,mBAAoB,IAAG,UAAU;AAAA,MACvC;AAEA,aAAO,SAAS,SAAU,UAAU;AAClC,YAAI,GAAG,eAAe,GAAG,YAAY;AACnC,aAAG,KAAK,QAAQ,SAAS,OAAO;AAC9B,mBAAO,OAAO,QAAQ;AAAA,UACxB,CAAC;AACD;AAAA,QACF;AAMA,YAAI,GAAG,YAAY,KAAM;AAEzB,YAAI,GAAG,QAAQ,eAAe,UAAU;AACtC,mBAAS;AACT,cAAI,OAAO,eAAe,WAAY,QAAO,QAAQ;AAAA,QACvD,OAAO;AACL,aAAG,QAAQ,KAAK,UAAU,SAAS,SAAS;AAI1C,qBAAS;AAAA,UACX,CAAC;AACD,aAAG,MAAM;AAAA,QACX;AAAA,MACF;AAEA,aAAO,QAAQ,WAAY;AACzB,YAAI,GAAG,SAAU,IAAG,OAAO;AAAA,MAC7B;AAEA,aAAO,SAAS,SAAU,OAAO,UAAU,UAAU;AACnD,YAAI,GAAG,eAAe,GAAG,YAAY;AACnC,aAAG,KAAK,QAAQ,SAAS,OAAO;AAC9B,mBAAO,OAAO,OAAO,UAAU,QAAQ;AAAA,UACzC,CAAC;AACD;AAAA,QACF;AAEA,WAAG,KAAK,OAAO,QAAQ;AAAA,MACzB;AAEA,aAAO,GAAG,OAAO,WAAW;AAC5B,aAAO,GAAG,SAAS,aAAa;AAChC,aAAO;AAAA,IACT;AAEA,IAAAF,QAAO,UAAUG;AAAA;AAAA;;;AChKjB;AAAA,oEAAAC,UAAAC,SAAA;AAAA;AAEA,QAAM,EAAE,WAAW,IAAI;AASvB,aAAS,MAAM,QAAQ;AACrB,YAAM,YAAY,oBAAI,IAAI;AAC1B,UAAI,QAAQ;AACZ,UAAI,MAAM;AACV,UAAI,IAAI;AAER,WAAK,GAAG,IAAI,OAAO,QAAQ,KAAK;AAC9B,cAAM,OAAO,OAAO,WAAW,CAAC;AAEhC,YAAI,QAAQ,MAAM,WAAW,IAAI,MAAM,GAAG;AACxC,cAAI,UAAU,GAAI,SAAQ;AAAA,QAC5B,WACE,MAAM,MACL,SAAS,MAAkB,SAAS,IACrC;AACA,cAAI,QAAQ,MAAM,UAAU,GAAI,OAAM;AAAA,QACxC,WAAW,SAAS,IAAgB;AAClC,cAAI,UAAU,IAAI;AAChB,kBAAM,IAAI,YAAY,iCAAiC,CAAC,EAAE;AAAA,UAC5D;AAEA,cAAI,QAAQ,GAAI,OAAM;AAEtB,gBAAMC,YAAW,OAAO,MAAM,OAAO,GAAG;AAExC,cAAI,UAAU,IAAIA,SAAQ,GAAG;AAC3B,kBAAM,IAAI,YAAY,QAAQA,SAAQ,6BAA6B;AAAA,UACrE;AAEA,oBAAU,IAAIA,SAAQ;AACtB,kBAAQ,MAAM;AAAA,QAChB,OAAO;AACL,gBAAM,IAAI,YAAY,iCAAiC,CAAC,EAAE;AAAA,QAC5D;AAAA,MACF;AAEA,UAAI,UAAU,MAAM,QAAQ,IAAI;AAC9B,cAAM,IAAI,YAAY,yBAAyB;AAAA,MACjD;AAEA,YAAM,WAAW,OAAO,MAAM,OAAO,CAAC;AAEtC,UAAI,UAAU,IAAI,QAAQ,GAAG;AAC3B,cAAM,IAAI,YAAY,QAAQ,QAAQ,6BAA6B;AAAA,MACrE;AAEA,gBAAU,IAAI,QAAQ;AACtB,aAAO;AAAA,IACT;AAEA,IAAAD,QAAO,UAAU,EAAE,MAAM;AAAA;AAAA;;;AC7DzB;AAAA,yEAAAE,UAAAC,SAAA;AAAA;AAIA,QAAM,eAAe,QAAQ,QAAQ;AACrC,QAAM,OAAO,QAAQ,MAAM;AAC3B,QAAM,EAAE,OAAO,IAAI,QAAQ,QAAQ;AACnC,QAAM,EAAE,YAAAC,YAAW,IAAI,QAAQ,QAAQ;AAEvC,QAAM,YAAY;AAClB,QAAM,oBAAoB;AAC1B,QAAM,cAAc;AACpB,QAAMC,aAAY;AAClB,QAAM,EAAE,eAAe,MAAM,WAAW,IAAI;AAE5C,QAAM,WAAW;AAEjB,QAAM,UAAU;AAChB,QAAM,UAAU;AAChB,QAAM,SAAS;AAOf,QAAMC,mBAAN,cAA8B,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAmCzC,YAAY,SAAS,UAAU;AAC7B,cAAM;AAEN,kBAAU;AAAA,UACR,wBAAwB;AAAA,UACxB,UAAU;AAAA,UACV,YAAY,MAAM,OAAO;AAAA,UACzB,oBAAoB;AAAA,UACpB,mBAAmB;AAAA,UACnB,iBAAiB;AAAA,UACjB,gBAAgB;AAAA,UAChB,cAAc;AAAA,UACd,cAAc;AAAA,UACd,UAAU;AAAA,UACV,SAAS;AAAA;AAAA,UACT,QAAQ;AAAA,UACR,MAAM;AAAA,UACN,MAAM;AAAA,UACN,MAAM;AAAA,UACN,WAAAD;AAAA,UACA,GAAG;AAAA,QACL;AAEA,YACG,QAAQ,QAAQ,QAAQ,CAAC,QAAQ,UAAU,CAAC,QAAQ,YACpD,QAAQ,QAAQ,SAAS,QAAQ,UAAU,QAAQ,aACnD,QAAQ,UAAU,QAAQ,UAC3B;AACA,gBAAM,IAAI;AAAA,YACR;AAAA,UAEF;AAAA,QACF;AAEA,YAAI,QAAQ,QAAQ,MAAM;AACxB,eAAK,UAAU,KAAK,aAAa,CAAC,KAAK,QAAQ;AAC7C,kBAAM,OAAO,KAAK,aAAa,GAAG;AAElC,gBAAI,UAAU,KAAK;AAAA,cACjB,kBAAkB,KAAK;AAAA,cACvB,gBAAgB;AAAA,YAClB,CAAC;AACD,gBAAI,IAAI,IAAI;AAAA,UACd,CAAC;AACD,eAAK,QAAQ;AAAA,YACX,QAAQ;AAAA,YACR,QAAQ;AAAA,YACR,QAAQ;AAAA,YACR;AAAA,UACF;AAAA,QACF,WAAW,QAAQ,QAAQ;AACzB,eAAK,UAAU,QAAQ;AAAA,QACzB;AAEA,YAAI,KAAK,SAAS;AAChB,gBAAM,iBAAiB,KAAK,KAAK,KAAK,MAAM,YAAY;AAExD,eAAK,mBAAmB,aAAa,KAAK,SAAS;AAAA,YACjD,WAAW,KAAK,KAAK,KAAK,MAAM,WAAW;AAAA,YAC3C,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO;AAAA,YACnC,SAAS,CAAC,KAAK,QAAQ,SAAS;AAC9B,mBAAK,cAAc,KAAK,QAAQ,MAAM,cAAc;AAAA,YACtD;AAAA,UACF,CAAC;AAAA,QACH;AAEA,YAAI,QAAQ,sBAAsB,KAAM,SAAQ,oBAAoB,CAAC;AACrE,YAAI,QAAQ,gBAAgB;AAC1B,eAAK,UAAU,oBAAI,IAAI;AACvB,eAAK,mBAAmB;AAAA,QAC1B;AAEA,aAAK,UAAU;AACf,aAAK,SAAS;AAAA,MAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAWA,UAAU;AACR,YAAI,KAAK,QAAQ,UAAU;AACzB,gBAAM,IAAI,MAAM,4CAA4C;AAAA,QAC9D;AAEA,YAAI,CAAC,KAAK,QAAS,QAAO;AAC1B,eAAO,KAAK,QAAQ,QAAQ;AAAA,MAC9B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MASA,MAAM,IAAI;AACR,YAAI,KAAK,WAAW,QAAQ;AAC1B,cAAI,IAAI;AACN,iBAAK,KAAK,SAAS,MAAM;AACvB,iBAAG,IAAI,MAAM,2BAA2B,CAAC;AAAA,YAC3C,CAAC;AAAA,UACH;AAEA,kBAAQ,SAAS,WAAW,IAAI;AAChC;AAAA,QACF;AAEA,YAAI,GAAI,MAAK,KAAK,SAAS,EAAE;AAE7B,YAAI,KAAK,WAAW,QAAS;AAC7B,aAAK,SAAS;AAEd,YAAI,KAAK,QAAQ,YAAY,KAAK,QAAQ,QAAQ;AAChD,cAAI,KAAK,SAAS;AAChB,iBAAK,iBAAiB;AACtB,iBAAK,mBAAmB,KAAK,UAAU;AAAA,UACzC;AAEA,cAAI,KAAK,SAAS;AAChB,gBAAI,CAAC,KAAK,QAAQ,MAAM;AACtB,sBAAQ,SAAS,WAAW,IAAI;AAAA,YAClC,OAAO;AACL,mBAAK,mBAAmB;AAAA,YAC1B;AAAA,UACF,OAAO;AACL,oBAAQ,SAAS,WAAW,IAAI;AAAA,UAClC;AAAA,QACF,OAAO;AACL,gBAAM,SAAS,KAAK;AAEpB,eAAK,iBAAiB;AACtB,eAAK,mBAAmB,KAAK,UAAU;AAMvC,iBAAO,MAAM,MAAM;AACjB,sBAAU,IAAI;AAAA,UAChB,CAAC;AAAA,QACH;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MASA,aAAa,KAAK;AAChB,YAAI,KAAK,QAAQ,MAAM;AACrB,gBAAM,QAAQ,IAAI,IAAI,QAAQ,GAAG;AACjC,gBAAM,WAAW,UAAU,KAAK,IAAI,IAAI,MAAM,GAAG,KAAK,IAAI,IAAI;AAE9D,cAAI,aAAa,KAAK,QAAQ,KAAM,QAAO;AAAA,QAC7C;AAEA,eAAO;AAAA,MACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAWA,cAAc,KAAK,QAAQ,MAAM,IAAI;AACnC,eAAO,GAAG,SAAS,aAAa;AAEhC,cAAM,MAAM,IAAI,QAAQ,mBAAmB;AAC3C,cAAM,UAAU,IAAI,QAAQ;AAC5B,cAAM,UAAU,CAAC,IAAI,QAAQ,uBAAuB;AAEpD,YAAI,IAAI,WAAW,OAAO;AACxB,gBAAM,UAAU;AAChB,4CAAkC,MAAM,KAAK,QAAQ,KAAK,OAAO;AACjE;AAAA,QACF;AAEA,YAAI,YAAY,UAAa,QAAQ,YAAY,MAAM,aAAa;AAClE,gBAAM,UAAU;AAChB,4CAAkC,MAAM,KAAK,QAAQ,KAAK,OAAO;AACjE;AAAA,QACF;AAEA,YAAI,QAAQ,UAAa,CAAC,SAAS,KAAK,GAAG,GAAG;AAC5C,gBAAM,UAAU;AAChB,4CAAkC,MAAM,KAAK,QAAQ,KAAK,OAAO;AACjE;AAAA,QACF;AAEA,YAAI,YAAY,MAAM,YAAY,GAAG;AACnC,gBAAM,UAAU;AAChB,4CAAkC,MAAM,KAAK,QAAQ,KAAK,SAAS;AAAA,YACjE,yBAAyB;AAAA,UAC3B,CAAC;AACD;AAAA,QACF;AAEA,YAAI,CAAC,KAAK,aAAa,GAAG,GAAG;AAC3B,yBAAe,QAAQ,GAAG;AAC1B;AAAA,QACF;AAEA,cAAM,uBAAuB,IAAI,QAAQ,wBAAwB;AACjE,YAAI,YAAY,oBAAI,IAAI;AAExB,YAAI,yBAAyB,QAAW;AACtC,cAAI;AACF,wBAAY,YAAY,MAAM,oBAAoB;AAAA,UACpD,SAASE,MAAK;AACZ,kBAAM,UAAU;AAChB,8CAAkC,MAAM,KAAK,QAAQ,KAAK,OAAO;AACjE;AAAA,UACF;AAAA,QACF;AAEA,cAAM,yBAAyB,IAAI,QAAQ,0BAA0B;AACrE,cAAM,aAAa,CAAC;AAEpB,YACE,KAAK,QAAQ,qBACb,2BAA2B,QAC3B;AACA,gBAAM,oBAAoB,IAAI;AAAA,YAC5B,KAAK,QAAQ;AAAA,YACb;AAAA,YACA,KAAK,QAAQ;AAAA,UACf;AAEA,cAAI;AACF,kBAAM,SAAS,UAAU,MAAM,sBAAsB;AAErD,gBAAI,OAAO,kBAAkB,aAAa,GAAG;AAC3C,gCAAkB,OAAO,OAAO,kBAAkB,aAAa,CAAC;AAChE,yBAAW,kBAAkB,aAAa,IAAI;AAAA,YAChD;AAAA,UACF,SAASA,MAAK;AACZ,kBAAM,UACJ;AACF,8CAAkC,MAAM,KAAK,QAAQ,KAAK,OAAO;AACjE;AAAA,UACF;AAAA,QACF;AAKA,YAAI,KAAK,QAAQ,cAAc;AAC7B,gBAAM,OAAO;AAAA,YACX,QACE,IAAI,QAAQ,GAAG,YAAY,IAAI,yBAAyB,QAAQ,EAAE;AAAA,YACpE,QAAQ,CAAC,EAAE,IAAI,OAAO,cAAc,IAAI,OAAO;AAAA,YAC/C;AAAA,UACF;AAEA,cAAI,KAAK,QAAQ,aAAa,WAAW,GAAG;AAC1C,iBAAK,QAAQ,aAAa,MAAM,CAAC,UAAU,MAAM,SAAS,YAAY;AACpE,kBAAI,CAAC,UAAU;AACb,uBAAO,eAAe,QAAQ,QAAQ,KAAK,SAAS,OAAO;AAAA,cAC7D;AAEA,mBAAK;AAAA,gBACH;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA;AAAA,cACF;AAAA,YACF,CAAC;AACD;AAAA,UACF;AAEA,cAAI,CAAC,KAAK,QAAQ,aAAa,IAAI,EAAG,QAAO,eAAe,QAAQ,GAAG;AAAA,QACzE;AAEA,aAAK,gBAAgB,YAAY,KAAK,WAAW,KAAK,QAAQ,MAAM,EAAE;AAAA,MACxE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAeA,gBAAgB,YAAY,KAAK,WAAW,KAAK,QAAQ,MAAM,IAAI;AAIjE,YAAI,CAAC,OAAO,YAAY,CAAC,OAAO,SAAU,QAAO,OAAO,QAAQ;AAEhE,YAAI,OAAO,UAAU,GAAG;AACtB,gBAAM,IAAI;AAAA,YACR;AAAA,UAEF;AAAA,QACF;AAEA,YAAI,KAAK,SAAS,QAAS,QAAO,eAAe,QAAQ,GAAG;AAE5D,cAAM,SAASH,YAAW,MAAM,EAC7B,OAAO,MAAM,IAAI,EACjB,OAAO,QAAQ;AAElB,cAAM,UAAU;AAAA,UACd;AAAA,UACA;AAAA,UACA;AAAA,UACA,yBAAyB,MAAM;AAAA,QACjC;AAEA,cAAM,KAAK,IAAI,KAAK,QAAQ,UAAU,MAAM,QAAW,KAAK,OAAO;AAEnE,YAAI,UAAU,MAAM;AAIlB,gBAAM,WAAW,KAAK,QAAQ,kBAC1B,KAAK,QAAQ,gBAAgB,WAAW,GAAG,IAC3C,UAAU,OAAO,EAAE,KAAK,EAAE;AAE9B,cAAI,UAAU;AACZ,oBAAQ,KAAK,2BAA2B,QAAQ,EAAE;AAClD,eAAG,YAAY;AAAA,UACjB;AAAA,QACF;AAEA,YAAI,WAAW,kBAAkB,aAAa,GAAG;AAC/C,gBAAM,SAAS,WAAW,kBAAkB,aAAa,EAAE;AAC3D,gBAAM,QAAQ,UAAU,OAAO;AAAA,YAC7B,CAAC,kBAAkB,aAAa,GAAG,CAAC,MAAM;AAAA,UAC5C,CAAC;AACD,kBAAQ,KAAK,6BAA6B,KAAK,EAAE;AACjD,aAAG,cAAc;AAAA,QACnB;AAKA,aAAK,KAAK,WAAW,SAAS,GAAG;AAEjC,eAAO,MAAM,QAAQ,OAAO,MAAM,EAAE,KAAK,MAAM,CAAC;AAChD,eAAO,eAAe,SAAS,aAAa;AAE5C,WAAG,UAAU,QAAQ,MAAM;AAAA,UACzB,wBAAwB,KAAK,QAAQ;AAAA,UACrC,YAAY,KAAK,QAAQ;AAAA,UACzB,oBAAoB,KAAK,QAAQ;AAAA,QACnC,CAAC;AAED,YAAI,KAAK,SAAS;AAChB,eAAK,QAAQ,IAAI,EAAE;AACnB,aAAG,GAAG,SAAS,MAAM;AACnB,iBAAK,QAAQ,OAAO,EAAE;AAEtB,gBAAI,KAAK,oBAAoB,CAAC,KAAK,QAAQ,MAAM;AAC/C,sBAAQ,SAAS,WAAW,IAAI;AAAA,YAClC;AAAA,UACF,CAAC;AAAA,QACH;AAEA,WAAG,IAAI,GAAG;AAAA,MACZ;AAAA,IACF;AAEA,IAAAD,QAAO,UAAUG;AAYjB,aAAS,aAAa,QAAQ,KAAK;AACjC,iBAAW,SAAS,OAAO,KAAK,GAAG,EAAG,QAAO,GAAG,OAAO,IAAI,KAAK,CAAC;AAEjE,aAAO,SAAS,kBAAkB;AAChC,mBAAW,SAAS,OAAO,KAAK,GAAG,GAAG;AACpC,iBAAO,eAAe,OAAO,IAAI,KAAK,CAAC;AAAA,QACzC;AAAA,MACF;AAAA,IACF;AAQA,aAAS,UAAU,QAAQ;AACzB,aAAO,SAAS;AAChB,aAAO,KAAK,OAAO;AAAA,IACrB;AAOA,aAAS,gBAAgB;AACvB,WAAK,QAAQ;AAAA,IACf;AAWA,aAAS,eAAe,QAAQ,MAAM,SAAS,SAAS;AAStD,gBAAU,WAAW,KAAK,aAAa,IAAI;AAC3C,gBAAU;AAAA,QACR,YAAY;AAAA,QACZ,gBAAgB;AAAA,QAChB,kBAAkB,OAAO,WAAW,OAAO;AAAA,QAC3C,GAAG;AAAA,MACL;AAEA,aAAO,KAAK,UAAU,OAAO,OAAO;AAEpC,aAAO;AAAA,QACL,YAAY,IAAI,IAAI,KAAK,aAAa,IAAI,CAAC;AAAA,IACzC,OAAO,KAAK,OAAO,EAChB,IAAI,CAAC,MAAM,GAAG,CAAC,KAAK,QAAQ,CAAC,CAAC,EAAE,EAChC,KAAK,MAAM,IACd,aACA;AAAA,MACJ;AAAA,IACF;AAcA,aAAS,kCACP,QACA,KACA,QACA,MACA,SACA,SACA;AACA,UAAI,OAAO,cAAc,eAAe,GAAG;AACzC,cAAMC,OAAM,IAAI,MAAM,OAAO;AAC7B,cAAM,kBAAkBA,MAAK,iCAAiC;AAE9D,eAAO,KAAK,iBAAiBA,MAAK,QAAQ,GAAG;AAAA,MAC/C,OAAO;AACL,uBAAe,QAAQ,MAAM,SAAS,OAAO;AAAA,MAC/C;AAAA,IACF;AAAA;AAAA;;;ACziBA;AAAA;AAAA;AAAA;AAAA;;;ACAA,IAAAC,kBAA+D;AAC/D,uBAAqB;;;ACDrB,qBAA6B;AAA7B;AAQA,SAAS,2BAA+C;AACtD,MAAI,OAAwC;AAC1C,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,UAAmB,KAAK;AACxC,SAAO,WAAW;AACpB;AAEA,SAAS,mCAAuD;AAC9D,MAAI;AACF,UAAM,iBAAiB,IAAI,IAAI,mBAAmB,YAAY,GAAG;AACjE,UAAM,cAAc,KAAK;AAAA,UACvB,6BAAa,gBAAgB,OAAO;AAAA,IACtC;AACA,UAAM,UAAU,YAAY,SAAS,KAAK;AAC1C,WAAO,WAAW;AAAA,EACpB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,IAAM,iBACX,yBAAyB,KACzB,iCAAiC,KACjC;;;ADvBF,IAAM,6BAA6B;AACnC,IAAM,SAAS,KAAK,KAAK,KAAK;AAO9B,IAAM,WAAW;AACjB,IAAM,kBAAkB;AACxB,IAAM,eAAe;AAErB,IAAM,cAAc;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAM,iBAAiB;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAM,gBAAgB;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAM,uBAAuB;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEO,SAAS,oBAAoB,UAAU,gBAAyB;AACrE,SAAO,YAAY,KAAK,OAAO;AACjC;AAEO,SAAS,yBACd,UACA,UAAoD,CAAC,GAC7C;AACR,MAAI,oBAAoB,QAAQ,WAAW,cAAc,GAAG;AAC1D,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL,KAAK,KAAa;AAChB,eAAS,KAAK,iBAAiB,GAAG,CAAC;AAAA,IACrC;AAAA,IACA,KAAK,KAAa;AAChB,eAAS,KAAK,iBAAiB,GAAG,CAAC;AAAA,IACrC;AAAA,IACA,MAAM,KAAa;AACjB,eAAS,MAAM,iBAAiB,GAAG,CAAC;AAAA,IACtC;AAAA,EACF;AACF;AAQO,IAAM,mBAAN,MAAyC;AAAA,EAM9C,YACmB,UACjB,UACA,UAAmC,CAAC,GACpC;AAHiB;AAIjB,SAAK,cAAU,uBAAK,UAAU,WAAW,uBAAuB,MAAM;AACtE,SAAK,aAAa,CAAC,oBAAoB,QAAQ,WAAW,cAAc;AACxE,SAAK,gBACH,OAAO,SAAS,QAAQ,aAAa,MAAM,QAAQ,iBAAiB,KAAK,IACrE,QAAQ,gBACR;AAEN,mCAAU,KAAK,SAAS,EAAE,WAAW,KAAK,CAAC;AAC3C,UAAM,MAAM,oBAAI,KAAK;AACrB,SAAK,iBAAiB,GAAG;AACzB,SAAK,mBAAmB,WAAW,GAAG;AAAA,EACxC;AAAA,EArBiB;AAAA,EACA;AAAA,EACA;AAAA,EACT,mBAAkC;AAAA,EAoB1C,KAAK,KAAmB;AACtB,SAAK,eAAe,oBAAI,KAAK,CAAC;AAC9B,UAAM,UAAU,KAAK,iBAAiB,GAAG;AACzC,SAAK,SAAS,KAAK,OAAO;AAC1B,SAAK,OAAO,QAAQ,OAAO;AAAA,EAC7B;AAAA,EAEA,KAAK,KAAmB;AACtB,UAAM,UAAU,KAAK,iBAAiB,GAAG;AACzC,SAAK,SAAS,KAAK,OAAO;AAC1B,SAAK,OAAO,QAAQ,OAAO;AAAA,EAC7B;AAAA,EAEA,MAAM,KAAmB;AACvB,UAAM,UAAU,KAAK,iBAAiB,GAAG;AACzC,SAAK,SAAS,MAAM,OAAO;AAC3B,SAAK,OAAO,SAAS,OAAO;AAAA,EAC9B;AAAA,EAEQ,iBAAiB,KAAqB;AAC5C,WAAO,KAAK,aAAa,iBAAiB,GAAG,IAAI;AAAA,EACnD;AAAA,EAEQ,OAAO,OAAe,KAAmB;AAC/C,UAAM,MAAM,oBAAI,KAAK;AACrB,UAAM,UAAU,KAAK,eAAe,GAAG;AACvC,UAAM,OAAO,qBAAqB,GAAG;AACrC,UAAM,OAAO,GAAG,IAAI,KAAK,KAAK,KAAK,GAAG;AAAA;AACtC,QAAI;AACF,8CAAe,uBAAK,KAAK,SAAS,GAAG,OAAO,MAAM,GAAG,IAAI;AAAA,IAC3D,QAAQ;AAAA,IAER;AAAA,EACF;AAAA,EAEQ,eAAe,KAAmB;AACxC,UAAM,UAAU,WAAW,GAAG;AAC9B,QAAI,KAAK,qBAAqB,SAAS;AACrC,WAAK,iBAAiB,GAAG;AACzB,WAAK,mBAAmB;AAAA,IAC1B;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,iBAAiB,KAAiB;AACxC,UAAM,WAAW,IAAI,QAAQ,IAAI,KAAK,gBAAgB;AACtD,UAAM,aAAa,WAAW,IAAI,KAAK,QAAQ,CAAC;AAEhD,QAAI;AACF,iBAAW,aAAS,6BAAY,KAAK,SAAS,EAAE,eAAe,KAAK,CAAC,GAAG;AACtE,YAAI,CAAC,MAAM,OAAO,EAAG;AACrB,cAAM,QAAQ,6BAA6B,KAAK,MAAM,IAAI;AAC1D,YAAI,SAAS,MAAM,CAAC,IAAI,YAAY;AAClC,0CAAO,uBAAK,KAAK,SAAS,MAAM,IAAI,GAAG,EAAE,OAAO,KAAK,CAAC;AAAA,QACxD;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AACF;AAEO,SAAS,iBAAiB,KAAqB;AACpD,MAAI,WAAW,OAAO,GAAG;AAEzB,aAAW,yBAAyB,UAAU,aAAa,eAAe;AAC1E,aAAW,yBAAyB,UAAU,gBAAgB,QAAQ;AACtE,aAAW,yBAAyB,UAAU,eAAe,YAAY;AAEzE,aAAW;AAAA,IACT;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,aAAW,+BAA+B,UAAU,gBAAgB,QAAQ;AAC5E,aAAW,+BAA+B,UAAU,eAAe,YAAY;AAE/E,aAAW,qBAAqB,UAAU,aAAa,eAAe;AACtE,aAAW,qBAAqB,UAAU,gBAAgB,QAAQ;AAClE,aAAW,qBAAqB,UAAU,eAAe,YAAY;AAErE,aAAW,sBAAsB,UAAU,aAAa,eAAe;AACvE,aAAW,sBAAsB,UAAU,gBAAgB,QAAQ;AACnE,aAAW,kBAAkB,UAAU,oBAAoB;AAC3D,aAAW,mBAAmB,QAAQ;AACtC,aAAW,qBAAqB,QAAQ;AACxC,aAAW,aAAa,QAAQ;AAChC,aAAW,mBAAmB,QAAQ;AACtC,aAAW,gBAAgB,QAAQ;AACnC,aAAW,oBAAoB,QAAQ;AAEvC,SAAO;AACT;AAEA,SAAS,yBACP,OACA,MACA,aACQ;AACR,QAAM,aAAa,gBAAgB,IAAI;AACvC,SAAO,MAAM;AAAA,IACX,IAAI;AAAA,MACF,UAAU,UAAU;AAAA,MACpB;AAAA,IACF;AAAA,IACA,CAAC,QAAQ,OAAe,QACtB,GAAG,KAAK,GAAG,GAAG,GAAG,KAAK,MAAM,WAAW;AAAA,EAC3C;AACF;AAEA,SAAS,qBACP,OACA,MACA,aACQ;AACR,QAAM,aAAa,gBAAgB,IAAI;AACvC,SAAO,MAAM;AAAA,IACX,IAAI;AAAA,MACF,gBAAgB,UAAU;AAAA,MAC1B;AAAA,IACF;AAAA,IACA,CAAC,QAAQ,QAAgB,GAAG,GAAG,IAAI,WAAW;AAAA,EAChD;AACF;AAEA,SAAS,+BACP,OACA,MACA,aACQ;AACR,QAAM,aAAa,gBAAgB,IAAI;AACvC,QAAM,QAAQ,IAAI,OAAO,OAAO,UAAU,sBAAsB,IAAI;AACpE,MAAI,SAAS;AACb,MAAI,YAAY;AAChB,MAAI;AAEJ,SAAQ,QAAQ,MAAM,KAAK,KAAK,GAAI;AAClC,UAAM,aAAa,MAAM,YAAY;AACrC,UAAM,WAAW,uBAAuB,OAAO,UAAU;AACzD,QAAI,aAAa,MAAM;AACrB;AAAA,IACF;AAEA,cAAU,MAAM,MAAM,WAAW,MAAM,KAAK;AAC5C,cAAU,GAAG,MAAM,CAAC,CAAC,IAAI,WAAW;AACpC,gBAAY;AACZ,UAAM,YAAY;AAAA,EACpB;AAEA,MAAI,cAAc,GAAG;AACnB,WAAO;AAAA,EACT;AAEA,SAAO,SAAS,MAAM,MAAM,SAAS;AACvC;AAEA,SAAS,uBAAuB,OAAe,OAA8B;AAC3E,QAAM,OAAO,MAAM,KAAK;AACxB,QAAM,QAAQ,SAAS,MAAM,MAAM;AACnC,QAAM,QAAkB,CAAC,KAAK;AAC9B,MAAI,QAAuB;AAC3B,MAAI,UAAU;AAEd,WAAS,IAAI,QAAQ,GAAG,IAAI,MAAM,QAAQ,KAAK;AAC7C,UAAM,KAAK,MAAM,CAAC;AAElB,QAAI,OAAO;AACT,UAAI,SAAS;AACX,kBAAU;AAAA,MACZ,WAAW,OAAO,MAAM;AACtB,kBAAU;AAAA,MACZ,WAAW,OAAO,OAAO;AACvB,gBAAQ;AAAA,MACV;AACA;AAAA,IACF;AAEA,QAAI,OAAO,OAAQ,OAAO,KAAK;AAC7B,cAAQ;AACR;AAAA,IACF;AAEA,QAAI,OAAO,OAAO,OAAO,KAAK;AAC5B,YAAM,KAAK,OAAO,MAAM,MAAM,GAAG;AACjC;AAAA,IACF;AAEA,QAAI,OAAO,MAAM,MAAM,SAAS,CAAC,GAAG;AAClC,YAAM,IAAI;AACV,UAAI,MAAM,WAAW,GAAG;AACtB,eAAO,IAAI;AAAA,MACb;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,sBACP,OACA,MACA,aACQ;AACR,QAAM,aAAa,gBAAgB,IAAI;AACvC,SAAO,MAAM;AAAA,IACX,IAAI,OAAO,OAAO,UAAU,wBAAwB,IAAI;AAAA,IACxD,CAAC,QAAQ,QAAgB,GAAG,GAAG,KAAK,WAAW;AAAA,EACjD;AACF;AAEA,SAAS,kBAAkB,OAAe,MAAwB;AAChE,QAAM,aAAa,gBAAgB,IAAI;AACvC,SAAO,MAAM;AAAA,IACX,IAAI,OAAO,SAAS,UAAU,kBAAkB,IAAI;AAAA,IACpD,CAAC,QAAQ,WAAmB,GAAG,MAAM,GAAG,mBAAmB,QAAQ,CAAC;AAAA,EACtE;AACF;AAEA,SAAS,mBAAmB,OAAuB;AACjD,SAAO,MAAM;AAAA,IACX;AAAA,IACA,KAAK,eAAe;AAAA,EACtB;AACF;AAEA,SAAS,gBAAgB,OAAuB;AAC9C,SAAO,MAAM;AAAA,IACX;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,oBAAoB,OAAuB;AAClD,SAAO,MAAM,QAAQ,uBAAuB,eAAe;AAC7D;AAEA,SAAS,aAAa,OAAuB;AAC3C,SAAO,MAAM;AAAA,IACX;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,mBAAmB,OAAuB;AACjD,SAAO,MAAM;AAAA,IACX;AAAA,IACA,CAAC,UAAU,GAAG,MAAM,MAAM,GAAG,CAAC,CAAC,OAAO,MAAM,MAAM,EAAE,CAAC;AAAA,EACvD;AACF;AAEA,SAAS,qBAAqB,OAAuB;AACnD,SAAO,MAAM;AAAA,IAAQ;AAAA,IAA2B,CAAC,WAC/C,UAAU,MAAM;AAAA,EAClB;AACF;AAEA,SAAS,UAAU,QAAwB;AACzC,MAAI;AACF,UAAM,MAAM,IAAI,IAAI,MAAM;AAC1B,eAAW,OAAO,MAAM,KAAK,IAAI,aAAa,KAAK,CAAC,GAAG;AACrD,UACE,qBAAqB;AAAA,QACnB,CAAC,iBAAiB,aAAa,YAAY,MAAM,IAAI,YAAY;AAAA,MACnE,GACA;AACA,YAAI,aAAa,IAAI,KAAK,QAAQ;AAAA,MACpC;AAAA,IACF;AAEA,QAAI,oBAAoB,GAAG,GAAG;AAC5B,aAAO,GAAG,IAAI,MAAM,IAAI,YAAY;AAAA,IACtC;AAEA,WAAO,IAAI,SAAS;AAAA,EACtB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,oBAAoB,KAAmB;AAC9C,QAAM,OAAO,IAAI,SAAS,YAAY;AACtC,QAAMC,QAAO,mBAAmB,IAAI,QAAQ,EAAE,YAAY;AAC1D,MACE,uCAAuC,KAAK,IAAI,KAC7C,gDAAgD,KAAK,IAAI,GAC5D;AACA,WAAO;AAAA,EACT;AACA,SACE,4DAA4D,KAAKA,KAAI,KAClE,sDAAsD,KAAKA,KAAI;AAEtE;AAEA,SAAS,gBAAgB,MAAwB;AAC/C,SAAO,KAAK,IAAI,YAAY,EAAE,KAAK,GAAG;AACxC;AAEA,SAAS,aAAa,OAAuB;AAC3C,SAAO,MAAM,QAAQ,uBAAuB,MAAM;AACpD;AAEA,SAAS,WAAW,GAAiB;AACnC,QAAM,IAAI,EAAE,YAAY;AACxB,QAAM,IAAI,OAAO,EAAE,SAAS,IAAI,CAAC,EAAE,SAAS,GAAG,GAAG;AAClD,QAAM,MAAM,OAAO,EAAE,QAAQ,CAAC,EAAE,SAAS,GAAG,GAAG;AAC/C,SAAO,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG;AACzB;AAEO,SAAS,qBAAqB,GAAiB;AACpD,QAAM,IAAI,EAAE,YAAY;AACxB,QAAM,IAAI,OAAO,EAAE,SAAS,IAAI,CAAC,EAAE,SAAS,GAAG,GAAG;AAClD,QAAM,MAAM,OAAO,EAAE,QAAQ,CAAC,EAAE,SAAS,GAAG,GAAG;AAC/C,QAAM,KAAK,OAAO,EAAE,SAAS,CAAC,EAAE,SAAS,GAAG,GAAG;AAC/C,QAAM,KAAK,OAAO,EAAE,WAAW,CAAC,EAAE,SAAS,GAAG,GAAG;AACjD,QAAM,KAAK,OAAO,EAAE,WAAW,CAAC,EAAE,SAAS,GAAG,GAAG;AACjD,QAAM,KAAK,OAAO,EAAE,gBAAgB,CAAC,EAAE,SAAS,GAAG,GAAG;AAEtD,QAAM,gBAAgB,CAAC,EAAE,kBAAkB;AAC3C,QAAM,OAAO,iBAAiB,IAAI,MAAM;AACxC,QAAM,mBAAmB,KAAK,IAAI,aAAa;AAC/C,QAAM,cAAc,OAAO,KAAK,MAAM,mBAAmB,EAAE,CAAC,EAAE,SAAS,GAAG,GAAG;AAC7E,QAAM,aAAa,OAAO,mBAAmB,EAAE,EAAE,SAAS,GAAG,GAAG;AAEhE,SAAO,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,IAAI,GAAG,WAAW,IAAI,UAAU;AACpF;;;AEpdO,SAAS,qBAAqB,OAAgC;AACnE,MAAI,OAAO,UAAU,WAAW;AAC9B,WAAO,QAAQ,IAAI;AAAA,EACrB;AAEA,MAAI,OAAO,UAAU,UAAU;AAC7B,WAAO,oBAAoB,KAAK;AAAA,EAClC;AAEA,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AAEA,MAAI,MAAM,iBAAiB,QAAW;AACpC,WAAO,oBAAoB,MAAM,YAAY;AAAA,EAC/C;AAEA,MAAI,MAAM,WAAW,QAAW;AAC9B,WAAO,MAAM,SAAS,IAAI;AAAA,EAC5B;AAEA,SAAO;AACT;AAEO,SAAS,sBAAsB,aAA2B;AAC/D,MAAI,gBAAgB,KAAK,gBAAgB,GAAG;AAC1C,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,oBAAoB,OAAuB;AAClD,MAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,GAAG;AACzC,UAAM,IAAI,MAAM,wDAA0B;AAAA,EAC5C;AAEA,SAAO;AACT;;;AC7CA,IAAAC,kBAAiE;AACjE,sBAAkC;AAClC,IAAAC,oBAAqB;AAuBd,SAAS,wBAAwB,KAAgC;AACtE,MAAI,IAAI,UAAU;AAChB,UAAM,UAAM;AAAA,MACV,IAAI;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,YAAI,4BAAW,GAAG,EAAG,QAAO;AAAA,EAC9B;AACA,MAAI,IAAI,cAAc;AACpB,UAAM,UAAM,wBAAK,IAAI,cAAc,eAAe;AAClD,YAAI,4BAAW,GAAG,EAAG,QAAO;AAAA,EAC9B;AACA,SAAO;AACT;AAGO,SAAS,aAAa,KAAuB;AAClD,QAAM,UAAU;AAChB,QAAM,OAAiB,CAAC;AACxB,aAAW,aAAS,6BAAY,KAAK,EAAE,eAAe,KAAK,CAAC,GAAG;AAC7D,QAAI,CAAC,MAAM,OAAO,EAAG;AACrB,UAAM,IAAI,QAAQ,KAAK,MAAM,IAAI;AACjC,QAAI,EAAG,MAAK,KAAK,EAAE,CAAC,CAAC;AAAA,EACvB;AACA,SAAO,KAAK,KAAK,EAAE,QAAQ;AAC7B;AAGO,SAAS,aACd,KACA,SACsB;AACtB,QAAM,eAAW,wBAAK,KAAK,GAAG,OAAO,OAAO;AAC5C,MAAI,KAAC,4BAAW,QAAQ,EAAG,QAAO,CAAC;AACnC,MAAI;AACF,WAAO,KAAK,UAAM,8BAAa,UAAU,OAAO,CAAC;AAAA,EACnD,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAGO,SAAS,QAAgB;AAC9B,SAAOC,YAAW,oBAAI,KAAK,CAAC;AAC9B;AAGO,SAASA,YAAW,GAAiB;AAC1C,QAAM,IAAI,EAAE,YAAY;AACxB,QAAM,IAAI,OAAO,EAAE,SAAS,IAAI,CAAC,EAAE,SAAS,GAAG,GAAG;AAClD,QAAM,MAAM,OAAO,EAAE,QAAQ,CAAC,EAAE,SAAS,GAAG,GAAG;AAC/C,SAAO,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG;AACzB;AAGO,SAAS,QAAQ,GAAmB;AACzC,QAAM,IAAI,oBAAI,KAAK;AACnB,IAAE,QAAQ,EAAE,QAAQ,IAAI,CAAC;AACzB,SAAOA,YAAW,CAAC;AACrB;AAGO,SAAS,gBACd,MACA,MACA,IACU;AACV,SAAO,KAAK,OAAO,CAAC,MAAM,KAAK,QAAQ,KAAK,EAAE;AAChD;AAGO,SAAS,aACd,OACA,YACQ;AACR,QAAM,aACJ;AACF,MAAI,CAAC,WAAW,KAAK,KAAK,GAAG;AAC3B;AAAA,MACE;AAAA,MACA,GAAG,UAAU;AAAA,IACf;AAAA,EACF;AAEA,QAAM,KAAK,KAAK,MAAM,KAAK;AAC3B,MAAI,OAAO,MAAM,EAAE,GAAG;AACpB;AAAA,MACE;AAAA,MACA,GAAG,UAAU;AAAA,IACf;AAAA,EACF;AACA,SAAO;AACT;AAGO,SAAS,iCACd,OACsB;AACtB,SAAO,MAAM,KAAK,CAAC,GAAG,MAAM,KAAK,MAAM,EAAE,SAAS,IAAI,KAAK,MAAM,EAAE,SAAS,CAAC;AAC/E;AAEA,IAAM,mBAAmB;AAAA,EACvB,CAAC,gBAAM,UAAU,UAAU,kBAAkB,iBAAiB;AAAA,EAC9D,CAAC,4BAAQ,SAAS,UAAU,oBAAoB;AAAA,EAChD,CAAC,gBAAM,UAAU,QAAQ,uBAAuB,yBAAyB,qBAAqB;AAAA,EAC9F,CAAC,gBAAM,YAAY,2BAA2B;AAAA,EAC9C,CAAC,MAAM,kBAAQ,sBAAsB;AACvC;AAEA,SAAS,oBAAoB,OAAuB;AAClD,SAAO,MAAM,KAAK,EAAE,YAAY;AAClC;AAEA,SAAS,cAAc,OAAgC;AACrD,QAAM,aAAa,oBAAoB,KAAK;AAC5C,MAAI,CAAC,WAAY,QAAO;AACxB,SAAO,iBAAiB;AAAA,IAAK,CAAC,UAC5B,MAAM,KAAK,CAAC,cAAc,oBAAoB,SAAS,MAAM,UAAU;AAAA,EACzE,KAAK;AACP;AAEO,SAAS,6BACd,MACA,KACS;AACT,QAAM,SAAS,oBAAoB,GAAG;AACtC,MAAI,CAAC,OAAQ,QAAO;AAEpB,QAAM,aAAa,CAAC,KAAK,SAAS,KAAK,cAAc,EAClD,OAAO,CAAC,UAA2B,OAAO,UAAU,YAAY,MAAM,SAAS,CAAC;AACnF,MAAI,WAAW,KAAK,CAAC,cAAc,oBAAoB,SAAS,MAAM,MAAM,GAAG;AAC7E,WAAO;AAAA,EACT;AAEA,QAAM,cAAc,cAAc,GAAG;AACrC,MAAI,CAAC,YAAa,QAAO;AACzB,SAAO,WAAW,KAAK,CAAC,cAAc,cAAc,SAAS,MAAM,WAAW;AAChF;AAGA,eAAsB,kBAAkB,KAAgC;AACtE,QAAM,UAAU;AAChB,QAAM,OAAiB,CAAC;AACxB,QAAM,UAAU,UAAM,yBAAQ,KAAK,EAAE,eAAe,KAAK,CAAC;AAC1D,aAAW,SAAS,SAAS;AAC3B,QAAI,CAAC,MAAM,OAAO,EAAG;AACrB,UAAM,IAAI,QAAQ,KAAK,MAAM,IAAI;AACjC,QAAI,EAAG,MAAK,KAAK,EAAE,CAAC,CAAC;AAAA,EACvB;AACA,SAAO,KAAK,KAAK,EAAE,QAAQ;AAC7B;AAGA,eAAsB,kBACpB,KACA,SAC+B;AAC/B,QAAM,eAAW,wBAAK,KAAK,GAAG,OAAO,OAAO;AAC5C,MAAI,KAAC,4BAAW,QAAQ,EAAG,QAAO,CAAC;AACnC,MAAI;AACF,UAAM,UAAU,UAAM,0BAAS,UAAU,OAAO;AAChD,WAAO,KAAK,MAAM,OAAO;AAAA,EAC3B,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAGO,SAAS,SAAS,SAAuB;AAC9C,UAAQ,OAAO,MAAM,UAAU,IAAI;AACrC;AAGO,SAAS,OAAO,MAAqB;AAC1C,UAAQ,OAAO,MAAM,KAAK,UAAU,MAAM,MAAM,CAAC,IAAI,IAAI;AAC3D;AAGO,SAAS,UAAU,MAAc,SAAwB;AAC9D,SAAO,EAAE,IAAI,OAAO,OAAO,EAAE,MAAM,QAAQ,EAAE,CAAC;AAC9C,UAAQ,KAAK,CAAC;AAChB;AAGO,SAAS,qBAAqB,KAAgC;AACnE,MAAI,IAAI,UAAU;AAChB,UAAM,UAAM;AAAA,MACV,IAAI;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,YAAI,4BAAW,GAAG,EAAG,QAAO;AAAA,EAC9B;AACA,MAAI,IAAI,cAAc;AACpB,UAAM,UAAM,wBAAK,IAAI,cAAc,YAAY;AAC/C,YAAI,4BAAW,GAAG,EAAG,QAAO;AAAA,EAC9B;AACA,SAAO;AACT;AA0BO,SAAS,qBAAqB,KAAyB;AAC5D,MAAI;AACJ,MAAI,IAAI,UAAU;AAChB,eAAO,wBAAK,IAAI,UAAU,WAAW,uBAAuB,YAAY;AAAA,EAC1E,WAAW,IAAI,cAAc;AAC3B,eAAO,wBAAK,IAAI,cAAc,YAAY;AAAA,EAC5C,OAAO;AACL;AAAA,MACE;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACA,iCAAU,MAAM,EAAE,WAAW,KAAK,CAAC;AACnC,aAAO,wBAAK,MAAM,iBAAiB;AACrC;AASO,SAAS,mBACd,KACqB;AACrB,QAAM,gBAAY,wBAAK,KAAK,YAAY;AACxC,MAAI,KAAC,4BAAW,SAAS,EAAG,QAAO,CAAC;AACpC,MAAI;AACF,UAAM,MAAM,KAAK,UAAM,8BAAa,WAAW,OAAO,CAAC;AACvD,WAAO,MAAM,QAAQ,KAAK,UAAU,IAAI,IAAI,aAAa,CAAC;AAAA,EAC5D,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;;;AC3RO,IAAM,cAAc;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AACO,IAAM,eAAe;AAiBrB,SAAS,iBAAiB,UAAqC;AACpE,MAAI,CAAC,MAAM,QAAQ,QAAQ,GAAG;AAC5B,WAAO,EAAE,OAAO,OAAO,QAAQ,CAAC,EAAE,OAAO,YAAY,SAAS,iCAAQ,CAAC,EAAE;AAAA,EAC3E;AACA,MAAI,SAAS,WAAW,GAAG;AACzB,WAAO,EAAE,OAAO,OAAO,QAAQ,CAAC,EAAE,OAAO,YAAY,SAAS,2BAAO,CAAC,EAAE;AAAA,EAC1E;AACA,MAAI,SAAS,SAAS,cAAc;AAClC,WAAO;AAAA,MACL,OAAO;AAAA,MACP,QAAQ,CAAC,EAAE,OAAO,YAAY,SAAS,gBAAM,YAAY,UAAK,CAAC;AAAA,IACjE;AAAA,EACF;AAEA,QAAM,SAA4B,CAAC;AACnC,QAAM,WAAgC,CAAC;AACvC,WAAS,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;AACxC,oBAAgB,SAAS,CAAC,GAAG,YAAY,CAAC,KAAK,QAAQ,QAAQ;AAAA,EACjE;AAEA,MAAI,OAAO,SAAS,EAAG,QAAO,EAAE,OAAO,OAAO,OAAO;AACrD,SAAO,EAAE,OAAO,MAAM,UAAsC,SAAS;AACvE;AAMO,SAAS,yBAAyB,MAA8B;AACrE,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,IAAI;AAAA,EAC1B,QAAQ;AACN,cAAU,qBAAqB,oDAAsB;AAAA,EACvD;AAEA,QAAM,SAAS,iBAAiB,MAAM;AACtC,MAAI,CAAC,OAAO,OAAO;AACjB,WAAO,EAAE,IAAI,OAAO,OAAO,EAAE,MAAM,qBAAqB,SAAS,OAAO,OAAO,EAAE,CAAC;AAClF,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,SAAO,OAAO;AAChB;AAEA,SAAS,gBACP,KACA,QACA,QACA,UACM;AACN,MAAI,CAAC,SAAS,GAAG,GAAG;AAClB,WAAO,KAAK,EAAE,OAAO,QAAQ,SAAS,iCAAQ,CAAC;AAC/C;AAAA,EACF;AAEA,QAAM,OAAO,IAAI;AACjB,MAAI,CAAC,YAAY,SAAS,IAAoC,GAAG;AAC/D,WAAO,KAAK;AAAA,MACV,OAAO,GAAG,MAAM;AAAA,MAChB,SAAS,yCAAW,OAAO,IAAI,CAAC,4BAAQ,YAAY,KAAK,GAAG,CAAC;AAAA,IAC/D,CAAC;AAAA,EACH;AAEA,4BAA0B,IAAI,YAAY,GAAG,MAAM,eAAe,QAAQ,iGAAsB;AAEhG,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,gCAA0B,KAAK,QAAQ,MAAM;AAC7C,wCAAkC,IAAI,aAAa,GAAG,MAAM,gBAAgB,MAAM;AAClF,gCAA0B,IAAI,WAAW,GAAG,MAAM,cAAc,MAAM;AACtE,6BAAuB,IAAI,QAAQ,GAAG,MAAM,WAAW,MAAM;AAC7D,iCAA2B,IAAI,YAAY,GAAG,MAAM,eAAe,MAAM;AACzE;AAAA,IACF,KAAK;AACH,gCAA0B,KAAK,QAAQ,MAAM;AAC7C,wCAAkC,IAAI,aAAa,GAAG,MAAM,gBAAgB,MAAM;AAClF,gCAA0B,IAAI,WAAW,GAAG,MAAM,cAAc,MAAM;AACtE,6BAAuB,IAAI,QAAQ,GAAG,MAAM,WAAW,MAAM;AAC7D,iCAA2B,IAAI,YAAY,GAAG,MAAM,eAAe,MAAM;AAEzE,UAAI,CAAC,cAAc,IAAI,KAAgB,KAAK,CAAC,cAAc,IAAI,UAAqB,GAAG;AACrF,eAAO,KAAK;AAAA,UACV,OAAO;AAAA,UACP,SAAS;AAAA,QACX,CAAC;AAAA,MACH;AACA,wCAAkC,KAAK,QAAQ,QAAQ;AACvD;AAAA,IACF,KAAK;AACH,gCAA0B,KAAK,QAAQ,MAAM;AAC7C,mCAA6B,IAAI,eAAe,GAAG,MAAM,kBAAkB,MAAM;AACjF;AAAA,IACF,KAAK;AACH,gCAA0B,KAAK,QAAQ,MAAM;AAC7C,wCAAkC,IAAI,aAAa,GAAG,MAAM,gBAAgB,MAAM;AAClF;AAAA,IACF,KAAK;AACH,gCAA0B,KAAK,QAAQ,MAAM;AAC7C;AAAA,IACF,KAAK;AACH,yBAAmB,IAAI,QAAQ,GAAG,MAAM,WAAW,MAAM;AACzD;AAAA,IACF;AACE,wCAAkC,IAAI,YAAY,GAAG,MAAM,eAAe,MAAM;AAChF,4BAAsB,IAAI,OAAO,GAAG,MAAM,UAAU,MAAM;AAC1D,wCAAkC,IAAI,aAAa,GAAG,MAAM,gBAAgB,MAAM;AAClF,gCAA0B,IAAI,WAAW,GAAG,MAAM,cAAc,MAAM;AACtE,6BAAuB,IAAI,QAAQ,GAAG,MAAM,WAAW,MAAM;AAC7D,mCAA6B,IAAI,eAAe,GAAG,MAAM,kBAAkB,MAAM;AACjF,iCAA2B,IAAI,YAAY,GAAG,MAAM,eAAe,MAAM;AAAA,EAC7E;AACF;AAEA,SAAS,0BACP,KACA,QACA,QACM;AACN;AAAA,IACE,IAAI;AAAA,IACJ,GAAG,MAAM;AAAA,IACT;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,gBAAc,IAAI,OAAO,GAAG,MAAM,UAAU,MAAM;AAElD,MAAI,IAAI,SAAS,YAAY,IAAI,eAAe,GAAG;AACjD,WAAO,KAAK;AAAA,MACV,OAAO,GAAG,MAAM;AAAA,MAChB,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AACF;AAEA,SAAS,mBACP,OACA,OACA,QACM;AACN,MAAI,CAAC,MAAM,QAAQ,KAAK,GAAG;AACzB,WAAO,KAAK,EAAE,OAAO,SAAS,sFAAoC,CAAC;AACnE;AAAA,EACF;AAEA,MAAI,MAAM,SAAS,KAAK,MAAM,SAAS,GAAG;AACxC,WAAO,KAAK,EAAE,OAAO,SAAS,4CAAmB,CAAC;AAAA,EACpD;AAEA,QAAM,OAAO,oBAAI,IAAY;AAC7B,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,UAAM,QAAQ,MAAM,CAAC;AACrB,UAAM,SAAS,GAAG,KAAK,IAAI,CAAC;AAC5B,QAAI,CAAC,SAAS,KAAK,GAAG;AACpB,aAAO,KAAK,EAAE,OAAO,QAAQ,SAAS,iCAAQ,CAAC;AAC/C;AAAA,IACF;AAEA,UAAM,MAAM,MAAM;AAClB,QAAI,CAAC,OAAO,UAAU,GAAG,KAAM,MAAiB,KAAM,MAAiB,GAAG;AACxE,aAAO,KAAK,EAAE,OAAO,GAAG,MAAM,UAAU,SAAS,uDAAoB,CAAC;AAAA,IACxE,WAAW,KAAK,IAAI,GAAa,GAAG;AAClC,aAAO,KAAK,EAAE,OAAO,GAAG,MAAM,UAAU,SAAS,SAAS,GAAG,gBAAM,CAAC;AAAA,IACtE,OAAO;AACL,WAAK,IAAI,GAAa;AAAA,IACxB;AAEA;AAAA,MACE,MAAM;AAAA,MACN,GAAG,MAAM;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,kBAAc,MAAM,OAAO,GAAG,MAAM,UAAU,MAAM;AAAA,EACtD;AACF;AAEA,SAAS,6BACP,OACA,OACA,QACM;AACN,MAAI,UAAU,OAAW;AACzB,MAAI,CAAC,SAAS,KAAK,GAAG;AACpB,WAAO,KAAK,EAAE,OAAO,SAAS,iCAAQ,CAAC;AACvC;AAAA,EACF;AAEA;AAAA,IACE,MAAM;AAAA,IACN,GAAG,KAAK;AAAA,IACR;AAAA,IACA;AAAA,EACF;AACA;AAAA,IACE,MAAM;AAAA,IACN,GAAG,KAAK;AAAA,IACR;AAAA,IACA;AAAA,EACF;AACA;AAAA,IACE,MAAM;AAAA,IACN,GAAG,KAAK;AAAA,IACR;AAAA,IACA;AAAA,EACF;AACA;AAAA,IACE,MAAM;AAAA,IACN,GAAG,KAAK;AAAA,IACR;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,2BACP,OACA,OACA,QACM;AACN,MAAI,UAAU,OAAW;AACzB,MAAI,CAAC,SAAS,KAAK,GAAG;AACpB,WAAO,KAAK,EAAE,OAAO,SAAS,yDAA2B,CAAC;AAC1D;AAAA,EACF;AAEA,gBAAc,OAAO,OAAO,MAAM;AAClC;AAAA,IACE,MAAM;AAAA,IACN,GAAG,KAAK;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,sBACP,OACA,OACA,QACM;AACN,MAAI,UAAU,OAAW;AACzB,gBAAc,OAAO,OAAO,MAAM;AACpC;AAEA,SAAS,cACP,OACA,OACA,QACM;AACN,MAAI,CAAC,SAAS,KAAK,GAAG;AACpB,WAAO,KAAK,EAAE,OAAO,SAAS,8CAAgB,CAAC;AAC/C;AAAA,EACF;AAEA,wBAAsB,MAAM,GAAG,GAAG,KAAK,MAAM,QAAQ,GAAG,KAAK,kDAAe;AAC5E,wBAAsB,MAAM,GAAG,GAAG,KAAK,MAAM,QAAQ,GAAG,KAAK,kDAAe;AAC5E,wBAAsB,MAAM,GAAG,GAAG,KAAK,MAAM,QAAQ,GAAG,KAAK,kDAAe;AAC9E;AAEA,SAAS,0BACP,OACA,OACA,QACM;AACN,MAAI,UAAU,OAAW;AACzB,MAAI,UAAU,SAAS,UAAU,OAAO;AACtC,WAAO,KAAK,EAAE,OAAO,SAAS,8CAA0B,CAAC;AAAA,EAC3D;AACF;AAEA,SAAS,uBACP,OACA,OACA,QACM;AACN,MAAI,UAAU,OAAW;AACzB,MAAI,UAAU,KAAK,UAAU,KAAK,UAAU,GAAG;AAC7C,WAAO,KAAK,EAAE,OAAO,SAAS,kCAAmB,CAAC;AAAA,EACpD;AACF;AAEA,SAAS,kCACP,OACA,OACA,QACM;AACN,MAAI,UAAU,OAAW;AACzB,4BAA0B,OAAO,OAAO,QAAQ,+CAAY;AAC9D;AAEA,SAAS,uBACP,OACA,OACA,QACA,SACM;AACN,MAAI,UAAU,OAAW;AACzB,MAAI,CAAC,eAAe,KAAK,KAAK,SAAS,GAAG;AACxC,WAAO,KAAK,EAAE,OAAO,QAAQ,CAAC;AAAA,EAChC;AACF;AAEA,SAAS,0BACP,OACA,OACA,QACA,SACM;AACN,MAAI,CAAC,eAAe,KAAK,KAAK,QAAQ,GAAG;AACvC,WAAO,KAAK,EAAE,OAAO,QAAQ,CAAC;AAAA,EAChC;AACF;AAEA,SAAS,sBACP,OACA,OACA,QACA,KACA,KACA,SACM;AACN,MAAI,CAAC,eAAe,KAAK,KAAK,QAAQ,OAAO,QAAQ,KAAK;AACxD,WAAO,KAAK,EAAE,OAAO,QAAQ,CAAC;AAAA,EAChC;AACF;AAEA,SAAS,cACP,OACS;AACT,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO,CAAC,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC,EAAE,KAAK,CAAC,YAAY,eAAe,OAAO,KAAK,UAAU,CAAC;AAC7F;AAUA,SAAS,kCACP,KACA,QACA,UACM;AACN,QAAM,QAAQ,IAAI;AAClB,QAAM,aAAa,IAAI;AAIvB,QAAM,aAAa,gBAAgB,KAAK;AACxC,QAAM,aAAa,gBAAgB,UAAU;AAC7C,MAAI,CAAC,WAAY;AAEjB,QAAM,kBAAkB,YAAY;AACpC,QAAM,eAAe,eAAe,eAAe,IAAI,kBAAkB;AACzE,QAAM,WAAW,CAAC,CAAC,cAAc,WAAW,KAAK,CAAC,MAAM,IAAI,CAAC,KAAK,eAAe;AACjF,MAAI,SAAU;AAEd,QAAM,mBAAmB,WAAW,OAAO,CAAC,MAAM,IAAI,CAAC;AACvD,MAAI,iBAAiB,WAAW,EAAG;AACnC,MAAI,iBAAiB,CAAC,IAAI,IAAK;AAE/B,WAAS,KAAK;AAAA,IACZ,OAAO;AAAA,IACP,MAAM;AAAA,IACN,SACE;AAAA,EAEJ,CAAC;AACH;AAEA,SAAS,gBACP,OACiC;AACjC,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,IAAI,eAAe,MAAM,CAAC,IAAI,MAAM,IAAI;AAC9C,QAAM,IAAI,eAAe,MAAM,CAAC,IAAI,MAAM,IAAI;AAC9C,QAAM,IAAI,eAAe,MAAM,CAAC,IAAI,MAAM,IAAI;AAC9C,SAAO,CAAC,GAAG,GAAG,CAAC;AACjB;AAEA,SAAS,eAAe,OAAiC;AACvD,SAAO,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK;AAC3D;AAEA,SAAS,SAAS,OAAkD;AAClE,SAAO,UAAU,QAAQ,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK;AAC5E;;;ACtaO,IAAM,6BAA6B;AAAA,EACxC,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AACV;AAEO,IAAM,iCAAiC;AAAA,EAC5C,2BAA2B;AAAA,EAC3B,2BAA2B;AAAA,EAC3B,2BAA2B;AAAA,EAC3B,2BAA2B;AAC7B;AAEO,IAAM,wBAAwB;AAAA,EACnC,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AACV;AAEO,IAAM,4BAA4B;AAAA,EACvC,sBAAsB;AAAA,EACtB,sBAAsB;AAAA,EACtB,sBAAsB;AAAA,EACtB,sBAAsB;AACxB;;;AC1BA,IAAAC,kBAQO;AACP,IAAAC,oBAA+B;AAU/B,SAAS,eAAe,KAAsC;AAC5D,MAAI,IAAI,aAAc,QAAO,IAAI;AAEjC,MAAI,IAAI,UAAU;AAChB,UAAM,2BAAuB,wBAAK,IAAI,UAAU,WAAW;AAC3D,YAAI,4BAAW,oBAAoB,EAAG,QAAO;AAC7C,WAAO,IAAI;AAAA,EACb;AAEA,QAAM,IAAI,MAAM,4CAA4C;AAC9D;AAEA,SAAS,SAAS,KAAsC;AACtD,aAAO,wBAAK,eAAe,GAAG,GAAG,OAAO;AAC1C;AAEA,SAAS,6BAA6B,MAAsB;AAC1D,SAAO,KAAK,KAAK,EAAE,QAAQ,YAAY,EAAE;AAC3C;AAEA,SAAS,qBACP,KACA,MACiD;AACjD,QAAM,MAAM,SAAS,GAAG;AACxB,QAAM,iBAAiB,6BAA6B,IAAI;AACxD,MAAI,CAAC,eAAgB,QAAO;AAE5B,QAAM,oBAAgB,wBAAK,KAAK,cAAc;AAC9C,QAAM,aAAa,SAAS,aAAa;AACzC,MAAI,YAAY;AACd,WAAO;AAAA,MACL,SAAS;AAAA,MACT,MAAM;AAAA,IACR;AAAA,EACF;AAEA,MAAI,KAAC,4BAAW,GAAG,EAAG,QAAO;AAE7B,aAAW,aAAS,6BAAY,KAAK,EAAE,eAAe,KAAK,CAAC,GAAG;AAC7D,QAAI,CAAC,MAAM,YAAY,EAAG;AAE1B,UAAM,cAAU,wBAAK,KAAK,MAAM,IAAI;AACpC,UAAM,OAAO,SAAS,OAAO;AAC7B,QAAI,MAAM,SAAS,gBAAgB;AACjC,aAAO;AAAA,QACL;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,mBAAmB,OAAoC;AAC9D,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,QAAM,UAAU,MAAM,KAAK;AAC3B,SAAO,WAAW;AACpB;AAEA,SAAS,SAAS,SAAuC;AACvD,QAAM,eAAW,wBAAK,SAAS,WAAW;AAC1C,MAAI,KAAC,4BAAW,QAAQ,EAAG,QAAO;AAClC,MAAI;AACF,UAAM,MAAM,KAAK,UAAM,8BAAa,UAAU,OAAO,CAAC;AACtD,QAAI,CAAC,OAAO,OAAO,QAAQ,YAAY,MAAM,QAAQ,GAAG,EAAG,QAAO;AAClE,QAAI,IAAI,SAAS,aAAc,QAAO;AACtC,QAAI,CAAC,MAAM,QAAQ,IAAI,QAAQ,EAAG,QAAO;AACzC,UAAM,OAAO,mBAAmB,IAAI,IAAI,SAAK,4BAAS,OAAO;AAC7D,UAAM,QAAQ,mBAAmB,IAAI,KAAK,KAAK;AAC/C,UAAM,cAAc,mBAAmB,IAAI,WAAW,KAAK;AAC3D,UAAM,YACJ,mBAAmB,IAAI,SAAS,SAAK,0BAAS,QAAQ,EAAE,UAAU,YAAY;AAChF,UAAM,UAAU,OAAO,IAAI,YAAY,YAAY,IAAI,UAAU;AACjE,UAAM,cAAc,qBAAqB;AAAA,MACvC,QAAQ,IAAI;AAAA,MACZ,cAAc,IAAI;AAAA,IACpB,CAAC;AACD,0BAAsB,WAAW;AACjC,WAAO;AAAA,MACL,GAAG;AAAA,MACH;AAAA,MACA;AAAA,MACA,MAAM;AAAA,MACN;AAAA,MACA,UAAU,IAAI;AAAA,MACd,cAAc;AAAA,MACd;AAAA,MACA;AAAA,IACF;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,UAAU,SAAiB,MAA2B;AAC7D,yCAAc,wBAAK,SAAS,WAAW,GAAG,KAAK,UAAU,MAAM,MAAM,CAAC,GAAG,OAAO;AAClF;AAEO,SAAS,eAAe,KAA+C;AAC5E,QAAM,MAAM,SAAS,GAAG;AACxB,MAAI,KAAC,4BAAW,GAAG,EAAG,QAAO,CAAC;AAE9B,QAAM,QAAyB,CAAC;AAChC,aAAW,aAAS,6BAAY,KAAK,EAAE,eAAe,KAAK,CAAC,GAAG;AAC7D,QAAI,CAAC,MAAM,YAAY,EAAG;AAC1B,UAAM,OAAO,aAAS,wBAAK,KAAK,MAAM,IAAI,CAAC;AAC3C,QAAI,KAAM,OAAM,KAAK,IAAI;AAAA,EAC3B;AACA,SAAO;AACT;AASO,SAAS,gBACd,KACA,QAQyB;AACzB,QAAM,MAAM,SAAS,GAAG;AACxB,QAAM,cAAU,wBAAK,KAAK,OAAO,IAAI;AAErC,UAAI,4BAAW,OAAO,GAAG;AACvB,UAAM,IAAI,eAAe,kBAAkB,6BAAS,OAAO,IAAI,sBAAO;AAAA,EACxE;AAEA,iCAAU,SAAS,EAAE,WAAW,KAAK,CAAC;AAEtC,QAAM,cAAc,qBAAqB;AAAA,IACvC,QAAQ,OAAO;AAAA,IACf,cAAc,OAAO;AAAA,EACvB,CAAC;AACD,wBAAsB,WAAW;AAEjC,QAAM,OAAsB;AAAA,IAC1B,MAAM,OAAO;AAAA,IACb,OAAO,OAAO;AAAA,IACd,MAAM;AAAA,IACN,aAAa,OAAO;AAAA,IACpB,UAAU,OAAO;AAAA,IACjB,cAAc;AAAA,IACd,SAAS;AAAA,IACT,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,EACpC;AAEA,YAAU,SAAS,IAAI;AAEvB,SAAO,EAAE,KAAK;AAChB;AAEO,SAAS,gBACd,KACA,QASyB;AACzB,QAAM,WAAW,qBAAqB,KAAK,OAAO,IAAI;AACtD,QAAM,UAAU,UAAU;AAC1B,QAAM,OAAO,UAAU;AAEvB,MAAI,CAAC,WAAW,CAAC,MAAM;AACrB,UAAM,IAAI,eAAe,aAAa,6BAAS,OAAO,IAAI,sBAAO;AAAA,EACnE;AAEA,MAAI,OAAO,gBAAgB,QAAW;AACpC,SAAK,cAAc,OAAO;AAAA,EAC5B;AACA,MAAI,OAAO,UAAU,QAAW;AAC9B,SAAK,QAAQ,OAAO;AAAA,EACtB;AACA,MAAI,OAAO,aAAa,QAAW;AACjC,SAAK,WAAW,OAAO;AAAA,EACzB;AACA,MAAI,OAAO,WAAW,UAAa,OAAO,iBAAiB,QAAW;AACpE,SAAK,eAAe,qBAAqB;AAAA,MACvC,QAAQ,OAAO;AAAA,MACf,cAAc,OAAO;AAAA,IACvB,CAAC;AACD,0BAAsB,KAAK,YAAY;AAAA,EACzC;AACA,MAAI,OAAO,YAAY,QAAW;AAChC,SAAK,UAAU,OAAO;AAAA,EACxB;AAEA,OAAK,aAAY,oBAAI,KAAK,GAAE,YAAY;AACxC,YAAU,SAAS,IAAI;AAEvB,SAAO,EAAE,KAAK;AAChB;AAEO,SAAS,gBACd,KACA,MACkB;AAClB,QAAM,WAAW,qBAAqB,KAAK,IAAI;AAC/C,QAAM,UAAU,UAAU;AAC1B,QAAM,OAAO,UAAU;AAEvB,MAAI,CAAC,WAAW,CAAC,MAAM;AACrB,UAAM,IAAI,eAAe,aAAa,6BAAS,IAAI,sBAAO;AAAA,EAC5D;AAEA,8BAAO,SAAS,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAEhD,SAAO,EAAE,MAAM,KAAK,KAAK;AAC3B;AAEO,IAAM,iBAAN,cAA6B,MAAM;AAAA,EACxC,YACS,MACP,SACA;AACA,UAAM,OAAO;AAHN;AAIP,SAAK,OAAO;AAAA,EACd;AACF;;;AC7OA,SAAS,sBAAsB,QAAqC;AAClE,MAAI,CAAC,UAAU,OAAO,WAAW,SAAU,QAAO;AAElD,QAAM,MAAM;AACZ,QAAM,aAAa,CAAC,IAAI,MAAM,IAAI,IAAI,IAAI,QAAQ,IAAI,QAAQ;AAC9D,aAAW,aAAa,YAAY;AAClC,QAAI,OAAO,cAAc,SAAU;AACnC,UAAM,aAAa,UAAU,KAAK,EAAE,QAAQ,YAAY,EAAE;AAC1D,QAAI,WAAY,QAAO;AAAA,EACzB;AAEA,SAAO;AACT;AAEO,SAAS,0BACd,KACA,UACA,QACA,mBACM;AAGN,QAAM,4CAA4C,CAChD,QACA,YACS;AACT,QAAI,sBAAsB,QAAQ,CAAC,SAAS;AAC1C,0BAAoB,KAAK,SAAS,SAAS;AAC3C,aAAO,QAAQ,IAAI;AAAA,IACrB,CAAC;AAAA,EACH;AAGA,4CAA0C,2BAA2B,MAAM,OAAO,EAAE,QAAQ,MAAM;AAChG,QAAI;AACF,eAAS,OAAO;AAChB,YAAM,QAAQ,SAAS,KAAK,EAAE,IAAI,CAAC,UAAU;AAAA,QAC3C,GAAG;AAAA,QACH,IAAI,KAAK;AAAA,MACX,EAAE;AACF,cAAQ,MAAM,EAAE,IAAI,MAAM,MAAM,CAAC;AAAA,IACnC,SAASC,MAAU;AACjB,aAAO,KAAK,GAAG,2BAA2B,IAAI,YAAYA,MAAK,OAAO,EAAE;AACxE,cAAQ,OAAO,MAAM;AAAA,QACnB,MAAM;AAAA,QACN,SAASA,MAAK,WAAW;AAAA,MAC3B,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AAGD;AAAA,IACE,2BAA2B;AAAA,IAC3B,OAAO,EAAE,QAAQ,QAAQ,MAAM;AAC7B,YAAM,EAAE,MAAM,OAAO,aAAa,UAAU,QAAQ,aAAa,IAC/D;AACF,YAAM,gBAAgB,OAAO,UAAU,YAAY,MAAM,KAAK,IAAI,MAAM,KAAK,IAAI;AAEjF,UAAI,CAAC,QAAQ,OAAO,SAAS,UAAU;AACrC,gBAAQ,OAAO,MAAM,EAAE,MAAM,kBAAkB,SAAS,mBAAmB,CAAC;AAC5E;AAAA,MACF;AACA,UAAI,CAAC,eAAe,OAAO,gBAAgB,UAAU;AACnD,gBAAQ,OAAO,MAAM,EAAE,MAAM,kBAAkB,SAAS,0BAA0B,CAAC;AACnF;AAAA,MACF;AAEA,YAAM,aAAa,iBAAiB,QAAQ;AAC5C,UAAI,CAAC,WAAW,OAAO;AACrB,gBAAQ,OAAO,MAAM;AAAA,UACnB,MAAM;AAAA,UACN,SAAS,KAAK,UAAU,WAAW,MAAM;AAAA,QAC3C,CAAC;AACD;AAAA,MACF;AAEA,UAAI;AACJ,UAAI;AACF,sBAAc,qBAAqB,EAAE,QAAQ,aAAa,CAAC;AAC3D,8BAAsB,WAAW;AAAA,MACnC,SAASA,MAAU;AACjB,gBAAQ,OAAO,MAAM;AAAA,UACnB,MAAM;AAAA,UACN,SAASA,MAAK,WAAW;AAAA,QAC3B,CAAC;AACD;AAAA,MACF;AAEA,UAAI;AACF,cAAM,SAAS,MAAM,SAAS,OAAO;AAAA,UACnC;AAAA,UACA,OAAO;AAAA,UACP;AAAA,UACA,UAAU,WAAW;AAAA,UACrB,cAAc;AAAA,QAChB,CAAC;AACD,eAAO,KAAK,uBAAuB,IAAI,EAAE;AACzC,gBAAQ,MAAM;AAAA,UACZ,IAAI;AAAA,UACJ,IAAI,OAAO,KAAK;AAAA,UAChB,MAAM,OAAO,KAAK;AAAA,UAClB,OAAO,OAAO,KAAK;AAAA,UACnB,MAAM,OAAO;AAAA,QACf,CAAC;AAAA,MACH,SAASA,MAAU;AACjB,YAAIA,gBAAe,gBAAgB;AACjC,kBAAQ,OAAO,MAAM,EAAE,MAAMA,KAAI,MAAM,SAASA,KAAI,QAAQ,CAAC;AAAA,QAC/D,OAAO;AACL,iBAAO,KAAK,GAAG,2BAA2B,MAAM,YAAYA,MAAK,OAAO,EAAE;AAC1E,kBAAQ,OAAO,MAAM;AAAA,YACnB,MAAM;AAAA,YACN,SAASA,MAAK,WAAW;AAAA,UAC3B,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA;AAAA,IACE,2BAA2B;AAAA,IAC3B,OAAO,EAAE,QAAQ,QAAQ,MAAM;AAC7B,YAAM,EAAE,OAAO,aAAa,UAAU,QAAQ,cAAc,QAAQ,IAClE;AACF,YAAM,OAAO,sBAAsB,MAAM;AACzC,YAAM,gBAAgB,OAAO,UAAU,WAAW,MAAM,KAAK,IAAI;AAEjE,UAAI,CAAC,MAAM;AACT,gBAAQ,OAAO,MAAM;AAAA,UACnB,MAAM;AAAA,UACN,SAAS;AAAA,QACX,CAAC;AACD;AAAA,MACF;AACA,UAAI,UAAU,UAAa,CAAC,eAAe;AACzC,gBAAQ,OAAO,MAAM;AAAA,UACnB,MAAM;AAAA,UACN,SAAS;AAAA,QACX,CAAC;AACD;AAAA,MACF;AACA,UAAI,gBAAgB,UAAa,OAAO,gBAAgB,UAAU;AAChE,gBAAQ,OAAO,MAAM;AAAA,UACnB,MAAM;AAAA,UACN,SAAS;AAAA,QACX,CAAC;AACD;AAAA,MACF;AAEA,UAAI;AACJ,UAAI,aAAa,QAAW;AAC1B,cAAM,aAAa,iBAAiB,QAAQ;AAC5C,YAAI,CAAC,WAAW,OAAO;AACrB,kBAAQ,OAAO,MAAM;AAAA,YACnB,MAAM;AAAA,YACN,SAAS,KAAK,UAAU,WAAW,MAAM;AAAA,UAC3C,CAAC;AACD;AAAA,QACF;AACA,4BAAoB,WAAW;AAAA,MACjC;AAEA,UAAI;AACJ,UAAI,WAAW,UAAa,iBAAiB,QAAW;AACtD,YAAI;AACF,wBAAc,qBAAqB,EAAE,QAAQ,aAAa,CAAC;AAC3D,gCAAsB,WAAW;AAAA,QACnC,SAASA,MAAU;AACjB,kBAAQ,OAAO,MAAM;AAAA,YACnB,MAAM;AAAA,YACN,SAASA,MAAK,WAAW;AAAA,UAC3B,CAAC;AACD;AAAA,QACF;AAAA,MACF;AAEA,UAAI;AACF,cAAM,SAAS,MAAM,SAAS,OAAO;AAAA,UACnC;AAAA,UACA,OAAO;AAAA,UACP;AAAA,UACA,UAAU;AAAA,UACV,cAAc;AAAA,UACd;AAAA,QACF,CAAC;AACD,eAAO,KAAK,uBAAuB,IAAI,EAAE;AACzC,gBAAQ,MAAM;AAAA,UACZ,IAAI;AAAA,UACJ,IAAI,OAAO,KAAK;AAAA,UAChB,MAAM,OAAO,KAAK;AAAA,UAClB,OAAO,OAAO,KAAK;AAAA,UACnB,SAAS;AAAA,UACT,MAAM,OAAO;AAAA,QACf,CAAC;AAAA,MACH,SAASA,MAAU;AACjB,YAAIA,gBAAe,gBAAgB;AACjC,kBAAQ,OAAO,MAAM,EAAE,MAAMA,KAAI,MAAM,SAASA,KAAI,QAAQ,CAAC;AAAA,QAC/D,OAAO;AACL,iBAAO,KAAK,GAAG,2BAA2B,MAAM,YAAYA,MAAK,OAAO,EAAE;AAC1E,kBAAQ,OAAO,MAAM;AAAA,YACnB,MAAM;AAAA,YACN,SAASA,MAAK,WAAW;AAAA,UAC3B,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA;AAAA,IACE,2BAA2B;AAAA,IAC3B,OAAO,EAAE,QAAQ,QAAQ,MAAM;AAC7B,YAAM,OAAO,sBAAsB,MAA0C;AAE7E,UAAI,CAAC,MAAM;AACT,gBAAQ,OAAO,MAAM;AAAA,UACnB,MAAM;AAAA,UACN,SAAS;AAAA,QACX,CAAC;AACD;AAAA,MACF;AACA,UAAI;AACF,cAAM,SAAS,MAAM,SAAS,OAAO,IAAI;AACzC,eAAO,KAAK,uBAAuB,OAAO,IAAI,EAAE;AAChD,gBAAQ,MAAM;AAAA,UACZ,IAAI;AAAA,UACJ,IAAI,OAAO;AAAA,UACX,MAAM,OAAO;AAAA,UACb,SAAS;AAAA,QACX,CAAC;AAAA,MACH,SAASA,MAAU;AACjB,YAAIA,gBAAe,gBAAgB;AACjC,kBAAQ,OAAO,MAAM,EAAE,MAAMA,KAAI,MAAM,SAASA,KAAI,QAAQ,CAAC;AAAA,QAC/D,OAAO;AACL,iBAAO,KAAK,GAAG,2BAA2B,MAAM,YAAYA,MAAK,OAAO,EAAE;AAC1E,kBAAQ,OAAO,MAAM;AAAA,YACnB,MAAM;AAAA,YACN,SAASA,MAAK,WAAW;AAAA,UAC3B,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;AC9NO,IAAM,oBAAN,MAAwB;AAAA,EACZ;AAAA;AAAA,EAEA,QAAQ,oBAAI,IAA2B;AAAA;AAAA,EAEhD,aAA+B,QAAQ,QAAQ;AAAA,EAEvD,YAAY,KAA8B;AACxC,SAAK,MAAM;AACX,SAAK,OAAO;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,SAAe;AACb,SAAK,MAAM,MAAM;AACjB,eAAW,QAAQ,eAAe,KAAK,GAAG,GAAG;AAC3C,WAAK,MAAM,IAAI,KAAK,MAAM,IAAI;AAAA,IAChC;AAAA,EACF;AAAA;AAAA,EAGA,OAAwB;AACtB,WAAO,MAAM,KAAK,KAAK,MAAM,OAAO,CAAC;AAAA,EACvC;AAAA;AAAA,EAGA,aAA8B;AAC5B,WAAO,KAAK,KAAK,EAAE,OAAO,CAAC,SAAS,KAAK,OAAO;AAAA,EAClD;AAAA;AAAA,EAGA,IAAI,MAAoC;AACtC,WAAO,KAAK,MAAM,IAAI,IAAI,KAAK;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,OAAO,QAA6C;AACxD,WAAO,KAAK,aAAa,MAAM;AAC7B,YAAM,SAAS,gBAAgB,KAAK,KAAK,MAAM;AAC/C,WAAK,MAAM,IAAI,OAAO,KAAK,MAAM,OAAO,IAAI;AAC5C,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAO,QAA6C;AACxD,WAAO,KAAK,aAAa,MAAM;AAC7B,YAAM,SAAS,gBAAgB,KAAK,KAAK,MAAM;AAC/C,WAAK,MAAM,IAAI,OAAO,KAAK,MAAM,OAAO,IAAI;AAC5C,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAO,MAAqC;AAChD,WAAO,KAAK,aAAa,MAAM;AAC7B,YAAM,SAAS,gBAAgB,KAAK,KAAK,IAAI;AAC7C,WAAK,MAAM,OAAO,OAAO,IAAI;AAC7B,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,oBAA4B;AAC1B,UAAM,UAAU,KAAK,WAAW;AAChC,QAAI,QAAQ,WAAW,GAAG;AACxB,aAAO;AAAA,IACT;AAEA,UAAM,QAAkB;AAAA,MACtB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,UAAM,SAAS,CAAC,GAAG,OAAO,EAAE;AAAA,MAAK,CAAC,GAAG,OAClC,EAAE,aAAa,IAAI,cAAc,EAAE,aAAa,EAAE;AAAA,IACrD;AAEA,WAAO,QAAQ,CAAC,MAAM,QAAQ;AAC5B,YAAM;AAAA,QACJ,IAAI,MAAM,CAAC,YAAY,KAAK,KAAK;AAAA,QACjC,aAAa,KAAK,IAAI;AAAA,QACtB,oBAAoB,KAAK,WAAW;AAAA,QACpC;AAAA,MACF;AAAA,IACF,CAAC;AAED,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,WAAO,MAAM,KAAK,IAAI;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASQ,aAAgB,IAAyB;AAC/C,UAAM,OAAO,KAAK,WAAW;AAAA,MAC3B,MAAM,GAAG;AAAA,MACT,MAAM,GAAG;AAAA,IACX;AAEA,SAAK,aAAa,KAAK,MAAM,MAAM,MAAS;AAC5C,WAAO;AAAA,EACT;AACF;;;ACtKO,IAAM,qBAAqB;AAElC,IAAM,kBAAkB;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAGA,IAAM,qBAAqB;AAC3B,IAAM,qBAAqB;AAG3B,IAAM,mBAAmB,CAAC,KAAK,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,IAAI,IAAI,IAAI,EAAE;AAE/D,IAAM,oBAAoB,CAAC,IAAI,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,MAAM,MAAM,MAAM,IAAI;AACnF,IAAM,kBAAkB,CAAC,MAAM,MAAM,MAAM,MAAM,MAAM,IAAI;AAC3D,IAAM,mBAAmB,CAAC,IAAI,IAAI,IAAI,KAAK,KAAK,GAAG;AACnD,IAAM,cAAc,CAAC,GAAG,IAAI,IAAI,KAAK,KAAK,GAAG;AAC7C,IAAM,8BAA8B,CAAC,GAAG,IAAI,IAAI,IAAI,KAAK,KAAK,GAAG;AACjE,IAAM,mCAAmC,EAAE,GAAG,GAAG,GAAG,MAAM,GAAG,KAAK;AAClE,IAAM,gCAAgC,EAAE,GAAG,GAAG,GAAG,MAAM,GAAG,KAAK;AAS/D,IAAM,gBAAsD;AAAA,EAC1D,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,aAAa;AACf;AAEO,SAAS,yBACd,UACA,aACA,qBACQ;AACR,qBAAmB,QAAQ;AAC3B,sBAAoB,QAAQ;AAE5B,QAAM,cAAc,qBAAqB,WAAW;AACpD,wBAAsB,WAAW;AAEjC,QAAM,cAAc,mBAAmB,qBAAqB,QAAQ;AACpE,QAAM,YAAY,gBAAgB,IAAI,qBAAqB;AAC3D,QAAM,UAAU,SAAS,IAAI,CAAC,YAAY,cAAc,OAAO,CAAC,EAAE,KAAK,EAAE;AACzE,SAAO,GAAG,WAAW,GAAG,SAAS,GAAG,OAAO;AAC7C;AAEA,SAAS,mBACP,UACA,UACQ;AACR,QAAM,UAAU,UAAU,KAAK;AAC/B,MAAI,QAAS,QAAO;AACpB,SAAO,kBAAkB,QAAQ;AACnC;AAEA,SAAS,mBAAmB,UAAgC;AAC1D,MAAI,SAAS,SAAS,KAAK,SAAS,SAAS,oBAAoB;AAC/D,UAAM,IAAI,MAAM,4BAA4B,kBAAkB,WAAW;AAAA,EAC3E;AACF;AAEA,SAAS,kBAAkB,UAAkC;AAC3D,QAAM,WAAW,SAAS,IAAI,CAAC,YAAY,QAAQ,IAAI,EAAE,KAAK,GAAG;AACjE,SAAO,WAAW,QAAQ,KAAK,SAAS,MAAM,WAAW,SAAS,SAAS,IAAI,MAAM,EAAE;AACzF;AAEA,SAAS,oBAAoB,UAAgC;AAC3D,QAAM,aAAa,iBAAiB,QAAQ;AAC5C,MAAI,CAAC,WAAW,OAAO;AACrB,UAAM,IAAI;AAAA,MACR,WAAW,OAAO,IAAI,CAAC,UAAU,GAAG,MAAM,KAAK,KAAK,MAAM,OAAO,EAAE,EAAE,KAAK,IAAI;AAAA,IAChF;AAAA,EACF;AACF;AAEA,SAAS,cAAc,SAA+B;AACpD,QAAM,SAAS;AAAA,IACb,cAAc,QAAQ,IAAI;AAAA,IAC1B,iBAAiB,QAAQ,UAAU;AAAA,EACrC;AAEA,MAAI;AACJ,UAAQ,QAAQ,MAAM;AAAA,IACpB,KAAK;AAAA,IACL,KAAK;AACH,YAAM,QAAQ,uBAAuB,QAAQ,KAAK;AAClD,YAAM,aAAa,uBAAuB,QAAQ,UAAU;AAC5D,eAAS;AAAA,QACP,GAAG;AAAA,QACH,SAAS,QAAQ,eAAe,KAAK,iBAAiB;AAAA,QACtD,wBAAwB,QAAQ,cAAc,CAAC;AAAA,QAC/C,SAAS,MAAM,GAAG,WAAW;AAAA,QAC7B,SAAS,MAAM,GAAG,WAAW;AAAA,QAC7B,SAAS,MAAM,GAAG,WAAW;AAAA,QAC7B,QAAQ,cAAc,QAAQ,IAAI;AAAA,QAClC,eAAe,QAAQ,UAAU,CAAC;AAAA,QAClC,SAAS,WAAW,GAAG,WAAW;AAAA,QAClC,SAAS,WAAW,GAAG,WAAW;AAAA,QAClC,SAAS,WAAW,GAAG,WAAW;AAAA,QAClC,SAAS,QAAQ,YAAY,cAAc,GAAG,2BAA2B;AAAA,MAC3E;AACA;AAAA,IACF,KAAK;AACH,YAAM,cAAc,uBAAuB,QAAQ,KAAK;AACxD,eAAS;AAAA,QACP,GAAG;AAAA,QACH,uBAAuB,QAAQ,eAAe,OAAO;AAAA,QACrD,sBAAsB,QAAQ,eAAe,OAAO;AAAA,QACpD,uBAAuB,QAAQ,eAAe,OAAO;AAAA,QACrD,sBAAsB,QAAQ,eAAe,MAAM;AAAA,QACnD,wBAAwB,QAAQ,cAAc,CAAC;AAAA,QAC/C,SAAS,YAAY,GAAG,WAAW;AAAA,QACnC,SAAS,YAAY,GAAG,WAAW;AAAA,QACnC,SAAS,YAAY,GAAG,WAAW;AAAA,MACrC;AACA;AAAA,IACF,KAAK;AACH,YAAM,cAAc,uBAAuB,QAAQ,KAAK;AACxD,eAAS;AAAA,QACP,GAAG;AAAA,QACH,SAAS,QAAQ,eAAe,KAAK,iBAAiB;AAAA,QACtD,wBAAwB,QAAQ,cAAc,CAAC;AAAA,QAC/C,SAAS,YAAY,GAAG,WAAW;AAAA,QACnC,SAAS,YAAY,GAAG,WAAW;AAAA,QACnC,SAAS,YAAY,GAAG,WAAW;AAAA,MACrC;AACA;AAAA,IACF,KAAK;AACH,YAAM,cAAc,uBAAuB,QAAQ,KAAK;AACxD,eAAS;AAAA,QACP,GAAG;AAAA,QACH,wBAAwB,QAAQ,cAAc,CAAC;AAAA,QAC/C,SAAS,YAAY,GAAG,WAAW;AAAA,QACnC,SAAS,YAAY,GAAG,WAAW;AAAA,QACnC,SAAS,YAAY,GAAG,WAAW;AAAA,MACrC;AACA;AAAA,IACF,KAAK;AACH,eAAS,uBAAuB,QAAQ,OAAO;AAC/C;AAAA,EACJ;AAEA,SAAO,OAAO,IAAI,CAAC,UAAU,gBAAgB,KAAK,CAAC,EAAE,KAAK,EAAE;AAC9D;AAEA,SAAS,uBAAuB,QAAkB,SAAiC;AACjF,QAAM,SAAS,QAAQ,UAAU,CAAC;AAClC,SAAO;AAAA,IACL,GAAG;AAAA,IACH,OAAO,SAAS;AAAA,IAChB,GAAG,OAAO,QAAQ,CAAC,UAAU;AAC3B,YAAM,QAAQ,uBAAuB,MAAM,KAAK;AAChD,aAAO;AAAA,QACL,MAAM;AAAA,QACN,SAAS,MAAM,GAAG,WAAW;AAAA,QAC7B,SAAS,MAAM,GAAG,WAAW;AAAA,QAC7B,SAAS,MAAM,GAAG,WAAW;AAAA,QAC7B,wBAAwB,MAAM,UAAU;AAAA,MAC1C;AAAA,IACF,CAAC;AAAA,EACH;AACF;AAEO,SAAS,uBACd,OAIqC;AACrC,QAAM,aAAa;AAAA,IACjB,GAAG,OAAO,KAAK;AAAA,IACf,GAAG,OAAO,KAAK;AAAA,IACf,GAAG,OAAO,KAAK;AAAA,EACjB;AAEA,MAAI,yBAAyB,UAAU,GAAG;AACxC,WAAO,+BAA+B,YAAY,6BAA6B;AAAA,EACjF;AAEA,MAAI,iCAAiC,UAAU,KAAK,GAAG;AACrD,WAAO;AAAA,EACT;AAEA,SAAO,+BAA+B,YAAY,gCAAgC;AACpF;AAEA,SAAS,iCAAiC,OAAoD;AAC5F,SAAO,OAAO,MAAM,IAAI,CAAC,IAAI,OAAO,MAAM,IAAI,CAAC,IAAI,OAAO,MAAM,IAAI,CAAC;AACvE;AAEA,SAAS,yBAAyB,OAAqD;AACrF,SAAO,MAAM,MAAM,OAAO,MAAM,MAAM,OAAO,MAAM,MAAM;AAC3D;AAEA,SAAS,+BACP,OACA,cACqC;AACrC,SAAO;AAAA,IACL,GAAG,0BAA0B,MAAM,GAAG,aAAa,CAAC;AAAA,IACpD,GAAG,0BAA0B,MAAM,GAAG,aAAa,CAAC;AAAA,IACpD,GAAG,0BAA0B,MAAM,GAAG,aAAa,CAAC;AAAA,EACtD;AACF;AAEA,SAAS,0BAA0B,OAAe,aAA6B;AAC7E,SAAO,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,KAAK,MAAM,QAAQ,WAAW,CAAC,CAAC;AACnE;AAEA,SAAS,SAAS,OAAe,OAAkC;AACjE,MAAI,YAAY;AAChB,MAAI,eAAe,OAAO;AAE1B,aAAW,CAAC,OAAO,IAAI,KAAK,MAAM,QAAQ,GAAG;AAC3C,UAAM,WAAW,KAAK,IAAI,QAAQ,IAAI;AACtC,QAAI,WAAW,cAAc;AAC3B,kBAAY;AACZ,qBAAe;AAAA,IACjB;AAAA,EACF;AAEA,SAAO;AACT;AAGA,SAAS,iBAAiB,YAA4B;AACpD,MAAI,eAAe,EAAG,QAAO;AAC7B,SAAO,SAAS,YAAY,gBAAgB;AAC9C;AAMA,SAAS,wBAAwB,YAA4B;AAC3D,MAAI,eAAe,EAAG,QAAO;AAC7B,SAAO,SAAS,YAAY,gBAAgB;AAC9C;AAEA,SAAS,uBAAuB,OAAmC;AACjE,SAAO,SAAS,SAAS,MAAM,eAAe;AAChD;AAEA,SAAS,sBAAsB,OAAmC;AAChE,MAAI,UAAU,GAAG;AACf,WAAO;AAAA,EACT;AAEA,SAAO,SAAS,SAAS,MAAM,gBAAgB,MAAM,GAAG,CAAC,CAAC;AAC5D;AAEA,SAAS,eAAe,OAA0B;AAChD,SAAO,QAAQ;AACjB;;;AC1QA,IAAM,oBAAoB;AAAA,EACxB,MAAM;AAAA,EACN,UAAU,CAAC,QAAQ,YAAY;AAAA,EAC/B,sBAAsB;AAAA,EACtB,YAAY;AAAA,IACV,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,MAAM,CAAC,QAAQ,UAAU,UAAU,UAAU,cAAc,aAAa;AAAA,MACxE,aACE;AAAA,IAIJ;AAAA,IACA,YAAY,EAAE,MAAM,UAAU,SAAS,GAAG,aAAa,6EAAiB;AAAA,IACxE,YAAY,EAAE,MAAM,UAAU,SAAS,GAAG,SAAS,IAAI;AAAA,IACvD,OAAO;AAAA,MACL,MAAM;AAAA,MACN,UAAU,CAAC,KAAK,KAAK,GAAG;AAAA,MACxB,sBAAsB;AAAA,MACtB,YAAY;AAAA,QACV,GAAG,EAAE,MAAM,UAAU,SAAS,GAAG,SAAS,IAAI;AAAA,QAC9C,GAAG,EAAE,MAAM,UAAU,SAAS,GAAG,SAAS,IAAI;AAAA,QAC9C,GAAG,EAAE,MAAM,UAAU,SAAS,GAAG,SAAS,IAAI;AAAA,MAChD;AAAA,IACF;AAAA,IACA,aAAa,EAAE,MAAM,UAAU,SAAS,EAAE;AAAA,IAC1C,WAAW,EAAE,MAAM,UAAU,MAAM,CAAC,OAAO,KAAK,EAAE;AAAA,IAClD,QAAQ,EAAE,MAAM,UAAU,MAAM,CAAC,GAAG,GAAG,CAAC,EAAE;AAAA,IAC1C,eAAe;AAAA,MACb,MAAM;AAAA,MACN,sBAAsB;AAAA,MACtB,YAAY;AAAA,QACV,SAAS,EAAE,MAAM,UAAU,SAAS,EAAE;AAAA,QACtC,SAAS,EAAE,MAAM,UAAU,SAAS,EAAE;AAAA,QACtC,SAAS,EAAE,MAAM,UAAU,SAAS,EAAE;AAAA,QACtC,QAAQ,EAAE,MAAM,UAAU,SAAS,EAAE;AAAA,MACvC;AAAA,IACF;AAAA,IACA,QAAQ,EAAE,MAAM,SAAS,OAAO,EAAE,MAAM,SAAS,OAAO,EAAE,MAAM,SAAS,EAAE,EAAE;AAAA,IAC7E,mBAAmB,EAAE,MAAM,UAAU,SAAS,EAAE;AAAA,IAChD,YAAY;AAAA,MACV,MAAM;AAAA,MACN,UAAU,CAAC,KAAK,KAAK,GAAG;AAAA,MACxB,sBAAsB;AAAA,MACtB,YAAY;AAAA,QACV,GAAG,EAAE,MAAM,UAAU,SAAS,GAAG,SAAS,IAAI;AAAA,QAC9C,GAAG,EAAE,MAAM,UAAU,SAAS,GAAG,SAAS,IAAI;AAAA,QAC9C,GAAG,EAAE,MAAM,UAAU,SAAS,GAAG,SAAS,IAAI;AAAA,MAChD;AAAA,IACF;AAAA,EACF;AACF;AAEA,IAAM,iBAAiB;AAAA,EACrB,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,UAAU;AAAA,EACV,OAAO;AACT;AAEA,SAAS,GAAG,MAA8E;AACxF,SAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,KAAK,UAAU,IAAI,EAAE,CAAC,GAAG,SAAS,KAAK;AAC3F;AAEA,SAAS,IACP,MACA,SACgE;AAChE,QAAM,OAAO,EAAE,IAAI,OAAO,OAAO,EAAE,MAAM,QAAQ,EAAE;AACnD,SAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,KAAK,UAAU,IAAI,EAAE,CAAC,GAAG,SAAS,KAAK;AAC3F;AAEO,SAAS,wBACd,KACA,UACA,QACM;AAEN,MAAI,aAAa;AAAA,IACf,MAAM,sBAAsB;AAAA,IAC5B,OAAO;AAAA,IACP,aACE;AAAA,IAEF,YAAY,EAAE,MAAM,UAAU,YAAY,CAAC,GAAG,sBAAsB,MAAM;AAAA,IAC1E,MAAM,QAAQ,aAAa,SAAS;AAClC,UAAI;AACF,iBAAS,OAAO;AAChB,cAAM,QAAQ,SAAS,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,GAAG,MAAM,IAAI,KAAK,KAAK,EAAE;AACxE,eAAO,GAAG,EAAE,IAAI,MAAM,MAAM,CAAC;AAAA,MAC/B,SAAS,GAAQ;AACf,eAAO,KAAK,GAAG,sBAAsB,IAAI,iBAAiB,GAAG,OAAO,EAAE;AACtE,eAAO,IAAI,kBAAkB,GAAG,WAAW,eAAe;AAAA,MAC5D;AAAA,IACF;AAAA,EACF,CAAC;AAGD,MAAI,aAAa;AAAA,IACf,MAAM,sBAAsB;AAAA,IAC5B,OAAO;AAAA,IACP,aACE;AAAA,IAGF,YAAY;AAAA,MACV,MAAM;AAAA,MACN,UAAU,CAAC,QAAQ,SAAS,eAAe,UAAU;AAAA,MACrD,sBAAsB;AAAA,MACtB,YAAY;AAAA,QACV,MAAM;AAAA,UACJ,MAAM;AAAA,UACN,aAAa;AAAA,QACf;AAAA,QACA,OAAO;AAAA,UACL,MAAM;AAAA,UACN,aACE;AAAA,QACJ;AAAA,QACA,aAAa;AAAA,UACX,MAAM;AAAA,UACN,aACE;AAAA,QACJ;AAAA,QACA,UAAU;AAAA,QACV,cAAc;AAAA,UACZ,MAAM;AAAA,UACN,aAAa;AAAA,QACf;AAAA,MACF;AAAA,IACF;AAAA,IACA,MAAM,QAAQ,aAAa,QAAQ;AACjC,YAAM,EAAE,MAAM,OAAO,aAAa,UAAU,aAAa,IACvD;AACF,YAAM,gBAAgB,OAAO,UAAU,YAAY,MAAM,KAAK,IAAI,MAAM,KAAK,IAAI;AAEjF,UAAI,CAAC,QAAQ,OAAO,SAAS;AAC3B,eAAO,IAAI,kBAAkB,kBAAkB;AACjD,UAAI,CAAC,eAAe,OAAO,gBAAgB;AACzC,eAAO,IAAI,kBAAkB,yBAAyB;AAExD,YAAM,aAAa,iBAAiB,QAAQ;AAC5C,UAAI,CAAC,WAAW,MAAO,QAAO,IAAI,qBAAqB,KAAK,UAAU,WAAW,MAAM,CAAC;AAExF,UAAI;AACJ,UAAI;AACF,sBAAc,qBAAqB,EAAE,aAAa,CAAC;AACnD,8BAAsB,WAAW;AAAA,MACnC,SAAS,GAAQ;AACf,eAAO,IAAI,qBAAqB,GAAG,WAAW,eAAe;AAAA,MAC/D;AAEA,UAAI;AACF,cAAM,SAAS,MAAM,SAAS,OAAO;AAAA,UACnC;AAAA,UACA,OAAO;AAAA,UACP;AAAA,UACA,UAAU,WAAW;AAAA,UACrB,cAAc;AAAA,QAChB,CAAC;AACD,eAAO,KAAK,GAAG,sBAAsB,MAAM,kBAAkB,IAAI,EAAE;AACnE,mBAAW,WAAW,WAAW,UAAU;AACzC,iBAAO;AAAA,YACL,GAAG,sBAAsB,MAAM,wBAAwB,QAAQ,IAAI,KAAK,QAAQ,KAAK,KAAK,QAAQ,OAAO;AAAA,UAC3G;AAAA,QACF;AACA,eAAO,GAAG;AAAA,UACR,IAAI;AAAA,UACJ,IAAI,OAAO,KAAK;AAAA,UAChB,MAAM,OAAO,KAAK;AAAA,UAClB,OAAO,OAAO,KAAK;AAAA,UACnB,MAAM,OAAO;AAAA,UACb,GAAI,WAAW,SAAS,SAAS,IAAI,EAAE,UAAU,WAAW,SAAS,IAAI,CAAC;AAAA,QAC5E,CAAC;AAAA,MACH,SAAS,GAAQ;AACf,YAAI,aAAa,eAAgB,QAAO,IAAI,EAAE,MAAM,EAAE,OAAO;AAC7D,eAAO,KAAK,GAAG,sBAAsB,MAAM,iBAAiB,GAAG,OAAO,EAAE;AACxE,eAAO,IAAI,kBAAkB,GAAG,WAAW,eAAe;AAAA,MAC5D;AAAA,IACF;AAAA,EACF,CAAC;AAGD,MAAI,aAAa;AAAA,IACf,MAAM,sBAAsB;AAAA,IAC5B,OAAO;AAAA,IACP,aACE;AAAA,IAEF,YAAY;AAAA,MACV,MAAM;AAAA,MACN,UAAU,CAAC,MAAM;AAAA,MACjB,sBAAsB;AAAA,MACtB,YAAY;AAAA,QACV,MAAM,EAAE,MAAM,UAAU,aAAa,6FAAkB;AAAA,QACvD,OAAO;AAAA,UACL,MAAM;AAAA,UACN,aAAa;AAAA,QACf;AAAA,QACA,aAAa,EAAE,MAAM,UAAU,aAAa,2EAAe;AAAA,QAC3D,SAAS,EAAE,MAAM,WAAW,aAAa,4CAAmB;AAAA,QAC5D,UAAU,EAAE,GAAG,gBAAgB,aAAa,qHAAsB;AAAA,QAClE,cAAc,EAAE,MAAM,UAAU,aAAa,+DAAa;AAAA,MAC5D;AAAA,IACF;AAAA,IACA,MAAM,QAAQ,aAAa,QAAQ;AACjC,YAAM,EAAE,MAAM,OAAO,aAAa,SAAS,UAAU,aAAa,IAChE;AACF,YAAM,gBAAgB,OAAO,UAAU,WAAW,MAAM,KAAK,IAAI;AAEjE,UAAI,CAAC,QAAQ,OAAO,SAAS;AAC3B,eAAO;AAAA,UACL;AAAA,UACA;AAAA,QACF;AACF,UAAI,UAAU,UAAa,CAAC;AAC1B,eAAO,IAAI,kBAAkB,kCAAkC;AACjE,UAAI,gBAAgB,UAAa,OAAO,gBAAgB;AACtD,eAAO,IAAI,kBAAkB,8BAA8B;AAE7D,UAAI;AACJ,UAAI,kBAAuC,CAAC;AAC5C,UAAI,aAAa,QAAW;AAC1B,cAAM,aAAa,iBAAiB,QAAQ;AAC5C,YAAI,CAAC,WAAW,MAAO,QAAO,IAAI,qBAAqB,KAAK,UAAU,WAAW,MAAM,CAAC;AACxF,4BAAoB,WAAW;AAC/B,0BAAkB,WAAW;AAAA,MAC/B;AAEA,UAAI;AACJ,UAAI,iBAAiB,QAAW;AAC9B,YAAI;AACF,wBAAc,qBAAqB,EAAE,aAAa,CAAC;AACnD,gCAAsB,WAAW;AAAA,QACnC,SAAS,GAAQ;AACf,iBAAO,IAAI,qBAAqB,GAAG,WAAW,eAAe;AAAA,QAC/D;AAAA,MACF;AAEA,UAAI;AACF,cAAM,SAAS,MAAM,SAAS,OAAO;AAAA,UACnC;AAAA,UACA,OAAO;AAAA,UACP;AAAA,UACA,UAAU;AAAA,UACV,cAAc;AAAA,UACd;AAAA,QACF,CAAC;AACD,eAAO,KAAK,GAAG,sBAAsB,MAAM,kBAAkB,IAAI,EAAE;AACnE,mBAAW,WAAW,iBAAiB;AACrC,iBAAO;AAAA,YACL,GAAG,sBAAsB,MAAM,wBAAwB,QAAQ,IAAI,KAAK,QAAQ,KAAK,KAAK,QAAQ,OAAO;AAAA,UAC3G;AAAA,QACF;AACA,eAAO,GAAG;AAAA,UACR,IAAI;AAAA,UACJ,MAAM,OAAO,KAAK;AAAA,UAClB,OAAO,OAAO,KAAK;AAAA,UACnB,SAAS;AAAA,UACT,MAAM,OAAO;AAAA,UACb,GAAI,gBAAgB,SAAS,IAAI,EAAE,UAAU,gBAAgB,IAAI,CAAC;AAAA,QACpE,CAAC;AAAA,MACH,SAAS,GAAQ;AACf,YAAI,aAAa,eAAgB,QAAO,IAAI,EAAE,MAAM,EAAE,OAAO;AAC7D,eAAO,KAAK,GAAG,sBAAsB,MAAM,iBAAiB,GAAG,OAAO,EAAE;AACxE,eAAO,IAAI,kBAAkB,GAAG,WAAW,eAAe;AAAA,MAC5D;AAAA,IACF;AAAA,EACF,CAAC;AAGD,MAAI,aAAa;AAAA,IACf,MAAM,sBAAsB;AAAA,IAC5B,OAAO;AAAA,IACP,aACE;AAAA,IACF,YAAY;AAAA,MACV,MAAM;AAAA,MACN,UAAU,CAAC,MAAM;AAAA,MACjB,sBAAsB;AAAA,MACtB,YAAY;AAAA,QACV,MAAM,EAAE,MAAM,UAAU,aAAa,mDAAW;AAAA,MAClD;AAAA,IACF;AAAA,IACA,MAAM,QAAQ,aAAa,QAAQ;AACjC,YAAM,EAAE,KAAK,IAAI;AAEjB,UAAI,CAAC,QAAQ,OAAO,SAAS;AAC3B,eAAO,IAAI,kBAAkB,kBAAkB;AAEjD,UAAI;AACF,cAAM,SAAS,MAAM,SAAS,OAAO,IAAI;AACzC,eAAO,KAAK,GAAG,sBAAsB,MAAM,kBAAkB,IAAI,EAAE;AACnE,eAAO,GAAG,EAAE,IAAI,MAAM,MAAM,OAAO,MAAM,SAAS,KAAK,CAAC;AAAA,MAC1D,SAAS,GAAQ;AACf,YAAI,aAAa,eAAgB,QAAO,IAAI,EAAE,MAAM,EAAE,OAAO;AAC7D,eAAO,KAAK,GAAG,sBAAsB,MAAM,iBAAiB,GAAG,OAAO,EAAE;AACxE,eAAO,IAAI,kBAAkB,GAAG,WAAW,eAAe;AAAA,MAC5D;AAAA,IACF;AAAA,EACF,CAAC;AACH;;;ACzSA;;;AChBA,yBAA2B;AAE3B;AAYA,eAAsB,gBACpB,QACA,UACA,QACA,aACA,QACA,OAC0B;AAC1B,QAAM,SAAS,WAAW,EAAE;AAC5B,QAAM,SAAS;AACf,QAAM,aAAa;AACnB,QAAM,gBAAgB,kBAAkB,OAAO,QAAQ,QAAQ;AAE/D,UAAQ;AAAA,IACN,wBAAwB,UAAU,OAAO,YAAY,SAAS,OAAO,UAAU,GAAG,CAAC,IAAI,WAAM,OAAO,gBAAgB,cAAc,OAAO,YAAY,SAAS,OAAO,UAAU,GAAG,EAAE,IAAI,WAAM,OAAO,WAAW,aAAa,YAAY,UAAU,EAAE,cAAc,KAAK,UAAU,QAAQ,CAAC;AAAA,EAC7R;AAEA,MAAI,CAAC,UAAU,CAAC,UAAU,CAAC,YAAY;AACrC,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,OACE;AAAA,IACJ;AAAA,EACF;AAEA,MAAI;AACJ,MAAI;AACF,iBAAa,yBAAyB,UAAU,aAAa,MAAM;AAAA,EACrE,SAAS,OAAY;AACnB,WAAO,EAAE,IAAI,OAAO,OAAO,OAAO,WAAW,OAAO,KAAK,EAAE;AAAA,EAC7D;AACA,QAAM,kBAAc,+BAAW;AAE/B,QAAM,cAAc;AAAA,IAClB;AAAA,IACA,QAAQ,EAAE,YAAY,8BAA8B,OAAO,eAAe,OAAO;AAAA,IACjF;AAAA,IACA,WAAW,EAAE,WAAW;AAAA,IACxB,UAAU;AAAA,IACV;AAAA,EACF;AAEA,UAAQ;AAAA,IACN,sBAAsB,MAAM,iBAAiB,WAAW,UAAU,KAAK,UAAU,WAAW,EAAE,UAAU,GAAG,GAAG,CAAC;AAAA,EACjH;AAEA,QAAM,MAAM,MAAM,MAAM,QAAQ;AAAA,IAC9B,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,gBAAgB;AAAA,MAChB,gBAAgB,OAAO,WAAW,SAAS,IACvC,OAAO,MAAM,UAAU,MAAM,IAC7B;AAAA,IACN;AAAA,IACA,MAAM,KAAK,UAAU,WAAW;AAAA,EAClC,CAAC;AAED,QAAM,UAAU,MAAM,IAAI,KAAK;AAC/B,MAAI,CAAC,IAAI,IAAI;AACX,YAAQ;AAAA,MACN,wBAAwB,IAAI,MAAM,SAAS,MAAM,aAAa,QAAQ,UAAU,GAAG,GAAG,CAAC;AAAA,IACzF;AACA,WAAO,EAAE,IAAI,OAAO,QAAQ,IAAI,QAAQ,OAAO,QAAQ;AAAA,EACzD;AAEA,UAAQ,KAAK,gCAAgC,WAAW,aAAa,QAAQ,UAAU,GAAG,GAAG,CAAC,EAAE;AAChG,SAAO,EAAE,IAAI,MAAM,aAAa,UAAU,KAAK,MAAM,OAAO,EAAE;AAChE;AAEA,SAAS,kBACP,OACA,QACA,UACQ;AACR,QAAM,eAAe,OAAO,KAAK;AACjC,MAAI,aAAc,QAAO;AAEzB,QAAM,gBAAgB,QAAQ,KAAK;AACnC,MAAI,cAAe,QAAO;AAE1B,QAAM,WAAW,SAAS,IAAI,CAAC,YAAY,QAAQ,IAAI,EAAE,KAAK,GAAG;AACjE,SAAO,WAAW,YAAY,QAAQ;AACxC;;;ADvEO,IAAM,2BAAN,MAA+B;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EAEjB,YAAY,MAIT;AACD,SAAK,SAAS,KAAK;AACnB,SAAK,WAAW,KAAK;AACrB,SAAK,UAAU,KAAK;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,SACJ,eACA,OACkB;AAClB,QAAI,cAAc,WAAW,EAAG,QAAO;AAEvC,UAAM,WAAW,OAAO,WAAW;AAEnC,SAAK,eAAe,qBAAqB,QAAQ;AACjD,UAAM,QAAQ,KAAK,SAAS,WAAW;AACvC,QAAI,MAAM,WAAW,GAAG;AACtB,WAAK,OAAO;AAAA,QACV,cAAc,QAAQ,sCAAsC,cAAc,MAAM;AAAA,MAClF;AACA,aAAO;AAAA,IACT;AAEA,SAAK,OAAO;AAAA,MACV,cAAc,QAAQ,+BAA+B,cAAc,MAAM,UAAU,MAAM,MAAM;AAAA,IACjG;AAEA,UAAM,mBAAmB,KAAK,IAAI;AAClC,UAAM,UAAU,MAAM,KAAK,QAAQ;AAAA,MACjC;AAAA,MACA;AAAA,MACA,OAAO;AAAA,IACT;AACA,UAAM,iBAAiB,KAAK,IAAI,IAAI;AACpC,QAAI,YAAY,MAAM;AACpB,WAAK,OAAO;AAAA,QACV,cAAc,QAAQ,kCAAkC,cAAc,MAAM,WAAW,MAAM,MAAM,eAAe,cAAc;AAAA,MAClI;AACA,aAAO;AAAA,IACT;AAEA,QAAI,QAAQ,WAAW,GAAG;AACxB,WAAK,OAAO;AAAA,QACV,cAAc,QAAQ,+BAA+B,cAAc,MAAM,WAAW,MAAM,MAAM,eAAe,cAAc;AAAA,MAC/H;AACA,aAAO;AAAA,IACT;AAEA,SAAK,OAAO;AAAA,MACV,cAAc,QAAQ,cAAc,QAAQ,MAAM,cAAc,cAAc;AAAA,IAChF;AAIA,UAAM,aAAa,oBAAI,IAAY;AACnC,SAAK,eAAe,qBAAqB,QAAQ;AACjD,eAAW,SAAS,SAAS;AAC3B,UAAI,WAAW,IAAI,MAAM,QAAQ,EAAG;AACpC,YAAM,OAAO,KAAK,SAAS,IAAI,MAAM,QAAQ;AAC7C,UAAI,CAAC,MAAM;AACT,aAAK,OAAO;AAAA,UACV,cAAc,QAAQ,oBAAoB,MAAM,QAAQ;AAAA,QAC1D;AACA;AAAA,MACF;AACA,UAAI,CAAC,KAAK,SAAS;AACjB,aAAK,OAAO;AAAA,UACV,cAAc,QAAQ,oBAAoB,MAAM,QAAQ;AAAA,QAC1D;AACA;AAAA,MACF;AACA,iBAAW,IAAI,MAAM,QAAQ;AAC7B,YAAM,eAAe,cAAc,MAAM,iBAAiB;AAC1D,YAAM,KAAK,aAAa,MAAM,cAAc,QAAQ;AAAA,IACtD;AAEA,SAAK,OAAO;AAAA,MACV,cAAc,QAAQ,YAAY,WAAW,IAAI,aAAa,CAAC,GAAG,UAAU,EAAE,KAAK,IAAI,CAAC,UAC7E,QAAQ,MAAM,qBAAqB,cAAc,MAAM;AAAA,IACpE;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,eAAe,OAAe,UAAwB;AAC5D,QAAI;AACF,WAAK,SAAS,OAAO;AAAA,IACvB,SAASC,MAAU;AACjB,WAAK,OAAO;AAAA,QACV,cAAc,QAAQ,6BAA6B,KAAK,KAAKA,MAAK,WAAWA,IAAG;AAAA,MAClF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,aACZ,MACA,cACA,UACe;AACf,QAAI;AACJ,QAAI;AACF,eAAS,cAAc;AAAA,IACzB,SAASA,MAAU;AACjB,WAAK,OAAO;AAAA,QACV,cAAc,QAAQ,eAAe,KAAK,IAAI,2BAA2BA,MAAK,WAAWA,IAAG;AAAA,MAC9F;AACA;AAAA,IACF;AAEA,UAAM,SAAS,mBAAmB,MAAM,YAAY;AACpD,SAAK,OAAO;AAAA,MACV,cAAc,QAAQ,oBAAoB,KAAK,IAAI,oBAC/B,cAAc,aAAa,GAAG,QACzC,cAAc,kBAAkB,cAAc,WAAW,GAAG;AAAA,IACvE;AAEA,UAAM,cAAc,KAAK,IAAI;AAC7B,QAAI;AACF,YAAM,SAAS,MAAM;AAAA,QACnB;AAAA,QACA,KAAK;AAAA,QACL,KAAK;AAAA,QACL,EAAE,cAAc,KAAK,aAAa;AAAA,QAClC;AAAA,QACA,KAAK;AAAA,MACP;AACA,UAAI,OAAO,IAAI;AACb,aAAK,OAAO;AAAA,UACV,cAAc,QAAQ,eAAe,KAAK,IAAI,oBAAoB,OAAO,eAAe,GAAG,cAAc,KAAK,IAAI,IAAI,WAAW;AAAA,QACnI;AAAA,MACF,OAAO;AACL,aAAK,OAAO;AAAA,UACV,cAAc,QAAQ,eAAe,KAAK,IAAI,kBAAkB,OAAO,UAAU,GAAG,eACrE,KAAK,IAAI,IAAI,WAAW,KAAK,OAAO,KAAK;AAAA,QAC1D;AAAA,MACF;AAAA,IACF,SAASA,MAAU;AACjB,WAAK,OAAO;AAAA,QACV,cAAc,QAAQ,eAAe,KAAK,IAAI,yBAAyB,KAAK,IAAI,IAAI,WAAW,KAAKA,MAAK,WAAWA,IAAG;AAAA,MACzH;AAAA,IACF;AAAA,EACF;AACF;AAEA,IAAM,qBAAqB;AAE3B,SAAS,mBACP,MACA,cACQ;AACR,QAAM,YAAY,KAAK,OAAO,KAAK,KAAK,KAAK;AAC7C,MAAI,CAAC,cAAc;AACjB,WAAO,gBAAM,SAAS;AAAA,EACxB;AAEA,QAAM,MAAM,aAAa,gBAAgB,KAAK,KAAK,aAAa,QAAQ,KAAK;AAC7E,QAAM,SAAS,aAAa,YAAY,KAAK,KAAK,aAAa,OAAO,KAAK;AAC3E,QAAM,eAAe,aAAa,kBAAkB,KAAK;AACzD,QAAM,UAAU,aAAa,qBAAqB;AAElD,MAAI,QAAQ;AACZ,MAAI,SAAS;AACX,YAAQ,eAAe,GAAG,GAAG,gBAAM,YAAY,MAAM,GAAG,GAAG;AAAA,EAC7D;AAEA,QAAM,SAAS,SAAS,GAAG,MAAM,6BAAS;AAC1C,QAAM,UAAU,iBAAiB,aAAa,OAAO;AACrD,QAAM,SAAS,UAAU,SAAI,OAAO,KAAK;AAEzC,SAAO,qBAAM,KAAK,SAAI,MAAM,GAAG,MAAM,sBAAO,SAAS;AACvD;AAEA,SAAS,iBAAiB,SAAqC;AAC7D,QAAM,UAAU,SAAS,KAAK;AAC9B,MAAI,CAAC,QAAS,QAAO;AACrB,MAAI,QAAQ,UAAU,mBAAoB,QAAO;AACjD,SAAO,GAAG,QAAQ,MAAM,GAAG,kBAAkB,CAAC;AAChD;;;AEvNA,IAAAC,sBAA4B;AAIrB,IAAM,4CAA4C;AA0BlD,IAAM,+BAAN,MAAmC;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAA0B,CAAC;AAAA,EACpC,QAA8C;AAAA,EAC9C,UAAU;AAAA,EACV,6BAA6B;AAAA,EAErC,YAAY,MAIT;AACD,SAAK,YAAY,KAAK;AACtB,SAAK,SAAS,KAAK;AACnB,UAAM,aACJ,KAAK,SAAS,cAAc;AAC9B,SAAK,aAAa,OAAO,SAAS,UAAU,KAAK,cAAc,IAC3D,aACA;AAAA,EACN;AAAA,EAEA,QACE,eACA,WAAmB,eACb;AACN,QAAI,cAAc,WAAW,EAAG;AAChC,UAAM,eAAe,KAAK,IAAI;AAC9B,eAAW,KAAK,eAAe;AAC7B,WAAK,QAAQ,KAAK,EAAE,cAAc,GAAG,UAAU,aAAa,CAAC;AAAA,IAC/D;AACA,SAAK,OAAO;AAAA,MACV,cAAc,QAAQ,wBAAwB,cAAc,MAAM,qBACrD,KAAK,QAAQ,MAAM,gBAAgB,KAAK,UAAU,aAAa,KAAK,OAAO;AAAA,IAC1F;AACA,SAAK,cAAc;AAAA,EACrB;AAAA,EAEQ,gBAAsB;AAC5B,QAAI,KAAK,UAAU,KAAM;AAEzB,SAAK,QAAQ,WAAW,MAAM;AAC5B,WAAK,QAAQ;AACb,WAAK,KAAK,MAAM,EAAE,MAAM,CAACC,SAAQ;AAC/B,aAAK,OAAO;AAAA,UACV,4CAA4CA,MAAK,WAAWA,IAAG;AAAA,QACjE;AAAA,MACF,CAAC;AAAA,IACH,GAAG,KAAK,UAAU;AAElB,UAAM,iBAAiB,KAAK;AAC5B,mBAAe,QAAQ;AAAA,EACzB;AAAA,EAEA,MAAc,QAAuB;AACnC,QAAI,KAAK,SAAS;AAChB,WAAK,6BAA6B;AAClC;AAAA,IACF;AAEA,UAAM,QAAQ,KAAK,QAAQ,OAAO,CAAC;AACnC,QAAI,MAAM,WAAW,EAAG;AAExB,UAAM,UAAU,aAAS,iCAAY,CAAC,EAAE,SAAS,KAAK,CAAC;AACvD,UAAM,YAAY,cAAc,MAAM,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC;AAC5D,UAAM,oBAAoB,MAAM,CAAC,EAAE;AACnC,UAAM,WAAW,KAAK,IAAI,IAAI;AAC9B,UAAM,gBAAgB,MAAM,IAAI,CAAC,MAAM,EAAE,YAAY;AAErD,SAAK,OAAO;AAAA,MACV,cAAc,OAAO,wBAAwB,MAAM,MAAM,eACzC,UAAU,KAAK,GAAG,CAAC,cAAc,QAAQ;AAAA,IAC3D;AAEA,SAAK,UAAU;AACf,UAAM,cAAc,KAAK,IAAI;AAC7B,QAAI;AACF,YAAM,KAAK,UAAU,SAAS,eAAe,EAAE,SAAS,UAAU,CAAC;AACnE,WAAK,OAAO;AAAA,QACV,cAAc,OAAO,0BAA0B,KAAK,IAAI,IAAI,WAAW;AAAA,MACzE;AAAA,IACF,SAASA,MAAU;AACjB,WAAK,OAAO;AAAA,QACV,cAAc,OAAO,uCAAuC,MAAM,MAAM,eACzD,KAAK,IAAI,IAAI,WAAW,KAAKA,MAAK,WAAWA,IAAG;AAAA,MACjE;AAAA,IACF,UAAE;AACA,WAAK,UAAU;AACf,UAAI,KAAK,QAAQ,SAAS,GAAG;AAC3B,YAAI,KAAK,4BAA4B;AACnC,eAAK,6BAA6B;AAClC,eAAK,KAAK,MAAM,EAAE,MAAM,CAACA,SAAQ;AAC/B,iBAAK,OAAO;AAAA,cACV,yCAAyCA,MAAK,WAAWA,IAAG;AAAA,YAC9D;AAAA,UACF,CAAC;AAAA,QACH,OAAO;AACL,eAAK,cAAc;AAAA,QACrB;AAAA,MACF,OAAO;AACL,aAAK,6BAA6B;AAAA,MACpC;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,cAAc,OAA2B;AAChD,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,MAAgB,CAAC;AACvB,aAAW,QAAQ,OAAO;AACxB,QAAI,KAAK,IAAI,IAAI,EAAG;AACpB,SAAK,IAAI,IAAI;AACb,QAAI,KAAK,IAAI;AAAA,EACf;AACA,SAAO;AACT;;;ACpIA,2BAIO;AAKP,IAAM,mBAAmB;AACzB,IAAM,mBAAmB;AACzB,IAAM,mBAAmB;AACzB,IAAM,qBAAqB;AAC3B,IAAM,uBAAuB;AAC7B,IAAM,oBAAoB;AAyBnB,IAAM,cAAN,MAAkB;AAAA,EACvB,YACmB,KACA,QACA,UAA8B,CAAC,GAChD;AAHiB;AACA;AACA;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASH,MAAM,mBACJ,eACA,OACA,UAAkB,cACgB;AAClC,QAAI,cAAc,WAAW,KAAK,MAAM,WAAW,EAAG,QAAO,CAAC;AAE9D,UAAM,WAAW;AAEjB,QAAI;AACJ,QAAI;AACJ,QAAI;AACF,OAAC,EAAE,OAAO,SAAS,IAAI,MAAM,KAAK,uBAAuB;AAAA,IAC3D,SAASC,MAAU;AACjB,WAAK,OAAO;AAAA,QACV,eAAe,QAAQ,sBAAsBA,MAAK,WAAW,OAAOA,IAAG,CAAC;AAAA,MAC1E;AACA,aAAO;AAAA,IACT;AACA,QAAI,WAAW,UAAU;AACvB,WAAK,OAAO;AAAA,QACV,eAAe,QAAQ,cAAc,KAAK,YAAY,SAAS,KAAK;AAAA,MACtE;AACA,aAAO;AAAA,IACT;AAEA,UAAM,eAAe,kBAAkB,KAAK;AAC5C,UAAM,cAAc,iBAAiB,aAAa;AAClD,UAAM,gBAAgB,KAAK,QAAQ,aAAa;AAChD,UAAM,cAAc,KAAK,IAAI,GAAG,KAAK,QAAQ,eAAe,oBAAoB;AAEhF,aAAS,UAAU,GAAG,WAAW,aAAa,WAAW,GAAG;AAC1D,YAAM,YAAY,gBAAgB;AAClC,YAAM,cAAc,KAAK,IAAI;AAC7B,WAAK,OAAO;AAAA,QACV,eAAe,QAAQ,uBAAuB,OAAO,IAAI,WAAW,UACzD,KAAK,cAAc,SAAS,kBAAkB,cAAc,MAAM,UAAU,MAAM,MAAM;AAAA,MACrG;AACA,UAAI;AACF,cAAM,OAAO,UAAM,gEAA0C;AAAA,UAC3D,OAAO,SAAS;AAAA,UAChB,MAAM,SAAS;AAAA,UACf,SAAS;AAAA,YACP;AAAA,YACA,UAAU;AAAA,cACR,EAAE,MAAM,QAAQ,SAAS,aAAa,WAAW,KAAK,IAAI,EAAE;AAAA,YAC9D;AAAA,UACF;AAAA,UACA,SAAS;AAAA,YACP,aAAa;AAAA,YACb,WAAW;AAAA,YACX,QAAQ,YAAY,QAAQ,SAAS;AAAA,YACrC,gBAAgB;AAAA,UAClB;AAAA,QACF,CAAC;AAED,cAAM,YAAY,KAAK,IAAI,IAAI;AAE/B,YAAI,KAAK,eAAe,WAAW,KAAK,eAAe,WAAW;AAChE,gBAAM,YAAY,KAAK,eAAe,aAAa,UAAU;AAC7D,eAAK,OAAO;AAAA,YACV,eAAe,QAAQ,4BAA4B,KAAK,UAAU,KAAK,KAAK,gBAAgB,KAAK,aACnF,OAAO,IAAI,WAAW,eAAe,SAAS,eAAe,SAAS,GAAG,YAAY,eAAe,EAAE;AAAA,UACtH;AACA,cAAI,WAAW;AACb;AAAA,UACF;AACA,iBAAO;AAAA,QACT;AAEA,cAAM,OAAO,YAAY,KAAK,OAAO;AACrC,cAAM,SAAS,iBAAiB,MAAM,cAAc,QAAQ,KAAK;AACjE,aAAK,OAAO;AAAA,UACV,eAAe,QAAQ,0BAA0B,OAAO,IAAI,WAAW,eACvD,KAAK,UAAU,cAAc,SAAS,YAAY,OAAO,MAAM;AAAA,QACjF;AACA,eAAO;AAAA,MACT,SAASA,MAAU;AACjB,cAAM,UAAUA,MAAK,WAAW,OAAOA,IAAG;AAC1C,cAAM,YAAY,KAAK,IAAI,IAAI;AAC/B,cAAM,YACJ,UAAU,gBACNA,MAAK,SAAS,gBAAgB,oBAAoB,KAAK,OAAO;AACpE,aAAK,OAAO;AAAA,UACV,eAAe,QAAQ,uBAAuB,OAAO,aACvC,OAAO,IAAI,WAAW,eAAe,SAAS,GAAG,YAAY,eAAe,EAAE;AAAA,QAC9F;AACA,YAAI,WAAW;AACb;AAAA,QACF;AACA,eAAO;AAAA,MACT;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,yBAGX;AACD,QAAI,KAAK,QAAQ,YAAY,KAAK,QAAQ,SAAS;AACjD,YAAM,WAAW,KAAK,QAAQ,YAAY;AAC1C,YAAM,UAAU,KAAK,QAAQ,WAAW;AACxC,YAAMC,YAAW,UAAM,mDAA6B;AAAA,QAClD,KAAK,KAAK,IAAI;AAAA,QACd;AAAA,QACA;AAAA,MACF,CAAC;AACD,aAAO,EAAE,OAAO,GAAG,QAAQ,IAAI,OAAO,IAAI,UAAAA,UAAS;AAAA,IACrD;AAEA,UAAM,UAAU,KAAK,QAAQ,SAAS,KAAK,KAAK;AAChD,UAAM,WAAW,KAAK,QAAQ,UAAU,KAAK;AAC7C,UAAM,WAAW,UAAM,2DAAqC;AAAA,MAC1D,KAAK,KAAK,IAAI;AAAA,MACd;AAAA,MACA,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;AAAA,IACjC,CAAC;AACD,UAAM,QACJ,eAAe,YAAY,SAAS,YAChC,GAAG,SAAS,UAAU,QAAQ,IAAI,SAAS,UAAU,OAAO,WAAW,OAAO,MAC9E,SAAS,OAAO;AACtB,WAAO,EAAE,OAAO,SAAS;AAAA,EAC3B;AACF;AAEA,SAAS,YAAY,SAA0B;AAC7C,MAAI,CAAC,MAAM,QAAQ,OAAO,EAAG,QAAO;AACpC,QAAM,QAAkB,CAAC;AACzB,aAAW,KAAK,SAAS;AACvB,QAAI,KAAK,OAAO,MAAM,YAAa,EAAU,SAAS,QAAQ;AAC5D,YAAM,IAAK,EAAU;AACrB,UAAI,OAAO,MAAM,SAAU,OAAM,KAAK,CAAC;AAAA,IACzC;AAAA,EACF;AACA,SAAO,MAAM,KAAK,EAAE;AACtB;AAEA,SAAS,kBAAkB,OAAgC;AACzD,QAAM,QAAkB;AAAA,IACtB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,QAAM,SAAS,CAAC,GAAG,KAAK,EAAE;AAAA,IACxB,CAAC,GAAG,OAAO,EAAE,aAAa,IAAI,cAAc,EAAE,aAAa,EAAE;AAAA,EAC/D;AACA,SAAO,QAAQ,CAAC,MAAM,QAAQ;AAC5B,UAAM;AAAA,MACJ,IAAI,MAAM,CAAC,UAAU,KAAK,IAAI;AAAA,MAC9B,SAAS,KAAK,KAAK;AAAA,MACnB,eAAe,KAAK,WAAW;AAAA,IACjC;AAAA,EACF,CAAC;AACD,SAAO,MAAM,KAAK,IAAI;AACxB;AAEA,SAAS,iBAAiB,eAA6C;AACrE,QAAM,QAAkB;AAAA,IACtB,gBAAM,cAAc,MAAM;AAAA,IAC1B;AAAA,EACF;AACA,gBAAc,QAAQ,CAAC,GAAG,MAAM;AAC9B,UAAM,MAAM,EAAE,kBAAkB,EAAE;AAClC,UAAM,KAAK,IAAI,CAAC,SAAS,GAAG,SAAS,EAAE,SAAS,EAAE;AAClD,QAAI,EAAE,YAAY;AAChB,YAAM,KAAK,eAAe,EAAE,UAAU,EAAE;AAAA,IAC1C;AACA,QAAI,EAAE,kBAAkB;AACtB,YAAM,KAAK,0BAA0B,EAAE,gBAAgB,EAAE;AAAA,IAC3D;AACA,QAAI,EAAE,kBAAkB;AACtB,YAAM,KAAK,0BAA0B,EAAE,gBAAgB,EAAE;AAAA,IAC3D;AACA,UAAM,KAAK,cAAc,EAAE,KAAK,IAAI,gBAAgB,EAAE,OAAO,IAAI,EAAE;AAAA,EACrE,CAAC;AACD,QAAM,KAAK,iJAA8B;AACzC,SAAO,MAAM,KAAK,IAAI;AACxB;AAEA,SAAS,iBACP,SACA,mBACA,OACkB;AAClB,MAAI,CAAC,QAAS,QAAO,CAAC;AAEtB,QAAM,OAAO,QACV,KAAK,EACL,QAAQ,qBAAqB,EAAE,EAC/B,QAAQ,YAAY,EAAE,EACtB,KAAK;AAER,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,IAAI;AAAA,EAC1B,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACA,MAAI,CAAC,UAAU,OAAO,WAAW,SAAU,QAAO,CAAC;AAEnD,QAAM,MAAO,OAAiC;AAC9C,MAAI,CAAC,MAAM,QAAQ,GAAG,EAAG,QAAO,CAAC;AAEjC,QAAM,iBAAiB,IAAI,IAAI,MAAM,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;AACvD,QAAM,UAA4B,CAAC;AACnC,aAAW,KAAK,KAAK;AACnB,QAAI,CAAC,KAAK,OAAO,MAAM,SAAU;AACjC,UAAM,QAAQ;AACd,UAAM,IACJ,OAAO,MAAM,MAAM,WACf,MAAM,IACN,OAAO,MAAM,UAAU,WACrB,MAAM,QACN;AACR,UAAM,WAAW,OAAO,MAAM,SAAS,WAAW,MAAM,OAAO;AAC/D,QAAI,CAAC,OAAO,UAAU,CAAC,KAAK,IAAI,KAAK,KAAK,kBAAmB;AAC7D,QAAI,CAAC,YAAY,CAAC,eAAe,IAAI,QAAQ,EAAG;AAChD,YAAQ,KAAK,EAAE,mBAAmB,GAAG,SAAS,CAAC;AAAA,EACjD;AACA,SAAO;AACT;;;AC3SA;;;ACUO,SAAS,qBAAqB,QAGf;AACpB,MAAI,OAAO,YAAY,cAAc;AACnC,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,mBAAmB;AAC5B,WAAO,OAAO;AAAA,EAChB;AAEA,SAAO;AACT;;;ACxBA,IAAAC,oBAAqB;;;ACCrB;;;ACSO,SAAS,SAAS,KAAuC;AAC9D,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,SAAmB,CAAC;AAC1B,QAAI,GAAG,QAAQ,CAAC,UAAkB,OAAO,KAAK,KAAK,CAAC;AACpD,QAAI,GAAG,OAAO,MAAM,QAAQ,OAAO,OAAO,MAAM,EAAE,SAAS,CAAC,CAAC;AAC7D,QAAI,GAAG,SAAS,MAAM;AAAA,EACxB,CAAC;AACH;AAEO,SAASC,iBAAgB,OAAoC;AAClE,MAAI,OAAO,UAAU,UAAU;AAC7B,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,MAAM,KAAK;AAC3B,SAAO,WAAW;AACpB;;;ADtBO,SAAS,0BACd,KACoB;AACpB,QAAM,eAAgB,KAAa,SAAS;AAC5C,QAAMC,mBAAkB,cAAc;AACtC,MAAI,OAAOA,qBAAoB,YAAY;AACzC,WAAO;AAAA,EACT;AAEA,MAAI;AACF,WAAOC,iBAAgBD,iBAAgB,KAAK,YAAY,CAAC;AAAA,EAC3D,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,sBACd,KACQ;AACR,SAAO,0BAA0B,GAAG,KAAK,gBAAoB;AAC/D;;;AEpBA,SAAS,YAAY,GAAgF;AACnG,QAAM,CAAC,MAAM,MAAM,IAAI,IAAI,EAAE,MAAM,KAAK,CAAC;AACzC,QAAM,CAAC,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC,IAAI,KAAK,MAAM,GAAG,EAAE,IAAI,MAAM;AACpE,SAAO,EAAE,OAAO,OAAO,OAAO,KAAK,OAAO,KAAK;AACjD;AAEA,SAAS,kBAAkB,GAAW,GAAmB;AACvD,QAAM,SAAS,EAAE,MAAM,GAAG;AAC1B,QAAM,SAAS,EAAE,MAAM,GAAG;AAC1B,WAAS,IAAI,GAAG,IAAI,KAAK,IAAI,OAAO,QAAQ,OAAO,MAAM,GAAG,KAAK;AAC/D,UAAM,KAAK,OAAO,CAAC,KAAK;AACxB,UAAM,KAAK,OAAO,CAAC,KAAK;AACxB,UAAM,KAAK,OAAO,EAAE;AACpB,UAAM,KAAK,OAAO,EAAE;AACpB,QAAI;AACJ,QAAI,CAAC,OAAO,MAAM,EAAE,KAAK,CAAC,OAAO,MAAM,EAAE,GAAG;AAC1C,aAAO,KAAK;AAAA,IACd,WAAW,KAAK,IAAI;AAClB,aAAO;AAAA,IACT,WAAW,KAAK,IAAI;AAClB,aAAO;AAAA,IACT,OAAO;AACL,aAAO;AAAA,IACT;AACA,QAAI,SAAS,EAAG,QAAO;AAAA,EACzB;AACA,SAAO;AACT;AAGA,SAAS,eAAe,WAAmB,SAA0B;AACnE,QAAM,IAAI,YAAY,SAAS;AAC/B,QAAM,IAAI,YAAY,OAAO;AAE7B,MAAI,EAAE,UAAU,EAAE,MAAO,QAAO,EAAE,QAAQ,EAAE;AAC5C,MAAI,EAAE,UAAU,EAAE,MAAO,QAAO,EAAE,QAAQ,EAAE;AAC5C,MAAI,EAAE,UAAU,EAAE,MAAO,QAAO,EAAE,QAAQ,EAAE;AAG5C,MAAI,EAAE,QAAQ,KAAM,QAAO,EAAE,QAAQ;AACrC,MAAI,EAAE,QAAQ,KAAM,QAAO;AAE3B,SAAO,kBAAkB,EAAE,KAAK,EAAE,GAAG,IAAI;AAC3C;AAEA,IAAM,eAAe;AACrB,IAAM,eACJ;AACF,IAAM,mBAAmB;AAElB,IAAM,gBAAN,MAAoB;AAAA,EAIzB,YACmB,QACA,eACA,YACA,SACjB;AAJiB;AACA;AACA;AACA;AAAA,EAChB;AAAA,EARK,QAA8C;AAAA,EAC9C,kBAAiC;AAAA,EASzC,QAAc;AAEZ,SAAK,QAAQ,WAAW,MAAM;AAC5B,WAAK,KAAK,MAAM;AAChB,WAAK,QAAQ,YAAY,MAAM,KAAK,KAAK,MAAM,GAAG,KAAK,UAAU;AAAA,IACnE,GAAG,GAAM;AAAA,EACX;AAAA,EAEA,OAAa;AACX,QAAI,KAAK,OAAO;AACd,oBAAc,KAAK,KAAK;AACxB,WAAK,QAAQ;AAAA,IACf;AAAA,EACF;AAAA,EAEA,MAAM,QAAuB;AAC3B,UAAM,SAAS,MAAM,KAAK,mBAAmB;AAC7C,QAAI,CAAC,UAAU,WAAW,eAAgB;AAC1C,QAAI,WAAW,KAAK,gBAAiB;AAGrC,QAAI,KAAK,YAAY,UAAU,OAAO,SAAS,GAAG,EAAG;AAGrD,QAAI,CAAC,eAAe,QAAQ,cAAc,EAAG;AAE7C,SAAK,kBAAkB;AACvB,SAAK,OAAO,KAAK,mCAAU,cAAc,WAAM,MAAM,EAAE;AACvD,SAAK,cAAc,EAAE,SAAS,gBAAgB,OAAO,CAAC;AAAA,EACxD;AAAA,EAEA,MAAc,qBAA6C;AACzD,UAAM,MAAM,KAAK,YAAY,SAAS,SAAS;AAG/C,QAAI;AACF,YAAM,MAAM,MAAM,MAAM,GAAG,YAAY,IAAI,GAAG,IAAI;AAAA,QAChD,QAAQ,YAAY,QAAQ,gBAAgB;AAAA,MAC9C,CAAC;AACD,UAAI,IAAI,IAAI;AACV,cAAM,QAAQ,MAAM,IAAI,KAAK,GAAG,KAAK;AACrC,YAAI,KAAM,QAAO;AAAA,MACnB;AAAA,IACF,QAAQ;AAAA,IAER;AAGA,QAAI;AACF,YAAM,MAAM,MAAM,MAAM,GAAG,YAAY,IAAI,GAAG,IAAI;AAAA,QAChD,QAAQ,YAAY,QAAQ,gBAAgB;AAAA,MAC9C,CAAC;AACD,UAAI,IAAI,IAAI;AACV,cAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,eAAO,KAAK,WAAW;AAAA,MACzB;AAAA,IACF,QAAQ;AACN,WAAK,OAAO,KAAK,sGAA2B;AAAA,IAC9C;AAEA,WAAO;AAAA,EACT;AACF;;;AC/HA,IAAAE,kBAA0E;AAC1E,IAAAC,oBAA8B;AAC9B,qBAAuB;AAGvB,IAAM,kBAAkB;AACxB,IAAM,WAAW;AAkBjB,eAAsB,cACpB,SACA,YACA,QACA,WACAC,qBACuB;AACvB,MAAI,CAAC,gBAAgB,KAAK,OAAO,GAAG;AAClC,WAAO,EAAE,SAAS,OAAO,SAAS,mCAAU,OAAO,GAAG;AAAA,EACxD;AAEA,QAAM,SAAS,GAAG,QAAQ,KAAK,OAAO,iCAAiC,OAAO;AAC9E,SAAO,KAAK,6BAAS,MAAM,WAAM,SAAS,EAAE;AAE5C,QAAM,cAAU,iCAAY,4BAAK,uBAAO,GAAG,0BAA0B,CAAC;AACtE,QAAM,cAAU,wBAAK,SAAS,YAAY;AAC1C,QAAM,iBAAa,wBAAK,SAAS,QAAQ;AACzC,MAAI,YAA2B;AAE/B,MAAI;AACF,WAAO,KAAK,mCAAU;AACtB,UAAM,WAAW,MAAM,MAAM,QAAQ,EAAE,QAAQ,YAAY,QAAQ,GAAM,EAAE,CAAC;AAC5E,QAAI,CAAC,SAAS,IAAI;AAChB,aAAO,EAAE,SAAS,OAAO,SAAS,kCAAc,SAAS,MAAM,MAAM,MAAM,GAAG;AAAA,IAChF;AACA,UAAM,SAAS,OAAO,KAAK,MAAM,SAAS,YAAY,CAAC;AACvD,uCAAc,SAAS,MAAM;AAC7B,WAAO,KAAK,6BAAS,OAAO,MAAM,SAAS;AAE3C,mCAAU,YAAY,EAAE,WAAW,KAAK,CAAC;AACzC,UAAM,YAAY,MAAM;AAAA,MACtB,CAAC,OAAO,QAAQ,SAAS,MAAM,YAAY,sBAAsB;AAAA,MACjE,EAAE,WAAW,IAAO;AAAA,IACtB;AACA,QAAI,UAAU,SAAS,GAAG;AACxB,YAAMC,OAAM,UAAU,UAAU,UAAU,UAAU;AACpD,aAAO,EAAE,SAAS,OAAO,SAAS,6BAASA,IAAG,GAAG;AAAA,IACnD;AAEA,uCAAU,2BAAQ,SAAS,GAAG,EAAE,WAAW,KAAK,CAAC;AACjD,QAAI;AACF,kBAAY,GAAG,SAAS,QAAQ,KAAK,IAAI,CAAC;AAC1C,sCAAW,WAAW,SAAS;AAAA,IACjC,QAAQ;AACN,kBAAY;AAAA,IACd;AACA,oCAAW,YAAY,SAAS;AAEhC,QAAI;AACF,YAAMD,oBAAmB,SAAS,MAAM;AAAA,IAC1C,SAASC,MAAK;AACZ,aAAO,KAAK,2GAAsB,OAAOA,IAAG,CAAC,EAAE;AAAA,IACjD;AAEA,QAAI,WAAW;AACb,UAAI;AAAE,oCAAO,WAAW,EAAE,OAAO,MAAM,WAAW,KAAK,CAAC;AAAA,MAAG,QAAQ;AAAA,MAAe;AAAA,IACpF;AAEA,UAAM,MAAM,4BAAQ,OAAO;AAC3B,WAAO,KAAK,GAAG;AACf,WAAO,EAAE,SAAS,MAAM,SAAS,KAAK,QAAQ;AAAA,EAEhD,SAASA,MAAK;AACZ,QAAI,WAAW;AACb,UAAI;AACF,oCAAO,WAAW,EAAE,OAAO,MAAM,WAAW,KAAK,CAAC;AAClD,wCAAW,WAAW,SAAS;AAC/B,eAAO,KAAK,kDAAU;AAAA,MACxB,SAAS,aAAa;AACpB,eAAO,MAAM,6BAAS,OAAO,WAAW,CAAC,EAAE;AAAA,MAC7C;AAAA,IACF;AACA,UAAM,SAAS,yCAAW,OAAOA,IAAG,CAAC;AACrC,WAAO,MAAM,MAAM;AACnB,WAAO,EAAE,SAAS,OAAO,SAAS,OAAO;AAAA,EAE3C,UAAE;AACA,QAAI;AAAE,kCAAO,SAAS,EAAE,OAAO,MAAM,WAAW,KAAK,CAAC;AAAA,IAAG,QAAQ;AAAA,IAAe;AAAA,EAClF;AACF;;;ACpFO,SAAS,uBACd,QACA,OAAmC,CAAC,GACN;AAC9B,MAAI;AACF,UAAM,MAAM,KAAK,aAAa;AAC9B,QAAI,KAAK,UAAU,YAAY,OAAO;AACpC,aAAO,KAAK,6EAA0C;AACtD,aAAO,EAAE,WAAW,MAAM;AAAA,IAC5B;AAAA,EACF,SAASC,MAAK;AACZ,WAAO,KAAK,gFAAyB,OAAOA,IAAG,CAAC,EAAE;AAAA,EACpD;AAEA,QAAM,mBACJ,KAAK,qBAAqB,CAAC,WAA2B,QAAQ,cAAc,MAAM;AACpF,MAAI,iBAAiB,SAAS,IAAI,GAAG;AACnC,WAAO,KAAK,4HAAuC;AACnD,WAAO,EAAE,WAAW,MAAM;AAAA,EAC5B;AAEA,QAAM,aACJ,KAAK,eAAe,CAAC,WAA2B,QAAQ,KAAK,MAAM;AACrE,QAAM,WACJ,KAAK,aAAa,CAAC,SAAqB;AAAE,eAAW,MAAM,CAAC;AAAA,EAAG;AAEjE,WAAS,MAAM;AACb,QAAI;AACF,YAAM,WAAW,WAAW,SAAS;AACrC,UAAI,UAAU;AACZ,eAAO,KAAK,+EAA6B;AAAA,MAC3C,OAAO;AACL,eAAO,KAAK,2FAA+B;AAAA,MAC7C;AAAA,IACF,SAASA,MAAK;AACZ,aAAO,KAAK,oEAAuB,OAAOA,IAAG,CAAC,EAAE;AAAA,IAClD;AAAA,EACF,CAAC;AAED,SAAO,EAAE,WAAW,KAAK;AAC3B;;;AL7CA,IAAM,YAAY;AAElB,SAAS,iBAAiB,KAAgC;AACxD,MAAI;AACF,UAAM,MAAO,IAAI,QAAgB,QAAQ,aAAa;AACtD,UAAM,cAAc,KAAK,SAAS,WAAW,SAAS,GAAG;AACzD,QAAI,YAAa,QAAO;AAAA,EAC1B,QAAQ;AAAA,EAAe;AACvB,aAAO,wBAAK,sBAAsB,GAAG,GAAG,cAAc,SAAS;AACjE;AAEA,eAAe,mBACb,KACA,SACA,WACA,QACe;AACf,QAAM,YAAa,IAAI,QAAgB;AACvC,MAAI,CAAC,UAAW;AAChB,QAAM,MAAM,UAAU,WAAW;AACjC,MAAI,CAAC,IAAI,QAAS,KAAI,UAAU,CAAC;AACjC,MAAI,CAAC,IAAI,QAAQ,SAAU,KAAI,QAAQ,WAAW,CAAC;AACnD,MAAI,QAAQ,SAAS,SAAS,IAAI;AAAA,IAChC,GAAG,IAAI,QAAQ,SAAS,SAAS;AAAA,IACjC,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,aAAa;AAAA,IACb;AAAA,IACA,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,EACtC;AACA,QAAM,UAAU,gBAAgB,GAAG;AACrC;AAEA,SAAS,qBACP,KACA,QACA,QAC2C;AAC3C,MAAI,CAAC,OAAO,SAAS;AACnB,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,uBAAuB,QAAQ;AAAA,IAC7C,YAAY,MAAM;AAChB,YAAM,YAAa,IAAI,QAAgB;AACvC,aAAO,WAAW,aAAa;AAAA,IACjC;AAAA,EACF,CAAC;AAED,QAAM,UAAU,OAAO,WAAW;AAClC,SAAO;AAAA,IACL,GAAG;AAAA,IACH,kBAAkB,QAAQ;AAAA,IAC1B,SAAS,QAAQ,YACb,4BAAQ,OAAO,kDACf,4BAAQ,OAAO;AAAA,EACrB;AACF;AAUO,SAAS,mBACd,KACA,QACA,QACA,cACA,mBACA,wBAKA;AACA,MAAI,OAAO,YAAY,OAAO;AAC5B,WAAO,KAAK,yEAAsC;AAClD,WAAO,EAAE,QAAQ;AAAA,IAAC,GAAG,OAAO;AAAA,IAAC,GAAG,uBAAuB;AAAA,IAAC,EAAE;AAAA,EAC5D;AAEA,MAAI,gBAAmC;AACvC,MAAI,uBAA0C;AAE9C,WAAS,mBAAmB,QAA6B;AACvD,UAAM,YAAY,aAAa;AAC/B,QAAI,CAAC,UAAW,QAAO;AAEvB,cAAU,0BAA0B;AAAA,MAClC,UAAU;AAAA,MACV,YAAY;AAAA,MACZ,SAAS,OAAO;AAAA,MAChB,QAAQ,OAAO;AAAA,IACjB,CAAC;AACD,2BAAuB;AACvB,WAAO;AAAA,EACT;AAIA,MAAI,GAAG,uBAAuB,MAAM;AAClC,QAAI,CAAC,cAAe;AACpB,WAAO;AAAA,MACL,qBACE,uFAAqC,cAAc,MAAM,+CAChD,cAAc,OAAO;AAAA;AAAA,IAIlC;AAAA,EACF,CAAC;AAKD,MAAI,aAAa;AAAA,IACf,MAAM;AAAA,IACN,OAAO;AAAA,IACP,aACE;AAAA,IAEF,YAAY;AAAA,MACV,MAAM;AAAA,MACN,UAAU,CAAC,SAAS;AAAA,MACpB,sBAAsB;AAAA,MACtB,YAAY;AAAA,QACV,SAAS;AAAA,UACP,MAAM;AAAA,UACN,aAAa;AAAA,QACf;AAAA,MACF;AAAA,IACF;AAAA,IACA,MAAM,QAAQ,aAAqB,QAAiB;AAClD,YAAM,EAAE,QAAQ,IAAI;AACpB,YAAM,YAAY,iBAAiB,GAAG;AACtC,YAAM,SAAS,MAAM;AAAA,QACnB;AAAA,QACA,IAAI,QAAQ,OAAO;AAAA,QACnB;AAAA,QACA;AAAA,QACA,CAAC,GAAG,QAAQ,mBAAmB,KAAK,GAAG,WAAW,GAAG;AAAA,MACvD;AACA,YAAM,cAAc,qBAAqB,KAAK,QAAQ,MAAM;AAC5D,UAAI,YAAY,SAAS;AACvB,wBAAgB;AAChB,gCAAwB,mBAAmB;AAAA,MAC7C;AACA,aAAO;AAAA,QACL,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,YAAY,QAAQ,CAAC;AAAA,QAC9D,SAAS;AAAA,MACX;AAAA,IACF;AAAA,EACF,CAAQ;AAIR,MAAI,sBAAsB,iBAAiB,OAAO,EAAE,QAAQ,SAAS,QAAQ,MAAM;AACjF,wBAAoB,SAAS,SAAS;AAEtC,UAAM,UAAW,OAAgC;AACjD,QAAI,CAAC,SAAS;AACZ,cAAQ,OAAO,QAAW;AAAA,QACxB,MAAM;AAAA,QACN,SAAS;AAAA,MACX,CAAC;AACD;AAAA,IACF;AACA,UAAM,YAAY,iBAAiB,GAAG;AACtC,UAAM,SAAS,MAAM;AAAA,MACnB;AAAA,MACA,IAAI,QAAQ,OAAO;AAAA,MACnB;AAAA,MACA;AAAA,MACA,CAAC,GAAG,QAAQ,mBAAmB,KAAK,GAAG,WAAW,GAAG;AAAA,IACvD;AACA,UAAM,cAAc,qBAAqB,KAAK,QAAQ,MAAM;AAC5D,QAAI,YAAY,SAAS;AACvB,sBAAgB;AAChB,8BAAwB,mBAAmB;AAAA,IAC7C;AACA,QAAI,YAAY,SAAS;AACvB,cAAQ,MAAM;AAAA,QACZ,SAAS,YAAY;AAAA,QACrB,kBAAkB,YAAY,qBAAqB;AAAA,MACrD,CAAC;AAAA,IACH,OAAO;AACL,cAAQ,OAAO,QAAW;AAAA,QACxB,MAAM;AAAA,QACN,SAAS,YAAY;AAAA,MACvB,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AAID,QAAM,cAAc,OAAO,sBAAsB,KAAK;AACtD,QAAM,UAAU,OAAO,WAAW;AAElC,SAAO;AAAA,IACL,uDAAoB,OAAO,wBAAwB,OAAO,sBAAsB,CAAC;AAAA,EACnF;AAEA,QAAM,UAAU,IAAI;AAAA,IAClB;AAAA,IACA,CAAC,WAAW;AACV,sBAAgB;AAEhB,YAAM,cAAc,mBAAmB,MAAM;AAC7C,UAAI,CAAC,YAAa,wBAAuB;AACzC,UAAI,CAAC,aAAa;AAChB,gCAAwB,sBAAsB,MAAM;AAAA,MACtD;AAEA,aAAO;AAAA,QACL,kCAAS,OAAO,OAAO,WAAM,OAAO,MAAM,MACvC,cACG,4CACA;AAAA,MACR;AAAA,IACF;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,SAAO;AAAA,IACL,OAAO,MAAM,QAAQ,MAAM;AAAA,IAC3B,MAAM,MAAM,QAAQ,KAAK;AAAA,IACzB,uBAAuB;AACrB,YAAM,SAAS;AACf,UAAI,CAAC,OAAQ;AACb,UAAI,CAAC,mBAAmB,MAAM,EAAG;AACjC,aAAO,KAAK,0DAAa,OAAO,OAAO,WAAM,OAAO,MAAM,EAAE;AAAA,IAC9D;AAAA,EACF;AACF;;;AFzOO,SAAS,4BACd,MACuC;AACvC,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AAEJ,QAAM,mBAAmB;AAAA,IACvB,GAAG,OAAO;AAAA,IACV,SAAS,qBAAqB;AAAA,MAC5B,mBAAmB,OAAO,YAAY;AAAA,MACtC,SAAS,YAAY;AAAA,IACvB,CAAC;AAAA,EACH;AAEA,QAAM,sBAAsB;AAAA,IAC1B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,gBACI;AAAA,MACE,uBAAuB,CAAC,WAAW,cAAc,sBAAsB,MAAM;AAAA,MAC7E,oBAAoB,MAAM,cAAc,mBAAmB;AAAA,IAC7D,IACA;AAAA,EACN;AAEA,MAAI,gBAAgB;AAAA,IAClB,IAAI;AAAA,IACJ,QAAQ;AACN,0BAAoB,MAAM;AAAA,IAC5B;AAAA,IACA,OAAO;AACL,0BAAoB,KAAK;AAAA,IAC3B;AAAA,EACF,CAAC;AAED,SAAO,KAAK,oEAAa;AACzB,SAAO;AACT;;;AQhEA,IAAAC,qBAAkC;;;ACAlC,IAAAC,kBAAmC;AAGnC;AAMO,SAAS,gBAAgB,SAA2B;AACzD,QAAM,OAAO,QACV,QAAQ,MAAM,EACd,YAAY,sCAAQ;AAEvB,OACG,QAAQ,sBAAsB,EAC9B,YAAY,8FAAwB,EACpC,OAAO,CAAC,WAAmB;AAC1B,qBAAiB,EAAE,GAAG,gBAAgB,GAAG,QAAQ,OAAO,OAAU,CAAC;AACnE,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,QAAQ,OAAO,MAAM,GAAG,CAAC,IAAI;AAAA,MAC7B,UAAU,gBAAgB;AAAA,IAC5B,CAAC;AAAA,EACH,CAAC;AAGH,OACG,QAAQ,mBAAmB,EAC3B,YAAY,8FAAwB,EACpC,OAAO,CAAC,UAAkB;AACzB,qBAAiB,EAAE,GAAG,gBAAgB,GAAG,QAAQ,OAAO,OAAO,OAAU,CAAC;AAC1E,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,QAAQ,MAAM,MAAM,GAAG,CAAC,IAAI;AAAA,MAC5B,UAAU,gBAAgB;AAAA,IAC5B,CAAC;AAAA,EACH,CAAC;AAEH,OACG,QAAQ,MAAM,EACd,YAAY,kDAAU,EACtB,OAAO,MAAM;AACZ,UAAM,QAAQ,gBAAgB;AAC9B,UAAM,SAAS,MAAM,UAAU,MAAM;AACrC,QAAI,QAAQ;AACV,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,WAAW;AAAA,QACX,QAAQ,OAAO,MAAM,GAAG,CAAC,IAAI;AAAA,QAC7B,UAAU,gBAAgB;AAAA,MAC5B,CAAC;AAAA,IACH,OAAO;AACL,aAAO,EAAE,IAAI,MAAM,WAAW,MAAM,CAAC;AAAA,IACvC;AAAA,EACF,CAAC;AAEH,OACG,QAAQ,OAAO,EACf,YAAY,8DAAY,EACxB,OAAO,MAAM;AACZ,UAAMC,QAAO,gBAAgB;AAC7B,YAAI,4BAAWA,KAAI,GAAG;AACpB,YAAM,QAAQ,gBAAgB;AAC9B,aAAO,MAAM;AACb,aAAO,MAAM;AACb,UAAI,OAAO,KAAK,KAAK,EAAE,WAAW,GAAG;AACnC,oCAAOA,OAAM,EAAE,OAAO,KAAK,CAAC;AAAA,MAC9B,OAAO;AACL,yBAAiB,KAAK;AAAA,MACxB;AAAA,IACF;AACA,WAAO,EAAE,IAAI,MAAM,SAAS,KAAK,CAAC;AAAA,EACpC,CAAC;AACL;;;ACxCO,SAAS,2BACd,UACA,cACA,YACA,WACQ;AACR,QAAM,QAAQ,YAAY,SAAS,SAAS,IAAI,WAAW,OAAO,YAAY;AAC9E,MAAI,CAAC,QAAQ,KAAK,KAAK,GAAG;AACxB,cAAU,WAAW,GAAG,UAAU,sDAAc;AAAA,EAClD;AAEA,QAAM,SAAS,OAAO,SAAS,OAAO,EAAE;AACxC,MAAI,UAAU,GAAG;AACf,cAAU,WAAW,GAAG,UAAU,sDAAc;AAAA,EAClD;AACA,SAAO;AACT;AAEO,SAAS,8BACd,MACA,eAAe,KACW;AAC1B,QAAM,QAAQ;AAAA,IACZ,KAAK;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,MACE,KAAK,oBACF,KAAK,qBAAqB,WAC1B,KAAK,qBAAqB,WAC7B;AACA;AAAA,MACE;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,QAAM,UAAU,OAAO,KAAK,SAAS,YAAY,KAAK,KAAK,SAAS;AACpE,QAAM,QAAQ,OAAO,KAAK,OAAO,YAAY,KAAK,GAAG,SAAS;AAC9D,QAAM,SAAS,UAAU,aAAa,KAAK,MAAO,QAAQ,IAAI;AAC9D,QAAM,OAAO,QAAQ,aAAa,KAAK,IAAK,MAAM,IAAI;AAEtD,MAAI,WAAW,QAAQ,SAAS,QAAQ,SAAS,MAAM;AACrD,cAAU,sBAAsB,sCAAkB;AAAA,EACpD;AAEA,SAAO;AAAA,IACL,MAAM,KAAK;AAAA,IACX,IAAI,KAAK;AAAA,IACT,KAAK,KAAK;AAAA,IACV,QAAQ,KAAK;AAAA,IACb,kBAAkB,KAAK;AAAA,IACvB,SAAS,KAAK;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa,UAAU,KAAK,KAAM,MAAM,GAAG,EAAE,IAAI;AAAA,IACjD,WAAW,QAAQ,KAAK,GAAI,MAAM,GAAG,EAAE,IAAI;AAAA,EAC7C;AACF;AAEO,SAAS,yBACd,MACA,MACS;AACT,MAAI,KAAK,OAAO,CAAC,6BAA6B,MAAM,KAAK,GAAG,EAAG,QAAO;AACtE,MACE,KAAK,oBACF,KAAK,qBAAqB,KAAK,kBAClC;AACA,WAAO;AAAA,EACT;AAEA,QAAM,iBAAiB,CAAC,KAAK,YAAY,KAAK,KAAK,EAChD,OAAO,CAAC,UAA2B,OAAO,UAAU,YAAY,MAAM,SAAS,CAAC,EAChF,KAAK,IAAI;AACZ,MAAI,KAAK,UAAU,CAAC,eAAe,SAAS,KAAK,MAAM,EAAG,QAAO;AAEjE,QAAM,kBAAkB;AAAA,IACtB,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,EACP,EACG,OAAO,CAAC,UAA2B,OAAO,UAAU,YAAY,MAAM,SAAS,CAAC,EAChF,KAAK,IAAI;AACZ,MAAI,KAAK,WAAW,CAAC,gBAAgB,SAAS,KAAK,OAAO,EAAG,QAAO;AAEpE,QAAM,SAAS,KAAK,MAAM,KAAK,SAAS;AACxC,MAAI,OAAO,MAAM,MAAM,EAAG,QAAO;AACjC,MAAI,KAAK,WAAW,QAAQ,SAAS,KAAK,OAAQ,QAAO;AACzD,MAAI,KAAK,SAAS,QAAQ,SAAS,KAAK,KAAM,QAAO;AAErD,SAAO;AACT;AAEA,eAAsB,6BACpB,KACA,MAC+B;AAC/B,QAAM,OAAO,MAAM,kBAAkB,GAAG;AACxC,QAAM,UAAgC,CAAC;AACvC,QAAM,oBAAoB,KAAK,WAAW,QAAQ,KAAK,SAAS;AAEhE,aAAW,WAAW,MAAM;AAC1B,QAAI,KAAK,eAAe,UAAU,KAAK,YAAa;AACpD,QAAI,KAAK,aAAa,UAAU,KAAK,UAAW;AAEhD,UAAM,QAAQ,iCAAiC;AAAA,MAC7C,GAAI,MAAM,kBAAkB,KAAK,OAAO;AAAA,IAC1C,CAAC;AACD,eAAW,QAAQ,OAAO;AACxB,UAAI,CAAC,yBAAyB,MAAM,IAAI,EAAG;AAC3C,cAAQ,KAAK,IAAI;AACjB,UAAI,qBAAqB,QAAQ,UAAU,KAAK,OAAO;AACrD,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAEA,SAAO,iCAAiC,OAAO,EAAE,MAAM,GAAG,KAAK,KAAK;AACtE;;;ACjJO,SAAS,kBAAkB,KAAiB,KAAuB;AACxE,MACG,QAAQ,QAAQ,EAChB,YAAY,uHAAwB,EACpC,OAAO,iBAAiB,+EAA4C,EACpE,OAAO,eAAe,+EAA4C,EAClE,OAAO,gBAAgB,sCAAQ,EAC/B,OAAO,mBAAmB,sCAAQ,EAClC;AAAA,IACC;AAAA,IACA;AAAA,EACF,EACC,OAAO,oBAAoB,0EAAc,EACzC,OAAO,eAAe,wCAAU,KAAK,EACrC;AAAA,IACC,OAAO,SAQD;AACJ,YAAM,MAAM,wBAAwB,GAAG;AACvC,UAAI,CAAC,IAAK,WAAU,uBAAuB,wDAAW;AAEtD,eAAS,yCAAW;AAEpB,YAAM,QAAQ,8BAA8B,IAAI;AAChD,YAAM,gBAAgB,MAAM,6BAA6B,KAAK,KAAK;AAEnE,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,OAAO,cAAc;AAAA,QACrB;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AACJ;;;ACxBA,SAAS,oBAAoB,MAA+C;AAC1E,QAAM,SAA8B;AAAA,IAClC,SAAS,KAAK;AAAA,IACd,OAAO,KAAK;AAAA,IACZ,SAAS,KAAK;AAAA,IACd,WAAW,KAAK;AAAA,EAClB;AACA,MAAI,KAAK,eAAgB,QAAO,iBAAiB,KAAK;AACtD,MAAI,KAAK,WAAY,QAAO,aAAa,KAAK;AAC9C,MAAI,KAAK,iBAAkB,QAAO,mBAAmB,KAAK;AAC1D,MAAI,KAAK,iBAAkB,QAAO,mBAAmB,KAAK;AAC1D,SAAO;AACT;AAEA,SAAS,SAAS,OAAe,YAAY,KAAa;AACxD,MAAI,MAAM,UAAU,UAAW,QAAO;AACtC,SAAO,GAAG,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC;AACzC;AAEA,SAAS,UACP,KACA,KACA,MACM;AACN,QAAM,WAAW,IAAI,IAAI,GAAG;AAC5B,MAAI,UAAU;AACZ,aAAS,SAAS;AAClB;AAAA,EACF;AACA,MAAI,IAAI,KAAK,EAAE,GAAG,MAAM,OAAO,EAAE,CAAC;AACpC;AAEA,SAAS,QACP,KACA,OACe;AACf,SAAO,CAAC,GAAG,IAAI,OAAO,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,KAAK;AAC3E;AAEA,SAAS,WAAW,WAAkC;AACpD,QAAM,QAAQ,gCAAgC,KAAK,SAAS;AAC5D,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO,GAAG,MAAM,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC;AAChC;AAEA,SAAS,qBACP,eACA,YAC6D;AAC7D,SAAO,WAAW,IAAI,CAAC,QAAQ;AAC7B,UAAM,UAAoB,CAAC;AAC3B,eAAW,QAAQ,eAAe;AAChC,YAAM,SAAS,KAAK,YAAY,KAAK,KAAK,KAAK,OAAO,KAAK,KAAK;AAChE,UAAI,WAAW,IAAI,OAAQ;AAC3B,YAAM,UAAU,SAAS,KAAK,QAAQ,KAAK,CAAC;AAC5C,UAAI,WAAW,CAAC,QAAQ,SAAS,OAAO,EAAG,SAAQ,KAAK,OAAO;AAC/D,UAAI,QAAQ,UAAU,EAAG;AAAA,IAC3B;AACA,WAAO,EAAE,QAAQ,IAAI,QAAQ,OAAO,IAAI,OAAO,QAAQ;AAAA,EACzD,CAAC;AACH;AAEO,SAAS,mBAAmB,KAAiB,KAAuB;AACzE,MACG,QAAQ,SAAS,EACjB,YAAY,gJAAkC,EAC9C,OAAO,iBAAiB,+EAA4C,EACpE,OAAO,eAAe,+EAA4C,EAClE,OAAO,gBAAgB,sCAAQ,EAC/B,OAAO,mBAAmB,sCAAQ,EAClC;AAAA,IACC;AAAA,IACA;AAAA,EACF,EACC,OAAO,oBAAoB,0EAAc,EACzC,OAAO,eAAe,sEAAe,KAAK,EAC1C,OAAO,gBAAgB,oDAAY,IAAI,EACvC,OAAO,aAAa,oDAAY,IAAI,EACpC;AAAA,IACC,OAAO,SAUD;AACJ,YAAM,MAAM,wBAAwB,GAAG;AACvC,UAAI,CAAC,IAAK,WAAU,uBAAuB,wDAAW;AAEtD,eAAS,iEAAe;AAExB,YAAM,QAAQ,8BAA8B,IAAI;AAChD,YAAM,cAAc;AAAA,QAClB,KAAK;AAAA,QACL;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACA,YAAM,WAAW;AAAA,QACf,KAAK;AAAA,QACL;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAEA,YAAM,gBAAgB,MAAM,6BAA6B,KAAK,KAAK;AACnE,YAAM,QAAQ,oBAAI,IAGhB;AACF,YAAM,WAAW,oBAAI,IAA0C;AAC/D,YAAM,iBAAiB,oBAAI,IAGzB;AACF,YAAM,SAAS,oBAAI,IAAwC;AAE3D,iBAAW,QAAQ,eAAe;AAChC,cAAM,SAAS,GAAG,KAAK,OAAO,KAAK,KAAK,kBAAkB,EAAE;AAC5D,kBAAU,OAAO,QAAQ;AAAA,UACvB,SAAS,KAAK;AAAA,UACd,GAAI,KAAK,iBAAiB,EAAE,gBAAgB,KAAK,eAAe,IAAI,CAAC;AAAA,QACvE,CAAC;AAED,cAAM,SAAS,KAAK,YAAY,KAAK,KAAK,KAAK,OAAO,KAAK,KAAK;AAChE,kBAAU,UAAU,QAAQ,EAAE,OAAO,CAAC;AAEtC,cAAM,mBACJ,KAAK,kBAAkB,KAAK,KAAK,KAAK,OAAO,KAAK,KAAK;AACzD,cAAM,kBAAkB,GAAG,gBAAgB,KAAK,KAAK,oBAAoB,EAAE;AAC3E,kBAAU,gBAAgB,iBAAiB;AAAA,UACzC;AAAA,UACA,GAAI,KAAK,mBACL,EAAE,kBAAkB,KAAK,iBAAiB,IAC1C,CAAC;AAAA,QACP,CAAC;AAED,cAAM,OAAO,WAAW,KAAK,SAAS;AACtC,YAAI,KAAM,WAAU,QAAQ,MAAM,EAAE,KAAK,CAAC;AAAA,MAC5C;AAEA,YAAM,aAAa,QAAQ,UAAU,QAAQ;AAC7C,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,OAAO,MAAM;AAAA,QACb,OAAO,cAAc;AAAA,QACrB,OAAO;AAAA,UACL,QAAQ,cAAc,CAAC,GAAG,aAAa;AAAA,UACvC,QAAQ,cAAc,cAAc,SAAS,CAAC,GAAG,aAAa;AAAA,QAChE;AAAA,QACA,OAAO,QAAQ,OAAO,QAAQ;AAAA,QAC9B,UAAU;AAAA,QACV,gBAAgB,QAAQ,gBAAgB,QAAQ;AAAA,QAChD,QAAQ,QAAQ,QAAQ,QAAQ;AAAA,QAChC,QAAQ,cAAc,MAAM,GAAG,WAAW,EAAE,IAAI,mBAAmB;AAAA,QACnE,iBAAiB,qBAAqB,eAAe,UAAU;AAAA,MACjE,CAAC;AAAA,IACH;AAAA,EACF;AACJ;;;AC/KO,SAAS,iBAAiB,KAAiB,KAAuB;AACvE,MACG,QAAQ,OAAO,EACf,YAAY,6HAAyB,EACrC,OAAO,iBAAiB,uCAAmB,QAAQ,CAAC,CAAC,EACrD,OAAO,eAAe,uCAAmB,MAAM,CAAC,EAChD,OAAO,gBAAgB,4CAAS,EAChC,OAAO,qBAAqB,0DAAiC,KAAK,EAClE;AAAA,IACC,CAAC,SAAkE;AACjE,YAAM,MAAM,wBAAwB,GAAG;AACvC,UAAI,CAAC,IAAK,WAAU,uBAAuB,wDAAW;AAEtD,YAAM,MAAM,KAAK;AACjB,YAAM,OAAO,gBAAgB,aAAa,GAAG,GAAG,KAAK,MAAM,KAAK,EAAE;AAElE,YAAM,SAAiC,CAAC;AACxC,YAAM,QAAgC,CAAC;AACvC,YAAM,WAAmC,CAAC;AAC1C,YAAM,SAAiC,CAAC;AACxC,UAAI,QAAQ;AAEZ,iBAAW,WAAW,MAAM;AAC1B,cAAM,QAAQ,aAAa,KAAK,OAAO;AACvC,YAAI,YAAY;AAChB,mBAAW,QAAQ,OAAO;AACxB,cAAI,KAAK,OAAO,CAAC,6BAA6B,MAAM,KAAK,GAAG,EAAG;AAC/D;AACA;AAEA,gBAAM,KAAK,OAAO,KAAK,MAAM,KAAK,OAAO,KAAK,KAAK;AAEnD,gBAAM,SAAS,KAAK,YAAY,KAAK,KAAK,KAAK,OAAO,KAAK;AAC3D,cAAI,QAAQ;AACV,qBAAS,MAAM,KAAK,SAAS,MAAM,KAAK,KAAK;AAAA,UAC/C;AAEA,gBAAM,YAAY,YAAY,KAAK,KAAK,SAAS;AACjD,cAAI,WAAW;AACb,kBAAM,IAAI,UAAU,CAAC;AACrB,mBAAO,CAAC,KAAK,OAAO,CAAC,KAAK,KAAK;AAAA,UACjC;AAAA,QACF;AACA,eAAO,OAAO,IAAI;AAAA,MACpB;AAEA,YAAM,SAAkC;AAAA,QACtC,IAAI;AAAA,QACJ,OAAO,EAAE,MAAM,KAAK,MAAM,IAAI,KAAK,GAAG;AAAA,QACtC;AAAA,MACF;AAEA,UAAI,QAAQ,UAAU,QAAQ,OAAO;AACnC,eAAO,SAAS;AAAA,MAClB;AACA,UAAI,QAAQ,SAAS,QAAQ,OAAO;AAClC,eAAO,QAAQ;AAAA,MACjB;AACA,UAAI,QAAQ,YAAY,QAAQ,OAAO;AAErC,cAAM,SAAS,OAAO,QAAQ,QAAQ,EACnC,KAAK,CAAC,GAAG,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,EAC1B,MAAM,GAAG,EAAE,EACX,IAAI,CAAC,CAAC,QAAQ,KAAK,OAAO,EAAE,QAAQ,MAAM,EAAE;AAC/C,eAAO,WAAW;AAAA,MACpB;AACA,UAAI,QAAQ,UAAU,QAAQ,OAAO;AACnC,eAAO,SAAS;AAAA,MAClB;AAEA,aAAO,MAAM;AAAA,IACf;AAAA,EACF;AACJ;;;ACzFA,IAAAC,mBAAwD;AACxD,IAAAC,oBAAqB;AAerB,IAAM,mBAAmB;AAEzB,SAAS,eAAe,KAAqB;AAC3C,aAAO,wBAAK,KAAK,kBAAkB;AACrC;AAEA,SAAS,eAAe,KAA6B;AACnD,QAAM,IAAI,eAAe,GAAG;AAC5B,MAAI,KAAC,6BAAW,CAAC,EAAG,QAAO,CAAC;AAC5B,MAAI;AACF,WAAO,KAAK,UAAM,+BAAa,GAAG,OAAO,CAAC;AAAA,EAC5C,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEA,SAAS,gBAAgB,KAAa,MAA4B;AAChE,sCAAc,eAAe,GAAG,GAAG,KAAK,UAAU,MAAM,MAAM,CAAC,GAAG,OAAO;AAC3E;AAEO,SAAS,gBAAgB,KAAiB,KAAuB;AACtE,QAAM,OAAO,IAAI,QAAQ,MAAM,EAAE,YAAY,wDAAW;AAExD,OACG,QAAQ,MAAM,EACd,YAAY,kGAAkB,EAC9B,OAAO,MAAM;AACZ,UAAM,MAAM,wBAAwB,GAAG;AACvC,QAAI,CAAC,IAAK,WAAU,uBAAuB,wDAAW;AAEtD,UAAM,aAAa,eAAe,GAAG;AACrC,UAAM,OAAO,aAAa,GAAG;AAC7B,UAAM,UAAiE,CAAC;AACxE,QAAI,eAAe;AAEnB,eAAW,WAAW,MAAM;AAC1B,YAAM,QAAQ,aAAa,KAAK,OAAO;AACvC,YAAM,YAAY,WAAW,OAAO,GAAG,aAAa;AACpD,YAAM,cAAc,MAAM,UAAU,YAAY;AAChD,UAAI,cAAc,GAAG;AACnB,gBAAQ,KAAK;AAAA,UACX,MAAM;AAAA,UACN,OAAO;AAAA,UACP,YAAY,YAAY;AAAA,QAC1B,CAAC;AACD,wBAAgB;AAAA,MAClB;AAAA,IACF;AAEA,WAAO,EAAE,IAAI,MAAM,SAAS,aAAa,CAAC;AAAA,EAC5C,CAAC;AAEH,OACG,QAAQ,OAAO,EACf,YAAY,sFAAgB,EAC5B,eAAe,iBAAiB,qCAAiB,EACjD,OAAO,2BAA2B,yFAAwB,EAC1D,OAAO,CAAC,SAAiD;AACxD,UAAM,MAAM,wBAAwB,GAAG;AACvC,QAAI,CAAC,IAAK,WAAU,uBAAuB,wDAAW;AAEtD,UAAM,QAAQ,aAAa,KAAK,KAAK,IAAI;AACzC,QAAI,MAAM,WAAW,GAAG;AACtB,gBAAU,WAAW,gBAAM,KAAK,IAAI,iCAAQ;AAAA,IAC9C;AAEA,UAAM,aAAa,eAAe,GAAG;AACrC,UAAM,YAAY,WAAW,KAAK,IAAI,GAAG,aAAa;AACtD,UAAM,aAAa,YAAY;AAC/B,QAAI,cAAc,MAAM,SAAS;AACjC,QAAI,OAAO,KAAK,gBAAgB,YAAY,KAAK,YAAY,SAAS,GAAG;AACvE,oBAAc,OAAO,SAAS,KAAK,aAAa,EAAE;AAClD,UAAI,CAAC,OAAO,UAAU,WAAW,KAAK,OAAO,WAAW,MAAM,KAAK,aAAa;AAC9E,kBAAU,yBAAyB,4DAAyB;AAAA,MAC9D;AACA,UAAI,cAAc,GAAG;AACnB,kBAAU,yBAAyB,4DAAyB;AAAA,MAC9D;AACA,oBAAc,KAAK,IAAI,aAAa,MAAM,SAAS,CAAC;AAAA,IACtD;AACA,UAAM,uBAAuB,KAAK,IAAI,YAAY,cAAc,CAAC;AACjE,UAAM,cAAc,MAAM,MAAM,YAAY,oBAAoB;AAChE,UAAM,gBAAgB,YAAY,MAAM,GAAG,gBAAgB;AAC3D,UAAM,WACJ,cAAc,SAAS,IAAI,aAAa,cAAc,SAAS,IAAI;AACrE,UAAM,UAAU,YAAY,SAAS,cAAc;AAEnD,QAAI,YAAY,WAAW,GAAG;AAC5B,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,MAAM,KAAK;AAAA,QACX;AAAA,QACA;AAAA,QACA,gBAAgB;AAAA,QAChB,OAAO;AAAA,QACP;AAAA,QACA,UAAU;AAAA,QACV,kBAAkB;AAAA,QAClB,SAAS;AAAA,QACT,eAAe,CAAC;AAAA,MAClB,CAAC;AACD;AAAA,IACF;AAEA,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,MAAM,KAAK;AAAA,MACX;AAAA,MACA;AAAA,MACA,gBAAgB,UAAU,WAAW,IAAI;AAAA,MACzC,OAAO;AAAA,MACP;AAAA,MACA,UAAU,cAAc;AAAA,MACxB,kBAAkB,YAAY;AAAA,MAC9B;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AAEH,OACG,QAAQ,QAAQ,EAChB,YAAY,mHAA8B,EAC1C,eAAe,iBAAiB,qCAAiB,EACjD,OAAO,uBAAuB,sDAAwB,EACtD,OAAO,CAAC,SAA8C;AACrD,UAAM,MAAM,wBAAwB,GAAG;AACvC,QAAI,CAAC,IAAK,WAAU,uBAAuB,wDAAW;AAEtD,UAAM,QAAQ,aAAa,KAAK,KAAK,IAAI;AACzC,QAAI,MAAM,WAAW,GAAG;AACtB,gBAAU,WAAW,gBAAM,KAAK,IAAI,iCAAQ;AAAA,IAC9C;AAEA,UAAM,aAAa,eAAe,GAAG;AACrC,UAAM,YAAY,WAAW,KAAK,IAAI,GAAG,aAAa;AACtD,QAAI;AACJ,QAAI,OAAO,KAAK,aAAa,YAAY,KAAK,SAAS,SAAS,GAAG;AACjE,uBAAiB,OAAO,SAAS,KAAK,UAAU,EAAE;AAClD,UAAI,CAAC,OAAO,UAAU,cAAc,KAAK,OAAO,cAAc,MAAM,KAAK,UAAU;AACjF,kBAAU,qBAAqB,wDAAqB;AAAA,MACtD;AACA,UAAI,iBAAiB,KAAK,kBAAkB,MAAM,QAAQ;AACxD;AAAA,UACE;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA,UAAI,iBAAiB,WAAW;AAC9B;AAAA,UACE;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA,UAAI,iBAAiB,YAAY,kBAAkB;AACjD;AAAA,UACE;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAAA,IACF,OAAO;AACL,uBAAiB,KAAK,IAAI,MAAM,SAAS,GAAG,YAAY,gBAAgB;AAAA,IAC1E;AACA,UAAM,UAAU,iBAAiB,MAAM,SAAS;AAChD,eAAW,KAAK,IAAI,IAAI,EAAE,WAAW,eAAe;AACpD,oBAAgB,KAAK,UAAU;AAE/B,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,MAAM,KAAK;AAAA,MACX;AAAA,MACA,YACE,OAAO,KAAK,aAAa,YAAY,KAAK,SAAS,SAAS,IACxD,oBACA;AAAA,MACN,OAAO;AAAA,MACP;AAAA,MACA,gBAAgB,UAAU,iBAAiB,IAAI;AAAA,IACjD,CAAC;AAAA,EACH,CAAC;AACL;;;ACnMA,IAAAC,mBAOO;AACP,IAAAC,qBAAqB;;;ACLd,SAAS,gBACd,MACA,YACQ;AACR,QAAM,UAAU,OAAO,WAAW,YAAY,WAAW,WAAW,UAAU;AAC9E,QAAM,iBAAiB,YAAY,WAAW,cAAc;AAC5D,QAAM,kBAAkB,YAAY,WAAW,eAAe;AAE9D,SAAO;AAAA,mDAC0C,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAUtC,UAAU,OAAO,CAAC;AAAA;AAAA;AAAA;AAAA,wBAIX,UAAU,cAAc,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,yBAKxB,UAAU,eAAe,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA6CnD;AAEA,SAAS,YAAY,OAA0B;AAC7C,MAAI,CAAC,MAAM,QAAQ,KAAK,EAAG,QAAO,CAAC;AACnC,SAAO,MAAM,OAAO,CAAC,SAAyB,OAAO,SAAS,YAAY,KAAK,SAAS,CAAC;AAC3F;AAEA,SAAS,UAAU,OAAkC;AACnD,SAAO,KAAK,UAAU,KAAK;AAC7B;;;AD9DA,SAASC,UAAS,KAAyB;AACzC,QAAM,OAAO,IAAI,gBAAgB,IAAI;AACrC,MAAI,CAAC,KAAM,OAAM,IAAI,MAAM,4CAA4C;AACvE,aAAO,yBAAK,MAAM,OAAO;AAC3B;AAEA,SAASC,UAAS,SAAqC;AACrD,QAAM,eAAW,yBAAK,SAAS,WAAW;AAC1C,MAAI,KAAC,6BAAW,QAAQ,EAAG,QAAO;AAClC,MAAI;AACF,WAAO,KAAK,UAAM,+BAAa,UAAU,OAAO,CAAC;AAAA,EACnD,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAASC,WAAU,SAAiB,MAAyB;AAC3D,0CAAc,yBAAK,SAAS,WAAW,GAAG,KAAK,UAAU,MAAM,MAAM,CAAC,GAAG,OAAO;AAClF;AAEA,SAAS,eAAe,MAAc,aAA6B;AACjE,SAAO,mBAAmB,IAAI;AAAA;AAAA;AAAA,EAG9B,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQb;AAEO,SAAS,mBAAmB,KAAiB,KAAuB;AACzE,QAAM,UAAU,IAAI,QAAQ,SAAS,EAAE,YAAY,kDAAU;AAE7D,UACG,QAAQ,MAAM,EACd,YAAY,kDAAU,EACtB,OAAO,MAAM;AACZ,UAAM,MAAMF,UAAS,GAAG;AACxB,QAAI,KAAC,6BAAW,GAAG,GAAG;AACpB,aAAO,EAAE,IAAI,MAAM,OAAO,CAAC,EAAE,CAAC;AAC9B;AAAA,IACF;AAEA,UAAM,QAAuB,CAAC;AAC9B,eAAW,aAAS,8BAAY,KAAK,EAAE,eAAe,KAAK,CAAC,GAAG;AAC7D,UAAI,CAAC,MAAM,YAAY,EAAG;AAC1B,YAAM,OAAOC,cAAS,yBAAK,KAAK,MAAM,IAAI,CAAC;AAC3C,UAAI,KAAM,OAAM,KAAK,IAAI;AAAA,IAC3B;AAEA,WAAO,EAAE,IAAI,MAAM,MAAM,CAAC;AAAA,EAC5B,CAAC;AAEH,UACG,QAAQ,aAAa,EACrB,YAAY,kDAAU,EACtB,OAAO,CAAC,SAAiB;AACxB,UAAM,cAAU,yBAAKD,UAAS,GAAG,GAAG,IAAI;AACxC,UAAM,OAAOC,UAAS,OAAO;AAC7B,QAAI,CAAC,KAAM,WAAU,aAAa,6BAAS,IAAI,sBAAO;AAEtD,UAAME,sBAAiB,yBAAK,SAAS,iBAAiB;AACtD,QAAI,aAAa,CAAC;AAClB,YAAI,6BAAWA,eAAc,GAAG;AAC9B,UAAI;AACF,qBAAa,KAAK,UAAM,+BAAaA,iBAAgB,OAAO,CAAC;AAAA,MAC/D,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,GAAG;AAAA,MACH,aAAa,SAAS,IAAI;AAAA,MAC1B,QAAQ,SAAS,IAAI;AAAA,MACrB;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AAEH,UACG,QAAQ,eAAe,EACvB,YAAY,sCAAQ,EACpB,eAAe,wBAAwB,0BAAM,EAC7C,eAAe,wBAAwB,+BAAW,EAClD,eAAe,qBAAqB,yBAAU,EAC9C;AAAA,IACC,CACE,MACA,SAKG;AACH,YAAM,MAAMH,UAAS,GAAG;AACxB,YAAM,cAAU,yBAAK,KAAK,IAAI;AAE9B,cAAI,6BAAW,OAAO,GAAG;AACvB,kBAAU,kBAAkB,6BAAS,IAAI,sBAAO;AAAA,MAClD;AAEA,UAAI;AACJ,UAAI;AACF,qBAAa,KAAK,MAAM,KAAK,UAAU;AAAA,MACzC,QAAQ;AACN;AAAA,UACE;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAEA,sCAAU,SAAS,EAAE,WAAW,KAAK,CAAC;AAEtC,YAAM,OAAoB;AAAA,QACxB;AAAA,QACA,aAAa,KAAK;AAAA,QAClB;AAAA,QACA,cAAc,KAAK;AAAA,QACnB,SAAS;AAAA,QACT,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MACpC;AACA,MAAAE,WAAU,SAAS,IAAI;AACvB;AAAA,YACE,yBAAK,SAAS,UAAU;AAAA,QACxB,gBAAgB,MAAM,UAAU;AAAA,QAChC;AAAA,MACF;AACA;AAAA,YACE,yBAAK,SAAS,WAAW;AAAA,QACzB,eAAe,MAAM,KAAK,WAAW;AAAA,QACrC;AAAA,MACF;AAEA,aAAO;AAAA,QACL,IAAI;AAAA,QACJ;AAAA,QACA,SAAS;AAAA,UACP,QAAQ,SAAS,IAAI;AAAA,UACrB,QAAQ,SAAS,IAAI;AAAA,UACrB,SAAS,SAAS,IAAI;AAAA,QACxB;AAAA,QACA,UAAU;AAAA,UACR,QAAQ;AAAA,UACR,KAAK;AAAA,YACH,MAAM,SAAS,IAAI;AAAA,YACnB,UAAU,KAAK;AAAA,YACf,eAAe;AAAA,YACf,SAAS;AAAA,kCAAkE,IAAI;AAAA;AAAA,2CAAoG,IAAI;AAAA,UACzL;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAEF,UACG,QAAQ,eAAe,EACvB,YAAY,sCAAQ,EACpB,OAAO,SAAS,0BAAM,EACtB,OAAO,CAAC,MAAc,SAA4B;AACjD,UAAM,cAAU,yBAAKF,UAAS,GAAG,GAAG,IAAI;AACxC,QAAI,KAAC,6BAAW,OAAO,GAAG;AACxB,gBAAU,aAAa,6BAAS,IAAI,sBAAO;AAAA,IAC7C;AAEA,QAAI,CAAC,KAAK,KAAK;AACb,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,OAAO;AAAA,UACL,MAAM;AAAA,UACN,SAAS,qDAAa,IAAI;AAAA,QAC5B;AAAA,MACF,CAAC;AACD,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,iCAAO,SAAS,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAChD,WAAO;AAAA,MACL,IAAI;AAAA,MACJ;AAAA,MACA,SAAS;AAAA,MACT,UAAU;AAAA,QACR,QAAQ;AAAA,QACR,MAAM,SAAS,IAAI;AAAA,MACrB;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AAEH,UACG,QAAQ,eAAe,EACvB,YAAY,sCAAQ,EACpB,OAAO,CAAC,SAAiB;AACxB,UAAM,cAAU,yBAAKA,UAAS,GAAG,GAAG,IAAI;AACxC,UAAM,OAAOC,UAAS,OAAO;AAC7B,QAAI,CAAC,KAAM,WAAU,aAAa,6BAAS,IAAI,sBAAO;AAEtD,SAAK,UAAU;AACf,IAAAC,WAAU,SAAS,IAAI;AACvB,WAAO,EAAE,IAAI,MAAM,MAAM,SAAS,KAAK,CAAC;AAAA,EAC1C,CAAC;AAEH,UACG,QAAQ,gBAAgB,EACxB,YAAY,sCAAQ,EACpB,OAAO,CAAC,SAAiB;AACxB,UAAM,cAAU,yBAAKF,UAAS,GAAG,GAAG,IAAI;AACxC,UAAM,OAAOC,UAAS,OAAO;AAC7B,QAAI,CAAC,KAAM,WAAU,aAAa,6BAAS,IAAI,sBAAO;AAEtD,SAAK,UAAU;AACf,IAAAC,WAAU,SAAS,IAAI;AACvB,WAAO,EAAE,IAAI,MAAM,MAAM,SAAS,MAAM,CAAC;AAAA,EAC3C,CAAC;AACL;;;AE/OA;AAKO,SAAS,kBAAkB,OAAyB;AACzD,QACG,QAAQ,MAAM,EACd,YAAY,oEAAa,EACzB,eAAe,qBAAqB,+BAAW,EAC/C,OAAO,YAAY,4FAAiB,EACpC,OAAO,sBAAsB,oJAAsC,EACnE,OAAO,OAAO,SAAuE;AACpF,QAAI;AACJ,QAAI;AACF,eAAS,cAAc;AAAA,IACzB,SAAS,GAAQ;AACf,gBAAU,iBAAiB,EAAE,OAAO;AAAA,IACtC;AAEA,UAAM,WAAW,yBAAyB,KAAK,QAAQ;AACvD,QAAI;AACJ,QAAI;AACF,oBAAc,qBAAqB;AAAA,QACjC,QAAQ,KAAK;AAAA,QACb,cAAc,KAAK,gBAAgB,SAAY,SAAY,OAAO,KAAK,WAAW;AAAA,MACpF,CAAC;AACD,4BAAsB,WAAW;AAAA,IACnC,SAAS,GAAQ;AACf,gBAAU,qBAAqB,EAAE,OAAO;AAAA,IAC1C;AAEA,UAAM,SAAS,MAAM;AAAA,MACnB;AAAA,MACA;AAAA,MACA;AAAA,MACA,EAAE,cAAc,YAAY;AAAA,IAC9B;AAEA,QAAI,CAAC,OAAO,IAAI;AACd,gBAAU,cAAc,6BAAS,OAAO,MAAM,IAAI,OAAO,KAAK,EAAE;AAAA,IAClE;AAEA,WAAO,EAAE,IAAI,MAAM,aAAa,OAAO,aAAa,UAAU,OAAO,SAAS,CAAC;AAAA,EACjF,CAAC;AACL;;;AC9CA,IAAAE,mBAAmE;AACnE,IAAAC,kBAAwB;AACxB,IAAAC,qBAA8B;AAM9B,SAAS,SAAS,OAAqC;AACrD,SAAO,CAAC,CAAC,SAAS,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK;AACrE;AAEA,SAAS,YAAY,KAAiB,KAAwB;AAC5D,QAAM,UAAU,IAAI,GAAG;AACvB,MAAI,MAAM,QAAQ,OAAO,EAAG,QAAO;AACnC,QAAM,OAAkB,CAAC;AACzB,MAAI,GAAG,IAAI;AACX,SAAO;AACT;AAEA,SAASC,qBAA4B;AACnC,QAAM,UAAU,QAAQ,IAAI,sBAAsB,KAAK;AACvD,MAAI,QAAS,QAAO;AACpB,aAAO,6BAAK,yBAAQ,GAAG,aAAa,eAAe;AACrD;AAEA,IAAM,cAAc,CAAC,iBAAiB,GAAG,yBAAyB;AAElE,SAAS,4BAA4B,KAGnC;AACA,MAAI,CAAC,SAAS,IAAI,KAAK,EAAG,KAAI,QAAQ,CAAC;AACvC,QAAM,iBAAiB,YAAY,IAAI,OAAqB,WAAW;AACvE,MAAI,gBAAgB;AACpB,aAAW,QAAQ,aAAa;AAC9B,QAAI,CAAC,eAAe,SAAS,IAAI,GAAG;AAClC,qBAAe,KAAK,IAAI;AACxB,sBAAgB;AAAA,IAClB;AAAA,EACF;AAEA,MAAI,CAAC,SAAS,IAAI,MAAM,EAAG,KAAI,SAAS,CAAC;AACzC,QAAM,SAAS,IAAI;AACnB,QAAM,OAAO,YAAY,QAAQ,MAAM;AACvC,MAAI,YAAY,KAAK;AAAA,IACnB,CAAC,SAAS,SAAS,IAAI,KAAK,KAAK,OAAO;AAAA,EAC1C;AACA,MAAI,CAAC,WAAW;AACd,gBAAY,EAAE,IAAI,OAAO;AACzB,SAAK,KAAK,SAAS;AAAA,EACrB;AACA,MAAI,CAAC,SAAS,UAAU,KAAK,EAAG,WAAU,QAAQ,CAAC;AACnD,QAAM,gBAAgB,YAAY,UAAU,OAAqB,WAAW;AAC5E,MAAI,mBAAmB;AACvB,aAAW,QAAQ,aAAa;AAC9B,QAAI,CAAC,cAAc,SAAS,IAAI,GAAG;AACjC,oBAAc,KAAK,IAAI;AACvB,yBAAmB;AAAA,IACrB;AAAA,EACF;AAEA,SAAO,EAAE,eAAe,iBAAiB;AAC3C;AAEO,SAAS,wBAAwB,OAAyB;AAC/D,QACG,QAAQ,OAAO,EACf,YAAY,mHAAsE,EAClF,OAAO,MAAM;AACZ,UAAM,aAAaA,mBAAkB;AACrC,QAAI,KAAC,6BAAW,UAAU,GAAG;AAC3B,gBAAU,oBAAoB,+CAAY,UAAU,EAAE;AAAA,IACxD;AAEA,QAAI,MAAkB,CAAC;AACvB,QAAI;AACF,YAAM,UAAM,+BAAa,YAAY,OAAO;AAC5C,YAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,UAAI,SAAS,MAAM,EAAG,OAAM;AAAA,IAC9B,SAASC,MAAU;AACjB,gBAAU,kBAAkB,sDAAcA,MAAK,WAAW,OAAOA,IAAG,CAAC,EAAE;AAAA,IACzE;AAEA,UAAM,SAAS,4BAA4B,GAAG;AAC9C,QAAI;AACF,0CAAU,4BAAQ,UAAU,GAAG,EAAE,WAAW,KAAK,CAAC;AAClD,0CAAc,YAAY,KAAK,UAAU,KAAK,MAAM,CAAC,IAAI,MAAM,OAAO;AAAA,IACxE,SAASA,MAAU;AACjB,gBAAU,gBAAgB,yCAAWA,MAAK,WAAW,OAAOA,IAAG,CAAC,EAAE;AAAA,IACpE;AAEA,WAAO;AAAA,MACL,IAAI;AAAA,MACJ;AAAA,MACA,SAAS,OAAO,iBAAiB,OAAO;AAAA,MACxC,SAAS;AAAA,QACP,gBAAgB,OAAO,gBAAgB,UAAU;AAAA,QACjD,oBAAoB,OAAO,mBAAmB,UAAU;AAAA,MAC1D;AAAA,MACA,MAAM;AAAA,IACR,CAAC;AAAA,EACH,CAAC;AACL;;;ACvGA;AACA;;;ACDA,IAAAC,mBAAyC;AACzC,IAAAC,qBAAqB;AAGd,IAAM,6BAAyB;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AACF;AACO,IAAM,2BAAuB;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AACF;AAuBA,SAAS,cAAc,OAAsC;AAC3D,SACE,UAAU,eACV,UAAU,gBACV,UAAU,kBACV,UAAU;AAEd;AAEA,SAAS,mBAAmB,OAA2C;AACrE,MAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,EAAG,QAAO;AACxE,QAAM,MAAM;AACZ,SACE,cAAc,IAAI,KAAK,KACvB,OAAO,IAAI,UAAU,YACrB,OAAO,IAAI,qBAAqB,aAC/B,IAAI,yBAAyB,UAC5B,OAAO,IAAI,yBAAyB;AAE1C;AAEA,SAAS,oBAAoB,OAAuC;AAClE,MAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,EAAG,QAAO;AACxE,QAAM,MAAM;AACZ,SAAO,OAAO,IAAI,QAAQ,YAAY,OAAO,IAAI,cAAc,WAC3D,EAAE,KAAK,IAAI,KAAK,WAAW,IAAI,UAAU,IACzC;AACN;AAEA,SAAS,eAAe,KAAsB;AAC5C,MAAI,CAAC,OAAO,UAAU,GAAG,KAAK,OAAO,EAAG,QAAO;AAC/C,MAAI,QAAQ,QAAQ,IAAK,QAAO;AAChC,MAAI;AACF,YAAQ,KAAK,KAAK,CAAC;AACnB,WAAO;AAAA,EACT,SAASC,MAAU;AACjB,WAAOA,MAAK,SAAS;AAAA,EACvB;AACF;AAEA,SAAS,sBACP,aACA,eACS;AACT,QAAM,WAAW,KAAK,MAAM,WAAW;AACvC,QAAM,SAAS,KAAK,MAAM,aAAa;AACvC,MAAI,OAAO,MAAM,QAAQ,KAAK,OAAO,MAAM,MAAM,EAAG,QAAO;AAC3D,SAAO,WAAW,MAAO;AAC3B;AAEA,SAAS,mBACP,QACA,MACQ;AACR,QAAM,SAAS,kFAAiB,OAAO,KAAK;AAE5C,MAAI,CAAC,KAAK,QAAQ;AAChB,WAAO,GAAG,MAAM;AAAA,EAClB;AAEA,MAAI,KAAK,QAAQ,QAAQ,KAAK,cAAc,MAAM;AAChD,WAAO,GAAG,MAAM;AAAA,EAClB;AAEA,MAAI,KAAK,WAAW,OAAO;AACzB,WAAO,GAAG,MAAM,wGAAwB,KAAK,GAAG;AAAA,EAClD;AAEA,SAAO,GAAG,MAAM,gEAAc,KAAK,SAAS;AAC9C;AAEO,SAAS,mBAAmB,UAA0C;AAC3E,QAAM,qBAAiB,yBAAK,UAAU,sBAAsB;AAC5D,QAAM,mBAAe,yBAAK,UAAU,oBAAoB;AAExD,MAAI,KAAC,6BAAW,cAAc,GAAG;AAC/B,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,cACE;AAAA,MACF;AAAA,MACA;AAAA,MACA,MAAM;AAAA,QACJ,YAAQ,6BAAW,YAAY;AAAA,QAC/B,KAAK;AAAA,QACL,WAAW;AAAA,QACX,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAEA,MAAI;AACJ,MAAI;AACF,gBAAY,KAAK,UAAM,+BAAa,gBAAgB,OAAO,CAAC;AAAA,EAC9D,QAAQ;AACN,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,cAAc;AAAA,MACd;AAAA,MACA;AAAA,MACA,MAAM;AAAA,QACJ,YAAQ,6BAAW,YAAY;AAAA,QAC/B,KAAK;AAAA,QACL,WAAW;AAAA,QACX,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAEA,MAAI,CAAC,mBAAmB,SAAS,GAAG;AAClC,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,cAAc;AAAA,MACd;AAAA,MACA;AAAA,MACA,MAAM;AAAA,QACJ,YAAQ,6BAAW,YAAY;AAAA,QAC/B,KAAK;AAAA,QACL,WAAW;AAAA,QACX,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAAS;AACf,QAAM,iBAAa,6BAAW,YAAY;AAC1C,MAAI,WAAkC;AAEtC,MAAI,YAAY;AACd,QAAI;AACF,iBAAW,oBAAoB,KAAK,UAAM,+BAAa,cAAc,OAAO,CAAC,CAAC;AAAA,IAChF,QAAQ;AACN,iBAAW;AAAA,IACb;AAAA,EACF;AAEA,QAAM,OAAO;AAAA,IACX,QAAQ;AAAA,IACR,KAAK,UAAU,OAAO;AAAA,IACtB,WAAW,UAAU,aAAa;AAAA,IAClC,QAAQ,WAAW,eAAe,SAAS,GAAG,IAAI;AAAA,EACpD;AAEA,MAAI,OAAO,UAAU,aAAa;AAChC,UAAM,UACJ,CAAC,KAAK,UACN,KAAK,QAAQ,QACb,KAAK,cAAc,QACnB,KAAK,WAAW,SAChB,sBAAsB,OAAO,OAAO,KAAK,SAAS;AAEpD,QAAI,SAAS;AACX,aAAO;AAAA,QACL;AAAA,QACA,WAAW;AAAA,QACX,cAAc,mBAAmB,QAAQ,IAAI;AAAA,QAC7C;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA,WAAW;AAAA,IACX,cAAc;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;AD3MA,SAAS,cAAc,QAAkC;AACvD,UAAQ,OAAO,OAAO;AAAA,IACpB,KAAK;AACH,aAAO,8CAAW,OAAO,KAAK;AAAA,IAChC,KAAK;AACH,aAAO,oDAAY,OAAO,KAAK,gBAAM,OAAO,gBAAgB;AAAA,IAC9D,KAAK;AACH,aAAO,8CAAW,OAAO,KAAK,SAAI,OAAO,uBAAuB,uBAAQ,OAAO,oBAAoB,KAAK,EAAE,8CAAW,OAAO,gBAAgB;AAAA,IAC9I,KAAK;AACH,aAAO,0DAAa,OAAO,KAAK;AAAA,IAClC;AACE,aAAO,6BAAS,OAAO,KAAK;AAAA,EAChC;AACF;AAEO,SAAS,qBAAqB,KAAiB,KAAuB;AAC3E,MACG,QAAQ,eAAe,EACvB,YAAY,oMAA8C,EAC1D,OAAO,YAAY;AAClB,UAAM,YAAY,WAAW,EAAE;AAC/B,UAAM,SAAS,WAAW;AAE1B,QAAI,CAAC,WAAW;AACd;AAAA,QACE;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,QAAI,CAAC,QAAQ;AACX;AAAA,QACE;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,QAAI,CAAC,IAAI,UAAU;AACjB;AAAA,QACE;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,UAAM,aAAa,mBAAmB,IAAI,QAAQ;AAClD,UAAM,SAAS,WAAW;AAE1B,QAAI,CAAC,QAAQ;AACX;AAAA,QACE,WAAW,aAAa;AAAA,QACxB,WAAW,gBACT;AAAA,MACJ;AAAA,IACF;AAEA,QAAI,WAAW,WAAW;AACxB,gBAAU,WAAW,WAAW,WAAW,gBAAgB,cAAc,MAAM,CAAC;AAAA,IAClF;AAEA,UAAMC,MAAK,OAAO,UAAU;AAC5B,WAAO;AAAA,MACL,IAAAA;AAAA,MACA;AAAA,MACA,YAAY;AAAA,QACV,OAAO,OAAO;AAAA,QACd,OAAO,OAAO;AAAA,QACd,kBAAkB,OAAO;AAAA,QACzB,sBAAsB,OAAO;AAAA,MAC/B;AAAA,MACA,SAAS;AAAA,QACP,cAAc,WAAW,KAAK;AAAA,QAC9B,oBAAoB,WAAW,KAAK;AAAA,QACpC,iBAAiB,WAAW,KAAK;AAAA,MACnC;AAAA,MACA,SAAS,cAAc,MAAM;AAAA,IAC/B,CAAC;AAED,QAAI,CAACA,IAAI,SAAQ,KAAK,CAAC;AAAA,EACzB,CAAC;AACL;;;AE9EO,SAAS,uBAAuB,KAAiB,KAAuB;AAC7E,MACG,QAAQ,cAAc,EACtB,YAAY,kDAAU,EACtB,OAAO,MAAM;AACZ,UAAM,MAAM,wBAAwB,GAAG;AACvC,QAAI,CAAC,IAAK,WAAU,uBAAuB,wDAAW;AACtD,WAAO,EAAE,IAAI,MAAM,MAAM,IAAI,CAAC;AAAA,EAChC,CAAC;AACL;;;ACjBA,IAAAC,mBAAsD;AACtD,IAAAC,qBAAqB;AAYrB,SAAS,eAAe,KAAgC;AACtD,MAAI,IAAI,UAAU;AAChB,UAAM,UAAM;AAAA,MACV,IAAI;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,YAAI,6BAAW,GAAG,EAAG,QAAO;AAAA,EAC9B;AACA,SAAO;AACT;AAGA,SAAS,gBAAgB,KAAuB;AAC9C,QAAM,UAAU;AAChB,QAAM,OAAiB,CAAC;AACxB,aAAW,aAAS,8BAAY,KAAK,EAAE,eAAe,KAAK,CAAC,GAAG;AAC7D,QAAI,CAAC,MAAM,OAAO,EAAG;AACrB,UAAM,IAAI,QAAQ,KAAK,MAAM,IAAI;AACjC,QAAI,EAAG,MAAK,KAAK,EAAE,CAAC,CAAC;AAAA,EACvB;AACA,SAAO,KAAK,KAAK,EAAE,QAAQ;AAC7B;AAGA,SAAS,gBACP,KACA,SACA,SACA,OACA,WACM;AACN,QAAM,eAAW,yBAAK,KAAK,GAAG,OAAO,MAAM;AAC3C,MAAI,KAAC,6BAAW,QAAQ,EAAG;AAE3B,QAAM,cAAU,+BAAa,UAAU,OAAO;AAC9C,QAAM,eAAe,SAAS,YAAY;AAE1C,aAAW,QAAQ,QAAQ,MAAM,IAAI,GAAG;AACtC,QAAI,UAAU,UAAU,MAAO;AAC/B,QAAI,CAAC,KAAM;AACX,QAAI,gBAAgB,CAAC,KAAK,YAAY,EAAE,SAAS,YAAY,EAAG;AAChE,cAAU,KAAK,IAAI,OAAO,KAAK,IAAI,EAAE;AAAA,EACvC;AACF;AAEO,SAAS,kBAAkB,KAAiB,KAAuB;AACxE,MACG,QAAQ,KAAK,EACb,YAAY,mDAAW,EACvB,OAAO,oBAAoB,kDAAU,EACrC,OAAO,iBAAiB,uCAAmB,QAAQ,CAAC,CAAC,EACrD,OAAO,eAAe,uCAAmB,MAAM,CAAC,EAChD,OAAO,eAAe,wCAAU,IAAI,EACpC;AAAA,IACC,CAAC,SAKK;AACJ,YAAM,MAAM,eAAe,GAAG;AAC9B,UAAI,CAAC,IAAK,WAAU,oBAAoB,4CAAS;AAEjD,YAAM,OAAO,gBAAgB,gBAAgB,GAAG,GAAG,KAAK,MAAM,KAAK,EAAE;AACrE,YAAM,QAAQ,SAAS,KAAK,OAAO,EAAE,KAAK;AAC1C,YAAM,UAAoB,CAAC;AAE3B,iBAAW,WAAW,MAAM;AAC1B,YAAI,QAAQ,UAAU,MAAO;AAC7B,wBAAgB,KAAK,SAAS,KAAK,SAAS,OAAO,OAAO;AAAA,MAC5D;AAEA,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,SAAS,KAAK,WAAW;AAAA,QACzB,OAAO,QAAQ;AAAA,QACf,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AAAA,EACF;AACJ;;;AC/FA,gCAA0B;AAC1B;AAOA;AAKA,IAAM,6BAA6B;AAEnC,IAAM,cAAc;AAAA,EAClB,OAAO;AAAA,EAEP;AAAA,EACA,OAAO;AAAA,EAEP;AAAA,EACA,QAAQ;AAAA,EAER;AACF;AAqCO,SAAS,oBAAoB,OAAmB,CAAC,GAAmB;AACzE,QAAM,eAAe,KAAK,uBAAuB,KAAK,qBAAqB;AAC3E,QAAM,MAAM,gBAAgB;AAC5B,QAAM,OAAO,WAAW,GAAG;AAE3B,SAAO;AAAA,IACL,IAAI;AAAA,IACJ;AAAA,IACA,QAAQ,eAAe,SAAS;AAAA,IAChC,aAAa,KAAK;AAAA,IAClB,gBAAgB,KAAK;AAAA,IACrB,eAAe,iBAAiB;AAAA,EAClC;AACF;AAEO,SAAS,mCACd,OAAmB,CAAC,GACH;AACjB,QAAM,kBACJ,KAAK,2BACJ,MAAM,uBAAuB,WAAW;AAC3C,QAAM,YAAY,gBAAgB;AAClC,MAAI,UAAU,WAAW;AACvB,WAAO;AAAA,MACL,WAAW;AAAA,MACX,IAAI;AAAA,MACJ,QAAQ;AAAA,MACR,SAAS;AAAA,IACX;AAAA,EACF;AAEA,QAAM,WAAW,KAAK,iBAAiB,KAAK,eAAe;AAC3D,MAAI,aAAa,SAAS;AACxB,WAAO;AAAA,MACL,WAAW;AAAA,MACX,IAAI;AAAA,MACJ,QAAQ;AAAA,MACR,SAAS;AAAA,IACX;AAAA,EACF;AAEA,QAAM,UAAU,KAAK,SAAS,KAAK,KAAK,QAAQ,IAAI,UAAU,KAAK,KAAK;AACxE,QAAM,UAAU,GAAG,OAAO;AAC1B,QAAM,MAAM,KAAK,aAAa;AAC9B,QAAM,SAAS,IAAI,SAAS,CAAC,WAAW,SAAS,GAAG;AAAA,IAClD,UAAU;AAAA,IACV,OAAO;AAAA,IACP,SAAS;AAAA,EACX,CAAC;AAED,MAAI,CAAC,OAAO,SAAS,OAAO,WAAW,GAAG;AACxC,WAAO;AAAA,MACL,WAAW;AAAA,MACX,IAAI;AAAA,MACJ,QAAQ;AAAA,MACR;AAAA,MACA,SAAS,kCAAS,OAAO;AAAA,IAC3B;AAAA,EACF;AAEA,QAAM,SACJ,OAAO,OAAO,WAAW,WAAW,OAAO,OAAO,KAAK,IAAI;AAC7D,QAAM,eAAe,OAAO,OAAO,SAAS,KAAK;AACjD,SAAO;AAAA,IACL,WAAW;AAAA,IACX,IAAI;AAAA,IACJ,QAAQ;AAAA,IACR;AAAA,IACA,SAAS,6HAAyB,OAAO;AAAA,IACzC,QACE,UACA,iBACC,OAAO,OAAO,WAAW,WACtB,eAAe,OAAO,MAAM,KAC5B;AAAA,EACR;AACF;AAEO,SAAS,sBACd,SACA,OAAmB,CAAC,GACF;AAClB,cAAY,OAAO;AACnB,QAAM,OAAO,WAAW,OAAO;AAC/B,QAAM,SAAS,mCAAmC,IAAI;AAEtD,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,SAAS,OAAO,KACZ,4BAAQ,OAAO,4DACf,4BAAQ,OAAO;AAAA,IACnB,KAAK;AAAA,IACL,aAAa,KAAK;AAAA,IAClB,gBAAgB,KAAK;AAAA,IACrB;AAAA,EACF;AACF;AAEO,SAAS,eAAe,KAAiB,OAAmB,CAAC,GAAS;AAC3E,QAAM,MAAM,IAAI,QAAQ,KAAK,EAAE,YAAY,oEAA4B;AAEvE,MACG,QAAQ,MAAM,EACd,YAAY,sFAAgB,EAC5B,OAAO,MAAM;AACZ,WAAO,oBAAoB,IAAI,CAAC;AAAA,EAClC,CAAC;AAEH,MACG,QAAQ,cAAc,EACtB,YAAY,uDAAyB,EACrC,OAAO,CAAC,YAAoB;AAC3B,UAAM,YAAY,iBAAiB;AACnC,QAAI,CAAC,UAAU,SAAS,OAAc,GAAG;AACvC;AAAA,QACE;AAAA,QACA,+CAAY,OAAO,6BAAS,UAAU,KAAK,IAAI,CAAC;AAAA,MAClD;AAAA,IACF;AACA,WAAO,sBAAsB,SAAoB,IAAI,CAAC;AAAA,EACxD,CAAC;AACL;;;ACvLA,IAAAC,mBAAyC;AACzC,2BAAgC;AAChC;;;ACFA,IAAAC,mBAA0D;AAG1D,SAASC,UAAS,GAA6B;AAC7C,SAAO,CAAC,CAAC,KAAK,OAAO,MAAM,YAAY,CAAC,MAAM,QAAQ,CAAC;AACzD;AAEO,IAAM,sBAA+B,CAAC,EAAE,KAAK,WAAW,MAAM;AACnE,QAAM,UAAU,IAAI;AACpB,MAAI,CAACA,UAAS,OAAO,EAAG,QAAO;AAE/B,QAAM,YAAY,QAAQ;AAC1B,MAAI,CAACA,UAAS,SAAS,EAAG,QAAO;AAEjC,MAAI,UAAU,iCAAiC,KAAM,QAAO;AAE5D,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,KAAK,MAAM;AACT,YAAM,UAAM,+BAAa,YAAY,OAAO;AAC5C,YAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,YAAM,KAAK,OAAO;AAClB,YAAM,MAAM,GAAG;AACf,UAAI,+BAA+B;AACnC,yCAAa,YAAY,aAAa,MAAM;AAC5C,0CAAc,YAAY,KAAK,UAAU,QAAQ,MAAM,CAAC,IAAI,MAAM,OAAO;AAAA,IAC3E;AAAA,EACF;AACF;;;AC9BA,SAASC,UAAS,GAA6B;AAC7C,SAAO,CAAC,CAAC,KAAK,OAAO,MAAM,YAAY,CAAC,MAAM,QAAQ,CAAC;AACzD;AAEO,IAAM,oBAA6B,CAAC,EAAE,IAAI,MAAM;AACrD,QAAM,UAAU,IAAI;AACpB,MAAI,CAACA,UAAS,OAAO,EAAG,QAAO;AAE/B,QAAM,OAAO,QAAQ;AACrB,MAAI,CAACA,UAAS,IAAI,EAAG,QAAO;AAE5B,MAAI,KAAK,SAAS,gBAAiB,QAAO;AAE1C,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,OAAO;AAAA,IACP,QACE;AAAA,IAGF,gBAAgB;AAAA,IAChB,KAAK;AAAA,EACP;AACF;AAEO,IAAM,8BAAuC,CAAC,EAAE,IAAI,MAAM;AAC/D,QAAM,UAAU,IAAI;AACpB,MAAI,CAACA,UAAS,OAAO,EAAG,QAAO;AAE/B,QAAM,OAAO,QAAQ;AACrB,MAAI,CAACA,UAAS,IAAI,EAAG,QAAO;AAE5B,MAAI,KAAK,SAAS,gBAAiB,QAAO;AAE1C,QAAM,KAAK,KAAK;AAChB,MAAI,CAACA,UAAS,EAAE,EAAG,QAAO,UAAU;AAEpC,QAAM,aAAa,GAAG;AACtB,MAAI,CAAC,MAAM,QAAQ,UAAU,KAAK,WAAW,WAAW,EAAG,QAAO,UAAU;AAE5E,SAAO;AACT;AAEA,SAAS,YAAY;AACnB,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,gBACE;AAAA,IACF,KAAK;AAAA,EACP;AACF;;;ACxDA,IAAAC,mBAAoC;AAG7B,IAAM,qBAA8B,CAAC,EAAE,SAAS,MAAM;AAC3D,MAAI;AACJ,MAAI;AACF,eAAO,2BAAS,QAAQ,EAAE;AAAA,EAC5B,QAAQ;AACN,WAAO;AAAA,EACT;AAGA,QAAM,YAAY,OAAO;AACzB,MAAI,cAAc,EAAG,QAAO;AAE5B,QAAM,UAAU,OAAO,OAAO,KAAO,SAAS,CAAC;AAE/C,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,OAAO,iEAAe,QAAQ,SAAS,OAAO;AAAA,IAC9C,QAAQ;AAAA,IACR,gBAAgB,eAAe;AAAA,IAC/B,KAAK,MAAM;AACT,sCAAU,UAAU,GAAK;AAAA,IAC3B;AAAA,EACF;AACF;;;ACzBA,SAASC,UAAS,GAA6B;AAC7C,SAAO,CAAC,CAAC,KAAK,OAAO,MAAM,YAAY,CAAC,MAAM,QAAQ,CAAC;AACzD;AAEO,IAAM,kBAA2B,CAAC,EAAE,IAAI,MAAM;AACnD,QAAM,SAAS,IAAI;AACnB,MAAI,CAACA,UAAS,MAAM,EAAG,QAAO;AAE9B,QAAM,OAAO,OAAO;AACpB,MAAI,CAAC,MAAM,QAAQ,IAAI,EAAG,QAAO;AAEjC,QAAM,mBAA6B,CAAC;AAEpC,aAAW,SAAS,MAAM;AACxB,QAAI,CAACA,UAAS,KAAK,EAAG;AACtB,UAAM,KAAK,OAAO,MAAM,MAAM,SAAS;AAGvC,UAAM,QAAQ,MAAM;AACpB,QAAI,CAACA,UAAS,KAAK,GAAG;AACpB,uBAAiB,KAAK,EAAE;AACxB;AAAA,IACF;AAEA,UAAM,UAAU,MAAM;AACtB,QAAI,CAAC,WAAW,YAAY,WAAW;AACrC,uBAAiB,KAAK,EAAE;AAAA,IAC1B;AAAA,EACF;AAEA,MAAI,iBAAiB,WAAW,EAAG,QAAO;AAE1C,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,OAAO;AAAA,IACP,QAAQ,+DAA4B,iBAAiB,KAAK,IAAI,CAAC;AAAA,IAC/D,gBACE;AAAA,IACF,KAAK;AAAA,EACP;AACF;;;AC3CA;AAGO,IAAM,mBAA4B,MAAM;AAC7C,QAAM,SAAS,WAAW;AAC1B,MAAI,OAAQ,QAAO;AAEnB,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,OAAO;AAAA,IACP,QACE;AAAA,IACF,gBACE;AAAA,IACF,KAAK;AAAA,EACP;AACF;;;ACdO,IAAM,cAAuB,CAAC,EAAE,SAAS,MAAM;AACpD,QAAM,aAAa,mBAAmB,QAAQ;AAC9C,QAAM,SAAS,WAAW;AAE1B,MAAI,WAAW,cAAc,oBAAoB;AAC/C,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,UAAU;AAAA,MACV,OAAO;AAAA,MACP,QAAQ,WAAW,gBAAgB;AAAA,MACnC,gBAAgB;AAAA,MAChB,KAAK;AAAA,IACP;AAAA,EACF;AAEA,MAAI,WAAW,cAAc,kBAAkB;AAC7C,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,UAAU;AAAA,MACV,OAAO;AAAA,MACP,QAAQ,WAAW,gBAAgB;AAAA,MACnC,gBAAgB;AAAA,MAChB,KAAK;AAAA,IACP;AAAA,EACF;AAEA,MAAI,WAAW,cAAc,gBAAgB;AAC3C,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,UAAU;AAAA,MACV,OAAO;AAAA,MACP,QAAQ,WAAW,gBAAgB;AAAA,MACnC,gBAAgB;AAAA,MAChB,KAAK;AAAA,IACP;AAAA,EACF;AAEA,MAAI,CAAC,UAAU,OAAO,UAAU,YAAa,QAAO;AAEpD,QAAM,eAAe,OAAO,uBACxB,uBAAQ,OAAO,oBAAoB,KACnC;AAEJ,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,OAAO,yCAAgB,OAAO,KAAK;AAAA,IACnC,QAAQ,sBAAO,OAAO,KAAK,iBAAO,OAAO,KAAK,gBAAM,YAAY,mCAAU,OAAO,gBAAgB;AAAA,IACjG,gBAAgB;AAAA,IAChB,KAAK;AAAA,EACP;AACF;;;ACpDA,IAAM,YAAY;AAClB,IAAM,YAAY;AAEX,IAAM,mBAA4B,MAAM;AAC7C,QAAM,UAAU,QAAQ,SAAS;AACjC,QAAM,CAAC,OAAO,KAAK,IAAI,QAAQ,MAAM,GAAG,EAAE,IAAI,MAAM;AAEpD,MAAI,QAAQ,aAAc,UAAU,aAAa,SAAS,WAAY;AACpE,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,OAAO,sCAAkB,OAAO;AAAA,IAChC,QAAQ,mBAAS,SAAS,IAAI,SAAS,+BAAW,OAAO;AAAA,IACzD,gBAAgB,qCAAiB,SAAS,IAAI,SAAS;AAAA,IACvD,KAAK;AAAA,EACP;AACF;;;ACrBA;AAKO,IAAM,qBAA8B,YAAY;AACrD,QAAM,UAAU,qBAAqB;AAAA,IACnC,SAAS,YAAY;AAAA,EACvB,CAAC;AAED,MAAI;AACJ,MAAI;AACF,UAAM,MAAM,MAAM;AAAA,MAChB,4DAA4D,OAAO;AAAA,MACnE,EAAE,QAAQ,YAAY,QAAQ,GAAI,EAAE;AAAA,IACtC;AACA,QAAI,CAAC,IAAI,GAAI,QAAO;AACpB,UAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,aAAS,KAAK,WAAW;AAAA,EAC3B,QAAQ;AAEN,WAAO;AAAA,EACT;AAEA,MAAI,CAAC,UAAU,WAAW,eAAgB,QAAO;AAEjD,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,OAAO,4DAAe,cAAc,wBAAS,MAAM;AAAA,IACnD,QAAQ;AAAA,IACR,gBAAgB,gFAAiE,MAAM;AAAA,IACvF,KAAK;AAAA,EACP;AACF;;;ACvBO,IAAM,cAAyB;AAAA;AAAA,EAEpC;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AACF;;;AThBA,SAASC,UAAS,GAA6B;AAC7C,SAAO,CAAC,CAAC,KAAK,OAAO,MAAM,YAAY,CAAC,MAAM,QAAQ,CAAC;AACzD;AAEA,SAAS,WAAW,YAAgC;AAClD,MAAI,KAAC,6BAAW,UAAU,EAAG,QAAO,CAAC;AACrC,MAAI;AACF,UAAM,SAAS,KAAK,UAAM,+BAAa,YAAY,OAAO,CAAC;AAC3D,WAAOA,UAAS,MAAM,IAAI,SAAS,CAAC;AAAA,EACtC,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEA,SAAS,aAAa,GAAqB;AACzC,UAAQ,GAAG;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,EACX;AACF;AAEA,SAAS,cAAc,GAAqB;AAC1C,UAAQ,GAAG;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,EACX;AACF;AAEA,SAAS,QAAQ,UAAoC;AACnD,QAAM,SAAK,sCAAgB,EAAE,OAAO,QAAQ,OAAO,QAAQ,QAAQ,OAAO,CAAC;AAC3E,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,OAAG,SAAS,UAAU,CAAC,WAAW;AAChC,SAAG,MAAM;AACT,cAAQ,OAAO,KAAK,EAAE,YAAY,MAAM,GAAG;AAAA,IAC7C,CAAC;AAAA,EACH,CAAC;AACH;AAEA,eAAe,UAAU,KAAiB,MAAe,KAA8B;AACrF,QAAM,WAAW,IAAI,YAAY,gBAAgB;AACjD,QAAM,aAAa,kBAAkB,QAAQ;AAC7C,QAAM,MAAM,WAAW,UAAU;AAEjC,QAAM,WAAW,EAAE,KAAK,YAAY,SAAS;AAG7C,QAAM,SAAwB,CAAC;AAC/B,aAAW,WAAW,aAAa;AACjC,UAAM,SAAS,MAAM,QAAQ,QAAQ;AACrC,QAAI,OAAQ,QAAO,KAAK,MAAM;AAAA,EAChC;AAGA,SAAO,KAAK,CAAC,GAAG,MAAM,cAAc,EAAE,QAAQ,IAAI,cAAc,EAAE,QAAQ,CAAC;AAG3E,QAAM,UAAU,EAAE,UAAU,GAAG,MAAM,GAAG,MAAM,EAAE;AAChD,aAAW,SAAS,QAAQ;AAC1B,YAAQ,MAAM,QAAQ;AAAA,EACxB;AAGA,MAAI,MAAM;AACR,WAAO;AAAA,MACL,IAAI,OAAO,WAAW;AAAA,MACtB;AAAA,MACA,QAAQ,OAAO,IAAI,CAAC,OAAO;AAAA,QACzB,IAAI,EAAE;AAAA,QACN,UAAU,EAAE;AAAA,QACZ,OAAO,EAAE;AAAA,QACT,QAAQ,EAAE;AAAA,QACV,aAAa,EAAE,QAAQ;AAAA,QACvB,gBAAgB,EAAE;AAAA,MACpB,EAAE;AAAA,IACJ,CAAC;AACD,QAAI,OAAO,SAAS,EAAG,SAAQ,KAAK,CAAC;AACrC;AAAA,EACF;AAGA,QAAM,MAAM,QAAQ;AACpB,MAAI,qEAAgC;AAEpC,MAAI,OAAO,WAAW,GAAG;AACvB,QAAI,wGAAkC;AACtC,WAAO,EAAE,IAAI,MAAM,QAAQ,CAAC;AAC5B;AAAA,EACF;AAEA,aAAW,SAAS,QAAQ;AAC1B,QAAI,GAAG,aAAa,MAAM,QAAQ,CAAC,IAAI,MAAM,KAAK,EAAE;AACpD,QAAI,YAAO,MAAM,MAAM,EAAE;AACzB,QAAI,0BAAW,MAAM,cAAc,EAAE;AACrC,QAAI;AAAA,EACN;AAEA;AAAA,IACE,qCAAiB,QAAQ,QAAQ,iCACpB,QAAQ,IAAI,6BACZ,QAAQ,IAAI;AAAA;AAAA,EAC3B;AAGA,QAAM,UAAU,OAAO,OAAO,CAAC,MAAM,EAAE,QAAQ,IAAI;AAEnD,MAAI,QAAQ,WAAW,GAAG;AACxB,QAAI,sHAAuB;AAC3B,WAAO,EAAE,IAAI,OAAO,QAAQ,CAAC;AAC7B,YAAQ,KAAK,CAAC;AACd;AAAA,EACF;AAEA,MAAI,gBAAM,QAAQ,MAAM,0DAAa;AACrC,aAAW,SAAS,SAAS;AAC3B,QAAI,YAAO,MAAM,KAAK,WAAM,MAAM,cAAc,EAAE;AAAA,EACpD;AACA,MAAI;AAEJ,QAAM,MAAM,QAAQ,QAAQ,MAAM,QAAQ,+DAAkB;AAC5D,MAAI,CAAC,KAAK;AACR,QAAI,8BAAU;AACd,WAAO,EAAE,IAAI,OAAO,SAAS,OAAO,EAAE,CAAC;AACvC,YAAQ,KAAK,CAAC;AACd;AAAA,EACF;AAEA,MAAI;AACJ,MAAI,QAAQ;AACZ,aAAW,SAAS,SAAS;AAC3B,QAAI;AACF,YAAM,MAAM,IAAK;AACjB,UAAI,yBAAoB,MAAM,KAAK,WAAM,MAAM,cAAc,EAAE;AAC/D;AAAA,IACF,SAASC,MAAU;AACjB;AAAA,QACE,yBAAoB,MAAM,KAAK,8BAAUA,MAAK,WAAW,OAAOA,IAAG,CAAC;AAAA,MACtE;AAAA,IACF;AAAA,EACF;AAEA,QAAM,cAAc,OAAO,SAAS,QAAQ;AAC5C,MAAI,cAAc,GAAG;AACnB,QAAI;AAAA,6BAAY,WAAW,+GAAqB;AAAA,EAClD;AAEA,MAAI;AAAA,4BAAW,KAAK,IAAI,QAAQ,MAAM;AAAA,CAAoC;AAC1E,SAAO,EAAE,IAAI,UAAU,QAAQ,UAAU,gBAAgB,GAAG,SAAS,MAAM,CAAC;AAC5E,MAAI,QAAQ,QAAQ,UAAU,cAAc,EAAG,SAAQ,KAAK,CAAC;AAC/D;AAEO,SAAS,eAAe,KAAiB,KAAuB;AACrE,MACG,QAAQ,QAAQ,EAChB,YAAY,8GAAoB,EAChC,OAAO,UAAU,4FAAsB,EACvC,OAAO,SAAS,8GAAoB,EACpC,OAAO,CAAC,SAA4C;AACnD,WAAO,UAAU,KAAK,KAAK,SAAS,MAAM,KAAK,GAAG;AAAA,EACpD,CAAC;AACL;;;AUtKO,SAAS,gBAAgB,KAAiB,KAAuB;AACtE,MACG,QAAQ,MAAM,EACd,YAAY,sFAAgB,EAC5B,OAAO,qBAAqB,kFAAgC,EAC5D,OAAO,CAAC,SAA8B;AACrC,UAAM,MAAM,qBAAqB,GAAG;AACpC,QAAI,CAAC,IAAK,WAAU,uBAAuB,wDAAW;AAEtD,QAAI,aAAa,mBAAmB,GAAG;AAEvC,QAAI,KAAK,QAAQ;AACf,mBAAa,WAAW,OAAO,CAAC,MAAM,EAAE,WAAW,KAAK,MAAM;AAAA,IAChE;AAEA,UAAM,QAAQ,WAAW,IAAI,CAAC,OAAO;AAAA,MACnC,IAAI,EAAE;AAAA,MACN,MAAM,EAAE,SAAS;AAAA,MACjB,cAAc,EAAE,SAAS;AAAA,MACzB,QAAQ,EAAE;AAAA,MACV,iBAAiB,EAAE,SAAS;AAAA,MAC5B,WAAW,CAAC,CAAC,EAAE;AAAA,MACf,gBAAgB,CAAC,CAAC,EAAE;AAAA,MACpB,YAAY,EAAE,SAAS;AAAA,MACvB,YAAY,EAAE;AAAA,MACd,OAAO,EAAE,aAAa;AAAA,IACxB,EAAE;AAEF,WAAO,EAAE,IAAI,MAAM,OAAO,MAAM,QAAQ,YAAY,MAAM,CAAC;AAAA,EAC7D,CAAC;AACL;;;AC9BO,SAAS,kBAAkB,KAAiB,KAAuB;AACxE,MACG,QAAQ,aAAa,EACrB,YAAY,kDAAU,EACtB,OAAO,CAAC,OAAe;AACtB,UAAM,MAAM,qBAAqB,GAAG;AACpC,QAAI,CAAC,IAAK,WAAU,uBAAuB,wDAAW;AAEtD,UAAM,aAAa,mBAAmB,GAAG;AACzC,UAAM,QAAQ,WAAW,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE;AAEhD,QAAI,CAAC,OAAO;AACV,gBAAU,aAAa,mCAAU,EAAE,EAAE;AAAA,IACvC;AAEA,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,WAAW;AAAA,QACT,IAAI,MAAM;AAAA,QACV,MAAM,MAAM,SAAS;AAAA,QACrB,cAAc,MAAM,SAAS;AAAA,QAC7B,iBAAiB,MAAM,SAAS;AAAA,QAChC,QAAQ,MAAM;AAAA,QACd,YAAY,MAAM,SAAS;AAAA,QAC3B,UAAU,MAAM,SAAS,YAAY;AAAA,QACrC,SAAS,MAAM,SAAS,WAAW,CAAC;AAAA,QACpC,WAAW,MAAM,aAAa;AAAA,QAC9B,SAAS,MAAM,WAAW;AAAA,QAC1B,oBAAoB,MAAM,sBAAsB;AAAA,QAChD,gBAAgB,MAAM,kBAAkB;AAAA,QACxC,aAAa,MAAM,eAAe;AAAA,QAClC,OAAO,MAAM,SAAS;AAAA,QACtB,OAAO,MAAM,aAAa;AAAA,QAC1B,YAAY,MAAM;AAAA,QAClB,WAAW,MAAM;AAAA,MACnB;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AACL;;;ACvCO,SAAS,uBACd,KACA,KACM;AACN,MACG,QAAQ,cAAc,EACtB,YAAY,kDAAU,EACtB,OAAO,MAAM;AACZ,UAAM,MAAM,qBAAqB,GAAG;AACpC,QAAI,CAAC,IAAK,WAAU,uBAAuB,wDAAW;AACtD,WAAO,EAAE,IAAI,MAAM,MAAM,IAAI,CAAC;AAAA,EAChC,CAAC;AACL;;;ACpBA,IAAAC,wBAAgC;AAChC,IAAAC,mBAAwD;AASxD,SAAS,IAAI,IAAQ,UAAmC;AACtD,SAAO,IAAI,QAAQ,CAAC,YAAY,GAAG,SAAS,UAAU,OAAO,CAAC;AAChE;AAMA,eAAe,UACb,IACA,QACA,SACA,aAAa,GACI;AACjB,UAAQ,QAAQ,CAAC,GAAG,MAAM;AACxB,UAAM,SAAS,MAAM,aAAa,WAAM;AACxC,YAAQ,OAAO,MAAM,KAAK,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC;AAAA,CAAI;AAAA,EACrD,CAAC;AACD,SAAO,MAAM;AACX,UAAM,OAAO,MAAM,IAAI,IAAI,GAAG,MAAM,OAAO,QAAQ,MAAM,sBAAO,aAAa,CAAC,KAAK,GAAG,KAAK;AAC3F,QAAI,CAAC,IAAK,QAAO;AACjB,UAAM,IAAI,SAAS,KAAK,EAAE;AAC1B,QAAI,CAAC,MAAM,CAAC,KAAK,KAAK,KAAK,KAAK,QAAQ,OAAQ,QAAO,IAAI;AAC3D,YAAQ,OAAO,MAAM,0BAAW,QAAQ,MAAM;AAAA,CAAU;AAAA,EAC1D;AACF;AAGA,eAAe,YAAY,IAAQ,QAA6C;AAC9E,QAAM,OAAO,MAAM,IAAI,IAAI,GAAG,MAAM,6DAAgB,GAAG,KAAK;AAC5D,SAAO,OAAO;AAChB;AAIA,eAAe,SAAS,IAA4B;AAClD,UAAQ,OAAO,MAAM,iGAAqC;AAC1D,UAAQ,OAAO,MAAM,kNAAiE;AAEtF,QAAM,WAAW,MAAM,YAAY,IAAI,6DAAoC;AAC3E,QAAM,WAAW,MAAM,YAAY,IAAI,oDAAiB;AACxD,QAAM,2BAA2B,MAAM,YAAY,IAAI,qEAAmB;AAC1E,QAAM,aAAa,0BAA0B,KAAK,EAAE,YAAY;AAChE,QAAM,sBACJ,eAAe,OAAO,eAAe,SAAS,eAAe;AAE/D,SAAO;AAAA,IACL,MAAM;AAAA,IACN,KAAK;AAAA,MACH,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;AAAA,MAC/B,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;AAAA,MAC/B,GAAI,2BAA2B,EAAE,oBAAoB,IAAI,CAAC;AAAA,IAC5D;AAAA,EACF;AACF;AAEA,eAAe,WAAW,IAA4B;AACpD,UAAQ,OAAO,MAAM,2FAA+B;AAEpD,UAAQ,OAAO,MAAM,kCAAS;AAC9B,QAAM,eAAe;AAAA,IACnB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,QAAM,WAAW,MAAM,UAAU,IAAI,4BAAQ,YAAY;AACzD,QAAM,QACJ,aAAa,IAAI,SAAa,aAAa,QAAQ;AAErD,QAAM,WAAW,MAAM,YAAY,IAAI,8FAAwB;AAE/D,UAAQ,OAAO,MAAM,oCAAW;AAChC,QAAM,iBAAiB;AAAA,IACrB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,QAAM,aAAa,MAAM,UAAU,IAAI,4BAAQ,cAAc;AAC7D,QAAM,UACJ,eAAe,IAAI,SAAa,CAAC,UAAU,QAAQ,KAAK,EAAY,aAAa,CAAC;AAEpF,UAAQ,OAAO,MAAM,0CAAY;AACjC,QAAM,gBAAgB;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,QAAM,YAAY,MAAM,UAAU,IAAI,kCAAS,aAAa;AAC5D,QAAM,cAAmC,CAAC,QAAQ,eAAe,UAAU,EAAY,SAAS;AAEhG,QAAM,iBAAiB,MAAM,YAAY,IAAI,kGAAkB;AAE/D,SAAO;AAAA,IACL,MAAM;AAAA,IACN,OAAO;AAAA,MACL,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;AAAA,MACzB,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;AAAA,MAC/B,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;AAAA,MAC7B;AAAA,MACA,GAAI,iBAAiB,EAAE,eAAe,IAAI,CAAC;AAAA,IAC7C;AAAA,EACF;AACF;AAIO,SAAS,iBAAiB,KAAiB,KAAuB;AACvE,MACG,QAAQ,OAAO,EACf,YAAY,yHAA0B,EACtC,OAAO,YAAY;AAClB,UAAM,aAAa,qBAAqB,GAAG;AAG3C,YAAI,6BAAW,UAAU,GAAG;AAC1B,UAAI;AACF,cAAM,WAAW,KAAK,UAAM,+BAAa,YAAY,OAAO,CAAC;AAC7D,gBAAQ,OAAO,MAAM,oDAAiB,SAAS,IAAI,EAAE;AACrD,YAAI,SAAS,UAAW,SAAQ,OAAO,MAAM,4BAAQ,SAAS,SAAS,EAAE;AACzE,gBAAQ,OAAO,MAAM,IAAI;AAAA,MAC3B,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,UAAM,SAAK,uCAAgB,EAAE,OAAO,QAAQ,OAAO,QAAQ,QAAQ,QAAQ,UAAU,KAAK,CAAC;AAE3F,QAAI;AACF,cAAQ,OAAO,MAAM,oCAAW;AAChC,YAAM,UAAU,MAAM,UAAU,IAAI,4BAAQ,CAAC,8DAA2B,uCAAmB,CAAC;AAE5F,YAAM,SAAoB,YAAY,IAAI,MAAM,SAAS,EAAE,IAAI,MAAM,WAAW,EAAE;AAClF,YAAM,SAAS,EAAE,GAAG,QAAQ,YAAW,oBAAI,KAAK,GAAE,YAAY,EAAE;AAEhE,0CAAc,YAAY,KAAK,UAAU,QAAQ,MAAM,CAAC,GAAG,OAAO;AAClE,cAAQ,OAAO,MAAM;AAAA,8CAAc,UAAU;AAAA;AAAA,CAAM;AAEnD,aAAO,EAAE,IAAI,MAAM,GAAG,OAAO,CAAC;AAAA,IAChC,UAAE;AACA,SAAG,MAAM;AAAA,IACX;AAAA,EACF,CAAC;AACL;;;AC5JA,IAAAC,6BAA0B;AAC1B,IAAAC,mBAA0C;AAC1C,IAAAC,qBAAqB;AACrB,IAAAC,kBAAe;AACf;AAKA,IAAMC,YAAW;AAEjB,eAAe,UAAU,KAA8B;AACrD,QAAM,MAAM,MAAM,MAAM,KAAK,EAAE,QAAQ,YAAY,QAAQ,GAAM,EAAE,CAAC;AACpE,MAAI,CAAC,IAAI,IAAI;AACX,UAAM,IAAI,MAAM,6BAAS,GAAG,UAAU,IAAI,MAAM,GAAG;AAAA,EACrD;AACA,SAAO,IAAI,KAAK;AAClB;AAEA,eAAe,UACb,KACA,MACe;AACf,QAAM,OAAO,KAAK,SAAS;AAC3B,QAAM,QAAQ,KAAK,UAAU;AAC7B,QAAM,OAAO,KAAK,SAAS;AAC3B,QAAM,UAAU,OAAO,SAAS;AAChC,QAAM,MAAM,CAAC,QAAgB;AAC3B,QAAI,CAAC,KAAM,SAAQ,OAAO,MAAM,GAAG,GAAG;AAAA,CAAI;AAAA,EAC5C;AAEA,MAAI,eAAK,OAAO,UAAU,EAAE,8BAAU;AAEtC,MAAI;AACJ,MAAI;AACF,cAAU,MAAM,UAAU,GAAGA,SAAQ,IAAI,OAAO,EAAE,GAAG,KAAK;AAAA,EAC5D,SAASC,MAAU;AACjB,UAAM,MAAM,qDAAaA,MAAK,WAAW,OAAOA,IAAG,CAAC;AACpD,QAAI,MAAM;AACR,aAAO,EAAE,IAAI,OAAO,OAAO,EAAE,MAAM,gBAAgB,SAAS,IAAI,EAAE,CAAC;AACnE,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,YAAQ,OAAO,MAAM,kCAAkC,GAAG;AAAA,CAAI;AAC9D,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,UAAU;AAEhB,MAAI,CAAC,SAAS,YAAY,QAAQ;AAChC,QAAI,mCAAe,OAAO,UAAU,EAAE,iBAAO,OAAO,SAAS;AAC7D,WAAO,EAAE,IAAI,MAAM,SAAS,QAAQ,SAAS,SAAS,MAAM,CAAC;AAC7D;AAAA,EACF;AAEA,MAAI,OAAO;AACT,QAAI,sCAAkB,OAAO,YAAO,MAAM,SAAS;AAAA,EACrD,OAAO;AACL,QAAI,4CAAmB,OAAO,YAAO,MAAM,2CAAkB;AAAA,EAC/D;AAGA,MAAI,0CAAY;AAChB,MAAI;AACJ,MAAI;AACF,oBAAgB,MAAM,UAAU,GAAGD,SAAQ,mBAAmB;AAAA,EAChE,SAASC,MAAU;AACjB,UAAM,MAAM,qDAAaA,MAAK,WAAW,OAAOA,IAAG,CAAC;AACpD,QAAI,MAAM;AACR,aAAO,EAAE,IAAI,OAAO,OAAO,EAAE,MAAM,mBAAmB,SAAS,IAAI,EAAE,CAAC;AACtE,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,YAAQ,OAAO,MAAM,kCAAkC,GAAG;AAAA,CAAI;AAC9D,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,QAAM,gBAAY,yBAAK,gBAAAC,QAAG,OAAO,GAAG,oBAAoB,KAAK,IAAI,CAAC,MAAM;AACxE,MAAI;AACF,wCAAc,WAAW,eAAe,OAAO;AAAA,EACjD,SAASD,MAAU;AACjB,UAAM,MAAM,qDAAaA,MAAK,WAAW,OAAOA,IAAG,CAAC;AACpD,QAAI,MAAM;AACR,aAAO,EAAE,IAAI,OAAO,OAAO,EAAE,MAAM,gBAAgB,SAAS,IAAI,EAAE,CAAC;AACnE,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,YAAQ,OAAO,MAAM,kCAAkC,GAAG;AAAA,CAAI;AAC9D,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,WAAW,IAAI,YAAY,gBAAgB;AAGjD,QAAM,aAAS;AAAA,IACb,QAAQ;AAAA,IACR,CAAC,WAAW,aAAa,QAAQ,eAAe,QAAQ;AAAA,IACxD,EAAE,OAAO,UAAU;AAAA,EACrB;AAEA,MAAI;AACF,qCAAW,SAAS;AAAA,EACtB,QAAQ;AAAA,EAER;AAEA,MAAI,OAAO,OAAO;AAChB,UAAM,MAAM,qDAAa,OAAO,MAAM,OAAO;AAC7C,QAAI,MAAM;AACR,aAAO,EAAE,IAAI,OAAO,OAAO,EAAE,MAAM,gBAAgB,SAAS,IAAI,EAAE,CAAC;AAAA,IACrE,OAAO;AACL,cAAQ,OAAO,MAAM,kCAAkC,GAAG;AAAA,CAAI;AAAA,IAChE;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,MAAI,OAAO,WAAW,GAAG;AACvB,QAAI,MAAM;AACR,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,OAAO;AAAA,UACL,MAAM;AAAA,UACN,SAAS,+CAAY,OAAO,MAAM;AAAA,QACpC;AAAA,MACF,CAAC;AAAA,IACH;AACA,YAAQ,KAAK,OAAO,UAAU,CAAC;AAAA,EACjC;AAEA,MAAI,MAAM;AACR,WAAO,EAAE,IAAI,MAAM,SAAS,QAAQ,SAAS,SAAS,KAAK,CAAC;AAAA,EAC9D;AACF;AAEO,SAAS,eAAe,KAAiB,KAAuB;AACrE,MACG,QAAQ,QAAQ,EAChB,YAAY,0HAAsB,EAClC,OAAO,UAAU,4FAAsB,EACvC,OAAO,WAAW,0HAAsB,EACxC,OAAO,UAAU,4CAAc,EAC/B,OAAO,CAAC,SAA8D;AACrE,WAAO,UAAU,KAAK,IAAI;AAAA,EAC5B,CAAC;AACL;;;ACzHO,SAAS,eACd,SACA,KACA,kBAAkB,OACZ;AACN,QAAM,MAAM,QACT,QAAQ,eAAe,EACvB,YAAY,kDAAU,EACtB,QAAQ,gBAAgB,iBAAiB,sCAAQ;AAGpD,kBAAgB,GAAG;AAGnB,oBAAkB,KAAK,GAAG;AAC1B,qBAAmB,KAAK,GAAG;AAC3B,mBAAiB,KAAK,GAAG;AACzB,kBAAgB,KAAK,GAAG;AACxB,qBAAmB,KAAK,GAAG;AAG3B,QAAM,QAAQ,IAAI,QAAQ,OAAO,EAAE,YAAY,0BAAM;AACrD,oBAAkB,KAAK;AACvB,0BAAwB,KAAK;AAG7B,yBAAuB,KAAK,GAAG;AAG/B,oBAAkB,KAAK,GAAG;AAG1B,uBAAqB,KAAK,GAAG;AAG7B,iBAAe,GAAG;AAGlB,iBAAe,KAAK,GAAG;AAGvB,QAAM,MAAM,IAAI,QAAQ,KAAK,EAAE,YAAY,0BAAM;AACjD,kBAAgB,KAAK,GAAG;AACxB,oBAAkB,KAAK,GAAG;AAC1B,yBAAuB,KAAK,GAAG;AAC/B,mBAAiB,KAAK,GAAG;AAGzB,iBAAe,KAAK,GAAG;AACzB;;;A/BjEA,SAAS,qBAAqB,cAA2C;AACvE,MAAI,CAAC,cAAc;AACjB,WAAO;AAAA,EACT;AAEA,UAAI,6BAAS,YAAY,MAAM,aAAa;AAC1C,WAAO;AAAA,EACT;AAEA,aAAO,4BAAQ,YAAY;AAC7B;AAEO,SAAS,kBACd,KACA,QAIM;AACN,QAAM,EAAE,QAAQ,YAAY,IAAI;AAEhC,QAAM,gBAAgB,CAAC,YAAiD;AACtE,QAAI;AAAA,MACF,CAAC,QAAQ;AACP,cAAM,cAAe,IAA+B;AACpD,cAAM,oBACJ,gBACC,OAAO,gBAAgB,WAAW,cAAc,WACjD,qBAAqB,IAAI,YAAY;AACvC;AAAA,UACE,IAAI;AAAA,UACJ;AAAA,YACE,UAAU;AAAA,YACV,cAAc,IAAI;AAAA,UACpB;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAAA,MACA,EAAE,UAAU,CAAC,OAAO,EAAE;AAAA,IACxB;AAAA,EACF;AAEA,gBAAc,KAAK;AACnB,gBAAc,qBAAqB;AACnC,SAAO,KAAK,8DAAqC;AACnD;;;AgCjDA;AASA,IAAM,yBAAyB;AAAA,EAC7B,MAAM;AAAA,EACN,UAAU,CAAC,YAAY,QAAQ;AAAA,EAC/B,sBAAsB;AAAA,EACtB,YAAY;AAAA,IACV,UAAU;AAAA,MACR,MAAM;AAAA,MACN,aAAa;AAAA,MACb,UAAU;AAAA,MACV,UAAU;AAAA,MACV,OAAO;AAAA,QACL,MAAM;AAAA,QACN,UAAU,CAAC,QAAQ,YAAY;AAAA,QAC/B,sBAAsB;AAAA,QACtB,YAAY;AAAA,UACV,MAAM;AAAA,YACJ,MAAM;AAAA,YACN,MAAM,CAAC,QAAQ,UAAU,UAAU,UAAU,cAAc,aAAa;AAAA,YACxE,aACE;AAAA,UAMJ;AAAA,UACA,YAAY;AAAA,YACV,MAAM;AAAA,YACN,SAAS;AAAA,YACT,aACE;AAAA,UACJ;AAAA,UACA,YAAY;AAAA,YACV,MAAM;AAAA,YACN,SAAS;AAAA,YACT,SAAS;AAAA,YACT,aACE;AAAA,UACJ;AAAA,UACA,OAAO;AAAA,YACL,MAAM;AAAA,YACN,UAAU,CAAC,KAAK,KAAK,GAAG;AAAA,YACxB,sBAAsB;AAAA,YACtB,YAAY;AAAA,cACV,GAAG,EAAE,MAAM,UAAU,SAAS,GAAG,SAAS,IAAI;AAAA,cAC9C,GAAG,EAAE,MAAM,UAAU,SAAS,GAAG,SAAS,IAAI;AAAA,cAC9C,GAAG,EAAE,MAAM,UAAU,SAAS,GAAG,SAAS,IAAI;AAAA,YAChD;AAAA,YACA,aACE;AAAA,UACJ;AAAA,UACA,aAAa;AAAA,YACX,MAAM;AAAA,YACN,SAAS;AAAA,YACT,aACE;AAAA,UACJ;AAAA,UACA,WAAW;AAAA,YACT,MAAM;AAAA,YACN,MAAM,CAAC,OAAO,KAAK;AAAA,YACnB,aAAa;AAAA,UACf;AAAA,UACA,QAAQ;AAAA,YACN,MAAM;AAAA,YACN,MAAM,CAAC,GAAG,GAAG,CAAC;AAAA,YACd,aACE;AAAA,UACJ;AAAA,UACA,eAAe;AAAA,YACb,MAAM;AAAA,YACN,sBAAsB;AAAA,YACtB,YAAY;AAAA,cACV,SAAS;AAAA,gBACP,MAAM;AAAA,gBACN,SAAS;AAAA,gBACT,aACE;AAAA,cACJ;AAAA,cACA,SAAS;AAAA,gBACP,MAAM;AAAA,gBACN,SAAS;AAAA,gBACT,aAAa;AAAA,cACf;AAAA,cACA,SAAS;AAAA,gBACP,MAAM;AAAA,gBACN,SAAS;AAAA,gBACT,aACE;AAAA,cACJ;AAAA,cACA,QAAQ;AAAA,gBACN,MAAM;AAAA,gBACN,SAAS;AAAA,gBACT,aAAa;AAAA,cACf;AAAA,YACF;AAAA,YACA,aACE;AAAA,UACJ;AAAA,UACA,YAAY;AAAA,YACV,MAAM;AAAA,YACN,UAAU,CAAC,KAAK,KAAK,KAAK,YAAY;AAAA,YACtC,sBAAsB;AAAA,YACtB,YAAY;AAAA,cACV,GAAG,EAAE,MAAM,UAAU,SAAS,GAAG,SAAS,IAAI;AAAA,cAC9C,GAAG,EAAE,MAAM,UAAU,SAAS,GAAG,SAAS,IAAI;AAAA,cAC9C,GAAG,EAAE,MAAM,UAAU,SAAS,GAAG,SAAS,IAAI;AAAA,cAC9C,YAAY;AAAA,gBACV,MAAM;AAAA,gBACN,SAAS;AAAA,gBACT,SAAS;AAAA,gBACT,aAAa;AAAA,cACf;AAAA,YACF;AAAA,YACA,aACE;AAAA,UACJ;AAAA,UACA,QAAQ;AAAA,YACN,MAAM;AAAA,YACN,UAAU;AAAA,YACV,UAAU;AAAA,YACV,OAAO;AAAA,cACL,MAAM;AAAA,cACN,UAAU,CAAC,SAAS,SAAS,YAAY;AAAA,cACzC,sBAAsB;AAAA,cACtB,YAAY;AAAA,gBACV,OAAO;AAAA,kBACL,MAAM;AAAA,kBACN,SAAS;AAAA,kBACT,SAAS;AAAA,kBACT,aAAa;AAAA,gBACf;AAAA,gBACA,OAAO;AAAA,kBACL,MAAM;AAAA,kBACN,UAAU,CAAC,KAAK,KAAK,GAAG;AAAA,kBACxB,sBAAsB;AAAA,kBACtB,YAAY;AAAA,oBACV,GAAG,EAAE,MAAM,UAAU,SAAS,GAAG,SAAS,IAAI;AAAA,oBAC9C,GAAG,EAAE,MAAM,UAAU,SAAS,GAAG,SAAS,IAAI;AAAA,oBAC9C,GAAG,EAAE,MAAM,UAAU,SAAS,GAAG,SAAS,IAAI;AAAA,kBAChD;AAAA,kBACA,aAAa;AAAA,gBACf;AAAA,gBACA,YAAY;AAAA,kBACV,MAAM;AAAA,kBACN,SAAS;AAAA,kBACT,SAAS;AAAA,kBACT,aAAa;AAAA,gBACf;AAAA,cACF;AAAA,YACF;AAAA,YACA,aACE;AAAA,UACJ;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IACA,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,aACE;AAAA,IAEJ;AAAA,IACA,OAAO;AAAA,MACL,MAAM;AAAA,MACN,aACE;AAAA,IACJ;AAAA,IACA,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,aACE;AAAA,IACJ;AAAA,IACA,cAAc;AAAA,MACZ,MAAM;AAAA,MACN,SAAS;AAAA,MACT,aACE;AAAA,IACJ;AAAA,EACF;AACF;AAEO,SAAS,yBACd,KACA,QACM;AACN,MAAI,aAAa;AAAA,IACf,MAAM;AAAA,IACN,OAAO;AAAA,IACP,aACE,6rCAG0C,sBAAsB,MAAM,WAAM,sBAAsB,MAAM;AAAA,IAC1G,YAAY;AAAA,IACZ,MAAM,QAAQ,aAAqB,QAAiB;AAClD,UAAI;AACJ,UAAI;AACF,iBAAS,cAAc;AAAA,MACzB,SAAS,GAAQ;AACf,eAAO;AAAA,UACL,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,EAAE,QAAQ,CAAC;AAAA,UACpD,SAAS,EAAE,IAAI,OAAO,OAAO,EAAE,MAAM,iBAAiB,SAAS,EAAE,QAAQ,EAAE;AAAA,QAC7E;AAAA,MACF;AAEA,YAAM,EAAE,UAAU,OAAO,QAAQ,QAAQ,aAAa,IAAI;AAC1D,YAAM,aAAa,iBAAiB,QAAQ;AAC5C,UAAI,CAAC,WAAW,OAAO;AACrB,eAAO;AAAA,UACL,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,KAAK,UAAU,WAAW,MAAM,EAAE,CAAC;AAAA,UAC5E,SAAS;AAAA,YACP,IAAI;AAAA,YACJ,OAAO,EAAE,MAAM,qBAAqB,SAAS,WAAW,OAAO;AAAA,UACjE;AAAA,QACF;AAAA,MACF;AAEA,UAAI;AACJ,UAAI;AACF,sBAAc,qBAAqB,EAAE,QAAQ,aAAa,CAAC;AAC3D,8BAAsB,WAAW;AAAA,MACnC,SAAS,OAAY;AACnB,eAAO;AAAA,UACL,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,OAAO,WAAW,OAAO,KAAK,EAAE,CAAC;AAAA,UAC1E,SAAS;AAAA,YACP,IAAI;AAAA,YACJ,OAAO,EAAE,MAAM,qBAAqB,SAAS,OAAO,WAAW,OAAO,KAAK,EAAE;AAAA,UAC/E;AAAA,QACF;AAAA,MACF;AAEA,aAAO,KAAK,wBAAwB,SAAS,EAAE,aAAa,MAAM,EAAE;AACpE,iBAAW,WAAW,WAAW,UAAU;AACzC,eAAO;AAAA,UACL,qCAAqC,QAAQ,IAAI,KAAK,QAAQ,KAAK,KAAK,QAAQ,OAAO;AAAA,QACzF;AAAA,MACF;AACA,YAAM,SAAS,MAAM;AAAA,QACnB;AAAA,QACA,WAAW;AAAA,QACX;AAAA,QACA,EAAE,cAAc,YAAY;AAAA,QAC5B;AAAA,QACA;AAAA,MACF;AAEA,UAAI,CAAC,OAAO,IAAI;AACd,eAAO;AAAA,UACL,sCAAsC,OAAO,MAAM,IAAI,OAAO,KAAK;AAAA,QACrE;AAAA,MACF,OAAO;AACL,eAAO,KAAK,mCAAmC,OAAO,WAAW,EAAE;AAAA,MACrE;AAEA,YAAM,UACJ,WAAW,SAAS,SAAS,IAAI,EAAE,GAAG,QAAQ,UAAU,WAAW,SAAS,IAAI;AAClF,aAAO;AAAA,QACL,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,KAAK,UAAU,OAAO,EAAE,CAAC;AAAA,QAClE;AAAA,MACF;AAAA,IACF;AAAA,EACF,CAAQ;AACV;;;AChRA,IAAAE,mBAA6B;AAE7B;;;ACFA,IAAAC,mBAAmE;AACnE,IAAAC,qBAAqB;AACrB;AACA;AAEA,IAAM,mBAAmB;AACzB,IAAM,aAAa;AAGnB,IAAM,2BAA2B,WAAW,EAAE;AAC9C,IAAM,oBACiD,GAA6B,KAAK,IACnF,GAA6B,KAAK,IAClC,WAAc;AAEpB,IAAM,6BAA6B;AAOnC,SAAS,kBAAkB,GAAyC;AAClE,MAAI,MAAM,QAAQ,OAAO,MAAM,SAAU,QAAO;AAChD,aAAW,OAAO,OAAO,OAAO,CAAC,EAAG,KAAI,OAAO,QAAQ,SAAU,QAAO;AACxE,SAAO;AACT;AAqBA,SAAS,wBAAwB,GAAwC;AACvE,MAAI,MAAM,QAAQ,OAAO,MAAM,SAAU,QAAO;AAChD,QAAM,IAAI;AACV,SAAO,MAAM,QAAQ,EAAE,IAAI,KAAK,EAAE,KAAK;AAAA,IACrC,CAAC,SACC,SAAS,QACT,OAAO,SAAS,YAChB,OAAQ,KAAwB,gBAAgB,YAChD,OAAQ,KAAwB,YAAY;AAAA,EAChD;AACF;AAEA,SAAS,aAAa,UAA0B;AAC9C,aAAO,yBAAK,UAAU,WAAW,kBAAkB,UAAU;AAC/D;AASO,SAAS,yBAAyB,MAGlB;AACrB,QAAM,EAAE,UAAU,OAAO,IAAI;AAC7B,QAAM,MAAM;AACZ,QAAM,eAAe;AAErB,QAAM,MAAM,oBAAI,IAAoB;AACpC,MAAI,eAAsD;AAC1D,MAAI,eAAoC;AACxC,MAAI,gBAAsC;AAE1C,WAAS,eAAqB;AAC5B,UAAMC,QAAO,aAAa,QAAQ;AAClC,QAAI,KAAC,6BAAWA,KAAI,EAAG;AACvB,QAAI;AACF,YAAM,MAAM,KAAK,UAAM,+BAAaA,OAAM,OAAO,CAAC;AAClD,UAAI,CAAC,kBAAkB,GAAG,EAAG;AAC7B,UAAI,MAAM;AACV,iBAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,GAAG,EAAG,KAAI,IAAI,GAAG,CAAC;AACtD,aAAO,KAAK,yBAAyB,IAAI,IAAI,wBAAwBA,KAAI,EAAE;AAAA,IAC7E,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,iBAAe,kBAAiC;AAC9C,UAAM,SAAS,WAAW;AAC1B,QAAI,CAAC,KAAK;AACR,aAAO,KAAK,wDAAwD;AACpE;AAAA,IACF;AACA,QAAI,CAAC,QAAQ;AACX,aAAO,KAAK,8CAA8C;AAC1D;AAAA,IACF;AAEA,UAAM,YAAY,OAAO,WAAW,SAAS,IACzC,OAAO,MAAM,UAAU,MAAM,IAC7B;AACJ,QAAI;AACF,YAAM,MAAM,MAAM,MAAM,KAAK;AAAA,QAC3B,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,oBAAoB,gBAAgB,UAAU;AAAA,QACzE,MAAM,KAAK,UAAU;AAAA,UACnB,UAAU;AAAA,QACZ,CAAC;AAAA,MACH,CAAC;AACD,UAAI,CAAC,IAAI,IAAI;AACX,eAAO,KAAK,uCAAuC,IAAI,MAAM,IAAI,IAAI,UAAU,EAAE;AACjF;AAAA,MACF;AACA,YAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,UAAI,CAAC,wBAAwB,IAAI,KAAK,CAAC,KAAK,WAAW,CAAC,KAAK,MAAM,QAAQ;AACzE,eAAO,KAAK,wEAAwE;AACpF;AAAA,MACF;AACA,UAAI,MAAM;AACV,iBAAW,QAAQ,KAAK,MAAM;AAC5B,YAAI,KAAK,eAAe,KAAK,QAAS,KAAI,IAAI,KAAK,aAAa,KAAK,OAAO;AAAA,MAC9E;AACA,UAAI,IAAI,SAAS,GAAG;AAClB,eAAO,KAAK,oDAAoD;AAChE;AAAA,MACF;AACA,YAAM,UAAM,yBAAK,UAAU,WAAW,gBAAgB;AAEtD,sCAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAClC,YAAM,YAAY,aAAa,QAAQ;AACvC,0CAAc,WAAW,KAAK,UAAU,OAAO,YAAY,GAAG,GAAG,MAAM,CAAC,GAAG,OAAO;AAClF,aAAO,KAAK,4BAA4B,IAAI,IAAI,mCAAmC,SAAS,EAAE;AAAA,IAChG,SAAS,GAAG;AACV,YAAM,UAAU,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AACzD,aAAO,KAAK,iCAAiC,OAAO,EAAE;AAAA,IACxD;AAAA,EACF;AAEA,iBAAe,iBAAgC;AAC7C,QAAI,cAAe,QAAO;AAC1B,oBAAgB,gBAAgB,EAAE,QAAQ,MAAM;AAC9C,sBAAgB;AAAA,IAClB,CAAC;AACD,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL,MAAM,mBAAmB,aAAsC;AAE7D,UAAI,IAAI,IAAI,WAAW,EAAG,QAAO,IAAI,IAAI,WAAW;AACpD,aAAO;AAAA,IAKT;AAAA,IAEA,MAAM,QAAuB;AAC3B,mBAAa;AACb,YAAM,gBAAgB;AAEtB,UAAI,CAAC,IAAK;AAEV,UAAI,eAAe,GAAG;AACpB,cAAM,KAAK,eAAe,KAAK,KAAK;AACpC,uBAAe,YAAY,MAAM,gBAAgB,EAAE,MAAM,MAAM;AAAA,QAAE,CAAC,GAAG,EAAE;AAAA,MACzE;AACA,qBAAe,iBAAiB,MAAM,gBAAgB,EAAE,MAAM,MAAM;AAAA,MAAE,CAAC,CAAC;AAAA,IAC1E;AAAA,IAEA,OAAa;AACX,qBAAe;AACf,qBAAe;AACf,UAAI,cAAc;AAChB,sBAAc,YAAY;AAC1B,uBAAe;AAAA,MACjB;AACA,UAAI,MAAM;AAAA,IACZ;AAAA,EACF;AACF;;;AC9LA,IAAAC,mBAUO;AACP,IAAAC,sBAA2B;AAC3B,IAAAC,qBAAqB;;;ACGrB,SAAS,sBAAsB,OAAoC;AACjE,MAAI,OAAO,UAAU,UAAU;AAC7B,WAAO;AAAA,EACT;AACA,QAAM,UAAU,MAAM,KAAK;AAC3B,SAAO,UAAU,UAAU;AAC7B;AAEA,SAAS,YAAY,SAA0B;AAC7C,QAAM,aAAa,QAAQ,KAAK,EAAE,YAAY;AAC9C,MAAI,CAAC,YAAY;AACf,WAAO;AAAA,EACT;AACA,SACE,eAAe,kBACZ,eAAe,YACf,eAAe,UACf,eAAe,yBACf,eAAe,2BACf,eAAe,yBACf,WAAW,SAAS,QAAQ,KAC5B,WAAW,SAAS,MAAM,KAC1B,WAAW,SAAS,cAAI;AAE/B;AAEA,SAAS,iBAAiB,MAAuB;AAC/C,QAAM,IAAI,KAAK,KAAK,EAAE,YAAY;AAClC,SAAO,MAAM,kBAAQ,MAAM,UAAU,MAAM;AAC7C;AAEA,SAAS,mBAAmB,MAAkC;AAC5D,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,aAAa,CAAC,KAAK,QAAQ,GAAG,GAAG,KAAK,QAAQ,QAAG,CAAC,EAAE,OAAO,CAAC,MAAM,IAAI,CAAC;AAC7E,MAAI,WAAW,WAAW,EAAG,QAAO;AACpC,QAAM,MAAM,KAAK,IAAI,GAAG,UAAU;AAClC,QAAM,aAAa,KAAK,MAAM,GAAG,GAAG,EAAE,KAAK;AAC3C,SAAO,cAAc;AACvB;AAEA,SAAS,sBACP,OACA,WACA,QAAQ,GAC4B;AACpC,MAAI,CAAC,SAAS,OAAO,UAAU,YAAY,QAAQ,GAAG;AACpD,WAAO,EAAE,OAAO,MAAM;AAAA,EACxB;AAEA,MAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,eAAW,QAAQ,OAAO;AACxB,YAAM,QAAQ,sBAAsB,MAAM,WAAW,QAAQ,CAAC;AAC9D,UAAI,MAAM,OAAO;AACf,eAAO;AAAA,MACT;AAAA,IACF;AACA,WAAO,EAAE,OAAO,MAAM;AAAA,EACxB;AAEA,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAgC,GAAG;AAC3E,QAAI,IAAI,KAAK,EAAE,YAAY,MAAM,WAAW;AAC1C,aAAO,EAAE,OAAO,MAAM,OAAO,sBAAsB,KAAK,EAAE;AAAA,IAC5D;AAAA,EACF;AAEA,aAAW,SAAS,OAAO,OAAO,KAAgC,GAAG;AACnE,UAAM,QAAQ,sBAAsB,OAAO,WAAW,QAAQ,CAAC;AAC/D,QAAI,MAAM,OAAO;AACf,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO,EAAE,OAAO,MAAM;AACxB;AAEA,SAAS,iBAAiB,GAA4C;AACpE,QAAM,WAAW,sBAAsB,EAAE,UAAU,UAAU;AAG7D,MAAI,SAAS,OAAO;AAClB,UAAM,aAAa,sBAAsB,EAAE,KAAK;AAChD,UAAM,aAAqC;AAAA,MACzC,kBAAkB,SAAS,QAAQ,UAAU;AAAA,IAC/C;AACA,QAAI,YAAY;AACd,iBAAW,aAAa;AAAA,IAC1B;AACA,QAAI,SAAS,OAAO;AAClB,iBAAW,mBAAmB,SAAS;AAAA,IACzC;AACA,WAAO;AAAA,EACT;AAGA,QAAM,WAAW,OAAO,EAAE,UAAU,WAAW,EAAE,QAAQ;AACzD,MAAI,iBAAiB,QAAQ,GAAG;AAC9B,UAAM,aAAa,mBAAmB,EAAE,QAAQ,EAAE;AAClD,QAAI,YAAY;AACd,aAAO;AAAA,QACL;AAAA,QACA,kBAAkB;AAAA,MACpB;AAAA,IACF;AAAA,EACF;AAEA,SAAO,CAAC;AACV;AAEA,SAAS,WAAW,GAAoB,YAA4C;AAClF,MAAI,WAAW,qBAAqB,WAAW,WAAW,kBAAkB;AAC1E,WAAO,WAAW;AAAA,EACpB;AAEA,MAAI,WAAW,qBAAqB,aAAa,WAAW,YAAY;AACtE,WAAO,WAAW;AAAA,EACpB;AACA,SAAO,OAAO,EAAE,UAAU,WAAW,EAAE,QAAQ;AACjD;AAEA,SAAS,aAAa,GAAoB,YAA4C;AACpF,QAAM,OAAO,EAAE,MAAM,KAAK;AAE1B,MAAI,WAAW,qBAAqB,WAAW,WAAW,cAAc,MAAM;AAC5E,UAAM,OAAO,GAAG,WAAW,UAAU;AACrC,UAAM,OAAO,GAAG,WAAW,UAAU;AACrC,WAAO,KAAK,WAAW,IAAI,KAAK,KAAK,WAAW,IAAI,IAChD,OACA,GAAG,WAAW,UAAU,KAAK,IAAI;AAAA,EACvC;AAEA,MAAI,WAAW,qBAAqB,aAAa,WAAW,cAAc,MAAM;AAC9E,UAAM,OAAO,GAAG,WAAW,UAAU;AACrC,UAAM,OAAO,GAAG,WAAW,UAAU;AACrC,QAAI,KAAK,WAAW,IAAI,EAAG,QAAO,KAAK,MAAM,KAAK,MAAM,EAAE,UAAU;AACpE,QAAI,KAAK,WAAW,IAAI,EAAG,QAAO,KAAK,MAAM,KAAK,MAAM,EAAE,UAAU;AACpE,WAAO;AAAA,EACT;AAEA,SAAO,QAAQ;AACjB;AAEO,SAAS,sBACd,GAC0C;AAC1C,QAAM,UAAU,OAAO,EAAE,QAAQ,WAAW,EAAE,MAAM;AACpD,MAAI,CAAC,YAAY,OAAO,GAAG;AACzB,WAAO;AAAA,EACT;AAEA,QAAM,aAAa,iBAAiB,CAAC;AAGrC,MACE,WAAW,eAAe,UACvB,WAAW,qBAAqB,UAChC,WAAW,qBAAqB,QACnC;AACA,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL,OAAO,WAAW,GAAG,UAAU;AAAA,IAC/B,SAAS,aAAa,GAAG,UAAU;AAAA,IACnC;AAAA,EACF;AACF;;;ADnIA,IAAM,wBAAwB;AAC9B,IAAM,oBAAoB;AAC1B,IAAM,6BAA6B;AAsB5B,SAAS,gCAAgC,UAA0B;AACxE,aAAO,yBAAK,UAAU,WAAW,uBAAuB,qBAAqB;AAC/E;AAEA,SAAS,aAAa,WAA8C;AAClE,MAAI,CAAC,UAAW,QAAO;AACvB,QAAM,IAAI,IAAI,KAAK,SAAS,EAAE,QAAQ;AACtC,MAAI,OAAO,MAAM,CAAC,EAAG,QAAO;AAC5B,SAAO,KAAK,IAAI,IAAI;AACtB;AAEA,SAAS,qBAAqB,GAA4B;AACxD,QAAM,OAAO,EAAE,MAAM,KAAK;AAC1B,MAAI,MAAM;AACR,WAAO;AAAA,EACT;AAEA,QAAM,WAAqB,CAAC;AAC5B,MAAI,EAAE,UAAU;AACd,aAAS,KAAK,YAAY,EAAE,QAAQ,EAAE;AAAA,EACxC;AACA,MAAI,EAAE,YAAY,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,GAAG;AACpD,aAAS,KAAK,YAAY,KAAK,UAAU,EAAE,QAAQ,CAAC,EAAE;AAAA,EACxD;AACA,SAAO,SAAS,KAAK,KAAK,KAAK;AACjC;AAEA,SAAS,wBAAwB,KAAsB;AACrD,MAAI;AACF,oCAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAClC,qCAAW,KAAK,2BAAU,OAAO,2BAAU,IAAI;AAC/C,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,8BACd,KACA,QACQ;AAER,QAAM,gBAAgB,gCAAgC,IAAI,QAAQ;AAElE,MAAI,wBAAwB,aAAa,GAAG;AAC1C,WAAO,KAAK,yDAAsB,aAAa,EAAE;AACjD,WAAO;AAAA,EACT;AAGA,MAAI,IAAI,cAAc;AACpB,UAAM,mBAAe,yBAAK,IAAI,cAAc,qBAAqB;AACjE,QAAI,wBAAwB,YAAY,GAAG;AACzC,aAAO;AAAA,QACL,iGAAqC,YAAY;AAAA,MACnD;AACA,aAAO;AAAA,IACT;AAAA,EACF;AAEA,QAAM,IAAI,MAAM,2DAAc,aAAa,EAAE;AAC/C;AAKO,IAAM,sBAAN,MAA0B;AAAA,EAS/B,YACE,KACQ,QACA,QACR,oBACA;AAHQ;AACA;AAGR,SAAK,MAAM;AACX,SAAK,iBAAa,yBAAK,KAAK,iBAAiB;AAC7C,SAAK,yBAAqB,yBAAK,KAAK,0BAA0B;AAC9D,SAAK,qBAAqB;AAAA,EAC5B;AAAA,EAlBQ;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU,oBAAI,IAAyB;AAAA,EACvC,kBAAkB,oBAAI,IAAyB;AAAA,EAC/C,kBAAkB,oBAAI,IAA2B;AAAA,EACjD;AAAA,EAcR,MAAM,OAAO;AACX,oCAAU,KAAK,KAAK,EAAE,WAAW,KAAK,CAAC;AACvC,oCAAU,KAAK,YAAY,EAAE,WAAW,KAAK,CAAC;AAC9C,iCAAO,KAAK,oBAAoB,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAChE,oCAAU,KAAK,oBAAoB,EAAE,WAAW,KAAK,CAAC;AAAA,EACxD;AAAA,EAEA,MAAM,OACJ,OACA,UACmC;AACnC,UAAM,SAAmC;AAAA,MACvC,UAAU,MAAM;AAAA,MAChB,UAAU;AAAA,MACV,aAAa;AAAA,MACb,kBAAkB;AAAA,MAClB,SAAS;AAAA,MACT,UAAU,CAAC;AAAA,IACb;AAEA,UAAM,WAAW,WAAW,IAAI,QAAQ,MAAM;AAC9C,eAAW,KAAK,OAAO;AACrB,YAAM,UAAU,MAAM,KAAK,kBAAkB,CAAC;AAC9C,YAAM,QAAQ,aAAa,EAAE,SAAS;AACtC,YAAM,UAAU,UAAU,OAAO,UAAU,OAAO,KAAK;AACvD,WAAK,OAAO;AAAA,QACV,SAAS,QAAQ,SAAS,EAAE,OAAO,SAAS,OAAO,EAAE,MAAM,GAAG,OAAO,EAAE,SAAS,IAAI,OAAO,YAAY,QAAQ,IAAI;AAAA,MACrH;AACA,cAAQ,QAAQ,MAAM;AAAA,QACpB,KAAK;AACH,iBAAO,YAAY;AACnB,iBAAO,SAAS,KAAK,QAAQ,KAAK;AAClC;AAAA,QACF,KAAK;AACH,iBAAO,eAAe;AACtB;AAAA,QACF,KAAK;AACH,iBAAO,oBAAoB;AAC3B;AAAA,QACF,KAAK;AACH,iBAAO,WAAW;AAClB;AAAA,MACJ;AAAA,IACF;AACA,SAAK,MAAM;AACX,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,kBAAkB,GAA2C;AACzE,UAAM,KAAK,IAAI,KAAK,EAAE,SAAS;AAC/B,QAAI,OAAO,MAAM,GAAG,QAAQ,CAAC,GAAG;AAC9B,WAAK,OAAO,KAAK,0DAAuB,EAAE,EAAE,EAAE;AAC9C,aAAO,EAAE,MAAM,UAAU;AAAA,IAC3B;AAEA,UAAM,UAAU,KAAK,WAAW,EAAE;AAClC,UAAM,eAAW,yBAAK,KAAK,KAAK,GAAG,OAAO,OAAO;AACjD,UAAM,eAAe,OAAO,EAAE,OAAO,WAAW,EAAE,GAAG,KAAK,IAAI;AAC9D,UAAM,QAAQ,KAAK,wBAAwB,CAAC;AAE5C,WAAO,KAAK,kBAAkB,SAAS,YAAY;AACjD,UAAI,gBAAgB,KAAK,kBAAkB,SAAS,YAAY,GAAG;AACjE,eAAO,EAAE,MAAM,cAAc;AAAA,MAC/B;AAEA,UAAI,KAAK,0BAA0B,SAAS,UAAU,KAAK,GAAG;AAC5D,eAAO,EAAE,MAAM,mBAAmB;AAAA,MACpC;AAEA,YAAM,iBAAiB,KAAK,qBACxB,MAAM,KAAK,mBAAmB,MAAM,OAAO,IAC3C,MAAM;AAEV,YAAM,cAAkC;AAAA,QACtC,GAAG;AAAA,QACH;AAAA,MACF;AAEA,YAAM,MAAM,KAAK,wBAAwB,QAAQ;AACjD,UAAI,KAAK,WAAW;AACpB,0CAAc,UAAU,KAAK,UAAU,KAAK,MAAM,CAAC,GAAG,OAAO;AAE7D,UAAI,cAAc;AAChB,aAAK,qBAAqB,SAAS,YAAY;AAAA,MACjD;AACA,WAAK,6BAA6B,SAAS,UAAU,WAAW;AAChE,aAAO,EAAE,MAAM,YAAY,OAAO,YAAY;AAAA,IAChD,CAAC;AAAA,EACH;AAAA,EAEQ,wBAAwB,GAAwC;AACtE,UAAM,UAAU,OAAO,EAAE,QAAQ,YAAY,EAAE,MAAM,EAAE,MAAM;AAC7D,UAAM,SAAS,sBAAsB,CAAC;AACtC,QAAI,QAAQ;AACV,aAAO;AAAA,QACL;AAAA,QACA,OAAO,OAAO;AAAA,QACd,SAAS,OAAO,WAAW,qBAAqB,CAAC;AAAA,QACjD,WAAW,EAAE;AAAA,QACb,GAAG,OAAO;AAAA,MACZ;AAAA,IACF;AACA,WAAO;AAAA,MACL;AAAA,MACA,OAAO,OAAO,EAAE,UAAU,WAAW,EAAE,QAAQ;AAAA,MAC/C,SAAS,qBAAqB,CAAC;AAAA,MAC/B,WAAW,EAAE;AAAA,IACf;AAAA,EACF;AAAA,EAEQ,WAAW,GAAiB;AAClC,UAAM,OAAO,EAAE,YAAY;AAC3B,UAAM,QAAQ,OAAO,EAAE,SAAS,IAAI,CAAC,EAAE,SAAS,GAAG,GAAG;AACtD,UAAM,MAAM,OAAO,EAAE,QAAQ,CAAC,EAAE,SAAS,GAAG,GAAG;AAC/C,WAAO,GAAG,IAAI,IAAI,KAAK,IAAI,GAAG;AAAA,EAChC;AAAA,EAEQ,eAAe,SAAyB;AAC9C,eAAO,yBAAK,KAAK,YAAY,GAAG,OAAO,MAAM;AAAA,EAC/C;AAAA,EAEQ,SAAS,SAA8B;AAC7C,UAAM,SAAS,KAAK,QAAQ,IAAI,OAAO;AACvC,QAAI,QAAQ;AACV,aAAO;AAAA,IACT;AAEA,UAAM,SAAS,KAAK,eAAe,OAAO;AAC1C,UAAM,MAAM,oBAAI,IAAY;AAC5B,YAAI,6BAAW,MAAM,GAAG;AACtB,YAAM,YAAQ,+BAAa,QAAQ,OAAO,EAAE,MAAM,OAAO;AACzD,iBAAW,QAAQ,OAAO;AACxB,cAAM,KAAK,KAAK,KAAK;AACrB,YAAI,IAAI;AACN,cAAI,IAAI,EAAE;AAAA,QACZ;AAAA,MACF;AAAA,IACF;AAEA,SAAK,QAAQ,IAAI,SAAS,GAAG;AAC7B,WAAO;AAAA,EACT;AAAA,EAEQ,kBAAkB,SAAiB,IAAqB;AAC9D,WAAO,KAAK,SAAS,OAAO,EAAE,IAAI,EAAE;AAAA,EACtC;AAAA,EAEQ,uBAAuB,SAAyB;AACtD,eAAO,yBAAK,KAAK,oBAAoB,GAAG,OAAO,OAAO;AAAA,EACxD;AAAA,EAEQ,iBAAiB,SAAiB,UAA+B;AACvE,UAAM,SAAS,KAAK,gBAAgB,IAAI,OAAO;AAC/C,QAAI,QAAQ;AACV,aAAO;AAAA,IACT;AAEA,UAAM,UAAU,KAAK,uBAAuB,OAAO;AACnD,UAAM,OAAO,oBAAI,IAAY;AAE7B,YAAI,6BAAW,QAAQ,GAAG;AACxB,iBAAW,QAAQ,KAAK,wBAAwB,QAAQ,GAAG;AACzD,aAAK,IAAI,KAAK,4BAA4B,IAAI,CAAC;AAAA,MACjD;AAAA,IACF;AAEA,QAAI,KAAK,OAAO,GAAG;AACjB,0CAAc,SAAS,GAAG,MAAM,KAAK,IAAI,EAAE,KAAK,IAAI,CAAC;AAAA,GAAM,OAAO;AAAA,IACpE,eAAW,6BAAW,OAAO,GAAG;AAC9B,mCAAO,SAAS,EAAE,OAAO,KAAK,CAAC;AAAA,IACjC;AAEA,SAAK,gBAAgB,IAAI,SAAS,IAAI;AACtC,WAAO;AAAA,EACT;AAAA,EAEQ,0BACN,SACA,UACA,OACS;AACT,WAAO,KAAK,iBAAiB,SAAS,QAAQ,EAAE;AAAA,MAC9C,KAAK,4BAA4B,KAAK;AAAA,IACxC;AAAA,EACF;AAAA,EAEQ,qBAAqB,SAAiB,IAAY;AACxD,UAAM,MAAM,KAAK,SAAS,OAAO;AACjC,QAAI,IAAI,IAAI,EAAE,GAAG;AACf;AAAA,IACF;AAEA,yCAAe,KAAK,eAAe,OAAO,GAAG,GAAG,EAAE;AAAA,GAAM,OAAO;AAC/D,QAAI,IAAI,EAAE;AAAA,EACZ;AAAA,EAEQ,6BACN,SACA,UACA,OACA;AACA,UAAM,OAAO,KAAK,iBAAiB,SAAS,QAAQ;AACpD,UAAM,MAAM,KAAK,4BAA4B,KAAK;AAElD,QAAI,KAAK,IAAI,GAAG,GAAG;AACjB;AAAA,IACF;AAEA,yCAAe,KAAK,uBAAuB,OAAO,GAAG,GAAG,GAAG;AAAA,GAAM,OAAO;AACxE,SAAK,IAAI,GAAG;AAAA,EACd;AAAA,EAEQ,4BACN,OACQ;AACR,eAAO,gCAAW,QAAQ,EACvB,OAAO,MAAM,OAAO,EACpB,OAAO,GAAM,EACb,OAAO,MAAM,KAAK,EAClB,OAAO,GAAM,EACb,OAAO,MAAM,OAAO,EACpB,OAAO,GAAM,EACb,OAAO,MAAM,SAAS,EACtB,OAAO,KAAK;AAAA,EACjB;AAAA,EAEQ,wBAAwB,UAAwC;AACtE,QAAI,KAAC,6BAAW,QAAQ,GAAG;AACzB,aAAO,CAAC;AAAA,IACV;AAEA,QAAI;AACF,YAAM,SAAS,KAAK,UAAM,+BAAa,UAAU,OAAO,CAAC;AACzD,aAAO,MAAM,QAAQ,MAAM,IAAI,SAAS,CAAC;AAAA,IAC3C,QAAQ;AACN,aAAO,CAAC;AAAA,IACV;AAAA,EACF;AAAA,EAEA,MAAc,kBACZ,SACA,MACY;AACZ,UAAM,WAAW,KAAK,gBAAgB,IAAI,OAAO,KAAK,QAAQ,QAAQ;AACtE,QAAI;AACJ,UAAM,UAAU,IAAI,QAAc,CAAC,YAAY;AAC7C,gBAAU;AAAA,IACZ,CAAC;AACD,UAAM,QAAQ,SAAS,KAAK,MAAM,OAAO;AACzC,SAAK,gBAAgB,IAAI,SAAS,KAAK;AAEvC,UAAM;AACN,QAAI;AACF,aAAO,MAAM,KAAK;AAAA,IACpB,UAAE;AACA,cAAQ;AACR,UAAI,KAAK,gBAAgB,IAAI,OAAO,MAAM,OAAO;AAC/C,aAAK,gBAAgB,OAAO,OAAO;AAAA,MACrC;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,QAAQ;AACd,UAAM,gBAAgB,KAAK,OAAO;AAClC,QAAI,kBAAkB,QAAW;AAC/B;AAAA,IACF;AAEA,UAAM,WAAW,KAAK,IAAI,IAAI,gBAAgB,KAAK,KAAK,KAAK;AAC7D,UAAM,aAAa,KAAK,WAAW,IAAI,KAAK,QAAQ,CAAC;AAErD,SAAK,eAAe,UAAU;AAC9B,SAAK,aAAa,UAAU;AAC5B,SAAK,qBAAqB,UAAU;AAAA,EACtC;AAAA;AAAA,EAGQ,eAAe,YAAoB;AACzC,UAAM,kBAAkB;AACxB,UAAM,iBAAiB;AAEvB,QAAI;AACF,iBAAW,aAAS,8BAAY,KAAK,KAAK,EAAE,eAAe,KAAK,CAAC,GAAG;AAClE,YAAI,MAAM,OAAO,GAAG;AAClB,gBAAM,QAAQ,gBAAgB,KAAK,MAAM,IAAI;AAC7C,cAAI,SAAS,MAAM,CAAC,IAAI,YAAY;AAClC,6CAAO,yBAAK,KAAK,KAAK,MAAM,IAAI,GAAG,EAAE,OAAO,KAAK,CAAC;AAAA,UACpD;AAAA,QACF,WAAW,MAAM,YAAY,KAAK,eAAe,KAAK,MAAM,IAAI,KAAK,MAAM,OAAO,YAAY;AAC5F,2CAAO,yBAAK,KAAK,KAAK,MAAM,IAAI,GAAG,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,QACrE;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAAA;AAAA,EAGQ,aAAa,YAAoB;AACvC,QAAI;AACF,iBAAW,aAAS,8BAAY,KAAK,YAAY,EAAE,eAAe,KAAK,CAAC,GAAG;AACzE,YAAI,CAAC,MAAM,OAAO,EAAG;AACrB,cAAM,QAAQ,6BAA6B,KAAK,MAAM,IAAI;AAC1D,YAAI,SAAS,MAAM,CAAC,IAAI,YAAY;AAClC,2CAAO,yBAAK,KAAK,YAAY,MAAM,IAAI,GAAG,EAAE,OAAO,KAAK,CAAC;AACzD,eAAK,QAAQ,OAAO,MAAM,CAAC,CAAC;AAAA,QAC9B;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAAA,EAEQ,qBAAqB,YAAoB;AAC/C,QAAI;AACF,iBAAW,aAAS,8BAAY,KAAK,oBAAoB,EAAE,eAAe,KAAK,CAAC,GAAG;AACjF,YAAI,CAAC,MAAM,OAAO,EAAG;AACrB,cAAM,QAAQ,8BAA8B,KAAK,MAAM,IAAI;AAC3D,YAAI,SAAS,MAAM,CAAC,IAAI,YAAY;AAClC,2CAAO,yBAAK,KAAK,oBAAoB,MAAM,IAAI,GAAG,EAAE,OAAO,KAAK,CAAC;AACjE,eAAK,gBAAgB,OAAO,MAAM,CAAC,CAAC;AAAA,QACtC;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAAA,EAEA,MAAM,QAAQ;AACZ,SAAK,QAAQ,MAAM;AACnB,SAAK,gBAAgB,MAAM;AAC3B,SAAK,gBAAgB,MAAM;AAAA,EAC7B;AACF;;;AE5dA,IAAAC,mBAQO;AACP,IAAAC,qBAA+B;;;ACN/B,IAAM,oBAGF,oBAAI,IAAmE;AAAA,EACzE,CAAC,oBAAoB,oBAAI,IAAI,CAAC,WAAW,CAAC,CAAC;AAAA,EAC3C,CAAC,aAAa,oBAAI,IAAI,CAAC,oBAAoB,CAAC,CAAC;AAAA,EAC7C,CAAC,sBAAsB,oBAAI,IAAI,CAAC,eAAe,CAAC,CAAC;AAAA,EACjD,CAAC,iBAAiB,oBAAI,IAAI,CAAC,cAAc,CAAC,CAAC;AAAA,EAC3C,CAAC,gBAAgB,oBAAI,IAAI,CAAC,kBAAkB,CAAC,CAAC;AAAA,EAC9C,CAAC,oBAAoB,oBAAI,IAAI,CAAC,UAAU,aAAa,CAAC,CAAC;AAAA,EACvD,CAAC,eAAe,oBAAI,IAAI,CAAC,kBAAkB,CAAC,CAAC;AAAA,EAC7C,CAAC,UAAU,oBAAI,IAAI,CAAC,cAAc,CAAC,CAAC;AAAA,EACpC,CAAC,gBAAgB,oBAAI,IAAI,CAAC,eAAe,mBAAmB,CAAC,CAAC;AAAA,EAC9D,CAAC,qBAAqB,oBAAI,IAAI,CAAC,cAAc,CAAC,CAAC;AAAA,EAC/C,CAAC,eAAe,oBAAI,IAAI,CAAC,cAAc,CAAC,CAAC;AAC3C,CAAC;AAgBM,SAAS,kBACd,MACA,IACS;AACT,QAAM,UAAU,kBAAkB,IAAI,IAAI;AAC1C,SAAO,UAAU,QAAQ,IAAI,EAAE,IAAI;AACrC;AAKO,SAAS,WACd,MACA,IACyB;AACzB,MAAI,CAAC,kBAAkB,MAAM,EAAE,GAAG;AAChC,UAAM,IAAI,gBAAgB,MAAM,EAAE;AAAA,EACpC;AACA,SAAO;AACT;AAaO,SAAS,sBAAsB,QAA0C;AAC9E,SACE,WAAW,YACR,WAAW,uBACX,WAAW;AAElB;AAYO,IAAM,kBAAN,cAA8B,MAAM;AAAA,EACzC,YACkB,MACA,IAChB;AACA,UAAM,yCAAW,IAAI,WAAM,EAAE,EAAE;AAHf;AACA;AAGhB,SAAK,OAAO;AAAA,EACd;AACF;;;AD5EA;AAaA,SAAS,gBAAgB,QAAwB;AAC/C,MAAI;AACF,UAAM,WAAW,IAAI,IAAI,MAAM,EAAE;AACjC,UAAM,IAAI,SAAS,MAAM,wBAAwB;AACjD,QAAI,EAAG,QAAO,EAAE,CAAC,EAAE,YAAY;AAAA,EACjC,QAAQ;AACN,UAAM,IAAI,OAAO,MAAM,wBAAwB;AAC/C,QAAI,EAAG,QAAO,EAAE,CAAC,EAAE,YAAY;AAAA,EACjC;AACA,SAAO;AACT;AA4CA,IAAM,iBAAiB;AACvB,IAAM,YAAY;AAClB,IAAM,sBAAsB;AAC5B,IAAM,kBAAkB;AACxB,IAAM,gBAAgB;AACtB,IAAM,aAAa;AAEnB,SAAS,mBAAmB,UAA0B;AACpD,SAAO,SAAS,QAAQ,SAAS,IAAI;AACvC;AAEA,SAAS,8BACP,gBACA,aACoB;AACpB,MAAI,CAAC,eAAgB,QAAO;AAC5B,QAAM,WAAO,6BAAS,gBAAgB,KAAK;AAC3C,QAAM,SAAS,GAAG,WAAW;AAC7B,MAAI,KAAK,WAAW,MAAM,GAAG;AAC3B,UAAM,UAAU,KAAK,MAAM,OAAO,MAAM,EAAE,KAAK;AAC/C,WAAO,WAAW;AAAA,EACpB;AACA,SAAO;AACT;AAEA,SAAS,yBAAyB,UAA0B;AAC1D,QAAM,aAAa,mBAAmB,QAAQ;AAC9C,QAAM,eAAe,WAAW,QAAQ,SAAS;AACjD,MAAI,OAAO,gBAAgB,IACvB,WAAW,MAAM,eAAe,UAAU,MAAM,IAChD;AAEJ,MAAI,KAAK,WAAW,IAAI,GAAG;AACzB,WAAO,KAAK,MAAM,CAAC;AAAA,EACrB;AAEA,MAAI,KAAK,WAAW,wBAAS,GAAG;AAC9B,UAAM,gBAAgB,KAAK,QAAQ,SAAS;AAC5C,QAAI,iBAAiB,GAAG;AACtB,aAAO,KAAK,MAAM,gBAAgB,UAAU,MAAM;AAClD,UAAI,KAAK,WAAW,IAAI,GAAG;AACzB,eAAO,KAAK,MAAM,CAAC;AAAA,MACrB;AAAA,IACF;AAAA,EACF;AAEA,QAAM,QAAQ,KACX,MAAM,IAAI,EACV,OAAO,CAAC,SAAS,CAAC,uBAAuB,KAAK,KAAK,KAAK,CAAC,CAAC,EAC1D,OAAO,CAAC,SAAS,CAAC,yBAAyB,KAAK,KAAK,KAAK,CAAC,CAAC;AAE/D,SAAO,MAAM,KAAK,IAAI,EAAE,QAAQ,WAAW,MAAM,EAAE,KAAK;AAC1D;AAOO,SAAS,2BACd,KACA,QACQ;AACR,QAAM,kBAAc;AAAA,IAClB,IAAI;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,MAAI;AACF,oCAAU,aAAa,EAAE,WAAW,KAAK,CAAC;AAC1C,WAAO,KAAK,yDAAsB,WAAW,EAAE;AAC/C,WAAO;AAAA,EACT,QAAQ;AAAA,EAER;AAEA,MAAI,IAAI,cAAc;AACpB,UAAM,eAAW,yBAAK,IAAI,cAAc,cAAc;AACtD,QAAI;AACF,sCAAU,UAAU,EAAE,WAAW,KAAK,CAAC;AACvC,aAAO,KAAK,iGAAqC,QAAQ,EAAE;AAC3D,aAAO;AAAA,IACT,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,QAAM,IAAI,MAAM,2DAAc,WAAW,EAAE;AAC7C;AAIO,IAAM,mBAAN,MAAuB;AAAA,EAS5B,YACE,KACiB,QACjB;AADiB;AAEjB,SAAK,MAAM;AACX,SAAK,eAAW,yBAAK,KAAK,SAAS;AACnC,SAAK,wBAAoB,yBAAK,KAAK,mBAAmB;AACtD,SAAK,qBAAiB,yBAAK,KAAK,eAAe;AAC/C,SAAK,mBAAe,yBAAK,KAAK,aAAa;AAC3C,SAAK,gBAAY,yBAAK,KAAK,UAAU;AAAA,EACvC;AAAA,EAlBiB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACT,QAAwB,EAAE,YAAY,CAAC,EAAE;AAAA;AAAA,EAejD,MAAM,OAAsB;AAC1B,oCAAU,KAAK,UAAU,EAAE,WAAW,KAAK,CAAC;AAC5C,oCAAU,KAAK,mBAAmB,EAAE,WAAW,KAAK,CAAC;AACrD,oCAAU,KAAK,gBAAgB,EAAE,WAAW,KAAK,CAAC;AAClD,oCAAU,KAAK,cAAc,EAAE,WAAW,KAAK,CAAC;AAChD,SAAK,UAAU;AACf,SAAK,OAAO;AAAA,MACV,qDAAa,KAAK,GAAG,gBAAM,KAAK,MAAM,WAAW,MAAM;AAAA,IACzD;AAAA,EACF;AAAA;AAAA,EAGA,cAAsB;AACpB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,uBAA+B;AAC7B,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,oBAA4B;AAC1B,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,kBAA0B;AACxB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAO,aAAqB,UAAqC;AAC/D,UAAM,KAAK;AACX,UAAM,WAAW,KAAK,SAAS,EAAE;AAEjC,QAAI,UAAU;AACZ,YAAM,eAAe,SAAS,SAAS,kBAAkB,SAAS;AAClE,YAAM,uBACJ,gBACG,CAAC,CAAC,SAAS,aACX,SAAS,WAAW,sBACpB,SAAS,WAAW;AAEzB,UAAI,sBAAsB;AACxB,iBAAS,WAAW;AACpB,iBAAS,aAAY,oBAAI,KAAK,GAAE,YAAY;AAC5C,aAAK,UAAU;AACf,aAAK,OAAO;AAAA,UACV,qDAAa,EAAE,0DAAa,SAAS,MAAM;AAAA,QAC7C;AACA,eAAO;AAAA,MACT;AAGA,UAAI,SAAS,oBAAoB;AAC/B,yCAAO,yBAAK,KAAK,KAAK,SAAS,kBAAkB,GAAG,EAAE,OAAO,KAAK,CAAC;AAAA,MACrE;AACA,UAAI,SAAS,gBAAgB;AAC3B,yCAAO,yBAAK,KAAK,KAAK,SAAS,cAAc,GAAG,EAAE,OAAO,KAAK,CAAC;AAAA,MACjE;AACA,UAAI,SAAS,aAAa;AACxB,yCAAO,yBAAK,KAAK,KAAK,SAAS,WAAW,GAAG,EAAE,OAAO,KAAK,CAAC;AAAA,MAC9D;AACA,eAAS,WAAW;AACpB,eAAS,SAAS;AAClB,eAAS,qBAAqB;AAC9B,eAAS,iBAAiB;AAC1B,eAAS,cAAc;AACvB,eAAS,QAAQ;AACjB,eAAS,YAAY;AACrB,eAAS,aAAY,oBAAI,KAAK,GAAE,YAAY;AAC5C,WAAK,OAAO,KAAK,qDAAa,EAAE,EAAE;AAAA,IACpC,OAAO;AACL,YAAM,QAA6B;AAAA,QACjC;AAAA,QACA;AAAA,QACA,QAAQ;AAAA,QACR,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,QACnC,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MACpC;AACA,WAAK,MAAM,WAAW,KAAK,KAAK;AAChC,WAAK,OAAO,KAAK,qDAAa,EAAE,EAAE;AAAA,IACpC;AAEA,SAAK,UAAU;AACf,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,aACE,aACA,WACqB;AACrB,UAAM,QAAQ,KAAK,SAAS,WAAW;AACvC,QAAI,CAAC,OAAO;AACV,YAAM,IAAI,MAAM,mCAAU,WAAW,EAAE;AAAA,IACzC;AAEA,UAAM,kBAAkB,WAAW,MAAM,QAAQ,SAAS;AAC1D,UAAM,SAAS;AACf,UAAM,aAAY,oBAAI,KAAK,GAAE,YAAY;AACzC,SAAK,UAAU;AACf,SAAK,OAAO,KAAK,yCAAW,WAAW,WAAM,SAAS,EAAE;AACxD,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,aAAqB,UAAwB;AACxD,UAAM,QAAQ,KAAK,SAAS,WAAW;AACvC,QAAI,CAAC,MAAO;AACZ,UAAM,YAAY,GAAG,SAAS,IAAI,QAAQ;AAC1C,UAAM,aAAY,oBAAI,KAAK,GAAE,YAAY;AACzC,SAAK,UAAU;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA,EAKA,WAAW,aAAqB,UAAwB;AACtD,UAAM,QAAQ,KAAK,SAAS,WAAW;AACvC,QAAI,CAAC,MAAO;AACZ,UAAM,UAAU,GAAG,SAAS,IAAI,QAAQ;AACxC,UAAM,aAAY,oBAAI,KAAK,GAAE,YAAY;AACzC,SAAK,UAAU;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA,EAKA,sBAAsB,aAAqB,UAAwB;AACjE,UAAM,QAAQ,KAAK,SAAS,WAAW;AACvC,QAAI,CAAC,MAAO;AACZ,UAAM,yBAAyB,GAAG,mBAAmB,IAAI,QAAQ;AACjE,QAAI,MAAM,sBAAsB,MAAM,uBAAuB,wBAAwB;AACnF,uCAAO,yBAAK,KAAK,KAAK,MAAM,kBAAkB,GAAG,EAAE,OAAO,KAAK,CAAC;AAAA,IAClE;AACA,UAAM,qBAAqB;AAC3B,UAAM,aAAY,oBAAI,KAAK,GAAE,YAAY;AACzC,SAAK,UAAU;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA,EAKA,kBAAkB,aAAqB,UAAwB;AAC7D,UAAM,QAAQ,KAAK,SAAS,WAAW;AACvC,QAAI,CAAC,MAAO;AACZ,UAAM,qBAAqB,GAAG,eAAe,IAAI,QAAQ;AACzD,QAAI,MAAM,kBAAkB,MAAM,mBAAmB,oBAAoB;AACvE,uCAAO,yBAAK,KAAK,KAAK,MAAM,cAAc,GAAG,EAAE,OAAO,KAAK,CAAC;AAAA,IAC9D;AACA,UAAM,iBAAiB;AACvB,UAAM,aAAY,oBAAI,KAAK,GAAE,YAAY;AACzC,SAAK,UAAU;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA,EAKA,eAAe,aAAqB,UAAwB;AAC1D,UAAM,QAAQ,KAAK,SAAS,WAAW;AACvC,QAAI,CAAC,MAAO;AACZ,UAAM,kBAAkB,GAAG,aAAa,IAAI,QAAQ;AACpD,QAAI,MAAM,eAAe,MAAM,gBAAgB,iBAAiB;AAC9D,uCAAO,yBAAK,KAAK,KAAK,MAAM,WAAW,GAAG,EAAE,OAAO,KAAK,CAAC;AAAA,IAC3D;AACA,UAAM,cAAc;AACpB,UAAM,aAAY,oBAAI,KAAK,GAAE,YAAY;AACzC,SAAK,UAAU;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA,EAKA,SAAS,aAAqB,OAAsB;AAClD,UAAM,QAAQ,KAAK,SAAS,WAAW;AACvC,QAAI,CAAC,MAAO;AACZ,UAAM,QAAQ,OAAO,KAAK,KAAK;AAC/B,UAAM,aAAY,oBAAI,KAAK,GAAE,YAAY;AACzC,SAAK,UAAU;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,aAAqB,OAAsB;AACtD,UAAM,QAAQ,KAAK,SAAS,WAAW;AACvC,QAAI,CAAC,MAAO;AACZ,UAAM,YAAY,OAAO,KAAK,KAAK;AACnC,UAAM,aAAY,oBAAI,KAAK,GAAE,YAAY;AACzC,SAAK,UAAU;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY,aAAyC;AACnD,UAAM,QAAQ,KAAK,SAAS,WAAW;AACvC,QAAI,CAAC,MAAO,QAAO;AAEnB,QAAI,MAAM,aAAa;AACrB,YAAM,UAAU,KAAK,qBAAqB,MAAM,WAAW;AAC3D,UAAI,SAAS,KAAK,GAAG;AACnB,eAAO,QAAQ,KAAK;AAAA,MACtB;AAAA,IACF;AAEA,UAAM,gBAAgB,MAAM,qBACxB,KAAK,+BAA+B,MAAM,kBAAkB,IAC5D;AACJ,WAAO,qCAAqC,aAAa;AAAA,EAC3D;AAAA;AAAA;AAAA;AAAA,EAKA,eAAe,aAAyC;AACtD,UAAM,QAAQ,KAAK,SAAS,WAAW;AACvC,QAAI,CAAC,MAAO,QAAO;AAEnB,QAAI,MAAM,oBAAoB;AAC5B,YAAM,gBAAgB,KAAK,+BAA+B,MAAM,kBAAkB;AAClF,YAAM,qBAAqB,kCAAkC,aAAa;AAC1E,UAAI,uBAAuB,QAAW;AACpC,eAAO;AAAA,MACT;AAAA,IACF;AAEA,QAAI,CAAC,MAAM,eAAgB,QAAO;AAClC,UAAM,WAAW,KAAK,qBAAqB,MAAM,cAAc;AAC/D,QAAI,CAAC,SAAU,QAAO;AACtB,UAAM,aAAa,yBAAyB,QAAQ;AACpD,WAAO,cAAc;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKA,uBAAuB,aAAqB;AAC1C,UAAM,QAAQ,KAAK,SAAS,WAAW;AACvC,QAAI,CAAC,OAAO,oBAAoB;AAC9B,aAAO;AAAA,IACT;AACA,WAAO,KAAK,+BAA+B,MAAM,kBAAkB;AAAA,EACrE;AAAA;AAAA,EAIA,SAAS,IAA6C;AACpD,WAAO,KAAK,MAAM,WAAW,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE;AAAA,EACtD;AAAA,EAEA,UAAiC;AAC/B,WAAO,CAAC,GAAG,KAAK,MAAM,UAAU,EAAE;AAAA,MAChC,CAAC,GAAG,MAAM,EAAE,SAAS,WAAW,cAAc,EAAE,SAAS,UAAU;AAAA,IACrE;AAAA,EACF;AAAA,EAEA,aAAa,QAAwD;AACnE,WAAO,KAAK,QAAQ,EAAE,OAAO,CAAC,MAAM,EAAE,WAAW,MAAM;AAAA,EACzD;AAAA,EAEA,OAAO,aAAqB,MAAmC;AAC7D,UAAM,QAAQ,KAAK,SAAS,WAAW;AACvC,QAAI,CAAC,OAAO;AACV,YAAM,IAAI,MAAM,mCAAU,WAAW,EAAE;AAAA,IACzC;AAEA,UAAM,WAAW;AAAA,MACf,GAAG,MAAM;AAAA,MACT;AAAA,IACF;AACA,UAAM,aAAY,oBAAI,KAAK,GAAE,YAAY;AACzC,SAAK,UAAU;AACf,SAAK,OAAO,KAAK,+CAAY,WAAW,WAAM,IAAI,EAAE;AACpD,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,OACE,aACA,MACS;AACT,UAAM,QAAQ,KAAK,SAAS,WAAW;AACvC,QAAI,CAAC,MAAO,QAAO;AAGnB,QAAI,MAAM,WAAW;AACnB,YAAM,gBAAY,yBAAK,KAAK,KAAK,MAAM,SAAS;AAChD,mCAAO,WAAW,EAAE,OAAO,KAAK,CAAC;AAAA,IACnC;AACA,QAAI,MAAM,SAAS;AACjB,YAAM,cAAU,yBAAK,KAAK,KAAK,MAAM,OAAO;AAC5C,mCAAO,SAAS,EAAE,OAAO,KAAK,CAAC;AAAA,IACjC;AACA,QAAI,MAAM,oBAAoB;AAC5B,YAAM,yBAAqB,yBAAK,KAAK,KAAK,MAAM,kBAAkB;AAClE,mCAAO,oBAAoB,EAAE,OAAO,KAAK,CAAC;AAAA,IAC5C;AACA,QAAI,MAAM,gBAAgB;AACxB,YAAM,qBAAiB,yBAAK,KAAK,KAAK,MAAM,cAAc;AAC1D,mCAAO,gBAAgB,EAAE,OAAO,KAAK,CAAC;AAAA,IACxC;AACA,QAAI,MAAM,aAAa;AACrB,YAAM,kBAAc,yBAAK,KAAK,KAAK,MAAM,WAAW;AACpD,mCAAO,aAAa,EAAE,OAAO,KAAK,CAAC;AAAA,IACrC;AAEA,QAAI,MAAM,WAAW;AAEnB,YAAM,YAAY;AAClB,YAAM,UAAU;AAChB,YAAM,qBAAqB;AAC3B,YAAM,iBAAiB;AACvB,YAAM,cAAc;AACpB,YAAM,aAAY,oBAAI,KAAK,GAAE,YAAY;AACzC,WAAK,UAAU;AACf,WAAK,OAAO,KAAK,+FAAoB,WAAW,EAAE;AAAA,IACpD,OAAO;AAEL,WAAK,MAAM,aAAa,KAAK,MAAM,WAAW;AAAA,QAC5C,CAAC,MAAM,EAAE,OAAO;AAAA,MAClB;AACA,WAAK,UAAU;AACf,WAAK,OAAO,KAAK,+CAAY,WAAW,EAAE;AAAA,IAC5C;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,mBAAmB,aAAqB,QAAyB;AAC/D,UAAM,MAAM,SAAS,gBAAgB,MAAM,IAAI;AAC/C,WAAO,GAAG,WAAW,GAAG,GAAG;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA,EAKA,iBAAiB,aAA6B;AAC5C,WAAO,GAAG,WAAW;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKA,4BAA4B,aAA6B;AACvD,WAAO,4BAAgC,WAAW;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,wBAAwB,aAAqB,SAAyB;AAEpE,UAAM,cAAc,QACjB,QAAQ,iBAAiB,EAAE,EAC3B,KAAK,EACL,MAAM,GAAG,EAAE;AACd,WAAO,cACH,GAAG,WAAW,IAAI,WAAW,QAC7B,GAAG,WAAW;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA,EAKA,qBAAqB,aAA6B;AAChD,WAAO,GAAG,WAAW;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKA,iBAAiB,aAAqB,QAAyB;AAC7D,eAAO,yBAAK,KAAK,UAAU,KAAK,mBAAmB,aAAa,MAAM,CAAC;AAAA,EACzE;AAAA;AAAA;AAAA;AAAA,EAKA,eAAe,aAA6B;AAC1C,eAAO,yBAAK,KAAK,UAAU,KAAK,iBAAiB,WAAW,CAAC;AAAA,EAC/D;AAAA;AAAA;AAAA;AAAA,EAKA,0BAA0B,aAA6B;AACrD,eAAO,yBAAK,KAAK,mBAAmB,KAAK,4BAA4B,WAAW,CAAC;AAAA,EACnF;AAAA;AAAA;AAAA;AAAA,EAKA,mBAAmB,aAA6B;AAC9C,eAAO,yBAAK,KAAK,cAAc,KAAK,qBAAqB,WAAW,CAAC;AAAA,EACvE;AAAA;AAAA,EAIQ,YAAkB;AACxB,QAAI,KAAC,6BAAW,KAAK,SAAS,GAAG;AAC/B,WAAK,QAAQ,EAAE,YAAY,CAAC,EAAE;AAC9B;AAAA,IACF;AACA,QAAI;AACF,YAAM,MAAM,KAAK,UAAM,+BAAa,KAAK,WAAW,OAAO,CAAC;AAC5D,UAAI,OAAO,MAAM,QAAQ,IAAI,UAAU,GAAG;AACxC,YAAI,eAAe;AACnB,cAAM,aAAa,IAAI,WACpB,OAAO,CAAC,UAAmB,SAAS,OAAO,UAAU,QAAQ,EAC7D,IAAI,CAAC,UAAe;AACnB,gBAAM,YAAiC;AAAA,YACrC,IAAI,MAAM;AAAA,YACV,UAAU,MAAM;AAAA,YAChB,QAAQ,MAAM;AAAA,YACd,YAAY,MAAM;AAAA,YAClB,WAAW,MAAM;AAAA,UACnB;AACA,cAAI,OAAO,MAAM,cAAc,SAAU,WAAU,YAAY,MAAM;AACrE,cAAI,OAAO,MAAM,YAAY,SAAU,WAAU,UAAU,MAAM;AACjE,cAAI,OAAO,MAAM,mBAAmB,UAAU;AAC5C,sBAAU,iBAAiB,MAAM;AAAA,UACnC;AACA,cAAI,gBAAgB,OAAO,MAAM,uBAAuB,WACpD,KAAK,+BAA+B,MAAM,kBAAkB,IAC5D;AACJ,cAAI,OAAO,MAAM,uBAAuB,YAAY,eAAe;AACjE,sBAAU,qBAAqB,MAAM;AAAA,UACvC,OAAO;AACL,kBAAM,uBAAuB,OAAO,MAAM,eAAe,YAAY,MAAM,WAAW,KAAK,IACvF,MAAM,WAAW,KAAK,IACtB,UAAU,iBACR;AAAA,cACA,KAAK,qBAAqB,UAAU,cAAc,KAAK;AAAA,YACzD,KAAK,SACH;AACN,kBAAM,cAAc,OAAO,MAAM,UAAU,YAAY,MAAM,MAAM,KAAK,IACpE,MAAM,MAAM,KAAK,IACjB,8BAA8B,UAAU,gBAAgB,UAAU,EAAE;AACxE,kBAAM,gBAAgB,OAAO,MAAM,YAAY,YAAY,MAAM,QAAQ,KAAK,IAC1E,MAAM,QAAQ,KAAK,IACnB;AAEJ,gBAAI,sBAAsB;AACxB,8BAAgB,wBAAwB;AAAA,gBACtC,aAAa,UAAU;AAAA,gBACvB,aAAa,UAAU;AAAA,gBACvB,QAAQ;AAAA,kBACN,UAAU;AAAA,gBACZ;AAAA,gBACA,OAAO;AAAA,gBACP,SAAS;AAAA,gBACT,MAAM;AAAA,gBACN,UAAU,CAAC;AAAA,cACb,CAAC;AACD,oBAAM,yBAAyB,KAAK,4BAA4B,UAAU,EAAE;AAC5E;AAAA,oBACE,yBAAK,KAAK,mBAAmB,sBAAsB;AAAA,gBACnD,KAAK,UAAU,eAAe,MAAM,CAAC;AAAA,gBACrC;AAAA,cACF;AACA,wBAAU,qBAAqB,GAAG,mBAAmB,IAAI,sBAAsB;AAC/E,6BAAe;AAAA,YACjB;AAAA,UACF;AAEA,cAAI,OAAO,MAAM,gBAAgB,UAAU;AACzC,sBAAU,cAAc,MAAM;AAAA,UAChC,WAAW,OAAO,MAAM,YAAY,YAAY,MAAM,QAAQ,KAAK,GAAG;AACpE,kBAAM,kBAAkB,KAAK,qBAAqB,MAAM,EAAE;AAC1D;AAAA,kBACE,yBAAK,KAAK,cAAc,eAAe;AAAA,cACvC,MAAM,QAAQ,KAAK;AAAA,cACnB;AAAA,YACF;AACA,sBAAU,cAAc,GAAG,aAAa,IAAI,eAAe;AAC3D,2BAAe;AAAA,UACjB,OAAO;AACL,kBAAM,sBAAsB,qCAAqC,aAAa;AAC9E,gBAAI,qBAAqB;AACvB,oBAAM,kBAAkB,KAAK,qBAAqB,MAAM,EAAE;AAC1D;AAAA,oBACE,yBAAK,KAAK,cAAc,eAAe;AAAA,gBACvC;AAAA,gBACA;AAAA,cACF;AACA,wBAAU,cAAc,GAAG,aAAa,IAAI,eAAe;AAC3D,6BAAe;AAAA,YACjB;AAAA,UACF;AACA,cAAI,OAAO,MAAM,UAAU,YAAY,MAAM,MAAM,KAAK,GAAG;AACzD,sBAAU,QAAQ,MAAM,MAAM,KAAK;AAAA,UACrC,OAAO;AACL,kBAAM,oBAAoB,mCAAmC,aAAa;AAC1E,kBAAM,eAAe,qBAAqB;AAAA,cACxC,UAAU;AAAA,cACV,UAAU;AAAA,YACZ;AACA,gBAAI,cAAc;AAChB,wBAAU,QAAQ;AAClB,6BAAe;AAAA,YACjB;AAAA,UACF;AACA,cAAI,OAAO,MAAM,cAAc,YAAY,MAAM,UAAU,KAAK,GAAG;AACjE,sBAAU,YAAY,MAAM,UAAU,KAAK;AAAA,UAC7C;AACA,cAAI,UAAU,WAAW,gBAAgB;AACvC,sBAAU,SAAS;AACnB,sBAAU,YAAY,UAAU,aAC3B;AACL,sBAAU,aAAY,oBAAI,KAAK,GAAE,YAAY;AAC7C,2BAAe;AAAA,UACjB;AACA,iBAAO;AAAA,QACT,CAAC;AACH,cAAM,iBAAiB,IAAI,WAAW;AAAA,UACpC,CAAC,UAAe,SAAS,OAAO,UAAU,aAAa,gBAAgB,SAAS,aAAa;AAAA,QAC/F;AACA,aAAK,QAAQ,EAAE,YAAY,WAAW;AACtC,YAAI,kBAAkB,cAAc;AAClC,eAAK,UAAU;AAAA,QACjB;AAAA,MACF,OAAO;AACL,aAAK,QAAQ,EAAE,YAAY,CAAC,EAAE;AAAA,MAChC;AAAA,IACF,QAAQ;AACN,WAAK,OAAO,KAAK,6EAAiB,KAAK,SAAS,EAAE;AAClD,WAAK,QAAQ,EAAE,YAAY,CAAC,EAAE;AAAA,IAChC;AAAA,EACF;AAAA,EAEQ,qBAAqB,cAA0C;AACrE,QAAI;AACF,iBAAO,mCAAa,yBAAK,KAAK,KAAK,YAAY,GAAG,OAAO;AAAA,IAC3D,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEQ,+BAA+B,cAAsB;AAC3D,UAAM,MAAM,KAAK,qBAAqB,YAAY;AAClD,QAAI,CAAC,KAAK;AACR,aAAO;AAAA,IACT;AACA,WAAO,wBAAwB,GAAG;AAAA,EACpC;AAAA,EAEQ,YAAkB;AACxB;AAAA,MACE,KAAK;AAAA,MACL,KAAK,UAAU,KAAK,OAAO,MAAM,CAAC;AAAA,MAClC;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,QAAuB;AAAA,EAE7B;AACF;;;AE1xBA;;;ACAA,IAAAC,mBAA+E;AAC/E,IAAAC,qBAAwB;AACxB,IAAAC,mBAAyB;AACzB,yBAAyB;AAwBzB,IAAMC,sBAAqB,IAAI,KAAK;AACpC,IAAM,sBAAsB;AAC5B,IAAM,2BAA2B;AAOjC,eAAsB,aACpB,KACA,UACA,QACA,SACyB;AACzB,QAAM,YAAY,SAAS,aAAaA;AACxC,QAAM,aAAa,SAAS,cAAc;AAC1C,QAAM,iBAAiB,SAAS,kBAAkB;AAElD,sCAAU,4BAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;AAEhD,MAAI;AAEJ,WAAS,UAAU,GAAG,WAAW,YAAY,WAAW;AACtD,UAAM,UAAU,KAAK,IAAI;AACzB,QAAI;AACF,aAAO;AAAA,QACL,kDAA8B,OAAO,IAAI,UAAU,MAAM,GAAG;AAAA,MAC9D;AAEA,YAAM,aAAa,IAAI,gBAAgB;AACvC,YAAM,QAAQ,WAAW,MAAM,WAAW,MAAM,GAAG,SAAS;AAE5D,UAAI;AACF,cAAM,MAAM,MAAM,MAAM,KAAK,EAAE,QAAQ,WAAW,OAAO,CAAC;AAE1D,YAAI,CAAC,IAAI,IAAI;AACX,gBAAM,IAAI,MAAM,QAAQ,IAAI,MAAM,IAAI,IAAI,UAAU,EAAE;AAAA,QACxD;AAEA,YAAI,CAAC,IAAI,MAAM;AACb,gBAAM,IAAI,MAAM,gCAAO;AAAA,QACzB;AAGA,cAAM,kBAAc,oCAAkB,QAAQ;AAC9C,cAAM,WAAW,4BAAS,QAAQ,IAAI,IAAW;AACjD,kBAAM,2BAAS,UAAU,WAAW;AAEpC,cAAM,UAAU,KAAK,IAAI,IAAI;AAC7B,cAAM,eAAW,6BAAW,QAAQ,QAChC,2BAAS,QAAQ,EAAE,OACnB;AAEJ,eAAO;AAAA,UACL,0CAAsB,QAAQ,KAAK,YAAY,QAAQ,CAAC,KAAK,OAAO;AAAA,QACtE;AAEA,eAAO,EAAE,IAAI,MAAM,WAAW,UAAU,WAAW,QAAQ;AAAA,MAC7D,UAAE;AACA,qBAAa,KAAK;AAAA,MACpB;AAAA,IACF,SAASC,MAAU;AACjB,kBAAYA,MAAK,WAAW,OAAOA,IAAG;AAGtC,UAAI;AACF,gBAAI,6BAAW,QAAQ,EAAG,kCAAW,QAAQ;AAAA,MAC/C,QAAQ;AAAA,MAER;AAEA,YAAM,UAAUA,MAAK,SAAS;AAC9B,aAAO;AAAA,QACL,kDAA8B,OAAO,IAAI,UAAU,MAAM,UAAU,iBAAO,SAAS;AAAA,MACrF;AAEA,UAAI,UAAU,YAAY;AACxB,cAAM,QAAQ,iBAAiB,KAAK,IAAI,GAAG,UAAU,CAAC;AACtD,eAAO,KAAK,gBAAgB,KAAK,0BAAW;AAC5C,cAAM,MAAM,KAAK;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AAEA,SAAO,EAAE,IAAI,OAAO,OAAO,aAAa,2BAAO;AACjD;AAKA,eAAsB,uBACpB,aACA,WACA,eACA,aACA,QACA,SAIC;AAED,QAAM,QAAQ,MAAM,aAAa,aAAa,eAAe,QAAQ,OAAO;AAG5E,MAAI,MAA6B;AACjC,MAAI,WAAW;AACb,UAAM,MAAM,aAAa,WAAW,aAAa,QAAQ,OAAO;AAChE,QAAI,CAAC,IAAI,IAAI;AAEX,aAAO,KAAK,gGAA+B,IAAI,KAAK,EAAE;AAAA,IACxD;AAAA,EACF;AAEA,SAAO,EAAE,OAAO,IAAI;AACtB;AAIA,SAAS,YAAY,OAAuB;AAC1C,MAAI,QAAQ,KAAM,QAAO,GAAG,KAAK;AACjC,MAAI,QAAQ,OAAO,KAAM,QAAO,IAAI,QAAQ,MAAM,QAAQ,CAAC,CAAC;AAC5D,SAAO,IAAI,SAAS,OAAO,OAAO,QAAQ,CAAC,CAAC;AAC9C;AAEA,SAAS,MAAM,IAA2B;AACxC,SAAO,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;AACzD;;;AD3HA;AAYA;;;AE/BA;;;ACZA;AACA;AAkBA,eAAsB,qBACpB,SACA,QAC8B;AAC9B,QAAM,UAAU,SAAS,KAAK;AAC9B,MAAI,CAAC,SAAS;AACZ,WAAO,EAAE,IAAI,OAAO,OAAO,mBAAmB;AAAA,EAChD;AAEA,QAAM,SAAS,WAAW;AAC1B,MAAI,CAAC,QAAQ;AACX,WAAO,EAAE,IAAI,OAAO,OAAO,4EAA0B;AAAA,EACvD;AAEA,QAAM,eAAe,WAAW,EAAE;AAClC,QAAM,YAAY,OAAO,WAAW,SAAS,IACzC,OAAO,MAAM,UAAU,MAAM,IAC7B;AAEJ,QAAM,MAAM,IAAI,IAAI,YAAY;AAChC,MAAI,aAAa,IAAI,WAAW,OAAO;AACvC,QAAM,WAAW,IAAI,SAAS;AAE9B,SAAO,KAAK,4EAA8C,QAAQ,EAAE;AAEpE,MAAI;AACJ,MAAI;AACF,UAAM,MAAM,MAAM,UAAU;AAAA,MAC1B,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,gBAAgB;AAAA,MAClB;AAAA,IACF,CAAC;AAAA,EACH,SAASC,MAAU;AACjB,UAAM,QAAQA,MAAK,WAAW,OAAOA,IAAG;AACxC,WAAO,KAAK,kDAA8B,KAAK,EAAE;AACjD,WAAO,EAAE,IAAI,OAAO,MAAM;AAAA,EAC5B;AAEA,QAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,MAAI,CAAC,IAAI,IAAI;AACX,WAAO;AAAA,MACL,kDAAwC,IAAI,MAAM,UAAU,KAAK,MAAM,GAAG,GAAG,CAAC;AAAA,IAChF;AACA,WAAO,EAAE,IAAI,OAAO,OAAO,QAAQ,IAAI,MAAM,IAAI,KAAK,MAAM,GAAG,GAAG,CAAC,GAAG;AAAA,EACxE;AAEA,MAAI;AACJ,MAAI;AACF,cAAU,OAAQ,KAAK,MAAM,IAAI,IAA+B;AAAA,EAClE,QAAQ;AACN,WAAO,KAAK,sDAAuC,KAAK,MAAM,GAAG,GAAG,CAAC,EAAE;AACvE,WAAO,EAAE,IAAI,OAAO,OAAO,uBAAuB;AAAA,EACpD;AAEA,QAAM,OAAO,OAAO,SAAS,SAAS,WAAW,OAAO,QAAQ,IAAI,IAAI,SAAS,MAAM,OAAO;AAC9F,MAAI,SAAS,UAAU;AACrB,UAAM,MAAM,SAAS,KAAK,OAAO,KAAK,KAAK,MAAM,GAAG,GAAG;AACvD,WAAO,KAAK,uDAAmC,QAAQ,KAAK,SAAS,GAAG,EAAE;AAC1E,WAAO,EAAE,IAAI,OAAO,OAAO,GAAG,QAAQ,SAAS,IAAI,GAAG,GAAG,KAAK,EAAE;AAAA,EAClE;AAEA,SAAO,KAAK,oEAA2C,OAAO,EAAE;AAChE,SAAO,EAAE,IAAI,KAAK;AACpB;;;ADjDA,SAAS,oBACP,aACA,SACA,QACA,cACA,OACA,QACM;AACN,MAAI,CAAC,cAAc;AACjB;AAAA,EACF;AAEA,QAAM,QAAQ,QAAQ,SAAS,WAAW;AAC1C,MAAI,CAAC,OAAO;AACV;AAAA,EACF;AAEA,QAAM,QAAQ,QAAQ,OAAO,KAAK,KAC7B,MAAM,OAAO,KAAK,KAClB,MAAM,SAAS,MAAM,KAAK,KAC1B,MAAM;AACX,QAAM,iBAAiB,MAAM,WAAW,KAAK,KAAK;AAElD,MAAI;AACF,iBAAa;AAAA,MACX,aAAa,MAAM;AAAA,MACnB,iBAAiB,MAAM;AAAA,MACvB,WAAW,MAAM;AAAA,MACjB,SAAS,MAAM;AAAA,MACf,oBAAoB,MAAM;AAAA,MAC1B,gBAAgB,MAAM;AAAA,MACtB,YAAY,QAAQ;AAAA,MACpB,SAAS,QAAQ;AAAA,MACjB;AAAA,MACA,WAAW,MAAM;AAAA,MACjB,OAAO,SAAS;AAAA,IAClB,CAAC;AAAA,EACH,SAASC,MAAU;AACjB,WAAO;AAAA,MACL,wEAAgC,WAAW,KAAKA,MAAK,WAAWA,IAAG;AAAA,IACrE;AAAA,EACF;AACF;AAEA,eAAe,6BACb,UACA,aACA,SACA,WACA,QACA,SACe;AACf,QAAM,gBAAgB,QAAQ;AAAA,IAC5B;AAAA,IACA,SAAS;AAAA,EACX;AACA,QAAM,cAAc,QAAQ,eAAe,WAAW;AAEtD,SAAO;AAAA,IACL,sEAA8B,WAAW,WAAW,SAAS,aAAa;AAAA,EAC5E;AAEA,QAAM,iBAAiB,MAAM;AAAA,IAC3B,SAAS;AAAA,IACT,SAAS;AAAA,IACT;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,MAAI,CAAC,eAAe,MAAM,IAAI;AAC5B,UAAM,QAAQ,yCAAW,eAAe,MAAM,KAAK;AACnD,WAAO,MAAM,oBAAoB,KAAK,KAAK,WAAW,EAAE;AACxD,YAAQ,aAAa,aAAa,aAAa;AAC/C,YAAQ,aAAa,aAAa,KAAK;AACvC;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,IACF;AACA;AAAA,EACF;AAEA,UAAQ,aAAa,aAAa,MAAS;AAC3C,UAAQ;AAAA,IACN;AAAA,IACA,QAAQ,mBAAmB,aAAa,SAAS,aAAa;AAAA,EAChE;AACA,MAAI,eAAe,KAAK,IAAI;AAC1B,YAAQ,WAAW,aAAa,QAAQ,iBAAiB,WAAW,CAAC;AAAA,EACvE;AAEA,UAAQ,aAAa,aAAa,QAAQ;AAC1C,SAAO,KAAK,oDAA2B,WAAW,EAAE;AACpD,sBAAoB,aAAa,SAAS,QAAQ,QAAQ,YAAY;AAEtE,MAAI,gBAAgB,SAAS,KAAK,sBAAsB,QAAQ,GAAG;AACjE,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;AAKA,eAAsB,oBACpB,aACA,UACA,SACA,WACA,QACA,UAAgC,CAAC,GACH;AAC9B,QAAM,WAAW,QAAQ,SAAS,WAAW;AAC7C,QAAM,wBACJ,CAAC,YACE,SAAS,SAAS,kBAAkB,SAAS,iBAC7C,CAAC,SAAS,aACV,SAAS,WAAW,sBACpB,SAAS,WAAW;AAEzB,UAAQ,OAAO,aAAa,QAAQ;AACpC,MAAI,uBAAuB;AACzB;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,MAAM,CAACA,SAAQ;AACf,YAAM,QAAQ,yCAAWA,MAAK,WAAWA,IAAG;AAC5C,aAAO,MAAM,oBAAoB,KAAK,KAAK,WAAW,EAAE;AACxD,YAAMC,WAAU,QAAQ,SAAS,WAAW;AAC5C,UAAIA,UAAS,WAAW,oBAAoB;AAC1C,gBAAQ,aAAa,aAAa,aAAa;AAAA,MACjD;AACA,cAAQ,aAAa,aAAa,KAAK;AACvC;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA,QAAQ;AAAA,QACR;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH,OAAO;AACL,WAAO;AAAA,MACL,kIAAwC,WAAW;AAAA,IACrD;AACA,wBAAoB,aAAa,SAAS,QAAQ,QAAQ,YAAY;AAEtE,UAAMA,WAAU,QAAQ,SAAS,WAAW;AAC5C,QAAIA,UAAS,WAAW,YAAY,gBAAgB,SAAS,GAAG;AAC9D;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,EAAE,MAAM,CAACD,SAAQ;AACf,eAAO;AAAA,UACL,uDAAyB,WAAW,KAAKA,MAAK,WAAWA,IAAG;AAAA,QAC9D;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAEA,QAAM,UAAU,QAAQ,SAAS,WAAW;AAC5C,SAAO;AAAA,IACL,IAAI;AAAA,IACJ;AAAA,IACA,iBAAiB,SAAS,UAAU;AAAA,IACpC,GAAI,SAAS,YAAY,EAAE,OAAO,QAAQ,UAAU,IAAI,CAAC;AAAA,EAC3D;AACF;AAKA,eAAsB,qBACpB,aACA,SACA,WACA,QACA,UAAgC,CAAC,GAClB;AACf,QAAM,QAAQ,QAAQ,SAAS,WAAW;AAC1C,MAAI,CAAC,OAAO;AACV,WAAO,KAAK,iDAAwB,WAAW,EAAE;AACjD;AAAA,EACF;AAEA,MAAI,CAAC,sBAAsB,MAAM,MAAM,GAAG;AACxC,WAAO;AAAA,MACL,yEAA4B,WAAW,YAAY,MAAM,MAAM;AAAA,IACjE;AACA;AAAA,EACF;AAGA,UAAQ,aAAa,aAAa,cAAc;AAChD,UAAQ,aAAa,aAAa,MAAS;AAC3C,sBAAoB,aAAa,SAAS,QAAQ,QAAQ,YAAY;AAEtE,QAAM,gBAAgB,QAAQ,iBAAiB,WAAW;AAE1D,MAAI;AACJ,MAAI;AACF,aAAS,MAAM,yBAAyB;AAAA,MACtC;AAAA,MACA,aAAa,MAAM,SAAS;AAAA,MAC5B,QAAQ;AAAA,MACR,SAAS,MAAM,SAAS,WAAW,CAAC;AAAA,MACpC,eAAe,MAAM,SAAS;AAAA,MAC9B,aAAa,MAAM,SAAS;AAAA,MAC5B,WAAW,MAAM,SAAS;AAAA,MAC1B,mBAAmB,QAAQ,qBAAqB;AAAA,MAChD,gBAAgB,QAAQ,kBAAkB;AAAA,MAC1C,cAAc,QAAQ,gBAAgB;AAAA,MACtC;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH,SAASA,MAAU;AACjB,UAAM,QAAQ,yCAAWA,MAAK,WAAWA,IAAG;AAC5C,WAAO,MAAM,iBAAiB,KAAK,KAAK,WAAW,EAAE;AACrD,aAAS,EAAE,IAAI,OAAO,MAAM;AAAA,EAC9B;AAEA,MAAI,OAAO,MAAM,OAAO,oBAAoB;AAC1C,QAAI,OAAO,wBAAwB;AACjC,cAAQ,sBAAsB,aAAa,OAAO,sBAAsB;AAAA,IAC1E;AACA,YAAQ,kBAAkB,aAAa,OAAO,kBAAkB;AAChE,QAAI,OAAO,iBAAiB;AAC1B,cAAQ,eAAe,aAAa,OAAO,eAAe;AAAA,IAC5D;AACA,YAAQ,SAAS,aAAa,OAAO,KAAK;AAC1C,YAAQ,aAAa,aAAa,aAAa;AAC/C;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,QACE,YAAY,OAAO,cAAc,CAAC;AAAA,QAClC,SAAS,OAAO;AAAA,QAChB,OAAO,OAAO,SAAS;AAAA,MACzB;AAAA,IACF;AACA,WAAO;AAAA,MACL,2CAAuB,WAAW,cAAc,OAAO,OAAO;AAAA,IAChE;AAGA,UAAM,cAAc,MAAM,SAAS,eAAe,KAAK;AACvD,QAAI,aAAa;AACf,WAAK,qBAAqB,aAAa,MAAM,EAAE,MAAM,CAACA,SAAQ;AAC5D,eAAO;AAAA,UACL,gFAAmC,WAAW,KAAKA,MAAK,WAAWA,IAAG;AAAA,QACxE;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF,OAAO;AACL,UAAM,QAAQ,OAAO,SAAS;AAC9B,YAAQ,aAAa,aAAa,mBAAmB;AACrD,YAAQ,aAAa,aAAa,KAAK;AACvC;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,IACF;AACA,WAAO;AAAA,MACL,2CAAuB,WAAW,WAAW,KAAK;AAAA,IACpD;AAAA,EACF;AACF;;;AExUA,IAAAE,mBAOO;AACP,IAAAC,qBAA8B;AAC9B;;;ACTA,IAAAC,mBAAyC;AACzC,IAAAC,qBAAwB;;;ACDxB,oBAAkC;AAClC,sBAAqB;AACrB,IAAAC,iBAAmB;AACnB,uBAAsB;AACtB,8BAA4B;AAG5B,IAAO,kBAAQ,iBAAAC;;;ACPR,SAAS,YAAY,MAA0B,MAAM,KAAa;AACvE,MAAI,CAAC,KAAM,QAAO;AAClB,SAAO,KAAK,UAAU,MAAM,OAAO,GAAG,KAAK,UAAU,GAAG,GAAG,CAAC;AAC9D;AAEO,SAAS,WAAW,OAAmC;AAC5D,MAAI,CAAC,MAAO,QAAO;AACnB,MAAI,MAAM,UAAU,GAAG;AACrB,WAAO,GAAG,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,MAAM,MAAM,EAAE,CAAC;AAAA,EAClD;AACA,SAAO,GAAG,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,MAAM,MAAM,EAAE,CAAC;AAClD;AAEO,SAAS,iBAAiB,QAAwB;AACvD,MAAI;AACF,UAAM,MAAM,IAAI,IAAI,MAAM;AAC1B,eAAW,OAAO,CAAC,UAAU,SAAS,cAAc,GAAG;AACrD,YAAM,QAAQ,IAAI,aAAa,IAAI,GAAG;AACtC,UAAI,OAAO;AACT,YAAI,aAAa,IAAI,KAAK,WAAW,KAAK,CAAC;AAAA,MAC7C;AAAA,IACF;AACA,WAAO,IAAI,SAAS;AAAA,EACtB,QAAQ;AACN,WAAO,OAAO;AAAA,MACZ;AAAA,MACA,CAAC,QAAQ,QAAgB,UAAkB;AACzC,YAAI,UAAU;AACd,YAAI;AACF,oBAAU,mBAAmB,KAAK;AAAA,QACpC,QAAQ;AAAA,QAER;AACA,eAAO,GAAG,MAAM,GAAG,WAAW,OAAO,CAAC;AAAA,MACxC;AAAA,IACF;AAAA,EACF;AACF;AAEO,SAAS,gBACd,SACA,KACoB;AACpB,MAAI,CAAC,QAAS,QAAO;AACrB,QAAM,WAAW,IAAI,YAAY;AACjC,aAAW,CAAC,WAAW,WAAW,KAAK,OAAO,QAAQ,OAAO,GAAG;AAC9D,QAAI,UAAU,YAAY,MAAM,UAAU;AACxC,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,wBAAwB,SAAqD;AAC3F,QAAM,cAAc,gBAAgB,SAAS,cAAc;AAC3D,QAAM,YAAY,gBAAgB,SAAS,cAAc;AACzD,QAAM,QAAkB,CAAC;AACzB,MAAI,aAAa;AACf,UAAM,KAAK,eAAe,WAAW,EAAE;AAAA,EACzC;AACA,MAAI,WAAW;AACb,UAAM,KAAK,cAAc,YAAY,WAAW,GAAG,CAAC,EAAE;AAAA,EACxD;AACA,SAAO,MAAM,SAAS,KAAK,MAAM,KAAK,IAAI,CAAC,KAAK;AAClD;;;AF1DA,SAASC,aAAY,MAAc,MAAM,KAAa;AACpD,SAAO,KAAK,UAAU,MAAM,OAAO,GAAG,KAAK,UAAU,GAAG,GAAG,CAAC;AAC9D;AAGA,IAAM,uBAAuB;AAE7B,IAAM,sBAAsB;AAE5B,IAAM,+BAA+B;AAmC9B,IAAM,cAAN,MAAkB;AAAA,EAavB,YAA6B,MAA0B;AAA1B;AAAA,EAA2B;AAAA,EAZhD,KAAuB;AAAA,EACvB,iBAAwD;AAAA,EACxD,mBAAmB;AAAA,EACnB,iBAAuD;AAAA,EACvD,WAA6B,CAAC;AAAA,EAC9B,oBAAwC,CAAC;AAAA,EACzC,UAAU;AAAA,EACV,gBAAgB;AAAA,EAChB,cAAoC;AAAA,EACpC,uBAAsC;AAAA,EACtC,2BAA2B;AAAA;AAAA,EAK3B,YACN,OACA,sBACM;AACN,QAAI,CAAC,KAAK,KAAK,eAAgB;AAC/B,UAAM,OAAyB;AAAA,MAC7B;AAAA,MACA,QAAO,oBAAI,KAAK,GAAE,YAAY;AAAA,MAC9B,kBAAkB,KAAK;AAAA,MACvB;AAAA,IACF;AACA,QAAI;AACF,0CAAU,4BAAQ,KAAK,KAAK,cAAc,GAAG,EAAE,WAAW,KAAK,CAAC;AAChE,0CAAc,KAAK,KAAK,gBAAgB,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC;AAAA,IACvE,QAAQ;AAAA,IAER;AAAA,EACF;AAAA;AAAA,EAGA,UAAU,SAA+B;AACvC,SAAK,SAAS,KAAK,OAAO;AAAA,EAC5B;AAAA;AAAA,EAGA,YAAY,SAAiC;AAC3C,SAAK,kBAAkB,KAAK,OAAO;AAAA,EACrC;AAAA;AAAA,EAGA,cAAuB;AACrB,WAAO,KAAK,IAAI,eAAe,gBAAU;AAAA,EAC3C;AAAA;AAAA,EAGA,MAAM,KAAK,SAAS,mBAAkC;AACpD,QAAI,KAAK,aAAa;AACpB,aAAO,KAAK;AAAA,IACd;AAEA,SAAK,UAAU;AACf,SAAK,YAAY,SAAS;AAC1B,SAAK,cAAc;AACnB,QAAI,KAAK,gBAAgB;AACvB,mBAAa,KAAK,cAAc;AAChC,WAAK,iBAAiB;AAAA,IACxB;AAEA,UAAM,KAAK,KAAK;AAChB,SAAK,KAAK;AACV,QAAI,CAAC,IAAI;AACP;AAAA,IACF;AAEA,SAAK,KAAK,OAAO;AAAA,MACf,6CAA6C,GAAG,UAAU,YAAY,MAAM;AAAA,IAC9E;AAEA,QACE,GAAG,eAAe,gBAAU,UAC5B,GAAG,eAAe,gBAAU,SAC5B;AACA;AAAA,IACF;AAEA,QAAI,GAAG,eAAe,gBAAU,MAAM;AACpC,UAAI;AACF,WAAG,UAAU;AAAA,MACf,QAAQ;AAAA,MAER;AACA;AAAA,IACF;AAEA,SAAK,cAAc,IAAI,QAAc,CAAC,YAAY;AAChD,UAAI,WAAW;AACf,UAAI,gBAAsD;AAE1D,YAAM,SAAS,MAAM;AACnB,YAAI,SAAU;AACd,mBAAW;AACX,YAAI,eAAe;AACjB,uBAAa,aAAa;AAC1B,0BAAgB;AAAA,QAClB;AACA,WAAG,IAAI,SAAS,WAAW;AAC3B,WAAG,IAAI,SAAS,WAAW;AAC3B,aAAK,cAAc;AACnB,gBAAQ;AAAA,MACV;AAEA,YAAM,cAAc,MAAM,OAAO;AACjC,YAAM,cAAc,MAAM,OAAO;AAEjC,SAAG,KAAK,SAAS,WAAW;AAC5B,SAAG,KAAK,SAAS,WAAW;AAE5B,sBAAgB,WAAW,MAAM;AAC/B,aAAK,KAAK,OAAO;AAAA,UACf;AAAA,QACF;AACA,YAAI;AACF,aAAG,UAAU;AAAA,QACf,QAAQ;AAAA,QAER;AACA,eAAO;AAAA,MACT,GAAG,IAAI;AAEP,UAAI;AACF,WAAG,MAAM,KAAM,MAAM;AAAA,MACvB,QAAQ;AACN,eAAO;AAAA,MACT;AAAA,IACF,CAAC;AAED,UAAM,KAAK;AAAA,EACb;AAAA;AAAA,EAGA,KAAK,OAA4B;AAC/B,QAAI,KAAK,IAAI,eAAe,gBAAU,MAAM;AAC1C,YAAM,UAAU,KAAK,UAAU,KAAK;AACpC,WAAK,KAAK,OAAO;AAAA,QACf,wCAAmC,MAAM,IAAI,QAAQ,QAAQ,QAAQ,MAAM,KAAK,KAAK,KAAK,QAAQ,MAAM;AAAA,MAC1G;AACA,WAAK,GAAG,KAAK,OAAO;AAAA,IACtB,OAAO;AACL,WAAK,eAAe,QAAQ,cAAc,MAAM,IAAI,EAAE;AAAA,IACxD;AAAA,EACF;AAAA;AAAA,EAGA,QAAQ,MAAoB;AAC1B,QAAI,KAAK,IAAI,eAAe,gBAAU,MAAM;AAC1C,WAAK,KAAK,OAAO;AAAA,QACf,iCAA4B,KAAK,MAAM,YAAY,KAAK,UAAU,MAAM,OAAO,KAAK,UAAU,GAAG,GAAG,IAAI,QAAG;AAAA,MAC7G;AACA,WAAK,GAAG,KAAK,IAAI;AAAA,IACnB,OAAO;AACL,WAAK,eAAe,SAAS;AAAA,IAC/B;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,yBAAyB,aAA0C;AACvE,QAAI,aAAa;AACf,kBAAY;AAAA,QACV;AAAA,QACA,MAAM;AACJ,eAAK,KAAK,KAAK;AAAA,QACjB;AAAA,QACA,EAAE,MAAM,KAAK;AAAA,MACf;AAAA,IACF;AAEA,UAAM,KAAK,QAAQ;AAGnB,WAAO,IAAI,QAAc,CAAC,YAAY;AACpC,UAAI,aAAa;AACf,oBAAY,iBAAiB,SAAS,MAAM,QAAQ,GAAG,EAAE,MAAM,KAAK,CAAC;AAAA,MACvE;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,MAAc,UAAyB;AACrC,QAAI,KAAK,QAAS;AAGlB,SAAK,QAAQ,IAAI;AAEjB,UAAM,YAAY,KAAK,KAAK,OAAO,WAAW,SAAS,IACnD,KAAK,KAAK,OAAO,MAAM,UAAU,MAAM,IACvC,KAAK,KAAK;AAEd,SAAK,KAAK,OAAO;AAAA,MACf,+BAA+B,iBAAiB,KAAK,KAAK,SAAS,CAAC,aAAa,KAAK,gBAAgB,eAAe,KAAK,KAAK,YAAY,aAAa,WAAW,SAAS,CAAC;AAAA,IAC/K;AACA,SAAK,YAAY,YAAY;AAE7B,WAAO,IAAI,QAAc,CAAC,YAAY;AACpC,UAAI,UAAU;AACd,YAAM,SAAS,MAAM;AACnB,YAAI,CAAC,SAAS;AACZ,oBAAU;AACV,kBAAQ;AAAA,QACV;AAAA,MACF;AAEA,YAAM,QAAQ,IAAI,IAAI,KAAK,KAAK,SAAS;AAEzC,UAAI,CAAC,MAAM,aAAa,IAAI,QAAQ,GAAG;AACrC,cAAM,aAAa,IAAI,UAAU,SAAS;AAAA,MAC5C;AAEA,YAAM,KAAK,IAAI,gBAAU,MAAM,SAAS,GAAG;AAAA,QACzC,SAAS;AAAA,UACP,gBAAgB;AAAA,QAClB;AAAA;AAAA,QAEA,kBAAkB;AAAA,MACpB,CAAC;AAED,WAAK,KAAK;AAGV,UAAI,kBAAwD,WAAW,MAAM;AAC3E,0BAAkB;AAClB,YAAI,KAAK,OAAO,MAAM,GAAG,eAAe,gBAAU,MAAM;AACtD;AAAA,QACF;AACA,aAAK,KAAK,OAAO;AAAA,UACf,oDAAoD,GAAG,UAAU,aAAa,KAAK,gBAAgB;AAAA,QACrG;AACA,YAAI;AACF,aAAG,UAAU;AAAA,QACf,QAAQ;AAAA,QAER;AAEA,YAAI,KAAK,OAAO,IAAI;AAClB,qBAAW,MAAM;AACf,gBAAI,KAAK,OAAO,IAAI;AAClB,mBAAK,KAAK,OAAO;AAAA,gBACf;AAAA,cACF;AACA,mBAAK,cAAc;AACnB,mBAAK,KAAK;AACV,mBAAK,YAAY,gBAAgB,gBAAgB;AACjD,mBAAK,kBAAkB;AACvB,qBAAO;AAAA,YACT;AAAA,UACF,GAAG,GAAI;AAAA,QACT;AAAA,MACF,GAAG,mBAAmB;AAEtB,YAAM,uBAAuB,MAAM;AACjC,YAAI,iBAAiB;AACnB,uBAAa,eAAe;AAC5B,4BAAkB;AAAA,QACpB;AAAA,MACF;AAEA,SAAG,GAAG,QAAQ,MAAM;AAClB,6BAAqB;AACrB,YAAI,KAAK,WAAW,KAAK,OAAO,IAAI;AAClC,eAAK,KAAK,OAAO;AAAA,YACf,wCAAwC,KAAK,OAAO,WAAW,KAAK,OAAO,EAAE;AAAA,UAC/E;AACA,cAAI;AACF,eAAG,UAAU;AAAA,UACf,QAAQ;AAAA,UAER;AACA,iBAAO;AACP;AAAA,QACF;AACA,aAAK,mBAAmB;AACxB,aAAK,gBAAgB,KAAK,IAAI;AAC9B,aAAK,eAAe;AACpB,aAAK,KAAK,OAAO,KAAK,mDAA8C;AACpE,aAAK,YAAY,WAAW;AAC5B,aAAK,cAAc;AACnB,eAAO;AAAA,MACT,CAAC;AAED,SAAG,GAAG,QAAQ,MAAM;AAClB,YAAI,KAAK,OAAO,IAAI;AAClB,eAAK,KAAK,OAAO,KAAK,oCAA+B;AACrD,eAAK,oBAAoB;AAAA,QAC3B;AAAA,MACF,CAAC;AAED,SAAG,GAAG,WAAW,CAAC,SAA4B;AAC5C,YAAI,KAAK,OAAO,IAAI;AAClB;AAAA,QACF;AACA,aAAK,cAAc,IAAI;AAAA,MACzB,CAAC;AAED,SAAG,GAAG,SAAS,CAAC,MAAc,WAAmB;AAC/C,6BAAqB;AACrB,cAAM,YAAY,OAAO,SAAS;AAClC,cAAM,mBAAmB,KAAK,gBAC1B,KAAK,IAAI,IAAI,KAAK,gBAClB;AACJ,cAAM,kBAAkB,KAAK,OAAO;AACpC,cAAM,aACJ,oCAAoC,IAAI,YAAYA,aAAY,WAAW,GAAG,CAAC,sBAAsB,oBAAoB,KAAK,sBAAsB,KAAK,gBAAgB;AAC3K,YAAI,KAAK,WAAW,CAAC,iBAAiB;AACpC,eAAK,KAAK,OAAO,KAAK,UAAU;AAAA,QAClC,OAAO;AACL,eAAK,KAAK,OAAO,KAAK,UAAU;AAAA,QAClC;AACA,YAAI,iBAAiB;AACnB,eAAK,cAAc;AACnB,eAAK,KAAK;AACV,eAAK,YAAY,gBAAgB,QAAQ,IAAI,YAAY,SAAS,EAAE;AACpE,eAAK,kBAAkB;AAAA,QACzB;AACA,eAAO;AAAA,MACT,CAAC;AAED,SAAG,GAAG,SAAS,CAACC,SAAe;AAC7B,6BAAqB;AACrB,aAAK,KAAK,OAAO;AAAA,UACf,kCAAkCA,KAAI,OAAO,gBAAgB,GAAG,UAAU,sBAAsB,KAAK,gBAAgB,SAAS,iBAAiB,MAAM,SAAS,CAAC,CAAC;AAAA,QAClK;AAGA,YAAI,KAAK,OAAO,IAAI;AAClB,eAAK,yBAAyB,IAAI,UAAUA,KAAI,OAAO,EAAE;AAAA,QAC3D;AACA,eAAO;AAAA,MACT,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA,EAEQ,gBAAsB;AAC5B,eAAW,WAAW,KAAK,mBAAmB;AAC5C,cAAQ,QAAQ,QAAQ,CAAC,EAAE,MAAM,CAACA,SAAQ;AACxC,aAAK,KAAK,OAAO;AAAA,UACf,6CAA6CA,gBAAe,QAAQA,KAAI,UAAU,OAAOA,IAAG,CAAC;AAAA,QAC/F;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEQ,cAAc,MAA+B;AACnD,UAAM,OACJ,OAAO,SAAS,WACZ,OACA,OAAO,SAAS,IAAI,IAClB,KAAK,SAAS,IACd,OAAO,IAAI;AAEnB,SAAK,oBAAoB;AAGzB,QAAI,SAAS,QAAQ;AACnB;AAAA,IACF;AAEA,SAAK,KAAK,OAAO;AAAA,MACf,0CAAqC,KAAK,MAAM,YAAYD,aAAY,IAAI,CAAC;AAAA,IAC/E;AAEA,QAAI;AACJ,QAAI;AACF,cAAQ,KAAK,MAAM,IAAI;AAAA,IACzB,QAAQ;AACN,WAAK,KAAK,OAAO;AAAA,QACf,2DAA2DA,aAAY,MAAM,GAAG,CAAC;AAAA,MACnF;AACA;AAAA,IACF;AAEA,SAAK,KAAK,OAAO,KAAK,mCAAmC,MAAM,IAAI,QAAQ,QAAQ,QAAQ,MAAM,KAAK,KAAK,EAAE;AAE7G,eAAW,WAAW,KAAK,UAAU;AACnC,UAAI;AACF,cAAM,SAAS,QAAQ,KAAK;AAC5B,YAAI,kBAAkB,SAAS;AAC7B,iBAAO,MAAM,CAACC,SAAQ;AACpB,iBAAK,KAAK,OAAO,MAAM,gCAAgCA,IAAG,EAAE;AAAA,UAC9D,CAAC;AAAA,QACH;AAAA,MACF,SAASA,MAAK;AACZ,aAAK,KAAK,OAAO,MAAM,gCAAgCA,IAAG,EAAE;AAAA,MAC9D;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,iBAAuB;AAC7B,SAAK,cAAc;AACnB,UAAM,aAAa,KAAK,KAAK,eAAe;AAC5C,SAAK,cAAc;AACnB,SAAK,iBAAiB,YAAY,MAAM;AACtC,WAAK,cAAc;AAAA,IACrB,GAAG,UAAU;AAAA,EACf;AAAA,EAEQ,gBAAsB;AAC5B,QAAI,KAAK,gBAAgB;AACvB,oBAAc,KAAK,cAAc;AACjC,WAAK,iBAAiB;AAAA,IACxB;AAAA,EACF;AAAA,EAEQ,wBAAgC;AACtC,WAAO,KAAK,KAAK,eAAe,IAAI;AAAA,EACtC;AAAA,EAEQ,gBAAsB;AAC5B,UAAM,KAAK,KAAK;AAChB,QAAI,IAAI,eAAe,gBAAU,MAAM;AACrC;AAAA,IACF;AAEA,UAAM,SAAS,KAAK,IAAI,IAAI,KAAK;AACjC,UAAM,YAAY,KAAK,sBAAsB;AAC7C,QAAI,UAAU,WAAW;AACvB,WAAK,KAAK,OAAO;AAAA,QACf,4DAA4D,MAAM,iBAAiB,SAAS;AAAA,MAC9F;AACA,WAAK,yBAAyB,IAAI,4BAA4B,MAAM,EAAE;AACtE;AAAA,IACF;AAEA,SAAK,KAAK,OAAO,KAAK,uCAAkC;AACxD,QAAI;AACF,SAAG,KAAK,MAAM;AAAA,IAChB,QAAQ;AAAA,IAER;AACA,QAAI;AACF,SAAG,KAAK;AAAA,IACV,QAAQ;AAAA,IAER;AAAA,EACF;AAAA,EAEQ,sBAA4B;AAClC,SAAK,gBAAgB,KAAK,IAAI;AAAA,EAChC;AAAA,EAEQ,QAAQ,QAAQ,OAAa;AACnC,SAAK,KAAK,OAAO;AAAA,MACf,6BAA6B,KAAK,KAAK,SAAS,MAAM,eAAe,CAAC,CAAC,KAAK,cAAc,eAAe,CAAC,CAAC,KAAK,cAAc;AAAA,IAChI;AACA,SAAK,cAAc;AACnB,QAAI,KAAK,gBAAgB;AACvB,mBAAa,KAAK,cAAc;AAChC,WAAK,iBAAiB;AAAA,IACxB;AACA,QAAI,KAAK,IAAI;AACX,UAAI;AACF,YAAI,OAAO;AACT,eAAK,GAAG,UAAU;AAAA,QACpB,OAAO;AACL,eAAK,GAAG,MAAM;AAAA,QAChB;AAAA,MACF,QAAQ;AAAA,MAER;AACA,WAAK,KAAK;AAAA,IACZ;AAAA,EACF;AAAA,EAEQ,yBAAyB,IAAe,QAAsB;AACpE,QAAI,KAAK,WAAW,KAAK,OAAO,GAAI;AAEpC,SAAK,cAAc;AACnB,SAAK,KAAK;AACV,SAAK,YAAY,gBAAgB,MAAM;AACvC,SAAK,kBAAkB;AAEvB,QAAI;AACF,UAAI,GAAG,eAAe,gBAAU,QAAQ;AACtC,WAAG,UAAU;AAAA,MACf;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAAA,EAEQ,eAAe,MAA0B,QAAuB;AACtE,UAAM,MAAM,KAAK,IAAI;AACrB,UAAM,YACJ,KAAK,yBAAyB,QAC9B,MAAM,KAAK,wBAAwB;AAErC,QAAI,CAAC,WAAW;AACd,WAAK;AACL;AAAA,IACF;AAEA,UAAM,mBACJ,KAAK,2BAA2B,IAC5B,gBAAgB,KAAK,wBAAwB,KAC7C;AACN,UAAM,eAAe,SAAS,KAAK,MAAM,KAAK;AAC9C,SAAK,KAAK,OAAO;AAAA,MACf,wBAAmB,IAAI,qCAAqC,KAAK,IAAI,cAAc,MAAM,GAAG,YAAY,GAAG,gBAAgB;AAAA,IAC7H;AACA,SAAK,uBAAuB;AAC5B,SAAK,2BAA2B;AAAA,EAClC;AAAA,EAEQ,oBAA0B;AAChC,QAAI,KAAK,QAAS;AAIlB,QAAI,KAAK,gBAAgB;AACvB;AAAA,IACF;AAEA,UAAM,SAAS,KAAK,KAAK;AACzB,UAAM,UAAU,KAAK;AAAA,MACnB,SAAS,KAAK,IAAI,GAAG,KAAK,gBAAgB;AAAA,MAC1C;AAAA,IACF;AACA,SAAK;AAEL,SAAK,KAAK,OAAO;AAAA,MACf,iCAAiC,OAAO,eAAe,KAAK,gBAAgB;AAAA,IAC9E;AAEA,SAAK,iBAAiB,WAAW,MAAM;AACrC,WAAK,iBAAiB;AACtB,UAAI,CAAC,KAAK,SAAS;AACjB,aAAK,QAAQ,EAAE,MAAM,CAACA,SAAQ;AAC5B,eAAK,KAAK,OAAO,MAAM,mCAAmCA,IAAG,EAAE;AAAA,QACjE,CAAC;AAAA,MACH;AAAA,IACF,GAAG,OAAO;AAAA,EACZ;AACF;;;AGzkBA,IAAAC,sBAA2B;AAK3B;;;ACLA,IAAAC,sBAAmB;AACnB,IAAAC,mBAAe;AACf,IAAAC,qBAAiB;AACjB;AAyBA,IAAM,sBAAsB,OAAO,KAAK,4BAA4B,KAAK;AAElE,SAAS,gBAAgB,KAAqB;AACnD,SAAO,IACJ,SAAS,QAAQ,EACjB,WAAW,KAAK,GAAG,EACnB,WAAW,KAAK,GAAG,EACnB,QAAQ,QAAQ,EAAE;AACvB;AAEO,SAAS,mBAAmB,cAA8B;AAC/D,QAAM,OAAO,oBAAAC,QAAO,gBAAgB,YAAY,EAAE,OAAO;AAAA,IACvD,MAAM;AAAA,IACN,QAAQ;AAAA,EACV,CAAC;AACD,MACE,KAAK,WAAW,oBAAoB,SAAS,MAC7C,KAAK,SAAS,GAAG,oBAAoB,MAAM,EAAE,OAAO,mBAAmB;AAEvE,WAAO,KAAK,SAAS,oBAAoB,MAAM;AACjD,SAAO;AACT;AAEO,SAAS,qBAAqB,cAA8B;AACjE,QAAM,MAAM,mBAAmB,YAAY;AAC3C,SAAO,oBAAAA,QAAO,WAAW,QAAQ,EAAE,OAAO,GAAG,EAAE,OAAO,KAAK;AAC7D;AAEO,SAAS,6BAA6B,cAA8B;AACzE,SAAO,gBAAgB,mBAAmB,YAAY,CAAC;AACzD;AAEO,SAAS,kBAAkB,eAAuB,SAAyB;AAChF,QAAM,MAAM,oBAAAA,QAAO,iBAAiB,aAAa;AACjD,SAAO,gBAAgB,oBAAAA,QAAO,KAAK,MAAM,OAAO,KAAK,SAAS,MAAM,GAAG,GAAG,CAAC;AAC7E;AAEO,SAAS,uBAAuB,QAS5B;AACT,QAAM,SAAS,OAAO,OAAO,KAAK,GAAG;AACrC,QAAM,QAAQ,OAAO,SAAS;AAC9B,SAAO;AAAA,IACL;AAAA,IACA,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP;AAAA,IACA,OAAO,OAAO,UAAU;AAAA,IACxB;AAAA,IACA,OAAO;AAAA,EACT,EAAE,KAAK,GAAG;AACZ;AAIO,SAAS,sBAAsB,UAAsC;AAC1E,SAAO,YAAY,gBAAoB;AACzC;AAEA,SAAS,UAAU,UAAwB;AACzC,mBAAAC,QAAG,UAAU,mBAAAC,QAAK,QAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;AAC1D;AAEA,SAAS,oBAAoB,UAA0B;AACrD,SAAO,mBAAAA,QAAK,KAAK,UAAU,YAAY,aAAa;AACtD;AAEA,SAAS,wBAAwB,MAAsB;AACrD,SAAO,KAAK,KAAK;AACnB;AAEA,SAAS,0BAA0B,QAA4B;AAC7D,QAAM,MAAM,oBAAI,IAAY;AAC5B,aAAW,SAAS,QAAQ;AAC1B,UAAM,UAAU,MAAM,KAAK;AAC3B,QAAI,SAAS;AACX,UAAI,IAAI,OAAO;AAAA,IACjB;AAAA,EACF;AACA,SAAO,CAAC,GAAG,GAAG,EAAE,KAAK;AACvB;AAEA,SAAS,sBAAsB,UAA0B;AACvD,SAAO,mBAAAA,QAAK,KAAK,UAAU,YAAY,kBAAkB;AAC3D;AAEA,SAAS,oBAAoB,UAA0C;AACrE,MAAI;AACF,QAAI,CAAC,iBAAAD,QAAG,WAAW,QAAQ,EAAG,QAAO;AACrC,UAAM,MAAM,iBAAAA,QAAG,aAAa,UAAU,MAAM;AAC5C,UAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,QAAI,QAAQ,YAAY,KAAK,OAAO,OAAO,aAAa,SAAU,QAAO;AACzE,QAAI,CAAC,OAAO,UAAU,OAAO,OAAO,WAAW,SAAU,QAAO;AAChE,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,qBAAqB,UAAkB,OAA8B;AAC5E,YAAU,QAAQ;AAClB,mBAAAA,QAAG,cAAc,UAAU,GAAG,KAAK,UAAU,OAAO,MAAM,CAAC,CAAC;AAAA,GAAM;AAAA,IAChE,MAAM;AAAA,EACR,CAAC;AACD,MAAI;AACF,qBAAAA,QAAG,UAAU,UAAU,GAAK;AAAA,EAC9B,QAAQ;AAAA,EAER;AACF;AAIO,SAAS,oBAAoB,QAIT;AACzB,QAAM,QAAQ,oBAAoB,sBAAsB,OAAO,QAAQ,CAAC;AACxE,MAAI,CAAC,SAAS,MAAM,aAAa,OAAO,SAAU,QAAO;AACzD,QAAM,QAAQ,MAAM,OAAO,wBAAwB,OAAO,IAAI,CAAC;AAC/D,MAAI,CAAC,SAAS,OAAO,MAAM,UAAU,SAAU,QAAO;AACtD,SAAO;AACT;AAEO,SAAS,qBAAqB,QAMjB;AAClB,QAAM,WAAW,sBAAsB,OAAO,QAAQ;AACtD,QAAM,WAAW,oBAAoB,QAAQ;AAC7C,QAAM,OAAO,wBAAwB,OAAO,IAAI;AAChD,QAAM,OAAwB;AAAA,IAC5B,SAAS;AAAA,IACT,UAAU,OAAO;AAAA,IACjB,QACE,YAAY,SAAS,aAAa,OAAO,YAAY,SAAS,SAC1D,EAAE,GAAG,SAAS,OAAO,IACrB,CAAC;AAAA,EACT;AACA,QAAM,QAAyB;AAAA,IAC7B,OAAO,OAAO;AAAA,IACd;AAAA,IACA,QAAQ,0BAA0B,OAAO,MAAM;AAAA,IAC/C,aAAa,KAAK,IAAI;AAAA,EACxB;AACA,OAAK,OAAO,IAAI,IAAI;AACpB,uBAAqB,UAAU,IAAI;AACnC,SAAO;AACT;AAEO,SAAS,qBAAqB,QAI5B;AACP,QAAM,WAAW,sBAAsB,OAAO,QAAQ;AACtD,QAAM,QAAQ,oBAAoB,QAAQ;AAC1C,MAAI,CAAC,SAAS,MAAM,aAAa,OAAO,SAAU;AAClD,QAAM,OAAO,wBAAwB,OAAO,IAAI;AAChD,MAAI,CAAC,MAAM,OAAO,IAAI,EAAG;AACzB,QAAM,OAAwB;AAAA,IAC5B,SAAS;AAAA,IACT,UAAU,MAAM;AAAA,IAChB,QAAQ,EAAE,GAAG,MAAM,OAAO;AAAA,EAC5B;AACA,SAAO,KAAK,OAAO,IAAI;AACvB,uBAAqB,UAAU,IAAI;AACrC;AAIO,SAAS,2BAA2B,UAAkC;AAC3E,QAAM,WAAW,oBAAoB,QAAQ;AAC7C,MAAI;AACF,QAAI,iBAAAA,QAAG,WAAW,QAAQ,GAAG;AAC3B,YAAM,MAAM,iBAAAA,QAAG,aAAa,UAAU,MAAM;AAC5C,YAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,UACE,QAAQ,YAAY,KACpB,OAAO,OAAO,aAAa,YAC3B,OAAO,OAAO,iBAAiB,YAC/B,OAAO,OAAO,kBAAkB,UAChC;AACA,cAAM,YAAY,qBAAqB,OAAO,YAAY;AAC1D,eAAO;AAAA,UACL,UAAU;AAAA,UACV,cAAc,OAAO;AAAA,UACrB,eAAe,OAAO;AAAA,QACxB;AAAA,MACF;AAAA,IACF;AAAA,EACF,QAAQ;AAAA,EAER;AAEA,QAAM,EAAE,WAAW,WAAW,IAAI,oBAAAD,QAAO,oBAAoB,SAAS;AACtE,QAAM,eAAe,UAClB,OAAO,EAAE,MAAM,QAAQ,QAAQ,MAAM,CAAC,EACtC,SAAS;AACZ,QAAM,gBAAgB,WACnB,OAAO,EAAE,MAAM,SAAS,QAAQ,MAAM,CAAC,EACvC,SAAS;AACZ,QAAM,WAA2B;AAAA,IAC/B,UAAU,qBAAqB,YAAY;AAAA,IAC3C;AAAA,IACA;AAAA,EACF;AACA,mBAAAC,QAAG,UAAU,mBAAAC,QAAK,QAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;AACxD,QAAM,SAAS;AAAA,IACb,SAAS;AAAA,IACT,GAAG;AAAA,IACH,aAAa,KAAK,IAAI;AAAA,EACxB;AACA,YAAU,QAAQ;AAClB,mBAAAD,QAAG,cAAc,UAAU,GAAG,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAAA,GAAM;AAAA,IACjE,MAAM;AAAA,EACR,CAAC;AACD,SAAO;AACT;;;AC/PO,IAAM,6BAA6B;AAiB1C,IAAM,WAAmC;AAAA,EACvC,mCAAmC;AACrC;AAEO,SAAS,QAAQ,GAAmB;AACzC,SAAO,SAAS,CAAC,KAAK;AACxB;AAIA,SAAS,0BAA0B,MAErB;AACZ,QAAM,QAAQ,KAAK,cAAc,KAAK,KAAK;AAC3C,QAAM,WAAW,KAAK,iBAAiB,KAAK,KAAK;AACjD,MAAI,CAAC,SAAS,CAAC,SAAU,QAAO;AAChC,SAAO,EAAE,OAAO,SAAS;AAC3B;AAEO,SAAS,8BACd,MACA,aAC2D;AAC3D,QAAM,OAAO,0BAA0B,IAAI;AAC3C,QAAM,WAAsE,CAAC;AAC7E,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,WAAW,KAAK;AAEtB,QAAM,aAAa,CAAC,MAA4B,WAA0B;AACxE,QAAI,CAAC,OAAQ;AAEb,UAAM,YAAY,GAAG,IAAI,IAAI,MAAM;AACnC,QAAI,KAAK,IAAI,SAAS,EAAG;AACzB,SAAK,IAAI,SAAS;AAElB,UAAM,UAAU,EAAE,GAAG,YAAY;AACjC,YAAQ,gBAAgB,UAAU,MAAM;AAExC,QAAI,SAAS,YAAY;AACvB,cAAQ,qBAAqB,IAAI;AAAA,IACnC,OAAO;AACL,aAAO,QAAQ,qBAAqB;AAAA,IACtC;AAEA,aAAS,KAAK;AAAA,MACZ,OAAO,SAAS,UAAU,kBAAkB;AAAA,MAC5C;AAAA,IACF,CAAC;AAAA,EACH;AAEA,MAAI,aAAa,YAAY;AAC3B,eAAW,YAAY,MAAM,QAAQ;AACrC,eAAW,SAAS,MAAM,KAAK;AAAA,EACjC,OAAO;AACL,eAAW,SAAS,MAAM,KAAK;AAC/B,eAAW,YAAY,MAAM,QAAQ;AAAA,EACvC;AAEA,MAAI,SAAS,WAAW,GAAG;AACzB,aAAS,KAAK;AAAA,MACZ,OAAO;AAAA,MACP,SAAS,EAAE,GAAG,YAAY;AAAA,IAC5B,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAIA,eAAsB,kBACpB,MACA,OACe;AACf,QAAM,aAAa,QAAQ,MAAM,IAAI;AACrC,QAAM,MAAM,IAAI,IAAI,YAAY,KAAK,cAAc;AACnD,QAAM,cAAc,KAAK,IAAI;AAG7B,QAAM,eAAuC,CAAC;AAC9C,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,MAAM,WAAW,CAAC,CAAC,GAAG;AACxD,UAAM,QAAQ,EAAE,YAAY;AAC5B,QAAI,UAAU,mBAAmB,UAAU,uBAAuB;AAChE,mBAAa,CAAC,IAAI;AAAA,IACpB;AAAA,EACF;AACA,eAAa,0BAA0B,IAAI;AAE3C,QAAM,eAAe,8BAA8B,MAAM,YAAY;AACrE,OAAK,OAAO;AAAA,IACV,wBAAwB,MAAM,EAAE,IAAI,MAAM,MAAM,IAAI,MAAM,IAAI,WAAM,IAAI,SAAS,CAAC,GAAG,wBAAwB,MAAM,OAAO,CAAC,kBAAkB,aAAa,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,MAAM,CAAC,UAAU,YAAY,MAAM,IAAI,CAAC;AAAA,EAC7N;AAEA,MAAI;AACF,aAAS,eAAe,GAAG,eAAe,aAAa,QAAQ,gBAAgB;AAC7E,YAAM,UAAU,aAAa,YAAY;AACzC,WAAK,OAAO;AAAA,QACV,wBAAwB,MAAM,EAAE,YAAY,eAAe,CAAC,IAAI,aAAa,MAAM,SAAS,QAAQ,KAAK;AAAA,MAC3G;AACA,YAAM,MAAM,MAAM,MAAM,IAAI,SAAS,GAAG;AAAA,QACtC,QAAQ,MAAM;AAAA,QACd,SAAS,QAAQ;AAAA,QACjB,MACE,MAAM,WAAW,SAAS,MAAM,WAAW,SACvC,MAAM,OACN;AAAA,MACR,CAAC;AAED,YAAM,cAAc,eAAe,aAAa,SAAS;AACzD,UAAI,IAAI,WAAW,OAAO,aAAa;AACrC,cAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,aAAK,OAAO;AAAA,UACV,wBAAwB,MAAM,EAAE,2BAA2B,QAAQ,KAAK,uBAAuB,KAAK,IAAI,IAAI,WAAW,+BAA+B,OAAO,UAAU,YAAY,IAAI,CAAC,KAAK,EAAE;AAAA,QACjM;AACA;AAAA,MACF;AAEA,YAAM,iBAAiB,MAAM;AAAA,QAC3B,SAAS,MAAM;AAAA,QACf,QAAQ,MAAM;AAAA,QACd,MAAM;AAAA,QACN,WAAW,QAAQ;AAAA,QACnB;AAAA,QACA;AAAA,MACF,CAAC;AACD;AAAA,IACF;AAAA,EACF,SAASE,MAAK;AACZ,UAAM,UAAUA,gBAAe,QAAQA,KAAI,UAAU,OAAOA,IAAG;AAC/D,SAAK,OAAO;AAAA,MACV,wBAAwB,MAAM,EAAE,IAAI,MAAM,MAAM,IAAI,UAAU,iBAAiB,KAAK,IAAI,IAAI,WAAW,OAAO,OAAO;AAAA,IACvH;AACA,SAAK,OAAO,KAAK;AAAA,MACf,MAAM;AAAA,MACN,IAAI,MAAM;AAAA,MACV,QAAQ;AAAA,MACR,SAAS,wBAAwB,OAAO;AAAA,IAC1C,CAAC;AAAA,EACH;AACF;AAIA,eAAe,iBACb,MACA,QAQe;AACf,QAAM,EAAE,SAAS,QAAQ,MAAAC,OAAM,WAAW,aAAa,IAAI,IAAI;AAC/D,QAAM,cAAc,IAAI,QAAQ,IAAI,cAAc,KAAK;AACvD,QAAM,cAAc,YAAY,SAAS,mBAAmB;AAC5D,QAAM,YAAY,KAAK,IAAI,IAAI;AAE/B,OAAK,OAAO;AAAA,IACV,wBAAwB,OAAO,IAAI,MAAM,IAAIA,KAAI,OAAO,IAAI,MAAM,KAAK,SAAS,YAAY,SAAS,kBAAkB,WAAW,eAAe,WAAW;AAAA,EAC9J;AAEA,MAAI,eAAe,IAAI,MAAM;AAC3B,UAAM,eAAe,MAAM,SAAS,KAAK,WAAW;AACpD;AAAA,EACF;AAEA,QAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,OAAK,OAAO;AAAA,IACV,wBAAwB,OAAO,kBAAkB,YAAY,IAAI,CAAC;AAAA,EACpE;AACA,QAAM,UAAkC,CAAC;AACzC,MAAI,QAAQ,QAAQ,CAAC,OAAO,QAAQ;AAClC,YAAQ,GAAG,IAAI;AAAA,EACjB,CAAC;AAED,OAAK,OAAO,KAAK;AAAA,IACf,MAAM;AAAA,IACN,IAAI;AAAA,IACJ,QAAQ,IAAI;AAAA,IACZ;AAAA,IACA;AAAA,EACF,CAAC;AACH;AAEA,eAAe,eACb,MACA,WACA,KACA,aACe;AACf,QAAM,SAAS,IAAI,KAAM,UAAU;AACnC,QAAM,UAAU,IAAI,YAAY;AAChC,MAAI,aAAa;AAEjB,OAAK,OAAO,KAAK,gCAAgC,SAAS,EAAE;AAE5D,MAAI;AACF,WAAO,MAAM;AACX,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,UAAI,KAAM;AAEV;AACA,YAAM,QAAQ,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;AACpD,WAAK,OAAO;AAAA,QACV,gCAAgC,SAAS,UAAU,UAAU,KAAK,MAAM,MAAM;AAAA,MAChF;AACA,WAAK,OAAO,KAAK;AAAA,QACf,MAAM;AAAA,QACN,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,MAAM;AAAA,MACR,CAAC;AAAA,IACH;AAEA,SAAK,OAAO;AAAA,MACV,8BAA8B,SAAS,kBAAkB,UAAU,oBAAoB,KAAK,IAAI,IAAI,WAAW;AAAA,IACjH;AACA,SAAK,OAAO,KAAK;AAAA,MACf,MAAM;AAAA,MACN,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,MAAM;AAAA,IACR,CAAC;AAAA,EACH,SAASD,MAAK;AACZ,SAAK,OAAO;AAAA,MACV,gCAAgC,SAAS,UAAU,UAAU,eAAe,KAAK,IAAI,IAAI,WAAW,OAAOA,gBAAe,QAAQA,KAAI,UAAU,OAAOA,IAAG,CAAC;AAAA,IAC7J;AACA,SAAK,OAAO,KAAK;AAAA,MACf,MAAM;AAAA,MACN,IAAI;AAAA,MACJ,QAAQ;AAAA,MACR,SAAS,iBAAiBA,gBAAe,QAAQA,KAAI,UAAU,OAAOA,IAAG,CAAC;AAAA,IAC5E,CAAC;AAAA,EACH;AACF;;;AClPO,IAAM,UAAN,MAAc;AAAA,EAInB,YAA6B,MAAsB;AAAtB;AAAA,EAAuB;AAAA;AAAA,EAF5C,cAAc,oBAAI,IAAuB;AAAA,EAIjD,IAAI,cAAsB;AACxB,WAAO,KAAK,YAAY;AAAA,EAC1B;AAAA,EAEA,UAAgB;AACd,eAAW,CAAC,IAAI,EAAE,KAAK,KAAK,aAAa;AACvC,WAAK,KAAK,OAAO,KAAK,0BAA0B,EAAE,EAAE;AACpD,UAAI;AACF,WAAG,MAAM;AAAA,MACX,QAAQ;AAAA,MAER;AAAA,IACF;AACA,SAAK,YAAY,MAAM;AAAA,EACzB;AAAA,EAEA,aAAa,OAA0B;AACrC,UAAM,QACJ,KAAK,KAAK,eAAe,QAAQ,SAAS,IAAI,IAC9C,QAAQ,MAAM,IAAI;AACpB,SAAK,KAAK,OAAO;AAAA,MACf,2BAA2B,MAAM,EAAE,UAAU,MAAM,IAAI,WAAM,KAAK;AAAA,IACpE;AAEA,QAAI;AACF,YAAM,KAAK,IAAI,gBAAU,OAAO;AAAA,QAC9B,SAAS,MAAM;AAAA,MACjB,CAAC;AAED,SAAG,GAAG,QAAQ,MAAM;AAClB,aAAK,YAAY,IAAI,MAAM,IAAI,EAAE;AACjC,aAAK,KAAK,OAAO;AAAA,UACf,sBAAsB,MAAM,EAAE,iCAAiC,KAAK,YAAY,IAAI;AAAA,QACtF;AACA,aAAK,KAAK,OAAO,KAAK;AAAA,UACpB,MAAM;AAAA,UACN,IAAI,MAAM;AAAA,QACZ,CAAC;AAAA,MACH,CAAC;AAED,SAAG,GAAG,WAAW,CAAC,SAA4B;AAC5C,cAAM,OACJ,OAAO,SAAS,WACZ,OACA,OAAO,SAAS,IAAI,IAClB,KAAK,SAAS,IACd,OAAO,IAAI;AAEnB,aAAK,KAAK,OAAO;AAAA,UACf,sBAAsB,MAAM,EAAE,yBAAoB,KAAK,MAAM,YAAY,KAAK,UAAU,GAAG,GAAG,CAAC;AAAA,QACjG;AACA,aAAK,KAAK,OAAO,KAAK;AAAA,UACpB,MAAM;AAAA,UACN,IAAI,MAAM;AAAA,UACV,MAAM;AAAA,QACR,CAAC;AAAA,MACH,CAAC;AAED,SAAG,GAAG,SAAS,CAAC,MAAc,WAAmB;AAC/C,aAAK,YAAY,OAAO,MAAM,EAAE;AAChC,aAAK,KAAK,OAAO;AAAA,UACf,sBAAsB,MAAM,EAAE,4BAA4B,IAAI,YAAY,OAAO,SAAS,CAAC,aAAa,KAAK,YAAY,IAAI;AAAA,QAC/H;AACA,aAAK,KAAK,OAAO,KAAK;AAAA,UACpB,MAAM;AAAA,UACN,IAAI,MAAM;AAAA,UACV;AAAA,UACA,QAAQ,OAAO,SAAS;AAAA,QAC1B,CAAC;AAAA,MACH,CAAC;AAED,SAAG,GAAG,SAAS,CAACE,SAAe;AAC7B,aAAK,KAAK,OAAO;AAAA,UACf,sBAAsB,MAAM,EAAE,WAAWA,KAAI,OAAO,YAAY,KAAK,YAAY,IAAI;AAAA,QACvF;AACA,aAAK,YAAY,OAAO,MAAM,EAAE;AAChC,aAAK,KAAK,OAAO,KAAK;AAAA,UACpB,MAAM;AAAA,UACN,IAAI,MAAM;AAAA,UACV,MAAM;AAAA,UACN,QAAQA,KAAI;AAAA,QACd,CAAC;AAAA,MACH,CAAC;AAAA,IACH,SAASA,MAAK;AACZ,WAAK,KAAK,OAAO;AAAA,QACf,sBAAsB,MAAM,EAAE,uBAAuBA,gBAAe,QAAQA,KAAI,UAAU,OAAOA,IAAG,CAAC;AAAA,MACvG;AACA,WAAK,KAAK,OAAO,KAAK;AAAA,QACpB,MAAM;AAAA,QACN,IAAI,MAAM;AAAA,QACV,MAAM;AAAA,QACN,QAAQ,sBAAsBA,gBAAe,QAAQA,KAAI,UAAU,OAAOA,IAAG,CAAC;AAAA,MAChF,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,aAAa,OAA0B;AACrC,UAAM,KAAK,KAAK,YAAY,IAAI,MAAM,EAAE;AACxC,QAAI,IAAI,eAAe,gBAAU,MAAM;AACrC,WAAK,KAAK,OAAO;AAAA,QACf,sBAAsB,MAAM,EAAE,yBAAoB,MAAM,KAAK,MAAM,YAAY,MAAM,KAAK,UAAU,GAAG,GAAG,CAAC;AAAA,MAC7G;AACA,SAAG,KAAK,MAAM,IAAI;AAAA,IACpB,OAAO;AACL,WAAK,KAAK,OAAO;AAAA,QACf,sBAAsB,MAAM,EAAE,sCAAsC,CAAC,CAAC,EAAE,gBAAgB,IAAI,cAAc,KAAK;AAAA,MACjH;AAAA,IACF;AAAA,EACF;AAAA,EAEA,cAAc,OAA2B;AACvC,UAAM,KAAK,KAAK,YAAY,IAAI,MAAM,EAAE;AACxC,QAAI,IAAI;AACN,WAAK,KAAK,OAAO;AAAA,QACf,sBAAsB,MAAM,EAAE,mCAAmC,MAAM,QAAQ,GAAI,YAAY,MAAM,UAAU,EAAE;AAAA,MACnH;AACA,WAAK,YAAY,OAAO,MAAM,EAAE;AAChC,UAAI;AACF,WAAG,MAAM,MAAM,QAAQ,KAAM,MAAM,UAAU,EAAE;AAAA,MACjD,QAAQ;AAAA,MAER;AAAA,IACF,OAAO;AACL,WAAK,KAAK,OAAO;AAAA,QACf,sBAAsB,MAAM,EAAE;AAAA,MAChC;AAAA,IACF;AAAA,EACF;AACF;;;AH/HO,IAAM,0CACX;AAoBF,IAAM,6BAA6B;AACnC,IAAM,iCAAiC;AAiBvC,IAAI,8BACF;AACF,IAAI,6BAA6B;AAEjC,SAAS,mBAAmBC,MAAsB;AAChD,MAAIA,gBAAe,SAASA,KAAI,QAAS,QAAOA,KAAI;AACpD,SAAO,OAAOA,IAAG;AACnB;AAEA,eAAe,yBACb,QACwC;AACxC,MAAI,CAAC,6BAA6B;AAChC,kCAA8B,OAAO,sCAAsC,EACxE;AAAA,MAAK,CAAC,QACL,OAAO,IAAI,yBAAyB,aAC/B,IAAI,uBACL;AAAA,IACN,EACC,MAAM,CAACA,SAAiB;AACvB,UAAI,CAAC,4BAA4B;AAC/B,qCAA6B;AAC7B,eAAO;AAAA,UACL,2HAA2H,mBAAmBA,IAAG,CAAC;AAAA,QACpJ;AAAA,MACF;AACA,aAAO;AAAA,IACT,CAAC;AAAA,EACL;AAEA,QAAM,uBAAuB,MAAM;AACnC,MAAI,CAAC,wBAAwB,CAAC,4BAA4B;AACxD,iCAA6B;AAC7B,WAAO;AAAA,MACL;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAMO,IAAM,cAAN,MAAkB;AAAA,EAwBvB,YAA6B,MAAoB;AAApB;AAC3B,SAAK,WAAW,sBAAsB,KAAK,QAAQ;AACnD,SAAK,eAAe,KAAK,gBAAgB,gBAAoB;AAC7D,SAAK,iBAAiB,2BAA2B,KAAK,QAAQ;AAC9D,SAAK,OAAO;AAAA,MACV,iDAAiD,KAAK,eAAe,QAAQ;AAAA,IAC/E;AACA,SAAK,UAAU,IAAI,QAAQ;AAAA,MACzB,gBAAgB,KAAK;AAAA,MACrB,QAAQ,KAAK;AAAA,MACb,QAAQ,KAAK;AAAA,IACf,CAAC;AAAA,EACH;AAAA;AAAA,EAlCQ,YAA8B;AAAA,EAC9B,sBAAsB;AAAA;AAAA,EAEtB,iBAAiB;AAAA;AAAA,EAEjB,8BAA8B;AAAA;AAAA,EAE9B,gCAAgC;AAAA;AAAA,EAEhC,mBAA6B,CAAC;AAAA;AAAA,EAE9B,qBAAqB,oBAAI,IAAmC;AAAA;AAAA,EAE5D,wBAAwB,oBAAI,IAAkC;AAAA;AAAA,EAG9D;AAAA,EAES;AAAA,EACA;AAAA,EACA;AAAA;AAAA;AAAA,EAmBjB,MAAM,YAAY,OAAoC;AACpD,SAAK,KAAK,OAAO;AAAA,MACf,oCAAoC,MAAM,IAAI,QAAQ,QAAQ,QAAQ,MAAM,KAAK,KAAK;AAAA,IACxF;AACA,YAAQ,MAAM,MAAM;AAAA,MAClB,KAAK;AACH,cAAM,kBAAkB,KAAK,MAAM,KAAK;AACxC;AAAA,MACF,KAAK;AACH,aAAK,eAAe,KAAK;AACzB;AAAA,MACF,KAAK;AACH,aAAK,QAAQ,aAAa,KAAK;AAC/B;AAAA,MACF,KAAK;AACH,aAAK,QAAQ,aAAa,KAAK;AAC/B;AAAA,MACF,KAAK;AACH,aAAK,QAAQ,cAAc,KAAK;AAChC;AAAA,MACF;AACE,aAAK,KAAK,OAAO;AAAA,UACf,oCAAqC,MAAc,IAAI,SAAS,QAAQ,QAAS,MAAc,KAAK,KAAK;AAAA,QAC3G;AAEA,aAAK,oBAAoB,KAAK,UAAU,KAAK,CAAC;AAC9C;AAAA,IACJ;AAAA,EACF;AAAA;AAAA,EAGA,UAAgB;AACd,SAAK,KAAK,OAAO;AAAA,MACf,iCAAiC,KAAK,QAAQ,WAAW,qCAAqC,CAAC,CAAC,KAAK,SAAS;AAAA,IAChH;AACA,SAAK,QAAQ,QAAQ;AAErB,QAAI,KAAK,WAAW;AAClB,UAAI;AACF,aAAK,UAAU,MAAM;AAAA,MACvB,QAAQ;AAAA,MAER;AACA,WAAK,YAAY;AAAA,IACnB;AACA,SAAK,iBAAiB;AACtB,SAAK,sBAAsB;AAC3B,SAAK,8BAA8B;AACnC,SAAK,gCAAgC;AACrC,SAAK,mBAAmB,CAAC;AACzB,SAAK,mBAAmB,MAAM;AAC9B,SAAK,sBAAsB,MAAM;AAAA,EACnC;AAAA;AAAA,EAIQ,mBAAmB,SAAiB,QAAsB;AAChE,SAAK,iBAAiB,KAAK,OAAO;AAClC,SAAK,KAAK,OAAO;AAAA,MACf,8CAA8C,KAAK,iBAAiB,MAAM,KAAK,MAAM;AAAA,IACvF;AAAA,EACF;AAAA;AAAA,EAGQ,oBAAoB,SAAuB;AACjD,SAAK,gBAAgB;AACrB,QAAI,KAAK,kBAAkB,KAAK,WAAW,eAAe,gBAAU,MAAM;AACxE,WAAK,UAAU,KAAK,OAAO;AAAA,IAC7B,OAAO;AACL,WAAK,mBAAmB,SAAS,0CAA0C;AAAA,IAC7E;AAAA,EACF;AAAA;AAAA,EAGQ,eAAe,OAAuB;AAC5C,UAAM,UAAU,KAAK,UAAU,KAAK;AACpC,SAAK,mBAAmB,IAAI,MAAM,IAAI;AAAA,MACpC,QAAQ,MAAM;AAAA,MACd,YAAY,KAAK,oBAAoB,MAAM,QAAQ,UAAU;AAAA,IAC/D,CAAC;AACD,SAAK,KAAK,OAAO;AAAA,MACf,uBAAuB,MAAM,EAAE,WAAW,MAAM,MAAM,uBAAkB,QAAQ,MAAM;AAAA,IACxF;AAEA,SAAK,gBAAgB;AAErB,QAAI,KAAK,kBAAkB,KAAK,WAAW,eAAe,gBAAU,MAAM;AACxE,WAAK,UAAU,KAAK,OAAO;AAAA,IAC7B,OAAO;AACL,WAAK,KAAK,OAAO;AAAA,QACf,uBAAuB,MAAM,EAAE;AAAA,MACjC;AACA,WAAK;AAAA,QACH;AAAA,QACA,UAAU,MAAM,EAAE;AAAA,MACpB;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAIQ,4BAEM;AACZ,UAAM,QAAQ,KAAK,KAAK,cAAc,KAAK,KAAK;AAChD,UAAM,WAAW,KAAK,KAAK,iBAAiB,KAAK,KAAK;AACtD,QAAI,CAAC,SAAS,CAAC,SAAU,QAAO;AAChC,WAAO,EAAE,OAAO,SAAS;AAAA,EAC3B;AAAA,EAEQ,sBAAsB,MAAkC;AAC9D,WACE,oBAAoB;AAAA,MAClB,UAAU,KAAK;AAAA,MACf,UAAU,KAAK,eAAe;AAAA,MAC9B;AAAA,IACF,CAAC,GAAG,SAAS;AAAA,EAEjB;AAAA,EAEQ,wBAAwB,MAK9B;AACA,UAAM,eAAe,KAAK,0BAA0B;AACpD,UAAM,eAAe,cAAc,UAAU,KAAK,KAAK;AACvD,UAAM,uBAAuB,cAAc,OAAO,KAAK,KAAK;AAC5D,UAAM,cAAc,uBAChB,SACA,KAAK,sBAAsB,IAAI;AACnC,UAAM,YAAY,wBAAwB;AAC1C,UAAM,OACJ,aAAa,gBAAgB,cACzB,EAAE,OAAO,WAAW,aAAa,UAAU,aAAa,IACxD;AACN,WAAO,EAAE,MAAM,WAAW,cAAc,YAAY;AAAA,EACtD;AAAA,EAEQ,uBAAuB,QAItB;AACP,UAAM,QAAQ,OAAO,UAAU;AAC/B,QAAI,OAAO,UAAU,YAAY,CAAC,MAAM,KAAK,EAAG;AAChD,UAAM,OACJ,OAAO,OAAO,UAAU,SAAS,YAAY,OAAO,SAAS,KAAK,KAAK,IACnE,OAAO,SAAS,KAAK,KAAK,IAC1B,OAAO;AACb,UAAM,SAAS,MAAM,QAAQ,OAAO,UAAU,MAAM,IAChD,OAAO,SAAS,OAAO;AAAA,MACrB,CAAC,UACC,OAAO,UAAU,YAAY,CAAC,CAAC,MAAM,KAAK;AAAA,IAC9C,IACA,OAAO;AACX,yBAAqB;AAAA,MACnB,UAAU,KAAK;AAAA,MACf,UAAU,KAAK,eAAe;AAAA,MAC9B;AAAA,MACA,OAAO,MAAM,KAAK;AAAA,MAClB;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEQ,sCAAsC,MAAc,QAAsB;AAChF,UAAM,eAAe,KAAK,0BAA0B;AACpD,QAAI,cAAc,SAAS,cAAc,SAAU;AACnD,QAAI,SAAS,QAAQ,CAAC,OAAO,YAAY,EAAE,SAAS,uBAAuB,EAAG;AAC9E,yBAAqB;AAAA,MACnB,UAAU,KAAK;AAAA,MACf,UAAU,KAAK,eAAe;AAAA,MAC9B,MAAM;AAAA,IACR,CAAC;AACD,SAAK,KAAK,OAAO;AAAA,MACf,mFAAmF,KAAK,eAAe,QAAQ;AAAA,IACjH;AAAA,EACF;AAAA,EAEA,MAAc,+BAA+B,OAA8B;AACzE,UAAM,YACJ,OAAO,OAAO,OAAO,SAAS,WAAW,MAAM,MAAM,OAAO;AAC9D,UAAM,cACJ,OAAO,OAAO,OAAO,SAAS,SAAS,WACnC,MAAM,MAAM,QAAQ,OACpB;AACN,QAAI,cAAc,gBAAgB,gBAAgB,oBAAoB;AACpE,aAAO;AAAA,IACT;AAEA,UAAM,YACJ,OAAO,OAAO,OAAO,SAAS,cAAc,WACxC,MAAM,MAAM,QAAQ,UAAU,KAAK,IACnC;AACN,UAAM,SACJ,OAAO,OAAO,OAAO,SAAS,WAAW,WACrC,MAAM,MAAM,QAAQ,OAAO,KAAK,IAChC;AAEN,QAAI,CAAC,WAAW;AACd,WAAK,KAAK,OAAO;AAAA,QACf;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAEA,QACE,UACA,WAAW,gBACX,WAAW,iBACX;AACA,WAAK,KAAK,OAAO;AAAA,QACf,iEAAiE,MAAM;AAAA,MACzE;AACA,aAAO;AAAA,IACT;AAEA,QAAI,KAAK,iCAAiC,4BAA4B;AACpE,WAAK,KAAK,OAAO;AAAA,QACf,kDAAkD,0BAA0B,gBAAgB,SAAS;AAAA,MACvG;AACA,aAAO;AAAA,IACT;AAEA,QAAI;AACF,YAAM,uBAAuB,MAAM,yBAAyB,KAAK,KAAK,MAAM;AAC5E,UAAI,CAAC,sBAAsB;AACzB,eAAO;AAAA,MACT;AACA,YAAM,WAAW,MAAM,qBAAqB,WAAW,KAAK,YAAY;AACxE,UAAI,CAAC,UAAU;AACb,aAAK,KAAK,OAAO;AAAA,UACf,wCAAwC,SAAS,4BAA4B,KAAK,YAAY;AAAA,QAChG;AACA,eAAO;AAAA,MACT;AACA,WAAK,iCAAiC;AACtC,WAAK,8BAA8B;AACnC,WAAK,KAAK,OAAO;AAAA,QACf,4DAA4D,SAAS,YAAY,UAAU,YAAY,kBAAkB,KAAK,YAAY,cAAc,KAAK,6BAA6B,IAAI,0BAA0B;AAAA,MAC1N;AACA,aAAO;AAAA,IACT,SAASA,MAAU;AACjB,WAAK,KAAK,OAAO;AAAA,QACf,+DAA+D,SAAS,KAAKA,MAAK,WAAW,OAAOA,IAAG,CAAC;AAAA,MAC1G;AACA,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA,EAIQ,oBAAoB,OAAoC;AAC9D,WAAO,OAAO,UAAU,YAAY,MAAM,KAAK,IAAI,MAAM,KAAK,IAAI;AAAA,EACpE;AAAA,EAEQ,eAAe,OAAoC;AACzD,WAAO,OAAO,UAAU,YAAY,MAAM,KAAK,IAAI,MAAM,KAAK,IAAI;AAAA,EACpE;AAAA,EAEQ,2BAA2B,MAAM,KAAK,IAAI,GAAS;AACzD,eAAW,CAAC,OAAO,KAAK,KAAK,KAAK,uBAAuB;AACvD,UAAI,MAAM,MAAM,cAAc,gCAAgC;AAC5D,aAAK,sBAAsB,OAAO,KAAK;AAAA,MACzC;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,6BAA6B,OAAgB,YAA2B;AAC9E,UAAM,kBAAkB,KAAK,eAAe,KAAK;AACjD,UAAM,uBAAuB,KAAK,oBAAoB,UAAU;AAChE,QAAI,CAAC,mBAAmB,CAAC,qBAAsB;AAC/C,SAAK,2BAA2B;AAChC,SAAK,sBAAsB,IAAI,iBAAiB;AAAA,MAC9C,YAAY;AAAA,MACZ,aAAa,KAAK,IAAI;AAAA,IACxB,CAAC;AAAA,EACH;AAAA,EAEQ,wBAAwB,SAAsB;AACpD,QAAI,CAAC,WAAW,OAAO,YAAY,SAAU,QAAO;AACpD,QAAI,OAAO,QAAQ,SAAS,SAAU,QAAO,QAAQ;AACrD,QAAI,CAAC,MAAM,QAAQ,QAAQ,OAAO,EAAG,QAAO;AAC5C,WAAO,QAAQ,QACZ;AAAA,MACC,CAAC,SACC,QACA,OAAO,SAAS,YAChB,KAAK,SAAS,UACd,OAAO,KAAK,SAAS;AAAA,IACzB,EACC,IAAI,CAAC,SAAc,KAAK,IAAI,EAC5B,KAAK,EAAE;AAAA,EACZ;AAAA,EAEQ,mCAAmC,MAAuB;AAChE,UAAM,aAAa,KAAK,KAAK,EAAE,YAAY;AAC3C,QAAI,CAAC,WAAY,QAAO;AACxB,WACE,WAAW,SAAS,4BAA4B,KAChD,WAAW,SAAS,SAAS,KAC7B,WAAW,SAAS,wBAAwB;AAAA,EAEhD;AAAA,EAEQ,+BACN,SACA,YACS;AACT,UAAM,OAAO,KAAK,wBAAwB,OAAO;AACjD,QAAI,CAAC,KAAK,mCAAmC,IAAI,EAAG,QAAO;AAC3D,UAAM,mBACJ,OAAO,SAAS,cAAc,WAAW,QAAQ,YAAY;AAC/D,UAAM,MAAM,KAAK,IAAI;AACrB,SAAK,2BAA2B,GAAG;AACnC,eAAW,SAAS,KAAK,sBAAsB,OAAO,GAAG;AACvD,UAAI,MAAM,eAAe,WAAY;AACrC,UAAI,qBAAqB,KAAM,QAAO;AACtC,UAAI,KAAK,IAAI,mBAAmB,MAAM,WAAW,KAAK,gCAAgC;AACpF,eAAO;AAAA,MACT;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,yBAAyB,MAAc,OAA2B;AACxE,SAAK,2BAA2B;AAEhC,QACE,OAAO,SAAS,WAChB,OAAO,UAAU,UACjB,OAAO,SAAS,UAAU,WAC1B;AACA,WAAK;AAAA,QACH,MAAM,SAAS;AAAA,QACf,MAAM,SAAS;AAAA,MACjB;AACA,aAAO;AAAA,IACT;AAEA,QAAI,OAAO,SAAS,SAAS,OAAO,OAAO,SAAS,OAAO,OAAO,OAAO,UAAU;AACjF,WAAK,mBAAmB,OAAO,MAAM,EAAE;AACvC,aAAO;AAAA,IACT;AAEA,QAAI;AACJ,QAAI,OAAO,SAAS,SAAS,OAAO,OAAO,OAAO,UAAU;AAC1D,gBAAU,KAAK,mBAAmB,IAAI,MAAM,EAAE;AAC9C,WAAK,mBAAmB,OAAO,MAAM,EAAE;AAAA,IACzC;AAEA,QACE,OAAO,SAAS,SAChB,OAAO,OAAO,QACd,SAAS,WAAW,cACpB;AACA,YAAM,SAAS,MAAM,QAAQ,OAAO,SAAS,MAAM,IAC/C,MAAM,QAAQ,SACd,CAAC;AACL,iBAAW,SAAS,QAAQ;AAC1B,aAAK,6BAA6B,OAAO,QAAQ,UAAU;AAAA,MAC7D;AACA,aAAO;AAAA,IACT;AAEA,QACE,OAAO,SAAS,WAChB,OAAO,UAAU,UACjB,OAAO,SAAS,UAAU,SAC1B;AACA,YAAM,QAAQ,KAAK,eAAe,OAAO,SAAS,KAAK;AACvD,YAAM,gBAAgB,KAAK,wBAAwB,OAAO,SAAS,OAAO;AAC1E,YAAM,cAAc,QAAQ,KAAK,sBAAsB,IAAI,KAAK,IAAI;AACpE,UACE,eACA,KAAK,mCAAmC,aAAa,GACrD;AACA,aAAK,KAAK,OAAO;AAAA,UACf,oEAAoE,KAAK;AAAA,QAC3E;AACA,eAAO;AAAA,MACT;AACA,aAAO;AAAA,IACT;AAEA,QACE,OAAO,SAAS,SAChB,OAAO,OAAO,QACd,SAAS,WAAW,kBACpB,MAAM,QAAQ,OAAO,SAAS,QAAQ,GACtC;AACA,YAAM,aACJ,KAAK,oBAAoB,OAAO,SAAS,UAAU,KAAK,QAAQ;AAClE,UAAI,CAAC,WAAY,QAAO;AACxB,YAAM,mBAAmB,MAAM,QAAQ,SAAS;AAAA,QAC9C,CAAC,YACC,CAAC,KAAK,+BAA+B,SAAS,UAAU;AAAA,MAC5D;AACA,UAAI,iBAAiB,WAAW,MAAM,QAAQ,SAAS,QAAQ;AAC7D,eAAO;AAAA,MACT;AACA,WAAK,KAAK,OAAO;AAAA,QACf,wBAAwB,MAAM,QAAQ,SAAS,SAAS,iBAAiB,MAAM,mDAAmD,UAAU;AAAA,MAC9I;AACA,aAAO,KAAK,UAAU;AAAA,QACpB,GAAG;AAAA,QACH,SAAS;AAAA,UACP,GAAG,MAAM;AAAA,UACT,UAAU;AAAA,QACZ;AAAA,MACF,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,EACT;AAAA;AAAA,EAGQ,kBAAwB;AAC9B,QAAI,KAAK,kBAAkB,KAAK,WAAW,eAAe,gBAAU;AAClE;AACF,QAAI,KAAK,oBAAqB;AAE9B,SAAK,sBAAsB;AAC3B,SAAK,iBAAiB;AACtB,UAAM,QAAQ,KAAK,KAAK,eAAe,QAAQ,SAAS,IAAI;AAE5D,SAAK,KAAK,OAAO;AAAA,MACf,6CAA6C,KAAK,aAAa,KAAK,iBAAiB,MAAM;AAAA,IAC7F;AAEA,UAAM,KAAK,IAAI,gBAAU,KAAK;AAE9B,OAAG,GAAG,QAAQ,MAAM;AAClB,WAAK,YAAY;AACjB,WAAK,KAAK,OAAO;AAAA,QACf,6EAA6E,KAAK,iBAAiB,MAAM;AAAA,MAC3G;AAAA,IACF,CAAC;AAED,OAAG,GAAG,WAAW,OAAO,SAA4B;AAClD,UAAI;AACJ,UAAI,OAAO,SAAS,UAAU;AAC5B,eAAO;AAAA,MACT,WAAW,OAAO,SAAS,IAAI,GAAG;AAChC,eAAO,KAAK,SAAS;AAAA,MACvB,OAAO;AACL,eAAO,OAAO,KAAK,IAAmB,EAAE,SAAS;AAAA,MACnD;AAEA,YAAM,UAAU,KAAK,UAAU,MAAM,OAAO,KAAK,UAAU,GAAG,GAAG,IAAI;AACrE,WAAK,KAAK,OAAO;AAAA,QACf,uCAAkC,KAAK,MAAM,YAAY,OAAO;AAAA,MAClE;AAEA,UAAI;AACJ,UAAI;AACF,gBAAQ,KAAK,MAAM,IAAI;AAAA,MACzB,QAAQ;AACN,aAAK,KAAK,OAAO;AAAA,UACf;AAAA,QACF;AACA;AAAA,MACF;AAGA,UAAI,MAAM,SAAS,WAAW,MAAM,UAAU,qBAAqB;AACjE,aAAK,uBAAuB,IAAI,KAAK;AACrC;AAAA,MACF;AAGA,UACE,MAAM,SAAS,SACf,MAAM,OAAO,QACb,MAAM,SAAS,SAAS,YACxB;AACA,aAAK,uBAAuB;AAAA,UAC1B,cAAc;AAAA,UACd,gBAAgB,CAAC,gBAAgB;AAAA,UACjC,UAAU,MAAM,SAAS;AAAA,QAC3B,CAAC;AACD,aAAK,gCAAgC;AACrC,aAAK,8BAA8B;AACnC,aAAK,iBAAiB;AACtB,aAAK,sBAAsB;AAC3B,aAAK,KAAK,OAAO;AAAA,UACf,2DAA2D,KAAK,iBAAiB,MAAM;AAAA,QACzF;AACA,mBAAW,WAAW,KAAK,kBAAkB;AAC3C,aAAG,KAAK,OAAO;AAAA,QACjB;AACA,aAAK,mBAAmB,CAAC;AACzB;AAAA,MACF;AAGA,UAAI,MAAM,SAAS,SAAS,MAAM,OAAO,SAAS,CAAC,KAAK,gBAAgB;AACtE,cAAM,eAAe,MAAM,KAAK,+BAA+B,KAAK;AACpE,YAAI,cAAc;AAChB,gBAAM,kBACJ,GAAG,eAAe,gBAAU,WAC5B,GAAG,eAAe,gBAAU,UAC5B,KAAK,cAAc;AACrB,eAAK,KAAK,OAAO;AAAA,YACf,+EAA+E,kBAAkB,iBAAiB,cAAc,aAAa,KAAK,iBAAiB,MAAM;AAAA,UAC3K;AACA,cAAI,iBAAiB;AACnB,iBAAK,8BAA8B;AACnC,iBAAK,gBAAgB;AACrB;AAAA,UACF;AACA,aAAG,MAAM,KAAM,gCAAgC;AAC/C;AAAA,QACF;AACA,aAAK,KAAK,OAAO;AAAA,UACf,iDAAiD,KAAK,iBAAiB,MAAM,MAAM,YAAY,KAAK,UAAU,MAAM,KAAK,GAAG,GAAG,CAAC;AAAA,QAClI;AACA,WAAG,MAAM;AACT;AAAA,MACF;AAGA,YAAM,YAAY,KAAK,yBAAyB,MAAM,KAAK;AAC3D,UAAI,cAAc,MAAM;AACtB,aAAK,KAAK,OAAO,QAAQ,SAAS;AAAA,MACpC;AAAA,IACF,CAAC;AAED,OAAG,GAAG,SAAS,CAAC,MAAc,WAAmB;AAC/C,YAAM,WAAW,KAAK;AACtB,YAAM,eAAe,KAAK,iBAAiB;AAC3C,YAAM,aAAa,OAAO,SAAS;AACnC,YAAM,kBACJ,KAAK,+BAA+B,eAAe;AACrD,WAAK,KAAK,OAAO;AAAA,QACf,+CAA+C,IAAI,YAAY,UAAU,WAAW,QAAQ,aAAa,YAAY,cAAc,KAAK,QAAQ,WAAW;AAAA,MAC7J;AACA,UAAI,KAAK,cAAc,IAAI;AACzB,aAAK,YAAY;AACjB,aAAK,iBAAiB;AAAA,MACxB;AACA,WAAK,sBAAsB;AAC3B,WAAK,sCAAsC,MAAM,UAAU;AAC3D,UAAI,iBAAiB;AACnB,aAAK,8BAA8B;AACnC,aAAK,KAAK,OAAO;AAAA,UACf,sEAAsE,KAAK,iBAAiB,MAAM;AAAA,QACpG;AACA,uBAAe,MAAM,KAAK,gBAAgB,CAAC;AAAA,MAC7C;AAAA,IACF,CAAC;AAED,OAAG,GAAG,SAAS,CAACA,SAAe;AAC7B,WAAK,KAAK,OAAO;AAAA,QACf,8BAA8BA,KAAI,OAAO,WAAW,KAAK,cAAc,aAAa,KAAK,iBAAiB,MAAM,cAAc,KAAK,QAAQ,WAAW;AAAA,MACxJ;AACA,WAAK,sBAAsB;AAC3B,UAAI,KAAK,cAAc,IAAI;AACzB,aAAK,YAAY;AACjB,aAAK,iBAAiB;AAAA,MACxB;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEQ,uBAAuB,IAAe,OAAkB;AAC9D,UAAM,iBAAyB,MAAM,SAAS,SAAS;AACvD,UAAM,mBAAmB,sBAAkB,gCAAW,CAAC;AACvD,UAAM,OAAO;AACb,UAAM,SAAS,CAAC,gBAAgB;AAChC,UAAM,qBAAqB,KAAK,wBAAwB,IAAI;AAC5D,SAAK,KAAK,OAAO;AAAA,MACf,kDAAkD,cAAc,kBAAkB,gBAAgB,cAAc,CAAC,CAAC,mBAAmB,SAAS,iBAAiB,CAAC,CAAC,mBAAmB,YAAY,oBAAoB,CAAC,CAAC,mBAAmB,WAAW;AAAA,IACtP;AAEA,UAAM,aAAa,KAAK,IAAI;AAC5B,UAAM,WAAW;AACjB,UAAM,aAAa;AAEnB,UAAM,cAAc,uBAAuB;AAAA,MACzC,UAAU,KAAK,eAAe;AAAA,MAC9B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO,mBAAmB,aAAa;AAAA,MACvC,OAAO;AAAA,IACT,CAAC;AACD,UAAM,YAAY;AAAA,MAChB,KAAK,eAAe;AAAA,MACpB;AAAA,IACF;AAEA,UAAM,aAAa;AAAA,MACjB,MAAM;AAAA,MACN,IAAI;AAAA,MACJ,QAAQ;AAAA,MACR,QAAQ;AAAA,QACN,aAAa;AAAA,QACb,aAAa;AAAA,QACb,QAAQ;AAAA,UACN,IAAI;AAAA,UACJ,SAAS;AAAA,UACT,UAAU,QAAQ;AAAA,UAClB,MAAM;AAAA,UACN,YAAY;AAAA,QACd;AAAA,QACA;AAAA,QACA;AAAA,QACA,GAAI,mBAAmB,OAAO,EAAE,MAAM,mBAAmB,KAAK,IAAI,CAAC;AAAA,QACnE,QAAQ;AAAA,UACN,IAAI,KAAK,eAAe;AAAA,UACxB,WAAW;AAAA,YACT,KAAK,eAAe;AAAA,UACtB;AAAA,UACA;AAAA,UACA,UAAU;AAAA,UACV,OAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF;AACA,OAAG,KAAK,KAAK,UAAU,UAAU,CAAC;AAAA,EACpC;AACF;;;AJnvBA,IAAM,wBAAwB;AAC9B,IAAM,+BAA+B;AAmC9B,SAAS,oBACd,MACoB;AACpB,MAAI,SAA6B;AACjC,MAAI,QAA4B;AAChC,MAAI,kBAA0C;AAC9C,MAAI,eAA8B;AAClC,MAAI,SAAwB;AAC5B,MAAI,sBAAyC;AAC7C,MAAI,6BAA6B;AAEjC,WAAS,wBAAwB,QAAsB;AACrD,UAAM,SAAS;AACf,QAAI,CAAC,UAAU,CAAC,QAAQ,YAAY,EAAG;AAEvC,UAAM,QAAQ,KAAK,UAAU;AAAA,MAC3B,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,QACP,UAAU;AAAA,QACV,YAAY;AAAA,QACZ,SAAS,OAAO;AAAA,QAChB,QAAQ,OAAO;AAAA,MACjB;AAAA,IACF,CAAC;AACD,SAAK,OAAO;AAAA,MACV,gDAAgD,OAAO,OAAO,WAAM,OAAO,MAAM,KAAK,MAAM;AAAA,IAC9F;AACA,WAAO,QAAQ,KAAK;AAAA,EACtB;AAEA,WAASC,gBAAe,KAAsB;AAC5C,QAAI,CAAC,OAAO,UAAU,GAAG,KAAK,OAAO,EAAG,QAAO;AAC/C,QAAI,QAAQ,QAAQ,IAAK,QAAO;AAChC,QAAI;AACF,cAAQ,KAAK,KAAK,CAAC;AACnB,aAAO;AAAA,IACT,SAASC,MAAU;AACjB,aAAOA,MAAK,SAAS;AAAA,IACvB;AAAA,EACF;AAEA,WAAS,cAAc,UAAiC;AACtD,QAAI;AACF,YAAM,SAAS,KAAK,UAAM,+BAAa,UAAU,OAAO,CAAC;AAGzD,aAAO,OAAO,OAAO,QAAQ,WAAW,OAAO,MAAM;AAAA,IACvD,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAEA,WAAS,cAAoB;AAC3B,UAAM,WAAW;AACjB,UAAM,KAAK;AACX,mBAAe;AACf,aAAS;AAET,QAAI,OAAO,MAAM;AACf,UAAI;AACF,wCAAU,EAAE;AAAA,MACd,QAAQ;AAAA,MAER;AAAA,IACF;AACA,QAAI,UAAU;AACZ,UAAI;AACF,yCAAW,QAAQ;AAAA,MACrB,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AAEA,WAAS,YAAY,UAA2B;AAC9C,wCAAU,4BAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;AAEhD,aAAS,UAAU,GAAG,UAAU,GAAG,WAAW;AAC5C,UAAI;AACF,cAAM,SAAK,2BAAS,UAAU,MAAM,GAAK;AACzC;AAAA,UACE;AAAA,UACA,KAAK,UAAU;AAAA,YACb,KAAK,QAAQ;AAAA,YACb,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,YAClC,WAAW,iBAAiB,KAAK,SAAS;AAAA,UAC5C,CAAC,IAAI;AAAA,QACP;AACA,uBAAe;AACf,iBAAS;AACT,eAAO;AAAA,MACT,SAASA,MAAU;AACjB,YAAIA,MAAK,SAAS,UAAU;AAC1B,eAAK,OAAO;AAAA,YACV,8CAA8C,QAAQ,KAAK,OAAOA,IAAG,CAAC;AAAA,UACxE;AACA,iBAAO;AAAA,QACT;AAEA,cAAM,WAAW,cAAc,QAAQ;AACvC,YAAI,YAAY,CAACD,gBAAe,QAAQ,GAAG;AACzC,eAAK,OAAO;AAAA,YACV,6DAA6D,QAAQ;AAAA,UACvE;AACA,cAAI;AACF,6CAAW,QAAQ;AAAA,UACrB,QAAQ;AAAA,UAER;AACA;AAAA,QACF;AAEA,aAAK,OAAO;AAAA,UACV,mEAAmE,WAAW,SAAS,QAAQ,MAAM,EAAE;AAAA,QACzG;AACA,eAAO;AAAA,MACT;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAEA,iBAAe,gBAAgB,QAA+B;AAC5D,UAAM,QAAQ,KAAK,MAAM;AACzB,QAAI,iBAAiB;AACnB,sBAAgB,MAAM;AACtB,wBAAkB;AAAA,IACpB;AACA,gBAAY;AACZ,WAAO,QAAQ;AACf,YAAQ;AACR,aAAS;AAAA,EACX;AAEA,SAAO;AAAA,IACL,IAAI;AAAA,IAEJ,MAAM,MAAM,KAA2B;AACrC,UAAI,4BAA4B;AAC9B,aAAK,OAAO;AAAA,UACV;AAAA,QACF;AACA;AAAA,MACF;AAGA,UAAI,iBAAiB;AACnB,aAAK,OAAO,KAAK,2DAA2D;AAC5E,cAAM,gBAAgB,oBAAoB;AAAA,MAC5C;AAEA,YAAM,SAAS,WAAW;AAC1B,UAAI,CAAC,QAAQ;AACX,aAAK,OAAO;AAAA,UACV;AAAA,QACF;AACA;AAAA,MACF;AAEA,YAAM,EAAE,OAAO,IAAI;AACnB,YAAM,mBAAe,yBAAK,IAAI,UAAU,WAAW,qBAAqB;AACxE,aAAO;AAAA,QACL,+BAA+B,QAAQ,GAAG,SAAS,iBAAiB,KAAK,SAAS,CAAC,eAAe,KAAK,gBAAgB,qBAAqB,cAAc,KAAK,sBAAsB,4BAA4B,eAAe,KAAK,cAAc,qBAAqB,CAAC,CAAC,KAAK,YAAY,mBAAmB,CAAC,CAAC,KAAK,eAAe;AAAA,MACtU;AACA,YAAM,qBAAiB,yBAAK,cAAc,oBAAoB;AAC9D,YAAM,eAAW,yBAAK,cAAc,mBAAmB;AAEvD,UAAI,CAAC,YAAY,QAAQ,GAAG;AAC1B;AAAA,MACF;AAEA,UAAI;AACF,iBAAS,IAAI,YAAY;AAAA,UACvB,WAAW,KAAK;AAAA,UAChB;AAAA,UACA,cAAc,KAAK,gBAAgB;AAAA,UACnC,oBAAoB,KAAK,sBAAsB;AAAA,UAC/C;AAAA,UACA;AAAA,QACF,CAAC;AAED,gBAAQ,IAAI,YAAY;AAAA,UACtB,UAAU;AAAA,UACV,cAAc,IAAI;AAAA,UAClB,gBAAgB,KAAK;AAAA,UACrB,iBAAiB,KAAK;AAAA,UACtB,cAAc,KAAK;AAAA,UACnB,iBAAiB,KAAK;AAAA,UACtB;AAAA,UACA;AAAA,QACF,CAAC;AAED,eAAO,UAAU,CAAC,UAAU,MAAO,YAAY,KAAK,CAAC;AACrD,eAAO,YAAY,MAAM;AACvB,kCAAwB,iBAAiB;AAAA,QAC3C,CAAC;AAED,0BAAkB,IAAI,gBAAgB;AAEtC,eAAO,yBAAyB,gBAAgB,MAAM,EAAE,MAAM,CAACC,SAAQ;AACrE,sBAAY;AACZ,iBAAO,MAAM,mCAAmCA,IAAG,EAAE;AAAA,QACvD,CAAC;AAED,eAAO,KAAK,6CAAoB;AAAA,MAClC,SAASA,MAAK;AACZ,oBAAY;AACZ,cAAMA;AAAA,MACR;AAAA,IACF;AAAA,IAEA,MAAM,OAAO;AACX,mCAA6B;AAC7B,YAAM,gBAAgB,kBAAkB;AACxC,WAAK,OAAO,KAAK,6CAAoB;AAAA,IACvC;AAAA,IAEA,MAAM,4BAA4B,QAAgB;AAChD,UAAI,8BAA8B,CAAC,UAAU,CAAC,SAAS,CAAC,iBAAiB;AACvE;AAAA,MACF;AAEA,mCAA6B;AAC7B,WAAK,OAAO;AAAA,QACV,kDAAkD,MAAM;AAAA,MAC1D;AACA,YAAM,gBAAgB,wBAAwB;AAAA,IAChD;AAAA,IAEA,sBAAsB,QAAoB;AACxC,4BAAsB;AACtB,8BAAwB,iBAAiB;AAAA,IAC3C;AAAA,IAEA,qBAAqB;AACnB,4BAAsB;AAAA,IACxB;AAAA,EACF;AACF;;;AVhRA;AAsBO,SAAS,yBACd,MACM;AACN,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AAEJ,MAAI,UAAsC;AAC1C,MAAI,mBAA4C;AAChD,MAAI,qBAAyE;AAE7E,MAAI,gBAAgB;AAAA,IAClB,IAAI;AAAA,IACJ,MAAM,MAAM,KAAK;AACf,YAAM,aAAa,8BAA8B,KAAK,MAAM;AAE5D,2BAAqB,yBAAyB;AAAA,QAC5C,UAAU,IAAI;AAAA,QACd;AAAA,MACF,CAAC;AACD,YAAM,mBAAmB,MAAM;AAE/B,YAAM,qBAAqB,mBAAmB,mBAAmB,KAAK,kBAAkB;AACxF,gBAAU,IAAI,oBAAoB,YAAY,QAAQ,QAAQ,kBAAkB;AAChF,YAAM,QAAQ,KAAK;AACnB,iBAAW,OAAO;AAClB,aAAO,KAAK,2DAAc,UAAU,EAAE;AAEtC,YAAM,SAAS,2BAA2B,KAAK,MAAM;AACrD,yBAAmB,IAAI,iBAAiB,QAAQ,MAAM;AACtD,YAAM,iBAAiB,KAAK;AAC5B,0BAAoB,gBAAgB;AACpC,aAAO,KAAK,2DAAc,MAAM,EAAE;AAElC,mBAAa,eAAe,IAAI;AAChC,UAAI,IAAI,UAAU;AAChB,qBAAa,WAAW,IAAI;AAAA,MAC9B;AAEA,uBAAiB;AAAA,IACnB;AAAA,IACA,MAAM,OAAO;AACX,YAAM,SAAS,MAAM;AACrB,gBAAU;AACV,iBAAW,IAAI;AAEf,YAAM,kBAAkB,MAAM;AAC9B,yBAAmB;AACnB,0BAAoB,IAAI;AAExB,0BAAoB,KAAK;AACzB,2BAAqB;AACrB,aAAO,KAAK,qEAAc;AAAA,IAC5B;AAAA,EACF,CAAC;AACH;AAEA,SAAS,sBAAsB,QAG5B;AACD,QAAM,aAAa,OAAO,WACtB,kBAAkB,OAAO,QAAQ,IACjC;AAEJ,MAAI;AAEJ,MAAI,YAAY;AACd,QAAI;AACF,mBAAa,KAAK,UAAM,+BAAa,YAAY,OAAO,CAAC;AAAA,IAC3D,SAASC,MAAU;AACjB,UAAIA,MAAK,SAAS,UAAU;AAC1B,eAAO,OAAO;AAAA,UACZ,4EAAoC,UAAU;AAAA,QAChD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,wBAAwB,QAO/B;AACA,QAAM,kBACJC,iBAAgB,QAAQ,IAAI,sBAAsB,KAClDA,iBAAgB,QAAQ,IAAI,mBAAmB;AACjD,QAAM,qBACJA,iBAAgB,QAAQ,IAAI,yBAAyB,KACrDA,iBAAgB,QAAQ,IAAI,sBAAsB;AAEpD,QAAM,aAAa,sBAAsB,MAAM;AAC/C,MAAI;AACJ,QAAM,qBAAqBA,iBAAgB,YAAY,SAAS,MAAM,IAAI;AAC1E,MAAI,uBAAuB,WAAW,uBAAuB,YAAY;AACvE,4BAAwB;AAAA,EAC1B;AACA,QAAM,qBAAqBA,iBAAgB,YAAY,SAAS,MAAM,KAAK;AAC3E,QAAM,wBAAwBA,iBAAgB,YAAY,SAAS,MAAM,QAAQ;AAEjF,SAAO;AAAA,IACL,iBAAiB;AAAA,IACjB,cAAc,mBAAmB;AAAA,IACjC,iBAAiB,sBAAsB;AAAA,EACzC;AACF;AAEA,SAAS,2BAA2B,QAGb;AACrB,QAAM,aAAa,sBAAsB,MAAM;AAC/C,QAAM,gBAAgBA,iBAAgB,YAAY,SAAS,WAAW,IAAI;AAC1E,MAAI,eAAe;AACjB,WAAO,0BAA0B,aAAa;AAAA,EAChD;AAEA,QAAM,YAAYA,iBAAgB,YAAY,SAAS,QAAQ,GAAG;AAClE,MAAI,aAAa,2BAA2B,SAAS,GAAG;AACtD,WAAO,sBAAsB,SAAS;AAAA,EACxC;AAEA,SAAO;AACT;AAEA,SAAS,2BAA2B,QAAyB;AAC3D,MAAI;AACJ,MAAI;AACF,WAAO,IAAI,IAAI,MAAM,EAAE,SAAS,YAAY;AAAA,EAC9C,QAAQ;AACN,WAAO;AAAA,EACT;AAEA,MAAI,SAAS,eAAe,SAAS,SAAS,SAAS,SAAS;AAC9D,WAAO;AAAA,EACT;AAEA,SAAO,CAAC,0BAA0B,KAAK,IAAI;AAC7C;AASO,SAAS,6BACd,MAC2B;AAC3B,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AAEJ,QAAM,YAAY,WAAW,EAAE;AAC/B,MAAI,CAAC,WAAW;AACd,WAAO;AAAA,EACT;AAEA,QAAM,sBAAsB,2BAA2B;AAAA,IACrD,UAAU;AAAA,IACV;AAAA,EACF,CAAC;AACD,MAAI,qBAAqB;AACvB,WAAO;AAAA,MACL,0BAA0B,mBAAmB;AAAA,IAC/C;AACA,WAAO;AAAA,EACT;AAEA,QAAM,cACJ,QAAQ,IAAI,yBACZ,QAAQ,IAAI,sBACZ;AACF,QAAM,EAAE,iBAAiB,cAAc,gBAAgB,IACrD,wBAAwB;AAAA,IACtB,UAAU;AAAA,IACV;AAAA,EACF,CAAC;AAEH,QAAM,gBAAgB,oBAAoB;AAAA,IACxC;AAAA,IACA,cAAc,OAAO,OAAO;AAAA,IAC5B,oBAAoB,OAAO,OAAO;AAAA,IAClC,gBAAgB,oBAAoB,WAAW;AAAA,IAC/C;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,MAAI,gBAAgB,aAAa;AACjC,SAAO,KAAK,6CAAoB;AAChC,SAAO;AACT;;;AkBzPA,IAAAC,sBAA4B;AAqB5B,SAAS,cAAsB;AAC7B,SAAO,WAAO,iCAAY,CAAC,EAAE,SAAS,KAAK,CAAC;AAC9C;AAEA,SAAS,uBAAuB,OAAkC;AAChE,QAAM,QAAQ,MAAM;AACpB,MAAI,UAAU,EAAG,QAAO;AACxB,QAAM,MAAM,KAAK,IAAI;AACrB,MAAI,WAAW,OAAO;AACtB,MAAI,SAAS,OAAO;AACpB,aAAW,KAAK,OAAO;AACrB,UAAM,IAAI,IAAI,KAAK,EAAE,SAAS,EAAE,QAAQ;AACxC,QAAI,OAAO,MAAM,CAAC,EAAG;AACrB,QAAI,IAAI,SAAU,YAAW;AAC7B,QAAI,IAAI,OAAQ,UAAS;AAAA,EAC3B;AACA,MAAI,CAAC,OAAO,SAAS,QAAQ,GAAG;AAC9B,WAAO,SAAS,KAAK;AAAA,EACvB;AACA,QAAM,SAAS,MAAM;AACrB,QAAM,SAAS,MAAM;AACrB,SAAO,SAAS,KAAK,eAAe,IAAI,KAAK,QAAQ,EAAE,YAAY,CAAC,QAAQ,MAAM,KAAK,MAAM;AAC/F;AAEA,SAAS,0BAAoD;AAC3D,SAAO;AAAA,IACL,UAAU;AAAA,IACV,UAAU;AAAA,IACV,aAAa;AAAA,IACb,kBAAkB;AAAA,IAClB,SAAS;AAAA,IACT,UAAU,CAAC;AAAA,EACb;AACF;AAEA,SAAS,2BAA2B,KAA+B;AACjE,QAAM,SAAS,IAAI,UAAU,0BAA0B;AACvD,MAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,WAAO,OAAO,SAAS,GAAG;AAAA,EAC5B;AACA,SAAO,WAAW;AACpB;AAOA,SAAS,iBACP,QAC4C;AAC5C,QAAM,EAAE,UAAU,WAAW,GAAG,KAAK,IAAI;AACzC,SAAO;AACT;AAgBO,SAAS,+BACd,MACM;AACN,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AAEJ,WAAS,mBACP,UACA,UACM;AACN,QAAI,SAAS,WAAW,KAAK,CAAC,cAAe;AAC7C,WAAO;AAAA,MACL,iBAAiB,QAAQ,cAAc,SAAS,MAAM;AAAA,IACxD;AACA,SAAK,QAAQ,QAAQ,EAClB,KAAK,MAAM,cAAc,UAAU,QAAQ,CAAC,EAC5C;AAAA,MAAM,CAACC,SACN,OAAO;AAAA,QACL,iBAAiB,QAAQ,4BAA4BA,MAAK,WAAWA,IAAG;AAAA,MAC1E;AAAA,IACF;AAAA,EACJ;AAEA;AAAA,IACE;AAAA,IACA,OAAO,EAAE,QAAQ,QAAQ,MAAM;AAC7B,YAAM,UAAU,WAAW;AAC3B,UAAI,CAAC,SAAS;AACZ,gBAAQ,OAAO,MAAM;AAAA,UACnB,MAAM;AAAA,UACN,SAAS;AAAA,QACX,CAAC;AACD;AAAA,MACF;AAEA,YAAM,EAAE,MAAM,IAAI;AAClB,UAAI,CAAC,MAAM,QAAQ,KAAK,GAAG;AACzB,gBAAQ,OAAO,MAAM;AAAA,UACnB,MAAM;AAAA,UACN,SAAS;AAAA,QACX,CAAC;AACD;AAAA,MACF;AAEA,YAAM,WAAW,YAAY;AAC7B,YAAM,UAAU,KAAK,IAAI;AACzB,aAAO;AAAA,QACL,iBAAiB,QAAQ,0CAA0C,uBAAuB,KAAK,CAAC;AAAA,MAClG;AAEA,YAAM,WAAW,oBAAoB,KAAK;AAC1C,UAAI,SAAS,WAAW,MAAM,QAAQ;AACpC,eAAO;AAAA,UACL,iBAAiB,QAAQ,eAAe,MAAM,SAAS,SAAS,MAAM,8BAA8B,SAAS,MAAM;AAAA,QACrH;AAAA,MACF;AACA,YAAM,SAAS,SAAS,SACpB,MAAM,QAAQ,OAAO,UAAU,QAAQ,IACvC,wBAAwB;AAE5B,aAAO;AAAA,QACL,iBAAiB,QAAQ,qBAAqB,KAAK,IAAI,IAAI,OAAO,gBACnD,OAAO,QAAQ,aAAa,OAAO,QAAQ,gBACzC,OAAO,WAAW,qBAAqB,OAAO,gBAAgB,YAAY,OAAO,OAAO;AAAA,MAC3G;AAGA,cAAQ,MAAM,iBAAiB,MAAM,CAAC;AAGtC,yBAAmB,OAAO,UAAU,QAAQ;AAAA,IAC9C;AAAA,EACF;AAEA,MAAI,kBAAkB;AAAA,IACpB,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM,QAAQ,KAAsB,KAAqB;AACvD,UAAI,IAAI,WAAW,QAAQ;AACzB,YAAI,UAAU,KAAK,EAAE,gBAAgB,mBAAmB,CAAC;AACzD,YAAI,IAAI,KAAK,UAAU,EAAE,IAAI,OAAO,OAAO,qBAAqB,CAAC,CAAC;AAClE;AAAA,MACF;AAEA,UAAI,CAAC,2BAA2B,GAAG,GAAG;AACpC,cAAM,eAAe,4BAA4B,qBAAqB;AAAA,MACxE;AAEA,YAAM,UAAU,WAAW;AAC3B,UAAI,CAAC,SAAS;AACZ,YAAI,UAAU,KAAK,EAAE,gBAAgB,mBAAmB,CAAC;AACzD,YAAI,IAAI,KAAK,UAAU,EAAE,IAAI,OAAO,OAAO,oBAAoB,CAAC,CAAC;AACjE;AAAA,MACF;AAEA,UAAI;AACJ,UAAI;AACF,cAAM,MAAM,MAAM,SAAS,GAAG;AAC9B,eAAO,KAAK,MAAM,GAAG;AAAA,MACvB,QAAQ;AACN,YAAI,UAAU,KAAK,EAAE,gBAAgB,mBAAmB,CAAC;AACzD,YAAI,IAAI,KAAK,UAAU,EAAE,IAAI,OAAO,OAAO,eAAe,CAAC,CAAC;AAC5D;AAAA,MACF;AAEA,UAAI,CAAC,MAAM,QAAQ,KAAK,aAAa,GAAG;AACtC,YAAI,UAAU,KAAK,EAAE,gBAAgB,mBAAmB,CAAC;AACzD,YAAI;AAAA,UACF,KAAK,UAAU;AAAA,YACb,IAAI;AAAA,YACJ,OAAO;AAAA,UACT,CAAC;AAAA,QACH;AACA;AAAA,MACF;AAEA,YAAM,WAAW,YAAY;AAC7B,YAAM,UAAU,KAAK,IAAI;AACzB,aAAO;AAAA,QACL,iBAAiB,QAAQ,wCAAwC,uBAAuB,KAAK,aAAa,CAAC;AAAA,MAC7G;AAEA,YAAM,WAAW,oBAAoB,KAAK,aAAa;AACvD,UAAI,SAAS,WAAW,KAAK,cAAc,QAAQ;AACjD,eAAO;AAAA,UACL,iBAAiB,QAAQ,eAAe,KAAK,cAAc,SAAS,SAAS,MAAM,8BAA8B,SAAS,MAAM;AAAA,QAClI;AAAA,MACF;AACA,YAAM,SAAS,SAAS,SACpB,MAAM,QAAQ,OAAO,UAAU,QAAQ,IACvC,wBAAwB;AAE5B,aAAO;AAAA,QACL,iBAAiB,QAAQ,qBAAqB,KAAK,IAAI,IAAI,OAAO,gBACnD,OAAO,QAAQ,aAAa,OAAO,QAAQ,gBACzC,OAAO,WAAW,qBAAqB,OAAO,gBAAgB,YAAY,OAAO,OAAO;AAAA,MAC3G;AAEA,UAAI,UAAU,KAAK,EAAE,gBAAgB,mBAAmB,CAAC;AACzD,UAAI,IAAI,KAAK,UAAU,EAAE,IAAI,MAAM,GAAG,iBAAiB,MAAM,EAAE,CAAC,CAAC;AAGjE,yBAAmB,OAAO,UAAU,QAAQ;AAAA,IAC9C;AAAA,EACF,CAAC;AAED,SAAO,KAAK,wEAAqC;AACjD,SAAO,KAAK,sEAAmC;AACjD;;;AClNA,IAAM,8BAA8B,oBAAI,IAA6B;AAAA,EACnE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,SAAS,0BACP,OACkC;AAClC,SAAO,4BAA4B,IAAI,KAAgC;AACzE;AAEA,SAAS,uBAAuB,OAA+C;AAC7E,SAAO;AAAA,IACL,aAAa,MAAM;AAAA,IACnB,MAAM,MAAM,SAAS;AAAA,IACrB,cAAc,MAAM,SAAS;AAAA,IAC7B,iBAAiB,MAAM,SAAS;AAAA,IAChC,YAAY,MAAM,SAAS;AAAA,IAC3B,iBAAiB,MAAM;AAAA,IACvB,cAAc,MAAM,SAAS,SAAS,UAAU;AAAA,IAChD,WAAW,CAAC,CAAC,MAAM;AAAA,IACnB,SAAS,CAAC,CAAC,MAAM;AAAA,IACjB,gBAAgB,CAAC,CAAC,MAAM;AAAA,IACxB,WAAW,MAAM;AAAA,IACjB,oBAAoB,MAAM;AAAA,IAC1B,gBAAgB,MAAM;AAAA,IACtB,WAAW,MAAM;AAAA,IACjB,GAAI,MAAM,YAAY,EAAE,OAAO,MAAM,UAAU,IAAI,CAAC;AAAA,EACtD;AACF;AAEA,SAASC,4BAA2B,KAA+B;AACjE,QAAM,SAAS,IAAI,UAAU,0BAA0B;AACvD,MAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,WAAO,OAAO,SAAS,GAAG;AAAA,EAC5B;AACA,SAAO,WAAW;AACpB;AAEA,SAAS,qBACP,OACA,QAIiB;AACjB,QAAM,QAAQ,MAAM,OAAO,KAAK,KAC3B,QAAQ,OAAO,KAAK,KACpB,MAAM,SAAS,MAAM,KAAK,KAC1B,MAAM;AAEX,SAAO;AAAA,IACL,aAAa,MAAM;AAAA,IACnB,MAAM,MAAM,SAAS;AAAA,IACrB,cAAc,MAAM,SAAS;AAAA,IAC7B,iBAAiB,MAAM,SAAS;AAAA,IAChC,YAAY,MAAM,SAAS;AAAA,IAC3B,UAAU,MAAM,SAAS;AAAA,IACzB,eAAe,MAAM,SAAS;AAAA,IAC9B,aAAa,MAAM,SAAS;AAAA,IAC5B,SAAS,MAAM,SAAS,WAAW,CAAC;AAAA,IACpC,iBAAiB,MAAM;AAAA,IACvB,WAAW,MAAM;AAAA,IACjB,SAAS,MAAM;AAAA,IACf,oBAAoB,MAAM;AAAA,IAC1B,gBAAgB,MAAM;AAAA,IACtB,aAAa,MAAM;AAAA,IACnB;AAAA,IACA,SAAS,QAAQ;AAAA,IACjB,YAAY,QAAQ;AAAA,IACpB,gBAAgB,QAAQ;AAAA,IACxB,YAAY,MAAM;AAAA,IAClB,WAAW,MAAM;AAAA,IACjB,GAAI,MAAM,YAAY,EAAE,OAAO,MAAM,UAAU,IAAI,CAAC;AAAA,EACtD;AACF;AAaO,SAAS,4BACd,MACM;AACN,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AAEJ,wBAAsB,mBAAmB,OAAO,EAAE,QAAQ,QAAQ,MAAM;AACtE,UAAM,mBAAmB,oBAAoB;AAC7C,QAAI,CAAC,kBAAkB;AACrB,cAAQ,OAAO,MAAM;AAAA,QACnB,MAAM;AAAA,QACN,SAAS;AAAA,MACX,CAAC;AACD;AAAA,IACF;AAEA,UAAM;AAAA,MACJ,aAAa;AAAA,MACb;AAAA,MACA;AAAA,IACF,IAAI;AACJ,UAAM,cAAcC,iBAAgB,cAAc;AAClD,QAAI,CAAC,aAAa;AAChB,cAAQ,OAAO,MAAM;AAAA,QACnB,MAAM;AAAA,QACN,SAAS;AAAA,MACX,CAAC;AACD;AAAA,IACF;AAEA,QAAI,CAAC,aAAa,CAAC,UAAU,iBAAiB,CAAC,UAAU,YAAY;AACnE,cAAQ,OAAO,MAAM;AAAA,QACnB,MAAM;AAAA,QACN,SAAS;AAAA,MACX,CAAC;AACD;AAAA,IACF;AAEA,UAAM,WAAW,MAAM,kBAAkB,GAAG,IAAI;AAChD,QAAI,UAAU;AACZ,cAAQ,OAAO,MAAM;AAAA,QACnB,MAAM;AAAA,QACN,SAAS;AAAA,MACX,CAAC;AACD;AAAA,IACF;AAEA,UAAM,SAAS,MAAM;AAAA,MACnB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,EAAE,cAAc,sBAAsB;AAAA,IACxC;AACA;AAAA,MACE,OAAO;AAAA,MACP;AAAA,MACA,OAAO,KACH,SACA;AAAA,QACE,MAAM;AAAA,QACN,SAAS,OAAO,SAAS;AAAA,MAC3B;AAAA,IACN;AAAA,EACF,CAAC;AAED,wBAAsB,mBAAmB,OAAO,EAAE,QAAQ,QAAQ,MAAM;AACtE,UAAM,mBAAmB,oBAAoB;AAC7C,QAAI,CAAC,kBAAkB;AACrB,cAAQ,OAAO,MAAM;AAAA,QACnB,MAAM;AAAA,QACN,SAAS;AAAA,MACX,CAAC;AACD;AAAA,IACF;AAEA,UAAM,YAAYA;AAAA,MACf,QAA4C;AAAA,IAC/C;AACA,QAAI,aAAa,CAAC,0BAA0B,SAAS,GAAG;AACtD,cAAQ,OAAO,MAAM;AAAA,QACnB,MAAM;AAAA,QACN,SAAS,6BAA6B,SAAS;AAAA,MACjD,CAAC;AACD;AAAA,IACF;AAEA,UAAM,SAAS;AACf,UAAM,UAAU,SACZ,iBAAiB,aAAa,MAAM,IACpC,iBAAiB,QAAQ;AAE7B,YAAQ,MAAM;AAAA,MACZ,OAAO,QAAQ;AAAA,MACf,YAAY,QAAQ,IAAI,sBAAsB;AAAA,IAChD,CAAC;AAAA,EACH,CAAC;AAED,wBAAsB,qBAAqB,OAAO,EAAE,QAAQ,QAAQ,MAAM;AACxE,UAAM,mBAAmB,oBAAoB;AAC7C,QAAI,CAAC,kBAAkB;AACrB,cAAQ,OAAO,MAAM;AAAA,QACnB,MAAM;AAAA,QACN,SAAS;AAAA,MACX,CAAC;AACD;AAAA,IACF;AAEA,UAAM,EAAE,YAAY,IAAI;AACxB,QAAI,CAAC,aAAa;AAChB,cAAQ,OAAO,MAAM;AAAA,QACnB,MAAM;AAAA,QACN,SAAS;AAAA,MACX,CAAC;AACD;AAAA,IACF;AAEA,UAAM,QAAQ,iBAAiB,SAAS,WAAW;AACnD,QAAI,CAAC,OAAO;AACV,cAAQ,OAAO,MAAM;AAAA,QACnB,MAAM;AAAA,QACN,SAAS,wBAAwB,WAAW;AAAA,MAC9C,CAAC;AACD;AAAA,IACF;AAEA;AAAA,MACE;AAAA,OACC,MAAM;AACL,cAAM,qBACJ,iBAAiB,uBAAuB,WAAW;AAErD,eAAO,qBAAqB,OAAO;AAAA,UACjC,SAAS,iBAAiB,YAAY,WAAW;AAAA,UACjD,OAAO,mCAAmC,kBAAkB;AAAA,UAC5D,YAAY,kCAAkC,kBAAkB;AAAA,UAChE,gBAAgB;AAAA,QAClB,CAAC;AAAA,MACH,GAAG;AAAA,IACL;AAAA,EACF,CAAC;AAED,wBAAsB,qBAAqB,OAAO,EAAE,QAAQ,QAAQ,MAAM;AACxE,UAAM,mBAAmB,oBAAoB;AAC7C,QAAI,CAAC,kBAAkB;AACrB,cAAQ,OAAO,MAAM;AAAA,QACnB,MAAM;AAAA,QACN,SAAS;AAAA,MACX,CAAC;AACD;AAAA,IACF;AAEA,UAAM,EAAE,aAAa,gBAAgB,MAAM,QAAQ,IACjD;AACF,UAAM,cAAcA,iBAAgB,cAAc;AAClD,UAAM,OAAOA,iBAAgB,OAAO;AACpC,QAAI,CAAC,aAAa;AAChB,cAAQ,OAAO,MAAM;AAAA,QACnB,MAAM;AAAA,QACN,SAAS;AAAA,MACX,CAAC;AACD;AAAA,IACF;AACA,QAAI,CAAC,MAAM;AACT,cAAQ,OAAO,MAAM;AAAA,QACnB,MAAM;AAAA,QACN,SAAS;AAAA,MACX,CAAC;AACD;AAAA,IACF;AAEA,UAAM,QAAQ,iBAAiB,SAAS,WAAW;AACnD,QAAI,CAAC,OAAO;AACV,cAAQ,OAAO,MAAM;AAAA,QACnB,MAAM;AAAA,QACN,SAAS,wBAAwB,WAAW;AAAA,MAC9C,CAAC;AACD;AAAA,IACF;AAEA,UAAM,UAAU,iBAAiB,OAAO,aAAa,IAAI;AACzD,YAAQ,MAAM,qBAAqB,OAAO,CAAC;AAAA,EAC7C,CAAC;AAED,wBAAsB,qBAAqB,OAAO,EAAE,QAAQ,QAAQ,MAAM;AACxE,UAAM,mBAAmB,oBAAoB;AAC7C,QAAI,CAAC,kBAAkB;AACrB,cAAQ,OAAO,MAAM;AAAA,QACnB,MAAM;AAAA,QACN,SAAS;AAAA,MACX,CAAC;AACD;AAAA,IACF;AAEA,UAAM,EAAE,aAAa,aAAa,IAAI;AAItC,QAAI,CAAC,aAAa;AAChB,cAAQ,OAAO,MAAM;AAAA,QACnB,MAAM;AAAA,QACN,SAAS;AAAA,MACX,CAAC;AACD;AAAA,IACF;AAEA,QAAI,cAAc;AAChB,YAAMC,WAAU,iBAAiB,OAAO,WAAW;AACnD;AAAA,QACEA;AAAA,QACA,EAAE,IAAIA,UAAS,aAAa,eAAe,KAAK;AAAA,QAChDA,WACI,SACA;AAAA,UACE,MAAM;AAAA,UACN,SAAS,wBAAwB,WAAW;AAAA,QAC9C;AAAA,MACN;AACA;AAAA,IACF;AAEA,UAAM,UAAU,iBAAiB,OAAO,aAAa;AAAA,MACnD,WAAW;AAAA,IACb,CAAC;AACD;AAAA,MACE;AAAA,MACA,EAAE,IAAI,SAAS,aAAa,eAAe,MAAM;AAAA,MACjD,UACI,SACA;AAAA,QACE,MAAM;AAAA,QACN,SAAS,wBAAwB,WAAW;AAAA,MAC9C;AAAA,IACN;AAAA,EACF,CAAC;AAED;AAAA,IACE;AAAA,IACA,OAAO,EAAE,QAAQ,QAAQ,MAAM;AAC7B,YAAM,mBAAmB,oBAAoB;AAC7C,UAAI,CAAC,kBAAkB;AACrB,gBAAQ,OAAO,MAAM;AAAA,UACnB,MAAM;AAAA,UACN,SAAS;AAAA,QACX,CAAC;AACD;AAAA,MACF;AAEA,YAAM,EAAE,aAAa,IAAI,IACvB;AACF,UAAI,CAAC,aAAa;AAChB,gBAAQ,OAAO,MAAM;AAAA,UACnB,MAAM;AAAA,UACN,SAAS;AAAA,QACX,CAAC;AACD;AAAA,MACF;AAEA,YAAM,WAAW,kBAAkB,GAAG;AACtC,UAAI,UAAU;AACZ,gBAAQ,OAAO,MAAM;AAAA,UACnB,MAAM;AAAA,UACN,SAAS;AAAA,QACX,CAAC;AACD;AAAA,MACF;AAEA,YAAM,QAAQ,iBAAiB,SAAS,WAAW;AACnD,UAAI,CAAC,OAAO;AACV,gBAAQ,OAAO,MAAM;AAAA,UACnB,MAAM;AAAA,UACN,SAAS,wBAAwB,WAAW;AAAA,QAC9C,CAAC;AACD;AAAA,MACF;AAEA,UAAI,CAAC,sBAAsB,MAAM,MAAM,GAAG;AACxC,gBAAQ,OAAO,MAAM;AAAA,UACnB,MAAM;AAAA,UACN,SAAS,iDAAiD,MAAM,MAAM;AAAA,QACxE,CAAC;AACD;AAAA,MACF;AAEA,2BAAqB,aAAa,kBAAkB,KAAK,QAAQ;AAAA,QAC/D,cAAc;AAAA,MAChB,CAAC,EAAE,MAAM,CAACC,SAAQ;AAChB,eAAO;AAAA,UACL,mEAAqC,WAAW,KAAKA,MAAK,WAAWA,IAAG;AAAA,QAC1E;AAAA,MACF,CAAC;AAED,cAAQ,MAAM,EAAE,IAAI,MAAM,aAAa,SAAS,6CAAU,CAAC;AAAA,IAC7D;AAAA,EACF;AAEA,wBAAsB,uBAAuB,OAAO,EAAE,QAAQ,QAAQ,MAAM;AAC1E,UAAM,EAAE,IAAI,IAAI;AAChB,UAAM,WAAW,kBAAkB,GAAG;AACtC,QAAI,UAAU;AACZ,cAAQ,OAAO,MAAM;AAAA,QACnB,MAAM;AAAA,QACN,SAAS;AAAA,MACX,CAAC;AACD;AAAA,IACF;AAEA,UAAM,SAAS,MAAM,cAAc,KAAK,YAAY,MAAM;AAC1D;AAAA,MACE,OAAO;AAAA,MACP;AAAA,MACA,OAAO,KACH,SACA;AAAA,QACE,MAAM;AAAA,QACN,SAAS,OAAO,SAAS;AAAA,MAC3B;AAAA,IACN;AAAA,EACF,CAAC;AAED,MAAI,kBAAkB;AAAA,IACpB,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM,QAAQ,KAAsB,KAAqB;AACvD,UAAI,IAAI,WAAW,QAAQ;AACzB,YAAI,UAAU,KAAK,EAAE,gBAAgB,mBAAmB,CAAC;AACzD,YAAI,IAAI,KAAK,UAAU,EAAE,IAAI,OAAO,OAAO,qBAAqB,CAAC,CAAC;AAClE;AAAA,MACF;AAEA,UAAI,CAACH,4BAA2B,GAAG,GAAG;AACpC,cAAM,eAAe,4BAA4B,kBAAkB;AAAA,MACrE;AAEA,YAAM,mBAAmB,oBAAoB;AAC7C,UAAI,CAAC,kBAAkB;AACrB,YAAI,UAAU,KAAK,EAAE,gBAAgB,mBAAmB,CAAC;AACzD,YAAI,IAAI,KAAK,UAAU,EAAE,IAAI,OAAO,OAAO,oBAAoB,CAAC,CAAC;AACjE;AAAA,MACF;AAEA,UAAI;AACJ,UAAI;AACF,cAAM,MAAM,MAAM,SAAS,GAAG;AAC9B,eAAO,KAAK,MAAM,GAAG;AAAA,MACvB,QAAQ;AACN,YAAI,UAAU,KAAK,EAAE,gBAAgB,mBAAmB,CAAC;AACzD,YAAI,IAAI,KAAK,UAAU,EAAE,IAAI,OAAO,OAAO,eAAe,CAAC,CAAC;AAC5D;AAAA,MACF;AAEA,YAAM,cAAcC,iBAAgB,KAAK,WAAW;AACpD,UAAI,CAAC,aAAa;AAChB,YAAI,UAAU,KAAK,EAAE,gBAAgB,mBAAmB,CAAC;AACzD,YAAI;AAAA,UACF,KAAK,UAAU;AAAA,YACb,IAAI;AAAA,YACJ,OAAO;AAAA,UACT,CAAC;AAAA,QACH;AACA;AAAA,MACF;AAEA,UAAI,CAAC,KAAK,aAAa,CAAC,KAAK,UAAU,eAAe;AACpD,YAAI,UAAU,KAAK,EAAE,gBAAgB,mBAAmB,CAAC;AACzD,YAAI;AAAA,UACF,KAAK,UAAU;AAAA,YACb,IAAI;AAAA,YACJ,OAAO;AAAA,UACT,CAAC;AAAA,QACH;AACA;AAAA,MACF;AAEA,YAAM,WAAW,KAAK,MAAM,kBAAkB,KAAK,GAAG,IAAI;AAC1D,UAAI,UAAU;AACZ,YAAI,UAAU,KAAK,EAAE,gBAAgB,mBAAmB,CAAC;AACzD,YAAI,IAAI,KAAK,UAAU,EAAE,IAAI,OAAO,OAAO,SAAS,CAAC,CAAC;AACtD;AAAA,MACF;AAEA,YAAM,SAAS,MAAM;AAAA,QACnB;AAAA,QACA,KAAK;AAAA,QACL;AAAA,QACA,KAAK;AAAA,QACL;AAAA,QACA,4BAA4B,IACxB,EAAE,cAAc,sBAAsB,IACtC;AAAA,MACN;AAEA,UAAI,UAAU,OAAO,KAAK,MAAM,KAAK;AAAA,QACnC,gBAAgB;AAAA,MAClB,CAAC;AACD,UAAI,IAAI,KAAK,UAAU,MAAM,CAAC;AAAA,IAChC;AAAA,EACF,CAAQ;AAER,SAAO;AAAA,IACL;AAAA,EACF;AACA,SAAO,KAAK,mEAAgC;AAC9C;;;AChiBA,IAAM,sBAAsB,oBAAI,IAAI,CAAC,OAAO,qBAAqB,CAAC;AAClE,IAAM,4BAA4B;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AACF;AACA,IAAM,gCAAgC,IAAI,IAAY,yBAAyB;AAE/E,SAAS,sBAAsB,OAAO,QAAQ,MAA0B;AACtE,QAAM,OAAO,KAAK,MAAM,CAAC;AAEzB,WAAS,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS;AAChD,UAAM,MAAM,KAAK,KAAK;AACtB,QAAI,CAAC,OAAO,QAAQ,MAAM;AACxB,aAAO;AAAA,IACT;AAEA,QAAI,8BAA8B,IAAI,GAAG,GAAG;AAC1C;AACA;AAAA,IACF;AAEA,QACE,0BAA0B,KAAK,CAAC,WAAW,IAAI,WAAW,GAAG,MAAM,GAAG,CAAC,GACvE;AACA;AAAA,IACF;AAEA,QAAI,IAAI,WAAW,GAAG,GAAG;AACvB;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEO,SAAS,sBAAsB,OAAO,QAAQ,MAAe;AAClE,QAAM,iBAAiB,sBAAsB,IAAI;AACjD,SAAO,iBAAiB,oBAAoB,IAAI,cAAc,IAAI;AACpE;;;A7EHA,IAAM,6BAA6B;AAAA,EACjC;AAAA,EACA,iTAA4D,sBAAsB,MAAM,WAAM,sBAAsB,MAAM;AAAA,EAC1H;AAAA,EACA;AACF,EAAE,KAAK,IAAI;AAEX,IAAO,gBAAQ;AAAA,EACb,IAAI;AAAA,EACJ,MAAM;AAAA,EAEN,SAAS,KAAwB;AAC/B,UAAM,SAAU,IAAI,gBAAgB,CAAC;AACrC,UAAM,cAAc,IAAI,IAAI,OAAO,eAAe,CAAC,CAAC;AAEpD,QAAI,UAAsC;AAC1C,QAAI,mBAA4C;AAChD,QAAI,cAAkC;AACtC,QAAI,sBAA6E;AACjF,QAAI,gBAAiE;AAErE,UAAM,cAAc,sBAAsB,GAAG;AAC7C,UAAM,SAAiB,cACnB,IAAI,iBAAa,IAAI,QAAQ,WAAW,IACxC,yBAAyB,IAAI,MAAM;AAEvC,UAAM,eAA6D;AAAA,MACjE,UAAU;AAAA,IACZ;AACA,UAAM,aACJ,eACA,QAAQ,IAAI,sBACZ,QAAQ,IAAI,mBACZ,QAAQ,IAAI;AAEd,QAAI,sBAAsB,GAAG;AAC3B,wBAAkB,KAAK;AAAA,QACrB;AAAA,QACA;AAAA,MACF,CAAC;AACD,aAAO;AAAA,QACL;AAAA,MACF;AACA;AAAA,IACF;AAEA,QAAI,GAAG,uBAAuB,OAAO;AAAA,MACnC,qBAAqB;AAAA,IACvB,EAAE;AAEF,aAAS,eAAe,WAA0C;AAChE,UAAI,CAAC,WAAW;AACd;AAAA,MACF;AAEA,YAAM,UAAU,gBAAgB;AAChC,oBAAc;AACd,UAAI,SAAS;AACX,6BAAqB,qBAAqB;AAAA,MAC5C;AAAA,IACF;AAEA,aAAS,6BACP,MACS;AACT,YAAM,SAAS,KAAK,QAAQ,SAAS;AACrC,UAAI,CAAC,OAAQ,QAAO;AACpB,UAAI,OAAO,eAAe,yCAAyC;AACjE,eAAO;AAAA,MACT;AACA,aAAO,OAAO,OAAO,kBAAkB,OAAO,OAAO;AAAA,IACvD;AAEA,mBAAe,uCACb,QACA,MACe;AACf,UAAI,CAAC,iBAAiB,CAAC,6BAA6B,IAAI,EAAG;AAE3D,YAAM,SAAS,KAAK,QAAQ,SAAS;AACrC,UAAI;AACF,cAAM,cAAc;AAAA,UAClB,kBAAkB,MAAM,SAAS,QAAQ,MAAM,SAAS;AAAA,QAC1D;AAAA,MACF,SAASG,MAAU;AACjB,eAAO;AAAA,UACL,kEAAkE,MAAM,KAAKA,MAAK,WAAW,OAAOA,IAAG,CAAC;AAAA,QAC1G;AAAA,MACF;AAAA,IACF;AAEA,aAAS,0CACP,QACA,SACM;AACN,UAAI,sBAAsB,QAAQ,OAAO,SAAS;AAChD,uBAAe,KAAK,SAAS,SAAS;AACtC,cAAM,uCAAuC,QAAQ,IAAI;AACzD,eAAO,QAAQ,IAAI;AAAA,MACrB,CAAC;AAAA,IACH;AAEA,aAAS,oBAAoB,OAA6C;AACxE,aAAO,MAAM,OAAO,CAAC,iBAAiB,CAAC,YAAY,IAAI,aAAa,GAAG,CAAC;AAAA,IAC1E;AAEA,aAAS,sBAAsB,OAAmC;AAChE,UAAI,CAAC,aAAa;AAChB,eAAO;AAAA,UACL,8FAA4C,MAAM,WAAW,OAAO,MAAM,eAAe;AAAA,QAC3F;AACA;AAAA,MACF;AAEA,kBAAY,oBAAoB,KAAK;AAAA,IACvC;AAEA,UAAM,oBAAoB,IAAI,kBAAkB,YAAY;AAC5D,UAAM,mBAAmB,IAAI,YAAY,KAAK,MAAM;AACpD,UAAM,2BAA2B,IAAI,yBAAyB;AAAA,MAC5D;AAAA,MACA,UAAU;AAAA,MACV,SAAS;AAAA,IACX,CAAC;AACD,UAAM,+BAA+B,IAAI,6BAA6B;AAAA,MACpE,WAAW;AAAA,MACX;AAAA,IACF,CAAC;AAED,6BAAyB;AAAA,MACvB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW,aAAa;AACtB,kBAAU;AAAA,MACZ;AAAA,MACA,oBAAoB,sBAAsB;AACxC,2BAAmB;AAAA,MACrB;AAAA,MACA,iBAAiB;AAGf,0BAAkB,OAAO;AAAA,MAC3B;AAAA,IACF,CAAC;AAED,oBAAgB,6BAA6B;AAAA,MAC3C;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,mCAA+B;AAAA,MAC7B;AAAA,MACA;AAAA,MACA,YAAY,MAAM;AAAA,MAClB;AAAA,MACA,uBAAuB;AAAA,MACvB;AAAA,MACA,cAAc,UAAU,UAAU;AAChC,qCAA6B,QAAQ,UAAU,QAAQ;AAAA,MACzD;AAAA,IACF,CAAC;AAED,6BAAyB,KAAK,MAAM;AAEpC,gCAA4B;AAAA,MAC1B;AAAA,MACA;AAAA,MACA;AAAA,MACA,qBAAqB,MAAM;AAAA,MAC3B;AAAA,MACA,uBAAuB;AAAA,MACvB,6BAA6B,MAAM,CAAC,CAAC;AAAA,MACrC;AAAA,IACF,CAAC;AAED,8BAA0B,KAAK,mBAAmB,QAAQ,cAAc;AACxE,4BAAwB,KAAK,mBAAmB,MAAM;AACtD,WAAO;AAAA,MACL,mEAAsB,+BAA+B,KAAK,IAAI,CAAC,WAAW,0BAA0B,KAAK,IAAI,CAAC;AAAA,IAChH;AAEA,0BAAsB,4BAA4B;AAAA,MAChD;AAAA,MACA;AAAA,MACA;AAAA,MACA,gBAAgB,MAAM;AAAA,MACtB;AAAA,MACA;AAAA,IACF,CAAC;AAED,sBAAkB,KAAK;AAAA,MACrB;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AACF;","names":["import_node_fs","import_node_path","path","import_node_fs","import_node_path","path","import_node_fs","import_node_path","normalizeOptionalText","os","formatBytes","err","renameSync","output","path","import_node_child_process","import_node_fs","import_node_path","import_promises","import_node_stream","import_node_os","getWhisperLocalStatus","downloadModel","resolveModelsDir","transcribeWithWhisperLocal","err","normalizeOptionalText","sleep","normalizeOptionalInteger","import_node_fs","import_node_path","exports","module","exports","module","output","exports","module","exports","module","err","data","exports","module","exports","module","Receiver","err","exports","module","Sender","err","exports","module","exports","module","exports","module","randomBytes","createHash","Readable","URL","Receiver","Sender","WebSocket","err","key","exports","module","WebSocket","err","createWebSocketStream","exports","module","protocol","exports","module","createHash","WebSocket","WebSocketServer","err","import_node_fs","path","import_node_fs","import_node_path","formatDate","import_node_fs","import_node_path","err","err","import_node_crypto","err","err","prepared","import_node_path","trimToUndefined","resolveStateDir","trimToUndefined","import_node_fs","import_node_path","updateConfigRecord","err","err","import_node_path","import_node_fs","path","import_node_fs","import_node_path","import_node_fs","import_node_path","tasksDir","readMeta","writeMeta","checkpointPath","import_node_fs","import_node_os","import_node_path","resolveConfigPath","err","import_node_fs","import_node_path","err","ok","import_node_fs","import_node_path","import_node_fs","import_node_fs","isObject","isObject","import_node_fs","isObject","isObject","err","import_node_readline","import_node_fs","import_node_child_process","import_node_fs","import_node_path","import_node_os","BASE_URL","err","os","import_node_fs","import_node_fs","import_node_path","path","import_node_fs","import_node_crypto","import_node_path","import_node_fs","import_node_path","import_node_fs","import_node_path","import_promises","DEFAULT_TIMEOUT_MS","err","err","err","current","import_node_fs","import_node_path","import_node_fs","import_node_path","import_sender","WebSocket","previewText","err","import_node_crypto","import_node_crypto","import_node_fs","import_node_path","crypto","fs","path","err","path","err","err","isProcessAlive","err","err","trimToUndefined","import_node_crypto","err","isRelayInternalHttpRequest","trimToUndefined","deleted","err","err"]}