ccusage
Version:
Usage analysis tool for Claude Code
1,311 lines • 205 kB
JavaScript
#!/usr/bin/env node
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-Dm8hcn_h.js";
import { CostModes, SortOrders, dateSchema } from "./_types-Cr2YEzKm.js";
import { calculateTotals, createTotalsObject, getTotalTokens } from "./calculate-cost-CoS7we68.js";
import { DEFAULT_SESSION_DURATION_HOURS, calculateBurnRate, calculateCostForEntry, createUniqueHash, filterRecentBlocks, formatDateCompact, getDefaultClaudePath, getEarliestTimestamp, glob, identifySessionBlocks, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData, projectBlockUsage, sortFilesByTimestamp, uniq, usageDataSchema } from "./data-loader-BeaFK_sH.js";
import { description, log, logger, name, version } from "./logger-Cke8hliP.js";
import { detectMismatches, printMismatchReport } from "./debug-BmJuGBXC.js";
import { createMcpHttpApp, createMcpServer, startMcpServerStdio } from "./mcp-DKqp_F9c.js";
import { readFile } from "node:fs/promises";
import path from "node:path";
import process$1 from "node:process";
import { createServer } from "node:http";
import { Http2ServerRequest } from "node:http2";
import { Readable } from "node:stream";
import crypto from "node:crypto";
/**
* The default locale string, which format is BCP 47 language tag.
*/
const DEFAULT_LOCALE = "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]) => {
acc[resolveBuiltInKey(key)] = value;
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 = obj[key];
if (typeof value === "object" && value !== null) deepFreeze(value);
}
return Object.freeze(obj);
}
var COMMAND = "COMMAND";
var COMMANDS = "COMMANDS";
var SUBCOMMAND = "SUBCOMMAND";
var USAGE = "USAGE";
var ARGUMENTS = "ARGUMENTS";
var OPTIONS = "OPTIONS";
var EXAMPLES = "EXAMPLES";
var FORMORE = "For more info, run any command with the `--help` flag:";
var NEGATABLE = "Negatable of";
var DEFAULT = "default";
var CHOICES = "choices";
var help = "Display this help message";
var version$1 = "Display this version";
var en_US_default = {
COMMAND,
COMMANDS,
SUBCOMMAND,
USAGE,
ARGUMENTS,
OPTIONS,
EXAMPLES,
FORMORE,
NEGATABLE,
DEFAULT,
CHOICES,
help,
version: version$1
};
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];
return void 0;
}
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, (_, name$1) => {
return values[name$1] == null ? "" : values[name$1].toString();
});
}
};
const BUILT_IN_PREFIX_CODE = BUILT_IN_PREFIX.codePointAt(0);
/**
* Create a {@link CommandContext | command context}
* @param param A {@link CommandContextParams | parameters} to create a {@link CommandContext | command context}
* @returns A {@link CommandContext | command context}, which is readonly
*/
async function createCommandContext({ args, values, positionals, rest, argv: argv$1, tokens, command, cliOptions, callMode = "entry", omitted = false }) {
/**
* normailize the options schema and values, to avoid prototype pollution
*/
const _args = Object.entries(args).reduce((acc, [key, value]) => {
acc[key] = Object.assign(create(), value);
return acc;
}, create());
/**
* setup the environment
*/
const env$2 = Object.assign(create(), COMMAND_OPTIONS_DEFAULT, cliOptions);
const locale = resolveLocale(cliOptions.locale);
const localeStr = locale.toString();
const translationAdapterFactory = cliOptions.translationAdapterFactory || createTranslationAdapter;
const adapter = translationAdapterFactory({
locale: localeStr,
fallbackLocale: DEFAULT_LOCALE
});
const localeResources = /* @__PURE__ */ new Map();
let builtInLoadedResources;
/**
* load the built-in locale resources
*/
localeResources.set(DEFAULT_LOCALE, mapResourceWithBuiltinKey(en_US_default));
if (DEFAULT_LOCALE !== localeStr) try {
builtInLoadedResources = (await import(`./locales/${localeStr}.json`, { with: { type: "json" } })).default;
localeResources.set(localeStr, mapResourceWithBuiltinKey(builtInLoadedResources));
} catch {}
/**
* define the translation function, which is used to {@link CommandContext.translate}.
*
*/
function translate(key, values$1 = create()) {
const strKey = key;
if (strKey.codePointAt(0) === BUILT_IN_PREFIX_CODE) {
const resource = localeResources.get(localeStr) || localeResources.get(DEFAULT_LOCALE);
return resource[strKey] || strKey;
} else return adapter.translate(locale.toString(), strKey, values$1) || "";
}
/**
* load the sub commands
*/
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)));
}
/**
* create the context
*/
const ctx = deepFreeze(Object.assign(create(), {
name: getCommandName(command),
description: command.description,
omitted,
callMode,
locale,
env: env$2,
args: _args,
values,
positionals,
rest,
_: argv$1,
tokens,
toKebab: command.toKebab,
log: cliOptions.usageSilent ? NOOP : log$1,
loadCommands,
translate
}));
/**
* load the command resources
*/
const loadedOptionsResources = Object.entries(args).map(([key, arg]) => {
const description$1 = arg.description || "";
return [key, description$1];
});
const defaultCommandResource = loadedOptionsResources.reduce((res, [key, value]) => {
res[resolveArgKey(key)] = value;
return res;
}, create());
defaultCommandResource.description = command.description || "";
defaultCommandResource.examples = await resolveExamples(ctx, command.examples);
adapter.setResource(DEFAULT_LOCALE, 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);
}
async function loadCommandResource(ctx, command) {
let resource;
try {
resource = await command.resource?.(ctx);
} catch {}
return resource;
}
/**
* Define a {@link Command | command} with type inference
* @param definition A {@link Command | command} definition
* @returns A {@link Command | command} definition with type inference
*/
function define(definition) {
return definition;
}
/**
* Entry point of utils.
*
* Note that this entry point is used by gunshi to import utility functions.
*
* @module
*/
/**
* @author kazuya kawaguchi (a.k.a. kazupon)
* @license MIT
*/
function kebabnize(str) {
return str.replace(/[A-Z]/g, (match, offset) => (offset > 0 ? "-" : "") + match.toLowerCase());
}
/**
* Render the header.
* @param ctx A {@link CommandContext | command context}
* @returns A rendered header.
*/
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);
/**
* Render the usage.
* @param ctx A {@link CommandContext | command context}
* @returns A rendered usage.
*/
async function renderUsage(ctx) {
const messages$1 = [];
if (!ctx.omitted) {
const description$1 = resolveDescription(ctx);
if (description$1) messages$1.push(description$1, "");
}
messages$1.push(...await renderUsageSection(ctx), "");
if (ctx.omitted && await hasCommands(ctx)) messages$1.push(...await renderCommandsSection(ctx), "");
if (hasPositionalArgs(ctx)) messages$1.push(...await renderPositionalArgsSection(ctx), "");
if (hasOptionalArgs(ctx)) messages$1.push(...await renderOptionalArgsSection(ctx), "");
const examples = await renderExamplesSection(ctx);
if (examples.length > 0) messages$1.push(...examples, "");
return messages$1.join("\n");
}
/**
* Render the positional arguments section
* @param ctx A {@link CommandContext | command context}
* @returns A rendered arguments section
*/
async function renderPositionalArgsSection(ctx) {
const messages$1 = [];
messages$1.push(`${ctx.translate(resolveBuiltInKey("ARGUMENTS"))}:`);
messages$1.push(await generatePositionalArgsUsage(ctx));
return messages$1;
}
/**
* Render the optional arguments section
* @param ctx A {@link CommandContext | command context}
* @returns A rendered options section
*/
async function renderOptionalArgsSection(ctx) {
const messages$1 = [];
messages$1.push(`${ctx.translate(resolveBuiltInKey("OPTIONS"))}:`);
messages$1.push(await generateOptionalArgsUsage(ctx, getOptionalArgsPairs(ctx)));
return messages$1;
}
/**
* Render the examples section
* @param ctx A {@link CommandContext | command context}
* @returns A rendered examples section
*/
async function renderExamplesSection(ctx) {
const messages$1 = [];
const resolvedExamples = await resolveExamples$1(ctx);
if (resolvedExamples) {
const examples = resolvedExamples.split("\n").map((example) => example.padStart(ctx.env.leftMargin + example.length));
messages$1.push(`${ctx.translate(resolveBuiltInKey("EXAMPLES"))}:`, ...examples);
}
return messages$1;
}
/**
* Render the usage section
* @param ctx A {@link CommandContext | command context}
* @returns A rendered usage section
*/
async function renderUsageSection(ctx) {
const messages$1 = [`${ctx.translate(resolveBuiltInKey("USAGE"))}:`];
if (ctx.omitted) {
const defaultCommand = `${resolveEntry(ctx)}${await hasCommands(ctx) ? ` [${resolveSubCommand(ctx)}]` : ""} ${[generateOptionsSymbols(ctx), generatePositionalSymbols(ctx)].filter(Boolean).join(" ")}`;
messages$1.push(defaultCommand.padStart(ctx.env.leftMargin + defaultCommand.length));
if (await hasCommands(ctx)) {
const commandsUsage = `${resolveEntry(ctx)} <${ctx.translate(resolveBuiltInKey("COMMANDS"))}>`;
messages$1.push(commandsUsage.padStart(ctx.env.leftMargin + commandsUsage.length));
}
} else {
const usageStr = `${resolveEntry(ctx)} ${resolveSubCommand(ctx)} ${[generateOptionsSymbols(ctx), generatePositionalSymbols(ctx)].filter(Boolean).join(" ")}`;
messages$1.push(usageStr.padStart(ctx.env.leftMargin + usageStr.length));
}
return messages$1;
}
/**
* Render the commands section
* @param ctx A {@link CommandContext | command context}
* @returns A rendered commands section
*/
async function renderCommandsSection(ctx) {
const messages$1 = [`${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$1.push(...commandsStr, "", ctx.translate(resolveBuiltInKey("FORMORE")));
messages$1.push(...loadedCommands.map((cmd) => {
const commandHelp = `${ctx.env.name} ${cmd.name} --help`;
return `${commandHelp.padStart(ctx.env.leftMargin + commandHelp.length)}`;
}));
return messages$1;
}
/**
* Resolve the entry command name
* @param ctx A {@link CommandContext | command context}
* @returns The entry command name
*/
function resolveEntry(ctx) {
return ctx.env.name || ctx.translate(resolveBuiltInKey("COMMAND"));
}
/**
* Resolve the sub command name
* @param ctx A {@link CommandContext | command context}
* @returns The sub command name
*/
function resolveSubCommand(ctx) {
return ctx.name || ctx.translate(resolveBuiltInKey("SUBCOMMAND"));
}
/**
* Resolve the command description
* @param ctx A {@link CommandContext | command context}
* @returns resolved command description
*/
function resolveDescription(ctx) {
return ctx.translate("description") || ctx.description || "";
}
/**
* Resolve the command examples
* @param ctx A {@link CommandContext | command context}
* @returns resolved command examples, if not resolved, return empty string
*/
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);
}
/**
* Check if the command has sub commands
* @param ctx A {@link CommandContext | command context}
* @returns True if the command has sub commands
*/
async function hasCommands(ctx) {
const loadedCommands = await ctx.loadCommands();
return loadedCommands.length > 1;
}
/**
* Check if the command has optional arguments
* @param ctx A {@link CommandContext | command context}
* @returns True if the command has options
*/
function hasOptionalArgs(ctx) {
return !!(ctx.args && Object.values(ctx.args).some((arg) => arg.type !== "positional"));
}
/**
* Check if the command has positional arguments
* @param ctx A {@link CommandContext | command context}
* @returns True if the command has options
*/
function hasPositionalArgs(ctx) {
return !!(ctx.args && Object.values(ctx.args).some((arg) => arg.type === "positional"));
}
/**
* Check if all options have default values
* @param ctx A {@link CommandContext | command context}
* @returns True if all options have default values
*/
function hasAllDefaultOptions(ctx) {
return !!(ctx.args && Object.values(ctx.args).every((arg) => arg.default));
}
/**
* Generate options symbols for usage
* @param ctx A {@link CommandContext | command context}
* @returns Options symbols for usage
*/
function generateOptionsSymbols(ctx) {
return hasOptionalArgs(ctx) ? hasAllDefaultOptions(ctx) ? `[${ctx.translate(resolveBuiltInKey("OPTIONS"))}]` : `<${ctx.translate(resolveBuiltInKey("OPTIONS"))}>` : "";
}
function makeShortLongOptionPair(schema, name$1, toKebab) {
const displayName = toKebab || schema.toKebab ? kebabnize(name$1) : name$1;
let key = `--${displayName}`;
if (schema.short) key = `-${schema.short}, ${key}`;
return key;
}
/**
* Get optional arguments pairs for usage
* @param ctx A {@link CommandContext | command context}
* @returns Options pairs for usage
*/
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 "";
}
/**
* Generate optional arguments usage
* @param ctx A {@link CommandContext | command context}
* @param optionsPairs Options pairs for usage
* @returns Generated options usage
*/
async function generateOptionalArgsUsage(ctx, optionsPairs) {
const optionsMaxLength = Math.max(...Object.entries(optionsPairs).map(([_, value]) => value.length));
const optionSchemaMaxLength = ctx.env.usageOptionType ? Math.max(...Object.entries(optionsPairs).map(([key]) => resolveNegatableType(key, ctx).length)) : 0;
const usages = await Promise.all(Object.entries(optionsPairs).map(([key, value]) => {
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.padEnd(optionsMaxLength + ctx.env.middleMargin)}${desc}${valueDesc ? ` ${valueDesc}` : ""}`;
return `${option.padStart(ctx.env.leftMargin + option.length)}`;
}));
return usages.join("\n");
}
function getPositionalArgs(ctx) {
return Object.entries(ctx.args).filter(([_, schema]) => schema.type === "positional");
}
async function generatePositionalArgsUsage(ctx) {
const positionals = getPositionalArgs(ctx);
const argsMaxLength = Math.max(...positionals.map(([name$1]) => name$1.length));
const usages = 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)}`;
}));
return usages.join("\n");
}
function generatePositionalSymbols(ctx) {
return hasPositionalArgs(ctx) ? getPositionalArgs(ctx).map(([name$1]) => `<${name$1}>`).join(" ") : "";
}
/**
* Render the validation errors.
* @param ctx A {@link CommandContext | command context}
* @param error An {@link AggregateError} of option in `args-token` validation
* @returns A rendered validation error.
*/
function renderValidationErrors(_ctx, error) {
const messages$1 = [];
for (const err of error.errors) messages$1.push(err.message);
return Promise.resolve(messages$1.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 = "--";
/**
* Parse command line arguments.
* @example
* ```js
* import { parseArgs } from 'args-tokens' // for Node.js and Bun
* // import { parseArgs } from 'jsr:@kazupon/args-tokens' // for Deno
*
* const tokens = parseArgs(['--foo', 'bar', '-x', '--bar=baz'])
* // do something with using tokens
* // ...
* console.log('tokens:', tokens)
* ```
* @param args command line arguments
* @param options parse options
* @returns Argument tokens.
*/
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;
let inlineValue;
if (groupCount) {
tokens.push({
kind: "option",
name: shortOption,
rawName: arg,
index,
value,
inlineValue
});
if (groupCount === 1 && hasOptionValue(nextArg)) {
value = remainings.shift();
if (hasShortValueSeparator) {
inlineValue = true;
hasShortValueSeparator = false;
}
tokens.push({
kind: "option",
index,
value,
inlineValue
});
}
} else tokens.push({
kind: "option",
name: shortOption,
rawName: arg,
index,
value,
inlineValue
});
if (value != 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 = arg.slice(equalIndex + 1);
tokens.push({
kind: "option",
name: longOption,
rawName: `${LONG_OPTION_PREFIX}${longOption}`,
index,
value,
inlineValue: true
});
continue;
}
tokens.push({
kind: "positional",
index,
value: arg
});
}
return tokens;
}
/**
* Check if `arg` is a short option (e.g. `-f`).
* @param arg the argument to check
* @returns whether `arg` is a short option.
*/
function isShortOption(arg) {
return arg.length === 2 && arg.codePointAt(0) === HYPHEN_CODE && arg.codePointAt(1) !== HYPHEN_CODE;
}
/**
* Check if `arg` is a short option group (e.g. `-abc`).
* @param arg the argument to check
* @returns whether `arg` is a short option group.
*/
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;
}
/**
* Check if `arg` is a long option (e.g. `--foo`).
* @param arg the argument to check
* @returns whether `arg` is a long option.
*/
function isLongOption(arg) {
return hasLongOptionPrefix(arg) && !arg.includes(EQUAL_CHAR, 3);
}
/**
* Check if `arg` is a long option with value (e.g. `--foo=bar`).
* @param arg the argument to check
* @returns whether `arg` is a long option.
*/
function isLongOptionAndValue(arg) {
return hasLongOptionPrefix(arg) && arg.includes(EQUAL_CHAR, 3);
}
/**
* Check if `arg` is a long option prefix (e.g. `--`).
* @param arg the argument to check
* @returns whether `arg` is a long option prefix.
*/
function hasLongOptionPrefix(arg) {
return arg.length > 2 && ~arg.indexOf(LONG_OPTION_PREFIX);
}
/**
* Check if a `value` is an option value.
* @param value a value to check
* @returns whether a `value` is an option value.
*/
function hasOptionValue(value) {
return !(value == null) && value.codePointAt(0) !== HYPHEN_CODE;
}
const SKIP_POSITIONAL_DEFAULT = -1;
/**
* Resolve command line arguments.
* @param args - An arguments that contains {@link ArgSchema | arguments schema}.
* @param tokens - An array of {@link ArgToken | tokens}.
* @param resolveArgs - An arguments that contains {@link ResolveArgs | resolve arguments}.
* @returns An object that contains the values of the arguments, positional arguments, rest arguments, and {@link AggregateError | validation errors}.
*/
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 = expandableShortOptions.map((token) => token.name).join("");
expandableShortOptions.length = 0;
return value;
}
}
function applyLongOptionValue(value = void 0) {
if (currentLongOption) {
currentLongOption.value = value;
optionTokens.push({ ...currentLongOption });
currentLongOption = void 0;
}
}
function applyShortOptionValue(value = void 0) {
if (currentShortOption) {
currentShortOption.value = value || toShortValue();
optionTokens.push({ ...currentShortOption });
currentShortOption = void 0;
}
}
/**
* analyze phase to resolve value
* separate tokens into positionals, long and short options, after that resolve values
*/
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) {
const found = schemas.find((schema) => schema.short === currentShortOption.name && schema.type === "boolean");
if (found) positionalTokens.push({ ...token });
} else if (currentLongOption) {
const found = args[currentLongOption.name]?.type === "boolean";
if (found) 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();
}
}
/**
* check if the last long or short option is not resolved
*/
applyLongOptionValue();
applyShortOptionValue();
/**
* resolve values
*/
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) {
const found = optionTokens.find((token) => {
return schema.short && token.name === schema.short || token.rawName && hasLongOptionPrefix(token.rawName) && token.name === arg;
});
if (!found) {
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) {
const message = schema.type === "positional" ? `Positional argument '${option}' is required` : `Optional argument '--${option}' ${schema.short ? `or '-${schema.short}' ` : ""}is required`;
return new ArgResolveError(message, option, "required", schema);
}
/**
* An error that occurs when resolving arguments.
* This error is thrown when the argument is not valid.
*/
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) {
return str.trim() !== "" && !isNaN(str);
}
function createTypeError(option, schema) {
return new ArgResolveError(`Optional argument '--${option}' ${schema.short ? `or '-${schema.short}' ` : ""}should be '${schema.type}'`, option, "type", schema);
}
/**
* Run the command.
* @param args Command line arguments
* @param entry A {@link Command | entry command}, an {@link CommandRunner | inline command runner}, or a {@link LazyCommand | lazily-loaded command}
* @param options A {@link CliOptions | CLI options}
* @returns A rendered usage or undefined. if you will use {@link CliOptions.usageSilent} option, it will return rendered usage string.
*/
async function cli(argv$1, entry, options = {}) {
const cliOptions = resolveCliOptions(options, entry);
const tokens = parseArgs(argv$1);
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 omitted = !subCommand;
const ctx = await createCommandContext({
args,
values,
positionals,
rest,
argv: argv$1,
tokens,
omitted,
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);
}
const resolvedOptions = Object.assign(create(), COMMAND_OPTIONS_DEFAULT, options, { subCommands: subCommands$1 });
return resolvedOptions;
}
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 require_picocolors = __commonJSMin((exports, module) => {
let p = process || {}, argv = p.argv || [], env$1 = p.env || {};
let isColorSupported = !(!!env$1.NO_COLOR || argv.includes("--no-color")) && (!!env$1.FORCE_COLOR || argv.includes("--color") || p.platform === "win32" || (p.stdout || {}).isTTY && env$1.TERM !== "dumb" || !!env$1.CI);
let formatter = (open, close, replace = open) => (input) => {
let string = "" + input, index = string.indexOf(close, open.length);
return ~index ? open + replaceClose(string, close, replace, index) + close : open + string + close;
};
let replaceClose = (string, close, replace, index) => {
let result = "", cursor = 0;
do {
result += string.substring(cursor, index) + replace;
cursor = index + close.length;
index = string.indexOf(close, cursor);
} while (~index);
return result + string.substring(cursor);
};
let createColors = (enabled = isColorSupported) => {
let f = enabled ? formatter : () => String;
return {
isColorSupported: enabled,
reset: f("\x1B[0m", "\x1B[0m"),
bold: f("\x1B[1m", "\x1B[22m", "\x1B[22m\x1B[1m"),
dim: f("\x1B[2m", "\x1B[22m", "\x1B[22m\x1B[2m"),
italic: f("\x1B[3m", "\x1B[23m"),
underline: f("\x1B[4m", "\x1B[24m"),
inverse: f("\x1B[7m", "\x1B[27m"),
hidden: f("\x1B[8m", "\x1B[28m"),
strikethrough: f("\x1B[9m", "\x1B[29m"),
black: f("\x1B[30m", "\x1B[39m"),
red: f("\x1B[31m", "\x1B[39m"),
green: f("\x1B[32m", "\x1B[39m"),
yellow: f("\x1B[33m", "\x1B[39m"),
blue: f("\x1B[34m", "\x1B[39m"),
magenta: f("\x1B[35m", "\x1B[39m"),
cyan: f("\x1B[36m", "\x1B[39m"),
white: f("\x1B[37m", "\x1B[39m"),
gray: f("\x1B[90m", "\x1B[39m"),
bgBlack: f("\x1B[40m", "\x1B[49m"),
bgRed: f("\x1B[41m", "\x1B[49m"),
bgGreen: f("\x1B[42m", "\x1B[49m"),
bgYellow: f("\x1B[43m", "\x1B[49m"),
bgBlue: f("\x1B[44m", "\x1B[49m"),
bgMagenta: f("\x1B[45m", "\x1B[49m"),
bgCyan: f("\x1B[46m", "\x1B[49m"),
bgWhite: f("\x1B[47m", "\x1B[49m"),
blackBright: f("\x1B[90m", "\x1B[39m"),
redBright: f("\x1B[91m", "\x1B[39m"),
greenBright: f("\x1B[92m", "\x1B[39m"),
yellowBright: f("\x1B[93m", "\x1B[39m"),
blueBright: f("\x1B[94m", "\x1B[39m"),
magentaBright: f("\x1B[95m", "\x1B[39m"),
cyanBright: f("\x1B[96m", "\x1B[39m"),
whiteBright: f("\x1B[97m", "\x1B[39m"),
bgBlackBright: f("\x1B[100m", "\x1B[49m"),
bgRedBright: f("\x1B[101m", "\x1B[49m"),
bgGreenBright: f("\x1B[102m", "\x1B[49m"),
bgYellowBright: f("\x1B[103m", "\x1B[49m"),
bgBlueBright: f("\x1B[104m", "\x1B[49m"),
bgMagentaBright: f("\x1B[105m", "\x1B[49m"),
bgCyanBright: f("\x1B[106m", "\x1B[49m"),
bgWhiteBright: f("\x1B[107m", "\x1B[49m")
};
};
module.exports = createColors();
module.exports.createColors = createColors;
});
/**
* Parses and validates a date argument in YYYYMMDD format
* @param value - Date string to parse
* @returns Validated date string
* @throws TypeError if date format is invalid
*/
function parseDateArg(value) {
const result = dateSchema.safeParse(value);
if (!result.success) throw new TypeError(result.error.issues[0]?.message ?? "Invalid date format");
return result.data;
}
/**
* Shared command line arguments used across multiple CLI commands
*/
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 costUSD)",
default: "auto",
choices: CostModes
},
debug: {
type: "boolean",
short: "d",
description: "Show pricing mismatch information for debugging",
default: false
},
debugSamples: {
type: "number",
description: "Number of sample discrepancies to show in debug output (default: 5)",
default: 5
},
order: {
type: "enum",
short: "o",
description: "Sort order: desc (newest first) or asc (oldest first)",
default: "asc",
choices: SortOrders
},
breakdown: {
type: "boolean",
short: "b",
description: "Show per-model cost breakdown",
default: false
},
offline: {
type: "boolean",
negatable: true,
short: "O",
description: "Use cached pricing data for Claude models instead of fetching from API",
default: false
}
};
/**
* Shared command configuration for Gunshi CLI commands
*/
const sharedCommandConfig = {
args: sharedArgs,
toKebab: true
};
var require_debug$1 = __commonJSMin((exports, module) => {
let messages = [];
let level = 0;
const debug$3 = (msg, min) => {
if (level >= min) messages.push(msg);
};
debug$3.WARN = 1;
debug$3.INFO = 2;
debug$3.DEBUG = 3;
debug$3.reset = () => {
messages = [];
};
debug$3.setDebugLevel = (v) => {
level = v;
};
debug$3.warn = (msg) => debug$3(msg, debug$3.WARN);
debug$3.info = (msg) => debug$3(msg, debug$3.INFO);
debug$3.debug = (msg) => debug$3(msg, debug$3.DEBUG);
debug$3.debugMessages = () => messages;
module.exports = debug$3;
});
var require_ansi_regex = __commonJSMin((exports, module) => {
module.exports = ({ onlyFirst = false } = {}) => {
const pattern = ["[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)", "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))"].join("|");
return new RegExp(pattern, onlyFirst ? void 0 : "g");
};
});
var require_strip_ansi = __commonJSMin((exports, module) => {
const ansiRegex$1 = require_ansi_regex();
module.exports = (string) => typeof string === "string" ? string.replace(ansiRegex$1(), "") : string;
});
var require_is_fullwidth_code_point = __commonJSMin((exports, module) => {
const isFullwidthCodePoint$1 = (codePoint) => {
if (Number.isNaN(codePoint)) return false;
if (codePoint >= 4352 && (codePoint <= 4447 || codePoint === 9001 || codePoint === 9002 || 11904 <= codePoint && codePoint <= 12871 && codePoint !== 12351 || 12880 <= codePoint && codePoint <= 19903 || 19968 <= codePoint && codePoint <= 42182 || 43360 <= codePoint && codePoint <= 43388 || 44032 <= codePoint && codePoint <= 55203 || 63744 <= codePoint && codePoint <= 64255 || 65040 <= codePoint && codePoint <= 65049 || 65072 <= codePoint && codePoint <= 65131 || 65281 <= codePoint && codePoint <= 65376 || 65504 <= codePoint && codePoint <= 65510 || 110592 <= codePoint && codePoint <= 110593 || 127488 <= codePoint && codePoint <= 127569 || 131072 <= codePoint && codePoint <= 262141)) return true;
return false;
};
module.exports = isFullwidthCodePoint$1;
module.exports.default = isFullwidthCodePoint$1;
});
var require_emoji_regex$1 = __commonJSMin((exports, module) => {
module.exports = function() {
return /\uD83C\uDFF4\uDB40\uDC67\uDB40\uDC62(?:\uDB40\uDC65\uDB40\uDC6E\uDB40\uDC67|\uDB40\uDC73\uDB40\uDC63\uDB40\uDC74|\uDB40\uDC77\uDB40\uDC6C\uDB40\uDC73)\uDB40\uDC7F|\uD83D\uDC68(?:\uD83C\uDFFC\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68\uD83C\uDFFB|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFE])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFD])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFC])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83D\uDC68|(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D[\uDC66\uDC67])|[\u2695\u2696\u2708]\uFE0F|\uD83D[\uDC66\uDC67]|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|(?:\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708])\uFE0F|\uD83C\uDFFB\u200D(?:\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C[\uDFFB-\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFB\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDD1D\u200D\uD83D\uDC69)\uD83C\uDFFB|\uD83E\uDDD1(?:\uD83C\uDFFF\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1(?:\uD83C[\uDFFB-\uDFFF])|\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1)|(?:\uD83E\uDDD1\uD83C\uDFFE\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB-\uDFFE])|(?:\uD83E\uDDD1\uD83C\uDFFC\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDD1D\u200D\uD83D\uDC69)(?:\uD83C[\uDFFB\uDFFC])|\uD83D\uDC69(?:\uD83C\uDFFE\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFD\uDFFF])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFD-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFB\u200D(?:\uD83E\uDD1D\u200D\u