repospend 0.1.1 → 0.1.3

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 CHANGED
@@ -2,6 +2,22 @@
2
2
 
3
3
  All notable changes to RepoSpend will be documented in this file.
4
4
 
5
+ ## 0.1.3
6
+
7
+ - Correct GPT-5.6 Terra and Luna API-equivalent pricing to the reduced July 30, 2026 OpenAI rates, including cached-input and cache-write rates.
8
+ - Migrate legacy full pricing files so the new Terra and Luna defaults take effect while preserving sparse user overrides and custom model rows.
9
+ - Improve unverified repo and folder grouping by using the outermost project marker below a safe shared-folder boundary, keeping nested non-Git workspace paths together without collapsing them into broad folders such as `Desktop`.
10
+ - Show paths relative to the home directory for unverified workspace labels so similarly named folders such as `src` remain distinguishable.
11
+
12
+ ## 0.1.2
13
+
14
+ - Add bundled GPT-5.6 API-equivalent pricing for the Sol, Terra, and Luna tiers, including cache-write and cached-input rates.
15
+ - Add bundled Claude Sonnet 5 introductory pricing through August 31, 2026, with dated model ID family pricing and a note for the standard September 1, 2026 rate.
16
+ - Add Claude Opus 4.8 fast mode pricing and keep special fast-mode rate cards separate from regular Opus family fallback.
17
+ - Add GitHub Copilot pricing coverage for MAI-Code-1-Flash and Kimi K2.7 Code, including suffix variant matching for local Copilot model IDs.
18
+ - Add the OpenAI GPT-5.6 preview pricing source to the bundled pricing metadata shown in Settings.
19
+ - Ignore local generated `marketing/` assets so release diffs stay focused on source, docs, and packaged files.
20
+
5
21
  ## 0.1.1
6
22
 
7
23
  - Add bundled Claude Fable 5 and Claude Mythos 5 API-equivalent pricing, including dated model ID family pricing and future Fable/Mythos version fallback.
package/README.md CHANGED
@@ -125,7 +125,7 @@ RepoSpend helps you break down local AI coding usage by:
125
125
  - input, cached input, output, and reasoning token shape
126
126
  - estimated API-equivalent cost
127
127
 
128
- Nested paths are grouped by Git root so usage rolls up to the repository.
128
+ Nested paths are grouped by Git root so usage rolls up to the repository. When no Git root is available, RepoSpend uses the outermost project marker below a safe shared-folder boundary, such as `package.json`, and keeps the grouping visibly unverified.
129
129
 
130
130
  ## Screenshots
131
131
 
