@hashimkarim/usagestat-linux-x64-gnu 2.1.0 → 2.2.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 (81) hide show
  1. package/native-manifest.json +197 -89
  2. package/package.json +19 -1
  3. package/plugins/abliteration/plugin.json +1 -1
  4. package/plugins/aerostack/plugin.json +1 -1
  5. package/plugins/aixy/plugin.json +1 -1
  6. package/plugins/atlascloud/plugin.json +1 -1
  7. package/plugins/bifrost/plugin.json +1 -1
  8. package/plugins/chatbox/plugin.json +1 -1
  9. package/plugins/claudeplatform/plugin.json +1 -1
  10. package/plugins/codex/plugin.js +11 -6
  11. package/plugins/codex/plugin.json +10 -1
  12. package/plugins/cosmic/plugin.json +1 -1
  13. package/plugins/cursor/plugin.js +18 -6
  14. package/plugins/devpass/plugin.json +1 -1
  15. package/plugins/exa/plugin.json +1 -1
  16. package/plugins/fal/plugin.json +1 -1
  17. package/plugins/flora/plugin.json +1 -1
  18. package/plugins/futureagi/plugin.json +1 -1
  19. package/plugins/gemini-apps/plugin.json +1 -1
  20. package/plugins/gitkraken/plugin.json +1 -1
  21. package/plugins/googledeveloper/LICENSE +21 -0
  22. package/plugins/googledeveloper/icon.svg +3 -0
  23. package/plugins/googledeveloper/plugin.js +204 -0
  24. package/plugins/googledeveloper/plugin.json +25 -0
  25. package/plugins/helmcode/plugin.js +80 -23
  26. package/plugins/helmcode/plugin.json +2 -2
  27. package/plugins/huggingface/plugin.json +1 -1
  28. package/plugins/hyper/plugin.json +1 -1
  29. package/plugins/jetbrains-ai-assistant/LICENSE +22 -0
  30. package/plugins/jetbrains-ai-assistant/plugin.js +502 -16
  31. package/plugins/jetbrains-ai-assistant/plugin.json +27 -4
  32. package/plugins/kimi/plugin.js +16 -1
  33. package/plugins/kimi/plugin.json +46 -6
  34. package/plugins/langdock/plugin.json +1 -1
  35. package/plugins/linkup/plugin.json +1 -1
  36. package/plugins/lithosai/plugin.json +1 -1
  37. package/plugins/llmman/plugin.json +1 -1
  38. package/plugins/munito/plugin.json +1 -1
  39. package/plugins/muse/plugin.json +1 -1
  40. package/plugins/museai/plugin.js +5 -3
  41. package/plugins/museai/plugin.json +2 -2
  42. package/plugins/nous/plugin.json +1 -1
  43. package/plugins/opencode-go/plugin.js +4 -3
  44. package/plugins/opendesign/LICENSE +21 -0
  45. package/plugins/opendesign/icon.svg +4 -0
  46. package/plugins/opendesign/plugin.js +108 -0
  47. package/plugins/opendesign/plugin.json +25 -0
  48. package/plugins/parallel/plugin.json +1 -1
  49. package/plugins/perplexity/LICENSE +22 -0
  50. package/plugins/perplexity/plugin.js +122 -0
  51. package/plugins/perplexity/plugin.json +36 -7
  52. package/plugins/qwencloud/plugin.json +1 -1
  53. package/plugins/raycast/plugin.json +1 -1
  54. package/plugins/replicate/plugin.json +1 -1
  55. package/plugins/sailresearch/plugin.json +1 -1
  56. package/plugins/siliconflow/LICENSE +21 -0
  57. package/plugins/siliconflow/icon.svg +3 -0
  58. package/plugins/siliconflow/plugin.js +87 -0
  59. package/plugins/siliconflow/plugin.json +32 -0
  60. package/plugins/sofya/plugin.json +1 -1
  61. package/plugins/soniox/plugin.json +1 -1
  62. package/plugins/synthetic/plugin.js +12 -0
  63. package/plugins/synthetic/plugin.json +51 -9
  64. package/plugins/tavily/plugin.json +1 -1
  65. package/plugins/tinyapi/plugin.json +1 -1
  66. package/plugins/traecn/plugin.js +10 -11
  67. package/plugins/traecn/plugin.json +2 -2
  68. package/plugins/tripo/LICENSE +21 -0
  69. package/plugins/tripo/icon.svg +4 -0
  70. package/plugins/tripo/plugin.js +60 -0
  71. package/plugins/tripo/plugin.json +24 -0
  72. package/plugins/typesafe/plugin.js +63 -112
  73. package/plugins/typesafe/plugin.json +2 -2
  74. package/plugins/v0/plugin.json +1 -1
  75. package/plugins/vercel/plugin.json +2 -2
  76. package/plugins/workbuddy/plugin.js +103 -17
  77. package/plugins/workbuddy/plugin.json +14 -2
  78. package/plugins/xapi/plugin.json +1 -1
  79. package/plugins/xkiro/plugin.json +1 -1
  80. package/usagestat +0 -0
  81. package/usagestatd +0 -0
