@poco-ai/tokenarena 0.2.3 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/parsers/claude-code.ts","../src/domain/aggregator.ts","../src/domain/session-extractor.ts","../src/infrastructure/fs/utils.ts","../src/parsers/registry.ts","../src/parsers/codex.ts","../src/parsers/gemini-cli.ts","../src/parsers/copilot-cli.ts","../src/parsers/opencode.ts","../src/parsers/openclaw.ts","../src/parsers/qwen-code.ts","../src/parsers/kimi-code.ts","../src/parsers/droid.ts","../src/parsers/pi-coding-agent.ts","../src/cli.ts","../src/infrastructure/config/manager.ts","../src/infrastructure/xdg.ts","../src/commands/config.ts","../src/services/sync-service.ts","../src/domain/project-identity.ts","../src/domain/upload-manifest.ts","../src/infrastructure/api/client.ts","../src/infrastructure/runtime/lock.ts","../src/infrastructure/runtime/paths.ts","../src/infrastructure/runtime/state.ts","../src/infrastructure/runtime/upload-manifest.ts","../src/services/parser-service.ts","../src/commands/init.ts","../src/commands/daemon.ts","../src/commands/status.ts","../src/commands/sync.ts","../src/commands/uninstall.ts","../src/commands/home.ts","../src/infrastructure/runtime/cli-version.ts","../src/infrastructure/runtime/main-module.ts","../src/index.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join, sep } from \"node:path\";\nimport { aggregateToBuckets } from \"../domain/aggregator\";\nimport { extractSessions } from \"../domain/session-extractor\";\nimport type {\n ParseResult,\n SessionEvent,\n TokenUsageEntry,\n} from \"../domain/types\";\nimport {\n extractSessionId,\n findJsonlFiles,\n readFileSafe,\n} from \"../infrastructure/fs/utils\";\nimport { registerParser } from \"./registry\";\nimport type { IParser, ToolDefinition } from \"./types\";\n\nconst TOOL: ToolDefinition = {\n id: \"claude-code\",\n name: \"Claude Code\",\n dataDir: join(homedir(), \".claude\", \"projects\"),\n};\n\nconst TRANSCRIPT_DIRS = [\n join(homedir(), \".claude\", \"transcripts\"),\n join(homedir(), \".claude\", \"sessions\"),\n];\n\nfunction extractProject(filePath: string): string {\n const projectsPrefix = TOOL.dataDir + sep;\n if (!filePath.startsWith(projectsPrefix)) return \"unknown\";\n const relative = filePath.slice(projectsPrefix.length);\n const firstSegment = relative.split(sep)[0];\n if (!firstSegment) return \"unknown\";\n const parts = firstSegment.split(\"-\").filter(Boolean);\n return parts.length > 0 ? parts[parts.length - 1] : \"unknown\";\n}\n\nclass ClaudeCodeParser implements IParser {\n readonly tool = TOOL;\n\n async parse(): Promise<ParseResult> {\n const entries: TokenUsageEntry[] = [];\n const sessionEvents: SessionEvent[] = [];\n const seenUuids = new Set<string>();\n const seenSessionIds = new Set<string>();\n\n const projectFiles = findJsonlFiles(TOOL.dataDir);\n\n for (const filePath of projectFiles) {\n const content = readFileSafe(filePath);\n if (!content) continue;\n\n const project = extractProject(filePath);\n const sessionId = extractSessionId(filePath);\n seenSessionIds.add(sessionId);\n\n for (const line of content.split(\"\\n\")) {\n if (!line.trim()) continue;\n try {\n const obj = JSON.parse(line);\n const timestamp = obj.timestamp;\n if (!timestamp) continue;\n\n const parsedTimestamp = new Date(timestamp);\n if (Number.isNaN(parsedTimestamp.getTime())) continue;\n\n if (obj.type === \"user\" || obj.type === \"assistant\") {\n sessionEvents.push({\n sessionId,\n source: \"claude-code\",\n project,\n timestamp: parsedTimestamp,\n role: obj.type === \"user\" ? \"user\" : \"assistant\",\n });\n }\n\n if (obj.type !== \"assistant\") continue;\n const message = obj.message;\n if (!message?.usage) continue;\n\n const usage = message.usage;\n if (usage.input_tokens == null && usage.output_tokens == null) {\n continue;\n }\n\n const uuid = obj.uuid;\n if (uuid) {\n if (seenUuids.has(uuid)) continue;\n seenUuids.add(uuid);\n }\n\n entries.push({\n sessionId,\n source: \"claude-code\",\n model: message.model || \"unknown\",\n project,\n timestamp: parsedTimestamp,\n inputTokens: usage.input_tokens || 0,\n outputTokens: usage.output_tokens || 0,\n reasoningTokens: 0,\n cachedTokens: usage.cache_read_input_tokens || 0,\n });\n } catch {\n // Ignore malformed lines and continue scanning the session log.\n }\n }\n }\n\n for (const transcriptsDir of TRANSCRIPT_DIRS) {\n const transcriptFiles = findJsonlFiles(transcriptsDir);\n\n for (const filePath of transcriptFiles) {\n const sessionId = extractSessionId(filePath);\n if (seenSessionIds.has(sessionId)) continue;\n\n const content = readFileSafe(filePath);\n if (!content) continue;\n\n for (const line of content.split(\"\\n\")) {\n if (!line.trim()) continue;\n try {\n const obj = JSON.parse(line);\n const timestamp = obj.timestamp;\n if (!timestamp) continue;\n\n const parsedTimestamp = new Date(timestamp);\n if (Number.isNaN(parsedTimestamp.getTime())) continue;\n\n if (obj.type === \"user\" || obj.type === \"assistant\") {\n sessionEvents.push({\n sessionId,\n source: \"claude-code\",\n project: \"unknown\",\n timestamp: parsedTimestamp,\n role: obj.type === \"user\" ? \"user\" : \"assistant\",\n });\n }\n } catch {\n // Ignore malformed lines and continue scanning the transcript log.\n }\n }\n }\n }\n\n return {\n buckets: aggregateToBuckets(entries),\n sessions: extractSessions(sessionEvents, entries),\n };\n }\n\n isInstalled(): boolean {\n return (\n existsSync(TOOL.dataDir) || TRANSCRIPT_DIRS.some((dir) => existsSync(dir))\n );\n }\n}\n\nregisterParser(new ClaudeCodeParser());\n","import { hostname } from \"node:os\";\nimport type { TokenBucket, TokenUsageEntry } from \"./types\";\n\n/**\n * Round a date down to the nearest 30-minute bucket\n */\nexport function roundToHalfHour(date: Date): Date {\n const d = new Date(date);\n d.setMinutes(d.getMinutes() < 30 ? 0 : 30, 0, 0);\n return d;\n}\n\n/**\n * Aggregate raw token usage entries into 30-minute buckets\n */\nexport function aggregateToBuckets(entries: TokenUsageEntry[]): TokenBucket[] {\n const map = new Map<string, TokenBucket>();\n const host = hostname().replace(/\\.local$/, \"\");\n\n for (const e of entries) {\n const bucketStart = roundToHalfHour(e.timestamp).toISOString();\n const key = `${e.source}|${e.model}|${e.project}|${bucketStart}`;\n\n if (!map.has(key)) {\n map.set(key, {\n source: e.source,\n model: e.model,\n project: e.project,\n bucketStart,\n hostname: host,\n inputTokens: 0,\n outputTokens: 0,\n reasoningTokens: 0,\n cachedTokens: 0,\n totalTokens: 0,\n });\n }\n\n const b = map.get(key);\n if (!b) continue;\n b.inputTokens += e.inputTokens || 0;\n b.outputTokens += e.outputTokens || 0;\n b.reasoningTokens += e.reasoningTokens || 0;\n b.cachedTokens += e.cachedTokens || 0;\n b.totalTokens +=\n (e.inputTokens || 0) +\n (e.outputTokens || 0) +\n (e.reasoningTokens || 0) +\n (e.cachedTokens || 0);\n }\n\n return Array.from(map.values());\n}\n\n/**\n * Add hostname to buckets after privacy filtering\n */\nexport function addHostname(buckets: TokenBucket[]): void {\n const host = hostname().replace(/\\.local$/, \"\");\n for (const b of buckets) {\n b.hostname = host;\n }\n}\n","import { createHash } from \"node:crypto\";\nimport { hostname } from \"node:os\";\nimport type {\n SessionEvent,\n SessionMetadata,\n SessionModelUsage,\n TokenUsageEntry,\n} from \"./types\";\n\nfunction toEntryTotalTokens(entry: TokenUsageEntry) {\n return (\n entry.inputTokens +\n entry.outputTokens +\n entry.reasoningTokens +\n entry.cachedTokens\n );\n}\n\nfunction buildSessionUsage(entries: TokenUsageEntry[]) {\n const usageBySession = new Map<string, Map<string, SessionModelUsage>>();\n\n for (const entry of entries) {\n if (!entry.sessionId) {\n continue;\n }\n\n let byModel = usageBySession.get(entry.sessionId);\n if (!byModel) {\n byModel = new Map<string, SessionModelUsage>();\n usageBySession.set(entry.sessionId, byModel);\n }\n\n const existing = byModel.get(entry.model);\n if (existing) {\n existing.inputTokens += entry.inputTokens;\n existing.outputTokens += entry.outputTokens;\n existing.reasoningTokens += entry.reasoningTokens;\n existing.cachedTokens += entry.cachedTokens;\n existing.totalTokens += toEntryTotalTokens(entry);\n continue;\n }\n\n byModel.set(entry.model, {\n model: entry.model,\n inputTokens: entry.inputTokens,\n outputTokens: entry.outputTokens,\n reasoningTokens: entry.reasoningTokens,\n cachedTokens: entry.cachedTokens,\n totalTokens: toEntryTotalTokens(entry),\n });\n }\n\n return usageBySession;\n}\n\n/**\n * Extract session metadata from timing events.\n *\n * Turn = first AI response → last AI response before next user prompt.\n * activeSeconds = sum(generation durations), excluding queue/TTFT wait.\n * durationSeconds = wall clock from first to last message.\n */\nexport function extractSessions(\n events: SessionEvent[],\n entries: TokenUsageEntry[] = [],\n): SessionMetadata[] {\n const groups = new Map<string, SessionEvent[]>();\n for (const e of events) {\n if (!groups.has(e.sessionId)) groups.set(e.sessionId, []);\n groups.get(e.sessionId)?.push(e);\n }\n\n const sessions: SessionMetadata[] = [];\n const host = hostname().replace(/\\.local$/, \"\");\n const usageBySession = buildSessionUsage(entries);\n\n for (const [sessionId, sessionEvents] of groups) {\n sessionEvents.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());\n\n const first = sessionEvents[0];\n const last = sessionEvents[sessionEvents.length - 1];\n const durationSeconds = Math.round(\n (last.timestamp.getTime() - first.timestamp.getTime()) / 1000,\n );\n\n let activeSeconds = 0;\n let turnStart: Date | null = null;\n let turnEnd: Date | null = null;\n let waitingForFirstResponse = false;\n\n for (const event of sessionEvents) {\n if (event.role === \"user\") {\n if (turnStart !== null && turnEnd !== null && turnEnd > turnStart) {\n activeSeconds += Math.round(\n (turnEnd.getTime() - turnStart.getTime()) / 1000,\n );\n }\n turnStart = null;\n turnEnd = null;\n waitingForFirstResponse = true;\n } else if (waitingForFirstResponse) {\n turnStart = event.timestamp;\n turnEnd = event.timestamp;\n waitingForFirstResponse = false;\n } else if (turnStart !== null) {\n turnEnd = event.timestamp;\n }\n }\n if (turnStart !== null && turnEnd !== null && turnEnd > turnStart) {\n activeSeconds += Math.round(\n (turnEnd.getTime() - turnStart.getTime()) / 1000,\n );\n }\n\n const userPromptHours = new Array(24).fill(0);\n let userMessageCount = 0;\n for (const event of sessionEvents) {\n if (event.role === \"user\") {\n userMessageCount++;\n userPromptHours[event.timestamp.getUTCHours()]++;\n }\n }\n\n const modelUsages = Array.from(\n usageBySession.get(sessionId)?.values() ?? [],\n ).sort((left, right) => {\n if (right.totalTokens !== left.totalTokens) {\n return right.totalTokens - left.totalTokens;\n }\n\n return left.model.localeCompare(right.model);\n });\n const inputTokens = modelUsages.reduce(\n (sum, usage) => sum + usage.inputTokens,\n 0,\n );\n const outputTokens = modelUsages.reduce(\n (sum, usage) => sum + usage.outputTokens,\n 0,\n );\n const reasoningTokens = modelUsages.reduce(\n (sum, usage) => sum + usage.reasoningTokens,\n 0,\n );\n const cachedTokens = modelUsages.reduce(\n (sum, usage) => sum + usage.cachedTokens,\n 0,\n );\n const totalTokens = modelUsages.reduce(\n (sum, usage) => sum + usage.totalTokens,\n 0,\n );\n const primaryModel = modelUsages[0]?.model ?? \"\";\n\n const sessionHash = createHash(\"sha256\")\n .update(sessionId)\n .digest(\"hex\")\n .slice(0, 16);\n\n sessions.push({\n source: first.source,\n project: first.project || \"unknown\",\n sessionHash,\n hostname: host,\n firstMessageAt: first.timestamp.toISOString(),\n lastMessageAt: last.timestamp.toISOString(),\n durationSeconds,\n activeSeconds,\n messageCount: sessionEvents.length,\n userMessageCount,\n userPromptHours,\n inputTokens,\n outputTokens,\n reasoningTokens,\n cachedTokens,\n totalTokens,\n primaryModel,\n modelUsages,\n });\n }\n\n return sessions;\n}\n\n/**\n * Add hostname to sessions after privacy filtering\n */\nexport function addHostnameToSessions(sessions: SessionMetadata[]): void {\n const host = hostname().replace(/\\.local$/, \"\");\n for (const s of sessions) {\n s.hostname = host;\n }\n}\n","import { existsSync, readdirSync, readFileSync } from \"node:fs\";\nimport { basename, join, sep } from \"node:path\";\n\n/**\n * Recursively find all .jsonl files under a directory\n */\nexport function findJsonlFiles(dir: string): string[] {\n const results: string[] = [];\n if (!existsSync(dir)) return results;\n\n try {\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const fullPath = join(dir, entry.name);\n if (entry.isDirectory()) {\n results.push(...findJsonlFiles(fullPath));\n } else if (entry.name.endsWith(\".jsonl\")) {\n results.push(fullPath);\n }\n }\n } catch {\n // ignore unreadable directories\n }\n return results;\n}\n\n/**\n * Find all JSON files matching a pattern in a directory (non-recursive)\n */\nexport function findJsonFiles(dir: string, pattern: RegExp): string[] {\n const results: string[] = [];\n if (!existsSync(dir)) return results;\n\n try {\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n if (entry.isFile() && pattern.test(entry.name)) {\n results.push(join(dir, entry.name));\n }\n }\n } catch {\n // ignore unreadable directories\n }\n return results;\n}\n\n/**\n * Read file contents, return null on error\n */\nexport function readFileSafe(filePath: string): string | null {\n try {\n return readFileSync(filePath, \"utf-8\");\n } catch {\n return null;\n }\n}\n\n/**\n * Parse JSONL file into array of objects\n */\nexport function parseJsonl<T>(content: string): T[] {\n const results: T[] = [];\n for (const line of content.split(\"\\n\")) {\n if (!line.trim()) continue;\n try {\n results.push(JSON.parse(line) as T);\n } catch {\n // skip malformed lines\n }\n }\n return results;\n}\n\n/**\n * Extract project name from a Claude-style encoded path\n * Path format: ~/.claude/projects/{encodedProjectPath}/{sessionId}.jsonl\n */\nexport function extractProjectFromPath(\n filePath: string,\n projectsDir: string,\n): string {\n const prefix = projectsDir + sep;\n if (!filePath.startsWith(prefix)) return \"unknown\";\n const relative = filePath.slice(prefix.length);\n const firstSeg = relative.split(sep)[0];\n if (!firstSeg) return \"unknown\";\n const parts = firstSeg.split(\"-\").filter(Boolean);\n return parts.length > 0 ? parts[parts.length - 1] : \"unknown\";\n}\n\n/**\n * Extract session ID from file path (basename without extension)\n */\nexport function extractSessionId(filePath: string): string {\n return basename(filePath, \".jsonl\");\n}\n","import { existsSync } from \"node:fs\";\nimport type { IParser, ToolDefinition } from \"./types\";\n\nexport const TOOLS: ToolDefinition[] = [];\n\nconst parsers = new Map<string, IParser>();\n\nexport function registerParser(parser: IParser): void {\n parsers.set(parser.tool.id, parser);\n if (!TOOLS.find((tool) => tool.id === parser.tool.id)) {\n TOOLS.push(parser.tool);\n }\n}\n\nexport function getParser(toolId: string): IParser | undefined {\n return parsers.get(toolId);\n}\n\nexport function getAllParsers(): IParser[] {\n return Array.from(parsers.values());\n}\n\nexport function isToolInstalled(toolId: string): boolean {\n const parser = parsers.get(toolId);\n if (parser?.isInstalled) {\n return parser.isInstalled();\n }\n\n const tool = TOOLS.find((candidate) => candidate.id === toolId);\n return tool ? existsSync(tool.dataDir) : false;\n}\n\nexport function detectInstalledTools(): ToolDefinition[] {\n return TOOLS.filter((tool) => isToolInstalled(tool.id));\n}\n\nexport function getAllTools(): ToolDefinition[] {\n return TOOLS;\n}\n","import { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { aggregateToBuckets } from \"../domain/aggregator\";\nimport { extractSessions } from \"../domain/session-extractor\";\nimport type {\n ParseResult,\n SessionEvent,\n TokenUsageEntry,\n} from \"../domain/types\";\nimport { findJsonlFiles, readFileSafe } from \"../infrastructure/fs/utils\";\nimport { registerParser } from \"./registry\";\nimport type { IParser, ToolDefinition } from \"./types\";\n\nconst TOOL: ToolDefinition = {\n id: \"codex\",\n name: \"Codex CLI\",\n dataDir: join(homedir(), \".codex\", \"sessions\"),\n};\n\ninterface CodexEvent {\n type: string;\n timestamp?: string;\n payload?: {\n type?: string;\n model?: string;\n cwd?: string;\n git?: {\n repository_url?: string;\n };\n info?: {\n model?: string;\n last_token_usage?: {\n input_tokens?: number;\n output_tokens?: number;\n cached_input_tokens?: number;\n reasoning_output_tokens?: number;\n };\n total_token_usage?: {\n input_tokens?: number;\n output_tokens?: number;\n cached_input_tokens?: number;\n reasoning_output_tokens?: number;\n };\n };\n };\n}\n\nfunction getPathLeaf(value: string): string {\n const normalized = value.replace(/\\\\/g, \"/\").replace(/\\/+$/, \"\");\n const leaf = normalized.split(\"/\").filter(Boolean).pop();\n return leaf || \"unknown\";\n}\n\nexport function resolveCodexProject(payload?: CodexEvent[\"payload\"]): string {\n if (!payload) {\n return \"unknown\";\n }\n\n const repositoryUrl = payload.git?.repository_url;\n if (repositoryUrl) {\n const match = repositoryUrl.match(/([^/]+\\/[^/]+?)(?:\\.git)?$/);\n if (match) {\n return match[1];\n }\n }\n\n if (payload.cwd) {\n return getPathLeaf(payload.cwd);\n }\n\n return \"unknown\";\n}\n\nclass CodexParser implements IParser {\n readonly tool = TOOL;\n\n async parse(): Promise<ParseResult> {\n const entries: TokenUsageEntry[] = [];\n const sessionEvents: SessionEvent[] = [];\n const files = findJsonlFiles(TOOL.dataDir);\n\n if (files.length === 0) {\n return { buckets: [], sessions: [] };\n }\n\n for (const filePath of files) {\n const content = readFileSafe(filePath);\n if (!content) continue;\n\n let sessionProject = \"unknown\";\n const sessionModel = \"unknown\";\n for (const line of content.split(\"\\n\")) {\n if (!line.trim()) continue;\n try {\n const obj = JSON.parse(line) as CodexEvent;\n if (obj.type === \"session_meta\") {\n sessionProject = resolveCodexProject(obj.payload);\n break;\n }\n } catch {\n break;\n }\n }\n\n let turnContextModel = \"unknown\";\n type TokenUsage = {\n input_tokens?: number;\n output_tokens?: number;\n cached_input_tokens?: number;\n reasoning_output_tokens?: number;\n };\n const prevTotal = new Map<string, TokenUsage>();\n\n for (const line of content.split(\"\\n\")) {\n if (!line.trim()) continue;\n try {\n const obj = JSON.parse(line) as CodexEvent;\n\n if (obj.type === \"turn_context\" && obj.timestamp) {\n const eventTimestamp = new Date(obj.timestamp);\n if (!Number.isNaN(eventTimestamp.getTime())) {\n sessionEvents.push({\n sessionId: filePath,\n source: \"codex\",\n project: sessionProject,\n timestamp: eventTimestamp,\n role: \"user\",\n });\n }\n }\n\n if (obj.type === \"turn_context\" && obj.payload?.model) {\n turnContextModel = obj.payload.model;\n continue;\n }\n\n if (obj.type !== \"event_msg\") continue;\n\n const payload = obj.payload;\n if (!payload || payload.type !== \"token_count\") continue;\n\n const info = payload.info;\n if (!info) continue;\n\n const timestamp = obj.timestamp ? new Date(obj.timestamp) : null;\n if (!timestamp || Number.isNaN(timestamp.getTime())) continue;\n\n sessionEvents.push({\n sessionId: filePath,\n source: \"codex\",\n project: sessionProject,\n timestamp,\n role: \"assistant\",\n });\n\n let usage = info.last_token_usage;\n if (!usage && info.total_token_usage) {\n const totalKey = `${info.model || payload.model || turnContextModel || \"\"}`;\n const prev = prevTotal.get(totalKey);\n const curr = info.total_token_usage;\n if (prev) {\n usage = {\n input_tokens:\n (curr.input_tokens || 0) - (prev.input_tokens || 0),\n output_tokens:\n (curr.output_tokens || 0) - (prev.output_tokens || 0),\n cached_input_tokens:\n (curr.cached_input_tokens || 0) -\n (prev.cached_input_tokens || 0),\n reasoning_output_tokens:\n (curr.reasoning_output_tokens || 0) -\n (prev.reasoning_output_tokens || 0),\n };\n } else {\n usage = curr;\n }\n prevTotal.set(totalKey, { ...curr });\n }\n if (!usage) continue;\n\n const model =\n info.model || payload.model || turnContextModel || sessionModel;\n const cachedInput = usage.cached_input_tokens || 0;\n const reasoningTokens = usage.reasoning_output_tokens || 0;\n\n entries.push({\n sessionId: filePath,\n source: \"codex\",\n model,\n project: sessionProject,\n timestamp,\n inputTokens: (usage.input_tokens || 0) - cachedInput,\n outputTokens: usage.output_tokens || 0,\n reasoningTokens,\n cachedTokens: cachedInput,\n });\n } catch {\n // Ignore malformed lines and continue scanning the session log.\n }\n }\n }\n\n return {\n buckets: aggregateToBuckets(entries),\n sessions: extractSessions(sessionEvents, entries),\n };\n }\n}\n\nregisterParser(new CodexParser());\n","import { existsSync, readdirSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { aggregateToBuckets } from \"../domain/aggregator\";\nimport { extractSessions } from \"../domain/session-extractor\";\nimport type {\n ParseResult,\n SessionEvent,\n TokenUsageEntry,\n} from \"../domain/types\";\nimport { registerParser } from \"./registry\";\nimport type { IParser, ToolDefinition } from \"./types\";\n\nconst TOOL: ToolDefinition = {\n id: \"gemini-cli\",\n name: \"Gemini CLI\",\n dataDir: join(homedir(), \".gemini\", \"tmp\"),\n};\n\nfunction findSessionFiles(baseDir: string): string[] {\n const results: string[] = [];\n if (!existsSync(baseDir)) return results;\n\n try {\n for (const entry of readdirSync(baseDir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n const chatsDir = join(baseDir, entry.name, \"chats\");\n if (!existsSync(chatsDir)) continue;\n try {\n for (const f of readdirSync(chatsDir)) {\n if (f.startsWith(\"session-\") && f.endsWith(\".json\")) {\n results.push(join(chatsDir, f));\n }\n }\n } catch {}\n }\n } catch {\n return results;\n }\n return results;\n}\n\ninterface GeminiMessage {\n role: string;\n timestamp?: string;\n createTime?: string;\n model?: string;\n tokens?: {\n input?: number;\n output?: number;\n cached?: number;\n thoughts?: number;\n };\n usage?: {\n promptTokenCount?: number;\n candidatesTokenCount?: number;\n cachedContentTokenCount?: number;\n thoughtsTokenCount?: number;\n input_tokens?: number;\n output_tokens?: number;\n };\n usageMetadata?: GeminiMessage[\"usage\"];\n token_count?: GeminiMessage[\"usage\"];\n}\n\ninterface GeminiSession {\n messages?: GeminiMessage[];\n history?: GeminiMessage[];\n model?: string;\n createTime?: string;\n}\n\nclass GeminiCliParser implements IParser {\n readonly tool = TOOL;\n\n async parse(): Promise<ParseResult> {\n const sessionFiles = findSessionFiles(TOOL.dataDir);\n if (sessionFiles.length === 0) {\n return { buckets: [], sessions: [] };\n }\n\n const entries: TokenUsageEntry[] = [];\n const sessionEvents: SessionEvent[] = [];\n\n for (const filePath of sessionFiles) {\n let data: GeminiSession;\n try {\n data = JSON.parse(readFileSync(filePath, \"utf-8\"));\n } catch {\n continue;\n }\n\n const messages = data.messages || data.history || [];\n for (const msg of messages) {\n const timestamp = msg.timestamp || msg.createTime || data.createTime;\n if (!timestamp) continue;\n const ts = new Date(timestamp);\n if (Number.isNaN(ts.getTime())) continue;\n\n if (msg.role !== \"user\" && msg.role !== \"assistant\") continue;\n\n const role = msg.role;\n sessionEvents.push({\n sessionId: filePath,\n source: \"gemini-cli\",\n project: \"unknown\",\n timestamp: ts,\n role,\n });\n\n const tokens = msg.tokens;\n const usage = msg.usage || msg.usageMetadata || msg.token_count;\n if (!tokens && !usage) continue;\n\n if (tokens) {\n const cached = tokens.cached || 0;\n const thoughts = tokens.thoughts || 0;\n entries.push({\n sessionId: filePath,\n source: \"gemini-cli\",\n model: msg.model || data.model || \"unknown\",\n project: \"unknown\",\n timestamp: ts,\n inputTokens: (tokens.input || 0) - cached,\n outputTokens: tokens.output || 0,\n reasoningTokens: thoughts,\n cachedTokens: cached,\n });\n } else if (usage) {\n const cached = usage.cachedContentTokenCount || 0;\n const thoughts = usage.thoughtsTokenCount || 0;\n entries.push({\n sessionId: filePath,\n source: \"gemini-cli\",\n model: msg.model || data.model || \"unknown\",\n project: \"unknown\",\n timestamp: ts,\n inputTokens:\n (usage.promptTokenCount || usage.input_tokens || 0) - cached,\n outputTokens:\n usage.candidatesTokenCount || usage.output_tokens || 0,\n reasoningTokens: thoughts,\n cachedTokens: cached,\n });\n }\n }\n }\n\n return {\n buckets: aggregateToBuckets(entries),\n sessions: extractSessions(sessionEvents, entries),\n };\n }\n}\n\nregisterParser(new GeminiCliParser());\n","import { existsSync, readdirSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { basename, dirname, join } from \"node:path\";\nimport { aggregateToBuckets } from \"../domain/aggregator\";\nimport { extractSessions } from \"../domain/session-extractor\";\nimport type {\n ParseResult,\n SessionEvent,\n TokenUsageEntry,\n} from \"../domain/types\";\nimport { registerParser } from \"./registry\";\nimport type { IParser, ToolDefinition } from \"./types\";\n\nconst ROOT_DIR = join(homedir(), \".copilot\");\n\nconst TOOL: ToolDefinition = {\n id: \"copilot-cli\",\n name: \"GitHub Copilot CLI\",\n dataDir: ROOT_DIR,\n};\n\ninterface CopilotEvent {\n type: string;\n timestamp?: string;\n data?: {\n context?: {\n gitRoot?: string;\n cwd?: string;\n };\n modelMetrics?: Record<\n string,\n {\n usage?: {\n inputTokens?: number;\n outputTokens?: number;\n cacheReadTokens?: number;\n cacheWriteTokens?: number;\n };\n }\n >;\n };\n}\n\nfunction collectEventFiles(\n dir: string,\n results: { filePath: string; sessionId: string }[],\n visited: Set<string>,\n): void {\n if (!existsSync(dir) || visited.has(dir)) {\n return;\n }\n\n visited.add(dir);\n\n try {\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const fullPath = join(dir, entry.name);\n\n if (entry.isDirectory()) {\n collectEventFiles(fullPath, results, visited);\n continue;\n }\n\n if (entry.isFile() && entry.name === \"events.jsonl\") {\n results.push({\n filePath: fullPath,\n sessionId: basename(dirname(fullPath)),\n });\n }\n }\n } catch {\n // Ignore unreadable directories and keep scanning.\n }\n}\n\nfunction findEventFiles(\n baseDir: string,\n): { filePath: string; sessionId: string }[] {\n const results: { filePath: string; sessionId: string }[] = [];\n collectEventFiles(baseDir, results, new Set<string>());\n return results;\n}\n\nfunction getProjectFromContext(\n context: { gitRoot?: string; cwd?: string } | undefined,\n): string {\n const projectPath = context?.gitRoot || context?.cwd;\n if (!projectPath) return \"unknown\";\n return basename(projectPath.replace(/[\\\\/]+$/, \"\")) || \"unknown\";\n}\n\nclass CopilotCliParser implements IParser {\n readonly tool = TOOL;\n\n async parse(): Promise<ParseResult> {\n const eventFiles = findEventFiles(ROOT_DIR);\n if (eventFiles.length === 0) {\n return { buckets: [], sessions: [] };\n }\n\n const entries: TokenUsageEntry[] = [];\n const sessionEvents: SessionEvent[] = [];\n\n for (const { filePath, sessionId } of eventFiles) {\n let content: string;\n try {\n content = readFileSync(filePath, \"utf-8\");\n } catch {\n continue;\n }\n\n let currentProject = \"unknown\";\n\n for (const line of content.split(\"\\n\")) {\n if (!line.trim()) continue;\n\n try {\n const obj = JSON.parse(line) as CopilotEvent;\n const timestamp = obj.timestamp ? new Date(obj.timestamp) : null;\n const hasTimestamp = timestamp && !Number.isNaN(timestamp.getTime());\n\n if (obj.type === \"session.start\" || obj.type === \"session.resume\") {\n currentProject = getProjectFromContext(obj.data?.context);\n }\n\n if (hasTimestamp && timestamp && obj.type === \"user.message\") {\n sessionEvents.push({\n sessionId,\n source: \"copilot-cli\",\n project: currentProject,\n timestamp,\n role: \"user\",\n });\n }\n\n if (hasTimestamp && timestamp && obj.type === \"assistant.message\") {\n sessionEvents.push({\n sessionId,\n source: \"copilot-cli\",\n project: currentProject,\n timestamp,\n role: \"assistant\",\n });\n }\n\n if (obj.type !== \"session.shutdown\" || !hasTimestamp || !timestamp) {\n continue;\n }\n\n const modelMetrics = obj.data?.modelMetrics || {};\n for (const [model, metrics] of Object.entries(modelMetrics)) {\n const usage = metrics?.usage;\n if (!usage) continue;\n\n const totalInput = usage.inputTokens || 0;\n const cachedRead = usage.cacheReadTokens || 0;\n const output = usage.outputTokens || 0;\n\n if (totalInput === 0 && cachedRead === 0 && output === 0) {\n continue;\n }\n\n entries.push({\n sessionId,\n source: \"copilot-cli\",\n model,\n project: currentProject,\n timestamp,\n inputTokens: Math.max(0, totalInput - cachedRead),\n outputTokens: output,\n reasoningTokens: 0,\n cachedTokens: cachedRead,\n });\n }\n } catch {\n // Ignore malformed lines and continue scanning the event log.\n }\n }\n }\n\n return {\n buckets: aggregateToBuckets(entries),\n sessions: extractSessions(sessionEvents, entries),\n };\n }\n\n isInstalled(): boolean {\n return existsSync(ROOT_DIR);\n }\n}\n\nregisterParser(new CopilotCliParser());\n","import { execFileSync } from \"node:child_process\";\nimport { type Dirent, existsSync, readdirSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { basename, join } from \"node:path\";\nimport { aggregateToBuckets } from \"../domain/aggregator\";\nimport { extractSessions } from \"../domain/session-extractor\";\nimport type {\n ParseResult,\n SessionEvent,\n TokenUsageEntry,\n} from \"../domain/types\";\nimport { registerParser } from \"./registry\";\nimport type { IParser, ToolDefinition } from \"./types\";\n\nconst DEFAULT_DATA_DIR = join(homedir(), \".local\", \"share\", \"opencode\");\n\nconst TOOL: ToolDefinition = {\n id: \"opencode\",\n name: \"OpenCode\",\n dataDir: DEFAULT_DATA_DIR,\n};\n\ninterface OpenCodeMessage {\n sessionID?: string;\n role?: string;\n created?: string;\n modelID?: string;\n tokens?: {\n input?: number;\n output?: number;\n cache?: {\n read?: number;\n };\n reasoning?: number;\n };\n path?: {\n root?: string;\n };\n time?: {\n created?: string;\n };\n}\n\ninterface SqliteRow {\n sessionID: string;\n role: string;\n created: string;\n modelID: string | null;\n tokens: string | null;\n rootPath: string | null;\n}\n\nfunction getOpenCodeDataDirs(env: NodeJS.ProcessEnv = process.env): string[] {\n const dirs = [\n env.TOKEN_ARENA_OPENCODE_DIR,\n env.XDG_DATA_HOME ? join(env.XDG_DATA_HOME, \"opencode\") : undefined,\n DEFAULT_DATA_DIR,\n env.LOCALAPPDATA ? join(env.LOCALAPPDATA, \"opencode\") : undefined,\n env.APPDATA ? join(env.APPDATA, \"opencode\") : undefined,\n ].filter((value): value is string => Boolean(value));\n\n return Array.from(new Set(dirs));\n}\n\nasync function withSuppressedSqliteWarning<T>(\n fn: () => Promise<T>,\n): Promise<T> {\n const originalEmitWarning = process.emitWarning;\n\n process.emitWarning = ((\n warning: string | Error,\n ...args: unknown[]\n ): void => {\n const warningName =\n typeof warning === \"string\"\n ? typeof args[0] === \"string\"\n ? args[0]\n : \"\"\n : warning.name;\n const warningMessage =\n typeof warning === \"string\" ? warning : warning.message;\n\n if (\n warningName === \"ExperimentalWarning\" &&\n warningMessage.includes(\"SQLite\")\n ) {\n return;\n }\n\n (\n originalEmitWarning as (\n warning: string | Error,\n ...warningArgs: unknown[]\n ) => void\n ).call(process, warning, ...args);\n }) as typeof process.emitWarning;\n\n try {\n return await fn();\n } finally {\n process.emitWarning = originalEmitWarning;\n }\n}\n\nasync function readSqliteRowsWithBuiltin(\n dbPath: string,\n query: string,\n): Promise<SqliteRow[] | null> {\n try {\n return await withSuppressedSqliteWarning(async () => {\n const sqliteModuleId = \"node:sqlite\";\n const sqlite = (await import(sqliteModuleId)) as {\n DatabaseSync: new (\n location: string,\n ) => {\n close(): void;\n prepare(sql: string): {\n all(): SqliteRow[];\n };\n };\n };\n const db = new sqlite.DatabaseSync(dbPath);\n\n try {\n return db.prepare(query).all() as SqliteRow[];\n } finally {\n db.close();\n }\n });\n } catch (err) {\n const error = err as NodeJS.ErrnoException;\n const message = (err as Error).message;\n if (\n error.code === \"ERR_UNKNOWN_BUILTIN_MODULE\" ||\n message.includes(\"node:sqlite\")\n ) {\n return null;\n }\n\n throw err;\n }\n}\n\nfunction readSqliteRowsWithCli(dbPath: string, query: string): SqliteRow[] {\n const candidates = [\n process.env.TOKEN_ARENA_SQLITE3,\n \"sqlite3\",\n \"sqlite3.exe\",\n ].filter((value): value is string => Boolean(value));\n\n let lastError: Error | null = null;\n\n for (const command of candidates) {\n try {\n const output = execFileSync(command, [\"-json\", dbPath, query], {\n encoding: \"utf-8\",\n maxBuffer: 100 * 1024 * 1024,\n timeout: 30000,\n windowsHide: true,\n }).trim();\n\n if (!output || output === \"[]\") {\n return [];\n }\n\n return JSON.parse(output) as SqliteRow[];\n } catch (err) {\n lastError = err as Error;\n const nodeError = err as NodeJS.ErrnoException & { status?: number };\n if (nodeError.status === 127 || nodeError.message?.includes(\"ENOENT\")) {\n continue;\n }\n\n throw err;\n }\n }\n\n throw new Error(\n `sqlite3 CLI not found. Install sqlite3 or set TOKEN_ARENA_SQLITE3 to its full path. Last error: ${lastError?.message || \"not found\"}`,\n );\n}\n\nclass OpenCodeParser implements IParser {\n readonly tool = TOOL;\n\n async parse(): Promise<ParseResult> {\n const buckets: ParseResult[\"buckets\"] = [];\n const sessions: ParseResult[\"sessions\"] = [];\n\n for (const rootDir of getOpenCodeDataDirs()) {\n const result = await this.parseRoot(rootDir);\n if (result.buckets.length > 0) {\n buckets.push(...result.buckets);\n }\n if (result.sessions.length > 0) {\n sessions.push(...result.sessions);\n }\n }\n\n return { buckets, sessions };\n }\n\n isInstalled(): boolean {\n return getOpenCodeDataDirs().some((dir) => existsSync(dir));\n }\n\n private async parseRoot(rootDir: string): Promise<ParseResult> {\n const dbPath = join(rootDir, \"opencode.db\");\n const messagesDir = join(rootDir, \"storage\", \"message\");\n\n if (existsSync(dbPath)) {\n try {\n return await this.parseFromSqlite(dbPath);\n } catch (err) {\n process.stderr.write(\n `warn: opencode sqlite parse failed (${(err as Error).message}), trying legacy json...\\n`,\n );\n }\n }\n\n return this.parseFromJson(messagesDir);\n }\n\n private async parseFromSqlite(dbPath: string): Promise<ParseResult> {\n const query = `SELECT\n session_id as sessionID,\n json_extract(data, '$.role') as role,\n json_extract(data, '$.time.created') as created,\n json_extract(data, '$.modelID') as modelID,\n json_extract(data, '$.tokens') as tokens,\n json_extract(data, '$.path.root') as rootPath\n FROM message`;\n\n const builtinRows = await readSqliteRowsWithBuiltin(dbPath, query);\n const rows = builtinRows ?? readSqliteRowsWithCli(dbPath, query);\n\n if (rows.length === 0) {\n return { buckets: [], sessions: [] };\n }\n\n const entries: TokenUsageEntry[] = [];\n const sessionEvents: SessionEvent[] = [];\n\n for (const row of rows) {\n const timestamp = new Date(row.created);\n if (Number.isNaN(timestamp.getTime())) continue;\n\n const project = row.rootPath ? basename(row.rootPath) : \"unknown\";\n const sessionId = row.sessionID || \"unknown\";\n if (row.role !== \"user\" && row.role !== \"assistant\") continue;\n\n sessionEvents.push({\n sessionId,\n source: \"opencode\",\n project,\n timestamp,\n role: row.role === \"user\" ? \"user\" : \"assistant\",\n });\n\n if (!row.modelID) continue;\n\n let tokens: OpenCodeMessage[\"tokens\"];\n try {\n tokens =\n typeof row.tokens === \"string\" ? JSON.parse(row.tokens) : row.tokens;\n } catch {\n continue;\n }\n if (!tokens || (!tokens.input && !tokens.output)) continue;\n\n entries.push({\n sessionId,\n source: \"opencode\",\n model: row.modelID || \"unknown\",\n project,\n timestamp,\n inputTokens: tokens.input || 0,\n outputTokens: tokens.output || 0,\n reasoningTokens: tokens.reasoning || 0,\n cachedTokens: tokens.cache?.read || 0,\n });\n }\n\n return {\n buckets: aggregateToBuckets(entries),\n sessions: extractSessions(sessionEvents, entries),\n };\n }\n\n private parseFromJson(messagesDir: string): ParseResult {\n if (!existsSync(messagesDir)) return { buckets: [], sessions: [] };\n\n const entries: TokenUsageEntry[] = [];\n const sessionEvents: SessionEvent[] = [];\n\n let sessionDirs: Dirent[];\n try {\n sessionDirs = readdirSync(messagesDir, { withFileTypes: true }).filter(\n (dirent) => dirent.isDirectory() && dirent.name.startsWith(\"ses_\"),\n );\n } catch {\n return { buckets: [], sessions: [] };\n }\n\n for (const sessionDir of sessionDirs) {\n const sessionPath = join(messagesDir, sessionDir.name);\n let messageFiles: string[];\n try {\n messageFiles = readdirSync(sessionPath).filter((file) =>\n file.endsWith(\".json\"),\n );\n } catch {\n continue;\n }\n\n for (const file of messageFiles) {\n const filePath = join(sessionPath, file);\n\n let data: OpenCodeMessage;\n try {\n data = JSON.parse(readFileSync(filePath, \"utf-8\"));\n } catch {\n continue;\n }\n\n const timestamp = new Date(data.time?.created || data.created);\n if (Number.isNaN(timestamp.getTime())) continue;\n\n const rootPath = data.path?.root;\n const project = rootPath ? basename(rootPath) : \"unknown\";\n if (data.role !== \"user\" && data.role !== \"assistant\") continue;\n\n sessionEvents.push({\n sessionId: sessionDir.name,\n source: \"opencode\",\n project,\n timestamp,\n role: data.role === \"user\" ? \"user\" : \"assistant\",\n });\n\n if (!data.modelID) continue;\n const tokens = data.tokens;\n if (!tokens || (!tokens.input && !tokens.output)) continue;\n\n entries.push({\n sessionId: sessionDir.name,\n source: \"opencode\",\n model: data.modelID || \"unknown\",\n project,\n timestamp,\n inputTokens: tokens.input || 0,\n outputTokens: tokens.output || 0,\n reasoningTokens: tokens.reasoning || 0,\n cachedTokens: tokens.cache?.read || 0,\n });\n }\n }\n\n return {\n buckets: aggregateToBuckets(entries),\n sessions: extractSessions(sessionEvents, entries),\n };\n }\n}\n\nregisterParser(new OpenCodeParser());\n","import { type Dirent, existsSync, readdirSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { aggregateToBuckets } from \"../domain/aggregator\";\nimport { extractSessions } from \"../domain/session-extractor\";\nimport type {\n ParseResult,\n SessionEvent,\n TokenUsageEntry,\n} from \"../domain/types\";\nimport { registerParser } from \"./registry\";\nimport type { IParser, ToolDefinition } from \"./types\";\n\nconst POSSIBLE_ROOTS = [\n join(homedir(), \".openclaw\"),\n join(homedir(), \".clawdbot\"),\n join(homedir(), \".moltbot\"),\n join(homedir(), \".moldbot\"),\n];\n\nconst TOOL: ToolDefinition = {\n id: \"openclaw\",\n name: \"OpenClaw\",\n dataDir: POSSIBLE_ROOTS[0], // Primary data dir for detection\n};\n\ninterface OpenClawMessage {\n type?: string;\n timestamp?: string | number;\n message?: {\n role?: string;\n timestamp?: string | number;\n model?: string;\n usage?: {\n input?: number;\n inputTokens?: number;\n input_tokens?: number;\n promptTokens?: number;\n prompt_tokens?: number;\n output?: number;\n outputTokens?: number;\n output_tokens?: number;\n completionTokens?: number;\n completion_tokens?: number;\n cacheRead?: number;\n cache_read?: number;\n cache_read_input_tokens?: number;\n };\n };\n model?: string;\n}\n\n/** Normalize usage fields — OpenClaw supports multiple naming conventions */\nfunction getTokens(\n usage: NonNullable<OpenClawMessage[\"message\"]>[\"usage\"],\n ...keys: string[]\n): number {\n for (const key of keys) {\n const value = (usage as Record<string, unknown>)[key];\n if (typeof value === \"number\" && value > 0) return value;\n }\n return 0;\n}\n\nclass OpenClawParser implements IParser {\n readonly tool = TOOL;\n\n async parse(): Promise<ParseResult> {\n const entries: TokenUsageEntry[] = [];\n const sessionEvents: SessionEvent[] = [];\n\n for (const root of POSSIBLE_ROOTS) {\n const agentsDir = join(root, \"agents\");\n if (!existsSync(agentsDir)) continue;\n\n let agentDirs: Dirent[];\n try {\n agentDirs = readdirSync(agentsDir, { withFileTypes: true }).filter(\n (d) => d.isDirectory(),\n );\n } catch {\n continue;\n }\n\n for (const agentDir of agentDirs) {\n const project = agentDir.name;\n const sessionsDir = join(agentsDir, agentDir.name, \"sessions\");\n if (!existsSync(sessionsDir)) continue;\n\n let files: string[];\n try {\n files = readdirSync(sessionsDir).filter((f) => f.endsWith(\".jsonl\"));\n } catch {\n continue;\n }\n\n for (const file of files) {\n const filePath = join(sessionsDir, file);\n\n let content: string;\n try {\n content = readFileSync(filePath, \"utf-8\");\n } catch {\n continue;\n }\n\n for (const line of content.split(\"\\n\")) {\n if (!line.trim()) continue;\n try {\n const obj = JSON.parse(line) as OpenClawMessage;\n\n if (obj.type !== \"message\") continue;\n const msg = obj.message;\n if (!msg) continue;\n\n const timestamp = obj.timestamp || msg.timestamp;\n if (!timestamp) continue;\n const ts = new Date(\n typeof timestamp === \"number\" ? timestamp : timestamp,\n );\n if (Number.isNaN(ts.getTime())) continue;\n if (msg.role !== \"user\" && msg.role !== \"assistant\") continue;\n\n sessionEvents.push({\n sessionId: filePath,\n source: \"openclaw\",\n project,\n timestamp: ts,\n role: msg.role === \"user\" ? \"user\" : \"assistant\",\n });\n\n if (msg.role !== \"assistant\") continue;\n const usage = msg.usage;\n if (!usage) continue;\n\n entries.push({\n sessionId: filePath,\n source: \"openclaw\",\n model: msg.model || obj.model || \"unknown\",\n project,\n timestamp: ts,\n inputTokens: getTokens(\n usage,\n \"input\",\n \"inputTokens\",\n \"input_tokens\",\n \"promptTokens\",\n \"prompt_tokens\",\n ),\n outputTokens: getTokens(\n usage,\n \"output\",\n \"outputTokens\",\n \"output_tokens\",\n \"completionTokens\",\n \"completion_tokens\",\n ),\n reasoningTokens: 0,\n cachedTokens: getTokens(\n usage,\n \"cacheRead\",\n \"cache_read\",\n \"cache_read_input_tokens\",\n ),\n });\n } catch {}\n }\n }\n }\n }\n\n return {\n buckets: aggregateToBuckets(entries),\n sessions: extractSessions(sessionEvents, entries),\n };\n }\n\n /** Check if any of the possible roots exist */\n isInstalled(): boolean {\n return POSSIBLE_ROOTS.some((root) => existsSync(join(root, \"agents\")));\n }\n}\n\nregisterParser(new OpenClawParser());\n","import { existsSync, readdirSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { aggregateToBuckets } from \"../domain/aggregator\";\nimport { extractSessions } from \"../domain/session-extractor\";\nimport type {\n ParseResult,\n SessionEvent,\n TokenUsageEntry,\n} from \"../domain/types\";\nimport { readFileSafe } from \"../infrastructure/fs/utils\";\nimport { registerParser } from \"./registry\";\nimport type { IParser, ToolDefinition } from \"./types\";\n\nconst TOOL_ID = \"qwen-code\";\nconst TOOL_NAME = \"Qwen Code\";\nconst DEFAULT_DATA_DIR = join(homedir(), \".qwen\", \"tmp\");\n\ninterface QwenUsage {\n promptTokenCount?: number;\n candidatesTokenCount?: number;\n cachedContentTokenCount?: number;\n thoughtsTokenCount?: number;\n input_tokens?: number;\n output_tokens?: number;\n}\n\ninterface QwenEvent {\n type?: string;\n timestamp?: string;\n cwd?: string;\n uuid?: string;\n model?: string;\n usageMetadata?: QwenUsage;\n usage?: QwenUsage;\n}\n\nexport interface QwenCodeParserOptions {\n dataDir?: string;\n}\n\nfunction createToolDefinition(dataDir: string): ToolDefinition {\n return {\n id: TOOL_ID,\n name: TOOL_NAME,\n dataDir,\n };\n}\n\nfunction toSafeNumber(value: unknown): number {\n const numberValue = Number(value);\n return Number.isFinite(numberValue) ? numberValue : 0;\n}\n\nfunction getPathLeaf(value: string): string {\n const normalized = value.replace(/\\\\/g, \"/\").replace(/\\/+$/, \"\");\n const leaf = normalized.split(\"/\").filter(Boolean).pop();\n return leaf || \"unknown\";\n}\n\nfunction normalizeForPrefix(value: string): string {\n return value.replace(/\\\\/g, \"/\").replace(/\\/+$/, \"\");\n}\n\nfunction findSessionFiles(baseDir: string): string[] {\n const results: string[] = [];\n if (!existsSync(baseDir)) return results;\n\n try {\n for (const entry of readdirSync(baseDir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n\n const chatsDir = join(baseDir, entry.name, \"chats\");\n if (!existsSync(chatsDir)) continue;\n\n try {\n for (const file of readdirSync(chatsDir)) {\n if (file.endsWith(\".jsonl\")) {\n results.push(join(chatsDir, file));\n }\n }\n } catch {\n // Ignore unreadable chat directories and keep scanning.\n }\n }\n } catch {\n return results;\n }\n\n return results;\n}\n\nexport function resolveQwenProject(\n cwd: string | undefined,\n filePath: string,\n dataDir = DEFAULT_DATA_DIR,\n): string {\n if (cwd) {\n return getPathLeaf(cwd);\n }\n\n const normalizedFilePath = normalizeForPrefix(filePath);\n const normalizedDataDir = normalizeForPrefix(dataDir);\n const prefix = `${normalizedDataDir}/`;\n\n if (!normalizedFilePath.startsWith(prefix)) {\n return \"unknown\";\n }\n\n const relativePath = normalizedFilePath.slice(prefix.length);\n const projectId = relativePath.split(\"/\")[0];\n return projectId || \"unknown\";\n}\n\nexport class QwenCodeParser implements IParser {\n readonly tool: ToolDefinition;\n\n constructor(private readonly dataDir = DEFAULT_DATA_DIR) {\n this.tool = createToolDefinition(dataDir);\n }\n\n async parse(): Promise<ParseResult> {\n const sessionFiles = findSessionFiles(this.dataDir);\n if (sessionFiles.length === 0) {\n return { buckets: [], sessions: [] };\n }\n\n const entries: TokenUsageEntry[] = [];\n const sessionEvents: SessionEvent[] = [];\n const seenUuids = new Set<string>();\n\n for (const filePath of sessionFiles) {\n const content = readFileSafe(filePath);\n if (!content) continue;\n\n const sessionId = filePath;\n\n for (const line of content.split(\"\\n\")) {\n if (!line.trim()) continue;\n\n try {\n const obj = JSON.parse(line) as QwenEvent;\n if (!obj.timestamp) continue;\n\n const timestamp = new Date(obj.timestamp);\n if (Number.isNaN(timestamp.getTime())) continue;\n\n const project = resolveQwenProject(obj.cwd, filePath, this.dataDir);\n\n if (obj.type === \"user\" || obj.type === \"assistant\") {\n sessionEvents.push({\n sessionId,\n source: TOOL_ID,\n project,\n timestamp,\n role: obj.type,\n });\n }\n\n if (obj.type !== \"assistant\") continue;\n\n const usage = obj.usageMetadata || obj.usage;\n if (!usage) continue;\n\n const totalInput =\n toSafeNumber(usage.promptTokenCount) ||\n toSafeNumber(usage.input_tokens);\n const totalOutput =\n toSafeNumber(usage.candidatesTokenCount) ||\n toSafeNumber(usage.output_tokens);\n const cachedTokens = toSafeNumber(usage.cachedContentTokenCount);\n const reasoningTokens = toSafeNumber(usage.thoughtsTokenCount);\n\n if (\n totalInput === 0 &&\n totalOutput === 0 &&\n cachedTokens === 0 &&\n reasoningTokens === 0\n ) {\n continue;\n }\n\n if (obj.uuid) {\n if (seenUuids.has(obj.uuid)) continue;\n seenUuids.add(obj.uuid);\n }\n\n entries.push({\n sessionId,\n source: TOOL_ID,\n model: obj.model || \"unknown\",\n project,\n timestamp,\n inputTokens: Math.max(0, totalInput - cachedTokens),\n outputTokens: Math.max(0, totalOutput - reasoningTokens),\n reasoningTokens,\n cachedTokens,\n });\n } catch {\n // Ignore malformed lines and continue scanning the session log.\n }\n }\n }\n\n return {\n buckets: aggregateToBuckets(entries),\n sessions: extractSessions(sessionEvents, entries),\n };\n }\n\n isInstalled(): boolean {\n return existsSync(this.dataDir);\n }\n}\n\nregisterParser(new QwenCodeParser());\n","import { existsSync, readdirSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { aggregateToBuckets } from \"../domain/aggregator\";\nimport { extractSessions } from \"../domain/session-extractor\";\nimport type {\n ParseResult,\n SessionEvent,\n TokenUsageEntry,\n} from \"../domain/types\";\nimport { readFileSafe } from \"../infrastructure/fs/utils\";\nimport { registerParser } from \"./registry\";\nimport type { IParser, ToolDefinition } from \"./types\";\n\nconst TOOL_ID = \"kimi-code\";\nconst TOOL_NAME = \"Kimi Code\";\nconst DEFAULT_SESSIONS_DIR = join(homedir(), \".kimi\", \"sessions\");\nconst DEFAULT_CONFIG_PATH = join(homedir(), \".kimi\", \"kimi.json\");\n\nconst USER_EVENT_TYPES = new Set([\"UserMessage\", \"user_message\", \"Input\"]);\nconst ASSISTANT_EVENT_TYPES = new Set([\n \"AssistantMessage\",\n \"assistant_message\",\n \"Output\",\n \"ModelOutput\",\n \"AssistantOutput\",\n]);\n\ninterface KimiTokenUsage {\n input_other?: unknown;\n output?: unknown;\n input_cache_read?: unknown;\n input_cache_creation?: unknown;\n}\n\ninterface KimiPayload {\n timestamp?: string | number;\n model?: string;\n role?: string;\n token_usage?: KimiTokenUsage;\n message_id?: string;\n}\n\ninterface KimiEvent {\n type?: string;\n timestamp?: string | number;\n payload?: KimiPayload;\n}\n\nexport interface KimiCodeParserOptions {\n sessionsDir?: string;\n configPath?: string;\n}\n\nfunction createToolDefinition(dataDir: string): ToolDefinition {\n return {\n id: TOOL_ID,\n name: TOOL_NAME,\n dataDir,\n };\n}\n\nfunction toSafeNumber(value: unknown): number {\n const numberValue = Number(value);\n return Number.isFinite(numberValue) ? numberValue : 0;\n}\n\nfunction getPathLeaf(value: string): string {\n const normalized = value.replace(/\\\\/g, \"/\").replace(/\\/+$/, \"\");\n const leaf = normalized.split(\"/\").filter(Boolean).pop();\n return leaf || \"unknown\";\n}\n\nfunction findWireFiles(\n baseDir: string,\n): Array<{ filePath: string; workDirHash: string }> {\n const results: Array<{ filePath: string; workDirHash: string }> = [];\n if (!existsSync(baseDir)) return results;\n\n try {\n for (const workDir of readdirSync(baseDir, { withFileTypes: true })) {\n if (!workDir.isDirectory()) continue;\n\n const workDirPath = join(baseDir, workDir.name);\n try {\n for (const session of readdirSync(workDirPath, {\n withFileTypes: true,\n })) {\n if (!session.isDirectory()) continue;\n\n const wireFile = join(workDirPath, session.name, \"wire.jsonl\");\n if (existsSync(wireFile)) {\n results.push({ filePath: wireFile, workDirHash: workDir.name });\n }\n }\n } catch {\n // Ignore unreadable session directories and keep scanning.\n }\n }\n } catch {\n return results;\n }\n\n return results;\n}\n\nfunction parseTimestamp(value: string | number | undefined): Date | null {\n if (value == null) return null;\n const timestamp = new Date(value);\n return Number.isNaN(timestamp.getTime()) ? null : timestamp;\n}\n\nfunction classifyKimiRole(\n type: string | undefined,\n payload: KimiPayload | undefined,\n): SessionEvent[\"role\"] | null {\n if (payload?.role === \"user\" || payload?.role === \"assistant\") {\n return payload.role;\n }\n\n if (type && USER_EVENT_TYPES.has(type)) {\n return \"user\";\n }\n\n if (type && ASSISTANT_EVENT_TYPES.has(type)) {\n return \"assistant\";\n }\n\n if (type?.toLowerCase().includes(\"assistant\")) {\n return \"assistant\";\n }\n\n return null;\n}\n\nfunction loadProjectMap(configPath: string): Map<string, string> {\n const projectMap = new Map<string, string>();\n const content = readFileSafe(configPath);\n if (!content) return projectMap;\n\n try {\n const config = JSON.parse(content) as {\n workspaces?: Record<string, string | { path?: string; dir?: string }>;\n projects?: Record<string, string | { path?: string; dir?: string }>;\n };\n\n const workspaces = config.workspaces || config.projects || {};\n for (const [hash, info] of Object.entries(workspaces)) {\n const pathValue =\n typeof info === \"string\" ? info : info.path || info.dir || undefined;\n if (!pathValue) continue;\n\n projectMap.set(hash, getPathLeaf(pathValue));\n }\n } catch {\n // Ignore unreadable config and fall back to work-dir hashes.\n }\n\n return projectMap;\n}\n\nexport class KimiCodeParser implements IParser {\n readonly tool: ToolDefinition;\n private readonly sessionsDir: string;\n private readonly configPath: string;\n\n constructor(options: KimiCodeParserOptions = {}) {\n this.sessionsDir = options.sessionsDir || DEFAULT_SESSIONS_DIR;\n this.configPath = options.configPath || DEFAULT_CONFIG_PATH;\n this.tool = createToolDefinition(this.sessionsDir);\n }\n\n async parse(): Promise<ParseResult> {\n const wireFiles = findWireFiles(this.sessionsDir);\n if (wireFiles.length === 0) {\n return { buckets: [], sessions: [] };\n }\n\n const projectMap = loadProjectMap(this.configPath);\n const entries: TokenUsageEntry[] = [];\n const sessionEvents: SessionEvent[] = [];\n const seenMessageIds = new Set<string>();\n\n for (const { filePath, workDirHash } of wireFiles) {\n const content = readFileSafe(filePath);\n if (!content) continue;\n\n const sessionId = filePath;\n const project = projectMap.get(workDirHash) || workDirHash;\n let currentModel = \"unknown\";\n let lastTimestampRaw: string | number | undefined;\n\n for (const line of content.split(\"\\n\")) {\n if (!line.trim()) continue;\n\n let obj: KimiEvent;\n try {\n obj = JSON.parse(line) as KimiEvent;\n } catch {\n continue;\n }\n\n const payload = obj.payload;\n if (!payload) continue;\n\n if (payload.model) {\n currentModel = payload.model;\n }\n\n const timestampValue =\n payload.timestamp ?? obj.timestamp ?? lastTimestampRaw;\n const timestamp = parseTimestamp(timestampValue);\n if (payload.timestamp != null) {\n lastTimestampRaw = payload.timestamp;\n } else if (obj.timestamp != null) {\n lastTimestampRaw = obj.timestamp;\n }\n\n const role = classifyKimiRole(obj.type, payload);\n if (role && timestamp) {\n sessionEvents.push({\n sessionId,\n source: TOOL_ID,\n project,\n timestamp,\n role,\n });\n }\n\n if (obj.type !== \"StatusUpdate\") continue;\n\n const tokenUsage = payload.token_usage;\n if (!tokenUsage || !timestamp) continue;\n\n const inputTokens = toSafeNumber(tokenUsage.input_other);\n const outputTokens = toSafeNumber(tokenUsage.output);\n const cachedTokens = toSafeNumber(tokenUsage.input_cache_read);\n const cacheCreateTokens = toSafeNumber(tokenUsage.input_cache_creation);\n\n if (\n inputTokens === 0 &&\n outputTokens === 0 &&\n cachedTokens === 0 &&\n cacheCreateTokens === 0\n ) {\n continue;\n }\n\n if (payload.message_id) {\n if (seenMessageIds.has(payload.message_id)) continue;\n seenMessageIds.add(payload.message_id);\n }\n\n if (!role) {\n sessionEvents.push({\n sessionId,\n source: TOOL_ID,\n project,\n timestamp,\n role: \"assistant\",\n });\n }\n\n entries.push({\n sessionId,\n source: TOOL_ID,\n model: currentModel,\n project,\n timestamp,\n inputTokens,\n outputTokens,\n reasoningTokens: 0,\n cachedTokens,\n });\n }\n }\n\n return {\n buckets: aggregateToBuckets(entries),\n sessions: extractSessions(sessionEvents, entries),\n };\n }\n\n isInstalled(): boolean {\n return existsSync(this.sessionsDir);\n }\n}\n\nregisterParser(new KimiCodeParser());\n","import { existsSync, readdirSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { basename, dirname, join } from \"node:path\";\nimport { aggregateToBuckets } from \"../domain/aggregator\";\nimport { extractSessions } from \"../domain/session-extractor\";\nimport type {\n ParseResult,\n SessionEvent,\n TokenUsageEntry,\n} from \"../domain/types\";\nimport { readFileSafe } from \"../infrastructure/fs/utils\";\nimport { registerParser } from \"./registry\";\nimport type { IParser, ToolDefinition } from \"./types\";\n\nconst TOOL_ID = \"droid\";\nconst TOOL_NAME = \"Droid\";\nconst DEFAULT_DATA_DIR = join(homedir(), \".factory\", \"sessions\");\n\ninterface DroidMessageEvent {\n type?: string;\n timestamp?: string;\n message?: {\n role?: string;\n };\n}\n\ninterface DroidSettings {\n model?: string;\n tokenUsage?: {\n inputTokens?: unknown;\n outputTokens?: unknown;\n cacheReadTokens?: unknown;\n thinkingTokens?: unknown;\n };\n}\n\nfunction createToolDefinition(dataDir: string): ToolDefinition {\n return {\n id: TOOL_ID,\n name: TOOL_NAME,\n dataDir,\n };\n}\n\nfunction findSessionFiles(dir: string): string[] {\n const results: string[] = [];\n if (!existsSync(dir)) return results;\n\n try {\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const fullPath = join(dir, entry.name);\n if (entry.isDirectory()) {\n results.push(...findSessionFiles(fullPath));\n } else if (\n entry.isFile() &&\n entry.name.endsWith(\".jsonl\") &&\n !entry.name.endsWith(\".settings.json\")\n ) {\n results.push(fullPath);\n }\n }\n } catch {\n // Ignore unreadable directories and keep scanning.\n }\n\n return results;\n}\n\nexport function extractDroidProject(slug: string): string {\n const parts = slug.split(\"-\").filter(Boolean);\n return parts.length > 0 ? parts[parts.length - 1] : \"unknown\";\n}\n\nfunction toSafeNumber(value: unknown): number {\n const numberValue = Number(value);\n return Number.isFinite(numberValue) ? numberValue : 0;\n}\n\nexport class DroidParser implements IParser {\n readonly tool: ToolDefinition;\n\n constructor(private readonly dataDir = DEFAULT_DATA_DIR) {\n this.tool = createToolDefinition(dataDir);\n }\n\n async parse(): Promise<ParseResult> {\n const sessionFiles = findSessionFiles(this.dataDir);\n if (sessionFiles.length === 0) {\n return { buckets: [], sessions: [] };\n }\n\n const entries: TokenUsageEntry[] = [];\n const sessionEvents: SessionEvent[] = [];\n\n for (const filePath of sessionFiles) {\n const sessionId = filePath;\n const project = extractDroidProject(basename(dirname(filePath)));\n let firstMessageTimestamp: Date | null = null;\n\n const content = readFileSafe(filePath);\n if (!content) continue;\n\n for (const line of content.split(\"\\n\")) {\n if (!line.trim()) continue;\n\n let obj: DroidMessageEvent;\n try {\n obj = JSON.parse(line) as DroidMessageEvent;\n } catch {\n continue;\n }\n\n if (obj.type !== \"message\" || !obj.timestamp) continue;\n\n const timestamp = new Date(obj.timestamp);\n if (Number.isNaN(timestamp.getTime())) continue;\n\n const role = obj.message?.role;\n if (role !== \"user\" && role !== \"assistant\") continue;\n\n if (firstMessageTimestamp === null) {\n firstMessageTimestamp = timestamp;\n }\n\n sessionEvents.push({\n sessionId,\n source: TOOL_ID,\n project,\n timestamp,\n role,\n });\n }\n\n const settingsPath = join(\n dirname(filePath),\n `${basename(filePath, \".jsonl\")}.settings.json`,\n );\n const settingsContent = readFileSafe(settingsPath);\n if (!settingsContent || firstMessageTimestamp === null) continue;\n\n let settings: DroidSettings;\n try {\n settings = JSON.parse(settingsContent) as DroidSettings;\n } catch {\n continue;\n }\n\n const tokenUsage = settings.tokenUsage;\n if (!tokenUsage) continue;\n\n const cachedTokens = toSafeNumber(tokenUsage.cacheReadTokens);\n const reasoningTokens = toSafeNumber(tokenUsage.thinkingTokens);\n const inputTokens = Math.max(\n 0,\n toSafeNumber(tokenUsage.inputTokens) - cachedTokens,\n );\n const outputTokens = Math.max(\n 0,\n toSafeNumber(tokenUsage.outputTokens) - reasoningTokens,\n );\n\n if (\n inputTokens === 0 &&\n outputTokens === 0 &&\n cachedTokens === 0 &&\n reasoningTokens === 0\n ) {\n continue;\n }\n\n entries.push({\n sessionId,\n source: TOOL_ID,\n model: settings.model || \"unknown\",\n project,\n timestamp: firstMessageTimestamp,\n inputTokens,\n outputTokens,\n reasoningTokens,\n cachedTokens,\n });\n }\n\n return {\n buckets: aggregateToBuckets(entries),\n sessions: extractSessions(sessionEvents, entries),\n };\n }\n\n isInstalled(): boolean {\n return existsSync(this.dataDir);\n }\n}\n\nregisterParser(new DroidParser());\n","import { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { aggregateToBuckets } from \"../domain/aggregator\";\nimport { extractSessions } from \"../domain/session-extractor\";\nimport type {\n ParseResult,\n SessionEvent,\n TokenUsageEntry,\n} from \"../domain/types\";\nimport {\n findJsonlFiles,\n parseJsonl,\n readFileSafe,\n} from \"../infrastructure/fs/utils\";\nimport { registerParser } from \"./registry\";\nimport type { IParser, ToolDefinition } from \"./types\";\n\nconst TOOL_ID = \"pi-coding-agent\";\nconst TOOL_NAME = \"pi\";\nconst DEFAULT_SESSIONS_DIR = join(homedir(), \".pi\", \"agent\", \"sessions\");\n\ninterface PiUsage {\n input?: number;\n inputTokens?: number;\n output?: number;\n outputTokens?: number;\n cacheRead?: number;\n cacheReadTokens?: number;\n cache_read?: number;\n reasoningOutputTokens?: number;\n thinkingTokens?: number;\n thoughts?: number;\n}\n\ninterface PiEvent {\n type?: string;\n id?: string;\n timestamp?: string;\n cwd?: string;\n message?: {\n role?: string;\n timestamp?: string;\n model?: string;\n usage?: PiUsage;\n };\n}\n\nfunction createToolDefinition(dataDir: string): ToolDefinition {\n return {\n id: TOOL_ID,\n name: TOOL_NAME,\n dataDir,\n };\n}\n\nfunction toSafeNumber(value: unknown): number {\n const numberValue = Number(value);\n return Number.isFinite(numberValue) ? numberValue : 0;\n}\n\nfunction getPathLeaf(value: string): string {\n const normalized = value.replace(/\\\\/g, \"/\").replace(/\\/+$/, \"\");\n const leaf = normalized.split(\"/\").filter(Boolean).pop();\n return leaf || \"unknown\";\n}\n\nfunction normalizeForPrefix(value: string): string {\n return value.replace(/\\\\/g, \"/\").replace(/\\/+$/, \"\");\n}\n\nfunction getUsageNumber(usage: PiUsage, ...keys: Array<keyof PiUsage>): number {\n for (const key of keys) {\n const value = usage[key];\n const numberValue = toSafeNumber(value);\n if (numberValue > 0) {\n return numberValue;\n }\n }\n\n return 0;\n}\n\nexport function extractPiProjectFromCwd(cwd: string): string {\n return getPathLeaf(cwd);\n}\n\nexport function extractPiProjectFromDir(\n filePath: string,\n sessionsDir = DEFAULT_SESSIONS_DIR,\n): string {\n const normalizedFilePath = normalizeForPrefix(filePath);\n const normalizedSessionsDir = normalizeForPrefix(sessionsDir);\n const prefix = `${normalizedSessionsDir}/`;\n\n if (!normalizedFilePath.startsWith(prefix)) {\n return \"unknown\";\n }\n\n const relativePath = normalizedFilePath.slice(prefix.length);\n const firstSegment = relativePath.split(\"/\")[0];\n if (!firstSegment) {\n return \"unknown\";\n }\n\n try {\n const decoded = decodeURIComponent(firstSegment);\n if (decoded.includes(\"/\") || decoded.includes(\"\\\\\")) {\n return getPathLeaf(decoded);\n }\n } catch {\n // Fall back to slug parsing when the segment is not URI-encoded.\n }\n\n const slugParts = firstSegment.split(\"-\").filter(Boolean);\n return slugParts.length > 0 ? slugParts[slugParts.length - 1] : \"unknown\";\n}\n\nexport class PiCodingAgentParser implements IParser {\n readonly tool: ToolDefinition;\n\n constructor(private readonly sessionsDir = DEFAULT_SESSIONS_DIR) {\n this.tool = createToolDefinition(sessionsDir);\n }\n\n async parse(): Promise<ParseResult> {\n const sessionFiles = findJsonlFiles(this.sessionsDir);\n if (sessionFiles.length === 0) {\n return { buckets: [], sessions: [] };\n }\n\n const entries: TokenUsageEntry[] = [];\n const sessionEvents: SessionEvent[] = [];\n const seenEntryIds = new Set<string>();\n\n for (const filePath of sessionFiles) {\n const content = readFileSafe(filePath);\n if (!content) continue;\n\n const rows = parseJsonl<PiEvent>(content);\n if (rows.length === 0) continue;\n\n let sessionId = filePath;\n let project = extractPiProjectFromDir(filePath, this.sessionsDir);\n\n for (const row of rows) {\n if (row.type !== \"session\") continue;\n if (row.id) {\n sessionId = row.id;\n }\n if (row.cwd) {\n project = extractPiProjectFromCwd(row.cwd);\n }\n break;\n }\n\n for (const row of rows) {\n if (row.type !== \"message\") continue;\n\n const message = row.message;\n if (!message) continue;\n\n const rawTimestamp = row.timestamp || message.timestamp;\n if (!rawTimestamp) continue;\n\n const timestamp = new Date(rawTimestamp);\n if (Number.isNaN(timestamp.getTime())) continue;\n\n if (message.role === \"user\" || message.role === \"assistant\") {\n sessionEvents.push({\n sessionId,\n source: TOOL_ID,\n project,\n timestamp,\n role: message.role,\n });\n }\n\n if (message.role !== \"assistant\") continue;\n\n const usage = message.usage;\n if (!usage) continue;\n\n const inputTokens = getUsageNumber(usage, \"input\", \"inputTokens\");\n const outputTokens = getUsageNumber(usage, \"output\", \"outputTokens\");\n const cachedTokens = getUsageNumber(\n usage,\n \"cacheRead\",\n \"cacheReadTokens\",\n \"cache_read\",\n );\n const reasoningTokens = getUsageNumber(\n usage,\n \"reasoningOutputTokens\",\n \"thinkingTokens\",\n \"thoughts\",\n );\n\n if (\n inputTokens === 0 &&\n outputTokens === 0 &&\n cachedTokens === 0 &&\n reasoningTokens === 0\n ) {\n continue;\n }\n\n if (row.id) {\n if (seenEntryIds.has(row.id)) continue;\n seenEntryIds.add(row.id);\n }\n\n entries.push({\n sessionId,\n source: TOOL_ID,\n model: message.model || \"unknown\",\n project,\n timestamp,\n inputTokens,\n outputTokens,\n reasoningTokens,\n cachedTokens,\n });\n }\n }\n\n return {\n buckets: aggregateToBuckets(entries),\n sessions: extractSessions(sessionEvents, entries),\n };\n }\n\n isInstalled(): boolean {\n return existsSync(this.sessionsDir);\n }\n}\n\nregisterParser(new PiCodingAgentParser());\n","import { Command, Option } from \"commander\";\nimport { handleConfig } from \"./commands/config\";\nimport { runDaemon } from \"./commands/daemon\";\nimport { runHome } from \"./commands/home\";\nimport { runInit } from \"./commands/init\";\nimport { runInstallService } from \"./commands/service\";\nimport { runStatus } from \"./commands/status\";\nimport { runSyncCommand } from \"./commands/sync\";\nimport { runUninstall } from \"./commands/uninstall\";\nimport { getCliVersion } from \"./infrastructure/runtime/cli-version\";\nimport { isInteractiveTerminal } from \"./infrastructure/ui/prompts\";\n\nconst CLI_VERSION = getCliVersion();\n\nexport function createCli(): Command {\n const program = new Command();\n\n program\n .name(\"tokenarena\")\n .description(\"Track token burn across AI coding tools\")\n .version(CLI_VERSION)\n .showHelpAfterError()\n .showSuggestionAfterError()\n .helpCommand(\"help [command]\", \"Display help for command\");\n\n // Default action: show help or error for unknown commands\n program.action(async () => {\n const userArgs = process.argv.slice(2).filter((a) => !a.startsWith(\"-\"));\n if (userArgs.length > 0) {\n program.error(`unknown command '${userArgs[0]}'`);\n }\n if (isInteractiveTerminal()) {\n await runHome(program);\n return;\n }\n program.help();\n });\n\n // init command\n program\n .command(\"init\")\n .description(\"Initialize configuration with API key\")\n .option(\"--api-url <url>\", \"Custom API server URL\")\n .action(async (opts) => {\n await runInit(opts);\n });\n\n // sync command\n program\n .command(\"sync\")\n .description(\"Manually sync usage data to server\")\n .addOption(new Option(\"--quiet\").hideHelp())\n .action(async (opts) => {\n await runSyncCommand(opts);\n });\n\n // daemon command\n program\n .command(\"daemon\")\n .description(\"Run continuous sync (every 5 minutes by default)\")\n .option(\"--interval <ms>\", \"Sync interval in milliseconds\", parseInt)\n .action(async (opts) => {\n await runDaemon(opts);\n });\n\n // service command\n program\n .command(\"service [action]\")\n .description(\n \"Manage systemd user service (setup|start|stop|restart|status|uninstall)\",\n )\n .action(async (action) => {\n await runInstallService({ action });\n });\n\n // status command\n program\n .command(\"status\")\n .description(\"Show configuration and detected tools\")\n .action(async () => {\n await runStatus();\n });\n\n // config command (with subcommands)\n program\n .command(\"config\")\n .description(\"Manage configuration\")\n .argument(\"[subcommand]\", \"get|set|show\")\n .argument(\"[key]\", \"Config key\")\n .argument(\"[value]\", \"Config value\")\n .allowUnknownOption(true)\n .action(async (subcommand, key, value) => {\n await handleConfig(\n [subcommand, key, value].filter(\n (item): item is string => typeof item === \"string\",\n ),\n );\n });\n\n // uninstall command\n program\n .command(\"uninstall\")\n .description(\"Remove all local configuration and data\")\n .action(async () => {\n await runUninstall();\n });\n\n return program;\n}\n","import { randomUUID } from \"node:crypto\";\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\nimport { getConfigHome } from \"../xdg\";\n\nexport interface Config {\n apiKey: string;\n apiUrl: string;\n deviceId?: string;\n syncInterval?: number;\n logLevel?: \"debug\" | \"info\" | \"warn\" | \"error\";\n}\n\nconst CONFIG_DIR = join(getConfigHome(), \"tokenarena\");\nconst isDev = process.env.TOKEN_ARENA_DEV === \"1\";\nconst CONFIG_FILE = join(CONFIG_DIR, isDev ? \"config.dev.json\" : \"config.json\");\n\nconst DEFAULT_API_URL = \"https://token.poco-ai.com\";\nconst VALID_CONFIG_KEYS = [\n \"apiKey\",\n \"apiUrl\",\n \"deviceId\",\n \"syncInterval\",\n \"logLevel\",\n];\n\nexport function getConfigPath(): string {\n return CONFIG_FILE;\n}\n\nexport function getConfigDir(): string {\n return CONFIG_DIR;\n}\n\nexport function loadConfig(): Config | null {\n if (!existsSync(CONFIG_FILE)) return null;\n try {\n const raw = readFileSync(CONFIG_FILE, \"utf-8\");\n const config = JSON.parse(raw) as Config;\n // Ensure apiUrl has a default\n if (!config.apiUrl) {\n config.apiUrl = DEFAULT_API_URL;\n }\n return config;\n } catch {\n return null;\n }\n}\n\nexport function saveConfig(config: Config): void {\n mkdirSync(CONFIG_DIR, { recursive: true });\n writeFileSync(CONFIG_FILE, `${JSON.stringify(config, null, 2)}\\n`, \"utf-8\");\n}\n\nexport function deleteConfig(): void {\n if (existsSync(CONFIG_FILE)) {\n unlinkSync(CONFIG_FILE);\n }\n}\n\nexport function getOrCreateDeviceId(config: Config): string {\n if (config.deviceId) return config.deviceId;\n\n const next = randomUUID();\n saveConfig({ ...config, deviceId: next });\n\n return next;\n}\n\nexport function validateApiKey(key: string): boolean {\n return key.startsWith(\"ta_\");\n}\n\nexport function isValidConfigKey(key: string): boolean {\n return VALID_CONFIG_KEYS.includes(key);\n}\n\nexport function getDefaultApiUrl(): string {\n return process.env.TOKEN_ARENA_API_URL || DEFAULT_API_URL;\n}\n","import { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\n/**\n * XDG Base Directory specification helpers.\n * @see https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html\n */\n\n/** User-specific configuration directory (`XDG_CONFIG_HOME`, default `~/.config`) */\nexport function getConfigHome(): string {\n return process.env.XDG_CONFIG_HOME || join(homedir(), \".config\");\n}\n\n/** User-specific data directory (`XDG_DATA_HOME`, default `~/.local/share`) */\nexport function getDataHome(): string {\n return process.env.XDG_DATA_HOME || join(homedir(), \".local\", \"share\");\n}\n\n/** User-specific cache directory (`XDG_CACHE_HOME`, default `~/.cache`) */\nexport function getCacheHome(): string {\n return process.env.XDG_CACHE_HOME || join(homedir(), \".cache\");\n}\n\n/** User-specific state directory (`XDG_STATE_HOME`, default `~/.local/state`) */\nexport function getStateHome(): string {\n return process.env.XDG_STATE_HOME || join(homedir(), \".local\", \"state\");\n}\n\n/**\n * User-specific runtime directory (`XDG_RUNTIME_DIR`).\n * Falls back to state home when not set (e.g. on macOS).\n */\nexport function getRuntimeDir(): string {\n return process.env.XDG_RUNTIME_DIR || getStateHome();\n}\n","import {\n getDefaultApiUrl,\n isValidConfigKey,\n loadConfig,\n saveConfig,\n validateApiKey,\n} from \"../infrastructure/config/manager\";\nimport {\n formatBullet,\n formatHeader,\n formatKeyValue,\n formatSection,\n maskSecret,\n} from \"../infrastructure/ui/format\";\nimport {\n isInteractiveTerminal,\n promptPassword,\n promptSelect,\n promptText,\n} from \"../infrastructure/ui/prompts\";\nimport { logger } from \"../utils/logger\";\n\nconst VALID_KEYS = [\"apiKey\", \"apiUrl\", \"syncInterval\", \"logLevel\"] as const;\n\ntype ConfigKey = (typeof VALID_KEYS)[number];\ntype ConfigSubcommand = \"get\" | \"set\" | \"show\";\n\nfunction isConfigKey(value: string): value is ConfigKey {\n return isValidConfigKey(value) && VALID_KEYS.includes(value as ConfigKey);\n}\n\nfunction formatConfigValue(key: ConfigKey, value: unknown): string {\n if (value === undefined || value === null || value === \"\") {\n return \"(empty)\";\n }\n\n if (key === \"apiKey\") {\n return maskSecret(String(value));\n }\n\n if (key === \"syncInterval\") {\n const ms = Number(value);\n const minutes = Math.round(ms / 60000);\n return `${minutes} 分钟 (${ms} ms)`;\n }\n\n return String(value);\n}\n\nasync function promptConfigSubcommand(): Promise<ConfigSubcommand> {\n logger.info(\n formatHeader(\"配置中心\", \"通过交互式菜单查看或修改 TokenArena CLI 配置。\"),\n );\n\n return promptSelect<ConfigSubcommand>({\n message: \"请选择配置操作\",\n choices: [\n {\n name: \"查看完整配置\",\n value: \"show\",\n description: \"以更适合阅读的方式展示当前配置\",\n },\n {\n name: \"读取单个配置项\",\n value: \"get\",\n description: \"查看某个配置键当前保存的值\",\n },\n {\n name: \"修改配置项\",\n value: \"set\",\n description: \"更新 API Key、API 地址、同步间隔或日志级别\",\n },\n ],\n });\n}\n\nasync function promptConfigKey(message: string): Promise<ConfigKey> {\n return promptSelect<ConfigKey>({\n message,\n choices: [\n {\n name: \"apiKey\",\n value: \"apiKey\",\n description: \"上传数据时使用的 CLI API Key\",\n },\n {\n name: \"apiUrl\",\n value: \"apiUrl\",\n description: \"TokenArena 服务端地址\",\n },\n {\n name: \"syncInterval\",\n value: \"syncInterval\",\n description: \"daemon 默认同步间隔(毫秒)\",\n },\n {\n name: \"logLevel\",\n value: \"logLevel\",\n description: \"CLI 日志级别\",\n },\n ],\n });\n}\n\nasync function promptSyncIntervalValue(\n existingValue?: number,\n): Promise<string> {\n const preset = await promptSelect<string>({\n message: \"请选择默认同步间隔\",\n choices: [\n {\n name: \"5 分钟\",\n value: String(5 * 60_000),\n description: \"适合作为默认值\",\n },\n {\n name: \"10 分钟\",\n value: String(10 * 60_000),\n description: \"更省电,仍保持较及时同步\",\n },\n {\n name: \"30 分钟\",\n value: String(30 * 60_000),\n description: \"适合低频使用场景\",\n },\n {\n name: \"60 分钟\",\n value: String(60 * 60_000),\n description: \"长周期后台同步\",\n },\n {\n name: \"自定义(毫秒)\",\n value: \"custom\",\n description: \"输入任意正整数毫秒值\",\n },\n ],\n });\n\n if (preset !== \"custom\") {\n return preset;\n }\n\n return promptText({\n message: \"请输入 syncInterval(毫秒)\",\n defaultValue: existingValue ? String(existingValue) : undefined,\n validate: (value) => {\n const parsed = Number.parseInt(value, 10);\n if (Number.isNaN(parsed) || parsed <= 0) {\n return \"请输入大于 0 的毫秒数,例如 300000。\";\n }\n return true;\n },\n });\n}\n\nasync function promptConfigValue(\n key: ConfigKey,\n existingValue?: unknown,\n): Promise<string> {\n switch (key) {\n case \"apiKey\":\n return promptPassword({\n message: \"请输入新的 CLI API Key\",\n validate: (value) =>\n validateApiKey(value) || 'API Key 必须以 \"ta_\" 开头。',\n });\n case \"apiUrl\":\n return promptText({\n message: \"请输入 API 服务地址\",\n defaultValue:\n typeof existingValue === \"string\" && existingValue.length > 0\n ? existingValue\n : getDefaultApiUrl(),\n validate: (value) => {\n try {\n const url = new URL(value);\n return Boolean(url.protocol && url.host) || \"请输入合法 URL。\";\n } catch {\n return \"请输入合法 URL。\";\n }\n },\n });\n case \"syncInterval\":\n return promptSyncIntervalValue(\n typeof existingValue === \"number\" ? existingValue : undefined,\n );\n case \"logLevel\":\n return promptSelect<string>({\n message: \"请选择日志级别\",\n choices: [\n {\n name: \"info\",\n value: \"info\",\n description: \"默认,输出常规进度与提示\",\n },\n {\n name: \"warn\",\n value: \"warn\",\n description: \"仅输出警告与错误\",\n },\n {\n name: \"error\",\n value: \"error\",\n description: \"只输出错误\",\n },\n {\n name: \"debug\",\n value: \"debug\",\n description: \"输出更详细的调试日志\",\n },\n ],\n });\n }\n}\n\nfunction printConfigShow(): void {\n const config = loadConfig();\n\n if (!config) {\n logger.info(formatHeader(\"当前配置\", \"尚未创建本地配置文件。\"));\n logger.info(formatBullet(\"运行 tokenarena init 完成首次配置。\", \"warning\"));\n return;\n }\n\n logger.info(formatHeader(\"当前配置\"));\n logger.info(formatSection(\"基础配置\"));\n logger.info(formatKeyValue(\"API Key\", maskSecret(config.apiKey || \"\")));\n logger.info(\n formatKeyValue(\"API 地址\", config.apiUrl || \"https://token.poco-ai.com\"),\n );\n logger.info(\n formatKeyValue(\n \"同步间隔\",\n config.syncInterval\n ? `${Math.round(config.syncInterval / 60000)} 分钟 (${config.syncInterval} ms)`\n : \"未设置(daemon 默认 5 分钟)\",\n ),\n );\n logger.info(formatKeyValue(\"日志级别\", config.logLevel || \"info\"));\n if (config.deviceId) {\n logger.info(formatKeyValue(\"设备 ID\", maskSecret(config.deviceId, 12)));\n }\n}\n\nexport async function handleConfig(args: string[]): Promise<void> {\n const interactive = isInteractiveTerminal();\n let sub = args[0] as ConfigSubcommand | undefined;\n\n if (!sub) {\n if (!interactive) {\n logger.error(\"Usage: tokenarena config <get|set|show>\");\n process.exit(1);\n }\n sub = await promptConfigSubcommand();\n }\n\n switch (sub) {\n case \"get\": {\n let key = args[1];\n if (!key) {\n if (!interactive) {\n logger.error(\"Usage: tokenarena config get <key>\");\n process.exit(1);\n }\n key = await promptConfigKey(\"请选择要读取的配置项\");\n }\n\n if (!isConfigKey(key)) {\n logger.error(`Unknown config key: ${key}`);\n logger.error(`Valid keys: ${VALID_KEYS.join(\", \")}`);\n process.exit(1);\n }\n\n const config = loadConfig();\n if (!config || !(key in config)) {\n process.exit(0);\n }\n\n const record = config as unknown as Record<string, unknown>;\n console.log(record[key] ?? \"\");\n break;\n }\n case \"set\": {\n let key = args[1];\n if (!key) {\n if (!interactive) {\n logger.error(\"Usage: tokenarena config set <key> <value>\");\n process.exit(1);\n }\n key = await promptConfigKey(\"请选择要修改的配置项\");\n }\n\n if (!isConfigKey(key)) {\n logger.error(`Unknown config key: ${key}`);\n logger.error(`Valid keys: ${VALID_KEYS.join(\", \")}`);\n process.exit(1);\n }\n\n const config = loadConfig() || {\n apiKey: \"\",\n apiUrl: getDefaultApiUrl(),\n };\n const record = config as unknown as Record<string, unknown>;\n\n let value = args[2];\n if (value === undefined) {\n if (!interactive) {\n logger.error(\"Usage: tokenarena config set <key> <value>\");\n process.exit(1);\n }\n value = await promptConfigValue(key, record[key]);\n }\n\n let normalized: string | number = value;\n if (key === \"apiKey\" && !validateApiKey(value)) {\n logger.error('API Key must start with \"ta_\"');\n process.exit(1);\n }\n\n if (key === \"apiUrl\") {\n try {\n const url = new URL(value);\n normalized = url.toString().replace(/\\/$/, \"\");\n } catch {\n logger.error(\"apiUrl must be a valid URL\");\n process.exit(1);\n }\n }\n\n if (key === \"syncInterval\") {\n normalized = Number.parseInt(value, 10);\n if (Number.isNaN(normalized) || normalized <= 0) {\n logger.error(\"syncInterval must be a positive number (milliseconds)\");\n process.exit(1);\n }\n }\n\n record[key] = normalized;\n saveConfig(config);\n\n if (interactive) {\n logger.info(formatHeader(\"配置已更新\"));\n logger.info(formatKeyValue(key, formatConfigValue(key, normalized)));\n } else {\n logger.info(`Set ${key} = ${normalized}`);\n }\n break;\n }\n case \"show\": {\n if (interactive) {\n printConfigShow();\n } else {\n const config = loadConfig();\n console.log(config ? JSON.stringify(config, null, 2) : \"{}\");\n }\n break;\n }\n default:\n logger.error(`Unknown config subcommand: ${sub || \"(none)\"}`);\n logger.error(\"Usage: tokenarena config <get|set|show>\");\n process.exit(1);\n }\n}\n","import { hostname } from \"node:os\";\nimport { toProjectIdentity } from \"../domain/project-identity\";\nimport type {\n ApiSettings,\n DeviceMetadata,\n SessionMetadata,\n TokenBucket,\n UploadSessionMetadata,\n UploadTokenBucket,\n} from \"../domain/types\";\nimport {\n buildUploadManifestScope,\n diffUploadManifest,\n type UploadManifest,\n type UploadManifestScopeChange,\n} from \"../domain/upload-manifest\";\nimport { ApiClient, getIngestPayloadSize } from \"../infrastructure/api/client\";\nimport {\n type Config,\n getOrCreateDeviceId,\n} from \"../infrastructure/config/manager\";\nimport {\n describeExistingSyncLock,\n tryAcquireSyncLock,\n} from \"../infrastructure/runtime/lock\";\nimport {\n markSyncFailed,\n markSyncStarted,\n markSyncSucceeded,\n type SyncSource,\n} from \"../infrastructure/runtime/state\";\nimport {\n loadUploadManifest,\n saveUploadManifest,\n} from \"../infrastructure/runtime/upload-manifest\";\nimport { logger } from \"../utils/logger\";\nimport { runAllParsers } from \"./parser-service\";\n\nconst BATCH_SIZE = 100;\nconst SESSION_BATCH_SIZE = 500;\nconst PROGRESS_BAR_WIDTH = 28;\n\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes}B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;\n}\n\nfunction renderProgressBar(progress: number): string {\n const safeProgress = Math.max(0, Math.min(progress, 1));\n const filled = Math.round(safeProgress * PROGRESS_BAR_WIDTH);\n return `${\"█\".repeat(filled)}${\"░\".repeat(PROGRESS_BAR_WIDTH - filled)}`;\n}\n\nfunction writeUploadProgress(\n sent: number,\n total: number,\n batchNum: number,\n totalBatches: number,\n): void {\n const pct = total > 0 ? Math.round((sent / total) * 100) : 100;\n const progressBar = renderProgressBar(total > 0 ? sent / total : 1);\n const batchLabel =\n totalBatches > 1 ? ` · batch ${batchNum}/${totalBatches}` : \"\";\n\n process.stdout.write(\n `\\r Uploading ${progressBar} ${String(pct).padStart(3, \" \")}% · ${formatBytes(sent)}/${formatBytes(total)}${batchLabel}\\x1b[K`,\n );\n}\n\nfunction formatScopeChangeReason(reason: UploadManifestScopeChange): string {\n switch (reason) {\n case \"server_or_api_key\":\n return \"server/API key\";\n case \"device_id\":\n return \"device ID\";\n case \"project_identity\":\n return \"project identity settings\";\n }\n}\n\nfunction persistUploadManifest(manifest: UploadManifest, quiet: boolean): void {\n try {\n saveUploadManifest(manifest);\n } catch (error) {\n if (!quiet) {\n logger.warn(\n `Uploaded data, but failed to update the local sync manifest: ${(error as Error).message}`,\n );\n }\n }\n}\n\nexport interface SyncOptions {\n source?: SyncSource;\n throws?: boolean;\n quiet?: boolean;\n}\n\nexport interface SyncResult {\n buckets: number;\n sessions: number;\n skipped?: \"locked\";\n}\n\nfunction toDeviceMetadata(config: Config): DeviceMetadata {\n return {\n deviceId: getOrCreateDeviceId(config),\n hostname: hostname().replace(/\\.local$/, \"\"),\n };\n}\n\nfunction toUploadBuckets(\n buckets: TokenBucket[],\n settings: ApiSettings,\n device: DeviceMetadata,\n): UploadTokenBucket[] {\n const aggregated = new Map<string, UploadTokenBucket>();\n\n for (const bucket of buckets) {\n const project = toProjectIdentity({\n project: bucket.project || \"unknown\",\n mode: settings.projectMode,\n salt: settings.projectHashSalt,\n });\n const key = [\n bucket.source,\n bucket.model,\n project.projectKey,\n bucket.bucketStart,\n device.deviceId,\n ].join(\"|\");\n\n const existing = aggregated.get(key);\n if (existing) {\n existing.inputTokens += bucket.inputTokens;\n existing.outputTokens += bucket.outputTokens;\n existing.reasoningTokens += bucket.reasoningTokens || 0;\n existing.cachedTokens += bucket.cachedTokens || 0;\n existing.totalTokens += bucket.totalTokens;\n continue;\n }\n\n aggregated.set(key, {\n source: bucket.source,\n model: bucket.model,\n projectKey: project.projectKey,\n projectLabel: project.projectLabel,\n bucketStart: bucket.bucketStart,\n deviceId: device.deviceId,\n hostname: device.hostname,\n inputTokens: bucket.inputTokens,\n outputTokens: bucket.outputTokens,\n reasoningTokens: bucket.reasoningTokens || 0,\n cachedTokens: bucket.cachedTokens || 0,\n totalTokens: bucket.totalTokens,\n });\n }\n\n return Array.from(aggregated.values());\n}\n\nfunction toUploadSessions(\n sessions: SessionMetadata[],\n settings: ApiSettings,\n device: DeviceMetadata,\n): UploadSessionMetadata[] {\n return sessions.map((session) => {\n const project = toProjectIdentity({\n project: session.project || \"unknown\",\n mode: settings.projectMode,\n salt: settings.projectHashSalt,\n });\n\n return {\n source: session.source,\n projectKey: project.projectKey,\n projectLabel: project.projectLabel,\n sessionHash: session.sessionHash,\n deviceId: device.deviceId,\n hostname: device.hostname,\n firstMessageAt: session.firstMessageAt,\n lastMessageAt: session.lastMessageAt,\n durationSeconds: session.durationSeconds,\n activeSeconds: session.activeSeconds,\n messageCount: session.messageCount,\n userMessageCount: session.userMessageCount,\n inputTokens: session.inputTokens,\n outputTokens: session.outputTokens,\n reasoningTokens: session.reasoningTokens,\n cachedTokens: session.cachedTokens,\n totalTokens: session.totalTokens,\n primaryModel: session.primaryModel,\n modelUsages: session.modelUsages,\n };\n });\n}\n\nclass SyncFailure extends Error {\n constructor(\n message: string,\n readonly kind: \"auth_error\" | \"error\",\n readonly causeError?: Error,\n ) {\n super(message);\n }\n}\n\nexport async function runSync(\n config: Config,\n opts: SyncOptions = {},\n): Promise<SyncResult> {\n const { quiet = false, source = \"manual\", throws = false } = opts;\n\n const lock = tryAcquireSyncLock(source);\n if (!lock) {\n const detail = describeExistingSyncLock();\n const message = detail\n ? `Another sync is already running (${detail}). Skipping.`\n : \"Another sync is already running. Skipping.\";\n\n markSyncFailed(source, message, \"skipped_locked\");\n logger.info(message);\n return {\n buckets: 0,\n sessions: 0,\n skipped: \"locked\",\n };\n }\n\n markSyncStarted(source);\n\n let totalIngested = 0;\n let totalSessionsSynced = 0;\n let caughtError: SyncFailure | null = null;\n\n try {\n const {\n buckets: allBuckets,\n sessions: allSessions,\n parserResults,\n } = await runAllParsers();\n\n if (allBuckets.length === 0 && allSessions.length === 0) {\n if (!quiet) {\n logger.info(\"No new usage data found.\");\n }\n markSyncSucceeded(source, { buckets: 0, sessions: 0 });\n return { buckets: 0, sessions: 0 };\n }\n\n if (!quiet && parserResults.length > 0) {\n for (const p of parserResults) {\n const parts: string[] = [];\n if (p.buckets > 0) parts.push(`${p.buckets} buckets`);\n if (p.sessions > 0) parts.push(`${p.sessions} sessions`);\n logger.info(` ${p.source}: ${parts.join(\", \")}`);\n }\n }\n\n const apiUrl = config.apiUrl || \"https://token.poco-ai.com\";\n const apiClient = new ApiClient(apiUrl, config.apiKey);\n\n let settings: ApiSettings | null;\n try {\n settings = await apiClient.fetchSettings();\n } catch (error) {\n if ((error as Error).message === \"UNAUTHORIZED\") {\n throw new SyncFailure(\n \"Invalid API key. Run `tokenarena init` to reconfigure.\",\n \"auth_error\",\n error as Error,\n );\n }\n\n settings = null;\n }\n\n if (!settings) {\n throw new SyncFailure(\n \"Could not fetch usage settings. Check your server URL and API key.\",\n \"error\",\n );\n }\n\n const device = toDeviceMetadata(config);\n const manifestScope = buildUploadManifestScope({\n apiKey: config.apiKey,\n apiUrl,\n deviceId: device.deviceId,\n settings,\n });\n const uploadBuckets = toUploadBuckets(allBuckets, settings, device);\n const uploadSessions = toUploadSessions(allSessions, settings, device);\n const uploadDiff = diffUploadManifest({\n buckets: uploadBuckets,\n previous: loadUploadManifest(),\n scope: manifestScope,\n sessions: uploadSessions,\n });\n const changedBuckets = uploadDiff.bucketsToUpload;\n const changedSessions = uploadDiff.sessionsToUpload;\n\n if (!quiet && uploadDiff.scopeChangedReasons.length > 0) {\n logger.warn(\n `Upload scope changed (${uploadDiff.scopeChangedReasons.map(formatScopeChangeReason).join(\", \")}). TokenArena will upload the current snapshot again, but existing remote records from the previous scope will not be deleted automatically.`,\n );\n }\n\n if (\n !quiet &&\n (uploadDiff.removedBuckets > 0 || uploadDiff.removedSessions > 0)\n ) {\n const parts: string[] = [];\n if (uploadDiff.removedBuckets > 0) {\n parts.push(`${uploadDiff.removedBuckets} buckets`);\n }\n if (uploadDiff.removedSessions > 0) {\n parts.push(`${uploadDiff.removedSessions} sessions`);\n }\n logger.warn(\n `Detected ${parts.join(\" + \")} that were present in the previous local snapshot but are missing now. Remote deletions are not supported yet, so renamed projects or removed local logs may leave stale data online.`,\n );\n }\n\n if (changedBuckets.length === 0 && changedSessions.length === 0) {\n if (!quiet) {\n const skippedParts: string[] = [];\n if (uploadDiff.unchangedBuckets > 0) {\n skippedParts.push(`${uploadDiff.unchangedBuckets} unchanged buckets`);\n }\n if (uploadDiff.unchangedSessions > 0) {\n skippedParts.push(\n `${uploadDiff.unchangedSessions} unchanged sessions`,\n );\n }\n logger.info(\n skippedParts.length > 0\n ? `No new or updated usage data to upload. Skipped ${skippedParts.join(\" + \")}.`\n : \"No new or updated usage data to upload.\",\n );\n }\n persistUploadManifest(uploadDiff.nextManifest, quiet);\n markSyncSucceeded(source, { buckets: 0, sessions: 0 });\n return { buckets: 0, sessions: 0 };\n }\n\n const bucketBatches = Math.ceil(changedBuckets.length / BATCH_SIZE);\n const sessionBatches = Math.ceil(\n changedSessions.length / SESSION_BATCH_SIZE,\n );\n const totalBatches = Math.max(bucketBatches, sessionBatches, 1);\n const batchPayloadSizes = Array.from(\n { length: totalBatches },\n (_, batchIdx) =>\n getIngestPayloadSize(\n device,\n changedBuckets.slice(\n batchIdx * BATCH_SIZE,\n (batchIdx + 1) * BATCH_SIZE,\n ),\n changedSessions.slice(\n batchIdx * SESSION_BATCH_SIZE,\n (batchIdx + 1) * SESSION_BATCH_SIZE,\n ),\n ),\n );\n const totalPayloadBytes = batchPayloadSizes.reduce(\n (sum, size) => sum + size,\n 0,\n );\n let uploadedBytesBeforeBatch = 0;\n\n if (!quiet) {\n const parts: string[] = [];\n if (changedBuckets.length > 0) {\n parts.push(`${changedBuckets.length} buckets`);\n }\n if (changedSessions.length > 0) {\n parts.push(`${changedSessions.length} sessions`);\n }\n const skippedParts: string[] = [];\n if (uploadDiff.unchangedBuckets > 0) {\n skippedParts.push(`${uploadDiff.unchangedBuckets} unchanged buckets`);\n }\n if (uploadDiff.unchangedSessions > 0) {\n skippedParts.push(`${uploadDiff.unchangedSessions} unchanged sessions`);\n }\n logger.info(\n `Uploading ${parts.join(\" + \")} (${totalBatches} batch${totalBatches > 1 ? \"es\" : \"\"}${skippedParts.length > 0 ? `, skipped ${skippedParts.join(\" + \")}` : \"\"})...`,\n );\n }\n\n for (let batchIdx = 0; batchIdx < totalBatches; batchIdx++) {\n const batch = changedBuckets.slice(\n batchIdx * BATCH_SIZE,\n (batchIdx + 1) * BATCH_SIZE,\n );\n const batchSessions = changedSessions.slice(\n batchIdx * SESSION_BATCH_SIZE,\n (batchIdx + 1) * SESSION_BATCH_SIZE,\n );\n const batchNum = batchIdx + 1;\n\n const result = await apiClient.ingest(\n device,\n batch,\n batchSessions.length > 0 ? batchSessions : undefined,\n quiet\n ? undefined\n : (sent, total) => {\n writeUploadProgress(\n uploadedBytesBeforeBatch + sent,\n totalPayloadBytes || total,\n batchNum,\n totalBatches,\n );\n },\n );\n\n totalIngested += result.ingested ?? batch.length;\n totalSessionsSynced += result.sessions ?? batchSessions.length;\n uploadedBytesBeforeBatch += batchPayloadSizes[batchIdx] ?? 0;\n }\n\n if (!quiet && (totalBatches > 1 || changedBuckets.length > 0)) {\n writeUploadProgress(\n totalPayloadBytes,\n totalPayloadBytes,\n totalBatches,\n totalBatches,\n );\n process.stdout.write(\"\\n\");\n }\n\n const syncParts = [`${totalIngested} buckets`];\n if (totalSessionsSynced > 0) {\n syncParts.push(`${totalSessionsSynced} sessions`);\n }\n logger.info(`Synced ${syncParts.join(\" + \")}.`);\n\n if (!quiet) {\n logger.info(`\\nView your dashboard at: ${apiUrl}/usage`);\n }\n\n persistUploadManifest(uploadDiff.nextManifest, quiet);\n markSyncSucceeded(source, {\n buckets: totalIngested,\n sessions: totalSessionsSynced,\n });\n\n return {\n buckets: totalIngested,\n sessions: totalSessionsSynced,\n };\n } catch (error) {\n const httpErr = error as Error & { statusCode?: number };\n\n if (httpErr.message === \"UNAUTHORIZED\") {\n caughtError = new SyncFailure(\n \"Invalid API key. Run `tokenarena init` to reconfigure.\",\n \"auth_error\",\n error as Error,\n );\n } else if (error instanceof SyncFailure) {\n caughtError = error;\n } else if (totalIngested > 0) {\n caughtError = new SyncFailure(\n `Sync partially completed (${totalIngested} buckets uploaded). ${httpErr.message}`,\n \"error\",\n error as Error,\n );\n } else {\n caughtError = new SyncFailure(\n `Sync failed: ${httpErr.message}`,\n \"error\",\n error as Error,\n );\n }\n\n markSyncFailed(source, caughtError.message, caughtError.kind);\n } finally {\n lock.release();\n }\n\n if (!caughtError) {\n return {\n buckets: totalIngested,\n sessions: totalSessionsSynced,\n };\n }\n\n logger.error(caughtError.message);\n if (throws) {\n throw caughtError.causeError ?? caughtError;\n }\n process.exit(1);\n}\n","import { createHmac } from \"node:crypto\";\n\nexport function toProjectIdentity(input: {\n project: string;\n mode: \"hashed\" | \"raw\" | \"disabled\";\n salt: string;\n}) {\n if (input.mode === \"disabled\") {\n return { projectKey: \"unknown\", projectLabel: \"Unknown Project\" };\n }\n\n if (input.mode === \"raw\") {\n return { projectKey: input.project, projectLabel: input.project };\n }\n\n const projectKey = createHmac(\"sha256\", input.salt)\n .update(input.project)\n .digest(\"hex\")\n .slice(0, 16);\n\n return {\n projectKey,\n projectLabel: `Project ${projectKey.slice(0, 6)}`,\n };\n}\n","import { createHash } from \"node:crypto\";\nimport type {\n ApiSettings,\n UploadSessionMetadata,\n UploadTokenBucket,\n} from \"./types\";\n\nconst MANIFEST_VERSION = 1 as const;\n\nfunction shortHash(value: string): string {\n return createHash(\"sha256\").update(value).digest(\"hex\").slice(0, 16);\n}\n\nfunction normalizeApiUrl(apiUrl: string): string {\n return apiUrl.replace(/\\/+$/, \"\");\n}\n\nexport interface UploadManifestScope {\n apiKeyHash: string;\n apiUrl: string;\n deviceId: string;\n projectHashSaltHash: string;\n projectMode: ApiSettings[\"projectMode\"];\n}\n\nexport interface UploadManifest {\n buckets: Record<string, string>;\n scope: UploadManifestScope;\n sessions: Record<string, string>;\n updatedAt: string;\n version: typeof MANIFEST_VERSION;\n}\n\nexport interface UploadManifestDiff {\n bucketsToUpload: UploadTokenBucket[];\n nextManifest: UploadManifest;\n removedBuckets: number;\n removedSessions: number;\n scopeChangedReasons: UploadManifestScopeChange[];\n sessionsToUpload: UploadSessionMetadata[];\n unchangedBuckets: number;\n unchangedSessions: number;\n}\n\nexport type UploadManifestScopeChange =\n | \"device_id\"\n | \"project_identity\"\n | \"server_or_api_key\";\n\nexport function buildUploadManifestScope(input: {\n apiKey: string;\n apiUrl: string;\n deviceId: string;\n settings: ApiSettings;\n}): UploadManifestScope {\n return {\n apiKeyHash: shortHash(input.apiKey),\n apiUrl: normalizeApiUrl(input.apiUrl),\n deviceId: input.deviceId,\n projectHashSaltHash: shortHash(input.settings.projectHashSalt),\n projectMode: input.settings.projectMode,\n };\n}\n\nexport function describeUploadManifestScopeChanges(\n previous: UploadManifestScope,\n current: UploadManifestScope,\n): UploadManifestScopeChange[] {\n const changes: UploadManifestScopeChange[] = [];\n\n if (\n previous.apiUrl !== current.apiUrl ||\n previous.apiKeyHash !== current.apiKeyHash\n ) {\n changes.push(\"server_or_api_key\");\n }\n\n if (previous.deviceId !== current.deviceId) {\n changes.push(\"device_id\");\n }\n\n if (\n previous.projectMode !== current.projectMode ||\n previous.projectHashSaltHash !== current.projectHashSaltHash\n ) {\n changes.push(\"project_identity\");\n }\n\n return changes;\n}\n\nexport function getUploadBucketManifestKey(bucket: UploadTokenBucket): string {\n return [\n bucket.deviceId,\n bucket.source,\n bucket.model,\n bucket.projectKey,\n bucket.bucketStart,\n ].join(\"|\");\n}\n\nexport function getUploadSessionManifestKey(\n session: UploadSessionMetadata,\n): string {\n return [session.deviceId, session.source, session.sessionHash].join(\"|\");\n}\n\nfunction getUploadBucketContentHash(bucket: UploadTokenBucket): string {\n return shortHash(\n JSON.stringify({\n cachedTokens: bucket.cachedTokens,\n hostname: bucket.hostname,\n inputTokens: bucket.inputTokens,\n outputTokens: bucket.outputTokens,\n projectLabel: bucket.projectLabel,\n reasoningTokens: bucket.reasoningTokens,\n totalTokens: bucket.totalTokens,\n }),\n );\n}\n\nfunction getUploadSessionContentHash(session: UploadSessionMetadata): string {\n return shortHash(\n JSON.stringify({\n activeSeconds: session.activeSeconds,\n cachedTokens: session.cachedTokens,\n durationSeconds: session.durationSeconds,\n firstMessageAt: session.firstMessageAt,\n hostname: session.hostname,\n inputTokens: session.inputTokens,\n lastMessageAt: session.lastMessageAt,\n messageCount: session.messageCount,\n modelUsages: session.modelUsages,\n outputTokens: session.outputTokens,\n primaryModel: session.primaryModel,\n projectKey: session.projectKey,\n projectLabel: session.projectLabel,\n reasoningTokens: session.reasoningTokens,\n totalTokens: session.totalTokens,\n userMessageCount: session.userMessageCount,\n }),\n );\n}\n\nfunction buildRecordHashes<T>(\n items: T[],\n getKey: (item: T) => string,\n getHash: (item: T) => string,\n): Record<string, string> {\n const hashes: Record<string, string> = {};\n\n for (const item of items) {\n hashes[getKey(item)] = getHash(item);\n }\n\n return hashes;\n}\n\nexport function createUploadManifest(input: {\n buckets: UploadTokenBucket[];\n scope: UploadManifestScope;\n sessions: UploadSessionMetadata[];\n updatedAt?: string;\n}): UploadManifest {\n return {\n buckets: buildRecordHashes(\n input.buckets,\n getUploadBucketManifestKey,\n getUploadBucketContentHash,\n ),\n scope: input.scope,\n sessions: buildRecordHashes(\n input.sessions,\n getUploadSessionManifestKey,\n getUploadSessionContentHash,\n ),\n updatedAt: input.updatedAt ?? new Date().toISOString(),\n version: MANIFEST_VERSION,\n };\n}\n\nfunction countRemovedRecords(\n previous: Record<string, string>,\n current: Record<string, string>,\n): number {\n let removed = 0;\n\n for (const key of Object.keys(previous)) {\n if (!(key in current)) {\n removed++;\n }\n }\n\n return removed;\n}\n\nexport function diffUploadManifest(input: {\n buckets: UploadTokenBucket[];\n previous: UploadManifest | null;\n scope: UploadManifestScope;\n sessions: UploadSessionMetadata[];\n updatedAt?: string;\n}): UploadManifestDiff {\n const nextManifest = createUploadManifest({\n buckets: input.buckets,\n scope: input.scope,\n sessions: input.sessions,\n updatedAt: input.updatedAt,\n });\n\n const scopeChangedReasons = input.previous\n ? describeUploadManifestScopeChanges(input.previous.scope, input.scope)\n : [];\n\n const previousBuckets =\n input.previous && scopeChangedReasons.length === 0\n ? input.previous.buckets\n : {};\n const previousSessions =\n input.previous && scopeChangedReasons.length === 0\n ? input.previous.sessions\n : {};\n\n const bucketsToUpload = input.buckets.filter((bucket) => {\n const key = getUploadBucketManifestKey(bucket);\n return previousBuckets[key] !== nextManifest.buckets[key];\n });\n const sessionsToUpload = input.sessions.filter((session) => {\n const key = getUploadSessionManifestKey(session);\n return previousSessions[key] !== nextManifest.sessions[key];\n });\n\n return {\n bucketsToUpload,\n nextManifest,\n removedBuckets: countRemovedRecords(previousBuckets, nextManifest.buckets),\n removedSessions: countRemovedRecords(\n previousSessions,\n nextManifest.sessions,\n ),\n scopeChangedReasons,\n sessionsToUpload,\n unchangedBuckets: input.buckets.length - bucketsToUpload.length,\n unchangedSessions: input.sessions.length - sessionsToUpload.length,\n };\n}\n","import http from \"node:http\";\nimport https from \"node:https\";\nimport { URL } from \"node:url\";\nimport type {\n ApiSettings,\n DeviceMetadata,\n IngestResponse,\n UploadSessionMetadata,\n UploadTokenBucket,\n} from \"../../domain/types\";\n\nconst MAX_RETRIES = 3;\nconst INITIAL_DELAY = 1000;\nconst TIMEOUT_MS = 60_000;\n\nexport function getIngestPayloadSize(\n device: DeviceMetadata,\n buckets: UploadTokenBucket[],\n sessions?: UploadSessionMetadata[],\n): number {\n const payload = {\n schemaVersion: 2 as const,\n device,\n buckets,\n sessions: sessions ?? [],\n };\n\n return Buffer.byteLength(JSON.stringify(payload));\n}\n\nexport class ApiClient {\n constructor(\n private apiUrl: string,\n private apiKey: string,\n ) {}\n\n /**\n * Ingest buckets and sessions to server\n */\n async ingest(\n device: DeviceMetadata,\n buckets: UploadTokenBucket[],\n sessions?: UploadSessionMetadata[],\n onProgress?: (sent: number, total: number) => void,\n ): Promise<{ ingested?: number; sessions?: number }> {\n let lastError: Error | undefined;\n for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {\n try {\n return await this.sendIngest(device, buckets, sessions, onProgress);\n } catch (err) {\n lastError = err as Error;\n const httpErr = err as { statusCode?: number; message: string };\n // Don't retry auth errors or client errors\n if (\n httpErr.message === \"UNAUTHORIZED\" ||\n (httpErr.statusCode &&\n httpErr.statusCode >= 400 &&\n httpErr.statusCode < 500)\n ) {\n throw err;\n }\n if (attempt < MAX_RETRIES - 1) {\n const delay = INITIAL_DELAY * 2 ** attempt;\n await new Promise((r) => setTimeout(r, delay));\n }\n }\n }\n throw lastError;\n }\n\n private sendIngest(\n device: DeviceMetadata,\n buckets: UploadTokenBucket[],\n sessions?: UploadSessionMetadata[],\n onProgress?: (sent: number, total: number) => void,\n ): Promise<{ ingested?: number; sessions?: number }> {\n return new Promise((resolve, reject) => {\n const url = new URL(\"/api/usage/ingest\", this.apiUrl);\n const body = Buffer.from(\n JSON.stringify({\n schemaVersion: 2 as const,\n device,\n buckets,\n sessions: sessions ?? [],\n }),\n );\n const totalBytes = body.length;\n const mod = url.protocol === \"https:\" ? https : http;\n\n const req = mod.request(\n url,\n {\n method: \"POST\",\n timeout: TIMEOUT_MS,\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.apiKey}`,\n \"Content-Length\": totalBytes,\n },\n },\n (res) => {\n let data = \"\";\n res.on(\"data\", (chunk) => {\n data += chunk;\n });\n res.on(\"end\", () => {\n if (res.statusCode === 401) {\n reject(new Error(\"UNAUTHORIZED\"));\n return;\n }\n if (\n !res.statusCode ||\n res.statusCode < 200 ||\n res.statusCode >= 300\n ) {\n const err = new Error(\n `HTTP ${res.statusCode}: ${data}`,\n ) as Error & {\n statusCode?: number;\n };\n err.statusCode = res.statusCode;\n reject(err);\n return;\n }\n try {\n const response = JSON.parse(data) as IngestResponse;\n resolve({\n ingested: response.bucketCount ?? response.ingested,\n sessions: response.sessionCount ?? response.sessions,\n });\n } catch {\n reject(new Error(`Invalid JSON response: ${data}`));\n }\n });\n },\n );\n\n req.on(\"error\", (err) => reject(err));\n req.on(\"timeout\", () => {\n req.destroy();\n reject(new Error(\"Request timed out (60s)\"));\n });\n\n // Write body in chunks to report upload progress\n const CHUNK = 16 * 1024;\n let sent = 0;\n\n const writeNext = () => {\n let ok = true;\n while (ok && sent < totalBytes) {\n const slice = body.subarray(sent, sent + CHUNK);\n sent += slice.length;\n if (onProgress) onProgress(sent, totalBytes);\n ok = req.write(slice);\n }\n if (sent < totalBytes) {\n req.once(\"drain\", writeNext);\n } else {\n req.end();\n }\n };\n\n writeNext();\n });\n }\n\n /**\n * Fetch user settings from server\n */\n async fetchSettings(): Promise<ApiSettings | null> {\n return new Promise((resolve, reject) => {\n const url = new URL(\"/api/usage/settings\", this.apiUrl);\n const mod = url.protocol === \"https:\" ? https : http;\n\n const req = mod.request(\n url,\n {\n method: \"GET\",\n timeout: 10_000,\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n },\n },\n (res) => {\n let data = \"\";\n res.on(\"data\", (chunk) => {\n data += chunk;\n });\n res.on(\"end\", () => {\n if (res.statusCode === 401) {\n reject(new Error(\"UNAUTHORIZED\"));\n return;\n }\n if (\n !res.statusCode ||\n res.statusCode < 200 ||\n res.statusCode >= 300\n ) {\n resolve(null);\n return;\n }\n try {\n const settings = JSON.parse(data) as ApiSettings;\n if (\n settings.schemaVersion !== 2 ||\n !settings.projectMode ||\n !settings.projectHashSalt ||\n !settings.timezone\n ) {\n resolve(null);\n return;\n }\n\n resolve(settings);\n } catch {\n resolve(null);\n }\n });\n },\n );\n\n req.on(\"error\", () => resolve(null));\n req.on(\"timeout\", () => {\n req.destroy();\n resolve(null);\n });\n req.end();\n });\n }\n\n /**\n * Delete all usage data for the authenticated user\n */\n async deleteAllData(opts?: {\n hostname?: string;\n }): Promise<{ deleted: number }> {\n return new Promise((resolve, reject) => {\n const url = new URL(\"/api/usage/ingest\", this.apiUrl);\n if (opts?.hostname) {\n url.searchParams.set(\"hostname\", opts.hostname);\n }\n const mod = url.protocol === \"https:\" ? https : http;\n\n const req = mod.request(\n url,\n {\n method: \"DELETE\",\n timeout: TIMEOUT_MS,\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n },\n },\n (res) => {\n let data = \"\";\n res.on(\"data\", (chunk) => {\n data += chunk;\n });\n res.on(\"end\", () => {\n if (res.statusCode === 401) {\n reject(new Error(\"UNAUTHORIZED\"));\n return;\n }\n if (\n !res.statusCode ||\n res.statusCode < 200 ||\n res.statusCode >= 300\n ) {\n const err = new Error(\n `HTTP ${res.statusCode}: ${data}`,\n ) as Error & {\n statusCode?: number;\n };\n err.statusCode = res.statusCode;\n reject(err);\n return;\n }\n try {\n resolve(JSON.parse(data));\n } catch {\n reject(new Error(`Invalid JSON response: ${data}`));\n }\n });\n },\n );\n\n req.on(\"error\", (err) => reject(err));\n req.on(\"timeout\", () => {\n req.destroy();\n reject(new Error(\"Request timed out (60s)\"));\n });\n req.end();\n });\n }\n}\n","import {\n closeSync,\n existsSync,\n openSync,\n readFileSync,\n rmSync,\n writeFileSync,\n} from \"node:fs\";\nimport { ensureAppDirs, getSyncLockPath } from \"./paths\";\nimport type { SyncSource } from \"./state\";\n\ninterface LockMetadata {\n createdAt: string;\n pid: number;\n source: SyncSource;\n}\n\nexport interface SyncLock {\n release(): void;\n}\n\nfunction isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n return code !== \"ESRCH\";\n }\n}\n\nfunction readLockMetadata(lockPath: string): LockMetadata | null {\n if (!existsSync(lockPath)) {\n return null;\n }\n\n try {\n return JSON.parse(readFileSync(lockPath, \"utf-8\")) as LockMetadata;\n } catch {\n return null;\n }\n}\n\nfunction removeStaleLock(lockPath: string): void {\n const metadata = readLockMetadata(lockPath);\n if (!metadata) {\n rmSync(lockPath, { force: true });\n return;\n }\n\n if (!isProcessAlive(metadata.pid)) {\n rmSync(lockPath, { force: true });\n }\n}\n\nexport function tryAcquireSyncLock(source: SyncSource): SyncLock | null {\n ensureAppDirs();\n const lockPath = getSyncLockPath();\n\n try {\n const fd = openSync(lockPath, \"wx\");\n const metadata: LockMetadata = {\n createdAt: new Date().toISOString(),\n pid: process.pid,\n source,\n };\n writeFileSync(fd, JSON.stringify(metadata, null, 2));\n closeSync(fd);\n\n return {\n release() {\n rmSync(lockPath, { force: true });\n },\n };\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (code !== \"EEXIST\") {\n throw error;\n }\n }\n\n removeStaleLock(lockPath);\n\n try {\n const fd = openSync(lockPath, \"wx\");\n const metadata: LockMetadata = {\n createdAt: new Date().toISOString(),\n pid: process.pid,\n source,\n };\n writeFileSync(fd, JSON.stringify(metadata, null, 2));\n closeSync(fd);\n\n return {\n release() {\n rmSync(lockPath, { force: true });\n },\n };\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (code === \"EEXIST\") {\n return null;\n }\n throw error;\n }\n}\n\nexport function describeExistingSyncLock(): string | null {\n const metadata = readLockMetadata(getSyncLockPath());\n if (!metadata) {\n return null;\n }\n\n return `pid=${metadata.pid}, source=${metadata.source}, createdAt=${metadata.createdAt}`;\n}\n","import { mkdirSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { getRuntimeDir, getStateHome } from \"../xdg\";\n\nconst APP_NAME = \"tokenarena\";\n\nexport function getConfigDir(): string {\n // Re-exported from manager for backward compat — callers should import from manager directly\n throw new Error(\"Use getConfigDir() from config/manager instead\");\n}\n\nexport function getRuntimeDirPath(): string {\n return join(getRuntimeDir(), APP_NAME);\n}\n\nexport function getStateDir(): string {\n return join(getStateHome(), APP_NAME);\n}\n\nexport function getSyncLockPath(): string {\n return join(getRuntimeDirPath(), \"sync.lock\");\n}\n\nexport function getSyncStatePath(): string {\n return join(getStateDir(), \"status.json\");\n}\n\nexport function getUploadManifestPath(): string {\n return join(getStateDir(), \"upload-manifest.json\");\n}\n\nexport function ensureAppDirs(): void {\n mkdirSync(getRuntimeDirPath(), { recursive: true });\n mkdirSync(getStateDir(), { recursive: true });\n}\n","import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { ensureAppDirs, getSyncStatePath } from \"./paths\";\n\nexport type SyncSource = \"daemon\" | \"default\" | \"init\" | \"manual\";\n\nexport type SyncStateStatus =\n | \"auth_error\"\n | \"error\"\n | \"idle\"\n | \"skipped_locked\"\n | \"syncing\";\n\nexport interface SyncState {\n pid?: number;\n lastAttemptAt?: string;\n lastCompletedAt?: string;\n lastError?: string;\n lastFailureAt?: string;\n lastResult?: {\n buckets: number;\n sessions: number;\n };\n lastSource?: SyncSource;\n lastSuccessAt?: string;\n status: SyncStateStatus;\n}\n\nfunction getDefaultState(): SyncState {\n return { status: \"idle\" };\n}\n\nexport function loadSyncState(): SyncState {\n const path = getSyncStatePath();\n if (!existsSync(path)) {\n return getDefaultState();\n }\n\n try {\n return {\n ...getDefaultState(),\n ...(JSON.parse(readFileSync(path, \"utf-8\")) as Partial<SyncState>),\n };\n } catch {\n return getDefaultState();\n }\n}\n\nexport function saveSyncState(next: SyncState): void {\n ensureAppDirs();\n writeFileSync(\n getSyncStatePath(),\n `${JSON.stringify(next, null, 2)}\\n`,\n \"utf-8\",\n );\n}\n\nexport function markSyncStarted(source: SyncSource): void {\n const current = loadSyncState();\n saveSyncState({\n ...current,\n pid: process.pid,\n lastAttemptAt: new Date().toISOString(),\n lastSource: source,\n status: \"syncing\",\n });\n}\n\nexport function markSyncSucceeded(\n source: SyncSource,\n result: { buckets: number; sessions: number },\n): void {\n const now = new Date().toISOString();\n const current = loadSyncState();\n saveSyncState({\n ...current,\n lastCompletedAt: now,\n lastError: undefined,\n lastFailureAt: undefined,\n lastResult: result,\n lastSource: source,\n lastSuccessAt: now,\n pid: undefined,\n status: \"idle\",\n });\n}\n\nexport function markSyncFailed(\n source: SyncSource,\n error: string,\n status: Extract<SyncStateStatus, \"auth_error\" | \"error\" | \"skipped_locked\">,\n): void {\n const now = new Date().toISOString();\n const current = loadSyncState();\n saveSyncState({\n ...current,\n lastCompletedAt: now,\n lastError: error,\n lastFailureAt: now,\n lastSource: source,\n pid: undefined,\n status,\n });\n}\n","import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport type { UploadManifest } from \"../../domain/upload-manifest\";\nimport { ensureAppDirs, getUploadManifestPath } from \"./paths\";\n\nfunction isRecordOfStrings(value: unknown): value is Record<string, string> {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return false;\n }\n\n return Object.values(value).every((entry) => typeof entry === \"string\");\n}\n\nfunction isUploadManifest(value: unknown): value is UploadManifest {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return false;\n }\n\n const manifest = value as Partial<UploadManifest>;\n\n return (\n manifest.version === 1 &&\n !!manifest.scope &&\n typeof manifest.scope === \"object\" &&\n typeof manifest.scope.apiUrl === \"string\" &&\n typeof manifest.scope.apiKeyHash === \"string\" &&\n typeof manifest.scope.deviceId === \"string\" &&\n typeof manifest.scope.projectMode === \"string\" &&\n typeof manifest.scope.projectHashSaltHash === \"string\" &&\n typeof manifest.updatedAt === \"string\" &&\n isRecordOfStrings(manifest.buckets) &&\n isRecordOfStrings(manifest.sessions)\n );\n}\n\nexport function loadUploadManifest(): UploadManifest | null {\n const path = getUploadManifestPath();\n if (!existsSync(path)) {\n return null;\n }\n\n try {\n const parsed = JSON.parse(readFileSync(path, \"utf-8\")) as unknown;\n return isUploadManifest(parsed) ? parsed : null;\n } catch {\n return null;\n }\n}\n\nexport function saveUploadManifest(manifest: UploadManifest): void {\n ensureAppDirs();\n writeFileSync(\n getUploadManifestPath(),\n `${JSON.stringify(manifest, null, 2)}\\n`,\n \"utf-8\",\n );\n}\n","import type {\n ParseResult,\n SessionMetadata,\n TokenBucket,\n} from \"../domain/types\";\nimport { detectInstalledTools, getAllParsers } from \"../parsers/registry\";\nimport { logger } from \"../utils/logger\";\n\nexport interface ParserResult {\n source: string;\n buckets: number;\n sessions: number;\n}\n\nexport interface AllParsersResult {\n buckets: TokenBucket[];\n sessions: SessionMetadata[];\n parserResults: ParserResult[];\n}\n\n/**\n * Run all registered parsers and collect results\n */\nexport async function runAllParsers(): Promise<AllParsersResult> {\n const allBuckets: TokenBucket[] = [];\n const allSessions: SessionMetadata[] = [];\n const parserResults: ParserResult[] = [];\n\n for (const parser of getAllParsers()) {\n try {\n const result: ParseResult = await parser.parse();\n const buckets = result.buckets;\n const sessions = result.sessions;\n\n if (buckets.length > 0) allBuckets.push(...buckets);\n if (sessions.length > 0) allSessions.push(...sessions);\n\n if (buckets.length > 0 || sessions.length > 0) {\n parserResults.push({\n source: parser.tool.id,\n buckets: buckets.length,\n sessions: sessions.length,\n });\n }\n } catch (err) {\n logger.warn(`${parser.tool.id} parser failed: ${(err as Error).message}`);\n }\n }\n\n return { buckets: allBuckets, sessions: allSessions, parserResults };\n}\n\n/**\n * Get list of detected tools for status display\n */\nexport function getDetectedTools() {\n return detectInstalledTools();\n}\n","import { execFileSync, spawn } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { appendFile, mkdir, readFile } from \"node:fs/promises\";\nimport { homedir, platform } from \"node:os\";\nimport { dirname, join, posix, win32 } from \"node:path\";\nimport { ApiClient } from \"../infrastructure/api/client\";\nimport {\n type Config,\n getDefaultApiUrl,\n getOrCreateDeviceId,\n loadConfig,\n saveConfig,\n validateApiKey,\n} from \"../infrastructure/config/manager\";\nimport {\n formatBullet,\n formatHeader,\n formatKeyValue,\n formatMutedPath,\n formatSection,\n maskSecret,\n} from \"../infrastructure/ui/format\";\nimport { promptConfirm, promptPassword } from \"../infrastructure/ui/prompts\";\nimport { getDetectedTools } from \"../services/parser-service\";\nimport { runSync } from \"../services/sync-service\";\nimport { isCommandAvailable } from \"../utils/command\";\nimport { logger } from \"../utils/logger\";\n\ninterface BrowserLaunchCommand {\n command: string;\n args: string[];\n}\n\nexport interface ShellAliasSetup {\n aliasLine: string;\n aliasPatterns: string[];\n configFile: string;\n shellLabel: string;\n sourceHint: string;\n}\n\ninterface ResolveShellAliasSetupOptions {\n currentPlatform?: NodeJS.Platform;\n env?: NodeJS.ProcessEnv;\n exists?: (path: string) => boolean;\n homeDir?: string;\n resolvePowerShellProfilePath?: () => string | null;\n}\n\nfunction joinForPlatform(\n currentPlatform: NodeJS.Platform,\n ...parts: string[]\n): string {\n return currentPlatform === \"win32\"\n ? win32.join(...parts)\n : posix.join(...parts);\n}\n\nfunction basenameLikeShell(input: string): string {\n return (\n input\n .split(/[\\\\/]+/)\n .pop()\n ?.replace(/\\.exe$/i, \"\") ?? input\n );\n}\n\nexport function getBrowserLaunchCommand(\n url: string,\n currentPlatform: NodeJS.Platform = platform(),\n): BrowserLaunchCommand {\n switch (currentPlatform) {\n case \"darwin\":\n return {\n command: \"open\",\n args: [url],\n };\n case \"win32\":\n return {\n command: \"cmd.exe\",\n args: [\"/d\", \"/s\", \"/c\", \"start\", \"\", url],\n };\n default:\n return {\n command: \"xdg-open\",\n args: [url],\n };\n }\n}\n\nfunction openBrowser(url: string): void {\n const { command, args } = getBrowserLaunchCommand(url);\n\n try {\n const child = spawn(command, args, {\n detached: true,\n stdio: \"ignore\",\n windowsHide: true,\n });\n\n child.on(\"error\", () => {});\n child.unref();\n } catch {\n // Best-effort only. We still print the URL for manual use.\n }\n}\n\nfunction resolvePowerShellProfilePath(): string | null {\n const systemRoot = process.env.SYSTEMROOT || \"C:\\\\Windows\";\n const candidates = [\n \"pwsh.exe\",\n join(systemRoot, \"System32\", \"WindowsPowerShell\", \"v1.0\", \"powershell.exe\"),\n ];\n\n for (const command of candidates) {\n try {\n const output = execFileSync(\n command,\n [\n \"-NoLogo\",\n \"-NoProfile\",\n \"-Command\",\n \"$PROFILE.CurrentUserCurrentHost\",\n ],\n {\n encoding: \"utf-8\",\n timeout: 3000,\n windowsHide: true,\n },\n ).trim();\n\n if (output) {\n return output;\n }\n } catch {\n // Try the next PowerShell executable.\n }\n }\n\n return null;\n}\n\nexport function resolveShellAliasSetup(\n options: ResolveShellAliasSetupOptions = {},\n): ShellAliasSetup | null {\n const currentPlatform = options.currentPlatform ?? platform();\n const env = options.env ?? process.env;\n const homeDir = options.homeDir ?? homedir();\n const pathExists = options.exists ?? existsSync;\n\n const shellFromEnv = env.SHELL\n ? basenameLikeShell(env.SHELL).toLowerCase()\n : \"\";\n const shellName =\n shellFromEnv || (currentPlatform === \"win32\" ? \"powershell\" : \"\");\n const aliasName = \"ta\";\n\n switch (shellName) {\n case \"zsh\":\n return {\n aliasLine: `alias ${aliasName}=\"tokenarena\"`,\n aliasPatterns: [`alias ${aliasName}=`, `function ${aliasName}`],\n configFile: joinForPlatform(currentPlatform, homeDir, \".zshrc\"),\n shellLabel: \"zsh\",\n sourceHint: \"source ~/.zshrc\",\n };\n case \"bash\": {\n const bashProfile = joinForPlatform(\n currentPlatform,\n homeDir,\n \".bash_profile\",\n );\n const useBashProfile =\n currentPlatform === \"darwin\" && pathExists(bashProfile);\n\n return {\n aliasLine: `alias ${aliasName}=\"tokenarena\"`,\n aliasPatterns: [`alias ${aliasName}=`, `function ${aliasName}`],\n configFile: useBashProfile\n ? bashProfile\n : joinForPlatform(currentPlatform, homeDir, \".bashrc\"),\n shellLabel: \"bash\",\n sourceHint: useBashProfile\n ? \"source ~/.bash_profile\"\n : \"source ~/.bashrc\",\n };\n }\n case \"fish\":\n return {\n aliasLine: `alias ${aliasName} \"tokenarena\"`,\n aliasPatterns: [`alias ${aliasName}`, `function ${aliasName}`],\n configFile: joinForPlatform(\n currentPlatform,\n homeDir,\n \".config\",\n \"fish\",\n \"config.fish\",\n ),\n shellLabel: \"fish\",\n sourceHint: \"source ~/.config/fish/config.fish\",\n };\n case \"powershell\": {\n const configFile =\n options.resolvePowerShellProfilePath?.() ||\n resolvePowerShellProfilePath() ||\n joinForPlatform(\n currentPlatform,\n homeDir,\n \"Documents\",\n \"PowerShell\",\n \"Microsoft.PowerShell_profile.ps1\",\n );\n\n return {\n aliasLine: `Set-Alias -Name ${aliasName} -Value tokenarena`,\n aliasPatterns: [\n `set-alias -name ${aliasName}`,\n `set-alias ${aliasName}`,\n `new-alias ${aliasName}`,\n `function ${aliasName}`,\n ],\n configFile,\n shellLabel: \"PowerShell\",\n sourceHint: \". $PROFILE\",\n };\n }\n default:\n return null;\n }\n}\n\nexport interface InitOptions {\n apiUrl?: string;\n}\n\nexport async function runInit(opts: InitOptions = {}): Promise<void> {\n logger.info(formatHeader(\"TokenArena 初始化\"));\n\n const existing = loadConfig();\n if (existing?.apiKey) {\n logger.info(formatSection(\"检测到已有配置\"));\n logger.info(formatKeyValue(\"当前 API Key\", maskSecret(existing.apiKey)));\n logger.info(\n formatKeyValue(\n \"当前 API 地址\",\n existing.apiUrl || \"https://token.poco-ai.com\",\n ),\n );\n\n const shouldOverwrite = await promptConfirm({\n message: \"已经存在本地配置,是否覆盖并重新初始化?\",\n defaultValue: false,\n });\n\n if (!shouldOverwrite) {\n logger.info(formatBullet(\"已取消初始化。\", \"warning\"));\n return;\n }\n }\n\n const apiUrl = opts.apiUrl || getDefaultApiUrl();\n const cliKeysUrl = `${apiUrl}/zh/settings/cli-keys`;\n logger.info(formatSection(\"第 1 步:准备 API Key\"));\n logger.info(formatBullet(\"浏览器将尝试自动打开 CLI Key 页面。\"));\n logger.info(formatKeyValue(\"Key 页面\", formatMutedPath(cliKeysUrl)));\n openBrowser(cliKeysUrl);\n\n const apiKey = await promptPassword({\n message: \"请粘贴你的 CLI API Key\",\n validate: (value) => validateApiKey(value) || 'API Key 必须以 \"ta_\" 开头。',\n });\n\n logger.info(formatSection(\"第 2 步:验证 API Key\"));\n logger.info(formatKeyValue(\"待验证 Key\", maskSecret(apiKey)));\n try {\n const client = new ApiClient(apiUrl, apiKey);\n const settings = await client.fetchSettings();\n\n if (!settings) {\n logger.info(\n formatBullet(\n \"无法在线验证 Key(可能是网络原因),将继续保存。\",\n \"warning\",\n ),\n );\n } else {\n logger.info(formatBullet(\"API Key 验证成功。\", \"success\"));\n }\n } catch (err) {\n if ((err as Error).message === \"UNAUTHORIZED\") {\n logger.error(\"Invalid API key. Please check and try again.\");\n process.exit(1);\n }\n logger.info(\n formatBullet(\n \"无法完成在线验证(可能是网络原因),将继续保存。\",\n \"warning\",\n ),\n );\n }\n\n const config: Config = {\n apiKey,\n apiUrl,\n ...(existing?.deviceId ? { deviceId: existing.deviceId } : {}),\n };\n saveConfig(config);\n const deviceId = getOrCreateDeviceId(config);\n config.deviceId = deviceId;\n logger.info(formatSection(\"第 3 步:完成本地注册\"));\n\n const tools = getDetectedTools();\n if (tools.length > 0) {\n logger.info(formatSection(\"检测到的 AI CLI\"));\n for (const tool of tools) {\n logger.info(formatBullet(tool.name, \"success\"));\n }\n } else {\n logger.info(formatSection(\"检测到的 AI CLI\"));\n logger.info(\n formatBullet(\n \"当前未检测到已安装工具,稍后安装后也可以直接执行 sync。\",\n \"warning\",\n ),\n );\n }\n\n logger.info(formatSection(\"首次同步\"));\n logger.info(formatBullet(\"正在上传本地已有的使用数据。\"));\n await runSync(config, { source: \"init\" });\n\n logger.info(formatSection(\"初始化完成\"));\n logger.info(formatBullet(\"TokenArena 已准备就绪。\", \"success\"));\n logger.info(formatKeyValue(\"控制台\", `${apiUrl}/usage`));\n\n await setupShellAlias();\n await setupSystemdService();\n}\n\nasync function setupSystemdService(): Promise<void> {\n const currentPlatform = platform();\n if (currentPlatform !== \"linux\") {\n return;\n }\n\n if (!isCommandAvailable(\"systemctl\")) {\n return;\n }\n\n const shouldSetup = await promptConfirm({\n message: \"是否设置 systemd 服务以自动运行 daemon?\",\n defaultValue: true,\n });\n\n if (!shouldSetup) {\n logger.info(formatBullet(\"已跳过 systemd 服务设置。\"));\n return;\n }\n\n try {\n const { runInstallService } = await import(\"./service\");\n await runInstallService({ action: \"setup\", skipPrompt: true });\n } catch (err) {\n logger.warn(`systemd 服务设置失败: ${(err as Error).message}`);\n }\n}\n\nasync function setupShellAlias(): Promise<void> {\n const setup = resolveShellAliasSetup();\n if (!setup) {\n return;\n }\n\n const shouldCreateAlias = await promptConfirm({\n message: `是否为 ${setup.shellLabel} 自动添加 ta 别名?`,\n defaultValue: true,\n });\n if (!shouldCreateAlias) {\n logger.info(formatBullet(\"已跳过 shell alias 设置。\"));\n return;\n }\n\n try {\n await mkdir(dirname(setup.configFile), { recursive: true });\n\n let existingContent = \"\";\n if (existsSync(setup.configFile)) {\n existingContent = await readFile(setup.configFile, \"utf-8\");\n }\n\n const normalizedContent = existingContent.toLowerCase();\n const aliasExists = setup.aliasPatterns.some((pattern) =>\n normalizedContent.includes(pattern.toLowerCase()),\n );\n\n if (aliasExists) {\n logger.info(formatBullet(`别名 ta 已存在:${setup.configFile}`));\n return;\n }\n\n const aliasWithComment = `\\n# TokenArena alias\\n${setup.aliasLine}\\n`;\n await appendFile(setup.configFile, aliasWithComment, \"utf-8\");\n\n logger.info(formatSection(\"Shell alias\"));\n logger.info(formatBullet(`已写入 ${setup.configFile}`, \"success\"));\n logger.info(\n formatKeyValue(\"生效方式\", `执行 '${setup.sourceHint}' 或重启终端`),\n );\n logger.info(formatKeyValue(\"之后可用\", \"ta sync\"));\n } catch (err) {\n logger.info(formatSection(\"Shell alias\"));\n logger.info(\n formatBullet(\n `无法写入 ${setup.configFile}: ${(err as Error).message}`,\n \"warning\",\n ),\n );\n logger.info(formatKeyValue(\"请手动添加\", setup.aliasLine));\n }\n}\n","import { loadConfig } from \"../infrastructure/config/manager\";\nimport { formatBullet, formatHeader } from \"../infrastructure/ui/format\";\nimport {\n isInteractiveTerminal,\n promptConfirm,\n} from \"../infrastructure/ui/prompts\";\nimport { runSync } from \"../services/sync-service\";\nimport { logger } from \"../utils/logger\";\nimport { runInit } from \"./init\";\n\nconst DEFAULT_INTERVAL = 5 * 60_000; // 5 minutes\n\nfunction log(msg: string): void {\n const ts = new Date().toLocaleTimeString(\"en-US\", { hour12: false });\n process.stdout.write(`[${ts}] ${msg}\\n`);\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport interface DaemonOptions {\n interval?: number;\n}\n\nexport async function runDaemon(opts: DaemonOptions = {}): Promise<void> {\n const config = loadConfig();\n if (!config?.apiKey) {\n if (isInteractiveTerminal()) {\n logger.info(\n formatHeader(\n \"尚未完成初始化\",\n \"启动 daemon 前需要先配置有效的 API Key。\",\n ),\n );\n const shouldInit = await promptConfirm({\n message: \"是否先进入初始化流程?\",\n defaultValue: true,\n });\n if (shouldInit) {\n await runInit();\n return;\n }\n logger.info(formatBullet(\"已取消启动 daemon。\", \"warning\"));\n return;\n }\n\n logger.error(\"Not configured. Run `tokenarena init` first.\");\n process.exit(1);\n }\n\n const interval = opts.interval || config.syncInterval || DEFAULT_INTERVAL;\n const intervalMin = Math.round(interval / 60000);\n\n log(`Daemon started (sync every ${intervalMin}m, Ctrl+C to stop)`);\n\n // eslint-disable-next-line no-constant-condition\n while (true) {\n try {\n await runSync(config, {\n quiet: true,\n source: \"daemon\",\n throws: true,\n });\n } catch (err) {\n if ((err as Error).message === \"UNAUTHORIZED\") {\n log(\"API key invalid. Exiting.\");\n process.exit(1);\n }\n log(`Sync error: ${(err as Error).message}`);\n }\n await sleep(interval);\n }\n}\n","import { getConfigPath, loadConfig } from \"../infrastructure/config/manager\";\nimport { loadSyncState } from \"../infrastructure/runtime/state\";\nimport {\n formatBullet,\n formatHeader,\n formatKeyValue,\n formatSection,\n formatStatusBadge,\n maskSecret,\n} from \"../infrastructure/ui/format\";\nimport {\n detectInstalledTools,\n getAllTools,\n isToolInstalled,\n} from \"../parsers/registry\";\nimport { logger } from \"../utils/logger\";\n\nfunction formatMaybe(value?: string): string {\n return value || \"(never)\";\n}\n\nexport async function runStatus(): Promise<void> {\n const config = loadConfig();\n logger.info(\n formatHeader(\n \"TokenArena 状态\",\n \"查看当前配置、已检测工具以及最近一次同步情况。\",\n ),\n );\n\n logger.info(formatSection(\"配置\"));\n if (!config?.apiKey) {\n logger.info(formatKeyValue(\"状态\", formatStatusBadge(\"未配置\", \"warning\")));\n logger.info(formatBullet(\"运行 tokenarena init 完成首次设置。\", \"warning\"));\n } else {\n logger.info(formatKeyValue(\"状态\", formatStatusBadge(\"已配置\", \"success\")));\n logger.info(formatKeyValue(\"配置文件\", getConfigPath()));\n logger.info(formatKeyValue(\"API Key\", maskSecret(config.apiKey)));\n logger.info(\n formatKeyValue(\"API URL\", config.apiUrl || \"https://token.poco-ai.com\"),\n );\n if (config.syncInterval) {\n logger.info(\n formatKeyValue(\n \"同步间隔\",\n `${Math.round(config.syncInterval / 60000)} 分钟`,\n ),\n );\n }\n }\n\n logger.info(formatSection(\"已检测工具\"));\n const detected = detectInstalledTools();\n if (detected.length === 0) {\n logger.info(formatBullet(\"未检测到已安装的 AI CLI。\", \"warning\"));\n } else {\n for (const tool of detected) {\n logger.info(formatBullet(tool.name, \"success\"));\n }\n }\n\n logger.info(formatSection(\"支持的工具\"));\n for (const tool of getAllTools()) {\n const installed = isToolInstalled(tool.id);\n logger.info(\n formatBullet(\n `${tool.name} · ${installed ? \"已安装\" : \"未发现\"}`,\n installed ? \"success\" : \"neutral\",\n ),\n );\n }\n\n const syncState = loadSyncState();\n logger.info(formatSection(\"同步状态\"));\n const statusTone =\n syncState.status === \"idle\"\n ? \"success\"\n : syncState.status === \"syncing\"\n ? \"warning\"\n : \"danger\";\n logger.info(\n formatKeyValue(\"状态\", formatStatusBadge(syncState.status, statusTone)),\n );\n logger.info(formatKeyValue(\"上次尝试\", formatMaybe(syncState.lastAttemptAt)));\n logger.info(formatKeyValue(\"上次成功\", formatMaybe(syncState.lastSuccessAt)));\n if (syncState.lastSource) {\n logger.info(formatKeyValue(\"触发来源\", syncState.lastSource));\n }\n if (syncState.lastError) {\n logger.info(formatKeyValue(\"错误信息\", syncState.lastError));\n }\n if (syncState.lastResult) {\n logger.info(\n formatKeyValue(\n \"最近结果\",\n `${syncState.lastResult.buckets} buckets, ${syncState.lastResult.sessions} sessions`,\n ),\n );\n }\n}\n","import { loadConfig } from \"../infrastructure/config/manager\";\nimport { formatBullet, formatHeader } from \"../infrastructure/ui/format\";\nimport {\n isInteractiveTerminal,\n promptConfirm,\n} from \"../infrastructure/ui/prompts\";\nimport { runSync } from \"../services/sync-service\";\nimport { logger } from \"../utils/logger\";\nimport { runInit } from \"./init\";\n\nexport interface SyncCommandOptions {\n quiet?: boolean;\n}\n\nexport async function runSyncCommand(\n opts: SyncCommandOptions = {},\n): Promise<void> {\n const config = loadConfig();\n if (!config?.apiKey) {\n if (isInteractiveTerminal()) {\n logger.info(\n formatHeader(\"尚未完成初始化\", \"同步前需要先配置有效的 API Key。\"),\n );\n const shouldInit = await promptConfirm({\n message: \"是否现在进入初始化流程?\",\n defaultValue: true,\n });\n if (shouldInit) {\n await runInit();\n return;\n }\n logger.info(formatBullet(\"已取消同步。\", \"warning\"));\n return;\n }\n\n logger.error(\"Not configured. Run `tokenarena init` first.\");\n process.exit(1);\n }\n\n await runSync(config, {\n quiet: opts.quiet,\n source: \"manual\",\n });\n}\n","import { existsSync, readFileSync, rmSync, writeFileSync } from \"node:fs\";\nimport { homedir, platform } from \"node:os\";\nimport {\n deleteConfig,\n getConfigDir,\n getConfigPath,\n loadConfig,\n} from \"../infrastructure/config/manager\";\nimport {\n getRuntimeDirPath,\n getStateDir,\n} from \"../infrastructure/runtime/paths\";\nimport {\n formatBullet,\n formatHeader,\n formatKeyValue,\n formatSection,\n maskSecret,\n} from \"../infrastructure/ui/format\";\nimport { promptConfirm } from \"../infrastructure/ui/prompts\";\nimport { logger } from \"../utils/logger\";\n\nfunction removeShellAlias(): void {\n const shell = process.env.SHELL;\n if (!shell) return;\n\n const shellName = shell.split(\"/\").pop() ?? \"\";\n const aliasName = \"ta\";\n\n let configFile: string;\n\n switch (shellName) {\n case \"zsh\":\n configFile = `${homedir()}/.zshrc`;\n break;\n case \"bash\":\n if (platform() === \"darwin\" && existsSync(`${homedir()}/.bash_profile`)) {\n configFile = `${homedir()}/.bash_profile`;\n } else {\n configFile = `${homedir()}/.bashrc`;\n }\n break;\n case \"fish\":\n configFile = `${homedir()}/.config/fish/config.fish`;\n break;\n default:\n return;\n }\n\n if (!existsSync(configFile)) return;\n\n try {\n let content = readFileSync(configFile, \"utf-8\");\n\n // Match the alias block: \"# TokenArena alias\" comment line + alias line\n const aliasPatterns = [\n // zsh / bash format: alias ta=\"tokenarena\"\n new RegExp(\n `\\\\n?#\\\\s*TokenArena alias\\\\s*\\\\n\\\\s*alias\\\\s+${aliasName}\\\\s*=\\\\s*\"tokenarena\"\\\\s*\\\\n?`,\n \"g\",\n ),\n // fish format: alias ta \"tokenarena\"\n new RegExp(\n `\\\\n?#\\\\s*TokenArena alias\\\\s*\\\\n\\\\s*alias\\\\s+${aliasName}\\\\s+\"tokenarena\"\\\\s*\\\\n?`,\n \"g\",\n ),\n // Loose match for any ta alias line\n new RegExp(`\\\\n?alias\\\\s+${aliasName}\\\\s*=\\\\s*\"tokenarena\"\\\\s*\\\\n?`, \"g\"),\n new RegExp(`\\\\n?alias\\\\s+${aliasName}\\\\s+\"tokenarena\"\\\\s*\\\\n?`, \"g\"),\n ];\n\n for (const pattern of aliasPatterns) {\n const next = content.replace(pattern, \"\\n\");\n if (next !== content) {\n content = next;\n }\n }\n\n writeFileSync(configFile, content, \"utf-8\");\n logger.info(`Removed shell alias from ${configFile}`);\n } catch (err) {\n logger.warn(\n `Could not update ${configFile}: ${(err as Error).message}. Please remove the alias manually.`,\n );\n }\n}\n\nexport async function runUninstall(): Promise<void> {\n const configPath = getConfigPath();\n const configDir = getConfigDir();\n\n if (!existsSync(configPath)) {\n logger.info(formatHeader(\"卸载 TokenArena\"));\n logger.info(formatBullet(\"未发现本地配置,无需卸载。\"));\n return;\n }\n\n const config = loadConfig();\n logger.info(\n formatHeader(\n \"卸载 TokenArena\",\n \"该操作会删除本地配置、同步状态与运行时文件。\",\n ),\n );\n if (config?.apiKey) {\n logger.info(formatKeyValue(\"API Key\", maskSecret(config.apiKey)));\n }\n logger.info(formatKeyValue(\"配置目录\", configDir));\n logger.info(formatKeyValue(\"状态目录\", getStateDir()));\n logger.info(formatKeyValue(\"运行目录\", getRuntimeDirPath()));\n\n const shouldUninstall = await promptConfirm({\n message: \"确认继续卸载本地 TokenArena 数据?\",\n defaultValue: false,\n });\n if (!shouldUninstall) {\n logger.info(formatBullet(\"已取消卸载。\", \"warning\"));\n return;\n }\n\n // 1. Delete config file\n deleteConfig();\n logger.info(formatSection(\"执行结果\"));\n logger.info(formatBullet(\"已删除配置文件。\", \"success\"));\n\n // 2. Remove config directory if empty\n if (existsSync(configDir)) {\n try {\n rmSync(configDir, { recursive: false, force: true });\n logger.info(formatBullet(\"已删除配置目录。\", \"success\"));\n } catch {\n // Directory not empty (other files), skip silently\n }\n }\n\n // 3. Delete state directory (status.json, etc.)\n const stateDir = getStateDir();\n if (existsSync(stateDir)) {\n rmSync(stateDir, { recursive: true, force: true });\n logger.info(formatBullet(\"已删除状态数据。\", \"success\"));\n }\n\n // 4. Delete runtime directory (sync.lock, etc.)\n const runtimeDir = getRuntimeDirPath();\n if (existsSync(runtimeDir)) {\n rmSync(runtimeDir, { recursive: true, force: true });\n logger.info(formatBullet(\"已删除运行时数据。\", \"success\"));\n }\n\n // 4. Clean up shell alias\n removeShellAlias();\n\n logger.info(formatSection(\"完成\"));\n logger.info(formatBullet(\"TokenArena 已从本地卸载完成。\", \"success\"));\n}\n","import type { Command } from \"commander\";\nimport { loadConfig } from \"../infrastructure/config/manager\";\nimport {\n formatBullet,\n formatHeader,\n formatKeyValue,\n formatStatusBadge,\n maskSecret,\n} from \"../infrastructure/ui/format\";\nimport { promptConfirm, promptSelect } from \"../infrastructure/ui/prompts\";\nimport { logger } from \"../utils/logger\";\nimport { handleConfig } from \"./config\";\nimport { runDaemon } from \"./daemon\";\nimport { runInit } from \"./init\";\nimport { runStatus } from \"./status\";\nimport { runSyncCommand } from \"./sync\";\nimport { runUninstall } from \"./uninstall\";\n\ntype HomeAction =\n | \"init\"\n | \"status\"\n | \"sync\"\n | \"config\"\n | \"daemon\"\n | \"uninstall\"\n | \"help\"\n | \"exit\";\n\nfunction logHomeSummary(): void {\n const config = loadConfig();\n const configured = Boolean(config?.apiKey);\n\n logger.info(\n formatHeader(\n \"TokenArena CLI\",\n \"通过更友好的交互完成初始化、同步、配置与清理。\",\n ),\n );\n logger.info(\n formatKeyValue(\n \"配置状态\",\n configured\n ? formatStatusBadge(\"已配置\", \"success\")\n : formatStatusBadge(\"未配置\", \"warning\"),\n ),\n );\n\n if (configured && config) {\n logger.info(formatKeyValue(\"API Key\", maskSecret(config.apiKey)));\n logger.info(\n formatKeyValue(\"API 地址\", config.apiUrl || \"https://token.poco-ai.com\"),\n );\n } else {\n logger.info(formatBullet(\"建议先运行初始化流程绑定 API Key。\", \"warning\"));\n }\n}\n\nasync function pickHomeAction(): Promise<HomeAction> {\n return promptSelect<HomeAction>({\n message: \"请选择要执行的操作\",\n choices: [\n {\n name: \"初始化 TokenArena\",\n value: \"init\",\n description: \"配置 API Key、检测工具并执行首次同步\",\n },\n {\n name: \"查看当前状态\",\n value: \"status\",\n description: \"查看配置、工具检测结果与最近同步状态\",\n },\n {\n name: \"立即同步\",\n value: \"sync\",\n description: \"手动上传本地最新 token 使用数据\",\n },\n {\n name: \"管理配置\",\n value: \"config\",\n description: \"查看或修改 API Key、API 地址、同步间隔等配置\",\n },\n {\n name: \"启动守护同步\",\n value: \"daemon\",\n description: \"持续后台同步,适合长期运行\",\n },\n {\n name: \"卸载本地配置\",\n value: \"uninstall\",\n description: \"删除本地配置、状态与运行时文件\",\n },\n {\n name: \"查看帮助\",\n value: \"help\",\n description: \"展示完整命令帮助\",\n },\n {\n name: \"退出\",\n value: \"exit\",\n description: \"结束当前交互\",\n },\n ],\n });\n}\n\nexport async function runHome(program: Command): Promise<void> {\n while (true) {\n logHomeSummary();\n\n const action = await pickHomeAction();\n logger.info(\"\");\n\n switch (action) {\n case \"init\":\n await runInit();\n break;\n case \"status\":\n await runStatus();\n break;\n case \"sync\":\n await runSyncCommand();\n break;\n case \"config\":\n await handleConfig([]);\n break;\n case \"daemon\":\n await runDaemon();\n return;\n case \"uninstall\":\n await runUninstall();\n break;\n case \"help\":\n program.outputHelp();\n break;\n case \"exit\":\n logger.info(formatBullet(\"已退出交互式主页。\", \"neutral\"));\n return;\n }\n\n const continueAnswer = await promptConfirm({\n message: \"是否继续执行其他操作?\",\n defaultValue: true,\n });\n\n if (!continueAnswer) {\n logger.info(formatBullet(\"下次可直接运行 tokenarena 继续。\", \"neutral\"));\n return;\n }\n }\n}\n","import { readFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst FALLBACK_VERSION = \"0.0.0\";\n\nlet cachedVersion: string | undefined;\n\nexport function getCliVersion(metaUrl = import.meta.url): string {\n if (cachedVersion) {\n return cachedVersion;\n }\n\n const packageJsonPath = join(\n dirname(fileURLToPath(metaUrl)),\n \"..\",\n \"package.json\",\n );\n\n try {\n const packageJson = JSON.parse(readFileSync(packageJsonPath, \"utf-8\")) as {\n version?: string;\n };\n\n cachedVersion =\n typeof packageJson.version === \"string\"\n ? packageJson.version\n : FALLBACK_VERSION;\n } catch {\n cachedVersion = FALLBACK_VERSION;\n }\n\n return cachedVersion;\n}\n","import { existsSync, realpathSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nexport function isMainModule(\n argvEntry = process.argv[1],\n metaUrl = import.meta.url,\n): boolean {\n if (!argvEntry) {\n return false;\n }\n\n const currentModulePath = fileURLToPath(metaUrl);\n\n try {\n return realpathSync(argvEntry) === realpathSync(currentModulePath);\n } catch {\n if (!existsSync(argvEntry)) {\n return false;\n }\n\n return resolve(argvEntry) === resolve(currentModulePath);\n }\n}\n","// Import parsers to register them before CLI setup\nimport \"./parsers/claude-code.js\";\nimport \"./parsers/codex.js\";\nimport \"./parsers/gemini-cli.js\";\nimport \"./parsers/copilot-cli.js\";\nimport \"./parsers/opencode.js\";\nimport \"./parsers/openclaw.js\";\nimport \"./parsers/qwen-code.js\";\nimport \"./parsers/kimi-code.js\";\nimport \"./parsers/droid.js\";\nimport \"./parsers/pi-coding-agent.js\";\n\nimport { createCli } from \"./cli.js\";\nimport { isMainModule } from \"./infrastructure/runtime/main-module.js\";\n\nexport function normalizeArgv(argv: string[]) {\n return argv.filter((arg, index) => index < 2 || arg !== \"--\");\n}\n\nexport async function run(argv = process.argv) {\n const program = createCli();\n await program.parseAsync(normalizeArgv(argv));\n}\n\nif (isMainModule()) {\n void run();\n}\n"],"mappings":"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","names":["existsSync","join","sep","hostname","existsSync","existsSync","join","sep","existsSync","homedir","join","TOOL","join","homedir","existsSync","readdirSync","readFileSync","homedir","join","TOOL","join","homedir","existsSync","readdirSync","readFileSync","existsSync","readdirSync","readFileSync","homedir","basename","join","join","homedir","TOOL","existsSync","readdirSync","basename","readFileSync","existsSync","readdirSync","readFileSync","homedir","basename","join","join","homedir","TOOL","existsSync","basename","readdirSync","readFileSync","existsSync","readdirSync","readFileSync","homedir","join","join","homedir","TOOL","existsSync","readdirSync","readFileSync","existsSync","readdirSync","homedir","join","DEFAULT_DATA_DIR","join","homedir","getPathLeaf","findSessionFiles","existsSync","readdirSync","existsSync","readdirSync","homedir","join","TOOL_ID","TOOL_NAME","join","homedir","createToolDefinition","toSafeNumber","getPathLeaf","existsSync","readdirSync","existsSync","readdirSync","homedir","basename","dirname","join","TOOL_ID","TOOL_NAME","DEFAULT_DATA_DIR","join","homedir","createToolDefinition","findSessionFiles","existsSync","readdirSync","toSafeNumber","basename","dirname","existsSync","homedir","join","TOOL_ID","TOOL_NAME","DEFAULT_SESSIONS_DIR","join","homedir","createToolDefinition","toSafeNumber","getPathLeaf","normalizeForPrefix","existsSync","existsSync","readFileSync","join","homedir","join","join","homedir","join","existsSync","readFileSync","hostname","createHash","URL","resolve","existsSync","readFileSync","writeFileSync","mkdirSync","join","join","mkdirSync","existsSync","readFileSync","writeFileSync","existsSync","readFileSync","writeFileSync","existsSync","readFileSync","writeFileSync","existsSync","readFileSync","writeFileSync","existsSync","readFileSync","writeFileSync","hostname","execFileSync","existsSync","homedir","dirname","join","join","execFileSync","homedir","existsSync","runInstallService","dirname","resolve","existsSync","readFileSync","rmSync","writeFileSync","homedir","platform","homedir","platform","existsSync","readFileSync","writeFileSync","rmSync","readFileSync","dirname","join","existsSync","fileURLToPath"]}
1
+ {"version":3,"sources":["../src/parsers/claude-code.ts","../src/domain/aggregator.ts","../src/domain/session-extractor.ts","../src/infrastructure/fs/utils.ts","../src/parsers/registry.ts","../src/parsers/codex.ts","../src/parsers/gemini-cli.ts","../src/parsers/copilot-cli.ts","../src/parsers/opencode.ts","../src/parsers/openclaw.ts","../src/parsers/qwen-code.ts","../src/parsers/kimi-code.ts","../src/parsers/droid.ts","../src/parsers/pi-coding-agent.ts","../src/cli.ts","../src/infrastructure/config/manager.ts","../src/infrastructure/xdg.ts","../src/infrastructure/ui/format.ts","../src/infrastructure/ui/prompts.ts","../src/utils/logger.ts","../src/commands/config.ts","../src/services/sync-service.ts","../src/domain/project-identity.ts","../src/domain/upload-manifest.ts","../src/infrastructure/api/client.ts","../src/infrastructure/runtime/lock.ts","../src/infrastructure/runtime/paths.ts","../src/infrastructure/runtime/state.ts","../src/infrastructure/runtime/upload-manifest.ts","../src/services/parser-service.ts","../src/commands/init.ts","../src/infrastructure/service/index.ts","../src/infrastructure/service/linux-systemd.ts","../src/utils/command.ts","../src/infrastructure/service/utils.ts","../src/infrastructure/service/macos-launchd.ts","../src/commands/daemon.ts","../src/commands/status.ts","../src/commands/sync.ts","../src/commands/uninstall.ts","../src/commands/home.ts","../src/commands/service.ts","../src/infrastructure/runtime/cli-version.ts","../src/infrastructure/runtime/main-module.ts","../src/index.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join, sep } from \"node:path\";\nimport { aggregateToBuckets } from \"../domain/aggregator\";\nimport { extractSessions } from \"../domain/session-extractor\";\nimport type {\n ParseResult,\n SessionEvent,\n TokenUsageEntry,\n} from \"../domain/types\";\nimport {\n extractSessionId,\n findJsonlFiles,\n readFileSafe,\n} from \"../infrastructure/fs/utils\";\nimport { registerParser } from \"./registry\";\nimport type { IParser, ToolDefinition } from \"./types\";\n\nconst TOOL: ToolDefinition = {\n id: \"claude-code\",\n name: \"Claude Code\",\n dataDir: join(homedir(), \".claude\", \"projects\"),\n};\n\nconst TRANSCRIPT_DIRS = [\n join(homedir(), \".claude\", \"transcripts\"),\n join(homedir(), \".claude\", \"sessions\"),\n];\n\nfunction extractProject(filePath: string): string {\n const projectsPrefix = TOOL.dataDir + sep;\n if (!filePath.startsWith(projectsPrefix)) return \"unknown\";\n const relative = filePath.slice(projectsPrefix.length);\n const firstSegment = relative.split(sep)[0];\n if (!firstSegment) return \"unknown\";\n const parts = firstSegment.split(\"-\").filter(Boolean);\n return parts.length > 0 ? parts[parts.length - 1] : \"unknown\";\n}\n\nclass ClaudeCodeParser implements IParser {\n readonly tool = TOOL;\n\n async parse(): Promise<ParseResult> {\n const entries: TokenUsageEntry[] = [];\n const sessionEvents: SessionEvent[] = [];\n const seenUuids = new Set<string>();\n const seenSessionIds = new Set<string>();\n\n const projectFiles = findJsonlFiles(TOOL.dataDir);\n\n for (const filePath of projectFiles) {\n const content = readFileSafe(filePath);\n if (!content) continue;\n\n const project = extractProject(filePath);\n const sessionId = extractSessionId(filePath);\n seenSessionIds.add(sessionId);\n\n for (const line of content.split(\"\\n\")) {\n if (!line.trim()) continue;\n try {\n const obj = JSON.parse(line);\n const timestamp = obj.timestamp;\n if (!timestamp) continue;\n\n const parsedTimestamp = new Date(timestamp);\n if (Number.isNaN(parsedTimestamp.getTime())) continue;\n\n if (obj.type === \"user\" || obj.type === \"assistant\") {\n sessionEvents.push({\n sessionId,\n source: \"claude-code\",\n project,\n timestamp: parsedTimestamp,\n role: obj.type === \"user\" ? \"user\" : \"assistant\",\n });\n }\n\n if (obj.type !== \"assistant\") continue;\n const message = obj.message;\n if (!message?.usage) continue;\n\n const usage = message.usage;\n if (usage.input_tokens == null && usage.output_tokens == null) {\n continue;\n }\n\n const uuid = obj.uuid;\n if (uuid) {\n if (seenUuids.has(uuid)) continue;\n seenUuids.add(uuid);\n }\n\n entries.push({\n sessionId,\n source: \"claude-code\",\n model: message.model || \"unknown\",\n project,\n timestamp: parsedTimestamp,\n inputTokens: usage.input_tokens || 0,\n outputTokens: usage.output_tokens || 0,\n reasoningTokens: 0,\n cachedTokens: usage.cache_read_input_tokens || 0,\n });\n } catch {\n // Ignore malformed lines and continue scanning the session log.\n }\n }\n }\n\n for (const transcriptsDir of TRANSCRIPT_DIRS) {\n const transcriptFiles = findJsonlFiles(transcriptsDir);\n\n for (const filePath of transcriptFiles) {\n const sessionId = extractSessionId(filePath);\n if (seenSessionIds.has(sessionId)) continue;\n\n const content = readFileSafe(filePath);\n if (!content) continue;\n\n for (const line of content.split(\"\\n\")) {\n if (!line.trim()) continue;\n try {\n const obj = JSON.parse(line);\n const timestamp = obj.timestamp;\n if (!timestamp) continue;\n\n const parsedTimestamp = new Date(timestamp);\n if (Number.isNaN(parsedTimestamp.getTime())) continue;\n\n if (obj.type === \"user\" || obj.type === \"assistant\") {\n sessionEvents.push({\n sessionId,\n source: \"claude-code\",\n project: \"unknown\",\n timestamp: parsedTimestamp,\n role: obj.type === \"user\" ? \"user\" : \"assistant\",\n });\n }\n } catch {\n // Ignore malformed lines and continue scanning the transcript log.\n }\n }\n }\n }\n\n return {\n buckets: aggregateToBuckets(entries),\n sessions: extractSessions(sessionEvents, entries),\n };\n }\n\n isInstalled(): boolean {\n return (\n existsSync(TOOL.dataDir) || TRANSCRIPT_DIRS.some((dir) => existsSync(dir))\n );\n }\n}\n\nregisterParser(new ClaudeCodeParser());\n","import { hostname } from \"node:os\";\nimport type { TokenBucket, TokenUsageEntry } from \"./types\";\n\n/**\n * Round a date down to the nearest 30-minute bucket\n */\nexport function roundToHalfHour(date: Date): Date {\n const d = new Date(date);\n d.setMinutes(d.getMinutes() < 30 ? 0 : 30, 0, 0);\n return d;\n}\n\n/**\n * Aggregate raw token usage entries into 30-minute buckets\n */\nexport function aggregateToBuckets(entries: TokenUsageEntry[]): TokenBucket[] {\n const map = new Map<string, TokenBucket>();\n const host = hostname().replace(/\\.local$/, \"\");\n\n for (const e of entries) {\n const bucketStart = roundToHalfHour(e.timestamp).toISOString();\n const key = `${e.source}|${e.model}|${e.project}|${bucketStart}`;\n\n if (!map.has(key)) {\n map.set(key, {\n source: e.source,\n model: e.model,\n project: e.project,\n bucketStart,\n hostname: host,\n inputTokens: 0,\n outputTokens: 0,\n reasoningTokens: 0,\n cachedTokens: 0,\n totalTokens: 0,\n });\n }\n\n const b = map.get(key);\n if (!b) continue;\n b.inputTokens += e.inputTokens || 0;\n b.outputTokens += e.outputTokens || 0;\n b.reasoningTokens += e.reasoningTokens || 0;\n b.cachedTokens += e.cachedTokens || 0;\n b.totalTokens +=\n (e.inputTokens || 0) +\n (e.outputTokens || 0) +\n (e.reasoningTokens || 0) +\n (e.cachedTokens || 0);\n }\n\n return Array.from(map.values());\n}\n\n/**\n * Add hostname to buckets after privacy filtering\n */\nexport function addHostname(buckets: TokenBucket[]): void {\n const host = hostname().replace(/\\.local$/, \"\");\n for (const b of buckets) {\n b.hostname = host;\n }\n}\n","import { createHash } from \"node:crypto\";\nimport { hostname } from \"node:os\";\nimport type {\n SessionEvent,\n SessionMetadata,\n SessionModelUsage,\n TokenUsageEntry,\n} from \"./types\";\n\nfunction toEntryTotalTokens(entry: TokenUsageEntry) {\n return (\n entry.inputTokens +\n entry.outputTokens +\n entry.reasoningTokens +\n entry.cachedTokens\n );\n}\n\nfunction buildSessionUsage(entries: TokenUsageEntry[]) {\n const usageBySession = new Map<string, Map<string, SessionModelUsage>>();\n\n for (const entry of entries) {\n if (!entry.sessionId) {\n continue;\n }\n\n let byModel = usageBySession.get(entry.sessionId);\n if (!byModel) {\n byModel = new Map<string, SessionModelUsage>();\n usageBySession.set(entry.sessionId, byModel);\n }\n\n const existing = byModel.get(entry.model);\n if (existing) {\n existing.inputTokens += entry.inputTokens;\n existing.outputTokens += entry.outputTokens;\n existing.reasoningTokens += entry.reasoningTokens;\n existing.cachedTokens += entry.cachedTokens;\n existing.totalTokens += toEntryTotalTokens(entry);\n continue;\n }\n\n byModel.set(entry.model, {\n model: entry.model,\n inputTokens: entry.inputTokens,\n outputTokens: entry.outputTokens,\n reasoningTokens: entry.reasoningTokens,\n cachedTokens: entry.cachedTokens,\n totalTokens: toEntryTotalTokens(entry),\n });\n }\n\n return usageBySession;\n}\n\n/**\n * Extract session metadata from timing events.\n *\n * Turn = first AI response → last AI response before next user prompt.\n * activeSeconds = sum(generation durations), excluding queue/TTFT wait.\n * durationSeconds = wall clock from first to last message.\n */\nexport function extractSessions(\n events: SessionEvent[],\n entries: TokenUsageEntry[] = [],\n): SessionMetadata[] {\n const groups = new Map<string, SessionEvent[]>();\n for (const e of events) {\n if (!groups.has(e.sessionId)) groups.set(e.sessionId, []);\n groups.get(e.sessionId)?.push(e);\n }\n\n const sessions: SessionMetadata[] = [];\n const host = hostname().replace(/\\.local$/, \"\");\n const usageBySession = buildSessionUsage(entries);\n\n for (const [sessionId, sessionEvents] of groups) {\n sessionEvents.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());\n\n const first = sessionEvents[0];\n const last = sessionEvents[sessionEvents.length - 1];\n const durationSeconds = Math.round(\n (last.timestamp.getTime() - first.timestamp.getTime()) / 1000,\n );\n\n let activeSeconds = 0;\n let turnStart: Date | null = null;\n let turnEnd: Date | null = null;\n let waitingForFirstResponse = false;\n\n for (const event of sessionEvents) {\n if (event.role === \"user\") {\n if (turnStart !== null && turnEnd !== null && turnEnd > turnStart) {\n activeSeconds += Math.round(\n (turnEnd.getTime() - turnStart.getTime()) / 1000,\n );\n }\n turnStart = null;\n turnEnd = null;\n waitingForFirstResponse = true;\n } else if (waitingForFirstResponse) {\n turnStart = event.timestamp;\n turnEnd = event.timestamp;\n waitingForFirstResponse = false;\n } else if (turnStart !== null) {\n turnEnd = event.timestamp;\n }\n }\n if (turnStart !== null && turnEnd !== null && turnEnd > turnStart) {\n activeSeconds += Math.round(\n (turnEnd.getTime() - turnStart.getTime()) / 1000,\n );\n }\n\n const userPromptHours = new Array(24).fill(0);\n let userMessageCount = 0;\n for (const event of sessionEvents) {\n if (event.role === \"user\") {\n userMessageCount++;\n userPromptHours[event.timestamp.getUTCHours()]++;\n }\n }\n\n const modelUsages = Array.from(\n usageBySession.get(sessionId)?.values() ?? [],\n ).sort((left, right) => {\n if (right.totalTokens !== left.totalTokens) {\n return right.totalTokens - left.totalTokens;\n }\n\n return left.model.localeCompare(right.model);\n });\n const inputTokens = modelUsages.reduce(\n (sum, usage) => sum + usage.inputTokens,\n 0,\n );\n const outputTokens = modelUsages.reduce(\n (sum, usage) => sum + usage.outputTokens,\n 0,\n );\n const reasoningTokens = modelUsages.reduce(\n (sum, usage) => sum + usage.reasoningTokens,\n 0,\n );\n const cachedTokens = modelUsages.reduce(\n (sum, usage) => sum + usage.cachedTokens,\n 0,\n );\n const totalTokens = modelUsages.reduce(\n (sum, usage) => sum + usage.totalTokens,\n 0,\n );\n const primaryModel = modelUsages[0]?.model ?? \"\";\n\n const sessionHash = createHash(\"sha256\")\n .update(sessionId)\n .digest(\"hex\")\n .slice(0, 16);\n\n sessions.push({\n source: first.source,\n project: first.project || \"unknown\",\n sessionHash,\n hostname: host,\n firstMessageAt: first.timestamp.toISOString(),\n lastMessageAt: last.timestamp.toISOString(),\n durationSeconds,\n activeSeconds,\n messageCount: sessionEvents.length,\n userMessageCount,\n userPromptHours,\n inputTokens,\n outputTokens,\n reasoningTokens,\n cachedTokens,\n totalTokens,\n primaryModel,\n modelUsages,\n });\n }\n\n return sessions;\n}\n\n/**\n * Add hostname to sessions after privacy filtering\n */\nexport function addHostnameToSessions(sessions: SessionMetadata[]): void {\n const host = hostname().replace(/\\.local$/, \"\");\n for (const s of sessions) {\n s.hostname = host;\n }\n}\n","import { existsSync, readdirSync, readFileSync } from \"node:fs\";\nimport { basename, join, sep } from \"node:path\";\n\n/**\n * Recursively find all .jsonl files under a directory\n */\nexport function findJsonlFiles(dir: string): string[] {\n const results: string[] = [];\n if (!existsSync(dir)) return results;\n\n try {\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const fullPath = join(dir, entry.name);\n if (entry.isDirectory()) {\n results.push(...findJsonlFiles(fullPath));\n } else if (entry.name.endsWith(\".jsonl\")) {\n results.push(fullPath);\n }\n }\n } catch {\n // ignore unreadable directories\n }\n return results;\n}\n\n/**\n * Find all JSON files matching a pattern in a directory (non-recursive)\n */\nexport function findJsonFiles(dir: string, pattern: RegExp): string[] {\n const results: string[] = [];\n if (!existsSync(dir)) return results;\n\n try {\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n if (entry.isFile() && pattern.test(entry.name)) {\n results.push(join(dir, entry.name));\n }\n }\n } catch {\n // ignore unreadable directories\n }\n return results;\n}\n\n/**\n * Read file contents, return null on error\n */\nexport function readFileSafe(filePath: string): string | null {\n try {\n return readFileSync(filePath, \"utf-8\");\n } catch {\n return null;\n }\n}\n\n/**\n * Parse JSONL file into array of objects\n */\nexport function parseJsonl<T>(content: string): T[] {\n const results: T[] = [];\n for (const line of content.split(\"\\n\")) {\n if (!line.trim()) continue;\n try {\n results.push(JSON.parse(line) as T);\n } catch {\n // skip malformed lines\n }\n }\n return results;\n}\n\n/**\n * Extract project name from a Claude-style encoded path\n * Path format: ~/.claude/projects/{encodedProjectPath}/{sessionId}.jsonl\n */\nexport function extractProjectFromPath(\n filePath: string,\n projectsDir: string,\n): string {\n const prefix = projectsDir + sep;\n if (!filePath.startsWith(prefix)) return \"unknown\";\n const relative = filePath.slice(prefix.length);\n const firstSeg = relative.split(sep)[0];\n if (!firstSeg) return \"unknown\";\n const parts = firstSeg.split(\"-\").filter(Boolean);\n return parts.length > 0 ? parts[parts.length - 1] : \"unknown\";\n}\n\n/**\n * Extract session ID from file path (basename without extension)\n */\nexport function extractSessionId(filePath: string): string {\n return basename(filePath, \".jsonl\");\n}\n","import { existsSync } from \"node:fs\";\nimport type { IParser, ToolDefinition } from \"./types\";\n\nexport const TOOLS: ToolDefinition[] = [];\n\nconst parsers = new Map<string, IParser>();\n\nexport function registerParser(parser: IParser): void {\n parsers.set(parser.tool.id, parser);\n if (!TOOLS.find((tool) => tool.id === parser.tool.id)) {\n TOOLS.push(parser.tool);\n }\n}\n\nexport function getParser(toolId: string): IParser | undefined {\n return parsers.get(toolId);\n}\n\nexport function getAllParsers(): IParser[] {\n return Array.from(parsers.values());\n}\n\nexport function isToolInstalled(toolId: string): boolean {\n const parser = parsers.get(toolId);\n if (parser?.isInstalled) {\n return parser.isInstalled();\n }\n\n const tool = TOOLS.find((candidate) => candidate.id === toolId);\n return tool ? existsSync(tool.dataDir) : false;\n}\n\nexport function detectInstalledTools(): ToolDefinition[] {\n return TOOLS.filter((tool) => isToolInstalled(tool.id));\n}\n\nexport function getAllTools(): ToolDefinition[] {\n return TOOLS;\n}\n","import { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { aggregateToBuckets } from \"../domain/aggregator\";\nimport { extractSessions } from \"../domain/session-extractor\";\nimport type {\n ParseResult,\n SessionEvent,\n TokenUsageEntry,\n} from \"../domain/types\";\nimport { findJsonlFiles, readFileSafe } from \"../infrastructure/fs/utils\";\nimport { registerParser } from \"./registry\";\nimport type { IParser, ToolDefinition } from \"./types\";\n\nconst TOOL: ToolDefinition = {\n id: \"codex\",\n name: \"Codex CLI\",\n dataDir: join(homedir(), \".codex\", \"sessions\"),\n};\n\ninterface CodexEvent {\n type: string;\n timestamp?: string;\n payload?: {\n type?: string;\n model?: string;\n cwd?: string;\n git?: {\n repository_url?: string;\n };\n info?: {\n model?: string;\n last_token_usage?: {\n input_tokens?: number;\n output_tokens?: number;\n cached_input_tokens?: number;\n reasoning_output_tokens?: number;\n };\n total_token_usage?: {\n input_tokens?: number;\n output_tokens?: number;\n cached_input_tokens?: number;\n reasoning_output_tokens?: number;\n };\n };\n };\n}\n\nfunction getPathLeaf(value: string): string {\n const normalized = value.replace(/\\\\/g, \"/\").replace(/\\/+$/, \"\");\n const leaf = normalized.split(\"/\").filter(Boolean).pop();\n return leaf || \"unknown\";\n}\n\nexport function resolveCodexProject(payload?: CodexEvent[\"payload\"]): string {\n if (!payload) {\n return \"unknown\";\n }\n\n const repositoryUrl = payload.git?.repository_url;\n if (repositoryUrl) {\n const match = repositoryUrl.match(/([^/]+\\/[^/]+?)(?:\\.git)?$/);\n if (match) {\n return match[1];\n }\n }\n\n if (payload.cwd) {\n return getPathLeaf(payload.cwd);\n }\n\n return \"unknown\";\n}\n\nclass CodexParser implements IParser {\n readonly tool = TOOL;\n\n async parse(): Promise<ParseResult> {\n const entries: TokenUsageEntry[] = [];\n const sessionEvents: SessionEvent[] = [];\n const files = findJsonlFiles(TOOL.dataDir);\n\n if (files.length === 0) {\n return { buckets: [], sessions: [] };\n }\n\n for (const filePath of files) {\n const content = readFileSafe(filePath);\n if (!content) continue;\n\n let sessionProject = \"unknown\";\n const sessionModel = \"unknown\";\n for (const line of content.split(\"\\n\")) {\n if (!line.trim()) continue;\n try {\n const obj = JSON.parse(line) as CodexEvent;\n if (obj.type === \"session_meta\") {\n sessionProject = resolveCodexProject(obj.payload);\n break;\n }\n } catch {\n break;\n }\n }\n\n let turnContextModel = \"unknown\";\n type TokenUsage = {\n input_tokens?: number;\n output_tokens?: number;\n cached_input_tokens?: number;\n reasoning_output_tokens?: number;\n };\n const prevTotal = new Map<string, TokenUsage>();\n\n for (const line of content.split(\"\\n\")) {\n if (!line.trim()) continue;\n try {\n const obj = JSON.parse(line) as CodexEvent;\n\n if (obj.type === \"turn_context\" && obj.timestamp) {\n const eventTimestamp = new Date(obj.timestamp);\n if (!Number.isNaN(eventTimestamp.getTime())) {\n sessionEvents.push({\n sessionId: filePath,\n source: \"codex\",\n project: sessionProject,\n timestamp: eventTimestamp,\n role: \"user\",\n });\n }\n }\n\n if (obj.type === \"turn_context\" && obj.payload?.model) {\n turnContextModel = obj.payload.model;\n continue;\n }\n\n if (obj.type !== \"event_msg\") continue;\n\n const payload = obj.payload;\n if (!payload || payload.type !== \"token_count\") continue;\n\n const info = payload.info;\n if (!info) continue;\n\n const timestamp = obj.timestamp ? new Date(obj.timestamp) : null;\n if (!timestamp || Number.isNaN(timestamp.getTime())) continue;\n\n sessionEvents.push({\n sessionId: filePath,\n source: \"codex\",\n project: sessionProject,\n timestamp,\n role: \"assistant\",\n });\n\n let usage = info.last_token_usage;\n if (!usage && info.total_token_usage) {\n const totalKey = `${info.model || payload.model || turnContextModel || \"\"}`;\n const prev = prevTotal.get(totalKey);\n const curr = info.total_token_usage;\n if (prev) {\n usage = {\n input_tokens:\n (curr.input_tokens || 0) - (prev.input_tokens || 0),\n output_tokens:\n (curr.output_tokens || 0) - (prev.output_tokens || 0),\n cached_input_tokens:\n (curr.cached_input_tokens || 0) -\n (prev.cached_input_tokens || 0),\n reasoning_output_tokens:\n (curr.reasoning_output_tokens || 0) -\n (prev.reasoning_output_tokens || 0),\n };\n } else {\n usage = curr;\n }\n prevTotal.set(totalKey, { ...curr });\n }\n if (!usage) continue;\n\n const model =\n info.model || payload.model || turnContextModel || sessionModel;\n const cachedInput = usage.cached_input_tokens || 0;\n const reasoningTokens = usage.reasoning_output_tokens || 0;\n\n entries.push({\n sessionId: filePath,\n source: \"codex\",\n model,\n project: sessionProject,\n timestamp,\n inputTokens: (usage.input_tokens || 0) - cachedInput,\n outputTokens: usage.output_tokens || 0,\n reasoningTokens,\n cachedTokens: cachedInput,\n });\n } catch {\n // Ignore malformed lines and continue scanning the session log.\n }\n }\n }\n\n return {\n buckets: aggregateToBuckets(entries),\n sessions: extractSessions(sessionEvents, entries),\n };\n }\n}\n\nregisterParser(new CodexParser());\n","import { existsSync, readdirSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { aggregateToBuckets } from \"../domain/aggregator\";\nimport { extractSessions } from \"../domain/session-extractor\";\nimport type {\n ParseResult,\n SessionEvent,\n TokenUsageEntry,\n} from \"../domain/types\";\nimport { registerParser } from \"./registry\";\nimport type { IParser, ToolDefinition } from \"./types\";\n\nconst TOOL: ToolDefinition = {\n id: \"gemini-cli\",\n name: \"Gemini CLI\",\n dataDir: join(homedir(), \".gemini\", \"tmp\"),\n};\n\nfunction findSessionFiles(baseDir: string): string[] {\n const results: string[] = [];\n if (!existsSync(baseDir)) return results;\n\n try {\n for (const entry of readdirSync(baseDir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n const chatsDir = join(baseDir, entry.name, \"chats\");\n if (!existsSync(chatsDir)) continue;\n try {\n for (const f of readdirSync(chatsDir)) {\n if (f.startsWith(\"session-\") && f.endsWith(\".json\")) {\n results.push(join(chatsDir, f));\n }\n }\n } catch {}\n }\n } catch {\n return results;\n }\n return results;\n}\n\ninterface GeminiMessage {\n role: string;\n timestamp?: string;\n createTime?: string;\n model?: string;\n tokens?: {\n input?: number;\n output?: number;\n cached?: number;\n thoughts?: number;\n };\n usage?: {\n promptTokenCount?: number;\n candidatesTokenCount?: number;\n cachedContentTokenCount?: number;\n thoughtsTokenCount?: number;\n input_tokens?: number;\n output_tokens?: number;\n };\n usageMetadata?: GeminiMessage[\"usage\"];\n token_count?: GeminiMessage[\"usage\"];\n}\n\ninterface GeminiSession {\n messages?: GeminiMessage[];\n history?: GeminiMessage[];\n model?: string;\n createTime?: string;\n}\n\nclass GeminiCliParser implements IParser {\n readonly tool = TOOL;\n\n async parse(): Promise<ParseResult> {\n const sessionFiles = findSessionFiles(TOOL.dataDir);\n if (sessionFiles.length === 0) {\n return { buckets: [], sessions: [] };\n }\n\n const entries: TokenUsageEntry[] = [];\n const sessionEvents: SessionEvent[] = [];\n\n for (const filePath of sessionFiles) {\n let data: GeminiSession;\n try {\n data = JSON.parse(readFileSync(filePath, \"utf-8\"));\n } catch {\n continue;\n }\n\n const messages = data.messages || data.history || [];\n for (const msg of messages) {\n const timestamp = msg.timestamp || msg.createTime || data.createTime;\n if (!timestamp) continue;\n const ts = new Date(timestamp);\n if (Number.isNaN(ts.getTime())) continue;\n\n if (msg.role !== \"user\" && msg.role !== \"assistant\") continue;\n\n const role = msg.role;\n sessionEvents.push({\n sessionId: filePath,\n source: \"gemini-cli\",\n project: \"unknown\",\n timestamp: ts,\n role,\n });\n\n const tokens = msg.tokens;\n const usage = msg.usage || msg.usageMetadata || msg.token_count;\n if (!tokens && !usage) continue;\n\n if (tokens) {\n const cached = tokens.cached || 0;\n const thoughts = tokens.thoughts || 0;\n entries.push({\n sessionId: filePath,\n source: \"gemini-cli\",\n model: msg.model || data.model || \"unknown\",\n project: \"unknown\",\n timestamp: ts,\n inputTokens: (tokens.input || 0) - cached,\n outputTokens: tokens.output || 0,\n reasoningTokens: thoughts,\n cachedTokens: cached,\n });\n } else if (usage) {\n const cached = usage.cachedContentTokenCount || 0;\n const thoughts = usage.thoughtsTokenCount || 0;\n entries.push({\n sessionId: filePath,\n source: \"gemini-cli\",\n model: msg.model || data.model || \"unknown\",\n project: \"unknown\",\n timestamp: ts,\n inputTokens:\n (usage.promptTokenCount || usage.input_tokens || 0) - cached,\n outputTokens:\n usage.candidatesTokenCount || usage.output_tokens || 0,\n reasoningTokens: thoughts,\n cachedTokens: cached,\n });\n }\n }\n }\n\n return {\n buckets: aggregateToBuckets(entries),\n sessions: extractSessions(sessionEvents, entries),\n };\n }\n}\n\nregisterParser(new GeminiCliParser());\n","import { existsSync, readdirSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { basename, dirname, join } from \"node:path\";\nimport { aggregateToBuckets } from \"../domain/aggregator\";\nimport { extractSessions } from \"../domain/session-extractor\";\nimport type {\n ParseResult,\n SessionEvent,\n TokenUsageEntry,\n} from \"../domain/types\";\nimport { registerParser } from \"./registry\";\nimport type { IParser, ToolDefinition } from \"./types\";\n\nconst ROOT_DIR = join(homedir(), \".copilot\");\n\nconst TOOL: ToolDefinition = {\n id: \"copilot-cli\",\n name: \"GitHub Copilot CLI\",\n dataDir: ROOT_DIR,\n};\n\ninterface CopilotEvent {\n type: string;\n timestamp?: string;\n data?: {\n context?: {\n gitRoot?: string;\n cwd?: string;\n };\n modelMetrics?: Record<\n string,\n {\n usage?: {\n inputTokens?: number;\n outputTokens?: number;\n cacheReadTokens?: number;\n cacheWriteTokens?: number;\n };\n }\n >;\n };\n}\n\nfunction collectEventFiles(\n dir: string,\n results: { filePath: string; sessionId: string }[],\n visited: Set<string>,\n): void {\n if (!existsSync(dir) || visited.has(dir)) {\n return;\n }\n\n visited.add(dir);\n\n try {\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const fullPath = join(dir, entry.name);\n\n if (entry.isDirectory()) {\n collectEventFiles(fullPath, results, visited);\n continue;\n }\n\n if (entry.isFile() && entry.name === \"events.jsonl\") {\n results.push({\n filePath: fullPath,\n sessionId: basename(dirname(fullPath)),\n });\n }\n }\n } catch {\n // Ignore unreadable directories and keep scanning.\n }\n}\n\nfunction findEventFiles(\n baseDir: string,\n): { filePath: string; sessionId: string }[] {\n const results: { filePath: string; sessionId: string }[] = [];\n collectEventFiles(baseDir, results, new Set<string>());\n return results;\n}\n\nfunction getProjectFromContext(\n context: { gitRoot?: string; cwd?: string } | undefined,\n): string {\n const projectPath = context?.gitRoot || context?.cwd;\n if (!projectPath) return \"unknown\";\n return basename(projectPath.replace(/[\\\\/]+$/, \"\")) || \"unknown\";\n}\n\nclass CopilotCliParser implements IParser {\n readonly tool = TOOL;\n\n async parse(): Promise<ParseResult> {\n const eventFiles = findEventFiles(ROOT_DIR);\n if (eventFiles.length === 0) {\n return { buckets: [], sessions: [] };\n }\n\n const entries: TokenUsageEntry[] = [];\n const sessionEvents: SessionEvent[] = [];\n\n for (const { filePath, sessionId } of eventFiles) {\n let content: string;\n try {\n content = readFileSync(filePath, \"utf-8\");\n } catch {\n continue;\n }\n\n let currentProject = \"unknown\";\n\n for (const line of content.split(\"\\n\")) {\n if (!line.trim()) continue;\n\n try {\n const obj = JSON.parse(line) as CopilotEvent;\n const timestamp = obj.timestamp ? new Date(obj.timestamp) : null;\n const hasTimestamp = timestamp && !Number.isNaN(timestamp.getTime());\n\n if (obj.type === \"session.start\" || obj.type === \"session.resume\") {\n currentProject = getProjectFromContext(obj.data?.context);\n }\n\n if (hasTimestamp && timestamp && obj.type === \"user.message\") {\n sessionEvents.push({\n sessionId,\n source: \"copilot-cli\",\n project: currentProject,\n timestamp,\n role: \"user\",\n });\n }\n\n if (hasTimestamp && timestamp && obj.type === \"assistant.message\") {\n sessionEvents.push({\n sessionId,\n source: \"copilot-cli\",\n project: currentProject,\n timestamp,\n role: \"assistant\",\n });\n }\n\n if (obj.type !== \"session.shutdown\" || !hasTimestamp || !timestamp) {\n continue;\n }\n\n const modelMetrics = obj.data?.modelMetrics || {};\n for (const [model, metrics] of Object.entries(modelMetrics)) {\n const usage = metrics?.usage;\n if (!usage) continue;\n\n const totalInput = usage.inputTokens || 0;\n const cachedRead = usage.cacheReadTokens || 0;\n const output = usage.outputTokens || 0;\n\n if (totalInput === 0 && cachedRead === 0 && output === 0) {\n continue;\n }\n\n entries.push({\n sessionId,\n source: \"copilot-cli\",\n model,\n project: currentProject,\n timestamp,\n inputTokens: Math.max(0, totalInput - cachedRead),\n outputTokens: output,\n reasoningTokens: 0,\n cachedTokens: cachedRead,\n });\n }\n } catch {\n // Ignore malformed lines and continue scanning the event log.\n }\n }\n }\n\n return {\n buckets: aggregateToBuckets(entries),\n sessions: extractSessions(sessionEvents, entries),\n };\n }\n\n isInstalled(): boolean {\n return existsSync(ROOT_DIR);\n }\n}\n\nregisterParser(new CopilotCliParser());\n","import { execFileSync } from \"node:child_process\";\nimport { type Dirent, existsSync, readdirSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { basename, join } from \"node:path\";\nimport { aggregateToBuckets } from \"../domain/aggregator\";\nimport { extractSessions } from \"../domain/session-extractor\";\nimport type {\n ParseResult,\n SessionEvent,\n TokenUsageEntry,\n} from \"../domain/types\";\nimport { registerParser } from \"./registry\";\nimport type { IParser, ToolDefinition } from \"./types\";\n\nconst DEFAULT_DATA_DIR = join(homedir(), \".local\", \"share\", \"opencode\");\n\nconst TOOL: ToolDefinition = {\n id: \"opencode\",\n name: \"OpenCode\",\n dataDir: DEFAULT_DATA_DIR,\n};\n\ninterface OpenCodeMessage {\n sessionID?: string;\n role?: string;\n created?: string;\n modelID?: string;\n tokens?: {\n input?: number;\n output?: number;\n cache?: {\n read?: number;\n };\n reasoning?: number;\n };\n path?: {\n root?: string;\n };\n time?: {\n created?: string;\n };\n}\n\ninterface SqliteRow {\n sessionID: string;\n role: string;\n created: string;\n modelID: string | null;\n tokens: string | null;\n rootPath: string | null;\n}\n\nfunction getOpenCodeDataDirs(env: NodeJS.ProcessEnv = process.env): string[] {\n const dirs = [\n env.TOKEN_ARENA_OPENCODE_DIR,\n env.XDG_DATA_HOME ? join(env.XDG_DATA_HOME, \"opencode\") : undefined,\n DEFAULT_DATA_DIR,\n env.LOCALAPPDATA ? join(env.LOCALAPPDATA, \"opencode\") : undefined,\n env.APPDATA ? join(env.APPDATA, \"opencode\") : undefined,\n ].filter((value): value is string => Boolean(value));\n\n return Array.from(new Set(dirs));\n}\n\nasync function withSuppressedSqliteWarning<T>(\n fn: () => Promise<T>,\n): Promise<T> {\n const originalEmitWarning = process.emitWarning;\n\n process.emitWarning = ((\n warning: string | Error,\n ...args: unknown[]\n ): void => {\n const warningName =\n typeof warning === \"string\"\n ? typeof args[0] === \"string\"\n ? args[0]\n : \"\"\n : warning.name;\n const warningMessage =\n typeof warning === \"string\" ? warning : warning.message;\n\n if (\n warningName === \"ExperimentalWarning\" &&\n warningMessage.includes(\"SQLite\")\n ) {\n return;\n }\n\n (\n originalEmitWarning as (\n warning: string | Error,\n ...warningArgs: unknown[]\n ) => void\n ).call(process, warning, ...args);\n }) as typeof process.emitWarning;\n\n try {\n return await fn();\n } finally {\n process.emitWarning = originalEmitWarning;\n }\n}\n\nasync function readSqliteRowsWithBuiltin(\n dbPath: string,\n query: string,\n): Promise<SqliteRow[] | null> {\n try {\n return await withSuppressedSqliteWarning(async () => {\n const sqliteModuleId = \"node:sqlite\";\n const sqlite = (await import(sqliteModuleId)) as {\n DatabaseSync: new (\n location: string,\n ) => {\n close(): void;\n prepare(sql: string): {\n all(): SqliteRow[];\n };\n };\n };\n const db = new sqlite.DatabaseSync(dbPath);\n\n try {\n return db.prepare(query).all() as SqliteRow[];\n } finally {\n db.close();\n }\n });\n } catch (err) {\n const error = err as NodeJS.ErrnoException;\n const message = (err as Error).message;\n if (\n error.code === \"ERR_UNKNOWN_BUILTIN_MODULE\" ||\n message.includes(\"node:sqlite\")\n ) {\n return null;\n }\n\n throw err;\n }\n}\n\nfunction readSqliteRowsWithCli(dbPath: string, query: string): SqliteRow[] {\n const candidates = [\n process.env.TOKEN_ARENA_SQLITE3,\n \"sqlite3\",\n \"sqlite3.exe\",\n ].filter((value): value is string => Boolean(value));\n\n let lastError: Error | null = null;\n\n for (const command of candidates) {\n try {\n const output = execFileSync(command, [\"-json\", dbPath, query], {\n encoding: \"utf-8\",\n maxBuffer: 100 * 1024 * 1024,\n timeout: 30000,\n windowsHide: true,\n }).trim();\n\n if (!output || output === \"[]\") {\n return [];\n }\n\n return JSON.parse(output) as SqliteRow[];\n } catch (err) {\n lastError = err as Error;\n const nodeError = err as NodeJS.ErrnoException & { status?: number };\n if (nodeError.status === 127 || nodeError.message?.includes(\"ENOENT\")) {\n continue;\n }\n\n throw err;\n }\n }\n\n throw new Error(\n `sqlite3 CLI not found. Install sqlite3 or set TOKEN_ARENA_SQLITE3 to its full path. Last error: ${lastError?.message || \"not found\"}`,\n );\n}\n\nclass OpenCodeParser implements IParser {\n readonly tool = TOOL;\n\n async parse(): Promise<ParseResult> {\n const buckets: ParseResult[\"buckets\"] = [];\n const sessions: ParseResult[\"sessions\"] = [];\n\n for (const rootDir of getOpenCodeDataDirs()) {\n const result = await this.parseRoot(rootDir);\n if (result.buckets.length > 0) {\n buckets.push(...result.buckets);\n }\n if (result.sessions.length > 0) {\n sessions.push(...result.sessions);\n }\n }\n\n return { buckets, sessions };\n }\n\n isInstalled(): boolean {\n return getOpenCodeDataDirs().some((dir) => existsSync(dir));\n }\n\n private async parseRoot(rootDir: string): Promise<ParseResult> {\n const dbPath = join(rootDir, \"opencode.db\");\n const messagesDir = join(rootDir, \"storage\", \"message\");\n\n if (existsSync(dbPath)) {\n try {\n return await this.parseFromSqlite(dbPath);\n } catch (err) {\n process.stderr.write(\n `warn: opencode sqlite parse failed (${(err as Error).message}), trying legacy json...\\n`,\n );\n }\n }\n\n return this.parseFromJson(messagesDir);\n }\n\n private async parseFromSqlite(dbPath: string): Promise<ParseResult> {\n const query = `SELECT\n session_id as sessionID,\n json_extract(data, '$.role') as role,\n json_extract(data, '$.time.created') as created,\n json_extract(data, '$.modelID') as modelID,\n json_extract(data, '$.tokens') as tokens,\n json_extract(data, '$.path.root') as rootPath\n FROM message`;\n\n const builtinRows = await readSqliteRowsWithBuiltin(dbPath, query);\n const rows = builtinRows ?? readSqliteRowsWithCli(dbPath, query);\n\n if (rows.length === 0) {\n return { buckets: [], sessions: [] };\n }\n\n const entries: TokenUsageEntry[] = [];\n const sessionEvents: SessionEvent[] = [];\n\n for (const row of rows) {\n const timestamp = new Date(row.created);\n if (Number.isNaN(timestamp.getTime())) continue;\n\n const project = row.rootPath ? basename(row.rootPath) : \"unknown\";\n const sessionId = row.sessionID || \"unknown\";\n if (row.role !== \"user\" && row.role !== \"assistant\") continue;\n\n sessionEvents.push({\n sessionId,\n source: \"opencode\",\n project,\n timestamp,\n role: row.role === \"user\" ? \"user\" : \"assistant\",\n });\n\n if (!row.modelID) continue;\n\n let tokens: OpenCodeMessage[\"tokens\"];\n try {\n tokens =\n typeof row.tokens === \"string\" ? JSON.parse(row.tokens) : row.tokens;\n } catch {\n continue;\n }\n if (!tokens || (!tokens.input && !tokens.output)) continue;\n\n entries.push({\n sessionId,\n source: \"opencode\",\n model: row.modelID || \"unknown\",\n project,\n timestamp,\n inputTokens: tokens.input || 0,\n outputTokens: tokens.output || 0,\n reasoningTokens: tokens.reasoning || 0,\n cachedTokens: tokens.cache?.read || 0,\n });\n }\n\n return {\n buckets: aggregateToBuckets(entries),\n sessions: extractSessions(sessionEvents, entries),\n };\n }\n\n private parseFromJson(messagesDir: string): ParseResult {\n if (!existsSync(messagesDir)) return { buckets: [], sessions: [] };\n\n const entries: TokenUsageEntry[] = [];\n const sessionEvents: SessionEvent[] = [];\n\n let sessionDirs: Dirent[];\n try {\n sessionDirs = readdirSync(messagesDir, { withFileTypes: true }).filter(\n (dirent) => dirent.isDirectory() && dirent.name.startsWith(\"ses_\"),\n );\n } catch {\n return { buckets: [], sessions: [] };\n }\n\n for (const sessionDir of sessionDirs) {\n const sessionPath = join(messagesDir, sessionDir.name);\n let messageFiles: string[];\n try {\n messageFiles = readdirSync(sessionPath).filter((file) =>\n file.endsWith(\".json\"),\n );\n } catch {\n continue;\n }\n\n for (const file of messageFiles) {\n const filePath = join(sessionPath, file);\n\n let data: OpenCodeMessage;\n try {\n data = JSON.parse(readFileSync(filePath, \"utf-8\"));\n } catch {\n continue;\n }\n\n const timestamp = new Date(data.time?.created || data.created);\n if (Number.isNaN(timestamp.getTime())) continue;\n\n const rootPath = data.path?.root;\n const project = rootPath ? basename(rootPath) : \"unknown\";\n if (data.role !== \"user\" && data.role !== \"assistant\") continue;\n\n sessionEvents.push({\n sessionId: sessionDir.name,\n source: \"opencode\",\n project,\n timestamp,\n role: data.role === \"user\" ? \"user\" : \"assistant\",\n });\n\n if (!data.modelID) continue;\n const tokens = data.tokens;\n if (!tokens || (!tokens.input && !tokens.output)) continue;\n\n entries.push({\n sessionId: sessionDir.name,\n source: \"opencode\",\n model: data.modelID || \"unknown\",\n project,\n timestamp,\n inputTokens: tokens.input || 0,\n outputTokens: tokens.output || 0,\n reasoningTokens: tokens.reasoning || 0,\n cachedTokens: tokens.cache?.read || 0,\n });\n }\n }\n\n return {\n buckets: aggregateToBuckets(entries),\n sessions: extractSessions(sessionEvents, entries),\n };\n }\n}\n\nregisterParser(new OpenCodeParser());\n","import { type Dirent, existsSync, readdirSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { aggregateToBuckets } from \"../domain/aggregator\";\nimport { extractSessions } from \"../domain/session-extractor\";\nimport type {\n ParseResult,\n SessionEvent,\n TokenUsageEntry,\n} from \"../domain/types\";\nimport { registerParser } from \"./registry\";\nimport type { IParser, ToolDefinition } from \"./types\";\n\nconst POSSIBLE_ROOTS = [\n join(homedir(), \".openclaw\"),\n join(homedir(), \".clawdbot\"),\n join(homedir(), \".moltbot\"),\n join(homedir(), \".moldbot\"),\n];\n\nconst TOOL: ToolDefinition = {\n id: \"openclaw\",\n name: \"OpenClaw\",\n dataDir: POSSIBLE_ROOTS[0], // Primary data dir for detection\n};\n\ninterface OpenClawMessage {\n type?: string;\n timestamp?: string | number;\n message?: {\n role?: string;\n timestamp?: string | number;\n model?: string;\n usage?: {\n input?: number;\n inputTokens?: number;\n input_tokens?: number;\n promptTokens?: number;\n prompt_tokens?: number;\n output?: number;\n outputTokens?: number;\n output_tokens?: number;\n completionTokens?: number;\n completion_tokens?: number;\n cacheRead?: number;\n cache_read?: number;\n cache_read_input_tokens?: number;\n };\n };\n model?: string;\n}\n\n/** Normalize usage fields — OpenClaw supports multiple naming conventions */\nfunction getTokens(\n usage: NonNullable<OpenClawMessage[\"message\"]>[\"usage\"],\n ...keys: string[]\n): number {\n for (const key of keys) {\n const value = (usage as Record<string, unknown>)[key];\n if (typeof value === \"number\" && value > 0) return value;\n }\n return 0;\n}\n\nclass OpenClawParser implements IParser {\n readonly tool = TOOL;\n\n async parse(): Promise<ParseResult> {\n const entries: TokenUsageEntry[] = [];\n const sessionEvents: SessionEvent[] = [];\n\n for (const root of POSSIBLE_ROOTS) {\n const agentsDir = join(root, \"agents\");\n if (!existsSync(agentsDir)) continue;\n\n let agentDirs: Dirent[];\n try {\n agentDirs = readdirSync(agentsDir, { withFileTypes: true }).filter(\n (d) => d.isDirectory(),\n );\n } catch {\n continue;\n }\n\n for (const agentDir of agentDirs) {\n const project = agentDir.name;\n const sessionsDir = join(agentsDir, agentDir.name, \"sessions\");\n if (!existsSync(sessionsDir)) continue;\n\n let files: string[];\n try {\n files = readdirSync(sessionsDir).filter((f) => f.endsWith(\".jsonl\"));\n } catch {\n continue;\n }\n\n for (const file of files) {\n const filePath = join(sessionsDir, file);\n\n let content: string;\n try {\n content = readFileSync(filePath, \"utf-8\");\n } catch {\n continue;\n }\n\n for (const line of content.split(\"\\n\")) {\n if (!line.trim()) continue;\n try {\n const obj = JSON.parse(line) as OpenClawMessage;\n\n if (obj.type !== \"message\") continue;\n const msg = obj.message;\n if (!msg) continue;\n\n const timestamp = obj.timestamp || msg.timestamp;\n if (!timestamp) continue;\n const ts = new Date(\n typeof timestamp === \"number\" ? timestamp : timestamp,\n );\n if (Number.isNaN(ts.getTime())) continue;\n if (msg.role !== \"user\" && msg.role !== \"assistant\") continue;\n\n sessionEvents.push({\n sessionId: filePath,\n source: \"openclaw\",\n project,\n timestamp: ts,\n role: msg.role === \"user\" ? \"user\" : \"assistant\",\n });\n\n if (msg.role !== \"assistant\") continue;\n const usage = msg.usage;\n if (!usage) continue;\n\n entries.push({\n sessionId: filePath,\n source: \"openclaw\",\n model: msg.model || obj.model || \"unknown\",\n project,\n timestamp: ts,\n inputTokens: getTokens(\n usage,\n \"input\",\n \"inputTokens\",\n \"input_tokens\",\n \"promptTokens\",\n \"prompt_tokens\",\n ),\n outputTokens: getTokens(\n usage,\n \"output\",\n \"outputTokens\",\n \"output_tokens\",\n \"completionTokens\",\n \"completion_tokens\",\n ),\n reasoningTokens: 0,\n cachedTokens: getTokens(\n usage,\n \"cacheRead\",\n \"cache_read\",\n \"cache_read_input_tokens\",\n ),\n });\n } catch {}\n }\n }\n }\n }\n\n return {\n buckets: aggregateToBuckets(entries),\n sessions: extractSessions(sessionEvents, entries),\n };\n }\n\n /** Check if any of the possible roots exist */\n isInstalled(): boolean {\n return POSSIBLE_ROOTS.some((root) => existsSync(join(root, \"agents\")));\n }\n}\n\nregisterParser(new OpenClawParser());\n","import { existsSync, readdirSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { aggregateToBuckets } from \"../domain/aggregator\";\nimport { extractSessions } from \"../domain/session-extractor\";\nimport type {\n ParseResult,\n SessionEvent,\n TokenUsageEntry,\n} from \"../domain/types\";\nimport { readFileSafe } from \"../infrastructure/fs/utils\";\nimport { registerParser } from \"./registry\";\nimport type { IParser, ToolDefinition } from \"./types\";\n\nconst TOOL_ID = \"qwen-code\";\nconst TOOL_NAME = \"Qwen Code\";\nconst DEFAULT_DATA_DIR = join(homedir(), \".qwen\", \"tmp\");\n\ninterface QwenUsage {\n promptTokenCount?: number;\n candidatesTokenCount?: number;\n cachedContentTokenCount?: number;\n thoughtsTokenCount?: number;\n input_tokens?: number;\n output_tokens?: number;\n}\n\ninterface QwenEvent {\n type?: string;\n timestamp?: string;\n cwd?: string;\n uuid?: string;\n model?: string;\n usageMetadata?: QwenUsage;\n usage?: QwenUsage;\n}\n\nexport interface QwenCodeParserOptions {\n dataDir?: string;\n}\n\nfunction createToolDefinition(dataDir: string): ToolDefinition {\n return {\n id: TOOL_ID,\n name: TOOL_NAME,\n dataDir,\n };\n}\n\nfunction toSafeNumber(value: unknown): number {\n const numberValue = Number(value);\n return Number.isFinite(numberValue) ? numberValue : 0;\n}\n\nfunction getPathLeaf(value: string): string {\n const normalized = value.replace(/\\\\/g, \"/\").replace(/\\/+$/, \"\");\n const leaf = normalized.split(\"/\").filter(Boolean).pop();\n return leaf || \"unknown\";\n}\n\nfunction normalizeForPrefix(value: string): string {\n return value.replace(/\\\\/g, \"/\").replace(/\\/+$/, \"\");\n}\n\nfunction findSessionFiles(baseDir: string): string[] {\n const results: string[] = [];\n if (!existsSync(baseDir)) return results;\n\n try {\n for (const entry of readdirSync(baseDir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n\n const chatsDir = join(baseDir, entry.name, \"chats\");\n if (!existsSync(chatsDir)) continue;\n\n try {\n for (const file of readdirSync(chatsDir)) {\n if (file.endsWith(\".jsonl\")) {\n results.push(join(chatsDir, file));\n }\n }\n } catch {\n // Ignore unreadable chat directories and keep scanning.\n }\n }\n } catch {\n return results;\n }\n\n return results;\n}\n\nexport function resolveQwenProject(\n cwd: string | undefined,\n filePath: string,\n dataDir = DEFAULT_DATA_DIR,\n): string {\n if (cwd) {\n return getPathLeaf(cwd);\n }\n\n const normalizedFilePath = normalizeForPrefix(filePath);\n const normalizedDataDir = normalizeForPrefix(dataDir);\n const prefix = `${normalizedDataDir}/`;\n\n if (!normalizedFilePath.startsWith(prefix)) {\n return \"unknown\";\n }\n\n const relativePath = normalizedFilePath.slice(prefix.length);\n const projectId = relativePath.split(\"/\")[0];\n return projectId || \"unknown\";\n}\n\nexport class QwenCodeParser implements IParser {\n readonly tool: ToolDefinition;\n\n constructor(private readonly dataDir = DEFAULT_DATA_DIR) {\n this.tool = createToolDefinition(dataDir);\n }\n\n async parse(): Promise<ParseResult> {\n const sessionFiles = findSessionFiles(this.dataDir);\n if (sessionFiles.length === 0) {\n return { buckets: [], sessions: [] };\n }\n\n const entries: TokenUsageEntry[] = [];\n const sessionEvents: SessionEvent[] = [];\n const seenUuids = new Set<string>();\n\n for (const filePath of sessionFiles) {\n const content = readFileSafe(filePath);\n if (!content) continue;\n\n const sessionId = filePath;\n\n for (const line of content.split(\"\\n\")) {\n if (!line.trim()) continue;\n\n try {\n const obj = JSON.parse(line) as QwenEvent;\n if (!obj.timestamp) continue;\n\n const timestamp = new Date(obj.timestamp);\n if (Number.isNaN(timestamp.getTime())) continue;\n\n const project = resolveQwenProject(obj.cwd, filePath, this.dataDir);\n\n if (obj.type === \"user\" || obj.type === \"assistant\") {\n sessionEvents.push({\n sessionId,\n source: TOOL_ID,\n project,\n timestamp,\n role: obj.type,\n });\n }\n\n if (obj.type !== \"assistant\") continue;\n\n const usage = obj.usageMetadata || obj.usage;\n if (!usage) continue;\n\n const totalInput =\n toSafeNumber(usage.promptTokenCount) ||\n toSafeNumber(usage.input_tokens);\n const totalOutput =\n toSafeNumber(usage.candidatesTokenCount) ||\n toSafeNumber(usage.output_tokens);\n const cachedTokens = toSafeNumber(usage.cachedContentTokenCount);\n const reasoningTokens = toSafeNumber(usage.thoughtsTokenCount);\n\n if (\n totalInput === 0 &&\n totalOutput === 0 &&\n cachedTokens === 0 &&\n reasoningTokens === 0\n ) {\n continue;\n }\n\n if (obj.uuid) {\n if (seenUuids.has(obj.uuid)) continue;\n seenUuids.add(obj.uuid);\n }\n\n entries.push({\n sessionId,\n source: TOOL_ID,\n model: obj.model || \"unknown\",\n project,\n timestamp,\n inputTokens: Math.max(0, totalInput - cachedTokens),\n outputTokens: Math.max(0, totalOutput - reasoningTokens),\n reasoningTokens,\n cachedTokens,\n });\n } catch {\n // Ignore malformed lines and continue scanning the session log.\n }\n }\n }\n\n return {\n buckets: aggregateToBuckets(entries),\n sessions: extractSessions(sessionEvents, entries),\n };\n }\n\n isInstalled(): boolean {\n return existsSync(this.dataDir);\n }\n}\n\nregisterParser(new QwenCodeParser());\n","import { existsSync, readdirSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { aggregateToBuckets } from \"../domain/aggregator\";\nimport { extractSessions } from \"../domain/session-extractor\";\nimport type {\n ParseResult,\n SessionEvent,\n TokenUsageEntry,\n} from \"../domain/types\";\nimport { readFileSafe } from \"../infrastructure/fs/utils\";\nimport { registerParser } from \"./registry\";\nimport type { IParser, ToolDefinition } from \"./types\";\n\nconst TOOL_ID = \"kimi-code\";\nconst TOOL_NAME = \"Kimi Code\";\nconst DEFAULT_SESSIONS_DIR = join(homedir(), \".kimi\", \"sessions\");\nconst DEFAULT_CONFIG_PATH = join(homedir(), \".kimi\", \"kimi.json\");\n\nconst USER_EVENT_TYPES = new Set([\"UserMessage\", \"user_message\", \"Input\"]);\nconst ASSISTANT_EVENT_TYPES = new Set([\n \"AssistantMessage\",\n \"assistant_message\",\n \"Output\",\n \"ModelOutput\",\n \"AssistantOutput\",\n]);\n\ninterface KimiTokenUsage {\n input_other?: unknown;\n output?: unknown;\n input_cache_read?: unknown;\n input_cache_creation?: unknown;\n}\n\ninterface KimiPayload {\n timestamp?: string | number;\n model?: string;\n role?: string;\n token_usage?: KimiTokenUsage;\n message_id?: string;\n}\n\ninterface KimiEvent {\n type?: string;\n timestamp?: string | number;\n payload?: KimiPayload;\n}\n\nexport interface KimiCodeParserOptions {\n sessionsDir?: string;\n configPath?: string;\n}\n\nfunction createToolDefinition(dataDir: string): ToolDefinition {\n return {\n id: TOOL_ID,\n name: TOOL_NAME,\n dataDir,\n };\n}\n\nfunction toSafeNumber(value: unknown): number {\n const numberValue = Number(value);\n return Number.isFinite(numberValue) ? numberValue : 0;\n}\n\nfunction getPathLeaf(value: string): string {\n const normalized = value.replace(/\\\\/g, \"/\").replace(/\\/+$/, \"\");\n const leaf = normalized.split(\"/\").filter(Boolean).pop();\n return leaf || \"unknown\";\n}\n\nfunction findWireFiles(\n baseDir: string,\n): Array<{ filePath: string; workDirHash: string }> {\n const results: Array<{ filePath: string; workDirHash: string }> = [];\n if (!existsSync(baseDir)) return results;\n\n try {\n for (const workDir of readdirSync(baseDir, { withFileTypes: true })) {\n if (!workDir.isDirectory()) continue;\n\n const workDirPath = join(baseDir, workDir.name);\n try {\n for (const session of readdirSync(workDirPath, {\n withFileTypes: true,\n })) {\n if (!session.isDirectory()) continue;\n\n const wireFile = join(workDirPath, session.name, \"wire.jsonl\");\n if (existsSync(wireFile)) {\n results.push({ filePath: wireFile, workDirHash: workDir.name });\n }\n }\n } catch {\n // Ignore unreadable session directories and keep scanning.\n }\n }\n } catch {\n return results;\n }\n\n return results;\n}\n\nfunction parseTimestamp(value: string | number | undefined): Date | null {\n if (value == null) return null;\n const timestamp = new Date(value);\n return Number.isNaN(timestamp.getTime()) ? null : timestamp;\n}\n\nfunction classifyKimiRole(\n type: string | undefined,\n payload: KimiPayload | undefined,\n): SessionEvent[\"role\"] | null {\n if (payload?.role === \"user\" || payload?.role === \"assistant\") {\n return payload.role;\n }\n\n if (type && USER_EVENT_TYPES.has(type)) {\n return \"user\";\n }\n\n if (type && ASSISTANT_EVENT_TYPES.has(type)) {\n return \"assistant\";\n }\n\n if (type?.toLowerCase().includes(\"assistant\")) {\n return \"assistant\";\n }\n\n return null;\n}\n\nfunction loadProjectMap(configPath: string): Map<string, string> {\n const projectMap = new Map<string, string>();\n const content = readFileSafe(configPath);\n if (!content) return projectMap;\n\n try {\n const config = JSON.parse(content) as {\n workspaces?: Record<string, string | { path?: string; dir?: string }>;\n projects?: Record<string, string | { path?: string; dir?: string }>;\n };\n\n const workspaces = config.workspaces || config.projects || {};\n for (const [hash, info] of Object.entries(workspaces)) {\n const pathValue =\n typeof info === \"string\" ? info : info.path || info.dir || undefined;\n if (!pathValue) continue;\n\n projectMap.set(hash, getPathLeaf(pathValue));\n }\n } catch {\n // Ignore unreadable config and fall back to work-dir hashes.\n }\n\n return projectMap;\n}\n\nexport class KimiCodeParser implements IParser {\n readonly tool: ToolDefinition;\n private readonly sessionsDir: string;\n private readonly configPath: string;\n\n constructor(options: KimiCodeParserOptions = {}) {\n this.sessionsDir = options.sessionsDir || DEFAULT_SESSIONS_DIR;\n this.configPath = options.configPath || DEFAULT_CONFIG_PATH;\n this.tool = createToolDefinition(this.sessionsDir);\n }\n\n async parse(): Promise<ParseResult> {\n const wireFiles = findWireFiles(this.sessionsDir);\n if (wireFiles.length === 0) {\n return { buckets: [], sessions: [] };\n }\n\n const projectMap = loadProjectMap(this.configPath);\n const entries: TokenUsageEntry[] = [];\n const sessionEvents: SessionEvent[] = [];\n const seenMessageIds = new Set<string>();\n\n for (const { filePath, workDirHash } of wireFiles) {\n const content = readFileSafe(filePath);\n if (!content) continue;\n\n const sessionId = filePath;\n const project = projectMap.get(workDirHash) || workDirHash;\n let currentModel = \"unknown\";\n let lastTimestampRaw: string | number | undefined;\n\n for (const line of content.split(\"\\n\")) {\n if (!line.trim()) continue;\n\n let obj: KimiEvent;\n try {\n obj = JSON.parse(line) as KimiEvent;\n } catch {\n continue;\n }\n\n const payload = obj.payload;\n if (!payload) continue;\n\n if (payload.model) {\n currentModel = payload.model;\n }\n\n const timestampValue =\n payload.timestamp ?? obj.timestamp ?? lastTimestampRaw;\n const timestamp = parseTimestamp(timestampValue);\n if (payload.timestamp != null) {\n lastTimestampRaw = payload.timestamp;\n } else if (obj.timestamp != null) {\n lastTimestampRaw = obj.timestamp;\n }\n\n const role = classifyKimiRole(obj.type, payload);\n if (role && timestamp) {\n sessionEvents.push({\n sessionId,\n source: TOOL_ID,\n project,\n timestamp,\n role,\n });\n }\n\n if (obj.type !== \"StatusUpdate\") continue;\n\n const tokenUsage = payload.token_usage;\n if (!tokenUsage || !timestamp) continue;\n\n const inputTokens = toSafeNumber(tokenUsage.input_other);\n const outputTokens = toSafeNumber(tokenUsage.output);\n const cachedTokens = toSafeNumber(tokenUsage.input_cache_read);\n const cacheCreateTokens = toSafeNumber(tokenUsage.input_cache_creation);\n\n if (\n inputTokens === 0 &&\n outputTokens === 0 &&\n cachedTokens === 0 &&\n cacheCreateTokens === 0\n ) {\n continue;\n }\n\n if (payload.message_id) {\n if (seenMessageIds.has(payload.message_id)) continue;\n seenMessageIds.add(payload.message_id);\n }\n\n if (!role) {\n sessionEvents.push({\n sessionId,\n source: TOOL_ID,\n project,\n timestamp,\n role: \"assistant\",\n });\n }\n\n entries.push({\n sessionId,\n source: TOOL_ID,\n model: currentModel,\n project,\n timestamp,\n inputTokens,\n outputTokens,\n reasoningTokens: 0,\n cachedTokens,\n });\n }\n }\n\n return {\n buckets: aggregateToBuckets(entries),\n sessions: extractSessions(sessionEvents, entries),\n };\n }\n\n isInstalled(): boolean {\n return existsSync(this.sessionsDir);\n }\n}\n\nregisterParser(new KimiCodeParser());\n","import { existsSync, readdirSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { basename, dirname, join } from \"node:path\";\nimport { aggregateToBuckets } from \"../domain/aggregator\";\nimport { extractSessions } from \"../domain/session-extractor\";\nimport type {\n ParseResult,\n SessionEvent,\n TokenUsageEntry,\n} from \"../domain/types\";\nimport { readFileSafe } from \"../infrastructure/fs/utils\";\nimport { registerParser } from \"./registry\";\nimport type { IParser, ToolDefinition } from \"./types\";\n\nconst TOOL_ID = \"droid\";\nconst TOOL_NAME = \"Droid\";\nconst DEFAULT_DATA_DIR = join(homedir(), \".factory\", \"sessions\");\n\ninterface DroidMessageEvent {\n type?: string;\n timestamp?: string;\n message?: {\n role?: string;\n };\n}\n\ninterface DroidSettings {\n model?: string;\n tokenUsage?: {\n inputTokens?: unknown;\n outputTokens?: unknown;\n cacheReadTokens?: unknown;\n thinkingTokens?: unknown;\n };\n}\n\nfunction createToolDefinition(dataDir: string): ToolDefinition {\n return {\n id: TOOL_ID,\n name: TOOL_NAME,\n dataDir,\n };\n}\n\nfunction findSessionFiles(dir: string): string[] {\n const results: string[] = [];\n if (!existsSync(dir)) return results;\n\n try {\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const fullPath = join(dir, entry.name);\n if (entry.isDirectory()) {\n results.push(...findSessionFiles(fullPath));\n } else if (\n entry.isFile() &&\n entry.name.endsWith(\".jsonl\") &&\n !entry.name.endsWith(\".settings.json\")\n ) {\n results.push(fullPath);\n }\n }\n } catch {\n // Ignore unreadable directories and keep scanning.\n }\n\n return results;\n}\n\nexport function extractDroidProject(slug: string): string {\n const parts = slug.split(\"-\").filter(Boolean);\n return parts.length > 0 ? parts[parts.length - 1] : \"unknown\";\n}\n\nfunction toSafeNumber(value: unknown): number {\n const numberValue = Number(value);\n return Number.isFinite(numberValue) ? numberValue : 0;\n}\n\nexport class DroidParser implements IParser {\n readonly tool: ToolDefinition;\n\n constructor(private readonly dataDir = DEFAULT_DATA_DIR) {\n this.tool = createToolDefinition(dataDir);\n }\n\n async parse(): Promise<ParseResult> {\n const sessionFiles = findSessionFiles(this.dataDir);\n if (sessionFiles.length === 0) {\n return { buckets: [], sessions: [] };\n }\n\n const entries: TokenUsageEntry[] = [];\n const sessionEvents: SessionEvent[] = [];\n\n for (const filePath of sessionFiles) {\n const sessionId = filePath;\n const project = extractDroidProject(basename(dirname(filePath)));\n let firstMessageTimestamp: Date | null = null;\n\n const content = readFileSafe(filePath);\n if (!content) continue;\n\n for (const line of content.split(\"\\n\")) {\n if (!line.trim()) continue;\n\n let obj: DroidMessageEvent;\n try {\n obj = JSON.parse(line) as DroidMessageEvent;\n } catch {\n continue;\n }\n\n if (obj.type !== \"message\" || !obj.timestamp) continue;\n\n const timestamp = new Date(obj.timestamp);\n if (Number.isNaN(timestamp.getTime())) continue;\n\n const role = obj.message?.role;\n if (role !== \"user\" && role !== \"assistant\") continue;\n\n if (firstMessageTimestamp === null) {\n firstMessageTimestamp = timestamp;\n }\n\n sessionEvents.push({\n sessionId,\n source: TOOL_ID,\n project,\n timestamp,\n role,\n });\n }\n\n const settingsPath = join(\n dirname(filePath),\n `${basename(filePath, \".jsonl\")}.settings.json`,\n );\n const settingsContent = readFileSafe(settingsPath);\n if (!settingsContent || firstMessageTimestamp === null) continue;\n\n let settings: DroidSettings;\n try {\n settings = JSON.parse(settingsContent) as DroidSettings;\n } catch {\n continue;\n }\n\n const tokenUsage = settings.tokenUsage;\n if (!tokenUsage) continue;\n\n const cachedTokens = toSafeNumber(tokenUsage.cacheReadTokens);\n const reasoningTokens = toSafeNumber(tokenUsage.thinkingTokens);\n const inputTokens = Math.max(\n 0,\n toSafeNumber(tokenUsage.inputTokens) - cachedTokens,\n );\n const outputTokens = Math.max(\n 0,\n toSafeNumber(tokenUsage.outputTokens) - reasoningTokens,\n );\n\n if (\n inputTokens === 0 &&\n outputTokens === 0 &&\n cachedTokens === 0 &&\n reasoningTokens === 0\n ) {\n continue;\n }\n\n entries.push({\n sessionId,\n source: TOOL_ID,\n model: settings.model || \"unknown\",\n project,\n timestamp: firstMessageTimestamp,\n inputTokens,\n outputTokens,\n reasoningTokens,\n cachedTokens,\n });\n }\n\n return {\n buckets: aggregateToBuckets(entries),\n sessions: extractSessions(sessionEvents, entries),\n };\n }\n\n isInstalled(): boolean {\n return existsSync(this.dataDir);\n }\n}\n\nregisterParser(new DroidParser());\n","import { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { aggregateToBuckets } from \"../domain/aggregator\";\nimport { extractSessions } from \"../domain/session-extractor\";\nimport type {\n ParseResult,\n SessionEvent,\n TokenUsageEntry,\n} from \"../domain/types\";\nimport {\n findJsonlFiles,\n parseJsonl,\n readFileSafe,\n} from \"../infrastructure/fs/utils\";\nimport { registerParser } from \"./registry\";\nimport type { IParser, ToolDefinition } from \"./types\";\n\nconst TOOL_ID = \"pi-coding-agent\";\nconst TOOL_NAME = \"pi\";\nconst DEFAULT_SESSIONS_DIR = join(homedir(), \".pi\", \"agent\", \"sessions\");\n\ninterface PiUsage {\n input?: number;\n inputTokens?: number;\n output?: number;\n outputTokens?: number;\n cacheRead?: number;\n cacheReadTokens?: number;\n cache_read?: number;\n reasoningOutputTokens?: number;\n thinkingTokens?: number;\n thoughts?: number;\n}\n\ninterface PiEvent {\n type?: string;\n id?: string;\n timestamp?: string;\n cwd?: string;\n message?: {\n role?: string;\n timestamp?: string;\n model?: string;\n usage?: PiUsage;\n };\n}\n\nfunction createToolDefinition(dataDir: string): ToolDefinition {\n return {\n id: TOOL_ID,\n name: TOOL_NAME,\n dataDir,\n };\n}\n\nfunction toSafeNumber(value: unknown): number {\n const numberValue = Number(value);\n return Number.isFinite(numberValue) ? numberValue : 0;\n}\n\nfunction getPathLeaf(value: string): string {\n const normalized = value.replace(/\\\\/g, \"/\").replace(/\\/+$/, \"\");\n const leaf = normalized.split(\"/\").filter(Boolean).pop();\n return leaf || \"unknown\";\n}\n\nfunction normalizeForPrefix(value: string): string {\n return value.replace(/\\\\/g, \"/\").replace(/\\/+$/, \"\");\n}\n\nfunction getUsageNumber(usage: PiUsage, ...keys: Array<keyof PiUsage>): number {\n for (const key of keys) {\n const value = usage[key];\n const numberValue = toSafeNumber(value);\n if (numberValue > 0) {\n return numberValue;\n }\n }\n\n return 0;\n}\n\nexport function extractPiProjectFromCwd(cwd: string): string {\n return getPathLeaf(cwd);\n}\n\nexport function extractPiProjectFromDir(\n filePath: string,\n sessionsDir = DEFAULT_SESSIONS_DIR,\n): string {\n const normalizedFilePath = normalizeForPrefix(filePath);\n const normalizedSessionsDir = normalizeForPrefix(sessionsDir);\n const prefix = `${normalizedSessionsDir}/`;\n\n if (!normalizedFilePath.startsWith(prefix)) {\n return \"unknown\";\n }\n\n const relativePath = normalizedFilePath.slice(prefix.length);\n const firstSegment = relativePath.split(\"/\")[0];\n if (!firstSegment) {\n return \"unknown\";\n }\n\n try {\n const decoded = decodeURIComponent(firstSegment);\n if (decoded.includes(\"/\") || decoded.includes(\"\\\\\")) {\n return getPathLeaf(decoded);\n }\n } catch {\n // Fall back to slug parsing when the segment is not URI-encoded.\n }\n\n const slugParts = firstSegment.split(\"-\").filter(Boolean);\n return slugParts.length > 0 ? slugParts[slugParts.length - 1] : \"unknown\";\n}\n\nexport class PiCodingAgentParser implements IParser {\n readonly tool: ToolDefinition;\n\n constructor(private readonly sessionsDir = DEFAULT_SESSIONS_DIR) {\n this.tool = createToolDefinition(sessionsDir);\n }\n\n async parse(): Promise<ParseResult> {\n const sessionFiles = findJsonlFiles(this.sessionsDir);\n if (sessionFiles.length === 0) {\n return { buckets: [], sessions: [] };\n }\n\n const entries: TokenUsageEntry[] = [];\n const sessionEvents: SessionEvent[] = [];\n const seenEntryIds = new Set<string>();\n\n for (const filePath of sessionFiles) {\n const content = readFileSafe(filePath);\n if (!content) continue;\n\n const rows = parseJsonl<PiEvent>(content);\n if (rows.length === 0) continue;\n\n let sessionId = filePath;\n let project = extractPiProjectFromDir(filePath, this.sessionsDir);\n\n for (const row of rows) {\n if (row.type !== \"session\") continue;\n if (row.id) {\n sessionId = row.id;\n }\n if (row.cwd) {\n project = extractPiProjectFromCwd(row.cwd);\n }\n break;\n }\n\n for (const row of rows) {\n if (row.type !== \"message\") continue;\n\n const message = row.message;\n if (!message) continue;\n\n const rawTimestamp = row.timestamp || message.timestamp;\n if (!rawTimestamp) continue;\n\n const timestamp = new Date(rawTimestamp);\n if (Number.isNaN(timestamp.getTime())) continue;\n\n if (message.role === \"user\" || message.role === \"assistant\") {\n sessionEvents.push({\n sessionId,\n source: TOOL_ID,\n project,\n timestamp,\n role: message.role,\n });\n }\n\n if (message.role !== \"assistant\") continue;\n\n const usage = message.usage;\n if (!usage) continue;\n\n const inputTokens = getUsageNumber(usage, \"input\", \"inputTokens\");\n const outputTokens = getUsageNumber(usage, \"output\", \"outputTokens\");\n const cachedTokens = getUsageNumber(\n usage,\n \"cacheRead\",\n \"cacheReadTokens\",\n \"cache_read\",\n );\n const reasoningTokens = getUsageNumber(\n usage,\n \"reasoningOutputTokens\",\n \"thinkingTokens\",\n \"thoughts\",\n );\n\n if (\n inputTokens === 0 &&\n outputTokens === 0 &&\n cachedTokens === 0 &&\n reasoningTokens === 0\n ) {\n continue;\n }\n\n if (row.id) {\n if (seenEntryIds.has(row.id)) continue;\n seenEntryIds.add(row.id);\n }\n\n entries.push({\n sessionId,\n source: TOOL_ID,\n model: message.model || \"unknown\",\n project,\n timestamp,\n inputTokens,\n outputTokens,\n reasoningTokens,\n cachedTokens,\n });\n }\n }\n\n return {\n buckets: aggregateToBuckets(entries),\n sessions: extractSessions(sessionEvents, entries),\n };\n }\n\n isInstalled(): boolean {\n return existsSync(this.sessionsDir);\n }\n}\n\nregisterParser(new PiCodingAgentParser());\n","import { Command, Option } from \"commander\";\nimport { handleConfig } from \"./commands/config\";\nimport { runDaemon } from \"./commands/daemon\";\nimport { runHome } from \"./commands/home\";\nimport { runInit } from \"./commands/init\";\nimport { runServiceCommand } from \"./commands/service\";\nimport { runStatus } from \"./commands/status\";\nimport { runSyncCommand } from \"./commands/sync\";\nimport { runUninstall } from \"./commands/uninstall\";\nimport { getCliVersion } from \"./infrastructure/runtime/cli-version\";\nimport { isInteractiveTerminal } from \"./infrastructure/ui/prompts\";\n\nconst CLI_VERSION = getCliVersion();\n\nexport function createCli(): Command {\n const program = new Command();\n\n program\n .name(\"tokenarena\")\n .description(\"Track token burn across AI coding tools\")\n .version(CLI_VERSION)\n .showHelpAfterError()\n .showSuggestionAfterError()\n .helpCommand(\"help [command]\", \"Display help for command\");\n\n // Default action: show help or error for unknown commands\n program.action(async () => {\n const userArgs = process.argv.slice(2).filter((a) => !a.startsWith(\"-\"));\n if (userArgs.length > 0) {\n program.error(`unknown command '${userArgs[0]}'`);\n }\n if (isInteractiveTerminal()) {\n await runHome(program);\n return;\n }\n program.help();\n });\n\n // init command\n program\n .command(\"init\")\n .description(\"Initialize configuration with API key\")\n .option(\"--api-url <url>\", \"Custom API server URL\")\n .action(async (opts) => {\n await runInit(opts);\n });\n\n // sync command\n program\n .command(\"sync\")\n .description(\"Manually sync usage data to server\")\n .addOption(new Option(\"--quiet\").hideHelp())\n .action(async (opts) => {\n await runSyncCommand(opts);\n });\n\n // daemon command\n program\n .command(\"daemon\")\n .description(\"Run continuous sync (every 5 minutes by default)\")\n .option(\"--interval <ms>\", \"Sync interval in milliseconds\", parseInt)\n .addOption(new Option(\"--service\").hideHelp())\n .action(async (opts) => {\n await runDaemon(opts);\n });\n\n // service command\n program\n .command(\"service [action]\")\n .description(\n \"Manage background service (setup|start|stop|restart|status|uninstall)\",\n )\n .action(async (action) => {\n await runServiceCommand({ action });\n });\n\n // status command\n program\n .command(\"status\")\n .description(\"Show configuration and detected tools\")\n .action(async () => {\n await runStatus();\n });\n\n // config command (with subcommands)\n program\n .command(\"config\")\n .description(\"Manage configuration\")\n .argument(\"[subcommand]\", \"get|set|show\")\n .argument(\"[key]\", \"Config key\")\n .argument(\"[value]\", \"Config value\")\n .allowUnknownOption(true)\n .action(async (subcommand, key, value) => {\n await handleConfig(\n [subcommand, key, value].filter(\n (item): item is string => typeof item === \"string\",\n ),\n );\n });\n\n // uninstall command\n program\n .command(\"uninstall\")\n .description(\"Remove all local configuration and data\")\n .action(async () => {\n await runUninstall();\n });\n\n return program;\n}\n","import { randomUUID } from \"node:crypto\";\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\nimport { getConfigHome } from \"../xdg\";\n\nexport interface Config {\n apiKey: string;\n apiUrl: string;\n deviceId?: string;\n syncInterval?: number;\n logLevel?: \"debug\" | \"info\" | \"warn\" | \"error\";\n}\n\nconst CONFIG_DIR = join(getConfigHome(), \"tokenarena\");\nconst isDev = process.env.TOKEN_ARENA_DEV === \"1\";\nconst CONFIG_FILE = join(CONFIG_DIR, isDev ? \"config.dev.json\" : \"config.json\");\n\nconst DEFAULT_API_URL = \"https://token.poco-ai.com\";\nconst VALID_CONFIG_KEYS = [\n \"apiKey\",\n \"apiUrl\",\n \"deviceId\",\n \"syncInterval\",\n \"logLevel\",\n];\n\nexport function getConfigPath(): string {\n return CONFIG_FILE;\n}\n\nexport function getConfigDir(): string {\n return CONFIG_DIR;\n}\n\nexport function loadConfig(): Config | null {\n if (!existsSync(CONFIG_FILE)) return null;\n try {\n const raw = readFileSync(CONFIG_FILE, \"utf-8\");\n const config = JSON.parse(raw) as Config;\n // Ensure apiUrl has a default\n if (!config.apiUrl) {\n config.apiUrl = DEFAULT_API_URL;\n }\n return config;\n } catch {\n return null;\n }\n}\n\nexport function saveConfig(config: Config): void {\n mkdirSync(CONFIG_DIR, { recursive: true });\n writeFileSync(CONFIG_FILE, `${JSON.stringify(config, null, 2)}\\n`, \"utf-8\");\n}\n\nexport function deleteConfig(): void {\n if (existsSync(CONFIG_FILE)) {\n unlinkSync(CONFIG_FILE);\n }\n}\n\nexport function getOrCreateDeviceId(config: Config): string {\n if (config.deviceId) return config.deviceId;\n\n const next = randomUUID();\n saveConfig({ ...config, deviceId: next });\n\n return next;\n}\n\nexport function validateApiKey(key: string): boolean {\n return key.startsWith(\"ta_\");\n}\n\nexport function isValidConfigKey(key: string): boolean {\n return VALID_CONFIG_KEYS.includes(key);\n}\n\nexport function getDefaultApiUrl(): string {\n return process.env.TOKEN_ARENA_API_URL || DEFAULT_API_URL;\n}\n","import { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\n/**\n * XDG Base Directory specification helpers.\n * @see https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html\n */\n\n/** User-specific configuration directory (`XDG_CONFIG_HOME`, default `~/.config`) */\nexport function getConfigHome(): string {\n return process.env.XDG_CONFIG_HOME || join(homedir(), \".config\");\n}\n\n/** User-specific data directory (`XDG_DATA_HOME`, default `~/.local/share`) */\nexport function getDataHome(): string {\n return process.env.XDG_DATA_HOME || join(homedir(), \".local\", \"share\");\n}\n\n/** User-specific cache directory (`XDG_CACHE_HOME`, default `~/.cache`) */\nexport function getCacheHome(): string {\n return process.env.XDG_CACHE_HOME || join(homedir(), \".cache\");\n}\n\n/** User-specific state directory (`XDG_STATE_HOME`, default `~/.local/state`) */\nexport function getStateHome(): string {\n return process.env.XDG_STATE_HOME || join(homedir(), \".local\", \"state\");\n}\n\n/**\n * User-specific runtime directory (`XDG_RUNTIME_DIR`).\n * Falls back to state home when not set (e.g. on macOS).\n */\nexport function getRuntimeDir(): string {\n return process.env.XDG_RUNTIME_DIR || getStateHome();\n}\n","const hasColor = Boolean(process.stdout.isTTY && process.env.NO_COLOR !== \"1\");\n\nfunction withCode(code: string, value: string): string {\n if (!hasColor) return value;\n return `\\u001b[${code}m${value}\\u001b[0m`;\n}\n\nexport function bold(value: string): string {\n return withCode(\"1\", value);\n}\n\nexport function dim(value: string): string {\n return withCode(\"2\", value);\n}\n\nexport function cyan(value: string): string {\n return withCode(\"36\", value);\n}\n\nexport function green(value: string): string {\n return withCode(\"32\", value);\n}\n\nexport function yellow(value: string): string {\n return withCode(\"33\", value);\n}\n\nexport function red(value: string): string {\n return withCode(\"31\", value);\n}\n\nexport function magenta(value: string): string {\n return withCode(\"35\", value);\n}\n\nexport function formatHeader(title: string, subtitle?: string): string {\n const lines = [`${cyan(\"◈\")} ${bold(title)}`];\n if (subtitle) {\n lines.push(dim(subtitle));\n }\n return `\\n${lines.join(\"\\n\")}`;\n}\n\nexport function formatSection(title: string): string {\n return `\\n${bold(title)}`;\n}\n\nexport function formatKeyValue(label: string, value: string): string {\n return ` ${dim(label.padEnd(14, \" \"))} ${value}`;\n}\n\nexport function formatBullet(\n value: string,\n tone: \"neutral\" | \"success\" | \"warning\" | \"danger\" = \"neutral\",\n): string {\n const icon =\n tone === \"success\"\n ? green(\"✔\")\n : tone === \"warning\"\n ? yellow(\"!\")\n : tone === \"danger\"\n ? red(\"✖\")\n : cyan(\"•\");\n return ` ${icon} ${value}`;\n}\n\nexport function formatMutedPath(path: string): string {\n return dim(path);\n}\n\nexport function maskSecret(value: string, visible = 8): string {\n if (!value) return \"(empty)\";\n if (value.length <= visible) return value;\n return `${value.slice(0, visible)}…`;\n}\n\nexport function formatDurationMinutes(minutes: number): string {\n if (minutes < 60) return `${minutes} 分钟`;\n const hours = Math.floor(minutes / 60);\n const restMinutes = minutes % 60;\n return restMinutes > 0\n ? `${hours} 小时 ${restMinutes} 分钟`\n : `${hours} 小时`;\n}\n\nexport function formatStatusBadge(\n label: string,\n tone: \"success\" | \"warning\" | \"danger\" | \"neutral\" = \"neutral\",\n): string {\n if (tone === \"success\") return green(label);\n if (tone === \"warning\") return yellow(label);\n if (tone === \"danger\") return red(label);\n return magenta(label);\n}\n","import {\n type Choice,\n confirm,\n input,\n password,\n select,\n} from \"@inquirer/prompts\";\n\nexport function isInteractiveTerminal(): boolean {\n return Boolean(process.stdin.isTTY && process.stdout.isTTY);\n}\n\nexport async function promptConfirm(options: {\n message: string;\n defaultValue?: boolean;\n}): Promise<boolean> {\n return confirm({\n message: options.message,\n default: options.defaultValue,\n });\n}\n\nexport async function promptText(options: {\n message: string;\n defaultValue?: string;\n validate?: (value: string) => boolean | string;\n}): Promise<string> {\n return input({\n message: options.message,\n default: options.defaultValue,\n validate: options.validate,\n });\n}\n\nexport async function promptPassword(options: {\n message: string;\n mask?: string;\n validate?: (value: string) => boolean | string;\n}): Promise<string> {\n return password({\n message: options.message,\n mask: options.mask ?? \"*\",\n validate: options.validate,\n });\n}\n\nexport async function promptSelect<T>(options: {\n message: string;\n choices: ReadonlyArray<Choice<T>>;\n}): Promise<T> {\n return select({\n message: options.message,\n choices: [...options.choices],\n pageSize: Math.min(Math.max(options.choices.length, 6), 10),\n });\n}\n","type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\";\n\nconst LOG_LEVELS: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n};\n\nexport class Logger {\n private level: LogLevel;\n\n constructor(level: LogLevel = \"info\") {\n this.level = level;\n }\n\n setLevel(level: LogLevel): void {\n this.level = level;\n }\n\n debug(msg: string): void {\n if (LOG_LEVELS[this.level] <= LOG_LEVELS.debug) {\n process.stderr.write(`[debug] ${msg}\\n`);\n }\n }\n\n info(msg: string): void {\n if (LOG_LEVELS[this.level] <= LOG_LEVELS.info) {\n process.stdout.write(`${msg}\\n`);\n }\n }\n\n warn(msg: string): void {\n if (LOG_LEVELS[this.level] <= LOG_LEVELS.warn) {\n process.stderr.write(`warn: ${msg}\\n`);\n }\n }\n\n error(msg: string): void {\n if (LOG_LEVELS[this.level] <= LOG_LEVELS.error) {\n process.stderr.write(`error: ${msg}\\n`);\n }\n }\n\n log(msg: string): void {\n this.info(msg);\n }\n}\n\nexport const logger = new Logger();\n","import {\n getDefaultApiUrl,\n isValidConfigKey,\n loadConfig,\n saveConfig,\n validateApiKey,\n} from \"../infrastructure/config/manager\";\nimport {\n formatBullet,\n formatHeader,\n formatKeyValue,\n formatSection,\n maskSecret,\n} from \"../infrastructure/ui/format\";\nimport {\n isInteractiveTerminal,\n promptPassword,\n promptSelect,\n promptText,\n} from \"../infrastructure/ui/prompts\";\nimport { logger } from \"../utils/logger\";\n\nconst VALID_KEYS = [\"apiKey\", \"apiUrl\", \"syncInterval\", \"logLevel\"] as const;\n\ntype ConfigKey = (typeof VALID_KEYS)[number];\ntype ConfigSubcommand = \"get\" | \"set\" | \"show\";\n\nfunction isConfigKey(value: string): value is ConfigKey {\n return isValidConfigKey(value) && VALID_KEYS.includes(value as ConfigKey);\n}\n\nfunction formatConfigValue(key: ConfigKey, value: unknown): string {\n if (value === undefined || value === null || value === \"\") {\n return \"(empty)\";\n }\n\n if (key === \"apiKey\") {\n return maskSecret(String(value));\n }\n\n if (key === \"syncInterval\") {\n const ms = Number(value);\n const minutes = Math.round(ms / 60000);\n return `${minutes} 分钟 (${ms} ms)`;\n }\n\n return String(value);\n}\n\nasync function promptConfigSubcommand(): Promise<ConfigSubcommand> {\n logger.info(\n formatHeader(\"配置中心\", \"通过交互式菜单查看或修改 TokenArena CLI 配置。\"),\n );\n\n return promptSelect<ConfigSubcommand>({\n message: \"请选择配置操作\",\n choices: [\n {\n name: \"查看完整配置\",\n value: \"show\",\n description: \"以更适合阅读的方式展示当前配置\",\n },\n {\n name: \"读取单个配置项\",\n value: \"get\",\n description: \"查看某个配置键当前保存的值\",\n },\n {\n name: \"修改配置项\",\n value: \"set\",\n description: \"更新 API Key、API 地址、同步间隔或日志级别\",\n },\n ],\n });\n}\n\nasync function promptConfigKey(message: string): Promise<ConfigKey> {\n return promptSelect<ConfigKey>({\n message,\n choices: [\n {\n name: \"apiKey\",\n value: \"apiKey\",\n description: \"上传数据时使用的 CLI API Key\",\n },\n {\n name: \"apiUrl\",\n value: \"apiUrl\",\n description: \"TokenArena 服务端地址\",\n },\n {\n name: \"syncInterval\",\n value: \"syncInterval\",\n description: \"daemon 默认同步间隔(毫秒)\",\n },\n {\n name: \"logLevel\",\n value: \"logLevel\",\n description: \"CLI 日志级别\",\n },\n ],\n });\n}\n\nasync function promptSyncIntervalValue(\n existingValue?: number,\n): Promise<string> {\n const preset = await promptSelect<string>({\n message: \"请选择默认同步间隔\",\n choices: [\n {\n name: \"5 分钟\",\n value: String(5 * 60_000),\n description: \"适合作为默认值\",\n },\n {\n name: \"10 分钟\",\n value: String(10 * 60_000),\n description: \"更省电,仍保持较及时同步\",\n },\n {\n name: \"30 分钟\",\n value: String(30 * 60_000),\n description: \"适合低频使用场景\",\n },\n {\n name: \"60 分钟\",\n value: String(60 * 60_000),\n description: \"长周期后台同步\",\n },\n {\n name: \"自定义(毫秒)\",\n value: \"custom\",\n description: \"输入任意正整数毫秒值\",\n },\n ],\n });\n\n if (preset !== \"custom\") {\n return preset;\n }\n\n return promptText({\n message: \"请输入 syncInterval(毫秒)\",\n defaultValue: existingValue ? String(existingValue) : undefined,\n validate: (value) => {\n const parsed = Number.parseInt(value, 10);\n if (Number.isNaN(parsed) || parsed <= 0) {\n return \"请输入大于 0 的毫秒数,例如 300000。\";\n }\n return true;\n },\n });\n}\n\nasync function promptConfigValue(\n key: ConfigKey,\n existingValue?: unknown,\n): Promise<string> {\n switch (key) {\n case \"apiKey\":\n return promptPassword({\n message: \"请输入新的 CLI API Key\",\n validate: (value) =>\n validateApiKey(value) || 'API Key 必须以 \"ta_\" 开头。',\n });\n case \"apiUrl\":\n return promptText({\n message: \"请输入 API 服务地址\",\n defaultValue:\n typeof existingValue === \"string\" && existingValue.length > 0\n ? existingValue\n : getDefaultApiUrl(),\n validate: (value) => {\n try {\n const url = new URL(value);\n return Boolean(url.protocol && url.host) || \"请输入合法 URL。\";\n } catch {\n return \"请输入合法 URL。\";\n }\n },\n });\n case \"syncInterval\":\n return promptSyncIntervalValue(\n typeof existingValue === \"number\" ? existingValue : undefined,\n );\n case \"logLevel\":\n return promptSelect<string>({\n message: \"请选择日志级别\",\n choices: [\n {\n name: \"info\",\n value: \"info\",\n description: \"默认,输出常规进度与提示\",\n },\n {\n name: \"warn\",\n value: \"warn\",\n description: \"仅输出警告与错误\",\n },\n {\n name: \"error\",\n value: \"error\",\n description: \"只输出错误\",\n },\n {\n name: \"debug\",\n value: \"debug\",\n description: \"输出更详细的调试日志\",\n },\n ],\n });\n }\n}\n\nfunction printConfigShow(): void {\n const config = loadConfig();\n\n if (!config) {\n logger.info(formatHeader(\"当前配置\", \"尚未创建本地配置文件。\"));\n logger.info(formatBullet(\"运行 tokenarena init 完成首次配置。\", \"warning\"));\n return;\n }\n\n logger.info(formatHeader(\"当前配置\"));\n logger.info(formatSection(\"基础配置\"));\n logger.info(formatKeyValue(\"API Key\", maskSecret(config.apiKey || \"\")));\n logger.info(\n formatKeyValue(\"API 地址\", config.apiUrl || \"https://token.poco-ai.com\"),\n );\n logger.info(\n formatKeyValue(\n \"同步间隔\",\n config.syncInterval\n ? `${Math.round(config.syncInterval / 60000)} 分钟 (${config.syncInterval} ms)`\n : \"未设置(daemon 默认 5 分钟)\",\n ),\n );\n logger.info(formatKeyValue(\"日志级别\", config.logLevel || \"info\"));\n if (config.deviceId) {\n logger.info(formatKeyValue(\"设备 ID\", maskSecret(config.deviceId, 12)));\n }\n}\n\nexport async function handleConfig(args: string[]): Promise<void> {\n const interactive = isInteractiveTerminal();\n let sub = args[0] as ConfigSubcommand | undefined;\n\n if (!sub) {\n if (!interactive) {\n logger.error(\"Usage: tokenarena config <get|set|show>\");\n process.exit(1);\n }\n sub = await promptConfigSubcommand();\n }\n\n switch (sub) {\n case \"get\": {\n let key = args[1];\n if (!key) {\n if (!interactive) {\n logger.error(\"Usage: tokenarena config get <key>\");\n process.exit(1);\n }\n key = await promptConfigKey(\"请选择要读取的配置项\");\n }\n\n if (!isConfigKey(key)) {\n logger.error(`Unknown config key: ${key}`);\n logger.error(`Valid keys: ${VALID_KEYS.join(\", \")}`);\n process.exit(1);\n }\n\n const config = loadConfig();\n if (!config || !(key in config)) {\n process.exit(0);\n }\n\n const record = config as unknown as Record<string, unknown>;\n console.log(record[key] ?? \"\");\n break;\n }\n case \"set\": {\n let key = args[1];\n if (!key) {\n if (!interactive) {\n logger.error(\"Usage: tokenarena config set <key> <value>\");\n process.exit(1);\n }\n key = await promptConfigKey(\"请选择要修改的配置项\");\n }\n\n if (!isConfigKey(key)) {\n logger.error(`Unknown config key: ${key}`);\n logger.error(`Valid keys: ${VALID_KEYS.join(\", \")}`);\n process.exit(1);\n }\n\n const config = loadConfig() || {\n apiKey: \"\",\n apiUrl: getDefaultApiUrl(),\n };\n const record = config as unknown as Record<string, unknown>;\n\n let value = args[2];\n if (value === undefined) {\n if (!interactive) {\n logger.error(\"Usage: tokenarena config set <key> <value>\");\n process.exit(1);\n }\n value = await promptConfigValue(key, record[key]);\n }\n\n let normalized: string | number = value;\n if (key === \"apiKey\" && !validateApiKey(value)) {\n logger.error('API Key must start with \"ta_\"');\n process.exit(1);\n }\n\n if (key === \"apiUrl\") {\n try {\n const url = new URL(value);\n normalized = url.toString().replace(/\\/$/, \"\");\n } catch {\n logger.error(\"apiUrl must be a valid URL\");\n process.exit(1);\n }\n }\n\n if (key === \"syncInterval\") {\n normalized = Number.parseInt(value, 10);\n if (Number.isNaN(normalized) || normalized <= 0) {\n logger.error(\"syncInterval must be a positive number (milliseconds)\");\n process.exit(1);\n }\n }\n\n record[key] = normalized;\n saveConfig(config);\n\n if (interactive) {\n logger.info(formatHeader(\"配置已更新\"));\n logger.info(formatKeyValue(key, formatConfigValue(key, normalized)));\n } else {\n logger.info(`Set ${key} = ${normalized}`);\n }\n break;\n }\n case \"show\": {\n if (interactive) {\n printConfigShow();\n } else {\n const config = loadConfig();\n console.log(config ? JSON.stringify(config, null, 2) : \"{}\");\n }\n break;\n }\n default:\n logger.error(`Unknown config subcommand: ${sub || \"(none)\"}`);\n logger.error(\"Usage: tokenarena config <get|set|show>\");\n process.exit(1);\n }\n}\n","import { hostname } from \"node:os\";\nimport { toProjectIdentity } from \"../domain/project-identity\";\nimport type {\n ApiSettings,\n DeviceMetadata,\n SessionMetadata,\n TokenBucket,\n UploadSessionMetadata,\n UploadTokenBucket,\n} from \"../domain/types\";\nimport {\n buildUploadManifestScope,\n diffUploadManifest,\n type UploadManifest,\n type UploadManifestScopeChange,\n} from \"../domain/upload-manifest\";\nimport { ApiClient, getIngestPayloadSize } from \"../infrastructure/api/client\";\nimport {\n type Config,\n getOrCreateDeviceId,\n} from \"../infrastructure/config/manager\";\nimport {\n describeExistingSyncLock,\n tryAcquireSyncLock,\n} from \"../infrastructure/runtime/lock\";\nimport {\n markSyncFailed,\n markSyncStarted,\n markSyncSucceeded,\n type SyncSource,\n} from \"../infrastructure/runtime/state\";\nimport {\n loadUploadManifest,\n saveUploadManifest,\n} from \"../infrastructure/runtime/upload-manifest\";\nimport { logger } from \"../utils/logger\";\nimport { runAllParsers } from \"./parser-service\";\n\nconst BATCH_SIZE = 100;\nconst SESSION_BATCH_SIZE = 500;\nconst PROGRESS_BAR_WIDTH = 28;\n\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes}B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;\n}\n\nfunction renderProgressBar(progress: number): string {\n const safeProgress = Math.max(0, Math.min(progress, 1));\n const filled = Math.round(safeProgress * PROGRESS_BAR_WIDTH);\n return `${\"█\".repeat(filled)}${\"░\".repeat(PROGRESS_BAR_WIDTH - filled)}`;\n}\n\nfunction writeUploadProgress(\n sent: number,\n total: number,\n batchNum: number,\n totalBatches: number,\n): void {\n const pct = total > 0 ? Math.round((sent / total) * 100) : 100;\n const progressBar = renderProgressBar(total > 0 ? sent / total : 1);\n const batchLabel =\n totalBatches > 1 ? ` · batch ${batchNum}/${totalBatches}` : \"\";\n\n process.stdout.write(\n `\\r Uploading ${progressBar} ${String(pct).padStart(3, \" \")}% · ${formatBytes(sent)}/${formatBytes(total)}${batchLabel}\\x1b[K`,\n );\n}\n\nfunction formatScopeChangeReason(reason: UploadManifestScopeChange): string {\n switch (reason) {\n case \"server_or_api_key\":\n return \"server/API key\";\n case \"device_id\":\n return \"device ID\";\n case \"project_identity\":\n return \"project identity settings\";\n }\n}\n\nfunction persistUploadManifest(manifest: UploadManifest, quiet: boolean): void {\n try {\n saveUploadManifest(manifest);\n } catch (error) {\n if (!quiet) {\n logger.warn(\n `Uploaded data, but failed to update the local sync manifest: ${(error as Error).message}`,\n );\n }\n }\n}\n\nexport interface SyncOptions {\n source?: SyncSource;\n throws?: boolean;\n quiet?: boolean;\n}\n\nexport interface SyncResult {\n buckets: number;\n sessions: number;\n skipped?: \"locked\";\n}\n\nfunction toDeviceMetadata(config: Config): DeviceMetadata {\n return {\n deviceId: getOrCreateDeviceId(config),\n hostname: hostname().replace(/\\.local$/, \"\"),\n };\n}\n\nfunction toUploadBuckets(\n buckets: TokenBucket[],\n settings: ApiSettings,\n device: DeviceMetadata,\n): UploadTokenBucket[] {\n const aggregated = new Map<string, UploadTokenBucket>();\n\n for (const bucket of buckets) {\n const project = toProjectIdentity({\n project: bucket.project || \"unknown\",\n mode: settings.projectMode,\n salt: settings.projectHashSalt,\n });\n const key = [\n bucket.source,\n bucket.model,\n project.projectKey,\n bucket.bucketStart,\n device.deviceId,\n ].join(\"|\");\n\n const existing = aggregated.get(key);\n if (existing) {\n existing.inputTokens += bucket.inputTokens;\n existing.outputTokens += bucket.outputTokens;\n existing.reasoningTokens += bucket.reasoningTokens || 0;\n existing.cachedTokens += bucket.cachedTokens || 0;\n existing.totalTokens += bucket.totalTokens;\n continue;\n }\n\n aggregated.set(key, {\n source: bucket.source,\n model: bucket.model,\n projectKey: project.projectKey,\n projectLabel: project.projectLabel,\n bucketStart: bucket.bucketStart,\n deviceId: device.deviceId,\n hostname: device.hostname,\n inputTokens: bucket.inputTokens,\n outputTokens: bucket.outputTokens,\n reasoningTokens: bucket.reasoningTokens || 0,\n cachedTokens: bucket.cachedTokens || 0,\n totalTokens: bucket.totalTokens,\n });\n }\n\n return Array.from(aggregated.values());\n}\n\nfunction toUploadSessions(\n sessions: SessionMetadata[],\n settings: ApiSettings,\n device: DeviceMetadata,\n): UploadSessionMetadata[] {\n return sessions.map((session) => {\n const project = toProjectIdentity({\n project: session.project || \"unknown\",\n mode: settings.projectMode,\n salt: settings.projectHashSalt,\n });\n\n return {\n source: session.source,\n projectKey: project.projectKey,\n projectLabel: project.projectLabel,\n sessionHash: session.sessionHash,\n deviceId: device.deviceId,\n hostname: device.hostname,\n firstMessageAt: session.firstMessageAt,\n lastMessageAt: session.lastMessageAt,\n durationSeconds: session.durationSeconds,\n activeSeconds: session.activeSeconds,\n messageCount: session.messageCount,\n userMessageCount: session.userMessageCount,\n inputTokens: session.inputTokens,\n outputTokens: session.outputTokens,\n reasoningTokens: session.reasoningTokens,\n cachedTokens: session.cachedTokens,\n totalTokens: session.totalTokens,\n primaryModel: session.primaryModel,\n modelUsages: session.modelUsages,\n };\n });\n}\n\nclass SyncFailure extends Error {\n constructor(\n message: string,\n readonly kind: \"auth_error\" | \"error\",\n readonly causeError?: Error,\n ) {\n super(message);\n }\n}\n\nexport async function runSync(\n config: Config,\n opts: SyncOptions = {},\n): Promise<SyncResult> {\n const { quiet = false, source = \"manual\", throws = false } = opts;\n\n const lock = tryAcquireSyncLock(source);\n if (!lock) {\n const detail = describeExistingSyncLock();\n const message = detail\n ? `Another sync is already running (${detail}). Skipping.`\n : \"Another sync is already running. Skipping.\";\n\n markSyncFailed(source, message, \"skipped_locked\");\n logger.info(message);\n return {\n buckets: 0,\n sessions: 0,\n skipped: \"locked\",\n };\n }\n\n markSyncStarted(source);\n\n let totalIngested = 0;\n let totalSessionsSynced = 0;\n let caughtError: SyncFailure | null = null;\n\n try {\n const {\n buckets: allBuckets,\n sessions: allSessions,\n parserResults,\n } = await runAllParsers();\n\n if (allBuckets.length === 0 && allSessions.length === 0) {\n if (!quiet) {\n logger.info(\"No new usage data found.\");\n }\n markSyncSucceeded(source, { buckets: 0, sessions: 0 });\n return { buckets: 0, sessions: 0 };\n }\n\n if (!quiet && parserResults.length > 0) {\n for (const p of parserResults) {\n const parts: string[] = [];\n if (p.buckets > 0) parts.push(`${p.buckets} buckets`);\n if (p.sessions > 0) parts.push(`${p.sessions} sessions`);\n logger.info(` ${p.source}: ${parts.join(\", \")}`);\n }\n }\n\n const apiUrl = config.apiUrl || \"https://token.poco-ai.com\";\n const apiClient = new ApiClient(apiUrl, config.apiKey);\n\n let settings: ApiSettings | null;\n try {\n settings = await apiClient.fetchSettings();\n } catch (error) {\n if ((error as Error).message === \"UNAUTHORIZED\") {\n throw new SyncFailure(\n \"Invalid API key. Run `tokenarena init` to reconfigure.\",\n \"auth_error\",\n error as Error,\n );\n }\n\n settings = null;\n }\n\n if (!settings) {\n throw new SyncFailure(\n \"Could not fetch usage settings. Check your server URL and API key.\",\n \"error\",\n );\n }\n\n const device = toDeviceMetadata(config);\n const manifestScope = buildUploadManifestScope({\n apiKey: config.apiKey,\n apiUrl,\n deviceId: device.deviceId,\n settings,\n });\n const uploadBuckets = toUploadBuckets(allBuckets, settings, device);\n const uploadSessions = toUploadSessions(allSessions, settings, device);\n const uploadDiff = diffUploadManifest({\n buckets: uploadBuckets,\n previous: loadUploadManifest(),\n scope: manifestScope,\n sessions: uploadSessions,\n });\n const changedBuckets = uploadDiff.bucketsToUpload;\n const changedSessions = uploadDiff.sessionsToUpload;\n\n if (!quiet && uploadDiff.scopeChangedReasons.length > 0) {\n logger.warn(\n `Upload scope changed (${uploadDiff.scopeChangedReasons.map(formatScopeChangeReason).join(\", \")}). TokenArena will upload the current snapshot again, but existing remote records from the previous scope will not be deleted automatically.`,\n );\n }\n\n if (\n !quiet &&\n (uploadDiff.removedBuckets > 0 || uploadDiff.removedSessions > 0)\n ) {\n const parts: string[] = [];\n if (uploadDiff.removedBuckets > 0) {\n parts.push(`${uploadDiff.removedBuckets} buckets`);\n }\n if (uploadDiff.removedSessions > 0) {\n parts.push(`${uploadDiff.removedSessions} sessions`);\n }\n logger.warn(\n `Detected ${parts.join(\" + \")} that were present in the previous local snapshot but are missing now. Remote deletions are not supported yet, so renamed projects or removed local logs may leave stale data online.`,\n );\n }\n\n if (changedBuckets.length === 0 && changedSessions.length === 0) {\n if (!quiet) {\n const skippedParts: string[] = [];\n if (uploadDiff.unchangedBuckets > 0) {\n skippedParts.push(`${uploadDiff.unchangedBuckets} unchanged buckets`);\n }\n if (uploadDiff.unchangedSessions > 0) {\n skippedParts.push(\n `${uploadDiff.unchangedSessions} unchanged sessions`,\n );\n }\n logger.info(\n skippedParts.length > 0\n ? `No new or updated usage data to upload. Skipped ${skippedParts.join(\" + \")}.`\n : \"No new or updated usage data to upload.\",\n );\n }\n persistUploadManifest(uploadDiff.nextManifest, quiet);\n markSyncSucceeded(source, { buckets: 0, sessions: 0 });\n return { buckets: 0, sessions: 0 };\n }\n\n const bucketBatches = Math.ceil(changedBuckets.length / BATCH_SIZE);\n const sessionBatches = Math.ceil(\n changedSessions.length / SESSION_BATCH_SIZE,\n );\n const totalBatches = Math.max(bucketBatches, sessionBatches, 1);\n const batchPayloadSizes = Array.from(\n { length: totalBatches },\n (_, batchIdx) =>\n getIngestPayloadSize(\n device,\n changedBuckets.slice(\n batchIdx * BATCH_SIZE,\n (batchIdx + 1) * BATCH_SIZE,\n ),\n changedSessions.slice(\n batchIdx * SESSION_BATCH_SIZE,\n (batchIdx + 1) * SESSION_BATCH_SIZE,\n ),\n ),\n );\n const totalPayloadBytes = batchPayloadSizes.reduce(\n (sum, size) => sum + size,\n 0,\n );\n let uploadedBytesBeforeBatch = 0;\n\n if (!quiet) {\n const parts: string[] = [];\n if (changedBuckets.length > 0) {\n parts.push(`${changedBuckets.length} buckets`);\n }\n if (changedSessions.length > 0) {\n parts.push(`${changedSessions.length} sessions`);\n }\n const skippedParts: string[] = [];\n if (uploadDiff.unchangedBuckets > 0) {\n skippedParts.push(`${uploadDiff.unchangedBuckets} unchanged buckets`);\n }\n if (uploadDiff.unchangedSessions > 0) {\n skippedParts.push(`${uploadDiff.unchangedSessions} unchanged sessions`);\n }\n logger.info(\n `Uploading ${parts.join(\" + \")} (${totalBatches} batch${totalBatches > 1 ? \"es\" : \"\"}${skippedParts.length > 0 ? `, skipped ${skippedParts.join(\" + \")}` : \"\"})...`,\n );\n }\n\n for (let batchIdx = 0; batchIdx < totalBatches; batchIdx++) {\n const batch = changedBuckets.slice(\n batchIdx * BATCH_SIZE,\n (batchIdx + 1) * BATCH_SIZE,\n );\n const batchSessions = changedSessions.slice(\n batchIdx * SESSION_BATCH_SIZE,\n (batchIdx + 1) * SESSION_BATCH_SIZE,\n );\n const batchNum = batchIdx + 1;\n\n const result = await apiClient.ingest(\n device,\n batch,\n batchSessions.length > 0 ? batchSessions : undefined,\n quiet\n ? undefined\n : (sent, total) => {\n writeUploadProgress(\n uploadedBytesBeforeBatch + sent,\n totalPayloadBytes || total,\n batchNum,\n totalBatches,\n );\n },\n );\n\n totalIngested += result.ingested ?? batch.length;\n totalSessionsSynced += result.sessions ?? batchSessions.length;\n uploadedBytesBeforeBatch += batchPayloadSizes[batchIdx] ?? 0;\n }\n\n if (!quiet && (totalBatches > 1 || changedBuckets.length > 0)) {\n writeUploadProgress(\n totalPayloadBytes,\n totalPayloadBytes,\n totalBatches,\n totalBatches,\n );\n process.stdout.write(\"\\n\");\n }\n\n const syncParts = [`${totalIngested} buckets`];\n if (totalSessionsSynced > 0) {\n syncParts.push(`${totalSessionsSynced} sessions`);\n }\n logger.info(`Synced ${syncParts.join(\" + \")}.`);\n\n if (!quiet) {\n logger.info(`\\nView your dashboard at: ${apiUrl}/usage`);\n }\n\n persistUploadManifest(uploadDiff.nextManifest, quiet);\n markSyncSucceeded(source, {\n buckets: totalIngested,\n sessions: totalSessionsSynced,\n });\n\n return {\n buckets: totalIngested,\n sessions: totalSessionsSynced,\n };\n } catch (error) {\n const httpErr = error as Error & { statusCode?: number };\n\n if (httpErr.message === \"UNAUTHORIZED\") {\n caughtError = new SyncFailure(\n \"Invalid API key. Run `tokenarena init` to reconfigure.\",\n \"auth_error\",\n error as Error,\n );\n } else if (error instanceof SyncFailure) {\n caughtError = error;\n } else if (totalIngested > 0) {\n caughtError = new SyncFailure(\n `Sync partially completed (${totalIngested} buckets uploaded). ${httpErr.message}`,\n \"error\",\n error as Error,\n );\n } else {\n caughtError = new SyncFailure(\n `Sync failed: ${httpErr.message}`,\n \"error\",\n error as Error,\n );\n }\n\n markSyncFailed(source, caughtError.message, caughtError.kind);\n } finally {\n lock.release();\n }\n\n if (!caughtError) {\n return {\n buckets: totalIngested,\n sessions: totalSessionsSynced,\n };\n }\n\n logger.error(caughtError.message);\n if (throws) {\n throw caughtError.causeError ?? caughtError;\n }\n process.exit(1);\n}\n","import { createHmac } from \"node:crypto\";\n\nexport function toProjectIdentity(input: {\n project: string;\n mode: \"hashed\" | \"raw\" | \"disabled\";\n salt: string;\n}) {\n if (input.mode === \"disabled\") {\n return { projectKey: \"unknown\", projectLabel: \"Unknown Project\" };\n }\n\n if (input.mode === \"raw\") {\n return { projectKey: input.project, projectLabel: input.project };\n }\n\n const projectKey = createHmac(\"sha256\", input.salt)\n .update(input.project)\n .digest(\"hex\")\n .slice(0, 16);\n\n return {\n projectKey,\n projectLabel: `Project ${projectKey.slice(0, 6)}`,\n };\n}\n","import { createHash } from \"node:crypto\";\nimport type {\n ApiSettings,\n UploadSessionMetadata,\n UploadTokenBucket,\n} from \"./types\";\n\nconst MANIFEST_VERSION = 1 as const;\n\nfunction shortHash(value: string): string {\n return createHash(\"sha256\").update(value).digest(\"hex\").slice(0, 16);\n}\n\nfunction normalizeApiUrl(apiUrl: string): string {\n return apiUrl.replace(/\\/+$/, \"\");\n}\n\nexport interface UploadManifestScope {\n apiKeyHash: string;\n apiUrl: string;\n deviceId: string;\n projectHashSaltHash: string;\n projectMode: ApiSettings[\"projectMode\"];\n}\n\nexport interface UploadManifest {\n buckets: Record<string, string>;\n scope: UploadManifestScope;\n sessions: Record<string, string>;\n updatedAt: string;\n version: typeof MANIFEST_VERSION;\n}\n\nexport interface UploadManifestDiff {\n bucketsToUpload: UploadTokenBucket[];\n nextManifest: UploadManifest;\n removedBuckets: number;\n removedSessions: number;\n scopeChangedReasons: UploadManifestScopeChange[];\n sessionsToUpload: UploadSessionMetadata[];\n unchangedBuckets: number;\n unchangedSessions: number;\n}\n\nexport type UploadManifestScopeChange =\n | \"device_id\"\n | \"project_identity\"\n | \"server_or_api_key\";\n\nexport function buildUploadManifestScope(input: {\n apiKey: string;\n apiUrl: string;\n deviceId: string;\n settings: ApiSettings;\n}): UploadManifestScope {\n return {\n apiKeyHash: shortHash(input.apiKey),\n apiUrl: normalizeApiUrl(input.apiUrl),\n deviceId: input.deviceId,\n projectHashSaltHash: shortHash(input.settings.projectHashSalt),\n projectMode: input.settings.projectMode,\n };\n}\n\nexport function describeUploadManifestScopeChanges(\n previous: UploadManifestScope,\n current: UploadManifestScope,\n): UploadManifestScopeChange[] {\n const changes: UploadManifestScopeChange[] = [];\n\n if (\n previous.apiUrl !== current.apiUrl ||\n previous.apiKeyHash !== current.apiKeyHash\n ) {\n changes.push(\"server_or_api_key\");\n }\n\n if (previous.deviceId !== current.deviceId) {\n changes.push(\"device_id\");\n }\n\n if (\n previous.projectMode !== current.projectMode ||\n previous.projectHashSaltHash !== current.projectHashSaltHash\n ) {\n changes.push(\"project_identity\");\n }\n\n return changes;\n}\n\nexport function getUploadBucketManifestKey(bucket: UploadTokenBucket): string {\n return [\n bucket.deviceId,\n bucket.source,\n bucket.model,\n bucket.projectKey,\n bucket.bucketStart,\n ].join(\"|\");\n}\n\nexport function getUploadSessionManifestKey(\n session: UploadSessionMetadata,\n): string {\n return [session.deviceId, session.source, session.sessionHash].join(\"|\");\n}\n\nfunction getUploadBucketContentHash(bucket: UploadTokenBucket): string {\n return shortHash(\n JSON.stringify({\n cachedTokens: bucket.cachedTokens,\n hostname: bucket.hostname,\n inputTokens: bucket.inputTokens,\n outputTokens: bucket.outputTokens,\n projectLabel: bucket.projectLabel,\n reasoningTokens: bucket.reasoningTokens,\n totalTokens: bucket.totalTokens,\n }),\n );\n}\n\nfunction getUploadSessionContentHash(session: UploadSessionMetadata): string {\n return shortHash(\n JSON.stringify({\n activeSeconds: session.activeSeconds,\n cachedTokens: session.cachedTokens,\n durationSeconds: session.durationSeconds,\n firstMessageAt: session.firstMessageAt,\n hostname: session.hostname,\n inputTokens: session.inputTokens,\n lastMessageAt: session.lastMessageAt,\n messageCount: session.messageCount,\n modelUsages: session.modelUsages,\n outputTokens: session.outputTokens,\n primaryModel: session.primaryModel,\n projectKey: session.projectKey,\n projectLabel: session.projectLabel,\n reasoningTokens: session.reasoningTokens,\n totalTokens: session.totalTokens,\n userMessageCount: session.userMessageCount,\n }),\n );\n}\n\nfunction buildRecordHashes<T>(\n items: T[],\n getKey: (item: T) => string,\n getHash: (item: T) => string,\n): Record<string, string> {\n const hashes: Record<string, string> = {};\n\n for (const item of items) {\n hashes[getKey(item)] = getHash(item);\n }\n\n return hashes;\n}\n\nexport function createUploadManifest(input: {\n buckets: UploadTokenBucket[];\n scope: UploadManifestScope;\n sessions: UploadSessionMetadata[];\n updatedAt?: string;\n}): UploadManifest {\n return {\n buckets: buildRecordHashes(\n input.buckets,\n getUploadBucketManifestKey,\n getUploadBucketContentHash,\n ),\n scope: input.scope,\n sessions: buildRecordHashes(\n input.sessions,\n getUploadSessionManifestKey,\n getUploadSessionContentHash,\n ),\n updatedAt: input.updatedAt ?? new Date().toISOString(),\n version: MANIFEST_VERSION,\n };\n}\n\nfunction countRemovedRecords(\n previous: Record<string, string>,\n current: Record<string, string>,\n): number {\n let removed = 0;\n\n for (const key of Object.keys(previous)) {\n if (!(key in current)) {\n removed++;\n }\n }\n\n return removed;\n}\n\nexport function diffUploadManifest(input: {\n buckets: UploadTokenBucket[];\n previous: UploadManifest | null;\n scope: UploadManifestScope;\n sessions: UploadSessionMetadata[];\n updatedAt?: string;\n}): UploadManifestDiff {\n const nextManifest = createUploadManifest({\n buckets: input.buckets,\n scope: input.scope,\n sessions: input.sessions,\n updatedAt: input.updatedAt,\n });\n\n const scopeChangedReasons = input.previous\n ? describeUploadManifestScopeChanges(input.previous.scope, input.scope)\n : [];\n\n const previousBuckets =\n input.previous && scopeChangedReasons.length === 0\n ? input.previous.buckets\n : {};\n const previousSessions =\n input.previous && scopeChangedReasons.length === 0\n ? input.previous.sessions\n : {};\n\n const bucketsToUpload = input.buckets.filter((bucket) => {\n const key = getUploadBucketManifestKey(bucket);\n return previousBuckets[key] !== nextManifest.buckets[key];\n });\n const sessionsToUpload = input.sessions.filter((session) => {\n const key = getUploadSessionManifestKey(session);\n return previousSessions[key] !== nextManifest.sessions[key];\n });\n\n return {\n bucketsToUpload,\n nextManifest,\n removedBuckets: countRemovedRecords(previousBuckets, nextManifest.buckets),\n removedSessions: countRemovedRecords(\n previousSessions,\n nextManifest.sessions,\n ),\n scopeChangedReasons,\n sessionsToUpload,\n unchangedBuckets: input.buckets.length - bucketsToUpload.length,\n unchangedSessions: input.sessions.length - sessionsToUpload.length,\n };\n}\n","import http from \"node:http\";\nimport https from \"node:https\";\nimport { URL } from \"node:url\";\nimport type {\n ApiSettings,\n DeviceMetadata,\n IngestResponse,\n UploadSessionMetadata,\n UploadTokenBucket,\n} from \"../../domain/types\";\n\nconst MAX_RETRIES = 3;\nconst INITIAL_DELAY = 1000;\nconst TIMEOUT_MS = 60_000;\n\nexport function getIngestPayloadSize(\n device: DeviceMetadata,\n buckets: UploadTokenBucket[],\n sessions?: UploadSessionMetadata[],\n): number {\n const payload = {\n schemaVersion: 2 as const,\n device,\n buckets,\n sessions: sessions ?? [],\n };\n\n return Buffer.byteLength(JSON.stringify(payload));\n}\n\nexport class ApiClient {\n constructor(\n private apiUrl: string,\n private apiKey: string,\n ) {}\n\n /**\n * Ingest buckets and sessions to server\n */\n async ingest(\n device: DeviceMetadata,\n buckets: UploadTokenBucket[],\n sessions?: UploadSessionMetadata[],\n onProgress?: (sent: number, total: number) => void,\n ): Promise<{ ingested?: number; sessions?: number }> {\n let lastError: Error | undefined;\n for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {\n try {\n return await this.sendIngest(device, buckets, sessions, onProgress);\n } catch (err) {\n lastError = err as Error;\n const httpErr = err as { statusCode?: number; message: string };\n // Don't retry auth errors or client errors\n if (\n httpErr.message === \"UNAUTHORIZED\" ||\n (httpErr.statusCode &&\n httpErr.statusCode >= 400 &&\n httpErr.statusCode < 500)\n ) {\n throw err;\n }\n if (attempt < MAX_RETRIES - 1) {\n const delay = INITIAL_DELAY * 2 ** attempt;\n await new Promise((r) => setTimeout(r, delay));\n }\n }\n }\n throw lastError;\n }\n\n private sendIngest(\n device: DeviceMetadata,\n buckets: UploadTokenBucket[],\n sessions?: UploadSessionMetadata[],\n onProgress?: (sent: number, total: number) => void,\n ): Promise<{ ingested?: number; sessions?: number }> {\n return new Promise((resolve, reject) => {\n const url = new URL(\"/api/usage/ingest\", this.apiUrl);\n const body = Buffer.from(\n JSON.stringify({\n schemaVersion: 2 as const,\n device,\n buckets,\n sessions: sessions ?? [],\n }),\n );\n const totalBytes = body.length;\n const mod = url.protocol === \"https:\" ? https : http;\n\n const req = mod.request(\n url,\n {\n method: \"POST\",\n timeout: TIMEOUT_MS,\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.apiKey}`,\n \"Content-Length\": totalBytes,\n },\n },\n (res) => {\n let data = \"\";\n res.on(\"data\", (chunk) => {\n data += chunk;\n });\n res.on(\"end\", () => {\n if (res.statusCode === 401) {\n reject(new Error(\"UNAUTHORIZED\"));\n return;\n }\n if (\n !res.statusCode ||\n res.statusCode < 200 ||\n res.statusCode >= 300\n ) {\n const err = new Error(\n `HTTP ${res.statusCode}: ${data}`,\n ) as Error & {\n statusCode?: number;\n };\n err.statusCode = res.statusCode;\n reject(err);\n return;\n }\n try {\n const response = JSON.parse(data) as IngestResponse;\n resolve({\n ingested: response.bucketCount ?? response.ingested,\n sessions: response.sessionCount ?? response.sessions,\n });\n } catch {\n reject(new Error(`Invalid JSON response: ${data}`));\n }\n });\n },\n );\n\n req.on(\"error\", (err) => reject(err));\n req.on(\"timeout\", () => {\n req.destroy();\n reject(new Error(\"Request timed out (60s)\"));\n });\n\n // Write body in chunks to report upload progress\n const CHUNK = 16 * 1024;\n let sent = 0;\n\n const writeNext = () => {\n let ok = true;\n while (ok && sent < totalBytes) {\n const slice = body.subarray(sent, sent + CHUNK);\n sent += slice.length;\n if (onProgress) onProgress(sent, totalBytes);\n ok = req.write(slice);\n }\n if (sent < totalBytes) {\n req.once(\"drain\", writeNext);\n } else {\n req.end();\n }\n };\n\n writeNext();\n });\n }\n\n /**\n * Fetch user settings from server\n */\n async fetchSettings(): Promise<ApiSettings | null> {\n return new Promise((resolve, reject) => {\n const url = new URL(\"/api/usage/settings\", this.apiUrl);\n const mod = url.protocol === \"https:\" ? https : http;\n\n const req = mod.request(\n url,\n {\n method: \"GET\",\n timeout: 10_000,\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n },\n },\n (res) => {\n let data = \"\";\n res.on(\"data\", (chunk) => {\n data += chunk;\n });\n res.on(\"end\", () => {\n if (res.statusCode === 401) {\n reject(new Error(\"UNAUTHORIZED\"));\n return;\n }\n if (\n !res.statusCode ||\n res.statusCode < 200 ||\n res.statusCode >= 300\n ) {\n resolve(null);\n return;\n }\n try {\n const settings = JSON.parse(data) as ApiSettings;\n if (\n settings.schemaVersion !== 2 ||\n !settings.projectMode ||\n !settings.projectHashSalt ||\n !settings.timezone\n ) {\n resolve(null);\n return;\n }\n\n resolve(settings);\n } catch {\n resolve(null);\n }\n });\n },\n );\n\n req.on(\"error\", () => resolve(null));\n req.on(\"timeout\", () => {\n req.destroy();\n resolve(null);\n });\n req.end();\n });\n }\n\n /**\n * Delete all usage data for the authenticated user\n */\n async deleteAllData(opts?: {\n hostname?: string;\n }): Promise<{ deleted: number }> {\n return new Promise((resolve, reject) => {\n const url = new URL(\"/api/usage/ingest\", this.apiUrl);\n if (opts?.hostname) {\n url.searchParams.set(\"hostname\", opts.hostname);\n }\n const mod = url.protocol === \"https:\" ? https : http;\n\n const req = mod.request(\n url,\n {\n method: \"DELETE\",\n timeout: TIMEOUT_MS,\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n },\n },\n (res) => {\n let data = \"\";\n res.on(\"data\", (chunk) => {\n data += chunk;\n });\n res.on(\"end\", () => {\n if (res.statusCode === 401) {\n reject(new Error(\"UNAUTHORIZED\"));\n return;\n }\n if (\n !res.statusCode ||\n res.statusCode < 200 ||\n res.statusCode >= 300\n ) {\n const err = new Error(\n `HTTP ${res.statusCode}: ${data}`,\n ) as Error & {\n statusCode?: number;\n };\n err.statusCode = res.statusCode;\n reject(err);\n return;\n }\n try {\n resolve(JSON.parse(data));\n } catch {\n reject(new Error(`Invalid JSON response: ${data}`));\n }\n });\n },\n );\n\n req.on(\"error\", (err) => reject(err));\n req.on(\"timeout\", () => {\n req.destroy();\n reject(new Error(\"Request timed out (60s)\"));\n });\n req.end();\n });\n }\n}\n","import {\n closeSync,\n existsSync,\n openSync,\n readFileSync,\n rmSync,\n writeFileSync,\n} from \"node:fs\";\nimport { ensureAppDirs, getSyncLockPath } from \"./paths\";\nimport type { SyncSource } from \"./state\";\n\ninterface LockMetadata {\n createdAt: string;\n pid: number;\n source: SyncSource;\n}\n\nexport interface SyncLock {\n release(): void;\n}\n\nfunction isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n return code !== \"ESRCH\";\n }\n}\n\nfunction readLockMetadata(lockPath: string): LockMetadata | null {\n if (!existsSync(lockPath)) {\n return null;\n }\n\n try {\n return JSON.parse(readFileSync(lockPath, \"utf-8\")) as LockMetadata;\n } catch {\n return null;\n }\n}\n\nfunction removeStaleLock(lockPath: string): void {\n const metadata = readLockMetadata(lockPath);\n if (!metadata) {\n rmSync(lockPath, { force: true });\n return;\n }\n\n if (!isProcessAlive(metadata.pid)) {\n rmSync(lockPath, { force: true });\n }\n}\n\nexport function tryAcquireSyncLock(source: SyncSource): SyncLock | null {\n ensureAppDirs();\n const lockPath = getSyncLockPath();\n\n try {\n const fd = openSync(lockPath, \"wx\");\n const metadata: LockMetadata = {\n createdAt: new Date().toISOString(),\n pid: process.pid,\n source,\n };\n writeFileSync(fd, JSON.stringify(metadata, null, 2));\n closeSync(fd);\n\n return {\n release() {\n rmSync(lockPath, { force: true });\n },\n };\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (code !== \"EEXIST\") {\n throw error;\n }\n }\n\n removeStaleLock(lockPath);\n\n try {\n const fd = openSync(lockPath, \"wx\");\n const metadata: LockMetadata = {\n createdAt: new Date().toISOString(),\n pid: process.pid,\n source,\n };\n writeFileSync(fd, JSON.stringify(metadata, null, 2));\n closeSync(fd);\n\n return {\n release() {\n rmSync(lockPath, { force: true });\n },\n };\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (code === \"EEXIST\") {\n return null;\n }\n throw error;\n }\n}\n\nexport function describeExistingSyncLock(): string | null {\n const metadata = readLockMetadata(getSyncLockPath());\n if (!metadata) {\n return null;\n }\n\n return `pid=${metadata.pid}, source=${metadata.source}, createdAt=${metadata.createdAt}`;\n}\n","import { mkdirSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { getRuntimeDir, getStateHome } from \"../xdg\";\n\nconst APP_NAME = \"tokenarena\";\n\nexport function getConfigDir(): string {\n // Re-exported from manager for backward compat — callers should import from manager directly\n throw new Error(\"Use getConfigDir() from config/manager instead\");\n}\n\nexport function getRuntimeDirPath(): string {\n return join(getRuntimeDir(), APP_NAME);\n}\n\nexport function getStateDir(): string {\n return join(getStateHome(), APP_NAME);\n}\n\nexport function getSyncLockPath(): string {\n return join(getRuntimeDirPath(), \"sync.lock\");\n}\n\nexport function getSyncStatePath(): string {\n return join(getStateDir(), \"status.json\");\n}\n\nexport function getUploadManifestPath(): string {\n return join(getStateDir(), \"upload-manifest.json\");\n}\n\nexport function ensureAppDirs(): void {\n mkdirSync(getRuntimeDirPath(), { recursive: true });\n mkdirSync(getStateDir(), { recursive: true });\n}\n","import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { ensureAppDirs, getSyncStatePath } from \"./paths\";\n\nexport type SyncSource = \"daemon\" | \"default\" | \"init\" | \"manual\";\n\nexport type SyncStateStatus =\n | \"auth_error\"\n | \"error\"\n | \"idle\"\n | \"skipped_locked\"\n | \"syncing\";\n\nexport interface SyncState {\n pid?: number;\n lastAttemptAt?: string;\n lastCompletedAt?: string;\n lastError?: string;\n lastFailureAt?: string;\n lastResult?: {\n buckets: number;\n sessions: number;\n };\n lastSource?: SyncSource;\n lastSuccessAt?: string;\n status: SyncStateStatus;\n}\n\nfunction getDefaultState(): SyncState {\n return { status: \"idle\" };\n}\n\nexport function loadSyncState(): SyncState {\n const path = getSyncStatePath();\n if (!existsSync(path)) {\n return getDefaultState();\n }\n\n try {\n return {\n ...getDefaultState(),\n ...(JSON.parse(readFileSync(path, \"utf-8\")) as Partial<SyncState>),\n };\n } catch {\n return getDefaultState();\n }\n}\n\nexport function saveSyncState(next: SyncState): void {\n ensureAppDirs();\n writeFileSync(\n getSyncStatePath(),\n `${JSON.stringify(next, null, 2)}\\n`,\n \"utf-8\",\n );\n}\n\nexport function markSyncStarted(source: SyncSource): void {\n const current = loadSyncState();\n saveSyncState({\n ...current,\n pid: process.pid,\n lastAttemptAt: new Date().toISOString(),\n lastSource: source,\n status: \"syncing\",\n });\n}\n\nexport function markSyncSucceeded(\n source: SyncSource,\n result: { buckets: number; sessions: number },\n): void {\n const now = new Date().toISOString();\n const current = loadSyncState();\n saveSyncState({\n ...current,\n lastCompletedAt: now,\n lastError: undefined,\n lastFailureAt: undefined,\n lastResult: result,\n lastSource: source,\n lastSuccessAt: now,\n pid: undefined,\n status: \"idle\",\n });\n}\n\nexport function markSyncFailed(\n source: SyncSource,\n error: string,\n status: Extract<SyncStateStatus, \"auth_error\" | \"error\" | \"skipped_locked\">,\n): void {\n const now = new Date().toISOString();\n const current = loadSyncState();\n saveSyncState({\n ...current,\n lastCompletedAt: now,\n lastError: error,\n lastFailureAt: now,\n lastSource: source,\n pid: undefined,\n status,\n });\n}\n","import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport type { UploadManifest } from \"../../domain/upload-manifest\";\nimport { ensureAppDirs, getUploadManifestPath } from \"./paths\";\n\nfunction isRecordOfStrings(value: unknown): value is Record<string, string> {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return false;\n }\n\n return Object.values(value).every((entry) => typeof entry === \"string\");\n}\n\nfunction isUploadManifest(value: unknown): value is UploadManifest {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return false;\n }\n\n const manifest = value as Partial<UploadManifest>;\n\n return (\n manifest.version === 1 &&\n !!manifest.scope &&\n typeof manifest.scope === \"object\" &&\n typeof manifest.scope.apiUrl === \"string\" &&\n typeof manifest.scope.apiKeyHash === \"string\" &&\n typeof manifest.scope.deviceId === \"string\" &&\n typeof manifest.scope.projectMode === \"string\" &&\n typeof manifest.scope.projectHashSaltHash === \"string\" &&\n typeof manifest.updatedAt === \"string\" &&\n isRecordOfStrings(manifest.buckets) &&\n isRecordOfStrings(manifest.sessions)\n );\n}\n\nexport function loadUploadManifest(): UploadManifest | null {\n const path = getUploadManifestPath();\n if (!existsSync(path)) {\n return null;\n }\n\n try {\n const parsed = JSON.parse(readFileSync(path, \"utf-8\")) as unknown;\n return isUploadManifest(parsed) ? parsed : null;\n } catch {\n return null;\n }\n}\n\nexport function saveUploadManifest(manifest: UploadManifest): void {\n ensureAppDirs();\n writeFileSync(\n getUploadManifestPath(),\n `${JSON.stringify(manifest, null, 2)}\\n`,\n \"utf-8\",\n );\n}\n","import type {\n ParseResult,\n SessionMetadata,\n TokenBucket,\n} from \"../domain/types\";\nimport { detectInstalledTools, getAllParsers } from \"../parsers/registry\";\nimport { logger } from \"../utils/logger\";\n\nexport interface ParserResult {\n source: string;\n buckets: number;\n sessions: number;\n}\n\nexport interface AllParsersResult {\n buckets: TokenBucket[];\n sessions: SessionMetadata[];\n parserResults: ParserResult[];\n}\n\n/**\n * Run all registered parsers and collect results\n */\nexport async function runAllParsers(): Promise<AllParsersResult> {\n const allBuckets: TokenBucket[] = [];\n const allSessions: SessionMetadata[] = [];\n const parserResults: ParserResult[] = [];\n\n for (const parser of getAllParsers()) {\n try {\n const result: ParseResult = await parser.parse();\n const buckets = result.buckets;\n const sessions = result.sessions;\n\n if (buckets.length > 0) allBuckets.push(...buckets);\n if (sessions.length > 0) allSessions.push(...sessions);\n\n if (buckets.length > 0 || sessions.length > 0) {\n parserResults.push({\n source: parser.tool.id,\n buckets: buckets.length,\n sessions: sessions.length,\n });\n }\n } catch (err) {\n logger.warn(`${parser.tool.id} parser failed: ${(err as Error).message}`);\n }\n }\n\n return { buckets: allBuckets, sessions: allSessions, parserResults };\n}\n\n/**\n * Get list of detected tools for status display\n */\nexport function getDetectedTools() {\n return detectInstalledTools();\n}\n","import { execFileSync, spawn } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { appendFile, mkdir, readFile } from \"node:fs/promises\";\nimport { homedir, platform } from \"node:os\";\nimport { dirname, join, posix, win32 } from \"node:path\";\nimport { ApiClient } from \"../infrastructure/api/client\";\nimport {\n type Config,\n getDefaultApiUrl,\n getOrCreateDeviceId,\n loadConfig,\n saveConfig,\n validateApiKey,\n} from \"../infrastructure/config/manager\";\nimport { getServiceBackend } from \"../infrastructure/service\";\nimport {\n formatBullet,\n formatHeader,\n formatKeyValue,\n formatMutedPath,\n formatSection,\n maskSecret,\n} from \"../infrastructure/ui/format\";\nimport { promptConfirm, promptPassword } from \"../infrastructure/ui/prompts\";\nimport { getDetectedTools } from \"../services/parser-service\";\nimport { runSync } from \"../services/sync-service\";\nimport { logger } from \"../utils/logger\";\n\ninterface BrowserLaunchCommand {\n command: string;\n args: string[];\n}\n\nexport interface ShellAliasSetup {\n aliasLine: string;\n aliasPatterns: string[];\n configFile: string;\n shellLabel: string;\n sourceHint: string;\n}\n\ninterface ResolveShellAliasSetupOptions {\n currentPlatform?: NodeJS.Platform;\n env?: NodeJS.ProcessEnv;\n exists?: (path: string) => boolean;\n homeDir?: string;\n resolvePowerShellProfilePath?: () => string | null;\n}\n\nfunction joinForPlatform(\n currentPlatform: NodeJS.Platform,\n ...parts: string[]\n): string {\n return currentPlatform === \"win32\"\n ? win32.join(...parts)\n : posix.join(...parts);\n}\n\nfunction basenameLikeShell(input: string): string {\n return (\n input\n .split(/[\\\\/]+/)\n .pop()\n ?.replace(/\\.exe$/i, \"\") ?? input\n );\n}\n\nexport function getBrowserLaunchCommand(\n url: string,\n currentPlatform: NodeJS.Platform = platform(),\n): BrowserLaunchCommand {\n switch (currentPlatform) {\n case \"darwin\":\n return {\n command: \"open\",\n args: [url],\n };\n case \"win32\":\n return {\n command: \"cmd.exe\",\n args: [\"/d\", \"/s\", \"/c\", \"start\", \"\", url],\n };\n default:\n return {\n command: \"xdg-open\",\n args: [url],\n };\n }\n}\n\nfunction openBrowser(url: string): void {\n const { command, args } = getBrowserLaunchCommand(url);\n\n try {\n const child = spawn(command, args, {\n detached: true,\n stdio: \"ignore\",\n windowsHide: true,\n });\n\n child.on(\"error\", () => {});\n child.unref();\n } catch {\n // Best-effort only. We still print the URL for manual use.\n }\n}\n\nfunction resolvePowerShellProfilePath(): string | null {\n const systemRoot = process.env.SYSTEMROOT || \"C:\\\\Windows\";\n const candidates = [\n \"pwsh.exe\",\n join(systemRoot, \"System32\", \"WindowsPowerShell\", \"v1.0\", \"powershell.exe\"),\n ];\n\n for (const command of candidates) {\n try {\n const output = execFileSync(\n command,\n [\n \"-NoLogo\",\n \"-NoProfile\",\n \"-Command\",\n \"$PROFILE.CurrentUserCurrentHost\",\n ],\n {\n encoding: \"utf-8\",\n timeout: 3000,\n windowsHide: true,\n },\n ).trim();\n\n if (output) {\n return output;\n }\n } catch {\n // Try the next PowerShell executable.\n }\n }\n\n return null;\n}\n\nexport function resolveShellAliasSetup(\n options: ResolveShellAliasSetupOptions = {},\n): ShellAliasSetup | null {\n const currentPlatform = options.currentPlatform ?? platform();\n const env = options.env ?? process.env;\n const homeDir = options.homeDir ?? homedir();\n const pathExists = options.exists ?? existsSync;\n\n const shellFromEnv = env.SHELL\n ? basenameLikeShell(env.SHELL).toLowerCase()\n : \"\";\n const shellName =\n shellFromEnv || (currentPlatform === \"win32\" ? \"powershell\" : \"\");\n const aliasName = \"ta\";\n\n switch (shellName) {\n case \"zsh\":\n return {\n aliasLine: `alias ${aliasName}=\"tokenarena\"`,\n aliasPatterns: [`alias ${aliasName}=`, `function ${aliasName}`],\n configFile: joinForPlatform(currentPlatform, homeDir, \".zshrc\"),\n shellLabel: \"zsh\",\n sourceHint: \"source ~/.zshrc\",\n };\n case \"bash\": {\n const bashProfile = joinForPlatform(\n currentPlatform,\n homeDir,\n \".bash_profile\",\n );\n const useBashProfile =\n currentPlatform === \"darwin\" && pathExists(bashProfile);\n\n return {\n aliasLine: `alias ${aliasName}=\"tokenarena\"`,\n aliasPatterns: [`alias ${aliasName}=`, `function ${aliasName}`],\n configFile: useBashProfile\n ? bashProfile\n : joinForPlatform(currentPlatform, homeDir, \".bashrc\"),\n shellLabel: \"bash\",\n sourceHint: useBashProfile\n ? \"source ~/.bash_profile\"\n : \"source ~/.bashrc\",\n };\n }\n case \"fish\":\n return {\n aliasLine: `alias ${aliasName} \"tokenarena\"`,\n aliasPatterns: [`alias ${aliasName}`, `function ${aliasName}`],\n configFile: joinForPlatform(\n currentPlatform,\n homeDir,\n \".config\",\n \"fish\",\n \"config.fish\",\n ),\n shellLabel: \"fish\",\n sourceHint: \"source ~/.config/fish/config.fish\",\n };\n case \"powershell\": {\n const configFile =\n options.resolvePowerShellProfilePath?.() ||\n resolvePowerShellProfilePath() ||\n joinForPlatform(\n currentPlatform,\n homeDir,\n \"Documents\",\n \"PowerShell\",\n \"Microsoft.PowerShell_profile.ps1\",\n );\n\n return {\n aliasLine: `Set-Alias -Name ${aliasName} -Value tokenarena`,\n aliasPatterns: [\n `set-alias -name ${aliasName}`,\n `set-alias ${aliasName}`,\n `new-alias ${aliasName}`,\n `function ${aliasName}`,\n ],\n configFile,\n shellLabel: \"PowerShell\",\n sourceHint: \". $PROFILE\",\n };\n }\n default:\n return null;\n }\n}\n\nexport interface InitOptions {\n apiUrl?: string;\n}\n\nexport async function runInit(opts: InitOptions = {}): Promise<void> {\n logger.info(formatHeader(\"TokenArena 初始化\"));\n\n const existing = loadConfig();\n if (existing?.apiKey) {\n logger.info(formatSection(\"检测到已有配置\"));\n logger.info(formatKeyValue(\"当前 API Key\", maskSecret(existing.apiKey)));\n logger.info(\n formatKeyValue(\n \"当前 API 地址\",\n existing.apiUrl || \"https://token.poco-ai.com\",\n ),\n );\n\n const shouldOverwrite = await promptConfirm({\n message: \"已经存在本地配置,是否覆盖并重新初始化?\",\n defaultValue: false,\n });\n\n if (!shouldOverwrite) {\n logger.info(formatBullet(\"已取消初始化。\", \"warning\"));\n return;\n }\n }\n\n const apiUrl = opts.apiUrl || getDefaultApiUrl();\n const cliKeysUrl = `${apiUrl}/zh/settings/cli-keys`;\n logger.info(formatSection(\"第 1 步:准备 API Key\"));\n logger.info(formatBullet(\"浏览器将尝试自动打开 CLI Key 页面。\"));\n logger.info(formatKeyValue(\"Key 页面\", formatMutedPath(cliKeysUrl)));\n openBrowser(cliKeysUrl);\n\n const apiKey = await promptPassword({\n message: \"请粘贴你的 CLI API Key\",\n validate: (value) => validateApiKey(value) || 'API Key 必须以 \"ta_\" 开头。',\n });\n\n logger.info(formatSection(\"第 2 步:验证 API Key\"));\n logger.info(formatKeyValue(\"待验证 Key\", maskSecret(apiKey)));\n try {\n const client = new ApiClient(apiUrl, apiKey);\n const settings = await client.fetchSettings();\n\n if (!settings) {\n logger.info(\n formatBullet(\n \"无法在线验证 Key(可能是网络原因),将继续保存。\",\n \"warning\",\n ),\n );\n } else {\n logger.info(formatBullet(\"API Key 验证成功。\", \"success\"));\n }\n } catch (err) {\n if ((err as Error).message === \"UNAUTHORIZED\") {\n logger.error(\"Invalid API key. Please check and try again.\");\n process.exit(1);\n }\n logger.info(\n formatBullet(\n \"无法完成在线验证(可能是网络原因),将继续保存。\",\n \"warning\",\n ),\n );\n }\n\n const config: Config = {\n apiKey,\n apiUrl,\n ...(existing?.deviceId ? { deviceId: existing.deviceId } : {}),\n };\n saveConfig(config);\n const deviceId = getOrCreateDeviceId(config);\n config.deviceId = deviceId;\n logger.info(formatSection(\"第 3 步:完成本地注册\"));\n\n const tools = getDetectedTools();\n if (tools.length > 0) {\n logger.info(formatSection(\"检测到的 AI CLI\"));\n for (const tool of tools) {\n logger.info(formatBullet(tool.name, \"success\"));\n }\n } else {\n logger.info(formatSection(\"检测到的 AI CLI\"));\n logger.info(\n formatBullet(\n \"当前未检测到已安装工具,稍后安装后也可以直接执行 sync。\",\n \"warning\",\n ),\n );\n }\n\n logger.info(formatSection(\"首次同步\"));\n logger.info(formatBullet(\"正在上传本地已有的使用数据。\"));\n await runSync(config, { source: \"init\" });\n\n logger.info(formatSection(\"初始化完成\"));\n logger.info(formatBullet(\"TokenArena 已准备就绪。\", \"success\"));\n logger.info(formatKeyValue(\"控制台\", `${apiUrl}/usage`));\n\n await setupShellAlias();\n await setupBackgroundService();\n}\n\nasync function setupBackgroundService(): Promise<void> {\n const backend = getServiceBackend();\n if (!backend) {\n return;\n }\n\n const support = backend.canSetup();\n if (!support.ok) {\n return;\n }\n\n const shouldSetup = await promptConfirm({\n message: `是否设置 ${backend.displayName} 以自动运行 daemon?`,\n defaultValue: true,\n });\n\n if (!shouldSetup) {\n logger.info(formatBullet(\"已跳过后台服务设置。\"));\n return;\n }\n\n try {\n await backend.setup(true);\n } catch (err) {\n logger.warn(`${backend.displayName} 设置失败: ${(err as Error).message}`);\n }\n}\n\nasync function setupShellAlias(): Promise<void> {\n const setup = resolveShellAliasSetup();\n if (!setup) {\n return;\n }\n\n const shouldCreateAlias = await promptConfirm({\n message: `是否为 ${setup.shellLabel} 自动添加 ta 别名?`,\n defaultValue: true,\n });\n if (!shouldCreateAlias) {\n logger.info(formatBullet(\"已跳过 shell alias 设置。\"));\n return;\n }\n\n try {\n await mkdir(dirname(setup.configFile), { recursive: true });\n\n let existingContent = \"\";\n if (existsSync(setup.configFile)) {\n existingContent = await readFile(setup.configFile, \"utf-8\");\n }\n\n const normalizedContent = existingContent.toLowerCase();\n const aliasExists = setup.aliasPatterns.some((pattern) =>\n normalizedContent.includes(pattern.toLowerCase()),\n );\n\n if (aliasExists) {\n logger.info(formatBullet(`别名 ta 已存在:${setup.configFile}`));\n return;\n }\n\n const aliasWithComment = `\\n# TokenArena alias\\n${setup.aliasLine}\\n`;\n await appendFile(setup.configFile, aliasWithComment, \"utf-8\");\n\n logger.info(formatSection(\"Shell alias\"));\n logger.info(formatBullet(`已写入 ${setup.configFile}`, \"success\"));\n logger.info(\n formatKeyValue(\"生效方式\", `执行 '${setup.sourceHint}' 或重启终端`),\n );\n logger.info(formatKeyValue(\"之后可用\", \"ta sync\"));\n } catch (err) {\n logger.info(formatSection(\"Shell alias\"));\n logger.info(\n formatBullet(\n `无法写入 ${setup.configFile}: ${(err as Error).message}`,\n \"warning\",\n ),\n );\n logger.info(formatKeyValue(\"请手动添加\", setup.aliasLine));\n }\n}\n","import { platform } from \"node:os\";\nimport { createLinuxSystemdServiceBackend } from \"./linux-systemd\";\nimport { createMacosLaunchdServiceBackend } from \"./macos-launchd\";\nimport type { ServiceBackend } from \"./types\";\n\nexport function getServiceBackend(\n currentPlatform: NodeJS.Platform = platform(),\n): ServiceBackend | null {\n switch (currentPlatform) {\n case \"linux\":\n return createLinuxSystemdServiceBackend();\n case \"darwin\":\n return createMacosLaunchdServiceBackend();\n default:\n return null;\n }\n}\n","import { execFileSync } from \"node:child_process\";\nimport { existsSync, mkdirSync, rmSync, writeFileSync } from \"node:fs\";\nimport { homedir, platform } from \"node:os\";\nimport { join } from \"node:path\";\nimport { isCommandAvailable } from \"../../utils/command\";\nimport { logger } from \"../../utils/logger\";\nimport {\n formatBullet,\n formatHeader,\n formatKeyValue,\n formatSection,\n} from \"../ui/format\";\nimport { promptConfirm } from \"../ui/prompts\";\nimport type { ServiceBackend, ServiceSupport } from \"./types\";\nimport {\n escapeDoubleQuotedValue,\n getManagedServiceEnvironment,\n resolveManagedDaemonCommand,\n} from \"./utils\";\n\nconst SYSTEMD_SERVICE_NAME = \"tokenarena\";\n\nexport interface SystemdServiceDefinitionOptions {\n environment: Record<string, string>;\n execPath: string;\n args: string[];\n}\n\nexport function getLinuxSystemdServiceDir(homePath = homedir()): string {\n return join(homePath, \".config/systemd/user\");\n}\n\nexport function getLinuxSystemdServiceFile(homePath = homedir()): string {\n return join(\n getLinuxSystemdServiceDir(homePath),\n `${SYSTEMD_SERVICE_NAME}.service`,\n );\n}\n\nexport function buildSystemdServiceContent(\n options: SystemdServiceDefinitionOptions,\n): string {\n const envLines = Object.entries(options.environment)\n .map(\n ([key, value]) =>\n `Environment=\"${escapeDoubleQuotedValue(key)}=${escapeDoubleQuotedValue(value)}\"`,\n )\n .join(\"\\n\");\n const execArgs = [options.execPath, ...options.args]\n .map((value) => `\"${escapeDoubleQuotedValue(value)}\"`)\n .join(\" \");\n\n return `[Unit]\nDescription=TokenArena Daemon - AI Usage Tracker\nAfter=network-online.target\nWants=network-online.target\n\n[Service]\nType=simple\nExecStart=${execArgs}\nRestart=on-failure\nRestartSec=10\n${envLines}\n\n[Install]\nWantedBy=default.target\n`;\n}\n\nfunction getSystemdSupport(): ServiceSupport {\n if (platform() !== \"linux\") {\n return {\n ok: false,\n reason: \"systemd 仅在 Linux 上可用。\",\n };\n }\n\n if (!isCommandAvailable(\"systemctl\")) {\n return {\n ok: false,\n reason: \"未检测到 systemctl。\",\n };\n }\n\n return { ok: true };\n}\n\nfunction execSystemctl(args: string[]): void {\n execFileSync(\"systemctl\", [\"--user\", ...args], {\n stdio: \"inherit\",\n });\n}\n\nfunction ensureSystemdAvailable(): boolean {\n const support = getSystemdSupport();\n if (support.ok) {\n return true;\n }\n\n logger.info(formatBullet(`systemd 不可用。${support.reason}`, \"warning\"));\n return false;\n}\n\nexport function createLinuxSystemdServiceBackend(): ServiceBackend {\n function isInstalled(): boolean {\n return existsSync(getLinuxSystemdServiceFile());\n }\n\n async function setup(skipPrompt = false): Promise<void> {\n if (!ensureSystemdAvailable()) {\n return;\n }\n\n const serviceDir = getLinuxSystemdServiceDir();\n const serviceFile = getLinuxSystemdServiceFile();\n\n logger.info(formatHeader(\"设置 systemd 服务\", \"TokenArena daemon\"));\n\n if (!skipPrompt) {\n const shouldSetup = await promptConfirm({\n message: \"是否创建并启用 systemd 用户服务?\",\n defaultValue: true,\n });\n\n if (!shouldSetup) {\n logger.info(formatBullet(\"已取消服务设置。\"));\n return;\n }\n }\n\n try {\n const command = resolveManagedDaemonCommand();\n const content = buildSystemdServiceContent({\n environment: getManagedServiceEnvironment(),\n execPath: command.execPath,\n args: command.args,\n });\n\n mkdirSync(serviceDir, { recursive: true });\n writeFileSync(serviceFile, content, \"utf-8\");\n\n execSystemctl([\"daemon-reload\"]);\n execSystemctl([\"enable\", SYSTEMD_SERVICE_NAME]);\n execSystemctl([\"start\", SYSTEMD_SERVICE_NAME]);\n\n logger.info(formatSection(\"服务已设置\"));\n logger.info(formatBullet(`服务文件: ${serviceFile}`, \"success\"));\n logger.info(formatBullet(\"服务已启用并启动\", \"success\"));\n logger.info(\n formatKeyValue(\"查看状态\", \"systemctl --user status tokenarena\"),\n );\n } catch (err) {\n logger.error(`设置服务失败: ${(err as Error).message}`);\n throw err;\n }\n }\n\n async function start(): Promise<void> {\n if (!ensureSystemdAvailable()) {\n return;\n }\n\n if (!isInstalled()) {\n logger.info(\n formatBullet(\n \"服务文件不存在。请先运行 'tokenarena service setup'。\",\n \"warning\",\n ),\n );\n return;\n }\n\n try {\n execSystemctl([\"start\", SYSTEMD_SERVICE_NAME]);\n logger.info(formatBullet(\"服务已启动\", \"success\"));\n } catch (err) {\n logger.error(`启动服务失败: ${(err as Error).message}`);\n throw err;\n }\n }\n\n async function stop(): Promise<void> {\n if (!ensureSystemdAvailable()) {\n return;\n }\n\n if (!isInstalled()) {\n logger.info(\n formatBullet(\n \"服务文件不存在。请先运行 'tokenarena service setup'。\",\n \"warning\",\n ),\n );\n return;\n }\n\n try {\n execSystemctl([\"stop\", SYSTEMD_SERVICE_NAME]);\n logger.info(formatBullet(\"服务已停止\", \"success\"));\n } catch (err) {\n logger.error(`停止服务失败: ${(err as Error).message}`);\n throw err;\n }\n }\n\n async function restart(): Promise<void> {\n if (!ensureSystemdAvailable()) {\n return;\n }\n\n if (!isInstalled()) {\n logger.info(\n formatBullet(\n \"服务文件不存在。请先运行 'tokenarena service setup'。\",\n \"warning\",\n ),\n );\n return;\n }\n\n try {\n execSystemctl([\"restart\", SYSTEMD_SERVICE_NAME]);\n logger.info(formatBullet(\"服务已重启\", \"success\"));\n } catch (err) {\n logger.error(`重启服务失败: ${(err as Error).message}`);\n throw err;\n }\n }\n\n async function status(): Promise<void> {\n if (!ensureSystemdAvailable()) {\n return;\n }\n\n if (!isInstalled()) {\n logger.info(\n formatBullet(\n \"服务文件不存在。请先运行 'tokenarena service setup'。\",\n \"warning\",\n ),\n );\n return;\n }\n\n try {\n execSystemctl([\"status\", SYSTEMD_SERVICE_NAME]);\n } catch {\n // systemctl status returns non-zero when the service is inactive or failed.\n }\n }\n\n async function uninstall(skipPrompt = false): Promise<void> {\n const serviceFile = getLinuxSystemdServiceFile();\n if (!existsSync(serviceFile)) {\n logger.info(formatBullet(\"服务文件不存在。\", \"warning\"));\n return;\n }\n\n if (!skipPrompt) {\n const shouldUninstall = await promptConfirm({\n message: \"是否卸载 systemd 服务?\",\n defaultValue: false,\n });\n\n if (!shouldUninstall) {\n logger.info(formatBullet(\"已取消卸载。\"));\n return;\n }\n }\n\n const support = getSystemdSupport();\n if (support.ok) {\n try {\n execSystemctl([\"stop\", SYSTEMD_SERVICE_NAME]);\n } catch {\n // Best effort: proceed with file cleanup.\n }\n\n try {\n execSystemctl([\"disable\", SYSTEMD_SERVICE_NAME]);\n } catch {\n // Best effort: proceed with file cleanup.\n }\n } else {\n logger.info(\n formatBullet(\n `当前无法访问 systemd,将只删除服务文件。${support.reason}`,\n \"warning\",\n ),\n );\n }\n\n try {\n rmSync(serviceFile);\n if (support.ok) {\n execSystemctl([\"daemon-reload\"]);\n }\n\n logger.info(formatSection(\"服务已卸载\"));\n logger.info(formatBullet(\"服务已停用并删除\", \"success\"));\n } catch (err) {\n logger.error(`卸载服务失败: ${(err as Error).message}`);\n throw err;\n }\n }\n\n return {\n displayName: \"systemd 用户服务\",\n canSetup: getSystemdSupport,\n isInstalled,\n getDefinitionPath: getLinuxSystemdServiceFile,\n getStatusHint: () => \"systemctl --user status tokenarena\",\n setup,\n start,\n stop,\n restart,\n status,\n uninstall,\n };\n}\n","import { execSync } from \"node:child_process\";\n\n/**\n * Check if a command is available in PATH.\n * Uses POSIX-standard `command -v` which is more reliable than `which`.\n *\n * @param command - The command name to check (e.g., 'systemctl', 'git')\n * @returns true if the command exists, false otherwise\n *\n * @remarks\n * Ensure you're using macOS/Linux. This uses shell built-in `command -v`\n * which may not be available on Windows.\n */\nexport function isCommandAvailable(command: string): boolean {\n try {\n execSync(`command -v ${command}`, { stdio: \"ignore\" });\n return true;\n } catch {\n return false;\n }\n}\n","const SERVICE_PATH_FALLBACKS = [\n \"/opt/homebrew/bin\",\n \"/usr/local/bin\",\n \"/usr/bin\",\n \"/bin\",\n \"/usr/sbin\",\n \"/sbin\",\n];\n\nconst SERVICE_ENV_KEYS = [\n \"TOKEN_ARENA_DEV\",\n \"XDG_CONFIG_HOME\",\n \"XDG_STATE_HOME\",\n \"XDG_RUNTIME_DIR\",\n] as const;\n\nexport interface ManagedDaemonCommand {\n execPath: string;\n args: string[];\n}\n\nfunction dedupePaths(paths: string[]): string[] {\n return [...new Set(paths.filter(Boolean))];\n}\n\nexport function getManagedServiceEnvironment(\n env: NodeJS.ProcessEnv = process.env,\n): Record<string, string> {\n const pathEntries = dedupePaths([\n ...(env.PATH?.split(\":\") ?? []),\n ...SERVICE_PATH_FALLBACKS,\n ]);\n const next: Record<string, string> = {\n PATH: pathEntries.join(\":\"),\n };\n\n for (const key of SERVICE_ENV_KEYS) {\n const value = env[key];\n if (value) {\n next[key] = value;\n }\n }\n\n return next;\n}\n\nexport function resolveManagedDaemonCommand(\n execPath = process.execPath,\n argv = process.argv,\n): ManagedDaemonCommand {\n const scriptPath = argv[1];\n if (!scriptPath) {\n throw new Error(\"无法解析 CLI 入口路径,请通过 tokenarena 命令重新执行。\");\n }\n\n return {\n execPath,\n args: [scriptPath, \"daemon\", \"--service\"],\n };\n}\n\nexport function escapeDoubleQuotedValue(value: string): string {\n return value.replaceAll(\"\\\\\", \"\\\\\\\\\").replaceAll('\"', '\\\\\"');\n}\n\nexport function escapeXml(value: string): string {\n return value\n .replaceAll(\"&\", \"&amp;\")\n .replaceAll(\"<\", \"&lt;\")\n .replaceAll(\">\", \"&gt;\")\n .replaceAll('\"', \"&quot;\")\n .replaceAll(\"'\", \"&apos;\");\n}\n","import { execFileSync } from \"node:child_process\";\nimport { existsSync, mkdirSync, rmSync, writeFileSync } from \"node:fs\";\nimport { homedir, platform } from \"node:os\";\nimport { join } from \"node:path\";\nimport { isCommandAvailable } from \"../../utils/command\";\nimport { logger } from \"../../utils/logger\";\nimport { ensureAppDirs, getStateDir } from \"../runtime/paths\";\nimport {\n formatBullet,\n formatHeader,\n formatKeyValue,\n formatSection,\n} from \"../ui/format\";\nimport { promptConfirm } from \"../ui/prompts\";\nimport type { ServiceBackend, ServiceSupport } from \"./types\";\nimport {\n escapeXml,\n getManagedServiceEnvironment,\n resolveManagedDaemonCommand,\n} from \"./utils\";\n\nexport const MACOS_LAUNCHD_LABEL = \"com.poco-ai.tokenarena\";\n\nexport interface LaunchdPlistOptions {\n label: string;\n programArguments: string[];\n environment: Record<string, string>;\n workingDirectory: string;\n standardOutPath: string;\n standardErrorPath: string;\n}\n\nfunction getCurrentUid(): number | null {\n return typeof process.getuid === \"function\" ? process.getuid() : null;\n}\n\nexport function getMacosLaunchAgentDir(homePath = homedir()): string {\n return join(homePath, \"Library/LaunchAgents\");\n}\n\nexport function getMacosLaunchAgentFile(homePath = homedir()): string {\n return join(getMacosLaunchAgentDir(homePath), `${MACOS_LAUNCHD_LABEL}.plist`);\n}\n\nexport function getMacosLaunchdDomain(uid = getCurrentUid()): string {\n if (uid == null) {\n throw new Error(\"无法获取当前用户 UID。\");\n }\n\n return `gui/${uid}`;\n}\n\nexport function getMacosLaunchdServiceTarget(uid = getCurrentUid()): string {\n return `${getMacosLaunchdDomain(uid)}/${MACOS_LAUNCHD_LABEL}`;\n}\n\nexport function getMacosLaunchdLogPaths(stateDir = getStateDir()): {\n stdoutPath: string;\n stderrPath: string;\n} {\n return {\n stdoutPath: join(stateDir, \"launchd.stdout.log\"),\n stderrPath: join(stateDir, \"launchd.stderr.log\"),\n };\n}\n\nfunction renderPlistArray(values: string[]): string {\n return values\n .map((value) => ` <string>${escapeXml(value)}</string>`)\n .join(\"\\n\");\n}\n\nfunction renderPlistDict(entries: Record<string, string>): string {\n return Object.entries(entries)\n .map(\n ([key, value]) =>\n ` <key>${escapeXml(key)}</key>\\n <string>${escapeXml(value)}</string>`,\n )\n .join(\"\\n\");\n}\n\nexport function buildLaunchdPlist(options: LaunchdPlistOptions): string {\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n <dict>\n <key>Label</key>\n <string>${escapeXml(options.label)}</string>\n <key>ProgramArguments</key>\n <array>\n${renderPlistArray(options.programArguments)}\n </array>\n <key>WorkingDirectory</key>\n <string>${escapeXml(options.workingDirectory)}</string>\n <key>EnvironmentVariables</key>\n <dict>\n${renderPlistDict(options.environment)}\n </dict>\n <key>KeepAlive</key>\n <dict>\n <key>SuccessfulExit</key>\n <false/>\n </dict>\n <key>ProcessType</key>\n <string>Background</string>\n <key>ThrottleInterval</key>\n <integer>30</integer>\n <key>ExitTimeOut</key>\n <integer>15</integer>\n <key>StandardOutPath</key>\n <string>${escapeXml(options.standardOutPath)}</string>\n <key>StandardErrorPath</key>\n <string>${escapeXml(options.standardErrorPath)}</string>\n </dict>\n</plist>\n`;\n}\n\nfunction getLaunchctlSupport(): ServiceSupport {\n if (platform() !== \"darwin\") {\n return {\n ok: false,\n reason: \"launchd 仅在 macOS 上可用。\",\n };\n }\n\n if (!isCommandAvailable(\"launchctl\")) {\n return {\n ok: false,\n reason: \"未检测到 launchctl。\",\n };\n }\n\n const uid = getCurrentUid();\n if (uid == null) {\n return {\n ok: false,\n reason: \"无法获取当前用户 UID。\",\n };\n }\n\n try {\n execFileSync(\"launchctl\", [\"print\", getMacosLaunchdDomain(uid)], {\n stdio: \"ignore\",\n });\n return { ok: true };\n } catch {\n return {\n ok: false,\n reason: \"当前未检测到图形化登录会话,请在桌面终端中执行。\",\n };\n }\n}\n\nfunction execLaunchctl(args: string[], inherit = true): void {\n execFileSync(\"launchctl\", args, {\n stdio: inherit ? \"inherit\" : \"ignore\",\n });\n}\n\nfunction isLoaded(): boolean {\n try {\n execLaunchctl([\"print\", getMacosLaunchdServiceTarget()], false);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction ensureLaunchctlAvailable(): boolean {\n const support = getLaunchctlSupport();\n if (support.ok) {\n return true;\n }\n\n logger.info(formatBullet(`launchd 不可用。${support.reason}`, \"warning\"));\n return false;\n}\n\nfunction writeLaunchAgentPlist(): string {\n const plistFile = getMacosLaunchAgentFile();\n const { stdoutPath, stderrPath } = getMacosLaunchdLogPaths();\n const command = resolveManagedDaemonCommand();\n const plist = buildLaunchdPlist({\n label: MACOS_LAUNCHD_LABEL,\n programArguments: [command.execPath, ...command.args],\n environment: getManagedServiceEnvironment(),\n workingDirectory: homedir(),\n standardOutPath: stdoutPath,\n standardErrorPath: stderrPath,\n });\n\n ensureAppDirs();\n mkdirSync(getMacosLaunchAgentDir(), { recursive: true });\n writeFileSync(plistFile, plist, \"utf-8\");\n\n return plistFile;\n}\n\nfunction bootstrapLaunchAgent(): void {\n const domain = getMacosLaunchdDomain();\n const serviceTarget = getMacosLaunchdServiceTarget();\n const plistFile = getMacosLaunchAgentFile();\n\n if (isLoaded()) {\n try {\n execLaunchctl([\"bootout\", serviceTarget]);\n } catch {\n // Best effort: try a fresh bootstrap anyway.\n }\n }\n\n execLaunchctl([\"bootstrap\", domain, plistFile]);\n execLaunchctl([\"enable\", serviceTarget]);\n execLaunchctl([\"kickstart\", \"-k\", serviceTarget]);\n}\n\nexport function createMacosLaunchdServiceBackend(): ServiceBackend {\n function isInstalled(): boolean {\n return existsSync(getMacosLaunchAgentFile());\n }\n\n async function setup(skipPrompt = false): Promise<void> {\n if (!ensureLaunchctlAvailable()) {\n return;\n }\n\n logger.info(formatHeader(\"设置 launchd 服务\", \"TokenArena daemon\"));\n\n if (!skipPrompt) {\n const shouldSetup = await promptConfirm({\n message: \"是否创建并启用 launchd 用户服务?\",\n defaultValue: true,\n });\n\n if (!shouldSetup) {\n logger.info(formatBullet(\"已取消服务设置。\"));\n return;\n }\n }\n\n try {\n const plistFile = writeLaunchAgentPlist();\n bootstrapLaunchAgent();\n\n logger.info(formatSection(\"服务已设置\"));\n logger.info(formatBullet(`服务文件: ${plistFile}`, \"success\"));\n logger.info(formatBullet(\"服务已启用并启动\", \"success\"));\n logger.info(\n formatKeyValue(\n \"查看状态\",\n `launchctl print ${getMacosLaunchdServiceTarget()}`,\n ),\n );\n } catch (err) {\n logger.error(`设置服务失败: ${(err as Error).message}`);\n throw err;\n }\n }\n\n async function start(): Promise<void> {\n if (!ensureLaunchctlAvailable()) {\n return;\n }\n\n if (!isInstalled()) {\n logger.info(\n formatBullet(\n \"服务文件不存在。请先运行 'tokenarena service setup'。\",\n \"warning\",\n ),\n );\n return;\n }\n\n try {\n if (!isLoaded()) {\n execLaunchctl([\n \"bootstrap\",\n getMacosLaunchdDomain(),\n getMacosLaunchAgentFile(),\n ]);\n }\n execLaunchctl([\"enable\", getMacosLaunchdServiceTarget()]);\n execLaunchctl([\"kickstart\", \"-k\", getMacosLaunchdServiceTarget()]);\n logger.info(formatBullet(\"服务已启动\", \"success\"));\n } catch (err) {\n logger.error(`启动服务失败: ${(err as Error).message}`);\n throw err;\n }\n }\n\n async function stop(): Promise<void> {\n if (!isInstalled()) {\n logger.info(\n formatBullet(\n \"服务文件不存在。请先运行 'tokenarena service setup'。\",\n \"warning\",\n ),\n );\n return;\n }\n\n if (!ensureLaunchctlAvailable()) {\n return;\n }\n\n if (!isLoaded()) {\n logger.info(formatBullet(\"服务当前未运行。\", \"warning\"));\n return;\n }\n\n try {\n execLaunchctl([\"bootout\", getMacosLaunchdServiceTarget()]);\n logger.info(formatBullet(\"服务已停止\", \"success\"));\n } catch (err) {\n logger.error(`停止服务失败: ${(err as Error).message}`);\n throw err;\n }\n }\n\n async function restart(): Promise<void> {\n if (!ensureLaunchctlAvailable()) {\n return;\n }\n\n if (!isInstalled()) {\n logger.info(\n formatBullet(\n \"服务文件不存在。请先运行 'tokenarena service setup'。\",\n \"warning\",\n ),\n );\n return;\n }\n\n try {\n if (isLoaded()) {\n execLaunchctl([\"kickstart\", \"-k\", getMacosLaunchdServiceTarget()]);\n } else {\n execLaunchctl([\n \"bootstrap\",\n getMacosLaunchdDomain(),\n getMacosLaunchAgentFile(),\n ]);\n execLaunchctl([\"enable\", getMacosLaunchdServiceTarget()]);\n execLaunchctl([\"kickstart\", \"-k\", getMacosLaunchdServiceTarget()]);\n }\n logger.info(formatBullet(\"服务已重启\", \"success\"));\n } catch (err) {\n logger.error(`重启服务失败: ${(err as Error).message}`);\n throw err;\n }\n }\n\n async function status(): Promise<void> {\n if (!isInstalled()) {\n logger.info(\n formatBullet(\n \"服务文件不存在。请先运行 'tokenarena service setup'。\",\n \"warning\",\n ),\n );\n return;\n }\n\n if (!ensureLaunchctlAvailable()) {\n return;\n }\n\n try {\n execLaunchctl([\"print\", getMacosLaunchdServiceTarget()]);\n } catch {\n logger.info(formatBullet(\"服务当前未加载。\", \"warning\"));\n logger.info(formatKeyValue(\"服务文件\", getMacosLaunchAgentFile()));\n }\n }\n\n async function uninstall(skipPrompt = false): Promise<void> {\n const plistFile = getMacosLaunchAgentFile();\n if (!existsSync(plistFile)) {\n logger.info(formatBullet(\"服务文件不存在。\", \"warning\"));\n return;\n }\n\n if (!skipPrompt) {\n const shouldUninstall = await promptConfirm({\n message: \"是否卸载 launchd 服务?\",\n defaultValue: false,\n });\n\n if (!shouldUninstall) {\n logger.info(formatBullet(\"已取消卸载。\"));\n return;\n }\n }\n\n const support = getLaunchctlSupport();\n if (support.ok && isLoaded()) {\n try {\n execLaunchctl([\"bootout\", getMacosLaunchdServiceTarget()]);\n } catch {\n // Best effort: continue with file cleanup.\n }\n } else if (!support.ok) {\n logger.info(\n formatBullet(\n `当前无法访问 launchd,会直接删除本地 plist 文件。${support.reason}`,\n \"warning\",\n ),\n );\n }\n\n try {\n const { stdoutPath, stderrPath } = getMacosLaunchdLogPaths();\n rmSync(plistFile);\n rmSync(stdoutPath, { force: true });\n rmSync(stderrPath, { force: true });\n\n logger.info(formatSection(\"服务已卸载\"));\n logger.info(formatBullet(\"服务已停用并删除\", \"success\"));\n } catch (err) {\n logger.error(`卸载服务失败: ${(err as Error).message}`);\n throw err;\n }\n }\n\n return {\n displayName: \"launchd 用户服务\",\n canSetup: getLaunchctlSupport,\n isInstalled,\n getDefinitionPath: getMacosLaunchAgentFile,\n getStatusHint: () => `launchctl print ${getMacosLaunchdServiceTarget()}`,\n setup,\n start,\n stop,\n restart,\n status,\n uninstall,\n };\n}\n","import { loadConfig } from \"../infrastructure/config/manager\";\nimport { formatBullet, formatHeader } from \"../infrastructure/ui/format\";\nimport {\n isInteractiveTerminal,\n promptConfirm,\n} from \"../infrastructure/ui/prompts\";\nimport { runSync } from \"../services/sync-service\";\nimport { logger } from \"../utils/logger\";\nimport { runInit } from \"./init\";\n\nconst DEFAULT_INTERVAL = 5 * 60_000; // 5 minutes\n\nfunction log(msg: string): void {\n const ts = new Date().toLocaleTimeString(\"en-US\", { hour12: false });\n process.stdout.write(`[${ts}] ${msg}\\n`);\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport interface DaemonOptions {\n interval?: number;\n service?: boolean;\n}\n\nexport function getDaemonExitCode(opts: DaemonOptions = {}): number {\n return opts.service ? 0 : 1;\n}\n\nexport async function runDaemon(opts: DaemonOptions = {}): Promise<void> {\n const config = loadConfig();\n if (!config?.apiKey) {\n if (isInteractiveTerminal()) {\n logger.info(\n formatHeader(\n \"尚未完成初始化\",\n \"启动 daemon 前需要先配置有效的 API Key。\",\n ),\n );\n const shouldInit = await promptConfirm({\n message: \"是否先进入初始化流程?\",\n defaultValue: true,\n });\n if (shouldInit) {\n await runInit();\n return;\n }\n logger.info(formatBullet(\"已取消启动 daemon。\", \"warning\"));\n return;\n }\n\n const message = opts.service\n ? \"Not configured. Exiting service mode.\"\n : \"Not configured. Run `tokenarena init` first.\";\n logger.error(message);\n process.exit(getDaemonExitCode(opts));\n }\n\n const interval = opts.interval || config.syncInterval || DEFAULT_INTERVAL;\n const intervalMin = Math.round(interval / 60000);\n const stopHint = opts.service ? \"service mode\" : \"Ctrl+C to stop\";\n\n log(`Daemon started (sync every ${intervalMin}m, ${stopHint})`);\n\n // eslint-disable-next-line no-constant-condition\n while (true) {\n try {\n await runSync(config, {\n quiet: true,\n source: \"daemon\",\n throws: true,\n });\n } catch (err) {\n if ((err as Error).message === \"UNAUTHORIZED\") {\n const message = opts.service\n ? \"API key invalid. Exiting service mode.\"\n : \"API key invalid. Exiting.\";\n log(message);\n process.exit(getDaemonExitCode(opts));\n }\n log(`Sync error: ${(err as Error).message}`);\n }\n await sleep(interval);\n }\n}\n","import { getConfigPath, loadConfig } from \"../infrastructure/config/manager\";\nimport { loadSyncState } from \"../infrastructure/runtime/state\";\nimport {\n formatBullet,\n formatHeader,\n formatKeyValue,\n formatSection,\n formatStatusBadge,\n maskSecret,\n} from \"../infrastructure/ui/format\";\nimport {\n detectInstalledTools,\n getAllTools,\n isToolInstalled,\n} from \"../parsers/registry\";\nimport { logger } from \"../utils/logger\";\n\nfunction formatMaybe(value?: string): string {\n return value || \"(never)\";\n}\n\nexport async function runStatus(): Promise<void> {\n const config = loadConfig();\n logger.info(\n formatHeader(\n \"TokenArena 状态\",\n \"查看当前配置、已检测工具以及最近一次同步情况。\",\n ),\n );\n\n logger.info(formatSection(\"配置\"));\n if (!config?.apiKey) {\n logger.info(formatKeyValue(\"状态\", formatStatusBadge(\"未配置\", \"warning\")));\n logger.info(formatBullet(\"运行 tokenarena init 完成首次设置。\", \"warning\"));\n } else {\n logger.info(formatKeyValue(\"状态\", formatStatusBadge(\"已配置\", \"success\")));\n logger.info(formatKeyValue(\"配置文件\", getConfigPath()));\n logger.info(formatKeyValue(\"API Key\", maskSecret(config.apiKey)));\n logger.info(\n formatKeyValue(\"API URL\", config.apiUrl || \"https://token.poco-ai.com\"),\n );\n if (config.syncInterval) {\n logger.info(\n formatKeyValue(\n \"同步间隔\",\n `${Math.round(config.syncInterval / 60000)} 分钟`,\n ),\n );\n }\n }\n\n logger.info(formatSection(\"已检测工具\"));\n const detected = detectInstalledTools();\n if (detected.length === 0) {\n logger.info(formatBullet(\"未检测到已安装的 AI CLI。\", \"warning\"));\n } else {\n for (const tool of detected) {\n logger.info(formatBullet(tool.name, \"success\"));\n }\n }\n\n logger.info(formatSection(\"支持的工具\"));\n for (const tool of getAllTools()) {\n const installed = isToolInstalled(tool.id);\n logger.info(\n formatBullet(\n `${tool.name} · ${installed ? \"已安装\" : \"未发现\"}`,\n installed ? \"success\" : \"neutral\",\n ),\n );\n }\n\n const syncState = loadSyncState();\n logger.info(formatSection(\"同步状态\"));\n const statusTone =\n syncState.status === \"idle\"\n ? \"success\"\n : syncState.status === \"syncing\"\n ? \"warning\"\n : \"danger\";\n logger.info(\n formatKeyValue(\"状态\", formatStatusBadge(syncState.status, statusTone)),\n );\n logger.info(formatKeyValue(\"上次尝试\", formatMaybe(syncState.lastAttemptAt)));\n logger.info(formatKeyValue(\"上次成功\", formatMaybe(syncState.lastSuccessAt)));\n if (syncState.lastSource) {\n logger.info(formatKeyValue(\"触发来源\", syncState.lastSource));\n }\n if (syncState.lastError) {\n logger.info(formatKeyValue(\"错误信息\", syncState.lastError));\n }\n if (syncState.lastResult) {\n logger.info(\n formatKeyValue(\n \"最近结果\",\n `${syncState.lastResult.buckets} buckets, ${syncState.lastResult.sessions} sessions`,\n ),\n );\n }\n}\n","import { loadConfig } from \"../infrastructure/config/manager\";\nimport { formatBullet, formatHeader } from \"../infrastructure/ui/format\";\nimport {\n isInteractiveTerminal,\n promptConfirm,\n} from \"../infrastructure/ui/prompts\";\nimport { runSync } from \"../services/sync-service\";\nimport { logger } from \"../utils/logger\";\nimport { runInit } from \"./init\";\n\nexport interface SyncCommandOptions {\n quiet?: boolean;\n}\n\nexport async function runSyncCommand(\n opts: SyncCommandOptions = {},\n): Promise<void> {\n const config = loadConfig();\n if (!config?.apiKey) {\n if (isInteractiveTerminal()) {\n logger.info(\n formatHeader(\"尚未完成初始化\", \"同步前需要先配置有效的 API Key。\"),\n );\n const shouldInit = await promptConfirm({\n message: \"是否现在进入初始化流程?\",\n defaultValue: true,\n });\n if (shouldInit) {\n await runInit();\n return;\n }\n logger.info(formatBullet(\"已取消同步。\", \"warning\"));\n return;\n }\n\n logger.error(\"Not configured. Run `tokenarena init` first.\");\n process.exit(1);\n }\n\n await runSync(config, {\n quiet: opts.quiet,\n source: \"manual\",\n });\n}\n","import { existsSync, readFileSync, rmSync, writeFileSync } from \"node:fs\";\nimport { homedir, platform } from \"node:os\";\nimport {\n deleteConfig,\n getConfigDir,\n getConfigPath,\n loadConfig,\n} from \"../infrastructure/config/manager\";\nimport {\n getRuntimeDirPath,\n getStateDir,\n} from \"../infrastructure/runtime/paths\";\nimport { getServiceBackend } from \"../infrastructure/service\";\nimport {\n formatBullet,\n formatHeader,\n formatKeyValue,\n formatSection,\n maskSecret,\n} from \"../infrastructure/ui/format\";\nimport { promptConfirm } from \"../infrastructure/ui/prompts\";\nimport { logger } from \"../utils/logger\";\n\nfunction removeShellAlias(): void {\n const shell = process.env.SHELL;\n if (!shell) return;\n\n const shellName = shell.split(\"/\").pop() ?? \"\";\n const aliasName = \"ta\";\n\n let configFile: string;\n\n switch (shellName) {\n case \"zsh\":\n configFile = `${homedir()}/.zshrc`;\n break;\n case \"bash\":\n if (platform() === \"darwin\" && existsSync(`${homedir()}/.bash_profile`)) {\n configFile = `${homedir()}/.bash_profile`;\n } else {\n configFile = `${homedir()}/.bashrc`;\n }\n break;\n case \"fish\":\n configFile = `${homedir()}/.config/fish/config.fish`;\n break;\n default:\n return;\n }\n\n if (!existsSync(configFile)) return;\n\n try {\n let content = readFileSync(configFile, \"utf-8\");\n\n // Match the alias block: \"# TokenArena alias\" comment line + alias line\n const aliasPatterns = [\n // zsh / bash format: alias ta=\"tokenarena\"\n new RegExp(\n `\\\\n?#\\\\s*TokenArena alias\\\\s*\\\\n\\\\s*alias\\\\s+${aliasName}\\\\s*=\\\\s*\"tokenarena\"\\\\s*\\\\n?`,\n \"g\",\n ),\n // fish format: alias ta \"tokenarena\"\n new RegExp(\n `\\\\n?#\\\\s*TokenArena alias\\\\s*\\\\n\\\\s*alias\\\\s+${aliasName}\\\\s+\"tokenarena\"\\\\s*\\\\n?`,\n \"g\",\n ),\n // Loose match for any ta alias line\n new RegExp(`\\\\n?alias\\\\s+${aliasName}\\\\s*=\\\\s*\"tokenarena\"\\\\s*\\\\n?`, \"g\"),\n new RegExp(`\\\\n?alias\\\\s+${aliasName}\\\\s+\"tokenarena\"\\\\s*\\\\n?`, \"g\"),\n ];\n\n for (const pattern of aliasPatterns) {\n const next = content.replace(pattern, \"\\n\");\n if (next !== content) {\n content = next;\n }\n }\n\n writeFileSync(configFile, content, \"utf-8\");\n logger.info(`Removed shell alias from ${configFile}`);\n } catch (err) {\n logger.warn(\n `Could not update ${configFile}: ${(err as Error).message}. Please remove the alias manually.`,\n );\n }\n}\n\nexport async function runUninstall(): Promise<void> {\n const configPath = getConfigPath();\n const configDir = getConfigDir();\n const stateDir = getStateDir();\n const runtimeDir = getRuntimeDirPath();\n const serviceBackend = getServiceBackend();\n const hasInstalledService = serviceBackend?.isInstalled() ?? false;\n const hasLocalArtifacts =\n existsSync(configPath) ||\n existsSync(configDir) ||\n existsSync(stateDir) ||\n existsSync(runtimeDir) ||\n hasInstalledService;\n\n if (!hasLocalArtifacts) {\n logger.info(formatHeader(\"卸载 TokenArena\"));\n logger.info(formatBullet(\"未发现本地配置,无需卸载。\"));\n return;\n }\n\n const config = loadConfig();\n logger.info(\n formatHeader(\n \"卸载 TokenArena\",\n \"该操作会删除本地配置、同步状态与运行时文件。\",\n ),\n );\n if (config?.apiKey) {\n logger.info(formatKeyValue(\"API Key\", maskSecret(config.apiKey)));\n }\n logger.info(formatKeyValue(\"配置目录\", configDir));\n logger.info(formatKeyValue(\"状态目录\", stateDir));\n logger.info(formatKeyValue(\"运行目录\", runtimeDir));\n if (hasInstalledService && serviceBackend) {\n logger.info(formatKeyValue(\"后台服务\", serviceBackend.getDefinitionPath()));\n }\n\n const shouldUninstall = await promptConfirm({\n message: \"确认继续卸载本地 TokenArena 数据?\",\n defaultValue: false,\n });\n if (!shouldUninstall) {\n logger.info(formatBullet(\"已取消卸载。\", \"warning\"));\n return;\n }\n\n if (hasInstalledService && serviceBackend) {\n const shouldRemoveService = await promptConfirm({\n message: `检测到已安装 ${serviceBackend.displayName},是否一并卸载?`,\n defaultValue: true,\n });\n\n if (shouldRemoveService) {\n try {\n await serviceBackend.uninstall(true);\n } catch (err) {\n logger.warn(`后台服务卸载失败: ${(err as Error).message}`);\n }\n }\n }\n\n // 1. Delete config file\n logger.info(formatSection(\"执行结果\"));\n if (existsSync(configPath)) {\n deleteConfig();\n logger.info(formatBullet(\"已删除配置文件。\", \"success\"));\n }\n\n // 2. Remove config directory if empty\n if (existsSync(configDir)) {\n try {\n rmSync(configDir, { recursive: false, force: true });\n logger.info(formatBullet(\"已删除配置目录。\", \"success\"));\n } catch {\n // Directory not empty (other files), skip silently\n }\n }\n\n // 3. Delete state directory (status.json, etc.)\n if (existsSync(stateDir)) {\n rmSync(stateDir, { recursive: true, force: true });\n logger.info(formatBullet(\"已删除状态数据。\", \"success\"));\n }\n\n // 4. Delete runtime directory (sync.lock, etc.)\n if (existsSync(runtimeDir)) {\n rmSync(runtimeDir, { recursive: true, force: true });\n logger.info(formatBullet(\"已删除运行时数据。\", \"success\"));\n }\n\n // 5. Clean up shell alias\n removeShellAlias();\n\n logger.info(formatSection(\"完成\"));\n logger.info(formatBullet(\"TokenArena 已从本地卸载完成。\", \"success\"));\n}\n","import type { Command } from \"commander\";\nimport { loadConfig } from \"../infrastructure/config/manager\";\nimport {\n formatBullet,\n formatHeader,\n formatKeyValue,\n formatStatusBadge,\n maskSecret,\n} from \"../infrastructure/ui/format\";\nimport { promptConfirm, promptSelect } from \"../infrastructure/ui/prompts\";\nimport { logger } from \"../utils/logger\";\nimport { handleConfig } from \"./config\";\nimport { runDaemon } from \"./daemon\";\nimport { runInit } from \"./init\";\nimport { runStatus } from \"./status\";\nimport { runSyncCommand } from \"./sync\";\nimport { runUninstall } from \"./uninstall\";\n\ntype HomeAction =\n | \"init\"\n | \"status\"\n | \"sync\"\n | \"config\"\n | \"daemon\"\n | \"uninstall\"\n | \"help\"\n | \"exit\";\n\nfunction logHomeSummary(): void {\n const config = loadConfig();\n const configured = Boolean(config?.apiKey);\n\n logger.info(\n formatHeader(\n \"TokenArena CLI\",\n \"通过更友好的交互完成初始化、同步、配置与清理。\",\n ),\n );\n logger.info(\n formatKeyValue(\n \"配置状态\",\n configured\n ? formatStatusBadge(\"已配置\", \"success\")\n : formatStatusBadge(\"未配置\", \"warning\"),\n ),\n );\n\n if (configured && config) {\n logger.info(formatKeyValue(\"API Key\", maskSecret(config.apiKey)));\n logger.info(\n formatKeyValue(\"API 地址\", config.apiUrl || \"https://token.poco-ai.com\"),\n );\n } else {\n logger.info(formatBullet(\"建议先运行初始化流程绑定 API Key。\", \"warning\"));\n }\n}\n\nasync function pickHomeAction(): Promise<HomeAction> {\n return promptSelect<HomeAction>({\n message: \"请选择要执行的操作\",\n choices: [\n {\n name: \"初始化 TokenArena\",\n value: \"init\",\n description: \"配置 API Key、检测工具并执行首次同步\",\n },\n {\n name: \"查看当前状态\",\n value: \"status\",\n description: \"查看配置、工具检测结果与最近同步状态\",\n },\n {\n name: \"立即同步\",\n value: \"sync\",\n description: \"手动上传本地最新 token 使用数据\",\n },\n {\n name: \"管理配置\",\n value: \"config\",\n description: \"查看或修改 API Key、API 地址、同步间隔等配置\",\n },\n {\n name: \"启动守护同步\",\n value: \"daemon\",\n description: \"持续后台同步,适合长期运行\",\n },\n {\n name: \"卸载本地配置\",\n value: \"uninstall\",\n description: \"删除本地配置、状态与运行时文件\",\n },\n {\n name: \"查看帮助\",\n value: \"help\",\n description: \"展示完整命令帮助\",\n },\n {\n name: \"退出\",\n value: \"exit\",\n description: \"结束当前交互\",\n },\n ],\n });\n}\n\nexport async function runHome(program: Command): Promise<void> {\n while (true) {\n logHomeSummary();\n\n const action = await pickHomeAction();\n logger.info(\"\");\n\n switch (action) {\n case \"init\":\n await runInit();\n break;\n case \"status\":\n await runStatus();\n break;\n case \"sync\":\n await runSyncCommand();\n break;\n case \"config\":\n await handleConfig([]);\n break;\n case \"daemon\":\n await runDaemon();\n return;\n case \"uninstall\":\n await runUninstall();\n break;\n case \"help\":\n program.outputHelp();\n break;\n case \"exit\":\n logger.info(formatBullet(\"已退出交互式主页。\", \"neutral\"));\n return;\n }\n\n const continueAnswer = await promptConfirm({\n message: \"是否继续执行其他操作?\",\n defaultValue: true,\n });\n\n if (!continueAnswer) {\n logger.info(formatBullet(\"下次可直接运行 tokenarena 继续。\", \"neutral\"));\n return;\n }\n }\n}\n","import { getServiceBackend } from \"../infrastructure/service\";\nimport {\n formatBullet,\n formatHeader,\n formatKeyValue,\n formatSection,\n} from \"../infrastructure/ui/format\";\nimport { logger } from \"../utils/logger\";\n\nexport interface ServiceCommandOptions {\n action?: string;\n skipPrompt?: boolean;\n}\n\nfunction printUsage(backendName?: string): void {\n logger.info(formatHeader(\"TokenArena 后台服务管理\"));\n if (backendName) {\n logger.info(formatKeyValue(\"当前实现\", backendName));\n }\n logger.info(formatSection(\"可用操作\"));\n logger.info(formatBullet(\"setup - 创建并启用服务\"));\n logger.info(formatBullet(\"start - 启动服务\"));\n logger.info(formatBullet(\"stop - 停止服务\"));\n logger.info(formatBullet(\"restart - 重启服务\"));\n logger.info(formatBullet(\"status - 查看服务状态\"));\n logger.info(formatBullet(\"uninstall - 卸载服务\"));\n}\n\nexport async function runServiceCommand(\n opts: ServiceCommandOptions,\n): Promise<void> {\n const backend = getServiceBackend();\n if (!backend) {\n logger.info(\n formatBullet(\n \"后台服务仅在 Linux(systemd) 和 macOS(launchd) 上支持。\",\n \"warning\",\n ),\n );\n return;\n }\n\n const action = opts.action?.toLowerCase();\n if (!action) {\n printUsage(backend.displayName);\n const support = backend.canSetup();\n if (!support.ok && support.reason) {\n logger.info(\n formatBullet(`当前环境暂不可管理服务。${support.reason}`, \"warning\"),\n );\n }\n return;\n }\n\n switch (action) {\n case \"setup\":\n await backend.setup(opts.skipPrompt);\n break;\n case \"start\":\n await backend.start();\n break;\n case \"stop\":\n await backend.stop();\n break;\n case \"restart\":\n await backend.restart();\n break;\n case \"status\":\n await backend.status();\n break;\n case \"uninstall\":\n await backend.uninstall(opts.skipPrompt);\n break;\n default:\n logger.error(`未知操作: ${action}`);\n process.exit(1);\n }\n}\n","import { readFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst FALLBACK_VERSION = \"0.0.0\";\n\nlet cachedVersion: string | undefined;\n\nexport function getCliVersion(metaUrl = import.meta.url): string {\n if (cachedVersion) {\n return cachedVersion;\n }\n\n const packageJsonPath = join(\n dirname(fileURLToPath(metaUrl)),\n \"..\",\n \"package.json\",\n );\n\n try {\n const packageJson = JSON.parse(readFileSync(packageJsonPath, \"utf-8\")) as {\n version?: string;\n };\n\n cachedVersion =\n typeof packageJson.version === \"string\"\n ? packageJson.version\n : FALLBACK_VERSION;\n } catch {\n cachedVersion = FALLBACK_VERSION;\n }\n\n return cachedVersion;\n}\n","import { existsSync, realpathSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nexport function isMainModule(\n argvEntry = process.argv[1],\n metaUrl = import.meta.url,\n): boolean {\n if (!argvEntry) {\n return false;\n }\n\n const currentModulePath = fileURLToPath(metaUrl);\n\n try {\n return realpathSync(argvEntry) === realpathSync(currentModulePath);\n } catch {\n if (!existsSync(argvEntry)) {\n return false;\n }\n\n return resolve(argvEntry) === resolve(currentModulePath);\n }\n}\n","// Import parsers to register them before CLI setup\nimport \"./parsers/claude-code.js\";\nimport \"./parsers/codex.js\";\nimport \"./parsers/gemini-cli.js\";\nimport \"./parsers/copilot-cli.js\";\nimport \"./parsers/opencode.js\";\nimport \"./parsers/openclaw.js\";\nimport \"./parsers/qwen-code.js\";\nimport \"./parsers/kimi-code.js\";\nimport \"./parsers/droid.js\";\nimport \"./parsers/pi-coding-agent.js\";\n\nimport { createCli } from \"./cli.js\";\nimport { isMainModule } from \"./infrastructure/runtime/main-module.js\";\n\nexport function normalizeArgv(argv: string[]) {\n return argv.filter((arg, index) => index < 2 || arg !== \"--\");\n}\n\nexport async function run(argv = process.argv) {\n const program = createCli();\n await program.parseAsync(normalizeArgv(argv));\n}\n\nif (isMainModule()) {\n void run();\n}\n"],"mappings":";;;AAAA,SAAS,cAAAA,mBAAkB;AAC3B,SAAS,eAAe;AACxB,SAAS,QAAAC,OAAM,OAAAC,YAAW;;;ACF1B,SAAS,gBAAgB;AAMlB,SAAS,gBAAgB,MAAkB;AAChD,QAAM,IAAI,IAAI,KAAK,IAAI;AACvB,IAAE,WAAW,EAAE,WAAW,IAAI,KAAK,IAAI,IAAI,GAAG,CAAC;AAC/C,SAAO;AACT;AAKO,SAAS,mBAAmB,SAA2C;AAC5E,QAAM,MAAM,oBAAI,IAAyB;AACzC,QAAM,OAAO,SAAS,EAAE,QAAQ,YAAY,EAAE;AAE9C,aAAW,KAAK,SAAS;AACvB,UAAM,cAAc,gBAAgB,EAAE,SAAS,EAAE,YAAY;AAC7D,UAAM,MAAM,GAAG,EAAE,MAAM,IAAI,EAAE,KAAK,IAAI,EAAE,OAAO,IAAI,WAAW;AAE9D,QAAI,CAAC,IAAI,IAAI,GAAG,GAAG;AACjB,UAAI,IAAI,KAAK;AAAA,QACX,QAAQ,EAAE;AAAA,QACV,OAAO,EAAE;AAAA,QACT,SAAS,EAAE;AAAA,QACX;AAAA,QACA,UAAU;AAAA,QACV,aAAa;AAAA,QACb,cAAc;AAAA,QACd,iBAAiB;AAAA,QACjB,cAAc;AAAA,QACd,aAAa;AAAA,MACf,CAAC;AAAA,IACH;AAEA,UAAM,IAAI,IAAI,IAAI,GAAG;AACrB,QAAI,CAAC,EAAG;AACR,MAAE,eAAe,EAAE,eAAe;AAClC,MAAE,gBAAgB,EAAE,gBAAgB;AACpC,MAAE,mBAAmB,EAAE,mBAAmB;AAC1C,MAAE,gBAAgB,EAAE,gBAAgB;AACpC,MAAE,gBACC,EAAE,eAAe,MACjB,EAAE,gBAAgB,MAClB,EAAE,mBAAmB,MACrB,EAAE,gBAAgB;AAAA,EACvB;AAEA,SAAO,MAAM,KAAK,IAAI,OAAO,CAAC;AAChC;;;ACpDA,SAAS,kBAAkB;AAC3B,SAAS,YAAAC,iBAAgB;AAQzB,SAAS,mBAAmB,OAAwB;AAClD,SACE,MAAM,cACN,MAAM,eACN,MAAM,kBACN,MAAM;AAEV;AAEA,SAAS,kBAAkB,SAA4B;AACrD,QAAM,iBAAiB,oBAAI,IAA4C;AAEvE,aAAW,SAAS,SAAS;AAC3B,QAAI,CAAC,MAAM,WAAW;AACpB;AAAA,IACF;AAEA,QAAI,UAAU,eAAe,IAAI,MAAM,SAAS;AAChD,QAAI,CAAC,SAAS;AACZ,gBAAU,oBAAI,IAA+B;AAC7C,qBAAe,IAAI,MAAM,WAAW,OAAO;AAAA,IAC7C;AAEA,UAAM,WAAW,QAAQ,IAAI,MAAM,KAAK;AACxC,QAAI,UAAU;AACZ,eAAS,eAAe,MAAM;AAC9B,eAAS,gBAAgB,MAAM;AAC/B,eAAS,mBAAmB,MAAM;AAClC,eAAS,gBAAgB,MAAM;AAC/B,eAAS,eAAe,mBAAmB,KAAK;AAChD;AAAA,IACF;AAEA,YAAQ,IAAI,MAAM,OAAO;AAAA,MACvB,OAAO,MAAM;AAAA,MACb,aAAa,MAAM;AAAA,MACnB,cAAc,MAAM;AAAA,MACpB,iBAAiB,MAAM;AAAA,MACvB,cAAc,MAAM;AAAA,MACpB,aAAa,mBAAmB,KAAK;AAAA,IACvC,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AASO,SAAS,gBACd,QACA,UAA6B,CAAC,GACX;AACnB,QAAM,SAAS,oBAAI,IAA4B;AAC/C,aAAW,KAAK,QAAQ;AACtB,QAAI,CAAC,OAAO,IAAI,EAAE,SAAS,EAAG,QAAO,IAAI,EAAE,WAAW,CAAC,CAAC;AACxD,WAAO,IAAI,EAAE,SAAS,GAAG,KAAK,CAAC;AAAA,EACjC;AAEA,QAAM,WAA8B,CAAC;AACrC,QAAM,OAAOA,UAAS,EAAE,QAAQ,YAAY,EAAE;AAC9C,QAAM,iBAAiB,kBAAkB,OAAO;AAEhD,aAAW,CAAC,WAAW,aAAa,KAAK,QAAQ;AAC/C,kBAAc,KAAK,CAAC,GAAG,MAAM,EAAE,UAAU,QAAQ,IAAI,EAAE,UAAU,QAAQ,CAAC;AAE1E,UAAM,QAAQ,cAAc,CAAC;AAC7B,UAAM,OAAO,cAAc,cAAc,SAAS,CAAC;AACnD,UAAM,kBAAkB,KAAK;AAAA,OAC1B,KAAK,UAAU,QAAQ,IAAI,MAAM,UAAU,QAAQ,KAAK;AAAA,IAC3D;AAEA,QAAI,gBAAgB;AACpB,QAAI,YAAyB;AAC7B,QAAI,UAAuB;AAC3B,QAAI,0BAA0B;AAE9B,eAAW,SAAS,eAAe;AACjC,UAAI,MAAM,SAAS,QAAQ;AACzB,YAAI,cAAc,QAAQ,YAAY,QAAQ,UAAU,WAAW;AACjE,2BAAiB,KAAK;AAAA,aACnB,QAAQ,QAAQ,IAAI,UAAU,QAAQ,KAAK;AAAA,UAC9C;AAAA,QACF;AACA,oBAAY;AACZ,kBAAU;AACV,kCAA0B;AAAA,MAC5B,WAAW,yBAAyB;AAClC,oBAAY,MAAM;AAClB,kBAAU,MAAM;AAChB,kCAA0B;AAAA,MAC5B,WAAW,cAAc,MAAM;AAC7B,kBAAU,MAAM;AAAA,MAClB;AAAA,IACF;AACA,QAAI,cAAc,QAAQ,YAAY,QAAQ,UAAU,WAAW;AACjE,uBAAiB,KAAK;AAAA,SACnB,QAAQ,QAAQ,IAAI,UAAU,QAAQ,KAAK;AAAA,MAC9C;AAAA,IACF;AAEA,UAAM,kBAAkB,IAAI,MAAM,EAAE,EAAE,KAAK,CAAC;AAC5C,QAAI,mBAAmB;AACvB,eAAW,SAAS,eAAe;AACjC,UAAI,MAAM,SAAS,QAAQ;AACzB;AACA,wBAAgB,MAAM,UAAU,YAAY,CAAC;AAAA,MAC/C;AAAA,IACF;AAEA,UAAM,cAAc,MAAM;AAAA,MACxB,eAAe,IAAI,SAAS,GAAG,OAAO,KAAK,CAAC;AAAA,IAC9C,EAAE,KAAK,CAAC,MAAM,UAAU;AACtB,UAAI,MAAM,gBAAgB,KAAK,aAAa;AAC1C,eAAO,MAAM,cAAc,KAAK;AAAA,MAClC;AAEA,aAAO,KAAK,MAAM,cAAc,MAAM,KAAK;AAAA,IAC7C,CAAC;AACD,UAAM,cAAc,YAAY;AAAA,MAC9B,CAAC,KAAK,UAAU,MAAM,MAAM;AAAA,MAC5B;AAAA,IACF;AACA,UAAM,eAAe,YAAY;AAAA,MAC/B,CAAC,KAAK,UAAU,MAAM,MAAM;AAAA,MAC5B;AAAA,IACF;AACA,UAAM,kBAAkB,YAAY;AAAA,MAClC,CAAC,KAAK,UAAU,MAAM,MAAM;AAAA,MAC5B;AAAA,IACF;AACA,UAAM,eAAe,YAAY;AAAA,MAC/B,CAAC,KAAK,UAAU,MAAM,MAAM;AAAA,MAC5B;AAAA,IACF;AACA,UAAM,cAAc,YAAY;AAAA,MAC9B,CAAC,KAAK,UAAU,MAAM,MAAM;AAAA,MAC5B;AAAA,IACF;AACA,UAAM,eAAe,YAAY,CAAC,GAAG,SAAS;AAE9C,UAAM,cAAc,WAAW,QAAQ,EACpC,OAAO,SAAS,EAChB,OAAO,KAAK,EACZ,MAAM,GAAG,EAAE;AAEd,aAAS,KAAK;AAAA,MACZ,QAAQ,MAAM;AAAA,MACd,SAAS,MAAM,WAAW;AAAA,MAC1B;AAAA,MACA,UAAU;AAAA,MACV,gBAAgB,MAAM,UAAU,YAAY;AAAA,MAC5C,eAAe,KAAK,UAAU,YAAY;AAAA,MAC1C;AAAA,MACA;AAAA,MACA,cAAc,cAAc;AAAA,MAC5B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAEA,SAAO;AACT;;;ACtLA,SAAS,YAAY,aAAa,oBAAoB;AACtD,SAAS,UAAU,MAAM,WAAW;AAK7B,SAAS,eAAe,KAAuB;AACpD,QAAM,UAAoB,CAAC;AAC3B,MAAI,CAAC,WAAW,GAAG,EAAG,QAAO;AAE7B,MAAI;AACF,eAAW,SAAS,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC,GAAG;AAC7D,YAAM,WAAW,KAAK,KAAK,MAAM,IAAI;AACrC,UAAI,MAAM,YAAY,GAAG;AACvB,gBAAQ,KAAK,GAAG,eAAe,QAAQ,CAAC;AAAA,MAC1C,WAAW,MAAM,KAAK,SAAS,QAAQ,GAAG;AACxC,gBAAQ,KAAK,QAAQ;AAAA,MACvB;AAAA,IACF;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAO;AACT;AAwBO,SAAS,aAAa,UAAiC;AAC5D,MAAI;AACF,WAAO,aAAa,UAAU,OAAO;AAAA,EACvC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAKO,SAAS,WAAc,SAAsB;AAClD,QAAM,UAAe,CAAC;AACtB,aAAW,QAAQ,QAAQ,MAAM,IAAI,GAAG;AACtC,QAAI,CAAC,KAAK,KAAK,EAAG;AAClB,QAAI;AACF,cAAQ,KAAK,KAAK,MAAM,IAAI,CAAM;AAAA,IACpC,QAAQ;AAAA,IAER;AAAA,EACF;AACA,SAAO;AACT;AAsBO,SAAS,iBAAiB,UAA0B;AACzD,SAAO,SAAS,UAAU,QAAQ;AACpC;;;AC7FA,SAAS,cAAAC,mBAAkB;AAGpB,IAAM,QAA0B,CAAC;AAExC,IAAM,UAAU,oBAAI,IAAqB;AAElC,SAAS,eAAe,QAAuB;AACpD,UAAQ,IAAI,OAAO,KAAK,IAAI,MAAM;AAClC,MAAI,CAAC,MAAM,KAAK,CAAC,SAAS,KAAK,OAAO,OAAO,KAAK,EAAE,GAAG;AACrD,UAAM,KAAK,OAAO,IAAI;AAAA,EACxB;AACF;AAMO,SAAS,gBAA2B;AACzC,SAAO,MAAM,KAAK,QAAQ,OAAO,CAAC;AACpC;AAEO,SAAS,gBAAgB,QAAyB;AACvD,QAAM,SAAS,QAAQ,IAAI,MAAM;AACjC,MAAI,QAAQ,aAAa;AACvB,WAAO,OAAO,YAAY;AAAA,EAC5B;AAEA,QAAM,OAAO,MAAM,KAAK,CAAC,cAAc,UAAU,OAAO,MAAM;AAC9D,SAAO,OAAOC,YAAW,KAAK,OAAO,IAAI;AAC3C;AAEO,SAAS,uBAAyC;AACvD,SAAO,MAAM,OAAO,CAAC,SAAS,gBAAgB,KAAK,EAAE,CAAC;AACxD;AAEO,SAAS,cAAgC;AAC9C,SAAO;AACT;;;AJpBA,IAAM,OAAuB;AAAA,EAC3B,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,SAASC,MAAK,QAAQ,GAAG,WAAW,UAAU;AAChD;AAEA,IAAM,kBAAkB;AAAA,EACtBA,MAAK,QAAQ,GAAG,WAAW,aAAa;AAAA,EACxCA,MAAK,QAAQ,GAAG,WAAW,UAAU;AACvC;AAEA,SAAS,eAAe,UAA0B;AAChD,QAAM,iBAAiB,KAAK,UAAUC;AACtC,MAAI,CAAC,SAAS,WAAW,cAAc,EAAG,QAAO;AACjD,QAAM,WAAW,SAAS,MAAM,eAAe,MAAM;AACrD,QAAM,eAAe,SAAS,MAAMA,IAAG,EAAE,CAAC;AAC1C,MAAI,CAAC,aAAc,QAAO;AAC1B,QAAM,QAAQ,aAAa,MAAM,GAAG,EAAE,OAAO,OAAO;AACpD,SAAO,MAAM,SAAS,IAAI,MAAM,MAAM,SAAS,CAAC,IAAI;AACtD;AAEA,IAAM,mBAAN,MAA0C;AAAA,EAC/B,OAAO;AAAA,EAEhB,MAAM,QAA8B;AAClC,UAAM,UAA6B,CAAC;AACpC,UAAM,gBAAgC,CAAC;AACvC,UAAM,YAAY,oBAAI,IAAY;AAClC,UAAM,iBAAiB,oBAAI,IAAY;AAEvC,UAAM,eAAe,eAAe,KAAK,OAAO;AAEhD,eAAW,YAAY,cAAc;AACnC,YAAM,UAAU,aAAa,QAAQ;AACrC,UAAI,CAAC,QAAS;AAEd,YAAM,UAAU,eAAe,QAAQ;AACvC,YAAM,YAAY,iBAAiB,QAAQ;AAC3C,qBAAe,IAAI,SAAS;AAE5B,iBAAW,QAAQ,QAAQ,MAAM,IAAI,GAAG;AACtC,YAAI,CAAC,KAAK,KAAK,EAAG;AAClB,YAAI;AACF,gBAAM,MAAM,KAAK,MAAM,IAAI;AAC3B,gBAAM,YAAY,IAAI;AACtB,cAAI,CAAC,UAAW;AAEhB,gBAAM,kBAAkB,IAAI,KAAK,SAAS;AAC1C,cAAI,OAAO,MAAM,gBAAgB,QAAQ,CAAC,EAAG;AAE7C,cAAI,IAAI,SAAS,UAAU,IAAI,SAAS,aAAa;AACnD,0BAAc,KAAK;AAAA,cACjB;AAAA,cACA,QAAQ;AAAA,cACR;AAAA,cACA,WAAW;AAAA,cACX,MAAM,IAAI,SAAS,SAAS,SAAS;AAAA,YACvC,CAAC;AAAA,UACH;AAEA,cAAI,IAAI,SAAS,YAAa;AAC9B,gBAAM,UAAU,IAAI;AACpB,cAAI,CAAC,SAAS,MAAO;AAErB,gBAAM,QAAQ,QAAQ;AACtB,cAAI,MAAM,gBAAgB,QAAQ,MAAM,iBAAiB,MAAM;AAC7D;AAAA,UACF;AAEA,gBAAM,OAAO,IAAI;AACjB,cAAI,MAAM;AACR,gBAAI,UAAU,IAAI,IAAI,EAAG;AACzB,sBAAU,IAAI,IAAI;AAAA,UACpB;AAEA,kBAAQ,KAAK;AAAA,YACX;AAAA,YACA,QAAQ;AAAA,YACR,OAAO,QAAQ,SAAS;AAAA,YACxB;AAAA,YACA,WAAW;AAAA,YACX,aAAa,MAAM,gBAAgB;AAAA,YACnC,cAAc,MAAM,iBAAiB;AAAA,YACrC,iBAAiB;AAAA,YACjB,cAAc,MAAM,2BAA2B;AAAA,UACjD,CAAC;AAAA,QACH,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF;AAEA,eAAW,kBAAkB,iBAAiB;AAC5C,YAAM,kBAAkB,eAAe,cAAc;AAErD,iBAAW,YAAY,iBAAiB;AACtC,cAAM,YAAY,iBAAiB,QAAQ;AAC3C,YAAI,eAAe,IAAI,SAAS,EAAG;AAEnC,cAAM,UAAU,aAAa,QAAQ;AACrC,YAAI,CAAC,QAAS;AAEd,mBAAW,QAAQ,QAAQ,MAAM,IAAI,GAAG;AACtC,cAAI,CAAC,KAAK,KAAK,EAAG;AAClB,cAAI;AACF,kBAAM,MAAM,KAAK,MAAM,IAAI;AAC3B,kBAAM,YAAY,IAAI;AACtB,gBAAI,CAAC,UAAW;AAEhB,kBAAM,kBAAkB,IAAI,KAAK,SAAS;AAC1C,gBAAI,OAAO,MAAM,gBAAgB,QAAQ,CAAC,EAAG;AAE7C,gBAAI,IAAI,SAAS,UAAU,IAAI,SAAS,aAAa;AACnD,4BAAc,KAAK;AAAA,gBACjB;AAAA,gBACA,QAAQ;AAAA,gBACR,SAAS;AAAA,gBACT,WAAW;AAAA,gBACX,MAAM,IAAI,SAAS,SAAS,SAAS;AAAA,cACvC,CAAC;AAAA,YACH;AAAA,UACF,QAAQ;AAAA,UAER;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,MACL,SAAS,mBAAmB,OAAO;AAAA,MACnC,UAAU,gBAAgB,eAAe,OAAO;AAAA,IAClD;AAAA,EACF;AAAA,EAEA,cAAuB;AACrB,WACEC,YAAW,KAAK,OAAO,KAAK,gBAAgB,KAAK,CAAC,QAAQA,YAAW,GAAG,CAAC;AAAA,EAE7E;AACF;AAEA,eAAe,IAAI,iBAAiB,CAAC;;;AK/JrC,SAAS,WAAAC,gBAAe;AACxB,SAAS,QAAAC,aAAY;AAYrB,IAAMC,QAAuB;AAAA,EAC3B,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,SAASC,MAAKC,SAAQ,GAAG,UAAU,UAAU;AAC/C;AA8BA,SAAS,YAAY,OAAuB;AAC1C,QAAM,aAAa,MAAM,QAAQ,OAAO,GAAG,EAAE,QAAQ,QAAQ,EAAE;AAC/D,QAAM,OAAO,WAAW,MAAM,GAAG,EAAE,OAAO,OAAO,EAAE,IAAI;AACvD,SAAO,QAAQ;AACjB;AAEO,SAAS,oBAAoB,SAAyC;AAC3E,MAAI,CAAC,SAAS;AACZ,WAAO;AAAA,EACT;AAEA,QAAM,gBAAgB,QAAQ,KAAK;AACnC,MAAI,eAAe;AACjB,UAAM,QAAQ,cAAc,MAAM,4BAA4B;AAC9D,QAAI,OAAO;AACT,aAAO,MAAM,CAAC;AAAA,IAChB;AAAA,EACF;AAEA,MAAI,QAAQ,KAAK;AACf,WAAO,YAAY,QAAQ,GAAG;AAAA,EAChC;AAEA,SAAO;AACT;AAEA,IAAM,cAAN,MAAqC;AAAA,EAC1B,OAAOF;AAAA,EAEhB,MAAM,QAA8B;AAClC,UAAM,UAA6B,CAAC;AACpC,UAAM,gBAAgC,CAAC;AACvC,UAAM,QAAQ,eAAeA,MAAK,OAAO;AAEzC,QAAI,MAAM,WAAW,GAAG;AACtB,aAAO,EAAE,SAAS,CAAC,GAAG,UAAU,CAAC,EAAE;AAAA,IACrC;AAEA,eAAW,YAAY,OAAO;AAC5B,YAAM,UAAU,aAAa,QAAQ;AACrC,UAAI,CAAC,QAAS;AAEd,UAAI,iBAAiB;AACrB,YAAM,eAAe;AACrB,iBAAW,QAAQ,QAAQ,MAAM,IAAI,GAAG;AACtC,YAAI,CAAC,KAAK,KAAK,EAAG;AAClB,YAAI;AACF,gBAAM,MAAM,KAAK,MAAM,IAAI;AAC3B,cAAI,IAAI,SAAS,gBAAgB;AAC/B,6BAAiB,oBAAoB,IAAI,OAAO;AAChD;AAAA,UACF;AAAA,QACF,QAAQ;AACN;AAAA,QACF;AAAA,MACF;AAEA,UAAI,mBAAmB;AAOvB,YAAM,YAAY,oBAAI,IAAwB;AAE9C,iBAAW,QAAQ,QAAQ,MAAM,IAAI,GAAG;AACtC,YAAI,CAAC,KAAK,KAAK,EAAG;AAClB,YAAI;AACF,gBAAM,MAAM,KAAK,MAAM,IAAI;AAE3B,cAAI,IAAI,SAAS,kBAAkB,IAAI,WAAW;AAChD,kBAAM,iBAAiB,IAAI,KAAK,IAAI,SAAS;AAC7C,gBAAI,CAAC,OAAO,MAAM,eAAe,QAAQ,CAAC,GAAG;AAC3C,4BAAc,KAAK;AAAA,gBACjB,WAAW;AAAA,gBACX,QAAQ;AAAA,gBACR,SAAS;AAAA,gBACT,WAAW;AAAA,gBACX,MAAM;AAAA,cACR,CAAC;AAAA,YACH;AAAA,UACF;AAEA,cAAI,IAAI,SAAS,kBAAkB,IAAI,SAAS,OAAO;AACrD,+BAAmB,IAAI,QAAQ;AAC/B;AAAA,UACF;AAEA,cAAI,IAAI,SAAS,YAAa;AAE9B,gBAAM,UAAU,IAAI;AACpB,cAAI,CAAC,WAAW,QAAQ,SAAS,cAAe;AAEhD,gBAAM,OAAO,QAAQ;AACrB,cAAI,CAAC,KAAM;AAEX,gBAAM,YAAY,IAAI,YAAY,IAAI,KAAK,IAAI,SAAS,IAAI;AAC5D,cAAI,CAAC,aAAa,OAAO,MAAM,UAAU,QAAQ,CAAC,EAAG;AAErD,wBAAc,KAAK;AAAA,YACjB,WAAW;AAAA,YACX,QAAQ;AAAA,YACR,SAAS;AAAA,YACT;AAAA,YACA,MAAM;AAAA,UACR,CAAC;AAED,cAAI,QAAQ,KAAK;AACjB,cAAI,CAAC,SAAS,KAAK,mBAAmB;AACpC,kBAAM,WAAW,GAAG,KAAK,SAAS,QAAQ,SAAS,oBAAoB,EAAE;AACzE,kBAAM,OAAO,UAAU,IAAI,QAAQ;AACnC,kBAAM,OAAO,KAAK;AAClB,gBAAI,MAAM;AACR,sBAAQ;AAAA,gBACN,eACG,KAAK,gBAAgB,MAAM,KAAK,gBAAgB;AAAA,gBACnD,gBACG,KAAK,iBAAiB,MAAM,KAAK,iBAAiB;AAAA,gBACrD,sBACG,KAAK,uBAAuB,MAC5B,KAAK,uBAAuB;AAAA,gBAC/B,0BACG,KAAK,2BAA2B,MAChC,KAAK,2BAA2B;AAAA,cACrC;AAAA,YACF,OAAO;AACL,sBAAQ;AAAA,YACV;AACA,sBAAU,IAAI,UAAU,EAAE,GAAG,KAAK,CAAC;AAAA,UACrC;AACA,cAAI,CAAC,MAAO;AAEZ,gBAAM,QACJ,KAAK,SAAS,QAAQ,SAAS,oBAAoB;AACrD,gBAAM,cAAc,MAAM,uBAAuB;AACjD,gBAAM,kBAAkB,MAAM,2BAA2B;AAEzD,kBAAQ,KAAK;AAAA,YACX,WAAW;AAAA,YACX,QAAQ;AAAA,YACR;AAAA,YACA,SAAS;AAAA,YACT;AAAA,YACA,cAAc,MAAM,gBAAgB,KAAK;AAAA,YACzC,cAAc,MAAM,iBAAiB;AAAA,YACrC;AAAA,YACA,cAAc;AAAA,UAChB,CAAC;AAAA,QACH,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,MACL,SAAS,mBAAmB,OAAO;AAAA,MACnC,UAAU,gBAAgB,eAAe,OAAO;AAAA,IAClD;AAAA,EACF;AACF;AAEA,eAAe,IAAI,YAAY,CAAC;;;ACjNhC,SAAS,cAAAG,aAAY,eAAAC,cAAa,gBAAAC,qBAAoB;AACtD,SAAS,WAAAC,gBAAe;AACxB,SAAS,QAAAC,aAAY;AAWrB,IAAMC,QAAuB;AAAA,EAC3B,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,SAASC,MAAKC,SAAQ,GAAG,WAAW,KAAK;AAC3C;AAEA,SAAS,iBAAiB,SAA2B;AACnD,QAAM,UAAoB,CAAC;AAC3B,MAAI,CAACC,YAAW,OAAO,EAAG,QAAO;AAEjC,MAAI;AACF,eAAW,SAASC,aAAY,SAAS,EAAE,eAAe,KAAK,CAAC,GAAG;AACjE,UAAI,CAAC,MAAM,YAAY,EAAG;AAC1B,YAAM,WAAWH,MAAK,SAAS,MAAM,MAAM,OAAO;AAClD,UAAI,CAACE,YAAW,QAAQ,EAAG;AAC3B,UAAI;AACF,mBAAW,KAAKC,aAAY,QAAQ,GAAG;AACrC,cAAI,EAAE,WAAW,UAAU,KAAK,EAAE,SAAS,OAAO,GAAG;AACnD,oBAAQ,KAAKH,MAAK,UAAU,CAAC,CAAC;AAAA,UAChC;AAAA,QACF;AAAA,MACF,QAAQ;AAAA,MAAC;AAAA,IACX;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAgCA,IAAM,kBAAN,MAAyC;AAAA,EAC9B,OAAOD;AAAA,EAEhB,MAAM,QAA8B;AAClC,UAAM,eAAe,iBAAiBA,MAAK,OAAO;AAClD,QAAI,aAAa,WAAW,GAAG;AAC7B,aAAO,EAAE,SAAS,CAAC,GAAG,UAAU,CAAC,EAAE;AAAA,IACrC;AAEA,UAAM,UAA6B,CAAC;AACpC,UAAM,gBAAgC,CAAC;AAEvC,eAAW,YAAY,cAAc;AACnC,UAAI;AACJ,UAAI;AACF,eAAO,KAAK,MAAMK,cAAa,UAAU,OAAO,CAAC;AAAA,MACnD,QAAQ;AACN;AAAA,MACF;AAEA,YAAM,WAAW,KAAK,YAAY,KAAK,WAAW,CAAC;AACnD,iBAAW,OAAO,UAAU;AAC1B,cAAM,YAAY,IAAI,aAAa,IAAI,cAAc,KAAK;AAC1D,YAAI,CAAC,UAAW;AAChB,cAAM,KAAK,IAAI,KAAK,SAAS;AAC7B,YAAI,OAAO,MAAM,GAAG,QAAQ,CAAC,EAAG;AAEhC,YAAI,IAAI,SAAS,UAAU,IAAI,SAAS,YAAa;AAErD,cAAM,OAAO,IAAI;AACjB,sBAAc,KAAK;AAAA,UACjB,WAAW;AAAA,UACX,QAAQ;AAAA,UACR,SAAS;AAAA,UACT,WAAW;AAAA,UACX;AAAA,QACF,CAAC;AAED,cAAM,SAAS,IAAI;AACnB,cAAM,QAAQ,IAAI,SAAS,IAAI,iBAAiB,IAAI;AACpD,YAAI,CAAC,UAAU,CAAC,MAAO;AAEvB,YAAI,QAAQ;AACV,gBAAM,SAAS,OAAO,UAAU;AAChC,gBAAM,WAAW,OAAO,YAAY;AACpC,kBAAQ,KAAK;AAAA,YACX,WAAW;AAAA,YACX,QAAQ;AAAA,YACR,OAAO,IAAI,SAAS,KAAK,SAAS;AAAA,YAClC,SAAS;AAAA,YACT,WAAW;AAAA,YACX,cAAc,OAAO,SAAS,KAAK;AAAA,YACnC,cAAc,OAAO,UAAU;AAAA,YAC/B,iBAAiB;AAAA,YACjB,cAAc;AAAA,UAChB,CAAC;AAAA,QACH,WAAW,OAAO;AAChB,gBAAM,SAAS,MAAM,2BAA2B;AAChD,gBAAM,WAAW,MAAM,sBAAsB;AAC7C,kBAAQ,KAAK;AAAA,YACX,WAAW;AAAA,YACX,QAAQ;AAAA,YACR,OAAO,IAAI,SAAS,KAAK,SAAS;AAAA,YAClC,SAAS;AAAA,YACT,WAAW;AAAA,YACX,cACG,MAAM,oBAAoB,MAAM,gBAAgB,KAAK;AAAA,YACxD,cACE,MAAM,wBAAwB,MAAM,iBAAiB;AAAA,YACvD,iBAAiB;AAAA,YACjB,cAAc;AAAA,UAChB,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,MACL,SAAS,mBAAmB,OAAO;AAAA,MACnC,UAAU,gBAAgB,eAAe,OAAO;AAAA,IAClD;AAAA,EACF;AACF;AAEA,eAAe,IAAI,gBAAgB,CAAC;;;AC3JpC,SAAS,cAAAC,aAAY,eAAAC,cAAa,gBAAAC,qBAAoB;AACtD,SAAS,WAAAC,gBAAe;AACxB,SAAS,YAAAC,WAAU,SAAS,QAAAC,aAAY;AAWxC,IAAM,WAAWC,MAAKC,SAAQ,GAAG,UAAU;AAE3C,IAAMC,QAAuB;AAAA,EAC3B,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,SAAS;AACX;AAwBA,SAAS,kBACP,KACA,SACA,SACM;AACN,MAAI,CAACC,YAAW,GAAG,KAAK,QAAQ,IAAI,GAAG,GAAG;AACxC;AAAA,EACF;AAEA,UAAQ,IAAI,GAAG;AAEf,MAAI;AACF,eAAW,SAASC,aAAY,KAAK,EAAE,eAAe,KAAK,CAAC,GAAG;AAC7D,YAAM,WAAWJ,MAAK,KAAK,MAAM,IAAI;AAErC,UAAI,MAAM,YAAY,GAAG;AACvB,0BAAkB,UAAU,SAAS,OAAO;AAC5C;AAAA,MACF;AAEA,UAAI,MAAM,OAAO,KAAK,MAAM,SAAS,gBAAgB;AACnD,gBAAQ,KAAK;AAAA,UACX,UAAU;AAAA,UACV,WAAWK,UAAS,QAAQ,QAAQ,CAAC;AAAA,QACvC,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF,QAAQ;AAAA,EAER;AACF;AAEA,SAAS,eACP,SAC2C;AAC3C,QAAM,UAAqD,CAAC;AAC5D,oBAAkB,SAAS,SAAS,oBAAI,IAAY,CAAC;AACrD,SAAO;AACT;AAEA,SAAS,sBACP,SACQ;AACR,QAAM,cAAc,SAAS,WAAW,SAAS;AACjD,MAAI,CAAC,YAAa,QAAO;AACzB,SAAOA,UAAS,YAAY,QAAQ,WAAW,EAAE,CAAC,KAAK;AACzD;AAEA,IAAM,mBAAN,MAA0C;AAAA,EAC/B,OAAOH;AAAA,EAEhB,MAAM,QAA8B;AAClC,UAAM,aAAa,eAAe,QAAQ;AAC1C,QAAI,WAAW,WAAW,GAAG;AAC3B,aAAO,EAAE,SAAS,CAAC,GAAG,UAAU,CAAC,EAAE;AAAA,IACrC;AAEA,UAAM,UAA6B,CAAC;AACpC,UAAM,gBAAgC,CAAC;AAEvC,eAAW,EAAE,UAAU,UAAU,KAAK,YAAY;AAChD,UAAI;AACJ,UAAI;AACF,kBAAUI,cAAa,UAAU,OAAO;AAAA,MAC1C,QAAQ;AACN;AAAA,MACF;AAEA,UAAI,iBAAiB;AAErB,iBAAW,QAAQ,QAAQ,MAAM,IAAI,GAAG;AACtC,YAAI,CAAC,KAAK,KAAK,EAAG;AAElB,YAAI;AACF,gBAAM,MAAM,KAAK,MAAM,IAAI;AAC3B,gBAAM,YAAY,IAAI,YAAY,IAAI,KAAK,IAAI,SAAS,IAAI;AAC5D,gBAAM,eAAe,aAAa,CAAC,OAAO,MAAM,UAAU,QAAQ,CAAC;AAEnE,cAAI,IAAI,SAAS,mBAAmB,IAAI,SAAS,kBAAkB;AACjE,6BAAiB,sBAAsB,IAAI,MAAM,OAAO;AAAA,UAC1D;AAEA,cAAI,gBAAgB,aAAa,IAAI,SAAS,gBAAgB;AAC5D,0BAAc,KAAK;AAAA,cACjB;AAAA,cACA,QAAQ;AAAA,cACR,SAAS;AAAA,cACT;AAAA,cACA,MAAM;AAAA,YACR,CAAC;AAAA,UACH;AAEA,cAAI,gBAAgB,aAAa,IAAI,SAAS,qBAAqB;AACjE,0BAAc,KAAK;AAAA,cACjB;AAAA,cACA,QAAQ;AAAA,cACR,SAAS;AAAA,cACT;AAAA,cACA,MAAM;AAAA,YACR,CAAC;AAAA,UACH;AAEA,cAAI,IAAI,SAAS,sBAAsB,CAAC,gBAAgB,CAAC,WAAW;AAClE;AAAA,UACF;AAEA,gBAAM,eAAe,IAAI,MAAM,gBAAgB,CAAC;AAChD,qBAAW,CAAC,OAAO,OAAO,KAAK,OAAO,QAAQ,YAAY,GAAG;AAC3D,kBAAM,QAAQ,SAAS;AACvB,gBAAI,CAAC,MAAO;AAEZ,kBAAM,aAAa,MAAM,eAAe;AACxC,kBAAM,aAAa,MAAM,mBAAmB;AAC5C,kBAAM,SAAS,MAAM,gBAAgB;AAErC,gBAAI,eAAe,KAAK,eAAe,KAAK,WAAW,GAAG;AACxD;AAAA,YACF;AAEA,oBAAQ,KAAK;AAAA,cACX;AAAA,cACA,QAAQ;AAAA,cACR;AAAA,cACA,SAAS;AAAA,cACT;AAAA,cACA,aAAa,KAAK,IAAI,GAAG,aAAa,UAAU;AAAA,cAChD,cAAc;AAAA,cACd,iBAAiB;AAAA,cACjB,cAAc;AAAA,YAChB,CAAC;AAAA,UACH;AAAA,QACF,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,MACL,SAAS,mBAAmB,OAAO;AAAA,MACnC,UAAU,gBAAgB,eAAe,OAAO;AAAA,IAClD;AAAA,EACF;AAAA,EAEA,cAAuB;AACrB,WAAOH,YAAW,QAAQ;AAAA,EAC5B;AACF;AAEA,eAAe,IAAI,iBAAiB,CAAC;;;AC/LrC,SAAS,oBAAoB;AAC7B,SAAsB,cAAAI,aAAY,eAAAC,cAAa,gBAAAC,qBAAoB;AACnE,SAAS,WAAAC,gBAAe;AACxB,SAAS,YAAAC,WAAU,QAAAC,aAAY;AAW/B,IAAM,mBAAmBC,MAAKC,SAAQ,GAAG,UAAU,SAAS,UAAU;AAEtE,IAAMC,QAAuB;AAAA,EAC3B,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,SAAS;AACX;AAgCA,SAAS,oBAAoB,MAAyB,QAAQ,KAAe;AAC3E,QAAM,OAAO;AAAA,IACX,IAAI;AAAA,IACJ,IAAI,gBAAgBF,MAAK,IAAI,eAAe,UAAU,IAAI;AAAA,IAC1D;AAAA,IACA,IAAI,eAAeA,MAAK,IAAI,cAAc,UAAU,IAAI;AAAA,IACxD,IAAI,UAAUA,MAAK,IAAI,SAAS,UAAU,IAAI;AAAA,EAChD,EAAE,OAAO,CAAC,UAA2B,QAAQ,KAAK,CAAC;AAEnD,SAAO,MAAM,KAAK,IAAI,IAAI,IAAI,CAAC;AACjC;AAEA,eAAe,4BACb,IACY;AACZ,QAAM,sBAAsB,QAAQ;AAEpC,UAAQ,eAAe,CACrB,YACG,SACM;AACT,UAAM,cACJ,OAAO,YAAY,WACf,OAAO,KAAK,CAAC,MAAM,WACjB,KAAK,CAAC,IACN,KACF,QAAQ;AACd,UAAM,iBACJ,OAAO,YAAY,WAAW,UAAU,QAAQ;AAElD,QACE,gBAAgB,yBAChB,eAAe,SAAS,QAAQ,GAChC;AACA;AAAA,IACF;AAEA,IACE,oBAIA,KAAK,SAAS,SAAS,GAAG,IAAI;AAAA,EAClC;AAEA,MAAI;AACF,WAAO,MAAM,GAAG;AAAA,EAClB,UAAE;AACA,YAAQ,cAAc;AAAA,EACxB;AACF;AAEA,eAAe,0BACb,QACA,OAC6B;AAC7B,MAAI;AACF,WAAO,MAAM,4BAA4B,YAAY;AACnD,YAAM,iBAAiB;AACvB,YAAM,SAAU,MAAM,OAAO;AAU7B,YAAM,KAAK,IAAI,OAAO,aAAa,MAAM;AAEzC,UAAI;AACF,eAAO,GAAG,QAAQ,KAAK,EAAE,IAAI;AAAA,MAC/B,UAAE;AACA,WAAG,MAAM;AAAA,MACX;AAAA,IACF,CAAC;AAAA,EACH,SAAS,KAAK;AACZ,UAAM,QAAQ;AACd,UAAM,UAAW,IAAc;AAC/B,QACE,MAAM,SAAS,gCACf,QAAQ,SAAS,aAAa,GAC9B;AACA,aAAO;AAAA,IACT;AAEA,UAAM;AAAA,EACR;AACF;AAEA,SAAS,sBAAsB,QAAgB,OAA4B;AACzE,QAAM,aAAa;AAAA,IACjB,QAAQ,IAAI;AAAA,IACZ;AAAA,IACA;AAAA,EACF,EAAE,OAAO,CAAC,UAA2B,QAAQ,KAAK,CAAC;AAEnD,MAAI,YAA0B;AAE9B,aAAW,WAAW,YAAY;AAChC,QAAI;AACF,YAAM,SAAS,aAAa,SAAS,CAAC,SAAS,QAAQ,KAAK,GAAG;AAAA,QAC7D,UAAU;AAAA,QACV,WAAW,MAAM,OAAO;AAAA,QACxB,SAAS;AAAA,QACT,aAAa;AAAA,MACf,CAAC,EAAE,KAAK;AAER,UAAI,CAAC,UAAU,WAAW,MAAM;AAC9B,eAAO,CAAC;AAAA,MACV;AAEA,aAAO,KAAK,MAAM,MAAM;AAAA,IAC1B,SAAS,KAAK;AACZ,kBAAY;AACZ,YAAM,YAAY;AAClB,UAAI,UAAU,WAAW,OAAO,UAAU,SAAS,SAAS,QAAQ,GAAG;AACrE;AAAA,MACF;AAEA,YAAM;AAAA,IACR;AAAA,EACF;AAEA,QAAM,IAAI;AAAA,IACR,mGAAmG,WAAW,WAAW,WAAW;AAAA,EACtI;AACF;AAEA,IAAM,iBAAN,MAAwC;AAAA,EAC7B,OAAOE;AAAA,EAEhB,MAAM,QAA8B;AAClC,UAAM,UAAkC,CAAC;AACzC,UAAM,WAAoC,CAAC;AAE3C,eAAW,WAAW,oBAAoB,GAAG;AAC3C,YAAM,SAAS,MAAM,KAAK,UAAU,OAAO;AAC3C,UAAI,OAAO,QAAQ,SAAS,GAAG;AAC7B,gBAAQ,KAAK,GAAG,OAAO,OAAO;AAAA,MAChC;AACA,UAAI,OAAO,SAAS,SAAS,GAAG;AAC9B,iBAAS,KAAK,GAAG,OAAO,QAAQ;AAAA,MAClC;AAAA,IACF;AAEA,WAAO,EAAE,SAAS,SAAS;AAAA,EAC7B;AAAA,EAEA,cAAuB;AACrB,WAAO,oBAAoB,EAAE,KAAK,CAAC,QAAQC,YAAW,GAAG,CAAC;AAAA,EAC5D;AAAA,EAEA,MAAc,UAAU,SAAuC;AAC7D,UAAM,SAASH,MAAK,SAAS,aAAa;AAC1C,UAAM,cAAcA,MAAK,SAAS,WAAW,SAAS;AAEtD,QAAIG,YAAW,MAAM,GAAG;AACtB,UAAI;AACF,eAAO,MAAM,KAAK,gBAAgB,MAAM;AAAA,MAC1C,SAAS,KAAK;AACZ,gBAAQ,OAAO;AAAA,UACb,uCAAwC,IAAc,OAAO;AAAA;AAAA,QAC/D;AAAA,MACF;AAAA,IACF;AAEA,WAAO,KAAK,cAAc,WAAW;AAAA,EACvC;AAAA,EAEA,MAAc,gBAAgB,QAAsC;AAClE,UAAM,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASd,UAAM,cAAc,MAAM,0BAA0B,QAAQ,KAAK;AACjE,UAAM,OAAO,eAAe,sBAAsB,QAAQ,KAAK;AAE/D,QAAI,KAAK,WAAW,GAAG;AACrB,aAAO,EAAE,SAAS,CAAC,GAAG,UAAU,CAAC,EAAE;AAAA,IACrC;AAEA,UAAM,UAA6B,CAAC;AACpC,UAAM,gBAAgC,CAAC;AAEvC,eAAW,OAAO,MAAM;AACtB,YAAM,YAAY,IAAI,KAAK,IAAI,OAAO;AACtC,UAAI,OAAO,MAAM,UAAU,QAAQ,CAAC,EAAG;AAEvC,YAAM,UAAU,IAAI,WAAWC,UAAS,IAAI,QAAQ,IAAI;AACxD,YAAM,YAAY,IAAI,aAAa;AACnC,UAAI,IAAI,SAAS,UAAU,IAAI,SAAS,YAAa;AAErD,oBAAc,KAAK;AAAA,QACjB;AAAA,QACA,QAAQ;AAAA,QACR;AAAA,QACA;AAAA,QACA,MAAM,IAAI,SAAS,SAAS,SAAS;AAAA,MACvC,CAAC;AAED,UAAI,CAAC,IAAI,QAAS;AAElB,UAAI;AACJ,UAAI;AACF,iBACE,OAAO,IAAI,WAAW,WAAW,KAAK,MAAM,IAAI,MAAM,IAAI,IAAI;AAAA,MAClE,QAAQ;AACN;AAAA,MACF;AACA,UAAI,CAAC,UAAW,CAAC,OAAO,SAAS,CAAC,OAAO,OAAS;AAElD,cAAQ,KAAK;AAAA,QACX;AAAA,QACA,QAAQ;AAAA,QACR,OAAO,IAAI,WAAW;AAAA,QACtB;AAAA,QACA;AAAA,QACA,aAAa,OAAO,SAAS;AAAA,QAC7B,cAAc,OAAO,UAAU;AAAA,QAC/B,iBAAiB,OAAO,aAAa;AAAA,QACrC,cAAc,OAAO,OAAO,QAAQ;AAAA,MACtC,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,MACL,SAAS,mBAAmB,OAAO;AAAA,MACnC,UAAU,gBAAgB,eAAe,OAAO;AAAA,IAClD;AAAA,EACF;AAAA,EAEQ,cAAc,aAAkC;AACtD,QAAI,CAACD,YAAW,WAAW,EAAG,QAAO,EAAE,SAAS,CAAC,GAAG,UAAU,CAAC,EAAE;AAEjE,UAAM,UAA6B,CAAC;AACpC,UAAM,gBAAgC,CAAC;AAEvC,QAAI;AACJ,QAAI;AACF,oBAAcE,aAAY,aAAa,EAAE,eAAe,KAAK,CAAC,EAAE;AAAA,QAC9D,CAAC,WAAW,OAAO,YAAY,KAAK,OAAO,KAAK,WAAW,MAAM;AAAA,MACnE;AAAA,IACF,QAAQ;AACN,aAAO,EAAE,SAAS,CAAC,GAAG,UAAU,CAAC,EAAE;AAAA,IACrC;AAEA,eAAW,cAAc,aAAa;AACpC,YAAM,cAAcL,MAAK,aAAa,WAAW,IAAI;AACrD,UAAI;AACJ,UAAI;AACF,uBAAeK,aAAY,WAAW,EAAE;AAAA,UAAO,CAAC,SAC9C,KAAK,SAAS,OAAO;AAAA,QACvB;AAAA,MACF,QAAQ;AACN;AAAA,MACF;AAEA,iBAAW,QAAQ,cAAc;AAC/B,cAAM,WAAWL,MAAK,aAAa,IAAI;AAEvC,YAAI;AACJ,YAAI;AACF,iBAAO,KAAK,MAAMM,cAAa,UAAU,OAAO,CAAC;AAAA,QACnD,QAAQ;AACN;AAAA,QACF;AAEA,cAAM,YAAY,IAAI,KAAK,KAAK,MAAM,WAAW,KAAK,OAAO;AAC7D,YAAI,OAAO,MAAM,UAAU,QAAQ,CAAC,EAAG;AAEvC,cAAM,WAAW,KAAK,MAAM;AAC5B,cAAM,UAAU,WAAWF,UAAS,QAAQ,IAAI;AAChD,YAAI,KAAK,SAAS,UAAU,KAAK,SAAS,YAAa;AAEvD,sBAAc,KAAK;AAAA,UACjB,WAAW,WAAW;AAAA,UACtB,QAAQ;AAAA,UACR;AAAA,UACA;AAAA,UACA,MAAM,KAAK,SAAS,SAAS,SAAS;AAAA,QACxC,CAAC;AAED,YAAI,CAAC,KAAK,QAAS;AACnB,cAAM,SAAS,KAAK;AACpB,YAAI,CAAC,UAAW,CAAC,OAAO,SAAS,CAAC,OAAO,OAAS;AAElD,gBAAQ,KAAK;AAAA,UACX,WAAW,WAAW;AAAA,UACtB,QAAQ;AAAA,UACR,OAAO,KAAK,WAAW;AAAA,UACvB;AAAA,UACA;AAAA,UACA,aAAa,OAAO,SAAS;AAAA,UAC7B,cAAc,OAAO,UAAU;AAAA,UAC/B,iBAAiB,OAAO,aAAa;AAAA,UACrC,cAAc,OAAO,OAAO,QAAQ;AAAA,QACtC,CAAC;AAAA,MACH;AAAA,IACF;AAEA,WAAO;AAAA,MACL,SAAS,mBAAmB,OAAO;AAAA,MACnC,UAAU,gBAAgB,eAAe,OAAO;AAAA,IAClD;AAAA,EACF;AACF;AAEA,eAAe,IAAI,eAAe,CAAC;;;AC7WnC,SAAsB,cAAAG,aAAY,eAAAC,cAAa,gBAAAC,qBAAoB;AACnE,SAAS,WAAAC,gBAAe;AACxB,SAAS,QAAAC,aAAY;AAWrB,IAAM,iBAAiB;AAAA,EACrBC,MAAKC,SAAQ,GAAG,WAAW;AAAA,EAC3BD,MAAKC,SAAQ,GAAG,WAAW;AAAA,EAC3BD,MAAKC,SAAQ,GAAG,UAAU;AAAA,EAC1BD,MAAKC,SAAQ,GAAG,UAAU;AAC5B;AAEA,IAAMC,QAAuB;AAAA,EAC3B,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,SAAS,eAAe,CAAC;AAAA;AAC3B;AA6BA,SAAS,UACP,UACG,MACK;AACR,aAAW,OAAO,MAAM;AACtB,UAAM,QAAS,MAAkC,GAAG;AACpD,QAAI,OAAO,UAAU,YAAY,QAAQ,EAAG,QAAO;AAAA,EACrD;AACA,SAAO;AACT;AAEA,IAAM,iBAAN,MAAwC;AAAA,EAC7B,OAAOA;AAAA,EAEhB,MAAM,QAA8B;AAClC,UAAM,UAA6B,CAAC;AACpC,UAAM,gBAAgC,CAAC;AAEvC,eAAW,QAAQ,gBAAgB;AACjC,YAAM,YAAYF,MAAK,MAAM,QAAQ;AACrC,UAAI,CAACG,YAAW,SAAS,EAAG;AAE5B,UAAI;AACJ,UAAI;AACF,oBAAYC,aAAY,WAAW,EAAE,eAAe,KAAK,CAAC,EAAE;AAAA,UAC1D,CAAC,MAAM,EAAE,YAAY;AAAA,QACvB;AAAA,MACF,QAAQ;AACN;AAAA,MACF;AAEA,iBAAW,YAAY,WAAW;AAChC,cAAM,UAAU,SAAS;AACzB,cAAM,cAAcJ,MAAK,WAAW,SAAS,MAAM,UAAU;AAC7D,YAAI,CAACG,YAAW,WAAW,EAAG;AAE9B,YAAI;AACJ,YAAI;AACF,kBAAQC,aAAY,WAAW,EAAE,OAAO,CAAC,MAAM,EAAE,SAAS,QAAQ,CAAC;AAAA,QACrE,QAAQ;AACN;AAAA,QACF;AAEA,mBAAW,QAAQ,OAAO;AACxB,gBAAM,WAAWJ,MAAK,aAAa,IAAI;AAEvC,cAAI;AACJ,cAAI;AACF,sBAAUK,cAAa,UAAU,OAAO;AAAA,UAC1C,QAAQ;AACN;AAAA,UACF;AAEA,qBAAW,QAAQ,QAAQ,MAAM,IAAI,GAAG;AACtC,gBAAI,CAAC,KAAK,KAAK,EAAG;AAClB,gBAAI;AACF,oBAAM,MAAM,KAAK,MAAM,IAAI;AAE3B,kBAAI,IAAI,SAAS,UAAW;AAC5B,oBAAM,MAAM,IAAI;AAChB,kBAAI,CAAC,IAAK;AAEV,oBAAM,YAAY,IAAI,aAAa,IAAI;AACvC,kBAAI,CAAC,UAAW;AAChB,oBAAM,KAAK,IAAI;AAAA,gBACb,OAAO,cAAc,WAAW,YAAY;AAAA,cAC9C;AACA,kBAAI,OAAO,MAAM,GAAG,QAAQ,CAAC,EAAG;AAChC,kBAAI,IAAI,SAAS,UAAU,IAAI,SAAS,YAAa;AAErD,4BAAc,KAAK;AAAA,gBACjB,WAAW;AAAA,gBACX,QAAQ;AAAA,gBACR;AAAA,gBACA,WAAW;AAAA,gBACX,MAAM,IAAI,SAAS,SAAS,SAAS;AAAA,cACvC,CAAC;AAED,kBAAI,IAAI,SAAS,YAAa;AAC9B,oBAAM,QAAQ,IAAI;AAClB,kBAAI,CAAC,MAAO;AAEZ,sBAAQ,KAAK;AAAA,gBACX,WAAW;AAAA,gBACX,QAAQ;AAAA,gBACR,OAAO,IAAI,SAAS,IAAI,SAAS;AAAA,gBACjC;AAAA,gBACA,WAAW;AAAA,gBACX,aAAa;AAAA,kBACX;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA;AAAA,gBACF;AAAA,gBACA,cAAc;AAAA,kBACZ;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA;AAAA,gBACF;AAAA,gBACA,iBAAiB;AAAA,gBACjB,cAAc;AAAA,kBACZ;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA;AAAA,gBACF;AAAA,cACF,CAAC;AAAA,YACH,QAAQ;AAAA,YAAC;AAAA,UACX;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,MACL,SAAS,mBAAmB,OAAO;AAAA,MACnC,UAAU,gBAAgB,eAAe,OAAO;AAAA,IAClD;AAAA,EACF;AAAA;AAAA,EAGA,cAAuB;AACrB,WAAO,eAAe,KAAK,CAAC,SAASF,YAAWH,MAAK,MAAM,QAAQ,CAAC,CAAC;AAAA,EACvE;AACF;AAEA,eAAe,IAAI,eAAe,CAAC;;;ACvLnC,SAAS,cAAAM,aAAY,eAAAC,oBAAmB;AACxC,SAAS,WAAAC,gBAAe;AACxB,SAAS,QAAAC,aAAY;AAYrB,IAAM,UAAU;AAChB,IAAM,YAAY;AAClB,IAAMC,oBAAmBC,MAAKC,SAAQ,GAAG,SAAS,KAAK;AAyBvD,SAAS,qBAAqB,SAAiC;AAC7D,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,MAAM;AAAA,IACN;AAAA,EACF;AACF;AAEA,SAAS,aAAa,OAAwB;AAC5C,QAAM,cAAc,OAAO,KAAK;AAChC,SAAO,OAAO,SAAS,WAAW,IAAI,cAAc;AACtD;AAEA,SAASC,aAAY,OAAuB;AAC1C,QAAM,aAAa,MAAM,QAAQ,OAAO,GAAG,EAAE,QAAQ,QAAQ,EAAE;AAC/D,QAAM,OAAO,WAAW,MAAM,GAAG,EAAE,OAAO,OAAO,EAAE,IAAI;AACvD,SAAO,QAAQ;AACjB;AAEA,SAAS,mBAAmB,OAAuB;AACjD,SAAO,MAAM,QAAQ,OAAO,GAAG,EAAE,QAAQ,QAAQ,EAAE;AACrD;AAEA,SAASC,kBAAiB,SAA2B;AACnD,QAAM,UAAoB,CAAC;AAC3B,MAAI,CAACC,YAAW,OAAO,EAAG,QAAO;AAEjC,MAAI;AACF,eAAW,SAASC,aAAY,SAAS,EAAE,eAAe,KAAK,CAAC,GAAG;AACjE,UAAI,CAAC,MAAM,YAAY,EAAG;AAE1B,YAAM,WAAWL,MAAK,SAAS,MAAM,MAAM,OAAO;AAClD,UAAI,CAACI,YAAW,QAAQ,EAAG;AAE3B,UAAI;AACF,mBAAW,QAAQC,aAAY,QAAQ,GAAG;AACxC,cAAI,KAAK,SAAS,QAAQ,GAAG;AAC3B,oBAAQ,KAAKL,MAAK,UAAU,IAAI,CAAC;AAAA,UACnC;AAAA,QACF;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEO,SAAS,mBACd,KACA,UACA,UAAUD,mBACF;AACR,MAAI,KAAK;AACP,WAAOG,aAAY,GAAG;AAAA,EACxB;AAEA,QAAM,qBAAqB,mBAAmB,QAAQ;AACtD,QAAM,oBAAoB,mBAAmB,OAAO;AACpD,QAAM,SAAS,GAAG,iBAAiB;AAEnC,MAAI,CAAC,mBAAmB,WAAW,MAAM,GAAG;AAC1C,WAAO;AAAA,EACT;AAEA,QAAM,eAAe,mBAAmB,MAAM,OAAO,MAAM;AAC3D,QAAM,YAAY,aAAa,MAAM,GAAG,EAAE,CAAC;AAC3C,SAAO,aAAa;AACtB;AAEO,IAAM,iBAAN,MAAwC;AAAA,EAG7C,YAA6B,UAAUH,mBAAkB;AAA5B;AAC3B,SAAK,OAAO,qBAAqB,OAAO;AAAA,EAC1C;AAAA,EAJS;AAAA,EAMT,MAAM,QAA8B;AAClC,UAAM,eAAeI,kBAAiB,KAAK,OAAO;AAClD,QAAI,aAAa,WAAW,GAAG;AAC7B,aAAO,EAAE,SAAS,CAAC,GAAG,UAAU,CAAC,EAAE;AAAA,IACrC;AAEA,UAAM,UAA6B,CAAC;AACpC,UAAM,gBAAgC,CAAC;AACvC,UAAM,YAAY,oBAAI,IAAY;AAElC,eAAW,YAAY,cAAc;AACnC,YAAM,UAAU,aAAa,QAAQ;AACrC,UAAI,CAAC,QAAS;AAEd,YAAM,YAAY;AAElB,iBAAW,QAAQ,QAAQ,MAAM,IAAI,GAAG;AACtC,YAAI,CAAC,KAAK,KAAK,EAAG;AAElB,YAAI;AACF,gBAAM,MAAM,KAAK,MAAM,IAAI;AAC3B,cAAI,CAAC,IAAI,UAAW;AAEpB,gBAAM,YAAY,IAAI,KAAK,IAAI,SAAS;AACxC,cAAI,OAAO,MAAM,UAAU,QAAQ,CAAC,EAAG;AAEvC,gBAAM,UAAU,mBAAmB,IAAI,KAAK,UAAU,KAAK,OAAO;AAElE,cAAI,IAAI,SAAS,UAAU,IAAI,SAAS,aAAa;AACnD,0BAAc,KAAK;AAAA,cACjB;AAAA,cACA,QAAQ;AAAA,cACR;AAAA,cACA;AAAA,cACA,MAAM,IAAI;AAAA,YACZ,CAAC;AAAA,UACH;AAEA,cAAI,IAAI,SAAS,YAAa;AAE9B,gBAAM,QAAQ,IAAI,iBAAiB,IAAI;AACvC,cAAI,CAAC,MAAO;AAEZ,gBAAM,aACJ,aAAa,MAAM,gBAAgB,KACnC,aAAa,MAAM,YAAY;AACjC,gBAAM,cACJ,aAAa,MAAM,oBAAoB,KACvC,aAAa,MAAM,aAAa;AAClC,gBAAM,eAAe,aAAa,MAAM,uBAAuB;AAC/D,gBAAM,kBAAkB,aAAa,MAAM,kBAAkB;AAE7D,cACE,eAAe,KACf,gBAAgB,KAChB,iBAAiB,KACjB,oBAAoB,GACpB;AACA;AAAA,UACF;AAEA,cAAI,IAAI,MAAM;AACZ,gBAAI,UAAU,IAAI,IAAI,IAAI,EAAG;AAC7B,sBAAU,IAAI,IAAI,IAAI;AAAA,UACxB;AAEA,kBAAQ,KAAK;AAAA,YACX;AAAA,YACA,QAAQ;AAAA,YACR,OAAO,IAAI,SAAS;AAAA,YACpB;AAAA,YACA;AAAA,YACA,aAAa,KAAK,IAAI,GAAG,aAAa,YAAY;AAAA,YAClD,cAAc,KAAK,IAAI,GAAG,cAAc,eAAe;AAAA,YACvD;AAAA,YACA;AAAA,UACF,CAAC;AAAA,QACH,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,MACL,SAAS,mBAAmB,OAAO;AAAA,MACnC,UAAU,gBAAgB,eAAe,OAAO;AAAA,IAClD;AAAA,EACF;AAAA,EAEA,cAAuB;AACrB,WAAOC,YAAW,KAAK,OAAO;AAAA,EAChC;AACF;AAEA,eAAe,IAAI,eAAe,CAAC;;;ACvNnC,SAAS,cAAAE,aAAY,eAAAC,oBAAmB;AACxC,SAAS,WAAAC,gBAAe;AACxB,SAAS,QAAAC,aAAY;AAYrB,IAAMC,WAAU;AAChB,IAAMC,aAAY;AAClB,IAAM,uBAAuBC,MAAKC,SAAQ,GAAG,SAAS,UAAU;AAChE,IAAM,sBAAsBD,MAAKC,SAAQ,GAAG,SAAS,WAAW;AAEhE,IAAM,mBAAmB,oBAAI,IAAI,CAAC,eAAe,gBAAgB,OAAO,CAAC;AACzE,IAAM,wBAAwB,oBAAI,IAAI;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AA4BD,SAASC,sBAAqB,SAAiC;AAC7D,SAAO;AAAA,IACL,IAAIJ;AAAA,IACJ,MAAMC;AAAA,IACN;AAAA,EACF;AACF;AAEA,SAASI,cAAa,OAAwB;AAC5C,QAAM,cAAc,OAAO,KAAK;AAChC,SAAO,OAAO,SAAS,WAAW,IAAI,cAAc;AACtD;AAEA,SAASC,aAAY,OAAuB;AAC1C,QAAM,aAAa,MAAM,QAAQ,OAAO,GAAG,EAAE,QAAQ,QAAQ,EAAE;AAC/D,QAAM,OAAO,WAAW,MAAM,GAAG,EAAE,OAAO,OAAO,EAAE,IAAI;AACvD,SAAO,QAAQ;AACjB;AAEA,SAAS,cACP,SACkD;AAClD,QAAM,UAA4D,CAAC;AACnE,MAAI,CAACC,YAAW,OAAO,EAAG,QAAO;AAEjC,MAAI;AACF,eAAW,WAAWC,aAAY,SAAS,EAAE,eAAe,KAAK,CAAC,GAAG;AACnE,UAAI,CAAC,QAAQ,YAAY,EAAG;AAE5B,YAAM,cAAcN,MAAK,SAAS,QAAQ,IAAI;AAC9C,UAAI;AACF,mBAAW,WAAWM,aAAY,aAAa;AAAA,UAC7C,eAAe;AAAA,QACjB,CAAC,GAAG;AACF,cAAI,CAAC,QAAQ,YAAY,EAAG;AAE5B,gBAAM,WAAWN,MAAK,aAAa,QAAQ,MAAM,YAAY;AAC7D,cAAIK,YAAW,QAAQ,GAAG;AACxB,oBAAQ,KAAK,EAAE,UAAU,UAAU,aAAa,QAAQ,KAAK,CAAC;AAAA,UAChE;AAAA,QACF;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEA,SAAS,eAAe,OAAiD;AACvE,MAAI,SAAS,KAAM,QAAO;AAC1B,QAAM,YAAY,IAAI,KAAK,KAAK;AAChC,SAAO,OAAO,MAAM,UAAU,QAAQ,CAAC,IAAI,OAAO;AACpD;AAEA,SAAS,iBACP,MACA,SAC6B;AAC7B,MAAI,SAAS,SAAS,UAAU,SAAS,SAAS,aAAa;AAC7D,WAAO,QAAQ;AAAA,EACjB;AAEA,MAAI,QAAQ,iBAAiB,IAAI,IAAI,GAAG;AACtC,WAAO;AAAA,EACT;AAEA,MAAI,QAAQ,sBAAsB,IAAI,IAAI,GAAG;AAC3C,WAAO;AAAA,EACT;AAEA,MAAI,MAAM,YAAY,EAAE,SAAS,WAAW,GAAG;AAC7C,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEA,SAAS,eAAe,YAAyC;AAC/D,QAAM,aAAa,oBAAI,IAAoB;AAC3C,QAAM,UAAU,aAAa,UAAU;AACvC,MAAI,CAAC,QAAS,QAAO;AAErB,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,OAAO;AAKjC,UAAM,aAAa,OAAO,cAAc,OAAO,YAAY,CAAC;AAC5D,eAAW,CAAC,MAAM,IAAI,KAAK,OAAO,QAAQ,UAAU,GAAG;AACrD,YAAM,YACJ,OAAO,SAAS,WAAW,OAAO,KAAK,QAAQ,KAAK,OAAO;AAC7D,UAAI,CAAC,UAAW;AAEhB,iBAAW,IAAI,MAAMD,aAAY,SAAS,CAAC;AAAA,IAC7C;AAAA,EACF,QAAQ;AAAA,EAER;AAEA,SAAO;AACT;AAEO,IAAM,iBAAN,MAAwC;AAAA,EACpC;AAAA,EACQ;AAAA,EACA;AAAA,EAEjB,YAAY,UAAiC,CAAC,GAAG;AAC/C,SAAK,cAAc,QAAQ,eAAe;AAC1C,SAAK,aAAa,QAAQ,cAAc;AACxC,SAAK,OAAOF,sBAAqB,KAAK,WAAW;AAAA,EACnD;AAAA,EAEA,MAAM,QAA8B;AAClC,UAAM,YAAY,cAAc,KAAK,WAAW;AAChD,QAAI,UAAU,WAAW,GAAG;AAC1B,aAAO,EAAE,SAAS,CAAC,GAAG,UAAU,CAAC,EAAE;AAAA,IACrC;AAEA,UAAM,aAAa,eAAe,KAAK,UAAU;AACjD,UAAM,UAA6B,CAAC;AACpC,UAAM,gBAAgC,CAAC;AACvC,UAAM,iBAAiB,oBAAI,IAAY;AAEvC,eAAW,EAAE,UAAU,YAAY,KAAK,WAAW;AACjD,YAAM,UAAU,aAAa,QAAQ;AACrC,UAAI,CAAC,QAAS;AAEd,YAAM,YAAY;AAClB,YAAM,UAAU,WAAW,IAAI,WAAW,KAAK;AAC/C,UAAI,eAAe;AACnB,UAAI;AAEJ,iBAAW,QAAQ,QAAQ,MAAM,IAAI,GAAG;AACtC,YAAI,CAAC,KAAK,KAAK,EAAG;AAElB,YAAI;AACJ,YAAI;AACF,gBAAM,KAAK,MAAM,IAAI;AAAA,QACvB,QAAQ;AACN;AAAA,QACF;AAEA,cAAM,UAAU,IAAI;AACpB,YAAI,CAAC,QAAS;AAEd,YAAI,QAAQ,OAAO;AACjB,yBAAe,QAAQ;AAAA,QACzB;AAEA,cAAM,iBACJ,QAAQ,aAAa,IAAI,aAAa;AACxC,cAAM,YAAY,eAAe,cAAc;AAC/C,YAAI,QAAQ,aAAa,MAAM;AAC7B,6BAAmB,QAAQ;AAAA,QAC7B,WAAW,IAAI,aAAa,MAAM;AAChC,6BAAmB,IAAI;AAAA,QACzB;AAEA,cAAM,OAAO,iBAAiB,IAAI,MAAM,OAAO;AAC/C,YAAI,QAAQ,WAAW;AACrB,wBAAc,KAAK;AAAA,YACjB;AAAA,YACA,QAAQJ;AAAA,YACR;AAAA,YACA;AAAA,YACA;AAAA,UACF,CAAC;AAAA,QACH;AAEA,YAAI,IAAI,SAAS,eAAgB;AAEjC,cAAM,aAAa,QAAQ;AAC3B,YAAI,CAAC,cAAc,CAAC,UAAW;AAE/B,cAAM,cAAcK,cAAa,WAAW,WAAW;AACvD,cAAM,eAAeA,cAAa,WAAW,MAAM;AACnD,cAAM,eAAeA,cAAa,WAAW,gBAAgB;AAC7D,cAAM,oBAAoBA,cAAa,WAAW,oBAAoB;AAEtE,YACE,gBAAgB,KAChB,iBAAiB,KACjB,iBAAiB,KACjB,sBAAsB,GACtB;AACA;AAAA,QACF;AAEA,YAAI,QAAQ,YAAY;AACtB,cAAI,eAAe,IAAI,QAAQ,UAAU,EAAG;AAC5C,yBAAe,IAAI,QAAQ,UAAU;AAAA,QACvC;AAEA,YAAI,CAAC,MAAM;AACT,wBAAc,KAAK;AAAA,YACjB;AAAA,YACA,QAAQL;AAAA,YACR;AAAA,YACA;AAAA,YACA,MAAM;AAAA,UACR,CAAC;AAAA,QACH;AAEA,gBAAQ,KAAK;AAAA,UACX;AAAA,UACA,QAAQA;AAAA,UACR,OAAO;AAAA,UACP;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,iBAAiB;AAAA,UACjB;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAEA,WAAO;AAAA,MACL,SAAS,mBAAmB,OAAO;AAAA,MACnC,UAAU,gBAAgB,eAAe,OAAO;AAAA,IAClD;AAAA,EACF;AAAA,EAEA,cAAuB;AACrB,WAAOO,YAAW,KAAK,WAAW;AAAA,EACpC;AACF;AAEA,eAAe,IAAI,eAAe,CAAC;;;AChSnC,SAAS,cAAAE,cAAY,eAAAC,oBAAmB;AACxC,SAAS,WAAAC,gBAAe;AACxB,SAAS,YAAAC,WAAU,WAAAC,UAAS,QAAAC,cAAY;AAYxC,IAAMC,WAAU;AAChB,IAAMC,aAAY;AAClB,IAAMC,oBAAmBC,OAAKC,SAAQ,GAAG,YAAY,UAAU;AAoB/D,SAASC,sBAAqB,SAAiC;AAC7D,SAAO;AAAA,IACL,IAAIL;AAAA,IACJ,MAAMC;AAAA,IACN;AAAA,EACF;AACF;AAEA,SAASK,kBAAiB,KAAuB;AAC/C,QAAM,UAAoB,CAAC;AAC3B,MAAI,CAACC,aAAW,GAAG,EAAG,QAAO;AAE7B,MAAI;AACF,eAAW,SAASC,aAAY,KAAK,EAAE,eAAe,KAAK,CAAC,GAAG;AAC7D,YAAM,WAAWL,OAAK,KAAK,MAAM,IAAI;AACrC,UAAI,MAAM,YAAY,GAAG;AACvB,gBAAQ,KAAK,GAAGG,kBAAiB,QAAQ,CAAC;AAAA,MAC5C,WACE,MAAM,OAAO,KACb,MAAM,KAAK,SAAS,QAAQ,KAC5B,CAAC,MAAM,KAAK,SAAS,gBAAgB,GACrC;AACA,gBAAQ,KAAK,QAAQ;AAAA,MACvB;AAAA,IACF;AAAA,EACF,QAAQ;AAAA,EAER;AAEA,SAAO;AACT;AAEO,SAAS,oBAAoB,MAAsB;AACxD,QAAM,QAAQ,KAAK,MAAM,GAAG,EAAE,OAAO,OAAO;AAC5C,SAAO,MAAM,SAAS,IAAI,MAAM,MAAM,SAAS,CAAC,IAAI;AACtD;AAEA,SAASG,cAAa,OAAwB;AAC5C,QAAM,cAAc,OAAO,KAAK;AAChC,SAAO,OAAO,SAAS,WAAW,IAAI,cAAc;AACtD;AAEO,IAAM,cAAN,MAAqC;AAAA,EAG1C,YAA6B,UAAUP,mBAAkB;AAA5B;AAC3B,SAAK,OAAOG,sBAAqB,OAAO;AAAA,EAC1C;AAAA,EAJS;AAAA,EAMT,MAAM,QAA8B;AAClC,UAAM,eAAeC,kBAAiB,KAAK,OAAO;AAClD,QAAI,aAAa,WAAW,GAAG;AAC7B,aAAO,EAAE,SAAS,CAAC,GAAG,UAAU,CAAC,EAAE;AAAA,IACrC;AAEA,UAAM,UAA6B,CAAC;AACpC,UAAM,gBAAgC,CAAC;AAEvC,eAAW,YAAY,cAAc;AACnC,YAAM,YAAY;AAClB,YAAM,UAAU,oBAAoBI,UAASC,SAAQ,QAAQ,CAAC,CAAC;AAC/D,UAAI,wBAAqC;AAEzC,YAAM,UAAU,aAAa,QAAQ;AACrC,UAAI,CAAC,QAAS;AAEd,iBAAW,QAAQ,QAAQ,MAAM,IAAI,GAAG;AACtC,YAAI,CAAC,KAAK,KAAK,EAAG;AAElB,YAAI;AACJ,YAAI;AACF,gBAAM,KAAK,MAAM,IAAI;AAAA,QACvB,QAAQ;AACN;AAAA,QACF;AAEA,YAAI,IAAI,SAAS,aAAa,CAAC,IAAI,UAAW;AAE9C,cAAM,YAAY,IAAI,KAAK,IAAI,SAAS;AACxC,YAAI,OAAO,MAAM,UAAU,QAAQ,CAAC,EAAG;AAEvC,cAAM,OAAO,IAAI,SAAS;AAC1B,YAAI,SAAS,UAAU,SAAS,YAAa;AAE7C,YAAI,0BAA0B,MAAM;AAClC,kCAAwB;AAAA,QAC1B;AAEA,sBAAc,KAAK;AAAA,UACjB;AAAA,UACA,QAAQX;AAAA,UACR;AAAA,UACA;AAAA,UACA;AAAA,QACF,CAAC;AAAA,MACH;AAEA,YAAM,eAAeG;AAAA,QACnBQ,SAAQ,QAAQ;AAAA,QAChB,GAAGD,UAAS,UAAU,QAAQ,CAAC;AAAA,MACjC;AACA,YAAM,kBAAkB,aAAa,YAAY;AACjD,UAAI,CAAC,mBAAmB,0BAA0B,KAAM;AAExD,UAAI;AACJ,UAAI;AACF,mBAAW,KAAK,MAAM,eAAe;AAAA,MACvC,QAAQ;AACN;AAAA,MACF;AAEA,YAAM,aAAa,SAAS;AAC5B,UAAI,CAAC,WAAY;AAEjB,YAAM,eAAeD,cAAa,WAAW,eAAe;AAC5D,YAAM,kBAAkBA,cAAa,WAAW,cAAc;AAC9D,YAAM,cAAc,KAAK;AAAA,QACvB;AAAA,QACAA,cAAa,WAAW,WAAW,IAAI;AAAA,MACzC;AACA,YAAM,eAAe,KAAK;AAAA,QACxB;AAAA,QACAA,cAAa,WAAW,YAAY,IAAI;AAAA,MAC1C;AAEA,UACE,gBAAgB,KAChB,iBAAiB,KACjB,iBAAiB,KACjB,oBAAoB,GACpB;AACA;AAAA,MACF;AAEA,cAAQ,KAAK;AAAA,QACX;AAAA,QACA,QAAQT;AAAA,QACR,OAAO,SAAS,SAAS;AAAA,QACzB;AAAA,QACA,WAAW;AAAA,QACX;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,MACL,SAAS,mBAAmB,OAAO;AAAA,MACnC,UAAU,gBAAgB,eAAe,OAAO;AAAA,IAClD;AAAA,EACF;AAAA,EAEA,cAAuB;AACrB,WAAOO,aAAW,KAAK,OAAO;AAAA,EAChC;AACF;AAEA,eAAe,IAAI,YAAY,CAAC;;;AClMhC,SAAS,cAAAK,oBAAkB;AAC3B,SAAS,WAAAC,iBAAe;AACxB,SAAS,QAAAC,cAAY;AAgBrB,IAAMC,WAAU;AAChB,IAAMC,aAAY;AAClB,IAAMC,wBAAuBC,OAAKC,UAAQ,GAAG,OAAO,SAAS,UAAU;AA4BvE,SAASC,sBAAqB,SAAiC;AAC7D,SAAO;AAAA,IACL,IAAIL;AAAA,IACJ,MAAMC;AAAA,IACN;AAAA,EACF;AACF;AAEA,SAASK,cAAa,OAAwB;AAC5C,QAAM,cAAc,OAAO,KAAK;AAChC,SAAO,OAAO,SAAS,WAAW,IAAI,cAAc;AACtD;AAEA,SAASC,aAAY,OAAuB;AAC1C,QAAM,aAAa,MAAM,QAAQ,OAAO,GAAG,EAAE,QAAQ,QAAQ,EAAE;AAC/D,QAAM,OAAO,WAAW,MAAM,GAAG,EAAE,OAAO,OAAO,EAAE,IAAI;AACvD,SAAO,QAAQ;AACjB;AAEA,SAASC,oBAAmB,OAAuB;AACjD,SAAO,MAAM,QAAQ,OAAO,GAAG,EAAE,QAAQ,QAAQ,EAAE;AACrD;AAEA,SAAS,eAAe,UAAmB,MAAoC;AAC7E,aAAW,OAAO,MAAM;AACtB,UAAM,QAAQ,MAAM,GAAG;AACvB,UAAM,cAAcF,cAAa,KAAK;AACtC,QAAI,cAAc,GAAG;AACnB,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,wBAAwB,KAAqB;AAC3D,SAAOC,aAAY,GAAG;AACxB;AAEO,SAAS,wBACd,UACA,cAAcL,uBACN;AACR,QAAM,qBAAqBM,oBAAmB,QAAQ;AACtD,QAAM,wBAAwBA,oBAAmB,WAAW;AAC5D,QAAM,SAAS,GAAG,qBAAqB;AAEvC,MAAI,CAAC,mBAAmB,WAAW,MAAM,GAAG;AAC1C,WAAO;AAAA,EACT;AAEA,QAAM,eAAe,mBAAmB,MAAM,OAAO,MAAM;AAC3D,QAAM,eAAe,aAAa,MAAM,GAAG,EAAE,CAAC;AAC9C,MAAI,CAAC,cAAc;AACjB,WAAO;AAAA,EACT;AAEA,MAAI;AACF,UAAM,UAAU,mBAAmB,YAAY;AAC/C,QAAI,QAAQ,SAAS,GAAG,KAAK,QAAQ,SAAS,IAAI,GAAG;AACnD,aAAOD,aAAY,OAAO;AAAA,IAC5B;AAAA,EACF,QAAQ;AAAA,EAER;AAEA,QAAM,YAAY,aAAa,MAAM,GAAG,EAAE,OAAO,OAAO;AACxD,SAAO,UAAU,SAAS,IAAI,UAAU,UAAU,SAAS,CAAC,IAAI;AAClE;AAEO,IAAM,sBAAN,MAA6C;AAAA,EAGlD,YAA6B,cAAcL,uBAAsB;AAApC;AAC3B,SAAK,OAAOG,sBAAqB,WAAW;AAAA,EAC9C;AAAA,EAJS;AAAA,EAMT,MAAM,QAA8B;AAClC,UAAM,eAAe,eAAe,KAAK,WAAW;AACpD,QAAI,aAAa,WAAW,GAAG;AAC7B,aAAO,EAAE,SAAS,CAAC,GAAG,UAAU,CAAC,EAAE;AAAA,IACrC;AAEA,UAAM,UAA6B,CAAC;AACpC,UAAM,gBAAgC,CAAC;AACvC,UAAM,eAAe,oBAAI,IAAY;AAErC,eAAW,YAAY,cAAc;AACnC,YAAM,UAAU,aAAa,QAAQ;AACrC,UAAI,CAAC,QAAS;AAEd,YAAM,OAAO,WAAoB,OAAO;AACxC,UAAI,KAAK,WAAW,EAAG;AAEvB,UAAI,YAAY;AAChB,UAAI,UAAU,wBAAwB,UAAU,KAAK,WAAW;AAEhE,iBAAW,OAAO,MAAM;AACtB,YAAI,IAAI,SAAS,UAAW;AAC5B,YAAI,IAAI,IAAI;AACV,sBAAY,IAAI;AAAA,QAClB;AACA,YAAI,IAAI,KAAK;AACX,oBAAU,wBAAwB,IAAI,GAAG;AAAA,QAC3C;AACA;AAAA,MACF;AAEA,iBAAW,OAAO,MAAM;AACtB,YAAI,IAAI,SAAS,UAAW;AAE5B,cAAM,UAAU,IAAI;AACpB,YAAI,CAAC,QAAS;AAEd,cAAM,eAAe,IAAI,aAAa,QAAQ;AAC9C,YAAI,CAAC,aAAc;AAEnB,cAAM,YAAY,IAAI,KAAK,YAAY;AACvC,YAAI,OAAO,MAAM,UAAU,QAAQ,CAAC,EAAG;AAEvC,YAAI,QAAQ,SAAS,UAAU,QAAQ,SAAS,aAAa;AAC3D,wBAAc,KAAK;AAAA,YACjB;AAAA,YACA,QAAQL;AAAA,YACR;AAAA,YACA;AAAA,YACA,MAAM,QAAQ;AAAA,UAChB,CAAC;AAAA,QACH;AAEA,YAAI,QAAQ,SAAS,YAAa;AAElC,cAAM,QAAQ,QAAQ;AACtB,YAAI,CAAC,MAAO;AAEZ,cAAM,cAAc,eAAe,OAAO,SAAS,aAAa;AAChE,cAAM,eAAe,eAAe,OAAO,UAAU,cAAc;AACnE,cAAM,eAAe;AAAA,UACnB;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AACA,cAAM,kBAAkB;AAAA,UACtB;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAEA,YACE,gBAAgB,KAChB,iBAAiB,KACjB,iBAAiB,KACjB,oBAAoB,GACpB;AACA;AAAA,QACF;AAEA,YAAI,IAAI,IAAI;AACV,cAAI,aAAa,IAAI,IAAI,EAAE,EAAG;AAC9B,uBAAa,IAAI,IAAI,EAAE;AAAA,QACzB;AAEA,gBAAQ,KAAK;AAAA,UACX;AAAA,UACA,QAAQA;AAAA,UACR,OAAO,QAAQ,SAAS;AAAA,UACxB;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAEA,WAAO;AAAA,MACL,SAAS,mBAAmB,OAAO;AAAA,MACnC,UAAU,gBAAgB,eAAe,OAAO;AAAA,IAClD;AAAA,EACF;AAAA,EAEA,cAAuB;AACrB,WAAOS,aAAW,KAAK,WAAW;AAAA,EACpC;AACF;AAEA,eAAe,IAAI,oBAAoB,CAAC;;;AC7OxC,SAAS,SAAS,cAAc;;;ACAhC,SAAS,kBAAkB;AAC3B;AAAA,EACE,cAAAC;AAAA,EACA;AAAA,EACA,gBAAAC;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,QAAAC,cAAY;;;ACRrB,SAAS,WAAAC,iBAAe;AACxB,SAAS,QAAAC,cAAY;AAQd,SAAS,gBAAwB;AACtC,SAAO,QAAQ,IAAI,mBAAmBA,OAAKD,UAAQ,GAAG,SAAS;AACjE;AAaO,SAAS,eAAuB;AACrC,SAAO,QAAQ,IAAI,kBAAkBE,OAAKC,UAAQ,GAAG,UAAU,OAAO;AACxE;AAMO,SAAS,gBAAwB;AACtC,SAAO,QAAQ,IAAI,mBAAmB,aAAa;AACrD;;;ADfA,IAAM,aAAaC,OAAK,cAAc,GAAG,YAAY;AACrD,IAAM,QAAQ,QAAQ,IAAI,oBAAoB;AAC9C,IAAM,cAAcA,OAAK,YAAY,QAAQ,oBAAoB,aAAa;AAE9E,IAAM,kBAAkB;AACxB,IAAM,oBAAoB;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEO,SAAS,gBAAwB;AACtC,SAAO;AACT;AAEO,SAAS,eAAuB;AACrC,SAAO;AACT;AAEO,SAAS,aAA4B;AAC1C,MAAI,CAACC,aAAW,WAAW,EAAG,QAAO;AACrC,MAAI;AACF,UAAM,MAAMC,cAAa,aAAa,OAAO;AAC7C,UAAM,SAAS,KAAK,MAAM,GAAG;AAE7B,QAAI,CAAC,OAAO,QAAQ;AAClB,aAAO,SAAS;AAAA,IAClB;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,WAAW,QAAsB;AAC/C,YAAU,YAAY,EAAE,WAAW,KAAK,CAAC;AACzC,gBAAc,aAAa,GAAG,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAAA,GAAM,OAAO;AAC5E;AAEO,SAAS,eAAqB;AACnC,MAAID,aAAW,WAAW,GAAG;AAC3B,eAAW,WAAW;AAAA,EACxB;AACF;AAEO,SAAS,oBAAoB,QAAwB;AAC1D,MAAI,OAAO,SAAU,QAAO,OAAO;AAEnC,QAAM,OAAO,WAAW;AACxB,aAAW,EAAE,GAAG,QAAQ,UAAU,KAAK,CAAC;AAExC,SAAO;AACT;AAEO,SAAS,eAAe,KAAsB;AACnD,SAAO,IAAI,WAAW,KAAK;AAC7B;AAEO,SAAS,iBAAiB,KAAsB;AACrD,SAAO,kBAAkB,SAAS,GAAG;AACvC;AAEO,SAAS,mBAA2B;AACzC,SAAO,QAAQ,IAAI,uBAAuB;AAC5C;;;AErFA,IAAM,WAAW,QAAQ,QAAQ,OAAO,SAAS,QAAQ,IAAI,aAAa,GAAG;AAE7E,SAAS,SAAS,MAAc,OAAuB;AACrD,MAAI,CAAC,SAAU,QAAO;AACtB,SAAO,QAAU,IAAI,IAAI,KAAK;AAChC;AAEO,SAAS,KAAK,OAAuB;AAC1C,SAAO,SAAS,KAAK,KAAK;AAC5B;AAEO,SAAS,IAAI,OAAuB;AACzC,SAAO,SAAS,KAAK,KAAK;AAC5B;AAEO,SAAS,KAAK,OAAuB;AAC1C,SAAO,SAAS,MAAM,KAAK;AAC7B;AAEO,SAAS,MAAM,OAAuB;AAC3C,SAAO,SAAS,MAAM,KAAK;AAC7B;AAEO,SAAS,OAAO,OAAuB;AAC5C,SAAO,SAAS,MAAM,KAAK;AAC7B;AAEO,SAAS,IAAI,OAAuB;AACzC,SAAO,SAAS,MAAM,KAAK;AAC7B;AAEO,SAAS,QAAQ,OAAuB;AAC7C,SAAO,SAAS,MAAM,KAAK;AAC7B;AAEO,SAAS,aAAa,OAAe,UAA2B;AACrE,QAAM,QAAQ,CAAC,GAAG,KAAK,QAAG,CAAC,IAAI,KAAK,KAAK,CAAC,EAAE;AAC5C,MAAI,UAAU;AACZ,UAAM,KAAK,IAAI,QAAQ,CAAC;AAAA,EAC1B;AACA,SAAO;AAAA,EAAK,MAAM,KAAK,IAAI,CAAC;AAC9B;AAEO,SAAS,cAAc,OAAuB;AACnD,SAAO;AAAA,EAAK,KAAK,KAAK,CAAC;AACzB;AAEO,SAAS,eAAe,OAAe,OAAuB;AACnE,SAAO,KAAK,IAAI,MAAM,OAAO,IAAI,GAAG,CAAC,CAAC,IAAI,KAAK;AACjD;AAEO,SAAS,aACd,OACA,OAAqD,WAC7C;AACR,QAAM,OACJ,SAAS,YACL,MAAM,QAAG,IACT,SAAS,YACP,OAAO,GAAG,IACV,SAAS,WACP,IAAI,QAAG,IACP,KAAK,QAAG;AAClB,SAAO,KAAK,IAAI,IAAI,KAAK;AAC3B;AAEO,SAAS,gBAAgB,MAAsB;AACpD,SAAO,IAAI,IAAI;AACjB;AAEO,SAAS,WAAW,OAAe,UAAU,GAAW;AAC7D,MAAI,CAAC,MAAO,QAAO;AACnB,MAAI,MAAM,UAAU,QAAS,QAAO;AACpC,SAAO,GAAG,MAAM,MAAM,GAAG,OAAO,CAAC;AACnC;AAWO,SAAS,kBACd,OACA,OAAqD,WAC7C;AACR,MAAI,SAAS,UAAW,QAAO,MAAM,KAAK;AAC1C,MAAI,SAAS,UAAW,QAAO,OAAO,KAAK;AAC3C,MAAI,SAAS,SAAU,QAAO,IAAI,KAAK;AACvC,SAAO,QAAQ,KAAK;AACtB;;;AC7FA;AAAA,EAEE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEA,SAAS,wBAAiC;AAC/C,SAAO,QAAQ,QAAQ,MAAM,SAAS,QAAQ,OAAO,KAAK;AAC5D;AAEA,eAAsB,cAAc,SAGf;AACnB,SAAO,QAAQ;AAAA,IACb,SAAS,QAAQ;AAAA,IACjB,SAAS,QAAQ;AAAA,EACnB,CAAC;AACH;AAEA,eAAsB,WAAW,SAIb;AAClB,SAAO,MAAM;AAAA,IACX,SAAS,QAAQ;AAAA,IACjB,SAAS,QAAQ;AAAA,IACjB,UAAU,QAAQ;AAAA,EACpB,CAAC;AACH;AAEA,eAAsB,eAAe,SAIjB;AAClB,SAAO,SAAS;AAAA,IACd,SAAS,QAAQ;AAAA,IACjB,MAAM,QAAQ,QAAQ;AAAA,IACtB,UAAU,QAAQ;AAAA,EACpB,CAAC;AACH;AAEA,eAAsB,aAAgB,SAGvB;AACb,SAAO,OAAO;AAAA,IACZ,SAAS,QAAQ;AAAA,IACjB,SAAS,CAAC,GAAG,QAAQ,OAAO;AAAA,IAC5B,UAAU,KAAK,IAAI,KAAK,IAAI,QAAQ,QAAQ,QAAQ,CAAC,GAAG,EAAE;AAAA,EAC5D,CAAC;AACH;;;ACrDA,IAAM,aAAuC;AAAA,EAC3C,OAAO;AAAA,EACP,MAAM;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AACT;AAEO,IAAM,SAAN,MAAa;AAAA,EACV;AAAA,EAER,YAAY,QAAkB,QAAQ;AACpC,SAAK,QAAQ;AAAA,EACf;AAAA,EAEA,SAAS,OAAuB;AAC9B,SAAK,QAAQ;AAAA,EACf;AAAA,EAEA,MAAM,KAAmB;AACvB,QAAI,WAAW,KAAK,KAAK,KAAK,WAAW,OAAO;AAC9C,cAAQ,OAAO,MAAM,WAAW,GAAG;AAAA,CAAI;AAAA,IACzC;AAAA,EACF;AAAA,EAEA,KAAK,KAAmB;AACtB,QAAI,WAAW,KAAK,KAAK,KAAK,WAAW,MAAM;AAC7C,cAAQ,OAAO,MAAM,GAAG,GAAG;AAAA,CAAI;AAAA,IACjC;AAAA,EACF;AAAA,EAEA,KAAK,KAAmB;AACtB,QAAI,WAAW,KAAK,KAAK,KAAK,WAAW,MAAM;AAC7C,cAAQ,OAAO,MAAM,SAAS,GAAG;AAAA,CAAI;AAAA,IACvC;AAAA,EACF;AAAA,EAEA,MAAM,KAAmB;AACvB,QAAI,WAAW,KAAK,KAAK,KAAK,WAAW,OAAO;AAC9C,cAAQ,OAAO,MAAM,UAAU,GAAG;AAAA,CAAI;AAAA,IACxC;AAAA,EACF;AAAA,EAEA,IAAI,KAAmB;AACrB,SAAK,KAAK,GAAG;AAAA,EACf;AACF;AAEO,IAAM,SAAS,IAAI,OAAO;;;AC3BjC,IAAM,aAAa,CAAC,UAAU,UAAU,gBAAgB,UAAU;AAKlE,SAAS,YAAY,OAAmC;AACtD,SAAO,iBAAiB,KAAK,KAAK,WAAW,SAAS,KAAkB;AAC1E;AAEA,SAAS,kBAAkB,KAAgB,OAAwB;AACjE,MAAI,UAAU,UAAa,UAAU,QAAQ,UAAU,IAAI;AACzD,WAAO;AAAA,EACT;AAEA,MAAI,QAAQ,UAAU;AACpB,WAAO,WAAW,OAAO,KAAK,CAAC;AAAA,EACjC;AAEA,MAAI,QAAQ,gBAAgB;AAC1B,UAAM,KAAK,OAAO,KAAK;AACvB,UAAM,UAAU,KAAK,MAAM,KAAK,GAAK;AACrC,WAAO,GAAG,OAAO,kBAAQ,EAAE;AAAA,EAC7B;AAEA,SAAO,OAAO,KAAK;AACrB;AAEA,eAAe,yBAAoD;AACjE,SAAO;AAAA,IACL,aAAa,4BAAQ,4GAAiC;AAAA,EACxD;AAEA,SAAO,aAA+B;AAAA,IACpC,SAAS;AAAA,IACT,SAAS;AAAA,MACP;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aAAa;AAAA,MACf;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aAAa;AAAA,MACf;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aAAa;AAAA,MACf;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAEA,eAAe,gBAAgB,SAAqC;AAClE,SAAO,aAAwB;AAAA,IAC7B;AAAA,IACA,SAAS;AAAA,MACP;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aAAa;AAAA,MACf;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aAAa;AAAA,MACf;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aAAa;AAAA,MACf;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aAAa;AAAA,MACf;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAEA,eAAe,wBACb,eACiB;AACjB,QAAM,SAAS,MAAM,aAAqB;AAAA,IACxC,SAAS;AAAA,IACT,SAAS;AAAA,MACP;AAAA,QACE,MAAM;AAAA,QACN,OAAO,OAAO,IAAI,GAAM;AAAA,QACxB,aAAa;AAAA,MACf;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO,OAAO,KAAK,GAAM;AAAA,QACzB,aAAa;AAAA,MACf;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO,OAAO,KAAK,GAAM;AAAA,QACzB,aAAa;AAAA,MACf;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO,OAAO,KAAK,GAAM;AAAA,QACzB,aAAa;AAAA,MACf;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aAAa;AAAA,MACf;AAAA,IACF;AAAA,EACF,CAAC;AAED,MAAI,WAAW,UAAU;AACvB,WAAO;AAAA,EACT;AAEA,SAAO,WAAW;AAAA,IAChB,SAAS;AAAA,IACT,cAAc,gBAAgB,OAAO,aAAa,IAAI;AAAA,IACtD,UAAU,CAAC,UAAU;AACnB,YAAM,SAAS,OAAO,SAAS,OAAO,EAAE;AACxC,UAAI,OAAO,MAAM,MAAM,KAAK,UAAU,GAAG;AACvC,eAAO;AAAA,MACT;AACA,aAAO;AAAA,IACT;AAAA,EACF,CAAC;AACH;AAEA,eAAe,kBACb,KACA,eACiB;AACjB,UAAQ,KAAK;AAAA,IACX,KAAK;AACH,aAAO,eAAe;AAAA,QACpB,SAAS;AAAA,QACT,UAAU,CAAC,UACT,eAAe,KAAK,KAAK;AAAA,MAC7B,CAAC;AAAA,IACH,KAAK;AACH,aAAO,WAAW;AAAA,QAChB,SAAS;AAAA,QACT,cACE,OAAO,kBAAkB,YAAY,cAAc,SAAS,IACxD,gBACA,iBAAiB;AAAA,QACvB,UAAU,CAAC,UAAU;AACnB,cAAI;AACF,kBAAM,MAAM,IAAI,IAAI,KAAK;AACzB,mBAAO,QAAQ,IAAI,YAAY,IAAI,IAAI,KAAK;AAAA,UAC9C,QAAQ;AACN,mBAAO;AAAA,UACT;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH,KAAK;AACH,aAAO;AAAA,QACL,OAAO,kBAAkB,WAAW,gBAAgB;AAAA,MACtD;AAAA,IACF,KAAK;AACH,aAAO,aAAqB;AAAA,QAC1B,SAAS;AAAA,QACT,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,OAAO;AAAA,YACP,aAAa;AAAA,UACf;AAAA,UACA;AAAA,YACE,MAAM;AAAA,YACN,OAAO;AAAA,YACP,aAAa;AAAA,UACf;AAAA,UACA;AAAA,YACE,MAAM;AAAA,YACN,OAAO;AAAA,YACP,aAAa;AAAA,UACf;AAAA,UACA;AAAA,YACE,MAAM;AAAA,YACN,OAAO;AAAA,YACP,aAAa;AAAA,UACf;AAAA,QACF;AAAA,MACF,CAAC;AAAA,EACL;AACF;AAEA,SAAS,kBAAwB;AAC/B,QAAM,SAAS,WAAW;AAE1B,MAAI,CAAC,QAAQ;AACX,WAAO,KAAK,aAAa,4BAAQ,oEAAa,CAAC;AAC/C,WAAO,KAAK,aAAa,2EAA8B,SAAS,CAAC;AACjE;AAAA,EACF;AAEA,SAAO,KAAK,aAAa,0BAAM,CAAC;AAChC,SAAO,KAAK,cAAc,0BAAM,CAAC;AACjC,SAAO,KAAK,eAAe,WAAW,WAAW,OAAO,UAAU,EAAE,CAAC,CAAC;AACtE,SAAO;AAAA,IACL,eAAe,oBAAU,OAAO,UAAU,2BAA2B;AAAA,EACvE;AACA,SAAO;AAAA,IACL;AAAA,MACE;AAAA,MACA,OAAO,eACH,GAAG,KAAK,MAAM,OAAO,eAAe,GAAK,CAAC,kBAAQ,OAAO,YAAY,SACrE;AAAA,IACN;AAAA,EACF;AACA,SAAO,KAAK,eAAe,4BAAQ,OAAO,YAAY,MAAM,CAAC;AAC7D,MAAI,OAAO,UAAU;AACnB,WAAO,KAAK,eAAe,mBAAS,WAAW,OAAO,UAAU,EAAE,CAAC,CAAC;AAAA,EACtE;AACF;AAEA,eAAsB,aAAa,MAA+B;AAChE,QAAM,cAAc,sBAAsB;AAC1C,MAAI,MAAM,KAAK,CAAC;AAEhB,MAAI,CAAC,KAAK;AACR,QAAI,CAAC,aAAa;AAChB,aAAO,MAAM,yCAAyC;AACtD,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,UAAM,MAAM,uBAAuB;AAAA,EACrC;AAEA,UAAQ,KAAK;AAAA,IACX,KAAK,OAAO;AACV,UAAI,MAAM,KAAK,CAAC;AAChB,UAAI,CAAC,KAAK;AACR,YAAI,CAAC,aAAa;AAChB,iBAAO,MAAM,oCAAoC;AACjD,kBAAQ,KAAK,CAAC;AAAA,QAChB;AACA,cAAM,MAAM,gBAAgB,8DAAY;AAAA,MAC1C;AAEA,UAAI,CAAC,YAAY,GAAG,GAAG;AACrB,eAAO,MAAM,uBAAuB,GAAG,EAAE;AACzC,eAAO,MAAM,eAAe,WAAW,KAAK,IAAI,CAAC,EAAE;AACnD,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAEA,YAAM,SAAS,WAAW;AAC1B,UAAI,CAAC,UAAU,EAAE,OAAO,SAAS;AAC/B,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAEA,YAAM,SAAS;AACf,cAAQ,IAAI,OAAO,GAAG,KAAK,EAAE;AAC7B;AAAA,IACF;AAAA,IACA,KAAK,OAAO;AACV,UAAI,MAAM,KAAK,CAAC;AAChB,UAAI,CAAC,KAAK;AACR,YAAI,CAAC,aAAa;AAChB,iBAAO,MAAM,4CAA4C;AACzD,kBAAQ,KAAK,CAAC;AAAA,QAChB;AACA,cAAM,MAAM,gBAAgB,8DAAY;AAAA,MAC1C;AAEA,UAAI,CAAC,YAAY,GAAG,GAAG;AACrB,eAAO,MAAM,uBAAuB,GAAG,EAAE;AACzC,eAAO,MAAM,eAAe,WAAW,KAAK,IAAI,CAAC,EAAE;AACnD,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAEA,YAAM,SAAS,WAAW,KAAK;AAAA,QAC7B,QAAQ;AAAA,QACR,QAAQ,iBAAiB;AAAA,MAC3B;AACA,YAAM,SAAS;AAEf,UAAI,QAAQ,KAAK,CAAC;AAClB,UAAI,UAAU,QAAW;AACvB,YAAI,CAAC,aAAa;AAChB,iBAAO,MAAM,4CAA4C;AACzD,kBAAQ,KAAK,CAAC;AAAA,QAChB;AACA,gBAAQ,MAAM,kBAAkB,KAAK,OAAO,GAAG,CAAC;AAAA,MAClD;AAEA,UAAI,aAA8B;AAClC,UAAI,QAAQ,YAAY,CAAC,eAAe,KAAK,GAAG;AAC9C,eAAO,MAAM,+BAA+B;AAC5C,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAEA,UAAI,QAAQ,UAAU;AACpB,YAAI;AACF,gBAAM,MAAM,IAAI,IAAI,KAAK;AACzB,uBAAa,IAAI,SAAS,EAAE,QAAQ,OAAO,EAAE;AAAA,QAC/C,QAAQ;AACN,iBAAO,MAAM,4BAA4B;AACzC,kBAAQ,KAAK,CAAC;AAAA,QAChB;AAAA,MACF;AAEA,UAAI,QAAQ,gBAAgB;AAC1B,qBAAa,OAAO,SAAS,OAAO,EAAE;AACtC,YAAI,OAAO,MAAM,UAAU,KAAK,cAAc,GAAG;AAC/C,iBAAO,MAAM,uDAAuD;AACpE,kBAAQ,KAAK,CAAC;AAAA,QAChB;AAAA,MACF;AAEA,aAAO,GAAG,IAAI;AACd,iBAAW,MAAM;AAEjB,UAAI,aAAa;AACf,eAAO,KAAK,aAAa,gCAAO,CAAC;AACjC,eAAO,KAAK,eAAe,KAAK,kBAAkB,KAAK,UAAU,CAAC,CAAC;AAAA,MACrE,OAAO;AACL,eAAO,KAAK,OAAO,GAAG,MAAM,UAAU,EAAE;AAAA,MAC1C;AACA;AAAA,IACF;AAAA,IACA,KAAK,QAAQ;AACX,UAAI,aAAa;AACf,wBAAgB;AAAA,MAClB,OAAO;AACL,cAAM,SAAS,WAAW;AAC1B,gBAAQ,IAAI,SAAS,KAAK,UAAU,QAAQ,MAAM,CAAC,IAAI,IAAI;AAAA,MAC7D;AACA;AAAA,IACF;AAAA,IACA;AACE,aAAO,MAAM,8BAA8B,OAAO,QAAQ,EAAE;AAC5D,aAAO,MAAM,yCAAyC;AACtD,cAAQ,KAAK,CAAC;AAAA,EAClB;AACF;;;AC1WA,SAAS,YAAAE,iBAAgB;;;ACAzB,SAAS,kBAAkB;AAEpB,SAAS,kBAAkBC,QAI/B;AACD,MAAIA,OAAM,SAAS,YAAY;AAC7B,WAAO,EAAE,YAAY,WAAW,cAAc,kBAAkB;AAAA,EAClE;AAEA,MAAIA,OAAM,SAAS,OAAO;AACxB,WAAO,EAAE,YAAYA,OAAM,SAAS,cAAcA,OAAM,QAAQ;AAAA,EAClE;AAEA,QAAM,aAAa,WAAW,UAAUA,OAAM,IAAI,EAC/C,OAAOA,OAAM,OAAO,EACpB,OAAO,KAAK,EACZ,MAAM,GAAG,EAAE;AAEd,SAAO;AAAA,IACL;AAAA,IACA,cAAc,WAAW,WAAW,MAAM,GAAG,CAAC,CAAC;AAAA,EACjD;AACF;;;ACxBA,SAAS,cAAAC,mBAAkB;AAO3B,IAAM,mBAAmB;AAEzB,SAAS,UAAU,OAAuB;AACxC,SAAOA,YAAW,QAAQ,EAAE,OAAO,KAAK,EAAE,OAAO,KAAK,EAAE,MAAM,GAAG,EAAE;AACrE;AAEA,SAAS,gBAAgB,QAAwB;AAC/C,SAAO,OAAO,QAAQ,QAAQ,EAAE;AAClC;AAkCO,SAAS,yBAAyBC,QAKjB;AACtB,SAAO;AAAA,IACL,YAAY,UAAUA,OAAM,MAAM;AAAA,IAClC,QAAQ,gBAAgBA,OAAM,MAAM;AAAA,IACpC,UAAUA,OAAM;AAAA,IAChB,qBAAqB,UAAUA,OAAM,SAAS,eAAe;AAAA,IAC7D,aAAaA,OAAM,SAAS;AAAA,EAC9B;AACF;AAEO,SAAS,mCACd,UACA,SAC6B;AAC7B,QAAM,UAAuC,CAAC;AAE9C,MACE,SAAS,WAAW,QAAQ,UAC5B,SAAS,eAAe,QAAQ,YAChC;AACA,YAAQ,KAAK,mBAAmB;AAAA,EAClC;AAEA,MAAI,SAAS,aAAa,QAAQ,UAAU;AAC1C,YAAQ,KAAK,WAAW;AAAA,EAC1B;AAEA,MACE,SAAS,gBAAgB,QAAQ,eACjC,SAAS,wBAAwB,QAAQ,qBACzC;AACA,YAAQ,KAAK,kBAAkB;AAAA,EACjC;AAEA,SAAO;AACT;AAEO,SAAS,2BAA2B,QAAmC;AAC5E,SAAO;AAAA,IACL,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,EACT,EAAE,KAAK,GAAG;AACZ;AAEO,SAAS,4BACd,SACQ;AACR,SAAO,CAAC,QAAQ,UAAU,QAAQ,QAAQ,QAAQ,WAAW,EAAE,KAAK,GAAG;AACzE;AAEA,SAAS,2BAA2B,QAAmC;AACrE,SAAO;AAAA,IACL,KAAK,UAAU;AAAA,MACb,cAAc,OAAO;AAAA,MACrB,UAAU,OAAO;AAAA,MACjB,aAAa,OAAO;AAAA,MACpB,cAAc,OAAO;AAAA,MACrB,cAAc,OAAO;AAAA,MACrB,iBAAiB,OAAO;AAAA,MACxB,aAAa,OAAO;AAAA,IACtB,CAAC;AAAA,EACH;AACF;AAEA,SAAS,4BAA4B,SAAwC;AAC3E,SAAO;AAAA,IACL,KAAK,UAAU;AAAA,MACb,eAAe,QAAQ;AAAA,MACvB,cAAc,QAAQ;AAAA,MACtB,iBAAiB,QAAQ;AAAA,MACzB,gBAAgB,QAAQ;AAAA,MACxB,UAAU,QAAQ;AAAA,MAClB,aAAa,QAAQ;AAAA,MACrB,eAAe,QAAQ;AAAA,MACvB,cAAc,QAAQ;AAAA,MACtB,aAAa,QAAQ;AAAA,MACrB,cAAc,QAAQ;AAAA,MACtB,cAAc,QAAQ;AAAA,MACtB,YAAY,QAAQ;AAAA,MACpB,cAAc,QAAQ;AAAA,MACtB,iBAAiB,QAAQ;AAAA,MACzB,aAAa,QAAQ;AAAA,MACrB,kBAAkB,QAAQ;AAAA,IAC5B,CAAC;AAAA,EACH;AACF;AAEA,SAAS,kBACP,OACA,QACA,SACwB;AACxB,QAAM,SAAiC,CAAC;AAExC,aAAW,QAAQ,OAAO;AACxB,WAAO,OAAO,IAAI,CAAC,IAAI,QAAQ,IAAI;AAAA,EACrC;AAEA,SAAO;AACT;AAEO,SAAS,qBAAqBA,QAKlB;AACjB,SAAO;AAAA,IACL,SAAS;AAAA,MACPA,OAAM;AAAA,MACN;AAAA,MACA;AAAA,IACF;AAAA,IACA,OAAOA,OAAM;AAAA,IACb,UAAU;AAAA,MACRA,OAAM;AAAA,MACN;AAAA,MACA;AAAA,IACF;AAAA,IACA,WAAWA,OAAM,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,IACrD,SAAS;AAAA,EACX;AACF;AAEA,SAAS,oBACP,UACA,SACQ;AACR,MAAI,UAAU;AAEd,aAAW,OAAO,OAAO,KAAK,QAAQ,GAAG;AACvC,QAAI,EAAE,OAAO,UAAU;AACrB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,mBAAmBA,QAMZ;AACrB,QAAM,eAAe,qBAAqB;AAAA,IACxC,SAASA,OAAM;AAAA,IACf,OAAOA,OAAM;AAAA,IACb,UAAUA,OAAM;AAAA,IAChB,WAAWA,OAAM;AAAA,EACnB,CAAC;AAED,QAAM,sBAAsBA,OAAM,WAC9B,mCAAmCA,OAAM,SAAS,OAAOA,OAAM,KAAK,IACpE,CAAC;AAEL,QAAM,kBACJA,OAAM,YAAY,oBAAoB,WAAW,IAC7CA,OAAM,SAAS,UACf,CAAC;AACP,QAAM,mBACJA,OAAM,YAAY,oBAAoB,WAAW,IAC7CA,OAAM,SAAS,WACf,CAAC;AAEP,QAAM,kBAAkBA,OAAM,QAAQ,OAAO,CAAC,WAAW;AACvD,UAAM,MAAM,2BAA2B,MAAM;AAC7C,WAAO,gBAAgB,GAAG,MAAM,aAAa,QAAQ,GAAG;AAAA,EAC1D,CAAC;AACD,QAAM,mBAAmBA,OAAM,SAAS,OAAO,CAAC,YAAY;AAC1D,UAAM,MAAM,4BAA4B,OAAO;AAC/C,WAAO,iBAAiB,GAAG,MAAM,aAAa,SAAS,GAAG;AAAA,EAC5D,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,gBAAgB,oBAAoB,iBAAiB,aAAa,OAAO;AAAA,IACzE,iBAAiB;AAAA,MACf;AAAA,MACA,aAAa;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,IACA,kBAAkBA,OAAM,QAAQ,SAAS,gBAAgB;AAAA,IACzD,mBAAmBA,OAAM,SAAS,SAAS,iBAAiB;AAAA,EAC9D;AACF;;;ACrPA,OAAO,UAAU;AACjB,OAAO,WAAW;AAClB,SAAS,OAAAC,YAAW;AASpB,IAAM,cAAc;AACpB,IAAM,gBAAgB;AACtB,IAAM,aAAa;AAEZ,SAAS,qBACd,QACA,SACA,UACQ;AACR,QAAM,UAAU;AAAA,IACd,eAAe;AAAA,IACf;AAAA,IACA;AAAA,IACA,UAAU,YAAY,CAAC;AAAA,EACzB;AAEA,SAAO,OAAO,WAAW,KAAK,UAAU,OAAO,CAAC;AAClD;AAEO,IAAM,YAAN,MAAgB;AAAA,EACrB,YACU,QACA,QACR;AAFQ;AACA;AAAA,EACP;AAAA;AAAA;AAAA;AAAA,EAKH,MAAM,OACJ,QACA,SACA,UACA,YACmD;AACnD,QAAI;AACJ,aAAS,UAAU,GAAG,UAAU,aAAa,WAAW;AACtD,UAAI;AACF,eAAO,MAAM,KAAK,WAAW,QAAQ,SAAS,UAAU,UAAU;AAAA,MACpE,SAAS,KAAK;AACZ,oBAAY;AACZ,cAAM,UAAU;AAEhB,YACE,QAAQ,YAAY,kBACnB,QAAQ,cACP,QAAQ,cAAc,OACtB,QAAQ,aAAa,KACvB;AACA,gBAAM;AAAA,QACR;AACA,YAAI,UAAU,cAAc,GAAG;AAC7B,gBAAM,QAAQ,gBAAgB,KAAK;AACnC,gBAAM,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,KAAK,CAAC;AAAA,QAC/C;AAAA,MACF;AAAA,IACF;AACA,UAAM;AAAA,EACR;AAAA,EAEQ,WACN,QACA,SACA,UACA,YACmD;AACnD,WAAO,IAAI,QAAQ,CAACC,UAAS,WAAW;AACtC,YAAM,MAAM,IAAID,KAAI,qBAAqB,KAAK,MAAM;AACpD,YAAM,OAAO,OAAO;AAAA,QAClB,KAAK,UAAU;AAAA,UACb,eAAe;AAAA,UACf;AAAA,UACA;AAAA,UACA,UAAU,YAAY,CAAC;AAAA,QACzB,CAAC;AAAA,MACH;AACA,YAAM,aAAa,KAAK;AACxB,YAAM,MAAM,IAAI,aAAa,WAAW,QAAQ;AAEhD,YAAM,MAAM,IAAI;AAAA,QACd;AAAA,QACA;AAAA,UACE,QAAQ;AAAA,UACR,SAAS;AAAA,UACT,SAAS;AAAA,YACP,gBAAgB;AAAA,YAChB,eAAe,UAAU,KAAK,MAAM;AAAA,YACpC,kBAAkB;AAAA,UACpB;AAAA,QACF;AAAA,QACA,CAAC,QAAQ;AACP,cAAI,OAAO;AACX,cAAI,GAAG,QAAQ,CAAC,UAAU;AACxB,oBAAQ;AAAA,UACV,CAAC;AACD,cAAI,GAAG,OAAO,MAAM;AAClB,gBAAI,IAAI,eAAe,KAAK;AAC1B,qBAAO,IAAI,MAAM,cAAc,CAAC;AAChC;AAAA,YACF;AACA,gBACE,CAAC,IAAI,cACL,IAAI,aAAa,OACjB,IAAI,cAAc,KAClB;AACA,oBAAM,MAAM,IAAI;AAAA,gBACd,QAAQ,IAAI,UAAU,KAAK,IAAI;AAAA,cACjC;AAGA,kBAAI,aAAa,IAAI;AACrB,qBAAO,GAAG;AACV;AAAA,YACF;AACA,gBAAI;AACF,oBAAM,WAAW,KAAK,MAAM,IAAI;AAChC,cAAAC,SAAQ;AAAA,gBACN,UAAU,SAAS,eAAe,SAAS;AAAA,gBAC3C,UAAU,SAAS,gBAAgB,SAAS;AAAA,cAC9C,CAAC;AAAA,YACH,QAAQ;AACN,qBAAO,IAAI,MAAM,0BAA0B,IAAI,EAAE,CAAC;AAAA,YACpD;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF;AAEA,UAAI,GAAG,SAAS,CAAC,QAAQ,OAAO,GAAG,CAAC;AACpC,UAAI,GAAG,WAAW,MAAM;AACtB,YAAI,QAAQ;AACZ,eAAO,IAAI,MAAM,yBAAyB,CAAC;AAAA,MAC7C,CAAC;AAGD,YAAM,QAAQ,KAAK;AACnB,UAAI,OAAO;AAEX,YAAM,YAAY,MAAM;AACtB,YAAI,KAAK;AACT,eAAO,MAAM,OAAO,YAAY;AAC9B,gBAAM,QAAQ,KAAK,SAAS,MAAM,OAAO,KAAK;AAC9C,kBAAQ,MAAM;AACd,cAAI,WAAY,YAAW,MAAM,UAAU;AAC3C,eAAK,IAAI,MAAM,KAAK;AAAA,QACtB;AACA,YAAI,OAAO,YAAY;AACrB,cAAI,KAAK,SAAS,SAAS;AAAA,QAC7B,OAAO;AACL,cAAI,IAAI;AAAA,QACV;AAAA,MACF;AAEA,gBAAU;AAAA,IACZ,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,gBAA6C;AACjD,WAAO,IAAI,QAAQ,CAACA,UAAS,WAAW;AACtC,YAAM,MAAM,IAAID,KAAI,uBAAuB,KAAK,MAAM;AACtD,YAAM,MAAM,IAAI,aAAa,WAAW,QAAQ;AAEhD,YAAM,MAAM,IAAI;AAAA,QACd;AAAA,QACA;AAAA,UACE,QAAQ;AAAA,UACR,SAAS;AAAA,UACT,SAAS;AAAA,YACP,eAAe,UAAU,KAAK,MAAM;AAAA,UACtC;AAAA,QACF;AAAA,QACA,CAAC,QAAQ;AACP,cAAI,OAAO;AACX,cAAI,GAAG,QAAQ,CAAC,UAAU;AACxB,oBAAQ;AAAA,UACV,CAAC;AACD,cAAI,GAAG,OAAO,MAAM;AAClB,gBAAI,IAAI,eAAe,KAAK;AAC1B,qBAAO,IAAI,MAAM,cAAc,CAAC;AAChC;AAAA,YACF;AACA,gBACE,CAAC,IAAI,cACL,IAAI,aAAa,OACjB,IAAI,cAAc,KAClB;AACA,cAAAC,SAAQ,IAAI;AACZ;AAAA,YACF;AACA,gBAAI;AACF,oBAAM,WAAW,KAAK,MAAM,IAAI;AAChC,kBACE,SAAS,kBAAkB,KAC3B,CAAC,SAAS,eACV,CAAC,SAAS,mBACV,CAAC,SAAS,UACV;AACA,gBAAAA,SAAQ,IAAI;AACZ;AAAA,cACF;AAEA,cAAAA,SAAQ,QAAQ;AAAA,YAClB,QAAQ;AACN,cAAAA,SAAQ,IAAI;AAAA,YACd;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF;AAEA,UAAI,GAAG,SAAS,MAAMA,SAAQ,IAAI,CAAC;AACnC,UAAI,GAAG,WAAW,MAAM;AACtB,YAAI,QAAQ;AACZ,QAAAA,SAAQ,IAAI;AAAA,MACd,CAAC;AACD,UAAI,IAAI;AAAA,IACV,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,cAAc,MAEa;AAC/B,WAAO,IAAI,QAAQ,CAACA,UAAS,WAAW;AACtC,YAAM,MAAM,IAAID,KAAI,qBAAqB,KAAK,MAAM;AACpD,UAAI,MAAM,UAAU;AAClB,YAAI,aAAa,IAAI,YAAY,KAAK,QAAQ;AAAA,MAChD;AACA,YAAM,MAAM,IAAI,aAAa,WAAW,QAAQ;AAEhD,YAAM,MAAM,IAAI;AAAA,QACd;AAAA,QACA;AAAA,UACE,QAAQ;AAAA,UACR,SAAS;AAAA,UACT,SAAS;AAAA,YACP,eAAe,UAAU,KAAK,MAAM;AAAA,UACtC;AAAA,QACF;AAAA,QACA,CAAC,QAAQ;AACP,cAAI,OAAO;AACX,cAAI,GAAG,QAAQ,CAAC,UAAU;AACxB,oBAAQ;AAAA,UACV,CAAC;AACD,cAAI,GAAG,OAAO,MAAM;AAClB,gBAAI,IAAI,eAAe,KAAK;AAC1B,qBAAO,IAAI,MAAM,cAAc,CAAC;AAChC;AAAA,YACF;AACA,gBACE,CAAC,IAAI,cACL,IAAI,aAAa,OACjB,IAAI,cAAc,KAClB;AACA,oBAAM,MAAM,IAAI;AAAA,gBACd,QAAQ,IAAI,UAAU,KAAK,IAAI;AAAA,cACjC;AAGA,kBAAI,aAAa,IAAI;AACrB,qBAAO,GAAG;AACV;AAAA,YACF;AACA,gBAAI;AACF,cAAAC,SAAQ,KAAK,MAAM,IAAI,CAAC;AAAA,YAC1B,QAAQ;AACN,qBAAO,IAAI,MAAM,0BAA0B,IAAI,EAAE,CAAC;AAAA,YACpD;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF;AAEA,UAAI,GAAG,SAAS,CAAC,QAAQ,OAAO,GAAG,CAAC;AACpC,UAAI,GAAG,WAAW,MAAM;AACtB,YAAI,QAAQ;AACZ,eAAO,IAAI,MAAM,yBAAyB,CAAC;AAAA,MAC7C,CAAC;AACD,UAAI,IAAI;AAAA,IACV,CAAC;AAAA,EACH;AACF;;;ACrSA;AAAA,EACE;AAAA,EACA,cAAAC;AAAA,EACA;AAAA,EACA,gBAAAC;AAAA,EACA;AAAA,EACA,iBAAAC;AAAA,OACK;;;ACPP,SAAS,aAAAC,kBAAiB;AAC1B,SAAS,QAAAC,cAAY;AAGrB,IAAM,WAAW;AAOV,SAAS,oBAA4B;AAC1C,SAAOC,OAAK,cAAc,GAAG,QAAQ;AACvC;AAEO,SAAS,cAAsB;AACpC,SAAOA,OAAK,aAAa,GAAG,QAAQ;AACtC;AAEO,SAAS,kBAA0B;AACxC,SAAOA,OAAK,kBAAkB,GAAG,WAAW;AAC9C;AAEO,SAAS,mBAA2B;AACzC,SAAOA,OAAK,YAAY,GAAG,aAAa;AAC1C;AAEO,SAAS,wBAAgC;AAC9C,SAAOA,OAAK,YAAY,GAAG,sBAAsB;AACnD;AAEO,SAAS,gBAAsB;AACpC,EAAAC,WAAU,kBAAkB,GAAG,EAAE,WAAW,KAAK,CAAC;AAClD,EAAAA,WAAU,YAAY,GAAG,EAAE,WAAW,KAAK,CAAC;AAC9C;;;ADbA,SAAS,eAAe,KAAsB;AAC5C,MAAI;AACF,YAAQ,KAAK,KAAK,CAAC;AACnB,WAAO;AAAA,EACT,SAAS,OAAO;AACd,UAAM,OAAQ,MAAgC;AAC9C,WAAO,SAAS;AAAA,EAClB;AACF;AAEA,SAAS,iBAAiB,UAAuC;AAC/D,MAAI,CAACC,aAAW,QAAQ,GAAG;AACzB,WAAO;AAAA,EACT;AAEA,MAAI;AACF,WAAO,KAAK,MAAMC,cAAa,UAAU,OAAO,CAAC;AAAA,EACnD,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,gBAAgB,UAAwB;AAC/C,QAAM,WAAW,iBAAiB,QAAQ;AAC1C,MAAI,CAAC,UAAU;AACb,WAAO,UAAU,EAAE,OAAO,KAAK,CAAC;AAChC;AAAA,EACF;AAEA,MAAI,CAAC,eAAe,SAAS,GAAG,GAAG;AACjC,WAAO,UAAU,EAAE,OAAO,KAAK,CAAC;AAAA,EAClC;AACF;AAEO,SAAS,mBAAmB,QAAqC;AACtE,gBAAc;AACd,QAAM,WAAW,gBAAgB;AAEjC,MAAI;AACF,UAAM,KAAK,SAAS,UAAU,IAAI;AAClC,UAAM,WAAyB;AAAA,MAC7B,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MAClC,KAAK,QAAQ;AAAA,MACb;AAAA,IACF;AACA,IAAAC,eAAc,IAAI,KAAK,UAAU,UAAU,MAAM,CAAC,CAAC;AACnD,cAAU,EAAE;AAEZ,WAAO;AAAA,MACL,UAAU;AACR,eAAO,UAAU,EAAE,OAAO,KAAK,CAAC;AAAA,MAClC;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,UAAM,OAAQ,MAAgC;AAC9C,QAAI,SAAS,UAAU;AACrB,YAAM;AAAA,IACR;AAAA,EACF;AAEA,kBAAgB,QAAQ;AAExB,MAAI;AACF,UAAM,KAAK,SAAS,UAAU,IAAI;AAClC,UAAM,WAAyB;AAAA,MAC7B,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MAClC,KAAK,QAAQ;AAAA,MACb;AAAA,IACF;AACA,IAAAA,eAAc,IAAI,KAAK,UAAU,UAAU,MAAM,CAAC,CAAC;AACnD,cAAU,EAAE;AAEZ,WAAO;AAAA,MACL,UAAU;AACR,eAAO,UAAU,EAAE,OAAO,KAAK,CAAC;AAAA,MAClC;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,UAAM,OAAQ,MAAgC;AAC9C,QAAI,SAAS,UAAU;AACrB,aAAO;AAAA,IACT;AACA,UAAM;AAAA,EACR;AACF;AAEO,SAAS,2BAA0C;AACxD,QAAM,WAAW,iBAAiB,gBAAgB,CAAC;AACnD,MAAI,CAAC,UAAU;AACb,WAAO;AAAA,EACT;AAEA,SAAO,OAAO,SAAS,GAAG,YAAY,SAAS,MAAM,eAAe,SAAS,SAAS;AACxF;;;AElHA,SAAS,cAAAC,cAAY,gBAAAC,eAAc,iBAAAC,sBAAqB;AA2BxD,SAAS,kBAA6B;AACpC,SAAO,EAAE,QAAQ,OAAO;AAC1B;AAEO,SAAS,gBAA2B;AACzC,QAAM,OAAO,iBAAiB;AAC9B,MAAI,CAACC,aAAW,IAAI,GAAG;AACrB,WAAO,gBAAgB;AAAA,EACzB;AAEA,MAAI;AACF,WAAO;AAAA,MACL,GAAG,gBAAgB;AAAA,MACnB,GAAI,KAAK,MAAMC,cAAa,MAAM,OAAO,CAAC;AAAA,IAC5C;AAAA,EACF,QAAQ;AACN,WAAO,gBAAgB;AAAA,EACzB;AACF;AAEO,SAAS,cAAc,MAAuB;AACnD,gBAAc;AACd,EAAAC;AAAA,IACE,iBAAiB;AAAA,IACjB,GAAG,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC;AAAA;AAAA,IAChC;AAAA,EACF;AACF;AAEO,SAAS,gBAAgB,QAA0B;AACxD,QAAM,UAAU,cAAc;AAC9B,gBAAc;AAAA,IACZ,GAAG;AAAA,IACH,KAAK,QAAQ;AAAA,IACb,gBAAe,oBAAI,KAAK,GAAE,YAAY;AAAA,IACtC,YAAY;AAAA,IACZ,QAAQ;AAAA,EACV,CAAC;AACH;AAEO,SAAS,kBACd,QACA,QACM;AACN,QAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,QAAM,UAAU,cAAc;AAC9B,gBAAc;AAAA,IACZ,GAAG;AAAA,IACH,iBAAiB;AAAA,IACjB,WAAW;AAAA,IACX,eAAe;AAAA,IACf,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,KAAK;AAAA,IACL,QAAQ;AAAA,EACV,CAAC;AACH;AAEO,SAAS,eACd,QACA,OACA,QACM;AACN,QAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,QAAM,UAAU,cAAc;AAC9B,gBAAc;AAAA,IACZ,GAAG;AAAA,IACH,iBAAiB;AAAA,IACjB,WAAW;AAAA,IACX,eAAe;AAAA,IACf,YAAY;AAAA,IACZ,KAAK;AAAA,IACL;AAAA,EACF,CAAC;AACH;;;ACtGA,SAAS,cAAAC,cAAY,gBAAAC,eAAc,iBAAAC,sBAAqB;AAIxD,SAAS,kBAAkB,OAAiD;AAC1E,MAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GAAG;AAC/D,WAAO;AAAA,EACT;AAEA,SAAO,OAAO,OAAO,KAAK,EAAE,MAAM,CAAC,UAAU,OAAO,UAAU,QAAQ;AACxE;AAEA,SAAS,iBAAiB,OAAyC;AACjE,MAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GAAG;AAC/D,WAAO;AAAA,EACT;AAEA,QAAM,WAAW;AAEjB,SACE,SAAS,YAAY,KACrB,CAAC,CAAC,SAAS,SACX,OAAO,SAAS,UAAU,YAC1B,OAAO,SAAS,MAAM,WAAW,YACjC,OAAO,SAAS,MAAM,eAAe,YACrC,OAAO,SAAS,MAAM,aAAa,YACnC,OAAO,SAAS,MAAM,gBAAgB,YACtC,OAAO,SAAS,MAAM,wBAAwB,YAC9C,OAAO,SAAS,cAAc,YAC9B,kBAAkB,SAAS,OAAO,KAClC,kBAAkB,SAAS,QAAQ;AAEvC;AAEO,SAAS,qBAA4C;AAC1D,QAAM,OAAO,sBAAsB;AACnC,MAAI,CAACC,aAAW,IAAI,GAAG;AACrB,WAAO;AAAA,EACT;AAEA,MAAI;AACF,UAAM,SAAS,KAAK,MAAMC,cAAa,MAAM,OAAO,CAAC;AACrD,WAAO,iBAAiB,MAAM,IAAI,SAAS;AAAA,EAC7C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,mBAAmB,UAAgC;AACjE,gBAAc;AACd,EAAAC;AAAA,IACE,sBAAsB;AAAA,IACtB,GAAG,KAAK,UAAU,UAAU,MAAM,CAAC,CAAC;AAAA;AAAA,IACpC;AAAA,EACF;AACF;;;AChCA,eAAsB,gBAA2C;AAC/D,QAAM,aAA4B,CAAC;AACnC,QAAM,cAAiC,CAAC;AACxC,QAAM,gBAAgC,CAAC;AAEvC,aAAW,UAAU,cAAc,GAAG;AACpC,QAAI;AACF,YAAM,SAAsB,MAAM,OAAO,MAAM;AAC/C,YAAM,UAAU,OAAO;AACvB,YAAM,WAAW,OAAO;AAExB,UAAI,QAAQ,SAAS,EAAG,YAAW,KAAK,GAAG,OAAO;AAClD,UAAI,SAAS,SAAS,EAAG,aAAY,KAAK,GAAG,QAAQ;AAErD,UAAI,QAAQ,SAAS,KAAK,SAAS,SAAS,GAAG;AAC7C,sBAAc,KAAK;AAAA,UACjB,QAAQ,OAAO,KAAK;AAAA,UACpB,SAAS,QAAQ;AAAA,UACjB,UAAU,SAAS;AAAA,QACrB,CAAC;AAAA,MACH;AAAA,IACF,SAAS,KAAK;AACZ,aAAO,KAAK,GAAG,OAAO,KAAK,EAAE,mBAAoB,IAAc,OAAO,EAAE;AAAA,IAC1E;AAAA,EACF;AAEA,SAAO,EAAE,SAAS,YAAY,UAAU,aAAa,cAAc;AACrE;AAKO,SAAS,mBAAmB;AACjC,SAAO,qBAAqB;AAC9B;;;ARnBA,IAAM,aAAa;AACnB,IAAM,qBAAqB;AAC3B,IAAM,qBAAqB;AAE3B,SAAS,YAAY,OAAuB;AAC1C,MAAI,QAAQ,KAAM,QAAO,GAAG,KAAK;AACjC,MAAI,QAAQ,OAAO,KAAM,QAAO,IAAI,QAAQ,MAAM,QAAQ,CAAC,CAAC;AAC5D,SAAO,IAAI,SAAS,OAAO,OAAO,QAAQ,CAAC,CAAC;AAC9C;AAEA,SAAS,kBAAkB,UAA0B;AACnD,QAAM,eAAe,KAAK,IAAI,GAAG,KAAK,IAAI,UAAU,CAAC,CAAC;AACtD,QAAM,SAAS,KAAK,MAAM,eAAe,kBAAkB;AAC3D,SAAO,GAAG,SAAI,OAAO,MAAM,CAAC,GAAG,SAAI,OAAO,qBAAqB,MAAM,CAAC;AACxE;AAEA,SAAS,oBACP,MACA,OACA,UACA,cACM;AACN,QAAM,MAAM,QAAQ,IAAI,KAAK,MAAO,OAAO,QAAS,GAAG,IAAI;AAC3D,QAAM,cAAc,kBAAkB,QAAQ,IAAI,OAAO,QAAQ,CAAC;AAClE,QAAM,aACJ,eAAe,IAAI,eAAY,QAAQ,IAAI,YAAY,KAAK;AAE9D,UAAQ,OAAO;AAAA,IACb,iBAAiB,WAAW,IAAI,OAAO,GAAG,EAAE,SAAS,GAAG,GAAG,CAAC,UAAO,YAAY,IAAI,CAAC,IAAI,YAAY,KAAK,CAAC,GAAG,UAAU;AAAA,EACzH;AACF;AAEA,SAAS,wBAAwB,QAA2C;AAC1E,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,EACX;AACF;AAEA,SAAS,sBAAsB,UAA0B,OAAsB;AAC7E,MAAI;AACF,uBAAmB,QAAQ;AAAA,EAC7B,SAAS,OAAO;AACd,QAAI,CAAC,OAAO;AACV,aAAO;AAAA,QACL,gEAAiE,MAAgB,OAAO;AAAA,MAC1F;AAAA,IACF;AAAA,EACF;AACF;AAcA,SAAS,iBAAiB,QAAgC;AACxD,SAAO;AAAA,IACL,UAAU,oBAAoB,MAAM;AAAA,IACpC,UAAUC,UAAS,EAAE,QAAQ,YAAY,EAAE;AAAA,EAC7C;AACF;AAEA,SAAS,gBACP,SACA,UACA,QACqB;AACrB,QAAM,aAAa,oBAAI,IAA+B;AAEtD,aAAW,UAAU,SAAS;AAC5B,UAAM,UAAU,kBAAkB;AAAA,MAChC,SAAS,OAAO,WAAW;AAAA,MAC3B,MAAM,SAAS;AAAA,MACf,MAAM,SAAS;AAAA,IACjB,CAAC;AACD,UAAM,MAAM;AAAA,MACV,OAAO;AAAA,MACP,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,OAAO;AAAA,IACT,EAAE,KAAK,GAAG;AAEV,UAAM,WAAW,WAAW,IAAI,GAAG;AACnC,QAAI,UAAU;AACZ,eAAS,eAAe,OAAO;AAC/B,eAAS,gBAAgB,OAAO;AAChC,eAAS,mBAAmB,OAAO,mBAAmB;AACtD,eAAS,gBAAgB,OAAO,gBAAgB;AAChD,eAAS,eAAe,OAAO;AAC/B;AAAA,IACF;AAEA,eAAW,IAAI,KAAK;AAAA,MAClB,QAAQ,OAAO;AAAA,MACf,OAAO,OAAO;AAAA,MACd,YAAY,QAAQ;AAAA,MACpB,cAAc,QAAQ;AAAA,MACtB,aAAa,OAAO;AAAA,MACpB,UAAU,OAAO;AAAA,MACjB,UAAU,OAAO;AAAA,MACjB,aAAa,OAAO;AAAA,MACpB,cAAc,OAAO;AAAA,MACrB,iBAAiB,OAAO,mBAAmB;AAAA,MAC3C,cAAc,OAAO,gBAAgB;AAAA,MACrC,aAAa,OAAO;AAAA,IACtB,CAAC;AAAA,EACH;AAEA,SAAO,MAAM,KAAK,WAAW,OAAO,CAAC;AACvC;AAEA,SAAS,iBACP,UACA,UACA,QACyB;AACzB,SAAO,SAAS,IAAI,CAAC,YAAY;AAC/B,UAAM,UAAU,kBAAkB;AAAA,MAChC,SAAS,QAAQ,WAAW;AAAA,MAC5B,MAAM,SAAS;AAAA,MACf,MAAM,SAAS;AAAA,IACjB,CAAC;AAED,WAAO;AAAA,MACL,QAAQ,QAAQ;AAAA,MAChB,YAAY,QAAQ;AAAA,MACpB,cAAc,QAAQ;AAAA,MACtB,aAAa,QAAQ;AAAA,MACrB,UAAU,OAAO;AAAA,MACjB,UAAU,OAAO;AAAA,MACjB,gBAAgB,QAAQ;AAAA,MACxB,eAAe,QAAQ;AAAA,MACvB,iBAAiB,QAAQ;AAAA,MACzB,eAAe,QAAQ;AAAA,MACvB,cAAc,QAAQ;AAAA,MACtB,kBAAkB,QAAQ;AAAA,MAC1B,aAAa,QAAQ;AAAA,MACrB,cAAc,QAAQ;AAAA,MACtB,iBAAiB,QAAQ;AAAA,MACzB,cAAc,QAAQ;AAAA,MACtB,aAAa,QAAQ;AAAA,MACrB,cAAc,QAAQ;AAAA,MACtB,aAAa,QAAQ;AAAA,IACvB;AAAA,EACF,CAAC;AACH;AAEA,IAAM,cAAN,cAA0B,MAAM;AAAA,EAC9B,YACE,SACS,MACA,YACT;AACA,UAAM,OAAO;AAHJ;AACA;AAAA,EAGX;AACF;AAEA,eAAsB,QACpB,QACA,OAAoB,CAAC,GACA;AACrB,QAAM,EAAE,QAAQ,OAAO,SAAS,UAAU,SAAS,MAAM,IAAI;AAE7D,QAAM,OAAO,mBAAmB,MAAM;AACtC,MAAI,CAAC,MAAM;AACT,UAAM,SAAS,yBAAyB;AACxC,UAAM,UAAU,SACZ,oCAAoC,MAAM,iBAC1C;AAEJ,mBAAe,QAAQ,SAAS,gBAAgB;AAChD,WAAO,KAAK,OAAO;AACnB,WAAO;AAAA,MACL,SAAS;AAAA,MACT,UAAU;AAAA,MACV,SAAS;AAAA,IACX;AAAA,EACF;AAEA,kBAAgB,MAAM;AAEtB,MAAI,gBAAgB;AACpB,MAAI,sBAAsB;AAC1B,MAAI,cAAkC;AAEtC,MAAI;AACF,UAAM;AAAA,MACJ,SAAS;AAAA,MACT,UAAU;AAAA,MACV;AAAA,IACF,IAAI,MAAM,cAAc;AAExB,QAAI,WAAW,WAAW,KAAK,YAAY,WAAW,GAAG;AACvD,UAAI,CAAC,OAAO;AACV,eAAO,KAAK,0BAA0B;AAAA,MACxC;AACA,wBAAkB,QAAQ,EAAE,SAAS,GAAG,UAAU,EAAE,CAAC;AACrD,aAAO,EAAE,SAAS,GAAG,UAAU,EAAE;AAAA,IACnC;AAEA,QAAI,CAAC,SAAS,cAAc,SAAS,GAAG;AACtC,iBAAW,KAAK,eAAe;AAC7B,cAAM,QAAkB,CAAC;AACzB,YAAI,EAAE,UAAU,EAAG,OAAM,KAAK,GAAG,EAAE,OAAO,UAAU;AACpD,YAAI,EAAE,WAAW,EAAG,OAAM,KAAK,GAAG,EAAE,QAAQ,WAAW;AACvD,eAAO,KAAK,KAAK,EAAE,MAAM,KAAK,MAAM,KAAK,IAAI,CAAC,EAAE;AAAA,MAClD;AAAA,IACF;AAEA,UAAM,SAAS,OAAO,UAAU;AAChC,UAAM,YAAY,IAAI,UAAU,QAAQ,OAAO,MAAM;AAErD,QAAI;AACJ,QAAI;AACF,iBAAW,MAAM,UAAU,cAAc;AAAA,IAC3C,SAAS,OAAO;AACd,UAAK,MAAgB,YAAY,gBAAgB;AAC/C,cAAM,IAAI;AAAA,UACR;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAEA,iBAAW;AAAA,IACb;AAEA,QAAI,CAAC,UAAU;AACb,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,UAAM,SAAS,iBAAiB,MAAM;AACtC,UAAM,gBAAgB,yBAAyB;AAAA,MAC7C,QAAQ,OAAO;AAAA,MACf;AAAA,MACA,UAAU,OAAO;AAAA,MACjB;AAAA,IACF,CAAC;AACD,UAAM,gBAAgB,gBAAgB,YAAY,UAAU,MAAM;AAClE,UAAM,iBAAiB,iBAAiB,aAAa,UAAU,MAAM;AACrE,UAAM,aAAa,mBAAmB;AAAA,MACpC,SAAS;AAAA,MACT,UAAU,mBAAmB;AAAA,MAC7B,OAAO;AAAA,MACP,UAAU;AAAA,IACZ,CAAC;AACD,UAAM,iBAAiB,WAAW;AAClC,UAAM,kBAAkB,WAAW;AAEnC,QAAI,CAAC,SAAS,WAAW,oBAAoB,SAAS,GAAG;AACvD,aAAO;AAAA,QACL,yBAAyB,WAAW,oBAAoB,IAAI,uBAAuB,EAAE,KAAK,IAAI,CAAC;AAAA,MACjG;AAAA,IACF;AAEA,QACE,CAAC,UACA,WAAW,iBAAiB,KAAK,WAAW,kBAAkB,IAC/D;AACA,YAAM,QAAkB,CAAC;AACzB,UAAI,WAAW,iBAAiB,GAAG;AACjC,cAAM,KAAK,GAAG,WAAW,cAAc,UAAU;AAAA,MACnD;AACA,UAAI,WAAW,kBAAkB,GAAG;AAClC,cAAM,KAAK,GAAG,WAAW,eAAe,WAAW;AAAA,MACrD;AACA,aAAO;AAAA,QACL,YAAY,MAAM,KAAK,KAAK,CAAC;AAAA,MAC/B;AAAA,IACF;AAEA,QAAI,eAAe,WAAW,KAAK,gBAAgB,WAAW,GAAG;AAC/D,UAAI,CAAC,OAAO;AACV,cAAM,eAAyB,CAAC;AAChC,YAAI,WAAW,mBAAmB,GAAG;AACnC,uBAAa,KAAK,GAAG,WAAW,gBAAgB,oBAAoB;AAAA,QACtE;AACA,YAAI,WAAW,oBAAoB,GAAG;AACpC,uBAAa;AAAA,YACX,GAAG,WAAW,iBAAiB;AAAA,UACjC;AAAA,QACF;AACA,eAAO;AAAA,UACL,aAAa,SAAS,IAClB,mDAAmD,aAAa,KAAK,KAAK,CAAC,MAC3E;AAAA,QACN;AAAA,MACF;AACA,4BAAsB,WAAW,cAAc,KAAK;AACpD,wBAAkB,QAAQ,EAAE,SAAS,GAAG,UAAU,EAAE,CAAC;AACrD,aAAO,EAAE,SAAS,GAAG,UAAU,EAAE;AAAA,IACnC;AAEA,UAAM,gBAAgB,KAAK,KAAK,eAAe,SAAS,UAAU;AAClE,UAAM,iBAAiB,KAAK;AAAA,MAC1B,gBAAgB,SAAS;AAAA,IAC3B;AACA,UAAM,eAAe,KAAK,IAAI,eAAe,gBAAgB,CAAC;AAC9D,UAAM,oBAAoB,MAAM;AAAA,MAC9B,EAAE,QAAQ,aAAa;AAAA,MACvB,CAAC,GAAG,aACF;AAAA,QACE;AAAA,QACA,eAAe;AAAA,UACb,WAAW;AAAA,WACV,WAAW,KAAK;AAAA,QACnB;AAAA,QACA,gBAAgB;AAAA,UACd,WAAW;AAAA,WACV,WAAW,KAAK;AAAA,QACnB;AAAA,MACF;AAAA,IACJ;AACA,UAAM,oBAAoB,kBAAkB;AAAA,MAC1C,CAAC,KAAK,SAAS,MAAM;AAAA,MACrB;AAAA,IACF;AACA,QAAI,2BAA2B;AAE/B,QAAI,CAAC,OAAO;AACV,YAAM,QAAkB,CAAC;AACzB,UAAI,eAAe,SAAS,GAAG;AAC7B,cAAM,KAAK,GAAG,eAAe,MAAM,UAAU;AAAA,MAC/C;AACA,UAAI,gBAAgB,SAAS,GAAG;AAC9B,cAAM,KAAK,GAAG,gBAAgB,MAAM,WAAW;AAAA,MACjD;AACA,YAAM,eAAyB,CAAC;AAChC,UAAI,WAAW,mBAAmB,GAAG;AACnC,qBAAa,KAAK,GAAG,WAAW,gBAAgB,oBAAoB;AAAA,MACtE;AACA,UAAI,WAAW,oBAAoB,GAAG;AACpC,qBAAa,KAAK,GAAG,WAAW,iBAAiB,qBAAqB;AAAA,MACxE;AACA,aAAO;AAAA,QACL,aAAa,MAAM,KAAK,KAAK,CAAC,KAAK,YAAY,SAAS,eAAe,IAAI,OAAO,EAAE,GAAG,aAAa,SAAS,IAAI,aAAa,aAAa,KAAK,KAAK,CAAC,KAAK,EAAE;AAAA,MAC/J;AAAA,IACF;AAEA,aAAS,WAAW,GAAG,WAAW,cAAc,YAAY;AAC1D,YAAM,QAAQ,eAAe;AAAA,QAC3B,WAAW;AAAA,SACV,WAAW,KAAK;AAAA,MACnB;AACA,YAAM,gBAAgB,gBAAgB;AAAA,QACpC,WAAW;AAAA,SACV,WAAW,KAAK;AAAA,MACnB;AACA,YAAM,WAAW,WAAW;AAE5B,YAAM,SAAS,MAAM,UAAU;AAAA,QAC7B;AAAA,QACA;AAAA,QACA,cAAc,SAAS,IAAI,gBAAgB;AAAA,QAC3C,QACI,SACA,CAAC,MAAM,UAAU;AACf;AAAA,YACE,2BAA2B;AAAA,YAC3B,qBAAqB;AAAA,YACrB;AAAA,YACA;AAAA,UACF;AAAA,QACF;AAAA,MACN;AAEA,uBAAiB,OAAO,YAAY,MAAM;AAC1C,6BAAuB,OAAO,YAAY,cAAc;AACxD,kCAA4B,kBAAkB,QAAQ,KAAK;AAAA,IAC7D;AAEA,QAAI,CAAC,UAAU,eAAe,KAAK,eAAe,SAAS,IAAI;AAC7D;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACA,cAAQ,OAAO,MAAM,IAAI;AAAA,IAC3B;AAEA,UAAM,YAAY,CAAC,GAAG,aAAa,UAAU;AAC7C,QAAI,sBAAsB,GAAG;AAC3B,gBAAU,KAAK,GAAG,mBAAmB,WAAW;AAAA,IAClD;AACA,WAAO,KAAK,UAAU,UAAU,KAAK,KAAK,CAAC,GAAG;AAE9C,QAAI,CAAC,OAAO;AACV,aAAO,KAAK;AAAA,0BAA6B,MAAM,QAAQ;AAAA,IACzD;AAEA,0BAAsB,WAAW,cAAc,KAAK;AACpD,sBAAkB,QAAQ;AAAA,MACxB,SAAS;AAAA,MACT,UAAU;AAAA,IACZ,CAAC;AAED,WAAO;AAAA,MACL,SAAS;AAAA,MACT,UAAU;AAAA,IACZ;AAAA,EACF,SAAS,OAAO;AACd,UAAM,UAAU;AAEhB,QAAI,QAAQ,YAAY,gBAAgB;AACtC,oBAAc,IAAI;AAAA,QAChB;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF,WAAW,iBAAiB,aAAa;AACvC,oBAAc;AAAA,IAChB,WAAW,gBAAgB,GAAG;AAC5B,oBAAc,IAAI;AAAA,QAChB,6BAA6B,aAAa,uBAAuB,QAAQ,OAAO;AAAA,QAChF;AAAA,QACA;AAAA,MACF;AAAA,IACF,OAAO;AACL,oBAAc,IAAI;AAAA,QAChB,gBAAgB,QAAQ,OAAO;AAAA,QAC/B;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,mBAAe,QAAQ,YAAY,SAAS,YAAY,IAAI;AAAA,EAC9D,UAAE;AACA,SAAK,QAAQ;AAAA,EACf;AAEA,MAAI,CAAC,aAAa;AAChB,WAAO;AAAA,MACL,SAAS;AAAA,MACT,UAAU;AAAA,IACZ;AAAA,EACF;AAEA,SAAO,MAAM,YAAY,OAAO;AAChC,MAAI,QAAQ;AACV,UAAM,YAAY,cAAc;AAAA,EAClC;AACA,UAAQ,KAAK,CAAC;AAChB;;;ASjfA,SAAS,gBAAAC,eAAc,aAAa;AACpC,SAAS,cAAAC,oBAAkB;AAC3B,SAAS,YAAY,OAAO,gBAAgB;AAC5C,SAAS,WAAAC,WAAS,YAAAC,iBAAgB;AAClC,SAAS,WAAAC,UAAS,QAAAC,QAAM,OAAO,aAAa;;;ACJ5C,SAAS,YAAAC,iBAAgB;;;ACAzB,SAAS,gBAAAC,qBAAoB;AAC7B,SAAS,cAAAC,cAAY,aAAAC,YAAW,UAAAC,SAAQ,iBAAAC,sBAAqB;AAC7D,SAAS,WAAAC,WAAS,gBAAgB;AAClC,SAAS,QAAAC,cAAY;;;ACHrB,SAAS,gBAAgB;AAalB,SAAS,mBAAmB,SAA0B;AAC3D,MAAI;AACF,aAAS,cAAc,OAAO,IAAI,EAAE,OAAO,SAAS,CAAC;AACrD,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;ACpBA,IAAM,yBAAyB;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAM,mBAAmB;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAOA,SAAS,YAAY,OAA2B;AAC9C,SAAO,CAAC,GAAG,IAAI,IAAI,MAAM,OAAO,OAAO,CAAC,CAAC;AAC3C;AAEO,SAAS,6BACd,MAAyB,QAAQ,KACT;AACxB,QAAM,cAAc,YAAY;AAAA,IAC9B,GAAI,IAAI,MAAM,MAAM,GAAG,KAAK,CAAC;AAAA,IAC7B,GAAG;AAAA,EACL,CAAC;AACD,QAAM,OAA+B;AAAA,IACnC,MAAM,YAAY,KAAK,GAAG;AAAA,EAC5B;AAEA,aAAW,OAAO,kBAAkB;AAClC,UAAM,QAAQ,IAAI,GAAG;AACrB,QAAI,OAAO;AACT,WAAK,GAAG,IAAI;AAAA,IACd;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,4BACd,WAAW,QAAQ,UACnB,OAAO,QAAQ,MACO;AACtB,QAAM,aAAa,KAAK,CAAC;AACzB,MAAI,CAAC,YAAY;AACf,UAAM,IAAI,MAAM,qIAAsC;AAAA,EACxD;AAEA,SAAO;AAAA,IACL;AAAA,IACA,MAAM,CAAC,YAAY,UAAU,WAAW;AAAA,EAC1C;AACF;AAEO,SAAS,wBAAwB,OAAuB;AAC7D,SAAO,MAAM,WAAW,MAAM,MAAM,EAAE,WAAW,KAAK,KAAK;AAC7D;AAEO,SAAS,UAAU,OAAuB;AAC/C,SAAO,MACJ,WAAW,KAAK,OAAO,EACvB,WAAW,KAAK,MAAM,EACtB,WAAW,KAAK,MAAM,EACtB,WAAW,KAAK,QAAQ,EACxB,WAAW,KAAK,QAAQ;AAC7B;;;AFpDA,IAAM,uBAAuB;AAQtB,SAAS,0BAA0B,WAAWC,UAAQ,GAAW;AACtE,SAAOC,OAAK,UAAU,sBAAsB;AAC9C;AAEO,SAAS,2BAA2B,WAAWD,UAAQ,GAAW;AACvE,SAAOC;AAAA,IACL,0BAA0B,QAAQ;AAAA,IAClC,GAAG,oBAAoB;AAAA,EACzB;AACF;AAEO,SAAS,2BACd,SACQ;AACR,QAAM,WAAW,OAAO,QAAQ,QAAQ,WAAW,EAChD;AAAA,IACC,CAAC,CAAC,KAAK,KAAK,MACV,gBAAgB,wBAAwB,GAAG,CAAC,IAAI,wBAAwB,KAAK,CAAC;AAAA,EAClF,EACC,KAAK,IAAI;AACZ,QAAM,WAAW,CAAC,QAAQ,UAAU,GAAG,QAAQ,IAAI,EAChD,IAAI,CAAC,UAAU,IAAI,wBAAwB,KAAK,CAAC,GAAG,EACpD,KAAK,GAAG;AAEX,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAOG,QAAQ;AAAA;AAAA;AAAA,EAGlB,QAAQ;AAAA;AAAA;AAAA;AAAA;AAKV;AAEA,SAAS,oBAAoC;AAC3C,MAAI,SAAS,MAAM,SAAS;AAC1B,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,QAAQ;AAAA,IACV;AAAA,EACF;AAEA,MAAI,CAAC,mBAAmB,WAAW,GAAG;AACpC,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,QAAQ;AAAA,IACV;AAAA,EACF;AAEA,SAAO,EAAE,IAAI,KAAK;AACpB;AAEA,SAAS,cAAc,MAAsB;AAC3C,EAAAC,cAAa,aAAa,CAAC,UAAU,GAAG,IAAI,GAAG;AAAA,IAC7C,OAAO;AAAA,EACT,CAAC;AACH;AAEA,SAAS,yBAAkC;AACzC,QAAM,UAAU,kBAAkB;AAClC,MAAI,QAAQ,IAAI;AACd,WAAO;AAAA,EACT;AAEA,SAAO,KAAK,aAAa,mCAAe,QAAQ,MAAM,IAAI,SAAS,CAAC;AACpE,SAAO;AACT;AAEO,SAAS,mCAAmD;AACjE,WAAS,cAAuB;AAC9B,WAAOC,aAAW,2BAA2B,CAAC;AAAA,EAChD;AAEA,iBAAe,MAAM,aAAa,OAAsB;AACtD,QAAI,CAAC,uBAAuB,GAAG;AAC7B;AAAA,IACF;AAEA,UAAM,aAAa,0BAA0B;AAC7C,UAAM,cAAc,2BAA2B;AAE/C,WAAO,KAAK,aAAa,qCAAiB,mBAAmB,CAAC;AAE9D,QAAI,CAAC,YAAY;AACf,YAAM,cAAc,MAAM,cAAc;AAAA,QACtC,SAAS;AAAA,QACT,cAAc;AAAA,MAChB,CAAC;AAED,UAAI,CAAC,aAAa;AAChB,eAAO,KAAK,aAAa,kDAAU,CAAC;AACpC;AAAA,MACF;AAAA,IACF;AAEA,QAAI;AACF,YAAM,UAAU,4BAA4B;AAC5C,YAAM,UAAU,2BAA2B;AAAA,QACzC,aAAa,6BAA6B;AAAA,QAC1C,UAAU,QAAQ;AAAA,QAClB,MAAM,QAAQ;AAAA,MAChB,CAAC;AAED,MAAAC,WAAU,YAAY,EAAE,WAAW,KAAK,CAAC;AACzC,MAAAC,eAAc,aAAa,SAAS,OAAO;AAE3C,oBAAc,CAAC,eAAe,CAAC;AAC/B,oBAAc,CAAC,UAAU,oBAAoB,CAAC;AAC9C,oBAAc,CAAC,SAAS,oBAAoB,CAAC;AAE7C,aAAO,KAAK,cAAc,gCAAO,CAAC;AAClC,aAAO,KAAK,aAAa,6BAAS,WAAW,IAAI,SAAS,CAAC;AAC3D,aAAO,KAAK,aAAa,oDAAY,SAAS,CAAC;AAC/C,aAAO;AAAA,QACL,eAAe,4BAAQ,oCAAoC;AAAA,MAC7D;AAAA,IACF,SAAS,KAAK;AACZ,aAAO,MAAM,yCAAY,IAAc,OAAO,EAAE;AAChD,YAAM;AAAA,IACR;AAAA,EACF;AAEA,iBAAe,QAAuB;AACpC,QAAI,CAAC,uBAAuB,GAAG;AAC7B;AAAA,IACF;AAEA,QAAI,CAAC,YAAY,GAAG;AAClB,aAAO;AAAA,QACL;AAAA,UACE;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA;AAAA,IACF;AAEA,QAAI;AACF,oBAAc,CAAC,SAAS,oBAAoB,CAAC;AAC7C,aAAO,KAAK,aAAa,kCAAS,SAAS,CAAC;AAAA,IAC9C,SAAS,KAAK;AACZ,aAAO,MAAM,yCAAY,IAAc,OAAO,EAAE;AAChD,YAAM;AAAA,IACR;AAAA,EACF;AAEA,iBAAe,OAAsB;AACnC,QAAI,CAAC,uBAAuB,GAAG;AAC7B;AAAA,IACF;AAEA,QAAI,CAAC,YAAY,GAAG;AAClB,aAAO;AAAA,QACL;AAAA,UACE;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA;AAAA,IACF;AAEA,QAAI;AACF,oBAAc,CAAC,QAAQ,oBAAoB,CAAC;AAC5C,aAAO,KAAK,aAAa,kCAAS,SAAS,CAAC;AAAA,IAC9C,SAAS,KAAK;AACZ,aAAO,MAAM,yCAAY,IAAc,OAAO,EAAE;AAChD,YAAM;AAAA,IACR;AAAA,EACF;AAEA,iBAAe,UAAyB;AACtC,QAAI,CAAC,uBAAuB,GAAG;AAC7B;AAAA,IACF;AAEA,QAAI,CAAC,YAAY,GAAG;AAClB,aAAO;AAAA,QACL;AAAA,UACE;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA;AAAA,IACF;AAEA,QAAI;AACF,oBAAc,CAAC,WAAW,oBAAoB,CAAC;AAC/C,aAAO,KAAK,aAAa,kCAAS,SAAS,CAAC;AAAA,IAC9C,SAAS,KAAK;AACZ,aAAO,MAAM,yCAAY,IAAc,OAAO,EAAE;AAChD,YAAM;AAAA,IACR;AAAA,EACF;AAEA,iBAAe,SAAwB;AACrC,QAAI,CAAC,uBAAuB,GAAG;AAC7B;AAAA,IACF;AAEA,QAAI,CAAC,YAAY,GAAG;AAClB,aAAO;AAAA,QACL;AAAA,UACE;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA;AAAA,IACF;AAEA,QAAI;AACF,oBAAc,CAAC,UAAU,oBAAoB,CAAC;AAAA,IAChD,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,iBAAe,UAAU,aAAa,OAAsB;AAC1D,UAAM,cAAc,2BAA2B;AAC/C,QAAI,CAACF,aAAW,WAAW,GAAG;AAC5B,aAAO,KAAK,aAAa,oDAAY,SAAS,CAAC;AAC/C;AAAA,IACF;AAEA,QAAI,CAAC,YAAY;AACf,YAAM,kBAAkB,MAAM,cAAc;AAAA,QAC1C,SAAS;AAAA,QACT,cAAc;AAAA,MAChB,CAAC;AAED,UAAI,CAAC,iBAAiB;AACpB,eAAO,KAAK,aAAa,sCAAQ,CAAC;AAClC;AAAA,MACF;AAAA,IACF;AAEA,UAAM,UAAU,kBAAkB;AAClC,QAAI,QAAQ,IAAI;AACd,UAAI;AACF,sBAAc,CAAC,QAAQ,oBAAoB,CAAC;AAAA,MAC9C,QAAQ;AAAA,MAER;AAEA,UAAI;AACF,sBAAc,CAAC,WAAW,oBAAoB,CAAC;AAAA,MACjD,QAAQ;AAAA,MAER;AAAA,IACF,OAAO;AACL,aAAO;AAAA,QACL;AAAA,UACE,2GAA2B,QAAQ,MAAM;AAAA,UACzC;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,QAAI;AACF,MAAAG,QAAO,WAAW;AAClB,UAAI,QAAQ,IAAI;AACd,sBAAc,CAAC,eAAe,CAAC;AAAA,MACjC;AAEA,aAAO,KAAK,cAAc,gCAAO,CAAC;AAClC,aAAO,KAAK,aAAa,oDAAY,SAAS,CAAC;AAAA,IACjD,SAAS,KAAK;AACZ,aAAO,MAAM,yCAAY,IAAc,OAAO,EAAE;AAChD,YAAM;AAAA,IACR;AAAA,EACF;AAEA,SAAO;AAAA,IACL,aAAa;AAAA,IACb,UAAU;AAAA,IACV;AAAA,IACA,mBAAmB;AAAA,IACnB,eAAe,MAAM;AAAA,IACrB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;AG/TA,SAAS,gBAAAC,qBAAoB;AAC7B,SAAS,cAAAC,cAAY,aAAAC,YAAW,UAAAC,SAAQ,iBAAAC,sBAAqB;AAC7D,SAAS,WAAAC,WAAS,YAAAC,iBAAgB;AAClC,SAAS,QAAAC,cAAY;AAkBd,IAAM,sBAAsB;AAWnC,SAAS,gBAA+B;AACtC,SAAO,OAAO,QAAQ,WAAW,aAAa,QAAQ,OAAO,IAAI;AACnE;AAEO,SAAS,uBAAuB,WAAWC,UAAQ,GAAW;AACnE,SAAOC,OAAK,UAAU,sBAAsB;AAC9C;AAEO,SAAS,wBAAwB,WAAWD,UAAQ,GAAW;AACpE,SAAOC,OAAK,uBAAuB,QAAQ,GAAG,GAAG,mBAAmB,QAAQ;AAC9E;AAEO,SAAS,sBAAsB,MAAM,cAAc,GAAW;AACnE,MAAI,OAAO,MAAM;AACf,UAAM,IAAI,MAAM,4DAAe;AAAA,EACjC;AAEA,SAAO,OAAO,GAAG;AACnB;AAEO,SAAS,6BAA6B,MAAM,cAAc,GAAW;AAC1E,SAAO,GAAG,sBAAsB,GAAG,CAAC,IAAI,mBAAmB;AAC7D;AAEO,SAAS,wBAAwB,WAAW,YAAY,GAG7D;AACA,SAAO;AAAA,IACL,YAAYA,OAAK,UAAU,oBAAoB;AAAA,IAC/C,YAAYA,OAAK,UAAU,oBAAoB;AAAA,EACjD;AACF;AAEA,SAAS,iBAAiB,QAA0B;AAClD,SAAO,OACJ,IAAI,CAAC,UAAU,iBAAiB,UAAU,KAAK,CAAC,WAAW,EAC3D,KAAK,IAAI;AACd;AAEA,SAAS,gBAAgB,SAAyC;AAChE,SAAO,OAAO,QAAQ,OAAO,EAC1B;AAAA,IACC,CAAC,CAAC,KAAK,KAAK,MACV,cAAc,UAAU,GAAG,CAAC;AAAA,gBAAyB,UAAU,KAAK,CAAC;AAAA,EACzE,EACC,KAAK,IAAI;AACd;AAEO,SAAS,kBAAkB,SAAsC;AACtE,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA,cAKK,UAAU,QAAQ,KAAK,CAAC;AAAA;AAAA;AAAA,EAGpC,iBAAiB,QAAQ,gBAAgB,CAAC;AAAA;AAAA;AAAA,cAG9B,UAAU,QAAQ,gBAAgB,CAAC;AAAA;AAAA;AAAA,EAG/C,gBAAgB,QAAQ,WAAW,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,cAcxB,UAAU,QAAQ,eAAe,CAAC;AAAA;AAAA,cAElC,UAAU,QAAQ,iBAAiB,CAAC;AAAA;AAAA;AAAA;AAIlD;AAEA,SAAS,sBAAsC;AAC7C,MAAIC,UAAS,MAAM,UAAU;AAC3B,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,QAAQ;AAAA,IACV;AAAA,EACF;AAEA,MAAI,CAAC,mBAAmB,WAAW,GAAG;AACpC,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,QAAQ;AAAA,IACV;AAAA,EACF;AAEA,QAAM,MAAM,cAAc;AAC1B,MAAI,OAAO,MAAM;AACf,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,QAAQ;AAAA,IACV;AAAA,EACF;AAEA,MAAI;AACF,IAAAC,cAAa,aAAa,CAAC,SAAS,sBAAsB,GAAG,CAAC,GAAG;AAAA,MAC/D,OAAO;AAAA,IACT,CAAC;AACD,WAAO,EAAE,IAAI,KAAK;AAAA,EACpB,QAAQ;AACN,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,QAAQ;AAAA,IACV;AAAA,EACF;AACF;AAEA,SAAS,cAAc,MAAgB,UAAU,MAAY;AAC3D,EAAAA,cAAa,aAAa,MAAM;AAAA,IAC9B,OAAO,UAAU,YAAY;AAAA,EAC/B,CAAC;AACH;AAEA,SAAS,WAAoB;AAC3B,MAAI;AACF,kBAAc,CAAC,SAAS,6BAA6B,CAAC,GAAG,KAAK;AAC9D,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,2BAAoC;AAC3C,QAAM,UAAU,oBAAoB;AACpC,MAAI,QAAQ,IAAI;AACd,WAAO;AAAA,EACT;AAEA,SAAO,KAAK,aAAa,mCAAe,QAAQ,MAAM,IAAI,SAAS,CAAC;AACpE,SAAO;AACT;AAEA,SAAS,wBAAgC;AACvC,QAAM,YAAY,wBAAwB;AAC1C,QAAM,EAAE,YAAY,WAAW,IAAI,wBAAwB;AAC3D,QAAM,UAAU,4BAA4B;AAC5C,QAAM,QAAQ,kBAAkB;AAAA,IAC9B,OAAO;AAAA,IACP,kBAAkB,CAAC,QAAQ,UAAU,GAAG,QAAQ,IAAI;AAAA,IACpD,aAAa,6BAA6B;AAAA,IAC1C,kBAAkBH,UAAQ;AAAA,IAC1B,iBAAiB;AAAA,IACjB,mBAAmB;AAAA,EACrB,CAAC;AAED,gBAAc;AACd,EAAAI,WAAU,uBAAuB,GAAG,EAAE,WAAW,KAAK,CAAC;AACvD,EAAAC,eAAc,WAAW,OAAO,OAAO;AAEvC,SAAO;AACT;AAEA,SAAS,uBAA6B;AACpC,QAAM,SAAS,sBAAsB;AACrC,QAAM,gBAAgB,6BAA6B;AACnD,QAAM,YAAY,wBAAwB;AAE1C,MAAI,SAAS,GAAG;AACd,QAAI;AACF,oBAAc,CAAC,WAAW,aAAa,CAAC;AAAA,IAC1C,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,gBAAc,CAAC,aAAa,QAAQ,SAAS,CAAC;AAC9C,gBAAc,CAAC,UAAU,aAAa,CAAC;AACvC,gBAAc,CAAC,aAAa,MAAM,aAAa,CAAC;AAClD;AAEO,SAAS,mCAAmD;AACjE,WAAS,cAAuB;AAC9B,WAAOC,aAAW,wBAAwB,CAAC;AAAA,EAC7C;AAEA,iBAAe,MAAM,aAAa,OAAsB;AACtD,QAAI,CAAC,yBAAyB,GAAG;AAC/B;AAAA,IACF;AAEA,WAAO,KAAK,aAAa,qCAAiB,mBAAmB,CAAC;AAE9D,QAAI,CAAC,YAAY;AACf,YAAM,cAAc,MAAM,cAAc;AAAA,QACtC,SAAS;AAAA,QACT,cAAc;AAAA,MAChB,CAAC;AAED,UAAI,CAAC,aAAa;AAChB,eAAO,KAAK,aAAa,kDAAU,CAAC;AACpC;AAAA,MACF;AAAA,IACF;AAEA,QAAI;AACF,YAAM,YAAY,sBAAsB;AACxC,2BAAqB;AAErB,aAAO,KAAK,cAAc,gCAAO,CAAC;AAClC,aAAO,KAAK,aAAa,6BAAS,SAAS,IAAI,SAAS,CAAC;AACzD,aAAO,KAAK,aAAa,oDAAY,SAAS,CAAC;AAC/C,aAAO;AAAA,QACL;AAAA,UACE;AAAA,UACA,mBAAmB,6BAA6B,CAAC;AAAA,QACnD;AAAA,MACF;AAAA,IACF,SAAS,KAAK;AACZ,aAAO,MAAM,yCAAY,IAAc,OAAO,EAAE;AAChD,YAAM;AAAA,IACR;AAAA,EACF;AAEA,iBAAe,QAAuB;AACpC,QAAI,CAAC,yBAAyB,GAAG;AAC/B;AAAA,IACF;AAEA,QAAI,CAAC,YAAY,GAAG;AAClB,aAAO;AAAA,QACL;AAAA,UACE;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA;AAAA,IACF;AAEA,QAAI;AACF,UAAI,CAAC,SAAS,GAAG;AACf,sBAAc;AAAA,UACZ;AAAA,UACA,sBAAsB;AAAA,UACtB,wBAAwB;AAAA,QAC1B,CAAC;AAAA,MACH;AACA,oBAAc,CAAC,UAAU,6BAA6B,CAAC,CAAC;AACxD,oBAAc,CAAC,aAAa,MAAM,6BAA6B,CAAC,CAAC;AACjE,aAAO,KAAK,aAAa,kCAAS,SAAS,CAAC;AAAA,IAC9C,SAAS,KAAK;AACZ,aAAO,MAAM,yCAAY,IAAc,OAAO,EAAE;AAChD,YAAM;AAAA,IACR;AAAA,EACF;AAEA,iBAAe,OAAsB;AACnC,QAAI,CAAC,YAAY,GAAG;AAClB,aAAO;AAAA,QACL;AAAA,UACE;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA;AAAA,IACF;AAEA,QAAI,CAAC,yBAAyB,GAAG;AAC/B;AAAA,IACF;AAEA,QAAI,CAAC,SAAS,GAAG;AACf,aAAO,KAAK,aAAa,oDAAY,SAAS,CAAC;AAC/C;AAAA,IACF;AAEA,QAAI;AACF,oBAAc,CAAC,WAAW,6BAA6B,CAAC,CAAC;AACzD,aAAO,KAAK,aAAa,kCAAS,SAAS,CAAC;AAAA,IAC9C,SAAS,KAAK;AACZ,aAAO,MAAM,yCAAY,IAAc,OAAO,EAAE;AAChD,YAAM;AAAA,IACR;AAAA,EACF;AAEA,iBAAe,UAAyB;AACtC,QAAI,CAAC,yBAAyB,GAAG;AAC/B;AAAA,IACF;AAEA,QAAI,CAAC,YAAY,GAAG;AAClB,aAAO;AAAA,QACL;AAAA,UACE;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA;AAAA,IACF;AAEA,QAAI;AACF,UAAI,SAAS,GAAG;AACd,sBAAc,CAAC,aAAa,MAAM,6BAA6B,CAAC,CAAC;AAAA,MACnE,OAAO;AACL,sBAAc;AAAA,UACZ;AAAA,UACA,sBAAsB;AAAA,UACtB,wBAAwB;AAAA,QAC1B,CAAC;AACD,sBAAc,CAAC,UAAU,6BAA6B,CAAC,CAAC;AACxD,sBAAc,CAAC,aAAa,MAAM,6BAA6B,CAAC,CAAC;AAAA,MACnE;AACA,aAAO,KAAK,aAAa,kCAAS,SAAS,CAAC;AAAA,IAC9C,SAAS,KAAK;AACZ,aAAO,MAAM,yCAAY,IAAc,OAAO,EAAE;AAChD,YAAM;AAAA,IACR;AAAA,EACF;AAEA,iBAAe,SAAwB;AACrC,QAAI,CAAC,YAAY,GAAG;AAClB,aAAO;AAAA,QACL;AAAA,UACE;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA;AAAA,IACF;AAEA,QAAI,CAAC,yBAAyB,GAAG;AAC/B;AAAA,IACF;AAEA,QAAI;AACF,oBAAc,CAAC,SAAS,6BAA6B,CAAC,CAAC;AAAA,IACzD,QAAQ;AACN,aAAO,KAAK,aAAa,oDAAY,SAAS,CAAC;AAC/C,aAAO,KAAK,eAAe,4BAAQ,wBAAwB,CAAC,CAAC;AAAA,IAC/D;AAAA,EACF;AAEA,iBAAe,UAAU,aAAa,OAAsB;AAC1D,UAAM,YAAY,wBAAwB;AAC1C,QAAI,CAACA,aAAW,SAAS,GAAG;AAC1B,aAAO,KAAK,aAAa,oDAAY,SAAS,CAAC;AAC/C;AAAA,IACF;AAEA,QAAI,CAAC,YAAY;AACf,YAAM,kBAAkB,MAAM,cAAc;AAAA,QAC1C,SAAS;AAAA,QACT,cAAc;AAAA,MAChB,CAAC;AAED,UAAI,CAAC,iBAAiB;AACpB,eAAO,KAAK,aAAa,sCAAQ,CAAC;AAClC;AAAA,MACF;AAAA,IACF;AAEA,UAAM,UAAU,oBAAoB;AACpC,QAAI,QAAQ,MAAM,SAAS,GAAG;AAC5B,UAAI;AACF,sBAAc,CAAC,WAAW,6BAA6B,CAAC,CAAC;AAAA,MAC3D,QAAQ;AAAA,MAER;AAAA,IACF,WAAW,CAAC,QAAQ,IAAI;AACtB,aAAO;AAAA,QACL;AAAA,UACE,wHAAmC,QAAQ,MAAM;AAAA,UACjD;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,QAAI;AACF,YAAM,EAAE,YAAY,WAAW,IAAI,wBAAwB;AAC3D,MAAAC,QAAO,SAAS;AAChB,MAAAA,QAAO,YAAY,EAAE,OAAO,KAAK,CAAC;AAClC,MAAAA,QAAO,YAAY,EAAE,OAAO,KAAK,CAAC;AAElC,aAAO,KAAK,cAAc,gCAAO,CAAC;AAClC,aAAO,KAAK,aAAa,oDAAY,SAAS,CAAC;AAAA,IACjD,SAAS,KAAK;AACZ,aAAO,MAAM,yCAAY,IAAc,OAAO,EAAE;AAChD,YAAM;AAAA,IACR;AAAA,EACF;AAEA,SAAO;AAAA,IACL,aAAa;AAAA,IACb,UAAU;AAAA,IACV;AAAA,IACA,mBAAmB;AAAA,IACnB,eAAe,MAAM,mBAAmB,6BAA6B,CAAC;AAAA,IACtE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;AJnbO,SAAS,kBACd,kBAAmCC,UAAS,GACrB;AACvB,UAAQ,iBAAiB;AAAA,IACvB,KAAK;AACH,aAAO,iCAAiC;AAAA,IAC1C,KAAK;AACH,aAAO,iCAAiC;AAAA,IAC1C;AACE,aAAO;AAAA,EACX;AACF;;;ADiCA,SAAS,gBACP,oBACG,OACK;AACR,SAAO,oBAAoB,UACvB,MAAM,KAAK,GAAG,KAAK,IACnB,MAAM,KAAK,GAAG,KAAK;AACzB;AAEA,SAAS,kBAAkBC,QAAuB;AAChD,SACEA,OACG,MAAM,QAAQ,EACd,IAAI,GACH,QAAQ,WAAW,EAAE,KAAKA;AAElC;AAEO,SAAS,wBACd,KACA,kBAAmCC,UAAS,GACtB;AACtB,UAAQ,iBAAiB;AAAA,IACvB,KAAK;AACH,aAAO;AAAA,QACL,SAAS;AAAA,QACT,MAAM,CAAC,GAAG;AAAA,MACZ;AAAA,IACF,KAAK;AACH,aAAO;AAAA,QACL,SAAS;AAAA,QACT,MAAM,CAAC,MAAM,MAAM,MAAM,SAAS,IAAI,GAAG;AAAA,MAC3C;AAAA,IACF;AACE,aAAO;AAAA,QACL,SAAS;AAAA,QACT,MAAM,CAAC,GAAG;AAAA,MACZ;AAAA,EACJ;AACF;AAEA,SAAS,YAAY,KAAmB;AACtC,QAAM,EAAE,SAAS,KAAK,IAAI,wBAAwB,GAAG;AAErD,MAAI;AACF,UAAM,QAAQ,MAAM,SAAS,MAAM;AAAA,MACjC,UAAU;AAAA,MACV,OAAO;AAAA,MACP,aAAa;AAAA,IACf,CAAC;AAED,UAAM,GAAG,SAAS,MAAM;AAAA,IAAC,CAAC;AAC1B,UAAM,MAAM;AAAA,EACd,QAAQ;AAAA,EAER;AACF;AAEA,SAAS,+BAA8C;AACrD,QAAM,aAAa,QAAQ,IAAI,cAAc;AAC7C,QAAM,aAAa;AAAA,IACjB;AAAA,IACAC,OAAK,YAAY,YAAY,qBAAqB,QAAQ,gBAAgB;AAAA,EAC5E;AAEA,aAAW,WAAW,YAAY;AAChC,QAAI;AACF,YAAM,SAASC;AAAA,QACb;AAAA,QACA;AAAA,UACE;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,QACA;AAAA,UACE,UAAU;AAAA,UACV,SAAS;AAAA,UACT,aAAa;AAAA,QACf;AAAA,MACF,EAAE,KAAK;AAEP,UAAI,QAAQ;AACV,eAAO;AAAA,MACT;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,uBACd,UAAyC,CAAC,GAClB;AACxB,QAAM,kBAAkB,QAAQ,mBAAmBF,UAAS;AAC5D,QAAM,MAAM,QAAQ,OAAO,QAAQ;AACnC,QAAM,UAAU,QAAQ,WAAWG,UAAQ;AAC3C,QAAM,aAAa,QAAQ,UAAUC;AAErC,QAAM,eAAe,IAAI,QACrB,kBAAkB,IAAI,KAAK,EAAE,YAAY,IACzC;AACJ,QAAM,YACJ,iBAAiB,oBAAoB,UAAU,eAAe;AAChE,QAAM,YAAY;AAElB,UAAQ,WAAW;AAAA,IACjB,KAAK;AACH,aAAO;AAAA,QACL,WAAW,SAAS,SAAS;AAAA,QAC7B,eAAe,CAAC,SAAS,SAAS,KAAK,YAAY,SAAS,EAAE;AAAA,QAC9D,YAAY,gBAAgB,iBAAiB,SAAS,QAAQ;AAAA,QAC9D,YAAY;AAAA,QACZ,YAAY;AAAA,MACd;AAAA,IACF,KAAK,QAAQ;AACX,YAAM,cAAc;AAAA,QAClB;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACA,YAAM,iBACJ,oBAAoB,YAAY,WAAW,WAAW;AAExD,aAAO;AAAA,QACL,WAAW,SAAS,SAAS;AAAA,QAC7B,eAAe,CAAC,SAAS,SAAS,KAAK,YAAY,SAAS,EAAE;AAAA,QAC9D,YAAY,iBACR,cACA,gBAAgB,iBAAiB,SAAS,SAAS;AAAA,QACvD,YAAY;AAAA,QACZ,YAAY,iBACR,2BACA;AAAA,MACN;AAAA,IACF;AAAA,IACA,KAAK;AACH,aAAO;AAAA,QACL,WAAW,SAAS,SAAS;AAAA,QAC7B,eAAe,CAAC,SAAS,SAAS,IAAI,YAAY,SAAS,EAAE;AAAA,QAC7D,YAAY;AAAA,UACV;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,QACA,YAAY;AAAA,QACZ,YAAY;AAAA,MACd;AAAA,IACF,KAAK,cAAc;AACjB,YAAM,aACJ,QAAQ,+BAA+B,KACvC,6BAA6B,KAC7B;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAEF,aAAO;AAAA,QACL,WAAW,mBAAmB,SAAS;AAAA,QACvC,eAAe;AAAA,UACb,mBAAmB,SAAS;AAAA,UAC5B,aAAa,SAAS;AAAA,UACtB,aAAa,SAAS;AAAA,UACtB,YAAY,SAAS;AAAA,QACvB;AAAA,QACA;AAAA,QACA,YAAY;AAAA,QACZ,YAAY;AAAA,MACd;AAAA,IACF;AAAA,IACA;AACE,aAAO;AAAA,EACX;AACF;AAMA,eAAsB,QAAQ,OAAoB,CAAC,GAAkB;AACnE,SAAO,KAAK,aAAa,+BAAgB,CAAC;AAE1C,QAAM,WAAW,WAAW;AAC5B,MAAI,UAAU,QAAQ;AACpB,WAAO,KAAK,cAAc,4CAAS,CAAC;AACpC,WAAO,KAAK,eAAe,wBAAc,WAAW,SAAS,MAAM,CAAC,CAAC;AACrE,WAAO;AAAA,MACL;AAAA,QACE;AAAA,QACA,SAAS,UAAU;AAAA,MACrB;AAAA,IACF;AAEA,UAAM,kBAAkB,MAAM,cAAc;AAAA,MAC1C,SAAS;AAAA,MACT,cAAc;AAAA,IAChB,CAAC;AAED,QAAI,CAAC,iBAAiB;AACpB,aAAO,KAAK,aAAa,8CAAW,SAAS,CAAC;AAC9C;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAAS,KAAK,UAAU,iBAAiB;AAC/C,QAAM,aAAa,GAAG,MAAM;AAC5B,SAAO,KAAK,cAAc,2CAAkB,CAAC;AAC7C,SAAO,KAAK,aAAa,yFAAwB,CAAC;AAClD,SAAO,KAAK,eAAe,oBAAU,gBAAgB,UAAU,CAAC,CAAC;AACjE,cAAY,UAAU;AAEtB,QAAM,SAAS,MAAM,eAAe;AAAA,IAClC,SAAS;AAAA,IACT,UAAU,CAAC,UAAU,eAAe,KAAK,KAAK;AAAA,EAChD,CAAC;AAED,SAAO,KAAK,cAAc,2CAAkB,CAAC;AAC7C,SAAO,KAAK,eAAe,0BAAW,WAAW,MAAM,CAAC,CAAC;AACzD,MAAI;AACF,UAAM,SAAS,IAAI,UAAU,QAAQ,MAAM;AAC3C,UAAM,WAAW,MAAM,OAAO,cAAc;AAE5C,QAAI,CAAC,UAAU;AACb,aAAO;AAAA,QACL;AAAA,UACE;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAAA,IACF,OAAO;AACL,aAAO,KAAK,aAAa,0CAAiB,SAAS,CAAC;AAAA,IACtD;AAAA,EACF,SAAS,KAAK;AACZ,QAAK,IAAc,YAAY,gBAAgB;AAC7C,aAAO,MAAM,8CAA8C;AAC3D,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,WAAO;AAAA,MACL;AAAA,QACE;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAAiB;AAAA,IACrB;AAAA,IACA;AAAA,IACA,GAAI,UAAU,WAAW,EAAE,UAAU,SAAS,SAAS,IAAI,CAAC;AAAA,EAC9D;AACA,aAAW,MAAM;AACjB,QAAM,WAAW,oBAAoB,MAAM;AAC3C,SAAO,WAAW;AAClB,SAAO,KAAK,cAAc,2DAAc,CAAC;AAEzC,QAAM,QAAQ,iBAAiB;AAC/B,MAAI,MAAM,SAAS,GAAG;AACpB,WAAO,KAAK,cAAc,iCAAa,CAAC;AACxC,eAAW,QAAQ,OAAO;AACxB,aAAO,KAAK,aAAa,KAAK,MAAM,SAAS,CAAC;AAAA,IAChD;AAAA,EACF,OAAO;AACL,WAAO,KAAK,cAAc,iCAAa,CAAC;AACxC,WAAO;AAAA,MACL;AAAA,QACE;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO,KAAK,cAAc,0BAAM,CAAC;AACjC,SAAO,KAAK,aAAa,sFAAgB,CAAC;AAC1C,QAAM,QAAQ,QAAQ,EAAE,QAAQ,OAAO,CAAC;AAExC,SAAO,KAAK,cAAc,gCAAO,CAAC;AAClC,SAAO,KAAK,aAAa,mDAAqB,SAAS,CAAC;AACxD,SAAO,KAAK,eAAe,sBAAO,GAAG,MAAM,QAAQ,CAAC;AAEpD,QAAM,gBAAgB;AACtB,QAAM,uBAAuB;AAC/B;AAEA,eAAe,yBAAwC;AACrD,QAAM,UAAU,kBAAkB;AAClC,MAAI,CAAC,SAAS;AACZ;AAAA,EACF;AAEA,QAAM,UAAU,QAAQ,SAAS;AACjC,MAAI,CAAC,QAAQ,IAAI;AACf;AAAA,EACF;AAEA,QAAM,cAAc,MAAM,cAAc;AAAA,IACtC,SAAS,4BAAQ,QAAQ,WAAW;AAAA,IACpC,cAAc;AAAA,EAChB,CAAC;AAED,MAAI,CAAC,aAAa;AAChB,WAAO,KAAK,aAAa,8DAAY,CAAC;AACtC;AAAA,EACF;AAEA,MAAI;AACF,UAAM,QAAQ,MAAM,IAAI;AAAA,EAC1B,SAAS,KAAK;AACZ,WAAO,KAAK,GAAG,QAAQ,WAAW,8BAAW,IAAc,OAAO,EAAE;AAAA,EACtE;AACF;AAEA,eAAe,kBAAiC;AAC9C,QAAM,QAAQ,uBAAuB;AACrC,MAAI,CAAC,OAAO;AACV;AAAA,EACF;AAEA,QAAM,oBAAoB,MAAM,cAAc;AAAA,IAC5C,SAAS,sBAAO,MAAM,UAAU;AAAA,IAChC,cAAc;AAAA,EAChB,CAAC;AACD,MAAI,CAAC,mBAAmB;AACtB,WAAO,KAAK,aAAa,mDAAqB,CAAC;AAC/C;AAAA,EACF;AAEA,MAAI;AACF,UAAM,MAAMC,SAAQ,MAAM,UAAU,GAAG,EAAE,WAAW,KAAK,CAAC;AAE1D,QAAI,kBAAkB;AACtB,QAAID,aAAW,MAAM,UAAU,GAAG;AAChC,wBAAkB,MAAM,SAAS,MAAM,YAAY,OAAO;AAAA,IAC5D;AAEA,UAAM,oBAAoB,gBAAgB,YAAY;AACtD,UAAM,cAAc,MAAM,cAAc;AAAA,MAAK,CAAC,YAC5C,kBAAkB,SAAS,QAAQ,YAAY,CAAC;AAAA,IAClD;AAEA,QAAI,aAAa;AACf,aAAO,KAAK,aAAa,2CAAa,MAAM,UAAU,EAAE,CAAC;AACzD;AAAA,IACF;AAEA,UAAM,mBAAmB;AAAA;AAAA,EAAyB,MAAM,SAAS;AAAA;AACjE,UAAM,WAAW,MAAM,YAAY,kBAAkB,OAAO;AAE5D,WAAO,KAAK,cAAc,aAAa,CAAC;AACxC,WAAO,KAAK,aAAa,sBAAO,MAAM,UAAU,IAAI,SAAS,CAAC;AAC9D,WAAO;AAAA,MACL,eAAe,4BAAQ,iBAAO,MAAM,UAAU,kCAAS;AAAA,IACzD;AACA,WAAO,KAAK,eAAe,4BAAQ,SAAS,CAAC;AAAA,EAC/C,SAAS,KAAK;AACZ,WAAO,KAAK,cAAc,aAAa,CAAC;AACxC,WAAO;AAAA,MACL;AAAA,QACE,4BAAQ,MAAM,UAAU,KAAM,IAAc,OAAO;AAAA,QACnD;AAAA,MACF;AAAA,IACF;AACA,WAAO,KAAK,eAAe,kCAAS,MAAM,SAAS,CAAC;AAAA,EACtD;AACF;;;AMzZA,IAAM,mBAAmB,IAAI;AAE7B,SAAS,IAAI,KAAmB;AAC9B,QAAM,MAAK,oBAAI,KAAK,GAAE,mBAAmB,SAAS,EAAE,QAAQ,MAAM,CAAC;AACnE,UAAQ,OAAO,MAAM,IAAI,EAAE,KAAK,GAAG;AAAA,CAAI;AACzC;AAEA,SAAS,MAAM,IAA2B;AACxC,SAAO,IAAI,QAAQ,CAACE,aAAY,WAAWA,UAAS,EAAE,CAAC;AACzD;AAOO,SAAS,kBAAkB,OAAsB,CAAC,GAAW;AAClE,SAAO,KAAK,UAAU,IAAI;AAC5B;AAEA,eAAsB,UAAU,OAAsB,CAAC,GAAkB;AACvE,QAAM,SAAS,WAAW;AAC1B,MAAI,CAAC,QAAQ,QAAQ;AACnB,QAAI,sBAAsB,GAAG;AAC3B,aAAO;AAAA,QACL;AAAA,UACE;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA,YAAM,aAAa,MAAM,cAAc;AAAA,QACrC,SAAS;AAAA,QACT,cAAc;AAAA,MAChB,CAAC;AACD,UAAI,YAAY;AACd,cAAM,QAAQ;AACd;AAAA,MACF;AACA,aAAO,KAAK,aAAa,+CAAiB,SAAS,CAAC;AACpD;AAAA,IACF;AAEA,UAAM,UAAU,KAAK,UACjB,0CACA;AACJ,WAAO,MAAM,OAAO;AACpB,YAAQ,KAAK,kBAAkB,IAAI,CAAC;AAAA,EACtC;AAEA,QAAM,WAAW,KAAK,YAAY,OAAO,gBAAgB;AACzD,QAAM,cAAc,KAAK,MAAM,WAAW,GAAK;AAC/C,QAAM,WAAW,KAAK,UAAU,iBAAiB;AAEjD,MAAI,8BAA8B,WAAW,MAAM,QAAQ,GAAG;AAG9D,SAAO,MAAM;AACX,QAAI;AACF,YAAM,QAAQ,QAAQ;AAAA,QACpB,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,QAAQ;AAAA,MACV,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,UAAK,IAAc,YAAY,gBAAgB;AAC7C,cAAM,UAAU,KAAK,UACjB,2CACA;AACJ,YAAI,OAAO;AACX,gBAAQ,KAAK,kBAAkB,IAAI,CAAC;AAAA,MACtC;AACA,UAAI,eAAgB,IAAc,OAAO,EAAE;AAAA,IAC7C;AACA,UAAM,MAAM,QAAQ;AAAA,EACtB;AACF;;;ACpEA,SAAS,YAAY,OAAwB;AAC3C,SAAO,SAAS;AAClB;AAEA,eAAsB,YAA2B;AAC/C,QAAM,SAAS,WAAW;AAC1B,SAAO;AAAA,IACL;AAAA,MACE;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,SAAO,KAAK,cAAc,cAAI,CAAC;AAC/B,MAAI,CAAC,QAAQ,QAAQ;AACnB,WAAO,KAAK,eAAe,gBAAM,kBAAkB,sBAAO,SAAS,CAAC,CAAC;AACrE,WAAO,KAAK,aAAa,2EAA8B,SAAS,CAAC;AAAA,EACnE,OAAO;AACL,WAAO,KAAK,eAAe,gBAAM,kBAAkB,sBAAO,SAAS,CAAC,CAAC;AACrE,WAAO,KAAK,eAAe,4BAAQ,cAAc,CAAC,CAAC;AACnD,WAAO,KAAK,eAAe,WAAW,WAAW,OAAO,MAAM,CAAC,CAAC;AAChE,WAAO;AAAA,MACL,eAAe,WAAW,OAAO,UAAU,2BAA2B;AAAA,IACxE;AACA,QAAI,OAAO,cAAc;AACvB,aAAO;AAAA,QACL;AAAA,UACE;AAAA,UACA,GAAG,KAAK,MAAM,OAAO,eAAe,GAAK,CAAC;AAAA,QAC5C;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO,KAAK,cAAc,gCAAO,CAAC;AAClC,QAAM,WAAW,qBAAqB;AACtC,MAAI,SAAS,WAAW,GAAG;AACzB,WAAO,KAAK,aAAa,iEAAoB,SAAS,CAAC;AAAA,EACzD,OAAO;AACL,eAAW,QAAQ,UAAU;AAC3B,aAAO,KAAK,aAAa,KAAK,MAAM,SAAS,CAAC;AAAA,IAChD;AAAA,EACF;AAEA,SAAO,KAAK,cAAc,gCAAO,CAAC;AAClC,aAAW,QAAQ,YAAY,GAAG;AAChC,UAAM,YAAY,gBAAgB,KAAK,EAAE;AACzC,WAAO;AAAA,MACL;AAAA,QACE,GAAG,KAAK,IAAI,SAAM,YAAY,uBAAQ,oBAAK;AAAA,QAC3C,YAAY,YAAY;AAAA,MAC1B;AAAA,IACF;AAAA,EACF;AAEA,QAAM,YAAY,cAAc;AAChC,SAAO,KAAK,cAAc,0BAAM,CAAC;AACjC,QAAM,aACJ,UAAU,WAAW,SACjB,YACA,UAAU,WAAW,YACnB,YACA;AACR,SAAO;AAAA,IACL,eAAe,gBAAM,kBAAkB,UAAU,QAAQ,UAAU,CAAC;AAAA,EACtE;AACA,SAAO,KAAK,eAAe,4BAAQ,YAAY,UAAU,aAAa,CAAC,CAAC;AACxE,SAAO,KAAK,eAAe,4BAAQ,YAAY,UAAU,aAAa,CAAC,CAAC;AACxE,MAAI,UAAU,YAAY;AACxB,WAAO,KAAK,eAAe,4BAAQ,UAAU,UAAU,CAAC;AAAA,EAC1D;AACA,MAAI,UAAU,WAAW;AACvB,WAAO,KAAK,eAAe,4BAAQ,UAAU,SAAS,CAAC;AAAA,EACzD;AACA,MAAI,UAAU,YAAY;AACxB,WAAO;AAAA,MACL;AAAA,QACE;AAAA,QACA,GAAG,UAAU,WAAW,OAAO,aAAa,UAAU,WAAW,QAAQ;AAAA,MAC3E;AAAA,IACF;AAAA,EACF;AACF;;;ACrFA,eAAsB,eACpB,OAA2B,CAAC,GACb;AACf,QAAM,SAAS,WAAW;AAC1B,MAAI,CAAC,QAAQ,QAAQ;AACnB,QAAI,sBAAsB,GAAG;AAC3B,aAAO;AAAA,QACL,aAAa,8CAAW,kFAAsB;AAAA,MAChD;AACA,YAAM,aAAa,MAAM,cAAc;AAAA,QACrC,SAAS;AAAA,QACT,cAAc;AAAA,MAChB,CAAC;AACD,UAAI,YAAY;AACd,cAAM,QAAQ;AACd;AAAA,MACF;AACA,aAAO,KAAK,aAAa,wCAAU,SAAS,CAAC;AAC7C;AAAA,IACF;AAEA,WAAO,MAAM,8CAA8C;AAC3D,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,QAAQ,QAAQ;AAAA,IACpB,OAAO,KAAK;AAAA,IACZ,QAAQ;AAAA,EACV,CAAC;AACH;;;AC3CA,SAAS,cAAAC,cAAY,gBAAAC,gBAAc,UAAAC,SAAQ,iBAAAC,sBAAqB;AAChE,SAAS,WAAAC,WAAS,YAAAC,iBAAgB;AAsBlC,SAAS,mBAAyB;AAChC,QAAM,QAAQ,QAAQ,IAAI;AAC1B,MAAI,CAAC,MAAO;AAEZ,QAAM,YAAY,MAAM,MAAM,GAAG,EAAE,IAAI,KAAK;AAC5C,QAAM,YAAY;AAElB,MAAI;AAEJ,UAAQ,WAAW;AAAA,IACjB,KAAK;AACH,mBAAa,GAAGC,UAAQ,CAAC;AACzB;AAAA,IACF,KAAK;AACH,UAAIC,UAAS,MAAM,YAAYC,aAAW,GAAGF,UAAQ,CAAC,gBAAgB,GAAG;AACvE,qBAAa,GAAGA,UAAQ,CAAC;AAAA,MAC3B,OAAO;AACL,qBAAa,GAAGA,UAAQ,CAAC;AAAA,MAC3B;AACA;AAAA,IACF,KAAK;AACH,mBAAa,GAAGA,UAAQ,CAAC;AACzB;AAAA,IACF;AACE;AAAA,EACJ;AAEA,MAAI,CAACE,aAAW,UAAU,EAAG;AAE7B,MAAI;AACF,QAAI,UAAUC,eAAa,YAAY,OAAO;AAG9C,UAAM,gBAAgB;AAAA;AAAA,MAEpB,IAAI;AAAA,QACF,gDAAgD,SAAS;AAAA,QACzD;AAAA,MACF;AAAA;AAAA,MAEA,IAAI;AAAA,QACF,gDAAgD,SAAS;AAAA,QACzD;AAAA,MACF;AAAA;AAAA,MAEA,IAAI,OAAO,gBAAgB,SAAS,iCAAiC,GAAG;AAAA,MACxE,IAAI,OAAO,gBAAgB,SAAS,4BAA4B,GAAG;AAAA,IACrE;AAEA,eAAW,WAAW,eAAe;AACnC,YAAM,OAAO,QAAQ,QAAQ,SAAS,IAAI;AAC1C,UAAI,SAAS,SAAS;AACpB,kBAAU;AAAA,MACZ;AAAA,IACF;AAEA,IAAAC,eAAc,YAAY,SAAS,OAAO;AAC1C,WAAO,KAAK,4BAA4B,UAAU,EAAE;AAAA,EACtD,SAAS,KAAK;AACZ,WAAO;AAAA,MACL,oBAAoB,UAAU,KAAM,IAAc,OAAO;AAAA,IAC3D;AAAA,EACF;AACF;AAEA,eAAsB,eAA8B;AAClD,QAAM,aAAa,cAAc;AACjC,QAAM,YAAY,aAAa;AAC/B,QAAM,WAAW,YAAY;AAC7B,QAAM,aAAa,kBAAkB;AACrC,QAAM,iBAAiB,kBAAkB;AACzC,QAAM,sBAAsB,gBAAgB,YAAY,KAAK;AAC7D,QAAM,oBACJF,aAAW,UAAU,KACrBA,aAAW,SAAS,KACpBA,aAAW,QAAQ,KACnBA,aAAW,UAAU,KACrB;AAEF,MAAI,CAAC,mBAAmB;AACtB,WAAO,KAAK,aAAa,yBAAe,CAAC;AACzC,WAAO,KAAK,aAAa,gFAAe,CAAC;AACzC;AAAA,EACF;AAEA,QAAM,SAAS,WAAW;AAC1B,SAAO;AAAA,IACL;AAAA,MACE;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACA,MAAI,QAAQ,QAAQ;AAClB,WAAO,KAAK,eAAe,WAAW,WAAW,OAAO,MAAM,CAAC,CAAC;AAAA,EAClE;AACA,SAAO,KAAK,eAAe,4BAAQ,SAAS,CAAC;AAC7C,SAAO,KAAK,eAAe,4BAAQ,QAAQ,CAAC;AAC5C,SAAO,KAAK,eAAe,4BAAQ,UAAU,CAAC;AAC9C,MAAI,uBAAuB,gBAAgB;AACzC,WAAO,KAAK,eAAe,4BAAQ,eAAe,kBAAkB,CAAC,CAAC;AAAA,EACxE;AAEA,QAAM,kBAAkB,MAAM,cAAc;AAAA,IAC1C,SAAS;AAAA,IACT,cAAc;AAAA,EAChB,CAAC;AACD,MAAI,CAAC,iBAAiB;AACpB,WAAO,KAAK,aAAa,wCAAU,SAAS,CAAC;AAC7C;AAAA,EACF;AAEA,MAAI,uBAAuB,gBAAgB;AACzC,UAAM,sBAAsB,MAAM,cAAc;AAAA,MAC9C,SAAS,wCAAU,eAAe,WAAW;AAAA,MAC7C,cAAc;AAAA,IAChB,CAAC;AAED,QAAI,qBAAqB;AACvB,UAAI;AACF,cAAM,eAAe,UAAU,IAAI;AAAA,MACrC,SAAS,KAAK;AACZ,eAAO,KAAK,qDAAc,IAAc,OAAO,EAAE;AAAA,MACnD;AAAA,IACF;AAAA,EACF;AAGA,SAAO,KAAK,cAAc,0BAAM,CAAC;AACjC,MAAIA,aAAW,UAAU,GAAG;AAC1B,iBAAa;AACb,WAAO,KAAK,aAAa,oDAAY,SAAS,CAAC;AAAA,EACjD;AAGA,MAAIA,aAAW,SAAS,GAAG;AACzB,QAAI;AACF,MAAAG,QAAO,WAAW,EAAE,WAAW,OAAO,OAAO,KAAK,CAAC;AACnD,aAAO,KAAK,aAAa,oDAAY,SAAS,CAAC;AAAA,IACjD,QAAQ;AAAA,IAER;AAAA,EACF;AAGA,MAAIH,aAAW,QAAQ,GAAG;AACxB,IAAAG,QAAO,UAAU,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AACjD,WAAO,KAAK,aAAa,oDAAY,SAAS,CAAC;AAAA,EACjD;AAGA,MAAIH,aAAW,UAAU,GAAG;AAC1B,IAAAG,QAAO,YAAY,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AACnD,WAAO,KAAK,aAAa,0DAAa,SAAS,CAAC;AAAA,EAClD;AAGA,mBAAiB;AAEjB,SAAO,KAAK,cAAc,cAAI,CAAC;AAC/B,SAAO,KAAK,aAAa,qEAAwB,SAAS,CAAC;AAC7D;;;AC3JA,SAAS,iBAAuB;AAC9B,QAAM,SAAS,WAAW;AAC1B,QAAM,aAAa,QAAQ,QAAQ,MAAM;AAEzC,SAAO;AAAA,IACL;AAAA,MACE;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACA,SAAO;AAAA,IACL;AAAA,MACE;AAAA,MACA,aACI,kBAAkB,sBAAO,SAAS,IAClC,kBAAkB,sBAAO,SAAS;AAAA,IACxC;AAAA,EACF;AAEA,MAAI,cAAc,QAAQ;AACxB,WAAO,KAAK,eAAe,WAAW,WAAW,OAAO,MAAM,CAAC,CAAC;AAChE,WAAO;AAAA,MACL,eAAe,oBAAU,OAAO,UAAU,2BAA2B;AAAA,IACvE;AAAA,EACF,OAAO;AACL,WAAO,KAAK,aAAa,0FAAyB,SAAS,CAAC;AAAA,EAC9D;AACF;AAEA,eAAe,iBAAsC;AACnD,SAAO,aAAyB;AAAA,IAC9B,SAAS;AAAA,IACT,SAAS;AAAA,MACP;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aAAa;AAAA,MACf;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aAAa;AAAA,MACf;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aAAa;AAAA,MACf;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aAAa;AAAA,MACf;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aAAa;AAAA,MACf;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aAAa;AAAA,MACf;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aAAa;AAAA,MACf;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aAAa;AAAA,MACf;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAEA,eAAsB,QAAQ,SAAiC;AAC7D,SAAO,MAAM;AACX,mBAAe;AAEf,UAAM,SAAS,MAAM,eAAe;AACpC,WAAO,KAAK,EAAE;AAEd,YAAQ,QAAQ;AAAA,MACd,KAAK;AACH,cAAM,QAAQ;AACd;AAAA,MACF,KAAK;AACH,cAAM,UAAU;AAChB;AAAA,MACF,KAAK;AACH,cAAM,eAAe;AACrB;AAAA,MACF,KAAK;AACH,cAAM,aAAa,CAAC,CAAC;AACrB;AAAA,MACF,KAAK;AACH,cAAM,UAAU;AAChB;AAAA,MACF,KAAK;AACH,cAAM,aAAa;AACnB;AAAA,MACF,KAAK;AACH,gBAAQ,WAAW;AACnB;AAAA,MACF,KAAK;AACH,eAAO,KAAK,aAAa,0DAAa,SAAS,CAAC;AAChD;AAAA,IACJ;AAEA,UAAM,iBAAiB,MAAM,cAAc;AAAA,MACzC,SAAS;AAAA,MACT,cAAc;AAAA,IAChB,CAAC;AAED,QAAI,CAAC,gBAAgB;AACnB,aAAO,KAAK,aAAa,4EAA0B,SAAS,CAAC;AAC7D;AAAA,IACF;AAAA,EACF;AACF;;;ACvIA,SAAS,WAAW,aAA4B;AAC9C,SAAO,KAAK,aAAa,iDAAmB,CAAC;AAC7C,MAAI,aAAa;AACf,WAAO,KAAK,eAAe,4BAAQ,WAAW,CAAC;AAAA,EACjD;AACA,SAAO,KAAK,cAAc,0BAAM,CAAC;AACjC,SAAO,KAAK,aAAa,wDAAqB,CAAC;AAC/C,SAAO,KAAK,aAAa,sCAAkB,CAAC;AAC5C,SAAO,KAAK,aAAa,sCAAkB,CAAC;AAC5C,SAAO,KAAK,aAAa,sCAAkB,CAAC;AAC5C,SAAO,KAAK,aAAa,kDAAoB,CAAC;AAC9C,SAAO,KAAK,aAAa,sCAAkB,CAAC;AAC9C;AAEA,eAAsB,kBACpB,MACe;AACf,QAAM,UAAU,kBAAkB;AAClC,MAAI,CAAC,SAAS;AACZ,WAAO;AAAA,MACL;AAAA,QACE;AAAA,QACA;AAAA,MACF;AAAA,IACF;AACA;AAAA,EACF;AAEA,QAAM,SAAS,KAAK,QAAQ,YAAY;AACxC,MAAI,CAAC,QAAQ;AACX,eAAW,QAAQ,WAAW;AAC9B,UAAM,UAAU,QAAQ,SAAS;AACjC,QAAI,CAAC,QAAQ,MAAM,QAAQ,QAAQ;AACjC,aAAO;AAAA,QACL,aAAa,2EAAe,QAAQ,MAAM,IAAI,SAAS;AAAA,MACzD;AAAA,IACF;AACA;AAAA,EACF;AAEA,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,YAAM,QAAQ,MAAM,KAAK,UAAU;AACnC;AAAA,IACF,KAAK;AACH,YAAM,QAAQ,MAAM;AACpB;AAAA,IACF,KAAK;AACH,YAAM,QAAQ,KAAK;AACnB;AAAA,IACF,KAAK;AACH,YAAM,QAAQ,QAAQ;AACtB;AAAA,IACF,KAAK;AACH,YAAM,QAAQ,OAAO;AACrB;AAAA,IACF,KAAK;AACH,YAAM,QAAQ,UAAU,KAAK,UAAU;AACvC;AAAA,IACF;AACE,aAAO,MAAM,6BAAS,MAAM,EAAE;AAC9B,cAAQ,KAAK,CAAC;AAAA,EAClB;AACF;;;AC7EA,SAAS,gBAAAC,sBAAoB;AAC7B,SAAS,WAAAC,UAAS,QAAAC,cAAY;AAC9B,SAAS,qBAAqB;AAE9B,IAAM,mBAAmB;AAEzB,IAAI;AAEG,SAAS,cAAc,UAAU,YAAY,KAAa;AAC/D,MAAI,eAAe;AACjB,WAAO;AAAA,EACT;AAEA,QAAM,kBAAkBA;AAAA,IACtBD,SAAQ,cAAc,OAAO,CAAC;AAAA,IAC9B;AAAA,IACA;AAAA,EACF;AAEA,MAAI;AACF,UAAM,cAAc,KAAK,MAAMD,eAAa,iBAAiB,OAAO,CAAC;AAIrE,oBACE,OAAO,YAAY,YAAY,WAC3B,YAAY,UACZ;AAAA,EACR,QAAQ;AACN,oBAAgB;AAAA,EAClB;AAEA,SAAO;AACT;;;A5BrBA,IAAM,cAAc,cAAc;AAE3B,SAAS,YAAqB;AACnC,QAAM,UAAU,IAAI,QAAQ;AAE5B,UACG,KAAK,YAAY,EACjB,YAAY,yCAAyC,EACrD,QAAQ,WAAW,EACnB,mBAAmB,EACnB,yBAAyB,EACzB,YAAY,kBAAkB,0BAA0B;AAG3D,UAAQ,OAAO,YAAY;AACzB,UAAM,WAAW,QAAQ,KAAK,MAAM,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,CAAC;AACvE,QAAI,SAAS,SAAS,GAAG;AACvB,cAAQ,MAAM,oBAAoB,SAAS,CAAC,CAAC,GAAG;AAAA,IAClD;AACA,QAAI,sBAAsB,GAAG;AAC3B,YAAM,QAAQ,OAAO;AACrB;AAAA,IACF;AACA,YAAQ,KAAK;AAAA,EACf,CAAC;AAGD,UACG,QAAQ,MAAM,EACd,YAAY,uCAAuC,EACnD,OAAO,mBAAmB,uBAAuB,EACjD,OAAO,OAAO,SAAS;AACtB,UAAM,QAAQ,IAAI;AAAA,EACpB,CAAC;AAGH,UACG,QAAQ,MAAM,EACd,YAAY,oCAAoC,EAChD,UAAU,IAAI,OAAO,SAAS,EAAE,SAAS,CAAC,EAC1C,OAAO,OAAO,SAAS;AACtB,UAAM,eAAe,IAAI;AAAA,EAC3B,CAAC;AAGH,UACG,QAAQ,QAAQ,EAChB,YAAY,kDAAkD,EAC9D,OAAO,mBAAmB,iCAAiC,QAAQ,EACnE,UAAU,IAAI,OAAO,WAAW,EAAE,SAAS,CAAC,EAC5C,OAAO,OAAO,SAAS;AACtB,UAAM,UAAU,IAAI;AAAA,EACtB,CAAC;AAGH,UACG,QAAQ,kBAAkB,EAC1B;AAAA,IACC;AAAA,EACF,EACC,OAAO,OAAO,WAAW;AACxB,UAAM,kBAAkB,EAAE,OAAO,CAAC;AAAA,EACpC,CAAC;AAGH,UACG,QAAQ,QAAQ,EAChB,YAAY,uCAAuC,EACnD,OAAO,YAAY;AAClB,UAAM,UAAU;AAAA,EAClB,CAAC;AAGH,UACG,QAAQ,QAAQ,EAChB,YAAY,sBAAsB,EAClC,SAAS,gBAAgB,cAAc,EACvC,SAAS,SAAS,YAAY,EAC9B,SAAS,WAAW,cAAc,EAClC,mBAAmB,IAAI,EACvB,OAAO,OAAO,YAAY,KAAK,UAAU;AACxC,UAAM;AAAA,MACJ,CAAC,YAAY,KAAK,KAAK,EAAE;AAAA,QACvB,CAAC,SAAyB,OAAO,SAAS;AAAA,MAC5C;AAAA,IACF;AAAA,EACF,CAAC;AAGH,UACG,QAAQ,WAAW,EACnB,YAAY,yCAAyC,EACrD,OAAO,YAAY;AAClB,UAAM,aAAa;AAAA,EACrB,CAAC;AAEH,SAAO;AACT;;;A6B7GA,SAAS,cAAAG,cAAY,oBAAoB;AACzC,SAAS,eAAe;AACxB,SAAS,iBAAAC,sBAAqB;AAEvB,SAAS,aACd,YAAY,QAAQ,KAAK,CAAC,GAC1B,UAAU,YAAY,KACb;AACT,MAAI,CAAC,WAAW;AACd,WAAO;AAAA,EACT;AAEA,QAAM,oBAAoBA,eAAc,OAAO;AAE/C,MAAI;AACF,WAAO,aAAa,SAAS,MAAM,aAAa,iBAAiB;AAAA,EACnE,QAAQ;AACN,QAAI,CAACD,aAAW,SAAS,GAAG;AAC1B,aAAO;AAAA,IACT;AAEA,WAAO,QAAQ,SAAS,MAAM,QAAQ,iBAAiB;AAAA,EACzD;AACF;;;ACRO,SAAS,cAAc,MAAgB;AAC5C,SAAO,KAAK,OAAO,CAAC,KAAK,UAAU,QAAQ,KAAK,QAAQ,IAAI;AAC9D;AAEA,eAAsB,IAAI,OAAO,QAAQ,MAAM;AAC7C,QAAM,UAAU,UAAU;AAC1B,QAAM,QAAQ,WAAW,cAAc,IAAI,CAAC;AAC9C;AAEA,IAAI,aAAa,GAAG;AAClB,OAAK,IAAI;AACX;","names":["existsSync","join","sep","hostname","existsSync","existsSync","join","sep","existsSync","homedir","join","TOOL","join","homedir","existsSync","readdirSync","readFileSync","homedir","join","TOOL","join","homedir","existsSync","readdirSync","readFileSync","existsSync","readdirSync","readFileSync","homedir","basename","join","join","homedir","TOOL","existsSync","readdirSync","basename","readFileSync","existsSync","readdirSync","readFileSync","homedir","basename","join","join","homedir","TOOL","existsSync","basename","readdirSync","readFileSync","existsSync","readdirSync","readFileSync","homedir","join","join","homedir","TOOL","existsSync","readdirSync","readFileSync","existsSync","readdirSync","homedir","join","DEFAULT_DATA_DIR","join","homedir","getPathLeaf","findSessionFiles","existsSync","readdirSync","existsSync","readdirSync","homedir","join","TOOL_ID","TOOL_NAME","join","homedir","createToolDefinition","toSafeNumber","getPathLeaf","existsSync","readdirSync","existsSync","readdirSync","homedir","basename","dirname","join","TOOL_ID","TOOL_NAME","DEFAULT_DATA_DIR","join","homedir","createToolDefinition","findSessionFiles","existsSync","readdirSync","toSafeNumber","basename","dirname","existsSync","homedir","join","TOOL_ID","TOOL_NAME","DEFAULT_SESSIONS_DIR","join","homedir","createToolDefinition","toSafeNumber","getPathLeaf","normalizeForPrefix","existsSync","existsSync","readFileSync","join","homedir","join","join","homedir","join","existsSync","readFileSync","hostname","input","createHash","input","URL","resolve","existsSync","readFileSync","writeFileSync","mkdirSync","join","join","mkdirSync","existsSync","readFileSync","writeFileSync","existsSync","readFileSync","writeFileSync","existsSync","readFileSync","writeFileSync","existsSync","readFileSync","writeFileSync","existsSync","readFileSync","writeFileSync","hostname","execFileSync","existsSync","homedir","platform","dirname","join","platform","execFileSync","existsSync","mkdirSync","rmSync","writeFileSync","homedir","join","homedir","join","execFileSync","existsSync","mkdirSync","writeFileSync","rmSync","execFileSync","existsSync","mkdirSync","rmSync","writeFileSync","homedir","platform","join","homedir","join","platform","execFileSync","mkdirSync","writeFileSync","existsSync","rmSync","platform","input","platform","join","execFileSync","homedir","existsSync","dirname","resolve","existsSync","readFileSync","rmSync","writeFileSync","homedir","platform","homedir","platform","existsSync","readFileSync","writeFileSync","rmSync","readFileSync","dirname","join","existsSync","fileURLToPath"]}