ai-burnrate-tool 0.0.0-stage โ†’ 1.0.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/README.md CHANGED
@@ -1,3 +1,208 @@
1
- # Temporary Holding Version
1
+ <div align="center">
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ # ๐Ÿ”ฅ ai-burnrate โšก
4
+
5
+ **Real-Time Local Token & Equivalent API Cost Tracker for Antigravity CLI & Claude Code**
6
+
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-10b981.svg?style=flat-square)](https://github.com/Cise07/ai-burnrate-tool)
8
+ [![Node.js](https://img.shields.io/badge/Node.js-%3E%3D18-06b6d4.svg?style=flat-square)](https://nodejs.org/)
9
+ [![GitHub Repo](https://img.shields.io/badge/GitHub-Cise07%2Fai--burnrate--tool-d946ef.svg?style=flat-square)](https://github.com/Cise07/ai-burnrate-tool)
10
+ [![100% Local](https://img.shields.io/badge/Privacy-100%25%20Local-f59e0b.svg?style=flat-square)](#)
11
+
12
+ Track in real time how many tokens you are consuming across **Antigravity CLI** (`~/.gemini`) and **Claude Code** (`~/.claude`), what your equivalent pay-as-you-go API spend would be in **USD (`$`) or EUR (`โ‚ฌ`)**, and how much money you are saving through Prompt Caching and your monthly subscriptions.
13
+
14
+ </div>
15
+
16
+ ---
17
+
18
+ ## โœจ Key Features
19
+
20
+ - ๐Ÿ”’ **100% Local, Dynamic & Cross-Platform:** Automatically resolves your user home directory (`os.homedir()` โ†’ `~/.gemini` and `~/.claude`) on Windows, macOS, and Linux with zero hardcoded paths. You can also override watched folders via `BURNRATE_GEMINI_DIR` and `BURNRATE_CLAUDE_DIR`.
21
+ - ๐ŸŸข **Live Dashboard & Server-Sent Events (SSE):** A background file watcher (`chokidar`) monitors your active AI transcripts and pushes instant real-time updates to charts, KPIs, and session tables in the browser via `/api/events`.
22
+ - ๐Ÿ”„ **Automatic Official Price Sync & Historical Tariff Protection:** On startup (and on manual rescan), `ai-burnrate` automatically fetches the latest official per-token model prices from the public **LiteLLM Pricing Registry** and the official repository feed. Whenever a model's price changes, a new timestamped rate snapshot (`effectiveFrom`) is appended to `~/.burnrate/pricing-ledger.json`โ€”**tokens consumed before the price change are never recalculated**, and the new tariff applies strictly to turns recorded after the change.
23
+ - ๐Ÿ’ฑ **Instant `$ USD` / `โ‚ฌ EUR` Currency Switch:** Toggle the entire dashboard (KPI cards, monthly subscription comparison, charts, and live session table) between US Dollars and Euros with persistent `localStorage` state.
24
+ - ๐Ÿง  **Granular Per-Model Token Breakdown:** Dedicated central widget and ANSI CLI tables breaking down *Input (Uncached)*, *Cache Read (Context)*, and *Output (Thinking + Response/Code)* with automatic streaming chunk deduplication.
25
+ - ๐Ÿ–ฅ๏ธ **Instant Terminal Mode (`--cli`):** Prints colorized ANSI tables (Tool Breakdown, Model Breakdown, and Top 12 Recent Sessions) directly in your terminal and exits immediately.
26
+
27
+ ---
28
+
29
+ ## ๐Ÿš€ Quick Install (Latest Version)
30
+
31
+ You don't need to manually download or clone the repositoryโ€”simply paste **one command** into your terminal from any directory. The installer automatically resolves the latest GitHub Release (falling back to `main` if none exist yet).
32
+
33
+ > โš ๏ธ **Prerequisite:** Make sure you have [Node.js (>= 18)](https://nodejs.org/) and `npm` installed.
34
+
35
+ ### ๐ŸชŸ Windows (PowerShell)
36
+ Open PowerShell and run:
37
+ ```powershell
38
+ irm https://raw.githubusercontent.com/Cise07/ai-burnrate-tool/main/scripts/install.ps1 | iex
39
+ ```
40
+ > ๐Ÿ’ก **Note on Windows permissions:** If PowerShell blocks the script with an `ExecutionPolicy` or permission error, enable script execution for your user by running:
41
+ > ```powershell
42
+ > Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
43
+ > ```
44
+
45
+ ### ๐ŸŽ macOS / ๐Ÿง Linux (Bash / Zsh)
46
+ Open your terminal and run:
47
+ ```bash
48
+ curl -fsSL https://raw.githubusercontent.com/Cise07/ai-burnrate-tool/main/scripts/install.sh | bash
49
+ ```
50
+
51
+ ### ๐Ÿ“ฆ Universal Alternative via `npm` (Cross-Platform)
52
+ ```bash
53
+ npm install -g https://github.com/Cise07/ai-burnrate-tool/archive/main.tar.gz
54
+ ```
55
+
56
+ *(Want to run it once without installing? Use `npx https://github.com/Cise07/ai-burnrate-tool/archive/main.tar.gz`)*
57
+
58
+ ### ๐Ÿท๏ธ Install a Specific Release Version
59
+ To pin a specific release tag (e.g., `v1.0.1`), use the release tarball directly or pass `BURNRATE_VERSION` to the installer:
60
+
61
+ ```bash
62
+ # Universal (recommended for GitHub Release notes)
63
+ npm install -g https://github.com/Cise07/ai-burnrate-tool/archive/refs/tags/vX.Y.Z.tar.gz
64
+ ```
65
+
66
+ ```powershell
67
+ # Windows PowerShell
68
+ $env:BURNRATE_VERSION="vX.Y.Z"; irm https://raw.githubusercontent.com/Cise07/ai-burnrate-tool/main/scripts/install.ps1 | iex
69
+ ```
70
+
71
+ ```bash
72
+ # macOS / Linux
73
+ BURNRATE_VERSION=vX.Y.Z curl -fsSL https://raw.githubusercontent.com/Cise07/ai-burnrate-tool/main/scripts/install.sh | bash
74
+ ```
75
+
76
+ ---
77
+
78
+ ## ๐Ÿ› ๏ธ Install from Local Clone (For Developers)
79
+
80
+ If you clone the repository locally, the installer script automatically detects `package.json`, installs dependencies, compiles both the React frontend (`dist/public`) and CLI (`dist/cli`), and registers the global `burnrate` binary:
81
+
82
+ ```bash
83
+ # 1. Clone the repository
84
+ git clone https://github.com/Cise07/ai-burnrate-tool.git
85
+ cd ai-burnrate-tool
86
+
87
+ # 2. Build and install globally
88
+ .\scripts\install.ps1 # Windows PowerShell
89
+ ./scripts/install.sh # macOS / Linux
90
+ # Or via npm script:
91
+ npm run setup
92
+ ```
93
+
94
+ ---
95
+
96
+ ## ๐ŸŽฎ Usage & CLI Flags
97
+
98
+ Once installed, the **`burnrate`** (or **`ai-burnrate`**) command is available globally from **any folder** in your terminal:
99
+
100
+ | Command | Description |
101
+ | :--- | :--- |
102
+ | `burnrate` | ๐ŸŸข **Live Mode (Default):** Syncs official pricing, starts the local HTTP + SSE server, watches `~/.gemini` & `~/.claude`, and opens the React Dashboard in your browser. |
103
+ | `burnrate --cli` | ๐Ÿ“Š **Terminal Mode:** Syncs pricing, prints the full token & cost report in colorized ANSI tables in the terminal, and exits immediately. |
104
+ | `burnrate --no-open` | ๐Ÿ”‡ **Headless Mode:** Starts the live server and file watcher without automatically opening the browser. |
105
+ | `burnrate -p, --port <number>` | ๐Ÿ”Œ **Custom Port:** Starts the dashboard on a specific port (default: `4321`, automatically falling back to the next free port if busy). |
106
+ | `burnrate --update` | ๐Ÿ”„ **Self-Update:** Updates `ai-burnrate` to the latest release directly from GitHub. |
107
+ | `burnrate --uninstall` | ๐Ÿ—‘๏ธ **Self-Uninstall:** Completely removes the global `burnrate` package from your system. |
108
+ | `burnrate -V, --version` | ๐Ÿท๏ธ Prints the installed version (`1.0.0`). |
109
+ | `burnrate -h, --help` | โ„น๏ธ Displays all available CLI options. |
110
+
111
+ > ๐Ÿ’ก **Clean Shutdown:** While running in live mode (`burnrate`), press `Ctrl+C` (`SIGINT`) to cleanly close all SSE streams, active HTTP sockets, and the `chokidar` file watcher.
112
+
113
+ ---
114
+
115
+ ## ๐Ÿ—‘๏ธ How to Uninstall `ai-burnrate`
116
+
117
+ You can remove the tool at any time using any of the following methods:
118
+
119
+ ### 1๏ธโƒฃ Built-in CLI Flag (Recommended)
120
+ From any directory in your terminal, simply run:
121
+ ```bash
122
+ burnrate --uninstall
123
+ ```
124
+
125
+ ### 2๏ธโƒฃ Via `npm`
126
+ ```bash
127
+ npm uninstall -g ai-burnrate-tool
128
+ ```
129
+
130
+ ### 3๏ธโƒฃ Via One-Liner Script
131
+ - **Windows (PowerShell):**
132
+ ```powershell
133
+ irm https://raw.githubusercontent.com/Cise07/ai-burnrate-tool/main/scripts/uninstall.ps1 | iex
134
+ ```
135
+ - **macOS / Linux:**
136
+ ```bash
137
+ curl -fsSL https://raw.githubusercontent.com/Cise07/ai-burnrate-tool/main/scripts/uninstall.sh | bash
138
+ ```
139
+
140
+ ---
141
+
142
+ ## ๐Ÿ’ฐ How Pricing & Historical Rate Versioning Work
143
+
144
+ `ai-burnrate` uses a time-versioned pricing engine (`src/core/pricing.ts`) so that price updates from AI providers never distort your past spending history:
145
+
146
+ 1. **Initial Seed (`config/pricing.json`):** Provides the initial baseline rates (effective from `1970-01-01T00:00:00.000Z`) and offline fallback for **Claude** (*Opus 4.x, Sonnet 4.x, 3.7 Sonnet, 3.5 Sonnet, Haiku*) and **Google Gemini** (*Gemini 4 Argon, Gemini Pro, Gemini 3.8 Flash High, Gemini Flash, Flash-Lite*).
147
+ 2. **Automatic Live Sync (`syncOfficialPricing`):** At launch and whenever you click the **Rescan** button in the UI, `ai-burnrate` queries the official **LiteLLM Model Pricing Registry** and the GitHub repository feed (with a 3.5s non-blocking timeout for offline resilience).
148
+ 3. **Immutable Historical Ledger (`~/.burnrate/pricing-ledger.json`):**
149
+ - When the sync detects that a provider has changed a model's `input`, `output`, `cacheRead`, or `cacheWrite` rate, it **does not overwrite** previous rates.
150
+ - Instead, it appends a new `RateSnapshot` to the `history` array in `~/.burnrate/pricing-ledger.json` stamped with `effectiveFrom: <current ISO timestamp>`.
151
+ 4. **Per-Turn Timestamp Matching (`getHistoricalRate`):**
152
+ - Every turn parsed from `~/.gemini` and `~/.claude` has its own `timestamp`.
153
+ - `calculateTurnCost` matches each turn's timestamp against `pricing.history` (`snapshot.effectiveFrom <= turn.timestamp`).
154
+ - All tokens used **before** a price change remain permanently valued at the old rate, while tokens used **after** the price change are valued at the new rate.
155
+
156
+ ---
157
+
158
+ ## ๐Ÿ“Š Dashboard Overview
159
+
160
+ - **๐Ÿ” Non-Wrapping Top Bar:** Displays the pulsing `LIVE` SSE connection badge, tool filter (`All`, `Antigravity`, `Claude`), time window selector (`24h`, `7d`, `30d`, `all`), `$ USD` / `โ‚ฌ EUR` currency switch, and manual rescan button.
161
+ - **๐Ÿ’ธ 4 Top KPI Cards:**
162
+ 1. **API Equivalent Spend:** Total spend with per-tool split (`AGY` vs `Claude`) and ROI multiplier against monthly subscription plans.
163
+ 2. **Total Tokens:** Cumulative tokens processed across all LLM turns, split into `Input`, `Output`, and `Cached`.
164
+ 3. **Cache Savings:** Total money saved via context caching and overall *Cache Hit Ratio* percentage.
165
+ 4. **Sessions & Projects:** Active sessions count, distinct workspaces count, and average cost per session.
166
+ - **๐Ÿ“ˆ Interactive Charts & Model Token Widget:**
167
+ - **Daily API Burn Rate:** Stacked area chart comparing Antigravity CLI and Claude Code spend over time.
168
+ - **Cost by Model:** Horizontal bar chart ranking spend by model.
169
+ - **Total Token Usage by Model:** Central grid showing total tokens, percentage share, and `Input / Cached / Output` breakdown for every model.
170
+ - **๐Ÿ—‚๏ธ Live Sessions & Workspaces Table:** Real-time searchable table displaying tool badge, relative workspace path (`~/...`), primary model, turns, input/output tokens, cache read tokens, cache savings, API cost, and relative last-active time.
171
+
172
+ ---
173
+
174
+ ## ๐Ÿ“ Project Structure
175
+
176
+ ```text
177
+ ai-burnrate/
178
+ โ”œโ”€โ”€ config/
179
+ โ”‚ โ””โ”€โ”€ pricing.json # Initial baseline model rates & subscription references
180
+ โ”œโ”€โ”€ scripts/
181
+ โ”‚ โ”œโ”€โ”€ install.ps1 # Windows remote one-liner & local installer
182
+ โ”‚ โ”œโ”€โ”€ uninstall.ps1 # Windows one-liner uninstaller
183
+ โ”‚ โ”œโ”€โ”€ install.sh # macOS/Linux remote one-liner & local installer
184
+ โ”‚ โ””โ”€โ”€ uninstall.sh # macOS/Linux one-liner uninstaller
185
+ โ”œโ”€โ”€ src/
186
+ โ”‚ โ”œโ”€โ”€ cli/
187
+ โ”‚ โ”‚ โ”œโ”€โ”€ index.ts # CLI entrypoint (#!/usr/bin/env node)
188
+ โ”‚ โ”‚ โ””โ”€โ”€ reporter.ts # ANSI terminal table formatter (--cli)
189
+ โ”‚ โ”œโ”€โ”€ core/
190
+ โ”‚ โ”‚ โ”œโ”€โ”€ parser.ts # Dynamic ~/.gemini & ~/.claude JSONL parser
191
+ โ”‚ โ”‚ โ”œโ”€โ”€ pricing.ts # Official price auto-sync & historical rate ledger
192
+ โ”‚ โ”‚ โ”œโ”€โ”€ watcher.ts # Real-time file watcher with chokidar
193
+ โ”‚ โ”‚ โ””โ”€โ”€ types.ts # Shared TypeScript interfaces
194
+ โ”‚ โ”œโ”€โ”€ server/
195
+ โ”‚ โ”‚ โ””โ”€โ”€ index.ts # Local HTTP server + SSE stream (/api/events)
196
+ โ”‚ โ””โ”€โ”€ web/
197
+ โ”‚ โ”œโ”€โ”€ App.tsx # Dark Mode React Dashboard + USD/EUR toggle
198
+ โ”‚ โ”œโ”€โ”€ main.tsx # React entrypoint
199
+ โ”‚ โ””โ”€โ”€ index.css # Tailwind CSS styles
200
+ โ”œโ”€โ”€ dist/ # Prebuilt bundle (CLI + static web assets)
201
+ โ””โ”€โ”€ package.json
202
+ ```
203
+
204
+ ---
205
+
206
+ ## ๐Ÿ“„ License
207
+
208
+ Distributed under the **MIT** License by [Cise07](https://github.com/Cise07). Feel free to open Issues or Pull Requests! โค๏ธ
@@ -0,0 +1,247 @@
1
+ {
2
+ "updatedAt": "2026-11-13",
3
+ "currency": "USD",
4
+ "unit": "per_1m_tokens",
5
+ "subscriptions": {
6
+ "claude_max": {
7
+ "name": "Claude Pro / Max",
8
+ "monthlyUSD": 20.0
9
+ },
10
+ "antigravity_pro": {
11
+ "name": "Google AI Ultra / Pro",
12
+ "monthlyUSD": 20.0
13
+ },
14
+ "combinedMonthlyUSD": 40.0
15
+ },
16
+ "models": {
17
+ "claude-3-7-sonnet": {
18
+ "label": "Claude 3.7 Sonnet",
19
+ "provider": "anthropic",
20
+ "input": 3.0,
21
+ "output": 15.0,
22
+ "cacheRead": 0.3,
23
+ "cacheWrite": 3.75
24
+ },
25
+ "claude-sonnet-4": {
26
+ "label": "Claude Sonnet 4.x",
27
+ "provider": "anthropic",
28
+ "input": 3.0,
29
+ "output": 15.0,
30
+ "cacheRead": 0.3,
31
+ "cacheWrite": 3.75
32
+ },
33
+ "claude-3-5-sonnet": {
34
+ "label": "Claude 3.5 Sonnet",
35
+ "provider": "anthropic",
36
+ "input": 3.0,
37
+ "output": 15.0,
38
+ "cacheRead": 0.3,
39
+ "cacheWrite": 3.75
40
+ },
41
+ "claude-opus-4": {
42
+ "label": "Claude Opus 4.x",
43
+ "provider": "anthropic",
44
+ "input": 15.0,
45
+ "output": 75.0,
46
+ "cacheRead": 1.5,
47
+ "cacheWrite": 18.75
48
+ },
49
+ "claude-3-opus": {
50
+ "label": "Claude 3 Opus",
51
+ "provider": "anthropic",
52
+ "input": 15.0,
53
+ "output": 75.0,
54
+ "cacheRead": 1.5,
55
+ "cacheWrite": 18.75
56
+ },
57
+ "claude-3-5-haiku": {
58
+ "label": "Claude 3.5 Haiku",
59
+ "provider": "anthropic",
60
+ "input": 0.8,
61
+ "output": 4.0,
62
+ "cacheRead": 0.08,
63
+ "cacheWrite": 1.0
64
+ },
65
+ "claude-haiku-4": {
66
+ "label": "Claude Haiku 4.x",
67
+ "provider": "anthropic",
68
+ "input": 0.8,
69
+ "output": 4.0,
70
+ "cacheRead": 0.08,
71
+ "cacheWrite": 1.0
72
+ },
73
+ "gemini-4-argon": {
74
+ "label": "Gemini 4 Argon",
75
+ "provider": "google",
76
+ "input": 2.0,
77
+ "output": 10.0,
78
+ "cacheRead": 0.1,
79
+ "cacheWrite": 2.0,
80
+ "isPromo": true,
81
+ "promoStart": "2026-10-21T00:00:00.000Z",
82
+ "promoEnd": "2026-11-30T23:59:59.999Z",
83
+ "promoNote": "Promo Google AI Launch (-50% dal 21/10/2026 al 30/11/2026)",
84
+ "standardInput": 4.0,
85
+ "standardOutput": 20.0,
86
+ "standardCacheRead": 0.2,
87
+ "standardCacheWrite": 4.0
88
+ },
89
+ "gemini-4-carbon": {
90
+ "label": "Gemini 4 Carbon",
91
+ "provider": "google",
92
+ "input": 2.0,
93
+ "output": 10.0,
94
+ "cacheRead": 0.1,
95
+ "cacheWrite": 2.0,
96
+ "isPromo": true,
97
+ "promoStart": "2026-10-21T00:00:00.000Z",
98
+ "promoEnd": "2026-11-30T23:59:59.999Z",
99
+ "promoNote": "Promo Google AI Launch (-50% dal 21/10/2026 al 30/11/2026)",
100
+ "standardInput": 4.0,
101
+ "standardOutput": 20.0,
102
+ "standardCacheRead": 0.2,
103
+ "standardCacheWrite": 4.0
104
+ },
105
+ "gemini-4-hydrogen": {
106
+ "label": "Gemini 4 Hydrogen",
107
+ "provider": "google",
108
+ "input": 1.5,
109
+ "output": 7.5,
110
+ "cacheRead": 0.075,
111
+ "cacheWrite": 1.5,
112
+ "isPromo": false
113
+ },
114
+ "orchestrator-carbon": {
115
+ "label": "Orchestrator (Carbon)",
116
+ "provider": "google",
117
+ "input": 1.65,
118
+ "output": 8.25,
119
+ "cacheRead": 0.0825,
120
+ "cacheWrite": 1.65,
121
+ "isPromo": true,
122
+ "promoStart": "2026-10-21T00:00:00.000Z",
123
+ "promoEnd": "2026-11-30T23:59:59.999Z",
124
+ "promoNote": "Promo Google AI Launch su Planner Carbon (-50% fino al 30/11/2026) + Hydrogen",
125
+ "standardInput": 2.25,
126
+ "standardOutput": 11.25,
127
+ "standardCacheRead": 0.1125,
128
+ "standardCacheWrite": 2.25
129
+ },
130
+ "orchestrator-argon": {
131
+ "label": "Orchestrator (Argon)",
132
+ "provider": "google",
133
+ "input": 1.65,
134
+ "output": 8.25,
135
+ "cacheRead": 0.0825,
136
+ "cacheWrite": 1.65,
137
+ "isPromo": true,
138
+ "promoStart": "2026-10-21T00:00:00.000Z",
139
+ "promoEnd": "2026-11-30T23:59:59.999Z",
140
+ "promoNote": "Promo Google AI Launch su Planner Argon (-50% fino al 30/11/2026) + Hydrogen",
141
+ "standardInput": 2.25,
142
+ "standardOutput": 11.25,
143
+ "standardCacheRead": 0.1125,
144
+ "standardCacheWrite": 2.25
145
+ },
146
+ "gemini-2.5-pro": {
147
+ "label": "Gemini Pro",
148
+ "provider": "google",
149
+ "input": 1.25,
150
+ "output": 10.0,
151
+ "cacheRead": 0.125,
152
+ "cacheWrite": 1.25,
153
+ "isPromo": true,
154
+ "promoStart": "2026-06-01T00:00:00.000Z",
155
+ "promoEnd": "2026-12-31T23:59:59.999Z",
156
+ "promoNote": "Promo Google AI (<200k tokens)",
157
+ "standardInput": 2.5,
158
+ "standardOutput": 12.5,
159
+ "standardCacheRead": 0.625,
160
+ "standardCacheWrite": 2.5
161
+ },
162
+ "gemini-pro": {
163
+ "label": "Gemini Pro",
164
+ "provider": "google",
165
+ "input": 1.25,
166
+ "output": 10.0,
167
+ "cacheRead": 0.125,
168
+ "cacheWrite": 1.25,
169
+ "isPromo": true,
170
+ "promoStart": "2026-06-01T00:00:00.000Z",
171
+ "promoEnd": "2026-12-31T23:59:59.999Z",
172
+ "promoNote": "Promo Google AI (<200k tokens)",
173
+ "standardInput": 2.5,
174
+ "standardOutput": 12.5,
175
+ "standardCacheRead": 0.625,
176
+ "standardCacheWrite": 2.5
177
+ },
178
+ "gemini-3.8-flash": {
179
+ "label": "Gemini 3.8 Flash (High)",
180
+ "provider": "google",
181
+ "input": 0.75,
182
+ "output": 3.75,
183
+ "cacheRead": 0.075,
184
+ "cacheWrite": 0.75,
185
+ "isPromo": true,
186
+ "promoStart": "2026-09-15T00:00:00.000Z",
187
+ "promoEnd": "2026-12-31T23:59:59.999Z",
188
+ "promoNote": "Promo Google AI (-50% dal 15/09/2026 al 31/12/2026)",
189
+ "standardInput": 1.5,
190
+ "standardOutput": 7.5,
191
+ "standardCacheRead": 0.15,
192
+ "standardCacheWrite": 1.5
193
+ },
194
+ "gemini-2.5-flash": {
195
+ "label": "Gemini Flash",
196
+ "provider": "google",
197
+ "input": 0.3,
198
+ "output": 2.5,
199
+ "cacheRead": 0.03,
200
+ "cacheWrite": 0.3,
201
+ "isPromo": true,
202
+ "promoStart": "2026-06-01T00:00:00.000Z",
203
+ "promoEnd": "2026-12-31T23:59:59.999Z",
204
+ "promoNote": "Promo Google AI Introductory",
205
+ "standardInput": 0.5,
206
+ "standardOutput": 2.5,
207
+ "standardCacheRead": 0.125,
208
+ "standardCacheWrite": 0.5
209
+ },
210
+ "gemini-flash": {
211
+ "label": "Gemini Flash",
212
+ "provider": "google",
213
+ "input": 0.3,
214
+ "output": 2.5,
215
+ "cacheRead": 0.03,
216
+ "cacheWrite": 0.3,
217
+ "isPromo": true,
218
+ "promoStart": "2026-06-01T00:00:00.000Z",
219
+ "promoEnd": "2026-12-31T23:59:59.999Z",
220
+ "promoNote": "Promo Google AI Introductory",
221
+ "standardInput": 0.5,
222
+ "standardOutput": 2.5,
223
+ "standardCacheRead": 0.125,
224
+ "standardCacheWrite": 0.5
225
+ },
226
+ "gemini-flash-lite": {
227
+ "label": "Gemini Flash-Lite",
228
+ "provider": "google",
229
+ "input": 0.1,
230
+ "output": 0.4,
231
+ "cacheRead": 0.01,
232
+ "cacheWrite": 0.1,
233
+ "isPromo": true,
234
+ "promoStart": "2026-06-01T00:00:00.000Z",
235
+ "promoEnd": "2026-12-31T23:59:59.999Z",
236
+ "promoNote": "Promo Google AI Tier",
237
+ "standardInput": 0.15,
238
+ "standardOutput": 0.6,
239
+ "standardCacheRead": 0.0375,
240
+ "standardCacheWrite": 0.15
241
+ }
242
+ },
243
+ "defaults": {
244
+ "claude": "claude-sonnet-4",
245
+ "antigravity": "gemini-4-argon"
246
+ }
247
+ }
@@ -0,0 +1,150 @@
1
+ #!/usr/bin/env node
2
+ import { execSync } from 'node:child_process';
3
+ import fs from 'node:fs';
4
+ import path from 'node:path';
5
+ import { Command } from 'commander';
6
+ import open from 'open';
7
+ import pc from 'picocolors';
8
+ import { scanAllLogs } from '../core/parser.js';
9
+ import { getPackageRoot, syncOfficialPricing } from '../core/pricing.js';
10
+ import { startLogWatcher } from '../core/watcher.js';
11
+ import { startServer } from '../server/index.js';
12
+ import { printCliReport } from './reporter.js';
13
+ const REPO_SLUG = 'Cise07/ai-burnrate-tool';
14
+ function getPackageVersion() {
15
+ try {
16
+ const pkgPath = path.join(getPackageRoot(), 'package.json');
17
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
18
+ return pkg.version || '1.0.0';
19
+ }
20
+ catch {
21
+ return '1.0.0';
22
+ }
23
+ }
24
+ async function resolveUpdateTarget() {
25
+ const requested = process.env.BURNRATE_VERSION?.trim();
26
+ if (requested) {
27
+ const tag = requested.startsWith('v') ? requested : `v${requested}`;
28
+ return {
29
+ label: tag,
30
+ url: `https://github.com/${REPO_SLUG}/archive/refs/tags/${tag}.tar.gz`,
31
+ };
32
+ }
33
+ try {
34
+ const res = await fetch(`https://api.github.com/repos/${REPO_SLUG}/releases/latest`, {
35
+ headers: { 'User-Agent': 'ai-burnrate-cli' },
36
+ signal: AbortSignal.timeout(4000),
37
+ });
38
+ if (res.ok) {
39
+ const data = (await res.json());
40
+ if (data.tag_name) {
41
+ return {
42
+ label: data.tag_name,
43
+ url: `https://github.com/${REPO_SLUG}/archive/refs/tags/${data.tag_name}.tar.gz`,
44
+ };
45
+ }
46
+ }
47
+ }
48
+ catch {
49
+ // Fallback to main branch if no GitHub Release exists yet or offline
50
+ }
51
+ return {
52
+ label: 'main',
53
+ url: `https://github.com/${REPO_SLUG}/archive/refs/heads/main.tar.gz`,
54
+ };
55
+ }
56
+ const program = new Command();
57
+ program
58
+ .name('burnrate')
59
+ .description('Real-time local token & API equivalent cost tracker for Antigravity CLI and Claude Code')
60
+ .version(getPackageVersion())
61
+ .option('--cli', 'Print the usage report in ANSI tables in the terminal and exit immediately', false)
62
+ .option('--no-open', 'Start the live server and file watcher without automatically opening the browser')
63
+ .option('-p, --port <number>', 'Specify a custom port for the dashboard server', '4321')
64
+ .option('--update', 'Update ai-burnrate to the latest release from GitHub', false)
65
+ .option('--uninstall', 'Uninstall ai-burnrate globally from your system', false);
66
+ program.parse(process.argv);
67
+ const opts = program.opts();
68
+ async function main() {
69
+ if (opts.update) {
70
+ const target = await resolveUpdateTarget();
71
+ console.log(`\n ${pc.cyan('โ—')} Updating ${pc.bold('ai-burnrate')} (${pc.cyan(target.label)}) from GitHub...`);
72
+ try {
73
+ execSync(`npm install -g ${target.url}`, {
74
+ stdio: 'inherit',
75
+ });
76
+ console.log(` ${pc.green('โœ“')} ${pc.bold('ai-burnrate')} updated successfully to ${pc.bold(target.label)}!\n`);
77
+ process.exit(0);
78
+ }
79
+ catch {
80
+ console.error(` ${pc.red('โœ—')} Failed to update automatically. Try running:\n ${pc.cyan(`npm install -g ${target.url}`)}\n`);
81
+ process.exit(1);
82
+ }
83
+ }
84
+ if (opts.uninstall) {
85
+ console.log(`\n ${pc.yellow('โ—')} Uninstalling ${pc.bold('ai-burnrate')} globally...`);
86
+ try {
87
+ execSync('npm uninstall -g ai-burnrate-tool', { stdio: 'inherit' });
88
+ console.log(` ${pc.green('โœ“')} ${pc.bold('ai-burnrate')} has been completely removed from your system.\n`);
89
+ process.exit(0);
90
+ }
91
+ catch {
92
+ console.error(` ${pc.red('โœ—')} Failed to uninstall automatically. Run: ${pc.cyan('npm uninstall -g ai-burnrate-tool')}`);
93
+ process.exit(1);
94
+ }
95
+ }
96
+ const syncResult = await syncOfficialPricing();
97
+ if (syncResult.updated && syncResult.effectiveFrom) {
98
+ console.log(` ${pc.cyan('โ†ป')} Official pricing updated (new tariff active for turns from ${pc.bold(syncResult.effectiveFrom)}; past turns preserved).`);
99
+ }
100
+ const snapshot = scanAllLogs(true);
101
+ if (opts.cli) {
102
+ printCliReport(snapshot);
103
+ process.exit(0);
104
+ }
105
+ const preferredPort = Number.parseInt(String(opts.port || '4321'), 10) || 4321;
106
+ const server = await startServer(preferredPort, snapshot);
107
+ const watcherHandle = startLogWatcher((updatedSnapshot, changedPath) => {
108
+ server.broadcast(updatedSnapshot, changedPath);
109
+ const timeStr = new Date().toLocaleTimeString();
110
+ console.log(`${pc.dim(`[${timeStr}]`)} ${pc.green('โ— SSE Sync')} ${pc.dim('โ†')} ${pc.cyan(changedPath)}`);
111
+ });
112
+ console.log('');
113
+ console.log(` ${pc.bgGreen(pc.black(pc.bold(' AI-BURNRATE ')))} ${pc.green('โ— LIVE')} ${pc.bold('Real-Time Token & Cost Tracker')}`);
114
+ console.log(` ${pc.dim('โ”€'.repeat(58))}`);
115
+ console.log(` ${pc.bold('Dashboard URL:')} ${pc.cyan(pc.underline(server.url))}`);
116
+ console.log(` ${pc.bold('SSE Stream:')} ${pc.dim(`${server.url}/api/events`)}`);
117
+ console.log(` ${pc.bold('Watching:')} ${pc.dim(snapshot.watchedPaths.join(' & '))}`);
118
+ console.log(` ${pc.bold('Sessions Found:')} ${pc.yellow(String(snapshot.sessions.length))}`);
119
+ console.log(` ${pc.dim('โ”€'.repeat(58))}`);
120
+ console.log(` ${pc.dim('Press Ctrl+C to stop the live watcher and exit.')}\n`);
121
+ if (opts.open !== false) {
122
+ try {
123
+ await open(server.url);
124
+ }
125
+ catch {
126
+ console.log(` ${pc.yellow('!')} Could not auto-open browser. Open ${pc.cyan(server.url)} manually.`);
127
+ }
128
+ }
129
+ let shuttingDown = false;
130
+ const shutdown = async (signal) => {
131
+ if (shuttingDown)
132
+ return;
133
+ shuttingDown = true;
134
+ console.log(`\n ${pc.yellow('โ—')} Received ${signal}. Closing file watcher and SSE connections...`);
135
+ try {
136
+ await Promise.all([watcherHandle.close(), server.close()]);
137
+ }
138
+ catch {
139
+ // ignore
140
+ }
141
+ console.log(` ${pc.green('โœ“')} ai-burnrate stopped cleanly.`);
142
+ process.exit(0);
143
+ };
144
+ process.on('SIGINT', () => void shutdown('SIGINT'));
145
+ process.on('SIGTERM', () => void shutdown('SIGTERM'));
146
+ }
147
+ main().catch((err) => {
148
+ console.error(pc.red('Fatal error starting ai-burnrate:'), err);
149
+ process.exit(1);
150
+ });