package/package.json CHANGED
@@ -212,6 +212,10 @@
212
212
  "plugins/gitkraken/icon.svg",
213
213
  "plugins/gitkraken/plugin.js",
214
214
  "plugins/gitkraken/plugin.json",
215
+ "plugins/googledeveloper/LICENSE",
216
+ "plugins/googledeveloper/icon.svg",
217
+ "plugins/googledeveloper/plugin.js",
218
+ "plugins/googledeveloper/plugin.json",
215
219
  "plugins/grok/icon-color.svg",
216
220
  "plugins/grok/icon.svg",
217
221
  "plugins/grok/plugin.js",
@@ -235,6 +239,7 @@
235
239
  "plugins/ibmbob/icon.svg",
236
240
  "plugins/ibmbob/plugin.js",
237
241
  "plugins/ibmbob/plugin.json",
242
+ "plugins/jetbrains-ai-assistant/LICENSE",
238
243
  "plugins/jetbrains-ai-assistant/icon-color.svg",
239
244
  "plugins/jetbrains-ai-assistant/icon-conflict.svg",
240
245
  "plugins/jetbrains-ai-assistant/icon.svg",
@@ -349,6 +354,10 @@
349
354
  "plugins/opencode/icon.svg",
350
355
  "plugins/opencode/plugin.js",
351
356
  "plugins/opencode/plugin.json",
357
+ "plugins/opendesign/LICENSE",
358
+ "plugins/opendesign/icon.svg",
359
+ "plugins/opendesign/plugin.js",
360
+ "plugins/opendesign/plugin.json",
352
361
  "plugins/openrouter/icon-color.svg",
353
362
  "plugins/openrouter/icon.svg",
354
363
  "plugins/openrouter/plugin.js",
@@ -357,6 +366,7 @@
357
366
  "plugins/parallel/icon.svg",
358
367
  "plugins/parallel/plugin.js",
359
368
  "plugins/parallel/plugin.json",
369
+ "plugins/perplexity/LICENSE",
360
370
  "plugins/perplexity/icon-color.svg",
361
371
  "plugins/perplexity/icon-conflict.svg",
362
372
  "plugins/perplexity/icon.svg",
@@ -391,6 +401,10 @@
391
401
  "plugins/sakana/icon.svg",
392
402
  "plugins/sakana/plugin.js",
393
403
  "plugins/sakana/plugin.json",
404
+ "plugins/siliconflow/LICENSE",
405
+ "plugins/siliconflow/icon.svg",
406
+ "plugins/siliconflow/plugin.js",
407
+ "plugins/siliconflow/plugin.json",
394
408
  "plugins/sofya/LICENSE",
395
409
  "plugins/sofya/icon.svg",
396
410
  "plugins/sofya/plugin.js",
@@ -427,6 +441,10 @@
427
441
  "plugins/traecn/icon.svg",
428
442
  "plugins/traecn/plugin.js",
429
443
  "plugins/traecn/plugin.json",
444
+ "plugins/tripo/LICENSE",
445
+ "plugins/tripo/icon.svg",
446
+ "plugins/tripo/plugin.js",
447
+ "plugins/tripo/plugin.json",
430
448
  "plugins/typesafe/LICENSE",
431
449
  "plugins/typesafe/icon.svg",
432
450
  "plugins/typesafe/plugin.js",
@@ -513,5 +531,5 @@
513
531
  "type": "git",
514
532
  "url": "https://github.com/hashimkarim/usagestat.git"
515
533
  },
516
- "version": "2.1.0"
534
+ "version": "2.2.0"
517
535
  }
@@ -16,7 +16,7 @@
16
16
  "setupFields": [],
