@hashimkarim/usagestat-linux-x64-gnu 2.0.0-alpha.1 → 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 (384) hide show
  1. package/LICENSE +0 -0
  2. package/native-manifest.json +1088 -134
  3. package/package.json +160 -1
  4. package/plugins/UPSTREAM-LICENSES.md +113 -0
  5. package/plugins/_provider-icons/LICENSE +21 -0
  6. package/plugins/_provider-icons/NOTICE +12 -0
  7. package/plugins/_provider-icons/licenses/CodexBar-MIT.txt +21 -0
  8. package/plugins/_provider-icons/licenses/LobeHub-MIT.txt +21 -0
  9. package/plugins/_provider-icons/licenses/UsageStat-Bar-MIT.txt +21 -0
  10. package/plugins/_provider-icons/manifest.json +1219 -0
  11. package/plugins/_provider-icons/provenance.json +269 -0
  12. package/plugins/_provider-icons/source.json +4 -0
  13. package/plugins/abacus-ai/icon-color.svg +18 -0
  14. package/plugins/abacus-ai/icon.svg +0 -0
  15. package/plugins/abacus-ai/plugin.js +0 -0
  16. package/plugins/abacus-ai/plugin.json +0 -0
  17. package/plugins/aiand/icon.svg +6 -0
  18. package/plugins/aiand/plugin.js +108 -0
  19. package/plugins/aiand/plugin.json +22 -0
  20. package/plugins/aixy/LICENSE +21 -0
  21. package/plugins/aixy/plugin.js +261 -0
  22. package/plugins/aixy/plugin.json +24 -0
  23. package/plugins/alibaba/icon-color.svg +0 -0
  24. package/plugins/alibaba/icon.svg +0 -0
  25. package/plugins/alibaba/plugin.js +0 -0
  26. package/plugins/alibaba/plugin.json +0 -0
  27. package/plugins/alibaba-token-plan/icon-color.svg +0 -0
  28. package/plugins/alibaba-token-plan/icon.svg +0 -0
  29. package/plugins/alibaba-token-plan/plugin.js +0 -0
  30. package/plugins/alibaba-token-plan/plugin.json +0 -0
  31. package/plugins/amp/icon-color.svg +0 -0
  32. package/plugins/amp/icon-conflict.svg +0 -0
  33. package/plugins/amp/icon.svg +0 -0
  34. package/plugins/amp/plugin.js +0 -0
  35. package/plugins/amp/plugin.json +0 -0
  36. package/plugins/antigravity/icon-color.svg +0 -0
  37. package/plugins/antigravity/icon-conflict.svg +0 -0
  38. package/plugins/antigravity/icon.svg +0 -0
  39. package/plugins/antigravity/plugin.js +136 -46
  40. package/plugins/antigravity/plugin.json +0 -0
  41. package/plugins/antigravity-cli/icon-color.svg +1 -0
  42. package/plugins/antigravity-cli/icon.svg +1 -3
  43. package/plugins/antigravity-cli/plugin.js +11 -15
  44. package/plugins/antigravity-cli/plugin.json +0 -0
  45. package/plugins/antigravity-ide/icon-color.svg +1 -0
  46. package/plugins/antigravity-ide/icon.svg +1 -3
  47. package/plugins/antigravity-ide/plugin.js +0 -0
  48. package/plugins/antigravity-ide/plugin.json +0 -0
  49. package/plugins/atlascloud/LICENSE +21 -0
  50. package/plugins/atlascloud/icon-color.svg +1 -0
  51. package/plugins/atlascloud/icon.svg +1 -0
  52. package/plugins/atlascloud/plugin.js +49 -0
  53. package/plugins/atlascloud/plugin.json +23 -0
  54. package/plugins/augment/icon-color.svg +14 -0
  55. package/plugins/augment/icon.svg +0 -0
  56. package/plugins/augment/plugin.js +0 -0
  57. package/plugins/augment/plugin.json +0 -0
  58. package/plugins/aws-bedrock/icon-color.svg +0 -0
  59. package/plugins/aws-bedrock/icon.svg +0 -0
  60. package/plugins/aws-bedrock/plugin.js +0 -0
  61. package/plugins/aws-bedrock/plugin.json +0 -0
  62. package/plugins/azure-openai/icon-color.svg +0 -0
  63. package/plugins/azure-openai/icon.svg +0 -0
  64. package/plugins/azure-openai/plugin.js +0 -0
  65. package/plugins/azure-openai/plugin.json +0 -0
  66. package/plugins/bifrost/LICENSE +21 -0
  67. package/plugins/bifrost/plugin.js +361 -0
  68. package/plugins/bifrost/plugin.json +23 -0
  69. package/plugins/chutes/icon.svg +0 -0
  70. package/plugins/chutes/plugin.js +0 -0
  71. package/plugins/chutes/plugin.json +0 -0
  72. package/plugins/claude/icon-color.svg +0 -0
  73. package/plugins/claude/icon.svg +0 -0
  74. package/plugins/claude/plugin.js +358 -161
  75. package/plugins/claude/plugin.json +1 -1
  76. package/plugins/clawrouter/icon.svg +7 -0
  77. package/plugins/clawrouter/plugin.js +45 -0
  78. package/plugins/clawrouter/plugin.json +22 -0
  79. package/plugins/clinepass/icon.svg +4 -0
  80. package/plugins/clinepass/plugin.js +87 -0
  81. package/plugins/clinepass/plugin.json +23 -0
  82. package/plugins/codebuddy/plugin.js +331 -0
  83. package/plugins/codebuddy/plugin.json +30 -0
  84. package/plugins/codebuff/icon-color.svg +92 -0
  85. package/plugins/codebuff/icon.svg +0 -0
  86. package/plugins/codebuff/plugin.js +0 -0
  87. package/plugins/codebuff/plugin.json +0 -0
  88. package/plugins/coderabbit/plugin.js +25 -0
  89. package/plugins/coderabbit/plugin.json +12 -0
  90. package/plugins/codex/icon-color.svg +0 -0
  91. package/plugins/codex/icon.svg +0 -0
  92. package/plugins/codex/plugin.js +8 -2
  93. package/plugins/codex/plugin.json +0 -0
  94. package/plugins/command-code/icon-color.svg +3 -0
  95. package/plugins/command-code/icon.svg +0 -0
  96. package/plugins/command-code/plugin.js +14 -3
  97. package/plugins/command-code/plugin.json +0 -0
  98. package/plugins/copilot/icon-color.svg +0 -0
  99. package/plugins/copilot/icon.svg +1 -1
  100. package/plugins/copilot/plugin.js +61 -9
  101. package/plugins/copilot/plugin.json +4 -1
  102. package/plugins/crof/icon-color.svg +3 -0
  103. package/plugins/crof/icon.svg +0 -0
  104. package/plugins/crof/plugin.js +0 -0
  105. package/plugins/crof/plugin.json +0 -0
  106. package/plugins/crofai/icon-color.svg +3 -0
  107. package/plugins/crofai/icon.svg +2 -15
  108. package/plugins/crofai/plugin.js +0 -0
  109. package/plugins/crofai/plugin.json +0 -0
  110. package/plugins/cursor/icon-color.svg +1 -0
  111. package/plugins/cursor/icon-conflict.svg +0 -0
  112. package/plugins/cursor/icon.svg +0 -0
  113. package/plugins/cursor/plugin.js +46 -9
  114. package/plugins/cursor/plugin.json +3 -2
  115. package/plugins/cursor-nightly/icon.png +0 -0
  116. package/plugins/cursor-nightly/plugin.js +45 -8
  117. package/plugins/cursor-nightly/plugin.json +3 -2
  118. package/plugins/deepgram/icon.svg +0 -0
  119. package/plugins/deepgram/plugin.js +0 -0
  120. package/plugins/deepgram/plugin.json +0 -0
  121. package/plugins/deepinfra/icon-color.svg +1 -0
  122. package/plugins/deepinfra/icon.svg +1 -0
  123. package/plugins/deepinfra/plugin.js +97 -0
  124. package/plugins/deepinfra/plugin.json +28 -0
  125. package/plugins/deepseek/icon-color.svg +0 -0
  126. package/plugins/deepseek/icon.svg +0 -0
  127. package/plugins/deepseek/plugin.js +150 -59
  128. package/plugins/deepseek/plugin.json +3 -1
  129. package/plugins/devin/icon.svg +0 -0
  130. package/plugins/devin/plugin.js +114 -0
  131. package/plugins/devin/plugin.json +2 -1
  132. package/plugins/devpass/LICENSE +21 -0
  133. package/plugins/devpass/plugin.js +115 -0
  134. package/plugins/devpass/plugin.json +23 -0
  135. package/plugins/doubao/icon-color.svg +0 -0
  136. package/plugins/doubao/icon.svg +0 -0
  137. package/plugins/doubao/plugin.js +0 -0
  138. package/plugins/doubao/plugin.json +0 -0
  139. package/plugins/droid/icon.svg +0 -0
  140. package/plugins/droid/plugin.json +2 -1
  141. package/plugins/elevenlabs/icon-color.svg +4 -0
  142. package/plugins/elevenlabs/icon.svg +0 -0
  143. package/plugins/elevenlabs/plugin.js +17 -2
  144. package/plugins/elevenlabs/plugin.json +0 -0
  145. package/plugins/factory/icon-color.svg +1 -0
  146. package/plugins/factory/icon-conflict.svg +0 -0
  147. package/plugins/factory/icon.svg +0 -0
  148. package/plugins/factory/plugin.js +38 -14
  149. package/plugins/factory/plugin.json +2 -1
  150. package/plugins/fireworks-ai/icon-color.svg +1 -0
  151. package/plugins/fireworks-ai/icon.svg +1 -6
  152. package/plugins/fireworks-ai/plugin.js +0 -0
  153. package/plugins/fireworks-ai/plugin.json +0 -0
  154. package/plugins/gemini/icon-color.svg +0 -0
  155. package/plugins/gemini/icon.svg +0 -0
  156. package/plugins/gemini/plugin.js +0 -0
  157. package/plugins/gemini/plugin.json +0 -0
  158. package/plugins/gemini-apps/LICENSE +22 -0
  159. package/plugins/gemini-apps/icon-color.svg +1 -0
  160. package/plugins/gemini-apps/icon.svg +1 -0
  161. package/plugins/gemini-apps/plugin.js +470 -0
  162. package/plugins/gemini-apps/plugin.json +19 -0
  163. package/plugins/gitkraken/LICENSE +21 -0
  164. package/plugins/gitkraken/plugin.js +153 -0
  165. package/plugins/gitkraken/plugin.json +24 -0
  166. package/plugins/grok/icon-color.svg +1 -0
  167. package/plugins/grok/icon.svg +0 -0
  168. package/plugins/grok/plugin.js +30 -5
  169. package/plugins/grok/plugin.json +3 -1
  170. package/plugins/groqcloud/icon-color.svg +1 -0
  171. package/plugins/groqcloud/icon.svg +0 -0
  172. package/plugins/groqcloud/plugin.js +0 -0
  173. package/plugins/groqcloud/plugin.json +0 -0
  174. package/plugins/helmcode/LICENSE +21 -0
  175. package/plugins/helmcode/plugin.js +188 -0
  176. package/plugins/helmcode/plugin.json +24 -0
  177. package/plugins/huggingface/LICENSE +21 -0
  178. package/plugins/huggingface/icon-color.svg +1 -0
  179. package/plugins/huggingface/icon.svg +1 -0
  180. package/plugins/huggingface/plugin.js +293 -0
  181. package/plugins/huggingface/plugin.json +25 -0
  182. package/plugins/hyper/LICENSE +21 -0
  183. package/plugins/hyper/plugin.js +131 -0
  184. package/plugins/hyper/plugin.json +26 -0
  185. package/plugins/ibmbob/icon.svg +23 -0
  186. package/plugins/ibmbob/plugin.js +61 -0
  187. package/plugins/ibmbob/plugin.json +22 -0
  188. package/plugins/jetbrains-ai-assistant/icon-color.svg +0 -0
  189. package/plugins/jetbrains-ai-assistant/icon-conflict.svg +0 -0
  190. package/plugins/jetbrains-ai-assistant/icon.svg +0 -0
  191. package/plugins/jetbrains-ai-assistant/plugin.js +0 -0
  192. package/plugins/jetbrains-ai-assistant/plugin.json +0 -0
  193. package/plugins/kilo/icon-color.svg +1 -0
  194. package/plugins/kilo/icon.svg +0 -0
  195. package/plugins/kilo/plugin.js +0 -0
  196. package/plugins/kilo/plugin.json +0 -0
  197. package/plugins/kimi/icon-color.svg +0 -0
  198. package/plugins/kimi/icon-conflict.svg +0 -0
  199. package/plugins/kimi/icon.svg +0 -0
  200. package/plugins/kimi/plugin.js +122 -141
  201. package/plugins/kimi/plugin.json +5 -2
  202. package/plugins/kimi-k2/icon-color.svg +0 -0
  203. package/plugins/kimi-k2/icon.svg +0 -0
  204. package/plugins/kimi-k2/plugin.js +0 -0
  205. package/plugins/kimi-k2/plugin.json +0 -0
  206. package/plugins/kiro/icon-color.svg +0 -0
  207. package/plugins/kiro/icon-conflict.svg +0 -0
  208. package/plugins/kiro/icon.svg +0 -0
  209. package/plugins/kiro/plugin.js +49 -10
  210. package/plugins/kiro/plugin.json +3 -1
  211. package/plugins/litellm/icon.svg +0 -0
  212. package/plugins/litellm/plugin.js +54 -3
  213. package/plugins/litellm/plugin.json +0 -0
  214. package/plugins/llm-proxy/icon.svg +0 -0
  215. package/plugins/llm-proxy/plugin.js +0 -0
  216. package/plugins/llm-proxy/plugin.json +0 -0
  217. package/plugins/llmman/LICENSE +21 -0
  218. package/plugins/llmman/plugin.js +133 -0
  219. package/plugins/llmman/plugin.json +23 -0
  220. package/plugins/longcat/icon-color.svg +1 -0
  221. package/plugins/longcat/icon.svg +1 -0
  222. package/plugins/longcat/plugin.js +182 -0
  223. package/plugins/longcat/plugin.json +23 -0
  224. package/plugins/manus/icon-color.svg +6 -0
  225. package/plugins/manus/icon.svg +0 -0
  226. package/plugins/manus/plugin.js +0 -0
  227. package/plugins/manus/plugin.json +0 -0
  228. package/plugins/mimo/icon-color.svg +4 -0
  229. package/plugins/mimo/icon.svg +4 -1
  230. package/plugins/mimo/plugin.js +0 -0
  231. package/plugins/mimo/plugin.json +0 -0
  232. package/plugins/minimax/icon-color.svg +0 -0
  233. package/plugins/minimax/icon-conflict.svg +0 -0
  234. package/plugins/minimax/icon.svg +0 -0
  235. package/plugins/minimax/plugin.js +25 -31
  236. package/plugins/minimax/plugin.json +0 -0
  237. package/plugins/mistral/icon-color.svg +0 -0
  238. package/plugins/mistral/icon.svg +0 -0
  239. package/plugins/mistral/plugin.js +110 -5
  240. package/plugins/mistral/plugin.json +0 -0
  241. package/plugins/moonshot/icon-color.svg +1 -0
  242. package/plugins/moonshot/icon.svg +0 -0
  243. package/plugins/moonshot/plugin.js +8 -6
  244. package/plugins/moonshot/plugin.json +0 -0
  245. package/plugins/muse/LICENSE +21 -0
  246. package/plugins/muse/plugin.js +319 -0
  247. package/plugins/muse/plugin.json +26 -0
  248. package/plugins/nanogpt/icon-color.svg +0 -0
  249. package/plugins/nanogpt/icon.svg +0 -0
  250. package/plugins/nanogpt/plugin.js +0 -0
  251. package/plugins/nanogpt/plugin.json +0 -0
  252. package/plugins/neuralwatt/icon.svg +0 -0
  253. package/plugins/neuralwatt/plugin.js +0 -0
  254. package/plugins/neuralwatt/plugin.json +0 -0
  255. package/plugins/notion/icon.svg +1 -0
  256. package/plugins/notion/plugin.js +282 -0
  257. package/plugins/notion/plugin.json +29 -0
  258. package/plugins/nous/LICENSE +21 -0
  259. package/plugins/nous/icon-color.svg +1 -0
  260. package/plugins/nous/icon.svg +1 -0
  261. package/plugins/nous/plugin.js +124 -0
  262. package/plugins/nous/plugin.json +24 -0
  263. package/plugins/ollama/icon-color.svg +1 -0
  264. package/plugins/ollama/icon.svg +0 -0
  265. package/plugins/ollama/plugin.js +257 -56
  266. package/plugins/ollama/plugin.json +6 -3
  267. package/plugins/openai-api/icon-color.svg +1 -0
  268. package/plugins/openai-api/icon.svg +0 -0
  269. package/plugins/openai-api/plugin.js +0 -0
  270. package/plugins/openai-api/plugin.json +0 -0
  271. package/plugins/opencode/icon-color.svg +1 -0
  272. package/plugins/opencode/icon.svg +0 -0
  273. package/plugins/opencode/plugin.js +0 -0
  274. package/plugins/opencode/plugin.json +0 -0
  275. package/plugins/opencode-go/icon-color.svg +1 -0
  276. package/plugins/opencode-go/icon-conflict.svg +0 -0
  277. package/plugins/opencode-go/icon.svg +0 -0
  278. package/plugins/opencode-go/plugin.js +103 -17
  279. package/plugins/opencode-go/plugin.json +5 -2
  280. package/plugins/openrouter/icon-color.svg +1 -0
  281. package/plugins/openrouter/icon.svg +0 -0
  282. package/plugins/openrouter/plugin.js +371 -114
  283. package/plugins/openrouter/plugin.json +6 -0
  284. package/plugins/perplexity/icon-color.svg +0 -0
  285. package/plugins/perplexity/icon-conflict.svg +0 -0
  286. package/plugins/perplexity/icon.svg +0 -0
  287. package/plugins/perplexity/plugin.js +0 -0
  288. package/plugins/perplexity/plugin.json +0 -0
  289. package/plugins/pi/plugin.js +113 -0
  290. package/plugins/pi/plugin.json +11 -0
  291. package/plugins/poe/icon.svg +0 -0
  292. package/plugins/poe/plugin.js +24 -18
  293. package/plugins/poe/plugin.json +2 -0
  294. package/plugins/qoder/icon.svg +3 -0
  295. package/plugins/qoder/plugin.js +227 -0
  296. package/plugins/qoder/plugin.json +23 -0
  297. package/plugins/qwencloud/icon-color.svg +1 -0
  298. package/plugins/qwencloud/icon.svg +1 -0
  299. package/plugins/qwencloud/plugin.js +677 -0
  300. package/plugins/qwencloud/plugin.json +29 -0
  301. package/plugins/raycast/LICENSE +21 -0
  302. package/plugins/raycast/plugin.js +174 -0
  303. package/plugins/raycast/plugin.json +24 -0
  304. package/plugins/replicate/LICENSE +21 -0
  305. package/plugins/replicate/icon-color.svg +1 -0
  306. package/plugins/replicate/icon.svg +1 -0
  307. package/plugins/replicate/plugin.js +165 -0
  308. package/plugins/replicate/plugin.json +24 -0
  309. package/plugins/sakana/icon.svg +5 -0
  310. package/plugins/sakana/plugin.js +156 -0
  311. package/plugins/sakana/plugin.json +23 -0
  312. package/plugins/stepfun/icon-color.svg +0 -0
  313. package/plugins/stepfun/icon.svg +0 -0
  314. package/plugins/stepfun/plugin.js +0 -0
  315. package/plugins/stepfun/plugin.json +0 -0
  316. package/plugins/sub2api/icon.svg +4 -0
  317. package/plugins/sub2api/plugin.js +191 -0
  318. package/plugins/sub2api/plugin.json +16 -0
  319. package/plugins/synthetic/icon-color.svg +14 -0
  320. package/plugins/synthetic/icon-conflict.svg +0 -0
  321. package/plugins/synthetic/icon.svg +0 -0
  322. package/plugins/synthetic/plugin.js +0 -0
  323. package/plugins/synthetic/plugin.json +0 -0
  324. package/plugins/t3chat/icon-color.svg +0 -0
  325. package/plugins/t3chat/icon.svg +0 -0
  326. package/plugins/t3chat/plugin.js +0 -0
  327. package/plugins/t3chat/plugin.json +0 -0
  328. package/plugins/typesafe/LICENSE +21 -0
  329. package/plugins/typesafe/plugin.js +225 -0
  330. package/plugins/typesafe/plugin.json +24 -0
  331. package/plugins/v0/LICENSE +21 -0
  332. package/plugins/v0/icon-color.svg +1 -0
  333. package/plugins/v0/icon.svg +1 -0
  334. package/plugins/v0/plugin.js +214 -0
  335. package/plugins/v0/plugin.json +24 -0
  336. package/plugins/venice/icon-color.svg +0 -0
  337. package/plugins/venice/icon.svg +0 -0
  338. package/plugins/venice/plugin.js +50 -1
  339. package/plugins/venice/plugin.json +2 -1
  340. package/plugins/vercel/LICENSE +21 -0
  341. package/plugins/vercel/icon-color.svg +1 -0
  342. package/plugins/vercel/icon.svg +1 -0
  343. package/plugins/vercel/plugin.js +55 -0
  344. package/plugins/vercel/plugin.json +23 -0
  345. package/plugins/vertex-ai/icon-color.svg +0 -0
  346. package/plugins/vertex-ai/icon.svg +0 -0
  347. package/plugins/vertex-ai/plugin.js +0 -0
  348. package/plugins/vertex-ai/plugin.json +0 -0
  349. package/plugins/warp/icon-color.svg +0 -0
  350. package/plugins/warp/icon.svg +0 -0
  351. package/plugins/warp/plugin.js +0 -0
  352. package/plugins/warp/plugin.json +0 -0
  353. package/plugins/wayfinder/icon.svg +5 -0
  354. package/plugins/wayfinder/plugin.js +47 -0
  355. package/plugins/wayfinder/plugin.json +16 -0
  356. package/plugins/windsurf/icon-color.svg +1 -0
  357. package/plugins/windsurf/icon-conflict.svg +0 -0
  358. package/plugins/windsurf/icon.svg +0 -0
  359. package/plugins/windsurf/plugin.js +0 -0
  360. package/plugins/windsurf/plugin.json +0 -0
  361. package/plugins/xai/icon-color.svg +1 -0
  362. package/plugins/xai/icon.svg +1 -0
  363. package/plugins/xai/plugin.js +162 -0
  364. package/plugins/xai/plugin.json +28 -0
  365. package/plugins/xkiro/LICENSE +21 -0
  366. package/plugins/xkiro/plugin.js +99 -0
  367. package/plugins/xkiro/plugin.json +23 -0
  368. package/plugins/zai/icon-color.svg +1 -0
  369. package/plugins/zai/icon-conflict.svg +0 -0
  370. package/plugins/zai/icon.svg +0 -0
  371. package/plugins/zai/plugin.js +111 -161
  372. package/plugins/zai/plugin.json +4 -1
  373. package/plugins/zed/icon.svg +0 -0
  374. package/plugins/zed/plugin.js +0 -0
  375. package/plugins/zed/plugin.json +0 -0
  376. package/plugins/zenmux/icon-color.svg +1 -0
  377. package/plugins/zenmux/icon.svg +1 -0
  378. package/plugins/zenmux/plugin.js +102 -0
  379. package/plugins/zenmux/plugin.json +23 -0
  380. package/plugins/zoommate/icon.svg +1 -0
  381. package/plugins/zoommate/plugin.js +244 -0
  382. package/plugins/zoommate/plugin.json +29 -0
  383. package/usagestat +0 -0
  384. package/usagestatd +0 -0
