@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,331 @@
1
+ (function () {
2
+ var API_URL = "https://www.codebuddy.cn/billing/meter/get-user-resource";
3
+ var ORIGIN = "https://www.codebuddy.cn";
4
+ var REFERER = "https://www.codebuddy.cn/profile/plans-usage";
5
+ var PRODUCT_CODE = "p_tcaca";
6
+ var USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36";
7
+ var MAX_RESPONSE_BYTES = 8 * 1024 * 1024;
8
+ var DEFAULT_PACKAGE_CODES = [
9
+ "TCACA_code_007_nzdH5h4Nl0",
10
+ "TCACA_code_029_6wCGEWquYy",
11
+ "TCACA_code_030_BjSt89qTvr",
12
+ "TCACA_code_008_cfWoLwvjU4",
13
+ "TCACA_code_002_AkiJS3ZHF5",
14
+ "TCACA_code_023_4xbGhMrE6q",
15
+ "TCACA_code_026_BaESVICNoi",
16
+ "TCACA_code_027_0FCGVA6vSa",
17
+ ];
18
+
19
+ function trim(value) {
20
+ return typeof value === "string" && value.trim() ? value.trim() : null;
21
+ }
22
+
23
+ function env(ctx, name) {
24
+ try {
25
+ return trim(ctx.host.env.get(name));
26
+ } catch (_) {
27
+ return null;
28
+ }
29
+ }
30
+
31
+ function setting(ctx, names) {
32
+ var settings = ctx.provider && ctx.provider.settings ? ctx.provider.settings : {};
33
+ for (var i = 0; i < names.length; i++) {
34
+ var value = trim(settings[names[i]]);
35
+ if (value) return value;
36
+ }
37
+ return null;
38
+ }
39
+
40
+ function normalizeCookie(raw) {
41
+ var header = trim(raw);
42
+ if (!header) return null;
43
+ header = header.replace(/^\uFEFF/, "").replace(/\^/g, "").trim();
44
+ if (header.slice(0, 7).toLowerCase() === "cookie:") header = header.slice(7).trim();
45
+ var pairs = [];
46
+ var chunks = header.split(";");
47
+ for (var i = 0; i < chunks.length; i++) {
48
+ var idx = chunks[i].indexOf("=");
49
+ if (idx < 0) continue;
50
+ var name = chunks[i].slice(0, idx).trim();
51
+ var value = chunks[i].slice(idx + 1).trim();
52
+ if (name && value) pairs.push(name + "=" + value);
53
+ }
54
+ return pairs.length ? pairs.join("; ") : null;
55
+ }
56
+
57
+ function codebuddyHome(ctx) {
58
+ return env(ctx, "CODEBUDDY_HOME") || (ctx.host.fs && ctx.host.fs.homeDir ? ctx.host.fs.homeDir + "/.codebuddy" : null);
59
+ }
60
+
61
+ function cookieFilePath(ctx) {
62
+ return env(ctx, "CB_COOKIE_FILE") || (codebuddyHome(ctx) ? codebuddyHome(ctx) + "/cb_cookie.txt" : null);
63
+ }
64
+
65
+ function creditsCachePath(ctx) {
66
+ return env(ctx, "CB_CREDITS_FILE") || (codebuddyHome(ctx) ? codebuddyHome(ctx) + "/cb_credits.json" : null);
67
+ }
68
+
69
+ function readTextIfExists(ctx, path) {
70
+ if (!path || !ctx.host.fs || !ctx.host.fs.exists(path)) return null;
71
+ return ctx.host.fs.readText(path);
72
+ }
73
+
74
+ function cookieHeader(ctx) {
75
+ var direct = normalizeCookie(ctx.provider && ctx.provider.cookieHeader) ||
76
+ normalizeCookie(setting(ctx, ["cookieHeader", "cookie"])) ||
77
+ normalizeCookie(env(ctx, "CODEBUDDY_COOKIE")) ||
78
+ normalizeCookie(env(ctx, "CB_COOKIE"));
79
+ if (direct) return direct;
80
+ return normalizeCookie(readTextIfExists(ctx, cookieFilePath(ctx)));
81
+ }
82
+
83
+ function apiUrl(ctx) {
84
+ var raw = setting(ctx, ["apiUrl", "apiBase"]) || env(ctx, "CB_API_URL") || API_URL;
85
+ return ctx.host.http.validateBaseUrl(raw, true);
86
+ }
87
+
88
+ function packageCodes(ctx) {
89
+ var raw = env(ctx, "CB_PACKAGE_CODES");
90
+ if (raw) {
91
+ try {
92
+ var parsed = JSON.parse(raw);
93
+ if (Array.isArray(parsed)) {
94
+ var out = [];
95
+ for (var i = 0; i < parsed.length && out.length < 64; i++) {
96
+ var code = trim(parsed[i]);
97
+ if (code && code.length <= 128 && !/[\x00-\x1f\x7f]/.test(code)) out.push(code);
98
+ }
99
+ if (out.length) return out;
100
+ }
101
+ } catch (_) {}
102
+ ctx.host.log.warn("CodeBuddy: CB_PACKAGE_CODES had no usable entries; using defaults");
103
+ }
104
+ return DEFAULT_PACKAGE_CODES;
105
+ }
106
+
107
+ function requestBody(ctx) {
108
+ return {
109
+ PageNumber: 1,
110
+ PageSize: 200,
111
+ ProductCode: PRODUCT_CODE,
112
+ Status: [0, 3],
113
+ OnlyValidPeriod: true,
114
+ PackageCodes: packageCodes(ctx),
115
+ };
116
+ }
117
+
118
+ function number(value) {
119
+ if (typeof value === "number" && Number.isFinite(value)) return value;
120
+ if (typeof value === "string" && value.trim()) {
121
+ var parsed = Number(value.replace(/,/g, ""));
122
+ if (Number.isFinite(parsed)) return parsed;
123
+ }
124
+ return null;
125
+ }
126
+
127
+ function valueFromKeys(obj, precise, fallback) {
128
+ var a = number(obj && obj[precise]);
129
+ return a !== null ? a : number(obj && obj[fallback]);
130
+ }
131
+
132
+ function parseDate(ctx, value) {
133
+ if (value === null || value === undefined || value === "") return null;
134
+ return ctx.util.toIso(value);
135
+ }
136
+
137
+ function expireTime(ctx, account) {
138
+ var keys = ["ExpireTime", "expireTime", "ExpireTimeStamp", "EndTime", "endTime", "ValidEndTime"];
139
+ for (var i = 0; i < keys.length; i++) {
140
+ var iso = parseDate(ctx, account && account[keys[i]]);
141
+ if (iso) return iso;
142
+ }
143
+ return null;
144
+ }
145
+
146
+ function normalizedTotals(total, used, remaining, reset) {
147
+ if (!Number.isFinite(total) || !Number.isFinite(used) || !Number.isFinite(remaining)) {
148
+ throw "CodeBuddy payload contains non-finite credit values.";
149
+ }
150
+ if (remaining > 0 && total > 0 && used <= 0) used = Math.max(0, total - remaining);
151
+ return {
152
+ total: Math.max(0, total),
153
+ used: Math.max(0, used),
154
+ remaining: remaining < 0 ? Math.max(0, total - used) : remaining,
155
+ resetsAt: reset,
156
+ };
157
+ }
158
+
159
+ function totalsFromPayload(ctx, value) {
160
+ var code = number(value && value.code);
161
+ if (code !== 0) {
162
+ var msg = String(value && value.msg || "unknown error");
163
+ if (/auth/i.test(msg) || msg.indexOf("登录") >= 0 || msg.indexOf("未登录") >= 0) throw { auth: true, message: "CodeBuddy login required." };
164
+ throw "CodeBuddy API code=" + code + ": " + msg;
165
+ }
166
+ var accounts = value && value.data && value.data.Response && value.data.Response.Data && value.data.Response.Data.Accounts;
167
+ if (!Array.isArray(accounts)) throw "CodeBuddy response missing data.Response.Data.Accounts.";
168
+ if (!accounts.length) throw "CodeBuddy returned zero packages. Set CB_PACKAGE_CODES from the browser cURL body.";
169
+ var total = 0;
170
+ var used = 0;
171
+ var remaining = 0;
172
+ var reset = null;
173
+ for (var i = 0; i < accounts.length; i++) {
174
+ var account = accounts[i] || {};
175
+ var capacity = valueFromKeys(account, "CapacitySizePrecise", "CapacitySize");
176
+ var consumed = valueFromKeys(account, "CapacityUsedPrecise", "CapacityUsed");
177
+ var available = valueFromKeys(account, "CapacityRemainPrecise", "CapacityRemain");
178
+ if (capacity === null || capacity < 0 || (consumed === null && available === null)) throw "CodeBuddy package is missing credit values.";
179
+ if (consumed === null) consumed = Math.max(0, capacity - available);
180
+ if (available === null) available = Math.max(0, capacity - consumed);
181
+ total += capacity;
182
+ used += consumed;
183
+ remaining += available;
184
+ var expiry = expireTime(ctx, account);
185
+ if (expiry && (!reset || expiry < reset)) reset = expiry;
186
+ }
187
+ return normalizedTotals(total, used, remaining, reset);
188
+ }
189
+
190
+ function totalsFromCache(ctx, cookie) {
191
+ var path = creditsCachePath(ctx);
192
+ var raw = readTextIfExists(ctx, path);
193
+ if (!raw) throw "No CodeBuddy cookie and no local cache at " + path + ".";
194
+ if (raw.length > 1024 * 1024) throw "CodeBuddy cache at " + path + " is too large.";
195
+ var value = ctx.util.tryParseJson(raw);
196
+ if (!value || typeof value !== "object") throw "Invalid CodeBuddy cache.";
197
+ if (cookie && value.accountHash !== ctx.host.crypto.sha256(cookie + "\n" + apiUrl(ctx))) throw "CodeBuddy cache belongs to different credentials.";
198
+ var updated = parseDate(ctx, value.updatedAt);
199
+ if (cookie && (!updated || Date.parse(ctx.nowIso) - Date.parse(updated) > 24 * 3600000 || Date.parse(updated) > Date.parse(ctx.nowIso))) throw "CodeBuddy cache is too old.";
200
+ var total = number(value.total);
201
+ if (total === null || total < 0) throw "cb_credits.json invalid total.";
202
+ var used = number(value.used);
203
+ var remaining = number(value.remaining);
204
+ if (used === null && remaining === null) throw "CodeBuddy cache is missing credit values.";
205
+ if (used === null) used = Math.max(0, total - remaining);
206
+ if (remaining === null) remaining = Math.max(0, total - used);
207
+ var totals = normalizedTotals(total, used, remaining, parseDate(ctx, value.resetsAt));
208
+ totals.fetchedAt = updated;
209
+ return totals;
210
+ }
211
+
212
+ function writeCache(ctx, totals, cookie) {
213
+ var path = creditsCachePath(ctx);
214
+ if (!path || !ctx.host.fs || typeof ctx.host.fs.writeText !== "function") return;
215
+ var value = {
216
+ total: totals.total,
217
+ used: totals.used,
218
+ remaining: totals.remaining,
219
+ source: "api",
220
+ updatedAt: ctx.nowIso,
221
+ accountHash: ctx.host.crypto.sha256(cookie + "\n" + apiUrl(ctx)),
222
+ };
223
+ if (totals.resetsAt) value.resetsAt = totals.resetsAt;
224
+ try {
225
+ ctx.host.fs.writeText(path, JSON.stringify(value, null, 2));
226
+ } catch (error) {
227
+ ctx.host.log.warn("CodeBuddy: failed to write local credits cache: " + String(error));
228
+ }
229
+ }
230
+
231
+ function looksLikeHtml(text) {
232
+ return /^\s*</.test(String(text || ""));
233
+ }
234
+
235
+ function fetchOnce(ctx, cookie) {
236
+ var resp = ctx.util.request({
237
+ method: "POST",
238
+ url: apiUrl(ctx),
239
+ headers: {
240
+ Cookie: cookie,
241
+ Accept: "application/json, text/plain, */*",
242
+ "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.7",
243
+ "Content-Type": "application/json",
244
+ Origin: ORIGIN,
245
+ Referer: REFERER,
246
+ "User-Agent": USER_AGENT,
247
+ "x-client-platform": "web",
248
+ "sec-fetch-dest": "empty",
249
+ "sec-fetch-mode": "cors",
250
+ "sec-fetch-site": "same-origin",
251
+ },
252
+ bodyText: JSON.stringify(requestBody(ctx)),
253
+ timeoutMs: 20000,
254
+ });
255
+ if (ctx.util.isAuthStatus(resp.status)) throw { auth: true, message: "CodeBuddy login required." };
256
+ if (resp.status === 429 || resp.status >= 500) throw { transient: true, message: "CodeBuddy temporary HTTP " + resp.status + "." };
257
+ if (resp.status < 200 || resp.status >= 300) throw "CodeBuddy get-user-resource returned HTTP " + resp.status + ".";
258
+ if ((resp.bodyText || "").length > MAX_RESPONSE_BYTES) throw "CodeBuddy response exceeds " + MAX_RESPONSE_BYTES + " bytes.";
259
+ if (looksLikeHtml(resp.bodyText)) throw { transient: true, message: "CodeBuddy WAF/HTML response." };
260
+ var json = ctx.util.tryParseJson(resp.bodyText);
261
+ if (!json) throw { transient: true, message: "Failed to parse CodeBuddy response." };
262
+ return totalsFromPayload(ctx, json);
263
+ }
264
+
265
+ function fetchWeb(ctx, cookie) {
266
+ var last = null;
267
+ for (var attempt = 0; attempt < 2; attempt++) {
268
+ try {
269
+ var totals = fetchOnce(ctx, cookie);
270
+ writeCache(ctx, totals, cookie);
271
+ return { totals: totals, source: "web" };
272
+ } catch (error) {
273
+ if (error && error.transient && attempt === 0) {
274
+ last = error;
275
+ continue;
276
+ }
277
+ throw error;
278
+ }
279
+ }
280
+ throw last || "CodeBuddy fetch failed.";
281
+ }
282
+
283
+ function formatNumber(value) {
284
+ var rounded = Math.round(value * 100) / 100;
285
+ var text = Math.abs(rounded - Math.round(rounded)) < 0.001 ? String(Math.round(rounded)) : rounded.toFixed(2).replace(/\.?0+$/, "");
286
+ return text.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
287
+ }
288
+
289
+ function resultFromTotals(ctx, totals, source) {
290
+ var percent = totals.total > 0 ? totals.used / totals.total * 100 : totals.used > 0 ? 100 : 0;
291
+ var detail = formatNumber(totals.remaining) + " / " + formatNumber(totals.total) + " left";
292
+ var opts = {
293
+ label: "Credits",
294
+ used: Math.max(0, Math.min(100, percent)),
295
+ limit: 100,
296
+ format: { kind: "percent" },
297
+ detail: detail,
298
+ };
299
+ if (totals.resetsAt) opts.resetsAt = totals.resetsAt;
300
+ return { displayName: "CodeBuddy", source: source, fetchedAt: totals.fetchedAt || ctx.nowIso, plan: "CodeBuddy CN", lines: [ctx.line.progress(opts)] };
301
+ }
302
+
303
+ function probe(ctx) {
304
+ if (ctx.sourceMode === "local" || ctx.sourceMode === "cli") {
305
+ return resultFromTotals(ctx, totalsFromCache(ctx), "local");
306
+ }
307
+ var cookie = cookieHeader(ctx);
308
+ if (!cookie) {
309
+ try {
310
+ return resultFromTotals(ctx, totalsFromCache(ctx), "local");
311
+ } catch (_) {
312
+ throw "CodeBuddy session not configured. Set CODEBUDDY_COOKIE, CB_COOKIE, provider cookieHeader, or ~/.codebuddy/cb_cookie.txt.";
313
+ }
314
+ }
315
+ try {
316
+ var fetched = fetchWeb(ctx, cookie);
317
+ return resultFromTotals(ctx, fetched.totals, fetched.source);
318
+ } catch (error) {
319
+ if (error && error.auth) throw error.message;
320
+ if (error && error.transient) {
321
+ try {
322
+ return resultFromTotals(ctx, totalsFromCache(ctx, cookie), "cached");
323
+ } catch (_) {}
324
+ throw error.message;
325
+ }
326
+ throw error;
327
+ }
328
+ }
329
+
330
+ globalThis.__openusage_plugin = { id: "codebuddy", probe: probe };
331
+ })();
@@ -0,0 +1,30 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "id": "codebuddy",
4
+ "name": "CodeBuddy",
5
+ "version": "0.1.0",
6
+ "entry": "plugin.js",
7
+ "enabledByDefault": false,
8
+ "supportedModes": [
9
+ "web",
10
+ "local"
11
+ ],
12
+ "autoMode": "web",
13
+ "webUrl": "https://www.codebuddy.cn",
14
+ "usageDashboardUrl": "https://www.codebuddy.cn/profile/plans-usage",
15
+ "links": [
16
+ {
17
+ "label": "Dashboard",
18
+ "url": "https://www.codebuddy.cn/profile/plans-usage"
19
+ }
20
+ ],
21
+ "envVars": [
22
+ "CODEBUDDY_HOME",
23
+ "CB_COOKIE_FILE",
24
+ "CB_CREDITS_FILE",
25
+ "CODEBUDDY_COOKIE",
26
+ "CB_COOKIE",
27
+ "CB_API_URL",
28
+ "CB_PACKAGE_CODES"
29
+ ]
30
+ }
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -691,6 +691,7 @@
691
691
  let didReloadAuth = false
