ccusage 16.1.2 → 16.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/config-schema.json +12 -0
- package/dist/{_types-BXB_jFi9.js → _types-DIdtMJ6V.js} +23 -2
- package/dist/calculate-cost.d.ts +2 -2
- package/dist/calculate-cost.js +1 -1
- package/dist/{data-loader--Ga8BPdt.d.ts → data-loader-D1FVB4Lp.d.ts} +7 -31
- package/dist/{data-loader-DUaYLdYR.js → data-loader-DzuyD9Va.js} +149 -232
- package/dist/data-loader.d.ts +3 -3
- package/dist/data-loader.js +5 -5
- package/dist/{debug-hX9iI1FE.js → debug-CWK-ECNy.js} +3 -3
- package/dist/debug.js +5 -5
- package/dist/index.js +447 -441
- package/dist/{logger-vSpPcCiQ.js → logger-Cl0x4-O7.js} +1 -1
- package/dist/logger.js +1 -1
- package/dist/{mcp-D343KJOh.js → mcp-CzT8_3kj.js} +5 -5
- package/dist/mcp.d.ts +2 -2
- package/dist/mcp.js +5 -5
- package/dist/{pricing-fetcher-BgDfBZ05.d.ts → pricing-fetcher-DK8lcI1w.d.ts} +1 -1
- package/dist/{pricing-fetcher-BrJoueZ1.js → pricing-fetcher-_ZIEzYHY.js} +5 -5
- package/dist/pricing-fetcher.d.ts +1 -1
- package/dist/pricing-fetcher.js +3 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { BLOCKS_COMPACT_WIDTH_THRESHOLD, BLOCKS_DEFAULT_TERMINAL_WIDTH, BLOCKS_WARNING_THRESHOLD, BURN_RATE_THRESHOLDS, CONFIG_FILE_NAME, DEFAULT_RECENT_DAYS, DEFAULT_REFRESH_INTERVAL_SECONDS, MAX_REFRESH_INTERVAL_SECONDS, MCP_DEFAULT_PORT, MIN_REFRESH_INTERVAL_SECONDS, MIN_RENDER_INTERVAL_MS, PricingFetcher, WEEK_DAYS, __commonJSMin, __require, __toESM, inspect, inspectError, isFailure, isSuccess, map, pipe, require_usingCtx, succeed, try_ } from "./pricing-fetcher-
|
|
2
|
+
import { BLOCKS_COMPACT_WIDTH_THRESHOLD, BLOCKS_DEFAULT_TERMINAL_WIDTH, BLOCKS_WARNING_THRESHOLD, BURN_RATE_THRESHOLDS, CONFIG_FILE_NAME, DEFAULT_CONTEXT_USAGE_THRESHOLDS, DEFAULT_LOCALE, DEFAULT_RECENT_DAYS, DEFAULT_REFRESH_INTERVAL_SECONDS, MAX_REFRESH_INTERVAL_SECONDS, MCP_DEFAULT_PORT, MIN_REFRESH_INTERVAL_SECONDS, MIN_RENDER_INTERVAL_MS, PricingFetcher, WEEK_DAYS, __commonJSMin, __require, __toESM, andThen, fail, inspect, inspectError, isFailure, isSuccess, map, pipe, require_usingCtx, succeed, try_ } from "./pricing-fetcher-_ZIEzYHY.js";
|
|
3
3
|
import { getTotalTokens } from "./_token-utils-WjkbrjKv.js";
|
|
4
|
-
import { CostModes, SortOrders, filterDateSchema, statuslineHookJsonSchema } from "./_types-
|
|
4
|
+
import { CostModes, SortOrders, coerce, filterDateSchema, statuslineHookJsonSchema } from "./_types-DIdtMJ6V.js";
|
|
5
5
|
import { calculateTotals, createTotalsObject } from "./calculate-cost-BDqO4yWA.js";
|
|
6
|
-
import { DEFAULT_SESSION_DURATION_HOURS, calculateBurnRate, calculateContextTokens, calculateCostForEntry, createUniqueHash, filterRecentBlocks, formatDateCompact, getClaudePaths,
|
|
7
|
-
import { description, log, logger, name, version } from "./logger-
|
|
8
|
-
import { detectMismatches, printMismatchReport } from "./debug-
|
|
9
|
-
import { createMcpHttpApp, createMcpServer, startMcpServerStdio } from "./mcp-
|
|
6
|
+
import { DEFAULT_SESSION_DURATION_HOURS, calculateBurnRate, calculateContextTokens, calculateCostForEntry, createUniqueHash, filterRecentBlocks, formatDateCompact, getClaudePaths, getEarliestTimestamp, getFileModifiedTime, getUsageLimitResetTime, globUsageFiles, identifySessionBlocks, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData, loadSessionUsageById, loadWeeklyUsageData, projectBlockUsage, sortFilesByTimestamp, toArray, uniq, unreachable, unwrap, usageDataSchema } from "./data-loader-DzuyD9Va.js";
|
|
7
|
+
import { description, log, logger, name, version } from "./logger-Cl0x4-O7.js";
|
|
8
|
+
import { detectMismatches, printMismatchReport } from "./debug-CWK-ECNy.js";
|
|
9
|
+
import { createMcpHttpApp, createMcpServer, startMcpServerStdio } from "./mcp-CzT8_3kj.js";
|
|
10
10
|
import a, { readFile, stat } from "node:fs/promises";
|
|
11
11
|
import path, { join } from "node:path";
|
|
12
12
|
import process$1 from "node:process";
|
|
@@ -22,7 +22,7 @@ import { createServer } from "node:http";
|
|
|
22
22
|
import { Http2ServerRequest } from "node:http2";
|
|
23
23
|
import { Readable } from "node:stream";
|
|
24
24
|
import crypto from "node:crypto";
|
|
25
|
-
const DEFAULT_LOCALE = "en-US", BUILT_IN_PREFIX = "_", ARG_PREFIX = "arg", BUILT_IN_KEY_SEPARATOR = ":", ANONYMOUS_COMMAND_NAME = "(anonymous)", NOOP = () => {}, COMMON_ARGS = {
|
|
25
|
+
const DEFAULT_LOCALE$1 = "en-US", BUILT_IN_PREFIX = "_", ARG_PREFIX = "arg", BUILT_IN_KEY_SEPARATOR = ":", ANONYMOUS_COMMAND_NAME = "(anonymous)", NOOP = () => {}, COMMON_ARGS = {
|
|
26
26
|
help: {
|
|
27
27
|
type: "boolean",
|
|
28
28
|
short: "h",
|
|
@@ -149,16 +149,16 @@ async function createCommandContext({ args, values, positionals, rest, argv: arg
|
|
|
149
149
|
return acc[key] = Object.assign(create(), value$1), acc;
|
|
150
150
|
}, create()), env$2 = Object.assign(create(), COMMAND_OPTIONS_DEFAULT, cliOptions), locale = resolveLocale(cliOptions.locale), localeStr = locale.toString(), translationAdapterFactory = cliOptions.translationAdapterFactory || createTranslationAdapter, adapter = translationAdapterFactory({
|
|
151
151
|
locale: localeStr,
|
|
152
|
-
fallbackLocale: DEFAULT_LOCALE
|
|
152
|
+
fallbackLocale: DEFAULT_LOCALE$1
|
|
153
153
|
}), localeResources = /* @__PURE__ */ new Map();
|
|
154
154
|
let builtInLoadedResources;
|
|
155
|
-
if (localeResources.set(DEFAULT_LOCALE, mapResourceWithBuiltinKey(en_US_default)), DEFAULT_LOCALE !== localeStr) try {
|
|
155
|
+
if (localeResources.set(DEFAULT_LOCALE$1, mapResourceWithBuiltinKey(en_US_default)), DEFAULT_LOCALE$1 !== localeStr) try {
|
|
156
156
|
builtInLoadedResources = (await import(`./locales/${localeStr}.json`, { with: { type: "json" } })).default, localeResources.set(localeStr, mapResourceWithBuiltinKey(builtInLoadedResources));
|
|
157
157
|
} catch {}
|
|
158
158
|
function translate(key, values$1 = create()) {
|
|
159
159
|
const strKey = key;
|
|
160
160
|
if (strKey.codePointAt(0) === BUILT_IN_PREFIX_CODE) {
|
|
161
|
-
const resource = localeResources.get(localeStr) || localeResources.get(DEFAULT_LOCALE);
|
|
161
|
+
const resource = localeResources.get(localeStr) || localeResources.get(DEFAULT_LOCALE$1);
|
|
162
162
|
return resource[strKey] || strKey;
|
|
163
163
|
} else return adapter.translate(locale.toString(), strKey, values$1) || "";
|
|
164
164
|
}
|
|
@@ -191,7 +191,7 @@ async function createCommandContext({ args, values, positionals, rest, argv: arg
|
|
|
191
191
|
}), defaultCommandResource = loadedOptionsResources.reduce((res, [key, value$1]) => {
|
|
192
192
|
return res[resolveArgKey(key)] = value$1, res;
|
|
193
193
|
}, create());
|
|
194
|
-
defaultCommandResource.description = command.description || "", defaultCommandResource.examples = await resolveExamples(ctx, command.examples), adapter.setResource(DEFAULT_LOCALE, defaultCommandResource);
|
|
194
|
+
defaultCommandResource.description = command.description || "", defaultCommandResource.examples = await resolveExamples(ctx, command.examples), adapter.setResource(DEFAULT_LOCALE$1, defaultCommandResource);
|
|
195
195
|
const originalResource = await loadCommandResource(ctx, command);
|
|
196
196
|
if (originalResource) {
|
|
197
197
|
const resource = Object.assign(create(), originalResource, { examples: await resolveExamples(ctx, originalResource.examples) });
|
|
@@ -204,7 +204,7 @@ function getCommandName(cmd) {
|
|
|
204
204
|
return isLazyCommand(cmd) ? cmd.commandName || cmd.name || ANONYMOUS_COMMAND_NAME : typeof cmd === "object" && cmd.name || ANONYMOUS_COMMAND_NAME;
|
|
205
205
|
}
|
|
206
206
|
function resolveLocale(locale) {
|
|
207
|
-
return locale instanceof Intl.Locale ? locale : typeof locale === "string" ? new Intl.Locale(locale) : new Intl.Locale(DEFAULT_LOCALE);
|
|
207
|
+
return locale instanceof Intl.Locale ? locale : typeof locale === "string" ? new Intl.Locale(locale) : new Intl.Locale(DEFAULT_LOCALE$1);
|
|
208
208
|
}
|
|
209
209
|
async function loadCommandResource(ctx, command) {
|
|
210
210
|
let resource;
|
|
@@ -817,7 +817,7 @@ var require_picocolors = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
817
817
|
};
|
|
818
818
|
};
|
|
819
819
|
module.exports = createColors(), module.exports.createColors = createColors;
|
|
820
|
-
})), import_picocolors$
|
|
820
|
+
})), import_picocolors$5 = /* @__PURE__ */ __toESM(require_picocolors(), 1), import_usingCtx$3 = /* @__PURE__ */ __toESM(require_usingCtx(), 1);
|
|
821
821
|
function extractExplicitArgs(tokens) {
|
|
822
822
|
const explicit = {};
|
|
823
823
|
for (const token of tokens) if (typeof token === "object" && token !== null) {
|
|
@@ -1157,7 +1157,7 @@ const sharedArgs = {
|
|
|
1157
1157
|
type: "string",
|
|
1158
1158
|
short: "l",
|
|
1159
1159
|
description: "Locale for date/time formatting (e.g., en-US, ja-JP, de-DE)",
|
|
1160
|
-
default:
|
|
1160
|
+
default: DEFAULT_LOCALE
|
|
1161
1161
|
},
|
|
1162
1162
|
jq: {
|
|
1163
1163
|
type: "string",
|
|
@@ -2467,7 +2467,7 @@ function stringWidth(string, options = {}) {
|
|
|
2467
2467
|
}
|
|
2468
2468
|
return width;
|
|
2469
2469
|
}
|
|
2470
|
-
var
|
|
2470
|
+
var ResponsiveTable = class {
|
|
2471
2471
|
head;
|
|
2472
2472
|
rows = [];
|
|
2473
2473
|
colAligns;
|
|
@@ -2499,7 +2499,7 @@ var import_usingCtx$2 = /* @__PURE__ */ __toESM(require_usingCtx(), 1), Responsi
|
|
|
2499
2499
|
getCompactIndices() {
|
|
2500
2500
|
return this.compactHead == null || !this.compactMode ? Array.from({ length: this.head.length }, (_, i) => i) : this.compactHead.map((compactHeader) => {
|
|
2501
2501
|
const index = this.head.indexOf(compactHeader);
|
|
2502
|
-
return index < 0 ? (
|
|
2502
|
+
return index < 0 ? (logger.warn(`Warning: Compact header "${compactHeader}" not found in table headers [${this.head.join(", ")}]. Using first column as fallback.`), 0) : index;
|
|
2503
2503
|
});
|
|
2504
2504
|
}
|
|
2505
2505
|
isCompactMode() {
|
|
@@ -2592,73 +2592,254 @@ function pushBreakdownRows(table, breakdowns, extraColumns = 1, trailingColumns
|
|
|
2592
2592
|
const row = [` └─ ${formatModelName(breakdown.modelName)}`];
|
|
2593
2593
|
for (let i = 0; i < extraColumns; i++) row.push("");
|
|
2594
2594
|
const totalTokens = breakdown.inputTokens + breakdown.outputTokens + breakdown.cacheCreationTokens + breakdown.cacheReadTokens;
|
|
2595
|
-
row.push(import_picocolors$
|
|
2595
|
+
row.push(import_picocolors$5.default.gray(formatNumber(breakdown.inputTokens)), import_picocolors$5.default.gray(formatNumber(breakdown.outputTokens)), import_picocolors$5.default.gray(formatNumber(breakdown.cacheCreationTokens)), import_picocolors$5.default.gray(formatNumber(breakdown.cacheReadTokens)), import_picocolors$5.default.gray(formatNumber(totalTokens)), import_picocolors$5.default.gray(formatCurrency(breakdown.cost)));
|
|
2596
2596
|
for (let i = 0; i < trailingColumns; i++) row.push("");
|
|
2597
2597
|
table.push(row);
|
|
2598
2598
|
}
|
|
2599
2599
|
}
|
|
2600
|
-
|
|
2600
|
+
function createUsageReportTable(config) {
|
|
2601
|
+
const baseHeaders = [
|
|
2602
|
+
config.firstColumnName,
|
|
2603
|
+
"Models",
|
|
2604
|
+
"Input",
|
|
2605
|
+
"Output",
|
|
2606
|
+
"Cache Create",
|
|
2607
|
+
"Cache Read",
|
|
2608
|
+
"Total Tokens",
|
|
2609
|
+
"Cost (USD)"
|
|
2610
|
+
], baseAligns = [
|
|
2611
|
+
"left",
|
|
2612
|
+
"left",
|
|
2613
|
+
"right",
|
|
2614
|
+
"right",
|
|
2615
|
+
"right",
|
|
2616
|
+
"right",
|
|
2617
|
+
"right",
|
|
2618
|
+
"right"
|
|
2619
|
+
], compactHeaders = [
|
|
2620
|
+
config.firstColumnName,
|
|
2621
|
+
"Models",
|
|
2622
|
+
"Input",
|
|
2623
|
+
"Output",
|
|
2624
|
+
"Cost (USD)"
|
|
2625
|
+
], compactAligns = [
|
|
2626
|
+
"left",
|
|
2627
|
+
"left",
|
|
2628
|
+
"right",
|
|
2629
|
+
"right",
|
|
2630
|
+
"right"
|
|
2631
|
+
];
|
|
2632
|
+
if (config.includeLastActivity ?? false) baseHeaders.push("Last Activity"), baseAligns.push("left"), compactHeaders.push("Last Activity"), compactAligns.push("left");
|
|
2633
|
+
return new ResponsiveTable({
|
|
2634
|
+
head: baseHeaders,
|
|
2635
|
+
style: { head: ["cyan"] },
|
|
2636
|
+
colAligns: baseAligns,
|
|
2637
|
+
dateFormatter: config.dateFormatter,
|
|
2638
|
+
compactHead: compactHeaders,
|
|
2639
|
+
compactColAligns: compactAligns,
|
|
2640
|
+
compactThreshold: 100,
|
|
2641
|
+
forceCompact: config.forceCompact
|
|
2642
|
+
});
|
|
2643
|
+
}
|
|
2644
|
+
function formatUsageDataRow(firstColumnValue, data, lastActivity) {
|
|
2645
|
+
const totalTokens = data.inputTokens + data.outputTokens + data.cacheCreationTokens + data.cacheReadTokens, row = [
|
|
2646
|
+
firstColumnValue,
|
|
2647
|
+
data.modelsUsed != null ? formatModelsDisplayMultiline(data.modelsUsed) : "",
|
|
2648
|
+
formatNumber(data.inputTokens),
|
|
2649
|
+
formatNumber(data.outputTokens),
|
|
2650
|
+
formatNumber(data.cacheCreationTokens),
|
|
2651
|
+
formatNumber(data.cacheReadTokens),
|
|
2652
|
+
formatNumber(totalTokens),
|
|
2653
|
+
formatCurrency(data.totalCost)
|
|
2654
|
+
];
|
|
2655
|
+
if (lastActivity !== void 0) row.push(lastActivity);
|
|
2656
|
+
return row;
|
|
2657
|
+
}
|
|
2658
|
+
function formatTotalsRow(totals, includeLastActivity = false) {
|
|
2659
|
+
const totalTokens = totals.inputTokens + totals.outputTokens + totals.cacheCreationTokens + totals.cacheReadTokens, row = [
|
|
2660
|
+
import_picocolors$5.default.yellow("Total"),
|
|
2661
|
+
"",
|
|
2662
|
+
import_picocolors$5.default.yellow(formatNumber(totals.inputTokens)),
|
|
2663
|
+
import_picocolors$5.default.yellow(formatNumber(totals.outputTokens)),
|
|
2664
|
+
import_picocolors$5.default.yellow(formatNumber(totals.cacheCreationTokens)),
|
|
2665
|
+
import_picocolors$5.default.yellow(formatNumber(totals.cacheReadTokens)),
|
|
2666
|
+
import_picocolors$5.default.yellow(formatNumber(totalTokens)),
|
|
2667
|
+
import_picocolors$5.default.yellow(formatCurrency(totals.totalCost))
|
|
2668
|
+
];
|
|
2669
|
+
if (includeLastActivity) row.push("");
|
|
2670
|
+
return row;
|
|
2671
|
+
}
|
|
2672
|
+
function addEmptySeparatorRow(table, columnCount) {
|
|
2673
|
+
const emptyRow = Array.from({ length: columnCount }, () => "");
|
|
2674
|
+
table.push(emptyRow);
|
|
2675
|
+
}
|
|
2676
|
+
var Node = class {
|
|
2677
|
+
value;
|
|
2678
|
+
next;
|
|
2679
|
+
constructor(value$1) {
|
|
2680
|
+
this.value = value$1;
|
|
2681
|
+
}
|
|
2682
|
+
}, Queue = class {
|
|
2683
|
+
#head;
|
|
2684
|
+
#tail;
|
|
2685
|
+
#size;
|
|
2686
|
+
constructor() {
|
|
2687
|
+
this.clear();
|
|
2688
|
+
}
|
|
2689
|
+
enqueue(value$1) {
|
|
2690
|
+
const node = new Node(value$1);
|
|
2691
|
+
if (this.#head) this.#tail.next = node, this.#tail = node;
|
|
2692
|
+
else this.#head = node, this.#tail = node;
|
|
2693
|
+
this.#size++;
|
|
2694
|
+
}
|
|
2695
|
+
dequeue() {
|
|
2696
|
+
const current = this.#head;
|
|
2697
|
+
if (current) return this.#head = this.#head.next, this.#size--, current.value;
|
|
2698
|
+
}
|
|
2699
|
+
peek() {
|
|
2700
|
+
if (this.#head) return this.#head.value;
|
|
2701
|
+
}
|
|
2702
|
+
clear() {
|
|
2703
|
+
this.#head = void 0, this.#tail = void 0, this.#size = 0;
|
|
2704
|
+
}
|
|
2705
|
+
get size() {
|
|
2706
|
+
return this.#size;
|
|
2707
|
+
}
|
|
2708
|
+
*[Symbol.iterator]() {
|
|
2709
|
+
let current = this.#head;
|
|
2710
|
+
while (current) yield current.value, current = current.next;
|
|
2711
|
+
}
|
|
2712
|
+
*drain() {
|
|
2713
|
+
while (this.#head) yield this.dequeue();
|
|
2714
|
+
}
|
|
2715
|
+
};
|
|
2716
|
+
function pLimit(concurrency) {
|
|
2717
|
+
validateConcurrency(concurrency);
|
|
2718
|
+
const queue = new Queue();
|
|
2719
|
+
let activeCount = 0;
|
|
2720
|
+
const resumeNext = () => {
|
|
2721
|
+
if (activeCount < concurrency && queue.size > 0) activeCount++, queue.dequeue()();
|
|
2722
|
+
}, next = () => {
|
|
2723
|
+
activeCount--, resumeNext();
|
|
2724
|
+
}, run$1 = async (function_, resolve, arguments_) => {
|
|
2725
|
+
const result = (async () => function_(...arguments_))();
|
|
2726
|
+
resolve(result);
|
|
2727
|
+
try {
|
|
2728
|
+
await result;
|
|
2729
|
+
} catch {}
|
|
2730
|
+
next();
|
|
2731
|
+
}, enqueue = (function_, resolve, arguments_) => {
|
|
2732
|
+
if (new Promise((internalResolve) => {
|
|
2733
|
+
queue.enqueue(internalResolve);
|
|
2734
|
+
}).then(run$1.bind(void 0, function_, resolve, arguments_)), activeCount < concurrency) resumeNext();
|
|
2735
|
+
}, generator = (function_, ...arguments_) => new Promise((resolve) => {
|
|
2736
|
+
enqueue(function_, resolve, arguments_);
|
|
2737
|
+
});
|
|
2738
|
+
return Object.defineProperties(generator, {
|
|
2739
|
+
activeCount: { get: () => activeCount },
|
|
2740
|
+
pendingCount: { get: () => queue.size },
|
|
2741
|
+
clearQueue: { value() {
|
|
2742
|
+
queue.clear();
|
|
2743
|
+
} },
|
|
2744
|
+
concurrency: {
|
|
2745
|
+
get: () => concurrency,
|
|
2746
|
+
set(newConcurrency) {
|
|
2747
|
+
validateConcurrency(newConcurrency), concurrency = newConcurrency, queueMicrotask(() => {
|
|
2748
|
+
while (activeCount < concurrency && queue.size > 0) resumeNext();
|
|
2749
|
+
});
|
|
2750
|
+
}
|
|
2751
|
+
},
|
|
2752
|
+
map: { async value(array, function_) {
|
|
2753
|
+
const promises = array.map((value$1, index) => this(function_, value$1, index));
|
|
2754
|
+
return Promise.all(promises);
|
|
2755
|
+
} }
|
|
2756
|
+
}), generator;
|
|
2757
|
+
}
|
|
2758
|
+
function validateConcurrency(concurrency) {
|
|
2759
|
+
if (!((Number.isInteger(concurrency) || concurrency === Number.POSITIVE_INFINITY) && concurrency > 0)) throw new TypeError("Expected `concurrency` to be a number from 1 and up");
|
|
2760
|
+
}
|
|
2761
|
+
var import_usingCtx$2 = /* @__PURE__ */ __toESM(require_usingCtx(), 1);
|
|
2762
|
+
const RETENTION_HOURS = 24, FILE_CONCURRENCY = 5;
|
|
2763
|
+
async function isRecentFile(filePath, cutoffTime) {
|
|
2601
2764
|
return pipe(try_({
|
|
2602
2765
|
try: stat(filePath),
|
|
2603
2766
|
catch: (error) => error
|
|
2604
|
-
}), map((
|
|
2605
|
-
}
|
|
2606
|
-
|
|
2607
|
-
config;
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
[Symbol.dispose]() {
|
|
2616
|
-
this.fetcher?.[Symbol.dispose]();
|
|
2617
|
-
}
|
|
2618
|
-
async getActiveBlock() {
|
|
2619
|
-
const results = await globUsageFiles(this.config.claudePaths), allFiles = results.map((r) => r.file);
|
|
2620
|
-
if (allFiles.length === 0) return null;
|
|
2621
|
-
const filesToRead = [];
|
|
2622
|
-
for (const file of allFiles) {
|
|
2623
|
-
const timestamp$1 = await getEarliestTimestamp(file), lastTimestamp = this.lastFileTimestamps.get(file);
|
|
2624
|
-
if (timestamp$1 != null && (lastTimestamp == null || timestamp$1.getTime() > lastTimestamp)) filesToRead.push(file), this.lastFileTimestamps.set(file, timestamp$1.getTime());
|
|
2625
|
-
}
|
|
2626
|
-
if (filesToRead.length > 0) {
|
|
2627
|
-
const sortedFiles = await sortFilesByTimestamp(filesToRead);
|
|
2628
|
-
for (const file of sortedFiles) {
|
|
2629
|
-
const content = await readFile(file, "utf-8").catch(() => {
|
|
2630
|
-
return "";
|
|
2631
|
-
}), lines = content.trim().split("\n").filter((line) => line.length > 0);
|
|
2632
|
-
for (const line of lines) try {
|
|
2633
|
-
const parsed = JSON.parse(line), result = usageDataSchema.safeParse(parsed);
|
|
2634
|
-
if (!result.success) continue;
|
|
2635
|
-
const data = result.data, uniqueHash = createUniqueHash(data);
|
|
2636
|
-
if (uniqueHash != null && this.processedHashes.has(uniqueHash)) continue;
|
|
2637
|
-
if (uniqueHash != null) this.processedHashes.add(uniqueHash);
|
|
2638
|
-
const costUSD = await (this.config.mode === "display" ? Promise.resolve(data.costUSD ?? 0) : calculateCostForEntry(data, this.config.mode, this.fetcher)), usageLimitResetTime = getUsageLimitResetTime(data);
|
|
2639
|
-
this.allEntries.push({
|
|
2640
|
-
timestamp: new Date(data.timestamp),
|
|
2641
|
-
usage: {
|
|
2642
|
-
inputTokens: data.message.usage.input_tokens ?? 0,
|
|
2643
|
-
outputTokens: data.message.usage.output_tokens ?? 0,
|
|
2644
|
-
cacheCreationInputTokens: data.message.usage.cache_creation_input_tokens ?? 0,
|
|
2645
|
-
cacheReadInputTokens: data.message.usage.cache_read_input_tokens ?? 0
|
|
2646
|
-
},
|
|
2647
|
-
costUSD,
|
|
2648
|
-
model: data.message.model ?? "<synthetic>",
|
|
2649
|
-
version: data.version,
|
|
2650
|
-
usageLimitResetTime: usageLimitResetTime ?? void 0
|
|
2651
|
-
});
|
|
2652
|
-
} catch {}
|
|
2653
|
-
}
|
|
2767
|
+
}), map((fileStats) => fileStats.mtime >= cutoffTime), unwrap(false));
|
|
2768
|
+
}
|
|
2769
|
+
function createLiveMonitorState(config) {
|
|
2770
|
+
const fetcher = config.mode !== "display" ? new PricingFetcher() : null;
|
|
2771
|
+
return {
|
|
2772
|
+
fetcher,
|
|
2773
|
+
lastFileTimestamps: /* @__PURE__ */ new Map(),
|
|
2774
|
+
processedHashes: /* @__PURE__ */ new Set(),
|
|
2775
|
+
allEntries: [],
|
|
2776
|
+
[Symbol.dispose]() {
|
|
2777
|
+
fetcher?.[Symbol.dispose]();
|
|
2654
2778
|
}
|
|
2655
|
-
|
|
2656
|
-
|
|
2779
|
+
};
|
|
2780
|
+
}
|
|
2781
|
+
function clearLiveMonitorCache(state) {
|
|
2782
|
+
state.lastFileTimestamps.clear(), state.processedHashes.clear(), state.allEntries = [];
|
|
2783
|
+
}
|
|
2784
|
+
function cleanupOldEntries(state, cutoffTime) {
|
|
2785
|
+
const initialCount = state.allEntries.length;
|
|
2786
|
+
if (state.allEntries = state.allEntries.filter((entry) => entry.timestamp >= cutoffTime), initialCount - state.allEntries.length > 100) state.processedHashes.clear();
|
|
2787
|
+
}
|
|
2788
|
+
async function processFileContent(state, config, content, cutoffTime) {
|
|
2789
|
+
const lines = content.trim().split("\n").filter((line) => line.length > 0);
|
|
2790
|
+
for (const line of lines) {
|
|
2791
|
+
const dataResult = pipe(try_({
|
|
2792
|
+
try: () => JSON.parse(line),
|
|
2793
|
+
catch: (error) => error
|
|
2794
|
+
})(), andThen((data$1) => {
|
|
2795
|
+
const parseResult = usageDataSchema.safeParse(data$1);
|
|
2796
|
+
return parseResult.success ? succeed(parseResult.data) : fail(parseResult.error);
|
|
2797
|
+
}));
|
|
2798
|
+
if (isFailure(dataResult)) continue;
|
|
2799
|
+
const data = unwrap(dataResult), entryTime = new Date(data.timestamp);
|
|
2800
|
+
if (entryTime < cutoffTime) continue;
|
|
2801
|
+
const uniqueHash = createUniqueHash(data);
|
|
2802
|
+
if (uniqueHash != null && state.processedHashes.has(uniqueHash)) continue;
|
|
2803
|
+
if (uniqueHash != null) state.processedHashes.add(uniqueHash);
|
|
2804
|
+
const costUSD = await (config.mode === "display" ? Promise.resolve(data.costUSD ?? 0) : calculateCostForEntry(data, config.mode, state.fetcher)), usageLimitResetTime = getUsageLimitResetTime(data);
|
|
2805
|
+
state.allEntries.push({
|
|
2806
|
+
timestamp: entryTime,
|
|
2807
|
+
usage: {
|
|
2808
|
+
inputTokens: data.message.usage.input_tokens ?? 0,
|
|
2809
|
+
outputTokens: data.message.usage.output_tokens ?? 0,
|
|
2810
|
+
cacheCreationInputTokens: data.message.usage.cache_creation_input_tokens ?? 0,
|
|
2811
|
+
cacheReadInputTokens: data.message.usage.cache_read_input_tokens ?? 0
|
|
2812
|
+
},
|
|
2813
|
+
costUSD,
|
|
2814
|
+
model: data.message.model ?? "<synthetic>",
|
|
2815
|
+
version: data.version,
|
|
2816
|
+
usageLimitResetTime: usageLimitResetTime ?? void 0
|
|
2817
|
+
});
|
|
2657
2818
|
}
|
|
2658
|
-
|
|
2659
|
-
|
|
2819
|
+
}
|
|
2820
|
+
async function getActiveBlock(state, config) {
|
|
2821
|
+
const cutoffTime = /* @__PURE__ */ new Date(Date.now() - RETENTION_HOURS * 60 * 60 * 1e3), results = await globUsageFiles(config.claudePaths), allFiles = results.map((r) => r.file);
|
|
2822
|
+
if (allFiles.length === 0) return null;
|
|
2823
|
+
const candidateFiles = [];
|
|
2824
|
+
for (const file of allFiles) if (await isRecentFile(file, cutoffTime)) candidateFiles.push(file);
|
|
2825
|
+
const filesToRead = [];
|
|
2826
|
+
for (const file of candidateFiles) {
|
|
2827
|
+
const timestamp$1 = await getEarliestTimestamp(file), lastTimestamp = state.lastFileTimestamps.get(file);
|
|
2828
|
+
if (timestamp$1 != null && (lastTimestamp == null || timestamp$1.getTime() > lastTimestamp)) filesToRead.push(file), state.lastFileTimestamps.set(file, timestamp$1.getTime());
|
|
2660
2829
|
}
|
|
2661
|
-
|
|
2830
|
+
if (cleanupOldEntries(state, cutoffTime), filesToRead.length > 0) {
|
|
2831
|
+
const sortedFiles = await sortFilesByTimestamp(filesToRead), fileLimit = pLimit(FILE_CONCURRENCY), fileResults = await Promise.allSettled(sortedFiles.map(async (file) => fileLimit(async () => ({
|
|
2832
|
+
file,
|
|
2833
|
+
content: await readFile(file, "utf-8")
|
|
2834
|
+
}))));
|
|
2835
|
+
for (const result of fileResults) if (result.status === "fulfilled") {
|
|
2836
|
+
const { content } = result.value;
|
|
2837
|
+
await processFileContent(state, config, content, cutoffTime);
|
|
2838
|
+
}
|
|
2839
|
+
}
|
|
2840
|
+
const blocks = identifySessionBlocks(state.allEntries, config.sessionDurationHours), sortedBlocks = config.order === "asc" ? blocks : blocks.reverse();
|
|
2841
|
+
return sortedBlocks.find((block) => block.isActive) ?? null;
|
|
2842
|
+
}
|
|
2662
2843
|
function delay(ms, options = {}) {
|
|
2663
2844
|
const { signal, persistent = true } = options;
|
|
2664
2845
|
return signal?.aborted ? Promise.reject(signal.reason) : new Promise((resolve, reject) => {
|
|
@@ -2884,20 +3065,20 @@ const SAVE_CURSOR = "\x1B7", RESTORE_CURSOR = "\x1B8";
|
|
|
2884
3065
|
function drawEmoji(emoji) {
|
|
2885
3066
|
return `${SAVE_CURSOR}${emoji}${RESTORE_CURSOR}${cursorForward(stringWidth(emoji))}`;
|
|
2886
3067
|
}
|
|
2887
|
-
var import_picocolors$
|
|
3068
|
+
var import_picocolors$4 = /* @__PURE__ */ __toESM(require_picocolors(), 1);
|
|
2888
3069
|
function getRateIndicator(burnRate) {
|
|
2889
3070
|
if (burnRate == null) return "";
|
|
2890
3071
|
switch (true) {
|
|
2891
|
-
case burnRate.tokensPerMinuteForIndicator > BURN_RATE_THRESHOLDS.HIGH: return import_picocolors$
|
|
2892
|
-
case burnRate.tokensPerMinuteForIndicator > BURN_RATE_THRESHOLDS.MODERATE: return import_picocolors$
|
|
2893
|
-
default: return import_picocolors$
|
|
3072
|
+
case burnRate.tokensPerMinuteForIndicator > BURN_RATE_THRESHOLDS.HIGH: return import_picocolors$4.default.red(`${drawEmoji("⚡")} HIGH`);
|
|
3073
|
+
case burnRate.tokensPerMinuteForIndicator > BURN_RATE_THRESHOLDS.MODERATE: return import_picocolors$4.default.yellow(`${drawEmoji("⚡")} MODERATE`);
|
|
3074
|
+
default: return import_picocolors$4.default.green(`${drawEmoji("✓")} NORMAL`);
|
|
2894
3075
|
}
|
|
2895
3076
|
}
|
|
2896
3077
|
async function delayWithAbort(ms, signal) {
|
|
2897
3078
|
await delay(ms, { signal });
|
|
2898
3079
|
}
|
|
2899
3080
|
async function renderWaitingState(terminal, config, signal) {
|
|
2900
|
-
terminal.startBuffering(), terminal.write(cursorTo(0, 0)), terminal.write(eraseDown), terminal.write(import_picocolors$
|
|
3081
|
+
terminal.startBuffering(), terminal.write(cursorTo(0, 0)), terminal.write(eraseDown), terminal.write(import_picocolors$4.default.yellow("No active session block found. Waiting...\n")), terminal.write(cursorHide), terminal.flush(), await delayWithAbort(config.refreshInterval, signal);
|
|
2901
3082
|
}
|
|
2902
3083
|
function renderActiveBlock(terminal, activeBlock, config) {
|
|
2903
3084
|
terminal.startBuffering(), terminal.write(cursorTo(0, 0)), terminal.write(eraseDown), renderLiveDisplay(terminal, activeBlock, config), terminal.write(cursorHide), terminal.flush();
|
|
@@ -2915,8 +3096,8 @@ function renderLiveDisplay(terminal, block, config) {
|
|
|
2915
3096
|
}
|
|
2916
3097
|
const boxWidth = Math.min(120, width - 2), boxMargin = Math.floor((width - boxWidth) / 2), marginStr = " ".repeat(boxMargin), sessionDuration = elapsed + remaining, sessionPercent = elapsed / sessionDuration * 100, sessionRightText = `${sessionPercent.toFixed(1).padStart(6)}%`, tokenPercent = config.tokenLimit != null && config.tokenLimit > 0 ? totalTokens / config.tokenLimit * 100 : 0, usageRightText = config.tokenLimit != null && config.tokenLimit > 0 ? `${tokenPercent.toFixed(1).padStart(6)}% (${formatTokensShort(totalTokens)}/${formatTokensShort(config.tokenLimit)})` : `(${formatTokensShort(totalTokens)} tokens)`, projection = projectBlockUsage(block), projectedPercent = projection != null && config.tokenLimit != null && config.tokenLimit > 0 ? projection.totalTokens / config.tokenLimit * 100 : 0, projectionRightText = projection != null ? config.tokenLimit != null && config.tokenLimit > 0 ? `${projectedPercent.toFixed(1).padStart(6)}% (${formatTokensShort(projection.totalTokens)}/${formatTokensShort(config.tokenLimit)})` : `(${formatTokensShort(projection.totalTokens)} tokens)` : "", maxRightTextWidth = Math.max(stringWidth(sessionRightText), stringWidth(usageRightText), projection != null ? stringWidth(projectionRightText) : 0), labelWidth = 14, spacing = 4, boxPadding = 4, barWidth = boxWidth - labelWidth - maxRightTextWidth - spacing - boxPadding, sessionProgressBar = createProgressBar(elapsed, sessionDuration, barWidth, {
|
|
2917
3098
|
showPercentage: false,
|
|
2918
|
-
fillChar: import_picocolors$
|
|
2919
|
-
emptyChar: import_picocolors$
|
|
3099
|
+
fillChar: import_picocolors$4.default.cyan("█"),
|
|
3100
|
+
emptyChar: import_picocolors$4.default.gray("░"),
|
|
2920
3101
|
leftBracket: "[",
|
|
2921
3102
|
rightBracket: "]"
|
|
2922
3103
|
}), startTime = block.startTime.toLocaleTimeString(void 0, {
|
|
@@ -2930,10 +3111,10 @@ function renderLiveDisplay(terminal, block, config) {
|
|
|
2930
3111
|
second: "2-digit",
|
|
2931
3112
|
hour12: true
|
|
2932
3113
|
}), detailsIndent = 3, detailsSpacing = 2, detailsAvailableWidth = boxWidth - 3 - detailsIndent;
|
|
2933
|
-
terminal.write(`${marginStr}┌${"─".repeat(boxWidth - 2)}┐\n`), terminal.write(`${marginStr}│${import_picocolors$
|
|
2934
|
-
const sessionLabel = `${drawEmoji("⏱️")}${import_picocolors$
|
|
3114
|
+
terminal.write(`${marginStr}┌${"─".repeat(boxWidth - 2)}┐\n`), terminal.write(`${marginStr}│${import_picocolors$4.default.bold(centerText("CLAUDE CODE - LIVE TOKEN USAGE MONITOR", boxWidth - 2))}│\n`), terminal.write(`${marginStr}├${"─".repeat(boxWidth - 2)}┤\n`), terminal.write(`${marginStr}│${" ".repeat(boxWidth - 2)}│\n`);
|
|
3115
|
+
const sessionLabel = `${drawEmoji("⏱️")}${import_picocolors$4.default.bold(" SESSION")}`, sessionLabelWidth = stringWidth(sessionLabel), sessionBarStr = `${sessionLabel}${"".padEnd(Math.max(0, labelWidth - sessionLabelWidth))} ${sessionProgressBar} ${sessionRightText}`, sessionBarPadded = sessionBarStr + " ".repeat(Math.max(0, boxWidth - 3 - stringWidth(sessionBarStr)));
|
|
2935
3116
|
terminal.write(`${marginStr}│ ${sessionBarPadded}│\n`);
|
|
2936
|
-
const sessionCol1 = `${import_picocolors$
|
|
3117
|
+
const sessionCol1 = `${import_picocolors$4.default.gray("Started:")} ${startTime}`, sessionCol2 = `${import_picocolors$4.default.gray("Elapsed:")} ${prettyMilliseconds(elapsed * 60 * 1e3, { compact: true })}`, sessionCol3 = `${import_picocolors$4.default.gray("Remaining:")} ${prettyMilliseconds(remaining * 60 * 1e3, { compact: true })} (${endTime})`;
|
|
2937
3118
|
let sessionDetails = `${" ".repeat(detailsIndent)}${sessionCol1}${" ".repeat(detailsSpacing)}${sessionCol2}${" ".repeat(detailsSpacing)}${sessionCol3}`;
|
|
2938
3119
|
const sessionDetailsWidth = stringWidth(sessionCol1) + stringWidth(sessionCol2) + stringWidth(sessionCol3) + detailsSpacing * 2;
|
|
2939
3120
|
if (sessionDetailsWidth > detailsAvailableWidth) sessionDetails = `${" ".repeat(detailsIndent)}${sessionCol1}${" ".repeat(detailsSpacing)}${sessionCol3}`;
|
|
@@ -2944,33 +3125,33 @@ function renderLiveDisplay(terminal, block, config) {
|
|
|
2944
3125
|
hour: "2-digit",
|
|
2945
3126
|
minute: "2-digit",
|
|
2946
3127
|
hour12: true
|
|
2947
|
-
}) ?? null, usageLimitResetTime = resetTime !== null ? import_picocolors$
|
|
3128
|
+
}) ?? null, usageLimitResetTime = resetTime !== null ? import_picocolors$4.default.red(`${drawEmoji("❌")} USAGE LIMIT. RESET AT ${resetTime}`) : "";
|
|
2948
3129
|
usageLimitResetTimePadded = resetTime !== null ? usageLimitResetTime + " ".repeat(Math.max(0, boxWidth - 3 - stringWidth(usageLimitResetTime))) : null;
|
|
2949
3130
|
}
|
|
2950
3131
|
if (terminal.write(`${marginStr}│ ${sessionDetailsPadded}│\n`), usageLimitResetTimePadded !== null) terminal.write(`${marginStr}│ ${usageLimitResetTimePadded}│\n`);
|
|
2951
3132
|
terminal.write(`${marginStr}│${" ".repeat(boxWidth - 2)}│\n`), terminal.write(`${marginStr}├${"─".repeat(boxWidth - 2)}┤\n`), terminal.write(`${marginStr}│${" ".repeat(boxWidth - 2)}│\n`);
|
|
2952
|
-
let barColor = import_picocolors$
|
|
2953
|
-
if (tokenPercent > 100) barColor = import_picocolors$
|
|
2954
|
-
else if (tokenPercent > 80) barColor = import_picocolors$
|
|
3133
|
+
let barColor = import_picocolors$4.default.green;
|
|
3134
|
+
if (tokenPercent > 100) barColor = import_picocolors$4.default.red;
|
|
3135
|
+
else if (tokenPercent > 80) barColor = import_picocolors$4.default.yellow;
|
|
2955
3136
|
const usageBar = config.tokenLimit != null && config.tokenLimit > 0 ? createProgressBar(totalTokens, config.tokenLimit, barWidth, {
|
|
2956
3137
|
showPercentage: false,
|
|
2957
3138
|
fillChar: barColor("█"),
|
|
2958
|
-
emptyChar: import_picocolors$
|
|
3139
|
+
emptyChar: import_picocolors$4.default.gray("░"),
|
|
2959
3140
|
leftBracket: "[",
|
|
2960
3141
|
rightBracket: "]"
|
|
2961
|
-
}) : `[${import_picocolors$
|
|
2962
|
-
if (burnRate == null) return `${import_picocolors$
|
|
3142
|
+
}) : `[${import_picocolors$4.default.green("█".repeat(Math.floor(barWidth * .1)))}${import_picocolors$4.default.gray("░".repeat(barWidth - Math.floor(barWidth * .1)))}]`, burnRate = calculateBurnRate(block), rateIndicator = getRateIndicator(burnRate), buildRateDisplay = (useShort) => {
|
|
3143
|
+
if (burnRate == null) return `${import_picocolors$4.default.bold("Burn Rate:")} N/A`;
|
|
2963
3144
|
const rateValue = Math.round(burnRate.tokensPerMinute), formattedRate = useShort ? formatTokensShort(rateValue) : formatNumber(rateValue);
|
|
2964
|
-
return `${import_picocolors$
|
|
2965
|
-
}, usageLabel = `${drawEmoji("🔥")}${import_picocolors$
|
|
2966
|
-
let rateDisplay = buildRateDisplay(false), usageCol1 = `${import_picocolors$
|
|
2967
|
-
const usageCol3 = `${import_picocolors$
|
|
3145
|
+
return `${import_picocolors$4.default.bold("Burn Rate:")} ${formattedRate} token/min ${rateIndicator}`;
|
|
3146
|
+
}, usageLabel = `${drawEmoji("🔥")}${import_picocolors$4.default.bold(" USAGE")}`, usageLabelWidth = stringWidth(usageLabel), usageBarStr = `${usageLabel}${"".padEnd(Math.max(0, labelWidth - usageLabelWidth))} ${usageBar} ${usageRightText}`;
|
|
3147
|
+
let rateDisplay = buildRateDisplay(false), usageCol1 = `${import_picocolors$4.default.gray("Tokens:")} ${formatTokenDisplay(totalTokens, false)} (${rateDisplay})`, usageCol2 = config.tokenLimit != null && config.tokenLimit > 0 ? `${import_picocolors$4.default.gray("Limit:")} ${formatTokenDisplay(config.tokenLimit, false)} tokens` : "";
|
|
3148
|
+
const usageCol3 = `${import_picocolors$4.default.gray("Cost:")} ${formatCurrency(block.costUSD)}`;
|
|
2968
3149
|
let totalWidth = stringWidth(usageCol1);
|
|
2969
3150
|
if (usageCol2.length > 0) totalWidth += detailsSpacing + stringWidth(usageCol2);
|
|
2970
3151
|
totalWidth += detailsSpacing + stringWidth(usageCol3);
|
|
2971
3152
|
let useTwoLineLayout = false;
|
|
2972
3153
|
if (totalWidth > detailsAvailableWidth) {
|
|
2973
|
-
if (useTwoLineLayout = true, rateDisplay = buildRateDisplay(true), usageCol1 = `${import_picocolors$
|
|
3154
|
+
if (useTwoLineLayout = true, rateDisplay = buildRateDisplay(true), usageCol1 = `${import_picocolors$4.default.gray("Tokens:")} ${formatTokenDisplay(totalTokens, true)} (${rateDisplay})`, usageCol2.length > 0) usageCol2 = `${import_picocolors$4.default.gray("Limit:")} ${formatTokenDisplay(config.tokenLimit, true)} tokens`;
|
|
2974
3155
|
}
|
|
2975
3156
|
const usageBarPadded = usageBarStr + " ".repeat(Math.max(0, boxWidth - 3 - stringWidth(usageBarStr)));
|
|
2976
3157
|
if (terminal.write(`${marginStr}│ ${usageBarPadded}│\n`), useTwoLineLayout) {
|
|
@@ -2989,22 +3170,22 @@ function renderLiveDisplay(terminal, block, config) {
|
|
|
2989
3170
|
terminal.write(`${marginStr}│ ${usageDetailsPadded}│\n`);
|
|
2990
3171
|
}
|
|
2991
3172
|
if (terminal.write(`${marginStr}│${" ".repeat(boxWidth - 2)}│\n`), terminal.write(`${marginStr}├${"─".repeat(boxWidth - 2)}┤\n`), terminal.write(`${marginStr}│${" ".repeat(boxWidth - 2)}│\n`), projection != null) {
|
|
2992
|
-
let projBarColor = import_picocolors$
|
|
2993
|
-
if (projectedPercent > 100) projBarColor = import_picocolors$
|
|
2994
|
-
else if (projectedPercent > 80) projBarColor = import_picocolors$
|
|
3173
|
+
let projBarColor = import_picocolors$4.default.green;
|
|
3174
|
+
if (projectedPercent > 100) projBarColor = import_picocolors$4.default.red;
|
|
3175
|
+
else if (projectedPercent > 80) projBarColor = import_picocolors$4.default.yellow;
|
|
2995
3176
|
const projectionBar = config.tokenLimit != null && config.tokenLimit > 0 ? createProgressBar(projection.totalTokens, config.tokenLimit, barWidth, {
|
|
2996
3177
|
showPercentage: false,
|
|
2997
3178
|
fillChar: projBarColor("█"),
|
|
2998
|
-
emptyChar: import_picocolors$
|
|
3179
|
+
emptyChar: import_picocolors$4.default.gray("░"),
|
|
2999
3180
|
leftBracket: "[",
|
|
3000
3181
|
rightBracket: "]"
|
|
3001
|
-
}) : `[${import_picocolors$
|
|
3182
|
+
}) : `[${import_picocolors$4.default.green("█".repeat(Math.floor(barWidth * .15)))}${import_picocolors$4.default.gray("░".repeat(barWidth - Math.floor(barWidth * .15)))}]`, limitStatus = config.tokenLimit != null && config.tokenLimit > 0 ? projectedPercent > 100 ? import_picocolors$4.default.red(`${drawEmoji("❌")} WILL EXCEED LIMIT`) : projectedPercent > 80 ? import_picocolors$4.default.yellow(`${drawEmoji("⚠️")} APPROACHING LIMIT`) : import_picocolors$4.default.green(`${drawEmoji("✓")} WITHIN LIMIT`) : import_picocolors$4.default.green(`${drawEmoji("✓")} ON TRACK`), projLabel = `${drawEmoji("📈")}${import_picocolors$4.default.bold(" PROJECTION")}`, projLabelWidth = stringWidth(projLabel), projBarStr = `${projLabel}${"".padEnd(Math.max(0, labelWidth - projLabelWidth))} ${projectionBar} ${projectionRightText}`, projBarPadded = projBarStr + " ".repeat(Math.max(0, boxWidth - 3 - stringWidth(projBarStr)));
|
|
3002
3183
|
terminal.write(`${marginStr}│ ${projBarPadded}│\n`);
|
|
3003
|
-
const projCol1 = `${import_picocolors$
|
|
3004
|
-
let projCol2 = `${import_picocolors$
|
|
3005
|
-
const projCol3 = `${import_picocolors$
|
|
3184
|
+
const projCol1 = `${import_picocolors$4.default.gray("Status:")} ${limitStatus}`;
|
|
3185
|
+
let projCol2 = `${import_picocolors$4.default.gray("Tokens:")} ${formatTokenDisplay(projection.totalTokens, false)}`;
|
|
3186
|
+
const projCol3 = `${import_picocolors$4.default.gray("Cost:")} ${formatCurrency(projection.totalCost)}`, projTotalWidth = stringWidth(projCol1) + stringWidth(projCol2) + stringWidth(projCol3) + detailsSpacing * 2;
|
|
3006
3187
|
let projUseTwoLineLayout = false;
|
|
3007
|
-
if (projTotalWidth > detailsAvailableWidth) projUseTwoLineLayout = true, projCol2 = `${import_picocolors$
|
|
3188
|
+
if (projTotalWidth > detailsAvailableWidth) projUseTwoLineLayout = true, projCol2 = `${import_picocolors$4.default.gray("Tokens:")} ${formatTokenDisplay(projection.totalTokens, true)}`;
|
|
3008
3189
|
if (projUseTwoLineLayout) {
|
|
3009
3190
|
const projDetailsLine1 = `${" ".repeat(detailsIndent)}${projCol1}`, projDetailsLine1Padded = projDetailsLine1 + " ".repeat(Math.max(0, boxWidth - 3 - stringWidth(projDetailsLine1)));
|
|
3010
3191
|
terminal.write(`${marginStr}│ ${projDetailsLine1Padded}│\n`);
|
|
@@ -3023,37 +3204,37 @@ function renderLiveDisplay(terminal, block, config) {
|
|
|
3023
3204
|
}
|
|
3024
3205
|
terminal.write(`${marginStr}├${"─".repeat(boxWidth - 2)}┤\n`);
|
|
3025
3206
|
const refreshText = `${drawEmoji("↻")} Refreshing every ${config.refreshInterval / 1e3}s • Press Ctrl+C to stop`;
|
|
3026
|
-
terminal.write(`${marginStr}│${import_picocolors$
|
|
3207
|
+
terminal.write(`${marginStr}│${import_picocolors$4.default.gray(centerText(refreshText, boxWidth - 2))}│\n`), terminal.write(`${marginStr}└${"─".repeat(boxWidth - 2)}┘\n`);
|
|
3027
3208
|
}
|
|
3028
3209
|
function renderCompactLiveDisplay(terminal, block, config, totalTokens, elapsed, remaining) {
|
|
3029
3210
|
const width = terminal.width;
|
|
3030
|
-
terminal.write(`${import_picocolors$
|
|
3211
|
+
terminal.write(`${import_picocolors$4.default.bold(centerText("LIVE MONITOR", width))}\n`), terminal.write(`${"─".repeat(width)}\n`);
|
|
3031
3212
|
const sessionPercent = elapsed / (elapsed + remaining) * 100;
|
|
3032
3213
|
if (terminal.write(`Session: ${sessionPercent.toFixed(1)}% (${Math.floor(elapsed / 60)}h ${Math.floor(elapsed % 60)}m)\n`), config.tokenLimit != null && config.tokenLimit > 0) {
|
|
3033
|
-
const tokenPercent = totalTokens / config.tokenLimit * 100, status = tokenPercent > 100 ? import_picocolors$
|
|
3214
|
+
const tokenPercent = totalTokens / config.tokenLimit * 100, status = tokenPercent > 100 ? import_picocolors$4.default.red("OVER") : tokenPercent > 80 ? import_picocolors$4.default.yellow("WARN") : import_picocolors$4.default.green("OK");
|
|
3034
3215
|
terminal.write(`Tokens: ${formatNumber(totalTokens)}/${formatNumber(config.tokenLimit)} ${status}\n`);
|
|
3035
3216
|
} else terminal.write(`Tokens: ${formatNumber(totalTokens)}\n`);
|
|
3036
3217
|
terminal.write(`Cost: ${formatCurrency(block.costUSD)}\n`);
|
|
3037
3218
|
const burnRate = calculateBurnRate(block);
|
|
3038
3219
|
if (burnRate != null) terminal.write(`Rate: ${formatNumber(burnRate.tokensPerMinute)}/min\n`);
|
|
3039
|
-
terminal.write(`${"─".repeat(width)}\n`), terminal.write(import_picocolors$
|
|
3220
|
+
terminal.write(`${"─".repeat(width)}\n`), terminal.write(import_picocolors$4.default.gray(`Refresh: ${config.refreshInterval / 1e3}s | Ctrl+C: stop\n`));
|
|
3040
3221
|
}
|
|
3041
|
-
var import_picocolors$
|
|
3222
|
+
var import_picocolors$3 = /* @__PURE__ */ __toESM(require_picocolors(), 1), import_usingCtx$1 = /* @__PURE__ */ __toESM(require_usingCtx(), 1);
|
|
3042
3223
|
async function startLiveMonitoring(config) {
|
|
3043
3224
|
try {
|
|
3044
3225
|
var _usingCtx = (0, import_usingCtx$1.default)();
|
|
3045
3226
|
const terminal = new TerminalManager(), abortController = new AbortController();
|
|
3046
3227
|
let lastRenderTime = 0;
|
|
3047
|
-
const
|
|
3048
|
-
if (abortController.abort(), terminal.cleanup(), terminal.clearScreen(), logger.info("Live monitoring stopped."), process$1.exitCode == null) process$1.exit(0);
|
|
3049
|
-
};
|
|
3050
|
-
process$1.on("SIGINT", cleanup), process$1.on("SIGTERM", cleanup), terminal.enterAlternateScreen(), terminal.enableSyncMode(), terminal.clearScreen(), terminal.hideCursor();
|
|
3051
|
-
const monitor = _usingCtx.u(new LiveMonitor({
|
|
3228
|
+
const monitorConfig = {
|
|
3052
3229
|
claudePaths: config.claudePaths,
|
|
3053
3230
|
sessionDurationHours: config.sessionDurationHours,
|
|
3054
3231
|
mode: config.mode,
|
|
3055
3232
|
order: config.order
|
|
3056
|
-
})),
|
|
3233
|
+
}, monitorState = _usingCtx.u(createLiveMonitorState(monitorConfig)), cleanup = () => {
|
|
3234
|
+
if (abortController.abort(), terminal.cleanup(), terminal.clearScreen(), logger.info("Live monitoring stopped."), process$1.exitCode == null) process$1.exit(0);
|
|
3235
|
+
};
|
|
3236
|
+
process$1.on("SIGINT", cleanup), process$1.on("SIGTERM", cleanup), terminal.enterAlternateScreen(), terminal.enableSyncMode(), terminal.clearScreen(), terminal.hideCursor();
|
|
3237
|
+
const monitoringResult = await try_({
|
|
3057
3238
|
try: async () => {
|
|
3058
3239
|
while (!abortController.signal.aborted) {
|
|
3059
3240
|
const now = Date.now(), timeSinceLastRender = now - lastRenderTime;
|
|
@@ -3061,8 +3242,8 @@ async function startLiveMonitoring(config) {
|
|
|
3061
3242
|
await delayWithAbort(MIN_RENDER_INTERVAL_MS - timeSinceLastRender, abortController.signal);
|
|
3062
3243
|
continue;
|
|
3063
3244
|
}
|
|
3064
|
-
const activeBlock = await
|
|
3065
|
-
if (
|
|
3245
|
+
const activeBlock = await getActiveBlock(monitorState, monitorConfig);
|
|
3246
|
+
if (clearLiveMonitorCache(monitorState), activeBlock == null) {
|
|
3066
3247
|
await renderWaitingState(terminal, config, abortController.signal);
|
|
3067
3248
|
continue;
|
|
3068
3249
|
}
|
|
@@ -3083,7 +3264,7 @@ async function startLiveMonitoring(config) {
|
|
|
3083
3264
|
const error = monitoringResult.error;
|
|
3084
3265
|
if ((error instanceof DOMException || error instanceof Error) && error.name === "AbortError") return;
|
|
3085
3266
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3086
|
-
terminal.startBuffering(), terminal.clearScreen(), terminal.write(import_picocolors$
|
|
3267
|
+
terminal.startBuffering(), terminal.clearScreen(), terminal.write(import_picocolors$3.default.red(`Error: ${errorMessage}\n`)), terminal.flush(), logger.error(`Live monitoring error: ${errorMessage}`), await delayWithAbort(config.refreshInterval, abortController.signal).catch(() => {});
|
|
3087
3268
|
}
|
|
3088
3269
|
} catch (_) {
|
|
3089
3270
|
_usingCtx.e = _;
|
|
@@ -3091,7 +3272,7 @@ async function startLiveMonitoring(config) {
|
|
|
3091
3272
|
_usingCtx.d();
|
|
3092
3273
|
}
|
|
3093
3274
|
}
|
|
3094
|
-
var import_picocolors$
|
|
3275
|
+
var import_picocolors$2 = /* @__PURE__ */ __toESM(require_picocolors(), 1);
|
|
3095
3276
|
function formatBlockTime(block, compact = false, locale) {
|
|
3096
3277
|
const start = compact ? block.startTime.toLocaleString(locale, {
|
|
3097
3278
|
month: "2-digit",
|
|
@@ -3260,13 +3441,13 @@ const blocksCommand = define({
|
|
|
3260
3441
|
const burnRate = calculateBurnRate(block), projection = projectBlockUsage(block);
|
|
3261
3442
|
logger.box("Current Session Block Status");
|
|
3262
3443
|
const now = /* @__PURE__ */ new Date(), elapsed = Math.round((now.getTime() - block.startTime.getTime()) / (1e3 * 60)), remaining = Math.round((block.endTime.getTime() - now.getTime()) / (1e3 * 60));
|
|
3263
|
-
if (log(`Block Started: ${import_picocolors$
|
|
3444
|
+
if (log(`Block Started: ${import_picocolors$2.default.cyan(block.startTime.toLocaleString())} (${import_picocolors$2.default.yellow(`${Math.floor(elapsed / 60)}h ${elapsed % 60}m`)} ago)`), log(`Time Remaining: ${import_picocolors$2.default.green(`${Math.floor(remaining / 60)}h ${remaining % 60}m`)}\n`), log(import_picocolors$2.default.bold("Current Usage:")), log(` Input Tokens: ${formatNumber(block.tokenCounts.inputTokens)}`), log(` Output Tokens: ${formatNumber(block.tokenCounts.outputTokens)}`), log(` Total Cost: ${formatCurrency(block.costUSD)}\n`), burnRate != null) log(import_picocolors$2.default.bold("Burn Rate:")), log(` Tokens/minute: ${formatNumber(burnRate.tokensPerMinute)}`), log(` Cost/hour: ${formatCurrency(burnRate.costPerHour)}\n`);
|
|
3264
3445
|
if (projection != null) {
|
|
3265
|
-
if (log(import_picocolors$
|
|
3446
|
+
if (log(import_picocolors$2.default.bold("Projected Usage (if current rate continues):")), log(` Total Tokens: ${formatNumber(projection.totalTokens)}`), log(` Total Cost: ${formatCurrency(projection.totalCost)}\n`), ctx.values.tokenLimit != null) {
|
|
3266
3447
|
const limit = parseTokenLimit(ctx.values.tokenLimit, maxTokensFromAll);
|
|
3267
3448
|
if (limit != null && limit > 0) {
|
|
3268
|
-
const currentTokens = getTotalTokens(block.tokenCounts), remainingTokens = Math.max(0, limit - currentTokens), percentUsed = projection.totalTokens / limit * 100, status = percentUsed > 100 ? import_picocolors$
|
|
3269
|
-
log(import_picocolors$
|
|
3449
|
+
const currentTokens = getTotalTokens(block.tokenCounts), remainingTokens = Math.max(0, limit - currentTokens), percentUsed = projection.totalTokens / limit * 100, status = percentUsed > 100 ? import_picocolors$2.default.red("EXCEEDS LIMIT") : percentUsed > BLOCKS_WARNING_THRESHOLD * 100 ? import_picocolors$2.default.yellow("WARNING") : import_picocolors$2.default.green("OK");
|
|
3450
|
+
log(import_picocolors$2.default.bold("Token Limit Status:")), log(` Limit: ${formatNumber(limit)} tokens`), log(` Current Usage: ${formatNumber(currentTokens)} (${(currentTokens / limit * 100).toFixed(1)}%)`), log(` Remaining: ${formatNumber(remainingTokens)} tokens`), log(` Projected Usage: ${percentUsed.toFixed(1)}% ${status}`);
|
|
3270
3451
|
}
|
|
3271
3452
|
}
|
|
3272
3453
|
}
|
|
@@ -3292,15 +3473,15 @@ const blocksCommand = define({
|
|
|
3292
3473
|
}), terminalWidth = process$1.stdout.columns || BLOCKS_DEFAULT_TERMINAL_WIDTH, isNarrowTerminal = terminalWidth < BLOCKS_COMPACT_WIDTH_THRESHOLD, useCompactFormat = ctx.values.compact || isNarrowTerminal;
|
|
3293
3474
|
for (const block of blocks) if (block.isGap ?? false) {
|
|
3294
3475
|
const gapRow = [
|
|
3295
|
-
import_picocolors$
|
|
3296
|
-
import_picocolors$
|
|
3297
|
-
import_picocolors$
|
|
3298
|
-
import_picocolors$
|
|
3476
|
+
import_picocolors$2.default.gray(formatBlockTime(block, useCompactFormat, ctx.values.locale)),
|
|
3477
|
+
import_picocolors$2.default.gray("(inactive)"),
|
|
3478
|
+
import_picocolors$2.default.gray("-"),
|
|
3479
|
+
import_picocolors$2.default.gray("-")
|
|
3299
3480
|
];
|
|
3300
|
-
if (actualTokenLimit != null && actualTokenLimit > 0) gapRow.push(import_picocolors$
|
|
3301
|
-
gapRow.push(import_picocolors$
|
|
3481
|
+
if (actualTokenLimit != null && actualTokenLimit > 0) gapRow.push(import_picocolors$2.default.gray("-"));
|
|
3482
|
+
gapRow.push(import_picocolors$2.default.gray("-")), table.push(gapRow);
|
|
3302
3483
|
} else {
|
|
3303
|
-
const totalTokens = getTotalTokens(block.tokenCounts), status = block.isActive ? import_picocolors$
|
|
3484
|
+
const totalTokens = getTotalTokens(block.tokenCounts), status = block.isActive ? import_picocolors$2.default.green("ACTIVE") : "", row = [
|
|
3304
3485
|
formatBlockTime(block, useCompactFormat, ctx.values.locale),
|
|
3305
3486
|
status,
|
|
3306
3487
|
formatModels(block.models),
|
|
@@ -3308,16 +3489,16 @@ const blocksCommand = define({
|
|
|
3308
3489
|
];
|
|
3309
3490
|
if (actualTokenLimit != null && actualTokenLimit > 0) {
|
|
3310
3491
|
const percentage = totalTokens / actualTokenLimit * 100, percentText = `${percentage.toFixed(1)}%`;
|
|
3311
|
-
row.push(percentage > 100 ? import_picocolors$
|
|
3492
|
+
row.push(percentage > 100 ? import_picocolors$2.default.red(percentText) : percentText);
|
|
3312
3493
|
}
|
|
3313
3494
|
if (row.push(formatCurrency(block.costUSD)), table.push(row), block.isActive) {
|
|
3314
3495
|
if (actualTokenLimit != null && actualTokenLimit > 0) {
|
|
3315
|
-
const currentTokens = getTotalTokens(block.tokenCounts), remainingTokens = Math.max(0, actualTokenLimit - currentTokens), remainingText = remainingTokens > 0 ? formatNumber(remainingTokens) : import_picocolors$
|
|
3496
|
+
const currentTokens = getTotalTokens(block.tokenCounts), remainingTokens = Math.max(0, actualTokenLimit - currentTokens), remainingText = remainingTokens > 0 ? formatNumber(remainingTokens) : import_picocolors$2.default.red("0"), remainingPercent = (actualTokenLimit - currentTokens) / actualTokenLimit * 100, remainingPercentText = remainingPercent > 0 ? `${remainingPercent.toFixed(1)}%` : import_picocolors$2.default.red("0.0%"), remainingRow = [
|
|
3316
3497
|
{
|
|
3317
|
-
content: import_picocolors$
|
|
3498
|
+
content: import_picocolors$2.default.gray(`(assuming ${formatNumber(actualTokenLimit)} token limit)`),
|
|
3318
3499
|
hAlign: "right"
|
|
3319
3500
|
},
|
|
3320
|
-
import_picocolors$
|
|
3501
|
+
import_picocolors$2.default.blue("REMAINING"),
|
|
3321
3502
|
"",
|
|
3322
3503
|
remainingText,
|
|
3323
3504
|
remainingPercentText,
|
|
@@ -3327,12 +3508,12 @@ const blocksCommand = define({
|
|
|
3327
3508
|
}
|
|
3328
3509
|
const projection = projectBlockUsage(block);
|
|
3329
3510
|
if (projection != null) {
|
|
3330
|
-
const projectedTokens = formatNumber(projection.totalTokens), projectedText = actualTokenLimit != null && actualTokenLimit > 0 && projection.totalTokens > actualTokenLimit ? import_picocolors$
|
|
3511
|
+
const projectedTokens = formatNumber(projection.totalTokens), projectedText = actualTokenLimit != null && actualTokenLimit > 0 && projection.totalTokens > actualTokenLimit ? import_picocolors$2.default.red(projectedTokens) : projectedTokens, projectedRow = [
|
|
3331
3512
|
{
|
|
3332
|
-
content: import_picocolors$
|
|
3513
|
+
content: import_picocolors$2.default.gray("(assuming current burn rate)"),
|
|
3333
3514
|
hAlign: "right"
|
|
3334
3515
|
},
|
|
3335
|
-
import_picocolors$
|
|
3516
|
+
import_picocolors$2.default.yellow("PROJECTED"),
|
|
3336
3517
|
"",
|
|
3337
3518
|
projectedText
|
|
3338
3519
|
];
|
|
@@ -3411,7 +3592,7 @@ function formatProjectName(projectName, aliases) {
|
|
|
3411
3592
|
const parsed = parseProjectName(projectName);
|
|
3412
3593
|
return aliases != null && aliases.has(parsed) ? aliases.get(parsed) : parsed;
|
|
3413
3594
|
}
|
|
3414
|
-
var import_picocolors$
|
|
3595
|
+
var import_picocolors$1 = /* @__PURE__ */ __toESM(require_picocolors(), 1);
|
|
3415
3596
|
const dailyCommand = define({
|
|
3416
3597
|
name: "daily",
|
|
3417
3598
|
description: "Show usage report grouped by date",
|
|
@@ -3488,46 +3669,11 @@ const dailyCommand = define({
|
|
|
3488
3669
|
} else log(JSON.stringify(jsonOutput, null, 2));
|
|
3489
3670
|
} else {
|
|
3490
3671
|
logger.box("Claude Code Token Usage Report - Daily");
|
|
3491
|
-
const
|
|
3492
|
-
|
|
3493
|
-
"Date",
|
|
3494
|
-
"Models",
|
|
3495
|
-
"Input",
|
|
3496
|
-
"Output",
|
|
3497
|
-
"Cache Create",
|
|
3498
|
-
"Cache Read",
|
|
3499
|
-
"Total Tokens",
|
|
3500
|
-
"Cost (USD)"
|
|
3501
|
-
],
|
|
3502
|
-
style: { head: ["cyan"] },
|
|
3503
|
-
colAligns: [
|
|
3504
|
-
"left",
|
|
3505
|
-
"left",
|
|
3506
|
-
"right",
|
|
3507
|
-
"right",
|
|
3508
|
-
"right",
|
|
3509
|
-
"right",
|
|
3510
|
-
"right",
|
|
3511
|
-
"right"
|
|
3512
|
-
],
|
|
3672
|
+
const tableConfig = {
|
|
3673
|
+
firstColumnName: "Date",
|
|
3513
3674
|
dateFormatter: (dateStr) => formatDateCompact(dateStr, mergedOptions.timezone, mergedOptions.locale ?? void 0),
|
|
3514
|
-
compactHead: [
|
|
3515
|
-
"Date",
|
|
3516
|
-
"Models",
|
|
3517
|
-
"Input",
|
|
3518
|
-
"Output",
|
|
3519
|
-
"Cost (USD)"
|
|
3520
|
-
],
|
|
3521
|
-
compactColAligns: [
|
|
3522
|
-
"left",
|
|
3523
|
-
"left",
|
|
3524
|
-
"right",
|
|
3525
|
-
"right",
|
|
3526
|
-
"right"
|
|
3527
|
-
],
|
|
3528
|
-
compactThreshold: 100,
|
|
3529
3675
|
forceCompact: ctx.values.compact
|
|
3530
|
-
});
|
|
3676
|
+
}, table = createUsageReportTable(tableConfig);
|
|
3531
3677
|
if (Boolean(mergedOptions.instances) && dailyData.some((d) => d.project != null)) {
|
|
3532
3678
|
const projectGroups = groupDataByProject(dailyData);
|
|
3533
3679
|
let isFirstProject = true;
|
|
@@ -3543,7 +3689,7 @@ const dailyCommand = define({
|
|
|
3543
3689
|
""
|
|
3544
3690
|
]);
|
|
3545
3691
|
table.push([
|
|
3546
|
-
import_picocolors$
|
|
3692
|
+
import_picocolors$1.default.cyan(`Project: ${formatProjectName(projectName, projectAliases)}`),
|
|
3547
3693
|
"",
|
|
3548
3694
|
"",
|
|
3549
3695
|
"",
|
|
@@ -3552,47 +3698,39 @@ const dailyCommand = define({
|
|
|
3552
3698
|
"",
|
|
3553
3699
|
""
|
|
3554
3700
|
]);
|
|
3555
|
-
for (const data of projectData)
|
|
3556
|
-
data.date,
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
|
|
3701
|
+
for (const data of projectData) {
|
|
3702
|
+
const row = formatUsageDataRow(data.date, {
|
|
3703
|
+
inputTokens: data.inputTokens,
|
|
3704
|
+
outputTokens: data.outputTokens,
|
|
3705
|
+
cacheCreationTokens: data.cacheCreationTokens,
|
|
3706
|
+
cacheReadTokens: data.cacheReadTokens,
|
|
3707
|
+
totalCost: data.totalCost,
|
|
3708
|
+
modelsUsed: data.modelsUsed
|
|
3709
|
+
});
|
|
3710
|
+
if (table.push(row), mergedOptions.breakdown) pushBreakdownRows(table, data.modelBreakdowns);
|
|
3711
|
+
}
|
|
3565
3712
|
isFirstProject = false;
|
|
3566
3713
|
}
|
|
3567
|
-
} else for (const data of dailyData)
|
|
3568
|
-
data.date,
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
import_picocolors$4.default.yellow("Total"),
|
|
3588
|
-
"",
|
|
3589
|
-
import_picocolors$4.default.yellow(formatNumber(totals.inputTokens)),
|
|
3590
|
-
import_picocolors$4.default.yellow(formatNumber(totals.outputTokens)),
|
|
3591
|
-
import_picocolors$4.default.yellow(formatNumber(totals.cacheCreationTokens)),
|
|
3592
|
-
import_picocolors$4.default.yellow(formatNumber(totals.cacheReadTokens)),
|
|
3593
|
-
import_picocolors$4.default.yellow(formatNumber(getTotalTokens(totals))),
|
|
3594
|
-
import_picocolors$4.default.yellow(formatCurrency(totals.totalCost))
|
|
3595
|
-
]), log(table.toString()), table.isCompactMode()) logger.info("\nRunning in Compact Mode"), logger.info("Expand terminal width to see cache metrics and total tokens");
|
|
3714
|
+
} else for (const data of dailyData) {
|
|
3715
|
+
const row = formatUsageDataRow(data.date, {
|
|
3716
|
+
inputTokens: data.inputTokens,
|
|
3717
|
+
outputTokens: data.outputTokens,
|
|
3718
|
+
cacheCreationTokens: data.cacheCreationTokens,
|
|
3719
|
+
cacheReadTokens: data.cacheReadTokens,
|
|
3720
|
+
totalCost: data.totalCost,
|
|
3721
|
+
modelsUsed: data.modelsUsed
|
|
3722
|
+
});
|
|
3723
|
+
if (table.push(row), mergedOptions.breakdown) pushBreakdownRows(table, data.modelBreakdowns);
|
|
3724
|
+
}
|
|
3725
|
+
addEmptySeparatorRow(table, 8);
|
|
3726
|
+
const totalsRow = formatTotalsRow({
|
|
3727
|
+
inputTokens: totals.inputTokens,
|
|
3728
|
+
outputTokens: totals.outputTokens,
|
|
3729
|
+
cacheCreationTokens: totals.cacheCreationTokens,
|
|
3730
|
+
cacheReadTokens: totals.cacheReadTokens,
|
|
3731
|
+
totalCost: totals.totalCost
|
|
3732
|
+
});
|
|
3733
|
+
if (table.push(totalsRow), log(table.toString()), table.isCompactMode()) logger.info("\nRunning in Compact Mode"), logger.info("Expand terminal width to see cache metrics and total tokens");
|
|
3596
3734
|
}
|
|
3597
3735
|
}
|
|
3598
3736
|
});
|
|
@@ -3978,9 +4116,7 @@ const mcpCommand = define({
|
|
|
3978
4116
|
}), logger.info(`MCP server is running on http://localhost:${port}`);
|
|
3979
4117
|
}
|
|
3980
4118
|
}
|
|
3981
|
-
})
|
|
3982
|
-
var import_picocolors$3 = /* @__PURE__ */ __toESM(require_picocolors(), 1);
|
|
3983
|
-
const monthlyCommand = define({
|
|
4119
|
+
}), monthlyCommand = define({
|
|
3984
4120
|
name: "monthly",
|
|
3985
4121
|
description: "Show usage report grouped by month",
|
|
3986
4122
|
...sharedCommandConfig,
|
|
@@ -4032,75 +4168,31 @@ const monthlyCommand = define({
|
|
|
4032
4168
|
} else log(JSON.stringify(jsonOutput, null, 2));
|
|
4033
4169
|
} else {
|
|
4034
4170
|
logger.box("Claude Code Token Usage Report - Monthly");
|
|
4035
|
-
const
|
|
4036
|
-
|
|
4037
|
-
|
|
4038
|
-
"Models",
|
|
4039
|
-
"Input",
|
|
4040
|
-
"Output",
|
|
4041
|
-
"Cache Create",
|
|
4042
|
-
"Cache Read",
|
|
4043
|
-
"Total Tokens",
|
|
4044
|
-
"Cost (USD)"
|
|
4045
|
-
],
|
|
4046
|
-
style: { head: ["cyan"] },
|
|
4047
|
-
colAligns: [
|
|
4048
|
-
"left",
|
|
4049
|
-
"left",
|
|
4050
|
-
"right",
|
|
4051
|
-
"right",
|
|
4052
|
-
"right",
|
|
4053
|
-
"right",
|
|
4054
|
-
"right",
|
|
4055
|
-
"right"
|
|
4056
|
-
],
|
|
4057
|
-
dateFormatter: (dateStr) => formatDateCompact(dateStr, mergedOptions.timezone, mergedOptions.locale ?? "en-CA"),
|
|
4058
|
-
compactHead: [
|
|
4059
|
-
"Month",
|
|
4060
|
-
"Models",
|
|
4061
|
-
"Input",
|
|
4062
|
-
"Output",
|
|
4063
|
-
"Cost (USD)"
|
|
4064
|
-
],
|
|
4065
|
-
compactColAligns: [
|
|
4066
|
-
"left",
|
|
4067
|
-
"left",
|
|
4068
|
-
"right",
|
|
4069
|
-
"right",
|
|
4070
|
-
"right"
|
|
4071
|
-
],
|
|
4072
|
-
compactThreshold: 100,
|
|
4171
|
+
const tableConfig = {
|
|
4172
|
+
firstColumnName: "Month",
|
|
4173
|
+
dateFormatter: (dateStr) => formatDateCompact(dateStr, mergedOptions.timezone, mergedOptions.locale ?? DEFAULT_LOCALE),
|
|
4073
4174
|
forceCompact: ctx.values.compact
|
|
4175
|
+
}, table = createUsageReportTable(tableConfig);
|
|
4176
|
+
for (const data of monthlyData) {
|
|
4177
|
+
const row = formatUsageDataRow(data.month, {
|
|
4178
|
+
inputTokens: data.inputTokens,
|
|
4179
|
+
outputTokens: data.outputTokens,
|
|
4180
|
+
cacheCreationTokens: data.cacheCreationTokens,
|
|
4181
|
+
cacheReadTokens: data.cacheReadTokens,
|
|
4182
|
+
totalCost: data.totalCost,
|
|
4183
|
+
modelsUsed: data.modelsUsed
|
|
4184
|
+
});
|
|
4185
|
+
if (table.push(row), mergedOptions.breakdown) pushBreakdownRows(table, data.modelBreakdowns);
|
|
4186
|
+
}
|
|
4187
|
+
addEmptySeparatorRow(table, 8);
|
|
4188
|
+
const totalsRow = formatTotalsRow({
|
|
4189
|
+
inputTokens: totals.inputTokens,
|
|
4190
|
+
outputTokens: totals.outputTokens,
|
|
4191
|
+
cacheCreationTokens: totals.cacheCreationTokens,
|
|
4192
|
+
cacheReadTokens: totals.cacheReadTokens,
|
|
4193
|
+
totalCost: totals.totalCost
|
|
4074
4194
|
});
|
|
4075
|
-
|
|
4076
|
-
data.month,
|
|
4077
|
-
formatModelsDisplayMultiline(data.modelsUsed),
|
|
4078
|
-
formatNumber(data.inputTokens),
|
|
4079
|
-
formatNumber(data.outputTokens),
|
|
4080
|
-
formatNumber(data.cacheCreationTokens),
|
|
4081
|
-
formatNumber(data.cacheReadTokens),
|
|
4082
|
-
formatNumber(getTotalTokens(data)),
|
|
4083
|
-
formatCurrency(data.totalCost)
|
|
4084
|
-
]), mergedOptions.breakdown) pushBreakdownRows(table, data.modelBreakdowns);
|
|
4085
|
-
if (table.push([
|
|
4086
|
-
"",
|
|
4087
|
-
"",
|
|
4088
|
-
"",
|
|
4089
|
-
"",
|
|
4090
|
-
"",
|
|
4091
|
-
"",
|
|
4092
|
-
"",
|
|
4093
|
-
""
|
|
4094
|
-
]), table.push([
|
|
4095
|
-
import_picocolors$3.default.yellow("Total"),
|
|
4096
|
-
"",
|
|
4097
|
-
import_picocolors$3.default.yellow(formatNumber(totals.inputTokens)),
|
|
4098
|
-
import_picocolors$3.default.yellow(formatNumber(totals.outputTokens)),
|
|
4099
|
-
import_picocolors$3.default.yellow(formatNumber(totals.cacheCreationTokens)),
|
|
4100
|
-
import_picocolors$3.default.yellow(formatNumber(totals.cacheReadTokens)),
|
|
4101
|
-
import_picocolors$3.default.yellow(formatNumber(getTotalTokens(totals))),
|
|
4102
|
-
import_picocolors$3.default.yellow(formatCurrency(totals.totalCost))
|
|
4103
|
-
]), log(table.toString()), table.isCompactMode()) logger.info("\nRunning in Compact Mode"), logger.info("Expand terminal width to see cache metrics and total tokens");
|
|
4195
|
+
if (table.push(totalsRow), log(table.toString()), table.isCompactMode()) logger.info("\nRunning in Compact Mode"), logger.info("Expand terminal width to see cache metrics and total tokens");
|
|
4104
4196
|
}
|
|
4105
4197
|
}
|
|
4106
4198
|
});
|
|
@@ -4178,7 +4270,6 @@ function calculateSessionTotalTokens(entries) {
|
|
|
4178
4270
|
return sum + usage.input_tokens + usage.output_tokens + (usage.cache_creation_input_tokens ?? 0) + (usage.cache_read_input_tokens ?? 0);
|
|
4179
4271
|
}, 0);
|
|
4180
4272
|
}
|
|
4181
|
-
var import_picocolors$2 = /* @__PURE__ */ __toESM(require_picocolors(), 1);
|
|
4182
4273
|
const sessionCommand = define({
|
|
4183
4274
|
name: "session",
|
|
4184
4275
|
description: "Show usage report grouped by conversation session",
|
|
@@ -4201,7 +4292,7 @@ const sessionCommand = define({
|
|
|
4201
4292
|
offline: mergedOptions.offline,
|
|
4202
4293
|
jq: mergedOptions.jq,
|
|
4203
4294
|
timezone: mergedOptions.timezone,
|
|
4204
|
-
locale: mergedOptions.locale ??
|
|
4295
|
+
locale: mergedOptions.locale ?? DEFAULT_LOCALE
|
|
4205
4296
|
} }, useJson);
|
|
4206
4297
|
const sessionData = await loadSessionData({
|
|
4207
4298
|
since: ctx.values.since,
|
|
@@ -4246,86 +4337,35 @@ const sessionCommand = define({
|
|
|
4246
4337
|
} else log(JSON.stringify(jsonOutput, null, 2));
|
|
4247
4338
|
} else {
|
|
4248
4339
|
logger.box("Claude Code Token Usage Report - By Session");
|
|
4249
|
-
const
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
"Models",
|
|
4253
|
-
"Input",
|
|
4254
|
-
"Output",
|
|
4255
|
-
"Cache Create",
|
|
4256
|
-
"Cache Read",
|
|
4257
|
-
"Total Tokens",
|
|
4258
|
-
"Cost (USD)",
|
|
4259
|
-
"Last Activity"
|
|
4260
|
-
],
|
|
4261
|
-
style: { head: ["cyan"] },
|
|
4262
|
-
colAligns: [
|
|
4263
|
-
"left",
|
|
4264
|
-
"left",
|
|
4265
|
-
"right",
|
|
4266
|
-
"right",
|
|
4267
|
-
"right",
|
|
4268
|
-
"right",
|
|
4269
|
-
"right",
|
|
4270
|
-
"right",
|
|
4271
|
-
"left"
|
|
4272
|
-
],
|
|
4340
|
+
const tableConfig = {
|
|
4341
|
+
firstColumnName: "Session",
|
|
4342
|
+
includeLastActivity: true,
|
|
4273
4343
|
dateFormatter: (dateStr) => formatDateCompact(dateStr, ctx.values.timezone, ctx.values.locale),
|
|
4274
|
-
compactHead: [
|
|
4275
|
-
"Session",
|
|
4276
|
-
"Models",
|
|
4277
|
-
"Input",
|
|
4278
|
-
"Output",
|
|
4279
|
-
"Cost (USD)",
|
|
4280
|
-
"Last Activity"
|
|
4281
|
-
],
|
|
4282
|
-
compactColAligns: [
|
|
4283
|
-
"left",
|
|
4284
|
-
"left",
|
|
4285
|
-
"right",
|
|
4286
|
-
"right",
|
|
4287
|
-
"right",
|
|
4288
|
-
"left"
|
|
4289
|
-
],
|
|
4290
|
-
compactThreshold: 100,
|
|
4291
4344
|
forceCompact: ctx.values.compact
|
|
4292
|
-
});
|
|
4345
|
+
}, table = createUsageReportTable(tableConfig);
|
|
4293
4346
|
let maxSessionLength = 0;
|
|
4294
4347
|
for (const data of sessionData) {
|
|
4295
4348
|
const sessionDisplay = data.sessionId.split("-").slice(-2).join("-");
|
|
4296
|
-
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
|
|
4300
|
-
|
|
4301
|
-
|
|
4302
|
-
|
|
4303
|
-
|
|
4304
|
-
|
|
4305
|
-
|
|
4306
|
-
]), ctx.values.breakdown) pushBreakdownRows(table, data.modelBreakdowns, 1, 1);
|
|
4349
|
+
maxSessionLength = Math.max(maxSessionLength, sessionDisplay.length);
|
|
4350
|
+
const row = formatUsageDataRow(sessionDisplay, {
|
|
4351
|
+
inputTokens: data.inputTokens,
|
|
4352
|
+
outputTokens: data.outputTokens,
|
|
4353
|
+
cacheCreationTokens: data.cacheCreationTokens,
|
|
4354
|
+
cacheReadTokens: data.cacheReadTokens,
|
|
4355
|
+
totalCost: data.totalCost,
|
|
4356
|
+
modelsUsed: data.modelsUsed
|
|
4357
|
+
}, data.lastActivity);
|
|
4358
|
+
if (table.push(row), ctx.values.breakdown) pushBreakdownRows(table, data.modelBreakdowns, 1, 1);
|
|
4307
4359
|
}
|
|
4308
|
-
|
|
4309
|
-
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
|
|
4315
|
-
|
|
4316
|
-
|
|
4317
|
-
""
|
|
4318
|
-
]), table.push([
|
|
4319
|
-
import_picocolors$2.default.yellow("Total"),
|
|
4320
|
-
"",
|
|
4321
|
-
import_picocolors$2.default.yellow(formatNumber(totals.inputTokens)),
|
|
4322
|
-
import_picocolors$2.default.yellow(formatNumber(totals.outputTokens)),
|
|
4323
|
-
import_picocolors$2.default.yellow(formatNumber(totals.cacheCreationTokens)),
|
|
4324
|
-
import_picocolors$2.default.yellow(formatNumber(totals.cacheReadTokens)),
|
|
4325
|
-
import_picocolors$2.default.yellow(formatNumber(getTotalTokens(totals))),
|
|
4326
|
-
import_picocolors$2.default.yellow(formatCurrency(totals.totalCost)),
|
|
4327
|
-
""
|
|
4328
|
-
]), log(table.toString()), table.isCompactMode()) logger.info("\nRunning in Compact Mode"), logger.info("Expand terminal width to see cache metrics and total tokens");
|
|
4360
|
+
addEmptySeparatorRow(table, 9);
|
|
4361
|
+
const totalsRow = formatTotalsRow({
|
|
4362
|
+
inputTokens: totals.inputTokens,
|
|
4363
|
+
outputTokens: totals.outputTokens,
|
|
4364
|
+
cacheCreationTokens: totals.cacheCreationTokens,
|
|
4365
|
+
cacheReadTokens: totals.cacheReadTokens,
|
|
4366
|
+
totalCost: totals.totalCost
|
|
4367
|
+
}, true);
|
|
4368
|
+
if (table.push(totalsRow), log(table.toString()), table.isCompactMode()) logger.info("\nRunning in Compact Mode"), logger.info("Expand terminal width to see cache metrics and total tokens");
|
|
4329
4369
|
}
|
|
4330
4370
|
}
|
|
4331
4371
|
});
|
|
@@ -5198,7 +5238,7 @@ getStdin.buffer = async () => {
|
|
|
5198
5238
|
for await (const chunk of stdin$1) result.push(chunk), length += chunk.length;
|
|
5199
5239
|
return Buffer.concat(result, length);
|
|
5200
5240
|
};
|
|
5201
|
-
var import_picocolors
|
|
5241
|
+
var import_picocolors = /* @__PURE__ */ __toESM(require_picocolors(), 1), import_usingCtx = /* @__PURE__ */ __toESM(require_usingCtx(), 1);
|
|
5202
5242
|
function formatRemainingTime(remaining) {
|
|
5203
5243
|
const remainingHours = Math.floor(remaining / 60), remainingMins = remaining % 60;
|
|
5204
5244
|
return remainingHours > 0 ? `${remainingHours}h ${remainingMins}m left` : `${remainingMins}m left`;
|
|
@@ -5219,7 +5259,7 @@ const visualBurnRateChoices = [
|
|
|
5219
5259
|
"ccusage",
|
|
5220
5260
|
"cc",
|
|
5221
5261
|
"both"
|
|
5222
|
-
], statuslineCommand = define({
|
|
5262
|
+
], contextThresholdSchema = coerce.number().int().min(0, "Context threshold must be at least 0").max(100, "Context threshold must be at most 100"), statuslineCommand = define({
|
|
5223
5263
|
name: "statusline",
|
|
5224
5264
|
description: "Display compact status line for Claude Code hooks with hybrid time+file caching (Beta)",
|
|
5225
5265
|
toKebab: true,
|
|
@@ -5255,11 +5295,23 @@ const visualBurnRateChoices = [
|
|
|
5255
5295
|
description: `Refresh interval in seconds for cache expiry (default: ${DEFAULT_REFRESH_INTERVAL_SECONDS})`,
|
|
5256
5296
|
default: DEFAULT_REFRESH_INTERVAL_SECONDS
|
|
5257
5297
|
},
|
|
5298
|
+
contextLowThreshold: {
|
|
5299
|
+
type: "custom",
|
|
5300
|
+
description: "Context usage percentage below which status is shown in green (0-100)",
|
|
5301
|
+
parse: (value$1) => contextThresholdSchema.parse(value$1),
|
|
5302
|
+
default: DEFAULT_CONTEXT_USAGE_THRESHOLDS.LOW
|
|
5303
|
+
},
|
|
5304
|
+
contextMediumThreshold: {
|
|
5305
|
+
type: "custom",
|
|
5306
|
+
description: "Context usage percentage below which status is shown in yellow (0-100)",
|
|
5307
|
+
parse: (value$1) => contextThresholdSchema.parse(value$1),
|
|
5308
|
+
default: DEFAULT_CONTEXT_USAGE_THRESHOLDS.MEDIUM
|
|
5309
|
+
},
|
|
5258
5310
|
config: sharedArgs.config,
|
|
5259
5311
|
debug: sharedArgs.debug
|
|
5260
5312
|
},
|
|
5261
5313
|
async run(ctx) {
|
|
5262
|
-
logger.level = 0;
|
|
5314
|
+
if (logger.level = 0, ctx.values.contextLowThreshold >= ctx.values.contextMediumThreshold) throw new Error(`Context low threshold (${ctx.values.contextLowThreshold}) must be less than medium threshold (${ctx.values.contextMediumThreshold})`);
|
|
5263
5315
|
const config = loadConfig(ctx.values.config, ctx.values.debug), mergedOptions = mergeConfigWithArgs(ctx, config, ctx.values.debug), refreshInterval = mergedOptions.refreshInterval, stdin$2 = await getStdin();
|
|
5264
5316
|
if (stdin$2.length === 0) log("❌ No input provided"), process$1.exit(1);
|
|
5265
5317
|
const hookDataJson = JSON.parse(stdin$2.trim()), hookDataParseResult = statuslineHookJsonSchema.safeParse(hookDataJson);
|
|
@@ -5339,7 +5391,7 @@ const visualBurnRateChoices = [
|
|
|
5339
5391
|
const cost = await getCcusageCost();
|
|
5340
5392
|
return { sessionCost: cost };
|
|
5341
5393
|
}
|
|
5342
|
-
return {};
|
|
5394
|
+
return unreachable(costSource), {};
|
|
5343
5395
|
})(), today = /* @__PURE__ */ new Date(), todayStr = today.toISOString().split("T")[0]?.replace(/-/g, "") ?? "", todayCost = await pipe(try_({
|
|
5344
5396
|
try: async () => loadDailyUsageData({
|
|
5345
5397
|
since: todayStr,
|
|
@@ -5374,17 +5426,17 @@ const visualBurnRateChoices = [
|
|
|
5374
5426
|
normal: {
|
|
5375
5427
|
emoji: "🟢",
|
|
5376
5428
|
textValue: "Normal",
|
|
5377
|
-
coloredString: import_picocolors
|
|
5429
|
+
coloredString: import_picocolors.default.green
|
|
5378
5430
|
},
|
|
5379
5431
|
moderate: {
|
|
5380
5432
|
emoji: "⚠️",
|
|
5381
5433
|
textValue: "Moderate",
|
|
5382
|
-
coloredString: import_picocolors
|
|
5434
|
+
coloredString: import_picocolors.default.yellow
|
|
5383
5435
|
},
|
|
5384
5436
|
high: {
|
|
5385
5437
|
emoji: "🚨",
|
|
5386
5438
|
textValue: "High",
|
|
5387
|
-
coloredString: import_picocolors
|
|
5439
|
+
coloredString: import_picocolors.default.red
|
|
5388
5440
|
}
|
|
5389
5441
|
}, { emoji, textValue, coloredString } = burnStatusMappings[burnStatus], burnRateOutputSegments = [coloredString(costPerHourStr)];
|
|
5390
5442
|
if (renderEmojiStatus) burnRateOutputSegments.push(emoji);
|
|
@@ -5406,9 +5458,9 @@ const visualBurnRateChoices = [
|
|
|
5406
5458
|
})), contextInfo = await pipe(try_({
|
|
5407
5459
|
try: calculateContextTokens(hookData.transcript_path, hookData.model.id, mergedOptions.offline),
|
|
5408
5460
|
catch: (error) => error
|
|
5409
|
-
}), inspectError((error) => logger.debug(`Failed to calculate context tokens: ${error instanceof Error ? error.message : String(error)}`)), map((
|
|
5410
|
-
if (
|
|
5411
|
-
const
|
|
5461
|
+
}), inspectError((error) => logger.debug(`Failed to calculate context tokens: ${error instanceof Error ? error.message : String(error)}`)), map((contextResult) => {
|
|
5462
|
+
if (contextResult == null) return void 0;
|
|
5463
|
+
const color = contextResult.percentage < ctx.values.contextLowThreshold ? import_picocolors.default.green : contextResult.percentage < ctx.values.contextMediumThreshold ? import_picocolors.default.yellow : import_picocolors.default.red, coloredPercentage = color(`${contextResult.percentage}%`), tokenDisplay = contextResult.inputTokens.toLocaleString();
|
|
5412
5464
|
return `${tokenDisplay} (${coloredPercentage})`;
|
|
5413
5465
|
}), unwrap(void 0)), modelName = hookData.model.display_name, sessionDisplay = (() => {
|
|
5414
5466
|
if (ccCost != null || ccusageCost != null) {
|
|
@@ -5454,9 +5506,7 @@ const visualBurnRateChoices = [
|
|
|
5454
5506
|
_usingCtx4.d();
|
|
5455
5507
|
}
|
|
5456
5508
|
}
|
|
5457
|
-
})
|
|
5458
|
-
var import_picocolors = /* @__PURE__ */ __toESM(require_picocolors(), 1);
|
|
5459
|
-
const weeklyCommand = define({
|
|
5509
|
+
}), weeklyCommand = define({
|
|
5460
5510
|
name: "weekly",
|
|
5461
5511
|
description: "Show usage report grouped by week",
|
|
5462
5512
|
args: {
|
|
@@ -5518,75 +5568,31 @@ const weeklyCommand = define({
|
|
|
5518
5568
|
} else log(JSON.stringify(jsonOutput, null, 2));
|
|
5519
5569
|
} else {
|
|
5520
5570
|
logger.box("Claude Code Token Usage Report - Weekly");
|
|
5521
|
-
const
|
|
5522
|
-
|
|
5523
|
-
"Week",
|
|
5524
|
-
"Models",
|
|
5525
|
-
"Input",
|
|
5526
|
-
"Output",
|
|
5527
|
-
"Cache Create",
|
|
5528
|
-
"Cache Read",
|
|
5529
|
-
"Total Tokens",
|
|
5530
|
-
"Cost (USD)"
|
|
5531
|
-
],
|
|
5532
|
-
style: { head: ["cyan"] },
|
|
5533
|
-
colAligns: [
|
|
5534
|
-
"left",
|
|
5535
|
-
"left",
|
|
5536
|
-
"right",
|
|
5537
|
-
"right",
|
|
5538
|
-
"right",
|
|
5539
|
-
"right",
|
|
5540
|
-
"right",
|
|
5541
|
-
"right"
|
|
5542
|
-
],
|
|
5571
|
+
const tableConfig = {
|
|
5572
|
+
firstColumnName: "Week",
|
|
5543
5573
|
dateFormatter: (dateStr) => formatDateCompact(dateStr, mergedOptions.timezone, mergedOptions.locale ?? void 0),
|
|
5544
|
-
compactHead: [
|
|
5545
|
-
"Week",
|
|
5546
|
-
"Models",
|
|
5547
|
-
"Input",
|
|
5548
|
-
"Output",
|
|
5549
|
-
"Cost (USD)"
|
|
5550
|
-
],
|
|
5551
|
-
compactColAligns: [
|
|
5552
|
-
"left",
|
|
5553
|
-
"left",
|
|
5554
|
-
"right",
|
|
5555
|
-
"right",
|
|
5556
|
-
"right"
|
|
5557
|
-
],
|
|
5558
|
-
compactThreshold: 100,
|
|
5559
5574
|
forceCompact: ctx.values.compact
|
|
5575
|
+
}, table = createUsageReportTable(tableConfig);
|
|
5576
|
+
for (const data of weeklyData) {
|
|
5577
|
+
const row = formatUsageDataRow(data.week, {
|
|
5578
|
+
inputTokens: data.inputTokens,
|
|
5579
|
+
outputTokens: data.outputTokens,
|
|
5580
|
+
cacheCreationTokens: data.cacheCreationTokens,
|
|
5581
|
+
cacheReadTokens: data.cacheReadTokens,
|
|
5582
|
+
totalCost: data.totalCost,
|
|
5583
|
+
modelsUsed: data.modelsUsed
|
|
5584
|
+
});
|
|
5585
|
+
if (table.push(row), mergedOptions.breakdown) pushBreakdownRows(table, data.modelBreakdowns);
|
|
5586
|
+
}
|
|
5587
|
+
addEmptySeparatorRow(table, 8);
|
|
5588
|
+
const totalsRow = formatTotalsRow({
|
|
5589
|
+
inputTokens: totals.inputTokens,
|
|
5590
|
+
outputTokens: totals.outputTokens,
|
|
5591
|
+
cacheCreationTokens: totals.cacheCreationTokens,
|
|
5592
|
+
cacheReadTokens: totals.cacheReadTokens,
|
|
5593
|
+
totalCost: totals.totalCost
|
|
5560
5594
|
});
|
|
5561
|
-
|
|
5562
|
-
data.week,
|
|
5563
|
-
formatModelsDisplayMultiline(data.modelsUsed),
|
|
5564
|
-
formatNumber(data.inputTokens),
|
|
5565
|
-
formatNumber(data.outputTokens),
|
|
5566
|
-
formatNumber(data.cacheCreationTokens),
|
|
5567
|
-
formatNumber(data.cacheReadTokens),
|
|
5568
|
-
formatNumber(getTotalTokens(data)),
|
|
5569
|
-
formatCurrency(data.totalCost)
|
|
5570
|
-
]), mergedOptions.breakdown) pushBreakdownRows(table, data.modelBreakdowns);
|
|
5571
|
-
if (table.push([
|
|
5572
|
-
"",
|
|
5573
|
-
"",
|
|
5574
|
-
"",
|
|
5575
|
-
"",
|
|
5576
|
-
"",
|
|
5577
|
-
"",
|
|
5578
|
-
"",
|
|
5579
|
-
""
|
|
5580
|
-
]), table.push([
|
|
5581
|
-
import_picocolors.default.yellow("Total"),
|
|
5582
|
-
"",
|
|
5583
|
-
import_picocolors.default.yellow(formatNumber(totals.inputTokens)),
|
|
5584
|
-
import_picocolors.default.yellow(formatNumber(totals.outputTokens)),
|
|
5585
|
-
import_picocolors.default.yellow(formatNumber(totals.cacheCreationTokens)),
|
|
5586
|
-
import_picocolors.default.yellow(formatNumber(totals.cacheReadTokens)),
|
|
5587
|
-
import_picocolors.default.yellow(formatNumber(getTotalTokens(totals))),
|
|
5588
|
-
import_picocolors.default.yellow(formatCurrency(totals.totalCost))
|
|
5589
|
-
]), log(table.toString()), table.isCompactMode()) logger.info("\nRunning in Compact Mode"), logger.info("Expand terminal width to see cache metrics and total tokens");
|
|
5595
|
+
if (table.push(totalsRow), log(table.toString()), table.isCompactMode()) logger.info("\nRunning in Compact Mode"), logger.info("Expand terminal width to see cache metrics and total tokens");
|
|
5590
5596
|
}
|
|
5591
5597
|
}
|
|
5592
5598
|
}), subCommandUnion = [
|