@@ -0,0 +1,293 @@
1
+ // Generated by tools/vendor-codexbar-providers.cjs; see LICENSE.
2
+ globalThis.__usagestat_bundled_options = {"labels":["Inference","ZeroGPU","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
+
32
+ defineProvider({
33
+ id: "huggingface",
34
+ name: "Hugging Face",
35
+ endpoints: ["https://huggingface.co"],
36
+ settings: [{ key: "HF_TOKEN", title: "Access token", type: "secure" }],
37
+ capabilities: ["browser-cookies", "http-status"],
38
+ cookieDomains: ["huggingface.co"],
39
+ async fetchUsage(ctx) {
40
+ const fail = (field) => {
41
+ throw ctx.fail.parseFailure(`Hugging Face billing response format changed: ${field}`);
42
+ };
43
+ const object = (value, field) => {
44
+ if (!value || typeof value !== "object" || Array.isArray(value)) return fail(field);
45
+ return value;
46
+ };
47
+ const number = (value, field) => {
48
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 0) return fail(field);
49
+ return value;
50
+ };
51
+ const optionalNumber = (value, field) => (value === undefined || value === null ? undefined : number(value, field));
52
+ const parse = (body) => {
53
+ let value;
54
+ try {
55
+ value = JSON.parse(body);
56
+ } catch (error) {
57
+ void error;
58
+ return fail("invalid JSON");
59
+ }
60
+ return object(value, "expected an object");
61
+ };
62
+ const date = (value) => {
63
+ if (value === undefined || value === null) return undefined;
64
+ if (typeof value === "number") {
65
+ if (!Number.isFinite(value) || value <= 0 || value > 64092211200) return undefined;
66
+ return ctx.date.unixSeconds(value);
67
+ }
68
+ if (typeof value === "string") {
69
+ try {
70
+ return ctx.date.iso(value);
71
+ } catch (error) {
72
+ void error;
73
+ }
74
+ }
75
+ return undefined;
76
+ };
77
+ const text = (value) => (typeof value === "string" ? value.trim() || undefined : undefined);
78
+ const userID = (profile) =>
79
+ profile.type === "user" && typeof profile.id === "string" && profile.id.trim() ? profile.id : undefined;
80
+ // Keep bearer authority off requests that verify the browser session.
81
+ const token = ctx.settings.getSecret("HF_TOKEN");
82
+ if (!token) throw ctx.fail.missingCredential("Missing Hugging Face access token.");
83
+ const apiHeaders = { Authorization: `Bearer ${token}`, "User-Agent": "CodexBar" };
84
+ const now = ctx.date.now();
85
+ const start = Math.floor(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1) / 1000);
86
+ const end = Math.floor(now.getTime() / 1000);
87
+ const response = await ctx.http.get(
88
+ `https://huggingface.co/api/settings/billing/usage-v2?startDate=${start}&endDate=${end}`,
89
+ { timeoutSeconds: 15, headers: apiHeaders },
90
+ );
91
+ if (response.status === 401) {
92
+ throw ctx.fail.authenticationExpired("Hugging Face rejected the token. Check that it is valid and not expired.");
93
+ }
94
+ if (response.status === 403) {
95
+ throw ctx.fail.permissionDenied(
96
+ "The Hugging Face token lacks billing access. Use a classic read token or enable Billing read on a fine-grained token.",
97
+ );
98
+ }
99
+ if (response.status === 429) throw ctx.fail.rateLimited("Hugging Face rate limit reached. Retry later.");
100
+ if (response.status >= 500)
101
+ throw ctx.fail.providerUnavailable(`Hugging Face API returned HTTP ${response.status}.`);
102
+ if (response.status < 200 || response.status >= 300) {
103
+ throw ctx.fail.apiFailure(`Hugging Face API returned HTTP ${response.status}.`);
104
+ }
105
+ const usage = object(parse(response.bodyText).usage, "missing usage");
106
+ const inference = object(usage.inferenceProviders, "missing inferenceProviders usage");
107
+ const gross = number(inference.usedNanoUsd, "usedNanoUsd") / 1e9;
108
+ const included = number(inference.includedNanoUsd, "includedNanoUsd") / 1e9;
109
+ const billable = Math.max(0, gross - included);
110
+ const limit = _nullishCoalesce(optionalNumber(inference.limitNanoUsd, "limitNanoUsd"), () => 0) / 1e9;
111
+ const requests = optionalNumber(inference.numRequests, "numRequests");
112
+ if (requests !== undefined && !Number.isSafeInteger(requests)) return fail("numRequests");
113
+ let secondary;
114
+ let gpuRows = [];
115
+ try {
116
+ const gpuResponse = await ctx.http.get("https://huggingface.co/api/spaces/zero-gpu/quota", {
117
+ timeoutSeconds: 2,
118
+ headers: apiHeaders,
119
+ });
120
+ if (gpuResponse.status >= 200 && gpuResponse.status < 300) {
121
+ const gpu = parse(gpuResponse.bodyText);
122
+ const total = number(gpu.base, "ZeroGPU base");
123
+ const remaining = number(gpu.current, "ZeroGPU current");
124
+ if (total > 0) {
125
+ const consumed = Math.max(0, total - remaining);
126
+ secondary = {
127
+ usedPercent: ctx.pct(consumed, total),
128
+ resetsAt: date(gpu.resetsAt),
129
+ resetDescription: "ZeroGPU quota",
130
+ };
131
+ const minutes = (seconds) =>
132
+ `${ctx.format.number(seconds / 60, {
133
+ minimumFractionDigits: seconds >= 600 ? 0 : 1,
134
+ maximumFractionDigits: seconds >= 600 ? 0 : 1,
135
+ })} min`;
136
+ gpuRows = [
137
+ { label: "GPU time used", value: minutes(consumed) },
138
+ { label: "GPU time remaining", value: minutes(remaining) },
139
+ ];
140
+ }
141
+ }
142
+ } catch (error) {
143
+ void error;
144
+ }
145
+ const cacheKey = "whoami-v2:" + token;
146
+ let identity = ctx.cache.get(cacheKey);
147
+ if (!identity || now.getTime() - identity.fetchedAt < 0 || now.getTime() - identity.fetchedAt >= 43200000) {
148
+ identity = undefined;
149
+ try {
150
+ const whoami = await ctx.http.get("https://huggingface.co/api/whoami-v2", {
151
+ timeoutSeconds: 2,
152
+ headers: apiHeaders,
153
+ });
154
+ if (whoami.status >= 200 && whoami.status < 300) {
155
+ const profile = parse(whoami.bodyText);
156
+ const username = text(profile.name);
157
+ const email = text(profile.email);
158
+ if (username || email || userID(profile)) {
159
+ identity = {
160
+ fetchedAt: now.getTime(),
161
+ userID: userID(profile),
162
+ username,
163
+ email,
164
+ plan: typeof profile.isPro === "boolean" ? (profile.isPro ? "PRO" : "Free") : undefined,
165
+ };
166
+ ctx.cache.set(cacheKey, identity, 43200);
167
+ }
168
+ }
169
+ } catch (error) {
170
+ void error;
171
+ }
172
+ }
173
+ let balance;
174
+ const availability = ctx.browser.availability("huggingface.co");
175
+ if (
176
+ _optionalChain([identity, "optionalAccess", (_2) => _2.userID]) &&
177
+ (availability === "available" || availability === "manual")
178
+ ) {
179
+ try {
180
+ const cookie = await ctx.browser.cookieHeader("huggingface.co");
181
+ const web = async (path, accept) => {
182
+ const result = await ctx.http.get(`https://huggingface.co${path}`, {
183
+ headers: { Cookie: cookie, Accept: accept },
184
+ timeoutSeconds: 2,
185
+ });
186
+ if (result.status === 401 || result.status === 403) ctx.browser.rejectCookie("huggingface.co");
187
+ if (result.status !== 200) return fail("wallet unavailable");
188
+ return result;
189
+ };
190
+ const billing = await web("/settings/billing", "text/html");
191
+ if (
192
+ !_optionalChain([
193
+ billing,
194
+ "access",
195
+ (_3) => _3.headers,
196
+ "access",
197
+ (_4) => _4["content-type"],
198
+ "optionalAccess",
199
+ (_5) => _5.toLowerCase,
200
+ "call",
201
+ (_6) => _6(),
202
+ "access",
203
+ (_7) => _7.includes,
204
+ "call",
205
+ (_8) => _8("text/html"),
206
+ ])
207
+ )
208
+ return fail("wallet content type");
209
+ const current = [];
210
+ const legacy = [];
211
+ const entities = new Map([
212
+ ["amp", "&"],
213
+ ["apos", "'"],
214
+ ["gt", ">"],
215
+ ["lt", "<"],
216
+ ["nbsp", "\u00a0"],
217
+ ["quot", '"'],
218
+ ]);
219
+ const decode = (raw) =>
220
+ raw.replace(/&([^;]*);/g, (_, entity) => {
221
+ const named = entities.get(entity);
222
+ if (named !== undefined) return named;
223
+ const scalar = /^#x[0-9a-f]+$/i.test(entity)
224
+ ? parseInt(entity.slice(2), 16)
225
+ : /^#[0-9]+$/.test(entity)
226
+ ? Number(entity.slice(1))
227
+ : NaN;
228
+ if (!Number.isInteger(scalar) || scalar > 0x10ffff || (scalar >= 0xd800 && scalar <= 0xdfff))
229
+ return fail("wallet HTML entity");
230
+ return String.fromCodePoint(scalar);
231
+ });
232
+ for (const tag of _nullishCoalesce(billing.bodyText.match(/<div\b[^>]*>/gi), () => [])) {
233
+ const props = /\bdata-props\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+))/i.exec(tag);
234
+ if (!props) continue;
235
+ const payload = JSON.parse(
236
+ decode(
237
+ _nullishCoalesce(
238
+ _nullishCoalesce(props[1], () => props[2]),
239
+ () => props[3],
240
+ ),
241
+ ),
242
+ );
243
+ if (!payload || typeof payload !== "object" || Array.isArray(payload)) continue;
244
+ const entity = payload.entity;
245
+ if (entity && Object.prototype.hasOwnProperty.call(entity, "currentBalanceUsd")) {
246
+ if (entity.type !== "user") return fail("wallet entity type");
247
+ current.push(entity.currentBalanceUsd);
248
+ }
249
+ if (Object.prototype.hasOwnProperty.call(payload, "invoiceCreditsCents"))
250
+ legacy.push(payload.invoiceCreditsCents);
251
+ }
252
+ let candidate;
253
+ if (current.length) {
254
+ if (current.length !== 1) return fail("ambiguous current wallet");
255
+ candidate = number(current[0], "currentBalanceUsd");
256
+ } else {
257
+ if (legacy.length !== 1) return fail("missing or ambiguous legacy wallet");
258
+ const cents = number(legacy[0], "invoiceCreditsCents");
259
+ if (!Number.isSafeInteger(cents)) return fail("invoiceCreditsCents");
260
+ candidate = cents / 100;
261
+ }
262
+ // The billing page's display names are not ownership proof. Resolve the same cookie without a bearer.
263
+ const profile = parse((await web("/api/whoami-v2", "application/json")).bodyText);
264
+ if (userID(profile) === identity.userID) balance = candidate;
265
+ } catch (error) {
266
+ void error;
267
+ }
268
+ }
269
+ // usage-v2 reports a query interval; its cutoff is not a quota reset.
270
+ // HF's billing UI deducts includedNanoUsd from usedNanoUsd to calculate the charge.
271
+ const rows = [{ label: "Billable usage", value: ctx.format.usd(billable) }];
272
+ if (included > 0) {
273
+ rows.push({ label: "Gross inference usage", value: ctx.format.usd(gross) });
274
+ rows.push({ label: "Included inference amount", value: ctx.format.usd(included) });
275
+ }
276
+ if (limit > 0) rows.push({ label: "Spending limit", value: ctx.format.usd(limit) });
277
+ if (requests !== undefined) rows.push({ label: "Requests", value: String(requests) });
278
+ const details = [{ title: "Inference Providers", rows }];
279
+ if (gpuRows.length) details.push({ title: "ZeroGPU", rows: gpuRows });
280
+ if (balance !== undefined)
281
+ details.push({ title: "Credits", rows: [{ label: "Prepaid balance", value: ctx.format.usd(balance) }] });
282
+ return {
283
+ secondary,
284
+ cost: { used: billable, balance, limit: limit > 0 ? limit : undefined, currency: "USD", period: "This month" },
285
+ details,
286
+ identity:
287
+ identity && (identity.username || identity.email || identity.plan)
288
+ ? { email: identity.email, accountID: identity.username, loginMethod: identity.plan }
289
+ : undefined,
290
+ dataConfidence: "exact",
291
+ };
292
+ },
293
+ });
@@ -0,0 +1,25 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "id": "huggingface",
4
+ "name": "Hugging Face",
5
+ "version": "0.1.0",
6
+ "entry": "plugin.js",
7
+ "enabledByDefault": false,
8
+ "supportedModes": [
9
+ "api"
10
+ ],
11
+ "autoMode": "api",
12
+ "usageDashboardUrl": "https://huggingface.co/settings/billing",
13
+ "webUrl": "https://huggingface.co",
14
+ "envVars": [
15
+ "HF_TOKEN",
16
+ "HUGGINGFACE_COOKIE"
17
+ ],
18
+ "upstream": {
19
+ "repository": "https://github.com/steipete/CodexBar",
20
+ "revision": "78ba5a1e65e6859da59a21b799df95ab91bc0b89",
21
+ "path": "Sources/CodexBarCore/Resources/Plugins/huggingface.js",
22
+ "sha256": "78cb1bb09535c71f7cb9d1a6336efb4ead44b36a1d4716602c1f7a1e35821291",
23
+ "license": "MIT"
24
+ }
25
+ }
@@ -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,131 @@
1
+ // Generated by tools/vendor-codexbar-providers.cjs; see LICENSE.
2
+ globalThis.__usagestat_bundled_options = {"labels":["Balance","Balance","Additional"],"defaults":{},"autoMode":"api"};
3
+ function _optionalChain(ops) {
4
+ let lastAccessLHS = undefined;
5
+ let value = ops[0];
6
+ let i = 1;
7
+ while (i < ops.length) {
8
+ const op = ops[i];
9
+ const fn = ops[i + 1];
10
+ i += 2;
11
+ if ((op === "optionalAccess" || op === "optionalCall") && value == null) {
12
+ return undefined;
13
+ }
14
+ if (op === "access" || op === "optionalAccess") {
15
+ lastAccessLHS = value;
16
+ value = fn(value);
17
+ } else if (op === "call" || op === "optionalCall") {
18
+ value = fn((...args) => value.call(lastAccessLHS, ...args));
19
+ lastAccessLHS = undefined;
20
+ }
21
+ }
22
+ return value;
23
+ }
24
+ defineProvider({
25
+ id: "hyper",
26
+ name: "Charm Hyper",
27
+ endpoints: ["https://hyper.charm.land"],
28
+ capabilities: ["browser-cookies", "http-status"],
29
+ cookieDomains: ["hyper.charm.land"],
30
+ settings: [
31
+ { key: "HYPER_API_KEY", title: "API key", type: "secure" },
32
+ { key: "SOURCE_MODE", title: "Source", type: "plain" },
33
+ ],
34
+ async fetchUsage(ctx) {
35
+ const domain = "hyper.charm.land";
36
+ const key = ctx.settings.getSecret("HYPER_API_KEY");
37
+ const webOnly = ctx.settings.get("SOURCE_MODE") === "web";
38
+ const missing = () => {
39
+ throw ctx.fail.missingCredential("Sign in to hyper.charm.land or configure a Charm Hyper API key.");
40
+ };
41
+ const request = (headers, timeoutSeconds = 10) =>
42
+ ctx.http.get(`https://${domain}/v1/credits`, {
43
+ headers,
44
+ timeoutSeconds,
45
+ });
46
+ let response;
47
+ let session = false;
48
+ if (ctx.browser.availability(domain) !== "off") {
49
+ try {
50
+ const cookie = await ctx.browser.cookieHeader(domain);
51
+ session = true;
52
+ response = await request({ Cookie: cookie }, 5);
53
+ } catch (error) {
54
+ if (error.transportClass === "cancelled") throw error;
55
+ if (webOnly || !key) {
56
+ if (session) throw ctx.fail.networkFailure("Charm Hyper session request failed.");
57
+ return missing();
58
+ }
59
+ }
60
+ if (
61
+ response &&
62
+ (response.status === 401 ||
63
+ response.status === 403 ||
64
+ (response.status >= 300 && response.status < 400) ||
65
+ (response.status === 200 &&
66
+ _optionalChain([
67
+ response,
68
+ "access",
69
+ (_) => _.headers,
70
+ "access",
71
+ (_2) => _2["content-type"],
72
+ "optionalAccess",
73
+ (_3) => _3.toLowerCase,
74
+ "call",
75
+ (_4) => _4(),
76
+ "access",
77
+ (_5) => _5.includes,
78
+ "call",
79
+ (_6) => _6("text/html"),
80
+ ])))
81
+ ) {
82
+ ctx.browser.rejectCookie(domain);
83
+ if (webOnly || !key) {
84
+ throw ctx.fail.authenticationExpired(
85
+ "Charm Hyper session expired. Sign in again or paste a fresh Cookie header.",
86
+ );
87
+ }
88
+ response = undefined;
89
+ }
90
+ }
91
+ if (!response) {
92
+ if (webOnly || !key) return missing();
93
+ response = await request({ Authorization: `Bearer ${key}` });
94
+ session = false;
95
+ }
96
+ if (response.status === 401) throw ctx.fail.authenticationExpired("Charm Hyper API key rejected (HTTP 401).");
97
+ if (response.status === 403)
98
+ throw ctx.fail.permissionDenied("Charm Hyper API key cannot access credits (HTTP 403).");
99
+ if (response.status === 429) throw ctx.fail.rateLimited("Charm Hyper credits requests are rate limited.");
100
+ if (response.status >= 500) throw ctx.fail.providerUnavailable(`Charm Hyper API error: HTTP ${response.status}`);
101
+ if (response.status !== 200) throw ctx.fail.apiFailure(`Charm Hyper API error: HTTP ${response.status}`);
102
+
103
+ let payload;
104
+ try {
105
+ payload = JSON.parse(response.bodyText);
106
+ } catch (error) {
107
+ void error;
108
+ throw ctx.fail.parseFailure("Charm Hyper credits response is not valid JSON.");
109
+ }
110
+ const balance = _optionalChain([payload, "optionalAccess", (_7) => _7.balance]);
111
+ if (typeof balance !== "number" || !Number.isFinite(balance) || balance < 0) {
112
+ throw ctx.fail.parseFailure("Charm Hyper balance must be a non-negative number.");
113
+ }
114
+ return {
115
+ details: [
116
+ {
117
+ title: "Hypercredits",
118
+ rows: [
119
+ {
120
+ label: "Balance",
121
+ value: `${ctx.format.number(balance, { maximumFractionDigits: 2 })} HC`,
122
+ usageValue: balance,
123
+ },
124
+ ],
125
+ },
126
+ ],
127
+ identity: { loginMethod: session ? "Browser session" : "API key" },
128
+ dataConfidence: "exact",
129
+ };
130
+ },
131
+ });
@@ -0,0 +1,26 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "id": "hyper",
4
+ "name": "Charm Hyper",
5
+ "version": "0.1.0",
6
+ "entry": "plugin.js",
7
+ "enabledByDefault": false,
8
+ "supportedModes": [
9
+ "api",
10
+ "web"
11
+ ],
12
+ "autoMode": "api",
13
+ "usageDashboardUrl": "https://hyper.charm.land",
14
+ "webUrl": "https://hyper.charm.land",
15
+ "envVars": [
16
+ "HYPER_API_KEY",
17
+ "HYPER_COOKIE"
18
+ ],
19
+ "upstream": {
20
+ "repository": "https://github.com/steipete/CodexBar",
21
+ "revision": "78ba5a1e65e6859da59a21b799df95ab91bc0b89",
22
+ "path": "Sources/CodexBarCore/Resources/Plugins/hyper.js",
23
+ "sha256": "893e1a9a91e7af57522bcc39791d77d6fe3b8ae0d61384aee1768f5f419636cd",
24
+ "license": "MIT"
25
+ }
26
+ }
@@ -0,0 +1,23 @@
1
+ <svg id="Bob" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
2
+ <defs>
3
+ <linearGradient id="helmetShade" x1="0" y1="0" x2="1" y2="0">
4
+ <stop offset=".134" stop-opacity="0"/>
5
+ <stop offset=".873"/>
6
+ </linearGradient>
7
+ <linearGradient id="bobGradient" x1="0" y1="32" x2="32" y2="0" gradientUnits="userSpaceOnUse">
8
+ <stop offset=".1" stop-color="#a16efb"/>
9
+ <stop offset=".9" stop-color="#0e61fa"/>
10
+ </linearGradient>
11
+ <mask id="helmetMask" x="0" y="0" width="32" height="32" maskUnits="userSpaceOnUse">
12
+ <path d="M29.718 15.25a13.67 13.67 0 0 0-9.991-12.476A1.747 1.747 0 0 0 18 1.25h-4c-.887 0-1.615.667-1.727 1.524A13.67 13.67 0 0 0 2.282 15.25H0v1.5h32v-1.5h-2.282zM12.25 4.337V13h1.5V3a.25.25 0 0 1 .25-.25h4a.25.25 0 0 1 .25.25v10h1.5V4.337a12.183 12.183 0 0 1 8.468 10.913H3.782A12.183 12.183 0 0 1 12.25 4.337z" fill="#fff"/>
13
+ <path d="M21 7v7H11V7h10z" fill="url(#helmetShade)"/>
14
+ </mask>
15
+ </defs>
16
+ <g mask="url(#helmetMask)">
17
+ <path fill="url(#bobGradient)" d="M0 0h32v32H0z"/>
18
+ </g>
19
+ <path d="M24 30.75H8a4.756 4.756 0 0 1-4.69-4H3c-.965 0-1.75-.785-1.75-1.75v-6h1.5v6c0 .138.112.25.25.25h1.75V26A3.254 3.254 0 0 0 8 29.25h16A3.254 3.254 0 0 0 27.25 26v-.75H29a.25.25 0 0 0 .25-.25v-6h1.5v6c0 .965-.785 1.75-1.75 1.75h-.31a4.756 4.756 0 0 1-4.69 4z" fill="#001d6c"/>
20
+ <circle cx="22" cy="21" r="2" fill="#001d6c"/>
21
+ <circle cx="10" cy="21" r="2" fill="#001d6c"/>
22
+ <path d="M16 27.75a5.695 5.695 0 0 1-3.451-1.15.75.75 0 0 1 .903-1.199c1.476 1.111 3.617 1.111 5.099 0a.75.75 0 1 1 .901 1.199 5.696 5.696 0 0 1-3.45 1.15z" fill="#001d6c"/>
23
+ </svg>
@@ -0,0 +1,61 @@
1
+ (function () {
2
+ function clean(value) {
3
+ return typeof value === "string" && value.trim() ? value.trim() : null
4
+ }
5
+ function number(value) {
6
+ if (typeof value !== "number" && typeof value !== "string") return null
7
+ if (typeof value === "string" && !value.trim()) return null
8
+ const n = Number(value)
9
+ return Number.isFinite(n) && n >= 0 ? n : null
10
+ }
11
+ function regionalBase(domain) {
12
+ if (!clean(domain)) return "https://api.us-east.bob.ibm.com"
13
+ const host = domain.trim().toLowerCase()
14
+ if (!/^(?:[a-z0-9-]+\.)*bob\.ibm\.com$/.test(host)) throw "IBM Bob returned an untrusted regional host."
15
+ return "https://" + (host.startsWith("api.") ? host : "api." + host)
16
+ }
17
+ function request(ctx, url, headers) {
18
+ const result = ctx.util.requestJson({ method: "GET", url, headers, timeoutMs: 5000 })
19
+ if (ctx.util.isAuthStatus(result.resp.status)) throw "IBM Bob rejected the API key."
20
+ if (result.resp.status < 200 || result.resp.status >= 300) throw "IBM Bob API returned HTTP " + result.resp.status + "."
21
+ if (!result.json || typeof result.json !== "object") throw "Invalid IBM Bob response."
22
+ return result.json
23
+ }
24
+ function probe(ctx) {
25
+ const key = clean(ctx.provider && ctx.provider.apiKey) || clean(ctx.host.env.get("BOBSHELL_API_KEY"))
26
+ if (!key) throw "Set BOBSHELL_API_KEY or the IBM Bob provider API key."
27
+ const jwt = key.split(".").length === 3 && ctx.jwt.decodePayload(key)
28
+ const headers = { Authorization: (jwt ? "Bearer " : "Apikey ") + key, Accept: "application/json", "User-Agent": "UsageStat" }
29
+ const profile = request(ctx, "https://api.us-east.bob.ibm.com/admin/v1/profile", headers)
30
+ if (!Array.isArray(profile.instances)) throw "IBM Bob profile is missing subscriptions."
31
+ const lines = []
32
+ const plans = []
33
+ let count = 0
34
+ for (const instance of profile.instances) {
35
+ if (!instance || !clean(instance.user_id) || !Array.isArray(instance.teams)) continue
36
+ const base = regionalBase(instance.region_domain)
37
+ for (const team of instance.teams) {
38
+ if (!team || !clean(team.id)) continue
39
+ if (ctx.provider && ctx.provider.workspaceId && ctx.provider.workspaceId !== team.id) continue
40
+ if (++count > 20) throw "IBM Bob returned more than 20 teams; select a workspace."
41
+ const budget = request(ctx, base + "/admin/v1/teams/" + encodeURIComponent(team.id) + "/users/" + encodeURIComponent(instance.user_id),
42
+ Object.assign({}, headers, { "x-instance-id": instance.instance_id, "x-team-id": team.id }))
43
+ const used = number(budget.usage)
44
+ const limit = number(budget.budget_limit) === null ? number(team.budget_limit) : number(budget.budget_limit)
45
+ if (used === null) throw "IBM Bob did not return valid Bobcoin usage."
46
+ const label = clean(instance.instance_name) || clean(instance.name) || instance.instance_id
47
+ const teamName = clean(team.name) || team.id
48
+ const reset = typeof instance.refresh_at === "number" ? instance.refresh_at * 1000 : instance.refresh_at
49
+ if (limit !== null && limit > 0) {
50
+ lines.push(ctx.line.progress({ label: label + " / " + teamName, used, limit,
51
+ format: { kind: "count", suffix: "Bobcoins" }, resetsAt: ctx.util.toIso(reset),
52
+ periodDurationMs: 30 * 24 * 60 * 60 * 1000 }))
53
+ } else lines.push(ctx.line.text({ label: teamName, value: used + " Bobcoins used" }))
54
+ if (clean(instance.plan_name) && !plans.includes(instance.plan_name)) plans.push(instance.plan_name)
55
+ }
56
+ }
57
+ if (!lines.length) throw "No IBM Bob team subscription found."
58
+ return { displayName: "IBM Bob", source: "api", plan: plans.join(", ") || undefined, lines }
59
+ }
60
+ globalThis.__openusage_plugin = { id: "ibmbob", probe }
61
+ })()
@@ -0,0 +1,22 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "id": "ibmbob",
4
+ "name": "IBM Bob",
5
+ "version": "0.1.0",
6
+ "entry": "plugin.js",
7
+ "enabledByDefault": false,
8
+ "envVars": [
9
+ "BOBSHELL_API_KEY"
10
+ ],
11
+ "supportedModes": [
12
+ "api"
13
+ ],
14
+ "autoMode": "api",
15
+ "usageDashboardUrl": "https://bob.ibm.com",
16
+ "links": [
17
+ {
18
+ "label": "Dashboard",
19
+ "url": "https://bob.ibm.com"
20
+ }
21
+ ]
22
+ }
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1 @@
1
+ <svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Kilo Code</title><path d="M0 0v24h24V0H0zm22.222 22.222H1.778V1.778h20.444v20.444zm-7.555-4.964h2.222v1.778h-2.794L12.89 17.83v-2.794h1.778v2.222zm4 0h-1.778v-2.222h-2.222v-1.778h2.793l1.207 1.207v2.793zm-7.556-2.591H9.333v-1.778h1.778v1.778zm-5.778-1.778h1.778v4h4v1.778H6.54L5.333 17.46V12.89zm13.334-3.556v1.778h-5.778V9.333h1.987V7.111h-1.987V5.333h2.558l1.206 1.207v2.793h2.014zm-11.556-2h2.222l1.778 1.778v2H9.333v-2H7.111v2H5.333V5.333h1.778v2zm4 0H9.333v-2h1.778v2z"></path></svg>
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes