@hashimkarim/usagestat-linux-x64-gnu 2.0.0-alpha.3 → 2.0.0-alpha.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/native-manifest.json +731 -65
  2. package/package.json +112 -1
  3. package/plugins/UPSTREAM-LICENSES.md +6 -2
  4. package/plugins/_provider-icons/LICENSE +21 -0
  5. package/plugins/_provider-icons/NOTICE +12 -0
  6. package/plugins/_provider-icons/licenses/CodexBar-MIT.txt +21 -0
  7. package/plugins/_provider-icons/licenses/LobeHub-MIT.txt +21 -0
  8. package/plugins/_provider-icons/licenses/UsageStat-Bar-MIT.txt +21 -0
  9. package/plugins/_provider-icons/manifest.json +1219 -0
  10. package/plugins/_provider-icons/provenance.json +269 -0
  11. package/plugins/_provider-icons/source.json +4 -0
  12. package/plugins/abacus-ai/icon-color.svg +18 -0
  13. package/plugins/aixy/LICENSE +21 -0
  14. package/plugins/aixy/plugin.js +261 -0
  15. package/plugins/aixy/plugin.json +24 -0
  16. package/plugins/antigravity/plugin.js +136 -46
  17. package/plugins/antigravity-cli/icon-color.svg +1 -0
  18. package/plugins/antigravity-cli/icon.svg +1 -3
  19. package/plugins/antigravity-cli/plugin.js +11 -15
  20. package/plugins/antigravity-ide/icon-color.svg +1 -0
  21. package/plugins/antigravity-ide/icon.svg +1 -3
  22. package/plugins/atlascloud/LICENSE +21 -0
  23. package/plugins/atlascloud/icon-color.svg +1 -0
  24. package/plugins/atlascloud/icon.svg +1 -0
  25. package/plugins/atlascloud/plugin.js +49 -0
  26. package/plugins/atlascloud/plugin.json +23 -0
  27. package/plugins/augment/icon-color.svg +14 -0
  28. package/plugins/bifrost/LICENSE +21 -0
  29. package/plugins/bifrost/plugin.js +361 -0
  30. package/plugins/bifrost/plugin.json +23 -0
  31. package/plugins/claude/plugin.js +302 -152
  32. package/plugins/claude/plugin.json +1 -1
  33. package/plugins/clinepass/plugin.js +19 -3
  34. package/plugins/codebuff/icon-color.svg +92 -0
  35. package/plugins/coderabbit/plugin.js +25 -0
  36. package/plugins/coderabbit/plugin.json +12 -0
  37. package/plugins/codex/plugin.js +1 -0
  38. package/plugins/command-code/icon-color.svg +3 -0
  39. package/plugins/command-code/plugin.js +7 -3
  40. package/plugins/copilot/icon.svg +1 -1
  41. package/plugins/crof/icon-color.svg +3 -0
  42. package/plugins/crofai/icon-color.svg +3 -0
  43. package/plugins/crofai/icon.svg +2 -15
  44. package/plugins/cursor/icon-color.svg +1 -0
  45. package/plugins/deepinfra/icon-color.svg +1 -0
  46. package/plugins/deepinfra/icon.svg +1 -4
  47. package/plugins/deepseek/plugin.js +150 -59
  48. package/plugins/deepseek/plugin.json +3 -1
  49. package/plugins/devin/plugin.js +3 -0
  50. package/plugins/devpass/LICENSE +21 -0
  51. package/plugins/devpass/plugin.js +115 -0
  52. package/plugins/devpass/plugin.json +23 -0
  53. package/plugins/elevenlabs/icon-color.svg +4 -0
  54. package/plugins/factory/icon-color.svg +1 -0
  55. package/plugins/fireworks-ai/icon-color.svg +1 -0
  56. package/plugins/fireworks-ai/icon.svg +1 -6
  57. package/plugins/gemini-apps/LICENSE +22 -0
  58. package/plugins/gemini-apps/icon-color.svg +1 -0
  59. package/plugins/gemini-apps/icon.svg +1 -0
  60. package/plugins/gemini-apps/plugin.js +470 -0
  61. package/plugins/gemini-apps/plugin.json +19 -0
  62. package/plugins/gitkraken/LICENSE +21 -0
  63. package/plugins/gitkraken/plugin.js +153 -0
  64. package/plugins/gitkraken/plugin.json +24 -0
  65. package/plugins/grok/icon-color.svg +1 -0
  66. package/plugins/groqcloud/icon-color.svg +1 -0
  67. package/plugins/helmcode/LICENSE +21 -0
  68. package/plugins/helmcode/plugin.js +188 -0
  69. package/plugins/helmcode/plugin.json +24 -0
  70. package/plugins/huggingface/LICENSE +21 -0
  71. package/plugins/huggingface/icon-color.svg +1 -0
  72. package/plugins/huggingface/icon.svg +1 -0
  73. package/plugins/huggingface/plugin.js +293 -0
  74. package/plugins/huggingface/plugin.json +25 -0
  75. package/plugins/hyper/LICENSE +21 -0
  76. package/plugins/hyper/plugin.js +131 -0
  77. package/plugins/hyper/plugin.json +26 -0
  78. package/plugins/kilo/icon-color.svg +1 -0
  79. package/plugins/litellm/plugin.js +54 -3
  80. package/plugins/llmman/LICENSE +21 -0
  81. package/plugins/llmman/plugin.js +133 -0
  82. package/plugins/llmman/plugin.json +23 -0
  83. package/plugins/longcat/icon-color.svg +1 -0
  84. package/plugins/longcat/icon.svg +1 -4
  85. package/plugins/manus/icon-color.svg +6 -0
  86. package/plugins/mimo/icon-color.svg +4 -0
  87. package/plugins/mimo/icon.svg +4 -1
  88. package/plugins/mistral/plugin.js +110 -5
  89. package/plugins/moonshot/icon-color.svg +1 -0
  90. package/plugins/muse/LICENSE +21 -0
  91. package/plugins/muse/plugin.js +319 -0
  92. package/plugins/muse/plugin.json +26 -0
  93. package/plugins/nous/LICENSE +21 -0
  94. package/plugins/nous/icon-color.svg +1 -0
  95. package/plugins/nous/icon.svg +1 -0
  96. package/plugins/nous/plugin.js +124 -0
  97. package/plugins/nous/plugin.json +24 -0
  98. package/plugins/ollama/icon-color.svg +1 -0
  99. package/plugins/openai-api/icon-color.svg +1 -0
  100. package/plugins/opencode/icon-color.svg +1 -0
  101. package/plugins/opencode-go/icon-color.svg +1 -0
  102. package/plugins/opencode-go/plugin.js +30 -12
  103. package/plugins/openrouter/icon-color.svg +1 -0
  104. package/plugins/pi/plugin.js +113 -0
  105. package/plugins/pi/plugin.json +11 -0
  106. package/plugins/qwencloud/icon-color.svg +1 -0
  107. package/plugins/qwencloud/icon.svg +1 -4
  108. package/plugins/raycast/LICENSE +21 -0
  109. package/plugins/raycast/plugin.js +174 -0
  110. package/plugins/raycast/plugin.json +24 -0
  111. package/plugins/replicate/LICENSE +21 -0
  112. package/plugins/replicate/icon-color.svg +1 -0
  113. package/plugins/replicate/icon.svg +1 -0
  114. package/plugins/replicate/plugin.js +165 -0
  115. package/plugins/replicate/plugin.json +24 -0
  116. package/plugins/synthetic/icon-color.svg +14 -0
  117. package/plugins/typesafe/LICENSE +21 -0
  118. package/plugins/typesafe/plugin.js +225 -0
  119. package/plugins/typesafe/plugin.json +24 -0
  120. package/plugins/v0/LICENSE +21 -0
  121. package/plugins/v0/icon-color.svg +1 -0
  122. package/plugins/v0/icon.svg +1 -0
  123. package/plugins/v0/plugin.js +214 -0
  124. package/plugins/v0/plugin.json +24 -0
  125. package/plugins/venice/plugin.js +50 -1
  126. package/plugins/venice/plugin.json +2 -1
  127. package/plugins/vercel/LICENSE +21 -0
  128. package/plugins/vercel/icon-color.svg +1 -0
  129. package/plugins/vercel/icon.svg +1 -0
  130. package/plugins/vercel/plugin.js +55 -0
  131. package/plugins/vercel/plugin.json +23 -0
  132. package/plugins/windsurf/icon-color.svg +1 -0
  133. package/plugins/xai/icon-color.svg +1 -0
  134. package/plugins/xai/icon.svg +1 -7
  135. package/plugins/xkiro/LICENSE +21 -0
  136. package/plugins/xkiro/plugin.js +99 -0
  137. package/plugins/xkiro/plugin.json +23 -0
  138. package/plugins/zai/icon-color.svg +1 -0
  139. package/plugins/zenmux/icon-color.svg +1 -0
  140. package/plugins/zenmux/icon.svg +1 -3
  141. package/usagestat +0 -0
  142. package/usagestatd +0 -0
