tokenflexing 1.1.0 → 1.2.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 (3) hide show
  1. package/README.md +155 -86
  2. package/package.json +1 -1
  3. package/src/cli.js +119 -16
package/README.md CHANGED
@@ -1,138 +1,207 @@
1
- # tokenflex
1
+ # tokenflexing
2
2
 
3
- Show off your AI token usage. Universal CLI for Claude Code, Codex, Cursor, and more.
3
+ > Show off your AI token usage. Universal CLI for Claude Code, Codex, Cursor, OpenCode, and 20+ other AI tools.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/tokenflexing.svg?color=ff6f00)](https://www.npmjs.com/package/tokenflexing)
6
+ [![npm downloads](https://img.shields.io/npm/dm/tokenflexing.svg)](https://www.npmjs.com/package/tokenflexing)
7
+ [![Node](https://img.shields.io/badge/node-%E2%89%A518-43853d?logo=node.js)](https://nodejs.org)
8
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](#license)
4
9
 
5
10
  ```bash
6
- npx tokenflex@latest scan
11
+ npx tokenflexing@latest scan
7
12
  ```
8
13
 
9
- Scans your entire device for AI tool usage data, extracts token counts where possible, and shows everything else it detected. **Never reads prompts or completions — only usage/token blocks.**
14
+ `tokenflexing` is a pure-local scanner that finds every AI coding tool on your machine, extracts token counts and cost where the data is parseable, and surfaces the rest as "detected but no telemetry yet". It never reads your prompts or model completions — only the usage/token blocks already written to disk by the tools themselves.
10
15
 
11
- ## Commands
16
+ It also ships an [MCP server](https://modelcontextprotocol.io), a `login`/`sync` pair for pushing snapshots to your [tokenflexing.com](https://tokenflexing.com) profile, and an `--install` flag that wires a daily auto-refresh into `launchd` (macOS) or Task Scheduler (Windows).
12
17
 
13
- | Command | What |
14
- |---|---|
15
- | `tokenflex` / `tokenflex stats` | Today / 7-day / 30-day / all-time dollar + token spend per source, per model |
16
- | `tokenflex scan` | Universal device inventory — measured, detected, and not-found in one view |
17
- | `tokenflex flex` | Shareable ASCII card — drop in tweets, HN comments, or Slack |
18
- | `tokenflex daemon` | Preview the daily auto-refresh LaunchAgent (macOS) or Task Scheduler entry (Windows) |
19
- | `tokenflex daemon --install` | Install the daemon (runs `tokenflex scan` at 6:00 AM daily) |
20
- | `tokenflex daemon --uninstall` | Remove the daemon |
21
- | `tokenflex mcp` | Start MCP server — Claude Code, Cursor, and any MCP-capable agent can call tokenflex tools natively |
22
- | `tokenflex install-hooks --apply` | Register tokenflex as an MCP server in Claude Code or Cursor settings |
23
- | `tokenflex --help` | Usage |
24
-
25
- ## What `tokenflex scan` detects
26
-
27
- | Tool | Status |
28
- |---|---|
29
- | **Claude Code** | ✅ Token counts + cost extracted (`~/.claude/projects/**/*.jsonl`) |
30
- | **Codex CLI** | ✅ Token counts + cost extracted (`~/.codex/sessions/**/*.jsonl`) |
31
- | **Cursor** | 🔍 Detected — SQLite `state.vscdb` reader planned |
32
- | **Claude Desktop** | 🔍 Detected — Electron, no token events exposed |
33
- | **ChatGPT Desktop** | 🔍 Detected — Electron, conversation data only |
34
- | **Windsurf (Codeium)** | 🔍 Detected — structured token log not exposed yet |
35
- | **Continue.dev** | 🔍 Detected — telemetry parser planned |
36
- | **Aider** | 🔍 Detected — cost-line parser planned |
37
- | **Cline** | 🔍 Detected — `ui_messages.json` task parser planned |
38
- | **Roo Code** | 🔍 Detected — `ui_messages.json` task parser planned |
39
- | **Kilo Code** | 🔍 Detected — `ui_messages.json` task parser planned |
40
- | **Zed AI** | 🔍 Detected — SQLite `threads.db` reader planned |
41
- | **Gemini CLI** | 🔍 Detected — `~/.gemini/tmp/*.jsonl` parser planned |
42
- | **OpenCode** | 🔍 Detected — `opencode/storage/message/*.json` parser planned |
43
- | **Amp** | 🔍 Detected — `amp/threads/T-*.json` parser planned |
44
- | **Antigravity (Google)** | 🔍 Detected — session cache format TBD |
45
- | **GitHub Copilot** | 🔍 Detected — OTEL trace extraction planned |
46
- | **Goose (Block)** | 🔍 Detected — SQLite `sessions.db` reader planned |
47
- | **Kiro (Amazon)** | 🔍 Detected — `~/.kiro/sessions/cli/*.json` parser planned |
48
- | **Mux** | 🔍 Detected — `session-usage.json` parser planned |
49
- | **OpenClaw** | 🔍 Detected — JSONL agent sessions parser planned |
50
- | **Crush** | 🔍 Detected — `projects.json` parser planned |
51
- | **Kimi (Moonshot)** | 🔍 Detected — `wire.jsonl` parser planned |
52
- | **Hermes** | 🔍 Detected — SQLite `state.db` reader planned |
53
-
54
- macOS, Windows, and Linux (XDG) paths covered.
18
+ ---
55
19
 
56
- ## Why local files?
20
+ ## Contents
21
+
22
+ - [Install](#install)
23
+ - [Commands](#commands)
24
+ - [What `scan` detects](#what-scan-detects)
25
+ - [Cloud sync](#cloud-sync)
26
+ - [MCP server](#mcp-server)
27
+ - [Daily auto-refresh](#daily-auto-refresh)
28
+ - [Privacy](#privacy)
29
+ - [Why local files?](#why-local-files)
30
+ - [Changelog](#changelog)
31
+ - [License](#license)
57
32
 
58
- Provider Admin APIs (Anthropic / OpenAI) require **organization admin** keys that individual developers don't have. Local session JSONL files contain per-turn usage data for **anyone** using Claude Code or Codex CLI on any plan — no org key needed.
33
+ ---
59
34
 
60
35
  ## Install
61
36
 
62
37
  ```bash
63
- # one-shot
64
- npx tokenflex@latest stats
38
+ # one-shot, no install
39
+ npx tokenflexing@latest scan
65
40
 
66
41
  # or install globally
67
- npm install -g tokenflex
68
- tokenflex scan
42
+ npm install -g tokenflexing
43
+ tokenflexing scan
69
44
  ```
70
45
 
71
- Requires Node ≥ 18.
46
+ Requires **Node ≥ 18**. Works on macOS, Windows, and Linux (XDG paths).
72
47
 
73
- ## MCP Server (agent-native access)
48
+ ---
74
49
 
75
- Register tokenflex as an MCP server so Claude Code, Cursor, and any MCP-capable agent can query your stats inline:
50
+ ## Commands
76
51
 
77
- ```bash
78
- # Dry-run — shows what will be written
79
- npx tokenflex@latest install-hooks
52
+ | Command | What it does |
53
+ |---|---|
54
+ | `tokenflexing` *(default)* | Today / 7-day / 30-day / all-time dollar + token totals. |
55
+ | `tokenflexing stats` | Same as above, with a per-model breakdown for every source. |
56
+ | `tokenflexing scan` | Full device inventory — measured, detected, and not-found tools side by side. |
57
+ | `tokenflexing flex` | Shareable ASCII card for X, HN, or Slack. |
58
+ | `tokenflexing login` | Browser-based pairing with your tokenflexing.com account. |
59
+ | `tokenflexing login --token <tok>` | Skip the browser flow — paste a token from tokenflexing.com/settings. |
60
+ | `tokenflexing sync` | Push current local stats to your public profile. |
61
+ | `tokenflexing mcp` | Start the MCP stdio server. |
62
+ | `tokenflexing install-hooks --apply` | Register `tokenflexing` as an MCP server in Claude Code (default) or Cursor (`--client cursor`). |
63
+ | `tokenflexing daemon` | Preview the daily-refresh LaunchAgent / Task Scheduler entry. |
64
+ | `tokenflexing daemon --install` | Install it (runs `tokenflexing scan` at 6:00 AM daily via `npx`). |
65
+ | `tokenflexing daemon --uninstall` | Remove the daemon. |
66
+ | `tokenflexing --version` | Print the installed version. |
67
+ | `tokenflexing --help` | Full usage. |
68
+
69
+ ---
70
+
71
+ ## What `scan` detects
72
+
73
+ ### Fully measured (token counts + cost extracted)
74
+
75
+ | Tool | Source |
76
+ |---|---|
77
+ | **Claude Code** | `~/.claude/projects/**/*.jsonl` |
78
+ | **Codex CLI** | `~/.codex/sessions/**/*.jsonl` |
79
+ | **OpenCode** | `~/.local/share/opencode/opencode.db` (when sessions exist) |
80
+
81
+ ### Detected (presence + path, telemetry parser in progress)
80
82
 
81
- # Write MCP entry to ~/.claude/settings.json (Claude Code)
82
- npx tokenflex@latest install-hooks --apply
83
+ Cursor · Claude Desktop · ChatGPT Desktop · Windsurf · Continue.dev · Aider · Cline · Roo Code · Kilo Code · Zed AI · Gemini CLI · Amp · Antigravity (Google) · GitHub Copilot · Goose (Block) · Kiro (Amazon) · Mux · OpenClaw · Crush · Kimi (Moonshot) · Hermes
83
84
 
84
- # Write to ~/.cursor/mcp.json (Cursor)
85
- npx tokenflex@latest install-hooks --client cursor --apply
85
+ Cursor is intentionally turn-count only because Cursor is subscription-based and stores no per-message token data locally.
86
86
 
87
- # Project-local (writes to .claude/settings.json in current dir)
88
- npx tokenflex@latest install-hooks --apply --project
87
+ ---
88
+
89
+ ## Cloud sync
90
+
91
+ ```bash
92
+ # one-time browser login — opens https://tokenflexing.com/cli-auth
93
+ npx tokenflexing@latest login
94
+
95
+ # push your local stats to your public profile + the global leaderboard
96
+ npx tokenflexing@latest sync
89
97
  ```
90
98
 
91
- After restarting your editor, your agent gets three new tools:
99
+ The token is stored at `~/.config/tokenflexing/token` (or `%APPDATA%/tokenflexing/token` on Windows). You only log in once; the token persists across reboots and only needs to be re-issued if you revoke it from [tokenflexing.com/settings](https://tokenflexing.com/settings).
92
100
 
93
- | Tool | What it does |
94
- |---|---|
95
- | `get_my_stats` | Token spend by period and model |
96
- | `get_device_scan` | Which AI tools are installed + measured |
97
- | `get_flex_card` | Shareable one-liner for X / HN / Slack |
101
+ `sync` reads the same data that `scan` produces and POSTs a snapshot per source to `/api/sync/device`. The web app stores it in the `device_stats` table keyed by `(user_id, source)`, and the dashboard surfaces rows from every device you've paired — so usage from your laptop, desktop, and CI box all roll up into one profile.
98
102
 
99
- Or run the MCP server directly (for custom integrations):
103
+ ---
104
+
105
+ ## MCP server
106
+
107
+ Make your AI agent self-aware about how much it costs to run. Register `tokenflexing` as an MCP server in Claude Code, Cursor, or any other [MCP-capable](https://modelcontextprotocol.io) client:
100
108
 
101
109
  ```bash
102
- npx tokenflex@latest mcp
110
+ # preview what will be written (no changes yet)
111
+ npx tokenflexing@latest install-hooks
112
+
113
+ # Claude Code: writes to ~/.claude/settings.json
114
+ npx tokenflexing@latest install-hooks --apply
115
+
116
+ # Cursor: writes to ~/.cursor/mcp.json
117
+ npx tokenflexing@latest install-hooks --client cursor --apply
118
+
119
+ # project-local: writes to .claude/settings.json in the current directory
120
+ npx tokenflexing@latest install-hooks --apply --project
103
121
  ```
104
122
 
105
- MCP entry format for manual config:
123
+ After restarting your editor, your agent has three new tools:
124
+
125
+ | Tool | Use it when the user asks |
126
+ |---|---|
127
+ | `get_my_stats` | "How much did I burn on AI this week?" |
128
+ | `get_device_scan` | "Which AI tools do I have installed?" |
129
+ | `get_flex_card` | "Show me a card I can post." |
130
+
131
+ Manual MCP config (if you prefer editing JSON):
106
132
 
107
133
  ```json
108
134
  {
109
135
  "mcpServers": {
110
- "tokenflex": { "command": "npx", "args": ["-y", "tokenflex@latest", "mcp"], "type": "stdio" }
136
+ "tokenflexing": {
137
+ "command": "npx",
138
+ "args": ["-y", "tokenflexing@latest", "mcp"],
139
+ "type": "stdio"
140
+ }
111
141
  }
112
142
  }
113
143
  ```
114
144
 
145
+ Or run the server directly for custom integrations:
146
+
147
+ ```bash
148
+ npx tokenflexing@latest mcp
149
+ ```
150
+
151
+ ---
152
+
115
153
  ## Daily auto-refresh
116
154
 
117
155
  ```bash
118
- # macOS: installs a LaunchAgent that runs tokenflex scan at 6 AM
119
- tokenflex daemon --install
156
+ # macOS: installs a LaunchAgent at ~/Library/LaunchAgents/com.tokenflexing.sync.plist
157
+ tokenflexing daemon --install
120
158
 
121
- # Windows: creates a Task Scheduler entry
122
- tokenflex daemon --install
159
+ # Windows: creates a Task Scheduler entry "Tokenflexing Sync"
160
+ tokenflexing daemon --install
123
161
 
124
- # Remove
125
- tokenflex daemon --uninstall
162
+ # remove it on either platform
163
+ tokenflexing daemon --uninstall
126
164
  ```
127
165
 
128
- Cloud sync (`tokenflex login` push to tokenflexing.com profile) ships in v0.3.
166
+ The scheduled job invokes `npx tokenflexing@latest scan` rather than a hard-coded local path, so it keeps working across upgrades, across `node` versions, and on machines that don't have the package installed globally. Logs land at `/tmp/tokenflexing-sync.log` on macOS / Linux.
167
+
168
+ ---
129
169
 
130
170
  ## Privacy
131
171
 
132
- - No network calls. Pure local read.
133
- - Only usage blocks (token counts, model ids) are parsed — never message content.
134
- - `tokenflex daemon` logs to `/tmp/tokenflex-sync.log` only.
172
+ - **No network calls** during `scan`, `stats`, or `flex` — pure local read.
173
+ - `login` and `sync` only contact `tokenflexing.com`.
174
+ - Only **usage blocks** (token counts, model ids, timestamps) are parsed — never message content, never prompts, never completions.
175
+ - The MCP server returns only the same aggregated numbers; it never reads your conversation history.
176
+ - The daemon logs to `/tmp/tokenflexing-sync.log` and nowhere else.
177
+
178
+ ---
179
+
180
+ ## Why local files?
181
+
182
+ Provider Admin APIs (Anthropic, OpenAI) require **organization admin** keys that individual developers don't have. From the Anthropic docs verbatim: *"The Admin API is unavailable for individual accounts."* OpenAI: *"Only Organization Owners can create and use Admin API keys."*
183
+
184
+ Local session JSONL and SQLite files contain per-turn usage data for **anyone** running Claude Code, Codex CLI, or OpenCode — on any plan, with no org key required. That's why `scan` parses files first and only falls back to API connectors when you explicitly add one.
185
+
186
+ ---
187
+
188
+ ## Changelog
189
+
190
+ ### 1.1.0 — 2026-05-17
191
+
192
+ - Renamed package from `tokenflex` to `tokenflexing` (the original name was taken on npm).
193
+ - **Fixed daemon path bug**: the LaunchAgent / Task Scheduler plist used to embed the developer's local file path resolved from `import.meta.url`, which never existed for end users. The plist now invokes `npx tokenflexing@latest scan`, derived from the same directory as `process.execPath` so it works on any host.
194
+ - Cloud sync (`login` + `sync`) promoted from "ships in v0.3" to live.
195
+ - OpenCode SQLite reader added; Cursor detection reports turn counts (Cursor is subscription-based).
196
+ - Config directory moved from `~/.config/tokenflex` to `~/.config/tokenflexing`.
197
+ - All help text, log messages, and MCP entry names updated to the new binary.
198
+
199
+ ### 0.3.0 — 2026-05-16
200
+
201
+ Initial preview release as `tokenflex` (now superseded by `tokenflexing@1.1.0`).
202
+
203
+ ---
135
204
 
136
205
  ## License
137
206
 
138
- MIT
207
+ MIT © 2026 Khadin Akbar
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tokenflexing",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Show off your AI token usage. CLI for Claude Code, Codex, Cursor, OpenCode and more.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/cli.js CHANGED
@@ -11,8 +11,9 @@ import {
11
11
  import { join, dirname } from "node:path";
12
12
  import { homedir, userInfo } from "node:os";
13
13
  import { execFileSync } from "node:child_process";
14
- // node:readline used for interactive prompts in commandLogin
15
- import { createInterface } from "node:readline";
14
+ // commandLogin currently uses browser-based polling rather than interactive
15
+ // stdin, so node:readline is intentionally not imported. Re-add if/when we
16
+ // reintroduce an interactive `--token` prompt fallback.
16
17
 
17
18
  /* ───── Platform ───────────────────────────────────────────────── */
18
19
 
@@ -459,7 +460,7 @@ function commandMcp() {
459
460
  function handle(req) {
460
461
  const { method, id, params } = req;
461
462
  if (method === "initialize") {
462
- send({ jsonrpc: "2.0", id, result: { protocolVersion: "2024-11-05", capabilities: { tools: {} }, serverInfo: { name: "tokenflexing", version: "1.1.0" } } });
463
+ send({ jsonrpc: "2.0", id, result: { protocolVersion: "2024-11-05", capabilities: { tools: {} }, serverInfo: { name: "tokenflexing", version: "1.2.0" } } });
463
464
  } else if (method === "notifications/initialized" || method === "ping") {
464
465
  if (id !== undefined) send({ jsonrpc: "2.0", id, result: {} });
465
466
  } else if (method === "tools/list") {
@@ -919,23 +920,39 @@ async function commandSync() {
919
920
  console.log(`${c.bold}tokenflexing sync${c.reset}`);
920
921
  console.log("");
921
922
 
922
- // Collect parsed source data
923
- const sources = collectSources();
923
+ // Collect every detected source (measured + detection-only). Detection-only
924
+ // rows ship with zero counts and `detected: true` so the dashboard knows
925
+ // the tool is installed even though we can't measure its tokens yet.
926
+ const sources = collectAllSources();
924
927
  if (!sources.length) {
925
- console.log(`${c.faint}Nothing to sync — no parseable sources found.${c.reset}`);
928
+ console.log(`${c.faint}Nothing to sync — no AI tools detected on this device.${c.reset}`);
926
929
  console.log("");
927
930
  return;
928
931
  }
929
932
 
930
- const scans = sources.map((s) => ({
931
- source: s.id,
932
- events: s.stats.events,
933
- input: s.stats.input,
934
- output: s.stats.output,
935
- cached: s.stats.cached,
936
- cost: s.stats.cost,
937
- models: Object.fromEntries(s.stats.models),
938
- }));
933
+ const scans = sources.map((s) => {
934
+ if (s.detected) {
935
+ return {
936
+ source: s.id,
937
+ detected: true,
938
+ events: 0,
939
+ input: 0,
940
+ output: 0,
941
+ cached: 0,
942
+ cost: 0,
943
+ models: {},
944
+ };
945
+ }
946
+ return {
947
+ source: s.id,
948
+ events: s.stats.events,
949
+ input: s.stats.input,
950
+ output: s.stats.output,
951
+ cached: s.stats.cached,
952
+ cost: s.stats.cost,
953
+ models: Object.fromEntries(s.stats.models),
954
+ };
955
+ });
939
956
 
940
957
  let res;
941
958
  try {
@@ -967,12 +984,97 @@ function collectSources() {
967
984
  .map((r) => ({ id: r.id, name: r.name, stats: r.stats }));
968
985
  }
969
986
 
970
- function commandVersion() { console.log("1.1.0"); }
987
+ /**
988
+ * Return every source the scan touched: measured (with token data) AND
989
+ * detection-only (presence confirmed but no usage parser yet). Detection-only
990
+ * entries get zero counts and a `detected: true` flag so the web dashboard can
991
+ * surface them as "installed, telemetry coming" rows instead of silently
992
+ * dropping them.
993
+ */
994
+ function collectAllSources() {
995
+ return runScan()
996
+ .filter((r) => r.found)
997
+ .map((r) => ({
998
+ id: r.id,
999
+ name: r.name,
1000
+ detected: !r.hasData,
1001
+ stats: r.hasData ? r.stats : null,
1002
+ }));
1003
+ }
1004
+
1005
+ /**
1006
+ * `tokenflexing connect` — the one-command onboarding flow.
1007
+ * Bundles scan + login (if needed) + sync + a friendly nudge to install the
1008
+ * daily-refresh daemon. Targeted at first-time users who don't want to read
1009
+ * the full command reference.
1010
+ */
1011
+ async function commandConnect() {
1012
+ console.log("");
1013
+ console.log(`${c.bold}tokenflexing connect${c.reset} ${c.faint}— one-command setup${c.reset}`);
1014
+ console.log("");
1015
+
1016
+ // ── Step 1: scan ────────────────────────────────────────────────
1017
+ console.log(`${c.faint}Step 1/3 · Scanning this machine for AI tools…${c.reset}`);
1018
+ const scan = runScan();
1019
+ const measured = scan.filter((r) => r.hasData);
1020
+ const detected = scan.filter((r) => r.found && !r.hasData);
1021
+
1022
+ if (!measured.length && !detected.length) {
1023
+ console.log("");
1024
+ console.log(`${c.faint}No AI tools detected on this device.${c.reset}`);
1025
+ console.log(`${c.faint}Install Claude Code, Codex CLI, Cursor, OpenCode, Antigravity,${c.reset}`);
1026
+ console.log(`${c.faint}Windsurf, Aider, or any of the 20+ supported tools and re-run.${c.reset}`);
1027
+ console.log("");
1028
+ return;
1029
+ }
1030
+
1031
+ console.log(`${c.green}✓${c.reset} Found ${c.bold}${measured.length}${c.reset} measured · ${c.bold}${detected.length}${c.reset} detected`);
1032
+ for (const m of measured) {
1033
+ const cost = m.stats?.cost ?? 0;
1034
+ console.log(` ${c.green}●${c.reset} ${pad(m.name, 22)} ${c.faint}${fmtUsd(cost)} all-time${c.reset}`);
1035
+ }
1036
+ for (const d of detected) {
1037
+ console.log(` ${c.yellow}◎${c.reset} ${pad(d.name, 22)} ${c.faint}detected · telemetry parser pending${c.reset}`);
1038
+ }
1039
+ console.log("");
1040
+
1041
+ // ── Step 2: login if needed ─────────────────────────────────────
1042
+ let token = loadToken();
1043
+ if (!token) {
1044
+ console.log(`${c.faint}Step 2/3 · Pairing this device with tokenflexing.com…${c.reset}`);
1045
+ await commandLogin([]);
1046
+ token = loadToken();
1047
+ if (!token) {
1048
+ console.log(`${c.faint}Connect aborted — could not pair this device.${c.reset}`);
1049
+ console.log("");
1050
+ return;
1051
+ }
1052
+ } else {
1053
+ console.log(`${c.faint}Step 2/3 · Already paired with tokenflexing.com${c.reset} ${c.green}✓${c.reset}`);
1054
+ console.log("");
1055
+ }
1056
+
1057
+ // ── Step 3: sync ────────────────────────────────────────────────
1058
+ console.log(`${c.faint}Step 3/3 · Pushing stats to your profile…${c.reset}`);
1059
+ await commandSync();
1060
+
1061
+ // ── Daemon nudge ────────────────────────────────────────────────
1062
+ console.log(`${c.bold}You're connected.${c.reset}`);
1063
+ console.log("");
1064
+ console.log(`Optional next steps:`);
1065
+ console.log(` ${c.green}tokenflexing daemon --install${c.reset} ${c.faint}refresh daily at 6 AM${c.reset}`);
1066
+ console.log(` ${c.green}tokenflexing install-hooks --apply${c.reset} ${c.faint}wire MCP into Claude Code${c.reset}`);
1067
+ console.log(` ${c.faint}View your profile: ${SITE}/dashboard${c.reset}`);
1068
+ console.log("");
1069
+ }
1070
+
1071
+ function commandVersion() { console.log("1.2.0"); }
971
1072
 
972
1073
  function commandHelp() {
973
1074
  console.log("");
974
1075
  console.log(`${c.bold}tokenflexing${c.reset}${c.faint} — show off your AI token usage${c.reset}`);
975
1076
  console.log("");
1077
+ console.log(` ${c.green}tokenflexing connect${c.reset} ${c.bold}one-command setup${c.reset} — scan + login + sync`);
976
1078
  console.log(` ${c.green}tokenflexing${c.reset} show stats (default)`);
977
1079
  console.log(` ${c.green}tokenflexing stats${c.reset} breakdown per source + model`);
978
1080
  console.log(` ${c.green}tokenflexing scan${c.reset} detect ALL AI tools on this device`);
@@ -1009,6 +1111,7 @@ export async function main(argv) {
1009
1111
  case undefined: return commandStats();
1010
1112
  case "scan": return commandScan();
1011
1113
  case "flex": return commandFlex();
1114
+ case "connect": return commandConnect();
1012
1115
  case "daemon": return commandDaemon(argv.slice(1));
1013
1116
  case "mcp": return commandMcp();
1014
1117
  case "install-hooks": return commandInstallHooks(argv.slice(1));