@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.
- package/LICENSE +0 -0
- package/native-manifest.json +365 -77
- package/package.json +49 -1
- package/plugins/UPSTREAM-LICENSES.md +109 -0
- package/plugins/abacus-ai/icon.svg +0 -0
- package/plugins/abacus-ai/plugin.js +0 -0
- package/plugins/abacus-ai/plugin.json +0 -0
- package/plugins/aiand/icon.svg +6 -0
- package/plugins/aiand/plugin.js +108 -0
- package/plugins/aiand/plugin.json +22 -0
- package/plugins/alibaba/icon-color.svg +0 -0
- package/plugins/alibaba/icon.svg +0 -0
- package/plugins/alibaba/plugin.js +0 -0
- package/plugins/alibaba/plugin.json +0 -0
- package/plugins/alibaba-token-plan/icon-color.svg +0 -0
- package/plugins/alibaba-token-plan/icon.svg +0 -0
- package/plugins/alibaba-token-plan/plugin.js +0 -0
- package/plugins/alibaba-token-plan/plugin.json +0 -0
- package/plugins/amp/icon-color.svg +0 -0
- package/plugins/amp/icon-conflict.svg +0 -0
- package/plugins/amp/icon.svg +0 -0
- package/plugins/amp/plugin.js +0 -0
- package/plugins/amp/plugin.json +0 -0
- package/plugins/antigravity/icon-color.svg +0 -0
- package/plugins/antigravity/icon-conflict.svg +0 -0
- package/plugins/antigravity/icon.svg +0 -0
- package/plugins/antigravity/plugin.js +0 -0
- package/plugins/antigravity/plugin.json +0 -0
- package/plugins/antigravity-cli/icon.svg +0 -0
- package/plugins/antigravity-cli/plugin.js +0 -0
- package/plugins/antigravity-cli/plugin.json +0 -0
- package/plugins/antigravity-ide/icon.svg +0 -0
- package/plugins/antigravity-ide/plugin.js +0 -0
- package/plugins/antigravity-ide/plugin.json +0 -0
- package/plugins/augment/icon.svg +0 -0
- package/plugins/augment/plugin.js +0 -0
- package/plugins/augment/plugin.json +0 -0
- package/plugins/aws-bedrock/icon-color.svg +0 -0
- package/plugins/aws-bedrock/icon.svg +0 -0
- package/plugins/aws-bedrock/plugin.js +0 -0
- package/plugins/aws-bedrock/plugin.json +0 -0
- package/plugins/azure-openai/icon-color.svg +0 -0
- package/plugins/azure-openai/icon.svg +0 -0
- package/plugins/azure-openai/plugin.js +0 -0
- package/plugins/azure-openai/plugin.json +0 -0
- package/plugins/chutes/icon.svg +0 -0
- package/plugins/chutes/plugin.js +0 -0
- package/plugins/chutes/plugin.json +0 -0
- package/plugins/claude/icon-color.svg +0 -0
- package/plugins/claude/icon.svg +0 -0
- package/plugins/claude/plugin.js +70 -23
- package/plugins/claude/plugin.json +0 -0
- package/plugins/clawrouter/icon.svg +7 -0
- package/plugins/clawrouter/plugin.js +45 -0
- package/plugins/clawrouter/plugin.json +22 -0
- package/plugins/clinepass/icon.svg +4 -0
- package/plugins/clinepass/plugin.js +71 -0
- package/plugins/clinepass/plugin.json +23 -0
- package/plugins/codebuddy/plugin.js +331 -0
- package/plugins/codebuddy/plugin.json +30 -0
- package/plugins/codebuff/icon.svg +0 -0
- package/plugins/codebuff/plugin.js +0 -0
- package/plugins/codebuff/plugin.json +0 -0
- package/plugins/codex/icon-color.svg +0 -0
- package/plugins/codex/icon.svg +0 -0
- package/plugins/codex/plugin.js +7 -2
- package/plugins/codex/plugin.json +0 -0
- package/plugins/command-code/icon.svg +0 -0
- package/plugins/command-code/plugin.js +7 -0
- package/plugins/command-code/plugin.json +0 -0
- package/plugins/copilot/icon-color.svg +0 -0
- package/plugins/copilot/icon.svg +0 -0
- package/plugins/copilot/plugin.js +61 -9
- package/plugins/copilot/plugin.json +4 -1
- package/plugins/crof/icon.svg +0 -0
- package/plugins/crof/plugin.js +0 -0
- package/plugins/crof/plugin.json +0 -0
- package/plugins/crofai/icon.svg +0 -0
- package/plugins/crofai/plugin.js +0 -0
- package/plugins/crofai/plugin.json +0 -0
- package/plugins/cursor/icon-conflict.svg +0 -0
- package/plugins/cursor/icon.svg +0 -0
- package/plugins/cursor/plugin.js +46 -9
- package/plugins/cursor/plugin.json +3 -2
- package/plugins/cursor-nightly/icon.png +0 -0
- package/plugins/cursor-nightly/plugin.js +45 -8
- package/plugins/cursor-nightly/plugin.json +3 -2
- package/plugins/deepgram/icon.svg +0 -0
- package/plugins/deepgram/plugin.js +0 -0
- package/plugins/deepgram/plugin.json +0 -0
- package/plugins/deepinfra/icon.svg +4 -0
- package/plugins/deepinfra/plugin.js +97 -0
- package/plugins/deepinfra/plugin.json +28 -0
- package/plugins/deepseek/icon-color.svg +0 -0
- package/plugins/deepseek/icon.svg +0 -0
- package/plugins/deepseek/plugin.js +0 -0
- package/plugins/deepseek/plugin.json +0 -0
- package/plugins/devin/icon.svg +0 -0
- package/plugins/devin/plugin.js +111 -0
- package/plugins/devin/plugin.json +2 -1
- package/plugins/doubao/icon-color.svg +0 -0
- package/plugins/doubao/icon.svg +0 -0
- package/plugins/doubao/plugin.js +0 -0
- package/plugins/doubao/plugin.json +0 -0
- package/plugins/droid/icon.svg +0 -0
- package/plugins/droid/plugin.json +2 -1
- package/plugins/elevenlabs/icon.svg +0 -0
- package/plugins/elevenlabs/plugin.js +17 -2
- package/plugins/elevenlabs/plugin.json +0 -0
- package/plugins/factory/icon-conflict.svg +0 -0
- package/plugins/factory/icon.svg +0 -0
- package/plugins/factory/plugin.js +38 -14
- package/plugins/factory/plugin.json +2 -1
- package/plugins/fireworks-ai/icon.svg +0 -0
- package/plugins/fireworks-ai/plugin.js +0 -0
- package/plugins/fireworks-ai/plugin.json +0 -0
- package/plugins/gemini/icon-color.svg +0 -0
- package/plugins/gemini/icon.svg +0 -0
- package/plugins/gemini/plugin.js +0 -0
- package/plugins/gemini/plugin.json +0 -0
- package/plugins/grok/icon.svg +0 -0
- package/plugins/grok/plugin.js +30 -5
- package/plugins/grok/plugin.json +3 -1
- package/plugins/groqcloud/icon.svg +0 -0
- package/plugins/groqcloud/plugin.js +0 -0
- package/plugins/groqcloud/plugin.json +0 -0
- package/plugins/ibmbob/icon.svg +23 -0
- package/plugins/ibmbob/plugin.js +61 -0
- package/plugins/ibmbob/plugin.json +22 -0
- package/plugins/jetbrains-ai-assistant/icon-color.svg +0 -0
- package/plugins/jetbrains-ai-assistant/icon-conflict.svg +0 -0
- package/plugins/jetbrains-ai-assistant/icon.svg +0 -0
- package/plugins/jetbrains-ai-assistant/plugin.js +0 -0
- package/plugins/jetbrains-ai-assistant/plugin.json +0 -0
- package/plugins/kilo/icon.svg +0 -0
- package/plugins/kilo/plugin.js +0 -0
- package/plugins/kilo/plugin.json +0 -0
- package/plugins/kimi/icon-color.svg +0 -0
- package/plugins/kimi/icon-conflict.svg +0 -0
- package/plugins/kimi/icon.svg +0 -0
- package/plugins/kimi/plugin.js +122 -141
- package/plugins/kimi/plugin.json +5 -2
- package/plugins/kimi-k2/icon-color.svg +0 -0
- package/plugins/kimi-k2/icon.svg +0 -0
- package/plugins/kimi-k2/plugin.js +0 -0
- package/plugins/kimi-k2/plugin.json +0 -0
- package/plugins/kiro/icon-color.svg +0 -0
- package/plugins/kiro/icon-conflict.svg +0 -0
- package/plugins/kiro/icon.svg +0 -0
- package/plugins/kiro/plugin.js +49 -10
- package/plugins/kiro/plugin.json +3 -1
- package/plugins/litellm/icon.svg +0 -0
- package/plugins/litellm/plugin.js +0 -0
- package/plugins/litellm/plugin.json +0 -0
- package/plugins/llm-proxy/icon.svg +0 -0
- package/plugins/llm-proxy/plugin.js +0 -0
- package/plugins/llm-proxy/plugin.json +0 -0
- package/plugins/longcat/icon.svg +4 -0
- package/plugins/longcat/plugin.js +182 -0
- package/plugins/longcat/plugin.json +23 -0
- package/plugins/manus/icon.svg +0 -0
- package/plugins/manus/plugin.js +0 -0
- package/plugins/manus/plugin.json +0 -0
- package/plugins/mimo/icon.svg +0 -0
- package/plugins/mimo/plugin.js +0 -0
- package/plugins/mimo/plugin.json +0 -0
- package/plugins/minimax/icon-color.svg +0 -0
- package/plugins/minimax/icon-conflict.svg +0 -0
- package/plugins/minimax/icon.svg +0 -0
- package/plugins/minimax/plugin.js +25 -31
- package/plugins/minimax/plugin.json +0 -0
- package/plugins/mistral/icon-color.svg +0 -0
- package/plugins/mistral/icon.svg +0 -0
- package/plugins/mistral/plugin.js +0 -0
- package/plugins/mistral/plugin.json +0 -0
- package/plugins/moonshot/icon.svg +0 -0
- package/plugins/moonshot/plugin.js +8 -6
- package/plugins/moonshot/plugin.json +0 -0
- package/plugins/nanogpt/icon-color.svg +0 -0
- package/plugins/nanogpt/icon.svg +0 -0
- package/plugins/nanogpt/plugin.js +0 -0
- package/plugins/nanogpt/plugin.json +0 -0
- package/plugins/neuralwatt/icon.svg +0 -0
- package/plugins/neuralwatt/plugin.js +0 -0
- package/plugins/neuralwatt/plugin.json +0 -0
- package/plugins/notion/icon.svg +1 -0
- package/plugins/notion/plugin.js +282 -0
- package/plugins/notion/plugin.json +29 -0
- package/plugins/ollama/icon.svg +0 -0
- package/plugins/ollama/plugin.js +257 -56
- package/plugins/ollama/plugin.json +6 -3
- package/plugins/openai-api/icon.svg +0 -0
- package/plugins/openai-api/plugin.js +0 -0
- package/plugins/openai-api/plugin.json +0 -0
- package/plugins/opencode/icon.svg +0 -0
- package/plugins/opencode/plugin.js +0 -0
- package/plugins/opencode/plugin.json +0 -0
- package/plugins/opencode-go/icon-conflict.svg +0 -0
- package/plugins/opencode-go/icon.svg +0 -0
- package/plugins/opencode-go/plugin.js +78 -10
- package/plugins/opencode-go/plugin.json +5 -2
- package/plugins/openrouter/icon.svg +0 -0
- package/plugins/openrouter/plugin.js +371 -114
- package/plugins/openrouter/plugin.json +6 -0
- package/plugins/perplexity/icon-color.svg +0 -0
- package/plugins/perplexity/icon-conflict.svg +0 -0
- package/plugins/perplexity/icon.svg +0 -0
- package/plugins/perplexity/plugin.js +0 -0
- package/plugins/perplexity/plugin.json +0 -0
- package/plugins/poe/icon.svg +0 -0
- package/plugins/poe/plugin.js +24 -18
- package/plugins/poe/plugin.json +2 -0
- package/plugins/qoder/icon.svg +3 -0
- package/plugins/qoder/plugin.js +227 -0
- package/plugins/qoder/plugin.json +23 -0
- package/plugins/qwencloud/icon.svg +4 -0
- package/plugins/qwencloud/plugin.js +677 -0
- package/plugins/qwencloud/plugin.json +29 -0
- package/plugins/sakana/icon.svg +5 -0
- package/plugins/sakana/plugin.js +156 -0
- package/plugins/sakana/plugin.json +23 -0
- package/plugins/stepfun/icon-color.svg +0 -0
- package/plugins/stepfun/icon.svg +0 -0
- package/plugins/stepfun/plugin.js +0 -0
- package/plugins/stepfun/plugin.json +0 -0
- package/plugins/sub2api/icon.svg +4 -0
- package/plugins/sub2api/plugin.js +191 -0
- package/plugins/sub2api/plugin.json +16 -0
- package/plugins/synthetic/icon-conflict.svg +0 -0
- package/plugins/synthetic/icon.svg +0 -0
- package/plugins/synthetic/plugin.js +0 -0
- package/plugins/synthetic/plugin.json +0 -0
- package/plugins/t3chat/icon-color.svg +0 -0
- package/plugins/t3chat/icon.svg +0 -0
- package/plugins/t3chat/plugin.js +0 -0
- package/plugins/t3chat/plugin.json +0 -0
- package/plugins/venice/icon-color.svg +0 -0
- package/plugins/venice/icon.svg +0 -0
- package/plugins/venice/plugin.js +0 -0
- package/plugins/venice/plugin.json +0 -0
- package/plugins/vertex-ai/icon-color.svg +0 -0
- package/plugins/vertex-ai/icon.svg +0 -0
- package/plugins/vertex-ai/plugin.js +0 -0
- package/plugins/vertex-ai/plugin.json +0 -0
- package/plugins/warp/icon-color.svg +0 -0
- package/plugins/warp/icon.svg +0 -0
- package/plugins/warp/plugin.js +0 -0
- package/plugins/warp/plugin.json +0 -0
- package/plugins/wayfinder/icon.svg +5 -0
- package/plugins/wayfinder/plugin.js +47 -0
- package/plugins/wayfinder/plugin.json +16 -0
- package/plugins/windsurf/icon-conflict.svg +0 -0
- package/plugins/windsurf/icon.svg +0 -0
- package/plugins/windsurf/plugin.js +0 -0
- package/plugins/windsurf/plugin.json +0 -0
- package/plugins/xai/icon.svg +7 -0
- package/plugins/xai/plugin.js +162 -0
- package/plugins/xai/plugin.json +28 -0
- package/plugins/zai/icon-conflict.svg +0 -0
- package/plugins/zai/icon.svg +0 -0
- package/plugins/zai/plugin.js +111 -161
- package/plugins/zai/plugin.json +4 -1
- package/plugins/zed/icon.svg +0 -0
- package/plugins/zed/plugin.js +0 -0
- package/plugins/zed/plugin.json +0 -0
- package/plugins/zenmux/icon.svg +3 -0
- package/plugins/zenmux/plugin.js +102 -0
- package/plugins/zenmux/plugin.json +23 -0
- package/plugins/zoommate/icon.svg +1 -0
- package/plugins/zoommate/plugin.js +244 -0
- package/plugins/zoommate/plugin.json +29 -0
- package/usagestat +0 -0
- package/usagestatd +0 -0
|
@@ -313,16 +313,14 @@
|
|
|
313
313
|
}
|
|
314
314
|
}
|
|
315
315
|
|
|
316
|
-
function fetchUsage(ctx, accessToken) {
|
|
316
|
+
function fetchUsage(ctx, accessToken, cookie) {
|
|
317
|
+
const headers = { Accept: "application/json", "Content-Type": "application/json", "User-Agent": "usagestat" }
|
|
318
|
+
if (accessToken) headers.Authorization = "Bearer " + accessToken
|
|
319
|
+
if (cookie) headers.Cookie = cookie
|
|
317
320
|
var resp = ctx.util.request({
|
|
318
321
|
method: "POST",
|
|
319
322
|
url: USAGE_URL,
|
|
320
|
-
headers
|
|
321
|
-
Authorization: "Bearer " + accessToken,
|
|
322
|
-
"Content-Type": "application/json",
|
|
323
|
-
Accept: "application/json",
|
|
324
|
-
"User-Agent": "OpenUsage",
|
|
325
|
-
},
|
|
323
|
+
headers,
|
|
326
324
|
bodyText: JSON.stringify({ useCache: true }),
|
|
327
325
|
timeoutMs: 10000,
|
|
328
326
|
})
|
|
@@ -331,18 +329,14 @@
|
|
|
331
329
|
resp = ctx.util.request({
|
|
332
330
|
method: "GET",
|
|
333
331
|
url: USAGE_URL,
|
|
334
|
-
headers
|
|
335
|
-
Authorization: "Bearer " + accessToken,
|
|
336
|
-
Accept: "application/json",
|
|
337
|
-
"User-Agent": "OpenUsage",
|
|
338
|
-
},
|
|
332
|
+
headers,
|
|
339
333
|
timeoutMs: 10000,
|
|
340
334
|
})
|
|
341
335
|
}
|
|
342
336
|
return resp
|
|
343
337
|
}
|
|
344
338
|
|
|
345
|
-
function
|
|
339
|
+
function fetchOAuth(ctx) {
|
|
346
340
|
const authState = loadAuth(ctx)
|
|
347
341
|
if (!authState) {
|
|
348
342
|
ctx.host.log.error("probe failed: not logged in")
|
|
@@ -412,7 +406,10 @@
|
|
|
412
406
|
}
|
|
413
407
|
|
|
414
408
|
ctx.host.log.info("usage fetch succeeded")
|
|
409
|
+
return resp
|
|
410
|
+
}
|
|
415
411
|
|
|
412
|
+
function buildResult(ctx, resp, source) {
|
|
416
413
|
const data = ctx.util.tryParseJson(resp.bodyText)
|
|
417
414
|
if (data === null) {
|
|
418
415
|
throw "Usage response invalid. Try again later."
|
|
@@ -480,7 +477,34 @@
|
|
|
480
477
|
lines.push(ctx.line.badge({ label: "Status", text: "No usage data", color: "#a3a3a3" }))
|
|
481
478
|
}
|
|
482
479
|
|
|
483
|
-
return { plan: plan, lines: lines }
|
|
480
|
+
return { plan: plan, lines: lines, source }
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
function probe(ctx) {
|
|
484
|
+
const configured = ctx.provider || {}
|
|
485
|
+
const mode = ctx.sourceMode || "auto"
|
|
486
|
+
const key = String(configured.apiKey || ctx.host.env.get("FACTORY_API_KEY") || "").trim()
|
|
487
|
+
const cookie = String(configured.cookieHeader || ctx.host.env.get("FACTORY_COOKIE") || ctx.host.env.get("DROID_COOKIE") || "").trim().replace(/^cookie:\s*/i, "")
|
|
488
|
+
if (mode === "api" && !key) throw "Set FACTORY_API_KEY or provider apiKey."
|
|
489
|
+
if (mode === "web" && !cookie) throw "Set FACTORY_COOKIE or provider cookieHeader."
|
|
490
|
+
if (key && (mode === "auto" || mode === "api")) {
|
|
491
|
+
try {
|
|
492
|
+
const resp = fetchUsage(ctx, key)
|
|
493
|
+
if (ctx.util.isAuthStatus(resp.status)) throw "Factory API key was rejected."
|
|
494
|
+
if (resp.status < 200 || resp.status >= 300) throw "Factory API returned HTTP " + resp.status + "."
|
|
495
|
+
return buildResult(ctx, resp, "api")
|
|
496
|
+
} catch (error) {
|
|
497
|
+
if (mode === "api" || (!cookie && !loadAuth(ctx))) throw error
|
|
498
|
+
ctx.host.log.warn("Factory API unavailable; trying the configured session")
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
if (cookie && (mode === "auto" || mode === "web")) {
|
|
502
|
+
const resp = fetchUsage(ctx, null, cookie)
|
|
503
|
+
if (ctx.util.isAuthStatus(resp.status)) throw "Factory web session expired."
|
|
504
|
+
if (resp.status < 200 || resp.status >= 300) throw "Factory web usage returned HTTP " + resp.status + "."
|
|
505
|
+
return buildResult(ctx, resp, "web")
|
|
506
|
+
}
|
|
507
|
+
return buildResult(ctx, fetchOAuth(ctx), "oauth")
|
|
484
508
|
}
|
|
485
509
|
|
|
486
510
|
globalThis.__openusage_plugin = { id: "factory", probe }
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
"entry": "plugin.js",
|
|
7
7
|
"icon": "icon.svg",
|
|
8
8
|
"brandColor": "#020202",
|
|
9
|
-
"supportedModes": ["oauth", "local"],
|
|
9
|
+
"supportedModes": ["api", "oauth", "local", "web"],
|
|
10
|
+
"envVars": ["FACTORY_API_KEY", "FACTORY_COOKIE", "DROID_COOKIE"],
|
|
10
11
|
"autoMode": "oauth",
|
|
11
12
|
"lines": [
|
|
12
13
|
{ "type": "progress", "label": "Standard", "scope": "overview", "primaryOrder": 1 },
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/plugins/gemini/icon.svg
CHANGED
|
File without changes
|
package/plugins/gemini/plugin.js
CHANGED
|
File without changes
|
|
File without changes
|
package/plugins/grok/icon.svg
CHANGED
|
File without changes
|
package/plugins/grok/plugin.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
(function () {
|
|
2
2
|
const AUTH_PATH = "~/.grok/auth.json";
|
|
3
|
-
const BILLING_URL = "https://cli-chat-proxy.grok.com/v1/billing";
|
|
3
|
+
const BILLING_URL = "https://cli-chat-proxy.grok.com/v1/billing?format=credits";
|
|
4
4
|
const SETTINGS_URL = "https://cli-chat-proxy.grok.com/v1/settings";
|
|
5
5
|
const REFRESH_URL = "https://auth.x.ai/oauth2/token";
|
|
6
6
|
const DEFAULT_CLIENT_ID = "b1a00492-073a-47ea-816f-4c329264a828";
|
|
@@ -8,6 +8,11 @@
|
|
|
8
8
|
const AUTH_REFRESH_BUFFER_MS = 5 * 60 * 1000;
|
|
9
9
|
const LOGIN_HINT = "Grok auth expired. Run `grok login` again.";
|
|
10
10
|
|
|
11
|
+
function authPath(ctx) {
|
|
12
|
+
const home = ctx.host.env.get("GROK_HOME");
|
|
13
|
+
return typeof home === "string" && home.trim() ? home.trim().replace(/\/+$/, "") + "/auth.json" : AUTH_PATH;
|
|
14
|
+
}
|
|
15
|
+
|
|
11
16
|
function readJson(ctx, path) {
|
|
12
17
|
if (!ctx.host.fs.exists(path)) return null;
|
|
13
18
|
try {
|
|
@@ -129,7 +134,7 @@
|
|
|
129
134
|
entry.expires_at = new Date(expiresAtMs).toISOString();
|
|
130
135
|
|
|
131
136
|
try {
|
|
132
|
-
ctx.host.fs.writeText(
|
|
137
|
+
ctx.host.fs.writeText(authPath(ctx), JSON.stringify(auth, null, 2));
|
|
133
138
|
ctx.host.log.info("Grok auth refresh succeeded, token persisted");
|
|
134
139
|
} catch (e) {
|
|
135
140
|
ctx.host.log.warn("Grok auth refresh succeeded but failed to save auth: " + String(e));
|
|
@@ -144,7 +149,7 @@
|
|
|
144
149
|
}
|
|
145
150
|
|
|
146
151
|
function loadAuth(ctx) {
|
|
147
|
-
const auth = readJson(ctx,
|
|
152
|
+
const auth = readJson(ctx, authPath(ctx));
|
|
148
153
|
if (!auth || typeof auth !== "object") {
|
|
149
154
|
throw "Grok not logged in. Run `grok login`.";
|
|
150
155
|
}
|
|
@@ -179,6 +184,7 @@
|
|
|
179
184
|
|
|
180
185
|
function unitsValue(obj) {
|
|
181
186
|
if (!obj || typeof obj !== "object") return null;
|
|
187
|
+
if ((typeof obj.val !== "number" && typeof obj.val !== "string") || String(obj.val).trim() === "") return null;
|
|
182
188
|
const n = Number(obj.val);
|
|
183
189
|
return Number.isFinite(n) ? n : null;
|
|
184
190
|
}
|
|
@@ -235,7 +241,7 @@
|
|
|
235
241
|
Accept: "application/json",
|
|
236
242
|
"User-Agent": "OpenUsage",
|
|
237
243
|
},
|
|
238
|
-
timeoutMs:
|
|
244
|
+
timeoutMs: 1500,
|
|
239
245
|
});
|
|
240
246
|
if (resp.status < 200 || resp.status >= 300) return null;
|
|
241
247
|
const data = ctx.util.tryParseJson(resp.bodyText);
|
|
@@ -262,6 +268,25 @@
|
|
|
262
268
|
throw "Grok billing response changed.";
|
|
263
269
|
}
|
|
264
270
|
|
|
271
|
+
if (config.currentPeriod) {
|
|
272
|
+
const period = config.currentPeriod;
|
|
273
|
+
const start = ctx.util.parseDateMs(period.start);
|
|
274
|
+
const end = ctx.util.parseDateMs(period.end);
|
|
275
|
+
const now = nowMs(ctx);
|
|
276
|
+
const knownType = ["USAGE_PERIOD_TYPE_WEEKLY", "USAGE_PERIOD_TYPE_MONTHLY"].includes(period.type);
|
|
277
|
+
if (!knownType || !Number.isFinite(start) || !Number.isFinite(end) || end <= start) throw "Grok billing period is invalid.";
|
|
278
|
+
const hasPercent = Object.prototype.hasOwnProperty.call(config, "creditUsagePercent");
|
|
279
|
+
let percent = hasPercent ? unitsValue({ val: config.creditUsagePercent }) : 0;
|
|
280
|
+
if (percent === null || percent < 0 || (!hasPercent && !(start <= now && now < end))) throw "Grok billing usage is unavailable for this period.";
|
|
281
|
+
const cap = config.onDemandCap === undefined ? 0 : config.onDemandCap && config.onDemandCap.val === undefined ? 0 : unitsValue(config.onDemandCap);
|
|
282
|
+
if (cap === null || cap < 0) throw "Grok on-demand cap is invalid.";
|
|
283
|
+
return { plan: fetchPlanName(ctx, auth.token), source: "api", lines: [
|
|
284
|
+
ctx.line.progress({ label: period.type === "USAGE_PERIOD_TYPE_WEEKLY" ? "Weekly limit" : "Monthly limit", used: clampPercent(percent), limit: 100,
|
|
285
|
+
format: { kind: "percent" }, resetsAt: ctx.util.toIso(end), periodDurationMs: end - start }),
|
|
286
|
+
ctx.line.badge({ label: "Pay as you go", text: cap > 0 ? String(cap) + " cap" : "Disabled", color: cap > 0 ? "#22c55e" : "#a3a3a3" }),
|
|
287
|
+
] };
|
|
288
|
+
}
|
|
289
|
+
|
|
265
290
|
const usedUnits = unitsValue(config.used);
|
|
266
291
|
const limitUnits = unitsValue(config.monthlyLimit);
|
|
267
292
|
const onDemandCapUnits = unitsValue(config.onDemandCap);
|
|
@@ -290,7 +315,7 @@
|
|
|
290
315
|
}),
|
|
291
316
|
];
|
|
292
317
|
|
|
293
|
-
return { plan: fetchPlanName(ctx, auth.token), lines };
|
|
318
|
+
return { plan: fetchPlanName(ctx, auth.token), source: "api", lines };
|
|
294
319
|
}
|
|
295
320
|
|
|
296
321
|
globalThis.__openusage_plugin = { id: "grok", probe };
|
package/plugins/grok/plugin.json
CHANGED
|
@@ -13,7 +13,9 @@
|
|
|
13
13
|
"autoMode": "cli",
|
|
14
14
|
"webUrl": "https://grok.com",
|
|
15
15
|
"lines": [
|
|
16
|
-
{ "type": "progress", "label": "
|
|
16
|
+
{ "type": "progress", "label": "Weekly limit", "scope": "overview", "primaryOrder": 1 },
|
|
17
|
+
{ "type": "progress", "label": "Monthly limit", "scope": "overview" },
|
|
18
|
+
{ "type": "progress", "label": "Credits used", "scope": "overview" },
|
|
17
19
|
{ "type": "badge", "label": "Pay as you go", "scope": "detail" }
|
|
18
20
|
]
|
|
19
21
|
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<svg id="Bob" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
|
2
|
+
<defs>
|
|
3
|
+
<linearGradient id="helmetShade" x1="0" y1="0" x2="1" y2="0">
|
|
4
|
+
<stop offset=".134" stop-opacity="0"/>
|
|
5
|
+
<stop offset=".873"/>
|
|
6
|
+
</linearGradient>
|
|
7
|
+
<linearGradient id="bobGradient" x1="0" y1="32" x2="32" y2="0" gradientUnits="userSpaceOnUse">
|
|
8
|
+
<stop offset=".1" stop-color="#a16efb"/>
|
|
9
|
+
<stop offset=".9" stop-color="#0e61fa"/>
|
|
10
|
+
</linearGradient>
|
|
11
|
+
<mask id="helmetMask" x="0" y="0" width="32" height="32" maskUnits="userSpaceOnUse">
|
|
12
|
+
<path d="M29.718 15.25a13.67 13.67 0 0 0-9.991-12.476A1.747 1.747 0 0 0 18 1.25h-4c-.887 0-1.615.667-1.727 1.524A13.67 13.67 0 0 0 2.282 15.25H0v1.5h32v-1.5h-2.282zM12.25 4.337V13h1.5V3a.25.25 0 0 1 .25-.25h4a.25.25 0 0 1 .25.25v10h1.5V4.337a12.183 12.183 0 0 1 8.468 10.913H3.782A12.183 12.183 0 0 1 12.25 4.337z" fill="#fff"/>
|
|
13
|
+
<path d="M21 7v7H11V7h10z" fill="url(#helmetShade)"/>
|
|
14
|
+
</mask>
|
|
15
|
+
</defs>
|
|
16
|
+
<g mask="url(#helmetMask)">
|
|
17
|
+
<path fill="url(#bobGradient)" d="M0 0h32v32H0z"/>
|
|
18
|
+
</g>
|
|
19
|
+
<path d="M24 30.75H8a4.756 4.756 0 0 1-4.69-4H3c-.965 0-1.75-.785-1.75-1.75v-6h1.5v6c0 .138.112.25.25.25h1.75V26A3.254 3.254 0 0 0 8 29.25h16A3.254 3.254 0 0 0 27.25 26v-.75H29a.25.25 0 0 0 .25-.25v-6h1.5v6c0 .965-.785 1.75-1.75 1.75h-.31a4.756 4.756 0 0 1-4.69 4z" fill="#001d6c"/>
|
|
20
|
+
<circle cx="22" cy="21" r="2" fill="#001d6c"/>
|
|
21
|
+
<circle cx="10" cy="21" r="2" fill="#001d6c"/>
|
|
22
|
+
<path d="M16 27.75a5.695 5.695 0 0 1-3.451-1.15.75.75 0 0 1 .903-1.199c1.476 1.111 3.617 1.111 5.099 0a.75.75 0 1 1 .901 1.199 5.696 5.696 0 0 1-3.45 1.15z" fill="#001d6c"/>
|
|
23
|
+
</svg>
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
(function () {
|
|
2
|
+
function clean(value) {
|
|
3
|
+
return typeof value === "string" && value.trim() ? value.trim() : null
|
|
4
|
+
}
|
|
5
|
+
function number(value) {
|
|
6
|
+
if (typeof value !== "number" && typeof value !== "string") return null
|
|
7
|
+
if (typeof value === "string" && !value.trim()) return null
|
|
8
|
+
const n = Number(value)
|
|
9
|
+
return Number.isFinite(n) && n >= 0 ? n : null
|
|
10
|
+
}
|
|
11
|
+
function regionalBase(domain) {
|
|
12
|
+
if (!clean(domain)) return "https://api.us-east.bob.ibm.com"
|
|
13
|
+
const host = domain.trim().toLowerCase()
|
|
14
|
+
if (!/^(?:[a-z0-9-]+\.)*bob\.ibm\.com$/.test(host)) throw "IBM Bob returned an untrusted regional host."
|
|
15
|
+
return "https://" + (host.startsWith("api.") ? host : "api." + host)
|
|
16
|
+
}
|
|
17
|
+
function request(ctx, url, headers) {
|
|
18
|
+
const result = ctx.util.requestJson({ method: "GET", url, headers, timeoutMs: 5000 })
|
|
19
|
+
if (ctx.util.isAuthStatus(result.resp.status)) throw "IBM Bob rejected the API key."
|
|
20
|
+
if (result.resp.status < 200 || result.resp.status >= 300) throw "IBM Bob API returned HTTP " + result.resp.status + "."
|
|
21
|
+
if (!result.json || typeof result.json !== "object") throw "Invalid IBM Bob response."
|
|
22
|
+
return result.json
|
|
23
|
+
}
|
|
24
|
+
function probe(ctx) {
|
|
25
|
+
const key = clean(ctx.provider && ctx.provider.apiKey) || clean(ctx.host.env.get("BOBSHELL_API_KEY"))
|
|
26
|
+
if (!key) throw "Set BOBSHELL_API_KEY or the IBM Bob provider API key."
|
|
27
|
+
const jwt = key.split(".").length === 3 && ctx.jwt.decodePayload(key)
|
|
28
|
+
const headers = { Authorization: (jwt ? "Bearer " : "Apikey ") + key, Accept: "application/json", "User-Agent": "UsageStat" }
|
|
29
|
+
const profile = request(ctx, "https://api.us-east.bob.ibm.com/admin/v1/profile", headers)
|
|
30
|
+
if (!Array.isArray(profile.instances)) throw "IBM Bob profile is missing subscriptions."
|
|
31
|
+
const lines = []
|
|
32
|
+
const plans = []
|
|
33
|
+
let count = 0
|
|
34
|
+
for (const instance of profile.instances) {
|
|
35
|
+
if (!instance || !clean(instance.user_id) || !Array.isArray(instance.teams)) continue
|
|
36
|
+
const base = regionalBase(instance.region_domain)
|
|
37
|
+
for (const team of instance.teams) {
|
|
38
|
+
if (!team || !clean(team.id)) continue
|
|
39
|
+
if (ctx.provider && ctx.provider.workspaceId && ctx.provider.workspaceId !== team.id) continue
|
|
40
|
+
if (++count > 20) throw "IBM Bob returned more than 20 teams; select a workspace."
|
|
41
|
+
const budget = request(ctx, base + "/admin/v1/teams/" + encodeURIComponent(team.id) + "/users/" + encodeURIComponent(instance.user_id),
|
|
42
|
+
Object.assign({}, headers, { "x-instance-id": instance.instance_id, "x-team-id": team.id }))
|
|
43
|
+
const used = number(budget.usage)
|
|
44
|
+
const limit = number(budget.budget_limit) === null ? number(team.budget_limit) : number(budget.budget_limit)
|
|
45
|
+
if (used === null) throw "IBM Bob did not return valid Bobcoin usage."
|
|
46
|
+
const label = clean(instance.instance_name) || clean(instance.name) || instance.instance_id
|
|
47
|
+
const teamName = clean(team.name) || team.id
|
|
48
|
+
const reset = typeof instance.refresh_at === "number" ? instance.refresh_at * 1000 : instance.refresh_at
|
|
49
|
+
if (limit !== null && limit > 0) {
|
|
50
|
+
lines.push(ctx.line.progress({ label: label + " / " + teamName, used, limit,
|
|
51
|
+
format: { kind: "count", suffix: "Bobcoins" }, resetsAt: ctx.util.toIso(reset),
|
|
52
|
+
periodDurationMs: 30 * 24 * 60 * 60 * 1000 }))
|
|
53
|
+
} else lines.push(ctx.line.text({ label: teamName, value: used + " Bobcoins used" }))
|
|
54
|
+
if (clean(instance.plan_name) && !plans.includes(instance.plan_name)) plans.push(instance.plan_name)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (!lines.length) throw "No IBM Bob team subscription found."
|
|
58
|
+
return { displayName: "IBM Bob", source: "api", plan: plans.join(", ") || undefined, lines }
|
|
59
|
+
}
|
|
60
|
+
globalThis.__openusage_plugin = { id: "ibmbob", probe }
|
|
61
|
+
})()
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"id": "ibmbob",
|
|
4
|
+
"name": "IBM Bob",
|
|
5
|
+
"version": "0.1.0",
|
|
6
|
+
"entry": "plugin.js",
|
|
7
|
+
"enabledByDefault": false,
|
|
8
|
+
"envVars": [
|
|
9
|
+
"BOBSHELL_API_KEY"
|
|
10
|
+
],
|
|
11
|
+
"supportedModes": [
|
|
12
|
+
"api"
|
|
13
|
+
],
|
|
14
|
+
"autoMode": "api",
|
|
15
|
+
"usageDashboardUrl": "https://bob.ibm.com",
|
|
16
|
+
"links": [
|
|
17
|
+
{
|
|
18
|
+
"label": "Dashboard",
|
|
19
|
+
"url": "https://bob.ibm.com"
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/plugins/kilo/icon.svg
CHANGED
|
File without changes
|
package/plugins/kilo/plugin.js
CHANGED
|
File without changes
|
package/plugins/kilo/plugin.json
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/plugins/kimi/icon.svg
CHANGED
|
File without changes
|