agent-usage-all-in-one 0.7.2 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1450,382 +1450,6 @@ var init_retail_pricing = __esm({
1450
1450
  }
1451
1451
  });
1452
1452
 
1453
- // src/core/plan-pricing.ts
1454
- function buildBillingPeriod(subscription, summary, comparisonCurrency, rates) {
1455
- if (!summary) return null;
1456
- const start = new Date(summary.start).getTime();
1457
- const end = new Date(summary.end).getTime();
1458
- const observedThrough = new Date(summary.observedThrough).getTime();
1459
- const totalDays = (end - start) / MILLISECONDS_PER_DAY;
1460
- const elapsedDays = Math.max(0, Math.min(observedThrough, end) - start) / MILLISECONDS_PER_DAY;
1461
- const periodCost = planMoneyAmount(
1462
- preciseAmount(subscription.amount),
1463
- subscription.currency,
1464
- comparisonCurrency,
1465
- // The period's own rate evidence first, so a short rolling window cannot
1466
- // leave a cycle amount unconverted.
1467
- [...summary.retailEquivalent.exchangeRates, ...rates],
1468
- summary.observedThrough
1469
- );
1470
- const retailAmount = summary.retailEquivalent.status === "available" ? summary.retailEquivalent.amount : null;
1471
- const breakEvenRatio = periodCost.amount !== null && periodCost.amount > 0 && retailAmount !== null ? preciseAmount(retailAmount / periodCost.amount) : null;
1472
- return {
1473
- start: summary.start,
1474
- end: summary.end,
1475
- elapsedDays: preciseAmount(elapsedDays),
1476
- totalDays: preciseAmount(totalDays),
1477
- progress: totalDays > 0 ? preciseAmount(Math.min(1, elapsedDays / totalDays)) : 0,
1478
- periodCost,
1479
- recordedTokens: summary.observationCount > 0 ? summary.recordedTokens : null,
1480
- retailEquivalent: summary.retailEquivalent,
1481
- breakEvenRatio,
1482
- ratioBound: ratioBoundFor(breakEvenRatio, summary.retailEquivalent.pricingCoverage)
1483
- };
1484
- }
1485
- function planCatalogEntry(catalog, id) {
1486
- return catalog.entries.find((entry) => entry.id === id) ?? null;
1487
- }
1488
- function planCatalogEntriesForDomain(catalog, providerId, billingDomainId) {
1489
- return catalog.entries.filter(
1490
- (entry) => entry.providerId === providerId && entry.billingDomainId === billingDomainId
1491
- );
1492
- }
1493
- function addMonths(date, months) {
1494
- const day = date.getUTCDate();
1495
- const shifted = new Date(
1496
- Date.UTC(
1497
- date.getUTCFullYear(),
1498
- date.getUTCMonth() + months,
1499
- 1,
1500
- date.getUTCHours(),
1501
- date.getUTCMinutes(),
1502
- date.getUTCSeconds(),
1503
- date.getUTCMilliseconds()
1504
- )
1505
- );
1506
- const lastDayOfMonth = new Date(
1507
- Date.UTC(shifted.getUTCFullYear(), shifted.getUTCMonth() + 1, 0)
1508
- ).getUTCDate();
1509
- shifted.setUTCDate(Math.min(day, lastDayOfMonth));
1510
- return shifted;
1511
- }
1512
- function billingPeriodContaining(anchorDate, billingPeriod, at) {
1513
- const anchor = new Date(anchorDate.length === 10 ? `${anchorDate}T00:00:00.000Z` : anchorDate);
1514
- if (Number.isNaN(anchor.getTime())) return null;
1515
- const step = billingPeriod === "monthly" ? 1 : 12;
1516
- const monthsApart = (at.getUTCFullYear() - anchor.getUTCFullYear()) * 12 + (at.getUTCMonth() - anchor.getUTCMonth());
1517
- let index = Math.floor(monthsApart / step);
1518
- let start = addMonths(anchor, index * step);
1519
- while (start.getTime() > at.getTime()) {
1520
- index -= 1;
1521
- start = addMonths(anchor, index * step);
1522
- }
1523
- let end = addMonths(anchor, (index + 1) * step);
1524
- while (end.getTime() <= at.getTime()) {
1525
- index += 1;
1526
- start = end;
1527
- end = addMonths(anchor, (index + 1) * step);
1528
- }
1529
- return { start, end };
1530
- }
1531
- function windowDays(start, end) {
1532
- const span = new Date(end).getTime() - new Date(start).getTime();
1533
- return span > 0 ? span / MILLISECONDS_PER_DAY : 0;
1534
- }
1535
- function proratePlanPrice(amount, billingPeriod, days) {
1536
- return amount * days / PLAN_PERIOD_DAYS[billingPeriod];
1537
- }
1538
- function convertPlanAmount(amount, currency, comparisonCurrency, rates, end) {
1539
- if (currency.toUpperCase() === comparisonCurrency.toUpperCase()) {
1540
- return { amount, reason: null, rate: null };
1541
- }
1542
- const rate = rates.find(
1543
- (candidate) => candidate.baseCurrency.toUpperCase() === currency.toUpperCase() && candidate.quoteCurrency.toUpperCase() === comparisonCurrency.toUpperCase()
1544
- );
1545
- if (!rate) return { amount: null, reason: "missing-rate", rate: null };
1546
- if (new Date(end).getTime() - new Date(rate.observedAt).getTime() > STALE_RATE_MILLISECONDS) {
1547
- return { amount: null, reason: "stale-rate", rate };
1548
- }
1549
- return { amount: amount * rate.rate, reason: null, rate };
1550
- }
1551
- function preciseAmount(value) {
1552
- return Number(value.toPrecision(12));
1553
- }
1554
- function planMoneyAmount(nativeAmount, nativeCurrency, comparisonCurrency, rates, end) {
1555
- const converted = convertPlanAmount(nativeAmount, nativeCurrency, comparisonCurrency, rates, end);
1556
- return {
1557
- status: converted.amount === null ? "unavailable" : "available",
1558
- amount: converted.amount === null ? null : preciseAmount(converted.amount),
1559
- nativeAmount,
1560
- nativeCurrency,
1561
- comparisonCurrency,
1562
- conversionUnavailableReason: converted.reason,
1563
- exchangeRates: converted.rate ? [converted.rate] : []
1564
- };
1565
- }
1566
- function ratioBoundFor(ratio, pricingCoverage) {
1567
- if (ratio === null) return "unavailable";
1568
- return pricingCoverage !== null && pricingCoverage < 0.999 ? "lower" : "exact";
1569
- }
1570
- function unitPricePerMillion(amount, tokens) {
1571
- if (amount === null || tokens <= 0) return null;
1572
- return preciseAmount(amount / (tokens / 1e6));
1573
- }
1574
- function buildWorkbenchPlanValue(options) {
1575
- const { comparisonCurrency, start, end, rates } = options;
1576
- const days = windowDays(start, end);
1577
- const subscriptionByDomain = new Map(
1578
- options.subscriptions.map((subscription) => [
1579
- `${subscription.providerId}:${subscription.billingDomainId}`,
1580
- subscription
1581
- ])
1582
- );
1583
- const entries = [];
1584
- const metered = [];
1585
- const unconfigured = [];
1586
- for (const domain of options.domains) {
1587
- const subscription = subscriptionByDomain.get(`${domain.providerId}:${domain.billingDomainId}`);
1588
- if (!subscription) {
1589
- if (domain.actualCost.records > 0) {
1590
- metered.push({
1591
- providerId: domain.providerId,
1592
- providerDisplayName: domain.providerDisplayName,
1593
- billingDomainId: domain.billingDomainId,
1594
- billingDomainDisplayName: domain.billingDomainDisplayName,
1595
- recordedTokens: domain.observationCount > 0 ? domain.recordedTokens : null,
1596
- actualCost: domain.actualCost,
1597
- retailEquivalent: domain.retailEquivalent
1598
- });
1599
- continue;
1600
- }
1601
- if (domain.observationCount > 0) {
1602
- unconfigured.push({
1603
- providerId: domain.providerId,
1604
- providerDisplayName: domain.providerDisplayName,
1605
- billingDomainId: domain.billingDomainId,
1606
- billingDomainDisplayName: domain.billingDomainDisplayName,
1607
- recordedTokens: domain.recordedTokens
1608
- });
1609
- }
1610
- continue;
1611
- }
1612
- const windowPlanCost = planMoneyAmount(
1613
- preciseAmount(proratePlanPrice(subscription.amount, subscription.billingPeriod, days)),
1614
- subscription.currency,
1615
- comparisonCurrency,
1616
- rates,
1617
- end
1618
- );
1619
- const retail = domain.retailEquivalent;
1620
- const retailAmount = retail.status === "available" ? retail.amount : null;
1621
- const valueRatio = windowPlanCost.amount !== null && windowPlanCost.amount > 0 && retailAmount !== null ? preciseAmount(retailAmount / windowPlanCost.amount) : null;
1622
- const ratioBound = ratioBoundFor(valueRatio, retail.pricingCoverage);
1623
- const billingPeriod = buildBillingPeriod(
1624
- subscription,
1625
- options.billingPeriods?.get(`${domain.providerId}:${domain.billingDomainId}`),
1626
- comparisonCurrency,
1627
- rates
1628
- );
1629
- entries.push({
1630
- providerId: domain.providerId,
1631
- providerDisplayName: domain.providerDisplayName,
1632
- billingDomainId: domain.billingDomainId,
1633
- billingDomainDisplayName: domain.billingDomainDisplayName,
1634
- includedInHeadline: domain.includedInHeadline,
1635
- plan: {
1636
- planId: subscription.planId,
1637
- displayName: subscription.displayName,
1638
- amount: subscription.amount,
1639
- currency: subscription.currency,
1640
- billingPeriod: subscription.billingPeriod,
1641
- anchorDate: subscription.anchorDate,
1642
- priceSource: subscription.priceSource,
1643
- updatedAt: subscription.updatedAt
1644
- },
1645
- windowDays: preciseAmount(days),
1646
- windowPlanCost,
1647
- billingPeriod,
1648
- recordedTokens: domain.observationCount > 0 ? domain.recordedTokens : null,
1649
- retailEquivalent: retail,
1650
- valueRatio,
1651
- ratioBound,
1652
- status: valueRatio === null ? "unavailable" : ratioBound === "lower" ? "partial" : "available",
1653
- effectiveUnitPrice: unitPricePerMillion(windowPlanCost.amount, domain.recordedTokens),
1654
- retailUnitPrice: unitPricePerMillion(retailAmount, retail.pricedTokens),
1655
- pricingCoverage: retail.pricingCoverage,
1656
- authorities: domain.authorities,
1657
- lastObservedAt: domain.lastObservedAt
1658
- });
1659
- }
1660
- const rank = (entry) => entry.valueRatio ?? -1;
1661
- entries.sort(
1662
- (left, right) => rank(right) - rank(left) || `${left.providerId}:${left.billingDomainId}`.localeCompare(
1663
- `${right.providerId}:${right.billingDomainId}`
1664
- )
1665
- );
1666
- metered.sort(
1667
- (left, right) => `${left.providerId}:${left.billingDomainId}`.localeCompare(
1668
- `${right.providerId}:${right.billingDomainId}`
1669
- )
1670
- );
1671
- unconfigured.sort(
1672
- (left, right) => right.recordedTokens - left.recordedTokens || `${left.providerId}:${left.billingDomainId}`.localeCompare(
1673
- `${right.providerId}:${right.billingDomainId}`
1674
- )
1675
- );
1676
- return {
1677
- windowDays: preciseAmount(days),
1678
- comparisonCurrency,
1679
- catalogVersion: SUBSCRIPTION_PLAN_CATALOG.version,
1680
- entries,
1681
- meteredDomains: metered,
1682
- unconfiguredDomains: unconfigured
1683
- };
1684
- }
1685
- var PLAN_PERIOD_DAYS, MILLISECONDS_PER_DAY, STALE_RATE_MILLISECONDS, SUBSCRIPTION_PLAN_CATALOG;
1686
- var init_plan_pricing = __esm({
1687
- "src/core/plan-pricing.ts"() {
1688
- "use strict";
1689
- PLAN_PERIOD_DAYS = {
1690
- monthly: 365.25 / 12,
1691
- annual: 365.25
1692
- };
1693
- MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1e3;
1694
- STALE_RATE_MILLISECONDS = 7 * MILLISECONDS_PER_DAY;
1695
- SUBSCRIPTION_PLAN_CATALOG = {
1696
- version: "2026-08-30",
1697
- entries: [
1698
- {
1699
- id: "claude-pro-monthly",
1700
- providerId: "claude-code",
1701
- billingDomainId: "subscription",
1702
- displayName: "Claude Pro",
1703
- amount: 20,
1704
- currency: "USD",
1705
- billingPeriod: "monthly",
1706
- source: {
1707
- title: "Claude plans and pricing",
1708
- url: "https://claude.com/pricing",
1709
- retrievedAt: "2026-08-30"
1710
- }
1711
- },
1712
- {
1713
- id: "claude-pro-annual",
1714
- providerId: "claude-code",
1715
- billingDomainId: "subscription",
1716
- displayName: "Claude Pro (annual billing)",
1717
- amount: 17 * 12,
1718
- currency: "USD",
1719
- billingPeriod: "annual",
1720
- source: {
1721
- title: "Claude plans and pricing",
1722
- url: "https://claude.com/pricing",
1723
- retrievedAt: "2026-08-30"
1724
- }
1725
- },
1726
- {
1727
- id: "claude-max-5x",
1728
- providerId: "claude-code",
1729
- billingDomainId: "subscription",
1730
- displayName: "Claude Max 5x",
1731
- amount: 100,
1732
- currency: "USD",
1733
- billingPeriod: "monthly",
1734
- source: {
1735
- title: "What is the Max plan?",
1736
- url: "https://support.claude.com/en/articles/11049741-what-is-the-max-plan",
1737
- retrievedAt: "2026-08-30"
1738
- }
1739
- },
1740
- {
1741
- id: "claude-max-20x",
1742
- providerId: "claude-code",
1743
- billingDomainId: "subscription",
1744
- displayName: "Claude Max 20x",
1745
- amount: 200,
1746
- currency: "USD",
1747
- billingPeriod: "monthly",
1748
- source: {
1749
- title: "What is the Max plan?",
1750
- url: "https://support.claude.com/en/articles/11049741-what-is-the-max-plan",
1751
- retrievedAt: "2026-08-30"
1752
- }
1753
- },
1754
- {
1755
- id: "chatgpt-plus",
1756
- providerId: "codex",
1757
- billingDomainId: "subscription",
1758
- displayName: "ChatGPT Plus",
1759
- amount: 20,
1760
- currency: "USD",
1761
- billingPeriod: "monthly",
1762
- source: {
1763
- title: "ChatGPT pricing",
1764
- url: "https://chatgpt.com/pricing/",
1765
- retrievedAt: "2026-08-30"
1766
- }
1767
- },
1768
- {
1769
- id: "chatgpt-pro-100",
1770
- providerId: "codex",
1771
- billingDomainId: "subscription",
1772
- displayName: "ChatGPT Pro (5x)",
1773
- amount: 100,
1774
- currency: "USD",
1775
- billingPeriod: "monthly",
1776
- source: {
1777
- title: "About ChatGPT Pro tiers",
1778
- url: "https://help.openai.com/en/articles/9793128-about-chatgpt-pro-tiers",
1779
- retrievedAt: "2026-08-30"
1780
- }
1781
- },
1782
- {
1783
- id: "chatgpt-pro-200",
1784
- providerId: "codex",
1785
- billingDomainId: "subscription",
1786
- displayName: "ChatGPT Pro (20x)",
1787
- amount: 200,
1788
- currency: "USD",
1789
- billingPeriod: "monthly",
1790
- source: {
1791
- title: "About ChatGPT Pro tiers",
1792
- url: "https://help.openai.com/en/articles/9793128-about-chatgpt-pro-tiers",
1793
- retrievedAt: "2026-08-30"
1794
- }
1795
- },
1796
- {
1797
- id: "chatgpt-business-seat",
1798
- providerId: "codex",
1799
- billingDomainId: "subscription",
1800
- displayName: "ChatGPT Business (one seat)",
1801
- amount: 25,
1802
- currency: "USD",
1803
- billingPeriod: "monthly",
1804
- source: {
1805
- title: "ChatGPT Business pricing",
1806
- url: "https://openai.com/business/chatgpt-pricing/",
1807
- retrievedAt: "2026-08-30"
1808
- }
1809
- },
1810
- {
1811
- id: "opencode-go-monthly",
1812
- providerId: "opencode-go",
1813
- billingDomainId: "go-subscription",
1814
- displayName: "OpenCode Go",
1815
- amount: 10,
1816
- currency: "USD",
1817
- billingPeriod: "monthly",
1818
- source: {
1819
- title: "OpenCode Go",
1820
- url: "https://opencode.ai/go",
1821
- retrievedAt: "2026-08-30"
1822
- }
1823
- }
1824
- ]
1825
- };
1826
- }
1827
- });
1828
-
1829
1453
  // src/core/usage-application.ts
