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

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 (273) hide show
  1. package/LICENSE +0 -0
  2. package/native-manifest.json +365 -77
  3. package/package.json +49 -1
  4. package/plugins/UPSTREAM-LICENSES.md +109 -0
  5. package/plugins/abacus-ai/icon.svg +0 -0
  6. package/plugins/abacus-ai/plugin.js +0 -0
  7. package/plugins/abacus-ai/plugin.json +0 -0
  8. package/plugins/aiand/icon.svg +6 -0
  9. package/plugins/aiand/plugin.js +108 -0
  10. package/plugins/aiand/plugin.json +22 -0
  11. package/plugins/alibaba/icon-color.svg +0 -0
  12. package/plugins/alibaba/icon.svg +0 -0
  13. package/plugins/alibaba/plugin.js +0 -0
  14. package/plugins/alibaba/plugin.json +0 -0
  15. package/plugins/alibaba-token-plan/icon-color.svg +0 -0
  16. package/plugins/alibaba-token-plan/icon.svg +0 -0
  17. package/plugins/alibaba-token-plan/plugin.js +0 -0
  18. package/plugins/alibaba-token-plan/plugin.json +0 -0
  19. package/plugins/amp/icon-color.svg +0 -0
  20. package/plugins/amp/icon-conflict.svg +0 -0
  21. package/plugins/amp/icon.svg +0 -0
  22. package/plugins/amp/plugin.js +0 -0
  23. package/plugins/amp/plugin.json +0 -0
  24. package/plugins/antigravity/icon-color.svg +0 -0
  25. package/plugins/antigravity/icon-conflict.svg +0 -0
  26. package/plugins/antigravity/icon.svg +0 -0
  27. package/plugins/antigravity/plugin.js +0 -0
  28. package/plugins/antigravity/plugin.json +0 -0
  29. package/plugins/antigravity-cli/icon.svg +0 -0
  30. package/plugins/antigravity-cli/plugin.js +0 -0
  31. package/plugins/antigravity-cli/plugin.json +0 -0
  32. package/plugins/antigravity-ide/icon.svg +0 -0
  33. package/plugins/antigravity-ide/plugin.js +0 -0
  34. package/plugins/antigravity-ide/plugin.json +0 -0
  35. package/plugins/augment/icon.svg +0 -0
  36. package/plugins/augment/plugin.js +0 -0
  37. package/plugins/augment/plugin.json +0 -0
  38. package/plugins/aws-bedrock/icon-color.svg +0 -0
  39. package/plugins/aws-bedrock/icon.svg +0 -0
  40. package/plugins/aws-bedrock/plugin.js +0 -0
  41. package/plugins/aws-bedrock/plugin.json +0 -0
  42. package/plugins/azure-openai/icon-color.svg +0 -0
  43. package/plugins/azure-openai/icon.svg +0 -0
  44. package/plugins/azure-openai/plugin.js +0 -0
  45. package/plugins/azure-openai/plugin.json +0 -0
  46. package/plugins/chutes/icon.svg +0 -0
  47. package/plugins/chutes/plugin.js +0 -0
  48. package/plugins/chutes/plugin.json +0 -0
  49. package/plugins/claude/icon-color.svg +0 -0
  50. package/plugins/claude/icon.svg +0 -0
  51. package/plugins/claude/plugin.js +70 -23
  52. package/plugins/claude/plugin.json +0 -0
  53. package/plugins/clawrouter/icon.svg +7 -0
  54. package/plugins/clawrouter/plugin.js +45 -0
  55. package/plugins/clawrouter/plugin.json +22 -0
  56. package/plugins/clinepass/icon.svg +4 -0
  57. package/plugins/clinepass/plugin.js +71 -0
  58. package/plugins/clinepass/plugin.json +23 -0
  59. package/plugins/codebuddy/plugin.js +331 -0
  60. package/plugins/codebuddy/plugin.json +30 -0
  61. package/plugins/codebuff/icon.svg +0 -0
  62. package/plugins/codebuff/plugin.js +0 -0
  63. package/plugins/codebuff/plugin.json +0 -0
  64. package/plugins/codex/icon-color.svg +0 -0
  65. package/plugins/codex/icon.svg +0 -0
  66. package/plugins/codex/plugin.js +7 -2
  67. package/plugins/codex/plugin.json +0 -0
  68. package/plugins/command-code/icon.svg +0 -0
  69. package/plugins/command-code/plugin.js +7 -0
  70. package/plugins/command-code/plugin.json +0 -0
  71. package/plugins/copilot/icon-color.svg +0 -0
  72. package/plugins/copilot/icon.svg +0 -0
  73. package/plugins/copilot/plugin.js +61 -9
  74. package/plugins/copilot/plugin.json +4 -1
  75. package/plugins/crof/icon.svg +0 -0
  76. package/plugins/crof/plugin.js +0 -0
  77. package/plugins/crof/plugin.json +0 -0
  78. package/plugins/crofai/icon.svg +0 -0
  79. package/plugins/crofai/plugin.js +0 -0
  80. package/plugins/crofai/plugin.json +0 -0
  81. package/plugins/cursor/icon-conflict.svg +0 -0
  82. package/plugins/cursor/icon.svg +0 -0
  83. package/plugins/cursor/plugin.js +46 -9
  84. package/plugins/cursor/plugin.json +3 -2
  85. package/plugins/cursor-nightly/icon.png +0 -0
  86. package/plugins/cursor-nightly/plugin.js +45 -8
  87. package/plugins/cursor-nightly/plugin.json +3 -2
  88. package/plugins/deepgram/icon.svg +0 -0
  89. package/plugins/deepgram/plugin.js +0 -0
  90. package/plugins/deepgram/plugin.json +0 -0
  91. package/plugins/deepinfra/icon.svg +4 -0
  92. package/plugins/deepinfra/plugin.js +97 -0
  93. package/plugins/deepinfra/plugin.json +28 -0
  94. package/plugins/deepseek/icon-color.svg +0 -0
  95. package/plugins/deepseek/icon.svg +0 -0
  96. package/plugins/deepseek/plugin.js +0 -0
  97. package/plugins/deepseek/plugin.json +0 -0
  98. package/plugins/devin/icon.svg +0 -0
  99. package/plugins/devin/plugin.js +111 -0
  100. package/plugins/devin/plugin.json +2 -1
  101. package/plugins/doubao/icon-color.svg +0 -0
  102. package/plugins/doubao/icon.svg +0 -0
  103. package/plugins/doubao/plugin.js +0 -0
  104. package/plugins/doubao/plugin.json +0 -0
  105. package/plugins/droid/icon.svg +0 -0
  106. package/plugins/droid/plugin.json +2 -1
  107. package/plugins/elevenlabs/icon.svg +0 -0
  108. package/plugins/elevenlabs/plugin.js +17 -2
  109. package/plugins/elevenlabs/plugin.json +0 -0
  110. package/plugins/factory/icon-conflict.svg +0 -0
  111. package/plugins/factory/icon.svg +0 -0
  112. package/plugins/factory/plugin.js +38 -14
  113. package/plugins/factory/plugin.json +2 -1
  114. package/plugins/fireworks-ai/icon.svg +0 -0
  115. package/plugins/fireworks-ai/plugin.js +0 -0
  116. package/plugins/fireworks-ai/plugin.json +0 -0
  117. package/plugins/gemini/icon-color.svg +0 -0
  118. package/plugins/gemini/icon.svg +0 -0
  119. package/plugins/gemini/plugin.js +0 -0
  120. package/plugins/gemini/plugin.json +0 -0
  121. package/plugins/grok/icon.svg +0 -0
  122. package/plugins/grok/plugin.js +30 -5
  123. package/plugins/grok/plugin.json +3 -1
  124. package/plugins/groqcloud/icon.svg +0 -0
  125. package/plugins/groqcloud/plugin.js +0 -0
  126. package/plugins/groqcloud/plugin.json +0 -0
  127. package/plugins/ibmbob/icon.svg +23 -0
  128. package/plugins/ibmbob/plugin.js +61 -0
  129. package/plugins/ibmbob/plugin.json +22 -0
  130. package/plugins/jetbrains-ai-assistant/icon-color.svg +0 -0
  131. package/plugins/jetbrains-ai-assistant/icon-conflict.svg +0 -0
  132. package/plugins/jetbrains-ai-assistant/icon.svg +0 -0
  133. package/plugins/jetbrains-ai-assistant/plugin.js +0 -0
  134. package/plugins/jetbrains-ai-assistant/plugin.json +0 -0
  135. package/plugins/kilo/icon.svg +0 -0
  136. package/plugins/kilo/plugin.js +0 -0
  137. package/plugins/kilo/plugin.json +0 -0
  138. package/plugins/kimi/icon-color.svg +0 -0
  139. package/plugins/kimi/icon-conflict.svg +0 -0
  140. package/plugins/kimi/icon.svg +0 -0
  141. package/plugins/kimi/plugin.js +122 -141
  142. package/plugins/kimi/plugin.json +5 -2
  143. package/plugins/kimi-k2/icon-color.svg +0 -0
  144. package/plugins/kimi-k2/icon.svg +0 -0
  145. package/plugins/kimi-k2/plugin.js +0 -0
  146. package/plugins/kimi-k2/plugin.json +0 -0
  147. package/plugins/kiro/icon-color.svg +0 -0
  148. package/plugins/kiro/icon-conflict.svg +0 -0
  149. package/plugins/kiro/icon.svg +0 -0
  150. package/plugins/kiro/plugin.js +49 -10
  151. package/plugins/kiro/plugin.json +3 -1
  152. package/plugins/litellm/icon.svg +0 -0
  153. package/plugins/litellm/plugin.js +0 -0
  154. package/plugins/litellm/plugin.json +0 -0
  155. package/plugins/llm-proxy/icon.svg +0 -0
  156. package/plugins/llm-proxy/plugin.js +0 -0
  157. package/plugins/llm-proxy/plugin.json +0 -0
  158. package/plugins/longcat/icon.svg +4 -0
  159. package/plugins/longcat/plugin.js +182 -0
  160. package/plugins/longcat/plugin.json +23 -0
  161. package/plugins/manus/icon.svg +0 -0
  162. package/plugins/manus/plugin.js +0 -0
  163. package/plugins/manus/plugin.json +0 -0
  164. package/plugins/mimo/icon.svg +0 -0
  165. package/plugins/mimo/plugin.js +0 -0
  166. package/plugins/mimo/plugin.json +0 -0
  167. package/plugins/minimax/icon-color.svg +0 -0
  168. package/plugins/minimax/icon-conflict.svg +0 -0
  169. package/plugins/minimax/icon.svg +0 -0
  170. package/plugins/minimax/plugin.js +25 -31
  171. package/plugins/minimax/plugin.json +0 -0
  172. package/plugins/mistral/icon-color.svg +0 -0
  173. package/plugins/mistral/icon.svg +0 -0
  174. package/plugins/mistral/plugin.js +0 -0
  175. package/plugins/mistral/plugin.json +0 -0
  176. package/plugins/moonshot/icon.svg +0 -0
  177. package/plugins/moonshot/plugin.js +8 -6
  178. package/plugins/moonshot/plugin.json +0 -0
  179. package/plugins/nanogpt/icon-color.svg +0 -0
  180. package/plugins/nanogpt/icon.svg +0 -0
  181. package/plugins/nanogpt/plugin.js +0 -0
  182. package/plugins/nanogpt/plugin.json +0 -0
  183. package/plugins/neuralwatt/icon.svg +0 -0
  184. package/plugins/neuralwatt/plugin.js +0 -0
  185. package/plugins/neuralwatt/plugin.json +0 -0
  186. package/plugins/notion/icon.svg +1 -0
  187. package/plugins/notion/plugin.js +282 -0
  188. package/plugins/notion/plugin.json +29 -0
  189. package/plugins/ollama/icon.svg +0 -0
  190. package/plugins/ollama/plugin.js +257 -56
  191. package/plugins/ollama/plugin.json +6 -3
  192. package/plugins/openai-api/icon.svg +0 -0
  193. package/plugins/openai-api/plugin.js +0 -0
  194. package/plugins/openai-api/plugin.json +0 -0
  195. package/plugins/opencode/icon.svg +0 -0
  196. package/plugins/opencode/plugin.js +0 -0
  197. package/plugins/opencode/plugin.json +0 -0
  198. package/plugins/opencode-go/icon-conflict.svg +0 -0
  199. package/plugins/opencode-go/icon.svg +0 -0
  200. package/plugins/opencode-go/plugin.js +78 -10
  201. package/plugins/opencode-go/plugin.json +5 -2
  202. package/plugins/openrouter/icon.svg +0 -0
  203. package/plugins/openrouter/plugin.js +371 -114
  204. package/plugins/openrouter/plugin.json +6 -0
  205. package/plugins/perplexity/icon-color.svg +0 -0
  206. package/plugins/perplexity/icon-conflict.svg +0 -0
  207. package/plugins/perplexity/icon.svg +0 -0
  208. package/plugins/perplexity/plugin.js +0 -0
  209. package/plugins/perplexity/plugin.json +0 -0
  210. package/plugins/poe/icon.svg +0 -0
  211. package/plugins/poe/plugin.js +24 -18
  212. package/plugins/poe/plugin.json +2 -0
  213. package/plugins/qoder/icon.svg +3 -0
  214. package/plugins/qoder/plugin.js +227 -0
  215. package/plugins/qoder/plugin.json +23 -0
  216. package/plugins/qwencloud/icon.svg +4 -0
  217. package/plugins/qwencloud/plugin.js +677 -0
  218. package/plugins/qwencloud/plugin.json +29 -0
  219. package/plugins/sakana/icon.svg +5 -0
  220. package/plugins/sakana/plugin.js +156 -0
  221. package/plugins/sakana/plugin.json +23 -0
  222. package/plugins/stepfun/icon-color.svg +0 -0
  223. package/plugins/stepfun/icon.svg +0 -0
  224. package/plugins/stepfun/plugin.js +0 -0
  225. package/plugins/stepfun/plugin.json +0 -0
  226. package/plugins/sub2api/icon.svg +4 -0
  227. package/plugins/sub2api/plugin.js +191 -0
  228. package/plugins/sub2api/plugin.json +16 -0
  229. package/plugins/synthetic/icon-conflict.svg +0 -0
  230. package/plugins/synthetic/icon.svg +0 -0
  231. package/plugins/synthetic/plugin.js +0 -0
  232. package/plugins/synthetic/plugin.json +0 -0
  233. package/plugins/t3chat/icon-color.svg +0 -0
  234. package/plugins/t3chat/icon.svg +0 -0
  235. package/plugins/t3chat/plugin.js +0 -0
  236. package/plugins/t3chat/plugin.json +0 -0
  237. package/plugins/venice/icon-color.svg +0 -0
  238. package/plugins/venice/icon.svg +0 -0
  239. package/plugins/venice/plugin.js +0 -0
  240. package/plugins/venice/plugin.json +0 -0
  241. package/plugins/vertex-ai/icon-color.svg +0 -0
  242. package/plugins/vertex-ai/icon.svg +0 -0
  243. package/plugins/vertex-ai/plugin.js +0 -0
  244. package/plugins/vertex-ai/plugin.json +0 -0
  245. package/plugins/warp/icon-color.svg +0 -0
  246. package/plugins/warp/icon.svg +0 -0
  247. package/plugins/warp/plugin.js +0 -0
  248. package/plugins/warp/plugin.json +0 -0
  249. package/plugins/wayfinder/icon.svg +5 -0
  250. package/plugins/wayfinder/plugin.js +47 -0
  251. package/plugins/wayfinder/plugin.json +16 -0
  252. package/plugins/windsurf/icon-conflict.svg +0 -0
  253. package/plugins/windsurf/icon.svg +0 -0
  254. package/plugins/windsurf/plugin.js +0 -0
  255. package/plugins/windsurf/plugin.json +0 -0
  256. package/plugins/xai/icon.svg +7 -0
  257. package/plugins/xai/plugin.js +162 -0
  258. package/plugins/xai/plugin.json +28 -0
  259. package/plugins/zai/icon-conflict.svg +0 -0
  260. package/plugins/zai/icon.svg +0 -0
  261. package/plugins/zai/plugin.js +111 -161
  262. package/plugins/zai/plugin.json +4 -1
  263. package/plugins/zed/icon.svg +0 -0
  264. package/plugins/zed/plugin.js +0 -0
  265. package/plugins/zed/plugin.json +0 -0
  266. package/plugins/zenmux/icon.svg +3 -0
  267. package/plugins/zenmux/plugin.js +102 -0
  268. package/plugins/zenmux/plugin.json +23 -0
  269. package/plugins/zoommate/icon.svg +1 -0
  270. package/plugins/zoommate/plugin.js +244 -0
  271. package/plugins/zoommate/plugin.json +29 -0
  272. package/usagestat +0 -0
  273. package/usagestatd +0 -0
