@leo000001/opencode-quota-sidebar 3.0.1 → 3.0.2

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 (41) hide show
  1. package/CHANGELOG.md +14 -2
  2. package/CONTRIBUTING.md +4 -1
  3. package/README.md +210 -514
  4. package/README.zh-CN.md +337 -0
  5. package/SECURITY.md +2 -2
  6. package/assets/OpenCode-Quota-Sidebar.png +0 -0
  7. package/dist/cost.d.ts +3 -3
  8. package/dist/cost.js +258 -169
  9. package/dist/format.js +10 -3
  10. package/dist/providers/common.d.ts +6 -0
  11. package/dist/providers/common.js +32 -12
  12. package/dist/providers/core/anthropic.d.ts +1 -1
  13. package/dist/providers/core/anthropic.js +43 -39
  14. package/dist/providers/core/kimi_for_coding.d.ts +1 -1
  15. package/dist/providers/core/kimi_for_coding.js +44 -64
  16. package/dist/providers/core/minimax_cn_coding_plan.d.ts +2 -0
  17. package/dist/providers/core/minimax_cn_coding_plan.js +214 -0
  18. package/dist/providers/core/zhipu_coding_plan.d.ts +1 -1
  19. package/dist/providers/core/zhipu_coding_plan.js +41 -61
  20. package/dist/providers/index.d.ts +3 -3
  21. package/dist/providers/index.js +5 -5
  22. package/dist/providers/third_party/rightcode.d.ts +1 -1
  23. package/dist/providers/third_party/rightcode.js +41 -61
  24. package/dist/providers/third_party/xyai.d.ts +2 -0
  25. package/dist/providers/third_party/{xyai_vibe.js → xyai.js} +113 -79
  26. package/dist/quota.d.ts +2 -2
  27. package/dist/quota.js +24 -18
  28. package/dist/quota_render.d.ts +1 -1
  29. package/dist/quota_render.js +23 -17
  30. package/dist/storage_parse.js +1 -0
  31. package/dist/title.js +7 -7
  32. package/dist/title_apply.js +18 -1
  33. package/dist/tui.tsx +2 -1
  34. package/dist/tui_helpers.d.ts +2 -1
  35. package/dist/tui_helpers.js +6 -1
  36. package/dist/types.d.ts +2 -0
  37. package/package.json +9 -2
  38. package/quota-sidebar.config.example.json +45 -45
  39. package/dist/providers/third_party/buzz.d.ts +0 -2
  40. package/dist/providers/third_party/buzz.js +0 -156
  41. package/dist/providers/third_party/xyai_vibe.d.ts +0 -2
package/dist/format.js CHANGED
@@ -219,12 +219,12 @@ function compactProviderLabel(quota) {
219
219
  return 'Kimi';
220
220
  if (canonical === 'zhipuai-coding-plan')
221
221
  return 'Zhipu';
222
+ if (canonical === 'minimax-cn-coding-plan')
223
+ return 'MiniMax';
222
224
  if (canonical === 'rightcode')
223
225
  return 'RC';
224
- if (canonical === 'xyai-vibe')
226
+ if (canonical === 'xyai')
225
227
  return 'XYAI';
226
- if (canonical === 'buzz')
227
- return 'Buzz';
228
228
  return sanitizeLine(quotaDisplayLabel(quota));
229
229
  }