1830
1454
  import { randomUUID } from "crypto";
1831
1455
  function safeConnectorFailure(error) {
@@ -1866,6 +1490,11 @@ function createProcessingStatus(startedAt, hardRebuild) {
1866
1490
  function yieldToEventLoop() {
1867
1491
  return new Promise((resolve5) => setImmediate(resolve5));
1868
1492
  }
1493
+ function yieldForPendingHttp() {
1494
+ return new Promise((resolve5) => {
1495
+ setTimeout(resolve5, PENDING_HTTP_YIELD_MS);
1496
+ });
1497
+ }
1869
1498
  function providerForConnector(id, definitions) {
1870
1499
  return definitions.find((definition) => definition.id === id)?.target.provider.id ?? id;
1871
1500
  }
@@ -1938,7 +1567,7 @@ function pickAgentProviderIndex(overview) {
1938
1567
  providers: overview.providers.filter((provider) => provider.id !== "opencode" && provider.id !== "dsh").map(({ id, displayName }) => ({ id, displayName }))
1939
1568
  };
1940
1569
  }
1941
- var UsageApplication;
1570
+ var UsageApplication, PENDING_HTTP_YIELD_MS;
1942
1571
  var init_usage_application = __esm({
1943
1572
  "src/core/usage-application.ts"() {
1944
1573
  "use strict";
@@ -1946,7 +1575,6 @@ var init_usage_application = __esm({
1946
1575
  init_redaction();
1947
1576
  init_usage_export();
1948
1577
  init_retail_pricing();
1949
- init_plan_pricing();
1950
1578
  UsageApplication = class {
1951
1579
  #repository;
1952
1580
  #connectors;
@@ -1961,7 +1589,6 @@ var init_usage_application = __esm({
1961
1589
  #startAtLoginManager;
1962
1590
  #basePriceCatalog;
1963
1591
  #priceCatalog;
1964
- #planCatalog;
1965
1592
  #refreshPromise = null;
1966
1593
  #refreshMode = null;
1967
1594
  #backgroundPromise = null;
@@ -1984,7 +1611,6 @@ var init_usage_application = __esm({
1984
1611
  this.#startAtLoginManager = options.startAtLoginManager;
1985
1612
  this.#basePriceCatalog = options.priceCatalog === void 0 ? OFFICIAL_PRICING_CATALOG : options.priceCatalog;
1986
1613
  this.#priceCatalog = this.#resolvePriceCatalog();
1987
- this.#planCatalog = options.planCatalog ?? SUBSCRIPTION_PLAN_CATALOG;
1988
1614
  this.#processingStatus = createProcessingStatus(this.#clock().toISOString(), false);
1989
1615
  }
1990
1616
  #resolvePriceCatalog() {
@@ -2141,15 +1767,15 @@ var init_usage_application = __esm({
2141
1767
  const runtimeStates = new Map(
2142
1768
  this.#repository.getConnectorRuntimeStates().map((state) => [state.id, state])
2143
1769
  );
2144
- await Promise.all(
1770
+ const collected = await Promise.all(
2145
1771
  this.#connectors.map(async (connector) => {
2146
1772
  if (connector.consentId && connectorStates.get(connector.consentId) !== "connected") {
2147
- return;
1773
+ return null;
2148
1774
  }
2149
1775
  const now = this.#clock();
2150
1776
  const runtime = runtimeStates.get(connector.id);
2151
1777
  if (!options.userInitiated && runtime?.nextAllowedAt && new Date(runtime.nextAllowedAt).getTime() > now.getTime()) {
2152
- return;
1778
+ return null;
2153
1779
  }
2154
1780
  const policy = this.#connectorPolicies[connector.id] ?? {
2155
1781
  minimumIntervalMs: 0,
@@ -2161,54 +1787,27 @@ var init_usage_application = __esm({
2161
1787
  policy.timeoutMs,
2162
1788
  `${connector.id} timed out`
2163
1789
  );
2164
- this.#repository.saveSnapshot(this.#withRetailCosts(snapshot2));
2165
- if (snapshot2.warnings && snapshot2.warnings.length > 0) {
2166
- const failure = redactFailure(combineFailures(snapshot2.warnings));
2167
- this.#repository.recordFailure(snapshot2.provider, this.#clock().toISOString(), failure);
2168
- this.#saveConnectorDiagnostic(
2169
- connector,
2170
- snapshot2.provider.id,
2171
- snapshot2.billingDomains[0]?.id ?? defaultBillingDomain(connector.id, this.#connectorDefinitions),
2172
- failure
2173
- );
2174
- this.#recordConnectorOutcome(
2175
- connector.id,
2176
- now,
2177
- policy,
2178
- false,
2179
- runtime?.failureCount ?? 0
2180
- );
2181
- } else {
2182
- this.#saveHealthyConnectorDiagnostic(
2183
- connector,
2184
- snapshot2.provider.id,
2185
- snapshot2.billingDomains[0]?.id ?? defaultBillingDomain(connector.id, this.#connectorDefinitions),
2186
- snapshot2.observedAt
2187
- );
2188
- this.#recordConnectorOutcome(
2189
- connector.id,
2190
- now,
2191
- policy,
2192
- true,
2193
- runtime?.failureCount ?? 0
2194
- );
2195
- }
1790
+ return { ok: true, connector, now, runtime, policy, snapshot: snapshot2 };
2196
1791
  } catch (error) {
2197
- const providerId = providerForConnector(connector.id, this.#connectorDefinitions);
2198
- const failure = redactFailure(safeConnectorFailure(error));
2199
- this.#repository.recordFailure(
2200
- {
2201
- id: providerId,
2202
- displayName: displayNameForProvider(providerId, connector.displayName)
2203
- },
2204
- this.#clock().toISOString(),
2205
- failure
2206
- );
1792
+ return { ok: false, connector, now, runtime, policy, error };
1793
+ }
1794
+ })
1795
+ );
1796
+ if (collected.some((result) => result !== null)) await yieldForPendingHttp();
1797
+ for (const result of collected) {
1798
+ if (!result) continue;
1799
+ const { connector, now, runtime, policy } = result;
1800
+ if (result.ok) {
1801
+ const snapshot2 = result.snapshot;
1802
+ await this.#repository.saveSnapshot(this.#withRetailCosts(snapshot2));
1803
+ if (snapshot2.warnings && snapshot2.warnings.length > 0) {
1804
+ const failure2 = redactFailure(combineFailures(snapshot2.warnings));
1805
+ this.#repository.recordFailure(snapshot2.provider, this.#clock().toISOString(), failure2);
2207
1806
  this.#saveConnectorDiagnostic(
2208
1807
  connector,
2209
- providerId,
2210
- defaultBillingDomain(connector.id, this.#connectorDefinitions),
2211
- failure
1808
+ snapshot2.provider.id,
1809
+ snapshot2.billingDomains[0]?.id ?? defaultBillingDomain(connector.id, this.#connectorDefinitions),
1810
+ failure2
2212
1811
  );
2213
1812
  this.#recordConnectorOutcome(
2214
1813
  connector.id,
@@ -2217,9 +1816,35 @@ var init_usage_application = __esm({
2217
1816
  false,
2218
1817
  runtime?.failureCount ?? 0
2219
1818
  );
1819
+ } else {
1820
+ this.#saveHealthyConnectorDiagnostic(
1821
+ connector,
1822
+ snapshot2.provider.id,
1823
+ snapshot2.billingDomains[0]?.id ?? defaultBillingDomain(connector.id, this.#connectorDefinitions),
1824
+ snapshot2.observedAt
1825
+ );
1826
+ this.#recordConnectorOutcome(connector.id, now, policy, true, runtime?.failureCount ?? 0);
2220
1827
  }
2221
- })
2222
- );
1828
+ continue;
1829
+ }
1830
+ const providerId = providerForConnector(connector.id, this.#connectorDefinitions);
1831
+ const failure = redactFailure(safeConnectorFailure(result.error));
1832
+ this.#repository.recordFailure(
1833
+ {
1834
+ id: providerId,
1835
+ displayName: displayNameForProvider(providerId, connector.displayName)
1836
+ },
1837
+ this.#clock().toISOString(),
1838
+ failure
1839
+ );
1840
+ this.#saveConnectorDiagnostic(
1841
+ connector,
1842
+ providerId,
1843
+ defaultBillingDomain(connector.id, this.#connectorDefinitions),
1844
+ failure
1845
+ );
1846
+ this.#recordConnectorOutcome(connector.id, now, policy, false, runtime?.failureCount ?? 0);
1847
+ }
2223
1848
  if (this.#repository.getMonitoringSettings().notificationsEnabled) {
2224
1849
  await this.#sendNotificationTransitions();
2225
1850
  }
@@ -2290,54 +1915,6 @@ var init_usage_application = __esm({
2290
1915
  connectors: this.#repository.getConnectorRuntimeStates()
2291
1916
  };
2292
1917
  }
2293
- async getPlanSettings() {
2294
- return {
2295
- catalogVersion: this.#planCatalog.version,
2296
- domains: this.#planEligibleDomains(),
2297
- subscriptions: this.#repository.getPlanSubscriptions()
2298
- };
2299
- }
2300
- async updatePlanSubscription(input) {
2301
- const domain = this.#planEligibleDomains().find(
2302
- (candidate) => candidate.providerId === input.providerId && candidate.billingDomainId === input.billingDomainId
2303
- );
2304
- if (!domain) throw new Error("Unknown subscription billing domain");
2305
- if (input.plan === null) {
2306
- this.#repository.deletePlanSubscription(input.providerId, input.billingDomainId);
2307
- return this.getPlanSettings();
2308
- }
2309
- const preset = input.plan.planId ? planCatalogEntry(this.#planCatalog, input.plan.planId) : null;
2310
- if (input.plan.planId && !preset) throw new Error("Unknown plan preset");
2311
- if (preset && (preset.providerId !== input.providerId || preset.billingDomainId !== input.billingDomainId)) {
2312
- throw new Error("Plan preset belongs to another billing domain");
2313
- }
2314
- const amount = input.plan.amount ?? preset?.amount;
2315
- if (amount === void 0) throw new Error("A plan price is required");
2316
- if (!Number.isFinite(amount) || amount <= 0) {
2317
- throw new Error("A plan price must be a positive amount");
2318
- }
2319
- const currency = (input.plan.currency ?? preset?.currency ?? "USD").toUpperCase();
2320
- if (!/^[A-Z]{3}$/.test(currency)) throw new Error("A plan currency must be a 3-letter code");
2321
- const billingPeriod = input.plan.billingPeriod ?? preset?.billingPeriod ?? "monthly";
2322
- const anchorDate = input.plan.anchorDate ?? null;
2323
- if (anchorDate !== null && Number.isNaN((/* @__PURE__ */ new Date(`${anchorDate}T00:00:00.000Z`)).getTime())) {
2324
- throw new Error("A renewal date must be a calendar date");
2325
- }
2326
- const overridesPreset = preset !== null && (amount !== preset.amount || currency !== preset.currency.toUpperCase() || billingPeriod !== preset.billingPeriod);
2327
- this.#repository.savePlanSubscription({
2328
- providerId: input.providerId,
2329
- billingDomainId: input.billingDomainId,
2330
- planId: preset?.id ?? null,
2331
- displayName: preset?.displayName ?? "",
2332
- amount,
2333
- currency,
2334
- billingPeriod,
2335
- anchorDate,
2336
- priceSource: preset && !overridesPreset ? "catalog-preset" : "user-entered",
2337
- updatedAt: this.#clock().toISOString()
2338
- });
2339
- return this.getPlanSettings();
2340
- }
2341
1918
  async getCustomModelRates() {
2342
1919
  return this.#repository.getCustomModelRates?.() ?? [];
2343
1920
  }
@@ -2389,35 +1966,6 @@ var init_usage_application = __esm({
2389
1966
  }
2390
1967
  return deleted;
2391
1968
  }
2392
- /**
2393
- * A billing domain can carry a plan price when its connector does not report
2394
- * an actual metered charge. Metered domains keep their own billed amounts and
2395
- * never receive a declared subscription price.
2396
- */
2397
- #planEligibleDomains() {
2398
- const domains = /* @__PURE__ */ new Map();
2399
- for (const definition of this.#connectorDefinitions) {
2400
- if (definition.expectedCoverage?.includes("actual-cost")) continue;
2401
- const key = `${definition.target.provider.id}:${definition.target.billingDomain.id}`;
2402
- if (domains.has(key)) continue;
2403
- domains.set(key, {
2404
- providerId: definition.target.provider.id,
2405
- providerDisplayName: definition.target.provider.displayName,
2406
- billingDomainId: definition.target.billingDomain.id,
2407
- billingDomainDisplayName: definition.target.billingDomain.displayName,
2408
- presets: planCatalogEntriesForDomain(
2409
- this.#planCatalog,
2410
- definition.target.provider.id,
2411
- definition.target.billingDomain.id
2412
- )
2413
- });
2414
- }
2415
- return [...domains.values()].sort(
2416
- (left, right) => `${left.providerId}:${left.billingDomainId}`.localeCompare(
2417
- `${right.providerId}:${right.billingDomainId}`
2418
- )
2419
- );
2420
- }
2421
1969
  async #sendNotificationTransitions() {
2422
1970
  if (!this.#notifier) return;
2423
1971
  const overview = this.#repository.getOverview(this.#clock());
@@ -2566,6 +2114,12 @@ var init_usage_application = __esm({
2566
2114
  async getOverview(query = {}) {
2567
2115
  return this.#repository.getOverview(this.#clock(), query);
2568
2116
  }
2117
+ async getUsageWall(query = {}) {
2118
+ if (!this.#repository.getUsageWall) {
2119
+ throw new Error("Usage wall is unavailable");
2120
+ }
2121
+ return this.#repository.getUsageWall(this.#clock(), query);
2122
+ }
2569
2123
  async getAgentProviderIndex() {
2570
2124
  const now = this.#clock();
2571
2125
  return this.#repository.getAgentProviderIndex?.(now) ?? pickAgentProviderIndex(this.#repository.getOverview(now));
@@ -2629,9 +2183,9 @@ var init_usage_application = __esm({
2629
2183
  if (snapshot2.usage.length === 0 && snapshot2.costs.length === 0) {
2630
2184
  throw new Error("Telemetry payload contained no supported metrics");
2631
2185
  }
2632
- await this.#queueDatabaseWrite(() => {
2633
- this.#repository.saveSnapshot(this.#withRetailCosts(snapshot2), { preserveFailure: true });
2634
- });
2186
+ await this.#queueDatabaseWrite(
2187
+ () => this.#repository.saveSnapshot(this.#withRetailCosts(snapshot2), { preserveFailure: true })
2188
+ );
2635
2189
  }
2636
2190
  #queueDatabaseWrite(action) {
2637
2191
  const result = this.#databaseWriteQueue.then(action, action);
@@ -2746,6 +2300,7 @@ var init_usage_application = __esm({
2746
2300
  return status;
2747
2301
  }
2748
2302
  };
2303
+ PENDING_HTTP_YIELD_MS = 20;
2749
2304
  }
2750
2305
  });
2751
2306
 
@@ -7452,6 +7007,16 @@ async function startLocalServer(options) {
7452
7007
  sendJson(response, 200, await options.application.getOverview(query));
7453
7008
  return;
7454
7009
  }
7010
+ if (request.method === "GET" && requestUrl.pathname === "/api/usage-wall") {
7011
+ sendJson(
7012
+ response,
7013
+ 200,
7014
+ await options.application.getUsageWall({
7015
+ timeZone: requestUrl.searchParams.get("timeZone") ?? void 0
7016
+ })
7017
+ );
7018
+ return;
7019
+ }
7455
7020
  if (request.method === "POST" && requestUrl.pathname === "/api/refresh") {
7456
7021
  if (authentication === "browser" && request.headers.origin !== origin) {
7457
7022
  sendJson(response, 403, { error: "invalid-origin" });
@@ -7516,19 +7081,6 @@ async function startLocalServer(options) {
7516
7081
  sendJson(response, 200, await options.application.clearData(input));
7517
7082
  return;
7518
7083
  }
7519
- if (request.method === "GET" && requestUrl.pathname === "/api/plans") {
7520
- sendJson(response, 200, await options.application.getPlanSettings());
7521
- return;
7522
- }
7523
- if (request.method === "PATCH" && requestUrl.pathname === "/api/plans") {
7524
- if (!validMutationOrigin(authentication, request, origin)) {
7525
- sendJson(response, 403, { error: "invalid-origin" });
7526
- return;
7527
- }
7528
- const input = planSubscriptionSchema.parse(await readJsonBody(request));
7529
- sendJson(response, 200, await options.application.updatePlanSubscription(input));
7530
- return;
7531
- }
7532
7084
  if (request.method === "GET" && requestUrl.pathname === "/api/custom-rates") {
7533
7085
  const rates = await options.application.getCustomModelRates();
7534
7086
  sendJson(response, 200, { rates });
@@ -7790,7 +7342,7 @@ function sendHtml(response, status, body) {
7790
7342
  response.writeHead(status, { "content-type": "text/html; charset=utf-8" });
7791
7343
  response.end(body);
7792
7344
  }
7793
- var SESSION_COOKIE, connectorActionSchema, usageQuerySchema, monitoringSettingsSchema, planSubscriptionSchema, customModelRateSchema, clearDataSchema, hardRebuildSchema;
7345
+ var SESSION_COOKIE, connectorActionSchema, usageQuerySchema, monitoringSettingsSchema, customModelRateSchema, clearDataSchema, hardRebuildSchema;
7794
7346
  var init_local_server = __esm({
7795
7347
  "src/server/local-server.ts"() {
7796
7348
  "use strict";
@@ -7813,17 +7365,6 @@ var init_local_server = __esm({
7813
7365
  notificationsEnabled: z9.boolean().optional(),
7814
7366
  startAtLogin: z9.boolean().optional()
7815
7367
  }).refine((value) => Object.keys(value).length > 0, "At least one setting is required");
7816
- planSubscriptionSchema = z9.object({
7817
- providerId: z9.string().min(1),
7818
- billingDomainId: z9.string().min(1),
7819
- plan: z9.object({
7820
- planId: z9.string().min(1).nullable(),
7821
- amount: z9.number().positive().finite().optional(),
7822
- currency: z9.string().length(3).optional(),
7823
- billingPeriod: z9.enum(["monthly", "annual"]).optional(),
7824
- anchorDate: z9.string().regex(/^\d{4}-\d{2}-\d{2}$/).nullable().optional()
7825
- }).nullable()
7826
- });
7827
7368
  customModelRateSchema = z9.object({
7828
7369
  id: z9.string().optional(),
7829
7370
  providerId: z9.string().min(1),
@@ -8283,7 +7824,7 @@ function buildGlobalSummary(providers, riskSummary, now, query) {
8283
7824
  tokenEvidence,
8284
7825
  apiRetailEquivalent: {
8285
7826
  status: sawRetailEquivalent ? "available" : "unavailable",
8286
- amount: sawRetailEquivalent ? preciseAmount2(retailAmount) : null,
7827
+ amount: sawRetailEquivalent ? preciseAmount(retailAmount) : null,
8287
7828
  currency: "USD",
8288
7829
  pricingCoverage: tokenEvidence.recordedTokens === 0 ? null : retailPricedTokens / tokenEvidence.recordedTokens
8289
7830
  },
@@ -8293,7 +7834,7 @@ function buildGlobalSummary(providers, riskSummary, now, query) {
8293
7834
  contributions
8294
7835
  };
8295
7836
  }
8296
- function buildTokenMoneyWorkbench(providers, now, query, planSubscriptions, planBillingPeriods) {
7837
+ function buildTokenMoneyWorkbench(providers, now, query) {
8297
7838
  const normalized = normalizeUsageQuery(now, query);
8298
7839
  const allHistories = allDomainHistories(providers);
8299
7840
  const headlineHistories = allHistories.filter(({ includedInHeadline }) => includedInHeadline);
@@ -8484,43 +8025,9 @@ function buildTokenMoneyWorkbench(providers, now, query, planSubscriptions, plan
8484
8025
  observationCount > 0 ? recordedTokens : null,
8485
8026
  retailEquivalent,
8486
8027
  reportedEstimate
8487
- ),
8488
- planValue: buildWorkbenchPlanValue({
8489
- domains: planValueDomains(allHistories, comparisonCurrency),
8490
- subscriptions: planSubscriptions,
8491
- comparisonCurrency,
8492
- start: normalized.start.toISOString(),
8493
- end: normalized.end.toISOString(),
8494
- rates: uniqueExchangeRates(allHistories.flatMap(({ history }) => history.exchangeRates)),
8495
- billingPeriods: planBillingPeriods
8496
- })
8028
+ )
8497
8029
  };
8498
8030
  }
8499
- function planValueDomains(histories, comparisonCurrency) {
8500
- return histories.map(({ provider, domain, history, includedInHeadline }) => {
8501
- const domainTokens = history.tokenEvidence.recordedTokens;
8502
- const metric = (purpose) => buildWorkbenchMetric(
8503
- history.costs,
8504
- purpose,
8505
- comparisonCurrency,
8506
- domainTokens,
8507
- history.exchangeRates
8508
- );
8509
- return {
8510
- providerId: provider.id,
8511
- providerDisplayName: provider.displayName,
8512
- billingDomainId: domain.id,
8513
- billingDomainDisplayName: domain.displayName,
8514
- includedInHeadline,
8515
- recordedTokens: domainTokens,
8516
- observationCount: history.tokenEvidence.observationCount,
8517
- retailEquivalent: metric("retail-equivalent"),
8518
- actualCost: metric("actual"),
8519
- authorities: history.authorities ?? [],
8520
- lastObservedAt: history.lastObservedAt ?? null
8521
- };
8522
- });
8523
- }
8524
8031
  function allDomainHistories(providers) {
8525
8032
  return providers.flatMap(
8526
8033
  (provider) => provider.billingDomains.map((domain) => ({
@@ -8576,11 +8083,11 @@ function buildWorkbenchMetric(costs, purpose, comparisonCurrency, recordedTokens
8576
8083
  return {
8577
8084
  purpose,
8578
8085
  status,
8579
- amount: status === "available" ? preciseAmount2(convertedAmount) : null,
8086
+ amount: status === "available" ? preciseAmount(convertedAmount) : null,
8580
8087
  comparisonCurrency,
8581
8088
  nativeAmounts: [...native.entries()].map(([currency, amount]) => ({
8582
8089
  currency,
8583
- amount: amount.complete ? preciseAmount2(amount.amount) : null,
8090
+ amount: amount.complete ? preciseAmount(amount.amount) : null,
8584
8091
  records: amount.records,
8585
8092
  knownRecords: amount.knownRecords
8586
8093
  })).sort((left, right) => left.currency.localeCompare(right.currency)),
@@ -8990,6 +8497,49 @@ function mapUnclassifiedObservation(row) {
8990
8497
  }
8991
8498
  };
8992
8499
  }
8500
+ function addLocalDays(date, days) {
8501
+ const next = /* @__PURE__ */ new Date(`${date}T00:00:00.000Z`);
8502
+ next.setUTCDate(next.getUTCDate() + days);
8503
+ return next.toISOString().slice(0, 10);
8504
+ }
8505
+ function zonedStartOfDay(date, timeZone) {
8506
+ const [year, month, day] = date.split("-").map(Number);
8507
+ const desiredUtc = Date.UTC(year, month - 1, day);
8508
+ let result = desiredUtc;
8509
+ for (let iteration = 0; iteration < 2; iteration += 1) {
8510
+ const parts = new Intl.DateTimeFormat("en-GB", {
8511
+ timeZone,
8512
+ year: "numeric",
8513
+ month: "2-digit",
8514
+ day: "2-digit",
8515
+ hour: "2-digit",
8516
+ minute: "2-digit",
8517
+ second: "2-digit",
8518
+ hourCycle: "h23"
8519
+ }).formatToParts(result);
8520
+ const part = (type) => Number(parts.find((candidate) => candidate.type === type)?.value);
8521
+ const representedUtc = Date.UTC(
8522
+ part("year"),
8523
+ part("month") - 1,
8524
+ part("day"),
8525
+ part("hour"),
8526
+ part("minute"),
8527
+ part("second")
8528
+ );
8529
+ result += desiredUtc - representedUtc;
8530
+ }
8531
+ return new Date(result).toISOString();
8532
+ }
8533
+ function usageWallLevel(recordedTokens, positiveTotals) {
8534
+ if (recordedTokens <= 0 || positiveTotals.length === 0) return 0;
8535
+ const index = positiveTotals.findIndex((value) => value >= recordedTokens);
8536
+ const rank = index === -1 ? positiveTotals.length - 1 : index;
8537
+ const ratio = (rank + 1) / positiveTotals.length;
8538
+ if (ratio <= 0.25) return 1;
8539
+ if (ratio <= 0.5) return 2;
8540
+ if (ratio <= 0.75) return 3;
8541
+ return 4;
8542
+ }
8993
8543
  function localDay(observedAt, timeZone) {
8994
8544
  const parts = new Intl.DateTimeFormat("en-US", {
8995
8545
  timeZone,
@@ -9226,7 +8776,7 @@ function round(value) {
9226
8776
  function pricingInputsChanged(existing, observation) {
9227
8777
  return existing.billing_domain_id !== observation.billingDomainId || existing.model !== (observation.model?.trim() || "__unclassified__") || existing.observed_at !== observation.observedAt || Number(existing.total_tokens) !== observation.recordedTokens || Number(existing.input_tokens) !== observation.inputTokens || Number(existing.output_tokens) !== observation.outputTokens || Number(existing.reasoning_tokens) !== observation.reasoningTokens || Number(existing.cache_read_tokens) !== observation.cacheReadTokens || Number(existing.cache_write_tokens) !== observation.cacheWriteTokens || (existing.cache_write_5m_tokens === null ? null : Number(existing.cache_write_5m_tokens)) !== (observation.cacheWriteTokenBreakdown?.fiveMinute ?? null) || (existing.cache_write_1h_tokens === null ? null : Number(existing.cache_write_1h_tokens)) !== (observation.cacheWriteTokenBreakdown?.oneHour ?? null) || Number(existing.unclassified_tokens) !== observation.unclassifiedTokens || existing.reasoning_semantics !== observation.tokenSemantics.reasoning || existing.cache_read_semantics !== observation.tokenSemantics.cacheRead || existing.cache_write_semantics !== observation.tokenSemantics.cacheWrite || existing.model_attribution !== observation.modelAttribution || existing.time_precision !== observation.timePrecision || existing.aggregation_temporality !== observation.aggregationTemporality;
9228
8778
  }
9229
- function preciseAmount2(value) {
8779
+ function preciseAmount(value) {
9230
8780
  return Number(value.toFixed(12));
9231
8781
  }
9232
8782
  function tokenAuthority(authorities) {
@@ -9263,7 +8813,6 @@ var init_sqlite_usage_repository = __esm({
9263
8813
  "use strict";
9264
8814
  init_token_normalization();
9265
8815
  init_quota_normalization();
9266
- init_plan_pricing();
9267
8816
  FRESHNESS_WINDOW_MS = 15 * 60 * 1e3;
9268
8817
  QUERY_INDEXES_SQL = `
9269
8818
  CREATE INDEX IF NOT EXISTS usage_observed_at_idx
@@ -9335,7 +8884,7 @@ var init_sqlite_usage_repository = __esm({
9335
8884
  this.#database.exec("PRAGMA journal_mode = WAL; PRAGMA foreign_keys = ON;");
9336
8885
  this.#migrate();
9337
8886
  }
9338
- saveSnapshot(snapshot2, options = {}) {
8887
+ async saveSnapshot(snapshot2, options = {}) {
9339
8888
  this.#database.exec("BEGIN IMMEDIATE");
9340
8889
  try {
9341
8890
  const providerSql = options.preserveFailure ? `INSERT INTO providers (
@@ -9848,23 +9397,101 @@ var init_sqlite_usage_repository = __esm({
9848
9397
  (provider) => this.#getProviderOverview(provider, now, query)
9849
9398
  );
9850
9399
  const riskSummary = buildRiskSummary(overviews);
9851
- const planSubscriptions = this.getPlanSubscriptions();
9852
9400
  const overview = {
9853
9401
  generatedAt: now.toISOString(),
9854
9402
  globalSummary: buildGlobalSummary(overviews, riskSummary, now, query),
9855
- workbench: buildTokenMoneyWorkbench(
9856
- overviews,
9857
- now,
9858
- query,
9859
- planSubscriptions,
9860
- this.#planBillingPeriodSummaries(planSubscriptions, now, query)
9861
- ),
9403
+ workbench: buildTokenMoneyWorkbench(overviews, now, query),
9862
9404
  providers: overviews,
9863
9405
  riskSummary
9864
9406
  };
9865
9407
  if (!query.auditEvidence) dropAuditEvidence(overviews);
9866
9408
  return overview;
9867
9409
  }
9410
+ getUsageWall(now, query = {}) {
9411
+ const timeZone = validTimeZone(query.timeZone) ? query.timeZone : "UTC";
9412
+ const today = localDay(now.toISOString(), timeZone);
9413
+ const start = addLocalDays(today, -365);
9414
+ const startInstant = zonedStartOfDay(start, timeZone);
9415
+ const endExclusiveInstant = zonedStartOfDay(addLocalDays(today, 1), timeZone);
9416
+ const providers = this.#database.prepare("SELECT id, display_name FROM providers ORDER BY id").all();
9417
+ const visibleProviders = this.#hideDemoProvider ? providers.filter((provider) => provider.id !== "demo") : providers;
9418
+ const headlineDomains = /* @__PURE__ */ new Map();
9419
+ for (const provider of visibleProviders) {
9420
+ const domains = this.#database.prepare(
9421
+ `SELECT id, display_name, last_success_at
9422
+ FROM billing_domains WHERE provider_id = ? ORDER BY id`
9423
+ ).all(provider.id);
9424
+ const summaryBillingDomainId = selectSummaryBillingDomainId(provider.id, domains);
9425
+ if (!summaryBillingDomainId) continue;
9426
+ headlineDomains.set(`${provider.id}:${summaryBillingDomainId}`, {
9427
+ displayName: provider.display_name,
9428
+ domainId: summaryBillingDomainId
9429
+ });
9430
+ }
9431
+ const totals = /* @__PURE__ */ new Map();
9432
+ const addContribution = (date, providerId, displayName, recordedTokens2) => {
9433
+ if (date < start || date > today || recordedTokens2 <= 0) return;
9434
+ const current = totals.get(date) ?? { recordedTokens: 0, providers: /* @__PURE__ */ new Map() };
9435
+ current.recordedTokens += recordedTokens2;
9436
+ current.providers.set(providerId, { providerId, displayName });
9437
+ totals.set(date, current);
9438
+ };
9439
+ const observationRows = this.#database.prepare(
9440
+ `SELECT provider_id, billing_domain_id, observed_at, total_tokens
9441
+ FROM usage_observations
9442
+ WHERE observed_at >= ? AND observed_at < ? AND ${additiveUsagePredicate()}
9443
+ ORDER BY observed_at, id`
9444
+ ).all(startInstant, endExclusiveInstant);
9445
+ for (const row of observationRows) {
9446
+ const headline = headlineDomains.get(`${row.provider_id}:${row.billing_domain_id}`);
9447
+ if (!headline) continue;
9448
+ addContribution(
9449
+ localDay(row.observed_at, timeZone),
9450
+ row.provider_id,
9451
+ headline.displayName,
9452
+ Number(row.total_tokens)
9453
+ );
9454
+ }
9455
+ const aggregateRows = this.#database.prepare(
9456
+ `SELECT provider_id, billing_domain_id, day_utc, total_tokens
9457
+ FROM daily_usage_aggregates
9458
+ WHERE day_utc >= ? AND day_utc <= ?
9459
+ ORDER BY day_utc, provider_id, billing_domain_id`
9460
+ ).all(start, today);
9461
+ for (const row of aggregateRows) {
9462
+ const headline = headlineDomains.get(`${row.provider_id}:${row.billing_domain_id}`);
9463
+ if (!headline) continue;
9464
+ addContribution(
9465
+ localDay(`${row.day_utc}T12:00:00.000Z`, timeZone),
9466
+ row.provider_id,
9467
+ headline.displayName,
9468
+ Number(row.total_tokens)
9469
+ );
9470
+ }
9471
+ const positiveTotals = [...totals.values()].map((day) => day.recordedTokens).filter((value) => value > 0).sort((left, right) => left - right);
9472
+ const days = [];
9473
+ let recordedTokens = 0;
9474
+ for (let cursor = start; cursor <= today; cursor = addLocalDays(cursor, 1)) {
9475
+ const contribution = totals.get(cursor);
9476
+ const dayTokens = contribution?.recordedTokens ?? 0;
9477
+ recordedTokens += dayTokens;
9478
+ days.push({
9479
+ date: cursor,
9480
+ recordedTokens: dayTokens,
9481
+ level: usageWallLevel(dayTokens, positiveTotals),
9482
+ providers: contribution ? [...contribution.providers.values()].sort(
9483
+ (left, right) => left.providerId.localeCompare(right.providerId)
9484
+ ) : []
9485
+ });
9486
+ }
9487
+ return {
9488
+ timeZone,
9489
+ start,
9490
+ end: today,
9491
+ recordedTokens,
9492
+ days
9493
+ };
9494
+ }
9868
9495
  getAgentProviderIndex(now) {
9869
9496
  const providers = this.#database.prepare("SELECT id, display_name FROM providers ORDER BY id").all();
9870
9497
  return {
@@ -9960,57 +9587,6 @@ var init_sqlite_usage_repository = __esm({
9960
9587
  settings.startAtLogin ? 1 : 0
9961
9588
  );
9962
9589
  }
9963
- getPlanSubscriptions() {
9964
- const rows = this.#database.prepare(
9965
- `SELECT provider_id, billing_domain_id, plan_id, display_name, amount, currency,
9966
- billing_period, anchor_date, price_source, updated_at
9967
- FROM plan_subscriptions
9968
- ORDER BY provider_id, billing_domain_id`
9969
- ).all();
9970
- return rows.map((row) => ({
9971
- providerId: row.provider_id,
9972
- billingDomainId: row.billing_domain_id,
9973
- planId: row.plan_id,
9974
- displayName: row.display_name,
9975
- amount: row.amount,
9976
- currency: row.currency,
9977
- billingPeriod: row.billing_period,
9978
- anchorDate: row.anchor_date,
9979
- priceSource: row.price_source,
9980
- updatedAt: row.updated_at
9981
- }));
9982
- }
9983
- savePlanSubscription(subscription) {
9984
- this.#database.prepare(
9985
- `INSERT INTO plan_subscriptions (
9986
- provider_id, billing_domain_id, plan_id, display_name, amount, currency,
9987
- billing_period, anchor_date, price_source, updated_at
9988
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
9989
- ON CONFLICT(provider_id, billing_domain_id) DO UPDATE SET
9990
- plan_id = excluded.plan_id,
9991
- display_name = excluded.display_name,
9992
- amount = excluded.amount,
9993
- currency = excluded.currency,
9994
- billing_period = excluded.billing_period,
9995
- anchor_date = excluded.anchor_date,
9996
- price_source = excluded.price_source,
9997
- updated_at = excluded.updated_at`
9998
- ).run(
9999
- subscription.providerId,
10000
- subscription.billingDomainId,
10001
- subscription.planId,
10002
- subscription.displayName,
10003
- subscription.amount,
10004
- subscription.currency,
10005
- subscription.billingPeriod,
10006
- subscription.anchorDate,
10007
- subscription.priceSource,
10008
- subscription.updatedAt
10009
- );
10010
- }
10011
- deletePlanSubscription(providerId, billingDomainId) {
10012
- this.#database.prepare("DELETE FROM plan_subscriptions WHERE provider_id = ? AND billing_domain_id = ?").run(providerId, billingDomainId);
10013
- }
10014
9590
  getCustomModelRates() {
10015
9591
  const rows = this.#database.prepare(
10016
9592
  `SELECT id, provider_id, billing_domain_id, model,
@@ -10588,101 +10164,6 @@ var init_sqlite_usage_repository = __esm({
10588
10164
  coverageByDomain
10589
10165
  };
10590
10166
  }
10591
- /**
10592
- * Cycle-to-date evidence for every subscription that declares a renewal date.
10593
- * Each Provider is measured over its own billing period, which is why this
10594
- * cannot reuse the one rolling window the rest of the workbench shares.
10595
- */
10596
- #planBillingPeriodSummaries(subscriptions, now, query) {
10597
- const normalized = normalizeUsageQuery(now, query);
10598
- const summaries = /* @__PURE__ */ new Map();
10599
- for (const subscription of subscriptions) {
10600
- if (!subscription.anchorDate) continue;
10601
- const period = billingPeriodContaining(
10602
- subscription.anchorDate,
10603
- subscription.billingPeriod,
10604
- now
10605
- );
10606
- if (!period) continue;
10607
- const observedThrough = new Date(Math.min(now.getTime(), period.end.getTime()));
10608
- summaries.set(`${subscription.providerId}:${subscription.billingDomainId}`, {
10609
- start: period.start.toISOString(),
10610
- end: period.end.toISOString(),
10611
- observedThrough: observedThrough.toISOString(),
10612
- ...this.#rangeUsageSummary(
10613
- subscription.providerId,
10614
- subscription.billingDomainId,
10615
- period.start,
10616
- observedThrough,
10617
- normalized.comparisonCurrency
10618
- )
10619
- });
10620
- }
10621
- return summaries;
10622
- }
10623
- #rangeUsageSummary(providerId, billingDomainId, start, end, comparisonCurrency) {
10624
- const startIso = start.toISOString();
10625
- const endIso = end.toISOString();
10626
- const usage = this.#database.prepare(
10627
- `SELECT id, model, observed_at, authority, total_tokens, input_tokens, output_tokens,
10628
- reasoning_tokens, cache_read_tokens, cache_write_tokens, cache_write_5m_tokens,
10629
- cache_write_1h_tokens, source_reported_total_tokens,
10630
- unclassified_tokens, total_derivation, model_attribution, time_precision,
10631
- usage_scope, aggregation_temporality, reasoning_semantics,
10632
- cache_read_semantics, cache_write_semantics
10633
- FROM usage_observations
10634
- WHERE provider_id = ? AND billing_domain_id = ?
10635
- AND observed_at >= ? AND observed_at < ?
10636
- AND ${additiveUsagePredicate()}
10637
- ORDER BY observed_at, id`
10638
- ).all(providerId, billingDomainId, startIso, endIso);
10639
- const costs = this.#database.prepare(
10640
- `SELECT id, source_id, billing_domain_id, observed_at, kind, amount, currency, authority,
10641
- price_snapshot_id, price_snapshot_version, price_snapshot_source,
10642
- price_snapshot_canonical_model, price_snapshot_effective_at,
10643
- price_snapshot_effective_until, price_snapshot_currency,
10644
- price_snapshot_rates_json, price_snapshot_source_url,
10645
- price_snapshot_context_tier, model, usage_observation_id, priced_tokens,
10646
- line_items_json, calculated_at
10647
- FROM cost_records
10648
- WHERE provider_id = ? AND billing_domain_id = ?
10649
- AND observed_at >= ? AND observed_at < ?
10650
- ORDER BY observed_at, id`
10651
- ).all(providerId, billingDomainId, startIso, endIso);
10652
- const rateRows = this.#database.prepare(
10653
- `SELECT id, base_currency, quote_currency, rate, observed_at, source
10654
- FROM exchange_rate_snapshots WHERE observed_at < ? ORDER BY observed_at DESC, id`
10655
- ).all(endIso);
10656
- const rateByCurrency = /* @__PURE__ */ new Map();
10657
- for (const row of rateRows) {
10658
- if (row.quote_currency === comparisonCurrency && !rateByCurrency.has(row.base_currency)) {
10659
- rateByCurrency.set(row.base_currency, row);
10660
- }
10661
- }
10662
- const evidence = emptyTokenEvidence();
10663
- for (const row of usage) addTokenEvidence(evidence, row);
10664
- const finished = finishTokenEvidence(evidence);
10665
- const usedRates = /* @__PURE__ */ new Map();
10666
- const historyCosts = summarizeHistoryCosts(
10667
- costs,
10668
- finished.recordedTokens,
10669
- rateByCurrency,
10670
- comparisonCurrency,
10671
- end,
10672
- usedRates
10673
- );
10674
- return {
10675
- recordedTokens: finished.recordedTokens,
10676
- observationCount: finished.observationCount,
10677
- retailEquivalent: buildWorkbenchMetric(
10678
- historyCosts,
10679
- "retail-equivalent",
10680
- comparisonCurrency,
10681
- finished.recordedTokens,
10682
- [...usedRates.values()]
10683
- )
10684
- };
10685
- }
10686
10167
  #getBillingHistory(providerId, billingDomainId, now, query) {
10687
10168
  const normalized = normalizeUsageQuery(now, query);
10688
10169
  const start = normalized.start.toISOString();
@@ -11091,19 +10572,6 @@ var init_sqlite_usage_repository = __esm({
11091
10572
  key TEXT PRIMARY KEY,
11092
10573
  value TEXT NOT NULL
11093
10574
  );
11094
- CREATE TABLE IF NOT EXISTS plan_subscriptions (
11095
- provider_id TEXT NOT NULL,
11096
- billing_domain_id TEXT NOT NULL,
11097
- plan_id TEXT,
11098
- display_name TEXT NOT NULL,
11099
- amount REAL NOT NULL,
11100
- currency TEXT NOT NULL,
11101
- billing_period TEXT NOT NULL,
11102
- anchor_date TEXT,
11103
- price_source TEXT NOT NULL,
11104
- updated_at TEXT NOT NULL,
11105
- PRIMARY KEY (provider_id, billing_domain_id)
11106
- );
11107
10575
  CREATE TABLE IF NOT EXISTS custom_model_rates (
11108
10576
  id TEXT PRIMARY KEY,
11109
10577
  provider_id TEXT NOT NULL,
@@ -11284,10 +10752,6 @@ var init_sqlite_usage_repository = __esm({
11284
10752
  this.#database.exec(`ALTER TABLE quota_buckets ADD COLUMN ${name} ${type}`);
11285
10753
  }
11286
10754
  }
11287
- const planColumns = this.#database.prepare("PRAGMA table_info(plan_subscriptions)").all();
11288
- if (planColumns.length > 0 && !planColumns.some((column) => column.name === "anchor_date")) {
11289
- this.#database.exec("ALTER TABLE plan_subscriptions ADD COLUMN anchor_date TEXT");
11290
- }
11291
10755
  }
11292
10756
  };
11293
10757
  }