@vimoxshah/tokenflow 1.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/CONTRIBUTING.md +84 -0
- package/LICENSE +21 -0
- package/README.md +250 -0
- package/Refresh & Open Dashboard.command +22 -0
- package/SECURITY.md +42 -0
- package/bin/tokenflow.js +1342 -0
- package/docs/architecture.md +193 -0
- package/docs/cli.md +390 -0
- package/docs/configuration.md +281 -0
- package/docs/creating-provider.md +262 -0
- package/docs/data-model.md +213 -0
- package/docs/getting-started.md +266 -0
- package/docs/live-mode.md +199 -0
- package/docs/media/architecture-hero.svg +86 -0
- package/docs/media/cost-editorial-dark.png +0 -0
- package/docs/media/health-terminal-light.png +0 -0
- package/docs/media/menubar-dark.png +0 -0
- package/docs/media/menubar-light.png +0 -0
- package/docs/media/models-terminal-dark.png +0 -0
- package/docs/media/overview-aurora-dark.png +0 -0
- package/docs/media/time-aurora-light.png +0 -0
- package/docs/providers.md +309 -0
- package/docs/skill.md +64 -0
- package/docs/troubleshooting.md +207 -0
- package/examples/config.example.yaml +92 -0
- package/examples/demo-data/README.md +38 -0
- package/examples/demo-data/sample-usage.csv +11 -0
- package/package.json +74 -0
- package/scripts/build-dmg.sh +33 -0
- package/scripts/build-menubar-app.sh +67 -0
- package/scripts/lint.js +111 -0
- package/scripts/validate-install.js +140 -0
- package/skills/tokenflow/SKILL.md +392 -0
- package/skills/tokenflow/examples/config.yaml +92 -0
- package/skills/tokenflow/examples/generic-mapping.json +26 -0
- package/skills/tokenflow/examples/session-transcript.md +191 -0
- package/skills/tokenflow/providers/adapter-template.js +135 -0
- package/skills/tokenflow/providers/detection-matrix.md +142 -0
- package/skills/tokenflow/schemas/config.schema.json +107 -0
- package/skills/tokenflow/schemas/normalized-record.json +63 -0
- package/src/analytics/aggregate.js +247 -0
- package/src/analytics/anomalies.js +222 -0
- package/src/analytics/capacity.js +278 -0
- package/src/analytics/comparison.js +96 -0
- package/src/analytics/dimensions.js +230 -0
- package/src/analytics/efficiency.js +138 -0
- package/src/analytics/forecast.js +202 -0
- package/src/analytics/index.js +327 -0
- package/src/analytics/insights.js +283 -0
- package/src/analytics/milestones.js +91 -0
- package/src/analytics/peak.js +106 -0
- package/src/analytics/productivity.js +166 -0
- package/src/analytics/token-usage.js +267 -0
- package/src/commands/diagnostics.js +88 -0
- package/src/commands/digest.js +155 -0
- package/src/commands/models-compare.js +96 -0
- package/src/core/budget.js +142 -0
- package/src/core/bundle.js +191 -0
- package/src/core/config.js +202 -0
- package/src/core/delivery.js +109 -0
- package/src/core/geo.js +99 -0
- package/src/core/ingest.js +457 -0
- package/src/core/interface-map.js +55 -0
- package/src/core/jsonl.js +124 -0
- package/src/core/live-status.js +417 -0
- package/src/core/model-map.js +157 -0
- package/src/core/notify.js +83 -0
- package/src/core/pricing.js +288 -0
- package/src/core/prompt-analytics.js +127 -0
- package/src/core/registry.js +107 -0
- package/src/core/restore.js +261 -0
- package/src/core/schedule.js +120 -0
- package/src/core/schema.js +316 -0
- package/src/core/sqlite.js +96 -0
- package/src/core/store.js +493 -0
- package/src/core/sync.js +151 -0
- package/src/core/units.js +147 -0
- package/src/core/validate.js +123 -0
- package/src/core/watch.js +287 -0
- package/src/core/yaml.js +209 -0
- package/src/export/bundler.js +107 -0
- package/src/export/csv.js +100 -0
- package/src/export/html-snapshot.js +101 -0
- package/src/export/menubar.js +158 -0
- package/src/index.js +18 -0
- package/src/providers/anthropic/index.js +294 -0
- package/src/providers/cline/index.js +120 -0
- package/src/providers/cursor/index.js +143 -0
- package/src/providers/generic/index.js +268 -0
- package/src/providers/git/index.js +188 -0
- package/src/providers/headroom/index.js +114 -0
- package/src/providers/hermes/index.js +299 -0
- package/src/providers/mock/index.js +117 -0
- package/src/providers/openai/index.js +370 -0
- package/src/providers/opencode/index.js +245 -0
- package/src/sdk.js +46 -0
- package/src/server/server.js +264 -0
- package/src/ui/app.js +2473 -0
- package/src/ui/charts.js +925 -0
- package/src/ui/index.html +42 -0
- package/src/ui/styles.css +644 -0
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thanks for looking. This project has an unusual set of constraints, and they are the reason it
|
|
4
|
+
works — please read this section before opening a PR.
|
|
5
|
+
|
|
6
|
+
## The five invariants
|
|
7
|
+
|
|
8
|
+
These are not style preferences. A change that breaks one of them makes the dashboard lie, which
|
|
9
|
+
is worse than a dashboard that is missing a feature.
|
|
10
|
+
|
|
11
|
+
1. **Missing is not zero.** Every token field is `number | null`. `null` means the source did not
|
|
12
|
+
report it; `0` means the source reported zero. They are different facts and they stay
|
|
13
|
+
different all the way through: schema → cube (`naIn`/`naOut`/…) → UI badge → CSV empty cell.
|
|
14
|
+
Never write `?? 0` on a token field.
|
|
15
|
+
2. **Measured and estimated never mix.** A cost from a gateway's billing log is evidence. A cost
|
|
16
|
+
from a price table is arithmetic. They are separate fields, separate KPIs, separately labelled.
|
|
17
|
+
3. **A streamed usage block is a snapshot, not an increment.** Several tools re-report a running
|
|
18
|
+
total per chunk. Summing them inflates by 3–45×. Adapters take the maximum of a monotonic run
|
|
19
|
+
per logical unit — there are regression tests for exactly this, do not "simplify" them.
|
|
20
|
+
4. **Tokens are not productivity.** The Productivity tab shows *activity proxies* and labels
|
|
21
|
+
correlations as correlations. No feature may imply that spending more tokens is doing more work.
|
|
22
|
+
5. **Nothing leaves the machine.** No network calls in ingest, analytics, or the UI. The server
|
|
23
|
+
binds to loopback. Prompts, conversations and source code are never read into the store —
|
|
24
|
+
only counts, identifiers and timestamps.
|
|
25
|
+
|
|
26
|
+
There is a sixth, softer one: **no runtime dependencies**. Node 22.5+ gives us `node:sqlite`,
|
|
27
|
+
`node:test` and everything else we need. A PR that adds a dependency needs a very good story.
|
|
28
|
+
|
|
29
|
+
## Getting set up
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
git clone <repo> && cd tokenflow
|
|
33
|
+
npm run demo -- --no-serve # synthetic data, no real logs needed
|
|
34
|
+
npm start # refresh + snapshot + open the dashboard
|
|
35
|
+
npm test && npm run lint
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
There is no build step and no `npm install` (there is nothing to install). The browser imports
|
|
39
|
+
the same ES modules the CLI runs.
|
|
40
|
+
|
|
41
|
+
Type-checking is the one exception. `jsconfig.json` runs `checkJs`, which needs `typescript` and
|
|
42
|
+
`@types/node` — both dev-only, so they are fetched on demand instead of being committed to
|
|
43
|
+
`package.json`:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npm run typecheck:deps # once per clone: installs into node_modules, saves nothing
|
|
47
|
+
npm run typecheck # must report zero errors
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
CI does the same two steps. A fresh clone has no `node_modules`, so `npm run typecheck` on its own
|
|
51
|
+
will fail until you have run `typecheck:deps`.
|
|
52
|
+
|
|
53
|
+
## Writing an adapter
|
|
54
|
+
|
|
55
|
+
An adapter is ~80 lines and lives in `src/providers/<id>/index.js`. It parses; the engine does
|
|
56
|
+
classification, timezones, pricing, dedup, shard writes and rollups. See
|
|
57
|
+
[`docs/creating-provider.md`](docs/creating-provider.md) for the full walkthrough, and
|
|
58
|
+
`src/providers/mock/` for the simplest complete example.
|
|
59
|
+
|
|
60
|
+
Every adapter PR needs:
|
|
61
|
+
|
|
62
|
+
- a **fixture** in `test/fixtures/` — a handful of redacted lines, not a real transcript
|
|
63
|
+
- a test that asserts the normalized records, including **one record with a missing field** that
|
|
64
|
+
must come out `null`
|
|
65
|
+
- `detect()` returning a useful `detail` string when the source is absent (it is shown in the UI)
|
|
66
|
+
|
|
67
|
+
## Tests
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
npm test # 101 tests, no network, no fixtures larger than a few KB
|
|
71
|
+
node --test test/store.test.js # one file
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Tests that encode a *bug we already fixed* are the most valuable thing in the suite. If you fix
|
|
75
|
+
something subtle, leave a test with a comment explaining what went wrong.
|
|
76
|
+
|
|
77
|
+
## Reporting an issue
|
|
78
|
+
|
|
79
|
+
Please do not paste raw session logs, prompts, or code. `tokenflow doctor` plus a description is
|
|
80
|
+
almost always enough.
|
|
81
|
+
|
|
82
|
+
## Code of conduct
|
|
83
|
+
|
|
84
|
+
By participating you agree to the [Code of Conduct](CODE_OF_CONDUCT.md).
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Vimox Shah and Tokenflow contributors
|
|
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
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
<h1 align="center">TokenFlow</h1>
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<strong>See where your AI tokens actually go.</strong><br>
|
|
5
|
+
Local-first analytics for tokens spent across Claude Code, Codex, OpenCode, Cline,
|
|
6
|
+
Cursor, Hermes — or anything you can point it at.
|
|
7
|
+
</p>
|
|
8
|
+
|
|
9
|
+

