repospend 0.1.5 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/README.md +21 -1
- package/dist/cli.js +120 -37
- package/docs/llms.txt +7 -0
- package/docs/pricing.md +26 -1
- package/package.json +1 -1
- package/web-dist/assets/index-C3XBInjD.css +1 -0
- package/web-dist/assets/{index-aLOshIdm.js → index-D4cLshng.js} +89 -89
- package/web-dist/index.html +2 -2
- package/web-dist/assets/index-Bzdfbi5w.css +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to RepoSpend will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## Unreleased
|
|
6
|
+
|
|
7
|
+
## 0.1.7
|
|
8
|
+
|
|
9
|
+
- Correct Claude Sonnet 5.5 cache reads to $0.10 per million tokens following the October 7 price reduction, without changing Sonnet 5 or intentional custom overrides.
|
|
10
|
+
- Add Claude Haiku 5.5 pricing for prompts up to and over 100,000 tokens, including both cache-write TTLs. Price deduplicated Claude and Copilot inference requests before summing session costs; leave aggregate-only Haiku usage unpriced when request lengths are unknown.
|
|
11
|
+
- Add Gemini 4 Argon and Copilot aliases at introductory $2 input / $0.10 cached input / $10 output rates, with the November 30 promotion expiry recorded in pricing documentation.
|
|
12
|
+
- Preserve exact custom snapshot cards and migrate unchanged Sonnet 5.5 rows in legacy full-table pricing settings.
|
|
13
|
+
- Sum unrounded request costs before rounding the session estimate to six decimal places.
|
|
14
|
+
- Keep inherited Haiku snapshot edits on the shared base card, expose the higher-tier card alongside used models, and explain missing request context and auxiliary model rates in pricing triage.
|
|
15
|
+
- Preserve Haiku rate-card identity while typing or clearing numeric fields, keep pricing columns compact, and show readable request-pricing diagnostics across repo views.
|
|
16
|
+
- Cache model resolution within each session's cost calculation and preserve tolerated numeric-string Claude input counts during deduplication.
|
|
17
|
+
|
|
18
|
+
## 0.1.6
|
|
19
|
+
|
|
20
|
+
- Add explicit GPT-6.1 Sol Standard API-equivalent pricing, including its lower $0.10 cached-input rate, without changing GPT-6 Sol estimates.
|
|
21
|
+
- Resolve date-suffixed GPT model IDs to the correct generation while preserving custom snapshot overrides, including case-insensitive and provider-prefixed aliases, and unknown fast-mode cards.
|
|
22
|
+
- Add model pricing and Codex usage guide links to the README and AI-readable documentation, with current pricing sources and estimate limits.
|
|
23
|
+
|
|
5
24
|
## 0.1.5
|
|
6
25
|
|
|
7
26
|
- Correct GPT-5.6 Sol and its alias to the current promotional rates, preserving custom pricing overrides.
|
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# RepoSpend
|
|
1
|
+
# RepoSpend — local AI coding cost tracker
|
|
2
2
|
|
|
3
3
|
RepoSpend is a local-first dashboard for tracking AI coding token usage and API-equivalent spend by repository, session, model, and tool. It supports local Codex, Claude Code, and GitHub Copilot usage data, runs with `npx repospend`, and does not upload prompts, code, transcripts, or usage data.
|
|
4
4
|
|
|
@@ -19,6 +19,26 @@ Project links:
|
|
|
19
19
|
- npm package: [`repospend`](https://www.npmjs.com/package/repospend)
|
|
20
20
|
- AI-readable summary: [docs/llms.txt](docs/llms.txt)
|
|
21
21
|
|
|
22
|
+
## Model pricing and usage guides
|
|
23
|
+
|
|
24
|
+
The 0.1.7 pricing update (October 17) adds Claude Haiku 5.5's two prompt-length tiers,
|
|
25
|
+
reduces Sonnet 5.5 cache reads to $0.10 per million tokens, and adds Gemini 4
|
|
26
|
+
Argon's introductory rates through November 30. Claude and Copilot inference
|
|
27
|
+
records are priced per request; aggregate-only Haiku usage stays unpriced when
|
|
28
|
+
request lengths are unavailable. These are current API-equivalent estimates,
|
|
29
|
+
not historical invoices. See [pricing methodology](docs/pricing.md) for rates,
|
|
30
|
+
promotion dates, and custom overrides.
|
|
31
|
+
|
|
32
|
+
RepoSpend includes explicit **GPT-6.1 Sol** API-equivalent pricing: $2 input,
|
|
33
|
+
$0.10 cached input, $2.50 cache writes, and $10 output per million tokens at
|
|
34
|
+
Standard short-context rates. GPT-6 Sol keeps its separate $0.20 cache-read rate.
|
|
35
|
+
Estimates describe local token usage, not your ChatGPT or Codex subscription bill.
|
|
36
|
+
|
|
37
|
+
- [GPT-6.1 Sol pricing and Codex cost tracking](https://repospend.com/guides/gpt-6-1-sol-pricing) — caching, a worked estimate, and local repository usage.
|
|
38
|
+
- [The AI coding price war: Claude 5.5 vs GPT-6.1 Sol](https://repospend.com/guides/ai-coding-price-war) — provider rates and cost per successful task.
|
|
39
|
+
- [Pricing methodology and local overrides](docs/pricing.md)
|
|
40
|
+
- [Token accounting: input, caching, output, and reasoning](docs/token-accounting.md)
|
|
41
|
+
|
|
22
42
|
```bash
|
|
23
43
|
npx repospend
|
|
24
44
|
```
|
package/dist/cli.js
CHANGED
|
@@ -253,9 +253,11 @@ function claudePricingFamilyModel(model, isUsable = () => true) {
|
|
|
253
253
|
"claude-sonnet-4-5",
|
|
254
254
|
"claude-sonnet-4",
|
|
255
255
|
"claude-haiku-4-5",
|
|
256
|
+
"claude-haiku-5-5",
|
|
256
257
|
"claude-3-5-haiku"
|
|
257
258
|
];
|
|
258
259
|
const normalized = normalizePricingModelId(model);
|
|
260
|
+
if (normalized.includes("-long-context")) return void 0;
|
|
259
261
|
const matchesFamily = (candidate) => normalized === candidate || normalized.startsWith(`${candidate}-`) || normalized.startsWith(`${candidate}.`);
|
|
260
262
|
if (normalized.includes("fast-mode")) {
|
|
261
263
|
return families.find((candidate) => candidate.includes("fast-mode") && matchesFamily(candidate) && isUsable(candidate));
|
|
@@ -271,7 +273,7 @@ function copilotPricingFamilyModel(model, isUsable = () => true) {
|
|
|
271
273
|
if ((normalized === "gemini-3-flash" || normalized.startsWith("gemini-3-flash-")) && isUsable("gemini-3-flash")) return "gemini-3-flash";
|
|
272
274
|
if ((normalized === "gemini-3.1-pro" || normalized.startsWith("gemini-3.1-pro-")) && isUsable("gemini-3.1-pro")) return "gemini-3.1-pro";
|
|
273
275
|
if ((normalized === "gemini-3.5-flash" || normalized.startsWith("gemini-3.5-flash-")) && isUsable("gemini-3.5-flash")) return "gemini-3.5-flash";
|
|
274
|
-
for (const candidate of ["gemini-3.6-flash", "gemini-3.7-flash", "gemini-3.8-flash", "grok-4.5", "grok-4.6", "grok-4.7", "mai-code-1.1-flash", "kimi-k3"]) {
|
|
276
|
+
for (const candidate of ["gemini-3.6-flash", "gemini-3.7-flash", "gemini-3.8-flash", "gemini-4-argon", "grok-4.5", "grok-4.6", "grok-4.7", "mai-code-1.1-flash", "kimi-k3"]) {
|
|
275
277
|
if ((normalized === candidate || normalized.startsWith(`${candidate}-`)) && isUsable(candidate)) return candidate;
|
|
276
278
|
}
|
|
277
279
|
if ((normalized === "raptor-mini" || normalized.startsWith("raptor-mini-") || normalized.startsWith("oswe-vscode")) && isUsable("raptor-mini")) return "raptor-mini";
|
|
@@ -282,13 +284,14 @@ function copilotPricingFamilyModel(model, isUsable = () => true) {
|
|
|
282
284
|
return void 0;
|
|
283
285
|
}
|
|
284
286
|
function parseVersionedModel(normalized) {
|
|
285
|
-
if (normalized.includes("fast-mode")) return void 0;
|
|
287
|
+
if (normalized.includes("fast-mode") || normalized.includes("-long-context")) return void 0;
|
|
286
288
|
const claude = normalized.match(/^(claude-(?:fable|mythos|opus|sonnet|haiku))-(\d+)(?:-(\d{1,2}))?(?!\d)/);
|
|
287
289
|
if (claude) {
|
|
288
290
|
const minor = claude[3] ? Number(claude[3]) : 0;
|
|
289
291
|
return { tier: claude[1], version: Number(claude[2]) + minor / 100 };
|
|
290
292
|
}
|
|
291
|
-
const
|
|
293
|
+
const gptModel = normalized.replace(/-(?:\d{4}-\d{2}-\d{2}|\d{8})$/, "");
|
|
294
|
+
const gpt = gptModel.match(/^(gpt)-(\d)(?:\.(\d+))?(-[a-z][a-z0-9-]*)?$/);
|
|
292
295
|
if (gpt) {
|
|
293
296
|
const minor = gpt[3] ? Number(gpt[3]) : 0;
|
|
294
297
|
return { tier: `gpt${gpt[4] ?? ""}`, version: Number(gpt[2]) + minor / 100 };
|
|
@@ -317,17 +320,36 @@ function positiveRate(value) {
|
|
|
317
320
|
function isUsableModelPricing(pricing) {
|
|
318
321
|
return positiveRate(pricing?.inputPerMillion) && positiveRate(pricing?.outputPerMillion);
|
|
319
322
|
}
|
|
320
|
-
function
|
|
323
|
+
function resolvePricingForModel(model, table) {
|
|
321
324
|
const lower = normalizePricingModelId(model);
|
|
322
|
-
const
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
325
|
+
const exactModel = table[model] ? model : table[lower] ? lower : void 0;
|
|
326
|
+
const exactPricing = exactModel ? table[exactModel] : void 0;
|
|
327
|
+
if (isUsableModelPricing(exactPricing)) {
|
|
328
|
+
return { pricing: exactPricing, sourceModel: exactModel, inherited: false };
|
|
329
|
+
}
|
|
330
|
+
const versioned = versionedFallbackModel(lower, Object.keys(table), (candidate) => isUsableModelPricing(table[candidate]));
|
|
331
|
+
if (versioned) {
|
|
332
|
+
return { pricing: table[versioned], sourceModel: versioned, inherited: versioned !== model && versioned !== lower };
|
|
333
|
+
}
|
|
334
|
+
const claudeFamily = claudePricingFamilyModel(lower, (candidate) => isUsableModelPricing(table[candidate]));
|
|
335
|
+
if (claudeFamily) {
|
|
336
|
+
return { pricing: table[claudeFamily], sourceModel: claudeFamily, inherited: claudeFamily !== model && claudeFamily !== lower };
|
|
337
|
+
}
|
|
338
|
+
const copilotFamily = copilotPricingFamilyModel(lower, (candidate) => isUsableModelPricing(table[candidate]));
|
|
339
|
+
if (copilotFamily) {
|
|
340
|
+
return { pricing: table[copilotFamily], sourceModel: copilotFamily, inherited: copilotFamily !== model && copilotFamily !== lower };
|
|
341
|
+
}
|
|
342
|
+
return {
|
|
343
|
+
pricing: exactPricing ?? {
|
|
344
|
+
inputPerMillion: 0,
|
|
345
|
+
cacheCreationInputPerMillion: 0,
|
|
346
|
+
cachedInputPerMillion: 0,
|
|
347
|
+
outputPerMillion: 0,
|
|
348
|
+
reasoningOutputPerMillion: 0
|
|
349
|
+
},
|
|
350
|
+
sourceModel: exactModel,
|
|
351
|
+
inherited: false
|
|
352
|
+
};
|
|
331
353
|
}
|
|
332
354
|
|
|
333
355
|
// packages/core/src/pricing.ts
|
|
@@ -337,18 +359,22 @@ var pricingInfo = {
|
|
|
337
359
|
sourceUrls: [
|
|
338
360
|
{ label: "OpenAI pricing reference", url: "https://developers.openai.com/api/docs/pricing" },
|
|
339
361
|
{ label: "OpenAI GPT-6 model reference", url: "https://developers.openai.com/api/docs/models" },
|
|
362
|
+
{ label: "OpenAI GPT-6.1 Sol reference", url: "https://developers.openai.com/api/docs/models/gpt-6.1-sol" },
|
|
340
363
|
{ label: "OpenAI GPT-5.6 preview pricing", url: "https://openai.com/index/previewing-gpt-5-6-sol/" },
|
|
341
364
|
{ label: "OpenAI GPT-5.6 price update", url: "https://openai.com/index/advancing-the-price-performance-frontier-with-gpt-5-6/" },
|
|
342
365
|
{ label: "Claude pricing reference", url: "https://platform.claude.com/docs/en/about-claude/pricing" },
|
|
366
|
+
{ label: "Claude Haiku 5.5 and Sonnet cache update", url: "https://www.anthropic.com/claude-haiku-5-5" },
|
|
367
|
+
{ label: "Gemini 4 Argon pricing", url: "https://ai.google.dev/gemini-api/docs/latest-model?hl=en" },
|
|
343
368
|
{ label: "GitHub Copilot model pricing reference", url: "https://docs.github.com/en/copilot/reference/copilot-billing/models-and-pricing" }
|
|
344
369
|
],
|
|
345
370
|
unit: "USD per 1M tokens",
|
|
346
|
-
updatedAt: "2026-
|
|
371
|
+
updatedAt: "2026-10-17",
|
|
347
372
|
note: "RepoSpend estimates API-equivalent cost from local token counts and public Standard pricing. GPT-6 defaults use short-context rates. Claude transcript fast-mode speeds use explicit published cards. Long-context, other processing modes, regional, and account-specific pricing can differ. This is not your actual bill."
|
|
348
373
|
};
|
|
349
374
|
var defaultPricing = {
|
|
350
375
|
"gpt-6-astra": { inputPerMillion: 10, cachedInputPerMillion: 1, cacheCreationInputPerMillion: 12.5, outputPerMillion: 50, reasoningOutputPerMillion: 50 },
|
|
351
376
|
"gpt-6-sol": { inputPerMillion: 2, cachedInputPerMillion: 0.2, cacheCreationInputPerMillion: 2.5, outputPerMillion: 10, reasoningOutputPerMillion: 10 },
|
|
377
|
+
"gpt-6.1-sol": { inputPerMillion: 2, cachedInputPerMillion: 0.1, cacheCreationInputPerMillion: 2.5, outputPerMillion: 10, reasoningOutputPerMillion: 10 },
|
|
352
378
|
"gpt-6-luna": { inputPerMillion: 0.1, cachedInputPerMillion: 0.01, cacheCreationInputPerMillion: 0.125, outputPerMillion: 0.5, reasoningOutputPerMillion: 0.5 },
|
|
353
379
|
"gpt-5.6": { inputPerMillion: 4, cachedInputPerMillion: 0.4, cacheCreationInputPerMillion: 5, outputPerMillion: 20, reasoningOutputPerMillion: 20, note: "GPT-5.6 aliases Sol. Promotional Standard short-context rates are available at least through November 21, 2026: $4 input / $20 output, $0.40 cache reads, and $5 cache writes per 1M tokens." },
|
|
354
380
|
"gpt-5.6-sol": { inputPerMillion: 4, cachedInputPerMillion: 0.4, cacheCreationInputPerMillion: 5, outputPerMillion: 20, reasoningOutputPerMillion: 20, note: "Promotional Standard short-context rates available at least through November 21, 2026." },
|
|
@@ -384,6 +410,7 @@ var defaultPricing = {
|
|
|
384
410
|
"gemini-3.6-flash": { inputPerMillion: 0.75, cachedInputPerMillion: 0.075, outputPerMillion: 3.75, note: "GitHub Copilot promotional rates through December 31, 2026; API-equivalent estimate." },
|
|
385
411
|
"gemini-3.7-flash": { inputPerMillion: 0.75, cachedInputPerMillion: 0.075, outputPerMillion: 3.75, note: "GitHub Copilot promotional rates through December 31, 2026; API-equivalent estimate." },
|
|
386
412
|
"gemini-3.8-flash": { inputPerMillion: 0.75, cachedInputPerMillion: 0.075, outputPerMillion: 3.75, note: "GitHub Copilot promotional rates through December 31, 2026; API-equivalent estimate." },
|
|
413
|
+
"gemini-4-argon": { inputPerMillion: 2, cachedInputPerMillion: 0.1, outputPerMillion: 10, reasoningOutputPerMillion: 10, note: "Introductory rates through November 30, 2026. From December 1: $4 input / $0.20 cached input / $20 output (including thinking) per 1M tokens. No explicit cache-write charge. Bundled prices are a dated snapshot, not an automatic future rate switch." },
|
|
387
414
|
"grok-4.5": { inputPerMillion: 2, cachedInputPerMillion: 0.5, outputPerMillion: 6, note: "GitHub Copilot Standard rates up to 200K input tokens; longer requests use different rates." },
|
|
388
415
|
"grok-4.6": { inputPerMillion: 2, cachedInputPerMillion: 0.5, outputPerMillion: 6, note: "GitHub Copilot Standard rates up to 200K input tokens; longer requests use different rates." },
|
|
389
416
|
"grok-4.7": { inputPerMillion: 2, cachedInputPerMillion: 0.5, outputPerMillion: 6, note: "GitHub Copilot Standard rates up to 200K input tokens; longer requests use different rates." },
|
|
@@ -411,15 +438,18 @@ var defaultPricing = {
|
|
|
411
438
|
"claude-opus-4-5": { inputPerMillion: 5, cacheCreationInput5mPerMillion: 6.25, cacheCreationInput1hPerMillion: 10, cacheCreationInputPerMillion: 10, cachedInputPerMillion: 0.5, outputPerMillion: 25 },
|
|
412
439
|
"claude-opus-4-1": { inputPerMillion: 15, cacheCreationInput5mPerMillion: 18.75, cacheCreationInput1hPerMillion: 30, cacheCreationInputPerMillion: 30, cachedInputPerMillion: 1.5, outputPerMillion: 75 },
|
|
413
440
|
"claude-opus-4": { inputPerMillion: 15, cacheCreationInput5mPerMillion: 18.75, cacheCreationInput1hPerMillion: 30, cacheCreationInputPerMillion: 30, cachedInputPerMillion: 1.5, outputPerMillion: 75 },
|
|
414
|
-
"claude-sonnet-5-5": { inputPerMillion: 2, cacheCreationInput5mPerMillion: 2.5, cacheCreationInput1hPerMillion: 4, cacheCreationInputPerMillion: 4, cachedInputPerMillion: 0.
|
|
441
|
+
"claude-sonnet-5-5": { inputPerMillion: 2, cacheCreationInput5mPerMillion: 2.5, cacheCreationInput1hPerMillion: 4, cacheCreationInputPerMillion: 4, cachedInputPerMillion: 0.1, outputPerMillion: 10 },
|
|
415
442
|
"claude-sonnet-5": { inputPerMillion: 2, cacheCreationInput5mPerMillion: 2.5, cacheCreationInput1hPerMillion: 4, cacheCreationInputPerMillion: 4, cachedInputPerMillion: 0.2, outputPerMillion: 10, note: "Anthropic made the $2 input / $10 output introductory pricing permanent on August 10, 2026." },
|
|
416
443
|
"claude-sonnet-4-6": { inputPerMillion: 3, cacheCreationInput5mPerMillion: 3.75, cacheCreationInput1hPerMillion: 6, cacheCreationInputPerMillion: 6, cachedInputPerMillion: 0.3, outputPerMillion: 15 },
|
|
417
444
|
"claude-sonnet-4-5": { inputPerMillion: 3, cacheCreationInput5mPerMillion: 3.75, cacheCreationInput1hPerMillion: 6, cacheCreationInputPerMillion: 6, cachedInputPerMillion: 0.3, outputPerMillion: 15 },
|
|
418
445
|
"claude-sonnet-4": { inputPerMillion: 3, cacheCreationInput5mPerMillion: 3.75, cacheCreationInput1hPerMillion: 6, cacheCreationInputPerMillion: 6, cachedInputPerMillion: 0.3, outputPerMillion: 15 },
|
|
419
446
|
"claude-haiku-4-5": { inputPerMillion: 1, cacheCreationInput5mPerMillion: 1.25, cacheCreationInput1hPerMillion: 2, cacheCreationInputPerMillion: 2, cachedInputPerMillion: 0.1, outputPerMillion: 5 },
|
|
447
|
+
"claude-haiku-5-5": { inputPerMillion: 0.1, cacheCreationInput5mPerMillion: 0.125, cacheCreationInput1hPerMillion: 0.2, cacheCreationInputPerMillion: 0.2, cachedInputPerMillion: 0.01, outputPerMillion: 0.5, note: "Prompts up to 100,000 input tokens per request, including cache reads and writes. Larger prompts use the separately editable claude-haiku-5-5-long-context card. Aggregate-only usage stays unpriced when request lengths are unknown." },
|
|
448
|
+
"claude-haiku-5-5-long-context": { inputPerMillion: 0.5, cacheCreationInput5mPerMillion: 0.625, cacheCreationInput1hPerMillion: 1, cacheCreationInputPerMillion: 1, cachedInputPerMillion: 0.05, outputPerMillion: 2.5, note: "RepoSpend pricing card, not a provider model ID. Applied to the whole Haiku 5.5 request when total prompt length exceeds 100,000 tokens." },
|
|
420
449
|
"claude-3-5-haiku": { inputPerMillion: 0.8, cacheCreationInput5mPerMillion: 1, cacheCreationInput1hPerMillion: 1.6, cacheCreationInputPerMillion: 1.6, cachedInputPerMillion: 0.08, outputPerMillion: 4 }
|
|
421
450
|
};
|
|
422
451
|
var legacyBundledPricing = {
|
|
452
|
+
"claude-sonnet-5-5": { inputPerMillion: 2, cacheCreationInput5mPerMillion: 2.5, cacheCreationInput1hPerMillion: 4, cacheCreationInputPerMillion: 4, cachedInputPerMillion: 0.2, outputPerMillion: 10 },
|
|
423
453
|
"gpt-5.6": { inputPerMillion: 5, cachedInputPerMillion: 0.5, cacheCreationInputPerMillion: 6.25, outputPerMillion: 30, reasoningOutputPerMillion: 30, note: "GPT-5.6 Sol flagship tier. OpenAI preview pricing lists Sol at $5 input / $30 output per 1M tokens, cache writes at 1.25x input, and cache reads at a 90% discount." },
|
|
424
454
|
"gpt-5.6-sol": { inputPerMillion: 5, cachedInputPerMillion: 0.5, cacheCreationInputPerMillion: 6.25, outputPerMillion: 30, reasoningOutputPerMillion: 30 },
|
|
425
455
|
"gpt-5.6-terra": { inputPerMillion: 2.5, cachedInputPerMillion: 0.25, cacheCreationInputPerMillion: 3.125, outputPerMillion: 15, reasoningOutputPerMillion: 15 },
|
|
@@ -526,12 +556,43 @@ function savePricingTable(pricingPath, pricing) {
|
|
|
526
556
|
function repospendHome() {
|
|
527
557
|
return process.env.REPOSPEND_HOME || path.join(os.homedir(), ".repospend");
|
|
528
558
|
}
|
|
529
|
-
function calculateCostUsd(usage, pricing) {
|
|
559
|
+
function calculateCostUsd(usage, pricing, requestInputTokens) {
|
|
560
|
+
const cost = unroundedCostUsd(usage, pricing, requestInputTokens);
|
|
561
|
+
return cost === void 0 ? void 0 : Number((cost + Number.EPSILON).toFixed(6));
|
|
562
|
+
}
|
|
563
|
+
function calculateRequestCosts(requests, pricing) {
|
|
564
|
+
const resolutions = /* @__PURE__ */ new Map();
|
|
565
|
+
const warnings = /* @__PURE__ */ new Set();
|
|
566
|
+
let total = 0;
|
|
567
|
+
for (const request of requests) {
|
|
568
|
+
let resolution = request.model ? resolutions.get(request.model) : void 0;
|
|
569
|
+
if (request.model && !resolution) {
|
|
570
|
+
resolution = resolvePricingForModel(request.model, pricing);
|
|
571
|
+
resolutions.set(request.model, resolution);
|
|
572
|
+
}
|
|
573
|
+
const cost = unroundedCostUsd(request, pricing, request.requestInputTokens, resolution);
|
|
574
|
+
if (cost !== void 0) total += cost;
|
|
575
|
+
else if (request.model && resolution) {
|
|
576
|
+
const missingContext = needsHaikuContext(request.model, resolution) && (request.requestInputTokens === void 0 || !Number.isFinite(request.requestInputTokens) || request.requestInputTokens < 0);
|
|
577
|
+
warnings.add(missingContext ? "unknown_request_context" : `unknown_pricing_model:${normalizePricingModelId(request.model)}`);
|
|
578
|
+
} else warnings.add("unknown_pricing");
|
|
579
|
+
}
|
|
580
|
+
return { costUsd: requests.length && !warnings.size ? Number((total + Number.EPSILON).toFixed(6)) : void 0, warnings: [...warnings] };
|
|
581
|
+
}
|
|
582
|
+
function needsHaikuContext(model, resolution) {
|
|
583
|
+
return resolution.sourceModel === "claude-haiku-5-5" || resolution.inherited && /^claude-haiku-5-5(?:$|[-.@[])/.test(normalizePricingModelId(model));
|
|
584
|
+
}
|
|
585
|
+
function unroundedCostUsd(usage, pricing, requestInputTokens, cachedResolution) {
|
|
530
586
|
if (!usage.model) {
|
|
531
587
|
return void 0;
|
|
532
588
|
}
|
|
533
|
-
const
|
|
534
|
-
|
|
589
|
+
const resolution = cachedResolution ?? resolvePricingForModel(usage.model, pricing);
|
|
590
|
+
let modelPricing = resolution.pricing;
|
|
591
|
+
if (needsHaikuContext(usage.model, resolution)) {
|
|
592
|
+
if (requestInputTokens === void 0 || !Number.isFinite(requestInputTokens) || requestInputTokens < 0) return void 0;
|
|
593
|
+
modelPricing = pricing[requestInputTokens > 1e5 ? "claude-haiku-5-5-long-context" : "claude-haiku-5-5"];
|
|
594
|
+
}
|
|
595
|
+
if (!isUsableModelPricing(modelPricing)) {
|
|
535
596
|
return void 0;
|
|
536
597
|
}
|
|
537
598
|
const cacheCreationInput5m = usage.cacheCreationInputTokens5m ?? 0;
|
|
@@ -546,7 +607,7 @@ function calculateCostUsd(usage, pricing) {
|
|
|
546
607
|
const cacheCreation1hRate = firstPositiveRate(modelPricing.cacheCreationInput1hPerMillion, modelPricing.cacheCreationInputPerMillion, modelPricing.inputPerMillion);
|
|
547
608
|
const reasoningRate = modelPricing.reasoningOutputPerMillion ?? modelPricing.outputPerMillion;
|
|
548
609
|
const cost = billableInput / 1e6 * modelPricing.inputPerMillion + usage.cachedInputTokens / 1e6 * cachedRate + cacheCreationInput5m / 1e6 * cacheCreation5mRate + cacheCreationInput1h / 1e6 * cacheCreation1hRate + unclassifiedCacheCreationInput / 1e6 * cacheCreationRate + usage.outputTokens / 1e6 * modelPricing.outputPerMillion + usage.reasoningTokens / 1e6 * reasoningRate;
|
|
549
|
-
return
|
|
610
|
+
return cost;
|
|
550
611
|
}
|
|
551
612
|
function firstPositiveRate(...rates) {
|
|
552
613
|
return rates.find((rate) => typeof rate === "number" && Number.isFinite(rate) && rate > 0) ?? 0;
|
|
@@ -2285,12 +2346,13 @@ function threadToUsage(row, index, sessionFiles, options, importedModels = /* @_
|
|
|
2285
2346
|
sessionOutcome: inferOutcome(sessionBreakdown),
|
|
2286
2347
|
compaction: sessionBreakdown.compaction
|
|
2287
2348
|
};
|
|
2288
|
-
const
|
|
2349
|
+
const estimate = hasPricedBreakdown ? calculateRequestCosts([usage], options.pricing) : void 0;
|
|
2350
|
+
const cost = estimate?.costUsd;
|
|
2289
2351
|
const costWarnings = hasPricedBreakdown ? warnings : [...warnings, "missing_token_breakdown"];
|
|
2290
2352
|
return {
|
|
2291
2353
|
...usage,
|
|
2292
2354
|
estimatedCostUsd: cost,
|
|
2293
|
-
warnings: cost === void 0 ? [...costWarnings, "unknown_pricing"] : warnings
|
|
2355
|
+
warnings: cost === void 0 ? [.../* @__PURE__ */ new Set([...costWarnings, "unknown_pricing", ...estimate?.warnings ?? []])] : warnings
|
|
2294
2356
|
};
|
|
2295
2357
|
}
|
|
2296
2358
|
function readStandaloneSessions(sessionFiles, options) {
|
|
@@ -2360,11 +2422,12 @@ function readStandaloneSessions(sessionFiles, options) {
|
|
|
2360
2422
|
compaction: breakdown.compaction
|
|
2361
2423
|
};
|
|
2362
2424
|
const hasPricedBreakdown = breakdown.inputTokens + breakdown.cachedInputTokens + breakdown.outputTokens + breakdown.reasoningTokens > 0;
|
|
2363
|
-
const
|
|
2425
|
+
const estimate = hasPricedBreakdown ? calculateRequestCosts([usage], options.pricing) : void 0;
|
|
2426
|
+
const cost = estimate?.costUsd;
|
|
2364
2427
|
return {
|
|
2365
2428
|
...usage,
|
|
2366
2429
|
estimatedCostUsd: cost,
|
|
2367
|
-
warnings: cost === void 0 ? [...usage.warnings, hasPricedBreakdown ? "unknown_pricing" : "missing_token_breakdown"] : usage.warnings
|
|
2430
|
+
warnings: cost === void 0 ? [.../* @__PURE__ */ new Set([...usage.warnings, hasPricedBreakdown ? "unknown_pricing" : "missing_token_breakdown", ...estimate?.warnings ?? []])] : usage.warnings
|
|
2368
2431
|
};
|
|
2369
2432
|
});
|
|
2370
2433
|
}
|
|
@@ -3050,21 +3113,30 @@ function claudeBreakdownToUsage(file, index, options, breakdown, idSuffix = "")
|
|
|
3050
3113
|
promptTimeline: breakdown.promptTimeline,
|
|
3051
3114
|
sessionOutcome: inferOutcome2(breakdown)
|
|
3052
3115
|
};
|
|
3053
|
-
const
|
|
3054
|
-
for (const event of breakdown.usageEvents) {
|
|
3116
|
+
const requests = breakdown.usageEvents.map((event) => {
|
|
3055
3117
|
const model = event.model ?? breakdown.model;
|
|
3056
3118
|
const normalized = model ? normalizePricingModelId(model) : void 0;
|
|
3057
3119
|
const pricingModel = normalized && normalizedServiceTier(event.usage.speed) === "fast" && !normalized.includes("fast-mode") && !/^claude-opus-4-6(?:$|-)/.test(normalized) ? `${normalized}-fast-mode` : model;
|
|
3058
|
-
const totals =
|
|
3120
|
+
const totals = emptyBreakdown2();
|
|
3059
3121
|
applyUsage(totals, event.usage);
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3122
|
+
return {
|
|
3123
|
+
model: pricingModel,
|
|
3124
|
+
inputTokens: totals.inputTokens,
|
|
3125
|
+
cachedInputTokens: totals.cachedInputTokens,
|
|
3126
|
+
cacheCreationInputTokens: totals.cacheCreationInputTokens,
|
|
3127
|
+
cacheCreationInputTokens5m: totals.cacheCreationInputTokens5m,
|
|
3128
|
+
cacheCreationInputTokens1h: totals.cacheCreationInputTokens1h,
|
|
3129
|
+
outputTokens: totals.outputTokens,
|
|
3130
|
+
reasoningTokens: 0,
|
|
3131
|
+
requestInputTokens: hasInputTokenCount(event.usage) ? totals.inputTokens : void 0
|
|
3132
|
+
};
|
|
3133
|
+
});
|
|
3134
|
+
const estimate = hasTokenBreakdown ? calculateRequestCosts(requests, options.pricing) : void 0;
|
|
3135
|
+
const cost = estimate?.costUsd;
|
|
3064
3136
|
return {
|
|
3065
3137
|
...usage,
|
|
3066
3138
|
estimatedCostUsd: cost,
|
|
3067
|
-
warnings: cost === void 0 ? [...usage.warnings, "unknown_pricing", ...
|
|
3139
|
+
warnings: cost === void 0 ? [.../* @__PURE__ */ new Set([...usage.warnings, "unknown_pricing", ...estimate?.warnings ?? [], ...estimate?.warnings.some((warning) => warning.startsWith("unknown_pricing_model:") && warning.includes("fast-mode")) ? ["unknown_fast_mode_pricing"] : []])] : usage.warnings
|
|
3068
3140
|
};
|
|
3069
3141
|
}
|
|
3070
3142
|
function inferClaudeEntrypointFromPath(filePath) {
|
|
@@ -3166,10 +3238,14 @@ function usageDedupKey(record, message) {
|
|
|
3166
3238
|
function occurrenceKey(filePath, recordIndex) {
|
|
3167
3239
|
return `${path6.resolve(filePath)}:${recordIndex}`;
|
|
3168
3240
|
}
|
|
3241
|
+
function hasInputTokenCount(usage) {
|
|
3242
|
+
const value = usage.input_tokens;
|
|
3243
|
+
return (typeof value === "number" || typeof value === "string" && value.trim() !== "") && Number.isFinite(Number(value)) && Number(value) >= 0;
|
|
3244
|
+
}
|
|
3169
3245
|
function cloneUsage(usage) {
|
|
3170
3246
|
const cacheCreation = firstObject4(usage.cache_creation);
|
|
3171
3247
|
return {
|
|
3172
|
-
input_tokens: numberValue(usage.input_tokens),
|
|
3248
|
+
input_tokens: hasInputTokenCount(usage) ? numberValue(usage.input_tokens) : void 0,
|
|
3173
3249
|
cache_read_input_tokens: numberValue(usage.cache_read_input_tokens),
|
|
3174
3250
|
cache_creation_input_tokens: numberValue(usage.cache_creation_input_tokens),
|
|
3175
3251
|
cache_creation: cacheCreation ? {
|
|
@@ -3184,7 +3260,7 @@ function cloneUsage(usage) {
|
|
|
3184
3260
|
function mergeUsageMax(target, usage) {
|
|
3185
3261
|
const targetCacheCreation = firstObject4(target.cache_creation) ?? {};
|
|
3186
3262
|
const usageCacheCreation = firstObject4(usage.cache_creation) ?? {};
|
|
3187
|
-
target.input_tokens = Math.max(numberValue(target.input_tokens), numberValue(usage.input_tokens));
|
|
3263
|
+
if (hasInputTokenCount(target) || hasInputTokenCount(usage)) target.input_tokens = Math.max(numberValue(target.input_tokens), numberValue(usage.input_tokens));
|
|
3188
3264
|
target.cache_read_input_tokens = Math.max(numberValue(target.cache_read_input_tokens), numberValue(usage.cache_read_input_tokens));
|
|
3189
3265
|
target.cache_creation_input_tokens = Math.max(numberValue(target.cache_creation_input_tokens), numberValue(usage.cache_creation_input_tokens));
|
|
3190
3266
|
target.cache_creation = {
|
|
@@ -3767,6 +3843,8 @@ function usageCandidateFromRecord(record, index, fallbackTimestamp, traceContext
|
|
|
3767
3843
|
const output = numberValue2(attributes["gen_ai.usage.output_tokens"]);
|
|
3768
3844
|
const cached = numberValue2(attributes["gen_ai.usage.cache_read.input_tokens"]);
|
|
3769
3845
|
const cacheCreation = firstPositiveNumber(attributes, ["gen_ai.usage.cache_write.input_tokens", "gen_ai.usage.cache_creation.input_tokens"]);
|
|
3846
|
+
const rawInput = attributes["gen_ai.usage.input_tokens"];
|
|
3847
|
+
const requestInputTokens = typeof rawInput === "number" && Number.isFinite(rawInput) && rawInput >= cached + cacheCreation ? rawInput : void 0;
|
|
3770
3848
|
const reasoning = firstPositiveNumber(attributes, ["gen_ai.usage.reasoning.output_tokens", "gen_ai.usage.reasoning_tokens"]);
|
|
3771
3849
|
const total = firstPositiveNumber(attributes, ["gen_ai.usage.total_tokens", "gen_ai.usage.total.token_count"]);
|
|
3772
3850
|
const outputWithFallback = output || outputTokensFromTotal(total, input, reasoning);
|
|
@@ -3783,6 +3861,7 @@ function usageCandidateFromRecord(record, index, fallbackTimestamp, traceContext
|
|
|
3783
3861
|
model: firstNonEmptyAttr(attributes, modelAttrs) ?? traceContext?.model,
|
|
3784
3862
|
timestamp: timestamp3,
|
|
3785
3863
|
durationMs: durationMsFromRecord(record),
|
|
3864
|
+
requestInputTokens,
|
|
3786
3865
|
inputTokens: input,
|
|
3787
3866
|
cachedInputTokens: cached,
|
|
3788
3867
|
cacheCreationInputTokens: cacheCreation,
|
|
@@ -3845,6 +3924,8 @@ function applyCandidate(breakdown, candidate) {
|
|
|
3845
3924
|
breakdown.endedAt = maxDate2(breakdown.endedAt, candidate.timestamp);
|
|
3846
3925
|
applyTokenEvent(breakdown, {
|
|
3847
3926
|
dedupKey: candidate.dedupKey,
|
|
3927
|
+
model: candidate.model,
|
|
3928
|
+
requestInputTokens: candidate.source === "chat_span" || candidate.source === "inference_log" ? candidate.requestInputTokens : void 0,
|
|
3848
3929
|
detailed: candidate.inputTokens > 0 || candidate.cachedInputTokens > 0 || candidate.cacheCreationInputTokens > 0 || candidate.reasoningTokens > 0,
|
|
3849
3930
|
inputTokens: candidate.inputTokens,
|
|
3850
3931
|
cachedInputTokens: candidate.cachedInputTokens,
|
|
@@ -3966,8 +4047,9 @@ function breakdownToUsage(breakdown, index, options) {
|
|
|
3966
4047
|
fileEditCount: breakdown.fileEditCount,
|
|
3967
4048
|
sourceMetadata: { copilot: { sourcePaths: breakdown.sourcePaths, surface: breakdown.surface } }
|
|
3968
4049
|
};
|
|
3969
|
-
const
|
|
3970
|
-
|
|
4050
|
+
const estimate = hasPricedBreakdown ? calculateRequestCosts(breakdown.tokenEvents.map((event) => ({ ...event, model: normalizeCopilotModel(hasKnownModel(event.model) ? event.model : breakdown.model) })), options.pricing) : void 0;
|
|
4051
|
+
const cost = estimate?.costUsd;
|
|
4052
|
+
return { ...usage, estimatedCostUsd: cost, warnings: hasPricedBreakdown && cost === void 0 ? [.../* @__PURE__ */ new Set([...usage.warnings, "unknown_pricing", ...estimate?.warnings ?? []])] : usage.warnings };
|
|
3971
4053
|
}
|
|
3972
4054
|
function unknownCopilotRepoInfo() {
|
|
3973
4055
|
return {
|
|
@@ -4872,12 +4954,13 @@ function candidateToUsage(candidate, index, options) {
|
|
|
4872
4954
|
}
|
|
4873
4955
|
}
|
|
4874
4956
|
};
|
|
4875
|
-
const
|
|
4957
|
+
const estimate = hasTokenBreakdown ? calculateRequestCosts([usage], options.pricing) : void 0;
|
|
4958
|
+
const pricedCost = estimate?.costUsd;
|
|
4876
4959
|
const estimatedCostUsd = pricedCost ?? breakdown.estimatedCostUsd;
|
|
4877
4960
|
return {
|
|
4878
4961
|
...usage,
|
|
4879
4962
|
estimatedCostUsd,
|
|
4880
|
-
warnings: estimatedCostUsd === void 0 ? [...usage.warnings, breakdown.hasEstimatedPromptTokens ? "cursor_cost_not_estimated_from_prompt_tokens" : hasTokenBreakdown ? "unknown_pricing" : "unknown_cost"] : usage.warnings
|
|
4963
|
+
warnings: estimatedCostUsd === void 0 ? [.../* @__PURE__ */ new Set([...usage.warnings, breakdown.hasEstimatedPromptTokens ? "cursor_cost_not_estimated_from_prompt_tokens" : hasTokenBreakdown ? "unknown_pricing" : "unknown_cost", ...estimate?.warnings ?? []])] : usage.warnings
|
|
4881
4964
|
};
|
|
4882
4965
|
}
|
|
4883
4966
|
function inferProjectPathFromCursorPath(filePath, cursorHome) {
|
package/docs/llms.txt
CHANGED
|
@@ -9,6 +9,8 @@ Canonical URLs:
|
|
|
9
9
|
- npm: https://www.npmjs.com/package/repospend
|
|
10
10
|
- Package name: repospend
|
|
11
11
|
- Run command: npx repospend
|
|
12
|
+
- GPT-6.1 Sol pricing and Codex tracking: https://repospend.com/guides/gpt-6-1-sol-pricing
|
|
13
|
+
- AI coding price comparison: https://repospend.com/guides/ai-coding-price-war
|
|
12
14
|
|
|
13
15
|
What RepoSpend is:
|
|
14
16
|
- A local-first AI coding token usage dashboard.
|
|
@@ -56,5 +58,10 @@ Positioning:
|
|
|
56
58
|
- RepoSpend totals can intentionally differ from ccusage or Tokscale because it includes Claude Desktop/local-agent session roots when present, treats cache reads/writes as input sub-buckets, prices Claude cache writes by recorded 5-minute vs 1-hour TTL, and separates Codex visible output from reasoning output.
|
|
57
59
|
|
|
58
60
|
Cost language:
|
|
61
|
+
- October 17, 2026 pricing update: Sonnet 5.5 cache reads are $0.10 per million tokens; Sonnet 5 remains at $0.20.
|
|
62
|
+
- Haiku 5.5 has two per-request prompt-length tiers: input/cache read/output $0.10/$0.01/$0.50 up to 100K, and $0.50/$0.05/$2.50 above 100K. Cache writes have separate 5-minute and 1-hour rates. Unknown request lengths stay unpriced.
|
|
63
|
+
- Gemini 4 Argon introductory input/cache read/output rates are $2/$0.10/$10 through November 30, 2026, then published rates become $4/$0.20/$20. Bundled tables are a dated snapshot, not an automatic future rate switch.
|
|
64
|
+
- Current API-equivalent pricing applied to older usage is not historical billing reconstruction.
|
|
65
|
+
- GPT-6.1 Sol has an explicit Standard short-context card: $2 input, $0.10 cached input, $2.50 cache writes, $10 output per million tokens, checked September 29, 2026.
|
|
59
66
|
- RepoSpend shows estimated API-equivalent cost.
|
|
60
67
|
- RepoSpend does not claim to show actual bills, invoices, subscription usage, savings, credits, or account-specific charges.
|
package/docs/pricing.md
CHANGED
|
@@ -4,10 +4,35 @@ RepoSpend estimates API-equivalent cost from a local pricing table. The bundled
|
|
|
4
4
|
|
|
5
5
|
The bundled table is seeded from public OpenAI, Anthropic, Google, and GitHub Copilot model references and is expressed as USD per 1M tokens. Pricing changes over time, so treat RepoSpend costs as API-equivalent estimates rather than invoice-grade accounting.
|
|
6
6
|
|
|
7
|
-
The
|
|
7
|
+
The October 17, 2026 update checks Claude Haiku 5.5, Sonnet 5.5, and Gemini 4 Argon against provider documentation. The GPT-6.1 Sol card was checked on September 29; the other bundled defaults retain the September 28 snapshot. Defaults use published Standard API prices. Sonnet 5.5 cache reads fell from $0.20 to $0.10 per 1M tokens on October 7; its $2 input, $10 output, $2.50 5-minute writes, and $4 1-hour writes are unchanged. Sonnet 5 retains its $0.20 cache-read rate.
|
|
8
|
+
|
|
9
|
+
### Claude Haiku 5.5 and request-length pricing
|
|
10
|
+
|
|
11
|
+
All rates are USD per 1M tokens, using Anthropic's global Standard API prices:
|
|
12
|
+
|
|
13
|
+
| Prompt length per request | Input | Cache reads | 5m writes | 1h writes | Output |
|
|
14
|
+
| --- | ---: | ---: | ---: | ---: | ---: |
|
|
15
|
+
| Up to and including 100,000 tokens | $0.10 | $0.01 | $0.125 | $0.20 | $0.50 |
|
|
16
|
+
| Over 100,000 tokens | $0.50 | $0.05 | $0.625 | $1 | $2.50 |
|
|
17
|
+
|
|
18
|
+
Prompt length includes uncached input, cache reads, and cache writes. The higher rates apply to the whole qualifying request, not just tokens above 100K. Multiple short requests keep the lower rates even when combined session input exceeds 100K. Claude's deduplicated usage events and Copilot chat/inference records are priced individually, then their unrounded costs are summed before rounding the session estimate once.
|
|
19
|
+
|
|
20
|
+
Settings exposes `claude-haiku-5-5` for the lower tier and `claude-haiku-5-5-long-context` for the higher tier. The latter is a RepoSpend rate card, not a provider model ID; both can be edited separately. The higher-tier card appears with used Haiku models. Editing an inherited Haiku snapshot updates the shared base card and retains automatic tier selection. Use Add model to intentionally create an exact custom snapshot with flat rates; such overrides remain authoritative. Haiku usage without a known request length (including aggregate-only Copilot, Codex, or experimental Cursor totals) stays unpriced unless an explicit custom flat snapshot card or recorded Cursor cost is available. Pricing triage distinguishes missing request lengths from missing rates and exposes any unpriced auxiliary request models. Unknown fast-mode cards remain unpriced.
|
|
21
|
+
|
|
22
|
+
These are current API-equivalent rates applied to the selected usage window, not historical date-effective billing. The Sonnet reduction does not claim that pre-October 7 API requests were billed at the new price. Sources: [Anthropic pricing](https://platform.claude.com/docs/en/about-claude/pricing), [October 7 announcement](https://www.anthropic.com/claude-haiku-5-5).
|
|
23
|
+
|
|
24
|
+
### Gemini 4 Argon introductory rates
|
|
25
|
+
|
|
26
|
+
`gemini-4-argon`, including Copilot-prefixed/suffixed aliases, uses $2 input, $0.10 cached input, and $10 output (including thinking) per 1M tokens through November 30, 2026. Google lists $4 input, $0.20 cached input, and $20 output from December 1. Argon has no explicit cache-write charge. Bundled rates are a verified snapshot: the application does not silently switch prices based on the machine clock. Refresh the table at the promotion boundary or save intentional overrides. Source: [Google's model and pricing guide](https://ai.google.dev/gemini-api/docs/latest-model?hl=en).
|
|
8
27
|
|
|
9
28
|
GPT-6 Astra, Sol, and Luna use OpenAI's Standard short-context rates. Their long-context requests above 272,000 input tokens use different rates, and local session totals do not identify every request's pricing tier. Fast, batch, and regional processing can also differ from these defaults. RepoSpend keeps the result labeled as an API-equivalent estimate.
|
|
10
29
|
|
|
30
|
+
### GPT-6.1 Sol (September 29, 2026)
|
|
31
|
+
|
|
32
|
+
The explicit `gpt-6.1-sol` card uses $2 input, $0.10 cached input, $2.50 cache writes, and $10 output/reasoning per 1M tokens, verified against [OpenAI's model reference](https://developers.openai.com/api/docs/models/gpt-6.1-sol) on September 29. GPT-6 Sol remains separate at $0.20 for cached input. Case-insensitive and Copilot-prefixed IDs resolve to the same card; terminal snapshot dates preserve the model generation. Snapshot support is defensive parsing, not a claim that OpenAI publishes those snapshot IDs. Custom exact-ID overrides continue to take precedence.
|
|
33
|
+
|
|
34
|
+
Above 272K input tokens per request, GPT-6.1 Sol's Standard rates become $4 input, $0.20 cached input, $5 cache writes, and $15 output per 1M tokens. Fast costs twice Standard; Batch and Flex cost half Standard. RepoSpend's default estimate uses Standard short-context pricing because aggregate local usage cannot reliably identify these modifiers for every request. See the [GPT-6.1 Sol pricing and Codex tracking guide](https://repospend.com/guides/gpt-6-1-sol-pricing) for a worked example.
|
|
35
|
+
|
|
11
36
|
Claude Fable 5.1 and Mythos 5.1 retain their predecessor's base rates but have lower cache-read pricing. Claude Opus 5.5 has its own lower base and cache rates. These model rows use Anthropic's global Standard rates.
|
|
12
37
|
|
|
13
38
|
OpenAI reduced GPT-5.6 pricing effective July 30, 2026. RepoSpend uses $2 input and $12 output per 1M tokens for Terra, and $0.20 input and $1.20 output for Luna. Cached input remains 90% below the uncached input rate, and cache writes are billed at 1.25x the uncached input rate, so Luna's bundled cache-write rate is $0.25 per 1M tokens.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "repospend",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "Local-first dashboard for tracking AI coding token usage and API-equivalent spend by repository, session, model, and tool.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Mehmet Mustafa Demir",
|