17
17
  "upstream": {
18
18
  "repository": "https://github.com/steipete/CodexBar",
19
- "revision": "6070b29a1a5d51193a634dc1b0a14a67c39d0ccc",
19
+ "revision": "1f6da9bec44455288ddee5ef6f3617a803d8eb2a",
20
20
  "path": "Sources/CodexBarCore/Resources/Plugins/abliteration.js",
21
21
  "sha256": "16982dfb14ae7e1181c688f5084e6b17ea84f72a28c1a98623ebc03c1dff5516",
22
22
  "license": "MIT"
@@ -16,7 +16,7 @@
16
16
  "setupFields": [],
17
17
  "upstream": {
18
18
  "repository": "https://github.com/steipete/CodexBar",
19
- "revision": "6070b29a1a5d51193a634dc1b0a14a67c39d0ccc",
19
+ "revision": "1f6da9bec44455288ddee5ef6f3617a803d8eb2a",
20
20
  "path": "Sources/CodexBarCore/Resources/Plugins/aerostack.js",
21
21
  "sha256": "f0ead202fc5ee40481ea22122b7f4d9238013cbc68cb6b218592d6a64439a9f3",
22
22
  "license": "MIT"
@@ -24,7 +24,7 @@
24
24
  ],
25
25
  "upstream": {
26
26
  "repository": "https://github.com/steipete/CodexBar",
27
- "revision": "6070b29a1a5d51193a634dc1b0a14a67c39d0ccc",
27
+ "revision": "1f6da9bec44455288ddee5ef6f3617a803d8eb2a",
28
28
  "path": "Sources/CodexBarCore/Resources/Plugins/aixy.js",
29
29
  "sha256": "975d98525503e286f9425c2a1d64fe00da8e2fdc0b00890e15c2cbcb9a37c125",
30
30
  "license": "MIT"
@@ -16,7 +16,7 @@
16
16
  "setupFields": [],
17
17
  "upstream": {
18
18
  "repository": "https://github.com/steipete/CodexBar",
19
- "revision": "6070b29a1a5d51193a634dc1b0a14a67c39d0ccc",
19
+ "revision": "1f6da9bec44455288ddee5ef6f3617a803d8eb2a",
20
20
  "path": "Sources/CodexBarCore/Resources/Plugins/atlascloud.js",
21
21
  "sha256": "852fb78abaf4fcdbbfbfeac0b60d6b82a9ca9b1d1d2f9014f6e5299b41ac47fa",
22
22
  "license": "MIT"
@@ -23,7 +23,7 @@
23
23
  ],
24
24
  "upstream": {
25
25
  "repository": "https://github.com/steipete/CodexBar",
26
- "revision": "6070b29a1a5d51193a634dc1b0a14a67c39d0ccc",
26
+ "revision": "1f6da9bec44455288ddee5ef6f3617a803d8eb2a",
27
27
  "path": "Sources/CodexBarCore/Resources/Plugins/bifrost.js",
28
28
  "sha256": "b7576d59ccd077c812118cf09d282042589a80df470c621e414583050f03aa07",
29
29
  "license": "MIT"
@@ -16,7 +16,7 @@
16
16
  "setupFields": [],
17
17
  "upstream": {
18
18
  "repository": "https://github.com/steipete/CodexBar",
19
- "revision": "6070b29a1a5d51193a634dc1b0a14a67c39d0ccc",
19
+ "revision": "1f6da9bec44455288ddee5ef6f3617a803d8eb2a",
20
20
  "path": "Sources/CodexBarCore/Resources/Plugins/chatbox.js",
21
21
  "sha256": "cf0ae84410aa3794635c0df1edf4936ae514a070968a189dc6ef613c5445f957",
22
22
  "license": "MIT"
@@ -17,7 +17,7 @@
17
17
  "setupFields": [],
18
18
  "upstream": {
19
19
  "repository": "https://github.com/steipete/CodexBar",
20
- "revision": "6070b29a1a5d51193a634dc1b0a14a67c39d0ccc",
20
+ "revision": "1f6da9bec44455288ddee5ef6f3617a803d8eb2a",
21
21
  "path": "Sources/CodexBarCore/Resources/Plugins/claudeplatform.js",
22
22
  "sha256": "d3c61855621fd4e5b5b753bdd223524e0ee7f4b55cfd63f24f23516ac33027e8",
23
23
  "license": "MIT"
@@ -382,6 +382,11 @@
382
382
  return ctx.fmt.planLabel(rawPlan) || null
383
383
  }
384
384
 
385
+ function reportedPeriod(window, fallback) {
386
+ const seconds = window && window.limit_window_seconds
387
+ return typeof seconds === "number" && Number.isFinite(seconds) && seconds > 0 ? seconds * 1000 : fallback
388
+ }
389
+
385
390
  function getResetsAtIso(ctx, nowSec, window) {
386
391
  if (!window) return null
387
392
  if (typeof window.reset_at === "number") {
@@ -780,12 +785,12 @@
780
785
 
781
786
  if (headerPrimary !== null) {
782
787
  lines.push(ctx.line.progress({
783
- label: "Session",
788
+ label: reportedPeriod(primaryWindow, PERIOD_SESSION_MS) === 30*86400000 ? "Monthly" : "Session",
784
789
  used: headerPrimary,
785
790
  limit: 100,
786
791
  format: { kind: "percent" },
787
792
  resetsAt: getResetsAtIso(ctx, nowSec, primaryWindow),
788
- periodDurationMs: PERIOD_SESSION_MS
793
+ periodDurationMs: reportedPeriod(primaryWindow, PERIOD_SESSION_MS)
789
794
  }))
790
795
  }
791
796
  if (headerSecondary !== null) {
@@ -795,19 +800,19 @@
795
800
  limit: 100,
796
801
  format: { kind: "percent" },
797
802
  resetsAt: getResetsAtIso(ctx, nowSec, secondaryWindow),
798
- periodDurationMs: PERIOD_WEEKLY_MS
803
+ periodDurationMs: reportedPeriod(secondaryWindow, PERIOD_WEEKLY_MS)
799
804
  }))
800
805
  }
801
806
 
802
807
  if (lines.length === 0 && data.rate_limit) {
803
808
  if (data.rate_limit.primary_window && typeof data.rate_limit.primary_window.used_percent === "number") {
804
809
  lines.push(ctx.line.progress({
805
- label: "Session",
810
+ label: reportedPeriod(primaryWindow, PERIOD_SESSION_MS) === 30*86400000 ? "Monthly" : "Session",
806
811
  used: data.rate_limit.primary_window.used_percent,
807
812
  limit: 100,
808
813
  format: { kind: "percent" },
809
814
  resetsAt: getResetsAtIso(ctx, nowSec, primaryWindow),
810
- periodDurationMs: PERIOD_SESSION_MS
815
+ periodDurationMs: reportedPeriod(primaryWindow, PERIOD_SESSION_MS)
811
816
  }))
812
817
  }
813
818
  if (data.rate_limit.secondary_window && typeof data.rate_limit.secondary_window.used_percent === "number") {
@@ -817,7 +822,7 @@
817
822
  limit: 100,
818
823
  format: { kind: "percent" },
819
824
  resetsAt: getResetsAtIso(ctx, nowSec, secondaryWindow),
820
- periodDurationMs: PERIOD_WEEKLY_MS
825
+ periodDurationMs: reportedPeriod(secondaryWindow, PERIOD_WEEKLY_MS)
821
826
  }))
822
827
  }
823
828
  }