692
692
  try {
693
693
  resp = ctx.util.retryOnceOnAuth({
694
+ isAuthStatus: (status) => status === 401,
694
695
  request: (token) => {
695
696
  try {
696
697
  return fetchUsage(ctx, token || accessToken, accountId)
@@ -727,7 +728,7 @@
727
728
  throw ERR_USAGE_CONNECTION
728
729
  }
729
730
 
730
- if (didReloadAuth && ctx.util.isAuthStatus(resp.status)) {
731
+ if (didReloadAuth && resp.status === 401) {
731
732
  ctx.host.log.info("reloaded auth returned 401, attempting refresh")
732
733
  didRefresh = true
733
734
  const refreshed = refreshToken(ctx, authState)
@@ -741,11 +742,15 @@
741
742
  }
742
743
  }
743
744
 
744
- if (ctx.util.isAuthStatus(resp.status)) {
745
+ if (resp.status === 401) {
745
746
  ctx.host.log.error("usage returned auth error after all retries: status=" + resp.status)
746
747
  throw ERR_TOKEN_EXPIRED
747
748
  }
748
749
 
750
+ if (resp.status === 403) {
751
+ throw "Codex usage access denied (HTTP 403). Check this account's permissions."
752
+ }
753
+
749
754
  if (resp.status < 200 || resp.status >= 300) {
750
755
  ctx.host.log.error("usage returned error: status=" + resp.status)
751
756
  throw "Usage request failed (HTTP " + String(resp.status) + "). Try again later."
File without changes
File without changes
@@ -5,6 +5,11 @@
5
5
 
6
6
  var PLAN_LABELS = {
7
7
  "individual-go": "Individual Go",
8
+ "individual-goat": "GOAT",
9
+ "individual-pro": "Pro",
10
+ "individual-pro-v1": "Pro",
11
+ "individual-max": "Max",
12
+ "individual-ultra": "Ultra",
8
13
  "individual": "Individual",
9
14
  "pro": "Pro",
10
15
  "team": "Team",
@@ -12,6 +17,8 @@
12
17
  };
13
18
 
14
19
  function readNumber(value) {
20
+ if (typeof value !== "number" && typeof value !== "string") return null;
21
+ if (typeof value === "string" && !value.trim()) return null;
15
22
  var n = Number(value);
16
23
  return Number.isFinite(n) ? n : null;
17
24
  }
File without changes
File without changes
File without changes
@@ -526,16 +526,18 @@
526
526
  }
527
527
 
528
528
  function makeProgressLine(ctx, label, snapshot, resetDate) {
529
- if (!snapshot || typeof snapshot.percent_remaining !== "number")
530
- return null;
531
- const usedPercent = Math.min(100, Math.max(0, 100 - snapshot.percent_remaining));
529
+ if (!snapshot || snapshot.unlimited === true || snapshot.entitlement === -1 || snapshot.remaining === -1 || snapshot.entitlement === 0) return null;
530
+ let percentRemaining = snapshot.percent_remaining;
531
+ if (!Number.isFinite(percentRemaining) && Number.isFinite(snapshot.entitlement) && snapshot.entitlement > 0 && Number.isFinite(snapshot.remaining)) percentRemaining = snapshot.remaining / snapshot.entitlement * 100;
532
+ if (!Number.isFinite(percentRemaining)) return null;
533
+ const usedPercent = Math.min(100, Math.max(0, 100 - percentRemaining));
532
534
  return ctx.line.progress({
533
535
  label: label,
534
536
  used: usedPercent,
535
537
  limit: 100,
536
538
  format: { kind: "percent" },
537
539
  resetsAt: ctx.util.toIso(resetDate),
538
- periodDurationMs: 30 * 24 * 60 * 60 * 1000,
540
+ periodDurationMs: calendarMonthDuration(ctx, resetDate),
539
541
  });
540
542
  }
541
543
 
@@ -550,10 +552,43 @@
550
552
  limit: 100,
551
553
  format: { kind: "percent" },
552
554
  resetsAt: ctx.util.toIso(resetDate),
553
- periodDurationMs: 30 * 24 * 60 * 60 * 1000,
555
+ periodDurationMs: calendarMonthDuration(ctx, resetDate),
554
556
  });
555
557
  }
556
558
 
559
+ function calendarMonthDuration(ctx, resetDate) {
560
+ const end = ctx.util.parseDateMs(resetDate);
561
+ if (!Number.isFinite(end)) return undefined;
562
+ const start = new Date(end);
563
+ start.setUTCMonth(start.getUTCMonth() - 1);
564
+ return end - start.getTime();
565
+ }
566
+
567
+ function fetchOrgBillingLines(ctx, token) {
568
+ const deadline = Date.now() + 3000;
569
+ function get(path) {
570
+ const remaining = deadline - Date.now();
571
+ if (remaining <= 0) return null;
572
+ const result = ctx.util.requestJson({ method: "GET", url: "https://api.github.com" + path,
573
+ headers: { Authorization: "token " + token, Accept: "application/vnd.github+json", "User-Agent": "usagestat", "X-GitHub-Api-Version": "2022-11-28" }, timeoutMs: remaining });
574
+ return result.resp.status === 200 ? result.json : null;
575
+ }
576
+ const selected = ctx.provider && ctx.provider.workspaceId;
577
+ const orgs = selected ? [{ login: selected }] : get("/user/orgs?per_page=100");
578
+ if (!Array.isArray(orgs)) return [];
579
+ const result = [];
580
+ for (const org of orgs.slice(0, 5)) {
581
+ if (!org || typeof org.login !== "string" || !/^[a-zA-Z0-9][a-zA-Z0-9-]*$/.test(org.login)) continue;
582
+ const body = get("/orgs/" + encodeURIComponent(org.login) + "/settings/billing/usage/summary");
583
+ if (!body || !Array.isArray(body.usageItems)) continue;
584
+ const items = body.usageItems.filter((item) => item && String(item.product).toLowerCase() === "copilot" && ["ai-units", "ai-credits"].includes(String(item.unitType).toLowerCase()));
585
+ if (!items.length || items.some((item) => !Number.isFinite(item.grossQuantity) || item.grossQuantity < 0 || !Number.isFinite(item.netAmount) || item.netAmount < 0)) continue;
586
+ result.push(ctx.line.text({ label: "Org Credits", value: String(items.reduce((n, item) => n + item.grossQuantity, 0)) + " credits", subtitle: org.login + " - organization total" }));
587
+ result.push(ctx.line.text({ label: "Org Spend", value: "$" + items.reduce((n, item) => n + item.netAmount, 0).toFixed(2), subtitle: org.login + " - this month" }));
588
+ }
589
+ return result;
590
+ }
591
+
557
592
  function probe(ctx) {
558
593
  const cred = loadToken(ctx);
559
594
  if (!cred) {
@@ -630,11 +665,15 @@
630
665
  if (snapshots) {
631
666
  const premiumLine = makeProgressLine(
632
667
  ctx,
633
- "Premium",
668
+ "Credits",
634
669
  snapshots.premium_interactions,
635
670
  data.quota_reset_date,
636
671
  );
637
- if (premiumLine) lines.push(premiumLine);
672
+ if (premiumLine) {
673
+ lines.push(premiumLine);
674
+ const premium = snapshots.premium_interactions;
675
+ if (premium.overage_permitted === true && Number.isFinite(premium.overage_count) && premium.overage_count >= 0) lines.push(ctx.line.text({ label: "Extra Usage", value: String(premium.overage_count) }));
676
+ }
638
677
 
639
678
  const chatLine = makeProgressLine(
640
679
  ctx,
@@ -643,10 +682,12 @@
643
682
  data.quota_reset_date,
644
683
  );
645
684
  if (chatLine) lines.push(chatLine);
685
+ const completionsLine = makeProgressLine(ctx, "Completions", snapshots.completions, data.quota_reset_date);
686
+ if (completionsLine) lines.push(completionsLine);
646
687
  }
647
688
 
648
689
  // Free tier: limited_user_quotas
649
- if (data.limited_user_quotas && data.monthly_quotas) {
690
+ if (!lines.length && data.limited_user_quotas && data.monthly_quotas) {
650
691
  const lq = data.limited_user_quotas;
651
692
  const mq = data.monthly_quotas;
652
693
  const resetDate = data.limited_user_reset_date;
@@ -658,6 +699,17 @@
658
699
  if (completionsLine) lines.push(completionsLine);
659
700
  }
660
701
 
702
+ const orgManaged = !lines.length && data.token_based_billing === true;
703
+ if (orgManaged) {
704
+ const credits = snapshots && snapshots.premium_interactions && snapshots.premium_interactions.credits_used;
705
+ if (Number.isFinite(credits) && credits > 0) lines.push(ctx.line.text({ label: "Credits", value: String(credits) + " credits" }));
706
+ try {
707
+ lines.push(...fetchOrgBillingLines(ctx, token));
708
+ } catch (_) {
709
+ ctx.host.log.warn("Copilot organization billing unavailable for this token");
710
+ }
711
+ }
712
+
661
713
  try {
662
714
  const budgetLines = fetchBudgetLines(ctx);
663
715
  for (let i = 0; i < budgetLines.length; i += 1) {
@@ -677,7 +729,7 @@
677
729
  );
678
730
  }
679
731
 
680
- return { plan: plan, lines: lines };
732
+ return { plan: plan, lines: lines, source: "api" };
681
733
  }
682
734
 
683
735
  globalThis.__openusage_plugin = { id: "copilot", probe };
@@ -9,7 +9,10 @@
9
9
  "supportedModes": ["oauth", "local", "cli"],
10
10
  "autoMode": "local",
11
11
  "lines": [
12
- { "type": "progress", "label": "Premium", "scope": "overview", "primaryOrder": 1 },
12
+ { "type": "progress", "label": "Credits", "scope": "overview", "primaryOrder": 1 },
13
+ { "type": "text", "label": "Extra Usage", "scope": "detail" },
14
+ { "type": "text", "label": "Org Credits", "scope": "detail" },
15
+ { "type": "text", "label": "Org Spend", "scope": "detail" },
13
16
  { "type": "progress", "label": "Chat", "scope": "overview", "primaryOrder": 2 },
14
17
  { "type": "progress", "label": "Completions", "scope": "overview" },
15
18
  { "type": "progress", "label": "Budget - Copilot", "scope": "detail" },
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes