@hashimkarim/usagestat-linux-x64-gnu 2.0.2 → 2.1.0
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/native-manifest.json +685 -133
- package/package.json +94 -2
- package/plugins/abliteration/LICENSE +21 -0
- package/plugins/abliteration/icon.svg +5 -0
- package/plugins/abliteration/plugin.js +89 -0
- package/plugins/abliteration/plugin.json +24 -0
- package/plugins/aerostack/LICENSE +21 -0
- package/plugins/aerostack/icon.svg +1 -0
- package/plugins/aerostack/plugin.js +94 -0
- package/plugins/aerostack/plugin.json +24 -0
- package/plugins/aixy/icon.svg +1 -0
- package/plugins/aixy/plugin.js +5 -0
- package/plugins/aixy/plugin.json +9 -1
- package/plugins/antigravity/plugin.js +19 -10
- package/plugins/antigravity-cli/plugin.js +8 -3
- package/plugins/antigravity-ide/plugin.js +8 -5
- package/plugins/atlascloud/plugin.js +5 -0
- package/plugins/atlascloud/plugin.json +2 -1
- package/plugins/bifrost/icon.svg +3 -0
- package/plugins/bifrost/plugin.js +5 -0
- package/plugins/bifrost/plugin.json +9 -1
- package/plugins/chatbox/LICENSE +21 -0
- package/plugins/chatbox/icon.svg +4 -0
- package/plugins/chatbox/plugin.js +208 -0
- package/plugins/chatbox/plugin.json +24 -0
- package/plugins/claude/plugin.js +39 -2
- package/plugins/claudeplatform/LICENSE +21 -0
- package/plugins/claudeplatform/icon.svg +3 -0
- package/plugins/claudeplatform/plugin.js +244 -0
- package/plugins/claudeplatform/plugin.json +25 -0
- package/plugins/codex/plugin.js +3 -2
- package/plugins/codex/plugin.json +1 -1
- package/plugins/cosmic/LICENSE +21 -0
- package/plugins/cosmic/icon.svg +1 -0
- package/plugins/cosmic/plugin.js +134 -0
- package/plugins/cosmic/plugin.json +32 -0
- package/plugins/cursor/plugin.js +9 -2
- package/plugins/cursor-nightly/plugin.json +1 -1
- package/plugins/devpass/icon.svg +3 -0
- package/plugins/devpass/plugin.js +5 -0
- package/plugins/devpass/plugin.json +2 -1
- package/plugins/exa/LICENSE +21 -0
- package/plugins/exa/icon-color.svg +1 -0
- package/plugins/exa/icon.svg +1 -0
- package/plugins/exa/plugin.js +75 -0
- package/plugins/exa/plugin.json +32 -0
- package/plugins/fal/LICENSE +21 -0
- package/plugins/fal/icon-color.svg +1 -0
- package/plugins/fal/icon.svg +1 -0
- package/plugins/fal/plugin.js +74 -0
- package/plugins/fal/plugin.json +24 -0
- package/plugins/flora/LICENSE +21 -0
- package/plugins/flora/icon.svg +4 -0
- package/plugins/flora/plugin.js +93 -0
- package/plugins/flora/plugin.json +32 -0
- package/plugins/futureagi/LICENSE +21 -0
- package/plugins/futureagi/icon.svg +24 -0
- package/plugins/futureagi/plugin.js +139 -0
- package/plugins/futureagi/plugin.json +32 -0
- package/plugins/gemini-apps/LICENSE +1 -2
- package/plugins/gemini-apps/plugin.js +136 -465
- package/plugins/gemini-apps/plugin.json +13 -7
- package/plugins/gitkraken/icon.svg +2 -0
- package/plugins/gitkraken/plugin.js +5 -0
- package/plugins/gitkraken/plugin.json +9 -1
- package/plugins/helmcode/icon.svg +5 -0
- package/plugins/helmcode/plugin.js +48 -40
- package/plugins/helmcode/plugin.json +10 -2
- package/plugins/huggingface/plugin.js +6 -1
- package/plugins/huggingface/plugin.json +4 -3
- package/plugins/hyper/plugin.js +53 -47
- package/plugins/hyper/plugin.json +3 -2
- package/plugins/kimi/plugin.js +39 -14
- package/plugins/langdock/LICENSE +21 -0
- package/plugins/langdock/icon.svg +4 -0
- package/plugins/langdock/plugin.js +106 -0
- package/plugins/langdock/plugin.json +25 -0
- package/plugins/linkup/LICENSE +21 -0
- package/plugins/linkup/icon.svg +10 -0
- package/plugins/linkup/plugin.js +46 -0
- package/plugins/linkup/plugin.json +24 -0
- package/plugins/lithosai/plugin.js +5 -0
- package/plugins/lithosai/plugin.json +2 -1
- package/plugins/llmman/icon.svg +4 -0
- package/plugins/llmman/plugin.js +5 -0
- package/plugins/llmman/plugin.json +9 -1
- package/plugins/munito/LICENSE +21 -0
- package/plugins/munito/icon.svg +7 -0
- package/plugins/munito/plugin.js +171 -0
- package/plugins/munito/plugin.json +24 -0
- package/plugins/muse/icon.svg +3 -0
- package/plugins/muse/plugin.js +5 -0
- package/plugins/muse/plugin.json +9 -1
- package/plugins/museai/plugin.js +5 -0
- package/plugins/museai/plugin.json +2 -1
- package/plugins/nous/plugin.js +5 -0
- package/plugins/nous/plugin.json +9 -1
- package/plugins/ollama/plugin.js +58 -0
- package/plugins/opencode-go/plugin.js +17 -6
- package/plugins/parallel/LICENSE +21 -0
- package/plugins/parallel/icon.svg +11 -0
- package/plugins/parallel/plugin.js +97 -0
- package/plugins/parallel/plugin.json +25 -0
- package/plugins/qwencloud/LICENSE +21 -0
- package/plugins/qwencloud/plugin.js +197 -0
- package/plugins/qwencloud/plugin.json +17 -0
- package/plugins/raycast/icon.svg +4 -0
- package/plugins/raycast/plugin.js +5 -0
- package/plugins/raycast/plugin.json +9 -1
- package/plugins/replicate/plugin.js +5 -0
- package/plugins/replicate/plugin.json +2 -1
- package/plugins/sailresearch/LICENSE +21 -0
- package/plugins/sailresearch/icon.svg +4 -0
- package/plugins/sailresearch/plugin.js +104 -0
- package/plugins/sailresearch/plugin.json +24 -0
- package/plugins/sofya/LICENSE +21 -0
- package/plugins/sofya/icon.svg +3 -0
- package/plugins/sofya/plugin.js +86 -0
- package/plugins/sofya/plugin.json +24 -0
- package/plugins/soniox/LICENSE +21 -0
- package/plugins/soniox/icon.svg +3 -0
- package/plugins/soniox/plugin.js +103 -0
- package/plugins/soniox/plugin.json +24 -0
- package/plugins/tavily/LICENSE +21 -0
- package/plugins/tavily/icon.svg +3 -0
- package/plugins/tavily/plugin.js +61 -0
- package/plugins/tavily/plugin.json +24 -0
- package/plugins/tinyapi/LICENSE +21 -0
- package/plugins/tinyapi/icon.svg +4 -0
- package/plugins/tinyapi/plugin.js +73 -0
- package/plugins/tinyapi/plugin.json +25 -0
- package/plugins/traecn/LICENSE +21 -0
- package/plugins/traecn/icon.svg +3 -0
- package/plugins/traecn/plugin.js +104 -0
- package/plugins/traecn/plugin.json +25 -0
- package/plugins/typesafe/icon.svg +4 -0
- package/plugins/typesafe/plugin.js +30 -25
- package/plugins/typesafe/plugin.json +3 -2
- package/plugins/v0/plugin.js +5 -0
- package/plugins/v0/plugin.json +9 -1
- package/plugins/vercel/plugin.js +147 -0
- package/plugins/vercel/plugin.json +34 -3
- package/plugins/workbuddy/icon.svg +1 -1
- package/plugins/workbuddy/plugin.js +9 -4
- package/plugins/workbuddy/plugin.json +20 -2
- package/plugins/xai/plugin.js +9 -0
- package/plugins/xapi/LICENSE +21 -0
- package/plugins/xapi/icon.svg +1 -0
- package/plugins/xapi/plugin.js +90 -0
- package/plugins/xapi/plugin.json +25 -0
- package/plugins/xkiro/icon.svg +1 -0
- package/plugins/xkiro/plugin.js +5 -0
- package/plugins/xkiro/plugin.json +2 -1
- package/usagestat +0 -0
- package/usagestatd +0 -0
- package/plugins/cursor-nightly/plugin.js +0 -1416
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"id": "tinyapi",
|
|
4
|
+
"name": "TinyApi",
|
|
5
|
+
"version": "0.1.0",
|
|
6
|
+
"entry": "plugin.js",
|
|
7
|
+
"enabledByDefault": false,
|
|
8
|
+
"supportedModes": [
|
|
9
|
+
"web"
|
|
10
|
+
],
|
|
11
|
+
"autoMode": "web",
|
|
12
|
+
"usageDashboardUrl": "https://tinyapi.rest",
|
|
13
|
+
"webUrl": "https://tinyapi.rest",
|
|
14
|
+
"envVars": [
|
|
15
|
+
"TINYAPI_COOKIE"
|
|
16
|
+
],
|
|
17
|
+
"setupFields": [],
|
|
18
|
+
"upstream": {
|
|
19
|
+
"repository": "https://github.com/steipete/CodexBar",
|
|
20
|
+
"revision": "6070b29a1a5d51193a634dc1b0a14a67c39d0ccc",
|
|
21
|
+
"path": "Sources/CodexBarCore/Resources/Plugins/tinyapi.js",
|
|
22
|
+
"sha256": "14f874b433198e9bfb9f1d689a0822f35ac8d97945cab015c039f836eed4ef17",
|
|
23
|
+
"license": "MIT"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Peter Steinberger
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="currentColor">
|
|
2
|
+
<path fill-rule="evenodd" d="M24 20.541H3.428v-3.426H0V3.4h24V20.54zM3.428 17.115h17.144V6.827H3.428v10.288zm8.573-5.196l-2.425 2.424-2.424-2.424 2.424-2.424 2.425 2.424zm6.857-.001l-2.424 2.423-2.425-2.423 2.425-2.425 2.424 2.425z"/>
|
|
3
|
+
</svg>
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// Generated by tools/vendor-codexbar-providers.cjs; see LICENSE.
|
|
2
|
+
globalThis.__usagestat_bundled_options = {"labels":["Credits","Additional","Additional"],"defaults":{},"autoMode":"web"};
|
|
3
|
+
(function(defineProvider) {
|
|
4
|
+
// BEGIN UPSTREAM Sources/CodexBarCore/Resources/Plugins/traecn.js
|
|
5
|
+
defineProvider({
|
|
6
|
+
id: "traecn",
|
|
7
|
+
name: "Trae CN",
|
|
8
|
+
endpoints: ["https://api.trae.cn"],
|
|
9
|
+
settings: [],
|
|
10
|
+
capabilities: ["browser-cookies", "http-status"],
|
|
11
|
+
// Include parent-domain sessions shared by the dashboard and API.
|
|
12
|
+
cookieDomains: ["trae.cn", "api.trae.cn"],
|
|
13
|
+
async fetchUsage(ctx) {
|
|
14
|
+
const domain = ctx.browser.availability("api.trae.cn") === "manual" ? "api.trae.cn" : "trae.cn";
|
|
15
|
+
const signIn = "Sign in to Trae CN at trae.cn, then refresh CodexBar.";
|
|
16
|
+
const malformed = () => {
|
|
17
|
+
throw ctx.fail.parseFailure("Trae CN usage response format changed.");
|
|
18
|
+
};
|
|
19
|
+
const finite = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0;
|
|
20
|
+
const rejected = (response) =>
|
|
21
|
+
response.status === 401 || response.status === 403 || (response.status >= 300 && response.status < 400);
|
|
22
|
+
const read = (response) => {
|
|
23
|
+
const message = "Trae CN request failed. Try refreshing later.";
|
|
24
|
+
if (response.status === 429) throw ctx.fail.rateLimited(message);
|
|
25
|
+
if (response.status === 408 || response.status >= 500) throw ctx.fail.providerUnavailable(message);
|
|
26
|
+
if (response.status !== 200) throw ctx.fail.apiFailure(message);
|
|
27
|
+
try {
|
|
28
|
+
return JSON.parse(response.bodyText);
|
|
29
|
+
} catch {
|
|
30
|
+
return malformed();
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
if (ctx.browser.availability(domain) === "off") throw ctx.fail.missingCredential(signIn);
|
|
34
|
+
let sessionRejected = false;
|
|
35
|
+
for await (const session of ctx.browser.sessions(domain)) {
|
|
36
|
+
const headers = { Cookie: session.header ?? "", Origin: "https://www.trae.cn", Referer: "https://www.trae.cn/" };
|
|
37
|
+
const tokenResponse = await ctx.http.post("https://api.trae.cn/cloudide/api/v3/common/GetUserToken", {
|
|
38
|
+
headers,
|
|
39
|
+
body: {},
|
|
40
|
+
timeoutSeconds: 15,
|
|
41
|
+
});
|
|
42
|
+
if (rejected(tokenResponse)) {
|
|
43
|
+
sessionRejected = true;
|
|
44
|
+
ctx.browser.rejectCookie(domain, session);
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
const tokenPayload = read(tokenResponse);
|
|
48
|
+
const token = tokenPayload?.Result?.Token;
|
|
49
|
+
if (typeof token !== "string" || !token.trim()) return malformed();
|
|
50
|
+
// The exchanged token lives only for this refresh, and only goes back to the declared API origin.
|
|
51
|
+
const usageResponse = await ctx.http.post("https://api.trae.cn/trae/api/v2/pay/user_current_entitlement_list", {
|
|
52
|
+
headers: { ...headers, Authorization: `Cloud-IDE-JWT ${token}` },
|
|
53
|
+
body: { require_usage: true, full_data: true },
|
|
54
|
+
timeoutSeconds: 15,
|
|
55
|
+
});
|
|
56
|
+
if (rejected(usageResponse)) {
|
|
57
|
+
sessionRejected = true;
|
|
58
|
+
ctx.browser.rejectCookie(domain, session);
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
const payload = read(usageResponse);
|
|
62
|
+
const summary = payload?.usage_summary;
|
|
63
|
+
if (payload?.code === 1001) {
|
|
64
|
+
sessionRejected = true;
|
|
65
|
+
ctx.browser.rejectCookie(domain, session);
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
if (
|
|
69
|
+
payload?.is_credits_billing !== true ||
|
|
70
|
+
!summary ||
|
|
71
|
+
!finite(summary.total_amount) ||
|
|
72
|
+
!finite(summary.consumed_amount)
|
|
73
|
+
)
|
|
74
|
+
return malformed();
|
|
75
|
+
const { total_amount: total, consumed_amount: used } = summary;
|
|
76
|
+
const packs = Array.isArray(payload.user_entitlement_pack_list) ? payload.user_entitlement_pack_list : [];
|
|
77
|
+
const subscription = packs.find(
|
|
78
|
+
(pack) => pack && pack.group_type === 0 && (pack.status === undefined || pack.status === 1),
|
|
79
|
+
);
|
|
80
|
+
const plan = typeof subscription?.display_desc === "string" ? subscription.display_desc.trim() : undefined;
|
|
81
|
+
const number = (value) => ctx.format.number(value, { maximumFractionDigits: 2 });
|
|
82
|
+
// Pack expiry and billing timestamps do not establish an aggregate reset or subscription renewal.
|
|
83
|
+
return {
|
|
84
|
+
primary: total > 0 ? { usedPercent: Math.min(100, (used / total) * 100) } : undefined,
|
|
85
|
+
identity: plan ? { loginMethod: plan } : undefined,
|
|
86
|
+
details: [
|
|
87
|
+
{
|
|
88
|
+
title: "Credits",
|
|
89
|
+
rows: [
|
|
90
|
+
{ label: "Used", value: number(used) },
|
|
91
|
+
{ label: "Total", value: number(total) },
|
|
92
|
+
{ label: "Remaining", value: number(Math.max(0, total - used)) },
|
|
93
|
+
],
|
|
94
|
+
},
|
|
95
|
+
],
|
|
96
|
+
dataConfidence: "exact",
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
throw sessionRejected ? ctx.fail.authenticationExpired(signIn) : ctx.fail.missingCredential(signIn);
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// END UPSTREAM
|
|
104
|
+
})(globalThis.defineProvider);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"id": "traecn",
|
|
4
|
+
"name": "Trae CN",
|
|
5
|
+
"version": "0.1.0",
|
|
6
|
+
"entry": "plugin.js",
|
|
7
|
+
"enabledByDefault": false,
|
|
8
|
+
"supportedModes": [
|
|
9
|
+
"web"
|
|
10
|
+
],
|
|
11
|
+
"autoMode": "web",
|
|
12
|
+
"usageDashboardUrl": "https://www.trae.cn",
|
|
13
|
+
"webUrl": "https://trae.cn",
|
|
14
|
+
"envVars": [
|
|
15
|
+
"TRAECN_COOKIE"
|
|
16
|
+
],
|
|
17
|
+
"setupFields": [],
|
|
18
|
+
"upstream": {
|
|
19
|
+
"repository": "https://github.com/steipete/CodexBar",
|
|
20
|
+
"revision": "6070b29a1a5d51193a634dc1b0a14a67c39d0ccc",
|
|
21
|
+
"path": "Sources/CodexBarCore/Resources/Plugins/traecn.js",
|
|
22
|
+
"sha256": "045bf8cbba44d779fc69a1ddbd14598a1d1178f265be875336b36b261af5604a",
|
|
23
|
+
"license": "MIT"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
<svg fill="currentColor" viewBox="24.68 24.68 350.65 350.65" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<title>TypeSafe</title>
|
|
3
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M256.407 86.5946V138.33L303.032 168.589L303.045 283.148L199.987 350L143.594 313.42V260.25L96.9556 229.993V116.866L101.395 113.977L199.999 50L256.407 86.5946ZM171.208 308.124L199.975 326.788L275.394 277.838L246.639 259.188L171.208 308.124ZM209.728 179.157V230.005L163.078 260.264V290.192L236.923 242.283V161.517L209.728 179.157ZM256.407 242.31L283.55 259.92V179.144L256.407 161.532V242.31ZM124.582 224.709L153.337 243.374L182.104 224.709L153.349 206.057L124.582 224.709ZM116.438 127.421V206.791L143.594 189.166V138.318L190.258 108.034V79.5105L116.438 127.421ZM163.078 189.154L190.246 206.779V179.144L163.078 161.517V189.154ZM171.208 143.589L199.999 162.266L228.768 143.601L199.987 124.925L171.208 143.589ZM209.742 108.034L236.923 125.671V97.1619L209.742 79.5105V108.034Z" />
|
|
4
|
+
</svg>
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// Generated by tools/vendor-codexbar-providers.cjs; see LICENSE.
|
|
2
2
|
globalThis.__usagestat_bundled_options = {"labels":["Spend","Spend","Additional"],"defaults":{},"autoMode":"web"};
|
|
3
|
+
(function(defineProvider) {
|
|
4
|
+
// BEGIN UPSTREAM Sources/CodexBarCore/Resources/Plugins/typesafe.js
|
|
3
5
|
function _optionalChain(ops) {
|
|
4
6
|
let lastAccessLHS = undefined;
|
|
5
7
|
let value = ops[0];
|
|
@@ -24,6 +26,9 @@ function _optionalChain(ops) {
|
|
|
24
26
|
|
|
25
27
|
const billingURL = "https://console.typesafe.ai/settings/billing";
|
|
26
28
|
const billingOrigin = "https://console.typesafe.ai";
|
|
29
|
+
// Cloudflare blocks the Linux default UA (it contains "curl/"), so send a browser-style one.
|
|
30
|
+
const userAgent =
|
|
31
|
+
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36";
|
|
27
32
|
const actionCacheKey = "typesafe.billing.next-action";
|
|
28
33
|
const actionCacheTTL = 12 * 60 * 60;
|
|
29
34
|
const maximumChunkCount = 60;
|
|
@@ -59,15 +64,13 @@ defineProvider({
|
|
|
59
64
|
throw ctx.fail.apiFailure(`TypeSafe returned HTTP ${response.status}.`);
|
|
60
65
|
};
|
|
61
66
|
// Login pages can also arrive directly with HTTP 200, without an HTTP redirect.
|
|
62
|
-
const isLoginLanding = (body) => /\\?"\(auth\)\\?",\{\\?"children\\?":\[\\?"login\\?"/.test(body);
|
|
63
67
|
const validateBody = (response) => {
|
|
64
68
|
validate(response);
|
|
65
|
-
if (
|
|
69
|
+
if (/\\?"\(auth\)\\?",\{\\?"children\\?":\[\\?"login\\?"/.test(response.bodyText)) expired();
|
|
66
70
|
};
|
|
67
|
-
const actionIDPattern = /"([0-9a-f]{40,})"[^)]{0,150}"getBillingOverviewResult"/i;
|
|
68
71
|
const discoverActionID = async (cookie) => {
|
|
69
72
|
const page = await ctx.http.get(billingURL, {
|
|
70
|
-
headers: { Cookie: cookie, Accept: "text/html" },
|
|
73
|
+
headers: { Cookie: cookie, Accept: "text/html", "User-Agent": userAgent },
|
|
71
74
|
timeoutSeconds: 6,
|
|
72
75
|
});
|
|
73
76
|
validateBody(page);
|
|
@@ -83,11 +86,11 @@ defineProvider({
|
|
|
83
86
|
let discoveryFailure;
|
|
84
87
|
for (const url of chunkURLs) {
|
|
85
88
|
try {
|
|
86
|
-
const chunk = await ctx.http.get(url, { timeoutSeconds: 2 });
|
|
89
|
+
const chunk = await ctx.http.get(url, { headers: { "User-Agent": userAgent }, timeoutSeconds: 2 });
|
|
87
90
|
if (chunk.status === 429 || chunk.status === 408 || chunk.status >= 500) validate(chunk);
|
|
88
91
|
if (chunk.status < 200 || chunk.status >= 300) continue;
|
|
89
92
|
const action = _optionalChain([
|
|
90
|
-
|
|
93
|
+
/"([0-9a-f]{40,})"[^)]{0,150}"getBillingOverviewResult"/i,
|
|
91
94
|
"access",
|
|
92
95
|
(_) => _.exec,
|
|
93
96
|
"call",
|
|
@@ -117,6 +120,7 @@ defineProvider({
|
|
|
117
120
|
"Next-Action": id,
|
|
118
121
|
Accept: "text/x-component",
|
|
119
122
|
"Content-Type": "application/json",
|
|
123
|
+
"User-Agent": userAgent,
|
|
120
124
|
},
|
|
121
125
|
body: [],
|
|
122
126
|
timeoutSeconds: 6,
|
|
@@ -188,25 +192,23 @@ defineProvider({
|
|
|
188
192
|
const availableRows = 24 - rows.length;
|
|
189
193
|
const creditRows = [];
|
|
190
194
|
let creditCount = 0;
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
});
|
|
209
|
-
}
|
|
195
|
+
for (const item of Array.isArray(billing.credits) ? billing.credits : []) {
|
|
196
|
+
const credit = record(item);
|
|
197
|
+
const amount = number(_optionalChain([credit, "optionalAccess", (_14) => _14.amount]));
|
|
198
|
+
const remaining = number(_optionalChain([credit, "optionalAccess", (_15) => _15.remaining]));
|
|
199
|
+
const expiresAt =
|
|
200
|
+
typeof _optionalChain([credit, "optionalAccess", (_16) => _16.expiresAt]) === "string"
|
|
201
|
+
? credit.expiresAt
|
|
202
|
+
: undefined;
|
|
203
|
+
if (amount === undefined || remaining === undefined || remaining <= 0 || !expiresAt) continue;
|
|
204
|
+
const expires = Date.parse(expiresAt);
|
|
205
|
+
if (!Number.isFinite(expires)) continue;
|
|
206
|
+
creditCount++;
|
|
207
|
+
if (creditRows.length >= availableRows) continue;
|
|
208
|
+
creditRows.push({
|
|
209
|
+
label: "Credit",
|
|
210
|
+
value: `${ctx.format.number(remaining)} of ${ctx.format.number(amount)}, expires ${ctx.format.monthDay(expires)}`,
|
|
211
|
+
});
|
|
210
212
|
}
|
|
211
213
|
if (creditCount > availableRows) {
|
|
212
214
|
const shown = availableRows - 1;
|
|
@@ -223,3 +225,6 @@ defineProvider({
|
|
|
223
225
|
};
|
|
224
226
|
},
|
|
225
227
|
});
|
|
228
|
+
|
|
229
|
+
// END UPSTREAM
|
|
230
|
+
})(globalThis.defineProvider);
|
|
@@ -14,11 +14,12 @@
|
|
|
14
14
|
"envVars": [
|
|
15
15
|
"TYPESAFE_COOKIE"
|
|
16
16
|
],
|
|
17
|
+
"setupFields": [],
|
|
17
18
|
"upstream": {
|
|
18
19
|
"repository": "https://github.com/steipete/CodexBar",
|
|
19
|
-
"revision": "
|
|
20
|
+
"revision": "6070b29a1a5d51193a634dc1b0a14a67c39d0ccc",
|
|
20
21
|
"path": "Sources/CodexBarCore/Resources/Plugins/typesafe.js",
|
|
21
|
-
"sha256": "
|
|
22
|
+
"sha256": "ef710412712c83277acda605517d363a4cea58256e33513477b7b863ccf6dc06",
|
|
22
23
|
"license": "MIT"
|
|
23
24
|
}
|
|
24
25
|
}
|
package/plugins/v0/plugin.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// Generated by tools/vendor-codexbar-providers.cjs; see LICENSE.
|
|
2
2
|
globalThis.__usagestat_bundled_options = {"labels":["Billing","Rate limit","Additional"],"defaults":{},"autoMode":"api"};
|
|
3
|
+
(function(defineProvider) {
|
|
4
|
+
// BEGIN UPSTREAM Sources/CodexBarCore/Resources/Plugins/v0.js
|
|
3
5
|
function _nullishCoalesce(lhs, rhsFn) {
|
|
4
6
|
if (lhs != null) {
|
|
5
7
|
return lhs;
|
|
@@ -212,3 +214,6 @@ defineProvider({
|
|
|
212
214
|
};
|
|
213
215
|
},
|
|
214
216
|
});
|
|
217
|
+
|
|
218
|
+
// END UPSTREAM
|
|
219
|
+
})(globalThis.defineProvider);
|
package/plugins/v0/plugin.json
CHANGED
|
@@ -14,9 +14,17 @@
|
|
|
14
14
|
"V0_API_KEY",
|
|
15
15
|
"V0_SCOPE"
|
|
16
16
|
],
|
|
17
|
+
"setupFields": [
|
|
18
|
+
{
|
|
19
|
+
"key": "V0_SCOPE",
|
|
20
|
+
"title": "Scope",
|
|
21
|
+
"type": "string",
|
|
22
|
+
"description": "Provider-specific account or source selection."
|
|
23
|
+
}
|
|
24
|
+
],
|
|
17
25
|
"upstream": {
|
|
18
26
|
"repository": "https://github.com/steipete/CodexBar",
|
|
19
|
-
"revision": "
|
|
27
|
+
"revision": "6070b29a1a5d51193a634dc1b0a14a67c39d0ccc",
|
|
20
28
|
"path": "Sources/CodexBarCore/Resources/Plugins/v0.js",
|
|
21
29
|
"sha256": "5f54a9329dca35d59d76e427c34d4d9db8d3400d0b38c5fcee8899928a900019",
|
|
22
30
|
"license": "MIT"
|
package/plugins/vercel/plugin.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// Generated by tools/vendor-codexbar-providers.cjs; see LICENSE.
|
|
2
2
|
globalThis.__usagestat_bundled_options = {"labels":["Balance","Balance","Additional"],"defaults":{},"autoMode":"api"};
|
|
3
|
+
(function(defineProvider) {
|
|
4
|
+
// BEGIN UPSTREAM Sources/CodexBarCore/Resources/Plugins/vercel.js
|
|
3
5
|
defineProvider({
|
|
4
6
|
id: "vercel",
|
|
5
7
|
name: "Vercel AI Gateway",
|
|
@@ -53,3 +55,148 @@ defineProvider({
|
|
|
53
55
|
};
|
|
54
56
|
},
|
|
55
57
|
});
|
|
58
|
+
|
|
59
|
+
// END UPSTREAM
|
|
60
|
+
})(globalThis.defineProvider);
|
|
61
|
+
(function() { const credits=globalThis.__usagestat_plugin; let budget;
|
|
62
|
+
(function(defineProvider) {
|
|
63
|
+
// BEGIN UPSTREAM Sources/CodexBarCore/Resources/Plugins/vercel-budget.js
|
|
64
|
+
defineProvider({
|
|
65
|
+
id: "vercel",
|
|
66
|
+
name: "Vercel AI Gateway",
|
|
67
|
+
endpoints: ["https://api.vercel.com"],
|
|
68
|
+
auth: { type: "bearer", secret: "VERCEL_ACCESS_TOKEN" },
|
|
69
|
+
settings: [
|
|
70
|
+
{ key: "VERCEL_ACCESS_TOKEN", title: "Vercel access token", type: "secure" },
|
|
71
|
+
{ key: "VERCEL_TEAM_ID", title: "Team ID", type: "plain" },
|
|
72
|
+
],
|
|
73
|
+
capabilities: ["http-status"],
|
|
74
|
+
async fetchUsage(ctx) {
|
|
75
|
+
const team = ctx.settings.get("VERCEL_TEAM_ID")?.trim();
|
|
76
|
+
if (!team) throw ctx.fail.missingCredential("Set the Vercel Team ID to read your personal budget.");
|
|
77
|
+
if (!/^[A-Za-z0-9_-]{1,128}$/.test(team)) {
|
|
78
|
+
throw ctx.fail.permissionDenied("Invalid Vercel Team ID. Enter the team ID or slug without spaces.");
|
|
79
|
+
}
|
|
80
|
+
function fail() {
|
|
81
|
+
throw ctx.fail.parseFailure("Vercel returned an unrecognized personal budget.");
|
|
82
|
+
}
|
|
83
|
+
async function read(url) {
|
|
84
|
+
const response = await ctx.http.get(url);
|
|
85
|
+
const message = `Vercel API returned HTTP ${response.status}.`;
|
|
86
|
+
if (response.status === 401) throw ctx.fail.authenticationExpired(message);
|
|
87
|
+
if (response.status === 403) throw ctx.fail.permissionDenied(message);
|
|
88
|
+
if (response.status === 429) {
|
|
89
|
+
const delay = Number(response.headers["retry-after"] ?? 1);
|
|
90
|
+
throw ctx.fail.rateLimited(message, {
|
|
91
|
+
retryAfterSeconds: Number.isFinite(delay) && delay >= 0 ? Math.min(delay, 10) : 1,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
if (response.status >= 500) throw ctx.fail.providerUnavailable(message);
|
|
95
|
+
if (response.status !== 200) throw ctx.fail.apiFailure(message);
|
|
96
|
+
try {
|
|
97
|
+
return JSON.parse(response.bodyText);
|
|
98
|
+
} catch {
|
|
99
|
+
return fail();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const user = (await read("https://api.vercel.com/v2/user"))?.user;
|
|
104
|
+
if (typeof user?.id !== "string" || !user.id) return fail();
|
|
105
|
+
|
|
106
|
+
// At most 20 pages; the plugin deadline bounds slower teams.
|
|
107
|
+
const matches = [];
|
|
108
|
+
const cursors = new Set();
|
|
109
|
+
let cursor = null;
|
|
110
|
+
for (let page = 0; ; page += 1) {
|
|
111
|
+
const query =
|
|
112
|
+
`teamId=${encodeURIComponent(team)}&scopeType=user&limit=200` +
|
|
113
|
+
(cursor === null ? "" : `&cursor=${encodeURIComponent(cursor)}`);
|
|
114
|
+
const body = await read(`https://api.vercel.com/ai-gateway/budgets/list?${query}`);
|
|
115
|
+
if (!Array.isArray(body?.budgets)) return fail();
|
|
116
|
+
for (const budget of body.budgets) {
|
|
117
|
+
if (budget?.scopeType !== "user" || ![user.id, `usr_${user.id}`].includes(budget.scopeId)) continue;
|
|
118
|
+
if (typeof budget.active !== "boolean" || typeof budget.archived !== "boolean") return fail();
|
|
119
|
+
if (budget.source !== undefined && budget.source !== "default") return fail();
|
|
120
|
+
if (budget.active && !budget.archived) matches.push(budget);
|
|
121
|
+
}
|
|
122
|
+
const next = body.nextCursor;
|
|
123
|
+
if (next === undefined || next === null) break;
|
|
124
|
+
if (typeof next !== "string" || !next || cursors.has(next) || page >= 19) return fail();
|
|
125
|
+
cursors.add(next);
|
|
126
|
+
cursor = next;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const identity = {
|
|
130
|
+
email: typeof user.email === "string" ? user.email : null,
|
|
131
|
+
organization: team,
|
|
132
|
+
loginMethod: "Access token",
|
|
133
|
+
accountID: user.id,
|
|
134
|
+
};
|
|
135
|
+
const custom = matches.filter((budget) => budget.source !== "default");
|
|
136
|
+
const effective = custom.length > 0 ? custom : matches;
|
|
137
|
+
if (effective.length > 1) return fail();
|
|
138
|
+
const budget = effective[0];
|
|
139
|
+
if (!budget) {
|
|
140
|
+
return {
|
|
141
|
+
details: [{ title: "Personal budget", rows: [{ label: "No personal budget configured", value: "—" }] }],
|
|
142
|
+
identity,
|
|
143
|
+
dataConfidence: "exact",
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
const limit = budget.limitAmount;
|
|
147
|
+
const spent = budget.currentSpend;
|
|
148
|
+
if (typeof limit !== "number" || !Number.isFinite(limit) || limit <= 0) return fail();
|
|
149
|
+
if (typeof spent !== "number" || !Number.isFinite(spent) || spent < 0) return fail();
|
|
150
|
+
|
|
151
|
+
// Documented UTC boundaries: daily midnight, weekly Monday, monthly the 1st; `none` never resets.
|
|
152
|
+
const now = ctx.date.now();
|
|
153
|
+
const year = now.getUTCFullYear();
|
|
154
|
+
const month = now.getUTCMonth();
|
|
155
|
+
const day = now.getUTCDate();
|
|
156
|
+
let start = null;
|
|
157
|
+
let end = null;
|
|
158
|
+
if (budget.refreshPeriod === "daily") {
|
|
159
|
+
start = Date.UTC(year, month, day);
|
|
160
|
+
end = Date.UTC(year, month, day + 1);
|
|
161
|
+
} else if (budget.refreshPeriod === "weekly") {
|
|
162
|
+
start = Date.UTC(year, month, day - ((now.getUTCDay() + 6) % 7));
|
|
163
|
+
end = start + 7 * 24 * 60 * 60 * 1000;
|
|
164
|
+
} else if (budget.refreshPeriod === "monthly") {
|
|
165
|
+
start = Date.UTC(year, month, 1);
|
|
166
|
+
end = Date.UTC(year, month + 1, 1);
|
|
167
|
+
} else if (budget.refreshPeriod !== "none") {
|
|
168
|
+
return fail();
|
|
169
|
+
}
|
|
170
|
+
const spentText = ctx.format.usd(spent);
|
|
171
|
+
const limitText = ctx.format.usd(limit);
|
|
172
|
+
return {
|
|
173
|
+
primary: {
|
|
174
|
+
usedPercent: (spent / limit) * 100,
|
|
175
|
+
windowMinutes: start === null ? null : (end - start) / 60000,
|
|
176
|
+
resetsAt: end === null ? null : new Date(end),
|
|
177
|
+
resetDescription: `${spentText} / ${limitText}`,
|
|
178
|
+
},
|
|
179
|
+
details: [
|
|
180
|
+
{
|
|
181
|
+
title: "Personal budget",
|
|
182
|
+
rows: [
|
|
183
|
+
{ label: "Spend", value: spentText },
|
|
184
|
+
{ label: "Limit", value: limitText },
|
|
185
|
+
{ label: "Remaining", value: ctx.format.usd(Math.max(0, limit - spent)) },
|
|
186
|
+
],
|
|
187
|
+
},
|
|
188
|
+
],
|
|
189
|
+
identity,
|
|
190
|
+
dataConfidence: "exact",
|
|
191
|
+
};
|
|
192
|
+
},
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
// END UPSTREAM
|
|
196
|
+
})(definition => { budget=globalThis.__usagestat_bundledProvider(definition,{"labels":["Personal budget","Additional","Additional"],"autoMode":"api","genericApiKey":false}); });
|
|
197
|
+
globalThis.__usagestat_plugin = {id:"vercel",probe(ctx) {
|
|
198
|
+
const selected=ctx.provider?.settings?.personalBudget;
|
|
199
|
+
if(selected!==undefined && typeof selected!=='boolean') throw new Error('personalBudget must be a boolean.');
|
|
200
|
+
return (selected===true ? budget : credits).probe(ctx);
|
|
201
|
+
}};
|
|
202
|
+
})();
|
|
@@ -11,13 +11,44 @@
|
|
|
11
11
|
"autoMode": "api",
|
|
12
12
|
"usageDashboardUrl": "https://vercel.com/d?to=%2F%5Bteam%5D%2F%7E%2Fai-gateway",
|
|
13
13
|
"envVars": [
|
|
14
|
-
"AI_GATEWAY_API_KEY"
|
|
14
|
+
"AI_GATEWAY_API_KEY",
|
|
15
|
+
"VERCEL_ACCESS_TOKEN",
|
|
16
|
+
"VERCEL_TEAM_ID"
|
|
17
|
+
],
|
|
18
|
+
"setupFields": [
|
|
19
|
+
{
|
|
20
|
+
"key": "personalBudget",
|
|
21
|
+
"title": "Read personal budget",
|
|
22
|
+
"type": "boolean",
|
|
23
|
+
"description": "Use a Vercel access token and Team ID instead of AI Gateway key credits."
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"key": "VERCEL_ACCESS_TOKEN",
|
|
27
|
+
"title": "Vercel access token",
|
|
28
|
+
"type": "string",
|
|
29
|
+
"description": "Separate account token; the AI Gateway API key is not used for budgets."
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"key": "VERCEL_TEAM_ID",
|
|
33
|
+
"title": "Team ID",
|
|
34
|
+
"type": "string",
|
|
35
|
+
"description": "Team ID or slug whose personal budget belongs to the token user."
|
|
36
|
+
}
|
|
15
37
|
],
|
|
16
38
|
"upstream": {
|
|
17
39
|
"repository": "https://github.com/steipete/CodexBar",
|
|
18
|
-
"revision": "
|
|
40
|
+
"revision": "6070b29a1a5d51193a634dc1b0a14a67c39d0ccc",
|
|
19
41
|
"path": "Sources/CodexBarCore/Resources/Plugins/vercel.js",
|
|
20
42
|
"sha256": "27b39f42709e93a2cfbf850171f198069553c99967f9b7ba6d16614862cb084a",
|
|
21
43
|
"license": "MIT"
|
|
22
|
-
}
|
|
44
|
+
},
|
|
45
|
+
"upstreamSources": [
|
|
46
|
+
{
|
|
47
|
+
"repository": "https://github.com/steipete/CodexBar",
|
|
48
|
+
"revision": "6070b29a1a5d51193a634dc1b0a14a67c39d0ccc",
|
|
49
|
+
"path": "Sources/CodexBarCore/Resources/Plugins/vercel-budget.js",
|
|
50
|
+
"sha256": "a65d3affe808517590edc33e4d15b813ba1fa870b4435ef18cb7c7195ab376ad",
|
|
51
|
+
"license": "MIT"
|
|
52
|
+
}
|
|
53
|
+
]
|
|
23
54
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor" fill-rule="evenodd"><path d="M18.777 1.647c.28-.02.536.114.972.51 1.018.926 2.437 2.828 3.318 4.452l.34.631.482.24.11.06v3.638a5.206 5.206 0 00-5.32-1.23c-.491.166-1.021.471-2.08 1.082l-6.09 3.516c-1.057.61-1.586.916-1.975 1.259a5.208 5.208 0 00-1.493 5.572c.165.49.471 1.02 1.082 2.08l.315.543h-3.26c-.685 0-1.34-.135-1.939-.377-.169-.956-.009-1.789.469-2.335.158-.18.164-.189.13-.493a11.846 11.846 0 01-.057-1.711l.02-.444-.667-1.18C2.1 15.622 1.445 14.078 1.192 12.9c-.133-.647-.125-.934.04-1.146.1-.128.427-.261.822-.334.994-.175 3.162-.017 5.575.41l.25.043.551-.487c.915-.81 1.522-1.264 2.641-1.962 1.167-.73 2.484-1.331 3.967-1.807l.476-.152.261-.688c.937-2.471 1.896-4.293 2.58-4.9.235-.21.25-.22.422-.23z"/><path d="M12.139 18.2a1.203 1.203 0 011.642.44l1.296 2.243a1.204 1.204 0 01-2.083 1.203l-1.296-2.243a1.203 1.203 0 01.44-1.644zM18.629 14.452a1.203 1.203 0 011.642.44l1.295 2.244a1.203 1.203 0 11-2.083 1.203l-1.295-2.243a1.203 1.203 0 01.44-1.644z"/></svg>
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// Generated by tools/vendor-codexbar-providers.cjs; see LICENSE.
|
|
2
2
|
globalThis.__usagestat_bundled_options = {"labels":["Credits","Credits","Additional"],"defaults":{},"autoMode":"web"};
|
|
3
|
+
(function(defineProvider) {
|
|
4
|
+
// BEGIN UPSTREAM Sources/CodexBarCore/Resources/Plugins/workbuddy.js
|
|
3
5
|
function _nullishCoalesce(lhs, rhsFn) {
|
|
4
6
|
if (lhs != null) {
|
|
5
7
|
return lhs;
|
|
@@ -93,7 +95,7 @@ defineProvider({
|
|
|
93
95
|
return object(root.data, "data");
|
|
94
96
|
};
|
|
95
97
|
|
|
96
|
-
// Cycle timestamps carry no zone
|
|
98
|
+
// Cycle timestamps carry no zone; WorkBuddy uses China Standard Time.
|
|
97
99
|
const cycleEnd = (value) => {
|
|
98
100
|
const raw = text(value);
|
|
99
101
|
if (!raw) return undefined;
|
|
@@ -159,11 +161,11 @@ defineProvider({
|
|
|
159
161
|
if (end && end.getTime() > now && (!earliest || end.getTime() < earliest.getTime())) earliest = end;
|
|
160
162
|
}
|
|
161
163
|
} catch (error) {
|
|
162
|
-
|
|
163
|
-
if (failure.transportClass === "cancelled") throw error;
|
|
164
|
+
if (error.transportClass === "cancelled") throw error;
|
|
164
165
|
}
|
|
166
|
+
// Paid cycles refill the allowance; free grants may expire earlier.
|
|
167
|
+
if (earliest) return earliest;
|
|
165
168
|
}
|
|
166
|
-
return earliest;
|
|
167
169
|
};
|
|
168
170
|
|
|
169
171
|
let rejected = false;
|
|
@@ -225,3 +227,6 @@ defineProvider({
|
|
|
225
227
|
);
|
|
226
228
|
},
|
|
227
229
|
});
|
|
230
|
+
|
|
231
|
+
// END UPSTREAM
|
|
232
|
+
})(globalThis.defineProvider);
|
|
@@ -16,6 +16,24 @@
|
|
|
16
16
|
],
|
|
17
17
|
"setupHelp": "Use a Cookie header from www.workbuddy.cn and the full User-Agent from the same browser. Set Browser User-Agent below. Desktop login files are not imported.",
|
|
18
18
|
"setupFields": [
|
|
19
|
+
{
|
|
20
|
+
"key": "webTimeoutSeconds",
|
|
21
|
+
"title": "Web timeout",
|
|
22
|
+
"type": "string",
|
|
23
|
+
"description": "Provider-specific account or source selection."
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"key": "resetDeadlineMillis",
|
|
27
|
+
"title": "Reset lookup deadline",
|
|
28
|
+
"type": "string",
|
|
29
|
+
"description": "Provider-specific account or source selection."
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"key": "chromeMajorVersion",
|
|
33
|
+
"title": "Chrome major version",
|
|
34
|
+
"type": "string",
|
|
35
|
+
"description": "Provider-specific account or source selection."
|
|
36
|
+
},
|
|
19
37
|
{
|
|
20
38
|
"key": "browserUserAgent",
|
|
21
39
|
"title": "Browser User-Agent",
|
|
@@ -25,9 +43,9 @@
|
|
|
25
43
|
],
|
|
26
44
|
"upstream": {
|
|
27
45
|
"repository": "https://github.com/steipete/CodexBar",
|
|
28
|
-
"revision": "
|
|
46
|
+
"revision": "6070b29a1a5d51193a634dc1b0a14a67c39d0ccc",
|
|
29
47
|
"path": "Sources/CodexBarCore/Resources/Plugins/workbuddy.js",
|
|
30
|
-
"sha256": "
|
|
48
|
+
"sha256": "9da73ec195a174e3ee96e3096a47db0b69295bc52dcfceb9fd9d1a2b8f74b08a",
|
|
31
49
|
"license": "MIT"
|
|
32
50
|
}
|
|
33
51
|
}
|
package/plugins/xai/plugin.js
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
function env(ctx, name) {
|
|
15
|
+
if (ctx.provider && ctx.provider.instanceId && ctx.provider.instanceId !== 'xai') return null;
|
|
15
16
|
try {
|
|
16
17
|
return clean(ctx.host.env.get(name));
|
|
17
18
|
} catch (_) {
|
|
@@ -135,6 +136,14 @@
|
|
|
135
136
|
});
|
|
136
137
|
var balance = balanceUsd(balanceJson.total && balanceJson.total.val);
|
|
137
138
|
var metrics = [ctx.line.text({ label: "Balance", value: balance < 0 ? "Deficit: $" + (-balance).toFixed(2) : "$" + balance.toFixed(2) })];
|
|
139
|
+
try {
|
|
140
|
+
var preview = ctx.util.requestJson({method:'GET',url:BASE_URL+'/v1/billing/teams/'+encodeURIComponent(id)+'/postpaid/invoice/preview',
|
|
141
|
+
headers:{Authorization:'Bearer '+key,Accept:'application/json'},timeoutMs:5000});
|
|
142
|
+
var cents = preview.json && preview.json.coreInvoice && preview.json.coreInvoice.amountAfterVat;
|
|
143
|
+
if (preview.resp.status>=200 && preview.resp.status<300 && typeof cents==='string' && /^-?\d+$/.test(cents) && Number.isSafeInteger(Number(cents)))
|
|
144
|
+
metrics.push(ctx.line.text({label:'Live remaining (est.)',value:'$'+(balance-Number(cents)/100).toFixed(2),
|
|
145
|
+
subtitle:'Prepaid balance less the current invoice preview; not a settled charge.'}));
|
|
146
|
+
} catch (_) {ctx.host.log.warn('xAI invoice preview unavailable');}
|
|
138
147
|
|
|
139
148
|
var daily = fetchDaily(ctx, key, id);
|
|
140
149
|
if (daily.length) {
|