@@ -0,0 +1,29 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "id": "qwencloud",
4
+ "name": "Qwen Cloud",
5
+ "version": "0.1.0",
6
+ "entry": "plugin.js",
7
+ "enabledByDefault": false,
8
+ "supportedModes": [
9
+ "web"
10
+ ],
11
+ "autoMode": "web",
12
+ "webUrl": "https://home.qwencloud.com",
13
+ "usageDashboardUrl": "https://home.qwencloud.com/billing/subscription/token-plan-individual",
14
+ "statusPageUrl": "https://status.alibabacloud.com",
15
+ "links": [
16
+ {
17
+ "label": "Dashboard",
18
+ "url": "https://home.qwencloud.com/billing/subscription/token-plan-individual"
19
+ },
20
+ {
21
+ "label": "Status",
22
+ "url": "https://status.alibabacloud.com"
23
+ }
24
+ ],
25
+ "envVars": [
26
+ "QWEN_CLOUD_COOKIE",
27
+ "QWEN_CLOUD_COOKIE_HEADER"
28
+ ]
29
+ }
@@ -0,0 +1,5 @@
1
+ <svg width="100" height="100" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M50 8C28.7 8 11.5 25.2 11.5 46.5C11.5 67.8 28.7 85 50 85C71.3 85 88.5 67.8 88.5 46.5C88.5 25.2 71.3 8 50 8Z" stroke="white" stroke-width="8"/>
3
+ <path d="M31 62C36.3 68.1 43.3 71.2 52 71.2C62.4 71.2 69.6 65.9 69.6 58.2C69.6 49.7 62.1 47.6 53.8 45.4C47.7 43.8 42.5 42.4 42.5 38.3C42.5 34.8 45.9 32.4 51.3 32.4C56.9 32.4 61.7 34.6 65.8 39" stroke="white" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
4
+ <path d="M33.2 30.4C37.1 24.8 43.9 21.5 51.8 21.5C60.5 21.5 67.3 25.1 72.2 32.2" stroke="white" stroke-width="8" stroke-linecap="round"/>
5
+ </svg>
@@ -0,0 +1,156 @@
1
+ (function () {
2
+ var BILLING_URL = "https://console.sakana.ai/billing";
3
+ var USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36";
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 normalizeCookie(raw) {
27
+ var header = trim(raw);
28
+ if (!header) return null;
29
+ if (header.slice(0, 7).toLowerCase() === "cookie:") header = header.slice(7).trim();
30
+ var pairs = [];
31
+ var chunks = header.split(";");
32
+ for (var i = 0; i < chunks.length; i++) {
33
+ var idx = chunks[i].indexOf("=");
34
+ if (idx < 0) continue;
35
+ var name = chunks[i].slice(0, idx).trim();
36
+ var value = chunks[i].slice(idx + 1).trim();
37
+ if (name && value) pairs.push(name + "=" + value);
38
+ }
39
+ return pairs.length ? pairs.join("; ") : null;
40
+ }
41
+
42
+ function cookieHeader(ctx) {
43
+ return normalizeCookie(ctx.provider && ctx.provider.cookieHeader) ||
44
+ normalizeCookie(setting(ctx, ["cookieHeader", "cookie"])) ||
45
+ normalizeCookie(env(ctx, "SAKANA_COOKIE"));
46
+ }
47
+
48
+ function looksSignedOut(text) {
49
+ var lower = String(text || "").toLowerCase();
50
+ return lower.indexOf("sign in") >= 0 || lower.indexOf("log in") >= 0 || lower.indexOf("/auth/") >= 0;
51
+ }
52
+
53
+ function parseReset(raw) {
54
+ var text = String(raw || "").replace(/\bat\b/i, "").replace(/\s+/g, " ").trim();
55
+ var ms = Date.parse(text + " UTC");
56
+ return Number.isFinite(ms) ? new Date(ms).toISOString() : null;
57
+ }
58
+
59
+ function extractResetText(segment) {
60
+ var patterns = [
61
+ /([A-Z][a-z]+ \d{1,2}, \d{4} at \d{1,2}:\d{2} [AP]M)/i,
62
+ /(?:reset|renews?)[^A-Z]{0,80}([A-Z][a-z]+ \d{1,2}, \d{4} at \d{1,2}:\d{2} [AP]M)/i,
63
+ ];
64
+ for (var i = 0; i < patterns.length; i++) {
65
+ var match = patterns[i].exec(segment);
66
+ if (match && match[1]) return match[1];
67
+ }
68
+ return null;
69
+ }
70
+
71
+ function extractPercent(segment) {
72
+ var patterns = [
73
+ /([0-9]+(?:\.[0-9]+)?)\s*%\s*(?:used|usage)?/i,
74
+ /(?:used|usage)[^0-9]{0,40}([0-9]+(?:\.[0-9]+)?)\s*%/i,
75
+ /"(?:usedPercent|used_percent|percent)"\s*:\s*([0-9]+(?:\.[0-9]+)?)/i,
76
+ ];
77
+ for (var i = 0; i < patterns.length; i++) {
78
+ var match = patterns[i].exec(segment);
79
+ if (match && match[1]) {
80
+ var value = Number(match[1]);
81
+ if (Number.isFinite(value)) return value;
82
+ }
83
+ }
84
+ return null;
85
+ }
86
+
87
+ function extractWindow(ctx, text, labels, displayLabel, minutes) {
88
+ var lower = text.toLowerCase();
89
+ var index = -1;
90
+ for (var i = 0; i < labels.length; i++) {
91
+ var found = lower.indexOf(labels[i]);
92
+ if (found >= 0 && (index < 0 || found < index)) index = found;
93
+ }
94
+ if (index < 0) return null;
95
+ var end = Math.min(text.length, index + 1400);
96
+ var boundaries = displayLabel === "Weekly" ? ["5-hour", "5 hour", "five-hour", "session"] : ["weekly", "week"];
97
+ for (var b = 0; b < boundaries.length; b++) {
98
+ var next = lower.indexOf(boundaries[b], index + 1);
99
+ if (next >= 0) end = Math.min(end, next);
100
+ }
101
+ var segment = text.slice(index, end);
102
+ var percent = extractPercent(segment);
103
+ if (percent === null) return null;
104
+ var resetText = extractResetText(segment);
105
+ var opts = {
106
+ label: displayLabel,
107
+ used: Math.max(0, Math.min(100, percent)),
108
+ limit: 100,
109
+ format: { kind: "percent" },
110
+ periodDurationMs: minutes * 60 * 1000,
111
+ };
112
+ if (resetText) {
113
+ opts.resetsAt = parseReset(resetText);
114
+ opts.detail = resetText;
115
+ }
116
+ return ctx.line.progress(opts);
117
+ }
118
+
119
+ function probe(ctx) {
120
+ var cookie = cookieHeader(ctx);
121
+ if (!cookie) throw "Sakana session not configured. Set SAKANA_COOKIE or provider cookieHeader.";
122
+ var resp = ctx.util.request({
123
+ method: "GET",
124
+ url: BILLING_URL,
125
+ headers: {
126
+ Cookie: cookie,
127
+ Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
128
+ "User-Agent": USER_AGENT,
129
+ },
130
+ timeoutMs: 15000,
131
+ });
132
+ if (ctx.util.isAuthStatus(resp.status)) throw "Sakana session expired.";
133
+ if (resp.status < 200 || resp.status >= 300) throw "Sakana billing returned HTTP " + resp.status + ".";
134
+ var primary = extractWindow(ctx, resp.bodyText || "", ["5-hour", "5 hour", "five-hour", "session"], "5-hour", 5 * 60);
135
+ var lines = primary ? [primary] : [];
136
+ var weekly = extractWindow(ctx, resp.bodyText || "", ["weekly", "week"], "Weekly", 7 * 24 * 60);
137
+ if (weekly) lines.push(weekly);
138
+ if (!lines.length) throw looksSignedOut(resp.bodyText) ? "Sakana login required." : "Missing Sakana quota windows.";
139
+ try {
140
+ var payg = ctx.util.request({ method: "GET", url: BILLING_URL + "?tab=payAsYouGo",
141
+ headers: { Cookie: cookie, Accept: "text/html,application/xhtml+xml", "User-Agent": USER_AGENT }, timeoutMs: 1500 });
142
+ if (payg.status === 200) {
143
+ var html = String(payg.bodyText || "").replace(/<!--[\s\S]*?-->/g, "");
144
+ var balance = /<h2[^>]*>\s*Credit balance\s*<\/h2>[\s\S]{0,900}?<p[^>]*tabular-nums[^>]*>\s*\$?([0-9][0-9,]*(?:\.[0-9]+)?)\s*<\/p>/i.exec(html);
145
+ var spent = /<h2[^>]*>\s*Usage\s*<\/h2>\s*<span[^>]*>\s*Total:\s*\$?([0-9][0-9,]*(?:\.[0-9]+)?)\s*<\/span>/i.exec(html);
146
+ if (balance && Number.isFinite(Number(balance[1].replace(/,/g, "")))) lines.push(ctx.line.text({ label: "PAYG Balance", value: "$" + Number(balance[1].replace(/,/g, "")).toFixed(2) }));
147
+ if (balance && spent && Number.isFinite(Number(spent[1].replace(/,/g, "")))) lines.push(ctx.line.text({ label: "PAYG Usage", value: "$" + Number(spent[1].replace(/,/g, "")).toFixed(2) }));
148
+ }
149
+ } catch (_) {
150
+ ctx.host.log.warn("Sakana PAYG balance unavailable");
151
+ }
152
+ return { displayName: "Sakana AI", source: "web", plan: "Sakana Console", lines: lines };
153
+ }
154
+
155
+ globalThis.__openusage_plugin = { id: "sakana", probe: probe };
156
+ })();
@@ -0,0 +1,23 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "id": "sakana",
4
+ "name": "Sakana AI",
5
+ "version": "0.1.0",
6
+ "entry": "plugin.js",
7
+ "enabledByDefault": false,
8
+ "supportedModes": [
9
+ "web"
10
+ ],
11
+ "autoMode": "web",
12
+ "webUrl": "https://console.sakana.ai",
13
+ "usageDashboardUrl": "https://console.sakana.ai/billing",
14
+ "links": [
15
+ {
16
+ "label": "Dashboard",
17
+ "url": "https://console.sakana.ai/billing"
18
+ }
19
+ ],
20
+ "envVars": [
21
+ "SAKANA_COOKIE"
22
+ ]
23
+ }
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,4 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
2
+ <path fill="#2dc6d8" d="M20 8h25l11 13-7 7-9-11H24L12 31l17 10-7 8L5 38a9 9 0 0 1-2-13L14 11a8 8 0 0 1 6-3Z"/>
3
+ <path fill="#2768ff" d="m42 15 17 11a9 9 0 0 1 2 13L50 53a8 8 0 0 1-6 3H19L8 43l7-7 9 11h16l12-14-17-10 7-8Z"/>
4
+ </svg>
@@ -0,0 +1,191 @@
1
+ (function () {
2
+ function clean(value) {
3
+ if (typeof value !== "string") return null;
4
+ var v = value.trim();
5
+ if (!v) return null;
6
+ if ((v[0] === "\"" && v[v.length - 1] === "\"") || (v[0] === "'" && v[v.length - 1] === "'")) v = v.slice(1, -1).trim();
7
+ return v || null;
8
+ }
9
+
10
+ function env(ctx, name) {
11
+ try {
12
+ return clean(ctx.host.env.get(name));
13
+ } catch (_) {
14
+ return null;
15
+ }
16
+ }
17
+
18
+ function setting(ctx, names) {
19
+ var settings = ctx.provider && ctx.provider.settings ? ctx.provider.settings : {};
20
+ for (var i = 0; i < names.length; i++) {
21
+ var v = clean(settings[names[i]]);
22
+ if (v) return v;
23
+ }
24
+ return null;
25
+ }
26
+
27
+ function apiKey(ctx) {
28
+ return clean(ctx.provider && ctx.provider.apiKey) || env(ctx, "SUB2API_API_KEY");
29
+ }
30
+
31
+ function baseUrl(ctx) {
32
+ var raw = setting(ctx, ["baseUrl", "apiUrl", "apiBase"]) || clean(ctx.provider && ctx.provider.workspaceId) || env(ctx, "SUB2API_BASE_URL");
33
+ var base = raw ? ctx.host.http.validateBaseUrl(raw, true) : null;
34
+ if (!base) throw "Missing or invalid sub2api base URL. Set SUB2API_BASE_URL or provider workspaceId.";
35
+ return base;
36
+ }
37
+
38
+ function usageUrl(base) {
39
+ var path = base.replace(/^https?:\/\/[^/]+/, "");
40
+ if (/\/v1\/usage$/i.test(path)) return base;
41
+ if (/\/v1$/i.test(path)) return base + "/usage";
42
+ return base + "/v1/usage";
43
+ }
44
+
45
+ function number(value, fallback) {
46
+ if (typeof value === "number" && Number.isFinite(value)) return value;
47
+ if (typeof value === "string" && value.trim()) {
48
+ var parsed = Number(value.replace(/,/g, ""));
49
+ if (Number.isFinite(parsed)) return parsed;
50
+ }
51
+ return fallback === undefined ? null : fallback;
52
+ }
53
+
54
+ function percent(used, limit) {
55
+ return limit > 0 ? Math.max(0, Math.min(100, used / limit * 100)) : 0;
56
+ }
57
+
58
+ function money(value, unit) {
59
+ return String(unit || "USD").toUpperCase() === "USD" ? "$" + value.toFixed(2) : value.toFixed(2) + " " + unit;
60
+ }
61
+
62
+ function dateIso(ctx, value) {
63
+ return value ? ctx.util.toIso(value) : null;
64
+ }
65
+
66
+ function progress(ctx, label, used, limit, unit, minutes, reset) {
67
+ if (used === null || used < 0 || limit === null || limit < 0) throw "sub2api returned invalid " + label + " quota values.";
68
+ if (limit === 0) return ctx.line.text({ label: label, value: money(used, unit) + " used; no cap reported" });
69
+ var opts = {
70
+ label: label,
71
+ used: percent(used, limit),
72
+ limit: 100,
73
+ format: { kind: "percent" },
74
+ detail: money(used, unit) + " / " + money(limit, unit),
75
+ };
76
+ if (minutes) opts.periodDurationMs = minutes * 60 * 1000;
77
+ var iso = dateIso(ctx, reset);
78
+ if (iso) opts.resetsAt = iso;
79
+ return ctx.line.progress(opts);
80
+ }
81
+
82
+ function windowMinutes(window) {
83
+ switch (String(window || "").toLowerCase()) {
84
+ case "5h": return 5 * 60;
85
+ case "1d": return 24 * 60;
86
+ case "7d": return 7 * 24 * 60;
87
+ default: return null;
88
+ }
89
+ }
90
+
91
+ function windowTitle(window) {
92
+ switch (String(window || "").toLowerCase()) {
93
+ case "5h": return "5 hour limit";
94
+ case "1d": return "Daily limit";
95
+ case "7d": return "7 day limit";
96
+ default: return String(window || "Rate") + " limit";
97
+ }
98
+ }
99
+
100
+ function totalsLine(ctx, label, totals, unit) {
101
+ var requests = number(totals && totals.requests);
102
+ var tokens = number(totals && totals.total_tokens);
103
+ var cost = number(totals && totals.actual_cost);
104
+ if (requests === null || tokens === null || cost === null || requests < 0 || tokens < 0 || cost < 0) return null;
105
+ return ctx.line.text({
106
+ label: label,
107
+ value: requests + " requests, " + tokens + " tokens, " + money(cost, unit),
108
+ });
109
+ }
110
+
111
+ function probe(ctx) {
112
+ var key = apiKey(ctx);
113
+ if (!key) throw "Missing sub2api API key. Set SUB2API_API_KEY or provider apiKey.";
114
+ var url = usageUrl(baseUrl(ctx));
115
+ var sep = url.indexOf("?") >= 0 ? "&" : "?";
116
+ url += sep + "days=30&timezone=UTC";
117
+ var result = ctx.util.requestJson({
118
+ method: "GET",
119
+ url: url,
120
+ headers: { Authorization: "Bearer " + key, Accept: "application/json" },
121
+ timeoutMs: 15000,
122
+ });
123
+ if (ctx.util.isAuthStatus(result.resp.status)) throw "sub2api API key invalid or expired.";
124
+ if (result.resp.status < 200 || result.resp.status >= 300) throw "sub2api usage returned HTTP " + result.resp.status + ".";
125
+ var data = result.json;
126
+ if (!data || typeof data !== "object") throw "Could not parse sub2api usage.";
127
+ if (data.isValid === false) throw "sub2api API key invalid or expired.";
128
+
129
+ var unit = data.unit || (data.quota && data.quota.unit) || "USD";
130
+ var metrics = [];
131
+ if (data.subscription) {
132
+ var sub = data.subscription;
133
+ ["daily", "weekly", "monthly"].forEach(function (window, index) {
134
+ var used = number(sub[window + "_usage_usd"]);
135
+ var limit = number(sub[window + "_limit_usd"]);
136
+ var label = ["Daily", "Weekly", "Monthly"][index];
137
+ if (used === null) return;
138
+ if (used < 0) throw "sub2api returned negative usage.";
139
+ metrics.push(limit !== null ? progress(ctx, label, used, limit, unit, [1440, 10080, 43200][index], null)
140
+ : ctx.line.text({ label: label, value: money(used, unit) + " used" }));
141
+ });
142
+ if (number(data.balance) !== null) metrics.push(ctx.line.text({ label: "Balance", value: money(number(data.balance), unit) }));
143
+ } else if (data.quota) {
144
+ metrics.push(progress(ctx, "Quota", number(data.quota.used), number(data.quota.limit), data.quota.unit || unit, null, null));
145
+ } else if (Array.isArray(data.rate_limits) && data.rate_limits.length) {
146
+ var first = data.rate_limits[0];
147
+ metrics.push(progress(ctx, windowTitle(first.window), number(first.used), number(first.limit), unit, windowMinutes(first.window), first.reset_at));
148
+ } else if (data.balance !== undefined || data.remaining !== undefined) {
149
+ var balance = number(data.balance !== undefined ? data.balance : data.remaining);
150
+ if (balance === null) throw "sub2api returned an invalid balance.";
151
+ metrics.push(ctx.line.text({ label: "Balance", value: money(balance, unit) }));
152
+ } else {
153
+ metrics.push(ctx.line.badge({ label: "Status", text: "No quota data", color: "#a3a3a3" }));
154
+ }
155
+
156
+ if (Array.isArray(data.rate_limits)) {
157
+ var skipFirst = !data.quota && !data.subscription && data.rate_limits.length > 0;
158
+ for (var i = 0; i < data.rate_limits.length; i++) {
159
+ if (skipFirst && i === 0) continue;
160
+ var rl = data.rate_limits[i];
161
+ metrics.push(progress(ctx, windowTitle(rl.window), number(rl.used), number(rl.limit), unit, windowMinutes(rl.window), rl.reset_at));
162
+ }
163
+ }
164
+ if (data.usage && data.usage.today) {
165
+ var today = totalsLine(ctx, "Today", data.usage.today, unit);
166
+ if (today) {
167
+ metrics.push(today);
168
+ if (String(unit).toUpperCase() === "USD") {
169
+ try {
170
+ ctx.host.usageDaily.ingest({ source: "sub2api_api", daily: [{ date: ctx.nowIso.slice(0, 10),
171
+ costUsd: number(data.usage.today.actual_cost), totalTokens: number(data.usage.today.total_tokens) }] });
172
+ } catch (_) { ctx.host.log.warn("Could not persist sub2api daily usage"); }
173
+ }
174
+ }
175
+ }
176
+ if (data.usage && data.usage.total) {
177
+ var total = totalsLine(ctx, "Total", data.usage.total, unit);
178
+ if (total) metrics.push(total);
179
+ }
180
+ var expires = ctx.util.toIso(data.subscription && data.subscription.expires_at || data.expires_at);
181
+ if (expires) metrics.push(ctx.line.text({ label: "Expires", value: expires }));
182
+ if (!metrics.length) throw "sub2api returned no measurable quota or usage.";
183
+
184
+ var plan = clean(data.planName);
185
+ if (plan && data.mode && data.mode !== "unknown" && String(data.mode).toLowerCase() !== plan.toLowerCase()) plan += " (" + data.mode + ")";
186
+ else if (!plan && data.mode && data.mode !== "unknown") plan = data.mode;
187
+ return { displayName: "sub2api", source: "api", plan: plan, lines: metrics };
188
+ }
189
+
190
+ globalThis.__openusage_plugin = { id: "sub2api", probe: probe };
191
+ })();
@@ -0,0 +1,16 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "id": "sub2api",
4
+ "name": "sub2api",
5
+ "version": "0.1.0",
6
+ "entry": "plugin.js",
7
+ "enabledByDefault": false,
8
+ "supportedModes": [
9
+ "api"
10
+ ],
11
+ "autoMode": "api",
12
+ "envVars": [
13
+ "SUB2API_API_KEY",
14
+ "SUB2API_BASE_URL"
15
+ ]
16
+ }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,5 @@
1
+ <svg viewBox="0 0 32 32" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M16 3v26"/>
3
+ <path d="M7 6h14l4 4-4 4H7z"/>
4
+ <path d="M25 17H11l-4 4 4 4h14z"/>
5
+ </svg>
@@ -0,0 +1,47 @@
1
+ (function () {
2
+ function clean(value) { return typeof value === "string" && value.trim() ? value.trim() : null }
3
+ function number(value) {
4
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 0) throw "Invalid Wayfinder usage response."
5
+ return value
6
+ }
7
+ function probe(ctx) {
8
+ const settings = ctx.provider && ctx.provider.settings || {}
9
+ const base = ctx.host.http.validateBaseUrl(clean(settings.baseUrl) || clean(ctx.host.env.get("WAYFINDER_GATEWAY_URL")) || "http://127.0.0.1:8088", true)
10
+ function get(path, json) {
11
+ const resp = ctx.host.http.request({ method: "GET", url: base + path, timeoutMs: 5000 })
12
+ if (resp.status < 200 || resp.status >= 300) throw "Wayfinder gateway returned HTTP " + resp.status + "."
13
+ if (!json) return resp.bodyText
14
+ const data = ctx.util.tryParseJson(resp.bodyText)
15
+ if (!data || typeof data !== "object") throw "Invalid Wayfinder response."
16
+ return data
17
+ }
18
+ const health = get("/healthz", true)
19
+ const models = get("/router/models", true)
20
+ const savings = get("/v1/savings?period=30d", true)
21
+ if (typeof health.status !== "string" || !Array.isArray(models.models) || typeof savings.priced !== "boolean") throw "Incomplete Wayfinder response."
22
+ const lines = [
23
+ ctx.line.badge({ label: "Gateway", text: health.offline ? "Offline mode" : models.dry_run ? "Dry run" : health.status }),
24
+ ctx.line.text({ label: "Models", value: String(models.models.length) }),
25
+ ctx.line.text({ label: "Requests", value: String(number(savings.requests)), subtitle: "Last 30 days" }),
26
+ ctx.line.text({ label: "Tokens", value: String(number(savings.tokens)) }),
27
+ ]
28
+ if (number(savings.saved) > 0) {
29
+ lines.push(ctx.line.text({ label: "Saved", value: (savings.priced ? "$" + savings.saved.toFixed(4) + "; " : "") +
30
+ number(savings.saved_pct).toFixed(1) + "%", subtitle: "Compared with highest-cost route" }))
31
+ }
32
+ const routes = Object.keys(savings.by_route || {}).map((name) => ({
33
+ label: name, value: number(savings.by_route[name].requests),
34
+ })).sort((a, b) => b.value - a.value)
35
+ if (routes.length) lines.push(ctx.line.barChart({ label: "Routed requests", points: routes.slice(0, 20) }))
36
+ try {
37
+ const metrics = get("/metrics", false)
38
+ const sum = metrics.match(/^wayfinder_router_decision_latency_seconds_sum\s+([0-9.eE+-]+)(?:\s|$)/m)
39
+ const count = metrics.match(/^wayfinder_router_decision_latency_seconds_count\s+([0-9.eE+-]+)(?:\s|$)/m)
40
+ if (sum && count && number(Number(count[1])) > 0) {
41
+ lines.push(ctx.line.text({ label: "Avg decision", value: (number(Number(sum[1])) / Number(count[1]) * 1000).toFixed(1) + " ms" }))
42
+ }
43
+ } catch (_) { ctx.host.log.warn("Wayfinder latency unavailable") }
44
+ return { displayName: "Wayfinder", source: "local", lines }
45
+ }
46
+ globalThis.__openusage_plugin = { id: "wayfinder", probe }
47
+ })()
@@ -0,0 +1,16 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "id": "wayfinder",
4
+ "name": "Wayfinder",
5
+ "version": "0.1.0",
6
+ "entry": "plugin.js",
7
+ "enabledByDefault": false,
8
+ "envVars": [
9
+ "WAYFINDER_GATEWAY_URL"
10
+ ],
11
+ "supportedModes": [
12
+ "local"
13
+ ],
14
+ "autoMode": "local",
15
+ "usageDashboardUrl": "http://127.0.0.1:8088/router"
16
+ }
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,7 @@
1
+ <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
2
+ <g fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round">
3
+ <path d="M4.5 4.5l11 15"/>
4
+ <path d="M15.5 4.5l-11 15"/>
5
+ <path d="M20 4.5v15"/>
6
+ </g>
7
+ </svg>