@hashimkarim/usagestat-linux-x64-gnu 2.0.1 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. package/native-manifest.json +743 -119
  2. package/package.json +106 -2
  3. package/plugins/abliteration/LICENSE +21 -0
  4. package/plugins/abliteration/icon.svg +5 -0
  5. package/plugins/abliteration/plugin.js +89 -0
  6. package/plugins/abliteration/plugin.json +24 -0
  7. package/plugins/aerostack/LICENSE +21 -0
  8. package/plugins/aerostack/icon.svg +1 -0
  9. package/plugins/aerostack/plugin.js +94 -0
  10. package/plugins/aerostack/plugin.json +24 -0
  11. package/plugins/aixy/icon.svg +1 -0
  12. package/plugins/aixy/plugin.js +5 -0
  13. package/plugins/aixy/plugin.json +9 -1
  14. package/plugins/antigravity/plugin.js +20 -11
  15. package/plugins/antigravity-cli/plugin.js +9 -4
  16. package/plugins/antigravity-ide/plugin.js +8 -5
  17. package/plugins/atlascloud/plugin.js +5 -0
  18. package/plugins/atlascloud/plugin.json +2 -1
  19. package/plugins/bifrost/icon.svg +3 -0
  20. package/plugins/bifrost/plugin.js +5 -0
  21. package/plugins/bifrost/plugin.json +9 -1
  22. package/plugins/chatbox/LICENSE +21 -0
  23. package/plugins/chatbox/icon.svg +4 -0
  24. package/plugins/chatbox/plugin.js +208 -0
  25. package/plugins/chatbox/plugin.json +24 -0
  26. package/plugins/claude/plugin.js +39 -2
  27. package/plugins/claudeplatform/LICENSE +21 -0
  28. package/plugins/claudeplatform/icon.svg +3 -0
  29. package/plugins/claudeplatform/plugin.js +244 -0
  30. package/plugins/claudeplatform/plugin.json +25 -0
  31. package/plugins/codex/plugin.js +3 -2
  32. package/plugins/codex/plugin.json +1 -1
  33. package/plugins/cosmic/LICENSE +21 -0
  34. package/plugins/cosmic/icon.svg +1 -0
  35. package/plugins/cosmic/plugin.js +134 -0
  36. package/plugins/cosmic/plugin.json +32 -0
  37. package/plugins/cursor/plugin.js +33 -8
  38. package/plugins/cursor-nightly/plugin.json +1 -1
  39. package/plugins/devpass/icon.svg +3 -0
  40. package/plugins/devpass/plugin.js +5 -0
  41. package/plugins/devpass/plugin.json +2 -1
  42. package/plugins/exa/LICENSE +21 -0
  43. package/plugins/exa/icon-color.svg +1 -0
  44. package/plugins/exa/icon.svg +1 -0
  45. package/plugins/exa/plugin.js +75 -0
  46. package/plugins/exa/plugin.json +32 -0
  47. package/plugins/fal/LICENSE +21 -0
  48. package/plugins/fal/icon-color.svg +1 -0
  49. package/plugins/fal/icon.svg +1 -0
  50. package/plugins/fal/plugin.js +74 -0
  51. package/plugins/fal/plugin.json +24 -0
  52. package/plugins/flora/LICENSE +21 -0
  53. package/plugins/flora/icon.svg +4 -0
  54. package/plugins/flora/plugin.js +93 -0
  55. package/plugins/flora/plugin.json +32 -0
  56. package/plugins/futureagi/LICENSE +21 -0
  57. package/plugins/futureagi/icon.svg +24 -0
  58. package/plugins/futureagi/plugin.js +139 -0
  59. package/plugins/futureagi/plugin.json +32 -0
  60. package/plugins/gemini-apps/LICENSE +1 -2
  61. package/plugins/gemini-apps/plugin.js +136 -465
  62. package/plugins/gemini-apps/plugin.json +13 -7
  63. package/plugins/gitkraken/icon.svg +2 -0
  64. package/plugins/gitkraken/plugin.js +5 -0
  65. package/plugins/gitkraken/plugin.json +9 -1
  66. package/plugins/helmcode/icon.svg +5 -0
  67. package/plugins/helmcode/plugin.js +49 -41
  68. package/plugins/helmcode/plugin.json +10 -2
  69. package/plugins/huggingface/plugin.js +6 -1
  70. package/plugins/huggingface/plugin.json +4 -3
  71. package/plugins/hyper/plugin.js +53 -47
  72. package/plugins/hyper/plugin.json +3 -2
  73. package/plugins/kimi/plugin.js +39 -14
  74. package/plugins/langdock/LICENSE +21 -0
  75. package/plugins/langdock/icon.svg +4 -0
  76. package/plugins/langdock/plugin.js +106 -0
  77. package/plugins/langdock/plugin.json +25 -0
  78. package/plugins/linkup/LICENSE +21 -0
  79. package/plugins/linkup/icon.svg +10 -0
  80. package/plugins/linkup/plugin.js +46 -0
  81. package/plugins/linkup/plugin.json +24 -0
  82. package/plugins/lithosai/LICENSE +21 -0
  83. package/plugins/lithosai/icon.svg +1 -0
  84. package/plugins/lithosai/plugin.js +130 -0
  85. package/plugins/lithosai/plugin.json +26 -0
  86. package/plugins/llmman/icon.svg +4 -0
  87. package/plugins/llmman/plugin.js +5 -0
  88. package/plugins/llmman/plugin.json +9 -1
  89. package/plugins/munito/LICENSE +21 -0
  90. package/plugins/munito/icon.svg +7 -0
  91. package/plugins/munito/plugin.js +171 -0
  92. package/plugins/munito/plugin.json +24 -0
  93. package/plugins/muse/icon.svg +3 -0
  94. package/plugins/muse/plugin.js +98 -129
  95. package/plugins/muse/plugin.json +10 -2
  96. package/plugins/museai/LICENSE +21 -0
  97. package/plugins/museai/icon.svg +3 -0
  98. package/plugins/museai/plugin.js +159 -0
  99. package/plugins/museai/plugin.json +26 -0
  100. package/plugins/nous/plugin.js +5 -0
  101. package/plugins/nous/plugin.json +9 -1
  102. package/plugins/ollama/plugin.js +58 -0
  103. package/plugins/opencode-go/plugin.js +72 -24
  104. package/plugins/parallel/LICENSE +21 -0
  105. package/plugins/parallel/icon.svg +11 -0
  106. package/plugins/parallel/plugin.js +97 -0
  107. package/plugins/parallel/plugin.json +25 -0
  108. package/plugins/qwencloud/LICENSE +21 -0
  109. package/plugins/qwencloud/plugin.js +197 -0
  110. package/plugins/qwencloud/plugin.json +17 -0
  111. package/plugins/raycast/icon.svg +4 -0
  112. package/plugins/raycast/plugin.js +5 -0
  113. package/plugins/raycast/plugin.json +9 -1
  114. package/plugins/replicate/plugin.js +5 -0
  115. package/plugins/replicate/plugin.json +2 -1
  116. package/plugins/sailresearch/LICENSE +21 -0
  117. package/plugins/sailresearch/icon.svg +4 -0
  118. package/plugins/sailresearch/plugin.js +104 -0
  119. package/plugins/sailresearch/plugin.json +24 -0
  120. package/plugins/sofya/LICENSE +21 -0
  121. package/plugins/sofya/icon.svg +3 -0
  122. package/plugins/sofya/plugin.js +86 -0
  123. package/plugins/sofya/plugin.json +24 -0
  124. package/plugins/soniox/LICENSE +21 -0
  125. package/plugins/soniox/icon.svg +3 -0
  126. package/plugins/soniox/plugin.js +103 -0
  127. package/plugins/soniox/plugin.json +24 -0
  128. package/plugins/tavily/LICENSE +21 -0
  129. package/plugins/tavily/icon.svg +3 -0
  130. package/plugins/tavily/plugin.js +61 -0
  131. package/plugins/tavily/plugin.json +24 -0
  132. package/plugins/tinyapi/LICENSE +21 -0
  133. package/plugins/tinyapi/icon.svg +4 -0
  134. package/plugins/tinyapi/plugin.js +73 -0
  135. package/plugins/tinyapi/plugin.json +25 -0
  136. package/plugins/traecn/LICENSE +21 -0
  137. package/plugins/traecn/icon.svg +3 -0
  138. package/plugins/traecn/plugin.js +104 -0
  139. package/plugins/traecn/plugin.json +25 -0
  140. package/plugins/typesafe/icon.svg +4 -0
  141. package/plugins/typesafe/plugin.js +30 -25
  142. package/plugins/typesafe/plugin.json +3 -2
  143. package/plugins/v0/plugin.js +5 -0
  144. package/plugins/v0/plugin.json +9 -1
  145. package/plugins/vercel/plugin.js +147 -0
  146. package/plugins/vercel/plugin.json +34 -3
  147. package/plugins/workbuddy/LICENSE +21 -0
  148. package/plugins/workbuddy/icon.svg +1 -0
  149. package/plugins/workbuddy/plugin.js +232 -0
  150. package/plugins/workbuddy/plugin.json +51 -0
  151. package/plugins/xai/plugin.js +9 -0
  152. package/plugins/xapi/LICENSE +21 -0
  153. package/plugins/xapi/icon.svg +1 -0
  154. package/plugins/xapi/plugin.js +90 -0
  155. package/plugins/xapi/plugin.json +25 -0
  156. package/plugins/xkiro/icon.svg +1 -0
  157. package/plugins/xkiro/plugin.js +5 -0
  158. package/plugins/xkiro/plugin.json +2 -1
  159. package/usagestat +0 -0
  160. package/usagestatd +0 -0
  161. package/plugins/cursor-nightly/plugin.js +0 -1416
