agent-usage-all-in-one 0.5.0 → 0.6.0

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.
Files changed (29) hide show
  1. package/README.md +12 -11
  2. package/README.zh-CN.md +12 -11
  3. package/dist/cli.js +1537 -191
  4. package/dist/cli.js.map +1 -1
  5. package/dist/web/_app/immutable/assets/2.RN1Pn-E8.css +1 -0
  6. package/dist/web/_app/immutable/chunks/BfTUk1IE.js +1 -0
  7. package/dist/web/_app/immutable/chunks/CkDl_J6h.js +3 -0
  8. package/dist/web/_app/immutable/chunks/YtE49JQT.js +1 -0
  9. package/dist/web/_app/immutable/entry/app.Cr-3S01G.js +2 -0
  10. package/dist/web/_app/immutable/entry/start.BiLBur5x.js +1 -0
  11. package/dist/web/_app/immutable/nodes/0.Bc_BSNVt.js +1 -0
  12. package/dist/web/_app/immutable/nodes/1.BYavEZ8T.js +1 -0
  13. package/dist/web/_app/immutable/nodes/2.ehiOyFDQ.js +28 -0
  14. package/dist/web/_app/version.json +1 -1
  15. package/dist/web/brand/agent-usage-showcase.jpg +0 -0
  16. package/dist/web/brands/antigravity.svg +3 -0
  17. package/dist/web/index.html +9 -9
  18. package/package.json +1 -1
  19. package/static/brand/agent-usage-showcase.jpg +0 -0
  20. package/static/brands/antigravity.svg +3 -0
  21. package/dist/web/_app/immutable/assets/2.CHCuk4nb.css +0 -1
  22. package/dist/web/_app/immutable/chunks/3vuWay1s.js +0 -3
  23. package/dist/web/_app/immutable/chunks/CIxAYfti.js +0 -1
  24. package/dist/web/_app/immutable/chunks/Kc2LV0tw.js +0 -1
  25. package/dist/web/_app/immutable/entry/app.BKd02i81.js +0 -2
  26. package/dist/web/_app/immutable/entry/start.DrTKmCEQ.js +0 -1
  27. package/dist/web/_app/immutable/nodes/0.f03zL-fK.js +0 -1
  28. package/dist/web/_app/immutable/nodes/1.HxUixbgc.js +0 -1
  29. package/dist/web/_app/immutable/nodes/2.D3Z9fN6k.js +0 -27
package/dist/cli.js CHANGED
@@ -159,7 +159,7 @@ function buildUsageExport(overview, request, accountIdentifiers = {}) {
159
159
  calculatedAt: null
160
160
  };
