agent-usage-all-in-one 0.8.1 → 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 +721 -92
- package/dist/cli.js.map +1 -1
- package/dist/web/_app/immutable/assets/{2.CebKccN1.css → 2.DCw7Yj68.css} +1 -1
- package/dist/web/_app/immutable/chunks/BJnEwO-n.js +1 -0
- package/dist/web/_app/immutable/entry/{app.BJQZZwy-.js → app.BroDwe18.js} +2 -2
- package/dist/web/_app/immutable/entry/start.IgKfiouf.js +1 -0
- package/dist/web/_app/immutable/nodes/{1.C0DvG6AA.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/chunks/YxRJCZwS.js +0 -1
- package/dist/web/_app/immutable/entry/start.DGorbLTC.js +0 -1
- package/dist/web/_app/immutable/nodes/2.L5Bpe4_s.js +0 -26
package/dist/cli.js
CHANGED
|
@@ -2406,6 +2406,20 @@ var init_catalog = __esm({
|
|
|
2406
2406
|
billingDomain: { id: "code-assist-subscription", displayName: "Gemini Code Assist" }
|
|
2407
2407
|
},
|
|
2408
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"]
|
|
2409
2423
|
}
|
|
2410
2424
|
];
|
|
2411
2425
|
}
|
|
@@ -2418,6 +2432,12 @@ function clampPercent(value) {
|
|
|
2418
2432
|
}
|
|
2419
2433
|
return Math.min(100, Math.max(0, value));
|
|
2420
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
|
+
}
|
|
2421
2441
|
var init_quota_normalization = __esm({
|
|
2422
2442
|
"src/core/quota-normalization.ts"() {
|
|
2423
2443
|
"use strict";
|
|
@@ -4014,7 +4034,28 @@ function isGrokOfficialModel(model) {
|
|
|
4014
4034
|
}
|
|
4015
4035
|
return false;
|
|
4016
4036
|
}
|
|
4017
|
-
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
|
+
}
|
|
4018
4059
|
if (!model) return "grok-build-subscription";
|
|
4019
4060
|
const normalized = model.trim().toLowerCase();
|
|
4020
4061
|
if (customEndpoints?.has(normalized)) {
|
|
@@ -4317,7 +4358,7 @@ function isParsedTranscriptRecord(value) {
|
|
|
4317
4358
|
];
|
|
4318
4359
|
const cacheWriteTokenBreakdown = asObject(observation.cacheWriteTokenBreakdown);
|
|
4319
4360
|
const tokenSemantics = asObject(observation.tokenSemantics);
|
|
4320
|
-
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(
|
|
4321
4362
|
(field) => observation[field] === void 0 || observation[field] === null || nonNegativeSafeInteger(observation[field])
|
|
4322
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(
|
|
4323
4364
|
String(observation.timePrecision)
|
|
@@ -4335,12 +4376,19 @@ function isParsedTranscriptRecord(value) {
|
|
|
4335
4376
|
function nonNegativeSafeInteger(value) {
|
|
4336
4377
|
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
4337
4378
|
}
|
|
4338
|
-
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) {
|
|
4339
4384
|
const record = parseObject(line);
|
|
4340
4385
|
const params = asObject(record?.params);
|
|
4341
4386
|
const update = asObject(params?.update);
|
|
4387
|
+
if (!record || !params || !update) return [];
|
|
4388
|
+
const selected = grokSelectedModelFromUpdate(update);
|
|
4389
|
+
if (selected) grokState.selectedModel = selected;
|
|
4342
4390
|
const usage = asObject(update?.usage);
|
|
4343
|
-
if (!
|
|
4391
|
+
if (!usage || update.sessionUpdate !== "turn_completed") {
|
|
4344
4392
|
return [];
|
|
4345
4393
|
}
|
|
4346
4394
|
const meta = asObject(params._meta);
|
|
@@ -4379,9 +4427,14 @@ function parseGrokTranscriptLine(line, grokCustomModels) {
|
|
|
4379
4427
|
const dedupeKey = `${sessionId}:${promptId ?? stableId(line)}:${model}`;
|
|
4380
4428
|
const directCost = grokCostUsd(totals.costUsdTicks);
|
|
4381
4429
|
const reportedCostUsd = directCost ?? (remainingCost !== null && untickedTokens > 0 ? remainingCost * (grokRecordedTokens(totals) / untickedTokens) : null);
|
|
4382
|
-
const billingDomainId = resolveGrokBillingDomain(
|
|
4430
|
+
const billingDomainId = resolveGrokBillingDomain(
|
|
4431
|
+
model,
|
|
4432
|
+
grokCustomModels,
|
|
4433
|
+
grokState.selectedModel
|
|
4434
|
+
);
|
|
4383
4435
|
return {
|
|
4384
4436
|
dedupeKey,
|
|
4437
|
+
grokSelectedModel: grokState.selectedModel,
|
|
4385
4438
|
observation: {
|
|
4386
4439
|
id: `grok-transcript:${stableId(dedupeKey)}`,
|
|
4387
4440
|
billingDomainId,
|
|
@@ -4512,8 +4565,8 @@ function isForkedCodexSession(payload) {
|
|
|
4512
4565
|
if (string(payload.forked_from_id)) return true;
|
|
4513
4566
|
const source = asObject(payload.source);
|
|
4514
4567
|
const subagent = asObject(source?.subagent);
|
|
4515
|
-
const
|
|
4516
|
-
return string(
|
|
4568
|
+
const spawn9 = asObject(subagent?.thread_spawn);
|
|
4569
|
+
return string(spawn9?.parent_thread_id) !== null;
|
|
4517
4570
|
}
|
|
4518
4571
|
async function listTranscriptFiles(roots, cutoff) {
|
|
4519
4572
|
const files = [];
|
|
@@ -4704,7 +4757,7 @@ function compact(value) {
|
|
|
4704
4757
|
function stableId(value) {
|
|
4705
4758
|
return createHash2("sha256").update(value).digest("hex").slice(0, 24);
|
|
4706
4759
|
}
|
|
4707
|
-
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;
|
|
4708
4761
|
var init_local_transcript_usage_client = __esm({
|
|
4709
4762
|
"src/server/local-transcript-usage-client.ts"() {
|
|
4710
4763
|
"use strict";
|
|
@@ -4715,6 +4768,7 @@ var init_local_transcript_usage_client = __esm({
|
|
|
4715
4768
|
DSH_SESSION_FORMAT_VERSION = 0;
|
|
4716
4769
|
DSH_COMPRESSED_SUFFIX = ".jsonl.zstd";
|
|
4717
4770
|
DSH_LINE_HINTS = ['"usage"', '"request/context"', '"type":"session"'];
|
|
4771
|
+
TRANSCRIPT_CACHE_VERSION = 2;
|
|
4718
4772
|
LocalTranscriptUsageClient = class {
|
|
4719
4773
|
#provider;
|
|
4720
4774
|
#roots;
|
|
@@ -4797,7 +4851,8 @@ var init_local_transcript_usage_client = __esm({
|
|
|
4797
4851
|
const remapped = cached.records.map((r) => {
|
|
4798
4852
|
const expectedDomain = resolveGrokBillingDomain(
|
|
4799
4853
|
r.observation.model,
|
|
4800
|
-
this.#grokCustomModels
|
|
4854
|
+
this.#grokCustomModels,
|
|
4855
|
+
r.grokSelectedModel
|
|
4801
4856
|
);
|
|
4802
4857
|
if (r.observation.billingDomainId !== expectedDomain) {
|
|
4803
4858
|
return {
|
|
@@ -4826,9 +4881,10 @@ var init_local_transcript_usage_client = __esm({
|
|
|
4826
4881
|
model: "",
|
|
4827
4882
|
unsupportedVersion: false
|
|
4828
4883
|
};
|
|
4884
|
+
const grokState = { selectedModel: null };
|
|
4829
4885
|
try {
|
|
4830
4886
|
for await (const line of readTranscriptLines(file.path)) {
|
|
4831
|
-
records.push(...this.#parseLine(line, codexState, dshState));
|
|
4887
|
+
records.push(...this.#parseLine(line, codexState, dshState, grokState));
|
|
4832
4888
|
if (dshState.unsupportedVersion) {
|
|
4833
4889
|
return { records: [], complete: false, unsupportedFormat: true };
|
|
4834
4890
|
}
|
|
@@ -4844,7 +4900,7 @@ var init_local_transcript_usage_client = __esm({
|
|
|
4844
4900
|
});
|
|
4845
4901
|
return { records, complete: true, unsupportedFormat: false };
|
|
4846
4902
|
}
|
|
4847
|
-
#parseLine(line, codexState, dshState) {
|
|
4903
|
+
#parseLine(line, codexState, dshState, grokState) {
|
|
4848
4904
|
if (this.#provider === "claude-code") {
|
|
4849
4905
|
return line.includes('"usage"') ? compact(parseClaudeTranscriptLine(line)) : [];
|
|
4850
4906
|
}
|
|
@@ -4852,7 +4908,10 @@ var init_local_transcript_usage_client = __esm({
|
|
|
4852
4908
|
if (this.#provider === "dsh") {
|
|
4853
4909
|
return DSH_LINE_HINTS.some((hint) => line.includes(hint)) ? parseDshTranscriptLine(line, dshState) : [];
|
|
4854
4910
|
}
|
|
4855
|
-
|
|
4911
|
+
if (line.includes('"turn_completed"') || line.includes('"modelId"') || line.includes('"current_mode_update"')) {
|
|
4912
|
+
return parseGrokTranscriptLine(line, this.#grokCustomModels, grokState);
|
|
4913
|
+
}
|
|
4914
|
+
return [];
|
|
4856
4915
|
}
|
|
4857
4916
|
async #loadCache() {
|
|
4858
4917
|
if (this.#cacheLoaded) return;
|
|
@@ -4860,7 +4919,7 @@ var init_local_transcript_usage_client = __esm({
|
|
|
4860
4919
|
if (!this.#cachePath) return;
|
|
4861
4920
|
try {
|
|
4862
4921
|
const stored = JSON.parse(await readFile3(this.#cachePath, "utf8"));
|
|
4863
|
-
if (stored.version !==
|
|
4922
|
+
if (stored.version !== TRANSCRIPT_CACHE_VERSION || !Array.isArray(stored.files)) return;
|
|
4864
4923
|
for (const file of stored.files) {
|
|
4865
4924
|
if (!isCachedTranscriptFile(file)) continue;
|
|
4866
4925
|
if (file.recordsDigest !== stableId(JSON.stringify(file.records))) continue;
|
|
@@ -4876,7 +4935,10 @@ var init_local_transcript_usage_client = __esm({
|
|
|
4876
4935
|
const temporary = `${this.#cachePath}.${process.pid}.tmp`;
|
|
4877
4936
|
await writeFile2(
|
|
4878
4937
|
temporary,
|
|
4879
|
-
JSON.stringify({
|
|
4938
|
+
JSON.stringify({
|
|
4939
|
+
version: TRANSCRIPT_CACHE_VERSION,
|
|
4940
|
+
files: [...this.#fileCache.values()]
|
|
4941
|
+
}),
|
|
4880
4942
|
{ mode: 384 }
|
|
4881
4943
|
);
|
|
4882
4944
|
await rename2(temporary, this.#cachePath);
|
|
@@ -5274,11 +5336,473 @@ var init_antigravity_connector = __esm({
|
|
|
5274
5336
|
}
|
|
5275
5337
|
});
|
|
5276
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
|
+
|
|
5277
5801
|
// src/server/antigravity-sqlite-usage-client.ts
|
|
5278
5802
|
import { createHash as createHash3 } from "crypto";
|
|
5279
|
-
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";
|
|
5280
5804
|
import { createRequire as createRequire2 } from "module";
|
|
5281
|
-
import { dirname as dirname2, join as
|
|
5805
|
+
import { dirname as dirname2, join as join6 } from "path";
|
|
5282
5806
|
import protobuf from "protobufjs";
|
|
5283
5807
|
function parseAntigravityDatabase(dbPath, conversationId, fallbackMtimeMs) {
|
|
5284
5808
|
const db = new DatabaseSync2(dbPath, { readOnly: true });
|
|
@@ -5552,7 +6076,7 @@ var init_antigravity_sqlite_usage_client = __esm({
|
|
|
5552
6076
|
} catch {
|
|
5553
6077
|
continue;
|
|
5554
6078
|
}
|
|
5555
|
-
const summariesPath =
|
|
6079
|
+
const summariesPath = join6(root, "conversation_summaries.db");
|
|
5556
6080
|
const candidateIds = /* @__PURE__ */ new Set();
|
|
5557
6081
|
let summariesLoaded = false;
|
|
5558
6082
|
try {
|
|
@@ -5575,7 +6099,7 @@ var init_antigravity_sqlite_usage_client = __esm({
|
|
|
5575
6099
|
}
|
|
5576
6100
|
} catch {
|
|
5577
6101
|
}
|
|
5578
|
-
const convDir =
|
|
6102
|
+
const convDir = join6(root, "conversations");
|
|
5579
6103
|
try {
|
|
5580
6104
|
const entries = await readdir(convDir);
|
|
5581
6105
|
for (const entry of entries) {
|
|
@@ -5584,7 +6108,7 @@ var init_antigravity_sqlite_usage_client = __esm({
|
|
|
5584
6108
|
if (summariesLoaded && candidateIds.size > 0 && !candidateIds.has(convId)) {
|
|
5585
6109
|
continue;
|
|
5586
6110
|
}
|
|
5587
|
-
const fullPath =
|
|
6111
|
+
const fullPath = join6(convDir, entry);
|
|
5588
6112
|
if (seenDbPaths.has(fullPath)) continue;
|
|
5589
6113
|
seenDbPaths.add(fullPath);
|
|
5590
6114
|
try {
|
|
@@ -5645,7 +6169,7 @@ var init_antigravity_sqlite_usage_client = __esm({
|
|
|
5645
6169
|
try {
|
|
5646
6170
|
await mkdir3(dirname2(this.#cachePath), { recursive: true, mode: 448 });
|
|
5647
6171
|
const temporary = `${this.#cachePath}.${process.pid}.tmp`;
|
|
5648
|
-
await
|
|
6172
|
+
await writeFile4(
|
|
5649
6173
|
temporary,
|
|
5650
6174
|
JSON.stringify({ version: 1, files: [...this.#fileCache.values()] }),
|
|
5651
6175
|
{ mode: 384 }
|
|
@@ -5773,10 +6297,10 @@ var init_grok_telemetry = __esm({
|
|
|
5773
6297
|
});
|
|
5774
6298
|
|
|
5775
6299
|
// src/connectors/grok-build/stdio-grok-billing-client.ts
|
|
5776
|
-
import { spawn as
|
|
6300
|
+
import { spawn as spawn5 } from "child_process";
|
|
5777
6301
|
import { open } from "fs/promises";
|
|
5778
6302
|
import { homedir as homedir3 } from "os";
|
|
5779
|
-
import { join as
|
|
6303
|
+
import { join as join7 } from "path";
|
|
5780
6304
|
import { z as z7 } from "zod";
|
|
5781
6305
|
function billingIsFresh(billing, now) {
|
|
5782
6306
|
if (!billing.sourceObservedAt) return false;
|
|
@@ -5797,7 +6321,7 @@ async function refreshBillingLogViaDashboard(command, timeoutMs) {
|
|
|
5797
6321
|
"expect eof"
|
|
5798
6322
|
].join("\n");
|
|
5799
6323
|
await new Promise((resolve5) => {
|
|
5800
|
-
const dashboard =
|
|
6324
|
+
const dashboard = spawn5("/usr/bin/expect", ["-c", expectScript2], {
|
|
5801
6325
|
env: {
|
|
5802
6326
|
...process.env,
|
|
5803
6327
|
AGENT_USAGE_GROK_REFRESH_COMMAND: command,
|
|
@@ -5864,7 +6388,7 @@ async function readLogTail(path) {
|
|
|
5864
6388
|
await handle.close();
|
|
5865
6389
|
}
|
|
5866
6390
|
}
|
|
5867
|
-
function
|
|
6391
|
+
function unavailableError4(cause) {
|
|
5868
6392
|
return new GrokBillingAdapterError(
|
|
5869
6393
|
"grok-client-unavailable",
|
|
5870
6394
|
"Grok Build billing capability is unavailable.",
|
|
@@ -5897,11 +6421,11 @@ var init_stdio_grok_billing_client = __esm({
|
|
|
5897
6421
|
constructor(options = {}) {
|
|
5898
6422
|
this.#command = options.command ?? "grok";
|
|
5899
6423
|
this.#timeoutMs = options.timeoutMs ?? 8e3;
|
|
5900
|
-
this.#spawnProcess = options.spawnProcess ?? ((command, arguments_) =>
|
|
6424
|
+
this.#spawnProcess = options.spawnProcess ?? ((command, arguments_) => spawn5(command, arguments_, {
|
|
5901
6425
|
stdio: ["pipe", "pipe", "pipe"]
|
|
5902
6426
|
}));
|
|
5903
6427
|
this.#readUnifiedLog = options.readUnifiedLog ?? (() => readLogTail(
|
|
5904
|
-
|
|
6428
|
+
join7(process.env.GROK_HOME ?? join7(homedir3(), ".grok"), "logs", "unified.jsonl")
|
|
5905
6429
|
));
|
|
5906
6430
|
this.#refreshBillingLog = options.refreshBillingLog ?? (options.readUnifiedLog ? async () => void 0 : () => refreshBillingLogViaDashboard(this.#command, this.#timeoutMs));
|
|
5907
6431
|
this.#clock = options.clock ?? (() => /* @__PURE__ */ new Date());
|
|
@@ -5913,7 +6437,7 @@ var init_stdio_grok_billing_client = __esm({
|
|
|
5913
6437
|
} catch (error) {
|
|
5914
6438
|
const fallback = await this.#readFreshLogFallback();
|
|
5915
6439
|
if (fallback) return fallback;
|
|
5916
|
-
throw
|
|
6440
|
+
throw unavailableError4(error);
|
|
5917
6441
|
}
|
|
5918
6442
|
process2.stderr.resume();
|
|
5919
6443
|
const peer = new JsonLinePeer2(process2, this.#timeoutMs);
|
|
@@ -5962,7 +6486,7 @@ var init_stdio_grok_billing_client = __esm({
|
|
|
5962
6486
|
{ cause: error }
|
|
5963
6487
|
);
|
|
5964
6488
|
}
|
|
5965
|
-
throw
|
|
6489
|
+
throw unavailableError4(error);
|
|
5966
6490
|
} finally {
|
|
5967
6491
|
peer.close();
|
|
5968
6492
|
}
|
|
@@ -6006,7 +6530,7 @@ var init_stdio_grok_billing_client = __esm({
|
|
|
6006
6530
|
this.#timeoutMs = timeoutMs;
|
|
6007
6531
|
process2.stdout.setEncoding("utf8");
|
|
6008
6532
|
process2.stdout.on("data", (chunk) => this.#consume(chunk));
|
|
6009
|
-
process2.once("error", (error) => this.#fail(
|
|
6533
|
+
process2.once("error", (error) => this.#fail(unavailableError4(error)));
|
|
6010
6534
|
process2.once("exit", (code, signal) => {
|
|
6011
6535
|
if (this.#closed) return;
|
|
6012
6536
|
this.#fail(
|
|
@@ -6044,7 +6568,7 @@ var init_stdio_grok_billing_client = __esm({
|
|
|
6044
6568
|
this.#closed = true;
|
|
6045
6569
|
for (const pending of this.#pending.values()) {
|
|
6046
6570
|
clearTimeout(pending.timeout);
|
|
6047
|
-
pending.reject(
|
|
6571
|
+
pending.reject(unavailableError4(new Error("Grok ACP connection closed")));
|
|
6048
6572
|
}
|
|
6049
6573
|
this.#pending.clear();
|
|
6050
6574
|
this.#process.kill();
|
|
@@ -6272,7 +6796,7 @@ function endpointFailure(error, label) {
|
|
|
6272
6796
|
recovery: "Check network access and xAI status, then retry."
|
|
6273
6797
|
};
|
|
6274
6798
|
}
|
|
6275
|
-
function
|
|
6799
|
+
function safeFailure9(error) {
|
|
6276
6800
|
if (error instanceof Error && "code" in error && typeof error.code === "string" && "recovery" in error && typeof error.recovery === "string") {
|
|
6277
6801
|
return { code: error.code, message: error.message, recovery: error.recovery };
|
|
6278
6802
|
}
|
|
@@ -6527,7 +7051,7 @@ var init_xai_api_connector = __esm({
|
|
|
6527
7051
|
costs: [],
|
|
6528
7052
|
balances: [],
|
|
6529
7053
|
invoices: [],
|
|
6530
|
-
warnings: [
|
|
7054
|
+
warnings: [safeFailure9(error)],
|
|
6531
7055
|
observedAt
|
|
6532
7056
|
};
|
|
6533
7057
|
}
|
|
@@ -6624,10 +7148,10 @@ var init_ecb_exchange_rate_provider = __esm({
|
|
|
6624
7148
|
});
|
|
6625
7149
|
|
|
6626
7150
|
// src/server/keychain-secret-store.ts
|
|
6627
|
-
import { spawn as
|
|
7151
|
+
import { spawn as spawn6 } from "child_process";
|
|
6628
7152
|
async function runSecurityCommand(arguments_, input) {
|
|
6629
7153
|
return await new Promise((resolveResult, reject) => {
|
|
6630
|
-
const child =
|
|
7154
|
+
const child = spawn6("/usr/bin/security", arguments_, {
|
|
6631
7155
|
stdio: ["pipe", "pipe", "ignore"]
|
|
6632
7156
|
});
|
|
6633
7157
|
let output = "";
|
|
@@ -6698,7 +7222,7 @@ var init_keychain_secret_store = __esm({
|
|
|
6698
7222
|
});
|
|
6699
7223
|
|
|
6700
7224
|
// src/server/macos-notifier.ts
|
|
6701
|
-
import { spawn as
|
|
7225
|
+
import { spawn as spawn7 } from "child_process";
|
|
6702
7226
|
var MacOsNotifier;
|
|
6703
7227
|
var init_macos_notifier = __esm({
|
|
6704
7228
|
"src/server/macos-notifier.ts"() {
|
|
@@ -6706,7 +7230,7 @@ var init_macos_notifier = __esm({
|
|
|
6706
7230
|
MacOsNotifier = class {
|
|
6707
7231
|
async notify(event) {
|
|
6708
7232
|
await new Promise((resolve5, reject) => {
|
|
6709
|
-
const child =
|
|
7233
|
+
const child = spawn7(
|
|
6710
7234
|
"/usr/bin/osascript",
|
|
6711
7235
|
[
|
|
6712
7236
|
"-e",
|
|
@@ -6726,8 +7250,8 @@ var init_macos_notifier = __esm({
|
|
|
6726
7250
|
});
|
|
6727
7251
|
|
|
6728
7252
|
// src/server/macos-start-at-login-manager.ts
|
|
6729
|
-
import { mkdir as mkdir4, rm, writeFile as
|
|
6730
|
-
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";
|
|
6731
7255
|
function launchAgentPlist(options) {
|
|
6732
7256
|
const label = options.label ?? LABEL;
|
|
6733
7257
|
const arguments_ = [
|
|
@@ -6779,15 +7303,15 @@ var init_macos_start_at_login_manager = __esm({
|
|
|
6779
7303
|
const label = validateLaunchAgentLabel(options.label ?? LABEL);
|
|
6780
7304
|
if (options.nodeImport) validateNodeImport(options.nodeImport);
|
|
6781
7305
|
this.#options = { ...options, label };
|
|
6782
|
-
this.#path =
|
|
7306
|
+
this.#path = join8(options.userHome, "Library", "LaunchAgents", `${label}.plist`);
|
|
6783
7307
|
}
|
|
6784
7308
|
async setEnabled(enabled) {
|
|
6785
7309
|
if (!enabled) {
|
|
6786
|
-
await
|
|
7310
|
+
await rm2(this.#path, { force: true });
|
|
6787
7311
|
return;
|
|
6788
7312
|
}
|
|
6789
7313
|
await mkdir4(dirname3(this.#path), { recursive: true, mode: 448 });
|
|
6790
|
-
await
|
|
7314
|
+
await writeFile5(this.#path, launchAgentPlist(this.#options), { mode: 384 });
|
|
6791
7315
|
}
|
|
6792
7316
|
async isEnabled() {
|
|
6793
7317
|
try {
|
|
@@ -6904,7 +7428,7 @@ var init_otlp_protobuf = __esm({
|
|
|
6904
7428
|
// src/server/local-server.ts
|
|
6905
7429
|
import { createReadStream as createReadStream2, existsSync, statSync } from "fs";
|
|
6906
7430
|
import { createServer } from "http";
|
|
6907
|
-
import { extname, join as
|
|
7431
|
+
import { extname, join as join9, normalize, resolve } from "path";
|
|
6908
7432
|
import { randomBytes } from "crypto";
|
|
6909
7433
|
import { z as z9 } from "zod";
|
|
6910
7434
|
async function startLocalServer(options) {
|
|
@@ -7270,8 +7794,8 @@ async function serveStatic(response, pathname, staticDirectory) {
|
|
|
7270
7794
|
const root = resolve(staticDirectory);
|
|
7271
7795
|
const requested = pathname === "/" ? "index.html" : pathname.replace(/^\/+/, "");
|
|
7272
7796
|
const normalized = normalize(requested);
|
|
7273
|
-
const candidate = resolve(
|
|
7274
|
-
const indexFile =
|
|
7797
|
+
const candidate = resolve(join9(root, normalized));
|
|
7798
|
+
const indexFile = join9(root, "index.html");
|
|
7275
7799
|
const file = candidate.startsWith(`${root}/`) && existsSync(candidate) && statSync(candidate).isFile() ? candidate : indexFile;
|
|
7276
7800
|
if (!existsSync(file)) {
|
|
7277
7801
|
sendText(response, 404, "Dashboard assets are not built");
|
|
@@ -7382,7 +7906,7 @@ var init_local_server = __esm({
|
|
|
7382
7906
|
// src/server/path-discovery-probe.ts
|
|
7383
7907
|
import { constants } from "fs";
|
|
7384
7908
|
import { access } from "fs/promises";
|
|
7385
|
-
import { delimiter, isAbsolute as isAbsolute2, join as
|
|
7909
|
+
import { delimiter, isAbsolute as isAbsolute2, join as join10, resolve as resolve2 } from "path";
|
|
7386
7910
|
async function isExecutable(path) {
|
|
7387
7911
|
try {
|
|
7388
7912
|
await access(path, constants.X_OK);
|
|
@@ -7428,7 +7952,7 @@ var init_path_discovery_probe = __esm({
|
|
|
7428
7952
|
async #findExecutable(command) {
|
|
7429
7953
|
if (command.includes("/")) return await isExecutable(command) ? resolve2(command) : null;
|
|
7430
7954
|
for (const directory of this.#path.split(delimiter).filter(Boolean)) {
|
|
7431
|
-
const candidate =
|
|
7955
|
+
const candidate = join10(directory, command);
|
|
7432
7956
|
if (await isExecutable(candidate)) return candidate;
|
|
7433
7957
|
}
|
|
7434
7958
|
return null;
|
|
@@ -7622,8 +8146,10 @@ function mapQuotaRow(row) {
|
|
|
7622
8146
|
billingDomainId: row.billing_domain_id,
|
|
7623
8147
|
label: row.label,
|
|
7624
8148
|
usedPercent: clampPercent(row.used_percent),
|
|
8149
|
+
usedAmount: row.used_amount,
|
|
7625
8150
|
windowDurationMinutes: row.window_duration_minutes,
|
|
7626
8151
|
resetsAt: row.resets_at,
|
|
8152
|
+
resetLabel: row.reset_label,
|
|
7627
8153
|
authority: row.authority,
|
|
7628
8154
|
observedAt: row.observed_at,
|
|
7629
8155
|
scope: row.scope ?? void 0,
|
|
@@ -8034,7 +8560,11 @@ function allDomainHistories(providers) {
|
|
|
8034
8560
|
provider,
|
|
8035
8561
|
domain,
|
|
8036
8562
|
history: domain.history,
|
|
8037
|
-
includedInHeadline:
|
|
8563
|
+
includedInHeadline: billingDomainIncludedInHeadline(
|
|
8564
|
+
provider.id,
|
|
8565
|
+
domain.id,
|
|
8566
|
+
provider.summaryBillingDomainId
|
|
8567
|
+
)
|
|
8038
8568
|
}))
|
|
8039
8569
|
);
|
|
8040
8570
|
}
|
|
@@ -8797,6 +9327,11 @@ function tokenCoverage(tokens, excludedObservationCount = 0) {
|
|
|
8797
9327
|
);
|
|
8798
9328
|
return scopes.includes("this-mac") || temporalities.includes("delta") ? "partial" : "complete";
|
|
8799
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
|
+
}
|
|
8800
9335
|
function selectSummaryBillingDomainId(providerId, domains) {
|
|
8801
9336
|
if (providerId === "grok") {
|
|
8802
9337
|
return domains.find((domain) => domain.id === "grok-build-subscription")?.id ?? domains[0]?.id ?? null;
|
|
@@ -8926,16 +9461,18 @@ var init_sqlite_usage_repository = __esm({
|
|
|
8926
9461
|
}
|
|
8927
9462
|
const quotaStatement = this.#database.prepare(
|
|
8928
9463
|
`INSERT INTO quota_buckets (
|
|
8929
|
-
provider_id, id, billing_domain_id, label, used_percent,
|
|
8930
|
-
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,
|
|
8931
9466
|
scope, status, limit_amount, limit_currency, fallback_status
|
|
8932
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
9467
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
8933
9468
|
ON CONFLICT(provider_id, id) DO UPDATE SET
|
|
8934
9469
|
billing_domain_id = excluded.billing_domain_id,
|
|
8935
9470
|
label = excluded.label,
|
|
8936
9471
|
used_percent = excluded.used_percent,
|
|
9472
|
+
used_amount = excluded.used_amount,
|
|
8937
9473
|
window_duration_minutes = excluded.window_duration_minutes,
|
|
8938
9474
|
resets_at = excluded.resets_at,
|
|
9475
|
+
reset_label = excluded.reset_label,
|
|
8939
9476
|
authority = excluded.authority,
|
|
8940
9477
|
observed_at = excluded.observed_at,
|
|
8941
9478
|
scope = excluded.scope,
|
|
@@ -8945,19 +9482,22 @@ var init_sqlite_usage_repository = __esm({
|
|
|
8945
9482
|
fallback_status = excluded.fallback_status`
|
|
8946
9483
|
);
|
|
8947
9484
|
const reportedQuotaDomains = [
|
|
8948
|
-
|
|
9485
|
+
.../* @__PURE__ */ new Set([
|
|
9486
|
+
...snapshot2.completeQuotaBillingDomainIds ?? [],
|
|
9487
|
+
...snapshot2.quotaBuckets.map((bucket) => bucket.billingDomainId)
|
|
9488
|
+
])
|
|
8949
9489
|
];
|
|
8950
9490
|
if (reportedQuotaDomains.length > 0) {
|
|
8951
|
-
const retiredQuotaStatement = this.#database.prepare(
|
|
8952
|
-
`DELETE FROM quota_buckets
|
|
8953
|
-
WHERE provider_id = ? AND billing_domain_id = ? AND id NOT IN (${snapshot2.quotaBuckets.map(() => "?").join(", ")})`
|
|
8954
|
-
);
|
|
8955
9491
|
for (const billingDomainId of reportedQuotaDomains) {
|
|
8956
|
-
|
|
8957
|
-
|
|
8958
|
-
billingDomainId
|
|
8959
|
-
|
|
8960
|
-
|
|
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);
|
|
8961
9501
|
}
|
|
8962
9502
|
}
|
|
8963
9503
|
for (const bucket of snapshot2.quotaBuckets) {
|
|
@@ -8968,8 +9508,10 @@ var init_sqlite_usage_repository = __esm({
|
|
|
8968
9508
|
bucket.billingDomainId,
|
|
8969
9509
|
bucket.label,
|
|
8970
9510
|
clampedUsedPercent,
|
|
9511
|
+
bucket.usedAmount ?? null,
|
|
8971
9512
|
bucket.windowDurationMinutes ?? null,
|
|
8972
9513
|
bucket.resetsAt,
|
|
9514
|
+
bucket.resetLabel ?? null,
|
|
8973
9515
|
bucket.authority,
|
|
8974
9516
|
snapshot2.observedAt,
|
|
8975
9517
|
bucket.scope ?? null,
|
|
@@ -9422,11 +9964,15 @@ var init_sqlite_usage_repository = __esm({
|
|
|
9422
9964
|
FROM billing_domains WHERE provider_id = ? ORDER BY id`
|
|
9423
9965
|
).all(provider.id);
|
|
9424
9966
|
const summaryBillingDomainId = selectSummaryBillingDomainId(provider.id, domains);
|
|
9425
|
-
|
|
9426
|
-
|
|
9427
|
-
|
|
9428
|
-
|
|
9429
|
-
|
|
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
|
+
}
|
|
9430
9976
|
}
|
|
9431
9977
|
const totals = /* @__PURE__ */ new Map();
|
|
9432
9978
|
const addContribution = (date, providerId, displayName, recordedTokens2) => {
|
|
@@ -9959,8 +10505,8 @@ var init_sqlite_usage_repository = __esm({
|
|
|
9959
10505
|
}
|
|
9960
10506
|
#getBillingDomainOverview(providerId, domain, now, query, forecasts, forecastCoverage, degradedDiagnostic, legacyProviderFailure = null) {
|
|
9961
10507
|
const quotaRows = this.#database.prepare(
|
|
9962
|
-
`SELECT id, billing_domain_id, label, used_percent,
|
|
9963
|
-
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,
|
|
9964
10510
|
scope, status, limit_amount, limit_currency, fallback_status
|
|
9965
10511
|
FROM quota_buckets WHERE provider_id = ? AND billing_domain_id = ? ORDER BY id`
|
|
9966
10512
|
).all(providerId, domain.id);
|
|
@@ -10393,9 +10939,11 @@ var init_sqlite_usage_repository = __esm({
|
|
|
10393
10939
|
observed_at TEXT NOT NULL,
|
|
10394
10940
|
scope TEXT,
|
|
10395
10941
|
status TEXT,
|
|
10942
|
+
used_amount REAL,
|
|
10396
10943
|
limit_amount REAL,
|
|
10397
10944
|
limit_currency TEXT,
|
|
10398
10945
|
fallback_status TEXT,
|
|
10946
|
+
reset_label TEXT,
|
|
10399
10947
|
total_tokens INTEGER NOT NULL DEFAULT 0,
|
|
10400
10948
|
PRIMARY KEY (provider_id, id),
|
|
10401
10949
|
FOREIGN KEY (provider_id, billing_domain_id)
|
|
@@ -10744,9 +11292,11 @@ var init_sqlite_usage_repository = __esm({
|
|
|
10744
11292
|
["window_duration_minutes", "INTEGER"],
|
|
10745
11293
|
["scope", "TEXT"],
|
|
10746
11294
|
["status", "TEXT"],
|
|
11295
|
+
["used_amount", "REAL"],
|
|
10747
11296
|
["limit_amount", "REAL"],
|
|
10748
11297
|
["limit_currency", "TEXT"],
|
|
10749
|
-
["fallback_status", "TEXT"]
|
|
11298
|
+
["fallback_status", "TEXT"],
|
|
11299
|
+
["reset_label", "TEXT"]
|
|
10750
11300
|
]) {
|
|
10751
11301
|
if (!quotaColumns.some((column) => column.name === name)) {
|
|
10752
11302
|
this.#database.exec(`ALTER TABLE quota_buckets ADD COLUMN ${name} ${type}`);
|
|
@@ -10763,14 +11313,14 @@ __export(runtime_exports, {
|
|
|
10763
11313
|
runDaemon: () => runDaemon
|
|
10764
11314
|
});
|
|
10765
11315
|
import { existsSync as existsSync2 } from "fs";
|
|
10766
|
-
import { mkdir as mkdir5, rm as
|
|
11316
|
+
import { mkdir as mkdir5, rm as rm3 } from "fs/promises";
|
|
10767
11317
|
import { homedir as homedir4 } from "os";
|
|
10768
|
-
import { isAbsolute as isAbsolute3, join as
|
|
11318
|
+
import { isAbsolute as isAbsolute3, join as join11, resolve as resolve3 } from "path";
|
|
10769
11319
|
import { fileURLToPath } from "url";
|
|
10770
11320
|
async function runDaemon(home) {
|
|
10771
11321
|
await mkdir5(home, { recursive: true, mode: 448 });
|
|
10772
11322
|
const demoEnabled = process.env.AGENT_USAGE_DEMO === "1";
|
|
10773
|
-
const repository = new SqliteUsageRepository(
|
|
11323
|
+
const repository = new SqliteUsageRepository(join11(home, "usage.sqlite"), {
|
|
10774
11324
|
hideDemoProvider: !demoEnabled
|
|
10775
11325
|
});
|
|
10776
11326
|
const keychainService = process.env.AGENT_USAGE_KEYCHAIN_SERVICE;
|
|
@@ -10809,11 +11359,15 @@ async function runDaemon(home) {
|
|
|
10809
11359
|
new AntigravityConnector({
|
|
10810
11360
|
historyClient: new AntigravitySqliteUsageClient({
|
|
10811
11361
|
roots: [
|
|
10812
|
-
|
|
10813
|
-
|
|
11362
|
+
join11(homedir4(), ".gemini/antigravity-cli"),
|
|
11363
|
+
join11(homedir4(), ".gemini/antigravity")
|
|
10814
11364
|
],
|
|
10815
|
-
cachePath:
|
|
11365
|
+
cachePath: join11(home, "antigravity-usage-cache.json")
|
|
10816
11366
|
})
|
|
11367
|
+
}),
|
|
11368
|
+
new CursorConnector({
|
|
11369
|
+
quotaClient: new ScreenReaderCursorQuotaClient(),
|
|
11370
|
+
accountClient: new CursorAboutAccountClient()
|
|
10817
11371
|
})
|
|
10818
11372
|
],
|
|
10819
11373
|
connectorDefinitions: defaultConnectorDefinitions,
|
|
@@ -10845,10 +11399,14 @@ async function runDaemon(home) {
|
|
|
10845
11399
|
"grok",
|
|
10846
11400
|
"xai-api",
|
|
10847
11401
|
"dsh",
|
|
10848
|
-
"antigravity"
|
|
11402
|
+
"antigravity",
|
|
11403
|
+
"cursor"
|
|
10849
11404
|
].map((id) => [
|
|
10850
11405
|
id,
|
|
10851
|
-
{
|
|
11406
|
+
{
|
|
11407
|
+
minimumIntervalMs: 5 * 60 * 1e3,
|
|
11408
|
+
timeoutMs: id === "claude-code" || id === "cursor" ? 25e3 : 2e4
|
|
11409
|
+
}
|
|
10852
11410
|
])
|
|
10853
11411
|
),
|
|
10854
11412
|
telemetryIngestors: [
|
|
@@ -10897,7 +11455,7 @@ async function runDaemon(home) {
|
|
|
10897
11455
|
scheduler.stop();
|
|
10898
11456
|
await server.close();
|
|
10899
11457
|
repository.close();
|
|
10900
|
-
await
|
|
11458
|
+
await rm3(join11(home, "daemon.json"), { force: true });
|
|
10901
11459
|
resolveStop();
|
|
10902
11460
|
};
|
|
10903
11461
|
process.once("SIGTERM", () => void stop());
|
|
@@ -10908,27 +11466,27 @@ function localTranscriptClient(provider, applicationHome) {
|
|
|
10908
11466
|
return new LocalTranscriptUsageClient({
|
|
10909
11467
|
provider,
|
|
10910
11468
|
roots: localTranscriptRoots(provider),
|
|
10911
|
-
cachePath:
|
|
11469
|
+
cachePath: join11(applicationHome, "cache", `${provider}-transcripts.json`)
|
|
10912
11470
|
});
|
|
10913
11471
|
}
|
|
10914
11472
|
function localTranscriptRoots(provider) {
|
|
10915
11473
|
if (provider === "codex") {
|
|
10916
11474
|
const home = resolveHomeOverride(process.env.CODEX_HOME, ".codex");
|
|
10917
|
-
return [
|
|
11475
|
+
return [join11(home, "sessions"), join11(home, "archived_sessions")];
|
|
10918
11476
|
}
|
|
10919
11477
|
if (provider === "claude-code") {
|
|
10920
|
-
return [
|
|
11478
|
+
return [join11(resolveHomeOverride(process.env.CLAUDE_CONFIG_DIR, ".claude"), "projects")];
|
|
10921
11479
|
}
|
|
10922
11480
|
if (provider === "dsh") {
|
|
10923
|
-
return [
|
|
11481
|
+
return [join11(resolveHomeOverride(process.env.DSH_HOME, ".dsh"), "sessions")];
|
|
10924
11482
|
}
|
|
10925
|
-
return [
|
|
11483
|
+
return [join11(resolveHomeOverride(process.env.GROK_HOME, ".grok"), "sessions")];
|
|
10926
11484
|
}
|
|
10927
11485
|
function resolveHomeOverride(value, fallback) {
|
|
10928
11486
|
const configured = value?.trim();
|
|
10929
|
-
if (!configured) return
|
|
11487
|
+
if (!configured) return join11(homedir4(), fallback);
|
|
10930
11488
|
if (configured === "~") return homedir4();
|
|
10931
|
-
if (configured.startsWith("~/")) return
|
|
11489
|
+
if (configured.startsWith("~/")) return join11(homedir4(), configured.slice(2));
|
|
10932
11490
|
return isAbsolute3(configured) ? configured : resolve3(configured);
|
|
10933
11491
|
}
|
|
10934
11492
|
function createDemoConnector() {
|
|
@@ -10974,7 +11532,7 @@ function locateStaticDirectory() {
|
|
|
10974
11532
|
fileURLToPath(new URL("./web", import.meta.url)),
|
|
10975
11533
|
fileURLToPath(new URL("../../dist/web", import.meta.url))
|
|
10976
11534
|
];
|
|
10977
|
-
return candidates.find((candidate) => existsSync2(
|
|
11535
|
+
return candidates.find((candidate) => existsSync2(join11(candidate, "index.html")));
|
|
10978
11536
|
}
|
|
10979
11537
|
var init_runtime = __esm({
|
|
10980
11538
|
"src/server/runtime.ts"() {
|
|
@@ -10993,6 +11551,9 @@ var init_runtime = __esm({
|
|
|
10993
11551
|
init_opencode_go_connector();
|
|
10994
11552
|
init_dsh_connector();
|
|
10995
11553
|
init_antigravity_connector();
|
|
11554
|
+
init_cursor_about_client();
|
|
11555
|
+
init_cursor_connector();
|
|
11556
|
+
init_cursor_usage_screen_client();
|
|
10996
11557
|
init_antigravity_sqlite_usage_client();
|
|
10997
11558
|
init_grok_build_connector();
|
|
10998
11559
|
init_grok_telemetry();
|
|
@@ -11012,14 +11573,73 @@ var init_runtime = __esm({
|
|
|
11012
11573
|
});
|
|
11013
11574
|
|
|
11014
11575
|
// src/cli.ts
|
|
11015
|
-
|
|
11016
|
-
init_daemon_state();
|
|
11017
|
-
import { spawn as spawn6 } from "child_process";
|
|
11576
|
+
import { spawn as spawn8 } from "child_process";
|
|
11018
11577
|
import { connect as tcpConnect } from "net";
|
|
11019
11578
|
import { homedir as homedir5 } from "os";
|
|
11020
|
-
import { join as
|
|
11579
|
+
import { join as join12, resolve as resolve4 } from "path";
|
|
11021
11580
|
import { Command } from "commander";
|
|
11022
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();
|
|
11023
11643
|
var program = new Command();
|
|
11024
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");
|
|
11025
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) => {
|
|
@@ -11331,7 +11951,7 @@ async function ensureDaemon(home) {
|
|
|
11331
11951
|
return await requireDaemonState(home);
|
|
11332
11952
|
} catch {
|
|
11333
11953
|
process.stderr.write("Agent Usage: starting local web service\u2026\n");
|
|
11334
|
-
const child =
|
|
11954
|
+
const child = spawn8(
|
|
11335
11955
|
process.execPath,
|
|
11336
11956
|
[...process.execArgv, process.argv[1], "--home", home, "serve"],
|
|
11337
11957
|
{
|
|
@@ -11398,7 +12018,7 @@ function formatOverview(overview) {
|
|
|
11398
12018
|
` : "";
|
|
11399
12019
|
return `${summary}${recommendation}${overview.providers.map((provider) => {
|
|
11400
12020
|
const quota = provider.quotaBuckets.map(
|
|
11401
|
-
(bucket) => `${bucket.label}: ${bucket
|
|
12021
|
+
(bucket) => `${bucket.label}: ${formatQuotaBucket(bucket)} (${formatEvidence(
|
|
11402
12022
|
bucket.authority,
|
|
11403
12023
|
bucket.observedAt ?? provider.freshness.lastSuccessAt
|
|
11404
12024
|
)})`
|
|
@@ -11458,6 +12078,15 @@ function formatTokenEvidence(evidence) {
|
|
|
11458
12078
|
function formatEvidence(authority, observedAt) {
|
|
11459
12079
|
return `source ${authority} at ${observedAt ?? "unknown time"}`;
|
|
11460
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
|
+
}
|
|
11461
12090
|
function formatDoctor(report) {
|
|
11462
12091
|
const providerLines = report.providers.map(
|
|
11463
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`
|
|
@@ -11473,6 +12102,6 @@ function formatDoctor(report) {
|
|
|
11473
12102
|
].join("\n");
|
|
11474
12103
|
}
|
|
11475
12104
|
function defaultHome() {
|
|
11476
|
-
return
|
|
12105
|
+
return join12(homedir5(), "Library", "Application Support", "Agent Usage");
|
|
11477
12106
|
}
|
|
11478
12107
|
//# sourceMappingURL=cli.js.map
|