ccusage-tracker 0.1.3 → 0.1.6
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/README.md +1 -1
- package/dist/index.js +56 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -30,7 +30,7 @@ After installation, the binary is also available as `tracker` (if installed glob
|
|
|
30
30
|
- **Stop** — primary reporting path: POSTs token usage + session metrics after each assistant turn, throttled to once per 5 minutes
|
|
31
31
|
- **SessionEnd** — backup path: same payload at session exit, in case Stop missed the last window
|
|
32
32
|
|
|
33
|
-
Hook scripts are downloaded from your tracker server, so they always match the server version. Re-running `setup` migrates old (no `--mode`) commands in-place — no manual cleanup needed.
|
|
33
|
+
Hook scripts are downloaded from your tracker server, so they always match the server version. Re-running `setup` migrates old (no `--mode`) commands and unquoted tracker hook paths in-place — no manual cleanup needed.
|
|
34
34
|
|
|
35
35
|
## Requirements
|
|
36
36
|
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// src/commands/setup.ts
|
|
4
4
|
import { createInterface } from "node:readline";
|
|
5
|
+
import { spawnSync } from "node:child_process";
|
|
5
6
|
|
|
6
7
|
// src/config.ts
|
|
7
8
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
@@ -36,21 +37,28 @@ function writeConfig(config) {
|
|
|
36
37
|
import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2, copyFileSync, mkdirSync as mkdirSync2 } from "node:fs";
|
|
37
38
|
import { join as join2 } from "node:path";
|
|
38
39
|
import { homedir as homedir2 } from "node:os";
|
|
39
|
-
var HOOK_TIMEOUT_SEC =
|
|
40
|
+
var HOOK_TIMEOUT_SEC = 45;
|
|
40
41
|
function getClaudeSettingsPath() {
|
|
41
42
|
return join2(homedir2(), ".claude", "settings.json");
|
|
42
43
|
}
|
|
43
44
|
function sessionEndScriptPath() {
|
|
44
45
|
return join2(homedir2(), ".config", "ccusage-tracker", "session-end.mjs");
|
|
45
46
|
}
|
|
47
|
+
function quoteScriptPath(path) {
|
|
48
|
+
return `"${path}"`;
|
|
49
|
+
}
|
|
50
|
+
function buildHookCommand(scriptPath, mode) {
|
|
51
|
+
const command = "node " + quoteScriptPath(scriptPath);
|
|
52
|
+
return mode ? `${command} --mode=${mode}` : command;
|
|
53
|
+
}
|
|
46
54
|
function getHookCommand() {
|
|
47
|
-
return
|
|
55
|
+
return buildHookCommand(sessionEndScriptPath(), "session-end");
|
|
48
56
|
}
|
|
49
57
|
function getStopHookCommand() {
|
|
50
|
-
return
|
|
58
|
+
return buildHookCommand(sessionEndScriptPath(), "stop");
|
|
51
59
|
}
|
|
52
60
|
function getStartHookCommand() {
|
|
53
|
-
return
|
|
61
|
+
return buildHookCommand(join2(homedir2(), ".config", "ccusage-tracker", "session-start.mjs"));
|
|
54
62
|
}
|
|
55
63
|
function isCcusageTrackerHook(command) {
|
|
56
64
|
return !!command && command.includes("ccusage-tracker");
|
|
@@ -179,8 +187,7 @@ async function defaultCheckServer(serverUrl) {
|
|
|
179
187
|
}
|
|
180
188
|
function defaultCheckCcusage() {
|
|
181
189
|
try {
|
|
182
|
-
|
|
183
|
-
return true;
|
|
190
|
+
return spawnSync("ccusage --version", { encoding: "utf8", shell: true, timeout: 1e4 }).status === 0;
|
|
184
191
|
} catch {
|
|
185
192
|
return false;
|
|
186
193
|
}
|
|
@@ -363,6 +370,7 @@ async function reportCommand(args) {
|
|
|
363
370
|
|
|
364
371
|
// src/commands/status.ts
|
|
365
372
|
import { existsSync as existsSync3, readFileSync as readFileSync3 } from "node:fs";
|
|
373
|
+
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
366
374
|
import { join as join3, dirname } from "node:path";
|
|
367
375
|
async function statusCommand() {
|
|
368
376
|
const configPath = getConfigPath();
|
|
@@ -408,12 +416,50 @@ Hook: ${hookInstalled ? "installed" : "not installed"}`);
|
|
|
408
416
|
} else {
|
|
409
417
|
console.log("Buffer: none");
|
|
410
418
|
}
|
|
419
|
+
const configDir = dirname(configPath);
|
|
420
|
+
const lastErrorPath = join3(configDir, "last-error.txt");
|
|
421
|
+
if (existsSync3(lastErrorPath)) {
|
|
422
|
+
const reason = readFileSync3(lastErrorPath, "utf-8").trim();
|
|
423
|
+
console.log(`
|
|
424
|
+
Last upload: FAILED - ${reason}`);
|
|
425
|
+
console.log(uploadFailureHint(reason));
|
|
426
|
+
} else {
|
|
427
|
+
console.log(`
|
|
428
|
+
Last upload: no recorded failure`);
|
|
429
|
+
}
|
|
430
|
+
const lastFlushPath = join3(configDir, "last-flush.txt");
|
|
431
|
+
if (existsSync3(lastFlushPath)) {
|
|
432
|
+
const ts = parseInt(readFileSync3(lastFlushPath, "utf-8").trim(), 10);
|
|
433
|
+
if (!isNaN(ts)) {
|
|
434
|
+
const ageMin = Math.floor((Date.now() - ts) / 60000);
|
|
435
|
+
console.log(`Last hook run: ${new Date(ts).toISOString()} (${ageMin} 分鐘前)`);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
const probe = probeCcusage();
|
|
439
|
+
console.log(probe ? `ccusage: installed (${probe})` : "ccusage: not found (install with: npx ccusage@latest)");
|
|
440
|
+
}
|
|
441
|
+
function uploadFailureHint(reason) {
|
|
442
|
+
if (reason.includes("ccusage")) {
|
|
443
|
+
return [
|
|
444
|
+
" 用量目前並未上報。請量測 ccusage 耗時,若接近 25s 需再放寬 timeout:",
|
|
445
|
+
" time ccusage daily --json --since $(date +%Y%m%d)"
|
|
446
|
+
].join(`
|
|
447
|
+
`);
|
|
448
|
+
}
|
|
449
|
+
return [
|
|
450
|
+
" 用量目前並未上報。ccusage 有取到數,卡在送出那一段 —— 先看上面的 Server 一行,",
|
|
451
|
+
" 再檢查網路 / VPN / proxy。當日快照是整日累計,下次 hook 跑成就會補齊"
|
|
452
|
+
].join(`
|
|
453
|
+
`);
|
|
454
|
+
}
|
|
455
|
+
function probeCcusage() {
|
|
411
456
|
try {
|
|
412
|
-
const
|
|
413
|
-
|
|
414
|
-
|
|
457
|
+
const r = spawnSync2("ccusage --version", { encoding: "utf8", shell: true, timeout: 1e4 });
|
|
458
|
+
if (r.status !== 0 || !r.stdout)
|
|
459
|
+
return null;
|
|
460
|
+
return r.stdout.trim() || "version unknown";
|
|
415
461
|
} catch {
|
|
416
|
-
|
|
462
|
+
return null;
|
|
417
463
|
}
|
|
418
464
|
}
|
|
419
465
|
|
package/package.json
CHANGED