tokensniff 0.1.0
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/LICENSE +21 -0
- package/README.md +809 -0
- package/bin/tokensniff-status.js +8 -0
- package/bin/tokensniff.js +8 -0
- package/dist/cli/run.d.ts +64 -0
- package/dist/cli/run.d.ts.map +1 -0
- package/dist/cli.js +2206 -0
- package/dist/cli.js.map +1 -0
- package/dist/collector/config.d.ts +43 -0
- package/dist/collector/config.d.ts.map +1 -0
- package/dist/collector/index.d.ts +14 -0
- package/dist/collector/index.d.ts.map +1 -0
- package/dist/collector/parse.d.ts +42 -0
- package/dist/collector/parse.d.ts.map +1 -0
- package/dist/collector/store.d.ts +76 -0
- package/dist/collector/store.d.ts.map +1 -0
- package/dist/dashboard/heatmap.d.ts +34 -0
- package/dist/dashboard/heatmap.d.ts.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2474 -0
- package/dist/index.js.map +1 -0
- package/dist/pricing.js +145 -0
- package/dist/pricing.js.map +1 -0
- package/dist/proxy.js +1744 -0
- package/dist/proxy.js.map +1 -0
- package/dist/renderer/format.d.ts +33 -0
- package/dist/renderer/format.d.ts.map +1 -0
- package/dist/renderer/index.d.ts +42 -0
- package/dist/renderer/index.d.ts.map +1 -0
- package/dist/schema.js +90 -0
- package/dist/schema.js.map +1 -0
- package/dist/shared/pricing.d.ts +60 -0
- package/dist/shared/pricing.d.ts.map +1 -0
- package/dist/shared/schema.d.ts +122 -0
- package/dist/shared/schema.d.ts.map +1 -0
- package/dist/status.js +521 -0
- package/dist/status.js.map +1 -0
- package/package.json +105 -0
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/collector/config.ts","../src/collector/store.ts","../src/shared/pricing.ts","../src/dashboard/heatmap.ts","../src/shared/schema.ts","../src/collector/parse.ts","../src/collector/index.ts","../src/cli/run.ts"],"names":["path","fs","proxyHost","exitCode"],"mappings":"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","file":"cli.js","sourcesContent":["/**\n * tokensniff — Configuration Loader & Resolver (v1 Production)\n *\n * Implements strict hierarchical configuration resolution:\n * process.env > ~/.tokensniff/config.json > embedded defaults.\n *\n * Hardened with defensive path normalization, numeric bounds verification,\n * safe stringified boolean parsing, and corruption fault-tolerance.\n */\n\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\n\nexport interface TokenSniffConfig {\n readonly listenPort: number;\n readonly listenHost: string;\n readonly upstreamHost: string;\n readonly upstreamPort: number;\n readonly upstreamTimeoutMs: number;\n readonly maxBodyBytes: number;\n readonly statusDirs: readonly string[];\n readonly maxSessions: number;\n readonly deadSessionMs: number;\n readonly staleAfterS: number;\n readonly labelMaxIn: number;\n readonly labelMaxOut: number;\n readonly warnPct: number;\n readonly critPct: number;\n readonly color: boolean;\n readonly upstreamCommand: string;\n readonly upstreamStopCommand: string;\n readonly harnessCommand: string;\n}\n\n/**\n * Validates TCP/IP port numbers against standard IANA boundaries [1, 65535].\n */\nfunction toValidPort(value: unknown, fallback: number): number {\n const parsed = Number(value);\n return Number.isInteger(parsed) && parsed >= 1 && parsed <= 65535 ? parsed : fallback;\n}\n\n/**\n * Validates and clamps integer bounds defensively.\n */\nfunction toBoundedInt(\n value: unknown,\n fallback: number,\n min = 0,\n max = Number.MAX_SAFE_INTEGER,\n): number {\n const parsed = Number(value);\n if (!Number.isFinite(parsed)) return fallback;\n const intVal = Math.floor(parsed);\n return Math.max(min, Math.min(max, intVal));\n}\n\n/**\n * Validates non-empty string fields with fallback protection against whitespace-only values.\n */\nfunction toNonEmptyString(value: unknown, fallback: string): string {\n if (typeof value !== 'string') return fallback;\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : fallback;\n}\n\n/**\n * Accurately parses boolean flags, safely handling stringified representations (\"false\", \"0\").\n */\nfunction toSafeBoolean(value: unknown, fallback: boolean): boolean {\n if (typeof value === 'boolean') return value;\n if (typeof value === 'string') {\n const lower = value.trim().toLowerCase();\n if (lower === 'true' || lower === '1') return true;\n if (lower === 'false' || lower === '0') return false;\n }\n return fallback;\n}\n\n/**\n * Normalizes directory paths, resolving cross-platform slashes and relative references to absolute paths.\n */\nfunction normalizeDirectory(targetPath: string): string {\n const resolved = path.resolve(targetPath.trim());\n return path.normalize(resolved);\n}\n\n/**\n * Dynamically resolves the canonical user home directory (~/.tokensniff) across OSes.\n */\nexport function getGlobalDir(): string {\n const home = process.env.USERPROFILE || os.homedir();\n return path.join(home, '.tokensniff');\n}\n\n/**\n * Resolves the configuration file location ~/.tokensniff/config.json.\n */\nexport function getGlobalConfigPath(): string {\n return path.join(getGlobalDir(), 'config.json');\n}\n\n/**\n * Loads configuration with strict precedence:\n * Environment Variables > File Configuration > Embedded Defaults.\n */\nexport function loadConfig(env: NodeJS.ProcessEnv = process.env): TokenSniffConfig {\n const targetConfigFile = env.TOKENSNIFF_CONFIG || getGlobalConfigPath();\n let fileConfig: Record<string, unknown> = {};\n\n // Safe JSON extraction with non-crashing syntax defense\n if (fs.existsSync(targetConfigFile)) {\n try {\n const raw = fs.readFileSync(targetConfigFile, 'utf8');\n const parsed: unknown = JSON.parse(raw);\n if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)) {\n fileConfig = parsed as Record<string, unknown>;\n }\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n console.error(`[tokensniff] ignoring corrupt config at ${targetConfigFile}: ${msg}`);\n }\n }\n\n const resolve = <T>(envKey: string, configKey: string, defaultValue: T): unknown => {\n return env[envKey] ?? fileConfig[configKey] ?? defaultValue;\n };\n\n const rootDir = getGlobalDir();\n const defaultStatusDir = path.join(rootDir, 'status');\n\n const rawStatusDirs = resolve('TOKENSNIFF_STATUS_DIRS', 'statusDirs', [defaultStatusDir]);\n\n // Handle both array and comma-separated string declarations of status directories\n const parsedDirs: string[] = Array.isArray(rawStatusDirs)\n ? rawStatusDirs.map(String)\n : String(rawStatusDirs).split(',');\n\n const normalizedStatusDirs = parsedDirs\n .map((d) => d.trim())\n .filter((d) => d.length > 0)\n .map(normalizeDirectory);\n\n const statusDirs =\n normalizedStatusDirs.length > 0 ? normalizedStatusDirs : [normalizeDirectory(defaultStatusDir)];\n\n // NO_COLOR standard (https://no-color.org/): any non-empty value disables ANSI formatting\n const isNoColorSet = typeof env.NO_COLOR === 'string' && env.NO_COLOR.length > 0;\n const colorDefault = !isNoColorSet;\n\n return {\n listenPort: toValidPort(resolve('TOKENSNIFF_PORT', 'listenPort', 4000), 4000),\n listenHost: toNonEmptyString(\n resolve('TOKENSNIFF_HOST', 'listenHost', '127.0.0.1'),\n '127.0.0.1',\n ),\n upstreamHost: toNonEmptyString(\n resolve('TOKENSNIFF_UPSTREAM_HOST', 'upstreamHost', 'localhost'),\n 'localhost',\n ),\n upstreamPort: toValidPort(resolve('TOKENSNIFF_UPSTREAM_PORT', 'upstreamPort', 8085), 8085),\n upstreamTimeoutMs: toBoundedInt(\n resolve('TOKENSNIFF_UPSTREAM_TIMEOUT_MS', 'upstreamTimeoutMs', 300_000),\n 300_000,\n 1000,\n 3_600_000,\n ),\n maxBodyBytes: toBoundedInt(\n resolve('TOKENSNIFF_MAX_BODY_BYTES', 'maxBodyBytes', 10 * 1024 * 1024),\n 10_485_760,\n 1024,\n 100 * 1024 * 1024,\n ),\n statusDirs,\n maxSessions: toBoundedInt(resolve('TOKENSNIFF_MAX_SESSIONS', 'maxSessions', 50), 50, 1, 1000),\n deadSessionMs: toBoundedInt(\n resolve('TOKENSNIFF_DEAD_SESSION_MS', 'deadSessionMs', 72 * 3600 * 1000),\n 259_200_000,\n 3600 * 1000,\n ),\n staleAfterS: toBoundedInt(\n resolve('TOKENSNIFF_STALE_AFTER_S', 'staleAfterS', 120),\n 120,\n 5,\n 86400,\n ),\n labelMaxIn: toBoundedInt(resolve('TOKENSNIFF_LABEL_MAX_IN', 'labelMaxIn', 2000), 2000, 100),\n labelMaxOut: toBoundedInt(resolve('TOKENSNIFF_LABEL_MAX_OUT', 'labelMaxOut', 60), 60, 1),\n warnPct: toBoundedInt(resolve('TOKENSNIFF_WARN_PCT', 'warnPct', 60), 60, 1, 99),\n critPct: toBoundedInt(resolve('TOKENSNIFF_CRIT_PCT', 'critPct', 80), 80, 2, 100),\n color: colorDefault && toSafeBoolean(resolve('TOKENSNIFF_COLOR', 'color', true), true),\n upstreamCommand: toNonEmptyString(\n resolve(\n 'TOKENSNIFF_UPSTREAM_CMD',\n 'upstreamCommand',\n 'npx antigravity-claude-proxy@latest start',\n ),\n 'npx antigravity-claude-proxy@latest start',\n ),\n upstreamStopCommand: String(\n resolve('TOKENSNIFF_UPSTREAM_STOP_CMD', 'upstreamStopCommand', ''),\n ).trim(),\n harnessCommand: toNonEmptyString(\n resolve('TOKENSNIFF_HARNESS_CMD', 'harnessCommand', 'claude'),\n 'claude',\n ),\n };\n}\n","/**\n * tokensniff — Telemetry Storage & Persistence Engine (v1 Production)\n *\n * Implements atomic file writes (temp-file + OS rename), append-only turn streaming,\n * Windows file-locking retry backoff (EPERM/EBUSY), and automated session pruning.\n */\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport type { TokenSniffLatest } from '../shared/schema.js';\n\nexport interface HistoryInput {\n readonly date?: string;\n readonly sessionId: string;\n readonly turn: number;\n readonly model: string;\n readonly tokens: number;\n readonly cost: number;\n readonly cacheRead: number;\n readonly thinkingTokens?: number;\n}\n\n/**\n * Sanitizes session identifiers to guarantee safe filesystem paths.\n * Enforces length limits and restricts characters to [A-Za-z0-9_-].\n */\nexport function sanitizeSessionId(id: unknown): string {\n const normalized = String(id || 'default')\n .trim()\n .slice(0, 64);\n return /^[A-Za-z0-9_-]+$/.test(normalized) ? normalized : 'default';\n}\n\n/**\n * Returns the current local calendar date formatted as YYYY-MM-DD.\n * Aligns daily spending calculations with developer local time rather than UTC midnight.\n */\nexport function getLocalDateString(d: Date = new Date()): string {\n const year = d.getFullYear();\n const month = String(d.getMonth() + 1).padStart(2, '0');\n const day = String(d.getDate()).padStart(2, '0');\n return `${year}-${month}-${day}`;\n}\n\n/**\n * Synchronous thread sleep without busy-waiting.\n * Utilizes SharedArrayBuffer and Atomics.wait for sub-millisecond precision.\n */\nexport function syncSleep(ms: number): void {\n try {\n Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);\n } catch {\n const end = Date.now() + ms;\n while (Date.now() < end) {\n /* fallback busy-wait */\n }\n }\n}\n\n/**\n * Ensures target directory exists synchronously.\n * Idempotent and resilient against multi-process TOCTOU race conditions.\n */\nexport function ensureDir(dir: string): void {\n try {\n fs.mkdirSync(dir, { recursive: true });\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'EEXIST') {\n throw error;\n }\n }\n}\n\n/**\n * Production-grade atomic file write:\n * 1. Writes to a private temp file in the target directory (same filesystem).\n * 2. Uses atomic OS rename so readers never read partial/corrupt JSON.\n * 3. Retries with exponential backoff on Windows EPERM/EBUSY file locks.\n * 4. Cleans up temp file on failure.\n */\nexport function atomicWrite(filePath: string, data: string, maxRetries = 5): void {\n const dir = path.dirname(filePath);\n ensureDir(dir);\n\n const tmpPath = path.join(\n dir,\n `.${path.basename(filePath)}.tmp.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}`,\n );\n\n fs.writeFileSync(tmpPath, data, 'utf8');\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n fs.renameSync(tmpPath, filePath);\n return;\n } catch (error) {\n const err = error as NodeJS.ErrnoException;\n const isLockError =\n process.platform === 'win32' &&\n (err.code === 'EPERM' || err.code === 'EBUSY' || err.code === 'EACCES');\n\n if (isLockError && attempt < maxRetries) {\n syncSleep((attempt + 1) * 10);\n continue;\n }\n\n try {\n fs.unlinkSync(tmpPath);\n } catch {\n /* ignore cleanup error */\n }\n throw error;\n }\n }\n}\n\n/**\n * Production-grade atomic append for turn telemetry stream (history.ndjson).\n * Retries on Windows transient file locks.\n */\nexport function atomicAppend(filePath: string, line: string, maxRetries = 5): void {\n const dir = path.dirname(filePath);\n ensureDir(dir);\n\n const payload = line.endsWith('\\n') ? line : `${line}\\n`;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n fs.appendFileSync(filePath, payload, { encoding: 'utf8', flag: 'a' });\n return;\n } catch (error) {\n const err = error as NodeJS.ErrnoException;\n const isLockError =\n process.platform === 'win32' &&\n (err.code === 'EPERM' || err.code === 'EBUSY' || err.code === 'EACCES');\n\n if (isLockError && attempt < maxRetries) {\n syncSleep((attempt + 1) * 10);\n continue;\n }\n throw error;\n }\n }\n}\n\n/**\n * Atomically saves latest status snapshots into all designated status directories.\n */\nexport function saveLatest(\n statusDirs: readonly string[],\n sessionId: string,\n latestPayload: TokenSniffLatest,\n): void {\n const safeId = sanitizeSessionId(sessionId);\n const serialized = JSON.stringify(latestPayload);\n\n for (const dir of statusDirs) {\n try {\n ensureDir(dir);\n atomicWrite(path.join(dir, `latest-${safeId}.json`), serialized);\n atomicWrite(path.join(dir, 'latest.json'), serialized);\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n console.error(`[tokensniff] failed saving status in ${dir}: ${msg}`);\n }\n }\n}\n\n/**\n * Persists cumulative spending totals across active sessions, bounding memory to maxSessions.\n */\nexport function saveTotals(\n statusDirs: readonly string[],\n totals: Record<string, number>,\n maxSessions: number,\n): Record<string, number> {\n const sessionKeys = Object.keys(totals);\n if (sessionKeys.length > maxSessions) {\n const expiredKeys = sessionKeys.slice(0, sessionKeys.length - maxSessions);\n for (const key of expiredKeys) {\n delete totals[key];\n }\n }\n\n const serialized = JSON.stringify(totals);\n for (const dir of statusDirs) {\n try {\n ensureDir(dir);\n atomicWrite(path.join(dir, 'totals.json'), serialized);\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n console.error(`[tokensniff] failed saving totals in ${dir}: ${msg}`);\n }\n }\n return totals;\n}\n\n/**\n * Reads cumulative spend totals from disk with directory fallback.\n */\nexport function loadTotals(statusDirs: readonly string[]): Record<string, number> {\n for (const dir of statusDirs) {\n const targetFile = path.join(dir, 'totals.json');\n try {\n if (fs.existsSync(targetFile)) {\n const parsed: unknown = JSON.parse(fs.readFileSync(targetFile, 'utf8'));\n if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)) {\n return parsed as Record<string, number>;\n }\n }\n } catch {\n /* continue to next directory candidate */\n }\n }\n return {};\n}\n\n/**\n * Appends a compact turn record to the persistent history stream (history.ndjson).\n */\nexport function appendHistory(statusDirs: readonly string[], entry: HistoryInput): void {\n const line = JSON.stringify({\n d: entry.date || getLocalDateString(),\n ts: Date.now(),\n s: sanitizeSessionId(entry.sessionId),\n t: entry.turn || 1,\n m: entry.model || 'unknown',\n tk: entry.tokens || 0,\n c: Number(Number(entry.cost || 0).toFixed(6)),\n cr: entry.cacheRead || 0,\n th: entry.thinkingTokens || 0,\n });\n\n for (const dir of statusDirs) {\n try {\n const historyPath = path.join(dir, 'history.ndjson');\n atomicAppend(historyPath, line);\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n console.error(`[tokensniff] failed appending history in ${dir}: ${msg}`);\n }\n }\n}\n\n/**\n * Computes today's cumulative spend in USD from history.ndjson.\n * Ignores malformed records and handles line-by-line reading safely.\n */\nexport function loadTodaySpend(\n statusDirs: readonly string[],\n targetDate: string = getLocalDateString(),\n): number {\n for (const dir of statusDirs) {\n const historyPath = path.join(dir, 'history.ndjson');\n if (!fs.existsSync(historyPath)) continue;\n\n try {\n const content = fs.readFileSync(historyPath, 'utf8');\n let totalCost = 0;\n const lines = content.split('\\n');\n\n for (const line of lines) {\n if (!line.trim()) continue;\n try {\n const row: unknown = JSON.parse(line);\n if (\n typeof row === 'object' &&\n row !== null &&\n (row as { d?: unknown }).d === targetDate &&\n typeof (row as { c?: unknown }).c === 'number'\n ) {\n totalCost += (row as { c: number }).c;\n }\n } catch {\n /* ignore truncated/malformed record */\n }\n }\n return totalCost;\n } catch {\n /* fallback to next directory */\n }\n }\n return 0;\n}\n\n/**\n * Prunes dead session records exceeding the staleness TTL.\n */\nexport function pruneDeadSessions(statusDirs: readonly string[], ttlMs: number): void {\n const cutoffTime = Date.now() - ttlMs;\n\n for (const dir of statusDirs) {\n if (!fs.existsSync(dir)) continue;\n\n try {\n const files = fs.readdirSync(dir);\n for (const file of files) {\n if (!file.startsWith('latest-') || !file.endsWith('.json')) continue;\n const filePath = path.join(dir, file);\n try {\n const stats = fs.statSync(filePath);\n if (stats.mtimeMs < cutoffTime) {\n fs.unlinkSync(filePath);\n }\n } catch {\n /* continue on per-file error */\n }\n }\n } catch {\n /* continue on unreadable directory */\n }\n }\n}\n","/**\n * tokensniff — Dynamic Universal Pricing & Context Capacity Engine (v1 Production)\n *\n * Provider-agnostic rate resolver mapping 1:1 to OpenRouter's live catalog schema.\n * Dynamically resolves token rates (prompt, completion, cache-read, cache-write)\n * and maximum context length (context_length) without vendor hardcoding or dummy fallbacks.\n */\n\nexport interface ModelRates {\n readonly in: number; // Cost per prompt token in USD\n readonly out: number; // Cost per completion token in USD\n readonly cached: number; // Cost per cache-read token in USD\n readonly cacheWrite: number; // Cost per cache-write token in USD\n readonly window: number; // Maximum context length in tokens\n}\n\nexport interface ModelPricingOverrides {\n readonly [model: string]: Partial<ModelRates>;\n}\n\ninterface OpenRouterPricingPayload {\n readonly prompt?: string;\n readonly completion?: string;\n readonly input_cache_read?: string;\n readonly input_cache_write?: string;\n}\n\ninterface OpenRouterModelItem {\n readonly id?: string;\n readonly context_length?: number;\n readonly pricing?: OpenRouterPricingPayload;\n}\n\n/**\n * In-memory index mapping model identifiers and clean slugs to ModelRates.\n * Guarantees O(1) latency on all subsequent turns after initial resolution.\n */\nconst rateCache = new Map<string, ModelRates>();\n\n/**\n * Concurrency guard preventing multiple redundant requests to OpenRouter.\n */\nlet catalogPromise: Promise<boolean> | null = null;\n\n/**\n * Normalizes vendor model names into canonical matching slugs.\n * Provider-agnostic: does not hardcode vendor names.\n *\n * Normalization rules:\n * 1. Strips provider namespaces (e.g. \"anthropic/...\", \"google/...\", \"~anthropic/...\")\n * 2. Strips variant flags (e.g. \":free\", \":batch\")\n * 3. Strips runtime proxy & mode suffixes (e.g. \"-tiered\", \"-thinking\", \"-preview\", \"-low\", \"-high\", \"-latest\")\n * 4. Strips calendar release dates (e.g. \"-20241022\", \"-2024-08-06\", \"-2407\")\n * 5. Standardizes numeric version separators (e.g. \"3-5\" -> \"3.5\", \"4-6\" -> \"4.6\")\n *\n * Examples:\n * - \"google/gemini-3.8-flash-tiered\" -> \"gemini-3.8-flash\"\n * - \"anthropic/claude-3-5-sonnet-20241022\" -> \"claude-3.5-sonnet\"\n * - \"claude-opus-4-6-thinking\" -> \"claude-opus-4.6\"\n * - \"meta-llama/llama-3.3-70b-instruct:free\" -> \"llama-3.3-70b-instruct\"\n */\nexport function normalizeModelName(raw: unknown): string {\n if (typeof raw !== 'string' || raw.trim().length === 0) {\n return 'unknown';\n }\n\n const trimmed = raw.trim().toLowerCase();\n\n // Strip provider namespace (anything before the first slash, including leading '~' aliases)\n const withoutNamespace = trimmed.replace(/^~?[a-zA-Z0-9_-]+\\//, '');\n\n // Strip variant flags (:free, :batch), proxy/mode tags, dates, and convert digit-dash-digit to dots\n return withoutNamespace\n .replace(/:[a-zA-Z0-9_-]+$/, '')\n .replace(/-(?:tiered|thinking|preview|low|high|latest)$/, '')\n .replace(/-(?:\\d{4}-\\d{2}-\\d{2}|\\d{8}|\\d{4})$/, '')\n .replace(/\\b(\\d+)-(\\d+)\\b/g, '$1.$2');\n}\n\n/**\n * Parses numeric rate strings from OpenRouter safely, guaranteeing non-negative finite numbers.\n */\nfunction toSafeRate(value: string | undefined, fallback = 0): number {\n if (!value) return fallback;\n const parsed = Number.parseFloat(value);\n return Number.isFinite(parsed) && parsed >= 0 ? parsed : fallback;\n}\n\n/**\n * Fetches and indexes OpenRouter's live models catalog.\n * Uses native Node 24 AbortSignal.timeout to enforce a strict network boundary.\n */\nexport async function syncOpenRouterCatalog(): Promise<boolean> {\n if (catalogPromise) {\n return catalogPromise;\n }\n\n catalogPromise = (async (): Promise<boolean> => {\n try {\n const response = await fetch('https://openrouter.ai/api/v1/models', {\n signal: AbortSignal.timeout(5000),\n headers: { Accept: 'application/json' },\n });\n\n if (!response.ok) {\n return false;\n }\n\n const json = (await response.json()) as {\n readonly data?: readonly OpenRouterModelItem[];\n };\n\n if (!Array.isArray(json?.data)) {\n return false;\n }\n\n for (const item of json.data) {\n if (!item?.id || !item.pricing) continue;\n\n const promptRate = toSafeRate(item.pricing.prompt);\n const completionRate = toSafeRate(item.pricing.completion);\n const cacheReadRate = toSafeRate(\n item.pricing.input_cache_read,\n promptRate > 0 ? promptRate * 0.1 : 0,\n );\n const cacheWriteRate = toSafeRate(item.pricing.input_cache_write, promptRate);\n\n // Dynamically extract real maximum context length from OpenRouter\n const rawWindow = item.context_length;\n const contextWindow =\n typeof rawWindow === 'number' && Number.isFinite(rawWindow) && rawWindow > 0\n ? rawWindow\n : 128_000;\n\n const resolvedRates: ModelRates = {\n in: promptRate,\n out: completionRate,\n cached: cacheReadRate,\n cacheWrite: cacheWriteRate,\n window: contextWindow,\n };\n\n const fullId = item.id.toLowerCase();\n const bareSlug = item.id.includes('/')\n ? (item.id.split('/')[1]?.toLowerCase() ?? fullId)\n : fullId;\n const cleanSlug = normalizeModelName(item.id);\n\n // Multi-key indexing for instant O(1) matching\n rateCache.set(fullId, resolvedRates);\n rateCache.set(bareSlug, resolvedRates);\n rateCache.set(cleanSlug, resolvedRates);\n }\n\n return true;\n } catch {\n return false;\n } finally {\n catalogPromise = null;\n }\n })();\n\n return catalogPromise;\n}\n\n/**\n * Resolves rates and maximum context length dynamically for the active turn model.\n * Seamlessly handles mid-session model switches and user custom overrides.\n */\nexport async function resolveModelRates(\n model: string,\n overrides: ModelPricingOverrides = {},\n): Promise<ModelRates> {\n const clean = normalizeModelName(model);\n const rawKey = model.trim().toLowerCase();\n\n // 1. User config overrides always take highest priority\n const matchedOverride = overrides[rawKey] ?? overrides[clean];\n if (matchedOverride) {\n const existing = rateCache.get(clean) ?? rateCache.get(rawKey);\n const resolvedOverride: ModelRates = {\n in: matchedOverride.in ?? existing?.in ?? 0,\n out: matchedOverride.out ?? existing?.out ?? 0,\n cached: matchedOverride.cached ?? existing?.cached ?? 0,\n cacheWrite: matchedOverride.in ?? existing?.cacheWrite ?? 0,\n window: matchedOverride.window ?? existing?.window ?? 128_000,\n };\n rateCache.set(clean, resolvedOverride);\n rateCache.set(rawKey, resolvedOverride);\n return resolvedOverride;\n }\n\n // 2. Fast-path: Instant in-memory cache hit\n const cached = rateCache.get(clean) ?? rateCache.get(rawKey);\n if (cached) {\n return cached;\n }\n\n // 3. Cache-miss: Fetch OpenRouter catalog on-demand\n await syncOpenRouterCatalog();\n\n const postSync = rateCache.get(clean) ?? rateCache.get(rawKey);\n if (postSync) {\n return postSync;\n }\n\n // 4. Longest-match fallback across indexed models (prioritizes specific variants over shorter base slugs)\n const candidateKeys = Array.from(rateCache.keys()).sort((a, b) => b.length - a.length);\n for (const key of candidateKeys) {\n if (key.length > 3 && (clean.includes(key) || key.includes(clean))) {\n const rates = rateCache.get(key);\n if (rates) {\n rateCache.set(clean, rates);\n return rates;\n }\n }\n }\n\n // 5. Zero-rate boundary if completely unknown to OpenRouter\n const defaultBoundary: ModelRates = {\n in: 0,\n out: 0,\n cached: 0,\n cacheWrite: 0,\n window: 128_000,\n };\n rateCache.set(clean, defaultBoundary);\n return defaultBoundary;\n}\n\n/**\n * Synchronous cache lookup for instantaneous read during statusline rendering.\n */\nexport function ratesFor(model: string): ModelRates {\n const clean = normalizeModelName(model);\n const rawKey = model.trim().toLowerCase();\n\n const hit = rateCache.get(clean) ?? rateCache.get(rawKey);\n if (hit) {\n return hit;\n }\n\n // Kick off background sync for future turns if not yet cached\n void syncOpenRouterCatalog();\n\n return {\n in: 0,\n out: 0,\n cached: 0,\n cacheWrite: 0,\n window: 128_000,\n };\n}\n\n/**\n * Calculates exact monetary cost in USD for a turn interaction.\n * Supports prompt, completion, cache-read, and cache-write token accounting.\n */\nexport function costFor(\n rates: ModelRates,\n usage: {\n readonly input?: number;\n readonly output?: number;\n readonly cacheRead?: number;\n readonly cacheCreate?: number;\n },\n): number {\n const inputTokens = Math.max(0, usage.input ?? 0);\n const outputTokens = Math.max(0, usage.output ?? 0);\n const cacheReadTokens = Math.max(0, usage.cacheRead ?? 0);\n const cacheCreateTokens = Math.max(0, usage.cacheCreate ?? 0);\n\n const cacheWriteRate = rates.cacheWrite > 0 ? rates.cacheWrite : rates.in;\n\n const total =\n inputTokens * rates.in +\n outputTokens * rates.out +\n cacheReadTokens * rates.cached +\n cacheCreateTokens * cacheWriteRate;\n\n if (!Number.isFinite(total) || total < 0) {\n return 0;\n }\n\n // 8-decimal deterministic rounding prevents IEEE 754 floating-point drift across turns\n return Math.round(total * 100_000_000) / 100_000_000;\n}\n","/**\n * tokensniff — Spend Calendar Heatmap Engine (v1 Production)\n *\n * Compiles historical turn telemetry into day-by-day aggregates and renders a\n * standalone, zero-dependency calendar heatmap with an obsidian & emerald aesthetic.\n */\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport * as store from '../collector/store.js';\nimport { costFor, ratesFor } from '../shared/pricing.js';\n\nexport interface DayBucket {\n readonly date: string; // Local date in YYYY-MM-DD\n tokens: number;\n cost: number;\n cacheRead: number;\n thinkingTokens: number;\n turns: number;\n readonly models: Record<string, number>;\n readonly hourlyTurns: number[];\n}\n\n/**\n * Parses history.ndjson into an aggregated day-by-day record map.\n * Recovers cleanly from truncated or malformed trailing records.\n */\nexport function loadDailyRollup(statusDirs: readonly string[]): Record<string, DayBucket> {\n const dailyMap: Record<string, DayBucket> = {};\n\n for (const dir of statusDirs) {\n const historyPath = path.join(dir, 'history.ndjson');\n if (!fs.existsSync(historyPath)) continue;\n\n try {\n const raw = fs.readFileSync(historyPath, 'utf8');\n const lines = raw.split('\\n');\n\n for (const line of lines) {\n if (!line.trim()) continue;\n try {\n const row: unknown = JSON.parse(line);\n if (typeof row !== 'object' || row === null) continue;\n\n const record = row as Record<string, unknown>;\n const dateStr = record.d;\n if (typeof dateStr !== 'string' || !/^\\d{4}-\\d{2}-\\d{2}$/.test(dateStr)) {\n continue;\n }\n\n if (!dailyMap[dateStr]) {\n dailyMap[dateStr] = {\n date: dateStr,\n tokens: 0,\n cost: 0,\n cacheRead: 0,\n thinkingTokens: 0,\n turns: 0,\n models: {},\n hourlyTurns: new Array(24).fill(0) as number[],\n };\n }\n\n const bucket = dailyMap[dateStr];\n if (!bucket) continue;\n\n bucket.tokens += typeof record.tk === 'number' ? record.tk : 0;\n bucket.cost += typeof record.c === 'number' ? record.c : 0;\n bucket.cacheRead += typeof record.cr === 'number' ? record.cr : 0;\n bucket.thinkingTokens += typeof record.th === 'number' ? record.th : 0;\n bucket.turns += 1;\n\n const model = typeof record.m === 'string' && record.m ? record.m : 'unknown';\n bucket.models[model] = (bucket.models[model] ?? 0) + 1;\n\n if (typeof record.ts === 'number') {\n const hour = new Date(record.ts).getHours();\n if (hour >= 0 && hour < 24 && bucket.hourlyTurns[hour] !== undefined) {\n bucket.hourlyTurns[hour] += 1;\n }\n }\n } catch {\n /* ignore corrupted line */\n }\n }\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n console.error(`[tokensniff] failed reading history in ${dir}: ${msg}`);\n }\n }\n\n return dailyMap;\n}\n\n/**\n * Ingests external raw HTTP probe captures and imports them into history.ndjson.\n */\nexport function importCapturesDirectory(\n sourceDir: string,\n targetStatusDirs: readonly string[],\n): { imported: number; skipped: number } {\n if (!fs.existsSync(sourceDir)) {\n return { imported: 0, skipped: 0 };\n }\n\n const files = fs.readdirSync(sourceDir);\n let imported = 0;\n let skipped = 0;\n\n for (const file of files) {\n if (!file.endsWith('.json') || file.startsWith('session_')) continue;\n const fullPath = path.join(sourceDir, file);\n\n try {\n const parsedData: unknown = JSON.parse(fs.readFileSync(fullPath, 'utf8'));\n if (typeof parsedData !== 'object' || parsedData === null) {\n skipped++;\n continue;\n }\n\n const data = parsedData as Record<string, unknown>;\n const timestamp =\n (data.timestamp as string) ||\n ((data.reqLog as Record<string, unknown>)?.timestamp as string);\n if (!timestamp) {\n skipped++;\n continue;\n }\n\n const dateStr = store.getLocalDateString(new Date(timestamp));\n const res = data.response || (data.reqLog as Record<string, unknown>)?.responseHeaders;\n if (!res) {\n skipped++;\n continue;\n }\n\n let rawBody = '';\n if (typeof (data.response as Record<string, unknown>)?.rawBodyString === 'string') {\n rawBody = (data.response as Record<string, unknown>).rawBodyString as string;\n } else if (typeof (data.reqLog as Record<string, unknown>)?.rawResponseBody === 'string') {\n rawBody = (data.reqLog as Record<string, unknown>).rawResponseBody as string;\n }\n\n if (!rawBody) {\n skipped++;\n continue;\n }\n\n const parsedBody: unknown = JSON.parse(rawBody);\n if (typeof parsedBody !== 'object' || parsedBody === null) {\n skipped++;\n continue;\n }\n\n const bodyObj = parsedBody as Record<string, unknown>;\n const usage = (bodyObj.usage as Record<string, unknown>) ?? {};\n const model = typeof bodyObj.model === 'string' ? bodyObj.model : 'gemini-3.7-flash-tiered';\n const rates = ratesFor(model);\n\n const inTokens = typeof usage.input_tokens === 'number' ? usage.input_tokens : 0;\n const outTokens = typeof usage.output_tokens === 'number' ? usage.output_tokens : 0;\n const cacheRead =\n typeof usage.cache_read_input_tokens === 'number' ? usage.cache_read_input_tokens : 0;\n const cacheCreate =\n typeof usage.cache_creation_input_tokens === 'number'\n ? usage.cache_creation_input_tokens\n : 0;\n\n if (inTokens === 0 && outTokens === 0) {\n skipped++;\n continue;\n }\n\n const turnCost = costFor(rates, {\n input: inTokens,\n output: outTokens,\n cacheRead,\n cacheCreate,\n });\n\n store.appendHistory(targetStatusDirs, {\n date: dateStr,\n sessionId: 'imported',\n turn: 1,\n model,\n tokens: inTokens + outTokens + cacheRead,\n cost: turnCost,\n cacheRead,\n thinkingTokens: 0,\n });\n\n imported++;\n } catch {\n skipped++;\n }\n }\n\n return { imported, skipped };\n}\n\n/**\n * Renders the pure, production-grade HTML heatmap dashboard.\n * Zero external web assets or font dependencies; 100% self-contained.\n */\nexport function renderHeatmapHtml(\n dailyMap: Record<string, DayBucket>,\n targetYear: number = new Date().getFullYear(),\n): string {\n let totalTokens = 0;\n let totalCost = 0;\n let totalTurns = 0;\n let totalCacheRead = 0;\n\n for (const bucket of Object.values(dailyMap)) {\n totalTokens += bucket.tokens;\n totalCost += bucket.cost;\n totalTurns += bucket.turns;\n totalCacheRead += bucket.cacheRead;\n }\n\n const cacheHitPct = totalTokens > 0 ? ((totalCacheRead / totalTokens) * 100).toFixed(1) : '0.0';\n const formattedTotalTokens =\n totalTokens >= 1e9\n ? `${(totalTokens / 1e9).toFixed(2)}B`\n : `${(totalTokens / 1e6).toFixed(2)}M`;\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <title>tokensniff • ${targetYear} Token Spend Heatmap</title>\n <style>\n *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }\n\n :root {\n --bg-deep: #05070c;\n --panel-surface: #0a0e17;\n --panel-border: rgba(255, 255, 255, 0.07);\n --panel-highlight: rgba(255, 255, 255, 0.12);\n --text-main: #f8fafc;\n --text-muted: #64748b;\n --text-subtle: #475569;\n --emerald-bright: #34d399;\n --emerald-vivid: #10b981;\n --emerald-deep: #047857;\n --emerald-dark: #064e3b;\n --tile-size: 16px;\n --tile-gap: 4.5px;\n --tile-radius: 3px;\n }\n\n body {\n overflow-x: hidden;\n background: radial-gradient(circle at 50% -10%, rgba(16, 185, 129, 0.12), transparent 70%),\n radial-gradient(circle at 10% 100%, rgba(5, 150, 105, 0.05), transparent 50%),\n var(--bg-deep);\n color: var(--text-main);\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Inter\", \"Geist\", sans-serif;\n min-height: 100vh;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 48px 24px;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n }\n\n .container {\n width: 100%;\n max-width: 1220px;\n background: var(--panel-surface);\n border: 1px solid var(--panel-border);\n border-radius: 20px;\n padding: 38px 44px;\n box-shadow: 0 40px 100px -20px rgba(0, 0, 0, 0.95),\n 0 0 0 1px rgba(255, 255, 255, 0.03) inset,\n 0 0 80px rgba(16, 185, 129, 0.04);\n position: relative;\n overflow: hidden;\n }\n\n .container::before {\n content: \"\";\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n height: 1px;\n background: linear-gradient(90deg, transparent, rgba(52, 211, 153, 0.4), transparent);\n }\n\n /* Header Bar */\n .header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding-bottom: 30px;\n border-bottom: 1px solid rgba(255, 255, 255, 0.06);\n flex-wrap: wrap;\n gap: 24px;\n }\n\n .title-group {\n display: flex;\n align-items: center;\n gap: 16px;\n }\n\n .badge-icon {\n width: 44px;\n height: 44px;\n border-radius: 12px;\n background: linear-gradient(135deg, rgba(16, 185, 129, 0.25), rgba(4, 120, 87, 0.08));\n border: 1px solid rgba(52, 211, 153, 0.4);\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--emerald-bright);\n font-weight: 800;\n font-size: 17px;\n font-family: ui-monospace, \"SF Mono\", monospace;\n box-shadow: 0 0 24px rgba(16, 185, 129, 0.2), inset 0 1px 1px rgba(255, 255, 255, 0.2);\n }\n\n h1 {\n font-size: 21px;\n font-weight: 700;\n color: #ffffff;\n letter-spacing: -0.025em;\n line-height: 1.2;\n }\n\n .subtext {\n font-size: 13px;\n color: var(--text-muted);\n margin-top: 4px;\n font-family: ui-monospace, \"SF Mono\", monospace;\n display: flex;\n align-items: center;\n gap: 8px;\n }\n\n .status-pulse {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-size: 11px;\n color: var(--emerald-bright);\n background: rgba(16, 185, 129, 0.1);\n border: 1px solid rgba(52, 211, 153, 0.25);\n border-radius: 20px;\n padding: 2px 10px;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n font-weight: 600;\n }\n\n .status-pulse-dot {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--emerald-bright);\n box-shadow: 0 0 8px var(--emerald-bright);\n }\n\n /* Structured Metric Bays */\n .summary-metrics {\n display: flex;\n gap: 14px;\n font-family: ui-monospace, \"SF Mono\", monospace;\n flex-wrap: wrap;\n }\n\n .summary-item {\n display: flex;\n flex-direction: column;\n align-items: flex-end;\n background: rgba(255, 255, 255, 0.02);\n border: 1px solid rgba(255, 255, 255, 0.06);\n border-radius: 12px;\n padding: 12px 20px;\n min-width: 125px;\n box-shadow: inset 0 1px 1px rgba(255, 255, 255, 0.03);\n }\n\n .summary-label {\n font-size: 10px;\n text-transform: uppercase;\n letter-spacing: 0.1em;\n color: var(--text-muted);\n font-weight: 600;\n }\n\n .summary-val {\n color: #ffffff;\n font-size: 18px;\n font-weight: 700;\n margin-top: 5px;\n letter-spacing: -0.02em;\n }\n\n .summary-val.emerald {\n color: var(--emerald-bright);\n text-shadow: 0 0 20px rgba(52, 211, 153, 0.45);\n }\n\n /* Heatmap Layout & Viewport */\n .heatmap-wrapper {\n padding-top: 34px;\n overflow-x: auto;\n scrollbar-width: thin;\n scrollbar-color: rgba(255, 255, 255, 0.1) transparent;\n }\n\n .heatmap-wrapper::-webkit-scrollbar {\n height: 6px;\n }\n .heatmap-wrapper::-webkit-scrollbar-thumb {\n background: rgba(255, 255, 255, 0.1);\n border-radius: 3px;\n }\n\n .months-row {\n position: relative;\n height: 22px;\n margin-left: 42px;\n margin-bottom: 10px;\n font-size: 12px;\n font-weight: 600;\n color: var(--text-muted);\n font-family: ui-monospace, \"SF Mono\", monospace;\n }\n\n .month-label {\n position: absolute;\n user-select: none;\n letter-spacing: -0.01em;\n }\n\n .grid-container {\n display: flex;\n gap: 12px;\n align-items: start;\n }\n\n .weekday-labels {\n display: grid;\n grid-template-rows: repeat(7, var(--tile-size));\n gap: var(--tile-gap);\n font-size: 11px;\n color: var(--text-subtle);\n font-family: ui-monospace, \"SF Mono\", monospace;\n font-weight: 600;\n user-select: none;\n line-height: var(--tile-size);\n text-align: right;\n padding-right: 6px;\n width: 34px;\n }\n\n .tiles-grid {\n display: grid;\n grid-template-rows: repeat(7, var(--tile-size));\n grid-auto-flow: column;\n grid-auto-columns: var(--tile-size);\n gap: var(--tile-gap);\n }\n\n .tile {\n width: var(--tile-size);\n height: var(--tile-size);\n border-radius: var(--tile-radius);\n cursor: pointer;\n transition: transform 0.16s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.16s ease, border-color 0.16s ease;\n outline: 1px solid transparent;\n position: relative;\n }\n\n .tile:hover {\n transform: scale(1.38);\n z-index: 10;\n outline: 1px solid #ffffff;\n box-shadow: 0 0 16px rgba(255, 255, 255, 0.65);\n }\n\n /* 5-Tier Competitive Millions/Billions Jewel Palette */\n .tier-0 {\n background: #0d121c;\n border: 1px solid rgba(255, 255, 255, 0.04);\n }\n .tier-1 {\n background: #064e3b;\n border: 1px solid #047857;\n box-shadow: inset 0 1px 1px rgba(255, 255, 255, 0.1);\n }\n .tier-2 {\n background: #047857;\n border: 1px solid #10b981;\n box-shadow: 0 0 8px rgba(4, 120, 87, 0.45), inset 0 1px 1px rgba(255, 255, 255, 0.2);\n }\n .tier-3 {\n background: #10b981;\n border: 1px solid #34d399;\n box-shadow: 0 0 14px rgba(16, 185, 129, 0.65), inset 0 1px 1px rgba(255, 255, 255, 0.3);\n }\n .tier-4 {\n background: #34d399;\n border: 1px solid #a7f3d0;\n box-shadow: 0 0 20px rgba(52, 211, 153, 0.9), inset 0 0 4px #ffffff;\n }\n\n /* Footer Milestone Legend */\n .footer {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-top: 32px;\n padding-top: 22px;\n border-top: 1px solid rgba(255, 255, 255, 0.06);\n font-size: 12px;\n color: var(--text-muted);\n font-family: ui-monospace, \"SF Mono\", monospace;\n flex-wrap: wrap;\n gap: 16px;\n }\n\n .legend-container {\n display: flex;\n align-items: center;\n gap: 12px;\n }\n\n .legend-label {\n font-size: 11px;\n color: var(--text-muted);\n text-transform: uppercase;\n letter-spacing: 0.06em;\n font-weight: 600;\n }\n\n .legend {\n display: flex;\n align-items: center;\n gap: 6px;\n }\n\n .legend-tile {\n width: 15px;\n height: 15px;\n border-radius: var(--tile-radius);\n }\n\n .legend-bounds {\n font-size: 11px;\n color: var(--text-muted);\n }\n\n /* Floating Glassmorphic HUD Tooltip */\n #tooltip {\n position: fixed;\n display: none;\n pointer-events: none;\n background: rgba(10, 14, 23, 0.97);\n backdrop-filter: blur(16px);\n -webkit-backdrop-filter: blur(16px);\n border: 1px solid rgba(255, 255, 255, 0.12);\n border-radius: 12px;\n padding: 14px 18px;\n font-size: 12px;\n color: #f1f5f9;\n box-shadow: 0 20px 40px rgba(0, 0, 0, 0.95), 0 0 30px rgba(16, 185, 129, 0.12);\n font-family: ui-monospace, \"SF Mono\", monospace;\n z-index: 1000;\n line-height: 1.6;\n min-width: 220px;\n }\n\n .tt-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 8px;\n padding-bottom: 6px;\n border-bottom: 1px solid rgba(255, 255, 255, 0.08);\n }\n\n .tt-date {\n font-weight: 700;\n color: #ffffff;\n font-size: 13px;\n }\n\n .tt-row {\n display: flex;\n justify-content: space-between;\n margin-top: 3px;\n }\n\n .tt-label {\n color: var(--text-muted);\n }\n\n .tt-cost {\n color: var(--emerald-bright);\n font-weight: 700;\n }\n\n .tt-val {\n font-weight: 600;\n color: #ffffff;\n }\n </style>\n</head>\n<body>\n <div class=\"container\">\n <div class=\"header\">\n <div class=\"title-group\">\n <div class=\"badge-icon\">TS</div>\n <div>\n <h1>tokensniff dashboard</h1>\n <div class=\"subtext\">\n <span>Year ${targetYear} Token Telemetry & Spend Ledger</span>\n <span class=\"status-pulse\"><span class=\"status-pulse-dot\"></span>Online</span>\n </div>\n </div>\n </div>\n <div class=\"summary-metrics\">\n <div class=\"summary-item\">\n <span class=\"summary-label\">Total Spend</span>\n <span class=\"summary-val emerald\">$${totalCost.toFixed(3)}</span>\n </div>\n <div class=\"summary-item\">\n <span class=\"summary-label\">Total Tokens</span>\n <span class=\"summary-val\">${formattedTotalTokens}</span>\n </div>\n <div class=\"summary-item\">\n <span class=\"summary-label\">Cache Ratio</span>\n <span class=\"summary-val\">${cacheHitPct}%</span>\n </div>\n <div class=\"summary-item\">\n <span class=\"summary-label\">Total Turns</span>\n <span class=\"summary-val\">${totalTurns}</span>\n </div>\n </div>\n </div>\n\n <div class=\"heatmap-wrapper\">\n <div id=\"months-row\" class=\"months-row\"></div>\n <div class=\"grid-container\">\n <div class=\"weekday-labels\">\n <span></span>\n <span>Mon</span>\n <span></span>\n <span>Wed</span>\n <span></span>\n <span>Fri</span>\n <span></span>\n </div>\n <div id=\"tiles\" class=\"tiles-grid\"></div>\n </div>\n </div>\n\n <div class=\"footer\">\n <span>Auto-updated live ledger • port 4000</span>\n <div class=\"legend-container\">\n <span class=\"legend-label\">Daily Volume</span>\n <span class=\"legend-bounds\">0</span>\n <div class=\"legend\">\n <div class=\"legend-tile tier-0\" title=\"0 tokens\"></div>\n <div class=\"legend-tile tier-1\" title=\"1M - 5M tokens\"></div>\n <div class=\"legend-tile tier-2\" title=\"5M - 25M tokens\"></div>\n <div class=\"legend-tile tier-3\" title=\"25M - 100M tokens\"></div>\n <div class=\"legend-tile tier-4\" title=\"> 100M tokens\"></div>\n </div>\n <span class=\"legend-bounds\">100M+</span>\n </div>\n </div>\n </div>\n\n <div id=\"tooltip\"></div>\n\n <script>\n const data = ${JSON.stringify(dailyMap)};\n const year = ${targetYear};\n const tilesContainer = document.getElementById('tiles');\n const monthsRow = document.getElementById('months-row');\n const tooltip = document.getElementById('tooltip');\n\n const startDate = new Date(year, 0, 1);\n const startDay = startDate.getDay(); // 0 is Sunday\n\n // Pad beginning of the year so rows align to Sunday-Saturday\n for (let p = 0; p < startDay; p++) {\n const empty = document.createElement('div');\n empty.style.width = '16px';\n empty.style.height = '16px';\n tilesContainer.appendChild(empty);\n }\n\n const isLeapYear = (year % 4 === 0 && year % 100 !== 0) || (year % 400 === 0);\n const totalDays = isLeapYear ? 366 : 365;\n const monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];\n let lastMonth = -1;\n\n function formatHumanTokens(t) {\n if (!t || t === 0) return '0';\n if (t >= 1e9) return (t / 1e9).toFixed(2) + 'B';\n if (t >= 1e6) return (t / 1e6).toFixed(2) + 'M';\n if (t >= 1e3) return (t / 1e3).toFixed(1) + 'k';\n return t.toLocaleString();\n }\n\n for (let i = 0; i < totalDays; i++) {\n const cur = new Date(year, 0, 1 + i);\n const m = cur.getMonth();\n const yearStr = cur.getFullYear();\n const monthStr = String(cur.getMonth() + 1).padStart(2, '0');\n const dayStr = String(cur.getDate()).padStart(2, '0');\n const dStr = yearStr + '-' + monthStr + '-' + dayStr;\n\n // Position month labels dynamically along the horizontal week track\n // 16px tile + 4.5px gap = 20.5px step\n if (m !== lastMonth) {\n lastMonth = m;\n const weekCol = Math.floor((i + startDay) / 7);\n const span = document.createElement('span');\n span.className = 'month-label';\n span.innerText = monthNames[m];\n span.style.left = (weekCol * 20.5) + 'px';\n monthsRow.appendChild(span);\n }\n\n const record = data[dStr];\n const tokens = record ? record.tokens : 0;\n const cost = record ? record.cost : 0;\n const turns = record ? record.turns : 0;\n const cacheRead = record ? record.cacheRead : 0;\n\n // Competitive Millions & Billions Tiers\n let tier = 'tier-0';\n if (tokens >= 100000000) tier = 'tier-4'; // > 100M tokens\n else if (tokens >= 25000000) tier = 'tier-3'; // 25M - 100M tokens\n else if (tokens >= 5000000) tier = 'tier-2'; // 5M - 25M tokens\n else if (tokens > 0) tier = 'tier-1'; // 1M - 5M tokens\n\n const tile = document.createElement('div');\n tile.className = 'tile ' + tier;\n\n function positionTooltip(e) {\n const tipWidth = tooltip.offsetWidth || 240;\n const tipHeight = tooltip.offsetHeight || 160;\n let x = e.clientX + 16;\n let y = e.clientY + 16;\n\n // If hovering near the right edge of the screen (e.g. December), flip to the left of the cursor\n if (x + tipWidth > window.innerWidth - 16) {\n x = e.clientX - tipWidth - 16;\n }\n\n // If hovering near the bottom of the screen, flip upward above the cursor\n if (y + tipHeight > window.innerHeight - 16) {\n y = e.clientY - tipHeight - 16;\n }\n\n tooltip.style.left = Math.max(12, x) + 'px';\n tooltip.style.top = Math.max(12, y) + 'px';\n }\n\n tile.onmouseenter = (e) => {\n const cachePct = tokens > 0 ? ((cacheRead / tokens) * 100).toFixed(1) : '0.0';\n tooltip.innerHTML =\n '<div class=\"tt-header\">' +\n '<span class=\"tt-date\">' + cur.toLocaleDateString(undefined, { weekday: 'short', month: 'short', day: 'numeric', year: 'numeric' }) + '</span>' +\n '<span class=\"tt-cost\">$' + cost.toFixed(4) + '</span>' +\n '</div>' +\n '<div class=\"tt-row\"><span class=\"tt-label\">Volume</span><span class=\"tt-val\">' + formatHumanTokens(tokens) + '</span></div>' +\n '<div class=\"tt-row\"><span class=\"tt-label\">Exact Tokens</span><span class=\"tt-val\">' + tokens.toLocaleString() + '</span></div>' +\n '<div class=\"tt-row\"><span class=\"tt-label\">Cache Leverage</span><span class=\"tt-val\">' + formatHumanTokens(cacheRead) + ' (' + cachePct + '%)</span></div>' +\n '<div class=\"tt-row\"><span class=\"tt-label\">Turns Logged</span><span class=\"tt-val\">' + turns + '</span></div>';\n positionTooltip(e);\n tooltip.style.display = 'block';\n };\n\n tile.onmousemove = (e) => {\n positionTooltip(e);\n };\n\n tile.onmouseleave = () => {\n tooltip.style.display = 'none';\n };\n\n tilesContainer.appendChild(tile);\n }\n </script>\n</body>\n</html>`;\n}\n","/**\n * tokensniff — Canonical Domain Telemetry Schema (v1 Production)\n *\n * Single source of truth for telemetry interfaces, runtime validation guards,\n * safe default factories, and agent state text parsing.\n */\n\nexport const SCHEMA_VERSION = 1 as const;\n\n/**\n * Summary representation of an aggregated tool call across a single turn.\n */\nexport interface ToolSummaryItem {\n readonly name: string;\n readonly count: number;\n readonly arg_tk: number;\n}\n\n/**\n * Granular record of an individual tool call during an execution turn.\n */\nexport interface ToolCallItem {\n readonly name: string;\n readonly argTk: number;\n}\n\n/**\n * Classification of the primary driver of a model turn.\n */\nexport type TurnKind = 'text' | 'tool' | 'thinking' | 'label' | 'error' | 'unknown';\n\n/**\n * Snapshot of provider upstream rate limits and token bucket quotas.\n */\nexport interface QuotaSnapshot {\n readonly remainingPct: number | null;\n readonly remainingFraction: number | null;\n readonly resetTime: string | null;\n readonly tier: string | null;\n readonly isRateLimited: boolean;\n}\n\n/**\n * Raw telemetry extracted directly from a single network interaction.\n */\nexport interface TurnMetrics {\n readonly model: string;\n readonly kind: TurnKind;\n readonly input: number;\n readonly output: number;\n readonly cacheRead: number;\n readonly cacheCreate: number;\n readonly tools: readonly ToolCallItem[];\n readonly toolsSummary: readonly ToolSummaryItem[];\n readonly thinking: boolean;\n readonly thinkingTokens: number;\n readonly stopReason: string;\n readonly label: string;\n}\n\n/**\n * Fully hydrated telemetry state persisted to ~/.tokensniff/status/<session_id>.json.\n * Consumed directly by terminal statusline renderers and CLI dashboards.\n */\nexport interface TokenSniffLatest {\n readonly v: typeof SCHEMA_VERSION;\n readonly session_id: string;\n readonly turn_index: number;\n readonly ts: number;\n readonly model: string;\n readonly is_bg: boolean;\n readonly ctx: number;\n readonly window: number;\n readonly pct: number;\n readonly cache_read: number;\n readonly cache_create: number;\n readonly delta_in: number;\n readonly in_tokens: number;\n readonly out_tokens: number;\n readonly thinking: boolean;\n readonly thinking_tokens: number;\n readonly tool: string | null;\n readonly tool_tk: number;\n readonly tools_summary: readonly ToolSummaryItem[];\n readonly stop_reason: string;\n readonly is_label: boolean;\n readonly label: string;\n readonly ttft_ms: number;\n readonly tps: number;\n readonly dur_s: number;\n readonly cost_turn: number;\n readonly cost_session: number;\n readonly cost_today: number;\n readonly error: number | null;\n readonly status: number;\n readonly quota_pct: number | null;\n readonly quota_reset: string | null;\n readonly tier: string | null;\n}\n\n/**\n * Compact append-only historical turn record for analytics and sparklines.\n */\nexport interface HistoryEntry {\n readonly d: string;\n readonly ts: number;\n readonly s: string;\n readonly t: number;\n readonly m: string;\n readonly tk: number;\n readonly c: number;\n readonly cr: number;\n readonly th: number;\n}\n\n/**\n * Defensive number sanitizer ensuring NaN and Infinity never corrupt telemetry output.\n */\nfunction toFiniteNumber(value: unknown, fallback = 0): number {\n const num = Number(value);\n return Number.isFinite(num) ? num : fallback;\n}\n\n/**\n * Runtime Type Guard to safely validate deserialized disk telemetry without unsafe casts.\n */\nexport function isTokenSniffLatest(value: unknown): value is TokenSniffLatest {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n return false;\n }\n\n const candidate = value as Record<string, unknown>;\n\n return (\n candidate.v === SCHEMA_VERSION &&\n typeof candidate.session_id === 'string' &&\n typeof candidate.turn_index === 'number' &&\n typeof candidate.ts === 'number' &&\n typeof candidate.model === 'string' &&\n typeof candidate.ctx === 'number' &&\n typeof candidate.window === 'number' &&\n typeof candidate.pct === 'number'\n );\n}\n\n/**\n * Factory creating fully hydrated TokenSniffLatest records with strictly sanitized defaults.\n */\nexport function buildLatest(\n partial: Partial<TokenSniffLatest> & { readonly session_id: string },\n): TokenSniffLatest {\n return {\n v: SCHEMA_VERSION,\n session_id: partial.session_id,\n turn_index: Math.max(1, Math.floor(toFiniteNumber(partial.turn_index, 1))),\n ts: toFiniteNumber(partial.ts, Date.now()),\n model:\n typeof partial.model === 'string' && partial.model.length > 0 ? partial.model : 'unknown',\n is_bg: Boolean(partial.is_bg),\n ctx: Math.max(0, toFiniteNumber(partial.ctx, 0)),\n window: Math.max(1, toFiniteNumber(partial.window, 1_000_000)),\n pct: Math.max(0, Math.min(100, toFiniteNumber(partial.pct, 0))),\n cache_read: Math.max(0, toFiniteNumber(partial.cache_read, 0)),\n cache_create: Math.max(0, toFiniteNumber(partial.cache_create, 0)),\n delta_in: toFiniteNumber(partial.delta_in, 0),\n in_tokens: Math.max(0, toFiniteNumber(partial.in_tokens, 0)),\n out_tokens: Math.max(0, toFiniteNumber(partial.out_tokens, 0)),\n thinking: Boolean(partial.thinking),\n thinking_tokens: Math.max(0, toFiniteNumber(partial.thinking_tokens, 0)),\n tool: typeof partial.tool === 'string' && partial.tool.length > 0 ? partial.tool : null,\n tool_tk: Math.max(0, toFiniteNumber(partial.tool_tk, 0)),\n tools_summary: Array.isArray(partial.tools_summary) ? partial.tools_summary : [],\n stop_reason: typeof partial.stop_reason === 'string' ? partial.stop_reason : '',\n is_label: Boolean(partial.is_label),\n label: typeof partial.label === 'string' ? partial.label : '',\n ttft_ms: Math.max(0, toFiniteNumber(partial.ttft_ms, 0)),\n tps: Math.max(0, toFiniteNumber(partial.tps, 0)),\n dur_s: Math.max(0, toFiniteNumber(partial.dur_s, 0)),\n cost_turn: Math.max(0, toFiniteNumber(partial.cost_turn, 0)),\n cost_session: Math.max(0, toFiniteNumber(partial.cost_session, 0)),\n cost_today: Math.max(0, toFiniteNumber(partial.cost_today, 0)),\n error:\n typeof partial.error === 'number' && Number.isFinite(partial.error) ? partial.error : null,\n status: Math.max(0, toFiniteNumber(partial.status, 0)),\n quota_pct:\n typeof partial.quota_pct === 'number' && Number.isFinite(partial.quota_pct)\n ? Math.max(0, Math.min(100, partial.quota_pct))\n : null,\n quota_reset: typeof partial.quota_reset === 'string' ? partial.quota_reset : null,\n tier: typeof partial.tier === 'string' ? partial.tier : null,\n };\n}\n\n/**\n * Extracts a concise, human-readable 1-line label from AI agent task descriptions.\n * Handles compound state/detail JSON structures, stringified JSON, and fallback text.\n */\nexport function extractCleanLabel(text: unknown): string {\n if (typeof text !== 'string' || text.length === 0) {\n return '';\n }\n\n const trimmed = text.trim();\n\n if (trimmed.startsWith('{')) {\n if (trimmed.endsWith('}')) {\n try {\n const parsed: unknown = JSON.parse(trimmed);\n if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)) {\n const record = parsed as Record<string, unknown>;\n\n // High priority: compound state + detail (e.g. \"Running tests: auth.test.ts\")\n if (record.state && record.detail) {\n return `${String(record.state).trim()}: ${String(record.detail).trim()}`;\n }\n\n // Secondary priority: specific action titles or summaries\n const candidate =\n record.title ??\n record.summary ??\n record.label ??\n record.message ??\n record.detail ??\n record.state;\n\n if (typeof candidate === 'string' && candidate.trim().length > 0) {\n return candidate.trim();\n }\n }\n } catch {\n // Fall through to regex extraction for malformed JSON\n }\n }\n\n // Regex fallback for truncated or malformed JSON streams\n const stateMatch = trimmed.match(/\"state\"\\s*:\\s*\"([^\"\\\\]*)(?:\"|$)/);\n const detailMatch = trimmed.match(/\"detail\"\\s*:\\s*\"([^\"\\\\]*)(?:\"|$)/);\n\n if (stateMatch?.[1] && detailMatch?.[1]) {\n return `${stateMatch[1].trim()}: ${detailMatch[1].trim()}`;\n }\n\n const singleMatch = trimmed.match(\n /\"(?:title|summary|label|message|detail|state)\"\\s*:\\s*\"([^\"\\\\]*)(?:\"|$)/,\n );\n if (singleMatch?.[1]) {\n return singleMatch[1].trim();\n }\n }\n\n // Strip wrapping quotation marks and extra whitespace\n return trimmed.replace(/^[\"']+|[\"']+$/g, '').trim();\n}\n","/**\n * tokensniff — Telemetry Stream & Payload Parser (v1 Production)\n *\n * Translates raw wire interaction buffers (SSE streams and buffered JSON)\n * into strongly-typed TurnMetrics using battle-tested regex extractors\n * calibrated directly against real-world Claude Code network captures.\n */\n\nimport {\n extractCleanLabel,\n type ToolCallItem,\n type ToolSummaryItem,\n type TurnKind,\n type TurnMetrics,\n} from '../shared/schema.js';\n\nexport interface InteractionPayload {\n readonly reqBody?: string | null;\n readonly resBody?: string | null;\n readonly contentType?: string | null;\n readonly statusCode?: number | null;\n}\n\n/**\n * Safe JSON parser with guaranteed non-throwing semantics and unknown return typing.\n */\nexport function parseSafeJson(raw: unknown): unknown {\n if (typeof raw !== 'string' || raw.trim().length === 0) {\n return null;\n }\n try {\n return JSON.parse(raw);\n } catch {\n return null;\n }\n}\n\n/**\n * Extracts the first positive integer match against an input string.\n */\nfunction extractFirstInt(pattern: RegExp, target: string): number {\n const match = target.match(pattern);\n if (!match?.[1]) return 0;\n const parsed = Number.parseInt(match[1], 10);\n return Number.isFinite(parsed) && parsed > 0 ? parsed : 0;\n}\n\n/**\n * Aggregates a flat list of individual tool calls into a grouped summary,\n * preserving initial encounter order.\n */\nexport function groupTools(tools: readonly ToolCallItem[]): ToolSummaryItem[] {\n if (tools.length === 0) return [];\n\n const map = new Map<string, { name: string; count: number; arg_tk: number }>();\n\n for (const t of tools) {\n if (!t.name) continue;\n const existing = map.get(t.name);\n if (existing) {\n existing.count += 1;\n existing.arg_tk += t.argTk;\n } else {\n map.set(t.name, {\n name: t.name,\n count: 1,\n arg_tk: t.argTk,\n });\n }\n }\n\n return Array.from(map.values()).map((v) => ({\n name: v.name,\n count: v.count,\n arg_tk: v.arg_tk,\n }));\n}\n\n/**\n * Extracts token telemetry, reasoning/thinking, and multi-tool activity from Server-Sent Events (SSE) streams.\n */\nexport function parseSseStream(fallbackModel: string, payload: string): TurnMetrics {\n const input = extractFirstInt(/\"input_tokens\"\\s*:\\s*(\\d+)/, payload);\n\n const cacheReadMatches = Array.from(payload.matchAll(/\"cache_read_input_tokens\"\\s*:\\s*(\\d+)/g));\n const cacheRead =\n cacheReadMatches.length > 0\n ? Math.max(\n ...cacheReadMatches.map((m) => {\n const val = m[1] ? Number.parseInt(m[1], 10) : 0;\n return Number.isFinite(val) ? val : 0;\n }),\n )\n : 0;\n\n const cacheCreateMatches = Array.from(\n payload.matchAll(/\"cache_creation_input_tokens\"\\s*:\\s*(\\d+)/g),\n );\n const cacheCreate =\n cacheCreateMatches.length > 0\n ? Math.max(\n ...cacheCreateMatches.map((m) => {\n const val = m[1] ? Number.parseInt(m[1], 10) : 0;\n return Number.isFinite(val) ? val : 0;\n }),\n )\n : 0;\n\n const outputMatches = Array.from(payload.matchAll(/\"output_tokens\"\\s*:\\s*(\\d+)/g));\n const lastOutputMatch = outputMatches[outputMatches.length - 1];\n const output = lastOutputMatch?.[1] ? Number.parseInt(lastOutputMatch[1], 10) : 0;\n\n const stopMatches = Array.from(payload.matchAll(/\"stop_reason\"\\s*:\\s*\"([^\"]*)\"/g));\n const lastStopMatch = stopMatches[stopMatches.length - 1];\n const stopReason = lastStopMatch?.[1] ?? '';\n\n // Tool parsing: match both tool_use declarations and streaming partial JSON\n const toolNames = Array.from(\n payload.matchAll(/\"type\"\\s*:\\s*\"tool_use\"[^}]*?\"name\"\\s*:\\s*\"([^\"]+)\"/g),\n ).map((m) => m[1] ?? '');\n\n const partialChunks = Array.from(\n payload.matchAll(/\"partial_json\"\\s*:\\s*\"((?:\\\\.|[^\"\\\\])*)\"/g),\n ).map((m) => m[1] ?? '');\n\n let argChars = 0;\n try {\n argChars = partialChunks.join('').replace(/\\\\./g, 'X').length;\n } catch {\n argChars = 0;\n }\n\n const estimatedTotalArgTk = Math.max(0, Math.round(argChars / 4));\n const avgArgTk =\n toolNames.length > 0 ? Math.max(1, Math.round(estimatedTotalArgTk / toolNames.length)) : 0;\n\n const tools: ToolCallItem[] = toolNames.map((name) => ({\n name,\n argTk: avgArgTk,\n }));\n\n // Reasoning / Thinking token extraction\n let thinkingTokens =\n extractFirstInt(/\"thinking_tokens\"\\s*:\\s*(\\d+)/, payload) ||\n extractFirstInt(/\"reasoning_tokens\"\\s*:\\s*(\\d+)/, payload) ||\n extractFirstInt(/\"reasoningTokenCount\"\\s*:\\s*(\\d+)/, payload);\n\n if (thinkingTokens === 0) {\n const thinkingDeltas = Array.from(\n payload.matchAll(/\"thinking\"\\s*:\\s*\"((?:\\\\.|[^\"\\\\])*)\"/g),\n ).map((m) => m[1] ?? '');\n if (thinkingDeltas.length > 0) {\n const thinkingChars = thinkingDeltas.join('').length;\n thinkingTokens = Math.max(1, Math.round(thinkingChars / 4));\n }\n }\n\n const thinking =\n thinkingTokens > 0 ||\n payload.includes('thinking_delta') ||\n payload.includes('\"type\":\"thinking\"') ||\n payload.includes('\"thought\":true');\n\n const kind: TurnKind = tools.length > 0 ? 'tool' : thinking ? 'thinking' : 'text';\n\n return {\n model: fallbackModel,\n kind,\n input,\n output,\n cacheRead,\n cacheCreate,\n tools,\n toolsSummary: groupTools(tools),\n thinking,\n thinkingTokens,\n stopReason,\n label: '',\n };\n}\n\ninterface AnthropicContentBlock {\n readonly type?: string;\n readonly text?: string;\n readonly name?: string;\n readonly input?: unknown;\n readonly thinking?: string;\n}\n\ninterface GeminiCandidatePart {\n readonly text?: string;\n readonly thought?: boolean;\n readonly functionCall?: {\n readonly name?: string;\n readonly args?: unknown;\n };\n}\n\ninterface RawResponsePayload {\n readonly model?: string;\n readonly stop_reason?: string;\n readonly content?: readonly AnthropicContentBlock[] | string;\n readonly candidates?: readonly {\n readonly finishReason?: string;\n readonly content?: {\n readonly parts?: readonly GeminiCandidatePart[];\n };\n }[];\n readonly usage?: {\n readonly input_tokens?: number;\n readonly output_tokens?: number;\n readonly prompt_tokens?: number;\n readonly completion_tokens?: number;\n readonly cache_read_input_tokens?: number;\n readonly cache_creation_input_tokens?: number;\n readonly thinking_tokens?: number;\n readonly reasoning_tokens?: number;\n };\n readonly usageMetadata?: {\n readonly promptTokenCount?: number;\n readonly candidatesTokenCount?: number;\n readonly cachedContentTokenCount?: number;\n readonly candidatesTokenDetails?: readonly {\n readonly reasoningTokenCount?: number;\n }[];\n };\n}\n\n/**\n * Extracts token telemetry from standard buffered JSON responses.\n * Supports Anthropic, Google Gemini (Antigravity), and OpenAI/DeepSeek schema styles.\n */\nexport function parseJsonPayload(fallbackModel: string, payload: string): TurnMetrics | null {\n const parsed = parseSafeJson(payload);\n if (!parsed || typeof parsed !== 'object') return null;\n\n const data = parsed as RawResponsePayload;\n const usage = data.usage ?? {};\n const tools: ToolCallItem[] = [];\n let rawText = '';\n let thinking = false;\n let thinkingChars = 0;\n\n // 1. Anthropic message content structure\n if (Array.isArray(data.content)) {\n for (const item of data.content) {\n if (!item) continue;\n if (item.type === 'text' && typeof item.text === 'string') {\n rawText += item.text;\n } else if (item.type === 'tool_use' && typeof item.name === 'string') {\n const argStr = JSON.stringify(item.input ?? {});\n tools.push({\n name: item.name,\n argTk: Math.max(1, Math.round(argStr.length / 4)),\n });\n } else if (item.type === 'thinking') {\n thinking = true;\n if (typeof item.thinking === 'string') {\n thinkingChars += item.thinking.length;\n }\n }\n }\n } else if (typeof data.content === 'string') {\n rawText = data.content;\n }\n\n // 2. Google Gemini candidates structure (Antigravity harness)\n if (Array.isArray(data.candidates)) {\n for (const candidate of data.candidates) {\n const parts = candidate?.content?.parts;\n if (Array.isArray(parts)) {\n for (const part of parts) {\n if (!part) continue;\n if (typeof part.text === 'string') {\n if (part.thought) {\n thinking = true;\n thinkingChars += part.text.length;\n } else {\n rawText += part.text;\n }\n } else if (part.functionCall?.name) {\n const argStr = JSON.stringify(part.functionCall.args ?? {});\n tools.push({\n name: part.functionCall.name,\n argTk: Math.max(1, Math.round(argStr.length / 4)),\n });\n }\n }\n }\n }\n }\n\n // Exact thinking token accounting\n let thinkingTokens =\n usage.thinking_tokens ??\n usage.reasoning_tokens ??\n data.usageMetadata?.candidatesTokenDetails?.[0]?.reasoningTokenCount ??\n 0;\n\n if (!thinkingTokens && thinkingChars > 0) {\n thinkingTokens = Math.max(1, Math.round(thinkingChars / 4));\n }\n\n if (thinkingTokens > 0) {\n thinking = true;\n }\n\n const input =\n usage.input_tokens ?? usage.prompt_tokens ?? data.usageMetadata?.promptTokenCount ?? 0;\n\n const output =\n usage.output_tokens ?? usage.completion_tokens ?? data.usageMetadata?.candidatesTokenCount ?? 0;\n\n const cacheRead =\n usage.cache_read_input_tokens ?? data.usageMetadata?.cachedContentTokenCount ?? 0;\n\n const cacheCreate = usage.cache_creation_input_tokens ?? 0;\n\n // Background micro-turn detection (e.g. status labels)\n const isMicro = input < 2000 && output < 60 && tools.length === 0 && !thinking;\n\n let kind: TurnKind = 'text';\n if (tools.length > 0) {\n kind = 'tool';\n } else if (thinking) {\n kind = 'thinking';\n } else if (isMicro) {\n kind = 'label';\n }\n\n const cleanLabel = isMicro ? extractCleanLabel(rawText).slice(0, 120) : '';\n\n return {\n model: data.model || fallbackModel,\n kind,\n input,\n output,\n cacheRead,\n cacheCreate,\n tools,\n toolsSummary: groupTools(tools),\n thinking,\n thinkingTokens,\n stopReason: data.stop_reason ?? data.candidates?.[0]?.finishReason ?? 'end_turn',\n label: cleanLabel,\n };\n}\n\n/**\n * Core parsing coordinator. Translates raw network interaction into TurnMetrics.\n * Guaranteed never to throw under invalid or truncated payloads.\n */\nexport function parseTurn(interaction: InteractionPayload): TurnMetrics {\n const fallbackResult: TurnMetrics = {\n model: 'unknown',\n kind: 'unknown',\n input: 0,\n output: 0,\n cacheRead: 0,\n cacheCreate: 0,\n tools: [],\n toolsSummary: [],\n thinking: false,\n thinkingTokens: 0,\n stopReason: '',\n label: '',\n };\n\n try {\n let resolvedModel = 'unknown';\n\n // Priority 1: Extract model from request body\n const parsedReq = parseSafeJson(interaction.reqBody);\n if (\n parsedReq &&\n typeof parsedReq === 'object' &&\n 'model' in parsedReq &&\n typeof (parsedReq as { model: unknown }).model === 'string'\n ) {\n resolvedModel = (parsedReq as { model: string }).model;\n }\n\n const resString = interaction.resBody ?? '';\n const isError = (interaction.statusCode ?? 0) === 429 || (interaction.statusCode ?? 0) >= 500;\n const isSse =\n (interaction.contentType ?? '').includes('text/event-stream') ||\n resString.includes('event: message_start');\n\n if (isError) {\n const base = isSse\n ? parseSseStream(resolvedModel, resString)\n : (parseJsonPayload(resolvedModel, resString) ?? fallbackResult);\n return { ...base, kind: 'error' };\n }\n\n if (isSse) {\n return parseSseStream(resolvedModel, resString);\n }\n\n return parseJsonPayload(resolvedModel, resString) ?? fallbackResult;\n } catch {\n return fallbackResult;\n }\n}\n\n/**\n * Cascading resolution of Claude Code session IDs with safe regex sanitization.\n */\nexport function extractSessionId(\n headers: Record<string, string | string[] | undefined> | undefined,\n rawReqBody: unknown,\n): string {\n let candidate = 'default';\n\n if (headers && typeof headers['x-claude-code-session-id'] === 'string') {\n candidate = headers['x-claude-code-session-id'];\n } else {\n const parsedBody = parseSafeJson(rawReqBody);\n if (\n parsedBody &&\n typeof parsedBody === 'object' &&\n 'metadata' in parsedBody &&\n typeof (parsedBody as { metadata: unknown }).metadata === 'object' &&\n (parsedBody as { metadata: Record<string, unknown> }).metadata !== null\n ) {\n const meta = (parsedBody as { metadata: Record<string, unknown> }).metadata;\n if (typeof meta.session_id === 'string' && meta.session_id.trim().length > 0) {\n candidate = meta.session_id;\n } else if (typeof meta.user_id === 'string') {\n const userMeta = parseSafeJson(meta.user_id);\n if (\n userMeta &&\n typeof userMeta === 'object' &&\n 'session_id' in userMeta &&\n typeof (userMeta as { session_id?: unknown }).session_id === 'string'\n ) {\n candidate = (userMeta as { session_id: string }).session_id;\n }\n }\n }\n }\n\n // Sanitize to safe identifier characters\n const sanitized = candidate.trim().replace(/[^a-zA-Z0-9_-]/g, '');\n return sanitized.length > 0 ? sanitized : 'default';\n}\n","/**\n * tokensniff — Telemetry Collector Proxy Daemon (v1 Production)\n *\n * Transparent HTTP reverse proxy sitting between Claude Code and the upstream provider.\n * Streams response bytes with zero latency overhead while capturing token metrics,\n * calculating turn costs, measuring TTFT/TPS velocity, and persisting telemetry state.\n */\n\nimport http from 'node:http';\nimport { loadDailyRollup, renderHeatmapHtml } from '../dashboard/heatmap.js';\nimport { costFor, resolveModelRates } from '../shared/pricing.js';\nimport { buildLatest, type TokenSniffLatest } from '../shared/schema.js';\nimport { loadConfig, type TokenSniffConfig } from './config.js';\nimport { extractSessionId, parseTurn } from './parse.js';\nimport * as store from './store.js';\n\nconst MAX_TRACKED_SESSIONS = 500;\n\n/**\n * LRU-bounded map insertion to prevent unbounded memory growth in long-running daemons.\n */\nfunction setBoundedLRU<K, V>(map: Map<K, V>, key: K, value: V): void {\n if (!map.has(key) && map.size >= MAX_TRACKED_SESSIONS) {\n const oldestKey = map.keys().next().value;\n if (oldestKey !== undefined) {\n map.delete(oldestKey);\n }\n }\n map.set(key, value);\n}\n\n/**\n * Resolves loopback IP candidates, prioritizing IPv4 before falling back to IPv6.\n */\nfunction getUpstreamCandidates(host: string): readonly string[] {\n if (host === 'localhost' || host === '127.0.0.1' || host === '::1') {\n return ['127.0.0.1', '::1'];\n }\n return [host];\n}\n\n/**\n * Starts the tokensniff HTTP reverse proxy server.\n */\nexport function start(userConfig?: Partial<TokenSniffConfig>): http.Server {\n const config: TokenSniffConfig = { ...loadConfig(), ...(userConfig || {}) };\n\n for (const dir of config.statusDirs) {\n store.ensureDir(dir);\n }\n store.pruneDeadSessions(config.statusDirs, config.deadSessionMs);\n\n const contextHistory = new Map<string, number>();\n const turnIndexBySession = new Map<string, number>();\n const sessionSpending: Record<string, number> = store.loadTotals(config.statusDirs);\n\n // Daily spend tracking with local midnight rollover\n let activeLocalDate = store.getLocalDateString();\n let todayTotalSpend = store.loadTodaySpend(config.statusDirs, activeLocalDate);\n\n let _requestSequence = 0;\n const upstreamHosts = getUpstreamCandidates(config.upstreamHost);\n\n const server = http.createServer((clientReq, clientRes) => {\n const reqUrl = clientReq.url || '/';\n const reqMethod = clientReq.method?.toUpperCase() || 'GET';\n\n // Serve pure heatmap dashboard directly on port 4000\n if (reqMethod === 'GET' && (reqUrl === '/' || reqUrl === '/dashboard')) {\n const dailyMap = loadDailyRollup(config.statusDirs);\n const html = renderHeatmapHtml(dailyMap, new Date().getFullYear());\n clientRes.writeHead(200, { 'content-type': 'text/html; charset=utf-8' });\n clientRes.end(html);\n return;\n }\n\n if (reqMethod === 'GET' && reqUrl === '/api/daily') {\n const dailyMap = loadDailyRollup(config.statusDirs);\n clientRes.writeHead(200, { 'content-type': 'application/json; charset=utf-8' });\n clientRes.end(JSON.stringify(dailyMap));\n return;\n }\n\n ++_requestSequence;\n const startTime = Date.now();\n const headers = clientReq.headers || {};\n const isModelExecution = reqUrl.includes('/v1/messages');\n const isBackgroundAgent = headers['x-app'] === 'cli-bg';\n\n const contentLength = Number(headers['content-length']);\n if (Number.isFinite(contentLength) && contentLength > config.maxBodyBytes) {\n clientRes.writeHead(413, { 'content-type': 'text/plain' });\n clientRes.end('Payload Too Large');\n return;\n }\n\n let resolvedSessionId = store.sanitizeSessionId(\n extractSessionId(headers as Record<string, string | string[] | undefined>, ''),\n );\n const requestChunks: Buffer[] = [];\n let receivedBytes = 0;\n let isPayloadExceeded = false;\n let isRequestComplete = false;\n let proxyClientReq: http.ClientRequest | null = null;\n let isResponseCommitted = false;\n\n const dispatch502 = (failureReason: string): void => {\n console.error(\n `[tokensniff] upstream ${config.upstreamHost}:${config.upstreamPort} unavailable: ${failureReason}`,\n );\n try {\n const fallbackStatus = buildLatest({\n session_id: resolvedSessionId,\n model: 'unknown',\n ctx: contextHistory.get(resolvedSessionId) ?? 0,\n error: 502,\n status: 502,\n cost_session: sessionSpending[resolvedSessionId] ?? 0,\n cost_today: todayTotalSpend,\n is_bg: isBackgroundAgent,\n });\n store.saveLatest(config.statusDirs, resolvedSessionId, fallbackStatus);\n } catch {\n /* ignore error */\n }\n\n if (!clientRes.headersSent) {\n clientRes.writeHead(502, { 'content-type': 'text/plain' });\n }\n try {\n clientRes.end('Bad Gateway: Upstream Unreachable');\n } catch {\n /* ignore error */\n }\n };\n\n const handleProxyResponse = (proxyRes: http.IncomingMessage): void => {\n isResponseCommitted = true;\n const responseChunks: Buffer[] = [];\n let responseBytes = 0;\n let isResponseCapped = false;\n let timeToFirstToken = 0;\n\n const contentType = String(proxyRes.headers['content-type'] || '').toLowerCase();\n const isStreaming = contentType.includes('text/event-stream');\n\n clientRes.writeHead(proxyRes.statusCode || 500, proxyRes.headers);\n\n proxyRes.on('data', (chunk: Buffer) => {\n if (isStreaming && timeToFirstToken === 0) {\n const text = chunk.toString('utf8');\n if (\n text.includes('content_block_start') ||\n text.includes('content_block_delta') ||\n text.includes('\"delta\"')\n ) {\n timeToFirstToken = Date.now();\n }\n }\n\n if (!isResponseCapped) {\n if (responseBytes + chunk.length <= config.maxBodyBytes) {\n responseChunks.push(chunk);\n responseBytes += chunk.length;\n } else {\n isResponseCapped = true;\n }\n }\n clientRes.write(chunk);\n });\n\n proxyRes.on('aborted', () => {\n try {\n clientRes.destroy();\n } catch {\n /* ignore error */\n }\n });\n\n proxyRes.on('error', () => {\n try {\n if (!clientRes.writableEnded) clientRes.end();\n } catch {\n /* ignore error */\n }\n });\n\n proxyRes.on('end', async () => {\n const endTime = Date.now();\n try {\n if (!clientRes.writableEnded) clientRes.end();\n } catch {\n /* ignore error */\n }\n\n if (!isModelExecution) return;\n\n const rawRequestBody = Buffer.concat(requestChunks);\n try {\n resolvedSessionId = store.sanitizeSessionId(\n extractSessionId(\n headers as Record<string, string | string[] | undefined>,\n rawRequestBody.toString('utf8'),\n ),\n );\n } catch {\n /* retain header-derived identifier */\n }\n const rawResponseBody = Buffer.concat(responseChunks);\n\n try {\n const turn = parseTurn({\n reqBody: rawRequestBody.toString('utf8'),\n resBody: rawResponseBody.toString('utf8'),\n contentType: String(proxyRes.headers['content-type'] || ''),\n statusCode: proxyRes.statusCode || 200,\n });\n\n // Dynamically resolve rates and context capacity on-demand\n const rates = await resolveModelRates(turn.model);\n\n const currentContextTokens =\n turn.input > turn.cacheRead\n ? turn.input + turn.cacheCreate\n : turn.input + turn.cacheRead + turn.cacheCreate;\n\n const previousContextTokens = contextHistory.has(resolvedSessionId)\n ? (contextHistory.get(resolvedSessionId) ?? currentContextTokens)\n : currentContextTokens;\n\n const durationSeconds = (endTime - startTime) / 1000;\n const streamGenerationMs =\n timeToFirstToken && isStreaming ? endTime - timeToFirstToken : 0;\n\n // Pure generation velocity: excludes initial network/server wait time (TTFT)\n let tokensPerSecond = 0;\n if (turn.output > 0) {\n if (isStreaming && streamGenerationMs >= 20) {\n tokensPerSecond = Math.round((turn.output / streamGenerationMs) * 1000);\n } else if (endTime > startTime) {\n // Fallback for non-streaming or coalesced socket payloads: use active turn duration\n const totalTurnMs = Math.max(20, endTime - startTime);\n tokensPerSecond = Math.round((turn.output / totalTurnMs) * 1000);\n }\n }\n\n const ttftMs =\n timeToFirstToken && isStreaming ? timeToFirstToken - startTime : endTime - startTime;\n\n const uncachedInput =\n turn.input > turn.cacheRead ? Math.max(0, turn.input - turn.cacheRead) : turn.input;\n\n const turnCostUsd = costFor(rates, {\n input: uncachedInput,\n output: turn.output,\n cacheRead: turn.cacheRead,\n cacheCreate: turn.cacheCreate,\n });\n\n // Monotonic session turn tracking\n const priorTurns = turnIndexBySession.get(resolvedSessionId) || 0;\n const currentTurnIndex = priorTurns + 1;\n setBoundedLRU(turnIndexBySession, resolvedSessionId, currentTurnIndex);\n\n // Session spend accumulation\n const accumulatedSessionCost = (sessionSpending[resolvedSessionId] || 0) + turnCostUsd;\n sessionSpending[resolvedSessionId] = accumulatedSessionCost;\n store.saveTotals(config.statusDirs, sessionSpending, config.maxSessions);\n\n // Local calendar day rollover detection\n const nowLocalDate = store.getLocalDateString();\n if (nowLocalDate !== activeLocalDate) {\n activeLocalDate = nowLocalDate;\n todayTotalSpend = 0;\n }\n todayTotalSpend += turnCostUsd;\n\n const isMicroLabel =\n (turn.kind === 'label' ||\n (turn.tools.length === 0 && turn.output > 0 && turn.output < config.labelMaxOut)) &&\n currentContextTokens < config.labelMaxIn;\n\n if (!isMicroLabel) {\n setBoundedLRU(contextHistory, resolvedSessionId, currentContextTokens);\n }\n\n const displayCtxTokens =\n isMicroLabel && contextHistory.has(resolvedSessionId)\n ? (contextHistory.get(resolvedSessionId) ?? currentContextTokens)\n : currentContextTokens;\n\n const statusSnapshot: TokenSniffLatest = buildLatest({\n session_id: resolvedSessionId,\n turn_index: currentTurnIndex,\n model: turn.model,\n is_bg: isBackgroundAgent,\n ctx: displayCtxTokens,\n window: rates.window,\n pct: Number(((displayCtxTokens / rates.window) * 100).toFixed(1)),\n cache_read: turn.cacheRead,\n cache_create: turn.cacheCreate,\n delta_in: isMicroLabel ? 0 : currentContextTokens - previousContextTokens,\n in_tokens: uncachedInput,\n out_tokens: turn.output,\n tool: turn.tools[0]?.name ?? null,\n tool_tk: turn.tools[0]?.argTk ?? 0,\n tools_summary: turn.toolsSummary,\n thinking: turn.thinking,\n thinking_tokens: turn.thinkingTokens,\n stop_reason: turn.stopReason,\n is_label: isMicroLabel,\n label: isMicroLabel ? turn.label : '',\n ttft_ms: ttftMs,\n tps: tokensPerSecond,\n dur_s: Number(durationSeconds.toFixed(1)),\n cost_turn: turnCostUsd,\n cost_session: accumulatedSessionCost,\n cost_today: todayTotalSpend,\n error: null,\n status: proxyRes.statusCode || 200,\n });\n\n store.saveLatest(config.statusDirs, resolvedSessionId, statusSnapshot);\n\n // Append to history.ndjson stream for heatmap & daily ledger\n if (!isMicroLabel && (turn.input > 0 || turn.output > 0)) {\n store.appendHistory(config.statusDirs, {\n date: nowLocalDate,\n sessionId: resolvedSessionId,\n turn: currentTurnIndex,\n model: turn.model,\n tokens: currentContextTokens + turn.output,\n cost: turnCostUsd,\n cacheRead: turn.cacheRead,\n thinkingTokens: turn.thinkingTokens,\n });\n }\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n console.error(`[tokensniff] turn parse/record failure: ${msg}`);\n }\n });\n };\n\n const tryForwardToHost = (hostIndex: number): void => {\n if (hostIndex >= upstreamHosts.length) {\n dispatch502('all loopback candidates exhausted');\n return;\n }\n\n const hostCandidate = upstreamHosts[hostIndex] ?? '127.0.0.1';\n const forwardHeaders = { ...headers };\n forwardHeaders.host = `${hostCandidate}:${config.upstreamPort}`;\n\n const proxyRequestOptions: http.RequestOptions = {\n hostname: hostCandidate,\n port: config.upstreamPort,\n path: clientReq.url,\n method: clientReq.method,\n headers: forwardHeaders,\n timeout: config.upstreamTimeoutMs,\n };\n\n proxyClientReq = http.request(proxyRequestOptions, (proxyRes) => {\n handleProxyResponse(proxyRes);\n });\n\n proxyClientReq.on('timeout', () => {\n try {\n proxyClientReq?.destroy();\n } catch {\n /* ignore error */\n }\n if (!isResponseCommitted) {\n tryForwardToHost(hostIndex + 1);\n }\n });\n\n proxyClientReq.on('error', () => {\n if (!isResponseCommitted) {\n tryForwardToHost(hostIndex + 1);\n }\n });\n\n for (const chunk of requestChunks) {\n proxyClientReq.write(chunk);\n }\n if (isRequestComplete) {\n proxyClientReq.end();\n }\n };\n\n clientReq.on('data', (chunk: Buffer) => {\n receivedBytes += chunk.length;\n if (receivedBytes > config.maxBodyBytes) {\n if (!isPayloadExceeded) {\n isPayloadExceeded = true;\n clientRes.writeHead(413, { 'content-type': 'text/plain' });\n clientRes.end('Payload Too Large');\n }\n return;\n }\n requestChunks.push(chunk);\n if (proxyClientReq) {\n proxyClientReq.write(chunk);\n }\n });\n\n clientReq.on('end', () => {\n isRequestComplete = true;\n if (proxyClientReq) {\n proxyClientReq.end();\n } else if (!isPayloadExceeded) {\n tryForwardToHost(0);\n }\n });\n\n clientRes.on('close', () => {\n if (!clientRes.writableEnded && proxyClientReq) {\n try {\n proxyClientReq.destroy();\n } catch {\n /* ignore error */\n }\n }\n });\n });\n\n server.listen(config.listenPort, config.listenHost, () => {\n console.log(\n `[tokensniff] proxy listening on http://${config.listenHost}:${config.listenPort} -> ${config.upstreamHost}:${config.upstreamPort}`,\n );\n });\n\n return server;\n}\n","/**\n * tokensniff — Master CLI Orchestrator (v1 Production)\n *\n * Automates the entire telemetry pipeline with multi-terminal reference-counted session lifecycle management:\n * 1. Checks if proxy is already active on port 4000 (multi-terminal smart attach).\n * 2. Checks if upstream is already running on upstreamPort before spawning upstreamCommand.\n * 3. Registers process ID in ~/.tokensniff/sessions/ for active session reference counting.\n * 4. On Ctrl+C or exit, decrements active session count:\n * - If other terminal sessions are alive: terminates only the local harness, leaving the proxy and upstream alive.\n * - If this was the last session: cleans up the proxy server and upstream process.\n */\n\nimport { type ChildProcess, execSync, spawn } from 'node:child_process';\nimport fs from 'node:fs';\nimport net from 'node:net';\nimport path from 'node:path';\nimport {\n getGlobalConfigPath,\n getGlobalDir,\n loadConfig,\n type TokenSniffConfig,\n} from '../collector/config.js';\nimport { start as startCollector } from '../collector/index.js';\nimport { importCapturesDirectory } from '../dashboard/heatmap.js';\n\nexport interface RunDependencies {\n readonly config?: TokenSniffConfig;\n readonly startProxy?: typeof startCollector;\n readonly waitMs?: number;\n}\n\n/**\n * Validates TCP availability across host candidates with timeout.\n */\nexport function waitForTcp(host: string, port: number, timeoutMs = 30000): Promise<void> {\n const hosts =\n host === 'localhost' || host === '127.0.0.1' || host === '::1' ? ['127.0.0.1', '::1'] : [host];\n\n const startTime = Date.now();\n return new Promise((resolve, reject) => {\n let hostIndex = 0;\n\n const probe = (): void => {\n const candidateHost = hosts[hostIndex % hosts.length] ?? '127.0.0.1';\n hostIndex++;\n\n const socket = net.connect(port, candidateHost, () => {\n socket.destroy();\n resolve();\n });\n\n socket.on('error', () => {\n socket.destroy();\n if (Date.now() - startTime > timeoutMs) {\n reject(\n new Error(`Timed out waiting for upstream network availability at ${host}:${port}`),\n );\n } else {\n setTimeout(probe, 250);\n }\n });\n };\n\n probe();\n });\n}\n\n/**\n * Checks if a TCP port is currently open and actively accepting connections.\n */\nexport function isPortActive(host: string, port: number): Promise<boolean> {\n return new Promise((resolve) => {\n const socket = net.connect(port, host, () => {\n socket.destroy();\n resolve(true);\n });\n socket.on('error', () => {\n socket.destroy();\n resolve(false);\n });\n });\n}\n\n/**\n * Generates the global ~/.tokensniff/config.json configuration template.\n */\nexport function writeInitFile(): string {\n const destination = getGlobalConfigPath();\n if (fs.existsSync(destination)) {\n console.log(`[tokensniff] configuration already present: ${destination}`);\n } else {\n const template = {\n upstreamCommand: 'npx antigravity-claude-proxy@latest start',\n upstreamHost: 'localhost',\n upstreamPort: 8085,\n listenPort: 4000,\n harnessCommand: 'claude',\n };\n\n fs.mkdirSync(path.dirname(destination), { recursive: true });\n fs.writeFileSync(destination, JSON.stringify(template, null, 2), 'utf8');\n console.log(`[tokensniff] generated global config: ${destination}`);\n }\n\n printClaudeInstructions();\n return destination;\n}\n\n/**\n * Prints the configuration blocks for ~/.claude/settings.json.\n */\nexport function printClaudeInstructions(): void {\n console.log('\\n------------------------------------------------------------');\n console.log('To route Claude Code through tokensniff and enable the HUD,');\n console.log('add this to your ~/.claude/settings.json file:\\n');\n console.log(' \"env\": {');\n console.log(' \"ANTHROPIC_BASE_URL\": \"http://localhost:4000\"');\n console.log(' },');\n console.log(' \"statusLine\": {');\n console.log(' \"type\": \"command\",');\n console.log(' \"command\": \"tokensniff-status\",');\n console.log(' \"padding\": 0');\n console.log(' }');\n console.log('------------------------------------------------------------\\n');\n}\n\n/**\n * Cross-platform process tree termination.\n */\nexport function terminateProcessTree(pid: number | undefined): void {\n if (!pid) return;\n if (process.platform === 'win32') {\n try {\n execSync(`taskkill /pid ${pid} /T /F`, { stdio: 'ignore' });\n } catch {\n /* process already exited */\n }\n } else {\n try {\n process.kill(-pid, 'SIGKILL');\n } catch {\n try {\n process.kill(pid, 'SIGKILL');\n } catch {\n /* process already exited */\n }\n }\n }\n}\n\n/**\n * Kills any detached process listening on a specific TCP port.\n */\nexport function killProcessOnPort(port: number): void {\n if (!port || !Number.isFinite(port) || port <= 0) return;\n if (process.platform === 'win32') {\n try {\n const output = execSync('netstat -ano -p tcp', { encoding: 'utf8' });\n const lines = output.split(/\\r?\\n/);\n const portPattern = new RegExp(`:${port}\\\\s+.*LISTENING\\\\s+(\\\\d+)`, 'i');\n const pidsToKill = new Set<string>();\n\n for (const line of lines) {\n const match = line.match(portPattern);\n if (match?.[1]) {\n const pid = match[1].trim();\n if (pid && pid !== '0' && pid !== '4' && pid !== String(process.pid)) {\n pidsToKill.add(pid);\n }\n }\n }\n\n for (const pid of pidsToKill) {\n try {\n execSync(`taskkill /pid ${pid} /T /F`, { stdio: 'ignore' });\n } catch {\n /* ignore process race */\n }\n }\n } catch {\n /* ignore netstat error */\n }\n } else {\n try {\n execSync(`lsof -ti tcp:${port} | xargs kill -9 2>/dev/null || true`, {\n stdio: 'ignore',\n });\n } catch {\n /* ignore lsof error */\n }\n }\n}\n\n/**\n * Checks if a process identifier is currently running on the host OS.\n */\nexport function isProcessAlive(pid: number): boolean {\n if (!pid || !Number.isFinite(pid) || pid <= 0) return false;\n try {\n process.kill(pid, 0);\n return true;\n } catch (error) {\n const err = error as NodeJS.ErrnoException;\n return err.code === 'EPERM'; // Process exists but lacks signaling permission\n }\n}\n\n/**\n * Resolves the persistent active sessions tracking directory: ~/.tokensniff/sessions.\n */\nexport function getSessionsDir(): string {\n return path.join(getGlobalDir(), 'sessions');\n}\n\n/**\n * Registers the current CLI terminal process into the shared active sessions pool.\n * Returns an idempotent unregister function to remove the session lock on exit.\n */\nexport function registerSession(pid: number = process.pid): () => void {\n const sessionsDir = getSessionsDir();\n try {\n fs.mkdirSync(sessionsDir, { recursive: true });\n const sessionFile = path.join(sessionsDir, `${pid}.json`);\n fs.writeFileSync(sessionFile, JSON.stringify({ pid, startedAt: Date.now() }), 'utf8');\n } catch {\n /* ignore registration file system error */\n }\n\n let unregistered = false;\n return (): void => {\n if (unregistered) return;\n unregistered = true;\n try {\n const sessionFile = path.join(sessionsDir, `${pid}.json`);\n if (fs.existsSync(sessionFile)) {\n fs.unlinkSync(sessionFile);\n }\n } catch {\n /* ignore file unlink error */\n }\n };\n}\n\n/**\n * Counts how many other terminal sessions are still alive, auto-pruning stale dead PID files.\n */\nexport function countActiveSessions(excludePid: number = process.pid): number {\n const sessionsDir = getSessionsDir();\n if (!fs.existsSync(sessionsDir)) return 0;\n\n let activeCount = 0;\n try {\n const files = fs.readdirSync(sessionsDir);\n for (const file of files) {\n if (!file.endsWith('.json')) continue;\n const pidStr = file.replace('.json', '');\n const pid = Number.parseInt(pidStr, 10);\n\n if (!Number.isFinite(pid) || pid <= 0) {\n try {\n fs.unlinkSync(path.join(sessionsDir, file));\n } catch {\n /* ignore */\n }\n continue;\n }\n\n if (pid === excludePid) {\n continue;\n }\n\n if (isProcessAlive(pid)) {\n activeCount++;\n } else {\n // Dead PID: Prune stale lockfile\n try {\n fs.unlinkSync(path.join(sessionsDir, file));\n } catch {\n /* ignore */\n }\n }\n }\n } catch {\n /* ignore readdir error */\n }\n\n return activeCount;\n}\n\n/**\n * Main command-line orchestrator.\n */\nexport async function main(\n argv: readonly string[] = process.argv.slice(2),\n deps: RunDependencies = {},\n): Promise<void> {\n const command = argv[0];\n const config = deps.config || loadConfig();\n\n if (command === 'init') {\n writeInitFile();\n return;\n }\n\n if (command === 'dashboard') {\n const proxyHost = config.listenHost === 'localhost' ? '127.0.0.1' : config.listenHost;\n const dashboardUrl = `http://${proxyHost}:${config.listenPort}/dashboard`;\n console.log(`[tokensniff] live heatmap dashboard: ${dashboardUrl}`);\n return;\n }\n\n if (command === 'import') {\n const targetDir = argv[1];\n if (!targetDir) {\n console.error(\n '[tokensniff] Error: directory path required.\\nUsage: tokensniff import <path-to-captures-dir>',\n );\n return;\n }\n const resolvedDir = path.resolve(process.cwd(), targetDir);\n console.log(`[tokensniff] importing probe captures from: ${resolvedDir}`);\n const result = importCapturesDirectory(resolvedDir, config.statusDirs);\n console.log(\n `[tokensniff] import complete: ${result.imported} turns recorded, ${result.skipped} non-token files skipped.`,\n );\n return;\n }\n\n if (command === '--help' || command === '-h') {\n console.log('Usage: tokensniff [init|dashboard|import] [-- <harness...>]');\n console.log(' tokensniff Run proxy + live dashboard + Claude Code');\n console.log(' tokensniff init Generate global config at ~/.tokensniff/config.json');\n console.log(' tokensniff dashboard Show live calendar spend heatmap URL');\n console.log(' tokensniff import [dir] Import raw probe captures into daily heatmap ledger');\n console.log(\n ' tokensniff -- <cmd> Run with an alternate harness command (e.g. codex)\\n',\n );\n printClaudeInstructions();\n return;\n }\n\n // 1. Register this terminal session in the shared reference counting directory\n const unregisterSession = registerSession(process.pid);\n\n const startProxy = deps.startProxy || startCollector;\n const separatorIndex = argv.indexOf('--');\n const customHarnessArgs =\n separatorIndex >= 0\n ? argv.slice(separatorIndex + 1)\n : argv.length > 0\n ? argv\n : String(config.harnessCommand || 'claude').split(' ');\n\n const [harnessBinary, ...harnessArgs] = customHarnessArgs.filter(Boolean);\n if (!harnessBinary) {\n unregisterSession();\n throw new Error('No executable harness binary resolved. Verify config.harnessCommand.');\n }\n\n const childProcesses: ChildProcess[] = [];\n let isCleaningUp = false;\n let didSpawnUpstream = false;\n let proxyServerInstance: ReturnType<typeof startCollector> | null = null;\n\n // Reference-counted teardown: Only shuts down proxy and upstream if NO other active terminals exist\n const cleanup = (exitCode: number): void => {\n if (isCleaningUp) return;\n isCleaningUp = true;\n\n // A. Terminate local harness child process immediately\n for (const proc of childProcesses) {\n terminateProcessTree(proc.pid);\n }\n\n // B. Unregister current session\n unregisterSession();\n\n // C. Check if other terminal sessions are active\n const remainingSessions = countActiveSessions(process.pid);\n\n if (remainingSessions > 0) {\n // Attached session or sibling sessions alive: do NOT touch proxy or upstream!\n console.log(\n `[tokensniff] session detached (${remainingSessions} active session(s) remaining, proxy maintained).`,\n );\n } else {\n // Last active session: cleanly shut down in-process proxy and upstream if we spawned it\n if (proxyServerInstance) {\n try {\n proxyServerInstance.close();\n } catch {\n /* ignore */\n }\n }\n\n if (didSpawnUpstream && config.upstreamCommand) {\n if (config.upstreamStopCommand) {\n try {\n execSync(config.upstreamStopCommand, {\n stdio: 'ignore',\n env: {\n ...process.env,\n PORT: process.env.PORT || String(config.upstreamPort),\n },\n });\n } catch {\n /* ignore */\n }\n } else if (config.upstreamCommand.includes('antigravity-claude-proxy')) {\n try {\n execSync('npx antigravity-claude-proxy@latest stop', {\n stdio: 'ignore',\n env: {\n ...process.env,\n PORT: process.env.PORT || String(config.upstreamPort),\n },\n });\n } catch {\n /* ignore */\n }\n }\n\n if (config.upstreamPort) {\n killProcessOnPort(config.upstreamPort);\n }\n }\n }\n\n process.exit(exitCode);\n };\n\n process.once('SIGINT', () => {\n cleanup(130);\n });\n\n process.once('SIGTERM', () => {\n cleanup(143);\n });\n\n // 2. Check if a tokensniff proxy is already running on configured listenPort (multi-terminal smart attach)\n const proxyHost = config.listenHost === 'localhost' ? '127.0.0.1' : config.listenHost;\n const baseUrl = `http://${proxyHost}:${config.listenPort}`;\n const isAlreadyRunning = await isPortActive(proxyHost, config.listenPort);\n\n if (isAlreadyRunning) {\n console.log(`[tokensniff] attaching to active tokensniff proxy on port ${config.listenPort}`);\n console.log(`[tokensniff] live heatmap dashboard available at: ${baseUrl}/dashboard`);\n } else {\n // 3. Check if Upstream Proxy is ALREADY running before attempting to spawn\n const isUpstreamAlreadyActive = await isPortActive(config.upstreamHost, config.upstreamPort);\n\n if (isUpstreamAlreadyActive) {\n console.log(\n `[tokensniff] upstream proxy already active on ${config.upstreamHost}:${config.upstreamPort}`,\n );\n } else if (config.upstreamCommand) {\n console.log(`[tokensniff] initiating upstream command: ${config.upstreamCommand}`);\n const upstreamProcess = spawn(config.upstreamCommand, {\n shell: true,\n stdio: 'inherit',\n detached: process.platform !== 'win32',\n env: {\n ...process.env,\n PORT: process.env.PORT || String(config.upstreamPort),\n },\n });\n\n childProcesses.push(upstreamProcess);\n didSpawnUpstream = true;\n\n upstreamProcess.on('exit', (code) => {\n if (code !== null && code !== 0 && !isCleaningUp) {\n console.log(`[tokensniff] upstream daemon exited with code ${code}`);\n }\n });\n\n try {\n await waitForTcp(config.upstreamHost, config.upstreamPort, deps.waitMs || 30000);\n console.log(\n `[tokensniff] upstream proxy responsive on ${config.upstreamHost}:${config.upstreamPort}`,\n );\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n console.error(`[tokensniff] upstream proxy failed health check: ${msg}`);\n console.error(\n '[tokensniff] continuing pipeline; downstream calls will receive 502 until ready.',\n );\n }\n }\n\n // 4. Start In-Process Telemetry Proxy + Heatmap Dashboard on listenPort\n proxyServerInstance = startProxy(config);\n if (!proxyServerInstance.listening) {\n await new Promise<void>((resolve, reject) => {\n proxyServerInstance?.once('listening', () => resolve());\n proxyServerInstance?.once('error', (err) => reject(err));\n });\n }\n\n console.log(`[tokensniff] live heatmap dashboard available at: ${baseUrl}/dashboard`);\n }\n\n // 5. Launch Harness\n console.log(`[tokensniff] launching harness: ${harnessBinary} ${harnessArgs.join(' ')}`.trim());\n\n const harnessProcess = spawn(harnessBinary, harnessArgs, {\n shell: true,\n stdio: 'inherit',\n env: process.env,\n });\n\n childProcesses.push(harnessProcess);\n\n const exitCode = await new Promise<number | null>((resolve) =>\n harnessProcess.on('close', (code) => resolve(code)),\n );\n\n cleanup(exitCode ?? 0);\n}\n"]}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tokensniff — Configuration Loader & Resolver (v1 Production)
|
|
3
|
+
*
|
|
4
|
+
* Implements strict hierarchical configuration resolution:
|
|
5
|
+
* process.env > ~/.tokensniff/config.json > embedded defaults.
|
|
6
|
+
*
|
|
7
|
+
* Hardened with defensive path normalization, numeric bounds verification,
|
|
8
|
+
* safe stringified boolean parsing, and corruption fault-tolerance.
|
|
9
|
+
*/
|
|
10
|
+
export interface TokenSniffConfig {
|
|
11
|
+
readonly listenPort: number;
|
|
12
|
+
readonly listenHost: string;
|
|
13
|
+
readonly upstreamHost: string;
|
|
14
|
+
readonly upstreamPort: number;
|
|
15
|
+
readonly upstreamTimeoutMs: number;
|
|
16
|
+
readonly maxBodyBytes: number;
|
|
17
|
+
readonly statusDirs: readonly string[];
|
|
18
|
+
readonly maxSessions: number;
|
|
19
|
+
readonly deadSessionMs: number;
|
|
20
|
+
readonly staleAfterS: number;
|
|
21
|
+
readonly labelMaxIn: number;
|
|
22
|
+
readonly labelMaxOut: number;
|
|
23
|
+
readonly warnPct: number;
|
|
24
|
+
readonly critPct: number;
|
|
25
|
+
readonly color: boolean;
|
|
26
|
+
readonly upstreamCommand: string;
|
|
27
|
+
readonly upstreamStopCommand: string;
|
|
28
|
+
readonly harnessCommand: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Dynamically resolves the canonical user home directory (~/.tokensniff) across OSes.
|
|
32
|
+
*/
|
|
33
|
+
export declare function getGlobalDir(): string;
|
|
34
|
+
/**
|
|
35
|
+
* Resolves the configuration file location ~/.tokensniff/config.json.
|
|
36
|
+
*/
|
|
37
|
+
export declare function getGlobalConfigPath(): string;
|
|
38
|
+
/**
|
|
39
|
+
* Loads configuration with strict precedence:
|
|
40
|
+
* Environment Variables > File Configuration > Embedded Defaults.
|
|
41
|
+
*/
|
|
42
|
+
export declare function loadConfig(env?: NodeJS.ProcessEnv): TokenSniffConfig;
|
|
43
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/collector/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC;AAuDD;;GAEG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAGrC;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,gBAAgB,CAqGjF"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tokensniff — Telemetry Collector Proxy Daemon (v1 Production)
|
|
3
|
+
*
|
|
4
|
+
* Transparent HTTP reverse proxy sitting between Claude Code and the upstream provider.
|
|
5
|
+
* Streams response bytes with zero latency overhead while capturing token metrics,
|
|
6
|
+
* calculating turn costs, measuring TTFT/TPS velocity, and persisting telemetry state.
|
|
7
|
+
*/
|
|
8
|
+
import http from 'node:http';
|
|
9
|
+
import { type TokenSniffConfig } from './config.js';
|
|
10
|
+
/**
|
|
11
|
+
* Starts the tokensniff HTTP reverse proxy server.
|
|
12
|
+
*/
|
|
13
|
+
export declare function start(userConfig?: Partial<TokenSniffConfig>): http.Server;
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/collector/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,IAAI,MAAM,WAAW,CAAC;AAI7B,OAAO,EAAc,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAC;AA6BhE;;GAEG;AACH,wBAAgB,KAAK,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG,IAAI,CAAC,MAAM,CAuYzE"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tokensniff — Telemetry Stream & Payload Parser (v1 Production)
|
|
3
|
+
*
|
|
4
|
+
* Translates raw wire interaction buffers (SSE streams and buffered JSON)
|
|
5
|
+
* into strongly-typed TurnMetrics using battle-tested regex extractors
|
|
6
|
+
* calibrated directly against real-world Claude Code network captures.
|
|
7
|
+
*/
|
|
8
|
+
import { type ToolCallItem, type ToolSummaryItem, type TurnMetrics } from '../shared/schema.js';
|
|
9
|
+
export interface InteractionPayload {
|
|
10
|
+
readonly reqBody?: string | null;
|
|
11
|
+
readonly resBody?: string | null;
|
|
12
|
+
readonly contentType?: string | null;
|
|
13
|
+
readonly statusCode?: number | null;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Safe JSON parser with guaranteed non-throwing semantics and unknown return typing.
|
|
17
|
+
*/
|
|
18
|
+
export declare function parseSafeJson(raw: unknown): unknown;
|
|
19
|
+
/**
|
|
20
|
+
* Aggregates a flat list of individual tool calls into a grouped summary,
|
|
21
|
+
* preserving initial encounter order.
|
|
22
|
+
*/
|
|
23
|
+
export declare function groupTools(tools: readonly ToolCallItem[]): ToolSummaryItem[];
|
|
24
|
+
/**
|
|
25
|
+
* Extracts token telemetry, reasoning/thinking, and multi-tool activity from Server-Sent Events (SSE) streams.
|
|
26
|
+
*/
|
|
27
|
+
export declare function parseSseStream(fallbackModel: string, payload: string): TurnMetrics;
|
|
28
|
+
/**
|
|
29
|
+
* Extracts token telemetry from standard buffered JSON responses.
|
|
30
|
+
* Supports Anthropic, Google Gemini (Antigravity), and OpenAI/DeepSeek schema styles.
|
|
31
|
+
*/
|
|
32
|
+
export declare function parseJsonPayload(fallbackModel: string, payload: string): TurnMetrics | null;
|
|
33
|
+
/**
|
|
34
|
+
* Core parsing coordinator. Translates raw network interaction into TurnMetrics.
|
|
35
|
+
* Guaranteed never to throw under invalid or truncated payloads.
|
|
36
|
+
*/
|
|
37
|
+
export declare function parseTurn(interaction: InteractionPayload): TurnMetrics;
|
|
38
|
+
/**
|
|
39
|
+
* Cascading resolution of Claude Code session IDs with safe regex sanitization.
|
|
40
|
+
*/
|
|
41
|
+
export declare function extractSessionId(headers: Record<string, string | string[] | undefined> | undefined, rawReqBody: unknown): string;
|
|
42
|
+
//# sourceMappingURL=parse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../src/collector/parse.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,eAAe,EAEpB,KAAK,WAAW,EACjB,MAAM,qBAAqB,CAAC;AAE7B,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACrC;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CASnD;AAYD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,YAAY,EAAE,GAAG,eAAe,EAAE,CAyB5E;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,WAAW,CAkGlF;AAiDD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAkH3F;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,WAAW,EAAE,kBAAkB,GAAG,WAAW,CAmDtE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,GAAG,SAAS,EAClE,UAAU,EAAE,OAAO,GAClB,MAAM,CAkCR"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tokensniff — Telemetry Storage & Persistence Engine (v1 Production)
|
|
3
|
+
*
|
|
4
|
+
* Implements atomic file writes (temp-file + OS rename), append-only turn streaming,
|
|
5
|
+
* Windows file-locking retry backoff (EPERM/EBUSY), and automated session pruning.
|
|
6
|
+
*/
|
|
7
|
+
import type { TokenSniffLatest } from '../shared/schema.js';
|
|
8
|
+
export interface HistoryInput {
|
|
9
|
+
readonly date?: string;
|
|
10
|
+
readonly sessionId: string;
|
|
11
|
+
readonly turn: number;
|
|
12
|
+
readonly model: string;
|
|
13
|
+
readonly tokens: number;
|
|
14
|
+
readonly cost: number;
|
|
15
|
+
readonly cacheRead: number;
|
|
16
|
+
readonly thinkingTokens?: number;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Sanitizes session identifiers to guarantee safe filesystem paths.
|
|
20
|
+
* Enforces length limits and restricts characters to [A-Za-z0-9_-].
|
|
21
|
+
*/
|
|
22
|
+
export declare function sanitizeSessionId(id: unknown): string;
|
|
23
|
+
/**
|
|
24
|
+
* Returns the current local calendar date formatted as YYYY-MM-DD.
|
|
25
|
+
* Aligns daily spending calculations with developer local time rather than UTC midnight.
|
|
26
|
+
*/
|
|
27
|
+
export declare function getLocalDateString(d?: Date): string;
|
|
28
|
+
/**
|
|
29
|
+
* Synchronous thread sleep without busy-waiting.
|
|
30
|
+
* Utilizes SharedArrayBuffer and Atomics.wait for sub-millisecond precision.
|
|
31
|
+
*/
|
|
32
|
+
export declare function syncSleep(ms: number): void;
|
|
33
|
+
/**
|
|
34
|
+
* Ensures target directory exists synchronously.
|
|
35
|
+
* Idempotent and resilient against multi-process TOCTOU race conditions.
|
|
36
|
+
*/
|
|
37
|
+
export declare function ensureDir(dir: string): void;
|
|
38
|
+
/**
|
|
39
|
+
* Production-grade atomic file write:
|
|
40
|
+
* 1. Writes to a private temp file in the target directory (same filesystem).
|
|
41
|
+
* 2. Uses atomic OS rename so readers never read partial/corrupt JSON.
|
|
42
|
+
* 3. Retries with exponential backoff on Windows EPERM/EBUSY file locks.
|
|
43
|
+
* 4. Cleans up temp file on failure.
|
|
44
|
+
*/
|
|
45
|
+
export declare function atomicWrite(filePath: string, data: string, maxRetries?: number): void;
|
|
46
|
+
/**
|
|
47
|
+
* Production-grade atomic append for turn telemetry stream (history.ndjson).
|
|
48
|
+
* Retries on Windows transient file locks.
|
|
49
|
+
*/
|
|
50
|
+
export declare function atomicAppend(filePath: string, line: string, maxRetries?: number): void;
|
|
51
|
+
/**
|
|
52
|
+
* Atomically saves latest status snapshots into all designated status directories.
|
|
53
|
+
*/
|
|
54
|
+
export declare function saveLatest(statusDirs: readonly string[], sessionId: string, latestPayload: TokenSniffLatest): void;
|
|
55
|
+
/**
|
|
56
|
+
* Persists cumulative spending totals across active sessions, bounding memory to maxSessions.
|
|
57
|
+
*/
|
|
58
|
+
export declare function saveTotals(statusDirs: readonly string[], totals: Record<string, number>, maxSessions: number): Record<string, number>;
|
|
59
|
+
/**
|
|
60
|
+
* Reads cumulative spend totals from disk with directory fallback.
|
|
61
|
+
*/
|
|
62
|
+
export declare function loadTotals(statusDirs: readonly string[]): Record<string, number>;
|
|
63
|
+
/**
|
|
64
|
+
* Appends a compact turn record to the persistent history stream (history.ndjson).
|
|
65
|
+
*/
|
|
66
|
+
export declare function appendHistory(statusDirs: readonly string[], entry: HistoryInput): void;
|
|
67
|
+
/**
|
|
68
|
+
* Computes today's cumulative spend in USD from history.ndjson.
|
|
69
|
+
* Ignores malformed records and handles line-by-line reading safely.
|
|
70
|
+
*/
|
|
71
|
+
export declare function loadTodaySpend(statusDirs: readonly string[], targetDate?: string): number;
|
|
72
|
+
/**
|
|
73
|
+
* Prunes dead session records exceeding the staleness TTL.
|
|
74
|
+
*/
|
|
75
|
+
export declare function pruneDeadSessions(statusDirs: readonly string[], ttlMs: number): void;
|
|
76
|
+
//# sourceMappingURL=store.d.ts.map
|