@@ -16,7 +16,11 @@
16
16
  "url": "https://chatgpt.com/settings/usage?tab=overview"
17
17
  }
18
18
  ],
19
- "supportedModes": ["oauth", "local", "web"],
19
+ "supportedModes": [
20
+ "oauth",
21
+ "local",
22
+ "web"
23
+ ],
20
24
  "autoMode": "oauth",
21
25
  "webUrl": "https://chatgpt.com",
22
26
  "lines": [
@@ -77,6 +81,11 @@
77
81
  "type": "barChart",
78
82
  "label": "Usage Trend",
79
83
  "scope": "detail"
84
+ },
85
+ {
86
+ "type": "progress",
87
+ "label": "Monthly",
88
+ "scope": "overview"
80
89
  }
81
90
  ]
82
91
  }
@@ -24,7 +24,7 @@
24
24
  ],
25
25
  "upstream": {
26
26
  "repository": "https://github.com/steipete/CodexBar",
27
- "revision": "6070b29a1a5d51193a634dc1b0a14a67c39d0ccc",
27
+ "revision": "1f6da9bec44455288ddee5ef6f3617a803d8eb2a",
28
28
  "path": "Sources/CodexBarCore/Resources/Plugins/cosmic.js",
29
29
  "sha256": "eb869360f719b3b3b96311617c173e624efa05b91c0f7d31ce985f0a3a77d7a6",
30
30
  "license": "MIT"
@@ -197,15 +197,16 @@
197
197
  const injected = readInjectedCredential(ctx)
198
198
  if (injected) return injected
199
199
 
200
- const sqliteAccessToken = readStateValue(ctx, "cursorAuth/accessToken")
201
- const sqliteRefreshToken = readStateValue(ctx, "cursorAuth/refreshToken")
200
+ const usable = value => typeof value === "string" && value.trim() && !value.trim().startsWith("cursor-safe-storage:") ? value.trim() : null
201
+ const sqliteAccessToken = usable(readStateValue(ctx, "cursorAuth/accessToken"))
202
+ const sqliteRefreshToken = usable(readStateValue(ctx, "cursorAuth/refreshToken"))
202
203
  if (sqliteAccessToken || sqliteRefreshToken) {
203
204
  return { accessToken: sqliteAccessToken, refreshToken: sqliteRefreshToken, source: "sqlite" }
204
205
  }
205
206
  // Generic CLI keychain targets are shared, not tied to an IDE variant.
206
207
  // They cannot represent Nightly or an explicitly selected database profile.
207
- const keychainAccessToken = sharedCredentialsAllowed(ctx) ? readKeychainValue(ctx, KEYCHAIN_ACCESS_TOKEN_SERVICE) : null
208
- const keychainRefreshToken = sharedCredentialsAllowed(ctx) ? readKeychainValue(ctx, KEYCHAIN_REFRESH_TOKEN_SERVICE) : null
208
+ const keychainAccessToken = sharedCredentialsAllowed(ctx) ? usable(readKeychainValue(ctx, KEYCHAIN_ACCESS_TOKEN_SERVICE)) : null
209
+ const keychainRefreshToken = sharedCredentialsAllowed(ctx) ? usable(readKeychainValue(ctx, KEYCHAIN_REFRESH_TOKEN_SERVICE)) : null
209
210
 
210
211
  if (keychainAccessToken || keychainRefreshToken) {
211
212
  return {
@@ -215,6 +216,13 @@
215
216
  }
216
217
  }
217
218
 
219
+ if (sharedCredentialsAllowed(ctx) && (!ctx.provider?.instanceId || ctx.provider.instanceId === "cursor") && ctx.host.cursorPaths?.readCliAuth) {
220
+ try {
221
+ const cli = ctx.util.tryParseJson(ctx.host.cursorPaths.readCliAuth())
222
+ if (cli && (usable(cli.accessToken) || usable(cli.refreshToken)))
223
+ return {accessToken:usable(cli.accessToken),refreshToken:usable(cli.refreshToken),source:"cli-file"}
224
+ } catch (_) {}
225
+ }
218
226
  return {
219
227
  accessToken: null,
220
228
  refreshToken: null,
@@ -231,6 +239,8 @@
231
239
  if (!credential) return null
232
240
  const accessToken = String(credential.accessToken || credential.sessionKey || "").trim()
233
241
  const refreshToken = String(credential.refreshToken || "").trim()
242
+ if (accessToken.startsWith("cursor-safe-storage:") || refreshToken.startsWith("cursor-safe-storage:"))
243
+ throw {code:"credential-malformed",message:"Cursor safe-storage values are encrypted, not provider access tokens."}
234
244
  if (!accessToken && !refreshToken) return null
235
245
  return {
236
246
  accessToken: accessToken || null,
@@ -238,6 +248,7 @@
238
248
  source: "provider-account",
239
249
  }
240
250
  } catch (e) {
251
+ if (e && e.code) throw e
241
252
  ctx.host.log.warn("provider account credential read failed: " + String(e))
242
253
  return null
243
254
  }
@@ -312,6 +323,7 @@
312
323
  }