|
|
10
|
+

|
|
11
|
+

|
|
12
|
+

|
|
13
|
+
|
|
14
|
+

|
|
15
|
+
|
|
16
|
+
<p align="center">
|
|
17
|
+
<img src="docs/media/architecture-hero.svg" alt="TokenFlow architecture: local logs → engine → dashboard, menu bar, CLI" width="100%">
|
|
18
|
+
</p>
|
|
19
|
+
|
|
20
|
+
<p align="center">
|
|
21
|
+
<img src="docs/media/menubar-light.png" width="30%" alt="TokenFlow menu bar popover — light">
|
|
22
|
+
|
|
23
|
+
<img src="docs/media/menubar-dark.png" width="30%" alt="TokenFlow menu bar popover — dark">
|
|
24
|
+
</p>
|
|
25
|
+
<p align="center"><em>The native macOS menu bar popover — live cost, tokens, per-provider,
|
|
26
|
+
per-source and per-model usage, capacity meters and forecast, in light and dark.</em></p>
|
|
27
|
+
|
|
28
|
+
**How deep it goes**
|
|
29
|
+
|
|
30
|
+
| Layer | What's inside |
|
|
31
|
+
|---|---|
|
|
32
|
+
| **Ingestion** | 10 adapters (Anthropic, OpenAI/Codex, OpenCode, Hermes, Cline, Cursor, Headroom gateway, git, generic CSV/JSONL/SQLite import, demo). Incremental byte-offset resumes, re-read windows for upserted rows, budgeted refresh that stops cleanly mid-corpus |
|
|
33
|
+
| **Correctness** | Cache read/write/input kept as mutually exclusive buckets; vendor convention differences handled; streaming re-reports collapsed to max-of-run; `null` never coerced to 0; measured gateway cost kept separate from estimates |
|
|
34
|
+
| **Costing** | Versioned price table with per-entry source URLs and fetch dates; service-tier multipliers; long-TTL cache-write tier priced separately; unpriced models surface as `null` with a configure action — never silent `$0` |
|
|
35
|
+
| **Analytics** | 12 views: overview KPIs, composition, provider/model intelligence, interfaces, hour×weekday heatmap + calendar, peaks, efficiency ratios, cost with coverage, git correlations (labelled), period compare, searchable data explorer, per-field data health |
|
|
36
|
+
| **Live mode** | Watcher daemon, native Swift menu bar app (provider/source/model breakdowns, capacity meters with reset countdowns & ETAs, forecast with stated confidence, MAD-based anomaly alerts, appearance toggle), SwiftBar/xbar plugin |
|
|
37
|
+
| **Engineering** | Zero runtime dependencies · 145 tests · lint invariants (e.g. "no `\|\| 0` on a token field") · tsc-clean JSDoc types · CI on macOS/Linux/Windows × Node 22/24 |
|
|
38
|
+
|
|
39
|
+
Zero runtime dependencies. Nothing leaves your machine. No API keys, no accounts, no telemetry.
|
|
40
|
+
|
|
41
|
+
### Install
|
|
42
|
+
|
|
43
|
+
**macOS app** — download `TokenFlow-*.dmg` from the
|
|
44
|
+
[**latest release**](https://github.com/vimoxshah/tokenflow/releases/latest) (each release also
|
|
45
|
+
carries `tokenflow-dashboard-demo.html`, an offline demo dashboard that opens in any browser).
|
|
46
|
+
Open the DMG, drag **TokenFlow.app** to Applications, launch from Launchpad.
|
|
47
|
+
|
|
48
|
+
> The build is unsigned (no Apple Developer account), so macOS blocks the first launch. This is
|
|
49
|
+
> expected and one-time only:
|
|
50
|
+
> 1. Open **System Settings → Privacy & Security** → scroll to **Security**.
|
|
51
|
+
> 2. Click **Open Anyway** next to the "TokenFlow was blocked" message.
|
|
52
|
+
> 3. Confirm **Open**.
|
|
53
|
+
>
|
|
54
|
+
> Alternatively right-click the app → **Open** → **Open**.
|
|
55
|
+
|
|
56
|
+
Then click the menu bar item → **Run setup**, which detects your installed tools and writes
|
|
57
|
+
`~/.tokenflow/config.yaml`. The watcher refreshes every two minutes after that.
|
|
58
|
+
|
|
59
|
+
**From source** (macOS, Linux, Windows — needs Node 22.5+, nothing else):
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
git clone https://github.com/vimoxshah/tokenflow.git && cd tokenflow
|
|
63
|
+
npm run setup # detect Claude Code, Codex, OpenCode, Cursor, Cline…
|
|
64
|
+
npm start # ingest what's new, then open the dashboard
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
No `npm run install` needed — zero dependencies. If nothing is detected, `node bin/tokenflow.js
|
|
68
|
+
providers` tells you what it looked for and where.
|
|
69
|
+
|
|
70
|
+
Just want a look first? `npm run demo` generates clearly-labelled synthetic data and opens the
|
|
71
|
+
dashboard.
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## What it does
|
|
76
|
+
|
|
77
|
+
| Question | Where |
|
|
78
|
+
|---|---|
|
|
79
|
+
| How much AI did I use, and how has that changed? | Overview — KPIs, daily series, trend |
|
|
80
|
+
| Input vs output vs cache? | Token composition — four buckets that sum to the total |
|
|
81
|
+
| Which provider and model do I rely on? | Provider & model share, growth, per-model efficiency |
|
|
82
|
+
| When do I use AI most? | Time patterns — hour/weekday profiles, heatmap, calendar |
|
|
83
|
+
| What does it cost? | Cost — estimated from a versioned price table with stated coverage |
|
|
84
|
+
| Does usage track shipped work? | Productivity — correlations with git activity, labelled as correlations |
|
|
85
|
+
| What changed between two periods? | Compare — any two windows, metric by metric |
|
|
86
|
+
| Can I trust these numbers? | Data health — per-field availability, per-adapter coverage |
|
|
87
|
+
|
|
88
|
+
<details>
|
|
89
|
+
<summary>All pages</summary>
|
|
90
|
+
|
|
91
|
+
Overview · Token composition · Providers & models · Interfaces · Time patterns · Peaks ·
|
|
92
|
+
Efficiency · Cost · Productivity · Compare · Data explorer (searchable/sortable/exportable) ·
|
|
93
|
+
Data health
|
|
94
|
+
|
|
95
|
+
</details>
|
|
96
|
+
|
|
97
|
+
*Every screenshot uses `npm run demo` data, which the UI labels as synthetic.*
|
|
98
|
+
|
|
99
|
+
## Supported sources
|
|
100
|
+
|
|
101
|
+
| Adapter | Source | Reports |
|
|
102
|
+
|---|---|---|
|
|
103
|
+
| `anthropic` | `~/.claude*/projects/**/*.jsonl` | per-request input, output, cache read/write, thinking |
|
|
104
|
+
| `openai` | `~/.codex/sessions/**/*.jsonl` | per-turn fresh/cached input, cache write, output, reasoning |
|
|
105
|
+
| `opencode` | opencode.db (XDG data dir) | per-request fresh input, cache read/write, output |
|
|
106
|
+
| `hermes` | `~/.hermes/state.db` | per-session-per-model tokens, measured cost when recorded |
|
|
107
|
+
| `cline` | `~/.cline/data/sessions/**` | sessions + model only — this source has no token counts |
|
|
108
|
+
| `cursor` | cursor ai-code-tracking db | AI-authored edits per commit |
|
|
109
|
+
| `headroom` | `~/.headroom/savings_events.jsonl` | measured cost + compression delta from a local gateway (overlay) |
|
|
110
|
+
| `git` | any repository | commits, churn — independent work signal |
|
|
111
|
+
| `generic` | CSV / TSV / JSON / JSONL / SQLite | anything via a saved field mapping |
|
|
112
|
+
| `mock` | — | deterministic demo data, always labelled |
|
|
113
|
+
|
|
114
|
+
New adapters drop into `src/providers/<id>/index.js` or `$TOKENFLOW_HOME/providers/*.js`; new
|
|
115
|
+
providers and models appear in every chart automatically. See [docs/providers.md](docs/providers.md).
|
|
116
|
+
|
|
117
|
+
## Correctness guarantees
|
|
118
|
+
|
|
119
|
+
The parts most token dashboards get wrong:
|
|
120
|
+
|
|
121
|
+
- **Cache tokens are not input tokens.** Fresh input, `cache_read`, `cache_write` and output are
|
|
122
|
+
mutually exclusive and sum to the total; long-TTL refreshes and reasoning are subsets, never
|
|
123
|
+
added again.
|
|
124
|
+
- **Vendors disagree on `input_tokens`.** Anthropic excludes cache; OpenAI includes cached input.
|
|
125
|
+
The OpenAI adapter subtracts so nothing counts twice.
|
|
126
|
+
- **Streaming logs re-report usage.** Summing them inflates totals badly (on our test corpus, ~45x
|
|
127
|
+
for Codex). Adapters take the maximum of each monotonic run instead.
|
|
128
|
+
- **Missing ≠ zero.** Unknown token fields are `null`, never coerced to `0`; sums skip nulls and
|
|
129
|
+
report coverage.
|
|
130
|
+
- **Overlay measurements don't inflate totals.** Gateway/proxy records describe traffic another
|
|
131
|
+
adapter already counted; they're excluded by default and used only for measured-cost cross-checks.
|
|
132
|
+
- **No invented prices.** Unpriced models show `null` cost and are listed for configuration — never
|
|
133
|
+
silently `$0`.
|
|
134
|
+
|
|
135
|
+
## Refresh model
|
|
136
|
+
|
|
137
|
+
Transcripts are append-only, so the store tracks each file's `{size, mtime, offset}`: unchanged
|
|
138
|
+
files are skipped entirely, grown files resume at their byte offset, rewrites are superseded and
|
|
139
|
+
compacted. On a real 1.5 GB / 5,110-file corpus: ~15 s first ingest, ~2 s no-op refresh.
|
|
140
|
+
`refresh --budget 30` stops cleanly on a file boundary and resumes later — big ingests fit inside
|
|
141
|
+
CI steps or browser requests.
|
|
142
|
+
|
|
143
|
+
## CLI
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
node bin/tokenflow.js setup # detect tools, write ~/.tokenflow/config.yaml
|
|
147
|
+
node bin/tokenflow.js refresh # incremental ingest (--full re-reads everything)
|
|
148
|
+
node bin/tokenflow.js status # current numbers, same modules the dashboard calls
|
|
149
|
+
node bin/tokenflow.js providers # what was detected, where
|
|
150
|
+
node bin/tokenflow.js dashboard # live UI at http://127.0.0.1:7799 (loopback only)
|
|
151
|
+
node bin/tokenflow.js watch # auto-refresh every N seconds (default 120)
|
|
152
|
+
node bin/tokenflow.js import f.csv # CSV/JSONL/SQLite via saved field mapping
|
|
153
|
+
node bin/tokenflow.js export --csv # --all for everything; --html for offline snapshot
|
|
154
|
+
node bin/tokenflow.js digest # shareable markdown summary (--format text, --from/--to, --out f.md)
|
|
155
|
+
node bin/tokenflow.js models-compare # cost/usage efficiency per model — your data
|
|
156
|
+
node bin/tokenflow.js budget --set 200 # monthly cap + forecast alerts (fires once per state/month)
|
|
157
|
+
node bin/tokenflow.js schedule --install --at "Monday 09:00" # weekly digest via launchd
|
|
158
|
+
node bin/tokenflow.js diagnostics # local observability — nothing transmitted
|
|
159
|
+
node bin/tokenflow.js up # refresh → rebuild offline HTML → serve + open
|
|
160
|
+
|
|
161
|
+
npm link # optional: global `tokenflow` command
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Every command is documented in [docs/cli.md](docs/cli.md); every config field in
|
|
165
|
+
[docs/configuration.md](docs/configuration.md).
|
|
166
|
+
|
|
167
|
+
## Menu bar app (macOS)
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
node bin/tokenflow.js menubar --app # builds & launches the native app
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
A small native Swift app compiled on your machine (no Electron): status item shows spend today or
|
|
174
|
+
limit pressure (`▲ 82%`, `✗ 105%`), with a dropdown covering today/week/month, per-provider rows,
|
|
175
|
+
per-source and per-model usage, capacity meters with reset countdowns, forecast, anomaly alerts,
|
|
176
|
+
and an appearance toggle (system → light → dark, persisted)
|
|
177
|
+
([light](docs/media/menubar-light.png) / [dark](docs/media/menubar-dark.png)). Declare caps yourself:
|
|
178
|
+
|
|
179
|
+
```yaml
|
|
180
|
+
limits:
|
|
181
|
+
- id: anthropic-monthly
|
|
182
|
+
provider: anthropic
|
|
183
|
+
scope: month
|
|
184
|
+
metric: tokens # or cost / requests / input / output
|
|
185
|
+
cap: 120000000
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Quotas exist because you declared them — none are invented. Details:
|
|
189
|
+
[docs/live-mode.md](docs/live-mode.md). SwiftBar users: `menubar --swiftbar --out <dir>`.
|
|
190
|
+
|
|
191
|
+
## Themes & export
|
|
192
|
+
|
|
193
|
+
Three skins (Aurora default, Terminal, Editorial) × dark/light, persisted via `ui.skin` /
|
|
194
|
+
`ui.mode`. Series colours belong to the mode, not the skin, validated for colour-blind separation —
|
|
195
|
+
switching themes never changes what a colour means.
|
|
196
|
+
|
|
197
|
+
`export --html` produces one self-contained offline file (CSS + analytics + data inline) that opens
|
|
198
|
+
from `file://` with no server. A full CSV export doubles as a portable dataset:
|
|
199
|
+
`tokenflow restore <file>.csv --yes` rebuilds a store on another machine without the raw vendor logs.
|
|
200
|
+
|
|
201
|
+
## Contributing
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
npm test # 102 tests: normalization, adapters, analytics, store, formatting
|
|
205
|
+
npm run lint # project invariants (incl. "no || 0 on a token field")
|
|
206
|
+
npm run typecheck # tsc over JSDoc types — must be zero errors
|
|
207
|
+
npm run validate # self-check: runtime, adapters, store↔cube agreement
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Read [CONTRIBUTING.md](CONTRIBUTING.md) first — it states the five invariants that keep this honest
|
|
211
|
+
(missing is not zero; measured and estimated never mix; a streamed usage block is a snapshot;
|
|
212
|
+
tokens are not productivity; nothing leaves the machine).
|
|
213
|
+
|
|
214
|
+
Easiest contribution: an adapter (`src/providers/<id>/index.js`) plus a fixture under
|
|
215
|
+
`test/fixtures/`, stating in its header comment what each vendor field means.
|
|
216
|
+
|
|
217
|
+
## Documentation
|
|
218
|
+
|
|
219
|
+
- [getting-started.md](docs/getting-started.md) — install to first dashboard
|
|
220
|
+
- [live-mode.md](docs/live-mode.md) — watcher, menu bar, capacity, forecasts
|
|
221
|
+
- [configuration.md](docs/configuration.md) — every config field
|
|
222
|
+
- [providers.md](docs/providers.md) — every adapter, what it reads
|
|
223
|
+
- [data-model.md](docs/data-model.md) — schema and token accounting rules
|
|
224
|
+
- [creating-provider.md](docs/creating-provider.md) — the adapter contract
|
|
225
|
+
- [cli.md](docs/cli.md) — every command and flag
|
|
226
|
+
- [architecture.md](docs/architecture.md) — layers and plugin points
|
|
227
|
+
- [troubleshooting.md](docs/troubleshooting.md) — when the numbers look wrong
|
|
228
|
+
|
|
229
|
+
## Privacy & security
|
|
230
|
+
|
|
231
|
+
Local data → local normalization → local analytics → local dashboard. The server binds to
|
|
232
|
+
`127.0.0.1`. No prompt text, code, or file content is ever stored — adapters read token counts and
|
|
233
|
+
discard the rest. No telemetry. Two features can touch the network, both strictly opt-in:
|
|
234
|
+
|
|
235
|
+
- **Digest delivery** (`delivery:` in config) — sends the digest you generate to your own
|
|
236
|
+
Telegram chat, email, or webhook. Credentials live only in `~/.tokenflow/config.yaml`.
|
|
237
|
+
- **Multi-machine sync** (`sync:` in config) — exchanges daily totals (date, tokens, requests,
|
|
238
|
+
est. cost) with a folder you own (iCloud/Dropbox/Syncthing). Never prompts, code, credentials.
|
|
239
|
+
Default is OFF; nothing leaves this machine until you set `sync.enabled: true`.
|
|
240
|
+
- **Prompt analytics** (`promptAnalytics:` in config) — OFF by default; even when enabled, only
|
|
241
|
+
one-way prompt hashes and keyword categories are stored. Raw text requires a separate opt-in.
|
|
242
|
+
- **Map location** (`map.showMyLocation: true`) — one cached IP geolocation of this machine to
|
|
243
|
+
place "you" on the Global activity map. The IP itself is never stored.
|
|
244
|
+
|
|
245
|
+
Everything lives in `~/.tokenflow/`.
|
|
246
|
+
[SECURITY.md](SECURITY.md) covers the threat model and private vulnerability reporting.
|
|
247
|
+
|
|
248
|
+
## License
|
|
249
|
+
|
|
250
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Double-click me.
|
|
3
|
+
#
|
|
4
|
+
# Brings your AI usage data up to date, rebuilds the offline HTML file, then
|
|
5
|
+
# opens the live dashboard in your browser. Everything runs on this machine;
|
|
6
|
+
# nothing is uploaded. Close the Terminal window (or press Ctrl+C) to stop the
|
|
7
|
+
# local server.
|
|
8
|
+
cd "$(dirname "$0")" || exit 1
|
|
9
|
+
if ! command -v node >/dev/null 2>&1; then
|
|
10
|
+
echo "Node.js 22.5+ is required and was not found on PATH."
|
|
11
|
+
echo "Install it from https://nodejs.org, then double-click this file again."
|
|
12
|
+
read -r -p "Press return to close." _
|
|
13
|
+
exit 1
|
|
14
|
+
fi
|
|
15
|
+
export TOKENFLOW_HOME="${TOKENFLOW_HOME:-$PWD/.tokenflow}"
|
|
16
|
+
node bin/tokenflow.js up "$@"
|
|
17
|
+
status=$?
|
|
18
|
+
if [ $status -ne 0 ]; then
|
|
19
|
+
echo
|
|
20
|
+
echo "Exited with status $status."
|
|
21
|
+
read -r -p "Press return to close." _
|
|
22
|
+
fi
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Security & privacy
|
|
2
|
+
|
|
3
|
+
## The privacy model, stated plainly
|
|
4
|
+
|
|
5
|
+
This tool reads local files that AI coding tools already write, extracts **counts, identifiers
|
|
6
|
+
and timestamps**, and stores them in a local directory. It does not read, store or transmit
|
|
7
|
+
prompts, completions, conversations, or source code.
|
|
8
|
+
|
|
9
|
+
- **No network calls** in ingest, analytics, or the UI. Not for pricing (the price table is a
|
|
10
|
+
committed file), not for telemetry (there is none), not for updates.
|
|
11
|
+
- The dashboard server binds to **127.0.0.1** and requires a token for any state-changing
|
|
12
|
+
request. The one CORS-open endpoint, `GET /api/ping`, returns a liveness flag, the port, a
|
|
13
|
+
record count and a timestamp — nothing else.
|
|
14
|
+
- All data lives under `~/.tokenflow` (or `$TOKENFLOW_HOME`). Deleting that directory
|
|
15
|
+
deletes everything the tool knows.
|
|
16
|
+
- A CSV or HTML export contains your usage counts and identifiers such as session ids, project
|
|
17
|
+
paths and repository names. Treat an export as you would treat a build log — it is not
|
|
18
|
+
prompt content, but it does describe your work. `tokenflow export --csv` is the one operation
|
|
19
|
+
that can move data off the machine, and only because you chose where to put the file.
|
|
20
|
+
|
|
21
|
+
Verify any of this yourself: `grep -rn "fetch\|https\?://" src/` — the only matches in the
|
|
22
|
+
ingest and analytics path are in this documentation and in the browser's calls to its own
|
|
23
|
+
loopback server.
|
|
24
|
+
|
|
25
|
+
## Reporting a vulnerability
|
|
26
|
+
|
|
27
|
+
Please **do not** open a public issue for a security problem. Instead:
|
|
28
|
+
|
|
29
|
+
1. Open a GitHub security advisory (Security → Report a vulnerability), or
|
|
30
|
+
2. Contact a maintainer privately.
|
|
31
|
+
|
|
32
|
+
Include what an attacker could do, and a minimal reproduction. We will acknowledge, investigate,
|
|
33
|
+
and credit you in the fix unless you prefer otherwise.
|
|
34
|
+
|
|
35
|
+
## Threat model, briefly
|
|
36
|
+
|
|
37
|
+
In scope: anything that could cause the tool to exfiltrate data, execute untrusted content from
|
|
38
|
+
a log file, escape the data directory when writing, or let another origin in the same browser
|
|
39
|
+
read or mutate your data through the local server.
|
|
40
|
+
|
|
41
|
+
Out of scope: an attacker who already has read access to your home directory (they can read the
|
|
42
|
+
AI tools' logs directly, which are the input to this tool).
|