@hashimkarim/usagestat-linux-x64-gnu 2.0.0-alpha.1

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 (225) hide show
  1. package/LICENSE +57744 -0
  2. package/native-manifest.json +1414 -0
  3. package/package.json +254 -0
  4. package/plugins/abacus-ai/icon.svg +18 -0
  5. package/plugins/abacus-ai/plugin.js +121 -0
  6. package/plugins/abacus-ai/plugin.json +17 -0
  7. package/plugins/alibaba/icon-color.svg +1 -0
  8. package/plugins/alibaba/icon.svg +1 -0
  9. package/plugins/alibaba/plugin.js +322 -0
  10. package/plugins/alibaba/plugin.json +20 -0
  11. package/plugins/alibaba-token-plan/icon-color.svg +1 -0
  12. package/plugins/alibaba-token-plan/icon.svg +1 -0
  13. package/plugins/alibaba-token-plan/plugin.js +544 -0
  14. package/plugins/alibaba-token-plan/plugin.json +19 -0
  15. package/plugins/amp/icon-color.svg +1 -0
  16. package/plugins/amp/icon-conflict.svg +6 -0
  17. package/plugins/amp/icon.svg +1 -0
  18. package/plugins/amp/plugin.js +175 -0
  19. package/plugins/amp/plugin.json +16 -0
  20. package/plugins/antigravity/icon-color.svg +1 -0
  21. package/plugins/antigravity/icon-conflict.svg +3 -0
  22. package/plugins/antigravity/icon.svg +1 -0
  23. package/plugins/antigravity/plugin.js +739 -0
  24. package/plugins/antigravity/plugin.json +31 -0
  25. package/plugins/antigravity-cli/icon.svg +3 -0
  26. package/plugins/antigravity-cli/plugin.js +570 -0
  27. package/plugins/antigravity-cli/plugin.json +16 -0
  28. package/plugins/antigravity-ide/icon.svg +3 -0
  29. package/plugins/antigravity-ide/plugin.js +257 -0
  30. package/plugins/antigravity-ide/plugin.json +29 -0
  31. package/plugins/augment/icon.svg +14 -0
  32. package/plugins/augment/plugin.js +59 -0
  33. package/plugins/augment/plugin.json +18 -0
  34. package/plugins/aws-bedrock/icon-color.svg +1 -0
  35. package/plugins/aws-bedrock/icon.svg +1 -0
  36. package/plugins/aws-bedrock/plugin.js +206 -0
  37. package/plugins/aws-bedrock/plugin.json +18 -0
  38. package/plugins/azure-openai/icon-color.svg +1 -0
  39. package/plugins/azure-openai/icon.svg +1 -0
  40. package/plugins/azure-openai/plugin.js +145 -0
  41. package/plugins/azure-openai/plugin.json +17 -0
  42. package/plugins/chutes/icon.svg +7 -0
  43. package/plugins/chutes/plugin.js +236 -0
  44. package/plugins/chutes/plugin.json +19 -0
  45. package/plugins/claude/icon-color.svg +1 -0
  46. package/plugins/claude/icon.svg +1 -0
  47. package/plugins/claude/plugin.js +1723 -0
  48. package/plugins/claude/plugin.json +30 -0
  49. package/plugins/codebuff/icon.svg +92 -0
  50. package/plugins/codebuff/plugin.js +113 -0
  51. package/plugins/codebuff/plugin.json +17 -0
  52. package/plugins/codex/icon-color.svg +5 -0
  53. package/plugins/codex/icon.svg +1 -0
  54. package/plugins/codex/plugin.js +1009 -0
  55. package/plugins/codex/plugin.json +82 -0
  56. package/plugins/command-code/icon.svg +3 -0
  57. package/plugins/command-code/plugin.js +184 -0
  58. package/plugins/command-code/plugin.json +20 -0
  59. package/plugins/copilot/icon-color.svg +1 -0
  60. package/plugins/copilot/icon.svg +1 -0
  61. package/plugins/copilot/plugin.js +684 -0
  62. package/plugins/copilot/plugin.json +21 -0
  63. package/plugins/crof/icon.svg +3 -0
  64. package/plugins/crof/plugin.js +53 -0
  65. package/plugins/crof/plugin.json +17 -0
  66. package/plugins/crofai/icon.svg +16 -0
  67. package/plugins/crofai/plugin.js +81 -0
  68. package/plugins/crofai/plugin.json +18 -0
  69. package/plugins/cursor/icon-conflict.svg +3 -0
  70. package/plugins/cursor/icon.svg +1 -0
  71. package/plugins/cursor/plugin.js +1379 -0
  72. package/plugins/cursor/plugin.json +23 -0
  73. package/plugins/cursor-nightly/icon.png +0 -0
  74. package/plugins/cursor-nightly/plugin.js +1379 -0
  75. package/plugins/cursor-nightly/plugin.json +23 -0
  76. package/plugins/deepgram/icon.svg +1 -0
  77. package/plugins/deepgram/plugin.js +20 -0
  78. package/plugins/deepgram/plugin.json +17 -0
  79. package/plugins/deepseek/icon-color.svg +1 -0
  80. package/plugins/deepseek/icon.svg +1 -0
  81. package/plugins/deepseek/plugin.js +71 -0
  82. package/plugins/deepseek/plugin.json +17 -0
  83. package/plugins/devin/icon.svg +5 -0
  84. package/plugins/devin/plugin.js +341 -0
  85. package/plugins/devin/plugin.json +16 -0
  86. package/plugins/doubao/icon-color.svg +1 -0
  87. package/plugins/doubao/icon.svg +1 -0
  88. package/plugins/doubao/plugin.js +92 -0
  89. package/plugins/doubao/plugin.json +17 -0
  90. package/plugins/droid/icon.svg +1 -0
  91. package/plugins/droid/plugin.json +20 -0
  92. package/plugins/elevenlabs/icon.svg +4 -0
  93. package/plugins/elevenlabs/plugin.js +48 -0
  94. package/plugins/elevenlabs/plugin.json +18 -0
  95. package/plugins/factory/icon-conflict.svg +1 -0
  96. package/plugins/factory/icon.svg +1 -0
  97. package/plugins/factory/plugin.js +487 -0
  98. package/plugins/factory/plugin.json +15 -0
  99. package/plugins/fireworks-ai/icon.svg +6 -0
  100. package/plugins/fireworks-ai/plugin.js +370 -0
  101. package/plugins/fireworks-ai/plugin.json +19 -0
  102. package/plugins/gemini/icon-color.svg +1 -0
  103. package/plugins/gemini/icon.svg +1 -0
  104. package/plugins/gemini/plugin.js +460 -0
  105. package/plugins/gemini/plugin.json +16 -0
  106. package/plugins/grok/icon.svg +1 -0
  107. package/plugins/grok/plugin.js +297 -0
  108. package/plugins/grok/plugin.json +19 -0
  109. package/plugins/groqcloud/icon.svg +1 -0
  110. package/plugins/groqcloud/plugin.js +117 -0
  111. package/plugins/groqcloud/plugin.json +19 -0
  112. package/plugins/jetbrains-ai-assistant/icon-color.svg +14 -0
  113. package/plugins/jetbrains-ai-assistant/icon-conflict.svg +3 -0
  114. package/plugins/jetbrains-ai-assistant/icon.svg +14 -0
  115. package/plugins/jetbrains-ai-assistant/plugin.js +313 -0
  116. package/plugins/jetbrains-ai-assistant/plugin.json +16 -0
  117. package/plugins/kilo/icon.svg +1 -0
  118. package/plugins/kilo/plugin.js +111 -0
  119. package/plugins/kilo/plugin.json +19 -0
  120. package/plugins/kimi/icon-color.svg +1 -0
  121. package/plugins/kimi/icon-conflict.svg +3 -0
  122. package/plugins/kimi/icon.svg +1 -0
  123. package/plugins/kimi/plugin.js +358 -0
  124. package/plugins/kimi/plugin.json +15 -0
  125. package/plugins/kimi-k2/icon-color.svg +1 -0
  126. package/plugins/kimi-k2/icon.svg +1 -0
  127. package/plugins/kimi-k2/plugin.js +58 -0
  128. package/plugins/kimi-k2/plugin.json +18 -0
  129. package/plugins/kiro/icon-color.svg +5 -0
  130. package/plugins/kiro/icon-conflict.svg +1 -0
  131. package/plugins/kiro/icon.svg +4 -0
  132. package/plugins/kiro/plugin.js +390 -0
  133. package/plugins/kiro/plugin.json +16 -0
  134. package/plugins/litellm/icon.svg +16 -0
  135. package/plugins/litellm/plugin.js +199 -0
  136. package/plugins/litellm/plugin.json +16 -0
  137. package/plugins/llm-proxy/icon.svg +1 -0
  138. package/plugins/llm-proxy/plugin.js +40 -0
  139. package/plugins/llm-proxy/plugin.json +17 -0
  140. package/plugins/manus/icon.svg +6 -0
  141. package/plugins/manus/plugin.js +50 -0
  142. package/plugins/manus/plugin.json +17 -0
  143. package/plugins/mimo/icon.svg +1 -0
  144. package/plugins/mimo/plugin.js +177 -0
  145. package/plugins/mimo/plugin.json +19 -0
  146. package/plugins/minimax/icon-color.svg +1 -0
  147. package/plugins/minimax/icon-conflict.svg +4 -0
  148. package/plugins/minimax/icon.svg +1 -0
  149. package/plugins/minimax/plugin.js +453 -0
  150. package/plugins/minimax/plugin.json +14 -0
  151. package/plugins/mistral/icon-color.svg +1 -0
  152. package/plugins/mistral/icon.svg +1 -0
  153. package/plugins/mistral/plugin.js +152 -0
  154. package/plugins/mistral/plugin.json +18 -0
  155. package/plugins/moonshot/icon.svg +1 -0
  156. package/plugins/moonshot/plugin.js +43 -0
  157. package/plugins/moonshot/plugin.json +16 -0
  158. package/plugins/nanogpt/icon-color.svg +17 -0
  159. package/plugins/nanogpt/icon.svg +10 -0
  160. package/plugins/nanogpt/plugin.js +80 -0
  161. package/plugins/nanogpt/plugin.json +17 -0
  162. package/plugins/neuralwatt/icon.svg +3 -0
  163. package/plugins/neuralwatt/plugin.js +152 -0
  164. package/plugins/neuralwatt/plugin.json +17 -0
  165. package/plugins/ollama/icon.svg +1 -0
  166. package/plugins/ollama/plugin.js +92 -0
  167. package/plugins/ollama/plugin.json +20 -0
  168. package/plugins/openai-api/icon.svg +1 -0
  169. package/plugins/openai-api/plugin.js +533 -0
  170. package/plugins/openai-api/plugin.json +26 -0
  171. package/plugins/opencode/icon.svg +1 -0
  172. package/plugins/opencode/plugin.js +342 -0
  173. package/plugins/opencode/plugin.json +19 -0
  174. package/plugins/opencode-go/icon-conflict.svg +1 -0
  175. package/plugins/opencode-go/icon.svg +1 -0
  176. package/plugins/opencode-go/plugin.js +617 -0
  177. package/plugins/opencode-go/plugin.json +50 -0
  178. package/plugins/openrouter/icon.svg +1 -0
  179. package/plugins/openrouter/plugin.js +156 -0
  180. package/plugins/openrouter/plugin.json +8 -0
  181. package/plugins/perplexity/icon-color.svg +1 -0
  182. package/plugins/perplexity/icon-conflict.svg +1 -0
  183. package/plugins/perplexity/icon.svg +1 -0
  184. package/plugins/perplexity/plugin.js +425 -0
  185. package/plugins/perplexity/plugin.json +19 -0
  186. package/plugins/poe/icon.svg +1 -0
  187. package/plugins/poe/plugin.js +190 -0
  188. package/plugins/poe/plugin.json +19 -0
  189. package/plugins/stepfun/icon-color.svg +1 -0
  190. package/plugins/stepfun/icon.svg +1 -0
  191. package/plugins/stepfun/plugin.js +155 -0
  192. package/plugins/stepfun/plugin.json +18 -0
  193. package/plugins/synthetic/icon-conflict.svg +12 -0
  194. package/plugins/synthetic/icon.svg +14 -0
  195. package/plugins/synthetic/plugin.js +331 -0
  196. package/plugins/synthetic/plugin.json +23 -0
  197. package/plugins/t3chat/icon-color.svg +28 -0
  198. package/plugins/t3chat/icon.svg +4 -0
  199. package/plugins/t3chat/plugin.js +243 -0
  200. package/plugins/t3chat/plugin.json +20 -0
  201. package/plugins/venice/icon-color.svg +1 -0
  202. package/plugins/venice/icon.svg +1 -0
  203. package/plugins/venice/plugin.js +69 -0
  204. package/plugins/venice/plugin.json +16 -0
  205. package/plugins/vertex-ai/icon-color.svg +1 -0
  206. package/plugins/vertex-ai/icon.svg +1 -0
  207. package/plugins/vertex-ai/plugin.js +172 -0
  208. package/plugins/vertex-ai/plugin.json +18 -0
  209. package/plugins/warp/icon-color.svg +10 -0
  210. package/plugins/warp/icon.svg +6 -0
  211. package/plugins/warp/plugin.js +108 -0
  212. package/plugins/warp/plugin.json +18 -0
  213. package/plugins/windsurf/icon-conflict.svg +3 -0
  214. package/plugins/windsurf/icon.svg +1 -0
  215. package/plugins/windsurf/plugin.js +208 -0
  216. package/plugins/windsurf/plugin.json +16 -0
  217. package/plugins/zai/icon-conflict.svg +5 -0
  218. package/plugins/zai/icon.svg +1 -0
  219. package/plugins/zai/plugin.js +188 -0
  220. package/plugins/zai/plugin.json +16 -0
  221. package/plugins/zed/icon.svg +4 -0
  222. package/plugins/zed/plugin.js +270 -0
  223. package/plugins/zed/plugin.json +19 -0
  224. package/usagestat +0 -0
  225. package/usagestatd +0 -0