313
324
 
314
325
  function persistAccessToken(ctx, source, accessToken) {
326
+ if (source === "cli-file") return false // The Cursor CLI owns its credential file.
315
327
  if (source === "provider-account") {
316
328
  try {
317
329
  if (ctx.host.credentials && typeof ctx.host.credentials.update === "function") {
@@ -1180,7 +1192,7 @@
1180
1192
 
1181
1193
  if (!accessToken && !refreshTokenValue) {
1182
1194
  ctx.host.log.error("probe failed: no access or refresh token in sqlite/keychain")
1183
- throw "Not logged in. " + LOGIN_HINT
1195
+ throw "Not logged in. Cursor encrypted sign-ins require `agent login` for the stable CLI, or explicit provider credentials. " + LOGIN_HINT
1184
1196
  }
1185
1197
 
1186
1198
  ctx.host.log.info("tokens loaded from " + authSource + ": accessToken=" + (accessToken ? "yes" : "no") + " refreshToken=" + (refreshTokenValue ? "yes" : "no"))
@@ -1202,7 +1214,7 @@
1202
1214
  accessToken = refreshed
1203
1215
  } else if (!accessToken) {
1204
1216
  ctx.host.log.error("refresh failed and no access token available")
1205
- throw "Not logged in. " + LOGIN_HINT
1217
+ throw "Not logged in. Cursor encrypted sign-ins require `agent login` for the stable CLI, or explicit provider credentials. " + LOGIN_HINT
1206
1218
  }
1207
1219
  }
1208
1220
 
@@ -16,7 +16,7 @@
16
16
  "setupFields": [],
17
17
  "upstream": {
18
18
  "repository": "https://github.com/steipete/CodexBar",
19
- "revision": "6070b29a1a5d51193a634dc1b0a14a67c39d0ccc",
19
+ "revision": "1f6da9bec44455288ddee5ef6f3617a803d8eb2a",
20
20
  "path": "Sources/CodexBarCore/Resources/Plugins/devpass.js",
21
21
  "sha256": "6fdfab17f543fc88f28b90f76fbe6edc6db3f4d3c7fa657a899c573d363a0886",
22
22
  "license": "MIT"
@@ -24,7 +24,7 @@
24
24
  ],
25
25
  "upstream": {
26
26
  "repository": "https://github.com/steipete/CodexBar",
27
- "revision": "6070b29a1a5d51193a634dc1b0a14a67c39d0ccc",
27
+ "revision": "1f6da9bec44455288ddee5ef6f3617a803d8eb2a",
28
28
  "path": "Sources/CodexBarCore/Resources/Plugins/exa.js",
29
29
  "sha256": "36d2cbf9973e160f2e0d2548ff1f9bbf254f94c9a09710004c0718749e5cdfbd",
30
30
  "license": "MIT"
@@ -16,7 +16,7 @@
16
16
  "setupFields": [],
17
17
  "upstream": {
18
18
  "repository": "https://github.com/steipete/CodexBar",
19
- "revision": "6070b29a1a5d51193a634dc1b0a14a67c39d0ccc",
19
+ "revision": "1f6da9bec44455288ddee5ef6f3617a803d8eb2a",
20
20
  "path": "Sources/CodexBarCore/Resources/Plugins/fal.js",
21
21
  "sha256": "5c3607c74508d8fcabe8fd04fbf6ed5edfec5364c24454a7dc9e8ab0ccedd30c",
22
22
  "license": "MIT"
@@ -24,7 +24,7 @@
24
24
  ],
25
25
  "upstream": {
26
26
  "repository": "https://github.com/steipete/CodexBar",
27
- "revision": "6070b29a1a5d51193a634dc1b0a14a67c39d0ccc",
27
+ "revision": "1f6da9bec44455288ddee5ef6f3617a803d8eb2a",
28
28
  "path": "Sources/CodexBarCore/Resources/Plugins/flora.js",
29
29
  "sha256": "451732a2e088769dcd023770cfa378c2c386eea8fad137c6db676b6e305e569f",
30
30
  "license": "MIT"
@@ -24,7 +24,7 @@
24
24
  ],
25
25
  "upstream": {
26
26
  "repository": "https://github.com/steipete/CodexBar",
27
- "revision": "6070b29a1a5d51193a634dc1b0a14a67c39d0ccc",
27
+ "revision": "1f6da9bec44455288ddee5ef6f3617a803d8eb2a",
28
28
  "path": "Sources/CodexBarCore/Resources/Plugins/futureagi.js",
29
29
  "sha256": "48c4e8b36e4556bc56dfe16f954e180aba0e11fb4111e382049fe015b4340c42",
30
30
  "license": "MIT"
@@ -17,7 +17,7 @@
17
17
  "setupFields": [],
18
18
  "upstream": {
19
19
  "repository": "https://github.com/steipete/CodexBar",
20
- "revision": "6070b29a1a5d51193a634dc1b0a14a67c39d0ccc",
20
+ "revision": "1f6da9bec44455288ddee5ef6f3617a803d8eb2a",
21
21
  "path": "Sources/CodexBarCore/Resources/Plugins/gemini-web.js",
22
22
  "sha256": "7c71195603b2051ad74d85c0acc523546cf5ec62a600ae4900a1d7e54be7b02e",
23
23
  "license": "MIT"
@@ -24,7 +24,7 @@
24
24
  ],
25
25
  "upstream": {
26
26
  "repository": "https://github.com/steipete/CodexBar",
27
- "revision": "6070b29a1a5d51193a634dc1b0a14a67c39d0ccc",
27
+ "revision": "1f6da9bec44455288ddee5ef6f3617a803d8eb2a",
28
28
  "path": "Sources/CodexBarCore/Resources/Plugins/gitkraken.js",
29
29
  "sha256": "c583890b74fc4c054cd818e560b30a17dd716c7611b554bd5b559f533a824ca2",
30
30
  "license": "MIT"
@@ -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,3 @@
1
+ <svg fill="currentColor" viewBox="0.25 -0.25 24 24" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M2.5 14.5a4.5 4.5 0 1 0 9 0a4.5 4.5 0 1 0-9 0ZM6.5 10.5a6 6 0 1 0 12 0a6 6 0 1 0-12 0ZM13 14.5a4.5 4.5 0 1 0 9 0a4.5 4.5 0 1 0-9 0ZM7 12v7h10.5v-7Z"/>
3
+ </svg>
@@ -0,0 +1,204 @@
1
+ // Generated by tools/vendor-codexbar-providers.cjs; see LICENSE.
2
+ globalThis.__usagestat_bundled_options = {"labels":["Credits","Additional","Additional"],"defaults":{},"autoMode":"web","balanceOnly":true};
3
+ (function(defineProvider) {
4
+ // BEGIN UPSTREAM Sources/CodexBarCore/Resources/Plugins/googledeveloper.js
5
+ function _nullishCoalesce(lhs, rhsFn) {
6
+ if (lhs != null) {
7
+ return lhs;
8
+ } else {
9
+ return rhsFn();
10
+ }
11
+ }
12
+ defineProvider({
13
+ id: "googledeveloper",
14
+ name: "Google Developer Program",
15
+ settings: [{ key: "MESSAGES", title: "Google Developer Program", type: "plain" }],
16
+ endpoints: ["https://me.developers.google.com"],
17
+ capabilities: ["browser-cookies", "http-status"],
18
+ cookieDomains: ["me.developers.google.com", "google.com"],
19
+ cookiePolicy: { selection: "request-url", cache: "nonpersistent", imports: "access-gated" },
20
+ async fetchUsage(ctx) {
21
+ const domain = "me.developers.google.com";
22
+ const origin = `https://${domain}`;
23
+ const messages = JSON.parse(ctx.settings.get("MESSAGES") || "{}");
24
+ const message = (key, ...values) => {
25
+ let text = messages[key] || key;
26
+ for (const value of values) text = text.replace("%@", () => value);
27
+ return text;
28
+ };
29
+ const signIn = message(
30
+ "No Google Developer Program session cookies found. Sign in at me.developers.google.com/benefits or paste a Cookie header.",
31
+ );
32
+ if (ctx.browser.availability(domain) === "off")
33
+ throw ctx.fail.missingCredential(message("%@ cookies are disabled.", "Google Developer Program"));
34
+ const invalid = () => {
35
+ throw ctx.fail.parseFailure(
36
+ message("Google Developer Program returned an unrecognized response. Update CodexBar and try again."),
37
+ );
38
+ };
39
+ const json = (text) => {
40
+ try {
41
+ return JSON.parse(text);
42
+ } catch (error) {
43
+ void error;
44
+ return invalid();
45
+ }
46
+ };
47
+ const array = (value) => (Array.isArray(value) ? value : invalid());
48
+ // Google Money arrays omit zero units and nanos.
49
+ const integer = (value) =>
50
+ value === null || value === undefined
51
+ ? 0
52
+ : typeof value === "number" && Number.isSafeInteger(value)
53
+ ? value
54
+ : invalid();
55
+ const money = (value) => {
56
+ const [currency, units, nanos] = array(value);
57
+ if (typeof currency !== "string" || !/^[A-Z]{3}$/.test(currency)) return invalid();
58
+ return { currency, amount: integer(units) + integer(nanos) / 1e9 };
59
+ };
60
+ // A malformed timestamp means an unknown date, never a failed refresh.
61
+ const date = (value) => {
62
+ const seconds = Array.isArray(value) ? value[0] : undefined;
63
+ return typeof seconds === "number" && Number.isSafeInteger(seconds) && seconds > 0
64
+ ? ctx.date.unixSeconds(seconds)
65
+ : undefined;
66
+ };
67
+ const day = (value) =>
68
+ `${value.getFullYear()}-${String(value.getMonth() + 1).padStart(2, "0")}-${String(value.getDate()).padStart(2, "0")}`;
69
+ // WIZ_global_data values are JSON string literals.
70
+ const pageValue = (html, key) => {
71
+ const literal = ctx.html.matchFirst(html, `"${key}":("(?:[^"\\\\]|\\\\.)*")`);
72
+ return literal ? json(literal) : undefined;
73
+ };
74
+ // Signed-out requests redirect to accounts.google.com, which the host refuses, or answer 401 or 403.
75
+ const denied = (response) => {
76
+ if ((response.status >= 300 && response.status < 400) || response.status === 401 || response.status === 403)
77
+ return true;
78
+ if (response.status === 429) {
79
+ throw ctx.fail.rateLimited(message("Google Developer Program is rate limiting requests. Try again later."));
80
+ }
81
+ if (response.status >= 500) {
82
+ throw ctx.fail.providerUnavailable(message("Google Developer Program request failed. Try refreshing later."));
83
+ }
84
+ if (response.status !== 200) {
85
+ throw ctx.fail.apiFailure(message("Google Developer Program request failed. Try refreshing later."));
86
+ }
87
+ return false;
88
+ };
89
+ let unapplied;
90
+ let signedIn = false;
91
+ let rejected = false;
92
+ for await (const session of ctx.browser.sessions(domain)) {
93
+ const emails = [];
94
+ // Each authuser index is one signed-in Google account, and only one of them may hold the credit.
95
+ for (let account = 0; account < 8; account += 1) {
96
+ const page = await ctx.http.get(`${origin}/benefits?authuser=${account}`, {
97
+ cookieSession: session.id,
98
+ headers: { Accept: "text/html" },
99
+ retryPolicy: "transientIdempotent",
100
+ });
101
+ if (denied(page)) break;
102
+ // Signed-out pages also omit the page tokens.
103
+ const token = pageValue(page.bodyText, "SNlM0e");
104
+ const email = pageValue(page.bodyText, "oPEP7c");
105
+ if (!token || !email || emails.includes(email)) break;
106
+
107
+ const response = await ctx.http.post(
108
+ `${origin}/_/GoogleDeveloperProfile/data/batchexecute` +
109
+ `?rpcids=Ro0AYc&source-path=%2Fbenefits&hl=en&authuser=${account}&rt=c`,
110
+ {
111
+ cookieSession: session.id,
112
+ form: { "f.req": JSON.stringify([[["Ro0AYc", "[]", null, "generic"]]]), at: token },
113
+ headers: { Origin: origin, Referer: `${origin}/benefits` },
114
+ },
115
+ );
116
+ if (denied(response)) break;
117
+ emails.push(email);
118
+ signedIn = true;
119
+ // The chunked envelope alternates length lines with JSON chunks. Only the Ro0AYc result matters.
120
+ const result = response.bodyText
121
+ .split("\n")
122
+ .filter((line) => line.startsWith("["))
123
+ .flatMap((line) => array(json(line)))
124
+ .find((entry) => Array.isArray(entry) && entry[0] === "wrb.fr" && entry[1] === "Ro0AYc");
125
+ if (!result) return invalid();
126
+ // A per-account RPC error has no string payload, so try the next account.
127
+ if (typeof result[2] !== "string") continue;
128
+ const list = array(json(result[2]))[0];
129
+ // Benefit type 19 is the monthly Gen AI & Cloud credit of Google AI Pro and Ultra.
130
+ const credit = array(_nullishCoalesce(list, () => []))
131
+ .map((benefit) => array(benefit))
132
+ .find((benefit) => benefit[0] === 19);
133
+ if (!credit) continue;
134
+ const offer = array(_nullishCoalesce(credit[9], () => []));
135
+ // A credit that is not applied to a billing account yet has no money fields.
136
+ if (offer[6] === null || offer[6] === undefined) {
137
+ unapplied ??= email;
138
+ continue;
139
+ }
140
+ const billing = array(offer[6]);
141
+ const granted = money(billing[0]);
142
+ const remaining = money(billing[1]);
143
+ if (granted.amount <= 0) return invalid();
144
+ if (remaining.currency !== granted.currency) return invalid();
145
+ const currency = granted.currency;
146
+ const left = Math.max(0, remaining.amount);
147
+ const expiresAt = date(offer[1]);
148
+ const grantedAt = date(offer[16]);
149
+ const amounts = message(
150
+ "%@ of %@ left",
151
+ ctx.format.currency(left, currency),
152
+ ctx.format.currency(granted.amount, currency),
153
+ );
154
+ // The billing account is display-only, so an unexpected format never fails the refresh.
155
+ const rows =
156
+ typeof billing[2] === "string"
157
+ ? [{ label: "Billing account", value: billing[2].replace(/^billingAccounts\//, "") }]
158
+ : [];
159
+ if (grantedAt) rows.push({ label: "Granted", value: day(grantedAt) });
160
+ return {
161
+ primary: {
162
+ usedPercent: ctx.pct(granted.amount - left, granted.amount),
163
+ resetDescription: expiresAt ? `${amounts} · ${message("Expires %@", day(expiresAt))}` : amounts,
164
+ },
165
+ cost: { used: left, currency, period: "Monthly credits", balance: left },
166
+ details: [{ title: "Billing", rows }],
167
+ identity: { email, loginMethod: message("Browser session") },
168
+ dataConfidence: "exact",
169
+ };
170
+ }
171
+ if (signedIn) break;
172
+ // A session whose first account fails the page or the RPC is signed out.
173
+ ctx.browser.rejectCookie(domain, session);
174
+ rejected = true;
175
+ }
176
+ if (unapplied) {
177
+ return {
178
+ details: [
179
+ {
180
+ title: "Cloud credits",
181
+ rows: [
182
+ {
183
+ label: "Status",
184
+ value: message("Not applied"),
185
+ secondaryValue: "me.developers.google.com/benefits",
186
+ },
187
+ ],
188
+ },
189
+ ],
190
+ identity: { email: unapplied, loginMethod: message("Browser session") },
191
+ dataConfidence: "exact",
192
+ };
193
+ }
194
+ if (signedIn)
195
+ throw ctx.fail.permissionDenied(message("No Cloud credit found. Check your Google Developer Program benefits."));
196
+ if (rejected) throw ctx.fail.authenticationExpired(`${message("Google session expired or invalid.")} ${signIn}`);
197
+ throw ctx.fail.missingCredential(
198
+ `${signIn} ${message("Supported browsers: %@. Use Manual for other browsers.", ctx.browser.supportedBrowsers)}`,
199
+ );
200
+ },
201
+ });
202
+
203
+ // END UPSTREAM
204
+ })(globalThis.defineProvider);
@@ -0,0 +1,25 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "id": "googledeveloper",
4
+ "name": "Google Developer Program",
5
+ "version": "0.1.0",
6
+ "entry": "plugin.js",
7
+ "enabledByDefault": false,
8
+ "supportedModes": [
9
+ "web"
10
+ ],
11
+ "autoMode": "web",
12
+ "usageDashboardUrl": "https://me.developers.google.com/benefits",
13
+ "webUrl": "https://me.developers.google.com",
14
+ "envVars": [
15
+ "GOOGLEDEVELOPER_COOKIE"
16
+ ],
17
+ "setupFields": [],
18
+ "upstream": {
19
+ "repository": "https://github.com/steipete/CodexBar",
20
+ "revision": "1f6da9bec44455288ddee5ef6f3617a803d8eb2a",
21
+ "path": "Sources/CodexBarCore/Resources/Plugins/googledeveloper.js",
22
+ "sha256": "16f97c5fa06d7f4b4255f1e0413af01fa9a0ee7af03243701a40b0f6294564c0",
23
+ "license": "MIT"
24
+ }
25
+ }