@hashimkarim/usagestat-linux-x64-gnu 2.1.0 → 2.2.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.
Files changed (81) hide show
  1. package/native-manifest.json +197 -89
  2. package/package.json +19 -1
  3. package/plugins/abliteration/plugin.json +1 -1
  4. package/plugins/aerostack/plugin.json +1 -1
  5. package/plugins/aixy/plugin.json +1 -1
  6. package/plugins/atlascloud/plugin.json +1 -1
  7. package/plugins/bifrost/plugin.json +1 -1
  8. package/plugins/chatbox/plugin.json +1 -1
  9. package/plugins/claudeplatform/plugin.json +1 -1
  10. package/plugins/codex/plugin.js +11 -6
  11. package/plugins/codex/plugin.json +10 -1
  12. package/plugins/cosmic/plugin.json +1 -1
  13. package/plugins/cursor/plugin.js +18 -6
  14. package/plugins/devpass/plugin.json +1 -1
  15. package/plugins/exa/plugin.json +1 -1
  16. package/plugins/fal/plugin.json +1 -1
  17. package/plugins/flora/plugin.json +1 -1
  18. package/plugins/futureagi/plugin.json +1 -1
  19. package/plugins/gemini-apps/plugin.json +1 -1
  20. package/plugins/gitkraken/plugin.json +1 -1
  21. package/plugins/googledeveloper/LICENSE +21 -0
  22. package/plugins/googledeveloper/icon.svg +3 -0
  23. package/plugins/googledeveloper/plugin.js +204 -0
  24. package/plugins/googledeveloper/plugin.json +25 -0
  25. package/plugins/helmcode/plugin.js +80 -23
  26. package/plugins/helmcode/plugin.json +2 -2
  27. package/plugins/huggingface/plugin.json +1 -1
  28. package/plugins/hyper/plugin.json +1 -1
  29. package/plugins/jetbrains-ai-assistant/LICENSE +22 -0
  30. package/plugins/jetbrains-ai-assistant/plugin.js +502 -16
  31. package/plugins/jetbrains-ai-assistant/plugin.json +27 -4
  32. package/plugins/kimi/plugin.js +16 -1
  33. package/plugins/kimi/plugin.json +46 -6
  34. package/plugins/langdock/plugin.json +1 -1
  35. package/plugins/linkup/plugin.json +1 -1
  36. package/plugins/lithosai/plugin.json +1 -1
  37. package/plugins/llmman/plugin.json +1 -1
  38. package/plugins/munito/plugin.json +1 -1
  39. package/plugins/muse/plugin.json +1 -1
  40. package/plugins/museai/plugin.js +5 -3
  41. package/plugins/museai/plugin.json +2 -2
  42. package/plugins/nous/plugin.json +1 -1
  43. package/plugins/opencode-go/plugin.js +4 -3
  44. package/plugins/opendesign/LICENSE +21 -0
  45. package/plugins/opendesign/icon.svg +4 -0
  46. package/plugins/opendesign/plugin.js +108 -0
  47. package/plugins/opendesign/plugin.json +25 -0
  48. package/plugins/parallel/plugin.json +1 -1
  49. package/plugins/perplexity/LICENSE +22 -0
  50. package/plugins/perplexity/plugin.js +122 -0
  51. package/plugins/perplexity/plugin.json +36 -7
  52. package/plugins/qwencloud/plugin.json +1 -1
  53. package/plugins/raycast/plugin.json +1 -1
  54. package/plugins/replicate/plugin.json +1 -1
  55. package/plugins/sailresearch/plugin.json +1 -1
  56. package/plugins/siliconflow/LICENSE +21 -0
  57. package/plugins/siliconflow/icon.svg +3 -0
  58. package/plugins/siliconflow/plugin.js +87 -0
  59. package/plugins/siliconflow/plugin.json +32 -0
  60. package/plugins/sofya/plugin.json +1 -1
  61. package/plugins/soniox/plugin.json +1 -1
  62. package/plugins/synthetic/plugin.js +12 -0
  63. package/plugins/synthetic/plugin.json +51 -9
  64. package/plugins/tavily/plugin.json +1 -1
  65. package/plugins/tinyapi/plugin.json +1 -1
  66. package/plugins/traecn/plugin.js +10 -11
  67. package/plugins/traecn/plugin.json +2 -2
  68. package/plugins/tripo/LICENSE +21 -0
  69. package/plugins/tripo/icon.svg +4 -0
  70. package/plugins/tripo/plugin.js +60 -0
  71. package/plugins/tripo/plugin.json +24 -0
  72. package/plugins/typesafe/plugin.js +63 -112
  73. package/plugins/typesafe/plugin.json +2 -2
  74. package/plugins/v0/plugin.json +1 -1
  75. package/plugins/vercel/plugin.json +2 -2
  76. package/plugins/workbuddy/plugin.js +103 -17
  77. package/plugins/workbuddy/plugin.json +14 -2
  78. package/plugins/xapi/plugin.json +1 -1
  79. package/plugins/xkiro/plugin.json +1 -1
  80. package/usagestat +0 -0
  81. package/usagestatd +0 -0
