@juspay/neurolink
Version:
The pipe layer of an AI nervous system: one interface connecting provider neurons to your application, across three inference types — generate, stream and decide. `decide` returns typed, calibrated judgements from a non-generative model (~400ms, ~$0.00002
169 lines • 9.24 kB
JavaScript
import chalk from "chalk";
import { logger } from "../../utils/logger.js";
/**
* `neurolink usage local` — token spend read from each CLI's own session logs.
*
* The proxy's ledger only sees traffic that went through it, which is a
* fraction of what a developer actually spends: it depends on each vendor
* shipping a base-URL override, and most do not. Every CLI writes a local
* transcript regardless, so this reads those instead — no auth, no vendor
* cooperation, no proxy in the request path, and it recovers history from
* before the proxy was ever installed.
*/
export class UsageCommandFactory {
static createUsageCommands() {
return {
command: "usage <subcommand>",
describe: "Token usage read from local CLI session logs",
builder: (yargs) => yargs.command({
command: "local",
describe: "Summarise token spend from each installed CLI's own session logs",
builder: (sub) => sub
.option("since", {
type: "number",
default: 30,
description: "Only read sessions modified within this many days (0 = all history)",
})
.option("cli", {
type: "string",
description: "Limit to one CLI id (e.g. claude-code, codex, opencode)",
})
.option("json", {
type: "boolean",
default: false,
description: "Emit the raw report as JSON",
}),
handler: async (argv) => {
// Single assertion, not a double. yargs types the sub-builder's
// argv structurally; the fields below are the ones the builder
// declares, so this stays overlap-checked by the compiler.
await UsageCommandFactory.executeLocal({
since: Number(argv.since ?? 30),
json: Boolean(argv.json),
...(typeof argv.cli === "string" ? { cli: argv.cli } : {}),
});
},
}),
handler: () => {
// yargs prints subcommand help when none is given.
},
};
}
static formatTokens(value) {
// Plain grouped digits rather than 1.2M: these are billing-adjacent
// figures and a reader comparing two rows needs the magnitudes to line up,
// not to be rounded into looking similar.
return value.toLocaleString("en-US");
}
static async executeLocal(argv) {
const { readAllLocalUsage, getLocalUsageDescriptors } = await import("../../localUsage/index.js");
// `--since 0` means all history — Infinity is the reader's sentinel for
// "no time filter", but 0 is what a person types. A NEGATIVE value is a
// mistake and must be rejected rather than folded in with 0: the previous
// expression sent -1 down the all-history path, so a typo produced the
// most expensive possible scan while the option's own help text says 0 is
// the way to ask for that.
if (!Number.isFinite(argv.since) || argv.since < 0) {
console.error(chalk.red(`--since must be zero or greater (0 means all history). Received: ${String(argv.since)}`));
process.exitCode = 1;
return;
}
const sinceDays = argv.since > 0 ? argv.since : Infinity;
// Validate BEFORE scanning. A typo should cost nothing, not a full sweep
// of every store followed by an empty result.
// `undefined` means the flag was not given. An empty string means it was
// given with no value, which is a mistake and must be rejected — a
// truthiness check treats the two as the same and silently scans every
// reader instead, reporting everything for a request that named nothing.
// "copilot-cli" is the pre-rename spelling and is still in the published
// LocalUsageCliId union, so it must keep resolving. Normalised here rather
// than registered twice: two descriptors for one reader would show the CLI
// twice in every report.
const wanted = argv.cli === "copilot-cli" ? "copilot" : argv.cli;
const known = getLocalUsageDescriptors().map((d) => d.id);
if (wanted !== undefined &&
!known.includes(wanted)) {
console.error(chalk.red(`Unknown CLI "${wanted}". Known readers: ${known.join(", ")}`));
process.exitCode = 1;
return;
}
const report = await readAllLocalUsage({
sinceDays,
// Passed down so only the requested reader opens its store at all.
...(wanted !== undefined
? { only: [wanted] }
: {}),
});
const rows = Object.entries(report.totals);
if (argv.json) {
logger.always(JSON.stringify(wanted ? { ...report, totals: Object.fromEntries(rows) } : report, null, 2));
return;
}
const window = sinceDays === Infinity ? "all history" : `last ${argv.since} days`;
logger.always(chalk.bold(`\nLocal CLI token usage — ${window}\n`));
// A reader that ran and found nothing in the window is a different fact
// from one that is not installed, and from one that failed. Printing a
// block of zeros for it buries the rows that matter, so it gets one line.
const quiet = rows.filter(([, t]) => t && t.requests === 0);
const active = rows.filter(([, t]) => t && t.requests > 0);
// What `requests` counts is not the same for every reader, so the label is
// read off the descriptor rather than hard-coded. Printing "turns" for a
// reader that counts sessions is a small lie that makes a Cursor row look
// directly comparable to a Claude Code row, which it is not.
const unitById = new Map(getLocalUsageDescriptors().map((d) => [d.id, d.requestUnit ?? "turn"]));
for (const [cliId, totals] of active) {
if (!totals) {
continue;
}
const cached = totals.cacheReadTokens + totals.cacheCreationTokens;
logger.always(chalk.cyan(` ${cliId}`));
const unit = unitById.get(cliId) ?? "turn";
logger.always(unit === "session-snapshot"
? ` sessions ${UsageCommandFactory.formatTokens(totals.requests)}` +
chalk.dim(" (context snapshots, not per-turn usage)")
: ` turns ${UsageCommandFactory.formatTokens(totals.requests)}`);
logger.always(` input ${UsageCommandFactory.formatTokens(totals.inputTokens)}` +
` output ${UsageCommandFactory.formatTokens(totals.outputTokens)}` +
` cached ${UsageCommandFactory.formatTokens(cached)}`);
// Cost and its confidence are printed together, always. A dollar figure
// shown without saying how it was arrived at is the thing this whole
// subsystem is trying not to do: "unavailable" means the CLI is a
// subscription and a per-token price would be invented, not that the
// lookup failed.
if (totals.costConfidence === "modeled") {
logger.always(` cost ${chalk.green(`$${totals.costUsd.toFixed(2)}`)} (modeled)` +
(totals.unpricedRequests > 0
? chalk.dim(` — ${totals.unpricedRequests} turns unpriced: ${totals.unpricedModels.join(", ")}`)
: ""));
}
else {
logger.always(` cost ${chalk.dim("unavailable")} ` +
chalk.dim(totals.costConfidence === "heuristic"
? "(estimated, not measured)"
: "(subscription — a per-token price would be invented)"));
}
logger.always("");
}
if (quiet.length > 0) {
logger.always(chalk.dim(` no usage in this window: ${quiet.map(([id]) => id).join(", ")}`));
}
if (report.notInstalled.length > 0) {
logger.always(chalk.dim(` not installed: ${report.notInstalled.join(", ")}`));
}
for (const failure of report.failures) {
logger.always(chalk.yellow(` ${failure.cliId} failed: ${failure.message}`));
}
// A reader that read nine of ten transcripts still reports totals, and
// those totals are wrong by the tenth. Printed next to the numbers they
// undercut, because a silently short total is the failure mode this whole
// command exists to avoid.
if (report.scanErrors.length > 0) {
logger.always(chalk.yellow(` ${report.scanErrors.length} file(s) could not be read; totals are incomplete`));
for (const scanError of report.scanErrors.slice(0, 5)) {
logger.always(chalk.dim(` ${scanError.cliId}: ${scanError.message}`));
}
}
logger.always("");
}
}
//# sourceMappingURL=usage.js.map