fleetlens 1.0.7 → 1.0.9
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/app/apps/web/.next/BUILD_ID +1 -1
- package/app/apps/web/.next/build-manifest.json +3 -3
- package/app/apps/web/.next/prerender-manifest.json +3 -3
- package/app/apps/web/.next/server/app/_global-error.html +1 -1
- package/app/apps/web/.next/server/app/_global-error.rsc +1 -1
- package/app/apps/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/app/apps/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/app/apps/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/app/apps/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/app/apps/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/app/apps/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/agent/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/changelog/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/day/[date]/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/day/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/digest/[date]/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/digest/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/insights/[key]/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/insights/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/parallelism/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/print/[key]/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/projects/[slug]/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/projects/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/runs/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/sessions/[id]/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/team/onboarding/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/team/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/app/usage/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/chunks/[root-of-the-server]__02.51sr._.js +1 -1
- package/app/apps/web/.next/server/chunks/[root-of-the-server]__0zyh554._.js +1 -1
- package/app/apps/web/.next/server/chunks/ssr/_0k8yioi._.js +1 -1
- package/app/apps/web/.next/server/chunks/ssr/apps_web_lib_changelog_ts_0n7_p1d._.js +1 -1
- package/app/apps/web/.next/server/chunks/ssr/apps_web_lib_changelog_ts_0nb5_-s._.js +1 -1
- package/app/apps/web/.next/server/middleware-build-manifest.js +3 -3
- package/app/apps/web/.next/server/middleware-manifest.json +5 -5
- package/app/apps/web/.next/server/pages/500.html +1 -1
- package/app/apps/web/.next/server/server-reference-manifest.js +1 -1
- package/app/apps/web/.next/server/server-reference-manifest.json +1 -1
- package/app/apps/web/.next/static/chunks/16ng0.1m2m026.js +1 -0
- package/app/apps/web/lib/changelog-data.generated.ts +1 -1
- package/app/apps/web/package.json +1 -1
- package/app/apps/web/tsconfig.tsbuildinfo +1 -1
- package/dist/daemon-worker.js +20 -10
- package/dist/index.js +2203 -1710
- package/menubar/Fleetlens.app/Contents/Info.plist +2 -2
- package/menubar/Fleetlens.app/Contents/MacOS/FleetlensMenubar +0 -0
- package/package.json +1 -1
- package/app/apps/web/.next/static/chunks/0pw75k-13ve.3.js +0 -1
- /package/app/apps/web/.next/static/{rSw7StGuB4J2DfY6_pElg → vYFdh4rRszFyu8bKNXN4N}/_buildManifest.js +0 -0
- /package/app/apps/web/.next/static/{rSw7StGuB4J2DfY6_pElg → vYFdh4rRszFyu8bKNXN4N}/_clientMiddlewareManifest.js +0 -0
- /package/app/apps/web/.next/static/{rSw7StGuB4J2DfY6_pElg → vYFdh4rRszFyu8bKNXN4N}/_ssgManifest.js +0 -0
package/dist/index.js
CHANGED
|
@@ -6298,9 +6298,9 @@ function onDiskVersion() {
|
|
|
6298
6298
|
try {
|
|
6299
6299
|
const here = dirname3(fileURLToPath(import.meta.url));
|
|
6300
6300
|
const pkg = JSON.parse(readFileSync5(join3(here, "..", "package.json"), "utf8"));
|
|
6301
|
-
return pkg.version ?? "1.0.
|
|
6301
|
+
return pkg.version ?? "1.0.9";
|
|
6302
6302
|
} catch {
|
|
6303
|
-
return "1.0.
|
|
6303
|
+
return "1.0.9";
|
|
6304
6304
|
}
|
|
6305
6305
|
}
|
|
6306
6306
|
function getServerStatus() {
|
|
@@ -6312,7 +6312,7 @@ function getServerStatus() {
|
|
|
6312
6312
|
return { running: false };
|
|
6313
6313
|
}
|
|
6314
6314
|
function isServerStale(status2) {
|
|
6315
|
-
return status2.running === true && status2.version !== "1.0.
|
|
6315
|
+
return status2.running === true && status2.version !== "1.0.9";
|
|
6316
6316
|
}
|
|
6317
6317
|
async function ensureCurrentServer(opts = {}) {
|
|
6318
6318
|
const status2 = getServerStatus();
|
|
@@ -6457,10 +6457,21 @@ __export(storage_exports, {
|
|
|
6457
6457
|
appendSnapshot: () => appendSnapshot,
|
|
6458
6458
|
latestClaudeCodeSnapshot: () => latestClaudeCodeSnapshot,
|
|
6459
6459
|
latestSnapshot: () => latestSnapshot,
|
|
6460
|
+
latestSnapshotsByAgent: () => latestSnapshotsByAgent,
|
|
6460
6461
|
pruneAgent: () => pruneAgent,
|
|
6461
6462
|
readSnapshots: () => readSnapshots
|
|
6462
6463
|
});
|
|
6463
|
-
import {
|
|
6464
|
+
import {
|
|
6465
|
+
appendFileSync as appendFileSync2,
|
|
6466
|
+
mkdirSync as mkdirSync4,
|
|
6467
|
+
readFileSync as readFileSync6,
|
|
6468
|
+
writeFileSync as writeFileSync4,
|
|
6469
|
+
existsSync as existsSync4,
|
|
6470
|
+
openSync,
|
|
6471
|
+
readSync,
|
|
6472
|
+
fstatSync,
|
|
6473
|
+
closeSync
|
|
6474
|
+
} from "node:fs";
|
|
6464
6475
|
import { dirname as dirname4 } from "node:path";
|
|
6465
6476
|
function appendSnapshot(filePath, snapshot) {
|
|
6466
6477
|
mkdirSync4(dirname4(filePath), { recursive: true });
|
|
@@ -6504,6 +6515,50 @@ function latestClaudeCodeSnapshot(filePath) {
|
|
|
6504
6515
|
}
|
|
6505
6516
|
return null;
|
|
6506
6517
|
}
|
|
6518
|
+
function latestSnapshotsByAgent(filePath, opts = {}) {
|
|
6519
|
+
if (!existsSync4(filePath)) return {};
|
|
6520
|
+
const tailBytes = opts.tailBytes ?? 262144;
|
|
6521
|
+
const raw = readTail(filePath, tailBytes);
|
|
6522
|
+
const byAgent = {};
|
|
6523
|
+
const lines = raw.split("\n");
|
|
6524
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
6525
|
+
const line = lines[i].trim();
|
|
6526
|
+
if (!line) continue;
|
|
6527
|
+
try {
|
|
6528
|
+
const s = JSON.parse(line);
|
|
6529
|
+
const agent = s.agent ?? "claude-code";
|
|
6530
|
+
if (byAgent[agent] === void 0) byAgent[agent] = s;
|
|
6531
|
+
} catch {
|
|
6532
|
+
}
|
|
6533
|
+
}
|
|
6534
|
+
return byAgent;
|
|
6535
|
+
}
|
|
6536
|
+
function readTail(filePath, maxBytes) {
|
|
6537
|
+
let fd;
|
|
6538
|
+
try {
|
|
6539
|
+
fd = openSync(filePath, "r");
|
|
6540
|
+
const size = fstatSync(fd).size;
|
|
6541
|
+
if (size <= 0) return "";
|
|
6542
|
+
const start2 = Math.max(0, size - maxBytes);
|
|
6543
|
+
const len = size - start2;
|
|
6544
|
+
const buf = Buffer.alloc(len);
|
|
6545
|
+
readSync(fd, buf, 0, len, start2);
|
|
6546
|
+
let text = buf.toString("utf8");
|
|
6547
|
+
if (start2 > 0) {
|
|
6548
|
+
const nl = text.indexOf("\n");
|
|
6549
|
+
if (nl !== -1) text = text.slice(nl + 1);
|
|
6550
|
+
}
|
|
6551
|
+
return text;
|
|
6552
|
+
} catch {
|
|
6553
|
+
try {
|
|
6554
|
+
return readFileSync6(filePath, "utf8");
|
|
6555
|
+
} catch {
|
|
6556
|
+
return "";
|
|
6557
|
+
}
|
|
6558
|
+
} finally {
|
|
6559
|
+
if (fd !== void 0) closeSync(fd);
|
|
6560
|
+
}
|
|
6561
|
+
}
|
|
6507
6562
|
var init_storage = __esm({
|
|
6508
6563
|
"src/usage/storage.ts"() {
|
|
6509
6564
|
"use strict";
|
|
@@ -6773,9 +6828,9 @@ Installed: ${PACKAGE_NAME}@${verify.installedVersion} at ${verify.installedPath
|
|
|
6773
6828
|
console.warn(
|
|
6774
6829
|
` \u2022 reinstall in the correct Node env: 'npm install -g ${PACKAGE_NAME}@latest'`
|
|
6775
6830
|
);
|
|
6776
|
-
} else if (verify.installedVersion !== "1.0.
|
|
6831
|
+
} else if (verify.installedVersion !== "1.0.9") {
|
|
6777
6832
|
console.log(
|
|
6778
|
-
` \u2192 This process is still running ${"1.0.
|
|
6833
|
+
` \u2192 This process is still running ${"1.0.9"}. Next invocation will use ${verify.installedVersion}.`
|
|
6779
6834
|
);
|
|
6780
6835
|
}
|
|
6781
6836
|
}
|
|
@@ -6810,14 +6865,14 @@ async function getUpdateAvailability() {
|
|
|
6810
6865
|
if (isDevMode()) return null;
|
|
6811
6866
|
const latest = await fetchLatestVersion();
|
|
6812
6867
|
if (latest === null) return {
|
|
6813
|
-
current: "1.0.
|
|
6868
|
+
current: "1.0.9",
|
|
6814
6869
|
latest: null,
|
|
6815
6870
|
updateAvailable: false
|
|
6816
6871
|
};
|
|
6817
6872
|
return {
|
|
6818
|
-
current: "1.0.
|
|
6873
|
+
current: "1.0.9",
|
|
6819
6874
|
latest,
|
|
6820
|
-
updateAvailable: shouldUpdate("1.0.
|
|
6875
|
+
updateAvailable: shouldUpdate("1.0.9", latest)
|
|
6821
6876
|
};
|
|
6822
6877
|
}
|
|
6823
6878
|
async function checkForUpdate() {
|
|
@@ -6907,7 +6962,7 @@ async function restartServices(state) {
|
|
|
6907
6962
|
}
|
|
6908
6963
|
async function forceUpdate() {
|
|
6909
6964
|
const latest = await fetchLatestVersion();
|
|
6910
|
-
const current = "1.0.
|
|
6965
|
+
const current = "1.0.9";
|
|
6911
6966
|
if (latest === null) {
|
|
6912
6967
|
console.error("Could not reach npm registry. Check your network.");
|
|
6913
6968
|
process.exit(1);
|
|
@@ -7328,7 +7383,7 @@ async function status() {
|
|
|
7328
7383
|
}
|
|
7329
7384
|
if (isServerStale(server)) {
|
|
7330
7385
|
console.log(
|
|
7331
|
-
` \u26A0 serving stale ${ver} (CLI is ${"1.0.
|
|
7386
|
+
` \u26A0 serving stale ${ver} (CLI is ${"1.0.9"}) \u2014 run 'fleetlens start' to restart on the current version`
|
|
7332
7387
|
);
|
|
7333
7388
|
}
|
|
7334
7389
|
} else {
|
|
@@ -7408,368 +7463,642 @@ var init_update = __esm({
|
|
|
7408
7463
|
}
|
|
7409
7464
|
});
|
|
7410
7465
|
|
|
7411
|
-
//
|
|
7412
|
-
|
|
7413
|
-
|
|
7414
|
-
import { homedir as homedir4, platform } from "node:os";
|
|
7415
|
-
import { join as join7 } from "node:path";
|
|
7416
|
-
function readOAuthCredentials() {
|
|
7417
|
-
if (platform() === "darwin") {
|
|
7418
|
-
return readFromMacKeychain() ?? readFromCredentialsFile();
|
|
7419
|
-
}
|
|
7420
|
-
return readFromCredentialsFile();
|
|
7421
|
-
}
|
|
7422
|
-
function readFromMacKeychain() {
|
|
7423
|
-
try {
|
|
7424
|
-
const blob = execFileSync2(
|
|
7425
|
-
"security",
|
|
7426
|
-
["find-generic-password", "-s", "Claude Code-credentials", "-w"],
|
|
7427
|
-
{ stdio: ["ignore", "pipe", "ignore"], encoding: "utf8" }
|
|
7428
|
-
);
|
|
7429
|
-
return extractCredentials(blob);
|
|
7430
|
-
} catch {
|
|
7431
|
-
return null;
|
|
7432
|
-
}
|
|
7433
|
-
}
|
|
7434
|
-
function readFromCredentialsFile() {
|
|
7435
|
-
const candidates = [
|
|
7436
|
-
join7(homedir4(), ".claude", ".credentials.json"),
|
|
7437
|
-
join7(homedir4(), ".config", "claude", "credentials.json")
|
|
7438
|
-
];
|
|
7439
|
-
for (const path11 of candidates) {
|
|
7440
|
-
try {
|
|
7441
|
-
const blob = readFileSync10(path11, "utf8");
|
|
7442
|
-
const creds = extractCredentials(blob);
|
|
7443
|
-
if (creds) return creds;
|
|
7444
|
-
} catch {
|
|
7445
|
-
}
|
|
7446
|
-
}
|
|
7447
|
-
return null;
|
|
7448
|
-
}
|
|
7449
|
-
function extractCredentials(blob) {
|
|
7450
|
-
try {
|
|
7451
|
-
const parsed = JSON.parse(blob);
|
|
7452
|
-
const oauth = parsed.claudeAiOauth;
|
|
7453
|
-
if (!oauth) return null;
|
|
7454
|
-
const accessToken = typeof oauth.accessToken === "string" ? oauth.accessToken : null;
|
|
7455
|
-
const expiresAt = typeof oauth.expiresAt === "number" ? oauth.expiresAt : null;
|
|
7456
|
-
if (!accessToken || expiresAt === null) return null;
|
|
7457
|
-
return { accessToken, expiresAt };
|
|
7458
|
-
} catch {
|
|
7459
|
-
return null;
|
|
7460
|
-
}
|
|
7461
|
-
}
|
|
7462
|
-
var init_token = __esm({
|
|
7463
|
-
"src/usage/token.ts"() {
|
|
7466
|
+
// ../parser/dist/types.js
|
|
7467
|
+
var init_types = __esm({
|
|
7468
|
+
"../parser/dist/types.js"() {
|
|
7464
7469
|
"use strict";
|
|
7465
7470
|
}
|
|
7466
7471
|
});
|
|
7467
7472
|
|
|
7468
|
-
//
|
|
7469
|
-
|
|
7470
|
-
|
|
7471
|
-
|
|
7472
|
-
|
|
7473
|
-
}
|
|
7474
|
-
|
|
7475
|
-
const
|
|
7476
|
-
|
|
7477
|
-
|
|
7478
|
-
|
|
7479
|
-
|
|
7480
|
-
|
|
7481
|
-
|
|
7482
|
-
|
|
7483
|
-
|
|
7484
|
-
|
|
7485
|
-
|
|
7486
|
-
);
|
|
7487
|
-
|
|
7488
|
-
|
|
7489
|
-
|
|
7490
|
-
|
|
7491
|
-
|
|
7492
|
-
|
|
7493
|
-
|
|
7473
|
+
// ../parser/dist/presentation.js
|
|
7474
|
+
function rowPrimaryIndex(r) {
|
|
7475
|
+
if (r.kind === "tool-group")
|
|
7476
|
+
return r.events[0].index;
|
|
7477
|
+
return r.event.index;
|
|
7478
|
+
}
|
|
7479
|
+
function buildMegaRows(rows) {
|
|
7480
|
+
const out = [];
|
|
7481
|
+
let buffer = [];
|
|
7482
|
+
let turnAnchor = null;
|
|
7483
|
+
const flush = () => {
|
|
7484
|
+
if (buffer.length === 0)
|
|
7485
|
+
return;
|
|
7486
|
+
let agentMessages = 0;
|
|
7487
|
+
let toolCalls = 0;
|
|
7488
|
+
let errors = 0;
|
|
7489
|
+
let firstAgentIndex;
|
|
7490
|
+
const toolMap = /* @__PURE__ */ new Map();
|
|
7491
|
+
const seenMsgIds = /* @__PURE__ */ new Set();
|
|
7492
|
+
const tokens = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
|
|
7493
|
+
for (let i = 0; i < buffer.length; i++) {
|
|
7494
|
+
const r = buffer[i];
|
|
7495
|
+
if (r.kind === "agent") {
|
|
7496
|
+
agentMessages++;
|
|
7497
|
+
if (firstAgentIndex === void 0)
|
|
7498
|
+
firstAgentIndex = i;
|
|
7499
|
+
const msgId = r.event.messageId;
|
|
7500
|
+
const usage2 = r.event.usage;
|
|
7501
|
+
if (msgId && !seenMsgIds.has(msgId) && usage2) {
|
|
7502
|
+
seenMsgIds.add(msgId);
|
|
7503
|
+
tokens.input += usage2.input;
|
|
7504
|
+
tokens.output += usage2.output;
|
|
7505
|
+
tokens.cacheRead += usage2.cacheRead;
|
|
7506
|
+
tokens.cacheWrite += usage2.cacheWrite;
|
|
7507
|
+
}
|
|
7508
|
+
} else if (r.kind === "tool-group") {
|
|
7509
|
+
toolCalls += r.count;
|
|
7510
|
+
for (const t of r.toolNames) {
|
|
7511
|
+
toolMap.set(t.name, (toolMap.get(t.name) ?? 0) + t.count);
|
|
7512
|
+
}
|
|
7513
|
+
} else if (r.kind === "error") {
|
|
7514
|
+
errors++;
|
|
7515
|
+
}
|
|
7516
|
+
}
|
|
7517
|
+
let finalAgentIndex;
|
|
7518
|
+
for (let i = buffer.length - 1; i >= 0; i--) {
|
|
7519
|
+
const r = buffer[i];
|
|
7520
|
+
if (r.kind !== "agent")
|
|
7521
|
+
continue;
|
|
7522
|
+
const prev = buffer[i - 1];
|
|
7523
|
+
if (prev?.kind === "task-notification")
|
|
7524
|
+
continue;
|
|
7525
|
+
finalAgentIndex = i;
|
|
7526
|
+
break;
|
|
7527
|
+
}
|
|
7528
|
+
if (finalAgentIndex === void 0) {
|
|
7529
|
+
for (let i = buffer.length - 1; i >= 0; i--) {
|
|
7530
|
+
if (buffer[i].kind === "agent") {
|
|
7531
|
+
finalAgentIndex = i;
|
|
7532
|
+
break;
|
|
7533
|
+
}
|
|
7534
|
+
}
|
|
7535
|
+
}
|
|
7536
|
+
const firstAgentPreview = firstAgentIndex !== void 0 && buffer[firstAgentIndex].kind === "agent" ? buffer[firstAgentIndex].event.preview : void 0;
|
|
7537
|
+
const finalAgentPreview = finalAgentIndex !== void 0 && buffer[finalAgentIndex].kind === "agent" ? buffer[finalAgentIndex].event.preview : void 0;
|
|
7538
|
+
const toolNames = Array.from(toolMap.entries()).sort((a, b) => b[1] - a[1]).map(([name, count]) => ({ name, count }));
|
|
7539
|
+
const first = buffer[0];
|
|
7540
|
+
const last = buffer[buffer.length - 1];
|
|
7541
|
+
const anchorOffset = turnAnchor?.tOffsetMs;
|
|
7542
|
+
const start2 = anchorOffset ?? first.tOffsetMs;
|
|
7543
|
+
const end = last.tOffsetMs;
|
|
7544
|
+
const durationMs = start2 !== void 0 && end !== void 0 && end >= start2 ? end - start2 : void 0;
|
|
7545
|
+
out.push({
|
|
7546
|
+
kind: "turn",
|
|
7547
|
+
rows: buffer,
|
|
7548
|
+
firstPrimaryIndex: rowPrimaryIndex(first),
|
|
7549
|
+
tOffsetMs: start2,
|
|
7550
|
+
durationMs,
|
|
7551
|
+
summary: {
|
|
7552
|
+
agentMessages,
|
|
7553
|
+
toolCalls,
|
|
7554
|
+
errors,
|
|
7555
|
+
firstAgentPreview,
|
|
7556
|
+
finalAgentPreview,
|
|
7557
|
+
firstAgentIndex,
|
|
7558
|
+
finalAgentIndex,
|
|
7559
|
+
toolNames,
|
|
7560
|
+
totalTokens: tokens
|
|
7494
7561
|
}
|
|
7495
7562
|
});
|
|
7496
|
-
|
|
7497
|
-
throw new UsageApiError(
|
|
7498
|
-
`Network error reaching Anthropic: ${err.message}`,
|
|
7499
|
-
"network"
|
|
7500
|
-
);
|
|
7501
|
-
}
|
|
7502
|
-
if (!res.ok) {
|
|
7503
|
-
throw new UsageApiError(
|
|
7504
|
-
`Usage endpoint returned ${res.status} ${res.statusText}`,
|
|
7505
|
-
"http"
|
|
7506
|
-
);
|
|
7507
|
-
}
|
|
7508
|
-
let body;
|
|
7509
|
-
try {
|
|
7510
|
-
body = await res.json();
|
|
7511
|
-
} catch (err) {
|
|
7512
|
-
throw new UsageApiError(`Failed to parse usage response: ${err.message}`, "parse");
|
|
7513
|
-
}
|
|
7514
|
-
const b = body;
|
|
7515
|
-
return {
|
|
7516
|
-
captured_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7517
|
-
agent: "claude-code",
|
|
7518
|
-
five_hour: normalizeWindow(b.five_hour) ?? { utilization: null, resets_at: null },
|
|
7519
|
-
seven_day: normalizeWindow(b.seven_day) ?? { utilization: null, resets_at: null },
|
|
7520
|
-
seven_day_opus: normalizeWindow(b.seven_day_opus),
|
|
7521
|
-
seven_day_sonnet: normalizeWindow(b.seven_day_sonnet),
|
|
7522
|
-
seven_day_oauth_apps: normalizeWindow(b.seven_day_oauth_apps),
|
|
7523
|
-
seven_day_cowork: normalizeWindow(b.seven_day_cowork),
|
|
7524
|
-
extra_usage: normalizeExtra(b.extra_usage),
|
|
7525
|
-
plan_type: null
|
|
7563
|
+
buffer = [];
|
|
7526
7564
|
};
|
|
7565
|
+
for (const r of rows) {
|
|
7566
|
+
if (r.kind === "user" || r.kind === "interrupt") {
|
|
7567
|
+
flush();
|
|
7568
|
+
out.push(r);
|
|
7569
|
+
turnAnchor = r;
|
|
7570
|
+
} else {
|
|
7571
|
+
buffer.push(r);
|
|
7572
|
+
}
|
|
7573
|
+
}
|
|
7574
|
+
flush();
|
|
7575
|
+
return out;
|
|
7527
7576
|
}
|
|
7528
|
-
function
|
|
7529
|
-
if (!
|
|
7530
|
-
|
|
7577
|
+
function parseTaskNotification(text) {
|
|
7578
|
+
if (!TASK_NOTIFICATION_RE.test(text))
|
|
7579
|
+
return null;
|
|
7580
|
+
const pick = (tag) => {
|
|
7581
|
+
const m = text.match(new RegExp(`<${tag}>([\\s\\S]*?)<\\/${tag}>`));
|
|
7582
|
+
return m ? m[1].trim() : void 0;
|
|
7583
|
+
};
|
|
7584
|
+
const statusRaw = (pick("status") ?? "").toLowerCase();
|
|
7585
|
+
let status2 = "unknown";
|
|
7586
|
+
if (statusRaw === "success" || statusRaw === "ok" || statusRaw === "done" || statusRaw === "completed")
|
|
7587
|
+
status2 = "success";
|
|
7588
|
+
else if (statusRaw === "failed" || statusRaw === "error" || statusRaw === "fail")
|
|
7589
|
+
status2 = "failed";
|
|
7590
|
+
else if (statusRaw === "running" || statusRaw === "in_progress")
|
|
7591
|
+
status2 = "running";
|
|
7531
7592
|
return {
|
|
7532
|
-
|
|
7533
|
-
|
|
7593
|
+
status: status2,
|
|
7594
|
+
summary: pick("summary") ?? "Background task notification",
|
|
7595
|
+
taskId: pick("task-id"),
|
|
7596
|
+
toolUseId: pick("tool-use-id"),
|
|
7597
|
+
outputFile: pick("output-file")
|
|
7534
7598
|
};
|
|
7535
7599
|
}
|
|
7536
|
-
function
|
|
7537
|
-
|
|
7538
|
-
const r = raw;
|
|
7539
|
-
return {
|
|
7540
|
-
is_enabled: r.is_enabled === true,
|
|
7541
|
-
monthly_limit: typeof r.monthly_limit === "number" ? r.monthly_limit : null,
|
|
7542
|
-
used_credits: typeof r.used_credits === "number" ? r.used_credits : null,
|
|
7543
|
-
utilization: typeof r.utilization === "number" ? r.utilization : null
|
|
7544
|
-
};
|
|
7600
|
+
function isAttachmentOrMeta(e) {
|
|
7601
|
+
return e.role === "system" || e.role === "meta";
|
|
7545
7602
|
}
|
|
7546
|
-
|
|
7547
|
-
|
|
7548
|
-
|
|
7549
|
-
|
|
7550
|
-
init_token();
|
|
7551
|
-
EXPIRY_SKEW_MS = 60 * 1e3;
|
|
7552
|
-
USAGE_ENDPOINT = "https://api.anthropic.com/api/oauth/usage";
|
|
7553
|
-
BETA_HEADER = "oauth-2025-04-20";
|
|
7554
|
-
UsageApiError = class extends Error {
|
|
7555
|
-
constructor(message, code) {
|
|
7556
|
-
super(message);
|
|
7557
|
-
this.code = code;
|
|
7558
|
-
}
|
|
7559
|
-
};
|
|
7603
|
+
function firstTextOfBlocks(blocks) {
|
|
7604
|
+
for (const b of blocks) {
|
|
7605
|
+
if (b?.type === "text")
|
|
7606
|
+
return b.text;
|
|
7560
7607
|
}
|
|
7561
|
-
|
|
7562
|
-
|
|
7563
|
-
// src/usage/grok.ts
|
|
7564
|
-
import { existsSync as existsSync8, readFileSync as readFileSync11 } from "node:fs";
|
|
7565
|
-
import os9 from "node:os";
|
|
7566
|
-
import path9 from "node:path";
|
|
7567
|
-
function grokHome() {
|
|
7568
|
-
return process.env.GROK_HOME || path9.join(os9.homedir(), ".grok");
|
|
7608
|
+
return void 0;
|
|
7569
7609
|
}
|
|
7570
|
-
function
|
|
7571
|
-
|
|
7610
|
+
function hasZeroUsage(e) {
|
|
7611
|
+
if (!e.usage)
|
|
7612
|
+
return false;
|
|
7613
|
+
const u = e.usage;
|
|
7614
|
+
return u.input === 0 && u.output === 0 && u.cacheRead === 0 && u.cacheWrite === 0;
|
|
7572
7615
|
}
|
|
7573
|
-
function
|
|
7574
|
-
const
|
|
7575
|
-
|
|
7576
|
-
|
|
7577
|
-
|
|
7578
|
-
|
|
7579
|
-
|
|
7580
|
-
|
|
7581
|
-
} catch {
|
|
7582
|
-
throw new GrokApiError("Grok auth.json is unreadable. Run `grok login`.", "no_auth");
|
|
7583
|
-
}
|
|
7584
|
-
for (const [entryKey2, entry] of Object.entries(raw)) {
|
|
7585
|
-
const token = typeof entry?.key === "string" ? entry.key.trim() : "";
|
|
7586
|
-
if (token) return { token, entry, entryKey: entryKey2 };
|
|
7616
|
+
function buildPresentation(events) {
|
|
7617
|
+
const byMessageId = /* @__PURE__ */ new Map();
|
|
7618
|
+
for (const e of events) {
|
|
7619
|
+
if (!e.messageId)
|
|
7620
|
+
continue;
|
|
7621
|
+
const list = byMessageId.get(e.messageId) ?? [];
|
|
7622
|
+
list.push(e);
|
|
7623
|
+
byMessageId.set(e.messageId, list);
|
|
7587
7624
|
}
|
|
7588
|
-
|
|
7589
|
-
|
|
7590
|
-
|
|
7591
|
-
|
|
7592
|
-
|
|
7593
|
-
|
|
7594
|
-
|
|
7595
|
-
|
|
7596
|
-
|
|
7597
|
-
|
|
7598
|
-
|
|
7599
|
-
|
|
7600
|
-
|
|
7601
|
-
|
|
7602
|
-
|
|
7603
|
-
|
|
7604
|
-
|
|
7625
|
+
const visible = events.filter((e) => {
|
|
7626
|
+
if (isAttachmentOrMeta(e))
|
|
7627
|
+
return false;
|
|
7628
|
+
if (e.role === "tool-result")
|
|
7629
|
+
return false;
|
|
7630
|
+
if (e.role === "agent-thinking")
|
|
7631
|
+
return false;
|
|
7632
|
+
if (e.role === "user") {
|
|
7633
|
+
const txt = firstTextOfBlocks(e.blocks) ?? "";
|
|
7634
|
+
if (e.blocks.length === 0 || !txt.trim())
|
|
7635
|
+
return false;
|
|
7636
|
+
if (SLASH_COMMAND_RE.test(txt))
|
|
7637
|
+
return true;
|
|
7638
|
+
if (TASK_NOTIFICATION_RE.test(txt))
|
|
7639
|
+
return true;
|
|
7640
|
+
if (isFrameworkInjectedUserInput(txt))
|
|
7641
|
+
return false;
|
|
7642
|
+
}
|
|
7643
|
+
return true;
|
|
7605
7644
|
});
|
|
7606
|
-
|
|
7607
|
-
|
|
7608
|
-
|
|
7609
|
-
|
|
7610
|
-
|
|
7611
|
-
|
|
7612
|
-
|
|
7613
|
-
|
|
7614
|
-
|
|
7615
|
-
|
|
7616
|
-
|
|
7617
|
-
|
|
7618
|
-
|
|
7619
|
-
|
|
7620
|
-
|
|
7621
|
-
|
|
7622
|
-
|
|
7623
|
-
|
|
7624
|
-
|
|
7625
|
-
|
|
7626
|
-
|
|
7627
|
-
|
|
7628
|
-
|
|
7629
|
-
|
|
7630
|
-
|
|
7631
|
-
|
|
7645
|
+
const rows = [];
|
|
7646
|
+
for (let i = 0; i < visible.length; i++) {
|
|
7647
|
+
const e = visible[i];
|
|
7648
|
+
if (e.role === "tool-call") {
|
|
7649
|
+
const start2 = i;
|
|
7650
|
+
while (i + 1 < visible.length && visible[i + 1].role === "tool-call") {
|
|
7651
|
+
i++;
|
|
7652
|
+
}
|
|
7653
|
+
const group = visible.slice(start2, i + 1);
|
|
7654
|
+
const order = [];
|
|
7655
|
+
const counts = /* @__PURE__ */ new Map();
|
|
7656
|
+
for (const ev of group) {
|
|
7657
|
+
const name = ev.toolName ?? "tool";
|
|
7658
|
+
if (!counts.has(name))
|
|
7659
|
+
order.push(name);
|
|
7660
|
+
counts.set(name, (counts.get(name) ?? 0) + 1);
|
|
7661
|
+
}
|
|
7662
|
+
const toolNames = order.map((name) => ({
|
|
7663
|
+
name,
|
|
7664
|
+
count: counts.get(name) ?? 1
|
|
7665
|
+
}));
|
|
7666
|
+
rows.push({
|
|
7667
|
+
kind: "tool-group",
|
|
7668
|
+
toolNames,
|
|
7669
|
+
count: group.length,
|
|
7670
|
+
events: group,
|
|
7671
|
+
tOffsetMs: group[0].tOffsetMs,
|
|
7672
|
+
gapMs: group[0].gapMs
|
|
7673
|
+
});
|
|
7674
|
+
continue;
|
|
7675
|
+
}
|
|
7676
|
+
if (e.role === "user") {
|
|
7677
|
+
const txt = firstTextOfBlocks(e.blocks) ?? "";
|
|
7678
|
+
const taskNotif = parseTaskNotification(txt);
|
|
7679
|
+
if (taskNotif) {
|
|
7680
|
+
rows.push({
|
|
7681
|
+
kind: "task-notification",
|
|
7682
|
+
event: e,
|
|
7683
|
+
status: taskNotif.status,
|
|
7684
|
+
summary: taskNotif.summary,
|
|
7685
|
+
taskId: taskNotif.taskId,
|
|
7686
|
+
toolUseId: taskNotif.toolUseId,
|
|
7687
|
+
outputFile: taskNotif.outputFile,
|
|
7688
|
+
tOffsetMs: e.tOffsetMs,
|
|
7689
|
+
gapMs: e.gapMs
|
|
7690
|
+
});
|
|
7691
|
+
continue;
|
|
7692
|
+
}
|
|
7693
|
+
if (INTERRUPT_RE.test(txt)) {
|
|
7694
|
+
rows.push({
|
|
7695
|
+
kind: "interrupt",
|
|
7696
|
+
event: e,
|
|
7697
|
+
tOffsetMs: e.tOffsetMs,
|
|
7698
|
+
gapMs: e.gapMs
|
|
7699
|
+
});
|
|
7700
|
+
continue;
|
|
7701
|
+
}
|
|
7702
|
+
const slashMatch = txt.match(SLASH_COMMAND_RE);
|
|
7703
|
+
if (slashMatch) {
|
|
7704
|
+
const cmd = slashMatch[1];
|
|
7705
|
+
const args2 = (slashMatch[2] ?? "").trim();
|
|
7706
|
+
const pretty = args2 ? `${cmd} ${args2}` : cmd;
|
|
7707
|
+
rows.push({
|
|
7708
|
+
kind: "user",
|
|
7709
|
+
event: e,
|
|
7710
|
+
displayPreview: pretty,
|
|
7711
|
+
displayBlocks: [{ type: "text", text: pretty }],
|
|
7712
|
+
tOffsetMs: e.tOffsetMs,
|
|
7713
|
+
gapMs: e.gapMs
|
|
7714
|
+
});
|
|
7715
|
+
continue;
|
|
7716
|
+
}
|
|
7717
|
+
rows.push({
|
|
7718
|
+
kind: "user",
|
|
7719
|
+
event: e,
|
|
7720
|
+
tOffsetMs: e.tOffsetMs,
|
|
7721
|
+
gapMs: e.gapMs
|
|
7722
|
+
});
|
|
7723
|
+
continue;
|
|
7724
|
+
}
|
|
7725
|
+
if (e.role === "agent") {
|
|
7726
|
+
const txt = firstTextOfBlocks(e.blocks) ?? "";
|
|
7727
|
+
if (hasZeroUsage(e)) {
|
|
7728
|
+
rows.push({
|
|
7729
|
+
kind: "model",
|
|
7730
|
+
event: e,
|
|
7731
|
+
tOffsetMs: e.tOffsetMs,
|
|
7732
|
+
gapMs: e.gapMs
|
|
7733
|
+
});
|
|
7734
|
+
if (RATE_LIMIT_RE.test(txt) && txt.length < 500) {
|
|
7735
|
+
rows.push({
|
|
7736
|
+
kind: "error",
|
|
7737
|
+
event: e,
|
|
7738
|
+
message: txt,
|
|
7739
|
+
tOffsetMs: e.tOffsetMs,
|
|
7740
|
+
gapMs: 0
|
|
7741
|
+
});
|
|
7632
7742
|
}
|
|
7743
|
+
continue;
|
|
7633
7744
|
}
|
|
7634
|
-
|
|
7635
|
-
|
|
7636
|
-
|
|
7745
|
+
if (RATE_LIMIT_RE.test(txt) && txt.length < 500) {
|
|
7746
|
+
rows.push({
|
|
7747
|
+
kind: "error",
|
|
7748
|
+
event: e,
|
|
7749
|
+
message: txt,
|
|
7750
|
+
tOffsetMs: e.tOffsetMs,
|
|
7751
|
+
gapMs: e.gapMs
|
|
7752
|
+
});
|
|
7753
|
+
continue;
|
|
7754
|
+
}
|
|
7755
|
+
const grouped = e.messageId ? byMessageId.get(e.messageId) ?? [e] : [e];
|
|
7756
|
+
rows.push({
|
|
7757
|
+
kind: "agent",
|
|
7758
|
+
event: e,
|
|
7759
|
+
groupedEvents: grouped,
|
|
7760
|
+
tOffsetMs: e.tOffsetMs,
|
|
7761
|
+
gapMs: e.gapMs
|
|
7762
|
+
});
|
|
7763
|
+
continue;
|
|
7637
7764
|
}
|
|
7638
|
-
return j.access_token;
|
|
7639
|
-
} catch {
|
|
7640
|
-
return null;
|
|
7641
7765
|
}
|
|
7766
|
+
return rows;
|
|
7642
7767
|
}
|
|
7643
|
-
|
|
7644
|
-
|
|
7645
|
-
|
|
7646
|
-
"
|
|
7647
|
-
|
|
7648
|
-
|
|
7649
|
-
|
|
7768
|
+
var INTERRUPT_RE, RATE_LIMIT_RE, SLASH_COMMAND_RE, TASK_NOTIFICATION_RE;
|
|
7769
|
+
var init_presentation = __esm({
|
|
7770
|
+
"../parser/dist/presentation.js"() {
|
|
7771
|
+
"use strict";
|
|
7772
|
+
init_user_input();
|
|
7773
|
+
INTERRUPT_RE = /\[request interrupted|interrupted by user/i;
|
|
7774
|
+
RATE_LIMIT_RE = /rate.?limit|overloaded_error|api error|Error sending message/i;
|
|
7775
|
+
SLASH_COMMAND_RE = /<command-name>(\/[^<\s]+)<\/command-name>(?:[\s\S]*?<command-args>([\s\S]*?)<\/command-args>)?/;
|
|
7776
|
+
TASK_NOTIFICATION_RE = /<task-notification>/;
|
|
7777
|
+
}
|
|
7778
|
+
});
|
|
7779
|
+
|
|
7780
|
+
// ../parser/dist/aggregate.js
|
|
7781
|
+
function isoDay(d) {
|
|
7782
|
+
return toLocalDay(d.getTime());
|
|
7650
7783
|
}
|
|
7651
|
-
function
|
|
7652
|
-
|
|
7653
|
-
|
|
7784
|
+
function rangeDays(start2, end) {
|
|
7785
|
+
const out = [];
|
|
7786
|
+
const cur = new Date(start2.getFullYear(), start2.getMonth(), start2.getDate());
|
|
7787
|
+
const stop2 = new Date(end.getFullYear(), end.getMonth(), end.getDate());
|
|
7788
|
+
while (cur.getTime() <= stop2.getTime()) {
|
|
7789
|
+
out.push(new Date(cur));
|
|
7790
|
+
cur.setDate(cur.getDate() + 1);
|
|
7654
7791
|
}
|
|
7655
|
-
|
|
7656
|
-
|
|
7657
|
-
|
|
7792
|
+
return out;
|
|
7793
|
+
}
|
|
7794
|
+
function calendarWeek(ref = /* @__PURE__ */ new Date()) {
|
|
7795
|
+
const d = new Date(ref.getFullYear(), ref.getMonth(), ref.getDate());
|
|
7796
|
+
const dow = d.getDay();
|
|
7797
|
+
const daysSinceMon = (dow + 6) % 7;
|
|
7798
|
+
const monday = new Date(d);
|
|
7799
|
+
monday.setDate(d.getDate() - daysSinceMon);
|
|
7800
|
+
const sunday = new Date(monday);
|
|
7801
|
+
sunday.setDate(monday.getDate() + 6);
|
|
7802
|
+
return { start: monday, end: sunday };
|
|
7803
|
+
}
|
|
7804
|
+
function priorCalendarWeek(ref = /* @__PURE__ */ new Date()) {
|
|
7805
|
+
const cur = calendarWeek(ref);
|
|
7806
|
+
const prevEnd = new Date(cur.start);
|
|
7807
|
+
prevEnd.setDate(cur.start.getDate() - 1);
|
|
7808
|
+
const prevStart = new Date(prevEnd);
|
|
7809
|
+
prevStart.setDate(prevEnd.getDate() - 6);
|
|
7810
|
+
return { start: prevStart, end: prevEnd };
|
|
7811
|
+
}
|
|
7812
|
+
function last4CompletedWeeks(ref = /* @__PURE__ */ new Date()) {
|
|
7813
|
+
const { end } = priorCalendarWeek(ref);
|
|
7814
|
+
const start2 = new Date(end);
|
|
7815
|
+
start2.setDate(end.getDate() - 27);
|
|
7816
|
+
return { start: start2, end };
|
|
7817
|
+
}
|
|
7818
|
+
function calendarMonth(ref = /* @__PURE__ */ new Date()) {
|
|
7819
|
+
const start2 = new Date(ref.getFullYear(), ref.getMonth(), 1);
|
|
7820
|
+
const end = new Date(ref.getFullYear(), ref.getMonth() + 1, 0);
|
|
7821
|
+
return { start: start2, end };
|
|
7822
|
+
}
|
|
7823
|
+
function priorCalendarMonth(ref = /* @__PURE__ */ new Date()) {
|
|
7824
|
+
const start2 = new Date(ref.getFullYear(), ref.getMonth() - 1, 1);
|
|
7825
|
+
const end = new Date(ref.getFullYear(), ref.getMonth(), 0);
|
|
7826
|
+
return { start: start2, end };
|
|
7827
|
+
}
|
|
7828
|
+
function aggregateConcurrency(bursts, period) {
|
|
7829
|
+
const days = rangeDays(period.start, period.end);
|
|
7830
|
+
const byDayKey = /* @__PURE__ */ new Map();
|
|
7831
|
+
for (const d of days)
|
|
7832
|
+
byDayKey.set(isoDay(d), { peak: 0, has_cross_project: false });
|
|
7833
|
+
for (const b of bursts) {
|
|
7834
|
+
const dayKey = isoDay(new Date(b.startMs));
|
|
7835
|
+
const cur = byDayKey.get(dayKey);
|
|
7836
|
+
if (!cur)
|
|
7837
|
+
continue;
|
|
7838
|
+
if (b.peak > cur.peak)
|
|
7839
|
+
cur.peak = b.peak;
|
|
7840
|
+
if (b.crossProject)
|
|
7841
|
+
cur.has_cross_project = true;
|
|
7658
7842
|
}
|
|
7659
|
-
const
|
|
7660
|
-
|
|
7661
|
-
|
|
7843
|
+
const by_day = days.map((d) => {
|
|
7844
|
+
const k = isoDay(d);
|
|
7845
|
+
const v = byDayKey.get(k);
|
|
7846
|
+
return { date: k, peak: v.peak, has_cross_project: v.has_cross_project };
|
|
7847
|
+
});
|
|
7848
|
+
let peak = 0;
|
|
7849
|
+
let peak_day;
|
|
7850
|
+
let multi_agent_days = 0;
|
|
7851
|
+
let cross_project_days = 0;
|
|
7852
|
+
for (const d of by_day) {
|
|
7853
|
+
if (d.peak > peak) {
|
|
7854
|
+
peak = d.peak;
|
|
7855
|
+
peak_day = d.date;
|
|
7856
|
+
}
|
|
7857
|
+
if (d.peak >= 3)
|
|
7858
|
+
multi_agent_days++;
|
|
7859
|
+
if (d.has_cross_project)
|
|
7860
|
+
cross_project_days++;
|
|
7662
7861
|
}
|
|
7663
|
-
|
|
7664
|
-
|
|
7665
|
-
|
|
7862
|
+
return { by_day, peak, peak_day, multi_agent_days, cross_project_days };
|
|
7863
|
+
}
|
|
7864
|
+
var init_aggregate = __esm({
|
|
7865
|
+
"../parser/dist/aggregate.js"() {
|
|
7866
|
+
"use strict";
|
|
7867
|
+
init_analytics();
|
|
7666
7868
|
}
|
|
7667
|
-
|
|
7668
|
-
|
|
7669
|
-
|
|
7670
|
-
|
|
7671
|
-
|
|
7672
|
-
|
|
7673
|
-
|
|
7869
|
+
});
|
|
7870
|
+
|
|
7871
|
+
// ../parser/dist/index.js
|
|
7872
|
+
var dist_exports = {};
|
|
7873
|
+
__export(dist_exports, {
|
|
7874
|
+
ANTIGRAVITY_METADATA: () => ANTIGRAVITY_METADATA,
|
|
7875
|
+
CLAUDE_CODE_METADATA: () => CLAUDE_CODE_METADATA,
|
|
7876
|
+
CODEX_METADATA: () => CODEX_METADATA,
|
|
7877
|
+
COPILOT_METADATA: () => COPILOT_METADATA,
|
|
7878
|
+
COWORK_METADATA: () => COWORK_METADATA,
|
|
7879
|
+
GEMINI_METADATA: () => GEMINI_METADATA,
|
|
7880
|
+
GROK_METADATA: () => GROK_METADATA,
|
|
7881
|
+
PRICES: () => PRICES,
|
|
7882
|
+
RATE_PER_PCT: () => RATE_PER_PCT,
|
|
7883
|
+
RATE_PER_PCT_5H: () => RATE_PER_PCT_5H,
|
|
7884
|
+
RATE_PER_PCT_7D: () => RATE_PER_PCT_7D,
|
|
7885
|
+
ZAI_METADATA: () => ZAI_METADATA,
|
|
7886
|
+
agentMetadata: () => agentMetadata,
|
|
7887
|
+
aggregateConcurrency: () => aggregateConcurrency,
|
|
7888
|
+
buildGanttDay: () => buildGanttDay,
|
|
7889
|
+
buildMegaRows: () => buildMegaRows,
|
|
7890
|
+
buildPresentation: () => buildPresentation,
|
|
7891
|
+
buildProjectKeyResolver: () => buildProjectKeyResolver,
|
|
7892
|
+
buildSpendIndex: () => buildSpendIndex,
|
|
7893
|
+
calendarMonth: () => calendarMonth,
|
|
7894
|
+
calendarWeek: () => calendarWeek,
|
|
7895
|
+
canonicalProjectName: () => canonicalProjectName,
|
|
7896
|
+
collectSnapPairRates: () => collectSnapPairRates,
|
|
7897
|
+
computeActiveSegments: () => computeActiveSegments,
|
|
7898
|
+
computeBurstsFromSessions: () => computeBurstsFromSessions,
|
|
7899
|
+
computeParallelism: () => computeParallelism,
|
|
7900
|
+
computeParallelismBursts: () => computeParallelismBursts,
|
|
7901
|
+
dailyActivity: () => dailyActivity,
|
|
7902
|
+
daysBetween: () => daysBetween,
|
|
7903
|
+
detectParallelRuns: () => detectParallelRuns,
|
|
7904
|
+
detectPrMarkers: () => detectPrMarkers,
|
|
7905
|
+
dollarsInRange: () => dollarsInRange,
|
|
7906
|
+
eventDollars: () => eventDollars,
|
|
7907
|
+
getAgentMetadata: () => getAgentMetadata,
|
|
7908
|
+
groupByProject: () => groupByProject,
|
|
7909
|
+
groupByTeam: () => groupByTeam,
|
|
7910
|
+
groupSnapsByCycle: () => groupSnapsByCycle,
|
|
7911
|
+
highLevelMetrics: () => highLevelMetrics,
|
|
7912
|
+
isAgentKind: () => isAgentKind,
|
|
7913
|
+
isFrameworkInjectedUserInput: () => isFrameworkInjectedUserInput,
|
|
7914
|
+
last4CompletedWeeks: () => last4CompletedWeeks,
|
|
7915
|
+
modelFamily: () => modelFamily,
|
|
7916
|
+
parseTranscript: () => parseTranscript,
|
|
7917
|
+
predictAnchored: () => predictAnchored,
|
|
7918
|
+
priorCalendarMonth: () => priorCalendarMonth,
|
|
7919
|
+
priorCalendarWeek: () => priorCalendarWeek,
|
|
7920
|
+
projectKey: () => projectKey,
|
|
7921
|
+
projectRepoName: () => projectRepoName,
|
|
7922
|
+
rowPrimaryIndex: () => rowPrimaryIndex,
|
|
7923
|
+
sessionAirTimeMs: () => sessionAirTimeMs,
|
|
7924
|
+
sessionDay: () => sessionDay,
|
|
7925
|
+
sessionProjectKey: () => sessionProjectKey,
|
|
7926
|
+
stripFrameworkBoilerplate: () => stripFrameworkBoilerplate,
|
|
7927
|
+
summarizeBursts: () => summarizeBursts,
|
|
7928
|
+
toLocalDay: () => toLocalDay,
|
|
7929
|
+
userSoloRate: () => userSoloRate,
|
|
7930
|
+
worktreeName: () => worktreeName
|
|
7931
|
+
});
|
|
7932
|
+
var init_dist = __esm({
|
|
7933
|
+
"../parser/dist/index.js"() {
|
|
7934
|
+
"use strict";
|
|
7935
|
+
init_types();
|
|
7936
|
+
init_parser();
|
|
7937
|
+
init_user_input();
|
|
7938
|
+
init_presentation();
|
|
7939
|
+
init_analytics();
|
|
7940
|
+
init_aggregate();
|
|
7941
|
+
init_calibration();
|
|
7942
|
+
init_agent_metadata();
|
|
7943
|
+
init_team();
|
|
7674
7944
|
}
|
|
7675
|
-
|
|
7676
|
-
|
|
7677
|
-
|
|
7678
|
-
|
|
7679
|
-
|
|
7680
|
-
|
|
7945
|
+
});
|
|
7946
|
+
|
|
7947
|
+
// src/args.ts
|
|
7948
|
+
function flag(args2, name) {
|
|
7949
|
+
const idx = args2.indexOf(name);
|
|
7950
|
+
return idx === -1 ? void 0 : args2[idx + 1];
|
|
7951
|
+
}
|
|
7952
|
+
var init_args = __esm({
|
|
7953
|
+
"src/args.ts"() {
|
|
7954
|
+
"use strict";
|
|
7681
7955
|
}
|
|
7682
|
-
|
|
7683
|
-
|
|
7684
|
-
|
|
7685
|
-
|
|
7686
|
-
|
|
7687
|
-
|
|
7956
|
+
});
|
|
7957
|
+
|
|
7958
|
+
// src/usage/token.ts
|
|
7959
|
+
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
7960
|
+
import { readFileSync as readFileSync10 } from "node:fs";
|
|
7961
|
+
import { homedir as homedir4, platform } from "node:os";
|
|
7962
|
+
import { join as join7 } from "node:path";
|
|
7963
|
+
function readOAuthCredentials() {
|
|
7964
|
+
if (platform() === "darwin") {
|
|
7965
|
+
return readFromMacKeychain() ?? readFromCredentialsFile();
|
|
7966
|
+
}
|
|
7967
|
+
return readFromCredentialsFile();
|
|
7688
7968
|
}
|
|
7689
|
-
|
|
7690
|
-
let res;
|
|
7969
|
+
function readFromMacKeychain() {
|
|
7691
7970
|
try {
|
|
7692
|
-
|
|
7693
|
-
|
|
7694
|
-
|
|
7695
|
-
|
|
7696
|
-
"network"
|
|
7971
|
+
const blob = execFileSync2(
|
|
7972
|
+
"security",
|
|
7973
|
+
["find-generic-password", "-s", "Claude Code-credentials", "-w"],
|
|
7974
|
+
{ stdio: ["ignore", "pipe", "ignore"], encoding: "utf8" }
|
|
7697
7975
|
);
|
|
7698
|
-
|
|
7699
|
-
let body = null;
|
|
7700
|
-
try {
|
|
7701
|
-
body = await res.json();
|
|
7976
|
+
return extractCredentials(blob);
|
|
7702
7977
|
} catch {
|
|
7978
|
+
return null;
|
|
7703
7979
|
}
|
|
7704
|
-
return { status: res.status, body };
|
|
7705
7980
|
}
|
|
7706
|
-
|
|
7707
|
-
const
|
|
7708
|
-
|
|
7709
|
-
|
|
7710
|
-
|
|
7711
|
-
|
|
7712
|
-
|
|
7713
|
-
|
|
7714
|
-
|
|
7715
|
-
|
|
7716
|
-
|
|
7717
|
-
if (refreshed) {
|
|
7718
|
-
token = refreshed;
|
|
7719
|
-
({ status: status2, body } = await fetchJson(CREDITS_URL, token));
|
|
7981
|
+
function readFromCredentialsFile() {
|
|
7982
|
+
const candidates = [
|
|
7983
|
+
join7(homedir4(), ".claude", ".credentials.json"),
|
|
7984
|
+
join7(homedir4(), ".config", "claude", "credentials.json")
|
|
7985
|
+
];
|
|
7986
|
+
for (const path11 of candidates) {
|
|
7987
|
+
try {
|
|
7988
|
+
const blob = readFileSync10(path11, "utf8");
|
|
7989
|
+
const creds = extractCredentials(blob);
|
|
7990
|
+
if (creds) return creds;
|
|
7991
|
+
} catch {
|
|
7720
7992
|
}
|
|
7721
7993
|
}
|
|
7722
|
-
|
|
7723
|
-
|
|
7724
|
-
|
|
7725
|
-
|
|
7994
|
+
return null;
|
|
7995
|
+
}
|
|
7996
|
+
function extractCredentials(blob) {
|
|
7997
|
+
try {
|
|
7998
|
+
const parsed = JSON.parse(blob);
|
|
7999
|
+
const oauth = parsed.claudeAiOauth;
|
|
8000
|
+
if (!oauth) return null;
|
|
8001
|
+
const accessToken = typeof oauth.accessToken === "string" ? oauth.accessToken : null;
|
|
8002
|
+
const expiresAt = typeof oauth.expiresAt === "number" ? oauth.expiresAt : null;
|
|
8003
|
+
if (!accessToken || expiresAt === null) return null;
|
|
8004
|
+
return { accessToken, expiresAt };
|
|
8005
|
+
} catch {
|
|
8006
|
+
return null;
|
|
8007
|
+
}
|
|
8008
|
+
}
|
|
8009
|
+
var init_token = __esm({
|
|
8010
|
+
"src/usage/token.ts"() {
|
|
8011
|
+
"use strict";
|
|
8012
|
+
}
|
|
8013
|
+
});
|
|
8014
|
+
|
|
8015
|
+
// src/usage/api.ts
|
|
8016
|
+
var api_exports = {};
|
|
8017
|
+
__export(api_exports, {
|
|
8018
|
+
UsageApiError: () => UsageApiError,
|
|
8019
|
+
fetchUsage: () => fetchUsage
|
|
8020
|
+
});
|
|
8021
|
+
async function fetchUsage() {
|
|
8022
|
+
const creds = readOAuthCredentials();
|
|
8023
|
+
if (!creds) {
|
|
8024
|
+
throw new UsageApiError(
|
|
8025
|
+
"No Claude Code OAuth token found. Run `claude` to log in first.",
|
|
8026
|
+
"no_token"
|
|
7726
8027
|
);
|
|
7727
8028
|
}
|
|
7728
|
-
|
|
7729
|
-
|
|
7730
|
-
|
|
7731
|
-
|
|
7732
|
-
"not_weekly"
|
|
8029
|
+
if (creds.expiresAt - EXPIRY_SKEW_MS <= Date.now()) {
|
|
8030
|
+
throw new UsageApiError(
|
|
8031
|
+
"Claude Code OAuth token expired. Open Claude Code to refresh it.",
|
|
8032
|
+
"expired"
|
|
7733
8033
|
);
|
|
7734
8034
|
}
|
|
7735
|
-
let
|
|
8035
|
+
let res;
|
|
7736
8036
|
try {
|
|
7737
|
-
|
|
7738
|
-
|
|
7739
|
-
|
|
7740
|
-
|
|
7741
|
-
|
|
7742
|
-
|
|
8037
|
+
res = await fetch(USAGE_ENDPOINT, {
|
|
8038
|
+
headers: {
|
|
8039
|
+
Authorization: `Bearer ${creds.accessToken}`,
|
|
8040
|
+
"anthropic-beta": BETA_HEADER
|
|
8041
|
+
}
|
|
8042
|
+
});
|
|
8043
|
+
} catch (err) {
|
|
8044
|
+
throw new UsageApiError(
|
|
8045
|
+
`Network error reaching Anthropic: ${err.message}`,
|
|
8046
|
+
"network"
|
|
8047
|
+
);
|
|
8048
|
+
}
|
|
8049
|
+
if (!res.ok) {
|
|
8050
|
+
throw new UsageApiError(
|
|
8051
|
+
`Usage endpoint returned ${res.status} ${res.statusText}`,
|
|
8052
|
+
"http"
|
|
8053
|
+
);
|
|
8054
|
+
}
|
|
8055
|
+
let body;
|
|
8056
|
+
try {
|
|
8057
|
+
body = await res.json();
|
|
8058
|
+
} catch (err) {
|
|
8059
|
+
throw new UsageApiError(`Failed to parse usage response: ${err.message}`, "parse");
|
|
7743
8060
|
}
|
|
8061
|
+
const b = body;
|
|
7744
8062
|
return {
|
|
7745
8063
|
captured_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7746
|
-
agent: "
|
|
7747
|
-
|
|
7748
|
-
|
|
7749
|
-
|
|
7750
|
-
|
|
7751
|
-
|
|
7752
|
-
|
|
7753
|
-
|
|
7754
|
-
|
|
7755
|
-
seven_day_oauth_apps: null,
|
|
7756
|
-
seven_day_cowork: null,
|
|
7757
|
-
extra_usage: null,
|
|
7758
|
-
plan_type: planType
|
|
8064
|
+
agent: "claude-code",
|
|
8065
|
+
five_hour: normalizeWindow(b.five_hour) ?? { utilization: null, resets_at: null },
|
|
8066
|
+
seven_day: normalizeWindow(b.seven_day) ?? { utilization: null, resets_at: null },
|
|
8067
|
+
seven_day_opus: normalizeWindow(b.seven_day_opus),
|
|
8068
|
+
seven_day_sonnet: normalizeWindow(b.seven_day_sonnet),
|
|
8069
|
+
seven_day_oauth_apps: normalizeWindow(b.seven_day_oauth_apps),
|
|
8070
|
+
seven_day_cowork: normalizeWindow(b.seven_day_cowork),
|
|
8071
|
+
extra_usage: normalizeExtra(b.extra_usage),
|
|
8072
|
+
plan_type: null
|
|
7759
8073
|
};
|
|
7760
8074
|
}
|
|
7761
|
-
|
|
7762
|
-
|
|
7763
|
-
|
|
8075
|
+
function normalizeWindow(raw) {
|
|
8076
|
+
if (!raw || typeof raw !== "object") return null;
|
|
8077
|
+
const r = raw;
|
|
8078
|
+
return {
|
|
8079
|
+
utilization: typeof r.utilization === "number" ? r.utilization : null,
|
|
8080
|
+
resets_at: typeof r.resets_at === "string" ? r.resets_at : null
|
|
8081
|
+
};
|
|
8082
|
+
}
|
|
8083
|
+
function normalizeExtra(raw) {
|
|
8084
|
+
if (!raw || typeof raw !== "object") return null;
|
|
8085
|
+
const r = raw;
|
|
8086
|
+
return {
|
|
8087
|
+
is_enabled: r.is_enabled === true,
|
|
8088
|
+
monthly_limit: typeof r.monthly_limit === "number" ? r.monthly_limit : null,
|
|
8089
|
+
used_credits: typeof r.used_credits === "number" ? r.used_credits : null,
|
|
8090
|
+
utilization: typeof r.utilization === "number" ? r.utilization : null
|
|
8091
|
+
};
|
|
8092
|
+
}
|
|
8093
|
+
var EXPIRY_SKEW_MS, USAGE_ENDPOINT, BETA_HEADER, UsageApiError;
|
|
8094
|
+
var init_api = __esm({
|
|
8095
|
+
"src/usage/api.ts"() {
|
|
7764
8096
|
"use strict";
|
|
7765
|
-
|
|
7766
|
-
|
|
7767
|
-
|
|
7768
|
-
|
|
7769
|
-
|
|
7770
|
-
WEEKLY_PERIOD = "USAGE_PERIOD_TYPE_WEEKLY";
|
|
7771
|
-
REFRESH_BUFFER_MS = 5 * 60 * 1e3;
|
|
7772
|
-
GrokApiError = class extends Error {
|
|
8097
|
+
init_token();
|
|
8098
|
+
EXPIRY_SKEW_MS = 60 * 1e3;
|
|
8099
|
+
USAGE_ENDPOINT = "https://api.anthropic.com/api/oauth/usage";
|
|
8100
|
+
BETA_HEADER = "oauth-2025-04-20";
|
|
8101
|
+
UsageApiError = class extends Error {
|
|
7773
8102
|
constructor(message, code) {
|
|
7774
8103
|
super(message);
|
|
7775
8104
|
this.code = code;
|
|
@@ -7778,90 +8107,52 @@ var init_grok2 = __esm({
|
|
|
7778
8107
|
}
|
|
7779
8108
|
});
|
|
7780
8109
|
|
|
7781
|
-
// src/usage/
|
|
7782
|
-
import {
|
|
7783
|
-
|
|
7784
|
-
|
|
7785
|
-
|
|
7786
|
-
|
|
7787
|
-
import os10 from "node:os";
|
|
7788
|
-
import path10 from "node:path";
|
|
7789
|
-
function codexHome() {
|
|
7790
|
-
const env = process.env.CODEX_HOME?.trim();
|
|
7791
|
-
if (env) return env;
|
|
7792
|
-
return path10.join(os10.homedir(), ".codex");
|
|
8110
|
+
// src/usage/grok.ts
|
|
8111
|
+
import { existsSync as existsSync8, readFileSync as readFileSync11 } from "node:fs";
|
|
8112
|
+
import os9 from "node:os";
|
|
8113
|
+
import path9 from "node:path";
|
|
8114
|
+
function grokHome() {
|
|
8115
|
+
return process.env.GROK_HOME || path9.join(os9.homedir(), ".grok");
|
|
7793
8116
|
}
|
|
7794
|
-
function
|
|
7795
|
-
return
|
|
8117
|
+
function authPath() {
|
|
8118
|
+
return path9.join(grokHome(), "auth.json");
|
|
7796
8119
|
}
|
|
7797
|
-
function
|
|
7798
|
-
const p =
|
|
7799
|
-
if (!
|
|
7800
|
-
throw new
|
|
7801
|
-
"Codex not logged in. Run `codex` to authenticate.",
|
|
7802
|
-
"no_auth"
|
|
7803
|
-
);
|
|
8120
|
+
function loadAuthEntry() {
|
|
8121
|
+
const p = authPath();
|
|
8122
|
+
if (!existsSync8(p)) {
|
|
8123
|
+
throw new GrokApiError("Grok not logged in. Run `grok login`.", "no_auth");
|
|
7804
8124
|
}
|
|
7805
|
-
let
|
|
8125
|
+
let raw;
|
|
7806
8126
|
try {
|
|
7807
|
-
|
|
8127
|
+
raw = JSON.parse(readFileSync11(p, "utf8"));
|
|
7808
8128
|
} catch {
|
|
7809
|
-
throw new
|
|
7810
|
-
"Codex auth.json is unreadable. Run `codex` to log in again.",
|
|
7811
|
-
"no_auth"
|
|
7812
|
-
);
|
|
7813
|
-
}
|
|
7814
|
-
const access = auth.tokens?.access_token?.trim();
|
|
7815
|
-
if (!access) {
|
|
7816
|
-
if (auth.OPENAI_API_KEY?.trim()) {
|
|
7817
|
-
throw new CodexApiError(
|
|
7818
|
-
"Codex usage is not available for API-key-only auth. Sign in with a ChatGPT account via `codex`.",
|
|
7819
|
-
"api_key_only"
|
|
7820
|
-
);
|
|
7821
|
-
}
|
|
7822
|
-
throw new CodexApiError(
|
|
7823
|
-
"Codex auth has no access token. Run `codex` to log in.",
|
|
7824
|
-
"no_auth"
|
|
7825
|
-
);
|
|
8129
|
+
throw new GrokApiError("Grok auth.json is unreadable. Run `grok login`.", "no_auth");
|
|
7826
8130
|
}
|
|
7827
|
-
|
|
7828
|
-
|
|
7829
|
-
|
|
7830
|
-
const parts = token.split(".");
|
|
7831
|
-
if (parts.length < 2) return null;
|
|
7832
|
-
try {
|
|
7833
|
-
const pad2 = "=".repeat((4 - parts[1].length % 4) % 4);
|
|
7834
|
-
const json = Buffer.from(parts[1] + pad2, "base64url").toString("utf8");
|
|
7835
|
-
const payload = JSON.parse(json);
|
|
7836
|
-
if (typeof payload.exp !== "number" || !Number.isFinite(payload.exp)) {
|
|
7837
|
-
return null;
|
|
7838
|
-
}
|
|
7839
|
-
return payload.exp * 1e3;
|
|
7840
|
-
} catch {
|
|
7841
|
-
return null;
|
|
8131
|
+
for (const [entryKey2, entry] of Object.entries(raw)) {
|
|
8132
|
+
const token = typeof entry?.key === "string" ? entry.key.trim() : "";
|
|
8133
|
+
if (token) return { token, entry, entryKey: entryKey2 };
|
|
7842
8134
|
}
|
|
8135
|
+
throw new GrokApiError("Grok auth has no access token. Run `grok login`.", "no_auth");
|
|
7843
8136
|
}
|
|
7844
|
-
function
|
|
7845
|
-
const
|
|
7846
|
-
if (
|
|
7847
|
-
|
|
7848
|
-
}
|
|
7849
|
-
if (!lastRefresh) return false;
|
|
7850
|
-
const ms = Date.parse(lastRefresh);
|
|
8137
|
+
function needsRefresh(entry) {
|
|
8138
|
+
const exp = entry.expires_at;
|
|
8139
|
+
if (!exp) return false;
|
|
8140
|
+
const ms = Date.parse(exp);
|
|
7851
8141
|
if (!Number.isFinite(ms)) return false;
|
|
7852
|
-
return
|
|
8142
|
+
return Date.now() >= ms - REFRESH_BUFFER_MS;
|
|
7853
8143
|
}
|
|
7854
|
-
async function
|
|
7855
|
-
const refresh =
|
|
8144
|
+
async function refreshAccessToken(entry) {
|
|
8145
|
+
const refresh = entry.refresh_token?.trim();
|
|
7856
8146
|
if (!refresh) return null;
|
|
8147
|
+
const clientId = entry.oidc_client_id?.trim() || DEFAULT_CLIENT_ID;
|
|
7857
8148
|
const body = new URLSearchParams({
|
|
7858
8149
|
grant_type: "refresh_token",
|
|
7859
|
-
client_id:
|
|
8150
|
+
client_id: clientId,
|
|
7860
8151
|
refresh_token: refresh
|
|
7861
8152
|
});
|
|
7862
8153
|
let res;
|
|
7863
8154
|
try {
|
|
7864
|
-
res = await fetch(
|
|
8155
|
+
res = await fetch(REFRESH_URL, {
|
|
7865
8156
|
method: "POST",
|
|
7866
8157
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
7867
8158
|
body: body.toString()
|
|
@@ -7873,189 +8164,159 @@ async function refreshAccessToken2(auth, filePath) {
|
|
|
7873
8164
|
try {
|
|
7874
8165
|
const j = await res.json();
|
|
7875
8166
|
if (typeof j.access_token !== "string" || !j.access_token) return null;
|
|
7876
|
-
const next = {
|
|
7877
|
-
...auth,
|
|
7878
|
-
tokens: {
|
|
7879
|
-
...auth.tokens,
|
|
7880
|
-
access_token: j.access_token,
|
|
7881
|
-
refresh_token: j.refresh_token ?? auth.tokens?.refresh_token,
|
|
7882
|
-
id_token: j.id_token ?? auth.tokens?.id_token
|
|
7883
|
-
},
|
|
7884
|
-
last_refresh: (/* @__PURE__ */ new Date()).toISOString()
|
|
7885
|
-
};
|
|
7886
8167
|
try {
|
|
7887
|
-
|
|
7888
|
-
|
|
7889
|
-
|
|
7890
|
-
|
|
7891
|
-
|
|
8168
|
+
const p = authPath();
|
|
8169
|
+
const raw = JSON.parse(readFileSync11(p, "utf8"));
|
|
8170
|
+
for (const key of Object.keys(raw)) {
|
|
8171
|
+
if (raw[key]?.key === entry.key || raw[key]?.refresh_token === refresh) {
|
|
8172
|
+
raw[key] = {
|
|
8173
|
+
...raw[key],
|
|
8174
|
+
key: j.access_token,
|
|
8175
|
+
refresh_token: j.refresh_token ?? raw[key].refresh_token,
|
|
8176
|
+
expires_at: typeof j.expires_in === "number" ? new Date(Date.now() + j.expires_in * 1e3).toISOString() : raw[key].expires_at
|
|
8177
|
+
};
|
|
8178
|
+
break;
|
|
8179
|
+
}
|
|
8180
|
+
}
|
|
8181
|
+
const { writeFileSync: writeFileSync18 } = await import("node:fs");
|
|
8182
|
+
writeFileSync18(p, JSON.stringify(raw, null, 2), "utf8");
|
|
7892
8183
|
} catch {
|
|
7893
8184
|
}
|
|
7894
|
-
return
|
|
8185
|
+
return j.access_token;
|
|
7895
8186
|
} catch {
|
|
7896
8187
|
return null;
|
|
7897
8188
|
}
|
|
7898
8189
|
}
|
|
7899
|
-
function
|
|
7900
|
-
|
|
7901
|
-
Authorization: `Bearer ${
|
|
8190
|
+
function authHeaders(token) {
|
|
8191
|
+
return {
|
|
8192
|
+
Authorization: `Bearer ${token.trim()}`,
|
|
8193
|
+
"X-XAI-Token-Auth": TOKEN_AUTH,
|
|
7902
8194
|
Accept: "application/json",
|
|
7903
8195
|
"User-Agent": "fleetlens"
|
|
7904
8196
|
};
|
|
7905
|
-
if (accountId?.trim()) {
|
|
7906
|
-
headers["ChatGPT-Account-Id"] = accountId.trim();
|
|
7907
|
-
}
|
|
7908
|
-
return headers;
|
|
7909
8197
|
}
|
|
7910
|
-
function
|
|
7911
|
-
if (typeof
|
|
7912
|
-
|
|
7913
|
-
const n = Number(v);
|
|
7914
|
-
if (Number.isFinite(n)) return n;
|
|
8198
|
+
function parseGrokCreditsConfig(body) {
|
|
8199
|
+
if (!body || typeof body !== "object") {
|
|
8200
|
+
throw new GrokApiError("Grok billing response missing body", "parse");
|
|
7915
8201
|
}
|
|
7916
|
-
|
|
7917
|
-
|
|
7918
|
-
|
|
7919
|
-
if (!raw) return void 0;
|
|
7920
|
-
const sec = numberOf3(raw.limit_window_seconds);
|
|
7921
|
-
if (sec !== void 0) return sec;
|
|
7922
|
-
const minutes = numberOf3(raw.window_minutes);
|
|
7923
|
-
if (minutes !== void 0) return minutes * 60;
|
|
7924
|
-
return void 0;
|
|
7925
|
-
}
|
|
7926
|
-
function normalizeWindow2(raw, headerPercent, nowMs) {
|
|
7927
|
-
const used = numberOf3(raw?.used_percent) ?? headerPercent;
|
|
7928
|
-
if (used === void 0) return null;
|
|
7929
|
-
let resetsAt = null;
|
|
7930
|
-
const resetUnix = numberOf3(raw?.reset_at) ?? numberOf3(raw?.resets_at);
|
|
7931
|
-
if (resetUnix !== void 0) {
|
|
7932
|
-
resetsAt = new Date(resetUnix * 1e3).toISOString();
|
|
7933
|
-
} else {
|
|
7934
|
-
const after = numberOf3(raw?.reset_after_seconds);
|
|
7935
|
-
if (after !== void 0) {
|
|
7936
|
-
resetsAt = new Date(nowMs + after * 1e3).toISOString();
|
|
7937
|
-
}
|
|
8202
|
+
const config = body.config;
|
|
8203
|
+
if (!config || typeof config !== "object") {
|
|
8204
|
+
throw new GrokApiError("Grok billing response missing config", "parse");
|
|
7938
8205
|
}
|
|
7939
|
-
|
|
7940
|
-
|
|
7941
|
-
|
|
7942
|
-
};
|
|
7943
|
-
}
|
|
7944
|
-
function parseCodexWhamUsage(body, headers = {}, nowMs = Date.now()) {
|
|
7945
|
-
if (!body || typeof body !== "object") {
|
|
7946
|
-
throw new CodexApiError("Codex usage response missing body", "parse");
|
|
8206
|
+
const period = config.currentPeriod;
|
|
8207
|
+
if (!period || typeof period !== "object") {
|
|
8208
|
+
throw new GrokApiError("Grok billing response missing currentPeriod", "parse");
|
|
7947
8209
|
}
|
|
7948
|
-
const
|
|
7949
|
-
|
|
7950
|
-
|
|
7951
|
-
const headerSecondary = numberOf3(headers["x-codex-secondary-used-percent"]);
|
|
7952
|
-
const primary = rateLimit.primary_window && typeof rateLimit.primary_window === "object" ? rateLimit.primary_window : null;
|
|
7953
|
-
const secondary = rateLimit.secondary_window && typeof rateLimit.secondary_window === "object" ? rateLimit.secondary_window : null;
|
|
7954
|
-
const candidates = [
|
|
7955
|
-
{ raw: primary, headerPercent: headerPrimary, fallback: "five_hour" },
|
|
7956
|
-
{ raw: secondary, headerPercent: headerSecondary, fallback: "seven_day" }
|
|
7957
|
-
];
|
|
7958
|
-
let fiveHour = null;
|
|
7959
|
-
let sevenDay = null;
|
|
7960
|
-
for (const c of candidates) {
|
|
7961
|
-
const secs = windowSeconds(c.raw);
|
|
7962
|
-
const window = normalizeWindow2(c.raw, c.headerPercent, nowMs);
|
|
7963
|
-
if (!window) continue;
|
|
7964
|
-
if (secs === FIVE_HOUR_SECONDS) fiveHour = window;
|
|
7965
|
-
else if (secs === SEVEN_DAY_SECONDS) sevenDay = window;
|
|
8210
|
+
const periodType = typeof period.type === "string" ? period.type.trim() : "";
|
|
8211
|
+
if (!periodType) {
|
|
8212
|
+
throw new GrokApiError("Grok billing period type missing", "parse");
|
|
7966
8213
|
}
|
|
7967
|
-
|
|
7968
|
-
|
|
7969
|
-
|
|
7970
|
-
|
|
7971
|
-
|
|
7972
|
-
if (!window) continue;
|
|
7973
|
-
if (c.fallback === "five_hour" && !fiveHour) fiveHour = window;
|
|
7974
|
-
else if (c.fallback === "seven_day" && !sevenDay) sevenDay = window;
|
|
8214
|
+
let utilization = 0;
|
|
8215
|
+
if (config.creditUsagePercent !== void 0 && config.creditUsagePercent !== null) {
|
|
8216
|
+
const n = Number(config.creditUsagePercent);
|
|
8217
|
+
if (!Number.isFinite(n)) {
|
|
8218
|
+
throw new GrokApiError("Grok creditUsagePercent is not a number", "parse");
|
|
7975
8219
|
}
|
|
8220
|
+
utilization = Math.min(100, Math.max(0, n));
|
|
8221
|
+
}
|
|
8222
|
+
const end = typeof period.end === "string" && period.end ? new Date(period.end).toISOString() : null;
|
|
8223
|
+
let onDemandCap = 0;
|
|
8224
|
+
const cap = config.onDemandCap;
|
|
8225
|
+
if (cap && typeof cap === "object" && "val" in cap) {
|
|
8226
|
+
const v = Number(cap.val);
|
|
8227
|
+
if (Number.isFinite(v)) onDemandCap = v;
|
|
7976
8228
|
}
|
|
7977
|
-
const planRaw = b.plan_type;
|
|
7978
|
-
const planType = typeof planRaw === "string" && planRaw.trim() ? planRaw.trim() : null;
|
|
7979
8229
|
return {
|
|
7980
|
-
|
|
7981
|
-
|
|
7982
|
-
|
|
8230
|
+
utilization,
|
|
8231
|
+
resets_at: end && !Number.isNaN(Date.parse(end)) ? end : null,
|
|
8232
|
+
period_type: periodType,
|
|
8233
|
+
on_demand_cap: onDemandCap
|
|
7983
8234
|
};
|
|
7984
8235
|
}
|
|
7985
|
-
async function
|
|
8236
|
+
async function fetchJson(url, token) {
|
|
7986
8237
|
let res;
|
|
7987
8238
|
try {
|
|
7988
|
-
res = await fetch(
|
|
7989
|
-
headers: authHeaders2(accessToken, accountId)
|
|
7990
|
-
});
|
|
8239
|
+
res = await fetch(url, { headers: authHeaders(token) });
|
|
7991
8240
|
} catch (err) {
|
|
7992
|
-
throw new
|
|
7993
|
-
`Network error reaching
|
|
8241
|
+
throw new GrokApiError(
|
|
8242
|
+
`Network error reaching Grok billing: ${err.message}`,
|
|
7994
8243
|
"network"
|
|
7995
8244
|
);
|
|
7996
8245
|
}
|
|
7997
|
-
const headers = {};
|
|
7998
|
-
res.headers.forEach((value, key) => {
|
|
7999
|
-
headers[key.toLowerCase()] = value;
|
|
8000
|
-
});
|
|
8001
8246
|
let body = null;
|
|
8002
8247
|
try {
|
|
8003
8248
|
body = await res.json();
|
|
8004
8249
|
} catch {
|
|
8005
8250
|
}
|
|
8006
|
-
return { status: res.status, body
|
|
8251
|
+
return { status: res.status, body };
|
|
8007
8252
|
}
|
|
8008
|
-
async function
|
|
8009
|
-
const loaded =
|
|
8010
|
-
|
|
8011
|
-
let
|
|
8012
|
-
|
|
8013
|
-
|
|
8014
|
-
|
|
8015
|
-
if (refreshed) {
|
|
8016
|
-
access = refreshed.accessToken;
|
|
8017
|
-
auth = refreshed.auth;
|
|
8018
|
-
}
|
|
8253
|
+
async function fetchGrokUsage() {
|
|
8254
|
+
const loaded = loadAuthEntry();
|
|
8255
|
+
const entry = loaded.entry;
|
|
8256
|
+
let token = loaded.token;
|
|
8257
|
+
if (needsRefresh(entry)) {
|
|
8258
|
+
const refreshed = await refreshAccessToken(entry);
|
|
8259
|
+
if (refreshed) token = refreshed;
|
|
8019
8260
|
}
|
|
8020
|
-
let { status: status2, body
|
|
8261
|
+
let { status: status2, body } = await fetchJson(CREDITS_URL, token);
|
|
8021
8262
|
if (status2 === 401 || status2 === 403) {
|
|
8022
|
-
const refreshed = await
|
|
8263
|
+
const refreshed = await refreshAccessToken(entry);
|
|
8023
8264
|
if (refreshed) {
|
|
8024
|
-
|
|
8025
|
-
({ status: status2, body
|
|
8265
|
+
token = refreshed;
|
|
8266
|
+
({ status: status2, body } = await fetchJson(CREDITS_URL, token));
|
|
8026
8267
|
}
|
|
8027
8268
|
}
|
|
8028
8269
|
if (status2 < 200 || status2 >= 300) {
|
|
8029
|
-
throw new
|
|
8030
|
-
`
|
|
8270
|
+
throw new GrokApiError(
|
|
8271
|
+
`Grok billing returned HTTP ${status2}`,
|
|
8031
8272
|
status2 === 401 || status2 === 403 ? "no_auth" : "http"
|
|
8032
8273
|
);
|
|
8033
8274
|
}
|
|
8034
|
-
const
|
|
8275
|
+
const credits = parseGrokCreditsConfig(body);
|
|
8276
|
+
if (credits.period_type !== WEEKLY_PERIOD) {
|
|
8277
|
+
throw new GrokApiError(
|
|
8278
|
+
`Grok period is ${credits.period_type}, not weekly`,
|
|
8279
|
+
"not_weekly"
|
|
8280
|
+
);
|
|
8281
|
+
}
|
|
8282
|
+
let planType = null;
|
|
8283
|
+
try {
|
|
8284
|
+
const settings = await fetchJson(SETTINGS_URL, token);
|
|
8285
|
+
if (settings.status >= 200 && settings.status < 300 && settings.body && typeof settings.body === "object") {
|
|
8286
|
+
const tier = settings.body.subscription_tier_display;
|
|
8287
|
+
if (typeof tier === "string" && tier.trim()) planType = tier.trim();
|
|
8288
|
+
}
|
|
8289
|
+
} catch {
|
|
8290
|
+
}
|
|
8035
8291
|
return {
|
|
8036
8292
|
captured_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8037
|
-
agent: "
|
|
8038
|
-
|
|
8039
|
-
|
|
8293
|
+
agent: "grok",
|
|
8294
|
+
// No 5-hour window — menubar / strip show "—" on the top line.
|
|
8295
|
+
five_hour: { utilization: null, resets_at: null },
|
|
8296
|
+
seven_day: {
|
|
8297
|
+
utilization: credits.utilization,
|
|
8298
|
+
resets_at: credits.resets_at
|
|
8299
|
+
},
|
|
8040
8300
|
seven_day_opus: null,
|
|
8041
8301
|
seven_day_sonnet: null,
|
|
8042
8302
|
seven_day_oauth_apps: null,
|
|
8043
8303
|
seven_day_cowork: null,
|
|
8044
8304
|
extra_usage: null,
|
|
8045
|
-
plan_type:
|
|
8305
|
+
plan_type: planType
|
|
8046
8306
|
};
|
|
8047
8307
|
}
|
|
8048
|
-
var
|
|
8049
|
-
var
|
|
8050
|
-
"src/usage/
|
|
8308
|
+
var CREDITS_URL, SETTINGS_URL, REFRESH_URL, TOKEN_AUTH, DEFAULT_CLIENT_ID, WEEKLY_PERIOD, REFRESH_BUFFER_MS, GrokApiError;
|
|
8309
|
+
var init_grok2 = __esm({
|
|
8310
|
+
"src/usage/grok.ts"() {
|
|
8051
8311
|
"use strict";
|
|
8052
|
-
|
|
8053
|
-
|
|
8054
|
-
|
|
8055
|
-
|
|
8056
|
-
|
|
8057
|
-
|
|
8058
|
-
|
|
8312
|
+
CREDITS_URL = "https://cli-chat-proxy.grok.com/v1/billing?format=credits";
|
|
8313
|
+
SETTINGS_URL = "https://cli-chat-proxy.grok.com/v1/settings";
|
|
8314
|
+
REFRESH_URL = "https://auth.x.ai/oauth2/token";
|
|
8315
|
+
TOKEN_AUTH = "xai-grok-cli";
|
|
8316
|
+
DEFAULT_CLIENT_ID = "b1a00492-073a-47ea-816f-4c329264a828";
|
|
8317
|
+
WEEKLY_PERIOD = "USAGE_PERIOD_TYPE_WEEKLY";
|
|
8318
|
+
REFRESH_BUFFER_MS = 5 * 60 * 1e3;
|
|
8319
|
+
GrokApiError = class extends Error {
|
|
8059
8320
|
constructor(message, code) {
|
|
8060
8321
|
super(message);
|
|
8061
8322
|
this.code = code;
|
|
@@ -8064,1205 +8325,1448 @@ var init_codex2 = __esm({
|
|
|
8064
8325
|
}
|
|
8065
8326
|
});
|
|
8066
8327
|
|
|
8067
|
-
// src/usage/
|
|
8068
|
-
import {
|
|
8069
|
-
|
|
8070
|
-
|
|
8071
|
-
|
|
8072
|
-
|
|
8073
|
-
|
|
8074
|
-
|
|
8075
|
-
|
|
8076
|
-
|
|
8077
|
-
|
|
8078
|
-
return
|
|
8328
|
+
// src/usage/codex.ts
|
|
8329
|
+
import {
|
|
8330
|
+
existsSync as existsSync9,
|
|
8331
|
+
readFileSync as readFileSync12,
|
|
8332
|
+
writeFileSync as writeFileSync6
|
|
8333
|
+
} from "node:fs";
|
|
8334
|
+
import os10 from "node:os";
|
|
8335
|
+
import path10 from "node:path";
|
|
8336
|
+
function codexHome() {
|
|
8337
|
+
const env = process.env.CODEX_HOME?.trim();
|
|
8338
|
+
if (env) return env;
|
|
8339
|
+
return path10.join(os10.homedir(), ".codex");
|
|
8079
8340
|
}
|
|
8080
|
-
function
|
|
8081
|
-
|
|
8082
|
-
return new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() + 1, 1)).toISOString();
|
|
8341
|
+
function authPath2() {
|
|
8342
|
+
return path10.join(codexHome(), "auth.json");
|
|
8083
8343
|
}
|
|
8084
|
-
function
|
|
8085
|
-
const
|
|
8086
|
-
|
|
8087
|
-
|
|
8088
|
-
|
|
8089
|
-
|
|
8090
|
-
|
|
8091
|
-
if (!snapshots) {
|
|
8092
|
-
throw new CopilotApiError("Copilot quota response missing quotaSnapshots", "parse");
|
|
8344
|
+
function loadAuth() {
|
|
8345
|
+
const p = authPath2();
|
|
8346
|
+
if (!existsSync9(p)) {
|
|
8347
|
+
throw new CodexApiError(
|
|
8348
|
+
"Codex not logged in. Run `codex` to authenticate.",
|
|
8349
|
+
"no_auth"
|
|
8350
|
+
);
|
|
8093
8351
|
}
|
|
8094
|
-
|
|
8095
|
-
|
|
8096
|
-
|
|
8097
|
-
|
|
8098
|
-
|
|
8099
|
-
|
|
8352
|
+
let auth;
|
|
8353
|
+
try {
|
|
8354
|
+
auth = JSON.parse(readFileSync12(p, "utf8"));
|
|
8355
|
+
} catch {
|
|
8356
|
+
throw new CodexApiError(
|
|
8357
|
+
"Codex auth.json is unreadable. Run `codex` to log in again.",
|
|
8358
|
+
"no_auth"
|
|
8359
|
+
);
|
|
8100
8360
|
}
|
|
8101
|
-
const
|
|
8102
|
-
|
|
8103
|
-
|
|
8104
|
-
|
|
8105
|
-
|
|
8106
|
-
|
|
8107
|
-
|
|
8108
|
-
|
|
8109
|
-
|
|
8110
|
-
|
|
8111
|
-
|
|
8112
|
-
|
|
8113
|
-
|
|
8114
|
-
|
|
8115
|
-
},
|
|
8116
|
-
monthly_quota: {
|
|
8117
|
-
used,
|
|
8118
|
-
limit,
|
|
8119
|
-
remaining: used !== null && limit !== null ? Math.max(0, limit - used) : null,
|
|
8120
|
-
unit,
|
|
8121
|
-
unlimited
|
|
8122
|
-
},
|
|
8123
|
-
seven_day_opus: null,
|
|
8124
|
-
seven_day_sonnet: null,
|
|
8125
|
-
seven_day_oauth_apps: null,
|
|
8126
|
-
seven_day_cowork: null,
|
|
8127
|
-
extra_usage: null,
|
|
8128
|
-
plan_type: unit === "ai-credits" ? "AI credits" : "premium requests"
|
|
8129
|
-
};
|
|
8361
|
+
const access = auth.tokens?.access_token?.trim();
|
|
8362
|
+
if (!access) {
|
|
8363
|
+
if (auth.OPENAI_API_KEY?.trim()) {
|
|
8364
|
+
throw new CodexApiError(
|
|
8365
|
+
"Codex usage is not available for API-key-only auth. Sign in with a ChatGPT account via `codex`.",
|
|
8366
|
+
"api_key_only"
|
|
8367
|
+
);
|
|
8368
|
+
}
|
|
8369
|
+
throw new CodexApiError(
|
|
8370
|
+
"Codex auth has no access token. Run `codex` to log in.",
|
|
8371
|
+
"no_auth"
|
|
8372
|
+
);
|
|
8373
|
+
}
|
|
8374
|
+
return { auth, path: p };
|
|
8130
8375
|
}
|
|
8131
|
-
function
|
|
8132
|
-
const
|
|
8133
|
-
return
|
|
8134
|
-
|
|
8135
|
-
|
|
8136
|
-
|
|
8137
|
-
|
|
8138
|
-
|
|
8376
|
+
function accessTokenExpiresAtMs(token) {
|
|
8377
|
+
const parts = token.split(".");
|
|
8378
|
+
if (parts.length < 2) return null;
|
|
8379
|
+
try {
|
|
8380
|
+
const pad2 = "=".repeat((4 - parts[1].length % 4) % 4);
|
|
8381
|
+
const json = Buffer.from(parts[1] + pad2, "base64url").toString("utf8");
|
|
8382
|
+
const payload = JSON.parse(json);
|
|
8383
|
+
if (typeof payload.exp !== "number" || !Number.isFinite(payload.exp)) {
|
|
8384
|
+
return null;
|
|
8385
|
+
}
|
|
8386
|
+
return payload.exp * 1e3;
|
|
8387
|
+
} catch {
|
|
8388
|
+
return null;
|
|
8389
|
+
}
|
|
8139
8390
|
}
|
|
8140
|
-
function
|
|
8141
|
-
const
|
|
8142
|
-
if (
|
|
8143
|
-
|
|
8144
|
-
|
|
8391
|
+
function needsRefresh2(accessToken, lastRefresh, nowMs = Date.now()) {
|
|
8392
|
+
const expMs = accessTokenExpiresAtMs(accessToken);
|
|
8393
|
+
if (expMs !== null) {
|
|
8394
|
+
return nowMs >= expMs - REFRESH_BUFFER_MS2;
|
|
8395
|
+
}
|
|
8396
|
+
if (!lastRefresh) return false;
|
|
8397
|
+
const ms = Date.parse(lastRefresh);
|
|
8398
|
+
if (!Number.isFinite(ms)) return false;
|
|
8399
|
+
return nowMs - ms > 8 * 24 * 60 * 60 * 1e3;
|
|
8145
8400
|
}
|
|
8146
|
-
async function
|
|
8147
|
-
const
|
|
8148
|
-
|
|
8149
|
-
|
|
8150
|
-
|
|
8151
|
-
|
|
8152
|
-
|
|
8153
|
-
};
|
|
8154
|
-
child.stdout.on("data", (chunk2) => {
|
|
8155
|
-
try {
|
|
8156
|
-
for (const value of decoder.push(chunk2)) {
|
|
8157
|
-
const message = recordOf2(value);
|
|
8158
|
-
const id = numberOf4(message?.id);
|
|
8159
|
-
if (id === void 0) continue;
|
|
8160
|
-
const waiter = pending.get(id);
|
|
8161
|
-
if (!waiter) continue;
|
|
8162
|
-
pending.delete(id);
|
|
8163
|
-
const rpcError = recordOf2(message?.error);
|
|
8164
|
-
if (rpcError) {
|
|
8165
|
-
waiter.reject(new CopilotApiError(
|
|
8166
|
-
typeof rpcError.message === "string" ? rpcError.message : "Copilot RPC request failed",
|
|
8167
|
-
"protocol"
|
|
8168
|
-
));
|
|
8169
|
-
} else {
|
|
8170
|
-
waiter.resolve(message?.result);
|
|
8171
|
-
}
|
|
8172
|
-
}
|
|
8173
|
-
} catch (error) {
|
|
8174
|
-
rejectAll(error);
|
|
8175
|
-
}
|
|
8176
|
-
});
|
|
8177
|
-
const exited = new Promise((_, reject) => {
|
|
8178
|
-
child.once("error", (error) => {
|
|
8179
|
-
reject(new CopilotApiError(
|
|
8180
|
-
error.message,
|
|
8181
|
-
error.code === "ENOENT" ? "no_cli" : "protocol"
|
|
8182
|
-
));
|
|
8183
|
-
});
|
|
8184
|
-
child.once("exit", (code) => {
|
|
8185
|
-
reject(new CopilotApiError(`Copilot RPC exited before responding (code ${code ?? "unknown"})`, "protocol"));
|
|
8186
|
-
});
|
|
8401
|
+
async function refreshAccessToken2(auth, filePath) {
|
|
8402
|
+
const refresh = auth.tokens?.refresh_token?.trim();
|
|
8403
|
+
if (!refresh) return null;
|
|
8404
|
+
const body = new URLSearchParams({
|
|
8405
|
+
grant_type: "refresh_token",
|
|
8406
|
+
client_id: CLIENT_ID,
|
|
8407
|
+
refresh_token: refresh
|
|
8187
8408
|
});
|
|
8188
|
-
|
|
8189
|
-
|
|
8190
|
-
|
|
8191
|
-
|
|
8192
|
-
|
|
8409
|
+
let res;
|
|
8410
|
+
try {
|
|
8411
|
+
res = await fetch(REFRESH_URL2, {
|
|
8412
|
+
method: "POST",
|
|
8413
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
8414
|
+
body: body.toString()
|
|
8193
8415
|
});
|
|
8194
|
-
|
|
8195
|
-
|
|
8196
|
-
|
|
8197
|
-
|
|
8198
|
-
}
|
|
8199
|
-
async function fetchCopilotUsage() {
|
|
8200
|
-
const cliPath = resolveCopilotCliPath();
|
|
8201
|
-
const child = spawn3(cliPath, ["--headless", "--no-auto-update", "--stdio", "--log-level", "none"], {
|
|
8202
|
-
cwd: process.cwd(),
|
|
8203
|
-
env: process.env,
|
|
8204
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
8205
|
-
windowsHide: true,
|
|
8206
|
-
shell: process.platform === "win32"
|
|
8207
|
-
});
|
|
8208
|
-
let stderr = "";
|
|
8209
|
-
child.stderr.on("data", (chunk2) => {
|
|
8210
|
-
stderr = (stderr + chunk2.toString("utf8")).slice(-2e3);
|
|
8211
|
-
});
|
|
8212
|
-
const timeout = new Promise((_, reject) => {
|
|
8213
|
-
const handle = setTimeout(() => {
|
|
8214
|
-
reject(new CopilotApiError("Timed out reading Copilot quota", "timeout"));
|
|
8215
|
-
}, RPC_TIMEOUT_MS);
|
|
8216
|
-
handle.unref();
|
|
8217
|
-
});
|
|
8416
|
+
} catch {
|
|
8417
|
+
return null;
|
|
8418
|
+
}
|
|
8419
|
+
if (!res.ok) return null;
|
|
8218
8420
|
try {
|
|
8219
|
-
const
|
|
8220
|
-
|
|
8221
|
-
|
|
8222
|
-
|
|
8223
|
-
|
|
8224
|
-
|
|
8225
|
-
|
|
8226
|
-
|
|
8227
|
-
|
|
8421
|
+
const j = await res.json();
|
|
8422
|
+
if (typeof j.access_token !== "string" || !j.access_token) return null;
|
|
8423
|
+
const next = {
|
|
8424
|
+
...auth,
|
|
8425
|
+
tokens: {
|
|
8426
|
+
...auth.tokens,
|
|
8427
|
+
access_token: j.access_token,
|
|
8428
|
+
refresh_token: j.refresh_token ?? auth.tokens?.refresh_token,
|
|
8429
|
+
id_token: j.id_token ?? auth.tokens?.id_token
|
|
8430
|
+
},
|
|
8431
|
+
last_refresh: (/* @__PURE__ */ new Date()).toISOString()
|
|
8432
|
+
};
|
|
8433
|
+
try {
|
|
8434
|
+
writeFileSync6(filePath, `${JSON.stringify(next, null, 2)}
|
|
8435
|
+
`, {
|
|
8436
|
+
encoding: "utf8",
|
|
8437
|
+
mode: 384
|
|
8438
|
+
});
|
|
8439
|
+
} catch {
|
|
8228
8440
|
}
|
|
8229
|
-
|
|
8230
|
-
}
|
|
8231
|
-
|
|
8441
|
+
return { accessToken: j.access_token, auth: next };
|
|
8442
|
+
} catch {
|
|
8443
|
+
return null;
|
|
8232
8444
|
}
|
|
8233
8445
|
}
|
|
8234
|
-
|
|
8235
|
-
|
|
8236
|
-
|
|
8237
|
-
|
|
8238
|
-
|
|
8239
|
-
|
|
8240
|
-
|
|
8241
|
-
|
|
8242
|
-
this.code = code;
|
|
8243
|
-
}
|
|
8244
|
-
};
|
|
8245
|
-
ContentLengthDecoder = class {
|
|
8246
|
-
buffer = Buffer.alloc(0);
|
|
8247
|
-
push(chunk2) {
|
|
8248
|
-
this.buffer = Buffer.concat([this.buffer, chunk2]);
|
|
8249
|
-
const messages = [];
|
|
8250
|
-
while (true) {
|
|
8251
|
-
const headerEnd = this.buffer.indexOf("\r\n\r\n");
|
|
8252
|
-
if (headerEnd === -1) break;
|
|
8253
|
-
const header = this.buffer.subarray(0, headerEnd).toString("ascii");
|
|
8254
|
-
const match = header.match(/(?:^|\r\n)Content-Length:\s*(\d+)/i);
|
|
8255
|
-
if (!match) {
|
|
8256
|
-
throw new CopilotApiError("Copilot RPC response missing Content-Length", "protocol");
|
|
8257
|
-
}
|
|
8258
|
-
const length = Number(match[1]);
|
|
8259
|
-
const bodyStart = headerEnd + 4;
|
|
8260
|
-
if (this.buffer.length < bodyStart + length) break;
|
|
8261
|
-
const body = this.buffer.subarray(bodyStart, bodyStart + length).toString("utf8");
|
|
8262
|
-
this.buffer = this.buffer.subarray(bodyStart + length);
|
|
8263
|
-
try {
|
|
8264
|
-
messages.push(JSON.parse(body));
|
|
8265
|
-
} catch {
|
|
8266
|
-
throw new CopilotApiError("Copilot RPC returned invalid JSON", "protocol");
|
|
8267
|
-
}
|
|
8268
|
-
}
|
|
8269
|
-
return messages;
|
|
8270
|
-
}
|
|
8271
|
-
};
|
|
8272
|
-
}
|
|
8273
|
-
});
|
|
8274
|
-
|
|
8275
|
-
// src/usage/format.ts
|
|
8276
|
-
function formatUsage(snapshot) {
|
|
8277
|
-
const rows = [
|
|
8278
|
-
["5 hour", snapshot.five_hour],
|
|
8279
|
-
["7 day", snapshot.seven_day],
|
|
8280
|
-
["7 day (Opus)", snapshot.seven_day_opus],
|
|
8281
|
-
["7 day (Sonnet)", snapshot.seven_day_sonnet],
|
|
8282
|
-
["7 day (OAuth apps)", snapshot.seven_day_oauth_apps],
|
|
8283
|
-
["7 day (Cowork)", snapshot.seven_day_cowork]
|
|
8284
|
-
];
|
|
8285
|
-
const lines = [];
|
|
8286
|
-
lines.push("");
|
|
8287
|
-
lines.push(` ${BOLD}Claude Code Usage${RESET}`);
|
|
8288
|
-
lines.push("");
|
|
8289
|
-
for (const [label, window] of rows) {
|
|
8290
|
-
if (!window || window.utilization === null) continue;
|
|
8291
|
-
const pct = window.utilization;
|
|
8292
|
-
const bar = renderBar(pct);
|
|
8293
|
-
const pctStr = `${pct.toFixed(1)}%`.padStart(6);
|
|
8294
|
-
const labelStr = label.padEnd(16);
|
|
8295
|
-
lines.push(` ${labelStr}${bar} ${BOLD}${pctStr}${RESET}`);
|
|
8296
|
-
if (window.resets_at) {
|
|
8297
|
-
lines.push(` ${" ".repeat(16)}${DIM}resets ${formatRelative(window.resets_at)}${RESET}`);
|
|
8298
|
-
}
|
|
8299
|
-
lines.push("");
|
|
8446
|
+
function authHeaders2(accessToken, accountId) {
|
|
8447
|
+
const headers = {
|
|
8448
|
+
Authorization: `Bearer ${accessToken}`,
|
|
8449
|
+
Accept: "application/json",
|
|
8450
|
+
"User-Agent": "fleetlens"
|
|
8451
|
+
};
|
|
8452
|
+
if (accountId?.trim()) {
|
|
8453
|
+
headers["ChatGPT-Account-Id"] = accountId.trim();
|
|
8300
8454
|
}
|
|
8301
|
-
|
|
8302
|
-
|
|
8303
|
-
|
|
8304
|
-
|
|
8305
|
-
|
|
8306
|
-
|
|
8307
|
-
if (
|
|
8308
|
-
lines.push(` ${" ".repeat(16)}${extra.used_credits} / ${extra.monthly_limit} credits`);
|
|
8309
|
-
}
|
|
8310
|
-
lines.push("");
|
|
8455
|
+
return headers;
|
|
8456
|
+
}
|
|
8457
|
+
function numberOf3(v) {
|
|
8458
|
+
if (typeof v === "number" && Number.isFinite(v)) return v;
|
|
8459
|
+
if (typeof v === "string" && v.trim()) {
|
|
8460
|
+
const n = Number(v);
|
|
8461
|
+
if (Number.isFinite(n)) return n;
|
|
8311
8462
|
}
|
|
8312
|
-
|
|
8313
|
-
lines.push("");
|
|
8314
|
-
return lines.join("\n");
|
|
8463
|
+
return void 0;
|
|
8315
8464
|
}
|
|
8316
|
-
function
|
|
8317
|
-
|
|
8318
|
-
const
|
|
8319
|
-
|
|
8320
|
-
const
|
|
8321
|
-
|
|
8322
|
-
|
|
8323
|
-
const filledCells = fullBlocks + (partial ? 1 : 0);
|
|
8324
|
-
const emptyCells = BAR_WIDTH - filledCells;
|
|
8325
|
-
const filled = "\u2588".repeat(fullBlocks) + partial;
|
|
8326
|
-
const empty = "\xB7".repeat(emptyCells);
|
|
8327
|
-
return `${color}${filled}${RESET}${DIM}${empty}${RESET}`;
|
|
8465
|
+
function windowSeconds(raw) {
|
|
8466
|
+
if (!raw) return void 0;
|
|
8467
|
+
const sec = numberOf3(raw.limit_window_seconds);
|
|
8468
|
+
if (sec !== void 0) return sec;
|
|
8469
|
+
const minutes = numberOf3(raw.window_minutes);
|
|
8470
|
+
if (minutes !== void 0) return minutes * 60;
|
|
8471
|
+
return void 0;
|
|
8328
8472
|
}
|
|
8329
|
-
function
|
|
8330
|
-
const
|
|
8331
|
-
|
|
8332
|
-
|
|
8333
|
-
const
|
|
8334
|
-
|
|
8335
|
-
|
|
8336
|
-
if (abs < 60) {
|
|
8337
|
-
value = `${abs}s`;
|
|
8338
|
-
} else if (abs < 3600) {
|
|
8339
|
-
value = `${Math.floor(abs / 60)}m`;
|
|
8340
|
-
} else if (abs < 86400) {
|
|
8341
|
-
const h = Math.floor(abs / 3600);
|
|
8342
|
-
const m = Math.floor(abs % 3600 / 60);
|
|
8343
|
-
value = m > 0 ? `${h}h${m}m` : `${h}h`;
|
|
8473
|
+
function normalizeWindow2(raw, headerPercent, nowMs) {
|
|
8474
|
+
const used = numberOf3(raw?.used_percent) ?? headerPercent;
|
|
8475
|
+
if (used === void 0) return null;
|
|
8476
|
+
let resetsAt = null;
|
|
8477
|
+
const resetUnix = numberOf3(raw?.reset_at) ?? numberOf3(raw?.resets_at);
|
|
8478
|
+
if (resetUnix !== void 0) {
|
|
8479
|
+
resetsAt = new Date(resetUnix * 1e3).toISOString();
|
|
8344
8480
|
} else {
|
|
8345
|
-
const
|
|
8346
|
-
|
|
8347
|
-
|
|
8481
|
+
const after = numberOf3(raw?.reset_after_seconds);
|
|
8482
|
+
if (after !== void 0) {
|
|
8483
|
+
resetsAt = new Date(nowMs + after * 1e3).toISOString();
|
|
8484
|
+
}
|
|
8348
8485
|
}
|
|
8349
|
-
return
|
|
8486
|
+
return {
|
|
8487
|
+
utilization: Math.min(100, Math.max(0, used)),
|
|
8488
|
+
resets_at: resetsAt
|
|
8489
|
+
};
|
|
8350
8490
|
}
|
|
8351
|
-
|
|
8352
|
-
|
|
8353
|
-
|
|
8354
|
-
"use strict";
|
|
8355
|
-
DIM = "\x1B[2m";
|
|
8356
|
-
BOLD = "\x1B[1m";
|
|
8357
|
-
RESET = "\x1B[0m";
|
|
8358
|
-
GREEN = "\x1B[32m";
|
|
8359
|
-
YELLOW = "\x1B[33m";
|
|
8360
|
-
RED = "\x1B[31m";
|
|
8361
|
-
BAR_WIDTH = 40;
|
|
8362
|
-
EIGHTHS = ["", "\u258F", "\u258E", "\u258D", "\u258C", "\u258B", "\u258A", "\u2589"];
|
|
8491
|
+
function parseCodexWhamUsage(body, headers = {}, nowMs = Date.now()) {
|
|
8492
|
+
if (!body || typeof body !== "object") {
|
|
8493
|
+
throw new CodexApiError("Codex usage response missing body", "parse");
|
|
8363
8494
|
}
|
|
8364
|
-
|
|
8365
|
-
|
|
8366
|
-
|
|
8367
|
-
|
|
8368
|
-
|
|
8369
|
-
|
|
8495
|
+
const b = body;
|
|
8496
|
+
const rateLimit = b.rate_limit && typeof b.rate_limit === "object" ? b.rate_limit : {};
|
|
8497
|
+
const headerPrimary = numberOf3(headers["x-codex-primary-used-percent"]);
|
|
8498
|
+
const headerSecondary = numberOf3(headers["x-codex-secondary-used-percent"]);
|
|
8499
|
+
const primary = rateLimit.primary_window && typeof rateLimit.primary_window === "object" ? rateLimit.primary_window : null;
|
|
8500
|
+
const secondary = rateLimit.secondary_window && typeof rateLimit.secondary_window === "object" ? rateLimit.secondary_window : null;
|
|
8501
|
+
const candidates = [
|
|
8502
|
+
{ raw: primary, headerPercent: headerPrimary, fallback: "five_hour" },
|
|
8503
|
+
{ raw: secondary, headerPercent: headerSecondary, fallback: "seven_day" }
|
|
8504
|
+
];
|
|
8505
|
+
let fiveHour = null;
|
|
8506
|
+
let sevenDay = null;
|
|
8507
|
+
for (const c of candidates) {
|
|
8508
|
+
const secs = windowSeconds(c.raw);
|
|
8509
|
+
const window = normalizeWindow2(c.raw, c.headerPercent, nowMs);
|
|
8510
|
+
if (!window) continue;
|
|
8511
|
+
if (secs === FIVE_HOUR_SECONDS) fiveHour = window;
|
|
8512
|
+
else if (secs === SEVEN_DAY_SECONDS) sevenDay = window;
|
|
8370
8513
|
}
|
|
8371
|
-
|
|
8514
|
+
if (!fiveHour || !sevenDay) {
|
|
8515
|
+
for (const c of candidates) {
|
|
8516
|
+
const secs = windowSeconds(c.raw);
|
|
8517
|
+
if (secs === FIVE_HOUR_SECONDS || secs === SEVEN_DAY_SECONDS) continue;
|
|
8518
|
+
const window = normalizeWindow2(c.raw, c.headerPercent, nowMs);
|
|
8519
|
+
if (!window) continue;
|
|
8520
|
+
if (c.fallback === "five_hour" && !fiveHour) fiveHour = window;
|
|
8521
|
+
else if (c.fallback === "seven_day" && !sevenDay) sevenDay = window;
|
|
8522
|
+
}
|
|
8523
|
+
}
|
|
8524
|
+
const planRaw = b.plan_type;
|
|
8525
|
+
const planType = typeof planRaw === "string" && planRaw.trim() ? planRaw.trim() : null;
|
|
8526
|
+
return {
|
|
8527
|
+
five_hour: fiveHour ?? { utilization: null, resets_at: null },
|
|
8528
|
+
seven_day: sevenDay ?? { utilization: null, resets_at: null },
|
|
8529
|
+
plan_type: planType
|
|
8530
|
+
};
|
|
8372
8531
|
}
|
|
8373
|
-
function
|
|
8374
|
-
|
|
8375
|
-
|
|
8376
|
-
|
|
8532
|
+
async function fetchUsageResponse(accessToken, accountId) {
|
|
8533
|
+
let res;
|
|
8534
|
+
try {
|
|
8535
|
+
res = await fetch(USAGE_URL, {
|
|
8536
|
+
headers: authHeaders2(accessToken, accountId)
|
|
8537
|
+
});
|
|
8538
|
+
} catch (err) {
|
|
8539
|
+
throw new CodexApiError(
|
|
8540
|
+
`Network error reaching Codex usage: ${err.message}`,
|
|
8541
|
+
"network"
|
|
8542
|
+
);
|
|
8543
|
+
}
|
|
8544
|
+
const headers = {};
|
|
8545
|
+
res.headers.forEach((value, key) => {
|
|
8546
|
+
headers[key.toLowerCase()] = value;
|
|
8547
|
+
});
|
|
8548
|
+
let body = null;
|
|
8549
|
+
try {
|
|
8550
|
+
body = await res.json();
|
|
8551
|
+
} catch {
|
|
8552
|
+
}
|
|
8553
|
+
return { status: res.status, body, headers };
|
|
8377
8554
|
}
|
|
8378
|
-
|
|
8379
|
-
|
|
8380
|
-
|
|
8555
|
+
async function fetchCodexUsage() {
|
|
8556
|
+
const loaded = loadAuth();
|
|
8557
|
+
let auth = loaded.auth;
|
|
8558
|
+
let access = auth.tokens.access_token.trim();
|
|
8559
|
+
const accountId = auth.tokens?.account_id;
|
|
8560
|
+
if (needsRefresh2(access, auth.last_refresh)) {
|
|
8561
|
+
const refreshed = await refreshAccessToken2(auth, loaded.path);
|
|
8562
|
+
if (refreshed) {
|
|
8563
|
+
access = refreshed.accessToken;
|
|
8564
|
+
auth = refreshed.auth;
|
|
8565
|
+
}
|
|
8566
|
+
}
|
|
8567
|
+
let { status: status2, body, headers } = await fetchUsageResponse(access, accountId);
|
|
8568
|
+
if (status2 === 401 || status2 === 403) {
|
|
8569
|
+
const refreshed = await refreshAccessToken2(auth, loaded.path);
|
|
8570
|
+
if (refreshed) {
|
|
8571
|
+
access = refreshed.accessToken;
|
|
8572
|
+
({ status: status2, body, headers } = await fetchUsageResponse(access, accountId));
|
|
8573
|
+
}
|
|
8574
|
+
}
|
|
8575
|
+
if (status2 < 200 || status2 >= 300) {
|
|
8576
|
+
throw new CodexApiError(
|
|
8577
|
+
`Codex usage returned HTTP ${status2}`,
|
|
8578
|
+
status2 === 401 || status2 === 403 ? "no_auth" : "http"
|
|
8579
|
+
);
|
|
8580
|
+
}
|
|
8581
|
+
const windows = parseCodexWhamUsage(body, headers);
|
|
8582
|
+
return {
|
|
8583
|
+
captured_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8584
|
+
agent: "codex",
|
|
8585
|
+
five_hour: windows.five_hour,
|
|
8586
|
+
seven_day: windows.seven_day,
|
|
8587
|
+
seven_day_opus: null,
|
|
8588
|
+
seven_day_sonnet: null,
|
|
8589
|
+
seven_day_oauth_apps: null,
|
|
8590
|
+
seven_day_cowork: null,
|
|
8591
|
+
extra_usage: null,
|
|
8592
|
+
plan_type: windows.plan_type
|
|
8593
|
+
};
|
|
8594
|
+
}
|
|
8595
|
+
var USAGE_URL, REFRESH_URL2, CLIENT_ID, FIVE_HOUR_SECONDS, SEVEN_DAY_SECONDS, REFRESH_BUFFER_MS2, CodexApiError;
|
|
8596
|
+
var init_codex2 = __esm({
|
|
8597
|
+
"src/usage/codex.ts"() {
|
|
8381
8598
|
"use strict";
|
|
8382
|
-
|
|
8383
|
-
|
|
8384
|
-
|
|
8385
|
-
|
|
8386
|
-
|
|
8387
|
-
|
|
8388
|
-
|
|
8389
|
-
|
|
8599
|
+
USAGE_URL = "https://chatgpt.com/backend-api/wham/usage";
|
|
8600
|
+
REFRESH_URL2 = "https://auth.openai.com/oauth/token";
|
|
8601
|
+
CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann";
|
|
8602
|
+
FIVE_HOUR_SECONDS = 5 * 60 * 60;
|
|
8603
|
+
SEVEN_DAY_SECONDS = 7 * 24 * 60 * 60;
|
|
8604
|
+
REFRESH_BUFFER_MS2 = 5 * 60 * 1e3;
|
|
8605
|
+
CodexApiError = class extends Error {
|
|
8606
|
+
constructor(message, code) {
|
|
8607
|
+
super(message);
|
|
8608
|
+
this.code = code;
|
|
8609
|
+
}
|
|
8610
|
+
};
|
|
8390
8611
|
}
|
|
8391
8612
|
});
|
|
8392
8613
|
|
|
8393
|
-
// src/
|
|
8394
|
-
|
|
8395
|
-
|
|
8614
|
+
// src/usage/copilot.ts
|
|
8615
|
+
import { spawn as spawn3 } from "node:child_process";
|
|
8616
|
+
import { existsSync as existsSync10 } from "node:fs";
|
|
8617
|
+
import { dirname as dirname8, join as join8 } from "node:path";
|
|
8618
|
+
function recordOf2(value) {
|
|
8619
|
+
return typeof value === "object" && value !== null ? value : void 0;
|
|
8396
8620
|
}
|
|
8397
|
-
function
|
|
8398
|
-
|
|
8399
|
-
return `${partial ? "\u2265" : ""}$${cost.toFixed(2)}`;
|
|
8621
|
+
function numberOf4(value) {
|
|
8622
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
8400
8623
|
}
|
|
8401
|
-
function
|
|
8402
|
-
|
|
8403
|
-
return s.padStart(width);
|
|
8624
|
+
function clampPercent(value) {
|
|
8625
|
+
return Math.min(100, Math.max(0, value));
|
|
8404
8626
|
}
|
|
8405
|
-
function
|
|
8406
|
-
const
|
|
8407
|
-
|
|
8408
|
-
lines.push(`${BOLD2}${title}${RESET2}`);
|
|
8409
|
-
lines.push("");
|
|
8410
|
-
const header = [
|
|
8411
|
-
pad("Date", 12, "left"),
|
|
8412
|
-
pad("Models", 20, "left"),
|
|
8413
|
-
pad("Input", 12),
|
|
8414
|
-
pad("Output", 12),
|
|
8415
|
-
pad("Cache Create", 14),
|
|
8416
|
-
pad("Cache Read", 14),
|
|
8417
|
-
pad("Total", 14),
|
|
8418
|
-
pad("Cost (USD)", 12)
|
|
8419
|
-
].join(" ");
|
|
8420
|
-
lines.push(`${DIM2}${header}${RESET2}`);
|
|
8421
|
-
lines.push(`${DIM2}${"\u2500".repeat(header.length)}${RESET2}`);
|
|
8422
|
-
let costIncomplete = false;
|
|
8423
|
-
for (const r of rows) {
|
|
8424
|
-
if (r.cost === null || r.costPartial) costIncomplete = true;
|
|
8425
|
-
lines.push([
|
|
8426
|
-
pad(r.date, 12, "left"),
|
|
8427
|
-
pad(r.models, 20, "left"),
|
|
8428
|
-
pad(fmtNum(r.input), 12),
|
|
8429
|
-
pad(fmtNum(r.output), 12),
|
|
8430
|
-
pad(fmtNum(r.cacheCreate), 14),
|
|
8431
|
-
pad(fmtNum(r.cacheRead), 14),
|
|
8432
|
-
pad(fmtNum(r.totalTokens), 14),
|
|
8433
|
-
pad(fmtCost(r.cost, r.costPartial), 12)
|
|
8434
|
-
].join(" "));
|
|
8435
|
-
}
|
|
8436
|
-
const totals = rows.reduce(
|
|
8437
|
-
(acc, r) => ({
|
|
8438
|
-
input: acc.input + r.input,
|
|
8439
|
-
output: acc.output + r.output,
|
|
8440
|
-
cacheCreate: acc.cacheCreate + r.cacheCreate,
|
|
8441
|
-
cacheRead: acc.cacheRead + r.cacheRead,
|
|
8442
|
-
totalTokens: acc.totalTokens + r.totalTokens,
|
|
8443
|
-
cost: acc.cost + (r.cost ?? 0),
|
|
8444
|
-
anyCost: acc.anyCost || r.cost !== null
|
|
8445
|
-
}),
|
|
8446
|
-
{ input: 0, output: 0, cacheCreate: 0, cacheRead: 0, totalTokens: 0, cost: 0, anyCost: false }
|
|
8447
|
-
);
|
|
8448
|
-
lines.push(`${DIM2}${"\u2500".repeat(header.length)}${RESET2}`);
|
|
8449
|
-
lines.push(
|
|
8450
|
-
`${BOLD2}${[
|
|
8451
|
-
pad("Total", 12, "left"),
|
|
8452
|
-
pad("", 20, "left"),
|
|
8453
|
-
pad(fmtNum(totals.input), 12),
|
|
8454
|
-
pad(fmtNum(totals.output), 12),
|
|
8455
|
-
pad(fmtNum(totals.cacheCreate), 14),
|
|
8456
|
-
pad(fmtNum(totals.cacheRead), 14),
|
|
8457
|
-
pad(fmtNum(totals.totalTokens), 14),
|
|
8458
|
-
pad(totals.anyCost ? fmtCost(totals.cost, costIncomplete) : fmtCost(null), 12)
|
|
8459
|
-
].join(" ")}${RESET2}`
|
|
8460
|
-
);
|
|
8461
|
-
if (costIncomplete) {
|
|
8462
|
-
lines.push("");
|
|
8463
|
-
lines.push(
|
|
8464
|
-
`${DIM2} Cost covers priced usage only \u2014 "\u2014" = no priced sessions that day, "\u2265" = lower bound (some sessions had unknown pricing).${RESET2}`
|
|
8465
|
-
);
|
|
8466
|
-
}
|
|
8467
|
-
lines.push("");
|
|
8468
|
-
return lines.join("\n");
|
|
8627
|
+
function nextCopilotMonthlyReset(nowMs = Date.now()) {
|
|
8628
|
+
const now = new Date(nowMs);
|
|
8629
|
+
return new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() + 1, 1)).toISOString();
|
|
8469
8630
|
}
|
|
8470
|
-
|
|
8471
|
-
|
|
8472
|
-
|
|
8473
|
-
|
|
8474
|
-
|
|
8475
|
-
|
|
8476
|
-
|
|
8477
|
-
|
|
8478
|
-
|
|
8479
|
-
|
|
8480
|
-
// src/commands/usage-history.ts
|
|
8481
|
-
var usage_history_exports = {};
|
|
8482
|
-
__export(usage_history_exports, {
|
|
8483
|
-
history: () => history
|
|
8484
|
-
});
|
|
8485
|
-
async function history(args2) {
|
|
8486
|
-
const live = args2.includes("--live");
|
|
8487
|
-
const sinceIdx = args2.indexOf("-s");
|
|
8488
|
-
const daysIdx = args2.indexOf("--days");
|
|
8489
|
-
let sinceDate = null;
|
|
8490
|
-
if (sinceIdx !== -1 && args2[sinceIdx + 1]) {
|
|
8491
|
-
const raw = args2[sinceIdx + 1];
|
|
8492
|
-
sinceDate = /* @__PURE__ */ new Date(`${raw.slice(0, 4)}-${raw.slice(4, 6)}-${raw.slice(6, 8)}`);
|
|
8493
|
-
} else if (daysIdx !== -1 && args2[daysIdx + 1]) {
|
|
8494
|
-
const days = parseInt(args2[daysIdx + 1], 10);
|
|
8495
|
-
sinceDate = /* @__PURE__ */ new Date();
|
|
8496
|
-
sinceDate.setDate(sinceDate.getDate() - days);
|
|
8497
|
-
sinceDate.setHours(0, 0, 0, 0);
|
|
8631
|
+
function quotaResetDate(value, nowMs) {
|
|
8632
|
+
const parsed = typeof value === "string" ? Date.parse(value) : Number.NaN;
|
|
8633
|
+
return Number.isFinite(parsed) && parsed > nowMs + 6e4 ? new Date(parsed).toISOString() : nextCopilotMonthlyReset(nowMs);
|
|
8634
|
+
}
|
|
8635
|
+
function parseCopilotQuota(body, nowMs = Date.now()) {
|
|
8636
|
+
const root = recordOf2(body);
|
|
8637
|
+
const snapshots = recordOf2(root?.quotaSnapshots);
|
|
8638
|
+
if (!snapshots) {
|
|
8639
|
+
throw new CopilotApiError("Copilot quota response missing quotaSnapshots", "parse");
|
|
8498
8640
|
}
|
|
8499
|
-
|
|
8500
|
-
|
|
8501
|
-
|
|
8502
|
-
|
|
8641
|
+
const chat = recordOf2(snapshots.chat);
|
|
8642
|
+
const legacy = recordOf2(snapshots.premium_interactions);
|
|
8643
|
+
const chatLimit = numberOf4(chat?.entitlementRequests);
|
|
8644
|
+
const quota = chat && (chatLimit !== void 0 && chatLimit > 0 || chat.isUnlimitedEntitlement === true) ? chat : legacy;
|
|
8645
|
+
if (!quota) {
|
|
8646
|
+
throw new CopilotApiError("Copilot quota response has no chat allowance", "parse");
|
|
8503
8647
|
}
|
|
8648
|
+
const unlimited = quota.isUnlimitedEntitlement === true;
|
|
8649
|
+
const remainingPercent = numberOf4(quota.remainingPercentage);
|
|
8650
|
+
const utilization = unlimited ? null : remainingPercent === void 0 ? null : clampPercent(100 - remainingPercent);
|
|
8651
|
+
const limit = numberOf4(quota.entitlementRequests) ?? null;
|
|
8652
|
+
const used = numberOf4(quota.usedRequests) ?? null;
|
|
8653
|
+
const unit = quota.tokenBasedBilling === true ? "ai-credits" : "premium-requests";
|
|
8654
|
+
return {
|
|
8655
|
+
captured_at: new Date(nowMs).toISOString(),
|
|
8656
|
+
agent: "copilot",
|
|
8657
|
+
five_hour: { utilization: null, resets_at: null },
|
|
8658
|
+
seven_day: { utilization: null, resets_at: null },
|
|
8659
|
+
monthly: {
|
|
8660
|
+
utilization,
|
|
8661
|
+
resets_at: quotaResetDate(quota.resetDate, nowMs)
|
|
8662
|
+
},
|
|
8663
|
+
monthly_quota: {
|
|
8664
|
+
used,
|
|
8665
|
+
limit,
|
|
8666
|
+
remaining: used !== null && limit !== null ? Math.max(0, limit - used) : null,
|
|
8667
|
+
unit,
|
|
8668
|
+
unlimited
|
|
8669
|
+
},
|
|
8670
|
+
seven_day_opus: null,
|
|
8671
|
+
seven_day_sonnet: null,
|
|
8672
|
+
seven_day_oauth_apps: null,
|
|
8673
|
+
seven_day_cowork: null,
|
|
8674
|
+
extra_usage: null,
|
|
8675
|
+
plan_type: unit === "ai-credits" ? "AI credits" : "premium requests"
|
|
8676
|
+
};
|
|
8504
8677
|
}
|
|
8505
|
-
|
|
8506
|
-
const
|
|
8507
|
-
|
|
8508
|
-
|
|
8509
|
-
|
|
8510
|
-
|
|
8511
|
-
|
|
8512
|
-
|
|
8513
|
-
const serverLine = status2.running ? `Server running on http://localhost:${status2.port}` : "Server not running";
|
|
8514
|
-
console.log(output);
|
|
8515
|
-
console.log(` ${todaySessions} sessions today \xB7 ${serverLine}`);
|
|
8516
|
-
console.log("");
|
|
8678
|
+
function rpcFrame(message) {
|
|
8679
|
+
const body = Buffer.from(JSON.stringify(message), "utf8");
|
|
8680
|
+
return Buffer.concat([
|
|
8681
|
+
Buffer.from(`Content-Length: ${body.length}\r
|
|
8682
|
+
\r
|
|
8683
|
+
`, "ascii"),
|
|
8684
|
+
body
|
|
8685
|
+
]);
|
|
8517
8686
|
}
|
|
8518
|
-
function
|
|
8519
|
-
|
|
8687
|
+
function resolveCopilotCliPath() {
|
|
8688
|
+
const configured = process.env.COPILOT_CLI_PATH?.trim();
|
|
8689
|
+
if (configured) return configured;
|
|
8690
|
+
const sibling = join8(dirname8(process.execPath), process.platform === "win32" ? "copilot.cmd" : "copilot");
|
|
8691
|
+
return existsSync10(sibling) ? sibling : process.platform === "win32" ? "copilot.cmd" : "copilot";
|
|
8520
8692
|
}
|
|
8521
|
-
function
|
|
8522
|
-
const
|
|
8523
|
-
|
|
8524
|
-
|
|
8525
|
-
|
|
8526
|
-
const
|
|
8527
|
-
|
|
8528
|
-
|
|
8529
|
-
|
|
8530
|
-
|
|
8531
|
-
|
|
8532
|
-
|
|
8533
|
-
|
|
8534
|
-
|
|
8535
|
-
|
|
8536
|
-
|
|
8537
|
-
|
|
8538
|
-
|
|
8539
|
-
|
|
8540
|
-
|
|
8541
|
-
|
|
8542
|
-
|
|
8543
|
-
|
|
8544
|
-
cost += c;
|
|
8545
|
-
anyPriced = true;
|
|
8693
|
+
async function requestQuota(child) {
|
|
8694
|
+
const decoder = new ContentLengthDecoder();
|
|
8695
|
+
const pending = /* @__PURE__ */ new Map();
|
|
8696
|
+
let nextId = 1;
|
|
8697
|
+
const rejectAll = (error) => {
|
|
8698
|
+
for (const waiter of pending.values()) waiter.reject(error);
|
|
8699
|
+
pending.clear();
|
|
8700
|
+
};
|
|
8701
|
+
child.stdout.on("data", (chunk2) => {
|
|
8702
|
+
try {
|
|
8703
|
+
for (const value of decoder.push(chunk2)) {
|
|
8704
|
+
const message = recordOf2(value);
|
|
8705
|
+
const id = numberOf4(message?.id);
|
|
8706
|
+
if (id === void 0) continue;
|
|
8707
|
+
const waiter = pending.get(id);
|
|
8708
|
+
if (!waiter) continue;
|
|
8709
|
+
pending.delete(id);
|
|
8710
|
+
const rpcError = recordOf2(message?.error);
|
|
8711
|
+
if (rpcError) {
|
|
8712
|
+
waiter.reject(new CopilotApiError(
|
|
8713
|
+
typeof rpcError.message === "string" ? rpcError.message : "Copilot RPC request failed",
|
|
8714
|
+
"protocol"
|
|
8715
|
+
));
|
|
8546
8716
|
} else {
|
|
8547
|
-
|
|
8717
|
+
waiter.resolve(message?.result);
|
|
8548
8718
|
}
|
|
8549
8719
|
}
|
|
8720
|
+
} catch (error) {
|
|
8721
|
+
rejectAll(error);
|
|
8550
8722
|
}
|
|
8551
|
-
const modelNames = [...models].join(", ");
|
|
8552
|
-
return {
|
|
8553
|
-
date,
|
|
8554
|
-
models: modelNames || "\u2014",
|
|
8555
|
-
input: usage2.input,
|
|
8556
|
-
output: usage2.output,
|
|
8557
|
-
cacheCreate: usage2.cacheWrite,
|
|
8558
|
-
cacheRead: usage2.cacheRead,
|
|
8559
|
-
totalTokens: usage2.input + usage2.output + usage2.cacheRead + usage2.cacheWrite,
|
|
8560
|
-
cost: anyPriced ? cost : null,
|
|
8561
|
-
costPartial: anyPriced && anyUnpriced
|
|
8562
|
-
};
|
|
8563
8723
|
});
|
|
8564
|
-
|
|
8565
|
-
|
|
8566
|
-
|
|
8567
|
-
|
|
8568
|
-
|
|
8569
|
-
|
|
8570
|
-
if (data.toString() === "q" || data.toString() === "") {
|
|
8571
|
-
process.stdout.write("\x1B[?25h");
|
|
8572
|
-
process.exit(0);
|
|
8573
|
-
}
|
|
8724
|
+
const exited = new Promise((_, reject) => {
|
|
8725
|
+
child.once("error", (error) => {
|
|
8726
|
+
reject(new CopilotApiError(
|
|
8727
|
+
error.message,
|
|
8728
|
+
error.code === "ENOENT" ? "no_cli" : "protocol"
|
|
8729
|
+
));
|
|
8574
8730
|
});
|
|
8575
|
-
|
|
8576
|
-
|
|
8577
|
-
|
|
8578
|
-
|
|
8579
|
-
|
|
8580
|
-
const
|
|
8581
|
-
|
|
8582
|
-
|
|
8583
|
-
|
|
8584
|
-
|
|
8585
|
-
|
|
8586
|
-
|
|
8587
|
-
|
|
8588
|
-
|
|
8589
|
-
|
|
8590
|
-
|
|
8591
|
-
|
|
8731
|
+
child.once("exit", (code) => {
|
|
8732
|
+
reject(new CopilotApiError(`Copilot RPC exited before responding (code ${code ?? "unknown"})`, "protocol"));
|
|
8733
|
+
});
|
|
8734
|
+
});
|
|
8735
|
+
const request = (method, params = {}) => {
|
|
8736
|
+
const id = nextId++;
|
|
8737
|
+
const response = new Promise((resolve4, reject) => {
|
|
8738
|
+
pending.set(id, { resolve: resolve4, reject });
|
|
8739
|
+
child.stdin.write(rpcFrame({ jsonrpc: "2.0", id, method, params }));
|
|
8740
|
+
});
|
|
8741
|
+
return Promise.race([response, exited]);
|
|
8742
|
+
};
|
|
8743
|
+
await request("connect", {});
|
|
8744
|
+
return request("account.getQuota", {});
|
|
8745
|
+
}
|
|
8746
|
+
async function fetchCopilotUsage() {
|
|
8747
|
+
const cliPath = resolveCopilotCliPath();
|
|
8748
|
+
const child = spawn3(cliPath, ["--headless", "--no-auto-update", "--stdio", "--log-level", "none"], {
|
|
8749
|
+
cwd: process.cwd(),
|
|
8750
|
+
env: process.env,
|
|
8751
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
8752
|
+
windowsHide: true,
|
|
8753
|
+
shell: process.platform === "win32"
|
|
8754
|
+
});
|
|
8755
|
+
let stderr = "";
|
|
8756
|
+
child.stderr.on("data", (chunk2) => {
|
|
8757
|
+
stderr = (stderr + chunk2.toString("utf8")).slice(-2e3);
|
|
8758
|
+
});
|
|
8759
|
+
const timeout = new Promise((_, reject) => {
|
|
8760
|
+
const handle = setTimeout(() => {
|
|
8761
|
+
reject(new CopilotApiError("Timed out reading Copilot quota", "timeout"));
|
|
8762
|
+
}, RPC_TIMEOUT_MS);
|
|
8763
|
+
handle.unref();
|
|
8764
|
+
});
|
|
8765
|
+
try {
|
|
8766
|
+
const body = await Promise.race([requestQuota(child), timeout]);
|
|
8767
|
+
return parseCopilotQuota(body);
|
|
8768
|
+
} catch (error) {
|
|
8769
|
+
if (error instanceof CopilotApiError) {
|
|
8770
|
+
const message = `${error.message} ${stderr}`.toLowerCase();
|
|
8771
|
+
if (message.includes("not logged") || message.includes("authentication")) {
|
|
8772
|
+
throw new CopilotApiError("Copilot not logged in. Run `copilot login`.", "no_auth");
|
|
8592
8773
|
}
|
|
8593
|
-
|
|
8774
|
+
throw error;
|
|
8594
8775
|
}
|
|
8595
|
-
|
|
8596
|
-
|
|
8597
|
-
|
|
8776
|
+
throw new CopilotApiError(error.message, "protocol");
|
|
8777
|
+
} finally {
|
|
8778
|
+
child.kill();
|
|
8779
|
+
}
|
|
8598
8780
|
}
|
|
8599
|
-
var
|
|
8600
|
-
|
|
8781
|
+
var RPC_TIMEOUT_MS, CopilotApiError, ContentLengthDecoder;
|
|
8782
|
+
var init_copilot2 = __esm({
|
|
8783
|
+
"src/usage/copilot.ts"() {
|
|
8601
8784
|
"use strict";
|
|
8602
|
-
|
|
8603
|
-
|
|
8604
|
-
|
|
8605
|
-
|
|
8785
|
+
RPC_TIMEOUT_MS = 1e4;
|
|
8786
|
+
CopilotApiError = class extends Error {
|
|
8787
|
+
constructor(message, code) {
|
|
8788
|
+
super(message);
|
|
8789
|
+
this.code = code;
|
|
8790
|
+
}
|
|
8791
|
+
};
|
|
8792
|
+
ContentLengthDecoder = class {
|
|
8793
|
+
buffer = Buffer.alloc(0);
|
|
8794
|
+
push(chunk2) {
|
|
8795
|
+
this.buffer = Buffer.concat([this.buffer, chunk2]);
|
|
8796
|
+
const messages = [];
|
|
8797
|
+
while (true) {
|
|
8798
|
+
const headerEnd = this.buffer.indexOf("\r\n\r\n");
|
|
8799
|
+
if (headerEnd === -1) break;
|
|
8800
|
+
const header = this.buffer.subarray(0, headerEnd).toString("ascii");
|
|
8801
|
+
const match = header.match(/(?:^|\r\n)Content-Length:\s*(\d+)/i);
|
|
8802
|
+
if (!match) {
|
|
8803
|
+
throw new CopilotApiError("Copilot RPC response missing Content-Length", "protocol");
|
|
8804
|
+
}
|
|
8805
|
+
const length = Number(match[1]);
|
|
8806
|
+
const bodyStart = headerEnd + 4;
|
|
8807
|
+
if (this.buffer.length < bodyStart + length) break;
|
|
8808
|
+
const body = this.buffer.subarray(bodyStart, bodyStart + length).toString("utf8");
|
|
8809
|
+
this.buffer = this.buffer.subarray(bodyStart + length);
|
|
8810
|
+
try {
|
|
8811
|
+
messages.push(JSON.parse(body));
|
|
8812
|
+
} catch {
|
|
8813
|
+
throw new CopilotApiError("Copilot RPC returned invalid JSON", "protocol");
|
|
8814
|
+
}
|
|
8815
|
+
}
|
|
8816
|
+
return messages;
|
|
8817
|
+
}
|
|
8818
|
+
};
|
|
8606
8819
|
}
|
|
8607
8820
|
});
|
|
8608
8821
|
|
|
8609
|
-
// src/
|
|
8610
|
-
|
|
8611
|
-
|
|
8612
|
-
usage: () => usage
|
|
8613
|
-
});
|
|
8614
|
-
async function saveAuxiliarySnapshots() {
|
|
8615
|
-
let saved = 0;
|
|
8616
|
-
for (const source of agentSources) {
|
|
8617
|
-
if (source.kind === "claude-code" || !source.usagePoller) continue;
|
|
8618
|
-
try {
|
|
8619
|
-
const partial = await source.usagePoller();
|
|
8620
|
-
if (!partial) continue;
|
|
8621
|
-
appendSnapshot(USAGE_LOG2, {
|
|
8622
|
-
...partial,
|
|
8623
|
-
seven_day_opus: null,
|
|
8624
|
-
seven_day_sonnet: null,
|
|
8625
|
-
seven_day_oauth_apps: null,
|
|
8626
|
-
seven_day_cowork: null,
|
|
8627
|
-
extra_usage: null
|
|
8628
|
-
});
|
|
8629
|
-
saved += 1;
|
|
8630
|
-
} catch {
|
|
8631
|
-
}
|
|
8632
|
-
}
|
|
8822
|
+
// src/usage/zai.ts
|
|
8823
|
+
import { existsSync as existsSync11, readFileSync as readFileSync13 } from "node:fs";
|
|
8824
|
+
function resolveApiKey() {
|
|
8633
8825
|
try {
|
|
8634
|
-
|
|
8635
|
-
|
|
8636
|
-
|
|
8637
|
-
|
|
8638
|
-
console.warn(`codex usage: ${err.message}`);
|
|
8826
|
+
const p = cclensPath("credentials.json");
|
|
8827
|
+
if (existsSync11(p)) {
|
|
8828
|
+
const store = JSON.parse(readFileSync13(p, "utf8"));
|
|
8829
|
+
return store.zai?.apiKey ?? null;
|
|
8639
8830
|
}
|
|
8831
|
+
} catch {
|
|
8640
8832
|
}
|
|
8641
|
-
|
|
8642
|
-
|
|
8643
|
-
|
|
8644
|
-
|
|
8645
|
-
|
|
8646
|
-
|
|
8647
|
-
|
|
8833
|
+
return null;
|
|
8834
|
+
}
|
|
8835
|
+
function epochMsToIso(ms) {
|
|
8836
|
+
if (typeof ms !== "number" || Number.isNaN(ms)) return null;
|
|
8837
|
+
return new Date(ms).toISOString();
|
|
8838
|
+
}
|
|
8839
|
+
function windowFromLimit(limit) {
|
|
8840
|
+
return {
|
|
8841
|
+
utilization: typeof limit.percentage === "number" ? limit.percentage : null,
|
|
8842
|
+
resets_at: epochMsToIso(limit.nextResetTime)
|
|
8843
|
+
};
|
|
8844
|
+
}
|
|
8845
|
+
function zaiHeaders(key) {
|
|
8846
|
+
return { Authorization: key, "Accept-Language": "en-US,en" };
|
|
8847
|
+
}
|
|
8848
|
+
async function fetchZaiUsage() {
|
|
8849
|
+
const key = resolveApiKey();
|
|
8850
|
+
if (!key) {
|
|
8851
|
+
throw new ZaiApiError(
|
|
8852
|
+
"No Z.ai API key found. Set ZAI_API_KEY (or GLM_API_KEY), or write ~/.config/zai/key.json.",
|
|
8853
|
+
"no_key"
|
|
8854
|
+
);
|
|
8648
8855
|
}
|
|
8856
|
+
let res;
|
|
8649
8857
|
try {
|
|
8650
|
-
|
|
8651
|
-
saved += 1;
|
|
8858
|
+
res = await fetch(ZAI_QUOTA_ENDPOINT, { headers: zaiHeaders(key) });
|
|
8652
8859
|
} catch (err) {
|
|
8653
|
-
|
|
8654
|
-
console.warn(`grok usage: ${err.message}`);
|
|
8655
|
-
}
|
|
8656
|
-
}
|
|
8657
|
-
return saved;
|
|
8658
|
-
}
|
|
8659
|
-
async function usage(args2) {
|
|
8660
|
-
if (args2.includes("--help") || args2.includes("-h")) {
|
|
8661
|
-
console.log(`fleetlens usage \u2014 plan utilization snapshot
|
|
8662
|
-
|
|
8663
|
-
Usage:
|
|
8664
|
-
fleetlens usage [--save] Current 5h/7d plan utilization
|
|
8665
|
-
fleetlens usage --history [-s YYYYMMDD | --days N]
|
|
8666
|
-
Daily token / cost history table`);
|
|
8667
|
-
return;
|
|
8860
|
+
throw new ZaiApiError(`Network error reaching Z.ai: ${err.message}`, "network");
|
|
8668
8861
|
}
|
|
8669
|
-
if (
|
|
8670
|
-
|
|
8671
|
-
await history2(args2.filter((a) => a !== "--history"));
|
|
8672
|
-
return;
|
|
8862
|
+
if (!res.ok) {
|
|
8863
|
+
throw new ZaiApiError(`Z.ai quota endpoint returned ${res.status} ${res.statusText}`, "http");
|
|
8673
8864
|
}
|
|
8674
|
-
|
|
8675
|
-
let snapshot;
|
|
8865
|
+
let body;
|
|
8676
8866
|
try {
|
|
8677
|
-
|
|
8678
|
-
if (save) appendSnapshot(USAGE_LOG2, snapshot);
|
|
8679
|
-
process.stdout.write(formatUsage(snapshot));
|
|
8867
|
+
body = await res.json();
|
|
8680
8868
|
} catch (err) {
|
|
8681
|
-
|
|
8682
|
-
|
|
8683
|
-
|
|
8684
|
-
|
|
8685
|
-
|
|
8869
|
+
throw new ZaiApiError(`Failed to parse Z.ai quota response: ${err.message}`, "parse");
|
|
8870
|
+
}
|
|
8871
|
+
const b = body;
|
|
8872
|
+
const limits = b.data?.limits ?? [];
|
|
8873
|
+
let fiveHour = null;
|
|
8874
|
+
let sevenDay = null;
|
|
8875
|
+
let webSearch = null;
|
|
8876
|
+
for (const limit of limits) {
|
|
8877
|
+
if (limit.type === "TIME_LIMIT") {
|
|
8878
|
+
const percentage = typeof limit.percentage === "number" ? limit.percentage : null;
|
|
8879
|
+
webSearch = {
|
|
8880
|
+
used: percentage,
|
|
8881
|
+
limit: percentage !== null ? 100 : null
|
|
8882
|
+
};
|
|
8883
|
+
continue;
|
|
8686
8884
|
}
|
|
8687
|
-
const
|
|
8688
|
-
if (
|
|
8689
|
-
|
|
8690
|
-
|
|
8885
|
+
const window = windowFromLimit(limit);
|
|
8886
|
+
if (limit.unit === 6) {
|
|
8887
|
+
sevenDay = sevenDay ?? window;
|
|
8888
|
+
} else {
|
|
8889
|
+
fiveHour = fiveHour ?? window;
|
|
8691
8890
|
}
|
|
8692
|
-
return;
|
|
8693
8891
|
}
|
|
8694
|
-
|
|
8695
|
-
|
|
8892
|
+
let planType = null;
|
|
8893
|
+
try {
|
|
8894
|
+
const subRes = await fetch(ZAI_SUBSCRIPTION_ENDPOINT, { headers: zaiHeaders(key) });
|
|
8895
|
+
if (subRes.ok) {
|
|
8896
|
+
const sub = await subRes.json();
|
|
8897
|
+
const entry = sub.data?.[0];
|
|
8898
|
+
planType = entry?.productName || entry?.planName || entry?.name || null;
|
|
8899
|
+
}
|
|
8900
|
+
} catch {
|
|
8901
|
+
}
|
|
8902
|
+
return {
|
|
8903
|
+
captured_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8904
|
+
agent: "zai",
|
|
8905
|
+
five_hour: fiveHour ?? { utilization: null, resets_at: null },
|
|
8906
|
+
seven_day: sevenDay ?? { utilization: null, resets_at: null },
|
|
8907
|
+
seven_day_opus: null,
|
|
8908
|
+
seven_day_sonnet: null,
|
|
8909
|
+
seven_day_oauth_apps: null,
|
|
8910
|
+
seven_day_cowork: null,
|
|
8911
|
+
extra_usage: null,
|
|
8912
|
+
plan_type: planType,
|
|
8913
|
+
web_search_quota: webSearch ?? null
|
|
8914
|
+
};
|
|
8696
8915
|
}
|
|
8697
|
-
var
|
|
8698
|
-
var
|
|
8699
|
-
"src/
|
|
8916
|
+
var ZAI_QUOTA_ENDPOINT, ZAI_SUBSCRIPTION_ENDPOINT, ZaiApiError;
|
|
8917
|
+
var init_zai = __esm({
|
|
8918
|
+
"src/usage/zai.ts"() {
|
|
8700
8919
|
"use strict";
|
|
8701
|
-
init_api();
|
|
8702
|
-
init_grok2();
|
|
8703
|
-
init_codex2();
|
|
8704
|
-
init_copilot2();
|
|
8705
|
-
init_format();
|
|
8706
|
-
init_storage();
|
|
8707
8920
|
init_fs();
|
|
8708
|
-
|
|
8921
|
+
ZAI_QUOTA_ENDPOINT = "https://api.z.ai/api/monitor/usage/quota/limit";
|
|
8922
|
+
ZAI_SUBSCRIPTION_ENDPOINT = "https://api.z.ai/api/biz/subscription/list";
|
|
8923
|
+
ZaiApiError = class extends Error {
|
|
8924
|
+
constructor(message, code) {
|
|
8925
|
+
super(message);
|
|
8926
|
+
this.code = code;
|
|
8927
|
+
}
|
|
8928
|
+
};
|
|
8709
8929
|
}
|
|
8710
8930
|
});
|
|
8711
8931
|
|
|
8712
|
-
//
|
|
8713
|
-
function
|
|
8932
|
+
// src/usage/format.ts
|
|
8933
|
+
function barWidthFor(columns, labelWidth) {
|
|
8934
|
+
return Math.max(4, columns - labelWidth - 12);
|
|
8935
|
+
}
|
|
8936
|
+
function layoutForColumns(columns) {
|
|
8937
|
+
const cols = Number.isFinite(columns) && columns > 0 ? Math.floor(columns) : 80;
|
|
8938
|
+
if (cols < 36) {
|
|
8939
|
+
return {
|
|
8940
|
+
mode: "narrow",
|
|
8941
|
+
barWidth: 0,
|
|
8942
|
+
labelWidth: 4,
|
|
8943
|
+
shortLabels: true,
|
|
8944
|
+
columns: cols
|
|
8945
|
+
};
|
|
8946
|
+
}
|
|
8947
|
+
if (cols < 72) {
|
|
8948
|
+
const labelWidth2 = 4;
|
|
8949
|
+
return {
|
|
8950
|
+
mode: "medium",
|
|
8951
|
+
barWidth: barWidthFor(cols, labelWidth2),
|
|
8952
|
+
labelWidth: labelWidth2,
|
|
8953
|
+
shortLabels: true,
|
|
8954
|
+
columns: cols
|
|
8955
|
+
};
|
|
8956
|
+
}
|
|
8957
|
+
const labelWidth = 16;
|
|
8714
8958
|
return {
|
|
8715
|
-
|
|
8716
|
-
|
|
8717
|
-
|
|
8718
|
-
|
|
8719
|
-
|
|
8720
|
-
brief_summary: null,
|
|
8721
|
-
underlying_goal: null,
|
|
8722
|
-
friction_detail: null,
|
|
8723
|
-
user_instructions: [],
|
|
8724
|
-
outcome: null,
|
|
8725
|
-
claude_helpfulness: null,
|
|
8726
|
-
goal_categories: {},
|
|
8727
|
-
retry_count: 0
|
|
8959
|
+
mode: "wide",
|
|
8960
|
+
barWidth: barWidthFor(cols, labelWidth),
|
|
8961
|
+
labelWidth,
|
|
8962
|
+
shortLabels: false,
|
|
8963
|
+
columns: cols
|
|
8728
8964
|
};
|
|
8729
8965
|
}
|
|
8730
|
-
function
|
|
8731
|
-
|
|
8732
|
-
|
|
8733
|
-
|
|
8734
|
-
|
|
8735
|
-
|
|
8736
|
-
|
|
8737
|
-
|
|
8738
|
-
|
|
8739
|
-
friction_detail: null,
|
|
8740
|
-
user_instructions: [],
|
|
8741
|
-
outcome: "trivial",
|
|
8742
|
-
claude_helpfulness: null,
|
|
8743
|
-
goal_categories: {},
|
|
8744
|
-
retry_count: 0
|
|
8745
|
-
};
|
|
8746
|
-
}
|
|
8747
|
-
function entryKey(sessionId, localDay2) {
|
|
8748
|
-
return `${sessionId}__${localDay2}`;
|
|
8749
|
-
}
|
|
8750
|
-
function parseEntryKey(key) {
|
|
8751
|
-
const m = /^([^_]+(?:_[^_]+)*)__(\d{4}-\d{2}-\d{2})$/.exec(key);
|
|
8752
|
-
if (!m)
|
|
8753
|
-
return null;
|
|
8754
|
-
return { session_id: m[1], local_day: m[2] };
|
|
8966
|
+
function resolveColumns(explicit) {
|
|
8967
|
+
if (explicit !== void 0 && Number.isFinite(explicit) && explicit > 0) {
|
|
8968
|
+
return Math.floor(explicit);
|
|
8969
|
+
}
|
|
8970
|
+
const c = process.stdout.columns;
|
|
8971
|
+
if (typeof c === "number" && c > 0) return c;
|
|
8972
|
+
const env = parseInt(process.env.COLUMNS ?? "", 10);
|
|
8973
|
+
if (Number.isFinite(env) && env > 0) return env;
|
|
8974
|
+
return 80;
|
|
8755
8975
|
}
|
|
8756
|
-
|
|
8757
|
-
|
|
8758
|
-
|
|
8759
|
-
|
|
8760
|
-
|
|
8761
|
-
|
|
8762
|
-
|
|
8763
|
-
|
|
8764
|
-
|
|
8765
|
-
"
|
|
8766
|
-
|
|
8767
|
-
|
|
8768
|
-
|
|
8769
|
-
"
|
|
8770
|
-
|
|
8771
|
-
"release",
|
|
8772
|
-
"warmup_minimal"
|
|
8773
|
-
];
|
|
8774
|
-
CURRENT_DAY_DIGEST_SCHEMA_VERSION = 2;
|
|
8775
|
-
CURRENT_WEEK_DIGEST_SCHEMA_VERSION = 2;
|
|
8776
|
-
CURRENT_MONTH_DIGEST_SCHEMA_VERSION = 2;
|
|
8777
|
-
PROMPT_FRAME_ORIGIN = {
|
|
8778
|
-
teammate: "claude-feature",
|
|
8779
|
-
"task-notification": "claude-feature",
|
|
8780
|
-
"local-command-caveat": "claude-feature",
|
|
8781
|
-
"image-attached": "claude-feature",
|
|
8782
|
-
"slash-command": "claude-feature",
|
|
8783
|
-
"handoff-prose": "personal-habit"
|
|
8784
|
-
};
|
|
8976
|
+
function formatMultiAgentUsage(byAgent, opts = {}) {
|
|
8977
|
+
const kinds = Object.keys(byAgent).sort(compareAgents);
|
|
8978
|
+
if (kinds.length === 0) return "";
|
|
8979
|
+
const layout = layoutForColumns(resolveColumns(opts.columns));
|
|
8980
|
+
const lines = [];
|
|
8981
|
+
lines.push("");
|
|
8982
|
+
if (opts.watch) {
|
|
8983
|
+
const sec = opts.intervalSec ?? 2;
|
|
8984
|
+
lines.push(
|
|
8985
|
+
layout.mode === "narrow" ? ` ${BOLD}Usage${RESET} ${DIM}live ${sec}s \xB7 ^C quit${RESET}` : ` ${BOLD}Fleetlens Usage${RESET} ${DIM}live \xB7 every ${sec}s \xB7 Ctrl+C to quit${RESET}`
|
|
8986
|
+
);
|
|
8987
|
+
} else {
|
|
8988
|
+
lines.push(
|
|
8989
|
+
layout.mode === "narrow" ? ` ${BOLD}Usage${RESET}` : ` ${BOLD}Fleetlens Usage${RESET}`
|
|
8990
|
+
);
|
|
8785
8991
|
}
|
|
8786
|
-
|
|
8787
|
-
|
|
8788
|
-
|
|
8789
|
-
|
|
8790
|
-
"../parser/dist/types.js"() {
|
|
8791
|
-
"use strict";
|
|
8992
|
+
lines.push("");
|
|
8993
|
+
for (const kind of kinds) {
|
|
8994
|
+
const snap = byAgent[kind];
|
|
8995
|
+
lines.push(...formatAgentBlock(kind, snap, layout));
|
|
8792
8996
|
}
|
|
8793
|
-
|
|
8794
|
-
|
|
8795
|
-
// ../parser/dist/presentation.js
|
|
8796
|
-
function rowPrimaryIndex(r) {
|
|
8797
|
-
if (r.kind === "tool-group")
|
|
8798
|
-
return r.events[0].index;
|
|
8799
|
-
return r.event.index;
|
|
8997
|
+
lines.push("");
|
|
8998
|
+
return lines.join("\n");
|
|
8800
8999
|
}
|
|
8801
|
-
function
|
|
8802
|
-
const
|
|
8803
|
-
|
|
8804
|
-
|
|
8805
|
-
|
|
8806
|
-
|
|
8807
|
-
|
|
8808
|
-
|
|
8809
|
-
|
|
8810
|
-
|
|
8811
|
-
|
|
8812
|
-
|
|
8813
|
-
|
|
8814
|
-
const
|
|
8815
|
-
|
|
8816
|
-
const
|
|
8817
|
-
|
|
8818
|
-
agentMessages++;
|
|
8819
|
-
if (firstAgentIndex === void 0)
|
|
8820
|
-
firstAgentIndex = i;
|
|
8821
|
-
const msgId = r.event.messageId;
|
|
8822
|
-
const usage2 = r.event.usage;
|
|
8823
|
-
if (msgId && !seenMsgIds.has(msgId) && usage2) {
|
|
8824
|
-
seenMsgIds.add(msgId);
|
|
8825
|
-
tokens.input += usage2.input;
|
|
8826
|
-
tokens.output += usage2.output;
|
|
8827
|
-
tokens.cacheRead += usage2.cacheRead;
|
|
8828
|
-
tokens.cacheWrite += usage2.cacheWrite;
|
|
8829
|
-
}
|
|
8830
|
-
} else if (r.kind === "tool-group") {
|
|
8831
|
-
toolCalls += r.count;
|
|
8832
|
-
for (const t of r.toolNames) {
|
|
8833
|
-
toolMap.set(t.name, (toolMap.get(t.name) ?? 0) + t.count);
|
|
8834
|
-
}
|
|
8835
|
-
} else if (r.kind === "error") {
|
|
8836
|
-
errors++;
|
|
8837
|
-
}
|
|
9000
|
+
function formatAgentBlock(kind, snapshot, layout) {
|
|
9001
|
+
const lines = [];
|
|
9002
|
+
const title = layout.shortLabels && isAgentKind(kind) ? getAgentMetadata(kind)?.shortLabel ?? agentTitle(kind) : agentTitle(kind);
|
|
9003
|
+
const plan = snapshot.plan_type && layout.mode !== "narrow" ? ` ${DIM}${snapshot.plan_type}${RESET}` : "";
|
|
9004
|
+
lines.push(` ${BOLD}${title}${RESET}${plan}`);
|
|
9005
|
+
let renderedMeter = false;
|
|
9006
|
+
for (const [label, window] of agentWindows(kind, snapshot, layout.shortLabels)) {
|
|
9007
|
+
if (!window || window.utilization === null) continue;
|
|
9008
|
+
renderedMeter = true;
|
|
9009
|
+
lines.push(...formatMeterRow(label, window.utilization, window.resets_at, layout));
|
|
9010
|
+
}
|
|
9011
|
+
if ((kind === "claude-code" || !kind) && snapshot.extra_usage?.is_enabled) {
|
|
9012
|
+
renderedMeter = true;
|
|
9013
|
+
const extra = snapshot.extra_usage;
|
|
9014
|
+
if (extra.utilization !== null) {
|
|
9015
|
+
const label = layout.shortLabels ? "xtra" : "Extra usage";
|
|
9016
|
+
lines.push(...formatMeterRow(label, extra.utilization, null, layout));
|
|
8838
9017
|
}
|
|
8839
|
-
|
|
8840
|
-
|
|
8841
|
-
|
|
8842
|
-
|
|
8843
|
-
|
|
8844
|
-
const prev = buffer[i - 1];
|
|
8845
|
-
if (prev?.kind === "task-notification")
|
|
8846
|
-
continue;
|
|
8847
|
-
finalAgentIndex = i;
|
|
8848
|
-
break;
|
|
9018
|
+
if (extra.used_credits !== null && extra.monthly_limit !== null) {
|
|
9019
|
+
const pad2 = layout.mode === "narrow" ? 2 : layout.labelWidth + 2;
|
|
9020
|
+
lines.push(
|
|
9021
|
+
` ${" ".repeat(pad2)}${DIM}${extra.used_credits} / ${extra.monthly_limit} credits${RESET}`
|
|
9022
|
+
);
|
|
8849
9023
|
}
|
|
8850
|
-
|
|
8851
|
-
|
|
8852
|
-
|
|
8853
|
-
|
|
8854
|
-
|
|
8855
|
-
|
|
9024
|
+
}
|
|
9025
|
+
if (kind === "zai" && snapshot.web_search_quota) {
|
|
9026
|
+
const used = snapshot.web_search_quota.used;
|
|
9027
|
+
if (used !== null && used !== void 0) {
|
|
9028
|
+
renderedMeter = true;
|
|
9029
|
+
const label = layout.shortLabels ? "web" : "Web search";
|
|
9030
|
+
lines.push(...formatMeterRow(label, used, null, layout, { wholePct: true }));
|
|
9031
|
+
}
|
|
9032
|
+
}
|
|
9033
|
+
if (kind === "copilot" && snapshot.monthly_quota) {
|
|
9034
|
+
const q = snapshot.monthly_quota;
|
|
9035
|
+
const unit = q.unit === "premium-requests" ? "premium requests" : "AI credits";
|
|
9036
|
+
const pad2 = layout.mode === "narrow" ? 2 : layout.labelWidth + 2;
|
|
9037
|
+
if (q.unlimited) {
|
|
9038
|
+
renderedMeter = true;
|
|
9039
|
+
const lab = layout.shortLabels ? "mo" : "Monthly";
|
|
9040
|
+
lines.push(` ${lab.padEnd(layout.labelWidth)}${BOLD}Limit not reported${RESET}`);
|
|
9041
|
+
if (q.used !== null) {
|
|
9042
|
+
lines.push(
|
|
9043
|
+
` ${" ".repeat(pad2)}${DIM}${q.used.toLocaleString("en-US")} ${unit}${RESET}`
|
|
9044
|
+
);
|
|
8856
9045
|
}
|
|
9046
|
+
} else if (q.used !== null && q.limit !== null) {
|
|
9047
|
+
lines.push(
|
|
9048
|
+
` ${" ".repeat(pad2)}${DIM}${q.used} / ${q.limit} ${unit}${RESET}`
|
|
9049
|
+
);
|
|
8857
9050
|
}
|
|
8858
|
-
|
|
8859
|
-
|
|
8860
|
-
|
|
8861
|
-
|
|
8862
|
-
|
|
8863
|
-
|
|
8864
|
-
|
|
8865
|
-
|
|
8866
|
-
|
|
8867
|
-
|
|
8868
|
-
|
|
8869
|
-
|
|
8870
|
-
|
|
8871
|
-
|
|
8872
|
-
|
|
8873
|
-
|
|
8874
|
-
|
|
8875
|
-
|
|
8876
|
-
|
|
8877
|
-
|
|
8878
|
-
|
|
8879
|
-
|
|
8880
|
-
|
|
8881
|
-
|
|
8882
|
-
|
|
8883
|
-
|
|
8884
|
-
|
|
8885
|
-
|
|
9051
|
+
}
|
|
9052
|
+
if (!renderedMeter) {
|
|
9053
|
+
lines.push(` ${DIM}(no utilization windows)${RESET}`);
|
|
9054
|
+
}
|
|
9055
|
+
lines.push(
|
|
9056
|
+
` ${DIM}sampled ${formatRelative(snapshot.captured_at)}${RESET}`
|
|
9057
|
+
);
|
|
9058
|
+
lines.push("");
|
|
9059
|
+
return lines;
|
|
9060
|
+
}
|
|
9061
|
+
function formatMeterRow(label, utilization, resetsAt, layout, opts = {}) {
|
|
9062
|
+
const pctStr = opts.wholePct ? `${utilization.toFixed(0)}%`.padStart(5) : `${utilization.toFixed(1)}%`.padStart(6);
|
|
9063
|
+
const labelStr = label.padEnd(layout.labelWidth);
|
|
9064
|
+
if (layout.mode === "narrow" && layout.barWidth <= 0) {
|
|
9065
|
+
const reset = resetsAt ? ` ${DIM}r${formatRelativeShort(resetsAt)}${RESET}` : "";
|
|
9066
|
+
return [` ${labelStr}${BOLD}${pctStr}${RESET}${reset}`];
|
|
9067
|
+
}
|
|
9068
|
+
const bar = renderBar(utilization, layout.barWidth);
|
|
9069
|
+
const lines = [` ${labelStr}${bar} ${BOLD}${pctStr}${RESET} `];
|
|
9070
|
+
if (resetsAt) {
|
|
9071
|
+
lines.push(
|
|
9072
|
+
` ${" ".repeat(layout.labelWidth)}${DIM}resets ${formatRelative(resetsAt)}${RESET}`
|
|
9073
|
+
);
|
|
9074
|
+
}
|
|
9075
|
+
return lines;
|
|
9076
|
+
}
|
|
9077
|
+
function agentWindows(kind, snapshot, shortLabels) {
|
|
9078
|
+
const L = shortLabels ? { five: "5h", seven: "7d", monthly: "mo", opus: "opus", sonnet: "son", oauth: "oath", cowork: "cowk" } : {
|
|
9079
|
+
five: "5 hour",
|
|
9080
|
+
seven: "7 day",
|
|
9081
|
+
monthly: "Monthly",
|
|
9082
|
+
opus: "7 day (Opus)",
|
|
9083
|
+
sonnet: "7 day (Sonnet)",
|
|
9084
|
+
oauth: "7 day (OAuth apps)",
|
|
9085
|
+
cowork: "7 day (Cowork)"
|
|
8886
9086
|
};
|
|
8887
|
-
|
|
8888
|
-
|
|
8889
|
-
|
|
8890
|
-
|
|
8891
|
-
|
|
8892
|
-
|
|
8893
|
-
|
|
9087
|
+
if (kind === "copilot") {
|
|
9088
|
+
return [[L.monthly, snapshot.monthly]];
|
|
9089
|
+
}
|
|
9090
|
+
if (kind === "grok") {
|
|
9091
|
+
return [[L.seven, snapshot.seven_day]];
|
|
9092
|
+
}
|
|
9093
|
+
if (kind === "codex" && snapshot.five_hour?.utilization == null) {
|
|
9094
|
+
return [[L.seven, snapshot.seven_day]];
|
|
9095
|
+
}
|
|
9096
|
+
const rows = [
|
|
9097
|
+
[L.five, snapshot.five_hour],
|
|
9098
|
+
[L.seven, snapshot.seven_day]
|
|
9099
|
+
];
|
|
9100
|
+
if (kind === "claude-code" || !snapshot.agent) {
|
|
9101
|
+
if (snapshot.seven_day_opus?.utilization != null) {
|
|
9102
|
+
rows.push([L.opus, snapshot.seven_day_opus]);
|
|
9103
|
+
}
|
|
9104
|
+
if (snapshot.seven_day_sonnet?.utilization != null) {
|
|
9105
|
+
rows.push([L.sonnet, snapshot.seven_day_sonnet]);
|
|
9106
|
+
}
|
|
9107
|
+
if (snapshot.seven_day_oauth_apps?.utilization != null) {
|
|
9108
|
+
rows.push([L.oauth, snapshot.seven_day_oauth_apps]);
|
|
9109
|
+
}
|
|
9110
|
+
if (snapshot.seven_day_cowork?.utilization != null) {
|
|
9111
|
+
rows.push([L.cowork, snapshot.seven_day_cowork]);
|
|
8894
9112
|
}
|
|
8895
9113
|
}
|
|
8896
|
-
|
|
8897
|
-
return out;
|
|
9114
|
+
return rows;
|
|
8898
9115
|
}
|
|
8899
|
-
function
|
|
8900
|
-
if (
|
|
8901
|
-
return
|
|
8902
|
-
|
|
8903
|
-
|
|
8904
|
-
return m ? m[1].trim() : void 0;
|
|
8905
|
-
};
|
|
8906
|
-
const statusRaw = (pick("status") ?? "").toLowerCase();
|
|
8907
|
-
let status2 = "unknown";
|
|
8908
|
-
if (statusRaw === "success" || statusRaw === "ok" || statusRaw === "done" || statusRaw === "completed")
|
|
8909
|
-
status2 = "success";
|
|
8910
|
-
else if (statusRaw === "failed" || statusRaw === "error" || statusRaw === "fail")
|
|
8911
|
-
status2 = "failed";
|
|
8912
|
-
else if (statusRaw === "running" || statusRaw === "in_progress")
|
|
8913
|
-
status2 = "running";
|
|
8914
|
-
return {
|
|
8915
|
-
status: status2,
|
|
8916
|
-
summary: pick("summary") ?? "Background task notification",
|
|
8917
|
-
taskId: pick("task-id"),
|
|
8918
|
-
toolUseId: pick("tool-use-id"),
|
|
8919
|
-
outputFile: pick("output-file")
|
|
8920
|
-
};
|
|
9116
|
+
function agentTitle(kind) {
|
|
9117
|
+
if (isAgentKind(kind)) {
|
|
9118
|
+
return getAgentMetadata(kind)?.displayName ?? kind;
|
|
9119
|
+
}
|
|
9120
|
+
return kind;
|
|
8921
9121
|
}
|
|
8922
|
-
function
|
|
8923
|
-
|
|
9122
|
+
function compareAgents(a, b) {
|
|
9123
|
+
const ia = AGENT_PRIORITY.indexOf(a);
|
|
9124
|
+
const ib = AGENT_PRIORITY.indexOf(b);
|
|
9125
|
+
if (ia !== -1 || ib !== -1) {
|
|
9126
|
+
if (ia === -1) return 1;
|
|
9127
|
+
if (ib === -1) return -1;
|
|
9128
|
+
return ia - ib;
|
|
9129
|
+
}
|
|
9130
|
+
return a.localeCompare(b);
|
|
8924
9131
|
}
|
|
8925
|
-
function
|
|
8926
|
-
|
|
8927
|
-
|
|
8928
|
-
|
|
9132
|
+
function renderBar(utilization, barWidth) {
|
|
9133
|
+
if (barWidth <= 0) return "";
|
|
9134
|
+
const clamped = Math.max(0, Math.min(100, utilization));
|
|
9135
|
+
const color = clamped >= 90 ? RED : clamped >= 70 ? YELLOW : GREEN;
|
|
9136
|
+
const totalEighths = Math.round(clamped / 100 * barWidth * 8);
|
|
9137
|
+
const fullBlocks = Math.floor(totalEighths / 8);
|
|
9138
|
+
const remainder = totalEighths % 8;
|
|
9139
|
+
const partial = EIGHTHS[remainder];
|
|
9140
|
+
const filledCells = fullBlocks + (partial ? 1 : 0);
|
|
9141
|
+
const emptyCells = Math.max(0, barWidth - filledCells);
|
|
9142
|
+
const filled = "\u2588".repeat(fullBlocks) + partial;
|
|
9143
|
+
const empty = "\xB7".repeat(emptyCells);
|
|
9144
|
+
return `${color}${filled}${RESET}${DIM}${empty}${RESET}`;
|
|
9145
|
+
}
|
|
9146
|
+
function formatRelative(iso) {
|
|
9147
|
+
const then = new Date(iso).getTime();
|
|
9148
|
+
const now = Date.now();
|
|
9149
|
+
const diffSec = Math.round((then - now) / 1e3);
|
|
9150
|
+
const abs = Math.abs(diffSec);
|
|
9151
|
+
const past = diffSec < 0;
|
|
9152
|
+
let value;
|
|
9153
|
+
if (abs < 60) {
|
|
9154
|
+
value = `${abs}s`;
|
|
9155
|
+
} else if (abs < 3600) {
|
|
9156
|
+
value = `${Math.floor(abs / 60)}m`;
|
|
9157
|
+
} else if (abs < 86400) {
|
|
9158
|
+
const h = Math.floor(abs / 3600);
|
|
9159
|
+
const m = Math.floor(abs % 3600 / 60);
|
|
9160
|
+
value = m > 0 ? `${h}h${m}m` : `${h}h`;
|
|
9161
|
+
} else {
|
|
9162
|
+
const d = Math.floor(abs / 86400);
|
|
9163
|
+
const h = Math.floor(abs % 86400 / 3600);
|
|
9164
|
+
value = h > 0 ? `${d}d${h}h` : `${d}d`;
|
|
8929
9165
|
}
|
|
8930
|
-
return
|
|
9166
|
+
return past ? `${value} ago` : `in ${value}`;
|
|
8931
9167
|
}
|
|
8932
|
-
function
|
|
8933
|
-
|
|
8934
|
-
|
|
8935
|
-
const
|
|
8936
|
-
|
|
9168
|
+
function formatRelativeShort(iso) {
|
|
9169
|
+
const then = new Date(iso).getTime();
|
|
9170
|
+
const now = Date.now();
|
|
9171
|
+
const abs = Math.abs(Math.round((then - now) / 1e3));
|
|
9172
|
+
if (abs < 60) return `${abs}s`;
|
|
9173
|
+
if (abs < 3600) return `${Math.floor(abs / 60)}m`;
|
|
9174
|
+
if (abs < 86400) return `${Math.floor(abs / 3600)}h`;
|
|
9175
|
+
return `${Math.floor(abs / 86400)}d`;
|
|
8937
9176
|
}
|
|
8938
|
-
|
|
8939
|
-
|
|
8940
|
-
|
|
8941
|
-
|
|
8942
|
-
|
|
8943
|
-
|
|
8944
|
-
|
|
8945
|
-
|
|
9177
|
+
var DIM, BOLD, RESET, GREEN, YELLOW, RED, EIGHTHS, AGENT_PRIORITY;
|
|
9178
|
+
var init_format = __esm({
|
|
9179
|
+
"src/usage/format.ts"() {
|
|
9180
|
+
"use strict";
|
|
9181
|
+
init_dist();
|
|
9182
|
+
DIM = "\x1B[2m";
|
|
9183
|
+
BOLD = "\x1B[1m";
|
|
9184
|
+
RESET = "\x1B[0m";
|
|
9185
|
+
GREEN = "\x1B[32m";
|
|
9186
|
+
YELLOW = "\x1B[33m";
|
|
9187
|
+
RED = "\x1B[31m";
|
|
9188
|
+
EIGHTHS = ["", "\u258F", "\u258E", "\u258D", "\u258C", "\u258B", "\u258A", "\u2589"];
|
|
9189
|
+
AGENT_PRIORITY = ["claude-code", "codex", "copilot", "zai", "grok"];
|
|
8946
9190
|
}
|
|
8947
|
-
|
|
8948
|
-
|
|
8949
|
-
|
|
8950
|
-
|
|
8951
|
-
|
|
8952
|
-
if (
|
|
8953
|
-
|
|
8954
|
-
|
|
8955
|
-
|
|
8956
|
-
|
|
8957
|
-
|
|
8958
|
-
|
|
8959
|
-
|
|
8960
|
-
|
|
8961
|
-
|
|
8962
|
-
|
|
8963
|
-
|
|
8964
|
-
|
|
8965
|
-
|
|
8966
|
-
|
|
8967
|
-
|
|
8968
|
-
|
|
8969
|
-
|
|
8970
|
-
|
|
8971
|
-
|
|
8972
|
-
|
|
8973
|
-
|
|
8974
|
-
|
|
8975
|
-
|
|
8976
|
-
|
|
8977
|
-
|
|
8978
|
-
|
|
8979
|
-
|
|
8980
|
-
|
|
8981
|
-
|
|
8982
|
-
|
|
8983
|
-
|
|
8984
|
-
|
|
8985
|
-
|
|
8986
|
-
|
|
8987
|
-
|
|
8988
|
-
|
|
8989
|
-
|
|
8990
|
-
|
|
8991
|
-
|
|
8992
|
-
|
|
8993
|
-
|
|
8994
|
-
|
|
8995
|
-
|
|
8996
|
-
|
|
8997
|
-
|
|
8998
|
-
|
|
8999
|
-
|
|
9000
|
-
|
|
9001
|
-
|
|
9002
|
-
|
|
9003
|
-
|
|
9004
|
-
|
|
9005
|
-
|
|
9006
|
-
|
|
9007
|
-
|
|
9008
|
-
|
|
9009
|
-
|
|
9010
|
-
|
|
9011
|
-
|
|
9012
|
-
|
|
9013
|
-
|
|
9014
|
-
|
|
9015
|
-
|
|
9016
|
-
|
|
9017
|
-
|
|
9018
|
-
|
|
9019
|
-
|
|
9020
|
-
|
|
9021
|
-
|
|
9022
|
-
|
|
9023
|
-
|
|
9024
|
-
|
|
9025
|
-
|
|
9026
|
-
|
|
9027
|
-
|
|
9028
|
-
|
|
9029
|
-
|
|
9030
|
-
|
|
9031
|
-
|
|
9032
|
-
|
|
9033
|
-
|
|
9034
|
-
|
|
9035
|
-
|
|
9036
|
-
|
|
9037
|
-
|
|
9191
|
+
});
|
|
9192
|
+
|
|
9193
|
+
// src/pricing.ts
|
|
9194
|
+
function findPricing(model) {
|
|
9195
|
+
for (const [prefix, pricing] of PRICING) {
|
|
9196
|
+
if (model.startsWith(prefix)) return pricing;
|
|
9197
|
+
}
|
|
9198
|
+
return null;
|
|
9199
|
+
}
|
|
9200
|
+
function estimateCost(model, usage2) {
|
|
9201
|
+
const p = findPricing(model);
|
|
9202
|
+
if (!p) return null;
|
|
9203
|
+
return (usage2.input * p.input + usage2.output * p.output + usage2.cacheRead * p.cacheRead + usage2.cacheWrite * p.cacheWrite) / 1e6;
|
|
9204
|
+
}
|
|
9205
|
+
var PRICING;
|
|
9206
|
+
var init_pricing = __esm({
|
|
9207
|
+
"src/pricing.ts"() {
|
|
9208
|
+
"use strict";
|
|
9209
|
+
PRICING = [
|
|
9210
|
+
["claude-opus-4", { input: 15, output: 75, cacheRead: 1.5, cacheWrite: 18.75 }],
|
|
9211
|
+
["claude-sonnet-4", { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }],
|
|
9212
|
+
["claude-haiku-4", { input: 0.8, output: 4, cacheRead: 0.08, cacheWrite: 1 }],
|
|
9213
|
+
["claude-3-5-sonnet", { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }],
|
|
9214
|
+
["claude-3-5-haiku", { input: 0.8, output: 4, cacheRead: 0.08, cacheWrite: 1 }],
|
|
9215
|
+
["claude-3-opus", { input: 15, output: 75, cacheRead: 1.5, cacheWrite: 18.75 }]
|
|
9216
|
+
];
|
|
9217
|
+
}
|
|
9218
|
+
});
|
|
9219
|
+
|
|
9220
|
+
// src/table.ts
|
|
9221
|
+
function fmtNum(n) {
|
|
9222
|
+
return n.toLocaleString("en-US");
|
|
9223
|
+
}
|
|
9224
|
+
function fmtCost(cost, partial = false) {
|
|
9225
|
+
if (cost === null) return "\u2014";
|
|
9226
|
+
return `${partial ? "\u2265" : ""}$${cost.toFixed(2)}`;
|
|
9227
|
+
}
|
|
9228
|
+
function pad(s, width, align = "right") {
|
|
9229
|
+
if (align === "left") return s.padEnd(width);
|
|
9230
|
+
return s.padStart(width);
|
|
9231
|
+
}
|
|
9232
|
+
function renderTable(rows, title) {
|
|
9233
|
+
const lines = [];
|
|
9234
|
+
lines.push("");
|
|
9235
|
+
lines.push(`${BOLD2}${title}${RESET2}`);
|
|
9236
|
+
lines.push("");
|
|
9237
|
+
const header = [
|
|
9238
|
+
pad("Date", 12, "left"),
|
|
9239
|
+
pad("Models", 20, "left"),
|
|
9240
|
+
pad("Input", 12),
|
|
9241
|
+
pad("Output", 12),
|
|
9242
|
+
pad("Cache Create", 14),
|
|
9243
|
+
pad("Cache Read", 14),
|
|
9244
|
+
pad("Total", 14),
|
|
9245
|
+
pad("Cost (USD)", 12)
|
|
9246
|
+
].join(" ");
|
|
9247
|
+
lines.push(`${DIM2}${header}${RESET2}`);
|
|
9248
|
+
lines.push(`${DIM2}${"\u2500".repeat(header.length)}${RESET2}`);
|
|
9249
|
+
let costIncomplete = false;
|
|
9250
|
+
for (const r of rows) {
|
|
9251
|
+
if (r.cost === null || r.costPartial) costIncomplete = true;
|
|
9252
|
+
lines.push([
|
|
9253
|
+
pad(r.date, 12, "left"),
|
|
9254
|
+
pad(r.models, 20, "left"),
|
|
9255
|
+
pad(fmtNum(r.input), 12),
|
|
9256
|
+
pad(fmtNum(r.output), 12),
|
|
9257
|
+
pad(fmtNum(r.cacheCreate), 14),
|
|
9258
|
+
pad(fmtNum(r.cacheRead), 14),
|
|
9259
|
+
pad(fmtNum(r.totalTokens), 14),
|
|
9260
|
+
pad(fmtCost(r.cost, r.costPartial), 12)
|
|
9261
|
+
].join(" "));
|
|
9262
|
+
}
|
|
9263
|
+
const totals = rows.reduce(
|
|
9264
|
+
(acc, r) => ({
|
|
9265
|
+
input: acc.input + r.input,
|
|
9266
|
+
output: acc.output + r.output,
|
|
9267
|
+
cacheCreate: acc.cacheCreate + r.cacheCreate,
|
|
9268
|
+
cacheRead: acc.cacheRead + r.cacheRead,
|
|
9269
|
+
totalTokens: acc.totalTokens + r.totalTokens,
|
|
9270
|
+
cost: acc.cost + (r.cost ?? 0),
|
|
9271
|
+
anyCost: acc.anyCost || r.cost !== null
|
|
9272
|
+
}),
|
|
9273
|
+
{ input: 0, output: 0, cacheCreate: 0, cacheRead: 0, totalTokens: 0, cost: 0, anyCost: false }
|
|
9274
|
+
);
|
|
9275
|
+
lines.push(`${DIM2}${"\u2500".repeat(header.length)}${RESET2}`);
|
|
9276
|
+
lines.push(
|
|
9277
|
+
`${BOLD2}${[
|
|
9278
|
+
pad("Total", 12, "left"),
|
|
9279
|
+
pad("", 20, "left"),
|
|
9280
|
+
pad(fmtNum(totals.input), 12),
|
|
9281
|
+
pad(fmtNum(totals.output), 12),
|
|
9282
|
+
pad(fmtNum(totals.cacheCreate), 14),
|
|
9283
|
+
pad(fmtNum(totals.cacheRead), 14),
|
|
9284
|
+
pad(fmtNum(totals.totalTokens), 14),
|
|
9285
|
+
pad(totals.anyCost ? fmtCost(totals.cost, costIncomplete) : fmtCost(null), 12)
|
|
9286
|
+
].join(" ")}${RESET2}`
|
|
9287
|
+
);
|
|
9288
|
+
if (costIncomplete) {
|
|
9289
|
+
lines.push("");
|
|
9290
|
+
lines.push(
|
|
9291
|
+
`${DIM2} Cost covers priced usage only \u2014 "\u2014" = no priced sessions that day, "\u2265" = lower bound (some sessions had unknown pricing).${RESET2}`
|
|
9292
|
+
);
|
|
9293
|
+
}
|
|
9294
|
+
lines.push("");
|
|
9295
|
+
return lines.join("\n");
|
|
9296
|
+
}
|
|
9297
|
+
var DIM2, BOLD2, RESET2;
|
|
9298
|
+
var init_table = __esm({
|
|
9299
|
+
"src/table.ts"() {
|
|
9300
|
+
"use strict";
|
|
9301
|
+
DIM2 = "\x1B[2m";
|
|
9302
|
+
BOLD2 = "\x1B[1m";
|
|
9303
|
+
RESET2 = "\x1B[0m";
|
|
9304
|
+
}
|
|
9305
|
+
});
|
|
9306
|
+
|
|
9307
|
+
// src/commands/usage-history.ts
|
|
9308
|
+
var usage_history_exports = {};
|
|
9309
|
+
__export(usage_history_exports, {
|
|
9310
|
+
history: () => history
|
|
9311
|
+
});
|
|
9312
|
+
async function history(args2) {
|
|
9313
|
+
const live = args2.includes("--live");
|
|
9314
|
+
const sinceIdx = args2.indexOf("-s");
|
|
9315
|
+
const daysIdx = args2.indexOf("--days");
|
|
9316
|
+
let sinceDate = null;
|
|
9317
|
+
if (sinceIdx !== -1 && args2[sinceIdx + 1]) {
|
|
9318
|
+
const raw = args2[sinceIdx + 1];
|
|
9319
|
+
sinceDate = /* @__PURE__ */ new Date(`${raw.slice(0, 4)}-${raw.slice(4, 6)}-${raw.slice(6, 8)}`);
|
|
9320
|
+
} else if (daysIdx !== -1 && args2[daysIdx + 1]) {
|
|
9321
|
+
const days = parseInt(args2[daysIdx + 1], 10);
|
|
9322
|
+
sinceDate = /* @__PURE__ */ new Date();
|
|
9323
|
+
sinceDate.setDate(sinceDate.getDate() - days);
|
|
9324
|
+
sinceDate.setHours(0, 0, 0, 0);
|
|
9325
|
+
}
|
|
9326
|
+
if (live) {
|
|
9327
|
+
await liveStats(sinceDate);
|
|
9328
|
+
} else {
|
|
9329
|
+
await printStats(sinceDate);
|
|
9330
|
+
}
|
|
9331
|
+
}
|
|
9332
|
+
async function printStats(sinceDate) {
|
|
9333
|
+
const sessions = await listSessions({ limit: 1e4 });
|
|
9334
|
+
const filtered = sinceDate ? sessions.filter((s) => s.firstTimestamp && new Date(s.firstTimestamp) >= sinceDate) : sessions;
|
|
9335
|
+
const rows = aggregateByDay(filtered);
|
|
9336
|
+
const output = renderTable(rows, "Claude Code Token Usage Report \u2014 Daily");
|
|
9337
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
9338
|
+
const todaySessions = filtered.filter((s) => s.firstTimestamp?.startsWith(today)).length;
|
|
9339
|
+
const status2 = getServerStatus();
|
|
9340
|
+
const serverLine = status2.running ? `Server running on http://localhost:${status2.port}` : "Server not running";
|
|
9341
|
+
console.log(output);
|
|
9342
|
+
console.log(` ${todaySessions} sessions today \xB7 ${serverLine}`);
|
|
9343
|
+
console.log("");
|
|
9344
|
+
}
|
|
9345
|
+
function displayModel(raw) {
|
|
9346
|
+
return raw.replace(/-\d{8}$/, "").replace(/^claude-/, "");
|
|
9347
|
+
}
|
|
9348
|
+
function aggregateByDay(sessions) {
|
|
9349
|
+
const byDay = /* @__PURE__ */ new Map();
|
|
9350
|
+
for (const s of sessions) {
|
|
9351
|
+
const day2 = s.firstTimestamp?.slice(0, 10) ?? "unknown";
|
|
9352
|
+
if (!byDay.has(day2)) byDay.set(day2, { sessions: [], models: /* @__PURE__ */ new Set() });
|
|
9353
|
+
const bucket = byDay.get(day2);
|
|
9354
|
+
bucket.sessions.push(s);
|
|
9355
|
+
if (s.model) bucket.models.add(displayModel(s.model));
|
|
9356
|
+
}
|
|
9357
|
+
const sorted = [...byDay.entries()].sort((a, b) => b[0].localeCompare(a[0]));
|
|
9358
|
+
return sorted.map(([date, { sessions: sessions2, models }]) => {
|
|
9359
|
+
const usage2 = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
|
|
9360
|
+
let cost = 0;
|
|
9361
|
+
let anyPriced = false;
|
|
9362
|
+
let anyUnpriced = false;
|
|
9363
|
+
for (const s of sessions2) {
|
|
9364
|
+
usage2.input += s.totalUsage.input;
|
|
9365
|
+
usage2.output += s.totalUsage.output;
|
|
9366
|
+
usage2.cacheRead += s.totalUsage.cacheRead;
|
|
9367
|
+
usage2.cacheWrite += s.totalUsage.cacheWrite;
|
|
9368
|
+
if (s.model) {
|
|
9369
|
+
const c = estimateCost(s.model, s.totalUsage);
|
|
9370
|
+
if (c !== null) {
|
|
9371
|
+
cost += c;
|
|
9372
|
+
anyPriced = true;
|
|
9373
|
+
} else {
|
|
9374
|
+
anyUnpriced = true;
|
|
9375
|
+
}
|
|
9038
9376
|
}
|
|
9039
|
-
rows.push({
|
|
9040
|
-
kind: "user",
|
|
9041
|
-
event: e,
|
|
9042
|
-
tOffsetMs: e.tOffsetMs,
|
|
9043
|
-
gapMs: e.gapMs
|
|
9044
|
-
});
|
|
9045
|
-
continue;
|
|
9046
9377
|
}
|
|
9047
|
-
|
|
9048
|
-
|
|
9049
|
-
|
|
9050
|
-
|
|
9051
|
-
|
|
9052
|
-
|
|
9053
|
-
|
|
9054
|
-
|
|
9055
|
-
|
|
9056
|
-
|
|
9057
|
-
|
|
9058
|
-
|
|
9059
|
-
|
|
9060
|
-
|
|
9061
|
-
|
|
9062
|
-
|
|
9063
|
-
|
|
9064
|
-
|
|
9065
|
-
|
|
9378
|
+
const modelNames = [...models].join(", ");
|
|
9379
|
+
return {
|
|
9380
|
+
date,
|
|
9381
|
+
models: modelNames || "\u2014",
|
|
9382
|
+
input: usage2.input,
|
|
9383
|
+
output: usage2.output,
|
|
9384
|
+
cacheCreate: usage2.cacheWrite,
|
|
9385
|
+
cacheRead: usage2.cacheRead,
|
|
9386
|
+
totalTokens: usage2.input + usage2.output + usage2.cacheRead + usage2.cacheWrite,
|
|
9387
|
+
cost: anyPriced ? cost : null,
|
|
9388
|
+
costPartial: anyPriced && anyUnpriced
|
|
9389
|
+
};
|
|
9390
|
+
});
|
|
9391
|
+
}
|
|
9392
|
+
async function liveStats(sinceDate) {
|
|
9393
|
+
if (process.stdin.isTTY) {
|
|
9394
|
+
process.stdin.setRawMode(true);
|
|
9395
|
+
process.stdin.resume();
|
|
9396
|
+
process.stdin.on("data", (data) => {
|
|
9397
|
+
if (data.toString() === "q" || data.toString() === "") {
|
|
9398
|
+
process.stdout.write("\x1B[?25h");
|
|
9399
|
+
process.exit(0);
|
|
9066
9400
|
}
|
|
9067
|
-
|
|
9068
|
-
|
|
9069
|
-
|
|
9070
|
-
|
|
9071
|
-
|
|
9072
|
-
|
|
9073
|
-
|
|
9074
|
-
|
|
9075
|
-
|
|
9401
|
+
});
|
|
9402
|
+
}
|
|
9403
|
+
const refresh = async () => {
|
|
9404
|
+
const sessions = await listSessions({ limit: 1e4 });
|
|
9405
|
+
const filtered = sinceDate ? sessions.filter((s) => s.firstTimestamp && new Date(s.firstTimestamp) >= sinceDate) : sessions;
|
|
9406
|
+
const rows = aggregateByDay(filtered);
|
|
9407
|
+
const output = renderTable(rows, "Claude Code Token Usage Report \u2014 Live (q to quit)");
|
|
9408
|
+
process.stdout.write("\x1B[2J\x1B[H");
|
|
9409
|
+
process.stdout.write("\x1B[?25l");
|
|
9410
|
+
process.stdout.write(output);
|
|
9411
|
+
const running = filtered.filter((s) => s.status === "running");
|
|
9412
|
+
if (running.length > 0) {
|
|
9413
|
+
process.stdout.write(" Active Sessions\n");
|
|
9414
|
+
for (const s of running.slice(0, 5)) {
|
|
9415
|
+
const project = s.projectName.split("/").slice(-2).join("/");
|
|
9416
|
+
const tokens = s.totalUsage.input + s.totalUsage.output;
|
|
9417
|
+
process.stdout.write(` ${project.padEnd(30)} ${tokens.toLocaleString()} tokens
|
|
9418
|
+
`);
|
|
9076
9419
|
}
|
|
9077
|
-
|
|
9078
|
-
rows.push({
|
|
9079
|
-
kind: "agent",
|
|
9080
|
-
event: e,
|
|
9081
|
-
groupedEvents: grouped,
|
|
9082
|
-
tOffsetMs: e.tOffsetMs,
|
|
9083
|
-
gapMs: e.gapMs
|
|
9084
|
-
});
|
|
9085
|
-
continue;
|
|
9420
|
+
process.stdout.write("\n");
|
|
9086
9421
|
}
|
|
9087
|
-
}
|
|
9088
|
-
|
|
9422
|
+
};
|
|
9423
|
+
await refresh();
|
|
9424
|
+
setInterval(refresh, 2e3);
|
|
9089
9425
|
}
|
|
9090
|
-
var
|
|
9091
|
-
|
|
9092
|
-
"../parser/dist/presentation.js"() {
|
|
9426
|
+
var init_usage_history = __esm({
|
|
9427
|
+
"src/commands/usage-history.ts"() {
|
|
9093
9428
|
"use strict";
|
|
9094
|
-
|
|
9095
|
-
|
|
9096
|
-
|
|
9097
|
-
|
|
9098
|
-
TASK_NOTIFICATION_RE = /<task-notification>/;
|
|
9429
|
+
init_fs();
|
|
9430
|
+
init_pricing();
|
|
9431
|
+
init_table();
|
|
9432
|
+
init_server();
|
|
9099
9433
|
}
|
|
9100
9434
|
});
|
|
9101
9435
|
|
|
9102
|
-
//
|
|
9103
|
-
|
|
9104
|
-
|
|
9105
|
-
|
|
9106
|
-
|
|
9107
|
-
|
|
9108
|
-
|
|
9109
|
-
const
|
|
9110
|
-
|
|
9111
|
-
|
|
9112
|
-
|
|
9436
|
+
// src/commands/usage.ts
|
|
9437
|
+
var usage_exports = {};
|
|
9438
|
+
__export(usage_exports, {
|
|
9439
|
+
usage: () => usage
|
|
9440
|
+
});
|
|
9441
|
+
async function saveAuxiliarySnapshots() {
|
|
9442
|
+
let saved = 0;
|
|
9443
|
+
for (const source of agentSources) {
|
|
9444
|
+
if (source.kind === "claude-code" || !source.usagePoller) continue;
|
|
9445
|
+
try {
|
|
9446
|
+
const partial = await source.usagePoller();
|
|
9447
|
+
if (!partial) continue;
|
|
9448
|
+
appendSnapshot(USAGE_LOG2, {
|
|
9449
|
+
...partial,
|
|
9450
|
+
seven_day_opus: null,
|
|
9451
|
+
seven_day_sonnet: null,
|
|
9452
|
+
seven_day_oauth_apps: null,
|
|
9453
|
+
seven_day_cowork: null,
|
|
9454
|
+
extra_usage: null
|
|
9455
|
+
});
|
|
9456
|
+
saved += 1;
|
|
9457
|
+
} catch {
|
|
9458
|
+
}
|
|
9113
9459
|
}
|
|
9114
|
-
|
|
9115
|
-
|
|
9116
|
-
|
|
9117
|
-
|
|
9118
|
-
|
|
9119
|
-
|
|
9120
|
-
|
|
9121
|
-
|
|
9122
|
-
|
|
9123
|
-
|
|
9124
|
-
|
|
9125
|
-
}
|
|
9126
|
-
|
|
9127
|
-
|
|
9128
|
-
|
|
9129
|
-
|
|
9130
|
-
|
|
9131
|
-
|
|
9132
|
-
|
|
9460
|
+
try {
|
|
9461
|
+
appendSnapshot(USAGE_LOG2, await fetchCodexUsage());
|
|
9462
|
+
saved += 1;
|
|
9463
|
+
} catch (err) {
|
|
9464
|
+
if (!(err instanceof CodexApiError) || err.code !== "no_auth" && err.code !== "api_key_only") {
|
|
9465
|
+
console.warn(`codex usage: ${err.message}`);
|
|
9466
|
+
}
|
|
9467
|
+
}
|
|
9468
|
+
try {
|
|
9469
|
+
appendSnapshot(USAGE_LOG2, await fetchCopilotUsage());
|
|
9470
|
+
saved += 1;
|
|
9471
|
+
} catch (err) {
|
|
9472
|
+
if (!(err instanceof CopilotApiError) || err.code !== "no_cli" && err.code !== "no_auth") {
|
|
9473
|
+
console.warn(`copilot usage: ${err.message}`);
|
|
9474
|
+
}
|
|
9475
|
+
}
|
|
9476
|
+
try {
|
|
9477
|
+
appendSnapshot(USAGE_LOG2, await fetchGrokUsage());
|
|
9478
|
+
saved += 1;
|
|
9479
|
+
} catch (err) {
|
|
9480
|
+
if (!(err instanceof GrokApiError) || err.code !== "no_auth" && err.code !== "not_weekly") {
|
|
9481
|
+
console.warn(`grok usage: ${err.message}`);
|
|
9482
|
+
}
|
|
9483
|
+
}
|
|
9484
|
+
try {
|
|
9485
|
+
appendSnapshot(USAGE_LOG2, await fetchZaiUsage());
|
|
9486
|
+
saved += 1;
|
|
9487
|
+
} catch (err) {
|
|
9488
|
+
if (!(err instanceof ZaiApiError) || err.code !== "no_key") {
|
|
9489
|
+
console.warn(`zai usage: ${err.message}`);
|
|
9490
|
+
}
|
|
9491
|
+
}
|
|
9492
|
+
return saved;
|
|
9133
9493
|
}
|
|
9134
|
-
function
|
|
9135
|
-
const
|
|
9136
|
-
|
|
9137
|
-
|
|
9138
|
-
|
|
9494
|
+
function parseAgentFilter(args2) {
|
|
9495
|
+
const raw = flag(args2, "--agent") ?? flag(args2, "-a");
|
|
9496
|
+
if (!raw) return void 0;
|
|
9497
|
+
const kind = raw.toLowerCase();
|
|
9498
|
+
const aliases = {
|
|
9499
|
+
claude: "claude-code",
|
|
9500
|
+
"claude-code": "claude-code",
|
|
9501
|
+
codex: "codex",
|
|
9502
|
+
copilot: "copilot",
|
|
9503
|
+
zai: "zai",
|
|
9504
|
+
"z.ai": "zai",
|
|
9505
|
+
grok: "grok"
|
|
9506
|
+
};
|
|
9507
|
+
return aliases[kind] ?? kind;
|
|
9139
9508
|
}
|
|
9140
|
-
function
|
|
9141
|
-
|
|
9142
|
-
const
|
|
9143
|
-
return {
|
|
9509
|
+
function filterAgents(byAgent, agentFilter) {
|
|
9510
|
+
if (!agentFilter) return byAgent;
|
|
9511
|
+
const hit = byAgent[agentFilter];
|
|
9512
|
+
return hit ? { [agentFilter]: hit } : {};
|
|
9144
9513
|
}
|
|
9145
|
-
function
|
|
9146
|
-
|
|
9147
|
-
|
|
9148
|
-
|
|
9514
|
+
async function collectSnapshots(opts) {
|
|
9515
|
+
let saved = 0;
|
|
9516
|
+
if (opts.save) {
|
|
9517
|
+
try {
|
|
9518
|
+
const snapshot = await fetchUsage();
|
|
9519
|
+
appendSnapshot(USAGE_LOG2, snapshot);
|
|
9520
|
+
saved += 1;
|
|
9521
|
+
} catch (err) {
|
|
9522
|
+
if (!(err instanceof UsageApiError)) throw err;
|
|
9523
|
+
}
|
|
9524
|
+
saved += await saveAuxiliarySnapshots();
|
|
9525
|
+
}
|
|
9526
|
+
const byAgent = latestSnapshotsByAgent(USAGE_LOG2);
|
|
9527
|
+
if (opts.preferLiveClaude && !opts.save) {
|
|
9528
|
+
try {
|
|
9529
|
+
const live = await fetchUsage();
|
|
9530
|
+
byAgent["claude-code"] = live;
|
|
9531
|
+
} catch {
|
|
9532
|
+
}
|
|
9533
|
+
}
|
|
9534
|
+
return { byAgent, saved };
|
|
9149
9535
|
}
|
|
9150
|
-
function
|
|
9151
|
-
|
|
9152
|
-
|
|
9153
|
-
|
|
9154
|
-
|
|
9155
|
-
|
|
9156
|
-
|
|
9157
|
-
|
|
9158
|
-
|
|
9159
|
-
|
|
9160
|
-
|
|
9161
|
-
|
|
9162
|
-
|
|
9163
|
-
|
|
9536
|
+
async function usage(args2) {
|
|
9537
|
+
if (args2.includes("--help") || args2.includes("-h")) {
|
|
9538
|
+
console.log(`fleetlens usage \u2014 plan utilization (all agents)
|
|
9539
|
+
|
|
9540
|
+
Usage:
|
|
9541
|
+
fleetlens usage [--agent KIND] Multi-agent snapshot (from daemon log + live Claude)
|
|
9542
|
+
fleetlens usage --watch [-a KIND] Live top-style view until Ctrl+C
|
|
9543
|
+
fleetlens usage --save Poll every provider and append to the usage log
|
|
9544
|
+
fleetlens usage --history [-s D] [--days N]
|
|
9545
|
+
Daily token / cost history table
|
|
9546
|
+
|
|
9547
|
+
Agents: claude | codex | copilot | zai | grok (or full ids like claude-code)
|
|
9548
|
+
Watch options:
|
|
9549
|
+
--interval N Redraw every N seconds (default 2; reads ~/.cclens/usage.jsonl)
|
|
9550
|
+
|
|
9551
|
+
Tip: leave the usage daemon running (\`fleetlens daemon start\`) so --watch
|
|
9552
|
+
stays fresh without hammering provider APIs.`);
|
|
9553
|
+
return;
|
|
9554
|
+
}
|
|
9555
|
+
if (args2.includes("--history")) {
|
|
9556
|
+
const { history: history2 } = await Promise.resolve().then(() => (init_usage_history(), usage_history_exports));
|
|
9557
|
+
await history2(args2.filter((a) => a !== "--history"));
|
|
9558
|
+
return;
|
|
9559
|
+
}
|
|
9560
|
+
const save = args2.includes("--save");
|
|
9561
|
+
const watch = args2.includes("--watch") || args2.includes("-w");
|
|
9562
|
+
const agentFilter = parseAgentFilter(args2);
|
|
9563
|
+
if (agentFilter && !isAgentKind(agentFilter)) {
|
|
9564
|
+
console.error(
|
|
9565
|
+
`Error: unknown agent "${agentFilter}". Use claude, codex, copilot, zai, or grok.`
|
|
9566
|
+
);
|
|
9567
|
+
process.exitCode = 1;
|
|
9568
|
+
return;
|
|
9569
|
+
}
|
|
9570
|
+
const intervalRaw = flag(args2, "--interval");
|
|
9571
|
+
const intervalSec = Math.max(1, parseInt(intervalRaw ?? "2", 10) || 2);
|
|
9572
|
+
if (watch) {
|
|
9573
|
+
await runWatch({ agentFilter, intervalSec, saveOnce: save });
|
|
9574
|
+
return;
|
|
9575
|
+
}
|
|
9576
|
+
const collected = await collectSnapshots({ save, preferLiveClaude: true });
|
|
9577
|
+
const byAgent = filterAgents(collected.byAgent, agentFilter);
|
|
9578
|
+
if (save && collected.saved === 0 && Object.keys(byAgent).length === 0) {
|
|
9579
|
+
console.error(
|
|
9580
|
+
"Error: could not poll any provider and no samples are on disk."
|
|
9581
|
+
);
|
|
9582
|
+
process.exitCode = 1;
|
|
9583
|
+
return;
|
|
9164
9584
|
}
|
|
9165
|
-
|
|
9166
|
-
|
|
9167
|
-
|
|
9168
|
-
|
|
9169
|
-
|
|
9170
|
-
|
|
9171
|
-
|
|
9172
|
-
|
|
9173
|
-
|
|
9174
|
-
|
|
9175
|
-
|
|
9176
|
-
|
|
9177
|
-
|
|
9585
|
+
if (save && collected.saved === 0) {
|
|
9586
|
+
console.error(
|
|
9587
|
+
"Error: every usage poll failed (showing last samples from disk only)."
|
|
9588
|
+
);
|
|
9589
|
+
process.exitCode = 1;
|
|
9590
|
+
}
|
|
9591
|
+
if (Object.keys(byAgent).length === 0) {
|
|
9592
|
+
if (agentFilter) {
|
|
9593
|
+
console.error(
|
|
9594
|
+
`Error: no usage samples for ${agentFilter}. Run \`fleetlens usage --save\` or start the daemon.`
|
|
9595
|
+
);
|
|
9596
|
+
} else {
|
|
9597
|
+
console.error(
|
|
9598
|
+
"Error: no usage samples yet. Run `fleetlens daemon start` or `fleetlens usage --save`."
|
|
9599
|
+
);
|
|
9178
9600
|
}
|
|
9179
|
-
|
|
9180
|
-
|
|
9181
|
-
|
|
9182
|
-
|
|
9601
|
+
process.exitCode = 1;
|
|
9602
|
+
return;
|
|
9603
|
+
}
|
|
9604
|
+
const columns = typeof process.stdout.columns === "number" && process.stdout.columns > 0 ? process.stdout.columns : void 0;
|
|
9605
|
+
process.stdout.write(formatMultiAgentUsage(byAgent, { columns }));
|
|
9606
|
+
if (!save) {
|
|
9607
|
+
const narrow = columns !== void 0 && columns < 48 || columns === void 0 && parseInt(process.env.COLUMNS ?? "", 10) < 48;
|
|
9608
|
+
process.stdout.write(
|
|
9609
|
+
narrow ? " (tip: --watch \xB7 --history \xB7 --save)\n" : " (tip: --watch for a live view \xB7 --history for the token table \xB7 --save to poll APIs)\n"
|
|
9610
|
+
);
|
|
9183
9611
|
}
|
|
9184
|
-
return { by_day, peak, peak_day, multi_agent_days, cross_project_days };
|
|
9185
9612
|
}
|
|
9186
|
-
|
|
9187
|
-
|
|
9613
|
+
async function runWatch(opts) {
|
|
9614
|
+
if (opts.saveOnce) {
|
|
9615
|
+
const { saved } = await collectSnapshots({ save: true, preferLiveClaude: false });
|
|
9616
|
+
if (saved === 0 && Object.keys(latestSnapshotsByAgent(USAGE_LOG2)).length === 0) {
|
|
9617
|
+
console.error(
|
|
9618
|
+
"Error: could not poll any provider and no samples are on disk."
|
|
9619
|
+
);
|
|
9620
|
+
process.exitCode = 1;
|
|
9621
|
+
return;
|
|
9622
|
+
}
|
|
9623
|
+
}
|
|
9624
|
+
const tty = Boolean(process.stdout.isTTY);
|
|
9625
|
+
let stopping = false;
|
|
9626
|
+
const leaveScreen = () => {
|
|
9627
|
+
if (!tty) return;
|
|
9628
|
+
process.stdout.write("\x1B[?25h\x1B[?1049l");
|
|
9629
|
+
};
|
|
9630
|
+
if (tty) {
|
|
9631
|
+
process.stdout.write("\x1B[?1049h\x1B[?25l");
|
|
9632
|
+
}
|
|
9633
|
+
const draw = () => {
|
|
9634
|
+
if (stopping) return;
|
|
9635
|
+
const byAgent = filterAgents(latestSnapshotsByAgent(USAGE_LOG2), opts.agentFilter);
|
|
9636
|
+
const columns = typeof process.stdout.columns === "number" && process.stdout.columns > 0 ? process.stdout.columns : void 0;
|
|
9637
|
+
if (tty) {
|
|
9638
|
+
process.stdout.write("\x1B[H\x1B[2J");
|
|
9639
|
+
} else {
|
|
9640
|
+
process.stdout.write("\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n");
|
|
9641
|
+
}
|
|
9642
|
+
if (Object.keys(byAgent).length === 0) {
|
|
9643
|
+
process.stdout.write(
|
|
9644
|
+
`
|
|
9645
|
+
${opts.agentFilter ? `No samples for ${opts.agentFilter}` : "Waiting for usage samples\u2026"}
|
|
9646
|
+
Start the daemon: fleetlens daemon start
|
|
9647
|
+
|
|
9648
|
+
live \xB7 every ${opts.intervalSec}s \xB7 Ctrl+C to quit
|
|
9649
|
+
`
|
|
9650
|
+
);
|
|
9651
|
+
return;
|
|
9652
|
+
}
|
|
9653
|
+
process.stdout.write(
|
|
9654
|
+
formatMultiAgentUsage(byAgent, {
|
|
9655
|
+
watch: true,
|
|
9656
|
+
intervalSec: opts.intervalSec,
|
|
9657
|
+
columns
|
|
9658
|
+
})
|
|
9659
|
+
);
|
|
9660
|
+
};
|
|
9661
|
+
if (tty) {
|
|
9662
|
+
process.stdout.on("resize", draw);
|
|
9663
|
+
}
|
|
9664
|
+
draw();
|
|
9665
|
+
const timer = setInterval(draw, opts.intervalSec * 1e3);
|
|
9666
|
+
const stop2 = () => {
|
|
9667
|
+
if (stopping) return;
|
|
9668
|
+
stopping = true;
|
|
9669
|
+
clearInterval(timer);
|
|
9670
|
+
leaveScreen();
|
|
9671
|
+
process.stdout.write("\n");
|
|
9672
|
+
process.exit(0);
|
|
9673
|
+
};
|
|
9674
|
+
process.on("SIGINT", stop2);
|
|
9675
|
+
process.on("SIGTERM", stop2);
|
|
9676
|
+
await new Promise(() => {
|
|
9677
|
+
});
|
|
9678
|
+
}
|
|
9679
|
+
var USAGE_LOG2;
|
|
9680
|
+
var init_usage = __esm({
|
|
9681
|
+
"src/commands/usage.ts"() {
|
|
9188
9682
|
"use strict";
|
|
9189
|
-
|
|
9683
|
+
init_dist();
|
|
9684
|
+
init_fs();
|
|
9685
|
+
init_args();
|
|
9686
|
+
init_api();
|
|
9687
|
+
init_grok2();
|
|
9688
|
+
init_codex2();
|
|
9689
|
+
init_copilot2();
|
|
9690
|
+
init_zai();
|
|
9691
|
+
init_format();
|
|
9692
|
+
init_storage();
|
|
9693
|
+
USAGE_LOG2 = cclensPath("usage.jsonl");
|
|
9190
9694
|
}
|
|
9191
9695
|
});
|
|
9192
9696
|
|
|
9193
|
-
// ../
|
|
9194
|
-
|
|
9195
|
-
|
|
9196
|
-
|
|
9197
|
-
|
|
9198
|
-
|
|
9199
|
-
|
|
9200
|
-
|
|
9201
|
-
|
|
9202
|
-
|
|
9203
|
-
|
|
9204
|
-
|
|
9205
|
-
|
|
9206
|
-
|
|
9207
|
-
|
|
9208
|
-
|
|
9209
|
-
|
|
9210
|
-
|
|
9211
|
-
|
|
9212
|
-
|
|
9213
|
-
|
|
9214
|
-
|
|
9215
|
-
|
|
9216
|
-
|
|
9217
|
-
|
|
9218
|
-
|
|
9219
|
-
|
|
9220
|
-
|
|
9221
|
-
|
|
9222
|
-
|
|
9223
|
-
|
|
9224
|
-
|
|
9225
|
-
|
|
9226
|
-
|
|
9227
|
-
|
|
9228
|
-
|
|
9229
|
-
|
|
9230
|
-
|
|
9231
|
-
|
|
9232
|
-
|
|
9233
|
-
|
|
9234
|
-
|
|
9235
|
-
|
|
9236
|
-
|
|
9237
|
-
|
|
9238
|
-
|
|
9239
|
-
|
|
9240
|
-
priorCalendarMonth: () => priorCalendarMonth,
|
|
9241
|
-
priorCalendarWeek: () => priorCalendarWeek,
|
|
9242
|
-
projectKey: () => projectKey,
|
|
9243
|
-
projectRepoName: () => projectRepoName,
|
|
9244
|
-
rowPrimaryIndex: () => rowPrimaryIndex,
|
|
9245
|
-
sessionAirTimeMs: () => sessionAirTimeMs,
|
|
9246
|
-
sessionDay: () => sessionDay,
|
|
9247
|
-
sessionProjectKey: () => sessionProjectKey,
|
|
9248
|
-
stripFrameworkBoilerplate: () => stripFrameworkBoilerplate,
|
|
9249
|
-
summarizeBursts: () => summarizeBursts,
|
|
9250
|
-
toLocalDay: () => toLocalDay,
|
|
9251
|
-
userSoloRate: () => userSoloRate,
|
|
9252
|
-
worktreeName: () => worktreeName
|
|
9253
|
-
});
|
|
9254
|
-
var init_dist = __esm({
|
|
9255
|
-
"../parser/dist/index.js"() {
|
|
9697
|
+
// ../entries/dist/types.js
|
|
9698
|
+
function pendingEnrichment() {
|
|
9699
|
+
return {
|
|
9700
|
+
status: "pending",
|
|
9701
|
+
generated_at: null,
|
|
9702
|
+
model: null,
|
|
9703
|
+
cost_usd: null,
|
|
9704
|
+
error: null,
|
|
9705
|
+
brief_summary: null,
|
|
9706
|
+
underlying_goal: null,
|
|
9707
|
+
friction_detail: null,
|
|
9708
|
+
user_instructions: [],
|
|
9709
|
+
outcome: null,
|
|
9710
|
+
claude_helpfulness: null,
|
|
9711
|
+
goal_categories: {},
|
|
9712
|
+
retry_count: 0
|
|
9713
|
+
};
|
|
9714
|
+
}
|
|
9715
|
+
function skippedTrivialEnrichment(generatedAt) {
|
|
9716
|
+
return {
|
|
9717
|
+
status: "skipped_trivial",
|
|
9718
|
+
generated_at: generatedAt,
|
|
9719
|
+
model: null,
|
|
9720
|
+
cost_usd: null,
|
|
9721
|
+
error: null,
|
|
9722
|
+
brief_summary: null,
|
|
9723
|
+
underlying_goal: null,
|
|
9724
|
+
friction_detail: null,
|
|
9725
|
+
user_instructions: [],
|
|
9726
|
+
outcome: "trivial",
|
|
9727
|
+
claude_helpfulness: null,
|
|
9728
|
+
goal_categories: {},
|
|
9729
|
+
retry_count: 0
|
|
9730
|
+
};
|
|
9731
|
+
}
|
|
9732
|
+
function entryKey(sessionId, localDay2) {
|
|
9733
|
+
return `${sessionId}__${localDay2}`;
|
|
9734
|
+
}
|
|
9735
|
+
function parseEntryKey(key) {
|
|
9736
|
+
const m = /^([^_]+(?:_[^_]+)*)__(\d{4}-\d{2}-\d{2})$/.exec(key);
|
|
9737
|
+
if (!m)
|
|
9738
|
+
return null;
|
|
9739
|
+
return { session_id: m[1], local_day: m[2] };
|
|
9740
|
+
}
|
|
9741
|
+
var CURRENT_ENTRY_SCHEMA_VERSION, GOAL_CATEGORIES, CURRENT_DAY_DIGEST_SCHEMA_VERSION, CURRENT_WEEK_DIGEST_SCHEMA_VERSION, CURRENT_MONTH_DIGEST_SCHEMA_VERSION, PROMPT_FRAME_ORIGIN;
|
|
9742
|
+
var init_types2 = __esm({
|
|
9743
|
+
"../entries/dist/types.js"() {
|
|
9256
9744
|
"use strict";
|
|
9257
|
-
|
|
9258
|
-
|
|
9259
|
-
|
|
9260
|
-
|
|
9261
|
-
|
|
9262
|
-
|
|
9263
|
-
|
|
9264
|
-
|
|
9265
|
-
|
|
9745
|
+
CURRENT_ENTRY_SCHEMA_VERSION = 2;
|
|
9746
|
+
GOAL_CATEGORIES = [
|
|
9747
|
+
"build",
|
|
9748
|
+
"plan",
|
|
9749
|
+
"debug",
|
|
9750
|
+
"review",
|
|
9751
|
+
"steer",
|
|
9752
|
+
"meta",
|
|
9753
|
+
"research",
|
|
9754
|
+
"refactor",
|
|
9755
|
+
"test",
|
|
9756
|
+
"release",
|
|
9757
|
+
"warmup_minimal"
|
|
9758
|
+
];
|
|
9759
|
+
CURRENT_DAY_DIGEST_SCHEMA_VERSION = 2;
|
|
9760
|
+
CURRENT_WEEK_DIGEST_SCHEMA_VERSION = 2;
|
|
9761
|
+
CURRENT_MONTH_DIGEST_SCHEMA_VERSION = 2;
|
|
9762
|
+
PROMPT_FRAME_ORIGIN = {
|
|
9763
|
+
teammate: "claude-feature",
|
|
9764
|
+
"task-notification": "claude-feature",
|
|
9765
|
+
"local-command-caveat": "claude-feature",
|
|
9766
|
+
"image-attached": "claude-feature",
|
|
9767
|
+
"slash-command": "claude-feature",
|
|
9768
|
+
"handoff-prose": "personal-habit"
|
|
9769
|
+
};
|
|
9266
9770
|
}
|
|
9267
9771
|
});
|
|
9268
9772
|
|
|
@@ -10004,7 +10508,7 @@ var init_build = __esm({
|
|
|
10004
10508
|
"../entries/dist/build.js"() {
|
|
10005
10509
|
"use strict";
|
|
10006
10510
|
init_analytics();
|
|
10007
|
-
|
|
10511
|
+
init_types2();
|
|
10008
10512
|
init_signals();
|
|
10009
10513
|
init_trivial();
|
|
10010
10514
|
IDLE_GAP_MS6 = 3 * 60 * 1e3;
|
|
@@ -10027,7 +10531,7 @@ var init_flag_glossary = __esm({
|
|
|
10027
10531
|
var init_dist2 = __esm({
|
|
10028
10532
|
"../entries/dist/index.js"() {
|
|
10029
10533
|
"use strict";
|
|
10030
|
-
|
|
10534
|
+
init_types2();
|
|
10031
10535
|
init_signals();
|
|
10032
10536
|
init_trivial();
|
|
10033
10537
|
init_build();
|
|
@@ -10036,11 +10540,11 @@ var init_dist2 = __esm({
|
|
|
10036
10540
|
});
|
|
10037
10541
|
|
|
10038
10542
|
// ../entries/dist/digest-fs.js
|
|
10039
|
-
import { readFileSync as
|
|
10543
|
+
import { readFileSync as readFileSync14, readdirSync, writeFileSync as writeFileSync7, renameSync as renameSync2, chmodSync, mkdirSync as mkdirSync6, existsSync as existsSync12 } from "node:fs";
|
|
10040
10544
|
import { dirname as dirname9, join as join9 } from "node:path";
|
|
10041
10545
|
function parseDigestFile(path11, expectedVersion) {
|
|
10042
10546
|
try {
|
|
10043
|
-
const parsed = JSON.parse(
|
|
10547
|
+
const parsed = JSON.parse(readFileSync14(path11, "utf8"));
|
|
10044
10548
|
if (!parsed || typeof parsed !== "object")
|
|
10045
10549
|
return null;
|
|
10046
10550
|
if (parsed.version !== expectedVersion)
|
|
@@ -10089,7 +10593,7 @@ function writeDayDigest(digest2) {
|
|
|
10089
10593
|
}
|
|
10090
10594
|
function readDayDigest(date) {
|
|
10091
10595
|
const p = dayDigestPath(date);
|
|
10092
|
-
if (!
|
|
10596
|
+
if (!existsSync12(p))
|
|
10093
10597
|
return null;
|
|
10094
10598
|
return parseDigestFile(p, CURRENT_DAY_DIGEST_SCHEMA_VERSION);
|
|
10095
10599
|
}
|
|
@@ -10125,13 +10629,13 @@ function writeWeekDigest(digest2) {
|
|
|
10125
10629
|
}
|
|
10126
10630
|
function readWeekDigest(monday) {
|
|
10127
10631
|
const p = weekDigestPath(monday);
|
|
10128
|
-
if (!
|
|
10632
|
+
if (!existsSync12(p))
|
|
10129
10633
|
return null;
|
|
10130
10634
|
return parseDigestFile(p, CURRENT_WEEK_DIGEST_SCHEMA_VERSION);
|
|
10131
10635
|
}
|
|
10132
10636
|
function listWeekDigestKeys() {
|
|
10133
10637
|
const dir = join9(digestsDir(), "week");
|
|
10134
|
-
if (!
|
|
10638
|
+
if (!existsSync12(dir))
|
|
10135
10639
|
return [];
|
|
10136
10640
|
return readdirSync(dir).filter((f) => f.endsWith(".json")).map((f) => f.slice(0, -".json".length)).filter((k) => /^\d{4}-\d{2}-\d{2}$/.test(k));
|
|
10137
10641
|
}
|
|
@@ -10162,13 +10666,13 @@ function writeMonthDigest(digest2) {
|
|
|
10162
10666
|
}
|
|
10163
10667
|
function readMonthDigest(yearMonth) {
|
|
10164
10668
|
const p = monthDigestPath(yearMonth);
|
|
10165
|
-
if (!
|
|
10669
|
+
if (!existsSync12(p))
|
|
10166
10670
|
return null;
|
|
10167
10671
|
return parseDigestFile(p, CURRENT_MONTH_DIGEST_SCHEMA_VERSION);
|
|
10168
10672
|
}
|
|
10169
10673
|
function listMonthDigestKeys() {
|
|
10170
10674
|
const dir = join9(digestsDir(), "month");
|
|
10171
|
-
if (!
|
|
10675
|
+
if (!existsSync12(dir))
|
|
10172
10676
|
return [];
|
|
10173
10677
|
return readdirSync(dir).filter((f) => f.endsWith(".json")).map((f) => f.slice(0, -".json".length)).filter((k) => /^\d{4}-\d{2}$/.test(k));
|
|
10174
10678
|
}
|
|
@@ -10189,7 +10693,7 @@ var init_digest_fs = __esm({
|
|
|
10189
10693
|
"../entries/dist/digest-fs.js"() {
|
|
10190
10694
|
"use strict";
|
|
10191
10695
|
init_fs();
|
|
10192
|
-
|
|
10696
|
+
init_types2();
|
|
10193
10697
|
digestsDirCached = null;
|
|
10194
10698
|
TODAY_TTL_MS = 10 * 60 * 1e3;
|
|
10195
10699
|
todayCache = null;
|
|
@@ -10230,7 +10734,7 @@ __export(fs_exports2, {
|
|
|
10230
10734
|
writeMonthDigest: () => writeMonthDigest,
|
|
10231
10735
|
writeWeekDigest: () => writeWeekDigest
|
|
10232
10736
|
});
|
|
10233
|
-
import { readFileSync as
|
|
10737
|
+
import { readFileSync as readFileSync15, readdirSync as readdirSync2, writeFileSync as writeFileSync8, mkdirSync as mkdirSync7, renameSync as renameSync3, existsSync as existsSync13 } from "node:fs";
|
|
10234
10738
|
import { randomBytes } from "node:crypto";
|
|
10235
10739
|
import { join as join10 } from "node:path";
|
|
10236
10740
|
function entriesDir() {
|
|
@@ -10289,17 +10793,17 @@ function writeEntryPreservingEnrichment(fresh) {
|
|
|
10289
10793
|
}
|
|
10290
10794
|
function readEntry(sessionId, localDay2) {
|
|
10291
10795
|
const p = pathFor(sessionId, localDay2);
|
|
10292
|
-
if (!
|
|
10796
|
+
if (!existsSync13(p))
|
|
10293
10797
|
return null;
|
|
10294
|
-
const raw =
|
|
10798
|
+
const raw = readFileSync15(p, "utf8");
|
|
10295
10799
|
return JSON.parse(raw);
|
|
10296
10800
|
}
|
|
10297
10801
|
function entryExists(sessionId, localDay2) {
|
|
10298
|
-
return
|
|
10802
|
+
return existsSync13(pathFor(sessionId, localDay2));
|
|
10299
10803
|
}
|
|
10300
10804
|
function listEntryKeys() {
|
|
10301
10805
|
const dir = entriesDir();
|
|
10302
|
-
if (!
|
|
10806
|
+
if (!existsSync13(dir))
|
|
10303
10807
|
return [];
|
|
10304
10808
|
return readdirSync2(dir).filter((f) => f.endsWith(".json")).map((f) => f.slice(0, -".json".length));
|
|
10305
10809
|
}
|
|
@@ -10348,7 +10852,7 @@ var init_fs2 = __esm({
|
|
|
10348
10852
|
"../entries/dist/fs.js"() {
|
|
10349
10853
|
"use strict";
|
|
10350
10854
|
init_fs();
|
|
10351
|
-
|
|
10855
|
+
init_types2();
|
|
10352
10856
|
init_digest_fs();
|
|
10353
10857
|
entriesDirCached = null;
|
|
10354
10858
|
PRESERVABLE_STATUSES = /* @__PURE__ */ new Set([
|
|
@@ -10358,17 +10862,6 @@ var init_fs2 = __esm({
|
|
|
10358
10862
|
}
|
|
10359
10863
|
});
|
|
10360
10864
|
|
|
10361
|
-
// src/args.ts
|
|
10362
|
-
function flag(args2, name) {
|
|
10363
|
-
const idx = args2.indexOf(name);
|
|
10364
|
-
return idx === -1 ? void 0 : args2[idx + 1];
|
|
10365
|
-
}
|
|
10366
|
-
var init_args = __esm({
|
|
10367
|
-
"src/args.ts"() {
|
|
10368
|
-
"use strict";
|
|
10369
|
-
}
|
|
10370
|
-
});
|
|
10371
|
-
|
|
10372
10865
|
// ../../node_modules/zod/v3/helpers/util.js
|
|
10373
10866
|
var util, objectUtil, ZodParsedType, getParsedType;
|
|
10374
10867
|
var init_util = __esm({
|
|
@@ -14514,7 +15007,7 @@ var init_enrich = __esm({
|
|
|
14514
15007
|
"../entries/dist/prompts/enrich.js"() {
|
|
14515
15008
|
"use strict";
|
|
14516
15009
|
init_zod();
|
|
14517
|
-
|
|
15010
|
+
init_types2();
|
|
14518
15011
|
GoalCategoryEnum = external_exports.enum(GOAL_CATEGORIES);
|
|
14519
15012
|
OutcomeEnum = external_exports.enum(["shipped", "partial", "exploratory", "blocked", "trivial"]);
|
|
14520
15013
|
HelpfulnessEnum = external_exports.enum(["essential", "helpful", "neutral", "unhelpful"]);
|
|
@@ -14578,14 +15071,14 @@ RESPOND WITH ONLY VALID JSON (no prose, no code fence):
|
|
|
14578
15071
|
});
|
|
14579
15072
|
|
|
14580
15073
|
// ../entries/dist/claude-bin.js
|
|
14581
|
-
import { existsSync as
|
|
15074
|
+
import { existsSync as existsSync14 } from "node:fs";
|
|
14582
15075
|
import { join as join11, dirname as dirname10, delimiter } from "node:path";
|
|
14583
15076
|
import { homedir as homedir5 } from "node:os";
|
|
14584
15077
|
function resolveClaudeBin(opts = {}) {
|
|
14585
15078
|
const env = opts.env ?? process.env;
|
|
14586
15079
|
const home = opts.home ?? homedir5();
|
|
14587
15080
|
const execPath = opts.execPath ?? process.execPath;
|
|
14588
|
-
const exists = opts.exists ??
|
|
15081
|
+
const exists = opts.exists ?? existsSync14;
|
|
14589
15082
|
for (const dir of (env.PATH ?? "").split(delimiter)) {
|
|
14590
15083
|
if (!dir)
|
|
14591
15084
|
continue;
|
|
@@ -14626,7 +15119,7 @@ var init_claude_bin = __esm({
|
|
|
14626
15119
|
});
|
|
14627
15120
|
|
|
14628
15121
|
// ../entries/dist/tmux-runner.js
|
|
14629
|
-
import { mkdirSync as mkdirSync8, writeFileSync as writeFileSync9, existsSync as
|
|
15122
|
+
import { mkdirSync as mkdirSync8, writeFileSync as writeFileSync9, existsSync as existsSync15, readdirSync as readdirSync3, realpathSync as realpathSync5, readFileSync as readFileSync16, unlinkSync as unlinkSync3, renameSync as renameSync4 } from "node:fs";
|
|
14630
15123
|
import { join as join12 } from "node:path";
|
|
14631
15124
|
import { homedir as homedir6 } from "node:os";
|
|
14632
15125
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
@@ -14645,7 +15138,7 @@ function tmuxRunnerAvailable() {
|
|
|
14645
15138
|
}
|
|
14646
15139
|
function runtimeCwd() {
|
|
14647
15140
|
const dir = join12(homedir6(), ".cclens", "runtime");
|
|
14648
|
-
if (!
|
|
15141
|
+
if (!existsSync15(dir))
|
|
14649
15142
|
mkdirSync8(dir, { recursive: true });
|
|
14650
15143
|
return realpathSync5(dir);
|
|
14651
15144
|
}
|
|
@@ -14653,7 +15146,7 @@ function ensureRuntimeCwdTrusted(cwd) {
|
|
|
14653
15146
|
const cfgPath = join12(homedir6(), ".claude.json");
|
|
14654
15147
|
let cfg;
|
|
14655
15148
|
try {
|
|
14656
|
-
cfg = JSON.parse(
|
|
15149
|
+
cfg = JSON.parse(readFileSync16(cfgPath, "utf8"));
|
|
14657
15150
|
} catch {
|
|
14658
15151
|
return;
|
|
14659
15152
|
}
|
|
@@ -14803,7 +15296,7 @@ function snapshotAllTranscripts() {
|
|
|
14803
15296
|
function readJsonlCwd(path11, maxLines = 8) {
|
|
14804
15297
|
let raw;
|
|
14805
15298
|
try {
|
|
14806
|
-
raw =
|
|
15299
|
+
raw = readFileSync16(path11, "utf8");
|
|
14807
15300
|
} catch {
|
|
14808
15301
|
return void 0;
|
|
14809
15302
|
}
|
|
@@ -14860,7 +15353,7 @@ async function discoverTranscript(targetCwd, existingBefore, startMs, timeoutMs,
|
|
|
14860
15353
|
function parseTranscript2(path11, defaultModel) {
|
|
14861
15354
|
let raw;
|
|
14862
15355
|
try {
|
|
14863
|
-
raw =
|
|
15356
|
+
raw = readFileSync16(path11, "utf8");
|
|
14864
15357
|
} catch {
|
|
14865
15358
|
return { assembled: "", inputTokens: 0, outputTokens: 0, modelUsed: defaultModel, done: false };
|
|
14866
15359
|
}
|
|
@@ -14955,11 +15448,11 @@ var init_tmux_runner = __esm({
|
|
|
14955
15448
|
|
|
14956
15449
|
// ../entries/dist/llm-runner.js
|
|
14957
15450
|
import { spawn as spawn4 } from "node:child_process";
|
|
14958
|
-
import { mkdirSync as mkdirSync9, appendFileSync as appendFileSync3, writeFileSync as writeFileSync10, existsSync as
|
|
15451
|
+
import { mkdirSync as mkdirSync9, appendFileSync as appendFileSync3, writeFileSync as writeFileSync10, existsSync as existsSync16 } from "node:fs";
|
|
14959
15452
|
import { join as join13 } from "node:path";
|
|
14960
15453
|
import { randomUUID } from "node:crypto";
|
|
14961
15454
|
function ensureRunsDir() {
|
|
14962
|
-
if (!
|
|
15455
|
+
if (!existsSync16(RUNS_DIR)) {
|
|
14963
15456
|
try {
|
|
14964
15457
|
mkdirSync9(RUNS_DIR, { recursive: true });
|
|
14965
15458
|
} catch {
|
|
@@ -15412,7 +15905,7 @@ var init_enrich2 = __esm({
|
|
|
15412
15905
|
});
|
|
15413
15906
|
|
|
15414
15907
|
// ../entries/dist/budget.js
|
|
15415
|
-
import { appendFileSync as appendFileSync4, readFileSync as
|
|
15908
|
+
import { appendFileSync as appendFileSync4, readFileSync as readFileSync17, existsSync as existsSync17, mkdirSync as mkdirSync10 } from "node:fs";
|
|
15416
15909
|
import { dirname as dirname11 } from "node:path";
|
|
15417
15910
|
function spendPath() {
|
|
15418
15911
|
if (spendPathCached)
|
|
@@ -15430,12 +15923,12 @@ function appendSpend(record) {
|
|
|
15430
15923
|
}
|
|
15431
15924
|
function monthToDateSpend(now = /* @__PURE__ */ new Date()) {
|
|
15432
15925
|
const p = spendPath();
|
|
15433
|
-
if (!
|
|
15926
|
+
if (!existsSync17(p))
|
|
15434
15927
|
return 0;
|
|
15435
15928
|
const year = now.getUTCFullYear();
|
|
15436
15929
|
const month2 = now.getUTCMonth();
|
|
15437
15930
|
let total = 0;
|
|
15438
|
-
const raw =
|
|
15931
|
+
const raw = readFileSync17(p, "utf8");
|
|
15439
15932
|
for (const line of raw.split("\n")) {
|
|
15440
15933
|
if (!line)
|
|
15441
15934
|
continue;
|
|
@@ -15464,7 +15957,7 @@ var init_budget = __esm({
|
|
|
15464
15957
|
});
|
|
15465
15958
|
|
|
15466
15959
|
// ../entries/dist/pipeline-lock.js
|
|
15467
|
-
import { writeFileSync as writeFileSync11, unlinkSync as unlinkSync4, existsSync as
|
|
15960
|
+
import { writeFileSync as writeFileSync11, unlinkSync as unlinkSync4, existsSync as existsSync18, readFileSync as readFileSync18, statSync as statSync3 } from "node:fs";
|
|
15468
15961
|
function lockPath() {
|
|
15469
15962
|
if (lockPathCached)
|
|
15470
15963
|
return lockPathCached;
|
|
@@ -15509,13 +16002,13 @@ function pidAlive(pid) {
|
|
|
15509
16002
|
}
|
|
15510
16003
|
function interactiveLockFresh(nowMs) {
|
|
15511
16004
|
const p = lockPath();
|
|
15512
|
-
if (!
|
|
16005
|
+
if (!existsSync18(p))
|
|
15513
16006
|
return false;
|
|
15514
16007
|
try {
|
|
15515
16008
|
const mtime = statSync3(p).mtimeMs;
|
|
15516
16009
|
if (nowMs - mtime > STALE_MS)
|
|
15517
16010
|
return false;
|
|
15518
|
-
const pid = Number(
|
|
16011
|
+
const pid = Number(readFileSync18(p, "utf8").trim());
|
|
15519
16012
|
if (!Number.isFinite(pid) || pid <= 0)
|
|
15520
16013
|
return false;
|
|
15521
16014
|
if (!pidAlive(pid))
|
|
@@ -15621,7 +16114,7 @@ var init_queue = __esm({
|
|
|
15621
16114
|
});
|
|
15622
16115
|
|
|
15623
16116
|
// ../entries/dist/settings.js
|
|
15624
|
-
import { readFileSync as
|
|
16117
|
+
import { readFileSync as readFileSync19, writeFileSync as writeFileSync12, renameSync as renameSync5, chmodSync as chmodSync2, mkdirSync as mkdirSync11, existsSync as existsSync19 } from "node:fs";
|
|
15625
16118
|
import { dirname as dirname12 } from "node:path";
|
|
15626
16119
|
function settingsPath() {
|
|
15627
16120
|
if (settingsPathCached)
|
|
@@ -15657,10 +16150,10 @@ function fromDisk(d) {
|
|
|
15657
16150
|
}
|
|
15658
16151
|
function readSettings() {
|
|
15659
16152
|
const p = settingsPath();
|
|
15660
|
-
if (!
|
|
16153
|
+
if (!existsSync19(p))
|
|
15661
16154
|
return DEFAULT_SETTINGS;
|
|
15662
16155
|
try {
|
|
15663
|
-
const raw =
|
|
16156
|
+
const raw = readFileSync19(p, "utf8");
|
|
15664
16157
|
return fromDisk(JSON.parse(raw));
|
|
15665
16158
|
} catch {
|
|
15666
16159
|
return DEFAULT_SETTINGS;
|
|
@@ -16145,7 +16638,7 @@ var DEFAULT_MODEL2, defaultCallLLMDigest, validateDay;
|
|
|
16145
16638
|
var init_digest_day2 = __esm({
|
|
16146
16639
|
"../entries/dist/digest-day.js"() {
|
|
16147
16640
|
"use strict";
|
|
16148
|
-
|
|
16641
|
+
init_types2();
|
|
16149
16642
|
init_signals();
|
|
16150
16643
|
init_digest_day();
|
|
16151
16644
|
init_enrich2();
|
|
@@ -17364,7 +17857,7 @@ var SHAPE_ORDER, DEFAULT_MODEL3, defaultCallLLMWeek, validateWeek;
|
|
|
17364
17857
|
var init_digest_week2 = __esm({
|
|
17365
17858
|
"../entries/dist/digest-week.js"() {
|
|
17366
17859
|
"use strict";
|
|
17367
|
-
|
|
17860
|
+
init_types2();
|
|
17368
17861
|
init_signals();
|
|
17369
17862
|
init_digest_day2();
|
|
17370
17863
|
init_digest_week();
|
|
@@ -17698,7 +18191,7 @@ var DEFAULT_MODEL4, defaultCallLLMMonth, validateMonth;
|
|
|
17698
18191
|
var init_digest_month2 = __esm({
|
|
17699
18192
|
"../entries/dist/digest-month.js"() {
|
|
17700
18193
|
"use strict";
|
|
17701
|
-
|
|
18194
|
+
init_types2();
|
|
17702
18195
|
init_digest_month();
|
|
17703
18196
|
init_enrich2();
|
|
17704
18197
|
init_llm_runner();
|
|
@@ -18850,13 +19343,13 @@ var init_digest_month_pipeline = __esm({
|
|
|
18850
19343
|
});
|
|
18851
19344
|
|
|
18852
19345
|
// ../entries/dist/credentials.js
|
|
18853
|
-
import { writeFileSync as writeFileSync13, readFileSync as
|
|
19346
|
+
import { writeFileSync as writeFileSync13, readFileSync as readFileSync20, renameSync as renameSync6, chmodSync as chmodSync3, mkdirSync as mkdirSync12, existsSync as existsSync20, unlinkSync as unlinkSync5 } from "node:fs";
|
|
18854
19347
|
import { dirname as dirname13 } from "node:path";
|
|
18855
|
-
async function
|
|
19348
|
+
async function fetchZaiUsage2(candidate) {
|
|
18856
19349
|
const key = candidate.trim();
|
|
18857
19350
|
if (!key)
|
|
18858
19351
|
throw new Error("empty key");
|
|
18859
|
-
const res = await fetch(
|
|
19352
|
+
const res = await fetch(ZAI_QUOTA_ENDPOINT2, {
|
|
18860
19353
|
headers: { Authorization: key, "Accept-Language": "en-US,en" }
|
|
18861
19354
|
});
|
|
18862
19355
|
if (!res.ok) {
|
|
@@ -18908,7 +19401,7 @@ async function fetchZaiUsage(candidate) {
|
|
|
18908
19401
|
};
|
|
18909
19402
|
}
|
|
18910
19403
|
async function validateAndSnapshotZaiKey(key) {
|
|
18911
|
-
const snap = await
|
|
19404
|
+
const snap = await fetchZaiUsage2(key);
|
|
18912
19405
|
appendUsageSnapshot(snap);
|
|
18913
19406
|
return snap;
|
|
18914
19407
|
}
|
|
@@ -18921,10 +19414,10 @@ function credentialsPath() {
|
|
|
18921
19414
|
}
|
|
18922
19415
|
function readCredentials() {
|
|
18923
19416
|
const p = credentialsPath();
|
|
18924
|
-
if (!
|
|
19417
|
+
if (!existsSync20(p))
|
|
18925
19418
|
return {};
|
|
18926
19419
|
try {
|
|
18927
|
-
const raw =
|
|
19420
|
+
const raw = readFileSync20(p, "utf8");
|
|
18928
19421
|
return JSON.parse(raw);
|
|
18929
19422
|
} catch {
|
|
18930
19423
|
return {};
|
|
@@ -18976,12 +19469,12 @@ function deleteZaiKey() {
|
|
|
18976
19469
|
function hasZaiKey() {
|
|
18977
19470
|
return !!readCredentials().zai?.apiKey;
|
|
18978
19471
|
}
|
|
18979
|
-
var
|
|
19472
|
+
var ZAI_QUOTA_ENDPOINT2;
|
|
18980
19473
|
var init_credentials = __esm({
|
|
18981
19474
|
"../entries/dist/credentials.js"() {
|
|
18982
19475
|
"use strict";
|
|
18983
19476
|
init_fs();
|
|
18984
|
-
|
|
19477
|
+
ZAI_QUOTA_ENDPOINT2 = "https://api.z.ai/api/monitor/usage/quota/limit";
|
|
18985
19478
|
}
|
|
18986
19479
|
});
|
|
18987
19480
|
|
|
@@ -19020,7 +19513,7 @@ __export(node_exports, {
|
|
|
19020
19513
|
deleteZaiKey: () => deleteZaiKey,
|
|
19021
19514
|
deleteZaiKeyAndPrune: () => deleteZaiKeyAndPrune,
|
|
19022
19515
|
enrichEntry: () => enrichEntry,
|
|
19023
|
-
fetchZaiUsage: () =>
|
|
19516
|
+
fetchZaiUsage: () => fetchZaiUsage2,
|
|
19024
19517
|
generateDayDigest: () => generateDayDigest,
|
|
19025
19518
|
generateMonthDigest: () => generateMonthDigest,
|
|
19026
19519
|
generateWeekDigest: () => generateWeekDigest,
|
|
@@ -19558,7 +20051,7 @@ var menubar_exports = {};
|
|
|
19558
20051
|
__export(menubar_exports, {
|
|
19559
20052
|
menubar: () => menubar
|
|
19560
20053
|
});
|
|
19561
|
-
import { existsSync as
|
|
20054
|
+
import { existsSync as existsSync21, mkdirSync as mkdirSync13, cpSync, rmSync as rmSync2, readdirSync as readdirSync4, writeFileSync as writeFileSync14, realpathSync as realpathSync6 } from "node:fs";
|
|
19562
20055
|
import { homedir as homedir7 } from "node:os";
|
|
19563
20056
|
import { join as join14, dirname as dirname14 } from "node:path";
|
|
19564
20057
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
@@ -19632,7 +20125,7 @@ async function installMenubar(opts) {
|
|
|
19632
20125
|
return;
|
|
19633
20126
|
}
|
|
19634
20127
|
const src = bundledAppPath();
|
|
19635
|
-
if (!
|
|
20128
|
+
if (!existsSync21(src)) {
|
|
19636
20129
|
console.error(
|
|
19637
20130
|
`Bundled widget not found at ${src}.
|
|
19638
20131
|
This install was probably built without the menubar artifact. Run \`bash apps/menubar/build-app.sh && cp -R apps/menubar/dist/Fleetlens.app packages/cli/menubar/\` and rebuild.`
|
|
@@ -19678,7 +20171,7 @@ async function uninstallMenubar() {
|
|
|
19678
20171
|
await new Promise((r) => setTimeout(r, 300));
|
|
19679
20172
|
}
|
|
19680
20173
|
const dest = installedAppPath();
|
|
19681
|
-
if (
|
|
20174
|
+
if (existsSync21(dest)) {
|
|
19682
20175
|
rmSync2(dest, { recursive: true, force: true });
|
|
19683
20176
|
console.log(`Removed ${dest}`);
|
|
19684
20177
|
} else {
|
|
@@ -19693,7 +20186,7 @@ async function openMenubar() {
|
|
|
19693
20186
|
return;
|
|
19694
20187
|
}
|
|
19695
20188
|
const dest = installedAppPath();
|
|
19696
|
-
if (!
|
|
20189
|
+
if (!existsSync21(dest)) {
|
|
19697
20190
|
console.log("Widget not installed yet. Run `fleetlens menubar install` first.");
|
|
19698
20191
|
return;
|
|
19699
20192
|
}
|
|
@@ -19710,9 +20203,9 @@ async function statusMenubar() {
|
|
|
19710
20203
|
return;
|
|
19711
20204
|
}
|
|
19712
20205
|
const dest = installedAppPath();
|
|
19713
|
-
const installed =
|
|
20206
|
+
const installed = existsSync21(dest);
|
|
19714
20207
|
const running = await isRunning();
|
|
19715
|
-
const bundled =
|
|
20208
|
+
const bundled = existsSync21(bundledAppPath());
|
|
19716
20209
|
console.log(`Menu bar widget: ${installed ? "installed" : "not installed"}${installed ? ` (${dest})` : ""}`);
|
|
19717
20210
|
console.log(`Running: ${running ? "yes" : "no"}`);
|
|
19718
20211
|
console.log(`Bundled in CLI: ${bundled ? "yes" : "no \u2014 this build ships without the widget"}`);
|
|
@@ -19803,7 +20296,7 @@ var init_config = __esm({
|
|
|
19803
20296
|
});
|
|
19804
20297
|
|
|
19805
20298
|
// src/perception/build-entries.ts
|
|
19806
|
-
import { statSync as statSync4, readFileSync as
|
|
20299
|
+
import { statSync as statSync4, readFileSync as readFileSync21 } from "node:fs";
|
|
19807
20300
|
import { basename as basename2, dirname as dirname15 } from "node:path";
|
|
19808
20301
|
function decodeProjectDirName(projectDir) {
|
|
19809
20302
|
if (projectDir.startsWith("-")) {
|
|
@@ -19813,7 +20306,7 @@ function decodeProjectDirName(projectDir) {
|
|
|
19813
20306
|
}
|
|
19814
20307
|
function buildEntriesForFile(filePath) {
|
|
19815
20308
|
const stat = statSync4(filePath);
|
|
19816
|
-
const raw =
|
|
20309
|
+
const raw = readFileSync21(filePath, "utf8");
|
|
19817
20310
|
const rawLines = raw.split("\n").filter(Boolean).map((l) => {
|
|
19818
20311
|
try {
|
|
19819
20312
|
return JSON.parse(l);
|
|
@@ -20082,7 +20575,7 @@ function buildIngestPayload(inputs) {
|
|
|
20082
20575
|
return {
|
|
20083
20576
|
ingestId: randomUUID2(),
|
|
20084
20577
|
observedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
20085
|
-
cliVersion: "1.0.
|
|
20578
|
+
cliVersion: "1.0.9",
|
|
20086
20579
|
...richRollup || inputs.enrichedExtras || inputs.artifactSignals ? { schemaVersion: RICH_ROLLUP_SCHEMA_VERSION } : {},
|
|
20087
20580
|
...inputs.rollup ? { dailyRollup: inputs.rollup } : {},
|
|
20088
20581
|
...richRollup ? { richRollup } : {},
|
|
@@ -20124,7 +20617,7 @@ var init_push = __esm({
|
|
|
20124
20617
|
});
|
|
20125
20618
|
|
|
20126
20619
|
// src/team/git-remote.ts
|
|
20127
|
-
import { existsSync as
|
|
20620
|
+
import { existsSync as existsSync22, readFileSync as readFileSync22, statSync as statSync5 } from "node:fs";
|
|
20128
20621
|
import { dirname as dirname16, isAbsolute as isAbsolute2, join as join15, resolve as resolve2 } from "node:path";
|
|
20129
20622
|
function parseGithubRemote(url) {
|
|
20130
20623
|
const m = url.trim().match(GITHUB_URL_RE);
|
|
@@ -20149,12 +20642,12 @@ function gitConfigPathFor(dir) {
|
|
|
20149
20642
|
const st = statSync5(dotGit, { throwIfNoEntry: false });
|
|
20150
20643
|
if (!st) return null;
|
|
20151
20644
|
if (st.isDirectory()) return join15(dotGit, "config");
|
|
20152
|
-
const m =
|
|
20645
|
+
const m = readFileSync22(dotGit, "utf8").match(/^gitdir:\s*(.+)\s*$/m);
|
|
20153
20646
|
if (!m) return null;
|
|
20154
20647
|
const gd = isAbsolute2(m[1]) ? m[1] : resolve2(dir, m[1]);
|
|
20155
20648
|
const commondirFile = join15(gd, "commondir");
|
|
20156
|
-
if (
|
|
20157
|
-
const common =
|
|
20649
|
+
if (existsSync22(commondirFile)) {
|
|
20650
|
+
const common = readFileSync22(commondirFile, "utf8").trim();
|
|
20158
20651
|
return join15(isAbsolute2(common) ? common : resolve2(gd, common), "config");
|
|
20159
20652
|
}
|
|
20160
20653
|
return join15(gd, "config");
|
|
@@ -20169,8 +20662,8 @@ function createRepoResolver() {
|
|
|
20169
20662
|
try {
|
|
20170
20663
|
for (let d = dir; ; d = dirname16(d)) {
|
|
20171
20664
|
const config = gitConfigPathFor(d);
|
|
20172
|
-
if (config &&
|
|
20173
|
-
const url = originUrl2(
|
|
20665
|
+
if (config && existsSync22(config)) {
|
|
20666
|
+
const url = originUrl2(readFileSync22(config, "utf8"));
|
|
20174
20667
|
repo = url ? parseGithubRemote(url) : null;
|
|
20175
20668
|
break;
|
|
20176
20669
|
}
|
|
@@ -20192,7 +20685,7 @@ var init_git_remote = __esm({
|
|
|
20192
20685
|
});
|
|
20193
20686
|
|
|
20194
20687
|
// src/team/queue.ts
|
|
20195
|
-
import { readFileSync as
|
|
20688
|
+
import { readFileSync as readFileSync23, writeFileSync as writeFileSync15, appendFileSync as appendFileSync5, statSync as statSync6, mkdirSync as mkdirSync14 } from "node:fs";
|
|
20196
20689
|
import { dirname as dirname17 } from "node:path";
|
|
20197
20690
|
function enqueuePayload(payload, queuePath = QUEUE_PATH) {
|
|
20198
20691
|
mkdirSync14(dirname17(queuePath), { recursive: true });
|
|
@@ -20209,7 +20702,7 @@ function enqueuePayload(payload, queuePath = QUEUE_PATH) {
|
|
|
20209
20702
|
function dequeuePayloads(queuePath = QUEUE_PATH) {
|
|
20210
20703
|
let lines;
|
|
20211
20704
|
try {
|
|
20212
|
-
lines =
|
|
20705
|
+
lines = readFileSync23(queuePath, "utf8").trim().split("\n").filter(Boolean);
|
|
20213
20706
|
} catch {
|
|
20214
20707
|
return [];
|
|
20215
20708
|
}
|
|
@@ -20230,7 +20723,7 @@ function dequeuePayloads(queuePath = QUEUE_PATH) {
|
|
|
20230
20723
|
function pruneOldest(queuePath) {
|
|
20231
20724
|
let lines;
|
|
20232
20725
|
try {
|
|
20233
|
-
lines =
|
|
20726
|
+
lines = readFileSync23(queuePath, "utf8").trim().split("\n").filter(Boolean);
|
|
20234
20727
|
} catch {
|
|
20235
20728
|
return;
|
|
20236
20729
|
}
|
|
@@ -20249,7 +20742,7 @@ var init_queue2 = __esm({
|
|
|
20249
20742
|
});
|
|
20250
20743
|
|
|
20251
20744
|
// src/usage/profile.ts
|
|
20252
|
-
import { existsSync as
|
|
20745
|
+
import { existsSync as existsSync23, mkdirSync as mkdirSync15, readFileSync as readFileSync24, writeFileSync as writeFileSync16 } from "node:fs";
|
|
20253
20746
|
import { dirname as dirname18 } from "node:path";
|
|
20254
20747
|
function mapRateLimitTier(rateLimitTier) {
|
|
20255
20748
|
switch (rateLimitTier) {
|
|
@@ -20290,9 +20783,9 @@ async function fetchProfile(nowMs = Date.now()) {
|
|
|
20290
20783
|
};
|
|
20291
20784
|
}
|
|
20292
20785
|
function readCachedProfile(cachePath) {
|
|
20293
|
-
if (!
|
|
20786
|
+
if (!existsSync23(cachePath)) return null;
|
|
20294
20787
|
try {
|
|
20295
|
-
const raw = JSON.parse(
|
|
20788
|
+
const raw = JSON.parse(readFileSync24(cachePath, "utf8"));
|
|
20296
20789
|
if (typeof raw.fetchedAtMs !== "number" || !raw.profile) return null;
|
|
20297
20790
|
return raw;
|
|
20298
20791
|
} catch {
|
|
@@ -20481,11 +20974,11 @@ var init_backfill = __esm({
|
|
|
20481
20974
|
});
|
|
20482
20975
|
|
|
20483
20976
|
// src/team/sync-log.ts
|
|
20484
|
-
import { readFileSync as
|
|
20977
|
+
import { readFileSync as readFileSync25 } from "node:fs";
|
|
20485
20978
|
function readPendingSyncLog(watermark) {
|
|
20486
20979
|
let raw;
|
|
20487
20980
|
try {
|
|
20488
|
-
raw =
|
|
20981
|
+
raw = readFileSync25(cclensPath("daemon.log"), "utf8");
|
|
20489
20982
|
} catch {
|
|
20490
20983
|
return { lines: [] };
|
|
20491
20984
|
}
|
|
@@ -20549,7 +21042,7 @@ __export(file_probe_exports, {
|
|
|
20549
21042
|
probeArtifactSignals: () => probeArtifactSignals
|
|
20550
21043
|
});
|
|
20551
21044
|
import { createHash } from "node:crypto";
|
|
20552
|
-
import { existsSync as
|
|
21045
|
+
import { existsSync as existsSync24, readdirSync as readdirSync5, statSync as statSync7 } from "node:fs";
|
|
20553
21046
|
import { homedir as homedir8 } from "node:os";
|
|
20554
21047
|
import { join as join17, relative, resolve as resolve3, sep } from "node:path";
|
|
20555
21048
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
@@ -20559,15 +21052,15 @@ function pathHash(relPath) {
|
|
|
20559
21052
|
function defaultScanRoots(extraRoots = []) {
|
|
20560
21053
|
const roots = [];
|
|
20561
21054
|
const home = join17(homedir8(), ".claude");
|
|
20562
|
-
if (
|
|
21055
|
+
if (existsSync24(home)) roots.push({ root: home, label: "user" });
|
|
20563
21056
|
for (const e of extraRoots) {
|
|
20564
21057
|
const r = resolve3(e, ".claude");
|
|
20565
|
-
if (
|
|
21058
|
+
if (existsSync24(r) && r !== home) roots.push({ root: r, label: "project" });
|
|
20566
21059
|
}
|
|
20567
21060
|
return roots;
|
|
20568
21061
|
}
|
|
20569
21062
|
function listMarkdownFiles(dir) {
|
|
20570
|
-
if (!
|
|
21063
|
+
if (!existsSync24(dir)) return [];
|
|
20571
21064
|
const out = [];
|
|
20572
21065
|
let entries2;
|
|
20573
21066
|
try {
|
|
@@ -20637,7 +21130,7 @@ function scanAuthored(roots, subdir, day2) {
|
|
|
20637
21130
|
const out = [];
|
|
20638
21131
|
for (const r of roots) {
|
|
20639
21132
|
const dir = join17(r.root, subdir);
|
|
20640
|
-
if (!
|
|
21133
|
+
if (!existsSync24(dir)) continue;
|
|
20641
21134
|
for (const f of listMarkdownFiles(dir)) {
|
|
20642
21135
|
const firstSeen = firstSeenDateOf(f);
|
|
20643
21136
|
if (firstSeen !== day2) continue;
|
|
@@ -20651,7 +21144,7 @@ function scanEdited(roots, day2) {
|
|
|
20651
21144
|
const out = [];
|
|
20652
21145
|
for (const r of roots) {
|
|
20653
21146
|
const dir = join17(r.root, "skills");
|
|
20654
|
-
if (!
|
|
21147
|
+
if (!existsSync24(dir)) continue;
|
|
20655
21148
|
for (const f of listMarkdownFiles(dir)) {
|
|
20656
21149
|
const firstSeen = firstSeenDateOf(f);
|
|
20657
21150
|
if (firstSeen === day2) continue;
|
|
@@ -20674,10 +21167,10 @@ function claudemdLineDelta(extraRoots, authorEmail, day2) {
|
|
|
20674
21167
|
const candidates = [];
|
|
20675
21168
|
for (const e of extraRoots) {
|
|
20676
21169
|
const f = resolve3(e, "CLAUDE.md");
|
|
20677
|
-
if (
|
|
21170
|
+
if (existsSync24(f)) candidates.push(f);
|
|
20678
21171
|
}
|
|
20679
21172
|
const homeClaudeMd = join17(homedir8(), "CLAUDE.md");
|
|
20680
|
-
if (
|
|
21173
|
+
if (existsSync24(homeClaudeMd)) candidates.push(homeClaudeMd);
|
|
20681
21174
|
for (const file of candidates) {
|
|
20682
21175
|
try {
|
|
20683
21176
|
const out = execFileSync3(
|
|
@@ -21567,11 +22060,11 @@ var logs_exports = {};
|
|
|
21567
22060
|
__export(logs_exports, {
|
|
21568
22061
|
teamLogs: () => teamLogs
|
|
21569
22062
|
});
|
|
21570
|
-
import { readFileSync as
|
|
22063
|
+
import { readFileSync as readFileSync26 } from "node:fs";
|
|
21571
22064
|
async function teamLogs() {
|
|
21572
22065
|
const logPath = cclensPath("daemon.log");
|
|
21573
22066
|
try {
|
|
21574
|
-
const lines =
|
|
22067
|
+
const lines = readFileSync26(logPath, "utf8").trim().split("\n");
|
|
21575
22068
|
const teamLines = lines.filter((l) => l.includes("[sync] ") || l.includes("team "));
|
|
21576
22069
|
if (teamLines.length === 0) {
|
|
21577
22070
|
console.log("No team-related log entries found.");
|
|
@@ -21699,7 +22192,7 @@ __export(runs_exports, {
|
|
|
21699
22192
|
runs: () => runs
|
|
21700
22193
|
});
|
|
21701
22194
|
import { execSync as execSync2 } from "node:child_process";
|
|
21702
|
-
import { existsSync as
|
|
22195
|
+
import { existsSync as existsSync25, readFileSync as readFileSync27, readdirSync as readdirSync6, statSync as statSync8 } from "node:fs";
|
|
21703
22196
|
import { join as join18 } from "node:path";
|
|
21704
22197
|
async function runs(args2) {
|
|
21705
22198
|
const json = args2.includes("--json");
|
|
@@ -21784,8 +22277,8 @@ function listActiveRuns() {
|
|
|
21784
22277
|
return runs2.sort((a, b) => a.elapsed_s - b.elapsed_s);
|
|
21785
22278
|
}
|
|
21786
22279
|
function readSpend(sinceMs) {
|
|
21787
|
-
if (!
|
|
21788
|
-
const lines =
|
|
22280
|
+
if (!existsSync25(SPEND_PATH)) return [];
|
|
22281
|
+
const lines = readFileSync27(SPEND_PATH, "utf-8").split("\n").filter((l) => l.trim());
|
|
21789
22282
|
const out = [];
|
|
21790
22283
|
for (const line of lines) {
|
|
21791
22284
|
try {
|
|
@@ -21906,7 +22399,7 @@ function ageLabel(ms) {
|
|
|
21906
22399
|
return `${Math.floor(ms / 864e5)}d`;
|
|
21907
22400
|
}
|
|
21908
22401
|
function listTraceFiles() {
|
|
21909
|
-
if (!
|
|
22402
|
+
if (!existsSync25(RUNS_DIR2)) return [];
|
|
21910
22403
|
const entries2 = readdirSync6(RUNS_DIR2).filter((f) => f.endsWith(".jsonl"));
|
|
21911
22404
|
return entries2.map((f) => {
|
|
21912
22405
|
const path11 = join18(RUNS_DIR2, f);
|
|
@@ -21915,14 +22408,14 @@ function listTraceFiles() {
|
|
|
21915
22408
|
}).sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
21916
22409
|
}
|
|
21917
22410
|
function resolveRunId(arg) {
|
|
21918
|
-
if (!
|
|
22411
|
+
if (!existsSync25(RUNS_DIR2)) return null;
|
|
21919
22412
|
if (arg === "latest") {
|
|
21920
22413
|
const all2 = listTraceFiles();
|
|
21921
22414
|
if (all2.length === 0) return null;
|
|
21922
22415
|
return { runId: all2[0].runId, path: all2[0].path };
|
|
21923
22416
|
}
|
|
21924
22417
|
const exact = join18(RUNS_DIR2, `${arg}.jsonl`);
|
|
21925
|
-
if (
|
|
22418
|
+
if (existsSync25(exact)) return { runId: arg, path: exact };
|
|
21926
22419
|
const all = listTraceFiles();
|
|
21927
22420
|
const matches = all.filter((r) => r.runId.includes(arg));
|
|
21928
22421
|
if (matches.length === 1) return { runId: matches[0].runId, path: matches[0].path };
|
|
@@ -21934,7 +22427,7 @@ function resolveRunId(arg) {
|
|
|
21934
22427
|
return null;
|
|
21935
22428
|
}
|
|
21936
22429
|
function readTrace(path11) {
|
|
21937
|
-
return
|
|
22430
|
+
return readFileSync27(path11, "utf-8").split("\n").filter((l) => l.trim()).map((l) => {
|
|
21938
22431
|
try {
|
|
21939
22432
|
return JSON.parse(l);
|
|
21940
22433
|
} catch {
|
|
@@ -21946,7 +22439,7 @@ async function inspect(arg, follow, json) {
|
|
|
21946
22439
|
const r = resolveRunId(arg);
|
|
21947
22440
|
if (!r) {
|
|
21948
22441
|
console.error(`run not found: ${arg}`);
|
|
21949
|
-
if (
|
|
22442
|
+
if (existsSync25(RUNS_DIR2)) {
|
|
21950
22443
|
const all = listTraceFiles().slice(0, 5);
|
|
21951
22444
|
if (all.length > 0) {
|
|
21952
22445
|
console.error(`
|
|
@@ -22126,7 +22619,7 @@ async function main() {
|
|
|
22126
22619
|
case "version":
|
|
22127
22620
|
case "--version":
|
|
22128
22621
|
case "-v":
|
|
22129
|
-
console.log(`fleetlens ${"1.0.
|
|
22622
|
+
console.log(`fleetlens ${"1.0.9"}`);
|
|
22130
22623
|
break;
|
|
22131
22624
|
case "help":
|
|
22132
22625
|
case "--help":
|
|
@@ -22140,7 +22633,7 @@ Common:
|
|
|
22140
22633
|
update Update to the latest version
|
|
22141
22634
|
|
|
22142
22635
|
Terminal:
|
|
22143
|
-
usage [--save]
|
|
22636
|
+
usage [--agent KIND] [--watch] [--save] Plan utilization (all agents; --watch is live)
|
|
22144
22637
|
usage --history [-s D] [--days N] Daily token/cost table
|
|
22145
22638
|
entries [--day D|--session ID|--all] [--json] Perception-layer entries
|
|
22146
22639
|
digest day [--date D|--yesterday|--today] [--json] Day digest
|