@@ -104,6 +104,14 @@
104
104
  })
105
105
  }
106
106
 
107
+ function monthlyBreakdown(ctx, lines, total, code) {
108
+ for (let i=lines.length-1;i>=0;i--) if (["Monthly Kimi Code","Monthly other features"].includes(lines[i].label)) lines.splice(i,1)
109
+ if (!Number.isFinite(total) || total < 0 || !Number.isFinite(code) || code < 0) return
110
+ const percent = value => value > 0 && value < .01 ? "<1% used" : Math.round(Math.min(1,value)*100)+"% used"
111
+ lines.push(ctx.line.text({label:"Monthly Kimi Code",value:percent(code)}),
112
+ ctx.line.text({label:"Monthly other features",value:percent(Math.max(0,total-code))}))
113
+ }
114
+
107
115
  function enrichMembership(ctx, result, token) {
108
116
  if (!token || ctx.provider.settings && ctx.provider.settings.cookieSource === "off") return result
109
117
  try {
@@ -122,7 +130,11 @@
122
130
  if (ratio >= 1) {
123
131
  if (existing >= 0) result.lines.splice(existing,1)
124
132
  result.lines.unshift(monthly)
125
- } else if (existing < 0) result.lines.push(monthly)
133
+ monthlyBreakdown(ctx,result.lines,ratio,readNumber(pool.kimiCodeUsedRatio))
134
+ } else if (existing < 0) {
135
+ result.lines.push(monthly)
136
+ monthlyBreakdown(ctx,result.lines,ratio,readNumber(pool.kimiCodeUsedRatio))
137
+ }
126
138
  }
127
139
  const weekly = data.ratelimitCode7d
128
140
  const weeklyRatio = weekly && readNumber(weekly.ratio)
@@ -355,6 +367,9 @@
355
367
  } else if (previous >= 0) lines[previous] = line
356
368
  else lines.push(line)
357
369
  }
370
+ if (lines.some(line => line.label === "Monthly")) {
371
+ monthlyBreakdown(ctx,lines,readNumber(data.usages?.limit_month_total?.used_ratio),readNumber(data.usages?.limit_month_code?.used_ratio))
372
+ }
358
373
  const result = enrichMembership(ctx, {source,plan:parsePlanLabel(data),lines}, token)
359
374
  if (result.lines.length === 0) throw "Kimi usage response did not contain measurable quota counters."
360
375
  return result
@@ -6,13 +6,53 @@
6
6
  "entry": "plugin.js",
7
7
  "icon": "icon.svg",
8
8
  "brandColor": "#000000",
9
- "supportedModes": ["api", "oauth", "cli", "web"],
9
+ "supportedModes": [
10
+ "api",
11
+ "oauth",
12
+ "cli",
13
+ "web"
14
+ ],
10
15
  "autoMode": "oauth",
11
- "envVars": ["KIMI_CODE_API_KEY", "KIMI_CODE_HOME", "KIMI_CODE_BASE_URL", "KIMI_CODE_OAUTH_HOST", "KIMI_OAUTH_HOST", "KIMI_AUTH_TOKEN"],
16
+ "envVars": [
17
+ "KIMI_CODE_API_KEY",
18
+ "KIMI_CODE_HOME",
19
+ "KIMI_CODE_BASE_URL",
20
+ "KIMI_CODE_OAUTH_HOST",
21
+ "KIMI_OAUTH_HOST",
22
+ "KIMI_AUTH_TOKEN"
23
+ ],
12
24
  "lines": [
13
- { "type": "progress", "label": "Session", "scope": "overview", "primaryOrder": 1 },
14
- { "type": "progress", "label": "Weekly", "scope": "overview", "primaryOrder": 2 },
15
- { "type": "progress", "label": "Monthly", "scope": "overview" },
16
- { "type": "progress", "label": "Code 7-day", "scope": "detail" }
25
+ {
26
+ "type": "progress",
27
+ "label": "Session",
28
+ "scope": "overview",
29
+ "primaryOrder": 1
30
+ },
31
+ {
32
+ "type": "progress",
33
+ "label": "Weekly",
34
+ "scope": "overview",
35
+ "primaryOrder": 2
36
+ },
37
+ {
38
+ "type": "progress",
39
+ "label": "Monthly",
40
+ "scope": "overview"
41
+ },
42
+ {
43
+ "type": "progress",
44
+ "label": "Code 7-day",
45
+ "scope": "detail"
46
+ },
47
+ {
48
+ "type": "text",
49
+ "label": "Monthly Kimi Code",
50
+ "scope": "detail"
51
+ },
52
+ {
53
+ "type": "text",
54
+ "label": "Monthly other features",
55
+ "scope": "detail"
56
+ }
17
57
  ]
