@poco-ai/tokenarena 0.1.2 → 0.1.5-beta.2

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/cli.ts","../src/infrastructure/config/manager.ts","../src/utils/logger.ts","../src/commands/config.ts","../src/services/sync-service.ts","../src/domain/project-identity.ts","../src/infrastructure/api/client.ts","../src/infrastructure/runtime/lock.ts","../src/infrastructure/runtime/paths.ts","../src/infrastructure/runtime/state.ts","../src/services/parser-service.ts","../src/commands/daemon.ts","../src/commands/init.ts","../src/commands/status.ts","../src/commands/sync.ts","../src/infrastructure/runtime/cli-version.ts","../src/infrastructure/runtime/main-module.ts","../src/index.ts"],"sourcesContent":["import { 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 TRANSCRIPTS_DIR = join(homedir(), \".claude\", \"transcripts\");\n\n/**\n * Extract project name from Claude-style encoded path\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 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\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 // --- projects/ directory: extract BOTH token buckets AND session events ---\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\n const timestamp = obj.timestamp;\n if (!timestamp) continue;\n const ts = new Date(timestamp);\n if (Number.isNaN(ts.getTime())) continue;\n\n if (obj.type === \"user\" || obj.type === \"assistant\") {\n sessionEvents.push({\n sessionId,\n source: \"claude-code\",\n project,\n timestamp: ts,\n role: obj.type === \"user\" ? \"user\" : \"assistant\",\n });\n }\n\n if (obj.type !== \"assistant\") continue;\n const msg = obj.message;\n if (!msg || !msg.usage) continue;\n\n const usage = msg.usage;\n if (usage.input_tokens == null && usage.output_tokens == null)\n continue;\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: msg.model || \"unknown\",\n project,\n timestamp: ts,\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 }\n }\n\n // --- transcripts/ directory: extract session events ONLY (no token data) ---\n const transcriptFiles = findJsonlFiles(TRANSCRIPTS_DIR);\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\n const timestamp = obj.timestamp;\n if (!timestamp) continue;\n const ts = new Date(timestamp);\n if (Number.isNaN(ts.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: ts,\n role: obj.type === \"user\" ? \"user\" : \"assistant\",\n });\n }\n } catch {}\n }\n }\n\n return {\n buckets: aggregateToBuckets(entries),\n sessions: extractSessions(sessionEvents, entries),\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\n/**\n * All supported tools and their data directories\n */\nexport const TOOLS: ToolDefinition[] = [];\n\n/**\n * Registered parsers by tool ID\n */\nconst parsers = new Map<string, IParser>();\n\n/**\n * Register a parser\n */\nexport function registerParser(parser: IParser): void {\n parsers.set(parser.tool.id, parser);\n if (!TOOLS.find((t) => t.id === parser.tool.id)) {\n TOOLS.push(parser.tool);\n }\n}\n\n/**\n * Get parser by tool ID\n */\nexport function getParser(toolId: string): IParser | undefined {\n return parsers.get(toolId);\n}\n\n/**\n * Get all registered parsers\n */\nexport function getAllParsers(): IParser[] {\n return Array.from(parsers.values());\n}\n\n/**\n * Detect installed tools by checking if their data directories exist\n */\nexport function detectInstalledTools(): ToolDefinition[] {\n return TOOLS.filter((t) => existsSync(t.dataDir));\n}\n\n/**\n * Get all tool definitions\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\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 // Extract project name and model from session_meta line\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\" && obj.payload) {\n const meta = obj.payload;\n if (meta.cwd) {\n sessionProject = meta.cwd.split(\"/\").pop() || \"unknown\";\n }\n if (meta.git?.repository_url) {\n const match = meta.git.repository_url.match(\n /([^/]+\\/[^/]+?)(?:\\.git)?$/,\n );\n if (match) sessionProject = match[1];\n }\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 evTs = new Date(obj.timestamp);\n if (!Number.isNaN(evTs.getTime())) {\n sessionEvents.push({\n sessionId: filePath,\n source: \"codex\",\n project: sessionProject,\n timestamp: evTs,\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) continue;\n\n if (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 // Prefer incremental per-request usage; compute delta from cumulative total as fallback\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\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 }\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, 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: \"copilot-cli\",\n name: \"GitHub Copilot CLI\",\n dataDir: join(homedir(), \".copilot\", \"session-state\"),\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 findEventFiles(\n baseDir: string,\n): { filePath: string; sessionId: string }[] {\n const results: { filePath: string; sessionId: 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 eventsFile = join(baseDir, entry.name, \"events.jsonl\");\n if (existsSync(eventsFile)) {\n results.push({ filePath: eventsFile, sessionId: entry.name });\n }\n }\n } catch {\n return results;\n }\n\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) || \"unknown\";\n}\n\nclass CopilotCliParser implements IParser {\n readonly tool = TOOL;\n\n async parse(): Promise<ParseResult> {\n const eventFiles = findEventFiles(TOOL.dataDir);\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 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 }\n }\n\n return {\n buckets: aggregateToBuckets(entries),\n sessions: extractSessions(sessionEvents, entries),\n };\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 TOOL: ToolDefinition = {\n id: \"opencode\",\n name: \"OpenCode\",\n dataDir: join(homedir(), \".local\", \"share\", \"opencode\"),\n};\n\nconst DB_PATH = join(TOOL.dataDir, \"opencode.db\");\nconst MESSAGES_DIR = join(TOOL.dataDir, \"storage\", \"message\");\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\nclass OpenCodeParser implements IParser {\n readonly tool = TOOL;\n\n async parse(): Promise<ParseResult> {\n // Try SQLite database first (opencode >= v0.2)\n if (existsSync(DB_PATH)) {\n try {\n return this.parseFromSqlite();\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 // Fall back to legacy JSON files\n return this.parseFromJson();\n }\n\n private parseFromSqlite(): 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 let output: string;\n try {\n output = execFileSync(\"sqlite3\", [\"-json\", DB_PATH, query], {\n encoding: \"utf-8\",\n maxBuffer: 100 * 1024 * 1024,\n timeout: 30000,\n });\n } catch (err) {\n const nodeErr = err as NodeJS.ErrnoException & { status?: number };\n if (nodeErr.status === 127 || nodeErr.message?.includes(\"ENOENT\")) {\n throw new Error(\n \"sqlite3 CLI not found. Install sqlite3 to sync opencode data.\",\n );\n }\n throw err;\n }\n\n output = output.trim();\n if (!output || output === \"[]\") return { buckets: [], sessions: [] };\n\n let rows: SqliteRow[];\n try {\n rows = JSON.parse(output);\n } catch {\n throw new Error(\"Failed to parse sqlite3 JSON output\");\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(): ParseResult {\n if (!existsSync(MESSAGES_DIR)) return { buckets: [], sessions: [] };\n\n const entries: TokenUsageEntry[] = [];\n const sessionEvents: SessionEvent[] = [];\n\n let sessionDirs: Dirent[];\n try {\n sessionDirs = readdirSync(MESSAGES_DIR, { withFileTypes: true }).filter(\n (d) => d.isDirectory() && d.name.startsWith(\"ses_\"),\n );\n } catch {\n return { buckets: [], sessions: [] };\n }\n\n for (const sessionDir of sessionDirs) {\n const sessionPath = join(MESSAGES_DIR, sessionDir.name);\n let msgFiles: string[];\n try {\n msgFiles = readdirSync(sessionPath).filter((f) => f.endsWith(\".json\"));\n } catch {\n continue;\n }\n\n for (const file of msgFiles) {\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 { Command, Option } from \"commander\";\nimport { handleConfig } from \"./commands/config\";\nimport { runDaemon } from \"./commands/daemon\";\nimport { runInit } from \"./commands/init\";\nimport { runStatus } from \"./commands/status\";\nimport { runSyncCommand } from \"./commands/sync\";\nimport { loadConfig } from \"./infrastructure/config/manager\";\nimport { getCliVersion } from \"./infrastructure/runtime/cli-version\";\nimport { runSync } from \"./services/sync-service\";\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\n // Default action: run init if not configured, otherwise sync\n program.action(async () => {\n const config = loadConfig();\n if (!config?.apiKey) {\n await runInit();\n } else {\n await runSync(config, { source: \"default\" });\n }\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 // 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((_subcommand, _key, _value, cmd) => {\n // Get all args after \"config\"\n const args = cmd.args.slice(1);\n handleConfig(args);\n });\n\n return program;\n}\n","import { randomUUID } from \"node:crypto\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\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(homedir(), \".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 = \"http://localhost:3000\";\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 const { unlinkSync } = require(\"node:fs\");\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(\"vbu_\");\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","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 { loadConfig, saveConfig } from \"../infrastructure/config/manager\";\nimport { logger } from \"../utils/logger\";\n\nconst VALID_KEYS = [\"apiKey\", \"apiUrl\", \"syncInterval\", \"logLevel\"];\n\nexport function handleConfig(args: string[]): void {\n const sub = args[0];\n\n switch (sub) {\n case \"get\": {\n const key = args[1];\n if (!key) {\n logger.error(\"Usage: tokenarena config get <key>\");\n process.exit(1);\n }\n const config = loadConfig();\n if (!config || !(key in config)) {\n // Output nothing — caller checks exit code or empty output\n process.exit(0);\n }\n // Output raw value (no formatting) for machine parsing\n console.log((config as Record<string, unknown>)[key] ?? \"\");\n break;\n }\n case \"set\": {\n const key = args[1];\n let value: string | number = args[2];\n if (!key || value === undefined) {\n logger.error(\"Usage: tokenarena config set <key> <value>\");\n process.exit(1);\n }\n if (!VALID_KEYS.includes(key)) {\n logger.error(`Unknown config key: ${key}`);\n logger.error(`Valid keys: ${VALID_KEYS.join(\", \")}`);\n process.exit(1);\n }\n const config = loadConfig() || {\n apiKey: \"\",\n apiUrl: \"http://localhost:3000\",\n };\n\n // Type conversion for numeric values\n if (key === \"syncInterval\") {\n value = parseInt(value, 10);\n if (Number.isNaN(value)) {\n logger.error(\"syncInterval must be a number (milliseconds)\");\n process.exit(1);\n }\n }\n\n (config as Record<string, unknown>)[key] = value;\n saveConfig(config);\n logger.info(`Set ${key} = ${value}`);\n break;\n }\n case \"show\": {\n const config = loadConfig();\n if (!config) {\n console.log(\"{}\");\n } else {\n console.log(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 { ApiClient } 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 { logger } from \"../utils/logger\";\nimport { runAllParsers } from \"./parser-service\";\n\nconst BATCH_SIZE = 100;\nconst SESSION_BATCH_SIZE = 500;\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 formatTime(secs: number): string {\n if (secs < 60) return `${secs}s`;\n const h = Math.floor(secs / 3600);\n const m = Math.floor((secs % 3600) / 60);\n return h > 0 ? (m > 0 ? `${h}h ${m}m` : `${h}h`) : `${m}m`;\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 || \"http://localhost:3000\";\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 uploadBuckets = toUploadBuckets(allBuckets, settings, device);\n const uploadSessions = toUploadSessions(allSessions, settings, device);\n\n if (!quiet) {\n const projectModeLabel: Record<ApiSettings[\"projectMode\"], string> = {\n hashed: \"哈希化\",\n raw: \"原始名称\",\n disabled: \"已隐藏\",\n };\n logger.info(`📂 项目模式: ${projectModeLabel[settings.projectMode]}`);\n }\n\n const bucketBatches = Math.ceil(uploadBuckets.length / BATCH_SIZE);\n const sessionBatches = Math.ceil(\n uploadSessions.length / SESSION_BATCH_SIZE,\n );\n const totalBatches = Math.max(bucketBatches, sessionBatches, 1);\n\n if (!quiet) {\n const parts: string[] = [];\n if (uploadBuckets.length > 0) {\n parts.push(`${uploadBuckets.length} buckets`);\n }\n if (uploadSessions.length > 0) {\n parts.push(`${uploadSessions.length} sessions`);\n }\n logger.info(\n `Uploading ${parts.join(\" + \")} (${totalBatches} batch${totalBatches > 1 ? \"es\" : \"\"})...`,\n );\n }\n\n for (let batchIdx = 0; batchIdx < totalBatches; batchIdx++) {\n const batch = uploadBuckets.slice(\n batchIdx * BATCH_SIZE,\n (batchIdx + 1) * BATCH_SIZE,\n );\n const batchSessions = uploadSessions.slice(\n batchIdx * SESSION_BATCH_SIZE,\n (batchIdx + 1) * SESSION_BATCH_SIZE,\n );\n const batchNum = batchIdx + 1;\n const prefix =\n totalBatches > 1 ? ` [${batchNum}/${totalBatches}] ` : \" \";\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 const pct = Math.round((sent / total) * 100);\n process.stdout.write(\n `\\r${prefix}${formatBytes(sent)}/${formatBytes(total)} (${pct}%)\\x1b[K`,\n );\n },\n );\n\n totalIngested += result.ingested ?? batch.length;\n totalSessionsSynced += result.sessions ?? batchSessions.length;\n }\n\n if (!quiet && (totalBatches > 1 || uploadBuckets.length > 0)) {\n process.stdout.write(\"\\n\");\n }\n\n const syncParts = [`${totalIngested} buckets`];\n if (totalSessionsSynced > 0) {\n syncParts.push(`${totalSessionsSynced} sessions`);\n }\n\n logger.info(`Synced ${syncParts.join(\" + \")}.`);\n\n if (!quiet && totalSessionsSynced > 0) {\n const totalActive = uploadSessions.reduce(\n (sum, session) => sum + session.activeSeconds,\n 0,\n );\n const totalDuration = uploadSessions.reduce(\n (sum, session) => sum + session.durationSeconds,\n 0,\n );\n const totalMsgs = uploadSessions.reduce(\n (sum, session) => sum + session.messageCount,\n 0,\n );\n logger.info(\n ` active: ${formatTime(totalActive)} / total: ${formatTime(totalDuration)}, ${totalMsgs} messages`,\n );\n }\n\n if (!quiet) {\n logger.info(`\\nView your dashboard at: ${apiUrl}/usage`);\n }\n\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 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 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 payload = {\n schemaVersion: 2 as const,\n device,\n buckets,\n sessions: sessions ?? [],\n };\n const body = Buffer.from(JSON.stringify(payload));\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 { ensureAppRuntimeDirs, 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 ensureAppRuntimeDirs();\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 { getConfigDir } from \"../config/manager\";\n\nexport function getRuntimeDir(): string {\n return join(getConfigDir(), \"runtime\");\n}\n\nexport function getSyncLockPath(): string {\n return join(getRuntimeDir(), \"sync.lock\");\n}\n\nexport function getSyncStatePath(): string {\n return join(getRuntimeDir(), \"status.json\");\n}\n\nexport function ensureAppRuntimeDirs(): void {\n mkdirSync(getRuntimeDir(), { recursive: true });\n}\n","import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { ensureAppRuntimeDirs, 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 ensureAppRuntimeDirs();\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 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 { loadConfig } from \"../infrastructure/config/manager\";\nimport { runSync } from \"../services/sync-service\";\nimport { logger } from \"../utils/logger\";\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 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 { execFile } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { appendFile, readFile } from \"node:fs/promises\";\nimport { homedir, platform } from \"node:os\";\nimport { createInterface } from \"node:readline\";\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 { getDetectedTools } from \"../services/parser-service\";\nimport { runSync } from \"../services/sync-service\";\nimport { logger } from \"../utils/logger\";\n\nfunction prompt(question: string): Promise<string> {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n return new Promise((resolve) => {\n rl.question(question, (answer) => {\n rl.close();\n resolve(answer.trim());\n });\n });\n}\n\nfunction openBrowser(url: string): void {\n const cmds: Record<string, string> = {\n darwin: \"open\",\n linux: \"xdg-open\",\n win32: \"start\",\n };\n const cmd = cmds[platform()] || cmds.linux;\n execFile(cmd, [url], () => {});\n}\n\nexport interface InitOptions {\n apiUrl?: string;\n}\n\nexport async function runInit(opts: InitOptions = {}): Promise<void> {\n logger.info(\"\\n tokenarena - Token Usage Tracker\\n\");\n\n const existing = loadConfig();\n if (existing?.apiKey) {\n const answer = await prompt(\"Config already exists. Overwrite? (y/N) \");\n if (answer.toLowerCase() !== \"y\") {\n logger.info(\"Cancelled.\");\n return;\n }\n }\n\n const apiUrl = opts.apiUrl || getDefaultApiUrl();\n logger.info(`Open ${apiUrl}/usage and create your API key from Settings.\\n`);\n openBrowser(`${apiUrl}/usage`);\n\n let apiKey: string;\n while (true) {\n apiKey = await prompt(\"Paste your API key: \");\n if (validateApiKey(apiKey)) break;\n logger.info('Invalid key — must start with \"vbu_\". Try again.');\n }\n\n logger.info(`\\nVerifying key ${apiKey.slice(0, 8)}...`);\n try {\n const client = new ApiClient(apiUrl, apiKey);\n const settings = await client.fetchSettings();\n\n if (!settings) {\n logger.info(\n \"Could not verify key settings (network error). Saving anyway.\\n\",\n );\n } else {\n logger.info(\"Key verified.\\n\");\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(\"Could not verify key (network error). Saving anyway.\\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(`Device registered: ${deviceId.slice(0, 8)}...`);\n\n const tools = getDetectedTools();\n if (tools.length > 0) {\n logger.info(`Detected tools: ${tools.map((t) => t.name).join(\", \")}`);\n } else {\n logger.info(\"No AI coding tools detected. Install one and re-run init.\");\n }\n\n logger.info(\"\\nRunning initial sync...\");\n await runSync(config, { source: \"init\" });\n\n logger.info(`\\nSetup complete! View your dashboard at: ${apiUrl}/usage`);\n\n // Offer to set up shell alias\n await setupShellAlias();\n}\n\nasync function setupShellAlias(): Promise<void> {\n const shell = process.env.SHELL;\n if (!shell) {\n return;\n }\n\n const shellName = shell.split(\"/\").pop() ?? \"\";\n const aliasName = \"ta\";\n\n let configFile: string;\n let aliasLine: string;\n let sourceHint: string;\n\n switch (shellName) {\n case \"zsh\":\n configFile = `${homedir()}/.zshrc`;\n aliasLine = `alias ${aliasName}=\"tokenarena\"`;\n sourceHint = \"source ~/.zshrc\";\n break;\n case \"bash\":\n // Check for bash_profile on macOS, bashrc on Linux\n if (platform() === \"darwin\" && existsSync(`${homedir()}/.bash_profile`)) {\n configFile = `${homedir()}/.bash_profile`;\n } else {\n configFile = `${homedir()}/.bashrc`;\n }\n aliasLine = `alias ${aliasName}=\"tokenarena\"`;\n sourceHint = `source ${configFile}`;\n break;\n case \"fish\":\n configFile = `${homedir()}/.config/fish/config.fish`;\n aliasLine = `alias ${aliasName} \"tokenarena\"`;\n sourceHint = \"source ~/.config/fish/config.fish\";\n break;\n default:\n // Unknown shell, skip\n return;\n }\n\n const answer = await prompt(\n `\\nSet up shell alias '${aliasName}' for 'tokenarena'? (Y/n) `,\n );\n if (answer.toLowerCase() === \"n\") {\n return;\n }\n\n try {\n // Check if alias already exists\n let existingContent = \"\";\n if (existsSync(configFile)) {\n existingContent = await readFile(configFile, \"utf-8\");\n }\n\n // Check for various alias formats\n const aliasPatterns = [\n `alias ${aliasName}=`,\n `alias ${aliasName} \"`,\n `alias ${aliasName}=`,\n ];\n\n const aliasExists = aliasPatterns.some((pattern) =>\n existingContent.includes(pattern),\n );\n\n if (aliasExists) {\n logger.info(\n `\\nAlias '${aliasName}' already exists in ${configFile}. Skipping.`,\n );\n return;\n }\n\n // Append the alias\n const aliasWithComment = `\\n# TokenArena alias\\n${aliasLine}\\n`;\n await appendFile(configFile, aliasWithComment);\n\n logger.info(`\\nAdded alias to ${configFile}`);\n logger.info(` Run '${sourceHint}' or restart your terminal to use it.`);\n logger.info(` Then you can use: ${aliasName} sync`);\n } catch (err) {\n logger.info(\n `\\nCould not write to ${configFile}: ${(err as Error).message}`,\n );\n logger.info(` Add this line manually: ${aliasLine}`);\n }\n}\n","import { existsSync } from \"node:fs\";\nimport { getConfigPath, loadConfig } from \"../infrastructure/config/manager\";\nimport { loadSyncState } from \"../infrastructure/runtime/state\";\nimport { detectInstalledTools, getAllTools } 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(\"\\ntokenarena status\\n\");\n\n if (!config?.apiKey) {\n logger.info(\" Config: not configured\");\n logger.info(` Run \\`tokenarena init\\` to set up.\\n`);\n } else {\n logger.info(` Config: ${getConfigPath()}`);\n logger.info(` API key: ${config.apiKey.slice(0, 8)}...`);\n logger.info(` API URL: ${config.apiUrl || \"http://localhost:3000\"}`);\n if (config.syncInterval) {\n logger.info(\n ` Sync interval: ${Math.round(config.syncInterval / 60000)}m`,\n );\n }\n }\n\n logger.info(\"\\n Detected tools:\");\n const detected = detectInstalledTools();\n if (detected.length === 0) {\n logger.info(\" (none)\\n\");\n } else {\n for (const tool of detected) {\n logger.info(` ${tool.name}`);\n }\n logger.info(\"\");\n }\n\n logger.info(\" All supported tools:\");\n for (const tool of getAllTools()) {\n const installed = existsSync(tool.dataDir) ? \"installed\" : \"not found\";\n logger.info(` ${tool.name}: ${installed}`);\n }\n\n const syncState = loadSyncState();\n logger.info(\"\\n Sync state:\");\n logger.info(` Status: ${syncState.status}`);\n logger.info(` Last attempt: ${formatMaybe(syncState.lastAttemptAt)}`);\n logger.info(` Last success: ${formatMaybe(syncState.lastSuccessAt)}`);\n if (syncState.lastSource) {\n logger.info(` Last source: ${syncState.lastSource}`);\n }\n if (syncState.lastError) {\n logger.info(` Last error: ${syncState.lastError}`);\n }\n if (syncState.lastResult) {\n logger.info(\n ` Last result: ${syncState.lastResult.buckets} buckets, ${syncState.lastResult.sessions} sessions`,\n );\n }\n\n logger.info(\"\");\n}\n","import { loadConfig } from \"../infrastructure/config/manager\";\nimport { runSync } from \"../services/sync-service\";\nimport { logger } from \"../utils/logger\";\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 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 { 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\";\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 function run(argv = process.argv) {\n const program = createCli();\n program.parse(normalizeArgv(argv));\n}\n\nif (isMainModule()) {\n run();\n}\n"],"mappings":"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","names":["join","sep","hostname","existsSync","existsSync","join","sep","homedir","join","TOOL","join","homedir","existsSync","readdirSync","readFileSync","homedir","join","TOOL","join","homedir","existsSync","readdirSync","readFileSync","existsSync","readdirSync","readFileSync","homedir","basename","join","TOOL","join","homedir","existsSync","readdirSync","basename","readFileSync","existsSync","readdirSync","readFileSync","homedir","basename","join","TOOL","join","homedir","existsSync","basename","readdirSync","readFileSync","existsSync","readdirSync","readFileSync","homedir","join","join","homedir","TOOL","existsSync","readdirSync","readFileSync","existsSync","readFileSync","homedir","join","existsSync","readFileSync","hostname","resolve","existsSync","readFileSync","writeFileSync","mkdirSync","join","join","mkdirSync","existsSync","readFileSync","writeFileSync","existsSync","readFileSync","writeFileSync","existsSync","readFileSync","writeFileSync","hostname","resolve","existsSync","homedir","resolve","homedir","existsSync","existsSync","existsSync","readFileSync","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/cli.ts","../src/infrastructure/config/manager.ts","../src/infrastructure/xdg.ts","../src/utils/logger.ts","../src/commands/config.ts","../src/services/sync-service.ts","../src/domain/project-identity.ts","../src/infrastructure/api/client.ts","../src/infrastructure/runtime/lock.ts","../src/infrastructure/runtime/paths.ts","../src/infrastructure/runtime/state.ts","../src/services/parser-service.ts","../src/commands/daemon.ts","../src/commands/init.ts","../src/commands/status.ts","../src/commands/sync.ts","../src/commands/uninstall.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 { Command, Option } from \"commander\";\nimport { handleConfig } from \"./commands/config\";\nimport { runDaemon } from \"./commands/daemon\";\nimport { runInit } from \"./commands/init\";\nimport { runStatus } from \"./commands/status\";\nimport { runSyncCommand } from \"./commands/sync\";\nimport { runUninstall } from \"./commands/uninstall\";\nimport { getCliVersion } from \"./infrastructure/runtime/cli-version\";\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(() => {\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 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 // 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((_subcommand, _key, _value, cmd) => {\n // Get all args after \"config\"\n const args = cmd.args.slice(1);\n handleConfig(args);\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","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 { loadConfig, saveConfig } from \"../infrastructure/config/manager\";\nimport { logger } from \"../utils/logger\";\n\nconst VALID_KEYS = [\"apiKey\", \"apiUrl\", \"syncInterval\", \"logLevel\"];\n\nexport function handleConfig(args: string[]): void {\n const sub = args[0];\n\n switch (sub) {\n case \"get\": {\n const key = args[1];\n if (!key) {\n logger.error(\"Usage: tokenarena config get <key>\");\n process.exit(1);\n }\n const config = loadConfig();\n if (!config || !(key in config)) {\n // Output nothing — caller checks exit code or empty output\n process.exit(0);\n }\n // Output raw value (no formatting) for machine parsing\n const record = config as unknown as Record<string, unknown>;\n console.log(record[key] ?? \"\");\n break;\n }\n case \"set\": {\n const key = args[1];\n let value: string | number = args[2];\n if (!key || value === undefined) {\n logger.error(\"Usage: tokenarena config set <key> <value>\");\n process.exit(1);\n }\n if (!VALID_KEYS.includes(key)) {\n logger.error(`Unknown config key: ${key}`);\n logger.error(`Valid keys: ${VALID_KEYS.join(\", \")}`);\n process.exit(1);\n }\n const config = loadConfig() || {\n apiKey: \"\",\n apiUrl: \"https://token.poco-ai.com\",\n };\n\n // Type conversion for numeric values\n if (key === \"syncInterval\") {\n value = parseInt(value, 10);\n if (Number.isNaN(value)) {\n logger.error(\"syncInterval must be a number (milliseconds)\");\n process.exit(1);\n }\n }\n\n const record = config as unknown as Record<string, unknown>;\n record[key] = value;\n saveConfig(config);\n logger.info(`Set ${key} = ${value}`);\n break;\n }\n case \"show\": {\n const config = loadConfig();\n if (!config) {\n console.log(\"{}\");\n } else {\n console.log(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 { ApiClient } 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 { logger } from \"../utils/logger\";\nimport { runAllParsers } from \"./parser-service\";\n\nconst BATCH_SIZE = 100;\nconst SESSION_BATCH_SIZE = 500;\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 formatTime(secs: number): string {\n if (secs < 60) return `${secs}s`;\n const h = Math.floor(secs / 3600);\n const m = Math.floor((secs % 3600) / 60);\n return h > 0 ? (m > 0 ? `${h}h ${m}m` : `${h}h`) : `${m}m`;\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 uploadBuckets = toUploadBuckets(allBuckets, settings, device);\n const uploadSessions = toUploadSessions(allSessions, settings, device);\n\n if (!quiet) {\n const projectModeLabel: Record<ApiSettings[\"projectMode\"], string> = {\n hashed: \"哈希化\",\n raw: \"原始名称\",\n disabled: \"已隐藏\",\n };\n logger.info(`📂 项目模式: ${projectModeLabel[settings.projectMode]}`);\n }\n\n const bucketBatches = Math.ceil(uploadBuckets.length / BATCH_SIZE);\n const sessionBatches = Math.ceil(\n uploadSessions.length / SESSION_BATCH_SIZE,\n );\n const totalBatches = Math.max(bucketBatches, sessionBatches, 1);\n\n if (!quiet) {\n const parts: string[] = [];\n if (uploadBuckets.length > 0) {\n parts.push(`${uploadBuckets.length} buckets`);\n }\n if (uploadSessions.length > 0) {\n parts.push(`${uploadSessions.length} sessions`);\n }\n logger.info(\n `Uploading ${parts.join(\" + \")} (${totalBatches} batch${totalBatches > 1 ? \"es\" : \"\"})...`,\n );\n }\n\n for (let batchIdx = 0; batchIdx < totalBatches; batchIdx++) {\n const batch = uploadBuckets.slice(\n batchIdx * BATCH_SIZE,\n (batchIdx + 1) * BATCH_SIZE,\n );\n const batchSessions = uploadSessions.slice(\n batchIdx * SESSION_BATCH_SIZE,\n (batchIdx + 1) * SESSION_BATCH_SIZE,\n );\n const batchNum = batchIdx + 1;\n const prefix =\n totalBatches > 1 ? ` [${batchNum}/${totalBatches}] ` : \" \";\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 const pct = Math.round((sent / total) * 100);\n process.stdout.write(\n `\\r${prefix}${formatBytes(sent)}/${formatBytes(total)} (${pct}%)\\x1b[K`,\n );\n },\n );\n\n totalIngested += result.ingested ?? batch.length;\n totalSessionsSynced += result.sessions ?? batchSessions.length;\n }\n\n if (!quiet && (totalBatches > 1 || uploadBuckets.length > 0)) {\n process.stdout.write(\"\\n\");\n }\n\n const syncParts = [`${totalIngested} buckets`];\n if (totalSessionsSynced > 0) {\n syncParts.push(`${totalSessionsSynced} sessions`);\n }\n\n logger.info(`Synced ${syncParts.join(\" + \")}.`);\n\n if (!quiet && totalSessionsSynced > 0) {\n const totalActive = uploadSessions.reduce(\n (sum, session) => sum + session.activeSeconds,\n 0,\n );\n const totalDuration = uploadSessions.reduce(\n (sum, session) => sum + session.durationSeconds,\n 0,\n );\n const totalMsgs = uploadSessions.reduce(\n (sum, session) => sum + session.messageCount,\n 0,\n );\n logger.info(\n ` active: ${formatTime(totalActive)} / total: ${formatTime(totalDuration)}, ${totalMsgs} messages`,\n );\n }\n\n if (!quiet) {\n logger.info(`\\nView your dashboard at: ${apiUrl}/usage`);\n }\n\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 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 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 payload = {\n schemaVersion: 2 as const,\n device,\n buckets,\n sessions: sessions ?? [],\n };\n const body = Buffer.from(JSON.stringify(payload));\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 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 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 { loadConfig } from \"../infrastructure/config/manager\";\nimport { runSync } from \"../services/sync-service\";\nimport { logger } from \"../utils/logger\";\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 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 { 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 { createInterface } from \"node:readline\";\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 { 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 prompt(question: string): Promise<string> {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n return new Promise((resolve) => {\n rl.question(question, (answer) => {\n rl.close();\n resolve(answer.trim());\n });\n });\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(\"\\n tokenarena - Token Usage Tracker\\n\");\n\n const existing = loadConfig();\n if (existing?.apiKey) {\n const answer = await prompt(\"Config already exists. Overwrite? (y/N) \");\n if (answer.toLowerCase() !== \"y\") {\n logger.info(\"Cancelled.\");\n return;\n }\n }\n\n const apiUrl = opts.apiUrl || getDefaultApiUrl();\n logger.info(`Open ${apiUrl}/usage and create your API key from Settings.\\n`);\n openBrowser(`${apiUrl}/usage`);\n\n let apiKey: string;\n while (true) {\n apiKey = await prompt(\"Paste your API key: \");\n if (validateApiKey(apiKey)) break;\n logger.info('Invalid key - must start with \"ta_\". Try again.');\n }\n\n logger.info(`\\nVerifying key ${apiKey.slice(0, 8)}...`);\n try {\n const client = new ApiClient(apiUrl, apiKey);\n const settings = await client.fetchSettings();\n\n if (!settings) {\n logger.info(\n \"Could not verify key settings (network error). Saving anyway.\\n\",\n );\n } else {\n logger.info(\"Key verified.\\n\");\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(\"Could not verify key (network error). Saving anyway.\\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(`Device registered: ${deviceId.slice(0, 8)}...`);\n\n const tools = getDetectedTools();\n if (tools.length > 0) {\n logger.info(`Detected tools: ${tools.map((tool) => tool.name).join(\", \")}`);\n } else {\n logger.info(\"No AI coding tools detected. Install one and re-run init.\");\n }\n\n logger.info(\"\\nRunning initial sync...\");\n await runSync(config, { source: \"init\" });\n\n logger.info(`\\nSetup complete! View your dashboard at: ${apiUrl}/usage`);\n\n await setupShellAlias();\n}\n\nasync function setupShellAlias(): Promise<void> {\n const setup = resolveShellAliasSetup();\n if (!setup) {\n return;\n }\n\n const answer = await prompt(\n `\\nSet up ${setup.shellLabel} alias 'ta' for 'tokenarena'? (Y/n) `,\n );\n if (answer.toLowerCase() === \"n\") {\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(\n `\\nAlias 'ta' already exists in ${setup.configFile}. Skipping.`,\n );\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(`\\nAdded alias to ${setup.configFile}`);\n logger.info(\n ` Run '${setup.sourceHint}' or restart your terminal to use it.`,\n );\n logger.info(\" Then you can use: ta sync\");\n } catch (err) {\n logger.info(\n `\\nCould not write to ${setup.configFile}: ${(err as Error).message}`,\n );\n logger.info(` Add this line manually: ${setup.aliasLine}`);\n }\n}\n","import { getConfigPath, loadConfig } from \"../infrastructure/config/manager\";\nimport { loadSyncState } from \"../infrastructure/runtime/state\";\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(\"\\ntokenarena status\\n\");\n\n if (!config?.apiKey) {\n logger.info(\" Config: not configured\");\n logger.info(\" Run `tokenarena init` to set up.\\n\");\n } else {\n logger.info(` Config: ${getConfigPath()}`);\n logger.info(` API key: ${config.apiKey.slice(0, 8)}...`);\n logger.info(` API URL: ${config.apiUrl || \"https://token.poco-ai.com\"}`);\n if (config.syncInterval) {\n logger.info(\n ` Sync interval: ${Math.round(config.syncInterval / 60000)}m`,\n );\n }\n }\n\n logger.info(\"\\n Detected tools:\");\n const detected = detectInstalledTools();\n if (detected.length === 0) {\n logger.info(\" (none)\\n\");\n } else {\n for (const tool of detected) {\n logger.info(` ${tool.name}`);\n }\n logger.info(\"\");\n }\n\n logger.info(\" All supported tools:\");\n for (const tool of getAllTools()) {\n const installed = isToolInstalled(tool.id) ? \"installed\" : \"not found\";\n logger.info(` ${tool.name}: ${installed}`);\n }\n\n const syncState = loadSyncState();\n logger.info(\"\\n Sync state:\");\n logger.info(` Status: ${syncState.status}`);\n logger.info(` Last attempt: ${formatMaybe(syncState.lastAttemptAt)}`);\n logger.info(` Last success: ${formatMaybe(syncState.lastSuccessAt)}`);\n if (syncState.lastSource) {\n logger.info(` Last source: ${syncState.lastSource}`);\n }\n if (syncState.lastError) {\n logger.info(` Last error: ${syncState.lastError}`);\n }\n if (syncState.lastResult) {\n logger.info(\n ` Last result: ${syncState.lastResult.buckets} buckets, ${syncState.lastResult.sessions} sessions`,\n );\n }\n\n logger.info(\"\");\n}\n","import { loadConfig } from \"../infrastructure/config/manager\";\nimport { runSync } from \"../services/sync-service\";\nimport { logger } from \"../utils/logger\";\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 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 { createInterface } from \"node:readline\";\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 { logger } from \"../utils/logger\";\n\nfunction prompt(question: string): Promise<string> {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n return new Promise((resolve) => {\n rl.question(question, (answer) => {\n rl.close();\n resolve(answer.trim());\n });\n });\n}\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(\"No configuration found. Nothing to uninstall.\");\n return;\n }\n\n const config = loadConfig();\n if (config?.apiKey) {\n logger.info(`API key: ${config.apiKey.slice(0, 8)}...`);\n }\n logger.info(`Config directory: ${configDir}`);\n\n const answer = await prompt(\n \"\\nAre you sure you want to uninstall? This will delete all local data. (y/N) \",\n );\n if (answer.toLowerCase() !== \"y\") {\n logger.info(\"Cancelled.\");\n return;\n }\n\n // 1. Delete config file\n deleteConfig();\n logger.info(\"Deleted configuration file.\");\n\n // 2. Remove config directory if empty\n if (existsSync(configDir)) {\n try {\n rmSync(configDir, { recursive: false, force: true });\n logger.info(\"Deleted config directory.\");\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(\"Deleted state data.\");\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(\"Deleted runtime data.\");\n }\n\n // 4. Clean up shell alias\n removeShellAlias();\n\n logger.info(\"\\nTokenArena has been uninstalled successfully.\");\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\";\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 function run(argv = process.argv) {\n const program = createCli();\n program.parse(normalizeArgv(argv));\n}\n\nif (isMainModule()) {\n 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","readFileSync","join","homedir","join","join","homedir","join","existsSync","readFileSync","hostname","resolve","existsSync","readFileSync","writeFileSync","mkdirSync","join","join","mkdirSync","existsSync","readFileSync","writeFileSync","existsSync","readFileSync","writeFileSync","existsSync","readFileSync","writeFileSync","hostname","resolve","execFileSync","existsSync","homedir","dirname","join","resolve","join","execFileSync","homedir","existsSync","dirname","existsSync","readFileSync","rmSync","writeFileSync","homedir","platform","createInterface","prompt","createInterface","resolve","homedir","platform","existsSync","readFileSync","writeFileSync","rmSync","readFileSync","dirname","join","existsSync","fileURLToPath"]}