@zhangferry-dev/tokendash 1.6.1 → 1.6.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/README.md +146 -83
- package/dist/client/assets/index-Bw503sNp.css +1 -0
- package/dist/client/index.html +2 -2
- package/dist/daemon.cjs +3306 -0
- package/dist/daemon.cjs.map +7 -0
- package/dist/electron-server.cjs +1019 -28
- package/dist/electron-server.cjs.map +4 -4
- package/dist/server/ccusage.d.ts +7 -0
- package/dist/server/ccusage.js +69 -0
- package/dist/server/daemon.d.ts +12 -0
- package/dist/server/daemon.js +176 -0
- package/dist/server/index.js +22 -11
- package/dist/server/insightsCalculator.d.ts +15 -0
- package/dist/server/insightsCalculator.js +276 -0
- package/dist/server/quota/adapter.d.ts +47 -0
- package/dist/server/quota/adapter.js +41 -0
- package/dist/server/quota/adapters/claude.d.ts +2 -0
- package/dist/server/quota/adapters/claude.js +124 -0
- package/dist/server/quota/adapters/codex.d.ts +2 -0
- package/dist/server/quota/adapters/codex.js +188 -0
- package/dist/server/quota/adapters/glm.d.ts +2 -0
- package/dist/server/quota/adapters/glm.js +133 -0
- package/dist/server/quota/adapters/kimi.d.ts +2 -0
- package/dist/server/quota/adapters/kimi.js +184 -0
- package/dist/server/quota/adapters/minimax.d.ts +2 -0
- package/dist/server/quota/adapters/minimax.js +77 -0
- package/dist/server/quota/cache.d.ts +20 -0
- package/dist/server/quota/cache.js +44 -0
- package/dist/server/quota/credentialsFile.d.ts +13 -0
- package/dist/server/quota/credentialsFile.js +23 -0
- package/dist/server/quota/helpers.d.ts +39 -0
- package/dist/server/quota/helpers.js +93 -0
- package/dist/server/quota/index.d.ts +5 -0
- package/dist/server/quota/index.js +23 -0
- package/dist/server/quota/quotaService.d.ts +37 -0
- package/dist/server/quota/quotaService.js +141 -0
- package/dist/server/quota/schemas.d.ts +358 -0
- package/dist/server/quota/schemas.js +53 -0
- package/dist/server/quota/types.d.ts +65 -0
- package/dist/server/quota/types.js +10 -0
- package/dist/server/routes/api.js +15 -0
- package/dist/server/routes/insights.d.ts +2 -0
- package/dist/server/routes/insights.js +155 -0
- package/package.json +6 -10
- package/resources/entitlements.mac.plist +10 -0
- package/resources/icon-1024.png +0 -0
- package/resources/icon.icns +0 -0
- package/resources/icon.png +0 -0
- package/resources/product_menu.png +0 -0
- package/resources/readme-hero.png +0 -0
- package/dist/client/assets/index-_yA9tOzZ.css +0 -1
- package/electron/main.cjs +0 -516
- package/electron/npmSync.cjs +0 -62
- package/electron/preload.cjs +0 -36
- package/electron/serverReuse.cjs +0 -59
- package/electron/trayBadge.cjs +0 -27
- package/electron/trayHelper +0 -0
- package/electron/trayHelper.swift +0 -152
- package/electron/updateService.cjs +0 -220
- package/electron-builder.yml +0 -20
- /package/dist/client/assets/{index-CY4G_b0x.js → index-C913wKtU.js} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/server/index.ts", "../src/server/cache.ts", "../src/shared/schemas.ts", "../src/server/codexParser.ts", "../src/server/codexPricing.ts", "../src/server/openclawParser.ts", "../src/server/opencodeParser.ts", "../src/server/claudeJsonlParser.ts", "../src/server/routes/daily.ts", "../src/server/routes/monthly.ts", "../src/server/routes/session.ts", "../src/server/routes/projects.ts", "../src/server/routes/blocks.ts", "../src/server/analyticsParser.ts", "../src/server/routes/analytics.ts", "../src/server/agentDetection.ts", "../src/server/routes/api.ts"],
|
|
4
|
-
"sourcesContent": ["import express from 'express';\nimport type { Express } from 'express';\nimport { existsSync, readFileSync } from 'node:fs';\nimport type { Server } from 'node:http';\nimport { fileURLToPath } from 'node:url';\nimport { basename, dirname, join, resolve } from 'node:path';\nimport { registerApiRoutes } from './routes/api.js';\nimport { detectAvailableAgents } from './agentDetection.js';\nimport open from 'open';\n\ninterface CliArgs {\n port?: number;\n noOpen?: boolean;\n showVersion?: boolean;\n tray?: boolean;\n}\n\nconst CLI_USAGE = [\n 'Usage:',\n ' tokendash',\n ' tokendash --version',\n ' tokendash --port <number> [--no-open]',\n ' tokendash --tray [--port <number>]',\n].join('\\n');\n\nconst PACKAGE_NAME = '@zhangferry-dev/tokendash';\n\nfunction getPackageVersion(): string {\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = dirname(__filename);\n const packageJsonPaths = [\n join(__dirname, '..', '..', 'package.json'), // dist/server/index.js\n join(__dirname, '..', 'package.json'), // dist/electron-server.cjs\n ];\n\n for (const packageJsonPath of packageJsonPaths) {\n if (!existsSync(packageJsonPath)) continue;\n const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8')) as { version?: string };\n if (packageJson.version) return packageJson.version;\n }\n\n return 'unknown';\n}\n\nfunction exitWithCliError(message: string): never {\n console.error(message);\n console.error(`\\n${CLI_USAGE}`);\n process.exit(1);\n}\n\nfunction parseCliArgs(): CliArgs {\n const args = process.argv.slice(2);\n const result: CliArgs = {};\n\n if (args.length === 1 && (args[0] === '--version' || args[0] === '-v')) {\n result.showVersion = true;\n return result;\n }\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n\n if (arg === '--version' || arg === '-v') {\n exitWithCliError('The --version flag must be used by itself.');\n }\n\n if (arg === '--port') {\n if (i + 1 >= args.length) {\n exitWithCliError('Missing value for --port.');\n }\n\n const value = parseInt(args[i + 1], 10);\n if (!Number.isInteger(value) || value <= 0) {\n exitWithCliError(`Invalid port value: ${args[i + 1]}`);\n }\n\n result.port = value;\n i++;\n } else if (arg === '--no-open') {\n result.noOpen = true;\n } else if (arg === '--tray') {\n result.tray = true;\n } else {\n exitWithCliError(`Unsupported argument: ${arg}`);\n }\n }\n\n return result;\n}\n\nasync function ensureUsageSupportAvailable(): Promise<boolean> {\n try {\n const agents = detectAvailableAgents();\n if (!agents.claude && !agents.codex) {\n console.error('Error: No AI coding assistant data found.');\n console.error('\\nDetails: Could not find Claude Code (~/.claude/projects/) or Codex (~/.codex/sessions/) data.');\n console.error('Please install at least one of: Claude Code or Codex CLI.');\n return false;\n }\n if (agents.claude) console.log(' \u2713 Claude Code detected');\n if (agents.codex) console.log(' \u2713 Codex detected');\n return true;\n } catch (error) {\n console.error('Error: failed to detect available AI coding assistants');\n console.error('\\nDetails:', error instanceof Error ? error.message : error);\n return false;\n }\n}\n\nfunction resolvePort(value?: number): number {\n return Number.isInteger(value) && value && value > 0 ? value : 3456;\n}\n\nfunction listen(app: Express, port: number): Promise<Server> {\n return new Promise((resolve, reject) => {\n const server = app.listen(port);\n\n const handleListening = () => {\n cleanup();\n resolve(server);\n };\n\n const handleError = (error: Error) => {\n cleanup();\n reject(error);\n };\n\n const cleanup = () => {\n server.off('listening', handleListening);\n server.off('error', handleError);\n };\n\n server.once('listening', handleListening);\n server.once('error', handleError);\n });\n}\n\nasync function listenWithPortFallback(app: Express, preferredPort: number): Promise<{ server: Server; port: number; usedFallback: boolean }> {\n let port = preferredPort;\n\n for (let attempt = 0; attempt < 20; attempt++, port++) {\n try {\n const server = await listen(app, port);\n return { server, port, usedFallback: port !== preferredPort };\n } catch (error) {\n const err = error as NodeJS.ErrnoException;\n if (err.code !== 'EADDRINUSE') {\n throw error;\n }\n }\n }\n\n throw new Error(`Could not find an available port starting from ${preferredPort}`);\n}\n\nexport function resolveStaticAssetBaseDir(moduleUrl = import.meta.url, baseDir?: string): { baseDir: string; isProduction: boolean } {\n if (baseDir) return { baseDir: resolve(baseDir), isProduction: true };\n\n const moduleDir = dirname(fileURLToPath(moduleUrl));\n const isProduction = moduleUrl.includes('/dist/');\n\n if (!isProduction) return { baseDir: resolve(moduleDir), isProduction: false };\n\n // The CLI entrypoint runs from dist/server/index.js while the Vite assets are\n // emitted to dist/client. Resolve the production asset base to dist instead\n // of dist/server so / resolves to dist/client/index.html in installed npm\n // packages. Electron passes dist explicitly and is unaffected by this branch.\n if (basename(moduleDir) === 'server') {\n return { baseDir: resolve(dirname(moduleDir)), isProduction: true };\n }\n\n return { baseDir: resolve(moduleDir), isProduction: true };\n}\n\nexport function createApp(_port: number, baseDir?: string): Express {\n const app = express();\n const router = express.Router();\n\n // Register API routes\n registerApiRoutes(router, {\n packageName: PACKAGE_NAME,\n version: getPackageVersion(),\n dashboardUrl: `http://localhost:${resolvePort(_port)}`,\n });\n app.use('/api', router);\n\n const { baseDir: _baseDir, isProduction } = resolveStaticAssetBaseDir(import.meta.url, baseDir);\n const popoverPath = isProduction\n ? join(_baseDir, 'client', 'popover.html')\n : join(_baseDir, '..', '..', 'public', 'popover.html');\n\n app.get('/popover.html', (_req, res, next) => {\n if (!existsSync(popoverPath)) {\n next();\n return;\n }\n res.type('html').send(readFileSync(popoverPath, 'utf8'));\n });\n\n // Check if running from dist (production build)\n if (isProduction) {\n // Serve static files from client build\n const clientPath = join(_baseDir, 'client');\n const clientIndexPath = join(clientPath, 'index.html');\n\n app.use(express.static(clientPath));\n\n // SPA fallback\n app.use('{*path}', (_req, res) => {\n res.sendFile(clientIndexPath);\n });\n }\n\n return app;\n}\n\nasync function main() {\n const args = parseCliArgs();\n if (args.showVersion) {\n console.log(getPackageVersion());\n return;\n }\n\n const version = getPackageVersion();\n const preferredPort = resolvePort(args.port ?? (process.env.PORT ? parseInt(process.env.PORT, 10) : undefined));\n\n // --tray mode: launch Electron\n if (args.tray) {\n if (process.platform !== 'darwin') {\n console.error('Error: --tray is only supported on macOS.');\n process.exit(1);\n }\n console.log(`Starting tokendash v${version} in tray mode...`);\n // @ts-ignore -- electron is installed separately for tray mode\n const { default: electronPath } = await import('electron');\n const { spawn } = await import('node:child_process');\n const child = spawn(electronPath as unknown as string, ['.'], {\n env: {\n ...process.env,\n TOKENDASH_PORT: String(preferredPort),\n TOKENDASH_TRAY: '1',\n },\n stdio: 'inherit',\n });\n child.on('close', (code) => process.exit(code ?? 0));\n process.on('SIGTERM', () => child.kill('SIGTERM'));\n return;\n }\n\n const shouldOpenBrowser = !args.noOpen;\n\n console.log(`Starting tokendash v${version}...`);\n console.log(`Checking local usage data sources...`);\n\n const isUsageSupportAvailable = await ensureUsageSupportAvailable();\n if (!isUsageSupportAvailable) {\n process.exit(1);\n }\n\n const app = createApp(preferredPort);\n const { server, port, usedFallback } = await listenWithPortFallback(app, preferredPort);\n\n if (usedFallback) {\n console.warn(`tokendash detected that port ${preferredPort} is already in use, switched to http://localhost:${port}`);\n }\n\n console.log(`tokendash running on http://localhost:${port}`);\n console.log(`API available at http://localhost:${port}/api`);\n const isProduction = import.meta.url.includes('dist/');\n if (isProduction) {\n console.log('Serving production build');\n } else {\n console.log('Development mode - use \"npm run dev\" for full dev experience');\n }\n\n // Open browser if requested\n if (shouldOpenBrowser) {\n // Small delay to ensure server is ready\n setTimeout(() => {\n console.log('Opening dashboard in your browser...');\n open(`http://localhost:${port}`).catch((err) => {\n console.warn('Could not open browser:', err.message);\n });\n }, 100);\n } else {\n console.log('Browser auto-open disabled (--no-open)');\n }\n\n // Graceful shutdown\n process.on('SIGTERM', () => {\n server.close(() => {\n console.log('Server closed');\n process.exit(0);\n });\n });\n}\n\nexport { main };\n", "import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { tmpdir } from 'node:os';\n\nconst DEFAULT_TTL = 5 * 60 * 1000; // 5 minutes (fresh)\nconst DISK_TTL = 60 * 60 * 1000; // 1 hour (stale but usable)\n\nconst CACHE_DIR = join(tmpdir(), 'tokendash-cache');\n\ninterface CacheEntry<T> {\n data: T;\n expiresAt: number;\n updatedAt: number;\n}\n\nfunction diskPath(key: string): string {\n const safe = key.replace(/[^a-zA-Z0-9_-]/g, '_');\n return join(CACHE_DIR, `${safe}.json`);\n}\n\nclass Cache {\n private store = new Map<string, CacheEntry<unknown>>();\n\n get<T>(key: string): T | null {\n const entry = this.store.get(key);\n if (entry && Date.now() <= entry.expiresAt) {\n return entry.data as T;\n }\n return null;\n }\n\n /** Get data even if stale (for stale-while-revalidate) */\n getStale<T>(key: string): T | null {\n // Try memory first\n const entry = this.store.get(key);\n if (entry) return entry.data as T;\n\n // Try disk\n return this.readFromDisk<T>(key);\n }\n\n set<T>(key: string, data: T, ttl: number = DEFAULT_TTL): void {\n const entry: CacheEntry<T> = {\n data,\n expiresAt: Date.now() + ttl,\n updatedAt: Date.now(),\n };\n this.store.set(key, entry as CacheEntry<unknown>);\n this.writeToDisk(key, entry);\n }\n\n clear(): void {\n this.store.clear();\n }\n\n delete(key: string): boolean {\n return this.store.delete(key);\n }\n\n has(key: string): boolean {\n const entry = this.store.get(key);\n if (!entry) return false;\n if (Date.now() > entry.expiresAt) {\n this.store.delete(key);\n return false;\n }\n return true;\n }\n\n private writeToDisk<T>(key: string, entry: CacheEntry<T>): void {\n try {\n if (!existsSync(CACHE_DIR)) mkdirSync(CACHE_DIR, { recursive: true });\n writeFileSync(diskPath(key), JSON.stringify(entry), 'utf-8');\n } catch {\n // Disk cache is best-effort\n }\n }\n\n private readFromDisk<T>(key: string): T | null {\n try {\n const path = diskPath(key);\n if (!existsSync(path)) return null;\n const raw = readFileSync(path, 'utf-8');\n const entry = JSON.parse(raw) as CacheEntry<T>;\n // Only use disk cache if less than DISK_TTL old\n if (Date.now() - entry.updatedAt < DISK_TTL) {\n // Promote to memory cache (with 0 TTL so it'll be treated as stale)\n this.store.set(key, { ...entry, expiresAt: 0 } as CacheEntry<unknown>);\n return entry.data;\n }\n } catch {\n // Disk cache is best-effort\n }\n return null;\n }\n}\n\nexport const cache = new Cache();\nexport type { CacheEntry };\n", "import { z } from 'zod';\n\nexport const ModelBreakdownSchema = z.object({\n modelName: z.string(),\n inputTokens: z.number().default(0),\n outputTokens: z.number().default(0),\n cacheCreationTokens: z.number().default(0),\n cacheReadTokens: z.number().default(0),\n cost: z.number().default(0),\n});\n\nexport const DailyEntrySchema = z.object({\n date: z.string(),\n inputTokens: z.number().default(0),\n outputTokens: z.number().default(0),\n cacheCreationTokens: z.number().default(0),\n cacheReadTokens: z.number().default(0),\n totalTokens: z.number().default(0),\n totalCost: z.number().default(0),\n modelsUsed: z.array(z.string()).default([]),\n modelBreakdowns: z.array(ModelBreakdownSchema).default([]),\n});\n\nexport const TotalsSchema = z.object({\n inputTokens: z.number().default(0),\n outputTokens: z.number().default(0),\n cacheCreationTokens: z.number().default(0),\n cacheReadTokens: z.number().default(0),\n totalTokens: z.number().default(0),\n totalCost: z.number().default(0),\n});\n\nexport const DailyResponseSchema = z.object({\n daily: z.array(DailyEntrySchema).default([]),\n totals: TotalsSchema,\n});\n\nexport const ProjectEntrySchema = z.object({\n projectPath: z.string(),\n instances: z.array(DailyEntrySchema).default([]),\n});\n\nexport const ProjectsResponseSchema = z.object({\n projects: z.record(z.array(DailyEntrySchema).default([])).default({}),\n});\n\nexport function validateDaily(data: unknown) {\n return DailyResponseSchema.parse(data);\n}\n\nexport function validateProjects(data: unknown) {\n return ProjectsResponseSchema.parse(data);\n}\n\nconst BlockEntrySchema = z.object({\n id: z.string(),\n startTime: z.string(),\n endTime: z.string(),\n actualEndTime: z.string().nullable().default(null),\n isActive: z.boolean().default(false),\n isGap: z.boolean().default(false),\n entries: z.number().default(0),\n tokenCounts: z.object({\n inputTokens: z.number().default(0),\n outputTokens: z.number().default(0),\n cacheCreationInputTokens: z.number().default(0),\n cacheReadInputTokens: z.number().default(0),\n }).default({ inputTokens: 0, outputTokens: 0, cacheCreationInputTokens: 0, cacheReadInputTokens: 0 }),\n totalTokens: z.number().default(0),\n costUSD: z.number().default(0),\n models: z.array(z.string()).default([]),\n});\n\nexport const BlocksResponseSchema = z.object({\n blocks: z.array(BlockEntrySchema).default([]),\n});\n\nexport function validateBlocks(data: unknown) {\n return BlocksResponseSchema.parse(data);\n}\n\n// --- Analytics schemas ---\n\nconst DailyCodeChangeSchema = z.object({\n date: z.string(),\n linesAdded: z.number().default(0),\n linesDeleted: z.number().default(0),\n netChange: z.number().default(0),\n filesModified: z.number().default(0),\n});\n\nconst ToolUsageEntrySchema = z.object({\n name: z.string(),\n count: z.number().default(0),\n});\n\nconst ProductivityKPIsSchema = z.object({\n avgLinesPerEdit: z.number().default(0),\n filesModifiedPerDay: z.number().default(0),\n addDeleteRatio: z.number().default(0),\n totalEdits: z.number().default(0),\n totalFilesModified: z.number().default(0),\n activeDaysWithEdits: z.number().default(0),\n});\n\nconst AnalyticsResponseSchema = z.object({\n codeChangeTrend: z.array(DailyCodeChangeSchema).default([]),\n toolUsageDistribution: z.array(ToolUsageEntrySchema).default([]),\n productivityKPIs: ProductivityKPIsSchema,\n toolCallTrend: z.array(z.record(z.union([z.string(), z.number()]))).default([]),\n});\n\nexport function validateAnalytics(data: unknown) {\n return AnalyticsResponseSchema.parse(data);\n}\n", "import { readFileSync, readdirSync, statSync, accessSync, constants } from 'node:fs';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { z } from 'zod';\nimport type { DailyEntry, DailyResponse, ProjectsResponse, BlockEntry, BlocksResponse, ModelBreakdown } from '../shared/types.js';\nimport { calculateCost } from './codexPricing.js';\n\n// ---------------------------------------------------------------------------\n// Zod schemas for JSONL event validation (format change detector)\n// ---------------------------------------------------------------------------\n\nconst TokenUsageSchema = z.object({\n input_tokens: z.number().default(0),\n cached_input_tokens: z.number().default(0),\n output_tokens: z.number().default(0),\n reasoning_output_tokens: z.number().default(0),\n total_tokens: z.number().default(0),\n}).default({ input_tokens: 0, cached_input_tokens: 0, output_tokens: 0, reasoning_output_tokens: 0, total_tokens: 0 });\n\nconst TokenCountInfoSchema = z.object({\n total_token_usage: TokenUsageSchema,\n last_token_usage: TokenUsageSchema.optional(),\n}).nullable().default(null);\n\nconst TokenCountPayloadSchema = z.object({\n type: z.literal('token_count'),\n info: TokenCountInfoSchema,\n});\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface ParsedTokenEvent {\n timestamp: string;\n inputTokens: number;\n cachedInputTokens: number;\n outputTokens: number;\n reasoningOutputTokens: number;\n totalTokens: number;\n}\n\nexport interface ParsedSession {\n id: string;\n cwd: string;\n model: string;\n createdAt: string;\n tokenEvents: ParsedTokenEvent[];\n}\n\nexport interface AggregateOptions {\n groupBy: 'day' | 'hour' | 'month' | 'session' | 'project';\n project?: string | null;\n since?: Date | null;\n until?: Date | null;\n timezone?: string;\n}\n\ninterface TokenAccumulator {\n inputTokens: number;\n cachedInputTokens: number;\n outputTokens: number;\n reasoningOutputTokens: number;\n totalTokens: number;\n}\n\ninterface AggregateBucket {\n acc: TokenAccumulator;\n models: Map<string, TokenAccumulator>;\n}\n\nfunction subtractTokenUsage(\n current: z.infer<typeof TokenUsageSchema>,\n previous: z.infer<typeof TokenUsageSchema> | null,\n): ParsedTokenEvent {\n return {\n timestamp: '',\n inputTokens: Math.max(0, current.input_tokens - (previous?.input_tokens ?? 0)),\n cachedInputTokens: Math.max(0, current.cached_input_tokens - (previous?.cached_input_tokens ?? 0)),\n outputTokens: Math.max(0, current.output_tokens - (previous?.output_tokens ?? 0)),\n reasoningOutputTokens: Math.max(0, current.reasoning_output_tokens - (previous?.reasoning_output_tokens ?? 0)),\n totalTokens: Math.max(0, current.total_tokens - (previous?.total_tokens ?? 0)),\n };\n}\n\nfunction displayInputTokens(inputTokens: number, cachedInputTokens: number): number {\n return Math.max(0, inputTokens - cachedInputTokens);\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction getSessionsDir(): string {\n return join(homedir(), '.codex', 'sessions');\n}\n\nexport function isSessionsDirAccessible(): boolean {\n try {\n accessSync(getSessionsDir(), constants.R_OK);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Recursively find all .jsonl files under ~/.codex/sessions/\n */\nexport function scanCodexSessions(): string[] {\n const sessionsDir = getSessionsDir();\n const results: string[] = [];\n\n function walk(dir: string): void {\n let entries;\n try {\n entries = readdirSync(dir);\n } catch {\n return;\n }\n for (const entry of entries) {\n const full = join(dir, entry);\n let st: ReturnType<typeof statSync>;\n try {\n st = statSync(full);\n } catch {\n continue;\n }\n if (st.isDirectory()) {\n walk(full);\n } else if (entry.endsWith('.jsonl')) {\n results.push(full);\n }\n }\n }\n\n walk(sessionsDir);\n return results.sort();\n}\n\n/**\n * Parse a single Codex session JSONL file.\n *\n * Codex can emit duplicate token_count events for the same turn, with identical\n * total_token_usage and last_token_usage snapshots a few seconds apart. These\n * are repeated status updates, not separate billable usage records, so only the\n * first occurrence of each cumulative total_token_usage snapshot should count.\n */\nexport function parseCodexSession(filepath: string): ParsedSession | null {\n let content: string;\n try {\n content = readFileSync(filepath, 'utf-8');\n } catch {\n return null;\n }\n\n const lines = content.split('\\n');\n let sessionId = '';\n let cwd = '';\n let model = '';\n let createdAt = '';\n const tokenEvents: ParsedTokenEvent[] = [];\n let previousTotalUsage: z.infer<typeof TokenUsageSchema> | null = null;\n const seenTotalUsageSnapshots = new Set<string>();\n const seenUsageEvents = new Set<string>();\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n\n let obj: Record<string, unknown>;\n try {\n obj = JSON.parse(trimmed) as Record<string, unknown>;\n } catch {\n continue;\n }\n\n const type = obj.type as string;\n\n if (type === 'session_meta') {\n const payload = (obj.payload as Record<string, unknown>) || {};\n sessionId = (payload.id as string) || '';\n cwd = (payload.cwd as string) || '';\n createdAt = (payload.timestamp as string) || '';\n }\n\n if (type === 'turn_context') {\n const payload = (obj.payload as Record<string, unknown>) || {};\n if (!model && payload.model) {\n model = payload.model as string;\n }\n }\n\n // Extract token counts from event_msg with nested token_count payload.\n if (type === 'event_msg') {\n const payload = (obj.payload as Record<string, unknown>) || {};\n if (payload.type === 'token_count') {\n const timestamp = (obj.timestamp as string) || '';\n const parseResult = TokenCountPayloadSchema.safeParse(payload);\n if (!parseResult.success) {\n console.warn(`[codexParser] Schema validation failed in ${filepath}:`, parseResult.error.message);\n continue;\n }\n const info = parseResult.data.info;\n if (!info) continue;\n const totalUsageKey = [\n info.total_token_usage.input_tokens,\n info.total_token_usage.cached_input_tokens,\n info.total_token_usage.output_tokens,\n info.total_token_usage.reasoning_output_tokens,\n info.total_token_usage.total_tokens,\n ].join(':');\n if (seenTotalUsageSnapshots.has(totalUsageKey)) continue;\n seenTotalUsageSnapshots.add(totalUsageKey);\n\n const last = info.last_token_usage ?? info.total_token_usage;\n const rawEvent = info.last_token_usage\n ? subtractTokenUsage(last, null)\n : subtractTokenUsage(last, previousTotalUsage);\n previousTotalUsage = info.total_token_usage;\n\n if (rawEvent.inputTokens === 0 && rawEvent.cachedInputTokens === 0 && rawEvent.outputTokens === 0 && rawEvent.reasoningOutputTokens === 0) {\n continue;\n }\n\n const event = {\n ...rawEvent,\n timestamp,\n cachedInputTokens: Math.min(rawEvent.cachedInputTokens, rawEvent.inputTokens),\n };\n const eventKey = [\n timestamp,\n model,\n event.inputTokens,\n event.cachedInputTokens,\n event.outputTokens,\n event.reasoningOutputTokens,\n event.totalTokens,\n ].join(':');\n if (seenUsageEvents.has(eventKey)) {\n continue;\n }\n seenUsageEvents.add(eventKey);\n tokenEvents.push(event);\n }\n }\n }\n\n if (!sessionId) return null;\n\n return { id: sessionId, cwd, model, createdAt, tokenEvents };\n}\n\n/** Parse all Codex sessions. */\nexport function parseAllSessions(): ParsedSession[] {\n return scanCodexSessions()\n .map(parseCodexSession)\n .filter((s): s is ParsedSession => s !== null);\n}\n\n// ---------------------------------------------------------------------------\n// Date/timezone helpers\n// ---------------------------------------------------------------------------\n\nconst TZ_OFFSETS: Record<string, number> = {\n 'Asia/Shanghai': 8,\n 'Asia/Tokyo': 9,\n 'America/New_York': -5,\n 'America/Los_Angeles': -8,\n 'Europe/London': 0,\n 'UTC': 0,\n};\n\nfunction getTzOffsetHours(tz: string): number {\n return TZ_OFFSETS[tz] ?? 8; // Default Asia/Shanghai\n}\n\nfunction toLocalISO(ts: string, tz: string): Date {\n const d = new Date(ts);\n return new Date(d.getTime() + getTzOffsetHours(tz) * 3600_000);\n}\n\nfunction getDateKey(ts: string, tz: string): string {\n return toLocalISO(ts, tz).toISOString().slice(0, 10);\n}\n\nfunction getHourKey(ts: string, tz: string): string {\n const local = toLocalISO(ts, tz);\n return local.toISOString().slice(0, 13).replace('T', ' ') + ':00';\n}\n\nfunction getMonthKey(ts: string, tz: string): string {\n return getDateKey(ts, tz).slice(0, 7);\n}\n\nfunction extractProjectName(cwd: string): string {\n if (!cwd) return 'unknown';\n const parts = cwd.replace(/\\/+$/, '').split('/');\n return parts[parts.length - 1] || 'unknown';\n}\n\n// ---------------------------------------------------------------------------\n// Core aggregation\n// ---------------------------------------------------------------------------\n\nfunction emptyAcc(): TokenAccumulator {\n return { inputTokens: 0, cachedInputTokens: 0, outputTokens: 0, reasoningOutputTokens: 0, totalTokens: 0 };\n}\n\nfunction addAcc(a: TokenAccumulator, ev: ParsedTokenEvent): void {\n a.inputTokens += ev.inputTokens;\n a.cachedInputTokens += ev.cachedInputTokens;\n a.outputTokens += ev.outputTokens;\n a.reasoningOutputTokens += ev.reasoningOutputTokens;\n a.totalTokens += ev.totalTokens;\n}\n\nfunction displayAcc(acc: TokenAccumulator): TokenAccumulator {\n return {\n ...acc,\n inputTokens: displayInputTokens(acc.inputTokens, acc.cachedInputTokens),\n };\n}\n\nfunction mergeAcc(a: TokenAccumulator, b: TokenAccumulator): void {\n a.inputTokens += b.inputTokens;\n a.cachedInputTokens += b.cachedInputTokens;\n a.outputTokens += b.outputTokens;\n a.reasoningOutputTokens += b.reasoningOutputTokens;\n a.totalTokens += b.totalTokens;\n}\n\nfunction addAccToBucket(bucket: AggregateBucket, ev: ParsedTokenEvent, model: string): void {\n addAcc(bucket.acc, ev);\n if (!model) return;\n if (!bucket.models.has(model)) bucket.models.set(model, emptyAcc());\n addAcc(bucket.models.get(model)!, ev);\n}\n\nfunction accToEntry(date: string, acc: TokenAccumulator, modelAccs: Map<string, TokenAccumulator>): DailyEntry {\n const display = displayAcc(acc);\n const modelNames = [...modelAccs.keys()];\n const modelBreakdowns = buildModelBreakdowns(modelAccs);\n const totalCost = modelBreakdowns.reduce((sum, model) => sum + model.cost, 0);\n return {\n date,\n inputTokens: display.inputTokens,\n outputTokens: display.outputTokens,\n cacheCreationTokens: 0,\n cacheReadTokens: display.cachedInputTokens,\n totalTokens: display.totalTokens,\n totalCost,\n modelsUsed: modelNames,\n modelBreakdowns,\n };\n}\n\nfunction buildModelBreakdowns(modelAccs: Map<string, TokenAccumulator>): ModelBreakdown[] {\n return [...modelAccs.entries()].map(([modelName, acc]) => {\n const display = displayAcc(acc);\n return {\n modelName,\n inputTokens: display.inputTokens,\n outputTokens: display.outputTokens,\n cacheCreationTokens: 0,\n cacheReadTokens: display.cachedInputTokens,\n cost: calculateCost(acc, new Set([modelName])),\n };\n });\n}\n\ntype GroupKey = string;\n\nfunction groupSessions(\n sessions: ParsedSession[],\n options: AggregateOptions,\n): Map<GroupKey, AggregateBucket> {\n const tz = options.timezone || 'Asia/Shanghai';\n const grouped = new Map<GroupKey, AggregateBucket>();\n\n for (const session of sessions) {\n if (options.project && extractProjectName(session.cwd) !== options.project) continue;\n\n for (const ev of session.tokenEvents) {\n const evDate = new Date(ev.timestamp);\n if (options.since && evDate < options.since) continue;\n if (options.until && evDate > options.until) continue;\n\n let key: string;\n switch (options.groupBy) {\n case 'hour': key = getHourKey(ev.timestamp, tz); break;\n case 'month': key = getMonthKey(ev.timestamp, tz); break;\n case 'session': key = session.id; break;\n case 'project': key = extractProjectName(session.cwd); break;\n default: key = getDateKey(ev.timestamp, tz); break;\n }\n\n if (!grouped.has(key)) {\n grouped.set(key, { acc: emptyAcc(), models: new Map() });\n }\n addAccToBucket(grouped.get(key)!, ev, session.model);\n }\n }\n\n return grouped;\n}\n\n// ---------------------------------------------------------------------------\n// Public API \u2014 response builders for route handlers\n// ---------------------------------------------------------------------------\n\nexport function buildCodexResponsesFromSessions(\n sessions: ParsedSession[],\n options?: Partial<AggregateOptions>,\n): { daily: DailyResponse; projects: ProjectsResponse; blocks: BlocksResponse } {\n return {\n daily: buildDailyResponse(sessions, options),\n projects: buildProjectsResponse(sessions, options),\n blocks: buildBlocksResponse(sessions, options),\n };\n}\n\nfunction buildDailyResponse(sessions: ParsedSession[], options?: Partial<AggregateOptions>): DailyResponse {\n const grouped = groupSessions(sessions, { groupBy: 'day', ...options });\n\n const daily: DailyEntry[] = [];\n const totalsAcc = emptyAcc();\n\n const totalModels = new Map<string, TokenAccumulator>();\n for (const [date, { acc, models }] of grouped) {\n daily.push(accToEntry(date, acc, models));\n mergeAcc(totalsAcc, acc);\n for (const [model, modelAcc] of models) {\n if (!totalModels.has(model)) totalModels.set(model, emptyAcc());\n mergeAcc(totalModels.get(model)!, modelAcc);\n }\n }\n\n daily.sort((a, b) => a.date.localeCompare(b.date));\n\n const totalCost = buildModelBreakdowns(totalModels).reduce((sum, model) => sum + model.cost, 0);\n\n return {\n daily,\n totals: {\n inputTokens: displayInputTokens(totalsAcc.inputTokens, totalsAcc.cachedInputTokens),\n outputTokens: totalsAcc.outputTokens,\n cacheCreationTokens: 0,\n cacheReadTokens: totalsAcc.cachedInputTokens,\n totalTokens: totalsAcc.totalTokens,\n totalCost,\n },\n };\n}\n\nfunction buildProjectsResponse(sessions: ParsedSession[], options?: Partial<AggregateOptions>): ProjectsResponse {\n const tz = options?.timezone || 'Asia/Shanghai';\n const projectGroups = new Map<string, Map<string, AggregateBucket>>();\n\n for (const session of sessions) {\n const projectName = extractProjectName(session.cwd);\n if (options?.project && projectName !== options.project) continue;\n if (!projectGroups.has(projectName)) projectGroups.set(projectName, new Map());\n const dailyMap = projectGroups.get(projectName)!;\n\n for (const ev of session.tokenEvents) {\n const evDate = new Date(ev.timestamp);\n if (options?.since && evDate < options.since) continue;\n if (options?.until && evDate > options.until) continue;\n\n const dayKey = getDateKey(ev.timestamp, tz);\n if (!dailyMap.has(dayKey)) {\n dailyMap.set(dayKey, { acc: emptyAcc(), models: new Map() });\n }\n addAccToBucket(dailyMap.get(dayKey)!, ev, session.model);\n }\n }\n\n const projects: Record<string, DailyEntry[]> = {};\n for (const [projectName, dailyMap] of projectGroups) {\n projects[projectName] = [...dailyMap.entries()]\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([date, { acc, models }]) => accToEntry(date, acc, models));\n }\n\n return { projects };\n}\n\nfunction buildBlocksResponse(sessions: ParsedSession[], options?: Partial<AggregateOptions>): BlocksResponse {\n const grouped = groupSessions(sessions, { groupBy: 'hour', ...options });\n\n const blocks: BlockEntry[] = [];\n let idx = 0;\n\n for (const [hourKey, { acc, models }] of grouped) {\n const cost = buildModelBreakdowns(models).reduce((sum, model) => sum + model.cost, 0);\n const [datePart, timePart] = hourKey.split(' ');\n const hour = timePart.split(':')[0];\n\n blocks.push({\n id: `codex-hour-${idx}`,\n startTime: `${datePart}T${hour}:00:00`,\n endTime: `${datePart}T${hour}:59:59`,\n actualEndTime: null,\n isActive: false,\n isGap: false,\n entries: acc.totalTokens > 0 ? 1 : 0,\n tokenCounts: {\n inputTokens: displayInputTokens(acc.inputTokens, acc.cachedInputTokens),\n outputTokens: acc.outputTokens,\n cacheCreationInputTokens: 0,\n cacheReadInputTokens: acc.cachedInputTokens,\n },\n totalTokens: acc.totalTokens,\n costUSD: cost,\n models: [...models.keys()],\n });\n idx++;\n }\n\n blocks.sort((a, b) => a.startTime.localeCompare(b.startTime));\n\n return { blocks };\n}\n\n/** Aggregate and return DailyResponse format (for /daily?agent=codex) */\nexport function getDailyResponse(options?: Partial<AggregateOptions>): DailyResponse {\n return buildDailyResponse(parseAllSessions(), options);\n}\n\n/** Aggregate and return ProjectsResponse format (for /projects?agent=codex) */\nexport function getProjectsResponse(options?: Partial<AggregateOptions>): ProjectsResponse {\n return buildProjectsResponse(parseAllSessions(), options);\n}\n\n/** Aggregate and return BlocksResponse format (hourly, for /blocks?agent=codex) */\nexport function getBlocksResponse(options?: Partial<AggregateOptions>): BlocksResponse {\n return buildBlocksResponse(parseAllSessions(), options);\n}\n", "/**\n * Codex token pricing configuration.\n *\n * Pricing formula (confirmed by reverse-engineering @ccusage/codex):\n * cost = (inputTokens - cachedInputTokens) * input_rate\n * + cachedInputTokens * cached_rate\n * + outputTokens * output_rate\n *\n * Reasoning tokens are NOT billed separately (included in outputTokens).\n *\n * Update rates from https://openai.com/api/pricing/ when models change.\n * All prices are USD per 1M tokens.\n */\n\ninterface ModelPricing {\n inputPer1M: number;\n cachedInputPer1M: number;\n outputPer1M: number;\n}\n\nconst MODEL_PRICING: Record<string, ModelPricing> = {\n 'gpt-5.4': {\n inputPer1M: 2.50,\n cachedInputPer1M: 0.25,\n outputPer1M: 15.00,\n },\n};\n\nconst DEFAULT_PRICING: ModelPricing = {\n inputPer1M: 2.50,\n cachedInputPer1M: 0.25,\n outputPer1M: 15.00,\n};\n\ninterface TokenCounts {\n inputTokens: number;\n cachedInputTokens: number;\n outputTokens: number;\n reasoningOutputTokens: number;\n totalTokens: number;\n}\n\n/**\n * Calculate cost in USD from token counts and model pricing.\n * Matches the @ccusage/codex calculateCostUSD function exactly.\n */\nexport function calculateCost(tokens: TokenCounts, models: Set<string>): number {\n const model = [...models][0] ?? '';\n const pricing = MODEL_PRICING[model] ?? DEFAULT_PRICING;\n\n const nonCachedInput = Math.max(tokens.inputTokens - tokens.cachedInputTokens, 0);\n const cachedInput = Math.min(tokens.cachedInputTokens, tokens.inputTokens);\n const outputTokens = tokens.outputTokens;\n\n const inputCost = (nonCachedInput / 1_000_000) * pricing.inputPer1M;\n const cachedCost = (cachedInput / 1_000_000) * pricing.cachedInputPer1M;\n const outputCost = (outputTokens / 1_000_000) * pricing.outputPer1M;\n\n return inputCost + cachedCost + outputCost;\n}\n\nexport function getModelPricing(model: string): ModelPricing {\n return MODEL_PRICING[model] ?? DEFAULT_PRICING;\n}\n", "import { readFileSync, readdirSync, statSync, accessSync, constants } from 'node:fs';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport type { DailyEntry, DailyResponse, ProjectsResponse, BlockEntry, BlocksResponse } from '../shared/types.js';\n\n// ---------------------------------------------------------------------------\n// OpenClaw JSONL format\n//\n// Each line in a session .jsonl file is one of:\n// { type: \"model_change\", provider: \"anthropic\", modelId: \"claude-opus-4-6\" }\n// { type: \"custom\", customType: \"model-snapshot\", data: { provider, modelId } }\n// { type: \"message\", message: { role, usage: { input, output, cacheRead, cacheWrite, cost: { total } }, timestamp (ms), model, provider } }\n//\n// sessions.json index:\n// { \"<key>\": { sessionId: \"...\", sessionFile?: \"...\" }, ... }\n// ---------------------------------------------------------------------------\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ninterface OpenClawTokenEvent {\n timestampMs: number;\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens: number;\n cacheWriteTokens: number;\n totalTokens: number;\n cost: number;\n model: string;\n}\n\ninterface OpenClawSession {\n id: string;\n agentId: string;\n tokenEvents: OpenClawTokenEvent[];\n}\n\ninterface TokenAccumulator {\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens: number;\n cacheWriteTokens: number;\n totalTokens: number;\n cost: number;\n}\n\n// ---------------------------------------------------------------------------\n// Directory helpers\n// ---------------------------------------------------------------------------\n\n/** All directories OpenClaw may have used (current + legacy names). */\nfunction getOpenClawDirs(): string[] {\n const home = homedir();\n return [\n join(home, '.openclaw'),\n join(home, '.clawdbot'), // legacy name 1\n join(home, '.moltbot'), // legacy name 2\n join(home, '.moldbot'), // legacy name 3\n ];\n}\n\nexport function isOpenClawAccessible(): boolean {\n for (const dir of getOpenClawDirs()) {\n try {\n accessSync(join(dir, 'agents'), constants.R_OK);\n return true;\n } catch {\n // try next\n }\n }\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// Session scanning\n// ---------------------------------------------------------------------------\n\ninterface SessionRef {\n sessionId: string;\n sessionFile: string; // absolute path to .jsonl\n agentId: string;\n}\n\n/** Scan all OpenClaw agent dirs and collect session file references. */\nexport function scanOpenClawSessions(): SessionRef[] {\n const refs: SessionRef[] = [];\n\n for (const baseDir of getOpenClawDirs()) {\n const agentsDir = join(baseDir, 'agents');\n let agentEntries: string[];\n try {\n agentEntries = readdirSync(agentsDir);\n } catch {\n continue;\n }\n\n for (const agentEntry of agentEntries) {\n const sessionsDir = join(agentsDir, agentEntry, 'sessions');\n const indexedPaths = new Set<string>();\n\n // Try sessions.json index first\n const indexPath = join(sessionsDir, 'sessions.json');\n try {\n const raw = readFileSync(indexPath, 'utf-8');\n const index = JSON.parse(raw) as Record<string, { sessionId?: string; sessionFile?: string }>;\n for (const entry of Object.values(index)) {\n if (!entry.sessionId) continue;\n let sessionPath: string;\n if (entry.sessionFile) {\n const filePath = entry.sessionFile;\n if (filePath.startsWith('/')) {\n // Validate absolute path stays within an OpenClaw directory\n if (!getOpenClawDirs().some(dir => filePath.startsWith(dir))) continue;\n sessionPath = filePath;\n } else {\n sessionPath = join(sessionsDir, filePath);\n }\n } else {\n sessionPath = join(sessionsDir, `${entry.sessionId}.jsonl`);\n }\n indexedPaths.add(sessionPath);\n refs.push({ sessionId: entry.sessionId, sessionFile: sessionPath, agentId: agentEntry });\n }\n } catch {\n // No sessions.json \u2014 will scan .jsonl files below\n }\n\n // Scan for .jsonl files not already covered by the index\n let files: string[];\n try {\n files = readdirSync(sessionsDir);\n } catch {\n continue;\n }\n for (const f of files) {\n if (!f.endsWith('.jsonl')) continue;\n const fullPath = join(sessionsDir, f);\n if (indexedPaths.has(fullPath)) continue;\n const sessionId = f.replace(/\\.jsonl.*$/, '');\n refs.push({ sessionId, sessionFile: fullPath, agentId: agentEntry });\n }\n }\n }\n\n return refs;\n}\n\n// ---------------------------------------------------------------------------\n// Session-level cache (mtime-based invalidation)\n// ---------------------------------------------------------------------------\n\nconst sessionCache = new Map<string, { mtime: number; result: OpenClawSession | null }>();\n\n// ---------------------------------------------------------------------------\n// JSONL parser\n// ---------------------------------------------------------------------------\n\nexport function parseOpenClawSession(ref: SessionRef): OpenClawSession | null {\n let fileMtimeMs = 0;\n try {\n fileMtimeMs = statSync(ref.sessionFile).mtimeMs;\n } catch { /* ok */ }\n\n // Return cached result if file hasn't changed\n const cached = sessionCache.get(ref.sessionFile);\n if (cached && cached.mtime === fileMtimeMs) {\n return cached.result;\n }\n\n let content: string;\n try {\n content = readFileSync(ref.sessionFile, 'utf-8');\n } catch {\n return null;\n }\n\n const tokenEvents: OpenClawTokenEvent[] = [];\n let currentModel = '';\n let currentProvider = '';\n\n for (const line of content.split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n\n let obj: Record<string, unknown>;\n try {\n obj = JSON.parse(trimmed) as Record<string, unknown>;\n } catch {\n continue;\n }\n\n const type = obj.type as string;\n\n if (type === 'model_change') {\n if (obj.modelId) currentModel = obj.modelId as string;\n if (obj.provider) currentProvider = obj.provider as string;\n continue;\n }\n\n if (type === 'custom' && (obj.customType as string) === 'model-snapshot') {\n const data = (obj.data as Record<string, unknown>) || {};\n if (data.modelId) currentModel = data.modelId as string;\n if (data.provider) currentProvider = data.provider as string;\n continue;\n }\n\n if (type === 'message') {\n const msg = (obj.message as Record<string, unknown>) || {};\n if ((msg.role as string) !== 'assistant') continue;\n\n const usage = (msg.usage as Record<string, unknown>) || {};\n if (!usage) continue;\n\n // Model: prefer embedded, fall back to tracked state\n const model = ((msg.model as string) || currentModel || '').trim();\n const provider = ((msg.provider as string) || currentProvider || '').trim();\n if (!model) continue; // can't attribute cost without a model\n\n // Update tracked state\n if (model) currentModel = model;\n if (provider) currentProvider = provider;\n\n const input = Number(usage.input ?? 0);\n const output = Number(usage.output ?? 0);\n const cacheRead = Number(usage.cacheRead ?? 0);\n const cacheWrite = Number(usage.cacheWrite ?? 0);\n const costObj = (usage.cost as Record<string, unknown>) || {};\n const cost = Number(costObj.total ?? 0);\n const timestampMs = Number(msg.timestamp ?? fileMtimeMs);\n\n tokenEvents.push({\n timestampMs,\n inputTokens: Math.max(0, input),\n outputTokens: Math.max(0, output),\n cacheReadTokens: Math.max(0, cacheRead),\n cacheWriteTokens: Math.max(0, cacheWrite),\n totalTokens: Math.max(0, input + output + cacheRead),\n cost: Math.max(0, cost),\n model: `${provider}/${model}`,\n });\n }\n }\n\n if (tokenEvents.length === 0) {\n sessionCache.set(ref.sessionFile, { mtime: fileMtimeMs, result: null });\n return null;\n }\n\n const result: OpenClawSession = { id: ref.sessionId, agentId: ref.agentId, tokenEvents };\n sessionCache.set(ref.sessionFile, { mtime: fileMtimeMs, result });\n return result;\n}\n\nexport function parseAllOpenClawSessions(): OpenClawSession[] {\n return scanOpenClawSessions()\n .map(parseOpenClawSession)\n .filter((s): s is OpenClawSession => s !== null);\n}\n\n// ---------------------------------------------------------------------------\n// Date / timezone helpers (same logic as codexParser)\n// ---------------------------------------------------------------------------\n\nconst TZ_OFFSETS: Record<string, number> = {\n 'Asia/Shanghai': 8,\n 'Asia/Tokyo': 9,\n 'America/New_York': -5,\n 'America/Los_Angeles': -8,\n 'Europe/London': 0,\n 'UTC': 0,\n};\n\nfunction getTzOffsetHours(tz: string): number {\n return TZ_OFFSETS[tz] ?? 8;\n}\n\nfunction msToLocalDate(ms: number, tz: string): Date {\n return new Date(ms + getTzOffsetHours(tz) * 3_600_000);\n}\n\nfunction getDateKey(ms: number, tz: string): string {\n return msToLocalDate(ms, tz).toISOString().slice(0, 10);\n}\n\nfunction getHourKey(ms: number, tz: string): string {\n const d = msToLocalDate(ms, tz);\n return d.toISOString().slice(0, 13).replace('T', ' ') + ':00';\n}\n\nfunction getMonthKey(ms: number, tz: string): string {\n return getDateKey(ms, tz).slice(0, 7);\n}\n\n// ---------------------------------------------------------------------------\n// Aggregation helpers\n// ---------------------------------------------------------------------------\n\nfunction emptyAcc(): TokenAccumulator {\n return { inputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0, totalTokens: 0, cost: 0 };\n}\n\nfunction addEvent(acc: TokenAccumulator, ev: OpenClawTokenEvent): void {\n acc.inputTokens += ev.inputTokens;\n acc.outputTokens += ev.outputTokens;\n acc.cacheReadTokens += ev.cacheReadTokens;\n acc.cacheWriteTokens += ev.cacheWriteTokens;\n acc.totalTokens += ev.totalTokens;\n acc.cost += ev.cost;\n}\n\nfunction mergeAcc(a: TokenAccumulator, b: TokenAccumulator): void {\n a.inputTokens += b.inputTokens;\n a.outputTokens += b.outputTokens;\n a.cacheReadTokens += b.cacheReadTokens;\n a.cacheWriteTokens += b.cacheWriteTokens;\n a.totalTokens += b.totalTokens;\n a.cost += b.cost;\n}\n\nfunction accToEntry(date: string, acc: TokenAccumulator, models: Set<string>): DailyEntry {\n const modelList = [...models];\n const costPerModel = modelList.length > 0 ? acc.cost / modelList.length : 0;\n return {\n date,\n inputTokens: acc.inputTokens,\n outputTokens: acc.outputTokens,\n cacheCreationTokens: acc.cacheWriteTokens,\n cacheReadTokens: acc.cacheReadTokens,\n totalTokens: acc.totalTokens,\n totalCost: acc.cost,\n modelsUsed: modelList,\n modelBreakdowns: modelList.map(name => ({\n modelName: name,\n inputTokens: acc.inputTokens,\n outputTokens: acc.outputTokens,\n cacheCreationTokens: acc.cacheWriteTokens,\n cacheReadTokens: acc.cacheReadTokens,\n cost: costPerModel,\n })),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Public API \u2014 mirrors codexParser's response builders\n// ---------------------------------------------------------------------------\n\nexport interface OpenClawAggregateOptions {\n groupBy?: 'day' | 'hour' | 'month' | 'session';\n since?: Date | null;\n until?: Date | null;\n timezone?: string;\n project?: string | null; // maps to agentId\n}\n\nexport function getDailyResponse(options?: OpenClawAggregateOptions): DailyResponse {\n const sessions = parseAllOpenClawSessions();\n const tz = options?.timezone || 'Asia/Shanghai';\n\n const grouped = new Map<string, { acc: TokenAccumulator; models: Set<string> }>();\n const totalsAcc = emptyAcc();\n\n for (const session of sessions) {\n if (options?.project && session.agentId !== options.project) continue;\n\n for (const ev of session.tokenEvents) {\n if (options?.since && ev.timestampMs < options.since.getTime()) continue;\n if (options?.until && ev.timestampMs > options.until.getTime()) continue;\n\n const key = getDateKey(ev.timestampMs, tz);\n if (!grouped.has(key)) grouped.set(key, { acc: emptyAcc(), models: new Set() });\n const entry = grouped.get(key)!;\n addEvent(entry.acc, ev);\n entry.models.add(ev.model);\n }\n }\n\n const daily: DailyEntry[] = [];\n for (const [date, { acc, models }] of grouped) {\n daily.push(accToEntry(date, acc, models));\n mergeAcc(totalsAcc, acc);\n }\n daily.sort((a, b) => a.date.localeCompare(b.date));\n\n return {\n daily,\n totals: {\n inputTokens: totalsAcc.inputTokens,\n outputTokens: totalsAcc.outputTokens,\n cacheCreationTokens: totalsAcc.cacheWriteTokens,\n cacheReadTokens: totalsAcc.cacheReadTokens,\n totalTokens: totalsAcc.totalTokens,\n totalCost: totalsAcc.cost,\n },\n };\n}\n\nexport function getProjectsResponse(options?: OpenClawAggregateOptions): ProjectsResponse {\n const sessions = parseAllOpenClawSessions();\n const tz = options?.timezone || 'Asia/Shanghai';\n const projects: Record<string, DailyEntry[]> = {};\n\n for (const session of sessions) {\n const projectName = session.agentId;\n const dailyMap = new Map<string, { acc: TokenAccumulator; models: Set<string> }>();\n\n for (const ev of session.tokenEvents) {\n if (options?.since && ev.timestampMs < options.since.getTime()) continue;\n if (options?.until && ev.timestampMs > options.until.getTime()) continue;\n\n const dayKey = getDateKey(ev.timestampMs, tz);\n if (!dailyMap.has(dayKey)) dailyMap.set(dayKey, { acc: emptyAcc(), models: new Set() });\n addEvent(dailyMap.get(dayKey)!.acc, ev);\n dailyMap.get(dayKey)!.models.add(ev.model);\n }\n\n if (!projects[projectName]) projects[projectName] = [];\n for (const [date, { acc, models }] of dailyMap) {\n projects[projectName].push(accToEntry(date, acc, models));\n }\n }\n\n for (const key of Object.keys(projects)) {\n projects[key].sort((a, b) => a.date.localeCompare(b.date));\n }\n\n return { projects };\n}\n\nexport function getBlocksResponse(options?: OpenClawAggregateOptions): BlocksResponse {\n const sessions = parseAllOpenClawSessions();\n const tz = options?.timezone || 'Asia/Shanghai';\n\n const grouped = new Map<string, { acc: TokenAccumulator; models: Set<string> }>();\n\n for (const session of sessions) {\n if (options?.project && session.agentId !== options.project) continue;\n\n for (const ev of session.tokenEvents) {\n if (options?.since && ev.timestampMs < options.since.getTime()) continue;\n if (options?.until && ev.timestampMs > options.until.getTime()) continue;\n\n const key = getHourKey(ev.timestampMs, tz);\n if (!grouped.has(key)) grouped.set(key, { acc: emptyAcc(), models: new Set() });\n addEvent(grouped.get(key)!.acc, ev);\n grouped.get(key)!.models.add(ev.model);\n }\n }\n\n const blocks: BlockEntry[] = [];\n let idx = 0;\n\n for (const [hourKey, { acc, models }] of grouped) {\n const [datePart, timePart] = hourKey.split(' ');\n const hour = timePart.split(':')[0];\n blocks.push({\n id: `openclaw-hour-${idx}`,\n startTime: `${datePart}T${hour}:00:00`,\n endTime: `${datePart}T${hour}:59:59`,\n actualEndTime: null,\n isActive: false,\n isGap: false,\n entries: acc.totalTokens > 0 ? 1 : 0,\n tokenCounts: {\n inputTokens: acc.inputTokens,\n outputTokens: acc.outputTokens,\n cacheCreationInputTokens: acc.cacheWriteTokens,\n cacheReadInputTokens: acc.cacheReadTokens,\n },\n totalTokens: acc.totalTokens,\n costUSD: acc.cost,\n models: [...models],\n });\n idx++;\n }\n\n blocks.sort((a, b) => a.startTime.localeCompare(b.startTime));\n return { blocks };\n}\n", "import { existsSync } from 'node:fs';\nimport { execSync } from 'node:child_process';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport type { DailyEntry, DailyResponse, ProjectsResponse, BlockEntry, BlocksResponse } from '../shared/types.js';\n\n// ---------------------------------------------------------------------------\n// OpenCode SQLite format\n//\n// Database: ~/.local/share/opencode/opencode.db\n// Table: message\n// Column: data (JSON) with structure:\n// {\n// \"role\": \"assistant\",\n// \"time\": { \"created\": <ms>, \"completed\": <ms> },\n// \"modelID\": \"glm-4.7\",\n// \"providerID\": \"zhipuai-coding-plan\",\n// \"tokens\": { \"input\": N, \"output\": N, \"reasoning\": N, \"cache\": { \"read\": N, \"write\": N } },\n// \"cost\": N,\n// \"path\": { \"cwd\": \"/path/to/project\" }\n// }\n// ---------------------------------------------------------------------------\n\nconst OPENCODE_DB = join(homedir(), '.local', 'share', 'opencode', 'opencode.db');\n\n// ---------------------------------------------------------------------------\n// Detection\n// ---------------------------------------------------------------------------\n\nexport function isOpencodeAccessible(): boolean {\n return existsSync(OPENCODE_DB);\n}\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ninterface OpenCodeTokenEvent {\n timestampMs: number;\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens: number;\n cacheWriteTokens: number;\n totalTokens: number;\n cost: number;\n model: string;\n project: string;\n}\n\ninterface TokenAccumulator {\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens: number;\n cacheWriteTokens: number;\n totalTokens: number;\n cost: number;\n}\n\n// ---------------------------------------------------------------------------\n// SQLite query helper\n// ---------------------------------------------------------------------------\n\nfunction queryOpenCodeDB(sql: string): string {\n return execSync(`sqlite3 -json \"${OPENCODE_DB}\" \"${sql}\"`, {\n encoding: 'utf-8',\n maxBuffer: 50 * 1024 * 1024,\n timeout: 10000,\n });\n}\n\n// ---------------------------------------------------------------------------\n// Parse all token events from message table\n// ---------------------------------------------------------------------------\n\ninterface RawMessage {\n data: string;\n}\n\nexport function parseAllOpenCodeEvents(project?: string | null): OpenCodeTokenEvent[] {\n let sql = `SELECT data FROM message WHERE json_extract(data, '$.role') = 'assistant'`;\n if (project) {\n sql += ` AND json_extract(data, '$.path.cwd') = '${project.replace(/'/g, \"''\")}'`;\n }\n\n let raw: string;\n try {\n raw = queryOpenCodeDB(sql);\n } catch {\n return [];\n }\n\n let rows: RawMessage[];\n try {\n rows = JSON.parse(raw) as RawMessage[];\n } catch {\n return [];\n }\n\n const events: OpenCodeTokenEvent[] = [];\n\n for (const row of rows) {\n let data: Record<string, unknown>;\n try {\n data = JSON.parse(row.data) as Record<string, unknown>;\n } catch {\n continue;\n }\n\n const tokens = (data.tokens as Record<string, unknown>) || {};\n const cache = (tokens.cache as Record<string, unknown>) || {};\n const time = (data.time as Record<string, unknown>) || {};\n const path = (data.path as Record<string, unknown>) || {};\n\n const input = Number(tokens.input ?? 0);\n const output = Number(tokens.output ?? 0);\n const cacheRead = Number(cache.read ?? 0);\n const cacheWrite = Number(cache.write ?? 0);\n\n if (input === 0 && output === 0 && cacheRead === 0 && cacheWrite === 0) continue;\n\n events.push({\n timestampMs: Number(time.created ?? 0),\n inputTokens: Math.max(0, input),\n outputTokens: Math.max(0, output),\n cacheReadTokens: Math.max(0, cacheRead),\n cacheWriteTokens: Math.max(0, cacheWrite),\n totalTokens: Math.max(0, input + output + cacheRead),\n cost: Math.max(0, Number(data.cost ?? 0)),\n model: String(data.modelID ?? 'unknown'),\n project: String(path.cwd ?? ''),\n });\n }\n\n return events;\n}\n\n// ---------------------------------------------------------------------------\n// Date / timezone helpers (same logic as openclawParser)\n// ---------------------------------------------------------------------------\n\nconst TZ_OFFSETS: Record<string, number> = {\n 'Asia/Shanghai': 8,\n 'Asia/Tokyo': 9,\n 'America/New_York': -5,\n 'America/Los_Angeles': -8,\n 'Europe/London': 0,\n 'UTC': 0,\n};\n\nfunction getTzOffsetHours(tz: string): number {\n return TZ_OFFSETS[tz] ?? 8;\n}\n\nfunction msToLocalDate(ms: number, tz: string): Date {\n return new Date(ms + getTzOffsetHours(tz) * 3_600_000);\n}\n\nfunction getDateKey(ms: number, tz: string): string {\n return msToLocalDate(ms, tz).toISOString().slice(0, 10);\n}\n\nfunction getHourKey(ms: number, tz: string): string {\n const d = msToLocalDate(ms, tz);\n return d.toISOString().slice(0, 13).replace('T', ' ') + ':00';\n}\n\n// ---------------------------------------------------------------------------\n// Aggregation helpers\n// ---------------------------------------------------------------------------\n\nfunction emptyAcc(): TokenAccumulator {\n return { inputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0, totalTokens: 0, cost: 0 };\n}\n\nfunction addEvent(acc: TokenAccumulator, ev: OpenCodeTokenEvent): void {\n acc.inputTokens += ev.inputTokens;\n acc.outputTokens += ev.outputTokens;\n acc.cacheReadTokens += ev.cacheReadTokens;\n acc.cacheWriteTokens += ev.cacheWriteTokens;\n acc.totalTokens += ev.totalTokens;\n acc.cost += ev.cost;\n}\n\n// ---------------------------------------------------------------------------\n// Public API \u2014 mirrors openclawParser's response builders\n// ---------------------------------------------------------------------------\n\nexport interface OpenCodeAggregateOptions {\n project?: string | null;\n timezone?: string;\n}\n\nexport function getDailyResponse(options?: OpenCodeAggregateOptions): DailyResponse {\n const events = parseAllOpenCodeEvents(options?.project);\n const tz = options?.timezone || 'Asia/Shanghai';\n\n // Track per-day, per-model accumulators for correct breakdowns\n interface ModelAcc { inputTokens: number; outputTokens: number; cacheCreationTokens: number; cacheReadTokens: number; cost: number; }\n interface DayGroup { totals: TokenAccumulator; models: Map<string, ModelAcc>; }\n const grouped = new Map<string, DayGroup>();\n\n for (const ev of events) {\n const key = getDateKey(ev.timestampMs, tz);\n if (!grouped.has(key)) grouped.set(key, { totals: emptyAcc(), models: new Map() });\n const g = grouped.get(key)!;\n addEvent(g.totals, ev);\n\n if (!g.models.has(ev.model)) {\n g.models.set(ev.model, { inputTokens: 0, outputTokens: 0, cacheCreationTokens: 0, cacheReadTokens: 0, cost: 0 });\n }\n const m = g.models.get(ev.model)!;\n m.inputTokens += ev.inputTokens;\n m.outputTokens += ev.outputTokens;\n m.cacheCreationTokens += ev.cacheWriteTokens;\n m.cacheReadTokens += ev.cacheReadTokens;\n m.cost += ev.cost;\n }\n\n const totalsAcc = emptyAcc();\n const daily: DailyEntry[] = [];\n for (const [date, g] of grouped) {\n mergeAcc(totalsAcc, g.totals);\n const modelList = [...g.models.keys()];\n daily.push({\n date,\n inputTokens: g.totals.inputTokens,\n outputTokens: g.totals.outputTokens,\n cacheCreationTokens: g.totals.cacheWriteTokens,\n cacheReadTokens: g.totals.cacheReadTokens,\n totalTokens: g.totals.totalTokens,\n totalCost: g.totals.cost,\n modelsUsed: modelList,\n modelBreakdowns: modelList.map(name => {\n const m = g.models.get(name)!;\n return {\n modelName: name,\n inputTokens: m.inputTokens,\n outputTokens: m.outputTokens,\n cacheCreationTokens: m.cacheCreationTokens,\n cacheReadTokens: m.cacheReadTokens,\n cost: m.cost,\n };\n }),\n });\n }\n daily.sort((a, b) => a.date.localeCompare(b.date));\n\n return {\n daily,\n totals: {\n inputTokens: totalsAcc.inputTokens,\n outputTokens: totalsAcc.outputTokens,\n cacheCreationTokens: totalsAcc.cacheWriteTokens,\n cacheReadTokens: totalsAcc.cacheReadTokens,\n totalTokens: totalsAcc.totalTokens,\n totalCost: totalsAcc.cost,\n },\n };\n}\n\nfunction mergeAcc(a: TokenAccumulator, b: TokenAccumulator): void {\n a.inputTokens += b.inputTokens;\n a.outputTokens += b.outputTokens;\n a.cacheReadTokens += b.cacheReadTokens;\n a.cacheWriteTokens += b.cacheWriteTokens;\n a.totalTokens += b.totalTokens;\n a.cost += b.cost;\n}\n\nexport function getProjectsResponse(options?: OpenCodeAggregateOptions): ProjectsResponse {\n const events = parseAllOpenCodeEvents();\n const tz = options?.timezone || 'Asia/Shanghai';\n const projects: Record<string, DailyEntry[]> = {};\n\n for (const ev of events) {\n const projectName = ev.project || 'unknown';\n const dayKey = getDateKey(ev.timestampMs, tz);\n\n if (!projects[projectName]) projects[projectName] = [];\n\n // Find or create entry for this date in this project\n let dayEntry = projects[projectName].find(d => d.date === dayKey);\n if (!dayEntry) {\n dayEntry = {\n date: dayKey,\n inputTokens: 0,\n outputTokens: 0,\n cacheCreationTokens: 0,\n cacheReadTokens: 0,\n totalTokens: 0,\n totalCost: 0,\n modelsUsed: [],\n modelBreakdowns: [],\n };\n projects[projectName].push(dayEntry);\n }\n\n dayEntry.inputTokens += ev.inputTokens;\n dayEntry.outputTokens += ev.outputTokens;\n dayEntry.cacheCreationTokens += ev.cacheWriteTokens;\n dayEntry.cacheReadTokens += ev.cacheReadTokens;\n dayEntry.totalTokens += ev.totalTokens;\n dayEntry.totalCost += ev.cost;\n\n if (!dayEntry.modelsUsed.includes(ev.model)) {\n dayEntry.modelsUsed.push(ev.model);\n }\n\n // Update or add model breakdown\n let breakdown = dayEntry.modelBreakdowns.find(b => b.modelName === ev.model);\n if (!breakdown) {\n breakdown = {\n modelName: ev.model,\n inputTokens: 0,\n outputTokens: 0,\n cacheCreationTokens: 0,\n cacheReadTokens: 0,\n cost: 0,\n };\n dayEntry.modelBreakdowns.push(breakdown);\n }\n breakdown.inputTokens += ev.inputTokens;\n breakdown.outputTokens += ev.outputTokens;\n breakdown.cacheCreationTokens += ev.cacheWriteTokens;\n breakdown.cacheReadTokens += ev.cacheReadTokens;\n breakdown.cost += ev.cost;\n }\n\n for (const key of Object.keys(projects)) {\n projects[key].sort((a, b) => a.date.localeCompare(b.date));\n }\n\n return { projects };\n}\n\nexport function getBlocksResponse(options?: OpenCodeAggregateOptions): BlocksResponse {\n const events = parseAllOpenCodeEvents(options?.project);\n const tz = options?.timezone || 'Asia/Shanghai';\n\n const grouped = new Map<string, { acc: TokenAccumulator; models: Set<string> }>();\n\n for (const ev of events) {\n const key = getHourKey(ev.timestampMs, tz);\n if (!grouped.has(key)) grouped.set(key, { acc: emptyAcc(), models: new Set() });\n addEvent(grouped.get(key)!.acc, ev);\n grouped.get(key)!.models.add(ev.model);\n }\n\n const blocks: BlockEntry[] = [];\n let idx = 0;\n\n for (const [hourKey, { acc, models }] of grouped) {\n const [datePart, timePart] = hourKey.split(' ');\n const hour = timePart.split(':')[0];\n blocks.push({\n id: `opencode-hour-${idx}`,\n startTime: `${datePart}T${hour}:00:00`,\n endTime: `${datePart}T${hour}:59:59`,\n actualEndTime: null,\n isActive: false,\n isGap: false,\n entries: acc.totalTokens > 0 ? 1 : 0,\n tokenCounts: {\n inputTokens: acc.inputTokens,\n outputTokens: acc.outputTokens,\n cacheCreationInputTokens: acc.cacheWriteTokens,\n cacheReadInputTokens: acc.cacheReadTokens,\n },\n totalTokens: acc.totalTokens,\n costUSD: acc.cost,\n models: [...models],\n });\n idx++;\n }\n\n blocks.sort((a, b) => a.startTime.localeCompare(b.startTime));\n return { blocks };\n}\n", "import { readFileSync, readdirSync, statSync, existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport type { DailyEntry, DailyResponse, ProjectsResponse, Totals, BlockEntry } from '../shared/types.js';\n\n// ---------------------------------------------------------------------------\n// Model pricing (USD per 1M tokens)\n// Update from https://docs.anthropic.com/en/docs/about-claude/models when needed\n// ---------------------------------------------------------------------------\n\ninterface ModelPricing {\n inputPer1M: number;\n cacheCreationPer1M: number;\n cacheReadPer1M: number;\n outputPer1M: number;\n}\n\nconst MODEL_PRICING: Record<string, ModelPricing> = {\n // Claude 4.6\n 'claude-opus-4-6': { inputPer1M: 15, cacheCreationPer1M: 18.75, cacheReadPer1M: 1.50, outputPer1M: 75 },\n 'claude-sonnet-4-6': { inputPer1M: 3, cacheCreationPer1M: 3.75, cacheReadPer1M: 0.30, outputPer1M: 15 },\n // Claude 4.5\n 'claude-sonnet-4-5-20250514': { inputPer1M: 3, cacheCreationPer1M: 3.75, cacheReadPer1M: 0.30, outputPer1M: 15 },\n 'claude-haiku-4-5-20251001': { inputPer1M: 0.80, cacheCreationPer1M: 1, cacheReadPer1M: 0.08, outputPer1M: 4 },\n // Older Claude models\n 'claude-3-5-sonnet-20241022': { inputPer1M: 3, cacheCreationPer1M: 3.75, cacheReadPer1M: 0.30, outputPer1M: 15 },\n 'claude-3-5-haiku-20241022': { inputPer1M: 0.80, cacheCreationPer1M: 1, cacheReadPer1M: 0.08, outputPer1M: 4 },\n 'claude-3-opus-20240229': { inputPer1M: 15, cacheCreationPer1M: 18.75, cacheReadPer1M: 1.50, outputPer1M: 75 },\n 'claude-3-haiku-20240307': { inputPer1M: 0.25, cacheCreationPer1M: 0.30, cacheReadPer1M: 0.03, outputPer1M: 1.25 },\n};\n\nconst DEFAULT_PRICING: ModelPricing = { inputPer1M: 3, cacheCreationPer1M: 3.75, cacheReadPer1M: 0.30, outputPer1M: 15 };\n\nfunction getPricing(model: string): ModelPricing {\n // Try exact match first, then prefix match\n if (MODEL_PRICING[model]) return MODEL_PRICING[model];\n const lower = model.toLowerCase();\n for (const key of Object.keys(MODEL_PRICING)) {\n if (lower.startsWith(key) || lower.includes(key)) return MODEL_PRICING[key];\n }\n return DEFAULT_PRICING;\n}\n\nexport function calculateCost(inputTokens: number, cacheReadTokens: number, outputTokens: number, model: string, cacheCreationTokens = 0): number {\n const p = getPricing(model);\n return (inputTokens / 1_000_000) * p.inputPer1M\n + (cacheCreationTokens / 1_000_000) * p.cacheCreationPer1M\n + (cacheReadTokens / 1_000_000) * p.cacheReadPer1M\n + (outputTokens / 1_000_000) * p.outputPer1M;\n}\n\nfunction totalClaudeTokens(inputTokens: number, outputTokens: number, cacheCreationTokens: number, cacheReadTokens: number): number {\n return inputTokens + outputTokens + cacheCreationTokens + cacheReadTokens;\n}\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ninterface ParsedUsage {\n timestamp: string;\n model: string;\n inputTokens: number;\n outputTokens: number;\n cacheCreationTokens: number;\n cacheReadTokens: number;\n projectDir: string;\n}\n\n// ---------------------------------------------------------------------------\n// JSONL parsing with mtime cache\n// ---------------------------------------------------------------------------\n\nconst CLAUDE_PROJECTS_DIR = join(homedir(), '.claude', 'projects');\n\nconst fileCache = new Map<string, { mtime: number; entries: ParsedUsage[] }>();\n\nconst projectNameCache = new Map<string, string>();\n\n/** Decode Claude's encoded project directory name.\n * Claude encodes paths: /Users/foo/bar \u2192 -Users-foo-bar\n * Since '-' replaces '/' and project names can contain '-',\n * we use filesystem checks to find the correct last segment.\n */\nexport function extractProjectName(dirName: string): string {\n if (!dirName.startsWith('-')) return dirName;\n\n const cached = projectNameCache.get(dirName);\n if (cached) return cached;\n\n const segments = dirName.replace(/^-/, '').split('-').filter(Boolean);\n if (segments.length === 0) { projectNameCache.set(dirName, dirName); return dirName; }\n if (segments.length === 1) { projectNameCache.set(dirName, segments[0]); return segments[0]; }\n\n let bestName = segments[segments.length - 1];\n\n // Try from right: find the longest last segment that forms a valid path\n for (let splitAt = segments.length - 1; splitAt >= 1; splitAt--) {\n const parentSegments = segments.slice(0, splitAt);\n const candidateName = segments.slice(splitAt).join('-');\n\n // Build parent path, handling hidden directories (dot prefix)\n let parentPath = '/';\n let valid = true;\n for (const seg of parentSegments) {\n const regular = join(parentPath, seg);\n const hidden = join(parentPath, '.' + seg);\n if (existsSync(regular)) {\n parentPath = regular;\n } else if (existsSync(hidden)) {\n parentPath = hidden;\n } else {\n valid = false;\n break;\n }\n }\n\n if (!valid) continue;\n\n if (existsSync(join(parentPath, candidateName)) || existsSync(join(parentPath, '.' + candidateName))) {\n bestName = candidateName;\n break;\n }\n }\n\n projectNameCache.set(dirName, bestName);\n return bestName;\n}\n\nfunction matchesProject(dirName: string, filter: string): boolean {\n return extractProjectName(dirName) === extractProjectName(filter);\n}\n\nfunction findJsonlFiles(dir: string): string[] {\n const results: string[] = [];\n try {\n const entries = readdirSync(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.isDirectory()) {\n results.push(...findJsonlFiles(join(dir, entry.name)));\n } else if (entry.name.endsWith('.jsonl')) {\n results.push(join(dir, entry.name));\n }\n }\n } catch { /* skip unreadable dirs */ }\n return results;\n}\n\nfunction parseAllSessions(project?: string | null): ParsedUsage[] {\n if (!existsSync(CLAUDE_PROJECTS_DIR)) return [];\n\n const results: ParsedUsage[] = [];\n const projectDirs = readdirSync(CLAUDE_PROJECTS_DIR, { withFileTypes: true })\n .filter(d => d.isDirectory())\n .map(d => d.name);\n\n for (const dirName of projectDirs) {\n if (project && !matchesProject(dirName, project)) continue;\n\n const dirPath = join(CLAUDE_PROJECTS_DIR, dirName);\n const files = findJsonlFiles(dirPath);\n\n for (const filePath of files) {\n\n let mtime = 0;\n try { mtime = statSync(filePath).mtimeMs; } catch { /* ok */ }\n\n const cached = fileCache.get(filePath);\n if (cached && cached.mtime === mtime) {\n results.push(...cached.entries);\n continue;\n }\n\n const entries: ParsedUsage[] = [];\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 const trimmed = line.trim();\n if (!trimmed) continue;\n\n let obj: Record<string, unknown>;\n try { obj = JSON.parse(trimmed) as Record<string, unknown>; } catch { continue; }\n\n if (obj.type !== 'assistant' || !obj.message) continue;\n const msg = obj.message as Record<string, unknown>;\n const usage = (msg.usage as Record<string, number>) || {};\n\n const inputTokens = usage.input_tokens || 0;\n const outputTokens = usage.output_tokens || 0;\n const cacheCreationTokens = usage.cache_creation_input_tokens || 0;\n const cacheReadTokens = usage.cache_read_input_tokens || 0;\n const totalTokens = totalClaudeTokens(inputTokens, outputTokens, cacheCreationTokens, cacheReadTokens);\n\n if (totalTokens === 0) continue;\n\n entries.push({\n timestamp: obj.timestamp as string,\n model: (msg.model as string) || 'unknown',\n inputTokens,\n outputTokens,\n cacheCreationTokens,\n cacheReadTokens,\n projectDir: dirName,\n });\n }\n\n fileCache.set(filePath, { mtime, entries });\n results.push(...entries);\n }\n }\n\n return results;\n}\n\n// ---------------------------------------------------------------------------\n// Timezone helpers\n// ---------------------------------------------------------------------------\n\nconst TZ_OFFSETS: Record<string, number> = {\n 'Asia/Shanghai': 8,\n 'Asia/Tokyo': 9,\n 'America/New_York': -5,\n 'America/Los_Angeles': -8,\n 'Europe/London': 0,\n 'UTC': 0,\n};\n\nexport function getDateKey(timestamp: string, tz: string): string {\n const offset = (TZ_OFFSETS[tz] ?? 8) * 3_600_000;\n const d = new Date(new Date(timestamp).getTime() + offset);\n // Use UTC methods since we manually applied the timezone offset\n return `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')}`;\n}\n\nexport function getHourKey(timestamp: string, tz: string): string {\n const offset = (TZ_OFFSETS[tz] ?? 8) * 3_600_000;\n const d = new Date(new Date(timestamp).getTime() + offset);\n // Use UTC methods since we manually applied the timezone offset\n const yyyy = d.getUTCFullYear();\n const mm = String(d.getUTCMonth() + 1).padStart(2, '0');\n const dd = String(d.getUTCDate()).padStart(2, '0');\n const hh = String(d.getUTCHours()).padStart(2, '0');\n return `${yyyy}-${mm}-${dd}T${hh}`;\n}\n\n// ---------------------------------------------------------------------------\n// Aggregation helpers\n// ---------------------------------------------------------------------------\n\ninterface DayAgg {\n date: string;\n inputTokens: number;\n outputTokens: number;\n cacheCreationTokens: number;\n cacheReadTokens: number;\n totalTokens: number;\n totalCost: number;\n models: Map<string, { input: number; output: number; cacheCreation: number; cacheRead: number; cost: number }>;\n}\n\nfunction toDailyEntry(agg: DayAgg): DailyEntry {\n const modelBreakdowns = [...agg.models.entries()].map(([modelName, m]) => ({\n modelName,\n inputTokens: m.input,\n outputTokens: m.output,\n cacheCreationTokens: m.cacheCreation,\n cacheReadTokens: m.cacheRead,\n cost: m.cost,\n }));\n\n return {\n date: agg.date,\n inputTokens: agg.inputTokens,\n outputTokens: agg.outputTokens,\n cacheCreationTokens: agg.cacheCreationTokens,\n cacheReadTokens: agg.cacheReadTokens,\n totalTokens: agg.totalTokens,\n totalCost: Math.round(agg.totalCost * 10000) / 10000,\n modelsUsed: [...agg.models.keys()],\n modelBreakdowns,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_TZ = 'Asia/Shanghai';\n\nexport function getDailyResponse(project?: string | null, tz = DEFAULT_TZ): DailyResponse {\n const entries = parseAllSessions(project);\n const dayMap = new Map<string, DayAgg>();\n\n for (const e of entries) {\n const date = getDateKey(e.timestamp, tz);\n if (!dayMap.has(date)) {\n dayMap.set(date, {\n date, inputTokens: 0, outputTokens: 0, cacheCreationTokens: 0,\n cacheReadTokens: 0, totalTokens: 0, totalCost: 0,\n models: new Map(),\n });\n }\n const agg = dayMap.get(date)!;\n agg.inputTokens += e.inputTokens;\n agg.outputTokens += e.outputTokens;\n agg.cacheCreationTokens += e.cacheCreationTokens;\n agg.cacheReadTokens += e.cacheReadTokens;\n agg.totalTokens += totalClaudeTokens(e.inputTokens, e.outputTokens, e.cacheCreationTokens, e.cacheReadTokens);\n\n const cost = calculateCost(e.inputTokens, e.cacheReadTokens, e.outputTokens, e.model, e.cacheCreationTokens);\n agg.totalCost += cost;\n\n if (!agg.models.has(e.model)) {\n agg.models.set(e.model, { input: 0, output: 0, cacheCreation: 0, cacheRead: 0, cost: 0 });\n }\n const m = agg.models.get(e.model)!;\n m.input += e.inputTokens;\n m.output += e.outputTokens;\n m.cacheCreation += e.cacheCreationTokens;\n m.cacheRead += e.cacheReadTokens;\n m.cost += cost;\n }\n\n const daily = [...dayMap.values()].sort((a, b) => a.date.localeCompare(b.date)).map(toDailyEntry);\n const totals: Totals = daily.reduce((acc, d) => ({\n inputTokens: acc.inputTokens + d.inputTokens,\n outputTokens: acc.outputTokens + d.outputTokens,\n cacheCreationTokens: acc.cacheCreationTokens + d.cacheCreationTokens,\n cacheReadTokens: acc.cacheReadTokens + d.cacheReadTokens,\n totalTokens: acc.totalTokens + d.totalTokens,\n totalCost: acc.totalCost + d.totalCost,\n }), { inputTokens: 0, outputTokens: 0, cacheCreationTokens: 0, cacheReadTokens: 0, totalTokens: 0, totalCost: 0 });\n\n return { daily, totals };\n}\n\nexport function getProjectsResponse(tz = DEFAULT_TZ): ProjectsResponse {\n const entries = parseAllSessions();\n const projectMap = new Map<string, Map<string, DayAgg>>();\n\n for (const e of entries) {\n const date = getDateKey(e.timestamp, tz);\n const projectName = extractProjectName(e.projectDir);\n\n if (!projectMap.has(projectName)) {\n projectMap.set(projectName, new Map());\n }\n const dayMap = projectMap.get(projectName)!;\n\n if (!dayMap.has(date)) {\n dayMap.set(date, {\n date, inputTokens: 0, outputTokens: 0, cacheCreationTokens: 0,\n cacheReadTokens: 0, totalTokens: 0, totalCost: 0,\n models: new Map(),\n });\n }\n const agg = dayMap.get(date)!;\n agg.inputTokens += e.inputTokens;\n agg.outputTokens += e.outputTokens;\n agg.cacheCreationTokens += e.cacheCreationTokens;\n agg.cacheReadTokens += e.cacheReadTokens;\n agg.totalTokens += totalClaudeTokens(e.inputTokens, e.outputTokens, e.cacheCreationTokens, e.cacheReadTokens);\n\n const cost = calculateCost(e.inputTokens, e.cacheReadTokens, e.outputTokens, e.model, e.cacheCreationTokens);\n agg.totalCost += cost;\n\n if (!agg.models.has(e.model)) {\n agg.models.set(e.model, { input: 0, output: 0, cacheCreation: 0, cacheRead: 0, cost: 0 });\n }\n const m = agg.models.get(e.model)!;\n m.input += e.inputTokens;\n m.output += e.outputTokens;\n m.cacheCreation += e.cacheCreationTokens;\n m.cacheRead += e.cacheReadTokens;\n m.cost += cost;\n }\n\n const projects: Record<string, DailyEntry[]> = {};\n for (const [projectName, dayMap] of projectMap) {\n projects[projectName] = [...dayMap.values()]\n .sort((a, b) => a.date.localeCompare(b.date))\n .map(toDailyEntry);\n }\n\n return { projects };\n}\n\nexport function getBlocksResponse(project?: string | null, tz = DEFAULT_TZ): { blocks: BlockEntry[] } {\n const entries = parseAllSessions(project);\n const hourMap = new Map<string, {\n inputTokens: number; outputTokens: number; cacheCreationTokens: number;\n cacheReadTokens: number; costUSD: number; models: Set<string>;\n }>();\n\n for (const e of entries) {\n const hourKey = getHourKey(e.timestamp, tz);\n if (!hourMap.has(hourKey)) {\n hourMap.set(hourKey, {\n inputTokens: 0, outputTokens: 0, cacheCreationTokens: 0,\n cacheReadTokens: 0, costUSD: 0, models: new Set(),\n });\n }\n const bucket = hourMap.get(hourKey)!;\n bucket.inputTokens += e.inputTokens;\n bucket.outputTokens += e.outputTokens;\n bucket.cacheCreationTokens += e.cacheCreationTokens;\n bucket.cacheReadTokens += e.cacheReadTokens;\n bucket.costUSD += calculateCost(e.inputTokens, e.cacheReadTokens, e.outputTokens, e.model, e.cacheCreationTokens);\n bucket.models.add(e.model);\n }\n\n const blocks: BlockEntry[] = [];\n let idx = 0;\n for (const [hourKey, bucket] of hourMap) {\n const totalTokens = totalClaudeTokens(bucket.inputTokens, bucket.outputTokens, bucket.cacheCreationTokens, bucket.cacheReadTokens);\n blocks.push({\n id: `claude-${idx}`,\n startTime: `${hourKey}:00:00`,\n endTime: `${hourKey}:59:59`,\n actualEndTime: null,\n isActive: false,\n isGap: false,\n entries: totalTokens > 0 ? 1 : 0,\n tokenCounts: {\n inputTokens: bucket.inputTokens,\n outputTokens: bucket.outputTokens,\n cacheCreationInputTokens: bucket.cacheCreationTokens,\n cacheReadInputTokens: bucket.cacheReadTokens,\n },\n totalTokens,\n costUSD: Math.round(bucket.costUSD * 10000) / 10000,\n models: [...bucket.models],\n });\n idx++;\n }\n\n blocks.sort((a, b) => a.startTime.localeCompare(b.startTime));\n return { blocks };\n}\n", "import { type Request, type Response } from 'express';\nimport { cache } from '../cache.js';\nimport { validateDaily } from '../../shared/schemas.js';\nimport { getDailyResponse as getCodexDailyResponse } from '../codexParser.js';\nimport { getDailyResponse as getOpenClawDailyResponse } from '../openclawParser.js';\nimport { getDailyResponse as getOpencodeDailyResponse } from '../opencodeParser.js';\nimport { getDailyResponse as getClaudeDailyResponse } from '../claudeJsonlParser.js';\n\nexport async function getDaily(req: Request, res: Response): Promise<void> {\n const agent = req.query.agent as string || 'claude';\n const cacheKey = `daily:${agent}`;\n try {\n const cached = cache.get(cacheKey);\n if (cached) {\n res.json(cached);\n return;\n }\n\n // Stale-while-revalidate: return stale data, refresh in background\n const stale = cache.getStale(cacheKey);\n if (stale) {\n refreshDailyCache(agent, cacheKey);\n res.json(stale);\n return;\n }\n\n const data = await fetchDailyData(agent);\n cache.set(cacheKey, data);\n res.json(data);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n console.error('Error fetching daily data:', error);\n res.status(502).json({\n error: `Failed to fetch daily data from ${agent}`,\n hint: message,\n });\n }\n}\n\nfunction fetchDailyData(agent: string) {\n if (agent === 'codex') {\n return Promise.resolve(getCodexDailyResponse());\n } else if (agent === 'openclaw') {\n return Promise.resolve(validateDaily(getOpenClawDailyResponse()));\n } else if (agent === 'opencode') {\n return Promise.resolve(validateDaily(getOpencodeDailyResponse()));\n } else {\n // Claude Code: parse JSONL directly (fast, no CLI)\n return Promise.resolve(validateDaily(getClaudeDailyResponse()));\n }\n}\n\nfunction refreshDailyCache(agent: string, cacheKey: string): void {\n fetchDailyData(agent)\n .then(data => cache.set(cacheKey, data))\n .catch(err => console.error('Background refresh failed (daily):', err));\n}\n", "import { type Request, type Response } from 'express';\nimport { cache } from '../cache.js';\nimport { validateDaily } from '../../shared/schemas.js';\nimport { getDailyResponse as getClaudeDailyResponse } from '../claudeJsonlParser.js';\nimport { getDailyResponse as getCodexDailyResponse } from '../codexParser.js';\nimport { getDailyResponse as getOpenClawDailyResponse } from '../openclawParser.js';\n\nexport async function getMonthly(req: Request, res: Response): Promise<void> {\n const agent = req.query.agent as string || 'claude';\n const cacheKey = `monthly:${agent}`;\n try {\n const cached = cache.get(cacheKey);\n if (cached) {\n res.json(cached);\n return;\n }\n\n const stale = cache.getStale(cacheKey);\n if (stale) {\n res.json(stale);\n return;\n }\n\n // Monthly is same as daily for our parser (aggregated by date already)\n let data;\n if (agent === 'codex') {\n data = validateDaily(getCodexDailyResponse());\n } else if (agent === 'openclaw') {\n data = validateDaily(getOpenClawDailyResponse());\n } else {\n data = validateDaily(getClaudeDailyResponse());\n }\n\n cache.set(cacheKey, data);\n res.json(data);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n console.error('Error fetching monthly data:', error);\n res.status(502).json({\n error: 'Failed to fetch monthly data',\n hint: message,\n });\n }\n}\n", "import { type Request, type Response } from 'express';\nimport { cache } from '../cache.js';\nimport { validateDaily } from '../../shared/schemas.js';\nimport { getDailyResponse as getClaudeDailyResponse } from '../claudeJsonlParser.js';\nimport { getDailyResponse as getCodexDailyResponse } from '../codexParser.js';\nimport { getDailyResponse as getOpenClawDailyResponse } from '../openclawParser.js';\n\nexport async function getSession(req: Request, res: Response): Promise<void> {\n const agent = req.query.agent as string || 'claude';\n const cacheKey = `session:${agent}`;\n try {\n const cached = cache.get(cacheKey);\n if (cached) {\n res.json(cached);\n return;\n }\n\n const stale = cache.getStale(cacheKey);\n if (stale) {\n res.json(stale);\n return;\n }\n\n // Session data uses same daily aggregation\n let data;\n if (agent === 'codex') {\n data = validateDaily(getCodexDailyResponse());\n } else if (agent === 'openclaw') {\n data = validateDaily(getOpenClawDailyResponse());\n } else {\n data = validateDaily(getClaudeDailyResponse());\n }\n\n cache.set(cacheKey, data);\n res.json(data);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n console.error('Error fetching session data:', error);\n res.status(502).json({\n error: 'Failed to fetch session data',\n hint: message,\n });\n }\n}\n", "import { type Request, type Response } from 'express';\nimport { cache } from '../cache.js';\nimport { validateProjects } from '../../shared/schemas.js';\nimport { getProjectsResponse as getCodexProjectsResponse } from '../codexParser.js';\nimport { getProjectsResponse as getOpenClawProjectsResponse } from '../openclawParser.js';\nimport { getProjectsResponse as getOpencodeProjectsResponse } from '../opencodeParser.js';\nimport { getProjectsResponse as getClaudeProjectsResponse } from '../claudeJsonlParser.js';\n\nexport async function getProjects(req: Request, res: Response): Promise<void> {\n const agent = req.query.agent as string || 'claude';\n const cacheKey = `projects:${agent}`;\n try {\n const cached = cache.get(cacheKey);\n if (cached) {\n res.json(cached);\n return;\n }\n\n // Stale-while-revalidate\n const stale = cache.getStale(cacheKey);\n if (stale) {\n refreshProjectsCache(agent, cacheKey);\n res.json(stale);\n return;\n }\n\n const data = fetchProjectsData(agent);\n cache.set(cacheKey, data);\n res.json(data);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n console.error('Error fetching projects data:', error);\n res.status(502).json({\n error: `Failed to fetch projects data from ${agent}`,\n hint: message,\n });\n }\n}\n\nfunction fetchProjectsData(agent: string) {\n if (agent === 'codex') {\n return getCodexProjectsResponse();\n } else if (agent === 'openclaw') {\n return validateProjects(getOpenClawProjectsResponse());\n } else if (agent === 'opencode') {\n return validateProjects(getOpencodeProjectsResponse());\n } else {\n // Claude Code: parse JSONL directly (fast, no CLI)\n return validateProjects(getClaudeProjectsResponse());\n }\n}\n\nfunction refreshProjectsCache(agent: string, cacheKey: string): void {\n Promise.resolve()\n .then(() => { const data = fetchProjectsData(agent); cache.set(cacheKey, data); })\n .catch(err => console.error('Background refresh failed (projects):', err));\n}\n", "import { type Request, type Response } from 'express';\nimport { cache } from '../cache.js';\nimport { validateBlocks } from '../../shared/schemas.js';\nimport { getBlocksResponse as getCodexBlocksResponse } from '../codexParser.js';\nimport { getBlocksResponse as getOpenClawBlocksResponse } from '../openclawParser.js';\nimport { getBlocksResponse as getOpencodeBlocksResponse } from '../opencodeParser.js';\nimport { getBlocksResponse as getClaudeBlocksResponse } from '../claudeJsonlParser.js';\n\nexport async function getBlocks(req: Request, res: Response): Promise<void> {\n const agent = req.query.agent as string || 'claude';\n const project = req.query.project as string || undefined;\n\n try {\n const cacheKey = `blocks:${agent}:${project || 'all'}`;\n const cached = cache.get(cacheKey);\n if (cached) {\n res.json(cached);\n return;\n }\n\n // Stale-while-revalidate\n const stale = cache.getStale(cacheKey);\n if (stale) {\n refreshBlocksCache(agent, project, cacheKey);\n res.json(stale);\n return;\n }\n\n const data = fetchBlocksData(agent, project);\n cache.set(cacheKey, data);\n res.json(data);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n console.error('Error fetching blocks data:', error);\n res.status(502).json({\n error: 'Failed to fetch blocks data',\n hint: message,\n });\n }\n}\n\nfunction fetchBlocksData(agent: string, project?: string) {\n if (agent === 'openclaw') {\n return validateBlocks(getOpenClawBlocksResponse({ project: project || null }));\n } else if (agent === 'opencode') {\n return validateBlocks(getOpencodeBlocksResponse({ project: project || null }));\n } else if (agent === 'codex') {\n return validateBlocks(getCodexBlocksResponse({ project: project || null }));\n } else {\n // Claude Code: parse JSONL directly (fast, no CLI)\n return validateBlocks(getClaudeBlocksResponse(project || null));\n }\n}\n\nfunction refreshBlocksCache(agent: string, project: string | undefined, cacheKey: string): void {\n Promise.resolve()\n .then(() => { const data = fetchBlocksData(agent, project); cache.set(cacheKey, data); })\n .catch(err => console.error('Background refresh failed (blocks):', err));\n}\n", "import { readFileSync, readdirSync, statSync, existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { scanOpenClawSessions } from './openclawParser.js';\nimport type { AnalyticsResponse, ToolUsageEntry, DailyCodeChange, DailyToolCall, ProductivityKPIs } from '../shared/types.js';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ninterface ToolCallRecord {\n toolName: string; // normalized name\n timestamp: number; // ms epoch\n filePath?: string;\n linesAdded: number;\n linesDeleted: number;\n}\n\n// ---------------------------------------------------------------------------\n// Timezone helpers (same as other parsers)\n// ---------------------------------------------------------------------------\n\nconst TZ_OFFSETS: Record<string, number> = {\n 'Asia/Shanghai': 8,\n 'Asia/Tokyo': 9,\n 'America/New_York': -5,\n 'America/Los_Angeles': -8,\n 'Europe/London': 0,\n 'UTC': 0,\n};\n\nfunction getDateKey(ms: number, tz: string): string {\n const offset = (TZ_OFFSETS[tz] ?? 8) * 3_600_000;\n const d = new Date(ms + offset);\n return `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')}`;\n}\n\n// ---------------------------------------------------------------------------\n// Tool name normalization\n// ---------------------------------------------------------------------------\n\nexport function normalizeToolName(name: string): string {\n const lower = name.toLowerCase();\n if (lower.startsWith('mcp__')) {\n const parts = name.split('__');\n const serverPart = parts.length >= 3 ? parts[2] : 'mcp';\n return `MCP:${serverPart}`;\n }\n const mapping: Record<string, string> = {\n 'exec': 'Bash',\n 'read': 'Read',\n 'edit': 'Edit',\n 'write': 'Write',\n };\n return mapping[lower] || name;\n}\n\n// ---------------------------------------------------------------------------\n// Line counting\n// ---------------------------------------------------------------------------\n\nfunction countLines(text: string): number {\n if (!text) return 0;\n return text.split('\\n').length;\n}\n\n// ---------------------------------------------------------------------------\n// Claude Code session scanning & tool extraction\n// ---------------------------------------------------------------------------\n\nconst CLAUDE_PROJECTS_DIR = join(homedir(), '.claude', 'projects');\n\nconst projectNameCache = new Map<string, string>();\n\n/** Decode Claude's encoded project directory name.\n * Claude encodes paths: /Users/foo/bar \u2192 -Users-foo-bar\n * Since '-' replaces '/' and project names can contain '-',\n * we use filesystem checks to find the correct last segment.\n */\nfunction extractProjectName(dirName: string): string {\n if (!dirName.startsWith('-')) return dirName;\n\n const cached = projectNameCache.get(dirName);\n if (cached) return cached;\n\n const segments = dirName.replace(/^-/, '').split('-').filter(Boolean);\n if (segments.length === 0) { projectNameCache.set(dirName, dirName); return dirName; }\n if (segments.length === 1) { projectNameCache.set(dirName, segments[0]); return segments[0]; }\n\n let bestName = segments[segments.length - 1];\n\n for (let splitAt = segments.length - 1; splitAt >= 1; splitAt--) {\n const parentSegments = segments.slice(0, splitAt);\n const candidateName = segments.slice(splitAt).join('-');\n\n let parentPath = '/';\n let valid = true;\n for (const seg of parentSegments) {\n const regular = join(parentPath, seg);\n const hidden = join(parentPath, '.' + seg);\n if (existsSync(regular)) {\n parentPath = regular;\n } else if (existsSync(hidden)) {\n parentPath = hidden;\n } else {\n valid = false;\n break;\n }\n }\n\n if (!valid) continue;\n\n if (existsSync(join(parentPath, candidateName)) || existsSync(join(parentPath, '.' + candidateName))) {\n bestName = candidateName;\n break;\n }\n }\n\n projectNameCache.set(dirName, bestName);\n return bestName;\n}\n\nfunction matchesProject(dirName: string, filter: string): boolean {\n return extractProjectName(dirName) === extractProjectName(filter);\n}\n\n// Session-level cache (mtime-based)\nconst claudeSessionCache = new Map<string, { mtime: number; toolCalls: ToolCallRecord[] }>();\n\nexport function extractClaudeToolCalls(project?: string | null): ToolCallRecord[] {\n if (!existsSync(CLAUDE_PROJECTS_DIR)) return [];\n\n const results: ToolCallRecord[] = [];\n const projectDirs = readdirSync(CLAUDE_PROJECTS_DIR, { withFileTypes: true })\n .filter(d => d.isDirectory())\n .map(d => d.name);\n\n for (const dirName of projectDirs) {\n if (project && !matchesProject(dirName, project)) continue;\n\n const dirPath = join(CLAUDE_PROJECTS_DIR, dirName);\n let files: string[];\n try {\n files = readdirSync(dirPath).filter(f => f.endsWith('.jsonl'));\n } catch {\n continue;\n }\n\n for (const file of files) {\n const filePath = join(dirPath, file);\n\n let mtime = 0;\n try { mtime = statSync(filePath).mtimeMs; } catch { /* ok */ }\n\n const cached = claudeSessionCache.get(filePath);\n if (cached && cached.mtime === mtime) {\n results.push(...cached.toolCalls);\n continue;\n }\n\n const toolCalls: ToolCallRecord[] = [];\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 const trimmed = line.trim();\n if (!trimmed) continue;\n\n let obj: Record<string, unknown>;\n try { obj = JSON.parse(trimmed) as Record<string, unknown>; } catch { continue; }\n\n if (obj.type !== 'assistant' || !obj.message) continue;\n const msg = obj.message as Record<string, unknown>;\n const timestamp = new Date(obj.timestamp as string).getTime();\n const content_arr = msg.content as Array<Record<string, unknown>> | undefined;\n if (!content_arr) continue;\n\n for (const item of content_arr) {\n if (item.type !== 'tool_use') continue;\n\n const toolName = normalizeToolName(item.name as string);\n const input = (item.input as Record<string, unknown>) || {};\n\n let linesAdded = 0;\n let linesDeleted = 0;\n const filePath2 = (input.file_path as string) || undefined;\n\n if (toolName === 'Edit') {\n linesDeleted = countLines(input.old_string as string || '');\n linesAdded = countLines(input.new_string as string || '');\n } else if (toolName === 'Write') {\n linesAdded = countLines(input.content as string || '');\n }\n\n toolCalls.push({ toolName, timestamp, filePath: filePath2, linesAdded, linesDeleted });\n }\n }\n\n claudeSessionCache.set(filePath, { mtime, toolCalls });\n results.push(...toolCalls);\n }\n }\n\n return results;\n}\n\n// ---------------------------------------------------------------------------\n// OpenClaw tool extraction\n// ---------------------------------------------------------------------------\n\nconst openclawSessionCache = new Map<string, { mtime: number; toolCalls: ToolCallRecord[] }>();\n\nexport function extractOpenClawToolCalls(project?: string | null): ToolCallRecord[] {\n const results: ToolCallRecord[] = [];\n const refs = scanOpenClawSessions();\n\n for (const ref of refs) {\n if (project && ref.agentId !== project) continue;\n\n let mtime = 0;\n try { mtime = statSync(ref.sessionFile).mtimeMs; } catch { /* ok */ }\n\n const cached = openclawSessionCache.get(ref.sessionFile);\n if (cached && cached.mtime === mtime) {\n results.push(...cached.toolCalls);\n continue;\n }\n\n const toolCalls: ToolCallRecord[] = [];\n let content: string;\n try {\n content = readFileSync(ref.sessionFile, 'utf-8');\n } catch {\n continue;\n }\n\n for (const line of content.split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n\n let obj: Record<string, unknown>;\n try { obj = JSON.parse(trimmed) as Record<string, unknown>; } catch { continue; }\n\n if (obj.type !== 'message') continue;\n const msg = obj.message as Record<string, unknown>;\n if (msg.role !== 'assistant') continue;\n\n const timestamp = Number(msg.timestamp ?? 0);\n const content_arr = msg.content as Array<Record<string, unknown>> | undefined;\n if (!content_arr) continue;\n\n for (const item of content_arr) {\n if (item.type !== 'toolCall') continue;\n\n const toolName = normalizeToolName(item.name as string);\n const args = (item.arguments as Record<string, unknown>) || {};\n\n let linesAdded = 0;\n let linesDeleted = 0;\n const filePath2 = (args.path as string) || undefined;\n\n if (toolName === 'Edit') {\n linesDeleted = countLines(args.oldText as string || '');\n linesAdded = countLines(args.newText as string || '');\n } else if (toolName === 'Write') {\n linesAdded = countLines(args.content as string || '');\n }\n\n toolCalls.push({ toolName, timestamp, filePath: filePath2, linesAdded, linesDeleted });\n }\n }\n\n openclawSessionCache.set(ref.sessionFile, { mtime, toolCalls });\n results.push(...toolCalls);\n }\n\n return results;\n}\n\n// ---------------------------------------------------------------------------\n// Analytics computation\n// ---------------------------------------------------------------------------\n\nexport function computeAnalytics(toolCalls: ToolCallRecord[], timezone = 'Asia/Shanghai'): AnalyticsResponse {\n // 1. Code Change Trend \u2014 group edit/write calls by date\n const changeMap = new Map<string, { added: number; deleted: number; files: Set<string> }>();\n for (const tc of toolCalls) {\n if (tc.linesAdded === 0 && tc.linesDeleted === 0) continue;\n const key = getDateKey(tc.timestamp, timezone);\n if (!changeMap.has(key)) changeMap.set(key, { added: 0, deleted: 0, files: new Set() });\n const entry = changeMap.get(key)!;\n entry.added += tc.linesAdded;\n entry.deleted += tc.linesDeleted;\n if (tc.filePath) entry.files.add(tc.filePath);\n }\n const codeChangeTrend: DailyCodeChange[] = [];\n for (const [date, { added, deleted, files }] of changeMap) {\n codeChangeTrend.push({ date, linesAdded: added, linesDeleted: deleted, netChange: added - deleted, filesModified: files.size });\n }\n codeChangeTrend.sort((a, b) => a.date.localeCompare(b.date));\n\n // 2. Tool Usage Distribution \u2014 count per tool\n const toolCountMap = new Map<string, number>();\n for (const tc of toolCalls) {\n toolCountMap.set(tc.toolName, (toolCountMap.get(tc.toolName) || 0) + 1);\n }\n const toolUsageDistribution: ToolUsageEntry[] = [...toolCountMap.entries()]\n .map(([name, count]) => ({ name, count }))\n .sort((a, b) => b.count - a.count);\n\n // 3. Productivity KPIs\n const editCalls = toolCalls.filter(tc => tc.toolName === 'Edit' || tc.toolName === 'Write');\n const totalEdits = editCalls.length;\n const totalLinesChanged = editCalls.reduce((s, tc) => s + tc.linesAdded + tc.linesDeleted, 0);\n const totalLinesAdded = editCalls.reduce((s, tc) => s + tc.linesAdded, 0);\n const totalLinesDeleted = editCalls.reduce((s, tc) => s + tc.linesDeleted, 0);\n const uniqueFiles = new Set(editCalls.filter(tc => tc.filePath).map(tc => tc.filePath!));\n const editDates = new Set(editCalls.map(tc => getDateKey(tc.timestamp, timezone)));\n\n const productivityKPIs: ProductivityKPIs = {\n avgLinesPerEdit: totalEdits > 0 ? Math.round(totalLinesChanged / totalEdits) : 0,\n filesModifiedPerDay: editDates.size > 0 ? Math.round(uniqueFiles.size / editDates.size) : 0,\n addDeleteRatio: totalLinesDeleted > 0 ? Math.round((totalLinesAdded / totalLinesDeleted) * 100) / 100 : totalLinesAdded > 0 ? 1 : 0,\n totalEdits,\n totalFilesModified: uniqueFiles.size,\n activeDaysWithEdits: editDates.size,\n };\n\n // 4. Tool Call Trend \u2014 group all calls by (date, toolName)\n const trendMap = new Map<string, Map<string, number>>();\n for (const tc of toolCalls) {\n const date = getDateKey(tc.timestamp, timezone);\n if (!trendMap.has(date)) trendMap.set(date, new Map());\n const dayMap = trendMap.get(date)!;\n dayMap.set(tc.toolName, (dayMap.get(tc.toolName) || 0) + 1);\n }\n const toolCallTrend: DailyToolCall[] = [];\n for (const [date, dayMap] of trendMap) {\n const entry: DailyToolCall = { date };\n for (const [tool, count] of dayMap) {\n entry[tool] = count;\n }\n toolCallTrend.push(entry);\n }\n toolCallTrend.sort((a, b) => a.date.localeCompare(b.date));\n\n // Fill missing tool values with 0 so chart lines don't break\n if (toolCallTrend.length > 0) {\n const allTools = new Set<string>();\n for (const entry of toolCallTrend) {\n for (const key of Object.keys(entry)) {\n if (key !== 'date') allTools.add(key);\n }\n }\n for (const entry of toolCallTrend) {\n for (const tool of allTools) {\n if (entry[tool] === undefined) {\n entry[tool] = 0;\n }\n }\n }\n }\n\n return { codeChangeTrend, toolUsageDistribution, productivityKPIs, toolCallTrend };\n}\n", "import { type Request, type Response } from 'express';\nimport { cache } from '../cache.js';\nimport { validateAnalytics } from '../../shared/schemas.js';\nimport { extractClaudeToolCalls, extractOpenClawToolCalls, computeAnalytics } from '../analyticsParser.js';\n\nconst EMPTY_ANALYTICS = {\n codeChangeTrend: [],\n toolUsageDistribution: [],\n productivityKPIs: { avgLinesPerEdit: 0, filesModifiedPerDay: 0, addDeleteRatio: 0, totalEdits: 0, totalFilesModified: 0, activeDaysWithEdits: 0 },\n toolCallTrend: [],\n};\n\nexport async function getAnalytics(req: Request, res: Response): Promise<void> {\n const agent = req.query.agent as string || 'claude';\n const project = req.query.project as string || undefined;\n\n if (agent === 'codex' || agent === 'opencode') {\n res.json(EMPTY_ANALYTICS);\n return;\n }\n\n try {\n const cacheKey = `analytics:${agent}:${project || 'all'}`;\n const cached = cache.get(cacheKey);\n if (cached) {\n res.json(cached);\n return;\n }\n\n const toolCalls = agent === 'openclaw'\n ? extractOpenClawToolCalls(project || null)\n : extractClaudeToolCalls(project || null);\n\n const data = computeAnalytics(toolCalls);\n const validated = validateAnalytics(data);\n cache.set(cacheKey, validated);\n res.json(validated);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n console.error('Error fetching analytics:', error);\n res.status(502).json({\n error: `Failed to fetch analytics from ${agent}`,\n hint: message,\n });\n }\n}\n", "import { existsSync, readdirSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\n\nconst CLAUDE_PROJECTS_DIR = join(homedir(), '.claude', 'projects');\nconst CODEX_SESSIONS_DIR = join(homedir(), '.codex', 'sessions');\n\nexport function isClaudeCodeAvailable(): boolean {\n if (!existsSync(CLAUDE_PROJECTS_DIR)) return false;\n try {\n const dirs = readdirSync(CLAUDE_PROJECTS_DIR, { withFileTypes: true });\n return dirs.some(d => d.isDirectory());\n } catch {\n return false;\n }\n}\n\nexport function isCodexAvailable(): boolean {\n return existsSync(CODEX_SESSIONS_DIR);\n}\n\nexport function isOpencodeAvailable(): boolean {\n return existsSync(join(homedir(), '.local', 'share', 'opencode', 'opencode.db'));\n}\n\nexport function detectAvailableAgents(): { claude: boolean; codex: boolean; opencode: boolean } {\n return {\n claude: isClaudeCodeAvailable(),\n codex: isCodexAvailable(),\n opencode: isOpencodeAvailable(),\n };\n}\n", "import { type Router, type Request, type Response } from 'express';\nimport { getDaily } from './daily.js';\nimport { getMonthly } from './monthly.js';\nimport { getSession } from './session.js';\nimport { getProjects } from './projects.js';\nimport { getBlocks } from './blocks.js';\nimport { getAnalytics } from './analytics.js';\nimport { detectAvailableAgents } from '../agentDetection.js';\nimport { isOpenClawAccessible } from '../openclawParser.js';\nimport { isOpencodeAccessible } from '../opencodeParser.js';\n\nexport interface AppInfo {\n packageName: string;\n version: string;\n dashboardUrl?: string;\n}\n\nfunction getAgents(_req: Request, res: Response): void {\n try {\n const agents = detectAvailableAgents();\n const available: string[] = [];\n if (agents.claude) available.push('claude');\n if (agents.codex) available.push('codex');\n if (isOpenClawAccessible()) available.push('openclaw');\n if (isOpencodeAccessible()) available.push('opencode');\n res.json({ available, default: available[0] || null });\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n res.status(500).json({ error: 'Failed to detect agents', hint: message });\n }\n}\n\nfunction getAppInfo(info: AppInfo): (_req: Request, res: Response) => void {\n return (req: Request, res: Response) => {\n const host = req.get('host');\n res.json({\n ...info,\n dashboardUrl: host ? `${req.protocol}://${host}` : info.dashboardUrl,\n });\n };\n}\n\nexport function registerApiRoutes(router: Router, appInfo: AppInfo): void {\n router.get('/app-info', getAppInfo(appInfo));\n router.get('/agents', getAgents);\n router.get('/daily', getDaily);\n router.get('/monthly', getMonthly);\n router.get('/session', getSession);\n router.get('/projects', getProjects);\n router.get('/blocks', getBlocks);\n router.get('/analytics', getAnalytics);\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["import_node_fs", "import_node_path", "import_node_fs", "import_node_path", "import_node_os", "import_zod", "import_node_fs", "import_node_path", "import_node_os", "TZ_OFFSETS", "getTzOffsetHours", "getDateKey", "getHourKey", "emptyAcc", "mergeAcc", "accToEntry", "getDailyResponse", "getDateKey", "getProjectsResponse", "getBlocksResponse", "getHourKey", "import_node_fs", "import_node_path", "import_node_os", "cache", "TZ_OFFSETS", "getTzOffsetHours", "msToLocalDate", "getDateKey", "getHourKey", "emptyAcc", "addEvent", "getDailyResponse", "mergeAcc", "getProjectsResponse", "getBlocksResponse", "import_node_fs", "import_node_path", "import_node_os", "MODEL_PRICING", "DEFAULT_PRICING", "calculateCost", "extractProjectName", "parseAllSessions", "TZ_OFFSETS", "getDateKey", "getHourKey", "getDailyResponse", "getProjectsResponse", "getBlocksResponse", "getDailyResponse", "getDailyResponse", "getDailyResponse", "getProjectsResponse", "getBlocksResponse", "import_node_fs", "import_node_path", "import_node_os", "TZ_OFFSETS", "getDateKey", "CLAUDE_PROJECTS_DIR", "projectNameCache", "extractProjectName", "matchesProject", "import_node_fs", "import_node_path", "import_node_os", "CLAUDE_PROJECTS_DIR", "resolve", "express", "
|
|
3
|
+
"sources": ["../src/server/index.ts", "../src/server/cache.ts", "../src/shared/schemas.ts", "../src/server/codexParser.ts", "../src/server/codexPricing.ts", "../src/server/openclawParser.ts", "../src/server/opencodeParser.ts", "../src/server/claudeJsonlParser.ts", "../src/server/routes/daily.ts", "../src/server/routes/monthly.ts", "../src/server/routes/session.ts", "../src/server/routes/projects.ts", "../src/server/routes/blocks.ts", "../src/server/analyticsParser.ts", "../src/server/routes/analytics.ts", "../src/server/agentDetection.ts", "../src/server/quota/adapter.ts", "../src/server/quota/cache.ts", "../src/server/quota/schemas.ts", "../src/server/quota/quotaService.ts", "../src/server/quota/adapters/codex.ts", "../src/server/quota/helpers.ts", "../src/server/quota/adapters/claude.ts", "../src/server/quota/adapters/glm.ts", "../src/server/quota/credentialsFile.ts", "../src/server/quota/adapters/minimax.ts", "../src/server/quota/adapters/kimi.ts", "../src/server/quota/index.ts", "../src/server/routes/api.ts"],
|
|
4
|
+
"sourcesContent": ["import express from 'express';\nimport type { Express } from 'express';\nimport { existsSync, readFileSync } from 'node:fs';\nimport type { Server } from 'node:http';\nimport { fileURLToPath } from 'node:url';\nimport { basename, dirname, join, resolve } from 'node:path';\nimport { registerApiRoutes } from './routes/api.js';\nimport { detectAvailableAgents } from './agentDetection.js';\n\ninterface CliArgs {\n port?: number;\n noOpen?: boolean;\n showVersion?: boolean;\n tray?: boolean;\n}\n\nconst CLI_USAGE = [\n 'Usage:',\n ' tokendash',\n ' tokendash --version',\n ' tokendash --port <number> [--no-open]',\n ' tokendash --tray [--port <number>]',\n].join('\\n');\n\nconst PACKAGE_NAME = '@zhangferry-dev/tokendash';\n\nfunction getPackageVersion(): string {\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = dirname(__filename);\n const packageJsonPaths = [\n join(__dirname, '..', '..', 'package.json'), // dist/server/index.js\n join(__dirname, '..', 'package.json'), // bundled server entrypoint\n ];\n\n for (const packageJsonPath of packageJsonPaths) {\n if (!existsSync(packageJsonPath)) continue;\n const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8')) as { version?: string };\n if (packageJson.version) return packageJson.version;\n }\n\n return 'unknown';\n}\n\nfunction exitWithCliError(message: string): never {\n console.error(message);\n console.error(`\\n${CLI_USAGE}`);\n process.exit(1);\n}\n\nfunction parseCliArgs(): CliArgs {\n const args = process.argv.slice(2);\n const result: CliArgs = {};\n\n if (args.length === 1 && (args[0] === '--version' || args[0] === '-v')) {\n result.showVersion = true;\n return result;\n }\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n\n if (arg === '--version' || arg === '-v') {\n exitWithCliError('The --version flag must be used by itself.');\n }\n\n if (arg === '--port') {\n if (i + 1 >= args.length) {\n exitWithCliError('Missing value for --port.');\n }\n\n const value = parseInt(args[i + 1], 10);\n if (!Number.isInteger(value) || value <= 0) {\n exitWithCliError(`Invalid port value: ${args[i + 1]}`);\n }\n\n result.port = value;\n i++;\n } else if (arg === '--no-open') {\n result.noOpen = true;\n } else if (arg === '--tray') {\n result.tray = true;\n } else {\n exitWithCliError(`Unsupported argument: ${arg}`);\n }\n }\n\n return result;\n}\n\nasync function ensureUsageSupportAvailable(): Promise<boolean> {\n try {\n const agents = detectAvailableAgents();\n if (!agents.claude && !agents.codex) {\n console.error('Error: No AI coding assistant data found.');\n console.error('\\nDetails: Could not find Claude Code (~/.claude/projects/) or Codex (~/.codex/sessions/) data.');\n console.error('Please install at least one of: Claude Code or Codex CLI.');\n return false;\n }\n if (agents.claude) console.log(' \u2713 Claude Code detected');\n if (agents.codex) console.log(' \u2713 Codex detected');\n return true;\n } catch (error) {\n console.error('Error: failed to detect available AI coding assistants');\n console.error('\\nDetails:', error instanceof Error ? error.message : error);\n return false;\n }\n}\n\nfunction resolvePort(value?: number): number {\n return Number.isInteger(value) && value && value > 0 ? value : 3456;\n}\n\nfunction listen(app: Express, port: number): Promise<Server> {\n return new Promise((resolve, reject) => {\n const server = app.listen(port);\n\n const handleListening = () => {\n cleanup();\n resolve(server);\n };\n\n const handleError = (error: Error) => {\n cleanup();\n reject(error);\n };\n\n const cleanup = () => {\n server.off('listening', handleListening);\n server.off('error', handleError);\n };\n\n server.once('listening', handleListening);\n server.once('error', handleError);\n });\n}\n\nasync function listenWithPortFallback(app: Express, preferredPort: number): Promise<{ server: Server; port: number; usedFallback: boolean }> {\n let port = preferredPort;\n\n for (let attempt = 0; attempt < 20; attempt++, port++) {\n try {\n const server = await listen(app, port);\n return { server, port, usedFallback: port !== preferredPort };\n } catch (error) {\n const err = error as NodeJS.ErrnoException;\n if (err.code !== 'EADDRINUSE') {\n throw error;\n }\n }\n }\n\n throw new Error(`Could not find an available port starting from ${preferredPort}`);\n}\n\nexport function resolveStaticAssetBaseDir(moduleUrl = import.meta.url, baseDir?: string): { baseDir: string; isProduction: boolean } {\n if (baseDir) return { baseDir: resolve(baseDir), isProduction: true };\n\n const moduleDir = dirname(fileURLToPath(moduleUrl));\n const isProduction = moduleUrl.includes('/dist/');\n\n if (!isProduction) return { baseDir: resolve(moduleDir), isProduction: false };\n\n // The CLI entrypoint runs from dist/server/index.js while the Vite assets are\n // emitted to dist/client. Resolve the production asset base to dist instead\n // of dist/server so / resolves to dist/client/index.html in installed npm\n // packages. The native app passes dist explicitly and is unaffected by this branch.\n if (basename(moduleDir) === 'server') {\n return { baseDir: resolve(dirname(moduleDir)), isProduction: true };\n }\n\n return { baseDir: resolve(moduleDir), isProduction: true };\n}\n\nexport function createApp(_port: number, baseDir?: string): Express {\n const app = express();\n const router = express.Router();\n\n // Register API routes\n registerApiRoutes(router, {\n packageName: PACKAGE_NAME,\n version: getPackageVersion(),\n dashboardUrl: `http://localhost:${resolvePort(_port)}`,\n });\n app.use('/api', router);\n\n const { baseDir: _baseDir, isProduction } = resolveStaticAssetBaseDir(import.meta.url, baseDir);\n const popoverPath = isProduction\n ? join(_baseDir, 'client', 'popover.html')\n : join(_baseDir, '..', '..', 'public', 'popover.html');\n\n app.get('/popover.html', (_req, res, next) => {\n if (!existsSync(popoverPath)) {\n next();\n return;\n }\n res.type('html').send(readFileSync(popoverPath, 'utf8'));\n });\n\n // Check if running from dist (production build)\n if (isProduction) {\n // Serve static files from client build\n const clientPath = join(_baseDir, 'client');\n const clientIndexPath = join(clientPath, 'index.html');\n\n app.use(express.static(clientPath));\n\n // SPA fallback\n app.use('{*path}', (_req, res) => {\n res.sendFile(clientIndexPath);\n });\n }\n\n return app;\n}\n\nasync function main() {\n const args = parseCliArgs();\n if (args.showVersion) {\n console.log(getPackageVersion());\n return;\n }\n\n const version = getPackageVersion();\n const preferredPort = resolvePort(args.port ?? (process.env.PORT ? parseInt(process.env.PORT, 10) : undefined));\n\n // --tray mode: launch native Swift menu bar app\n if (args.tray) {\n if (process.platform !== 'darwin') {\n console.error('Error: --tray is only supported on macOS.');\n process.exit(1);\n }\n console.log(`Starting tokendash v${version} in tray mode...`);\n const { spawn } = await import('node:child_process');\n const { resolve } = await import('node:path');\n const { existsSync } = await import('node:fs');\n\n // Find Swift binary: check packaged app first, then dev build\n const moduleDir = dirname(fileURLToPath(import.meta.url));\n const packagedPath = resolve(moduleDir, '..', '..', 'TokenDashSwift', '.build', 'debug', 'TokenDash');\n const devPath = resolve(moduleDir, '..', '..', 'TokenDashSwift', '.build', 'debug', 'TokenDash');\n const swiftBin = existsSync(packagedPath) ? packagedPath : devPath;\n\n if (!existsSync(swiftBin)) {\n console.error('Error: TokenDash Swift binary not found. Run \"npm run build:swift\" first.');\n process.exit(1);\n }\n\n const child = spawn(swiftBin, [], {\n env: {\n ...process.env,\n TOKENDASH_PORT: String(preferredPort),\n },\n stdio: 'inherit',\n });\n child.on('close', (code) => process.exit(code ?? 0));\n process.on('SIGTERM', () => child.kill('SIGTERM'));\n return;\n }\n\n const shouldOpenBrowser = !args.noOpen;\n\n console.log(`Starting tokendash v${version}...`);\n console.log(`Checking local usage data sources...`);\n\n const isUsageSupportAvailable = await ensureUsageSupportAvailable();\n if (!isUsageSupportAvailable) {\n process.exit(1);\n }\n\n const app = createApp(preferredPort);\n const { server, port, usedFallback } = await listenWithPortFallback(app, preferredPort);\n\n if (usedFallback) {\n console.warn(`tokendash detected that port ${preferredPort} is already in use, switched to http://localhost:${port}`);\n }\n\n console.log(`tokendash running on http://localhost:${port}`);\n console.log(`API available at http://localhost:${port}/api`);\n const isProduction = import.meta.url.includes('dist/');\n if (isProduction) {\n console.log('Serving production build');\n } else {\n console.log('Development mode - use \"npm run dev\" for full dev experience');\n }\n\n // Open browser if requested\n if (shouldOpenBrowser) {\n // Small delay to ensure server is ready\n setTimeout(async () => {\n console.log('Opening dashboard in your browser...');\n try {\n const { default: open } = await import('open');\n await open(`http://localhost:${port}`);\n } catch (err: any) {\n console.warn('Could not open browser:', err.message);\n }\n }, 100);\n } else {\n console.log('Browser auto-open disabled (--no-open)');\n }\n\n // Graceful shutdown\n process.on('SIGTERM', () => {\n server.close(() => {\n console.log('Server closed');\n process.exit(0);\n });\n });\n}\n\nexport { main };\n", "import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { tmpdir } from 'node:os';\n\nconst DEFAULT_TTL = 5 * 60 * 1000; // 5 minutes (fresh)\nconst DISK_TTL = 60 * 60 * 1000; // 1 hour (stale but usable)\n\nconst CACHE_DIR = join(tmpdir(), 'tokendash-cache');\n\ninterface CacheEntry<T> {\n data: T;\n expiresAt: number;\n updatedAt: number;\n}\n\nfunction diskPath(key: string): string {\n const safe = key.replace(/[^a-zA-Z0-9_-]/g, '_');\n return join(CACHE_DIR, `${safe}.json`);\n}\n\nclass Cache {\n private store = new Map<string, CacheEntry<unknown>>();\n\n get<T>(key: string): T | null {\n const entry = this.store.get(key);\n if (entry && Date.now() <= entry.expiresAt) {\n return entry.data as T;\n }\n return null;\n }\n\n /** Get data even if stale (for stale-while-revalidate) */\n getStale<T>(key: string): T | null {\n // Try memory first\n const entry = this.store.get(key);\n if (entry) return entry.data as T;\n\n // Try disk\n return this.readFromDisk<T>(key);\n }\n\n set<T>(key: string, data: T, ttl: number = DEFAULT_TTL): void {\n const entry: CacheEntry<T> = {\n data,\n expiresAt: Date.now() + ttl,\n updatedAt: Date.now(),\n };\n this.store.set(key, entry as CacheEntry<unknown>);\n this.writeToDisk(key, entry);\n }\n\n clear(): void {\n this.store.clear();\n }\n\n delete(key: string): boolean {\n return this.store.delete(key);\n }\n\n has(key: string): boolean {\n const entry = this.store.get(key);\n if (!entry) return false;\n if (Date.now() > entry.expiresAt) {\n this.store.delete(key);\n return false;\n }\n return true;\n }\n\n private writeToDisk<T>(key: string, entry: CacheEntry<T>): void {\n try {\n if (!existsSync(CACHE_DIR)) mkdirSync(CACHE_DIR, { recursive: true });\n writeFileSync(diskPath(key), JSON.stringify(entry), 'utf-8');\n } catch {\n // Disk cache is best-effort\n }\n }\n\n private readFromDisk<T>(key: string): T | null {\n try {\n const path = diskPath(key);\n if (!existsSync(path)) return null;\n const raw = readFileSync(path, 'utf-8');\n const entry = JSON.parse(raw) as CacheEntry<T>;\n // Only use disk cache if less than DISK_TTL old\n if (Date.now() - entry.updatedAt < DISK_TTL) {\n // Promote to memory cache (with 0 TTL so it'll be treated as stale)\n this.store.set(key, { ...entry, expiresAt: 0 } as CacheEntry<unknown>);\n return entry.data;\n }\n } catch {\n // Disk cache is best-effort\n }\n return null;\n }\n}\n\nexport const cache = new Cache();\nexport type { CacheEntry };\n", "import { z } from 'zod';\n\nexport const ModelBreakdownSchema = z.object({\n modelName: z.string(),\n inputTokens: z.number().default(0),\n outputTokens: z.number().default(0),\n cacheCreationTokens: z.number().default(0),\n cacheReadTokens: z.number().default(0),\n cost: z.number().default(0),\n});\n\nexport const DailyEntrySchema = z.object({\n date: z.string(),\n inputTokens: z.number().default(0),\n outputTokens: z.number().default(0),\n cacheCreationTokens: z.number().default(0),\n cacheReadTokens: z.number().default(0),\n totalTokens: z.number().default(0),\n totalCost: z.number().default(0),\n modelsUsed: z.array(z.string()).default([]),\n modelBreakdowns: z.array(ModelBreakdownSchema).default([]),\n});\n\nexport const TotalsSchema = z.object({\n inputTokens: z.number().default(0),\n outputTokens: z.number().default(0),\n cacheCreationTokens: z.number().default(0),\n cacheReadTokens: z.number().default(0),\n totalTokens: z.number().default(0),\n totalCost: z.number().default(0),\n});\n\nexport const DailyResponseSchema = z.object({\n daily: z.array(DailyEntrySchema).default([]),\n totals: TotalsSchema,\n});\n\nexport const ProjectEntrySchema = z.object({\n projectPath: z.string(),\n instances: z.array(DailyEntrySchema).default([]),\n});\n\nexport const ProjectsResponseSchema = z.object({\n projects: z.record(z.array(DailyEntrySchema).default([])).default({}),\n});\n\nexport function validateDaily(data: unknown) {\n return DailyResponseSchema.parse(data);\n}\n\nexport function validateProjects(data: unknown) {\n return ProjectsResponseSchema.parse(data);\n}\n\nconst BlockEntrySchema = z.object({\n id: z.string(),\n startTime: z.string(),\n endTime: z.string(),\n actualEndTime: z.string().nullable().default(null),\n isActive: z.boolean().default(false),\n isGap: z.boolean().default(false),\n entries: z.number().default(0),\n tokenCounts: z.object({\n inputTokens: z.number().default(0),\n outputTokens: z.number().default(0),\n cacheCreationInputTokens: z.number().default(0),\n cacheReadInputTokens: z.number().default(0),\n }).default({ inputTokens: 0, outputTokens: 0, cacheCreationInputTokens: 0, cacheReadInputTokens: 0 }),\n totalTokens: z.number().default(0),\n costUSD: z.number().default(0),\n models: z.array(z.string()).default([]),\n});\n\nexport const BlocksResponseSchema = z.object({\n blocks: z.array(BlockEntrySchema).default([]),\n});\n\nexport function validateBlocks(data: unknown) {\n return BlocksResponseSchema.parse(data);\n}\n\n// --- Analytics schemas ---\n\nconst DailyCodeChangeSchema = z.object({\n date: z.string(),\n linesAdded: z.number().default(0),\n linesDeleted: z.number().default(0),\n netChange: z.number().default(0),\n filesModified: z.number().default(0),\n});\n\nconst ToolUsageEntrySchema = z.object({\n name: z.string(),\n count: z.number().default(0),\n});\n\nconst ProductivityKPIsSchema = z.object({\n avgLinesPerEdit: z.number().default(0),\n filesModifiedPerDay: z.number().default(0),\n addDeleteRatio: z.number().default(0),\n totalEdits: z.number().default(0),\n totalFilesModified: z.number().default(0),\n activeDaysWithEdits: z.number().default(0),\n});\n\nconst AnalyticsResponseSchema = z.object({\n codeChangeTrend: z.array(DailyCodeChangeSchema).default([]),\n toolUsageDistribution: z.array(ToolUsageEntrySchema).default([]),\n productivityKPIs: ProductivityKPIsSchema,\n toolCallTrend: z.array(z.record(z.union([z.string(), z.number()]))).default([]),\n});\n\nexport function validateAnalytics(data: unknown) {\n return AnalyticsResponseSchema.parse(data);\n}\n", "import { readFileSync, readdirSync, statSync, accessSync, constants } from 'node:fs';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { z } from 'zod';\nimport type { DailyEntry, DailyResponse, ProjectsResponse, BlockEntry, BlocksResponse, ModelBreakdown } from '../shared/types.js';\nimport { calculateCost } from './codexPricing.js';\n\n// ---------------------------------------------------------------------------\n// Zod schemas for JSONL event validation (format change detector)\n// ---------------------------------------------------------------------------\n\nconst TokenUsageSchema = z.object({\n input_tokens: z.number().default(0),\n cached_input_tokens: z.number().default(0),\n output_tokens: z.number().default(0),\n reasoning_output_tokens: z.number().default(0),\n total_tokens: z.number().default(0),\n}).default({ input_tokens: 0, cached_input_tokens: 0, output_tokens: 0, reasoning_output_tokens: 0, total_tokens: 0 });\n\nconst TokenCountInfoSchema = z.object({\n total_token_usage: TokenUsageSchema,\n last_token_usage: TokenUsageSchema.optional(),\n}).nullable().default(null);\n\nconst TokenCountPayloadSchema = z.object({\n type: z.literal('token_count'),\n info: TokenCountInfoSchema,\n});\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface ParsedTokenEvent {\n timestamp: string;\n inputTokens: number;\n cachedInputTokens: number;\n outputTokens: number;\n reasoningOutputTokens: number;\n totalTokens: number;\n}\n\nexport interface ParsedSession {\n id: string;\n cwd: string;\n model: string;\n createdAt: string;\n tokenEvents: ParsedTokenEvent[];\n}\n\nexport interface AggregateOptions {\n groupBy: 'day' | 'hour' | 'month' | 'session' | 'project';\n project?: string | null;\n since?: Date | null;\n until?: Date | null;\n timezone?: string;\n}\n\ninterface TokenAccumulator {\n inputTokens: number;\n cachedInputTokens: number;\n outputTokens: number;\n reasoningOutputTokens: number;\n totalTokens: number;\n}\n\ninterface AggregateBucket {\n acc: TokenAccumulator;\n models: Map<string, TokenAccumulator>;\n}\n\nfunction subtractTokenUsage(\n current: z.infer<typeof TokenUsageSchema>,\n previous: z.infer<typeof TokenUsageSchema> | null,\n): ParsedTokenEvent {\n return {\n timestamp: '',\n inputTokens: Math.max(0, current.input_tokens - (previous?.input_tokens ?? 0)),\n cachedInputTokens: Math.max(0, current.cached_input_tokens - (previous?.cached_input_tokens ?? 0)),\n outputTokens: Math.max(0, current.output_tokens - (previous?.output_tokens ?? 0)),\n reasoningOutputTokens: Math.max(0, current.reasoning_output_tokens - (previous?.reasoning_output_tokens ?? 0)),\n totalTokens: Math.max(0, current.total_tokens - (previous?.total_tokens ?? 0)),\n };\n}\n\nfunction displayInputTokens(inputTokens: number, cachedInputTokens: number): number {\n return Math.max(0, inputTokens - cachedInputTokens);\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction getSessionsDir(): string {\n return join(homedir(), '.codex', 'sessions');\n}\n\nexport function isSessionsDirAccessible(): boolean {\n try {\n accessSync(getSessionsDir(), constants.R_OK);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Recursively find all .jsonl files under ~/.codex/sessions/\n */\nexport function scanCodexSessions(): string[] {\n const sessionsDir = getSessionsDir();\n const results: string[] = [];\n\n function walk(dir: string): void {\n let entries;\n try {\n entries = readdirSync(dir);\n } catch {\n return;\n }\n for (const entry of entries) {\n const full = join(dir, entry);\n let st: ReturnType<typeof statSync>;\n try {\n st = statSync(full);\n } catch {\n continue;\n }\n if (st.isDirectory()) {\n walk(full);\n } else if (entry.endsWith('.jsonl')) {\n results.push(full);\n }\n }\n }\n\n walk(sessionsDir);\n return results.sort();\n}\n\n/**\n * Parse a single Codex session JSONL file.\n *\n * Codex can emit duplicate token_count events for the same turn, with identical\n * total_token_usage and last_token_usage snapshots a few seconds apart. These\n * are repeated status updates, not separate billable usage records, so only the\n * first occurrence of each cumulative total_token_usage snapshot should count.\n */\nexport function parseCodexSession(filepath: string): ParsedSession | null {\n let content: string;\n try {\n content = readFileSync(filepath, 'utf-8');\n } catch {\n return null;\n }\n\n const lines = content.split('\\n');\n let sessionId = '';\n let cwd = '';\n let model = '';\n let createdAt = '';\n const tokenEvents: ParsedTokenEvent[] = [];\n let previousTotalUsage: z.infer<typeof TokenUsageSchema> | null = null;\n const seenTotalUsageSnapshots = new Set<string>();\n const seenUsageEvents = new Set<string>();\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n\n let obj: Record<string, unknown>;\n try {\n obj = JSON.parse(trimmed) as Record<string, unknown>;\n } catch {\n continue;\n }\n\n const type = obj.type as string;\n\n if (type === 'session_meta') {\n const payload = (obj.payload as Record<string, unknown>) || {};\n sessionId = (payload.id as string) || '';\n cwd = (payload.cwd as string) || '';\n createdAt = (payload.timestamp as string) || '';\n }\n\n if (type === 'turn_context') {\n const payload = (obj.payload as Record<string, unknown>) || {};\n if (!model && payload.model) {\n model = payload.model as string;\n }\n }\n\n // Extract token counts from event_msg with nested token_count payload.\n if (type === 'event_msg') {\n const payload = (obj.payload as Record<string, unknown>) || {};\n if (payload.type === 'token_count') {\n const timestamp = (obj.timestamp as string) || '';\n const parseResult = TokenCountPayloadSchema.safeParse(payload);\n if (!parseResult.success) {\n console.warn(`[codexParser] Schema validation failed in ${filepath}:`, parseResult.error.message);\n continue;\n }\n const info = parseResult.data.info;\n if (!info) continue;\n const totalUsageKey = [\n info.total_token_usage.input_tokens,\n info.total_token_usage.cached_input_tokens,\n info.total_token_usage.output_tokens,\n info.total_token_usage.reasoning_output_tokens,\n info.total_token_usage.total_tokens,\n ].join(':');\n if (seenTotalUsageSnapshots.has(totalUsageKey)) continue;\n seenTotalUsageSnapshots.add(totalUsageKey);\n\n const last = info.last_token_usage ?? info.total_token_usage;\n const rawEvent = info.last_token_usage\n ? subtractTokenUsage(last, null)\n : subtractTokenUsage(last, previousTotalUsage);\n previousTotalUsage = info.total_token_usage;\n\n if (rawEvent.inputTokens === 0 && rawEvent.cachedInputTokens === 0 && rawEvent.outputTokens === 0 && rawEvent.reasoningOutputTokens === 0) {\n continue;\n }\n\n const event = {\n ...rawEvent,\n timestamp,\n cachedInputTokens: Math.min(rawEvent.cachedInputTokens, rawEvent.inputTokens),\n };\n const eventKey = [\n timestamp,\n model,\n event.inputTokens,\n event.cachedInputTokens,\n event.outputTokens,\n event.reasoningOutputTokens,\n event.totalTokens,\n ].join(':');\n if (seenUsageEvents.has(eventKey)) {\n continue;\n }\n seenUsageEvents.add(eventKey);\n tokenEvents.push(event);\n }\n }\n }\n\n if (!sessionId) return null;\n\n return { id: sessionId, cwd, model, createdAt, tokenEvents };\n}\n\n/** Parse all Codex sessions. */\nexport function parseAllSessions(): ParsedSession[] {\n return scanCodexSessions()\n .map(parseCodexSession)\n .filter((s): s is ParsedSession => s !== null);\n}\n\n// ---------------------------------------------------------------------------\n// Date/timezone helpers\n// ---------------------------------------------------------------------------\n\nconst TZ_OFFSETS: Record<string, number> = {\n 'Asia/Shanghai': 8,\n 'Asia/Tokyo': 9,\n 'America/New_York': -5,\n 'America/Los_Angeles': -8,\n 'Europe/London': 0,\n 'UTC': 0,\n};\n\nfunction getTzOffsetHours(tz: string): number {\n return TZ_OFFSETS[tz] ?? 8; // Default Asia/Shanghai\n}\n\nfunction toLocalISO(ts: string, tz: string): Date {\n const d = new Date(ts);\n return new Date(d.getTime() + getTzOffsetHours(tz) * 3600_000);\n}\n\nfunction getDateKey(ts: string, tz: string): string {\n return toLocalISO(ts, tz).toISOString().slice(0, 10);\n}\n\nfunction getHourKey(ts: string, tz: string): string {\n const local = toLocalISO(ts, tz);\n return local.toISOString().slice(0, 13).replace('T', ' ') + ':00';\n}\n\nfunction getMonthKey(ts: string, tz: string): string {\n return getDateKey(ts, tz).slice(0, 7);\n}\n\nfunction extractProjectName(cwd: string): string {\n if (!cwd) return 'unknown';\n const parts = cwd.replace(/\\/+$/, '').split('/');\n return parts[parts.length - 1] || 'unknown';\n}\n\n// ---------------------------------------------------------------------------\n// Core aggregation\n// ---------------------------------------------------------------------------\n\nfunction emptyAcc(): TokenAccumulator {\n return { inputTokens: 0, cachedInputTokens: 0, outputTokens: 0, reasoningOutputTokens: 0, totalTokens: 0 };\n}\n\nfunction addAcc(a: TokenAccumulator, ev: ParsedTokenEvent): void {\n a.inputTokens += ev.inputTokens;\n a.cachedInputTokens += ev.cachedInputTokens;\n a.outputTokens += ev.outputTokens;\n a.reasoningOutputTokens += ev.reasoningOutputTokens;\n a.totalTokens += ev.totalTokens;\n}\n\nfunction displayAcc(acc: TokenAccumulator): TokenAccumulator {\n return {\n ...acc,\n inputTokens: displayInputTokens(acc.inputTokens, acc.cachedInputTokens),\n };\n}\n\nfunction mergeAcc(a: TokenAccumulator, b: TokenAccumulator): void {\n a.inputTokens += b.inputTokens;\n a.cachedInputTokens += b.cachedInputTokens;\n a.outputTokens += b.outputTokens;\n a.reasoningOutputTokens += b.reasoningOutputTokens;\n a.totalTokens += b.totalTokens;\n}\n\nfunction addAccToBucket(bucket: AggregateBucket, ev: ParsedTokenEvent, model: string): void {\n addAcc(bucket.acc, ev);\n if (!model) return;\n if (!bucket.models.has(model)) bucket.models.set(model, emptyAcc());\n addAcc(bucket.models.get(model)!, ev);\n}\n\nfunction accToEntry(date: string, acc: TokenAccumulator, modelAccs: Map<string, TokenAccumulator>): DailyEntry {\n const display = displayAcc(acc);\n const modelNames = [...modelAccs.keys()];\n const modelBreakdowns = buildModelBreakdowns(modelAccs);\n const totalCost = modelBreakdowns.reduce((sum, model) => sum + model.cost, 0);\n return {\n date,\n inputTokens: display.inputTokens,\n outputTokens: display.outputTokens,\n cacheCreationTokens: 0,\n cacheReadTokens: display.cachedInputTokens,\n totalTokens: display.totalTokens,\n totalCost,\n modelsUsed: modelNames,\n modelBreakdowns,\n };\n}\n\nfunction buildModelBreakdowns(modelAccs: Map<string, TokenAccumulator>): ModelBreakdown[] {\n return [...modelAccs.entries()].map(([modelName, acc]) => {\n const display = displayAcc(acc);\n return {\n modelName,\n inputTokens: display.inputTokens,\n outputTokens: display.outputTokens,\n cacheCreationTokens: 0,\n cacheReadTokens: display.cachedInputTokens,\n cost: calculateCost(acc, new Set([modelName])),\n };\n });\n}\n\ntype GroupKey = string;\n\nfunction groupSessions(\n sessions: ParsedSession[],\n options: AggregateOptions,\n): Map<GroupKey, AggregateBucket> {\n const tz = options.timezone || 'Asia/Shanghai';\n const grouped = new Map<GroupKey, AggregateBucket>();\n\n for (const session of sessions) {\n if (options.project && extractProjectName(session.cwd) !== options.project) continue;\n\n for (const ev of session.tokenEvents) {\n const evDate = new Date(ev.timestamp);\n if (options.since && evDate < options.since) continue;\n if (options.until && evDate > options.until) continue;\n\n let key: string;\n switch (options.groupBy) {\n case 'hour': key = getHourKey(ev.timestamp, tz); break;\n case 'month': key = getMonthKey(ev.timestamp, tz); break;\n case 'session': key = session.id; break;\n case 'project': key = extractProjectName(session.cwd); break;\n default: key = getDateKey(ev.timestamp, tz); break;\n }\n\n if (!grouped.has(key)) {\n grouped.set(key, { acc: emptyAcc(), models: new Map() });\n }\n addAccToBucket(grouped.get(key)!, ev, session.model);\n }\n }\n\n return grouped;\n}\n\n// ---------------------------------------------------------------------------\n// Public API \u2014 response builders for route handlers\n// ---------------------------------------------------------------------------\n\nexport function buildCodexResponsesFromSessions(\n sessions: ParsedSession[],\n options?: Partial<AggregateOptions>,\n): { daily: DailyResponse; projects: ProjectsResponse; blocks: BlocksResponse } {\n return {\n daily: buildDailyResponse(sessions, options),\n projects: buildProjectsResponse(sessions, options),\n blocks: buildBlocksResponse(sessions, options),\n };\n}\n\nfunction buildDailyResponse(sessions: ParsedSession[], options?: Partial<AggregateOptions>): DailyResponse {\n const grouped = groupSessions(sessions, { groupBy: 'day', ...options });\n\n const daily: DailyEntry[] = [];\n const totalsAcc = emptyAcc();\n\n const totalModels = new Map<string, TokenAccumulator>();\n for (const [date, { acc, models }] of grouped) {\n daily.push(accToEntry(date, acc, models));\n mergeAcc(totalsAcc, acc);\n for (const [model, modelAcc] of models) {\n if (!totalModels.has(model)) totalModels.set(model, emptyAcc());\n mergeAcc(totalModels.get(model)!, modelAcc);\n }\n }\n\n daily.sort((a, b) => a.date.localeCompare(b.date));\n\n const totalCost = buildModelBreakdowns(totalModels).reduce((sum, model) => sum + model.cost, 0);\n\n return {\n daily,\n totals: {\n inputTokens: displayInputTokens(totalsAcc.inputTokens, totalsAcc.cachedInputTokens),\n outputTokens: totalsAcc.outputTokens,\n cacheCreationTokens: 0,\n cacheReadTokens: totalsAcc.cachedInputTokens,\n totalTokens: totalsAcc.totalTokens,\n totalCost,\n },\n };\n}\n\nfunction buildProjectsResponse(sessions: ParsedSession[], options?: Partial<AggregateOptions>): ProjectsResponse {\n const tz = options?.timezone || 'Asia/Shanghai';\n const projectGroups = new Map<string, Map<string, AggregateBucket>>();\n\n for (const session of sessions) {\n const projectName = extractProjectName(session.cwd);\n if (options?.project && projectName !== options.project) continue;\n if (!projectGroups.has(projectName)) projectGroups.set(projectName, new Map());\n const dailyMap = projectGroups.get(projectName)!;\n\n for (const ev of session.tokenEvents) {\n const evDate = new Date(ev.timestamp);\n if (options?.since && evDate < options.since) continue;\n if (options?.until && evDate > options.until) continue;\n\n const dayKey = getDateKey(ev.timestamp, tz);\n if (!dailyMap.has(dayKey)) {\n dailyMap.set(dayKey, { acc: emptyAcc(), models: new Map() });\n }\n addAccToBucket(dailyMap.get(dayKey)!, ev, session.model);\n }\n }\n\n const projects: Record<string, DailyEntry[]> = {};\n for (const [projectName, dailyMap] of projectGroups) {\n projects[projectName] = [...dailyMap.entries()]\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([date, { acc, models }]) => accToEntry(date, acc, models));\n }\n\n return { projects };\n}\n\nfunction buildBlocksResponse(sessions: ParsedSession[], options?: Partial<AggregateOptions>): BlocksResponse {\n const grouped = groupSessions(sessions, { groupBy: 'hour', ...options });\n\n const blocks: BlockEntry[] = [];\n let idx = 0;\n\n for (const [hourKey, { acc, models }] of grouped) {\n const cost = buildModelBreakdowns(models).reduce((sum, model) => sum + model.cost, 0);\n const [datePart, timePart] = hourKey.split(' ');\n const hour = timePart.split(':')[0];\n\n blocks.push({\n id: `codex-hour-${idx}`,\n startTime: `${datePart}T${hour}:00:00`,\n endTime: `${datePart}T${hour}:59:59`,\n actualEndTime: null,\n isActive: false,\n isGap: false,\n entries: acc.totalTokens > 0 ? 1 : 0,\n tokenCounts: {\n inputTokens: displayInputTokens(acc.inputTokens, acc.cachedInputTokens),\n outputTokens: acc.outputTokens,\n cacheCreationInputTokens: 0,\n cacheReadInputTokens: acc.cachedInputTokens,\n },\n totalTokens: acc.totalTokens,\n costUSD: cost,\n models: [...models.keys()],\n });\n idx++;\n }\n\n blocks.sort((a, b) => a.startTime.localeCompare(b.startTime));\n\n return { blocks };\n}\n\n/** Aggregate and return DailyResponse format (for /daily?agent=codex) */\nexport function getDailyResponse(options?: Partial<AggregateOptions>): DailyResponse {\n return buildDailyResponse(parseAllSessions(), options);\n}\n\n/** Aggregate and return ProjectsResponse format (for /projects?agent=codex) */\nexport function getProjectsResponse(options?: Partial<AggregateOptions>): ProjectsResponse {\n return buildProjectsResponse(parseAllSessions(), options);\n}\n\n/** Aggregate and return BlocksResponse format (hourly, for /blocks?agent=codex) */\nexport function getBlocksResponse(options?: Partial<AggregateOptions>): BlocksResponse {\n return buildBlocksResponse(parseAllSessions(), options);\n}\n", "/**\n * Codex token pricing configuration.\n *\n * Pricing formula (confirmed by reverse-engineering @ccusage/codex):\n * cost = (inputTokens - cachedInputTokens) * input_rate\n * + cachedInputTokens * cached_rate\n * + outputTokens * output_rate\n *\n * Reasoning tokens are NOT billed separately (included in outputTokens).\n *\n * Update rates from https://openai.com/api/pricing/ when models change.\n * All prices are USD per 1M tokens.\n */\n\ninterface ModelPricing {\n inputPer1M: number;\n cachedInputPer1M: number;\n outputPer1M: number;\n}\n\nconst MODEL_PRICING: Record<string, ModelPricing> = {\n 'gpt-5.4': {\n inputPer1M: 2.50,\n cachedInputPer1M: 0.25,\n outputPer1M: 15.00,\n },\n};\n\nconst DEFAULT_PRICING: ModelPricing = {\n inputPer1M: 2.50,\n cachedInputPer1M: 0.25,\n outputPer1M: 15.00,\n};\n\ninterface TokenCounts {\n inputTokens: number;\n cachedInputTokens: number;\n outputTokens: number;\n reasoningOutputTokens: number;\n totalTokens: number;\n}\n\n/**\n * Calculate cost in USD from token counts and model pricing.\n * Matches the @ccusage/codex calculateCostUSD function exactly.\n */\nexport function calculateCost(tokens: TokenCounts, models: Set<string>): number {\n const model = [...models][0] ?? '';\n const pricing = MODEL_PRICING[model] ?? DEFAULT_PRICING;\n\n const nonCachedInput = Math.max(tokens.inputTokens - tokens.cachedInputTokens, 0);\n const cachedInput = Math.min(tokens.cachedInputTokens, tokens.inputTokens);\n const outputTokens = tokens.outputTokens;\n\n const inputCost = (nonCachedInput / 1_000_000) * pricing.inputPer1M;\n const cachedCost = (cachedInput / 1_000_000) * pricing.cachedInputPer1M;\n const outputCost = (outputTokens / 1_000_000) * pricing.outputPer1M;\n\n return inputCost + cachedCost + outputCost;\n}\n\nexport function getModelPricing(model: string): ModelPricing {\n return MODEL_PRICING[model] ?? DEFAULT_PRICING;\n}\n", "import { readFileSync, readdirSync, statSync, accessSync, constants } from 'node:fs';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport type { DailyEntry, DailyResponse, ProjectsResponse, BlockEntry, BlocksResponse } from '../shared/types.js';\n\n// ---------------------------------------------------------------------------\n// OpenClaw JSONL format\n//\n// Each line in a session .jsonl file is one of:\n// { type: \"model_change\", provider: \"anthropic\", modelId: \"claude-opus-4-6\" }\n// { type: \"custom\", customType: \"model-snapshot\", data: { provider, modelId } }\n// { type: \"message\", message: { role, usage: { input, output, cacheRead, cacheWrite, cost: { total } }, timestamp (ms), model, provider } }\n//\n// sessions.json index:\n// { \"<key>\": { sessionId: \"...\", sessionFile?: \"...\" }, ... }\n// ---------------------------------------------------------------------------\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ninterface OpenClawTokenEvent {\n timestampMs: number;\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens: number;\n cacheWriteTokens: number;\n totalTokens: number;\n cost: number;\n model: string;\n}\n\ninterface OpenClawSession {\n id: string;\n agentId: string;\n tokenEvents: OpenClawTokenEvent[];\n}\n\ninterface TokenAccumulator {\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens: number;\n cacheWriteTokens: number;\n totalTokens: number;\n cost: number;\n}\n\n// ---------------------------------------------------------------------------\n// Directory helpers\n// ---------------------------------------------------------------------------\n\n/** All directories OpenClaw may have used (current + legacy names). */\nfunction getOpenClawDirs(): string[] {\n const home = homedir();\n return [\n join(home, '.openclaw'),\n join(home, '.clawdbot'), // legacy name 1\n join(home, '.moltbot'), // legacy name 2\n join(home, '.moldbot'), // legacy name 3\n ];\n}\n\nexport function isOpenClawAccessible(): boolean {\n for (const dir of getOpenClawDirs()) {\n try {\n accessSync(join(dir, 'agents'), constants.R_OK);\n return true;\n } catch {\n // try next\n }\n }\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// Session scanning\n// ---------------------------------------------------------------------------\n\ninterface SessionRef {\n sessionId: string;\n sessionFile: string; // absolute path to .jsonl\n agentId: string;\n}\n\n/** Scan all OpenClaw agent dirs and collect session file references. */\nexport function scanOpenClawSessions(): SessionRef[] {\n const refs: SessionRef[] = [];\n\n for (const baseDir of getOpenClawDirs()) {\n const agentsDir = join(baseDir, 'agents');\n let agentEntries: string[];\n try {\n agentEntries = readdirSync(agentsDir);\n } catch {\n continue;\n }\n\n for (const agentEntry of agentEntries) {\n const sessionsDir = join(agentsDir, agentEntry, 'sessions');\n const indexedPaths = new Set<string>();\n\n // Try sessions.json index first\n const indexPath = join(sessionsDir, 'sessions.json');\n try {\n const raw = readFileSync(indexPath, 'utf-8');\n const index = JSON.parse(raw) as Record<string, { sessionId?: string; sessionFile?: string }>;\n for (const entry of Object.values(index)) {\n if (!entry.sessionId) continue;\n let sessionPath: string;\n if (entry.sessionFile) {\n const filePath = entry.sessionFile;\n if (filePath.startsWith('/')) {\n // Validate absolute path stays within an OpenClaw directory\n if (!getOpenClawDirs().some(dir => filePath.startsWith(dir))) continue;\n sessionPath = filePath;\n } else {\n sessionPath = join(sessionsDir, filePath);\n }\n } else {\n sessionPath = join(sessionsDir, `${entry.sessionId}.jsonl`);\n }\n indexedPaths.add(sessionPath);\n refs.push({ sessionId: entry.sessionId, sessionFile: sessionPath, agentId: agentEntry });\n }\n } catch {\n // No sessions.json \u2014 will scan .jsonl files below\n }\n\n // Scan for .jsonl files not already covered by the index\n let files: string[];\n try {\n files = readdirSync(sessionsDir);\n } catch {\n continue;\n }\n for (const f of files) {\n if (!f.endsWith('.jsonl')) continue;\n const fullPath = join(sessionsDir, f);\n if (indexedPaths.has(fullPath)) continue;\n const sessionId = f.replace(/\\.jsonl.*$/, '');\n refs.push({ sessionId, sessionFile: fullPath, agentId: agentEntry });\n }\n }\n }\n\n return refs;\n}\n\n// ---------------------------------------------------------------------------\n// Session-level cache (mtime-based invalidation)\n// ---------------------------------------------------------------------------\n\nconst sessionCache = new Map<string, { mtime: number; result: OpenClawSession | null }>();\n\n// ---------------------------------------------------------------------------\n// JSONL parser\n// ---------------------------------------------------------------------------\n\nexport function parseOpenClawSession(ref: SessionRef): OpenClawSession | null {\n let fileMtimeMs = 0;\n try {\n fileMtimeMs = statSync(ref.sessionFile).mtimeMs;\n } catch { /* ok */ }\n\n // Return cached result if file hasn't changed\n const cached = sessionCache.get(ref.sessionFile);\n if (cached && cached.mtime === fileMtimeMs) {\n return cached.result;\n }\n\n let content: string;\n try {\n content = readFileSync(ref.sessionFile, 'utf-8');\n } catch {\n return null;\n }\n\n const tokenEvents: OpenClawTokenEvent[] = [];\n let currentModel = '';\n let currentProvider = '';\n\n for (const line of content.split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n\n let obj: Record<string, unknown>;\n try {\n obj = JSON.parse(trimmed) as Record<string, unknown>;\n } catch {\n continue;\n }\n\n const type = obj.type as string;\n\n if (type === 'model_change') {\n if (obj.modelId) currentModel = obj.modelId as string;\n if (obj.provider) currentProvider = obj.provider as string;\n continue;\n }\n\n if (type === 'custom' && (obj.customType as string) === 'model-snapshot') {\n const data = (obj.data as Record<string, unknown>) || {};\n if (data.modelId) currentModel = data.modelId as string;\n if (data.provider) currentProvider = data.provider as string;\n continue;\n }\n\n if (type === 'message') {\n const msg = (obj.message as Record<string, unknown>) || {};\n if ((msg.role as string) !== 'assistant') continue;\n\n const usage = (msg.usage as Record<string, unknown>) || {};\n if (!usage) continue;\n\n // Model: prefer embedded, fall back to tracked state\n const model = ((msg.model as string) || currentModel || '').trim();\n const provider = ((msg.provider as string) || currentProvider || '').trim();\n if (!model) continue; // can't attribute cost without a model\n\n // Update tracked state\n if (model) currentModel = model;\n if (provider) currentProvider = provider;\n\n const input = Number(usage.input ?? 0);\n const output = Number(usage.output ?? 0);\n const cacheRead = Number(usage.cacheRead ?? 0);\n const cacheWrite = Number(usage.cacheWrite ?? 0);\n const costObj = (usage.cost as Record<string, unknown>) || {};\n const cost = Number(costObj.total ?? 0);\n const timestampMs = Number(msg.timestamp ?? fileMtimeMs);\n\n tokenEvents.push({\n timestampMs,\n inputTokens: Math.max(0, input),\n outputTokens: Math.max(0, output),\n cacheReadTokens: Math.max(0, cacheRead),\n cacheWriteTokens: Math.max(0, cacheWrite),\n totalTokens: Math.max(0, input + output + cacheRead),\n cost: Math.max(0, cost),\n model: `${provider}/${model}`,\n });\n }\n }\n\n if (tokenEvents.length === 0) {\n sessionCache.set(ref.sessionFile, { mtime: fileMtimeMs, result: null });\n return null;\n }\n\n const result: OpenClawSession = { id: ref.sessionId, agentId: ref.agentId, tokenEvents };\n sessionCache.set(ref.sessionFile, { mtime: fileMtimeMs, result });\n return result;\n}\n\nexport function parseAllOpenClawSessions(): OpenClawSession[] {\n return scanOpenClawSessions()\n .map(parseOpenClawSession)\n .filter((s): s is OpenClawSession => s !== null);\n}\n\n// ---------------------------------------------------------------------------\n// Date / timezone helpers (same logic as codexParser)\n// ---------------------------------------------------------------------------\n\nconst TZ_OFFSETS: Record<string, number> = {\n 'Asia/Shanghai': 8,\n 'Asia/Tokyo': 9,\n 'America/New_York': -5,\n 'America/Los_Angeles': -8,\n 'Europe/London': 0,\n 'UTC': 0,\n};\n\nfunction getTzOffsetHours(tz: string): number {\n return TZ_OFFSETS[tz] ?? 8;\n}\n\nfunction msToLocalDate(ms: number, tz: string): Date {\n return new Date(ms + getTzOffsetHours(tz) * 3_600_000);\n}\n\nfunction getDateKey(ms: number, tz: string): string {\n return msToLocalDate(ms, tz).toISOString().slice(0, 10);\n}\n\nfunction getHourKey(ms: number, tz: string): string {\n const d = msToLocalDate(ms, tz);\n return d.toISOString().slice(0, 13).replace('T', ' ') + ':00';\n}\n\nfunction getMonthKey(ms: number, tz: string): string {\n return getDateKey(ms, tz).slice(0, 7);\n}\n\n// ---------------------------------------------------------------------------\n// Aggregation helpers\n// ---------------------------------------------------------------------------\n\nfunction emptyAcc(): TokenAccumulator {\n return { inputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0, totalTokens: 0, cost: 0 };\n}\n\nfunction addEvent(acc: TokenAccumulator, ev: OpenClawTokenEvent): void {\n acc.inputTokens += ev.inputTokens;\n acc.outputTokens += ev.outputTokens;\n acc.cacheReadTokens += ev.cacheReadTokens;\n acc.cacheWriteTokens += ev.cacheWriteTokens;\n acc.totalTokens += ev.totalTokens;\n acc.cost += ev.cost;\n}\n\nfunction mergeAcc(a: TokenAccumulator, b: TokenAccumulator): void {\n a.inputTokens += b.inputTokens;\n a.outputTokens += b.outputTokens;\n a.cacheReadTokens += b.cacheReadTokens;\n a.cacheWriteTokens += b.cacheWriteTokens;\n a.totalTokens += b.totalTokens;\n a.cost += b.cost;\n}\n\nfunction accToEntry(date: string, acc: TokenAccumulator, models: Set<string>): DailyEntry {\n const modelList = [...models];\n const costPerModel = modelList.length > 0 ? acc.cost / modelList.length : 0;\n return {\n date,\n inputTokens: acc.inputTokens,\n outputTokens: acc.outputTokens,\n cacheCreationTokens: acc.cacheWriteTokens,\n cacheReadTokens: acc.cacheReadTokens,\n totalTokens: acc.totalTokens,\n totalCost: acc.cost,\n modelsUsed: modelList,\n modelBreakdowns: modelList.map(name => ({\n modelName: name,\n inputTokens: acc.inputTokens,\n outputTokens: acc.outputTokens,\n cacheCreationTokens: acc.cacheWriteTokens,\n cacheReadTokens: acc.cacheReadTokens,\n cost: costPerModel,\n })),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Public API \u2014 mirrors codexParser's response builders\n// ---------------------------------------------------------------------------\n\nexport interface OpenClawAggregateOptions {\n groupBy?: 'day' | 'hour' | 'month' | 'session';\n since?: Date | null;\n until?: Date | null;\n timezone?: string;\n project?: string | null; // maps to agentId\n}\n\nexport function getDailyResponse(options?: OpenClawAggregateOptions): DailyResponse {\n const sessions = parseAllOpenClawSessions();\n const tz = options?.timezone || 'Asia/Shanghai';\n\n const grouped = new Map<string, { acc: TokenAccumulator; models: Set<string> }>();\n const totalsAcc = emptyAcc();\n\n for (const session of sessions) {\n if (options?.project && session.agentId !== options.project) continue;\n\n for (const ev of session.tokenEvents) {\n if (options?.since && ev.timestampMs < options.since.getTime()) continue;\n if (options?.until && ev.timestampMs > options.until.getTime()) continue;\n\n const key = getDateKey(ev.timestampMs, tz);\n if (!grouped.has(key)) grouped.set(key, { acc: emptyAcc(), models: new Set() });\n const entry = grouped.get(key)!;\n addEvent(entry.acc, ev);\n entry.models.add(ev.model);\n }\n }\n\n const daily: DailyEntry[] = [];\n for (const [date, { acc, models }] of grouped) {\n daily.push(accToEntry(date, acc, models));\n mergeAcc(totalsAcc, acc);\n }\n daily.sort((a, b) => a.date.localeCompare(b.date));\n\n return {\n daily,\n totals: {\n inputTokens: totalsAcc.inputTokens,\n outputTokens: totalsAcc.outputTokens,\n cacheCreationTokens: totalsAcc.cacheWriteTokens,\n cacheReadTokens: totalsAcc.cacheReadTokens,\n totalTokens: totalsAcc.totalTokens,\n totalCost: totalsAcc.cost,\n },\n };\n}\n\nexport function getProjectsResponse(options?: OpenClawAggregateOptions): ProjectsResponse {\n const sessions = parseAllOpenClawSessions();\n const tz = options?.timezone || 'Asia/Shanghai';\n const projects: Record<string, DailyEntry[]> = {};\n\n for (const session of sessions) {\n const projectName = session.agentId;\n const dailyMap = new Map<string, { acc: TokenAccumulator; models: Set<string> }>();\n\n for (const ev of session.tokenEvents) {\n if (options?.since && ev.timestampMs < options.since.getTime()) continue;\n if (options?.until && ev.timestampMs > options.until.getTime()) continue;\n\n const dayKey = getDateKey(ev.timestampMs, tz);\n if (!dailyMap.has(dayKey)) dailyMap.set(dayKey, { acc: emptyAcc(), models: new Set() });\n addEvent(dailyMap.get(dayKey)!.acc, ev);\n dailyMap.get(dayKey)!.models.add(ev.model);\n }\n\n if (!projects[projectName]) projects[projectName] = [];\n for (const [date, { acc, models }] of dailyMap) {\n projects[projectName].push(accToEntry(date, acc, models));\n }\n }\n\n for (const key of Object.keys(projects)) {\n projects[key].sort((a, b) => a.date.localeCompare(b.date));\n }\n\n return { projects };\n}\n\nexport function getBlocksResponse(options?: OpenClawAggregateOptions): BlocksResponse {\n const sessions = parseAllOpenClawSessions();\n const tz = options?.timezone || 'Asia/Shanghai';\n\n const grouped = new Map<string, { acc: TokenAccumulator; models: Set<string> }>();\n\n for (const session of sessions) {\n if (options?.project && session.agentId !== options.project) continue;\n\n for (const ev of session.tokenEvents) {\n if (options?.since && ev.timestampMs < options.since.getTime()) continue;\n if (options?.until && ev.timestampMs > options.until.getTime()) continue;\n\n const key = getHourKey(ev.timestampMs, tz);\n if (!grouped.has(key)) grouped.set(key, { acc: emptyAcc(), models: new Set() });\n addEvent(grouped.get(key)!.acc, ev);\n grouped.get(key)!.models.add(ev.model);\n }\n }\n\n const blocks: BlockEntry[] = [];\n let idx = 0;\n\n for (const [hourKey, { acc, models }] of grouped) {\n const [datePart, timePart] = hourKey.split(' ');\n const hour = timePart.split(':')[0];\n blocks.push({\n id: `openclaw-hour-${idx}`,\n startTime: `${datePart}T${hour}:00:00`,\n endTime: `${datePart}T${hour}:59:59`,\n actualEndTime: null,\n isActive: false,\n isGap: false,\n entries: acc.totalTokens > 0 ? 1 : 0,\n tokenCounts: {\n inputTokens: acc.inputTokens,\n outputTokens: acc.outputTokens,\n cacheCreationInputTokens: acc.cacheWriteTokens,\n cacheReadInputTokens: acc.cacheReadTokens,\n },\n totalTokens: acc.totalTokens,\n costUSD: acc.cost,\n models: [...models],\n });\n idx++;\n }\n\n blocks.sort((a, b) => a.startTime.localeCompare(b.startTime));\n return { blocks };\n}\n", "import { existsSync } from 'node:fs';\nimport { execSync } from 'node:child_process';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport type { DailyEntry, DailyResponse, ProjectsResponse, BlockEntry, BlocksResponse } from '../shared/types.js';\n\n// ---------------------------------------------------------------------------\n// OpenCode SQLite format\n//\n// Database: ~/.local/share/opencode/opencode.db\n// Table: message\n// Column: data (JSON) with structure:\n// {\n// \"role\": \"assistant\",\n// \"time\": { \"created\": <ms>, \"completed\": <ms> },\n// \"modelID\": \"glm-4.7\",\n// \"providerID\": \"zhipuai-coding-plan\",\n// \"tokens\": { \"input\": N, \"output\": N, \"reasoning\": N, \"cache\": { \"read\": N, \"write\": N } },\n// \"cost\": N,\n// \"path\": { \"cwd\": \"/path/to/project\" }\n// }\n// ---------------------------------------------------------------------------\n\nconst OPENCODE_DB = join(homedir(), '.local', 'share', 'opencode', 'opencode.db');\n\n// ---------------------------------------------------------------------------\n// Detection\n// ---------------------------------------------------------------------------\n\nexport function isOpencodeAccessible(): boolean {\n return existsSync(OPENCODE_DB);\n}\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ninterface OpenCodeTokenEvent {\n timestampMs: number;\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens: number;\n cacheWriteTokens: number;\n totalTokens: number;\n cost: number;\n model: string;\n project: string;\n}\n\ninterface TokenAccumulator {\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens: number;\n cacheWriteTokens: number;\n totalTokens: number;\n cost: number;\n}\n\n// ---------------------------------------------------------------------------\n// SQLite query helper\n// ---------------------------------------------------------------------------\n\nfunction queryOpenCodeDB(sql: string): string {\n return execSync(`sqlite3 -json \"${OPENCODE_DB}\" \"${sql}\"`, {\n encoding: 'utf-8',\n maxBuffer: 50 * 1024 * 1024,\n timeout: 10000,\n });\n}\n\n// ---------------------------------------------------------------------------\n// Parse all token events from message table\n// ---------------------------------------------------------------------------\n\ninterface RawMessage {\n data: string;\n}\n\nexport function parseAllOpenCodeEvents(project?: string | null): OpenCodeTokenEvent[] {\n let sql = `SELECT data FROM message WHERE json_extract(data, '$.role') = 'assistant'`;\n if (project) {\n sql += ` AND json_extract(data, '$.path.cwd') = '${project.replace(/'/g, \"''\")}'`;\n }\n\n let raw: string;\n try {\n raw = queryOpenCodeDB(sql);\n } catch {\n return [];\n }\n\n let rows: RawMessage[];\n try {\n rows = JSON.parse(raw) as RawMessage[];\n } catch {\n return [];\n }\n\n const events: OpenCodeTokenEvent[] = [];\n\n for (const row of rows) {\n let data: Record<string, unknown>;\n try {\n data = JSON.parse(row.data) as Record<string, unknown>;\n } catch {\n continue;\n }\n\n const tokens = (data.tokens as Record<string, unknown>) || {};\n const cache = (tokens.cache as Record<string, unknown>) || {};\n const time = (data.time as Record<string, unknown>) || {};\n const path = (data.path as Record<string, unknown>) || {};\n\n const input = Number(tokens.input ?? 0);\n const output = Number(tokens.output ?? 0);\n const cacheRead = Number(cache.read ?? 0);\n const cacheWrite = Number(cache.write ?? 0);\n\n if (input === 0 && output === 0 && cacheRead === 0 && cacheWrite === 0) continue;\n\n events.push({\n timestampMs: Number(time.created ?? 0),\n inputTokens: Math.max(0, input),\n outputTokens: Math.max(0, output),\n cacheReadTokens: Math.max(0, cacheRead),\n cacheWriteTokens: Math.max(0, cacheWrite),\n totalTokens: Math.max(0, input + output + cacheRead),\n cost: Math.max(0, Number(data.cost ?? 0)),\n model: String(data.modelID ?? 'unknown'),\n project: String(path.cwd ?? ''),\n });\n }\n\n return events;\n}\n\n// ---------------------------------------------------------------------------\n// Date / timezone helpers (same logic as openclawParser)\n// ---------------------------------------------------------------------------\n\nconst TZ_OFFSETS: Record<string, number> = {\n 'Asia/Shanghai': 8,\n 'Asia/Tokyo': 9,\n 'America/New_York': -5,\n 'America/Los_Angeles': -8,\n 'Europe/London': 0,\n 'UTC': 0,\n};\n\nfunction getTzOffsetHours(tz: string): number {\n return TZ_OFFSETS[tz] ?? 8;\n}\n\nfunction msToLocalDate(ms: number, tz: string): Date {\n return new Date(ms + getTzOffsetHours(tz) * 3_600_000);\n}\n\nfunction getDateKey(ms: number, tz: string): string {\n return msToLocalDate(ms, tz).toISOString().slice(0, 10);\n}\n\nfunction getHourKey(ms: number, tz: string): string {\n const d = msToLocalDate(ms, tz);\n return d.toISOString().slice(0, 13).replace('T', ' ') + ':00';\n}\n\n// ---------------------------------------------------------------------------\n// Aggregation helpers\n// ---------------------------------------------------------------------------\n\nfunction emptyAcc(): TokenAccumulator {\n return { inputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0, totalTokens: 0, cost: 0 };\n}\n\nfunction addEvent(acc: TokenAccumulator, ev: OpenCodeTokenEvent): void {\n acc.inputTokens += ev.inputTokens;\n acc.outputTokens += ev.outputTokens;\n acc.cacheReadTokens += ev.cacheReadTokens;\n acc.cacheWriteTokens += ev.cacheWriteTokens;\n acc.totalTokens += ev.totalTokens;\n acc.cost += ev.cost;\n}\n\n// ---------------------------------------------------------------------------\n// Public API \u2014 mirrors openclawParser's response builders\n// ---------------------------------------------------------------------------\n\nexport interface OpenCodeAggregateOptions {\n project?: string | null;\n timezone?: string;\n}\n\nexport function getDailyResponse(options?: OpenCodeAggregateOptions): DailyResponse {\n const events = parseAllOpenCodeEvents(options?.project);\n const tz = options?.timezone || 'Asia/Shanghai';\n\n // Track per-day, per-model accumulators for correct breakdowns\n interface ModelAcc { inputTokens: number; outputTokens: number; cacheCreationTokens: number; cacheReadTokens: number; cost: number; }\n interface DayGroup { totals: TokenAccumulator; models: Map<string, ModelAcc>; }\n const grouped = new Map<string, DayGroup>();\n\n for (const ev of events) {\n const key = getDateKey(ev.timestampMs, tz);\n if (!grouped.has(key)) grouped.set(key, { totals: emptyAcc(), models: new Map() });\n const g = grouped.get(key)!;\n addEvent(g.totals, ev);\n\n if (!g.models.has(ev.model)) {\n g.models.set(ev.model, { inputTokens: 0, outputTokens: 0, cacheCreationTokens: 0, cacheReadTokens: 0, cost: 0 });\n }\n const m = g.models.get(ev.model)!;\n m.inputTokens += ev.inputTokens;\n m.outputTokens += ev.outputTokens;\n m.cacheCreationTokens += ev.cacheWriteTokens;\n m.cacheReadTokens += ev.cacheReadTokens;\n m.cost += ev.cost;\n }\n\n const totalsAcc = emptyAcc();\n const daily: DailyEntry[] = [];\n for (const [date, g] of grouped) {\n mergeAcc(totalsAcc, g.totals);\n const modelList = [...g.models.keys()];\n daily.push({\n date,\n inputTokens: g.totals.inputTokens,\n outputTokens: g.totals.outputTokens,\n cacheCreationTokens: g.totals.cacheWriteTokens,\n cacheReadTokens: g.totals.cacheReadTokens,\n totalTokens: g.totals.totalTokens,\n totalCost: g.totals.cost,\n modelsUsed: modelList,\n modelBreakdowns: modelList.map(name => {\n const m = g.models.get(name)!;\n return {\n modelName: name,\n inputTokens: m.inputTokens,\n outputTokens: m.outputTokens,\n cacheCreationTokens: m.cacheCreationTokens,\n cacheReadTokens: m.cacheReadTokens,\n cost: m.cost,\n };\n }),\n });\n }\n daily.sort((a, b) => a.date.localeCompare(b.date));\n\n return {\n daily,\n totals: {\n inputTokens: totalsAcc.inputTokens,\n outputTokens: totalsAcc.outputTokens,\n cacheCreationTokens: totalsAcc.cacheWriteTokens,\n cacheReadTokens: totalsAcc.cacheReadTokens,\n totalTokens: totalsAcc.totalTokens,\n totalCost: totalsAcc.cost,\n },\n };\n}\n\nfunction mergeAcc(a: TokenAccumulator, b: TokenAccumulator): void {\n a.inputTokens += b.inputTokens;\n a.outputTokens += b.outputTokens;\n a.cacheReadTokens += b.cacheReadTokens;\n a.cacheWriteTokens += b.cacheWriteTokens;\n a.totalTokens += b.totalTokens;\n a.cost += b.cost;\n}\n\nexport function getProjectsResponse(options?: OpenCodeAggregateOptions): ProjectsResponse {\n const events = parseAllOpenCodeEvents();\n const tz = options?.timezone || 'Asia/Shanghai';\n const projects: Record<string, DailyEntry[]> = {};\n\n for (const ev of events) {\n const projectName = ev.project || 'unknown';\n const dayKey = getDateKey(ev.timestampMs, tz);\n\n if (!projects[projectName]) projects[projectName] = [];\n\n // Find or create entry for this date in this project\n let dayEntry = projects[projectName].find(d => d.date === dayKey);\n if (!dayEntry) {\n dayEntry = {\n date: dayKey,\n inputTokens: 0,\n outputTokens: 0,\n cacheCreationTokens: 0,\n cacheReadTokens: 0,\n totalTokens: 0,\n totalCost: 0,\n modelsUsed: [],\n modelBreakdowns: [],\n };\n projects[projectName].push(dayEntry);\n }\n\n dayEntry.inputTokens += ev.inputTokens;\n dayEntry.outputTokens += ev.outputTokens;\n dayEntry.cacheCreationTokens += ev.cacheWriteTokens;\n dayEntry.cacheReadTokens += ev.cacheReadTokens;\n dayEntry.totalTokens += ev.totalTokens;\n dayEntry.totalCost += ev.cost;\n\n if (!dayEntry.modelsUsed.includes(ev.model)) {\n dayEntry.modelsUsed.push(ev.model);\n }\n\n // Update or add model breakdown\n let breakdown = dayEntry.modelBreakdowns.find(b => b.modelName === ev.model);\n if (!breakdown) {\n breakdown = {\n modelName: ev.model,\n inputTokens: 0,\n outputTokens: 0,\n cacheCreationTokens: 0,\n cacheReadTokens: 0,\n cost: 0,\n };\n dayEntry.modelBreakdowns.push(breakdown);\n }\n breakdown.inputTokens += ev.inputTokens;\n breakdown.outputTokens += ev.outputTokens;\n breakdown.cacheCreationTokens += ev.cacheWriteTokens;\n breakdown.cacheReadTokens += ev.cacheReadTokens;\n breakdown.cost += ev.cost;\n }\n\n for (const key of Object.keys(projects)) {\n projects[key].sort((a, b) => a.date.localeCompare(b.date));\n }\n\n return { projects };\n}\n\nexport function getBlocksResponse(options?: OpenCodeAggregateOptions): BlocksResponse {\n const events = parseAllOpenCodeEvents(options?.project);\n const tz = options?.timezone || 'Asia/Shanghai';\n\n const grouped = new Map<string, { acc: TokenAccumulator; models: Set<string> }>();\n\n for (const ev of events) {\n const key = getHourKey(ev.timestampMs, tz);\n if (!grouped.has(key)) grouped.set(key, { acc: emptyAcc(), models: new Set() });\n addEvent(grouped.get(key)!.acc, ev);\n grouped.get(key)!.models.add(ev.model);\n }\n\n const blocks: BlockEntry[] = [];\n let idx = 0;\n\n for (const [hourKey, { acc, models }] of grouped) {\n const [datePart, timePart] = hourKey.split(' ');\n const hour = timePart.split(':')[0];\n blocks.push({\n id: `opencode-hour-${idx}`,\n startTime: `${datePart}T${hour}:00:00`,\n endTime: `${datePart}T${hour}:59:59`,\n actualEndTime: null,\n isActive: false,\n isGap: false,\n entries: acc.totalTokens > 0 ? 1 : 0,\n tokenCounts: {\n inputTokens: acc.inputTokens,\n outputTokens: acc.outputTokens,\n cacheCreationInputTokens: acc.cacheWriteTokens,\n cacheReadInputTokens: acc.cacheReadTokens,\n },\n totalTokens: acc.totalTokens,\n costUSD: acc.cost,\n models: [...models],\n });\n idx++;\n }\n\n blocks.sort((a, b) => a.startTime.localeCompare(b.startTime));\n return { blocks };\n}\n", "import { readFileSync, readdirSync, statSync, existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport type { DailyEntry, DailyResponse, ProjectsResponse, Totals, BlockEntry } from '../shared/types.js';\n\n// ---------------------------------------------------------------------------\n// Model pricing (USD per 1M tokens)\n// Update from https://docs.anthropic.com/en/docs/about-claude/models when needed\n// ---------------------------------------------------------------------------\n\ninterface ModelPricing {\n inputPer1M: number;\n cacheCreationPer1M: number;\n cacheReadPer1M: number;\n outputPer1M: number;\n}\n\nconst MODEL_PRICING: Record<string, ModelPricing> = {\n // Claude 4.6\n 'claude-opus-4-6': { inputPer1M: 15, cacheCreationPer1M: 18.75, cacheReadPer1M: 1.50, outputPer1M: 75 },\n 'claude-sonnet-4-6': { inputPer1M: 3, cacheCreationPer1M: 3.75, cacheReadPer1M: 0.30, outputPer1M: 15 },\n // Claude 4.5\n 'claude-sonnet-4-5-20250514': { inputPer1M: 3, cacheCreationPer1M: 3.75, cacheReadPer1M: 0.30, outputPer1M: 15 },\n 'claude-haiku-4-5-20251001': { inputPer1M: 0.80, cacheCreationPer1M: 1, cacheReadPer1M: 0.08, outputPer1M: 4 },\n // Older Claude models\n 'claude-3-5-sonnet-20241022': { inputPer1M: 3, cacheCreationPer1M: 3.75, cacheReadPer1M: 0.30, outputPer1M: 15 },\n 'claude-3-5-haiku-20241022': { inputPer1M: 0.80, cacheCreationPer1M: 1, cacheReadPer1M: 0.08, outputPer1M: 4 },\n 'claude-3-opus-20240229': { inputPer1M: 15, cacheCreationPer1M: 18.75, cacheReadPer1M: 1.50, outputPer1M: 75 },\n 'claude-3-haiku-20240307': { inputPer1M: 0.25, cacheCreationPer1M: 0.30, cacheReadPer1M: 0.03, outputPer1M: 1.25 },\n};\n\nconst DEFAULT_PRICING: ModelPricing = { inputPer1M: 3, cacheCreationPer1M: 3.75, cacheReadPer1M: 0.30, outputPer1M: 15 };\n\nfunction getPricing(model: string): ModelPricing {\n // Try exact match first, then prefix match\n if (MODEL_PRICING[model]) return MODEL_PRICING[model];\n const lower = model.toLowerCase();\n for (const key of Object.keys(MODEL_PRICING)) {\n if (lower.startsWith(key) || lower.includes(key)) return MODEL_PRICING[key];\n }\n return DEFAULT_PRICING;\n}\n\nexport function calculateCost(inputTokens: number, cacheReadTokens: number, outputTokens: number, model: string, cacheCreationTokens = 0): number {\n const p = getPricing(model);\n return (inputTokens / 1_000_000) * p.inputPer1M\n + (cacheCreationTokens / 1_000_000) * p.cacheCreationPer1M\n + (cacheReadTokens / 1_000_000) * p.cacheReadPer1M\n + (outputTokens / 1_000_000) * p.outputPer1M;\n}\n\nfunction totalClaudeTokens(inputTokens: number, outputTokens: number, cacheCreationTokens: number, cacheReadTokens: number): number {\n return inputTokens + outputTokens + cacheCreationTokens + cacheReadTokens;\n}\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ninterface ParsedUsage {\n timestamp: string;\n model: string;\n inputTokens: number;\n outputTokens: number;\n cacheCreationTokens: number;\n cacheReadTokens: number;\n projectDir: string;\n}\n\n// ---------------------------------------------------------------------------\n// JSONL parsing with mtime cache\n// ---------------------------------------------------------------------------\n\nconst CLAUDE_PROJECTS_DIR = join(homedir(), '.claude', 'projects');\n\nconst fileCache = new Map<string, { mtime: number; entries: ParsedUsage[] }>();\n\nconst projectNameCache = new Map<string, string>();\n\n/** Decode Claude's encoded project directory name.\n * Claude encodes paths: /Users/foo/bar \u2192 -Users-foo-bar\n * Since '-' replaces '/' and project names can contain '-',\n * we use filesystem checks to find the correct last segment.\n */\nexport function extractProjectName(dirName: string): string {\n if (!dirName.startsWith('-')) return dirName;\n\n const cached = projectNameCache.get(dirName);\n if (cached) return cached;\n\n const segments = dirName.replace(/^-/, '').split('-').filter(Boolean);\n if (segments.length === 0) { projectNameCache.set(dirName, dirName); return dirName; }\n if (segments.length === 1) { projectNameCache.set(dirName, segments[0]); return segments[0]; }\n\n let bestName = segments[segments.length - 1];\n\n // Try from right: find the longest last segment that forms a valid path\n for (let splitAt = segments.length - 1; splitAt >= 1; splitAt--) {\n const parentSegments = segments.slice(0, splitAt);\n const candidateName = segments.slice(splitAt).join('-');\n\n // Build parent path, handling hidden directories (dot prefix)\n let parentPath = '/';\n let valid = true;\n for (const seg of parentSegments) {\n const regular = join(parentPath, seg);\n const hidden = join(parentPath, '.' + seg);\n if (existsSync(regular)) {\n parentPath = regular;\n } else if (existsSync(hidden)) {\n parentPath = hidden;\n } else {\n valid = false;\n break;\n }\n }\n\n if (!valid) continue;\n\n if (existsSync(join(parentPath, candidateName)) || existsSync(join(parentPath, '.' + candidateName))) {\n bestName = candidateName;\n break;\n }\n }\n\n projectNameCache.set(dirName, bestName);\n return bestName;\n}\n\nfunction matchesProject(dirName: string, filter: string): boolean {\n return extractProjectName(dirName) === extractProjectName(filter);\n}\n\nfunction findJsonlFiles(dir: string): string[] {\n const results: string[] = [];\n try {\n const entries = readdirSync(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.isDirectory()) {\n results.push(...findJsonlFiles(join(dir, entry.name)));\n } else if (entry.name.endsWith('.jsonl')) {\n results.push(join(dir, entry.name));\n }\n }\n } catch { /* skip unreadable dirs */ }\n return results;\n}\n\nfunction parseAllSessions(project?: string | null): ParsedUsage[] {\n if (!existsSync(CLAUDE_PROJECTS_DIR)) return [];\n\n const results: ParsedUsage[] = [];\n const projectDirs = readdirSync(CLAUDE_PROJECTS_DIR, { withFileTypes: true })\n .filter(d => d.isDirectory())\n .map(d => d.name);\n\n for (const dirName of projectDirs) {\n if (project && !matchesProject(dirName, project)) continue;\n\n const dirPath = join(CLAUDE_PROJECTS_DIR, dirName);\n const files = findJsonlFiles(dirPath);\n\n for (const filePath of files) {\n\n let mtime = 0;\n try { mtime = statSync(filePath).mtimeMs; } catch { /* ok */ }\n\n const cached = fileCache.get(filePath);\n if (cached && cached.mtime === mtime) {\n results.push(...cached.entries);\n continue;\n }\n\n const entries: ParsedUsage[] = [];\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 const trimmed = line.trim();\n if (!trimmed) continue;\n\n let obj: Record<string, unknown>;\n try { obj = JSON.parse(trimmed) as Record<string, unknown>; } catch { continue; }\n\n if (obj.type !== 'assistant' || !obj.message) continue;\n const msg = obj.message as Record<string, unknown>;\n const usage = (msg.usage as Record<string, number>) || {};\n\n const inputTokens = usage.input_tokens || 0;\n const outputTokens = usage.output_tokens || 0;\n const cacheCreationTokens = usage.cache_creation_input_tokens || 0;\n const cacheReadTokens = usage.cache_read_input_tokens || 0;\n const totalTokens = totalClaudeTokens(inputTokens, outputTokens, cacheCreationTokens, cacheReadTokens);\n\n if (totalTokens === 0) continue;\n\n entries.push({\n timestamp: obj.timestamp as string,\n model: (msg.model as string) || 'unknown',\n inputTokens,\n outputTokens,\n cacheCreationTokens,\n cacheReadTokens,\n projectDir: dirName,\n });\n }\n\n fileCache.set(filePath, { mtime, entries });\n results.push(...entries);\n }\n }\n\n return results;\n}\n\n// ---------------------------------------------------------------------------\n// Timezone helpers\n// ---------------------------------------------------------------------------\n\nconst TZ_OFFSETS: Record<string, number> = {\n 'Asia/Shanghai': 8,\n 'Asia/Tokyo': 9,\n 'America/New_York': -5,\n 'America/Los_Angeles': -8,\n 'Europe/London': 0,\n 'UTC': 0,\n};\n\nexport function getDateKey(timestamp: string, tz: string): string {\n const offset = (TZ_OFFSETS[tz] ?? 8) * 3_600_000;\n const d = new Date(new Date(timestamp).getTime() + offset);\n // Use UTC methods since we manually applied the timezone offset\n return `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')}`;\n}\n\nexport function getHourKey(timestamp: string, tz: string): string {\n const offset = (TZ_OFFSETS[tz] ?? 8) * 3_600_000;\n const d = new Date(new Date(timestamp).getTime() + offset);\n // Use UTC methods since we manually applied the timezone offset\n const yyyy = d.getUTCFullYear();\n const mm = String(d.getUTCMonth() + 1).padStart(2, '0');\n const dd = String(d.getUTCDate()).padStart(2, '0');\n const hh = String(d.getUTCHours()).padStart(2, '0');\n return `${yyyy}-${mm}-${dd}T${hh}`;\n}\n\n// ---------------------------------------------------------------------------\n// Aggregation helpers\n// ---------------------------------------------------------------------------\n\ninterface DayAgg {\n date: string;\n inputTokens: number;\n outputTokens: number;\n cacheCreationTokens: number;\n cacheReadTokens: number;\n totalTokens: number;\n totalCost: number;\n models: Map<string, { input: number; output: number; cacheCreation: number; cacheRead: number; cost: number }>;\n}\n\nfunction toDailyEntry(agg: DayAgg): DailyEntry {\n const modelBreakdowns = [...agg.models.entries()].map(([modelName, m]) => ({\n modelName,\n inputTokens: m.input,\n outputTokens: m.output,\n cacheCreationTokens: m.cacheCreation,\n cacheReadTokens: m.cacheRead,\n cost: m.cost,\n }));\n\n return {\n date: agg.date,\n inputTokens: agg.inputTokens,\n outputTokens: agg.outputTokens,\n cacheCreationTokens: agg.cacheCreationTokens,\n cacheReadTokens: agg.cacheReadTokens,\n totalTokens: agg.totalTokens,\n totalCost: Math.round(agg.totalCost * 10000) / 10000,\n modelsUsed: [...agg.models.keys()],\n modelBreakdowns,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_TZ = 'Asia/Shanghai';\n\nexport function getDailyResponse(project?: string | null, tz = DEFAULT_TZ): DailyResponse {\n const entries = parseAllSessions(project);\n const dayMap = new Map<string, DayAgg>();\n\n for (const e of entries) {\n const date = getDateKey(e.timestamp, tz);\n if (!dayMap.has(date)) {\n dayMap.set(date, {\n date, inputTokens: 0, outputTokens: 0, cacheCreationTokens: 0,\n cacheReadTokens: 0, totalTokens: 0, totalCost: 0,\n models: new Map(),\n });\n }\n const agg = dayMap.get(date)!;\n agg.inputTokens += e.inputTokens;\n agg.outputTokens += e.outputTokens;\n agg.cacheCreationTokens += e.cacheCreationTokens;\n agg.cacheReadTokens += e.cacheReadTokens;\n agg.totalTokens += totalClaudeTokens(e.inputTokens, e.outputTokens, e.cacheCreationTokens, e.cacheReadTokens);\n\n const cost = calculateCost(e.inputTokens, e.cacheReadTokens, e.outputTokens, e.model, e.cacheCreationTokens);\n agg.totalCost += cost;\n\n if (!agg.models.has(e.model)) {\n agg.models.set(e.model, { input: 0, output: 0, cacheCreation: 0, cacheRead: 0, cost: 0 });\n }\n const m = agg.models.get(e.model)!;\n m.input += e.inputTokens;\n m.output += e.outputTokens;\n m.cacheCreation += e.cacheCreationTokens;\n m.cacheRead += e.cacheReadTokens;\n m.cost += cost;\n }\n\n const daily = [...dayMap.values()].sort((a, b) => a.date.localeCompare(b.date)).map(toDailyEntry);\n const totals: Totals = daily.reduce((acc, d) => ({\n inputTokens: acc.inputTokens + d.inputTokens,\n outputTokens: acc.outputTokens + d.outputTokens,\n cacheCreationTokens: acc.cacheCreationTokens + d.cacheCreationTokens,\n cacheReadTokens: acc.cacheReadTokens + d.cacheReadTokens,\n totalTokens: acc.totalTokens + d.totalTokens,\n totalCost: acc.totalCost + d.totalCost,\n }), { inputTokens: 0, outputTokens: 0, cacheCreationTokens: 0, cacheReadTokens: 0, totalTokens: 0, totalCost: 0 });\n\n return { daily, totals };\n}\n\nexport function getProjectsResponse(tz = DEFAULT_TZ): ProjectsResponse {\n const entries = parseAllSessions();\n const projectMap = new Map<string, Map<string, DayAgg>>();\n\n for (const e of entries) {\n const date = getDateKey(e.timestamp, tz);\n const projectName = extractProjectName(e.projectDir);\n\n if (!projectMap.has(projectName)) {\n projectMap.set(projectName, new Map());\n }\n const dayMap = projectMap.get(projectName)!;\n\n if (!dayMap.has(date)) {\n dayMap.set(date, {\n date, inputTokens: 0, outputTokens: 0, cacheCreationTokens: 0,\n cacheReadTokens: 0, totalTokens: 0, totalCost: 0,\n models: new Map(),\n });\n }\n const agg = dayMap.get(date)!;\n agg.inputTokens += e.inputTokens;\n agg.outputTokens += e.outputTokens;\n agg.cacheCreationTokens += e.cacheCreationTokens;\n agg.cacheReadTokens += e.cacheReadTokens;\n agg.totalTokens += totalClaudeTokens(e.inputTokens, e.outputTokens, e.cacheCreationTokens, e.cacheReadTokens);\n\n const cost = calculateCost(e.inputTokens, e.cacheReadTokens, e.outputTokens, e.model, e.cacheCreationTokens);\n agg.totalCost += cost;\n\n if (!agg.models.has(e.model)) {\n agg.models.set(e.model, { input: 0, output: 0, cacheCreation: 0, cacheRead: 0, cost: 0 });\n }\n const m = agg.models.get(e.model)!;\n m.input += e.inputTokens;\n m.output += e.outputTokens;\n m.cacheCreation += e.cacheCreationTokens;\n m.cacheRead += e.cacheReadTokens;\n m.cost += cost;\n }\n\n const projects: Record<string, DailyEntry[]> = {};\n for (const [projectName, dayMap] of projectMap) {\n projects[projectName] = [...dayMap.values()]\n .sort((a, b) => a.date.localeCompare(b.date))\n .map(toDailyEntry);\n }\n\n return { projects };\n}\n\nexport function getBlocksResponse(project?: string | null, tz = DEFAULT_TZ): { blocks: BlockEntry[] } {\n const entries = parseAllSessions(project);\n const hourMap = new Map<string, {\n inputTokens: number; outputTokens: number; cacheCreationTokens: number;\n cacheReadTokens: number; costUSD: number; models: Set<string>;\n }>();\n\n for (const e of entries) {\n const hourKey = getHourKey(e.timestamp, tz);\n if (!hourMap.has(hourKey)) {\n hourMap.set(hourKey, {\n inputTokens: 0, outputTokens: 0, cacheCreationTokens: 0,\n cacheReadTokens: 0, costUSD: 0, models: new Set(),\n });\n }\n const bucket = hourMap.get(hourKey)!;\n bucket.inputTokens += e.inputTokens;\n bucket.outputTokens += e.outputTokens;\n bucket.cacheCreationTokens += e.cacheCreationTokens;\n bucket.cacheReadTokens += e.cacheReadTokens;\n bucket.costUSD += calculateCost(e.inputTokens, e.cacheReadTokens, e.outputTokens, e.model, e.cacheCreationTokens);\n bucket.models.add(e.model);\n }\n\n const blocks: BlockEntry[] = [];\n let idx = 0;\n for (const [hourKey, bucket] of hourMap) {\n const totalTokens = totalClaudeTokens(bucket.inputTokens, bucket.outputTokens, bucket.cacheCreationTokens, bucket.cacheReadTokens);\n blocks.push({\n id: `claude-${idx}`,\n startTime: `${hourKey}:00:00`,\n endTime: `${hourKey}:59:59`,\n actualEndTime: null,\n isActive: false,\n isGap: false,\n entries: totalTokens > 0 ? 1 : 0,\n tokenCounts: {\n inputTokens: bucket.inputTokens,\n outputTokens: bucket.outputTokens,\n cacheCreationInputTokens: bucket.cacheCreationTokens,\n cacheReadInputTokens: bucket.cacheReadTokens,\n },\n totalTokens,\n costUSD: Math.round(bucket.costUSD * 10000) / 10000,\n models: [...bucket.models],\n });\n idx++;\n }\n\n blocks.sort((a, b) => a.startTime.localeCompare(b.startTime));\n return { blocks };\n}\n", "import { type Request, type Response } from 'express';\nimport { cache } from '../cache.js';\nimport { validateDaily } from '../../shared/schemas.js';\nimport { getDailyResponse as getCodexDailyResponse } from '../codexParser.js';\nimport { getDailyResponse as getOpenClawDailyResponse } from '../openclawParser.js';\nimport { getDailyResponse as getOpencodeDailyResponse } from '../opencodeParser.js';\nimport { getDailyResponse as getClaudeDailyResponse } from '../claudeJsonlParser.js';\n\nexport async function getDaily(req: Request, res: Response): Promise<void> {\n const agent = req.query.agent as string || 'claude';\n const cacheKey = `daily:${agent}`;\n try {\n const cached = cache.get(cacheKey);\n if (cached) {\n res.json(cached);\n return;\n }\n\n // Stale-while-revalidate: return stale data, refresh in background\n const stale = cache.getStale(cacheKey);\n if (stale) {\n refreshDailyCache(agent, cacheKey);\n res.json(stale);\n return;\n }\n\n const data = await fetchDailyData(agent);\n cache.set(cacheKey, data);\n res.json(data);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n console.error('Error fetching daily data:', error);\n res.status(502).json({\n error: `Failed to fetch daily data from ${agent}`,\n hint: message,\n });\n }\n}\n\nfunction fetchDailyData(agent: string) {\n if (agent === 'codex') {\n return Promise.resolve(getCodexDailyResponse());\n } else if (agent === 'openclaw') {\n return Promise.resolve(validateDaily(getOpenClawDailyResponse()));\n } else if (agent === 'opencode') {\n return Promise.resolve(validateDaily(getOpencodeDailyResponse()));\n } else {\n // Claude Code: parse JSONL directly (fast, no CLI)\n return Promise.resolve(validateDaily(getClaudeDailyResponse()));\n }\n}\n\nfunction refreshDailyCache(agent: string, cacheKey: string): void {\n fetchDailyData(agent)\n .then(data => cache.set(cacheKey, data))\n .catch(err => console.error('Background refresh failed (daily):', err));\n}\n", "import { type Request, type Response } from 'express';\nimport { cache } from '../cache.js';\nimport { validateDaily } from '../../shared/schemas.js';\nimport { getDailyResponse as getClaudeDailyResponse } from '../claudeJsonlParser.js';\nimport { getDailyResponse as getCodexDailyResponse } from '../codexParser.js';\nimport { getDailyResponse as getOpenClawDailyResponse } from '../openclawParser.js';\n\nexport async function getMonthly(req: Request, res: Response): Promise<void> {\n const agent = req.query.agent as string || 'claude';\n const cacheKey = `monthly:${agent}`;\n try {\n const cached = cache.get(cacheKey);\n if (cached) {\n res.json(cached);\n return;\n }\n\n const stale = cache.getStale(cacheKey);\n if (stale) {\n res.json(stale);\n return;\n }\n\n // Monthly is same as daily for our parser (aggregated by date already)\n let data;\n if (agent === 'codex') {\n data = validateDaily(getCodexDailyResponse());\n } else if (agent === 'openclaw') {\n data = validateDaily(getOpenClawDailyResponse());\n } else {\n data = validateDaily(getClaudeDailyResponse());\n }\n\n cache.set(cacheKey, data);\n res.json(data);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n console.error('Error fetching monthly data:', error);\n res.status(502).json({\n error: 'Failed to fetch monthly data',\n hint: message,\n });\n }\n}\n", "import { type Request, type Response } from 'express';\nimport { cache } from '../cache.js';\nimport { validateDaily } from '../../shared/schemas.js';\nimport { getDailyResponse as getClaudeDailyResponse } from '../claudeJsonlParser.js';\nimport { getDailyResponse as getCodexDailyResponse } from '../codexParser.js';\nimport { getDailyResponse as getOpenClawDailyResponse } from '../openclawParser.js';\n\nexport async function getSession(req: Request, res: Response): Promise<void> {\n const agent = req.query.agent as string || 'claude';\n const cacheKey = `session:${agent}`;\n try {\n const cached = cache.get(cacheKey);\n if (cached) {\n res.json(cached);\n return;\n }\n\n const stale = cache.getStale(cacheKey);\n if (stale) {\n res.json(stale);\n return;\n }\n\n // Session data uses same daily aggregation\n let data;\n if (agent === 'codex') {\n data = validateDaily(getCodexDailyResponse());\n } else if (agent === 'openclaw') {\n data = validateDaily(getOpenClawDailyResponse());\n } else {\n data = validateDaily(getClaudeDailyResponse());\n }\n\n cache.set(cacheKey, data);\n res.json(data);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n console.error('Error fetching session data:', error);\n res.status(502).json({\n error: 'Failed to fetch session data',\n hint: message,\n });\n }\n}\n", "import { type Request, type Response } from 'express';\nimport { cache } from '../cache.js';\nimport { validateProjects } from '../../shared/schemas.js';\nimport { getProjectsResponse as getCodexProjectsResponse } from '../codexParser.js';\nimport { getProjectsResponse as getOpenClawProjectsResponse } from '../openclawParser.js';\nimport { getProjectsResponse as getOpencodeProjectsResponse } from '../opencodeParser.js';\nimport { getProjectsResponse as getClaudeProjectsResponse } from '../claudeJsonlParser.js';\n\nexport async function getProjects(req: Request, res: Response): Promise<void> {\n const agent = req.query.agent as string || 'claude';\n const cacheKey = `projects:${agent}`;\n try {\n const cached = cache.get(cacheKey);\n if (cached) {\n res.json(cached);\n return;\n }\n\n // Stale-while-revalidate\n const stale = cache.getStale(cacheKey);\n if (stale) {\n refreshProjectsCache(agent, cacheKey);\n res.json(stale);\n return;\n }\n\n const data = fetchProjectsData(agent);\n cache.set(cacheKey, data);\n res.json(data);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n console.error('Error fetching projects data:', error);\n res.status(502).json({\n error: `Failed to fetch projects data from ${agent}`,\n hint: message,\n });\n }\n}\n\nfunction fetchProjectsData(agent: string) {\n if (agent === 'codex') {\n return getCodexProjectsResponse();\n } else if (agent === 'openclaw') {\n return validateProjects(getOpenClawProjectsResponse());\n } else if (agent === 'opencode') {\n return validateProjects(getOpencodeProjectsResponse());\n } else {\n // Claude Code: parse JSONL directly (fast, no CLI)\n return validateProjects(getClaudeProjectsResponse());\n }\n}\n\nfunction refreshProjectsCache(agent: string, cacheKey: string): void {\n Promise.resolve()\n .then(() => { const data = fetchProjectsData(agent); cache.set(cacheKey, data); })\n .catch(err => console.error('Background refresh failed (projects):', err));\n}\n", "import { type Request, type Response } from 'express';\nimport { cache } from '../cache.js';\nimport { validateBlocks } from '../../shared/schemas.js';\nimport { getBlocksResponse as getCodexBlocksResponse } from '../codexParser.js';\nimport { getBlocksResponse as getOpenClawBlocksResponse } from '../openclawParser.js';\nimport { getBlocksResponse as getOpencodeBlocksResponse } from '../opencodeParser.js';\nimport { getBlocksResponse as getClaudeBlocksResponse } from '../claudeJsonlParser.js';\n\nexport async function getBlocks(req: Request, res: Response): Promise<void> {\n const agent = req.query.agent as string || 'claude';\n const project = req.query.project as string || undefined;\n\n try {\n const cacheKey = `blocks:${agent}:${project || 'all'}`;\n const cached = cache.get(cacheKey);\n if (cached) {\n res.json(cached);\n return;\n }\n\n // Stale-while-revalidate\n const stale = cache.getStale(cacheKey);\n if (stale) {\n refreshBlocksCache(agent, project, cacheKey);\n res.json(stale);\n return;\n }\n\n const data = fetchBlocksData(agent, project);\n cache.set(cacheKey, data);\n res.json(data);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n console.error('Error fetching blocks data:', error);\n res.status(502).json({\n error: 'Failed to fetch blocks data',\n hint: message,\n });\n }\n}\n\nfunction fetchBlocksData(agent: string, project?: string) {\n if (agent === 'openclaw') {\n return validateBlocks(getOpenClawBlocksResponse({ project: project || null }));\n } else if (agent === 'opencode') {\n return validateBlocks(getOpencodeBlocksResponse({ project: project || null }));\n } else if (agent === 'codex') {\n return validateBlocks(getCodexBlocksResponse({ project: project || null }));\n } else {\n // Claude Code: parse JSONL directly (fast, no CLI)\n return validateBlocks(getClaudeBlocksResponse(project || null));\n }\n}\n\nfunction refreshBlocksCache(agent: string, project: string | undefined, cacheKey: string): void {\n Promise.resolve()\n .then(() => { const data = fetchBlocksData(agent, project); cache.set(cacheKey, data); })\n .catch(err => console.error('Background refresh failed (blocks):', err));\n}\n", "import { readFileSync, readdirSync, statSync, existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { scanOpenClawSessions } from './openclawParser.js';\nimport type { AnalyticsResponse, ToolUsageEntry, DailyCodeChange, DailyToolCall, ProductivityKPIs } from '../shared/types.js';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ninterface ToolCallRecord {\n toolName: string; // normalized name\n timestamp: number; // ms epoch\n filePath?: string;\n linesAdded: number;\n linesDeleted: number;\n}\n\n// ---------------------------------------------------------------------------\n// Timezone helpers (same as other parsers)\n// ---------------------------------------------------------------------------\n\nconst TZ_OFFSETS: Record<string, number> = {\n 'Asia/Shanghai': 8,\n 'Asia/Tokyo': 9,\n 'America/New_York': -5,\n 'America/Los_Angeles': -8,\n 'Europe/London': 0,\n 'UTC': 0,\n};\n\nfunction getDateKey(ms: number, tz: string): string {\n const offset = (TZ_OFFSETS[tz] ?? 8) * 3_600_000;\n const d = new Date(ms + offset);\n return `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')}`;\n}\n\n// ---------------------------------------------------------------------------\n// Tool name normalization\n// ---------------------------------------------------------------------------\n\nexport function normalizeToolName(name: string): string {\n const lower = name.toLowerCase();\n if (lower.startsWith('mcp__')) {\n const parts = name.split('__');\n const serverPart = parts.length >= 3 ? parts[2] : 'mcp';\n return `MCP:${serverPart}`;\n }\n const mapping: Record<string, string> = {\n 'exec': 'Bash',\n 'read': 'Read',\n 'edit': 'Edit',\n 'write': 'Write',\n };\n return mapping[lower] || name;\n}\n\n// ---------------------------------------------------------------------------\n// Line counting\n// ---------------------------------------------------------------------------\n\nfunction countLines(text: string): number {\n if (!text) return 0;\n return text.split('\\n').length;\n}\n\n// ---------------------------------------------------------------------------\n// Claude Code session scanning & tool extraction\n// ---------------------------------------------------------------------------\n\nconst CLAUDE_PROJECTS_DIR = join(homedir(), '.claude', 'projects');\n\nconst projectNameCache = new Map<string, string>();\n\n/** Decode Claude's encoded project directory name.\n * Claude encodes paths: /Users/foo/bar \u2192 -Users-foo-bar\n * Since '-' replaces '/' and project names can contain '-',\n * we use filesystem checks to find the correct last segment.\n */\nfunction extractProjectName(dirName: string): string {\n if (!dirName.startsWith('-')) return dirName;\n\n const cached = projectNameCache.get(dirName);\n if (cached) return cached;\n\n const segments = dirName.replace(/^-/, '').split('-').filter(Boolean);\n if (segments.length === 0) { projectNameCache.set(dirName, dirName); return dirName; }\n if (segments.length === 1) { projectNameCache.set(dirName, segments[0]); return segments[0]; }\n\n let bestName = segments[segments.length - 1];\n\n for (let splitAt = segments.length - 1; splitAt >= 1; splitAt--) {\n const parentSegments = segments.slice(0, splitAt);\n const candidateName = segments.slice(splitAt).join('-');\n\n let parentPath = '/';\n let valid = true;\n for (const seg of parentSegments) {\n const regular = join(parentPath, seg);\n const hidden = join(parentPath, '.' + seg);\n if (existsSync(regular)) {\n parentPath = regular;\n } else if (existsSync(hidden)) {\n parentPath = hidden;\n } else {\n valid = false;\n break;\n }\n }\n\n if (!valid) continue;\n\n if (existsSync(join(parentPath, candidateName)) || existsSync(join(parentPath, '.' + candidateName))) {\n bestName = candidateName;\n break;\n }\n }\n\n projectNameCache.set(dirName, bestName);\n return bestName;\n}\n\nfunction matchesProject(dirName: string, filter: string): boolean {\n return extractProjectName(dirName) === extractProjectName(filter);\n}\n\n// Session-level cache (mtime-based)\nconst claudeSessionCache = new Map<string, { mtime: number; toolCalls: ToolCallRecord[] }>();\n\nexport function extractClaudeToolCalls(project?: string | null): ToolCallRecord[] {\n if (!existsSync(CLAUDE_PROJECTS_DIR)) return [];\n\n const results: ToolCallRecord[] = [];\n const projectDirs = readdirSync(CLAUDE_PROJECTS_DIR, { withFileTypes: true })\n .filter(d => d.isDirectory())\n .map(d => d.name);\n\n for (const dirName of projectDirs) {\n if (project && !matchesProject(dirName, project)) continue;\n\n const dirPath = join(CLAUDE_PROJECTS_DIR, dirName);\n let files: string[];\n try {\n files = readdirSync(dirPath).filter(f => f.endsWith('.jsonl'));\n } catch {\n continue;\n }\n\n for (const file of files) {\n const filePath = join(dirPath, file);\n\n let mtime = 0;\n try { mtime = statSync(filePath).mtimeMs; } catch { /* ok */ }\n\n const cached = claudeSessionCache.get(filePath);\n if (cached && cached.mtime === mtime) {\n results.push(...cached.toolCalls);\n continue;\n }\n\n const toolCalls: ToolCallRecord[] = [];\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 const trimmed = line.trim();\n if (!trimmed) continue;\n\n let obj: Record<string, unknown>;\n try { obj = JSON.parse(trimmed) as Record<string, unknown>; } catch { continue; }\n\n if (obj.type !== 'assistant' || !obj.message) continue;\n const msg = obj.message as Record<string, unknown>;\n const timestamp = new Date(obj.timestamp as string).getTime();\n const content_arr = msg.content as Array<Record<string, unknown>> | undefined;\n if (!content_arr) continue;\n\n for (const item of content_arr) {\n if (item.type !== 'tool_use') continue;\n\n const toolName = normalizeToolName(item.name as string);\n const input = (item.input as Record<string, unknown>) || {};\n\n let linesAdded = 0;\n let linesDeleted = 0;\n const filePath2 = (input.file_path as string) || undefined;\n\n if (toolName === 'Edit') {\n linesDeleted = countLines(input.old_string as string || '');\n linesAdded = countLines(input.new_string as string || '');\n } else if (toolName === 'Write') {\n linesAdded = countLines(input.content as string || '');\n }\n\n toolCalls.push({ toolName, timestamp, filePath: filePath2, linesAdded, linesDeleted });\n }\n }\n\n claudeSessionCache.set(filePath, { mtime, toolCalls });\n results.push(...toolCalls);\n }\n }\n\n return results;\n}\n\n// ---------------------------------------------------------------------------\n// OpenClaw tool extraction\n// ---------------------------------------------------------------------------\n\nconst openclawSessionCache = new Map<string, { mtime: number; toolCalls: ToolCallRecord[] }>();\n\nexport function extractOpenClawToolCalls(project?: string | null): ToolCallRecord[] {\n const results: ToolCallRecord[] = [];\n const refs = scanOpenClawSessions();\n\n for (const ref of refs) {\n if (project && ref.agentId !== project) continue;\n\n let mtime = 0;\n try { mtime = statSync(ref.sessionFile).mtimeMs; } catch { /* ok */ }\n\n const cached = openclawSessionCache.get(ref.sessionFile);\n if (cached && cached.mtime === mtime) {\n results.push(...cached.toolCalls);\n continue;\n }\n\n const toolCalls: ToolCallRecord[] = [];\n let content: string;\n try {\n content = readFileSync(ref.sessionFile, 'utf-8');\n } catch {\n continue;\n }\n\n for (const line of content.split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n\n let obj: Record<string, unknown>;\n try { obj = JSON.parse(trimmed) as Record<string, unknown>; } catch { continue; }\n\n if (obj.type !== 'message') continue;\n const msg = obj.message as Record<string, unknown>;\n if (msg.role !== 'assistant') continue;\n\n const timestamp = Number(msg.timestamp ?? 0);\n const content_arr = msg.content as Array<Record<string, unknown>> | undefined;\n if (!content_arr) continue;\n\n for (const item of content_arr) {\n if (item.type !== 'toolCall') continue;\n\n const toolName = normalizeToolName(item.name as string);\n const args = (item.arguments as Record<string, unknown>) || {};\n\n let linesAdded = 0;\n let linesDeleted = 0;\n const filePath2 = (args.path as string) || undefined;\n\n if (toolName === 'Edit') {\n linesDeleted = countLines(args.oldText as string || '');\n linesAdded = countLines(args.newText as string || '');\n } else if (toolName === 'Write') {\n linesAdded = countLines(args.content as string || '');\n }\n\n toolCalls.push({ toolName, timestamp, filePath: filePath2, linesAdded, linesDeleted });\n }\n }\n\n openclawSessionCache.set(ref.sessionFile, { mtime, toolCalls });\n results.push(...toolCalls);\n }\n\n return results;\n}\n\n// ---------------------------------------------------------------------------\n// Analytics computation\n// ---------------------------------------------------------------------------\n\nexport function computeAnalytics(toolCalls: ToolCallRecord[], timezone = 'Asia/Shanghai'): AnalyticsResponse {\n // 1. Code Change Trend \u2014 group edit/write calls by date\n const changeMap = new Map<string, { added: number; deleted: number; files: Set<string> }>();\n for (const tc of toolCalls) {\n if (tc.linesAdded === 0 && tc.linesDeleted === 0) continue;\n const key = getDateKey(tc.timestamp, timezone);\n if (!changeMap.has(key)) changeMap.set(key, { added: 0, deleted: 0, files: new Set() });\n const entry = changeMap.get(key)!;\n entry.added += tc.linesAdded;\n entry.deleted += tc.linesDeleted;\n if (tc.filePath) entry.files.add(tc.filePath);\n }\n const codeChangeTrend: DailyCodeChange[] = [];\n for (const [date, { added, deleted, files }] of changeMap) {\n codeChangeTrend.push({ date, linesAdded: added, linesDeleted: deleted, netChange: added - deleted, filesModified: files.size });\n }\n codeChangeTrend.sort((a, b) => a.date.localeCompare(b.date));\n\n // 2. Tool Usage Distribution \u2014 count per tool\n const toolCountMap = new Map<string, number>();\n for (const tc of toolCalls) {\n toolCountMap.set(tc.toolName, (toolCountMap.get(tc.toolName) || 0) + 1);\n }\n const toolUsageDistribution: ToolUsageEntry[] = [...toolCountMap.entries()]\n .map(([name, count]) => ({ name, count }))\n .sort((a, b) => b.count - a.count);\n\n // 3. Productivity KPIs\n const editCalls = toolCalls.filter(tc => tc.toolName === 'Edit' || tc.toolName === 'Write');\n const totalEdits = editCalls.length;\n const totalLinesChanged = editCalls.reduce((s, tc) => s + tc.linesAdded + tc.linesDeleted, 0);\n const totalLinesAdded = editCalls.reduce((s, tc) => s + tc.linesAdded, 0);\n const totalLinesDeleted = editCalls.reduce((s, tc) => s + tc.linesDeleted, 0);\n const uniqueFiles = new Set(editCalls.filter(tc => tc.filePath).map(tc => tc.filePath!));\n const editDates = new Set(editCalls.map(tc => getDateKey(tc.timestamp, timezone)));\n\n const productivityKPIs: ProductivityKPIs = {\n avgLinesPerEdit: totalEdits > 0 ? Math.round(totalLinesChanged / totalEdits) : 0,\n filesModifiedPerDay: editDates.size > 0 ? Math.round(uniqueFiles.size / editDates.size) : 0,\n addDeleteRatio: totalLinesDeleted > 0 ? Math.round((totalLinesAdded / totalLinesDeleted) * 100) / 100 : totalLinesAdded > 0 ? 1 : 0,\n totalEdits,\n totalFilesModified: uniqueFiles.size,\n activeDaysWithEdits: editDates.size,\n };\n\n // 4. Tool Call Trend \u2014 group all calls by (date, toolName)\n const trendMap = new Map<string, Map<string, number>>();\n for (const tc of toolCalls) {\n const date = getDateKey(tc.timestamp, timezone);\n if (!trendMap.has(date)) trendMap.set(date, new Map());\n const dayMap = trendMap.get(date)!;\n dayMap.set(tc.toolName, (dayMap.get(tc.toolName) || 0) + 1);\n }\n const toolCallTrend: DailyToolCall[] = [];\n for (const [date, dayMap] of trendMap) {\n const entry: DailyToolCall = { date };\n for (const [tool, count] of dayMap) {\n entry[tool] = count;\n }\n toolCallTrend.push(entry);\n }\n toolCallTrend.sort((a, b) => a.date.localeCompare(b.date));\n\n // Fill missing tool values with 0 so chart lines don't break\n if (toolCallTrend.length > 0) {\n const allTools = new Set<string>();\n for (const entry of toolCallTrend) {\n for (const key of Object.keys(entry)) {\n if (key !== 'date') allTools.add(key);\n }\n }\n for (const entry of toolCallTrend) {\n for (const tool of allTools) {\n if (entry[tool] === undefined) {\n entry[tool] = 0;\n }\n }\n }\n }\n\n return { codeChangeTrend, toolUsageDistribution, productivityKPIs, toolCallTrend };\n}\n", "import { type Request, type Response } from 'express';\nimport { cache } from '../cache.js';\nimport { validateAnalytics } from '../../shared/schemas.js';\nimport { extractClaudeToolCalls, extractOpenClawToolCalls, computeAnalytics } from '../analyticsParser.js';\n\nconst EMPTY_ANALYTICS = {\n codeChangeTrend: [],\n toolUsageDistribution: [],\n productivityKPIs: { avgLinesPerEdit: 0, filesModifiedPerDay: 0, addDeleteRatio: 0, totalEdits: 0, totalFilesModified: 0, activeDaysWithEdits: 0 },\n toolCallTrend: [],\n};\n\nexport async function getAnalytics(req: Request, res: Response): Promise<void> {\n const agent = req.query.agent as string || 'claude';\n const project = req.query.project as string || undefined;\n\n if (agent === 'codex' || agent === 'opencode') {\n res.json(EMPTY_ANALYTICS);\n return;\n }\n\n try {\n const cacheKey = `analytics:${agent}:${project || 'all'}`;\n const cached = cache.get(cacheKey);\n if (cached) {\n res.json(cached);\n return;\n }\n\n const toolCalls = agent === 'openclaw'\n ? extractOpenClawToolCalls(project || null)\n : extractClaudeToolCalls(project || null);\n\n const data = computeAnalytics(toolCalls);\n const validated = validateAnalytics(data);\n cache.set(cacheKey, validated);\n res.json(validated);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n console.error('Error fetching analytics:', error);\n res.status(502).json({\n error: `Failed to fetch analytics from ${agent}`,\n hint: message,\n });\n }\n}\n", "import { existsSync, readdirSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\n\nconst CLAUDE_PROJECTS_DIR = join(homedir(), '.claude', 'projects');\nconst CODEX_SESSIONS_DIR = join(homedir(), '.codex', 'sessions');\n\nexport function isClaudeCodeAvailable(): boolean {\n if (!existsSync(CLAUDE_PROJECTS_DIR)) return false;\n try {\n const dirs = readdirSync(CLAUDE_PROJECTS_DIR, { withFileTypes: true });\n return dirs.some(d => d.isDirectory());\n } catch {\n return false;\n }\n}\n\nexport function isCodexAvailable(): boolean {\n return existsSync(CODEX_SESSIONS_DIR);\n}\n\nexport function isOpencodeAvailable(): boolean {\n return existsSync(join(homedir(), '.local', 'share', 'opencode', 'opencode.db'));\n}\n\nexport function detectAvailableAgents(): { claude: boolean; codex: boolean; opencode: boolean } {\n return {\n claude: isClaudeCodeAvailable(),\n codex: isCodexAvailable(),\n opencode: isOpencodeAvailable(),\n };\n}\n", "import type { QuotaProviderId, QuotaSnapshot, QuotaProviderStatus } from './types.js';\n\n/**\n * Structured quota error. Adapters throw this (not generic Error) so the\n * service can classify the status without inspecting message strings.\n * Messages must never contain secrets \u2014 they reach the API response.\n */\nexport class QuotaError extends Error {\n readonly status: QuotaProviderStatus;\n constructor(status: QuotaProviderStatus) {\n const msg = 'message' in status && status.message ? status.message : '';\n super(msg ? `${status.state}: ${msg}` : status.state);\n this.name = 'QuotaError';\n this.status = status;\n }\n}\n\n/**\n * One provider adapter. Responsible only for:\n * 1. detecting whether the provider is configured (credentials present)\n * 2. invoking the upstream interface\n * 3. validating the response\n * 4. converting to a normalized snapshot\n *\n * It does NOT cache, deduplicate, or time out \u2014 the service owns those.\n * Detecting a provider as configured means it appears in the dashboard;\n * fetch() may still fail with an auth/error status.\n */\nexport interface QuotaAdapter {\n readonly provider: QuotaProviderId;\n readonly displayName: string;\n\n /** True when credentials/config exist for this provider locally. Cheap, no network. */\n isConfigured(): Promise<boolean>;\n\n /**\n * Fetch a fresh normalized snapshot. Throws QuotaError on any failure.\n * Must NOT include secrets in any field of the returned snapshot.\n */\n fetch(): Promise<QuotaSnapshot>;\n}\n\n/**\n * Registry of all known adapters, keyed by provider id.\n * Adding a quota provider = ship one adapter + register it here.\n */\nexport class QuotaAdapterRegistry {\n private readonly adapters = new Map<QuotaProviderId, QuotaAdapter>();\n\n register(adapter: QuotaAdapter): void {\n this.adapters.set(adapter.provider, adapter);\n }\n\n get(provider: QuotaProviderId): QuotaAdapter | undefined {\n return this.adapters.get(provider);\n }\n\n list(): QuotaAdapter[] {\n return Array.from(this.adapters.values());\n }\n}\n\n/** Build a baseline snapshot with shared fields filled in. */\nexport function baseSnapshot(\n provider: QuotaProviderId,\n displayName: string,\n opts: { planName?: string; windows?: QuotaSnapshot['windows'] } = {},\n): Pick<QuotaSnapshot, 'provider' | 'displayName' | 'planName' | 'fetchedAt' | 'freshness' | 'windows'> {\n return {\n provider,\n displayName,\n planName: opts.planName,\n fetchedAt: new Date().toISOString(),\n freshness: 'live',\n windows: opts.windows ?? [],\n };\n}\n", "import type { QuotaSnapshot } from './types.js';\n\n/**\n * Per-provider quota cache.\n *\n * Keeps the last successful snapshot so a transient refresh failure returns\n * stale-but-useful data (marked freshness \"stale\") instead of erasing it.\n * The cache is in-memory only \u2014 quota snapshots are live and short-lived,\n * so disk persistence (unlike the usage cache) adds no value.\n */\nexport class QuotaCache {\n private readonly store = new Map<string, { snapshot: QuotaSnapshot; expiresAt: number; updatedAt: number }>();\n\n constructor(private readonly ttlMs: number = 60_000) {}\n\n /** Fresh cached snapshot, or null if expired / absent. */\n getFresh(provider: string): QuotaSnapshot | null {\n const entry = this.store.get(provider);\n if (!entry) return null;\n if (Date.now() > entry.expiresAt) return null;\n return { ...entry.snapshot, freshness: 'cached' };\n }\n\n /** Last successful snapshot regardless of TTL (for stale-while-revalidate). */\n getStale(provider: string): QuotaSnapshot | null {\n const entry = this.store.get(provider);\n if (!entry) return null;\n return { ...entry.snapshot, freshness: 'stale' };\n }\n\n set(snapshot: QuotaSnapshot): void {\n this.store.set(snapshot.provider, {\n snapshot,\n expiresAt: Date.now() + this.ttlMs,\n updatedAt: Date.now(),\n });\n }\n\n clear(provider?: string): void {\n if (provider) this.store.delete(provider);\n else this.store.clear();\n }\n}\n", "import { z } from 'zod';\n\n/**\n * Zod schemas for the normalized quota contract.\n *\n * Provider adapter OUTPUT is validated here before it leaves the service,\n * so the API response (and the Swift client) can always trust the shape.\n * Validation is tolerant of additive upstream fields \u2014 adapters strip those \u2014\n * but strict on fields used in calculations.\n */\n\nexport const QuotaWindowSchema = z.object({\n id: z.string(),\n label: z.string(),\n usedPercent: z.number().min(0).max(100).default(0),\n remainingPercent: z.number().min(0).max(100).default(0),\n used: z.number().optional(),\n limit: z.number().optional(),\n durationMins: z.number().optional(),\n resetsAt: z.string().optional(),\n isUnlimited: z.boolean().optional(),\n modelName: z.string().optional(),\n});\n\nexport const QuotaProviderStatusSchema = z.object({\n state: z.enum([\n 'ok',\n 'auth_failed',\n 'not_configured',\n 'upstream_unavailable',\n 'rate_limited',\n 'malformed_response',\n 'timed_out',\n 'error',\n ]),\n message: z.string().optional(),\n category: z.string().optional(),\n});\n\nexport const QuotaSnapshotSchema = z.object({\n provider: z.enum(['codex', 'claude', 'glm', 'minimax', 'kimi']),\n displayName: z.string(),\n planName: z.string().optional(),\n fetchedAt: z.string(),\n freshness: z.enum(['live', 'cached', 'stale']),\n windows: z.array(QuotaWindowSchema).default([]),\n status: QuotaProviderStatusSchema,\n});\n\nexport const QuotaResponseSchema = z.object({\n providers: z.array(QuotaSnapshotSchema).default([]),\n});\n\nexport function validateQuotaSnapshot(data: unknown) {\n return QuotaSnapshotSchema.parse(data);\n}\n\nexport function validateQuotaResponse(data: unknown) {\n return QuotaResponseSchema.parse(data);\n}\n", "import type { QuotaSnapshot, QuotaProviderId, QuotaProviderStatus, QuotaResponse } from './types.js';\nimport type { QuotaAdapter, QuotaAdapterRegistry } from './adapter.js';\nimport { QuotaError } from './adapter.js';\nimport { QuotaCache } from './cache.js';\nimport { validateQuotaSnapshot } from './schemas.js';\n\n/**\n * Deep quota service. Owns discovery, concurrency, deduplication, caching,\n * stale-while-revalidate, timeouts, and error classification. Adapters only\n * detect + fetch + normalize; everything cross-cutting lives here.\n */\nexport class QuotaService {\n /** Cap concurrent upstream calls so a slow provider can't block the others. */\n private readonly fetchTimeoutMs: number;\n /** In-flight promises keyed by provider id, to dedupe concurrent requests. */\n private readonly inflight = new Map<string, Promise<QuotaSnapshot>>();\n\n constructor(\n private readonly registry: QuotaAdapterRegistry,\n private readonly cache: QuotaCache = new QuotaCache(),\n private readonly configuredCache: QuotaProviderId[] | null = null,\n fetchTimeoutMs = 8_000,\n ) {\n this.fetchTimeoutMs = fetchTimeoutMs;\n }\n\n /**\n * List provider ids that are configured locally. Cheap (no network).\n * The dashboard only shows these \u2014 not-configured providers are excluded.\n */\n async discover(): Promise<QuotaProviderId[]> {\n const all = this.registry.list();\n const checks = await Promise.all(\n all.map(async (a) => ({ id: a.provider, configured: await safeIsConfigured(a) })),\n );\n return checks.filter((c) => c.configured).map((c) => c.id);\n }\n\n /**\n * Fetch one provider's snapshot. Fresh if available; stale-but-retained\n * on failure; never throws (errors become structured statuses).\n */\n async fetchOne(provider: QuotaProviderId): Promise<QuotaSnapshot | null> {\n // 1. Fresh cache hit\n const fresh = this.cache.getFresh(provider);\n if (fresh) return fresh;\n\n const adapter = this.registry.get(provider);\n if (!adapter) return null;\n\n // 2. Dedupe concurrent requests for the same provider\n let p = this.inflight.get(provider);\n if (!p) {\n p = this.fetchWithTimeout(adapter).finally(() => this.inflight.delete(provider));\n this.inflight.set(provider, p);\n }\n return p;\n }\n\n /**\n * Fetch all configured providers concurrently. Partial success: one\n * provider's failure never breaks the others. Order = registry order.\n */\n async fetchAll(): Promise<QuotaResponse> {\n const ids = this.configuredCache ?? (await this.discover());\n const byId = new Map<string, QuotaSnapshot>();\n const snapshots = await Promise.all(ids.map((id) => this.fetchOne(id)));\n // Preserve registry order regardless of completion order.\n for (const adapter of this.registry.list()) {\n const snap = snapshots.find((s) => s?.provider === adapter.provider);\n if (snap) byId.set(adapter.provider, snap);\n }\n return { providers: this.registry.list().map((a) => byId.get(a.provider)).filter((s): s is QuotaSnapshot => !!s) };\n }\n\n /** Force a refresh of all configured providers, bypassing the cache. */\n async refreshAll(): Promise<QuotaResponse> {\n // Cache-clear only the freshness gate; stale data is still retained by fetchOne on failure.\n this.configuredCache?.forEach(() => {});\n for (const adapter of this.registry.list()) {\n this.cache.clear(adapter.provider);\n }\n return this.fetchAll();\n }\n\n private async fetchWithTimeout(adapter: QuotaAdapter): Promise<QuotaSnapshot> {\n try {\n const snapshot = await withTimeout(adapter.fetch(), this.fetchTimeoutMs, adapter.provider);\n const validated = validateQuotaSnapshot(snapshot);\n this.cache.set(validated);\n return validated;\n } catch (err) {\n return this.handleFailure(adapter, err);\n }\n }\n\n private handleFailure(adapter: QuotaAdapter, err: unknown): QuotaSnapshot {\n let status: QuotaProviderStatus;\n if (err instanceof QuotaError) {\n status = err.status;\n } else if (err instanceof TimeoutError) {\n status = { state: 'timed_out', message: `upstream did not respond within ${this.fetchTimeoutMs}ms` };\n } else {\n status = { state: 'error', message: redact(err), category: 'unexpected' };\n }\n\n // Retain last good snapshot as stale.\n const stale = this.cache.getStale(adapter.provider);\n if (stale) {\n return { ...stale, freshness: 'stale', status };\n }\n // No prior data \u2014 surface the structured error so the user can act on it.\n return {\n provider: adapter.provider,\n displayName: adapter.displayName,\n fetchedAt: new Date().toISOString(),\n freshness: 'stale',\n windows: [],\n status,\n };\n }\n}\n\nclass TimeoutError extends Error {\n constructor(provider: string) {\n super(`quota fetch timed out: ${provider}`);\n this.name = 'TimeoutError';\n }\n}\n\nfunction withTimeout<T>(p: Promise<T>, ms: number, provider: string): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => reject(new TimeoutError(provider)), ms);\n p.then(\n (v) => { clearTimeout(timer); resolve(v); },\n (e) => { clearTimeout(timer); reject(e); },\n );\n });\n}\n\nasync function safeIsConfigured(adapter: QuotaAdapter): Promise<boolean> {\n try {\n return await adapter.isConfigured();\n } catch {\n return false;\n }\n}\n\n/** Strip anything that looks like a token/key from an error before it surfaces. */\nfunction redact(err: unknown): string {\n const msg = err instanceof Error ? err.message : String(err);\n return msg.replace(/(sk-[A-Za-z0-9_-]{6,})[A-Za-z0-9_-]*/g, '$1\u2026')\n .replace(/(Bearer\\s+)[A-Za-z0-9._-]+/gi, '$1\u2026')\n .slice(0, 200);\n}\n", "import { existsSync, readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { spawn, type ChildProcessWithoutNullStreams } from 'node:child_process';\nimport type { QuotaSnapshot } from '../types.js';\nimport type { QuotaAdapter } from '../adapter.js';\nimport { QuotaError, baseSnapshot } from '../adapter.js';\nimport { unixToIso, windowFromPercent } from '../helpers.js';\n\n/**\n * OpenAI Codex adapter.\n *\n * Source: official `codex app-server` JSON-RPC 2.0 method\n * `account/rateLimits/read`. We do NOT read the OAuth token or call the\n * backend usage endpoint directly \u2014 the app-server holds the auth and\n * returns authoritative rate limits.\n *\n * Credentials live at `$CODEX_HOME/auth.json` (default ~/.codex/auth.json)\n * or the OS keyring; presence of auth.json is our cheap configured check.\n */\n\ninterface CodexRateLimit {\n limitId?: string;\n limitName?: string | null;\n primary?: { usedPercent?: number; windowDurationMins?: number; resetsAt?: number } | null;\n secondary?: { usedPercent?: number; windowDurationMins?: number; resetsAt?: number } | null;\n}\n\ninterface CodexRateLimitsResult {\n rateLimits?: CodexRateLimit;\n rateLimitsByLimitId?: Record<string, CodexRateLimit>;\n planType?: string;\n}\n\nfunction codexHome(): string {\n return process.env.CODEX_HOME || join(homedir(), '.codex');\n}\n\nexport const codexAdapter: QuotaAdapter = {\n provider: 'codex',\n displayName: 'OpenAI Codex',\n\n async isConfigured(): Promise<boolean> {\n // auth.json present signals the user has logged in (file credential store).\n // Keyring-stored creds won't show a file, but the app-server itself is the\n // authority there \u2014 so also treat the codex binary being runnable as configured.\n if (existsSync(join(codexHome(), 'auth.json'))) return true;\n return await codexBinaryAvailable();\n },\n\n async fetch(): Promise<QuotaSnapshot> {\n const result = await queryRateLimits();\n const buckets = result.rateLimitsByLimitId ?? (result.rateLimits ? { primary: result.rateLimits } : {});\n const windows = [];\n\n for (const [key, bucket] of Object.entries(buckets)) {\n if (bucket.primary) {\n windows.push(windowFromPercent(`codex_${key}_primary`, labelForBucket(key, 'primary', bucket), bucket.primary.usedPercent ?? 0, {\n durationMins: bucket.primary.windowDurationMins,\n resetsAt: unixToIso(bucket.primary.resetsAt),\n }));\n }\n if (bucket.secondary) {\n windows.push(windowFromPercent(`codex_${key}_secondary`, labelForBucket(key, 'secondary', bucket), bucket.secondary.usedPercent ?? 0, {\n durationMins: bucket.secondary.windowDurationMins,\n resetsAt: unixToIso(bucket.secondary.resetsAt),\n }));\n }\n }\n\n const snap = baseSnapshot('codex', 'OpenAI Codex', {\n planName: result.planType ? capitalize(result.planType) : undefined,\n windows,\n });\n return { ...snap, status: { state: 'ok' } };\n },\n};\n\nfunction labelForBucket(key: string, tier: 'primary' | 'secondary', bucket: CodexRateLimit): string {\n const dur = tier === 'primary' ? bucket.primary?.windowDurationMins : bucket.secondary?.windowDurationMins;\n const durLabel = dur ? durationLabel(dur) : capitalize(tier);\n // Prefer an explicit limit name; fall back to the bucket key, then the tier.\n const who = bucket.limitName || (key && key !== 'primary' ? key : '');\n return who ? `${capitalize(who)} \u00B7 ${durLabel}` : durLabel;\n}\n\nfunction durationLabel(mins: number): string {\n if (mins >= 10080) return 'Weekly';\n if (mins >= 1440) return `${Math.round(mins / 1440)}-Day`;\n if (mins >= 60) return `${Math.round(mins / 60)}-Hour`;\n return `${mins}m`;\n}\n\nfunction capitalize(s: string): string {\n return s.charAt(0).toUpperCase() + s.slice(1);\n}\n\n// --- JSON-RPC over the codex app-server ---\n\nasync function queryRateLimits(): Promise<CodexRateLimitsResult> {\n if (!(await codexBinaryAvailable())) {\n throw new QuotaError({ state: 'not_configured', message: 'codex CLI not found on PATH' });\n }\n const proc = spawn('codex', ['app-server'], { stdio: ['pipe', 'pipe', 'pipe'] });\n const client = new JsonRpcClient(proc);\n try {\n await client.request('initialize', {\n protocolVersion: '2025-03-26',\n clientInfo: { name: 'tokendash', version: '1.0.0' },\n });\n client.notify('initialized', {});\n const res = await client.request<CodexRateLimitsResult>('account/rateLimits/read', {});\n return res;\n } catch (err) {\n throw toQuotaError(err);\n } finally {\n client.dispose();\n try { proc.kill('SIGKILL'); } catch { /* already gone */ }\n }\n}\n\nfunction toQuotaError(err: unknown): QuotaError {\n const msg = err instanceof Error ? err.message : String(err);\n if (/not found|ENOENT|spawn/i.test(msg)) {\n return new QuotaError({ state: 'not_configured', message: 'codex app-server unavailable' });\n }\n if (/401|403|unauthor|auth/i.test(msg)) {\n return new QuotaError({ state: 'auth_failed', message: 'codex session not authenticated' });\n }\n return new QuotaError({ state: 'upstream_unavailable', message: msg.slice(0, 200) });\n}\n\n/** Minimal line-delimited JSON-RPC 2.0 client over a child process stdio. */\nclass JsonRpcClient {\n private id = 0;\n private buffer = '';\n private pending = new Map<number, { resolve: (v: unknown) => void; reject: (e: Error) => void }>();\n private disposed = false;\n\n constructor(private proc: ChildProcessWithoutNullStreams) {\n proc.stdout.setEncoding('utf8');\n proc.stdout.on('data', (chunk: string) => this.onData(chunk));\n proc.on('error', (err) => this.failAll(err));\n proc.on('close', () => this.failAll(new Error('codex app-server closed unexpectedly')));\n }\n\n request<T = unknown>(method: string, params: unknown): Promise<T> {\n if (this.disposed) return Promise.reject(new Error('client disposed'));\n const id = ++this.id;\n const msg = JSON.stringify({ jsonrpc: '2.0', id, method, params }) + '\\n';\n return new Promise<T>((resolve, reject) => {\n this.pending.set(id, { resolve: resolve as (v: unknown) => void, reject });\n this.proc.stdin.write(msg, (err) => {\n if (err) reject(err instanceof Error ? err : new Error(String(err)));\n });\n });\n }\n\n notify(method: string, params: unknown): void {\n if (this.disposed) return;\n const msg = JSON.stringify({ jsonrpc: '2.0', method, params }) + '\\n';\n this.proc.stdin.write(msg, () => {});\n }\n\n dispose(): void {\n this.disposed = true;\n this.failAll(new Error('disposed'));\n }\n\n private onData(chunk: string): void {\n this.buffer += chunk;\n let idx: number;\n while ((idx = this.buffer.indexOf('\\n')) >= 0) {\n const line = this.buffer.slice(0, idx).trim();\n this.buffer = this.buffer.slice(idx + 1);\n if (!line) continue;\n let msg: { id?: number; result?: unknown; error?: { message?: string } };\n try {\n msg = JSON.parse(line);\n } catch {\n continue; // skip non-JSON framing lines\n }\n if (msg.id === undefined) continue; // notifications\n const entry = this.pending.get(msg.id);\n if (!entry) continue;\n this.pending.delete(msg.id);\n if (msg.error) entry.reject(new Error(msg.error.message || 'codex JSON-RPC error'));\n else entry.resolve(msg.result);\n }\n }\n\n private failAll(err: Error): void {\n for (const [, entry] of this.pending) entry.reject(err);\n this.pending.clear();\n }\n}\n\nlet cachedCodexPath: string | null | undefined;\n\nasync function codexBinaryAvailable(): Promise<boolean> {\n if (cachedCodexPath !== undefined) return cachedCodexPath !== null;\n return new Promise<boolean>((resolve) => {\n const proc = spawn('which', ['codex'], { stdio: ['ignore', 'pipe', 'ignore'] });\n let out = '';\n proc.stdout.on('data', (c) => { out += c; });\n proc.on('close', () => {\n cachedCodexPath = out.trim() || null;\n resolve(cachedCodexPath !== null);\n });\n proc.on('error', () => { cachedCodexPath = null; resolve(false); });\n });\n}\n\n// Keep readFileSync referenced for potential future auth.json inspection without network.\nvoid readFileSync;\n", "import type { QuotaWindow } from './types.js';\n\n/** Shared helpers for provider adapters. */\n\n/** Convert a Unix timestamp (seconds or ms) to ISO 8601, or undefined. */\nexport function unixToIso(unix: number | string | null | undefined): string | undefined {\n if (unix === null || unix === undefined || unix === '') return undefined;\n const n = typeof unix === 'string' ? parseInt(unix, 10) : unix;\n if (!Number.isFinite(n) || n <= 0) return undefined;\n // Codex/MiniMax use seconds or ms; disambiguate by magnitude.\n const ms = n > 1e12 ? n : n * 1000;\n return new Date(ms).toISOString();\n}\n\n/** Clamp a percentage to 0-100. */\nexport function clampPercent(v: number): number {\n if (!Number.isFinite(v)) return 0;\n return Math.max(0, Math.min(100, v));\n}\n\n/** Round to 1 decimal place so 61.1999... \u2192 61.2, integers unchanged. */\nfunction round1(v: number): number {\n return Math.round(v * 10) / 10;\n}\n\n/** Build a QuotaWindow from used/limit percentages. */\nexport function windowFromPercent(\n id: string,\n label: string,\n usedPercent: number,\n opts: { durationMins?: number; resetsAt?: string; used?: number; limit?: number; modelName?: string; isUnlimited?: boolean } = {},\n): QuotaWindow {\n const used = round1(clampPercent(usedPercent));\n return {\n id,\n label,\n usedPercent: used,\n remainingPercent: round1(100 - used),\n durationMins: opts.durationMins,\n resetsAt: opts.resetsAt,\n used: opts.used,\n limit: opts.limit,\n modelName: opts.modelName,\n isUnlimited: opts.isUnlimited,\n };\n}\n\n/** Build a QuotaWindow from absolute used/limit counts. */\nexport function windowFromCounts(\n id: string,\n label: string,\n used: number,\n limit: number,\n opts: { durationMins?: number; resetsAt?: string; modelName?: string } = {},\n): QuotaWindow {\n if (limit <= 0) {\n return { id, label, usedPercent: 0, remainingPercent: 100, used, limit, isUnlimited: true, ...opts };\n }\n const pct = round1(clampPercent((used / limit) * 100));\n return {\n id,\n label,\n usedPercent: pct,\n remainingPercent: round1(100 - pct),\n used,\n limit,\n ...opts,\n };\n}\n\n/**\n * Fetch JSON with a timeout. Adapters that hit HTTP APIs use this so they\n * share redaction + abort behavior. Returns parsed JSON or throws.\n */\nexport async function fetchJsonWithTimeout(\n url: string,\n opts: { headers?: Record<string, string>; timeoutMs?: number } = {},\n): Promise<unknown> {\n const ctrl = new AbortController();\n const timer = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 8_000);\n try {\n const res = await fetch(url, { headers: opts.headers, signal: ctrl.signal });\n if (!res.ok) {\n const body = await res.text().catch(() => '');\n throw new HttpError(res.status, body.slice(0, 200));\n }\n return await res.json();\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport class HttpError extends Error {\n constructor(readonly status: number, readonly body: string) {\n super(`HTTP ${status}`);\n this.name = 'HttpError';\n }\n}\n\n/** Map an HTTP status to a coarse auth/upstream classification. */\nexport function classifyHttpError(err: HttpError): { state: 'auth_failed' | 'rate_limited' | 'upstream_unavailable'; message: string } {\n if (err.status === 401 || err.status === 403) {\n return { state: 'auth_failed', message: 'credential rejected by provider' };\n }\n if (err.status === 429) {\n return { state: 'rate_limited', message: 'provider throttled the request' };\n }\n return { state: 'upstream_unavailable', message: `provider returned HTTP ${err.status}` };\n}\n", "import { existsSync, readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { execFileSync } from 'node:child_process';\nimport type { QuotaSnapshot } from '../types.js';\nimport type { QuotaAdapter } from '../adapter.js';\nimport { QuotaError, baseSnapshot } from '../adapter.js';\nimport { fetchJsonWithTimeout, HttpError, classifyHttpError, windowFromPercent } from '../helpers.js';\n\n/**\n * Claude Code adapter.\n *\n * Authoritative source: Anthropic OAuth usage endpoint\n * `GET https://api.anthropic.com/api/oauth/usage`, called with the locally\n * stored Claude Code OAuth token. This is the same data Claude Code surfaces\n * in its statusline, queried directly so it stays fresh without Claude Code\n * running.\n *\n * Credentials (macOS Keychain `Claude Code-credentials`, or\n * ~/.claude/.credentials.json on other platforms) are read into memory only\n * to build the request and never serialized into the response.\n */\n\ninterface ClaudeUsageWindow {\n utilization?: number;\n resets_at?: string;\n}\n\ninterface ClaudeUsageResponse {\n five_hour?: ClaudeUsageWindow;\n seven_day?: ClaudeUsageWindow;\n seven_day_opus?: ClaudeUsageWindow | null;\n seven_day_oauth_apps?: ClaudeUsageWindow | null;\n}\n\nexport const claudeAdapter: QuotaAdapter = {\n provider: 'claude',\n displayName: 'Claude Code',\n\n async isConfigured(): Promise<boolean> {\n const token = readClaudeToken();\n return !!token;\n },\n\n async fetch(): Promise<QuotaSnapshot> {\n const token = readClaudeToken();\n if (!token) {\n throw new QuotaError({ state: 'not_configured', message: 'no Claude Code OAuth credential found' });\n }\n let data: ClaudeUsageResponse;\n try {\n data = (await fetchJsonWithTimeout('https://api.anthropic.com/api/oauth/usage', {\n headers: {\n Authorization: `Bearer ${token}`,\n 'anthropic-beta': 'oauth-2025-04-20',\n 'Content-Type': 'application/json',\n },\n })) as ClaudeUsageResponse;\n } catch (err) {\n throw classifyFetchError(err);\n }\n\n const windows = [];\n if (data.five_hour) {\n windows.push(windowFromPercent('five_hour', '5-Hour Window', data.five_hour.utilization ?? 0, {\n durationMins: 300,\n resetsAt: normalizeIso(data.five_hour.resets_at),\n }));\n }\n if (data.seven_day) {\n windows.push(windowFromPercent('seven_day', 'Weekly', data.seven_day.utilization ?? 0, {\n durationMins: 10080,\n resetsAt: normalizeIso(data.seven_day.resets_at),\n }));\n }\n if (data.seven_day_opus?.utilization !== undefined && data.seven_day_opus?.utilization !== null) {\n windows.push(windowFromPercent('seven_day_opus', 'Weekly \u00B7 Opus', data.seven_day_opus.utilization, {\n durationMins: 10080,\n resetsAt: normalizeIso(data.seven_day_opus.resets_at),\n }));\n }\n\n const snap = baseSnapshot('claude', 'Claude Code', { windows });\n return { ...snap, status: { state: 'ok' } };\n },\n};\n\nfunction classifyFetchError(err: unknown): QuotaError {\n if (err instanceof HttpError) {\n const c = classifyHttpError(err);\n return new QuotaError(c);\n }\n const msg = err instanceof Error ? err.message : String(err);\n return new QuotaError({ state: 'upstream_unavailable', message: msg.slice(0, 200) });\n}\n\n/** The OAuth response returns ISO strings; pass through (normalize Z suffix). */\nfunction normalizeIso(s?: string): string | undefined {\n return s ? new Date(s).toISOString() : undefined;\n}\n\n/** Read the Claude Code OAuth access token from keychain (macOS) or file. */\nfunction readClaudeToken(): string | null {\n if (process.platform === 'darwin') {\n const token = readFromKeychain();\n if (token) return token;\n // Fall through to file for headless/SSH sessions where keychain is locked.\n }\n const configDir = process.env.CLAUDE_CONFIG_DIR || join(homedir(), '.claude');\n const credPath = join(configDir, '.credentials.json');\n if (existsSync(credPath)) {\n try {\n const parsed = JSON.parse(readFileSync(credPath, 'utf8'));\n return parsed?.claudeAiOauth?.accessToken ?? null;\n } catch {\n return null;\n }\n }\n return null;\n}\n\nfunction readFromKeychain(): string | null {\n // Keychain entries may carry a per-installation GUID suffix; try the base\n // name first, then any matching suffix.\n const candidates = ['Claude Code-credentials'];\n try {\n const list = execFileSync('security', ['dump-keychain'], { stdio: ['ignore', 'pipe', 'ignore'], encoding: 'utf8' });\n for (const m of list.matchAll(/\"srvname\"<blob>=\"([^\"]*Claude Code-credentials[^\"]*)\"/g)) {\n if (m[1] && !candidates.includes(m[1])) candidates.push(m[1]);\n }\n } catch {\n // dump-keychain may prompt or fail; base name is the common case.\n }\n for (const name of candidates) {\n try {\n const raw = execFileSync('security', ['find-generic-password', '-s', name, '-w'], {\n stdio: ['ignore', 'pipe', 'ignore'],\n encoding: 'utf8',\n }).trim();\n if (!raw) continue;\n // The stored value is itself a JSON blob holding the OAuth tokens.\n try {\n const parsed = JSON.parse(raw);\n return parsed?.claudeAiOauth?.accessToken ?? null;\n } catch {\n return raw; // already a bare token in some setups\n }\n } catch {\n continue;\n }\n }\n return null;\n}\n", "import { existsSync, readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport type { QuotaSnapshot } from '../types.js';\nimport type { QuotaAdapter } from '../adapter.js';\nimport { QuotaError, baseSnapshot } from '../adapter.js';\nimport { fetchJsonWithTimeout, HttpError, classifyHttpError, windowFromPercent, windowFromCounts, unixToIso } from '../helpers.js';\nimport { readStoredCredential } from '../credentialsFile.js';\n\n/**\n * GLM (Zhipu) Coding Plan adapter.\n *\n * Source: the monitor endpoint used by Z.ai's official usage-query plugin,\n * `GET /api/monitor/usage/quota/limit`. Auth is the API key sent directly\n * in the Authorization header WITHOUT a \"Bearer\" prefix. Two base domains:\n * api.z.ai (global, ZAI_API_KEY) and open.bigmodel.cn (CN, ZHIPU_API_KEY).\n */\n\ninterface GlmLimit {\n type?: string; // \"TOKENS_LIMIT\" | \"TIME_LIMIT\"\n percentage?: number;\n usage?: number; // total (for TIME_LIMIT / MCP)\n currentValue?: number; // used (for TIME_LIMIT / MCP)\n remaining?: number;\n nextResetTime?: number; // unix seconds\n}\n\ninterface GlmQuotaResponse {\n code?: number;\n msg?: string;\n success?: boolean;\n data?: { limits?: GlmLimit[]; level?: string };\n}\n\nexport const glmAdapter: QuotaAdapter = {\n provider: 'glm',\n displayName: 'GLM Coding Plan',\n\n async isConfigured(): Promise<boolean> {\n return !!resolveCredential();\n },\n\n async fetch(): Promise<QuotaSnapshot> {\n const cred = resolveCredential();\n if (!cred) {\n throw new QuotaError({ state: 'not_configured', message: 'set ZAI_API_KEY or ZHIPU_API_KEY' });\n }\n\n let data: GlmQuotaResponse;\n try {\n data = (await fetchJsonWithTimeout(`${cred.base}/api/monitor/usage/quota/limit`, {\n headers: {\n // GLM wants the raw key, NOT \"Bearer <key>\".\n Authorization: cred.key,\n 'Accept-Language': 'en-US,en',\n 'Content-Type': 'application/json',\n },\n })) as GlmQuotaResponse;\n } catch (err) {\n throw classifyFetchError(err);\n }\n\n if (!data?.success && data?.code !== 200) {\n throw new QuotaError({ state: 'upstream_unavailable', message: data?.msg || 'GLM quota request failed' });\n }\n\n const limits = data.data?.limits ?? [];\n const windows = [];\n\n // TOKENS_LIMIT: two entries (5h + weekly). Sort by reset time so the\n // shorter window is labeled first.\n const tokenLimits = limits\n .filter((l) => l.type === 'TOKENS_LIMIT' && typeof l.percentage === 'number')\n .sort((a, b) => (a.nextResetTime ?? 0) - (b.nextResetTime ?? 0));\n tokenLimits.forEach((l, i) => {\n const isShort = i === 0; // first after sort = nearer reset = 5h\n windows.push(windowFromPercent(\n isShort ? 'glm_5h' : 'glm_weekly',\n isShort ? '5-Hour Window' : 'Weekly',\n l.percentage ?? 0,\n { durationMins: isShort ? 300 : 10080, resetsAt: unixToIso(l.nextResetTime) },\n ));\n });\n\n // TIME_LIMIT: monthly MCP usage, reported with absolute counts.\n const timeLimit = limits.find((l) => l.type === 'TIME_LIMIT');\n if (timeLimit && typeof timeLimit.usage === 'number') {\n windows.push(windowFromCounts(\n 'glm_mcp_monthly',\n 'MCP \u00B7 Monthly',\n timeLimit.currentValue ?? 0,\n timeLimit.usage,\n ));\n }\n\n const snap = baseSnapshot('glm', 'GLM Coding Plan', {\n planName: data.data?.level ? capitalize(data.data.level) : undefined,\n windows,\n });\n return { ...snap, status: { state: 'ok' } };\n },\n};\n\nfunction classifyFetchError(err: unknown): QuotaError {\n if (err instanceof HttpError) {\n const c = classifyHttpError(err);\n return new QuotaError(c);\n }\n const msg = err instanceof Error ? err.message : String(err);\n return new QuotaError({ state: 'upstream_unavailable', message: msg.slice(0, 200) });\n}\n\nfunction resolveCredential(): { key: string; base: string } | null {\n // 0. Key entered in-app (via the credential sheet) \u2014 highest priority.\n const stored = readStoredCredential('glm');\n if (stored) return { key: stored.apiKey, base: stored.baseUrl || 'https://open.bigmodel.cn' };\n\n // 1. Explicit GLM Coding Plan API keys.\n const zai = envOrConfig('ZAI_API_KEY');\n if (zai) return { key: zai, base: envOrConfig('ZAI_BASE_URL') || 'https://api.z.ai' };\n const zhipu = envOrConfig('ZHIPU_API_KEY');\n if (zhipu) return { key: zhipu, base: envOrConfig('ZHIPU_BASE_URL') || 'https://open.bigmodel.cn' };\n\n // 2. cc-switch / Claude Code scenario: ANTHROPIC_BASE_URL is pointed at a\n // GLM domain (open.bigmodel.cn or api.z.ai) and the plan token lives in\n // ANTHROPIC_AUTH_TOKEN / ANTHROPIC_API_KEY. The monitor endpoint shares the\n // same token; we just swap the path from /api/anthropic to /api/monitor/...\n const anthropicBase = envOrConfig('ANTHROPIC_BASE_URL');\n if (anthropicBase && isGlmHost(anthropicBase)) {\n const origin = originOf(anthropicBase);\n const token = envOrConfig('ANTHROPIC_AUTH_TOKEN') || envOrConfig('ANTHROPIC_API_KEY');\n if (origin && token) return { key: token, base: origin };\n }\n return null;\n}\n\nfunction isGlmHost(url: string): boolean {\n const h = url.toLowerCase();\n return h.includes('bigmodel.cn') || h.includes('z.ai');\n}\n\nfunction originOf(url: string): string | null {\n try {\n const u = new URL(url);\n return `${u.protocol}//${u.host}`;\n } catch {\n return null;\n }\n}\n\n/**\n * Read an env var, falling back to the Claude Code settings.json `env` block.\n * Needed because the Swift app launches the daemon from Finder, where the\n * ANTHROPIC_* vars Claude Code injects into its own process are absent \u2014 but\n * they're persisted in ~/.claude/settings.json (how cc-switch writes them).\n */\nlet claudeSettingsEnv: Record<string, string> | null | undefined;\nfunction envOrConfig(key: string): string | undefined {\n if (process.env[key]) return process.env[key];\n if (claudeSettingsEnv === undefined) claudeSettingsEnv = loadClaudeSettingsEnv();\n return claudeSettingsEnv?.[key];\n}\n\nfunction loadClaudeSettingsEnv(): Record<string, string> | null {\n const configDir = process.env.CLAUDE_CONFIG_DIR || join(homedir(), '.claude');\n try {\n const path = join(configDir, 'settings.json');\n if (!existsSync(path)) return null;\n const parsed = JSON.parse(readFileSync(path, 'utf8'));\n return parsed?.env && typeof parsed.env === 'object' ? parsed.env as Record<string, string> : null;\n } catch {\n return null;\n }\n}\n\nfunction capitalize(s: string): string {\n return s.charAt(0).toUpperCase() + s.slice(1);\n}\n", "import { existsSync, readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\n\n/**\n * Reads the cross-process credential bridge file written by the Swift app's\n * CredentialSheet (~/.tokendash/credentials.json). Adapters check this FIRST \u2014\n * before env vars and settings.json \u2014 so a key entered in-app wins.\n *\n * Read fresh on each call (no cache) so a credential saved via the sheet takes\n * effect on the very next quota refresh. The file is tiny, so the cost is nil.\n */\nexport interface StoredCredential {\n apiKey: string;\n baseUrl?: string;\n}\n\nexport function readStoredCredential(provider: string): StoredCredential | null {\n try {\n const path = join(homedir(), '.tokendash', 'credentials.json');\n if (!existsSync(path)) return null;\n const all = JSON.parse(readFileSync(path, 'utf8')) as Record<string, unknown>;\n const entry = all?.[provider];\n if (entry && typeof entry === 'object' && typeof (entry as { apiKey?: unknown }).apiKey === 'string') {\n const apiKey = (entry as { apiKey: string }).apiKey;\n if (!apiKey) return null;\n const baseUrl = (entry as { baseUrl?: unknown }).baseUrl;\n return { apiKey, baseUrl: typeof baseUrl === 'string' ? baseUrl : undefined };\n }\n return null;\n } catch {\n return null;\n }\n}\n", "import type { QuotaSnapshot } from '../types.js';\nimport type { QuotaAdapter } from '../adapter.js';\nimport { QuotaError, baseSnapshot } from '../adapter.js';\nimport { fetchJsonWithTimeout, HttpError, classifyHttpError, windowFromCounts, unixToIso } from '../helpers.js';\nimport { readStoredCredential } from '../credentialsFile.js';\n\n/**\n * MiniMax Coding Plan (Token Plan) adapter.\n *\n * Source: official `GET /v1/token_plan/remains`, Bearer auth with the\n * Subscription Key (sk-..., NOT the pay-as-you-go API key). Per-model buckets,\n * each with a 5-hour interval window and a weekly window.\n *\n * NAMING GOTCHA: despite the name, `current_interval_usage_count` /\n * `current_weekly_usage_count` return REMAINING units, not consumed. We invert\n * to derive used = total - usage_count.\n */\n\ninterface MinimaxModelRemain {\n model_name?: string;\n start_time?: number; // unix ms\n end_time?: number; // unix ms\n remains_time?: number;\n current_interval_usage_count?: number; // REMAINING (misnamed upstream)\n current_interval_total_count?: number; // total\n current_weekly_usage_count?: number; // REMAINING (misnamed upstream)\n current_weekly_total_count?: number; // total\n}\n\ninterface MinimaxRemainsResponse {\n model_remains?: MinimaxModelRemain[];\n base_resp?: { status_code?: number; status_msg?: string };\n}\n\nexport const minimaxAdapter: QuotaAdapter = {\n provider: 'minimax',\n displayName: 'MiniMax Coding Plan',\n\n async isConfigured(): Promise<boolean> {\n return !!resolveCredential();\n },\n\n async fetch(): Promise<QuotaSnapshot> {\n const cred = resolveCredential();\n if (!cred) {\n throw new QuotaError({ state: 'not_configured', message: 'set MINIMAX_API_KEY (Subscription Key)' });\n }\n\n let data: MinimaxRemainsResponse;\n try {\n data = (await fetchJsonWithTimeout(`${cred.base}/v1/token_plan/remains`, {\n headers: {\n Authorization: `Bearer ${cred.key}`,\n 'Content-Type': 'application/json',\n },\n })) as MinimaxRemainsResponse;\n } catch (err) {\n throw classifyFetchError(err);\n }\n\n if (data.base_resp?.status_code && data.base_resp.status_code !== 0) {\n throw new QuotaError({\n state: 'upstream_unavailable',\n message: data.base_resp.status_msg || `MiniMax error ${data.base_resp.status_code}`,\n });\n }\n\n const windows = [];\n for (const m of data.model_remains ?? []) {\n const model = m.model_name ?? 'MiniMax';\n const intervalTotal = m.current_interval_total_count ?? 0;\n const intervalRemaining = m.current_interval_usage_count ?? 0;\n // used = total - remaining (the \"*_usage_count\" fields are misnamed).\n if (intervalTotal > 0) {\n windows.push(windowFromCounts(\n `minimax_5h_${model}`,\n `5-Hour \u00B7 ${model}`,\n Math.max(0, intervalTotal - intervalRemaining),\n intervalTotal,\n { durationMins: 300, resetsAt: unixToIso(m.end_time) },\n ));\n }\n const weeklyTotal = m.current_weekly_total_count ?? 0;\n const weeklyRemaining = m.current_weekly_usage_count ?? 0;\n if (weeklyTotal > 0) {\n windows.push(windowFromCounts(\n `minimax_weekly_${model}`,\n `Weekly \u00B7 ${model}`,\n Math.max(0, weeklyTotal - weeklyRemaining),\n weeklyTotal,\n { durationMins: 10080 },\n ));\n }\n }\n\n const snap = baseSnapshot('minimax', 'MiniMax Coding Plan', { windows });\n return { ...snap, status: { state: 'ok' } };\n },\n};\n\nfunction classifyFetchError(err: unknown): QuotaError {\n if (err instanceof HttpError) {\n const c = classifyHttpError(err);\n return new QuotaError(c);\n }\n const msg = err instanceof Error ? err.message : String(err);\n return new QuotaError({ state: 'upstream_unavailable', message: msg.slice(0, 200) });\n}\n\nfunction resolveCredential(): { key: string; base: string } | null {\n // 0. Key entered in-app (via the credential sheet) \u2014 highest priority.\n const stored = readStoredCredential('minimax');\n if (stored) {\n const region = (process.env.MINIMAX_REGION || '').toLowerCase();\n const base = stored.baseUrl || (region === 'cn' ? 'https://www.minimaxi.com' : 'https://www.minimax.io');\n return { key: stored.apiKey, base };\n }\n\n const key = process.env.MINIMAX_API_KEY || process.env.MINIMAX_SUBSCRIPTION_KEY;\n if (!key) return null;\n // minimax.io = global, minimaxi.com = China.\n const region = (process.env.MINIMAX_REGION || '').toLowerCase();\n const base = region === 'cn'\n ? (process.env.MINIMAX_BASE_URL || 'https://www.minimaxi.com')\n : (process.env.MINIMAX_BASE_URL || 'https://www.minimax.io');\n return { key, base };\n}\n", "import { existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport { readStoredCredential } from '../credentialsFile.js';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport type { QuotaSnapshot } from '../types.js';\nimport type { QuotaAdapter } from '../adapter.js';\nimport { QuotaError, baseSnapshot } from '../adapter.js';\nimport { fetchJsonWithTimeout, HttpError, classifyHttpError, windowFromCounts } from '../helpers.js';\n\n/**\n * Kimi Code adapter.\n *\n * Source: `GET https://api.kimi.com/coding/v1/usages`, Bearer auth with the\n * OAuth token stored by the Kimi CLI at ~/.kimi/credentials/kimi-code.json.\n * Returns a primary weekly `usage` block plus an arbitrary-length `limits[]`\n * array of windows (e.g. a 5-hour rolling window).\n *\n * Token lifetime is ~1h, so we refresh it from auth.kimi.com before it\n * expires and persist the new tokens back to the same file (the Kimi CLI\n * reads the same file, so both stay in sync).\n */\n\nconst KIMI_CLIENT_ID = '17e5f671-d194-4dfb-9706-5516cb48c098';\nconst KIMI_BASE = 'https://api.kimi.com/coding/v1';\nconst KIMI_AUTH = 'https://auth.kimi.com/api/oauth/token';\n\ninterface KimiCredentials {\n access_token?: string;\n refresh_token?: string;\n expires_at?: number; // unix seconds\n scope?: string;\n token_type?: string;\n}\n\ninterface KimiQuotaDetail {\n limit?: string | number; // STRING-typed upstream\n remaining?: string | number;\n resetTime?: string;\n}\n\ninterface KimiUsageResponse {\n usage?: KimiQuotaDetail; // weekly\n limits?: { window?: { duration?: number; timeUnit?: string }; detail?: KimiQuotaDetail }[];\n user?: { membership?: { level?: string } };\n}\n\ninterface TokenRefreshResponse {\n access_token?: string;\n refresh_token?: string;\n expires_in?: number; // seconds\n token_type?: string;\n}\n\nexport const kimiAdapter: QuotaAdapter = {\n provider: 'kimi',\n displayName: 'Kimi Code',\n\n async isConfigured(): Promise<boolean> {\n const cred = readCredentials();\n return !!cred && !!cred.access_token;\n },\n\n async fetch(): Promise<QuotaSnapshot> {\n const credPath = credentialsPath();\n let cred = readCredentials();\n if (!cred || !cred.access_token) {\n throw new QuotaError({ state: 'not_configured', message: 'run `kimi` to log in first' });\n }\n\n // Refresh proactively if within 5 min of expiry.\n const nowSec = Math.floor(Date.now() / 1000);\n if (cred.expires_at && cred.expires_at - nowSec < 300 && cred.refresh_token) {\n cred = await refreshToken(credPath, cred.refresh_token).catch(() => cred!);\n }\n\n let data: KimiUsageResponse;\n try {\n data = (await fetchJsonWithTimeout(`${KIMI_BASE}/usages`, {\n headers: {\n Authorization: `Bearer ${cred.access_token}`,\n Accept: 'application/json',\n },\n })) as KimiUsageResponse;\n } catch (err) {\n throw classifyFetchError(err);\n }\n\n const windows = [];\n\n // Primary weekly usage.\n if (data.usage) {\n const { used, limit } = toCounts(data.usage);\n if (limit > 0) {\n windows.push(windowFromCounts('kimi_weekly', 'Weekly', used, limit, {\n durationMins: 10080,\n resetsAt: normalizeIso(data.usage.resetTime),\n }));\n }\n }\n\n // Arbitrary-length limits[] (e.g. 5-hour rolling window).\n for (let i = 0; i < (data.limits?.length ?? 0); i++) {\n const entry = data.limits![i];\n const detail = entry?.detail;\n if (!detail) continue;\n const { used, limit } = toCounts(detail);\n if (limit <= 0) continue;\n const mins = minutesForWindow(entry?.window);\n windows.push(windowFromCounts(`kimi_limit_${i}`, mins ? `${durationLabel(mins)} Window` : `Window ${i + 1}`, used, limit, {\n durationMins: mins,\n resetsAt: normalizeIso(detail.resetTime),\n }));\n }\n\n const snap = baseSnapshot('kimi', 'Kimi Code', {\n planName: data.user?.membership?.level ? prettifyLevel(data.user.membership.level) : undefined,\n windows,\n });\n return { ...snap, status: { state: 'ok' } };\n },\n};\n\nfunction classifyFetchError(err: unknown): QuotaError {\n if (err instanceof HttpError) {\n const c = classifyHttpError(err);\n return new QuotaError(c);\n }\n const msg = err instanceof Error ? err.message : String(err);\n return new QuotaError({ state: 'upstream_unavailable', message: msg.slice(0, 200) });\n}\n\n/** Kimi returns limit/remaining as STRINGS \u2014 coerce and invert to used. */\nfunction toCounts(detail: KimiQuotaDetail): { used: number; limit: number } {\n const limit = toNumber(detail.limit);\n const remaining = toNumber(detail.remaining);\n if (limit <= 0) return { used: 0, limit: 0 };\n return { used: Math.max(0, limit - remaining), limit };\n}\n\nfunction toNumber(v: string | number | undefined): number {\n if (v === undefined || v === null) return 0;\n const n = typeof v === 'string' ? parseFloat(v) : v;\n return Number.isFinite(n) ? n : 0;\n}\n\nfunction minutesForWindow(window?: { duration?: number; timeUnit?: string }): number | undefined {\n if (!window?.duration) return undefined;\n const unit = (window.timeUnit || '').toUpperCase();\n if (unit.includes('HOUR')) return window.duration * 60;\n if (unit.includes('DAY')) return window.duration * 1440;\n return window.duration; // default minutes\n}\n\nfunction durationLabel(mins: number): string {\n if (mins >= 10080) return 'Weekly';\n if (mins >= 1440) return `${Math.round(mins / 1440)}-Day`;\n if (mins >= 60) return `${Math.round(mins / 60)}-Hour`;\n return `${mins}m`;\n}\n\nfunction normalizeIso(s?: string): string | undefined {\n return s ? new Date(s).toISOString() : undefined;\n}\n\nfunction prettifyLevel(level: string): string {\n // \"LEVEL_INTERMEDIATE\" -> \"Intermediate\"\n return level.replace(/^LEVEL_/, '').toLowerCase().replace(/(^|_)(\\w)/g, (_, __, c: string) => ' ' + c.toUpperCase()).trim();\n}\n\nfunction kimiDataDir(): string {\n return process.env.KIMI_DATA_DIR || join(homedir(), '.kimi');\n}\n\nfunction credentialsPath(): string {\n return join(kimiDataDir(), 'credentials', 'kimi-code.json');\n}\n\nfunction readCredentials(): KimiCredentials | null {\n // 0. Token entered in-app (via the credential sheet) \u2014 highest priority.\n // Treated as a bare access token; no refresh token, so it's used as-is.\n const stored = readStoredCredential('kimi');\n if (stored?.apiKey) {\n return { access_token: stored.apiKey, token_type: 'Bearer' };\n }\n\n const path = credentialsPath();\n if (!existsSync(path)) return null;\n try {\n return JSON.parse(readFileSync(path, 'utf8')) as KimiCredentials;\n } catch {\n return null;\n }\n}\n\nasync function refreshToken(credPath: string, refreshToken: string): Promise<KimiCredentials> {\n const body = new URLSearchParams({\n client_id: KIMI_CLIENT_ID,\n grant_type: 'refresh_token',\n refresh_token: refreshToken,\n });\n const res = await fetch(KIMI_AUTH, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body,\n });\n if (!res.ok) throw new Error(`token refresh failed: HTTP ${res.status}`);\n const tokens = (await res.json()) as TokenRefreshResponse;\n const updated: KimiCredentials = {\n access_token: tokens.access_token,\n refresh_token: tokens.refresh_token || refreshToken,\n expires_at: Math.floor(Date.now() / 1000) + (tokens.expires_in ?? 3600),\n token_type: tokens.token_type || 'Bearer',\n };\n // Persist back so the Kimi CLI and this adapter share the refreshed token.\n try {\n writeFileSync(credPath, JSON.stringify(updated, null, 2), 'utf8');\n } catch {\n // Best-effort; the in-memory token still works for this request.\n }\n return updated;\n}\n", "/**\n * Quota module entry point.\n *\n * Builds the singleton adapter registry + service. The rest of the server\n * imports `quotaService` from here; adapters are wired in registration order,\n * which becomes the dashboard display order.\n */\nimport { QuotaAdapterRegistry } from './adapter.js';\nimport { QuotaCache } from './cache.js';\nimport { QuotaService } from './quotaService.js';\nimport { codexAdapter } from './adapters/codex.js';\nimport { claudeAdapter } from './adapters/claude.js';\nimport { glmAdapter } from './adapters/glm.js';\nimport { minimaxAdapter } from './adapters/minimax.js';\nimport { kimiAdapter } from './adapters/kimi.js';\n\nexport type { QuotaSnapshot, QuotaWindow, QuotaProviderStatus, QuotaResponse, QuotaProviderId } from './types.js';\n\nconst registry = new QuotaAdapterRegistry();\nregistry.register(claudeAdapter);\nregistry.register(codexAdapter);\nregistry.register(glmAdapter);\nregistry.register(minimaxAdapter);\nregistry.register(kimiAdapter);\n\nexport const quotaCache = new QuotaCache();\nexport const quotaService = new QuotaService(registry, quotaCache);\n", "import { type Router, type Request, type Response } from 'express';\nimport { getDaily } from './daily.js';\nimport { getMonthly } from './monthly.js';\nimport { getSession } from './session.js';\nimport { getProjects } from './projects.js';\nimport { getBlocks } from './blocks.js';\nimport { getAnalytics } from './analytics.js';\nimport { detectAvailableAgents } from '../agentDetection.js';\nimport { isOpenClawAccessible } from '../openclawParser.js';\nimport { isOpencodeAccessible } from '../opencodeParser.js';\nimport { quotaService } from '../quota/index.js';\n\nasync function getQuota(_req: Request, res: Response): Promise<void> {\n // Fresh data only \u2014 quotaService handles cache, stale retention, and per-provider\n // failure isolation internally. One provider's error never fails the whole response.\n const force = _req.query.refresh === '1' || _req.query.refresh === 'true';\n try {\n const data = force ? await quotaService.refreshAll() : await quotaService.fetchAll();\n res.json(data);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n res.status(500).json({ error: 'Failed to fetch quota', hint: message });\n }\n}\n\nexport interface AppInfo {\n packageName: string;\n version: string;\n dashboardUrl?: string;\n}\n\nfunction getAgents(_req: Request, res: Response): void {\n try {\n const agents = detectAvailableAgents();\n const available: string[] = [];\n if (agents.claude) available.push('claude');\n if (agents.codex) available.push('codex');\n if (isOpenClawAccessible()) available.push('openclaw');\n if (isOpencodeAccessible()) available.push('opencode');\n res.json({ available, default: available[0] || null });\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n res.status(500).json({ error: 'Failed to detect agents', hint: message });\n }\n}\n\nfunction getAppInfo(info: AppInfo): (_req: Request, res: Response) => void {\n return (req: Request, res: Response) => {\n const host = req.get('host');\n res.json({\n ...info,\n dashboardUrl: host ? `${req.protocol}://${host}` : info.dashboardUrl,\n });\n };\n}\n\nexport function registerApiRoutes(router: Router, appInfo: AppInfo): void {\n router.get('/app-info', getAppInfo(appInfo));\n router.get('/agents', getAgents);\n router.get('/daily', getDaily);\n router.get('/monthly', getMonthly);\n router.get('/session', getSession);\n router.get('/projects', getProjects);\n router.get('/blocks', getBlocks);\n router.get('/analytics', getAnalytics);\n router.get('/quota', getQuota);\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["import_node_fs", "import_node_path", "import_node_fs", "import_node_path", "import_node_os", "import_zod", "import_node_fs", "import_node_path", "import_node_os", "TZ_OFFSETS", "getTzOffsetHours", "getDateKey", "getHourKey", "emptyAcc", "mergeAcc", "accToEntry", "getDailyResponse", "getDateKey", "getProjectsResponse", "getBlocksResponse", "getHourKey", "import_node_fs", "import_node_path", "import_node_os", "cache", "TZ_OFFSETS", "getTzOffsetHours", "msToLocalDate", "getDateKey", "getHourKey", "emptyAcc", "addEvent", "getDailyResponse", "mergeAcc", "getProjectsResponse", "getBlocksResponse", "import_node_fs", "import_node_path", "import_node_os", "MODEL_PRICING", "DEFAULT_PRICING", "calculateCost", "extractProjectName", "parseAllSessions", "TZ_OFFSETS", "getDateKey", "getHourKey", "getDailyResponse", "getProjectsResponse", "getBlocksResponse", "getDailyResponse", "getDailyResponse", "getDailyResponse", "getProjectsResponse", "getBlocksResponse", "import_node_fs", "import_node_path", "import_node_os", "TZ_OFFSETS", "getDateKey", "CLAUDE_PROJECTS_DIR", "projectNameCache", "extractProjectName", "matchesProject", "import_node_fs", "import_node_path", "import_node_os", "CLAUDE_PROJECTS_DIR", "import_zod", "registry", "cache", "resolve", "import_node_fs", "import_node_path", "import_node_os", "import_node_child_process", "resolve", "import_node_fs", "import_node_path", "import_node_os", "import_node_child_process", "import_node_fs", "import_node_path", "import_node_os", "import_node_fs", "import_node_path", "import_node_os", "classifyFetchError", "capitalize", "resolveCredential", "classifyFetchError", "region", "base", "import_node_fs", "import_node_path", "import_node_os", "classifyFetchError", "normalizeIso", "durationLabel", "refreshToken", "resolve", "express", "spawn", "existsSync"]
|
|
7
7
|
}
|