161
161
  const modelObservations = history.models.flatMap(
162
- (model) => model.observations.map((observation) => ({
162
+ (model) => (model.observations ?? []).map((observation) => ({
163
163
  model: model.model,
164
164
  observation
165
165
  }))
@@ -210,14 +210,14 @@ function buildUsageExport(overview, request, accountIdentifiers = {}) {
210
210
  });
211
211
  const observationsById = new Map([
212
212
  ...history.models.flatMap(
213
- (model) => model.observations.map((observation) => [observation.id, observation])
213
+ (model) => (model.observations ?? []).map((observation) => [observation.id, observation])
214
214
  ),
215
215
  ...(history.unclassified.observations ?? []).map(
216
216
  (observation) => [observation.id, observation]
217
217
  )
218
218
  ]);
219
219
  const costRows = history.costs.map((cost) => {
220
- const authorities = domain.costs.filter(
220
+ const authorities = (domain.costs ?? []).filter(
221
221
  (candidate) => candidate.kind === cost.kind && candidate.currency.toUpperCase() === cost.currency.toUpperCase() && candidate.observedAt >= history.start && candidate.observedAt < history.end
222
222
  ).map((candidate) => candidate.authority);
223
223
  return {
@@ -268,7 +268,7 @@ function buildUsageExport(overview, request, accountIdentifiers = {}) {
268
268
  calculatedAt: null
269
269
  };
270
270
  });
271
- const costObservationRows = domain.costs.filter((cost) => cost.observedAt >= history.start && cost.observedAt < history.end).map((cost) => {
271
+ const costObservationRows = (domain.costs ?? []).filter((cost) => cost.observedAt >= history.start && cost.observedAt < history.end).map((cost) => {
272
272
  const snapshot2 = cost.priceSnapshot ?? null;
273
273
  const observation = cost.usageObservationId ? observationsById.get(cost.usageObservationId) : null;
274
274
  return {
@@ -557,10 +557,34 @@ function anthropicEntry(options) {
557
557
  source: {
558
558
  title: "Anthropic Claude API pricing",
559
559
  url: options.sourceUrl,
560
- retrievedAt: "2026-08-28"
560
+ retrievedAt: options.retrievedAt ?? "2026-08-28"
561
561
  }
562
562
  };
563
563
  }
564
+ function antigravityEntry(options) {
565
+ const versionDate = "2026-09-02";
566
+ return {
567
+ id: options.id,
568
+ priceVersion: `antigravity-${versionDate}`,
569
+ providerId: "antigravity",
570
+ billingDomainId: "code-assist-subscription",
571
+ canonicalModel: options.model,
572
+ aliases: options.aliases,
573
+ currency: "USD",
574
+ effectiveFrom: GOOGLE_ANTIGRAVITY_EFFECTIVE_FROM,
575
+ effectiveUntil: null,
576
+ contextTier: "standard-api",
577
+ contextRule: { kind: "fixed" },
578
+ ratesPerMillion: {
579
+ input: options.input,
580
+ output: options.output,
581
+ reasoning: options.output,
582
+ "cache-read": options.cacheRead ?? null,
583
+ "cache-write": null
584
+ },
585
+ source: options.source ?? GOOGLE_ANTIGRAVITY_SOURCE
586
+ };
587
+ }
564
588
  function openAiGpt56Entries(model, periods) {
565
589
  return periods.flatMap(([effectiveFrom, effectiveUntil, input, output]) => {
566
590
  const versionDate = effectiveFrom.slice(0, 10);
@@ -705,8 +729,48 @@ function openCodeLocalModelPrefix(entry) {
705
729
  if (entry.providerId === "opencode-go" && entry.billingDomainId === "go-subscription") {
706
730
  return "opencode-go";
707
731
  }
732
+ if (entry.providerId === "antigravity" && entry.billingDomainId === "code-assist-subscription") {
733
+ return "google";
734
+ }
708
735
  return null;
709
736
  }
737
+ function customModelRateToCatalogEntry(rate) {
738
+ const versionDate = rate.updatedAt.slice(0, 10);
739
+ return {
740
+ id: `custom-rate-${rate.id}`,
741
+ priceVersion: `custom-${rate.id}-${rate.updatedAt}`,
742
+ providerId: rate.providerId,
743
+ billingDomainId: rate.billingDomainId ?? "*",
744
+ canonicalModel: rate.model,
745
+ aliases: [],
746
+ currency: "USD",
747
+ effectiveFrom: "2020-01-01T00:00:00.000Z",
748
+ effectiveUntil: null,
749
+ contextTier: "custom-rate",
750
+ contextRule: { kind: "fixed" },
751
+ ratesPerMillion: {
752
+ input: rate.ratesPerMillion.input,
753
+ output: rate.ratesPerMillion.output,
754
+ reasoning: rate.ratesPerMillion.output,
755
+ "cache-read": rate.ratesPerMillion.cacheRead,
756
+ "cache-write": null
757
+ },
758
+ source: {
759
+ title: "User-configured custom model rate",
760
+ url: "local://settings/rates",
761
+ retrievedAt: versionDate
762
+ }
763
+ };
764
+ }
765
+ function mergeCatalogWithCustomRates(catalog, customRates) {
766
+ if (!customRates || customRates.length === 0) return catalog;
767
+ const customEntries = customRates.map(customModelRateToCatalogEntry);
768
+ const rateFingerprints = customRates.map((r) => `${r.id}:${r.updatedAt}`).sort().join(";");
769
+ return {
770
+ version: `${catalog.version}+custom:${rateFingerprints}`,
771
+ entries: [...customEntries, ...catalog.entries]
772
+ };
773
+ }
710
774
  function deriveRetailEquivalentCosts(snapshot2, catalog = ANTHROPIC_PRICING_CATALOG, calculatedAt = snapshot2.observedAt) {
711
775
  const costs = [];
712
776
  const decisions = [];
@@ -732,13 +796,31 @@ function priceObservation(providerId, observation, catalog, calculatedAt) {
732
796
  return unavailable("model-unclassified");
733
797
  }
734
798
  const normalizedModel = normalized.model.trim().toLowerCase();
735
- const modelEntries = catalog.entries.filter(
736
- (entry2) => entry2.providerId === providerId && entry2.billingDomainId === observation.billingDomainId && [entry2.canonicalModel, ...entry2.aliases].some(
799
+ const matchingCandidates = catalog.entries.filter(
800
+ (entry2) => entry2.providerId === providerId && (entry2.billingDomainId === observation.billingDomainId || entry2.billingDomainId === "*") && [entry2.canonicalModel, ...entry2.aliases].some(
737
801
  (model) => model.trim().toLowerCase() === normalizedModel
738
802
  )
739
803
  );
740
- if (modelEntries.length === 0) return unavailable("model-unrecognized");
741
- const timeActiveEntries = modelEntries.filter(
804
+ let selectedEntries;
805
+ const customExact = matchingCandidates.filter(
806
+ (e) => e.contextTier === "custom-rate" && e.billingDomainId === observation.billingDomainId
807
+ );
808
+ if (customExact.length > 0) {
809
+ selectedEntries = customExact;
810
+ } else {
811
+ const customWildcard = matchingCandidates.filter(
812
+ (e) => e.contextTier === "custom-rate" && e.billingDomainId === "*"
813
+ );
814
+ if (customWildcard.length > 0) {
815
+ selectedEntries = customWildcard;
816
+ } else {
817
+ selectedEntries = matchingCandidates.filter(
818
+ (e) => e.contextTier !== "custom-rate" && e.billingDomainId === observation.billingDomainId
819
+ );
820
+ }
821
+ }
822
+ if (selectedEntries.length === 0) return unavailable("model-unrecognized");
823
+ const timeActiveEntries = selectedEntries.filter(
742
824
  (entry2) => observation.observedAt >= entry2.effectiveFrom && (!entry2.effectiveUntil || observation.observedAt < entry2.effectiveUntil)
743
825
  );
744
826
  if (timeActiveEntries.length === 0) return unavailable("price-not-effective");
@@ -877,7 +959,7 @@ function matchContext(rule, observation) {
877
959
  function preciseMoney(value) {
878
960
  return Number(value.toFixed(12));
879
961
  }
880
- var ANTHROPIC_PRICING_CATALOG, OPENCODE_GO_SOURCE, XAI_PRICING_SOURCE, OPENAI_GPT_56_SOURCE, OPEN_CODE_GO_SOURCE_PATH, openCodeHistory, OPEN_CODE_BASE_HISTORY, OPEN_CODE_PRICE_HISTORY, OPEN_CODE_FLAT_MODELS, OPEN_CODE_CONTEXT_MODELS, DEEPSEEK_GO_MODELS, WEEKDAY_PEAK_RANGES, DEEPSEEK_OFFICIAL_SOURCE, DEEPSEEK_OFFICIAL_MODELS, DEEPSEEK_OFFICIAL_EFFECTIVE_FROM, DIRECT_OFFICIAL_PRICING_CATALOG, OFFICIAL_PRICING_CATALOG;
962
+ var ANTHROPIC_PRICING_CATALOG, OPENCODE_GO_SOURCE, XAI_PRICING_SOURCE, OPENAI_GPT_56_SOURCE, OPEN_CODE_GO_SOURCE_PATH, openCodeHistory, OPEN_CODE_BASE_HISTORY, OPEN_CODE_PRICE_HISTORY, OPEN_CODE_FLAT_MODELS, OPEN_CODE_CONTEXT_MODELS, DEEPSEEK_GO_MODELS, WEEKDAY_PEAK_RANGES, DEEPSEEK_OFFICIAL_SOURCE, DEEPSEEK_OFFICIAL_MODELS, DEEPSEEK_OFFICIAL_EFFECTIVE_FROM, GOOGLE_ANTIGRAVITY_SOURCE, GOOGLE_ANTIGRAVITY_EFFECTIVE_FROM, DIRECT_OFFICIAL_PRICING_CATALOG, OFFICIAL_PRICING_CATALOG;
881
963
  var init_retail_pricing = __esm({
882
964
  "src/core/retail-pricing.ts"() {
883
965
  "use strict";
@@ -885,6 +967,25 @@ var init_retail_pricing = __esm({
885
967
  ANTHROPIC_PRICING_CATALOG = {
886
968
  version: "2026-08-28",
887
969
  entries: [
970
+ anthropicEntry({
971
+ id: "anthropic-fable-5-1-2026-09-01",
972
+ priceVersion: "anthropic-2026-09-01",
973
+ model: "claude-fable-5-1",
974
+ aliases: [
975
+ "Claude Fable 5.1",
976
+ "claude-fable-5.1",
977
+ "claude-fable-5-1-20260901",
978
+ "claude-fable-5.1-20260901",
979
+ "fable-5.1",
980
+ "fable-5-1"
981
+ ],
982
+ effectiveFrom: "2026-09-01T00:00:00.000Z",
983
+ input: 10,
984
+ output: 50,
985
+ cacheRead: 0.25,
986
+ sourceUrl: "https://platform.claude.com/docs/en/about-claude/pricing",
987
+ retrievedAt: "2026-09-03"
988
+ }),
888
989
  {
889
990
  id: "anthropic-fable-5-2026-06-09",
890
991
  priceVersion: "anthropic-2026-06-09",
@@ -1086,6 +1187,12 @@ var init_retail_pricing = __esm({
1086
1187
  ["deepseek-v4-flash-vision-exp", 0.22, 0.66, 7e-3]
1087
1188
  ];
1088
1189
  DEEPSEEK_OFFICIAL_EFFECTIVE_FROM = "2026-08-17T00:00:00.000Z";
1190
+ GOOGLE_ANTIGRAVITY_SOURCE = {
1191
+ title: "Google Gemini API pricing",
1192
+ url: "https://ai.google.dev/pricing",
1193
+ retrievedAt: "2026-09-02"
1194
+ };
1195
+ GOOGLE_ANTIGRAVITY_EFFECTIVE_FROM = "2026-01-01T00:00:00.000Z";
1089
1196
  DIRECT_OFFICIAL_PRICING_CATALOG = {
1090
1197
  version: "2026-08-28-grok-4.6-build",
1091
1198
  entries: [
@@ -1222,11 +1329,91 @@ var init_retail_pricing = __esm({
1222
1329
  output: 12,
1223
1330
  cacheRead: 1,
1224
1331
  contextRule: { kind: "prompt-tokens", minimumExclusive: 2e5 }
1332
+ }),
1333
+ antigravityEntry({
1334
+ id: "antigravity-gemini-3.7-flash-2026-09-02",
1335
+ model: "gemini-3.7-flash",
1336
+ aliases: [
1337
+ "gemini-3.7-flash-high",
1338
+ "gemini-3.7-flash-medium",
1339
+ "gemini-3.7-flash-low",
1340
+ "gemini-3p7-flash-exp-d",
1341
+ "gemini-3.7-flash-exp",
1342
+ "Gemini 3.7 Flash (High)",
1343
+ "Gemini 3.7 Flash (Medium)",
1344
+ "Gemini 3.7 Flash (Low)"
1345
+ ],
1346
+ input: 0.1,
1347
+ output: 0.4,
1348
+ cacheRead: 0.025
1349
+ }),
1350
+ antigravityEntry({
1351
+ id: "antigravity-gemini-3.6-flash-2026-09-02",
1352
+ model: "gemini-3.6-flash",
1353
+ aliases: [
1354
+ "gemini-3.6-flash-high",
1355
+ "gemini-3.6-flash-medium",
1356
+ "gemini-3.6-flash-low",
1357
+ "Gemini 3.6 Flash (High)",
1358
+ "Gemini 3.6 Flash (Medium)",
1359
+ "Gemini 3.6 Flash (Low)"
1360
+ ],
1361
+ input: 0.1,
1362
+ output: 0.4,
1363
+ cacheRead: 0.025
1364
+ }),
1365
+ antigravityEntry({
1366
+ id: "antigravity-gemini-3.1-pro-2026-09-02",
1367
+ model: "gemini-3.1-pro",
1368
+ aliases: [
1369
+ "gemini-3.1-pro-high",
1370
+ "gemini-3.1-pro-low",
1371
+ "gemini-3p1-pro-exp",
1372
+ "Gemini 3.1 Pro (High)",
1373
+ "Gemini 3.1 Pro (Low)"
1374
+ ],
1375
+ input: 1.25,
1376
+ output: 5,
1377
+ cacheRead: 0.3125
1378
+ }),
1379
+ antigravityEntry({
1380
+ id: "antigravity-claude-sonnet-4-6-2026-09-02",
1381
+ model: "claude-sonnet-4-6",
1382
+ aliases: ["claude-sonnet-4-6-thinking", "Claude Sonnet 4.6 (Thinking)"],
1383
+ input: 3,
1384
+ output: 15,
1385
+ cacheRead: 0.3,
1386
+ source: {
1387
+ title: "Anthropic Claude API pricing",
1388
+ url: "https://platform.claude.com/docs/en/about-claude/pricing",
1389
+ retrievedAt: "2026-09-02"
1390
+ }
1391
+ }),
1392
+ antigravityEntry({
1393
+ id: "antigravity-claude-opus-4-6-2026-09-02",
1394
+ model: "claude-opus-4-6-thinking",
1395
+ aliases: ["claude-opus-4-6", "Claude Opus 4.6 (Thinking)"],
1396
+ input: 15,
1397
+ output: 75,
1398
+ cacheRead: 1.5,
1399
+ source: {
1400
+ title: "Anthropic Claude API pricing",
1401
+ url: "https://platform.claude.com/docs/en/about-claude/pricing",
1402
+ retrievedAt: "2026-09-02"
1403
+ }
1404
+ }),
1405
+ antigravityEntry({
1406
+ id: "antigravity-gpt-oss-120b-2026-09-02",
1407
+ model: "gpt-oss-120b-medium",
1408
+ aliases: ["gpt-oss-120b", "GPT-OSS 120B (Medium)"],
1409
+ input: 0.15,
1410
+ output: 0.6,
1411
+ cacheRead: 0.05
1225
1412
  })
1226
1413
  ]
1227
1414
  };
1228
1415
  OFFICIAL_PRICING_CATALOG = {
1229
- version: "2026-09-01-dsh-deepseek-official",
1416
+ version: "2026-09-03-fable-5.1",
1230
1417
  entries: [
1231
1418
  ...DIRECT_OFFICIAL_PRICING_CATALOG.entries,
1232
1419
  ...openCodeLocalHistoryEntries(DIRECT_OFFICIAL_PRICING_CATALOG.entries)
@@ -1612,6 +1799,7 @@ var init_plan_pricing = __esm({
1612
1799
  });
1613
1800
 
1614
1801
  // src/core/usage-application.ts
1802
+ import { randomUUID } from "crypto";
1615
1803
  function safeConnectorFailure(error) {
1616
1804
  if (error instanceof Error && "code" in error && typeof error.code === "string" && "recovery" in error && typeof error.recovery === "string") {
1617
1805
  return { code: error.code, message: error.message, recovery: error.recovery };
@@ -1719,7 +1907,7 @@ function notificationLevel(value) {
1719
1907
  function pickAgentProviderIndex(overview) {
1720
1908
  return {
1721
1909
  generatedAt: overview.generatedAt,
1722
- providers: overview.providers.filter((provider) => provider.id !== "opencode").map(({ id, displayName }) => ({ id, displayName }))
1910
+ providers: overview.providers.filter((provider) => provider.id !== "opencode" && provider.id !== "dsh").map(({ id, displayName }) => ({ id, displayName }))
1723
1911
  };
1724
1912
  }
1725
1913
  var UsageApplication;
@@ -1743,6 +1931,7 @@ var init_usage_application = __esm({
1743
1931
  #connectorPolicies;
1744
1932
  #notifier;
1745
1933
  #startAtLoginManager;
1934
+ #basePriceCatalog;
1746
1935
  #priceCatalog;
1747
1936
  #planCatalog;
1748
1937
  #refreshPromise = null;
@@ -1765,10 +1954,16 @@ var init_usage_application = __esm({
1765
1954
  this.#connectorPolicies = options.connectorPolicies ?? {};
1766
1955
  this.#notifier = options.notifier;
1767
1956
  this.#startAtLoginManager = options.startAtLoginManager;
1768
- this.#priceCatalog = options.priceCatalog === void 0 ? OFFICIAL_PRICING_CATALOG : options.priceCatalog;
1957
+ this.#basePriceCatalog = options.priceCatalog === void 0 ? OFFICIAL_PRICING_CATALOG : options.priceCatalog;
1958
+ this.#priceCatalog = this.#resolvePriceCatalog();
1769
1959
  this.#planCatalog = options.planCatalog ?? SUBSCRIPTION_PLAN_CATALOG;
1770
1960
  this.#processingStatus = createProcessingStatus(this.#clock().toISOString(), false);
1771
1961
  }
1962
+ #resolvePriceCatalog() {
1963
+ if (!this.#basePriceCatalog) return null;
1964
+ const customRates = this.#repository.getCustomModelRates?.() ?? [];
1965
+ return mergeCatalogWithCustomRates(this.#basePriceCatalog, customRates);
1966
+ }
1772
1967
  async #backfillRetailCosts(mode) {
1773
1968
  if (!this.#priceCatalog || !this.#repository.getRetailPricingBackfillPage && !this.#repository.getRetailPricingBackfillSnapshots || !this.#repository.saveDerivedCosts) {
1774
1969
  return;
@@ -2115,6 +2310,57 @@ var init_usage_application = __esm({
2115
2310
  });
2116
2311
  return this.getPlanSettings();
2117
2312
  }
2313
+ async getCustomModelRates() {
2314
+ return this.#repository.getCustomModelRates?.() ?? [];
2315
+ }
2316
+ async getCustomModelRate(id) {
2317
+ return this.#repository.getCustomModelRate?.(id) ?? null;
2318
+ }
2319
+ async setCustomModelRate(input) {
2320
+ const providerId = input.providerId?.trim();
2321
+ if (!providerId) throw new Error("Provider ID is required");
2322
+ const model = input.model?.trim();
2323
+ if (!model) throw new Error("Model name is required");
2324
+ if (!Number.isFinite(input.inputRate) || input.inputRate < 0) {
2325
+ throw new Error("Input rate must be a non-negative number");
2326
+ }
2327
+ if (!Number.isFinite(input.outputRate) || input.outputRate < 0) {
2328
+ throw new Error("Output rate must be a non-negative number");
2329
+ }
2330
+ const cacheReadRate = input.cacheReadRate ?? 0;
2331
+ if (!Number.isFinite(cacheReadRate) || cacheReadRate < 0) {
2332
+ throw new Error("Cache read rate must be a non-negative number");
2333
+ }
2334
+ const rate = {
2335
+ id: input.id || `rate-${randomUUID()}`,
2336
+ providerId,
2337
+ billingDomainId: input.billingDomainId?.trim() || null,
2338
+ model,
2339
+ ratesPerMillion: {
2340
+ input: input.inputRate,
2341
+ output: input.outputRate,
2342
+ cacheRead: cacheReadRate
2343
+ },
2344
+ updatedAt: this.#clock().toISOString()
2345
+ };
2346
+ await this.#queueDatabaseWrite(() => {
2347
+ this.#repository.saveCustomModelRate?.(rate);
2348
+ });
2349
+ this.#priceCatalog = this.#resolvePriceCatalog();
2350
+ await this.#backfillRetailCosts("hard-rebuild");
2351
+ return rate;
2352
+ }
2353
+ async deleteCustomModelRate(id) {
2354
+ let deleted = false;
2355
+ await this.#queueDatabaseWrite(() => {
2356
+ deleted = this.#repository.deleteCustomModelRate?.(id) ?? false;
2357
+ });
2358
+ if (deleted) {
2359
+ this.#priceCatalog = this.#resolvePriceCatalog();
2360
+ await this.#backfillRetailCosts("hard-rebuild");
2361
+ }
2362
+ return deleted;
2363
+ }
2118
2364
  /**
2119
2365
  * A billing domain can carry a plan price when its connector does not report
2120
2366
  * an actual metered charge. Metered domains keep their own billed amounts and
@@ -2301,7 +2547,10 @@ var init_usage_application = __esm({
2301
2547
  return this.#repository.getProviderOverview?.(now, providerId, query) ?? this.#repository.getOverview(now, query).providers.find((provider) => provider.id === providerId) ?? null;
2302
2548
  }
2303
2549
  async exportUsage(request) {
2304
- const overview = this.#repository.getOverview(this.#clock(), request);
2550
+ const overview = this.#repository.getOverview(this.#clock(), {
2551
+ ...request,
2552
+ auditEvidence: true
2553
+ });
2305
2554
  const accountIdentifiers = request.includeAccountIdentifiers ? this.#repository.getProviderAccountIdentifiers() : {};
2306
2555
  return buildUsageExport(overview, request, accountIdentifiers);
2307
2556
  }
@@ -2560,6 +2809,20 @@ var init_catalog = __esm({
2560
2809
  billingDomain: { id: "deepseek-official", displayName: "DeepSeek API" }
2561
2810
  },
2562
2811
  officialCredentialPaths: [".dsh"]
2812
+ },
2813
+ {
2814
+ id: "antigravity",
2815
+ displayName: "Antigravity",
2816
+ command: "agy",
2817
+ permissionDescription: "Read local Antigravity conversation session databases for token history. No credential file is opened.",
2818
+ credentialOwner: "official-client",
2819
+ experimental: true,
2820
+ expectedCoverage: ["quota", "tokens", "history"],
2821
+ target: {
2822
+ provider: { id: "antigravity", displayName: "Antigravity" },
2823
+ billingDomain: { id: "code-assist-subscription", displayName: "Gemini Code Assist" }
2824
+ },
2825
+ officialCredentialPaths: [".gemini/antigravity-cli", ".gemini/antigravity"]
2563
2826
  }
2564
2827
  ];
2565
2828
  }
@@ -4765,14 +5028,785 @@ var init_local_transcript_usage_client = __esm({
4765
5028
  async #persistCache() {
4766
5029
  if (!this.#cachePath) return;
4767
5030
  try {
4768
- await mkdir2(dirname(this.#cachePath), { recursive: true, mode: 448 });
5031
+ await mkdir2(dirname(this.#cachePath), { recursive: true, mode: 448 });
5032
+ const temporary = `${this.#cachePath}.${process.pid}.tmp`;
5033
+ await writeFile2(
5034
+ temporary,
5035
+ JSON.stringify({ version: 1, files: [...this.#fileCache.values()] }),
5036
+ { mode: 384 }
5037
+ );
5038
+ await rename2(temporary, this.#cachePath);
5039
+ } catch {
5040
+ }
5041
+ }
5042
+ };
5043
+ }
5044
+ });
5045
+
5046
+ // src/connectors/dsh/dsh-connector.ts
5047
+ function billingDomains(usage) {
5048
+ const primary = { id: DSH_PRIMARY_BILLING_DOMAIN_ID, displayName: "DeepSeek API" };
5049
+ const observedRoutes = [...new Set(usage.map((observation) => observation.billingDomainId))].filter((id) => id !== primary.id).sort();
5050
+ return [primary, ...observedRoutes.map((id) => ({ id, displayName: id }))];
5051
+ }
5052
+ function incompleteSessionLogFailure() {
5053
+ return {
5054
+ code: "dsh-session-log-scan-incomplete",
5055
+ message: "Some local dsh session history could not be read.",
5056
+ recovery: "Agent Usage will retry automatically without removing stored history."
5057
+ };
5058
+ }
5059
+ function unsupportedFormatFailure() {
5060
+ return {
5061
+ code: "dsh-session-format-unsupported",
5062
+ message: "A dsh session log declares an on-disk format this version does not read.",
5063
+ recovery: "Update Agent Usage; stored dsh history from earlier scans is retained."
5064
+ };
5065
+ }
5066
+ function safeFailure5(error) {
5067
+ if (error instanceof Error && "code" in error && typeof error.code === "string" && "recovery" in error && typeof error.recovery === "string") {
5068
+ return { code: error.code, message: error.message, recovery: error.recovery };
5069
+ }
5070
+ return {
5071
+ code: "dsh-session-log-read-failed",
5072
+ message: "Local dsh session history is unavailable.",
5073
+ recovery: "Run agent-usage doctor, then retry refresh."
5074
+ };
5075
+ }
5076
+ var DshConnector;
5077
+ var init_dsh_connector = __esm({
5078
+ "src/connectors/dsh/dsh-connector.ts"() {
5079
+ "use strict";
5080
+ init_local_transcript_usage_client();
5081
+ DshConnector = class {
5082
+ id = "dsh";
5083
+ displayName = "dsh";
5084
+ consentId = "dsh";
5085
+ #historyClient;
5086
+ #clock;
5087
+ constructor(options) {
5088
+ this.#historyClient = options.historyClient;
5089
+ this.#clock = options.clock ?? (() => /* @__PURE__ */ new Date());
5090
+ }
5091
+ async collect(options = { mode: "incremental" }) {
5092
+ const observedAt = this.#clock().toISOString();
5093
+ const warnings = [];
5094
+ let history = null;
5095
+ try {
5096
+ history = await this.#historyClient.readUsage(options);
5097
+ } catch (error) {
5098
+ warnings.push(safeFailure5(error));
5099
+ }
5100
+ if (history?.unsupportedFormat) warnings.push(unsupportedFormatFailure());
5101
+ else if (history && !history.complete) warnings.push(incompleteSessionLogFailure());
5102
+ const usage = history?.usage ?? [];
5103
+ return {
5104
+ provider: { id: this.id, displayName: this.displayName },
5105
+ billingDomains: billingDomains(usage),
5106
+ quotaBuckets: [],
5107
+ usage,
5108
+ ...usage.length > 0 && history?.complete ? {
5109
+ usageReconciliation: {
5110
+ authoritativeIdPrefixes: ["dsh-transcript:"],
5111
+ retiredIdPrefixes: []
5112
+ }
5113
+ } : {},
5114
+ costs: history?.costs ?? [],
5115
+ warnings,
5116
+ observedAt
5117
+ };
5118
+ }
5119
+ };
5120
+ }
5121
+ });
5122
+
5123
+ // src/server/antigravity-quota-client.ts
5124
+ import { readdirSync, readFileSync } from "fs";
5125
+ import { homedir as homedir2 } from "os";
5126
+ import { join as join4 } from "path";
5127
+ function mapQuotaGroups(groups) {
5128
+ const buckets = [];
5129
+ for (const group of groups) {
5130
+ const isGemini = /gemini/i.test(group.displayName ?? "");
5131
+ const isClaudeOrGpt = /claude|gpt/i.test(group.displayName ?? "");
5132
+ for (const rawBucket of group.buckets ?? []) {
5133
+ const windowStr = (rawBucket.window ?? "").toLowerCase();
5134
+ const displayStr = (rawBucket.displayName ?? "").toLowerCase();
5135
+ const is5h = windowStr === "5h" || /5[- ]?hour/i.test(displayStr);
5136
+ const isWeekly = windowStr === "weekly" || /week/i.test(displayStr);
5137
+ let durationMinutes;
5138
+ let windowName;
5139
+ if (is5h) {
5140
+ durationMinutes = 300;
5141
+ windowName = "5 hour";
5142
+ } else if (isWeekly) {
5143
+ durationMinutes = 10080;
5144
+ windowName = "Week";
5145
+ } else {
5146
+ continue;
5147
+ }
5148
+ let label = windowName;
5149
+ if (!isGemini) {
5150
+ if (isClaudeOrGpt) {
5151
+ label = `Claude / GPT \xB7 ${windowName}`;
5152
+ } else if (group.displayName) {
5153
+ label = `${group.displayName} \xB7 ${windowName}`;
5154
+ }
5155
+ }
5156
+ const usedPercent = typeof rawBucket.remainingFraction === "number" ? Math.max(0, Math.min(100, Math.round((1 - rawBucket.remainingFraction) * 100))) : null;
5157
+ buckets.push({
5158
+ id: rawBucket.bucketId || `${isGemini ? "gemini" : "3p"}-${windowStr}`,
5159
+ billingDomainId: ANTIGRAVITY_PRIMARY_BILLING_DOMAIN_ID,
5160
+ label,
5161
+ usedPercent,
5162
+ windowDurationMinutes: durationMinutes,
5163
+ resetsAt: rawBucket.resetTime ?? null,
5164
+ authority: "official-client",
5165
+ scope: "account-wide"
5166
+ });
5167
+ }
5168
+ }
5169
+ return buckets;
5170
+ }
5171
+ var AntigravityQuotaClient;
5172
+ var init_antigravity_quota_client = __esm({
5173
+ "src/server/antigravity-quota-client.ts"() {
5174
+ "use strict";
5175
+ init_antigravity_connector();
5176
+ AntigravityQuotaClient = class {
5177
+ #logRoots;
5178
+ #ports;
5179
+ #fetchFn;
5180
+ #timeoutMs;
5181
+ constructor(options = {}) {
5182
+ this.#logRoots = options.logRoots ?? [
5183
+ join4(homedir2(), "Library/Logs/Antigravity"),
5184
+ join4(homedir2(), ".gemini/antigravity-cli/log"),
5185
+ join4(homedir2(), ".gemini/antigravity/log")
5186
+ ];
5187
+ this.#ports = options.ports;
5188
+ this.#fetchFn = options.fetchFn ?? globalThis.fetch;
5189
+ this.#timeoutMs = options.timeoutMs ?? 1500;
5190
+ }
5191
+ async readQuota() {
5192
+ const { ports, csrfToken } = this.discoverCandidates();
5193
+ const candidatePorts = this.#ports ?? ports;
5194
+ if (candidatePorts.length === 0) {
5195
+ return null;
5196
+ }
5197
+ for (const port of candidatePorts) {
5198
+ const quota = await this.queryPort(port, csrfToken);
5199
+ if (quota) {
5200
+ return quota;
5201
+ }
5202
+ }
5203
+ return null;
5204
+ }
5205
+ discoverCandidates() {
5206
+ let csrfToken = process.env.ANTIGRAVITY_CSRF_TOKEN ?? null;
5207
+ const ports = [];
5208
+ const httpPortRegex = /(?:Language server listening on random port at|Reloading all windows with URL: https?:\/\/127\.0\.0\.1:|Local:\s+https?:\/\/127\.0\.0\.1:|Host bridge server listening on http:\/\/127\.0\.0\.1:)\s*(\d+)/g;
5209
+ const csrfRegex = /--csrf_token[= ]([a-f0-9-]+)/;
5210
+ for (const root of this.#logRoots) {
5211
+ try {
5212
+ const files = readdirSync(root).filter((file) => file.endsWith(".log")).sort().reverse().slice(0, 10);
5213
+ for (const file of files) {
5214
+ const filePath = join4(root, file);
5215
+ try {
5216
+ const content = readFileSync(filePath, "utf8");
5217
+ if (!csrfToken) {
5218
+ const csrfMatch = csrfRegex.exec(content);
5219
+ if (csrfMatch) csrfToken = csrfMatch[1];
5220
+ }
5221
+ let match;
5222
+ while ((match = httpPortRegex.exec(content)) !== null) {
5223
+ const basePort = Number(match[1]);
5224
+ ports.push(basePort);
5225
+ ports.push(basePort + 1);
5226
+ ports.push(basePort + 2);
5227
+ }
5228
+ } catch {
5229
+ }
5230
+ }
5231
+ } catch {
5232
+ }
5233
+ }
5234
+ return {
5235
+ ports: [...new Set(ports.reverse())],
5236
+ csrfToken
5237
+ };
5238
+ }
5239
+ discoverCandidatePorts() {
5240
+ return this.discoverCandidates().ports;
5241
+ }
5242
+ async queryPort(port, csrfToken = null) {
5243
+ try {
5244
+ const url = `http://127.0.0.1:${port}/exa.language_server_pb.LanguageServerService/RetrieveUserQuotaSummary`;
5245
+ const response = await this.#fetchFn(url, {
5246
+ method: "POST",
5247
+ headers: {
5248
+ "Content-Type": "application/json",
5249
+ "Connect-Protocol-Version": "1",
5250
+ ...csrfToken ? { "x-codeium-csrf-token": csrfToken } : {}
5251
+ },
5252
+ body: JSON.stringify({}),
5253
+ signal: AbortSignal.timeout(this.#timeoutMs)
5254
+ });
5255
+ if (!response.ok) {
5256
+ return null;
5257
+ }
5258
+ const body = await response.json();
5259
+ const groups = body.response?.groups;
5260
+ if (!Array.isArray(groups) || groups.length === 0) {
5261
+ return null;
5262
+ }
5263
+ return mapQuotaGroups(groups);
5264
+ } catch {
5265
+ return null;
5266
+ }
5267
+ }
5268
+ };
5269
+ }
5270
+ });
5271
+
5272
+ // src/connectors/antigravity/antigravity-connector.ts
5273
+ function buildAntigravityQuotaBuckets(usage, nowMs, limits = DEFAULT_ANTIGRAVITY_QUOTA_LIMITS) {
5274
+ const fiveHoursMs = 300 * 60 * 1e3;
5275
+ const sevenDaysMs = 7 * 24 * 60 * 60 * 1e3;
5276
+ const cutoff5h = nowMs - fiveHoursMs;
5277
+ const cutoff7d = nowMs - sevenDaysMs;
5278
+ const obs5h = [];
5279
+ const obs7d = [];
5280
+ for (const obs of usage) {
5281
+ const t = new Date(obs.observedAt).getTime();
5282
+ if (t >= cutoff5h) obs5h.push(obs);
5283
+ if (t >= cutoff7d) obs7d.push(obs);
5284
+ }
5285
+ const tokens5h = obs5h.reduce(
5286
+ (acc, obs) => acc + obs.inputTokens + obs.outputTokens + obs.cacheReadTokens,
5287
+ 0
5288
+ );
5289
+ const usedPercent5h = Math.min(100, Math.round(tokens5h / limits.rolling5hTokens * 100));
5290
+ let resetsAt5h;
5291
+ if (obs5h.length > 0) {
5292
+ const oldestMs = Math.min(...obs5h.map((o) => new Date(o.observedAt).getTime()));
5293
+ resetsAt5h = new Date(oldestMs + fiveHoursMs).toISOString();
5294
+ } else {
5295
+ resetsAt5h = new Date(nowMs + fiveHoursMs).toISOString();
5296
+ }
5297
+ const tokens7d = obs7d.reduce(
5298
+ (acc, obs) => acc + obs.inputTokens + obs.outputTokens + obs.cacheReadTokens,
5299
+ 0
5300
+ );
5301
+ const usedPercent7d = Math.min(100, Math.round(tokens7d / limits.weeklyTokens * 100));
5302
+ let resetsAt7d;
5303
+ if (obs7d.length > 0) {
5304
+ const oldestMs = Math.min(...obs7d.map((o) => new Date(o.observedAt).getTime()));
5305
+ resetsAt7d = new Date(oldestMs + sevenDaysMs).toISOString();
5306
+ } else {
5307
+ resetsAt7d = new Date(nowMs + sevenDaysMs).toISOString();
5308
+ }
5309
+ return [
5310
+ {
5311
+ id: "gemini-5h",
5312
+ billingDomainId: ANTIGRAVITY_PRIMARY_BILLING_DOMAIN_ID,
5313
+ label: "5 hour",
5314
+ usedPercent: usedPercent5h,
5315
+ windowDurationMinutes: 300,
5316
+ resetsAt: resetsAt5h,
5317
+ authority: "local-observation",
5318
+ scope: "local-only"
5319
+ },
5320
+ {
5321
+ id: "gemini-weekly",
5322
+ billingDomainId: ANTIGRAVITY_PRIMARY_BILLING_DOMAIN_ID,
5323
+ label: "Week",
5324
+ usedPercent: usedPercent7d,
5325
+ windowDurationMinutes: 10080,
5326
+ resetsAt: resetsAt7d,
5327
+ authority: "local-observation",
5328
+ scope: "local-only"
5329
+ }
5330
+ ];
5331
+ }
5332
+ function billingDomains2(usage) {
5333
+ const primary = {
5334
+ id: ANTIGRAVITY_PRIMARY_BILLING_DOMAIN_ID,
5335
+ displayName: "Gemini Code Assist"
5336
+ };
5337
+ const observedRoutes = [...new Set(usage.map((obs) => obs.billingDomainId))].filter((id) => id !== primary.id).sort();
5338
+ return [primary, ...observedRoutes.map((id) => ({ id, displayName: id }))];
5339
+ }
5340
+ function incompleteSessionScanFailure() {
5341
+ return {
5342
+ code: "antigravity-session-scan-incomplete",
5343
+ message: "Some local Antigravity conversation databases could not be read.",
5344
+ recovery: "Agent Usage will retry automatically on the next scan without removing stored history."
5345
+ };
5346
+ }
5347
+ function safeFailure6() {
5348
+ return {
5349
+ code: "antigravity-sqlite-read-failed",
5350
+ message: "Failed to read local Antigravity conversation stores.",
5351
+ recovery: "Check read permissions for ~/.gemini/antigravity-cli and ~/.gemini/antigravity directories."
5352
+ };
5353
+ }
5354
+ var ANTIGRAVITY_PRIMARY_BILLING_DOMAIN_ID, DEFAULT_ANTIGRAVITY_QUOTA_LIMITS, AntigravityConnector;
5355
+ var init_antigravity_connector = __esm({
5356
+ "src/connectors/antigravity/antigravity-connector.ts"() {
5357
+ "use strict";
5358
+ init_antigravity_quota_client();
5359
+ ANTIGRAVITY_PRIMARY_BILLING_DOMAIN_ID = "code-assist-subscription";
5360
+ DEFAULT_ANTIGRAVITY_QUOTA_LIMITS = {
5361
+ rolling5hTokens: 15e6,
5362
+ weeklyTokens: 1e8
5363
+ };
5364
+ AntigravityConnector = class {
5365
+ id = "antigravity";
5366
+ displayName = "Antigravity";
5367
+ consentId = "antigravity";
5368
+ #historyClient;
5369
+ #quotaClient;
5370
+ #clock;
5371
+ #quotaLimits;
5372
+ constructor(options) {
5373
+ this.#historyClient = options.historyClient;
5374
+ this.#quotaClient = options.quotaClient ?? new AntigravityQuotaClient();
5375
+ this.#clock = options.clock ?? (() => /* @__PURE__ */ new Date());
5376
+ this.#quotaLimits = {
5377
+ rolling5hTokens: options.quotaLimits?.rolling5hTokens ?? DEFAULT_ANTIGRAVITY_QUOTA_LIMITS.rolling5hTokens,
5378
+ weeklyTokens: options.quotaLimits?.weeklyTokens ?? DEFAULT_ANTIGRAVITY_QUOTA_LIMITS.weeklyTokens
5379
+ };
5380
+ }
5381
+ async collect(options = { mode: "incremental" }) {
5382
+ const observedAt = this.#clock().toISOString();
5383
+ const nowMs = this.#clock().getTime();
5384
+ const warnings = [];
5385
+ let history = null;
5386
+ try {
5387
+ history = await this.#historyClient.readUsage(options);
5388
+ } catch {
5389
+ warnings.push(safeFailure6());
5390
+ }
5391
+ if (history && !history.complete) {
5392
+ warnings.push(incompleteSessionScanFailure());
5393
+ }
5394
+ const usage = history?.usage ?? [];
5395
+ let quotaBuckets = [];
5396
+ try {
5397
+ const liveQuota = await this.#quotaClient.readQuota();
5398
+ if (liveQuota && liveQuota.length > 0) {
5399
+ quotaBuckets = [...liveQuota];
5400
+ }
5401
+ } catch {
5402
+ }
5403
+ const localBuckets = buildAntigravityQuotaBuckets(usage, nowMs, this.#quotaLimits);
5404
+ const has5h = quotaBuckets.some((b) => b.label === "5 hour" || b.id === "gemini-5h");
5405
+ const hasWeekly = quotaBuckets.some((b) => b.label === "Week" || b.id === "gemini-weekly");
5406
+ if (!has5h || !hasWeekly) {
5407
+ for (const localBucket of localBuckets) {
5408
+ if (!quotaBuckets.some((b) => b.id === localBucket.id || b.label === localBucket.label)) {
5409
+ quotaBuckets.push(localBucket);
5410
+ }
5411
+ }
5412
+ }
5413
+ return {
5414
+ provider: { id: this.id, displayName: this.displayName },
5415
+ billingDomains: billingDomains2(usage),
5416
+ quotaBuckets,
5417
+ usage,
5418
+ ...usage.length > 0 && history?.complete ? {
5419
+ usageReconciliation: {
5420
+ authoritativeIdPrefixes: ["antigravity:"],
5421
+ retiredIdPrefixes: []
5422
+ }
5423
+ } : {},
5424
+ costs: history?.costs ?? [],
5425
+ warnings,
5426
+ observedAt
5427
+ };
5428
+ }
5429
+ };
5430
+ }
5431
+ });
5432
+
5433
+ // src/server/antigravity-sqlite-usage-client.ts
5434
+ import { createHash as createHash3 } from "crypto";
5435
+ import { readdir, readFile as readFile4, rename as rename3, stat as stat2, writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
5436
+ import { createRequire as createRequire2 } from "module";
5437
+ import { dirname as dirname2, join as join5 } from "path";
5438
+ import protobuf from "protobufjs";
5439
+ function parseAntigravityDatabase(dbPath, conversationId, fallbackMtimeMs) {
5440
+ const db = new DatabaseSync2(dbPath, { readOnly: true });
5441
+ try {
5442
+ const tableExists = db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name='gen_metadata'").get();
5443
+ if (!tableExists) return [];
5444
+ const stepTimestamps = /* @__PURE__ */ new Map();
5445
+ try {
5446
+ const stepRows = db.prepare("SELECT idx, metadata FROM steps WHERE length(metadata) > 0").all();
5447
+ for (const row of stepRows) {
5448
+ const ts = extractTimestampFromStepMetadata(row.metadata);
5449
+ if (ts !== null) stepTimestamps.set(row.idx, ts);
5450
+ }
5451
+ } catch {
5452
+ }
5453
+ const genRows = db.prepare("SELECT idx, data FROM gen_metadata ORDER BY idx ASC").all();
5454
+ const records = [];
5455
+ for (const row of genRows) {
5456
+ if (!row.data || row.data.length === 0) continue;
5457
+ const parsed = decodeGenMetadata(row.data);
5458
+ if (parsed.inputTokens === 0 && parsed.outputTokens === 0 && parsed.cacheReadTokens === 0) {
5459
+ continue;
5460
+ }
5461
+ const timestampMs = stepTimestamps.get(row.idx) ?? fallbackMtimeMs;
5462
+ const observedAt = new Date(timestampMs).toISOString();
5463
+ const dedupeKey = `antigravity:${conversationId}:${row.idx}`;
5464
+ const observation = {
5465
+ id: dedupeKey,
5466
+ billingDomainId: "code-assist-subscription",
5467
+ model: parsed.canonicalModel,
5468
+ observedAt,
5469
+ inputTokens: parsed.inputTokens,
5470
+ outputTokens: parsed.outputTokens,
5471
+ reasoningTokens: 0,
5472
+ cacheReadTokens: parsed.cacheReadTokens,
5473
+ cacheWriteTokens: 0,
5474
+ tokenSemantics: {
5475
+ reasoning: "included-in-output",
5476
+ cacheRead: "separate",
5477
+ cacheWrite: "separate"
5478
+ },
5479
+ modelAttribution: "known",
5480
+ timePrecision: "event",
5481
+ usageScope: "this-mac",
5482
+ aggregationTemporality: "delta",
5483
+ authority: "local-observation"
5484
+ };
5485
+ normalizeTokenObservation(observation);
5486
+ records.push({ dedupeKey, observation });
5487
+ }
5488
+ return records;
5489
+ } finally {
5490
+ db.close();
5491
+ }
5492
+ }
5493
+ function decodeGenMetadata(buf) {
5494
+ let rawModel = "unknown";
5495
+ let inputTokens = 0;
5496
+ const outputTokens = 0;
5497
+ let cacheReadTokens = 0;
5498
+ try {
5499
+ const r = protobuf.Reader.create(buf);
5500
+ while (r.pos < r.len) {
5501
+ const tag = r.uint32();
5502
+ const fn = tag >>> 3;
5503
+ const wt = tag & 7;
5504
+ if (fn === 1 && wt === 2) {
5505
+ const sub1 = r.bytes();
5506
+ const rSub = protobuf.Reader.create(sub1);
5507
+ while (rSub.pos < rSub.len) {
5508
+ const sTag = rSub.uint32();
5509
+ const sFn = sTag >>> 3;
5510
+ const sWt = sTag & 7;
5511
+ if (sFn === 19 && sWt === 2) {
5512
+ rawModel = Buffer.from(rSub.bytes()).toString("utf8");
5513
+ } else if (sFn === 9 && sWt === 2) {
5514
+ const sub9 = rSub.bytes();
5515
+ const r9 = protobuf.Reader.create(sub9);
5516
+ while (r9.pos < r9.len) {
5517
+ const t9 = r9.uint32();
5518
+ const fn9 = t9 >>> 3;
5519
+ const wt9 = t9 & 7;
5520
+ if (fn9 === 10 && wt9 === 2) {
5521
+ const sub10 = r9.bytes();
5522
+ const r10 = protobuf.Reader.create(sub10);
5523
+ while (r10.pos < r10.len) {
5524
+ const t10 = r10.uint32();
5525
+ const fn10 = t10 >>> 3;
5526
+ const wt10 = t10 & 7;
5527
+ if (fn10 === 1 && wt10 === 0) {
5528
+ inputTokens = toNumeric(r10.uint64());
5529
+ } else if (fn10 === 3 && wt10 === 2) {
5530
+ const sub3 = r10.bytes();
5531
+ const r3 = protobuf.Reader.create(sub3);
5532
+ while (r3.pos < r3.len) {
5533
+ const t3 = r3.uint32();
5534
+ const fn3 = t3 >>> 3;
5535
+ const wt3 = t3 & 7;
5536
+ if (fn3 === 2 && wt3 === 0) {
5537
+ cacheReadTokens = toNumeric(r3.uint64());
5538
+ } else {
5539
+ r3.skipType(wt3);
5540
+ }
5541
+ }
5542
+ } else {
5543
+ r10.skipType(wt10);
5544
+ }
5545
+ }
5546
+ } else {
5547
+ r9.skipType(wt9);
5548
+ }
5549
+ }
5550
+ } else {
5551
+ rSub.skipType(sWt);
5552
+ }
5553
+ }
5554
+ } else {
5555
+ r.skipType(wt);
5556
+ }
5557
+ }
5558
+ } catch {
5559
+ }
5560
+ return {
5561
+ rawModel,
5562
+ canonicalModel: canonicalizeAntigravityModel(rawModel),
5563
+ inputTokens,
5564
+ outputTokens,
5565
+ cacheReadTokens
5566
+ };
5567
+ }
5568
+ function canonicalizeAntigravityModel(raw) {
5569
+ const normalized = raw.trim().toLowerCase().replace(/[\s_]+/g, "-");
5570
+ if (normalized.startsWith("gemini-3p7") || normalized.startsWith("gemini-3.7")) {
5571
+ return "gemini-3.7-flash";
5572
+ }
5573
+ if (normalized.startsWith("gemini-3p6") || normalized.startsWith("gemini-3.6")) {
5574
+ return "gemini-3.6-flash";
5575
+ }
5576
+ if (normalized.startsWith("gemini-3p1") || normalized.startsWith("gemini-3.1")) {
5577
+ return "gemini-3.1-pro";
5578
+ }
5579
+ if (normalized.includes("claude-sonnet")) {
5580
+ return "claude-sonnet-4-6";
5581
+ }
5582
+ if (normalized.includes("claude-opus")) {
5583
+ return "claude-opus-4-6-thinking";
5584
+ }
5585
+ if (normalized.includes("gpt-oss")) {
5586
+ return "gpt-oss-120b-medium";
5587
+ }
5588
+ return raw.trim() || "unknown";
5589
+ }
5590
+ function extractTimestampFromStepMetadata(buf) {
5591
+ try {
5592
+ const r = protobuf.Reader.create(buf);
5593
+ while (r.pos < r.len) {
5594
+ const tag = r.uint32();
5595
+ const fn = tag >>> 3;
5596
+ const wt = tag & 7;
5597
+ if (fn === 1 && wt === 2) {
5598
+ const tsBytes = r.bytes();
5599
+ const rTs = protobuf.Reader.create(tsBytes);
5600
+ let seconds = 0;
5601
+ let nanos = 0;
5602
+ while (rTs.pos < rTs.len) {
5603
+ const t = rTs.uint32();
5604
+ const tFn = t >>> 3;
5605
+ const tWt = t & 7;
5606
+ if (tFn === 1 && tWt === 0) {
5607
+ seconds = toNumeric(rTs.uint64());
5608
+ } else if (tFn === 2 && tWt === 0) {
5609
+ nanos = toNumeric(rTs.uint64());
5610
+ } else {
5611
+ rTs.skipType(tWt);
5612
+ }
5613
+ }
5614
+ if (seconds > 0) {
5615
+ return seconds * 1e3 + Math.floor(nanos / 1e6);
5616
+ }
5617
+ } else {
5618
+ r.skipType(wt);
5619
+ }
5620
+ }
5621
+ } catch {
5622
+ }
5623
+ return null;
5624
+ }
5625
+ function toNumeric(val) {
5626
+ return Number(val?.toString?.() ?? 0);
5627
+ }
5628
+ function stableId2(value) {
5629
+ return createHash3("sha256").update(value).digest("hex").slice(0, 16);
5630
+ }
5631
+ function isCachedDatabaseFile(value) {
5632
+ if (typeof value !== "object" || value === null) return false;
5633
+ const rec = value;
5634
+ return typeof rec.path === "string" && typeof rec.size === "number" && typeof rec.mtimeMs === "number" && Array.isArray(rec.records) && typeof rec.recordsDigest === "string";
5635
+ }
5636
+ var DatabaseSync2, AntigravitySqliteUsageClient;
5637
+ var init_antigravity_sqlite_usage_client = __esm({
5638
+ "src/server/antigravity-sqlite-usage-client.ts"() {
5639
+ "use strict";
5640
+ init_token_normalization();
5641
+ init_retail_pricing();
5642
+ ({ DatabaseSync: DatabaseSync2 } = createRequire2(import.meta.url)(
5643
+ "node:sqlite"
5644
+ ));
5645
+ AntigravitySqliteUsageClient = class {
5646
+ #roots;
5647
+ #clock;
5648
+ #lookbackDays;
5649
+ #cachePath;
5650
+ #priceCatalog;
5651
+ #fileCache = /* @__PURE__ */ new Map();
5652
+ #cacheLoaded = false;
5653
+ constructor(options) {
5654
+ this.#roots = options.roots;
5655
+ this.#clock = options.clock ?? (() => /* @__PURE__ */ new Date());
5656
+ this.#lookbackDays = options.lookbackDays ?? 90;
5657
+ this.#cachePath = options.cachePath;
5658
+ this.#priceCatalog = options.priceCatalog ?? OFFICIAL_PRICING_CATALOG;
5659
+ }
5660
+ async readUsage(options = { mode: "incremental" }) {
5661
+ await this.#loadCache();
5662
+ if (options.mode === "hard-rebuild") this.#fileCache.clear();
5663
+ const cutoff = this.#clock().getTime() - this.#lookbackDays * 24 * 60 * 60 * 1e3;
5664
+ const discoveredFiles = await this.#discoverDatabases(cutoff);
5665
+ const livePaths = new Set(discoveredFiles.map((file) => stableId2(file.path)));
5666
+ for (const path of this.#fileCache.keys()) {
5667
+ if (!livePaths.has(path)) this.#fileCache.delete(path);
5668
+ }
5669
+ const usage = [];
5670
+ const seenDedupeKeys = /* @__PURE__ */ new Set();
5671
+ let allComplete = true;
5672
+ for (const file of discoveredFiles) {
5673
+ const parsed = await this.#parseDatabaseFile(file);
5674
+ allComplete &&= parsed.complete;
5675
+ for (const record of parsed.records) {
5676
+ if (new Date(record.observation.observedAt).getTime() < cutoff) continue;
5677
+ if (seenDedupeKeys.has(record.dedupeKey)) continue;
5678
+ seenDedupeKeys.add(record.dedupeKey);
5679
+ usage.push(record.observation);
5680
+ }
5681
+ }
5682
+ usage.sort((a, b) => a.observedAt.localeCompare(b.observedAt) || a.id.localeCompare(b.id));
5683
+ const { costs } = deriveRetailEquivalentCosts(
5684
+ {
5685
+ provider: { id: "antigravity", displayName: "Antigravity" },
5686
+ billingDomains: [{ id: "code-assist-subscription", displayName: "Gemini Code Assist" }],
5687
+ quotaBuckets: [],
5688
+ usage,
5689
+ costs: [],
5690
+ observedAt: this.#clock().toISOString()
5691
+ },
5692
+ this.#priceCatalog
5693
+ );
5694
+ await this.#persistCache();
5695
+ return {
5696
+ usage,
5697
+ costs,
5698
+ complete: allComplete
5699
+ };
5700
+ }
5701
+ async #discoverDatabases(cutoff) {
5702
+ const results = [];
5703
+ const seenDbPaths = /* @__PURE__ */ new Set();
5704
+ for (const root of this.#roots) {
5705
+ try {
5706
+ const rootStat = await stat2(root);
5707
+ if (!rootStat.isDirectory()) continue;
5708
+ } catch {
5709
+ continue;
5710
+ }
5711
+ const summariesPath = join5(root, "conversation_summaries.db");
5712
+ const candidateIds = /* @__PURE__ */ new Set();
5713
+ let summariesLoaded = false;
5714
+ try {
5715
+ const summariesStat = await stat2(summariesPath);
5716
+ if (summariesStat.isFile()) {
5717
+ const db = new DatabaseSync2(summariesPath, { readOnly: true });
5718
+ try {
5719
+ const rows = db.prepare("SELECT conversation_id, last_modified_time FROM conversation_summaries").all();
5720
+ for (const row of rows) {
5721
+ if (!row.conversation_id) continue;
5722
+ const modifiedMs = row.last_modified_time ? new Date(row.last_modified_time).getTime() : 0;
5723
+ if (modifiedMs >= cutoff || modifiedMs === 0) {
5724
+ candidateIds.add(row.conversation_id);
5725
+ }
5726
+ }
5727
+ summariesLoaded = true;
5728
+ } finally {
5729
+ db.close();
5730
+ }
5731
+ }
5732
+ } catch {
5733
+ }
5734
+ const convDir = join5(root, "conversations");
5735
+ try {
5736
+ const entries = await readdir(convDir);
5737
+ for (const entry of entries) {
5738
+ if (!entry.endsWith(".db")) continue;
5739
+ const convId = entry.slice(0, -3);
5740
+ if (summariesLoaded && candidateIds.size > 0 && !candidateIds.has(convId)) {
5741
+ continue;
5742
+ }
5743
+ const fullPath = join5(convDir, entry);
5744
+ if (seenDbPaths.has(fullPath)) continue;
5745
+ seenDbPaths.add(fullPath);
5746
+ try {
5747
+ const fileStat = await stat2(fullPath);
5748
+ if (fileStat.mtimeMs < cutoff && summariesLoaded) continue;
5749
+ results.push({
5750
+ path: fullPath,
5751
+ size: fileStat.size,
5752
+ mtimeMs: fileStat.mtimeMs,
5753
+ conversationId: convId
5754
+ });
5755
+ } catch {
5756
+ }
5757
+ }
5758
+ } catch {
5759
+ }
5760
+ }
5761
+ return results;
5762
+ }
5763
+ async #parseDatabaseFile(file) {
5764
+ const cached = this.#fileCache.get(stableId2(file.path));
5765
+ if (cached && cached.size === file.size && cached.mtimeMs === file.mtimeMs) {
5766
+ return { records: cached.records, complete: true };
5767
+ }
5768
+ try {
5769
+ const records = parseAntigravityDatabase(file.path, file.conversationId, file.mtimeMs);
5770
+ const digest = stableId2(JSON.stringify(records));
5771
+ this.#fileCache.set(stableId2(file.path), {
5772
+ path: file.path,
5773
+ size: file.size,
5774
+ mtimeMs: file.mtimeMs,
5775
+ records,
5776
+ recordsDigest: digest
5777
+ });
5778
+ return { records, complete: true };
5779
+ } catch {
5780
+ return { records: [], complete: false };
5781
+ }
5782
+ }
5783
+ async #loadCache() {
5784
+ if (this.#cacheLoaded) return;
5785
+ this.#cacheLoaded = true;
5786
+ if (!this.#cachePath) return;
5787
+ try {
5788
+ const content = await readFile4(this.#cachePath, "utf8");
5789
+ const stored = JSON.parse(content);
5790
+ if (stored.version !== 1 || !Array.isArray(stored.files)) return;
5791
+ for (const item of stored.files) {
5792
+ if (!isCachedDatabaseFile(item)) continue;
5793
+ if (item.recordsDigest !== stableId2(JSON.stringify(item.records))) continue;
5794
+ this.#fileCache.set(stableId2(item.path), item);
5795
+ }
5796
+ } catch {
5797
+ }
5798
+ }
5799
+ async #persistCache() {
5800
+ if (!this.#cachePath) return;
5801
+ try {
5802
+ await mkdir3(dirname2(this.#cachePath), { recursive: true, mode: 448 });
4769
5803
  const temporary = `${this.#cachePath}.${process.pid}.tmp`;
4770
- await writeFile2(
5804
+ await writeFile3(
4771
5805
  temporary,
4772
5806
  JSON.stringify({ version: 1, files: [...this.#fileCache.values()] }),
4773
5807
  { mode: 384 }
4774
5808
  );
4775
- await rename2(temporary, this.#cachePath);
5809
+ await rename3(temporary, this.#cachePath);
4776
5810
  } catch {
4777
5811
  }
4778
5812
  }
@@ -4780,83 +5814,6 @@ var init_local_transcript_usage_client = __esm({
4780
5814
  }
4781
5815
  });
4782
5816
 
4783
- // src/connectors/dsh/dsh-connector.ts
4784
- function billingDomains(usage) {
4785
- const primary = { id: DSH_PRIMARY_BILLING_DOMAIN_ID, displayName: "DeepSeek API" };
4786
- const observedRoutes = [...new Set(usage.map((observation) => observation.billingDomainId))].filter((id) => id !== primary.id).sort();
4787
- return [primary, ...observedRoutes.map((id) => ({ id, displayName: id }))];
4788
- }
4789
- function incompleteSessionLogFailure() {
4790
- return {
4791
- code: "dsh-session-log-scan-incomplete",
4792
- message: "Some local dsh session history could not be read.",
4793
- recovery: "Agent Usage will retry automatically without removing stored history."
4794
- };
4795
- }
4796
- function unsupportedFormatFailure() {
4797
- return {
4798
- code: "dsh-session-format-unsupported",
4799
- message: "A dsh session log declares an on-disk format this version does not read.",
4800
- recovery: "Update Agent Usage; stored dsh history from earlier scans is retained."
4801
- };
4802
- }
4803
- function safeFailure5(error) {
4804
- if (error instanceof Error && "code" in error && typeof error.code === "string" && "recovery" in error && typeof error.recovery === "string") {
4805
- return { code: error.code, message: error.message, recovery: error.recovery };
4806
- }
4807
- return {
4808
- code: "dsh-session-log-read-failed",
4809
- message: "Local dsh session history is unavailable.",
4810
- recovery: "Run agent-usage doctor, then retry refresh."
4811
- };
4812
- }
4813
- var DshConnector;
4814
- var init_dsh_connector = __esm({
4815
- "src/connectors/dsh/dsh-connector.ts"() {
4816
- "use strict";
4817
- init_local_transcript_usage_client();
4818
- DshConnector = class {
4819
- id = "dsh";
4820
- displayName = "dsh";
4821
- consentId = "dsh";
4822
- #historyClient;
4823
- #clock;
4824
- constructor(options) {
4825
- this.#historyClient = options.historyClient;
4826
- this.#clock = options.clock ?? (() => /* @__PURE__ */ new Date());
4827
- }
4828
- async collect(options = { mode: "incremental" }) {
4829
- const observedAt = this.#clock().toISOString();
4830
- const warnings = [];
4831
- let history = null;
4832
- try {
4833
- history = await this.#historyClient.readUsage(options);
4834
- } catch (error) {
4835
- warnings.push(safeFailure5(error));
4836
- }
4837
- if (history?.unsupportedFormat) warnings.push(unsupportedFormatFailure());
4838
- else if (history && !history.complete) warnings.push(incompleteSessionLogFailure());
4839
- const usage = history?.usage ?? [];
4840
- return {
4841
- provider: { id: this.id, displayName: this.displayName },
4842
- billingDomains: billingDomains(usage),
4843
- quotaBuckets: [],
4844
- usage,
4845
- ...usage.length > 0 && history?.complete ? {
4846
- usageReconciliation: {
4847
- authoritativeIdPrefixes: ["dsh-transcript:"],
4848
- retiredIdPrefixes: []
4849
- }
4850
- } : {},
4851
- costs: history?.costs ?? [],
4852
- warnings,
4853
- observedAt
4854
- };
4855
- }
4856
- };
4857
- }
4858
- });
4859
-
4860
5817
  // src/connectors/grok-build/grok-build-connector.ts
4861
5818
  import { z as z6 } from "zod";
4862
5819
  function incompleteTranscriptFailure3() {
@@ -4919,7 +5876,7 @@ function derivePercent(used, limit) {
4919
5876
  if (used === void 0 || limit === void 0 || limit <= 0) return null;
4920
5877
  return Math.min(100, Math.max(0, used / limit * 100));
4921
5878
  }
4922
- function safeFailure6(error) {
5879
+ function safeFailure7(error) {
4923
5880
  if (error instanceof Error && "code" in error && typeof error.code === "string" && "recovery" in error && typeof error.recovery === "string") {
4924
5881
  return { code: error.code, message: error.message, recovery: error.recovery };
4925
5882
  }
@@ -4982,7 +5939,7 @@ var init_grok_build_connector = __esm({
4982
5939
  });
4983
5940
  }
4984
5941
  } catch (error) {
4985
- warnings.push(safeFailure6(error));
5942
+ warnings.push(safeFailure7(error));
4986
5943
  }
4987
5944
  const history = this.#historyClient ? await this.#historyClient.readUsage(options) : { usage: [], costs: [], complete: true };
4988
5945
  if (!history.complete) warnings.push(incompleteTranscriptFailure3());
@@ -5123,8 +6080,8 @@ var init_grok_telemetry = __esm({
5123
6080
  // src/connectors/grok-build/stdio-grok-billing-client.ts
5124
6081
  import { spawn as spawn3 } from "child_process";
5125
6082
  import { open } from "fs/promises";
5126
- import { homedir as homedir2 } from "os";
5127
- import { join as join4 } from "path";
6083
+ import { homedir as homedir3 } from "os";
6084
+ import { join as join6 } from "path";
5128
6085
  import { z as z7 } from "zod";
5129
6086
  function billingIsFresh(billing, now) {
5130
6087
  if (!billing.sourceObservedAt) return false;
@@ -5249,7 +6206,7 @@ var init_stdio_grok_billing_client = __esm({
5249
6206
  stdio: ["pipe", "pipe", "pipe"]
5250
6207
  }));
5251
6208
  this.#readUnifiedLog = options.readUnifiedLog ?? (() => readLogTail(
5252
- join4(process.env.GROK_HOME ?? join4(homedir2(), ".grok"), "logs", "unified.jsonl")
6209
+ join6(process.env.GROK_HOME ?? join6(homedir3(), ".grok"), "logs", "unified.jsonl")
5253
6210
  ));
5254
6211
  this.#refreshBillingLog = options.refreshBillingLog ?? (options.readUnifiedLog ? async () => void 0 : () => refreshBillingLogViaDashboard(this.#command, this.#timeoutMs));
5255
6212
  this.#clock = options.clock ?? (() => /* @__PURE__ */ new Date());
@@ -5620,7 +6577,7 @@ function endpointFailure(error, label) {
5620
6577
  recovery: "Check network access and xAI status, then retry."
5621
6578
  };
5622
6579
  }
5623
- function safeFailure7(error) {
6580
+ function safeFailure8(error) {
5624
6581
  if (error instanceof Error && "code" in error && typeof error.code === "string" && "recovery" in error && typeof error.recovery === "string") {
5625
6582
  return { code: error.code, message: error.message, recovery: error.recovery };
5626
6583
  }
@@ -5875,7 +6832,7 @@ var init_xai_api_connector = __esm({
5875
6832
  costs: [],
5876
6833
  balances: [],
5877
6834
  invoices: [],
5878
- warnings: [safeFailure7(error)],
6835
+ warnings: [safeFailure8(error)],
5879
6836
  observedAt
5880
6837
  };
5881
6838
  }
@@ -6074,8 +7031,8 @@ var init_macos_notifier = __esm({
6074
7031
  });
6075
7032
 
6076
7033
  // src/server/macos-start-at-login-manager.ts
6077
- import { mkdir as mkdir3, rm, writeFile as writeFile3 } from "fs/promises";
6078
- import { dirname as dirname2, isAbsolute, join as join5 } from "path";
7034
+ import { mkdir as mkdir4, rm, writeFile as writeFile4 } from "fs/promises";
7035
+ import { dirname as dirname3, isAbsolute, join as join7 } from "path";
6079
7036
  function launchAgentPlist(options) {
6080
7037
  const label = options.label ?? LABEL;
6081
7038
  const arguments_ = [
@@ -6127,15 +7084,15 @@ var init_macos_start_at_login_manager = __esm({
6127
7084
  const label = validateLaunchAgentLabel(options.label ?? LABEL);
6128
7085
  if (options.nodeImport) validateNodeImport(options.nodeImport);
6129
7086
  this.#options = { ...options, label };
6130
- this.#path = join5(options.userHome, "Library", "LaunchAgents", `${label}.plist`);
7087
+ this.#path = join7(options.userHome, "Library", "LaunchAgents", `${label}.plist`);
6131
7088
  }
6132
7089
  async setEnabled(enabled) {
6133
7090
  if (!enabled) {
6134
7091
  await rm(this.#path, { force: true });
6135
7092
  return;
6136
7093
  }
6137
- await mkdir3(dirname2(this.#path), { recursive: true, mode: 448 });
6138
- await writeFile3(this.#path, launchAgentPlist(this.#options), { mode: 384 });
7094
+ await mkdir4(dirname3(this.#path), { recursive: true, mode: 448 });
7095
+ await writeFile4(this.#path, launchAgentPlist(this.#options), { mode: 384 });
6139
7096
  }
6140
7097
  async isEnabled() {
6141
7098
  try {
@@ -6252,7 +7209,7 @@ var init_otlp_protobuf = __esm({
6252
7209
  // src/server/local-server.ts
6253
7210
  import { createReadStream as createReadStream2, existsSync, statSync } from "fs";
6254
7211
  import { createServer } from "http";
6255
- import { extname, join as join6, normalize, resolve } from "path";
7212
+ import { extname, join as join8, normalize, resolve } from "path";
6256
7213
  import { randomBytes } from "crypto";
6257
7214
  import { z as z9 } from "zod";
6258
7215
  async function startLocalServer(options) {
@@ -6432,6 +7389,53 @@ async function startLocalServer(options) {
6432
7389
  sendJson(response, 200, await options.application.updatePlanSubscription(input));
6433
7390
  return;
6434
7391
  }
7392
+ if (request.method === "GET" && requestUrl.pathname === "/api/custom-rates") {
7393
+ const rates = await options.application.getCustomModelRates();
7394
+ sendJson(response, 200, { rates });
7395
+ return;
7396
+ }
7397
+ if (request.method === "GET" && requestUrl.pathname.startsWith("/api/custom-rates/")) {
7398
+ const id = decodeURIComponent(requestUrl.pathname.slice("/api/custom-rates/".length));
7399
+ const rate = await options.application.getCustomModelRate(id);
7400
+ if (!rate) {
7401
+ sendJson(response, 404, { error: "rate-not-found" });
7402
+ return;
7403
+ }
7404
+ sendJson(response, 200, { rate });
7405
+ return;
7406
+ }
7407
+ if (request.method === "POST" && requestUrl.pathname === "/api/custom-rates") {
7408
+ if (!validMutationOrigin(authentication, request, origin)) {
7409
+ sendJson(response, 403, { error: "invalid-origin" });
7410
+ return;
7411
+ }
7412
+ const input = customModelRateSchema.parse(await readJsonBody(request));
7413
+ const rate = await options.application.setCustomModelRate(input);
7414
+ sendJson(response, 200, { rate });
7415
+ return;
7416
+ }
7417
+ if ((request.method === "PUT" || request.method === "PATCH") && requestUrl.pathname.startsWith("/api/custom-rates/")) {
7418
+ if (!validMutationOrigin(authentication, request, origin)) {
7419
+ sendJson(response, 403, { error: "invalid-origin" });
7420
+ return;
7421
+ }
7422
+ const id = decodeURIComponent(requestUrl.pathname.slice("/api/custom-rates/".length));
7423
+ const body = await readJsonBody(request);
7424
+ const input = customModelRateSchema.parse({ ...body, id });
7425
+ const rate = await options.application.setCustomModelRate(input);
7426
+ sendJson(response, 200, { rate });
7427
+ return;
7428
+ }
7429
+ if (request.method === "DELETE" && requestUrl.pathname.startsWith("/api/custom-rates/")) {
7430
+ if (!validMutationOrigin(authentication, request, origin)) {
7431
+ sendJson(response, 403, { error: "invalid-origin" });
7432
+ return;
7433
+ }
7434
+ const id = decodeURIComponent(requestUrl.pathname.slice("/api/custom-rates/".length));
7435
+ const deleted = await options.application.deleteCustomModelRate(id);
7436
+ sendJson(response, 200, { deleted });
7437
+ return;
7438
+ }
6435
7439
  if (request.method === "GET" && requestUrl.pathname === "/api/monitoring") {
6436
7440
  sendJson(response, 200, await options.application.getMonitoringStatus());
6437
7441
  return;
@@ -6488,8 +7492,7 @@ async function startLocalServer(options) {
6488
7492
  }
6489
7493
  sendJson(response, 404, { error: "not-found" });
6490
7494
  } catch (error) {
6491
- const message = publicErrorMessage(error);
6492
- sendJson(response, 500, { error: "internal-error", message });
7495
+ respondWithFailure(response, error);
6493
7496
  }
6494
7497
  });
6495
7498
  await new Promise((resolveListening, reject) => {
@@ -6575,8 +7578,8 @@ async function serveStatic(response, pathname, staticDirectory) {
6575
7578
  const root = resolve(staticDirectory);
6576
7579
  const requested = pathname === "/" ? "index.html" : pathname.replace(/^\/+/, "");
6577
7580
  const normalized = normalize(requested);
6578
- const candidate = resolve(join6(root, normalized));
6579
- const indexFile = join6(root, "index.html");
7581
+ const candidate = resolve(join8(root, normalized));
7582
+ const indexFile = join8(root, "index.html");
6580
7583
  const file = candidate.startsWith(`${root}/`) && existsSync(candidate) && statSync(candidate).isFile() ? candidate : indexFile;
6581
7584
  if (!existsSync(file)) {
6582
7585
  sendText(response, 404, "Dashboard assets are not built");
@@ -6609,11 +7612,28 @@ function secureToken() {
6609
7612
  return randomBytes(32).toString("base64url");
6610
7613
  }
6611
7614
  function sendJson(response, status, body) {
7615
+ const payload = JSON.stringify(body);
6612
7616
  response.writeHead(status, {
6613
7617
  "content-type": "application/json; charset=utf-8",
6614
7618
  "cache-control": "no-store"
6615
7619
  });
6616
- response.end(JSON.stringify(body));
7620
+ response.end(payload);
7621
+ }
7622
+ function respondWithFailure(response, error) {
7623
+ const message = publicErrorMessage(error);
7624
+ if (response.headersSent || response.writableEnded) {
7625
+ process.stderr.write(`Agent Usage: a started response failed to finish: ${message}
7626
+ `);
7627
+ response.destroy();
7628
+ return;
7629
+ }
7630
+ try {
7631
+ sendJson(response, 500, { error: "internal-error", message });
7632
+ } catch {
7633
+ process.stderr.write(`Agent Usage: a request failed without a reportable reason.
7634
+ `);
7635
+ response.destroy();
7636
+ }
6617
7637
  }
6618
7638
  function sendOtlpProtobuf(response, status) {
6619
7639
  response.writeHead(status, {
@@ -6630,7 +7650,7 @@ function sendHtml(response, status, body) {
6630
7650
  response.writeHead(status, { "content-type": "text/html; charset=utf-8" });
6631
7651
  response.end(body);
6632
7652
  }
6633
- var SESSION_COOKIE, connectorActionSchema, usageQuerySchema, monitoringSettingsSchema, planSubscriptionSchema, clearDataSchema, hardRebuildSchema;
7653
+ var SESSION_COOKIE, connectorActionSchema, usageQuerySchema, monitoringSettingsSchema, planSubscriptionSchema, customModelRateSchema, clearDataSchema, hardRebuildSchema;
6634
7654
  var init_local_server = __esm({
6635
7655
  "src/server/local-server.ts"() {
6636
7656
  "use strict";
@@ -6664,6 +7684,15 @@ var init_local_server = __esm({
6664
7684
  anchorDate: z9.string().regex(/^\d{4}-\d{2}-\d{2}$/).nullable().optional()
6665
7685
  }).nullable()
6666
7686
  });
7687
+ customModelRateSchema = z9.object({
7688
+ id: z9.string().optional(),
7689
+ providerId: z9.string().min(1),
7690
+ billingDomainId: z9.string().nullable().optional(),
7691
+ model: z9.string().min(1),
7692
+ inputRate: z9.number().nonnegative(),
7693
+ outputRate: z9.number().nonnegative(),
7694
+ cacheReadRate: z9.number().nonnegative().optional()
7695
+ });
6667
7696
  clearDataSchema = z9.object({ deleteProductSecrets: z9.boolean().default(false) });
6668
7697
  hardRebuildSchema = z9.object({ confirmExpensiveOperation: z9.literal(true) });
6669
7698
  }
@@ -6672,7 +7701,7 @@ var init_local_server = __esm({
6672
7701
  // src/server/path-discovery-probe.ts
6673
7702
  import { constants } from "fs";
6674
7703
  import { access } from "fs/promises";
6675
- import { delimiter, isAbsolute as isAbsolute2, join as join7, resolve as resolve2 } from "path";
7704
+ import { delimiter, isAbsolute as isAbsolute2, join as join9, resolve as resolve2 } from "path";
6676
7705
  async function isExecutable(path) {
6677
7706
  try {
6678
7707
  await access(path, constants.X_OK);
@@ -6718,7 +7747,7 @@ var init_path_discovery_probe = __esm({
6718
7747
  async #findExecutable(command) {
6719
7748
  if (command.includes("/")) return await isExecutable(command) ? resolve2(command) : null;
6720
7749
  for (const directory of this.#path.split(delimiter).filter(Boolean)) {
6721
- const candidate = join7(directory, command);
7750
+ const candidate = join9(directory, command);
6722
7751
  if (await isExecutable(candidate)) return candidate;
6723
7752
  }
6724
7753
  return null;
@@ -6729,8 +7758,8 @@ var init_path_discovery_probe = __esm({
6729
7758
 
6730
7759
  // src/server/sqlite-usage-repository.ts
6731
7760
  import { mkdirSync } from "fs";
6732
- import { createRequire as createRequire2 } from "module";
6733
- import { dirname as dirname3 } from "path";
7761
+ import { createRequire as createRequire3 } from "module";
7762
+ import { dirname as dirname4 } from "path";
6734
7763
  import { Worker } from "worker_threads";
6735
7764
  async function runDatabaseWorker(workerData) {
6736
7765
  return new Promise((resolve5, reject) => {
@@ -7096,7 +8125,7 @@ function buildGlobalSummary(providers, riskSummary, now, query) {
7096
8125
  for (const observedAt of [
7097
8126
  domain.history.lastObservedAt,
7098
8127
  ...domain.quotaBuckets.map((bucket) => bucket.observedAt ?? null),
7099
- ...domain.costs.map((cost) => cost.observedAt),
8128
+ domain.lastCostObservedAt,
7100
8129
  ...domain.balances.map((balance) => balance.observedAt),
7101
8130
  ...domain.invoices.map((invoice) => invoice.createdAt)
7102
8131
  ]) {
@@ -7358,7 +8387,7 @@ function allDomainHistories(providers) {
7358
8387
  provider,
7359
8388
  domain,
7360
8389
  history: domain.history,
7361
- includedInHeadline: domain.id === provider.summaryBillingDomainId
8390
+ includedInHeadline: provider.id === "dsh" ? true : domain.id === provider.summaryBillingDomainId
7362
8391
  }))
7363
8392
  );
7364
8393
  }
@@ -7436,25 +8465,28 @@ function buildWorkbenchModelRanking(histories, buckets, comparisonCurrency, reco
7436
8465
  const entries = histories.flatMap(
7437
8466
  ({ provider, domain, history, includedInHeadline }) => history.models.map((model) => {
7438
8467
  const retailEquivalent = buildWorkbenchMetric(
7439
- model.priceEvidence,
8468
+ model.priceEvidence ?? [],
7440
8469
  "retail-equivalent",
7441
8470
  comparisonCurrency,
7442
8471
  model.tokenEvidence.recordedTokens,
7443
8472
  history.exchangeRates
7444
8473
  );
7445
8474
  const reportedEstimate = buildWorkbenchMetric(
7446
- model.priceEvidence,
8475
+ model.priceEvidence ?? [],
7447
8476
  "reported-estimate",
7448
8477
  comparisonCurrency,
7449
8478
  model.tokenEvidence.recordedTokens,
7450
8479
  history.exchangeRates
7451
8480
  );
8481
+ const observations = model.observations ?? [];
8482
+ const priceEvidence = model.priceEvidence ?? [];
7452
8483
  const authorities = [
7453
- ...new Set(model.observations.map((observation) => observation.authority))
8484
+ ...new Set(observations.map((observation) => observation.authority))
7454
8485
  ].sort();
7455
- const lastObservedAt = [...model.observations].sort(
7456
- (left, right) => right.observedAt.localeCompare(left.observedAt)
7457
- )[0]?.observedAt ?? null;
8486
+ const lastObservedAt = observations.reduce(
8487
+ (latest, observation) => latest === null || observation.observedAt > latest ? observation.observedAt : latest,
8488
+ null
8489
+ ) ?? null;
7458
8490
  return {
7459
8491
  id: modelRankingId(provider.id, domain.id, model.model),
7460
8492
  providerId: provider.id,
@@ -7472,28 +8504,28 @@ function buildWorkbenchModelRanking(histories, buckets, comparisonCurrency, reco
7472
8504
  reportedShare: includedInHeadline && reportedEstimate.status === "available" && reportedEstimate.amount !== null && totalReportedEstimate.status === "available" && totalReportedEstimate.amount !== null && totalReportedEstimate.amount !== 0 ? reportedEstimate.amount / totalReportedEstimate.amount : null,
7473
8505
  authorities,
7474
8506
  lastObservedAt,
7475
- observations: model.observations,
7476
- priceEvidence: model.priceEvidence,
8507
+ composition: nonOverlappingComposition(observations, model.tokenTotals),
8508
+ priceSnapshots: distinctPriceSnapshots(priceEvidence),
7477
8509
  trend: buckets.map((bucket) => {
7478
- const observations = model.observations.filter(
8510
+ const bucketObservations = observations.filter(
7479
8511
  (observation) => observation.observedAt >= bucket.start && observation.observedAt < bucket.end
7480
8512
  );
7481
- const priceEvidence = model.priceEvidence.filter(
8513
+ const bucketPriceEvidence = priceEvidence.filter(
7482
8514
  (cost) => (cost.observedAt ?? "") >= bucket.start && (cost.observedAt ?? "") < bucket.end
7483
8515
  );
7484
- const tokenTotals = observations.reduce(
8516
+ const tokenTotals = bucketObservations.reduce(
7485
8517
  (total, observation) => addTokenTotals(total, observation.tokenTotals),
7486
8518
  zeroTokenTotals()
7487
8519
  );
7488
8520
  const intervalRetail = buildWorkbenchMetric(
7489
- priceEvidence,
8521
+ bucketPriceEvidence,
7490
8522
  "retail-equivalent",
7491
8523
  comparisonCurrency,
7492
8524
  tokenTotals.total,
7493
8525
  history.exchangeRates
7494
8526
  );
7495
8527
  const intervalReported = buildWorkbenchMetric(
7496
- priceEvidence,
8528
+ bucketPriceEvidence,
7497
8529
  "reported-estimate",
7498
8530
  comparisonCurrency,
7499
8531
  tokenTotals.total,
@@ -7503,14 +8535,19 @@ function buildWorkbenchModelRanking(histories, buckets, comparisonCurrency, reco
7503
8535
  start: bucket.start,
7504
8536
  end: bucket.end,
7505
8537
  label: bucket.label,
7506
- gap: observations.length === 0,
8538
+ gap: bucketObservations.length === 0,
7507
8539
  tokenTotals,
8540
+ recordedTokens: bucketObservations.reduce(
8541
+ (total, observation) => total + observation.recordedTokens,
8542
+ 0
8543
+ ),
7508
8544
  authorities: [
7509
- ...new Set(observations.map((observation) => observation.authority))
8545
+ ...new Set(bucketObservations.map((observation) => observation.authority))
7510
8546
  ].sort(),
7511
- lastObservedAt: [...observations].sort(
7512
- (left, right) => right.observedAt.localeCompare(left.observedAt)
7513
- )[0]?.observedAt ?? null,
8547
+ lastObservedAt: bucketObservations.reduce(
8548
+ (latest, observation) => latest === null || observation.observedAt > latest ? observation.observedAt : latest,
8549
+ null
8550
+ ) ?? null,
7514
8551
  retailEquivalent: {
7515
8552
  status: intervalRetail.status,
7516
8553
  amount: intervalRetail.amount,
@@ -7587,6 +8624,49 @@ function buildWorkbenchModelRanking(histories, buckets, comparisonCurrency, reco
7587
8624
  unclassified
7588
8625
  };
7589
8626
  }
8627
+ function dropAuditEvidence(providers) {
8628
+ for (const provider of providers) {
8629
+ for (const domain of provider.billingDomains) {
8630
+ for (const model of domain.history.models) {
8631
+ delete model.observations;
8632
+ delete model.priceEvidence;
8633
+ }
8634
+ delete domain.history.unclassified.observations;
8635
+ }
8636
+ }
8637
+ }
8638
+ function nonOverlappingComposition(observations, fallback) {
8639
+ if (observations.length === 0) {
8640
+ return {
8641
+ ...fallback,
8642
+ total: fallback.input + fallback.output + fallback.cacheRead + fallback.cacheWrite
8643
+ };
8644
+ }
8645
+ const totals = zeroTokenTotals();
8646
+ for (const observation of observations) {
8647
+ totals.input += observation.tokenTotals.input;
8648
+ totals.output += observation.tokenTotals.output;
8649
+ if (observation.tokenSemantics.reasoning === "separate") {
8650
+ totals.reasoning += observation.tokenTotals.reasoning;
8651
+ }
8652
+ if (observation.tokenSemantics.cacheRead === "separate") {
8653
+ totals.cacheRead += observation.tokenTotals.cacheRead;
8654
+ }
8655
+ if (observation.tokenSemantics.cacheWrite === "separate") {
8656
+ totals.cacheWrite += observation.tokenTotals.cacheWrite;
8657
+ }
8658
+ }
8659
+ totals.total = totals.input + totals.output + totals.reasoning + totals.cacheRead + totals.cacheWrite;
8660
+ return totals;
8661
+ }
8662
+ function distinctPriceSnapshots(priceEvidence) {
8663
+ const snapshots = /* @__PURE__ */ new Map();
8664
+ for (const evidence of priceEvidence) {
8665
+ const snapshot2 = evidence.priceSnapshot;
8666
+ if (snapshot2 && !snapshots.has(snapshot2.id)) snapshots.set(snapshot2.id, snapshot2);
8667
+ }
8668
+ return [...snapshots.values()];
8669
+ }
7590
8670
  function modelRankingId(providerId, billingDomainId, model) {
7591
8671
  return `${providerId}::${billingDomainId}::${model}`;
7592
8672
  }
@@ -8034,7 +9114,7 @@ function freshnessStatus(lastSuccessAt, now) {
8034
9114
  if (!lastSuccessAt) return "unavailable";
8035
9115
  return now.getTime() - new Date(lastSuccessAt).getTime() <= FRESHNESS_WINDOW_MS ? "fresh" : "stale";
8036
9116
  }
8037
- var FRESHNESS_WINDOW_MS, QUERY_INDEXES_SQL, DELETE_DERIVED_RETAIL_COSTS_SQL, DELETE_DEMO_PROVIDER_DATA_SQL, DatabaseSync2, RETENTION_AGGREGATE_SQL, SqliteUsageRepository;
9117
+ var FRESHNESS_WINDOW_MS, QUERY_INDEXES_SQL, DELETE_DERIVED_RETAIL_COSTS_SQL, DELETE_DEMO_PROVIDER_DATA_SQL, DatabaseSync3, RETENTION_AGGREGATE_SQL, SqliteUsageRepository;
8038
9118
  var init_sqlite_usage_repository = __esm({
8039
9119
  "src/server/sqlite-usage-repository.ts"() {
8040
9120
  "use strict";
@@ -8075,7 +9155,7 @@ var init_sqlite_usage_repository = __esm({
8075
9155
  DELETE FROM connector_settings WHERE id = 'demo';
8076
9156
  DELETE FROM providers WHERE id = 'demo';
8077
9157
  `;
8078
- ({ DatabaseSync: DatabaseSync2 } = createRequire2(import.meta.url)(
9158
+ ({ DatabaseSync: DatabaseSync3 } = createRequire3(import.meta.url)(
8079
9159
  "node:sqlite"
8080
9160
  ));
8081
9161
  RETENTION_AGGREGATE_SQL = `
@@ -8106,8 +9186,8 @@ var init_sqlite_usage_repository = __esm({
8106
9186
  constructor(databasePath, options = {}) {
8107
9187
  this.#databasePath = databasePath;
8108
9188
  this.#hideDemoProvider = options.hideDemoProvider ?? false;
8109
- mkdirSync(dirname3(databasePath), { recursive: true });
8110
- this.#database = new DatabaseSync2(databasePath);
9189
+ mkdirSync(dirname4(databasePath), { recursive: true });
9190
+ this.#database = new DatabaseSync3(databasePath);
8111
9191
  this.#database.exec("PRAGMA journal_mode = WAL; PRAGMA foreign_keys = ON;");
8112
9192
  this.#migrate();
8113
9193
  }
@@ -8171,6 +9251,22 @@ var init_sqlite_usage_repository = __esm({
8171
9251
  limit_currency = excluded.limit_currency,
8172
9252
  fallback_status = excluded.fallback_status`
8173
9253
  );
9254
+ const reportedQuotaDomains = [
9255
+ ...new Set(snapshot2.quotaBuckets.map((bucket) => bucket.billingDomainId))
9256
+ ];
9257
+ if (reportedQuotaDomains.length > 0) {
9258
+ const retiredQuotaStatement = this.#database.prepare(
9259
+ `DELETE FROM quota_buckets
9260
+ WHERE provider_id = ? AND billing_domain_id = ? AND id NOT IN (${snapshot2.quotaBuckets.map(() => "?").join(", ")})`
9261
+ );
9262
+ for (const billingDomainId of reportedQuotaDomains) {
9263
+ retiredQuotaStatement.run(
9264
+ snapshot2.provider.id,
9265
+ billingDomainId,
9266
+ ...snapshot2.quotaBuckets.map((bucket) => bucket.id)
9267
+ );
9268
+ }
9269
+ }
8174
9270
  for (const bucket of snapshot2.quotaBuckets) {
8175
9271
  quotaStatement.run(
8176
9272
  snapshot2.provider.id,
@@ -8532,7 +9628,11 @@ var init_sqlite_usage_repository = __esm({
8532
9628
  price_snapshot_source_url, price_snapshot_context_tier,
8533
9629
  model, usage_observation_id, priced_tokens, line_items_json, calculated_at
8534
9630
  ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
8535
- ON CONFLICT(provider_id, id) DO NOTHING`
9631
+ ON CONFLICT(provider_id, id) DO UPDATE SET
9632
+ amount = excluded.amount,
9633
+ price_snapshot_rates_json = excluded.price_snapshot_rates_json,
9634
+ line_items_json = excluded.line_items_json,
9635
+ calculated_at = excluded.calculated_at`
8536
9636
  );
8537
9637
  this.#database.exec("BEGIN IMMEDIATE");
8538
9638
  try {
@@ -8602,7 +9702,7 @@ var init_sqlite_usage_repository = __esm({
8602
9702
  );
8603
9703
  const riskSummary = buildRiskSummary(overviews);
8604
9704
  const planSubscriptions = this.getPlanSubscriptions();
8605
- return {
9705
+ const overview = {
8606
9706
  generatedAt: now.toISOString(),
8607
9707
  globalSummary: buildGlobalSummary(overviews, riskSummary, now, query),
8608
9708
  workbench: buildTokenMoneyWorkbench(
@@ -8615,13 +9715,15 @@ var init_sqlite_usage_repository = __esm({
8615
9715
  providers: overviews,
8616
9716
  riskSummary
8617
9717
  };
9718
+ if (!query.auditEvidence) dropAuditEvidence(overviews);
9719
+ return overview;
8618
9720
  }
8619
9721
  getAgentProviderIndex(now) {
8620
9722
  const providers = this.#database.prepare("SELECT id, display_name FROM providers ORDER BY id").all();
8621
9723
  return {
8622
9724
  generatedAt: now.toISOString(),
8623
9725
  providers: providers.filter(
8624
- (provider) => provider.id !== "opencode" && (!this.#hideDemoProvider || provider.id !== "demo")
9726
+ (provider) => provider.id !== "opencode" && provider.id !== "dsh" && (!this.#hideDemoProvider || provider.id !== "demo")
8625
9727
  ).map((provider) => ({ id: provider.id, displayName: provider.display_name }))
8626
9728
  };
8627
9729
  }
@@ -8631,7 +9733,10 @@ var init_sqlite_usage_repository = __esm({
8631
9733
  `SELECT id, display_name, last_success_at, last_error, last_error_code, last_recovery
8632
9734
  FROM providers WHERE id = ?`
8633
9735
  ).get(providerId);
8634
- return provider ? this.#getProviderOverview(provider, now, query) : null;
9736
+ if (!provider) return null;
9737
+ const overview = this.#getProviderOverview(provider, now, query);
9738
+ if (!query.auditEvidence) dropAuditEvidence([overview]);
9739
+ return overview;
8635
9740
  }
8636
9741
  saveExchangeRateSnapshot(snapshot2) {
8637
9742
  this.#database.prepare(
@@ -8759,6 +9864,95 @@ var init_sqlite_usage_repository = __esm({
8759
9864
  deletePlanSubscription(providerId, billingDomainId) {
8760
9865
  this.#database.prepare("DELETE FROM plan_subscriptions WHERE provider_id = ? AND billing_domain_id = ?").run(providerId, billingDomainId);
8761
9866
  }
9867
+ getCustomModelRates() {
9868
+ const rows = this.#database.prepare(
9869
+ `SELECT id, provider_id, billing_domain_id, model,
9870
+ input_rate, output_rate, cache_read_rate, updated_at
9871
+ FROM custom_model_rates
9872
+ ORDER BY updated_at DESC`
9873
+ ).all();
9874
+ return rows.map((row) => ({
9875
+ id: row.id,
9876
+ providerId: row.provider_id,
9877
+ billingDomainId: row.billing_domain_id ?? null,
9878
+ model: row.model,
9879
+ ratesPerMillion: {
9880
+ input: row.input_rate,
9881
+ output: row.output_rate,
9882
+ cacheRead: row.cache_read_rate
9883
+ },
9884
+ updatedAt: row.updated_at
9885
+ }));
9886
+ }
9887
+ getCustomModelRate(id) {
9888
+ const row = this.#database.prepare(
9889
+ `SELECT id, provider_id, billing_domain_id, model,
9890
+ input_rate, output_rate, cache_read_rate, updated_at
9891
+ FROM custom_model_rates
9892
+ WHERE id = ?`
9893
+ ).get(id);
9894
+ if (!row) return null;
9895
+ return {
9896
+ id: row.id,
9897
+ providerId: row.provider_id,
9898
+ billingDomainId: row.billing_domain_id ?? null,
9899
+ model: row.model,
9900
+ ratesPerMillion: {
9901
+ input: row.input_rate,
9902
+ output: row.output_rate,
9903
+ cacheRead: row.cache_read_rate
9904
+ },
9905
+ updatedAt: row.updated_at
9906
+ };
9907
+ }
9908
+ saveCustomModelRate(rate) {
9909
+ const byId = this.#database.prepare("SELECT id FROM custom_model_rates WHERE id = ?").get(rate.id);
9910
+ const byKey = this.#database.prepare(
9911
+ `SELECT id FROM custom_model_rates
9912
+ WHERE provider_id = ? AND COALESCE(billing_domain_id, '') = COALESCE(?, '') AND lower(model) = lower(?)`
9913
+ ).get(rate.providerId, rate.billingDomainId, rate.model);
9914
+ if (byId && byKey && byId.id !== byKey.id) {
9915
+ this.#database.prepare("DELETE FROM custom_model_rates WHERE id = ?").run(byKey.id);
9916
+ }
9917
+ const existingId = byId?.id ?? byKey?.id;
9918
+ if (existingId) {
9919
+ this.#database.prepare(
9920
+ `UPDATE custom_model_rates SET
9921
+ provider_id = ?, billing_domain_id = ?, model = ?,
9922
+ input_rate = ?, output_rate = ?, cache_read_rate = ?, updated_at = ?
9923
+ WHERE id = ?`
9924
+ ).run(
9925
+ rate.providerId,
9926
+ rate.billingDomainId,
9927
+ rate.model,
9928
+ rate.ratesPerMillion.input,
9929
+ rate.ratesPerMillion.output,
9930
+ rate.ratesPerMillion.cacheRead,
9931
+ rate.updatedAt,
9932
+ existingId
9933
+ );
9934
+ } else {
9935
+ this.#database.prepare(
9936
+ `INSERT INTO custom_model_rates (
9937
+ id, provider_id, billing_domain_id, model,
9938
+ input_rate, output_rate, cache_read_rate, updated_at
9939
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`
9940
+ ).run(
9941
+ rate.id,
9942
+ rate.providerId,
9943
+ rate.billingDomainId,
9944
+ rate.model,
9945
+ rate.ratesPerMillion.input,
9946
+ rate.ratesPerMillion.output,
9947
+ rate.ratesPerMillion.cacheRead,
9948
+ rate.updatedAt
9949
+ );
9950
+ }
9951
+ }
9952
+ deleteCustomModelRate(id) {
9953
+ const result = this.#database.prepare("DELETE FROM custom_model_rates WHERE id = ?").run(id);
9954
+ return result.changes > 0;
9955
+ }
8762
9956
  getNotificationState(key) {
8763
9957
  const row = this.#database.prepare("SELECT value FROM notification_state WHERE key = ?").get(key);
8764
9958
  return row?.value ?? null;
@@ -8976,7 +10170,7 @@ var init_sqlite_usage_repository = __esm({
8976
10170
  FROM billing_domains WHERE provider_id = ? ORDER BY id`
8977
10171
  ).all(provider.id);
8978
10172
  const summaryBillingDomainId = selectSummaryBillingDomainId(provider.id, domainRows);
8979
- const billingDomains2 = domainRows.map(
10173
+ const billingDomains3 = domainRows.map(
8980
10174
  (domain) => this.#getBillingDomainOverview(
8981
10175
  provider.id,
8982
10176
  domain,
@@ -8988,7 +10182,7 @@ var init_sqlite_usage_repository = __esm({
8988
10182
  domainRows.length === 1 ? provider : null
8989
10183
  )
8990
10184
  );
8991
- const summaryDomain = billingDomains2.find((domain) => domain.id === summaryBillingDomainId);
10185
+ const summaryDomain = billingDomains3.find((domain) => domain.id === summaryBillingDomainId);
8992
10186
  const emptyTotals = zeroTokenTotals();
8993
10187
  const emptyEvidence = finishTokenEvidence(emptyTokenEvidence());
8994
10188
  const emptyCoverage = {
@@ -9003,6 +10197,23 @@ var init_sqlite_usage_repository = __esm({
9003
10197
  message: provider.last_error,
9004
10198
  recovery: provider.last_recovery
9005
10199
  } : { status: "healthy", errorCode: null, message: null, recovery: null };
10200
+ let providerTokenTotals = summaryDomain?.tokenTotals ?? emptyTotals;
10201
+ let providerTokenEvidence = summaryDomain?.tokenEvidence ?? emptyEvidence;
10202
+ if (provider.id === "dsh" && billingDomains3.length > 1) {
10203
+ const combinedTotals = zeroTokenTotals();
10204
+ const combinedEvidence = emptyTokenEvidence();
10205
+ for (const d of billingDomains3) {
10206
+ combinedTotals.total += d.tokenTotals.total;
10207
+ combinedTotals.input += d.tokenTotals.input;
10208
+ combinedTotals.output += d.tokenTotals.output;
10209
+ combinedTotals.reasoning += d.tokenTotals.reasoning;
10210
+ combinedTotals.cacheRead += d.tokenTotals.cacheRead;
10211
+ combinedTotals.cacheWrite += d.tokenTotals.cacheWrite;
10212
+ addAggregatedTokenEvidence(combinedEvidence, d.tokenEvidence);
10213
+ }
10214
+ providerTokenTotals = combinedTotals;
10215
+ providerTokenEvidence = finishTokenEvidence(combinedEvidence);
10216
+ }
9006
10217
  return {
9007
10218
  id: provider.id,
9008
10219
  displayName: provider.display_name,
@@ -9014,10 +10225,10 @@ var init_sqlite_usage_repository = __esm({
9014
10225
  health: summaryDomain?.health ?? providerFallbackHealth,
9015
10226
  coverage: summaryDomain?.coverage ?? emptyCoverage,
9016
10227
  quotaBuckets: summaryDomain?.quotaBuckets ?? [],
9017
- tokenTotals: summaryDomain?.tokenTotals ?? emptyTotals,
9018
- tokenEvidence: summaryDomain?.tokenEvidence ?? emptyEvidence,
10228
+ tokenTotals: providerTokenTotals,
10229
+ tokenEvidence: providerTokenEvidence,
9019
10230
  tokenAuthority: summaryDomain?.tokenAuthority ?? null,
9020
- billingDomains: billingDomains2,
10231
+ billingDomains: billingDomains3,
9021
10232
  forecasts: summaryDomain?.forecasts ?? [],
9022
10233
  forecastCoverage: summaryDomain?.forecastCoverage ?? "insufficient"
9023
10234
  };
@@ -9049,7 +10260,7 @@ var init_sqlite_usage_repository = __esm({
9049
10260
  FROM usage_observations
9050
10261
  WHERE provider_id = ? AND billing_domain_id = ? AND ${additiveUsagePredicate()}`
9051
10262
  ).get(providerId, domain.id);
9052
- const costs = this.#database.prepare(
10263
+ const costs = query.auditEvidence ? this.#database.prepare(
9053
10264
  `SELECT id, source_id, billing_domain_id, observed_at, kind, amount, currency, authority,
9054
10265
  price_snapshot_id, price_snapshot_version, price_snapshot_source,
9055
10266
  price_snapshot_canonical_model, price_snapshot_effective_at,
@@ -9058,7 +10269,11 @@ var init_sqlite_usage_repository = __esm({
9058
10269
  price_snapshot_context_tier, model, usage_observation_id, priced_tokens,
9059
10270
  line_items_json, calculated_at
9060
10271
  FROM cost_records WHERE provider_id = ? AND billing_domain_id = ? ORDER BY observed_at DESC, id`
9061
- ).all(providerId, domain.id);
10272
+ ).all(providerId, domain.id) : null;
10273
+ const lastCostObservedAt = this.#database.prepare(
10274
+ `SELECT MAX(observed_at) AS observed_at FROM cost_records
10275
+ WHERE provider_id = ? AND billing_domain_id = ?`
10276
+ ).get(providerId, domain.id).observed_at ?? null;
9062
10277
  const balances = this.#database.prepare(
9063
10278
  `SELECT id, source_id, billing_domain_id, observed_at, kind, amount, currency, authority
9064
10279
  FROM balance_records WHERE provider_id = ? AND billing_domain_id = ? ORDER BY observed_at DESC, id`
@@ -9067,7 +10282,12 @@ var init_sqlite_usage_repository = __esm({
9067
10282
  `SELECT id, billing_domain_id, created_at, number, status, amount, currency, authority
9068
10283
  FROM invoice_records WHERE provider_id = ? AND billing_domain_id = ? ORDER BY created_at DESC, id`
9069
10284
  ).all(providerId, domain.id);
9070
- const actualCostCount = costs.filter((cost) => cost.kind === "actual").length;
10285
+ const actualCostCount = Number(
10286
+ this.#database.prepare(
10287
+ `SELECT COUNT(*) AS count FROM cost_records
10288
+ WHERE provider_id = ? AND billing_domain_id = ? AND kind = 'actual'`
10289
+ ).get(providerId, domain.id).count
10290
+ );
9071
10291
  const nonAdditiveTokenCount = this.#database.prepare(
9072
10292
  `SELECT COUNT(*) AS count FROM usage_observations
9073
10293
  WHERE provider_id = ? AND billing_domain_id = ?
@@ -9097,22 +10317,25 @@ var init_sqlite_usage_repository = __esm({
9097
10317
  tokenTotals: mapTokenTotals(tokens),
9098
10318
  tokenEvidence: mapTokenEvidence(tokens),
9099
10319
  tokenAuthority: tokenAuthority(tokens.authorities),
9100
- costs: costs.map((row) => ({
9101
- id: row.id,
9102
- sourceId: row.source_id,
9103
- billingDomainId: row.billing_domain_id,
9104
- observedAt: row.observed_at,
9105
- kind: row.kind,
9106
- amount: row.amount,
9107
- currency: row.currency,
9108
- authority: row.authority,
9109
- priceSnapshot: priceSnapshotFromRow(row),
9110
- model: row.model,
9111
- usageObservationId: row.usage_observation_id,
9112
- pricedTokens: row.priced_tokens,
9113
- lineItems: parseLineItems(row.line_items_json),
9114
- calculatedAt: row.calculated_at
9115
- })),
10320
+ ...costs ? {
10321
+ costs: costs.map((row) => ({
10322
+ id: row.id,
10323
+ sourceId: row.source_id,
10324
+ billingDomainId: row.billing_domain_id,
10325
+ observedAt: row.observed_at,
10326
+ kind: row.kind,
10327
+ amount: row.amount,
10328
+ currency: row.currency,
10329
+ authority: row.authority,
10330
+ priceSnapshot: priceSnapshotFromRow(row),
10331
+ model: row.model,
10332
+ usageObservationId: row.usage_observation_id,
10333
+ pricedTokens: row.priced_tokens,
10334
+ lineItems: parseLineItems(row.line_items_json),
10335
+ calculatedAt: row.calculated_at
10336
+ }))
10337
+ } : {},
10338
+ lastCostObservedAt,
9116
10339
  balances: balances.map((row) => ({
9117
10340
  id: row.id,
9118
10341
  sourceId: row.source_id,
@@ -9733,6 +10956,18 @@ var init_sqlite_usage_repository = __esm({
9733
10956
  updated_at TEXT NOT NULL,
9734
10957
  PRIMARY KEY (provider_id, billing_domain_id)
9735
10958
  );
10959
+ CREATE TABLE IF NOT EXISTS custom_model_rates (
10960
+ id TEXT PRIMARY KEY,
10961
+ provider_id TEXT NOT NULL,
10962
+ billing_domain_id TEXT,
10963
+ model TEXT NOT NULL,
10964
+ input_rate REAL NOT NULL,
10965
+ output_rate REAL NOT NULL,
10966
+ cache_read_rate REAL NOT NULL,
10967
+ updated_at TEXT NOT NULL
10968
+ );
10969
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_custom_model_rates_key
10970
+ ON custom_model_rates(provider_id, COALESCE(billing_domain_id, ''), lower(model));
9736
10971
  `);
9737
10972
  const usageColumns = this.#database.prepare("PRAGMA table_info(usage_observations)").all();
9738
10973
  if (!usageColumns.some((column) => column.name === "total_tokens")) {
@@ -9890,9 +11125,9 @@ var init_sqlite_usage_repository = __esm({
9890
11125
  `);
9891
11126
  const quotaColumns = this.#database.prepare("PRAGMA table_info(quota_buckets)").all();
9892
11127
  for (const [name, type] of [
11128
+ ["window_duration_minutes", "INTEGER"],
9893
11129
  ["scope", "TEXT"],
9894
11130
  ["status", "TEXT"],
9895
- ["window_duration_minutes", "INTEGER"],
9896
11131
  ["limit_amount", "REAL"],
9897
11132
  ["limit_currency", "TEXT"],
9898
11133
  ["fallback_status", "TEXT"]
@@ -9916,14 +11151,14 @@ __export(runtime_exports, {
9916
11151
  runDaemon: () => runDaemon
9917
11152
  });
9918
11153
  import { existsSync as existsSync2 } from "fs";
9919
- import { mkdir as mkdir4, rm as rm2 } from "fs/promises";
9920
- import { homedir as homedir3 } from "os";
9921
- import { isAbsolute as isAbsolute3, join as join8, resolve as resolve3 } from "path";
11154
+ import { mkdir as mkdir5, rm as rm2 } from "fs/promises";
11155
+ import { homedir as homedir4 } from "os";
11156
+ import { isAbsolute as isAbsolute3, join as join10, resolve as resolve3 } from "path";
9922
11157
  import { fileURLToPath } from "url";
9923
11158
  async function runDaemon(home) {
9924
- await mkdir4(home, { recursive: true, mode: 448 });
11159
+ await mkdir5(home, { recursive: true, mode: 448 });
9925
11160
  const demoEnabled = process.env.AGENT_USAGE_DEMO === "1";
9926
- const repository = new SqliteUsageRepository(join8(home, "usage.sqlite"), {
11161
+ const repository = new SqliteUsageRepository(join10(home, "usage.sqlite"), {
9927
11162
  hideDemoProvider: !demoEnabled
9928
11163
  });
9929
11164
  const keychainService = process.env.AGENT_USAGE_KEYCHAIN_SERVICE;
@@ -9958,7 +11193,16 @@ async function runDaemon(home) {
9958
11193
  historyClient: localTranscriptClient("grok", home)
9959
11194
  }),
9960
11195
  new XaiApiConnector({ accountClient: new XaiManagementApiClient({ secretStore }) }),
9961
- new DshConnector({ historyClient: localTranscriptClient("dsh", home) })
11196
+ new DshConnector({ historyClient: localTranscriptClient("dsh", home) }),
11197
+ new AntigravityConnector({
11198
+ historyClient: new AntigravitySqliteUsageClient({
11199
+ roots: [
11200
+ join10(homedir4(), ".gemini/antigravity-cli"),
11201
+ join10(homedir4(), ".gemini/antigravity")
11202
+ ],
11203
+ cachePath: join10(home, "antigravity-usage-cache.json")
11204
+ })
11205
+ })
9962
11206
  ],
9963
11207
  connectorDefinitions: defaultConnectorDefinitions,
9964
11208
  discoveryProbe: new PathDiscoveryProbe(),
@@ -9966,7 +11210,7 @@ async function runDaemon(home) {
9966
11210
  exchangeRateProvider: new EcbExchangeRateProvider(),
9967
11211
  notifier: new MacOsNotifier(),
9968
11212
  startAtLoginManager: new MacOsStartAtLoginManager({
9969
- userHome: homedir3(),
11213
+ userHome: homedir4(),
9970
11214
  executable: process.execPath,
9971
11215
  cliPath: process.argv[1],
9972
11216
  applicationHome: home,
@@ -9981,7 +11225,16 @@ async function runDaemon(home) {
9981
11225
  }
9982
11226
  }),
9983
11227
  connectorPolicies: Object.fromEntries(
9984
- ["codex", "claude-code", "opencode-go", "opencode", "grok", "xai-api", "dsh"].map((id) => [
11228
+ [
11229
+ "codex",
11230
+ "claude-code",
11231
+ "opencode-go",
11232
+ "opencode",
11233
+ "grok",
11234
+ "xai-api",
11235
+ "dsh",
11236
+ "antigravity"
11237
+ ].map((id) => [
9985
11238
  id,
9986
11239
  { minimumIntervalMs: 5 * 60 * 1e3, timeoutMs: id === "claude-code" ? 25e3 : 2e4 }
9987
11240
  ])
@@ -10032,7 +11285,7 @@ async function runDaemon(home) {
10032
11285
  scheduler.stop();
10033
11286
  await server.close();
10034
11287
  repository.close();
10035
- await rm2(join8(home, "daemon.json"), { force: true });
11288
+ await rm2(join10(home, "daemon.json"), { force: true });
10036
11289
  resolveStop();
10037
11290
  };
10038
11291
  process.once("SIGTERM", () => void stop());
@@ -10043,27 +11296,27 @@ function localTranscriptClient(provider, applicationHome) {
10043
11296
  return new LocalTranscriptUsageClient({
10044
11297
  provider,
10045
11298
  roots: localTranscriptRoots(provider),
10046
- cachePath: join8(applicationHome, "cache", `${provider}-transcripts.json`)
11299
+ cachePath: join10(applicationHome, "cache", `${provider}-transcripts.json`)
10047
11300
  });
10048
11301
  }
10049
11302
  function localTranscriptRoots(provider) {
10050
11303
  if (provider === "codex") {
10051
11304
  const home = resolveHomeOverride(process.env.CODEX_HOME, ".codex");
10052
- return [join8(home, "sessions"), join8(home, "archived_sessions")];
11305
+ return [join10(home, "sessions"), join10(home, "archived_sessions")];
10053
11306
  }
10054
11307
  if (provider === "claude-code") {
10055
- return [join8(resolveHomeOverride(process.env.CLAUDE_CONFIG_DIR, ".claude"), "projects")];
11308
+ return [join10(resolveHomeOverride(process.env.CLAUDE_CONFIG_DIR, ".claude"), "projects")];
10056
11309
  }
10057
11310
  if (provider === "dsh") {
10058
- return [join8(resolveHomeOverride(process.env.DSH_HOME, ".dsh"), "sessions")];
11311
+ return [join10(resolveHomeOverride(process.env.DSH_HOME, ".dsh"), "sessions")];
10059
11312
  }
10060
- return [join8(resolveHomeOverride(process.env.GROK_HOME, ".grok"), "sessions")];
11313
+ return [join10(resolveHomeOverride(process.env.GROK_HOME, ".grok"), "sessions")];
10061
11314
  }
10062
11315
  function resolveHomeOverride(value, fallback) {
10063
11316
  const configured = value?.trim();
10064
- if (!configured) return join8(homedir3(), fallback);
10065
- if (configured === "~") return homedir3();
10066
- if (configured.startsWith("~/")) return join8(homedir3(), configured.slice(2));
11317
+ if (!configured) return join10(homedir4(), fallback);
11318
+ if (configured === "~") return homedir4();
11319
+ if (configured.startsWith("~/")) return join10(homedir4(), configured.slice(2));
10067
11320
  return isAbsolute3(configured) ? configured : resolve3(configured);
10068
11321
  }
10069
11322
  function createDemoConnector() {
@@ -10109,7 +11362,7 @@ function locateStaticDirectory() {
10109
11362
  fileURLToPath(new URL("./web", import.meta.url)),
10110
11363
  fileURLToPath(new URL("../../dist/web", import.meta.url))
10111
11364
  ];
10112
- return candidates.find((candidate) => existsSync2(join8(candidate, "index.html")));
11365
+ return candidates.find((candidate) => existsSync2(join10(candidate, "index.html")));
10113
11366
  }
10114
11367
  var init_runtime = __esm({
10115
11368
  "src/server/runtime.ts"() {
@@ -10127,6 +11380,8 @@ var init_runtime = __esm({
10127
11380
  init_opencode_auth_reader();
10128
11381
  init_opencode_go_connector();
10129
11382
  init_dsh_connector();
11383
+ init_antigravity_connector();
11384
+ init_antigravity_sqlite_usage_client();
10130
11385
  init_grok_build_connector();
10131
11386
  init_grok_telemetry();
10132
11387
  init_stdio_grok_billing_client();
@@ -10149,8 +11404,8 @@ init_redaction();
10149
11404
  init_daemon_state();
10150
11405
  import { spawn as spawn6 } from "child_process";
10151
11406
  import { connect as tcpConnect } from "net";
10152
- import { homedir as homedir4 } from "os";
10153
- import { join as join9, resolve as resolve4 } from "path";
11407
+ import { homedir as homedir5 } from "os";
11408
+ import { join as join11, resolve as resolve4 } from "path";
10154
11409
  import { Command } from "commander";
10155
11410
  import open2 from "open";
10156
11411
  var program = new Command();
@@ -10332,6 +11587,97 @@ program.command("start-at-login <action>").description("enable, disable, or show
10332
11587
  process.stdout.write(`${status.settings.startAtLogin ? "enabled" : "disabled"}
10333
11588
  `);
10334
11589
  });
11590
+ var ratesCommand = program.command("rates").description("view and manage custom model rates for custom endpoints");
11591
+ ratesCommand.command("list").description("list configured custom model rates").option("--json", "emit machine-readable JSON").action(async (options) => {
11592
+ const home = resolve4(program.opts().home);
11593
+ const state = await requireDaemonState(home);
11594
+ const response = await fetch(`${state.origin}/api/custom-rates`, {
11595
+ headers: { authorization: `Bearer ${state.apiToken}` }
11596
+ });
11597
+ if (!response.ok) throw new Error(`Daemon returned HTTP ${response.status}`);
11598
+ const data = await response.json();
11599
+ if (options.json) {
11600
+ process.stdout.write(`${JSON.stringify(data.rates, null, 2)}
11601
+ `);
11602
+ return;
11603
+ }
11604
+ if (data.rates.length === 0) {
11605
+ process.stdout.write("No custom model rates configured.\n");
11606
+ return;
11607
+ }
11608
+ for (const rate of data.rates) {
11609
+ const domain = rate.billingDomainId ?? "*";
11610
+ process.stdout.write(
11611
+ `${rate.id} | ${rate.providerId} | domain: ${domain} | model: ${rate.model} | in: $${rate.ratesPerMillion.input}/M | out: $${rate.ratesPerMillion.output}/M | cache: $${rate.ratesPerMillion.cacheRead}/M
11612
+ `
11613
+ );
11614
+ }
11615
+ });
11616
+ ratesCommand.command("set <model>").description("set custom model rate").requiredOption("--provider <provider>", "provider id (e.g. dsh)").option("--domain <domain>", "billing domain id (omit for wildcard across all routes)").requiredOption("--input <rate>", "input rate in USD per million tokens", parseFloat).requiredOption("--output <rate>", "output rate in USD per million tokens", parseFloat).option("--cache-read <rate>", "cache read rate in USD per million tokens", parseFloat, 0).option("--id <id>", "custom model rate ID to update").action(
11617
+ async (model, options) => {
11618
+ const home = resolve4(program.opts().home);
11619
+ const state = await requireDaemonState(home);
11620
+ const response = await fetch(`${state.origin}/api/custom-rates`, {
11621
+ method: "POST",
11622
+ headers: {
11623
+ authorization: `Bearer ${state.apiToken}`,
11624
+ "content-type": "application/json",
11625
+ origin: state.origin
11626
+ },
11627
+ body: JSON.stringify({
11628
+ ...options.id ? { id: options.id } : {},
11629
+ providerId: options.provider,
11630
+ billingDomainId: options.domain || null,
11631
+ model,
11632
+ inputRate: options.input,
11633
+ outputRate: options.output,
11634
+ cacheReadRate: options.cacheRead
11635
+ })
11636
+ });
11637
+ if (!response.ok) throw new Error(`Daemon returned HTTP ${response.status}`);
11638
+ const data = await response.json();
11639
+ process.stdout.write(
11640
+ `Custom model rate configured for ${data.rate.model} (ID: ${data.rate.id})
11641
+ `
11642
+ );
11643
+ }
11644
+ );
11645
+ ratesCommand.command("get <id>").description("get details of a custom model rate by ID").option("--json", "emit machine-readable JSON").action(async (id, options) => {
11646
+ const home = resolve4(program.opts().home);
11647
+ const state = await requireDaemonState(home);
11648
+ const response = await fetch(`${state.origin}/api/custom-rates/${encodeURIComponent(id)}`, {
11649
+ headers: { authorization: `Bearer ${state.apiToken}` }
11650
+ });
11651
+ if (!response.ok) {
11652
+ if (response.status === 404) throw new Error(`Custom model rate not found: ${id}`);
11653
+ throw new Error(`Daemon returned HTTP ${response.status}`);
11654
+ }
11655
+ const data = await response.json();
11656
+ if (options.json) {
11657
+ process.stdout.write(`${JSON.stringify(data.rate, null, 2)}
11658
+ `);
11659
+ return;
11660
+ }
11661
+ const domain = data.rate.billingDomainId ?? "*";
11662
+ process.stdout.write(
11663
+ `${data.rate.id} | ${data.rate.providerId} | domain: ${domain} | model: ${data.rate.model} | in: $${data.rate.ratesPerMillion.input}/M | out: $${data.rate.ratesPerMillion.output}/M | cache: $${data.rate.ratesPerMillion.cacheRead}/M | updated: ${data.rate.updatedAt}
11664
+ `
11665
+ );
11666
+ });
11667
+ ratesCommand.command("delete <id>").description("delete custom model rate by ID").action(async (id) => {
11668
+ const home = resolve4(program.opts().home);
11669
+ const state = await requireDaemonState(home);
11670
+ const response = await fetch(`${state.origin}/api/custom-rates/${encodeURIComponent(id)}`, {
11671
+ method: "DELETE",
11672
+ headers: {
11673
+ authorization: `Bearer ${state.apiToken}`,
11674
+ origin: state.origin
11675
+ }
11676
+ });
11677
+ if (!response.ok) throw new Error(`Daemon returned HTTP ${response.status}`);
11678
+ process.stdout.write(`Deleted custom model rate ${id}
11679
+ `);
11680
+ });
10335
11681
  program.command("serve").description("run the internal local daemon").action(async () => {
10336
11682
  const home = resolve4(program.opts().home);
10337
11683
  const { runDaemon: runDaemon2 } = await Promise.resolve().then(() => (init_runtime(), runtime_exports));
@@ -10515,6 +11861,6 @@ function formatDoctor(report) {
10515
11861
  ].join("\n");
10516
11862
  }
10517
11863
  function defaultHome() {
10518
- return join9(homedir4(), "Library", "Application Support", "Agent Usage");
11864
+ return join11(homedir5(), "Library", "Application Support", "Agent Usage");
10519
11865
  }
10520
11866
  //# sourceMappingURL=cli.js.map