18
58
  }
@@ -17,7 +17,7 @@
17
17
  "setupFields": [],
18
18
  "upstream": {
19
19
  "repository": "https://github.com/steipete/CodexBar",
20
- "revision": "6070b29a1a5d51193a634dc1b0a14a67c39d0ccc",
20
+ "revision": "1f6da9bec44455288ddee5ef6f3617a803d8eb2a",
21
21
  "path": "Sources/CodexBarCore/Resources/Plugins/langdock.js",
22
22
  "sha256": "c950eb7566aea322bba26fc97735a7ba688b6cfb7fa6a5e06a2e0cb6fff6f831",
23
23
  "license": "MIT"
@@ -16,7 +16,7 @@
16
16
  "setupFields": [],
17
17
  "upstream": {
18
18
  "repository": "https://github.com/steipete/CodexBar",
19
- "revision": "6070b29a1a5d51193a634dc1b0a14a67c39d0ccc",
19
+ "revision": "1f6da9bec44455288ddee5ef6f3617a803d8eb2a",
20
20
  "path": "Sources/CodexBarCore/Resources/Plugins/linkup.js",
21
21
  "sha256": "7857c63217818a2a9935397a8fe70621b42ab17115a43da2eab6b4a0ea27b775",
22
22
  "license": "MIT"
@@ -18,7 +18,7 @@
18
18
  "setupFields": [],
19
19
  "upstream": {
20
20
  "repository": "https://github.com/steipete/CodexBar",
21
- "revision": "6070b29a1a5d51193a634dc1b0a14a67c39d0ccc",
21
+ "revision": "1f6da9bec44455288ddee5ef6f3617a803d8eb2a",
22
22
  "path": "Sources/CodexBarCore/Resources/Plugins/lithosai.js",
23
23
  "sha256": "11f83683e93728e8d35ae6d9852b854d6f8db9dee2b0b293e5899089216b01ff",
24
24
  "license": "MIT"
@@ -23,7 +23,7 @@
23
23
  ],
24
24
  "upstream": {
25
25
  "repository": "https://github.com/steipete/CodexBar",
26
- "revision": "6070b29a1a5d51193a634dc1b0a14a67c39d0ccc",
26
+ "revision": "1f6da9bec44455288ddee5ef6f3617a803d8eb2a",
27
27
  "path": "Sources/CodexBarCore/Resources/Plugins/llmman.js",
28
28
  "sha256": "eb48d35bb101fda0e3bf122eea358c6e16ea937ac72376e6e4ede52e7828d209",
29
29
  "license": "MIT"
@@ -16,7 +16,7 @@
16
16
  "setupFields": [],
17
17
  "upstream": {
18
18
  "repository": "https://github.com/steipete/CodexBar",
19
- "revision": "6070b29a1a5d51193a634dc1b0a14a67c39d0ccc",
19
+ "revision": "1f6da9bec44455288ddee5ef6f3617a803d8eb2a",
20
20
  "path": "Sources/CodexBarCore/Resources/Plugins/munito.js",
21
21
  "sha256": "6feee407bd3765acb723bca995e660ee9dc8d556e51bfdff158686e3ffaf0ffe",
22
22
  "license": "MIT"
@@ -26,7 +26,7 @@
26
26
  ],
27
27
  "upstream": {
28
28
  "repository": "https://github.com/steipete/CodexBar",
29
- "revision": "6070b29a1a5d51193a634dc1b0a14a67c39d0ccc",
29
+ "revision": "1f6da9bec44455288ddee5ef6f3617a803d8eb2a",
30
30
  "path": "Sources/CodexBarCore/Resources/Plugins/muse.js",
31
31
  "sha256": "85b6f9489f4e004d027cca1fe2a0a87884792d0be7aa50ef7b8df3b17902c424",
32
32
  "license": "MIT"
@@ -17,7 +17,8 @@ defineProvider({
17
17
  if (policy === "off") throw ctx.fail.missingCredential("muse.ai cookies are disabled.");
18
18
  const signedOut = (r) =>
19
19
  r.status === 401 || r.status === 403 || (r.headers["location"] ?? "").startsWith("https://auth.muse.ai/");
20
- const staleAction = (r) => r.status === 404 && /server action not found/i.test(r.bodyText);
20
+ // A redeployed muse.ai answers a stale action with 400, 404 or 409 (#5051).
21
+ const actionNeedsRediscovery = (r) => !signedOut(r) && [400, 404, 409].includes(r.status);
21
22
  const discoveryFailure = () =>
22
23
  ctx.fail.parseFailure(
23
24
  "Could not find a working muse.ai subscription action. muse.ai may have changed. Refresh to retry.",
@@ -34,6 +35,7 @@ defineProvider({
34
35
  "Sec-Fetch-Site": "same-origin",
35
36
  "Sec-Fetch-Mode": "cors",
36
37
  "Sec-Fetch-Dest": "empty",
38
+ "Content-Type": "text/plain;charset=UTF-8",
37
39
  "User-Agent": userAgent,
38
40
  },
39
41
  });
@@ -84,14 +86,14 @@ defineProvider({
84
86
  let actionID = ctx.storage.get("actionID");
85
87
  const subscription = async (cookie) => {
86
88
  const response = actionID ? await post(cookie, actionID) : undefined;
87
- if (response && !staleAction(response)) {
89
+ if (response && !actionNeedsRediscovery(response)) {
88
90
  return signedOut(response) ? undefined : response;
89
91
  }
90
92
  ctx.storage.remove("actionID");
91
93
  actionID = await discover(cookie);
92
94
  if (!actionID) return undefined;
93
95
  const fresh = await post(cookie, actionID);
94
- if (staleAction(fresh)) throw discoveryFailure();
96
+ if (actionNeedsRediscovery(fresh)) throw discoveryFailure();
95
97
  return signedOut(fresh) ? undefined : fresh;
96
98
  };
97
99
 
@@ -18,9 +18,9 @@
18
18
  "setupFields": [],
19
19
  "upstream": {
20
20
  "repository": "https://github.com/steipete/CodexBar",
21
- "revision": "6070b29a1a5d51193a634dc1b0a14a67c39d0ccc",
21
+ "revision": "1f6da9bec44455288ddee5ef6f3617a803d8eb2a",
22
22
  "path": "Sources/CodexBarCore/Resources/Plugins/museai.js",
23
- "sha256": "ab325a1b6cff46bbe347d98340d9212cab732f6b48c0d2ae5c6d955824ac5019",
23
+ "sha256": "fa82f1936a5b59e16aab91d42e3c3591d3f6b50d65017557a341924095234f1d",
24
24
  "license": "MIT"
25
25
  }
26
26
  }
@@ -24,7 +24,7 @@
24
24
  ],
25
25
  "upstream": {
26
26
  "repository": "https://github.com/steipete/CodexBar",
27
- "revision": "6070b29a1a5d51193a634dc1b0a14a67c39d0ccc",
27
+ "revision": "1f6da9bec44455288ddee5ef6f3617a803d8eb2a",
28
28
  "path": "Sources/CodexBarCore/Resources/Plugins/nous.js",
29
29
  "sha256": "160f5329bf4895a061d3bed74d0476283d3abad47e071fb868d667c0c5cb485e",
30
30
  "license": "MIT"
@@ -15,8 +15,9 @@
15
15
  const TABLES_SQL = "SELECT name FROM sqlite_master WHERE type = 'table' AND name IN ('message','session_message','credential','migration')";
16
16
  const CREDENTIALS_IMPORTED_SQL = "SELECT 1 AS imported FROM migration WHERE id = '20260805200742_import_legacy_credentials' LIMIT 1";
17
17
  const CREDENTIAL_SQL = `SELECT value FROM credential
18
- WHERE integration_id = 'opencode-go' AND (active IS NULL OR active = 1)
19
- ORDER BY active DESC, time_updated DESC, id DESC LIMIT 1`;
18
+ WHERE (integration_id = 'opencode-go' AND (active IS NULL OR active = 1))
19
+ OR (integration_id = 'opencode' AND active = 1)
20
+ ORDER BY CASE integration_id WHEN 'opencode-go' THEN 0 ELSE 1 END, active DESC, time_updated DESC, id DESC LIMIT 1`;
20
21
  function historySQL(tables) {
21
22
  const sources = [];
22
23
  if (tables.includes('session_message')) sources.push(`SELECT id, time_created, data FROM session_message
@@ -367,7 +368,7 @@
367
368
  if (inline) throw {code: "credential-malformed", message: "OPENCODE_AUTH_CONTENT must contain an auth JSON object."};
368
369
  throw {code:'credential-malformed',message:'OpenCode auth file is not valid JSON.'};
369
370
  }
370
- const entry = parsed[PROVIDER_ID];
371
+ const entry = parsed[PROVIDER_ID] || parsed.opencode;
371
372
  if (!entry || typeof entry !== "object") return null;
372
373
  const key = typeof entry.key === "string" ? entry.key.trim() : "";
373
374
  return key || null;
@@ -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,4 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="100 100 385 385" fill="currentColor">
2
+ <path fill-rule="evenodd" d="M292.716 112.374C392.751 112.374 473.845 193.468 473.845 293.503C473.845 393.538 392.751 474.632 292.716 474.632H135.685C122.347 474.632 111.587 463.874 111.587 450.536C111.587 410.139 111.587 329.633 111.587 293.503C111.587 193.468 192.681 112.374 292.716 112.374ZM292.716 148.6C212.689 148.6 147.813 213.476 147.813 293.504C147.813 373.532 212.689 438.407 292.716 438.407C372.744 438.407 437.619 373.532 437.619 293.504C437.619 213.476 372.744 148.6 292.716 148.6Z"/>
3
+ <path d="M281.618 378.232L226.395 232.908C224.608 228.205 229.201 223.594 233.873 225.402L379.265 281.651C385.249 283.966 383.6 292.898 377.189 292.898H292.803V376.155C292.803 382.61 283.91 384.262 281.618 378.232Z"/>
4
+ </svg>
@@ -0,0 +1,108 @@
1
+ // Generated by tools/vendor-codexbar-providers.cjs; see LICENSE.
2
+ globalThis.__usagestat_bundled_options = {"labels":["Session","Weekly","Additional"],"defaults":{},"autoMode":"web"};
3
+ (function(defineProvider) {
4
+ // BEGIN UPSTREAM Sources/CodexBarCore/Resources/Plugins/opendesign.js
5
+ defineProvider({
6
+ id: "opendesign",
7
+ name: "OpenDesign",
8
+ settings: [{ key: "MESSAGES", title: "OpenDesign", type: "plain" }],
9
+ endpoints: ["https://amr-api.open-design.ai"],
10
+ capabilities: ["browser-cookies", "http-status"],
11
+ cookieDomains: ["amr-api.open-design.ai"],
12
+ cookiePolicy: {
13
+ selection: "request-url",
14
+ cache: "nonpersistent",
15
+ imports: "access-gated",
16
+ // The host's optional name filter excludes dots; validate the opaque session at the endpoint.
17
+ },
18
+ async fetchUsage(ctx) {
19
+ const domain = "amr-api.open-design.ai";
20
+ const messages = JSON.parse(ctx.settings.get("MESSAGES") || "{}");
21
+ const message = (key) => messages[key] || key;
22
+ const signIn = message("Sign in to OpenDesign, then refresh CodexBar.");
23
+ const expired = ctx.fail.authenticationExpired(signIn);
24
+ const malformed = () => {
25
+ throw ctx.fail.parseFailure(message("OpenDesign usage response format changed."));
26
+ };
27
+ const text = (value) => (typeof value === "string" && value.trim() ? value.trim() : undefined);
28
+ const credits = (value) => {
29
+ if (typeof value === "string" && /^\d+(\.\d+)?$/.test(value)) value = Number(value);
30
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 && value <= Number.MAX_SAFE_INTEGER
31
+ ? value
32
+ : malformed();
33
+ };
34
+ if (ctx.browser.availability(domain) === "off") throw ctx.fail.missingCredential(signIn);
35
+ let rejected = false;
36
+ for await (const session of ctx.browser.sessions(domain)) {
37
+ const get = async (path, workspace) => {
38
+ const response = await ctx.http.get(`https://${domain}/api/v1/workspaces/${path}`, {
39
+ cookieSession: session.id,
40
+ headers: { Accept: "application/json", ...(workspace ? { "X-Vela-Workspace-Id": workspace } : {}) },
41
+ });
42
+ if (response.status === 401) throw expired;
43
+ if (response.status === 403) throw ctx.fail.permissionDenied(message("OpenDesign billing access was denied."));
44
+ const failed = message("OpenDesign request failed. Try again later.");
45
+ if (response.status === 429) throw ctx.fail.rateLimited(failed);
46
+ if (response.status >= 500 || response.status === 408) throw ctx.fail.providerUnavailable(failed);
47
+ if (response.status !== 200) throw ctx.fail.apiFailure(failed);
48
+ try {
49
+ return JSON.parse(response.bodyText);
50
+ } catch {
51
+ return malformed();
52
+ }
53
+ };
54
+ try {
55
+ const workspace = await get("current");
56
+ const id = text(workspace?.workspaceId);
57
+ if (!id || !/^[A-Za-z0-9_-]{1,128}$/.test(id)) return malformed();
58
+ const usage = await get(`${id}/billing/coding-plan-usage`, id);
59
+ if (usage?.workspaceId !== id || typeof usage.eligible !== "boolean" || !Array.isArray(usage.windows))
60
+ return malformed();
61
+ const unavailable = () => {
62
+ throw ctx.fail.providerUnavailable(
63
+ message("OpenDesign subscription usage is unavailable for this workspace."),
64
+ );
65
+ };
66
+ if (!usage.eligible) return unavailable();
67
+ const window = (seconds) => {
68
+ const matches = usage.windows.filter((item) => item?.durationSeconds === seconds);
69
+ if (matches.length === 0) return undefined;
70
+ if (matches.length !== 1) return malformed();
71
+ const item = matches[0];
72
+ const used = credits(item.usedCredits);
73
+ const limit = credits(item.limitCredits);
74
+ if (limit <= 0) return malformed();
75
+ const reset = text(item.resetsAt);
76
+ return {
77
+ usedPercent: ctx.pct(used, limit),
78
+ windowMinutes: seconds / 60,
79
+ quotaLimit: limit,
80
+ quotaUnit: "credits",
81
+ resetsAt:
82
+ reset && /^\d{4}-\d{2}-\d{2}T/.test(reset) && Number.isFinite(Date.parse(reset)) ? reset : undefined,
83
+ };
84
+ };
85
+ const primary = window(18000);
86
+ const secondary = window(604800);
87
+ if (!primary && !secondary) return unavailable();
88
+ return {
89
+ primary,
90
+ secondary,
91
+ identity: {
92
+ accountID: id,
93
+ organization: text(workspace.workspaceName),
94
+ loginMethod: text(usage.tier) ?? text(workspace.personalMembershipTier),
95
+ },
96
+ };
97
+ } catch (error) {
98
+ if (error !== expired) throw error;
99
+ ctx.browser.rejectCookie(domain, session);
100
+ rejected = true;
101
+ }
102
+ }
103
+ throw rejected ? expired : ctx.fail.missingCredential(signIn);
104
+ },
105
+ });
106
+
107
+ // END UPSTREAM
108
+ })(globalThis.defineProvider);
@@ -0,0 +1,25 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "id": "opendesign",
4
+ "name": "OpenDesign",
5
+ "version": "0.1.0",
6
+ "entry": "plugin.js",
7
+ "enabledByDefault": false,
8
+ "supportedModes": [
9
+ "web"
10
+ ],
11
+ "autoMode": "web",
12
+ "usageDashboardUrl": "https://open-design.ai",
13
+ "webUrl": "https://amr-api.open-design.ai",
14
+ "envVars": [
15
+ "OPENDESIGN_COOKIE"
16
+ ],
17
+ "setupFields": [],
18
+ "upstream": {
19
+ "repository": "https://github.com/steipete/CodexBar",
20
+ "revision": "1f6da9bec44455288ddee5ef6f3617a803d8eb2a",
21
+ "path": "Sources/CodexBarCore/Resources/Plugins/opendesign.js",
22
+ "sha256": "9eb64161b779de122e6343eb166ee6ebca6d3e828dc7e40df7a1af695f6a79d4",
23
+ "license": "MIT"
24
+ }
25
+ }
@@ -17,7 +17,7 @@
17
17
  "setupFields": [],
18
18
  "upstream": {
19
19
  "repository": "https://github.com/steipete/CodexBar",
20
- "revision": "6070b29a1a5d51193a634dc1b0a14a67c39d0ccc",
20
+ "revision": "1f6da9bec44455288ddee5ef6f3617a803d8eb2a",
21
21
  "path": "Sources/CodexBarCore/Resources/Plugins/parallel.js",
22
22
  "sha256": "854d5faa2b6c01b96cf009295fabe85cbdc28d07911d7c7e1da970c8cc77e5e8",
23
23
  "license": "MIT"
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Robin Ebers (original macOS creator)
4
+ Copyright (c) 2026 barramee kottanawadee
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
@@ -1,3 +1,4 @@
1
+ // Adapted from barramee27/crossusage at 78b243b798abce1270d6fed775c79e65825b2c33; see LICENSE.
1
2
  (function () {
2
3
  const LOCAL_USER_ENDPOINT = "https://www.perplexity.ai/api/user"
3
4
  const REST_API_BASE = "https://www.perplexity.ai/rest/pplx-api/v2"
@@ -380,7 +381,128 @@
380
381
  return { groupId: groupId, group: group, usageAnalytics: usageAnalytics, rateLimits: rateLimits }
381
382
  }
382
383
 
384
+ // --- Web-session (cookie) auth -------------------------------------------
385
+ // The Bearer flow above only exists on macOS: it scrapes the CFURL cache of
386
+ // the native app. On Windows/Linux there is no Bearer token anywhere — the
387
+ // Electron app and the website both authenticate with next-auth cookies.
388
+ // So accept a pasted session cookie and talk to the same REST API the web
389
+ // client uses.
390
+ const WEB_ORIGIN = "https://www.perplexity.ai"
391
+ const WEB_QS = "?version=2.18&source=default"
392
+ const WEB_UA =
393
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36"
394
+
395
+ const WEB_MODE_CATEGORIES = [
396
+ { key: "pro_search", label: "Queries" },
397
+ { key: "research", label: "Deep Research" },
398
+ { key: "labs", label: "Labs" },
399
+ { key: "agentic_research", label: "Agentic Research" },
400
+ ]
401
+
402
+ function fetchWebJson(ctx, path) {
403
+ let resp
404
+ try {
405
+ resp = ctx.host.http.requestCookieSession({
406
+ method: "GET",
407
+ url: WEB_ORIGIN + path + WEB_QS,
408
+ headers: {
409
+ Accept: "application/json",
410
+ "User-Agent": WEB_UA,
411
+ Origin: WEB_ORIGIN,
412
+ Referer: WEB_ORIGIN + "/account/usage",
413
+ },
414
+ timeoutMs: 10000,
415
+ cookieSession: "configured",
416
+ })
417
+ } catch (e) {
418
+ ctx.host.log.warn("web request failed (" + path + "): " + String(e))
419
+ return null
420
+ }
421
+ if (typeof resp.bodyText === "string" && resp.bodyText.indexOf("Just a moment") !== -1) {
422
+ ctx.host.log.warn("cloudflare challenge on " + path + " — paste the full cookie string incl. cf_clearance")
423
+ return null
424
+ }
425
+ if (ctx.util.isAuthStatus(resp.status)) {
426
+ ctx.host.log.warn("web request unauthorized (" + path + "): status=" + String(resp.status))
427
+ return null
428
+ }
429
+ if (resp.status < 200 || resp.status >= 300) {
430
+ ctx.host.log.warn("web request status " + String(resp.status) + " (" + path + ")")
431
+ return null
432
+ }
433
+ const parsed = ctx.util.tryParseJson(resp.bodyText)
434
+ if (!parsed || typeof parsed !== "object") {
435
+ ctx.host.log.warn("web request returned invalid JSON (" + path + ")")
436
+ return null
437
+ }
438
+ return parsed
439
+ }
440
+
441
+ function describeModeAvailability(mode) {
442
+ if (!mode || typeof mode !== "object") return null
443
+ const detail = mode.remaining_detail || mode.remainingDetail
444
+ if (detail && detail.kind === "exact") {
445
+ const n = Number(detail.remaining)
446
+ if (Number.isFinite(n)) return String(Math.max(0, Math.floor(n))) + " remaining"
447
+ }
448
+ if (mode.available === true) return "available"
449
+ if (mode.available === false) return "not available"
450
+ return null
451
+ }
452
+
453
+ function probeViaCookie(ctx) {
454
+ ctx.host.log.info("session loaded from provider account (web cookie)")
455
+
456
+ const status = fetchWebJson(ctx, "/rest/rate-limit/status")
457
+ const authSession = fetchWebJson(ctx, "/api/auth/session")
458
+ const credits =
459
+ fetchWebJson(ctx, "/rest/billing/credits") ||
460
+ fetchWebJson(ctx, "/rest/billing/credits/computer-submit-gate")
461
+
462
+ if (!status && !authSession && !credits) {
463
+ throw "Session cookie rejected. Re-copy it from a logged-in perplexity.ai tab."
464
+ }
465
+
466
+ const lines = []
467
+
468
+ const balanceCents = credits ? readNumberField(credits, ["balance_cents", "balanceCents"]) : null
469
+ if (balanceCents !== null && Number.isFinite(balanceCents)) {
470
+ lines.push(ctx.line.text({
471
+ label: "API credits",
472
+ value: "$" + (balanceCents / 100).toFixed(2),
473
+ }))
474
+ }
475
+
476
+ const modes = status && (status.modes || status.Modes)
477
+ if (modes && typeof modes === "object") {
478
+ for (let i = 0; i < WEB_MODE_CATEGORIES.length; i += 1) {
479
+ const cat = WEB_MODE_CATEGORIES[i]
480
+ const text = describeModeAvailability(modes[cat.key])
481
+ if (text) lines.push(ctx.line.text({ label: cat.label, value: text }))
482
+ }
483
+ }
484
+
485
+ if (lines.length === 0) throw "Usage data unavailable. Try again later."
486
+
487
+ const user = authSession && authSession.user
488
+ const tier = user && (user.subscription_tier || user.subscriptionTier)
489
+ const plan =
490
+ typeof tier === "string" && tier
491
+ ? tier
492
+ .split("_")
493
+ .filter(Boolean)
494
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
495
+ .join(" ")
496
+ : null
497
+
498
+ return plan ? { plan: plan, lines: lines } : { lines: lines }
499
+ }
500
+
383
501
  function probe(ctx) {
502
+ if (ctx.provider?.settings?.cookies !== "off" && ctx.host.http.cookieSessionAvailable === true) {
503
+ return probeViaCookie(ctx)
504
+ }
505
+
384
506
  const session = loadLocalSession(ctx)
385
507
  if (!session) throw "Not logged in. Sign in via Perplexity app."
386
508
  if (session.sourcePath) ctx.host.log.info("using cache db: " + session.sourcePath)
@@ -6,14 +6,43 @@
6
6
  "entry": "plugin.js",
7
7
  "icon": "icon.svg",
8
8
  "brandColor": "#20808D",
9
- "supportedModes": ["oauth", "local", "web"],
9
+ "supportedModes": [
10
+ "oauth",
11
+ "local",
12
+ "web"
13
+ ],
10
14
  "autoMode": "web",
11
15
  "webUrl": "https://www.perplexity.ai",
12
16
  "lines": [
13
- { "type": "progress", "label": "API credits", "scope": "overview", "primaryOrder": 1 },
14
- { "type": "text", "label": "Queries", "scope": "overview" },
15
- { "type": "text", "label": "Deep Research", "scope": "overview" },
16
- { "type": "text", "label": "Labs", "scope": "detail" },
17
- { "type": "text", "label": "Agentic Research", "scope": "detail" }
18
- ]
17
+ {
18
+ "type": "progress",
19
+ "label": "API credits",
20
+ "scope": "overview",
21
+ "primaryOrder": 1
22
+ },
23
+ {
24
+ "type": "text",
25
+ "label": "Queries",
26
+ "scope": "overview"
27
+ },
28
+ {
29
+ "type": "text",
30
+ "label": "Deep Research",
31
+ "scope": "overview"
32
+ },
33
+ {
34
+ "type": "text",
35
+ "label": "Labs",
36
+ "scope": "detail"
37
+ },
38
+ {
39
+ "type": "text",
40
+ "label": "Agentic Research",
41
+ "scope": "detail"
42
+ }
43
+ ],
44
+ "envVars": [
45
+ "PERPLEXITY_COOKIE"
46
+ ],
47
+ "setupHelp": "Paste a Cookie header from your own perplexity.ai session for web usage. The scoped cookie is sent only to approved Perplexity read routes."
19
48
  }
@@ -29,7 +29,7 @@
29
29
  "upstreamSources": [
30
30
  {
31
31
  "repository": "https://github.com/steipete/CodexBar",
32
- "revision": "6070b29a1a5d51193a634dc1b0a14a67c39d0ccc",
32
+ "revision": "1f6da9bec44455288ddee5ef6f3617a803d8eb2a",
33
33
  "path": "Sources/CodexBarCore/Resources/Plugins/qwencloud-team.js",
34
34
  "sha256": "11a7e231c1705a83f29b4509102abaa656b9888f63cfc132de0a520d94ee9301",
35
35
  "license": "MIT"
@@ -24,7 +24,7 @@
24
24
  ],
25
25
  "upstream": {
26
26
  "repository": "https://github.com/steipete/CodexBar",
27
- "revision": "6070b29a1a5d51193a634dc1b0a14a67c39d0ccc",
27
+ "revision": "1f6da9bec44455288ddee5ef6f3617a803d8eb2a",
28
28
  "path": "Sources/CodexBarCore/Resources/Plugins/raycast.js",
29
29
  "sha256": "df8f6d185cb67fd9ec9b622d2321a6d4e5395576b9ab54b1725aac272c95ecb7",
30
30
  "license": "MIT"