@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,313 @@
1
+ (function () {
2
+ var QUOTA_FILENAME = "AIAssistantQuotaManager2.xml"
3
+
4
+ // JetBrains stores AI quota in 1e-5 credit units; divide by this to get credits.
5
+ var CREDIT_UNIT_SCALE = 100000
6
+
7
+ var PRODUCT_PREFIXES = [
8
+ "Aqua",
9
+ "AndroidStudio",
10
+ "CLion",
11
+ "DataGrip",
12
+ "DataSpell",
13
+ "GoLand",
14
+ "IdeaIC",
15
+ "IntelliJIdea",
16
+ "IntelliJIdeaCE",
17
+ "PhpStorm",
18
+ "PyCharm",
19
+ "PyCharmCE",
20
+ "Rider",
21
+ "RubyMine",
22
+ "RustRover",
23
+ "WebStorm",
24
+ "Writerside",
25
+ ]
26
+
27
+ function platformBaseDirs(ctx) {
28
+ var root = ctx.host.fs.appSupportPath("JetBrains")
29
+ if (!root) throw {code: "failed", message: "JetBrains configuration directory unavailable. Set settings.configDir to the IDE configuration directory."}
30
+ return [root]
31
+ }
32
+
33
+ function isLikelyIdeDirName(name) {
34
+ if (typeof name !== "string") return false
35
+ var trimmed = name.trim()
36
+ if (!trimmed) return false
37
+ var hasPrefix = false
38
+ for (var i = 0; i < PRODUCT_PREFIXES.length; i += 1) {
39
+ if (trimmed.indexOf(PRODUCT_PREFIXES[i]) === 0) {
40
+ hasPrefix = true
41
+ break
42
+ }
43
+ }
44
+ if (!hasPrefix) return false
45
+ return /\d{4}\.\d/.test(trimmed)
46
+ }
47
+
48
+ function safeListDir(ctx, path) {
49
+ if (
50
+ !ctx.host.fs ||
51
+ typeof ctx.host.fs.listDir !== "function" ||
52
+ !ctx.host.fs.exists(path)
53
+ ) {
54
+ return []
55
+ }
56
+
57
+ try {
58
+ var entries = ctx.host.fs.listDir(path)
59
+ return Array.isArray(entries) ? entries : []
60
+ } catch (e) {
61
+ ctx.host.log.warn("listDir failed for " + path + ": " + String(e))
62
+ return []
63
+ }
64
+ }
65
+
66
+ function buildQuotaPaths(ctx) {
67
+ var settings = (ctx.provider && ctx.provider.settings) || {}
68
+ if (typeof settings.configDir === "string" && settings.configDir) {
69
+ var explicit = settings.configDir.replace(/[\\/]+$/, "") + "/options/" + QUOTA_FILENAME
70
+ return ctx.host.fs.exists(explicit) ? [explicit] : []
71
+ }
72
+ var bases = platformBaseDirs(ctx)
73
+ var paths = []
74
+ var seen = Object.create(null)
75
+ for (var b = 0; b < bases.length; b += 1) {
76
+ var base = bases[b]
77
+ var entries = safeListDir(ctx, base)
78
+ for (var i = 0; i < entries.length; i += 1) {
79
+ var dirName = entries[i]
80
+ if (!isLikelyIdeDirName(dirName)) continue
81
+ var quotaPath = base + "/" + dirName + "/options/" + QUOTA_FILENAME
82
+ if (!ctx.host.fs.exists(quotaPath)) continue
83
+ if (!seen[quotaPath]) {
84
+ seen[quotaPath] = true
85
+ paths.push(quotaPath)
86
+ }
87
+ }
88
+ }
89
+ return paths
90
+ }
91
+
92
+ function decodeXmlEntities(text) {
93
+ if (!text) return ""
94
+ return String(text)
95
+ .replace(/&#10;/g, "\n")
96
+ .replace(/&#13;/g, "\r")
97
+ .replace(/&quot;/g, '"')
98
+ .replace(/&apos;/g, "'")
99
+ .replace(/&lt;/g, "<")
100
+ .replace(/&gt;/g, ">")
101
+ .replace(/&amp;/g, "&")
102
+ }
103
+
104
+ function parseOptionJson(ctx, xml, optionName) {
105
+ var elemMatch = xml.match(new RegExp('<option\\b[^>]*\\bname="' + optionName + '"[^>]*/>'))
106
+ if (!elemMatch) return null
107
+ var valueMatch = elemMatch[0].match(/\bvalue="([^"]*)"/)
108
+ if (!valueMatch) return null
109
+ return ctx.util.tryParseJson(decodeXmlEntities(valueMatch[1]))
110
+ }
111
+
112
+ function toNumber(value) {
113
+ var n = Number(value)
114
+ return Number.isFinite(n) ? n : null
115
+ }
116
+
117
+ function clamp(value, min, max) {
118
+ if (value < min) return min
119
+ if (value > max) return max
120
+ return value
121
+ }
122
+
123
+ function normalizeQuota(quotaInfo) {
124
+ if (!quotaInfo || typeof quotaInfo !== "object") return null
125
+
126
+ var maximum = toNumber(quotaInfo.maximum)
127
+ var used = toNumber(quotaInfo.current)
128
+ var remaining = toNumber(quotaInfo.available)
129
+
130
+ var tariff = quotaInfo.tariffQuota && typeof quotaInfo.tariffQuota === "object"
131
+ ? quotaInfo.tariffQuota
132
+ : null
133
+ var topUp = quotaInfo.topUpQuota && typeof quotaInfo.topUpQuota === "object"
134
+ ? quotaInfo.topUpQuota
135
+ : null
136
+
137
+ if (maximum === null) {
138
+ var tariffMaximum = tariff ? toNumber(tariff.maximum) : null
139
+ var topUpMaximum = topUp ? toNumber(topUp.maximum) : null
140
+ if (tariffMaximum !== null || topUpMaximum !== null) {
141
+ maximum = (tariffMaximum !== null ? tariffMaximum : 0) + (topUpMaximum !== null ? topUpMaximum : 0)
142
+ }
143
+ }
144
+
145
+ if (used === null) {
146
+ var tariffUsed = tariff ? toNumber(tariff.current) : null
147
+ var topUpUsed = topUp ? toNumber(topUp.current) : null
148
+ if (tariffUsed !== null || topUpUsed !== null) {
149
+ used = (tariffUsed !== null ? tariffUsed : 0) + (topUpUsed !== null ? topUpUsed : 0)
150
+ }
151
+ }
152
+
153
+ if (remaining === null) {
154
+ var tariffRemaining = tariff ? toNumber(tariff.available) : null
155
+ var topUpRemaining = topUp ? toNumber(topUp.available) : null
156
+ if (tariffRemaining !== null || topUpRemaining !== null) {
157
+ remaining = (tariffRemaining !== null ? tariffRemaining : 0) + (topUpRemaining !== null ? topUpRemaining : 0)
158
+ }
159
+ }
160
+
161
+ if (remaining === null && maximum !== null && used !== null) {
162
+ remaining = maximum - used
163
+ }
164
+
165
+ if (maximum === null || maximum <= 0 || used === null) return null
166
+
167
+ used = clamp(used, 0, maximum)
168
+ if (remaining !== null) remaining = clamp(remaining, 0, maximum)
169
+
170
+ return {
171
+ used: used,
172
+ maximum: maximum,
173
+ remaining: remaining,
174
+ until: quotaInfo.until || null,
175
+ }
176
+ }
177
+
178
+ function readQuotaState(ctx, path) {
179
+ if (!ctx.host.fs.exists(path)) return null
180
+ try {
181
+ var xml = ctx.host.fs.readText(path)
182
+ var quotaInfo = parseOptionJson(ctx, xml, "quotaInfo")
183
+ var nextRefill = parseOptionJson(ctx, xml, "nextRefill")
184
+ var quota = normalizeQuota(quotaInfo)
185
+ if (!quota) return null
186
+ return { path: path, quota: quota, nextRefill: nextRefill }
187
+ } catch (e) {
188
+ ctx.host.log.warn("failed reading quota state " + path + ": " + String(e))
189
+ return null
190
+ }
191
+ }
192
+
193
+ // Handles only simple single-component durations (PTnH, PnD, PnW).
194
+ // JetBrains currently uses values like PT720H or P30D.
195
+ function parseIsoDurationMs(value) {
196
+ if (typeof value !== "string" || !value) return null
197
+
198
+ var h = value.match(/^PT(\d+)H$/)
199
+ if (h) return Number(h[1]) * 60 * 60 * 1000
200
+
201
+ var d = value.match(/^P(\d+)D$/)
202
+ if (d) return Number(d[1]) * 24 * 60 * 60 * 1000
203
+
204
+ var w = value.match(/^P(\d+)W$/)
205
+ if (w) return Number(w[1]) * 7 * 24 * 60 * 60 * 1000
206
+
207
+ return null
208
+ }
209
+
210
+ function formatDecimal(value, places) {
211
+ if (!Number.isFinite(value)) return null
212
+ var factor = Math.pow(10, places)
213
+ var rounded = Math.round(value * factor) / factor
214
+ return rounded.toFixed(places).replace(/\.?0+$/, "")
215
+ }
216
+
217
+ function detectDisplayScale(quota, nextRefill) {
218
+ var maxAbs = Math.max(
219
+ Math.abs(quota.maximum || 0),
220
+ Math.abs(quota.used || 0),
221
+ Math.abs(quota.remaining || 0)
222
+ )
223
+
224
+ if (nextRefill && nextRefill.tariff && typeof nextRefill.tariff === "object") {
225
+ var tariffAmount = toNumber(nextRefill.tariff.amount)
226
+ if (tariffAmount !== null) {
227
+ maxAbs = Math.max(maxAbs, Math.abs(tariffAmount))
228
+ }
229
+ }
230
+
231
+ if (maxAbs >= CREDIT_UNIT_SCALE) return CREDIT_UNIT_SCALE
232
+ return 1
233
+ }
234
+
235
+ function probe(ctx) {
236
+ var paths = buildQuotaPaths(ctx)
237
+ var states = []
238
+
239
+ for (var i = 0; i < paths.length; i += 1) {
240
+ var state = readQuotaState(ctx, paths[i])
241
+ if (state) states.push(state)
242
+ }
243
+
244
+ if (states.length === 0) {
245
+ throw paths.length > 0
246
+ ? "JetBrains AI Assistant quota data unavailable. Open AI Assistant once and try again."
247
+ : "JetBrains AI Assistant not detected. Open a JetBrains IDE with AI Assistant enabled."
248
+ }
249
+
250
+ if (states.length > 1) {
251
+ throw {code: "failed", message: "Multiple JetBrains IDE quota profiles found. Select settings.configDir to choose one installation."}
252
+ }
253
+ var chosen = states[0]
254
+ var quota = chosen.quota
255
+ var scale = detectDisplayScale(quota, chosen.nextRefill)
256
+ var usedPercent = (quota.used / quota.maximum) * 100
257
+ if (!Number.isFinite(usedPercent)) usedPercent = 0
258
+ usedPercent = clamp(usedPercent, 0, 100)
259
+ var line = {
260
+ label: "Quota",
261
+ used: usedPercent,
262
+ limit: 100,
263
+ format: { kind: "percent" },
264
+ }
265
+
266
+ var resetSource = null
267
+ if (chosen.nextRefill && chosen.nextRefill.next) {
268
+ resetSource = chosen.nextRefill.next
269
+ } else if (quota.until) {
270
+ resetSource = quota.until
271
+ }
272
+
273
+ var resetsAt = ctx.util.toIso(resetSource)
274
+ if (resetsAt) line.resetsAt = resetsAt
275
+
276
+ var duration = null
277
+ if (
278
+ chosen.nextRefill &&
279
+ chosen.nextRefill.tariff &&
280
+ typeof chosen.nextRefill.tariff === "object"
281
+ ) {
282
+ duration = parseIsoDurationMs(chosen.nextRefill.tariff.duration)
283
+ }
284
+ if (duration) line.periodDurationMs = duration
285
+
286
+ var lines = [ctx.line.progress(line)]
287
+
288
+ lines.push(
289
+ ctx.line.text({
290
+ label: "Used",
291
+ value:
292
+ scale > 1
293
+ ? formatDecimal(quota.used / scale, 2) + " / " + formatDecimal(quota.maximum / scale, 2) + " credits"
294
+ : String(quota.used),
295
+ })
296
+ )
297
+
298
+ if (quota.remaining !== null) {
299
+ lines.push(
300
+ ctx.line.text({
301
+ label: "Remaining",
302
+ value: scale > 1 ? formatDecimal(quota.remaining / scale, 2) + " credits" : String(quota.remaining),
303
+ })
304
+ )
305
+ }
306
+
307
+ ctx.host.log.info("quota loaded from " + chosen.path)
308
+
309
+ return { lines: lines }
310
+ }
311
+
312
+ globalThis.__openusage_plugin = { id: "jetbrains-ai-assistant", probe: probe }
313
+ })()
@@ -0,0 +1,16 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "id": "jetbrains-ai-assistant",
4
+ "name": "JetBrains AI Assistant",
5
+ "version": "0.0.1",
6
+ "entry": "plugin.js",
7
+ "icon": "icon.svg",
8
+ "brandColor": "#7d5fe6",
9
+ "supportedModes": ["local"],
10
+ "autoMode": "local",
11
+ "lines": [
12
+ { "type": "progress", "label": "Quota", "scope": "overview", "primaryOrder": 1 },
13
+ { "type": "text", "label": "Used", "scope": "detail" },
14
+ { "type": "text", "label": "Remaining", "scope": "detail" }
15
+ ]
16
+ }
@@ -0,0 +1 @@
1
+ <svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Kilo Code</title><path d="M0 0v24h24V0H0zm22.222 22.222H1.778V1.778h20.444v20.444zm-7.555-4.964h2.222v1.778h-2.794L12.89 17.83v-2.794h1.778v2.222zm4 0h-1.778v-2.222h-2.222v-1.778h2.793l1.207 1.207v2.793zm-7.556-2.591H9.333v-1.778h1.778v1.778zm-5.778-1.778h1.778v4h4v1.778H6.54L5.333 17.46V12.89zm13.334-3.556v1.778h-5.778V9.333h1.987V7.111h-1.987V5.333h2.558l1.206 1.207v2.793h2.014zm-11.556-2h2.222l1.778 1.778v2H9.333v-2H7.111v2H5.333V5.333h1.778v2zm4 0H9.333v-2h1.778v2z"></path></svg>
@@ -0,0 +1,111 @@
1
+ (function () {
2
+ var TRPC_BASE = "https://app.kilo.ai/api/trpc";
3
+ var PROCEDURES = "user.getCreditBlocks,kiloPass.getState,user.getAutoTopUpPaymentMethod";
4
+ var AUTH_PATH = "~/.local/share/kilo/auth.json";
5
+
6
+ function loadApiKey(ctx) {
7
+ var v = ctx.host.env.get("KILO_API_KEY");
8
+ if (typeof v === "string" && v.trim()) return v.trim();
9
+
10
+ try {
11
+ if (ctx.host.fs.exists(AUTH_PATH)) {
12
+ var json = ctx.util.tryParseJson(ctx.host.fs.readText(AUTH_PATH));
13
+ if (json) {
14
+ var keys = ["apiKey", "api_key", "token"];
15
+ for (var i = 0; i < keys.length; i++) {
16
+ if (typeof json[keys[i]] === "string" && json[keys[i]].trim()) return json[keys[i]].trim();
17
+ }
18
+ }
19
+ }
20
+ } catch (e) {
21
+ ctx.host.log.warn("kilo: failed to read auth.json: " + e);
22
+ }
23
+ return null;
24
+ }
25
+
26
+ function buildUrl() {
27
+ var input = JSON.stringify({
28
+ "0": { json: null, meta: { values: ["undefined"] } },
29
+ "1": { json: null, meta: { values: ["undefined"] } },
30
+ "2": { json: null, meta: { values: ["undefined"] } },
31
+ });
32
+ return TRPC_BASE + "/" + PROCEDURES + "?batch=1&input=" + encodeURIComponent(input);
33
+ }
34
+
35
+ function extractData(batch, index) {
36
+ if (!Array.isArray(batch)) return null;
37
+ var item = batch[index];
38
+ return item && item.result && item.result.data && item.result.data.json;
39
+ }
40
+
41
+ function probe(ctx) {
42
+ var apiKey = loadApiKey(ctx);
43
+ if (!apiKey) {
44
+ throw "Kilo API key not found. Set KILO_API_KEY or sign in with Kilo CLI.";
45
+ }
46
+
47
+ var result = ctx.util.requestJson({
48
+ method: "GET",
49
+ url: buildUrl(),
50
+ headers: { Authorization: "Bearer " + apiKey, Accept: "application/json" },
51
+ timeoutMs: 30000,
52
+ });
53
+
54
+ if (ctx.util.isAuthStatus(result.resp.status)) {
55
+ throw "API key invalid or expired.";
56
+ }
57
+ if (result.resp.status < 200 || result.resp.status >= 300) {
58
+ throw "Kilo API error (HTTP " + result.resp.status + ").";
59
+ }
60
+ if (!result.json) throw "Could not parse Kilo response.";
61
+
62
+ var creditBlocks = extractData(result.json, 0);
63
+ var kiloPass = extractData(result.json, 1);
64
+
65
+ var totalMusd = 0, remainingMusd = 0;
66
+ if (Array.isArray(creditBlocks)) {
67
+ creditBlocks.forEach(function (block) {
68
+ totalMusd += (block.amount_mUsd || 0);
69
+ remainingMusd += (block.balance_mUsd || 0);
70
+ });
71
+ }
72
+
73
+ var totalUsd = totalMusd / 1e6;
74
+ var remainingUsd = remainingMusd / 1e6;
75
+ var usedUsd = Math.max(0, totalUsd - remainingUsd);
76
+ var usedPct = totalUsd > 0 ? Math.min(100, (usedUsd / totalUsd) * 100) : 0;
77
+
78
+ var lines = [
79
+ ctx.line.progress({
80
+ label: "Credits",
81
+ used: usedPct,
82
+ limit: 100,
83
+ format: { kind: "percent" },
84
+ }),
85
+ ctx.line.text({ label: "Balance", value: "$" + usedUsd.toFixed(2) + " / $" + totalUsd.toFixed(2) }),
86
+ ];
87
+
88
+ var plan = null;
89
+ if (kiloPass) {
90
+ var passUsage = kiloPass.currentPeriodUsageUsd || 0;
91
+ var passBase = kiloPass.currentPeriodBaseCreditsUsd || 0;
92
+ var passBonus = kiloPass.currentPeriodBonusCreditsUsd || 0;
93
+ var passTotal = passBase + passBonus;
94
+ if (passTotal > 0) {
95
+ var passPct = Math.min(100, (passUsage / passTotal) * 100);
96
+ lines.push(ctx.line.progress({
97
+ label: "Pass",
98
+ used: passPct,
99
+ limit: 100,
100
+ format: { kind: "percent" },
101
+ }));
102
+ lines.push(ctx.line.text({ label: "Pass Balance", value: "$" + passUsage.toFixed(2) + " / $" + passTotal.toFixed(2) }));
103
+ }
104
+ plan = kiloPass.planName || kiloPass.tier || kiloPass.status || null;
105
+ }
106
+
107
+ return { plan: plan, lines: lines };
108
+ }
109
+
110
+ globalThis.__openusage_plugin = { id: "kilo", probe: probe };
111
+ })();
@@ -0,0 +1,19 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "id": "kilo",
4
+ "name": "Kilo",
5
+ "version": "0.0.1",
6
+ "entry": "plugin.js",
7
+ "brandColor": "#F59E0B",
8
+ "links": [
9
+ { "label": "Usage", "url": "https://app.kilo.ai/usage" }
10
+ ],
11
+ "supportedModes": ["api", "local"],
12
+ "autoMode": "local",
13
+ "lines": [
14
+ { "type": "progress", "label": "Credits", "scope": "overview", "primaryOrder": 1 },
15
+ { "type": "text", "label": "Balance", "scope": "detail" },
16
+ { "type": "progress", "label": "Pass", "scope": "overview", "primaryOrder": 2 },
17
+ { "type": "text", "label": "Pass Balance", "scope": "detail" }
18
+ ]
19
+ }
@@ -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,3 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
2
+ <path d="M11.065 11.199l7.257-7.2c.137-.136.06-.41-.116-.41H14.3a.164.164 0 0 0-.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 0 1 .205-.023l6.484 4.772a7.677 7.677 0 0 0 3.453 1.283c.108.012.2-.095.2-.23v-3.06c0-.117-.07-.212-.164-.227a5.028 5.028 0 0 1-2.027-.807l-5.613-4.064c-.117-.078-.132-.279-.028-.381z" />
3
+ </svg>
@@ -0,0 +1 @@
1
+ <svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>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>