UNPKG

ccusage

Version:

Usage analysis tool for Claude Code

1,278 lines 129 kB
#!/usr/bin/env node import { $ as DEFAULT_RECENT_DAYS, B as pushBreakdownRows, D as calculateBurnRate, E as DEFAULT_SESSION_DURATION_HOURS, F as formatDateCompact, G as BLOCKS_COMPACT_WIDTH_THRESHOLD, H as getFileModifiedTime, I as formatModelsDisplayMultiline, K as BLOCKS_DEFAULT_TERMINAL_WIDTH, L as formatNumber, M as addEmptySeparatorRow, N as createUsageReportTable, O as filterRecentBlocks, P as formatCurrency, Q as DEFAULT_LOCALE, R as formatTotalsRow, U as unreachable, V as require_picocolors, W as _usingCtx, Y as CONFIG_FILE_NAME, Z as DEFAULT_CONTEXT_USAGE_THRESHOLDS, _ as loadWeeklyUsageData, at as try_, ct as inspectError, dt as isSuccess, et as DEFAULT_REFRESH_INTERVAL_SECONDS, f as loadDailyUsageData, ft as isFailure, g as loadSessionUsageById, h as loadSessionData, it as unwrap, j as ResponsiveTable, k as projectBlockUsage, lt as inspect, m as loadSessionBlockData, mt as __toESM, n as calculateContextTokens, nt as WEEK_DAYS, ot as pipe, p as loadMonthlyUsageData, pt as toArray, q as BLOCKS_WARNING_THRESHOLD, s as getClaudePaths, st as map$1, ut as succeed, z as formatUsageDataRow } from "./data-loader-B58Zt4YE.js"; import { B as getTotalTokens, D as maxValue, E as integer$1, F as safeParse, I as string, L as transform, M as parse$1, O as minValue, P as pipe$1, R as trim, T as flatten, d as filterDateSchema, k as number, n as SortOrders, t as CostModes, w as check, y as statuslineHookJsonSchema, z as union } from "./_types-DY3gqCWm.js"; import { n as createTotalsObject, t as calculateTotals } from "./calculate-cost-DWGfKMSD.js"; import { a as version, i as name, n as logger, r as description, t as log } from "./logger-TGVysPie.js"; import { n as printMismatchReport, t as detectMismatches } from "./debug-0PxspX9a.js"; import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs"; import a from "node:fs/promises"; import path, { join } from "node:path"; import process$1 from "node:process"; import { tmpdir } from "node:os"; import { fileURLToPath } from "node:url"; import { stripVTControlCharacters } from "node:util"; import { spawn } from "node:child_process"; import { on, once } from "node:events"; import { pipeline } from "node:stream/promises"; import * as readline from "node:readline/promises"; const DEFAULT_LOCALE$1 = "en-US"; const BUILT_IN_PREFIX = "_"; const ARG_PREFIX = "arg"; const BUILT_IN_KEY_SEPARATOR = ":"; const ANONYMOUS_COMMAND_NAME = "(anonymous)"; const NOOP = () => {}; const COMMON_ARGS = { help: { type: "boolean", short: "h", description: "Display this help message" }, version: { type: "boolean", short: "v", description: "Display this version" } }; const COMMAND_OPTIONS_DEFAULT = { name: void 0, description: void 0, version: void 0, cwd: void 0, usageSilent: false, subCommands: void 0, leftMargin: 2, middleMargin: 10, usageOptionType: false, usageOptionValue: true, renderHeader: void 0, renderUsage: void 0, renderValidationErrors: void 0, translationAdapterFactory: void 0 }; function isLazyCommand(cmd) { return typeof cmd === "function" && "commandName" in cmd && !!cmd.commandName; } async function resolveLazyCommand(cmd, name$1, needRunResolving = false) { let command; if (isLazyCommand(cmd)) { command = Object.assign(create(), { name: cmd.commandName, description: cmd.description, args: cmd.args, examples: cmd.examples, resource: cmd.resource }); if (needRunResolving) { const loaded = await cmd(); if (typeof loaded === "function") command.run = loaded; else if (typeof loaded === "object") { if (loaded.run == null) throw new TypeError(`'run' is required in command: ${cmd.name || name$1}`); command.run = loaded.run; command.name = loaded.name; command.description = loaded.description; command.args = loaded.args; command.examples = loaded.examples; command.resource = loaded.resource; } else throw new TypeError(`Cannot resolve command: ${cmd.name || name$1}`); } } else command = Object.assign(create(), cmd); if (command.name == null && name$1) command.name = name$1; return deepFreeze(command); } function resolveBuiltInKey(key) { return `${BUILT_IN_PREFIX}${BUILT_IN_KEY_SEPARATOR}${key}`; } function resolveArgKey(key) { return `${ARG_PREFIX}${BUILT_IN_KEY_SEPARATOR}${key}`; } async function resolveExamples(ctx, examples) { return typeof examples === "string" ? examples : typeof examples === "function" ? await examples(ctx) : ""; } function mapResourceWithBuiltinKey(resource) { return Object.entries(resource).reduce((acc, [key, value$1]) => { acc[resolveBuiltInKey(key)] = value$1; return acc; }, create()); } function create(obj = null) { return Object.create(obj); } function log$1(...args) { console.log(...args); } function deepFreeze(obj) { if (obj === null || typeof obj !== "object") return obj; for (const key of Object.keys(obj)) { const value$1 = obj[key]; if (typeof value$1 === "object" && value$1 !== null) deepFreeze(value$1); } return Object.freeze(obj); } var en_US_default = { COMMAND: "COMMAND", COMMANDS: "COMMANDS", SUBCOMMAND: "SUBCOMMAND", USAGE: "USAGE", ARGUMENTS: "ARGUMENTS", OPTIONS: "OPTIONS", EXAMPLES: "EXAMPLES", FORMORE: "For more info, run any command with the `--help` flag:", NEGATABLE: "Negatable of", DEFAULT: "default", CHOICES: "choices", help: "Display this help message", version: "Display this version" }; function createTranslationAdapter(options) { return new DefaultTranslation(options); } var DefaultTranslation = class { #resources = /* @__PURE__ */ new Map(); #options; constructor(options) { this.#options = options; this.#resources.set(options.locale, create()); if (options.locale !== options.fallbackLocale) this.#resources.set(options.fallbackLocale, create()); } getResource(locale) { return this.#resources.get(locale); } setResource(locale, resource) { this.#resources.set(locale, resource); } getMessage(locale, key) { const resource = this.getResource(locale); if (resource) return resource[key]; } translate(locale, key, values = create()) { let message = this.getMessage(locale, key); if (message === void 0 && locale !== this.#options.fallbackLocale) message = this.getMessage(this.#options.fallbackLocale, key); if (message === void 0) return; return message.replaceAll(/\{\{(\w+)\}\}/g, (_$1, name$1) => { return values[name$1] == null ? "" : values[name$1].toString(); }); } }; const BUILT_IN_PREFIX_CODE = BUILT_IN_PREFIX.codePointAt(0); async function createCommandContext({ args, values, positionals, rest, argv, tokens, command, cliOptions, callMode = "entry", omitted = false }) { const _args = Object.entries(args).reduce((acc, [key, value$1]) => { acc[key] = Object.assign(create(), value$1); return acc; }, create()); const env = Object.assign(create(), COMMAND_OPTIONS_DEFAULT, cliOptions); const locale = resolveLocale(cliOptions.locale); const localeStr = locale.toString(); const adapter = (cliOptions.translationAdapterFactory || createTranslationAdapter)({ locale: localeStr, fallbackLocale: DEFAULT_LOCALE$1 }); const localeResources = /* @__PURE__ */ new Map(); let builtInLoadedResources; localeResources.set(DEFAULT_LOCALE$1, mapResourceWithBuiltinKey(en_US_default)); if (DEFAULT_LOCALE$1 !== localeStr) try { builtInLoadedResources = (await import(`./locales/${localeStr}.json`, { with: { type: "json" } })).default; localeResources.set(localeStr, mapResourceWithBuiltinKey(builtInLoadedResources)); } catch {} function translate(key, values$1 = create()) { const strKey = key; if (strKey.codePointAt(0) === BUILT_IN_PREFIX_CODE) return (localeResources.get(localeStr) || localeResources.get(DEFAULT_LOCALE$1))[strKey] || strKey; else return adapter.translate(locale.toString(), strKey, values$1) || ""; } let cachedCommands; async function loadCommands() { if (cachedCommands) return cachedCommands; const subCommands$1 = [...cliOptions.subCommands || []]; return cachedCommands = await Promise.all(subCommands$1.map(async ([name$1, cmd]) => await resolveLazyCommand(cmd, name$1))); } const ctx = deepFreeze(Object.assign(create(), { name: getCommandName(command), description: command.description, omitted, callMode, locale, env, args: _args, values, positionals, rest, _: argv, tokens, toKebab: command.toKebab, log: cliOptions.usageSilent ? NOOP : log$1, loadCommands, translate })); const defaultCommandResource = Object.entries(args).map(([key, arg]) => { return [key, arg.description || ""]; }).reduce((res, [key, value$1]) => { res[resolveArgKey(key)] = value$1; return res; }, create()); defaultCommandResource.description = command.description || ""; defaultCommandResource.examples = await resolveExamples(ctx, command.examples); adapter.setResource(DEFAULT_LOCALE$1, defaultCommandResource); const originalResource = await loadCommandResource(ctx, command); if (originalResource) { const resource = Object.assign(create(), originalResource, { examples: await resolveExamples(ctx, originalResource.examples) }); if (builtInLoadedResources) { resource.help = builtInLoadedResources.help; resource.version = builtInLoadedResources.version; } adapter.setResource(localeStr, resource); } return ctx; } function getCommandName(cmd) { if (isLazyCommand(cmd)) return cmd.commandName || cmd.name || ANONYMOUS_COMMAND_NAME; else if (typeof cmd === "object") return cmd.name || ANONYMOUS_COMMAND_NAME; else return ANONYMOUS_COMMAND_NAME; } function resolveLocale(locale) { return locale instanceof Intl.Locale ? locale : typeof locale === "string" ? new Intl.Locale(locale) : new Intl.Locale(DEFAULT_LOCALE$1); } async function loadCommandResource(ctx, command) { let resource; try { resource = await command.resource?.(ctx); } catch {} return resource; } function define(definition) { return definition; } /** * @author kazuya kawaguchi (a.k.a. kazupon) * @license MIT */ function kebabnize(str$1) { return str$1.replace(/[A-Z]/g, (match, offset) => (offset > 0 ? "-" : "") + match.toLowerCase()); } function renderHeader(ctx) { const title = ctx.env.description || ctx.env.name || ""; return Promise.resolve(title ? `${title} (${ctx.env.name || ""}${ctx.env.version ? ` v${ctx.env.version}` : ""})` : title); } const COMMON_ARGS_KEYS = Object.keys(COMMON_ARGS); async function renderUsage(ctx) { const messages = []; if (!ctx.omitted) { const description$1 = resolveDescription(ctx); if (description$1) messages.push(description$1, ""); } messages.push(...await renderUsageSection(ctx), ""); if (ctx.omitted && await hasCommands(ctx)) messages.push(...await renderCommandsSection(ctx), ""); if (hasPositionalArgs(ctx)) messages.push(...await renderPositionalArgsSection(ctx), ""); if (hasOptionalArgs(ctx)) messages.push(...await renderOptionalArgsSection(ctx), ""); const examples = await renderExamplesSection(ctx); if (examples.length > 0) messages.push(...examples, ""); return messages.join("\n"); } async function renderPositionalArgsSection(ctx) { const messages = []; messages.push(`${ctx.translate(resolveBuiltInKey("ARGUMENTS"))}:`); messages.push(await generatePositionalArgsUsage(ctx)); return messages; } async function renderOptionalArgsSection(ctx) { const messages = []; messages.push(`${ctx.translate(resolveBuiltInKey("OPTIONS"))}:`); messages.push(await generateOptionalArgsUsage(ctx, getOptionalArgsPairs(ctx))); return messages; } async function renderExamplesSection(ctx) { const messages = []; const resolvedExamples = await resolveExamples$1(ctx); if (resolvedExamples) { const examples = resolvedExamples.split("\n").map((example) => example.padStart(ctx.env.leftMargin + example.length)); messages.push(`${ctx.translate(resolveBuiltInKey("EXAMPLES"))}:`, ...examples); } return messages; } async function renderUsageSection(ctx) { const messages = [`${ctx.translate(resolveBuiltInKey("USAGE"))}:`]; if (ctx.omitted) { const defaultCommand = `${resolveEntry(ctx)}${await hasCommands(ctx) ? ` [${resolveSubCommand(ctx)}]` : ""} ${[generateOptionsSymbols(ctx), generatePositionalSymbols(ctx)].filter(Boolean).join(" ")}`; messages.push(defaultCommand.padStart(ctx.env.leftMargin + defaultCommand.length)); if (await hasCommands(ctx)) { const commandsUsage = `${resolveEntry(ctx)} <${ctx.translate(resolveBuiltInKey("COMMANDS"))}>`; messages.push(commandsUsage.padStart(ctx.env.leftMargin + commandsUsage.length)); } } else { const usageStr = `${resolveEntry(ctx)} ${resolveSubCommand(ctx)} ${[generateOptionsSymbols(ctx), generatePositionalSymbols(ctx)].filter(Boolean).join(" ")}`; messages.push(usageStr.padStart(ctx.env.leftMargin + usageStr.length)); } return messages; } async function renderCommandsSection(ctx) { const messages = [`${ctx.translate(resolveBuiltInKey("COMMANDS"))}:`]; const loadedCommands = await ctx.loadCommands(); const commandMaxLength = Math.max(...loadedCommands.map((cmd) => (cmd.name || "").length)); const commandsStr = await Promise.all(loadedCommands.map((cmd) => { const key = cmd.name || ""; const desc = cmd.description || ""; const command = `${key.padEnd(commandMaxLength + ctx.env.middleMargin)}${desc} `; return `${command.padStart(ctx.env.leftMargin + command.length)} `; })); messages.push(...commandsStr, "", ctx.translate(resolveBuiltInKey("FORMORE"))); messages.push(...loadedCommands.map((cmd) => { const commandHelp = `${ctx.env.name} ${cmd.name} --help`; return `${commandHelp.padStart(ctx.env.leftMargin + commandHelp.length)}`; })); return messages; } function resolveEntry(ctx) { return ctx.env.name || ctx.translate(resolveBuiltInKey("COMMAND")); } function resolveSubCommand(ctx) { return ctx.name || ctx.translate(resolveBuiltInKey("SUBCOMMAND")); } function resolveDescription(ctx) { return ctx.translate("description") || ctx.description || ""; } async function resolveExamples$1(ctx) { const ret = ctx.translate("examples"); if (ret) return ret; const command = ctx.env.subCommands?.get(ctx.name || ""); return await resolveExamples(ctx, command?.examples); } async function hasCommands(ctx) { return (await ctx.loadCommands()).length > 1; } function hasOptionalArgs(ctx) { return !!(ctx.args && Object.values(ctx.args).some((arg) => arg.type !== "positional")); } function hasPositionalArgs(ctx) { return !!(ctx.args && Object.values(ctx.args).some((arg) => arg.type === "positional")); } function hasAllDefaultOptions(ctx) { return !!(ctx.args && Object.values(ctx.args).every((arg) => arg.default)); } function generateOptionsSymbols(ctx) { return hasOptionalArgs(ctx) ? hasAllDefaultOptions(ctx) ? `[${ctx.translate(resolveBuiltInKey("OPTIONS"))}]` : `<${ctx.translate(resolveBuiltInKey("OPTIONS"))}>` : ""; } function makeShortLongOptionPair(schema, name$1, toKebab) { let key = `--${toKebab || schema.toKebab ? kebabnize(name$1) : name$1}`; if (schema.short) key = `-${schema.short}, ${key}`; return key; } function getOptionalArgsPairs(ctx) { return Object.entries(ctx.args).reduce((acc, [name$1, schema]) => { if (schema.type === "positional") return acc; let key = makeShortLongOptionPair(schema, name$1, ctx.toKebab); if (schema.type !== "boolean") { const displayName = ctx.toKebab || schema.toKebab ? kebabnize(name$1) : name$1; key = schema.default ? `${key} [${displayName}]` : `${key} <${displayName}>`; } acc[name$1] = key; if (schema.type === "boolean" && schema.negatable && !COMMON_ARGS_KEYS.includes(name$1)) { const displayName = ctx.toKebab || schema.toKebab ? kebabnize(name$1) : name$1; acc[`no-${name$1}`] = `--no-${displayName}`; } return acc; }, create()); } const resolveNegatableKey = (key) => key.split("no-")[1]; function resolveNegatableType(key, ctx) { return ctx.args[key.startsWith("no-") ? resolveNegatableKey(key) : key].type; } function generateDefaultDisplayValue(ctx, schema) { return `${ctx.translate(resolveBuiltInKey("DEFAULT"))}: ${schema.default}`; } function resolveDisplayValue(ctx, key) { if (COMMON_ARGS_KEYS.includes(key)) return ""; const schema = ctx.args[key]; if ((schema.type === "boolean" || schema.type === "number" || schema.type === "string" || schema.type === "custom") && schema.default !== void 0) return `(${generateDefaultDisplayValue(ctx, schema)})`; if (schema.type === "enum") { const _default = schema.default !== void 0 ? generateDefaultDisplayValue(ctx, schema) : ""; const choices = `${ctx.translate(resolveBuiltInKey("CHOICES"))}: ${schema.choices.join(" | ")}`; return `(${_default ? `${_default}, ${choices}` : choices})`; } return ""; } async function generateOptionalArgsUsage(ctx, optionsPairs) { const optionsMaxLength = Math.max(...Object.entries(optionsPairs).map(([_$1, value$1]) => value$1.length)); const optionSchemaMaxLength = ctx.env.usageOptionType ? Math.max(...Object.entries(optionsPairs).map(([key]) => resolveNegatableType(key, ctx).length)) : 0; return (await Promise.all(Object.entries(optionsPairs).map(([key, value$1]) => { let rawDesc = ctx.translate(resolveArgKey(key)); if (!rawDesc && key.startsWith("no-")) { const name$1 = resolveNegatableKey(key); const schema = ctx.args[name$1]; const optionKey = makeShortLongOptionPair(schema, name$1, ctx.toKebab); rawDesc = `${ctx.translate(resolveBuiltInKey("NEGATABLE"))} ${optionKey}`; } const optionsSchema = ctx.env.usageOptionType ? `[${resolveNegatableType(key, ctx)}] ` : ""; const valueDesc = key.startsWith("no-") ? "" : resolveDisplayValue(ctx, key); const desc = `${optionsSchema ? optionsSchema.padEnd(optionSchemaMaxLength + 3) : ""}${rawDesc}`; const option = `${value$1.padEnd(optionsMaxLength + ctx.env.middleMargin)}${desc}${valueDesc ? ` ${valueDesc}` : ""}`; return `${option.padStart(ctx.env.leftMargin + option.length)}`; }))).join("\n"); } function getPositionalArgs(ctx) { return Object.entries(ctx.args).filter(([_$1, schema]) => schema.type === "positional"); } async function generatePositionalArgsUsage(ctx) { const positionals = getPositionalArgs(ctx); const argsMaxLength = Math.max(...positionals.map(([name$1]) => name$1.length)); return (await Promise.all(positionals.map(([name$1]) => { const desc = ctx.translate(resolveArgKey(name$1)) || ctx.args[name$1].description || ""; const arg = `${name$1.padEnd(argsMaxLength + ctx.env.middleMargin)} ${desc}`; return `${arg.padStart(ctx.env.leftMargin + arg.length)}`; }))).join("\n"); } function generatePositionalSymbols(ctx) { return hasPositionalArgs(ctx) ? getPositionalArgs(ctx).map(([name$1]) => `<${name$1}>`).join(" ") : ""; } function renderValidationErrors(_ctx, error) { const messages = []; for (const err of error.errors) messages.push(err.message); return Promise.resolve(messages.join("\n")); } const HYPHEN_CHAR = "-"; const HYPHEN_CODE = HYPHEN_CHAR.codePointAt(0); const EQUAL_CHAR = "="; const EQUAL_CODE = EQUAL_CHAR.codePointAt(0); const TERMINATOR = "--"; const SHORT_OPTION_PREFIX = HYPHEN_CHAR; const LONG_OPTION_PREFIX = "--"; function parseArgs(args, options = {}) { const { allowCompatible = false } = options; const tokens = []; const remainings = [...args]; let index = -1; let groupCount = 0; let hasShortValueSeparator = false; while (remainings.length > 0) { const arg = remainings.shift(); if (arg == void 0) break; const nextArg = remainings[0]; if (groupCount > 0) groupCount--; else index++; if (arg === TERMINATOR) { tokens.push({ kind: "option-terminator", index }); const mapped = remainings.map((arg$1) => { return { kind: "positional", index: ++index, value: arg$1 }; }); tokens.push(...mapped); break; } if (isShortOption(arg)) { const shortOption = arg.charAt(1); let value$1; let inlineValue; if (groupCount) { tokens.push({ kind: "option", name: shortOption, rawName: arg, index, value: value$1, inlineValue }); if (groupCount === 1 && hasOptionValue(nextArg)) { value$1 = remainings.shift(); if (hasShortValueSeparator) { inlineValue = true; hasShortValueSeparator = false; } tokens.push({ kind: "option", index, value: value$1, inlineValue }); } } else tokens.push({ kind: "option", name: shortOption, rawName: arg, index, value: value$1, inlineValue }); if (value$1 != null) ++index; continue; } if (isShortOptionGroup(arg)) { const expanded = []; let shortValue = ""; for (let i = 1; i < arg.length; i++) { const shortableOption = arg.charAt(i); if (hasShortValueSeparator) shortValue += shortableOption; else if (!allowCompatible && shortableOption.codePointAt(0) === EQUAL_CODE) hasShortValueSeparator = true; else expanded.push(`${SHORT_OPTION_PREFIX}${shortableOption}`); } if (shortValue) expanded.push(shortValue); remainings.unshift(...expanded); groupCount = expanded.length; continue; } if (isLongOption(arg)) { const longOption = arg.slice(2); tokens.push({ kind: "option", name: longOption, rawName: arg, index, value: void 0, inlineValue: void 0 }); continue; } if (isLongOptionAndValue(arg)) { const equalIndex = arg.indexOf(EQUAL_CHAR); const longOption = arg.slice(2, equalIndex); const value$1 = arg.slice(equalIndex + 1); tokens.push({ kind: "option", name: longOption, rawName: `${LONG_OPTION_PREFIX}${longOption}`, index, value: value$1, inlineValue: true }); continue; } tokens.push({ kind: "positional", index, value: arg }); } return tokens; } function isShortOption(arg) { return arg.length === 2 && arg.codePointAt(0) === HYPHEN_CODE && arg.codePointAt(1) !== HYPHEN_CODE; } function isShortOptionGroup(arg) { if (arg.length <= 2) return false; if (arg.codePointAt(0) !== HYPHEN_CODE) return false; if (arg.codePointAt(1) === HYPHEN_CODE) return false; return true; } function isLongOption(arg) { return hasLongOptionPrefix(arg) && !arg.includes(EQUAL_CHAR, 3); } function isLongOptionAndValue(arg) { return hasLongOptionPrefix(arg) && arg.includes(EQUAL_CHAR, 3); } function hasLongOptionPrefix(arg) { return arg.length > 2 && ~arg.indexOf(LONG_OPTION_PREFIX); } function hasOptionValue(value$1) { return !(value$1 == null) && value$1.codePointAt(0) !== HYPHEN_CODE; } const SKIP_POSITIONAL_DEFAULT = -1; function resolveArgs(args, tokens, { shortGrouping = false, skipPositional = SKIP_POSITIONAL_DEFAULT, toKebab = false } = {}) { const skipPositionalIndex = typeof skipPositional === "number" ? Math.max(skipPositional, SKIP_POSITIONAL_DEFAULT) : SKIP_POSITIONAL_DEFAULT; const rest = []; const optionTokens = []; const positionalTokens = []; let currentLongOption; let currentShortOption; const expandableShortOptions = []; function toShortValue() { if (expandableShortOptions.length === 0) return void 0; else { const value$1 = expandableShortOptions.map((token) => token.name).join(""); expandableShortOptions.length = 0; return value$1; } } function applyLongOptionValue(value$1 = void 0) { if (currentLongOption) { currentLongOption.value = value$1; optionTokens.push({ ...currentLongOption }); currentLongOption = void 0; } } function applyShortOptionValue(value$1 = void 0) { if (currentShortOption) { currentShortOption.value = value$1 || toShortValue(); optionTokens.push({ ...currentShortOption }); currentShortOption = void 0; } } const schemas = Object.values(args); let terminated = false; for (let i = 0; i < tokens.length; i++) { const token = tokens[i]; if (token.kind === "positional") { if (terminated && token.value) { rest.push(token.value); continue; } if (currentShortOption) { if (schemas.find((schema) => schema.short === currentShortOption.name && schema.type === "boolean")) positionalTokens.push({ ...token }); } else if (currentLongOption) { if (args[currentLongOption.name]?.type === "boolean") positionalTokens.push({ ...token }); } else positionalTokens.push({ ...token }); applyLongOptionValue(token.value); applyShortOptionValue(token.value); } else if (token.kind === "option") if (token.rawName) { if (hasLongOptionPrefix(token.rawName)) { applyLongOptionValue(); if (token.inlineValue) optionTokens.push({ ...token }); else currentLongOption = { ...token }; applyShortOptionValue(); } else if (isShortOption(token.rawName)) if (currentShortOption) { if (currentShortOption.index === token.index) if (shortGrouping) { currentShortOption.value = token.value; optionTokens.push({ ...currentShortOption }); currentShortOption = { ...token }; } else expandableShortOptions.push({ ...token }); else { currentShortOption.value = toShortValue(); optionTokens.push({ ...currentShortOption }); currentShortOption = { ...token }; } applyLongOptionValue(); } else { currentShortOption = { ...token }; applyLongOptionValue(); } } else { if (currentShortOption && currentShortOption.index == token.index && token.inlineValue) { currentShortOption.value = token.value; optionTokens.push({ ...currentShortOption }); currentShortOption = void 0; } applyLongOptionValue(); } else { if (token.kind === "option-terminator") terminated = true; applyLongOptionValue(); applyShortOptionValue(); } } applyLongOptionValue(); applyShortOptionValue(); const values = Object.create(null); const errors = []; function checkTokenName(option, schema, token) { return token.name === (schema.type === "boolean" ? schema.negatable && token.name?.startsWith("no-") ? `no-${option}` : option : option); } const positionalItemCount = tokens.filter((token) => token.kind === "positional").length; function getPositionalSkipIndex() { return Math.min(skipPositionalIndex, positionalItemCount); } let positionalsCount = 0; for (const [rawArg, schema] of Object.entries(args)) { const arg = toKebab || schema.toKebab ? kebabnize(rawArg) : rawArg; if (schema.required) { if (!optionTokens.find((token) => { return schema.short && token.name === schema.short || token.rawName && hasLongOptionPrefix(token.rawName) && token.name === arg; })) { errors.push(createRequireError(arg, schema)); continue; } } if (schema.type === "positional") { if (skipPositionalIndex > SKIP_POSITIONAL_DEFAULT) while (positionalsCount <= getPositionalSkipIndex()) positionalsCount++; const positional = positionalTokens[positionalsCount]; if (positional != null) values[rawArg] = positional.value; else errors.push(createRequireError(arg, schema)); positionalsCount++; continue; } for (let i = 0; i < optionTokens.length; i++) { const token = optionTokens[i]; if (checkTokenName(arg, schema, token) && token.rawName != void 0 && hasLongOptionPrefix(token.rawName) || schema.short === token.name && token.rawName != void 0 && isShortOption(token.rawName)) { const invalid = validateRequire(token, arg, schema); if (invalid) { errors.push(invalid); continue; } if (schema.type === "boolean") token.value = void 0; const [parsedValue, error] = parse(token, arg, schema); if (error) errors.push(error); else if (schema.multiple) { values[rawArg] ||= []; values[rawArg].push(parsedValue); } else values[rawArg] = parsedValue; } } if (values[rawArg] == null && schema.default != null) values[rawArg] = schema.default; } return { values, positionals: positionalTokens.map((token) => token.value), rest, error: errors.length > 0 ? new AggregateError(errors) : void 0 }; } function parse(token, option, schema) { switch (schema.type) { case "string": return typeof token.value === "string" ? [token.value || schema.default, void 0] : [void 0, createTypeError(option, schema)]; case "boolean": return token.value ? [token.value || schema.default, void 0] : [!(schema.negatable && token.name.startsWith("no-")), void 0]; case "number": if (!isNumeric(token.value)) return [void 0, createTypeError(option, schema)]; return token.value ? [+token.value, void 0] : [+(schema.default || ""), void 0]; case "enum": if (schema.choices && !schema.choices.includes(token.value)) return [void 0, new ArgResolveError(`Optional argument '--${option}' ${schema.short ? `or '-${schema.short}' ` : ""}should be chosen from '${schema.type}' [${schema.choices.map((c) => JSON.stringify(c)).join(", ")}] values`, option, "type", schema)]; return [token.value || schema.default, void 0]; case "custom": if (typeof schema.parse !== "function") throw new TypeError(`argument '${option}' should have a 'parse' function`); try { return [schema.parse(token.value || String(schema.default || "")), void 0]; } catch (error) { return [void 0, error]; } default: throw new Error(`Unsupported argument type '${schema.type}' for option '${option}'`); } } function createRequireError(option, schema) { return new ArgResolveError(schema.type === "positional" ? `Positional argument '${option}' is required` : `Optional argument '--${option}' ${schema.short ? `or '-${schema.short}' ` : ""}is required`, option, "required", schema); } var ArgResolveError = class extends Error { name; schema; type; constructor(message, name$1, type, schema) { super(message); this.name = name$1; this.type = type; this.schema = schema; } }; function validateRequire(token, option, schema) { if (schema.required && schema.type !== "boolean" && !token.value) return createRequireError(option, schema); } function isNumeric(str$1) { return str$1.trim() !== "" && !isNaN(str$1); } function createTypeError(option, schema) { return new ArgResolveError(`Optional argument '--${option}' ${schema.short ? `or '-${schema.short}' ` : ""}should be '${schema.type}'`, option, "type", schema); } async function cli(argv, entry, options = {}) { const cliOptions = resolveCliOptions(options, entry); const tokens = parseArgs(argv); const subCommand = getSubCommand(tokens); const { commandName: name$1, command, callMode } = await resolveCommand(subCommand, entry, cliOptions); if (!command) throw new Error(`Command not found: ${name$1 || ""}`); const args = resolveArguments(getCommandArgs(command)); const { values, positionals, rest, error } = resolveArgs(args, tokens, { shortGrouping: true, toKebab: command.toKebab, skipPositional: cliOptions.subCommands.size > 0 ? 0 : -1 }); const ctx = await createCommandContext({ args, values, positionals, rest, argv, tokens, omitted: !subCommand, callMode, command, cliOptions }); if (values.version) { showVersion(ctx); return; } const usageBuffer = []; const header = await showHeader(ctx); if (header) usageBuffer.push(header); if (values.help) { const usage = await showUsage(ctx); if (usage) usageBuffer.push(usage); return usageBuffer.join("\n"); } if (error) { await showValidationErrors(ctx, error); return; } await executeCommand(command, ctx, name$1 || ""); } function getCommandArgs(cmd) { if (isLazyCommand(cmd)) return cmd.args || create(); else if (typeof cmd === "object") return cmd.args || create(); else return create(); } function resolveArguments(args) { return Object.assign(create(), args, COMMON_ARGS); } function resolveCliOptions(options, entry) { const subCommands$1 = new Map(options.subCommands); if (options.subCommands) { if (isLazyCommand(entry)) subCommands$1.set(entry.commandName, entry); else if (typeof entry === "object" && entry.name) subCommands$1.set(entry.name, entry); } return Object.assign(create(), COMMAND_OPTIONS_DEFAULT, options, { subCommands: subCommands$1 }); } function getSubCommand(tokens) { const firstToken = tokens[0]; return firstToken && firstToken.kind === "positional" && firstToken.index === 0 && firstToken.value ? firstToken.value : ""; } async function showUsage(ctx) { if (ctx.env.renderUsage === null) return; const usage = await (ctx.env.renderUsage || renderUsage)(ctx); if (usage) { ctx.log(usage); return usage; } } function showVersion(ctx) { ctx.log(ctx.env.version); } async function showHeader(ctx) { if (ctx.env.renderHeader === null) return; const header = await (ctx.env.renderHeader || renderHeader)(ctx); if (header) { ctx.log(header); ctx.log(); return header; } } async function showValidationErrors(ctx, error) { if (ctx.env.renderValidationErrors === null) return; const render = ctx.env.renderValidationErrors || renderValidationErrors; ctx.log(await render(ctx, error)); } const CANNOT_RESOLVE_COMMAND = { callMode: "unexpected" }; async function resolveCommand(sub, entry, options) { const omitted = !sub; async function doResolveCommand() { if (typeof entry === "function") if ("commandName" in entry && entry.commandName) return { commandName: entry.commandName, command: entry, callMode: "entry" }; else return { command: { run: entry }, callMode: "entry" }; else if (typeof entry === "object") return { commandName: resolveEntryName(entry), command: entry, callMode: "entry" }; else return CANNOT_RESOLVE_COMMAND; } if (omitted || options.subCommands?.size === 0) return doResolveCommand(); const cmd = options.subCommands?.get(sub); if (cmd == null) return { commandName: sub, callMode: "unexpected" }; if (isLazyCommand(cmd) && cmd.commandName == null) cmd.commandName = sub; else if (typeof cmd === "object" && cmd.name == null) cmd.name = sub; return { commandName: sub, command: cmd, callMode: "subCommand" }; } function resolveEntryName(entry) { return entry.name || ANONYMOUS_COMMAND_NAME; } async function executeCommand(cmd, ctx, name$1) { const resolved = isLazyCommand(cmd) ? await resolveLazyCommand(cmd, name$1, true) : cmd; if (resolved.run == null) throw new Error(`'run' not found on Command \`${name$1}\``); await resolved.run(ctx); } var import_picocolors$2 = /* @__PURE__ */ __toESM(require_picocolors(), 1); function extractExplicitArgs(tokens) { const explicit = {}; for (const token of tokens) if (typeof token === "object" && token !== null) { const t = token; if (t.kind === "option" && typeof t.name === "string") explicit[t.name] = true; } return explicit; } function getConfigSearchPaths() { return [join(process$1.cwd(), ".ccusage"), ...toArray(getClaudePaths())].map((dir) => join(dir, CONFIG_FILE_NAME)); } function validateConfigJson(data) { if (typeof data !== "object" || data === null) return false; const config = data; if (config.$schema != null && typeof config.$schema !== "string") return false; if (config.defaults != null && (typeof config.defaults !== "object" || config.defaults === null)) return false; if (config.commands != null && (typeof config.commands !== "object" || config.commands === null)) return false; return true; } function loadConfigFile(filePath, debug = false) { if (!existsSync(filePath)) { if (debug) logger.info(` • Checking: ${filePath} (not found)`); return; } return pipe(try_({ try: () => { const content = readFileSync(filePath, "utf-8"); const data = JSON.parse(content); if (!validateConfigJson(data)) throw new Error("Invalid configuration structure"); data.source = filePath; return data; }, catch: (error) => error })(), inspect(() => { logger.debug(`Parsed configuration file: ${filePath}`); if (debug) logger.info(` • Checking: ${filePath} (found ✓)`); }), inspectError((error) => { const errorMessage = error instanceof Error ? error.message : String(error); logger.warn(`Error parsing configuration file at ${filePath}: ${errorMessage}`); if (debug) logger.info(` • Checking: ${filePath} (error: ${errorMessage})`); }), unwrap(void 0)); } function loadConfig(configPath, debug = false) { if (debug) logger.info("Debug mode enabled - showing config loading details\n"); if (configPath != null) { if (debug) { logger.info("Using specified config file:"); logger.info(` • Path: ${configPath}`); } const config = loadConfigFile(configPath, debug); if (config == null) logger.warn(`Configuration file not found or invalid: ${configPath}`); else if (debug) { logger.info(""); logger.info(`Loaded config from: ${configPath}`); logger.info(` • Schema: ${config.$schema ?? "none"}`); logger.info(` • Has defaults: ${config.defaults != null ? "yes" : "no"}${config.defaults != null ? ` (${Object.keys(config.defaults).length} options)` : ""}`); logger.info(` • Has command configs: ${config.commands != null ? "yes" : "no"}${config.commands != null ? ` (${Object.keys(config.commands).join(", ")})` : ""}`); } return config; } if (debug) logger.info("Searching for config files:"); for (const searchPath of getConfigSearchPaths()) { const config = loadConfigFile(searchPath, debug); if (config != null) { if (debug) { logger.info(""); logger.info(`Loaded config from: ${searchPath}`); logger.info(` • Schema: ${config.$schema ?? "none"}`); logger.info(` • Has defaults: ${config.defaults != null ? "yes" : "no"}${config.defaults != null ? ` (${Object.keys(config.defaults).length} options)` : ""}`); logger.info(` • Has command configs: ${config.commands != null ? "yes" : "no"}${config.commands != null ? ` (${Object.keys(config.commands).join(", ")})` : ""}`); } return config; } } logger.debug("No valid configuration file found"); if (debug) { logger.info(""); logger.info("No valid configuration file found"); } } function mergeConfigWithArgs(ctx, config, debug = false) { if (config == null) { if (debug) { logger.info(""); logger.info(`No config file loaded, using CLI args only for '${ctx.name ?? "unknown"}' command`); } return ctx.values; } const merged = {}; const commandName = ctx.name; const sources = {}; if (config.defaults != null) for (const [key, value$1] of Object.entries(config.defaults)) { merged[key] = value$1; sources[key] = "defaults"; } if (commandName != null && config.commands?.[commandName] != null) for (const [key, value$1] of Object.entries(config.commands[commandName])) { merged[key] = value$1; sources[key] = "command config"; } const explicit = extractExplicitArgs(ctx.tokens); for (const [key, value$1] of Object.entries(ctx.values)) if (value$1 != null && explicit[key] === true) { merged[key] = value$1; sources[key] = "CLI"; } logger.debug(`Merged config for ${commandName ?? "unknown"}:`, merged); if (debug) { logger.info(""); logger.info(`Merging options for '${commandName ?? "unknown"}' command:`); const bySource = { defaults: [], "command config": [], CLI: [] }; for (const [key, source] of Object.entries(sources)) if (bySource[source] != null) bySource[source].push(`${key}=${JSON.stringify(merged[key])}`); if (bySource.defaults.length > 0) logger.info(` • From defaults: ${bySource.defaults.join(", ")}`); if (bySource["command config"].length > 0) logger.info(` • From command config: ${bySource["command config"].join(", ")}`); if (bySource.CLI.length > 0) logger.info(` • From CLI args: ${bySource.CLI.join(", ")}`); logger.info(" • Final merged options: {"); for (const [key, value$1] of Object.entries(merged)) { const source = sources[key] ?? "unknown"; logger.info(` ${key}: ${JSON.stringify(value$1)} (from ${source}),`); } logger.info(" }"); } return merged; } const getContext = (raw) => ({ start: process$1.hrtime.bigint(), command: raw.map((part) => getCommandPart(stripVTControlCharacters(part))).join(" "), state: { stdout: "", stderr: "", output: "" } }); const getCommandPart = (part) => /[^\w./-]/.test(part) ? `'${part.replaceAll("'", "'\\''")}'` : part; const getOptions = ({ stdin: stdin$2, stdout: stdout$1, stderr, stdio = [ stdin$2, stdout$1, stderr ], env: envOption, preferLocal, cwd: cwdOption = ".", ...options }) => { const cwd = cwdOption instanceof URL ? fileURLToPath(cwdOption) : path.resolve(cwdOption); const env = envOption ? { ...process$1.env, ...envOption } : void 0; const input = stdio[0]?.string; return { ...options, input, stdio: input === void 0 ? stdio : ["pipe", ...stdio.slice(1)], env: preferLocal ? addLocalPath(env ?? process$1.env, cwd) : env, cwd }; }; const addLocalPath = ({ Path = "", PATH = Path, ...env }, cwd) => { const pathParts = PATH.split(path.delimiter); const localPaths = getLocalPaths([], path.resolve(cwd)).map((localPath) => path.join(localPath, "node_modules/.bin")).filter((localPath) => !pathParts.includes(localPath)); return { ...env, PATH: [...localPaths, PATH].filter(Boolean).join(path.delimiter) }; }; const getLocalPaths = (localPaths, localPath) => localPaths.at(-1) === localPath ? localPaths : getLocalPaths([...localPaths, localPath], path.resolve(localPath, "..")); const applyForceShell = async (file, commandArguments, options) => await shouldForceShell(file, options) ? [ escapeFile(file), commandArguments.map((argument) => escapeArgument(argument)), { ...options, shell: true } ] : [ file, commandArguments, options ]; const shouldForceShell = async (file, { shell, cwd, env = process$1.env }) => process$1.platform === "win32" && !shell && !await isExe(file, cwd, env); const isExe = (file, cwd, { Path = "", PATH = Path }) => exeExtensions.some((extension) => file.toLowerCase().endsWith(extension)) || mIsExe(file, cwd, PATH); const EXE_MEMO = {}; const memoize = (function_) => (...arguments_) => EXE_MEMO[arguments_.join("\0")] ??= function_(...arguments_); const access = memoize(a.access); const mIsExe = memoize(async (file, cwd, PATH) => { const parts = PATH.split(path.delimiter).filter(Boolean).map((part) => part.replace(/^"(.*)"$/, "$1")); try { await Promise.any([cwd, ...parts].flatMap((part) => exeExtensions.map((extension) => access(`${path.resolve(part, file)}${extension}`)))); } catch { return false; } return true; }); const exeExtensions = [".exe", ".com"]; const escapeArgument = (argument) => escapeFile(escapeFile(`"${argument.replaceAll(/(\\*)"/g, "$1$1\\\"").replace(/(\\*)$/, "$1$1")}"`)); const escapeFile = (file) => file.replaceAll(/([()\][%!^"`<>&|;, *?])/g, "^$1"); const getResult = async (nodeChildProcess, { input }, context) => { const instance = await nodeChildProcess; if (input !== void 0) instance.stdin.end(input); const onClose = once(instance, "close"); try { await Promise.race([onClose, ...instance.stdio.filter(Boolean).map((stream) => onStreamError(stream))]); checkFailure(context, getErrorOutput(instance)); return getOutputs(context); } catch (error) { await Promise.allSettled([onClose]); throw getResultError(error, instance, context); } }; const onStreamError = async (stream) => { for await (const [error] of on(stream, "error")) if (!["ERR_STREAM_PREMATURE_CLOSE", "EPIPE"].includes(error?.code)) throw error; }; const checkFailure = ({ command }, { exitCode, signalName }) => { if (signalName !== void 0) throw new SubprocessError(`Command was terminated with ${signalName}: ${command}`); if (exitCode !== void 0) throw new SubprocessError(`Command failed with exit code ${exitCode}: ${command}`); }; const getResultError = (error, instance, context) => Object.assign(getErrorInstance(error, context), getErrorOutput(instance), getOutputs(context)); const getErrorInstance = (error, { command }) => error instanceof SubprocessError ? error : new SubprocessError(`Command failed: ${command}`, { cause: error }); var SubprocessError = class extends Error { name = "SubprocessError"; }; const getErrorOutput = ({ exitCode, signalCode }) => ({ ...exitCode < 1 ? {} : { exitCode }, ...signalCode === null ? {} : { signalName: signalCode } }); const getOutputs = ({ state: { stdout: stdout$1, stderr, output }, command, start }) => ({ stdout: getOutput(stdout$1), stderr: getOutput(stderr), output: getOutput(output), command, durationMs: Number(process$1.hrtime.bigint() - start) / 1e6 }); const getOutput = (output) => output.at(-1) === "\n" ? output.slice(0, output.at(-2) === "\r" ? -2 : -1) : output; const spawnSubprocess = async (file, commandArguments, options, context) => { try { if (["node", "node.exe"].includes(file.toLowerCase())) { file = process$1.execPath; commandArguments = [...process$1.execArgv.filter((flag) => !flag.startsWith("--inspect")), ...commandArguments]; } [file, commandArguments, options] = await applyForceShell(file, commandArguments, options); [file, commandArguments, options] = concatenateShell(file, commandArguments, options); const instance = spawn(file, commandArguments, options); bufferOutput(instance.stdout, context, "stdout"); bufferOutput(instance.stderr, context, "stderr"); instance.once("error", () => {}); await once(instance, "spawn"); return instance; } catch (error) { throw getResultError(error, {}, context); } }; const concatenateShell = (file, commandArguments, options) => options.shell && commandArguments.length > 0 ? [ [file, ...commandArguments].join(" "), [], options ] : [ file, commandArguments, options ]; const bufferOutput = (stream, { state }, streamName) => { if (stream) { stream.setEncoding("utf8"); if (!state.isIterating) { state.isIterating = false; stream.on("data", (chunk) => { state[streamName] += chunk; state.output += chunk; }); } } }; const handlePipe = async (subprocesses) => { const [[from, to]] = await Promise.all([Promise.allSettled(subprocesses), pipeStreams(subprocesses)]); if (to.reason) { to.reason.pipedFrom = from.reason ?? from.value; throw to.reason; } if (from.reason) throw from.reason; return { ...to.value, pipedFrom: from.value }; }; const pipeStreams = async (subprocesses) => { try { const [{ stdout: stdout$1 }, { stdin: stdin$2 }] = await Promise.all(subprocesses.map(({ nodeChildProcess }) => nodeChildProcess)); if (stdin$2 === null) throw new Error("The \"stdin\" option must be set on the first \"spawn()\" call in the pipeline."); if (stdout$1 === null) throw new Error("The \"stdout\" option must be set on the last \"spawn()\" call in the pipeline."); pipeline(stdout$1, stdin$2).catch(() => {}); } catch (error) { await Promise.allSettled(subprocesses.map(({ nodeChildProcess }) => closeStdin(nodeChildProcess))); throw error; } }; const closeStdin = async (nodeChildProcess) => { const { stdin: stdin$2 } = await nodeChildProcess; stdin$2.end(); }; const lineIterator = async function* (subprocess, { state }, streamName) { if (state.isIterating === false) throw new Error(`The subprocess must be iterated right away, for example: for await (const line of spawn(...)) { ... }`); state.isIterating = true; try { const { [streamName]: stream } = await subprocess.nodeChildProcess; if (!stream) return; handleErrors(subprocess); yield* readline.createInterface({ input: stream }); } finally { await subprocess; } }; const handleErrors = async (subprocess) => { try { await subprocess; } catch {} }; const combineAsyncIterators = async function* (...iterators) { try { let promises = []; while (iterators.length > 0) { promises = iterators.map((iterator$1, index$1) => promises[index$1] ?? getNext(iterator$1)); const [{ value: value$1, done }, index] = await Promise.race(promises.map((promise, index$1) => Promise.all([promise, index$1]))); const [iterator] = iterators.splice(index, 1); promises.splice(index, 1); if (!done) { iterators.push(iterator); yield value$1; } } } finally { await Promise.all(iterators.map((iterator) => iterator.return())); } }; const getNext = async (iterator) => { try { return await iterator.next(); } catch (error) { await iterator.throw(error); } }; function spawn$1(file, second, third, previous) { const [commandArguments = [], options = {}] = Array.isArray(second) ? [second, third] : [[], second]; const context = getContext([file, ...commandArguments]); const spawnOptions = getOptions(options); const nodeChildProcess = spawnSubprocess(file, commandArguments, spawnOptions, context); let subprocess = getResult(nodeChildProcess, spawnOptions, context); Object.assign(subprocess, { nodeChildProcess }); subprocess = previous ? handlePipe([previous, subprocess]) : subprocess; const stdout$1 = lineIterator(subprocess, context, "stdout"); const stderr = lineIterator(subprocess, context, "stderr"); return Object.assign(subprocess, { nodeChildProcess, stdout: stdout$1, stderr, [Symbol.asyncIterator]: () => combineAsyncIterators(stdout$1, stderr), pipe: (file$1, second$1, third$1) => spawn$1(file$1, second$1, third$1, subprocess) }); } async function processWithJq(jsonData, jqCommand) { const jsonString = JSON.stringify(jsonData); return try_({ try: async () => { return (await spawn$1("jq", [jqCommand], { stdin: { string: jsonString } })).output.trim(); }, catch: (error) => { if (error instanceof Error) { if (error.message.includes("ENOENT") || error.message.includes("not found")) return /* @__PURE__ */ new Error("jq command not found. Please install jq to use the --jq option."); return /* @__PURE__ */ new Error(`jq processing failed: ${error.message}`); } return /* @__PURE__ */ new Error("Unknown error during jq processing"); } })(); } function parseDateArg(value$1) { return parse$1(filterDateSchema, value$1); } const sharedArgs = { since: { type: "custom", short: "s", description: "Filter from date (YYYYMMDD format)", parse: parseDateArg }, until: { type: "custom", short: "u", description: "Filter until date (YYYYMMDD format)", parse: parseDateArg }, json: { type: "boolean", short: "j", description: "Output in JSON format", default: false }, mode: { type: "enum", short: "m", description: "Cost calculation mode: auto (use costUSD if exists, otherwise calculate), calculate (always calculate), display (always use