@@ -0,0 +1,232 @@
1
+ // Generated by tools/vendor-codexbar-providers.cjs; see LICENSE.
2
+ globalThis.__usagestat_bundled_options = {"labels":["Credits","Credits","Additional"],"defaults":{},"autoMode":"web"};
3
+ (function(defineProvider) {
4
+ // BEGIN UPSTREAM Sources/CodexBarCore/Resources/Plugins/workbuddy.js
5
+ function _nullishCoalesce(lhs, rhsFn) {
6
+ if (lhs != null) {
7
+ return lhs;
8
+ } else {
9
+ return rhsFn();
10
+ }
11
+ }
12
+ defineProvider({
13
+ id: "workbuddy",
14
+ name: "WorkBuddy",
15
+ endpoints: ["https://www.workbuddy.cn"],
16
+ settings: [
17
+ { key: "webTimeoutSeconds", title: "Web timeout", type: "plain" },
18
+ { key: "resetDeadlineMillis", title: "Reset lookup deadline", type: "plain" },
19
+ { key: "chromeMajorVersion", title: "Chrome major version", type: "plain" },
20
+ ],
21
+ capabilities: ["browser-cookies", "http-status"],
22
+ cookieDomains: ["workbuddy.cn", "www.workbuddy.cn"],
23
+ cookiePolicy: {
24
+ selection: "request-url",
25
+ cache: "validated-single-entry",
26
+ imports: "access-gated",
27
+ },
28
+ async fetchUsage(ctx) {
29
+ const origin = "https://www.workbuddy.cn";
30
+ const domain = "www.workbuddy.cn";
31
+ const policy = ctx.browser.availability(domain);
32
+ if (policy === "off") throw ctx.fail.missingCredential("WorkBuddy cookies are disabled.");
33
+ const timeoutRaw = Number(_nullishCoalesce(ctx.settings.get("webTimeoutSeconds"), () => "15"));
34
+ const timeoutSeconds = Number.isFinite(timeoutRaw) ? Math.min(30, Math.max(1, Math.round(timeoutRaw))) : 15;
35
+ // WorkBuddy binds the session to the browser User-Agent, and Chrome's reduced UA varies only by major version.
36
+ // The previous major covers an installed update that Chrome has not relaunched into yet.
37
+ const major = Number(_nullishCoalesce(ctx.settings.get("chromeMajorVersion"), () => ""));
38
+ const userAgent = (version) =>
39
+ `Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${version}.0.0.0 Safari/537.36`;
40
+ const userAgents =
41
+ Number.isSafeInteger(major) && major > 1 ? [userAgent(major), userAgent(major - 1)] : [undefined];
42
+
43
+ const fail = (field) => {
44
+ throw ctx.fail.parseFailure(`Invalid WorkBuddy billing response: ${field}`);
45
+ };
46
+ const object = (value, field) =>
47
+ value !== null && typeof value === "object" && !Array.isArray(value) ? value : fail(field);
48
+ // Billing amounts arrive as decimal strings ("500"); numbers are accepted for robustness.
49
+ const amount = (value, field) => {
50
+ if (typeof value === "number") return Number.isFinite(value) && value >= 0 ? value : fail(field);
51
+ if (typeof value !== "string" || !/^\d+(?:\.\d+)?$/.test(value.trim())) return fail(field);
52
+ const parsed = Number(value.trim());
53
+ return Number.isFinite(parsed) ? parsed : fail(field);
54
+ };
55
+ const text = (value) => (typeof value === "string" ? value.trim() || undefined : undefined);
56
+ const format = (value) => ctx.format.number(value, { maximumFractionDigits: 2 });
57
+ const decode = (bodyText, field) => {
58
+ let value;
59
+ try {
60
+ value = JSON.parse(bodyText);
61
+ } catch (error) {
62
+ void error;
63
+ return fail(field);
64
+ }
65
+ return object(value, field);
66
+ };
67
+
68
+ const sessionExpired = ctx.fail.authenticationExpired(
69
+ "WorkBuddy session expired. Sign in at www.workbuddy.cn or paste a fresh Cookie header.",
70
+ );
71
+ const post = async (session, agent, path, body, requestTimeout = timeoutSeconds) => {
72
+ const headers = {
73
+ Accept: "application/json",
74
+ Origin: origin,
75
+ Referer: `${origin}/profile/plans-usage`,
76
+ };
77
+ if (agent) headers["User-Agent"] = agent;
78
+ const response = await ctx.http.post(`${origin}${path}`, {
79
+ body,
80
+ timeoutSeconds: requestTimeout,
81
+ cookieSession: session.id,
82
+ headers,
83
+ });
84
+ if (response.status === 401) throw sessionExpired;
85
+ if (response.status === 403) throw ctx.fail.permissionDenied("WorkBuddy denied access to billing data.");
86
+ if (response.status === 429) throw ctx.fail.rateLimited("WorkBuddy billing requests are rate limited.");
87
+ if (response.status >= 500) {
88
+ throw ctx.fail.providerUnavailable(`WorkBuddy billing API returned HTTP ${response.status}.`);
89
+ }
90
+ if (response.status !== 200) throw ctx.fail.apiFailure(`WorkBuddy billing API returned HTTP ${response.status}.`);
91
+ const root = decode(response.bodyText, "expected a JSON object");
92
+ if (root.code !== 0) {
93
+ throw ctx.fail.apiFailure(`WorkBuddy billing API returned code ${String(root.code)}.`);
94
+ }
95
+ return object(root.data, "data");
96
+ };
97
+
98
+ // Cycle timestamps carry no zone; WorkBuddy uses China Standard Time.
99
+ const cycleEnd = (value) => {
100
+ const raw = text(value);
101
+ if (!raw) return undefined;
102
+ const match = /^(\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}:\d{2})$/.exec(raw);
103
+ if (!match) return undefined;
104
+ const end = ctx.date.iso(`${match[1]}T${match[2]}+08:00`);
105
+ // The dashboard refreshes one second after the inclusive end time.
106
+ return new Date(end.getTime() + 1000);
107
+ };
108
+ // Package codes the WorkBuddy client sends for its paid and free listings (WorkBuddy 5.6.2).
109
+ const paidPackageCodes = [
110
+ "TCACA_code_002_AkiJS3ZHF5",
111
+ "TCACA_code_005_maRGyrHhw1",
112
+ "TCACA_code_003_FAnt7lcmRT",
113
+ "TCACA_code_023_4xbGhMrE6q",
114
+ "TCACA_code_026_BaESVICNoi",
115
+ "TCACA_code_027_0FCGVA6vSa",
116
+ "TCACA_code_009_0XmEQc2xOf",
117
+ "TCACA_code_038_OhvqZtiPKr",
118
+ "TCACA_code_036_lupO5WgNdG",
119
+ ];
120
+ const freePackageCodes = [
121
+ "TCACA_code_001_PqouKr6QWV",
122
+ "TCACA_code_008_cfWoLwvjU4",
123
+ "TCACA_code_035_ArVxJcGDsm",
124
+ "TCACA_code_006_DbXS0lrypC",
125
+ "TCACA_code_039_KRcQj7wUat",
126
+ "TCACA_code_040_mi9rCYg46x",
127
+ "TCACA_code_007_nzdH5h4Nl0",
128
+ "TCACA_code_028_NtpWi0jzXs",
129
+ "TCACA_code_037_WxOD3MpI2o",
130
+ "TCACA_code_029_6wCGEWquYy",
131
+ "TCACA_code_030_BjSt89qTvr",
132
+ ];
133
+ // Reset time is optional: a failed or unexpected package listing must not discard the balance.
134
+ const nextReset = async (session, agent) => {
135
+ const now = ctx.date.now().getTime();
136
+ // Share five seconds across listings, retaining the host's margin for publishing the balance.
137
+ const hostDeadline = Number(ctx.settings.get("resetDeadlineMillis"));
138
+ const deadline = Math.min(Date.now() + 5000, hostDeadline > 0 ? hostDeadline : Infinity);
139
+ let earliest;
140
+ for (const [path, codes] of [
141
+ ["/billing/meter/get-user-resource-paid-packages", paidPackageCodes],
142
+ ["/billing/meter/get-user-resource-free-packages", freePackageCodes],
143
+ ]) {
144
+ const budget = (deadline - Date.now()) / 1000;
145
+ if (budget < 1) break;
146
+ try {
147
+ // The listings reject requests without package codes (HTTP 400, code 10001). Status 0 is valid, 3 used up.
148
+ const page = await post(
149
+ session,
150
+ agent,
151
+ path,
152
+ { PageNumber: 1, PageSize: 100, PackageCodes: codes, Status: [0, 3] },
153
+ Math.min(timeoutSeconds, budget),
154
+ );
155
+ if (!Array.isArray(page.Accounts)) continue;
156
+ for (const raw of page.Accounts) {
157
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw)) continue;
158
+ const account = raw;
159
+ if (account.CapacityUnit !== "credits") continue;
160
+ const end = cycleEnd(account.CycleEndTime);
161
+ if (end && end.getTime() > now && (!earliest || end.getTime() < earliest.getTime())) earliest = end;
162
+ }
163
+ } catch (error) {
164
+ if (error.transportClass === "cancelled") throw error;
165
+ }
166
+ // Paid cycles refill the allowance; free grants may expire earlier.
167
+ if (earliest) return earliest;
168
+ }
169
+ };
170
+
171
+ let rejected = false;
172
+ for await (const session of ctx.browser.sessions(domain)) {
173
+ let summary;
174
+ let agent;
175
+ for (const candidate of userAgents) {
176
+ try {
177
+ summary = await post(session, candidate, "/billing/meter/get-user-resource-summary", {});
178
+ agent = candidate;
179
+ break;
180
+ } catch (error) {
181
+ if (error !== sessionExpired) throw error;
182
+ }
183
+ }
184
+ if (!summary) {
185
+ rejected = true;
186
+ ctx.browser.rejectCookie(domain, session);
187
+ if (policy === "manual") break;
188
+ continue;
189
+ }
190
+
191
+ if (!Array.isArray(summary.Packages)) return fail("Packages");
192
+ // The host caches an imported session only after the billing API accepts it.
193
+ if (policy !== "manual") ctx.browser.acceptCookie(domain, session);
194
+ let total = 0;
195
+ let remaining = 0;
196
+ let frozen = 0;
197
+ for (const raw of summary.Packages) {
198
+ const item = object(raw, "package");
199
+ if (item.CapacityUnit !== "credits") continue;
200
+ total += amount(item.CycleTotalCapacity, "CycleTotalCapacity");
201
+ remaining += amount(item.CycleRemainCapacity, "CycleRemainCapacity");
202
+ if (item.CycleFrozenCapacity !== undefined) frozen += amount(item.CycleFrozenCapacity, "CycleFrozenCapacity");
203
+ }
204
+ const plan = text(summary.SubscriptionPackageName);
205
+ // Frozen credits are listed as reported; the meter uses the remaining amount the dashboard shows.
206
+ const rows = frozen > 0 ? [{ label: "Reserved", value: format(frozen) }] : [];
207
+ if (total <= 0) {
208
+ rows.unshift({ label: "Left", value: format(remaining) }, { label: "Total", value: format(total) });
209
+ }
210
+ return {
211
+ primary:
212
+ total > 0
213
+ ? {
214
+ usedPercent: ctx.pct(Math.max(0, total - remaining), total),
215
+ resetsAt: await nextReset(session, agent),
216
+ resetDescription: `${format(remaining)} / ${format(total)} credits left`,
217
+ }
218
+ : undefined,
219
+ details: rows.length ? [{ title: "Credits", rows }] : undefined,
220
+ identity: plan ? { loginMethod: plan } : undefined,
221
+ dataConfidence: "exact",
222
+ };
223
+ }
224
+ if (rejected) throw sessionExpired;
225
+ throw ctx.fail.missingCredential(
226
+ `No WorkBuddy session cookies found. Sign in at www.workbuddy.cn (${ctx.browser.supportedBrowsers}) or paste a Cookie header.`,
227
+ );
228
+ },
229
+ });
230
+
231
+ // END UPSTREAM
232
+ })(globalThis.defineProvider);
@@ -0,0 +1,51 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "id": "workbuddy",
4
+ "name": "WorkBuddy",
5
+ "version": "0.1.0",
6
+ "entry": "plugin.js",
7
+ "enabledByDefault": false,
8
+ "supportedModes": [
9
+ "web"
10
+ ],
11
+ "autoMode": "web",
12
+ "usageDashboardUrl": "https://www.workbuddy.cn",
13
+ "webUrl": "https://workbuddy.cn",
14
+ "envVars": [
15
+ "WORKBUDDY_COOKIE"
16
+ ],
17
+ "setupHelp": "Use a Cookie header from www.workbuddy.cn and the full User-Agent from the same browser. Set Browser User-Agent below. Desktop login files are not imported.",
18
+ "setupFields": [
19
+ {
20
+ "key": "webTimeoutSeconds",
21
+ "title": "Web timeout",
22
+ "type": "string",
23
+ "description": "Provider-specific account or source selection."
24
+ },
25
+ {
26
+ "key": "resetDeadlineMillis",
27
+ "title": "Reset lookup deadline",
28
+ "type": "string",
29
+ "description": "Provider-specific account or source selection."
30
+ },
31
+ {
32
+ "key": "chromeMajorVersion",
33
+ "title": "Chrome major version",
34
+ "type": "string",
35
+ "description": "Provider-specific account or source selection."
36
+ },
37
+ {
38
+ "key": "browserUserAgent",
39
+ "title": "Browser User-Agent",
40
+ "type": "string",
41
+ "description": "Paste the full User-Agent from the same browser session that supplied the cookies. Required for WorkBuddy web readback."
42
+ }
43
+ ],
44
+ "upstream": {
45
+ "repository": "https://github.com/steipete/CodexBar",
46
+ "revision": "6070b29a1a5d51193a634dc1b0a14a67c39d0ccc",
47
+ "path": "Sources/CodexBarCore/Resources/Plugins/workbuddy.js",
48
+ "sha256": "9da73ec195a174e3ee96e3096a47db0b69295bc52dcfceb9fd9d1a2b8f74b08a",
49
+ "license": "MIT"
50
+ }
51
+ }
@@ -12,6 +12,7 @@
12
12
  }
