codesesh 0.1.0 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +83 -0
- package/dist/{chunk-H3D3GNQK.js → chunk-BQ22Y6H4.js} +142 -37
- package/dist/chunk-BQ22Y6H4.js.map +1 -0
- package/dist/{dist-KGHAVLGF.js → dist-RRY4LURU.js} +2 -2
- package/dist/index.js +5 -5
- package/dist/index.js.map +1 -1
- package/dist/web/assets/{index-Cbmq6KvN.js → index-D12EHlVg.js} +1 -1
- package/dist/web/index.html +2 -2
- package/dist/web/logo.svg +78 -29
- package/package.json +36 -5
- package/.turbo/turbo-build.log +0 -16
- package/dist/chunk-H3D3GNQK.js.map +0 -1
- package/scripts/copy-web-dist.js +0 -31
- package/src/api/__tests__/handlers.test.ts +0 -191
- package/src/api/__tests__/routes.test.ts +0 -16
- package/src/api/handlers.ts +0 -76
- package/src/api/routes.ts +0 -13
- package/src/commands/serve.ts +0 -78
- package/src/index.ts +0 -203
- package/src/output.ts +0 -47
- package/src/server.ts +0 -56
- package/tsconfig.json +0 -9
- package/tsup.config.ts +0 -16
- /package/dist/{dist-KGHAVLGF.js.map → dist-RRY4LURU.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../core/src/agents/registry.ts","../../core/src/agents/claudecode.ts","../../core/src/agents/base.ts","../../core/src/discovery/paths.ts","../../core/src/utils/jsonl.ts","../../core/src/utils/title-fallback.ts","../../core/src/utils/perf.ts","../../core/src/agents/opencode.ts","../../core/src/utils/sqlite.ts","../../core/src/agents/kimi.ts","../../core/src/agents/codex.ts","../../core/src/agents/cursor.ts","../../core/src/agents/register.ts","../../core/src/discovery/scanner.ts","../../core/src/discovery/cache.ts"],"sourcesContent":["import type { BaseAgent } from \"./base.js\";\nimport type { AgentInfo } from \"../types/index.js\";\n\nexport interface AgentRegistration {\n name: string;\n displayName: string;\n create: () => BaseAgent;\n icon: string;\n}\n\nlet registrations: AgentRegistration[] = [];\n\nexport function registerAgent(reg: AgentRegistration): void {\n registrations.push(reg);\n}\n\nexport function createRegisteredAgents(): BaseAgent[] {\n return registrations.map((r) => r.create());\n}\n\nexport function getRegisteredAgents(): readonly AgentRegistration[] {\n return registrations;\n}\n\nexport function getAgentInfoMap(sessionsByAgent: Record<string, number>): AgentInfo[] {\n return registrations.map((r) => ({\n name: r.name,\n displayName: r.displayName,\n icon: r.icon,\n count: sessionsByAgent[r.name] ?? 0,\n }));\n}\n\nexport function getAgentByName(name: string): AgentRegistration | undefined {\n return registrations.find((r) => r.name === name);\n}\n","import { existsSync, readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { join, basename } from \"node:path\";\nimport { BaseAgent } from \"./base.js\";\nimport type { SessionHead, SessionData, Message, MessagePart } from \"../types/index.js\";\nimport { resolveProviderRoots, firstExisting } from \"../discovery/paths.js\";\nimport { parseJsonlLines } from \"../utils/jsonl.js\";\nimport { resolveSessionTitle, basenameTitle } from \"../utils/title-fallback.js\";\nimport { perf } from \"../utils/perf.js\";\nimport type { SessionCacheMeta, ChangeCheckResult } from \"./base.js\";\n\ninterface SessionMeta extends SessionCacheMeta {\n id: string;\n title: string;\n sourcePath: string;\n directory: string;\n model: string | null | undefined;\n messageCount: number;\n createdAt: number;\n updatedAt: number;\n}\n\nfunction parseTimestampMs(data: Record<string, unknown>): number {\n const raw = String(data[\"timestamp\"] ?? \"\").trim();\n if (!raw) return 0;\n try {\n return new Date(raw.includes(\"Z\") ? raw : raw + \"Z\").getTime();\n } catch {\n return 0;\n }\n}\n\nfunction normalizeTitleText(text: string): string {\n // First non-empty line, truncated\n const line = text.split(\"\\n\").find((l) => l.trim());\n return line?.trim().slice(0, 80) || \"\";\n}\n\nexport class ClaudeCodeAgent extends BaseAgent {\n readonly name = \"claudecode\";\n readonly displayName = \"Claude Code\";\n\n private basePath: string | null = null;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private sessionsIndexCache: Record<string, any> = {};\n private sessionMetaMap = new Map<string, SessionMeta>();\n\n private findBasePath(): string | null {\n const roots = resolveProviderRoots();\n return firstExisting(join(roots.claudeRoot, \"projects\"), \"data/claudecode\");\n }\n\n isAvailable(): boolean {\n this.basePath = this.findBasePath();\n if (!this.basePath) return false;\n try {\n for (const entry of readdirSync(this.basePath)) {\n const dir = join(this.basePath, entry);\n if (existsSync(dir) && readdirSync(dir).some((f) => f.endsWith(\".jsonl\"))) {\n return true;\n }\n }\n } catch {\n // ignore\n }\n return false;\n }\n\n scan(): SessionHead[] {\n if (!this.basePath) return [];\n\n const scanMarker = perf.start(\"claudecode:scan\");\n const heads: SessionHead[] = [];\n\n const listMarker = perf.start(\"listProjectDirs\");\n const projectDirs = this.listProjectDirs();\n perf.end(listMarker);\n\n for (const projectDir of projectDirs) {\n const fileMarker = perf.start(`listJsonlFiles:${basename(projectDir)}`);\n const files = this.listJsonlFiles(projectDir);\n perf.end(fileMarker);\n\n for (const file of files) {\n try {\n const parseMarker = perf.start(`parseSessionHead:${basename(file)}`);\n const head = this.parseSessionHead(file, projectDir);\n perf.end(parseMarker);\n\n if (head) {\n heads.push(head);\n this.sessionMetaMap.set(head.id, {\n id: head.id,\n title: head.title,\n sourcePath: file,\n directory: head.directory,\n model: head.stats.total_tokens ? \"unknown\" : undefined,\n messageCount: head.stats.message_count,\n createdAt: head.time_created,\n updatedAt: head.time_updated ?? head.time_created,\n });\n }\n } catch {\n // skip malformed files\n }\n }\n }\n\n perf.end(scanMarker);\n return heads;\n }\n\n getSessionMetaMap(): Map<string, SessionCacheMeta> {\n return this.sessionMetaMap;\n }\n\n setSessionMetaMap(meta: Map<string, SessionCacheMeta>): void {\n this.sessionMetaMap = meta as Map<string, SessionMeta>;\n }\n\n getSessionData(sessionId: string): SessionData {\n const meta = this.sessionMetaMap.get(sessionId);\n if (!meta) {\n throw new Error(`Session not found: ${sessionId}`);\n }\n if (!existsSync(meta.sourcePath)) {\n throw new Error(`Session file missing: ${meta.sourcePath}`);\n }\n\n const content = readFileSync(meta.sourcePath, \"utf-8\");\n const messages: Message[] = [];\n const pendingToolCalls = new Map<string, [number, number]>();\n const ignoredToolCallIds = new Set<string>();\n const assistantUuidToToolCalls = new Map<string, string[]>();\n const assistantState = {\n currentIndex: null as number | null,\n latestTextIndex: null as number | null,\n };\n\n let totalCost = 0;\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n\n for (const record of parseJsonlLines(content)) {\n try {\n this.convertRecord(\n record,\n messages,\n pendingToolCalls,\n ignoredToolCallIds,\n assistantUuidToToolCalls,\n assistantState,\n );\n } catch {\n // skip malformed records\n }\n }\n\n // Aggregate stats from messages\n for (const msg of messages) {\n totalCost += msg.cost ?? 0;\n totalInputTokens += msg.tokens?.input ?? 0;\n totalOutputTokens += msg.tokens?.output ?? 0;\n }\n\n return {\n id: meta.id,\n title: meta.title,\n slug: `claudecode/${meta.id}`,\n directory: meta.directory,\n version: undefined,\n time_created: meta.createdAt,\n time_updated: meta.updatedAt,\n stats: {\n message_count: messages.length,\n total_input_tokens: totalInputTokens,\n total_output_tokens: totalOutputTokens,\n total_cost: totalCost,\n },\n messages,\n };\n }\n\n /**\n * 检测文件系统变更\n * 通过比较文件修改时间判断是否有新内容\n */\n checkForChanges(sinceTimestamp: number, cachedSessions: SessionHead[]): ChangeCheckResult {\n if (!this.basePath) {\n return { hasChanges: false, timestamp: Date.now() };\n }\n\n const changedIds: string[] = [];\n\n for (const session of cachedSessions) {\n const meta = this.sessionMetaMap.get(session.id);\n if (!meta) continue;\n\n try {\n const stat = statSync(meta.sourcePath);\n // 如果文件修改时间晚于缓存时间,说明有变更\n if (stat.mtimeMs > sinceTimestamp) {\n changedIds.push(session.id);\n }\n } catch {\n // 文件可能被删除,也视为变更\n changedIds.push(session.id);\n }\n }\n\n // 检查是否有新文件(简单实现:比较缓存数量和实际文件数量)\n try {\n let totalFiles = 0;\n for (const dir of this.listProjectDirs()) {\n totalFiles += this.listJsonlFiles(dir).length;\n }\n const hasNewFiles = totalFiles > cachedSessions.length;\n\n return {\n hasChanges: changedIds.length > 0 || hasNewFiles,\n changedIds,\n timestamp: Date.now(),\n };\n } catch {\n return {\n hasChanges: changedIds.length > 0,\n changedIds,\n timestamp: Date.now(),\n };\n }\n }\n\n /**\n * 增量扫描 - 只扫描变更的会话\n */\n incrementalScan(cachedSessions: SessionHead[], changedIds: string[]): SessionHead[] {\n if (!this.basePath) return cachedSessions;\n\n // 创建缓存会话的 Map 便于更新\n const sessionMap = new Map(cachedSessions.map((s) => [s.id, s]));\n\n // 重新扫描变更的会话\n for (const projectDir of this.listProjectDirs()) {\n for (const file of this.listJsonlFiles(projectDir)) {\n try {\n const sessionId = basename(file, \".jsonl\");\n\n // 只处理变更的会话\n if (changedIds.includes(sessionId)) {\n const head = this.parseSessionHead(file, projectDir);\n if (head) {\n sessionMap.set(head.id, head);\n this.sessionMetaMap.set(head.id, {\n id: head.id,\n title: head.title,\n sourcePath: file,\n directory: head.directory,\n model: head.stats.total_tokens ? \"unknown\" : undefined,\n messageCount: head.stats.message_count,\n createdAt: head.time_created,\n updatedAt: head.time_updated ?? head.time_created,\n });\n }\n }\n } catch {\n // skip malformed files\n }\n }\n }\n\n // 检查是否有新文件需要添加\n for (const projectDir of this.listProjectDirs()) {\n for (const file of this.listJsonlFiles(projectDir)) {\n try {\n const sessionId = basename(file, \".jsonl\");\n if (!sessionMap.has(sessionId)) {\n const head = this.parseSessionHead(file, projectDir);\n if (head) {\n sessionMap.set(head.id, head);\n this.sessionMetaMap.set(head.id, {\n id: head.id,\n title: head.title,\n sourcePath: file,\n directory: head.directory,\n model: head.stats.total_tokens ? \"unknown\" : undefined,\n messageCount: head.stats.message_count,\n createdAt: head.time_created,\n updatedAt: head.time_updated ?? head.time_created,\n });\n }\n }\n } catch {\n // skip malformed files\n }\n }\n }\n\n return Array.from(sessionMap.values());\n }\n\n // --- Private helpers ---\n\n private listProjectDirs(): string[] {\n if (!this.basePath) return [];\n try {\n return readdirSync(this.basePath)\n .map((e) => join(this.basePath!, e))\n .filter((p) => existsSync(p));\n } catch {\n return [];\n }\n }\n\n private listJsonlFiles(dir: string): string[] {\n try {\n return readdirSync(dir)\n .filter((f) => f.endsWith(\".jsonl\") && f !== \"sessions-index.json\")\n .map((f) => join(dir, f));\n } catch {\n return [];\n }\n }\n\n private loadSessionsIndex(projectDir: string): Map<string, Record<string, unknown>> {\n const cacheKey = basename(projectDir);\n if (cacheKey in this.sessionsIndexCache) {\n return this.sessionsIndexCache[cacheKey];\n }\n\n const indexPath = join(projectDir, \"sessions-index.json\");\n const map = new Map<string, Record<string, unknown>>();\n\n if (existsSync(indexPath)) {\n try {\n const data = JSON.parse(readFileSync(indexPath, \"utf-8\"));\n const entries: Record<string, unknown>[] = data?.entries ?? [];\n for (const entry of entries) {\n const sid = entry?.sessionId;\n if (typeof sid === \"string\") {\n map.set(sid, entry);\n }\n }\n } catch {\n // ignore\n }\n }\n\n this.sessionsIndexCache[cacheKey] = map;\n return map;\n }\n\n private parseSessionHead(filePath: string, projectDir: string): SessionHead | null {\n const content = readFileSync(filePath, \"utf-8\");\n const lines = content.split(\"\\n\").filter((l) => l.trim());\n\n if (lines.length === 0) return null;\n\n const sessionId = basename(filePath, \".jsonl\");\n\n let firstRecord: Record<string, unknown>;\n try {\n firstRecord = JSON.parse(lines[0]!);\n } catch {\n return null;\n }\n\n const createdAt = parseTimestampMs(firstRecord) || statSync(filePath).mtimeMs;\n\n // Try to get title from sessions-index.json\n const index = this.loadSessionsIndex(projectDir);\n const indexEntry = index.get(sessionId);\n const explicitTitle = indexEntry?.summary ? String(indexEntry.summary) : null;\n\n // Extract lightweight metadata; cwd lives in user-type records, not the first line\n let updatedAt = createdAt;\n let messageCount = 0;\n let model: string | null = null;\n let cwd: string | null = null;\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n\n for (const line of lines) {\n try {\n const data = JSON.parse(line);\n const ts = parseTimestampMs(data);\n if (ts > updatedAt) updatedAt = ts;\n\n // cwd is a top-level field on user records\n if (!cwd && data[\"cwd\"] && typeof data[\"cwd\"] === \"string\") {\n cwd = data[\"cwd\"];\n }\n\n const msg = data[\"message\"];\n if (msg && typeof msg === \"object\") {\n const role = (msg as Record<string, unknown>)[\"role\"];\n if (typeof role === \"string\" && role.trim()) {\n messageCount++;\n }\n if (!model) {\n const m = (msg as Record<string, unknown>)[\"model\"];\n if (typeof m === \"string\" && m.trim()) model = m.trim();\n }\n if (role === \"assistant\") {\n const usage = (msg as Record<string, unknown>)[\"usage\"] as\n | Record<string, unknown>\n | undefined;\n if (usage && typeof usage === \"object\") {\n totalInputTokens +=\n ((usage[\"input_tokens\"] as number) ?? 0) +\n ((usage[\"cache_creation_input_tokens\"] as number) ?? 0) +\n ((usage[\"cache_read_input_tokens\"] as number) ?? 0);\n totalOutputTokens += (usage[\"output_tokens\"] as number) ?? 0;\n }\n }\n }\n } catch {\n // skip\n }\n }\n\n const directory = cwd ?? projectDir;\n\n // Extract first user message as fallback title\n const messageTitle = this.extractTitle(lines);\n const directoryTitle = basenameTitle(directory) || basenameTitle(projectDir);\n\n const title = resolveSessionTitle(explicitTitle, messageTitle, directoryTitle);\n\n return {\n id: sessionId,\n slug: `claudecode/${sessionId}`,\n title,\n directory,\n time_created: createdAt,\n time_updated: updatedAt,\n stats: {\n message_count: messageCount,\n total_input_tokens: totalInputTokens,\n total_output_tokens: totalOutputTokens,\n total_cost: 0,\n },\n };\n }\n\n private extractTitle(lines: string[]): string | null {\n for (const line of lines.slice(0, 20)) {\n try {\n const data = JSON.parse(line);\n const msg = data[\"message\"];\n if (!msg || typeof msg !== \"object\") continue;\n if ((msg as Record<string, unknown>)[\"role\"] !== \"user\") continue;\n\n const content = (msg as Record<string, unknown>)[\"content\"];\n if (!content) continue;\n\n if (typeof content === \"string\") {\n return normalizeTitleText(content);\n }\n if (Array.isArray(content)) {\n const texts = content\n .filter((item) => typeof item === \"object\" && item !== null && \"text\" in item)\n .map((item) => String((item as Record<string, unknown>)[\"text\"] ?? \"\"))\n .join(\" \");\n return normalizeTitleText(texts);\n }\n } catch {\n // skip\n }\n }\n return null;\n }\n\n // --- Record conversion ---\n\n private convertRecord(\n data: Record<string, unknown>,\n messages: Message[],\n pendingToolCalls: Map<string, [number, number]>,\n ignoredToolCallIds: Set<string>,\n assistantUuidToToolCalls: Map<string, string[]>,\n assistantState: { currentIndex: number | null; latestTextIndex: number | null },\n ): void {\n if (data[\"isMeta\"] === true) return;\n\n const msgType = String(data[\"type\"] ?? \"\");\n\n if (msgType === \"assistant\") {\n this.convertAssistantRecord(\n data,\n messages,\n pendingToolCalls,\n ignoredToolCallIds,\n assistantUuidToToolCalls,\n assistantState,\n );\n } else if (msgType === \"user\") {\n this.convertUserRecord(\n data,\n messages,\n pendingToolCalls,\n ignoredToolCallIds,\n assistantUuidToToolCalls,\n assistantState,\n );\n } else if (msgType === \"tool_result\") {\n this.convertToolResultRecord(data, messages, assistantState);\n }\n }\n\n private convertAssistantRecord(\n data: Record<string, unknown>,\n messages: Message[],\n pendingToolCalls: Map<string, [number, number]>,\n ignoredToolCallIds: Set<string>,\n assistantUuidToToolCalls: Map<string, string[]>,\n assistantState: { currentIndex: number | null; latestTextIndex: number | null },\n ): void {\n const msg = (data[\"message\"] ?? {}) as Record<string, unknown>;\n const timestampMs = parseTimestampMs(data);\n const rawContent = (msg[\"content\"] ?? []) as unknown[];\n const uuid = String(data[\"uuid\"] ?? \"\");\n\n const toolCallIds: string[] = [];\n let currentAssistantIndex = assistantState.currentIndex;\n let latestAssistantTextIndex = assistantState.latestTextIndex;\n\n if (Array.isArray(rawContent)) {\n for (const item of rawContent) {\n if (!item || typeof item !== \"object\") continue;\n const part = item as Record<string, unknown>;\n const partType = String(part[\"type\"] ?? \"\");\n\n if (partType === \"thinking\") {\n const text = String(part[\"thinking\"] ?? \"\");\n if (text.trim()) {\n currentAssistantIndex = this.appendAssistantReasoning(\n messages,\n { messageId: uuid, msg, timestampMs, text },\n currentAssistantIndex,\n );\n }\n continue;\n }\n\n if (partType === \"text\") {\n const text = String(part[\"text\"] ?? \"\");\n if (text.trim()) {\n currentAssistantIndex = this.appendAssistantText(\n messages,\n { messageId: uuid, msg, timestampMs, text },\n currentAssistantIndex,\n );\n latestAssistantTextIndex = currentAssistantIndex;\n }\n continue;\n }\n\n if (partType !== \"tool_use\") continue;\n\n const toolName = String(part[\"name\"] ?? \"\").trim();\n const toolCallId = String(part[\"id\"] ?? \"\").trim();\n\n if (toolName && toolCallId && this.shouldIgnoreTool(toolName)) {\n ignoredToolCallIds.add(toolCallId);\n continue;\n }\n\n const toolPart = this.buildToolPart(part, timestampMs);\n const [msgIndex, partIndex] = this.attachToolCallToLatestAssistant(messages, {\n messageId: uuid,\n msg,\n timestampMs,\n toolPart,\n latestTextIndex: latestAssistantTextIndex,\n });\n currentAssistantIndex = msgIndex;\n if (toolCallId) {\n pendingToolCalls.set(toolCallId, [msgIndex, partIndex]);\n toolCallIds.push(toolCallId);\n }\n }\n }\n\n if (toolCallIds.length > 0) {\n assistantUuidToToolCalls.set(uuid, toolCallIds);\n }\n\n assistantState.currentIndex = currentAssistantIndex;\n assistantState.latestTextIndex = latestAssistantTextIndex;\n }\n\n private convertUserRecord(\n data: Record<string, unknown>,\n messages: Message[],\n pendingToolCalls: Map<string, [number, number]>,\n ignoredToolCallIds: Set<string>,\n assistantUuidToToolCalls: Map<string, string[]>,\n assistantState: { currentIndex: number | null; latestTextIndex: number | null },\n ): void {\n const msg = (data[\"message\"] ?? {}) as Record<string, unknown>;\n const timestampMs = parseTimestampMs(data);\n const content = msg[\"content\"] ?? \"\";\n const uuid = String(data[\"uuid\"] ?? \"\");\n\n // String content — simple user message\n if (typeof content === \"string\") {\n const parts = this.normalizeUserTextParts(content, timestampMs);\n if (parts.length === 0) {\n assistantState.currentIndex = null;\n assistantState.latestTextIndex = null;\n return;\n }\n messages.push(this.buildMessage({ messageId: uuid, role: \"user\", timestampMs, parts }));\n assistantState.currentIndex = null;\n assistantState.latestTextIndex = null;\n return;\n }\n\n if (!Array.isArray(content)) {\n assistantState.currentIndex = null;\n assistantState.latestTextIndex = null;\n return;\n }\n\n const visibleParts = this.normalizeUserTextParts(content, timestampMs);\n const toolStateUpdates = this.extractToolStateUpdates(data[\"toolUseResult\"]);\n\n for (const item of content) {\n if (!item || typeof item !== \"object\") continue;\n const ci = item as Record<string, unknown>;\n if (ci[\"type\"] !== \"tool_result\") continue;\n\n const toolCallId = this.resolveToolCallId(data, ci, assistantUuidToToolCalls);\n if (toolCallId && ignoredToolCallIds.has(toolCallId)) continue;\n\n const outputParts = this.normalizeClaudeToolOutput(ci[\"content\"], timestampMs);\n if (\n this.backfillToolOutput(\n messages,\n pendingToolCalls,\n toolCallId,\n outputParts,\n toolStateUpdates,\n )\n ) {\n continue;\n }\n\n const fallback = this.buildFallbackToolMessage({\n messageId: uuid,\n timestampMs,\n toolCallId,\n outputParts,\n });\n if (fallback) messages.push(fallback);\n }\n\n if (visibleParts.length > 0) {\n messages.push(\n this.buildMessage({ messageId: uuid, role: \"user\", timestampMs, parts: visibleParts }),\n );\n }\n\n assistantState.currentIndex = null;\n assistantState.latestTextIndex = null;\n }\n\n private convertToolResultRecord(\n data: Record<string, unknown>,\n messages: Message[],\n assistantState: { currentIndex: number | null; latestTextIndex: number | null },\n ): void {\n const timestampMs = parseTimestampMs(data);\n const msg = (data[\"message\"] ?? {}) as Record<string, unknown>;\n const outputParts = this.normalizeClaudeToolOutput(msg[\"content\"], timestampMs);\n const uuid = String(data[\"uuid\"] ?? \"\");\n\n const fallback = this.buildFallbackToolMessage({\n messageId: uuid,\n timestampMs,\n toolCallId: null,\n outputParts,\n });\n if (fallback) messages.push(fallback);\n\n assistantState.currentIndex = null;\n assistantState.latestTextIndex = null;\n }\n\n // --- Message building ---\n\n private buildMessage(opts: {\n messageId: string;\n role: string;\n timestampMs: number;\n parts: MessagePart[];\n agent?: string;\n mode?: string;\n model?: string | null;\n provider?: string | null;\n tokens?: Record<string, unknown>;\n cost?: number;\n }): Message {\n return {\n id: opts.messageId,\n role: opts.role as Message[\"role\"],\n agent: opts.agent ?? null,\n time_created: opts.timestampMs,\n mode: opts.mode ?? null,\n model: opts.model ?? null,\n provider: opts.provider ?? null,\n tokens: opts.tokens ? (opts.tokens as Message[\"tokens\"]) : undefined,\n cost: opts.cost ?? 0,\n parts: opts.parts,\n };\n }\n\n private buildTextPart(text: string, timestampMs: number): MessagePart {\n return { type: \"text\", text, time_created: timestampMs };\n }\n\n private buildReasoningPart(text: string, timestampMs: number): MessagePart {\n return { type: \"reasoning\", text, time_created: timestampMs };\n }\n\n private buildToolPart(part: Record<string, unknown>, timestampMs: number): MessagePart {\n const toolName = String(part[\"name\"] ?? \"\");\n return {\n type: \"tool\",\n tool: toolName,\n callID: String(part[\"id\"] ?? \"\"),\n title: `Tool: ${toolName}`,\n state: {\n input: part[\"input\"] ?? {},\n output: null,\n },\n time_created: timestampMs,\n };\n }\n\n private applyAssistantMetadata(message: Message, msg: Record<string, unknown>): void {\n const model = msg[\"model\"];\n if (model && typeof model === \"string\" && !message.model) {\n message.model = model;\n }\n const usage = msg[\"usage\"];\n if (usage && typeof usage === \"object\" && !message.tokens) {\n const u = usage as Record<string, unknown>;\n message.tokens = {\n input:\n ((u[\"input_tokens\"] as number) ?? 0) +\n ((u[\"cache_creation_input_tokens\"] as number) ?? 0) +\n ((u[\"cache_read_input_tokens\"] as number) ?? 0),\n output: (u[\"output_tokens\"] as number) ?? 0,\n };\n }\n }\n\n // --- Assistant message grouping ---\n\n private appendAssistantReasoning(\n messages: Message[],\n opts: { messageId: string; msg: Record<string, unknown>; timestampMs: number; text: string },\n currentIndex: number | null,\n ): number {\n const part = this.buildReasoningPart(opts.text, opts.timestampMs);\n\n if (currentIndex !== null) {\n const message = messages[currentIndex]!;\n const hasText = message.parts.some((p) => p.type === \"text\");\n const hasTool = message.parts.some((p) => p.type === \"tool\");\n if (!hasText && !hasTool) {\n this.appendPartIfNew(message, part);\n this.applyAssistantMetadata(message, opts.msg);\n return currentIndex;\n }\n }\n\n const message = this.buildMessage({\n messageId: opts.messageId,\n role: \"assistant\",\n timestampMs: opts.timestampMs,\n parts: [part],\n agent: \"claude\",\n });\n this.applyAssistantMetadata(message, opts.msg);\n messages.push(message);\n return messages.length - 1;\n }\n\n private appendAssistantText(\n messages: Message[],\n opts: { messageId: string; msg: Record<string, unknown>; timestampMs: number; text: string },\n currentIndex: number | null,\n ): number {\n const part = this.buildTextPart(opts.text, opts.timestampMs);\n\n if (currentIndex !== null) {\n const message = messages[currentIndex]!;\n const hasTool = message.parts.some((p) => p.type === \"tool\");\n if (!hasTool) {\n this.appendPartIfNew(message, part);\n this.applyAssistantMetadata(message, opts.msg);\n return currentIndex;\n }\n }\n\n const message = this.buildMessage({\n messageId: opts.messageId,\n role: \"assistant\",\n timestampMs: opts.timestampMs,\n parts: [part],\n agent: \"claude\",\n });\n this.applyAssistantMetadata(message, opts.msg);\n messages.push(message);\n return messages.length - 1;\n }\n\n private attachToolCallToLatestAssistant(\n messages: Message[],\n opts: {\n messageId: string;\n msg: Record<string, unknown>;\n timestampMs: number;\n toolPart: MessagePart;\n latestTextIndex: number | null;\n },\n ): [number, number] {\n if (opts.latestTextIndex !== null) {\n const message = messages[opts.latestTextIndex]!;\n message.parts.push(opts.toolPart);\n this.applyAssistantMetadata(message, opts.msg);\n return [opts.latestTextIndex, message.parts.length - 1];\n }\n\n const message = this.buildMessage({\n messageId: opts.messageId,\n role: \"assistant\",\n timestampMs: opts.timestampMs,\n parts: [opts.toolPart],\n agent: \"claude\",\n mode: \"tool\",\n });\n this.applyAssistantMetadata(message, opts.msg);\n messages.push(message);\n return [messages.length - 1, 0];\n }\n\n // --- User content normalization ---\n\n private normalizeUserTextParts(content: unknown, timestampMs: number): MessagePart[] {\n if (typeof content === \"string\") {\n return content.trim() ? [this.buildTextPart(content, timestampMs)] : [];\n }\n if (!Array.isArray(content)) return [];\n\n const parts: MessagePart[] = [];\n for (const item of content) {\n if (typeof item === \"object\" && item !== null) {\n const ci = item as Record<string, unknown>;\n if (ci[\"type\"] === \"tool_result\") continue;\n const text = String(ci[\"text\"] ?? \"\");\n if (text.trim()) parts.push(this.buildTextPart(text, timestampMs));\n } else if (typeof item === \"string\" && item.trim()) {\n parts.push(this.buildTextPart(item, timestampMs));\n }\n }\n return parts;\n }\n\n private normalizeClaudeToolOutput(content: unknown, timestampMs: number): MessagePart[] {\n if (typeof content === \"string\") {\n return content.trim() ? [this.buildTextPart(content, timestampMs)] : [];\n }\n if (content === null || content === undefined) return [];\n\n if (Array.isArray(content)) {\n const parts: MessagePart[] = [];\n for (const item of content) {\n if (typeof item === \"object\" && item !== null) {\n const text = String(\n (item as Record<string, unknown>)[\"text\"] ??\n (item as Record<string, unknown>)[\"content\"] ??\n \"\",\n );\n if (text.trim()) parts.push(this.buildTextPart(text, timestampMs));\n } else if (typeof item === \"string\" && item.trim()) {\n parts.push(this.buildTextPart(item, timestampMs));\n }\n }\n return parts;\n }\n\n const text = String(content);\n return text.trim() ? [this.buildTextPart(text, timestampMs)] : [];\n }\n\n // --- Tool backfill ---\n\n private backfillToolOutput(\n messages: Message[],\n pendingToolCalls: Map<string, [number, number]>,\n callId: string,\n outputParts: MessagePart[],\n stateUpdates?: Record<string, unknown>,\n ): boolean {\n if (!callId) return false;\n\n const location = pendingToolCalls.get(callId);\n if (location === undefined) return false;\n\n const [msgIndex, partIndex] = location;\n const state =\n messages[msgIndex]!.parts[partIndex]!.state ??\n (messages[msgIndex]!.parts[partIndex]!.state = {});\n\n if (outputParts.length > 0) {\n const existing = state.output;\n if (Array.isArray(existing)) {\n existing.push(...outputParts);\n } else if (existing === null || existing === undefined) {\n state.output = [...outputParts];\n } else {\n state.output = [existing, ...outputParts];\n }\n }\n\n if (stateUpdates) {\n Object.assign(state, stateUpdates);\n }\n\n if (outputParts.length > 0 && !state.status) {\n state.status = \"completed\";\n }\n\n return outputParts.length > 0 || !!stateUpdates;\n }\n\n private resolveToolCallId(\n data: Record<string, unknown>,\n item: Record<string, unknown>,\n assistantUuidToToolCalls: Map<string, string[]>,\n ): string {\n const directId = String(item[\"tool_use_id\"] ?? \"\").trim();\n if (directId) return directId;\n\n const sourceUuid = String(data[\"sourceToolAssistantUUID\"] ?? \"\").trim();\n if (!sourceUuid) return \"\";\n\n const ids = assistantUuidToToolCalls.get(sourceUuid);\n if (ids && ids.length === 1) return ids[0]!;\n return \"\";\n }\n\n private extractToolStateUpdates(toolUseResult: unknown): Record<string, unknown> {\n if (!toolUseResult || typeof toolUseResult !== \"object\") return {};\n\n const result = toolUseResult as Record<string, unknown>;\n const updates: Record<string, unknown> = {};\n\n const success = result[\"success\"];\n if (typeof success === \"boolean\") {\n updates[\"status\"] = success ? \"success\" : \"error\";\n }\n\n const commandName = result[\"commandName\"];\n if (commandName) {\n updates[\"meta\"] = { commandName };\n }\n\n return updates;\n }\n\n // --- Fallback ---\n\n private buildFallbackToolMessage(opts: {\n messageId: string;\n timestampMs: number;\n toolCallId: string | null;\n outputParts: MessagePart[];\n }): Message | null {\n if (opts.outputParts.length === 0) return null;\n return this.buildMessage({\n messageId: opts.messageId,\n role: \"tool\",\n timestampMs: opts.timestampMs,\n parts: opts.outputParts,\n });\n }\n\n // --- Utilities ---\n\n private shouldIgnoreTool(toolName: string): boolean {\n return toolName === \"TodoWrite\";\n }\n\n private appendPartIfNew(message: Message, part: MessagePart): void {\n const parts = message.parts;\n if (parts.length > 0 && parts[parts.length - 1]!.type === part.type) {\n // Skip if identical to tail part (streaming dedup)\n const tail = parts[parts.length - 1]!;\n if (tail.text === part.text) return;\n }\n parts.push(part);\n }\n}\n","import type { SessionHead, SessionData } from \"../types/index.js\";\n\nexport interface SessionCacheMeta {\n id: string;\n sourcePath: string;\n [key: string]: unknown;\n}\n\n/** 变更检测结果 */\nexport interface ChangeCheckResult {\n /** 是否有变更 */\n hasChanges: boolean;\n /** 变更的会话 ID 列表(可选,用于精确更新) */\n changedIds?: string[];\n /** 检测时间戳 */\n timestamp: number;\n}\n\nexport abstract class BaseAgent {\n abstract readonly name: string;\n abstract readonly displayName: string;\n\n /** Check if this agent has data available on the local filesystem. */\n abstract isAvailable(): boolean;\n\n /** Scan for available sessions, returning lightweight metadata. */\n abstract scan(): SessionHead[];\n\n /** Load full session data including all messages. */\n abstract getSessionData(sessionId: string): SessionData;\n\n getUri(sessionId: string): string {\n return `${this.name}://${sessionId}`;\n }\n\n /**\n * Get session metadata for caching.\n * Override this to enable caching of session metadata.\n */\n getSessionMetaMap?(): Map<string, SessionCacheMeta>;\n\n /**\n * Restore session metadata from cache.\n * Override this to enable restoring cached metadata.\n */\n setSessionMetaMap?(meta: Map<string, SessionCacheMeta>): void;\n\n /**\n * 检查是否有变更(用于智能刷新)\n * @param sinceTimestamp 上次缓存时间戳\n * @param cachedSessions 缓存的会话列表\n * @returns 变更检测结果\n */\n checkForChanges?(\n sinceTimestamp: number,\n cachedSessions: SessionHead[],\n ): Promise<ChangeCheckResult> | ChangeCheckResult;\n\n /**\n * 增量扫描(仅扫描变更的会话)\n * @param cachedSessions 缓存的会话列表\n * @param changedIds 变更的会话 ID 列表\n * @returns 更新后的会话列表\n */\n incrementalScan?(\n cachedSessions: SessionHead[],\n changedIds: string[],\n ): Promise<SessionHead[]> | SessionHead[];\n}\n","import { existsSync } from \"node:fs\";\nimport { homedir, platform } from \"node:os\";\nimport { join } from \"node:path\";\n\nfunction envPath(name: string): string | null {\n const value = process.env[name];\n if (!value) return null;\n return value;\n}\n\nfunction firstExisting(...paths: string[]): string | null {\n for (const p of paths) {\n if (existsSync(p)) return p;\n }\n return null;\n}\n\nfunction getDataHome(): string {\n const xdg = envPath(\"XDG_DATA_HOME\");\n if (xdg) return xdg;\n\n const p = platform();\n if (p === \"win32\") {\n return envPath(\"LOCALAPPDATA\") ?? envPath(\"APPDATA\") ?? join(homedir(), \"AppData\", \"Local\");\n }\n\n // macOS / Linux\n return join(homedir(), \".local\", \"share\");\n}\n\nexport interface ProviderRoots {\n codexRoot: string;\n claudeRoot: string;\n kimiRoot: string;\n opencodeRoot: string;\n}\n\nexport function resolveProviderRoots(): ProviderRoots {\n const home = homedir();\n return {\n codexRoot: envPath(\"CODEX_HOME\") ?? join(home, \".codex\"),\n claudeRoot: envPath(\"CLAUDE_CONFIG_DIR\") ?? join(home, \".claude\"),\n kimiRoot: envPath(\"KIMI_SHARE_DIR\") ?? join(home, \".kimi\"),\n opencodeRoot: join(getDataHome(), \"opencode\"),\n };\n}\n\nexport function getCursorDataPath(): string | null {\n const override = envPath(\"CURSOR_DATA_PATH\");\n if (override) return override;\n\n const p = platform();\n if (p === \"darwin\") {\n return firstExisting(join(homedir(), \"Library\", \"Application Support\", \"Cursor\", \"User\"));\n }\n if (p === \"linux\") {\n const xdg = envPath(\"XDG_CONFIG_HOME\") ?? join(homedir(), \".config\");\n return firstExisting(join(xdg, \"Cursor\", \"User\"));\n }\n if (p === \"win32\") {\n const appData = envPath(\"APPDATA\") ?? join(homedir(), \"AppData\", \"Roaming\");\n return firstExisting(join(appData, \"Cursor\", \"User\"));\n }\n return null;\n}\n\nexport { firstExisting };\n","import { readFileSync } from \"node:fs\";\n\nexport function* parseJsonlLines(content: string): Generator<Record<string, unknown>> {\n for (const line of content.split(\"\\n\")) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n try {\n yield JSON.parse(trimmed) as Record<string, unknown>;\n } catch {\n // Skip malformed lines\n }\n }\n}\n\nexport function readJsonlFile(filePath: string): Generator<Record<string, unknown>> {\n const content = readFileSync(filePath, \"utf-8\");\n return parseJsonlLines(content);\n}\n","import { basename } from \"node:path\";\n\nconst TITLE_MAX_LENGTH = 100;\nconst UNTITLED_SESSION = \"Untitled Session\";\n\n/** Normalize extracted title text for display. */\nexport function normalizeTitleText(text: string): string | null {\n const cleaned = text.replace(/\\s+/g, \" \").trim();\n if (!cleaned) return null;\n return cleaned.slice(0, TITLE_MAX_LENGTH);\n}\n\n/** Return a stable basename for fallback title. */\nexport function basenameTitle(path: string | null | undefined): string | null {\n if (!path) return null;\n const normalized = path.trim().replace(/[/\\\\]+$/, \"\");\n if (!normalized) return null;\n const name = basename(normalized).trim();\n return name || null;\n}\n\n/** Resolve final session title from explicit, message, and directory fallbacks. */\nexport function resolveSessionTitle(\n explicit: string | null | undefined,\n message: string | null | undefined,\n directory: string | null | undefined,\n): string {\n for (const candidate of [explicit, message, directory]) {\n if (candidate) {\n const normalized = normalizeTitleText(candidate);\n if (normalized) return normalized;\n }\n }\n return UNTITLED_SESSION;\n}\n","/**\n * 性能追踪工具 - 用于测量启动过程中的各个阶段耗时\n */\n\nexport interface PerfMarker {\n name: string;\n startTime: number;\n endTime?: number;\n duration?: number;\n children: PerfMarker[];\n parent?: PerfMarker;\n}\n\nclass PerfTracer {\n private rootMarkers: PerfMarker[] = [];\n private activeStack: PerfMarker[] = [];\n private enabled = false;\n\n enable() {\n this.enabled = true;\n }\n\n start(name: string): PerfMarker {\n const marker: PerfMarker = {\n name,\n startTime: performance.now(),\n children: [],\n };\n\n if (!this.enabled) return marker;\n\n const parent = this.activeStack[this.activeStack.length - 1];\n if (parent) {\n marker.parent = parent;\n parent.children.push(marker);\n } else {\n this.rootMarkers.push(marker);\n }\n\n this.activeStack.push(marker);\n return marker;\n }\n\n end(marker?: PerfMarker): void {\n if (!this.enabled) return;\n\n const target = marker ?? this.activeStack[this.activeStack.length - 1];\n if (!target) return;\n\n target.endTime = performance.now();\n target.duration = target.endTime - target.startTime;\n\n // Pop until we remove the target\n while (this.activeStack.length > 0) {\n const popped = this.activeStack.pop();\n if (popped === target) break;\n }\n }\n\n measure<T>(name: string, fn: () => T): T {\n const marker = this.start(name);\n try {\n return fn();\n } finally {\n this.end(marker);\n }\n }\n\n async measureAsync<T>(name: string, fn: () => Promise<T>): Promise<T> {\n const marker = this.start(name);\n try {\n return await fn();\n } finally {\n this.end(marker);\n }\n }\n\n getReport(): string {\n if (!this.enabled) return \"Performance tracing disabled\";\n\n const lines: string[] = [];\n lines.push(\"\\n=== Performance Report ===\\n\");\n\n for (const marker of this.rootMarkers) {\n this.formatMarker(marker, 0, lines);\n }\n\n return lines.join(\"\\n\");\n }\n\n private formatMarker(marker: PerfMarker, depth: number, lines: string[]): void {\n const indent = \" \".repeat(depth);\n const duration = marker.duration?.toFixed(2) ?? \"?\";\n lines.push(`${indent}${marker.name}: ${duration}ms`);\n\n for (const child of marker.children) {\n this.formatMarker(child, depth + 1, lines);\n }\n }\n\n reset(): void {\n this.rootMarkers = [];\n this.activeStack = [];\n }\n}\n\nexport const perf = new PerfTracer();\n","import { existsSync, statSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { BaseAgent } from \"./base.js\";\nimport type { SessionCacheMeta, ChangeCheckResult } from \"./base.js\";\nimport type { SessionHead, SessionData, Message, MessagePart } from \"../types/index.js\";\nimport { resolveProviderRoots, firstExisting } from \"../discovery/paths.js\";\nimport { openDbReadOnly, isSqliteAvailable } from \"../utils/sqlite.js\";\n\nexport class OpenCodeAgent extends BaseAgent {\n readonly name = \"opencode\";\n readonly displayName = \"OpenCode\";\n\n private dbPath: string | null = null;\n\n // Session metadata for caching\n private sessionMetaMap = new Map<string, { id: string; sourcePath: string }>();\n\n private findDbPath(): string | null {\n if (!isSqliteAvailable()) return null;\n const roots = resolveProviderRoots();\n return firstExisting(join(roots.opencodeRoot, \"opencode.db\"), \"data/opencode/opencode.db\");\n }\n\n isAvailable(): boolean {\n this.dbPath = this.findDbPath();\n return this.dbPath !== null;\n }\n\n scan(): SessionHead[] {\n if (!this.dbPath) return [];\n\n const db = openDbReadOnly(this.dbPath);\n if (!db) return [];\n\n try {\n const cutoffTime = Date.now() - 3650 * 24 * 60 * 60 * 1000;\n\n const hasMessageTable = db\n .prepare(\"SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'message'\")\n .get();\n\n let rows: Record<string, unknown>[];\n if (hasMessageTable) {\n rows = db\n .prepare(`\n SELECT\n s.id, s.title, s.time_created, s.time_updated, s.slug, s.directory,\n s.version, s.summary_files,\n (SELECT COUNT(*) FROM message m WHERE m.session_id = s.id) AS message_count,\n (SELECT m.data FROM message m\n WHERE m.session_id = s.id AND m.data LIKE '%\"modelID\"%'\n ORDER BY m.time_created DESC LIMIT 1) AS model_message_data\n FROM session s\n WHERE s.time_created >= ?\n ORDER BY s.time_created DESC\n `)\n .all(cutoffTime);\n } else {\n rows = db\n .prepare(`\n SELECT s.id, s.title, s.time_created, s.time_updated, s.slug, s.directory,\n s.version, s.summary_files, 0 AS message_count, NULL AS model_message_data\n FROM session s\n WHERE s.time_created >= ?\n ORDER BY s.time_created DESC\n `)\n .all(cutoffTime);\n }\n\n const heads: SessionHead[] = [];\n for (const row of rows) {\n const id = String(row.id ?? \"\");\n const title = String(row.title ?? \"\").trim() || \"Untitled\";\n const timeCreated = Number(row.time_created ?? 0);\n const timeUpdated = Number(row.time_updated ?? timeCreated);\n const slug = `opencode/${id}`;\n const directory = String(row.directory ?? \"\");\n\n heads.push({\n id,\n slug,\n title,\n directory,\n time_created: timeCreated,\n time_updated: timeUpdated,\n stats: {\n message_count: Number(row.message_count ?? 0),\n total_input_tokens: 0,\n total_output_tokens: 0,\n total_cost: 0,\n },\n });\n\n // Store session metadata for caching\n if (this.dbPath) {\n this.sessionMetaMap.set(id, {\n id,\n sourcePath: this.dbPath,\n });\n }\n }\n\n return heads;\n } catch {\n return [];\n } finally {\n db.close();\n }\n }\n\n getSessionMetaMap(): Map<string, SessionCacheMeta> {\n return this.sessionMetaMap as Map<string, SessionCacheMeta>;\n }\n\n setSessionMetaMap(meta: Map<string, SessionCacheMeta>): void {\n this.sessionMetaMap = meta as Map<string, { id: string; sourcePath: string }>;\n }\n\n /**\n * 检测数据库变更\n * 对于 SQLite,检测数据库文件修改时间\n */\n checkForChanges(sinceTimestamp: number, cachedSessions: SessionHead[]): ChangeCheckResult {\n if (!this.dbPath) {\n this.dbPath = this.findDbPath();\n }\n if (!this.dbPath || !existsSync(this.dbPath)) {\n return { hasChanges: false, timestamp: Date.now() };\n }\n\n try {\n // 检测数据库文件修改时间\n const stat = statSync(this.dbPath);\n const hasChanges = stat.mtimeMs > sinceTimestamp;\n\n // 如果数据库有变更,标记所有缓存会话需要刷新\n const changedIds = hasChanges ? cachedSessions.map((s) => s.id) : [];\n\n return {\n hasChanges,\n changedIds,\n timestamp: Date.now(),\n };\n } catch {\n return { hasChanges: false, timestamp: Date.now() };\n }\n }\n\n /**\n * 增量扫描 - 重新查询数据库\n */\n incrementalScan(_cachedSessions: SessionHead[], _changedIds: string[]): SessionHead[] {\n // 对于 OpenCode,直接重新执行完整扫描\n return this.scan();\n }\n\n getSessionData(sessionId: string): SessionData {\n // Ensure dbPath is set\n if (!this.dbPath) {\n this.dbPath = this.findDbPath();\n }\n if (!this.dbPath) {\n throw new Error(\"OpenCode database is missing\");\n }\n\n const db = openDbReadOnly(this.dbPath);\n if (!db) {\n throw new Error(\"OpenCode database is missing\");\n }\n\n try {\n // First get session metadata\n const sessionRow = db.prepare(\"SELECT * FROM session WHERE id = ?\").get(sessionId) as\n | Record<string, unknown>\n | undefined;\n if (!sessionRow) {\n throw new Error(`Session not found: ${sessionId}`);\n }\n\n const id = String(sessionRow.id ?? sessionId);\n const title = String(sessionRow.title ?? \"Untitled\");\n const slug = `opencode/${id}`;\n const directory = String(sessionRow.directory ?? \"\");\n const timeCreated = Number(sessionRow.time_created ?? 0);\n const timeUpdated = Number(sessionRow.time_updated ?? timeCreated);\n\n const messages: Message[] = [];\n let totalCost = 0;\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n\n // Get messages\n const msgRows = db\n .prepare(\"SELECT * FROM message WHERE session_id = ? ORDER BY time_created ASC\")\n .all(sessionId) as Record<string, unknown>[];\n\n for (const msgRow of msgRows) {\n const msgData = JSON.parse(String(msgRow.data ?? \"{}\")) as Record<string, unknown>;\n\n const parts: MessagePart[] = [];\n const cost = Number(msgData.cost ?? 0);\n const tokens = msgData.tokens as Record<string, unknown> | undefined;\n const inputTokens = Number(tokens?.input ?? 0);\n const outputTokens = Number(tokens?.output ?? 0);\n\n totalCost += cost;\n totalInputTokens += inputTokens;\n totalOutputTokens += outputTokens;\n\n // Get parts for this message\n const partRows = db\n .prepare(\"SELECT * FROM part WHERE message_id = ? ORDER BY time_created ASC\")\n .all(msgRow.id) as Record<string, unknown>[];\n\n for (const partRow of partRows) {\n const partData = JSON.parse(String(partRow.data ?? \"{}\")) as Record<string, unknown>;\n const partType = String(partData.type ?? \"\");\n\n if (partType === \"text\" || partType === \"reasoning\") {\n parts.push({\n type: partType as \"text\" | \"reasoning\",\n text: partData.text ?? \"\",\n time_created: Number(partRow.time_created ?? 0),\n });\n } else if (partType === \"tool\") {\n parts.push({\n type: \"tool\",\n tool: String(partData.tool ?? \"\"),\n callID: String(partData.callID ?? \"\"),\n title: String(partData.title ?? \"\"),\n state: (partData.state ?? {}) as MessagePart[\"state\"],\n time_created: Number(partRow.time_created ?? 0),\n });\n }\n // Skip step-start, step-finish parts\n }\n\n messages.push({\n id: String(msgRow.id ?? \"\"),\n role: String(msgData.role ?? \"assistant\") as Message[\"role\"],\n agent: (msgData.agent as string | null) ?? null,\n mode: (msgData.mode as string | null) ?? null,\n model: (msgData.modelID as string | null) ?? null,\n provider: (msgData.providerID as string | null) ?? null,\n time_created: Number(msgRow.time_created ?? 0),\n tokens: tokens ? { input: inputTokens, output: outputTokens } : undefined,\n cost,\n parts,\n });\n }\n\n return {\n id,\n title,\n slug,\n directory,\n version: (sessionRow.version as string | null) ?? undefined,\n time_created: timeCreated,\n time_updated: timeUpdated,\n summary_files: sessionRow.summary_files ?? undefined,\n stats: {\n message_count: messages.length,\n total_input_tokens: totalInputTokens,\n total_output_tokens: totalOutputTokens,\n total_cost: totalCost,\n },\n messages,\n };\n } finally {\n db.close();\n }\n }\n}\n","/**\n * SQLite helper — graceful degradation if better-sqlite3 is unavailable.\n */\n\nimport { createRequire } from \"node:module\";\n\nlet DatabaseConstructor: ((path: string) => unknown) | null = null;\n\ntry {\n const require = createRequire(import.meta.url);\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const mod = require(\"better-sqlite3\");\n DatabaseConstructor =\n typeof mod === \"function\"\n ? mod\n : ((mod as { default?: unknown }).default as typeof DatabaseConstructor);\n} catch {\n // better-sqlite3 not installed — adapters that need SQLite will gracefully skip\n}\n\nexport interface DatabaseRow {\n [key: string]: unknown;\n}\n\nexport interface SQLiteDatabase {\n prepare(sql: string): {\n all(...params: unknown[]): DatabaseRow[];\n get(...params: unknown[]): DatabaseRow | undefined;\n run(...params: unknown[]): void;\n };\n close(): void;\n}\n\n/**\n * Open a SQLite database in read-only mode.\n * Returns null if better-sqlite3 is unavailable or the file can't be opened.\n */\nexport function openDbReadOnly(dbPath: string): SQLiteDatabase | null {\n if (!DatabaseConstructor) return null;\n try {\n // better-sqlite3 constructor with readonly flag\n const db = (\n DatabaseConstructor as (path: string, options?: { readonly?: boolean }) => SQLiteDatabase\n )(dbPath, { readonly: true });\n return db;\n } catch {\n return null;\n }\n}\n\n/**\n * Check if SQLite support is available.\n */\nexport function isSqliteAvailable(): boolean {\n return DatabaseConstructor !== null;\n}\n","import { createHash } from \"node:crypto\";\nimport { existsSync, readFileSync, readdirSync, statSync } from \"node:fs\";\nimport { join, basename, dirname } from \"node:path\";\nimport { BaseAgent } from \"./base.js\";\nimport type { SessionHead, SessionData, Message, MessagePart } from \"../types/index.js\";\nimport { resolveProviderRoots, firstExisting } from \"../discovery/paths.js\";\nimport { parseJsonlLines } from \"../utils/jsonl.js\";\nimport { perf } from \"../utils/perf.js\";\n\nconst KIMI_TOOL_TITLE_MAP: Record<string, string> = {\n ReadFile: \"read\",\n Glob: \"glob\",\n StrReplaceFile: \"edit\",\n Grep: \"grep\",\n WriteFile: \"write\",\n Shell: \"bash\",\n};\n\nconst KIMI_IGNORED_TOOLS = new Set([\"SetTodoList\"]);\n\nfunction mapToolTitle(toolName: string): string {\n return KIMI_TOOL_TITLE_MAP[toolName] ?? toolName;\n}\n\nimport type { SessionCacheMeta, ChangeCheckResult } from \"./base.js\";\n\ninterface SessionMeta extends SessionCacheMeta {\n id: string;\n title: string;\n sourcePath: string;\n cwd: string;\n contextFile: string | null;\n wireFile: string | null;\n createdAt: number;\n metaFile: string;\n}\n\ninterface KimiWorkDir {\n path: string;\n last_session_id: string | null;\n}\n\nfunction normalizeToolArguments(raw: unknown): unknown {\n if (typeof raw === \"string\") {\n try {\n return JSON.parse(raw);\n } catch {\n return raw;\n }\n }\n return raw;\n}\n\nfunction normalizeToolOutputParts(content: unknown, timestampMs: number): MessagePart[] {\n if (typeof content === \"string\") {\n return content.trim()\n ? [{ type: \"text\" as const, text: content, time_created: timestampMs }]\n : [];\n }\n if (Array.isArray(content)) {\n const parts: MessagePart[] = [];\n for (const item of content) {\n if (typeof item === \"object\" && item !== null && \"text\" in item) {\n const text = String((item as Record<string, unknown>).text ?? \"\");\n if (text.trim()) parts.push({ type: \"text\", text, time_created: timestampMs });\n } else if (typeof item === \"string\" && item.trim()) {\n parts.push({ type: \"text\", text: item, time_created: timestampMs });\n }\n }\n return parts;\n }\n if (content == null) return [];\n const text = String(content);\n return text.trim() ? [{ type: \"text\", text, time_created: timestampMs }] : [];\n}\n\nfunction normalizeWireToolOutputParts(returnValue: unknown, timestampMs: number): MessagePart[] {\n if (returnValue == null) return [];\n if (typeof returnValue === \"string\") {\n return returnValue.trim()\n ? [{ type: \"text\" as const, text: returnValue, time_created: timestampMs }]\n : [];\n }\n if (typeof returnValue === \"object\") {\n return [\n { type: \"text\", text: JSON.stringify(returnValue, null, 2), time_created: timestampMs },\n ];\n }\n const text = String(returnValue);\n return text.trim() ? [{ type: \"text\", text, time_created: timestampMs }] : [];\n}\n\nexport class KimiAgent extends BaseAgent {\n readonly name = \"kimi\";\n readonly displayName = \"Kimi-Cli\";\n\n private basePath: string | null = null;\n private sessionMetaMap = new Map<string, SessionMeta>();\n private projectMap = new Map<string, string>();\n\n private findBasePath(): string | null {\n const roots = resolveProviderRoots();\n return firstExisting(join(roots.kimiRoot, \"sessions\"), \"data/kimi\");\n }\n\n /** Parse kimi.json and build md5(project_path) → cwd mapping */\n private loadKimiConfig(): void {\n const roots = resolveProviderRoots();\n const configPath = join(roots.kimiRoot, \"kimi.json\");\n if (!existsSync(configPath)) return;\n try {\n const raw = JSON.parse(readFileSync(configPath, \"utf-8\")) as Record<string, unknown>;\n const workDirs = raw?.work_dirs;\n if (!Array.isArray(workDirs)) return;\n for (const wd of workDirs) {\n const path = (wd as KimiWorkDir).path;\n if (typeof path !== \"string\") continue;\n const hash = createHash(\"md5\").update(path).digest(\"hex\");\n this.projectMap.set(hash, path);\n }\n } catch {\n // ignore malformed config\n }\n }\n\n isAvailable(): boolean {\n this.basePath = this.findBasePath();\n if (!this.basePath) return false;\n this.loadKimiConfig();\n try {\n return this.listSessionDirs().length > 0;\n } catch {\n // ignore\n }\n return false;\n }\n\n /** Walk sessions/{project_hash}/{session_id}/ and find valid session dirs */\n private listSessionDirs(): string[] {\n if (!this.basePath) return [];\n const dirs: string[] = [];\n try {\n for (const hashEntry of readdirSync(this.basePath, { withFileTypes: true })) {\n if (!hashEntry.isDirectory()) continue;\n const hashPath = join(this.basePath, hashEntry.name);\n try {\n for (const sessionEntry of readdirSync(hashPath, { withFileTypes: true })) {\n if (!sessionEntry.isDirectory()) continue;\n const sessionPath = join(hashPath, sessionEntry.name);\n if (\n existsSync(join(sessionPath, \"metadata.json\")) ||\n existsSync(join(sessionPath, \"state.json\"))\n ) {\n dirs.push(sessionPath);\n }\n }\n } catch {\n // skip unreadable hash dirs\n }\n }\n } catch {\n // skip unreadable base\n }\n return dirs;\n }\n\n /** Parse session directory, preferring state.json over metadata.json */\n private parseSessionDir(sessionDir: string): SessionMeta | null {\n try {\n const sessionId = basename(sessionDir);\n const projectHash = basename(dirname(sessionDir));\n const contextFile = join(sessionDir, \"context.jsonl\");\n const wireFile = join(sessionDir, \"wire.jsonl\");\n\n if (!existsSync(contextFile) && !existsSync(wireFile)) return null;\n\n const statePath = join(sessionDir, \"state.json\");\n const metaPath = join(sessionDir, \"metadata.json\");\n\n let title = \"\";\n let wireMtime: number | null = null;\n let metaFile = \"\";\n\n if (existsSync(statePath)) {\n const state = JSON.parse(readFileSync(statePath, \"utf-8\")) as Record<string, unknown>;\n title = String(state.custom_title ?? \"\");\n wireMtime = typeof state.wire_mtime === \"number\" ? state.wire_mtime : null;\n metaFile = statePath;\n } else if (existsSync(metaPath)) {\n const meta = JSON.parse(readFileSync(metaPath, \"utf-8\")) as Record<string, unknown>;\n title = String(meta.title ?? \"\");\n wireMtime = typeof meta.wire_mtime === \"number\" ? meta.wire_mtime : null;\n metaFile = metaPath;\n }\n\n const cwd = this.projectMap.get(projectHash) || \"\";\n const createdAt =\n wireMtime !== null\n ? wireMtime * 1000\n : metaFile\n ? statSync(metaFile).mtimeMs\n : statSync(sessionDir).mtimeMs;\n\n return {\n id: sessionId,\n title: title || \"Untitled Session\",\n sourcePath: sessionDir,\n cwd,\n contextFile: existsSync(contextFile) ? contextFile : null,\n wireFile: existsSync(wireFile) ? wireFile : null,\n createdAt,\n metaFile,\n };\n } catch {\n return null;\n }\n }\n\n scan(): SessionHead[] {\n if (!this.basePath) return [];\n\n const scanMarker = perf.start(\"kimi:scan\");\n\n const listMarker = perf.start(\"listSessionDirs\");\n const sessionDirs = this.listSessionDirs();\n perf.end(listMarker);\n\n const heads: SessionHead[] = [];\n for (const dir of sessionDirs) {\n try {\n const parseMarker = perf.start(`parseSessionDir:${basename(dir)}`);\n const meta = this.parseSessionDir(dir);\n perf.end(parseMarker);\n\n if (!meta) continue;\n\n this.sessionMetaMap.set(meta.id, meta);\n heads.push({\n id: meta.id,\n slug: `kimi/${meta.id}`,\n title: meta.title,\n directory: meta.cwd,\n time_created: meta.createdAt,\n time_updated: meta.createdAt,\n stats: {\n message_count: 0,\n total_input_tokens: 0,\n total_output_tokens: 0,\n total_cost: 0,\n },\n });\n } catch {\n // skip\n }\n }\n\n perf.end(scanMarker);\n return heads;\n }\n\n getSessionMetaMap(): Map<string, SessionCacheMeta> {\n return this.sessionMetaMap;\n }\n\n setSessionMetaMap(meta: Map<string, SessionCacheMeta>): void {\n this.sessionMetaMap = meta as Map<string, SessionMeta>;\n }\n\n /**\n * 检测文件系统变更\n */\n checkForChanges(sinceTimestamp: number, cachedSessions: SessionHead[]): ChangeCheckResult {\n const changedIds: string[] = [];\n\n for (const session of cachedSessions) {\n const meta = this.sessionMetaMap.get(session.id);\n if (!meta) continue;\n\n try {\n // 检查 metadata.json 或 state.json 的修改时间\n if (meta.metaFile) {\n const stat = statSync(meta.metaFile);\n if (stat.mtimeMs > sinceTimestamp) {\n changedIds.push(session.id);\n continue;\n }\n }\n\n // 检查 wire.jsonl 或 context.jsonl 的修改时间\n const dataFile = meta.wireFile || meta.contextFile;\n if (dataFile) {\n const dataStat = statSync(dataFile);\n if (dataStat.mtimeMs > sinceTimestamp) {\n changedIds.push(session.id);\n }\n }\n } catch {\n changedIds.push(session.id);\n }\n }\n\n return {\n hasChanges: changedIds.length > 0,\n changedIds,\n timestamp: Date.now(),\n };\n }\n\n /**\n * 增量扫描\n */\n incrementalScan(cachedSessions: SessionHead[], changedIds: string[]): SessionHead[] {\n const sessionMap = new Map(cachedSessions.map((s) => [s.id, s]));\n\n for (const dir of this.listSessionDirs()) {\n try {\n const meta = this.parseSessionDir(dir);\n if (!meta) continue;\n\n if (changedIds.includes(meta.id)) {\n this.sessionMetaMap.set(meta.id, meta);\n sessionMap.set(meta.id, {\n id: meta.id,\n slug: `kimi/${meta.id}`,\n title: meta.title,\n directory: meta.cwd,\n time_created: meta.createdAt,\n time_updated: meta.createdAt,\n stats: {\n message_count: 0,\n total_input_tokens: 0,\n total_output_tokens: 0,\n total_cost: 0,\n },\n });\n }\n } catch {\n // skip\n }\n }\n\n return Array.from(sessionMap.values());\n }\n\n getSessionData(sessionId: string): SessionData {\n const meta = this.sessionMetaMap.get(sessionId);\n if (!meta) throw new Error(`Session not found: ${sessionId}`);\n\n if (meta.contextFile) {\n return this.getSessionDataFromContext(meta);\n }\n return this.getSessionDataFromWire(meta);\n }\n\n private getSessionDataFromContext(meta: SessionMeta): SessionData {\n if (!meta.contextFile) throw new Error(\"context.jsonl is missing\");\n\n const content = readFileSync(meta.contextFile, \"utf-8\");\n const messages: Message[] = [];\n const pendingToolCalls = new Map<string, [number, number]>();\n const ignoredToolCallIds = new Set<string>();\n\n let seq = 0;\n const fallbackTs = meta.createdAt;\n for (const record of parseJsonlLines(content)) {\n seq++;\n try {\n const role = String(record.role ?? \"\");\n if (role === \"_checkpoint\" || role === \"_usage\") continue;\n\n if (role === \"user\") {\n const text = String(record.content ?? \"\");\n if (text.trim()) {\n messages.push(\n this.buildMessage({\n messageId: `context-${seq}`,\n role: \"user\",\n timestampMs: fallbackTs,\n parts: [{ type: \"text\", text, time_created: fallbackTs }],\n }),\n );\n }\n continue;\n }\n\n if (role === \"assistant\") {\n const { message, toolIndexes } = this.buildContextAssistantMessage(\n record,\n seq,\n ignoredToolCallIds,\n fallbackTs,\n );\n if (!message) continue;\n const msgIndex = messages.length;\n messages.push(message);\n for (const [callId, partIndex] of toolIndexes) {\n pendingToolCalls.set(callId, [msgIndex, partIndex]);\n }\n continue;\n }\n\n if (role === \"tool\") {\n const callId = String(record.tool_call_id ?? \"\").trim();\n if (callId && ignoredToolCallIds.has(callId)) continue;\n const outputParts = normalizeToolOutputParts(record.content, fallbackTs);\n if (callId && this.backfillToolOutput(messages, pendingToolCalls, callId, outputParts)) {\n continue;\n }\n if (outputParts.length > 0) {\n messages.push(\n this.buildMessage({\n messageId: `context-${seq}`,\n role: \"tool\",\n timestampMs: fallbackTs,\n parts: outputParts,\n }),\n );\n }\n }\n } catch {\n // skip\n }\n }\n\n const stats = this.extractStats(meta.sourcePath);\n return this.buildSessionData(meta, messages, stats);\n }\n\n private getSessionDataFromWire(meta: SessionMeta): SessionData {\n const wirePath = meta.wireFile ?? join(meta.sourcePath, \"wire.jsonl\");\n if (!existsSync(wirePath)) throw new Error(\"wire.jsonl is missing\");\n\n const content = readFileSync(wirePath, \"utf-8\");\n const messages: Message[] = [];\n const pendingToolCalls = new Map<string, [number, number]>();\n const ignoredToolCallIds = new Set<string>();\n const openToolArgumentBuffer = new Map<string, string>();\n\n let currentAssistantIndex: number | null = null;\n let openToolCallId: string | null = null;\n let seq = 0;\n\n for (const record of parseJsonlLines(content)) {\n seq++;\n try {\n const message = (record.message ?? {}) as Record<string, unknown>;\n const msgType = String(message.type ?? \"\");\n const payload = (message.payload ?? {}) as Record<string, unknown>;\n const timestamp = Number(record.timestamp ?? 0);\n const timestampMs = Number.isFinite(timestamp) ? Math.floor(timestamp * 1000) : 0;\n\n // Bind usage to the most recent assistant message without tokens\n const usage = message[\"usage\"] as Record<string, unknown> | undefined;\n if (usage && typeof usage === \"object\") {\n const inputTokens = Number(usage[\"input_tokens\"] ?? 0);\n const outputTokens = Number(usage[\"output_tokens\"] ?? 0);\n if (inputTokens || outputTokens) {\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i]!;\n if (msg.role === \"assistant\" && !msg.tokens) {\n msg.tokens = { input: inputTokens, output: outputTokens };\n break;\n }\n }\n }\n }\n\n if (msgType === \"TurnBegin\") {\n const userInput = payload.user_input;\n if (Array.isArray(userInput) && userInput.length > 0) {\n const text = String((userInput[0] as Record<string, unknown>)?.text ?? \"\");\n if (text.trim()) {\n messages.push(\n this.buildMessage({\n messageId: `wire-${seq}`,\n role: \"user\",\n timestampMs,\n parts: [{ type: \"text\", text, time_created: timestampMs }],\n }),\n );\n }\n }\n currentAssistantIndex = null;\n openToolCallId = null;\n continue;\n }\n\n if (msgType === \"ContentPart\") {\n currentAssistantIndex = this.getOrCreateWireAssistant(\n messages,\n currentAssistantIndex,\n `wire-${seq}`,\n );\n const assistant = messages[currentAssistantIndex]!;\n const partType = String(payload.type ?? \"\");\n if (partType === \"think\") {\n const text = String(payload.think ?? \"\");\n if (text.trim()) {\n assistant.parts.push({ type: \"reasoning\", text, time_created: timestampMs });\n }\n } else if (partType === \"text\") {\n const text = String(payload.text ?? \"\");\n if (text.trim()) {\n assistant.parts.push({ type: \"text\", text, time_created: timestampMs });\n }\n }\n continue;\n }\n\n if (msgType === \"ToolCall\") {\n const function_ = payload.function as Record<string, unknown> | undefined;\n const toolName = String(function_?.name ?? \"\").trim();\n const callId = String(payload.id ?? \"\").trim();\n\n if (toolName && callId && KIMI_IGNORED_TOOLS.has(toolName)) {\n ignoredToolCallIds.add(callId);\n openToolCallId = callId;\n continue;\n }\n\n if (!function_ || !callId || !toolName) continue;\n\n currentAssistantIndex = this.getOrCreateWireAssistant(\n messages,\n currentAssistantIndex,\n `wire-${seq}`,\n );\n const assistant = messages[currentAssistantIndex]!;\n\n const rawArgs = function_.arguments;\n const normalizedArgs = normalizeToolArguments(rawArgs);\n const buffer =\n typeof rawArgs === \"string\" && typeof normalizedArgs !== \"string\" ? rawArgs : null;\n\n const toolPart: MessagePart = {\n type: \"tool\",\n tool: toolName,\n callID: callId,\n title: mapToolTitle(toolName),\n state: { arguments: normalizedArgs, output: null },\n time_created: timestampMs,\n };\n\n const partIndex = assistant.parts.length;\n assistant.parts.push(toolPart);\n assistant.mode = \"tool\";\n pendingToolCalls.set(callId, [currentAssistantIndex, partIndex]);\n openToolCallId = callId;\n\n if (buffer !== null) {\n openToolArgumentBuffer.set(callId, buffer);\n }\n continue;\n }\n\n if (msgType === \"ToolCallPart\") {\n if (openToolCallId && ignoredToolCallIds.has(openToolCallId)) continue;\n const argumentsPart = String(payload.arguments_part ?? \"\");\n this.appendWireToolCallPart(\n argumentsPart,\n openToolCallId,\n openToolArgumentBuffer,\n messages,\n pendingToolCalls,\n );\n continue;\n }\n\n if (msgType === \"ToolResult\") {\n const callId = String(payload.tool_call_id ?? \"\").trim();\n if (callId && ignoredToolCallIds.has(callId)) continue;\n const outputParts = normalizeWireToolOutputParts(payload.return_value, timestampMs);\n if (callId && this.backfillToolOutput(messages, pendingToolCalls, callId, outputParts)) {\n continue;\n }\n if (outputParts.length > 0) {\n messages.push(\n this.buildMessage({\n messageId: `wire-${seq}`,\n role: \"tool\",\n timestampMs,\n parts: outputParts,\n }),\n );\n }\n continue;\n }\n\n // Skip StepBegin, StatusUpdate, ApprovalRequest, ApprovalResponse, TurnEnd\n } catch {\n // skip\n }\n }\n\n // Filter out messages with empty parts\n const filteredMessages = messages.filter((m) => m.parts.length > 0);\n const stats = this.extractStats(meta.sourcePath);\n return this.buildSessionData(meta, filteredMessages, stats);\n }\n\n // --- Helpers ---\n\n private buildMessage(opts: {\n messageId: string;\n role: string;\n timestampMs: number;\n parts: MessagePart[];\n agent?: string;\n mode?: string;\n model?: string | null;\n provider?: string | null;\n tokens?: Record<string, unknown>;\n cost?: number;\n }): Message {\n return {\n id: opts.messageId,\n role: opts.role as Message[\"role\"],\n agent: opts.agent ?? null,\n time_created: opts.timestampMs,\n mode: opts.mode ?? null,\n model: opts.model ?? null,\n provider: opts.provider ?? null,\n tokens: opts.tokens ? (opts.tokens as Message[\"tokens\"]) : undefined,\n cost: opts.cost ?? 0,\n parts: opts.parts,\n };\n }\n\n private buildContextAssistantMessage(\n record: Record<string, unknown>,\n seq: number,\n ignoredToolCallIds: Set<string>,\n fallbackTs: number,\n ): { message: Message; toolIndexes: Map<string, number> } {\n const parts: MessagePart[] = [];\n const toolIndexes = new Map<string, number>();\n\n const content = record.content;\n if (Array.isArray(content)) {\n for (const item of content) {\n if (typeof item !== \"object\" || item === null) continue;\n const ci = item as Record<string, unknown>;\n const partType = String(ci.type ?? \"\");\n\n if (partType === \"think\") {\n const text = String(ci.think ?? \"\");\n if (text.trim()) parts.push({ type: \"reasoning\", text, time_created: fallbackTs });\n } else if (partType === \"text\") {\n const text = String(ci.text ?? \"\");\n if (text.trim()) parts.push({ type: \"text\", text, time_created: fallbackTs });\n }\n }\n }\n\n const toolCalls = record.tool_calls;\n if (Array.isArray(toolCalls)) {\n for (const tc of toolCalls) {\n if (typeof tc !== \"object\" || tc === null) continue;\n const tcRecord = tc as Record<string, unknown>;\n const function_ = tcRecord.function as Record<string, unknown> | undefined;\n\n if (!function_) continue;\n const toolName = String(function_.name ?? \"\").trim();\n const callId = String(tcRecord.id ?? \"\").trim();\n\n if (toolName && callId && KIMI_IGNORED_TOOLS.has(toolName)) {\n ignoredToolCallIds.add(callId);\n continue;\n }\n\n if (!toolName || !callId) continue;\n\n const part: MessagePart = {\n type: \"tool\",\n tool: toolName,\n callID: callId,\n title: mapToolTitle(toolName),\n state: { arguments: normalizeToolArguments(function_.arguments), output: null },\n time_created: fallbackTs,\n };\n toolIndexes.set(callId, parts.length);\n parts.push(part);\n }\n }\n\n if (parts.length === 0) {\n return {\n message: this.buildMessage({\n messageId: `context-${seq}`,\n role: \"assistant\",\n timestampMs: fallbackTs,\n parts: [],\n }),\n toolIndexes,\n };\n }\n\n const allTools = parts.every((p) => p.type === \"tool\");\n const message = this.buildMessage({\n messageId: `context-${seq}`,\n role: \"assistant\",\n timestampMs: fallbackTs,\n parts,\n agent: \"kimi\",\n mode: allTools ? \"tool\" : undefined,\n });\n\n return { message, toolIndexes };\n }\n\n private getOrCreateWireAssistant(\n messages: Message[],\n currentIndex: number | null,\n messageId: string,\n ): number {\n if (currentIndex !== null) return currentIndex;\n messages.push(\n this.buildMessage({\n messageId,\n role: \"assistant\",\n timestampMs: 0,\n parts: [],\n agent: \"kimi\",\n }),\n );\n return messages.length - 1;\n }\n\n private appendWireToolCallPart(\n argumentsPart: string,\n openCallId: string | null,\n buffer: Map<string, string>,\n messages: Message[],\n pendingToolCalls: Map<string, [number, number]>,\n ): void {\n if (!openCallId || !pendingToolCalls.has(openCallId)) return;\n\n const existing = buffer.get(openCallId) ?? \"\";\n const combined = existing + argumentsPart;\n\n try {\n const parsed = JSON.parse(combined) as unknown;\n const location = pendingToolCalls.get(openCallId);\n if (!location) return;\n const msgPart = messages[location[0]]?.parts[location[1]];\n if (msgPart?.state) {\n msgPart.state.arguments = parsed;\n }\n buffer.delete(openCallId);\n } catch {\n buffer.set(openCallId, combined);\n }\n }\n\n private backfillToolOutput(\n messages: Message[],\n pendingToolCalls: Map<string, [number, number]>,\n callId: string,\n outputParts: MessagePart[],\n ): boolean {\n if (!outputParts.length || !callId) return false;\n\n const location = pendingToolCalls.get(callId);\n if (!location) return false;\n\n const part = messages[location[0]]?.parts[location[1]];\n if (!part) return false;\n if (!part.state) part.state = {};\n part.state.output = [...outputParts];\n return true;\n }\n\n private extractStats(sessionDir: string): SessionData[\"stats\"] {\n const stats = {\n total_cost: 0,\n total_input_tokens: 0,\n total_output_tokens: 0,\n total_tokens: 0,\n message_count: 0,\n };\n\n const wirePath = join(sessionDir, \"wire.jsonl\");\n if (!existsSync(wirePath)) return stats;\n\n try {\n const content = readFileSync(wirePath, \"utf-8\");\n for (const line of content.split(\"\\n\").filter((l) => l.trim())) {\n try {\n const data = JSON.parse(line) as Record<string, unknown>;\n const tokenUsage = (data.message as Record<string, unknown>)?.usage as\n | Record<string, unknown>\n | undefined;\n if (!tokenUsage) continue;\n stats.total_input_tokens += Number(tokenUsage.input_tokens ?? 0);\n stats.total_output_tokens += Number(tokenUsage.output_tokens ?? 0);\n } catch {\n // skip\n }\n }\n } catch {\n // skip\n }\n\n // Extract total tokens from context or wire\n const contextPath = join(sessionDir, \"context.jsonl\");\n const rawPath = existsSync(contextPath) ? contextPath : wirePath;\n if (!existsSync(rawPath)) return stats;\n\n try {\n const rawContent = readFileSync(rawPath, \"utf-8\");\n for (const line of rawContent.split(\"\\n\").filter((l) => l.trim())) {\n try {\n const data = JSON.parse(line) as Record<string, unknown>;\n if (data.role === \"_usage\" && typeof data.token_count === \"number\") {\n stats.total_tokens = data.token_count;\n }\n } catch {\n // skip\n }\n }\n } catch {\n // skip\n }\n\n return stats;\n }\n\n private buildSessionData(\n meta: SessionMeta,\n messages: Message[],\n stats: SessionData[\"stats\"],\n ): SessionData {\n stats.message_count = messages.length;\n return {\n id: meta.id,\n title: meta.title,\n slug: `kimi/${meta.id}`,\n directory: meta.cwd,\n time_created: meta.createdAt,\n time_updated: meta.createdAt,\n stats,\n messages,\n };\n }\n}\n","import { existsSync, readFileSync, readdirSync, statSync } from \"node:fs\";\nimport { join, basename } from \"node:path\";\nimport { BaseAgent } from \"./base.js\";\nimport type { SessionHead, SessionData, Message, MessagePart } from \"../types/index.js\";\nimport { resolveProviderRoots, firstExisting } from \"../discovery/paths.js\";\nimport { parseJsonlLines } from \"../utils/jsonl.js\";\nimport { resolveSessionTitle, basenameTitle } from \"../utils/title-fallback.js\";\nimport { perf } from \"../utils/perf.js\";\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst PROPOSED_PLAN_PATTERN = /<proposed_plan>\\s*([\\s\\S]*?)\\s*<\\/proposed_plan>/;\nconst PLAN_APPROVAL_PREFIX = \"PLEASE IMPLEMENT THIS PLAN\";\nconst SUBAGENT_NOTIFICATION_PATTERN =\n /<subagent_notification>\\s*([\\s\\S]*?)\\s*<\\/subagent_notification>/;\n\nconst DEVELOPER_LIKE_USER_MARKERS = [\n \"agents.md instructions for\",\n \"<instructions>\",\n \"<environment_context>\",\n \"<permissions instructions>\",\n \"<collaboration_mode>\",\n];\n\nfunction isDeveloperLikeUserMessage(text: string): boolean {\n const lower = text.toLowerCase();\n return DEVELOPER_LIKE_USER_MARKERS.some((m) => lower.includes(m));\n}\n\nconst CODEX_TOOL_TITLE_MAP: Record<string, string> = {\n exec_command: \"bash\",\n apply_patch: \"patch\",\n patch: \"patch\",\n spawn_agent: \"subagent\",\n subagent: \"subagent\",\n};\n\n// ---------------------------------------------------------------------------\n// Session ID extraction\n// ---------------------------------------------------------------------------\n\n/**\n * Extract session UUID from Codex filename.\n * \"rollout-2026-02-03T10-04-47-019c213e-c251-73a3-af66-0ec9d7cb9e29.jsonl\"\n * → last 5 dash-delimited parts joined with \"-\"\n */\nfunction extractSessionId(filename: string): string {\n const stem = basename(filename, \".jsonl\");\n const parts = stem.split(\"-\");\n if (parts.length >= 5) {\n return parts.slice(-5).join(\"-\");\n }\n return stem;\n}\n\n// ---------------------------------------------------------------------------\n// Timestamp\n// ---------------------------------------------------------------------------\n\nfunction parseTimestampMs(data: Record<string, unknown>): number {\n const ts = String(data[\"timestamp\"] ?? \"\").trim();\n if (!ts) return 0;\n try {\n return new Date(ts.includes(\"Z\") ? ts : ts.replace(\" \", \"T\") + \"Z\").getTime();\n } catch {\n return 0;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Title helpers\n// ---------------------------------------------------------------------------\n\nfunction normalizeTitleText(text: string): string {\n const line = text.split(\"\\n\").find((l) => l.trim());\n return line?.trim().slice(0, 80) || \"\";\n}\n\n// ---------------------------------------------------------------------------\n// Tool helpers\n// ---------------------------------------------------------------------------\n\nfunction mapToolTitle(name: string): string {\n return CODEX_TOOL_TITLE_MAP[name] ?? name;\n}\n\nfunction normalizeToolArguments(raw: unknown): unknown {\n if (typeof raw === \"string\") {\n try {\n return JSON.parse(raw);\n } catch {\n return raw;\n }\n }\n return raw;\n}\n\nfunction normalizeCustomToolArguments(toolName: string, input: unknown): unknown {\n if (toolName === \"apply_patch\") {\n return parseApplyPatchInput(input);\n }\n return input;\n}\n\n// ---------------------------------------------------------------------------\n// Patch parsing\n// ---------------------------------------------------------------------------\n\ninterface PatchBlock {\n type: \"write_file\" | \"delete_file\" | \"move_file\" | \"edit_file\";\n path?: string;\n content?: string;\n targetPath?: string;\n}\n\nconst PATCH_BEGIN_RE = /\\*\\*\\* Begin Patch/;\nconst PATCH_END_RE = /\\*\\*\\* End Patch/;\nconst PATCH_HEADER_RE = /\\*\\*\\*\\s+(Add|Delete|Update|Move)\\s+File:\\s*(.+)/;\nconst PATCH_MOVE_TO_RE = /\\*\\*\\*\\s+Move to:\\s*(.+)/;\n\nfunction parseApplyPatchInput(input: unknown): PatchBlock[] {\n const text = typeof input === \"string\" ? input : \"\";\n if (!text) return [];\n\n const blocks: PatchBlock[] = [];\n const lines = text.split(\"\\n\");\n let inPatch = false;\n let i = 0;\n\n while (i < lines.length) {\n const line = lines[i]!;\n\n if (!inPatch && PATCH_BEGIN_RE.test(line)) {\n inPatch = true;\n i++;\n continue;\n }\n\n if (inPatch && PATCH_END_RE.test(line)) {\n inPatch = false;\n i++;\n continue;\n }\n\n if (inPatch) {\n const headerMatch = line.match(PATCH_HEADER_RE);\n if (headerMatch) {\n const action = headerMatch[1]!;\n const filePath = headerMatch[2]!.trim();\n i++;\n\n if (action === \"Add\") {\n const content = extractPatchContent(lines, i);\n i = content.nextLineIndex;\n blocks.push({ type: \"write_file\", path: filePath, content: content.text });\n } else if (action === \"Update\") {\n // Check for Move to on the next non-empty line\n let moveToTarget: string | null = null;\n let contentStart = i;\n for (let j = i; j < lines.length; j++) {\n const l = lines[j]!;\n if (!l.trim()) continue;\n const moveMatch = l.match(PATCH_MOVE_TO_RE);\n if (moveMatch) {\n moveToTarget = moveMatch[1]!.trim();\n contentStart = j + 1;\n break;\n }\n break;\n }\n if (moveToTarget) {\n const content = extractPatchContent(lines, contentStart);\n i = content.nextLineIndex;\n blocks.push({\n type: \"move_file\",\n path: filePath,\n targetPath: moveToTarget,\n content: content.text,\n });\n } else {\n const content = extractPatchContent(lines, i);\n i = content.nextLineIndex;\n blocks.push({ type: \"edit_file\", path: filePath, content: content.text });\n }\n } else if (action === \"Delete\") {\n blocks.push({ type: \"delete_file\", path: filePath });\n // No content to read for delete\n }\n continue;\n }\n }\n\n i++;\n }\n\n return blocks;\n}\n\nfunction extractPatchContent(\n lines: string[],\n startIndex: number,\n): { text: string; nextLineIndex: number } {\n const contentLines: string[] = [];\n let i = startIndex;\n while (i < lines.length) {\n const line = lines[i]!;\n // Stop at next patch header or end patch\n if (PATCH_HEADER_RE.test(line) || PATCH_END_RE.test(line)) break;\n contentLines.push(line);\n i++;\n }\n return { text: contentLines.join(\"\\n\"), nextLineIndex: i };\n}\n\n// ---------------------------------------------------------------------------\n// Session meta\n// ---------------------------------------------------------------------------\n\nimport type { SessionCacheMeta, ChangeCheckResult } from \"./base.js\";\n\ninterface SessionMeta extends SessionCacheMeta {\n id: string;\n title: string;\n sourcePath: string;\n directory: string;\n model: string | null;\n messageCount: number;\n createdAt: number;\n updatedAt: number;\n}\n\n// ---------------------------------------------------------------------------\n// CodexAgent\n// ---------------------------------------------------------------------------\n\nexport class CodexAgent extends BaseAgent {\n readonly name = \"codex\";\n readonly displayName = \"Codex\";\n\n private basePath: string | null = null;\n private sessionIndexCache = new Map<string, string>();\n private sessionMetaMap = new Map<string, SessionMeta>();\n\n // ---- BaseAgent implementation ----\n\n private findBasePath(): string | null {\n const roots = resolveProviderRoots();\n return firstExisting(join(roots.codexRoot, \"sessions\"));\n }\n\n isAvailable(): boolean {\n this.basePath = this.findBasePath();\n if (!this.basePath) return false;\n try {\n // Check recursively for rollout jsonl files\n const files = this.walkDirForRolloutFiles(this.basePath);\n return files.length > 0;\n } catch {\n return false;\n }\n }\n\n scan(): SessionHead[] {\n if (!this.basePath) return [];\n\n const scanMarker = perf.start(\"codex:scan\");\n\n // Pre-load session index for titles\n const indexMarker = perf.start(\"loadSessionIndex\");\n this.loadSessionIndex();\n perf.end(indexMarker);\n\n const heads: SessionHead[] = [];\n\n const listMarker = perf.start(\"listRolloutFiles\");\n const files = this.listRolloutFiles();\n perf.end(listMarker);\n\n for (const file of files) {\n try {\n const parseMarker = perf.start(`parseSessionHead:${basename(file)}`);\n const head = this.parseSessionHead(file);\n perf.end(parseMarker);\n\n if (head) {\n heads.push(head);\n this.sessionMetaMap.set(head.id, {\n id: head.id,\n title: head.title,\n sourcePath: file,\n directory: head.directory,\n model: null,\n messageCount: head.stats.message_count,\n createdAt: head.time_created,\n updatedAt: head.time_updated ?? head.time_created,\n });\n }\n } catch {\n // skip malformed files\n }\n }\n\n perf.end(scanMarker);\n return heads;\n }\n\n getSessionMetaMap(): Map<string, SessionCacheMeta> {\n return this.sessionMetaMap;\n }\n\n setSessionMetaMap(meta: Map<string, SessionCacheMeta>): void {\n this.sessionMetaMap = meta as Map<string, SessionMeta>;\n }\n\n /**\n * 检测文件系统变更\n */\n checkForChanges(sinceTimestamp: number, cachedSessions: SessionHead[]): ChangeCheckResult {\n if (!this.basePath) {\n return { hasChanges: false, timestamp: Date.now() };\n }\n\n const changedIds: string[] = [];\n\n for (const session of cachedSessions) {\n const meta = this.sessionMetaMap.get(session.id);\n if (!meta) continue;\n\n try {\n const stat = statSync(meta.sourcePath);\n if (stat.mtimeMs > sinceTimestamp) {\n changedIds.push(session.id);\n }\n } catch {\n changedIds.push(session.id);\n }\n }\n\n // 检查新文件\n try {\n const allFiles = this.listRolloutFiles();\n const hasNewFiles = allFiles.length > cachedSessions.length;\n\n return {\n hasChanges: changedIds.length > 0 || hasNewFiles,\n changedIds,\n timestamp: Date.now(),\n };\n } catch {\n return {\n hasChanges: changedIds.length > 0,\n changedIds,\n timestamp: Date.now(),\n };\n }\n }\n\n /**\n * 增量扫描\n */\n incrementalScan(cachedSessions: SessionHead[], changedIds: string[]): SessionHead[] {\n if (!this.basePath) return cachedSessions;\n\n const sessionMap = new Map(cachedSessions.map((s) => [s.id, s]));\n\n // 重新扫描变更的会话\n for (const file of this.listRolloutFiles()) {\n try {\n const sessionId = extractSessionId(file);\n\n if (changedIds.includes(sessionId)) {\n const head = this.parseSessionHead(file);\n if (head) {\n sessionMap.set(head.id, head);\n this.sessionMetaMap.set(head.id, {\n id: head.id,\n title: head.title,\n sourcePath: file,\n directory: head.directory,\n model: null,\n messageCount: head.stats.message_count,\n createdAt: head.time_created,\n updatedAt: head.time_updated ?? head.time_created,\n });\n }\n }\n } catch {\n // skip\n }\n }\n\n // 检查新文件\n for (const file of this.listRolloutFiles()) {\n try {\n const sessionId = extractSessionId(file);\n if (!sessionMap.has(sessionId)) {\n const head = this.parseSessionHead(file);\n if (head) {\n sessionMap.set(head.id, head);\n this.sessionMetaMap.set(head.id, {\n id: head.id,\n title: head.title,\n sourcePath: file,\n directory: head.directory,\n model: null,\n messageCount: head.stats.message_count,\n createdAt: head.time_created,\n updatedAt: head.time_updated ?? head.time_created,\n });\n }\n }\n } catch {\n // skip\n }\n }\n\n return Array.from(sessionMap.values());\n }\n\n getSessionData(sessionId: string): SessionData {\n const meta = this.sessionMetaMap.get(sessionId);\n if (!meta) throw new Error(`Session not found: ${sessionId}`);\n if (!existsSync(meta.sourcePath)) throw new Error(`Session file missing: ${meta.sourcePath}`);\n\n const content = readFileSync(meta.sourcePath, \"utf-8\");\n const messages: Message[] = [];\n const pendingToolCalls = new Map<string, [number, number]>();\n\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n\n // Assistant message grouping state\n let currentAssistantIndex: number | null = null;\n let latestAssistantTextIndex: number | null = null;\n let pendingPlan: MessagePart | null = null;\n\n // Token-count dedup state (matches codeburn strategy)\n let prevCumulativeTotal = 0;\n let prevInput = 0;\n let prevCached = 0;\n let prevOutput = 0;\n let prevReasoning = 0;\n\n for (const record of parseJsonlLines(content)) {\n try {\n const result = this.convertRecord(\n record,\n messages,\n pendingToolCalls,\n meta.id,\n currentAssistantIndex,\n latestAssistantTextIndex,\n pendingPlan,\n );\n currentAssistantIndex = result.currentAssistantIndex;\n latestAssistantTextIndex = result.latestAssistantTextIndex;\n pendingPlan = result.pendingPlan;\n\n // Process Codex token_count events\n const recordType = String(record[\"type\"] ?? \"\");\n if (recordType === \"event_msg\") {\n const payload = (record[\"payload\"] ?? {}) as Record<string, unknown>;\n if (String(payload[\"type\"] ?? \"\") === \"token_count\") {\n const info = payload[\"info\"] as Record<string, unknown> | undefined;\n const totalUsage = info?.[\"total_token_usage\"] as Record<string, unknown> | undefined;\n const cumulativeTotal = Number(totalUsage?.[\"total_tokens\"] ?? 0);\n\n if (cumulativeTotal > 0 && cumulativeTotal === prevCumulativeTotal) {\n // duplicate event\n } else {\n prevCumulativeTotal = cumulativeTotal;\n\n const lastUsage = info?.[\"last_token_usage\"] as Record<string, unknown> | undefined;\n let inputTokens = 0;\n let cachedInputTokens = 0;\n let outputTokens = 0;\n let reasoningTokens = 0;\n\n if (lastUsage) {\n inputTokens = Number(lastUsage[\"input_tokens\"] ?? 0);\n cachedInputTokens = Number(lastUsage[\"cached_input_tokens\"] ?? 0);\n outputTokens = Number(lastUsage[\"output_tokens\"] ?? 0);\n reasoningTokens = Number(lastUsage[\"reasoning_output_tokens\"] ?? 0);\n } else if (cumulativeTotal > 0 && totalUsage) {\n inputTokens = Number(totalUsage[\"input_tokens\"] ?? 0) - prevInput;\n cachedInputTokens = Number(totalUsage[\"cached_input_tokens\"] ?? 0) - prevCached;\n outputTokens = Number(totalUsage[\"output_tokens\"] ?? 0) - prevOutput;\n reasoningTokens =\n Number(totalUsage[\"reasoning_output_tokens\"] ?? 0) - prevReasoning;\n\n prevInput = Number(totalUsage[\"input_tokens\"] ?? 0);\n prevCached = Number(totalUsage[\"cached_input_tokens\"] ?? 0);\n prevOutput = Number(totalUsage[\"output_tokens\"] ?? 0);\n prevReasoning = Number(totalUsage[\"reasoning_output_tokens\"] ?? 0);\n }\n\n const uncachedInput = Math.max(0, inputTokens - cachedInputTokens);\n if (uncachedInput || outputTokens || reasoningTokens) {\n totalInputTokens += uncachedInput;\n totalOutputTokens += outputTokens + reasoningTokens;\n\n // Bind to the most recent assistant message without tokens\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i]!;\n if (msg.role === \"assistant\" && !msg.tokens) {\n msg.tokens = {\n input: uncachedInput,\n output: outputTokens + reasoningTokens,\n };\n break;\n }\n }\n }\n }\n }\n }\n } catch {\n // skip malformed records\n }\n }\n\n // Finalize pending plan if any\n if (pendingPlan && currentAssistantIndex !== null) {\n messages[currentAssistantIndex]!.parts.push(pendingPlan);\n }\n\n return {\n id: meta.id,\n title: meta.title,\n slug: `codex/${meta.id}`,\n directory: meta.directory,\n time_created: meta.createdAt,\n time_updated: meta.updatedAt,\n stats: {\n message_count: messages.length,\n total_input_tokens: totalInputTokens,\n total_output_tokens: totalOutputTokens,\n total_cost: 0,\n },\n messages,\n };\n }\n\n // ---- File listing ----\n\n private listRolloutFiles(): string[] {\n if (!this.basePath) return [];\n try {\n return this.walkDirForRolloutFiles(this.basePath);\n } catch {\n return [];\n }\n }\n\n private walkDirForRolloutFiles(dir: string): string[] {\n const files: string[] = [];\n try {\n for (const entry of readdirSync(dir)) {\n const fullPath = join(dir, entry);\n const stat = statSync(fullPath);\n if (stat.isDirectory()) {\n files.push(...this.walkDirForRolloutFiles(fullPath));\n } else if (entry.endsWith(\".jsonl\") && entry.startsWith(\"rollout-\")) {\n files.push(fullPath);\n }\n }\n } catch {\n // skip permission errors\n }\n return files;\n }\n\n // ---- Session index ----\n\n private loadSessionIndex(): void {\n if (this.sessionIndexCache.size > 0) return;\n\n const roots = resolveProviderRoots();\n const indexPath = join(roots.codexRoot, \"session_index.jsonl\");\n if (!existsSync(indexPath)) return;\n\n try {\n const content = readFileSync(indexPath, \"utf-8\");\n for (const record of parseJsonlLines(content)) {\n const sid = String(record[\"id\"] ?? \"\").trim();\n const threadName = String(record[\"thread_name\"] ?? \"\").trim();\n if (sid && threadName) {\n this.sessionIndexCache.set(sid, threadName);\n }\n }\n } catch {\n // ignore\n }\n }\n\n private getTitleForSession(sessionId: string): string | null {\n return this.sessionIndexCache.get(sessionId) ?? null;\n }\n\n // ---- Session head parsing ----\n\n private parseSessionHead(filePath: string): SessionHead | null {\n const content = readFileSync(filePath, \"utf-8\");\n const lines = content.split(\"\\n\").filter((l) => l.trim());\n if (lines.length === 0) return null;\n\n const sessionId = extractSessionId(filePath);\n\n let firstRecord: Record<string, unknown>;\n try {\n firstRecord = JSON.parse(lines[0]!);\n } catch {\n return null;\n }\n\n const payload = (firstRecord[\"payload\"] ?? {}) as Record<string, unknown>;\n const createdAt = parseTimestampMs(payload) || statSync(filePath).mtimeMs;\n\n // Try title from session index\n const indexTitle = this.getTitleForSession(sessionId);\n // Fallback: extract from first user message\n const messageTitle = this.extractTitleFromLines(lines);\n const directoryTitle = basenameTitle(payload[\"cwd\"] ? String(payload[\"cwd\"]) : null);\n\n const title = resolveSessionTitle(indexTitle, messageTitle, directoryTitle);\n\n // Walk all lines to count messages, extract model, and pre-accumulate tokens\n let updatedAt = createdAt;\n let messageCount = 0;\n let model: string | null = null;\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n\n let scanPrevCumulativeTotal = 0;\n let scanPrevInput = 0;\n let scanPrevCached = 0;\n let scanPrevOutput = 0;\n let scanPrevReasoning = 0;\n\n const COUNTED_TYPES = new Set([\"message\", \"function_call\", \"function_call_output\"]);\n\n for (const line of lines) {\n try {\n const data = JSON.parse(line);\n const recordType = String(data[\"type\"] ?? \"\");\n if (recordType === \"session_meta\") {\n const p = (data[\"payload\"] ?? {}) as Record<string, unknown>;\n const ts = parseTimestampMs(p);\n if (ts > updatedAt) updatedAt = ts;\n continue;\n }\n\n if (recordType === \"response_item\") {\n const p = (data[\"payload\"] ?? {}) as Record<string, unknown>;\n const pType = String(p[\"type\"] ?? \"\");\n if (COUNTED_TYPES.has(pType)) {\n messageCount++;\n }\n // Extract model from response_item\n if (!model) {\n const info = p[\"info\"] as Record<string, unknown> | undefined;\n const m = info?.[\"model\"] ?? p[\"model\"];\n if (typeof m === \"string\" && m.trim()) model = m.trim();\n }\n }\n\n if (recordType === \"event_msg\") {\n const p = (data[\"payload\"] ?? {}) as Record<string, unknown>;\n if (String(p[\"type\"] ?? \"\") === \"token_count\") {\n const info = p[\"info\"] as Record<string, unknown> | undefined;\n const totalUsage = info?.[\"total_token_usage\"] as Record<string, unknown> | undefined;\n const cumulativeTotal = Number(totalUsage?.[\"total_tokens\"] ?? 0);\n\n if (cumulativeTotal > 0 && cumulativeTotal !== scanPrevCumulativeTotal) {\n scanPrevCumulativeTotal = cumulativeTotal;\n\n const lastUsage = info?.[\"last_token_usage\"] as Record<string, unknown> | undefined;\n let inputTokens = 0;\n let cachedInputTokens = 0;\n let outputTokens = 0;\n let reasoningTokens = 0;\n\n if (lastUsage) {\n inputTokens = Number(lastUsage[\"input_tokens\"] ?? 0);\n cachedInputTokens = Number(lastUsage[\"cached_input_tokens\"] ?? 0);\n outputTokens = Number(lastUsage[\"output_tokens\"] ?? 0);\n reasoningTokens = Number(lastUsage[\"reasoning_output_tokens\"] ?? 0);\n } else if (cumulativeTotal > 0 && totalUsage) {\n inputTokens = Number(totalUsage[\"input_tokens\"] ?? 0) - scanPrevInput;\n cachedInputTokens = Number(totalUsage[\"cached_input_tokens\"] ?? 0) - scanPrevCached;\n outputTokens = Number(totalUsage[\"output_tokens\"] ?? 0) - scanPrevOutput;\n reasoningTokens =\n Number(totalUsage[\"reasoning_output_tokens\"] ?? 0) - scanPrevReasoning;\n\n scanPrevInput = Number(totalUsage[\"input_tokens\"] ?? 0);\n scanPrevCached = Number(totalUsage[\"cached_input_tokens\"] ?? 0);\n scanPrevOutput = Number(totalUsage[\"output_tokens\"] ?? 0);\n scanPrevReasoning = Number(totalUsage[\"reasoning_output_tokens\"] ?? 0);\n }\n\n const uncachedInput = Math.max(0, inputTokens - cachedInputTokens);\n totalInputTokens += uncachedInput;\n totalOutputTokens += outputTokens + reasoningTokens;\n }\n }\n }\n } catch {\n // skip\n }\n }\n\n const directory = payload[\"cwd\"] ? String(payload[\"cwd\"]) : \"\";\n\n return {\n id: sessionId,\n slug: `codex/${sessionId}`,\n title,\n directory,\n time_created: createdAt,\n time_updated: updatedAt,\n stats: {\n message_count: messageCount,\n total_input_tokens: totalInputTokens,\n total_output_tokens: totalOutputTokens,\n total_cost: 0,\n },\n };\n }\n\n private extractTitleFromLines(lines: string[]): string | null {\n let userMessageCount = 0;\n for (const line of lines.slice(0, 20)) {\n try {\n const data = JSON.parse(line);\n const recordType = String(data[\"type\"] ?? \"\");\n if (recordType !== \"response_item\") continue;\n\n const payload = (data[\"payload\"] ?? {}) as Record<string, unknown>;\n const pType = String(payload[\"type\"] ?? \"\");\n if (pType !== \"message\") continue;\n if (String(payload[\"role\"] ?? \"\") !== \"user\") continue;\n\n // Skip the first user message (context injection); use the second\n userMessageCount++;\n if (userMessageCount < 2) continue;\n\n const content = payload[\"content\"];\n if (Array.isArray(content)) {\n const texts = content\n .filter((item) => typeof item === \"object\" && item !== null && \"text\" in item)\n .map((item) => String((item as Record<string, unknown>)[\"text\"] ?? \"\"))\n .join(\" \");\n return normalizeTitleText(texts);\n }\n if (typeof content === \"string\") {\n return normalizeTitleText(content);\n }\n } catch {\n // skip\n }\n }\n return null;\n }\n\n // ---- Record conversion ----\n\n private convertRecord(\n data: Record<string, unknown>,\n messages: Message[],\n pendingToolCalls: Map<string, [number, number]>,\n sessionId: string,\n currentAssistantIndex: number | null,\n latestAssistantTextIndex: number | null,\n pendingPlan: MessagePart | null,\n ): {\n currentAssistantIndex: number | null;\n latestAssistantTextIndex: number | null;\n pendingPlan: MessagePart | null;\n } {\n const recordType = String(data[\"type\"] ?? \"\");\n\n // Skip non-response records\n if (recordType === \"session_meta\" || recordType === \"event_msg\") {\n return { currentAssistantIndex, latestAssistantTextIndex, pendingPlan };\n }\n\n if (recordType !== \"response_item\") {\n return { currentAssistantIndex, latestAssistantTextIndex, pendingPlan };\n }\n\n const payload = (data[\"payload\"] ?? {}) as Record<string, unknown>;\n const payloadType = String(payload[\"type\"] ?? \"\");\n const timestampMs = parseTimestampMs(data) || parseTimestampMs(payload);\n\n switch (payloadType) {\n case \"message\": {\n const role = String(payload[\"role\"] ?? \"\");\n if (role === \"assistant\") {\n return this.convertAssistantMessage(\n payload,\n messages,\n timestampMs,\n currentAssistantIndex,\n latestAssistantTextIndex,\n pendingPlan,\n );\n }\n if (role === \"user\") {\n return this.convertUserMessage(\n payload,\n messages,\n timestampMs,\n currentAssistantIndex,\n latestAssistantTextIndex,\n pendingPlan,\n );\n }\n break;\n }\n\n case \"reasoning\":\n return this.convertReasoning(payload, messages, timestampMs, currentAssistantIndex);\n\n case \"function_call\":\n return this.convertFunctionCall(\n payload,\n messages,\n pendingToolCalls,\n timestampMs,\n currentAssistantIndex,\n latestAssistantTextIndex,\n );\n\n case \"function_call_output\":\n this.convertFunctionCallOutput(payload, messages, pendingToolCalls, timestampMs);\n return { currentAssistantIndex, latestAssistantTextIndex, pendingPlan };\n\n case \"custom_tool_call\":\n return this.convertCustomToolCall(\n payload,\n messages,\n pendingToolCalls,\n timestampMs,\n currentAssistantIndex,\n latestAssistantTextIndex,\n );\n\n case \"custom_tool_call_output\":\n this.convertCustomToolCallOutput(payload, messages, pendingToolCalls, timestampMs);\n return { currentAssistantIndex, latestAssistantTextIndex, pendingPlan };\n }\n\n return { currentAssistantIndex, latestAssistantTextIndex, pendingPlan };\n }\n\n // ---- Assistant message ----\n\n private convertAssistantMessage(\n payload: Record<string, unknown>,\n messages: Message[],\n timestampMs: number,\n currentAssistantIndex: number | null,\n latestAssistantTextIndex: number | null,\n pendingPlan: MessagePart | null,\n ): {\n currentAssistantIndex: number | null;\n latestAssistantTextIndex: number | null;\n pendingPlan: MessagePart | null;\n } {\n const content = payload[\"content\"];\n if (!Array.isArray(content)) {\n return { currentAssistantIndex, latestAssistantTextIndex, pendingPlan };\n }\n\n // Extract output_text items\n const textParts: string[] = [];\n for (const item of content) {\n if (typeof item !== \"object\" || item === null) continue;\n const ci = item as Record<string, unknown>;\n if (String(ci[\"type\"] ?? \"\") === \"output_text\") {\n const text = String(ci[\"text\"] ?? \"\");\n if (text.trim()) textParts.push(text);\n }\n }\n\n if (textParts.length === 0) {\n return { currentAssistantIndex, latestAssistantTextIndex, pendingPlan };\n }\n\n const fullText = textParts.join(\"\\n\");\n\n // Check for proposed plan\n const planMatch = fullText.match(PROPOSED_PLAN_PATTERN);\n if (planMatch) {\n const planText = planMatch[1]!.trim();\n const planPart: MessagePart = {\n type: \"plan\",\n text: planText,\n approval_status: \"success\",\n time_created: timestampMs,\n };\n pendingPlan = planPart;\n }\n\n // Build text part (strip the proposed plan tags)\n const displayText = fullText.replace(PROPOSED_PLAN_PATTERN, \"\").trim();\n if (!displayText) {\n return { currentAssistantIndex, latestAssistantTextIndex, pendingPlan };\n }\n\n const textPart: MessagePart = { type: \"text\", text: displayText, time_created: timestampMs };\n\n // Append to current assistant or create new one\n if (currentAssistantIndex !== null) {\n const message = messages[currentAssistantIndex]!;\n const hasTool = message.parts.some((p) => p.type === \"tool\");\n if (!hasTool) {\n message.parts.push(textPart);\n latestAssistantTextIndex = currentAssistantIndex;\n return { currentAssistantIndex, latestAssistantTextIndex, pendingPlan };\n }\n }\n\n messages.push(\n this.buildMessage({\n messageId: \"\",\n role: \"assistant\",\n timestampMs,\n parts: [textPart],\n agent: \"codex\",\n }),\n );\n currentAssistantIndex = messages.length - 1;\n latestAssistantTextIndex = currentAssistantIndex;\n\n return { currentAssistantIndex, latestAssistantTextIndex, pendingPlan };\n }\n\n // ---- User message ----\n\n private convertUserMessage(\n payload: Record<string, unknown>,\n messages: Message[],\n timestampMs: number,\n currentAssistantIndex: number | null,\n latestAssistantTextIndex: number | null,\n pendingPlan: MessagePart | null,\n ): {\n currentAssistantIndex: number | null;\n latestAssistantTextIndex: number | null;\n pendingPlan: MessagePart | null;\n } {\n const content = payload[\"content\"];\n const text = Array.isArray(content)\n ? content\n .map((c) =>\n typeof c === \"object\" && c !== null\n ? String((c as Record<string, unknown>)[\"text\"] ?? \"\")\n : String(c ?? \"\"),\n )\n .join(\" \")\n : String(content ?? \"\");\n\n if (!text.trim()) {\n return { currentAssistantIndex, latestAssistantTextIndex, pendingPlan };\n }\n\n // Skip injected developer/system context messages\n if (isDeveloperLikeUserMessage(text)) {\n return { currentAssistantIndex, latestAssistantTextIndex, pendingPlan };\n }\n\n // Check for plan approval\n if (text.trimStart().startsWith(PLAN_APPROVAL_PREFIX)) {\n // Finalize pending plan by attaching it to current assistant\n if (pendingPlan && currentAssistantIndex !== null) {\n messages[currentAssistantIndex]!.parts.push(pendingPlan);\n }\n pendingPlan = null;\n\n // The approval message itself is a user message\n messages.push(\n this.buildMessage({\n messageId: \"\",\n role: \"user\",\n timestampMs,\n parts: [{ type: \"text\", text: text.trim(), time_created: timestampMs }],\n }),\n );\n\n currentAssistantIndex = null;\n latestAssistantTextIndex = null;\n return { currentAssistantIndex, latestAssistantTextIndex, pendingPlan };\n }\n\n // Check for subagent notification\n const subagentMatch = text.match(SUBAGENT_NOTIFICATION_PATTERN);\n if (subagentMatch) {\n try {\n const notifPayload = JSON.parse(subagentMatch[1]!) as Record<string, unknown>;\n const agentId = String(notifPayload[\"agent_id\"] ?? \"\");\n const nickname = String(notifPayload[\"nickname\"] ?? \"\");\n const completedText = String(notifPayload[\"completed\"] ?? \"\");\n\n // Convert user message with subagent notification to assistant message\n const textPart: MessagePart = {\n type: \"text\",\n text: completedText || `Subagent ${nickname} completed`,\n time_created: timestampMs,\n };\n\n messages.push(\n this.buildMessage({\n messageId: \"\",\n role: \"assistant\",\n timestampMs,\n parts: [textPart],\n agent: \"codex\",\n subagent_id: agentId || undefined,\n nickname: nickname || undefined,\n }),\n );\n\n currentAssistantIndex = null;\n latestAssistantTextIndex = null;\n return { currentAssistantIndex, latestAssistantTextIndex, pendingPlan };\n } catch {\n // Not valid JSON, treat as normal user message\n }\n }\n\n // Normal user message\n messages.push(\n this.buildMessage({\n messageId: \"\",\n role: \"user\",\n timestampMs,\n parts: [{ type: \"text\", text: text.trim(), time_created: timestampMs }],\n }),\n );\n\n currentAssistantIndex = null;\n latestAssistantTextIndex = null;\n return { currentAssistantIndex, latestAssistantTextIndex, pendingPlan };\n }\n\n // ---- Reasoning ----\n\n private convertReasoning(\n payload: Record<string, unknown>,\n messages: Message[],\n timestampMs: number,\n currentAssistantIndex: number | null,\n ): {\n currentAssistantIndex: number | null;\n latestAssistantTextIndex: number | null;\n pendingPlan: MessagePart | null;\n } {\n const summary = payload[\"summary\"];\n if (!Array.isArray(summary)) {\n return { currentAssistantIndex, latestAssistantTextIndex: null, pendingPlan: null };\n }\n\n const texts: string[] = [];\n for (const item of summary) {\n if (typeof item === \"object\" && item !== null) {\n const ci = item as Record<string, unknown>;\n if (String(ci[\"type\"] ?? \"\") === \"summary_text\") {\n const text = String(ci[\"text\"] ?? \"\");\n if (text.trim()) texts.push(text);\n }\n }\n }\n\n if (texts.length === 0) {\n return { currentAssistantIndex, latestAssistantTextIndex: null, pendingPlan: null };\n }\n\n const reasoningText = texts.join(\"\\n\");\n const part: MessagePart = { type: \"reasoning\", text: reasoningText, time_created: timestampMs };\n\n if (currentAssistantIndex !== null) {\n const message = messages[currentAssistantIndex]!;\n const hasText = message.parts.some((p) => p.type === \"text\");\n const hasTool = message.parts.some((p) => p.type === \"tool\");\n if (!hasText && !hasTool) {\n message.parts.push(part);\n return { currentAssistantIndex, latestAssistantTextIndex: null, pendingPlan: null };\n }\n }\n\n messages.push(\n this.buildMessage({\n messageId: \"\",\n role: \"assistant\",\n timestampMs,\n parts: [part],\n agent: \"codex\",\n }),\n );\n\n return {\n currentAssistantIndex: messages.length - 1,\n latestAssistantTextIndex: null,\n pendingPlan: null,\n };\n }\n\n // ---- Function call ----\n\n private convertFunctionCall(\n payload: Record<string, unknown>,\n messages: Message[],\n pendingToolCalls: Map<string, [number, number]>,\n timestampMs: number,\n currentAssistantIndex: number | null,\n latestAssistantTextIndex: number | null,\n ): {\n currentAssistantIndex: number | null;\n latestAssistantTextIndex: number | null;\n pendingPlan: MessagePart | null;\n } {\n const callId = String(payload[\"call_id\"] ?? \"\").trim();\n const name = String(payload[\"name\"] ?? \"\").trim();\n if (!name) {\n return { currentAssistantIndex, latestAssistantTextIndex, pendingPlan: null };\n }\n\n const mappedName = mapToolTitle(name);\n const arguments_ = normalizeToolArguments(payload[\"arguments\"]);\n\n const toolPart: MessagePart = {\n type: \"tool\",\n tool: mappedName,\n callID: callId,\n title: `Tool: ${mappedName}`,\n state: {\n arguments: arguments_,\n output: null,\n },\n time_created: timestampMs,\n };\n\n // Attach to latest assistant text message\n const targetIndex = latestAssistantTextIndex ?? currentAssistantIndex;\n if (targetIndex !== null) {\n const message = messages[targetIndex]!;\n const partIndex = message.parts.length;\n message.parts.push(toolPart);\n message.mode = \"tool\";\n if (callId) {\n pendingToolCalls.set(callId, [targetIndex, partIndex]);\n }\n return {\n currentAssistantIndex: targetIndex,\n latestAssistantTextIndex: targetIndex,\n pendingPlan: null,\n };\n }\n\n // Fallback: create new assistant message for tool\n messages.push(\n this.buildMessage({\n messageId: \"\",\n role: \"assistant\",\n timestampMs,\n parts: [toolPart],\n agent: \"codex\",\n mode: \"tool\",\n }),\n );\n const newIndex = messages.length - 1;\n if (callId) {\n pendingToolCalls.set(callId, [newIndex, 0]);\n }\n\n return { currentAssistantIndex: newIndex, latestAssistantTextIndex: null, pendingPlan: null };\n }\n\n // ---- Function call output ----\n\n private convertFunctionCallOutput(\n payload: Record<string, unknown>,\n messages: Message[],\n pendingToolCalls: Map<string, [number, number]>,\n timestampMs: number,\n ): void {\n const callId = String(payload[\"call_id\"] ?? \"\").trim();\n if (!callId) return;\n\n const location = pendingToolCalls.get(callId);\n if (!location) return;\n\n const outputText = String(payload[\"output\"] ?? \"\");\n const outputParts: MessagePart[] = outputText.trim()\n ? [{ type: \"text\", text: outputText, time_created: timestampMs }]\n : [];\n\n const [msgIndex, partIndex] = location;\n const state =\n messages[msgIndex]!.parts[partIndex]!.state ??\n (messages[msgIndex]!.parts[partIndex]!.state = {});\n\n if (outputParts.length > 0) {\n state.output = [...outputParts];\n state.status = \"completed\";\n }\n }\n\n // ---- Custom tool call ----\n\n private convertCustomToolCall(\n payload: Record<string, unknown>,\n messages: Message[],\n pendingToolCalls: Map<string, [number, number]>,\n timestampMs: number,\n currentAssistantIndex: number | null,\n latestAssistantTextIndex: number | null,\n ): {\n currentAssistantIndex: number | null;\n latestAssistantTextIndex: number | null;\n pendingPlan: MessagePart | null;\n } {\n const callId = String(payload[\"call_id\"] ?? \"\").trim();\n const name = String(payload[\"name\"] ?? \"\").trim();\n if (!name) {\n return { currentAssistantIndex, latestAssistantTextIndex, pendingPlan: null };\n }\n\n const mappedName = mapToolTitle(name);\n const rawInput = payload[\"input\"];\n const normalizedInput = normalizeCustomToolArguments(name, rawInput);\n\n const toolPart: MessagePart = {\n type: \"tool\",\n tool: mappedName,\n callID: callId,\n title: `Tool: ${mappedName}`,\n state: {\n arguments: normalizedInput,\n output: null,\n },\n time_created: timestampMs,\n };\n\n // Attach to latest assistant text message\n const targetIndex = latestAssistantTextIndex ?? currentAssistantIndex;\n if (targetIndex !== null) {\n const message = messages[targetIndex]!;\n const partIndex = message.parts.length;\n message.parts.push(toolPart);\n message.mode = \"tool\";\n if (callId) {\n pendingToolCalls.set(callId, [targetIndex, partIndex]);\n }\n return {\n currentAssistantIndex: targetIndex,\n latestAssistantTextIndex: targetIndex,\n pendingPlan: null,\n };\n }\n\n // Fallback: create new assistant message\n messages.push(\n this.buildMessage({\n messageId: \"\",\n role: \"assistant\",\n timestampMs,\n parts: [toolPart],\n agent: \"codex\",\n mode: \"tool\",\n }),\n );\n const newIndex = messages.length - 1;\n if (callId) {\n pendingToolCalls.set(callId, [newIndex, 0]);\n }\n\n return { currentAssistantIndex: newIndex, latestAssistantTextIndex: null, pendingPlan: null };\n }\n\n // ---- Custom tool call output ----\n\n private convertCustomToolCallOutput(\n payload: Record<string, unknown>,\n messages: Message[],\n pendingToolCalls: Map<string, [number, number]>,\n timestampMs: number,\n ): void {\n const callId = String(payload[\"call_id\"] ?? \"\").trim();\n if (!callId) return;\n\n const location = pendingToolCalls.get(callId);\n if (!location) return;\n\n const outputText = String(payload[\"output\"] ?? \"\");\n const outputParts: MessagePart[] = outputText.trim()\n ? [{ type: \"text\", text: outputText, time_created: timestampMs }]\n : [];\n\n const [msgIndex, partIndex] = location;\n const state =\n messages[msgIndex]!.parts[partIndex]!.state ??\n (messages[msgIndex]!.parts[partIndex]!.state = {});\n\n if (outputParts.length > 0) {\n state.output = [...outputParts];\n state.status = \"completed\";\n }\n }\n\n // ---- Message builder ----\n\n private buildMessage(opts: {\n messageId: string;\n role: string;\n timestampMs: number;\n parts: MessagePart[];\n agent?: string;\n mode?: string;\n model?: string | null;\n provider?: string | null;\n tokens?: Record<string, unknown>;\n cost?: number;\n subagent_id?: string;\n nickname?: string;\n }): Message {\n return {\n id: opts.messageId,\n role: opts.role as Message[\"role\"],\n agent: opts.agent ?? null,\n time_created: opts.timestampMs,\n mode: opts.mode ?? null,\n model: opts.model ?? null,\n provider: opts.provider ?? null,\n tokens: opts.tokens ? (opts.tokens as Message[\"tokens\"]) : undefined,\n cost: opts.cost ?? 0,\n parts: opts.parts,\n subagent_id: opts.subagent_id,\n nickname: opts.nickname,\n };\n }\n}\n","import { existsSync, readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { join, normalize } from \"node:path\";\nimport { BaseAgent } from \"./base.js\";\nimport type { SessionCacheMeta, ChangeCheckResult } from \"./base.js\";\nimport type { SessionHead, SessionData, Message, MessagePart } from \"../types/index.js\";\nimport { getCursorDataPath } from \"../discovery/paths.js\";\nimport { openDbReadOnly, isSqliteAvailable, type SQLiteDatabase } from \"../utils/sqlite.js\";\nimport { perf } from \"../utils/perf.js\";\n\n// ---------------------------------------------------------------------------\n// Cursor data model interfaces\n// ---------------------------------------------------------------------------\n\ninterface ComposerData {\n id?: string;\n composerId?: string;\n text?: string;\n name?: string;\n title?: string;\n createdAt?: number;\n updatedAt?: number;\n lastSendTime?: number;\n lastUpdatedAt?: number;\n model?: string;\n modelConfig?: { modelName?: string };\n inputTokenCount?: number;\n outputTokenCount?: number;\n subagentInfos?: SubagentInfo[];\n chatMessages?: ChatMessage[];\n usageData?: {\n contextTokensUsed?: number;\n contextTokenLimit?: number;\n contextUsagePercent?: number;\n };\n}\n\ninterface BubbleData {\n id?: string;\n composerId?: string;\n chatMessages?: ChatMessage[];\n type?: number; // 1 = user, 2 = assistant\n text?: string;\n requestId?: string;\n createdAt?: number;\n timestamp?: number;\n timingInfo?: {\n clientRpcSendTime?: number;\n clientSettleTime?: number;\n clientEndTime?: number;\n };\n tokenCount?: {\n inputTokens?: number;\n outputTokens?: number;\n };\n modelInfo?: {\n modelName?: string;\n };\n toolFormerData?: {\n name?: string;\n toolCallId?: string;\n status?: string;\n params?: unknown;\n result?: unknown;\n additionalData?: Record<string, unknown>;\n };\n [key: string]: unknown;\n}\n\ninterface SubagentInfo {\n id?: string;\n composerId?: string;\n title?: string;\n nickname?: string;\n}\n\ninterface ChatMessage {\n role: string;\n text?: string;\n createdAt?: number;\n timestamp?: number;\n actions?: ActionEntry[];\n isCompletion?: boolean;\n [key: string]: unknown;\n}\n\ninterface ActionEntry {\n type?: string;\n tool?: string;\n input?: Record<string, unknown>;\n output?: unknown;\n state?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nconst CURSOR_TOOL_TITLE_MAP: Record<string, string> = {\n read_file_v2: \"read\",\n edit_file_v2: \"edit\",\n run_terminal_command_v2: \"bash\",\n ripgrep_raw_search: \"grep\",\n glob_file_search: \"glob\",\n};\n\nfunction mapToolTitle(toolName: string): string {\n return CURSOR_TOOL_TITLE_MAP[toolName] ?? toolName;\n}\n\n/** Normalize tool output into MessagePart[] */\nfunction normalizeToolOutputParts(output: unknown, timestampMs: number): MessagePart[] {\n if (output == null) return [];\n\n if (typeof output === \"string\") {\n return output.trim()\n ? [{ type: \"text\" as const, text: output, time_created: timestampMs }]\n : [];\n }\n\n if (Array.isArray(output)) {\n const parts: MessagePart[] = [];\n for (const item of output) {\n if (typeof item === \"object\" && item !== null) {\n const text = String(\n (item as Record<string, unknown>).text ?? (item as Record<string, unknown>).content ?? \"\",\n );\n if (text.trim()) parts.push({ type: \"text\", text, time_created: timestampMs });\n } else if (typeof item === \"string\" && item.trim()) {\n parts.push({ type: \"text\", text: item, time_created: timestampMs });\n }\n }\n return parts;\n }\n\n // For object output, stringify for readability\n const text = String(output);\n return text.trim() ? [{ type: \"text\", text, time_created: timestampMs }] : [];\n}\n\n/** Extract a timestamp (in ms) from a chat message */\nfunction extractTimestamp(msg: ChatMessage): number {\n if (msg.createdAt && typeof msg.createdAt === \"number\" && msg.createdAt > 0) {\n return msg.createdAt;\n }\n if (msg.timestamp && typeof msg.timestamp === \"number\" && msg.timestamp > 0) {\n return msg.timestamp;\n }\n return 0;\n}\n\n/** Build a normalized tool state object from an action entry */\nfunction buildToolState(action: ActionEntry): MessagePart[\"state\"] {\n const state: MessagePart[\"state\"] = {};\n\n // Copy input\n if (action.input) {\n state.input = action.input;\n }\n\n // Normalize output into parts\n if (action.output != null) {\n const ts = 0; // we don't have a finer-grained timestamp for the output\n const outputParts = normalizeToolOutputParts(action.output, ts);\n state.output = outputParts.length > 0 ? outputParts : action.output;\n }\n\n // Merge any explicit state fields\n if (action.state) {\n Object.assign(state, action.state);\n }\n\n // Derive status from output shape if not set\n if (!state.status) {\n if (typeof action.output === \"object\" && action.output !== null) {\n const out = action.output as Record<string, unknown>;\n if (out.success === true) state.status = \"completed\";\n else if (out.success === false) state.status = \"error\";\n else state.status = \"completed\";\n } else if (action.output != null) {\n state.status = \"completed\";\n }\n }\n\n return state;\n}\n\n/** Build a MessagePart for a tool action */\nfunction buildToolPart(action: ActionEntry, timestampMs: number): MessagePart {\n const toolName = action.tool ?? \"unknown\";\n return {\n type: \"tool\",\n tool: mapToolTitle(toolName),\n callID: action.type ? `${action.type}:${String(action.input?.id ?? \"\")}` : \"\",\n title: `Tool: ${mapToolTitle(toolName)}`,\n state: buildToolState(action),\n time_created: timestampMs,\n };\n}\n\n/** Build a MessagePart for terminal command actions */\nfunction buildTerminalToolPart(action: ActionEntry, timestampMs: number): MessagePart {\n const command = String(action.input?.command ?? \"\");\n const description = String(action.input?.commandDescription ?? \"\");\n\n return {\n type: \"tool\",\n tool: \"bash\",\n callID: \"\",\n title: description || `bash: ${command.slice(0, 60)}`,\n state: {\n input: { command },\n output:\n typeof action.output === \"string\"\n ? [{ type: \"text\" as const, text: action.output, time_created: timestampMs }]\n : normalizeToolOutputParts(action.output, timestampMs),\n },\n time_created: timestampMs,\n };\n}\n\n/** Convert an ActionEntry into a MessagePart */\nfunction convertActionToPart(action: ActionEntry, timestampMs: number): MessagePart | null {\n const toolName = action.tool ?? \"\";\n\n // Terminal commands get special handling\n if (toolName === \"run_terminal_command_v2\") {\n return buildTerminalToolPart(action, timestampMs);\n }\n\n // Generic tool call\n if (toolName && action.type === \"tool\") {\n return buildToolPart(action, timestampMs);\n }\n\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// CursorAgent\n// ---------------------------------------------------------------------------\n\nexport class CursorAgent extends BaseAgent {\n readonly name = \"cursor\";\n readonly displayName = \"Cursor\";\n\n private dbPath: string | null = null;\n\n // Cache composer data from scan so getSessionData can reuse it\n private composerCache = new Map<string, ComposerData>();\n\n // Session metadata for caching\n private sessionMetaMap = new Map<string, { id: string; sourcePath: string }>();\n\n private findDbPath(): string | null {\n if (!isSqliteAvailable()) return null;\n const dataPath = getCursorDataPath();\n if (!dataPath) return null;\n return join(dataPath, \"globalStorage\", \"state.vscdb\");\n }\n\n /**\n * Build a map of composerId → workspace folder path by reading\n * workspaceStorage/{id}/workspace.json and the corresponding state.vscdb.\n */\n private buildWorkspacePathMap(): Map<string, string> {\n const map = new Map<string, string>();\n const dataPath = getCursorDataPath();\n if (!dataPath) return map;\n\n const wsStoragePath = join(dataPath, \"workspaceStorage\");\n if (!existsSync(wsStoragePath)) return map;\n\n let entryNames: string[];\n try {\n entryNames = readdirSync(wsStoragePath) as string[];\n } catch {\n return map;\n }\n\n for (const name of entryNames) {\n const wsDir = join(wsStoragePath, name);\n try {\n if (!statSync(wsDir).isDirectory()) continue;\n } catch {\n continue;\n }\n const wsJsonPath = join(wsDir, \"workspace.json\");\n if (!existsSync(wsJsonPath)) continue;\n\n // Parse workspace.json to get the project folder path\n let workspacePath: string;\n try {\n const data = JSON.parse(readFileSync(wsJsonPath, \"utf-8\")) as {\n folder?: string;\n workspace?: string;\n };\n const uri = data.folder ?? data.workspace ?? \"\";\n if (!uri) continue;\n workspacePath = normalize(decodeURIComponent(uri.replace(/^file:\\/\\//, \"\")));\n } catch {\n continue;\n }\n\n // Read composer IDs from this workspace's state.vscdb (ItemTable)\n const wsDbPath = join(wsDir, \"state.vscdb\");\n if (!existsSync(wsDbPath)) continue;\n\n const wsDb = openDbReadOnly(wsDbPath);\n if (!wsDb) continue;\n\n try {\n const row = wsDb\n .prepare(\"SELECT value FROM ItemTable WHERE key = 'composer.composerData'\")\n .get() as { value: string } | undefined;\n if (!row?.value) continue;\n\n const parsed = JSON.parse(row.value) as unknown;\n let composers: Array<{ composerId?: string; id?: string }>;\n\n if (\n parsed !== null &&\n typeof parsed === \"object\" &&\n \"allComposers\" in (parsed as Record<string, unknown>) &&\n Array.isArray((parsed as Record<string, unknown>)[\"allComposers\"])\n ) {\n composers = (parsed as { allComposers: Array<{ composerId?: string; id?: string }> })\n .allComposers;\n } else if (Array.isArray(parsed)) {\n composers = parsed as Array<{ composerId?: string; id?: string }>;\n } else {\n continue;\n }\n\n for (const c of composers) {\n const id = c.composerId ?? c.id;\n if (id) map.set(id, workspacePath);\n }\n } catch {\n // skip unreadable workspace db\n } finally {\n wsDb.close();\n }\n }\n\n return map;\n }\n\n isAvailable(): boolean {\n this.dbPath = this.findDbPath();\n return this.dbPath !== null && existsSync(this.dbPath);\n }\n\n scan(): SessionHead[] {\n if (!this.dbPath) return [];\n\n const scanMarker = perf.start(\"cursor:scan\");\n\n const dbMarker = perf.start(\"openDatabase\");\n const db = this.openDatabase();\n perf.end(dbMarker);\n\n if (!db) return [];\n\n // Build composerId → workspace path map from workspaceStorage\n const wsMarker = perf.start(\"buildWorkspacePathMap\");\n const workspacePathMap = this.buildWorkspacePathMap();\n perf.end(wsMarker);\n\n try {\n const rows = db\n .prepare(\"SELECT key, value FROM cursorDiskKV WHERE key LIKE 'composerData:%'\")\n .all() as Array<{ key: string; value: string }>;\n\n const heads: SessionHead[] = [];\n\n for (const row of rows) {\n try {\n const composer = JSON.parse(row.value) as ComposerData;\n if (!composer.id && !composer.composerId) continue;\n\n const composerId = composer.id || composer.composerId || \"\";\n\n // Try to extract requestId from bubbles (like agent-dump does)\n const requestId = this.extractRequestIdFromBubbles(db, composerId);\n const sessionId = requestId || composerId;\n\n const title = this.extractTitle(composer);\n const createdAt = composer.createdAt ?? 0;\n const updatedAt = composer.updatedAt ?? createdAt;\n\n // Load actual messages to filter out empty composers\n const messages = this.loadMessagesFromBubbles(db, composerId, sessionId);\n const hasSubagents =\n Array.isArray(composer.subagentInfos) && composer.subagentInfos.length > 0;\n if (messages.length === 0 && !hasSubagents) {\n continue; // Skip empty sessions\n }\n const messageCount = messages.length;\n\n const directory = workspacePathMap.get(composerId) ?? \"\";\n\n heads.push({\n id: sessionId,\n slug: `cursor/${sessionId}`,\n title,\n directory,\n time_created: createdAt,\n time_updated: updatedAt || undefined,\n stats: {\n message_count: messageCount,\n total_input_tokens: composer.inputTokenCount ?? 0,\n total_output_tokens: composer.outputTokenCount ?? 0,\n total_cost: 0,\n },\n });\n\n // Cache with sessionId (requestId) as key\n this.composerCache.set(sessionId, composer);\n // Also cache composerId -> sessionId mapping and directory\n this.composerCache.set(`__mapping__${composerId}`, {\n sessionId,\n } as unknown as ComposerData);\n if (directory) {\n this.composerCache.set(`__dir__${composerId}`, {\n directory,\n } as unknown as ComposerData);\n }\n\n // Store session metadata for caching\n this.sessionMetaMap.set(sessionId, {\n id: sessionId,\n sourcePath: this.dbPath || \"\",\n });\n } catch {\n // skip malformed entries\n }\n }\n\n perf.end(scanMarker);\n return heads;\n } catch {\n return [];\n } finally {\n db.close();\n }\n }\n\n getSessionMetaMap(): Map<string, SessionCacheMeta> {\n return this.sessionMetaMap as Map<string, SessionCacheMeta>;\n }\n\n setSessionMetaMap(meta: Map<string, SessionCacheMeta>): void {\n this.sessionMetaMap = meta as Map<string, { id: string; sourcePath: string }>;\n }\n\n /**\n * 检测数据库变更\n * 对于 SQLite,检测数据库文件修改时间\n */\n checkForChanges(sinceTimestamp: number, cachedSessions: SessionHead[]): ChangeCheckResult {\n if (!this.dbPath) {\n this.dbPath = this.findDbPath();\n }\n if (!this.dbPath || !existsSync(this.dbPath)) {\n return { hasChanges: false, timestamp: Date.now() };\n }\n\n try {\n // 检测数据库文件修改时间\n const stat = statSync(this.dbPath);\n const hasChanges = stat.mtimeMs > sinceTimestamp;\n\n // 如果数据库有变更,标记所有缓存会话需要刷新\n // 因为 SQLite 内部变更检测较复杂,简单起见全部刷新\n const changedIds = hasChanges ? cachedSessions.map((s) => s.id) : [];\n\n return {\n hasChanges,\n changedIds,\n timestamp: Date.now(),\n };\n } catch {\n return { hasChanges: false, timestamp: Date.now() };\n }\n }\n\n /**\n * 增量扫描 - 重新查询数据库\n */\n incrementalScan(_cachedSessions: SessionHead[], _changedIds: string[]): SessionHead[] {\n // 对于 Cursor,直接重新执行完整扫描\n // 因为 scan() 方法已经做了很好的优化\n return this.scan();\n }\n\n getSessionData(sessionId: string): SessionData {\n // Ensure dbPath is set\n if (!this.dbPath) {\n this.dbPath = this.findDbPath();\n }\n if (!this.dbPath) {\n throw new Error(\"Cursor database is missing\");\n }\n\n const db = this.openDatabase();\n if (!db) {\n throw new Error(\"Cursor database is missing\");\n }\n\n try {\n // Try cached composer data first\n let composer = this.composerCache.get(sessionId);\n let resolvedSessionId = sessionId;\n\n if (!composer) {\n // Try loading directly by sessionId (might be composerId)\n composer = this.loadComposer(db, sessionId) ?? undefined;\n }\n\n if (!composer) {\n // sessionId might be a requestId - try to find the composer\n const composerId = this.findComposerIdByRequestId(db, sessionId);\n if (composerId) {\n composer = this.loadComposer(db, composerId) ?? undefined;\n resolvedSessionId = sessionId; // Keep the requestId as sessionId\n }\n }\n\n if (!composer) {\n throw new Error(`Session not found: ${sessionId}`);\n }\n\n const composerId = composer.id || composer.composerId || \"\";\n const title = this.extractTitle(composer);\n const createdAt = composer.createdAt ?? 0;\n const updatedAt = composer.updatedAt ?? createdAt;\n\n // Load messages from bubbles (like agent-dump does)\n const messages = this.loadMessagesFromBubbles(db, composerId, resolvedSessionId);\n\n // Aggregate stats\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n\n for (const msg of messages) {\n totalInputTokens += msg.tokens?.input ?? 0;\n totalOutputTokens += msg.tokens?.output ?? 0;\n }\n\n // Use session-level token counts if per-message counts are zero\n if (totalInputTokens === 0) totalInputTokens = composer.inputTokenCount ?? 0;\n if (totalOutputTokens === 0) totalOutputTokens = composer.outputTokenCount ?? 0;\n\n // Append subagent messages\n this.appendSubagentMessages(db, composer, messages);\n\n // Retrieve directory from cache (populated during scan) or build map on demand\n const cachedDir = this.composerCache.get(`__dir__${composerId}`);\n const directory =\n (cachedDir as unknown as { directory?: string })?.directory ??\n this.buildWorkspacePathMap().get(composerId) ??\n \"\";\n\n return {\n id: resolvedSessionId,\n title,\n slug: `cursor/${resolvedSessionId}`,\n directory,\n time_created: createdAt,\n time_updated: updatedAt || undefined,\n stats: {\n message_count: messages.length,\n total_input_tokens: totalInputTokens,\n total_output_tokens: totalOutputTokens,\n total_cost: 0,\n },\n messages,\n };\n } finally {\n db.close();\n }\n }\n\n // --- Private helpers ---\n\n private openDatabase(): SQLiteDatabase | null {\n if (!this.dbPath) return null;\n return openDbReadOnly(this.dbPath);\n }\n\n /** Extract requestId from bubbles for a composer (like agent-dump) */\n private extractRequestIdFromBubbles(db: SQLiteDatabase, composerId: string): string | null {\n try {\n const rows = db\n .prepare(\"SELECT value FROM cursorDiskKV WHERE key LIKE ? ORDER BY key\")\n .all(`bubbleId:${composerId}:%`) as Array<{ value: string }>;\n\n for (const row of rows) {\n try {\n const bubble = JSON.parse(row.value) as BubbleData;\n if (bubble.requestId && typeof bubble.requestId === \"string\" && bubble.requestId.trim()) {\n return bubble.requestId.trim();\n }\n } catch {\n // skip malformed bubbles\n }\n }\n } catch {\n // ignore errors\n }\n return null;\n }\n\n /** Find composerId by requestId (reverse lookup) */\n private findComposerIdByRequestId(db: SQLiteDatabase, requestId: string): string | null {\n try {\n const rows = db\n .prepare(\"SELECT key, value FROM cursorDiskKV WHERE key LIKE 'bubbleId:%' AND value LIKE ?\")\n .all(`%\"requestId\":\"${requestId}\"%`) as Array<{ key: string; value: string }>;\n\n for (const row of rows) {\n try {\n const bubble = JSON.parse(row.value) as BubbleData;\n if (bubble.requestId === requestId) {\n // Extract composerId from key (bubbleId:{composerId}:{bubbleId})\n const keyParts = row.key.split(\":\");\n if (keyParts.length >= 2 && keyParts[1]) {\n return keyParts[1];\n }\n }\n } catch {\n // skip malformed bubbles\n }\n }\n } catch {\n // ignore errors\n }\n return null;\n }\n\n /** Extract title from composer (like agent-dump) */\n private extractTitle(composer: ComposerData): string {\n if (composer.name && typeof composer.name === \"string\" && composer.name.trim()) {\n return composer.name.trim();\n }\n if (composer.title && typeof composer.title === \"string\" && composer.title.trim()) {\n return composer.title.trim();\n }\n if (composer.text && typeof composer.text === \"string\" && composer.text.trim()) {\n const firstLine = composer.text\n .split(\"\\n\")\n .find((l) => l.trim())\n ?.trim()\n .slice(0, 80);\n if (firstLine) return firstLine;\n }\n const composerId = composer.composerId || composer.id || \"\";\n return `Cursor Session ${composerId.slice(0, 8)}`;\n }\n\n /** Count messages from bubbles */\n private countMessagesFromBubbles(db: SQLiteDatabase, composerId: string): number {\n try {\n const rows = db\n .prepare(\"SELECT value FROM cursorDiskKV WHERE key LIKE ?\")\n .all(`bubbleId:${composerId}:%`) as Array<{ value: string }>;\n\n let count = 0;\n for (const row of rows) {\n try {\n const bubble = JSON.parse(row.value) as BubbleData;\n // type 1 = user, type 2 = assistant\n if (bubble.type === 1 || bubble.type === 2) {\n count++;\n }\n } catch {\n // skip malformed bubbles\n }\n }\n return count;\n } catch {\n return 0;\n }\n }\n\n /** Load messages from bubbles (like agent-dump) */\n private loadMessagesFromBubbles(\n db: SQLiteDatabase,\n composerId: string,\n _sessionId: string,\n ): Message[] {\n const messages: Message[] = [];\n\n try {\n const rows = db\n .prepare(\"SELECT key, value FROM cursorDiskKV WHERE key LIKE ? ORDER BY rowid ASC\")\n .all(`bubbleId:${composerId}:%`) as Array<{ key: string; value: string }>;\n\n let activeModelName: string | null = null;\n let messageIndex = 0;\n\n for (const row of rows) {\n try {\n const bubble = JSON.parse(row.value) as BubbleData;\n const bubbleId = row.key.split(\":\").pop() || String(messageIndex);\n\n // Determine role: type 2 = assistant, otherwise user\n const role = bubble.type === 2 ? \"assistant\" : \"user\";\n\n // Extract timestamp\n let timestampMs = 0;\n if (bubble.timingInfo?.clientRpcSendTime) {\n timestampMs = Math.floor(bubble.timingInfo.clientRpcSendTime);\n } else if (bubble.createdAt) {\n timestampMs = bubble.createdAt;\n } else if (bubble.timestamp) {\n timestampMs = bubble.timestamp;\n }\n\n // Track model from user turn\n if (role === \"user\" && bubble.modelInfo?.modelName) {\n activeModelName = bubble.modelInfo.modelName;\n }\n\n // Extract tokens\n const inputTokens = bubble.tokenCount?.inputTokens ?? 0;\n const outputTokens = bubble.tokenCount?.outputTokens ?? 0;\n\n // Build message parts\n const parts: MessagePart[] = [];\n\n // Text content\n const text = bubble.text?.trim();\n if (text) {\n parts.push({ type: \"text\", text, time_created: timestampMs });\n }\n\n // Tool calls from toolFormerData\n if (bubble.toolFormerData) {\n const toolPart = this.convertToolFormerData(bubble.toolFormerData, timestampMs);\n if (toolPart) {\n parts.push(toolPart);\n }\n }\n\n // Skip empty messages\n if (parts.length === 0) continue;\n\n messages.push({\n id: `cursor-${composerId}-${bubbleId}`,\n role: role as Message[\"role\"],\n agent: \"cursor\",\n time_created: timestampMs,\n time_completed: null,\n mode: role === \"assistant\" && parts.some((p) => p.type === \"tool\") ? \"tool\" : null,\n model: activeModelName,\n provider: null,\n tokens: { input: inputTokens, output: outputTokens },\n cost: 0,\n parts,\n });\n\n messageIndex++;\n } catch {\n // skip malformed bubbles\n }\n }\n } catch {\n // ignore errors\n }\n\n return messages;\n }\n\n /** Convert toolFormerData to MessagePart */\n private convertToolFormerData(\n toolData: BubbleData[\"toolFormerData\"],\n timestampMs: number,\n ): MessagePart | null {\n if (!toolData || !toolData.name) return null;\n\n const toolName = toolData.name;\n const normalizedName = toolName === \"create_plan\" ? \"plan\" : mapToolTitle(toolName);\n\n // Build state\n const state: MessagePart[\"state\"] = {\n status: toolData.status === \"completed\" ? \"completed\" : \"running\",\n };\n\n // Parse input params\n if (toolData.params) {\n if (typeof toolData.params === \"string\") {\n try {\n state.input = JSON.parse(toolData.params);\n } catch {\n state.input = { _raw: toolData.params };\n }\n } else {\n state.input = toolData.params;\n }\n }\n\n // Parse result/output\n if (toolData.result !== undefined) {\n if (typeof toolData.result === \"string\") {\n try {\n const parsed = JSON.parse(toolData.result);\n state.output = parsed;\n if (parsed.error || parsed.message || parsed.stderr) {\n state.error = parsed.error || parsed.message || parsed.stderr;\n state.status = \"error\";\n }\n } catch {\n state.output = toolData.result;\n }\n } else {\n state.output = toolData.result;\n }\n }\n\n // Handle plan tool specially\n if (toolName === \"create_plan\") {\n const planText =\n typeof state.input === \"object\" && state.input !== null\n ? (state.input as Record<string, unknown>).plan\n : undefined;\n return {\n type: \"plan\",\n title: \"Plan\",\n input: planText,\n approval_status: state.status === \"completed\" ? \"success\" : \"fail\",\n state,\n time_created: timestampMs,\n };\n }\n\n return {\n type: \"tool\",\n tool: normalizedName,\n callID: toolData.toolCallId || \"\",\n title: `Tool: ${toolName}`,\n state,\n time_created: timestampMs,\n };\n }\n\n private loadComposer(db: SQLiteDatabase, sessionId: string): ComposerData | null {\n const row = db\n .prepare(\"SELECT value FROM cursorDiskKV WHERE key = ?\")\n .get(`composerData:${sessionId}`) as { value: string } | undefined;\n\n if (!row) return null;\n\n try {\n return JSON.parse(row.value) as ComposerData;\n } catch {\n return null;\n }\n }\n\n private loadBubble(db: SQLiteDatabase, sessionId: string): BubbleData | null {\n const row = db\n .prepare(\"SELECT value FROM cursorDiskKV WHERE key = ?\")\n .get(`bubble:${sessionId}`) as { value: string } | undefined;\n\n if (!row) return null;\n\n try {\n return JSON.parse(row.value) as BubbleData;\n } catch {\n return null;\n }\n }\n\n private appendSubagentMessages(\n db: SQLiteDatabase,\n composer: ComposerData,\n messages: Message[],\n ): void {\n const subagentInfos = composer.subagentInfos;\n if (!Array.isArray(subagentInfos) || subagentInfos.length === 0) return;\n\n for (const subInfo of subagentInfos) {\n if (!subInfo.id) continue;\n\n const bubble = this.loadBubble(db, subInfo.id);\n if (!bubble || !Array.isArray(bubble.chatMessages)) continue;\n\n for (const chatMsg of bubble.chatMessages) {\n const role = chatMsg.role?.trim().toLowerCase();\n if (role !== \"user\" && role !== \"assistant\") continue;\n\n const timestampMs = extractTimestamp(chatMsg);\n const parts: MessagePart[] = [];\n\n const text = chatMsg.text ?? \"\";\n if (text.trim()) {\n parts.push({ type: \"text\", text, time_created: timestampMs });\n }\n\n if (role === \"assistant\" && Array.isArray(chatMsg.actions)) {\n for (const action of chatMsg.actions) {\n const part = convertActionToPart(action as ActionEntry, timestampMs);\n if (part) parts.push(part);\n }\n }\n\n if (parts.length === 0) continue;\n\n messages.push({\n id: `cursor-sub-${subInfo.id}`,\n role: role as Message[\"role\"],\n agent: \"cursor\",\n time_created: timestampMs,\n time_completed: null,\n mode: null,\n model: null,\n provider: null,\n tokens: undefined,\n cost: 0,\n subagent_id: subInfo.id,\n nickname: subInfo.nickname ?? subInfo.title,\n parts,\n });\n }\n }\n }\n}\n","import { registerAgent } from \"./registry.js\";\nimport { ClaudeCodeAgent } from \"./claudecode.js\";\nimport { OpenCodeAgent } from \"./opencode.js\";\nimport { KimiAgent } from \"./kimi.js\";\nimport { CodexAgent } from \"./codex.js\";\nimport { CursorAgent } from \"./cursor.js\";\n\nregisterAgent({\n name: \"claudecode\",\n displayName: \"Claude Code\",\n icon: \"/icon/agent/claudecode.svg\",\n create: () => new ClaudeCodeAgent(),\n});\n\nregisterAgent({\n name: \"opencode\",\n displayName: \"OpenCode\",\n icon: \"/icon/agent/opencode.svg\",\n create: () => new OpenCodeAgent(),\n});\n\nregisterAgent({\n name: \"kimi\",\n displayName: \"Kimi-Cli\",\n icon: \"/icon/agent/kimi.svg\",\n create: () => new KimiAgent(),\n});\n\nregisterAgent({\n name: \"codex\",\n displayName: \"Codex\",\n icon: \"/icon/agent/codex.svg\",\n create: () => new CodexAgent(),\n});\n\nregisterAgent({\n name: \"cursor\",\n displayName: \"Cursor\",\n icon: \"/icon/agent/cursor.svg\",\n create: () => new CursorAgent(),\n});\n","import { resolve, sep } from \"node:path\";\nimport type { SessionHead } from \"../types/index.js\";\nimport type { BaseAgent, SessionCacheMeta } from \"../agents/index.js\";\nimport { createRegisteredAgents } from \"../agents/index.js\";\nimport { perf } from \"../utils/index.js\";\nimport { loadCachedSessions, saveCachedSessions } from \"./cache.js\";\n\nexport interface ScanOptions {\n /** Filter to specific agent name(s) */\n agents?: string[];\n /** Filter to sessions from a specific project directory (substring match) */\n cwd?: string;\n /** Only include sessions created after this timestamp (ms) */\n from?: number;\n /** Only include sessions created before this timestamp (ms) */\n to?: number;\n /** Use cached scan results if available */\n useCache?: boolean;\n /** Enable smart refresh (fast cache + background incremental scan) */\n smartRefresh?: boolean;\n}\n\nexport interface ScanResult {\n sessions: SessionHead[];\n byAgent: Record<string, SessionHead[]>;\n agents: BaseAgent[];\n}\n\n/** 扫描状态更新回调 */\nexport interface ScanProgress {\n agent: string;\n phase: \"cache\" | \"checking\" | \"incremental\" | \"complete\";\n cachedCount?: number;\n newCount?: number;\n changedCount?: number;\n}\n\n/**\n * Bidirectional path scope match (mirrors agent-dump's is_path_scope_match).\n * Matches when:\n * - paths are equal\n * - queryPath is a parent of sessionPath (session is inside the queried project)\n * - sessionPath is a parent of queryPath (session root contains the queried path)\n */\nfunction isPathScopeMatch(queryPath: string, sessionPath: string): boolean {\n if (!sessionPath) return false;\n const q = resolve(queryPath);\n const s = resolve(sessionPath);\n const sepNorm = (p: string) => p.replaceAll(sep, \"/\");\n const sn = sepNorm(s);\n const qn = sepNorm(q);\n return sn === qn || sn.startsWith(qn + \"/\") || qn.startsWith(sn + \"/\");\n}\n\nexport function filterSessions(sessions: SessionHead[], options: ScanOptions): SessionHead[] {\n let result = sessions;\n\n if (options.cwd) {\n const cwd = options.cwd;\n result = result.filter((s) => isPathScopeMatch(cwd, s.directory));\n }\n\n if (options.from != null) {\n result = result.filter((s) => s.time_created >= options.from!);\n }\n\n if (options.to != null) {\n result = result.filter((s) => s.time_created <= options.to!);\n }\n\n return result;\n}\n\ninterface AgentScanResult {\n agent: BaseAgent;\n heads: SessionHead[];\n fromCache?: boolean;\n refreshed?: boolean;\n}\n\n/**\n * 智能扫描单个 Agent\n * 1. 优先使用缓存立即返回\n * 2. 后台检测变更\n * 3. 增量刷新(仅更新变更的部分)\n */\nasync function scanAgentSmart(\n agent: BaseAgent,\n options: ScanOptions,\n onProgress?: (progress: ScanProgress) => void,\n): Promise<AgentScanResult | null> {\n const useCache = options.useCache ?? true;\n const smartRefresh = options.smartRefresh ?? true;\n\n // 1. 尝试加载缓存\n if (useCache) {\n const cached = loadCachedSessions(agent.name);\n if (cached !== null) {\n // 恢复元数据\n if (agent.setSessionMetaMap) {\n const metaMap = new Map<string, SessionCacheMeta>();\n for (const [id, meta] of Object.entries(cached.meta)) {\n metaMap.set(id, meta);\n }\n agent.setSessionMetaMap(metaMap);\n }\n\n // 通知缓存已加载\n onProgress?.({\n agent: agent.name,\n phase: \"cache\",\n cachedCount: cached.sessions.length,\n });\n\n // 2. 智能刷新:后台检测变更\n if (smartRefresh && agent.checkForChanges) {\n setTimeout(async () => {\n await refreshAgentAsync(agent, cached.sessions, cached.timestamp, onProgress);\n }, 0);\n }\n\n const filtered = filterSessions(cached.sessions, options);\n return { agent, heads: filtered, fromCache: true };\n }\n }\n\n // 无缓存或缓存失效,执行完整扫描\n return scanAgentFull(agent, options, onProgress);\n}\n\n/**\n * 后台异步刷新 Agent 数据\n */\nasync function refreshAgentAsync(\n agent: BaseAgent,\n cachedSessions: SessionHead[],\n cacheTimestamp: number,\n onProgress?: (progress: ScanProgress) => void,\n): Promise<void> {\n try {\n // 检测变更\n onProgress?.({ agent: agent.name, phase: \"checking\" });\n\n const checkResult = await Promise.resolve(\n agent.checkForChanges!(cacheTimestamp, cachedSessions),\n );\n\n if (!checkResult.hasChanges) {\n onProgress?.({ agent: agent.name, phase: \"complete\" });\n return;\n }\n\n // 增量刷新\n onProgress?.({\n agent: agent.name,\n phase: \"incremental\",\n changedCount: checkResult.changedIds?.length,\n });\n\n const updatedSessions = await Promise.resolve(\n agent.incrementalScan!(cachedSessions, checkResult.changedIds || []),\n );\n\n // 保存更新后的缓存\n const metaMap = agent.getSessionMetaMap?.();\n const meta: Record<string, SessionCacheMeta> = {};\n if (metaMap) {\n for (const [id, data] of metaMap.entries()) {\n meta[id] = { id, ...(data as Record<string, unknown>) } as SessionCacheMeta;\n }\n }\n saveCachedSessions(agent.name, updatedSessions, meta);\n\n onProgress?.({\n agent: agent.name,\n phase: \"complete\",\n newCount: updatedSessions.length,\n });\n } catch (err) {\n // 刷新失败不中断主流程\n console.error(`[${agent.name}] Background refresh failed:`, err);\n }\n}\n\n/**\n * 完整扫描 Agent(无缓存时使用)\n */\nasync function scanAgentFull(\n agent: BaseAgent,\n options: ScanOptions,\n onProgress?: (progress: ScanProgress) => void,\n): Promise<AgentScanResult | null> {\n const availMarker = perf.start(`agent:${agent.name}:isAvailable`);\n const isAvail = agent.isAvailable();\n perf.end(availMarker);\n\n if (!isAvail) {\n return null;\n }\n\n try {\n const scanMarker = perf.start(`agent:${agent.name}:scan`);\n const heads = agent.scan();\n perf.end(scanMarker);\n\n // 收集元数据\n const metaMap = agent.getSessionMetaMap?.();\n const meta: Record<string, SessionCacheMeta> = {};\n if (metaMap) {\n for (const [id, data] of metaMap.entries()) {\n meta[id] = { id, ...(data as Record<string, unknown>) } as SessionCacheMeta;\n }\n }\n\n // 保存到缓存\n saveCachedSessions(agent.name, heads, meta);\n\n onProgress?.({ agent: agent.name, phase: \"complete\", newCount: heads.length });\n\n const filtered = filterSessions(heads, options);\n return { agent, heads: filtered, fromCache: false };\n } catch (err) {\n console.error(`Error scanning ${agent.name}:`, err);\n return { agent, heads: [], fromCache: false };\n }\n}\n\n/**\n * 主扫描函数 - 并行扫描所有 Agent\n */\nexport async function scanSessions(\n options: ScanOptions = {},\n onProgress?: (progress: ScanProgress) => void,\n): Promise<ScanResult> {\n const scanMarker = perf.start(\"scanSessions\");\n const agents = createRegisteredAgents();\n const byAgent: Record<string, SessionHead[]> = {};\n const allSessions: SessionHead[] = [];\n const availableAgents: BaseAgent[] = [];\n\n const agentFilter = options.agents?.length\n ? new Set(options.agents.map((a) => a.toLowerCase()))\n : null;\n\n // 过滤需要扫描的 Agent\n const agentsToScan = agents.filter((agent) => {\n if (agentFilter && !agentFilter.has(agent.name.toLowerCase())) {\n return false;\n }\n return true;\n });\n\n // 并行扫描所有 Agent\n const scanPromises = agentsToScan.map((agent) => scanAgentSmart(agent, options, onProgress));\n\n const results = await Promise.all(scanPromises);\n\n // 处理结果\n for (const result of results) {\n if (result) {\n availableAgents.push(result.agent);\n byAgent[result.agent.name] = result.heads;\n allSessions.push(...result.heads);\n }\n }\n\n perf.end(scanMarker);\n return { sessions: allSessions, byAgent, agents: availableAgents };\n}\n\n/**\n * 异步扫描(带增量更新支持)\n */\nexport async function scanSessionsAsync(\n options: ScanOptions = {},\n onProgress?: (progress: ScanProgress) => void,\n): Promise<ScanResult> {\n return scanSessions(options, onProgress);\n}\n","/**\n * 扫描结果缓存 - 将扫描结果持久化到磁盘,加速后续启动\n */\n\nimport { existsSync, readFileSync, writeFileSync, mkdirSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport type { SessionHead } from \"../types/index.js\";\n\nconst CACHE_VERSION = 2; // Bumped version for metadata support\nconst CACHE_FILENAME = \"scan-cache.json\";\n\n// Session metadata needed for getSessionData\nexport interface SessionCacheMeta {\n id: string;\n sourcePath: string;\n // Additional fields per agent type\n [key: string]: unknown;\n}\n\ninterface CacheEntry {\n sessions: SessionHead[];\n meta: Record<string, SessionCacheMeta>; // keyed by session id\n timestamp: number;\n version: number;\n}\n\ninterface CacheData {\n version: number;\n entries: Record<string, CacheEntry>; // keyed by agent name\n lastScanTime: number;\n}\n\nfunction getCachePath(): string {\n return join(homedir(), \".cache\", \"codesesh\", CACHE_FILENAME);\n}\n\nfunction ensureCacheDir(): void {\n const cacheDir = join(homedir(), \".cache\", \"codesesh\");\n if (!existsSync(cacheDir)) {\n mkdirSync(cacheDir, { recursive: true });\n }\n}\n\nexport interface CachedResult {\n sessions: SessionHead[];\n meta: Record<string, SessionCacheMeta>;\n timestamp: number;\n}\n\nexport function loadCachedSessions(agentName: string): CachedResult | null {\n try {\n const cachePath = getCachePath();\n if (!existsSync(cachePath)) return null;\n\n const data = JSON.parse(readFileSync(cachePath, \"utf-8\")) as CacheData;\n\n // Version check\n if (data.version !== CACHE_VERSION) return null;\n\n const entry = data.entries[agentName];\n if (!entry) return null;\n\n // Check if cache is too old (7 days)\n const CACHE_TTL = 7 * 24 * 60 * 60 * 1000;\n if (Date.now() - entry.timestamp > CACHE_TTL) return null;\n\n return { sessions: entry.sessions, meta: entry.meta || {}, timestamp: entry.timestamp };\n } catch {\n return null;\n }\n}\n\nexport function saveCachedSessions(\n agentName: string,\n sessions: SessionHead[],\n meta: Record<string, SessionCacheMeta> = {},\n): void {\n try {\n ensureCacheDir();\n const cachePath = getCachePath();\n\n let data: CacheData;\n if (existsSync(cachePath)) {\n try {\n data = JSON.parse(readFileSync(cachePath, \"utf-8\")) as CacheData;\n if (data.version !== CACHE_VERSION) {\n data = { version: CACHE_VERSION, entries: {}, lastScanTime: 0 };\n }\n } catch {\n data = { version: CACHE_VERSION, entries: {}, lastScanTime: 0 };\n }\n } else {\n data = { version: CACHE_VERSION, entries: {}, lastScanTime: 0 };\n }\n\n data.entries[agentName] = {\n sessions,\n meta,\n timestamp: Date.now(),\n version: CACHE_VERSION,\n };\n data.lastScanTime = Date.now();\n\n writeFileSync(cachePath, JSON.stringify(data, null, 2), \"utf-8\");\n } catch {\n // Ignore cache write errors\n }\n}\n\nexport function clearCache(): void {\n try {\n const cachePath = getCachePath();\n if (existsSync(cachePath)) {\n const data: CacheData = {\n version: CACHE_VERSION,\n entries: {},\n lastScanTime: 0,\n };\n writeFileSync(cachePath, JSON.stringify(data, null, 2), \"utf-8\");\n }\n } catch {\n // Ignore errors\n }\n}\n\nexport function getCacheInfo(): { lastScanTime: number | null; size: number } {\n try {\n const cachePath = getCachePath();\n if (!existsSync(cachePath)) {\n return { lastScanTime: null, size: 0 };\n }\n\n const data = JSON.parse(readFileSync(cachePath, \"utf-8\")) as CacheData;\n const size = Object.values(data.entries).reduce((sum, entry) => sum + entry.sessions.length, 0);\n\n return {\n lastScanTime: data.lastScanTime || null,\n size,\n };\n } catch {\n return { lastScanTime: null, size: 0 };\n }\n}\n"],"mappings":";;;ACAA,SAAS,cAAAA,aAAY,aAAa,gBAAAC,eAAc,gBAAgB;AAChE,SAAS,QAAAC,OAAM,YAAAC,iBAAgB;AED/B,SAAS,kBAAkB;AAC3B,SAAS,SAAS,gBAAgB;AAClC,SAAS,YAAY;ACFrB,SAAS,oBAAoB;ACA7B,SAAS,gBAAgB;AEAzB,SAAS,cAAAH,aAAY,YAAAI,iBAAgB;AACrC,SAAS,QAAAF,aAAY;ACGrB,SAAS,qBAAqB;ACJ9B,SAAS,kBAAkB;AAC3B,SAAS,cAAAF,aAAY,gBAAAC,eAAc,eAAAI,cAAa,YAAAD,iBAAgB;AAChE,SAAS,QAAAF,OAAM,YAAAC,WAAU,eAAe;ACFxC,SAAS,cAAAH,aAAY,gBAAAC,eAAc,eAAAI,cAAa,YAAAD,iBAAgB;AAChE,SAAS,QAAAF,OAAM,YAAAC,iBAAgB;ACD/B,SAAS,cAAAH,aAAY,eAAAK,cAAa,gBAAAJ,eAAc,YAAAG,iBAAgB;AAChE,SAAS,QAAAF,OAAM,iBAAiB;AEDhC,SAAS,SAAS,WAAW;ACI7B,SAAS,cAAAF,aAAY,gBAAAC,eAAc,eAAe,iBAAiB;AACnE,SAAS,QAAAC,aAAY;AACrB,SAAS,WAAAI,gBAAe;AdIxB,IAAI,gBAAqC,CAAC;AAEnC,SAAS,cAAc,KAA8B;AAC1D,gBAAc,KAAK,GAAG;AACxB;AAEO,SAAS,yBAAsC;AACpD,SAAO,cAAc,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC;AAC5C;AAEO,SAAS,sBAAoD;AAClE,SAAO;AACT;AAEO,SAAS,gBAAgB,iBAAsD;AACpF,SAAO,cAAc,IAAI,CAAC,OAAO;IAC/B,MAAM,EAAE;IACR,aAAa,EAAE;IACf,MAAM,EAAE;IACR,OAAO,gBAAgB,EAAE,IAAI,KAAK;EACpC,EAAE;AACJ;AAEO,SAAS,eAAe,MAA6C;AAC1E,SAAO,cAAc,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI;AAClD;AEjBO,IAAe,YAAf,MAAyB;EAa9B,OAAO,WAA2B;AAChC,WAAO,GAAG,KAAK,IAAI,MAAM,SAAS;EACpC;AAmCF;AChEA,SAAS,QAAQ,MAA6B;AAC5C,QAAM,QAAQ,QAAQ,IAAI,IAAI;AAC9B,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO;AACT;AAEA,SAAS,iBAAiB,OAAgC;AACxD,aAAW,KAAK,OAAO;AACrB,QAAI,WAAW,CAAC,EAAG,QAAO;EAC5B;AACA,SAAO;AACT;AAEA,SAAS,cAAsB;AAC7B,QAAM,MAAM,QAAQ,eAAe;AACnC,MAAI,IAAK,QAAO;AAEhB,QAAM,IAAI,SAAS;AACnB,MAAI,MAAM,SAAS;AACjB,WAAO,QAAQ,cAAc,KAAK,QAAQ,SAAS,KAAK,KAAK,QAAQ,GAAG,WAAW,OAAO;EAC5F;AAGA,SAAO,KAAK,QAAQ,GAAG,UAAU,OAAO;AAC1C;AASO,SAAS,uBAAsC;AACpD,QAAM,OAAO,QAAQ;AACrB,SAAO;IACL,WAAW,QAAQ,YAAY,KAAK,KAAK,MAAM,QAAQ;IACvD,YAAY,QAAQ,mBAAmB,KAAK,KAAK,MAAM,SAAS;IAChE,UAAU,QAAQ,gBAAgB,KAAK,KAAK,MAAM,OAAO;IACzD,cAAc,KAAK,YAAY,GAAG,UAAU;EAC9C;AACF;AAEO,SAAS,oBAAmC;AACjD,QAAM,WAAW,QAAQ,kBAAkB;AAC3C,MAAI,SAAU,QAAO;AAErB,QAAM,IAAI,SAAS;AACnB,MAAI,MAAM,UAAU;AAClB,WAAO,cAAc,KAAK,QAAQ,GAAG,WAAW,uBAAuB,UAAU,MAAM,CAAC;EAC1F;AACA,MAAI,MAAM,SAAS;AACjB,UAAM,MAAM,QAAQ,iBAAiB,KAAK,KAAK,QAAQ,GAAG,SAAS;AACnE,WAAO,cAAc,KAAK,KAAK,UAAU,MAAM,CAAC;EAClD;AACA,MAAI,MAAM,SAAS;AACjB,UAAM,UAAU,QAAQ,SAAS,KAAK,KAAK,QAAQ,GAAG,WAAW,SAAS;AAC1E,WAAO,cAAc,KAAK,SAAS,UAAU,MAAM,CAAC;EACtD;AACA,SAAO;AACT;AC9DO,UAAU,gBAAgB,SAAqD;AACpF,aAAW,QAAQ,QAAQ,MAAM,IAAI,GAAG;AACtC,UAAM,UAAU,KAAK,KAAK;AAC1B,QAAI,CAAC,QAAS;AACd,QAAI;AACF,YAAM,KAAK,MAAM,OAAO;IAC1B,QAAQ;IAER;EACF;AACF;AAEO,SAAS,cAAc,UAAsD;AAClF,QAAM,UAAU,aAAa,UAAU,OAAO;AAC9C,SAAO,gBAAgB,OAAO;AAChC;ACfA,IAAM,mBAAmB;AACzB,IAAM,mBAAmB;AAGlB,SAAS,mBAAmB,MAA6B;AAC9D,QAAM,UAAU,KAAK,QAAQ,QAAQ,GAAG,EAAE,KAAK;AAC/C,MAAI,CAAC,QAAS,QAAO;AACrB,SAAO,QAAQ,MAAM,GAAG,gBAAgB;AAC1C;AAGO,SAAS,cAAc,MAAgD;AAC5E,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,aAAa,KAAK,KAAK,EAAE,QAAQ,WAAW,EAAE;AACpD,MAAI,CAAC,WAAY,QAAO;AACxB,QAAM,OAAO,SAAS,UAAU,EAAE,KAAK;AACvC,SAAO,QAAQ;AACjB;AAGO,SAAS,oBACd,UACA,SACA,WACQ;AACR,aAAW,aAAa,CAAC,UAAU,SAAS,SAAS,GAAG;AACtD,QAAI,WAAW;AACb,YAAM,aAAa,mBAAmB,SAAS;AAC/C,UAAI,WAAY,QAAO;IACzB;EACF;AACA,SAAO;AACT;ACrBA,IAAM,aAAN,MAAiB;EACP,cAA4B,CAAC;EAC7B,cAA4B,CAAC;EAC7B,UAAU;EAElB,SAAS;AACP,SAAK,UAAU;EACjB;EAEA,MAAM,MAA0B;AAC9B,UAAM,SAAqB;MACzB;MACA,WAAW,YAAY,IAAI;MAC3B,UAAU,CAAC;IACb;AAEA,QAAI,CAAC,KAAK,QAAS,QAAO;AAE1B,UAAM,SAAS,KAAK,YAAY,KAAK,YAAY,SAAS,CAAC;AAC3D,QAAI,QAAQ;AACV,aAAO,SAAS;AAChB,aAAO,SAAS,KAAK,MAAM;IAC7B,OAAO;AACL,WAAK,YAAY,KAAK,MAAM;IAC9B;AAEA,SAAK,YAAY,KAAK,MAAM;AAC5B,WAAO;EACT;EAEA,IAAI,QAA2B;AAC7B,QAAI,CAAC,KAAK,QAAS;AAEnB,UAAM,SAAS,UAAU,KAAK,YAAY,KAAK,YAAY,SAAS,CAAC;AACrE,QAAI,CAAC,OAAQ;AAEb,WAAO,UAAU,YAAY,IAAI;AACjC,WAAO,WAAW,OAAO,UAAU,OAAO;AAG1C,WAAO,KAAK,YAAY,SAAS,GAAG;AAClC,YAAM,SAAS,KAAK,YAAY,IAAI;AACpC,UAAI,WAAW,OAAQ;IACzB;EACF;EAEA,QAAW,MAAc,IAAgB;AACvC,UAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,QAAI;AACF,aAAO,GAAG;IACZ,UAAA;AACE,WAAK,IAAI,MAAM;IACjB;EACF;EAEA,MAAM,aAAgB,MAAc,IAAkC;AACpE,UAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,QAAI;AACF,aAAO,MAAM,GAAG;IAClB,UAAA;AACE,WAAK,IAAI,MAAM;IACjB;EACF;EAEA,YAAoB;AAClB,QAAI,CAAC,KAAK,QAAS,QAAO;AAE1B,UAAM,QAAkB,CAAC;AACzB,UAAM,KAAK,gCAAgC;AAE3C,eAAW,UAAU,KAAK,aAAa;AACrC,WAAK,aAAa,QAAQ,GAAG,KAAK;IACpC;AAEA,WAAO,MAAM,KAAK,IAAI;EACxB;EAEQ,aAAa,QAAoB,OAAe,OAAuB;AAC7E,UAAM,SAAS,KAAK,OAAO,KAAK;AAChC,UAAM,WAAW,OAAO,UAAU,QAAQ,CAAC,KAAK;AAChD,UAAM,KAAK,GAAG,MAAM,GAAG,OAAO,IAAI,KAAK,QAAQ,IAAI;AAEnD,eAAW,SAAS,OAAO,UAAU;AACnC,WAAK,aAAa,OAAO,QAAQ,GAAG,KAAK;IAC3C;EACF;EAEA,QAAc;AACZ,SAAK,cAAc,CAAC;AACpB,SAAK,cAAc,CAAC;EACtB;AACF;AAEO,IAAM,OAAO,IAAI,WAAW;ALrFnC,SAAS,iBAAiB,MAAuC;AAC/D,QAAM,MAAM,OAAO,KAAK,WAAW,KAAK,EAAE,EAAE,KAAK;AACjD,MAAI,CAAC,IAAK,QAAO;AACjB,MAAI;AACF,WAAO,IAAI,KAAK,IAAI,SAAS,GAAG,IAAI,MAAM,MAAM,GAAG,EAAE,QAAQ;EAC/D,QAAQ;AACN,WAAO;EACT;AACF;AAEA,SAASC,oBAAmB,MAAsB;AAEhD,QAAM,OAAO,KAAK,MAAM,IAAI,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC;AAClD,SAAO,MAAM,KAAK,EAAE,MAAM,GAAG,EAAE,KAAK;AACtC;AAEO,IAAM,kBAAN,cAA8B,UAAU;EACpC,OAAO;EACP,cAAc;EAEf,WAA0B;;EAE1B,qBAA0C,CAAC;EAC3C,iBAAiB,oBAAI,IAAyB;EAE9C,eAA8B;AACpC,UAAM,QAAQ,qBAAqB;AACnC,WAAO,cAAcL,MAAK,MAAM,YAAY,UAAU,GAAG,iBAAiB;EAC5E;EAEA,cAAuB;AACrB,SAAK,WAAW,KAAK,aAAa;AAClC,QAAI,CAAC,KAAK,SAAU,QAAO;AAC3B,QAAI;AACF,iBAAW,SAAS,YAAY,KAAK,QAAQ,GAAG;AAC9C,cAAM,MAAMA,MAAK,KAAK,UAAU,KAAK;AACrC,YAAIF,YAAW,GAAG,KAAK,YAAY,GAAG,EAAE,KAAK,CAAC,MAAM,EAAE,SAAS,QAAQ,CAAC,GAAG;AACzE,iBAAO;QACT;MACF;IACF,QAAQ;IAER;AACA,WAAO;EACT;EAEA,OAAsB;AACpB,QAAI,CAAC,KAAK,SAAU,QAAO,CAAC;AAE5B,UAAM,aAAa,KAAK,MAAM,iBAAiB;AAC/C,UAAM,QAAuB,CAAC;AAE9B,UAAM,aAAa,KAAK,MAAM,iBAAiB;AAC/C,UAAM,cAAc,KAAK,gBAAgB;AACzC,SAAK,IAAI,UAAU;AAEnB,eAAW,cAAc,aAAa;AACpC,YAAM,aAAa,KAAK,MAAM,kBAAkBG,UAAS,UAAU,CAAC,EAAE;AACtE,YAAM,QAAQ,KAAK,eAAe,UAAU;AAC5C,WAAK,IAAI,UAAU;AAEnB,iBAAW,QAAQ,OAAO;AACxB,YAAI;AACF,gBAAM,cAAc,KAAK,MAAM,oBAAoBA,UAAS,IAAI,CAAC,EAAE;AACnE,gBAAM,OAAO,KAAK,iBAAiB,MAAM,UAAU;AACnD,eAAK,IAAI,WAAW;AAEpB,cAAI,MAAM;AACR,kBAAM,KAAK,IAAI;AACf,iBAAK,eAAe,IAAI,KAAK,IAAI;cAC/B,IAAI,KAAK;cACT,OAAO,KAAK;cACZ,YAAY;cACZ,WAAW,KAAK;cAChB,OAAO,KAAK,MAAM,eAAe,YAAY;cAC7C,cAAc,KAAK,MAAM;cACzB,WAAW,KAAK;cAChB,WAAW,KAAK,gBAAgB,KAAK;YACvC,CAAC;UACH;QACF,QAAQ;QAER;MACF;IACF;AAEA,SAAK,IAAI,UAAU;AACnB,WAAO;EACT;EAEA,oBAAmD;AACjD,WAAO,KAAK;EACd;EAEA,kBAAkB,MAA2C;AAC3D,SAAK,iBAAiB;EACxB;EAEA,eAAe,WAAgC;AAC7C,UAAM,OAAO,KAAK,eAAe,IAAI,SAAS;AAC9C,QAAI,CAAC,MAAM;AACT,YAAM,IAAI,MAAM,sBAAsB,SAAS,EAAE;IACnD;AACA,QAAI,CAACH,YAAW,KAAK,UAAU,GAAG;AAChC,YAAM,IAAI,MAAM,yBAAyB,KAAK,UAAU,EAAE;IAC5D;AAEA,UAAM,UAAUC,cAAa,KAAK,YAAY,OAAO;AACrD,UAAM,WAAsB,CAAC;AAC7B,UAAM,mBAAmB,oBAAI,IAA8B;AAC3D,UAAM,qBAAqB,oBAAI,IAAY;AAC3C,UAAM,2BAA2B,oBAAI,IAAsB;AAC3D,UAAM,iBAAiB;MACrB,cAAc;MACd,iBAAiB;IACnB;AAEA,QAAI,YAAY;AAChB,QAAI,mBAAmB;AACvB,QAAI,oBAAoB;AAExB,eAAW,UAAU,gBAAgB,OAAO,GAAG;AAC7C,UAAI;AACF,aAAK;UACH;UACA;UACA;UACA;UACA;UACA;QACF;MACF,QAAQ;MAER;IACF;AAGA,eAAW,OAAO,UAAU;AAC1B,mBAAa,IAAI,QAAQ;AACzB,0BAAoB,IAAI,QAAQ,SAAS;AACzC,2BAAqB,IAAI,QAAQ,UAAU;IAC7C;AAEA,WAAO;MACL,IAAI,KAAK;MACT,OAAO,KAAK;MACZ,MAAM,cAAc,KAAK,EAAE;MAC3B,WAAW,KAAK;MAChB,SAAS;MACT,cAAc,KAAK;MACnB,cAAc,KAAK;MACnB,OAAO;QACL,eAAe,SAAS;QACxB,oBAAoB;QACpB,qBAAqB;QACrB,YAAY;MACd;MACA;IACF;EACF;;;;;EAMA,gBAAgB,gBAAwB,gBAAkD;AACxF,QAAI,CAAC,KAAK,UAAU;AAClB,aAAO,EAAE,YAAY,OAAO,WAAW,KAAK,IAAI,EAAE;IACpD;AAEA,UAAM,aAAuB,CAAC;AAE9B,eAAW,WAAW,gBAAgB;AACpC,YAAM,OAAO,KAAK,eAAe,IAAI,QAAQ,EAAE;AAC/C,UAAI,CAAC,KAAM;AAEX,UAAI;AACF,cAAM,OAAO,SAAS,KAAK,UAAU;AAErC,YAAI,KAAK,UAAU,gBAAgB;AACjC,qBAAW,KAAK,QAAQ,EAAE;QAC5B;MACF,QAAQ;AAEN,mBAAW,KAAK,QAAQ,EAAE;MAC5B;IACF;AAGA,QAAI;AACF,UAAI,aAAa;AACjB,iBAAW,OAAO,KAAK,gBAAgB,GAAG;AACxC,sBAAc,KAAK,eAAe,GAAG,EAAE;MACzC;AACA,YAAM,cAAc,aAAa,eAAe;AAEhD,aAAO;QACL,YAAY,WAAW,SAAS,KAAK;QACrC;QACA,WAAW,KAAK,IAAI;MACtB;IACF,QAAQ;AACN,aAAO;QACL,YAAY,WAAW,SAAS;QAChC;QACA,WAAW,KAAK,IAAI;MACtB;IACF;EACF;;;;EAKA,gBAAgB,gBAA+B,YAAqC;AAClF,QAAI,CAAC,KAAK,SAAU,QAAO;AAG3B,UAAM,aAAa,IAAI,IAAI,eAAe,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AAG/D,eAAW,cAAc,KAAK,gBAAgB,GAAG;AAC/C,iBAAW,QAAQ,KAAK,eAAe,UAAU,GAAG;AAClD,YAAI;AACF,gBAAM,YAAYE,UAAS,MAAM,QAAQ;AAGzC,cAAI,WAAW,SAAS,SAAS,GAAG;AAClC,kBAAM,OAAO,KAAK,iBAAiB,MAAM,UAAU;AACnD,gBAAI,MAAM;AACR,yBAAW,IAAI,KAAK,IAAI,IAAI;AAC5B,mBAAK,eAAe,IAAI,KAAK,IAAI;gBAC/B,IAAI,KAAK;gBACT,OAAO,KAAK;gBACZ,YAAY;gBACZ,WAAW,KAAK;gBAChB,OAAO,KAAK,MAAM,eAAe,YAAY;gBAC7C,cAAc,KAAK,MAAM;gBACzB,WAAW,KAAK;gBAChB,WAAW,KAAK,gBAAgB,KAAK;cACvC,CAAC;YACH;UACF;QACF,QAAQ;QAER;MACF;IACF;AAGA,eAAW,cAAc,KAAK,gBAAgB,GAAG;AAC/C,iBAAW,QAAQ,KAAK,eAAe,UAAU,GAAG;AAClD,YAAI;AACF,gBAAM,YAAYA,UAAS,MAAM,QAAQ;AACzC,cAAI,CAAC,WAAW,IAAI,SAAS,GAAG;AAC9B,kBAAM,OAAO,KAAK,iBAAiB,MAAM,UAAU;AACnD,gBAAI,MAAM;AACR,yBAAW,IAAI,KAAK,IAAI,IAAI;AAC5B,mBAAK,eAAe,IAAI,KAAK,IAAI;gBAC/B,IAAI,KAAK;gBACT,OAAO,KAAK;gBACZ,YAAY;gBACZ,WAAW,KAAK;gBAChB,OAAO,KAAK,MAAM,eAAe,YAAY;gBAC7C,cAAc,KAAK,MAAM;gBACzB,WAAW,KAAK;gBAChB,WAAW,KAAK,gBAAgB,KAAK;cACvC,CAAC;YACH;UACF;QACF,QAAQ;QAER;MACF;IACF;AAEA,WAAO,MAAM,KAAK,WAAW,OAAO,CAAC;EACvC;;EAIQ,kBAA4B;AAClC,QAAI,CAAC,KAAK,SAAU,QAAO,CAAC;AAC5B,QAAI;AACF,aAAO,YAAY,KAAK,QAAQ,EAC7B,IAAI,CAAC,MAAMD,MAAK,KAAK,UAAW,CAAC,CAAC,EAClC,OAAO,CAAC,MAAMF,YAAW,CAAC,CAAC;IAChC,QAAQ;AACN,aAAO,CAAC;IACV;EACF;EAEQ,eAAe,KAAuB;AAC5C,QAAI;AACF,aAAO,YAAY,GAAG,EACnB,OAAO,CAAC,MAAM,EAAE,SAAS,QAAQ,KAAK,MAAM,qBAAqB,EACjE,IAAI,CAAC,MAAME,MAAK,KAAK,CAAC,CAAC;IAC5B,QAAQ;AACN,aAAO,CAAC;IACV;EACF;EAEQ,kBAAkB,YAA0D;AAClF,UAAM,WAAWC,UAAS,UAAU;AACpC,QAAI,YAAY,KAAK,oBAAoB;AACvC,aAAO,KAAK,mBAAmB,QAAQ;IACzC;AAEA,UAAM,YAAYD,MAAK,YAAY,qBAAqB;AACxD,UAAM,MAAM,oBAAI,IAAqC;AAErD,QAAIF,YAAW,SAAS,GAAG;AACzB,UAAI;AACF,cAAM,OAAO,KAAK,MAAMC,cAAa,WAAW,OAAO,CAAC;AACxD,cAAM,UAAqC,MAAM,WAAW,CAAC;AAC7D,mBAAW,SAAS,SAAS;AAC3B,gBAAM,MAAM,OAAO;AACnB,cAAI,OAAO,QAAQ,UAAU;AAC3B,gBAAI,IAAI,KAAK,KAAK;UACpB;QACF;MACF,QAAQ;MAER;IACF;AAEA,SAAK,mBAAmB,QAAQ,IAAI;AACpC,WAAO;EACT;EAEQ,iBAAiB,UAAkB,YAAwC;AACjF,UAAM,UAAUA,cAAa,UAAU,OAAO;AAC9C,UAAM,QAAQ,QAAQ,MAAM,IAAI,EAAE,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC;AAExD,QAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,UAAM,YAAYE,UAAS,UAAU,QAAQ;AAE7C,QAAI;AACJ,QAAI;AACF,oBAAc,KAAK,MAAM,MAAM,CAAC,CAAE;IACpC,QAAQ;AACN,aAAO;IACT;AAEA,UAAM,YAAY,iBAAiB,WAAW,KAAK,SAAS,QAAQ,EAAE;AAGtE,UAAM,QAAQ,KAAK,kBAAkB,UAAU;AAC/C,UAAM,aAAa,MAAM,IAAI,SAAS;AACtC,UAAM,gBAAgB,YAAY,UAAU,OAAO,WAAW,OAAO,IAAI;AAGzE,QAAI,YAAY;AAChB,QAAI,eAAe;AACnB,QAAI,QAAuB;AAC3B,QAAI,MAAqB;AACzB,QAAI,mBAAmB;AACvB,QAAI,oBAAoB;AAExB,eAAW,QAAQ,OAAO;AACxB,UAAI;AACF,cAAM,OAAO,KAAK,MAAM,IAAI;AAC5B,cAAM,KAAK,iBAAiB,IAAI;AAChC,YAAI,KAAK,UAAW,aAAY;AAGhC,YAAI,CAAC,OAAO,KAAK,KAAK,KAAK,OAAO,KAAK,KAAK,MAAM,UAAU;AAC1D,gBAAM,KAAK,KAAK;QAClB;AAEA,cAAM,MAAM,KAAK,SAAS;AAC1B,YAAI,OAAO,OAAO,QAAQ,UAAU;AAClC,gBAAM,OAAQ,IAAgC,MAAM;AACpD,cAAI,OAAO,SAAS,YAAY,KAAK,KAAK,GAAG;AAC3C;UACF;AACA,cAAI,CAAC,OAAO;AACV,kBAAM,IAAK,IAAgC,OAAO;AAClD,gBAAI,OAAO,MAAM,YAAY,EAAE,KAAK,EAAG,SAAQ,EAAE,KAAK;UACxD;AACA,cAAI,SAAS,aAAa;AACxB,kBAAM,QAAS,IAAgC,OAAO;AAGtD,gBAAI,SAAS,OAAO,UAAU,UAAU;AACtC,mCACI,MAAM,cAAc,KAAgB,MACpC,MAAM,6BAA6B,KAAgB,MACnD,MAAM,yBAAyB,KAAgB;AACnD,mCAAsB,MAAM,eAAe,KAAgB;YAC7D;UACF;QACF;MACF,QAAQ;MAER;IACF;AAEA,UAAM,YAAY,OAAO;AAGzB,UAAM,eAAe,KAAK,aAAa,KAAK;AAC5C,UAAM,iBAAiB,cAAc,SAAS,KAAK,cAAc,UAAU;AAE3E,UAAM,QAAQ,oBAAoB,eAAe,cAAc,cAAc;AAE7E,WAAO;MACL,IAAI;MACJ,MAAM,cAAc,SAAS;MAC7B;MACA;MACA,cAAc;MACd,cAAc;MACd,OAAO;QACL,eAAe;QACf,oBAAoB;QACpB,qBAAqB;QACrB,YAAY;MACd;IACF;EACF;EAEQ,aAAa,OAAgC;AACnD,eAAW,QAAQ,MAAM,MAAM,GAAG,EAAE,GAAG;AACrC,UAAI;AACF,cAAM,OAAO,KAAK,MAAM,IAAI;AAC5B,cAAM,MAAM,KAAK,SAAS;AAC1B,YAAI,CAAC,OAAO,OAAO,QAAQ,SAAU;AACrC,YAAK,IAAgC,MAAM,MAAM,OAAQ;AAEzD,cAAM,UAAW,IAAgC,SAAS;AAC1D,YAAI,CAAC,QAAS;AAEd,YAAI,OAAO,YAAY,UAAU;AAC/B,iBAAOI,oBAAmB,OAAO;QACnC;AACA,YAAI,MAAM,QAAQ,OAAO,GAAG;AAC1B,gBAAM,QAAQ,QACX,OAAO,CAAC,SAAS,OAAO,SAAS,YAAY,SAAS,QAAQ,UAAU,IAAI,EAC5E,IAAI,CAAC,SAAS,OAAQ,KAAiC,MAAM,KAAK,EAAE,CAAC,EACrE,KAAK,GAAG;AACX,iBAAOA,oBAAmB,KAAK;QACjC;MACF,QAAQ;MAER;IACF;AACA,WAAO;EACT;;EAIQ,cACN,MACA,UACA,kBACA,oBACA,0BACA,gBACM;AACN,QAAI,KAAK,QAAQ,MAAM,KAAM;AAE7B,UAAM,UAAU,OAAO,KAAK,MAAM,KAAK,EAAE;AAEzC,QAAI,YAAY,aAAa;AAC3B,WAAK;QACH;QACA;QACA;QACA;QACA;QACA;MACF;IACF,WAAW,YAAY,QAAQ;AAC7B,WAAK;QACH;QACA;QACA;QACA;QACA;QACA;MACF;IACF,WAAW,YAAY,eAAe;AACpC,WAAK,wBAAwB,MAAM,UAAU,cAAc;IAC7D;EACF;EAEQ,uBACN,MACA,UACA,kBACA,oBACA,0BACA,gBACM;AACN,UAAM,MAAO,KAAK,SAAS,KAAK,CAAC;AACjC,UAAM,cAAc,iBAAiB,IAAI;AACzC,UAAM,aAAc,IAAI,SAAS,KAAK,CAAC;AACvC,UAAM,OAAO,OAAO,KAAK,MAAM,KAAK,EAAE;AAEtC,UAAM,cAAwB,CAAC;AAC/B,QAAI,wBAAwB,eAAe;AAC3C,QAAI,2BAA2B,eAAe;AAE9C,QAAI,MAAM,QAAQ,UAAU,GAAG;AAC7B,iBAAW,QAAQ,YAAY;AAC7B,YAAI,CAAC,QAAQ,OAAO,SAAS,SAAU;AACvC,cAAM,OAAO;AACb,cAAM,WAAW,OAAO,KAAK,MAAM,KAAK,EAAE;AAE1C,YAAI,aAAa,YAAY;AAC3B,gBAAM,OAAO,OAAO,KAAK,UAAU,KAAK,EAAE;AAC1C,cAAI,KAAK,KAAK,GAAG;AACf,oCAAwB,KAAK;cAC3B;cACA,EAAE,WAAW,MAAM,KAAK,aAAa,KAAK;cAC1C;YACF;UACF;AACA;QACF;AAEA,YAAI,aAAa,QAAQ;AACvB,gBAAM,OAAO,OAAO,KAAK,MAAM,KAAK,EAAE;AACtC,cAAI,KAAK,KAAK,GAAG;AACf,oCAAwB,KAAK;cAC3B;cACA,EAAE,WAAW,MAAM,KAAK,aAAa,KAAK;cAC1C;YACF;AACA,uCAA2B;UAC7B;AACA;QACF;AAEA,YAAI,aAAa,WAAY;AAE7B,cAAM,WAAW,OAAO,KAAK,MAAM,KAAK,EAAE,EAAE,KAAK;AACjD,cAAM,aAAa,OAAO,KAAK,IAAI,KAAK,EAAE,EAAE,KAAK;AAEjD,YAAI,YAAY,cAAc,KAAK,iBAAiB,QAAQ,GAAG;AAC7D,6BAAmB,IAAI,UAAU;AACjC;QACF;AAEA,cAAM,WAAW,KAAK,cAAc,MAAM,WAAW;AACrD,cAAM,CAAC,UAAU,SAAS,IAAI,KAAK,gCAAgC,UAAU;UAC3E,WAAW;UACX;UACA;UACA;UACA,iBAAiB;QACnB,CAAC;AACD,gCAAwB;AACxB,YAAI,YAAY;AACd,2BAAiB,IAAI,YAAY,CAAC,UAAU,SAAS,CAAC;AACtD,sBAAY,KAAK,UAAU;QAC7B;MACF;IACF;AAEA,QAAI,YAAY,SAAS,GAAG;AAC1B,+BAAyB,IAAI,MAAM,WAAW;IAChD;AAEA,mBAAe,eAAe;AAC9B,mBAAe,kBAAkB;EACnC;EAEQ,kBACN,MACA,UACA,kBACA,oBACA,0BACA,gBACM;AACN,UAAM,MAAO,KAAK,SAAS,KAAK,CAAC;AACjC,UAAM,cAAc,iBAAiB,IAAI;AACzC,UAAM,UAAU,IAAI,SAAS,KAAK;AAClC,UAAM,OAAO,OAAO,KAAK,MAAM,KAAK,EAAE;AAGtC,QAAI,OAAO,YAAY,UAAU;AAC/B,YAAM,QAAQ,KAAK,uBAAuB,SAAS,WAAW;AAC9D,UAAI,MAAM,WAAW,GAAG;AACtB,uBAAe,eAAe;AAC9B,uBAAe,kBAAkB;AACjC;MACF;AACA,eAAS,KAAK,KAAK,aAAa,EAAE,WAAW,MAAM,MAAM,QAAQ,aAAa,MAAM,CAAC,CAAC;AACtF,qBAAe,eAAe;AAC9B,qBAAe,kBAAkB;AACjC;IACF;AAEA,QAAI,CAAC,MAAM,QAAQ,OAAO,GAAG;AAC3B,qBAAe,eAAe;AAC9B,qBAAe,kBAAkB;AACjC;IACF;AAEA,UAAM,eAAe,KAAK,uBAAuB,SAAS,WAAW;AACrE,UAAM,mBAAmB,KAAK,wBAAwB,KAAK,eAAe,CAAC;AAE3E,eAAW,QAAQ,SAAS;AAC1B,UAAI,CAAC,QAAQ,OAAO,SAAS,SAAU;AACvC,YAAM,KAAK;AACX,UAAI,GAAG,MAAM,MAAM,cAAe;AAElC,YAAM,aAAa,KAAK,kBAAkB,MAAM,IAAI,wBAAwB;AAC5E,UAAI,cAAc,mBAAmB,IAAI,UAAU,EAAG;AAEtD,YAAM,cAAc,KAAK,0BAA0B,GAAG,SAAS,GAAG,WAAW;AAC7E,UACE,KAAK;QACH;QACA;QACA;QACA;QACA;MACF,GACA;AACA;MACF;AAEA,YAAM,WAAW,KAAK,yBAAyB;QAC7C,WAAW;QACX;QACA;QACA;MACF,CAAC;AACD,UAAI,SAAU,UAAS,KAAK,QAAQ;IACtC;AAEA,QAAI,aAAa,SAAS,GAAG;AAC3B,eAAS;QACP,KAAK,aAAa,EAAE,WAAW,MAAM,MAAM,QAAQ,aAAa,OAAO,aAAa,CAAC;MACvF;IACF;AAEA,mBAAe,eAAe;AAC9B,mBAAe,kBAAkB;EACnC;EAEQ,wBACN,MACA,UACA,gBACM;AACN,UAAM,cAAc,iBAAiB,IAAI;AACzC,UAAM,MAAO,KAAK,SAAS,KAAK,CAAC;AACjC,UAAM,cAAc,KAAK,0BAA0B,IAAI,SAAS,GAAG,WAAW;AAC9E,UAAM,OAAO,OAAO,KAAK,MAAM,KAAK,EAAE;AAEtC,UAAM,WAAW,KAAK,yBAAyB;MAC7C,WAAW;MACX;MACA,YAAY;MACZ;IACF,CAAC;AACD,QAAI,SAAU,UAAS,KAAK,QAAQ;AAEpC,mBAAe,eAAe;AAC9B,mBAAe,kBAAkB;EACnC;;EAIQ,aAAa,MAWT;AACV,WAAO;MACL,IAAI,KAAK;MACT,MAAM,KAAK;MACX,OAAO,KAAK,SAAS;MACrB,cAAc,KAAK;MACnB,MAAM,KAAK,QAAQ;MACnB,OAAO,KAAK,SAAS;MACrB,UAAU,KAAK,YAAY;MAC3B,QAAQ,KAAK,SAAU,KAAK,SAA+B;MAC3D,MAAM,KAAK,QAAQ;MACnB,OAAO,KAAK;IACd;EACF;EAEQ,cAAc,MAAc,aAAkC;AACpE,WAAO,EAAE,MAAM,QAAQ,MAAM,cAAc,YAAY;EACzD;EAEQ,mBAAmB,MAAc,aAAkC;AACzE,WAAO,EAAE,MAAM,aAAa,MAAM,cAAc,YAAY;EAC9D;EAEQ,cAAc,MAA+B,aAAkC;AACrF,UAAM,WAAW,OAAO,KAAK,MAAM,KAAK,EAAE;AAC1C,WAAO;MACL,MAAM;MACN,MAAM;MACN,QAAQ,OAAO,KAAK,IAAI,KAAK,EAAE;MAC/B,OAAO,SAAS,QAAQ;MACxB,OAAO;QACL,OAAO,KAAK,OAAO,KAAK,CAAC;QACzB,QAAQ;MACV;MACA,cAAc;IAChB;EACF;EAEQ,uBAAuB,SAAkB,KAAoC;AACnF,UAAM,QAAQ,IAAI,OAAO;AACzB,QAAI,SAAS,OAAO,UAAU,YAAY,CAAC,QAAQ,OAAO;AACxD,cAAQ,QAAQ;IAClB;AACA,UAAM,QAAQ,IAAI,OAAO;AACzB,QAAI,SAAS,OAAO,UAAU,YAAY,CAAC,QAAQ,QAAQ;AACzD,YAAM,IAAI;AACV,cAAQ,SAAS;QACf,QACI,EAAE,cAAc,KAAgB,MAChC,EAAE,6BAA6B,KAAgB,MAC/C,EAAE,yBAAyB,KAAgB;QAC/C,QAAS,EAAE,eAAe,KAAgB;MAC5C;IACF;EACF;;EAIQ,yBACN,UACA,MACA,cACQ;AACR,UAAM,OAAO,KAAK,mBAAmB,KAAK,MAAM,KAAK,WAAW;AAEhE,QAAI,iBAAiB,MAAM;AACzB,YAAMC,WAAU,SAAS,YAAY;AACrC,YAAM,UAAUA,SAAQ,MAAM,KAAK,CAAC,MAAM,EAAE,SAAS,MAAM;AAC3D,YAAM,UAAUA,SAAQ,MAAM,KAAK,CAAC,MAAM,EAAE,SAAS,MAAM;AAC3D,UAAI,CAAC,WAAW,CAAC,SAAS;AACxB,aAAK,gBAAgBA,UAAS,IAAI;AAClC,aAAK,uBAAuBA,UAAS,KAAK,GAAG;AAC7C,eAAO;MACT;IACF;AAEA,UAAM,UAAU,KAAK,aAAa;MAChC,WAAW,KAAK;MAChB,MAAM;MACN,aAAa,KAAK;MAClB,OAAO,CAAC,IAAI;MACZ,OAAO;IACT,CAAC;AACD,SAAK,uBAAuB,SAAS,KAAK,GAAG;AAC7C,aAAS,KAAK,OAAO;AACrB,WAAO,SAAS,SAAS;EAC3B;EAEQ,oBACN,UACA,MACA,cACQ;AACR,UAAM,OAAO,KAAK,cAAc,KAAK,MAAM,KAAK,WAAW;AAE3D,QAAI,iBAAiB,MAAM;AACzB,YAAMA,WAAU,SAAS,YAAY;AACrC,YAAM,UAAUA,SAAQ,MAAM,KAAK,CAAC,MAAM,EAAE,SAAS,MAAM;AAC3D,UAAI,CAAC,SAAS;AACZ,aAAK,gBAAgBA,UAAS,IAAI;AAClC,aAAK,uBAAuBA,UAAS,KAAK,GAAG;AAC7C,eAAO;MACT;IACF;AAEA,UAAM,UAAU,KAAK,aAAa;MAChC,WAAW,KAAK;MAChB,MAAM;MACN,aAAa,KAAK;MAClB,OAAO,CAAC,IAAI;MACZ,OAAO;IACT,CAAC;AACD,SAAK,uBAAuB,SAAS,KAAK,GAAG;AAC7C,aAAS,KAAK,OAAO;AACrB,WAAO,SAAS,SAAS;EAC3B;EAEQ,gCACN,UACA,MAOkB;AAClB,QAAI,KAAK,oBAAoB,MAAM;AACjC,YAAMA,WAAU,SAAS,KAAK,eAAe;AAC7CA,eAAQ,MAAM,KAAK,KAAK,QAAQ;AAChC,WAAK,uBAAuBA,UAAS,KAAK,GAAG;AAC7C,aAAO,CAAC,KAAK,iBAAiBA,SAAQ,MAAM,SAAS,CAAC;IACxD;AAEA,UAAM,UAAU,KAAK,aAAa;MAChC,WAAW,KAAK;MAChB,MAAM;MACN,aAAa,KAAK;MAClB,OAAO,CAAC,KAAK,QAAQ;MACrB,OAAO;MACP,MAAM;IACR,CAAC;AACD,SAAK,uBAAuB,SAAS,KAAK,GAAG;AAC7C,aAAS,KAAK,OAAO;AACrB,WAAO,CAAC,SAAS,SAAS,GAAG,CAAC;EAChC;;EAIQ,uBAAuB,SAAkB,aAAoC;AACnF,QAAI,OAAO,YAAY,UAAU;AAC/B,aAAO,QAAQ,KAAK,IAAI,CAAC,KAAK,cAAc,SAAS,WAAW,CAAC,IAAI,CAAC;IACxE;AACA,QAAI,CAAC,MAAM,QAAQ,OAAO,EAAG,QAAO,CAAC;AAErC,UAAM,QAAuB,CAAC;AAC9B,eAAW,QAAQ,SAAS;AAC1B,UAAI,OAAO,SAAS,YAAY,SAAS,MAAM;AAC7C,cAAM,KAAK;AACX,YAAI,GAAG,MAAM,MAAM,cAAe;AAClC,cAAM,OAAO,OAAO,GAAG,MAAM,KAAK,EAAE;AACpC,YAAI,KAAK,KAAK,EAAG,OAAM,KAAK,KAAK,cAAc,MAAM,WAAW,CAAC;MACnE,WAAW,OAAO,SAAS,YAAY,KAAK,KAAK,GAAG;AAClD,cAAM,KAAK,KAAK,cAAc,MAAM,WAAW,CAAC;MAClD;IACF;AACA,WAAO;EACT;EAEQ,0BAA0B,SAAkB,aAAoC;AACtF,QAAI,OAAO,YAAY,UAAU;AAC/B,aAAO,QAAQ,KAAK,IAAI,CAAC,KAAK,cAAc,SAAS,WAAW,CAAC,IAAI,CAAC;IACxE;AACA,QAAI,YAAY,QAAQ,YAAY,OAAW,QAAO,CAAC;AAEvD,QAAI,MAAM,QAAQ,OAAO,GAAG;AAC1B,YAAM,QAAuB,CAAC;AAC9B,iBAAW,QAAQ,SAAS;AAC1B,YAAI,OAAO,SAAS,YAAY,SAAS,MAAM;AAC7C,gBAAMC,QAAO;YACV,KAAiC,MAAM,KACrC,KAAiC,SAAS,KAC3C;UACJ;AACA,cAAIA,MAAK,KAAK,EAAG,OAAM,KAAK,KAAK,cAAcA,OAAM,WAAW,CAAC;QACnE,WAAW,OAAO,SAAS,YAAY,KAAK,KAAK,GAAG;AAClD,gBAAM,KAAK,KAAK,cAAc,MAAM,WAAW,CAAC;QAClD;MACF;AACA,aAAO;IACT;AAEA,UAAM,OAAO,OAAO,OAAO;AAC3B,WAAO,KAAK,KAAK,IAAI,CAAC,KAAK,cAAc,MAAM,WAAW,CAAC,IAAI,CAAC;EAClE;;EAIQ,mBACN,UACA,kBACA,QACA,aACA,cACS;AACT,QAAI,CAAC,OAAQ,QAAO;AAEpB,UAAM,WAAW,iBAAiB,IAAI,MAAM;AAC5C,QAAI,aAAa,OAAW,QAAO;AAEnC,UAAM,CAAC,UAAU,SAAS,IAAI;AAC9B,UAAM,QACJ,SAAS,QAAQ,EAAG,MAAM,SAAS,EAAG,UACrC,SAAS,QAAQ,EAAG,MAAM,SAAS,EAAG,QAAQ,CAAC;AAElD,QAAI,YAAY,SAAS,GAAG;AAC1B,YAAM,WAAW,MAAM;AACvB,UAAI,MAAM,QAAQ,QAAQ,GAAG;AAC3B,iBAAS,KAAK,GAAG,WAAW;MAC9B,WAAW,aAAa,QAAQ,aAAa,QAAW;AACtD,cAAM,SAAS,CAAC,GAAG,WAAW;MAChC,OAAO;AACL,cAAM,SAAS,CAAC,UAAU,GAAG,WAAW;MAC1C;IACF;AAEA,QAAI,cAAc;AAChB,aAAO,OAAO,OAAO,YAAY;IACnC;AAEA,QAAI,YAAY,SAAS,KAAK,CAAC,MAAM,QAAQ;AAC3C,YAAM,SAAS;IACjB;AAEA,WAAO,YAAY,SAAS,KAAK,CAAC,CAAC;EACrC;EAEQ,kBACN,MACA,MACA,0BACQ;AACR,UAAM,WAAW,OAAO,KAAK,aAAa,KAAK,EAAE,EAAE,KAAK;AACxD,QAAI,SAAU,QAAO;AAErB,UAAM,aAAa,OAAO,KAAK,yBAAyB,KAAK,EAAE,EAAE,KAAK;AACtE,QAAI,CAAC,WAAY,QAAO;AAExB,UAAM,MAAM,yBAAyB,IAAI,UAAU;AACnD,QAAI,OAAO,IAAI,WAAW,EAAG,QAAO,IAAI,CAAC;AACzC,WAAO;EACT;EAEQ,wBAAwB,eAAiD;AAC/E,QAAI,CAAC,iBAAiB,OAAO,kBAAkB,SAAU,QAAO,CAAC;AAEjE,UAAM,SAAS;AACf,UAAM,UAAmC,CAAC;AAE1C,UAAM,UAAU,OAAO,SAAS;AAChC,QAAI,OAAO,YAAY,WAAW;AAChC,cAAQ,QAAQ,IAAI,UAAU,YAAY;IAC5C;AAEA,UAAM,cAAc,OAAO,aAAa;AACxC,QAAI,aAAa;AACf,cAAQ,MAAM,IAAI,EAAE,YAAY;IAClC;AAEA,WAAO;EACT;;EAIQ,yBAAyB,MAKd;AACjB,QAAI,KAAK,YAAY,WAAW,EAAG,QAAO;AAC1C,WAAO,KAAK,aAAa;MACvB,WAAW,KAAK;MAChB,MAAM;MACN,aAAa,KAAK;MAClB,OAAO,KAAK;IACd,CAAC;EACH;;EAIQ,iBAAiB,UAA2B;AAClD,WAAO,aAAa;EACtB;EAEQ,gBAAgB,SAAkB,MAAyB;AACjE,UAAM,QAAQ,QAAQ;AACtB,QAAI,MAAM,SAAS,KAAK,MAAM,MAAM,SAAS,CAAC,EAAG,SAAS,KAAK,MAAM;AAEnE,YAAM,OAAO,MAAM,MAAM,SAAS,CAAC;AACnC,UAAI,KAAK,SAAS,KAAK,KAAM;IAC/B;AACA,UAAM,KAAK,IAAI;EACjB;AACF;AOv+BA,IAAI,sBAA0D;AAE9D,IAAI;AACF,QAAMC,WAAU,cAAc,YAAY,GAAG;AAE7C,QAAM,MAAMA,SAAQ,gBAAgB;AACpC,wBACE,OAAO,QAAQ,aACX,MACE,IAA8B;AACxC,QAAQ;AAER;AAmBO,SAAS,eAAe,QAAuC;AACpE,MAAI,CAAC,oBAAqB,QAAO;AACjC,MAAI;AAEF,UAAM,KACJ,oBACA,QAAQ,EAAE,UAAU,KAAK,CAAC;AAC5B,WAAO;EACT,QAAQ;AACN,WAAO;EACT;AACF;AAKO,SAAS,oBAA6B;AAC3C,SAAO,wBAAwB;AACjC;AD/CO,IAAM,gBAAN,cAA4B,UAAU;EAClC,OAAO;EACP,cAAc;EAEf,SAAwB;;EAGxB,iBAAiB,oBAAI,IAAgD;EAErE,aAA4B;AAClC,QAAI,CAAC,kBAAkB,EAAG,QAAO;AACjC,UAAM,QAAQ,qBAAqB;AACnC,WAAO,cAAcR,MAAK,MAAM,cAAc,aAAa,GAAG,2BAA2B;EAC3F;EAEA,cAAuB;AACrB,SAAK,SAAS,KAAK,WAAW;AAC9B,WAAO,KAAK,WAAW;EACzB;EAEA,OAAsB;AACpB,QAAI,CAAC,KAAK,OAAQ,QAAO,CAAC;AAE1B,UAAM,KAAK,eAAe,KAAK,MAAM;AACrC,QAAI,CAAC,GAAI,QAAO,CAAC;AAEjB,QAAI;AACF,YAAM,aAAa,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,KAAK;AAEtD,YAAM,kBAAkB,GACrB,QAAQ,0EAA0E,EAClF,IAAI;AAEP,UAAI;AACJ,UAAI,iBAAiB;AACnB,eAAO,GACJ,QAAQ;;;;;;;;;;;SAWV,EACE,IAAI,UAAU;MACnB,OAAO;AACL,eAAO,GACJ,QAAQ;;;;;;SAMV,EACE,IAAI,UAAU;MACnB;AAEA,YAAM,QAAuB,CAAC;AAC9B,iBAAW,OAAO,MAAM;AACtB,cAAM,KAAK,OAAO,IAAI,MAAM,EAAE;AAC9B,cAAM,QAAQ,OAAO,IAAI,SAAS,EAAE,EAAE,KAAK,KAAK;AAChD,cAAM,cAAc,OAAO,IAAI,gBAAgB,CAAC;AAChD,cAAM,cAAc,OAAO,IAAI,gBAAgB,WAAW;AAC1D,cAAM,OAAO,YAAY,EAAE;AAC3B,cAAM,YAAY,OAAO,IAAI,aAAa,EAAE;AAE5C,cAAM,KAAK;UACT;UACA;UACA;UACA;UACA,cAAc;UACd,cAAc;UACd,OAAO;YACL,eAAe,OAAO,IAAI,iBAAiB,CAAC;YAC5C,oBAAoB;YACpB,qBAAqB;YACrB,YAAY;UACd;QACF,CAAC;AAGD,YAAI,KAAK,QAAQ;AACf,eAAK,eAAe,IAAI,IAAI;YAC1B;YACA,YAAY,KAAK;UACnB,CAAC;QACH;MACF;AAEA,aAAO;IACT,QAAQ;AACN,aAAO,CAAC;IACV,UAAA;AACE,SAAG,MAAM;IACX;EACF;EAEA,oBAAmD;AACjD,WAAO,KAAK;EACd;EAEA,kBAAkB,MAA2C;AAC3D,SAAK,iBAAiB;EACxB;;;;;EAMA,gBAAgB,gBAAwB,gBAAkD;AACxF,QAAI,CAAC,KAAK,QAAQ;AAChB,WAAK,SAAS,KAAK,WAAW;IAChC;AACA,QAAI,CAAC,KAAK,UAAU,CAACF,YAAW,KAAK,MAAM,GAAG;AAC5C,aAAO,EAAE,YAAY,OAAO,WAAW,KAAK,IAAI,EAAE;IACpD;AAEA,QAAI;AAEF,YAAM,OAAOI,UAAS,KAAK,MAAM;AACjC,YAAM,aAAa,KAAK,UAAU;AAGlC,YAAM,aAAa,aAAa,eAAe,IAAI,CAAC,MAAM,EAAE,EAAE,IAAI,CAAC;AAEnE,aAAO;QACL;QACA;QACA,WAAW,KAAK,IAAI;MACtB;IACF,QAAQ;AACN,aAAO,EAAE,YAAY,OAAO,WAAW,KAAK,IAAI,EAAE;IACpD;EACF;;;;EAKA,gBAAgB,iBAAgC,aAAsC;AAEpF,WAAO,KAAK,KAAK;EACnB;EAEA,eAAe,WAAgC;AAE7C,QAAI,CAAC,KAAK,QAAQ;AAChB,WAAK,SAAS,KAAK,WAAW;IAChC;AACA,QAAI,CAAC,KAAK,QAAQ;AAChB,YAAM,IAAI,MAAM,8BAA8B;IAChD;AAEA,UAAM,KAAK,eAAe,KAAK,MAAM;AACrC,QAAI,CAAC,IAAI;AACP,YAAM,IAAI,MAAM,8BAA8B;IAChD;AAEA,QAAI;AAEF,YAAM,aAAa,GAAG,QAAQ,oCAAoC,EAAE,IAAI,SAAS;AAGjF,UAAI,CAAC,YAAY;AACf,cAAM,IAAI,MAAM,sBAAsB,SAAS,EAAE;MACnD;AAEA,YAAM,KAAK,OAAO,WAAW,MAAM,SAAS;AAC5C,YAAM,QAAQ,OAAO,WAAW,SAAS,UAAU;AACnD,YAAM,OAAO,YAAY,EAAE;AAC3B,YAAM,YAAY,OAAO,WAAW,aAAa,EAAE;AACnD,YAAM,cAAc,OAAO,WAAW,gBAAgB,CAAC;AACvD,YAAM,cAAc,OAAO,WAAW,gBAAgB,WAAW;AAEjE,YAAM,WAAsB,CAAC;AAC7B,UAAI,YAAY;AAChB,UAAI,mBAAmB;AACvB,UAAI,oBAAoB;AAGxB,YAAM,UAAU,GACb,QAAQ,sEAAsE,EAC9E,IAAI,SAAS;AAEhB,iBAAW,UAAU,SAAS;AAC5B,cAAM,UAAU,KAAK,MAAM,OAAO,OAAO,QAAQ,IAAI,CAAC;AAEtD,cAAM,QAAuB,CAAC;AAC9B,cAAM,OAAO,OAAO,QAAQ,QAAQ,CAAC;AACrC,cAAM,SAAS,QAAQ;AACvB,cAAM,cAAc,OAAO,QAAQ,SAAS,CAAC;AAC7C,cAAM,eAAe,OAAO,QAAQ,UAAU,CAAC;AAE/C,qBAAa;AACb,4BAAoB;AACpB,6BAAqB;AAGrB,cAAM,WAAW,GACd,QAAQ,mEAAmE,EAC3E,IAAI,OAAO,EAAE;AAEhB,mBAAW,WAAW,UAAU;AAC9B,gBAAM,WAAW,KAAK,MAAM,OAAO,QAAQ,QAAQ,IAAI,CAAC;AACxD,gBAAM,WAAW,OAAO,SAAS,QAAQ,EAAE;AAE3C,cAAI,aAAa,UAAU,aAAa,aAAa;AACnD,kBAAM,KAAK;cACT,MAAM;cACN,MAAM,SAAS,QAAQ;cACvB,cAAc,OAAO,QAAQ,gBAAgB,CAAC;YAChD,CAAC;UACH,WAAW,aAAa,QAAQ;AAC9B,kBAAM,KAAK;cACT,MAAM;cACN,MAAM,OAAO,SAAS,QAAQ,EAAE;cAChC,QAAQ,OAAO,SAAS,UAAU,EAAE;cACpC,OAAO,OAAO,SAAS,SAAS,EAAE;cAClC,OAAQ,SAAS,SAAS,CAAC;cAC3B,cAAc,OAAO,QAAQ,gBAAgB,CAAC;YAChD,CAAC;UACH;QAEF;AAEA,iBAAS,KAAK;UACZ,IAAI,OAAO,OAAO,MAAM,EAAE;UAC1B,MAAM,OAAO,QAAQ,QAAQ,WAAW;UACxC,OAAQ,QAAQ,SAA2B;UAC3C,MAAO,QAAQ,QAA0B;UACzC,OAAQ,QAAQ,WAA6B;UAC7C,UAAW,QAAQ,cAAgC;UACnD,cAAc,OAAO,OAAO,gBAAgB,CAAC;UAC7C,QAAQ,SAAS,EAAE,OAAO,aAAa,QAAQ,aAAa,IAAI;UAChE;UACA;QACF,CAAC;MACH;AAEA,aAAO;QACL;QACA;QACA;QACA;QACA,SAAU,WAAW,WAA6B;QAClD,cAAc;QACd,cAAc;QACd,eAAe,WAAW,iBAAiB;QAC3C,OAAO;UACL,eAAe,SAAS;UACxB,oBAAoB;UACpB,qBAAqB;UACrB,YAAY;QACd;QACA;MACF;IACF,UAAA;AACE,SAAG,MAAM;IACX;EACF;AACF;AEvQA,IAAM,sBAA8C;EAClD,UAAU;EACV,MAAM;EACN,gBAAgB;EAChB,MAAM;EACN,WAAW;EACX,OAAO;AACT;AAEA,IAAM,qBAAqB,oBAAI,IAAI,CAAC,aAAa,CAAC;AAElD,SAAS,aAAa,UAA0B;AAC9C,SAAO,oBAAoB,QAAQ,KAAK;AAC1C;AAoBA,SAAS,uBAAuB,KAAuB;AACrD,MAAI,OAAO,QAAQ,UAAU;AAC3B,QAAI;AACF,aAAO,KAAK,MAAM,GAAG;IACvB,QAAQ;AACN,aAAO;IACT;EACF;AACA,SAAO;AACT;AAEA,SAAS,yBAAyB,SAAkB,aAAoC;AACtF,MAAI,OAAO,YAAY,UAAU;AAC/B,WAAO,QAAQ,KAAK,IAChB,CAAC,EAAE,MAAM,QAAiB,MAAM,SAAS,cAAc,YAAY,CAAC,IACpE,CAAC;EACP;AACA,MAAI,MAAM,QAAQ,OAAO,GAAG;AAC1B,UAAM,QAAuB,CAAC;AAC9B,eAAW,QAAQ,SAAS;AAC1B,UAAI,OAAO,SAAS,YAAY,SAAS,QAAQ,UAAU,MAAM;AAC/D,cAAMK,QAAO,OAAQ,KAAiC,QAAQ,EAAE;AAChE,YAAIA,MAAK,KAAK,EAAG,OAAM,KAAK,EAAE,MAAM,QAAQ,MAAAA,OAAM,cAAc,YAAY,CAAC;MAC/E,WAAW,OAAO,SAAS,YAAY,KAAK,KAAK,GAAG;AAClD,cAAM,KAAK,EAAE,MAAM,QAAQ,MAAM,MAAM,cAAc,YAAY,CAAC;MACpE;IACF;AACA,WAAO;EACT;AACA,MAAI,WAAW,KAAM,QAAO,CAAC;AAC7B,QAAM,OAAO,OAAO,OAAO;AAC3B,SAAO,KAAK,KAAK,IAAI,CAAC,EAAE,MAAM,QAAQ,MAAM,cAAc,YAAY,CAAC,IAAI,CAAC;AAC9E;AAEA,SAAS,6BAA6B,aAAsB,aAAoC;AAC9F,MAAI,eAAe,KAAM,QAAO,CAAC;AACjC,MAAI,OAAO,gBAAgB,UAAU;AACnC,WAAO,YAAY,KAAK,IACpB,CAAC,EAAE,MAAM,QAAiB,MAAM,aAAa,cAAc,YAAY,CAAC,IACxE,CAAC;EACP;AACA,MAAI,OAAO,gBAAgB,UAAU;AACnC,WAAO;MACL,EAAE,MAAM,QAAQ,MAAM,KAAK,UAAU,aAAa,MAAM,CAAC,GAAG,cAAc,YAAY;IACxF;EACF;AACA,QAAM,OAAO,OAAO,WAAW;AAC/B,SAAO,KAAK,KAAK,IAAI,CAAC,EAAE,MAAM,QAAQ,MAAM,cAAc,YAAY,CAAC,IAAI,CAAC;AAC9E;AAEO,IAAM,YAAN,cAAwB,UAAU;EAC9B,OAAO;EACP,cAAc;EAEf,WAA0B;EAC1B,iBAAiB,oBAAI,IAAyB;EAC9C,aAAa,oBAAI,IAAoB;EAErC,eAA8B;AACpC,UAAM,QAAQ,qBAAqB;AACnC,WAAO,cAAcP,MAAK,MAAM,UAAU,UAAU,GAAG,WAAW;EACpE;;EAGQ,iBAAuB;AAC7B,UAAM,QAAQ,qBAAqB;AACnC,UAAM,aAAaA,MAAK,MAAM,UAAU,WAAW;AACnD,QAAI,CAACF,YAAW,UAAU,EAAG;AAC7B,QAAI;AACF,YAAM,MAAM,KAAK,MAAMC,cAAa,YAAY,OAAO,CAAC;AACxD,YAAM,WAAW,KAAK;AACtB,UAAI,CAAC,MAAM,QAAQ,QAAQ,EAAG;AAC9B,iBAAW,MAAM,UAAU;AACzB,cAAM,OAAQ,GAAmB;AACjC,YAAI,OAAO,SAAS,SAAU;AAC9B,cAAM,OAAO,WAAW,KAAK,EAAE,OAAO,IAAI,EAAE,OAAO,KAAK;AACxD,aAAK,WAAW,IAAI,MAAM,IAAI;MAChC;IACF,QAAQ;IAER;EACF;EAEA,cAAuB;AACrB,SAAK,WAAW,KAAK,aAAa;AAClC,QAAI,CAAC,KAAK,SAAU,QAAO;AAC3B,SAAK,eAAe;AACpB,QAAI;AACF,aAAO,KAAK,gBAAgB,EAAE,SAAS;IACzC,QAAQ;IAER;AACA,WAAO;EACT;;EAGQ,kBAA4B;AAClC,QAAI,CAAC,KAAK,SAAU,QAAO,CAAC;AAC5B,UAAM,OAAiB,CAAC;AACxB,QAAI;AACF,iBAAW,aAAaI,aAAY,KAAK,UAAU,EAAE,eAAe,KAAK,CAAC,GAAG;AAC3E,YAAI,CAAC,UAAU,YAAY,EAAG;AAC9B,cAAM,WAAWH,MAAK,KAAK,UAAU,UAAU,IAAI;AACnD,YAAI;AACF,qBAAW,gBAAgBG,aAAY,UAAU,EAAE,eAAe,KAAK,CAAC,GAAG;AACzE,gBAAI,CAAC,aAAa,YAAY,EAAG;AACjC,kBAAM,cAAcH,MAAK,UAAU,aAAa,IAAI;AACpD,gBACEF,YAAWE,MAAK,aAAa,eAAe,CAAC,KAC7CF,YAAWE,MAAK,aAAa,YAAY,CAAC,GAC1C;AACA,mBAAK,KAAK,WAAW;YACvB;UACF;QACF,QAAQ;QAER;MACF;IACF,QAAQ;IAER;AACA,WAAO;EACT;;EAGQ,gBAAgB,YAAwC;AAC9D,QAAI;AACF,YAAM,YAAYC,UAAS,UAAU;AACrC,YAAM,cAAcA,UAAS,QAAQ,UAAU,CAAC;AAChD,YAAM,cAAcD,MAAK,YAAY,eAAe;AACpD,YAAM,WAAWA,MAAK,YAAY,YAAY;AAE9C,UAAI,CAACF,YAAW,WAAW,KAAK,CAACA,YAAW,QAAQ,EAAG,QAAO;AAE9D,YAAM,YAAYE,MAAK,YAAY,YAAY;AAC/C,YAAM,WAAWA,MAAK,YAAY,eAAe;AAEjD,UAAI,QAAQ;AACZ,UAAI,YAA2B;AAC/B,UAAI,WAAW;AAEf,UAAIF,YAAW,SAAS,GAAG;AACzB,cAAM,QAAQ,KAAK,MAAMC,cAAa,WAAW,OAAO,CAAC;AACzD,gBAAQ,OAAO,MAAM,gBAAgB,EAAE;AACvC,oBAAY,OAAO,MAAM,eAAe,WAAW,MAAM,aAAa;AACtE,mBAAW;MACb,WAAWD,YAAW,QAAQ,GAAG;AAC/B,cAAM,OAAO,KAAK,MAAMC,cAAa,UAAU,OAAO,CAAC;AACvD,gBAAQ,OAAO,KAAK,SAAS,EAAE;AAC/B,oBAAY,OAAO,KAAK,eAAe,WAAW,KAAK,aAAa;AACpE,mBAAW;MACb;AAEA,YAAM,MAAM,KAAK,WAAW,IAAI,WAAW,KAAK;AAChD,YAAM,YACJ,cAAc,OACV,YAAY,MACZ,WACEG,UAAS,QAAQ,EAAE,UACnBA,UAAS,UAAU,EAAE;AAE7B,aAAO;QACL,IAAI;QACJ,OAAO,SAAS;QAChB,YAAY;QACZ;QACA,aAAaJ,YAAW,WAAW,IAAI,cAAc;QACrD,UAAUA,YAAW,QAAQ,IAAI,WAAW;QAC5C;QACA;MACF;IACF,QAAQ;AACN,aAAO;IACT;EACF;EAEA,OAAsB;AACpB,QAAI,CAAC,KAAK,SAAU,QAAO,CAAC;AAE5B,UAAM,aAAa,KAAK,MAAM,WAAW;AAEzC,UAAM,aAAa,KAAK,MAAM,iBAAiB;AAC/C,UAAM,cAAc,KAAK,gBAAgB;AACzC,SAAK,IAAI,UAAU;AAEnB,UAAM,QAAuB,CAAC;AAC9B,eAAW,OAAO,aAAa;AAC7B,UAAI;AACF,cAAM,cAAc,KAAK,MAAM,mBAAmBG,UAAS,GAAG,CAAC,EAAE;AACjE,cAAM,OAAO,KAAK,gBAAgB,GAAG;AACrC,aAAK,IAAI,WAAW;AAEpB,YAAI,CAAC,KAAM;AAEX,aAAK,eAAe,IAAI,KAAK,IAAI,IAAI;AACrC,cAAM,KAAK;UACT,IAAI,KAAK;UACT,MAAM,QAAQ,KAAK,EAAE;UACrB,OAAO,KAAK;UACZ,WAAW,KAAK;UAChB,cAAc,KAAK;UACnB,cAAc,KAAK;UACnB,OAAO;YACL,eAAe;YACf,oBAAoB;YACpB,qBAAqB;YACrB,YAAY;UACd;QACF,CAAC;MACH,QAAQ;MAER;IACF;AAEA,SAAK,IAAI,UAAU;AACnB,WAAO;EACT;EAEA,oBAAmD;AACjD,WAAO,KAAK;EACd;EAEA,kBAAkB,MAA2C;AAC3D,SAAK,iBAAiB;EACxB;;;;EAKA,gBAAgB,gBAAwB,gBAAkD;AACxF,UAAM,aAAuB,CAAC;AAE9B,eAAW,WAAW,gBAAgB;AACpC,YAAM,OAAO,KAAK,eAAe,IAAI,QAAQ,EAAE;AAC/C,UAAI,CAAC,KAAM;AAEX,UAAI;AAEF,YAAI,KAAK,UAAU;AACjB,gBAAM,OAAOC,UAAS,KAAK,QAAQ;AACnC,cAAI,KAAK,UAAU,gBAAgB;AACjC,uBAAW,KAAK,QAAQ,EAAE;AAC1B;UACF;QACF;AAGA,cAAM,WAAW,KAAK,YAAY,KAAK;AACvC,YAAI,UAAU;AACZ,gBAAM,WAAWA,UAAS,QAAQ;AAClC,cAAI,SAAS,UAAU,gBAAgB;AACrC,uBAAW,KAAK,QAAQ,EAAE;UAC5B;QACF;MACF,QAAQ;AACN,mBAAW,KAAK,QAAQ,EAAE;MAC5B;IACF;AAEA,WAAO;MACL,YAAY,WAAW,SAAS;MAChC;MACA,WAAW,KAAK,IAAI;IACtB;EACF;;;;EAKA,gBAAgB,gBAA+B,YAAqC;AAClF,UAAM,aAAa,IAAI,IAAI,eAAe,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AAE/D,eAAW,OAAO,KAAK,gBAAgB,GAAG;AACxC,UAAI;AACF,cAAM,OAAO,KAAK,gBAAgB,GAAG;AACrC,YAAI,CAAC,KAAM;AAEX,YAAI,WAAW,SAAS,KAAK,EAAE,GAAG;AAChC,eAAK,eAAe,IAAI,KAAK,IAAI,IAAI;AACrC,qBAAW,IAAI,KAAK,IAAI;YACtB,IAAI,KAAK;YACT,MAAM,QAAQ,KAAK,EAAE;YACrB,OAAO,KAAK;YACZ,WAAW,KAAK;YAChB,cAAc,KAAK;YACnB,cAAc,KAAK;YACnB,OAAO;cACL,eAAe;cACf,oBAAoB;cACpB,qBAAqB;cACrB,YAAY;YACd;UACF,CAAC;QACH;MACF,QAAQ;MAER;IACF;AAEA,WAAO,MAAM,KAAK,WAAW,OAAO,CAAC;EACvC;EAEA,eAAe,WAAgC;AAC7C,UAAM,OAAO,KAAK,eAAe,IAAI,SAAS;AAC9C,QAAI,CAAC,KAAM,OAAM,IAAI,MAAM,sBAAsB,SAAS,EAAE;AAE5D,QAAI,KAAK,aAAa;AACpB,aAAO,KAAK,0BAA0B,IAAI;IAC5C;AACA,WAAO,KAAK,uBAAuB,IAAI;EACzC;EAEQ,0BAA0B,MAAgC;AAChE,QAAI,CAAC,KAAK,YAAa,OAAM,IAAI,MAAM,0BAA0B;AAEjE,UAAM,UAAUH,cAAa,KAAK,aAAa,OAAO;AACtD,UAAM,WAAsB,CAAC;AAC7B,UAAM,mBAAmB,oBAAI,IAA8B;AAC3D,UAAM,qBAAqB,oBAAI,IAAY;AAE3C,QAAI,MAAM;AACV,UAAM,aAAa,KAAK;AACxB,eAAW,UAAU,gBAAgB,OAAO,GAAG;AAC7C;AACA,UAAI;AACF,cAAM,OAAO,OAAO,OAAO,QAAQ,EAAE;AACrC,YAAI,SAAS,iBAAiB,SAAS,SAAU;AAEjD,YAAI,SAAS,QAAQ;AACnB,gBAAM,OAAO,OAAO,OAAO,WAAW,EAAE;AACxC,cAAI,KAAK,KAAK,GAAG;AACf,qBAAS;cACP,KAAK,aAAa;gBAChB,WAAW,WAAW,GAAG;gBACzB,MAAM;gBACN,aAAa;gBACb,OAAO,CAAC,EAAE,MAAM,QAAQ,MAAM,cAAc,WAAW,CAAC;cAC1D,CAAC;YACH;UACF;AACA;QACF;AAEA,YAAI,SAAS,aAAa;AACxB,gBAAM,EAAE,SAAS,YAAY,IAAI,KAAK;YACpC;YACA;YACA;YACA;UACF;AACA,cAAI,CAAC,QAAS;AACd,gBAAM,WAAW,SAAS;AAC1B,mBAAS,KAAK,OAAO;AACrB,qBAAW,CAAC,QAAQ,SAAS,KAAK,aAAa;AAC7C,6BAAiB,IAAI,QAAQ,CAAC,UAAU,SAAS,CAAC;UACpD;AACA;QACF;AAEA,YAAI,SAAS,QAAQ;AACnB,gBAAM,SAAS,OAAO,OAAO,gBAAgB,EAAE,EAAE,KAAK;AACtD,cAAI,UAAU,mBAAmB,IAAI,MAAM,EAAG;AAC9C,gBAAM,cAAc,yBAAyB,OAAO,SAAS,UAAU;AACvE,cAAI,UAAU,KAAK,mBAAmB,UAAU,kBAAkB,QAAQ,WAAW,GAAG;AACtF;UACF;AACA,cAAI,YAAY,SAAS,GAAG;AAC1B,qBAAS;cACP,KAAK,aAAa;gBAChB,WAAW,WAAW,GAAG;gBACzB,MAAM;gBACN,aAAa;gBACb,OAAO;cACT,CAAC;YACH;UACF;QACF;MACF,QAAQ;MAER;IACF;AAEA,UAAM,QAAQ,KAAK,aAAa,KAAK,UAAU;AAC/C,WAAO,KAAK,iBAAiB,MAAM,UAAU,KAAK;EACpD;EAEQ,uBAAuB,MAAgC;AAC7D,UAAM,WAAW,KAAK,YAAYC,MAAK,KAAK,YAAY,YAAY;AACpE,QAAI,CAACF,YAAW,QAAQ,EAAG,OAAM,IAAI,MAAM,uBAAuB;AAElE,UAAM,UAAUC,cAAa,UAAU,OAAO;AAC9C,UAAM,WAAsB,CAAC;AAC7B,UAAM,mBAAmB,oBAAI,IAA8B;AAC3D,UAAM,qBAAqB,oBAAI,IAAY;AAC3C,UAAM,yBAAyB,oBAAI,IAAoB;AAEvD,QAAI,wBAAuC;AAC3C,QAAI,iBAAgC;AACpC,QAAI,MAAM;AAEV,eAAW,UAAU,gBAAgB,OAAO,GAAG;AAC7C;AACA,UAAI;AACF,cAAM,UAAW,OAAO,WAAW,CAAC;AACpC,cAAM,UAAU,OAAO,QAAQ,QAAQ,EAAE;AACzC,cAAM,UAAW,QAAQ,WAAW,CAAC;AACrC,cAAM,YAAY,OAAO,OAAO,aAAa,CAAC;AAC9C,cAAM,cAAc,OAAO,SAAS,SAAS,IAAI,KAAK,MAAM,YAAY,GAAI,IAAI;AAGhF,cAAM,QAAQ,QAAQ,OAAO;AAC7B,YAAI,SAAS,OAAO,UAAU,UAAU;AACtC,gBAAM,cAAc,OAAO,MAAM,cAAc,KAAK,CAAC;AACrD,gBAAM,eAAe,OAAO,MAAM,eAAe,KAAK,CAAC;AACvD,cAAI,eAAe,cAAc;AAC/B,qBAAS,IAAI,SAAS,SAAS,GAAG,KAAK,GAAG,KAAK;AAC7C,oBAAM,MAAM,SAAS,CAAC;AACtB,kBAAI,IAAI,SAAS,eAAe,CAAC,IAAI,QAAQ;AAC3C,oBAAI,SAAS,EAAE,OAAO,aAAa,QAAQ,aAAa;AACxD;cACF;YACF;UACF;QACF;AAEA,YAAI,YAAY,aAAa;AAC3B,gBAAM,YAAY,QAAQ;AAC1B,cAAI,MAAM,QAAQ,SAAS,KAAK,UAAU,SAAS,GAAG;AACpD,kBAAM,OAAO,OAAQ,UAAU,CAAC,GAA+B,QAAQ,EAAE;AACzE,gBAAI,KAAK,KAAK,GAAG;AACf,uBAAS;gBACP,KAAK,aAAa;kBAChB,WAAW,QAAQ,GAAG;kBACtB,MAAM;kBACN;kBACA,OAAO,CAAC,EAAE,MAAM,QAAQ,MAAM,cAAc,YAAY,CAAC;gBAC3D,CAAC;cACH;YACF;UACF;AACA,kCAAwB;AACxB,2BAAiB;AACjB;QACF;AAEA,YAAI,YAAY,eAAe;AAC7B,kCAAwB,KAAK;YAC3B;YACA;YACA,QAAQ,GAAG;UACb;AACA,gBAAM,YAAY,SAAS,qBAAqB;AAChD,gBAAM,WAAW,OAAO,QAAQ,QAAQ,EAAE;AAC1C,cAAI,aAAa,SAAS;AACxB,kBAAM,OAAO,OAAO,QAAQ,SAAS,EAAE;AACvC,gBAAI,KAAK,KAAK,GAAG;AACf,wBAAU,MAAM,KAAK,EAAE,MAAM,aAAa,MAAM,cAAc,YAAY,CAAC;YAC7E;UACF,WAAW,aAAa,QAAQ;AAC9B,kBAAM,OAAO,OAAO,QAAQ,QAAQ,EAAE;AACtC,gBAAI,KAAK,KAAK,GAAG;AACf,wBAAU,MAAM,KAAK,EAAE,MAAM,QAAQ,MAAM,cAAc,YAAY,CAAC;YACxE;UACF;AACA;QACF;AAEA,YAAI,YAAY,YAAY;AAC1B,gBAAM,YAAY,QAAQ;AAC1B,gBAAM,WAAW,OAAO,WAAW,QAAQ,EAAE,EAAE,KAAK;AACpD,gBAAM,SAAS,OAAO,QAAQ,MAAM,EAAE,EAAE,KAAK;AAE7C,cAAI,YAAY,UAAU,mBAAmB,IAAI,QAAQ,GAAG;AAC1D,+BAAmB,IAAI,MAAM;AAC7B,6BAAiB;AACjB;UACF;AAEA,cAAI,CAAC,aAAa,CAAC,UAAU,CAAC,SAAU;AAExC,kCAAwB,KAAK;YAC3B;YACA;YACA,QAAQ,GAAG;UACb;AACA,gBAAM,YAAY,SAAS,qBAAqB;AAEhD,gBAAM,UAAU,UAAU;AAC1B,gBAAM,iBAAiB,uBAAuB,OAAO;AACrD,gBAAM,SACJ,OAAO,YAAY,YAAY,OAAO,mBAAmB,WAAW,UAAU;AAEhF,gBAAM,WAAwB;YAC5B,MAAM;YACN,MAAM;YACN,QAAQ;YACR,OAAO,aAAa,QAAQ;YAC5B,OAAO,EAAE,WAAW,gBAAgB,QAAQ,KAAK;YACjD,cAAc;UAChB;AAEA,gBAAM,YAAY,UAAU,MAAM;AAClC,oBAAU,MAAM,KAAK,QAAQ;AAC7B,oBAAU,OAAO;AACjB,2BAAiB,IAAI,QAAQ,CAAC,uBAAuB,SAAS,CAAC;AAC/D,2BAAiB;AAEjB,cAAI,WAAW,MAAM;AACnB,mCAAuB,IAAI,QAAQ,MAAM;UAC3C;AACA;QACF;AAEA,YAAI,YAAY,gBAAgB;AAC9B,cAAI,kBAAkB,mBAAmB,IAAI,cAAc,EAAG;AAC9D,gBAAM,gBAAgB,OAAO,QAAQ,kBAAkB,EAAE;AACzD,eAAK;YACH;YACA;YACA;YACA;YACA;UACF;AACA;QACF;AAEA,YAAI,YAAY,cAAc;AAC5B,gBAAM,SAAS,OAAO,QAAQ,gBAAgB,EAAE,EAAE,KAAK;AACvD,cAAI,UAAU,mBAAmB,IAAI,MAAM,EAAG;AAC9C,gBAAM,cAAc,6BAA6B,QAAQ,cAAc,WAAW;AAClF,cAAI,UAAU,KAAK,mBAAmB,UAAU,kBAAkB,QAAQ,WAAW,GAAG;AACtF;UACF;AACA,cAAI,YAAY,SAAS,GAAG;AAC1B,qBAAS;cACP,KAAK,aAAa;gBAChB,WAAW,QAAQ,GAAG;gBACtB,MAAM;gBACN;gBACA,OAAO;cACT,CAAC;YACH;UACF;AACA;QACF;MAGF,QAAQ;MAER;IACF;AAGA,UAAM,mBAAmB,SAAS,OAAO,CAAC,MAAM,EAAE,MAAM,SAAS,CAAC;AAClE,UAAM,QAAQ,KAAK,aAAa,KAAK,UAAU;AAC/C,WAAO,KAAK,iBAAiB,MAAM,kBAAkB,KAAK;EAC5D;;EAIQ,aAAa,MAWT;AACV,WAAO;MACL,IAAI,KAAK;MACT,MAAM,KAAK;MACX,OAAO,KAAK,SAAS;MACrB,cAAc,KAAK;MACnB,MAAM,KAAK,QAAQ;MACnB,OAAO,KAAK,SAAS;MACrB,UAAU,KAAK,YAAY;MAC3B,QAAQ,KAAK,SAAU,KAAK,SAA+B;MAC3D,MAAM,KAAK,QAAQ;MACnB,OAAO,KAAK;IACd;EACF;EAEQ,6BACN,QACA,KACA,oBACA,YACwD;AACxD,UAAM,QAAuB,CAAC;AAC9B,UAAM,cAAc,oBAAI,IAAoB;AAE5C,UAAM,UAAU,OAAO;AACvB,QAAI,MAAM,QAAQ,OAAO,GAAG;AAC1B,iBAAW,QAAQ,SAAS;AAC1B,YAAI,OAAO,SAAS,YAAY,SAAS,KAAM;AAC/C,cAAM,KAAK;AACX,cAAM,WAAW,OAAO,GAAG,QAAQ,EAAE;AAErC,YAAI,aAAa,SAAS;AACxB,gBAAM,OAAO,OAAO,GAAG,SAAS,EAAE;AAClC,cAAI,KAAK,KAAK,EAAG,OAAM,KAAK,EAAE,MAAM,aAAa,MAAM,cAAc,WAAW,CAAC;QACnF,WAAW,aAAa,QAAQ;AAC9B,gBAAM,OAAO,OAAO,GAAG,QAAQ,EAAE;AACjC,cAAI,KAAK,KAAK,EAAG,OAAM,KAAK,EAAE,MAAM,QAAQ,MAAM,cAAc,WAAW,CAAC;QAC9E;MACF;IACF;AAEA,UAAM,YAAY,OAAO;AACzB,QAAI,MAAM,QAAQ,SAAS,GAAG;AAC5B,iBAAW,MAAM,WAAW;AAC1B,YAAI,OAAO,OAAO,YAAY,OAAO,KAAM;AAC3C,cAAM,WAAW;AACjB,cAAM,YAAY,SAAS;AAE3B,YAAI,CAAC,UAAW;AAChB,cAAM,WAAW,OAAO,UAAU,QAAQ,EAAE,EAAE,KAAK;AACnD,cAAM,SAAS,OAAO,SAAS,MAAM,EAAE,EAAE,KAAK;AAE9C,YAAI,YAAY,UAAU,mBAAmB,IAAI,QAAQ,GAAG;AAC1D,6BAAmB,IAAI,MAAM;AAC7B;QACF;AAEA,YAAI,CAAC,YAAY,CAAC,OAAQ;AAE1B,cAAM,OAAoB;UACxB,MAAM;UACN,MAAM;UACN,QAAQ;UACR,OAAO,aAAa,QAAQ;UAC5B,OAAO,EAAE,WAAW,uBAAuB,UAAU,SAAS,GAAG,QAAQ,KAAK;UAC9E,cAAc;QAChB;AACA,oBAAY,IAAI,QAAQ,MAAM,MAAM;AACpC,cAAM,KAAK,IAAI;MACjB;IACF;AAEA,QAAI,MAAM,WAAW,GAAG;AACtB,aAAO;QACL,SAAS,KAAK,aAAa;UACzB,WAAW,WAAW,GAAG;UACzB,MAAM;UACN,aAAa;UACb,OAAO,CAAC;QACV,CAAC;QACD;MACF;IACF;AAEA,UAAM,WAAW,MAAM,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM;AACrD,UAAM,UAAU,KAAK,aAAa;MAChC,WAAW,WAAW,GAAG;MACzB,MAAM;MACN,aAAa;MACb;MACA,OAAO;MACP,MAAM,WAAW,SAAS;IAC5B,CAAC;AAED,WAAO,EAAE,SAAS,YAAY;EAChC;EAEQ,yBACN,UACA,cACA,WACQ;AACR,QAAI,iBAAiB,KAAM,QAAO;AAClC,aAAS;MACP,KAAK,aAAa;QAChB;QACA,MAAM;QACN,aAAa;QACb,OAAO,CAAC;QACR,OAAO;MACT,CAAC;IACH;AACA,WAAO,SAAS,SAAS;EAC3B;EAEQ,uBACN,eACA,YACA,QACA,UACA,kBACM;AACN,QAAI,CAAC,cAAc,CAAC,iBAAiB,IAAI,UAAU,EAAG;AAEtD,UAAM,WAAW,OAAO,IAAI,UAAU,KAAK;AAC3C,UAAM,WAAW,WAAW;AAE5B,QAAI;AACF,YAAM,SAAS,KAAK,MAAM,QAAQ;AAClC,YAAM,WAAW,iBAAiB,IAAI,UAAU;AAChD,UAAI,CAAC,SAAU;AACf,YAAM,UAAU,SAAS,SAAS,CAAC,CAAC,GAAG,MAAM,SAAS,CAAC,CAAC;AACxD,UAAI,SAAS,OAAO;AAClB,gBAAQ,MAAM,YAAY;MAC5B;AACA,aAAO,OAAO,UAAU;IAC1B,QAAQ;AACN,aAAO,IAAI,YAAY,QAAQ;IACjC;EACF;EAEQ,mBACN,UACA,kBACA,QACA,aACS;AACT,QAAI,CAAC,YAAY,UAAU,CAAC,OAAQ,QAAO;AAE3C,UAAM,WAAW,iBAAiB,IAAI,MAAM;AAC5C,QAAI,CAAC,SAAU,QAAO;AAEtB,UAAM,OAAO,SAAS,SAAS,CAAC,CAAC,GAAG,MAAM,SAAS,CAAC,CAAC;AACrD,QAAI,CAAC,KAAM,QAAO;AAClB,QAAI,CAAC,KAAK,MAAO,MAAK,QAAQ,CAAC;AAC/B,SAAK,MAAM,SAAS,CAAC,GAAG,WAAW;AACnC,WAAO;EACT;EAEQ,aAAa,YAA0C;AAC7D,UAAM,QAAQ;MACZ,YAAY;MACZ,oBAAoB;MACpB,qBAAqB;MACrB,cAAc;MACd,eAAe;IACjB;AAEA,UAAM,WAAWC,MAAK,YAAY,YAAY;AAC9C,QAAI,CAACF,YAAW,QAAQ,EAAG,QAAO;AAElC,QAAI;AACF,YAAM,UAAUC,cAAa,UAAU,OAAO;AAC9C,iBAAW,QAAQ,QAAQ,MAAM,IAAI,EAAE,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG;AAC9D,YAAI;AACF,gBAAM,OAAO,KAAK,MAAM,IAAI;AAC5B,gBAAM,aAAc,KAAK,SAAqC;AAG9D,cAAI,CAAC,WAAY;AACjB,gBAAM,sBAAsB,OAAO,WAAW,gBAAgB,CAAC;AAC/D,gBAAM,uBAAuB,OAAO,WAAW,iBAAiB,CAAC;QACnE,QAAQ;QAER;MACF;IACF,QAAQ;IAER;AAGA,UAAM,cAAcC,MAAK,YAAY,eAAe;AACpD,UAAM,UAAUF,YAAW,WAAW,IAAI,cAAc;AACxD,QAAI,CAACA,YAAW,OAAO,EAAG,QAAO;AAEjC,QAAI;AACF,YAAM,aAAaC,cAAa,SAAS,OAAO;AAChD,iBAAW,QAAQ,WAAW,MAAM,IAAI,EAAE,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG;AACjE,YAAI;AACF,gBAAM,OAAO,KAAK,MAAM,IAAI;AAC5B,cAAI,KAAK,SAAS,YAAY,OAAO,KAAK,gBAAgB,UAAU;AAClE,kBAAM,eAAe,KAAK;UAC5B;QACF,QAAQ;QAER;MACF;IACF,QAAQ;IAER;AAEA,WAAO;EACT;EAEQ,iBACN,MACA,UACA,OACa;AACb,UAAM,gBAAgB,SAAS;AAC/B,WAAO;MACL,IAAI,KAAK;MACT,OAAO,KAAK;MACZ,MAAM,QAAQ,KAAK,EAAE;MACrB,WAAW,KAAK;MAChB,cAAc,KAAK;MACnB,cAAc,KAAK;MACnB;MACA;IACF;EACF;AACF;AC/zBA,IAAM,wBAAwB;AAC9B,IAAM,uBAAuB;AAC7B,IAAM,gCACJ;AAEF,IAAM,8BAA8B;EAClC;EACA;EACA;EACA;EACA;AACF;AAEA,SAAS,2BAA2B,MAAuB;AACzD,QAAM,QAAQ,KAAK,YAAY;AAC/B,SAAO,4BAA4B,KAAK,CAAC,MAAM,MAAM,SAAS,CAAC,CAAC;AAClE;AAEA,IAAM,uBAA+C;EACnD,cAAc;EACd,aAAa;EACb,OAAO;EACP,aAAa;EACb,UAAU;AACZ;AAWA,SAAS,iBAAiB,UAA0B;AAClD,QAAM,OAAOE,UAAS,UAAU,QAAQ;AACxC,QAAM,QAAQ,KAAK,MAAM,GAAG;AAC5B,MAAI,MAAM,UAAU,GAAG;AACrB,WAAO,MAAM,MAAM,EAAE,EAAE,KAAK,GAAG;EACjC;AACA,SAAO;AACT;AAMA,SAASQ,kBAAiB,MAAuC;AAC/D,QAAM,KAAK,OAAO,KAAK,WAAW,KAAK,EAAE,EAAE,KAAK;AAChD,MAAI,CAAC,GAAI,QAAO;AAChB,MAAI;AACF,WAAO,IAAI,KAAK,GAAG,SAAS,GAAG,IAAI,KAAK,GAAG,QAAQ,KAAK,GAAG,IAAI,GAAG,EAAE,QAAQ;EAC9E,QAAQ;AACN,WAAO;EACT;AACF;AAMA,SAASJ,oBAAmB,MAAsB;AAChD,QAAM,OAAO,KAAK,MAAM,IAAI,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC;AAClD,SAAO,MAAM,KAAK,EAAE,MAAM,GAAG,EAAE,KAAK;AACtC;AAMA,SAASK,cAAa,MAAsB;AAC1C,SAAO,qBAAqB,IAAI,KAAK;AACvC;AAEA,SAASC,wBAAuB,KAAuB;AACrD,MAAI,OAAO,QAAQ,UAAU;AAC3B,QAAI;AACF,aAAO,KAAK,MAAM,GAAG;IACvB,QAAQ;AACN,aAAO;IACT;EACF;AACA,SAAO;AACT;AAEA,SAAS,6BAA6B,UAAkB,OAAyB;AAC/E,MAAI,aAAa,eAAe;AAC9B,WAAO,qBAAqB,KAAK;EACnC;AACA,SAAO;AACT;AAaA,IAAM,iBAAiB;AACvB,IAAM,eAAe;AACrB,IAAM,kBAAkB;AACxB,IAAM,mBAAmB;AAEzB,SAAS,qBAAqB,OAA8B;AAC1D,QAAM,OAAO,OAAO,UAAU,WAAW,QAAQ;AACjD,MAAI,CAAC,KAAM,QAAO,CAAC;AAEnB,QAAM,SAAuB,CAAC;AAC9B,QAAM,QAAQ,KAAK,MAAM,IAAI;AAC7B,MAAI,UAAU;AACd,MAAI,IAAI;AAER,SAAO,IAAI,MAAM,QAAQ;AACvB,UAAM,OAAO,MAAM,CAAC;AAEpB,QAAI,CAAC,WAAW,eAAe,KAAK,IAAI,GAAG;AACzC,gBAAU;AACV;AACA;IACF;AAEA,QAAI,WAAW,aAAa,KAAK,IAAI,GAAG;AACtC,gBAAU;AACV;AACA;IACF;AAEA,QAAI,SAAS;AACX,YAAM,cAAc,KAAK,MAAM,eAAe;AAC9C,UAAI,aAAa;AACf,cAAM,SAAS,YAAY,CAAC;AAC5B,cAAM,WAAW,YAAY,CAAC,EAAG,KAAK;AACtC;AAEA,YAAI,WAAW,OAAO;AACpB,gBAAM,UAAU,oBAAoB,OAAO,CAAC;AAC5C,cAAI,QAAQ;AACZ,iBAAO,KAAK,EAAE,MAAM,cAAc,MAAM,UAAU,SAAS,QAAQ,KAAK,CAAC;QAC3E,WAAW,WAAW,UAAU;AAE9B,cAAI,eAA8B;AAClC,cAAI,eAAe;AACnB,mBAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,kBAAM,IAAI,MAAM,CAAC;AACjB,gBAAI,CAAC,EAAE,KAAK,EAAG;AACf,kBAAM,YAAY,EAAE,MAAM,gBAAgB;AAC1C,gBAAI,WAAW;AACb,6BAAe,UAAU,CAAC,EAAG,KAAK;AAClC,6BAAe,IAAI;AACnB;YACF;AACA;UACF;AACA,cAAI,cAAc;AAChB,kBAAM,UAAU,oBAAoB,OAAO,YAAY;AACvD,gBAAI,QAAQ;AACZ,mBAAO,KAAK;cACV,MAAM;cACN,MAAM;cACN,YAAY;cACZ,SAAS,QAAQ;YACnB,CAAC;UACH,OAAO;AACL,kBAAM,UAAU,oBAAoB,OAAO,CAAC;AAC5C,gBAAI,QAAQ;AACZ,mBAAO,KAAK,EAAE,MAAM,aAAa,MAAM,UAAU,SAAS,QAAQ,KAAK,CAAC;UAC1E;QACF,WAAW,WAAW,UAAU;AAC9B,iBAAO,KAAK,EAAE,MAAM,eAAe,MAAM,SAAS,CAAC;QAErD;AACA;MACF;IACF;AAEA;EACF;AAEA,SAAO;AACT;AAEA,SAAS,oBACP,OACA,YACyC;AACzC,QAAM,eAAyB,CAAC;AAChC,MAAI,IAAI;AACR,SAAO,IAAI,MAAM,QAAQ;AACvB,UAAM,OAAO,MAAM,CAAC;AAEpB,QAAI,gBAAgB,KAAK,IAAI,KAAK,aAAa,KAAK,IAAI,EAAG;AAC3D,iBAAa,KAAK,IAAI;AACtB;EACF;AACA,SAAO,EAAE,MAAM,aAAa,KAAK,IAAI,GAAG,eAAe,EAAE;AAC3D;AAuBO,IAAM,aAAN,cAAyB,UAAU;EAC/B,OAAO;EACP,cAAc;EAEf,WAA0B;EAC1B,oBAAoB,oBAAI,IAAoB;EAC5C,iBAAiB,oBAAI,IAAyB;;EAI9C,eAA8B;AACpC,UAAM,QAAQ,qBAAqB;AACnC,WAAO,cAAcX,MAAK,MAAM,WAAW,UAAU,CAAC;EACxD;EAEA,cAAuB;AACrB,SAAK,WAAW,KAAK,aAAa;AAClC,QAAI,CAAC,KAAK,SAAU,QAAO;AAC3B,QAAI;AAEF,YAAM,QAAQ,KAAK,uBAAuB,KAAK,QAAQ;AACvD,aAAO,MAAM,SAAS;IACxB,QAAQ;AACN,aAAO;IACT;EACF;EAEA,OAAsB;AACpB,QAAI,CAAC,KAAK,SAAU,QAAO,CAAC;AAE5B,UAAM,aAAa,KAAK,MAAM,YAAY;AAG1C,UAAM,cAAc,KAAK,MAAM,kBAAkB;AACjD,SAAK,iBAAiB;AACtB,SAAK,IAAI,WAAW;AAEpB,UAAM,QAAuB,CAAC;AAE9B,UAAM,aAAa,KAAK,MAAM,kBAAkB;AAChD,UAAM,QAAQ,KAAK,iBAAiB;AACpC,SAAK,IAAI,UAAU;AAEnB,eAAW,QAAQ,OAAO;AACxB,UAAI;AACF,cAAM,cAAc,KAAK,MAAM,oBAAoBC,UAAS,IAAI,CAAC,EAAE;AACnE,cAAM,OAAO,KAAK,iBAAiB,IAAI;AACvC,aAAK,IAAI,WAAW;AAEpB,YAAI,MAAM;AACR,gBAAM,KAAK,IAAI;AACf,eAAK,eAAe,IAAI,KAAK,IAAI;YAC/B,IAAI,KAAK;YACT,OAAO,KAAK;YACZ,YAAY;YACZ,WAAW,KAAK;YAChB,OAAO;YACP,cAAc,KAAK,MAAM;YACzB,WAAW,KAAK;YAChB,WAAW,KAAK,gBAAgB,KAAK;UACvC,CAAC;QACH;MACF,QAAQ;MAER;IACF;AAEA,SAAK,IAAI,UAAU;AACnB,WAAO;EACT;EAEA,oBAAmD;AACjD,WAAO,KAAK;EACd;EAEA,kBAAkB,MAA2C;AAC3D,SAAK,iBAAiB;EACxB;;;;EAKA,gBAAgB,gBAAwB,gBAAkD;AACxF,QAAI,CAAC,KAAK,UAAU;AAClB,aAAO,EAAE,YAAY,OAAO,WAAW,KAAK,IAAI,EAAE;IACpD;AAEA,UAAM,aAAuB,CAAC;AAE9B,eAAW,WAAW,gBAAgB;AACpC,YAAM,OAAO,KAAK,eAAe,IAAI,QAAQ,EAAE;AAC/C,UAAI,CAAC,KAAM;AAEX,UAAI;AACF,cAAM,OAAOC,UAAS,KAAK,UAAU;AACrC,YAAI,KAAK,UAAU,gBAAgB;AACjC,qBAAW,KAAK,QAAQ,EAAE;QAC5B;MACF,QAAQ;AACN,mBAAW,KAAK,QAAQ,EAAE;MAC5B;IACF;AAGA,QAAI;AACF,YAAM,WAAW,KAAK,iBAAiB;AACvC,YAAM,cAAc,SAAS,SAAS,eAAe;AAErD,aAAO;QACL,YAAY,WAAW,SAAS,KAAK;QACrC;QACA,WAAW,KAAK,IAAI;MACtB;IACF,QAAQ;AACN,aAAO;QACL,YAAY,WAAW,SAAS;QAChC;QACA,WAAW,KAAK,IAAI;MACtB;IACF;EACF;;;;EAKA,gBAAgB,gBAA+B,YAAqC;AAClF,QAAI,CAAC,KAAK,SAAU,QAAO;AAE3B,UAAM,aAAa,IAAI,IAAI,eAAe,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AAG/D,eAAW,QAAQ,KAAK,iBAAiB,GAAG;AAC1C,UAAI;AACF,cAAM,YAAY,iBAAiB,IAAI;AAEvC,YAAI,WAAW,SAAS,SAAS,GAAG;AAClC,gBAAM,OAAO,KAAK,iBAAiB,IAAI;AACvC,cAAI,MAAM;AACR,uBAAW,IAAI,KAAK,IAAI,IAAI;AAC5B,iBAAK,eAAe,IAAI,KAAK,IAAI;cAC/B,IAAI,KAAK;cACT,OAAO,KAAK;cACZ,YAAY;cACZ,WAAW,KAAK;cAChB,OAAO;cACP,cAAc,KAAK,MAAM;cACzB,WAAW,KAAK;cAChB,WAAW,KAAK,gBAAgB,KAAK;YACvC,CAAC;UACH;QACF;MACF,QAAQ;MAER;IACF;AAGA,eAAW,QAAQ,KAAK,iBAAiB,GAAG;AAC1C,UAAI;AACF,cAAM,YAAY,iBAAiB,IAAI;AACvC,YAAI,CAAC,WAAW,IAAI,SAAS,GAAG;AAC9B,gBAAM,OAAO,KAAK,iBAAiB,IAAI;AACvC,cAAI,MAAM;AACR,uBAAW,IAAI,KAAK,IAAI,IAAI;AAC5B,iBAAK,eAAe,IAAI,KAAK,IAAI;cAC/B,IAAI,KAAK;cACT,OAAO,KAAK;cACZ,YAAY;cACZ,WAAW,KAAK;cAChB,OAAO;cACP,cAAc,KAAK,MAAM;cACzB,WAAW,KAAK;cAChB,WAAW,KAAK,gBAAgB,KAAK;YACvC,CAAC;UACH;QACF;MACF,QAAQ;MAER;IACF;AAEA,WAAO,MAAM,KAAK,WAAW,OAAO,CAAC;EACvC;EAEA,eAAe,WAAgC;AAC7C,UAAM,OAAO,KAAK,eAAe,IAAI,SAAS;AAC9C,QAAI,CAAC,KAAM,OAAM,IAAI,MAAM,sBAAsB,SAAS,EAAE;AAC5D,QAAI,CAACJ,YAAW,KAAK,UAAU,EAAG,OAAM,IAAI,MAAM,yBAAyB,KAAK,UAAU,EAAE;AAE5F,UAAM,UAAUC,cAAa,KAAK,YAAY,OAAO;AACrD,UAAM,WAAsB,CAAC;AAC7B,UAAM,mBAAmB,oBAAI,IAA8B;AAE3D,QAAI,mBAAmB;AACvB,QAAI,oBAAoB;AAGxB,QAAI,wBAAuC;AAC3C,QAAI,2BAA0C;AAC9C,QAAI,cAAkC;AAGtC,QAAI,sBAAsB;AAC1B,QAAI,YAAY;AAChB,QAAI,aAAa;AACjB,QAAI,aAAa;AACjB,QAAI,gBAAgB;AAEpB,eAAW,UAAU,gBAAgB,OAAO,GAAG;AAC7C,UAAI;AACF,cAAM,SAAS,KAAK;UAClB;UACA;UACA;UACA,KAAK;UACL;UACA;UACA;QACF;AACA,gCAAwB,OAAO;AAC/B,mCAA2B,OAAO;AAClC,sBAAc,OAAO;AAGrB,cAAM,aAAa,OAAO,OAAO,MAAM,KAAK,EAAE;AAC9C,YAAI,eAAe,aAAa;AAC9B,gBAAM,UAAW,OAAO,SAAS,KAAK,CAAC;AACvC,cAAI,OAAO,QAAQ,MAAM,KAAK,EAAE,MAAM,eAAe;AACnD,kBAAM,OAAO,QAAQ,MAAM;AAC3B,kBAAM,aAAa,OAAO,mBAAmB;AAC7C,kBAAM,kBAAkB,OAAO,aAAa,cAAc,KAAK,CAAC;AAEhE,gBAAI,kBAAkB,KAAK,oBAAoB,qBAAqB;YAEpE,OAAO;AACL,oCAAsB;AAEtB,oBAAM,YAAY,OAAO,kBAAkB;AAC3C,kBAAI,cAAc;AAClB,kBAAI,oBAAoB;AACxB,kBAAI,eAAe;AACnB,kBAAI,kBAAkB;AAEtB,kBAAI,WAAW;AACb,8BAAc,OAAO,UAAU,cAAc,KAAK,CAAC;AACnD,oCAAoB,OAAO,UAAU,qBAAqB,KAAK,CAAC;AAChE,+BAAe,OAAO,UAAU,eAAe,KAAK,CAAC;AACrD,kCAAkB,OAAO,UAAU,yBAAyB,KAAK,CAAC;cACpE,WAAW,kBAAkB,KAAK,YAAY;AAC5C,8BAAc,OAAO,WAAW,cAAc,KAAK,CAAC,IAAI;AACxD,oCAAoB,OAAO,WAAW,qBAAqB,KAAK,CAAC,IAAI;AACrE,+BAAe,OAAO,WAAW,eAAe,KAAK,CAAC,IAAI;AAC1D,kCACE,OAAO,WAAW,yBAAyB,KAAK,CAAC,IAAI;AAEvD,4BAAY,OAAO,WAAW,cAAc,KAAK,CAAC;AAClD,6BAAa,OAAO,WAAW,qBAAqB,KAAK,CAAC;AAC1D,6BAAa,OAAO,WAAW,eAAe,KAAK,CAAC;AACpD,gCAAgB,OAAO,WAAW,yBAAyB,KAAK,CAAC;cACnE;AAEA,oBAAM,gBAAgB,KAAK,IAAI,GAAG,cAAc,iBAAiB;AACjE,kBAAI,iBAAiB,gBAAgB,iBAAiB;AACpD,oCAAoB;AACpB,qCAAqB,eAAe;AAGpC,yBAAS,IAAI,SAAS,SAAS,GAAG,KAAK,GAAG,KAAK;AAC7C,wBAAM,MAAM,SAAS,CAAC;AACtB,sBAAI,IAAI,SAAS,eAAe,CAAC,IAAI,QAAQ;AAC3C,wBAAI,SAAS;sBACX,OAAO;sBACP,QAAQ,eAAe;oBACzB;AACA;kBACF;gBACF;cACF;YACF;UACF;QACF;MACF,QAAQ;MAER;IACF;AAGA,QAAI,eAAe,0BAA0B,MAAM;AACjD,eAAS,qBAAqB,EAAG,MAAM,KAAK,WAAW;IACzD;AAEA,WAAO;MACL,IAAI,KAAK;MACT,OAAO,KAAK;MACZ,MAAM,SAAS,KAAK,EAAE;MACtB,WAAW,KAAK;MAChB,cAAc,KAAK;MACnB,cAAc,KAAK;MACnB,OAAO;QACL,eAAe,SAAS;QACxB,oBAAoB;QACpB,qBAAqB;QACrB,YAAY;MACd;MACA;IACF;EACF;;EAIQ,mBAA6B;AACnC,QAAI,CAAC,KAAK,SAAU,QAAO,CAAC;AAC5B,QAAI;AACF,aAAO,KAAK,uBAAuB,KAAK,QAAQ;IAClD,QAAQ;AACN,aAAO,CAAC;IACV;EACF;EAEQ,uBAAuB,KAAuB;AACpD,UAAM,QAAkB,CAAC;AACzB,QAAI;AACF,iBAAW,SAASI,aAAY,GAAG,GAAG;AACpC,cAAM,WAAWH,MAAK,KAAK,KAAK;AAChC,cAAM,OAAOE,UAAS,QAAQ;AAC9B,YAAI,KAAK,YAAY,GAAG;AACtB,gBAAM,KAAK,GAAG,KAAK,uBAAuB,QAAQ,CAAC;QACrD,WAAW,MAAM,SAAS,QAAQ,KAAK,MAAM,WAAW,UAAU,GAAG;AACnE,gBAAM,KAAK,QAAQ;QACrB;MACF;IACF,QAAQ;IAER;AACA,WAAO;EACT;;EAIQ,mBAAyB;AAC/B,QAAI,KAAK,kBAAkB,OAAO,EAAG;AAErC,UAAM,QAAQ,qBAAqB;AACnC,UAAM,YAAYF,MAAK,MAAM,WAAW,qBAAqB;AAC7D,QAAI,CAACF,YAAW,SAAS,EAAG;AAE5B,QAAI;AACF,YAAM,UAAUC,cAAa,WAAW,OAAO;AAC/C,iBAAW,UAAU,gBAAgB,OAAO,GAAG;AAC7C,cAAM,MAAM,OAAO,OAAO,IAAI,KAAK,EAAE,EAAE,KAAK;AAC5C,cAAM,aAAa,OAAO,OAAO,aAAa,KAAK,EAAE,EAAE,KAAK;AAC5D,YAAI,OAAO,YAAY;AACrB,eAAK,kBAAkB,IAAI,KAAK,UAAU;QAC5C;MACF;IACF,QAAQ;IAER;EACF;EAEQ,mBAAmB,WAAkC;AAC3D,WAAO,KAAK,kBAAkB,IAAI,SAAS,KAAK;EAClD;;EAIQ,iBAAiB,UAAsC;AAC7D,UAAM,UAAUA,cAAa,UAAU,OAAO;AAC9C,UAAM,QAAQ,QAAQ,MAAM,IAAI,EAAE,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC;AACxD,QAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,UAAM,YAAY,iBAAiB,QAAQ;AAE3C,QAAI;AACJ,QAAI;AACF,oBAAc,KAAK,MAAM,MAAM,CAAC,CAAE;IACpC,QAAQ;AACN,aAAO;IACT;AAEA,UAAM,UAAW,YAAY,SAAS,KAAK,CAAC;AAC5C,UAAM,YAAYU,kBAAiB,OAAO,KAAKP,UAAS,QAAQ,EAAE;AAGlE,UAAM,aAAa,KAAK,mBAAmB,SAAS;AAEpD,UAAM,eAAe,KAAK,sBAAsB,KAAK;AACrD,UAAM,iBAAiB,cAAc,QAAQ,KAAK,IAAI,OAAO,QAAQ,KAAK,CAAC,IAAI,IAAI;AAEnF,UAAM,QAAQ,oBAAoB,YAAY,cAAc,cAAc;AAG1E,QAAI,YAAY;AAChB,QAAI,eAAe;AACnB,QAAI,QAAuB;AAC3B,QAAI,mBAAmB;AACvB,QAAI,oBAAoB;AAExB,QAAI,0BAA0B;AAC9B,QAAI,gBAAgB;AACpB,QAAI,iBAAiB;AACrB,QAAI,iBAAiB;AACrB,QAAI,oBAAoB;AAExB,UAAM,gBAAgB,oBAAI,IAAI,CAAC,WAAW,iBAAiB,sBAAsB,CAAC;AAElF,eAAW,QAAQ,OAAO;AACxB,UAAI;AACF,cAAM,OAAO,KAAK,MAAM,IAAI;AAC5B,cAAM,aAAa,OAAO,KAAK,MAAM,KAAK,EAAE;AAC5C,YAAI,eAAe,gBAAgB;AACjC,gBAAM,IAAK,KAAK,SAAS,KAAK,CAAC;AAC/B,gBAAM,KAAKO,kBAAiB,CAAC;AAC7B,cAAI,KAAK,UAAW,aAAY;AAChC;QACF;AAEA,YAAI,eAAe,iBAAiB;AAClC,gBAAM,IAAK,KAAK,SAAS,KAAK,CAAC;AAC/B,gBAAM,QAAQ,OAAO,EAAE,MAAM,KAAK,EAAE;AACpC,cAAI,cAAc,IAAI,KAAK,GAAG;AAC5B;UACF;AAEA,cAAI,CAAC,OAAO;AACV,kBAAM,OAAO,EAAE,MAAM;AACrB,kBAAM,IAAI,OAAO,OAAO,KAAK,EAAE,OAAO;AACtC,gBAAI,OAAO,MAAM,YAAY,EAAE,KAAK,EAAG,SAAQ,EAAE,KAAK;UACxD;QACF;AAEA,YAAI,eAAe,aAAa;AAC9B,gBAAM,IAAK,KAAK,SAAS,KAAK,CAAC;AAC/B,cAAI,OAAO,EAAE,MAAM,KAAK,EAAE,MAAM,eAAe;AAC7C,kBAAM,OAAO,EAAE,MAAM;AACrB,kBAAM,aAAa,OAAO,mBAAmB;AAC7C,kBAAM,kBAAkB,OAAO,aAAa,cAAc,KAAK,CAAC;AAEhE,gBAAI,kBAAkB,KAAK,oBAAoB,yBAAyB;AACtE,wCAA0B;AAE1B,oBAAM,YAAY,OAAO,kBAAkB;AAC3C,kBAAI,cAAc;AAClB,kBAAI,oBAAoB;AACxB,kBAAI,eAAe;AACnB,kBAAI,kBAAkB;AAEtB,kBAAI,WAAW;AACb,8BAAc,OAAO,UAAU,cAAc,KAAK,CAAC;AACnD,oCAAoB,OAAO,UAAU,qBAAqB,KAAK,CAAC;AAChE,+BAAe,OAAO,UAAU,eAAe,KAAK,CAAC;AACrD,kCAAkB,OAAO,UAAU,yBAAyB,KAAK,CAAC;cACpE,WAAW,kBAAkB,KAAK,YAAY;AAC5C,8BAAc,OAAO,WAAW,cAAc,KAAK,CAAC,IAAI;AACxD,oCAAoB,OAAO,WAAW,qBAAqB,KAAK,CAAC,IAAI;AACrE,+BAAe,OAAO,WAAW,eAAe,KAAK,CAAC,IAAI;AAC1D,kCACE,OAAO,WAAW,yBAAyB,KAAK,CAAC,IAAI;AAEvD,gCAAgB,OAAO,WAAW,cAAc,KAAK,CAAC;AACtD,iCAAiB,OAAO,WAAW,qBAAqB,KAAK,CAAC;AAC9D,iCAAiB,OAAO,WAAW,eAAe,KAAK,CAAC;AACxD,oCAAoB,OAAO,WAAW,yBAAyB,KAAK,CAAC;cACvE;AAEA,oBAAM,gBAAgB,KAAK,IAAI,GAAG,cAAc,iBAAiB;AACjE,kCAAoB;AACpB,mCAAqB,eAAe;YACtC;UACF;QACF;MACF,QAAQ;MAER;IACF;AAEA,UAAM,YAAY,QAAQ,KAAK,IAAI,OAAO,QAAQ,KAAK,CAAC,IAAI;AAE5D,WAAO;MACL,IAAI;MACJ,MAAM,SAAS,SAAS;MACxB;MACA;MACA,cAAc;MACd,cAAc;MACd,OAAO;QACL,eAAe;QACf,oBAAoB;QACpB,qBAAqB;QACrB,YAAY;MACd;IACF;EACF;EAEQ,sBAAsB,OAAgC;AAC5D,QAAI,mBAAmB;AACvB,eAAW,QAAQ,MAAM,MAAM,GAAG,EAAE,GAAG;AACrC,UAAI;AACF,cAAM,OAAO,KAAK,MAAM,IAAI;AAC5B,cAAM,aAAa,OAAO,KAAK,MAAM,KAAK,EAAE;AAC5C,YAAI,eAAe,gBAAiB;AAEpC,cAAM,UAAW,KAAK,SAAS,KAAK,CAAC;AACrC,cAAM,QAAQ,OAAO,QAAQ,MAAM,KAAK,EAAE;AAC1C,YAAI,UAAU,UAAW;AACzB,YAAI,OAAO,QAAQ,MAAM,KAAK,EAAE,MAAM,OAAQ;AAG9C;AACA,YAAI,mBAAmB,EAAG;AAE1B,cAAM,UAAU,QAAQ,SAAS;AACjC,YAAI,MAAM,QAAQ,OAAO,GAAG;AAC1B,gBAAM,QAAQ,QACX,OAAO,CAAC,SAAS,OAAO,SAAS,YAAY,SAAS,QAAQ,UAAU,IAAI,EAC5E,IAAI,CAAC,SAAS,OAAQ,KAAiC,MAAM,KAAK,EAAE,CAAC,EACrE,KAAK,GAAG;AACX,iBAAOJ,oBAAmB,KAAK;QACjC;AACA,YAAI,OAAO,YAAY,UAAU;AAC/B,iBAAOA,oBAAmB,OAAO;QACnC;MACF,QAAQ;MAER;IACF;AACA,WAAO;EACT;;EAIQ,cACN,MACA,UACA,kBACA,WACA,uBACA,0BACA,aAKA;AACA,UAAM,aAAa,OAAO,KAAK,MAAM,KAAK,EAAE;AAG5C,QAAI,eAAe,kBAAkB,eAAe,aAAa;AAC/D,aAAO,EAAE,uBAAuB,0BAA0B,YAAY;IACxE;AAEA,QAAI,eAAe,iBAAiB;AAClC,aAAO,EAAE,uBAAuB,0BAA0B,YAAY;IACxE;AAEA,UAAM,UAAW,KAAK,SAAS,KAAK,CAAC;AACrC,UAAM,cAAc,OAAO,QAAQ,MAAM,KAAK,EAAE;AAChD,UAAM,cAAcI,kBAAiB,IAAI,KAAKA,kBAAiB,OAAO;AAEtE,YAAQ,aAAa;MACnB,KAAK,WAAW;AACd,cAAM,OAAO,OAAO,QAAQ,MAAM,KAAK,EAAE;AACzC,YAAI,SAAS,aAAa;AACxB,iBAAO,KAAK;YACV;YACA;YACA;YACA;YACA;YACA;UACF;QACF;AACA,YAAI,SAAS,QAAQ;AACnB,iBAAO,KAAK;YACV;YACA;YACA;YACA;YACA;YACA;UACF;QACF;AACA;MACF;MAEA,KAAK;AACH,eAAO,KAAK,iBAAiB,SAAS,UAAU,aAAa,qBAAqB;MAEpF,KAAK;AACH,eAAO,KAAK;UACV;UACA;UACA;UACA;UACA;UACA;QACF;MAEF,KAAK;AACH,aAAK,0BAA0B,SAAS,UAAU,kBAAkB,WAAW;AAC/E,eAAO,EAAE,uBAAuB,0BAA0B,YAAY;MAExE,KAAK;AACH,eAAO,KAAK;UACV;UACA;UACA;UACA;UACA;UACA;QACF;MAEF,KAAK;AACH,aAAK,4BAA4B,SAAS,UAAU,kBAAkB,WAAW;AACjF,eAAO,EAAE,uBAAuB,0BAA0B,YAAY;IAC1E;AAEA,WAAO,EAAE,uBAAuB,0BAA0B,YAAY;EACxE;;EAIQ,wBACN,SACA,UACA,aACA,uBACA,0BACA,aAKA;AACA,UAAM,UAAU,QAAQ,SAAS;AACjC,QAAI,CAAC,MAAM,QAAQ,OAAO,GAAG;AAC3B,aAAO,EAAE,uBAAuB,0BAA0B,YAAY;IACxE;AAGA,UAAM,YAAsB,CAAC;AAC7B,eAAW,QAAQ,SAAS;AAC1B,UAAI,OAAO,SAAS,YAAY,SAAS,KAAM;AAC/C,YAAM,KAAK;AACX,UAAI,OAAO,GAAG,MAAM,KAAK,EAAE,MAAM,eAAe;AAC9C,cAAM,OAAO,OAAO,GAAG,MAAM,KAAK,EAAE;AACpC,YAAI,KAAK,KAAK,EAAG,WAAU,KAAK,IAAI;MACtC;IACF;AAEA,QAAI,UAAU,WAAW,GAAG;AAC1B,aAAO,EAAE,uBAAuB,0BAA0B,YAAY;IACxE;AAEA,UAAM,WAAW,UAAU,KAAK,IAAI;AAGpC,UAAM,YAAY,SAAS,MAAM,qBAAqB;AACtD,QAAI,WAAW;AACb,YAAM,WAAW,UAAU,CAAC,EAAG,KAAK;AACpC,YAAM,WAAwB;QAC5B,MAAM;QACN,MAAM;QACN,iBAAiB;QACjB,cAAc;MAChB;AACA,oBAAc;IAChB;AAGA,UAAM,cAAc,SAAS,QAAQ,uBAAuB,EAAE,EAAE,KAAK;AACrE,QAAI,CAAC,aAAa;AAChB,aAAO,EAAE,uBAAuB,0BAA0B,YAAY;IACxE;AAEA,UAAM,WAAwB,EAAE,MAAM,QAAQ,MAAM,aAAa,cAAc,YAAY;AAG3F,QAAI,0BAA0B,MAAM;AAClC,YAAM,UAAU,SAAS,qBAAqB;AAC9C,YAAM,UAAU,QAAQ,MAAM,KAAK,CAAC,MAAM,EAAE,SAAS,MAAM;AAC3D,UAAI,CAAC,SAAS;AACZ,gBAAQ,MAAM,KAAK,QAAQ;AAC3B,mCAA2B;AAC3B,eAAO,EAAE,uBAAuB,0BAA0B,YAAY;MACxE;IACF;AAEA,aAAS;MACP,KAAK,aAAa;QAChB,WAAW;QACX,MAAM;QACN;QACA,OAAO,CAAC,QAAQ;QAChB,OAAO;MACT,CAAC;IACH;AACA,4BAAwB,SAAS,SAAS;AAC1C,+BAA2B;AAE3B,WAAO,EAAE,uBAAuB,0BAA0B,YAAY;EACxE;;EAIQ,mBACN,SACA,UACA,aACA,uBACA,0BACA,aAKA;AACA,UAAM,UAAU,QAAQ,SAAS;AACjC,UAAM,OAAO,MAAM,QAAQ,OAAO,IAC9B,QACG;MAAI,CAAC,MACJ,OAAO,MAAM,YAAY,MAAM,OAC3B,OAAQ,EAA8B,MAAM,KAAK,EAAE,IACnD,OAAO,KAAK,EAAE;IACpB,EACC,KAAK,GAAG,IACX,OAAO,WAAW,EAAE;AAExB,QAAI,CAAC,KAAK,KAAK,GAAG;AAChB,aAAO,EAAE,uBAAuB,0BAA0B,YAAY;IACxE;AAGA,QAAI,2BAA2B,IAAI,GAAG;AACpC,aAAO,EAAE,uBAAuB,0BAA0B,YAAY;IACxE;AAGA,QAAI,KAAK,UAAU,EAAE,WAAW,oBAAoB,GAAG;AAErD,UAAI,eAAe,0BAA0B,MAAM;AACjD,iBAAS,qBAAqB,EAAG,MAAM,KAAK,WAAW;MACzD;AACA,oBAAc;AAGd,eAAS;QACP,KAAK,aAAa;UAChB,WAAW;UACX,MAAM;UACN;UACA,OAAO,CAAC,EAAE,MAAM,QAAQ,MAAM,KAAK,KAAK,GAAG,cAAc,YAAY,CAAC;QACxE,CAAC;MACH;AAEA,8BAAwB;AACxB,iCAA2B;AAC3B,aAAO,EAAE,uBAAuB,0BAA0B,YAAY;IACxE;AAGA,UAAM,gBAAgB,KAAK,MAAM,6BAA6B;AAC9D,QAAI,eAAe;AACjB,UAAI;AACF,cAAM,eAAe,KAAK,MAAM,cAAc,CAAC,CAAE;AACjD,cAAM,UAAU,OAAO,aAAa,UAAU,KAAK,EAAE;AACrD,cAAM,WAAW,OAAO,aAAa,UAAU,KAAK,EAAE;AACtD,cAAM,gBAAgB,OAAO,aAAa,WAAW,KAAK,EAAE;AAG5D,cAAM,WAAwB;UAC5B,MAAM;UACN,MAAM,iBAAiB,YAAY,QAAQ;UAC3C,cAAc;QAChB;AAEA,iBAAS;UACP,KAAK,aAAa;YAChB,WAAW;YACX,MAAM;YACN;YACA,OAAO,CAAC,QAAQ;YAChB,OAAO;YACP,aAAa,WAAW;YACxB,UAAU,YAAY;UACxB,CAAC;QACH;AAEA,gCAAwB;AACxB,mCAA2B;AAC3B,eAAO,EAAE,uBAAuB,0BAA0B,YAAY;MACxE,QAAQ;MAER;IACF;AAGA,aAAS;MACP,KAAK,aAAa;QAChB,WAAW;QACX,MAAM;QACN;QACA,OAAO,CAAC,EAAE,MAAM,QAAQ,MAAM,KAAK,KAAK,GAAG,cAAc,YAAY,CAAC;MACxE,CAAC;IACH;AAEA,4BAAwB;AACxB,+BAA2B;AAC3B,WAAO,EAAE,uBAAuB,0BAA0B,YAAY;EACxE;;EAIQ,iBACN,SACA,UACA,aACA,uBAKA;AACA,UAAM,UAAU,QAAQ,SAAS;AACjC,QAAI,CAAC,MAAM,QAAQ,OAAO,GAAG;AAC3B,aAAO,EAAE,uBAAuB,0BAA0B,MAAM,aAAa,KAAK;IACpF;AAEA,UAAM,QAAkB,CAAC;AACzB,eAAW,QAAQ,SAAS;AAC1B,UAAI,OAAO,SAAS,YAAY,SAAS,MAAM;AAC7C,cAAM,KAAK;AACX,YAAI,OAAO,GAAG,MAAM,KAAK,EAAE,MAAM,gBAAgB;AAC/C,gBAAM,OAAO,OAAO,GAAG,MAAM,KAAK,EAAE;AACpC,cAAI,KAAK,KAAK,EAAG,OAAM,KAAK,IAAI;QAClC;MACF;IACF;AAEA,QAAI,MAAM,WAAW,GAAG;AACtB,aAAO,EAAE,uBAAuB,0BAA0B,MAAM,aAAa,KAAK;IACpF;AAEA,UAAM,gBAAgB,MAAM,KAAK,IAAI;AACrC,UAAM,OAAoB,EAAE,MAAM,aAAa,MAAM,eAAe,cAAc,YAAY;AAE9F,QAAI,0BAA0B,MAAM;AAClC,YAAM,UAAU,SAAS,qBAAqB;AAC9C,YAAM,UAAU,QAAQ,MAAM,KAAK,CAAC,MAAM,EAAE,SAAS,MAAM;AAC3D,YAAM,UAAU,QAAQ,MAAM,KAAK,CAAC,MAAM,EAAE,SAAS,MAAM;AAC3D,UAAI,CAAC,WAAW,CAAC,SAAS;AACxB,gBAAQ,MAAM,KAAK,IAAI;AACvB,eAAO,EAAE,uBAAuB,0BAA0B,MAAM,aAAa,KAAK;MACpF;IACF;AAEA,aAAS;MACP,KAAK,aAAa;QAChB,WAAW;QACX,MAAM;QACN;QACA,OAAO,CAAC,IAAI;QACZ,OAAO;MACT,CAAC;IACH;AAEA,WAAO;MACL,uBAAuB,SAAS,SAAS;MACzC,0BAA0B;MAC1B,aAAa;IACf;EACF;;EAIQ,oBACN,SACA,UACA,kBACA,aACA,uBACA,0BAKA;AACA,UAAM,SAAS,OAAO,QAAQ,SAAS,KAAK,EAAE,EAAE,KAAK;AACrD,UAAM,OAAO,OAAO,QAAQ,MAAM,KAAK,EAAE,EAAE,KAAK;AAChD,QAAI,CAAC,MAAM;AACT,aAAO,EAAE,uBAAuB,0BAA0B,aAAa,KAAK;IAC9E;AAEA,UAAM,aAAaC,cAAa,IAAI;AACpC,UAAM,aAAaC,wBAAuB,QAAQ,WAAW,CAAC;AAE9D,UAAM,WAAwB;MAC5B,MAAM;MACN,MAAM;MACN,QAAQ;MACR,OAAO,SAAS,UAAU;MAC1B,OAAO;QACL,WAAW;QACX,QAAQ;MACV;MACA,cAAc;IAChB;AAGA,UAAM,cAAc,4BAA4B;AAChD,QAAI,gBAAgB,MAAM;AACxB,YAAM,UAAU,SAAS,WAAW;AACpC,YAAM,YAAY,QAAQ,MAAM;AAChC,cAAQ,MAAM,KAAK,QAAQ;AAC3B,cAAQ,OAAO;AACf,UAAI,QAAQ;AACV,yBAAiB,IAAI,QAAQ,CAAC,aAAa,SAAS,CAAC;MACvD;AACA,aAAO;QACL,uBAAuB;QACvB,0BAA0B;QAC1B,aAAa;MACf;IACF;AAGA,aAAS;MACP,KAAK,aAAa;QAChB,WAAW;QACX,MAAM;QACN;QACA,OAAO,CAAC,QAAQ;QAChB,OAAO;QACP,MAAM;MACR,CAAC;IACH;AACA,UAAM,WAAW,SAAS,SAAS;AACnC,QAAI,QAAQ;AACV,uBAAiB,IAAI,QAAQ,CAAC,UAAU,CAAC,CAAC;IAC5C;AAEA,WAAO,EAAE,uBAAuB,UAAU,0BAA0B,MAAM,aAAa,KAAK;EAC9F;;EAIQ,0BACN,SACA,UACA,kBACA,aACM;AACN,UAAM,SAAS,OAAO,QAAQ,SAAS,KAAK,EAAE,EAAE,KAAK;AACrD,QAAI,CAAC,OAAQ;AAEb,UAAM,WAAW,iBAAiB,IAAI,MAAM;AAC5C,QAAI,CAAC,SAAU;AAEf,UAAM,aAAa,OAAO,QAAQ,QAAQ,KAAK,EAAE;AACjD,UAAM,cAA6B,WAAW,KAAK,IAC/C,CAAC,EAAE,MAAM,QAAQ,MAAM,YAAY,cAAc,YAAY,CAAC,IAC9D,CAAC;AAEL,UAAM,CAAC,UAAU,SAAS,IAAI;AAC9B,UAAM,QACJ,SAAS,QAAQ,EAAG,MAAM,SAAS,EAAG,UACrC,SAAS,QAAQ,EAAG,MAAM,SAAS,EAAG,QAAQ,CAAC;AAElD,QAAI,YAAY,SAAS,GAAG;AAC1B,YAAM,SAAS,CAAC,GAAG,WAAW;AAC9B,YAAM,SAAS;IACjB;EACF;;EAIQ,sBACN,SACA,UACA,kBACA,aACA,uBACA,0BAKA;AACA,UAAM,SAAS,OAAO,QAAQ,SAAS,KAAK,EAAE,EAAE,KAAK;AACrD,UAAM,OAAO,OAAO,QAAQ,MAAM,KAAK,EAAE,EAAE,KAAK;AAChD,QAAI,CAAC,MAAM;AACT,aAAO,EAAE,uBAAuB,0BAA0B,aAAa,KAAK;IAC9E;AAEA,UAAM,aAAaD,cAAa,IAAI;AACpC,UAAM,WAAW,QAAQ,OAAO;AAChC,UAAM,kBAAkB,6BAA6B,MAAM,QAAQ;AAEnE,UAAM,WAAwB;MAC5B,MAAM;MACN,MAAM;MACN,QAAQ;MACR,OAAO,SAAS,UAAU;MAC1B,OAAO;QACL,WAAW;QACX,QAAQ;MACV;MACA,cAAc;IAChB;AAGA,UAAM,cAAc,4BAA4B;AAChD,QAAI,gBAAgB,MAAM;AACxB,YAAM,UAAU,SAAS,WAAW;AACpC,YAAM,YAAY,QAAQ,MAAM;AAChC,cAAQ,MAAM,KAAK,QAAQ;AAC3B,cAAQ,OAAO;AACf,UAAI,QAAQ;AACV,yBAAiB,IAAI,QAAQ,CAAC,aAAa,SAAS,CAAC;MACvD;AACA,aAAO;QACL,uBAAuB;QACvB,0BAA0B;QAC1B,aAAa;MACf;IACF;AAGA,aAAS;MACP,KAAK,aAAa;QAChB,WAAW;QACX,MAAM;QACN;QACA,OAAO,CAAC,QAAQ;QAChB,OAAO;QACP,MAAM;MACR,CAAC;IACH;AACA,UAAM,WAAW,SAAS,SAAS;AACnC,QAAI,QAAQ;AACV,uBAAiB,IAAI,QAAQ,CAAC,UAAU,CAAC,CAAC;IAC5C;AAEA,WAAO,EAAE,uBAAuB,UAAU,0BAA0B,MAAM,aAAa,KAAK;EAC9F;;EAIQ,4BACN,SACA,UACA,kBACA,aACM;AACN,UAAM,SAAS,OAAO,QAAQ,SAAS,KAAK,EAAE,EAAE,KAAK;AACrD,QAAI,CAAC,OAAQ;AAEb,UAAM,WAAW,iBAAiB,IAAI,MAAM;AAC5C,QAAI,CAAC,SAAU;AAEf,UAAM,aAAa,OAAO,QAAQ,QAAQ,KAAK,EAAE;AACjD,UAAM,cAA6B,WAAW,KAAK,IAC/C,CAAC,EAAE,MAAM,QAAQ,MAAM,YAAY,cAAc,YAAY,CAAC,IAC9D,CAAC;AAEL,UAAM,CAAC,UAAU,SAAS,IAAI;AAC9B,UAAM,QACJ,SAAS,QAAQ,EAAG,MAAM,SAAS,EAAG,UACrC,SAAS,QAAQ,EAAG,MAAM,SAAS,EAAG,QAAQ,CAAC;AAElD,QAAI,YAAY,SAAS,GAAG;AAC1B,YAAM,SAAS,CAAC,GAAG,WAAW;AAC9B,YAAM,SAAS;IACjB;EACF;;EAIQ,aAAa,MAaT;AACV,WAAO;MACL,IAAI,KAAK;MACT,MAAM,KAAK;MACX,OAAO,KAAK,SAAS;MACrB,cAAc,KAAK;MACnB,MAAM,KAAK,QAAQ;MACnB,OAAO,KAAK,SAAS;MACrB,UAAU,KAAK,YAAY;MAC3B,QAAQ,KAAK,SAAU,KAAK,SAA+B;MAC3D,MAAM,KAAK,QAAQ;MACnB,OAAO,KAAK;MACZ,aAAa,KAAK;MAClB,UAAU,KAAK;IACjB;EACF;AACF;AC9tCA,IAAM,wBAAgD;EACpD,cAAc;EACd,cAAc;EACd,yBAAyB;EACzB,oBAAoB;EACpB,kBAAkB;AACpB;AAEA,SAASA,cAAa,UAA0B;AAC9C,SAAO,sBAAsB,QAAQ,KAAK;AAC5C;AAGA,SAASE,0BAAyB,QAAiB,aAAoC;AACrF,MAAI,UAAU,KAAM,QAAO,CAAC;AAE5B,MAAI,OAAO,WAAW,UAAU;AAC9B,WAAO,OAAO,KAAK,IACf,CAAC,EAAE,MAAM,QAAiB,MAAM,QAAQ,cAAc,YAAY,CAAC,IACnE,CAAC;EACP;AAEA,MAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,UAAM,QAAuB,CAAC;AAC9B,eAAW,QAAQ,QAAQ;AACzB,UAAI,OAAO,SAAS,YAAY,SAAS,MAAM;AAC7C,cAAML,QAAO;UACV,KAAiC,QAAS,KAAiC,WAAW;QACzF;AACA,YAAIA,MAAK,KAAK,EAAG,OAAM,KAAK,EAAE,MAAM,QAAQ,MAAAA,OAAM,cAAc,YAAY,CAAC;MAC/E,WAAW,OAAO,SAAS,YAAY,KAAK,KAAK,GAAG;AAClD,cAAM,KAAK,EAAE,MAAM,QAAQ,MAAM,MAAM,cAAc,YAAY,CAAC;MACpE;IACF;AACA,WAAO;EACT;AAGA,QAAM,OAAO,OAAO,MAAM;AAC1B,SAAO,KAAK,KAAK,IAAI,CAAC,EAAE,MAAM,QAAQ,MAAM,cAAc,YAAY,CAAC,IAAI,CAAC;AAC9E;AAGA,SAAS,iBAAiB,KAA0B;AAClD,MAAI,IAAI,aAAa,OAAO,IAAI,cAAc,YAAY,IAAI,YAAY,GAAG;AAC3E,WAAO,IAAI;EACb;AACA,MAAI,IAAI,aAAa,OAAO,IAAI,cAAc,YAAY,IAAI,YAAY,GAAG;AAC3E,WAAO,IAAI;EACb;AACA,SAAO;AACT;AAGA,SAAS,eAAe,QAA2C;AACjE,QAAM,QAA8B,CAAC;AAGrC,MAAI,OAAO,OAAO;AAChB,UAAM,QAAQ,OAAO;EACvB;AAGA,MAAI,OAAO,UAAU,MAAM;AACzB,UAAM,KAAK;AACX,UAAM,cAAcK,0BAAyB,OAAO,QAAQ,EAAE;AAC9D,UAAM,SAAS,YAAY,SAAS,IAAI,cAAc,OAAO;EAC/D;AAGA,MAAI,OAAO,OAAO;AAChB,WAAO,OAAO,OAAO,OAAO,KAAK;EACnC;AAGA,MAAI,CAAC,MAAM,QAAQ;AACjB,QAAI,OAAO,OAAO,WAAW,YAAY,OAAO,WAAW,MAAM;AAC/D,YAAM,MAAM,OAAO;AACnB,UAAI,IAAI,YAAY,KAAM,OAAM,SAAS;eAChC,IAAI,YAAY,MAAO,OAAM,SAAS;UAC1C,OAAM,SAAS;IACtB,WAAW,OAAO,UAAU,MAAM;AAChC,YAAM,SAAS;IACjB;EACF;AAEA,SAAO;AACT;AAGA,SAAS,cAAc,QAAqB,aAAkC;AAC5E,QAAM,WAAW,OAAO,QAAQ;AAChC,SAAO;IACL,MAAM;IACN,MAAMF,cAAa,QAAQ;IAC3B,QAAQ,OAAO,OAAO,GAAG,OAAO,IAAI,IAAI,OAAO,OAAO,OAAO,MAAM,EAAE,CAAC,KAAK;IAC3E,OAAO,SAASA,cAAa,QAAQ,CAAC;IACtC,OAAO,eAAe,MAAM;IAC5B,cAAc;EAChB;AACF;AAGA,SAAS,sBAAsB,QAAqB,aAAkC;AACpF,QAAM,UAAU,OAAO,OAAO,OAAO,WAAW,EAAE;AAClD,QAAM,cAAc,OAAO,OAAO,OAAO,sBAAsB,EAAE;AAEjE,SAAO;IACL,MAAM;IACN,MAAM;IACN,QAAQ;IACR,OAAO,eAAe,SAAS,QAAQ,MAAM,GAAG,EAAE,CAAC;IACnD,OAAO;MACL,OAAO,EAAE,QAAQ;MACjB,QACE,OAAO,OAAO,WAAW,WACrB,CAAC,EAAE,MAAM,QAAiB,MAAM,OAAO,QAAQ,cAAc,YAAY,CAAC,IAC1EE,0BAAyB,OAAO,QAAQ,WAAW;IAC3D;IACA,cAAc;EAChB;AACF;AAGA,SAAS,oBAAoB,QAAqB,aAAyC;AACzF,QAAM,WAAW,OAAO,QAAQ;AAGhC,MAAI,aAAa,2BAA2B;AAC1C,WAAO,sBAAsB,QAAQ,WAAW;EAClD;AAGA,MAAI,YAAY,OAAO,SAAS,QAAQ;AACtC,WAAO,cAAc,QAAQ,WAAW;EAC1C;AAEA,SAAO;AACT;AAMO,IAAM,cAAN,cAA0B,UAAU;EAChC,OAAO;EACP,cAAc;EAEf,SAAwB;;EAGxB,gBAAgB,oBAAI,IAA0B;;EAG9C,iBAAiB,oBAAI,IAAgD;EAErE,aAA4B;AAClC,QAAI,CAAC,kBAAkB,EAAG,QAAO;AACjC,UAAM,WAAW,kBAAkB;AACnC,QAAI,CAAC,SAAU,QAAO;AACtB,WAAOZ,MAAK,UAAU,iBAAiB,aAAa;EACtD;;;;;EAMQ,wBAA6C;AACnD,UAAM,MAAM,oBAAI,IAAoB;AACpC,UAAM,WAAW,kBAAkB;AACnC,QAAI,CAAC,SAAU,QAAO;AAEtB,UAAM,gBAAgBA,MAAK,UAAU,kBAAkB;AACvD,QAAI,CAACF,YAAW,aAAa,EAAG,QAAO;AAEvC,QAAI;AACJ,QAAI;AACF,mBAAaK,aAAY,aAAa;IACxC,QAAQ;AACN,aAAO;IACT;AAEA,eAAW,QAAQ,YAAY;AAC7B,YAAM,QAAQH,MAAK,eAAe,IAAI;AACtC,UAAI;AACF,YAAI,CAACE,UAAS,KAAK,EAAE,YAAY,EAAG;MACtC,QAAQ;AACN;MACF;AACA,YAAM,aAAaF,MAAK,OAAO,gBAAgB;AAC/C,UAAI,CAACF,YAAW,UAAU,EAAG;AAG7B,UAAI;AACJ,UAAI;AACF,cAAM,OAAO,KAAK,MAAMC,cAAa,YAAY,OAAO,CAAC;AAIzD,cAAM,MAAM,KAAK,UAAU,KAAK,aAAa;AAC7C,YAAI,CAAC,IAAK;AACV,wBAAgB,UAAU,mBAAmB,IAAI,QAAQ,cAAc,EAAE,CAAC,CAAC;MAC7E,QAAQ;AACN;MACF;AAGA,YAAM,WAAWC,MAAK,OAAO,aAAa;AAC1C,UAAI,CAACF,YAAW,QAAQ,EAAG;AAE3B,YAAM,OAAO,eAAe,QAAQ;AACpC,UAAI,CAAC,KAAM;AAEX,UAAI;AACF,cAAM,MAAM,KACT,QAAQ,iEAAiE,EACzE,IAAI;AACP,YAAI,CAAC,KAAK,MAAO;AAEjB,cAAM,SAAS,KAAK,MAAM,IAAI,KAAK;AACnC,YAAI;AAEJ,YACE,WAAW,QACX,OAAO,WAAW,YAClB,kBAAmB,UACnB,MAAM,QAAS,OAAmC,cAAc,CAAC,GACjE;AACA,sBAAa,OACV;QACL,WAAW,MAAM,QAAQ,MAAM,GAAG;AAChC,sBAAY;QACd,OAAO;AACL;QACF;AAEA,mBAAW,KAAK,WAAW;AACzB,gBAAM,KAAK,EAAE,cAAc,EAAE;AAC7B,cAAI,GAAI,KAAI,IAAI,IAAI,aAAa;QACnC;MACF,QAAQ;MAER,UAAA;AACE,aAAK,MAAM;MACb;IACF;AAEA,WAAO;EACT;EAEA,cAAuB;AACrB,SAAK,SAAS,KAAK,WAAW;AAC9B,WAAO,KAAK,WAAW,QAAQA,YAAW,KAAK,MAAM;EACvD;EAEA,OAAsB;AACpB,QAAI,CAAC,KAAK,OAAQ,QAAO,CAAC;AAE1B,UAAM,aAAa,KAAK,MAAM,aAAa;AAE3C,UAAM,WAAW,KAAK,MAAM,cAAc;AAC1C,UAAM,KAAK,KAAK,aAAa;AAC7B,SAAK,IAAI,QAAQ;AAEjB,QAAI,CAAC,GAAI,QAAO,CAAC;AAGjB,UAAM,WAAW,KAAK,MAAM,uBAAuB;AACnD,UAAM,mBAAmB,KAAK,sBAAsB;AACpD,SAAK,IAAI,QAAQ;AAEjB,QAAI;AACF,YAAM,OAAO,GACV,QAAQ,qEAAqE,EAC7E,IAAI;AAEP,YAAM,QAAuB,CAAC;AAE9B,iBAAW,OAAO,MAAM;AACtB,YAAI;AACF,gBAAM,WAAW,KAAK,MAAM,IAAI,KAAK;AACrC,cAAI,CAAC,SAAS,MAAM,CAAC,SAAS,WAAY;AAE1C,gBAAM,aAAa,SAAS,MAAM,SAAS,cAAc;AAGzD,gBAAM,YAAY,KAAK,4BAA4B,IAAI,UAAU;AACjE,gBAAM,YAAY,aAAa;AAE/B,gBAAM,QAAQ,KAAK,aAAa,QAAQ;AACxC,gBAAM,YAAY,SAAS,aAAa;AACxC,gBAAM,YAAY,SAAS,aAAa;AAGxC,gBAAM,WAAW,KAAK,wBAAwB,IAAI,YAAY,SAAS;AACvE,gBAAM,eACJ,MAAM,QAAQ,SAAS,aAAa,KAAK,SAAS,cAAc,SAAS;AAC3E,cAAI,SAAS,WAAW,KAAK,CAAC,cAAc;AAC1C;UACF;AACA,gBAAM,eAAe,SAAS;AAE9B,gBAAM,YAAY,iBAAiB,IAAI,UAAU,KAAK;AAEtD,gBAAM,KAAK;YACT,IAAI;YACJ,MAAM,UAAU,SAAS;YACzB;YACA;YACA,cAAc;YACd,cAAc,aAAa;YAC3B,OAAO;cACL,eAAe;cACf,oBAAoB,SAAS,mBAAmB;cAChD,qBAAqB,SAAS,oBAAoB;cAClD,YAAY;YACd;UACF,CAAC;AAGD,eAAK,cAAc,IAAI,WAAW,QAAQ;AAE1C,eAAK,cAAc,IAAI,cAAc,UAAU,IAAI;YACjD;UACF,CAA4B;AAC5B,cAAI,WAAW;AACb,iBAAK,cAAc,IAAI,UAAU,UAAU,IAAI;cAC7C;YACF,CAA4B;UAC9B;AAGA,eAAK,eAAe,IAAI,WAAW;YACjC,IAAI;YACJ,YAAY,KAAK,UAAU;UAC7B,CAAC;QACH,QAAQ;QAER;MACF;AAEA,WAAK,IAAI,UAAU;AACnB,aAAO;IACT,QAAQ;AACN,aAAO,CAAC;IACV,UAAA;AACE,SAAG,MAAM;IACX;EACF;EAEA,oBAAmD;AACjD,WAAO,KAAK;EACd;EAEA,kBAAkB,MAA2C;AAC3D,SAAK,iBAAiB;EACxB;;;;;EAMA,gBAAgB,gBAAwB,gBAAkD;AACxF,QAAI,CAAC,KAAK,QAAQ;AAChB,WAAK,SAAS,KAAK,WAAW;IAChC;AACA,QAAI,CAAC,KAAK,UAAU,CAACA,YAAW,KAAK,MAAM,GAAG;AAC5C,aAAO,EAAE,YAAY,OAAO,WAAW,KAAK,IAAI,EAAE;IACpD;AAEA,QAAI;AAEF,YAAM,OAAOI,UAAS,KAAK,MAAM;AACjC,YAAM,aAAa,KAAK,UAAU;AAIlC,YAAM,aAAa,aAAa,eAAe,IAAI,CAAC,MAAM,EAAE,EAAE,IAAI,CAAC;AAEnE,aAAO;QACL;QACA;QACA,WAAW,KAAK,IAAI;MACtB;IACF,QAAQ;AACN,aAAO,EAAE,YAAY,OAAO,WAAW,KAAK,IAAI,EAAE;IACpD;EACF;;;;EAKA,gBAAgB,iBAAgC,aAAsC;AAGpF,WAAO,KAAK,KAAK;EACnB;EAEA,eAAe,WAAgC;AAE7C,QAAI,CAAC,KAAK,QAAQ;AAChB,WAAK,SAAS,KAAK,WAAW;IAChC;AACA,QAAI,CAAC,KAAK,QAAQ;AAChB,YAAM,IAAI,MAAM,4BAA4B;IAC9C;AAEA,UAAM,KAAK,KAAK,aAAa;AAC7B,QAAI,CAAC,IAAI;AACP,YAAM,IAAI,MAAM,4BAA4B;IAC9C;AAEA,QAAI;AAEF,UAAI,WAAW,KAAK,cAAc,IAAI,SAAS;AAC/C,UAAI,oBAAoB;AAExB,UAAI,CAAC,UAAU;AAEb,mBAAW,KAAK,aAAa,IAAI,SAAS,KAAK;MACjD;AAEA,UAAI,CAAC,UAAU;AAEb,cAAMW,cAAa,KAAK,0BAA0B,IAAI,SAAS;AAC/D,YAAIA,aAAY;AACd,qBAAW,KAAK,aAAa,IAAIA,WAAU,KAAK;AAChD,8BAAoB;QACtB;MACF;AAEA,UAAI,CAAC,UAAU;AACb,cAAM,IAAI,MAAM,sBAAsB,SAAS,EAAE;MACnD;AAEA,YAAM,aAAa,SAAS,MAAM,SAAS,cAAc;AACzD,YAAM,QAAQ,KAAK,aAAa,QAAQ;AACxC,YAAM,YAAY,SAAS,aAAa;AACxC,YAAM,YAAY,SAAS,aAAa;AAGxC,YAAM,WAAW,KAAK,wBAAwB,IAAI,YAAY,iBAAiB;AAG/E,UAAI,mBAAmB;AACvB,UAAI,oBAAoB;AAExB,iBAAW,OAAO,UAAU;AAC1B,4BAAoB,IAAI,QAAQ,SAAS;AACzC,6BAAqB,IAAI,QAAQ,UAAU;MAC7C;AAGA,UAAI,qBAAqB,EAAG,oBAAmB,SAAS,mBAAmB;AAC3E,UAAI,sBAAsB,EAAG,qBAAoB,SAAS,oBAAoB;AAG9E,WAAK,uBAAuB,IAAI,UAAU,QAAQ;AAGlD,YAAM,YAAY,KAAK,cAAc,IAAI,UAAU,UAAU,EAAE;AAC/D,YAAM,YACH,WAAiD,aAClD,KAAK,sBAAsB,EAAE,IAAI,UAAU,KAC3C;AAEF,aAAO;QACL,IAAI;QACJ;QACA,MAAM,UAAU,iBAAiB;QACjC;QACA,cAAc;QACd,cAAc,aAAa;QAC3B,OAAO;UACL,eAAe,SAAS;UACxB,oBAAoB;UACpB,qBAAqB;UACrB,YAAY;QACd;QACA;MACF;IACF,UAAA;AACE,SAAG,MAAM;IACX;EACF;;EAIQ,eAAsC;AAC5C,QAAI,CAAC,KAAK,OAAQ,QAAO;AACzB,WAAO,eAAe,KAAK,MAAM;EACnC;;EAGQ,4BAA4B,IAAoB,YAAmC;AACzF,QAAI;AACF,YAAM,OAAO,GACV,QAAQ,8DAA8D,EACtE,IAAI,YAAY,UAAU,IAAI;AAEjC,iBAAW,OAAO,MAAM;AACtB,YAAI;AACF,gBAAM,SAAS,KAAK,MAAM,IAAI,KAAK;AACnC,cAAI,OAAO,aAAa,OAAO,OAAO,cAAc,YAAY,OAAO,UAAU,KAAK,GAAG;AACvF,mBAAO,OAAO,UAAU,KAAK;UAC/B;QACF,QAAQ;QAER;MACF;IACF,QAAQ;IAER;AACA,WAAO;EACT;;EAGQ,0BAA0B,IAAoB,WAAkC;AACtF,QAAI;AACF,YAAM,OAAO,GACV,QAAQ,kFAAkF,EAC1F,IAAI,iBAAiB,SAAS,IAAI;AAErC,iBAAW,OAAO,MAAM;AACtB,YAAI;AACF,gBAAM,SAAS,KAAK,MAAM,IAAI,KAAK;AACnC,cAAI,OAAO,cAAc,WAAW;AAElC,kBAAM,WAAW,IAAI,IAAI,MAAM,GAAG;AAClC,gBAAI,SAAS,UAAU,KAAK,SAAS,CAAC,GAAG;AACvC,qBAAO,SAAS,CAAC;YACnB;UACF;QACF,QAAQ;QAER;MACF;IACF,QAAQ;IAER;AACA,WAAO;EACT;;EAGQ,aAAa,UAAgC;AACnD,QAAI,SAAS,QAAQ,OAAO,SAAS,SAAS,YAAY,SAAS,KAAK,KAAK,GAAG;AAC9E,aAAO,SAAS,KAAK,KAAK;IAC5B;AACA,QAAI,SAAS,SAAS,OAAO,SAAS,UAAU,YAAY,SAAS,MAAM,KAAK,GAAG;AACjF,aAAO,SAAS,MAAM,KAAK;IAC7B;AACA,QAAI,SAAS,QAAQ,OAAO,SAAS,SAAS,YAAY,SAAS,KAAK,KAAK,GAAG;AAC9E,YAAM,YAAY,SAAS,KACxB,MAAM,IAAI,EACV,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,GACnB,KAAK,EACN,MAAM,GAAG,EAAE;AACd,UAAI,UAAW,QAAO;IACxB;AACA,UAAM,aAAa,SAAS,cAAc,SAAS,MAAM;AACzD,WAAO,kBAAkB,WAAW,MAAM,GAAG,CAAC,CAAC;EACjD;;EAGQ,yBAAyB,IAAoB,YAA4B;AAC/E,QAAI;AACF,YAAM,OAAO,GACV,QAAQ,iDAAiD,EACzD,IAAI,YAAY,UAAU,IAAI;AAEjC,UAAI,QAAQ;AACZ,iBAAW,OAAO,MAAM;AACtB,YAAI;AACF,gBAAM,SAAS,KAAK,MAAM,IAAI,KAAK;AAEnC,cAAI,OAAO,SAAS,KAAK,OAAO,SAAS,GAAG;AAC1C;UACF;QACF,QAAQ;QAER;MACF;AACA,aAAO;IACT,QAAQ;AACN,aAAO;IACT;EACF;;EAGQ,wBACN,IACA,YACA,YACW;AACX,UAAM,WAAsB,CAAC;AAE7B,QAAI;AACF,YAAM,OAAO,GACV,QAAQ,yEAAyE,EACjF,IAAI,YAAY,UAAU,IAAI;AAEjC,UAAI,kBAAiC;AACrC,UAAI,eAAe;AAEnB,iBAAW,OAAO,MAAM;AACtB,YAAI;AACF,gBAAM,SAAS,KAAK,MAAM,IAAI,KAAK;AACnC,gBAAM,WAAW,IAAI,IAAI,MAAM,GAAG,EAAE,IAAI,KAAK,OAAO,YAAY;AAGhE,gBAAM,OAAO,OAAO,SAAS,IAAI,cAAc;AAG/C,cAAI,cAAc;AAClB,cAAI,OAAO,YAAY,mBAAmB;AACxC,0BAAc,KAAK,MAAM,OAAO,WAAW,iBAAiB;UAC9D,WAAW,OAAO,WAAW;AAC3B,0BAAc,OAAO;UACvB,WAAW,OAAO,WAAW;AAC3B,0BAAc,OAAO;UACvB;AAGA,cAAI,SAAS,UAAU,OAAO,WAAW,WAAW;AAClD,8BAAkB,OAAO,UAAU;UACrC;AAGA,gBAAM,cAAc,OAAO,YAAY,eAAe;AACtD,gBAAM,eAAe,OAAO,YAAY,gBAAgB;AAGxD,gBAAM,QAAuB,CAAC;AAG9B,gBAAM,OAAO,OAAO,MAAM,KAAK;AAC/B,cAAI,MAAM;AACR,kBAAM,KAAK,EAAE,MAAM,QAAQ,MAAM,cAAc,YAAY,CAAC;UAC9D;AAGA,cAAI,OAAO,gBAAgB;AACzB,kBAAM,WAAW,KAAK,sBAAsB,OAAO,gBAAgB,WAAW;AAC9E,gBAAI,UAAU;AACZ,oBAAM,KAAK,QAAQ;YACrB;UACF;AAGA,cAAI,MAAM,WAAW,EAAG;AAExB,mBAAS,KAAK;YACZ,IAAI,UAAU,UAAU,IAAI,QAAQ;YACpC;YACA,OAAO;YACP,cAAc;YACd,gBAAgB;YAChB,MAAM,SAAS,eAAe,MAAM,KAAK,CAAC,MAAM,EAAE,SAAS,MAAM,IAAI,SAAS;YAC9E,OAAO;YACP,UAAU;YACV,QAAQ,EAAE,OAAO,aAAa,QAAQ,aAAa;YACnD,MAAM;YACN;UACF,CAAC;AAED;QACF,QAAQ;QAER;MACF;IACF,QAAQ;IAER;AAEA,WAAO;EACT;;EAGQ,sBACN,UACA,aACoB;AACpB,QAAI,CAAC,YAAY,CAAC,SAAS,KAAM,QAAO;AAExC,UAAM,WAAW,SAAS;AAC1B,UAAM,iBAAiB,aAAa,gBAAgB,SAASH,cAAa,QAAQ;AAGlF,UAAM,QAA8B;MAClC,QAAQ,SAAS,WAAW,cAAc,cAAc;IAC1D;AAGA,QAAI,SAAS,QAAQ;AACnB,UAAI,OAAO,SAAS,WAAW,UAAU;AACvC,YAAI;AACF,gBAAM,QAAQ,KAAK,MAAM,SAAS,MAAM;QAC1C,QAAQ;AACN,gBAAM,QAAQ,EAAE,MAAM,SAAS,OAAO;QACxC;MACF,OAAO;AACL,cAAM,QAAQ,SAAS;MACzB;IACF;AAGA,QAAI,SAAS,WAAW,QAAW;AACjC,UAAI,OAAO,SAAS,WAAW,UAAU;AACvC,YAAI;AACF,gBAAM,SAAS,KAAK,MAAM,SAAS,MAAM;AACzC,gBAAM,SAAS;AACf,cAAI,OAAO,SAAS,OAAO,WAAW,OAAO,QAAQ;AACnD,kBAAM,QAAQ,OAAO,SAAS,OAAO,WAAW,OAAO;AACvD,kBAAM,SAAS;UACjB;QACF,QAAQ;AACN,gBAAM,SAAS,SAAS;QAC1B;MACF,OAAO;AACL,cAAM,SAAS,SAAS;MAC1B;IACF;AAGA,QAAI,aAAa,eAAe;AAC9B,YAAM,WACJ,OAAO,MAAM,UAAU,YAAY,MAAM,UAAU,OAC9C,MAAM,MAAkC,OACzC;AACN,aAAO;QACL,MAAM;QACN,OAAO;QACP,OAAO;QACP,iBAAiB,MAAM,WAAW,cAAc,YAAY;QAC5D;QACA,cAAc;MAChB;IACF;AAEA,WAAO;MACL,MAAM;MACN,MAAM;MACN,QAAQ,SAAS,cAAc;MAC/B,OAAO,SAAS,QAAQ;MACxB;MACA,cAAc;IAChB;EACF;EAEQ,aAAa,IAAoB,WAAwC;AAC/E,UAAM,MAAM,GACT,QAAQ,8CAA8C,EACtD,IAAI,gBAAgB,SAAS,EAAE;AAElC,QAAI,CAAC,IAAK,QAAO;AAEjB,QAAI;AACF,aAAO,KAAK,MAAM,IAAI,KAAK;IAC7B,QAAQ;AACN,aAAO;IACT;EACF;EAEQ,WAAW,IAAoB,WAAsC;AAC3E,UAAM,MAAM,GACT,QAAQ,8CAA8C,EACtD,IAAI,UAAU,SAAS,EAAE;AAE5B,QAAI,CAAC,IAAK,QAAO;AAEjB,QAAI;AACF,aAAO,KAAK,MAAM,IAAI,KAAK;IAC7B,QAAQ;AACN,aAAO;IACT;EACF;EAEQ,uBACN,IACA,UACA,UACM;AACN,UAAM,gBAAgB,SAAS;AAC/B,QAAI,CAAC,MAAM,QAAQ,aAAa,KAAK,cAAc,WAAW,EAAG;AAEjE,eAAW,WAAW,eAAe;AACnC,UAAI,CAAC,QAAQ,GAAI;AAEjB,YAAM,SAAS,KAAK,WAAW,IAAI,QAAQ,EAAE;AAC7C,UAAI,CAAC,UAAU,CAAC,MAAM,QAAQ,OAAO,YAAY,EAAG;AAEpD,iBAAW,WAAW,OAAO,cAAc;AACzC,cAAM,OAAO,QAAQ,MAAM,KAAK,EAAE,YAAY;AAC9C,YAAI,SAAS,UAAU,SAAS,YAAa;AAE7C,cAAM,cAAc,iBAAiB,OAAO;AAC5C,cAAM,QAAuB,CAAC;AAE9B,cAAM,OAAO,QAAQ,QAAQ;AAC7B,YAAI,KAAK,KAAK,GAAG;AACf,gBAAM,KAAK,EAAE,MAAM,QAAQ,MAAM,cAAc,YAAY,CAAC;QAC9D;AAEA,YAAI,SAAS,eAAe,MAAM,QAAQ,QAAQ,OAAO,GAAG;AAC1D,qBAAW,UAAU,QAAQ,SAAS;AACpC,kBAAM,OAAO,oBAAoB,QAAuB,WAAW;AACnE,gBAAI,KAAM,OAAM,KAAK,IAAI;UAC3B;QACF;AAEA,YAAI,MAAM,WAAW,EAAG;AAExB,iBAAS,KAAK;UACZ,IAAI,cAAc,QAAQ,EAAE;UAC5B;UACA,OAAO;UACP,cAAc;UACd,gBAAgB;UAChB,MAAM;UACN,OAAO;UACP,UAAU;UACV,QAAQ;UACR,MAAM;UACN,aAAa,QAAQ;UACrB,UAAU,QAAQ,YAAY,QAAQ;UACtC;QACF,CAAC;MACH;IACF;EACF;AACF;ACz5BA,cAAc;EACZ,MAAM;EACN,aAAa;EACb,MAAM;EACN,QAAQ,MAAM,IAAI,gBAAgB;AACpC,CAAC;AAED,cAAc;EACZ,MAAM;EACN,aAAa;EACb,MAAM;EACN,QAAQ,MAAM,IAAI,cAAc;AAClC,CAAC;AAED,cAAc;EACZ,MAAM;EACN,aAAa;EACb,MAAM;EACN,QAAQ,MAAM,IAAI,UAAU;AAC9B,CAAC;AAED,cAAc;EACZ,MAAM;EACN,aAAa;EACb,MAAM;EACN,QAAQ,MAAM,IAAI,WAAW;AAC/B,CAAC;AAED,cAAc;EACZ,MAAM;EACN,aAAa;EACb,MAAM;EACN,QAAQ,MAAM,IAAI,YAAY;AAChC,CAAC;AE/BD,IAAM,gBAAgB;AACtB,IAAM,iBAAiB;AAuBvB,SAAS,eAAuB;AAC9B,SAAOV,MAAKI,SAAQ,GAAG,UAAU,YAAY,cAAc;AAC7D;AAEA,SAAS,iBAAuB;AAC9B,QAAM,WAAWJ,MAAKI,SAAQ,GAAG,UAAU,UAAU;AACrD,MAAI,CAACN,YAAW,QAAQ,GAAG;AACzB,cAAU,UAAU,EAAE,WAAW,KAAK,CAAC;EACzC;AACF;AAQO,SAAS,mBAAmB,WAAwC;AACzE,MAAI;AACF,UAAM,YAAY,aAAa;AAC/B,QAAI,CAACA,YAAW,SAAS,EAAG,QAAO;AAEnC,UAAM,OAAO,KAAK,MAAMC,cAAa,WAAW,OAAO,CAAC;AAGxD,QAAI,KAAK,YAAY,cAAe,QAAO;AAE3C,UAAM,QAAQ,KAAK,QAAQ,SAAS;AACpC,QAAI,CAAC,MAAO,QAAO;AAGnB,UAAM,YAAY,IAAI,KAAK,KAAK,KAAK;AACrC,QAAI,KAAK,IAAI,IAAI,MAAM,YAAY,UAAW,QAAO;AAErD,WAAO,EAAE,UAAU,MAAM,UAAU,MAAM,MAAM,QAAQ,CAAC,GAAG,WAAW,MAAM,UAAU;EACxF,QAAQ;AACN,WAAO;EACT;AACF;AAEO,SAAS,mBACd,WACA,UACA,OAAyC,CAAC,GACpC;AACN,MAAI;AACF,mBAAe;AACf,UAAM,YAAY,aAAa;AAE/B,QAAI;AACJ,QAAID,YAAW,SAAS,GAAG;AACzB,UAAI;AACF,eAAO,KAAK,MAAMC,cAAa,WAAW,OAAO,CAAC;AAClD,YAAI,KAAK,YAAY,eAAe;AAClC,iBAAO,EAAE,SAAS,eAAe,SAAS,CAAC,GAAG,cAAc,EAAE;QAChE;MACF,QAAQ;AACN,eAAO,EAAE,SAAS,eAAe,SAAS,CAAC,GAAG,cAAc,EAAE;MAChE;IACF,OAAO;AACL,aAAO,EAAE,SAAS,eAAe,SAAS,CAAC,GAAG,cAAc,EAAE;IAChE;AAEA,SAAK,QAAQ,SAAS,IAAI;MACxB;MACA;MACA,WAAW,KAAK,IAAI;MACpB,SAAS;IACX;AACA,SAAK,eAAe,KAAK,IAAI;AAE7B,kBAAc,WAAW,KAAK,UAAU,MAAM,MAAM,CAAC,GAAG,OAAO;EACjE,QAAQ;EAER;AACF;AAEO,SAAS,aAAmB;AACjC,MAAI;AACF,UAAM,YAAY,aAAa;AAC/B,QAAID,YAAW,SAAS,GAAG;AACzB,YAAM,OAAkB;QACtB,SAAS;QACT,SAAS,CAAC;QACV,cAAc;MAChB;AACA,oBAAc,WAAW,KAAK,UAAU,MAAM,MAAM,CAAC,GAAG,OAAO;IACjE;EACF,QAAQ;EAER;AACF;AAEO,SAAS,eAA8D;AAC5E,MAAI;AACF,UAAM,YAAY,aAAa;AAC/B,QAAI,CAACA,YAAW,SAAS,GAAG;AAC1B,aAAO,EAAE,cAAc,MAAM,MAAM,EAAE;IACvC;AAEA,UAAM,OAAO,KAAK,MAAMC,cAAa,WAAW,OAAO,CAAC;AACxD,UAAM,OAAO,OAAO,OAAO,KAAK,OAAO,EAAE,OAAO,CAAC,KAAK,UAAU,MAAM,MAAM,SAAS,QAAQ,CAAC;AAE9F,WAAO;MACL,cAAc,KAAK,gBAAgB;MACnC;IACF;EACF,QAAQ;AACN,WAAO,EAAE,cAAc,MAAM,MAAM,EAAE;EACvC;AACF;ADnGA,SAAS,iBAAiB,WAAmB,aAA8B;AACzE,MAAI,CAAC,YAAa,QAAO;AACzB,QAAM,IAAI,QAAQ,SAAS;AAC3B,QAAM,IAAI,QAAQ,WAAW;AAC7B,QAAM,UAAU,CAAC,MAAc,EAAE,WAAW,KAAK,GAAG;AACpD,QAAM,KAAK,QAAQ,CAAC;AACpB,QAAM,KAAK,QAAQ,CAAC;AACpB,SAAO,OAAO,MAAM,GAAG,WAAW,KAAK,GAAG,KAAK,GAAG,WAAW,KAAK,GAAG;AACvE;AAEO,SAAS,eAAe,UAAyB,SAAqC;AAC3F,MAAI,SAAS;AAEb,MAAI,QAAQ,KAAK;AACf,UAAM,MAAM,QAAQ;AACpB,aAAS,OAAO,OAAO,CAAC,MAAM,iBAAiB,KAAK,EAAE,SAAS,CAAC;EAClE;AAEA,MAAI,QAAQ,QAAQ,MAAM;AACxB,aAAS,OAAO,OAAO,CAAC,MAAM,EAAE,gBAAgB,QAAQ,IAAK;EAC/D;AAEA,MAAI,QAAQ,MAAM,MAAM;AACtB,aAAS,OAAO,OAAO,CAAC,MAAM,EAAE,gBAAgB,QAAQ,EAAG;EAC7D;AAEA,SAAO;AACT;AAeA,eAAe,eACb,OACA,SACA,YACiC;AACjC,QAAM,WAAW,QAAQ,YAAY;AACrC,QAAM,eAAe,QAAQ,gBAAgB;AAG7C,MAAI,UAAU;AACZ,UAAM,SAAS,mBAAmB,MAAM,IAAI;AAC5C,QAAI,WAAW,MAAM;AAEnB,UAAI,MAAM,mBAAmB;AAC3B,cAAM,UAAU,oBAAI,IAA8B;AAClD,mBAAW,CAAC,IAAI,IAAI,KAAK,OAAO,QAAQ,OAAO,IAAI,GAAG;AACpD,kBAAQ,IAAI,IAAI,IAAI;QACtB;AACA,cAAM,kBAAkB,OAAO;MACjC;AAGA,mBAAa;QACX,OAAO,MAAM;QACb,OAAO;QACP,aAAa,OAAO,SAAS;MAC/B,CAAC;AAGD,UAAI,gBAAgB,MAAM,iBAAiB;AACzC,mBAAW,YAAY;AACrB,gBAAM,kBAAkB,OAAO,OAAO,UAAU,OAAO,WAAW,UAAU;QAC9E,GAAG,CAAC;MACN;AAEA,YAAM,WAAW,eAAe,OAAO,UAAU,OAAO;AACxD,aAAO,EAAE,OAAO,OAAO,UAAU,WAAW,KAAK;IACnD;EACF;AAGA,SAAO,cAAc,OAAO,SAAS,UAAU;AACjD;AAKA,eAAe,kBACb,OACA,gBACA,gBACA,YACe;AACf,MAAI;AAEF,iBAAa,EAAE,OAAO,MAAM,MAAM,OAAO,WAAW,CAAC;AAErD,UAAM,cAAc,MAAM,QAAQ;MAChC,MAAM,gBAAiB,gBAAgB,cAAc;IACvD;AAEA,QAAI,CAAC,YAAY,YAAY;AAC3B,mBAAa,EAAE,OAAO,MAAM,MAAM,OAAO,WAAW,CAAC;AACrD;IACF;AAGA,iBAAa;MACX,OAAO,MAAM;MACb,OAAO;MACP,cAAc,YAAY,YAAY;IACxC,CAAC;AAED,UAAM,kBAAkB,MAAM,QAAQ;MACpC,MAAM,gBAAiB,gBAAgB,YAAY,cAAc,CAAC,CAAC;IACrE;AAGA,UAAM,UAAU,MAAM,oBAAoB;AAC1C,UAAM,OAAyC,CAAC;AAChD,QAAI,SAAS;AACX,iBAAW,CAAC,IAAI,IAAI,KAAK,QAAQ,QAAQ,GAAG;AAC1C,aAAK,EAAE,IAAI,EAAE,IAAI,GAAI,KAAiC;MACxD;IACF;AACA,uBAAmB,MAAM,MAAM,iBAAiB,IAAI;AAEpD,iBAAa;MACX,OAAO,MAAM;MACb,OAAO;MACP,UAAU,gBAAgB;IAC5B,CAAC;EACH,SAAS,KAAK;AAEZ,YAAQ,MAAM,IAAI,MAAM,IAAI,gCAAgC,GAAG;EACjE;AACF;AAKA,eAAe,cACb,OACA,SACA,YACiC;AACjC,QAAM,cAAc,KAAK,MAAM,SAAS,MAAM,IAAI,cAAc;AAChE,QAAM,UAAU,MAAM,YAAY;AAClC,OAAK,IAAI,WAAW;AAEpB,MAAI,CAAC,SAAS;AACZ,WAAO;EACT;AAEA,MAAI;AACF,UAAM,aAAa,KAAK,MAAM,SAAS,MAAM,IAAI,OAAO;AACxD,UAAM,QAAQ,MAAM,KAAK;AACzB,SAAK,IAAI,UAAU;AAGnB,UAAM,UAAU,MAAM,oBAAoB;AAC1C,UAAM,OAAyC,CAAC;AAChD,QAAI,SAAS;AACX,iBAAW,CAAC,IAAI,IAAI,KAAK,QAAQ,QAAQ,GAAG;AAC1C,aAAK,EAAE,IAAI,EAAE,IAAI,GAAI,KAAiC;MACxD;IACF;AAGA,uBAAmB,MAAM,MAAM,OAAO,IAAI;AAE1C,iBAAa,EAAE,OAAO,MAAM,MAAM,OAAO,YAAY,UAAU,MAAM,OAAO,CAAC;AAE7E,UAAM,WAAW,eAAe,OAAO,OAAO;AAC9C,WAAO,EAAE,OAAO,OAAO,UAAU,WAAW,MAAM;EACpD,SAAS,KAAK;AACZ,YAAQ,MAAM,kBAAkB,MAAM,IAAI,KAAK,GAAG;AAClD,WAAO,EAAE,OAAO,OAAO,CAAC,GAAG,WAAW,MAAM;EAC9C;AACF;AAKA,eAAsB,aACpB,UAAuB,CAAC,GACxB,YACqB;AACrB,QAAM,aAAa,KAAK,MAAM,cAAc;AAC5C,QAAM,SAAS,uBAAuB;AACtC,QAAM,UAAyC,CAAC;AAChD,QAAM,cAA6B,CAAC;AACpC,QAAM,kBAA+B,CAAC;AAEtC,QAAM,cAAc,QAAQ,QAAQ,SAChC,IAAI,IAAI,QAAQ,OAAO,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,IAClD;AAGJ,QAAM,eAAe,OAAO,OAAO,CAAC,UAAU;AAC5C,QAAI,eAAe,CAAC,YAAY,IAAI,MAAM,KAAK,YAAY,CAAC,GAAG;AAC7D,aAAO;IACT;AACA,WAAO;EACT,CAAC;AAGD,QAAM,eAAe,aAAa,IAAI,CAAC,UAAU,eAAe,OAAO,SAAS,UAAU,CAAC;AAE3F,QAAM,UAAU,MAAM,QAAQ,IAAI,YAAY;AAG9C,aAAW,UAAU,SAAS;AAC5B,QAAI,QAAQ;AACV,sBAAgB,KAAK,OAAO,KAAK;AACjC,cAAQ,OAAO,MAAM,IAAI,IAAI,OAAO;AACpC,kBAAY,KAAK,GAAG,OAAO,KAAK;IAClC;EACF;AAEA,OAAK,IAAI,UAAU;AACnB,SAAO,EAAE,UAAU,aAAa,SAAS,QAAQ,gBAAgB;AACnE;AAKA,eAAsB,kBACpB,UAAuB,CAAC,GACxB,YACqB;AACrB,SAAO,aAAa,SAAS,UAAU;AACzC;","names":["existsSync","readFileSync","join","basename","statSync","readdirSync","homedir","normalizeTitleText","message","text","require","parseTimestampMs","mapToolTitle","normalizeToolArguments","normalizeToolOutputParts","composerId"]}
|