@@ -0,0 +1,361 @@
1
+ // Generated by tools/vendor-codexbar-providers.cjs; see LICENSE.
2
+ globalThis.__usagestat_bundled_options = {"labels":["Budget","Secondary budget","Additional"],"defaults":{},"autoMode":"api"};
3
+ function _nullishCoalesce(lhs, rhsFn) {
4
+ if (lhs != null) {
5
+ return lhs;
6
+ } else {
7
+ return rhsFn();
8
+ }
9
+ }
10
+ function _optionalChain(ops) {
11
+ let lastAccessLHS = undefined;
12
+ let value = ops[0];
13
+ let i = 1;
14
+ while (i < ops.length) {
15
+ const op = ops[i];
16
+ const fn = ops[i + 1];
17
+ i += 2;
18
+ if ((op === "optionalAccess" || op === "optionalCall") && value == null) {
19
+ return undefined;
20
+ }
21
+ if (op === "access" || op === "optionalAccess") {
22
+ lastAccessLHS = value;
23
+ value = fn(value);
24
+ } else if (op === "call" || op === "optionalCall") {
25
+ value = fn((...args) => value.call(lastAccessLHS, ...args));
26
+ lastAccessLHS = undefined;
27
+ }
28
+ }
29
+ return value;
30
+ }
31
+ defineProvider({
32
+ id: "bifrost",
33
+ name: "Bifrost",
34
+ endpoints: [{ setting: "BIFROST_BASE_URL", policy: "https-or-private-network-http" }],
35
+ auth: { type: "header", header: "x-bf-vk", secret: "BIFROST_API_KEY" },
36
+ settings: [
37
+ { key: "BIFROST_API_KEY", title: "Virtual key", type: "secure" },
38
+ { key: "BIFROST_BASE_URL", title: "Base URL", type: "plain" },
39
+ ],
40
+ capabilities: ["http-status"],
41
+ async fetchUsage(ctx) {
42
+ const fail = (message) => {
43
+ throw ctx.fail.parseFailure(`Bifrost: ${message}`);
44
+ };
45
+ const object = (value) => {
46
+ if (!value || typeof value !== "object" || Array.isArray(value)) return fail("expected an object");
47
+ return value;
48
+ };
49
+ const array = (value) => {
50
+ if (value == null) return [];
51
+ if (!Array.isArray(value)) return fail("expected an array");
52
+ return value.map(object);
53
+ };
54
+ const text = (value) => {
55
+ if (value == null) return undefined;
56
+ if (typeof value !== "string") return fail("invalid string");
57
+ return value.trim() || undefined;
58
+ };
59
+ const number = (value) => {
60
+ if (value == null) return undefined;
61
+ if (typeof value !== "number" || !Number.isFinite(value)) return fail("invalid number");
62
+ return value;
63
+ };
64
+ const compare = (a, b) => (a < b ? -1 : a > b ? 1 : 0);
65
+ const bounded = (value) => Array.from(value).slice(0, 120).join("");
66
+ const labels = {
67
+ "1h": "Hourly",
68
+ "1d": "Daily",
69
+ "1w": "Weekly",
70
+ "1M": "Monthly",
71
+ "1Q": "Quarterly",
72
+ "1Y": "Yearly",
73
+ };
74
+ const units = {
75
+ Y: 31536000,
76
+ Q: 7776000,
77
+ M: 2592000,
78
+ w: 604800,
79
+ d: 86400,
80
+ h: 3600,
81
+ m: 60,
82
+ s: 1,
83
+ ms: 0.001,
84
+ us: 0.000001,
85
+ µs: 0.000001,
86
+ μs: 0.000001,
87
+ ns: 0.000000001,
88
+ };
89
+ const duration = (raw) => {
90
+ if (!raw) return undefined;
91
+ const extended = raw.match(/^(\d+(?:\.\d+)?)([dwMQY])$/u);
92
+ const parts = raw.match(/(?:\d+(?:\.\d*)?|\.\d+)(?:ns|us|µs|μs|ms|s|m|h)/gu);
93
+ let seconds;
94
+ if (extended) seconds = Number(extended[1]) * units[extended[2]];
95
+ else if (parts && parts.join("") === raw) {
96
+ seconds = parts.reduce((sum, part) => {
97
+ const match = part.match(/^([\d.]+)(.+)$/u);
98
+ return sum + Number(match[1]) * units[match[2]];
99
+ }, 0);
100
+ }
101
+ return seconds !== undefined && Number.isFinite(seconds) && seconds > 0 ? seconds : undefined;
102
+ };
103
+ const timing = (reset, lastReset) => {
104
+ const raw = text(reset),
105
+ seconds = duration(raw),
106
+ last = text(lastReset);
107
+ // The quota endpoint omits the owner's calendar-alignment policy. Do not invent calendar resets.
108
+ const fixed = raw !== undefined && !/[dwMQY]$/u.test(raw);
109
+ let resetsAt;
110
+ if (fixed && last && seconds) {
111
+ const start = new Date(last).getTime(),
112
+ period = seconds * 1000;
113
+ const next = new Date(
114
+ start + (Math.max(0, Math.floor((ctx.date.now().getTime() - start) / period)) + 1) * period,
115
+ );
116
+ if (Number.isFinite(next.getTime())) resetsAt = next;
117
+ }
118
+ const minutes = seconds === undefined ? 0 : Math.floor(seconds / 60);
119
+ return {
120
+ seconds,
121
+ resetsAt,
122
+ label: raw && Object.hasOwn(labels, raw) ? labels[raw] : undefined,
123
+ windowMinutes: fixed && Number.isSafeInteger(minutes) && minutes > 0 ? minutes : undefined,
124
+ };
125
+ };
126
+ const rawBase = ctx.settings.get("BIFROST_BASE_URL") || "";
127
+ const [base, suffix = ""] = rawBase.split(/(?=[?#])/u, 2);
128
+ let response;
129
+ try {
130
+ response = await ctx.http.get(`${base.replace(/\/+$/u, "")}/api/governance/virtual-keys/quota${suffix}`);
131
+ } catch (error) {
132
+ if (error.transportClass === "cancelled") throw error;
133
+ throw ctx.fail.networkFailure("Bifrost quota request could not reach the configured gateway.");
134
+ }
135
+ const message = `Bifrost quota request failed (HTTP ${response.status}).`;
136
+ if (response.status === 401) throw ctx.fail.authenticationExpired("Bifrost rejected the virtual key.");
137
+ if (response.status === 403) throw ctx.fail.permissionDenied("Bifrost denied access to this virtual key's quota.");
138
+ if (response.status === 429) throw ctx.fail.rateLimited(message);
139
+ if (response.status >= 500) throw ctx.fail.providerUnavailable(message);
140
+ if (response.status < 200 || response.status >= 300) throw ctx.fail.apiFailure(message);
141
+ let decoded;
142
+ try {
143
+ decoded = JSON.parse(response.bodyText);
144
+ } catch (error) {
145
+ void error;
146
+ return fail("invalid quota JSON");
147
+ }
148
+ const root = object(decoded);
149
+ if (root.is_active != null && typeof root.is_active !== "boolean") return fail("invalid key activity");
150
+ const scopes = [
151
+ { id: "", body: root },
152
+ ...array(root.provider_configs).map((body, index) => ({
153
+ id: `provider-${index}-`,
154
+ title: `Provider ${text(body.provider) || index + 1}`,
155
+ body,
156
+ })),
157
+ ...array(root.model_configs).map((body, index) => ({
158
+ id: `model-${index}-`,
159
+ title: `Model ${[text(body.provider), text(body.model_name) || index + 1].filter(Boolean).join(" · ")}`,
160
+ body,
161
+ })),
162
+ ];
163
+ const budgets = scopes
164
+ .flatMap((scope) =>
165
+ array(scope.body.budgets).flatMap((budget) => {
166
+ const id = text(budget.id);
167
+ if (!id) return [];
168
+ const amount = _nullishCoalesce(number(budget.override_amount), () => 0),
169
+ mode = text(budget.override_mode);
170
+ const cycles = _nullishCoalesce(number(budget.override_cycles_remaining), () => 0);
171
+ if (!Number.isInteger(cycles)) return fail("invalid override cycles");
172
+ const active = amount > 0 && (mode === "forever" || (mode === "cycles" && cycles > 0));
173
+ const limit = _nullishCoalesce(number(budget.max_limit), () => 0) + (active ? amount : 0);
174
+ if (!Number.isFinite(limit)) return fail("invalid effective budget");
175
+ return [
176
+ {
177
+ id,
178
+ scope,
179
+ source: text(budget.source_name),
180
+ limit,
181
+ used: _nullishCoalesce(number(budget.current_usage), () => 0),
182
+ timing: timing(budget.reset_duration, budget.last_reset),
183
+ models: array(budget.per_model_usage),
184
+ },
185
+ ];
186
+ }),
187
+ )
188
+ .sort(
189
+ (a, b) =>
190
+ _nullishCoalesce(a.timing.seconds, () => Infinity) - _nullishCoalesce(b.timing.seconds, () => Infinity) ||
191
+ compare(a.id, b.id),
192
+ );
193
+ const limits = scopes.flatMap((scope) => {
194
+ const components = array(scope.body.rate_limits);
195
+ // rate_limit is a compatibility merge of these components, not another pool.
196
+ const selected = components.length
197
+ ? components
198
+ : scope.body.rate_limit == null
199
+ ? []
200
+ : [object(scope.body.rate_limit)];
201
+ return selected.map((limit, index) => ({ scope, limit, index }));
202
+ });
203
+ if (root.is_active === false && !budgets.length && !limits.length) {
204
+ throw ctx.fail.permissionDenied("Bifrost virtual key is inactive and has no budgets or rate limits to display.");
205
+ }
206
+ const allWindows = budgets
207
+ .filter((budget) => budget.limit > 0)
208
+ .map((budget) => ({
209
+ id: `bifrost-${budget.scope.id}budget-${budget.id}`,
210
+ scope: budget.scope,
211
+ title: bounded([budget.scope.title, budget.source || "Budget"].filter(Boolean).join(" · ")),
212
+ window: {
213
+ usedPercent: ctx.pct(budget.used, budget.limit),
214
+ windowMinutes: budget.timing.windowMinutes,
215
+ resetsAt: budget.timing.resetsAt,
216
+ resetDescription: [
217
+ _optionalChain([
218
+ budget,
219
+ "access",
220
+ (_) => _.source,
221
+ "optionalAccess",
222
+ (_2) => _2.slice,
223
+ "call",
224
+ (_3) => _3(0, 24),
225
+ ]),
226
+ budget.timing.label,
227
+ `${ctx.format.usd(budget.used)} / ${ctx.format.usd(budget.limit)}`,
228
+ ]
229
+ .filter(Boolean)
230
+ .join(" · "),
231
+ },
232
+ }));
233
+ const windows = allWindows.filter((window) => !window.scope.id);
234
+ const extraWindows = [...windows.slice(2), ...allWindows.filter((window) => window.scope.id)].map(
235
+ ({ id, title, window }) => ({ id, title, window }),
236
+ );
237
+ limits.forEach(({ scope, limit, index }) => {
238
+ const source = text(limit.source_name);
239
+ for (const [key, title] of [
240
+ ["token", "Tokens"],
241
+ ["request", "Requests"],
242
+ ]) {
243
+ const max = number(limit[`${key}_max_limit`]),
244
+ used = _nullishCoalesce(number(limit[`${key}_current_usage`]), () => 0);
245
+ const reset = text(limit[`${key}_reset_duration`]),
246
+ known = max !== undefined && max > 0;
247
+ // Last-reset timestamps are serialized even for unconfigured dimensions.
248
+ if (!known && !reset) continue;
249
+ const time = timing(reset, limit[`${key}_last_reset`]);
250
+ extraWindows.push({
251
+ id: `bifrost-${scope.id}${key}s-${index}`,
252
+ title: bounded([scope.title, source, title].filter(Boolean).join(" ")),
253
+ usageKnown: known,
254
+ window: {
255
+ usedPercent: known ? ctx.pct(used, max) : 0,
256
+ windowMinutes: time.windowMinutes,
257
+ resetsAt: time.resetsAt,
258
+ resetDescription: time.label,
259
+ },
260
+ });
261
+ }
262
+ });
263
+ if (root.is_active === false) {
264
+ extraWindows.unshift({ id: "bifrost-key-inactive", title: "Key inactive", usageKnown: false, usedPercent: 0 });
265
+ }
266
+ const first = budgets.find((budget) => !budget.scope.id),
267
+ details = [];
268
+ const modelName = (raw) =>
269
+ raw
270
+ .replace(/^(us-gov|us|eu|apac|global)\./iu, "")
271
+ .replace(
272
+ /^(ai21|amazon|anthropic|cohere|deepseek|luma|meta|mistral|openai|qwen|stability|twelvelabs|writer)\./iu,
273
+ "",
274
+ )
275
+ .replace(/-v\d+:\d+$/u, "")
276
+ .replace(/(?:-|\s)(?:\d{8}|\d{4}-\d{2}-\d{2})$/u, "")
277
+ .replace(/[ \t-]+$/u, "") || raw;
278
+ const tokenCount = (value) => {
279
+ const magnitude = Math.abs(value),
280
+ sign = value < 0 ? "-" : "";
281
+ for (const [threshold, divisor, unit] of [
282
+ [999500000, 1e9, "B"],
283
+ [999500, 1e6, "M"],
284
+ [1000, 1000, "K"],
285
+ ]) {
286
+ if (magnitude >= threshold) {
287
+ const scaled = magnitude / divisor;
288
+ return sign + scaled.toFixed(scaled >= 10 ? 0 : 1).replace(/\.0$/u, "") + unit;
289
+ }
290
+ }
291
+ return String(value);
292
+ };
293
+ const models = (_optionalChain([first, "optionalAccess", (_4) => _4.models]) || [])
294
+ .map((model) => {
295
+ const tokens = number(model.total_tokens);
296
+ number(model.total_requests);
297
+ return {
298
+ raw: text(model.model) || "Model",
299
+ provider: text(model.provider),
300
+ cost: number(model.total_cost),
301
+ tokens: tokens !== undefined && Math.abs(tokens) < 9223372036854775808 ? Math.trunc(tokens) : undefined,
302
+ };
303
+ })
304
+ .filter((model) => (model.cost || 0) !== 0 || (model.tokens || 0) !== 0)
305
+ .sort((a, b) => (b.cost || 0) - (a.cost || 0) || (b.tokens || 0) - (a.tokens || 0) || compare(a.raw, b.raw));
306
+ if (models.length) {
307
+ const visible = models.slice(0, 5),
308
+ names = visible.map((model) => modelName(model.raw));
309
+ const mixed = new Set(visible.map((model) => model.provider).filter(Boolean)).size > 1;
310
+ const rows = visible.map((model, index) => ({
311
+ label: bounded(
312
+ [
313
+ mixed ? model.provider : undefined,
314
+ names.indexOf(names[index]) !== names.lastIndexOf(names[index]) ? model.raw : names[index],
315
+ ]
316
+ .filter(Boolean)
317
+ .join(" · "),
318
+ ),
319
+ value: model.cost === undefined ? "—" : ctx.format.usd(model.cost),
320
+ usageValue: model.cost,
321
+ secondaryValue: model.tokens === undefined ? undefined : `${tokenCount(model.tokens)} tokens`,
322
+ }));
323
+ if (models.length > 5) rows.push({ label: "Other models", value: String(models.length - 5) });
324
+ details.push({ title: "Models", rows });
325
+ }
326
+ if (budgets.length > 1 || budgets.some((budget) => budget.scope.id))
327
+ details.push({
328
+ title: "Budgets",
329
+ rows: budgets.slice(0, 24).map((budget) => ({
330
+ label: bounded([budget.scope.title, budget.source || `Budget ${budget.id}`].filter(Boolean).join(" · ")),
331
+ value:
332
+ budget.limit > 0
333
+ ? `${ctx.format.usd(budget.used)} / ${ctx.format.usd(budget.limit)}`
334
+ : ctx.format.usd(budget.used),
335
+ secondaryValue: budget.timing.label,
336
+ usageValue: budget.used,
337
+ progress: budget.limit > 0 ? ctx.pct(budget.used, budget.limit) / 100 : undefined,
338
+ })),
339
+ });
340
+ return {
341
+ primary: _optionalChain([windows, "access", (_5) => _5[0], "optionalAccess", (_6) => _6.window]),
342
+ secondary: _optionalChain([windows, "access", (_7) => _7[1], "optionalAccess", (_8) => _8.window]),
343
+ extraWindows,
344
+ details,
345
+ cost: first
346
+ ? {
347
+ used: first.used,
348
+ limit: Math.max(0, first.limit),
349
+ currency: "USD",
350
+ period: first.timing.label || (first.limit > 0 ? "Budget" : "Spend"),
351
+ resetsAt: first.timing.resetsAt,
352
+ }
353
+ : undefined,
354
+ identity: {
355
+ email: text(root.virtual_key_name),
356
+ organization: _optionalChain([first, "optionalAccess", (_9) => _9.source]),
357
+ loginMethod: "api",
358
+ },
359
+ };
360
+ },
361
+ });
@@ -0,0 +1,23 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "id": "bifrost",
4
+ "name": "Bifrost",
5
+ "version": "0.1.0",
6
+ "entry": "plugin.js",
7
+ "enabledByDefault": false,
8
+ "supportedModes": [
9
+ "api"
10
+ ],
11
+ "autoMode": "api",
12
+ "envVars": [
13
+ "BIFROST_API_KEY",
14
+ "BIFROST_BASE_URL"
15
+ ],
16
+ "upstream": {
17
+ "repository": "https://github.com/steipete/CodexBar",
18
+ "revision": "78ba5a1e65e6859da59a21b799df95ab91bc0b89",
19
+ "path": "Sources/CodexBarCore/Resources/Plugins/bifrost.js",
20
+ "sha256": "b7576d59ccd077c812118cf09d282042589a80df470c621e414583050f03aa07",
21
+ "license": "MIT"
22
+ }
23
+ }