230
230
  function compactWindowToken(label) {
@@ -260,6 +260,13 @@ function compactQuotaPercentToken(label, percent) {
260
260
  return rounded ? `R${rounded}` : '';
261
261
  if (/^sonnet\s+7d$/i.test(safe))
262
262
  return rounded ? `S7d${rounded}` : 'S7d';
263
+ if (/^opus\s+7d$/i.test(safe))
264
+ return rounded ? `O7d${rounded}` : 'O7d';
265
+ if (/^oauth\s+apps\s+7d$/i.test(safe)) {
266
+ return rounded ? `OA7d${rounded}` : 'OA7d';
267
+ }
268
+ if (/^cowork\s+7d$/i.test(safe))
269
+ return rounded ? `Co7d${rounded}` : 'Co7d';
263
270
  const token = compactWindowToken(safe).replace(/\s+/g, '');
264
271
  if (!rounded)
265
272
  return token;
@@ -21,5 +21,11 @@ export declare function configuredProviderEnabled(config: {
21
21
  [key: string]: unknown;
22
22
  }>;
23
23
  }, adapterID: string, fallback?: boolean): boolean;
24
+ export declare function resolveApiKey(auth: {
25
+ type: "oauth" | "api" | "wellknown";
26
+ access?: string;
27
+ key?: string;
28
+ token?: string;
29
+ } | undefined, providerOptions: Record<string, unknown> | undefined): string | undefined;
24
30
  export declare function sanitizeBaseURL(value: unknown): string | undefined;
25
31
  export declare function basePathPrefixes(value: unknown): string[];
@@ -1,8 +1,8 @@
1
- import { asNumber as asNumberShared, isRecord } from '../helpers.js';
1
+ import { asNumber as asNumberShared, isRecord } from "../helpers.js";
2
2
  // Public OAuth client ID embedded in the ChatGPT web app (not a private secret).
3
3
  // Source: https://github.com/vbgate/opencode-mystatus (reverse-engineered from browser client).
4
4
  // If OpenAI rotates this value, update it here or expose it via quota-sidebar.config.json.
5
- export const OPENAI_OAUTH_CLIENT_ID = 'app_EMoamEEZ73f0CkXaXp7hrann';
5
+ export const OPENAI_OAUTH_CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann";
6
6
  export async function fetchWithTimeout(url, init, timeoutMs) {
7
7
  const controller = new AbortController();
8
8
  const timer = setTimeout(() => controller.abort(), timeoutMs);
@@ -30,7 +30,7 @@ export function normalizePercent(value) {
30
30
  return expanded;
31
31
  }
32
32
  export function toIso(value) {
33
- if (typeof value === 'string') {
33
+ if (typeof value === "string") {
34
34
  const time = Date.parse(value);
35
35
  if (!Number.isNaN(time))
36
36
  return new Date(time).toISOString();
@@ -46,7 +46,7 @@ export function toIso(value) {
46
46
  * Derive a human-readable window label from `limit_window_seconds`.
47
47
  * Uses fallback label when the limit is missing.
48
48
  */
49
- export function windowLabel(win, fallback = '') {
49
+ export function windowLabel(win, fallback = "") {
50
50
  const limitSec = asNumber(win.limit_window_seconds);
51
51
  if (limitSec !== undefined && limitSec > 0) {
52
52
  const hours = limitSec / 3600;
@@ -55,9 +55,9 @@ export function windowLabel(win, fallback = '') {
55
55
  const days = hours / 24;
56
56
  if (days <= 6)
57
57
  return `${Math.round(days)}d`;
58
- return 'Weekly';
58
+ return "Weekly";
59
59
  }
60
- return fallback || 'Window';
60
+ return fallback || "Window";
61
61
  }
62
62
  export function parseRateLimitWindow(win, fallbackLabel) {
63
63
  const usedPercent = normalizePercent(win.used_percent);
@@ -77,16 +77,36 @@ export function asRecord(value) {
77
77
  }
78
78
  export function configuredProviderEnabled(config, adapterID, fallback = true) {
79
79
  const enabled = config.providers?.[adapterID]?.enabled;
80
- if (typeof enabled === 'boolean')
80
+ if (typeof enabled === "boolean")
81
81
  return enabled;
82
82
  return fallback;
83
83
  }
84
+ export function resolveApiKey(auth, providerOptions) {
85
+ const optionKey = providerOptions?.apiKey;
86
+ if (typeof optionKey === "string" && optionKey)
87
+ return optionKey;
88
+ if (!auth)
89
+ return undefined;
90
+ if (auth.type === "api" && typeof auth.key === "string" && auth.key) {
91
+ return auth.key;
92
+ }
93
+ if (auth.type === "wellknown") {
94
+ if (typeof auth.key === "string" && auth.key)
95
+ return auth.key;
96
+ if (typeof auth.token === "string" && auth.token)
97
+ return auth.token;
98
+ }
99
+ if (auth.type === "oauth" && typeof auth.access === "string" && auth.access) {
100
+ return auth.access;
101
+ }
102
+ return undefined;
103
+ }
84
104
  export function sanitizeBaseURL(value) {
85
- if (typeof value !== 'string' || !value)
105
+ if (typeof value !== "string" || !value)
86
106
  return undefined;
87
107
  try {
88
108
  const parsed = new URL(value);
89
- const pathname = parsed.pathname.replace(/\/+$/, '') || '/';
109
+ const pathname = parsed.pathname.replace(/\/+$/, "") || "/";
90
110
  return `${parsed.origin}${pathname}`;
91
111
  }
92
112
  catch {
@@ -99,13 +119,13 @@ export function basePathPrefixes(value) {
99
119
  return [];
100
120
  try {
101
121
  const parsed = new URL(sanitized);
102
- const parts = parsed.pathname.split('/').filter(Boolean);
122
+ const parts = parsed.pathname.split("/").filter(Boolean);
103
123
  const prefixes = [];
104
124
  for (let i = parts.length; i >= 1; i--) {
105
- prefixes.push(`/${parts.slice(0, i).join('/')}`);
125
+ prefixes.push(`/${parts.slice(0, i).join("/")}`);
106
126
  }
107
127
  if (prefixes.length === 0)
108
- prefixes.push('/');
128
+ prefixes.push("/");
109
129
  return prefixes;
110
130
  }
111
131
  catch {
@@ -1,2 +1,2 @@
1
- import type { QuotaProviderAdapter } from '../types.js';
1
+ import type { QuotaProviderAdapter } from "../types.js";
2
2
  export declare const anthropicAdapter: QuotaProviderAdapter;
@@ -1,6 +1,14 @@
1
- import { swallow } from '../../helpers.js';
2
- import { asRecord, configuredProviderEnabled, fetchWithTimeout, normalizePercent, toIso, } from '../common.js';
3
- const ANTHROPIC_OAUTH_USAGE_BETA = 'oauth-2025-04-20';
1
+ import { swallow } from "../../helpers.js";
2
+ import { asRecord, configuredProviderEnabled, fetchWithTimeout, normalizePercent, toIso, } from "../common.js";
3
+ const ANTHROPIC_OAUTH_USAGE_BETA = "oauth-2025-04-20";
4
+ const ANTHROPIC_WINDOW_FIELDS = [
5
+ ["five_hour", "5h"],
6
+ ["seven_day", "Weekly"],
7
+ ["seven_day_sonnet", "Sonnet 7d"],
8
+ ["seven_day_opus", "Opus 7d"],
9
+ ["seven_day_oauth_apps", "OAuth Apps 7d"],
10
+ ["seven_day_cowork", "Cowork 7d"],
11
+ ];
4
12
  function parseAnthropicWindow(value, label) {
5
13
  const win = asRecord(value);
6
14
  if (!win)
@@ -20,96 +28,92 @@ async function fetchAnthropicQuota({ providerID, auth, config, }) {
20
28
  const checkedAt = Date.now();
21
29
  const base = {
22
30
  providerID,
23
- adapterID: 'anthropic',
24
- label: 'Anthropic',
25
- shortLabel: 'Anthropic',
31
+ adapterID: "anthropic",
32
+ label: "Anthropic",
33
+ shortLabel: "Anthropic",
26
34
  sortOrder: 30,
27
35
  };
28
36
  if (!auth) {
29
37
  return {
30
38
  ...base,
31
- status: 'unavailable',
39
+ status: "unavailable",
32
40
  checkedAt,
33
- note: 'auth not found',
41
+ note: "auth not found",
34
42
  };
35
43
  }
36
- if (auth.type !== 'oauth') {
44
+ if (auth.type !== "oauth") {
37
45
  return {
38
46
  ...base,
39
- status: 'unsupported',
47
+ status: "unsupported",
40
48
  checkedAt,
41
- note: 'api key auth has no quota endpoint',
49
+ note: "api key auth has no quota endpoint",
42
50
  };
43
51
  }
44
- if (typeof auth.access !== 'string' || !auth.access) {
52
+ if (typeof auth.access !== "string" || !auth.access) {
45
53
  return {
46
54
  ...base,
47
- status: 'unavailable',
55
+ status: "unavailable",
48
56
  checkedAt,
49
- note: 'missing oauth access token',
57
+ note: "missing oauth access token",
50
58
  };
51
59
  }
52
- const response = await fetchWithTimeout('https://api.anthropic.com/api/oauth/usage', {
53
- method: 'GET',
60
+ const response = await fetchWithTimeout("https://api.anthropic.com/api/oauth/usage", {
61
+ method: "GET",
54
62
  headers: {
55
- Accept: 'application/json',
63
+ Accept: "application/json",
56
64
  Authorization: `Bearer ${auth.access}`,
57
- 'Content-Type': 'application/json',
58
- 'User-Agent': 'opencode-quota-sidebar',
59
- 'anthropic-beta': ANTHROPIC_OAUTH_USAGE_BETA,
65
+ "Content-Type": "application/json",
66
+ "User-Agent": "opencode-quota-sidebar",
67
+ "anthropic-beta": ANTHROPIC_OAUTH_USAGE_BETA,
60
68
  },
61
- }, config.quota.requestTimeoutMs).catch(swallow('fetchAnthropicQuota:usage'));
69
+ }, config.quota.requestTimeoutMs).catch(swallow("fetchAnthropicQuota:usage"));
62
70
  if (!response) {
63
71
  return {
64
72
  ...base,
65
- status: 'error',
73
+ status: "error",
66
74
  checkedAt,
67
- note: 'network request failed',
75
+ note: "network request failed",
68
76
  };
69
77
  }
70
78
  if (!response.ok) {
71
79
  return {
72
80
  ...base,
73
- status: 'error',
81
+ status: "error",
74
82
  checkedAt,
75
83
  note: `http ${response.status}`,
76
84
  };
77
85
  }
78
86
  const payload = await response
79
87
  .json()
80
- .catch(swallow('fetchAnthropicQuota:json'));
88
+ .catch(swallow("fetchAnthropicQuota:json"));
81
89
  const usage = asRecord(payload);
82
90
  if (!usage) {
83
91
  return {
84
92
  ...base,
85
- status: 'error',
93
+ status: "error",
86
94
  checkedAt,
87
- note: 'invalid response',
95
+ note: "invalid response",
88
96
  };
89
97
  }
90
- const windows = [
91
- parseAnthropicWindow(usage.five_hour, '5h'),
92
- parseAnthropicWindow(usage.seven_day, 'Weekly'),
93
- parseAnthropicWindow(usage.seven_day_sonnet, 'Sonnet 7d'),
94
- ].filter((window) => Boolean(window));
98
+ const windows = ANTHROPIC_WINDOW_FIELDS.map(([field, label]) => parseAnthropicWindow(usage[field], label)).filter((window) => Boolean(window));
95
99
  const primary = windows[0];
96
100
  return {
97
101
  ...base,
98
- status: primary ? 'ok' : 'error',
102
+ status: primary ? "ok" : "error",
99
103
  checkedAt,
100
104
  usedPercent: primary?.usedPercent,
101
105
  remainingPercent: primary?.remainingPercent,
102
106
  resetAt: primary?.resetAt,
103
- note: primary ? undefined : 'missing quota fields',
107
+ note: primary ? undefined : "missing quota fields",
104
108
  windows: windows.length > 0 ? windows : undefined,
105
109
  };
106
110
  }
107
111
  export const anthropicAdapter = {
108
- id: 'anthropic',
109
- label: 'Anthropic',
110
- shortLabel: 'Anthropic',
112
+ id: "anthropic",
113
+ label: "Anthropic",
114
+ shortLabel: "Anthropic",
111
115
  sortOrder: 30,
112
- matchScore: ({ providerID }) => (providerID === 'anthropic' ? 80 : 0),
113
- isEnabled: (config) => configuredProviderEnabled(config.quota, 'anthropic', config.quota.includeAnthropic),
116
+ matchScore: ({ providerID }) => (providerID === "anthropic" ? 80 : 0),
117
+ isEnabled: (config) => configuredProviderEnabled(config.quota, "anthropic", config.quota.includeAnthropic),
114
118
  fetch: fetchAnthropicQuota,
115
119
  };
@@ -1,2 +1,2 @@
1
- import type { QuotaProviderAdapter } from '../types.js';
1
+ import type { QuotaProviderAdapter } from "../types.js";
2
2
  export declare const kimiForCodingAdapter: QuotaProviderAdapter;
@@ -1,36 +1,16 @@
1
- import { isRecord, swallow } from '../../helpers.js';
2
- import { asNumber, configuredProviderEnabled, fetchWithTimeout, sanitizeBaseURL, toIso, } from '../common.js';
3
- const KIMI_FOR_CODING_BASE_URL = 'https://api.kimi.com/coding/v1';
4
- function resolveApiKey(auth, providerOptions) {
5
- const optionKey = providerOptions?.apiKey;
6
- if (typeof optionKey === 'string' && optionKey)
7
- return optionKey;
8
- if (!auth)
9
- return undefined;
10
- if (auth.type === 'api' && typeof auth.key === 'string' && auth.key) {
11
- return auth.key;
12
- }
13
- if (auth.type === 'wellknown') {
14
- if (typeof auth.key === 'string' && auth.key)
15
- return auth.key;
16
- if (typeof auth.token === 'string' && auth.token)
17
- return auth.token;
18
- }
19
- if (auth.type === 'oauth' && typeof auth.access === 'string' && auth.access) {
20
- return auth.access;
21
- }
22
- return undefined;
23
- }
1
+ import { isRecord, swallow } from "../../helpers.js";
2
+ import { asNumber, configuredProviderEnabled, fetchWithTimeout, resolveApiKey, sanitizeBaseURL, toIso, } from "../common.js";
3
+ const KIMI_FOR_CODING_BASE_URL = "https://api.kimi.com/coding/v1";
24
4
  function isKimiCodingBaseURL(value) {
25
5
  const normalized = sanitizeBaseURL(value);
26
6
  if (!normalized)
27
7
  return false;
28
8
  try {
29
9
  const parsed = new URL(normalized);
30
- if (parsed.protocol !== 'https:')
10
+ if (parsed.protocol !== "https:")
31
11
  return false;
32
- const pathname = parsed.pathname.replace(/\/+$/, '');
33
- return parsed.host === 'api.kimi.com' && pathname === '/coding/v1';
12
+ const pathname = parsed.pathname.replace(/\/+$/, "");
13
+ return parsed.host === "api.kimi.com" && pathname === "/coding/v1";
34
14
  }
35
15
  catch {
36
16
  return false;
@@ -45,9 +25,9 @@ function usagesUrl(baseURL) {
45
25
  }
46
26
  function percentFromQuota(limit, remaining) {
47
27
  const total = asNumber(limit) ??
48
- (typeof limit === 'string' && limit.trim() ? Number(limit) : undefined);
28
+ (typeof limit === "string" && limit.trim() ? Number(limit) : undefined);
49
29
  const left = asNumber(remaining) ??
50
- (typeof remaining === 'string' && remaining.trim()
30
+ (typeof remaining === "string" && remaining.trim()
51
31
  ? Number(remaining)
52
32
  : undefined);
53
33
  if (total === undefined || left === undefined || total <= 0)
@@ -57,27 +37,27 @@ function percentFromQuota(limit, remaining) {
57
37
  return Math.max(0, Math.min(100, (left / total) * 100));
58
38
  }
59
39
  function windowLabel(duration, timeUnit) {
60
- if (timeUnit === 'TIME_UNIT_MINUTE' && duration === 300)
61
- return '5h';
62
- if (timeUnit === 'TIME_UNIT_DAY' && duration === 7)
63
- return 'Weekly';
64
- if (timeUnit === 'TIME_UNIT_MINUTE' && duration && duration > 0) {
40
+ if (timeUnit === "TIME_UNIT_MINUTE" && duration === 300)
41
+ return "5h";
42
+ if (timeUnit === "TIME_UNIT_DAY" && duration === 7)
43
+ return "Weekly";
44
+ if (timeUnit === "TIME_UNIT_MINUTE" && duration && duration > 0) {
65
45
  const hours = duration / 60;
66
46
  if (hours <= 24)
67
47
  return `${Math.round(hours)}h`;
68
48
  }
69
- if (timeUnit === 'TIME_UNIT_HOUR' && duration && duration > 0) {
49
+ if (timeUnit === "TIME_UNIT_HOUR" && duration && duration > 0) {
70
50
  if (duration <= 24)
71
51
  return `${Math.round(duration)}h`;
72
52
  const days = duration / 24;
73
53
  if (days <= 6)
74
54
  return `${Math.round(days)}d`;
75
55
  }
76
- if (timeUnit === 'TIME_UNIT_DAY' && duration && duration > 0) {
56
+ if (timeUnit === "TIME_UNIT_DAY" && duration && duration > 0) {
77
57
  if (duration <= 6)
78
58
  return `${Math.round(duration)}d`;
79
59
  if (duration === 7)
80
- return 'Weekly';
60
+ return "Weekly";
81
61
  }
82
62
  return undefined;
83
63
  }
@@ -89,7 +69,7 @@ function parseWindow(value) {
89
69
  if (!window || !detail)
90
70
  return undefined;
91
71
  const duration = asNumber(window.duration);
92
- const timeUnit = typeof window.timeUnit === 'string' ? window.timeUnit : undefined;
72
+ const timeUnit = typeof window.timeUnit === "string" ? window.timeUnit : undefined;
93
73
  const label = windowLabel(duration, timeUnit);
94
74
  const remainingPercent = percentFromQuota(detail.limit, detail.remaining);
95
75
  if (!label || remainingPercent === undefined)
@@ -104,7 +84,7 @@ function dedupeWindows(windows) {
104
84
  const seen = new Set();
105
85
  const deduped = [];
106
86
  for (const window of windows) {
107
- const key = `${window.label}|${window.resetAt || ''}|${window.remainingPercent ?? ''}`;
87
+ const key = `${window.label}|${window.resetAt || ""}|${window.remainingPercent ?? ""}`;
108
88
  if (seen.has(key))
109
89
  continue;
110
90
  seen.add(key);
@@ -116,53 +96,53 @@ async function fetchKimiForCodingQuota({ providerID, providerOptions, auth, conf
116
96
  const checkedAt = Date.now();
117
97
  const base = {
118
98
  providerID,
119
- adapterID: 'kimi-for-coding',
120
- label: 'Kimi For Coding',
121
- shortLabel: 'Kimi',
99
+ adapterID: "kimi-for-coding",
100
+ label: "Kimi For Coding",
101
+ shortLabel: "Kimi",
122
102
  sortOrder: 15,
123
103
  };
124
104
  const apiKey = resolveApiKey(auth, providerOptions);
125
105
  if (!apiKey) {
126
106
  return {
127
107
  ...base,
128
- status: 'unavailable',
108
+ status: "unavailable",
129
109
  checkedAt,
130
- note: 'missing api key',
110
+ note: "missing api key",
131
111
  };
132
112
  }
133
113
  const response = await fetchWithTimeout(usagesUrl(providerOptions?.baseURL), {
134
- method: 'GET',
114
+ method: "GET",
135
115
  headers: {
136
- Accept: 'application/json',
116
+ Accept: "application/json",
137
117
  Authorization: `Bearer ${apiKey}`,
138
- 'User-Agent': 'opencode-quota-sidebar',
118
+ "User-Agent": "opencode-quota-sidebar",
139
119
  },
140
- }, config.quota.requestTimeoutMs).catch(swallow('fetchKimiForCodingQuota:usage'));
120
+ }, config.quota.requestTimeoutMs).catch(swallow("fetchKimiForCodingQuota:usage"));
141
121
  if (!response) {
142
122
  return {
143
123
  ...base,
144
- status: 'error',
124
+ status: "error",
145
125
  checkedAt,
146
- note: 'network request failed',
126
+ note: "network request failed",
147
127
  };
148
128
  }
149
129
  if (!response.ok) {
150
130
  return {
151
131
  ...base,
152
- status: 'error',
132
+ status: "error",
153
133
  checkedAt,
154
134
  note: `http ${response.status}`,
155
135
  };
156
136
  }
157
137
  const payload = await response
158
138
  .json()
159
- .catch(swallow('fetchKimiForCodingQuota:json'));
139
+ .catch(swallow("fetchKimiForCodingQuota:json"));
160
140
  if (!isRecord(payload)) {
161
141
  return {
162
142
  ...base,
163
- status: 'error',
143
+ status: "error",
164
144
  checkedAt,
165
- note: 'invalid response',
145
+ note: "invalid response",
166
146
  };
167
147
  }
168
148
  const windows = Array.isArray(payload.limits)
@@ -177,16 +157,16 @@ async function fetchKimiForCodingQuota({ providerID, providerOptions, auth, conf
177
157
  ...windows,
178
158
  topLevelRemainingPercent !== undefined
179
159
  ? {
180
- label: 'Weekly',
160
+ label: "Weekly",
181
161
  remainingPercent: topLevelRemainingPercent,
182
162
  resetAt: topLevelResetAt,
183
163
  }
184
164
  : undefined,
185
165
  ].filter((value) => Boolean(value))).sort((left, right) => {
186
166
  const order = (label) => {
187
- if (label === '5h')
167
+ if (label === "5h")
188
168
  return 0;
189
- if (label === 'Weekly')
169
+ if (label === "Weekly")
190
170
  return 1;
191
171
  return 2;
192
172
  };
@@ -195,25 +175,25 @@ async function fetchKimiForCodingQuota({ providerID, providerOptions, auth, conf
195
175
  const primary = allWindows[0];
196
176
  return {
197
177
  ...base,
198
- status: primary ? 'ok' : 'error',
178
+ status: primary ? "ok" : "error",
199
179
  checkedAt,
200
180
  remainingPercent: primary?.remainingPercent,
201
181
  resetAt: primary?.resetAt,
202
- note: primary ? undefined : 'missing quota fields',
182
+ note: primary ? undefined : "missing quota fields",
203
183
  windows: allWindows.length > 0 ? allWindows : undefined,
204
184
  };
205
185
  }
206
186
  export const kimiForCodingAdapter = {
207
- id: 'kimi-for-coding',
208
- label: 'Kimi For Coding',
209
- shortLabel: 'Kimi',
187
+ id: "kimi-for-coding",
188
+ label: "Kimi For Coding",
189
+ shortLabel: "Kimi",
210
190
  sortOrder: 15,
211
- normalizeID: (providerID) => providerID === 'kimi-for-coding' ? 'kimi-for-coding' : undefined,
191
+ normalizeID: (providerID) => providerID === "kimi-for-coding" ? "kimi-for-coding" : undefined,
212
192
  matchScore: ({ providerID, providerOptions }) => {
213
- if (providerID === 'kimi-for-coding')
193
+ if (providerID === "kimi-for-coding")
214
194
  return 100;
215
195
  return isKimiCodingBaseURL(providerOptions?.baseURL) ? 95 : 0;
216
196
  },
217
- isEnabled: (config) => configuredProviderEnabled(config.quota, 'kimi-for-coding', true),
197
+ isEnabled: (config) => configuredProviderEnabled(config.quota, "kimi-for-coding", true),
218
198
  fetch: fetchKimiForCodingQuota,
219
199
  };
@@ -0,0 +1,2 @@
1
+ import type { QuotaProviderAdapter } from "../types.js";
2
+ export declare const minimaxCnCodingPlanAdapter: QuotaProviderAdapter;