13
13
 
14
14
  function env(ctx, name) {
15
+ if (ctx.provider && ctx.provider.instanceId && ctx.provider.instanceId !== 'xai') return null;
15
16
  try {
16
17
  return clean(ctx.host.env.get(name));
17
18
  } catch (_) {
@@ -135,6 +136,14 @@
135
136
  });
136
137
  var balance = balanceUsd(balanceJson.total && balanceJson.total.val);
137
138
  var metrics = [ctx.line.text({ label: "Balance", value: balance < 0 ? "Deficit: $" + (-balance).toFixed(2) : "$" + balance.toFixed(2) })];
139
+ try {
140
+ var preview = ctx.util.requestJson({method:'GET',url:BASE_URL+'/v1/billing/teams/'+encodeURIComponent(id)+'/postpaid/invoice/preview',
141
+ headers:{Authorization:'Bearer '+key,Accept:'application/json'},timeoutMs:5000});
142
+ var cents = preview.json && preview.json.coreInvoice && preview.json.coreInvoice.amountAfterVat;
143
+ if (preview.resp.status>=200 && preview.resp.status<300 && typeof cents==='string' && /^-?\d+$/.test(cents) && Number.isSafeInteger(Number(cents)))
144
+ metrics.push(ctx.line.text({label:'Live remaining (est.)',value:'$'+(balance-Number(cents)/100).toFixed(2),
145
+ subtitle:'Prepaid balance less the current invoice preview; not a settled charge.'}));
146
+ } catch (_) {ctx.host.log.warn('xAI invoice preview unavailable');}
138
147
 
