@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,358 @@
1
+ (function () {
2
+ const CRED_PATH = "~/.kimi/credentials/kimi-code.json"
3
+ const USAGE_URL = "https://api.kimi.com/coding/v1/usages"
4
+ const REFRESH_URL = "https://auth.kimi.com/api/oauth/token"
5
+ const CLIENT_ID = "17e5f671-d194-4dfb-9706-5516cb48c098"
6
+ const REFRESH_BUFFER_SEC = 5 * 60
7
+
8
+ function readNumber(value) {
9
+ const n = Number(value)
10
+ return Number.isFinite(n) ? n : null
11
+ }
12
+
13
+ function titleCaseWords(value) {
14
+ return String(value)
15
+ .trim()
16
+ .toLowerCase()
17
+ .replace(/\b[a-z]/g, function (c) {
18
+ return c.toUpperCase()
19
+ })
20
+ }
21
+
22
+ function parsePlanLabel(data) {
23
+ const level =
24
+ data &&
25
+ data.user &&
26
+ data.user.membership &&
27
+ typeof data.user.membership.level === "string"
28
+ ? data.user.membership.level
29
+ : null
30
+ if (!level) return null
31
+
32
+ const cleaned = level.replace(/^LEVEL_/, "").replace(/_/g, " ")
33
+ const label = titleCaseWords(cleaned)
34
+ return label || null
35
+ }
36
+
37
+ function loadCredentials(ctx) {
38
+ if (!ctx.host.fs.exists(CRED_PATH)) {
39
+ ctx.host.log.warn("credentials file not found: " + CRED_PATH)
40
+ return null
41
+ }
42
+
43
+ try {
44
+ const text = ctx.host.fs.readText(CRED_PATH)
45
+ const parsed = ctx.util.tryParseJson(text)
46
+ if (!parsed || typeof parsed !== "object") {
47
+ ctx.host.log.warn("credentials file is not valid json")
48
+ return null
49
+ }
50
+ if (!parsed.access_token && !parsed.refresh_token) {
51
+ ctx.host.log.warn("credentials missing access_token and refresh_token")
52
+ return null
53
+ }
54
+ return parsed
55
+ } catch (e) {
56
+ ctx.host.log.warn("credentials read failed: " + String(e))
57
+ return null
58
+ }
59
+ }
60
+
61
+ function saveCredentials(ctx, creds) {
62
+ try {
63
+ ctx.host.fs.writeText(CRED_PATH, JSON.stringify(creds))
64
+ } catch (e) {
65
+ ctx.host.log.warn("failed to persist credentials: " + String(e))
66
+ }
67
+ }
68
+
69
+ function needsRefresh(creds, nowSec) {
70
+ if (!creds.access_token) return true
71
+ const expiresAt = readNumber(creds.expires_at)
72
+ if (expiresAt === null) return true
73
+ return nowSec + REFRESH_BUFFER_SEC >= expiresAt
74
+ }
75
+
76
+ function refreshToken(ctx, creds) {
77
+ if (!creds.refresh_token) {
78
+ ctx.host.log.warn("refresh skipped: no refresh token")
79
+ return null
80
+ }
81
+
82
+ ctx.host.log.info("attempting token refresh")
83
+ let resp
84
+ try {
85
+ resp = ctx.util.request({
86
+ method: "POST",
87
+ url: REFRESH_URL,
88
+ headers: {
89
+ "Content-Type": "application/x-www-form-urlencoded",
90
+ Accept: "application/json",
91
+ },
92
+ bodyText:
93
+ "client_id=" +
94
+ encodeURIComponent(CLIENT_ID) +
95
+ "&grant_type=refresh_token" +
96
+ "&refresh_token=" +
97
+ encodeURIComponent(creds.refresh_token),
98
+ timeoutMs: 15000,
99
+ })
100
+ } catch (e) {
101
+ ctx.host.log.error("refresh exception: " + String(e))
102
+ return null
103
+ }
104
+
105
+ if (ctx.util.isAuthStatus(resp.status)) {
106
+ throw "Session expired. Run `kimi login` to authenticate."
107
+ }
108
+
109
+ if (resp.status < 200 || resp.status >= 300) {
110
+ ctx.host.log.warn("refresh returned unexpected status: " + resp.status)
111
+ return null
112
+ }
113
+
114
+ const body = ctx.util.tryParseJson(resp.bodyText)
115
+ if (!body || !body.access_token) {
116
+ ctx.host.log.warn("refresh response missing access_token")
117
+ return null
118
+ }
119
+
120
+ creds.access_token = body.access_token
121
+ if (body.refresh_token) creds.refresh_token = body.refresh_token
122
+ if (typeof body.expires_in === "number") {
123
+ creds.expires_at = Date.now() / 1000 + body.expires_in
124
+ }
125
+ if (typeof body.scope === "string") creds.scope = body.scope
126
+ if (typeof body.token_type === "string") creds.token_type = body.token_type
127
+
128
+ saveCredentials(ctx, creds)
129
+ return creds.access_token
130
+ }
131
+
132
+ function fetchUsage(ctx, accessToken) {
133
+ return ctx.util.request({
134
+ method: "GET",
135
+ url: USAGE_URL,
136
+ headers: {
137
+ Authorization: "Bearer " + accessToken,
138
+ Accept: "application/json",
139
+ "User-Agent": "OpenUsage",
140
+ },
141
+ timeoutMs: 10000,
142
+ })
143
+ }
144
+
145
+ function parseWindowPeriodMs(window) {
146
+ if (!window || typeof window !== "object") return null
147
+ const duration = readNumber(window.duration)
148
+ if (duration === null || duration <= 0) return null
149
+
150
+ const unit = String(window.timeUnit || window.time_unit || "").toUpperCase()
151
+ if (unit.indexOf("MINUTE") !== -1) return duration * 60 * 1000
152
+ if (unit.indexOf("HOUR") !== -1) return duration * 60 * 60 * 1000
153
+ if (unit.indexOf("DAY") !== -1) return duration * 24 * 60 * 60 * 1000
154
+ if (unit.indexOf("SECOND") !== -1) return duration * 1000
155
+ return null
156
+ }
157
+
158
+ function parseQuota(row, ctx) {
159
+ if (!row || typeof row !== "object") return null
160
+
161
+ const limit = readNumber(row.limit)
162
+ if (limit === null || limit <= 0) return null
163
+
164
+ let used = readNumber(row.used)
165
+ if (used === null) {
166
+ const remaining = readNumber(row.remaining)
167
+ if (remaining !== null) {
168
+ used = limit - remaining
169
+ }
170
+ }
171
+ if (used === null) return null
172
+
173
+ return {
174
+ used,
175
+ limit,
176
+ resetsAt: ctx.util.toIso(row.resetTime || row.reset_at || row.resetAt || row.reset_time),
177
+ }
178
+ }
179
+
180
+ function toPercentUsage(quota) {
181
+ if (!quota || quota.limit <= 0) return null
182
+ const usedPercent = (quota.used / quota.limit) * 100
183
+ if (!Number.isFinite(usedPercent)) return null
184
+ return {
185
+ used: Math.round(Math.max(0, usedPercent) * 10) / 10,
186
+ limit: 100,
187
+ resetsAt: quota.resetsAt,
188
+ }
189
+ }
190
+
191
+ function collectLimitCandidates(ctx, data) {
192
+ const limits = Array.isArray(data && data.limits) ? data.limits : []
193
+ const out = []
194
+
195
+ for (let i = 0; i < limits.length; i += 1) {
196
+ const item = limits[i]
197
+ const detail = item && typeof item.detail === "object" ? item.detail : item
198
+ const quota = parseQuota(detail, ctx)
199
+ if (!quota) continue
200
+
201
+ const periodMs = parseWindowPeriodMs(item && item.window)
202
+ out.push({ quota, periodMs })
203
+ }
204
+
205
+ return out
206
+ }
207
+
208
+ function pickSessionCandidate(candidates) {
209
+ if (!candidates.length) return null
210
+ const sorted = candidates.slice().sort(function (a, b) {
211
+ const aKnown = typeof a.periodMs === "number"
212
+ const bKnown = typeof b.periodMs === "number"
213
+ if (aKnown && bKnown) return a.periodMs - b.periodMs
214
+ if (aKnown) return -1
215
+ if (bKnown) return 1
216
+ return 0
217
+ })
218
+ return sorted[0]
219
+ }
220
+
221
+ function pickLargestByPeriod(candidates) {
222
+ if (!candidates.length) return null
223
+ let best = candidates[0]
224
+ for (let i = 1; i < candidates.length; i += 1) {
225
+ const cur = candidates[i]
226
+ const curMs = typeof cur.periodMs === "number" ? cur.periodMs : -1
227
+ const bestMs = typeof best.periodMs === "number" ? best.periodMs : -1
228
+ if (curMs > bestMs) best = cur
229
+ }
230
+ return best
231
+ }
232
+
233
+ function sameQuota(a, b) {
234
+ if (!a || !b) return false
235
+ return (
236
+ a.quota.used === b.quota.used &&
237
+ a.quota.limit === b.quota.limit &&
238
+ (a.quota.resetsAt || null) === (b.quota.resetsAt || null)
239
+ )
240
+ }
241
+
242
+ function probe(ctx) {
243
+ const creds = loadCredentials(ctx)
244
+ if (!creds) {
245
+ throw "Not logged in. Run `kimi login` to authenticate."
246
+ }
247
+
248
+ const nowSec = Date.now() / 1000
249
+ let accessToken = creds.access_token || ""
250
+
251
+ if (needsRefresh(creds, nowSec)) {
252
+ const refreshed = refreshToken(ctx, creds)
253
+ if (refreshed) {
254
+ accessToken = refreshed
255
+ } else if (!accessToken) {
256
+ throw "Not logged in. Run `kimi login` to authenticate."
257
+ }
258
+ }
259
+
260
+ let didRefresh = false
261
+ let resp
262
+ try {
263
+ resp = ctx.util.retryOnceOnAuth({
264
+ request: function (token) {
265
+ return fetchUsage(ctx, token || accessToken)
266
+ },
267
+ refresh: function () {
268
+ didRefresh = true
269
+ const refreshed = refreshToken(ctx, creds)
270
+ if (refreshed) accessToken = refreshed
271
+ return refreshed
272
+ },
273
+ })
274
+ } catch (e) {
275
+ if (typeof e === "string") throw e
276
+ if (didRefresh) {
277
+ throw "Usage request failed after refresh. Try again."
278
+ }
279
+ throw "Usage request failed. Check your connection."
280
+ }
281
+
282
+ if (ctx.util.isAuthStatus(resp.status)) {
283
+ throw "Token expired. Run `kimi login` to authenticate."
284
+ }
285
+ if (resp.status < 200 || resp.status >= 300) {
286
+ throw "Usage request failed (HTTP " + String(resp.status) + "). Try again later."
287
+ }
288
+
289
+ const data = ctx.util.tryParseJson(resp.bodyText)
290
+ if (!data || typeof data !== "object") {
291
+ throw "Usage response invalid. Try again later."
292
+ }
293
+
294
+ const lines = []
295
+ const candidates = collectLimitCandidates(ctx, data)
296
+ const sessionCandidate = pickSessionCandidate(candidates)
297
+
298
+ let weeklyCandidate = null
299
+ const usageQuota = parseQuota(data.usage, ctx)
300
+ if (usageQuota) {
301
+ weeklyCandidate = { quota: usageQuota, periodMs: null }
302
+ } else {
303
+ const withoutSession = candidates.filter(function (candidate) {
304
+ return candidate !== sessionCandidate
305
+ })
306
+ weeklyCandidate = pickLargestByPeriod(withoutSession)
307
+ }
308
+
309
+ if (sessionCandidate) {
310
+ const sessionPercent = toPercentUsage(sessionCandidate.quota)
311
+ if (sessionPercent) {
312
+ lines.push(
313
+ ctx.line.progress({
314
+ label: "Session",
315
+ used: sessionPercent.used,
316
+ limit: sessionPercent.limit,
317
+ format: { kind: "percent" },
318
+ resetsAt: sessionPercent.resetsAt || undefined,
319
+ periodDurationMs:
320
+ typeof sessionCandidate.periodMs === "number"
321
+ ? sessionCandidate.periodMs
322
+ : undefined,
323
+ })
324
+ )
325
+ }
326
+ }
327
+
328
+ if (weeklyCandidate && !sameQuota(weeklyCandidate, sessionCandidate)) {
329
+ const weeklyPercent = toPercentUsage(weeklyCandidate.quota)
330
+ if (weeklyPercent) {
331
+ lines.push(
332
+ ctx.line.progress({
333
+ label: "Weekly",
334
+ used: weeklyPercent.used,
335
+ limit: weeklyPercent.limit,
336
+ format: { kind: "percent" },
337
+ resetsAt: weeklyPercent.resetsAt || undefined,
338
+ periodDurationMs:
339
+ typeof weeklyCandidate.periodMs === "number"
340
+ ? weeklyCandidate.periodMs
341
+ : undefined,
342
+ })
343
+ )
344
+ }
345
+ }
346
+
347
+ if (lines.length === 0) {
348
+ lines.push(ctx.line.badge({ label: "Status", text: "No usage data", color: "#a3a3a3" }))
349
+ }
350
+
351
+ return {
352
+ plan: parsePlanLabel(data),
353
+ lines,
354
+ }
355
+ }
356
+
357
+ globalThis.__openusage_plugin = { id: "kimi", probe }
358
+ })()
@@ -0,0 +1,15 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "id": "kimi",
4
+ "name": "Kimi",
5
+ "version": "0.0.1",
6
+ "entry": "plugin.js",
7
+ "icon": "icon.svg",
8
+ "brandColor": "#000000",
9
+ "supportedModes": ["oauth", "local"],
10
+ "autoMode": "oauth",
11
+ "lines": [
12
+ { "type": "progress", "label": "Session", "scope": "overview", "primaryOrder": 1 },
13
+ { "type": "progress", "label": "Weekly", "scope": "overview", "primaryOrder": 2 }
14
+ ]
15
+ }
@@ -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>Kimi</title><path d="M21.846 0a1.923 1.923 0 110 3.846H20.15a.226.226 0 01-.227-.226V1.923C19.923.861 20.784 0 21.846 0z" fill="#1783FF"></path><path d="M11.065 11.199l7.257-7.2c.137-.136.06-.41-.116-.41H14.3a.164.164 0 00-.117.051l-7.82 7.756c-.122.12-.302.013-.302-.179V3.82c0-.127-.083-.23-.185-.23H3.186c-.103 0-.186.103-.186.23V19.77c0 .128.083.23.186.23h2.69c.103 0 .186-.102.186-.23v-3.25c0-.069.025-.135.069-.178l2.424-2.406a.158.158 0 01.205-.023l6.484 4.772a7.677 7.677 0 003.453 1.283c.108.012.2-.095.2-.23v-3.06c0-.117-.07-.212-.164-.227a5.028 5.028 0 01-2.027-.807l-5.613-4.064c-.117-.078-.132-.279-.028-.381z" fill="#fff"></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>Kimi</title><path d="M21.846 0a1.923 1.923 0 110 3.846H20.15a.226.226 0 01-.227-.226V1.923C19.923.861 20.784 0 21.846 0z"></path><path d="M11.065 11.199l7.257-7.2c.137-.136.06-.41-.116-.41H14.3a.164.164 0 00-.117.051l-7.82 7.756c-.122.12-.302.013-.302-.179V3.82c0-.127-.083-.23-.185-.23H3.186c-.103 0-.186.103-.186.23V19.77c0 .128.083.23.186.23h2.69c.103 0 .186-.102.186-.23v-3.25c0-.069.025-.135.069-.178l2.424-2.406a.158.158 0 01.205-.023l6.484 4.772a7.677 7.677 0 003.453 1.283c.108.012.2-.095.2-.23v-3.06c0-.117-.07-.212-.164-.227a5.028 5.028 0 01-2.027-.807l-5.613-4.064c-.117-.078-.132-.279-.028-.381z"></path></svg>
@@ -0,0 +1,58 @@
1
+ (function () {
2
+ var API_URL = "https://api.moonshot.cn/v1/users/me/balance";
3
+
4
+ function loadApiKey(ctx) {
5
+ var names = ["MOONSHOT_API_KEY", "KIMI_API_KEY"];
6
+ for (var i = 0; i < names.length; i++) {
7
+ var v = ctx.host.env.get(names[i]);
8
+ if (typeof v === "string" && v.trim()) return v.trim();
9
+ }
10
+ return null;
11
+ }
12
+
13
+ function probe(ctx) {
14
+ var apiKey = loadApiKey(ctx);
15
+ if (!apiKey) {
16
+ throw "Kimi K2 / Moonshot API key not found. Set MOONSHOT_API_KEY or KIMI_API_KEY.";
17
+ }
18
+
19
+ var result = ctx.util.requestJson({
20
+ method: "GET",
21
+ url: API_URL,
22
+ headers: { Authorization: "Bearer " + apiKey, Accept: "application/json" },
23
+ timeoutMs: 30000,
24
+ });
25
+
26
+ if (ctx.util.isAuthStatus(result.resp.status)) {
27
+ throw "API key invalid or expired.";
28
+ }
29
+ if (result.resp.status < 200 || result.resp.status >= 300) {
30
+ throw "Kimi K2 API error (HTTP " + result.resp.status + ").";
31
+ }
32
+ if (!result.json) throw "Could not parse Kimi K2 balance response.";
33
+
34
+ var data = result.json.data || result.json;
35
+ var available = typeof data.available_balance === "number" ? data.available_balance
36
+ : typeof data.balance === "number" ? data.balance : 0;
37
+ var total = typeof data.total_balance === "number" ? data.total_balance
38
+ : typeof data.total === "number" ? data.total : 0;
39
+ var used = typeof data.used_balance === "number" ? data.used_balance
40
+ : typeof data.used === "number" ? data.used : Math.max(0, total - available);
41
+
42
+ var usedPct = total > 0 ? Math.min(100, (used / total) * 100) : 0;
43
+
44
+ var lines = [
45
+ ctx.line.progress({
46
+ label: "Credits",
47
+ used: usedPct,
48
+ limit: 100,
49
+ format: { kind: "percent" },
50
+ }),
51
+ ctx.line.text({ label: "Balance", value: available.toFixed(4) + " CNY remaining" }),
52
+ ];
53
+
54
+ return { lines: lines };
55
+ }
56
+
57
+ globalThis.__openusage_plugin = { id: "kimi-k2", probe: probe };
58
+ })();
@@ -0,0 +1,18 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "id": "kimi-k2",
4
+ "name": "Kimi K2",
5
+ "version": "0.0.1",
6
+ "entry": "plugin.js",
7
+ "brandColor": "#1A6EFF",
8
+ "links": [
9
+ { "label": "Platform", "url": "https://platform.moonshot.cn" }
10
+ ],
11
+ "usageDashboardUrl": "https://platform.moonshot.cn",
12
+ "supportedModes": ["api"],
13
+ "autoMode": "api",
14
+ "lines": [
15
+ { "type": "progress", "label": "Credits", "scope": "overview", "primaryOrder": 1 },
16
+ { "type": "text", "label": "Balance", "scope": "detail" }
17
+ ]
18
+ }
@@ -0,0 +1,5 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500">
2
+ <rect x="151.97" y="69.168" width="280.728" height="310.743" fill="#fff"/>
3
+ <path fill="#8845f4" fill-rule="nonzero" d="M166.827 19.829C135.251 21.699 107.072 40.278 92.913 68.571c-5.469 10.989-8.602 23-9.17 35.277-.152 2.653-.202 41.202-.152 120.737.051 109.873.102 117.022.392 119.687 1.427 11.747 4.092 20.866 8.93 30.592 8.589 17.316 22.684 31.299 40.064 39.761 9.473 4.699 19.047 7.452 30.288 8.74 2.868.341 9.726.341 122.366.341 112.981 0 119.448 0 122.366-.341 11.582-1.338 20.966-4.041 30.78-8.929 17.317-8.589 31.312-22.685 39.762-40.065 4.698-9.473 7.452-19.047 8.74-30.288.341-2.867.341-9.726.341-122.075 0-126.003.051-120.37-.884-126.685-3.6-24.693-17.468-46.708-38.195-60.602a69.461 69.461 0 0 0-9.562-5.621c-10.925-5.456-22.848-8.614-35.037-9.271-4.143-.252-232.871-.252-237.115 0Zm136.272 68.282c31.728 2.362 60.185 20.385 75.885 48.059 1.869 3.246 5.128 10.054 6.568 13.704 4.976 12.631 7.982 27.245 9.713 47.365.442 4.8.631 24.819.29 30.402-1.578 27.383-7.894 52.834-19.135 76.769a128.67 128.67 0 0 1-10.117 18.15c-11.747 16.483-29.303 29.455-43.955 32.461-11.304 2.324-20.234-1.263-25.867-10.445a42.032 42.032 0 0 1-3.158-6.669c-.442-1.226-.783-1.63-1.086-1.137-.038.101-1.137.947-2.413 1.932-11.999 9.12-25.513 14.841-38.637 16.332-3.448.379-10.849.29-13.704-.202-9.031-1.529-16.243-5.57-20.828-11.747a34.411 34.411 0 0 1-4.143-7.982c-1.477-4.547-1.97-10.269-1.477-15.498.682-6.947 2.854-14.955 6.113-22.306.24-.467.429-.972.543-1.478a24.767 24.767 0 0 0-1.731.695c-4.584 2.021-11.342 3.852-16.52 4.433-10.661 1.238-18.012-1.768-21.662-8.828-1.339-2.564-1.882-4.926-2.021-8.539-.101-3.296.101-5.431.834-8.285.745-2.905 1.528-4.636 5.09-11.242 4.825-9.094 6.214-11.948 8.033-17.026 4.143-11.355 6.063-21.762 8.69-47.415 1.869-18.555 3.208-27.03 5.469-34.936.354-1.137.985-3.499 1.44-5.23 10.054-38.826 39.319-65.464 77.653-70.744 1.629-.202 3.903-.505 5.04-.593 3.006-.202 12.125-.253 15.093 0Z"/>
4
+ <path fill="#8845f4" fill-rule="nonzero" d="M295.155 162.808c-1.794.48-3.436 1.427-4.737 2.766-2.223 2.274-3.701 5.57-4.496 10.155-.493 2.969-.733 7.604-.493 10.964.354 5.128 1.036 8.083 2.577 11.292 1.616 3.309 3.839 5.38 6.896 6.264 1.339.392 4.837.392 6.315 0 5.33-1.427 8.88-6.707 10.117-15.043.341-4.004.291-8.02-.151-11.999-.783-4.774-2.312-8.526-4.535-10.9-2.008-2.438-5.027-3.802-8.184-3.701-1.099-.114-2.223-.05-3.309.202Zm45.735-.101c-1.667.467-3.233 1.276-4.585 2.375-2.071 1.819-3.701 5.077-4.597 9.069-.632 2.905-.885 5.38-.885 9.384 0 4.042.253 6.454.885 9.372 1.389 6.265 4.446 10.206 8.689 11.342 1.529.392 4.787.392 6.316 0 5.077-1.326 8.589-6.315 9.864-14.02.442-2.501.594-8.184.303-10.988-.795-7.958-3.7-13.376-8.197-15.536a17.769 17.769 0 0 0-2.766-.998c-1.667-.252-3.36-.252-5.027 0Z"/>
5
+ </svg>
@@ -0,0 +1 @@
1
+ <svg width="17" height="16" viewBox="0 0 17 16" xmlns="http://www.w3.org/2000/svg" fill="currentColor"><path d="M8.74842 1C10.9904 0.997658 13.2522 2.35131 14.0873 4.98145L14.1635 5.24024L14.2631 5.65918C14.5302 6.92198 14.9273 10.1 13.1898 13.249L13.1888 13.25C12.6834 14.1641 11.7454 15.0605 10.7611 15.459C10.2633 15.6604 9.62658 15.7841 8.99744 15.5586C8.737 15.4652 8.51267 15.3237 8.32166 15.1465C7.29212 15.6815 6.13882 15.8407 5.18983 15.4424C4.52211 15.1621 3.99817 14.61 3.80799 13.8301C3.7494 13.5896 3.72834 13.3402 3.73572 13.084C3.20222 13.0354 2.72563 12.8114 2.39197 12.3281C2.12296 11.9385 2.05135 11.4999 2.06385 11.1397C2.07645 10.7768 2.17568 10.4166 2.33729 10.1113L2.34022 10.1064L2.62537 9.56934C2.69173 9.43932 2.7378 9.34011 2.77772 9.23438C2.93103 8.8105 2.97379 8.57168 3.04041 8.11328L3.04139 8.11133L3.08631 7.77051C3.12624 7.43395 3.15342 7.10561 3.19569 6.72657C3.24643 6.27143 3.31804 5.77596 3.46424 5.28809C4.13106 2.4575 6.43044 1.00258 8.74842 1ZM13.1986 5.50391C11.9212 0.832507 5.53387 0.824247 4.43494 5.52735C4.17712 6.35134 4.1734 7.28628 4.03065 8.25684L3.97694 8.59864C3.92246 8.91789 3.85695 9.19102 3.71717 9.57715C3.6061 9.87417 3.45901 10.1355 3.22108 10.5791L3.15858 10.7148C2.88165 11.4262 3.12847 12.5525 4.89881 11.9063L5.06776 11.8311C3.75892 14.732 6.55455 15.4597 8.61658 13.7607C9.18562 15.5472 11.2185 14.4089 12.1439 13.042L12.3138 12.7666C13.8864 9.9168 13.5268 7.01816 13.2875 5.87891L13.1986 5.50391Z"/><path d="M8.86245 7.52841C8.33877 7.52841 8.25943 6.90239 8.25943 6.52994C8.25943 6.19316 8.31894 5.92769 8.43399 5.75732C8.53317 5.60676 8.67996 5.53148 8.86245 5.53148C9.04495 5.53148 9.20364 5.60676 9.31472 5.76128C9.44167 5.93562 9.50912 6.20108 9.50912 6.52994C9.50912 7.15597 9.26711 7.52841 8.86642 7.52841H8.86245Z"/><path d="M11.0166 7.52841C10.4929 7.52841 10.4136 6.90239 10.4136 6.52994C10.4136 6.19316 10.4731 5.92769 10.5881 5.75732C10.6873 5.60676 10.8341 5.53148 11.0166 5.53148C11.1991 5.53148 11.3578 5.60676 11.4689 5.76128C11.5958 5.93562 11.6633 6.20108 11.6633 6.52994C11.6633 7.15597 11.4213 7.52841 11.0206 7.52841H11.0166Z"/></svg>
@@ -0,0 +1,4 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500">
2
+ <path fill="currentColor" fill-rule="nonzero" d="M166.827 19.829C135.251 21.699 107.072 40.278 92.913 68.571c-5.469 10.989-8.602 23-9.17 35.277-.152 2.653-.202 41.202-.152 120.737.051 109.873.102 117.022.392 119.687 1.427 11.747 4.092 20.866 8.93 30.592 8.589 17.316 22.684 31.299 40.064 39.761 9.473 4.699 19.047 7.452 30.288 8.74 2.868.341 9.726.341 122.366.341 112.981 0 119.448 0 122.366-.341 11.582-1.338 20.966-4.041 30.78-8.929 17.317-8.589 31.312-22.685 39.762-40.065 4.698-9.473 7.452-19.047 8.74-30.288.341-2.867.341-9.726.341-122.075 0-126.003.051-120.37-.884-126.685-3.6-24.693-17.468-46.708-38.195-60.602a69.461 69.461 0 0 0-9.562-5.621c-10.925-5.456-22.848-8.614-35.037-9.271-4.143-.252-232.871-.252-237.115 0Zm136.272 68.282c31.728 2.362 60.185 20.385 75.885 48.059 1.869 3.246 5.128 10.054 6.568 13.704 4.976 12.631 7.982 27.245 9.713 47.365.442 4.8.631 24.819.29 30.402-1.578 27.383-7.894 52.834-19.135 76.769a128.67 128.67 0 0 1-10.117 18.15c-11.747 16.483-29.303 29.455-43.955 32.461-11.304 2.324-20.234-1.263-25.867-10.445a42.032 42.032 0 0 1-3.158-6.669c-.442-1.226-.783-1.63-1.086-1.137-.038.101-1.137.947-2.413 1.932-11.999 9.12-25.513 14.841-38.637 16.332-3.448.379-10.849.29-13.704-.202-9.031-1.529-16.243-5.57-20.828-11.747a34.411 34.411 0 0 1-4.143-7.982c-1.477-4.547-1.97-10.269-1.477-15.498.682-6.947 2.854-14.955 6.113-22.306.24-.467.429-.972.543-1.478a24.767 24.767 0 0 0-1.731.695c-4.584 2.021-11.342 3.852-16.52 4.433-10.661 1.238-18.012-1.768-21.662-8.828-1.339-2.564-1.882-4.926-2.021-8.539-.101-3.296.101-5.431.834-8.285.745-2.905 1.528-4.636 5.09-11.242 4.825-9.094 6.214-11.948 8.033-17.026 4.143-11.355 6.063-21.762 8.69-47.415 1.869-18.555 3.208-27.03 5.469-34.936.354-1.137.985-3.499 1.44-5.23 10.054-38.826 39.319-65.464 77.653-70.744 1.629-.202 3.903-.505 5.04-.593 3.006-.202 12.125-.253 15.093 0Z"/>
3
+ <path fill="currentColor" fill-rule="nonzero" d="M295.155 162.808c-1.794.48-3.436 1.427-4.737 2.766-2.223 2.274-3.701 5.57-4.496 10.155-.493 2.969-.733 7.604-.493 10.964.354 5.128 1.036 8.083 2.577 11.292 1.616 3.309 3.839 5.38 6.896 6.264 1.339.392 4.837.392 6.315 0 5.33-1.427 8.88-6.707 10.117-15.043.341-4.004.291-8.02-.151-11.999-.783-4.774-2.312-8.526-4.535-10.9-2.008-2.438-5.027-3.802-8.184-3.701-1.099-.114-2.223-.05-3.309.202Zm45.735-.101c-1.667.467-3.233 1.276-4.585 2.375-2.071 1.819-3.701 5.077-4.597 9.069-.632 2.905-.885 5.38-.885 9.384 0 4.042.253 6.454.885 9.372 1.389 6.265 4.446 10.206 8.689 11.342 1.529.392 4.787.392 6.316 0 5.077-1.326 8.589-6.315 9.864-14.02.442-2.501.594-8.184.303-10.988-.795-7.958-3.7-13.376-8.197-15.536a17.769 17.769 0 0 0-2.766-.998c-1.667-.252-3.36-.252-5.027 0Z"/>
4
+ </svg>