nomnomtokens 0.4.0 → 0.6.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 (120) hide show
  1. package/README.md +50 -27
  2. package/dist/index.js +1207 -129
  3. package/dist/index.js.map +1 -1
  4. package/package.json +1 -1
  5. package/web/nitro.json +1 -1
  6. package/web/public/_nuxt/AuWqCQTg.js +1 -0
  7. package/web/public/_nuxt/{W3KL_OjU.js → B1SHP0x7.js} +1 -1
  8. package/web/public/_nuxt/{DQEnwY-5.js → B4lg_KdO.js} +1 -1
  9. package/web/public/_nuxt/B8pNcdCn.js +1 -0
  10. package/web/public/_nuxt/{COwSpxrx.js → BL80uXr2.js} +1 -1
  11. package/web/public/_nuxt/{B2aHje2L.js → BOu13FsZ.js} +1 -1
  12. package/web/public/_nuxt/{CvIugsJe2.js → BYf03To42.js} +1 -1
  13. package/web/public/_nuxt/{CkRZsevx.js → B_fydnl_.js} +1 -1
  14. package/web/public/_nuxt/{DnTwjl0_2.js → BboXpc0v2.js} +2 -2
  15. package/web/public/_nuxt/{CfBMjq8x.js → Bg-w_mbM.js} +1 -1
  16. package/web/public/_nuxt/{B1jhn8zK.js → BsIJiDwC.js} +1 -1
  17. package/web/public/_nuxt/BsfWsX6E.js +1 -0
  18. package/web/public/_nuxt/{C9MiT_Wm.js → BuKW47N9.js} +2 -2
  19. package/web/public/_nuxt/{4C_a23zt.js → BvB3OU0z.js} +1 -1
  20. package/web/public/_nuxt/CLdT3CQk.js +1 -0
  21. package/web/public/_nuxt/{D9j6aFUy.js → Car0xtsn.js} +1 -1
  22. package/web/public/_nuxt/Ch1ysvEi.js +1 -0
  23. package/web/public/_nuxt/{BOKlFKrX.js → Ck5ddq-9.js} +1 -1
  24. package/web/public/_nuxt/{Cq1Sq3Go.js → CsVo4EXo.js} +1 -1
  25. package/web/public/_nuxt/CzaLG4_B2.js +1 -0
  26. package/web/public/_nuxt/{C51OzH6V.js → D9MZNmok.js} +1 -1
  27. package/web/public/_nuxt/{D9Mxq5ER.js → DQ6vgNw-.js} +1 -1
  28. package/web/public/_nuxt/{D49wVVwm2.js → DZ0oUjlX2.js} +1 -1
  29. package/web/public/_nuxt/DbTv-m36.js +1 -0
  30. package/web/public/_nuxt/{D4C6J8YV.js → DdHo_MGy.js} +1 -1
  31. package/web/public/_nuxt/{m3-Vaz25.js → DmteO8Ul.js} +1 -1
  32. package/web/public/_nuxt/DyoXCutE.js +1 -0
  33. package/web/public/_nuxt/{DPnm6zS2.js → DyvBBld_2.js} +1 -1
  34. package/web/public/_nuxt/{CIKwfDBl.js → PaV2v2OF.js} +1 -1
  35. package/web/public/_nuxt/{BMSLzLlT.js → RjmsMzM7.js} +1 -1
  36. package/web/public/_nuxt/builds/latest.json +1 -1
  37. package/web/public/_nuxt/builds/meta/fe9c123e-ca03-4d26-9bfd-e56ed456cf65.json +1 -0
  38. package/web/public/_nuxt/entry.CE8-9Sal.css +2 -0
  39. package/web/public/_nuxt/{Dy30RUCD2.js → hPGLTkZo2.js} +1 -1
  40. package/web/public/_nuxt/{Bprokln-.js → jeqgGzjf.js} +1 -1
  41. package/web/public/_nuxt/n29w62AT.js +1 -0
  42. package/web/public/_nuxt/{CDzUujek.js → tShBBc0S.js} +2 -2
  43. package/web/server/chunks/_/filters.mjs +1 -0
  44. package/web/server/chunks/_/filters.mjs.map +1 -1
  45. package/web/server/chunks/build/AuditCard-CgGiEb_r.mjs +290 -0
  46. package/web/server/chunks/build/AuditCard-CgGiEb_r.mjs.map +1 -0
  47. package/web/server/chunks/build/{CardContent-C_IMqI8K.mjs → CardDescription-Bi5t5iXj.mjs} +30 -30
  48. package/web/server/chunks/build/CardDescription-Bi5t5iXj.mjs.map +1 -0
  49. package/web/server/chunks/build/{FilterBar-BlEsJ5dy.mjs → FilterBar-BYBOdTrl.mjs} +2 -2
  50. package/web/server/chunks/build/{FilterBar-BlEsJ5dy.mjs.map → FilterBar-BYBOdTrl.mjs.map} +1 -1
  51. package/web/server/chunks/build/{Sparkline-CaCRq45J.mjs → Sparkline-B3kazZhU.mjs} +2 -2
  52. package/web/server/chunks/build/{Sparkline-CaCRq45J.mjs.map → Sparkline-B3kazZhU.mjs.map} +1 -1
  53. package/web/server/chunks/build/{_id_-BvccBwzH.mjs → _id_-DPUt6OzN.mjs} +4 -4
  54. package/web/server/chunks/build/{_id_-BvccBwzH.mjs.map → _id_-DPUt6OzN.mjs.map} +1 -1
  55. package/web/server/chunks/build/asyncData-CMa0z9Yw.mjs +2 -2
  56. package/web/server/chunks/build/audit-BPAlwhzn.mjs +1180 -0
  57. package/web/server/chunks/build/audit-BPAlwhzn.mjs.map +1 -0
  58. package/web/server/chunks/build/{default-BokiYQNv.mjs → default-CvQF0-O_.mjs} +46 -22
  59. package/web/server/chunks/build/default-CvQF0-O_.mjs.map +1 -0
  60. package/web/server/chunks/build/export-CwC19yOz.mjs +232 -0
  61. package/web/server/chunks/build/export-CwC19yOz.mjs.map +1 -0
  62. package/web/server/chunks/build/fetch-DJ9NNbFP.mjs +1 -1
  63. package/web/server/chunks/build/{import-CO3NEu0P.mjs → import-BmoVtcGR.mjs} +31 -15
  64. package/web/server/chunks/build/import-BmoVtcGR.mjs.map +1 -0
  65. package/web/server/chunks/build/{limits-CX9zBSqw.mjs → limits-C21_a18j.mjs} +5 -5
  66. package/web/server/chunks/build/{limits-CX9zBSqw.mjs.map → limits-C21_a18j.mjs.map} +1 -1
  67. package/web/server/chunks/build/nuxt-link-mYiLFsJs.mjs +2 -2
  68. package/web/server/chunks/build/{pages-DyXqJyPq.mjs → pages-CJpczmoA.mjs} +81 -11
  69. package/web/server/chunks/build/pages-CJpczmoA.mjs.map +1 -0
  70. package/web/server/chunks/build/{providers-Ca7keu2G.mjs → providers-BBVw9CDb.mjs} +4 -4
  71. package/web/server/chunks/build/{providers-Ca7keu2G.mjs.map → providers-BBVw9CDb.mjs.map} +1 -1
  72. package/web/server/chunks/build/{scopes-E5z80S19.mjs → scopes-DpYnOAM9.mjs} +203 -62
  73. package/web/server/chunks/build/scopes-DpYnOAM9.mjs.map +1 -0
  74. package/web/server/chunks/build/{sessions-CESRiCOS.mjs → sessions-B-Y_ifp1.mjs} +5 -5
  75. package/web/server/chunks/build/{sessions-CESRiCOS.mjs.map → sessions-B-Y_ifp1.mjs.map} +1 -1
  76. package/web/server/chunks/build/{timeline-d27OlbZN.mjs → timeline-8kK28WQB.mjs} +5 -5
  77. package/web/server/chunks/build/{timeline-d27OlbZN.mjs.map → timeline-8kK28WQB.mjs.map} +1 -1
  78. package/web/server/chunks/build/useFormat-NkyUqeik.mjs +1 -1
  79. package/web/server/chunks/build/{useStats-CmYzpdbE.mjs → useStats-BQQJIKQO.mjs} +7 -5
  80. package/web/server/chunks/build/{useStats-CmYzpdbE.mjs.map → useStats-BQQJIKQO.mjs.map} +1 -1
  81. package/web/server/chunks/nitro/nitro.mjs +695 -217
  82. package/web/server/chunks/nitro/nitro.mjs.map +1 -1
  83. package/web/server/chunks/routes/api/export.get.mjs +22 -3
  84. package/web/server/chunks/routes/api/export.get.mjs.map +1 -1
  85. package/web/server/chunks/routes/api/import/csv.post.mjs +20 -6
  86. package/web/server/chunks/routes/api/import/csv.post.mjs.map +1 -1
  87. package/web/server/chunks/routes/api/ingest.post.mjs +1 -1
  88. package/web/server/chunks/routes/api/meta.get.mjs +1 -1
  89. package/web/server/chunks/routes/api/scopes/_hash_.patch.mjs +35 -0
  90. package/web/server/chunks/routes/api/scopes/_hash_.patch.mjs.map +1 -0
  91. package/web/server/chunks/routes/api/stats/audit.get.mjs +60 -0
  92. package/web/server/chunks/routes/api/stats/audit.get.mjs.map +1 -0
  93. package/web/server/chunks/routes/api/stats/limits.get.mjs +1 -1
  94. package/web/server/chunks/routes/api/stats/providers.get.mjs +1 -1
  95. package/web/server/chunks/routes/api/stats/scopes.get.mjs +1 -1
  96. package/web/server/chunks/routes/api/stats/session/_id_.get.mjs +1 -1
  97. package/web/server/chunks/routes/api/stats/summary.get.mjs +1 -1
  98. package/web/server/chunks/routes/api/stats/verdict.get.mjs +35 -0
  99. package/web/server/chunks/routes/api/stats/verdict.get.mjs.map +1 -0
  100. package/web/server/chunks/routes/renderer.mjs +2 -2
  101. package/web/server/chunks/virtual/entry.mjs +17 -12
  102. package/web/server/chunks/virtual/precomputed.mjs +1 -1
  103. package/web/server/chunks/virtual/precomputed.mjs.map +1 -1
  104. package/web/server/index.mjs +1 -1
  105. package/web/public/_nuxt/Bia8fJFj.js +0 -1
  106. package/web/public/_nuxt/CIHIOSzn.js +0 -1
  107. package/web/public/_nuxt/CZSbzIi-.js +0 -1
  108. package/web/public/_nuxt/DMgad8mU.js +0 -1
  109. package/web/public/_nuxt/DhJW7zb9.js +0 -1
  110. package/web/public/_nuxt/OU1MVgXQ.js +0 -1
  111. package/web/public/_nuxt/builds/meta/b80e2306-16ec-4868-89f8-b713594d0c00.json +0 -1
  112. package/web/public/_nuxt/cbxnBwm6.js +0 -1
  113. package/web/public/_nuxt/entry.MbqNBIeH.css +0 -2
  114. package/web/server/chunks/build/CardContent-C_IMqI8K.mjs.map +0 -1
  115. package/web/server/chunks/build/default-BokiYQNv.mjs.map +0 -1
  116. package/web/server/chunks/build/export-BhfwmSMl.mjs +0 -184
  117. package/web/server/chunks/build/export-BhfwmSMl.mjs.map +0 -1
  118. package/web/server/chunks/build/import-CO3NEu0P.mjs.map +0 -1
  119. package/web/server/chunks/build/pages-DyXqJyPq.mjs.map +0 -1
  120. package/web/server/chunks/build/scopes-E5z80S19.mjs.map +0 -1
package/README.md CHANGED
@@ -1,10 +1,11 @@
1
1
  # nomnomtokens
2
2
 
3
- > nom nom nom — your agent is eating tokens. The dashboard shows exactly how many.
3
+ > nom nom nom — your agents are eating tokens. One local store shows where.
4
4
 
5
- A local-first dashboard for AI coding agent spend. Run one command and a
6
- dashboard opens in your browser: how much your agent ate today, on which
7
- projects, and when you'll hit your limit.
5
+ A local-first dashboard for AI coding agent spend across Claude Code, Codex,
6
+ and Cursor. Run one command and a dashboard opens in your browser: how much
7
+ went today, on which projects and models, how much of that was cache or
8
+ subagents, and when you'll hit your limit.
8
9
 
9
10
  ```sh
10
11
  npx nomnomtokens
@@ -14,21 +15,27 @@ npx nomnomtokens
14
15
 
15
16
  ![nomnomtokens Timeline — spend stacked by model and activity heatmap](docs/timeline.png)
16
17
 
17
- Claude Code, Cursor (when its local IDE database has token fields), and Codex
18
- CLI/IDE session rollouts. The event contract is deliberately not AI-shaped, so
19
- other agents — and eventually CI minutes and cloud bills — plug in as adapters
20
- without touching the core.
18
+ One store for Claude Code, Codex CLI/IDE session rollouts, and Cursor (when its
19
+ local IDE database has token fields). The point is not another total — it is
20
+ history you can filter and audit: model mix, cache vs fresh tokens, and
21
+ subagent share where the transcript marks it. The event contract is deliberately
22
+ not AI-shaped, so other agents — and eventually CI minutes and cloud bills —
23
+ plug in as adapters without touching the core.
21
24
 
22
25
  ## What you get
23
26
 
24
- - **Overview** — eaten today / this week / this month, with a limits widget that
25
- projects when you'll hit the cap at your current burn rate.
27
+ - **Overview** — eaten today / this week / this month, a limits widget that
28
+ projects when you'll hit the cap, a **Where it went** card (cache hit,
29
+ subagent share, model mix, tips), and a **Verdict** when weekly limit
30
+ snapshots exist.
31
+ - **Audit** — the full report: models, top sessions, cold resumes, tips. Same
32
+ numbers as `nnt audit`.
26
33
  - **Timeline** — spend over time stacked by model, plus an hour×weekday heatmap
27
34
  of when you actually work.
28
35
  - **Projects** — per-project cost with trend against the preceding period. Click
29
- a row to filter every screen. This is the one that lets a freelancer bill a
30
- client.
31
- - **Providers** — cache hit rate and cost per 1,000 changed lines.
36
+ a row to filter every screen; expand a row to tag a client for invoices.
37
+ - **Providers** — per-agent and per-model breakdown: cache hit rate and cost per
38
+ 1,000 changed lines.
32
39
  - **Sessions** — every conversation, drilling into how the bill accumulated.
33
40
  - **Limits** — window-fill history with a burn-rate projection and markers for
34
41
  the moments you actually hit the cap.
@@ -54,12 +61,18 @@ live updates.
54
61
  The hook doubles as a real status line:
55
62
 
56
63
  ```