139
148
  var daily = fetchDaily(ctx, key, id);
140
149
  if (daily.length) {
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Peter Steinberger
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="currentColor" d="M3 3h5.2l5.3 7.1L19.5 3H22l-7.3 8.9L22 21h-5.2l-5.7-7.5L4.7 21H2l7.9-9.3L3 3zm3.4 1.7 11.2 14.6h1.1L7.5 4.7H6.4z"/></svg>
@@ -0,0 +1,90 @@
1
+ // Generated by tools/vendor-codexbar-providers.cjs; see LICENSE.
2
+ globalThis.__usagestat_bundled_options = {"labels":["Balance","Additional","Additional"],"defaults":{},"autoMode":"web","balanceOnly":true};
3
+ (function(defineProvider) {
4
+ // BEGIN UPSTREAM Sources/CodexBarCore/Resources/Plugins/xapi.js
5
+ defineProvider({
6
+ id: "xapi",
7
+ name: "X API",
8
+ settings: [],
9
+ endpoints: ["https://console.x.com"],
10
+ capabilities: ["browser-cookies", "http-status"],
11
+ cookieDomains: ["x.com", "console.x.com"],
12
+ cookiePolicy: {
13
+ selection: "request-url",
14
+ cache: "nonpersistent",
15
+ imports: "access-gated",
16
+ requiredCookies: ["auth_token", "ct0"],
17
+ headerEcho: { origin: "https://console.x.com", cookie: "ct0", header: "X-CSRF-Token" },
18
+ },
19
+ async fetchUsage(ctx) {
20
+ const domain = "console.x.com";
21
+ if (ctx.browser.availability(domain) === "off") throw ctx.fail.missingCredential("X API cookies are disabled.");
22
+ const invalid = () => {
23
+ throw ctx.fail.parseFailure("X API returned an unrecognized account or dollar balance.");
24
+ };
25
+ const amount = (value) => (typeof value === "number" && Number.isFinite(value) ? value : invalid());
26
+ const expired = ctx.fail.authenticationExpired("X API session expired. Sign in to console.x.com again.");
27
+ let rejected = false;
28
+ for await (const session of ctx.browser.sessions(domain)) {
29
+ const request = async (path) => {
30
+ const response = await ctx.http.get(`https://console.x.com${path}`, {
31
+ cookieSession: session.id,
32
+ headers: { Accept: "application/json" },
33
+ });
34
+ if (response.status === 401) throw expired;
35
+ if (response.status === 403) throw ctx.fail.permissionDenied("X developer console access was denied.");
36
+ if (response.status === 429)
37
+ throw ctx.fail.rateLimited("X API console is rate limited. Wait before refreshing.");
38
+ if (response.status >= 500) throw ctx.fail.providerUnavailable("X developer console is unavailable.");
39
+ let json;
40
+ try {
41
+ json = JSON.parse(response.bodyText);
42
+ } catch {
43
+ if (response.status === 200) return invalid();
44
+ }
45
+ // The console also reports expired authentication as HTTP 400 / code 215.
46
+ if (response.status === 400 && Array.isArray(json?.errors) && json.errors.some((error) => error?.code === 215))
47
+ throw expired;
48
+ if (response.status !== 200) throw ctx.fail.apiFailure(`X developer console returned HTTP ${response.status}.`);
49
+ return json;
50
+ };
51
+ try {
52
+ const me = await request("/api/me");
53
+ const id = me?.account?.id;
54
+ const account = Number.isSafeInteger(id) && id >= 0 ? String(id) : id;
55
+ if (typeof account !== "string" || !/^[A-Za-z0-9_-]{1,128}$/.test(account)) return invalid();
56
+ const credits = await request(`/api/accounts/${account}/credits`);
57
+ // The console renders these directly as dollars; its spend endpoint uses different units.
58
+ const paid = amount(credits?.credits?.balance);
59
+ const free = credits?.freeCredits === undefined ? 0 : amount(credits.freeCredits?.balance);
60
+ const balance = amount(paid + free);
61
+ return {
62
+ cost: { used: 0, balance, currency: "USD", period: "Prepaid credits" },
63
+ details: [
64
+ {
65
+ title: "Credits",
66
+ rows: [
67
+ { label: "Balance", value: ctx.format.currency(balance, "USD"), usageValue: balance },
68
+ { label: "Purchased credits", value: ctx.format.currency(paid, "USD") },
69
+ { label: "Free credits", value: ctx.format.currency(free, "USD") },
70
+ ],
71
+ },
72
+ ],
73
+ identity: { loginMethod: "Browser session" },
74
+ dataConfidence: "exact",
75
+ };
76
+ } catch (error) {
77
+ if (error !== expired) throw error;
78
+ ctx.browser.rejectCookie(domain, session);
79
+ rejected = true;
80
+ }
81
+ }
82
+ if (rejected) throw expired;
83
+ throw ctx.fail.missingCredential(
84
+ `Sign in to console.x.com. Supported browsers: ${ctx.browser.supportedBrowsers}. Or paste its Cookie header.`,
85
+ );
86
+ },
87
+ });
88
+
89
+ // END UPSTREAM
90
+ })(globalThis.defineProvider);
@@ -0,0 +1,25 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "id": "xapi",
4
+ "name": "X API",
5
+ "version": "0.1.0",
6
+ "entry": "plugin.js",
7
+ "enabledByDefault": false,
8
+ "supportedModes": [
9
+ "web"
10
+ ],
11
+ "autoMode": "web",
12
+ "usageDashboardUrl": "https://console.x.com",
13
+ "webUrl": "https://x.com",
14
+ "envVars": [
15
+ "XAPI_COOKIE"
16
+ ],
17
+ "setupFields": [],
18
+ "upstream": {
19
+ "repository": "https://github.com/steipete/CodexBar",
20
+ "revision": "6070b29a1a5d51193a634dc1b0a14a67c39d0ccc",
21
+ "path": "Sources/CodexBarCore/Resources/Plugins/xapi.js",
22
+ "sha256": "c8aff7628f2a67a8726486d847747dd8121123da6526b2793b4b7b36ec37930f",
23
+ "license": "MIT"
24
+ }
25
+ }
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="M3 4h5l4 5.5L16 4h5l-6.5 8L21 20h-5l-4-5.5L8 20H3l6.5-8Z"/></svg>
@@ -1,5 +1,7 @@
1
1
  // Generated by tools/vendor-codexbar-providers.cjs; see LICENSE.
