agent-usage-all-in-one 0.2.2 → 0.4.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 (34) hide show
  1. package/BUNDLED_DEPENDENCIES.json +4 -1
  2. package/BUNDLED_LICENSES.md +283 -0
  3. package/README.md +24 -12
  4. package/README.zh-CN.md +17 -10
  5. package/THIRD_PARTY_LICENSES.md +3 -1
  6. package/dist/cli.js +1125 -119
  7. package/dist/cli.js.map +1 -1
  8. package/dist/web/_app/immutable/assets/2.BWrFQDDF.css +1 -0
  9. package/dist/web/_app/immutable/chunks/3vuWay1s.js +3 -0
  10. package/dist/web/_app/immutable/chunks/CIxAYfti.js +1 -0
  11. package/dist/web/_app/immutable/chunks/DrMah8OK.js +1 -0
  12. package/dist/web/_app/immutable/entry/app.BJJ5ybn9.js +2 -0
  13. package/dist/web/_app/immutable/entry/start.C8pSj-JI.js +1 -0
  14. package/dist/web/_app/immutable/nodes/0.f03zL-fK.js +1 -0
  15. package/dist/web/_app/immutable/nodes/1.zxn5xzLP.js +1 -0
  16. package/dist/web/_app/immutable/nodes/2.CeZkCUZN.js +27 -0
  17. package/dist/web/_app/version.json +1 -1
  18. package/dist/web/brand/agent-usage-showcase.jpg +0 -0
  19. package/dist/web/brands/README.md +4 -4
  20. package/dist/web/index.html +30 -8
  21. package/docs/open-source.md +1 -1
  22. package/package.json +2 -1
  23. package/static/brand/agent-usage-showcase.jpg +0 -0
  24. package/static/brands/README.md +4 -4
  25. package/dist/web/_app/immutable/assets/2.Bb7EkOVL.css +0 -1
  26. package/dist/web/_app/immutable/chunks/Cui19qu3.js +0 -1
  27. package/dist/web/_app/immutable/chunks/DQaovcqE.js +0 -3
  28. package/dist/web/_app/immutable/entry/app.CpOB18I2.js +0 -2
  29. package/dist/web/_app/immutable/entry/start.Csw0voA2.js +0 -1
  30. package/dist/web/_app/immutable/nodes/0.Di1qFV6d.js +0 -1
  31. package/dist/web/_app/immutable/nodes/1.CVs4QxxY.js +0 -1
  32. package/dist/web/_app/immutable/nodes/2.ByyWXaMo.js +0 -31
  33. package/dist/web/brand/agent-usage-banner.svg +0 -27
  34. package/static/brand/agent-usage-banner.svg +0 -27
package/dist/cli.js CHANGED
@@ -643,6 +643,41 @@ function xaiEntry(options) {
643
643
  source: XAI_PRICING_SOURCE
644
644
  };
645
645
  }
646
+ function openCodeLocalHistoryEntries(entries) {
647
+ return entries.flatMap((entry) => {
648
+ const modelPrefix = openCodeLocalModelPrefix(entry);
649
+ if (!modelPrefix) return [];
650
+ const localModel = (model) => model.includes("/") ? model : `${modelPrefix}/${model}`;
651
+ const canonicalModel = localModel(entry.canonicalModel);
652
+ return [
653
+ {
654
+ ...entry,
655
+ id: `opencode-local-${entry.id}`,
656
+ providerId: "opencode",
657
+ billingDomainId: "local-history",
658
+ canonicalModel,
659
+ aliases: [
660
+ ...new Set(
661
+ [entry.canonicalModel, ...entry.aliases].map(localModel).filter((model) => model !== canonicalModel)
662
+ )
663
+ ]
664
+ }
665
+ ];
666
+ });
667
+ }
668
+ function openCodeLocalModelPrefix(entry) {
669
+ if (entry.providerId === "claude-code" && entry.billingDomainId === "subscription") {
670
+ return "anthropic";
671
+ }
672
+ if (entry.providerId === "codex" && entry.billingDomainId === "subscription") {
673
+ return "openai";
674
+ }
675
+ if (entry.providerId === "grok" && entry.billingDomainId === "xai-api") return "xai";
676
+ if (entry.providerId === "opencode-go" && entry.billingDomainId === "go-subscription") {
677
+ return "opencode-go";
678
+ }
679
+ return null;
680
+ }
646
681
  function deriveRetailEquivalentCosts(snapshot2, catalog = ANTHROPIC_PRICING_CATALOG, calculatedAt = snapshot2.observedAt) {
647
682
  const costs = [];
648
683
  const decisions = [];
@@ -714,16 +749,15 @@ function priceObservation(providerId, observation, catalog, calculatedAt) {
714
749
  ratePerMillion: entry.cacheWriteRatesPerMillion.oneHour
715
750
  }
716
751
  ].filter((item) => item.tokens > 0) : null;
717
- if (cacheWriteTokens > 0 && entry.ratesPerMillion["cache-write"] === null && !exactCacheWriteItems) {
718
- return unavailable("pricing-tier-ambiguous");
719
- }
720
- if (cacheWriteTokens > 0 && !exactCacheWriteItems) {
752
+ const cacheWriteFree = cacheWriteTokens > 0 && !exactCacheWriteItems && entry.ratesPerMillion["cache-write"] === null && !entry.cacheWriteRatesPerMillion;
753
+ const cacheWriteBillable = cacheWriteTokens > 0 && !exactCacheWriteItems && !cacheWriteFree;
754
+ if (cacheWriteBillable) {
721
755
  billableTokens.push({ tokenKind: "cache-write", tokens: cacheWriteTokens });
722
756
  }
723
757
  const nonZero = billableTokens.filter((item) => item.tokens > 0);
724
758
  if (nonZero.some((item) => entry.ratesPerMillion[item.tokenKind] === null)) {
725
759
  return unavailable(
726
- normalized.cacheWriteTokens > 0 ? "pricing-tier-ambiguous" : "token-kinds-incomplete"
760
+ normalized.cacheWriteTokens > 0 && !cacheWriteFree ? "pricing-tier-ambiguous" : "token-kinds-incomplete"
727
761
  );
728
762
  }
729
763
  const lineItems = nonZero.map((item) => {
@@ -742,6 +776,14 @@ function priceObservation(providerId, observation, catalog, calculatedAt) {
742
776
  }))
743
777
  );
744
778
  }
779
+ if (cacheWriteFree) {
780
+ lineItems.push({
781
+ tokenKind: "cache-write",
782
+ tokens: cacheWriteTokens,
783
+ ratePerMillion: 0,
784
+ amount: 0
785
+ });
786
+ }
745
787
  const pricedTokens = lineItems.reduce((total, item) => total + item.tokens, 0);
746
788
  if (pricedTokens !== normalized.recordedTokens) return unavailable("token-kinds-incomplete");
747
789
  const amount = preciseMoney(lineItems.reduce((total, item) => total + item.amount, 0));
