@usagefleet/cli 1.2.69 → 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.
- package/LICENSE +674 -0
- package/README.md +121 -233
- package/dist/collector.js +21 -4
- package/dist/config.js +1 -1
- package/dist/index.js +55 -37
- package/dist/release.js +1 -1
- package/dist/service.js +33 -16
- package/dist/uploader.js +10 -4
- package/package.json +2 -2
package/dist/service.js
CHANGED
|
@@ -2,9 +2,9 @@ import { execFileSync } from 'node:child_process';
|
|
|
2
2
|
import { chmodSync, existsSync, mkdirSync, realpathSync, rmSync, writeFileSync } from 'node:fs';
|
|
3
3
|
import { homedir, tmpdir } from 'node:os';
|
|
4
4
|
import { delimiter, join } from 'node:path';
|
|
5
|
-
import { DEFAULT_ENDPOINT } from './config.js';
|
|
5
|
+
import { DEFAULT_ENDPOINT, loadConfig } from './config.js';
|
|
6
6
|
import { installPromptHook, uninstallPromptHook } from './hook.js';
|
|
7
|
-
import { readStore } from './store.js';
|
|
7
|
+
import { readStore, storePath, updateStore } from './store.js';
|
|
8
8
|
import { fail, header, hint, host, row, step, tilde, warn } from './ui.js';
|
|
9
9
|
const LABEL = 'dev.usagefleet.collector';
|
|
10
10
|
/** Scheduled Task name on Windows (mirrors the launchd label / systemd unit). */
|
|
@@ -216,23 +216,40 @@ function xml(s) {
|
|
|
216
216
|
.replaceAll("'", ''');
|
|
217
217
|
}
|
|
218
218
|
export function install() {
|
|
219
|
-
// Pre-flight: refuse to install a service
|
|
220
|
-
//
|
|
221
|
-
//
|
|
222
|
-
//
|
|
223
|
-
//
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
console.error(
|
|
230
|
-
console.error(hint('
|
|
231
|
-
process.exit(1);
|
|
219
|
+
// Pre-flight: refuse to install a service whose baked `watch` would throw on
|
|
220
|
+
// every launch, because the service manager crash-loops it invisibly (only the
|
|
221
|
+
// log file shows it). Resolving through loadConfig() is what makes this a real
|
|
222
|
+
// pre-flight rather than a lookalike: it is the same call `watch` makes, so a
|
|
223
|
+
// missing token or a non-https endpoint fails here or not at all.
|
|
224
|
+
let cfg;
|
|
225
|
+
try {
|
|
226
|
+
cfg = loadConfig();
|
|
227
|
+
}
|
|
228
|
+
catch (error) {
|
|
229
|
+
console.error(fail('config', error.message));
|
|
230
|
+
console.error(hint(' usagefleet install --endpoint <url> --token <device-token>'));
|
|
231
|
+
return process.exit(1);
|
|
232
|
+
}
|
|
233
|
+
// Config that only ever lived in this shell's env is lost to every later
|
|
234
|
+
// invocation: `usagefleet guard` runs from Claude Code's environment, which
|
|
235
|
+
// carries no USAGEFLEET_* vars (hook.ts bakes the command, not the env). The
|
|
236
|
+
// endpoint would fall back to the hosted default and send this device's token
|
|
237
|
+
// there; the token would be missing outright and the guard would fail open. So
|
|
238
|
+
// pin both to disk. The default endpoint is stored as absent rather than
|
|
239
|
+
// written out, so it can still move under an existing install.
|
|
240
|
+
const desiredEndpoint = cfg.endpoint === DEFAULT_ENDPOINT ? undefined : cfg.endpoint;
|
|
241
|
+
const stored = readStore();
|
|
242
|
+
if (stored.token !== cfg.token || stored.endpoint !== desiredEndpoint) {
|
|
243
|
+
// Only on a real change: `update` re-runs install every six hours, and this
|
|
244
|
+
// file is shared with the running collector's offset writes.
|
|
245
|
+
updateStore(storePath(), store => {
|
|
246
|
+
store.token = cfg.token;
|
|
247
|
+
store.endpoint = desiredEndpoint;
|
|
248
|
+
});
|
|
232
249
|
}
|
|
233
250
|
console.log(header());
|
|
234
251
|
console.log('');
|
|
235
|
-
console.log(step('configured', host(endpoint)));
|
|
252
|
+
console.log(step('configured', host(cfg.endpoint)));
|
|
236
253
|
// Windows: stop a running task first, or `schtasks /run` below is ignored (the
|
|
237
254
|
// task is IgnoreNew) — leaving the OLD version resident after an "update".
|
|
238
255
|
if (process.platform === 'win32') {
|
package/dist/uploader.js
CHANGED
|
@@ -44,7 +44,9 @@ export async function uploadBatch(payload, cfg) {
|
|
|
44
44
|
}
|
|
45
45
|
return { fatal: 'transient', ok: false };
|
|
46
46
|
}
|
|
47
|
-
/** Map a
|
|
47
|
+
/** Map a non-OK status to a failure kind. uploadBatch only ever passes a 4xx it
|
|
48
|
+
* has already decided not to retry; postLimits passes anything, and the 5xx/429
|
|
49
|
+
* fall-through to 'transient' is the answer it wants. */
|
|
48
50
|
function classifyClientError(status) {
|
|
49
51
|
if (status === 401 || status === 403) {
|
|
50
52
|
return 'auth';
|
|
@@ -76,7 +78,11 @@ function retryAfterMs(header, fallback) {
|
|
|
76
78
|
}
|
|
77
79
|
return Math.min(Math.max(wait, 0), 60_000) + Math.floor(Math.random() * 500);
|
|
78
80
|
}
|
|
79
|
-
/** Report the account's real limit utilization to the server.
|
|
81
|
+
/** Report the account's real limit utilization to the server. Shares uploadBatch's
|
|
82
|
+
* failure vocabulary so a plan wall reads as one on this leg too: it runs every
|
|
83
|
+
* cycle even when no usage records moved, so collapsing 402 to a bare failure
|
|
84
|
+
* would log an unactionable warning forever. Single-shot by design — a stale
|
|
85
|
+
* reading is worth less than the next cycle's fresh one. */
|
|
80
86
|
export async function postLimits(report, cfg) {
|
|
81
87
|
try {
|
|
82
88
|
const res = await fetch(`${cfg.endpoint}/api/v1/limits`, {
|
|
@@ -88,9 +94,9 @@ export async function postLimits(report, cfg) {
|
|
|
88
94
|
method: 'POST',
|
|
89
95
|
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
|
|
90
96
|
});
|
|
91
|
-
return res.ok;
|
|
97
|
+
return res.ok ? 'ok' : classifyClientError(res.status);
|
|
92
98
|
}
|
|
93
99
|
catch {
|
|
94
|
-
return
|
|
100
|
+
return 'transient';
|
|
95
101
|
}
|
|
96
102
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@usagefleet/cli",
|
|
3
|
-
"version": "1.2.
|
|
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",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"usage"
|
|
11
11
|
],
|
|
12
12
|
"homepage": "https://usagefleet.com",
|
|
13
|
-
"license": "
|
|
13
|
+
"license": "GPL-3.0-or-later",
|
|
14
14
|
"repository": {
|
|
15
15
|
"type": "git",
|
|
16
16
|
"url": "git+https://github.com/rokartur/usagefleet.git",
|