ccusage 15.1.0 → 15.2.0
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 +3 -1
- package/dist/{_types-Cr2YEzKm.js → _types-CmSE0O0q.js} +1 -6
- package/dist/{calculate-cost-CoS7we68.js → calculate-cost-B0RYn0Vm.js} +2 -6
- package/dist/calculate-cost.d.ts +2 -2
- package/dist/calculate-cost.js +2 -2
- package/dist/{data-loader-DZczD-9E.d.ts → data-loader-BuHgMcpg.d.ts} +2 -8
- package/dist/{data-loader-BeaFK_sH.js → data-loader-CzOPffdg.js} +5 -25
- package/dist/data-loader.d.ts +3 -3
- package/dist/data-loader.js +5 -5
- package/dist/{debug-BmJuGBXC.js → debug-CCsUo8-n.js} +10 -4
- package/dist/debug.js +5 -5
- package/dist/index.js +407 -329
- package/dist/{logger-Cke8hliP.js → logger-CeR-gFvq.js} +1 -1
- package/dist/logger.d.ts +4 -1
- package/dist/logger.js +1 -1
- package/dist/{mcp-DKqp_F9c.js → mcp-DGCqhgBz.js} +211 -28
- package/dist/mcp.d.ts +2 -2
- package/dist/mcp.js +6 -5
- package/dist/{pricing-fetcher-BZe7AafW.d.ts → pricing-fetcher-CrV0acwD.d.ts} +2 -0
- package/dist/{pricing-fetcher-Dm8hcn_h.js → pricing-fetcher-fT0o6CKK.js} +145 -116
- 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,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { BLOCKS_COMPACT_WIDTH_THRESHOLD, BLOCKS_DEFAULT_TERMINAL_WIDTH, BLOCKS_WARNING_THRESHOLD, CLAUDE_PROJECTS_DIR_NAME, DEFAULT_RECENT_DAYS, DEFAULT_REFRESH_INTERVAL_SECONDS, MAX_REFRESH_INTERVAL_SECONDS, MCP_DEFAULT_PORT, MIN_REFRESH_INTERVAL_SECONDS, PricingFetcher, USAGE_DATA_GLOB_PATTERN, __commonJSMin, __require, __toESM, require_usingCtx } from "./pricing-fetcher-
|
|
3
|
-
import { CostModes, SortOrders,
|
|
4
|
-
import { calculateTotals, createTotalsObject, getTotalTokens } from "./calculate-cost-
|
|
5
|
-
import { DEFAULT_SESSION_DURATION_HOURS, calculateBurnRate, calculateCostForEntry, createUniqueHash, filterRecentBlocks, formatDateCompact,
|
|
6
|
-
import { description, log, logger, name, version } from "./logger-
|
|
7
|
-
import { detectMismatches, printMismatchReport } from "./debug-
|
|
8
|
-
import { createMcpHttpApp, createMcpServer, startMcpServerStdio } from "./mcp-
|
|
2
|
+
import { BLOCKS_COMPACT_WIDTH_THRESHOLD, BLOCKS_DEFAULT_TERMINAL_WIDTH, BLOCKS_WARNING_THRESHOLD, CLAUDE_PROJECTS_DIR_NAME, DEFAULT_RECENT_DAYS, DEFAULT_REFRESH_INTERVAL_SECONDS, MAX_REFRESH_INTERVAL_SECONDS, MCP_DEFAULT_PORT, MIN_REFRESH_INTERVAL_SECONDS, MIN_RENDER_INTERVAL_MS, PricingFetcher, USAGE_DATA_GLOB_PATTERN, __commonJSMin, __require, __toESM, require_usingCtx } from "./pricing-fetcher-fT0o6CKK.js";
|
|
3
|
+
import { CostModes, SortOrders, filterDateSchema } from "./_types-CmSE0O0q.js";
|
|
4
|
+
import { calculateTotals, createTotalsObject, getTotalTokens } from "./calculate-cost-B0RYn0Vm.js";
|
|
5
|
+
import { DEFAULT_SESSION_DURATION_HOURS, calculateBurnRate, calculateCostForEntry, createUniqueHash, filterRecentBlocks, formatDateCompact, getClaudePaths, getEarliestTimestamp, glob, identifySessionBlocks, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData, projectBlockUsage, sortFilesByTimestamp, uniq, usageDataSchema } from "./data-loader-CzOPffdg.js";
|
|
6
|
+
import { description, log, logger, name, version } from "./logger-CeR-gFvq.js";
|
|
7
|
+
import { detectMismatches, printMismatchReport } from "./debug-CCsUo8-n.js";
|
|
8
|
+
import { createMcpHttpApp, createMcpServer, startMcpServerStdio } from "./mcp-DGCqhgBz.js";
|
|
9
9
|
import { readFile } from "node:fs/promises";
|
|
10
10
|
import path from "node:path";
|
|
11
11
|
import process$1 from "node:process";
|
|
@@ -1194,7 +1194,7 @@ var require_picocolors = __commonJSMin((exports, module) => {
|
|
|
1194
1194
|
* @throws TypeError if date format is invalid
|
|
1195
1195
|
*/
|
|
1196
1196
|
function parseDateArg(value) {
|
|
1197
|
-
const result =
|
|
1197
|
+
const result = filterDateSchema.safeParse(value);
|
|
1198
1198
|
if (!result.success) throw new TypeError(result.error.issues[0]?.message ?? "Invalid date format");
|
|
1199
1199
|
return result.data;
|
|
1200
1200
|
}
|
|
@@ -2931,7 +2931,7 @@ function stringWidth(string, options = {}) {
|
|
|
2931
2931
|
return width;
|
|
2932
2932
|
}
|
|
2933
2933
|
var import_cli_table3 = __toESM(require_cli_table3(), 1);
|
|
2934
|
-
var import_picocolors$
|
|
2934
|
+
var import_picocolors$6 = __toESM(require_picocolors(), 1);
|
|
2935
2935
|
/**
|
|
2936
2936
|
* Responsive table class that adapts column widths based on terminal size
|
|
2937
2937
|
* Automatically adjusts formatting and layout for different screen sizes
|
|
@@ -3167,11 +3167,92 @@ function pushBreakdownRows(table, breakdowns, extraColumns = 1, trailingColumns
|
|
|
3167
3167
|
const row = [` └─ ${formatModelName(breakdown.modelName)}`];
|
|
3168
3168
|
for (let i = 0; i < extraColumns; i++) row.push("");
|
|
3169
3169
|
const totalTokens = breakdown.inputTokens + breakdown.outputTokens + breakdown.cacheCreationTokens + breakdown.cacheReadTokens;
|
|
3170
|
-
row.push(import_picocolors$
|
|
3170
|
+
row.push(import_picocolors$6.default.gray(formatNumber(breakdown.inputTokens)), import_picocolors$6.default.gray(formatNumber(breakdown.outputTokens)), import_picocolors$6.default.gray(formatNumber(breakdown.cacheCreationTokens)), import_picocolors$6.default.gray(formatNumber(breakdown.cacheReadTokens)), import_picocolors$6.default.gray(formatNumber(totalTokens)), import_picocolors$6.default.gray(formatCurrency(breakdown.cost)));
|
|
3171
3171
|
for (let i = 0; i < trailingColumns; i++) row.push("");
|
|
3172
3172
|
table.push(row);
|
|
3173
3173
|
}
|
|
3174
3174
|
}
|
|
3175
|
+
/**
|
|
3176
|
+
* Manages live monitoring of Claude usage with efficient data reloading
|
|
3177
|
+
*/
|
|
3178
|
+
var LiveMonitor = class {
|
|
3179
|
+
config;
|
|
3180
|
+
fetcher = null;
|
|
3181
|
+
lastFileTimestamps = /* @__PURE__ */ new Map();
|
|
3182
|
+
processedHashes = /* @__PURE__ */ new Set();
|
|
3183
|
+
allEntries = [];
|
|
3184
|
+
constructor(config) {
|
|
3185
|
+
this.config = config;
|
|
3186
|
+
if (config.mode !== "display") this.fetcher = new PricingFetcher();
|
|
3187
|
+
}
|
|
3188
|
+
/**
|
|
3189
|
+
* Implements Disposable interface
|
|
3190
|
+
*/
|
|
3191
|
+
[Symbol.dispose]() {
|
|
3192
|
+
this.fetcher?.[Symbol.dispose]();
|
|
3193
|
+
}
|
|
3194
|
+
/**
|
|
3195
|
+
* Gets the current active session block with minimal file reading
|
|
3196
|
+
* Only reads new or modified files since last check
|
|
3197
|
+
*/
|
|
3198
|
+
async getActiveBlock() {
|
|
3199
|
+
const claudeDir = path.join(this.config.claudePath, CLAUDE_PROJECTS_DIR_NAME);
|
|
3200
|
+
const files = await glob([USAGE_DATA_GLOB_PATTERN], {
|
|
3201
|
+
cwd: claudeDir,
|
|
3202
|
+
absolute: true
|
|
3203
|
+
});
|
|
3204
|
+
if (files.length === 0) return null;
|
|
3205
|
+
const filesToRead = [];
|
|
3206
|
+
for (const file of files) {
|
|
3207
|
+
const timestamp = await getEarliestTimestamp(file);
|
|
3208
|
+
const lastTimestamp = this.lastFileTimestamps.get(file);
|
|
3209
|
+
if (timestamp != null && (lastTimestamp == null || timestamp.getTime() > lastTimestamp)) {
|
|
3210
|
+
filesToRead.push(file);
|
|
3211
|
+
this.lastFileTimestamps.set(file, timestamp.getTime());
|
|
3212
|
+
}
|
|
3213
|
+
}
|
|
3214
|
+
if (filesToRead.length > 0) {
|
|
3215
|
+
const sortedFiles = await sortFilesByTimestamp(filesToRead);
|
|
3216
|
+
for (const file of sortedFiles) {
|
|
3217
|
+
const content = await readFile(file, "utf-8");
|
|
3218
|
+
const lines = content.trim().split("\n").filter((line) => line.length > 0);
|
|
3219
|
+
for (const line of lines) try {
|
|
3220
|
+
const parsed = JSON.parse(line);
|
|
3221
|
+
const result = usageDataSchema.safeParse(parsed);
|
|
3222
|
+
if (!result.success) continue;
|
|
3223
|
+
const data = result.data;
|
|
3224
|
+
const uniqueHash = createUniqueHash(data);
|
|
3225
|
+
if (uniqueHash != null && this.processedHashes.has(uniqueHash)) continue;
|
|
3226
|
+
if (uniqueHash != null) this.processedHashes.add(uniqueHash);
|
|
3227
|
+
const costUSD = await (this.config.mode === "display" ? Promise.resolve(data.costUSD ?? 0) : calculateCostForEntry(data, this.config.mode, this.fetcher));
|
|
3228
|
+
this.allEntries.push({
|
|
3229
|
+
timestamp: new Date(data.timestamp),
|
|
3230
|
+
usage: {
|
|
3231
|
+
inputTokens: data.message.usage.input_tokens ?? 0,
|
|
3232
|
+
outputTokens: data.message.usage.output_tokens ?? 0,
|
|
3233
|
+
cacheCreationInputTokens: data.message.usage.cache_creation_input_tokens ?? 0,
|
|
3234
|
+
cacheReadInputTokens: data.message.usage.cache_read_input_tokens ?? 0
|
|
3235
|
+
},
|
|
3236
|
+
costUSD,
|
|
3237
|
+
model: data.message.model ?? "<synthetic>",
|
|
3238
|
+
version: data.version
|
|
3239
|
+
});
|
|
3240
|
+
} catch {}
|
|
3241
|
+
}
|
|
3242
|
+
}
|
|
3243
|
+
const blocks = identifySessionBlocks(this.allEntries, this.config.sessionDurationHours);
|
|
3244
|
+
const sortedBlocks = this.config.order === "asc" ? blocks : blocks.reverse();
|
|
3245
|
+
return sortedBlocks.find((block) => block.isActive) ?? null;
|
|
3246
|
+
}
|
|
3247
|
+
/**
|
|
3248
|
+
* Clears all cached data to force a full reload
|
|
3249
|
+
*/
|
|
3250
|
+
clearCache() {
|
|
3251
|
+
this.lastFileTimestamps.clear();
|
|
3252
|
+
this.processedHashes.clear();
|
|
3253
|
+
this.allEntries = [];
|
|
3254
|
+
}
|
|
3255
|
+
};
|
|
3175
3256
|
/** Options for {@linkcode delay}. */
|
|
3176
3257
|
/**
|
|
3177
3258
|
* Resolve a {@linkcode Promise} after a given amount of milliseconds.
|
|
@@ -3225,6 +3306,54 @@ function pushBreakdownRows(table, breakdowns, extraColumns = 1, trailingColumns
|
|
|
3225
3306
|
}
|
|
3226
3307
|
});
|
|
3227
3308
|
}
|
|
3309
|
+
const isBrowser = globalThis.window?.document !== void 0;
|
|
3310
|
+
const isNode = globalThis.process?.versions?.node !== void 0;
|
|
3311
|
+
const isBun = globalThis.process?.versions?.bun !== void 0;
|
|
3312
|
+
const isDeno = globalThis.Deno?.version?.deno !== void 0;
|
|
3313
|
+
const isElectron = globalThis.process?.versions?.electron !== void 0;
|
|
3314
|
+
const isJsDom = globalThis.navigator?.userAgent?.includes("jsdom") === true;
|
|
3315
|
+
const isWebWorker = typeof WorkerGlobalScope !== "undefined" && globalThis instanceof WorkerGlobalScope;
|
|
3316
|
+
const isDedicatedWorker = typeof DedicatedWorkerGlobalScope !== "undefined" && globalThis instanceof DedicatedWorkerGlobalScope;
|
|
3317
|
+
const isSharedWorker = typeof SharedWorkerGlobalScope !== "undefined" && globalThis instanceof SharedWorkerGlobalScope;
|
|
3318
|
+
const isServiceWorker = typeof ServiceWorkerGlobalScope !== "undefined" && globalThis instanceof ServiceWorkerGlobalScope;
|
|
3319
|
+
const platform = globalThis.navigator?.userAgentData?.platform;
|
|
3320
|
+
const isMacOs = platform === "macOS" || globalThis.navigator?.platform === "MacIntel" || globalThis.navigator?.userAgent?.includes(" Mac ") === true || globalThis.process?.platform === "darwin";
|
|
3321
|
+
const isWindows$1 = platform === "Windows" || globalThis.navigator?.platform === "Win32" || globalThis.process?.platform === "win32";
|
|
3322
|
+
const isLinux = platform === "Linux" || globalThis.navigator?.platform?.startsWith("Linux") === true || globalThis.navigator?.userAgent?.includes(" Linux ") === true || globalThis.process?.platform === "linux";
|
|
3323
|
+
const isIos = platform === "iOS" || globalThis.navigator?.platform === "MacIntel" && globalThis.navigator?.maxTouchPoints > 1 || /iPad|iPhone|iPod/.test(globalThis.navigator?.platform);
|
|
3324
|
+
const isAndroid = platform === "Android" || globalThis.navigator?.platform === "Android" || globalThis.navigator?.userAgent?.includes(" Android ") === true || globalThis.process?.platform === "android";
|
|
3325
|
+
const ESC = "\x1B[";
|
|
3326
|
+
const SEP = ";";
|
|
3327
|
+
const isTerminalApp = !isBrowser && process$1.env.TERM_PROGRAM === "Apple_Terminal";
|
|
3328
|
+
const isWindows = !isBrowser && process$1.platform === "win32";
|
|
3329
|
+
const cwdFunction = isBrowser ? () => {
|
|
3330
|
+
throw new Error("`process.cwd()` only works in Node.js, not the browser.");
|
|
3331
|
+
} : process$1.cwd;
|
|
3332
|
+
const cursorTo = (x, y) => {
|
|
3333
|
+
if (typeof x !== "number") throw new TypeError("The `x` argument is required");
|
|
3334
|
+
if (typeof y !== "number") return ESC + (x + 1) + "G";
|
|
3335
|
+
return ESC + (y + 1) + SEP + (x + 1) + "H";
|
|
3336
|
+
};
|
|
3337
|
+
const cursorLeft = ESC + "G";
|
|
3338
|
+
const cursorSavePosition = isTerminalApp ? "\x1B7" : ESC + "s";
|
|
3339
|
+
const cursorRestorePosition = isTerminalApp ? "\x1B8" : ESC + "u";
|
|
3340
|
+
const cursorGetPosition = ESC + "6n";
|
|
3341
|
+
const cursorNextLine = ESC + "E";
|
|
3342
|
+
const cursorPrevLine = ESC + "F";
|
|
3343
|
+
const cursorHide = ESC + "?25l";
|
|
3344
|
+
const cursorShow = ESC + "?25h";
|
|
3345
|
+
const eraseEndLine = ESC + "K";
|
|
3346
|
+
const eraseStartLine = ESC + "1K";
|
|
3347
|
+
const eraseLine = ESC + "2K";
|
|
3348
|
+
const eraseDown = ESC + "J";
|
|
3349
|
+
const eraseUp = ESC + "1J";
|
|
3350
|
+
const eraseScreen = ESC + "2J";
|
|
3351
|
+
const scrollUp = ESC + "S";
|
|
3352
|
+
const scrollDown = ESC + "T";
|
|
3353
|
+
const clearScreen = "\x1Bc";
|
|
3354
|
+
const clearTerminal = isWindows ? `${eraseScreen}${ESC}0f` : `${eraseScreen}${ESC}3J${ESC}H`;
|
|
3355
|
+
const enterAlternativeScreen = ESC + "?1049h";
|
|
3356
|
+
const exitAlternativeScreen = ESC + "?1049l";
|
|
3228
3357
|
const toZeroIfInfinity = (value) => Number.isFinite(value) ? value : 0;
|
|
3229
3358
|
function parseNumber(milliseconds) {
|
|
3230
3359
|
return {
|
|
@@ -3336,255 +3465,170 @@ function prettyMilliseconds(milliseconds, options) {
|
|
|
3336
3465
|
if (typeof options.unitCount === "number") result = result.slice(0, Math.max(options.unitCount, 1));
|
|
3337
3466
|
return sign + result.join(separator);
|
|
3338
3467
|
}
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
fetcher = null;
|
|
3345
|
-
lastFileTimestamps = /* @__PURE__ */ new Map();
|
|
3346
|
-
processedHashes = /* @__PURE__ */ new Set();
|
|
3347
|
-
allEntries = [];
|
|
3348
|
-
constructor(config) {
|
|
3349
|
-
this.config = config;
|
|
3350
|
-
if (config.mode !== "display") this.fetcher = new PricingFetcher();
|
|
3351
|
-
}
|
|
3352
|
-
/**
|
|
3353
|
-
* Implements Disposable interface
|
|
3354
|
-
*/
|
|
3355
|
-
[Symbol.dispose]() {
|
|
3356
|
-
this.fetcher?.[Symbol.dispose]();
|
|
3357
|
-
}
|
|
3358
|
-
/**
|
|
3359
|
-
* Gets the current active session block with minimal file reading
|
|
3360
|
-
* Only reads new or modified files since last check
|
|
3361
|
-
*/
|
|
3362
|
-
async getActiveBlock() {
|
|
3363
|
-
const claudeDir = path.join(this.config.claudePath, CLAUDE_PROJECTS_DIR_NAME);
|
|
3364
|
-
const files = await glob([USAGE_DATA_GLOB_PATTERN], {
|
|
3365
|
-
cwd: claudeDir,
|
|
3366
|
-
absolute: true
|
|
3367
|
-
});
|
|
3368
|
-
if (files.length === 0) return null;
|
|
3369
|
-
const filesToRead = [];
|
|
3370
|
-
for (const file of files) {
|
|
3371
|
-
const timestamp = await getEarliestTimestamp(file);
|
|
3372
|
-
const lastTimestamp = this.lastFileTimestamps.get(file);
|
|
3373
|
-
if (timestamp != null && (lastTimestamp == null || timestamp.getTime() > lastTimestamp)) {
|
|
3374
|
-
filesToRead.push(file);
|
|
3375
|
-
this.lastFileTimestamps.set(file, timestamp.getTime());
|
|
3376
|
-
}
|
|
3377
|
-
}
|
|
3378
|
-
if (filesToRead.length > 0) {
|
|
3379
|
-
const sortedFiles = await sortFilesByTimestamp(filesToRead);
|
|
3380
|
-
for (const file of sortedFiles) {
|
|
3381
|
-
const content = await readFile(file, "utf-8");
|
|
3382
|
-
const lines = content.trim().split("\n").filter((line) => line.length > 0);
|
|
3383
|
-
for (const line of lines) try {
|
|
3384
|
-
const parsed = JSON.parse(line);
|
|
3385
|
-
const result = usageDataSchema.safeParse(parsed);
|
|
3386
|
-
if (!result.success) continue;
|
|
3387
|
-
const data = result.data;
|
|
3388
|
-
const uniqueHash = createUniqueHash(data);
|
|
3389
|
-
if (uniqueHash != null && this.processedHashes.has(uniqueHash)) continue;
|
|
3390
|
-
if (uniqueHash != null) this.processedHashes.add(uniqueHash);
|
|
3391
|
-
const costUSD = await (this.config.mode === "display" ? Promise.resolve(data.costUSD ?? 0) : calculateCostForEntry(data, this.config.mode, this.fetcher));
|
|
3392
|
-
this.allEntries.push({
|
|
3393
|
-
timestamp: new Date(data.timestamp),
|
|
3394
|
-
usage: {
|
|
3395
|
-
inputTokens: data.message.usage.input_tokens ?? 0,
|
|
3396
|
-
outputTokens: data.message.usage.output_tokens ?? 0,
|
|
3397
|
-
cacheCreationInputTokens: data.message.usage.cache_creation_input_tokens ?? 0,
|
|
3398
|
-
cacheReadInputTokens: data.message.usage.cache_read_input_tokens ?? 0
|
|
3399
|
-
},
|
|
3400
|
-
costUSD,
|
|
3401
|
-
model: data.message.model ?? "<synthetic>",
|
|
3402
|
-
version: data.version
|
|
3403
|
-
});
|
|
3404
|
-
} catch {}
|
|
3405
|
-
}
|
|
3406
|
-
}
|
|
3407
|
-
const blocks = identifySessionBlocks(this.allEntries, this.config.sessionDurationHours);
|
|
3408
|
-
const sortedBlocks = this.config.order === "asc" ? blocks : blocks.reverse();
|
|
3409
|
-
return sortedBlocks.find((block) => block.isActive) ?? null;
|
|
3410
|
-
}
|
|
3411
|
-
/**
|
|
3412
|
-
* Clears all cached data to force a full reload
|
|
3413
|
-
*/
|
|
3414
|
-
clearCache() {
|
|
3415
|
-
this.lastFileTimestamps.clear();
|
|
3416
|
-
this.processedHashes.clear();
|
|
3417
|
-
this.allEntries = [];
|
|
3418
|
-
}
|
|
3419
|
-
};
|
|
3420
|
-
const isBrowser = globalThis.window?.document !== void 0;
|
|
3421
|
-
const isNode = globalThis.process?.versions?.node !== void 0;
|
|
3422
|
-
const isBun = globalThis.process?.versions?.bun !== void 0;
|
|
3423
|
-
const isDeno = globalThis.Deno?.version?.deno !== void 0;
|
|
3424
|
-
const isElectron = globalThis.process?.versions?.electron !== void 0;
|
|
3425
|
-
const isJsDom = globalThis.navigator?.userAgent?.includes("jsdom") === true;
|
|
3426
|
-
const isWebWorker = typeof WorkerGlobalScope !== "undefined" && globalThis instanceof WorkerGlobalScope;
|
|
3427
|
-
const isDedicatedWorker = typeof DedicatedWorkerGlobalScope !== "undefined" && globalThis instanceof DedicatedWorkerGlobalScope;
|
|
3428
|
-
const isSharedWorker = typeof SharedWorkerGlobalScope !== "undefined" && globalThis instanceof SharedWorkerGlobalScope;
|
|
3429
|
-
const isServiceWorker = typeof ServiceWorkerGlobalScope !== "undefined" && globalThis instanceof ServiceWorkerGlobalScope;
|
|
3430
|
-
const platform = globalThis.navigator?.userAgentData?.platform;
|
|
3431
|
-
const isMacOs = platform === "macOS" || globalThis.navigator?.platform === "MacIntel" || globalThis.navigator?.userAgent?.includes(" Mac ") === true || globalThis.process?.platform === "darwin";
|
|
3432
|
-
const isWindows$1 = platform === "Windows" || globalThis.navigator?.platform === "Win32" || globalThis.process?.platform === "win32";
|
|
3433
|
-
const isLinux = platform === "Linux" || globalThis.navigator?.platform?.startsWith("Linux") === true || globalThis.navigator?.userAgent?.includes(" Linux ") === true || globalThis.process?.platform === "linux";
|
|
3434
|
-
const isIos = platform === "iOS" || globalThis.navigator?.platform === "MacIntel" && globalThis.navigator?.maxTouchPoints > 1 || /iPad|iPhone|iPod/.test(globalThis.navigator?.platform);
|
|
3435
|
-
const isAndroid = platform === "Android" || globalThis.navigator?.platform === "Android" || globalThis.navigator?.userAgent?.includes(" Android ") === true || globalThis.process?.platform === "android";
|
|
3436
|
-
const ESC = "\x1B[";
|
|
3437
|
-
const SEP = ";";
|
|
3438
|
-
const isTerminalApp = !isBrowser && process$1.env.TERM_PROGRAM === "Apple_Terminal";
|
|
3439
|
-
const isWindows = !isBrowser && process$1.platform === "win32";
|
|
3440
|
-
const cwdFunction = isBrowser ? () => {
|
|
3441
|
-
throw new Error("`process.cwd()` only works in Node.js, not the browser.");
|
|
3442
|
-
} : process$1.cwd;
|
|
3443
|
-
const cursorTo = (x, y) => {
|
|
3444
|
-
if (typeof x !== "number") throw new TypeError("The `x` argument is required");
|
|
3445
|
-
if (typeof y !== "number") return ESC + (x + 1) + "G";
|
|
3446
|
-
return ESC + (y + 1) + SEP + (x + 1) + "H";
|
|
3447
|
-
};
|
|
3448
|
-
const cursorUp = (count = 1) => ESC + count + "A";
|
|
3449
|
-
const cursorDown = (count = 1) => ESC + count + "B";
|
|
3450
|
-
const cursorLeft = ESC + "G";
|
|
3451
|
-
const cursorSavePosition = isTerminalApp ? "\x1B7" : ESC + "s";
|
|
3452
|
-
const cursorRestorePosition = isTerminalApp ? "\x1B8" : ESC + "u";
|
|
3453
|
-
const cursorGetPosition = ESC + "6n";
|
|
3454
|
-
const cursorNextLine = ESC + "E";
|
|
3455
|
-
const cursorPrevLine = ESC + "F";
|
|
3456
|
-
const cursorHide = ESC + "?25l";
|
|
3457
|
-
const cursorShow = ESC + "?25h";
|
|
3458
|
-
const eraseEndLine = ESC + "K";
|
|
3459
|
-
const eraseStartLine = ESC + "1K";
|
|
3460
|
-
const eraseLine = ESC + "2K";
|
|
3461
|
-
const eraseDown = ESC + "J";
|
|
3462
|
-
const eraseUp = ESC + "1J";
|
|
3463
|
-
const eraseScreen = ESC + "2J";
|
|
3464
|
-
const scrollUp = ESC + "S";
|
|
3465
|
-
const scrollDown = ESC + "T";
|
|
3466
|
-
const clearScreen = "\x1Bc";
|
|
3467
|
-
const clearTerminal = isWindows ? `${eraseScreen}${ESC}0f` : `${eraseScreen}${ESC}3J${ESC}H`;
|
|
3468
|
-
const enterAlternativeScreen = ESC + "?1049h";
|
|
3469
|
-
const exitAlternativeScreen = ESC + "?1049l";
|
|
3470
|
-
/**
|
|
3471
|
-
* Terminal control sequences for live display updates
|
|
3472
|
-
*/
|
|
3473
|
-
const TERMINAL_CONTROL = {
|
|
3474
|
-
HIDE_CURSOR: cursorHide,
|
|
3475
|
-
SHOW_CURSOR: cursorShow,
|
|
3476
|
-
CLEAR_SCREEN: clearScreen,
|
|
3477
|
-
CLEAR_LINE: eraseLine,
|
|
3478
|
-
MOVE_TO_TOP: cursorTo(0, 0),
|
|
3479
|
-
MOVE_UP: (n) => cursorUp(n),
|
|
3480
|
-
MOVE_DOWN: (n) => cursorDown(n),
|
|
3481
|
-
MOVE_TO_COLUMN: (n) => cursorTo(n - 1, void 0)
|
|
3482
|
-
};
|
|
3468
|
+
const SYNC_START = "\x1B[?2026h";
|
|
3469
|
+
const SYNC_END = "\x1B[?2026l";
|
|
3470
|
+
const DISABLE_LINE_WRAP = "\x1B[?7l";
|
|
3471
|
+
const ENABLE_LINE_WRAP = "\x1B[?7h";
|
|
3472
|
+
const ANSI_RESET = "\x1B[0m";
|
|
3483
3473
|
/**
|
|
3484
3474
|
* Manages terminal state for live updates
|
|
3475
|
+
* Provides a clean interface for terminal operations with automatic TTY checking
|
|
3476
|
+
* and cursor state management for live monitoring displays
|
|
3485
3477
|
*/
|
|
3486
3478
|
var TerminalManager = class {
|
|
3487
3479
|
stream;
|
|
3488
3480
|
cursorHidden = false;
|
|
3489
|
-
|
|
3481
|
+
buffer = [];
|
|
3482
|
+
useBuffering = false;
|
|
3483
|
+
alternateScreenActive = false;
|
|
3484
|
+
syncMode = false;
|
|
3490
3485
|
constructor(stream = process$1.stdout) {
|
|
3491
3486
|
this.stream = stream;
|
|
3492
|
-
this.originalWrite = stream.write.bind(stream);
|
|
3493
3487
|
}
|
|
3494
3488
|
/**
|
|
3495
|
-
* Hides the terminal cursor
|
|
3489
|
+
* Hides the terminal cursor for cleaner live updates
|
|
3490
|
+
* Only works in TTY environments (real terminals)
|
|
3496
3491
|
*/
|
|
3497
3492
|
hideCursor() {
|
|
3498
3493
|
if (!this.cursorHidden && this.stream.isTTY) {
|
|
3499
|
-
this.stream.write(
|
|
3494
|
+
this.stream.write(cursorHide);
|
|
3500
3495
|
this.cursorHidden = true;
|
|
3501
3496
|
}
|
|
3502
3497
|
}
|
|
3503
3498
|
/**
|
|
3504
3499
|
* Shows the terminal cursor
|
|
3500
|
+
* Should be called during cleanup to restore normal terminal behavior
|
|
3505
3501
|
*/
|
|
3506
3502
|
showCursor() {
|
|
3507
3503
|
if (this.cursorHidden && this.stream.isTTY) {
|
|
3508
|
-
this.stream.write(
|
|
3504
|
+
this.stream.write(cursorShow);
|
|
3509
3505
|
this.cursorHidden = false;
|
|
3510
3506
|
}
|
|
3511
3507
|
}
|
|
3512
3508
|
/**
|
|
3513
|
-
* Clears the entire screen and moves cursor to top
|
|
3509
|
+
* Clears the entire screen and moves cursor to top-left corner
|
|
3510
|
+
* Essential for live monitoring displays that need to refresh completely
|
|
3514
3511
|
*/
|
|
3515
3512
|
clearScreen() {
|
|
3516
3513
|
if (this.stream.isTTY) {
|
|
3517
|
-
this.stream.write(
|
|
3518
|
-
this.stream.write(
|
|
3514
|
+
this.stream.write(clearScreen);
|
|
3515
|
+
this.stream.write(cursorTo(0, 0));
|
|
3519
3516
|
}
|
|
3520
3517
|
}
|
|
3521
3518
|
/**
|
|
3522
|
-
*
|
|
3519
|
+
* Writes text to the terminal stream
|
|
3520
|
+
* Supports buffering mode for performance optimization
|
|
3523
3521
|
*/
|
|
3524
|
-
|
|
3525
|
-
if (this.
|
|
3522
|
+
write(text) {
|
|
3523
|
+
if (this.useBuffering) this.buffer.push(text);
|
|
3524
|
+
else this.stream.write(text);
|
|
3526
3525
|
}
|
|
3527
3526
|
/**
|
|
3528
|
-
*
|
|
3527
|
+
* Enables buffering mode - collects all writes in memory instead of sending immediately
|
|
3528
|
+
* This prevents flickering when doing many rapid updates
|
|
3529
3529
|
*/
|
|
3530
|
-
|
|
3531
|
-
|
|
3530
|
+
startBuffering() {
|
|
3531
|
+
this.useBuffering = true;
|
|
3532
|
+
this.buffer = [];
|
|
3532
3533
|
}
|
|
3533
3534
|
/**
|
|
3534
|
-
*
|
|
3535
|
+
* Sends all buffered content to terminal at once
|
|
3536
|
+
* This creates smooth, atomic updates without flickering
|
|
3535
3537
|
*/
|
|
3536
|
-
|
|
3537
|
-
if (this.
|
|
3538
|
+
flush() {
|
|
3539
|
+
if (this.useBuffering && this.buffer.length > 0) {
|
|
3540
|
+
if (this.syncMode && this.stream.isTTY) this.stream.write(SYNC_START + this.buffer.join("") + SYNC_END);
|
|
3541
|
+
else this.stream.write(this.buffer.join(""));
|
|
3542
|
+
this.buffer = [];
|
|
3543
|
+
}
|
|
3544
|
+
this.useBuffering = false;
|
|
3538
3545
|
}
|
|
3539
3546
|
/**
|
|
3540
|
-
*
|
|
3547
|
+
* Switches to alternate screen buffer (like vim/less does)
|
|
3548
|
+
* This preserves what was on screen before and allows full-screen apps
|
|
3541
3549
|
*/
|
|
3542
|
-
|
|
3543
|
-
this.stream.
|
|
3550
|
+
enterAlternateScreen() {
|
|
3551
|
+
if (!this.alternateScreenActive && this.stream.isTTY) {
|
|
3552
|
+
this.stream.write(enterAlternativeScreen);
|
|
3553
|
+
this.stream.write(DISABLE_LINE_WRAP);
|
|
3554
|
+
this.alternateScreenActive = true;
|
|
3555
|
+
}
|
|
3544
3556
|
}
|
|
3545
3557
|
/**
|
|
3546
|
-
*
|
|
3558
|
+
* Returns to normal screen, restoring what was there before
|
|
3559
|
+
*/
|
|
3560
|
+
exitAlternateScreen() {
|
|
3561
|
+
if (this.alternateScreenActive && this.stream.isTTY) {
|
|
3562
|
+
this.stream.write(ENABLE_LINE_WRAP);
|
|
3563
|
+
this.stream.write(exitAlternativeScreen);
|
|
3564
|
+
this.alternateScreenActive = false;
|
|
3565
|
+
}
|
|
3566
|
+
}
|
|
3567
|
+
/**
|
|
3568
|
+
* Enables sync mode - terminal will wait for END signal before showing updates
|
|
3569
|
+
* Prevents the user from seeing partial/torn screen updates
|
|
3570
|
+
*/
|
|
3571
|
+
enableSyncMode() {
|
|
3572
|
+
this.syncMode = true;
|
|
3573
|
+
}
|
|
3574
|
+
/**
|
|
3575
|
+
* Disables synchronized output mode
|
|
3576
|
+
*/
|
|
3577
|
+
disableSyncMode() {
|
|
3578
|
+
this.syncMode = false;
|
|
3579
|
+
}
|
|
3580
|
+
/**
|
|
3581
|
+
* Gets terminal width in columns
|
|
3582
|
+
* Falls back to 80 columns if detection fails
|
|
3547
3583
|
*/
|
|
3548
3584
|
get width() {
|
|
3549
3585
|
return this.stream.columns || 80;
|
|
3550
3586
|
}
|
|
3551
3587
|
/**
|
|
3552
|
-
* Gets terminal height
|
|
3588
|
+
* Gets terminal height in rows
|
|
3589
|
+
* Falls back to 24 rows if detection fails
|
|
3553
3590
|
*/
|
|
3554
3591
|
get height() {
|
|
3555
3592
|
return this.stream.rows || 24;
|
|
3556
3593
|
}
|
|
3557
3594
|
/**
|
|
3558
|
-
*
|
|
3595
|
+
* Returns true if output goes to a real terminal (not a file or pipe)
|
|
3596
|
+
* We only send fancy ANSI codes to real terminals
|
|
3559
3597
|
*/
|
|
3560
3598
|
get isTTY() {
|
|
3561
3599
|
return this.stream.isTTY ?? false;
|
|
3562
3600
|
}
|
|
3563
3601
|
/**
|
|
3564
|
-
*
|
|
3602
|
+
* Restores terminal to normal state - MUST call before program exits
|
|
3603
|
+
* Otherwise user's terminal might be left in a broken state
|
|
3565
3604
|
*/
|
|
3566
3605
|
cleanup() {
|
|
3567
3606
|
this.showCursor();
|
|
3607
|
+
this.exitAlternateScreen();
|
|
3608
|
+
this.disableSyncMode();
|
|
3568
3609
|
}
|
|
3569
3610
|
};
|
|
3570
3611
|
/**
|
|
3571
|
-
* Creates a progress bar string
|
|
3572
|
-
*
|
|
3573
|
-
*
|
|
3574
|
-
*
|
|
3575
|
-
* @param
|
|
3576
|
-
* @param
|
|
3612
|
+
* Creates a progress bar string with customizable appearance
|
|
3613
|
+
*
|
|
3614
|
+
* Example: createProgressBar(75, 100, 20) -> "[████████████████░░░░] 75.0%"
|
|
3615
|
+
*
|
|
3616
|
+
* @param value - Current progress value
|
|
3617
|
+
* @param max - Maximum value (100% point)
|
|
3618
|
+
* @param width - Character width of the progress bar (excluding brackets and text)
|
|
3619
|
+
* @param options - Customization options for appearance and display
|
|
3620
|
+
* @param options.showPercentage - Whether to show percentage after the bar
|
|
3577
3621
|
* @param options.showValues - Whether to show current/max values
|
|
3578
|
-
* @param options.fillChar - Character for filled portion
|
|
3579
|
-
* @param options.emptyChar - Character for empty portion
|
|
3580
|
-
* @param options.leftBracket - Left bracket character
|
|
3581
|
-
* @param options.rightBracket - Right bracket character
|
|
3582
|
-
* @param options.colors - Color configuration
|
|
3583
|
-
* @param options.colors.low - Color for low percentage
|
|
3584
|
-
* @param options.colors.medium - Color for medium percentage
|
|
3585
|
-
* @param options.colors.high - Color for high percentage
|
|
3586
|
-
* @param options.colors.critical - Color for critical percentage
|
|
3587
|
-
* @returns Formatted progress bar string
|
|
3622
|
+
* @param options.fillChar - Character for filled portion (default: '█')
|
|
3623
|
+
* @param options.emptyChar - Character for empty portion (default: '░')
|
|
3624
|
+
* @param options.leftBracket - Left bracket character (default: '[')
|
|
3625
|
+
* @param options.rightBracket - Right bracket character (default: ']')
|
|
3626
|
+
* @param options.colors - Color configuration for different thresholds
|
|
3627
|
+
* @param options.colors.low - Color for low percentage values
|
|
3628
|
+
* @param options.colors.medium - Color for medium percentage values
|
|
3629
|
+
* @param options.colors.high - Color for high percentage values
|
|
3630
|
+
* @param options.colors.critical - Color for critical percentage values
|
|
3631
|
+
* @returns Formatted progress bar string with optional percentage/values
|
|
3588
3632
|
*/
|
|
3589
3633
|
function createProgressBar(value, max, width, options = {}) {
|
|
3590
3634
|
const { showPercentage = true, showValues = false, fillChar = "█", emptyChar = "░", leftBracket = "[", rightBracket = "]", colors: colors$2 = {} } = options;
|
|
@@ -3600,17 +3644,23 @@ function createProgressBar(value, max, width, options = {}) {
|
|
|
3600
3644
|
if (color !== "") bar += color;
|
|
3601
3645
|
bar += fillChar.repeat(fillWidth);
|
|
3602
3646
|
bar += emptyChar.repeat(emptyWidth);
|
|
3603
|
-
if (color !== "") bar +=
|
|
3647
|
+
if (color !== "") bar += ANSI_RESET;
|
|
3604
3648
|
bar += rightBracket;
|
|
3605
3649
|
if (showPercentage) bar += ` ${percentage.toFixed(1)}%`;
|
|
3606
3650
|
if (showValues) bar += ` (${value}/${max})`;
|
|
3607
3651
|
return bar;
|
|
3608
3652
|
}
|
|
3609
3653
|
/**
|
|
3610
|
-
* Centers text within a
|
|
3611
|
-
*
|
|
3612
|
-
*
|
|
3613
|
-
*
|
|
3654
|
+
* Centers text within a specified width using spaces for padding
|
|
3655
|
+
*
|
|
3656
|
+
* Uses string-width to handle Unicode characters and ANSI escape codes properly.
|
|
3657
|
+
* If text is longer than width, returns original text without truncation.
|
|
3658
|
+
*
|
|
3659
|
+
* Example: centerText("Hello", 10) -> " Hello "
|
|
3660
|
+
*
|
|
3661
|
+
* @param text - Text to center (may contain ANSI color codes)
|
|
3662
|
+
* @param width - Total character width including padding
|
|
3663
|
+
* @returns Text with spaces added for centering
|
|
3614
3664
|
*/
|
|
3615
3665
|
function centerText(text, width) {
|
|
3616
3666
|
const textLength = stringWidth(text);
|
|
@@ -3619,12 +3669,40 @@ function centerText(text, width) {
|
|
|
3619
3669
|
const rightPadding = width - textLength - leftPadding;
|
|
3620
3670
|
return " ".repeat(leftPadding) + text + " ".repeat(rightPadding);
|
|
3621
3671
|
}
|
|
3622
|
-
var import_picocolors$
|
|
3623
|
-
|
|
3672
|
+
var import_picocolors$5 = __toESM(require_picocolors(), 1);
|
|
3673
|
+
/**
|
|
3674
|
+
* Delay with AbortSignal support and graceful error handling
|
|
3675
|
+
*/
|
|
3676
|
+
async function delayWithAbort(ms, signal) {
|
|
3677
|
+
await delay(ms, { signal });
|
|
3678
|
+
}
|
|
3679
|
+
/**
|
|
3680
|
+
* Shows waiting message when no Claude session is active
|
|
3681
|
+
* Uses efficient cursor positioning instead of full screen clear
|
|
3682
|
+
*/
|
|
3683
|
+
async function renderWaitingState(terminal, config, signal) {
|
|
3684
|
+
terminal.startBuffering();
|
|
3685
|
+
terminal.write(cursorTo(0, 0));
|
|
3686
|
+
terminal.write(eraseDown);
|
|
3687
|
+
terminal.write(import_picocolors$5.default.yellow("No active session block found. Waiting...\n"));
|
|
3688
|
+
terminal.write(cursorHide);
|
|
3689
|
+
terminal.flush();
|
|
3690
|
+
await delayWithAbort(config.refreshInterval, signal);
|
|
3691
|
+
}
|
|
3692
|
+
/**
|
|
3693
|
+
* Displays the live monitoring dashboard for active Claude session
|
|
3694
|
+
* Uses buffering and sync mode to prevent screen flickering
|
|
3695
|
+
*/
|
|
3696
|
+
function renderActiveBlock(terminal, activeBlock, config) {
|
|
3697
|
+
terminal.startBuffering();
|
|
3698
|
+
terminal.write(cursorTo(0, 0));
|
|
3699
|
+
terminal.write(eraseDown);
|
|
3700
|
+
renderLiveDisplay(terminal, activeBlock, config);
|
|
3701
|
+
terminal.write(cursorHide);
|
|
3702
|
+
terminal.flush();
|
|
3703
|
+
}
|
|
3624
3704
|
/**
|
|
3625
3705
|
* Format token counts with K suffix for display
|
|
3626
|
-
* @param num - Number of tokens
|
|
3627
|
-
* @returns Formatted string like "12.3k" or "999"
|
|
3628
3706
|
*/
|
|
3629
3707
|
function formatTokensShort(num) {
|
|
3630
3708
|
if (num >= 1e3) return `${(num / 1e3).toFixed(1)}k`;
|
|
@@ -3638,69 +3716,6 @@ const DETAIL_COLUMN_WIDTHS = {
|
|
|
3638
3716
|
col2: 37
|
|
3639
3717
|
};
|
|
3640
3718
|
/**
|
|
3641
|
-
* Starts live monitoring of the active session block
|
|
3642
|
-
*/
|
|
3643
|
-
async function startLiveMonitoring(config) {
|
|
3644
|
-
try {
|
|
3645
|
-
var _usingCtx = (0, import_usingCtx.default)();
|
|
3646
|
-
const terminal = new TerminalManager();
|
|
3647
|
-
const abortController = new AbortController();
|
|
3648
|
-
const cleanup = () => {
|
|
3649
|
-
abortController.abort();
|
|
3650
|
-
terminal.cleanup();
|
|
3651
|
-
terminal.clearScreen();
|
|
3652
|
-
logger.info("Live monitoring stopped.");
|
|
3653
|
-
if (process$1.exitCode == null) process$1.exit(0);
|
|
3654
|
-
};
|
|
3655
|
-
process$1.on("SIGINT", cleanup);
|
|
3656
|
-
process$1.on("SIGTERM", cleanup);
|
|
3657
|
-
terminal.hideCursor();
|
|
3658
|
-
const monitor = _usingCtx.u(new LiveMonitor({
|
|
3659
|
-
claudePath: config.claudePath,
|
|
3660
|
-
sessionDurationHours: config.sessionDurationHours,
|
|
3661
|
-
mode: config.mode,
|
|
3662
|
-
order: config.order
|
|
3663
|
-
}));
|
|
3664
|
-
try {
|
|
3665
|
-
while (!abortController.signal.aborted) {
|
|
3666
|
-
const activeBlock = await monitor.getActiveBlock();
|
|
3667
|
-
if (activeBlock == null) {
|
|
3668
|
-
terminal.clearScreen();
|
|
3669
|
-
terminal.write(import_picocolors$4.default.yellow("No active session block found. Waiting...\n"));
|
|
3670
|
-
try {
|
|
3671
|
-
await delay(config.refreshInterval, { signal: abortController.signal });
|
|
3672
|
-
} catch (error) {
|
|
3673
|
-
if ((error instanceof DOMException || error instanceof Error) && error.name === "AbortError") break;
|
|
3674
|
-
throw error;
|
|
3675
|
-
}
|
|
3676
|
-
continue;
|
|
3677
|
-
}
|
|
3678
|
-
terminal.clearScreen();
|
|
3679
|
-
renderLiveDisplay(terminal, activeBlock, config);
|
|
3680
|
-
try {
|
|
3681
|
-
await delay(config.refreshInterval, { signal: abortController.signal });
|
|
3682
|
-
} catch (error) {
|
|
3683
|
-
if ((error instanceof DOMException || error instanceof Error) && error.name === "AbortError") break;
|
|
3684
|
-
throw error;
|
|
3685
|
-
}
|
|
3686
|
-
}
|
|
3687
|
-
} catch (error) {
|
|
3688
|
-
if ((error instanceof DOMException || error instanceof Error) && error.name === "AbortError") return;
|
|
3689
|
-
terminal.clearScreen();
|
|
3690
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3691
|
-
terminal.write(import_picocolors$4.default.red(`Error: ${errorMessage}\n`));
|
|
3692
|
-
logger.error(`Live monitoring error: ${errorMessage}`);
|
|
3693
|
-
try {
|
|
3694
|
-
await delay(config.refreshInterval, { signal: abortController.signal });
|
|
3695
|
-
} catch {}
|
|
3696
|
-
}
|
|
3697
|
-
} catch (_) {
|
|
3698
|
-
_usingCtx.e = _;
|
|
3699
|
-
} finally {
|
|
3700
|
-
_usingCtx.d();
|
|
3701
|
-
}
|
|
3702
|
-
}
|
|
3703
|
-
/**
|
|
3704
3719
|
* Renders the live display for an active session block
|
|
3705
3720
|
*/
|
|
3706
3721
|
function renderLiveDisplay(terminal, block, config) {
|
|
@@ -3713,7 +3728,6 @@ function renderLiveDisplay(terminal, block, config) {
|
|
|
3713
3728
|
renderCompactLiveDisplay(terminal, block, config, totalTokens, elapsed, remaining);
|
|
3714
3729
|
return;
|
|
3715
3730
|
}
|
|
3716
|
-
terminal.clearScreen();
|
|
3717
3731
|
const boxWidth = Math.min(120, width - 2);
|
|
3718
3732
|
const boxMargin = Math.floor((width - boxWidth) / 2);
|
|
3719
3733
|
const marginStr = " ".repeat(boxMargin);
|
|
@@ -3725,8 +3739,8 @@ function renderLiveDisplay(terminal, block, config) {
|
|
|
3725
3739
|
const sessionPercent = elapsed / sessionDuration * 100;
|
|
3726
3740
|
const sessionProgressBar = createProgressBar(elapsed, sessionDuration, barWidth, {
|
|
3727
3741
|
showPercentage: false,
|
|
3728
|
-
fillChar: import_picocolors$
|
|
3729
|
-
emptyChar: import_picocolors$
|
|
3742
|
+
fillChar: import_picocolors$5.default.cyan("█"),
|
|
3743
|
+
emptyChar: import_picocolors$5.default.gray("░"),
|
|
3730
3744
|
leftBracket: "[",
|
|
3731
3745
|
rightBracket: "]"
|
|
3732
3746
|
});
|
|
@@ -3743,96 +3757,89 @@ function renderLiveDisplay(terminal, block, config) {
|
|
|
3743
3757
|
hour12: true
|
|
3744
3758
|
});
|
|
3745
3759
|
terminal.write(`${marginStr}┌${"─".repeat(boxWidth - 2)}┐\n`);
|
|
3746
|
-
terminal.write(`${marginStr}│${import_picocolors$
|
|
3760
|
+
terminal.write(`${marginStr}│${import_picocolors$5.default.bold(centerText("CLAUDE CODE - LIVE TOKEN USAGE MONITOR", boxWidth - 2))}│\n`);
|
|
3747
3761
|
terminal.write(`${marginStr}├${"─".repeat(boxWidth - 2)}┤\n`);
|
|
3748
3762
|
terminal.write(`${marginStr}│${" ".repeat(boxWidth - 2)}│\n`);
|
|
3749
|
-
const sessionLabel = import_picocolors$
|
|
3763
|
+
const sessionLabel = import_picocolors$5.default.bold("⏱️ SESSION");
|
|
3750
3764
|
const sessionLabelWidth = stringWidth(sessionLabel);
|
|
3751
3765
|
const sessionBarStr = `${sessionLabel}${"".padEnd(Math.max(0, labelWidth - sessionLabelWidth))} ${sessionProgressBar} ${sessionPercent.toFixed(1).padStart(6)}%`;
|
|
3752
3766
|
const sessionBarPadded = sessionBarStr + " ".repeat(Math.max(0, boxWidth - 3 - stringWidth(sessionBarStr)));
|
|
3753
3767
|
terminal.write(`${marginStr}│ ${sessionBarPadded}│\n`);
|
|
3754
|
-
const col1 = `${import_picocolors$
|
|
3755
|
-
const col2 = `${import_picocolors$
|
|
3756
|
-
const col3 = `${import_picocolors$
|
|
3768
|
+
const col1 = `${import_picocolors$5.default.gray("Started:")} ${startTime}`;
|
|
3769
|
+
const col2 = `${import_picocolors$5.default.gray("Elapsed:")} ${prettyMilliseconds(elapsed * 60 * 1e3, { compact: true })}`;
|
|
3770
|
+
const col3 = `${import_picocolors$5.default.gray("Remaining:")} ${prettyMilliseconds(remaining * 60 * 1e3, { compact: true })} (${endTime})`;
|
|
3757
3771
|
const col1Visible = stringWidth(col1);
|
|
3758
3772
|
const col2Visible = stringWidth(col2);
|
|
3759
3773
|
const pad1 = " ".repeat(Math.max(0, DETAIL_COLUMN_WIDTHS.col1 - col1Visible));
|
|
3760
3774
|
const pad2 = " ".repeat(Math.max(0, DETAIL_COLUMN_WIDTHS.col2 - col2Visible));
|
|
3761
|
-
const sessionDetails = ` ${col1}${pad1}${
|
|
3775
|
+
const sessionDetails = ` ${col1}${pad1}${pad2}${col3}`;
|
|
3762
3776
|
const sessionDetailsPadded = sessionDetails + " ".repeat(Math.max(0, boxWidth - 3 - stringWidth(sessionDetails)));
|
|
3763
3777
|
terminal.write(`${marginStr}│ ${sessionDetailsPadded}│\n`);
|
|
3764
3778
|
terminal.write(`${marginStr}│${" ".repeat(boxWidth - 2)}│\n`);
|
|
3765
3779
|
terminal.write(`${marginStr}├${"─".repeat(boxWidth - 2)}┤\n`);
|
|
3766
3780
|
terminal.write(`${marginStr}│${" ".repeat(boxWidth - 2)}│\n`);
|
|
3767
3781
|
const tokenPercent = config.tokenLimit != null && config.tokenLimit > 0 ? totalTokens / config.tokenLimit * 100 : 0;
|
|
3768
|
-
let barColor = import_picocolors$
|
|
3769
|
-
if (tokenPercent > 100) barColor = import_picocolors$
|
|
3770
|
-
else if (tokenPercent > 80) barColor = import_picocolors$
|
|
3782
|
+
let barColor = import_picocolors$5.default.green;
|
|
3783
|
+
if (tokenPercent > 100) barColor = import_picocolors$5.default.red;
|
|
3784
|
+
else if (tokenPercent > 80) barColor = import_picocolors$5.default.yellow;
|
|
3771
3785
|
const usageBar = config.tokenLimit != null && config.tokenLimit > 0 ? createProgressBar(totalTokens, config.tokenLimit, barWidth, {
|
|
3772
3786
|
showPercentage: false,
|
|
3773
3787
|
fillChar: barColor("█"),
|
|
3774
|
-
emptyChar: import_picocolors$
|
|
3788
|
+
emptyChar: import_picocolors$5.default.gray("░"),
|
|
3775
3789
|
leftBracket: "[",
|
|
3776
3790
|
rightBracket: "]"
|
|
3777
|
-
}) : `[${import_picocolors$
|
|
3791
|
+
}) : `[${import_picocolors$5.default.green("█".repeat(Math.floor(barWidth * .1)))}${import_picocolors$5.default.gray("░".repeat(barWidth - Math.floor(barWidth * .1)))}]`;
|
|
3778
3792
|
const burnRate = calculateBurnRate(block);
|
|
3779
|
-
const rateIndicator = burnRate != null ? burnRate.tokensPerMinute > 1e3 ? import_picocolors$
|
|
3780
|
-
const rateDisplay = burnRate != null ? `${import_picocolors$
|
|
3781
|
-
const usageLabel = import_picocolors$
|
|
3793
|
+
const rateIndicator = burnRate != null ? burnRate.tokensPerMinute > 1e3 ? import_picocolors$5.default.red("⚡ HIGH") : burnRate.tokensPerMinute > 500 ? import_picocolors$5.default.yellow("⚡ MODERATE") : import_picocolors$5.default.green("✓ NORMAL") : "";
|
|
3794
|
+
const rateDisplay = burnRate != null ? `${import_picocolors$5.default.bold("Burn Rate:")} ${Math.round(burnRate.tokensPerMinute)} token/min ${rateIndicator}` : `${import_picocolors$5.default.bold("Burn Rate:")} N/A`;
|
|
3795
|
+
const usageLabel = import_picocolors$5.default.bold("🔥 USAGE");
|
|
3782
3796
|
const usageLabelWidth = stringWidth(usageLabel);
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
const col1Visible$1 = stringWidth(col1$1);
|
|
3804
|
-
const pad1$1 = " ".repeat(Math.max(0, DETAIL_COLUMN_WIDTHS.col1 - col1Visible$1));
|
|
3805
|
-
const pad2$1 = " ".repeat(DETAIL_COLUMN_WIDTHS.col2);
|
|
3806
|
-
const usageDetails = ` ${col1$1}${pad1$1}${pad2$1}${col3$1}`;
|
|
3807
|
-
const usageDetailsPadded = usageDetails + " ".repeat(Math.max(0, boxWidth - 3 - stringWidth(usageDetails)));
|
|
3808
|
-
terminal.write(`${marginStr}│ ${usageDetailsPadded}│\n`);
|
|
3809
|
-
}
|
|
3797
|
+
const { usageBarStr, usageCol1, usageCol2, usageCol3 } = config.tokenLimit != null && config.tokenLimit > 0 ? {
|
|
3798
|
+
usageBarStr: `${usageLabel}${"".padEnd(Math.max(0, labelWidth - usageLabelWidth))} ${usageBar} ${tokenPercent.toFixed(1).padStart(6)}% (${formatTokensShort(totalTokens)}/${formatTokensShort(config.tokenLimit)})`,
|
|
3799
|
+
usageCol1: `${import_picocolors$5.default.gray("Tokens:")} ${formatNumber(totalTokens)} (${rateDisplay})`,
|
|
3800
|
+
usageCol2: `${import_picocolors$5.default.gray("Limit:")} ${formatNumber(config.tokenLimit)} tokens`,
|
|
3801
|
+
usageCol3: `${import_picocolors$5.default.gray("Cost:")} ${formatCurrency(block.costUSD)}`
|
|
3802
|
+
} : {
|
|
3803
|
+
usageBarStr: `${usageLabel}${"".padEnd(Math.max(0, labelWidth - usageLabelWidth))} ${usageBar} (${formatTokensShort(totalTokens)} tokens)`,
|
|
3804
|
+
usageCol1: `${import_picocolors$5.default.gray("Tokens:")} ${formatNumber(totalTokens)} (${rateDisplay})`,
|
|
3805
|
+
usageCol2: "",
|
|
3806
|
+
usageCol3: `${import_picocolors$5.default.gray("Cost:")} ${formatCurrency(block.costUSD)}`
|
|
3807
|
+
};
|
|
3808
|
+
const usageBarPadded = usageBarStr + " ".repeat(Math.max(0, boxWidth - 3 - stringWidth(usageBarStr)));
|
|
3809
|
+
terminal.write(`${marginStr}│ ${usageBarPadded}│\n`);
|
|
3810
|
+
const usageCol1Visible = stringWidth(usageCol1);
|
|
3811
|
+
const usageCol2Visible = stringWidth(usageCol2);
|
|
3812
|
+
const usagePad1 = " ".repeat(Math.max(0, DETAIL_COLUMN_WIDTHS.col1 - usageCol1Visible));
|
|
3813
|
+
const usagePad2 = usageCol2.length > 0 ? " ".repeat(Math.max(0, DETAIL_COLUMN_WIDTHS.col2 - usageCol2Visible)) : " ".repeat(DETAIL_COLUMN_WIDTHS.col2);
|
|
3814
|
+
const usageDetails = ` ${usageCol1}${usagePad1}${usageCol2}${usagePad2}${usageCol3}`;
|
|
3815
|
+
const usageDetailsPadded = usageDetails + " ".repeat(Math.max(0, boxWidth - 3 - stringWidth(usageDetails)));
|
|
3816
|
+
terminal.write(`${marginStr}│ ${usageDetailsPadded}│\n`);
|
|
3810
3817
|
terminal.write(`${marginStr}│${" ".repeat(boxWidth - 2)}│\n`);
|
|
3811
3818
|
terminal.write(`${marginStr}├${"─".repeat(boxWidth - 2)}┤\n`);
|
|
3812
3819
|
terminal.write(`${marginStr}│${" ".repeat(boxWidth - 2)}│\n`);
|
|
3813
3820
|
const projection = projectBlockUsage(block);
|
|
3814
3821
|
if (projection != null) {
|
|
3815
3822
|
const projectedPercent = config.tokenLimit != null && config.tokenLimit > 0 ? projection.totalTokens / config.tokenLimit * 100 : 0;
|
|
3816
|
-
let projBarColor = import_picocolors$
|
|
3817
|
-
if (projectedPercent > 100) projBarColor = import_picocolors$
|
|
3818
|
-
else if (projectedPercent > 80) projBarColor = import_picocolors$
|
|
3823
|
+
let projBarColor = import_picocolors$5.default.green;
|
|
3824
|
+
if (projectedPercent > 100) projBarColor = import_picocolors$5.default.red;
|
|
3825
|
+
else if (projectedPercent > 80) projBarColor = import_picocolors$5.default.yellow;
|
|
3819
3826
|
const projectionBar = config.tokenLimit != null && config.tokenLimit > 0 ? createProgressBar(projection.totalTokens, config.tokenLimit, barWidth, {
|
|
3820
3827
|
showPercentage: false,
|
|
3821
3828
|
fillChar: projBarColor("█"),
|
|
3822
|
-
emptyChar: import_picocolors$
|
|
3829
|
+
emptyChar: import_picocolors$5.default.gray("░"),
|
|
3823
3830
|
leftBracket: "[",
|
|
3824
3831
|
rightBracket: "]"
|
|
3825
|
-
}) : `[${import_picocolors$
|
|
3826
|
-
const limitStatus = config.tokenLimit != null && config.tokenLimit > 0 ? projectedPercent > 100 ? import_picocolors$
|
|
3827
|
-
const projLabel = import_picocolors$
|
|
3832
|
+
}) : `[${import_picocolors$5.default.green("█".repeat(Math.floor(barWidth * .15)))}${import_picocolors$5.default.gray("░".repeat(barWidth - Math.floor(barWidth * .15)))}]`;
|
|
3833
|
+
const limitStatus = config.tokenLimit != null && config.tokenLimit > 0 ? projectedPercent > 100 ? import_picocolors$5.default.red("❌ WILL EXCEED LIMIT") : projectedPercent > 80 ? import_picocolors$5.default.yellow("⚠️ APPROACHING LIMIT") : import_picocolors$5.default.green("✓ WITHIN LIMIT") : import_picocolors$5.default.green("✓ ON TRACK");
|
|
3834
|
+
const projLabel = import_picocolors$5.default.bold("📈 PROJECTION");
|
|
3828
3835
|
const projLabelWidth = stringWidth(projLabel);
|
|
3829
3836
|
if (config.tokenLimit != null && config.tokenLimit > 0) {
|
|
3830
3837
|
const projBarStr = `${projLabel}${"".padEnd(Math.max(0, labelWidth - projLabelWidth))} ${projectionBar} ${projectedPercent.toFixed(1).padStart(6)}% (${formatTokensShort(projection.totalTokens)}/${formatTokensShort(config.tokenLimit)})`;
|
|
3831
3838
|
const projBarPadded = projBarStr + " ".repeat(Math.max(0, boxWidth - 3 - stringWidth(projBarStr)));
|
|
3832
3839
|
terminal.write(`${marginStr}│ ${projBarPadded}│\n`);
|
|
3833
|
-
const col1$1 = `${import_picocolors$
|
|
3834
|
-
const col2$1 = `${import_picocolors$
|
|
3835
|
-
const col3$1 = `${import_picocolors$
|
|
3840
|
+
const col1$1 = `${import_picocolors$5.default.gray("Status:")} ${limitStatus}`;
|
|
3841
|
+
const col2$1 = `${import_picocolors$5.default.gray("Tokens:")} ${formatNumber(projection.totalTokens)}`;
|
|
3842
|
+
const col3$1 = `${import_picocolors$5.default.gray("Cost:")} ${formatCurrency(projection.totalCost)}`;
|
|
3836
3843
|
const col1Visible$1 = stringWidth(col1$1);
|
|
3837
3844
|
const col2Visible$1 = stringWidth(col2$1);
|
|
3838
3845
|
const pad1$1 = " ".repeat(Math.max(0, DETAIL_COLUMN_WIDTHS.col1 - col1Visible$1));
|
|
@@ -3844,9 +3851,9 @@ function renderLiveDisplay(terminal, block, config) {
|
|
|
3844
3851
|
const projBarStr = `${projLabel}${"".padEnd(Math.max(0, labelWidth - projLabelWidth))} ${projectionBar} (${formatTokensShort(projection.totalTokens)} tokens)`;
|
|
3845
3852
|
const projBarPadded = projBarStr + " ".repeat(Math.max(0, boxWidth - 3 - stringWidth(projBarStr)));
|
|
3846
3853
|
terminal.write(`${marginStr}│ ${projBarPadded}│\n`);
|
|
3847
|
-
const col1$1 = `${import_picocolors$
|
|
3848
|
-
const col2$1 = `${import_picocolors$
|
|
3849
|
-
const col3$1 = `${import_picocolors$
|
|
3854
|
+
const col1$1 = `${import_picocolors$5.default.gray("Status:")} ${limitStatus}`;
|
|
3855
|
+
const col2$1 = `${import_picocolors$5.default.gray("Tokens:")} ${formatNumber(projection.totalTokens)}`;
|
|
3856
|
+
const col3$1 = `${import_picocolors$5.default.gray("Cost:")} ${formatCurrency(projection.totalCost)}`;
|
|
3850
3857
|
const col1Visible$1 = stringWidth(col1$1);
|
|
3851
3858
|
const col2Visible$1 = stringWidth(col2$1);
|
|
3852
3859
|
const pad1$1 = " ".repeat(Math.max(0, DETAIL_COLUMN_WIDTHS.col1 - col1Visible$1));
|
|
@@ -3865,7 +3872,7 @@ function renderLiveDisplay(terminal, block, config) {
|
|
|
3865
3872
|
}
|
|
3866
3873
|
terminal.write(`${marginStr}├${"─".repeat(boxWidth - 2)}┤\n`);
|
|
3867
3874
|
const refreshText = `↻ Refreshing every ${config.refreshInterval / 1e3}s • Press Ctrl+C to stop`;
|
|
3868
|
-
terminal.write(`${marginStr}│${import_picocolors$
|
|
3875
|
+
terminal.write(`${marginStr}│${import_picocolors$5.default.gray(centerText(refreshText, boxWidth - 2))}│\n`);
|
|
3869
3876
|
terminal.write(`${marginStr}└${"─".repeat(boxWidth - 2)}┘\n`);
|
|
3870
3877
|
}
|
|
3871
3878
|
/**
|
|
@@ -3873,20 +3880,81 @@ function renderLiveDisplay(terminal, block, config) {
|
|
|
3873
3880
|
*/
|
|
3874
3881
|
function renderCompactLiveDisplay(terminal, block, config, totalTokens, elapsed, remaining) {
|
|
3875
3882
|
const width = terminal.width;
|
|
3876
|
-
terminal.write(`${import_picocolors$
|
|
3883
|
+
terminal.write(`${import_picocolors$5.default.bold(centerText("LIVE MONITOR", width))}\n`);
|
|
3877
3884
|
terminal.write(`${"─".repeat(width)}\n`);
|
|
3878
3885
|
const sessionPercent = elapsed / (elapsed + remaining) * 100;
|
|
3879
3886
|
terminal.write(`Session: ${sessionPercent.toFixed(1)}% (${Math.floor(elapsed / 60)}h ${Math.floor(elapsed % 60)}m)\n`);
|
|
3880
3887
|
if (config.tokenLimit != null && config.tokenLimit > 0) {
|
|
3881
3888
|
const tokenPercent = totalTokens / config.tokenLimit * 100;
|
|
3882
|
-
const status = tokenPercent > 100 ? import_picocolors$
|
|
3889
|
+
const status = tokenPercent > 100 ? import_picocolors$5.default.red("OVER") : tokenPercent > 80 ? import_picocolors$5.default.yellow("WARN") : import_picocolors$5.default.green("OK");
|
|
3883
3890
|
terminal.write(`Tokens: ${formatNumber(totalTokens)}/${formatNumber(config.tokenLimit)} ${status}\n`);
|
|
3884
3891
|
} else terminal.write(`Tokens: ${formatNumber(totalTokens)}\n`);
|
|
3885
3892
|
terminal.write(`Cost: ${formatCurrency(block.costUSD)}\n`);
|
|
3886
3893
|
const burnRate = calculateBurnRate(block);
|
|
3887
3894
|
if (burnRate != null) terminal.write(`Rate: ${formatNumber(burnRate.tokensPerMinute)}/min\n`);
|
|
3888
3895
|
terminal.write(`${"─".repeat(width)}\n`);
|
|
3889
|
-
terminal.write(import_picocolors$
|
|
3896
|
+
terminal.write(import_picocolors$5.default.gray(`Refresh: ${config.refreshInterval / 1e3}s | Ctrl+C: stop\n`));
|
|
3897
|
+
}
|
|
3898
|
+
var import_picocolors$4 = __toESM(require_picocolors(), 1);
|
|
3899
|
+
var import_usingCtx = __toESM(require_usingCtx(), 1);
|
|
3900
|
+
async function startLiveMonitoring(config) {
|
|
3901
|
+
try {
|
|
3902
|
+
var _usingCtx = (0, import_usingCtx.default)();
|
|
3903
|
+
const terminal = new TerminalManager();
|
|
3904
|
+
const abortController = new AbortController();
|
|
3905
|
+
let lastRenderTime = 0;
|
|
3906
|
+
const cleanup = () => {
|
|
3907
|
+
abortController.abort();
|
|
3908
|
+
terminal.cleanup();
|
|
3909
|
+
terminal.clearScreen();
|
|
3910
|
+
logger.info("Live monitoring stopped.");
|
|
3911
|
+
if (process$1.exitCode == null) process$1.exit(0);
|
|
3912
|
+
};
|
|
3913
|
+
process$1.on("SIGINT", cleanup);
|
|
3914
|
+
process$1.on("SIGTERM", cleanup);
|
|
3915
|
+
terminal.enterAlternateScreen();
|
|
3916
|
+
terminal.enableSyncMode();
|
|
3917
|
+
terminal.clearScreen();
|
|
3918
|
+
terminal.hideCursor();
|
|
3919
|
+
const monitor = _usingCtx.u(new LiveMonitor({
|
|
3920
|
+
claudePath: config.claudePath,
|
|
3921
|
+
sessionDurationHours: config.sessionDurationHours,
|
|
3922
|
+
mode: config.mode,
|
|
3923
|
+
order: config.order
|
|
3924
|
+
}));
|
|
3925
|
+
try {
|
|
3926
|
+
while (!abortController.signal.aborted) {
|
|
3927
|
+
const now = Date.now();
|
|
3928
|
+
const timeSinceLastRender = now - lastRenderTime;
|
|
3929
|
+
if (timeSinceLastRender < MIN_RENDER_INTERVAL_MS) {
|
|
3930
|
+
await delayWithAbort(MIN_RENDER_INTERVAL_MS - timeSinceLastRender, abortController.signal);
|
|
3931
|
+
continue;
|
|
3932
|
+
}
|
|
3933
|
+
const activeBlock = await monitor.getActiveBlock();
|
|
3934
|
+
monitor.clearCache();
|
|
3935
|
+
if (activeBlock == null) {
|
|
3936
|
+
await renderWaitingState(terminal, config, abortController.signal);
|
|
3937
|
+
continue;
|
|
3938
|
+
}
|
|
3939
|
+
renderActiveBlock(terminal, activeBlock, config);
|
|
3940
|
+
lastRenderTime = Date.now();
|
|
3941
|
+
await delayWithAbort(config.refreshInterval, abortController.signal);
|
|
3942
|
+
}
|
|
3943
|
+
} catch (error) {
|
|
3944
|
+
if ((error instanceof DOMException || error instanceof Error) && error.name === "AbortError") return;
|
|
3945
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3946
|
+
terminal.startBuffering();
|
|
3947
|
+
terminal.clearScreen();
|
|
3948
|
+
terminal.write(import_picocolors$4.default.red(`Error: ${errorMessage}\n`));
|
|
3949
|
+
terminal.flush();
|
|
3950
|
+
logger.error(`Live monitoring error: ${errorMessage}`);
|
|
3951
|
+
await delayWithAbort(config.refreshInterval, abortController.signal).catch(() => {});
|
|
3952
|
+
}
|
|
3953
|
+
} catch (_) {
|
|
3954
|
+
_usingCtx.e = _;
|
|
3955
|
+
} finally {
|
|
3956
|
+
_usingCtx.d();
|
|
3957
|
+
}
|
|
3890
3958
|
}
|
|
3891
3959
|
var import_picocolors$3 = __toESM(require_picocolors(), 1);
|
|
3892
3960
|
/**
|
|
@@ -4037,8 +4105,13 @@ const blocksCommand = define({
|
|
|
4037
4105
|
}
|
|
4038
4106
|
const refreshInterval = Math.max(MIN_REFRESH_INTERVAL_SECONDS, Math.min(MAX_REFRESH_INTERVAL_SECONDS, ctx.values.refreshInterval));
|
|
4039
4107
|
if (refreshInterval !== ctx.values.refreshInterval) logger.warn(`Refresh interval adjusted to ${refreshInterval} seconds (valid range: ${MIN_REFRESH_INTERVAL_SECONDS}-${MAX_REFRESH_INTERVAL_SECONDS})`);
|
|
4108
|
+
const paths = getClaudePaths();
|
|
4109
|
+
if (paths.length === 0) {
|
|
4110
|
+
logger.error("No valid Claude data directory found");
|
|
4111
|
+
throw new Error("No valid Claude data directory found");
|
|
4112
|
+
}
|
|
4040
4113
|
await startLiveMonitoring({
|
|
4041
|
-
claudePath:
|
|
4114
|
+
claudePath: paths[0],
|
|
4042
4115
|
tokenLimit: parseTokenLimit(tokenLimitValue, maxTokensFromAll),
|
|
4043
4116
|
refreshInterval: refreshInterval * 1e3,
|
|
4044
4117
|
sessionDurationHours: ctx.values.sessionLength,
|
|
@@ -4732,8 +4805,13 @@ const mcpCommand = define({
|
|
|
4732
4805
|
async run(ctx) {
|
|
4733
4806
|
const { type, mode, port } = ctx.values;
|
|
4734
4807
|
if (type === "stdio") logger.level = 0;
|
|
4808
|
+
const paths = getClaudePaths();
|
|
4809
|
+
if (paths.length === 0) {
|
|
4810
|
+
logger.error("No valid Claude data directory found");
|
|
4811
|
+
throw new Error("No valid Claude data directory found");
|
|
4812
|
+
}
|
|
4735
4813
|
const options = {
|
|
4736
|
-
claudePath:
|
|
4814
|
+
claudePath: paths[0],
|
|
4737
4815
|
mode
|
|
4738
4816
|
};
|
|
4739
4817
|
if (type === "stdio") {
|