@@ -806,7 +848,7 @@ function matchContext(rule, observation) {
806
848
  function preciseMoney(value) {
807
849
  return Number(value.toFixed(12));
808
850
  }
809
- 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, OFFICIAL_PRICING_CATALOG;
851
+ 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, DIRECT_OFFICIAL_PRICING_CATALOG, OFFICIAL_PRICING_CATALOG;
810
852
  var init_retail_pricing = __esm({
811
853
  "src/core/retail-pricing.ts"() {
812
854
  "use strict";
@@ -1004,7 +1046,7 @@ var init_retail_pricing = __esm({
1004
1046
  { startHour: 1, endHour: 4 },
1005
1047
  { startHour: 6, endHour: 10 }
1006
1048
  ];
1007
- OFFICIAL_PRICING_CATALOG = {
1049
+ DIRECT_OFFICIAL_PRICING_CATALOG = {
1008
1050
  version: "2026-08-28-grok-4.6-build",
1009
1051
  entries: [
1010
1052
  ...ANTHROPIC_PRICING_CATALOG.entries,
@@ -1139,6 +1181,389 @@ var init_retail_pricing = __esm({
1139
1181
  })
1140
1182
  ]
1141
1183
  };
1184
+ OFFICIAL_PRICING_CATALOG = {
1185
+ version: "2026-08-29-opencode-local-history",
1186
+ entries: [
1187
+ ...DIRECT_OFFICIAL_PRICING_CATALOG.entries,
1188
+ ...openCodeLocalHistoryEntries(DIRECT_OFFICIAL_PRICING_CATALOG.entries)
1189
+ ]
1190
+ };
1191
+ }
1192
+ });
1193
+
1194
+ // src/core/plan-pricing.ts
1195
+ function buildBillingPeriod(subscription, summary, comparisonCurrency, rates) {
1196
+ if (!summary) return null;
1197
+ const start = new Date(summary.start).getTime();
1198
+ const end = new Date(summary.end).getTime();
1199
+ const observedThrough = new Date(summary.observedThrough).getTime();
1200
+ const totalDays = (end - start) / MILLISECONDS_PER_DAY;
1201
+ const elapsedDays = Math.max(0, Math.min(observedThrough, end) - start) / MILLISECONDS_PER_DAY;
1202
+ const periodCost = planMoneyAmount(
1203
+ preciseAmount(subscription.amount),
1204
+ subscription.currency,
1205
+ comparisonCurrency,
1206
+ // The period's own rate evidence first, so a short rolling window cannot
1207
+ // leave a cycle amount unconverted.
1208
+ [...summary.retailEquivalent.exchangeRates, ...rates],
1209
+ summary.observedThrough
1210
+ );
1211
+ const retailAmount = summary.retailEquivalent.status === "available" ? summary.retailEquivalent.amount : null;
1212
+ const breakEvenRatio = periodCost.amount !== null && periodCost.amount > 0 && retailAmount !== null ? preciseAmount(retailAmount / periodCost.amount) : null;
1213
+ return {
1214
+ start: summary.start,
1215
+ end: summary.end,
1216
+ elapsedDays: preciseAmount(elapsedDays),
1217
+ totalDays: preciseAmount(totalDays),
1218
+ progress: totalDays > 0 ? preciseAmount(Math.min(1, elapsedDays / totalDays)) : 0,
1219
+ periodCost,
1220
+ recordedTokens: summary.observationCount > 0 ? summary.recordedTokens : null,
1221
+ retailEquivalent: summary.retailEquivalent,
1222
+ breakEvenRatio,
1223
+ ratioBound: ratioBoundFor(breakEvenRatio, summary.retailEquivalent.pricingCoverage)
1224
+ };
1225
+ }
1226
+ function planCatalogEntry(catalog, id) {
1227
+ return catalog.entries.find((entry) => entry.id === id) ?? null;
1228
+ }
1229
+ function planCatalogEntriesForDomain(catalog, providerId, billingDomainId) {
1230
+ return catalog.entries.filter(
1231
+ (entry) => entry.providerId === providerId && entry.billingDomainId === billingDomainId
1232
+ );
1233
+ }
1234
+ function addMonths(date, months) {
1235
+ const day = date.getUTCDate();
1236
+ const shifted = new Date(
1237
+ Date.UTC(
1238
+ date.getUTCFullYear(),
1239
+ date.getUTCMonth() + months,
1240
+ 1,
1241
+ date.getUTCHours(),
1242
+ date.getUTCMinutes(),
1243
+ date.getUTCSeconds(),
1244
+ date.getUTCMilliseconds()
1245
+ )
1246
+ );
1247
+ const lastDayOfMonth = new Date(
1248
+ Date.UTC(shifted.getUTCFullYear(), shifted.getUTCMonth() + 1, 0)
1249
+ ).getUTCDate();
1250
+ shifted.setUTCDate(Math.min(day, lastDayOfMonth));
1251
+ return shifted;
1252
+ }
1253
+ function billingPeriodContaining(anchorDate, billingPeriod, at) {
1254
+ const anchor = new Date(anchorDate.length === 10 ? `${anchorDate}T00:00:00.000Z` : anchorDate);
1255
+ if (Number.isNaN(anchor.getTime())) return null;
1256
+ const step = billingPeriod === "monthly" ? 1 : 12;
1257
+ const monthsApart = (at.getUTCFullYear() - anchor.getUTCFullYear()) * 12 + (at.getUTCMonth() - anchor.getUTCMonth());
1258
+ let index = Math.floor(monthsApart / step);
1259
+ let start = addMonths(anchor, index * step);
1260
+ while (start.getTime() > at.getTime()) {
1261
+ index -= 1;
1262
+ start = addMonths(anchor, index * step);
1263
+ }
1264
+ let end = addMonths(anchor, (index + 1) * step);
1265
+ while (end.getTime() <= at.getTime()) {
1266
+ index += 1;
1267
+ start = end;
1268
+ end = addMonths(anchor, (index + 1) * step);
1269
+ }
1270
+ return { start, end };
1271
+ }
1272
+ function windowDays(start, end) {
1273
+ const span = new Date(end).getTime() - new Date(start).getTime();
1274
+ return span > 0 ? span / MILLISECONDS_PER_DAY : 0;
1275
+ }
1276
+ function proratePlanPrice(amount, billingPeriod, days) {
1277
+ return amount * days / PLAN_PERIOD_DAYS[billingPeriod];
1278
+ }
1279
+ function convertPlanAmount(amount, currency, comparisonCurrency, rates, end) {
1280
+ if (currency.toUpperCase() === comparisonCurrency.toUpperCase()) {
1281
+ return { amount, reason: null, rate: null };
1282
+ }
1283
+ const rate = rates.find(
1284
+ (candidate) => candidate.baseCurrency.toUpperCase() === currency.toUpperCase() && candidate.quoteCurrency.toUpperCase() === comparisonCurrency.toUpperCase()
1285
+ );
1286
+ if (!rate) return { amount: null, reason: "missing-rate", rate: null };
1287
+ if (new Date(end).getTime() - new Date(rate.observedAt).getTime() > STALE_RATE_MILLISECONDS) {
1288
+ return { amount: null, reason: "stale-rate", rate };
1289
+ }
1290
+ return { amount: amount * rate.rate, reason: null, rate };
1291
+ }
1292
+ function preciseAmount(value) {
1293
+ return Number(value.toPrecision(12));
1294
+ }
1295
+ function planMoneyAmount(nativeAmount, nativeCurrency, comparisonCurrency, rates, end) {
1296
+ const converted = convertPlanAmount(nativeAmount, nativeCurrency, comparisonCurrency, rates, end);
1297
+ return {
1298
+ status: converted.amount === null ? "unavailable" : "available",
1299
+ amount: converted.amount === null ? null : preciseAmount(converted.amount),
1300
+ nativeAmount,
1301
+ nativeCurrency,
1302
+ comparisonCurrency,
1303
+ conversionUnavailableReason: converted.reason,
1304
+ exchangeRates: converted.rate ? [converted.rate] : []
1305
+ };
1306
+ }
1307
+ function ratioBoundFor(ratio, pricingCoverage) {
1308
+ if (ratio === null) return "unavailable";
1309
+ return pricingCoverage !== null && pricingCoverage < 0.999 ? "lower" : "exact";
1310
+ }
1311
+ function unitPricePerMillion(amount, tokens) {
1312
+ if (amount === null || tokens <= 0) return null;
1313
+ return preciseAmount(amount / (tokens / 1e6));
1314
+ }
1315
+ function buildWorkbenchPlanValue(options) {
1316
+ const { comparisonCurrency, start, end, rates } = options;
1317
+ const days = windowDays(start, end);
1318
+ const subscriptionByDomain = new Map(
1319
+ options.subscriptions.map((subscription) => [
1320
+ `${subscription.providerId}:${subscription.billingDomainId}`,
1321
+ subscription
1322
+ ])
1323
+ );
1324
+ const entries = [];
1325
+ const metered = [];
1326
+ const unconfigured = [];
1327
+ for (const domain of options.domains) {
1328
+ const subscription = subscriptionByDomain.get(`${domain.providerId}:${domain.billingDomainId}`);
1329
+ if (!subscription) {
1330
+ if (domain.actualCost.records > 0) {
1331
+ metered.push({
1332
+ providerId: domain.providerId,
1333
+ providerDisplayName: domain.providerDisplayName,
1334
+ billingDomainId: domain.billingDomainId,
1335
+ billingDomainDisplayName: domain.billingDomainDisplayName,
1336
+ recordedTokens: domain.observationCount > 0 ? domain.recordedTokens : null,
1337
+ actualCost: domain.actualCost,
1338
+ retailEquivalent: domain.retailEquivalent
1339
+ });
1340
+ continue;
1341
+ }
1342
+ if (domain.observationCount > 0) {
1343
+ unconfigured.push({
1344
+ providerId: domain.providerId,
1345
+ providerDisplayName: domain.providerDisplayName,
1346
+ billingDomainId: domain.billingDomainId,
1347
+ billingDomainDisplayName: domain.billingDomainDisplayName,
1348
+ recordedTokens: domain.recordedTokens
1349
+ });
1350
+ }
1351
+ continue;
1352
+ }
1353
+ const windowPlanCost = planMoneyAmount(
1354
+ preciseAmount(proratePlanPrice(subscription.amount, subscription.billingPeriod, days)),
1355
+ subscription.currency,
1356
+ comparisonCurrency,
1357
+ rates,
1358
+ end
1359
+ );
1360
+ const retail = domain.retailEquivalent;
1361
+ const retailAmount = retail.status === "available" ? retail.amount : null;
1362
+ const valueRatio = windowPlanCost.amount !== null && windowPlanCost.amount > 0 && retailAmount !== null ? preciseAmount(retailAmount / windowPlanCost.amount) : null;
1363
+ const ratioBound = ratioBoundFor(valueRatio, retail.pricingCoverage);
1364
+ const billingPeriod = buildBillingPeriod(
1365
+ subscription,
1366
+ options.billingPeriods?.get(`${domain.providerId}:${domain.billingDomainId}`),
1367
+ comparisonCurrency,
1368
+ rates
1369
+ );
1370
+ entries.push({
1371
+ providerId: domain.providerId,
1372
+ providerDisplayName: domain.providerDisplayName,
1373
+ billingDomainId: domain.billingDomainId,
1374
+ billingDomainDisplayName: domain.billingDomainDisplayName,
1375
+ includedInHeadline: domain.includedInHeadline,
1376
+ plan: {
1377
+ planId: subscription.planId,
1378
+ displayName: subscription.displayName,
1379
+ amount: subscription.amount,
1380
+ currency: subscription.currency,
1381
+ billingPeriod: subscription.billingPeriod,
1382
+ anchorDate: subscription.anchorDate,
1383
+ priceSource: subscription.priceSource,
1384
+ updatedAt: subscription.updatedAt
1385
+ },
1386
+ windowDays: preciseAmount(days),
1387
+ windowPlanCost,
1388
+ billingPeriod,
1389
+ recordedTokens: domain.observationCount > 0 ? domain.recordedTokens : null,
1390
+ retailEquivalent: retail,
1391
+ valueRatio,
1392
+ ratioBound,
1393
+ status: valueRatio === null ? "unavailable" : ratioBound === "lower" ? "partial" : "available",
1394
+ effectiveUnitPrice: unitPricePerMillion(windowPlanCost.amount, domain.recordedTokens),
1395
+ retailUnitPrice: unitPricePerMillion(retailAmount, retail.pricedTokens),
1396
+ pricingCoverage: retail.pricingCoverage,
1397
+ authorities: domain.authorities,
1398
+ lastObservedAt: domain.lastObservedAt
1399
+ });
1400
+ }
1401
+ const rank = (entry) => entry.valueRatio ?? -1;
1402
+ entries.sort(
1403
+ (left, right) => rank(right) - rank(left) || `${left.providerId}:${left.billingDomainId}`.localeCompare(
1404
+ `${right.providerId}:${right.billingDomainId}`
1405
+ )
1406
+ );
1407
+ metered.sort(
1408
+ (left, right) => `${left.providerId}:${left.billingDomainId}`.localeCompare(
1409
+ `${right.providerId}:${right.billingDomainId}`
1410
+ )
1411
+ );
1412
+ unconfigured.sort(
1413
+ (left, right) => right.recordedTokens - left.recordedTokens || `${left.providerId}:${left.billingDomainId}`.localeCompare(
1414
+ `${right.providerId}:${right.billingDomainId}`
1415
+ )
1416
+ );
1417
+ return {
1418
+ windowDays: preciseAmount(days),
1419
+ comparisonCurrency,
1420
+ catalogVersion: SUBSCRIPTION_PLAN_CATALOG.version,
1421
+ entries,
1422
+ meteredDomains: metered,
1423
+ unconfiguredDomains: unconfigured
1424
+ };
1425
+ }
1426
+ var PLAN_PERIOD_DAYS, MILLISECONDS_PER_DAY, STALE_RATE_MILLISECONDS, SUBSCRIPTION_PLAN_CATALOG;
1427
+ var init_plan_pricing = __esm({
1428
+ "src/core/plan-pricing.ts"() {
1429
+ "use strict";
1430
+ PLAN_PERIOD_DAYS = {
1431
+ monthly: 365.25 / 12,
1432
+ annual: 365.25
1433
+ };
1434
+ MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1e3;
1435
+ STALE_RATE_MILLISECONDS = 7 * MILLISECONDS_PER_DAY;
1436
+ SUBSCRIPTION_PLAN_CATALOG = {
1437
+ version: "2026-08-30",
1438
+ entries: [
1439
+ {
1440
+ id: "claude-pro-monthly",
1441
+ providerId: "claude-code",
1442
+ billingDomainId: "subscription",
1443
+ displayName: "Claude Pro",
1444
+ amount: 20,
1445
+ currency: "USD",
1446
+ billingPeriod: "monthly",
1447
+ source: {
1448
+ title: "Claude plans and pricing",
1449
+ url: "https://claude.com/pricing",
1450
+ retrievedAt: "2026-08-30"
1451
+ }
1452
+ },
1453
+ {
1454
+ id: "claude-pro-annual",
1455
+ providerId: "claude-code",
1456
+ billingDomainId: "subscription",
1457
+ displayName: "Claude Pro (annual billing)",
1458
+ amount: 17 * 12,
1459
+ currency: "USD",
1460
+ billingPeriod: "annual",
1461
+ source: {
1462
+ title: "Claude plans and pricing",
1463
+ url: "https://claude.com/pricing",
1464
+ retrievedAt: "2026-08-30"
1465
+ }
1466
+ },
1467
+ {
1468
+ id: "claude-max-5x",
1469
+ providerId: "claude-code",
1470
+ billingDomainId: "subscription",
1471
+ displayName: "Claude Max 5x",
1472
+ amount: 100,
1473
+ currency: "USD",
1474
+ billingPeriod: "monthly",
1475
+ source: {
1476
+ title: "What is the Max plan?",
1477
+ url: "https://support.claude.com/en/articles/11049741-what-is-the-max-plan",
1478
+ retrievedAt: "2026-08-30"
1479
+ }
1480
+ },
1481
+ {
1482
+ id: "claude-max-20x",
1483
+ providerId: "claude-code",
1484
+ billingDomainId: "subscription",
1485
+ displayName: "Claude Max 20x",
1486
+ amount: 200,
1487
+ currency: "USD",
1488
+ billingPeriod: "monthly",
1489
+ source: {
1490
+ title: "What is the Max plan?",
1491
+ url: "https://support.claude.com/en/articles/11049741-what-is-the-max-plan",
1492
+ retrievedAt: "2026-08-30"
1493
+ }
1494
+ },
1495
+ {
1496
+ id: "chatgpt-plus",
1497
+ providerId: "codex",
1498
+ billingDomainId: "subscription",
1499
+ displayName: "ChatGPT Plus",
1500
+ amount: 20,
1501
+ currency: "USD",
1502
+ billingPeriod: "monthly",
1503
+ source: {
1504
+ title: "ChatGPT pricing",
1505
+ url: "https://chatgpt.com/pricing/",
1506
+ retrievedAt: "2026-08-30"
1507
+ }
1508
+ },
1509
+ {
1510
+ id: "chatgpt-pro-100",
1511
+ providerId: "codex",
1512
+ billingDomainId: "subscription",
1513
+ displayName: "ChatGPT Pro (5x)",
1514
+ amount: 100,
1515
+ currency: "USD",
1516
+ billingPeriod: "monthly",
1517
+ source: {
1518
+ title: "About ChatGPT Pro tiers",
1519
+ url: "https://help.openai.com/en/articles/9793128-about-chatgpt-pro-tiers",
1520
+ retrievedAt: "2026-08-30"
1521
+ }
1522
+ },
1523
+ {
1524
+ id: "chatgpt-pro-200",
1525
+ providerId: "codex",
1526
+ billingDomainId: "subscription",
1527
+ displayName: "ChatGPT Pro (20x)",
1528
+ amount: 200,
1529
+ currency: "USD",
1530
+ billingPeriod: "monthly",
1531
+ source: {
1532
+ title: "About ChatGPT Pro tiers",
1533
+ url: "https://help.openai.com/en/articles/9793128-about-chatgpt-pro-tiers",
1534
+ retrievedAt: "2026-08-30"
1535
+ }
1536
+ },
1537
+ {
1538
+ id: "chatgpt-business-seat",
1539
+ providerId: "codex",
1540
+ billingDomainId: "subscription",
1541
+ displayName: "ChatGPT Business (one seat)",
1542
+ amount: 25,
1543
+ currency: "USD",
1544
+ billingPeriod: "monthly",
1545
+ source: {
1546
+ title: "ChatGPT Business pricing",
1547
+ url: "https://openai.com/business/chatgpt-pricing/",
1548
+ retrievedAt: "2026-08-30"
1549
+ }
1550
+ },
1551
+ {
1552
+ id: "opencode-go-monthly",
1553
+ providerId: "opencode-go",
1554
+ billingDomainId: "go-subscription",
1555
+ displayName: "OpenCode Go",
1556
+ amount: 10,
1557
+ currency: "USD",
1558
+ billingPeriod: "monthly",
1559
+ source: {
1560
+ title: "OpenCode Go",
1561
+ url: "https://opencode.ai/go",
1562
+ retrievedAt: "2026-08-30"
1563
+ }
1564
+ }
1565
+ ]
1566
+ };
1142
1567
  }
1143
1568
  });
1144
1569
 
@@ -1247,6 +1672,12 @@ async function withTimeout(promise, timeoutMs, message) {
1247
1672
  function notificationLevel(value) {
1248
1673
  return value === "5" ? 2 : value === "20" ? 1 : 0;
1249
1674
  }
1675
+ function pickAgentProviderIndex(overview) {
1676
+ return {
1677
+ generatedAt: overview.generatedAt,
1678
+ providers: overview.providers.filter((provider) => provider.id !== "opencode").map(({ id, displayName }) => ({ id, displayName }))
1679
+ };
1680
+ }
1250
1681
  var UsageApplication;
1251
1682
  var init_usage_application = __esm({
1252
1683
  "src/core/usage-application.ts"() {
@@ -1255,6 +1686,7 @@ var init_usage_application = __esm({
1255
1686
  init_redaction();
1256
1687
  init_usage_export();
1257
1688
  init_retail_pricing();
1689
+ init_plan_pricing();
1258
1690
  UsageApplication = class {
1259
1691
  #repository;
1260
1692
  #connectors;
@@ -1268,10 +1700,13 @@ var init_usage_application = __esm({
1268
1700
  #notifier;
1269
1701
  #startAtLoginManager;
1270
1702
  #priceCatalog;
1703
+ #planCatalog;
1271
1704
  #refreshPromise = null;
1272
1705
  #refreshMode = null;
1273
1706
  #backgroundPromise = null;
1274
1707
  #queuedHardRebuildPromise = null;
1708
+ #queuedUserProcessingPromise = null;
1709
+ #userInitiatedProcessing = false;
1275
1710
  #databaseWriteQueue = Promise.resolve();
1276
1711
  #processingStatus;
1277
1712
  constructor(options) {
@@ -1287,6 +1722,7 @@ var init_usage_application = __esm({
1287
1722
  this.#notifier = options.notifier;
1288
1723
  this.#startAtLoginManager = options.startAtLoginManager;
1289
1724
  this.#priceCatalog = options.priceCatalog === void 0 ? OFFICIAL_PRICING_CATALOG : options.priceCatalog;
1725
+ this.#planCatalog = options.planCatalog ?? SUBSCRIPTION_PLAN_CATALOG;
1290
1726
  this.#processingStatus = createProcessingStatus(this.#clock().toISOString(), false);
1291
1727
  }
1292
1728
  async #backfillRetailCosts(mode) {
@@ -1333,40 +1769,50 @@ var init_usage_application = __esm({
1333
1769
  getProcessingStatus() {
1334
1770
  return structuredClone(this.#processingStatus);
1335
1771
  }
1336
- startBackgroundProcessing() {
1337
- return this.#startProcessing("incremental");
1772
+ startBackgroundProcessing(options = {}) {
1773
+ return this.#startProcessing("incremental", options.userInitiated === true);
1338
1774
  }
1339
1775
  startHardRebuild() {
1340
- return this.#startProcessing("hard-rebuild");
1776
+ return this.#startProcessing("hard-rebuild", true);
1341
1777
  }
1342
- #startProcessing(mode) {
1778
+ #startProcessing(mode, userInitiated) {
1343
1779
  if (this.#backgroundPromise) {
1344
1780
  if (mode === "hard-rebuild" && !this.#processingStatus.hardRebuild) {
1345
1781
  this.#queuedHardRebuildPromise ??= this.#backgroundPromise.then(
1346
- () => this.#startProcessing("hard-rebuild"),
1347
- () => this.#startProcessing("hard-rebuild")
1782
+ () => this.#startProcessing("hard-rebuild", true),
1783
+ () => this.#startProcessing("hard-rebuild", true)
1348
1784
  ).finally(() => {
1349
1785
  this.#queuedHardRebuildPromise = null;
1350
1786
  });
1351
1787
  return this.#queuedHardRebuildPromise;
1352
1788
  }
1789
+ if (userInitiated && !this.#userInitiatedProcessing) {
1790
+ this.#queuedUserProcessingPromise ??= this.#backgroundPromise.then(
1791
+ () => this.#startProcessing(mode, true),
1792
+ () => this.#startProcessing(mode, true)
1793
+ ).finally(() => {
1794
+ this.#queuedUserProcessingPromise = null;
1795
+ });
1796
+ return this.#queuedUserProcessingPromise;
1797
+ }
1353
1798
  return this.#backgroundPromise;
1354
1799
  }
1800
+ this.#userInitiatedProcessing = userInitiated || mode === "hard-rebuild";
1355
1801
  this.#processingStatus = createProcessingStatus(
1356
1802
  this.#clock().toISOString(),
1357
1803
  mode === "hard-rebuild"
1358
1804
  );
1359
- this.#backgroundPromise = this.#runProcessing(mode).finally(() => {
1360
- this.#backgroundPromise = null;
1361
- });
1805
+ this.#backgroundPromise = this.#runProcessing(mode, this.#userInitiatedProcessing).finally(
1806
+ () => {
1807
+ this.#backgroundPromise = null;
1808
+ this.#userInitiatedProcessing = false;
1809
+ }
1810
+ );
1362
1811
  return this.#backgroundPromise;
1363
1812
  }
1364
- async #runProcessing(mode) {
1813
+ async #runProcessing(mode, userInitiated) {
1365
1814
  await this.#runModule("discovery", () => this.discoverConnectors().then(() => void 0));
1366
- await this.#runModule(
1367
- "usage",
1368
- () => this.refresh({ userInitiated: mode === "hard-rebuild", mode })
1369
- );
1815
+ await this.#runModule("usage", () => this.refresh({ userInitiated, mode }));
1370
1816
  await this.#runModule(
1371
1817
  "pricing",
1372
1818
  () => this.#queueDatabaseWrite(async () => {
@@ -1577,6 +2023,83 @@ var init_usage_application = __esm({
1577
2023
  connectors: this.#repository.getConnectorRuntimeStates()
1578
2024
  };
1579
2025
  }
2026
+ async getPlanSettings() {
2027
+ return {
2028
+ catalogVersion: this.#planCatalog.version,
2029
+ domains: this.#planEligibleDomains(),
2030
+ subscriptions: this.#repository.getPlanSubscriptions()
2031
+ };
2032
+ }
2033
+ async updatePlanSubscription(input) {
2034
+ const domain = this.#planEligibleDomains().find(
2035
+ (candidate) => candidate.providerId === input.providerId && candidate.billingDomainId === input.billingDomainId
2036
+ );
2037
+ if (!domain) throw new Error("Unknown subscription billing domain");
2038
+ if (input.plan === null) {
2039
+ this.#repository.deletePlanSubscription(input.providerId, input.billingDomainId);
2040
+ return this.getPlanSettings();
2041
+ }
2042
+ const preset = input.plan.planId ? planCatalogEntry(this.#planCatalog, input.plan.planId) : null;
2043
+ if (input.plan.planId && !preset) throw new Error("Unknown plan preset");
2044
+ if (preset && (preset.providerId !== input.providerId || preset.billingDomainId !== input.billingDomainId)) {
2045
+ throw new Error("Plan preset belongs to another billing domain");
2046
+ }
2047
+ const amount = input.plan.amount ?? preset?.amount;
2048
+ if (amount === void 0) throw new Error("A plan price is required");
2049
+ if (!Number.isFinite(amount) || amount <= 0) {
2050
+ throw new Error("A plan price must be a positive amount");
2051
+ }
2052
+ const currency = (input.plan.currency ?? preset?.currency ?? "USD").toUpperCase();
2053
+ if (!/^[A-Z]{3}$/.test(currency)) throw new Error("A plan currency must be a 3-letter code");
2054
+ const billingPeriod = input.plan.billingPeriod ?? preset?.billingPeriod ?? "monthly";
2055
+ const anchorDate = input.plan.anchorDate ?? null;
2056
+ if (anchorDate !== null && Number.isNaN((/* @__PURE__ */ new Date(`${anchorDate}T00:00:00.000Z`)).getTime())) {
2057
+ throw new Error("A renewal date must be a calendar date");
2058
+ }
2059
+ const overridesPreset = preset !== null && (amount !== preset.amount || currency !== preset.currency.toUpperCase() || billingPeriod !== preset.billingPeriod);
2060
+ this.#repository.savePlanSubscription({
2061
+ providerId: input.providerId,
2062
+ billingDomainId: input.billingDomainId,
2063
+ planId: preset?.id ?? null,
2064
+ displayName: preset?.displayName ?? "",
2065
+ amount,
2066
+ currency,
2067
+ billingPeriod,
2068
+ anchorDate,
2069
+ priceSource: preset && !overridesPreset ? "catalog-preset" : "user-entered",
2070
+ updatedAt: this.#clock().toISOString()
2071
+ });
2072
+ return this.getPlanSettings();
2073
+ }
2074
+ /**
2075
+ * A billing domain can carry a plan price when its connector does not report
2076
+ * an actual metered charge. Metered domains keep their own billed amounts and
2077
+ * never receive a declared subscription price.
2078
+ */
2079
+ #planEligibleDomains() {
2080
+ const domains = /* @__PURE__ */ new Map();
2081
+ for (const definition of this.#connectorDefinitions) {
2082
+ if (definition.expectedCoverage?.includes("actual-cost")) continue;
2083
+ const key = `${definition.target.provider.id}:${definition.target.billingDomain.id}`;
2084
+ if (domains.has(key)) continue;
2085
+ domains.set(key, {
2086
+ providerId: definition.target.provider.id,
2087
+ providerDisplayName: definition.target.provider.displayName,
2088
+ billingDomainId: definition.target.billingDomain.id,
2089
+ billingDomainDisplayName: definition.target.billingDomain.displayName,
2090
+ presets: planCatalogEntriesForDomain(
2091
+ this.#planCatalog,
2092
+ definition.target.provider.id,
2093
+ definition.target.billingDomain.id
2094
+ )
2095
+ });
2096
+ }
2097
+ return [...domains.values()].sort(
2098
+ (left, right) => `${left.providerId}:${left.billingDomainId}`.localeCompare(
2099
+ `${right.providerId}:${right.billingDomainId}`
2100
+ )
2101
+ );
2102
+ }
1580
2103
  async #sendNotificationTransitions() {
1581
2104
  if (!this.#notifier) return;
1582
2105
  const overview = this.#repository.getOverview(this.#clock());
@@ -1725,6 +2248,14 @@ var init_usage_application = __esm({
1725
2248
  async getOverview(query = {}) {
1726
2249
  return this.#repository.getOverview(this.#clock(), query);
1727
2250
  }
2251
+ async getAgentProviderIndex() {
2252
+ const now = this.#clock();
2253
+ return this.#repository.getAgentProviderIndex?.(now) ?? pickAgentProviderIndex(this.#repository.getOverview(now));
2254
+ }
2255
+ async getProviderOverview(providerId, query = {}) {
2256
+ const now = this.#clock();
2257
+ return this.#repository.getProviderOverview?.(now, providerId, query) ?? this.#repository.getOverview(now, query).providers.find((provider) => provider.id === providerId) ?? null;
2258
+ }
1728
2259
  async exportUsage(request) {
1729
2260
  const overview = this.#repository.getOverview(this.#clock(), request);
1730
2261
  const accountIdentifiers = request.includeAccountIdentifiers ? this.#repository.getProviderAccountIdentifiers() : {};
@@ -1933,9 +2464,9 @@ var init_catalog = __esm({
1933
2464
  },
1934
2465
  {
1935
2466
  id: "opencode-go",
1936
- displayName: "OpenCode Go",
2467
+ displayName: "OpenCode",
1937
2468
  command: "opencode",
1938
- permissionDescription: "Read account quota and local exports through official OpenCode surfaces.",
2469
+ permissionDescription: "Read local usage and optional Go account quota through official OpenCode surfaces.",
1939
2470
  credentialOwner: "official-client",
1940
2471
  experimental: false,
1941
2472
  expectedCoverage: ["quota", "tokens", "history"],
@@ -1990,6 +2521,7 @@ function mapQuota(quota) {
1990
2521
  billingDomainId: "subscription",
1991
2522
  label: quota.label,
1992
2523
  usedPercent: quota.usedPercent,
2524
+ windowDurationMinutes: quota.windowDurationMinutes,
1993
2525
  resetsAt: quota.resetsAt,
1994
2526
  authority: "official-client",
1995
2527
  scope: "account-wide"
@@ -2294,6 +2826,7 @@ function parseClaudeUsageScreen(text, now) {
2294
2826
  id,
2295
2827
  label: displayLabel(heading),
2296
2828
  usedPercent: Number(match[1]),
2829
+ windowDurationMinutes: windowDurationMinutes(heading),
2297
2830
  resetsAt: resetLine ? parseReset(resetLine, now) : null
2298
2831
  });
2299
2832
  }
@@ -2326,6 +2859,11 @@ function displayLabel(heading) {
2326
2859
  const weekly = heading.match(/^Weekly\s*[·—-]\s*(.+)$/i);
2327
2860
  return weekly ? `Week \xB7 ${weekly[1]}` : heading;
2328
2861
  }
2862
+ function windowDurationMinutes(heading) {
2863
+ if (/^(5[- ]hour limit|current session)$/i.test(heading)) return 300;
2864
+ if (/^(Current week\s*\(.+\)|Weekly\s*[·—-]\s*.+)$/i.test(heading)) return 10080;
2865
+ return null;
2866
+ }
2329
2867
  function parseReset(line, now) {
2330
2868
  const relative = line.match(/Resets\s+in\s+(?:(\d+)d\s*)?(?:(\d+)h\s*)?(?:(\d+)m)?/i);
2331
2869
  if (relative) {
@@ -2652,6 +3190,7 @@ function mapQuotaBuckets(response) {
2652
3190
  billingDomainId: "subscription",
2653
3191
  label: multipleLimits ? `${baseLabel} \xB7 ${windowLabel}` : windowLabel,
2654
3192
  usedPercent: window.usedPercent,
3193
+ windowDurationMinutes: window.windowDurationMins,
2655
3194
  resetsAt: window.resetsAt === null ? null : new Date(window.resetsAt * 1e3).toISOString(),
2656
3195
  authority: "official-account"
2657
3196
  });
@@ -2989,6 +3528,119 @@ var init_stdio_codex_account_client = __esm({
2989
3528
  }
2990
3529
  });
2991
3530
 
3531
+ // src/connectors/opencode-local/opencode-local-connector.ts
3532
+ function mapLocalUsage(request) {
3533
+ return {
3534
+ id: `opencode-local-request:${request.id}`,
3535
+ billingDomainId: "local-history",
3536
+ model: request.model,
3537
+ observedAt: new Date(request.observedAtMs).toISOString(),
3538
+ inputTokens: request.inputTokens,
3539
+ outputTokens: request.outputTokens,
3540
+ reasoningTokens: request.reasoningTokens,
3541
+ cacheReadTokens: request.cacheReadTokens,
3542
+ cacheWriteTokens: request.cacheWriteTokens,
3543
+ tokenSemantics: {
3544
+ reasoning: "separate",
3545
+ cacheRead: "separate",
3546
+ cacheWrite: "separate"
3547
+ },
3548
+ modelAttribution: "known",
3549
+ timePrecision: "event",
3550
+ usageScope: "this-mac",
3551
+ aggregationTemporality: "delta",
3552
+ authority: "local-observation"
3553
+ };
3554
+ }
3555
+ function mapLocalCost(request, cost) {
3556
+ const usageObservationId = `opencode-local-request:${request.id}`;
3557
+ return {
3558
+ id: `opencode-local-request-cost:${request.id}`,
3559
+ sourceId: usageObservationId,
3560
+ billingDomainId: "local-history",
3561
+ observedAt: new Date(request.observedAtMs).toISOString(),
3562
+ kind: "reported-estimate",
3563
+ amount: cost,
3564
+ currency: "USD",
3565
+ authority: "local-observation",
3566
+ model: request.model,
3567
+ usageObservationId,
3568
+ priceSnapshot: {
3569
+ id: "opencode-local-message-reported-cost-v1",
3570
+ version: "2026-08-29",
3571
+ source: "OpenCode local message history reported cost",
3572
+ canonicalModel: request.model,
3573
+ effectiveAt: "2026-08-29T00:00:00.000Z",
3574
+ effectiveUntil: null,
3575
+ currency: "USD",
3576
+ ratesPerMillion: {
3577
+ input: null,
3578
+ output: null,
3579
+ reasoning: null,
3580
+ "cache-read": null,
3581
+ "cache-write": null
3582
+ }
3583
+ }
3584
+ };
3585
+ }
3586
+ function safeFailure3(error) {
3587
+ if (error instanceof Error && "code" in error && typeof error.code === "string" && "recovery" in error && typeof error.recovery === "string") {
3588
+ return { code: error.code, message: error.message, recovery: error.recovery };
3589
+ }
3590
+ return {
3591
+ code: "opencode-local-refresh-failed",
3592
+ message: "OpenCode local history coverage is incomplete.",
3593
+ recovery: "Run agent-usage doctor, then retry refresh."
3594
+ };
3595
+ }
3596
+ var OpenCodeLocalConnector;
3597
+ var init_opencode_local_connector = __esm({
3598
+ "src/connectors/opencode-local/opencode-local-connector.ts"() {
3599
+ "use strict";
3600
+ OpenCodeLocalConnector = class {
3601
+ id = "opencode";
3602
+ displayName = "OpenCode";
3603
+ consentId = "opencode-go";
3604
+ #localHistoryClient;
3605
+ #clock;
3606
+ constructor(options) {
3607
+ this.#localHistoryClient = options.localHistoryClient;
3608
+ this.#clock = options.clock ?? (() => /* @__PURE__ */ new Date());
3609
+ }
3610
+ async collect() {
3611
+ const observedAt = this.#clock().toISOString();
3612
+ try {
3613
+ const requests = await this.#localHistoryClient.readHistory();
3614
+ return {
3615
+ provider: { id: this.id, displayName: this.displayName },
3616
+ billingDomains: [{ id: "local-history", displayName: "Local history" }],
3617
+ quotaBuckets: [],
3618
+ usage: requests.map(mapLocalUsage),
3619
+ usageReconciliation: {
3620
+ authoritativeIdPrefix: "opencode-local-request:",
3621
+ retiredIdPrefixes: []
3622
+ },
3623
+ costs: requests.flatMap(
3624
+ (request) => request.cost === null ? [] : [mapLocalCost(request, request.cost)]
3625
+ ),
3626
+ observedAt
3627
+ };
3628
+ } catch (error) {
3629
+ return {
3630
+ provider: { id: this.id, displayName: this.displayName },
3631
+ billingDomains: [{ id: "local-history", displayName: "Local history" }],
3632
+ quotaBuckets: [],
3633
+ usage: [],
3634
+ costs: [],
3635
+ warnings: [safeFailure3(error)],
3636
+ observedAt
3637
+ };
3638
+ }
3639
+ }
3640
+ };
3641
+ }
3642
+ });
3643
+
2992
3644
  // src/connectors/opencode-go/local-opencode-history-client.ts
2993
3645
  import { execFile as execFileCallback } from "child_process";
2994
3646
  import { createHash } from "crypto";
@@ -3077,12 +3729,27 @@ var init_local_opencode_history_client = __esm({
3077
3729
  #command;
3078
3730
  #execFile;
3079
3731
  #readDatabase;
3732
+ #activeRead = null;
3080
3733
  constructor(options = {}) {
3081
3734
  this.#command = options.command ?? "opencode";
3082
3735
  this.#execFile = options.execFile ?? executeOpenCode;
3083
3736
  this.#readDatabase = options.readDatabase ?? readDatabase;
3084
3737
  }
3085
- async readHistory() {
3738
+ readHistory() {
3739
+ if (this.#activeRead) return this.#activeRead;
3740
+ const activeRead = this.#readHistory();
3741
+ this.#activeRead = activeRead;
3742
+ activeRead.then(
3743
+ () => {
3744
+ if (this.#activeRead === activeRead) this.#activeRead = null;
3745
+ },
3746
+ () => {
3747
+ if (this.#activeRead === activeRead) this.#activeRead = null;
3748
+ }
3749
+ );
3750
+ return activeRead;
3751
+ }
3752
+ async #readHistory() {
3086
3753
  let databasePath;
3087
3754
  try {
3088
3755
  const { stdout } = await this.#execFile(this.#command, ["db", "path"]);
@@ -3113,8 +3780,9 @@ var init_local_opencode_history_client = __esm({
3113
3780
  { cause: error }
3114
3781
  );
3115
3782
  }
3116
- return completedAssistantRows.filter((row) => row.providerId === "opencode-go").filter(hasCategorizedTokens).map((row) => ({
3783
+ return completedAssistantRows.filter(hasCategorizedTokens).map((row) => ({
3117
3784
  id: `v2:${createHash("sha256").update(row.sourceId).digest("hex")}`,
3785
+ providerId: row.providerId,
3118
3786
  model: `${row.providerId}/${row.modelId}`,
3119
3787
  cost: row.cost,
3120
3788
  inputTokens: row.inputTokens,
@@ -3317,6 +3985,7 @@ function mapQuota2(response) {
3317
3985
  billingDomainId: "go-subscription",
3318
3986
  label: LIMITS[id].label,
3319
3987
  usedPercent: response.usage[id].percent,
3988
+ windowDurationMinutes: LIMITS[id].windowDurationMinutes,
3320
3989
  resetsAt: response.usage[id].resetsAt,
3321
3990
  authority: "official-account",
3322
3991
  scope: "account-wide",
@@ -3326,61 +3995,7 @@ function mapQuota2(response) {
3326
3995
  fallbackStatus: "unknown"
3327
3996
  }));
3328
3997
  }
3329
- function mapLocalUsage(request) {
3330
- return {
3331
- id: `opencode-request:${request.id}`,
3332
- billingDomainId: "go-subscription",
3333
- model: request.model,
3334
- observedAt: new Date(request.observedAtMs).toISOString(),
3335
- inputTokens: request.inputTokens,
3336
- outputTokens: request.outputTokens,
3337
- reasoningTokens: request.reasoningTokens,
3338
- cacheReadTokens: request.cacheReadTokens,
3339
- cacheWriteTokens: request.cacheWriteTokens,
3340
- tokenSemantics: {
3341
- reasoning: "separate",
3342
- cacheRead: "separate",
3343
- cacheWrite: "separate"
3344
- },
3345
- modelAttribution: "known",
3346
- timePrecision: "event",
3347
- usageScope: "this-mac",
3348
- aggregationTemporality: "delta",
3349
- authority: "local-observation"
3350
- };
3351
- }
3352
- function mapLocalCost(request, cost) {
3353
- const usageObservationId = `opencode-request:${request.id}`;
3354
- return {
3355
- id: `opencode-request-cost:${request.id}`,
3356
- sourceId: usageObservationId,
3357
- billingDomainId: "go-subscription",
3358
- observedAt: new Date(request.observedAtMs).toISOString(),
3359
- kind: "reported-estimate",
3360
- amount: cost,
3361
- currency: "USD",
3362
- authority: "local-observation",
3363
- model: request.model,
3364
- usageObservationId,
3365
- priceSnapshot: {
3366
- id: "opencode-message-reported-cost-v2",
3367
- version: "2026-08-28",
3368
- source: "OpenCode local message history reported cost",
3369
- canonicalModel: request.model,
3370
- effectiveAt: "2026-08-28T00:00:00.000Z",
3371
- effectiveUntil: null,
3372
- currency: "USD",
3373
- ratesPerMillion: {
3374
- input: null,
3375
- output: null,
3376
- reasoning: null,
3377
- "cache-read": null,
3378
- "cache-write": null
3379
- }
3380
- }
3381
- };
3382
- }
3383
- function safeFailure3(error) {
3998
+ function safeFailure4(error) {
3384
3999
  if (error instanceof Error && "code" in error && typeof error.code === "string" && "recovery" in error && typeof error.recovery === "string") {
3385
4000
  return { code: error.code, message: error.message, recovery: error.recovery };
3386
4001
  }
@@ -3395,9 +4010,9 @@ var init_opencode_go_connector = __esm({
3395
4010
  "src/connectors/opencode-go/opencode-go-connector.ts"() {
3396
4011
  "use strict";
3397
4012
  LIMITS = {
3398
- rolling: { label: "5 hour", amount: 12 },
3399
- weekly: { label: "Week", amount: 30 },
3400
- monthly: { label: "Month", amount: 60 }
4013
+ rolling: { label: "5 hour", amount: 12, windowDurationMinutes: 300 },
4014
+ weekly: { label: "Week", amount: 30, windowDurationMinutes: 10080 },
4015
+ monthly: { label: "Month", amount: 60, windowDurationMinutes: 43200 }
3401
4016
  };
3402
4017
  OpenCodeGoConnector = class {
3403
4018
  id = "opencode-go";
@@ -3418,24 +4033,21 @@ var init_opencode_go_connector = __esm({
3418
4033
  this.#localHistoryClient.readHistory()
3419
4034
  ]);
3420
4035
  const warnings = [];
3421
- if (accountResult.status === "rejected") warnings.push(safeFailure3(accountResult.reason));
3422
- if (localResult.status === "rejected") warnings.push(safeFailure3(localResult.reason));
4036
+ if (accountResult.status === "rejected") warnings.push(safeFailure4(accountResult.reason));
4037
+ if (localResult.status === "rejected") warnings.push(safeFailure4(localResult.reason));
3423
4038
  const account = accountResult.status === "fulfilled" ? accountResult.value : null;
3424
- const local = localResult.status === "fulfilled" ? localResult.value : [];
3425
4039
  return {
3426
4040
  provider: { id: this.id, displayName: this.displayName },
3427
4041
  billingDomains: [{ id: "go-subscription", displayName: "OpenCode Go subscription" }],
3428
4042
  quotaBuckets: account ? mapQuota2(account) : [],
3429
- usage: local.map(mapLocalUsage),
4043
+ usage: [],
3430
4044
  ...localResult.status === "fulfilled" ? {
3431
4045
  usageReconciliation: {
3432
4046
  authoritativeIdPrefix: "opencode-request:",
3433
4047
  retiredIdPrefixes: ["opencode-session:"]
3434
4048
  }
3435
4049
  } : {},
3436
- costs: local.flatMap(
3437
- (request) => request.cost === null ? [] : [mapLocalCost(request, request.cost)]
3438
- ),
4050
+ costs: [],
3439
4051
  warnings,
3440
4052
  observedAt
3441
4053
  };
@@ -3473,6 +4085,11 @@ function mapBillingQuota(billing) {
3473
4085
  billingDomainId: "grok-build-subscription",
3474
4086
  label: period.label,
3475
4087
  usedPercent,
4088
+ windowDurationMinutes: nativeWindowDurationMinutes(
4089
+ config.currentPeriod?.start ?? config.billingPeriodStart,
4090
+ resetsAt,
4091
+ period.id
4092
+ ),
3476
4093
  resetsAt,
3477
4094
  authority: "official-client",
3478
4095
  scope: "account-wide",
@@ -3480,6 +4097,16 @@ function mapBillingQuota(billing) {
3480
4097
  }
3481
4098
  ];
3482
4099
  }
4100
+ function nativeWindowDurationMinutes(startsAt, resetsAt, period) {
4101
+ const start = startsAt ? Date.parse(startsAt) : Number.NaN;
4102
+ const end = resetsAt ? Date.parse(resetsAt) : Number.NaN;
4103
+ if (Number.isFinite(start) && Number.isFinite(end) && end > start) {
4104
+ return Math.round((end - start) / 6e4);
4105
+ }
4106
+ if (period === "weekly") return 10080;
4107
+ if (period === "monthly") return 43200;
4108
+ return null;
4109
+ }
3483
4110
  function nativePeriod(type, fallback) {
3484
4111
  if (type === "USAGE_PERIOD_TYPE_WEEKLY") return { id: "weekly", label: "Weekly limit" };
3485
4112
  if (type === "USAGE_PERIOD_TYPE_MONTHLY" || fallback === "monthly") {
@@ -3491,7 +4118,7 @@ function derivePercent(used, limit) {
3491
4118
  if (used === void 0 || limit === void 0 || limit <= 0) return null;
3492
4119
  return Math.min(100, Math.max(0, used / limit * 100));
3493
4120
  }
3494
- function safeFailure4(error) {
4121
+ function safeFailure5(error) {
3495
4122
  if (error instanceof Error && "code" in error && typeof error.code === "string" && "recovery" in error && typeof error.recovery === "string") {
3496
4123
  return { code: error.code, message: error.message, recovery: error.recovery };
3497
4124
  }
@@ -3554,7 +4181,7 @@ var init_grok_build_connector = __esm({
3554
4181
  });
3555
4182
  }
3556
4183
  } catch (error) {
3557
- warnings.push(safeFailure4(error));
4184
+ warnings.push(safeFailure5(error));
3558
4185
  }
3559
4186
  const history = this.#historyClient ? await this.#historyClient.readUsage(options) : { usage: [], costs: [], complete: true };
3560
4187
  if (!history.complete) warnings.push(incompleteTranscriptFailure3());
@@ -3698,6 +4325,50 @@ import { open } from "fs/promises";
3698
4325
  import { homedir as homedir2 } from "os";
3699
4326
  import { join as join3 } from "path";
3700
4327
  import { z as z7 } from "zod";
4328
+ function billingIsFresh(billing, now) {
4329
+ if (!billing.sourceObservedAt) return false;
4330
+ const observedAt = Date.parse(billing.sourceObservedAt);
4331
+ if (!Number.isFinite(observedAt)) return false;
4332
+ return now.getTime() - observedAt <= GROK_BILLING_FRESHNESS_MS;
4333
+ }
4334
+ async function refreshBillingLogViaDashboard(command, timeoutMs) {
4335
+ if (process.platform !== "darwin") return;
4336
+ const refreshTimeoutMs = Math.min(timeoutMs, 6e3);
4337
+ const expectScript2 = [
4338
+ `set timeout ${Math.max(1, Math.ceil(refreshTimeoutMs / 1e3))}`,
4339
+ "log_user 0",
4340
+ "set command $env(AGENT_USAGE_GROK_REFRESH_COMMAND)",
4341
+ "spawn -noecho $command dashboard",
4342
+ `after ${Math.min(2e3, Math.max(250, refreshTimeoutMs - 1e3))}`,
4343
+ 'send "\\021\\021"',
4344
+ "expect eof"
4345
+ ].join("\n");
4346
+ await new Promise((resolve5) => {
4347
+ const dashboard = spawn3("/usr/bin/expect", ["-c", expectScript2], {
4348
+ env: {
4349
+ ...process.env,
4350
+ AGENT_USAGE_GROK_REFRESH_COMMAND: command,
4351
+ TERM: process.env.TERM ?? "xterm-256color"
4352
+ },
4353
+ stdio: ["ignore", "pipe", "pipe"]
4354
+ });
4355
+ dashboard.stdout.resume();
4356
+ dashboard.stderr.resume();
4357
+ let settled = false;
4358
+ const stopTimer = setTimeout(() => {
4359
+ dashboard.kill("SIGTERM");
4360
+ finish();
4361
+ }, refreshTimeoutMs);
4362
+ const finish = () => {
4363
+ if (settled) return;
4364
+ settled = true;
4365
+ clearTimeout(stopTimer);
4366
+ resolve5();
4367
+ };
4368
+ dashboard.once("error", finish);
4369
+ dashboard.once("exit", finish);
4370
+ });
4371
+ }
3701
4372
  function parseLatestBillingLog(text) {
3702
4373
  const lines = text.split(/\r?\n/);
3703
4374
  for (let index = lines.length - 1; index >= 0; index -= 1) {
@@ -3748,7 +4419,7 @@ function unavailableError3(cause) {
3748
4419
  { cause }
3749
4420
  );
3750
4421
  }
3751
- var GrokBillingAdapterError, StdioGrokBillingClient, JsonRpcError, JsonLinePeer2;
4422
+ var GrokBillingAdapterError, StdioGrokBillingClient, GROK_BILLING_FRESHNESS_MS, JsonRpcError, JsonLinePeer2;
3752
4423
  var init_stdio_grok_billing_client = __esm({
3753
4424
  "src/connectors/grok-build/stdio-grok-billing-client.ts"() {
3754
4425
  "use strict";
@@ -3768,6 +4439,8 @@ var init_stdio_grok_billing_client = __esm({
3768
4439
  #timeoutMs;
3769
4440
  #spawnProcess;
3770
4441
  #readUnifiedLog;
4442
+ #refreshBillingLog;
4443
+ #clock;
3771
4444
  constructor(options = {}) {
3772
4445
  this.#command = options.command ?? "grok";
3773
4446
  this.#timeoutMs = options.timeoutMs ?? 8e3;
@@ -3777,13 +4450,15 @@ var init_stdio_grok_billing_client = __esm({
3777
4450
  this.#readUnifiedLog = options.readUnifiedLog ?? (() => readLogTail(
3778
4451
  join3(process.env.GROK_HOME ?? join3(homedir2(), ".grok"), "logs", "unified.jsonl")
3779
4452
  ));
4453
+ this.#refreshBillingLog = options.refreshBillingLog ?? (options.readUnifiedLog ? async () => void 0 : () => refreshBillingLogViaDashboard(this.#command, this.#timeoutMs));
4454
+ this.#clock = options.clock ?? (() => /* @__PURE__ */ new Date());
3780
4455
  }
3781
4456
  async readBilling() {
3782
4457
  let process2;
3783
4458
  try {
3784
4459
  process2 = this.#spawnProcess(this.#command, ["agent", "--no-leader", "stdio"]);
3785
4460
  } catch (error) {
3786
- const fallback = await this.#readLogFallback();
4461
+ const fallback = await this.#readFreshLogFallback();
3787
4462
  if (fallback) return fallback;
3788
4463
  throw unavailableError3(error);
3789
4464
  }
@@ -3815,7 +4490,7 @@ var init_stdio_grok_billing_client = __esm({
3815
4490
  }
3816
4491
  return billing.data;
3817
4492
  } catch (error) {
3818
- const fallback = await this.#readLogFallback();
4493
+ const fallback = await this.#readFreshLogFallback();
3819
4494
  if (fallback) return fallback;
3820
4495
  if (error instanceof GrokBillingAdapterError) throw error;
3821
4496
  if (error instanceof JsonRpcError && error.code === -32601) {
@@ -3846,7 +4521,18 @@ var init_stdio_grok_billing_client = __esm({
3846
4521
  return null;
3847
4522
  }
3848
4523
  }
4524
+ async #readFreshLogFallback() {
4525
+ const cached = await this.#readLogFallback();
4526
+ if (cached && billingIsFresh(cached, this.#clock())) return cached;
4527
+ try {
4528
+ await this.#refreshBillingLog();
4529
+ } catch {
4530
+ return cached;
4531
+ }
4532
+ return await this.#readLogFallback() ?? cached;
4533
+ }
3849
4534
  };
4535
+ GROK_BILLING_FRESHNESS_MS = 5 * 60 * 1e3;
3850
4536
  JsonRpcError = class extends Error {
3851
4537
  code;
3852
4538
  constructor(body) {
@@ -4133,7 +4819,7 @@ function endpointFailure(error, label) {
4133
4819
  recovery: "Check network access and xAI status, then retry."
4134
4820
  };
4135
4821
  }
4136
- function safeFailure5(error) {
4822
+ function safeFailure6(error) {
4137
4823
  if (error instanceof Error && "code" in error && typeof error.code === "string" && "recovery" in error && typeof error.recovery === "string") {
4138
4824
  return { code: error.code, message: error.message, recovery: error.recovery };
4139
4825
  }
@@ -4388,7 +5074,7 @@ var init_xai_api_connector = __esm({
4388
5074
  costs: [],
4389
5075
  balances: [],
4390
5076
  invoices: [],
4391
- warnings: [safeFailure5(error)],
5077
+ warnings: [safeFailure6(error)],
4392
5078
  observedAt
4393
5079
  };
4394
5080
  }
@@ -4844,6 +5530,25 @@ async function startLocalServer(options) {
4844
5530
  sendOtlpProtobuf(response, 200);
4845
5531
  return;
4846
5532
  }
5533
+ if (request.method === "GET" && requestUrl.pathname === "/api/overview/providers") {
5534
+ sendJson(response, 200, await options.application.getAgentProviderIndex());
5535
+ return;
5536
+ }
5537
+ if (request.method === "GET" && requestUrl.pathname.startsWith("/api/overview/providers/")) {
5538
+ const providerId = decodeURIComponent(
5539
+ requestUrl.pathname.slice("/api/overview/providers/".length)
5540
+ );
5541
+ const provider = await options.application.getProviderOverview(
5542
+ providerId,
5543
+ parseUsageQuery(requestUrl)
5544
+ );
5545
+ if (!provider) {
5546
+ sendJson(response, 404, { error: "provider-not-found" });
5547
+ return;
5548
+ }
5549
+ sendJson(response, 200, provider);
5550
+ return;
5551
+ }
4847
5552
  if (request.method === "GET" && requestUrl.pathname === "/api/overview") {
4848
5553
  const query = parseUsageQuery(requestUrl);
4849
5554
  sendJson(response, 200, await options.application.getOverview(query));
@@ -4854,6 +5559,13 @@ async function startLocalServer(options) {
4854
5559
  sendJson(response, 403, { error: "invalid-origin" });
4855
5560
  return;
4856
5561
  }
5562
+ if (requestUrl.searchParams.get("background") === "true") {
5563
+ void options.application.startBackgroundProcessing({
5564
+ userInitiated: requestUrl.searchParams.get("mode") !== "automatic"
5565
+ });
5566
+ sendJson(response, 202, { accepted: true });
5567
+ return;
5568
+ }
4857
5569
  await options.application.refresh({
4858
5570
  userInitiated: requestUrl.searchParams.get("mode") !== "automatic"
4859
5571
  });
@@ -4906,6 +5618,19 @@ async function startLocalServer(options) {
4906
5618
  sendJson(response, 200, await options.application.clearData(input));
4907
5619
  return;
4908
5620
  }
5621
+ if (request.method === "GET" && requestUrl.pathname === "/api/plans") {
5622
+ sendJson(response, 200, await options.application.getPlanSettings());
5623
+ return;
5624
+ }
5625
+ if (request.method === "PATCH" && requestUrl.pathname === "/api/plans") {
5626
+ if (!validMutationOrigin(authentication, request, origin)) {
5627
+ sendJson(response, 403, { error: "invalid-origin" });
5628
+ return;
5629
+ }
5630
+ const input = planSubscriptionSchema.parse(await readJsonBody(request));
5631
+ sendJson(response, 200, await options.application.updatePlanSubscription(input));
5632
+ return;
5633
+ }
4909
5634
  if (request.method === "GET" && requestUrl.pathname === "/api/monitoring") {
4910
5635
  sendJson(response, 200, await options.application.getMonitoringStatus());
4911
5636
  return;
@@ -5104,7 +5829,7 @@ function sendHtml(response, status, body) {
5104
5829
  response.writeHead(status, { "content-type": "text/html; charset=utf-8" });
5105
5830
  response.end(body);
5106
5831
  }
5107
- var SESSION_COOKIE, connectorActionSchema, usageQuerySchema, monitoringSettingsSchema, clearDataSchema, hardRebuildSchema;
5832
+ var SESSION_COOKIE, connectorActionSchema, usageQuerySchema, monitoringSettingsSchema, planSubscriptionSchema, clearDataSchema, hardRebuildSchema;
5108
5833
  var init_local_server = __esm({
5109
5834
  "src/server/local-server.ts"() {
5110
5835
  "use strict";
@@ -5127,6 +5852,17 @@ var init_local_server = __esm({
5127
5852
  notificationsEnabled: z9.boolean().optional(),
5128
5853
  startAtLogin: z9.boolean().optional()
5129
5854
  }).refine((value) => Object.keys(value).length > 0, "At least one setting is required");
5855
+ planSubscriptionSchema = z9.object({
5856
+ providerId: z9.string().min(1),
5857
+ billingDomainId: z9.string().min(1),
5858
+ plan: z9.object({
5859
+ planId: z9.string().min(1).nullable(),
5860
+ amount: z9.number().positive().finite().optional(),
5861
+ currency: z9.string().length(3).optional(),
5862
+ billingPeriod: z9.enum(["monthly", "annual"]).optional(),
5863
+ anchorDate: z9.string().regex(/^\d{4}-\d{2}-\d{2}$/).nullable().optional()
5864
+ }).nullable()
5865
+ });
5130
5866
  clearDataSchema = z9.object({ deleteProductSecrets: z9.boolean().default(false) });
5131
5867
  hardRebuildSchema = z9.object({ confirmExpensiveOperation: z9.literal(true) });
5132
5868
  }
@@ -5677,6 +6413,16 @@ async function runDatabaseWorker(workerData) {
5677
6413
  if (workerData.operation === 'indexes') {
5678
6414
  database.exec(workerData.indexesSql);
5679
6415
  parentPort.postMessage({ ok: true, data: null });
6416
+ } else if (workerData.operation === 'delete-demo-data') {
6417
+ database.exec('BEGIN IMMEDIATE');
6418
+ try {
6419
+ database.exec(workerData.deleteDemoDataSql);
6420
+ database.exec('COMMIT');
6421
+ parentPort.postMessage({ ok: true, data: null });
6422
+ } catch (error) {
6423
+ database.exec('ROLLBACK');
6424
+ throw error;
6425
+ }
5680
6426
  } else if (workerData.operation === 'delete-derived-costs') {
5681
6427
  database.prepare(workerData.deleteDerivedCostsSql).run();
5682
6428
  parentPort.postMessage({ ok: true, data: null });
@@ -5844,6 +6590,7 @@ function mapQuotaRow(row) {
5844
6590
  billingDomainId: row.billing_domain_id,
5845
6591
  label: row.label,
5846
6592
  usedPercent: row.used_percent,
6593
+ windowDurationMinutes: row.window_duration_minutes,
5847
6594
  resetsAt: row.resets_at,
5848
6595
  authority: row.authority,
5849
6596
  observedAt: row.observed_at,
@@ -6045,7 +6792,7 @@ function buildGlobalSummary(providers, riskSummary, now, query) {
6045
6792
  tokenEvidence,
6046
6793
  apiRetailEquivalent: {
6047
6794
  status: sawRetailEquivalent ? "available" : "unavailable",
6048
- amount: sawRetailEquivalent ? preciseAmount(retailAmount) : null,
6795
+ amount: sawRetailEquivalent ? preciseAmount2(retailAmount) : null,
6049
6796
  currency: "USD",
6050
6797
  pricingCoverage: tokenEvidence.recordedTokens === 0 ? null : retailPricedTokens / tokenEvidence.recordedTokens
6051
6798
  },
@@ -6055,7 +6802,7 @@ function buildGlobalSummary(providers, riskSummary, now, query) {
6055
6802
  contributions
6056
6803
  };
6057
6804
  }
6058
- function buildTokenMoneyWorkbench(providers, now, query) {
6805
+ function buildTokenMoneyWorkbench(providers, now, query, planSubscriptions, planBillingPeriods) {
6059
6806
  const normalized = normalizeUsageQuery(now, query);
6060
6807
  const allHistories = allDomainHistories(providers);
6061
6808
  const headlineHistories = allHistories.filter(({ includedInHeadline }) => includedInHeadline);
@@ -6246,9 +6993,43 @@ function buildTokenMoneyWorkbench(providers, now, query) {
6246
6993
  observationCount > 0 ? recordedTokens : null,
6247
6994
  retailEquivalent,
6248
6995
  reportedEstimate
6249
- )
6996
+ ),
6997
+ planValue: buildWorkbenchPlanValue({
6998
+ domains: planValueDomains(allHistories, comparisonCurrency),
6999
+ subscriptions: planSubscriptions,
7000
+ comparisonCurrency,
7001
+ start: normalized.start.toISOString(),
7002
+ end: normalized.end.toISOString(),
7003
+ rates: uniqueExchangeRates(allHistories.flatMap(({ history }) => history.exchangeRates)),
7004
+ billingPeriods: planBillingPeriods
7005
+ })
6250
7006
  };
6251
7007
  }
7008
+ function planValueDomains(histories, comparisonCurrency) {
7009
+ return histories.map(({ provider, domain, history, includedInHeadline }) => {
7010
+ const domainTokens = history.tokenEvidence.recordedTokens;
7011
+ const metric = (purpose) => buildWorkbenchMetric(
7012
+ history.costs,
7013
+ purpose,
7014
+ comparisonCurrency,
7015
+ domainTokens,
7016
+ history.exchangeRates
7017
+ );
7018
+ return {
7019
+ providerId: provider.id,
7020
+ providerDisplayName: provider.displayName,
7021
+ billingDomainId: domain.id,
7022
+ billingDomainDisplayName: domain.displayName,
7023
+ includedInHeadline,
7024
+ recordedTokens: domainTokens,
7025
+ observationCount: history.tokenEvidence.observationCount,
7026
+ retailEquivalent: metric("retail-equivalent"),
7027
+ actualCost: metric("actual"),
7028
+ authorities: history.authorities ?? [],
7029
+ lastObservedAt: history.lastObservedAt ?? null
7030
+ };
7031
+ });
7032
+ }
6252
7033
  function allDomainHistories(providers) {
6253
7034
  return providers.flatMap(
6254
7035
  (provider) => provider.billingDomains.map((domain) => ({
@@ -6304,11 +7085,11 @@ function buildWorkbenchMetric(costs, purpose, comparisonCurrency, recordedTokens
6304
7085
  return {
6305
7086
  purpose,
6306
7087
  status,
6307
- amount: status === "available" ? preciseAmount(convertedAmount) : null,
7088
+ amount: status === "available" ? preciseAmount2(convertedAmount) : null,
6308
7089
  comparisonCurrency,
6309
7090
  nativeAmounts: [...native.entries()].map(([currency, amount]) => ({
6310
7091
  currency,
6311
- amount: amount.complete ? preciseAmount(amount.amount) : null,
7092
+ amount: amount.complete ? preciseAmount2(amount.amount) : null,
6312
7093
  records: amount.records,
6313
7094
  knownRecords: amount.knownRecords
6314
7095
  })).sort((left, right) => left.currency.localeCompare(right.currency)),
@@ -6477,9 +7258,9 @@ function buildWorkbenchModelRanking(histories, buckets, comparisonCurrency, reco
6477
7258
  )
6478
7259
  );
6479
7260
  return {
6480
- byTokens: byTokens.slice(0, 5).map((entry) => entry.id),
6481
- byCost: byCost.slice(0, 5).map((entry) => entry.id),
6482
- byRetailEquivalent: byRetailEquivalent.slice(0, 5).map((entry) => entry.id),
7261
+ byTokens: byTokens.map((entry) => entry.id),
7262
+ byCost: byCost.map((entry) => entry.id),
7263
+ byRetailEquivalent: byRetailEquivalent.map((entry) => entry.id),
6483
7264
  entries: byTokens,
6484
7265
  unclassified
6485
7266
  };
@@ -6900,7 +7681,7 @@ function round(value) {
6900
7681
  function pricingInputsChanged(existing, observation) {
6901
7682
  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;
6902
7683
  }
6903
- function preciseAmount(value) {
7684
+ function preciseAmount2(value) {
6904
7685
  return Number(value.toFixed(12));
6905
7686
  }
6906
7687
  function tokenAuthority(authorities) {
@@ -6931,11 +7712,12 @@ function freshnessStatus(lastSuccessAt, now) {
6931
7712
  if (!lastSuccessAt) return "unavailable";
6932
7713
  return now.getTime() - new Date(lastSuccessAt).getTime() <= FRESHNESS_WINDOW_MS ? "fresh" : "stale";
6933
7714
  }
6934
- var FRESHNESS_WINDOW_MS, QUERY_INDEXES_SQL, DELETE_DERIVED_RETAIL_COSTS_SQL, DatabaseSync2, RETENTION_AGGREGATE_SQL, SqliteUsageRepository;
7715
+ var FRESHNESS_WINDOW_MS, QUERY_INDEXES_SQL, DELETE_DERIVED_RETAIL_COSTS_SQL, DELETE_DEMO_PROVIDER_DATA_SQL, DatabaseSync2, RETENTION_AGGREGATE_SQL, SqliteUsageRepository;
6935
7716
  var init_sqlite_usage_repository = __esm({
6936
7717
  "src/server/sqlite-usage-repository.ts"() {
6937
7718
  "use strict";
6938
7719
  init_token_normalization();
7720
+ init_plan_pricing();
6939
7721
  FRESHNESS_WINDOW_MS = 15 * 60 * 1e3;
6940
7722
  QUERY_INDEXES_SQL = `
6941
7723
  CREATE INDEX IF NOT EXISTS usage_observed_at_idx
@@ -6964,6 +7746,12 @@ var init_sqlite_usage_repository = __esm({
6964
7746
  WHERE usage.provider_id = cost_records.provider_id
6965
7747
  AND usage.id = cost_records.usage_observation_id
6966
7748
  )
7749
+ `;
7750
+ DELETE_DEMO_PROVIDER_DATA_SQL = `
7751
+ DELETE FROM connector_diagnostics WHERE provider_id = 'demo';
7752
+ DELETE FROM connector_runtime WHERE id = 'demo';
7753
+ DELETE FROM connector_settings WHERE id = 'demo';
7754
+ DELETE FROM providers WHERE id = 'demo';
6967
7755
  `;
6968
7756
  ({ DatabaseSync: DatabaseSync2 } = createRequire2(import.meta.url)(
6969
7757
  "node:sqlite"
@@ -6992,8 +7780,10 @@ var init_sqlite_usage_repository = __esm({
6992
7780
  SqliteUsageRepository = class {
6993
7781
  #database;
6994
7782
  #databasePath;
6995
- constructor(databasePath) {
7783
+ #hideDemoProvider;
7784
+ constructor(databasePath, options = {}) {
6996
7785
  this.#databasePath = databasePath;
7786
+ this.#hideDemoProvider = options.hideDemoProvider ?? false;
6997
7787
  mkdirSync(dirname3(databasePath), { recursive: true });
6998
7788
  this.#database = new DatabaseSync2(databasePath);
6999
7789
  this.#database.exec("PRAGMA journal_mode = WAL; PRAGMA foreign_keys = ON;");
@@ -7041,13 +7831,15 @@ var init_sqlite_usage_repository = __esm({
7041
7831
  }
7042
7832
  const quotaStatement = this.#database.prepare(
7043
7833
  `INSERT INTO quota_buckets (
7044
- provider_id, id, billing_domain_id, label, used_percent, resets_at, authority, observed_at,
7834
+ provider_id, id, billing_domain_id, label, used_percent, window_duration_minutes,
7835
+ resets_at, authority, observed_at,
7045
7836
  scope, status, limit_amount, limit_currency, fallback_status
7046
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
7837
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
7047
7838
  ON CONFLICT(provider_id, id) DO UPDATE SET
7048
7839
  billing_domain_id = excluded.billing_domain_id,
7049
7840
  label = excluded.label,
7050
7841
  used_percent = excluded.used_percent,
7842
+ window_duration_minutes = excluded.window_duration_minutes,
7051
7843
  resets_at = excluded.resets_at,
7052
7844
  authority = excluded.authority,
7053
7845
  observed_at = excluded.observed_at,
@@ -7064,6 +7856,7 @@ var init_sqlite_usage_repository = __esm({
7064
7856
  bucket.billingDomainId,
7065
7857
  bucket.label,
7066
7858
  bucket.usedPercent,
7859
+ bucket.windowDurationMinutes ?? null,
7067
7860
  bucket.resetsAt,
7068
7861
  bucket.authority,
7069
7862
  snapshot2.observedAt,
@@ -7480,16 +8273,43 @@ var init_sqlite_usage_repository = __esm({
7480
8273
  `SELECT id, display_name, last_success_at, last_error, last_error_code, last_recovery
7481
8274
  FROM providers ORDER BY id`
7482
8275
  ).all();
7483
- const overviews = providers.map((provider) => this.#getProviderOverview(provider, now, query));
8276
+ const visibleProviders = this.#hideDemoProvider ? providers.filter((provider) => provider.id !== "demo") : providers;
8277
+ const overviews = visibleProviders.map(
8278
+ (provider) => this.#getProviderOverview(provider, now, query)
8279
+ );
7484
8280
  const riskSummary = buildRiskSummary(overviews);
8281
+ const planSubscriptions = this.getPlanSubscriptions();
7485
8282
  return {
7486
8283
  generatedAt: now.toISOString(),
7487
8284
  globalSummary: buildGlobalSummary(overviews, riskSummary, now, query),
7488
- workbench: buildTokenMoneyWorkbench(overviews, now, query),
8285
+ workbench: buildTokenMoneyWorkbench(
8286
+ overviews,
8287
+ now,
8288
+ query,
8289
+ planSubscriptions,
8290
+ this.#planBillingPeriodSummaries(planSubscriptions, now, query)
8291
+ ),
7489
8292
  providers: overviews,
7490
8293
  riskSummary
7491
8294
  };
7492
8295
  }
8296
+ getAgentProviderIndex(now) {
8297
+ const providers = this.#database.prepare("SELECT id, display_name FROM providers ORDER BY id").all();
8298
+ return {
8299
+ generatedAt: now.toISOString(),
8300
+ providers: providers.filter(
8301
+ (provider) => provider.id !== "opencode" && (!this.#hideDemoProvider || provider.id !== "demo")
8302
+ ).map((provider) => ({ id: provider.id, displayName: provider.display_name }))
8303
+ };
8304
+ }
8305
+ getProviderOverview(now, providerId, query = {}) {
8306
+ if (this.#hideDemoProvider && providerId === "demo") return null;
8307
+ const provider = this.#database.prepare(
8308
+ `SELECT id, display_name, last_success_at, last_error, last_error_code, last_recovery
8309
+ FROM providers WHERE id = ?`
8310
+ ).get(providerId);
8311
+ return provider ? this.#getProviderOverview(provider, now, query) : null;
8312
+ }
7493
8313
  saveExchangeRateSnapshot(snapshot2) {
7494
8314
  this.#database.prepare(
7495
8315
  `INSERT INTO exchange_rate_snapshots (
@@ -7565,6 +8385,57 @@ var init_sqlite_usage_repository = __esm({
7565
8385
  settings.startAtLogin ? 1 : 0
7566
8386
  );
7567
8387
  }
8388
+ getPlanSubscriptions() {
8389
+ const rows = this.#database.prepare(
8390
+ `SELECT provider_id, billing_domain_id, plan_id, display_name, amount, currency,
8391
+ billing_period, anchor_date, price_source, updated_at
8392
+ FROM plan_subscriptions
8393
+ ORDER BY provider_id, billing_domain_id`
8394
+ ).all();
8395
+ return rows.map((row) => ({
8396
+ providerId: row.provider_id,
8397
+ billingDomainId: row.billing_domain_id,
8398
+ planId: row.plan_id,
8399
+ displayName: row.display_name,
8400
+ amount: row.amount,
8401
+ currency: row.currency,
8402
+ billingPeriod: row.billing_period,
8403
+ anchorDate: row.anchor_date,
8404
+ priceSource: row.price_source,
8405
+ updatedAt: row.updated_at
8406
+ }));
8407
+ }
8408
+ savePlanSubscription(subscription) {
8409
+ this.#database.prepare(
8410
+ `INSERT INTO plan_subscriptions (
8411
+ provider_id, billing_domain_id, plan_id, display_name, amount, currency,
8412
+ billing_period, anchor_date, price_source, updated_at
8413
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
8414
+ ON CONFLICT(provider_id, billing_domain_id) DO UPDATE SET
8415
+ plan_id = excluded.plan_id,
8416
+ display_name = excluded.display_name,
8417
+ amount = excluded.amount,
8418
+ currency = excluded.currency,
8419
+ billing_period = excluded.billing_period,
8420
+ anchor_date = excluded.anchor_date,
8421
+ price_source = excluded.price_source,
8422
+ updated_at = excluded.updated_at`
8423
+ ).run(
8424
+ subscription.providerId,
8425
+ subscription.billingDomainId,
8426
+ subscription.planId,
8427
+ subscription.displayName,
8428
+ subscription.amount,
8429
+ subscription.currency,
8430
+ subscription.billingPeriod,
8431
+ subscription.anchorDate,
8432
+ subscription.priceSource,
8433
+ subscription.updatedAt
8434
+ );
8435
+ }
8436
+ deletePlanSubscription(providerId, billingDomainId) {
8437
+ this.#database.prepare("DELETE FROM plan_subscriptions WHERE provider_id = ? AND billing_domain_id = ?").run(providerId, billingDomainId);
8438
+ }
7568
8439
  getNotificationState(key) {
7569
8440
  const row = this.#database.prepare("SELECT value FROM notification_state WHERE key = ?").get(key);
7570
8441
  return row?.value ?? null;
@@ -7720,6 +8591,13 @@ var init_sqlite_usage_repository = __esm({
7720
8591
  throw error;
7721
8592
  }
7722
8593
  }
8594
+ async deleteDemoProviderDataAsync() {
8595
+ await runDatabaseWorker({
8596
+ databasePath: this.#databasePath,
8597
+ operation: "delete-demo-data",
8598
+ deleteDemoDataSql: DELETE_DEMO_PROVIDER_DATA_SQL
8599
+ });
8600
+ }
7723
8601
  deleteDerivedRetailCosts() {
7724
8602
  this.#database.prepare(DELETE_DERIVED_RETAIL_COSTS_SQL).run();
7725
8603
  }
@@ -7823,7 +8701,8 @@ var init_sqlite_usage_repository = __esm({
7823
8701
  }
7824
8702
  #getBillingDomainOverview(providerId, domain, now, query, forecasts, forecastCoverage, degradedDiagnostic, legacyProviderFailure = null) {
7825
8703
  const quotaRows = this.#database.prepare(
7826
- `SELECT id, billing_domain_id, label, used_percent, resets_at, authority, observed_at,
8704
+ `SELECT id, billing_domain_id, label, used_percent, window_duration_minutes, resets_at,
8705
+ authority, observed_at,
7827
8706
  scope, status, limit_amount, limit_currency, fallback_status
7828
8707
  FROM quota_buckets WHERE provider_id = ? AND billing_domain_id = ? ORDER BY id`
7829
8708
  ).all(providerId, domain.id);
@@ -8015,6 +8894,101 @@ var init_sqlite_usage_repository = __esm({
8015
8894
  coverageByDomain
8016
8895
  };
8017
8896
  }
8897
+ /**
8898
+ * Cycle-to-date evidence for every subscription that declares a renewal date.
8899
+ * Each Provider is measured over its own billing period, which is why this
8900
+ * cannot reuse the one rolling window the rest of the workbench shares.
8901
+ */
8902
+ #planBillingPeriodSummaries(subscriptions, now, query) {
8903
+ const normalized = normalizeUsageQuery(now, query);
8904
+ const summaries = /* @__PURE__ */ new Map();
8905
+ for (const subscription of subscriptions) {
8906
+ if (!subscription.anchorDate) continue;
8907
+ const period = billingPeriodContaining(
8908
+ subscription.anchorDate,
8909
+ subscription.billingPeriod,
8910
+ now
8911
+ );
8912
+ if (!period) continue;
8913
+ const observedThrough = new Date(Math.min(now.getTime(), period.end.getTime()));
8914
+ summaries.set(`${subscription.providerId}:${subscription.billingDomainId}`, {
8915
+ start: period.start.toISOString(),
8916
+ end: period.end.toISOString(),
8917
+ observedThrough: observedThrough.toISOString(),
8918
+ ...this.#rangeUsageSummary(
8919
+ subscription.providerId,
8920
+ subscription.billingDomainId,
8921
+ period.start,
8922
+ observedThrough,
8923
+ normalized.comparisonCurrency
8924
+ )
8925
+ });
8926
+ }
8927
+ return summaries;
8928
+ }
8929
+ #rangeUsageSummary(providerId, billingDomainId, start, end, comparisonCurrency) {
8930
+ const startIso = start.toISOString();
8931
+ const endIso = end.toISOString();
8932
+ const usage = this.#database.prepare(
8933
+ `SELECT id, model, observed_at, authority, total_tokens, input_tokens, output_tokens,
8934
+ reasoning_tokens, cache_read_tokens, cache_write_tokens, cache_write_5m_tokens,
8935
+ cache_write_1h_tokens, source_reported_total_tokens,
8936
+ unclassified_tokens, total_derivation, model_attribution, time_precision,
8937
+ usage_scope, aggregation_temporality, reasoning_semantics,
8938
+ cache_read_semantics, cache_write_semantics
8939
+ FROM usage_observations
8940
+ WHERE provider_id = ? AND billing_domain_id = ?
8941
+ AND observed_at >= ? AND observed_at < ?
8942
+ AND ${additiveUsagePredicate()}
8943
+ ORDER BY observed_at, id`
8944
+ ).all(providerId, billingDomainId, startIso, endIso);
8945
+ const costs = this.#database.prepare(
8946
+ `SELECT id, source_id, billing_domain_id, observed_at, kind, amount, currency, authority,
8947
+ price_snapshot_id, price_snapshot_version, price_snapshot_source,
8948
+ price_snapshot_canonical_model, price_snapshot_effective_at,
8949
+ price_snapshot_effective_until, price_snapshot_currency,
8950
+ price_snapshot_rates_json, price_snapshot_source_url,
8951
+ price_snapshot_context_tier, model, usage_observation_id, priced_tokens,
8952
+ line_items_json, calculated_at
8953
+ FROM cost_records
8954
+ WHERE provider_id = ? AND billing_domain_id = ?
8955
+ AND observed_at >= ? AND observed_at < ?
8956
+ ORDER BY observed_at, id`
8957
+ ).all(providerId, billingDomainId, startIso, endIso);
8958
+ const rateRows = this.#database.prepare(
8959
+ `SELECT id, base_currency, quote_currency, rate, observed_at, source
8960
+ FROM exchange_rate_snapshots WHERE observed_at < ? ORDER BY observed_at DESC, id`
8961
+ ).all(endIso);
8962
+ const rateByCurrency = /* @__PURE__ */ new Map();
8963
+ for (const row of rateRows) {
8964
+ if (row.quote_currency === comparisonCurrency && !rateByCurrency.has(row.base_currency)) {
8965
+ rateByCurrency.set(row.base_currency, row);
8966
+ }
8967
+ }
8968
+ const evidence = emptyTokenEvidence();
8969
+ for (const row of usage) addTokenEvidence(evidence, row);
8970
+ const finished = finishTokenEvidence(evidence);
8971
+ const usedRates = /* @__PURE__ */ new Map();
8972
+ const historyCosts = summarizeHistoryCosts(
8973
+ costs,
8974
+ finished.recordedTokens,
8975
+ rateByCurrency,
8976
+ comparisonCurrency,
8977
+ end,
8978
+ usedRates
8979
+ );
8980
+ return {
8981
+ recordedTokens: finished.recordedTokens,
8982
+ observationCount: finished.observationCount,
8983
+ retailEquivalent: buildWorkbenchMetric(
8984
+ historyCosts,
8985
+ "retail-equivalent",
8986
+ comparisonCurrency,
8987
+ finished.recordedTokens,
8988
+ [...usedRates.values()]
8989
+ )
8990
+ };
8991
+ }
8018
8992
  #getBillingHistory(providerId, billingDomainId, now, query) {
8019
8993
  const normalized = normalizeUsageQuery(now, query);
8020
8994
  const start = normalized.start.toISOString();
@@ -8238,6 +9212,7 @@ var init_sqlite_usage_repository = __esm({
8238
9212
  billing_domain_id TEXT NOT NULL,
8239
9213
  label TEXT NOT NULL,
8240
9214
  used_percent REAL,
9215
+ window_duration_minutes INTEGER,
8241
9216
  resets_at TEXT,
8242
9217
  authority TEXT NOT NULL,
8243
9218
  observed_at TEXT NOT NULL,
@@ -8422,6 +9397,19 @@ var init_sqlite_usage_repository = __esm({
8422
9397
  key TEXT PRIMARY KEY,
8423
9398
  value TEXT NOT NULL
8424
9399
  );
9400
+ CREATE TABLE IF NOT EXISTS plan_subscriptions (
9401
+ provider_id TEXT NOT NULL,
9402
+ billing_domain_id TEXT NOT NULL,
9403
+ plan_id TEXT,
9404
+ display_name TEXT NOT NULL,
9405
+ amount REAL NOT NULL,
9406
+ currency TEXT NOT NULL,
9407
+ billing_period TEXT NOT NULL,
9408
+ anchor_date TEXT,
9409
+ price_source TEXT NOT NULL,
9410
+ updated_at TEXT NOT NULL,
9411
+ PRIMARY KEY (provider_id, billing_domain_id)
9412
+ );
8425
9413
  `);
8426
9414
  const usageColumns = this.#database.prepare("PRAGMA table_info(usage_observations)").all();
8427
9415
  if (!usageColumns.some((column) => column.name === "total_tokens")) {
@@ -8581,6 +9569,7 @@ var init_sqlite_usage_repository = __esm({
8581
9569
  for (const [name, type] of [
8582
9570
  ["scope", "TEXT"],
8583
9571
  ["status", "TEXT"],
9572
+ ["window_duration_minutes", "INTEGER"],
8584
9573
  ["limit_amount", "REAL"],
8585
9574
  ["limit_currency", "TEXT"],
8586
9575
  ["fallback_status", "TEXT"]
@@ -8589,6 +9578,10 @@ var init_sqlite_usage_repository = __esm({
8589
9578
  this.#database.exec(`ALTER TABLE quota_buckets ADD COLUMN ${name} ${type}`);
8590
9579
  }
8591
9580
  }
9581
+ const planColumns = this.#database.prepare("PRAGMA table_info(plan_subscriptions)").all();
9582
+ if (planColumns.length > 0 && !planColumns.some((column) => column.name === "anchor_date")) {
9583
+ this.#database.exec("ALTER TABLE plan_subscriptions ADD COLUMN anchor_date TEXT");
9584
+ }
8592
9585
  }
8593
9586
  };
8594
9587
  }
@@ -8606,17 +9599,21 @@ import { isAbsolute as isAbsolute3, join as join8, resolve as resolve3 } from "p
8606
9599
  import { fileURLToPath } from "url";
8607
9600
  async function runDaemon(home) {
8608
9601
  await mkdir4(home, { recursive: true, mode: 448 });
8609
- const repository = new SqliteUsageRepository(join8(home, "usage.sqlite"));
9602
+ const demoEnabled = process.env.AGENT_USAGE_DEMO === "1";
9603
+ const repository = new SqliteUsageRepository(join8(home, "usage.sqlite"), {
9604
+ hideDemoProvider: !demoEnabled
9605
+ });
8610
9606
  const keychainService = process.env.AGENT_USAGE_KEYCHAIN_SERVICE;
8611
9607
  const launchAgentLabel = process.env.AGENT_USAGE_LAUNCH_AGENT_LABEL;
8612
9608
  const nodeImport = process.env.AGENT_USAGE_NODE_IMPORT;
8613
9609
  const secretStore = new MacOsKeychainSecretStore(void 0, {
8614
9610
  service: keychainService
8615
9611
  });
9612
+ const openCodeLocalHistoryClient = new CliOpenCodeLocalHistoryClient();
8616
9613
  const application = new UsageApplication({
8617
9614
  repository,
8618
9615
  connectors: [
8619
- ...process.env.AGENT_USAGE_DEMO === "1" ? [createDemoConnector()] : [],
9616
+ ...demoEnabled ? [createDemoConnector()] : [],
8620
9617
  new CodexConnector(
8621
9618
  new StdioCodexAccountClient(),
8622
9619
  void 0,
@@ -8630,8 +9627,9 @@ async function runDaemon(home) {
8630
9627
  accountClient: new OfficialOpenCodeGoClient({
8631
9628
  authReader: new OpenCodeAuthFileReader()
8632
9629
  }),
8633
- localHistoryClient: new CliOpenCodeLocalHistoryClient()
9630
+ localHistoryClient: openCodeLocalHistoryClient
8634
9631
  }),
9632
+ new OpenCodeLocalConnector({ localHistoryClient: openCodeLocalHistoryClient }),
8635
9633
  new GrokBuildConnector({
8636
9634
  billingClient: new StdioGrokBillingClient(),
8637
9635
  historyClient: localTranscriptClient("grok", home)
@@ -8655,11 +9653,11 @@ async function runDaemon(home) {
8655
9653
  ...keychainService ? { AGENT_USAGE_KEYCHAIN_SERVICE: keychainService } : {},
8656
9654
  ...launchAgentLabel ? { AGENT_USAGE_LAUNCH_AGENT_LABEL: launchAgentLabel } : {},
8657
9655
  ...nodeImport ? { AGENT_USAGE_NODE_IMPORT: nodeImport } : {},
8658
- ...process.env.AGENT_USAGE_DEMO === "1" ? { AGENT_USAGE_DEMO: "1" } : {}
9656
+ ...demoEnabled ? { AGENT_USAGE_DEMO: "1" } : {}
8659
9657
  }
8660
9658
  }),
8661
9659
  connectorPolicies: Object.fromEntries(
8662
- ["codex", "claude-code", "opencode-go", "grok", "xai-api"].map((id) => [
9660
+ ["codex", "claude-code", "opencode-go", "opencode", "grok", "xai-api"].map((id) => [
8663
9661
  id,
8664
9662
  { minimumIntervalMs: 5 * 60 * 1e3, timeoutMs: id === "claude-code" ? 25e3 : 2e4 }
8665
9663
  ])
@@ -8687,6 +9685,13 @@ async function runDaemon(home) {
8687
9685
  origin: server.origin,
8688
9686
  apiToken: server.apiToken
8689
9687
  });
9688
+ if (!demoEnabled) {
9689
+ void repository.deleteDemoProviderDataAsync().catch(() => {
9690
+ process.stderr.write(
9691
+ "Agent Usage: stale demo data remains hidden and will be cleaned on a later startup.\n"
9692
+ );
9693
+ });
9694
+ }
8690
9695
  process.stderr.write(`Agent Usage: web service ready at ${server.origin}
8691
9696
  `);
8692
9697
  process.stderr.write("Agent Usage: updating cached usage in the background\u2026\n");
@@ -8788,6 +9793,7 @@ var init_runtime = __esm({
8788
9793
  init_claude_usage_screen_client();
8789
9794
  init_codex_connector();
8790
9795
  init_stdio_codex_account_client();
9796
+ init_opencode_local_connector();
8791
9797
  init_local_opencode_history_client();
8792
9798
  init_official_opencode_go_client();
8793
9799
  init_opencode_auth_reader();