57
- (^u^) $4.20 ctx 37% 5h 73% ·1h47m 7d 41% ·4d3h 138 lines
64
+ Limits: 7d 81% 4d3h | 5h 73% 1h47m | ctx. 37% | Opus 4.6
58
65
  ```
59
66
 
60
- The countdown after each window is the time left until it resets: the
61
- percentage tells you whether to slow down, the countdown tells you what slowing
62
- down would cost. It is omitted when Claude Code sends no `resets_at`.
67
+ The labels `7d`, `5h`, and `ctx`, and the session model name, are cyan; the
68
+ figures stay the default colour. The model is Claude's `display_name` for
69
+ whatever is selected in this session. The countdown after each percentage is
70
+ the time left until that
71
+ window resets. It is omitted when there is no `resets_at`. If this render's
72
+ payload has no `rate_limits` yet — typical before the first request of a
73
+ session — the last stored snapshot is shown instead, as long as that window
74
+ has not reset. If Claude's week is nearly full and a recent Codex snapshot
75
+ in the store still has headroom, a `codex: N%` segment is appended.
63
76
 
64
77
  ## Commands
65
78
 
@@ -70,16 +83,22 @@ down would cost. It is omitted when Claude Code sends no `resets_at`.
70
83
  | `nnt serve [--port]` | open the dashboard |
71
84
  | `nnt init [--force]` | wire up the status line hook |
72
85
  | `nnt statusline` | ingest a session payload and print a status line |
73
- | `nnt doctor` | why is it empty? checks sources, hook, and store |
74
- | `nnt import <file.csv>` | import a billing CSV into the local store |
75
- | `nnt export` | dump filtered events as CSV/JSON |
86
+ | `nnt doctor` | why is it empty? checks sources, hook, store, and transcript wipe |
87
+ | `nnt import <file>` | billing CSV or nnt archive JSON into the local store |
88
+ | `nnt export` | dump filtered events as CSV/JSON, or `--format nnt` for a portable store |
76
89
  | `nnt prices [show\|refresh]` | local model price table (`~/.nomnomtokens/prices.json`) |
77
90
  | `nnt alerts [show\|check]` | limit % / daily $ thresholds (`~/.nomnomtokens/alerts.json`) |
91
+ | `nnt audit [--days] [--json]` | where spend went: cache, subagents, models, cold resumes, tips |
92
+ | `nnt verdict [--json]` | which Claude plan weekly fill actually needs (dated estimates) |
93
+ | `nnt weigh [--json]` | weekly limit points per list-price dollar, when one model owns the gap |
94
+ | `nnt otel --endpoint <url>` | opt-in OTLP/HTTP JSON export of numbers and hashes |
78
95
 
79
96
  ## Privacy
80
97
 
81
- Your data never leaves your machine. No account, no telemetry, no network calls
82
- at all — not even a font or a CDN script.
98
+ Your data never leaves your machine unless you opt in. No account, no telemetry.
99
+ The dashboard makes no outbound calls — not even a font or a CDN script. The
100
+ only network is explicit: `nnt prices refresh --from`, alert webhooks, and
101
+ `nnt otel --endpoint`.
83
102
 
84
103
  The event type has nowhere to put a prompt, a diff, or a path:
85
104
 
@@ -145,9 +164,11 @@ the core, the contract is wrong and that's a bug worth reporting.
145
164
 
146
165
  ## Roadmap
147
166
 
148
- Shipped: Claude Code / Cursor / Codex adapters, CSV import & export, Projects
149
- grouped by name, local `prices.json` refresh, limit/daily alerts, all dashboard
150
- screens, limits with forecasting, live updates.
167
+ Shipped: Claude Code / Cursor / Codex adapters, CSV and nnt-archive import &
168
+ export, Projects grouped by name with optional client tags, local `prices.json`
169
+ refresh, limit/daily alerts, all dashboard screens including `/audit`, limits
170
+ with forecasting, live updates, Overview audit + verdict, `nnt audit` /
171
+ `nnt verdict`, and opt-in `nnt otel`.
151
172
 
152
173
  Cursor caveat: the IDE often stores zero token counts in local bubbles. We only
153
174
  emit events when numbers are present (exact `tokenCount`, or
@@ -155,8 +176,10 @@ emit events when numbers are present (exact `tokenCount`, or
155
176
  local counts will not appear until Cursor writes them — or until you import a
156
177
  billing CSV.
157
178
 
158
- Next: OTLP receiver, then cloud mode — a second sink for the same events, never
159
- a rewrite, and never in the critical path.
179
+ Next: a desktop window and menu bar around the same local store. Cloud mode
180
+ stays a later second sink for the same events, never a rewrite, and never in
181
+ the critical path. An OTLP *receiver* is not on the roadmap — `nnt otel`
182
+ exports into Grafana/Datadog you already run.
160
183
 
161
184
  ## License
162
185