2
2
  globalThis.__usagestat_bundled_options = {"labels":["Daily free tokens","Weekly","Additional"],"defaults":{},"autoMode":"api"};
3
+ (function(defineProvider) {
4
+ // BEGIN UPSTREAM Sources/CodexBarCore/Resources/Plugins/xkiro.js
3
5
  function _nullishCoalesce(lhs, rhsFn) {
4
6
  if (lhs != null) {
5
7
  return lhs;
@@ -97,3 +99,6 @@ defineProvider({
97
99
  };
98
100
  },
99
101
  });
102
+
103
+ // END UPSTREAM
104
+ })(globalThis.defineProvider);
@@ -13,9 +13,10 @@
13
13
  "envVars": [
14
14
  "XKIRO_API_KEY"
15
15
  ],
16
+ "setupFields": [],
16
17
  "upstream": {
17
18
  "repository": "https://github.com/steipete/CodexBar",
18
- "revision": "25bba9b7fd9ce83c33053958f7366e23b2dc8a82",
19
+ "revision": "6070b29a1a5d51193a634dc1b0a14a67c39d0ccc",
19
20
  "path": "Sources/CodexBarCore/Resources/Plugins/xkiro.js",
20
21
  "sha256": "03bfcb8e518577ee18dd335e4e1e1f7d629d3e5abdf2216b187b1cba8b683853",
21
22
  "license": "MIT"
package/usagestat CHANGED
Binary file
package/usagestatd CHANGED
Binary file