tokentrax 0.0.0-stage → 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.
Files changed (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +288 -2
  3. package/assets/built-with-ai-assistance.png +0 -0
  4. package/assets/tokentrax.png +0 -0
  5. package/bin/postinstall.js +61 -0
  6. package/bin/start-server.sh +38 -0
  7. package/bin/stop-server.sh +18 -0
  8. package/bin/tracker.js +11 -0
  9. package/dashboard/index.html +9427 -0
  10. package/data/curated-overrides.json +46 -0
  11. package/data/pricing-seed.json +26 -0
  12. package/package.json +52 -4
  13. package/src/cli.js +94 -0
  14. package/src/commands/backup.js +214 -0
  15. package/src/commands/costs.js +78 -0
  16. package/src/commands/doctor.js +173 -0
  17. package/src/commands/export.js +74 -0
  18. package/src/commands/init.js +156 -0
  19. package/src/commands/migratePricing.js +131 -0
  20. package/src/commands/price.js +93 -0
  21. package/src/commands/serve.js +1132 -0
  22. package/src/commands/status.js +198 -0
  23. package/src/commands/sync.js +1001 -0
  24. package/src/commands/syncPricing.js +24 -0
  25. package/src/commands/top.js +95 -0
  26. package/src/commands/uninstall.js +79 -0
  27. package/src/lib/config.js +54 -0
  28. package/src/lib/fs.js +111 -0
  29. package/src/lib/hooks.js +466 -0
  30. package/src/lib/local-time.js +193 -0
  31. package/src/lib/model.js +28 -0
  32. package/src/lib/normalization.js +49 -0
  33. package/src/lib/parsers/claude.js +75 -0
  34. package/src/lib/parsers/codebuddy.js +97 -0
  35. package/src/lib/parsers/copilot.js +89 -0
  36. package/src/lib/parsers/cursor.js +60 -0
  37. package/src/lib/parsers/gemini.js +97 -0
  38. package/src/lib/parsers/hermes.js +112 -0
  39. package/src/lib/parsers/kimi.js +97 -0
  40. package/src/lib/parsers/kiro.js +112 -0
  41. package/src/lib/parsers/omp.js +97 -0
  42. package/src/lib/parsers/opencode.js +131 -0
  43. package/src/lib/parsers/opencodedb.js +189 -0
  44. package/src/lib/parsers/pi.js +166 -0
  45. package/src/lib/parsers/rollout.js +106 -0
  46. package/src/lib/parsers/stream.js +117 -0
  47. package/src/lib/pricing-fetch.js +130 -0
  48. package/src/lib/pricing-overrides.js +108 -0
  49. package/src/lib/pricing.js +181 -0
  50. package/src/lib/sqlite.js +1657 -0
  51. package/src/lib/ui.js +153 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Josh Greene
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,289 @@
1
- # Temporary Holding Version
1
+ <img src="assets/tokentrax.png" width=50%>
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
+ **Lean, local-first AI token usage tracker — zero bloat**
4
+
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT)
6
+ [![Node](https://img.shields.io/badge/node-%3E%3D20-brightgreen)](https://nodejs.org) <img src="assets/built-with-ai-assistance.png" height=20>
7
+ <img src="assets/phone-high.jpg" alt="TokenTrax Dashboard" width="100%">
8
+
9
+ ---
10
+
11
+ ## Installation
12
+
13
+ ### Via npm (recommended)
14
+
15
+ ```bash
16
+ npm install -g tokentrax
17
+ ```
18
+
19
+ ### Via git clone
20
+
21
+ ```bash
22
+ git clone https://github.com/jeshuwah/TokenTrax.git
23
+ cd tokentrax
24
+ ./install.sh
25
+ ```
26
+
27
+ Or manually:
28
+
29
+ ```bash
30
+ git clone https://github.com/jeshuwah/TokenTrax.git
31
+ cd tokentrax
32
+ npm install
33
+ npm link
34
+ ```
35
+
36
+ This installs TokenTrax globally and automatically:
37
+
38
+ - Runs database migrations (schema updates are applied automatically)
39
+ - Backfills pricing for any existing data without costs
40
+
41
+ ### Remote agent
42
+
43
+ To report usage from a *second* machine — a laptop, a work box, anywhere
44
+ with an AI harness — install the agent there:
45
+
46
+ ```bash
47
+ npm install -g tokentrax-agent
48
+ tokentrax-agent setup --server http://your-dashboard:7680 --key <sync-key>
49
+ ```
50
+
51
+ That writes the configuration, installs a systemd user timer and starts it.
52
+ The machine then reports its sessions, tokens and cost to the dashboard every
53
+ five minutes. See [`agent/README.md`](agent/README.md) for the details, and
54
+ [`docs/agent-configuration.md`](docs/agent-configuration.md) for every option.
55
+
56
+ ### Requirements
57
+
58
+ - Node.js >= 20
59
+ - `better-sqlite3` (installed automatically as a native module)
60
+
61
+ ### Setup
62
+
63
+ ```bash
64
+ tokentrax init # Install hooks for detected AI tools
65
+ tokentrax sync # Parse existing logs → SQLite
66
+ tokentrax serve # Open dashboard at localhost:7680
67
+ ```
68
+
69
+ ### Updating
70
+
71
+ ```bash
72
+ npm update -g tokentrax
73
+ ```
74
+
75
+ Updates are safe — the postinstall script automatically migrates your existing database schema and backfills any missing pricing data.
76
+
77
+ ---
78
+
79
+ ## Features
80
+
81
+ - **Zero runtime dependencies** — only `better-sqlite3` (native module)
82
+ - **Single-file dashboard** — no bundler, no framework, no build step
83
+ - **SQLite storage** — indexed upserts, bounded file size, WAL mode
84
+ - **12 AI tool integrations** — Claude Code, Codex, Gemini, Cursor, Kiro, Hermes, and more
85
+ - **Bundled + live pricing** — 2200+ model prices cached locally, auto-refreshed
86
+ - **Normalization engine** — maps 100+ model aliases to canonical names
87
+ - **Privacy-first** — all data stays in `~/.tokentrax/`, no telemetry
88
+
89
+ ---
90
+
91
+ ## Dashboard
92
+
93
+ ### Overview
94
+
95
+ Real-time metrics, daily usage chart, and source breakdown — everything at a glance.
96
+
97
+ ### Activity Heatmap
98
+
99
+ GitHub-style contribution grid showing weekly token usage across 52 weeks.
100
+
101
+ <img src="docs/screenshots/heatmap.png" alt="Activity Heatmap" width="100%">
102
+
103
+ ### Models Breakdown
104
+
105
+ Per-model and per-source token tracking with cost estimates, sorted by usage.
106
+
107
+ <img src="docs/screenshots/models.png" alt="Models Breakdown" width="100%">
108
+
109
+ ### Import & Upload
110
+
111
+ Drag-and-drop JSONL/CSV files from unsupported tools, or upload API usage logs.
112
+
113
+ <img src="docs/screenshots/import.png" alt="Import & Upload" width="100%">
114
+
115
+ ### Settings
116
+
117
+ Theme toggle (dark/light), pricing freshness indicator, normalization rule editor, and sync controls.
118
+
119
+ <img src="docs/screenshots/settings.png" alt="Settings" width="100%">
120
+
121
+ ---
122
+
123
+ ## Supported AI Tools
124
+
125
+ | Tool | Integration | Type |
126
+ | ------ | ------------- | ------ |
127
+ | Claude Code | SessionEnd hook | Hook |
128
+ | Codex CLI | TOML notify | Hook |
129
+ | Gemini CLI | SessionEnd hook | Hook |
130
+ | CodeBuddy | SessionEnd hook | Hook |
131
+ | Every Code | TOML notify | Hook |
132
+ | OpenCode | Plugin + SQLite | Hook + Passive |
133
+ | Cursor | API + SQLite | Passive |
134
+ | Kiro | SQLite + JSONL | Passive |
135
+ | Hermes | SQLite | Passive |
136
+ | GitHub Copilot | OpenTelemetry | Passive |
137
+ | Kimi Code | JSONL reader | Passive |
138
+ | oh-my-pi | JSONL reader | Passive |
139
+ | Pi Coding Agent | JSONL reader | Passive |
140
+
141
+ ---
142
+
143
+ ## Commands
144
+
145
+ ### Core Commands
146
+
147
+ | Command | Description |
148
+ | --------- | ------------- |
149
+ | `tokentrax` | Open dashboard (alias for `serve`) |
150
+ | `tokentrax serve [--port N] [--no-browser]` | Start HTTP server on :7680 |
151
+ | `tokentrax init [--force] [--source NAME]` | Install hooks for detected AI tools |
152
+ | `tokentrax sync [--auto] [--source NAME]` | Parse logs → SQLite |
153
+ | `tokentrax sync-pricing` | Fetch latest model prices from OpenRouter |
154
+ | `tokentrax migrate-pricing` | Lock costs at current prices (one-time) |
155
+ | `tokentrax status [--verbose]` | Check hook configuration |
156
+ | `tokentrax doctor [--fix]` | Health check (DB, paths, hooks) |
157
+ | `tokentrax uninstall [--purge]` | Remove hooks, optionally delete all data |
158
+
159
+ ### Query Commands
160
+
161
+ | Command | Description |
162
+ | --------- | ------------- |
163
+ | `tokentrax costs [--days N] [--source NAME] [--json]` | Show cost summary |
164
+ | `tokentrax top [--limit N] [--days N] [--by model\|source]` | Top models/sources by usage |
165
+ | `tokentrax price [model] [--json]` | Look up model prices |
166
+ | `tokentrax export [--format csv\|json] [--days N] [--source NAME]` | Export usage data |
167
+
168
+ ---
169
+
170
+ ## Data & Privacy
171
+
172
+ All data stored in `~/.tokentrax/`:
173
+
174
+ | File | Purpose |
175
+ | ------ | --------- |
176
+ | `tokentrax.db` | SQLite database with token records |
177
+ | `pricing-cache.json` | Cached model prices (auto-refreshed) |
178
+ | `model-norm.json` | Custom model name normalization rules |
179
+ | `config.json` | User preferences (theme, timezone) |
180
+
181
+ ### Environment Variables
182
+
183
+ | Variable | Description | Default |
184
+ | ---------- | ------------- | --------- |
185
+ | `TOKENTRAX_DEBUG` | Enable debug output | — |
186
+ | `TOKENTRAX_HOME` | Override TokenTrax data directory | `~/.tokentrax` |
187
+ | `TOKENTRAX_CONFIG_PATH` | Override config file path | `~/.tokentrax/config.json` |
188
+ | `GEMINI_HOME` | Override Gemini config dir | `~/.gemini` |
189
+ | `CODEX_HOME` | Override Codex config dir | `~/.codex` |
190
+ | `CLAUDE_HOME` | Override Claude config dir | `~/.claude` |
191
+ | `CODEBUDDY_HOME` | Override Codebuddy config dir | `~/.codebuddy` |
192
+ | `EVERYCODE_HOME` | Override Everycode config dir | `~/.code` |
193
+ | `PI_CODING_AGENT_DIR` | Override Pi Coding Agent base directory | `~/.pi/agent` |
194
+ | `PI_CODING_AGENT_SESSION_DIR` | Override Pi sessions directory | `~/.pi/agent/sessions` |
195
+ | `COPILOT_OTEL_FILE_EXPORTER_PATH` | Override Copilot OTEL export directory | — |
196
+
197
+ ---
198
+
199
+ ## Privacy
200
+
201
+ - **No content uploaded** — only token counts and timestamps are stored
202
+ - **Local-only by default** — all data in `~/.tokentrax/tokentrax.db`
203
+ - **Auditable** — open source, read the parser code in `src/lib/parsers/`
204
+ - **No telemetry** — no analytics, no crash reporting, no phone-home
205
+
206
+ ---
207
+
208
+ ## Development
209
+
210
+ ```bash
211
+ git clone https://github.com/jeshuwah/TokenTrax.git
212
+ cd tokentrax
213
+ npm install
214
+ npm start # Run CLI
215
+ npm test # Run tests
216
+ ```
217
+
218
+ ### Project Structure
219
+
220
+ ```
221
+ tokentrax/
222
+ ├── bin/tracker.js # npm entry point
223
+ ├── src/
224
+ │ ├── cli.js # Command dispatcher
225
+ │ ├── commands/ # init, sync, serve, status, doctor, uninstall
226
+ │ └── lib/
227
+ │ ├── sqlite.js # DB schema + upsert logic
228
+ │ ├── pricing.js # Cost computation
229
+ │ └── parsers/ # One parser per AI tool (13 total)
230
+ ├── dashboard/
231
+ │ └── index.html # Single-file SPA dashboard
232
+ ├── docs/
233
+ │ ├── screenshots/ # Dashboard screenshots
234
+ │ └── IMPLEMENTATION.md # Architecture & design notes
235
+ ├── data/ # Bundled pricing seed data
236
+ └── tests/ # Test suite
237
+ ```
238
+
239
+ ---
240
+
241
+ ## Comparison: TokenTracker vs TokenTrax
242
+
243
+ | Metric | TokenTracker | TokenTrax |
244
+ | -------- | -------------- | ----------- |
245
+ | CLI LOC | ~8000 | ~2500 |
246
+ | Dashboard files | 146 | 1 |
247
+ | Runtime deps | 413 packages | 1 (better-sqlite3) |
248
+ | Storage | queue.jsonl | SQLite |
249
+ | Pricing | Live API + cache | Cached + auto-refresh |
250
+ | Build step | Vite + TypeScript | None |
251
+ | Dashboard size | ~2MB | ~10KB |
252
+
253
+ ---
254
+
255
+ ## Troubleshooting
256
+
257
+ ### Database locked
258
+
259
+ ```bash
260
+ pkill -f tokentrax # Kill any running server
261
+ rm ~/.tokentrax/tokentrax.db-wal
262
+ rm ~/.tokentrax/tokentrax.db-shm
263
+ ```
264
+
265
+ ### Hook not triggering
266
+
267
+ ```bash
268
+ tokentrax status # Check configuration
269
+ tokentrax uninstall
270
+ tokentrax init # Reinstall hooks
271
+ ```
272
+
273
+ ### Missing provider
274
+
275
+ 1. Verify the tool is installed (e.g., `claude --version`)
276
+ 2. Check the config file exists (e.g., `~/.claude/settings.json`)
277
+ 3. Run `tokentrax init --source <name>` to force installation
278
+
279
+ ---
280
+
281
+ ## License
282
+
283
+ [MIT](LICENSE)
284
+
285
+ ---
286
+
287
+ ## Credits
288
+
289
+ Inspired by [TokenTracker](https://github.com/mm7894215/TokenTracker). TokenTrax is a minimal reimplementation focused on local-only usage with zero bloat.
Binary file
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * tokentrax postinstall
4
+ *
5
+ * Runs automatically after `npm install` or `npm update`.
6
+ * Handles database migrations silently to ensure schema is up-to-date.
7
+ */
8
+ const { createDB } = require("../src/lib/sqlite");
9
+
10
+ try {
11
+ // Initialize DB (triggers schema migrations automatically)
12
+ const db = createDB();
13
+
14
+ // Check if there are any token rows without pricing
15
+ const unpricedCount = db.db
16
+ .prepare("SELECT COUNT(*) as cnt FROM tokens WHERE total_cost_usd IS NULL")
17
+ .get();
18
+
19
+ if (unpricedCount.cnt > 0) {
20
+ // Silently migrate pricing for existing rows
21
+ // This is safe to run multiple times - it only updates NULL values
22
+ const { getPricing, computeCost } = require("../src/lib/pricing");
23
+
24
+ const CHUNK = 1000;
25
+ const updateStmt = db.db.prepare(
26
+ "UPDATE tokens SET total_cost_usd = ? WHERE id = ? AND total_cost_usd IS NULL",
27
+ );
28
+
29
+ const migrate = db.db.transaction(() => {
30
+ let rowsUpdated;
31
+
32
+ do {
33
+ const rows = db.db
34
+ .prepare(`
35
+ SELECT id, hour_start, source, model, input_tokens, output_tokens,
36
+ cached_input_tokens, cache_creation_input_tokens,
37
+ reasoning_output_tokens, conversation_count
38
+ FROM tokens WHERE total_cost_usd IS NULL
39
+ LIMIT ?
40
+ `)
41
+ .all(CHUNK);
42
+
43
+ for (const row of rows) {
44
+ const pricing = getPricing(row.model);
45
+ const cost = computeCost(row, pricing);
46
+ updateStmt.run(cost, row.id);
47
+ }
48
+
49
+ rowsUpdated = rows.length;
50
+ } while (rowsUpdated === CHUNK);
51
+ });
52
+
53
+ migrate();
54
+ }
55
+
56
+ db.close();
57
+ } catch (err) {
58
+ // Non-fatal: log but don't fail install
59
+ console.error("tokentrax: postinstall warning:", err.message);
60
+ process.exit(0);
61
+ }
@@ -0,0 +1,38 @@
1
+ #!/bin/bash
2
+ set -e
3
+
4
+ PID_FILE="${TOKENTRAX_PID_FILE:-$HOME/.tokentrax/server.pid}"
5
+ PORT="${TOKENTRAX_PORT:-7680}"
6
+ # Default to localhost. Set TOKENTRAX_HOST=0.0.0.0 explicitly to expose on LAN.
7
+ # WARNING: exposing 0.0.0.0 without setting TOKENTRAX_SYNC_KEY leaves mutating
8
+ # endpoints (/api/upload, /api/settings, /api/agent-sync) unauthenticated.
9
+ HOST="${TOKENTRAX_HOST:-localhost}"
10
+
11
+ cd "$(dirname "$0")/.."
12
+
13
+ if [ -f "$PID_FILE" ]; then
14
+ OLD_PID=$(cat "$PID_FILE")
15
+ if kill -0 "$OLD_PID" 2>/dev/null; then
16
+ echo "Stopping existing server (PID $OLD_PID)..."
17
+ kill "$OLD_PID" 2>/dev/null || true
18
+ sleep 1
19
+ fi
20
+ rm -f "$PID_FILE"
21
+ fi
22
+
23
+ echo "Starting TokenTrax dashboard at http://$HOST:$PORT ..."
24
+
25
+ # Run node in the foreground so systemd (Type=simple) supervises the real
26
+ # server process instead of the exiting wrapper. Disable JOBCTL errexit
27
+ # just for the launch so a non-zero exit from the server itself still
28
+ # propagates through `exec` rather than being masked by `set -e`.
29
+ set +e
30
+ echo "$$" > "$PID_FILE"
31
+ echo "Server starting (wrapper PID $$, will exec node)"
32
+ # Print the address the server is actually bound to. This used to be hardcoded
33
+ # to localhost, which contradicted the line above whenever TOKENTRAX_HOST was
34
+ # set to a LAN or container address — the log advertised a URL that refused
35
+ # connections while the real one worked.
36
+ echo "Dashboard: http://$HOST:$PORT"
37
+ echo "PID saved to: $PID_FILE"
38
+ exec node bin/tracker.js serve --host "$HOST" --port "$PORT" --no-open
@@ -0,0 +1,18 @@
1
+ #!/bin/bash
2
+
3
+ PID_FILE="${TOKENTRAX_PID_FILE:-$HOME/.tokentrax/server.pid}"
4
+
5
+ if [ -f "$PID_FILE" ]; then
6
+ OLD_PID=$(cat "$PID_FILE")
7
+ if kill -0 "$OLD_PID" 2>/dev/null; then
8
+ echo "Stopping server (PID $OLD_PID)..."
9
+ kill "$OLD_PID"
10
+ rm -f "$PID_FILE"
11
+ echo "Server stopped"
12
+ else
13
+ echo "Server not running (stale PID file)"
14
+ rm -f "$PID_FILE"
15
+ fi
16
+ else
17
+ echo "No PID file found"
18
+ fi
package/bin/tracker.js ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ const { run } = require("../src/cli.js");
3
+
4
+ (async () => {
5
+ try {
6
+ await run(process.argv.slice(2));
7
+ } catch (err) {
8
+ console.error("tokentrax:", err.message);
9
+ process.exit(1);
10
+ }
11
+ })();