@usagefleet/cli 1.2.70 → 1.2.71

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 +120 -233
  2. package/dist/release.js +1 -1
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,200 +1,85 @@
1
1
  # @usagefleet/cli
2
2
 
3
- Tails the local JSONL logs of Claude Code, Claude Desktop's agent-mode
4
- (Cowork) sessions, **and** the [pi](https://github.com/badlogic/pi-mono) coding
5
- agent (`~/.pi/agent/sessions`; only its Anthropic-provider records usage via
6
- other providers doesn't touch Claude limits), reporting token usage to a
7
- UsageFleet server. Read-only on the log files. Zero runtime dependencies
8
- (Node ≥ 20).
3
+ The UsageFleet collector. It tails the local logs of your Claude agents and
4
+ reports usage to [usagefleet.com](https://usagefleet.com), where it's split
5
+ across your device groups. Read-only on the log files, zero runtime
6
+ dependencies, Node 20.
9
7
 
10
8
  ## Install
11
9
 
12
- Two commands, identical on macOS, Linux and Windows. You only need a device
13
- **token** from the server's Devices page (endpoint defaults to
14
- `https://usagefleet.com`):
10
+ Get a device **token** from the [Devices](https://usagefleet.com/devices) page,
11
+ then, on that machine:
15
12
 
16
13
  ```bash
17
14
  npm i -g @usagefleet/cli
18
- usagefleet install --token uf_xxx # autostart at login; --endpoint <url> when self-hosting
15
+ usagefleet install --token uf_xxx
19
16
  ```
20
17
 
21
- In PowerShell chain them with `;` instead of `&&` Windows PowerShell 5.1 has
22
- no `&&`.
18
+ Same two commands on macOS, Linux and Windows (in PowerShell chain them with
19
+ `;` — 5.1 has no `&&`). `install` sets the collector to start at login and
20
+ writes `~/.config/usagefleet/config.json` (mode `600`). The dashboard fills in
21
+ within a minute.
23
22
 
24
- Autostart uses launchd (macOS), systemd `--user` (Linux) and Task Scheduler
25
- (Windows). If `npm i -g` fails with EACCES your global prefix is root-owned:
26
- either use a Node version manager (nvm, fnm, volta) or
27
- `npm config set prefix ~/.local` and put `~/.local/bin` on your PATH. Installing
28
- the collector under `sudo` would run it as the wrong user.
23
+ Running your own server? Add `--endpoint https://track.example.com`.
29
24
 
30
- **Update** happens on its own (see below) or on demand with
31
- `usagefleet update`. `npm i -g @usagefleet/cli` does the same thing.
25
+ If `npm i -g` fails with EACCES your global prefix is root-owned: use a Node
26
+ version manager (nvm, fnm, volta) or `npm config set prefix ~/.local` with
27
+ `~/.local/bin` on your PATH. Don't install under `sudo` — the collector would
28
+ run as the wrong user.
32
29
 
33
- ### Run from source
34
-
35
- ```bash
36
- cd apps/cli
37
- bun install
38
- bun run src/index.ts status # or: npm run build && node dist/index.js status
39
- ```
40
-
41
- ## Configure
42
-
43
- Get a device **token** from the server's Devices page, then either:
44
-
45
- ```bash
46
- usagefleet install --endpoint https://track.example.com --token uf_xxx
47
- # writes ~/.config/usagefleet/config.json
48
- ```
49
-
50
- That one file (mode `600`) holds everything the CLI persists — your settings
51
- plus the two machine-managed sections, `state` (per-log tail offsets) and
52
- `notify` (which alert thresholds already fired). Delete it to start clean.
53
- `XDG_CONFIG_HOME` is honoured. Installs predating the consolidation are folded
54
- in automatically from `~/.usagefleet.json`, `~/.usagefleet-state.json` and
55
- `~/.usagefleet-notify.json` on first write; those files are then unused and
56
- safe to delete.
57
-
58
- Or set env vars (they override the config file):
59
-
60
- | Variable | Meaning |
61
- |----------|---------|
62
- | `USAGEFLEET_ENDPOINT` | server base URL. Must be `https://` (loopback may be `http://`): it carries the device token on every request |
63
- | `USAGEFLEET_TOKEN` | device token |
64
- | `USAGEFLEET_PROJECTS` | override `~/.claude/projects` (Claude Code logs) |
65
- | `USAGEFLEET_DESKTOP` | override the Claude Desktop agent-mode sessions dir (auto-detected per-OS); set `off`/`0` to skip desktop collection |
66
- | `USAGEFLEET_PI` | override the pi agent sessions dirs, comma-separated (default `~/.pi/agent/sessions` plus whatever `PI_CODING_AGENT_DIR`/`PI_CODING_AGENT_SESSION_DIR` point at — a service inherits neither, so set this if you relocated pi's agent dir); set `off`/`0` to skip pi collection |
67
- | `USAGEFLEET_INTERVAL` | watch poll seconds (default 15) |
68
- | `USAGEFLEET_LIMITS_INTERVAL` | how often to ping for real 5h/weekly limits, seconds (default 300; decoupled from the faster usage poll so the 1-token ping doesn't run every cycle) |
69
- | `USAGEFLEET_NOTIFY` | desktop notifications on/off (default **on**; set `0`/`false`/`off` to disable) |
70
- | `USAGEFLEET_NOTIFY_THRESHOLDS` | comma list of utilization % that trigger an alert (default `80,95`) |
71
- | `USAGEFLEET_BATCH` | records per upload request (default 100, capped at the server's limit of 1000) |
72
- | `USAGEFLEET_CONFIG` | override the whole config file path (default `~/.config/usagefleet/config.json`) |
73
- | `USAGEFLEET_UPDATE` | set `0` to turn the self-update check off |
74
- | `USAGEFLEET_UPDATE_INTERVAL` | seconds between self-update checks (default `21600` = 6h, i.e. 4×/day) |
75
- | `USAGEFLEET_HOOK` | set `0` to keep the prompt-blocking hook out of `~/.claude/settings.json` |
76
-
77
- ### Setting the token per shell
78
-
79
- **bash / zsh** (macOS, Linux) — one-off for the current session:
80
-
81
- ```bash
82
- export USAGEFLEET_ENDPOINT="https://track.example.com"
83
- export USAGEFLEET_TOKEN="uf_xxx"
84
- ```
85
-
86
- Persist it by appending those lines to `~/.bashrc` / `~/.zshrc`, then
87
- `source ~/.zshrc`. Or set it inline for a single command:
88
-
89
- ```bash
90
- USAGEFLEET_ENDPOINT=https://track.example.com USAGEFLEET_TOKEN=uf_xxx usagefleet run
91
- ```
92
-
93
- **fish**:
94
-
95
- ```fish
96
- set -x USAGEFLEET_ENDPOINT "https://track.example.com"
97
- set -x USAGEFLEET_TOKEN "uf_xxx"
98
- # persist (writes to universal vars, survives restarts):
99
- set -Ux USAGEFLEET_TOKEN "uf_xxx"
100
- set -Ux USAGEFLEET_ENDPOINT "https://track.example.com"
101
- ```
102
-
103
- **PowerShell** (Windows) — current session:
104
-
105
- ```powershell
106
- $env:USAGEFLEET_ENDPOINT = "https://track.example.com"
107
- $env:USAGEFLEET_TOKEN = "uf_xxx"
108
- # persist for your user (new shells only):
109
- setx USAGEFLEET_TOKEN "uf_xxx"
110
- setx USAGEFLEET_ENDPOINT "https://track.example.com"
111
- ```
112
-
113
- **cmd.exe** (Windows):
114
-
115
- ```cmd
116
- set USAGEFLEET_ENDPOINT=https://track.example.com
117
- set USAGEFLEET_TOKEN=uf_xxx
118
- :: persist: setx USAGEFLEET_TOKEN "uf_xxx"
119
- ```
120
-
121
- > Prefer not to put a long-lived token in shell history/rc files? Use
122
- > `usagefleet install --endpoint <url> --token <t>` instead — it writes
123
- > `~/.config/usagefleet/config.json` (mode `600`), which the collector reads
124
- > automatically. The write merges, so re-running it rotates the token without
125
- > resetting your tail offsets.
126
- > When run as a service, `usagefleet install` bakes every `USAGEFLEET_*` value
127
- > that is currently set (plus `ANTHROPIC_API_KEY`) into the launchd/systemd unit.
128
- > The unit is written mode `600`, since it holds those secrets.
129
-
130
- ## Run
30
+ ## Commands
131
31
 
132
32
  ```bash
33
+ usagefleet status # service health, last limits reading, resolved config
133
34
  usagefleet run # one scan: upload usage + report limits
134
- usagefleet watch # poll continuously
35
+ usagefleet watch # poll continuously (what the service runs)
135
36
  usagefleet limits # report ONLY your real 5h/weekly limit usage
136
37
  usagefleet guard # exit 2 if this device's group is over a blocking limit
137
- usagefleet update # upgrade to the latest published version now
138
- usagefleet status # service health, last limits reading, resolved config
38
+ usagefleet notify-test # fire a sample desktop notification
39
+ usagefleet update # upgrade now (it also self-updates every 6h)
139
40
  usagefleet config # config file location + every env override
140
- usagefleet version # bare release version
41
+ usagefleet install # (re)install the background service, idempotent
42
+ usagefleet uninstall # remove it
141
43
  ```
142
44
 
143
- ### Updates
144
-
145
- `watch` asks the npm registry for the published version at startup and then
146
- every 6 hours (`USAGEFLEET_UPDATE_INTERVAL`, in seconds); when it differs from
147
- the one baked into this build it runs `npm install -g @usagefleet/cli@<version>`
148
- and re-runs `install` to restart the service on it. `usagefleet update` does the
149
- same on demand.
45
+ ## What it collects
150
46
 
151
- npm is called through the absolute path next to the `node` running the
152
- collector, because a launchd/systemd service gets a minimal PATH that rarely has
153
- your version manager on it.
47
+ - **Token usage** Claude Code (`~/.claude/projects/**/*.jsonl`), Claude
48
+ Desktop agent-mode (Cowork) sessions, and the
49
+ [pi](https://github.com/badlogic/pi-mono) agent (`~/.pi/agent/sessions`,
50
+ Anthropic-provider records only; other providers don't touch Claude limits).
51
+ A per-file byte offset in the config file means each line is sent once;
52
+ rotation and truncation are handled and partial lines are never sent. Delivery
53
+ is at-least-once — the server dedups on `uuid`.
54
+ - **Your real limit %** — the collector uses the Claude login already on the
55
+ machine (subscription OAuth from `claude`: macOS login Keychain, elsewhere
56
+ `~/.claude/.credentials.json`; falling back to `ANTHROPIC_API_KEY`), sends a
57
+ 1-token ping to the Messages API, and reads Anthropic's
58
+ `anthropic-ratelimit-unified-5h/7d-utilization` headers. Credentials never
59
+ leave the machine — only the percentages do. `usagefleet status` shows which
60
+ login was found.
154
61
 
155
- Every failure is a no-op: registry unreachable, a version string that isn't
156
- plain semver, npm missing, npm exiting non-zero (a root-owned global prefix is
157
- the usual cause) and locally-built (`dev`) builds all leave the install as it
158
- was — the service is only restarted after npm reports success. Set
159
- `USAGEFLEET_UPDATE=0` to turn the check off.
62
+ Uploaded per record: token counts, model, session id, hostname, working
63
+ directory, git branch. Prompts, responses and file contents are never read.
160
64
 
161
- The collector tracks a per-file byte offset in the config file's `state`
162
- section, so each line is sent once; it handles rotation/truncation and never
163
- sends a partial line. Delivery is at-least-once — the server dedups on `uuid`.
65
+ ## Desktop notifications
164
66
 
165
- ### Real limit % (auto-detected)
67
+ The first time a window crosses a threshold (default `80` and `95`) you get a
68
+ desktop notification — once per threshold per window, re-armed when the window
69
+ resets. macOS uses `osascript`, Linux `notify-send` (falling back to
70
+ `kdialog --passivepopup`; install `libnotify-bin` if neither exists), Windows a
71
+ WinRT toast via `powershell.exe`.
166
72
 
167
- On `run`/`watch`/`limits`, the collector reads your **local Claude login** on
168
- this machine and reports your true utilization — no keys pasted anywhere:
73
+ `usagefleet notify-test` confirms it works. Tune with
74
+ `USAGEFLEET_NOTIFY_THRESHOLDS="50,80,95"`, disable with `USAGEFLEET_NOTIFY=0`.
169
75
 
170
- 1. **Subscription** the OAuth token from `claude` (Claude Code). On macOS it's
171
- read from the login Keychain (`Claude Code-credentials`); on Linux/Windows from
172
- `~/.claude/.credentials.json`. Sign in once with `claude` and it's detected.
173
- 2. **API key** — falls back to `ANTHROPIC_API_KEY` if no subscription login.
174
-
175
- It sends a 1-token ping to the Messages API and reads Anthropic's
176
- `anthropic-ratelimit-unified-5h/7d-utilization` (and `-reset`) headers, then POSTs
177
- the percentages to the server. `usagefleet status` shows which login was found.
178
- The token/credentials never leave your machine — only the resulting percentages
179
- are uploaded.
180
-
181
- ### Blocking prompts over the limit
76
+ ## Blocking prompts over the limit
182
77
 
183
78
  A group can be set to **refuse new prompts** once it has burned its budget slice
184
- (1/group count of the account limit) for a window. Two switches per group, both
185
- off by default flip them in the database:
186
-
187
- ```sql
188
- UPDATE groups SET block_on_session_limit = true WHERE name = 'Backend'; -- 5h window
189
- UPDATE groups SET block_on_weekly_limit = true WHERE name = 'Backend'; -- 7d window
190
- ```
191
-
192
- Enforcement is a Claude Code `UserPromptSubmit` hook, registered in
193
- `~/.claude/settings.json` automatically by `usagefleet install` (and removed
194
- by `usagefleet uninstall`). Re-running install refreshes the path instead of
195
- stacking a second hook; a settings file that doesn't parse is left untouched.
196
- Set `USAGEFLEET_HOOK=0` to keep your settings file out of it and add the hook
197
- yourself:
79
+ (1/N of the account limit) for a window a switch per window on the Groups
80
+ page, both off by default. `usagefleet install` registers a Claude Code `UserPromptSubmit` hook in
81
+ `~/.claude/settings.json` (removed by `uninstall`, refreshed rather than stacked
82
+ on re-install, and skipped entirely with `USAGEFLEET_HOOK=0`):
198
83
 
199
84
  ```json
200
85
  {
@@ -206,79 +91,81 @@ yourself:
206
91
  }
207
92
  ```
208
93
 
209
- `usagefleet guard` asks the server whether the calling device's group is over
210
- a window it blocks on; exit code 2 refuses the prompt and shows the reason.
211
- It **fails open** everywhere else no config, server down, timeout (5s), old
212
- server, 429 — because a tracker problem must never stop you from working.
213
- Only whole prompts are blocked, never tool calls mid-turn, so the current turn
214
- always finishes.
94
+ `guard` **fails open** everywhere else no config, server down, timeout (5s),
95
+ old server, 429 because a tracker problem must never stop you working. Only
96
+ whole prompts are blocked, never tool calls mid-turn, so the current turn always
97
+ finishes.
215
98
 
216
- ### Desktop notifications
99
+ ## Configuration
217
100
 
218
- When the collector reads your real 5h/weekly utilization, it raises a **desktop
219
- notification** the first time each window crosses a threshold (default `80%` and
220
- `95%`). It fires at most once per threshold per window and re-arms when the
221
- window resets, so it never spams.
101
+ `~/.config/usagefleet/config.json` (honours `XDG_CONFIG_HOME`) holds everything
102
+ the CLI persists: your settings plus two machine-managed sections, `state` (tail
103
+ offsets) and `notify` (which thresholds already fired). Delete it to start
104
+ clean. Re-running `install` merges, so rotating a token doesn't reset offsets.
222
105
 
223
- ```bash
224
- usagefleet notify-test # fire a sample notification to confirm it works
225
- ```
106
+ Env vars override the file:
107
+
108
+ | Variable | Meaning |
109
+ |----------|---------|
110
+ | `USAGEFLEET_ENDPOINT` | server base URL (default `https://usagefleet.com`). Must be `https://`, loopback may be `http://` |
111
+ | `USAGEFLEET_TOKEN` | device token |
112
+ | `USAGEFLEET_PROJECTS` | override `~/.claude/projects` |
113
+ | `USAGEFLEET_DESKTOP` | override the Claude Desktop sessions dir; `off` to skip it |
114
+ | `USAGEFLEET_PI` | override the pi sessions dirs, comma-separated; `off` to skip |
115
+ | `USAGEFLEET_INTERVAL` | watch poll seconds (default 15) |
116
+ | `USAGEFLEET_LIMITS_INTERVAL` | seconds between limit pings (default 300, so the 1-token ping isn't every cycle) |
117
+ | `USAGEFLEET_NOTIFY` | desktop notifications, on by default |
118
+ | `USAGEFLEET_NOTIFY_THRESHOLDS` | utilization % that trigger an alert (default `80,95`) |
119
+ | `USAGEFLEET_BATCH` | records per upload (default 100, server caps at 1000) |
120
+ | `USAGEFLEET_CONFIG` | override the config file path |
121
+ | `USAGEFLEET_UPDATE` | `0` turns the self-update check off |
122
+ | `USAGEFLEET_UPDATE_INTERVAL` | seconds between update checks (default `21600` = 6h) |
123
+ | `USAGEFLEET_HOOK` | `0` keeps the prompt-blocking hook out of `~/.claude/settings.json` |
226
124
 
227
- - **macOS** uses `osascript` Notification Center (no extra install).
228
- - **Linux (KDE Plasma / freedesktop)** uses `notify-send`; if that's missing it
229
- falls back to KDE's `kdialog --passivepopup`. Install `notify-send` via
230
- `libnotify` (e.g. `apt install libnotify-bin`) if neither is present.
231
- - **Windows** — a WinRT toast via built-in `powershell.exe` → Action Center (no
232
- extra install; it appears under "Windows PowerShell"). Check Settings →
233
- Notifications if nothing shows up.
125
+ When run as a service, `install` bakes every `USAGEFLEET_*` value currently set
126
+ (plus `ANTHROPIC_API_KEY`) into the launchd/systemd unit, written mode `600`.
234
127
 
235
- Tune or disable:
128
+ ## Background service
236
129
 
237
- ```bash
238
- export USAGEFLEET_NOTIFY_THRESHOLDS="50,80,95" # alert at 50/80/95%
239
- export USAGEFLEET_NOTIFY=0 # turn notifications off
240
- ```
130
+ `install` is idempotent and reload-safe: re-running it rewrites the service
131
+ definition and restarts it, so it doubles as the update step. It launches an
132
+ absolute `node` plus the installed package path, so an empty service PATH is
133
+ fine — but removing that Node version (`nvm uninstall`) stops the collector
134
+ until you re-run `usagefleet install` under the new one.
135
+
136
+ - **macOS** — a LaunchAgent (`~/Library/LaunchAgents`, RunAtLoad + KeepAlive),
137
+ booted immediately. Logs in `~/Library/Logs/usagefleet/`. Plist is mode `600`:
138
+ it holds your token.
139
+ - **Linux** — a `systemd --user` unit, plus `loginctl enable-linger $USER` so it
140
+ survives logout. If `systemctl` can't be driven it prints the manual steps.
141
+ - **Windows** — a Scheduled Task (`usagefleet`) starting at logon, restarting on
142
+ failure, running hidden through a `wscript` launcher in
143
+ `%LOCALAPPDATA%\usagefleet` (which carries the env values set at install
144
+ time). Log: `%LOCALAPPDATA%\usagefleet\usagefleet.log`. Inspect with
145
+ `schtasks /query /tn usagefleet /v /fo list`.
146
+
147
+ > **macOS limits under the service.** Usage collection works headless. Reading
148
+ > the login Keychain for the real limit % may be denied to a non-interactive
149
+ > agent — the collector logs a clear hint. Either approve `/usr/bin/security`
150
+ > access to the `Claude Code-credentials` item once, or set `ANTHROPIC_API_KEY`
151
+ > before `usagefleet install` so limits use the API key.
241
152
 
242
- > **Under a background service.** On macOS the LaunchAgent runs in your GUI
243
- > session, so notifications appear normally. On Linux a `systemd --user` service
244
- > needs access to your session bus (`DBUS_SESSION_BUS_ADDRESS`) for `notify-send`
245
- > to reach the notification daemon — typical for `--user` units in a graphical
246
- > login. `usagefleet install` bakes `USAGEFLEET_NOTIFY*` into the unit.
153
+ ## Updates
247
154
 
248
- ## Run as a background service
155
+ `watch` checks the npm registry at startup and every 6 hours; on a new version
156
+ it runs `npm install -g @usagefleet/cli@<version>` and re-runs `install` to
157
+ restart the service on it. `usagefleet update` does the same on demand. npm is
158
+ called through the absolute path next to the running `node`, because a
159
+ launchd/systemd service gets a minimal PATH.
160
+
161
+ Every failure is a no-op — registry unreachable, non-semver version, npm
162
+ missing or exiting non-zero, local `dev` builds — and the service is only
163
+ restarted after npm reports success.
164
+
165
+ ## From source
249
166
 
250
167
  ```bash
251
- usagefleet install # launchd (macOS) / systemd --user (Linux) / Task Scheduler (Windows)
252
- usagefleet uninstall
168
+ cd apps/cli
169
+ bun install
170
+ bun run src/index.ts status # or: npm run build && node dist/index.js status
253
171
  ```
254
-
255
- `install` is idempotent and reload-safe: re-running it rewrites the service
256
- definition and restarts it, so it doubles as the update step. The service is
257
- launched as an absolute `node` plus the installed package path, so an empty
258
- service PATH is fine — but removing that Node version (`nvm uninstall`) stops
259
- the collector until you re-run `usagefleet install` under the new one.
260
-
261
- - **macOS** — installs a LaunchAgent (`~/Library/LaunchAgents`, RunAtLoad +
262
- KeepAlive) and boots it (bootout → bootstrap → kickstart). Logs at
263
- `~/Library/Logs/usagefleet/usagefleet.*.log` (not `/tmp`, which is
264
- world-writable). The plist is written mode `600`: it holds your token.
265
- - **Linux** — writes a `--user` unit and runs `systemctl --user daemon-reload`,
266
- `enable --now`, `restart`, plus `loginctl enable-linger $USER` automatically so
267
- it survives logout. If `systemctl` can't be driven, it prints the manual steps.
268
- - **Windows** — registers a Scheduled Task (`usagefleet`) that starts at logon,
269
- restarts on failure, and runs **hidden** (no console window) through a
270
- generated `wscript` launcher in `%LOCALAPPDATA%\usagefleet`. Task XML has no
271
- env support, so the launcher carries the `USAGEFLEET_*` values that were set
272
- when you ran `install`, and redirects output to
273
- `%LOCALAPPDATA%\usagefleet\usagefleet.log` (truncated on each start).
274
- Inspect it with `schtasks /query /tn usagefleet /v /fo list`.
275
-
276
- The OS is reported automatically (`process.platform` → `mac`/`linux`/`windows`).
277
-
278
- > **macOS limits under the service.** Usage collection (reading JSONL files) works
279
- > headless. The **real limit %** feature reads the login Keychain, and a
280
- > non-interactive launchd agent may be denied that read — the collector logs a
281
- > clear hint when this happens. If it does, either approve `/usr/bin/security`
282
- > access to the `Claude Code-credentials` item once, or set `ANTHROPIC_API_KEY`
283
- > before `usagefleet install` (it's baked into the service) so limits use the
284
- > API key instead.
package/dist/release.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // Generated by .github/workflows/release.yml.
2
- export const RELEASE_VERSION = "1.2.70";
2
+ export const RELEASE_VERSION = "1.2.71";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usagefleet/cli",
3
- "version": "1.2.70",
3
+ "version": "1.2.71",
4
4
  "description": "Tails Claude Code, Claude Desktop, and pi agent JSONL logs and reports token usage to a UsageFleet server.",
5
5
  "keywords": [
6
6
  "claude",