agent-usage-all-in-one 0.8.0 → 0.9.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.
package/dist/cli.js CHANGED
@@ -1490,6 +1490,11 @@ function createProcessingStatus(startedAt, hardRebuild) {
1490
1490
  function yieldToEventLoop() {
1491
1491
  return new Promise((resolve5) => setImmediate(resolve5));
1492
1492
  }
1493
+ function yieldForPendingHttp() {
1494
+ return new Promise((resolve5) => {
1495
+ setTimeout(resolve5, PENDING_HTTP_YIELD_MS);
1496
+ });
1497
+ }
1493
1498
  function providerForConnector(id, definitions) {
1494
1499
  return definitions.find((definition) => definition.id === id)?.target.provider.id ?? id;
1495
1500
  }
@@ -1562,7 +1567,7 @@ function pickAgentProviderIndex(overview) {
1562
1567
  providers: overview.providers.filter((provider) => provider.id !== "opencode" && provider.id !== "dsh").map(({ id, displayName }) => ({ id, displayName }))
1563
1568
  };
1564
1569
  }
1565
- var UsageApplication;
1570
+ var UsageApplication, PENDING_HTTP_YIELD_MS;
1566
1571
  var init_usage_application = __esm({
1567
1572
  "src/core/usage-application.ts"() {
1568
1573
  "use strict";
@@ -1762,15 +1767,15 @@ var init_usage_application = __esm({
1762
1767
  const runtimeStates = new Map(
1763
1768
  this.#repository.getConnectorRuntimeStates().map((state) => [state.id, state])
1764
1769
  );
1765
- await Promise.all(
1770
+ const collected = await Promise.all(
1766
1771
  this.#connectors.map(async (connector) => {
1767
1772
  if (connector.consentId && connectorStates.get(connector.consentId) !== "connected") {
1768
- return;
1773
+ return null;
1769
1774
  }
1770
1775
  const now = this.#clock();
1771
1776
  const runtime = runtimeStates.get(connector.id);
1772
1777
  if (!options.userInitiated && runtime?.nextAllowedAt && new Date(runtime.nextAllowedAt).getTime() > now.getTime()) {
1773
- return;
1778
+ return null;
1774
1779
  }
1775
1780
  const policy = this.#connectorPolicies[connector.id] ?? {
1776
1781
  minimumIntervalMs: 0,
@@ -1782,54 +1787,27 @@ var init_usage_application = __esm({
1782
1787
  policy.timeoutMs,
1783
1788
  `${connector.id} timed out`
1784
1789
  );
1785
- this.#repository.saveSnapshot(this.#withRetailCosts(snapshot2));
1786
- if (snapshot2.warnings && snapshot2.warnings.length > 0) {
1787
- const failure = redactFailure(combineFailures(snapshot2.warnings));
1788
- this.#repository.recordFailure(snapshot2.provider, this.#clock().toISOString(), failure);
1789
- this.#saveConnectorDiagnostic(
1790
- connector,
1791
- snapshot2.provider.id,
1792
- snapshot2.billingDomains[0]?.id ?? defaultBillingDomain(connector.id, this.#connectorDefinitions),
1793
- failure
1794
- );
1795
- this.#recordConnectorOutcome(
1796
- connector.id,
1797
- now,
1798
- policy,
1799
- false,
1800
- runtime?.failureCount ?? 0
1801
- );
1802
- } else {
1803
- this.#saveHealthyConnectorDiagnostic(
1804
- connector,
1805
- snapshot2.provider.id,
1806
- snapshot2.billingDomains[0]?.id ?? defaultBillingDomain(connector.id, this.#connectorDefinitions),
1807
- snapshot2.observedAt
1808
- );
1809
- this.#recordConnectorOutcome(
1810
- connector.id,
1811
- now,
1812
- policy,
1813
- true,
1814
- runtime?.failureCount ?? 0
1815
- );
1816
- }
1790
+ return { ok: true, connector, now, runtime, policy, snapshot: snapshot2 };
1817
1791
  } catch (error) {
1818
- const providerId = providerForConnector(connector.id, this.#connectorDefinitions);
1819
- const failure = redactFailure(safeConnectorFailure(error));
1820
- this.#repository.recordFailure(
1821
- {
1822
- id: providerId,
1823
- displayName: displayNameForProvider(providerId, connector.displayName)
1824
- },
1825
- this.#clock().toISOString(),
1826
- failure
1827
- );
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);
1828
1806
  this.#saveConnectorDiagnostic(
1829
1807
  connector,
1830
- providerId,
1831
- defaultBillingDomain(connector.id, this.#connectorDefinitions),
1832
- failure
1808
+ snapshot2.provider.id,
1809
+ snapshot2.billingDomains[0]?.id ?? defaultBillingDomain(connector.id, this.#connectorDefinitions),
1810
+ failure2
1833
1811
  );
1834
1812
  this.#recordConnectorOutcome(
1835
1813
  connector.id,
@@ -1838,9 +1816,35 @@ var init_usage_application = __esm({
1838
1816
  false,
1839
1817
  runtime?.failureCount ?? 0
1840
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);
1841
1827
  }
1842
- })
1843
- );
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
+ }
1844
1848
  if (this.#repository.getMonitoringSettings().notificationsEnabled) {
1845
1849
  await this.#sendNotificationTransitions();
1846
1850
  }
@@ -2179,9 +2183,9 @@ var init_usage_application = __esm({
2179
2183
  if (snapshot2.usage.length === 0 && snapshot2.costs.length === 0) {
2180
2184
  throw new Error("Telemetry payload contained no supported metrics");
2181
2185
  }
2182
- await this.#queueDatabaseWrite(() => {
2183
- this.#repository.saveSnapshot(this.#withRetailCosts(snapshot2), { preserveFailure: true });
2184
- });
2186
+ await this.#queueDatabaseWrite(
2187
+ () => this.#repository.saveSnapshot(this.#withRetailCosts(snapshot2), { preserveFailure: true })
2188
+ );
2185
2189
  }
2186
2190
  #queueDatabaseWrite(action) {
2187
2191
  const result = this.#databaseWriteQueue.then(action, action);
@@ -2296,6 +2300,7 @@ var init_usage_application = __esm({
2296
2300
  return status;
2297
2301
  }
2298
2302
  };
2303
+ PENDING_HTTP_YIELD_MS = 20;
2299
2304
  }
2300
2305
  });
2301
2306
 
@@ -2401,6 +2406,20 @@ var init_catalog = __esm({
2401
2406
  billingDomain: { id: "code-assist-subscription", displayName: "Gemini Code Assist" }
2402
2407
  },
2403
2408
  officialCredentialPaths: [".gemini/antigravity-cli", ".gemini/antigravity"]
2409
+ },
2410
+ {
2411
+ id: "cursor",
2412
+ displayName: "Cursor",
2413
+ command: "agent",
2414
+ permissionDescription: "Read the official Agent CLI /usage screen and account email. Connecting starts agent on refresh and may leave Cursor session files under ~/.cursor; credentials stay in Cursor.",
2415
+ credentialOwner: "official-client",
2416
+ experimental: true,
2417
+ expectedCoverage: ["quota"],
2418
+ target: {
2419
+ provider: { id: "cursor", displayName: "Cursor" },
2420
+ billingDomain: { id: "cursor-subscription", displayName: "Cursor subscription" }
2421
+ },
2422
+ officialCredentialPaths: [".cursor"]
2404
2423
  }
2405
2424
  ];
2406
2425
  }
@@ -2413,6 +2432,12 @@ function clampPercent(value) {
2413
2432
  }
2414
2433
  return Math.min(100, Math.max(0, value));
2415
2434
  }
2435
+ function percentFromUsedAndLimit(usedAmount, limitAmount) {
2436
+ if (usedAmount === null || usedAmount === void 0 || limitAmount === null || limitAmount === void 0 || !Number.isFinite(usedAmount) || !Number.isFinite(limitAmount) || limitAmount <= 0) {
2437
+ return null;
2438
+ }
2439
+ return clampPercent(usedAmount / limitAmount * 100);
2440
+ }
2416
2441
  var init_quota_normalization = __esm({
2417
2442
  "src/core/quota-normalization.ts"() {
2418
2443
  "use strict";
@@ -4009,7 +4034,28 @@ function isGrokOfficialModel(model) {
4009
4034
  }
4010
4035
  return false;
4011
4036
  }
4012
- function resolveGrokBillingDomain(model, customEndpoints) {
4037
+ function grokModelFamilyKey(model) {
4038
+ if (!model) return null;
4039
+ let normalized = model.trim().toLowerCase();
4040
+ if (!normalized) return null;
4041
+ if (normalized === "grk" || normalized.startsWith("grk-") || normalized.startsWith("grk/")) {
4042
+ normalized = `grok${normalized.slice(3)}`;
4043
+ }
4044
+ for (; ; ) {
4045
+ const stripped = normalized.replace(/-(high|medium|low|xhigh|build|latest)$/, "");
4046
+ if (stripped === normalized) return normalized;
4047
+ normalized = stripped;
4048
+ }
4049
+ }
4050
+ function resolveGrokBillingDomain(model, customEndpoints, selectedModel) {
4051
+ const selectedKey = selectedModel?.trim().toLowerCase() ?? "";
4052
+ if (selectedKey && customEndpoints?.has(selectedKey)) {
4053
+ const usageFamily = grokModelFamilyKey(model);
4054
+ const selectedFamily = grokModelFamilyKey(selectedModel);
4055
+ if (usageFamily && selectedFamily && usageFamily === selectedFamily) {
4056
+ return customEndpoints.get(selectedKey);
4057
+ }
4058
+ }
4013
4059
  if (!model) return "grok-build-subscription";
4014
4060
  const normalized = model.trim().toLowerCase();
4015
4061
  if (customEndpoints?.has(normalized)) {
@@ -4312,7 +4358,7 @@ function isParsedTranscriptRecord(value) {
4312
4358
  ];
4313
4359
  const cacheWriteTokenBreakdown = asObject(observation.cacheWriteTokenBreakdown);
4314
4360
  const tokenSemantics = asObject(observation.tokenSemantics);
4315
- const structurallyValid = typeof record.dedupeKey === "string" && (record.reportedCostUsd === null || finiteNonNegative(record.reportedCostUsd) !== null) && typeof observation.id === "string" && typeof observation.billingDomainId === "string" && (observation.model === null || typeof observation.model === "string") && (observation.sessionId === void 0 || observation.sessionId === null || typeof observation.sessionId === "string") && typeof observation.observedAt === "string" && Number.isFinite(Date.parse(observation.observedAt)) && requiredTokenFields.every((field) => nonNegativeSafeInteger(observation[field])) && optionalTokenFields.every(
4361
+ const structurallyValid = typeof record.dedupeKey === "string" && (record.grokSelectedModel === void 0 || record.grokSelectedModel === null || typeof record.grokSelectedModel === "string") && (record.reportedCostUsd === null || finiteNonNegative(record.reportedCostUsd) !== null) && typeof observation.id === "string" && typeof observation.billingDomainId === "string" && (observation.model === null || typeof observation.model === "string") && (observation.sessionId === void 0 || observation.sessionId === null || typeof observation.sessionId === "string") && typeof observation.observedAt === "string" && Number.isFinite(Date.parse(observation.observedAt)) && requiredTokenFields.every((field) => nonNegativeSafeInteger(observation[field])) && optionalTokenFields.every(
4316
4362
  (field) => observation[field] === void 0 || observation[field] === null || nonNegativeSafeInteger(observation[field])
4317
4363
  ) && (observation.cacheWriteTokenBreakdown === void 0 || observation.cacheWriteTokenBreakdown === null || cacheWriteTokenBreakdown !== null && nonNegativeSafeInteger(cacheWriteTokenBreakdown.fiveMinute) && nonNegativeSafeInteger(cacheWriteTokenBreakdown.oneHour)) && (observation.tokenSemantics === void 0 || tokenSemantics !== null && ["included-in-output", "separate"].includes(String(tokenSemantics.reasoning)) && ["included-in-input", "separate"].includes(String(tokenSemantics.cacheRead)) && ["included-in-input", "separate"].includes(String(tokenSemantics.cacheWrite))) && (observation.modelAttribution === void 0 || ["known", "unclassified"].includes(String(observation.modelAttribution))) && (observation.timePrecision === void 0 || ["event", "hour", "day", "billing-period", "unknown"].includes(
4318
4364
  String(observation.timePrecision)
@@ -4330,12 +4376,19 @@ function isParsedTranscriptRecord(value) {
4330
4376
  function nonNegativeSafeInteger(value) {
4331
4377
  return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
4332
4378
  }
4333
- function parseGrokTranscriptLine(line, grokCustomModels) {
4379
+ function grokSelectedModelFromUpdate(update) {
4380
+ const meta = asObject(update._meta);
4381
+ return string(update.model) ?? string(meta?.modelId);
4382
+ }
4383
+ function parseGrokTranscriptLine(line, grokCustomModels, grokState) {
4334
4384
  const record = parseObject(line);
4335
4385
  const params = asObject(record?.params);
4336
4386
  const update = asObject(params?.update);
4387
+ if (!record || !params || !update) return [];
4388
+ const selected = grokSelectedModelFromUpdate(update);
4389
+ if (selected) grokState.selectedModel = selected;
4337
4390
  const usage = asObject(update?.usage);
4338
- if (!record || !params || !update || !usage || update.sessionUpdate !== "turn_completed") {
4391
+ if (!usage || update.sessionUpdate !== "turn_completed") {
4339
4392
  return [];
4340
4393
  }
4341
4394
  const meta = asObject(params._meta);
@@ -4374,9 +4427,14 @@ function parseGrokTranscriptLine(line, grokCustomModels) {
4374
4427
  const dedupeKey = `${sessionId}:${promptId ?? stableId(line)}:${model}`;
4375
4428
  const directCost = grokCostUsd(totals.costUsdTicks);
4376
4429
  const reportedCostUsd = directCost ?? (remainingCost !== null && untickedTokens > 0 ? remainingCost * (grokRecordedTokens(totals) / untickedTokens) : null);
4377
- const billingDomainId = resolveGrokBillingDomain(model, grokCustomModels);
4430
+ const billingDomainId = resolveGrokBillingDomain(
4431
+ model,
4432
+ grokCustomModels,
4433
+ grokState.selectedModel
4434
+ );
4378
4435
  return {
4379
4436
  dedupeKey,
4437
+ grokSelectedModel: grokState.selectedModel,
4380
4438
  observation: {
4381
4439
  id: `grok-transcript:${stableId(dedupeKey)}`,
4382
4440
  billingDomainId,
@@ -4507,8 +4565,8 @@ function isForkedCodexSession(payload) {
4507
4565
  if (string(payload.forked_from_id)) return true;
4508
4566
  const source = asObject(payload.source);
4509
4567
  const subagent = asObject(source?.subagent);
4510
- const spawn7 = asObject(subagent?.thread_spawn);
4511
- return string(spawn7?.parent_thread_id) !== null;
4568
+ const spawn9 = asObject(subagent?.thread_spawn);
4569
+ return string(spawn9?.parent_thread_id) !== null;
4512
4570
  }
4513
4571
  async function listTranscriptFiles(roots, cutoff) {
4514
4572
  const files = [];
@@ -4699,7 +4757,7 @@ function compact(value) {
4699
4757
  function stableId(value) {
4700
4758
  return createHash2("sha256").update(value).digest("hex").slice(0, 24);
4701
4759
  }
4702
- var DSH_PRIMARY_BILLING_DOMAIN_ID, DSH_SESSION_FORMAT_VERSION, DSH_COMPRESSED_SUFFIX, DSH_LINE_HINTS, LocalTranscriptUsageClient;
4760
+ var DSH_PRIMARY_BILLING_DOMAIN_ID, DSH_SESSION_FORMAT_VERSION, DSH_COMPRESSED_SUFFIX, DSH_LINE_HINTS, TRANSCRIPT_CACHE_VERSION, LocalTranscriptUsageClient;
4703
4761
  var init_local_transcript_usage_client = __esm({
4704
4762
  "src/server/local-transcript-usage-client.ts"() {
4705
4763
  "use strict";
@@ -4710,6 +4768,7 @@ var init_local_transcript_usage_client = __esm({
4710
4768
  DSH_SESSION_FORMAT_VERSION = 0;
4711
4769
  DSH_COMPRESSED_SUFFIX = ".jsonl.zstd";
4712
4770
  DSH_LINE_HINTS = ['"usage"', '"request/context"', '"type":"session"'];
4771
+ TRANSCRIPT_CACHE_VERSION = 2;
4713
4772
  LocalTranscriptUsageClient = class {
4714
4773
  #provider;
4715
4774
  #roots;
@@ -4792,7 +4851,8 @@ var init_local_transcript_usage_client = __esm({
4792
4851
  const remapped = cached.records.map((r) => {
4793
4852
  const expectedDomain = resolveGrokBillingDomain(
4794
4853
  r.observation.model,
4795
- this.#grokCustomModels
4854
+ this.#grokCustomModels,
4855
+ r.grokSelectedModel
4796
4856
  );
4797
4857
  if (r.observation.billingDomainId !== expectedDomain) {
4798
4858
  return {
@@ -4821,9 +4881,10 @@ var init_local_transcript_usage_client = __esm({
4821
4881
  model: "",
4822
4882
  unsupportedVersion: false
4823
4883
  };
4884
+ const grokState = { selectedModel: null };
4824
4885
  try {
4825
4886
  for await (const line of readTranscriptLines(file.path)) {
4826
- records.push(...this.#parseLine(line, codexState, dshState));
4887
+ records.push(...this.#parseLine(line, codexState, dshState, grokState));
4827
4888
  if (dshState.unsupportedVersion) {
4828
4889
  return { records: [], complete: false, unsupportedFormat: true };
4829
4890
  }
@@ -4839,7 +4900,7 @@ var init_local_transcript_usage_client = __esm({
4839
4900
  });
4840
4901
  return { records, complete: true, unsupportedFormat: false };
4841
4902
  }
4842
- #parseLine(line, codexState, dshState) {
4903
+ #parseLine(line, codexState, dshState, grokState) {
4843
4904
  if (this.#provider === "claude-code") {
4844
4905
  return line.includes('"usage"') ? compact(parseClaudeTranscriptLine(line)) : [];
4845
4906
  }
@@ -4847,7 +4908,10 @@ var init_local_transcript_usage_client = __esm({
4847
4908
  if (this.#provider === "dsh") {
4848
4909
  return DSH_LINE_HINTS.some((hint) => line.includes(hint)) ? parseDshTranscriptLine(line, dshState) : [];
4849
4910
  }
4850
- return line.includes('"turn_completed"') ? parseGrokTranscriptLine(line, this.#grokCustomModels) : [];
4911
+ if (line.includes('"turn_completed"') || line.includes('"modelId"') || line.includes('"current_mode_update"')) {
4912
+ return parseGrokTranscriptLine(line, this.#grokCustomModels, grokState);
4913
+ }
4914
+ return [];
4851
4915
  }
4852
4916
  async #loadCache() {
4853
4917
  if (this.#cacheLoaded) return;
@@ -4855,7 +4919,7 @@ var init_local_transcript_usage_client = __esm({
4855
4919
  if (!this.#cachePath) return;
4856
4920
  try {
4857
4921
  const stored = JSON.parse(await readFile3(this.#cachePath, "utf8"));
4858
- if (stored.version !== 1 || !Array.isArray(stored.files)) return;
4922
+ if (stored.version !== TRANSCRIPT_CACHE_VERSION || !Array.isArray(stored.files)) return;
4859
4923
  for (const file of stored.files) {
4860
4924
  if (!isCachedTranscriptFile(file)) continue;
4861
4925
  if (file.recordsDigest !== stableId(JSON.stringify(file.records))) continue;
@@ -4871,7 +4935,10 @@ var init_local_transcript_usage_client = __esm({
4871
4935
  const temporary = `${this.#cachePath}.${process.pid}.tmp`;
4872
4936
  await writeFile2(
4873
4937
  temporary,
4874
- JSON.stringify({ version: 1, files: [...this.#fileCache.values()] }),
4938
+ JSON.stringify({
4939
+ version: TRANSCRIPT_CACHE_VERSION,
4940
+ files: [...this.#fileCache.values()]
4941
+ }),
4875
4942
  { mode: 384 }
4876
4943
  );
4877
4944
  await rename2(temporary, this.#cachePath);
@@ -5269,11 +5336,473 @@ var init_antigravity_connector = __esm({
5269
5336
  }
5270
5337
  });
5271
5338
 
5339
+ // src/connectors/cursor/cursor-about-client.ts
5340
+ import { spawn as spawn3 } from "child_process";
5341
+ function runCaptured(command, arguments_, options) {
5342
+ return new Promise((resolve5, reject) => {
5343
+ const child = spawn3(command, arguments_, {
5344
+ env: options.env,
5345
+ stdio: ["ignore", "pipe", "pipe"]
5346
+ });
5347
+ let stdout = "";
5348
+ const timer = setTimeout(() => {
5349
+ child.kill();
5350
+ reject(new Error("agent about timed out"));
5351
+ }, options.timeoutMs);
5352
+ child.stdout.setEncoding("utf8");
5353
+ child.stdout.on("data", (chunk) => {
5354
+ stdout += chunk;
5355
+ });
5356
+ child.once("error", (error) => {
5357
+ clearTimeout(timer);
5358
+ reject(error);
5359
+ });
5360
+ child.once("exit", (code) => {
5361
+ clearTimeout(timer);
5362
+ if (code === 0) resolve5(stdout);
5363
+ else reject(new Error(`agent about exited ${String(code)}`));
5364
+ });
5365
+ });
5366
+ }
5367
+ var CursorAboutAccountClient;
5368
+ var init_cursor_about_client = __esm({
5369
+ "src/connectors/cursor/cursor-about-client.ts"() {
5370
+ "use strict";
5371
+ CursorAboutAccountClient = class {
5372
+ #command;
5373
+ #timeoutMs;
5374
+ #environment;
5375
+ #runCommand;
5376
+ constructor(options = {}) {
5377
+ this.#command = options.command ?? "agent";
5378
+ this.#timeoutMs = options.timeoutMs ?? 8e3;
5379
+ this.#environment = {
5380
+ ...options.environment ?? process.env,
5381
+ LC_ALL: "en_US.UTF-8",
5382
+ LANG: "en_US.UTF-8"
5383
+ };
5384
+ this.#runCommand = options.runCommand ?? runCaptured;
5385
+ }
5386
+ async readAccountIdentifier() {
5387
+ if (!/^[a-zA-Z0-9_./-]+$/.test(this.#command)) return null;
5388
+ try {
5389
+ const stdout = await this.#runCommand(this.#command, ["about", "--format", "json"], {
5390
+ env: this.#environment,
5391
+ timeoutMs: this.#timeoutMs
5392
+ });
5393
+ const parsed = JSON.parse(stdout);
5394
+ return typeof parsed.userEmail === "string" && parsed.userEmail.trim() ? parsed.userEmail.trim() : null;
5395
+ } catch {
5396
+ return null;
5397
+ }
5398
+ }
5399
+ };
5400
+ }
5401
+ });
5402
+
5403
+ // src/connectors/cursor/cursor-connector.ts
5404
+ function mapUsage(usage, observedAt) {
5405
+ if (usage.kind === "unmetered") return [];
5406
+ const buckets = [
5407
+ {
5408
+ id: "included",
5409
+ billingDomainId: CURSOR_BILLING_DOMAIN_ID,
5410
+ label: "Included",
5411
+ usedPercent: clampPercent(usage.included.usedPercent),
5412
+ resetsAt: null,
5413
+ resetLabel: usage.resetLabel,
5414
+ authority: "official-client",
5415
+ observedAt,
5416
+ scope: "account-wide"
5417
+ }
5418
+ ];
5419
+ if (usage.onDemand?.kind === "fixed") {
5420
+ buckets.push({
5421
+ id: "on-demand",
5422
+ billingDomainId: CURSOR_BILLING_DOMAIN_ID,
5423
+ label: "On-Demand",
5424
+ usedPercent: usage.onDemand.usedPercent,
5425
+ usedAmount: usage.onDemand.usedAmount,
5426
+ limitAmount: usage.onDemand.limitAmount,
5427
+ limitCurrency: usage.onDemand.currency,
5428
+ resetsAt: null,
5429
+ resetLabel: usage.resetLabel,
5430
+ authority: "official-client",
5431
+ observedAt,
5432
+ scope: "account-wide",
5433
+ fallbackStatus: "enabled"
5434
+ });
5435
+ } else if (usage.onDemand?.kind === "unlimited") {
5436
+ buckets.push({
5437
+ id: "on-demand",
5438
+ billingDomainId: CURSOR_BILLING_DOMAIN_ID,
5439
+ label: "On-Demand",
5440
+ usedPercent: null,
5441
+ usedAmount: usage.onDemand.usedAmount,
5442
+ limitCurrency: usage.onDemand.currency,
5443
+ resetsAt: null,
5444
+ resetLabel: usage.resetLabel,
5445
+ authority: "official-client",
5446
+ observedAt,
5447
+ scope: "account-wide",
5448
+ fallbackStatus: "enabled"
5449
+ });
5450
+ } else if (usage.onDemand?.kind === "disabled") {
5451
+ buckets.push({
5452
+ id: "on-demand",
5453
+ billingDomainId: CURSOR_BILLING_DOMAIN_ID,
5454
+ label: "On-Demand",
5455
+ usedPercent: null,
5456
+ resetsAt: null,
5457
+ resetLabel: usage.resetLabel,
5458
+ authority: "official-client",
5459
+ observedAt,
5460
+ scope: "account-wide",
5461
+ fallbackStatus: "disabled"
5462
+ });
5463
+ }
5464
+ return buckets;
5465
+ }
5466
+ function safeFailure8(error) {
5467
+ if (error instanceof Error && "code" in error && typeof error.code === "string" && "recovery" in error && typeof error.recovery === "string") {
5468
+ return { code: error.code, message: error.message, recovery: error.recovery };
5469
+ }
5470
+ return {
5471
+ code: "cursor-quota-adapter-failed",
5472
+ message: "Cursor subscription quota is unavailable.",
5473
+ recovery: "Open agent, run /usage, then retry."
5474
+ };
5475
+ }
5476
+ var CURSOR_BILLING_DOMAIN_ID, CURSOR_BILLING_DOMAIN_NAME, CursorConnector;
5477
+ var init_cursor_connector = __esm({
5478
+ "src/connectors/cursor/cursor-connector.ts"() {
5479
+ "use strict";
5480
+ init_quota_normalization();
5481
+ CURSOR_BILLING_DOMAIN_ID = "cursor-subscription";
5482
+ CURSOR_BILLING_DOMAIN_NAME = "Cursor subscription";
5483
+ CursorConnector = class {
5484
+ id = "cursor";
5485
+ displayName = "Cursor";
5486
+ consentId = "cursor";
5487
+ #quotaClient;
5488
+ #accountClient;
5489
+ #clock;
5490
+ constructor(options) {
5491
+ this.#quotaClient = options.quotaClient;
5492
+ this.#accountClient = options.accountClient;
5493
+ this.#clock = options.clock ?? (() => /* @__PURE__ */ new Date());
5494
+ }
5495
+ async collect() {
5496
+ const observedAt = this.#clock().toISOString();
5497
+ const warnings = [];
5498
+ let quotaBuckets = [];
5499
+ let completeQuotaBillingDomainIds;
5500
+ try {
5501
+ const usage = await this.#quotaClient.readUsage();
5502
+ completeQuotaBillingDomainIds = [CURSOR_BILLING_DOMAIN_ID];
5503
+ quotaBuckets = mapUsage(usage, observedAt);
5504
+ } catch (error) {
5505
+ warnings.push(safeFailure8(error));
5506
+ }
5507
+ let accountIdentifier = null;
5508
+ if (this.#accountClient) {
5509
+ try {
5510
+ accountIdentifier = await this.#accountClient.readAccountIdentifier();
5511
+ } catch {
5512
+ accountIdentifier = null;
5513
+ }
5514
+ }
5515
+ return {
5516
+ provider: {
5517
+ id: this.id,
5518
+ displayName: this.displayName,
5519
+ accountIdentifier
5520
+ },
5521
+ billingDomains: [{ id: CURSOR_BILLING_DOMAIN_ID, displayName: CURSOR_BILLING_DOMAIN_NAME }],
5522
+ quotaBuckets,
5523
+ completeQuotaBillingDomainIds,
5524
+ usage: [],
5525
+ costs: [],
5526
+ warnings,
5527
+ observedAt
5528
+ };
5529
+ }
5530
+ };
5531
+ }
5532
+ });
5533
+
5534
+ // src/connectors/cursor/cursor-usage-screen-client.ts
5535
+ import { spawn as spawn4 } from "child_process";
5536
+ import { mkdtemp, rm, writeFile as writeFile3 } from "fs/promises";
5537
+ import { tmpdir } from "os";
5538
+ import { join as join5 } from "path";
5539
+ function parseCursorUsageScreen(text) {
5540
+ const normalized = collapseVerticalLetters(stripTerminalControls2(text));
5541
+ const lines = normalized.split(/\r?\n/).map((line) => collapseSpaces(line)).filter(Boolean);
5542
+ const body = `${lines.join("\n")}
5543
+ ${collapseSpaces(normalized)}`;
5544
+ if (NOT_LOGGED_IN.test(body)) {
5545
+ throw new CursorUsageAdapterError(
5546
+ "cursor-not-logged-in",
5547
+ "Cursor Agent CLI is not signed in.",
5548
+ "Run agent login, then retry."
5549
+ );
5550
+ }
5551
+ if (UNMETERED_PLAN.test(body) || SPEND_CHART.test(body)) {
5552
+ return { kind: "unmetered" };
5553
+ }
5554
+ const included = findIncludedPercent(lines);
5555
+ if (included === null) {
5556
+ if (STANDARD_TABLE.test(body) || UNMETERED_PLAN.test(body) || SPEND_CHART.test(body)) {
5557
+ return { kind: "unmetered" };
5558
+ }
5559
+ throw new CursorUsageAdapterError(
5560
+ "cursor-usage-unparsed",
5561
+ "Cursor /usage did not print Included usage.",
5562
+ "Open agent, run /usage, then retry after updating Cursor Agent CLI."
5563
+ );
5564
+ }
5565
+ return {
5566
+ kind: "meters",
5567
+ included: { usedPercent: included },
5568
+ onDemand: parseOnDemand(lines),
5569
+ resetLabel: lines.find((line) => RESET_LINE.test(line)) ?? null
5570
+ };
5571
+ }
5572
+ function findIncludedPercent(lines) {
5573
+ for (const line of lines) {
5574
+ const compact2 = line.match(/^Included:\s*(\d+(?:\.\d+)?)%\s+used/i);
5575
+ if (compact2) return clampPercent(Number(compact2[1]));
5576
+ const table = line.match(/^Included\s+(\d+(?:\.\d+)?)%\s+used/i);
5577
+ if (table) return clampPercent(Number(table[1]));
5578
+ }
5579
+ return null;
5580
+ }
5581
+ function parseOnDemand(lines) {
5582
+ const joined = lines.join("\n");
5583
+ if (/On-demand usage is off/i.test(joined) || /On-Demand:\s*Disabled/i.test(joined)) {
5584
+ return { kind: "disabled" };
5585
+ }
5586
+ if (/On-demand limit unavailable/i.test(joined)) {
5587
+ return null;
5588
+ }
5589
+ for (const line of lines) {
5590
+ const pair = line.match(/On-Demand[:\s]+(\$[\d,]+(?:\.\d+)?)\s*\/\s*(\$[\d,]+(?:\.\d+)?)/i) ?? line.match(/^On-Demand\s+(\$[\d,]+(?:\.\d+)?)\s*\/\s*(\$[\d,]+(?:\.\d+)?)/i);
5591
+ if (pair) {
5592
+ const usedAmount = parseUsd(pair[1]);
5593
+ const limitAmount = parseUsd(pair[2]);
5594
+ const usedPercent = percentFromUsedAndLimit(usedAmount, limitAmount);
5595
+ if (usedAmount === null || limitAmount === null || usedPercent === null) continue;
5596
+ return { kind: "fixed", usedAmount, limitAmount, currency: "USD", usedPercent };
5597
+ }
5598
+ const unlimited = line.match(/On-Demand[:\s]+(\$[\d,]+(?:\.\d+)?)(?:\s*$)/i);
5599
+ if (unlimited && /No monthly limit|No personal limit/i.test(joined)) {
5600
+ const usedAmount = parseUsd(unlimited[1]);
5601
+ if (usedAmount === null) continue;
5602
+ return { kind: "unlimited", usedAmount, currency: "USD" };
5603
+ }
5604
+ }
5605
+ return null;
5606
+ }
5607
+ function parseUsd(value) {
5608
+ const amount = Number(value.replace(/[$,]/g, ""));
5609
+ return Number.isFinite(amount) ? amount : null;
5610
+ }
5611
+ function collapseSpaces(line) {
5612
+ return line.replace(/\s+/g, " ").trim();
5613
+ }
5614
+ function collapseVerticalLetters(text) {
5615
+ const lines = text.split(/\r?\n/);
5616
+ const collapsed = [];
5617
+ let run = "";
5618
+ for (const line of lines) {
5619
+ const trimmed = line.trim();
5620
+ if (trimmed.length === 1 && /[\w%$.:/-]/.test(trimmed)) {
5621
+ run += trimmed;
5622
+ continue;
5623
+ }
5624
+ if (run) {
5625
+ collapsed.push(run);
5626
+ run = "";
5627
+ }
5628
+ collapsed.push(line);
5629
+ }
5630
+ if (run) collapsed.push(run);
5631
+ return collapsed.join("\n");
5632
+ }
5633
+ function stripTerminalControls2(value) {
5634
+ return value.replace(/\u001B\][^\u0007]*(?:\u0007|\u001B\\)/g, "").replace(/\u001B\[[0-?]*[ -/]*[@-~]/g, "").replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F]/g, "");
5635
+ }
5636
+ function cursorUsageEnvironment(environment) {
5637
+ return {
5638
+ ...environment,
5639
+ LC_ALL: "en_US.UTF-8",
5640
+ LANG: "en_US.UTF-8",
5641
+ INK_SCREEN_READER: "true"
5642
+ };
5643
+ }
5644
+ async function runCursorUsagePtySession(session) {
5645
+ const driver = join5(session.cwd, "run-cursor-usage-pty.py");
5646
+ await writeFile3(driver, CURSOR_USAGE_PTY_DRIVER, { mode: 448 });
5647
+ return new Promise((resolve5, reject) => {
5648
+ const child = spawn4("python3", [driver, session.command], {
5649
+ cwd: session.cwd,
5650
+ env: {
5651
+ ...session.env,
5652
+ TERM: session.env.TERM ?? "xterm-256color",
5653
+ COLUMNS: "120",
5654
+ LINES: "40"
5655
+ },
5656
+ stdio: ["ignore", "pipe", "pipe"]
5657
+ });
5658
+ let output = "";
5659
+ let stderr = "";
5660
+ const timer = setTimeout(() => {
5661
+ child.kill();
5662
+ reject(
5663
+ new CursorUsageAdapterError(
5664
+ "cursor-usage-timeout",
5665
+ "Cursor Agent CLI did not return the usage screen in time.",
5666
+ "Open agent, run /usage, then retry."
5667
+ )
5668
+ );
5669
+ }, session.timeoutMs);
5670
+ child.stdout.setEncoding("utf8");
5671
+ child.stdout.on("data", (chunk) => {
5672
+ output += chunk;
5673
+ });
5674
+ child.stderr.setEncoding("utf8");
5675
+ child.stderr.on("data", (chunk) => {
5676
+ stderr += chunk;
5677
+ });
5678
+ child.once("error", (error) => {
5679
+ clearTimeout(timer);
5680
+ reject(error);
5681
+ });
5682
+ child.once("exit", (code) => {
5683
+ clearTimeout(timer);
5684
+ if (output.trim()) resolve5(output);
5685
+ else reject(new Error(stderr.trim() || `Cursor usage driver exited ${String(code)}`));
5686
+ });
5687
+ });
5688
+ }
5689
+ function unavailableError3(cause) {
5690
+ return new CursorUsageAdapterError(
5691
+ "cursor-quota-adapter-failed",
5692
+ "Cursor subscription quota is unavailable.",
5693
+ "Open agent, run /usage, then retry.",
5694
+ cause instanceof Error ? { cause } : void 0
5695
+ );
5696
+ }
5697
+ var CursorUsageAdapterError, NOT_LOGGED_IN, UNMETERED_PLAN, SPEND_CHART, STANDARD_TABLE, RESET_LINE, ScreenReaderCursorQuotaClient, CURSOR_USAGE_PTY_DRIVER;
5698
+ var init_cursor_usage_screen_client = __esm({
5699
+ "src/connectors/cursor/cursor-usage-screen-client.ts"() {
5700
+ "use strict";
5701
+ init_quota_normalization();
5702
+ CursorUsageAdapterError = class extends Error {
5703
+ code;
5704
+ recovery;
5705
+ constructor(code, message, recovery, options) {
5706
+ super(message, options);
5707
+ this.name = "CursorUsageAdapterError";
5708
+ this.code = code;
5709
+ this.recovery = recovery;
5710
+ }
5711
+ };
5712
+ NOT_LOGGED_IN = /Not logged in\. Run \/login first/i;
5713
+ UNMETERED_PLAN = /Usage details are not available for this plan in the CLI/i;
5714
+ SPEND_CHART = /Personal spend for the current billing period/i;
5715
+ STANDARD_TABLE = /Monthly plan and on-demand usage/i;
5716
+ RESET_LINE = /^(Resets\s+.+)$/i;
5717
+ ScreenReaderCursorQuotaClient = class {
5718
+ #command;
5719
+ #timeoutMs;
5720
+ #environment;
5721
+ #runSession;
5722
+ constructor(options = {}) {
5723
+ this.#command = options.command ?? "agent";
5724
+ this.#timeoutMs = options.timeoutMs ?? 24e3;
5725
+ this.#environment = cursorUsageEnvironment(options.environment ?? process.env);
5726
+ this.#runSession = options.runSession ?? runCursorUsagePtySession;
5727
+ }
5728
+ async readUsage() {
5729
+ if (!/^[a-zA-Z0-9_./-]+$/.test(this.#command)) {
5730
+ throw unavailableError3(new Error("Unsafe Cursor command path"));
5731
+ }
5732
+ const cwd = await mkdtemp(join5(tmpdir(), "agent-usage-cursor-"));
5733
+ try {
5734
+ const output = await this.#runSession({
5735
+ command: this.#command,
5736
+ cwd,
5737
+ env: this.#environment,
5738
+ timeoutMs: this.#timeoutMs
5739
+ });
5740
+ if (NOT_LOGGED_IN.test(output)) {
5741
+ throw new CursorUsageAdapterError(
5742
+ "cursor-not-logged-in",
5743
+ "Cursor Agent CLI is not signed in.",
5744
+ "Run agent login, then retry."
5745
+ );
5746
+ }
5747
+ return parseCursorUsageScreen(output);
5748
+ } catch (error) {
5749
+ if (error instanceof CursorUsageAdapterError) throw error;
5750
+ throw unavailableError3(error);
5751
+ } finally {
5752
+ await rm(cwd, { recursive: true, force: true });
5753
+ }
5754
+ }
5755
+ };
5756
+ CURSOR_USAGE_PTY_DRIVER = `#!/usr/bin/env python3
5757
+ import os, pty, select, sys, time
5758
+ def collect(fd, seconds):
5759
+ data = b""
5760
+ deadline = time.time() + seconds
5761
+ while time.time() < deadline:
5762
+ ready, _, _ = select.select([fd], [], [], max(0.0, deadline - time.time()))
5763
+ if not ready:
5764
+ continue
5765
+ try:
5766
+ chunk = os.read(fd, 8192)
5767
+ except OSError:
5768
+ break
5769
+ if not chunk:
5770
+ break
5771
+ data += chunk
5772
+ return data
5773
+ def write_keys(fd, payload):
5774
+ try:
5775
+ os.write(fd, payload)
5776
+ return True
5777
+ except OSError:
5778
+ return False
5779
+ command = sys.argv[1]
5780
+ pid, fd = pty.fork()
5781
+ if pid == 0:
5782
+ os.execvp(command, [command, "--trust", "--mode", "ask"])
5783
+ captured = collect(fd, 2.5)
5784
+ if write_keys(fd, b"/"):
5785
+ captured += collect(fd, 0.6)
5786
+ if write_keys(fd, b"usage"):
5787
+ captured += collect(fd, 1.6)
5788
+ if write_keys(fd, bytes([13])):
5789
+ captured += collect(fd, 10.0)
5790
+ if write_keys(fd, bytes([27])):
5791
+ captured += collect(fd, 0.5)
5792
+ try:
5793
+ os.kill(pid, 9)
5794
+ except OSError:
5795
+ pass
5796
+ sys.stdout.buffer.write(captured)
5797
+ `;
5798
+ }
5799
+ });
5800
+
5272
5801
  // src/server/antigravity-sqlite-usage-client.ts
5273
5802
  import { createHash as createHash3 } from "crypto";
5274
- import { readdir, readFile as readFile4, rename as rename3, stat as stat2, writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
5803
+ import { readdir, readFile as readFile4, rename as rename3, stat as stat2, writeFile as writeFile4, mkdir as mkdir3 } from "fs/promises";
5275
5804
  import { createRequire as createRequire2 } from "module";
5276
- import { dirname as dirname2, join as join5 } from "path";
5805
+ import { dirname as dirname2, join as join6 } from "path";
5277
5806
  import protobuf from "protobufjs";
5278
5807
  function parseAntigravityDatabase(dbPath, conversationId, fallbackMtimeMs) {
5279
5808
  const db = new DatabaseSync2(dbPath, { readOnly: true });
@@ -5547,7 +6076,7 @@ var init_antigravity_sqlite_usage_client = __esm({
5547
6076
  } catch {
5548
6077
  continue;
5549
6078
  }
5550
- const summariesPath = join5(root, "conversation_summaries.db");
6079
+ const summariesPath = join6(root, "conversation_summaries.db");
5551
6080
  const candidateIds = /* @__PURE__ */ new Set();
5552
6081
  let summariesLoaded = false;
5553
6082
  try {
@@ -5570,7 +6099,7 @@ var init_antigravity_sqlite_usage_client = __esm({
5570
6099
  }
5571
6100
  } catch {
5572
6101
  }
5573
- const convDir = join5(root, "conversations");
6102
+ const convDir = join6(root, "conversations");
5574
6103
  try {
5575
6104
  const entries = await readdir(convDir);
5576
6105
  for (const entry of entries) {
@@ -5579,7 +6108,7 @@ var init_antigravity_sqlite_usage_client = __esm({
5579
6108
  if (summariesLoaded && candidateIds.size > 0 && !candidateIds.has(convId)) {
5580
6109
  continue;
5581
6110
  }
5582
- const fullPath = join5(convDir, entry);
6111
+ const fullPath = join6(convDir, entry);
5583
6112
  if (seenDbPaths.has(fullPath)) continue;
5584
6113
  seenDbPaths.add(fullPath);
5585
6114
  try {
@@ -5640,7 +6169,7 @@ var init_antigravity_sqlite_usage_client = __esm({
5640
6169
  try {
5641
6170
  await mkdir3(dirname2(this.#cachePath), { recursive: true, mode: 448 });
5642
6171
  const temporary = `${this.#cachePath}.${process.pid}.tmp`;
5643
- await writeFile3(
6172
+ await writeFile4(
5644
6173
  temporary,
5645
6174
  JSON.stringify({ version: 1, files: [...this.#fileCache.values()] }),
5646
6175
  { mode: 384 }
@@ -5768,10 +6297,10 @@ var init_grok_telemetry = __esm({
5768
6297
  });
5769
6298
 
5770
6299
  // src/connectors/grok-build/stdio-grok-billing-client.ts
5771
- import { spawn as spawn3 } from "child_process";
6300
+ import { spawn as spawn5 } from "child_process";
5772
6301
  import { open } from "fs/promises";
5773
6302
  import { homedir as homedir3 } from "os";
5774
- import { join as join6 } from "path";
6303
+ import { join as join7 } from "path";
5775
6304
  import { z as z7 } from "zod";
5776
6305
  function billingIsFresh(billing, now) {
5777
6306
  if (!billing.sourceObservedAt) return false;
@@ -5792,7 +6321,7 @@ async function refreshBillingLogViaDashboard(command, timeoutMs) {
5792
6321
  "expect eof"
5793
6322
  ].join("\n");
5794
6323
  await new Promise((resolve5) => {
5795
- const dashboard = spawn3("/usr/bin/expect", ["-c", expectScript2], {
6324
+ const dashboard = spawn5("/usr/bin/expect", ["-c", expectScript2], {
5796
6325
  env: {
5797
6326
  ...process.env,
5798
6327
  AGENT_USAGE_GROK_REFRESH_COMMAND: command,
@@ -5859,7 +6388,7 @@ async function readLogTail(path) {
5859
6388
  await handle.close();
5860
6389
  }
5861
6390
  }
5862
- function unavailableError3(cause) {
6391
+ function unavailableError4(cause) {
5863
6392
  return new GrokBillingAdapterError(
5864
6393
  "grok-client-unavailable",
5865
6394
  "Grok Build billing capability is unavailable.",
@@ -5892,11 +6421,11 @@ var init_stdio_grok_billing_client = __esm({
5892
6421
  constructor(options = {}) {
5893
6422
  this.#command = options.command ?? "grok";
5894
6423
  this.#timeoutMs = options.timeoutMs ?? 8e3;
5895
- this.#spawnProcess = options.spawnProcess ?? ((command, arguments_) => spawn3(command, arguments_, {
6424
+ this.#spawnProcess = options.spawnProcess ?? ((command, arguments_) => spawn5(command, arguments_, {
5896
6425
  stdio: ["pipe", "pipe", "pipe"]
5897
6426
  }));
5898
6427
  this.#readUnifiedLog = options.readUnifiedLog ?? (() => readLogTail(
5899
- join6(process.env.GROK_HOME ?? join6(homedir3(), ".grok"), "logs", "unified.jsonl")
6428
+ join7(process.env.GROK_HOME ?? join7(homedir3(), ".grok"), "logs", "unified.jsonl")
5900
6429
  ));
5901
6430
  this.#refreshBillingLog = options.refreshBillingLog ?? (options.readUnifiedLog ? async () => void 0 : () => refreshBillingLogViaDashboard(this.#command, this.#timeoutMs));
5902
6431
  this.#clock = options.clock ?? (() => /* @__PURE__ */ new Date());
@@ -5908,7 +6437,7 @@ var init_stdio_grok_billing_client = __esm({
5908
6437
  } catch (error) {
5909
6438
  const fallback = await this.#readFreshLogFallback();
5910
6439
  if (fallback) return fallback;
5911
- throw unavailableError3(error);
6440
+ throw unavailableError4(error);
5912
6441
  }
5913
6442
  process2.stderr.resume();
5914
6443
  const peer = new JsonLinePeer2(process2, this.#timeoutMs);
@@ -5957,7 +6486,7 @@ var init_stdio_grok_billing_client = __esm({
5957
6486
  { cause: error }
5958
6487
  );
5959
6488
  }
5960
- throw unavailableError3(error);
6489
+ throw unavailableError4(error);
5961
6490
  } finally {
5962
6491
  peer.close();
5963
6492
  }
@@ -6001,7 +6530,7 @@ var init_stdio_grok_billing_client = __esm({
6001
6530
  this.#timeoutMs = timeoutMs;
6002
6531
  process2.stdout.setEncoding("utf8");
6003
6532
  process2.stdout.on("data", (chunk) => this.#consume(chunk));
6004
- process2.once("error", (error) => this.#fail(unavailableError3(error)));
6533
+ process2.once("error", (error) => this.#fail(unavailableError4(error)));
6005
6534
  process2.once("exit", (code, signal) => {
6006
6535
  if (this.#closed) return;
6007
6536
  this.#fail(
@@ -6039,7 +6568,7 @@ var init_stdio_grok_billing_client = __esm({
6039
6568
  this.#closed = true;
6040
6569
  for (const pending of this.#pending.values()) {
6041
6570
  clearTimeout(pending.timeout);
6042
- pending.reject(unavailableError3(new Error("Grok ACP connection closed")));
6571
+ pending.reject(unavailableError4(new Error("Grok ACP connection closed")));
6043
6572
  }
6044
6573
  this.#pending.clear();
6045
6574
  this.#process.kill();
@@ -6267,7 +6796,7 @@ function endpointFailure(error, label) {
6267
6796
  recovery: "Check network access and xAI status, then retry."
6268
6797
  };
6269
6798
  }
6270
- function safeFailure8(error) {
6799
+ function safeFailure9(error) {
6271
6800
  if (error instanceof Error && "code" in error && typeof error.code === "string" && "recovery" in error && typeof error.recovery === "string") {
6272
6801
  return { code: error.code, message: error.message, recovery: error.recovery };
6273
6802
  }
@@ -6522,7 +7051,7 @@ var init_xai_api_connector = __esm({
6522
7051
  costs: [],
6523
7052
  balances: [],
6524
7053
  invoices: [],
6525
- warnings: [safeFailure8(error)],
7054
+ warnings: [safeFailure9(error)],
6526
7055
  observedAt
6527
7056
  };
6528
7057
  }
@@ -6619,10 +7148,10 @@ var init_ecb_exchange_rate_provider = __esm({
6619
7148
  });
6620
7149
 
6621
7150
  // src/server/keychain-secret-store.ts
6622
- import { spawn as spawn4 } from "child_process";
7151
+ import { spawn as spawn6 } from "child_process";
6623
7152
  async function runSecurityCommand(arguments_, input) {
6624
7153
  return await new Promise((resolveResult, reject) => {
6625
- const child = spawn4("/usr/bin/security", arguments_, {
7154
+ const child = spawn6("/usr/bin/security", arguments_, {
6626
7155
  stdio: ["pipe", "pipe", "ignore"]
6627
7156
  });
6628
7157
  let output = "";
@@ -6693,7 +7222,7 @@ var init_keychain_secret_store = __esm({
6693
7222
  });
6694
7223
 
6695
7224
  // src/server/macos-notifier.ts
6696
- import { spawn as spawn5 } from "child_process";
7225
+ import { spawn as spawn7 } from "child_process";
6697
7226
  var MacOsNotifier;
6698
7227
  var init_macos_notifier = __esm({
6699
7228
  "src/server/macos-notifier.ts"() {
@@ -6701,7 +7230,7 @@ var init_macos_notifier = __esm({
6701
7230
  MacOsNotifier = class {
6702
7231
  async notify(event) {
6703
7232
  await new Promise((resolve5, reject) => {
6704
- const child = spawn5(
7233
+ const child = spawn7(
6705
7234
  "/usr/bin/osascript",
6706
7235
  [
6707
7236
  "-e",
@@ -6721,8 +7250,8 @@ var init_macos_notifier = __esm({
6721
7250
  });
6722
7251
 
6723
7252
  // src/server/macos-start-at-login-manager.ts
6724
- import { mkdir as mkdir4, rm, writeFile as writeFile4 } from "fs/promises";
6725
- import { dirname as dirname3, isAbsolute, join as join7 } from "path";
7253
+ import { mkdir as mkdir4, rm as rm2, writeFile as writeFile5 } from "fs/promises";
7254
+ import { dirname as dirname3, isAbsolute, join as join8 } from "path";
6726
7255
  function launchAgentPlist(options) {
6727
7256
  const label = options.label ?? LABEL;
6728
7257
  const arguments_ = [
@@ -6774,15 +7303,15 @@ var init_macos_start_at_login_manager = __esm({
6774
7303
  const label = validateLaunchAgentLabel(options.label ?? LABEL);
6775
7304
  if (options.nodeImport) validateNodeImport(options.nodeImport);
6776
7305
  this.#options = { ...options, label };
6777
- this.#path = join7(options.userHome, "Library", "LaunchAgents", `${label}.plist`);
7306
+ this.#path = join8(options.userHome, "Library", "LaunchAgents", `${label}.plist`);
6778
7307
  }
6779
7308
  async setEnabled(enabled) {
6780
7309
  if (!enabled) {
6781
- await rm(this.#path, { force: true });
7310
+ await rm2(this.#path, { force: true });
6782
7311
  return;
6783
7312
  }
6784
7313
  await mkdir4(dirname3(this.#path), { recursive: true, mode: 448 });
6785
- await writeFile4(this.#path, launchAgentPlist(this.#options), { mode: 384 });
7314
+ await writeFile5(this.#path, launchAgentPlist(this.#options), { mode: 384 });
6786
7315
  }
6787
7316
  async isEnabled() {
6788
7317
  try {
@@ -6899,7 +7428,7 @@ var init_otlp_protobuf = __esm({
6899
7428
  // src/server/local-server.ts
6900
7429
  import { createReadStream as createReadStream2, existsSync, statSync } from "fs";
6901
7430
  import { createServer } from "http";
6902
- import { extname, join as join8, normalize, resolve } from "path";
7431
+ import { extname, join as join9, normalize, resolve } from "path";
6903
7432
  import { randomBytes } from "crypto";
6904
7433
  import { z as z9 } from "zod";
6905
7434
  async function startLocalServer(options) {
@@ -7265,8 +7794,8 @@ async function serveStatic(response, pathname, staticDirectory) {
7265
7794
  const root = resolve(staticDirectory);
7266
7795
  const requested = pathname === "/" ? "index.html" : pathname.replace(/^\/+/, "");
7267
7796
  const normalized = normalize(requested);
7268
- const candidate = resolve(join8(root, normalized));
7269
- const indexFile = join8(root, "index.html");
7797
+ const candidate = resolve(join9(root, normalized));
7798
+ const indexFile = join9(root, "index.html");
7270
7799
  const file = candidate.startsWith(`${root}/`) && existsSync(candidate) && statSync(candidate).isFile() ? candidate : indexFile;
7271
7800
  if (!existsSync(file)) {
7272
7801
  sendText(response, 404, "Dashboard assets are not built");
@@ -7377,7 +7906,7 @@ var init_local_server = __esm({
7377
7906
  // src/server/path-discovery-probe.ts
7378
7907
  import { constants } from "fs";
7379
7908
  import { access } from "fs/promises";
7380
- import { delimiter, isAbsolute as isAbsolute2, join as join9, resolve as resolve2 } from "path";
7909
+ import { delimiter, isAbsolute as isAbsolute2, join as join10, resolve as resolve2 } from "path";
7381
7910
  async function isExecutable(path) {
7382
7911
  try {
7383
7912
  await access(path, constants.X_OK);
@@ -7423,7 +7952,7 @@ var init_path_discovery_probe = __esm({
7423
7952
  async #findExecutable(command) {
7424
7953
  if (command.includes("/")) return await isExecutable(command) ? resolve2(command) : null;
7425
7954
  for (const directory of this.#path.split(delimiter).filter(Boolean)) {
7426
- const candidate = join9(directory, command);
7955
+ const candidate = join10(directory, command);
7427
7956
  if (await isExecutable(candidate)) return candidate;
7428
7957
  }
7429
7958
  return null;
@@ -7617,8 +8146,10 @@ function mapQuotaRow(row) {
7617
8146
  billingDomainId: row.billing_domain_id,
7618
8147
  label: row.label,
7619
8148
  usedPercent: clampPercent(row.used_percent),
8149
+ usedAmount: row.used_amount,
7620
8150
  windowDurationMinutes: row.window_duration_minutes,
7621
8151
  resetsAt: row.resets_at,
8152
+ resetLabel: row.reset_label,
7622
8153
  authority: row.authority,
7623
8154
  observedAt: row.observed_at,
7624
8155
  scope: row.scope ?? void 0,
@@ -8029,7 +8560,11 @@ function allDomainHistories(providers) {
8029
8560
  provider,
8030
8561
  domain,
8031
8562
  history: domain.history,
8032
- includedInHeadline: provider.id === "dsh" || provider.id === "grok" && domain.id !== "xai-api" ? true : domain.id === provider.summaryBillingDomainId
8563
+ includedInHeadline: billingDomainIncludedInHeadline(
8564
+ provider.id,
8565
+ domain.id,
8566
+ provider.summaryBillingDomainId
8567
+ )
8033
8568
  }))
8034
8569
  );
8035
8570
  }
@@ -8792,6 +9327,11 @@ function tokenCoverage(tokens, excludedObservationCount = 0) {
8792
9327
  );
8793
9328
  return scopes.includes("this-mac") || temporalities.includes("delta") ? "partial" : "complete";
8794
9329
  }
9330
+ function billingDomainIncludedInHeadline(providerId, billingDomainId, summaryBillingDomainId) {
9331
+ if (providerId === "dsh") return true;
9332
+ if (providerId === "grok" && billingDomainId !== "xai-api") return true;
9333
+ return summaryBillingDomainId !== null && billingDomainId === summaryBillingDomainId;
9334
+ }
8795
9335
  function selectSummaryBillingDomainId(providerId, domains) {
8796
9336
  if (providerId === "grok") {
8797
9337
  return domains.find((domain) => domain.id === "grok-build-subscription")?.id ?? domains[0]?.id ?? null;
@@ -8879,7 +9419,7 @@ var init_sqlite_usage_repository = __esm({
8879
9419
  this.#database.exec("PRAGMA journal_mode = WAL; PRAGMA foreign_keys = ON;");
8880
9420
  this.#migrate();
8881
9421
  }
8882
- saveSnapshot(snapshot2, options = {}) {
9422
+ async saveSnapshot(snapshot2, options = {}) {
8883
9423
  this.#database.exec("BEGIN IMMEDIATE");
8884
9424
  try {
8885
9425
  const providerSql = options.preserveFailure ? `INSERT INTO providers (
@@ -8921,16 +9461,18 @@ var init_sqlite_usage_repository = __esm({
8921
9461
  }
8922
9462
  const quotaStatement = this.#database.prepare(
8923
9463
  `INSERT INTO quota_buckets (
8924
- provider_id, id, billing_domain_id, label, used_percent, window_duration_minutes,
8925
- resets_at, authority, observed_at,
9464
+ provider_id, id, billing_domain_id, label, used_percent, used_amount,
9465
+ window_duration_minutes, resets_at, reset_label, authority, observed_at,
8926
9466
  scope, status, limit_amount, limit_currency, fallback_status
8927
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
9467
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
8928
9468
  ON CONFLICT(provider_id, id) DO UPDATE SET
8929
9469
  billing_domain_id = excluded.billing_domain_id,
8930
9470
  label = excluded.label,
8931
9471
  used_percent = excluded.used_percent,
9472
+ used_amount = excluded.used_amount,
8932
9473
  window_duration_minutes = excluded.window_duration_minutes,
8933
9474
  resets_at = excluded.resets_at,
9475
+ reset_label = excluded.reset_label,
8934
9476
  authority = excluded.authority,
8935
9477
  observed_at = excluded.observed_at,
8936
9478
  scope = excluded.scope,
@@ -8940,19 +9482,22 @@ var init_sqlite_usage_repository = __esm({
8940
9482
  fallback_status = excluded.fallback_status`
8941
9483
  );
8942
9484
  const reportedQuotaDomains = [
8943
- ...new Set(snapshot2.quotaBuckets.map((bucket) => bucket.billingDomainId))
9485
+ .../* @__PURE__ */ new Set([
9486
+ ...snapshot2.completeQuotaBillingDomainIds ?? [],
9487
+ ...snapshot2.quotaBuckets.map((bucket) => bucket.billingDomainId)
9488
+ ])
8944
9489
  ];
8945
9490
  if (reportedQuotaDomains.length > 0) {
8946
- const retiredQuotaStatement = this.#database.prepare(
8947
- `DELETE FROM quota_buckets
8948
- WHERE provider_id = ? AND billing_domain_id = ? AND id NOT IN (${snapshot2.quotaBuckets.map(() => "?").join(", ")})`
8949
- );
8950
9491
  for (const billingDomainId of reportedQuotaDomains) {
8951
- retiredQuotaStatement.run(
8952
- snapshot2.provider.id,
8953
- billingDomainId,
8954
- ...snapshot2.quotaBuckets.map((bucket) => bucket.id)
8955
- );
9492
+ const ids = snapshot2.quotaBuckets.filter((bucket) => bucket.billingDomainId === billingDomainId).map((bucket) => bucket.id);
9493
+ if (ids.length === 0) {
9494
+ this.#database.prepare(`DELETE FROM quota_buckets WHERE provider_id = ? AND billing_domain_id = ?`).run(snapshot2.provider.id, billingDomainId);
9495
+ continue;
9496
+ }
9497
+ this.#database.prepare(
9498
+ `DELETE FROM quota_buckets
9499
+ WHERE provider_id = ? AND billing_domain_id = ? AND id NOT IN (${ids.map(() => "?").join(", ")})`
9500
+ ).run(snapshot2.provider.id, billingDomainId, ...ids);
8956
9501
  }
8957
9502
  }
8958
9503
  for (const bucket of snapshot2.quotaBuckets) {
@@ -8963,8 +9508,10 @@ var init_sqlite_usage_repository = __esm({
8963
9508
  bucket.billingDomainId,
8964
9509
  bucket.label,
8965
9510
  clampedUsedPercent,
9511
+ bucket.usedAmount ?? null,
8966
9512
  bucket.windowDurationMinutes ?? null,
8967
9513
  bucket.resetsAt,
9514
+ bucket.resetLabel ?? null,
8968
9515
  bucket.authority,
8969
9516
  snapshot2.observedAt,
8970
9517
  bucket.scope ?? null,
@@ -9417,11 +9964,15 @@ var init_sqlite_usage_repository = __esm({
9417
9964
  FROM billing_domains WHERE provider_id = ? ORDER BY id`
9418
9965
  ).all(provider.id);
9419
9966
  const summaryBillingDomainId = selectSummaryBillingDomainId(provider.id, domains);
9420
- if (!summaryBillingDomainId) continue;
9421
- headlineDomains.set(`${provider.id}:${summaryBillingDomainId}`, {
9422
- displayName: provider.display_name,
9423
- domainId: summaryBillingDomainId
9424
- });
9967
+ for (const domain of domains) {
9968
+ if (!billingDomainIncludedInHeadline(provider.id, domain.id, summaryBillingDomainId)) {
9969
+ continue;
9970
+ }
9971
+ headlineDomains.set(`${provider.id}:${domain.id}`, {
9972
+ displayName: provider.display_name,
9973
+ domainId: domain.id
9974
+ });
9975
+ }
9425
9976
  }
9426
9977
  const totals = /* @__PURE__ */ new Map();
9427
9978
  const addContribution = (date, providerId, displayName, recordedTokens2) => {
@@ -9954,8 +10505,8 @@ var init_sqlite_usage_repository = __esm({
9954
10505
  }
9955
10506
  #getBillingDomainOverview(providerId, domain, now, query, forecasts, forecastCoverage, degradedDiagnostic, legacyProviderFailure = null) {
9956
10507
  const quotaRows = this.#database.prepare(
9957
- `SELECT id, billing_domain_id, label, used_percent, window_duration_minutes, resets_at,
9958
- authority, observed_at,
10508
+ `SELECT id, billing_domain_id, label, used_percent, used_amount, window_duration_minutes,
10509
+ resets_at, reset_label, authority, observed_at,
9959
10510
  scope, status, limit_amount, limit_currency, fallback_status
9960
10511
  FROM quota_buckets WHERE provider_id = ? AND billing_domain_id = ? ORDER BY id`
9961
10512
  ).all(providerId, domain.id);
@@ -10388,9 +10939,11 @@ var init_sqlite_usage_repository = __esm({
10388
10939
  observed_at TEXT NOT NULL,
10389
10940
  scope TEXT,
10390
10941
  status TEXT,
10942
+ used_amount REAL,
10391
10943
  limit_amount REAL,
10392
10944
  limit_currency TEXT,
10393
10945
  fallback_status TEXT,
10946
+ reset_label TEXT,
10394
10947
  total_tokens INTEGER NOT NULL DEFAULT 0,
10395
10948
  PRIMARY KEY (provider_id, id),
10396
10949
  FOREIGN KEY (provider_id, billing_domain_id)
@@ -10739,9 +11292,11 @@ var init_sqlite_usage_repository = __esm({
10739
11292
  ["window_duration_minutes", "INTEGER"],
10740
11293
  ["scope", "TEXT"],
10741
11294
  ["status", "TEXT"],
11295
+ ["used_amount", "REAL"],
10742
11296
  ["limit_amount", "REAL"],
10743
11297
  ["limit_currency", "TEXT"],
10744
- ["fallback_status", "TEXT"]
11298
+ ["fallback_status", "TEXT"],
11299
+ ["reset_label", "TEXT"]
10745
11300
  ]) {
10746
11301
  if (!quotaColumns.some((column) => column.name === name)) {
10747
11302
  this.#database.exec(`ALTER TABLE quota_buckets ADD COLUMN ${name} ${type}`);
@@ -10758,14 +11313,14 @@ __export(runtime_exports, {
10758
11313
  runDaemon: () => runDaemon
10759
11314
  });
10760
11315
  import { existsSync as existsSync2 } from "fs";
10761
- import { mkdir as mkdir5, rm as rm2 } from "fs/promises";
11316
+ import { mkdir as mkdir5, rm as rm3 } from "fs/promises";
10762
11317
  import { homedir as homedir4 } from "os";
10763
- import { isAbsolute as isAbsolute3, join as join10, resolve as resolve3 } from "path";
11318
+ import { isAbsolute as isAbsolute3, join as join11, resolve as resolve3 } from "path";
10764
11319
  import { fileURLToPath } from "url";
10765
11320
  async function runDaemon(home) {
10766
11321
  await mkdir5(home, { recursive: true, mode: 448 });
10767
11322
  const demoEnabled = process.env.AGENT_USAGE_DEMO === "1";
10768
- const repository = new SqliteUsageRepository(join10(home, "usage.sqlite"), {
11323
+ const repository = new SqliteUsageRepository(join11(home, "usage.sqlite"), {
10769
11324
  hideDemoProvider: !demoEnabled
10770
11325
  });
10771
11326
  const keychainService = process.env.AGENT_USAGE_KEYCHAIN_SERVICE;
@@ -10804,11 +11359,15 @@ async function runDaemon(home) {
10804
11359
  new AntigravityConnector({
10805
11360
  historyClient: new AntigravitySqliteUsageClient({
10806
11361
  roots: [
10807
- join10(homedir4(), ".gemini/antigravity-cli"),
10808
- join10(homedir4(), ".gemini/antigravity")
11362
+ join11(homedir4(), ".gemini/antigravity-cli"),
11363
+ join11(homedir4(), ".gemini/antigravity")
10809
11364
  ],
10810
- cachePath: join10(home, "antigravity-usage-cache.json")
11365
+ cachePath: join11(home, "antigravity-usage-cache.json")
10811
11366
  })
11367
+ }),
11368
+ new CursorConnector({
11369
+ quotaClient: new ScreenReaderCursorQuotaClient(),
11370
+ accountClient: new CursorAboutAccountClient()
10812
11371
  })
10813
11372
  ],
10814
11373
  connectorDefinitions: defaultConnectorDefinitions,
@@ -10840,10 +11399,14 @@ async function runDaemon(home) {
10840
11399
  "grok",
10841
11400
  "xai-api",
10842
11401
  "dsh",
10843
- "antigravity"
11402
+ "antigravity",
11403
+ "cursor"
10844
11404
  ].map((id) => [
10845
11405
  id,
10846
- { minimumIntervalMs: 5 * 60 * 1e3, timeoutMs: id === "claude-code" ? 25e3 : 2e4 }
11406
+ {
11407
+ minimumIntervalMs: 5 * 60 * 1e3,
11408
+ timeoutMs: id === "claude-code" || id === "cursor" ? 25e3 : 2e4
11409
+ }
10847
11410
  ])
10848
11411
  ),
10849
11412
  telemetryIngestors: [
@@ -10892,7 +11455,7 @@ async function runDaemon(home) {
10892
11455
  scheduler.stop();
10893
11456
  await server.close();
10894
11457
  repository.close();
10895
- await rm2(join10(home, "daemon.json"), { force: true });
11458
+ await rm3(join11(home, "daemon.json"), { force: true });
10896
11459
  resolveStop();
10897
11460
  };
10898
11461
  process.once("SIGTERM", () => void stop());
@@ -10903,27 +11466,27 @@ function localTranscriptClient(provider, applicationHome) {
10903
11466
  return new LocalTranscriptUsageClient({
10904
11467
  provider,
10905
11468
  roots: localTranscriptRoots(provider),
10906
- cachePath: join10(applicationHome, "cache", `${provider}-transcripts.json`)
11469
+ cachePath: join11(applicationHome, "cache", `${provider}-transcripts.json`)
10907
11470
  });
10908
11471
  }
10909
11472
  function localTranscriptRoots(provider) {
10910
11473
  if (provider === "codex") {
10911
11474
  const home = resolveHomeOverride(process.env.CODEX_HOME, ".codex");
10912
- return [join10(home, "sessions"), join10(home, "archived_sessions")];
11475
+ return [join11(home, "sessions"), join11(home, "archived_sessions")];
10913
11476
  }
10914
11477
  if (provider === "claude-code") {
10915
- return [join10(resolveHomeOverride(process.env.CLAUDE_CONFIG_DIR, ".claude"), "projects")];
11478
+ return [join11(resolveHomeOverride(process.env.CLAUDE_CONFIG_DIR, ".claude"), "projects")];
10916
11479
  }
10917
11480
  if (provider === "dsh") {
10918
- return [join10(resolveHomeOverride(process.env.DSH_HOME, ".dsh"), "sessions")];
11481
+ return [join11(resolveHomeOverride(process.env.DSH_HOME, ".dsh"), "sessions")];
10919
11482
  }
10920
- return [join10(resolveHomeOverride(process.env.GROK_HOME, ".grok"), "sessions")];
11483
+ return [join11(resolveHomeOverride(process.env.GROK_HOME, ".grok"), "sessions")];
10921
11484
  }
10922
11485
  function resolveHomeOverride(value, fallback) {
10923
11486
  const configured = value?.trim();
10924
- if (!configured) return join10(homedir4(), fallback);
11487
+ if (!configured) return join11(homedir4(), fallback);
10925
11488
  if (configured === "~") return homedir4();
10926
- if (configured.startsWith("~/")) return join10(homedir4(), configured.slice(2));
11489
+ if (configured.startsWith("~/")) return join11(homedir4(), configured.slice(2));
10927
11490
  return isAbsolute3(configured) ? configured : resolve3(configured);
10928
11491
  }
10929
11492
  function createDemoConnector() {
@@ -10969,7 +11532,7 @@ function locateStaticDirectory() {
10969
11532
  fileURLToPath(new URL("./web", import.meta.url)),
10970
11533
  fileURLToPath(new URL("../../dist/web", import.meta.url))
10971
11534
  ];
10972
- return candidates.find((candidate) => existsSync2(join10(candidate, "index.html")));
11535
+ return candidates.find((candidate) => existsSync2(join11(candidate, "index.html")));
10973
11536
  }
10974
11537
  var init_runtime = __esm({
10975
11538
  "src/server/runtime.ts"() {
@@ -10988,6 +11551,9 @@ var init_runtime = __esm({
10988
11551
  init_opencode_go_connector();
10989
11552
  init_dsh_connector();
10990
11553
  init_antigravity_connector();
11554
+ init_cursor_about_client();
11555
+ init_cursor_connector();
11556
+ init_cursor_usage_screen_client();
10991
11557
  init_antigravity_sqlite_usage_client();
10992
11558
  init_grok_build_connector();
10993
11559
  init_grok_telemetry();
@@ -11007,14 +11573,73 @@ var init_runtime = __esm({
11007
11573
  });
11008
11574
 
11009
11575
  // src/cli.ts
11010
- init_redaction();
11011
- init_daemon_state();
11012
- import { spawn as spawn6 } from "child_process";
11576
+ import { spawn as spawn8 } from "child_process";
11013
11577
  import { connect as tcpConnect } from "net";
11014
11578
  import { homedir as homedir5 } from "os";
11015
- import { join as join11, resolve as resolve4 } from "path";
11579
+ import { join as join12, resolve as resolve4 } from "path";
11016
11580
  import { Command } from "commander";
11017
11581
  import open2 from "open";
11582
+
11583
+ // src/lib/quota-bucket-display.ts
11584
+ function formatQuotaMoney(amount, currency, locale) {
11585
+ try {
11586
+ return new Intl.NumberFormat(locale, {
11587
+ style: "currency",
11588
+ currency,
11589
+ minimumFractionDigits: Number.isInteger(amount) ? 0 : 2,
11590
+ maximumFractionDigits: 2
11591
+ }).format(amount);
11592
+ } catch {
11593
+ const digits = Number.isInteger(amount) ? amount.toString() : amount.toFixed(2);
11594
+ return `${currency} ${digits}`;
11595
+ }
11596
+ }
11597
+ function quotaBucketDisplay(bucket, locale, copy) {
11598
+ const resetText = bucket.resetLabel?.trim() || null;
11599
+ if (bucket.fallbackStatus === "disabled") {
11600
+ return {
11601
+ kind: "disabled",
11602
+ primary: copy.onDemandOff,
11603
+ progressPercent: null,
11604
+ resetText
11605
+ };
11606
+ }
11607
+ const currency = bucket.limitCurrency ?? "USD";
11608
+ if (bucket.usedAmount !== null && bucket.usedAmount !== void 0 && bucket.limitAmount !== null && bucket.limitAmount !== void 0) {
11609
+ return {
11610
+ kind: "amount",
11611
+ primary: `${formatQuotaMoney(bucket.usedAmount, currency, locale)} / ${formatQuotaMoney(bucket.limitAmount, currency, locale)}`,
11612
+ progressPercent: bucket.usedPercent,
11613
+ resetText
11614
+ };
11615
+ }
11616
+ if (bucket.usedAmount !== null && bucket.usedAmount !== void 0) {
11617
+ return {
11618
+ kind: "amount",
11619
+ primary: `${formatQuotaMoney(bucket.usedAmount, currency, locale)} \xB7 ${copy.noMonthlyLimit}`,
11620
+ progressPercent: null,
11621
+ resetText
11622
+ };
11623
+ }
11624
+ if (bucket.usedPercent !== null) {
11625
+ return {
11626
+ kind: "percent",
11627
+ primary: `${bucket.usedPercent}% ${copy.used}`,
11628
+ progressPercent: bucket.usedPercent,
11629
+ resetText
11630
+ };
11631
+ }
11632
+ return {
11633
+ kind: "unavailable",
11634
+ primary: copy.unavailable,
11635
+ progressPercent: null,
11636
+ resetText
11637
+ };
11638
+ }
11639
+
11640
+ // src/cli.ts
11641
+ init_redaction();
11642
+ init_daemon_state();
11018
11643
  var program = new Command();
11019
11644
  program.name("agent-usage").description("View local coding-agent quota, token, and cost usage").option("--home <directory>", "application data directory", defaultHome()).option("--no-open", "start the dashboard without opening a browser");
11020
11645
  program.command("status").description("print the current provider overview").option("--json", "emit machine-readable JSON").option("--window <window>", "history window: 24h, 7d, or 30d", "24h").action(async (options) => {
@@ -11326,7 +11951,7 @@ async function ensureDaemon(home) {
11326
11951
  return await requireDaemonState(home);
11327
11952
  } catch {
11328
11953
  process.stderr.write("Agent Usage: starting local web service\u2026\n");
11329
- const child = spawn6(
11954
+ const child = spawn8(
11330
11955
  process.execPath,
11331
11956
  [...process.execArgv, process.argv[1], "--home", home, "serve"],
11332
11957
  {
@@ -11393,7 +12018,7 @@ function formatOverview(overview) {
11393
12018
  ` : "";
11394
12019
  return `${summary}${recommendation}${overview.providers.map((provider) => {
11395
12020
  const quota = provider.quotaBuckets.map(
11396
- (bucket) => `${bucket.label}: ${bucket.usedPercent ?? "?"}% used (${formatEvidence(
12021
+ (bucket) => `${bucket.label}: ${formatQuotaBucket(bucket)} (${formatEvidence(
11397
12022
  bucket.authority,
11398
12023
  bucket.observedAt ?? provider.freshness.lastSuccessAt
11399
12024
  )})`
@@ -11453,6 +12078,15 @@ function formatTokenEvidence(evidence) {
11453
12078
  function formatEvidence(authority, observedAt) {
11454
12079
  return `source ${authority} at ${observedAt ?? "unknown time"}`;
11455
12080
  }
12081
+ function formatQuotaBucket(bucket) {
12082
+ const display = quotaBucketDisplay(bucket, "en", {
12083
+ used: "used",
12084
+ unavailable: "unavailable",
12085
+ noMonthlyLimit: "No monthly limit",
12086
+ onDemandOff: "On-demand usage is off"
12087
+ });
12088
+ return display.resetText ? `${display.primary}; ${display.resetText}` : display.primary;
12089
+ }
11456
12090
  function formatDoctor(report) {
11457
12091
  const providerLines = report.providers.map(
11458
12092
  (provider) => provider.status === "degraded" ? `${provider.displayName} \u2014 degraded${provider.health.errorCode ? ` (${provider.health.errorCode})` : ""}: ${provider.health.recovery ?? "Run refresh and inspect connector diagnostics."}` : `${provider.displayName} \u2014 healthy`
@@ -11468,6 +12102,6 @@ function formatDoctor(report) {
11468
12102
  ].join("\n");
11469
12103
  }
11470
12104
  function defaultHome() {
11471
- return join11(homedir5(), "Library", "Application Support", "Agent Usage");
12105
+ return join12(homedir5(), "Library", "Application Support", "Agent Usage");
11472
12106
  }
11473
12107
  //# sourceMappingURL=cli.js.map