package/dist/cli.js CHANGED
@@ -235,11 +235,13 @@ function claudePricingFamilyModel(model, isUsable = () => true) {
235
235
  const families = [
236
236
  "claude-fable-5",
237
237
  "claude-mythos-5",
238
+ "claude-opus-4-8-fast-mode",
238
239
  "claude-opus-4-7",
239
240
  "claude-opus-4-6",
240
241
  "claude-opus-4-5",
241
242
  "claude-opus-4-1",
242
243
  "claude-opus-4",
244
+ "claude-sonnet-5",
243
245
  "claude-sonnet-4-6",
244
246
  "claude-sonnet-4-5",
245
247
  "claude-sonnet-4",
@@ -262,6 +264,8 @@ function copilotPricingFamilyModel(model, isUsable = () => true) {
262
264
  if ((normalized === "raptor-mini" || normalized.startsWith("raptor-mini-") || normalized.startsWith("oswe-vscode")) && isUsable("raptor-mini")) return "raptor-mini";
263
265
  if ((normalized === "lark" || normalized.startsWith("lark-")) && isUsable("lark")) return "lark";
264
266
  if ((normalized === "goldeneye" || normalized.startsWith("goldeneye-")) && isUsable("goldeneye")) return "goldeneye";
267
+ if ((normalized === "mai-code-1-flash" || normalized.startsWith("mai-code-1-flash-")) && isUsable("mai-code-1-flash")) return "mai-code-1-flash";
268
+ if ((normalized === "kimi-k2.7-code" || normalized.startsWith("kimi-k2.7-code-")) && isUsable("kimi-k2.7-code")) return "kimi-k2.7-code";
265
269
  return void 0;
266
270
  }
267
271
  function parseVersionedModel(normalized) {
@@ -292,7 +296,7 @@ function versionedFallbackModel(model, knownModels, isUsable = () => true) {
292
296
  }
293
297
  function isCopilotAliasModel(model) {
294
298
  const normalized = normalizePricingModelId(model);
295
- return normalized.startsWith("raptor-mini") || normalized.startsWith("oswe-vscode") || normalized === "lark" || normalized.startsWith("lark-") || normalized.startsWith("goldeneye");
299
+ return normalized.startsWith("raptor-mini") || normalized.startsWith("oswe-vscode") || normalized === "lark" || normalized.startsWith("lark-") || normalized.startsWith("goldeneye") || normalized.startsWith("mai-code-1-flash") || normalized.startsWith("kimi-k2.7-code");
296
300
  }
297
301
  function positiveRate(value) {
298
302
  return typeof value === "number" && Number.isFinite(value) && value > 0;
@@ -319,14 +323,20 @@ var pricingInfo = {
319
323
  sourceUrl: "https://developers.openai.com/api/docs/pricing",
320
324
  sourceUrls: [
321
325
  { label: "OpenAI pricing reference", url: "https://developers.openai.com/api/docs/pricing" },
326
+ { label: "OpenAI GPT-5.6 preview pricing", url: "https://openai.com/index/previewing-gpt-5-6-sol/" },
327
+ { label: "OpenAI GPT-5.6 price update", url: "https://openai.com/index/advancing-the-price-performance-frontier-with-gpt-5-6/" },
322
328
  { label: "Claude pricing reference", url: "https://platform.claude.com/docs/en/about-claude/pricing" },
323
329
  { label: "GitHub Copilot model pricing reference", url: "https://docs.github.com/en/copilot/reference/copilot-billing/models-and-pricing" }
324
330
  ],
325
331
  unit: "USD per 1M tokens",
326
- updatedAt: "2026-06-10",
327
- note: "RepoSpend estimates API-equivalent cost from local token counts and public API-style Standard pricing. This is not your actual bill; subscriptions, credits, provider terms, cache behavior, regional processing, or other billing factors can make your real cost different."
332
+ updatedAt: "2026-07-30",
333
+ note: "RepoSpend estimates API-equivalent cost from local token counts and public API-style Standard pricing. GPT-5.6 Terra and Luna use the reduced OpenAI API rates effective July 30, 2026. This is not your actual bill; subscriptions, credits, provider terms, cache behavior, regional processing, or other billing factors can make your real cost different."
328
334
  };
329
335
  var defaultPricing = {
336
+ "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." },
337
+ "gpt-5.6-sol": { inputPerMillion: 5, cachedInputPerMillion: 0.5, cacheCreationInputPerMillion: 6.25, outputPerMillion: 30, reasoningOutputPerMillion: 30 },
338
+ "gpt-5.6-terra": { inputPerMillion: 2, cachedInputPerMillion: 0.2, cacheCreationInputPerMillion: 2.5, outputPerMillion: 12, reasoningOutputPerMillion: 12, note: "GPT-5.6 Terra reduced API pricing effective July 30, 2026. Cache reads are 90% below input and cache writes are 1.25x input." },
339
+ "gpt-5.6-luna": { inputPerMillion: 0.2, cachedInputPerMillion: 0.02, cacheCreationInputPerMillion: 0.25, outputPerMillion: 1.2, reasoningOutputPerMillion: 1.2, note: "GPT-5.6 Luna reduced API pricing effective July 30, 2026. Cache reads are 90% below input and cache writes are 1.25x input." },
330
340
  "gpt-5.5": { inputPerMillion: 5, cachedInputPerMillion: 0.5, outputPerMillion: 30, reasoningOutputPerMillion: 30 },
331
341
  "gpt-5.5-pro": { inputPerMillion: 30, outputPerMillion: 180, reasoningOutputPerMillion: 180 },
332
342
  "gpt-5.4": { inputPerMillion: 2.5, cachedInputPerMillion: 0.25, outputPerMillion: 15, reasoningOutputPerMillion: 15 },
@@ -358,32 +368,63 @@ var defaultPricing = {
358
368
  "oswe-vscode-prime": { inputPerMillion: 0.25, cachedInputPerMillion: 0.025, outputPerMillion: 2, note: "GitHub Copilot Raptor mini internal model id." },
359
369
  "lark": { inputPerMillion: 0.25, cachedInputPerMillion: 0.025, outputPerMillion: 2, note: "GitHub Copilot preview model; estimated with lightweight Copilot pricing." },
360
370
  "goldeneye": { inputPerMillion: 1.25, cachedInputPerMillion: 0.125, outputPerMillion: 10, note: "GitHub Copilot fine-tuned model using GPT-5.1-Codex pricing." },
371
+ "mai-code-1-flash": { inputPerMillion: 0.75, cachedInputPerMillion: 0.075, outputPerMillion: 4.5, note: "GitHub Copilot supported Microsoft model; API-equivalent estimate, not a Copilot bill." },
372
+ "kimi-k2.7-code": { inputPerMillion: 0.95, cachedInputPerMillion: 0.19, outputPerMillion: 4, note: "GitHub Copilot supported Moonshot AI model; API-equivalent estimate, not a Copilot bill." },
361
373
  "claude-fable-5": { inputPerMillion: 10, cacheCreationInput5mPerMillion: 12.5, cacheCreationInput1hPerMillion: 20, cacheCreationInputPerMillion: 20, cachedInputPerMillion: 1, outputPerMillion: 50 },
362
374
  "claude-mythos-5": { inputPerMillion: 10, cacheCreationInput5mPerMillion: 12.5, cacheCreationInput1hPerMillion: 20, cacheCreationInputPerMillion: 20, cachedInputPerMillion: 1, outputPerMillion: 50, note: "Limited availability Anthropic model; same public API-equivalent pricing as Claude Fable 5." },
363
375
  "claude-opus-4-8": { inputPerMillion: 5, cacheCreationInput5mPerMillion: 6.25, cacheCreationInput1hPerMillion: 10, cacheCreationInputPerMillion: 10, cachedInputPerMillion: 0.5, outputPerMillion: 25 },
376
+ "claude-opus-4-8-fast-mode": { inputPerMillion: 10, cacheCreationInput5mPerMillion: 12.5, cacheCreationInput1hPerMillion: 20, cacheCreationInputPerMillion: 12.5, cachedInputPerMillion: 1, outputPerMillion: 50, note: "Claude Opus 4.8 fast mode research preview pricing. Prompt caching multipliers apply on top of fast mode pricing." },
364
377
  "claude-opus-4-7": { inputPerMillion: 5, cacheCreationInput5mPerMillion: 6.25, cacheCreationInput1hPerMillion: 10, cacheCreationInputPerMillion: 10, cachedInputPerMillion: 0.5, outputPerMillion: 25 },
365
378
  "claude-opus-4-6": { inputPerMillion: 5, cacheCreationInput5mPerMillion: 6.25, cacheCreationInput1hPerMillion: 10, cacheCreationInputPerMillion: 10, cachedInputPerMillion: 0.5, outputPerMillion: 25 },
366
379
  "claude-opus-4-6-fast-mode": { inputPerMillion: 0, cacheCreationInput5mPerMillion: 0, cacheCreationInput1hPerMillion: 0, cacheCreationInputPerMillion: 0, cachedInputPerMillion: 0, outputPerMillion: 0, note: "GitHub Copilot supported model, but public per-token pricing is not listed separately. RepoSpend leaves API-equivalent pricing unset." },
367
380
  "claude-opus-4-5": { inputPerMillion: 5, cacheCreationInput5mPerMillion: 6.25, cacheCreationInput1hPerMillion: 10, cacheCreationInputPerMillion: 10, cachedInputPerMillion: 0.5, outputPerMillion: 25 },
368
381
  "claude-opus-4-1": { inputPerMillion: 15, cacheCreationInput5mPerMillion: 18.75, cacheCreationInput1hPerMillion: 30, cacheCreationInputPerMillion: 30, cachedInputPerMillion: 1.5, outputPerMillion: 75 },
369
382
  "claude-opus-4": { inputPerMillion: 15, cacheCreationInput5mPerMillion: 18.75, cacheCreationInput1hPerMillion: 30, cacheCreationInputPerMillion: 30, cachedInputPerMillion: 1.5, outputPerMillion: 75 },
383
+ "claude-sonnet-5": { inputPerMillion: 2, cacheCreationInput5mPerMillion: 2.5, cacheCreationInput1hPerMillion: 4, cacheCreationInputPerMillion: 4, cachedInputPerMillion: 0.2, outputPerMillion: 10, note: "Anthropic introductory pricing through August 31, 2026. Standard pricing from September 1, 2026 is $3 input / $15 output per 1M tokens." },
370
384
  "claude-sonnet-4-6": { inputPerMillion: 3, cacheCreationInput5mPerMillion: 3.75, cacheCreationInput1hPerMillion: 6, cacheCreationInputPerMillion: 6, cachedInputPerMillion: 0.3, outputPerMillion: 15 },
371
385
  "claude-sonnet-4-5": { inputPerMillion: 3, cacheCreationInput5mPerMillion: 3.75, cacheCreationInput1hPerMillion: 6, cacheCreationInputPerMillion: 6, cachedInputPerMillion: 0.3, outputPerMillion: 15 },
372
386
  "claude-sonnet-4": { inputPerMillion: 3, cacheCreationInput5mPerMillion: 3.75, cacheCreationInput1hPerMillion: 6, cacheCreationInputPerMillion: 6, cachedInputPerMillion: 0.3, outputPerMillion: 15 },
373
387
  "claude-haiku-4-5": { inputPerMillion: 1, cacheCreationInput5mPerMillion: 1.25, cacheCreationInput1hPerMillion: 2, cacheCreationInputPerMillion: 2, cachedInputPerMillion: 0.1, outputPerMillion: 5 },
374
388
  "claude-3-5-haiku": { inputPerMillion: 0.8, cacheCreationInput5mPerMillion: 1, cacheCreationInput1hPerMillion: 1.6, cacheCreationInputPerMillion: 1.6, cachedInputPerMillion: 0.08, outputPerMillion: 4 }
375
389
  };
390
+ var legacyBundledPricing = {
391
+ "gpt-5.6-terra": { inputPerMillion: 2.5, cachedInputPerMillion: 0.25, cacheCreationInputPerMillion: 3.125, outputPerMillion: 15, reasoningOutputPerMillion: 15 },
392
+ "gpt-5.6-luna": { inputPerMillion: 1, cachedInputPerMillion: 0.1, cacheCreationInputPerMillion: 1.25, outputPerMillion: 6, reasoningOutputPerMillion: 6 }
393
+ };
376
394
  function loadPricingTable(pricingPath) {
377
395
  if (!pricingPath) {
378
396
  return defaultPricing;
379
397
  }
380
398
  try {
381
399
  const resolved = path.resolve(pricingPath);
382
- return { ...defaultPricing, ...JSON.parse(fs.readFileSync(resolved, "utf8")) };
400
+ const stored = JSON.parse(fs.readFileSync(resolved, "utf8"));
401
+ return { ...defaultPricing, ...migrateLegacyBundledPricing(stored) };
383
402
  } catch {
384
403
  return defaultPricing;
385
404
  }
386
405
  }
406
+ function pricingOverrides(pricing) {
407
+ return Object.fromEntries(
408
+ Object.entries(pricing).filter(([model, modelPricing]) => {
409
+ const bundled = defaultPricing[model];
410
+ return !bundled || !pricingEntriesEqual(modelPricing, bundled);
411
+ })
412
+ );
413
+ }
414
+ function migrateLegacyBundledPricing(stored) {
415
+ const isLegacyFullTable = Object.keys(defaultPricing).every((model) => Object.hasOwn(stored, model));
416
+ if (!isLegacyFullTable) return stored;
417
+ const migrated = { ...stored };
418
+ for (const [model, legacyPricing] of Object.entries(legacyBundledPricing)) {
419
+ if (pricingEntriesEqual(migrated[model], legacyPricing)) delete migrated[model];
420
+ }
421
+ return pricingOverrides(migrated);
422
+ }
423
+ function pricingEntriesEqual(left, right) {
424
+ if (!left || !right) return left === right;
425
+ const keys = /* @__PURE__ */ new Set([...Object.keys(left), ...Object.keys(right)]);
426
+ return [...keys].every((key) => left[key] === right[key]);
427
+ }
387
428
  function resolvePricingPath(config = {}) {
388
429
  return config.pricingPath ? path.resolve(repospendHome(), config.pricingPath) : path.join(repospendHome(), "pricing.json");
389
430
  }
@@ -1222,6 +1263,7 @@ function isDashboardVisibleSession(session) {
1222
1263
 
1223
1264
  // packages/core/src/repo.ts
1224
1265
  import fs4 from "node:fs";
1266
+ import os2 from "node:os";
1225
1267
  import path4 from "node:path";
1226
1268
  function normalizeRoot(p) {
1227
1269
  const stripped = p.startsWith("\\\\?\\") ? p.slice(4) : p;
@@ -1251,9 +1293,9 @@ function findGitRoot(cwd, fileSystem = fs4) {
1251
1293
  function resolveRepoInfo(cwd, config = {}, fileSystem = fs4) {
1252
1294
  const warnings = [];
1253
1295
  const gitRoot = safeFindGitRoot(cwd, fileSystem);
1254
- const repoRoot = gitRoot ?? fallbackWorkspaceRoot(cwd);
1296
+ const repoRoot = gitRoot ?? fallbackWorkspaceRoot(cwd, fileSystem);
1255
1297
  const alias = aliasForPath(repoRoot, config);
1256
- const repoName = alias ?? (path4.basename(repoRoot) || "unknown-workspace");
1298
+ const repoName = alias ?? (gitRoot ? path4.basename(repoRoot) : fallbackWorkspaceLabel(repoRoot));
1257
1299
  const gitMeta = gitRoot ? readGitMetadata(gitRoot, fileSystem) : { remote: void 0, branch: void 0 };
1258
1300
  if (!gitRoot) {
1259
1301
  warnings.push("repo_unverified_no_git_root");
@@ -1274,16 +1316,59 @@ function safeFindGitRoot(cwd, fileSystem) {
1274
1316
  return void 0;
1275
1317
  }
1276
1318
  }
1277
- function fallbackWorkspaceRoot(cwd) {
1319
+ var workspaceMarkers = [
1320
+ "package.json",
1321
+ "pyproject.toml",
1322
+ "Cargo.toml",
1323
+ "go.mod",
1324
+ "mix.exs",
1325
+ "composer.json",
1326
+ "Gemfile",
1327
+ "pom.xml",
1328
+ "build.gradle",
1329
+ "Package.swift",
1330
+ "CMakeLists.txt"
1331
+ ];
1332
+ var fallbackWorkspaceCache = /* @__PURE__ */ new Map();
1333
+ function fallbackWorkspaceRoot(cwd, fileSystem = fs4) {
1278
1334
  const resolved = normalizeRoot(path4.resolve(cwd || process.cwd()));
1279
- const home = process.env.HOME ? normalizeRoot(path4.resolve(process.env.HOME)) : void 0;
1280
- if (home && (resolved === home || resolved.startsWith(`${home}${path4.sep}`))) {
1281
- const relative = path4.relative(home, resolved).split(path4.sep).filter(Boolean);
1282
- const first = relative[0];
1283
- return first ? path4.join(home, first) : home;
1335
+ if (fileSystem === fs4) {
1336
+ const cached = fallbackWorkspaceCache.get(resolved);
1337
+ if (cached) return cached;
1338
+ }
1339
+ const root = findWorkspaceMarkerRoot(resolved, fileSystem) ?? resolved;
1340
+ if (fileSystem === fs4) fallbackWorkspaceCache.set(resolved, root);
1341
+ return root;
1342
+ }
1343
+ function findWorkspaceMarkerRoot(start, fileSystem) {
1344
+ const home = normalizeRoot(path4.resolve(os2.homedir()));
1345
+ const boundary = isWithin(start, home) ? home : path4.parse(start).root;
1346
+ let candidate;
1347
+ let current = start;
1348
+ while (true) {
1349
+ if (current !== boundary && isAllowedMarkerRoot(current, boundary) && workspaceMarkers.some((marker) => fileSystem.existsSync(path4.join(current, marker)))) {
1350
+ candidate = current;
1351
+ }
1352
+ if (current === boundary) return candidate;
1353
+ const parent = path4.dirname(current);
1354
+ if (parent === current) return candidate;
1355
+ current = parent;
1356
+ }
1357
+ }
1358
+ function isAllowedMarkerRoot(candidate, boundary) {
1359
+ const relative = path4.relative(boundary, candidate).split(path4.sep).filter(Boolean);
1360
+ return relative.length > 1;
1361
+ }
1362
+ function isWithin(candidate, parent) {
1363
+ return candidate === parent || candidate.startsWith(`${parent}${path4.sep}`);
1364
+ }
1365
+ function fallbackWorkspaceLabel(repoRoot) {
1366
+ const home = normalizeRoot(path4.resolve(os2.homedir()));
1367
+ const relativeToHome = path4.relative(home, repoRoot);
1368
+ if (relativeToHome && !relativeToHome.startsWith("..") && !path4.isAbsolute(relativeToHome)) {
1369
+ return relativeToHome.split(path4.sep).filter(Boolean).join("/");
1284
1370
  }
1285
- const parts = resolved.split(path4.sep).filter(Boolean);
1286
- return `${path4.sep}${parts.slice(0, Math.min(parts.length, 3)).join(path4.sep)}`;
1371
+ return path4.basename(repoRoot) || "unknown-workspace";
1287
1372
  }
1288
1373
  function readGitMetadata(repoRoot, fileSystem) {
1289
1374
  const gitPath = path4.join(repoRoot, ".git");
@@ -1318,7 +1403,7 @@ function parseBranch(head) {
1318
1403
  // packages/core/src/sources/codex.ts
1319
1404
  import { spawnSync } from "node:child_process";
1320
1405
  import fs5 from "node:fs";
1321
- import os2 from "node:os";
1406
+ import os3 from "node:os";
1322
1407
  import path5 from "node:path";
1323
1408
  import { fileURLToPath } from "node:url";
1324
1409
  import Database from "better-sqlite3";
@@ -1843,7 +1928,7 @@ function numberFromKeys(object, keys) {
1843
1928
  var codexSessionCacheVersion = "codex-session-v1";
1844
1929
  var nativeSqliteRebuildAttempted = false;
1845
1930
  function scanCodex(options) {
1846
- const codexHome = options.codexHome ?? path5.join(os2.homedir(), ".codex");
1931
+ const codexHome = options.codexHome ?? path5.join(os3.homedir(), ".codex");
1847
1932
  const statePath = path5.join(codexHome, "state_5.sqlite");
1848
1933
  const sessionsPath = path5.join(codexHome, "sessions");
1849
1934
  const configPath2 = path5.join(codexHome, "config.toml");
@@ -1925,7 +2010,7 @@ function readThreads(statePath, sessionFiles, options, warnings) {
1925
2010
  warnings.push("Codex threads table has no recognized columns.");
1926
2011
  return [];
1927
2012
  }
1928
- const importedModels = readImportedModelMap(options.codexHome ?? path5.join(os2.homedir(), ".codex"), warnings);
2013
+ const importedModels = readImportedModelMap(options.codexHome ?? path5.join(os3.homedir(), ".codex"), warnings);
1929
2014
  const rows = db.prepare(`SELECT ${selectedColumns.map((column) => `"${column}"`).join(", ")} FROM threads`).all().filter((row) => rowMatchesScanWindow(row, options.scanWindow));
1930
2015
  const sessions = rows.map((row, index) => threadToUsage(row, index, sessionFiles, options, importedModels));
1931
2016
  return attributeSubagentsToParentSurfaces(sessions, rows);
@@ -2082,7 +2167,7 @@ function threadToUsage(row, index, sessionFiles, options, importedModels = /* @_
2082
2167
  messageCount: sessionBreakdown.messageCount,
2083
2168
  rawTokenTotal: dbTokens || sessionBreakdown.totalTokens || void 0,
2084
2169
  warnings,
2085
- codexHome: options.codexHome ?? path5.join(os2.homedir(), ".codex"),
2170
+ codexHome: options.codexHome ?? path5.join(os3.homedir(), ".codex"),
2086
2171
  durationMs: durationMs(startedAt, endedAt),
2087
2172
  rawEventCount: sessionBreakdown.rawEventCount,
2088
2173
  parseStatus: sessionBreakdown.parseStatus,
@@ -2156,7 +2241,7 @@ function readStandaloneSessions(sessionFiles, options) {
2156
2241
  messageCount: breakdown.messageCount,
2157
2242
  rawTokenTotal: breakdown.totalTokens || void 0,
2158
2243
  warnings: [...repo.warnings, ...breakdown.warnings],
2159
- codexHome: options.codexHome ?? path5.join(os2.homedir(), ".codex"),
2244
+ codexHome: options.codexHome ?? path5.join(os3.homedir(), ".codex"),
2160
2245
  durationMs: durationMs(breakdown.startedAt, breakdown.endedAt),
2161
2246
  rawEventCount: breakdown.rawEventCount,
2162
2247
  parseStatus: breakdown.parseStatus,
@@ -2667,7 +2752,7 @@ function errorMessage(error) {
2667
2752
 
2668
2753
  // packages/core/src/sources/claude.ts
2669
2754
  import fs6 from "node:fs";
2670
- import os3 from "node:os";
2755
+ import os4 from "node:os";
2671
2756
  import path6 from "node:path";
2672
2757
  function scanClaude(options) {
2673
2758
  const claudeHome = options.claudeHome ?? defaultClaudeHome();
@@ -2721,7 +2806,7 @@ function scanClaude(options) {
2721
2806
  function discoverClaudeSessionFiles(claudeHome, warnings, explicitHome) {
2722
2807
  const files = [];
2723
2808
  const projectDirs = /* @__PURE__ */ new Set();
2724
- const projectsPaths = explicitHome ? [path6.join(claudeHome, "projects")] : unique3([...configuredClaudeHomes(claudeHome).map((root) => path6.join(root, "projects")), path6.join(os3.homedir(), ".config", "claude", "projects")]);
2809
+ const projectsPaths = explicitHome ? [path6.join(claudeHome, "projects")] : unique3([...configuredClaudeHomes(claudeHome).map((root) => path6.join(root, "projects")), path6.join(os4.homedir(), ".config", "claude", "projects")]);
2725
2810
  for (const projectsPath of projectsPaths) {
2726
2811
  collectProjectFiles(projectsPath, files, projectDirs, warnings);
2727
2812
  }
@@ -3235,10 +3320,10 @@ function claudeSourceAppLabel(entrypoint) {
3235
3320
  return "Claude Code";
3236
3321
  }
3237
3322
  function defaultClaudeHome() {
3238
- return process.env.CLAUDE_CONFIG_DIR?.split(",").map((item) => item.trim()).filter(Boolean)[0] ?? path6.join(os3.homedir(), ".claude");
3323
+ return process.env.CLAUDE_CONFIG_DIR?.split(",").map((item) => item.trim()).filter(Boolean)[0] ?? path6.join(os4.homedir(), ".claude");
3239
3324
  }
3240
3325
  function defaultDesktopSessionRoots() {
3241
- const home = os3.homedir();
3326
+ const home = os4.homedir();
3242
3327
  const xdg = process.env.XDG_CONFIG_HOME || path6.join(home, ".config");
3243
3328
  return [
3244
3329
  path6.join(home, "Library", "Application Support", "Claude", "local-agent-mode-sessions"),
@@ -3329,12 +3414,12 @@ function safeMtimeMs(filePath) {
3329
3414
 
3330
3415
  // packages/core/src/sources/copilot.ts
3331
3416
  import fs7 from "node:fs";
3332
- import os4 from "node:os";
3417
+ import os5 from "node:os";
3333
3418
  import path7 from "node:path";
3334
3419
  var maxJsonlBytes = 50 * 1024 * 1024;
3335
3420
  var copilotOtelEnv = "COPILOT_OTEL_FILE_EXPORTER_PATH";
3336
3421
  function scanCopilot(options) {
3337
- const copilotHome = options.copilotHome ?? path7.join(os4.homedir(), ".copilot");
3422
+ const copilotHome = options.copilotHome ?? path7.join(os5.homedir(), ".copilot");
3338
3423
  const discovery = discoverCopilotFiles(copilotHome, Boolean(options.copilotHome), options.codeUserRoots);
3339
3424
  const files = discovery.files.filter((file) => fileMayOverlapScanWindow2(file.filePath, options.scanWindow));
3340
3425
  const sessionMap = /* @__PURE__ */ new Map();
@@ -4003,7 +4088,7 @@ function timestampMs2(value) {
4003
4088
  return iso ? Date.parse(iso) : void 0;
4004
4089
  }
4005
4090
  function defaultCodeUserRoots() {
4006
- const home = os4.homedir();
4091
+ const home = os5.homedir();
4007
4092
  if (process.platform === "win32") {
4008
4093
  const appData = process.env.APPDATA ?? path7.join(home, "AppData", "Roaming");
4009
4094
  return ["Code", "Code - Insiders", "VSCodium"].map((name) => path7.join(appData, name, "User"));
@@ -4138,7 +4223,7 @@ function errorMessage3(error) {
4138
4223
 
4139
4224
  // packages/core/src/sources/cursor.ts
4140
4225
  import fs8 from "node:fs";
4141
- import os5 from "node:os";
4226
+ import os6 from "node:os";
4142
4227
  import path8 from "node:path";
4143
4228
  import Database2 from "better-sqlite3";
4144
4229
  var parserVersion = "cursor-v1";
@@ -4147,7 +4232,7 @@ var maxDatabaseBytes = 100 * 1024 * 1024;
4147
4232
  var cursorStoragePrefixes = ["cursor.", "anysphere."];
4148
4233
  var interestingTerms = ["cursor", "composer", "aichat", "ai_chat", "aiservice", "agent-transcript", "prompttokenbreakdown"];
4149
4234
  function scanCursor(options) {
4150
- const cursorHome = options.cursorHome ?? path8.join(os5.homedir(), ".cursor");
4235
+ const cursorHome = options.cursorHome ?? path8.join(os6.homedir(), ".cursor");
4151
4236
  const discovery = discoverCursorFiles(cursorHome, Boolean(options.cursorHome));
4152
4237
  const jsonlFiles = discovery.jsonlFiles.filter((filePath) => fileMayOverlapScanWindow3(filePath, options.scanWindow));
4153
4238
  const databaseFiles = discovery.databaseFiles.filter((filePath) => fileMayOverlapScanWindow3(filePath, options.scanWindow));
@@ -4263,7 +4348,7 @@ function cursorOwnedChildDirs(root) {
4263
4348
  }
4264
4349
  }
4265
4350
  function defaultCursorAppPaths() {
4266
- const home = os5.homedir();
4351
+ const home = os6.homedir();
4267
4352
  if (process.platform === "win32") {
4268
4353
  const appData = process.env.APPDATA ?? path8.join(home, "AppData", "Roaming");
4269
4354
  const globalStoragePath2 = path8.join(appData, "Cursor", "User", "globalStorage");
@@ -5103,7 +5188,7 @@ function writeConfigData(nextConfig) {
5103
5188
  function writePricingData(models) {
5104
5189
  const config = loadConfig();
5105
5190
  const pricingPath = resolvePricingPath(config);
5106
- savePricingTable(pricingPath, models);
5191
+ savePricingTable(pricingPath, pricingOverrides(models));
5107
5192
  clearScanCache();
5108
5193
  return {
5109
5194
  path: pricingPath,
package/docs/pricing.md CHANGED
@@ -4,6 +4,14 @@ 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 bundled defaults use currently published standard API prices unless a provider has an active introductory API rate. For example, Claude Sonnet 5 uses Anthropic's $2 input and $10 output introductory rate through August 31, 2026, with a pricing-table note for the $3 input and $15 output standard rate that starts September 1, 2026.
8
+
9
+ 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.
10
+
11
+ The Settings page persists only custom or intentionally edited model rows. This lets future bundled rate updates flow through automatically. Older full pricing files are migrated for the GPT-5.6 Terra and Luna reductions when they still contain the previous bundled rates.
12
+
13
+ Some GitHub Copilot model rows are hosted or fine-tuned vendor models such as Raptor mini, MAI-Code-1-Flash, and Kimi K2.7 Code. RepoSpend prices those rows from GitHub's public per-token table as API-equivalent estimates, not as a Copilot invoice.
14
+
7
15
  For Claude models, RepoSpend uses Anthropic's cache-write TTL split when local
8
16
  Claude Code usage reports expose it. Tokens recorded under
9
17
  `cache_creation.ephemeral_5m_input_tokens` use the 5-minute cache-write rate, and
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "repospend",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
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",
@@ -46,7 +46,8 @@
46
46
  "clean": "pnpm -r clean && rm -rf dist web-dist",
47
47
  "rebuild:native": "pnpm rebuild better-sqlite3",
48
48
  "doctor:native": "node scripts/check-native.mjs",
49
- "media:capture": "node scripts/capture-release-media.mjs"
49
+ "media:capture": "node scripts/capture-release-media.mjs",
50
+ "media:producthunt": "node scripts/generate-producthunt-media.mjs"
50
51
  },
51
52
  "keywords": [
52
53
  "codex",
@@ -232,7 +232,7 @@ Error generating stack: `+w.message+`
232
232
  *
233
233
  * This source code is licensed under the ISC license.
234
234
  * See the LICENSE file in the root directory of this source tree.
235
- */const NI=qe("X",[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]]);function Qa(e){return e.toLowerCase().replace(/^github_copilot\//,"").replace(/^github-copilot\//,"").replace(/^copilot\//,"").replace(/claude-(opus|sonnet|haiku)-(\d+)\.(\d+)(?=$|[-.])/,"claude-$1-$2-$3")}function PP(e,t=()=>!0){const n=["claude-fable-5","claude-mythos-5","claude-opus-4-7","claude-opus-4-6","claude-opus-4-5","claude-opus-4-1","claude-opus-4","claude-sonnet-4-6","claude-sonnet-4-5","claude-sonnet-4","claude-haiku-4-5","claude-3-5-haiku"],r=Qa(e);if(r!=="claude-opus-4-6-fast-mode")return n.find(i=>(r===i||r.startsWith(`${i}-`)||r.startsWith(`${i}.`))&&t(i))}function AI(e,t=()=>!0){const n=Qa(e),r=PP(n,t);if(r)return r;if((n==="gpt-4.1"||n.startsWith("gpt-4.1-")||n.startsWith("gpt-41"))&&t("gpt-4.1"))return"gpt-4.1";if((n==="gemini-2.5-pro"||n.startsWith("gemini-2.5-pro-"))&&t("gemini-2.5-pro"))return"gemini-2.5-pro";if((n==="gemini-3-flash"||n.startsWith("gemini-3-flash-"))&&t("gemini-3-flash"))return"gemini-3-flash";if((n==="gemini-3.1-pro"||n.startsWith("gemini-3.1-pro-"))&&t("gemini-3.1-pro"))return"gemini-3.1-pro";if((n==="gemini-3.5-flash"||n.startsWith("gemini-3.5-flash-"))&&t("gemini-3.5-flash"))return"gemini-3.5-flash";if((n==="raptor-mini"||n.startsWith("raptor-mini-")||n.startsWith("oswe-vscode"))&&t("raptor-mini"))return"raptor-mini";if((n==="lark"||n.startsWith("lark-"))&&t("lark"))return"lark";if((n==="goldeneye"||n.startsWith("goldeneye-"))&&t("goldeneye"))return"goldeneye"}function rj(e){if(e.includes("fast-mode"))return;const t=e.match(/^(claude-(?:fable|mythos|opus|sonnet|haiku))-(\d+)(?:-(\d+))?/);if(t){const r=t[3]?Number(t[3]):0;return{tier:t[1],version:Number(t[2])+r/100}}const n=e.match(/^(gpt)-(\d)(?:\.(\d+))?(-[a-z][a-z0-9-]*)?$/);if(n){const r=n[3]?Number(n[3]):0;return{tier:`gpt${n[4]??""}`,version:Number(n[2])+r/100}}}function EI(e,t,n=()=>!0){const r=rj(Qa(e));if(!r)return;let i;for(const o of t){const u=rj(Qa(o));!u||u.tier!==r.tier||u.version>r.version||n(o)&&(!i||u.version>i.version)&&(i={id:o,version:u.version})}return i==null?void 0:i.id}function MI(e){const t=Qa(e);return t.startsWith("raptor-mini")||t.startsWith("oswe-vscode")||t==="lark"||t.startsWith("lark-")||t.startsWith("goldeneye")}function ij(e){return typeof e=="number"&&Number.isFinite(e)&&e>0}function Ba(e){return ij(e==null?void 0:e.inputPerMillion)&&ij(e==null?void 0:e.outputPerMillion)}function zx(e,t){const n=Qa(e),r=t[e]?e:t[n]?n:void 0,i=r?t[r]:void 0;if(Ba(i))return{pricing:i,sourceModel:r,inherited:!1};const o=EI(n,Object.keys(t),f=>Ba(t[f]));if(o)return{pricing:t[o],sourceModel:o,inherited:o!==e&&o!==n};const u=PP(n,f=>Ba(t[f]));if(u)return{pricing:t[u],sourceModel:u,inherited:u!==e&&u!==n};const c=AI(n,f=>Ba(t[f]));return c?{pricing:t[c],sourceModel:c,inherited:c!==e&&c!==n}:{pricing:i??{inputPerMillion:0,cacheCreationInputPerMillion:0,cachedInputPerMillion:0,outputPerMillion:0,reasoningOutputPerMillion:0},sourceModel:r,inherited:!1}}function NP(e){var t,n,r="";if(typeof e=="string"||typeof e=="number")r+=e;else if(typeof e=="object")if(Array.isArray(e)){var i=e.length;for(t=0;t<i;t++)e[t]&&(n=NP(e[t]))&&(r&&(r+=" "),r+=n)}else for(n in e)e[n]&&(r&&(r+=" "),r+=n);return r}function Be(){for(var e,t,n=0,r="",i=arguments.length;n<i;n++)(e=arguments[n])&&(t=NP(e))&&(r&&(r+=" "),r+=t);return r}var sp,aj;function dn(){if(aj)return sp;aj=1;var e=Array.isArray;return sp=e,sp}var lp,oj;function AP(){if(oj)return lp;oj=1;var e=typeof ec=="object"&&ec&&ec.Object===Object&&ec;return lp=e,lp}var up,sj;function mr(){if(sj)return up;sj=1;var e=AP(),t=typeof self=="object"&&self&&self.Object===Object&&self,n=e||t||Function("return this")();return up=n,up}var cp,lj;function Ml(){if(lj)return cp;lj=1;var e=mr(),t=e.Symbol;return cp=t,cp}var dp,uj;function II(){if(uj)return dp;uj=1;var e=Ml(),t=Object.prototype,n=t.hasOwnProperty,r=t.toString,i=e?e.toStringTag:void 0;function o(u){var c=n.call(u,i),f=u[i];try{u[i]=void 0;var h=!0}catch{}var v=r.call(u);return h&&(c?u[i]=f:delete u[i]),v}return dp=o,dp}var fp,cj;function RI(){if(cj)return fp;cj=1;var e=Object.prototype,t=e.toString;function n(r){return t.call(r)}return fp=n,fp}var hp,dj;function Lr(){if(dj)return hp;dj=1;var e=Ml(),t=II(),n=RI(),r="[object Null]",i="[object Undefined]",o=e?e.toStringTag:void 0;function u(c){return c==null?c===void 0?i:r:o&&o in Object(c)?t(c):n(c)}return hp=u,hp}var pp,fj;function Ur(){if(fj)return pp;fj=1;function e(t){return t!=null&&typeof t=="object"}return pp=e,pp}var mp,hj;function Oo(){if(hj)return mp;hj=1;var e=Lr(),t=Ur(),n="[object Symbol]";function r(i){return typeof i=="symbol"||t(i)&&e(i)==n}return mp=r,mp}var vp,pj;function Wx(){if(pj)return vp;pj=1;var e=dn(),t=Oo(),n=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,r=/^\w*$/;function i(o,u){if(e(o))return!1;var c=typeof o;return c=="number"||c=="symbol"||c=="boolean"||o==null||t(o)?!0:r.test(o)||!n.test(o)||u!=null&&o in Object(u)}return vp=i,vp}var gp,mj;function yi(){if(mj)return gp;mj=1;function e(t){var n=typeof t;return t!=null&&(n=="object"||n=="function")}return gp=e,gp}var yp,vj;function Hx(){if(vj)return yp;vj=1;var e=Lr(),t=yi(),n="[object AsyncFunction]",r="[object Function]",i="[object GeneratorFunction]",o="[object Proxy]";function u(c){if(!t(c))return!1;var f=e(c);return f==r||f==i||f==n||f==o}return yp=u,yp}var xp,gj;function $I(){if(gj)return xp;gj=1;var e=mr(),t=e["__core-js_shared__"];return xp=t,xp}var bp,yj;function DI(){if(yj)return bp;yj=1;var e=$I(),t=(function(){var r=/[^.]+$/.exec(e&&e.keys&&e.keys.IE_PROTO||"");return r?"Symbol(src)_1."+r:""})();function n(r){return!!t&&t in r}return bp=n,bp}var wp,xj;function EP(){if(xj)return wp;xj=1;var e=Function.prototype,t=e.toString;function n(r){if(r!=null){try{return t.call(r)}catch{}try{return r+""}catch{}}return""}return wp=n,wp}var jp,bj;function LI(){if(bj)return jp;bj=1;var e=Hx(),t=DI(),n=yi(),r=EP(),i=/[\\^$.*+?()[\]{}|]/g,o=/^\[object .+?Constructor\]$/,u=Function.prototype,c=Object.prototype,f=u.toString,h=c.hasOwnProperty,v=RegExp("^"+f.call(h).replace(i,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$");function m(y){if(!n(y)||t(y))return!1;var b=e(y)?v:o;return b.test(r(y))}return jp=m,jp}var Sp,wj;function UI(){if(wj)return Sp;wj=1;function e(t,n){return t==null?void 0:t[n]}return Sp=e,Sp}var kp,jj;function oa(){if(jj)return kp;jj=1;var e=LI(),t=UI();function n(r,i){var o=t(r,i);return e(o)?o:void 0}return kp=n,kp}var Cp,Sj;function Pd(){if(Sj)return Cp;Sj=1;var e=oa(),t=e(Object,"create");return Cp=t,Cp}var _p,kj;function qI(){if(kj)return _p;kj=1;var e=Pd();function t(){this.__data__=e?e(null):{},this.size=0}return _p=t,_p}var Op,Cj;function FI(){if(Cj)return Op;Cj=1;function e(t){var n=this.has(t)&&delete this.__data__[t];return this.size-=n?1:0,n}return Op=e,Op}var Tp,_j;function BI(){if(_j)return Tp;_j=1;var e=Pd(),t="__lodash_hash_undefined__",n=Object.prototype,r=n.hasOwnProperty;function i(o){var u=this.__data__;if(e){var c=u[o];return c===t?void 0:c}return r.call(u,o)?u[o]:void 0}return Tp=i,Tp}var Pp,Oj;function zI(){if(Oj)return Pp;Oj=1;var e=Pd(),t=Object.prototype,n=t.hasOwnProperty;function r(i){var o=this.__data__;return e?o[i]!==void 0:n.call(o,i)}return Pp=r,Pp}var Np,Tj;function WI(){if(Tj)return Np;Tj=1;var e=Pd(),t="__lodash_hash_undefined__";function n(r,i){var o=this.__data__;return this.size+=this.has(r)?0:1,o[r]=e&&i===void 0?t:i,this}return Np=n,Np}var Ap,Pj;function HI(){if(Pj)return Ap;Pj=1;var e=qI(),t=FI(),n=BI(),r=zI(),i=WI();function o(u){var c=-1,f=u==null?0:u.length;for(this.clear();++c<f;){var h=u[c];this.set(h[0],h[1])}}return o.prototype.clear=e,o.prototype.delete=t,o.prototype.get=n,o.prototype.has=r,o.prototype.set=i,Ap=o,Ap}var Ep,Nj;function KI(){if(Nj)return Ep;Nj=1;function e(){this.__data__=[],this.size=0}return Ep=e,Ep}var Mp,Aj;function Kx(){if(Aj)return Mp;Aj=1;function e(t,n){return t===n||t!==t&&n!==n}return Mp=e,Mp}var Ip,Ej;function Nd(){if(Ej)return Ip;Ej=1;var e=Kx();function t(n,r){for(var i=n.length;i--;)if(e(n[i][0],r))return i;return-1}return Ip=t,Ip}var Rp,Mj;function VI(){if(Mj)return Rp;Mj=1;var e=Nd(),t=Array.prototype,n=t.splice;function r(i){var o=this.__data__,u=e(o,i);if(u<0)return!1;var c=o.length-1;return u==c?o.pop():n.call(o,u,1),--this.size,!0}return Rp=r,Rp}var $p,Ij;function GI(){if(Ij)return $p;Ij=1;var e=Nd();function t(n){var r=this.__data__,i=e(r,n);return i<0?void 0:r[i][1]}return $p=t,$p}var Dp,Rj;function XI(){if(Rj)return Dp;Rj=1;var e=Nd();function t(n){return e(this.__data__,n)>-1}return Dp=t,Dp}var Lp,$j;function YI(){if($j)return Lp;$j=1;var e=Nd();function t(n,r){var i=this.__data__,o=e(i,n);return o<0?(++this.size,i.push([n,r])):i[o][1]=r,this}return Lp=t,Lp}var Up,Dj;function Ad(){if(Dj)return Up;Dj=1;var e=KI(),t=VI(),n=GI(),r=XI(),i=YI();function o(u){var c=-1,f=u==null?0:u.length;for(this.clear();++c<f;){var h=u[c];this.set(h[0],h[1])}}return o.prototype.clear=e,o.prototype.delete=t,o.prototype.get=n,o.prototype.has=r,o.prototype.set=i,Up=o,Up}var qp,Lj;function Vx(){if(Lj)return qp;Lj=1;var e=oa(),t=mr(),n=e(t,"Map");return qp=n,qp}var Fp,Uj;function QI(){if(Uj)return Fp;Uj=1;var e=HI(),t=Ad(),n=Vx();function r(){this.size=0,this.__data__={hash:new e,map:new(n||t),string:new e}}return Fp=r,Fp}var Bp,qj;function ZI(){if(qj)return Bp;qj=1;function e(t){var n=typeof t;return n=="string"||n=="number"||n=="symbol"||n=="boolean"?t!=="__proto__":t===null}return Bp=e,Bp}var zp,Fj;function Ed(){if(Fj)return zp;Fj=1;var e=ZI();function t(n,r){var i=n.__data__;return e(r)?i[typeof r=="string"?"string":"hash"]:i.map}return zp=t,zp}var Wp,Bj;function JI(){if(Bj)return Wp;Bj=1;var e=Ed();function t(n){var r=e(this,n).delete(n);return this.size-=r?1:0,r}return Wp=t,Wp}var Hp,zj;function eR(){if(zj)return Hp;zj=1;var e=Ed();function t(n){return e(this,n).get(n)}return Hp=t,Hp}var Kp,Wj;function tR(){if(Wj)return Kp;Wj=1;var e=Ed();function t(n){return e(this,n).has(n)}return Kp=t,Kp}var Vp,Hj;function nR(){if(Hj)return Vp;Hj=1;var e=Ed();function t(n,r){var i=e(this,n),o=i.size;return i.set(n,r),this.size+=i.size==o?0:1,this}return Vp=t,Vp}var Gp,Kj;function Gx(){if(Kj)return Gp;Kj=1;var e=QI(),t=JI(),n=eR(),r=tR(),i=nR();function o(u){var c=-1,f=u==null?0:u.length;for(this.clear();++c<f;){var h=u[c];this.set(h[0],h[1])}}return o.prototype.clear=e,o.prototype.delete=t,o.prototype.get=n,o.prototype.has=r,o.prototype.set=i,Gp=o,Gp}var Xp,Vj;function MP(){if(Vj)return Xp;Vj=1;var e=Gx(),t="Expected a function";function n(r,i){if(typeof r!="function"||i!=null&&typeof i!="function")throw new TypeError(t);var o=function(){var u=arguments,c=i?i.apply(this,u):u[0],f=o.cache;if(f.has(c))return f.get(c);var h=r.apply(this,u);return o.cache=f.set(c,h)||f,h};return o.cache=new(n.Cache||e),o}return n.Cache=e,Xp=n,Xp}var Yp,Gj;function rR(){if(Gj)return Yp;Gj=1;var e=MP(),t=500;function n(r){var i=e(r,function(u){return o.size===t&&o.clear(),u}),o=i.cache;return i}return Yp=n,Yp}var Qp,Xj;function iR(){if(Xj)return Qp;Xj=1;var e=rR(),t=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,n=/\\(\\)?/g,r=e(function(i){var o=[];return i.charCodeAt(0)===46&&o.push(""),i.replace(t,function(u,c,f,h){o.push(f?h.replace(n,"$1"):c||u)}),o});return Qp=r,Qp}var Zp,Yj;function Xx(){if(Yj)return Zp;Yj=1;function e(t,n){for(var r=-1,i=t==null?0:t.length,o=Array(i);++r<i;)o[r]=n(t[r],r,t);return o}return Zp=e,Zp}var Jp,Qj;function aR(){if(Qj)return Jp;Qj=1;var e=Ml(),t=Xx(),n=dn(),r=Oo(),i=e?e.prototype:void 0,o=i?i.toString:void 0;function u(c){if(typeof c=="string")return c;if(n(c))return t(c,u)+"";if(r(c))return o?o.call(c):"";var f=c+"";return f=="0"&&1/c==-1/0?"-0":f}return Jp=u,Jp}var em,Zj;function IP(){if(Zj)return em;Zj=1;var e=aR();function t(n){return n==null?"":e(n)}return em=t,em}var tm,Jj;function RP(){if(Jj)return tm;Jj=1;var e=dn(),t=Wx(),n=iR(),r=IP();function i(o,u){return e(o)?o:t(o,u)?[o]:n(r(o))}return tm=i,tm}var nm,eS;function Md(){if(eS)return nm;eS=1;var e=Oo();function t(n){if(typeof n=="string"||e(n))return n;var r=n+"";return r=="0"&&1/n==-1/0?"-0":r}return nm=t,nm}var rm,tS;function Yx(){if(tS)return rm;tS=1;var e=RP(),t=Md();function n(r,i){i=e(i,r);for(var o=0,u=i.length;r!=null&&o<u;)r=r[t(i[o++])];return o&&o==u?r:void 0}return rm=n,rm}var im,nS;function $P(){if(nS)return im;nS=1;var e=Yx();function t(n,r,i){var o=n==null?void 0:e(n,r);return o===void 0?i:o}return im=t,im}var oR=$P();const In=Ze(oR);var am,rS;function sR(){if(rS)return am;rS=1;function e(t){return t==null}return am=e,am}var lR=sR();const Le=Ze(lR);var om,iS;function uR(){if(iS)return om;iS=1;var e=Lr(),t=dn(),n=Ur(),r="[object String]";function i(o){return typeof o=="string"||!t(o)&&n(o)&&e(o)==r}return om=i,om}var cR=uR();const Qi=Ze(cR);var dR=Hx();const Re=Ze(dR);var fR=yi();const To=Ze(fR);var sm={exports:{}},Ve={};/**
235
+ */const NI=qe("X",[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]]);function Qa(e){return e.toLowerCase().replace(/^github_copilot\//,"").replace(/^github-copilot\//,"").replace(/^copilot\//,"").replace(/claude-(opus|sonnet|haiku)-(\d+)\.(\d+)(?=$|[-.])/,"claude-$1-$2-$3")}function PP(e,t=()=>!0){const n=["claude-fable-5","claude-mythos-5","claude-opus-4-8-fast-mode","claude-opus-4-7","claude-opus-4-6","claude-opus-4-5","claude-opus-4-1","claude-opus-4","claude-sonnet-5","claude-sonnet-4-6","claude-sonnet-4-5","claude-sonnet-4","claude-haiku-4-5","claude-3-5-haiku"],r=Qa(e);if(r!=="claude-opus-4-6-fast-mode")return n.find(i=>(r===i||r.startsWith(`${i}-`)||r.startsWith(`${i}.`))&&t(i))}function AI(e,t=()=>!0){const n=Qa(e),r=PP(n,t);if(r)return r;if((n==="gpt-4.1"||n.startsWith("gpt-4.1-")||n.startsWith("gpt-41"))&&t("gpt-4.1"))return"gpt-4.1";if((n==="gemini-2.5-pro"||n.startsWith("gemini-2.5-pro-"))&&t("gemini-2.5-pro"))return"gemini-2.5-pro";if((n==="gemini-3-flash"||n.startsWith("gemini-3-flash-"))&&t("gemini-3-flash"))return"gemini-3-flash";if((n==="gemini-3.1-pro"||n.startsWith("gemini-3.1-pro-"))&&t("gemini-3.1-pro"))return"gemini-3.1-pro";if((n==="gemini-3.5-flash"||n.startsWith("gemini-3.5-flash-"))&&t("gemini-3.5-flash"))return"gemini-3.5-flash";if((n==="raptor-mini"||n.startsWith("raptor-mini-")||n.startsWith("oswe-vscode"))&&t("raptor-mini"))return"raptor-mini";if((n==="lark"||n.startsWith("lark-"))&&t("lark"))return"lark";if((n==="goldeneye"||n.startsWith("goldeneye-"))&&t("goldeneye"))return"goldeneye";if((n==="mai-code-1-flash"||n.startsWith("mai-code-1-flash-"))&&t("mai-code-1-flash"))return"mai-code-1-flash";if((n==="kimi-k2.7-code"||n.startsWith("kimi-k2.7-code-"))&&t("kimi-k2.7-code"))return"kimi-k2.7-code"}function rj(e){if(e.includes("fast-mode"))return;const t=e.match(/^(claude-(?:fable|mythos|opus|sonnet|haiku))-(\d+)(?:-(\d+))?/);if(t){const r=t[3]?Number(t[3]):0;return{tier:t[1],version:Number(t[2])+r/100}}const n=e.match(/^(gpt)-(\d)(?:\.(\d+))?(-[a-z][a-z0-9-]*)?$/);if(n){const r=n[3]?Number(n[3]):0;return{tier:`gpt${n[4]??""}`,version:Number(n[2])+r/100}}}function EI(e,t,n=()=>!0){const r=rj(Qa(e));if(!r)return;let i;for(const o of t){const u=rj(Qa(o));!u||u.tier!==r.tier||u.version>r.version||n(o)&&(!i||u.version>i.version)&&(i={id:o,version:u.version})}return i==null?void 0:i.id}function MI(e){const t=Qa(e);return t.startsWith("raptor-mini")||t.startsWith("oswe-vscode")||t==="lark"||t.startsWith("lark-")||t.startsWith("goldeneye")||t.startsWith("mai-code-1-flash")||t.startsWith("kimi-k2.7-code")}function ij(e){return typeof e=="number"&&Number.isFinite(e)&&e>0}function Ba(e){return ij(e==null?void 0:e.inputPerMillion)&&ij(e==null?void 0:e.outputPerMillion)}function zx(e,t){const n=Qa(e),r=t[e]?e:t[n]?n:void 0,i=r?t[r]:void 0;if(Ba(i))return{pricing:i,sourceModel:r,inherited:!1};const o=EI(n,Object.keys(t),f=>Ba(t[f]));if(o)return{pricing:t[o],sourceModel:o,inherited:o!==e&&o!==n};const u=PP(n,f=>Ba(t[f]));if(u)return{pricing:t[u],sourceModel:u,inherited:u!==e&&u!==n};const c=AI(n,f=>Ba(t[f]));return c?{pricing:t[c],sourceModel:c,inherited:c!==e&&c!==n}:{pricing:i??{inputPerMillion:0,cacheCreationInputPerMillion:0,cachedInputPerMillion:0,outputPerMillion:0,reasoningOutputPerMillion:0},sourceModel:r,inherited:!1}}function NP(e){var t,n,r="";if(typeof e=="string"||typeof e=="number")r+=e;else if(typeof e=="object")if(Array.isArray(e)){var i=e.length;for(t=0;t<i;t++)e[t]&&(n=NP(e[t]))&&(r&&(r+=" "),r+=n)}else for(n in e)e[n]&&(r&&(r+=" "),r+=n);return r}function Be(){for(var e,t,n=0,r="",i=arguments.length;n<i;n++)(e=arguments[n])&&(t=NP(e))&&(r&&(r+=" "),r+=t);return r}var sp,aj;function dn(){if(aj)return sp;aj=1;var e=Array.isArray;return sp=e,sp}var lp,oj;function AP(){if(oj)return lp;oj=1;var e=typeof ec=="object"&&ec&&ec.Object===Object&&ec;return lp=e,lp}var up,sj;function mr(){if(sj)return up;sj=1;var e=AP(),t=typeof self=="object"&&self&&self.Object===Object&&self,n=e||t||Function("return this")();return up=n,up}var cp,lj;function Ml(){if(lj)return cp;lj=1;var e=mr(),t=e.Symbol;return cp=t,cp}var dp,uj;function II(){if(uj)return dp;uj=1;var e=Ml(),t=Object.prototype,n=t.hasOwnProperty,r=t.toString,i=e?e.toStringTag:void 0;function o(u){var c=n.call(u,i),f=u[i];try{u[i]=void 0;var h=!0}catch{}var v=r.call(u);return h&&(c?u[i]=f:delete u[i]),v}return dp=o,dp}var fp,cj;function RI(){if(cj)return fp;cj=1;var e=Object.prototype,t=e.toString;function n(r){return t.call(r)}return fp=n,fp}var hp,dj;function Lr(){if(dj)return hp;dj=1;var e=Ml(),t=II(),n=RI(),r="[object Null]",i="[object Undefined]",o=e?e.toStringTag:void 0;function u(c){return c==null?c===void 0?i:r:o&&o in Object(c)?t(c):n(c)}return hp=u,hp}var pp,fj;function Ur(){if(fj)return pp;fj=1;function e(t){return t!=null&&typeof t=="object"}return pp=e,pp}var mp,hj;function Oo(){if(hj)return mp;hj=1;var e=Lr(),t=Ur(),n="[object Symbol]";function r(i){return typeof i=="symbol"||t(i)&&e(i)==n}return mp=r,mp}var vp,pj;function Wx(){if(pj)return vp;pj=1;var e=dn(),t=Oo(),n=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,r=/^\w*$/;function i(o,u){if(e(o))return!1;var c=typeof o;return c=="number"||c=="symbol"||c=="boolean"||o==null||t(o)?!0:r.test(o)||!n.test(o)||u!=null&&o in Object(u)}return vp=i,vp}var gp,mj;function yi(){if(mj)return gp;mj=1;function e(t){var n=typeof t;return t!=null&&(n=="object"||n=="function")}return gp=e,gp}var yp,vj;function Hx(){if(vj)return yp;vj=1;var e=Lr(),t=yi(),n="[object AsyncFunction]",r="[object Function]",i="[object GeneratorFunction]",o="[object Proxy]";function u(c){if(!t(c))return!1;var f=e(c);return f==r||f==i||f==n||f==o}return yp=u,yp}var xp,gj;function $I(){if(gj)return xp;gj=1;var e=mr(),t=e["__core-js_shared__"];return xp=t,xp}var bp,yj;function DI(){if(yj)return bp;yj=1;var e=$I(),t=(function(){var r=/[^.]+$/.exec(e&&e.keys&&e.keys.IE_PROTO||"");return r?"Symbol(src)_1."+r:""})();function n(r){return!!t&&t in r}return bp=n,bp}var wp,xj;function EP(){if(xj)return wp;xj=1;var e=Function.prototype,t=e.toString;function n(r){if(r!=null){try{return t.call(r)}catch{}try{return r+""}catch{}}return""}return wp=n,wp}var jp,bj;function LI(){if(bj)return jp;bj=1;var e=Hx(),t=DI(),n=yi(),r=EP(),i=/[\\^$.*+?()[\]{}|]/g,o=/^\[object .+?Constructor\]$/,u=Function.prototype,c=Object.prototype,f=u.toString,h=c.hasOwnProperty,v=RegExp("^"+f.call(h).replace(i,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$");function m(y){if(!n(y)||t(y))return!1;var b=e(y)?v:o;return b.test(r(y))}return jp=m,jp}var Sp,wj;function UI(){if(wj)return Sp;wj=1;function e(t,n){return t==null?void 0:t[n]}return Sp=e,Sp}var kp,jj;function oa(){if(jj)return kp;jj=1;var e=LI(),t=UI();function n(r,i){var o=t(r,i);return e(o)?o:void 0}return kp=n,kp}var Cp,Sj;function Pd(){if(Sj)return Cp;Sj=1;var e=oa(),t=e(Object,"create");return Cp=t,Cp}var _p,kj;function qI(){if(kj)return _p;kj=1;var e=Pd();function t(){this.__data__=e?e(null):{},this.size=0}return _p=t,_p}var Op,Cj;function FI(){if(Cj)return Op;Cj=1;function e(t){var n=this.has(t)&&delete this.__data__[t];return this.size-=n?1:0,n}return Op=e,Op}var Tp,_j;function BI(){if(_j)return Tp;_j=1;var e=Pd(),t="__lodash_hash_undefined__",n=Object.prototype,r=n.hasOwnProperty;function i(o){var u=this.__data__;if(e){var c=u[o];return c===t?void 0:c}return r.call(u,o)?u[o]:void 0}return Tp=i,Tp}var Pp,Oj;function zI(){if(Oj)return Pp;Oj=1;var e=Pd(),t=Object.prototype,n=t.hasOwnProperty;function r(i){var o=this.__data__;return e?o[i]!==void 0:n.call(o,i)}return Pp=r,Pp}var Np,Tj;function WI(){if(Tj)return Np;Tj=1;var e=Pd(),t="__lodash_hash_undefined__";function n(r,i){var o=this.__data__;return this.size+=this.has(r)?0:1,o[r]=e&&i===void 0?t:i,this}return Np=n,Np}var Ap,Pj;function HI(){if(Pj)return Ap;Pj=1;var e=qI(),t=FI(),n=BI(),r=zI(),i=WI();function o(u){var c=-1,f=u==null?0:u.length;for(this.clear();++c<f;){var h=u[c];this.set(h[0],h[1])}}return o.prototype.clear=e,o.prototype.delete=t,o.prototype.get=n,o.prototype.has=r,o.prototype.set=i,Ap=o,Ap}var Ep,Nj;function KI(){if(Nj)return Ep;Nj=1;function e(){this.__data__=[],this.size=0}return Ep=e,Ep}var Mp,Aj;function Kx(){if(Aj)return Mp;Aj=1;function e(t,n){return t===n||t!==t&&n!==n}return Mp=e,Mp}var Ip,Ej;function Nd(){if(Ej)return Ip;Ej=1;var e=Kx();function t(n,r){for(var i=n.length;i--;)if(e(n[i][0],r))return i;return-1}return Ip=t,Ip}var Rp,Mj;function VI(){if(Mj)return Rp;Mj=1;var e=Nd(),t=Array.prototype,n=t.splice;function r(i){var o=this.__data__,u=e(o,i);if(u<0)return!1;var c=o.length-1;return u==c?o.pop():n.call(o,u,1),--this.size,!0}return Rp=r,Rp}var $p,Ij;function GI(){if(Ij)return $p;Ij=1;var e=Nd();function t(n){var r=this.__data__,i=e(r,n);return i<0?void 0:r[i][1]}return $p=t,$p}var Dp,Rj;function XI(){if(Rj)return Dp;Rj=1;var e=Nd();function t(n){return e(this.__data__,n)>-1}return Dp=t,Dp}var Lp,$j;function YI(){if($j)return Lp;$j=1;var e=Nd();function t(n,r){var i=this.__data__,o=e(i,n);return o<0?(++this.size,i.push([n,r])):i[o][1]=r,this}return Lp=t,Lp}var Up,Dj;function Ad(){if(Dj)return Up;Dj=1;var e=KI(),t=VI(),n=GI(),r=XI(),i=YI();function o(u){var c=-1,f=u==null?0:u.length;for(this.clear();++c<f;){var h=u[c];this.set(h[0],h[1])}}return o.prototype.clear=e,o.prototype.delete=t,o.prototype.get=n,o.prototype.has=r,o.prototype.set=i,Up=o,Up}var qp,Lj;function Vx(){if(Lj)return qp;Lj=1;var e=oa(),t=mr(),n=e(t,"Map");return qp=n,qp}var Fp,Uj;function QI(){if(Uj)return Fp;Uj=1;var e=HI(),t=Ad(),n=Vx();function r(){this.size=0,this.__data__={hash:new e,map:new(n||t),string:new e}}return Fp=r,Fp}var Bp,qj;function ZI(){if(qj)return Bp;qj=1;function e(t){var n=typeof t;return n=="string"||n=="number"||n=="symbol"||n=="boolean"?t!=="__proto__":t===null}return Bp=e,Bp}var zp,Fj;function Ed(){if(Fj)return zp;Fj=1;var e=ZI();function t(n,r){var i=n.__data__;return e(r)?i[typeof r=="string"?"string":"hash"]:i.map}return zp=t,zp}var Wp,Bj;function JI(){if(Bj)return Wp;Bj=1;var e=Ed();function t(n){var r=e(this,n).delete(n);return this.size-=r?1:0,r}return Wp=t,Wp}var Hp,zj;function eR(){if(zj)return Hp;zj=1;var e=Ed();function t(n){return e(this,n).get(n)}return Hp=t,Hp}var Kp,Wj;function tR(){if(Wj)return Kp;Wj=1;var e=Ed();function t(n){return e(this,n).has(n)}return Kp=t,Kp}var Vp,Hj;function nR(){if(Hj)return Vp;Hj=1;var e=Ed();function t(n,r){var i=e(this,n),o=i.size;return i.set(n,r),this.size+=i.size==o?0:1,this}return Vp=t,Vp}var Gp,Kj;function Gx(){if(Kj)return Gp;Kj=1;var e=QI(),t=JI(),n=eR(),r=tR(),i=nR();function o(u){var c=-1,f=u==null?0:u.length;for(this.clear();++c<f;){var h=u[c];this.set(h[0],h[1])}}return o.prototype.clear=e,o.prototype.delete=t,o.prototype.get=n,o.prototype.has=r,o.prototype.set=i,Gp=o,Gp}var Xp,Vj;function MP(){if(Vj)return Xp;Vj=1;var e=Gx(),t="Expected a function";function n(r,i){if(typeof r!="function"||i!=null&&typeof i!="function")throw new TypeError(t);var o=function(){var u=arguments,c=i?i.apply(this,u):u[0],f=o.cache;if(f.has(c))return f.get(c);var h=r.apply(this,u);return o.cache=f.set(c,h)||f,h};return o.cache=new(n.Cache||e),o}return n.Cache=e,Xp=n,Xp}var Yp,Gj;function rR(){if(Gj)return Yp;Gj=1;var e=MP(),t=500;function n(r){var i=e(r,function(u){return o.size===t&&o.clear(),u}),o=i.cache;return i}return Yp=n,Yp}var Qp,Xj;function iR(){if(Xj)return Qp;Xj=1;var e=rR(),t=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,n=/\\(\\)?/g,r=e(function(i){var o=[];return i.charCodeAt(0)===46&&o.push(""),i.replace(t,function(u,c,f,h){o.push(f?h.replace(n,"$1"):c||u)}),o});return Qp=r,Qp}var Zp,Yj;function Xx(){if(Yj)return Zp;Yj=1;function e(t,n){for(var r=-1,i=t==null?0:t.length,o=Array(i);++r<i;)o[r]=n(t[r],r,t);return o}return Zp=e,Zp}var Jp,Qj;function aR(){if(Qj)return Jp;Qj=1;var e=Ml(),t=Xx(),n=dn(),r=Oo(),i=e?e.prototype:void 0,o=i?i.toString:void 0;function u(c){if(typeof c=="string")return c;if(n(c))return t(c,u)+"";if(r(c))return o?o.call(c):"";var f=c+"";return f=="0"&&1/c==-1/0?"-0":f}return Jp=u,Jp}var em,Zj;function IP(){if(Zj)return em;Zj=1;var e=aR();function t(n){return n==null?"":e(n)}return em=t,em}var tm,Jj;function RP(){if(Jj)return tm;Jj=1;var e=dn(),t=Wx(),n=iR(),r=IP();function i(o,u){return e(o)?o:t(o,u)?[o]:n(r(o))}return tm=i,tm}var nm,eS;function Md(){if(eS)return nm;eS=1;var e=Oo();function t(n){if(typeof n=="string"||e(n))return n;var r=n+"";return r=="0"&&1/n==-1/0?"-0":r}return nm=t,nm}var rm,tS;function Yx(){if(tS)return rm;tS=1;var e=RP(),t=Md();function n(r,i){i=e(i,r);for(var o=0,u=i.length;r!=null&&o<u;)r=r[t(i[o++])];return o&&o==u?r:void 0}return rm=n,rm}var im,nS;function $P(){if(nS)return im;nS=1;var e=Yx();function t(n,r,i){var o=n==null?void 0:e(n,r);return o===void 0?i:o}return im=t,im}var oR=$P();const In=Ze(oR);var am,rS;function sR(){if(rS)return am;rS=1;function e(t){return t==null}return am=e,am}var lR=sR();const Le=Ze(lR);var om,iS;function uR(){if(iS)return om;iS=1;var e=Lr(),t=dn(),n=Ur(),r="[object String]";function i(o){return typeof o=="string"||!t(o)&&n(o)&&e(o)==r}return om=i,om}var cR=uR();const Qi=Ze(cR);var dR=Hx();const Re=Ze(dR);var fR=yi();const To=Ze(fR);var sm={exports:{}},Ve={};/**
236
236
  * @license React
237
237
  * react-is.production.min.js
238
238
  *
@@ -10,7 +10,7 @@
10
10
  <meta name="theme-color" content="#060b12" />
11
11
  <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
12
12
  <title>RepoSpend</title>
13
- <script type="module" crossorigin src="/assets/index-BBw375PL.js"></script>
13
+ <script type="module" crossorigin src="/assets/index-BgcURWGy.js"></script>
14
14
  <link rel="stylesheet" crossorigin href="/assets/index-Bzdfbi5w.css">
15
15
  </head>
16
16
  <body>