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/CONTRIBUTING.md +3 -1
- package/README.md +53 -9
- package/README.zh-CN.md +29 -4
- package/dist/cli.js +781 -147
- package/dist/cli.js.map +1 -1
- package/dist/web/_app/immutable/assets/2.DCw7Yj68.css +1 -0
- package/dist/web/_app/immutable/chunks/{CiAz1kOc.js → BJnEwO-n.js} +1 -1
- package/dist/web/_app/immutable/entry/{app.Z7FhDi1v.js → app.BroDwe18.js} +2 -2
- package/dist/web/_app/immutable/entry/start.IgKfiouf.js +1 -0
- package/dist/web/_app/immutable/nodes/{1.oDSuYnui.js → 1.BM7JX0do.js} +1 -1
- package/dist/web/_app/immutable/nodes/2.CE6LF_M_.js +26 -0
- package/dist/web/_app/version.json +1 -1
- package/dist/web/brand/agent-usage-showcase.jpg +0 -0
- package/dist/web/brands/README.md +7 -0
- package/dist/web/brands/cursor-dark.svg +12 -0
- package/dist/web/brands/cursor-light.svg +12 -0
- package/dist/web/index.html +6 -6
- package/docs/open-source.md +4 -3
- package/package.json +2 -1
- package/static/brand/agent-usage-showcase.jpg +0 -0
- package/static/brands/README.md +7 -0
- package/static/brands/cursor-dark.svg +12 -0
- package/static/brands/cursor-light.svg +12 -0
- package/dist/web/_app/immutable/assets/2.B3WVopjI.css +0 -1
- package/dist/web/_app/immutable/entry/start.DEVa4z2m.js +0 -1
- package/dist/web/_app/immutable/nodes/2.8Hl62Zo_.js +0 -26
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
|
-
|
|
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
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
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
|
-
|
|
1831
|
-
defaultBillingDomain(connector.id, this.#connectorDefinitions),
|
|
1832
|
-
|
|
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
|
|
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
|
|
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 (!
|
|
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(
|
|
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
|
|
4511
|
-
return string(
|
|
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
|
-
|
|
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 !==
|
|
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({
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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_) =>
|
|
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
|
-
|
|
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
|
|
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
|
|
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(
|
|
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(
|
|
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
|
|
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: [
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
6725
|
-
import { dirname as dirname3, isAbsolute, join as
|
|
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 =
|
|
7306
|
+
this.#path = join8(options.userHome, "Library", "LaunchAgents", `${label}.plist`);
|
|
6778
7307
|
}
|
|
6779
7308
|
async setEnabled(enabled) {
|
|
6780
7309
|
if (!enabled) {
|
|
6781
|
-
await
|
|
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
|
|
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
|
|
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(
|
|
7269
|
-
const indexFile =
|
|
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
|
|
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 =
|
|
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:
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
8952
|
-
|
|
8953
|
-
billingDomainId
|
|
8954
|
-
|
|
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
|
-
|
|
9421
|
-
|
|
9422
|
-
|
|
9423
|
-
|
|
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,
|
|
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
|
|
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
|
|
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(
|
|
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
|
-
|
|
10808
|
-
|
|
11362
|
+
join11(homedir4(), ".gemini/antigravity-cli"),
|
|
11363
|
+
join11(homedir4(), ".gemini/antigravity")
|
|
10809
11364
|
],
|
|
10810
|
-
cachePath:
|
|
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
|
-
{
|
|
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
|
|
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:
|
|
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 [
|
|
11475
|
+
return [join11(home, "sessions"), join11(home, "archived_sessions")];
|
|
10913
11476
|
}
|
|
10914
11477
|
if (provider === "claude-code") {
|
|
10915
|
-
return [
|
|
11478
|
+
return [join11(resolveHomeOverride(process.env.CLAUDE_CONFIG_DIR, ".claude"), "projects")];
|
|
10916
11479
|
}
|
|
10917
11480
|
if (provider === "dsh") {
|
|
10918
|
-
return [
|
|
11481
|
+
return [join11(resolveHomeOverride(process.env.DSH_HOME, ".dsh"), "sessions")];
|
|
10919
11482
|
}
|
|
10920
|
-
return [
|
|
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
|
|
11487
|
+
if (!configured) return join11(homedir4(), fallback);
|
|
10925
11488
|
if (configured === "~") return homedir4();
|
|
10926
|
-
if (configured.startsWith("~/")) return
|
|
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(
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
12105
|
+
return join12(homedir5(), "Library", "Application Support", "Agent Usage");
|
|
11472
12106
|
}
|
|
11473
12107
|
//# sourceMappingURL=cli.js.map
|