@@ -0,0 +1,69 @@
1
+ (function () {
2
+ var API_URL = "https://api.venice.ai/api/v1/billing/balance";
3
+
4
+ function loadApiKey(ctx) {
5
+ var v = ctx.host.env.get("VENICE_API_KEY");
6
+ if (typeof v === "string" && v.trim()) return v.trim();
7
+ return null;
8
+ }
9
+
10
+ function probe(ctx) {
11
+ var apiKey = loadApiKey(ctx);
12
+ if (!apiKey) {
13
+ throw "Venice API key not found. Set VENICE_API_KEY.";
14
+ }
15
+
16
+ var result = ctx.util.requestJson({
17
+ method: "GET",
18
+ url: API_URL,
19
+ headers: { Authorization: "Bearer " + apiKey, Accept: "application/json" },
20
+ timeoutMs: 15000,
21
+ });
22
+
23
+ if (ctx.util.isAuthStatus(result.resp.status)) {
24
+ throw "API key invalid or expired.";
25
+ }
26
+ if (result.resp.status < 200 || result.resp.status >= 300) {
27
+ throw "Venice API error (HTTP " + result.resp.status + ").";
28
+ }
29
+ if (!result.json) throw "Could not parse Venice balance response.";
30
+
31
+ var json = result.json;
32
+ var canConsume = json.canConsume !== false;
33
+ var currency = (json.consumptionCurrency || "").toUpperCase();
34
+ var balances = json.balances || {};
35
+ var diem = typeof balances.diem === "number" ? balances.diem : null;
36
+ var usd = typeof balances.usd === "number" ? balances.usd : null;
37
+ var epochAlloc = typeof json.diemEpochAllocation === "number" ? json.diemEpochAllocation : null;
38
+
39
+ var lines = [];
40
+
41
+ if (!canConsume) {
42
+ lines.push(ctx.line.badge({ label: "Balance", text: "Balance unavailable for API calls", color: "#ef4444" }));
43
+ return { lines: lines };
44
+ }
45
+
46
+ if (currency === "USD" && usd !== null && usd > 0) {
47
+ lines.push(ctx.line.text({ label: "Balance", value: "$" + usd.toFixed(2) + " USD" }));
48
+ } else if (currency !== "USD" && diem !== null && epochAlloc !== null && epochAlloc > 0) {
49
+ var usedPct = Math.max(0, Math.min(100, (epochAlloc - diem) / epochAlloc * 100));
50
+ lines.push(ctx.line.progress({
51
+ label: "DIEM",
52
+ used: usedPct,
53
+ limit: 100,
54
+ format: { kind: "percent" },
55
+ }));
56
+ lines.push(ctx.line.text({ label: "Allocation", value: "DIEM " + diem.toFixed(2) + " / " + epochAlloc.toFixed(2) }));
57
+ } else if (diem !== null && diem > 0) {
58
+ lines.push(ctx.line.text({ label: "Balance", value: "DIEM " + diem.toFixed(2) }));
59
+ } else if (usd !== null && usd > 0) {
60
+ lines.push(ctx.line.text({ label: "Balance", value: "$" + usd.toFixed(2) + " USD" }));
61
+ } else {
62
+ lines.push(ctx.line.badge({ label: "Balance", text: "No Venice API balance", color: "#a3a3a3" }));
63
+ }
64
+
65
+ return { lines: lines };
66
+ }
67
+
68
+ globalThis.__openusage_plugin = { id: "venice", probe: probe };
69
+ })();
@@ -0,0 +1,16 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "id": "venice",
4
+ "name": "Venice",
5
+ "version": "0.0.1",
6
+ "entry": "plugin.js",
7
+ "brandColor": "#6B48FF",
8
+ "links": [
9
+ { "label": "API Keys", "url": "https://venice.ai/settings/api" }
10
+ ],
11
+ "supportedModes": ["api"],
12
+ "autoMode": "api",
13
+ "lines": [
14
+ { "type": "text", "label": "Balance", "scope": "overview" }
15
+ ]
16
+ }
@@ -0,0 +1 @@
1
+ <svg height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>VertexAI</title><path d="M11.995 20.216a1.892 1.892 0 100 3.785 1.892 1.892 0 000-3.785zm0 2.806a.927.927 0 11.927-.914.914.914 0 01-.927.914z" fill="#4285F4"></path><path clip-rule="evenodd" d="M21.687 14.144c.237.038.452.16.605.344a.978.978 0 01-.18 1.3l-8.24 6.082a1.892 1.892 0 00-1.147-1.508l8.28-6.08a.991.991 0 01.682-.138z" fill="#669DF6" fill-rule="evenodd"></path><path clip-rule="evenodd" d="M10.122 21.842l-8.217-6.066a.952.952 0 01-.206-1.287.978.978 0 011.287-.206l8.28 6.08a1.893 1.893 0 00-1.144 1.479z" fill="#AECBFA" fill-rule="evenodd"></path><path d="M4.273 4.475a.978.978 0 01-.965-.965V1.09a.978.978 0 111.943 0v2.42a.978.978 0 01-.978.965zM4.247 13.034a.978.978 0 100-1.956.978.978 0 000 1.956zM4.247 10.19a.978.978 0 100-1.956.978.978 0 000 1.956zM4.247 7.332a.978.978 0 100-1.956.978.978 0 000 1.956z" fill="#AECBFA"></path><path d="M19.718 7.307a.978.978 0 01-.965-.979v-2.42a.965.965 0 011.93 0v2.42a.964.964 0 01-.965.979zM19.743 13.047a.978.978 0 100-1.956.978.978 0 000 1.956zM19.743 10.151a.978.978 0 100-1.956.978.978 0 000 1.956zM19.743 2.068a.978.978 0 100-1.956.978.978 0 000 1.956z" fill="#4285F4"></path><path d="M11.995 15.917a.978.978 0 01-.965-.965v-2.459a.978.978 0 011.943 0v2.433a.976.976 0 01-.978.991zM11.995 18.762a.978.978 0 100-1.956.978.978 0 000 1.956zM11.995 10.64a.978.978 0 100-1.956.978.978 0 000 1.956zM11.995 7.783a.978.978 0 100-1.956.978.978 0 000 1.956z" fill="#669DF6"></path><path d="M15.856 10.177a.978.978 0 01-.965-.965v-2.42a.977.977 0 011.702-.763.979.979 0 01.241.763v2.42a.978.978 0 01-.978.965zM15.869 4.913a.978.978 0 100-1.956.978.978 0 000 1.956zM15.869 15.853a.978.978 0 100-1.956.978.978 0 000 1.956zM15.869 12.996a.978.978 0 100-1.956.978.978 0 000 1.956z" fill="#4285F4"></path><path d="M8.121 15.853a.978.978 0 100-1.956.978.978 0 000 1.956zM8.121 7.783a.978.978 0 100-1.956.978.978 0 000 1.956zM8.121 4.913a.978.978 0 100-1.957.978.978 0 000 1.957zM8.134 12.996a.978.978 0 01-.978-.94V9.611a.965.965 0 011.93 0v2.445a.966.966 0 01-.952.94z" fill="#AECBFA"></path></svg>
@@ -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>VertexAI</title><path d="M11.995 20.216a1.892 1.892 0 100 3.785 1.892 1.892 0 000-3.785zm0 2.806a.927.927 0 11.927-.914.914.914 0 01-.927.914z"></path><path clip-rule="evenodd" d="M21.687 14.144c.237.038.452.16.605.344a.978.978 0 01-.18 1.3l-8.24 6.082a1.892 1.892 0 00-1.147-1.508l8.28-6.08a.991.991 0 01.682-.138z"></path><path clip-rule="evenodd" d="M10.122 21.842l-8.217-6.066a.952.952 0 01-.206-1.287.978.978 0 011.287-.206l8.28 6.08a1.893 1.893 0 00-1.144 1.479z"></path><path d="M4.273 4.475a.978.978 0 01-.965-.965V1.09a.978.978 0 111.943 0v2.42a.978.978 0 01-.978.965zM4.247 13.034a.978.978 0 100-1.956.978.978 0 000 1.956zM4.247 10.19a.978.978 0 100-1.956.978.978 0 000 1.956zM4.247 7.332a.978.978 0 100-1.956.978.978 0 000 1.956z"></path><path d="M19.718 7.307a.978.978 0 01-.965-.979v-2.42a.965.965 0 011.93 0v2.42a.964.964 0 01-.965.979zM19.743 13.047a.978.978 0 100-1.956.978.978 0 000 1.956zM19.743 10.151a.978.978 0 100-1.956.978.978 0 000 1.956zM19.743 2.068a.978.978 0 100-1.956.978.978 0 000 1.956z"></path><path d="M11.995 15.917a.978.978 0 01-.965-.965v-2.459a.978.978 0 011.943 0v2.433a.976.976 0 01-.978.991zM11.995 18.762a.978.978 0 100-1.956.978.978 0 000 1.956zM11.995 10.64a.978.978 0 100-1.956.978.978 0 000 1.956zM11.995 7.783a.978.978 0 100-1.956.978.978 0 000 1.956z"></path><path d="M15.856 10.177a.978.978 0 01-.965-.965v-2.42a.977.977 0 011.702-.763.979.979 0 01.241.763v2.42a.978.978 0 01-.978.965zM15.869 4.913a.978.978 0 100-1.956.978.978 0 000 1.956zM15.869 15.853a.978.978 0 100-1.956.978.978 0 000 1.956zM15.869 12.996a.978.978 0 100-1.956.978.978 0 000 1.956z"></path><path d="M8.121 15.853a.978.978 0 100-1.956.978.978 0 000 1.956zM8.121 7.783a.978.978 0 100-1.956.978.978 0 000 1.956zM8.121 4.913a.978.978 0 100-1.957.978.978 0 000 1.957zM8.134 12.996a.978.978 0 01-.978-.94V9.611a.965.965 0 011.93 0v2.445a.966.966 0 01-.952.94z"></path></svg>
@@ -0,0 +1,172 @@
1
+ (function () {
2
+ var TOKEN_URL = "https://oauth2.googleapis.com/token";
3
+ var RESOURCE_MANAGER_URL = "https://cloudresourcemanager.googleapis.com/v1/projects/";
4
+
5
+ function trim(value) {
6
+ return typeof value === "string" && value.trim() ? value.trim() : null;
7
+ }
8
+
9
+ function env(ctx, name) {
10
+ try {
11
+ return trim(ctx.host.env.get(name));
12
+ } catch (_) {
13
+ return null;
14
+ }
15
+ }
16
+
17
+ function setting(ctx, names) {
18
+ var settings = ctx.provider && ctx.provider.settings ? ctx.provider.settings : {};
19
+ for (var i = 0; i < names.length; i++) {
20
+ var value = trim(settings[names[i]]);
21
+ if (value) return value;
22
+ }
23
+ return null;
24
+ }
25
+
26
+ function readJson(ctx, path) {
27
+ if (!path || !ctx.host.fs.exists(path)) return null;
28
+ try {
29
+ return ctx.util.tryParseJson(ctx.host.fs.readText(path));
30
+ } catch (_) {
31
+ return null;
32
+ }
33
+ }
34
+
35
+ function adcPath(ctx) {
36
+ var explicit = env(ctx, "GOOGLE_APPLICATION_CREDENTIALS");
37
+ if (explicit) return explicit;
38
+ var configDir = env(ctx, "CLOUDSDK_CONFIG");
39
+ if (configDir) return configDir.replace(/\/+$/, "") + "/application_default_credentials.json";
40
+ return (ctx.host.fs.homeDir || "~") + "/.config/gcloud/application_default_credentials.json";
41
+ }
42
+
43
+ function gcloudPropertiesPath(ctx) {
44
+ var configDir = env(ctx, "CLOUDSDK_CONFIG");
45
+ if (configDir) return configDir.replace(/\/+$/, "") + "/properties";
46
+ return (ctx.host.fs.homeDir || "~") + "/.config/gcloud/properties";
47
+ }
48
+
49
+ function refreshAccessToken(ctx, creds) {
50
+ if (!creds || !trim(creds.refresh_token) || !trim(creds.client_id) || !trim(creds.client_secret)) return null;
51
+ var resp = ctx.util.request({
52
+ method: "POST",
53
+ url: TOKEN_URL,
54
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
55
+ bodyText:
56
+ "client_id=" + encodeURIComponent(creds.client_id) +
57
+ "&client_secret=" + encodeURIComponent(creds.client_secret) +
58
+ "&refresh_token=" + encodeURIComponent(creds.refresh_token) +
59
+ "&grant_type=refresh_token",
60
+ timeoutMs: 15000,
61
+ });
62
+ if (ctx.util.isAuthStatus(resp.status) || resp.status === 400) {
63
+ throw "Vertex AI credentials expired. Run `gcloud auth application-default login` again.";
64
+ }
65
+ if (resp.status < 200 || resp.status >= 300) {
66
+ ctx.host.log.warn("Vertex AI token refresh returned HTTP " + resp.status);
67
+ return null;
68
+ }
69
+ var body = ctx.util.tryParseJson(resp.bodyText);
70
+ return body && trim(body.access_token);
71
+ }
72
+
73
+ function tokenFromGcloud(ctx, args) {
74
+ try {
75
+ if (!ctx.host.command || typeof ctx.host.command.run !== "function") return null;
76
+ var result = ctx.host.command.run({ program: "gcloud", args: args, timeoutMs: 15000 });
77
+ if (result && result.status === 0 && typeof result.stdout === "string") {
78
+ return trim(result.stdout);
79
+ }
80
+ if (result && result.stderr) ctx.host.log.info("gcloud token command failed: " + String(result.stderr).trim());
81
+ } catch (e) {
82
+ ctx.host.log.info("gcloud token command unavailable: " + String(e));
83
+ }
84
+ return null;
85
+ }
86
+
87
+ function accessToken(ctx) {
88
+ var configured = setting(ctx, ["accessToken", "token"]) || (ctx.provider && trim(ctx.provider.apiKey));
89
+ if (configured) return configured;
90
+
91
+ var creds = readJson(ctx, adcPath(ctx));
92
+ if (creds && typeof creds === "object") {
93
+ if (trim(creds.access_token)) return trim(creds.access_token);
94
+ var refreshed = refreshAccessToken(ctx, creds);
95
+ if (refreshed) return refreshed;
96
+ }
97
+
98
+ return tokenFromGcloud(ctx, ["auth", "application-default", "print-access-token"]) ||
99
+ tokenFromGcloud(ctx, ["auth", "print-access-token"]);
100
+ }
101
+
102
+ function projectFromProperties(ctx) {
103
+ var path = gcloudPropertiesPath(ctx);
104
+ if (!ctx.host.fs.exists(path)) return null;
105
+ try {
106
+ var lines = ctx.host.fs.readText(path).split(/\r?\n/);
107
+ for (var i = 0; i < lines.length; i++) {
108
+ var line = lines[i].trim();
109
+ if (line.indexOf("project") === 0 && line.indexOf("=") >= 0) {
110
+ return trim(line.split("=").slice(1).join("="));
111
+ }
112
+ }
113
+ } catch (_) {}
114
+ return null;
115
+ }
116
+
117
+ function projectId(ctx) {
118
+ var configured = setting(ctx, ["projectId", "project", "googleCloudProject"]) ||
119
+ env(ctx, "GOOGLE_CLOUD_PROJECT") ||
120
+ env(ctx, "GCLOUD_PROJECT") ||
121
+ projectFromProperties(ctx);
122
+ if (configured) return configured;
123
+ var creds = readJson(ctx, adcPath(ctx));
124
+ return creds && trim(creds.project_id);
125
+ }
126
+
127
+ function validateProject(ctx, token, project) {
128
+ if (!project) return null;
129
+ try {
130
+ var resp = ctx.util.request({
131
+ method: "GET",
132
+ url: RESOURCE_MANAGER_URL + encodeURIComponent(project),
133
+ headers: {
134
+ Authorization: "Bearer " + token,
135
+ Accept: "application/json",
136
+ },
137
+ timeoutMs: 15000,
138
+ });
139
+ if (ctx.util.isAuthStatus(resp.status)) throw "Vertex AI credentials expired. Run `gcloud auth application-default login` again.";
140
+ if (resp.status < 200 || resp.status >= 300) {
141
+ ctx.host.log.warn("Vertex AI project validation returned HTTP " + resp.status);
142
+ return null;
143
+ }
144
+ var json = ctx.util.tryParseJson(resp.bodyText);
145
+ return json && (trim(json.name) || trim(json.projectId));
146
+ } catch (e) {
147
+ if (typeof e === "string") throw e;
148
+ ctx.host.log.warn("Vertex AI project validation failed: " + String(e));
149
+ return null;
150
+ }
151
+ }
152
+
153
+ function probe(ctx) {
154
+ var token = accessToken(ctx);
155
+ if (!token) {
156
+ throw "Vertex AI credentials not configured. Run gcloud auth application-default login or set GOOGLE_APPLICATION_CREDENTIALS.";
157
+ }
158
+ var project = projectId(ctx);
159
+ var projectName = validateProject(ctx, token, project) || project || "configured";
160
+ return {
161
+ displayName: "Vertex AI",
162
+ source: project ? "oauth" : "cli",
163
+ plan: project ? "Vertex AI (" + project + ")" : "Vertex AI",
164
+ lines: [
165
+ ctx.line.badge({ label: "Status", text: "Authenticated", color: "#22c55e" }),
166
+ ctx.line.text({ label: "Project", value: projectName }),
167
+ ],
168
+ };
169
+ }
170
+
171
+ globalThis.__openusage_plugin = { id: "vertex-ai", probe: probe };
172
+ })();
@@ -0,0 +1,18 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "id": "vertex-ai",
4
+ "name": "Vertex AI",
5
+ "version": "0.0.1",
6
+ "entry": "plugin.js",
7
+ "brandColor": "#4285F4",
8
+ "links": [
9
+ { "label": "Quotas", "url": "https://console.cloud.google.com/iam-admin/quotas" },
10
+ { "label": "Status", "url": "https://status.cloud.google.com" }
11
+ ],
12
+ "supportedModes": ["oauth", "local"],
13
+ "autoMode": "oauth",
14
+ "lines": [
15
+ { "type": "badge", "label": "Status", "scope": "overview", "primaryOrder": 1 },
16
+ { "type": "text", "label": "Project", "scope": "detail" }
17
+ ]
18
+ }
@@ -0,0 +1,10 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500">
2
+ <linearGradient id="a" x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(545.112313, -461.090759, 391.609634, 499.309021, 1447.697863, 171.147092)">
3
+ <stop stop-color="#01a4ff" offset="0"></stop>
4
+ <stop stop-color="#01ffc2" offset="0.792"></stop>
5
+ </linearGradient>
6
+ <g style="" transform="matrix(0.303615, 0, 0, 0.303615, -167.583325, 245.098888)">
7
+ <path fill="#006da8" d="M 1360.69 422.528 L 978.206 422.528 C 916.289 422.528 866.093 370.377 866.093 306.048 L 866.093 -146.17 C 866.093 -210.49 916.289 -262.64 978.206 -262.64 L 1525.57 -262.64 L 1360.69 422.528 Z" style="stroke-width: 1;"></path>
8
+ <path fill="url(#a)" d="M 1387.1 -392.85 L 1771.86 -392.85 C 1834.16 -392.85 1884.64 -340.4 1884.64 -275.71 L 1884.64 179.118 C 1884.64 243.815 1834.16 296.265 1771.86 296.265 L 1221.24 296.265 L 1387.1 -392.85 Z" style="stroke-width: 1;"></path>
9
+ </g>
10
+ </svg>
@@ -0,0 +1,6 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500">
2
+ <g style="" transform="matrix(0.438038, 0, 0, 0.438038, -92.835669, 201.648709)">
3
+ <path d="M 790.462 -169.42 C 790.663 -170.25 790.763 -170.67 790.992 -170.98 C 791.193 -171.25 791.465 -171.46 791.777 -171.59 C 792.131 -171.74 792.557 -171.74 793.41 -171.74 L 1057.29 -171.74 C 1100.39 -171.74 1135.33 -135.64 1135.33 -91.1 L 1135.33 221.988 C 1135.33 266.527 1100.39 302.633 1057.29 302.633 L 680.109 302.633 C 678.794 302.633 678.137 302.633 677.685 302.36 C 677.289 302.122 676.994 301.747 676.856 301.306 C 676.697 300.803 676.852 300.164 677.161 298.886 L 790.462 -169.42 Z" fill="currentColor" style="stroke-width: 1;"></path>
4
+ <path d="M 720.966 -78.133 C 721.272 -79.41 721.426 -80.048 721.267 -80.55 C 721.127 -80.99 720.832 -81.364 720.437 -81.602 C 719.986 -81.874 719.329 -81.874 718.017 -81.874 L 507.372 -81.874 C 464.637 -81.874 429.994 -45.768 429.994 -1.23 L 429.994 311.858 C 429.994 356.397 464.637 392.503 507.372 392.503 L 768.973 392.503 C 769.827 392.503 770.255 392.503 770.609 392.353 C 770.922 392.22 771.193 392.006 771.395 391.733 C 771.624 391.423 771.723 391.008 771.923 390.177 L 781.054 352.111 C 781.36 350.834 781.513 350.196 781.354 349.694 C 781.215 349.254 780.92 348.88 780.524 348.641 C 780.073 348.37 779.417 348.37 778.104 348.37 L 622.507 348.37 C 621.194 348.37 620.537 348.37 620.086 348.098 C 619.691 347.86 619.396 347.486 619.256 347.046 C 619.098 346.544 619.251 345.906 619.557 344.629 L 720.966 -78.133 Z" fill="currentColor" style="stroke-width: 1;"></path>
5
+ </g>
6
+ </svg>
@@ -0,0 +1,108 @@
1
+ (function () {
2
+ var API_URL = "https://app.warp.dev/graphql/v2?op=GetRequestLimitInfo";
3
+ var GRAPHQL_QUERY = "query GetRequestLimitInfo($requestContext: RequestContext!) { user(requestContext: $requestContext) { __typename ... on UserOutput { user { requestLimitInfo { isUnlimited nextRefreshTime requestLimit requestsUsedSinceLastRefresh } bonusGrants { requestCreditsGranted requestCreditsRemaining expiration } workspaces { bonusGrantsInfo { grants { requestCreditsGranted requestCreditsRemaining expiration } } } } } } }";
4
+
5
+ function loadApiKey(ctx) {
6
+ var v = ctx.host.env.get("WARP_API_KEY");
7
+ if (typeof v === "string" && v.trim()) return v.trim();
8
+ return null;
9
+ }
10
+
11
+ function probe(ctx) {
12
+ var apiKey = loadApiKey(ctx);
13
+ if (!apiKey) {
14
+ throw "Warp API key not found. Set WARP_API_KEY.";
15
+ }
16
+
17
+ var body = JSON.stringify({
18
+ query: GRAPHQL_QUERY,
19
+ variables: {
20
+ requestContext: {
21
+ clientContext: {},
22
+ osContext: { category: "Linux", name: "Linux", version: "6.0" },
23
+ },
24
+ },
25
+ operationName: "GetRequestLimitInfo",
26
+ });
27
+
28
+ var result = ctx.util.requestJson({
29
+ method: "POST",
30
+ url: API_URL,
31
+ headers: {
32
+ "Content-Type": "application/json",
33
+ Accept: "application/json",
34
+ "x-warp-client-id": "warp-app",
35
+ "x-warp-os-category": "Linux",
36
+ "x-warp-os-name": "Linux",
37
+ "x-warp-os-version": "6.0",
38
+ Authorization: "Bearer " + apiKey,
39
+ "User-Agent": "Warp/1.0",
40
+ },
41
+ bodyText: body,
42
+ timeoutMs: 15000,
43
+ });
44
+
45
+ if (ctx.util.isAuthStatus(result.resp.status)) {
46
+ throw "API key invalid or expired.";
47
+ }
48
+ if (result.resp.status < 200 || result.resp.status >= 300) {
49
+ throw "Warp API error (HTTP " + result.resp.status + ").";
50
+ }
51
+
52
+ var json = result.json;
53
+ if (!json) throw "Could not parse Warp response.";
54
+
55
+ if (json.errors && json.errors.length > 0) {
56
+ var msgs = json.errors.map(function (e) { return e.message || ""; }).filter(Boolean);
57
+ throw msgs.length > 0 ? msgs.join(" | ") : "GraphQL request failed.";
58
+ }
59
+
60
+ var userData = json.data && json.data.user && json.data.user.user;
61
+ if (!userData) throw "Missing user data in Warp response.";
62
+
63
+ var limitInfo = userData.requestLimitInfo || {};
64
+ var isUnlimited = limitInfo.isUnlimited === true;
65
+ var requestLimit = limitInfo.requestLimit || 0;
66
+ var requestsUsed = limitInfo.requestsUsedSinceLastRefresh || 0;
67
+
68
+ var usedPct = isUnlimited ? 0 : (requestLimit > 0 ? Math.min(100, requestsUsed / requestLimit * 100) : 0);
69
+
70
+ var progressOpts = {
71
+ label: "Credits",
72
+ used: usedPct,
73
+ limit: 100,
74
+ format: { kind: "percent" },
75
+ };
76
+ if (limitInfo.nextRefreshTime) {
77
+ var t = ctx.util.toIso(limitInfo.nextRefreshTime);
78
+ if (t) progressOpts.resetsAt = t;
79
+ }
80
+
81
+ var lines = [ctx.line.progress(progressOpts)];
82
+
83
+ if (isUnlimited) {
84
+ lines.push(ctx.line.badge({ label: "Plan", text: "Unlimited", color: "#22c55e" }));
85
+ } else {
86
+ lines.push(ctx.line.text({ label: "Usage", value: requestsUsed + " / " + requestLimit + " credits" }));
87
+ }
88
+
89
+ // Aggregate bonus grants from user + workspaces
90
+ var allGrants = [];
91
+ if (Array.isArray(userData.bonusGrants)) allGrants = allGrants.concat(userData.bonusGrants);
92
+ if (Array.isArray(userData.workspaces)) {
93
+ userData.workspaces.forEach(function (ws) {
94
+ var grants = ws && ws.bonusGrantsInfo && ws.bonusGrantsInfo.grants;
95
+ if (Array.isArray(grants)) allGrants = allGrants.concat(grants);
96
+ });
97
+ }
98
+ var bonusTotal = allGrants.reduce(function (s, g) { return s + (g.requestCreditsGranted || 0); }, 0);
99
+ var bonusRemaining = allGrants.reduce(function (s, g) { return s + (g.requestCreditsRemaining || 0); }, 0);
100
+ if (bonusTotal > 0 || bonusRemaining > 0) {
101
+ lines.push(ctx.line.text({ label: "Bonus", value: bonusRemaining + " / " + bonusTotal + " add-on credits" }));
102
+ }
103
+
104
+ return { lines: lines };
105
+ }
106
+
107
+ globalThis.__openusage_plugin = { id: "warp", probe: probe };
108
+ })();
@@ -0,0 +1,18 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "id": "warp",
4
+ "name": "Warp",
5
+ "version": "0.0.1",
6
+ "entry": "plugin.js",
7
+ "brandColor": "#01A4FF",
8
+ "links": [
9
+ { "label": "API Keys", "url": "https://docs.warp.dev/reference/cli/api-keys" }
10
+ ],
11
+ "supportedModes": ["api"],
12
+ "autoMode": "api",
13
+ "lines": [
14
+ { "type": "progress", "label": "Credits", "scope": "overview", "primaryOrder": 1 },
15
+ { "type": "text", "label": "Usage", "scope": "detail" },
16
+ { "type": "text", "label": "Bonus", "scope": "detail" }
17
+ ]
18
+ }
@@ -0,0 +1,3 @@
1
+ <svg width="100" height="100" viewBox="-10 -40 532 380" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M507.28 0.142623H502.4C476.721 0.10263 455.882 20.899 455.882 46.5745V150.416C455.882 171.153 438.743 187.95 418.344 187.95C406.224 187.95 394.125 181.851 386.945 171.613L280.889 20.1391C272.089 7.56133 257.77 0.0626373 242.271 0.0626373C218.091 0.0626373 196.332 20.6191 196.332 45.9946V150.436C196.332 171.173 179.333 187.97 158.794 187.97C146.634 187.97 134.555 181.871 127.375 171.633L8.69966 2.12228C6.01976 -1.71705 0 0.182617 0 4.8618V95.426C0 100.005 1.39995 104.444 4.01984 108.204L120.815 274.995C127.715 284.853 137.895 292.172 149.634 294.831C179.013 301.51 206.052 278.894 206.052 250.079V145.697C206.052 124.961 222.851 108.164 243.59 108.164H243.65C256.15 108.164 267.87 114.263 275.049 124.501L381.125 275.955C389.945 288.552 403.524 296.031 419.724 296.031C444.443 296.031 465.622 275.455 465.622 250.099V145.677C465.622 124.941 482.421 108.144 503.16 108.144H507.3C509.9 108.144 512 106.044 512 103.445V4.8418C512 2.24226 509.9 0.142623 507.3 0.142623H507.28Z" fill="currentColor"/>
3
+ </svg>
@@ -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>Windsurf</title><path clip-rule="evenodd" d="M23.78 5.004h-.228a2.187 2.187 0 00-2.18 2.196v4.912c0 .98-.804 1.775-1.76 1.775a1.818 1.818 0 01-1.472-.773L13.168 5.95a2.197 2.197 0 00-1.81-.95c-1.134 0-2.154.972-2.154 2.173v4.94c0 .98-.797 1.775-1.76 1.775-.57 0-1.136-.289-1.472-.773L.408 5.098C.282 4.918 0 5.007 0 5.228v4.284c0 .216.066.426.188.604l5.475 7.889c.324.466.8.812 1.351.938 1.377.316 2.645-.754 2.645-2.117V11.89c0-.98.787-1.775 1.76-1.775h.002c.586 0 1.135.288 1.472.773l4.972 7.163a2.15 2.15 0 001.81.95c1.158 0 2.151-.973 2.151-2.173v-4.939c0-.98.787-1.775 1.76-1.775h.194c.122 0 .22-.1.22-.222V5.225a.221.221 0 00-.22-.222z"></path></svg>
@@ -0,0 +1,208 @@
1
+ (function () {
2
+ var CLOUD_SERVICE = "exa.seat_management_pb.SeatManagementService"
3
+ var CLOUD_URL = "https://server.self-serve.windsurf.com"
4
+ var CLOUD_COMPAT_VERSION = "1.108.2"
5
+ var LOGIN_HINT = "Start Windsurf or sign in and try again."
6
+ var QUOTA_HINT = "Windsurf quota data unavailable. Try again later."
7
+ var DAY_MS = 24 * 60 * 60 * 1000
8
+ var WEEK_MS = 7 * DAY_MS
9
+
10
+ var VARIANTS = [
11
+ { marker: "devin-windsurf", ideName: "windsurf", appDir: "Devin" },
12
+ { marker: "devin-next-windsurf", ideName: "windsurf-next", appDir: "Devin - Next" },
13
+ { marker: "windsurf", ideName: "windsurf", appDir: "Windsurf" },
14
+ { marker: "windsurf-next", ideName: "windsurf-next", appDir: "Windsurf - Next" },
15
+ ]
16
+
17
+ function resolveVariants(ctx) {
18
+ var settings = (ctx.provider && ctx.provider.settings) || {}
19
+ var selected = settings.ideVariant
20
+ if (selected && !VARIANTS.some(function(v) { return v.marker === selected })) {
21
+ throw {code: "failed", message: "Unknown settings.ideVariant. Use windsurf, windsurf-next, devin-windsurf or devin-next-windsurf."}
22
+ }
23
+ if (settings.userDataDir && !selected) {
24
+ throw {code: "failed", message: "Set settings.ideVariant together with settings.userDataDir."}
25
+ }
26
+ return VARIANTS.filter(function(v) { return !selected || v.marker === selected }).map(function(v) {
27
+ var root = settings.userDataDir || ctx.host.fs.appSupportPath(v.appDir)
28
+ if (!root) throw {code: "failed", message: "IDE data directory unavailable. Set settings.ideVariant and settings.userDataDir."}
29
+ return {marker: v.marker, ideName: v.ideName, stateDb: root.replace(/[\\/]+$/, "") + "/User/globalStorage/state.vscdb"}
30
+ })
31
+ }
32
+
33
+ function readFiniteNumber(value) {
34
+ if (typeof value === "number") return Number.isFinite(value) ? value : null
35
+ if (typeof value !== "string") return null
36
+ var trimmed = value.trim()
37
+ if (!trimmed) return null
38
+ var parsed = Number(trimmed)
39
+ return Number.isFinite(parsed) ? parsed : null
40
+ }
41
+
42
+ function clampPercent(value) {
43
+ if (!Number.isFinite(value)) return 0
44
+ if (value < 0) return 0
45
+ if (value > 100) return 100
46
+ return value
47
+ }
48
+
49
+ function loadApiKey(ctx, variant) {
50
+ try {
51
+ var rows = ctx.host.sqlite.query(
52
+ variant.stateDb,
53
+ "SELECT value FROM ItemTable WHERE key = 'windsurfAuthStatus' LIMIT 1"
54
+ )
55
+ var parsed = ctx.util.tryParseJson(rows)
56
+ if (!parsed || !parsed.length || !parsed[0].value) return null
57
+ var auth = ctx.util.tryParseJson(parsed[0].value)
58
+ if (!auth || !auth.apiKey) return null
59
+ return auth.apiKey
60
+ } catch (e) {
61
+ ctx.host.log.warn("failed to read API key from " + variant.marker + ": " + String(e))
62
+ return null
63
+ }
64
+ }
65
+
66
+ function callCloud(ctx, apiKey, variant) {
67
+ try {
68
+ var resp = ctx.host.http.request({
69
+ method: "POST",
70
+ url: CLOUD_URL + "/" + CLOUD_SERVICE + "/GetUserStatus",
71
+ headers: {
72
+ "Content-Type": "application/json",
73
+ "Connect-Protocol-Version": "1",
74
+ },
75
+ bodyText: JSON.stringify({
76
+ metadata: {
77
+ apiKey: apiKey,
78
+ ideName: variant.ideName,
79
+ ideVersion: CLOUD_COMPAT_VERSION,
80
+ extensionName: variant.ideName,
81
+ extensionVersion: CLOUD_COMPAT_VERSION,
82
+ locale: "en",
83
+ },
84
+ }),
85
+ timeoutMs: 15000,
86
+ })
87
+ if (resp.status < 200 || resp.status >= 300) {
88
+ ctx.host.log.warn("cloud request returned status " + resp.status + " for " + variant.marker)
89
+ if (ctx.util && typeof ctx.util.isAuthStatus === "function" && ctx.util.isAuthStatus(resp.status)) {
90
+ return { __openusageAuthError: true }
91
+ }
92
+ return null
93
+ }
94
+ return ctx.util.tryParseJson(resp.bodyText)
95
+ } catch (e) {
96
+ ctx.host.log.warn("cloud request failed for " + variant.marker + ": " + String(e))
97
+ return null
98
+ }
99
+ }
100
+
101
+ function unixSecondsToIso(ctx, value) {
102
+ var seconds = readFiniteNumber(value)
103
+ if (seconds === null) return null
104
+ return ctx.util.toIso(seconds * 1000)
105
+ }
106
+
107
+ function formatDollarsFromMicros(value) {
108
+ var micros = readFiniteNumber(value)
109
+ if (micros === null) return null
110
+ if (!Number.isFinite(micros)) return null
111
+ if (micros < 0) micros = 0
112
+ return "$" + (micros / 1000000).toFixed(2)
113
+ }
114
+
115
+ function buildQuotaLine(ctx, label, remainingPercent, resetsAt, periodDurationMs) {
116
+ var remaining = readFiniteNumber(remainingPercent)
117
+ if (remaining === null) return null
118
+ var line = {
119
+ label: label,
120
+ used: clampPercent(100 - remaining),
121
+ limit: 100,
122
+ format: { kind: "percent" },
123
+ periodDurationMs: periodDurationMs,
124
+ }
125
+ if (resetsAt) line.resetsAt = resetsAt
126
+ return ctx.line.progress(line)
127
+ }
128
+
129
+ function hasQuotaContract(planStatus) {
130
+ return (
131
+ readFiniteNumber(planStatus && planStatus.dailyQuotaRemainingPercent) !== null &&
132
+ readFiniteNumber(planStatus && planStatus.weeklyQuotaRemainingPercent) !== null &&
133
+ readFiniteNumber(planStatus && planStatus.dailyQuotaResetAtUnix) !== null &&
134
+ readFiniteNumber(planStatus && planStatus.weeklyQuotaResetAtUnix) !== null
135
+ )
136
+ }
137
+
138
+ function buildOutput(ctx, userStatus) {
139
+ var planStatus = (userStatus && userStatus.planStatus) || {}
140
+ if (!hasQuotaContract(planStatus)) throw QUOTA_HINT
141
+
142
+ var planInfo = planStatus.planInfo || {}
143
+ var planName = typeof planInfo.planName === "string" && planInfo.planName.trim()
144
+ ? planInfo.planName.trim()
145
+ : "Unknown"
146
+
147
+ var dailyReset = unixSecondsToIso(ctx, planStatus.dailyQuotaResetAtUnix)
148
+ var weeklyReset = unixSecondsToIso(ctx, planStatus.weeklyQuotaResetAtUnix)
149
+ var extraUsageBalance = formatDollarsFromMicros(planStatus.overageBalanceMicros)
150
+
151
+ if (!dailyReset || !weeklyReset) throw QUOTA_HINT
152
+
153
+ var dailyLine = buildQuotaLine(ctx, "Daily quota", planStatus.dailyQuotaRemainingPercent, dailyReset, DAY_MS)
154
+ var weeklyLine = buildQuotaLine(ctx, "Weekly quota", planStatus.weeklyQuotaRemainingPercent, weeklyReset, WEEK_MS)
155
+
156
+ if (!dailyLine || !weeklyLine) throw QUOTA_HINT
157
+
158
+ var lines = [dailyLine, weeklyLine]
159
+ if (extraUsageBalance) {
160
+ lines.push(ctx.line.text({ label: "Extra usage balance", value: extraUsageBalance }))
161
+ }
162
+
163
+ return {
164
+ plan: planName,
165
+ lines: lines,
166
+ }
167
+ }
168
+
169
+ function probe(ctx) {
170
+ var sawApiKey = false
171
+ var sawAuthFailure = false
172
+
173
+ var candidates = resolveVariants(ctx).map(function(variant) {
174
+ return {variant: variant, apiKey: loadApiKey(ctx, variant)}
175
+ }).filter(function(candidate) { return !!candidate.apiKey })
176
+ if (candidates.length > 1) {
177
+ throw {code: "failed", message: "Multiple Windsurf/Devin installations are signed in. Select settings.ideVariant to choose one account."}
178
+ }
179
+ for (var i = 0; i < candidates.length; i++) {
180
+ var variant = candidates[i].variant
181
+ var apiKey = candidates[i].apiKey
182
+ sawApiKey = true
183
+
184
+ var data = callCloud(ctx, apiKey, variant)
185
+ if (data && data.__openusageAuthError) {
186
+ sawAuthFailure = true
187
+ continue
188
+ }
189
+ if (!data || !data.userStatus) continue
190
+
191
+ try {
192
+ return buildOutput(ctx, data.userStatus)
193
+ } catch (e) {
194
+ if (e === QUOTA_HINT) {
195
+ ctx.host.log.warn("quota contract unavailable for " + variant.marker)
196
+ continue
197
+ }
198
+ throw e
199
+ }
200
+ }
201
+
202
+ if (sawAuthFailure) throw LOGIN_HINT
203
+ if (sawApiKey) throw QUOTA_HINT
204
+ throw LOGIN_HINT
205
+ }
206
+
207
+ globalThis.__openusage_plugin = { id: "windsurf", probe: probe }
208
+ })()