fleetlens 1.0.7 → 1.0.8
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/17s-kgtdv385l.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 +2118 -1715
- 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 → qeUfJEEwWX-_kBAEMzh_M}/_buildManifest.js +0 -0
- /package/app/apps/web/.next/static/{rSw7StGuB4J2DfY6_pElg → qeUfJEEwWX-_kBAEMzh_M}/_clientMiddlewareManifest.js +0 -0
- /package/app/apps/web/.next/static/{rSw7StGuB4J2DfY6_pElg → qeUfJEEwWX-_kBAEMzh_M}/_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.8";
|
|
6302
6302
|
} catch {
|
|
6303
|
-
return "1.0.
|
|
6303
|
+
return "1.0.8";
|
|
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.8";
|
|
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.8") {
|
|
6777
6832
|
console.log(
|
|
6778
|
-
` \u2192 This process is still running ${"1.0.
|
|
6833
|
+
` \u2192 This process is still running ${"1.0.8"}. 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.8",
|
|
6814
6869
|
latest: null,
|
|
6815
6870
|
updateAvailable: false
|
|
6816
6871
|
};
|
|
6817
6872
|
return {
|
|
6818
|
-
current: "1.0.
|
|
6873
|
+
current: "1.0.8",
|
|
6819
6874
|
latest,
|
|
6820
|
-
updateAvailable: shouldUpdate("1.0.
|
|
6875
|
+
updateAvailable: shouldUpdate("1.0.8", 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.8";
|
|
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.8"}) \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,1358 @@ 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
|
|
8714
|
-
|
|
8715
|
-
|
|
8716
|
-
|
|
8717
|
-
|
|
8718
|
-
|
|
8719
|
-
|
|
8720
|
-
|
|
8721
|
-
|
|
8722
|
-
|
|
8723
|
-
|
|
8724
|
-
|
|
8725
|
-
claude_helpfulness: null,
|
|
8726
|
-
goal_categories: {},
|
|
8727
|
-
retry_count: 0
|
|
8728
|
-
};
|
|
8729
|
-
}
|
|
8730
|
-
function skippedTrivialEnrichment(generatedAt) {
|
|
8731
|
-
return {
|
|
8732
|
-
status: "skipped_trivial",
|
|
8733
|
-
generated_at: generatedAt,
|
|
8734
|
-
model: null,
|
|
8735
|
-
cost_usd: null,
|
|
8736
|
-
error: null,
|
|
8737
|
-
brief_summary: null,
|
|
8738
|
-
underlying_goal: null,
|
|
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] };
|
|
8755
|
-
}
|
|
8756
|
-
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;
|
|
8757
|
-
var init_types = __esm({
|
|
8758
|
-
"../entries/dist/types.js"() {
|
|
8759
|
-
"use strict";
|
|
8760
|
-
CURRENT_ENTRY_SCHEMA_VERSION = 2;
|
|
8761
|
-
GOAL_CATEGORIES = [
|
|
8762
|
-
"build",
|
|
8763
|
-
"plan",
|
|
8764
|
-
"debug",
|
|
8765
|
-
"review",
|
|
8766
|
-
"steer",
|
|
8767
|
-
"meta",
|
|
8768
|
-
"research",
|
|
8769
|
-
"refactor",
|
|
8770
|
-
"test",
|
|
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
|
-
};
|
|
8932
|
+
// src/usage/format.ts
|
|
8933
|
+
function formatMultiAgentUsage(byAgent, opts = {}) {
|
|
8934
|
+
const kinds = Object.keys(byAgent).sort(compareAgents);
|
|
8935
|
+
if (kinds.length === 0) return "";
|
|
8936
|
+
const lines = [];
|
|
8937
|
+
lines.push("");
|
|
8938
|
+
if (opts.watch) {
|
|
8939
|
+
const sec = opts.intervalSec ?? 2;
|
|
8940
|
+
lines.push(
|
|
8941
|
+
` ${BOLD}Fleetlens Usage${RESET} ${DIM}live \xB7 every ${sec}s \xB7 Ctrl+C to quit${RESET}`
|
|
8942
|
+
);
|
|
8943
|
+
} else {
|
|
8944
|
+
lines.push(` ${BOLD}Fleetlens Usage${RESET}`);
|
|
8785
8945
|
}
|
|
8786
|
-
|
|
8787
|
-
|
|
8788
|
-
|
|
8789
|
-
|
|
8790
|
-
"../parser/dist/types.js"() {
|
|
8791
|
-
"use strict";
|
|
8946
|
+
lines.push("");
|
|
8947
|
+
for (const kind of kinds) {
|
|
8948
|
+
const snap = byAgent[kind];
|
|
8949
|
+
lines.push(...formatAgentBlock(kind, snap));
|
|
8792
8950
|
}
|
|
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;
|
|
8951
|
+
lines.push("");
|
|
8952
|
+
return lines.join("\n");
|
|
8800
8953
|
}
|
|
8801
|
-
function
|
|
8802
|
-
const
|
|
8803
|
-
|
|
8804
|
-
|
|
8805
|
-
|
|
8806
|
-
|
|
8807
|
-
|
|
8808
|
-
|
|
8809
|
-
|
|
8810
|
-
|
|
8811
|
-
|
|
8812
|
-
const
|
|
8813
|
-
const
|
|
8814
|
-
|
|
8815
|
-
|
|
8816
|
-
|
|
8817
|
-
if (r.kind === "agent") {
|
|
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
|
-
}
|
|
8954
|
+
function formatAgentBlock(kind, snapshot) {
|
|
8955
|
+
const lines = [];
|
|
8956
|
+
const title = agentTitle(kind);
|
|
8957
|
+
const plan = snapshot.plan_type ? ` ${DIM}${snapshot.plan_type}${RESET}` : "";
|
|
8958
|
+
lines.push(` ${BOLD}${title}${RESET}${plan}`);
|
|
8959
|
+
let renderedMeter = false;
|
|
8960
|
+
for (const [label, window] of agentWindows(kind, snapshot)) {
|
|
8961
|
+
if (!window || window.utilization === null) continue;
|
|
8962
|
+
renderedMeter = true;
|
|
8963
|
+
const pct = window.utilization;
|
|
8964
|
+
const bar = renderBar(pct);
|
|
8965
|
+
const pctStr = `${pct.toFixed(1)}%`.padStart(6);
|
|
8966
|
+
const labelStr = label.padEnd(16);
|
|
8967
|
+
lines.push(` ${labelStr}${bar} ${BOLD}${pctStr}${RESET}`);
|
|
8968
|
+
if (window.resets_at) {
|
|
8969
|
+
lines.push(` ${" ".repeat(16)}${DIM}resets ${formatRelative(window.resets_at)}${RESET}`);
|
|
8838
8970
|
}
|
|
8839
|
-
|
|
8840
|
-
|
|
8841
|
-
|
|
8842
|
-
|
|
8843
|
-
|
|
8844
|
-
|
|
8845
|
-
|
|
8846
|
-
|
|
8847
|
-
finalAgentIndex = i;
|
|
8848
|
-
break;
|
|
8971
|
+
}
|
|
8972
|
+
if ((kind === "claude-code" || !kind) && snapshot.extra_usage?.is_enabled) {
|
|
8973
|
+
renderedMeter = true;
|
|
8974
|
+
const extra = snapshot.extra_usage;
|
|
8975
|
+
if (extra.utilization !== null) {
|
|
8976
|
+
lines.push(
|
|
8977
|
+
` ${"Extra usage".padEnd(16)}${renderBar(extra.utilization)} ${BOLD}${extra.utilization.toFixed(1)}%${RESET}`
|
|
8978
|
+
);
|
|
8849
8979
|
}
|
|
8850
|
-
if (
|
|
8851
|
-
|
|
8852
|
-
|
|
8853
|
-
|
|
8854
|
-
break;
|
|
8855
|
-
}
|
|
8856
|
-
}
|
|
8980
|
+
if (extra.used_credits !== null && extra.monthly_limit !== null) {
|
|
8981
|
+
lines.push(
|
|
8982
|
+
` ${" ".repeat(16)}${DIM}${extra.used_credits} / ${extra.monthly_limit} credits${RESET}`
|
|
8983
|
+
);
|
|
8857
8984
|
}
|
|
8858
|
-
|
|
8859
|
-
|
|
8860
|
-
const
|
|
8861
|
-
|
|
8862
|
-
|
|
8863
|
-
|
|
8864
|
-
|
|
8865
|
-
|
|
8866
|
-
|
|
8867
|
-
|
|
8868
|
-
|
|
8869
|
-
|
|
8870
|
-
|
|
8871
|
-
|
|
8872
|
-
|
|
8873
|
-
|
|
8874
|
-
|
|
8875
|
-
|
|
8876
|
-
|
|
8877
|
-
|
|
8878
|
-
finalAgentPreview,
|
|
8879
|
-
firstAgentIndex,
|
|
8880
|
-
finalAgentIndex,
|
|
8881
|
-
toolNames,
|
|
8882
|
-
totalTokens: tokens
|
|
8985
|
+
}
|
|
8986
|
+
if (kind === "zai" && snapshot.web_search_quota) {
|
|
8987
|
+
const used = snapshot.web_search_quota.used;
|
|
8988
|
+
if (used !== null && used !== void 0) {
|
|
8989
|
+
renderedMeter = true;
|
|
8990
|
+
lines.push(
|
|
8991
|
+
` ${"Web search".padEnd(16)}${renderBar(used)} ${BOLD}${used.toFixed(0)}%${RESET}`
|
|
8992
|
+
);
|
|
8993
|
+
}
|
|
8994
|
+
}
|
|
8995
|
+
if (kind === "copilot" && snapshot.monthly_quota) {
|
|
8996
|
+
const q = snapshot.monthly_quota;
|
|
8997
|
+
const unit = q.unit === "premium-requests" ? "premium requests" : "AI credits";
|
|
8998
|
+
if (q.unlimited) {
|
|
8999
|
+
renderedMeter = true;
|
|
9000
|
+
lines.push(` ${"Monthly".padEnd(16)}${BOLD}Limit not reported${RESET}`);
|
|
9001
|
+
if (q.used !== null) {
|
|
9002
|
+
lines.push(
|
|
9003
|
+
` ${" ".repeat(16)}${DIM}${q.used.toLocaleString("en-US")} ${unit} reported by Copilot${RESET}`
|
|
9004
|
+
);
|
|
8883
9005
|
}
|
|
8884
|
-
})
|
|
8885
|
-
|
|
8886
|
-
}
|
|
8887
|
-
|
|
8888
|
-
if (r.kind === "user" || r.kind === "interrupt") {
|
|
8889
|
-
flush();
|
|
8890
|
-
out.push(r);
|
|
8891
|
-
turnAnchor = r;
|
|
8892
|
-
} else {
|
|
8893
|
-
buffer.push(r);
|
|
9006
|
+
} else if (q.used !== null && q.limit !== null) {
|
|
9007
|
+
lines.push(
|
|
9008
|
+
` ${" ".repeat(16)}${DIM}${q.used} / ${q.limit} ${unit}${RESET}`
|
|
9009
|
+
);
|
|
8894
9010
|
}
|
|
8895
9011
|
}
|
|
8896
|
-
|
|
8897
|
-
|
|
9012
|
+
if (!renderedMeter) {
|
|
9013
|
+
lines.push(` ${DIM}(no utilization windows)${RESET}`);
|
|
9014
|
+
}
|
|
9015
|
+
lines.push(
|
|
9016
|
+
` ${DIM}sampled ${formatRelative(snapshot.captured_at)}${RESET}`
|
|
9017
|
+
);
|
|
9018
|
+
lines.push("");
|
|
9019
|
+
return lines;
|
|
8898
9020
|
}
|
|
8899
|
-
function
|
|
8900
|
-
if (
|
|
8901
|
-
return
|
|
8902
|
-
|
|
8903
|
-
|
|
8904
|
-
return
|
|
8905
|
-
}
|
|
8906
|
-
|
|
8907
|
-
|
|
8908
|
-
|
|
8909
|
-
|
|
8910
|
-
|
|
8911
|
-
|
|
8912
|
-
|
|
8913
|
-
|
|
8914
|
-
|
|
8915
|
-
|
|
8916
|
-
|
|
8917
|
-
|
|
8918
|
-
|
|
8919
|
-
|
|
8920
|
-
|
|
9021
|
+
function agentWindows(kind, snapshot) {
|
|
9022
|
+
if (kind === "copilot") {
|
|
9023
|
+
return [["Monthly", snapshot.monthly]];
|
|
9024
|
+
}
|
|
9025
|
+
if (kind === "grok") {
|
|
9026
|
+
return [["7 day", snapshot.seven_day]];
|
|
9027
|
+
}
|
|
9028
|
+
if (kind === "codex" && snapshot.five_hour?.utilization == null) {
|
|
9029
|
+
return [["7 day", snapshot.seven_day]];
|
|
9030
|
+
}
|
|
9031
|
+
const rows = [
|
|
9032
|
+
["5 hour", snapshot.five_hour],
|
|
9033
|
+
["7 day", snapshot.seven_day]
|
|
9034
|
+
];
|
|
9035
|
+
if (kind === "claude-code" || !snapshot.agent) {
|
|
9036
|
+
if (snapshot.seven_day_opus?.utilization != null) {
|
|
9037
|
+
rows.push(["7 day (Opus)", snapshot.seven_day_opus]);
|
|
9038
|
+
}
|
|
9039
|
+
if (snapshot.seven_day_sonnet?.utilization != null) {
|
|
9040
|
+
rows.push(["7 day (Sonnet)", snapshot.seven_day_sonnet]);
|
|
9041
|
+
}
|
|
9042
|
+
if (snapshot.seven_day_oauth_apps?.utilization != null) {
|
|
9043
|
+
rows.push(["7 day (OAuth apps)", snapshot.seven_day_oauth_apps]);
|
|
9044
|
+
}
|
|
9045
|
+
if (snapshot.seven_day_cowork?.utilization != null) {
|
|
9046
|
+
rows.push(["7 day (Cowork)", snapshot.seven_day_cowork]);
|
|
9047
|
+
}
|
|
9048
|
+
}
|
|
9049
|
+
return rows;
|
|
8921
9050
|
}
|
|
8922
|
-
function
|
|
8923
|
-
|
|
9051
|
+
function agentTitle(kind) {
|
|
9052
|
+
if (isAgentKind(kind)) {
|
|
9053
|
+
return getAgentMetadata(kind)?.displayName ?? kind;
|
|
9054
|
+
}
|
|
9055
|
+
return kind;
|
|
8924
9056
|
}
|
|
8925
|
-
function
|
|
8926
|
-
|
|
8927
|
-
|
|
8928
|
-
|
|
9057
|
+
function compareAgents(a, b) {
|
|
9058
|
+
const ia = AGENT_PRIORITY.indexOf(a);
|
|
9059
|
+
const ib = AGENT_PRIORITY.indexOf(b);
|
|
9060
|
+
if (ia !== -1 || ib !== -1) {
|
|
9061
|
+
if (ia === -1) return 1;
|
|
9062
|
+
if (ib === -1) return -1;
|
|
9063
|
+
return ia - ib;
|
|
8929
9064
|
}
|
|
8930
|
-
return
|
|
9065
|
+
return a.localeCompare(b);
|
|
8931
9066
|
}
|
|
8932
|
-
function
|
|
8933
|
-
|
|
8934
|
-
|
|
8935
|
-
const
|
|
8936
|
-
|
|
9067
|
+
function renderBar(utilization) {
|
|
9068
|
+
const clamped = Math.max(0, Math.min(100, utilization));
|
|
9069
|
+
const color = clamped >= 90 ? RED : clamped >= 70 ? YELLOW : GREEN;
|
|
9070
|
+
const totalEighths = Math.round(clamped / 100 * BAR_WIDTH * 8);
|
|
9071
|
+
const fullBlocks = Math.floor(totalEighths / 8);
|
|
9072
|
+
const remainder = totalEighths % 8;
|
|
9073
|
+
const partial = EIGHTHS[remainder];
|
|
9074
|
+
const filledCells = fullBlocks + (partial ? 1 : 0);
|
|
9075
|
+
const emptyCells = BAR_WIDTH - filledCells;
|
|
9076
|
+
const filled = "\u2588".repeat(fullBlocks) + partial;
|
|
9077
|
+
const empty = "\xB7".repeat(emptyCells);
|
|
9078
|
+
return `${color}${filled}${RESET}${DIM}${empty}${RESET}`;
|
|
8937
9079
|
}
|
|
8938
|
-
function
|
|
8939
|
-
const
|
|
8940
|
-
|
|
8941
|
-
|
|
8942
|
-
|
|
8943
|
-
|
|
8944
|
-
|
|
8945
|
-
|
|
9080
|
+
function formatRelative(iso) {
|
|
9081
|
+
const then = new Date(iso).getTime();
|
|
9082
|
+
const now = Date.now();
|
|
9083
|
+
const diffSec = Math.round((then - now) / 1e3);
|
|
9084
|
+
const abs = Math.abs(diffSec);
|
|
9085
|
+
const past = diffSec < 0;
|
|
9086
|
+
let value;
|
|
9087
|
+
if (abs < 60) {
|
|
9088
|
+
value = `${abs}s`;
|
|
9089
|
+
} else if (abs < 3600) {
|
|
9090
|
+
value = `${Math.floor(abs / 60)}m`;
|
|
9091
|
+
} else if (abs < 86400) {
|
|
9092
|
+
const h = Math.floor(abs / 3600);
|
|
9093
|
+
const m = Math.floor(abs % 3600 / 60);
|
|
9094
|
+
value = m > 0 ? `${h}h${m}m` : `${h}h`;
|
|
9095
|
+
} else {
|
|
9096
|
+
const d = Math.floor(abs / 86400);
|
|
9097
|
+
const h = Math.floor(abs % 86400 / 3600);
|
|
9098
|
+
value = h > 0 ? `${d}d${h}h` : `${d}d`;
|
|
8946
9099
|
}
|
|
8947
|
-
|
|
8948
|
-
|
|
8949
|
-
|
|
8950
|
-
|
|
8951
|
-
|
|
8952
|
-
|
|
8953
|
-
|
|
8954
|
-
|
|
8955
|
-
|
|
8956
|
-
|
|
8957
|
-
|
|
8958
|
-
|
|
8959
|
-
|
|
8960
|
-
|
|
8961
|
-
|
|
8962
|
-
|
|
8963
|
-
|
|
8964
|
-
|
|
8965
|
-
|
|
8966
|
-
|
|
8967
|
-
|
|
8968
|
-
for (
|
|
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
|
-
|
|
9100
|
+
return past ? `${value} ago` : `in ${value}`;
|
|
9101
|
+
}
|
|
9102
|
+
var DIM, BOLD, RESET, GREEN, YELLOW, RED, BAR_WIDTH, EIGHTHS, AGENT_PRIORITY;
|
|
9103
|
+
var init_format = __esm({
|
|
9104
|
+
"src/usage/format.ts"() {
|
|
9105
|
+
"use strict";
|
|
9106
|
+
init_dist();
|
|
9107
|
+
DIM = "\x1B[2m";
|
|
9108
|
+
BOLD = "\x1B[1m";
|
|
9109
|
+
RESET = "\x1B[0m";
|
|
9110
|
+
GREEN = "\x1B[32m";
|
|
9111
|
+
YELLOW = "\x1B[33m";
|
|
9112
|
+
RED = "\x1B[31m";
|
|
9113
|
+
BAR_WIDTH = 40;
|
|
9114
|
+
EIGHTHS = ["", "\u258F", "\u258E", "\u258D", "\u258C", "\u258B", "\u258A", "\u2589"];
|
|
9115
|
+
AGENT_PRIORITY = ["claude-code", "codex", "copilot", "zai", "grok"];
|
|
9116
|
+
}
|
|
9117
|
+
});
|
|
9118
|
+
|
|
9119
|
+
// src/pricing.ts
|
|
9120
|
+
function findPricing(model) {
|
|
9121
|
+
for (const [prefix, pricing] of PRICING) {
|
|
9122
|
+
if (model.startsWith(prefix)) return pricing;
|
|
9123
|
+
}
|
|
9124
|
+
return null;
|
|
9125
|
+
}
|
|
9126
|
+
function estimateCost(model, usage2) {
|
|
9127
|
+
const p = findPricing(model);
|
|
9128
|
+
if (!p) return null;
|
|
9129
|
+
return (usage2.input * p.input + usage2.output * p.output + usage2.cacheRead * p.cacheRead + usage2.cacheWrite * p.cacheWrite) / 1e6;
|
|
9130
|
+
}
|
|
9131
|
+
var PRICING;
|
|
9132
|
+
var init_pricing = __esm({
|
|
9133
|
+
"src/pricing.ts"() {
|
|
9134
|
+
"use strict";
|
|
9135
|
+
PRICING = [
|
|
9136
|
+
["claude-opus-4", { input: 15, output: 75, cacheRead: 1.5, cacheWrite: 18.75 }],
|
|
9137
|
+
["claude-sonnet-4", { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }],
|
|
9138
|
+
["claude-haiku-4", { input: 0.8, output: 4, cacheRead: 0.08, cacheWrite: 1 }],
|
|
9139
|
+
["claude-3-5-sonnet", { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }],
|
|
9140
|
+
["claude-3-5-haiku", { input: 0.8, output: 4, cacheRead: 0.08, cacheWrite: 1 }],
|
|
9141
|
+
["claude-3-opus", { input: 15, output: 75, cacheRead: 1.5, cacheWrite: 18.75 }]
|
|
9142
|
+
];
|
|
9143
|
+
}
|
|
9144
|
+
});
|
|
9145
|
+
|
|
9146
|
+
// src/table.ts
|
|
9147
|
+
function fmtNum(n) {
|
|
9148
|
+
return n.toLocaleString("en-US");
|
|
9149
|
+
}
|
|
9150
|
+
function fmtCost(cost, partial = false) {
|
|
9151
|
+
if (cost === null) return "\u2014";
|
|
9152
|
+
return `${partial ? "\u2265" : ""}$${cost.toFixed(2)}`;
|
|
9153
|
+
}
|
|
9154
|
+
function pad(s, width, align = "right") {
|
|
9155
|
+
if (align === "left") return s.padEnd(width);
|
|
9156
|
+
return s.padStart(width);
|
|
9157
|
+
}
|
|
9158
|
+
function renderTable(rows, title) {
|
|
9159
|
+
const lines = [];
|
|
9160
|
+
lines.push("");
|
|
9161
|
+
lines.push(`${BOLD2}${title}${RESET2}`);
|
|
9162
|
+
lines.push("");
|
|
9163
|
+
const header = [
|
|
9164
|
+
pad("Date", 12, "left"),
|
|
9165
|
+
pad("Models", 20, "left"),
|
|
9166
|
+
pad("Input", 12),
|
|
9167
|
+
pad("Output", 12),
|
|
9168
|
+
pad("Cache Create", 14),
|
|
9169
|
+
pad("Cache Read", 14),
|
|
9170
|
+
pad("Total", 14),
|
|
9171
|
+
pad("Cost (USD)", 12)
|
|
9172
|
+
].join(" ");
|
|
9173
|
+
lines.push(`${DIM2}${header}${RESET2}`);
|
|
9174
|
+
lines.push(`${DIM2}${"\u2500".repeat(header.length)}${RESET2}`);
|
|
9175
|
+
let costIncomplete = false;
|
|
9176
|
+
for (const r of rows) {
|
|
9177
|
+
if (r.cost === null || r.costPartial) costIncomplete = true;
|
|
9178
|
+
lines.push([
|
|
9179
|
+
pad(r.date, 12, "left"),
|
|
9180
|
+
pad(r.models, 20, "left"),
|
|
9181
|
+
pad(fmtNum(r.input), 12),
|
|
9182
|
+
pad(fmtNum(r.output), 12),
|
|
9183
|
+
pad(fmtNum(r.cacheCreate), 14),
|
|
9184
|
+
pad(fmtNum(r.cacheRead), 14),
|
|
9185
|
+
pad(fmtNum(r.totalTokens), 14),
|
|
9186
|
+
pad(fmtCost(r.cost, r.costPartial), 12)
|
|
9187
|
+
].join(" "));
|
|
9188
|
+
}
|
|
9189
|
+
const totals = rows.reduce(
|
|
9190
|
+
(acc, r) => ({
|
|
9191
|
+
input: acc.input + r.input,
|
|
9192
|
+
output: acc.output + r.output,
|
|
9193
|
+
cacheCreate: acc.cacheCreate + r.cacheCreate,
|
|
9194
|
+
cacheRead: acc.cacheRead + r.cacheRead,
|
|
9195
|
+
totalTokens: acc.totalTokens + r.totalTokens,
|
|
9196
|
+
cost: acc.cost + (r.cost ?? 0),
|
|
9197
|
+
anyCost: acc.anyCost || r.cost !== null
|
|
9198
|
+
}),
|
|
9199
|
+
{ input: 0, output: 0, cacheCreate: 0, cacheRead: 0, totalTokens: 0, cost: 0, anyCost: false }
|
|
9200
|
+
);
|
|
9201
|
+
lines.push(`${DIM2}${"\u2500".repeat(header.length)}${RESET2}`);
|
|
9202
|
+
lines.push(
|
|
9203
|
+
`${BOLD2}${[
|
|
9204
|
+
pad("Total", 12, "left"),
|
|
9205
|
+
pad("", 20, "left"),
|
|
9206
|
+
pad(fmtNum(totals.input), 12),
|
|
9207
|
+
pad(fmtNum(totals.output), 12),
|
|
9208
|
+
pad(fmtNum(totals.cacheCreate), 14),
|
|
9209
|
+
pad(fmtNum(totals.cacheRead), 14),
|
|
9210
|
+
pad(fmtNum(totals.totalTokens), 14),
|
|
9211
|
+
pad(totals.anyCost ? fmtCost(totals.cost, costIncomplete) : fmtCost(null), 12)
|
|
9212
|
+
].join(" ")}${RESET2}`
|
|
9213
|
+
);
|
|
9214
|
+
if (costIncomplete) {
|
|
9215
|
+
lines.push("");
|
|
9216
|
+
lines.push(
|
|
9217
|
+
`${DIM2} Cost covers priced usage only \u2014 "\u2014" = no priced sessions that day, "\u2265" = lower bound (some sessions had unknown pricing).${RESET2}`
|
|
9218
|
+
);
|
|
9219
|
+
}
|
|
9220
|
+
lines.push("");
|
|
9221
|
+
return lines.join("\n");
|
|
9222
|
+
}
|
|
9223
|
+
var DIM2, BOLD2, RESET2;
|
|
9224
|
+
var init_table = __esm({
|
|
9225
|
+
"src/table.ts"() {
|
|
9226
|
+
"use strict";
|
|
9227
|
+
DIM2 = "\x1B[2m";
|
|
9228
|
+
BOLD2 = "\x1B[1m";
|
|
9229
|
+
RESET2 = "\x1B[0m";
|
|
9230
|
+
}
|
|
9231
|
+
});
|
|
9232
|
+
|
|
9233
|
+
// src/commands/usage-history.ts
|
|
9234
|
+
var usage_history_exports = {};
|
|
9235
|
+
__export(usage_history_exports, {
|
|
9236
|
+
history: () => history
|
|
9237
|
+
});
|
|
9238
|
+
async function history(args2) {
|
|
9239
|
+
const live = args2.includes("--live");
|
|
9240
|
+
const sinceIdx = args2.indexOf("-s");
|
|
9241
|
+
const daysIdx = args2.indexOf("--days");
|
|
9242
|
+
let sinceDate = null;
|
|
9243
|
+
if (sinceIdx !== -1 && args2[sinceIdx + 1]) {
|
|
9244
|
+
const raw = args2[sinceIdx + 1];
|
|
9245
|
+
sinceDate = /* @__PURE__ */ new Date(`${raw.slice(0, 4)}-${raw.slice(4, 6)}-${raw.slice(6, 8)}`);
|
|
9246
|
+
} else if (daysIdx !== -1 && args2[daysIdx + 1]) {
|
|
9247
|
+
const days = parseInt(args2[daysIdx + 1], 10);
|
|
9248
|
+
sinceDate = /* @__PURE__ */ new Date();
|
|
9249
|
+
sinceDate.setDate(sinceDate.getDate() - days);
|
|
9250
|
+
sinceDate.setHours(0, 0, 0, 0);
|
|
9251
|
+
}
|
|
9252
|
+
if (live) {
|
|
9253
|
+
await liveStats(sinceDate);
|
|
9254
|
+
} else {
|
|
9255
|
+
await printStats(sinceDate);
|
|
9256
|
+
}
|
|
9257
|
+
}
|
|
9258
|
+
async function printStats(sinceDate) {
|
|
9259
|
+
const sessions = await listSessions({ limit: 1e4 });
|
|
9260
|
+
const filtered = sinceDate ? sessions.filter((s) => s.firstTimestamp && new Date(s.firstTimestamp) >= sinceDate) : sessions;
|
|
9261
|
+
const rows = aggregateByDay(filtered);
|
|
9262
|
+
const output = renderTable(rows, "Claude Code Token Usage Report \u2014 Daily");
|
|
9263
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
9264
|
+
const todaySessions = filtered.filter((s) => s.firstTimestamp?.startsWith(today)).length;
|
|
9265
|
+
const status2 = getServerStatus();
|
|
9266
|
+
const serverLine = status2.running ? `Server running on http://localhost:${status2.port}` : "Server not running";
|
|
9267
|
+
console.log(output);
|
|
9268
|
+
console.log(` ${todaySessions} sessions today \xB7 ${serverLine}`);
|
|
9269
|
+
console.log("");
|
|
9270
|
+
}
|
|
9271
|
+
function displayModel(raw) {
|
|
9272
|
+
return raw.replace(/-\d{8}$/, "").replace(/^claude-/, "");
|
|
9273
|
+
}
|
|
9274
|
+
function aggregateByDay(sessions) {
|
|
9275
|
+
const byDay = /* @__PURE__ */ new Map();
|
|
9276
|
+
for (const s of sessions) {
|
|
9277
|
+
const day2 = s.firstTimestamp?.slice(0, 10) ?? "unknown";
|
|
9278
|
+
if (!byDay.has(day2)) byDay.set(day2, { sessions: [], models: /* @__PURE__ */ new Set() });
|
|
9279
|
+
const bucket = byDay.get(day2);
|
|
9280
|
+
bucket.sessions.push(s);
|
|
9281
|
+
if (s.model) bucket.models.add(displayModel(s.model));
|
|
9282
|
+
}
|
|
9283
|
+
const sorted = [...byDay.entries()].sort((a, b) => b[0].localeCompare(a[0]));
|
|
9284
|
+
return sorted.map(([date, { sessions: sessions2, models }]) => {
|
|
9285
|
+
const usage2 = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
|
|
9286
|
+
let cost = 0;
|
|
9287
|
+
let anyPriced = false;
|
|
9288
|
+
let anyUnpriced = false;
|
|
9289
|
+
for (const s of sessions2) {
|
|
9290
|
+
usage2.input += s.totalUsage.input;
|
|
9291
|
+
usage2.output += s.totalUsage.output;
|
|
9292
|
+
usage2.cacheRead += s.totalUsage.cacheRead;
|
|
9293
|
+
usage2.cacheWrite += s.totalUsage.cacheWrite;
|
|
9294
|
+
if (s.model) {
|
|
9295
|
+
const c = estimateCost(s.model, s.totalUsage);
|
|
9296
|
+
if (c !== null) {
|
|
9297
|
+
cost += c;
|
|
9298
|
+
anyPriced = true;
|
|
9299
|
+
} else {
|
|
9300
|
+
anyUnpriced = true;
|
|
9301
|
+
}
|
|
9038
9302
|
}
|
|
9039
|
-
rows.push({
|
|
9040
|
-
kind: "user",
|
|
9041
|
-
event: e,
|
|
9042
|
-
tOffsetMs: e.tOffsetMs,
|
|
9043
|
-
gapMs: e.gapMs
|
|
9044
|
-
});
|
|
9045
|
-
continue;
|
|
9046
9303
|
}
|
|
9047
|
-
|
|
9048
|
-
|
|
9049
|
-
|
|
9050
|
-
|
|
9051
|
-
|
|
9052
|
-
|
|
9053
|
-
|
|
9054
|
-
|
|
9055
|
-
|
|
9056
|
-
|
|
9057
|
-
|
|
9058
|
-
|
|
9059
|
-
|
|
9060
|
-
|
|
9061
|
-
|
|
9062
|
-
|
|
9063
|
-
|
|
9064
|
-
|
|
9065
|
-
|
|
9304
|
+
const modelNames = [...models].join(", ");
|
|
9305
|
+
return {
|
|
9306
|
+
date,
|
|
9307
|
+
models: modelNames || "\u2014",
|
|
9308
|
+
input: usage2.input,
|
|
9309
|
+
output: usage2.output,
|
|
9310
|
+
cacheCreate: usage2.cacheWrite,
|
|
9311
|
+
cacheRead: usage2.cacheRead,
|
|
9312
|
+
totalTokens: usage2.input + usage2.output + usage2.cacheRead + usage2.cacheWrite,
|
|
9313
|
+
cost: anyPriced ? cost : null,
|
|
9314
|
+
costPartial: anyPriced && anyUnpriced
|
|
9315
|
+
};
|
|
9316
|
+
});
|
|
9317
|
+
}
|
|
9318
|
+
async function liveStats(sinceDate) {
|
|
9319
|
+
if (process.stdin.isTTY) {
|
|
9320
|
+
process.stdin.setRawMode(true);
|
|
9321
|
+
process.stdin.resume();
|
|
9322
|
+
process.stdin.on("data", (data) => {
|
|
9323
|
+
if (data.toString() === "q" || data.toString() === "") {
|
|
9324
|
+
process.stdout.write("\x1B[?25h");
|
|
9325
|
+
process.exit(0);
|
|
9066
9326
|
}
|
|
9067
|
-
|
|
9068
|
-
|
|
9069
|
-
|
|
9070
|
-
|
|
9071
|
-
|
|
9072
|
-
|
|
9073
|
-
|
|
9074
|
-
|
|
9075
|
-
|
|
9327
|
+
});
|
|
9328
|
+
}
|
|
9329
|
+
const refresh = async () => {
|
|
9330
|
+
const sessions = await listSessions({ limit: 1e4 });
|
|
9331
|
+
const filtered = sinceDate ? sessions.filter((s) => s.firstTimestamp && new Date(s.firstTimestamp) >= sinceDate) : sessions;
|
|
9332
|
+
const rows = aggregateByDay(filtered);
|
|
9333
|
+
const output = renderTable(rows, "Claude Code Token Usage Report \u2014 Live (q to quit)");
|
|
9334
|
+
process.stdout.write("\x1B[2J\x1B[H");
|
|
9335
|
+
process.stdout.write("\x1B[?25l");
|
|
9336
|
+
process.stdout.write(output);
|
|
9337
|
+
const running = filtered.filter((s) => s.status === "running");
|
|
9338
|
+
if (running.length > 0) {
|
|
9339
|
+
process.stdout.write(" Active Sessions\n");
|
|
9340
|
+
for (const s of running.slice(0, 5)) {
|
|
9341
|
+
const project = s.projectName.split("/").slice(-2).join("/");
|
|
9342
|
+
const tokens = s.totalUsage.input + s.totalUsage.output;
|
|
9343
|
+
process.stdout.write(` ${project.padEnd(30)} ${tokens.toLocaleString()} tokens
|
|
9344
|
+
`);
|
|
9076
9345
|
}
|
|
9077
|
-
|
|
9078
|
-
rows.push({
|
|
9079
|
-
kind: "agent",
|
|
9080
|
-
event: e,
|
|
9081
|
-
groupedEvents: grouped,
|
|
9082
|
-
tOffsetMs: e.tOffsetMs,
|
|
9083
|
-
gapMs: e.gapMs
|
|
9084
|
-
});
|
|
9085
|
-
continue;
|
|
9346
|
+
process.stdout.write("\n");
|
|
9086
9347
|
}
|
|
9087
|
-
}
|
|
9088
|
-
|
|
9348
|
+
};
|
|
9349
|
+
await refresh();
|
|
9350
|
+
setInterval(refresh, 2e3);
|
|
9089
9351
|
}
|
|
9090
|
-
var
|
|
9091
|
-
|
|
9092
|
-
"../parser/dist/presentation.js"() {
|
|
9352
|
+
var init_usage_history = __esm({
|
|
9353
|
+
"src/commands/usage-history.ts"() {
|
|
9093
9354
|
"use strict";
|
|
9094
|
-
|
|
9095
|
-
|
|
9096
|
-
|
|
9097
|
-
|
|
9098
|
-
TASK_NOTIFICATION_RE = /<task-notification>/;
|
|
9355
|
+
init_fs();
|
|
9356
|
+
init_pricing();
|
|
9357
|
+
init_table();
|
|
9358
|
+
init_server();
|
|
9099
9359
|
}
|
|
9100
9360
|
});
|
|
9101
9361
|
|
|
9102
|
-
//
|
|
9103
|
-
|
|
9104
|
-
|
|
9105
|
-
|
|
9106
|
-
|
|
9107
|
-
|
|
9108
|
-
|
|
9109
|
-
const
|
|
9110
|
-
|
|
9111
|
-
|
|
9112
|
-
|
|
9362
|
+
// src/commands/usage.ts
|
|
9363
|
+
var usage_exports = {};
|
|
9364
|
+
__export(usage_exports, {
|
|
9365
|
+
usage: () => usage
|
|
9366
|
+
});
|
|
9367
|
+
async function saveAuxiliarySnapshots() {
|
|
9368
|
+
let saved = 0;
|
|
9369
|
+
for (const source of agentSources) {
|
|
9370
|
+
if (source.kind === "claude-code" || !source.usagePoller) continue;
|
|
9371
|
+
try {
|
|
9372
|
+
const partial = await source.usagePoller();
|
|
9373
|
+
if (!partial) continue;
|
|
9374
|
+
appendSnapshot(USAGE_LOG2, {
|
|
9375
|
+
...partial,
|
|
9376
|
+
seven_day_opus: null,
|
|
9377
|
+
seven_day_sonnet: null,
|
|
9378
|
+
seven_day_oauth_apps: null,
|
|
9379
|
+
seven_day_cowork: null,
|
|
9380
|
+
extra_usage: null
|
|
9381
|
+
});
|
|
9382
|
+
saved += 1;
|
|
9383
|
+
} catch {
|
|
9384
|
+
}
|
|
9113
9385
|
}
|
|
9114
|
-
|
|
9115
|
-
|
|
9116
|
-
|
|
9117
|
-
|
|
9118
|
-
|
|
9119
|
-
|
|
9120
|
-
|
|
9121
|
-
|
|
9122
|
-
|
|
9123
|
-
|
|
9124
|
-
|
|
9125
|
-
}
|
|
9126
|
-
|
|
9127
|
-
|
|
9128
|
-
|
|
9129
|
-
|
|
9130
|
-
|
|
9131
|
-
|
|
9132
|
-
|
|
9386
|
+
try {
|
|
9387
|
+
appendSnapshot(USAGE_LOG2, await fetchCodexUsage());
|
|
9388
|
+
saved += 1;
|
|
9389
|
+
} catch (err) {
|
|
9390
|
+
if (!(err instanceof CodexApiError) || err.code !== "no_auth" && err.code !== "api_key_only") {
|
|
9391
|
+
console.warn(`codex usage: ${err.message}`);
|
|
9392
|
+
}
|
|
9393
|
+
}
|
|
9394
|
+
try {
|
|
9395
|
+
appendSnapshot(USAGE_LOG2, await fetchCopilotUsage());
|
|
9396
|
+
saved += 1;
|
|
9397
|
+
} catch (err) {
|
|
9398
|
+
if (!(err instanceof CopilotApiError) || err.code !== "no_cli" && err.code !== "no_auth") {
|
|
9399
|
+
console.warn(`copilot usage: ${err.message}`);
|
|
9400
|
+
}
|
|
9401
|
+
}
|
|
9402
|
+
try {
|
|
9403
|
+
appendSnapshot(USAGE_LOG2, await fetchGrokUsage());
|
|
9404
|
+
saved += 1;
|
|
9405
|
+
} catch (err) {
|
|
9406
|
+
if (!(err instanceof GrokApiError) || err.code !== "no_auth" && err.code !== "not_weekly") {
|
|
9407
|
+
console.warn(`grok usage: ${err.message}`);
|
|
9408
|
+
}
|
|
9409
|
+
}
|
|
9410
|
+
try {
|
|
9411
|
+
appendSnapshot(USAGE_LOG2, await fetchZaiUsage());
|
|
9412
|
+
saved += 1;
|
|
9413
|
+
} catch (err) {
|
|
9414
|
+
if (!(err instanceof ZaiApiError) || err.code !== "no_key") {
|
|
9415
|
+
console.warn(`zai usage: ${err.message}`);
|
|
9416
|
+
}
|
|
9417
|
+
}
|
|
9418
|
+
return saved;
|
|
9133
9419
|
}
|
|
9134
|
-
function
|
|
9135
|
-
const
|
|
9136
|
-
|
|
9137
|
-
|
|
9138
|
-
|
|
9420
|
+
function parseAgentFilter(args2) {
|
|
9421
|
+
const raw = flag(args2, "--agent") ?? flag(args2, "-a");
|
|
9422
|
+
if (!raw) return void 0;
|
|
9423
|
+
const kind = raw.toLowerCase();
|
|
9424
|
+
const aliases = {
|
|
9425
|
+
claude: "claude-code",
|
|
9426
|
+
"claude-code": "claude-code",
|
|
9427
|
+
codex: "codex",
|
|
9428
|
+
copilot: "copilot",
|
|
9429
|
+
zai: "zai",
|
|
9430
|
+
"z.ai": "zai",
|
|
9431
|
+
grok: "grok"
|
|
9432
|
+
};
|
|
9433
|
+
return aliases[kind] ?? kind;
|
|
9139
9434
|
}
|
|
9140
|
-
function
|
|
9141
|
-
|
|
9142
|
-
const
|
|
9143
|
-
return {
|
|
9435
|
+
function filterAgents(byAgent, agentFilter) {
|
|
9436
|
+
if (!agentFilter) return byAgent;
|
|
9437
|
+
const hit = byAgent[agentFilter];
|
|
9438
|
+
return hit ? { [agentFilter]: hit } : {};
|
|
9144
9439
|
}
|
|
9145
|
-
function
|
|
9146
|
-
|
|
9147
|
-
|
|
9148
|
-
|
|
9440
|
+
async function collectSnapshots(opts) {
|
|
9441
|
+
let saved = 0;
|
|
9442
|
+
if (opts.save) {
|
|
9443
|
+
try {
|
|
9444
|
+
const snapshot = await fetchUsage();
|
|
9445
|
+
appendSnapshot(USAGE_LOG2, snapshot);
|
|
9446
|
+
saved += 1;
|
|
9447
|
+
} catch (err) {
|
|
9448
|
+
if (!(err instanceof UsageApiError)) throw err;
|
|
9449
|
+
}
|
|
9450
|
+
saved += await saveAuxiliarySnapshots();
|
|
9451
|
+
}
|
|
9452
|
+
const byAgent = latestSnapshotsByAgent(USAGE_LOG2);
|
|
9453
|
+
if (opts.preferLiveClaude && !opts.save) {
|
|
9454
|
+
try {
|
|
9455
|
+
const live = await fetchUsage();
|
|
9456
|
+
byAgent["claude-code"] = live;
|
|
9457
|
+
} catch {
|
|
9458
|
+
}
|
|
9459
|
+
}
|
|
9460
|
+
return { byAgent, saved };
|
|
9149
9461
|
}
|
|
9150
|
-
function
|
|
9151
|
-
|
|
9152
|
-
|
|
9153
|
-
|
|
9154
|
-
|
|
9155
|
-
|
|
9156
|
-
|
|
9157
|
-
|
|
9158
|
-
|
|
9159
|
-
|
|
9160
|
-
|
|
9161
|
-
|
|
9162
|
-
|
|
9163
|
-
|
|
9462
|
+
async function usage(args2) {
|
|
9463
|
+
if (args2.includes("--help") || args2.includes("-h")) {
|
|
9464
|
+
console.log(`fleetlens usage \u2014 plan utilization (all agents)
|
|
9465
|
+
|
|
9466
|
+
Usage:
|
|
9467
|
+
fleetlens usage [--agent KIND] Multi-agent snapshot (from daemon log + live Claude)
|
|
9468
|
+
fleetlens usage --watch [-a KIND] Live top-style view until Ctrl+C
|
|
9469
|
+
fleetlens usage --save Poll every provider and append to the usage log
|
|
9470
|
+
fleetlens usage --history [-s D] [--days N]
|
|
9471
|
+
Daily token / cost history table
|
|
9472
|
+
|
|
9473
|
+
Agents: claude | codex | copilot | zai | grok (or full ids like claude-code)
|
|
9474
|
+
Watch options:
|
|
9475
|
+
--interval N Redraw every N seconds (default 2; reads ~/.cclens/usage.jsonl)
|
|
9476
|
+
|
|
9477
|
+
Tip: leave the usage daemon running (\`fleetlens daemon start\`) so --watch
|
|
9478
|
+
stays fresh without hammering provider APIs.`);
|
|
9479
|
+
return;
|
|
9480
|
+
}
|
|
9481
|
+
if (args2.includes("--history")) {
|
|
9482
|
+
const { history: history2 } = await Promise.resolve().then(() => (init_usage_history(), usage_history_exports));
|
|
9483
|
+
await history2(args2.filter((a) => a !== "--history"));
|
|
9484
|
+
return;
|
|
9485
|
+
}
|
|
9486
|
+
const save = args2.includes("--save");
|
|
9487
|
+
const watch = args2.includes("--watch") || args2.includes("-w");
|
|
9488
|
+
const agentFilter = parseAgentFilter(args2);
|
|
9489
|
+
if (agentFilter && !isAgentKind(agentFilter)) {
|
|
9490
|
+
console.error(
|
|
9491
|
+
`Error: unknown agent "${agentFilter}". Use claude, codex, copilot, zai, or grok.`
|
|
9492
|
+
);
|
|
9493
|
+
process.exitCode = 1;
|
|
9494
|
+
return;
|
|
9495
|
+
}
|
|
9496
|
+
const intervalRaw = flag(args2, "--interval");
|
|
9497
|
+
const intervalSec = Math.max(1, parseInt(intervalRaw ?? "2", 10) || 2);
|
|
9498
|
+
if (watch) {
|
|
9499
|
+
await runWatch({ agentFilter, intervalSec, saveOnce: save });
|
|
9500
|
+
return;
|
|
9164
9501
|
}
|
|
9165
|
-
const
|
|
9166
|
-
|
|
9167
|
-
|
|
9168
|
-
|
|
9169
|
-
|
|
9170
|
-
|
|
9171
|
-
|
|
9172
|
-
|
|
9173
|
-
|
|
9174
|
-
|
|
9175
|
-
|
|
9176
|
-
|
|
9177
|
-
|
|
9502
|
+
const collected = await collectSnapshots({ save, preferLiveClaude: true });
|
|
9503
|
+
const byAgent = filterAgents(collected.byAgent, agentFilter);
|
|
9504
|
+
if (save && collected.saved === 0 && Object.keys(byAgent).length === 0) {
|
|
9505
|
+
console.error(
|
|
9506
|
+
"Error: could not poll any provider and no samples are on disk."
|
|
9507
|
+
);
|
|
9508
|
+
process.exitCode = 1;
|
|
9509
|
+
return;
|
|
9510
|
+
}
|
|
9511
|
+
if (save && collected.saved === 0) {
|
|
9512
|
+
console.error(
|
|
9513
|
+
"Error: every usage poll failed (showing last samples from disk only)."
|
|
9514
|
+
);
|
|
9515
|
+
process.exitCode = 1;
|
|
9516
|
+
}
|
|
9517
|
+
if (Object.keys(byAgent).length === 0) {
|
|
9518
|
+
if (agentFilter) {
|
|
9519
|
+
console.error(
|
|
9520
|
+
`Error: no usage samples for ${agentFilter}. Run \`fleetlens usage --save\` or start the daemon.`
|
|
9521
|
+
);
|
|
9522
|
+
} else {
|
|
9523
|
+
console.error(
|
|
9524
|
+
"Error: no usage samples yet. Run `fleetlens daemon start` or `fleetlens usage --save`."
|
|
9525
|
+
);
|
|
9178
9526
|
}
|
|
9179
|
-
|
|
9180
|
-
|
|
9181
|
-
|
|
9182
|
-
|
|
9527
|
+
process.exitCode = 1;
|
|
9528
|
+
return;
|
|
9529
|
+
}
|
|
9530
|
+
process.stdout.write(formatMultiAgentUsage(byAgent));
|
|
9531
|
+
if (!save) {
|
|
9532
|
+
process.stdout.write(
|
|
9533
|
+
" (tip: --watch for a live view \xB7 --history for the token table \xB7 --save to poll APIs)\n"
|
|
9534
|
+
);
|
|
9183
9535
|
}
|
|
9184
|
-
return { by_day, peak, peak_day, multi_agent_days, cross_project_days };
|
|
9185
9536
|
}
|
|
9186
|
-
|
|
9187
|
-
|
|
9537
|
+
async function runWatch(opts) {
|
|
9538
|
+
if (opts.saveOnce) {
|
|
9539
|
+
const { saved } = await collectSnapshots({ save: true, preferLiveClaude: false });
|
|
9540
|
+
if (saved === 0 && Object.keys(latestSnapshotsByAgent(USAGE_LOG2)).length === 0) {
|
|
9541
|
+
console.error(
|
|
9542
|
+
"Error: could not poll any provider and no samples are on disk."
|
|
9543
|
+
);
|
|
9544
|
+
process.exitCode = 1;
|
|
9545
|
+
return;
|
|
9546
|
+
}
|
|
9547
|
+
}
|
|
9548
|
+
let stopping = false;
|
|
9549
|
+
const stop2 = () => {
|
|
9550
|
+
if (stopping) return;
|
|
9551
|
+
stopping = true;
|
|
9552
|
+
process.stdout.write("\x1B[?25h");
|
|
9553
|
+
process.stdout.write("\n");
|
|
9554
|
+
process.exit(0);
|
|
9555
|
+
};
|
|
9556
|
+
process.on("SIGINT", stop2);
|
|
9557
|
+
process.on("SIGTERM", stop2);
|
|
9558
|
+
if (process.stdout.isTTY) process.stdout.write("\x1B[?25l");
|
|
9559
|
+
const draw = () => {
|
|
9560
|
+
if (stopping) return;
|
|
9561
|
+
const byAgent = filterAgents(latestSnapshotsByAgent(USAGE_LOG2), opts.agentFilter);
|
|
9562
|
+
if (process.stdout.isTTY) {
|
|
9563
|
+
process.stdout.write("\x1B[2J\x1B[H");
|
|
9564
|
+
}
|
|
9565
|
+
if (Object.keys(byAgent).length === 0) {
|
|
9566
|
+
process.stdout.write(
|
|
9567
|
+
`
|
|
9568
|
+
${opts.agentFilter ? `No samples for ${opts.agentFilter}` : "Waiting for usage samples\u2026"}
|
|
9569
|
+
${" ".repeat(0)}Start the daemon: fleetlens daemon start
|
|
9570
|
+
|
|
9571
|
+
live \xB7 every ${opts.intervalSec}s \xB7 Ctrl+C to quit
|
|
9572
|
+
`
|
|
9573
|
+
);
|
|
9574
|
+
return;
|
|
9575
|
+
}
|
|
9576
|
+
process.stdout.write(
|
|
9577
|
+
formatMultiAgentUsage(byAgent, {
|
|
9578
|
+
watch: true,
|
|
9579
|
+
intervalSec: opts.intervalSec
|
|
9580
|
+
})
|
|
9581
|
+
);
|
|
9582
|
+
};
|
|
9583
|
+
draw();
|
|
9584
|
+
const timer = setInterval(draw, opts.intervalSec * 1e3);
|
|
9585
|
+
await new Promise(() => {
|
|
9586
|
+
void timer;
|
|
9587
|
+
});
|
|
9588
|
+
}
|
|
9589
|
+
var USAGE_LOG2;
|
|
9590
|
+
var init_usage = __esm({
|
|
9591
|
+
"src/commands/usage.ts"() {
|
|
9188
9592
|
"use strict";
|
|
9189
|
-
|
|
9593
|
+
init_dist();
|
|
9594
|
+
init_fs();
|
|
9595
|
+
init_args();
|
|
9596
|
+
init_api();
|
|
9597
|
+
init_grok2();
|
|
9598
|
+
init_codex2();
|
|
9599
|
+
init_copilot2();
|
|
9600
|
+
init_zai();
|
|
9601
|
+
init_format();
|
|
9602
|
+
init_storage();
|
|
9603
|
+
USAGE_LOG2 = cclensPath("usage.jsonl");
|
|
9190
9604
|
}
|
|
9191
9605
|
});
|
|
9192
9606
|
|
|
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"() {
|
|
9607
|
+
// ../entries/dist/types.js
|
|
9608
|
+
function pendingEnrichment() {
|
|
9609
|
+
return {
|
|
9610
|
+
status: "pending",
|
|
9611
|
+
generated_at: null,
|
|
9612
|
+
model: null,
|
|
9613
|
+
cost_usd: null,
|
|
9614
|
+
error: null,
|
|
9615
|
+
brief_summary: null,
|
|
9616
|
+
underlying_goal: null,
|
|
9617
|
+
friction_detail: null,
|
|
9618
|
+
user_instructions: [],
|
|
9619
|
+
outcome: null,
|
|
9620
|
+
claude_helpfulness: null,
|
|
9621
|
+
goal_categories: {},
|
|
9622
|
+
retry_count: 0
|
|
9623
|
+
};
|
|
9624
|
+
}
|
|
9625
|
+
function skippedTrivialEnrichment(generatedAt) {
|
|
9626
|
+
return {
|
|
9627
|
+
status: "skipped_trivial",
|
|
9628
|
+
generated_at: generatedAt,
|
|
9629
|
+
model: null,
|
|
9630
|
+
cost_usd: null,
|
|
9631
|
+
error: null,
|
|
9632
|
+
brief_summary: null,
|
|
9633
|
+
underlying_goal: null,
|
|
9634
|
+
friction_detail: null,
|
|
9635
|
+
user_instructions: [],
|
|
9636
|
+
outcome: "trivial",
|
|
9637
|
+
claude_helpfulness: null,
|
|
9638
|
+
goal_categories: {},
|
|
9639
|
+
retry_count: 0
|
|
9640
|
+
};
|
|
9641
|
+
}
|
|
9642
|
+
function entryKey(sessionId, localDay2) {
|
|
9643
|
+
return `${sessionId}__${localDay2}`;
|
|
9644
|
+
}
|
|
9645
|
+
function parseEntryKey(key) {
|
|
9646
|
+
const m = /^([^_]+(?:_[^_]+)*)__(\d{4}-\d{2}-\d{2})$/.exec(key);
|
|
9647
|
+
if (!m)
|
|
9648
|
+
return null;
|
|
9649
|
+
return { session_id: m[1], local_day: m[2] };
|
|
9650
|
+
}
|
|
9651
|
+
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;
|
|
9652
|
+
var init_types2 = __esm({
|
|
9653
|
+
"../entries/dist/types.js"() {
|
|
9256
9654
|
"use strict";
|
|
9257
|
-
|
|
9258
|
-
|
|
9259
|
-
|
|
9260
|
-
|
|
9261
|
-
|
|
9262
|
-
|
|
9263
|
-
|
|
9264
|
-
|
|
9265
|
-
|
|
9655
|
+
CURRENT_ENTRY_SCHEMA_VERSION = 2;
|
|
9656
|
+
GOAL_CATEGORIES = [
|
|
9657
|
+
"build",
|
|
9658
|
+
"plan",
|
|
9659
|
+
"debug",
|
|
9660
|
+
"review",
|
|
9661
|
+
"steer",
|
|
9662
|
+
"meta",
|
|
9663
|
+
"research",
|
|
9664
|
+
"refactor",
|
|
9665
|
+
"test",
|
|
9666
|
+
"release",
|
|
9667
|
+
"warmup_minimal"
|
|
9668
|
+
];
|
|
9669
|
+
CURRENT_DAY_DIGEST_SCHEMA_VERSION = 2;
|
|
9670
|
+
CURRENT_WEEK_DIGEST_SCHEMA_VERSION = 2;
|
|
9671
|
+
CURRENT_MONTH_DIGEST_SCHEMA_VERSION = 2;
|
|
9672
|
+
PROMPT_FRAME_ORIGIN = {
|
|
9673
|
+
teammate: "claude-feature",
|
|
9674
|
+
"task-notification": "claude-feature",
|
|
9675
|
+
"local-command-caveat": "claude-feature",
|
|
9676
|
+
"image-attached": "claude-feature",
|
|
9677
|
+
"slash-command": "claude-feature",
|
|
9678
|
+
"handoff-prose": "personal-habit"
|
|
9679
|
+
};
|
|
9266
9680
|
}
|
|
9267
9681
|
});
|
|
9268
9682
|
|
|
@@ -10004,7 +10418,7 @@ var init_build = __esm({
|
|
|
10004
10418
|
"../entries/dist/build.js"() {
|
|
10005
10419
|
"use strict";
|
|
10006
10420
|
init_analytics();
|
|
10007
|
-
|
|
10421
|
+
init_types2();
|
|
10008
10422
|
init_signals();
|
|
10009
10423
|
init_trivial();
|
|
10010
10424
|
IDLE_GAP_MS6 = 3 * 60 * 1e3;
|
|
@@ -10027,7 +10441,7 @@ var init_flag_glossary = __esm({
|
|
|
10027
10441
|
var init_dist2 = __esm({
|
|
10028
10442
|
"../entries/dist/index.js"() {
|
|
10029
10443
|
"use strict";
|
|
10030
|
-
|
|
10444
|
+
init_types2();
|
|
10031
10445
|
init_signals();
|
|
10032
10446
|
init_trivial();
|
|
10033
10447
|
init_build();
|
|
@@ -10036,11 +10450,11 @@ var init_dist2 = __esm({
|
|
|
10036
10450
|
});
|
|
10037
10451
|
|
|
10038
10452
|
// ../entries/dist/digest-fs.js
|
|
10039
|
-
import { readFileSync as
|
|
10453
|
+
import { readFileSync as readFileSync14, readdirSync, writeFileSync as writeFileSync7, renameSync as renameSync2, chmodSync, mkdirSync as mkdirSync6, existsSync as existsSync12 } from "node:fs";
|
|
10040
10454
|
import { dirname as dirname9, join as join9 } from "node:path";
|
|
10041
10455
|
function parseDigestFile(path11, expectedVersion) {
|
|
10042
10456
|
try {
|
|
10043
|
-
const parsed = JSON.parse(
|
|
10457
|
+
const parsed = JSON.parse(readFileSync14(path11, "utf8"));
|
|
10044
10458
|
if (!parsed || typeof parsed !== "object")
|
|
10045
10459
|
return null;
|
|
10046
10460
|
if (parsed.version !== expectedVersion)
|
|
@@ -10089,7 +10503,7 @@ function writeDayDigest(digest2) {
|
|
|
10089
10503
|
}
|
|
10090
10504
|
function readDayDigest(date) {
|
|
10091
10505
|
const p = dayDigestPath(date);
|
|
10092
|
-
if (!
|
|
10506
|
+
if (!existsSync12(p))
|
|
10093
10507
|
return null;
|
|
10094
10508
|
return parseDigestFile(p, CURRENT_DAY_DIGEST_SCHEMA_VERSION);
|
|
10095
10509
|
}
|
|
@@ -10125,13 +10539,13 @@ function writeWeekDigest(digest2) {
|
|
|
10125
10539
|
}
|
|
10126
10540
|
function readWeekDigest(monday) {
|
|
10127
10541
|
const p = weekDigestPath(monday);
|
|
10128
|
-
if (!
|
|
10542
|
+
if (!existsSync12(p))
|
|
10129
10543
|
return null;
|
|
10130
10544
|
return parseDigestFile(p, CURRENT_WEEK_DIGEST_SCHEMA_VERSION);
|
|
10131
10545
|
}
|
|
10132
10546
|
function listWeekDigestKeys() {
|
|
10133
10547
|
const dir = join9(digestsDir(), "week");
|
|
10134
|
-
if (!
|
|
10548
|
+
if (!existsSync12(dir))
|
|
10135
10549
|
return [];
|
|
10136
10550
|
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
10551
|
}
|
|
@@ -10162,13 +10576,13 @@ function writeMonthDigest(digest2) {
|
|
|
10162
10576
|
}
|
|
10163
10577
|
function readMonthDigest(yearMonth) {
|
|
10164
10578
|
const p = monthDigestPath(yearMonth);
|
|
10165
|
-
if (!
|
|
10579
|
+
if (!existsSync12(p))
|
|
10166
10580
|
return null;
|
|
10167
10581
|
return parseDigestFile(p, CURRENT_MONTH_DIGEST_SCHEMA_VERSION);
|
|
10168
10582
|
}
|
|
10169
10583
|
function listMonthDigestKeys() {
|
|
10170
10584
|
const dir = join9(digestsDir(), "month");
|
|
10171
|
-
if (!
|
|
10585
|
+
if (!existsSync12(dir))
|
|
10172
10586
|
return [];
|
|
10173
10587
|
return readdirSync(dir).filter((f) => f.endsWith(".json")).map((f) => f.slice(0, -".json".length)).filter((k) => /^\d{4}-\d{2}$/.test(k));
|
|
10174
10588
|
}
|
|
@@ -10189,7 +10603,7 @@ var init_digest_fs = __esm({
|
|
|
10189
10603
|
"../entries/dist/digest-fs.js"() {
|
|
10190
10604
|
"use strict";
|
|
10191
10605
|
init_fs();
|
|
10192
|
-
|
|
10606
|
+
init_types2();
|
|
10193
10607
|
digestsDirCached = null;
|
|
10194
10608
|
TODAY_TTL_MS = 10 * 60 * 1e3;
|
|
10195
10609
|
todayCache = null;
|
|
@@ -10230,7 +10644,7 @@ __export(fs_exports2, {
|
|
|
10230
10644
|
writeMonthDigest: () => writeMonthDigest,
|
|
10231
10645
|
writeWeekDigest: () => writeWeekDigest
|
|
10232
10646
|
});
|
|
10233
|
-
import { readFileSync as
|
|
10647
|
+
import { readFileSync as readFileSync15, readdirSync as readdirSync2, writeFileSync as writeFileSync8, mkdirSync as mkdirSync7, renameSync as renameSync3, existsSync as existsSync13 } from "node:fs";
|
|
10234
10648
|
import { randomBytes } from "node:crypto";
|
|
10235
10649
|
import { join as join10 } from "node:path";
|
|
10236
10650
|
function entriesDir() {
|
|
@@ -10289,17 +10703,17 @@ function writeEntryPreservingEnrichment(fresh) {
|
|
|
10289
10703
|
}
|
|
10290
10704
|
function readEntry(sessionId, localDay2) {
|
|
10291
10705
|
const p = pathFor(sessionId, localDay2);
|
|
10292
|
-
if (!
|
|
10706
|
+
if (!existsSync13(p))
|
|
10293
10707
|
return null;
|
|
10294
|
-
const raw =
|
|
10708
|
+
const raw = readFileSync15(p, "utf8");
|
|
10295
10709
|
return JSON.parse(raw);
|
|
10296
10710
|
}
|
|
10297
10711
|
function entryExists(sessionId, localDay2) {
|
|
10298
|
-
return
|
|
10712
|
+
return existsSync13(pathFor(sessionId, localDay2));
|
|
10299
10713
|
}
|
|
10300
10714
|
function listEntryKeys() {
|
|
10301
10715
|
const dir = entriesDir();
|
|
10302
|
-
if (!
|
|
10716
|
+
if (!existsSync13(dir))
|
|
10303
10717
|
return [];
|
|
10304
10718
|
return readdirSync2(dir).filter((f) => f.endsWith(".json")).map((f) => f.slice(0, -".json".length));
|
|
10305
10719
|
}
|
|
@@ -10348,7 +10762,7 @@ var init_fs2 = __esm({
|
|
|
10348
10762
|
"../entries/dist/fs.js"() {
|
|
10349
10763
|
"use strict";
|
|
10350
10764
|
init_fs();
|
|
10351
|
-
|
|
10765
|
+
init_types2();
|
|
10352
10766
|
init_digest_fs();
|
|
10353
10767
|
entriesDirCached = null;
|
|
10354
10768
|
PRESERVABLE_STATUSES = /* @__PURE__ */ new Set([
|
|
@@ -10358,17 +10772,6 @@ var init_fs2 = __esm({
|
|
|
10358
10772
|
}
|
|
10359
10773
|
});
|
|
10360
10774
|
|
|
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
10775
|
// ../../node_modules/zod/v3/helpers/util.js
|
|
10373
10776
|
var util, objectUtil, ZodParsedType, getParsedType;
|
|
10374
10777
|
var init_util = __esm({
|
|
@@ -14514,7 +14917,7 @@ var init_enrich = __esm({
|
|
|
14514
14917
|
"../entries/dist/prompts/enrich.js"() {
|
|
14515
14918
|
"use strict";
|
|
14516
14919
|
init_zod();
|
|
14517
|
-
|
|
14920
|
+
init_types2();
|
|
14518
14921
|
GoalCategoryEnum = external_exports.enum(GOAL_CATEGORIES);
|
|
14519
14922
|
OutcomeEnum = external_exports.enum(["shipped", "partial", "exploratory", "blocked", "trivial"]);
|
|
14520
14923
|
HelpfulnessEnum = external_exports.enum(["essential", "helpful", "neutral", "unhelpful"]);
|
|
@@ -14578,14 +14981,14 @@ RESPOND WITH ONLY VALID JSON (no prose, no code fence):
|
|
|
14578
14981
|
});
|
|
14579
14982
|
|
|
14580
14983
|
// ../entries/dist/claude-bin.js
|
|
14581
|
-
import { existsSync as
|
|
14984
|
+
import { existsSync as existsSync14 } from "node:fs";
|
|
14582
14985
|
import { join as join11, dirname as dirname10, delimiter } from "node:path";
|
|
14583
14986
|
import { homedir as homedir5 } from "node:os";
|
|
14584
14987
|
function resolveClaudeBin(opts = {}) {
|
|
14585
14988
|
const env = opts.env ?? process.env;
|
|
14586
14989
|
const home = opts.home ?? homedir5();
|
|
14587
14990
|
const execPath = opts.execPath ?? process.execPath;
|
|
14588
|
-
const exists = opts.exists ??
|
|
14991
|
+
const exists = opts.exists ?? existsSync14;
|
|
14589
14992
|
for (const dir of (env.PATH ?? "").split(delimiter)) {
|
|
14590
14993
|
if (!dir)
|
|
14591
14994
|
continue;
|
|
@@ -14626,7 +15029,7 @@ var init_claude_bin = __esm({
|
|
|
14626
15029
|
});
|
|
14627
15030
|
|
|
14628
15031
|
// ../entries/dist/tmux-runner.js
|
|
14629
|
-
import { mkdirSync as mkdirSync8, writeFileSync as writeFileSync9, existsSync as
|
|
15032
|
+
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
15033
|
import { join as join12 } from "node:path";
|
|
14631
15034
|
import { homedir as homedir6 } from "node:os";
|
|
14632
15035
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
@@ -14645,7 +15048,7 @@ function tmuxRunnerAvailable() {
|
|
|
14645
15048
|
}
|
|
14646
15049
|
function runtimeCwd() {
|
|
14647
15050
|
const dir = join12(homedir6(), ".cclens", "runtime");
|
|
14648
|
-
if (!
|
|
15051
|
+
if (!existsSync15(dir))
|
|
14649
15052
|
mkdirSync8(dir, { recursive: true });
|
|
14650
15053
|
return realpathSync5(dir);
|
|
14651
15054
|
}
|
|
@@ -14653,7 +15056,7 @@ function ensureRuntimeCwdTrusted(cwd) {
|
|
|
14653
15056
|
const cfgPath = join12(homedir6(), ".claude.json");
|
|
14654
15057
|
let cfg;
|
|
14655
15058
|
try {
|
|
14656
|
-
cfg = JSON.parse(
|
|
15059
|
+
cfg = JSON.parse(readFileSync16(cfgPath, "utf8"));
|
|
14657
15060
|
} catch {
|
|
14658
15061
|
return;
|
|
14659
15062
|
}
|
|
@@ -14803,7 +15206,7 @@ function snapshotAllTranscripts() {
|
|
|
14803
15206
|
function readJsonlCwd(path11, maxLines = 8) {
|
|
14804
15207
|
let raw;
|
|
14805
15208
|
try {
|
|
14806
|
-
raw =
|
|
15209
|
+
raw = readFileSync16(path11, "utf8");
|
|
14807
15210
|
} catch {
|
|
14808
15211
|
return void 0;
|
|
14809
15212
|
}
|
|
@@ -14860,7 +15263,7 @@ async function discoverTranscript(targetCwd, existingBefore, startMs, timeoutMs,
|
|
|
14860
15263
|
function parseTranscript2(path11, defaultModel) {
|
|
14861
15264
|
let raw;
|
|
14862
15265
|
try {
|
|
14863
|
-
raw =
|
|
15266
|
+
raw = readFileSync16(path11, "utf8");
|
|
14864
15267
|
} catch {
|
|
14865
15268
|
return { assembled: "", inputTokens: 0, outputTokens: 0, modelUsed: defaultModel, done: false };
|
|
14866
15269
|
}
|
|
@@ -14955,11 +15358,11 @@ var init_tmux_runner = __esm({
|
|
|
14955
15358
|
|
|
14956
15359
|
// ../entries/dist/llm-runner.js
|
|
14957
15360
|
import { spawn as spawn4 } from "node:child_process";
|
|
14958
|
-
import { mkdirSync as mkdirSync9, appendFileSync as appendFileSync3, writeFileSync as writeFileSync10, existsSync as
|
|
15361
|
+
import { mkdirSync as mkdirSync9, appendFileSync as appendFileSync3, writeFileSync as writeFileSync10, existsSync as existsSync16 } from "node:fs";
|
|
14959
15362
|
import { join as join13 } from "node:path";
|
|
14960
15363
|
import { randomUUID } from "node:crypto";
|
|
14961
15364
|
function ensureRunsDir() {
|
|
14962
|
-
if (!
|
|
15365
|
+
if (!existsSync16(RUNS_DIR)) {
|
|
14963
15366
|
try {
|
|
14964
15367
|
mkdirSync9(RUNS_DIR, { recursive: true });
|
|
14965
15368
|
} catch {
|
|
@@ -15412,7 +15815,7 @@ var init_enrich2 = __esm({
|
|
|
15412
15815
|
});
|
|
15413
15816
|
|
|
15414
15817
|
// ../entries/dist/budget.js
|
|
15415
|
-
import { appendFileSync as appendFileSync4, readFileSync as
|
|
15818
|
+
import { appendFileSync as appendFileSync4, readFileSync as readFileSync17, existsSync as existsSync17, mkdirSync as mkdirSync10 } from "node:fs";
|
|
15416
15819
|
import { dirname as dirname11 } from "node:path";
|
|
15417
15820
|
function spendPath() {
|
|
15418
15821
|
if (spendPathCached)
|
|
@@ -15430,12 +15833,12 @@ function appendSpend(record) {
|
|
|
15430
15833
|
}
|
|
15431
15834
|
function monthToDateSpend(now = /* @__PURE__ */ new Date()) {
|
|
15432
15835
|
const p = spendPath();
|
|
15433
|
-
if (!
|
|
15836
|
+
if (!existsSync17(p))
|
|
15434
15837
|
return 0;
|
|
15435
15838
|
const year = now.getUTCFullYear();
|
|
15436
15839
|
const month2 = now.getUTCMonth();
|
|
15437
15840
|
let total = 0;
|
|
15438
|
-
const raw =
|
|
15841
|
+
const raw = readFileSync17(p, "utf8");
|
|
15439
15842
|
for (const line of raw.split("\n")) {
|
|
15440
15843
|
if (!line)
|
|
15441
15844
|
continue;
|
|
@@ -15464,7 +15867,7 @@ var init_budget = __esm({
|
|
|
15464
15867
|
});
|
|
15465
15868
|
|
|
15466
15869
|
// ../entries/dist/pipeline-lock.js
|
|
15467
|
-
import { writeFileSync as writeFileSync11, unlinkSync as unlinkSync4, existsSync as
|
|
15870
|
+
import { writeFileSync as writeFileSync11, unlinkSync as unlinkSync4, existsSync as existsSync18, readFileSync as readFileSync18, statSync as statSync3 } from "node:fs";
|
|
15468
15871
|
function lockPath() {
|
|
15469
15872
|
if (lockPathCached)
|
|
15470
15873
|
return lockPathCached;
|
|
@@ -15509,13 +15912,13 @@ function pidAlive(pid) {
|
|
|
15509
15912
|
}
|
|
15510
15913
|
function interactiveLockFresh(nowMs) {
|
|
15511
15914
|
const p = lockPath();
|
|
15512
|
-
if (!
|
|
15915
|
+
if (!existsSync18(p))
|
|
15513
15916
|
return false;
|
|
15514
15917
|
try {
|
|
15515
15918
|
const mtime = statSync3(p).mtimeMs;
|
|
15516
15919
|
if (nowMs - mtime > STALE_MS)
|
|
15517
15920
|
return false;
|
|
15518
|
-
const pid = Number(
|
|
15921
|
+
const pid = Number(readFileSync18(p, "utf8").trim());
|
|
15519
15922
|
if (!Number.isFinite(pid) || pid <= 0)
|
|
15520
15923
|
return false;
|
|
15521
15924
|
if (!pidAlive(pid))
|
|
@@ -15621,7 +16024,7 @@ var init_queue = __esm({
|
|
|
15621
16024
|
});
|
|
15622
16025
|
|
|
15623
16026
|
// ../entries/dist/settings.js
|
|
15624
|
-
import { readFileSync as
|
|
16027
|
+
import { readFileSync as readFileSync19, writeFileSync as writeFileSync12, renameSync as renameSync5, chmodSync as chmodSync2, mkdirSync as mkdirSync11, existsSync as existsSync19 } from "node:fs";
|
|
15625
16028
|
import { dirname as dirname12 } from "node:path";
|
|
15626
16029
|
function settingsPath() {
|
|
15627
16030
|
if (settingsPathCached)
|
|
@@ -15657,10 +16060,10 @@ function fromDisk(d) {
|
|
|
15657
16060
|
}
|
|
15658
16061
|
function readSettings() {
|
|
15659
16062
|
const p = settingsPath();
|
|
15660
|
-
if (!
|
|
16063
|
+
if (!existsSync19(p))
|
|
15661
16064
|
return DEFAULT_SETTINGS;
|
|
15662
16065
|
try {
|
|
15663
|
-
const raw =
|
|
16066
|
+
const raw = readFileSync19(p, "utf8");
|
|
15664
16067
|
return fromDisk(JSON.parse(raw));
|
|
15665
16068
|
} catch {
|
|
15666
16069
|
return DEFAULT_SETTINGS;
|
|
@@ -16145,7 +16548,7 @@ var DEFAULT_MODEL2, defaultCallLLMDigest, validateDay;
|
|
|
16145
16548
|
var init_digest_day2 = __esm({
|
|
16146
16549
|
"../entries/dist/digest-day.js"() {
|
|
16147
16550
|
"use strict";
|
|
16148
|
-
|
|
16551
|
+
init_types2();
|
|
16149
16552
|
init_signals();
|
|
16150
16553
|
init_digest_day();
|
|
16151
16554
|
init_enrich2();
|
|
@@ -17364,7 +17767,7 @@ var SHAPE_ORDER, DEFAULT_MODEL3, defaultCallLLMWeek, validateWeek;
|
|
|
17364
17767
|
var init_digest_week2 = __esm({
|
|
17365
17768
|
"../entries/dist/digest-week.js"() {
|
|
17366
17769
|
"use strict";
|
|
17367
|
-
|
|
17770
|
+
init_types2();
|
|
17368
17771
|
init_signals();
|
|
17369
17772
|
init_digest_day2();
|
|
17370
17773
|
init_digest_week();
|
|
@@ -17698,7 +18101,7 @@ var DEFAULT_MODEL4, defaultCallLLMMonth, validateMonth;
|
|
|
17698
18101
|
var init_digest_month2 = __esm({
|
|
17699
18102
|
"../entries/dist/digest-month.js"() {
|
|
17700
18103
|
"use strict";
|
|
17701
|
-
|
|
18104
|
+
init_types2();
|
|
17702
18105
|
init_digest_month();
|
|
17703
18106
|
init_enrich2();
|
|
17704
18107
|
init_llm_runner();
|
|
@@ -18850,13 +19253,13 @@ var init_digest_month_pipeline = __esm({
|
|
|
18850
19253
|
});
|
|
18851
19254
|
|
|
18852
19255
|
// ../entries/dist/credentials.js
|
|
18853
|
-
import { writeFileSync as writeFileSync13, readFileSync as
|
|
19256
|
+
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
19257
|
import { dirname as dirname13 } from "node:path";
|
|
18855
|
-
async function
|
|
19258
|
+
async function fetchZaiUsage2(candidate) {
|
|
18856
19259
|
const key = candidate.trim();
|
|
18857
19260
|
if (!key)
|
|
18858
19261
|
throw new Error("empty key");
|
|
18859
|
-
const res = await fetch(
|
|
19262
|
+
const res = await fetch(ZAI_QUOTA_ENDPOINT2, {
|
|
18860
19263
|
headers: { Authorization: key, "Accept-Language": "en-US,en" }
|
|
18861
19264
|
});
|
|
18862
19265
|
if (!res.ok) {
|
|
@@ -18908,7 +19311,7 @@ async function fetchZaiUsage(candidate) {
|
|
|
18908
19311
|
};
|
|
18909
19312
|
}
|
|
18910
19313
|
async function validateAndSnapshotZaiKey(key) {
|
|
18911
|
-
const snap = await
|
|
19314
|
+
const snap = await fetchZaiUsage2(key);
|
|
18912
19315
|
appendUsageSnapshot(snap);
|
|
18913
19316
|
return snap;
|
|
18914
19317
|
}
|
|
@@ -18921,10 +19324,10 @@ function credentialsPath() {
|
|
|
18921
19324
|
}
|
|
18922
19325
|
function readCredentials() {
|
|
18923
19326
|
const p = credentialsPath();
|
|
18924
|
-
if (!
|
|
19327
|
+
if (!existsSync20(p))
|
|
18925
19328
|
return {};
|
|
18926
19329
|
try {
|
|
18927
|
-
const raw =
|
|
19330
|
+
const raw = readFileSync20(p, "utf8");
|
|
18928
19331
|
return JSON.parse(raw);
|
|
18929
19332
|
} catch {
|
|
18930
19333
|
return {};
|
|
@@ -18976,12 +19379,12 @@ function deleteZaiKey() {
|
|
|
18976
19379
|
function hasZaiKey() {
|
|
18977
19380
|
return !!readCredentials().zai?.apiKey;
|
|
18978
19381
|
}
|
|
18979
|
-
var
|
|
19382
|
+
var ZAI_QUOTA_ENDPOINT2;
|
|
18980
19383
|
var init_credentials = __esm({
|
|
18981
19384
|
"../entries/dist/credentials.js"() {
|
|
18982
19385
|
"use strict";
|
|
18983
19386
|
init_fs();
|
|
18984
|
-
|
|
19387
|
+
ZAI_QUOTA_ENDPOINT2 = "https://api.z.ai/api/monitor/usage/quota/limit";
|
|
18985
19388
|
}
|
|
18986
19389
|
});
|
|
18987
19390
|
|
|
@@ -19020,7 +19423,7 @@ __export(node_exports, {
|
|
|
19020
19423
|
deleteZaiKey: () => deleteZaiKey,
|
|
19021
19424
|
deleteZaiKeyAndPrune: () => deleteZaiKeyAndPrune,
|
|
19022
19425
|
enrichEntry: () => enrichEntry,
|
|
19023
|
-
fetchZaiUsage: () =>
|
|
19426
|
+
fetchZaiUsage: () => fetchZaiUsage2,
|
|
19024
19427
|
generateDayDigest: () => generateDayDigest,
|
|
19025
19428
|
generateMonthDigest: () => generateMonthDigest,
|
|
19026
19429
|
generateWeekDigest: () => generateWeekDigest,
|
|
@@ -19558,7 +19961,7 @@ var menubar_exports = {};
|
|
|
19558
19961
|
__export(menubar_exports, {
|
|
19559
19962
|
menubar: () => menubar
|
|
19560
19963
|
});
|
|
19561
|
-
import { existsSync as
|
|
19964
|
+
import { existsSync as existsSync21, mkdirSync as mkdirSync13, cpSync, rmSync as rmSync2, readdirSync as readdirSync4, writeFileSync as writeFileSync14, realpathSync as realpathSync6 } from "node:fs";
|
|
19562
19965
|
import { homedir as homedir7 } from "node:os";
|
|
19563
19966
|
import { join as join14, dirname as dirname14 } from "node:path";
|
|
19564
19967
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
@@ -19632,7 +20035,7 @@ async function installMenubar(opts) {
|
|
|
19632
20035
|
return;
|
|
19633
20036
|
}
|
|
19634
20037
|
const src = bundledAppPath();
|
|
19635
|
-
if (!
|
|
20038
|
+
if (!existsSync21(src)) {
|
|
19636
20039
|
console.error(
|
|
19637
20040
|
`Bundled widget not found at ${src}.
|
|
19638
20041
|
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 +20081,7 @@ async function uninstallMenubar() {
|
|
|
19678
20081
|
await new Promise((r) => setTimeout(r, 300));
|
|
19679
20082
|
}
|
|
19680
20083
|
const dest = installedAppPath();
|
|
19681
|
-
if (
|
|
20084
|
+
if (existsSync21(dest)) {
|
|
19682
20085
|
rmSync2(dest, { recursive: true, force: true });
|
|
19683
20086
|
console.log(`Removed ${dest}`);
|
|
19684
20087
|
} else {
|
|
@@ -19693,7 +20096,7 @@ async function openMenubar() {
|
|
|
19693
20096
|
return;
|
|
19694
20097
|
}
|
|
19695
20098
|
const dest = installedAppPath();
|
|
19696
|
-
if (!
|
|
20099
|
+
if (!existsSync21(dest)) {
|
|
19697
20100
|
console.log("Widget not installed yet. Run `fleetlens menubar install` first.");
|
|
19698
20101
|
return;
|
|
19699
20102
|
}
|
|
@@ -19710,9 +20113,9 @@ async function statusMenubar() {
|
|
|
19710
20113
|
return;
|
|
19711
20114
|
}
|
|
19712
20115
|
const dest = installedAppPath();
|
|
19713
|
-
const installed =
|
|
20116
|
+
const installed = existsSync21(dest);
|
|
19714
20117
|
const running = await isRunning();
|
|
19715
|
-
const bundled =
|
|
20118
|
+
const bundled = existsSync21(bundledAppPath());
|
|
19716
20119
|
console.log(`Menu bar widget: ${installed ? "installed" : "not installed"}${installed ? ` (${dest})` : ""}`);
|
|
19717
20120
|
console.log(`Running: ${running ? "yes" : "no"}`);
|
|
19718
20121
|
console.log(`Bundled in CLI: ${bundled ? "yes" : "no \u2014 this build ships without the widget"}`);
|
|
@@ -19803,7 +20206,7 @@ var init_config = __esm({
|
|
|
19803
20206
|
});
|
|
19804
20207
|
|
|
19805
20208
|
// src/perception/build-entries.ts
|
|
19806
|
-
import { statSync as statSync4, readFileSync as
|
|
20209
|
+
import { statSync as statSync4, readFileSync as readFileSync21 } from "node:fs";
|
|
19807
20210
|
import { basename as basename2, dirname as dirname15 } from "node:path";
|
|
19808
20211
|
function decodeProjectDirName(projectDir) {
|
|
19809
20212
|
if (projectDir.startsWith("-")) {
|
|
@@ -19813,7 +20216,7 @@ function decodeProjectDirName(projectDir) {
|
|
|
19813
20216
|
}
|
|
19814
20217
|
function buildEntriesForFile(filePath) {
|
|
19815
20218
|
const stat = statSync4(filePath);
|
|
19816
|
-
const raw =
|
|
20219
|
+
const raw = readFileSync21(filePath, "utf8");
|
|
19817
20220
|
const rawLines = raw.split("\n").filter(Boolean).map((l) => {
|
|
19818
20221
|
try {
|
|
19819
20222
|
return JSON.parse(l);
|
|
@@ -20082,7 +20485,7 @@ function buildIngestPayload(inputs) {
|
|
|
20082
20485
|
return {
|
|
20083
20486
|
ingestId: randomUUID2(),
|
|
20084
20487
|
observedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
20085
|
-
cliVersion: "1.0.
|
|
20488
|
+
cliVersion: "1.0.8",
|
|
20086
20489
|
...richRollup || inputs.enrichedExtras || inputs.artifactSignals ? { schemaVersion: RICH_ROLLUP_SCHEMA_VERSION } : {},
|
|
20087
20490
|
...inputs.rollup ? { dailyRollup: inputs.rollup } : {},
|
|
20088
20491
|
...richRollup ? { richRollup } : {},
|
|
@@ -20124,7 +20527,7 @@ var init_push = __esm({
|
|
|
20124
20527
|
});
|
|
20125
20528
|
|
|
20126
20529
|
// src/team/git-remote.ts
|
|
20127
|
-
import { existsSync as
|
|
20530
|
+
import { existsSync as existsSync22, readFileSync as readFileSync22, statSync as statSync5 } from "node:fs";
|
|
20128
20531
|
import { dirname as dirname16, isAbsolute as isAbsolute2, join as join15, resolve as resolve2 } from "node:path";
|
|
20129
20532
|
function parseGithubRemote(url) {
|
|
20130
20533
|
const m = url.trim().match(GITHUB_URL_RE);
|
|
@@ -20149,12 +20552,12 @@ function gitConfigPathFor(dir) {
|
|
|
20149
20552
|
const st = statSync5(dotGit, { throwIfNoEntry: false });
|
|
20150
20553
|
if (!st) return null;
|
|
20151
20554
|
if (st.isDirectory()) return join15(dotGit, "config");
|
|
20152
|
-
const m =
|
|
20555
|
+
const m = readFileSync22(dotGit, "utf8").match(/^gitdir:\s*(.+)\s*$/m);
|
|
20153
20556
|
if (!m) return null;
|
|
20154
20557
|
const gd = isAbsolute2(m[1]) ? m[1] : resolve2(dir, m[1]);
|
|
20155
20558
|
const commondirFile = join15(gd, "commondir");
|
|
20156
|
-
if (
|
|
20157
|
-
const common =
|
|
20559
|
+
if (existsSync22(commondirFile)) {
|
|
20560
|
+
const common = readFileSync22(commondirFile, "utf8").trim();
|
|
20158
20561
|
return join15(isAbsolute2(common) ? common : resolve2(gd, common), "config");
|
|
20159
20562
|
}
|
|
20160
20563
|
return join15(gd, "config");
|
|
@@ -20169,8 +20572,8 @@ function createRepoResolver() {
|
|
|
20169
20572
|
try {
|
|
20170
20573
|
for (let d = dir; ; d = dirname16(d)) {
|
|
20171
20574
|
const config = gitConfigPathFor(d);
|
|
20172
|
-
if (config &&
|
|
20173
|
-
const url = originUrl2(
|
|
20575
|
+
if (config && existsSync22(config)) {
|
|
20576
|
+
const url = originUrl2(readFileSync22(config, "utf8"));
|
|
20174
20577
|
repo = url ? parseGithubRemote(url) : null;
|
|
20175
20578
|
break;
|
|
20176
20579
|
}
|
|
@@ -20192,7 +20595,7 @@ var init_git_remote = __esm({
|
|
|
20192
20595
|
});
|
|
20193
20596
|
|
|
20194
20597
|
// src/team/queue.ts
|
|
20195
|
-
import { readFileSync as
|
|
20598
|
+
import { readFileSync as readFileSync23, writeFileSync as writeFileSync15, appendFileSync as appendFileSync5, statSync as statSync6, mkdirSync as mkdirSync14 } from "node:fs";
|
|
20196
20599
|
import { dirname as dirname17 } from "node:path";
|
|
20197
20600
|
function enqueuePayload(payload, queuePath = QUEUE_PATH) {
|
|
20198
20601
|
mkdirSync14(dirname17(queuePath), { recursive: true });
|
|
@@ -20209,7 +20612,7 @@ function enqueuePayload(payload, queuePath = QUEUE_PATH) {
|
|
|
20209
20612
|
function dequeuePayloads(queuePath = QUEUE_PATH) {
|
|
20210
20613
|
let lines;
|
|
20211
20614
|
try {
|
|
20212
|
-
lines =
|
|
20615
|
+
lines = readFileSync23(queuePath, "utf8").trim().split("\n").filter(Boolean);
|
|
20213
20616
|
} catch {
|
|
20214
20617
|
return [];
|
|
20215
20618
|
}
|
|
@@ -20230,7 +20633,7 @@ function dequeuePayloads(queuePath = QUEUE_PATH) {
|
|
|
20230
20633
|
function pruneOldest(queuePath) {
|
|
20231
20634
|
let lines;
|
|
20232
20635
|
try {
|
|
20233
|
-
lines =
|
|
20636
|
+
lines = readFileSync23(queuePath, "utf8").trim().split("\n").filter(Boolean);
|
|
20234
20637
|
} catch {
|
|
20235
20638
|
return;
|
|
20236
20639
|
}
|
|
@@ -20249,7 +20652,7 @@ var init_queue2 = __esm({
|
|
|
20249
20652
|
});
|
|
20250
20653
|
|
|
20251
20654
|
// src/usage/profile.ts
|
|
20252
|
-
import { existsSync as
|
|
20655
|
+
import { existsSync as existsSync23, mkdirSync as mkdirSync15, readFileSync as readFileSync24, writeFileSync as writeFileSync16 } from "node:fs";
|
|
20253
20656
|
import { dirname as dirname18 } from "node:path";
|
|
20254
20657
|
function mapRateLimitTier(rateLimitTier) {
|
|
20255
20658
|
switch (rateLimitTier) {
|
|
@@ -20290,9 +20693,9 @@ async function fetchProfile(nowMs = Date.now()) {
|
|
|
20290
20693
|
};
|
|
20291
20694
|
}
|
|
20292
20695
|
function readCachedProfile(cachePath) {
|
|
20293
|
-
if (!
|
|
20696
|
+
if (!existsSync23(cachePath)) return null;
|
|
20294
20697
|
try {
|
|
20295
|
-
const raw = JSON.parse(
|
|
20698
|
+
const raw = JSON.parse(readFileSync24(cachePath, "utf8"));
|
|
20296
20699
|
if (typeof raw.fetchedAtMs !== "number" || !raw.profile) return null;
|
|
20297
20700
|
return raw;
|
|
20298
20701
|
} catch {
|
|
@@ -20481,11 +20884,11 @@ var init_backfill = __esm({
|
|
|
20481
20884
|
});
|
|
20482
20885
|
|
|
20483
20886
|
// src/team/sync-log.ts
|
|
20484
|
-
import { readFileSync as
|
|
20887
|
+
import { readFileSync as readFileSync25 } from "node:fs";
|
|
20485
20888
|
function readPendingSyncLog(watermark) {
|
|
20486
20889
|
let raw;
|
|
20487
20890
|
try {
|
|
20488
|
-
raw =
|
|
20891
|
+
raw = readFileSync25(cclensPath("daemon.log"), "utf8");
|
|
20489
20892
|
} catch {
|
|
20490
20893
|
return { lines: [] };
|
|
20491
20894
|
}
|
|
@@ -20549,7 +20952,7 @@ __export(file_probe_exports, {
|
|
|
20549
20952
|
probeArtifactSignals: () => probeArtifactSignals
|
|
20550
20953
|
});
|
|
20551
20954
|
import { createHash } from "node:crypto";
|
|
20552
|
-
import { existsSync as
|
|
20955
|
+
import { existsSync as existsSync24, readdirSync as readdirSync5, statSync as statSync7 } from "node:fs";
|
|
20553
20956
|
import { homedir as homedir8 } from "node:os";
|
|
20554
20957
|
import { join as join17, relative, resolve as resolve3, sep } from "node:path";
|
|
20555
20958
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
@@ -20559,15 +20962,15 @@ function pathHash(relPath) {
|
|
|
20559
20962
|
function defaultScanRoots(extraRoots = []) {
|
|
20560
20963
|
const roots = [];
|
|
20561
20964
|
const home = join17(homedir8(), ".claude");
|
|
20562
|
-
if (
|
|
20965
|
+
if (existsSync24(home)) roots.push({ root: home, label: "user" });
|
|
20563
20966
|
for (const e of extraRoots) {
|
|
20564
20967
|
const r = resolve3(e, ".claude");
|
|
20565
|
-
if (
|
|
20968
|
+
if (existsSync24(r) && r !== home) roots.push({ root: r, label: "project" });
|
|
20566
20969
|
}
|
|
20567
20970
|
return roots;
|
|
20568
20971
|
}
|
|
20569
20972
|
function listMarkdownFiles(dir) {
|
|
20570
|
-
if (!
|
|
20973
|
+
if (!existsSync24(dir)) return [];
|
|
20571
20974
|
const out = [];
|
|
20572
20975
|
let entries2;
|
|
20573
20976
|
try {
|
|
@@ -20637,7 +21040,7 @@ function scanAuthored(roots, subdir, day2) {
|
|
|
20637
21040
|
const out = [];
|
|
20638
21041
|
for (const r of roots) {
|
|
20639
21042
|
const dir = join17(r.root, subdir);
|
|
20640
|
-
if (!
|
|
21043
|
+
if (!existsSync24(dir)) continue;
|
|
20641
21044
|
for (const f of listMarkdownFiles(dir)) {
|
|
20642
21045
|
const firstSeen = firstSeenDateOf(f);
|
|
20643
21046
|
if (firstSeen !== day2) continue;
|
|
@@ -20651,7 +21054,7 @@ function scanEdited(roots, day2) {
|
|
|
20651
21054
|
const out = [];
|
|
20652
21055
|
for (const r of roots) {
|
|
20653
21056
|
const dir = join17(r.root, "skills");
|
|
20654
|
-
if (!
|
|
21057
|
+
if (!existsSync24(dir)) continue;
|
|
20655
21058
|
for (const f of listMarkdownFiles(dir)) {
|
|
20656
21059
|
const firstSeen = firstSeenDateOf(f);
|
|
20657
21060
|
if (firstSeen === day2) continue;
|
|
@@ -20674,10 +21077,10 @@ function claudemdLineDelta(extraRoots, authorEmail, day2) {
|
|
|
20674
21077
|
const candidates = [];
|
|
20675
21078
|
for (const e of extraRoots) {
|
|
20676
21079
|
const f = resolve3(e, "CLAUDE.md");
|
|
20677
|
-
if (
|
|
21080
|
+
if (existsSync24(f)) candidates.push(f);
|
|
20678
21081
|
}
|
|
20679
21082
|
const homeClaudeMd = join17(homedir8(), "CLAUDE.md");
|
|
20680
|
-
if (
|
|
21083
|
+
if (existsSync24(homeClaudeMd)) candidates.push(homeClaudeMd);
|
|
20681
21084
|
for (const file of candidates) {
|
|
20682
21085
|
try {
|
|
20683
21086
|
const out = execFileSync3(
|
|
@@ -21567,11 +21970,11 @@ var logs_exports = {};
|
|
|
21567
21970
|
__export(logs_exports, {
|
|
21568
21971
|
teamLogs: () => teamLogs
|
|
21569
21972
|
});
|
|
21570
|
-
import { readFileSync as
|
|
21973
|
+
import { readFileSync as readFileSync26 } from "node:fs";
|
|
21571
21974
|
async function teamLogs() {
|
|
21572
21975
|
const logPath = cclensPath("daemon.log");
|
|
21573
21976
|
try {
|
|
21574
|
-
const lines =
|
|
21977
|
+
const lines = readFileSync26(logPath, "utf8").trim().split("\n");
|
|
21575
21978
|
const teamLines = lines.filter((l) => l.includes("[sync] ") || l.includes("team "));
|
|
21576
21979
|
if (teamLines.length === 0) {
|
|
21577
21980
|
console.log("No team-related log entries found.");
|
|
@@ -21699,7 +22102,7 @@ __export(runs_exports, {
|
|
|
21699
22102
|
runs: () => runs
|
|
21700
22103
|
});
|
|
21701
22104
|
import { execSync as execSync2 } from "node:child_process";
|
|
21702
|
-
import { existsSync as
|
|
22105
|
+
import { existsSync as existsSync25, readFileSync as readFileSync27, readdirSync as readdirSync6, statSync as statSync8 } from "node:fs";
|
|
21703
22106
|
import { join as join18 } from "node:path";
|
|
21704
22107
|
async function runs(args2) {
|
|
21705
22108
|
const json = args2.includes("--json");
|
|
@@ -21784,8 +22187,8 @@ function listActiveRuns() {
|
|
|
21784
22187
|
return runs2.sort((a, b) => a.elapsed_s - b.elapsed_s);
|
|
21785
22188
|
}
|
|
21786
22189
|
function readSpend(sinceMs) {
|
|
21787
|
-
if (!
|
|
21788
|
-
const lines =
|
|
22190
|
+
if (!existsSync25(SPEND_PATH)) return [];
|
|
22191
|
+
const lines = readFileSync27(SPEND_PATH, "utf-8").split("\n").filter((l) => l.trim());
|
|
21789
22192
|
const out = [];
|
|
21790
22193
|
for (const line of lines) {
|
|
21791
22194
|
try {
|
|
@@ -21906,7 +22309,7 @@ function ageLabel(ms) {
|
|
|
21906
22309
|
return `${Math.floor(ms / 864e5)}d`;
|
|
21907
22310
|
}
|
|
21908
22311
|
function listTraceFiles() {
|
|
21909
|
-
if (!
|
|
22312
|
+
if (!existsSync25(RUNS_DIR2)) return [];
|
|
21910
22313
|
const entries2 = readdirSync6(RUNS_DIR2).filter((f) => f.endsWith(".jsonl"));
|
|
21911
22314
|
return entries2.map((f) => {
|
|
21912
22315
|
const path11 = join18(RUNS_DIR2, f);
|
|
@@ -21915,14 +22318,14 @@ function listTraceFiles() {
|
|
|
21915
22318
|
}).sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
21916
22319
|
}
|
|
21917
22320
|
function resolveRunId(arg) {
|
|
21918
|
-
if (!
|
|
22321
|
+
if (!existsSync25(RUNS_DIR2)) return null;
|
|
21919
22322
|
if (arg === "latest") {
|
|
21920
22323
|
const all2 = listTraceFiles();
|
|
21921
22324
|
if (all2.length === 0) return null;
|
|
21922
22325
|
return { runId: all2[0].runId, path: all2[0].path };
|
|
21923
22326
|
}
|
|
21924
22327
|
const exact = join18(RUNS_DIR2, `${arg}.jsonl`);
|
|
21925
|
-
if (
|
|
22328
|
+
if (existsSync25(exact)) return { runId: arg, path: exact };
|
|
21926
22329
|
const all = listTraceFiles();
|
|
21927
22330
|
const matches = all.filter((r) => r.runId.includes(arg));
|
|
21928
22331
|
if (matches.length === 1) return { runId: matches[0].runId, path: matches[0].path };
|
|
@@ -21934,7 +22337,7 @@ function resolveRunId(arg) {
|
|
|
21934
22337
|
return null;
|
|
21935
22338
|
}
|
|
21936
22339
|
function readTrace(path11) {
|
|
21937
|
-
return
|
|
22340
|
+
return readFileSync27(path11, "utf-8").split("\n").filter((l) => l.trim()).map((l) => {
|
|
21938
22341
|
try {
|
|
21939
22342
|
return JSON.parse(l);
|
|
21940
22343
|
} catch {
|
|
@@ -21946,7 +22349,7 @@ async function inspect(arg, follow, json) {
|
|
|
21946
22349
|
const r = resolveRunId(arg);
|
|
21947
22350
|
if (!r) {
|
|
21948
22351
|
console.error(`run not found: ${arg}`);
|
|
21949
|
-
if (
|
|
22352
|
+
if (existsSync25(RUNS_DIR2)) {
|
|
21950
22353
|
const all = listTraceFiles().slice(0, 5);
|
|
21951
22354
|
if (all.length > 0) {
|
|
21952
22355
|
console.error(`
|
|
@@ -22126,7 +22529,7 @@ async function main() {
|
|
|
22126
22529
|
case "version":
|
|
22127
22530
|
case "--version":
|
|
22128
22531
|
case "-v":
|
|
22129
|
-
console.log(`fleetlens ${"1.0.
|
|
22532
|
+
console.log(`fleetlens ${"1.0.8"}`);
|
|
22130
22533
|
break;
|
|
22131
22534
|
case "help":
|
|
22132
22535
|
case "--help":
|
|
@@ -22140,7 +22543,7 @@ Common:
|
|
|
22140
22543
|
update Update to the latest version
|
|
22141
22544
|
|
|
22142
22545
|
Terminal:
|
|
22143
|
-
usage [--save]
|
|
22546
|
+
usage [--agent KIND] [--watch] [--save] Plan utilization (all agents; --watch is live)
|
|
22144
22547
|
usage --history [-s D] [--days N] Daily token/cost table
|
|
22145
22548
|
entries [--day D|--session ID|--all] [--json] Perception-layer entries
|
|
22146
22549
|
digest day [--date D|--yesterday|--today] [--json] Day digest
|