@leo000001/opencode-quota-sidebar 3.0.2 → 3.0.5
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/README.md +14 -14
- package/README.zh-CN.md +14 -14
- package/dist/cost.d.ts +3 -3
- package/dist/cost.js +292 -197
- package/dist/format.js +33 -42
- package/dist/index.js +4 -3
- package/dist/title.js +8 -6
- package/dist/tools.d.ts +13 -8
- package/dist/tools.js +4 -2
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -108,17 +108,17 @@ USAGE
|
|
|
108
108
|
CR31.4k CW3.2k Cd66%
|
|
109
109
|
Est $12.8
|
|
110
110
|
QUOTA
|
|
111
|
-
OAI 5h80
|
|
112
|
-
W70
|
|
113
|
-
Cop M78
|
|
114
|
-
RC D$88.9/$60
|
|
111
|
+
OAI 5h80 R3h20m
|
|
112
|
+
W70 R2D04h
|
|
113
|
+
Cop M78 R12D00h
|
|
114
|
+
RC D$88.9/$60 E6D00h
|
|
115
115
|
B260
|
|
116
116
|
```
|
|
117
117
|
|
|
118
118
|
Compact shared title example:
|
|
119
119
|
|
|
120
120
|
```text
|
|
121
|
-
Fix quota adapter matching | OAI 5h80
|
|
121
|
+
Fix quota adapter matching | OAI 5h80 R3h20m W70 R2D04h | RC D$88.9/$60 B260 | Cd66% | Est$12.8
|
|
122
122
|
```
|
|
123
123
|
|
|
124
124
|
Another compact title example with multiple providers:
|
|
@@ -143,9 +143,9 @@ Example `quota_summary` markdown output shape:
|
|
|
143
143
|
|
|
144
144
|
## Quota
|
|
145
145
|
|
|
146
|
-
- OpenAI: 5h 80% (reset
|
|
147
|
-
- Copilot: Monthly 78% (reset
|
|
148
|
-
- RightCode: Daily $88.9/$60 (exp
|
|
146
|
+
- OpenAI: 5h 80% (reset 3h20m), Weekly 70% (reset 2D04h)
|
|
147
|
+
- Copilot: Monthly 78% (reset 12D00h)
|
|
148
|
+
- RightCode: Daily $88.9/$60 (exp 6D00h), Balance $260
|
|
149
149
|
```
|
|
150
150
|
|
|
151
151
|
The tool already returns full markdown. Clients should display that report directly instead of replacing it with a short summary.
|
|
@@ -185,15 +185,15 @@ Quota tokens:
|
|
|
185
185
|
- `D`: daily window
|
|
186
186
|
- `W`: weekly window
|
|
187
187
|
- `M`: monthly window
|
|
188
|
-
- `
|
|
189
|
-
- `
|
|
190
|
-
- `
|
|
188
|
+
- `R3h20m`: resets in `3h20m`
|
|
189
|
+
- `R2D04h`: resets in `2D04h`
|
|
190
|
+
- `E6D00h`: expires in `6D00h`
|
|
191
191
|
|
|
192
192
|
Example compact quota fragments:
|
|
193
193
|
|
|
194
|
-
- `OAI 5h80
|
|
195
|
-
- `Cop M78
|
|
196
|
-
- `RC D$88.9/$60
|
|
194
|
+
- `OAI 5h80 R3h20m`: OpenAI short window, 80% remaining, resets in `3h20m`
|
|
195
|
+
- `Cop M78 R12D00h`: Copilot monthly quota, 78% remaining, resets in `12D00h`
|
|
196
|
+
- `RC D$88.9/$60 E6D00h B260`: RightCode daily quota plus balance
|
|
197
197
|
|
|
198
198
|
## Config
|
|
199
199
|
|
package/README.zh-CN.md
CHANGED
|
@@ -89,17 +89,17 @@ USAGE
|
|
|
89
89
|
CR31.4k CW3.2k Cd66%
|
|
90
90
|
Est $12.8
|
|
91
91
|
QUOTA
|
|
92
|
-
OAI 5h80
|
|
93
|
-
W70
|
|
94
|
-
Cop M78
|
|
95
|
-
RC D$88.9/$60
|
|
92
|
+
OAI 5h80 R3h20m
|
|
93
|
+
W70 R2D04h
|
|
94
|
+
Cop M78 R12D00h
|
|
95
|
+
RC D$88.9/$60 E6D00h
|
|
96
96
|
B260
|
|
97
97
|
```
|
|
98
98
|
|
|
99
99
|
compact shared title 示例:
|
|
100
100
|
|
|
101
101
|
```text
|
|
102
|
-
Fix quota adapter matching | OAI 5h80
|
|
102
|
+
Fix quota adapter matching | OAI 5h80 R3h20m W70 R2D04h | RC D$88.9/$60 B260 | Cd66% | Est$12.8
|
|
103
103
|
```
|
|
104
104
|
|
|
105
105
|
另一个多 provider 示例:
|
|
@@ -124,9 +124,9 @@ Add XYAI quota adapter | Ant 5h100 W77 O7d60 | Cop M78 R04-01 | Cd52% | Est$2.34
|
|
|
124
124
|
|
|
125
125
|
## Quota
|
|
126
126
|
|
|
127
|
-
- OpenAI: 5h 80% (reset
|
|
128
|
-
- Copilot: Monthly 78% (reset
|
|
129
|
-
- RightCode: Daily $88.9/$60 (exp
|
|
127
|
+
- OpenAI: 5h 80% (reset 3h20m), Weekly 70% (reset 2D04h)
|
|
128
|
+
- Copilot: Monthly 78% (reset 12D00h)
|
|
129
|
+
- RightCode: Daily $88.9/$60 (exp 6D00h), Balance $260
|
|
130
130
|
```
|
|
131
131
|
|
|
132
132
|
这个工具本身就返回完整 markdown,调用方应该直接展示,而不是再压缩成一句话摘要。
|
|
@@ -170,15 +170,15 @@ Quota token:
|
|
|
170
170
|
- `D`:daily window
|
|
171
171
|
- `W`:weekly window
|
|
172
172
|
- `M`:monthly window
|
|
173
|
-
- `
|
|
174
|
-
- `
|
|
175
|
-
- `
|
|
173
|
+
- `R3h20m`:还剩 `3h20m` 重置
|
|
174
|
+
- `R2D04h`:还剩 `2D04h` 重置
|
|
175
|
+
- `E6D00h`:还剩 `6D00h` 到期
|
|
176
176
|
|
|
177
177
|
compact quota 片段示例:
|
|
178
178
|
|
|
179
|
-
- `OAI 5h80
|
|
180
|
-
- `Cop M78
|
|
181
|
-
- `RC D$88.9/$60
|
|
179
|
+
- `OAI 5h80 R3h20m`:OpenAI 短窗口剩余 80%,还剩 `3h20m` 重置
|
|
180
|
+
- `Cop M78 R12D00h`:Copilot 月额度剩余 78%,还剩 `12D00h` 重置
|
|
181
|
+
- `RC D$88.9/$60 E6D00h B260`:RightCode 日额度 + 余额
|
|
182
182
|
|
|
183
183
|
## 安装
|
|
184
184
|
|
package/dist/cost.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { AssistantMessage } from
|
|
2
|
-
import type { CacheCoverageMode } from
|
|
1
|
+
import type { AssistantMessage } from '@opencode-ai/sdk';
|
|
2
|
+
import type { CacheCoverageMode } from './types.js';
|
|
3
3
|
export declare const API_COST_ENABLED_PROVIDERS: Set<string>;
|
|
4
|
-
export type CanonicalPriceSource =
|
|
4
|
+
export type CanonicalPriceSource = 'official-doc' | 'runtime';
|
|
5
5
|
export declare function canonicalPricingProviderID(providerID: string): string;
|
|
6
6
|
export declare function canonicalApiCostProviderID(providerID: string): string;
|
|
7
7
|
export type ModelCostRates = {
|
package/dist/cost.js
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import { asNumber, isRecord } from
|
|
1
|
+
import { asNumber, isRecord } from './helpers.js';
|
|
2
2
|
export const API_COST_ENABLED_PROVIDERS = new Set([
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
'openai',
|
|
4
|
+
'anthropic',
|
|
5
|
+
'kimi-for-coding',
|
|
6
|
+
'zhipu',
|
|
7
|
+
'minimax-cn-coding-plan',
|
|
8
8
|
]);
|
|
9
9
|
const MODEL_COST_RATE_ALIASES = {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
'zhipuai-coding-plan:glm-5.1': ['zhipu:glm-5'],
|
|
11
|
+
'zhipuai-coding-plan:glm-5.1-thinking': ['zhipu:glm-5'],
|
|
12
|
+
'zhipu:glm-5.1': ['zhipu:glm-5'],
|
|
13
|
+
'zhipu:glm-5.1-thinking': ['zhipu:glm-5'],
|
|
14
14
|
};
|
|
15
15
|
function moonshotCanonicalModelID(modelID) {
|
|
16
|
-
const stripped = modelID.replace(/^moonshotai[/:]/i,
|
|
16
|
+
const stripped = modelID.replace(/^moonshotai[/:]/i, '');
|
|
17
17
|
switch (stripped) {
|
|
18
|
-
case
|
|
19
|
-
case
|
|
20
|
-
return
|
|
18
|
+
case 'k2p5':
|
|
19
|
+
case 'kimi-k2-5':
|
|
20
|
+
return 'kimi-k2.5';
|
|
21
21
|
default:
|
|
22
22
|
return stripped;
|
|
23
23
|
}
|
|
@@ -30,7 +30,7 @@ function moonshotModelAliases(modelID, options) {
|
|
|
30
30
|
if (!aliases.includes(value))
|
|
31
31
|
aliases.push(value);
|
|
32
32
|
};
|
|
33
|
-
const stripped = modelID.replace(/^moonshotai[/:]/i,
|
|
33
|
+
const stripped = modelID.replace(/^moonshotai[/:]/i, '');
|
|
34
34
|
const canonical = moonshotCanonicalModelID(modelID);
|
|
35
35
|
if (!options?.canonicalProviderKeys)
|
|
36
36
|
push(modelID);
|
|
@@ -49,11 +49,11 @@ function minimaxModelAliases(modelID) {
|
|
|
49
49
|
};
|
|
50
50
|
push(modelID);
|
|
51
51
|
push(modelID.toLowerCase());
|
|
52
|
-
const stripped = modelID.replace(/^(?:minimax|minimax-cn-coding-plan)[/:]/i,
|
|
52
|
+
const stripped = modelID.replace(/^(?:minimax|minimax-cn-coding-plan)[/:]/i, '');
|
|
53
53
|
push(stripped);
|
|
54
54
|
push(stripped.toLowerCase());
|
|
55
55
|
if (/^minimax-/i.test(stripped)) {
|
|
56
|
-
const suffix = stripped.slice(
|
|
56
|
+
const suffix = stripped.slice('minimax-'.length);
|
|
57
57
|
push(`MiniMax-${suffix}`);
|
|
58
58
|
push(`minimax-${suffix.toLowerCase()}`);
|
|
59
59
|
}
|
|
@@ -77,19 +77,19 @@ function zhipuModelAliases(modelID) {
|
|
|
77
77
|
push(modelID);
|
|
78
78
|
for (let index = 0; index < queue.length; index++) {
|
|
79
79
|
const stem = queue[index];
|
|
80
|
-
const withoutProviderPrefix = stem.replace(/^(?:zhipu|z-ai|bigmodel|zhipuai-coding-plan)[/:]/,
|
|
80
|
+
const withoutProviderPrefix = stem.replace(/^(?:zhipu|z-ai|bigmodel|zhipuai-coding-plan)[/:]/, '');
|
|
81
81
|
push(withoutProviderPrefix);
|
|
82
82
|
push(`zhipu/${withoutProviderPrefix}`);
|
|
83
|
-
const withoutBillingSuffix = withoutProviderPrefix.replace(/-billing$/,
|
|
83
|
+
const withoutBillingSuffix = withoutProviderPrefix.replace(/-billing$/, '');
|
|
84
84
|
push(withoutBillingSuffix);
|
|
85
85
|
push(`zhipu/${withoutBillingSuffix}`);
|
|
86
|
-
const withoutThinkingSuffix = withoutBillingSuffix.replace(/-thinking$/,
|
|
86
|
+
const withoutThinkingSuffix = withoutBillingSuffix.replace(/-thinking$/, '');
|
|
87
87
|
push(withoutThinkingSuffix);
|
|
88
88
|
push(`zhipu/${withoutThinkingSuffix}`);
|
|
89
|
-
const dotted = withoutThinkingSuffix.replace(/(\d)-(\d)(?=-|$)/g,
|
|
89
|
+
const dotted = withoutThinkingSuffix.replace(/(\d)-(\d)(?=-|$)/g, '$1.$2');
|
|
90
90
|
push(dotted);
|
|
91
91
|
push(`zhipu/${dotted}`);
|
|
92
|
-
const hyphenated = withoutThinkingSuffix.replace(/(\d)\.(\d)(?=-|$)/g,
|
|
92
|
+
const hyphenated = withoutThinkingSuffix.replace(/(\d)\.(\d)(?=-|$)/g, '$1-$2');
|
|
93
93
|
push(hyphenated);
|
|
94
94
|
push(`zhipu/${hyphenated}`);
|
|
95
95
|
}
|
|
@@ -110,71 +110,71 @@ function anthropicModelAliases(modelID) {
|
|
|
110
110
|
for (let index = 0; index < queue.length; index++) {
|
|
111
111
|
const stem = queue[index];
|
|
112
112
|
const withoutProviderPrefix = stem
|
|
113
|
-
.replace(/^(?:[a-z]+\.)*anthropic\./,
|
|
114
|
-
.replace(/^anthropic[/.]/,
|
|
113
|
+
.replace(/^(?:[a-z]+\.)*anthropic\./, '')
|
|
114
|
+
.replace(/^anthropic[/.]/, '');
|
|
115
115
|
push(withoutProviderPrefix);
|
|
116
116
|
push(`anthropic/${withoutProviderPrefix}`);
|
|
117
|
-
const withoutVersionSuffix = withoutProviderPrefix.replace(/-v\d+(?::\d+)?$/,
|
|
117
|
+
const withoutVersionSuffix = withoutProviderPrefix.replace(/-v\d+(?::\d+)?$/, '');
|
|
118
118
|
push(withoutVersionSuffix);
|
|
119
119
|
push(`anthropic/${withoutVersionSuffix}`);
|
|
120
|
-
const atDate = withoutVersionSuffix.replace(/@(\d{8})$/,
|
|
120
|
+
const atDate = withoutVersionSuffix.replace(/@(\d{8})$/, '-$1');
|
|
121
121
|
push(atDate);
|
|
122
122
|
push(`anthropic/${atDate}`);
|
|
123
|
-
const withAtDate = withoutVersionSuffix.replace(/-(\d{8})$/,
|
|
123
|
+
const withAtDate = withoutVersionSuffix.replace(/-(\d{8})$/, '@$1');
|
|
124
124
|
push(withAtDate);
|
|
125
125
|
push(`anthropic/${withAtDate}`);
|
|
126
|
-
const withoutThinkingSuffix = withoutVersionSuffix.replace(/-thinking$/,
|
|
126
|
+
const withoutThinkingSuffix = withoutVersionSuffix.replace(/-thinking$/, '');
|
|
127
127
|
push(withoutThinkingSuffix);
|
|
128
128
|
push(`anthropic/${withoutThinkingSuffix}`);
|
|
129
|
-
const withoutLatestSuffix = withoutThinkingSuffix.replace(/-latest$/,
|
|
129
|
+
const withoutLatestSuffix = withoutThinkingSuffix.replace(/-latest$/, '');
|
|
130
130
|
push(withoutLatestSuffix);
|
|
131
131
|
push(`anthropic/${withoutLatestSuffix}`);
|
|
132
132
|
const withoutDateSuffix = withoutLatestSuffix
|
|
133
|
-
.replace(/-\d{8}$/,
|
|
134
|
-
.replace(/@\d{8}$/,
|
|
133
|
+
.replace(/-\d{8}$/, '')
|
|
134
|
+
.replace(/@\d{8}$/, '');
|
|
135
135
|
push(withoutDateSuffix);
|
|
136
136
|
push(`anthropic/${withoutDateSuffix}`);
|
|
137
|
-
const dotted = withoutDateSuffix.replace(/(\d)-(\d)(?=-|$)/g,
|
|
137
|
+
const dotted = withoutDateSuffix.replace(/(\d)-(\d)(?=-|$)/g, '$1.$2');
|
|
138
138
|
push(dotted);
|
|
139
139
|
push(`anthropic/${dotted}`);
|
|
140
|
-
const hyphenated = withoutDateSuffix.replace(/(\d)\.(\d)(?=-|$)/g,
|
|
140
|
+
const hyphenated = withoutDateSuffix.replace(/(\d)\.(\d)(?=-|$)/g, '$1-$2');
|
|
141
141
|
push(hyphenated);
|
|
142
142
|
push(`anthropic/${hyphenated}`);
|
|
143
143
|
}
|
|
144
144
|
return aliases;
|
|
145
145
|
}
|
|
146
146
|
function normalizeKnownProviderID(providerID) {
|
|
147
|
-
if (providerID.startsWith(
|
|
148
|
-
return
|
|
147
|
+
if (providerID.startsWith('github-copilot'))
|
|
148
|
+
return 'github-copilot';
|
|
149
149
|
return providerID;
|
|
150
150
|
}
|
|
151
151
|
function isCanonicalZhipuProviderID(providerID) {
|
|
152
|
-
return (providerID ===
|
|
153
|
-
providerID ===
|
|
154
|
-
providerID ===
|
|
155
|
-
providerID ===
|
|
152
|
+
return (providerID === 'zhipu' ||
|
|
153
|
+
providerID === 'bigmodel' ||
|
|
154
|
+
providerID === 'z-ai' ||
|
|
155
|
+
providerID === 'zhipuai-coding-plan');
|
|
156
156
|
}
|
|
157
157
|
function isCanonicalMiniMaxProviderID(providerID) {
|
|
158
|
-
return providerID ===
|
|
158
|
+
return providerID === 'minimax' || providerID === 'minimax-cn-coding-plan';
|
|
159
159
|
}
|
|
160
160
|
export function canonicalPricingProviderID(providerID) {
|
|
161
161
|
const normalized = normalizeKnownProviderID(providerID);
|
|
162
162
|
const lowered = normalized.toLowerCase();
|
|
163
163
|
if (isCanonicalMiniMaxProviderID(lowered)) {
|
|
164
|
-
return
|
|
164
|
+
return 'minimax';
|
|
165
165
|
}
|
|
166
166
|
if (isCanonicalZhipuProviderID(lowered)) {
|
|
167
|
-
return
|
|
167
|
+
return 'zhipu';
|
|
168
168
|
}
|
|
169
|
-
if (lowered ===
|
|
170
|
-
return
|
|
171
|
-
if (lowered.includes(
|
|
172
|
-
return
|
|
169
|
+
if (lowered === 'kimi-for-coding')
|
|
170
|
+
return 'moonshotai';
|
|
171
|
+
if (lowered.includes('anthropic') || lowered.includes('claude')) {
|
|
172
|
+
return 'anthropic';
|
|
173
173
|
}
|
|
174
|
-
if (lowered.includes(
|
|
175
|
-
return
|
|
176
|
-
if (lowered.includes(
|
|
177
|
-
return
|
|
174
|
+
if (lowered.includes('openai') || lowered.endsWith('-oai'))
|
|
175
|
+
return 'openai';
|
|
176
|
+
if (lowered.includes('copilot'))
|
|
177
|
+
return 'github-copilot';
|
|
178
178
|
return normalized;
|
|
179
179
|
}
|
|
180
180
|
export function canonicalApiCostProviderID(providerID) {
|
|
@@ -182,17 +182,17 @@ export function canonicalApiCostProviderID(providerID) {
|
|
|
182
182
|
const lowered = normalized.toLowerCase();
|
|
183
183
|
if (API_COST_ENABLED_PROVIDERS.has(lowered))
|
|
184
184
|
return lowered;
|
|
185
|
-
if (lowered ===
|
|
186
|
-
return
|
|
187
|
-
if (lowered.includes(
|
|
188
|
-
return
|
|
189
|
-
if (lowered.includes(
|
|
190
|
-
return
|
|
191
|
-
if (lowered.includes(
|
|
192
|
-
return
|
|
185
|
+
if (lowered === 'minimax')
|
|
186
|
+
return 'minimax-cn-coding-plan';
|
|
187
|
+
if (lowered.includes('copilot'))
|
|
188
|
+
return 'github-copilot';
|
|
189
|
+
if (lowered.includes('openai') || lowered.endsWith('-oai'))
|
|
190
|
+
return 'openai';
|
|
191
|
+
if (lowered.includes('anthropic') || lowered.includes('claude')) {
|
|
192
|
+
return 'anthropic';
|
|
193
193
|
}
|
|
194
194
|
if (isCanonicalZhipuProviderID(lowered)) {
|
|
195
|
-
return
|
|
195
|
+
return 'zhipu';
|
|
196
196
|
}
|
|
197
197
|
return normalized;
|
|
198
198
|
}
|
|
@@ -233,6 +233,14 @@ function moonshotPricing(input, output, cacheRead) {
|
|
|
233
233
|
cacheWrite: 0,
|
|
234
234
|
};
|
|
235
235
|
}
|
|
236
|
+
function openaiPricing(input, output, cacheRead) {
|
|
237
|
+
return {
|
|
238
|
+
input,
|
|
239
|
+
output,
|
|
240
|
+
cacheRead,
|
|
241
|
+
cacheWrite: 0,
|
|
242
|
+
};
|
|
243
|
+
}
|
|
236
244
|
function minimaxPricing(input, output, cacheRead, cacheWrite) {
|
|
237
245
|
return {
|
|
238
246
|
input,
|
|
@@ -243,238 +251,325 @@ function minimaxPricing(input, output, cacheRead, cacheWrite) {
|
|
|
243
251
|
}
|
|
244
252
|
const BUNDLED_CANONICAL_PRICE_ENTRIES = [
|
|
245
253
|
{
|
|
246
|
-
provider:
|
|
247
|
-
|
|
254
|
+
provider: 'openai',
|
|
255
|
+
// OpenCode commonly reports the flagship alias as `gpt-5`; keep a bundled
|
|
256
|
+
// fallback so API-equivalent cost still renders when runtime metadata omits
|
|
257
|
+
// OpenAI pricing on a given client or subscription path.
|
|
258
|
+
model: 'gpt-5',
|
|
259
|
+
rates: openaiPricing(2.5, 15, 0.25),
|
|
260
|
+
source: 'official-doc',
|
|
261
|
+
sourceURL: 'https://openai.com/api/pricing/',
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
provider: 'openai',
|
|
265
|
+
model: 'gpt-5.3',
|
|
266
|
+
rates: openaiPricing(1.75, 14, 0.175),
|
|
267
|
+
source: 'official-doc',
|
|
268
|
+
sourceURL: 'https://developers.openai.com/api/docs/models/gpt-5.3-chat-latest',
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
provider: 'openai',
|
|
272
|
+
model: 'gpt-5.3-chat-latest',
|
|
273
|
+
rates: openaiPricing(1.75, 14, 0.175),
|
|
274
|
+
source: 'official-doc',
|
|
275
|
+
sourceURL: 'https://developers.openai.com/api/docs/models/gpt-5.3-chat-latest',
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
provider: 'openai',
|
|
279
|
+
model: 'gpt-5.3-codex',
|
|
280
|
+
rates: openaiPricing(1.75, 14, 0.175),
|
|
281
|
+
source: 'official-doc',
|
|
282
|
+
sourceURL: 'https://developers.openai.com/api/docs/models/gpt-5.3-codex',
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
provider: 'openai',
|
|
286
|
+
model: 'gpt-5.2',
|
|
287
|
+
rates: openaiPricing(1.75, 14, 0.175),
|
|
288
|
+
source: 'official-doc',
|
|
289
|
+
sourceURL: 'https://developers.openai.com/api/docs/models/gpt-5.2',
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
provider: 'openai',
|
|
293
|
+
model: 'gpt-5.2-chat-latest',
|
|
294
|
+
rates: openaiPricing(1.75, 14, 0.175),
|
|
295
|
+
source: 'official-doc',
|
|
296
|
+
sourceURL: 'https://developers.openai.com/api/docs/models/gpt-5.2-chat-latest',
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
provider: 'openai',
|
|
300
|
+
model: 'gpt-5.2-pro',
|
|
301
|
+
rates: openaiPricing(21, 168, 0),
|
|
302
|
+
source: 'official-doc',
|
|
303
|
+
sourceURL: 'https://openai.com/index/introducing-gpt-5-2/',
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
provider: 'openai',
|
|
307
|
+
model: 'gpt-5.4',
|
|
308
|
+
rates: openaiPricing(2.5, 15, 0.25),
|
|
309
|
+
source: 'official-doc',
|
|
310
|
+
sourceURL: 'https://openai.com/api/pricing/',
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
provider: 'openai',
|
|
314
|
+
model: 'gpt-5-mini',
|
|
315
|
+
rates: openaiPricing(0.75, 4.5, 0.075),
|
|
316
|
+
source: 'official-doc',
|
|
317
|
+
sourceURL: 'https://openai.com/api/pricing/',
|
|
318
|
+
},
|
|
319
|
+
{
|
|
320
|
+
provider: 'openai',
|
|
321
|
+
model: 'gpt-5.4-mini',
|
|
322
|
+
rates: openaiPricing(0.75, 4.5, 0.075),
|
|
323
|
+
source: 'official-doc',
|
|
324
|
+
sourceURL: 'https://openai.com/api/pricing/',
|
|
325
|
+
},
|
|
326
|
+
{
|
|
327
|
+
provider: 'openai',
|
|
328
|
+
model: 'gpt-5-nano',
|
|
329
|
+
rates: openaiPricing(0.2, 1.25, 0.02),
|
|
330
|
+
source: 'official-doc',
|
|
331
|
+
sourceURL: 'https://openai.com/api/pricing/',
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
provider: 'openai',
|
|
335
|
+
model: 'gpt-5.4-nano',
|
|
336
|
+
rates: openaiPricing(0.2, 1.25, 0.02),
|
|
337
|
+
source: 'official-doc',
|
|
338
|
+
sourceURL: 'https://openai.com/api/pricing/',
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
provider: 'anthropic',
|
|
342
|
+
model: 'claude-opus-4-6',
|
|
248
343
|
rates: anthropicPricing(5, 25),
|
|
249
|
-
source:
|
|
250
|
-
sourceURL:
|
|
344
|
+
source: 'official-doc',
|
|
345
|
+
sourceURL: 'https://docs.anthropic.com/en/docs/about-claude/pricing',
|
|
251
346
|
},
|
|
252
347
|
{
|
|
253
|
-
provider:
|
|
254
|
-
model:
|
|
348
|
+
provider: 'anthropic',
|
|
349
|
+
model: 'claude-opus-4-5',
|
|
255
350
|
rates: anthropicPricing(5, 25),
|
|
256
|
-
source:
|
|
257
|
-
sourceURL:
|
|
351
|
+
source: 'official-doc',
|
|
352
|
+
sourceURL: 'https://docs.anthropic.com/en/docs/about-claude/pricing',
|
|
258
353
|
},
|
|
259
354
|
{
|
|
260
|
-
provider:
|
|
261
|
-
model:
|
|
355
|
+
provider: 'anthropic',
|
|
356
|
+
model: 'claude-opus-4-1',
|
|
262
357
|
rates: anthropicPricing(15, 75),
|
|
263
|
-
source:
|
|
264
|
-
sourceURL:
|
|
358
|
+
source: 'official-doc',
|
|
359
|
+
sourceURL: 'https://docs.anthropic.com/en/docs/about-claude/pricing',
|
|
265
360
|
},
|
|
266
361
|
{
|
|
267
|
-
provider:
|
|
268
|
-
model:
|
|
362
|
+
provider: 'anthropic',
|
|
363
|
+
model: 'claude-opus-4',
|
|
269
364
|
rates: anthropicPricing(15, 75),
|
|
270
|
-
source:
|
|
271
|
-
sourceURL:
|
|
365
|
+
source: 'official-doc',
|
|
366
|
+
sourceURL: 'https://docs.anthropic.com/en/docs/about-claude/pricing',
|
|
272
367
|
},
|
|
273
368
|
{
|
|
274
|
-
provider:
|
|
275
|
-
model:
|
|
369
|
+
provider: 'anthropic',
|
|
370
|
+
model: 'claude-sonnet-4-6',
|
|
276
371
|
rates: anthropicPricing(3, 15),
|
|
277
|
-
source:
|
|
278
|
-
sourceURL:
|
|
372
|
+
source: 'official-doc',
|
|
373
|
+
sourceURL: 'https://docs.anthropic.com/en/docs/about-claude/pricing',
|
|
279
374
|
},
|
|
280
375
|
{
|
|
281
|
-
provider:
|
|
282
|
-
model:
|
|
376
|
+
provider: 'anthropic',
|
|
377
|
+
model: 'claude-sonnet-4-5',
|
|
283
378
|
rates: anthropicPricing(3, 15, {
|
|
284
379
|
longContextInput: 6,
|
|
285
380
|
longContextOutput: 22.5,
|
|
286
381
|
}),
|
|
287
|
-
source:
|
|
288
|
-
sourceURL:
|
|
382
|
+
source: 'official-doc',
|
|
383
|
+
sourceURL: 'https://docs.anthropic.com/en/docs/about-claude/pricing',
|
|
289
384
|
},
|
|
290
385
|
{
|
|
291
|
-
provider:
|
|
292
|
-
model:
|
|
386
|
+
provider: 'anthropic',
|
|
387
|
+
model: 'claude-sonnet-4',
|
|
293
388
|
rates: anthropicPricing(3, 15, {
|
|
294
389
|
longContextInput: 6,
|
|
295
390
|
longContextOutput: 22.5,
|
|
296
391
|
}),
|
|
297
|
-
source:
|
|
298
|
-
sourceURL:
|
|
392
|
+
source: 'official-doc',
|
|
393
|
+
sourceURL: 'https://docs.anthropic.com/en/docs/about-claude/pricing',
|
|
299
394
|
},
|
|
300
395
|
{
|
|
301
|
-
provider:
|
|
302
|
-
model:
|
|
396
|
+
provider: 'anthropic',
|
|
397
|
+
model: 'claude-3-7-sonnet',
|
|
303
398
|
rates: anthropicPricing(3, 15),
|
|
304
|
-
source:
|
|
305
|
-
sourceURL:
|
|
399
|
+
source: 'official-doc',
|
|
400
|
+
sourceURL: 'https://docs.anthropic.com/en/docs/about-claude/pricing',
|
|
306
401
|
},
|
|
307
402
|
{
|
|
308
|
-
provider:
|
|
309
|
-
model:
|
|
403
|
+
provider: 'anthropic',
|
|
404
|
+
model: 'claude-3-5-sonnet',
|
|
310
405
|
rates: anthropicPricing(3, 15),
|
|
311
|
-
source:
|
|
312
|
-
sourceURL:
|
|
406
|
+
source: 'official-doc',
|
|
407
|
+
sourceURL: 'https://docs.anthropic.com/en/docs/about-claude/pricing',
|
|
313
408
|
},
|
|
314
409
|
{
|
|
315
|
-
provider:
|
|
316
|
-
model:
|
|
410
|
+
provider: 'anthropic',
|
|
411
|
+
model: 'claude-haiku-4-5',
|
|
317
412
|
rates: anthropicPricing(1, 5),
|
|
318
|
-
source:
|
|
319
|
-
sourceURL:
|
|
413
|
+
source: 'official-doc',
|
|
414
|
+
sourceURL: 'https://docs.anthropic.com/en/docs/about-claude/pricing',
|
|
320
415
|
},
|
|
321
416
|
{
|
|
322
|
-
provider:
|
|
323
|
-
model:
|
|
417
|
+
provider: 'anthropic',
|
|
418
|
+
model: 'claude-3-5-haiku',
|
|
324
419
|
rates: anthropicPricing(0.8, 4),
|
|
325
|
-
source:
|
|
326
|
-
sourceURL:
|
|
420
|
+
source: 'official-doc',
|
|
421
|
+
sourceURL: 'https://docs.anthropic.com/en/docs/about-claude/pricing',
|
|
327
422
|
},
|
|
328
423
|
{
|
|
329
|
-
provider:
|
|
330
|
-
model:
|
|
424
|
+
provider: 'anthropic',
|
|
425
|
+
model: 'claude-3-opus',
|
|
331
426
|
rates: anthropicPricing(15, 75),
|
|
332
|
-
source:
|
|
333
|
-
sourceURL:
|
|
427
|
+
source: 'official-doc',
|
|
428
|
+
sourceURL: 'https://docs.anthropic.com/en/docs/about-claude/pricing',
|
|
334
429
|
},
|
|
335
430
|
{
|
|
336
|
-
provider:
|
|
337
|
-
model:
|
|
431
|
+
provider: 'anthropic',
|
|
432
|
+
model: 'claude-3-haiku',
|
|
338
433
|
rates: anthropicPricing(0.25, 1.25),
|
|
339
|
-
source:
|
|
340
|
-
sourceURL:
|
|
434
|
+
source: 'official-doc',
|
|
435
|
+
sourceURL: 'https://docs.anthropic.com/en/docs/about-claude/pricing',
|
|
341
436
|
},
|
|
342
437
|
{
|
|
343
|
-
provider:
|
|
344
|
-
model:
|
|
438
|
+
provider: 'zhipu',
|
|
439
|
+
model: 'glm-5',
|
|
345
440
|
rates: zhipuPricing(1, 3.2, 0.2),
|
|
346
|
-
source:
|
|
347
|
-
sourceURL:
|
|
441
|
+
source: 'official-doc',
|
|
442
|
+
sourceURL: 'https://docs.z.ai/guides/overview/pricing',
|
|
348
443
|
},
|
|
349
444
|
{
|
|
350
|
-
provider:
|
|
351
|
-
model:
|
|
445
|
+
provider: 'zhipu',
|
|
446
|
+
model: 'glm-4.7',
|
|
352
447
|
rates: zhipuPricing(0.6, 2.2, 0.11),
|
|
353
|
-
source:
|
|
354
|
-
sourceURL:
|
|
448
|
+
source: 'official-doc',
|
|
449
|
+
sourceURL: 'https://docs.z.ai/guides/overview/pricing',
|
|
355
450
|
},
|
|
356
451
|
{
|
|
357
|
-
provider:
|
|
358
|
-
model:
|
|
452
|
+
provider: 'zhipu',
|
|
453
|
+
model: 'glm-4.6',
|
|
359
454
|
rates: zhipuPricing(0.6, 2.2, 0.11),
|
|
360
|
-
source:
|
|
361
|
-
sourceURL:
|
|
455
|
+
source: 'official-doc',
|
|
456
|
+
sourceURL: 'https://docs.z.ai/guides/overview/pricing',
|
|
362
457
|
},
|
|
363
458
|
{
|
|
364
|
-
provider:
|
|
365
|
-
model:
|
|
459
|
+
provider: 'zhipu',
|
|
460
|
+
model: 'glm-4.6v',
|
|
366
461
|
rates: zhipuPricing(0.3, 0.9, 0.05),
|
|
367
|
-
source:
|
|
368
|
-
sourceURL:
|
|
462
|
+
source: 'official-doc',
|
|
463
|
+
sourceURL: 'https://docs.z.ai/guides/overview/pricing',
|
|
369
464
|
},
|
|
370
465
|
{
|
|
371
|
-
provider:
|
|
372
|
-
model:
|
|
466
|
+
provider: 'zhipu',
|
|
467
|
+
model: 'glm-4.5',
|
|
373
468
|
rates: zhipuPricing(0.6, 2.2, 0.11),
|
|
374
|
-
source:
|
|
375
|
-
sourceURL:
|
|
469
|
+
source: 'official-doc',
|
|
470
|
+
sourceURL: 'https://docs.z.ai/guides/overview/pricing',
|
|
376
471
|
},
|
|
377
472
|
{
|
|
378
|
-
provider:
|
|
379
|
-
model:
|
|
473
|
+
provider: 'zhipu',
|
|
474
|
+
model: 'glm-4.5-air',
|
|
380
475
|
rates: zhipuPricing(0.2, 1.1, 0.03),
|
|
381
|
-
source:
|
|
382
|
-
sourceURL:
|
|
476
|
+
source: 'official-doc',
|
|
477
|
+
sourceURL: 'https://docs.z.ai/guides/overview/pricing',
|
|
383
478
|
},
|
|
384
479
|
{
|
|
385
|
-
provider:
|
|
386
|
-
model:
|
|
480
|
+
provider: 'zhipu',
|
|
481
|
+
model: 'glm-4.5v',
|
|
387
482
|
rates: zhipuPricing(0.6, 1.8, 0.11),
|
|
388
|
-
source:
|
|
389
|
-
sourceURL:
|
|
483
|
+
source: 'official-doc',
|
|
484
|
+
sourceURL: 'https://docs.z.ai/guides/overview/pricing',
|
|
390
485
|
},
|
|
391
486
|
{
|
|
392
|
-
provider:
|
|
393
|
-
model:
|
|
487
|
+
provider: 'moonshotai',
|
|
488
|
+
model: 'kimi-k2.5',
|
|
394
489
|
rates: moonshotPricing(0.6, 3, 0.1),
|
|
395
|
-
source:
|
|
396
|
-
sourceURL:
|
|
490
|
+
source: 'official-doc',
|
|
491
|
+
sourceURL: 'https://platform.moonshot.ai/docs/pricing/chat',
|
|
397
492
|
},
|
|
398
493
|
{
|
|
399
|
-
provider:
|
|
400
|
-
model:
|
|
494
|
+
provider: 'moonshotai',
|
|
495
|
+
model: 'kimi-k2-thinking',
|
|
401
496
|
rates: moonshotPricing(0.6, 2.5, 0.15),
|
|
402
|
-
source:
|
|
403
|
-
sourceURL:
|
|
497
|
+
source: 'official-doc',
|
|
498
|
+
sourceURL: 'https://platform.moonshot.ai/docs/pricing/chat',
|
|
404
499
|
},
|
|
405
500
|
{
|
|
406
|
-
provider:
|
|
407
|
-
model:
|
|
501
|
+
provider: 'moonshotai',
|
|
502
|
+
model: 'kimi-k2-0711-preview',
|
|
408
503
|
rates: moonshotPricing(0.6, 2.5, 0.15),
|
|
409
|
-
source:
|
|
410
|
-
sourceURL:
|
|
504
|
+
source: 'official-doc',
|
|
505
|
+
sourceURL: 'https://platform.moonshot.ai/docs/pricing/chat',
|
|
411
506
|
},
|
|
412
507
|
{
|
|
413
|
-
provider:
|
|
414
|
-
model:
|
|
508
|
+
provider: 'moonshotai',
|
|
509
|
+
model: 'kimi-k2-0905-preview',
|
|
415
510
|
rates: moonshotPricing(0.6, 2.5, 0.15),
|
|
416
|
-
source:
|
|
417
|
-
sourceURL:
|
|
511
|
+
source: 'official-doc',
|
|
512
|
+
sourceURL: 'https://platform.moonshot.ai/docs/pricing/chat',
|
|
418
513
|
},
|
|
419
514
|
{
|
|
420
|
-
provider:
|
|
421
|
-
model:
|
|
515
|
+
provider: 'moonshotai',
|
|
516
|
+
model: 'kimi-k2-turbo-preview',
|
|
422
517
|
rates: moonshotPricing(2.4, 10, 0.6),
|
|
423
|
-
source:
|
|
424
|
-
sourceURL:
|
|
518
|
+
source: 'official-doc',
|
|
519
|
+
sourceURL: 'https://platform.moonshot.ai/docs/pricing/chat',
|
|
425
520
|
},
|
|
426
521
|
{
|
|
427
|
-
provider:
|
|
428
|
-
model:
|
|
522
|
+
provider: 'moonshotai',
|
|
523
|
+
model: 'kimi-k2-thinking-turbo',
|
|
429
524
|
rates: moonshotPricing(1.15, 8, 0.15),
|
|
430
|
-
source:
|
|
431
|
-
sourceURL:
|
|
525
|
+
source: 'official-doc',
|
|
526
|
+
sourceURL: 'https://platform.moonshot.ai/docs/pricing/chat',
|
|
432
527
|
},
|
|
433
528
|
{
|
|
434
|
-
provider:
|
|
435
|
-
model:
|
|
529
|
+
provider: 'minimax',
|
|
530
|
+
model: 'MiniMax-M2.7',
|
|
436
531
|
// OpenCode sources provider pricing from models.dev. The bundled MiniMax
|
|
437
532
|
// fallback mirrors those USD-denominated entries rather than the CN RMB
|
|
438
533
|
// docs so API-equivalent cost stays on the same currency basis as the rest
|
|
439
534
|
// of the sidebar/report output.
|
|
440
535
|
rates: minimaxPricing(0.3, 1.2, 0.06, 0.375),
|
|
441
|
-
source:
|
|
442
|
-
sourceURL:
|
|
536
|
+
source: 'runtime',
|
|
537
|
+
sourceURL: 'https://github.com/anomalyco/models.dev/blob/dev/providers/minimax/models/MiniMax-M2.7.toml',
|
|
443
538
|
},
|
|
444
539
|
{
|
|
445
|
-
provider:
|
|
446
|
-
model:
|
|
540
|
+
provider: 'minimax',
|
|
541
|
+
model: 'MiniMax-M2.7-highspeed',
|
|
447
542
|
rates: minimaxPricing(0.6, 2.4, 0.06, 0.375),
|
|
448
|
-
source:
|
|
449
|
-
sourceURL:
|
|
543
|
+
source: 'runtime',
|
|
544
|
+
sourceURL: 'https://github.com/anomalyco/models.dev/blob/dev/providers/minimax/models/MiniMax-M2.7-highspeed.toml',
|
|
450
545
|
},
|
|
451
546
|
{
|
|
452
|
-
provider:
|
|
453
|
-
model:
|
|
547
|
+
provider: 'minimax',
|
|
548
|
+
model: 'MiniMax-M2.5',
|
|
454
549
|
rates: minimaxPricing(0.3, 1.2, 0.03, 0.375),
|
|
455
|
-
source:
|
|
456
|
-
sourceURL:
|
|
550
|
+
source: 'runtime',
|
|
551
|
+
sourceURL: 'https://github.com/anomalyco/models.dev/blob/dev/providers/minimax/models/MiniMax-M2.5.toml',
|
|
457
552
|
},
|
|
458
553
|
{
|
|
459
|
-
provider:
|
|
460
|
-
model:
|
|
554
|
+
provider: 'minimax',
|
|
555
|
+
model: 'MiniMax-M2.5-highspeed',
|
|
461
556
|
rates: minimaxPricing(0.6, 2.4, 0.06, 0.375),
|
|
462
|
-
source:
|
|
463
|
-
sourceURL:
|
|
557
|
+
source: 'runtime',
|
|
558
|
+
sourceURL: 'https://github.com/anomalyco/models.dev/blob/dev/providers/minimax/models/MiniMax-M2.5-highspeed.toml',
|
|
464
559
|
},
|
|
465
560
|
{
|
|
466
|
-
provider:
|
|
467
|
-
model:
|
|
561
|
+
provider: 'minimax',
|
|
562
|
+
model: 'MiniMax-M2.1',
|
|
468
563
|
rates: minimaxPricing(0.3, 1.2, 0.03, 0.375),
|
|
469
|
-
source:
|
|
470
|
-
sourceURL:
|
|
564
|
+
source: 'runtime',
|
|
565
|
+
sourceURL: 'https://github.com/anomalyco/models.dev/blob/dev/providers/minimax/models/MiniMax-M2.1.toml',
|
|
471
566
|
},
|
|
472
567
|
{
|
|
473
|
-
provider:
|
|
474
|
-
model:
|
|
568
|
+
provider: 'minimax',
|
|
569
|
+
model: 'MiniMax-M2',
|
|
475
570
|
rates: minimaxPricing(0.3, 1.2, 0, 0),
|
|
476
|
-
source:
|
|
477
|
-
sourceURL:
|
|
571
|
+
source: 'runtime',
|
|
572
|
+
sourceURL: 'https://github.com/anomalyco/models.dev/blob/dev/providers/minimax/models/MiniMax-M2.toml',
|
|
478
573
|
},
|
|
479
574
|
];
|
|
480
575
|
export function modelCostKey(providerID, modelID) {
|
|
@@ -487,13 +582,13 @@ export function modelCostLookupKeys(providerID, modelID) {
|
|
|
487
582
|
if (!keys.includes(key))
|
|
488
583
|
keys.push(key);
|
|
489
584
|
};
|
|
490
|
-
const modelIDsFor = (options) => canonicalProviderID ===
|
|
585
|
+
const modelIDsFor = (options) => canonicalProviderID === 'anthropic'
|
|
491
586
|
? anthropicModelAliases(modelID)
|
|
492
|
-
: canonicalProviderID ===
|
|
587
|
+
: canonicalProviderID === 'zhipu'
|
|
493
588
|
? zhipuModelAliases(modelID)
|
|
494
|
-
: canonicalProviderID ===
|
|
589
|
+
: canonicalProviderID === 'moonshotai'
|
|
495
590
|
? moonshotModelAliases(modelID, options)
|
|
496
|
-
: canonicalProviderID ===
|
|
591
|
+
: canonicalProviderID === 'minimax'
|
|
497
592
|
? minimaxModelAliases(modelID)
|
|
498
593
|
: [modelID];
|
|
499
594
|
for (const candidateModelID of modelIDsFor()) {
|
|
@@ -541,9 +636,9 @@ export function parseModelCostRates(value) {
|
|
|
541
636
|
if (!isRecord(value))
|
|
542
637
|
return undefined;
|
|
543
638
|
const readRate = (input) => {
|
|
544
|
-
if (typeof input ===
|
|
639
|
+
if (typeof input === 'number')
|
|
545
640
|
return input;
|
|
546
|
-
if (typeof input ===
|
|
641
|
+
if (typeof input === 'string') {
|
|
547
642
|
const parsed = Number(input);
|
|
548
643
|
return Number.isFinite(parsed) ? parsed : 0;
|
|
549
644
|
}
|
|
@@ -595,12 +690,12 @@ export function guessModelCostDivisor(rates) {
|
|
|
595
690
|
}
|
|
596
691
|
export function cacheCoverageModeFromRates(rates) {
|
|
597
692
|
if (!rates)
|
|
598
|
-
return
|
|
693
|
+
return 'none';
|
|
599
694
|
if (rates.cacheWrite > 0)
|
|
600
|
-
return
|
|
695
|
+
return 'read-write';
|
|
601
696
|
if (rates.cacheRead > 0)
|
|
602
|
-
return
|
|
603
|
-
return
|
|
697
|
+
return 'read-only';
|
|
698
|
+
return 'none';
|
|
604
699
|
}
|
|
605
700
|
export function calcEquivalentApiCostForMessage(message, rates) {
|
|
606
701
|
const effectiveRates = message.tokens.input + message.tokens.cache.read > 200_000 &&
|
package/dist/format.js
CHANGED
|
@@ -736,36 +736,36 @@ function compactQuotaWide(quota, labelWidth = 0, options) {
|
|
|
736
736
|
: `Remaining ${percent}${reset ? ` Rst ${reset}` : ''}`;
|
|
737
737
|
return maybeBreak(fallbackText, [fallbackText]);
|
|
738
738
|
}
|
|
739
|
-
function
|
|
740
|
-
if (
|
|
741
|
-
return
|
|
742
|
-
|
|
739
|
+
function compactCountdown(remainingMs) {
|
|
740
|
+
if (!Number.isFinite(remainingMs))
|
|
741
|
+
return undefined;
|
|
742
|
+
if (remainingMs <= 0)
|
|
743
|
+
return '0m';
|
|
744
|
+
const minuteMs = 60_000;
|
|
745
|
+
const hourMinutes = 60;
|
|
746
|
+
const dayMinutes = 24 * hourMinutes;
|
|
747
|
+
const totalMinutes = Math.max(1, Math.floor(remainingMs / minuteMs));
|
|
748
|
+
if (totalMinutes < hourMinutes) {
|
|
749
|
+
return `${totalMinutes}m`;
|
|
750
|
+
}
|
|
751
|
+
if (totalMinutes < dayMinutes) {
|
|
752
|
+
const hours = Math.floor(totalMinutes / hourMinutes);
|
|
753
|
+
const minutes = totalMinutes % hourMinutes;
|
|
754
|
+
return `${hours}h${`${minutes}`.padStart(2, '0')}m`;
|
|
755
|
+
}
|
|
756
|
+
const days = Math.floor(totalMinutes / dayMinutes);
|
|
757
|
+
const hours = Math.floor((totalMinutes % dayMinutes) / hourMinutes);
|
|
758
|
+
return `${days}D${`${hours}`.padStart(2, '0')}h`;
|
|
743
759
|
}
|
|
744
760
|
function compactReset(iso, resetLabel, windowLabel) {
|
|
761
|
+
void resetLabel;
|
|
762
|
+
void windowLabel;
|
|
745
763
|
if (!iso)
|
|
746
764
|
return undefined;
|
|
747
765
|
const timestamp = Date.parse(iso);
|
|
748
766
|
if (Number.isNaN(timestamp))
|
|
749
767
|
return undefined;
|
|
750
|
-
|
|
751
|
-
// RightCode subscriptions are displayed as an expiry date (MM-DD), not a time.
|
|
752
|
-
// Using UTC here makes the output stable across time zones for ISO `...Z` input.
|
|
753
|
-
if (typeof resetLabel === 'string' && resetLabel.startsWith('Exp')) {
|
|
754
|
-
const two = (num) => `${num}`.padStart(2, '0');
|
|
755
|
-
return `${two(value.getUTCMonth() + 1)}-${two(value.getUTCDate())}`;
|
|
756
|
-
}
|
|
757
|
-
const now = new Date();
|
|
758
|
-
const sameDay = value.getFullYear() === now.getFullYear() &&
|
|
759
|
-
value.getMonth() === now.getMonth() &&
|
|
760
|
-
value.getDate() === now.getDate();
|
|
761
|
-
const two = (num) => `${num}`.padStart(2, '0');
|
|
762
|
-
if (isShortResetWindow(windowLabel)) {
|
|
763
|
-
const hhmm = `${two(value.getHours())}:${two(value.getMinutes())}`;
|
|
764
|
-
if (sameDay)
|
|
765
|
-
return hhmm;
|
|
766
|
-
return `${two(value.getMonth() + 1)}-${two(value.getDate())} ${hhmm}`;
|
|
767
|
-
}
|
|
768
|
-
return `${two(value.getMonth() + 1)}-${two(value.getDate())}`;
|
|
768
|
+
return compactCountdown(timestamp - Date.now());
|
|
769
769
|
}
|
|
770
770
|
function dateLine(iso) {
|
|
771
771
|
if (!iso)
|
|
@@ -785,16 +785,10 @@ function expiryAlertLine(iso, nowMs = Date.now()) {
|
|
|
785
785
|
const thresholdMs = 3 * 24 * 60 * 60 * 1000;
|
|
786
786
|
if (remainingMs > thresholdMs)
|
|
787
787
|
return undefined;
|
|
788
|
-
const
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
value.getDate() === now.getDate();
|
|
793
|
-
const two = (num) => `${num}`.padStart(2, '0');
|
|
794
|
-
const hhmm = `${two(value.getHours())}:${two(value.getMinutes())}`;
|
|
795
|
-
if (sameDay)
|
|
796
|
-
return `Exp today ${hhmm}`;
|
|
797
|
-
return `Exp ${two(value.getMonth() + 1)}-${two(value.getDate())} ${hhmm}`;
|
|
788
|
+
const countdown = compactCountdown(remainingMs);
|
|
789
|
+
if (!countdown)
|
|
790
|
+
return undefined;
|
|
791
|
+
return `Exp ${countdown}`;
|
|
798
792
|
}
|
|
799
793
|
function quotaExpiryPairs(quotas, nowMs = Date.now()) {
|
|
800
794
|
return collapseQuotaSnapshots(quotas)
|
|
@@ -805,6 +799,9 @@ function quotaExpiryPairs(quotas, nowMs = Date.now()) {
|
|
|
805
799
|
}))
|
|
806
800
|
.filter((item) => Boolean(item.value));
|
|
807
801
|
}
|
|
802
|
+
function toolVisibleQuotaSnapshots(quotas) {
|
|
803
|
+
return collapseQuotaSnapshots(quotas).filter((item) => item.status === 'ok' || item.status === 'error');
|
|
804
|
+
}
|
|
808
805
|
function reportResetLine(iso, resetLabel, windowLabel) {
|
|
809
806
|
const compact = compactReset(iso, resetLabel, windowLabel);
|
|
810
807
|
if (compact)
|
|
@@ -927,7 +924,7 @@ export function renderMarkdownReport(period, usage, quotas, options) {
|
|
|
927
924
|
const providerDivider = showCost
|
|
928
925
|
? '| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: |'
|
|
929
926
|
: '| --- | ---: | ---: | ---: | ---: | ---: |';
|
|
930
|
-
const quotaLines =
|
|
927
|
+
const quotaLines = toolVisibleQuotaSnapshots(quotas).flatMap((quota) => {
|
|
931
928
|
const displayLabel = quotaDisplayLabel(quota);
|
|
932
929
|
// Multi-window detail
|
|
933
930
|
if (quota.windows && quota.windows.length > 0 && quota.status === 'ok') {
|
|
@@ -953,7 +950,7 @@ export function renderMarkdownReport(period, usage, quotas, options) {
|
|
|
953
950
|
mdCell(`- ${displayLabel}: ${quota.status} | balance ${formatCurrency(quota.balance.amount, quota.balance.currency)}`),
|
|
954
951
|
];
|
|
955
952
|
}
|
|
956
|
-
if (quota.status
|
|
953
|
+
if (quota.status === 'error') {
|
|
957
954
|
return [
|
|
958
955
|
mdCell(`- ${displayLabel}: ${quota.status}${quota.note ? ` | ${quota.note}` : ''}`),
|
|
959
956
|
];
|
|
@@ -1074,7 +1071,7 @@ export function renderToastMessage(period, usage, quotas, options) {
|
|
|
1074
1071
|
lines.push(fitLine('Provider Cache', width));
|
|
1075
1072
|
lines.push(...alignPairs(providerCachePairs).map((line) => fitLine(line, width)));
|
|
1076
1073
|
}
|
|
1077
|
-
const quotaPairs =
|
|
1074
|
+
const quotaPairs = toolVisibleQuotaSnapshots(quotas).flatMap((item) => {
|
|
1078
1075
|
if (item.status === 'ok') {
|
|
1079
1076
|
if (item.windows && item.windows.length > 0) {
|
|
1080
1077
|
const pairs = item.windows.map((win, idx) => {
|
|
@@ -1118,12 +1115,6 @@ export function renderToastMessage(period, usage, quotas, options) {
|
|
|
1118
1115
|
},
|
|
1119
1116
|
];
|
|
1120
1117
|
}
|
|
1121
|
-
if (item.status === 'unsupported') {
|
|
1122
|
-
return [{ label: quotaDisplayLabel(item), value: 'unsupported' }];
|
|
1123
|
-
}
|
|
1124
|
-
if (item.status === 'unavailable') {
|
|
1125
|
-
return [{ label: quotaDisplayLabel(item), value: 'unavailable' }];
|
|
1126
|
-
}
|
|
1127
1118
|
return [{ label: quotaDisplayLabel(item), value: 'Remaining ?' }];
|
|
1128
1119
|
});
|
|
1129
1120
|
if (quotaPairs.length > 0) {
|
package/dist/index.js
CHANGED
|
@@ -186,9 +186,10 @@ export async function QuotaSidebarPlugin(input) {
|
|
|
186
186
|
startupTitleWork = runStartupRestore().catch(swallow('startup:restoreAllVisibleTitles'));
|
|
187
187
|
}
|
|
188
188
|
else {
|
|
189
|
-
startupTitleWork =
|
|
190
|
-
.
|
|
191
|
-
.catch(swallow('startup:refreshAllTouchedTitles'))
|
|
189
|
+
startupTitleWork = Promise.allSettled([
|
|
190
|
+
refreshAllVisibleTitles().catch(swallow('startup:refreshAllVisibleTitles')),
|
|
191
|
+
refreshAllTouchedTitles().catch(swallow('startup:refreshAllTouchedTitles')),
|
|
192
|
+
]).then(() => undefined);
|
|
192
193
|
}
|
|
193
194
|
const shutdown = async () => {
|
|
194
195
|
await Promise.race([
|
package/dist/title.js
CHANGED
|
@@ -57,28 +57,30 @@ function isCoreDecoratedDetail(line) {
|
|
|
57
57
|
function isQuotaDecoratedDetail(line) {
|
|
58
58
|
if (!line)
|
|
59
59
|
return false;
|
|
60
|
+
const resetValue = '[-:\\dhmD]+';
|
|
61
|
+
const compactResetValue = '\\d[\\d:.\\-hmD]*';
|
|
60
62
|
if (/^(OAI|Cop|Ant|Kimi|XYAI|RC(?:-[^\s]+)?)(?:\s+(?:\?|unsupported|unavailable|error|(?:\d+h|D|W|M)\d{1,3}|D[\d.,]+\/[\d.,]+|B(?:[¥$-])?[\d.,]+))+$/i.test(line)) {
|
|
61
63
|
return true;
|
|
62
64
|
}
|
|
63
65
|
if (/^(OpenAI|Copilot|Anthropic|Kimi|XYAI|RC(?:-[^\s]+)?)\s*$/.test(line)) {
|
|
64
66
|
return true;
|
|
65
67
|
}
|
|
66
|
-
if (
|
|
68
|
+
if (new RegExp(`^(?:(?:Daily\\s+\\$[\\d.,]+\\/\\$[\\d.,]+|\\$[\\d.,]+\\/\\$[\\d.,]+)(?:\\s+(?:Rst|Exp\\+?)\\s+${resetValue})?|(?:\\d+[hdw]|Weekly|Monthly)\\s+\\d{1,3}%(?:\\s+Rst\\s+${resetValue})?|Balance\\s+\\$[\\d.,]+|Remaining\\s+\\?|(?:error|unsupported|unavailable))$`).test(line)) {
|
|
67
69
|
return true;
|
|
68
70
|
}
|
|
69
|
-
if (
|
|
71
|
+
if (new RegExp(`^(?:D\\$?[\\d.,]+\\/\\$?[\\d.,]+|B(?:[¥$-])?[\\d.,]+|(?:\\d+[hdw]|[DWM])\\d{1,3}|(?:S7d|O7d|OA7d|Co7d)\\d{1,3})(?:\\s+(?:R|E\\+?)${compactResetValue})?$`).test(line)) {
|
|
70
72
|
return true;
|
|
71
73
|
}
|
|
72
|
-
if (
|
|
74
|
+
if (new RegExp(`^(OpenAI|Copilot|Anthropic|Kimi|XYAI|RC(?:-[^\\s]+)?)(?:\\s+(?:(?:Daily\\s+\\$[\\d.,]+\\/\\$[\\d.,]+|\\$[\\d.,]+\\/\\$[\\d.,]+)(?:\\s+(?:Rst|Exp\\+?)\\s+${resetValue})?|(?:\\d+[hdw]|Weekly|Monthly)\\s+\\d{1,3}%(?:\\s+Rst\\s+${resetValue})?|(?:error|unsupported|unavailable)))$`).test(line)) {
|
|
73
75
|
return true;
|
|
74
76
|
}
|
|
75
|
-
if (
|
|
77
|
+
if (new RegExp(`^(OpenAI|Copilot|Anthropic|Kimi|XYAI|RC(?:-[^\\s]+)?)(?:\\s+(?:D\\$?[\\d.,]+\\/\\$?[\\d.,]+|B(?:[¥$-])?[\\d.,]+|(?:\\d+[hdw]|[DWM])\\d{1,3}|(?:S7d|O7d|OA7d|Co7d)\\d{1,3})(?:\\s+(?:R|E\\+?)${compactResetValue})?)$`).test(line)) {
|
|
76
78
|
return true;
|
|
77
79
|
}
|
|
78
|
-
if (
|
|
80
|
+
if (new RegExp(`^(?:(?:D\\$?[\\d.,]+\\/\\$?[\\d.,]+|B(?:[¥$-])?[\\d.,]+|(?:\\d+[hdw]|[DWM])\\d{1,3}|(?:S7d|O7d|OA7d|Co7d)\\d{1,3}|(?:R|E\\+?)${compactResetValue}))(?:\\s+(?:(?:D\\$?[\\d.,]+\\/\\$?[\\d.,]+|B(?:[¥$-])?[\\d.,]+|(?:\\d+[hdw]|[DWM])\\d{1,3}|(?:S7d|O7d|OA7d|Co7d)\\d{1,3}|(?:R|E\\+?)${compactResetValue})))*$`).test(line)) {
|
|
79
81
|
return true;
|
|
80
82
|
}
|
|
81
|
-
if (
|
|
83
|
+
if (new RegExp(`^(OpenAI|Copilot|Anthropic|Kimi|XYAI|RC(?:-[^\\s]+)?)(?:\\s+(?:(?:D\\$?[\\d.,]+\\/\\$?[\\d.,]+|B(?:[¥$-])?[\\d.,]+|(?:\\d+[hdw]|[DWM])\\d{1,3}|(?:S7d|O7d|OA7d|Co7d)\\d{1,3}|(?:R|E\\+?)${compactResetValue})))*$`).test(line)) {
|
|
82
84
|
return true;
|
|
83
85
|
}
|
|
84
86
|
return false;
|
package/dist/tools.d.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
+
import * as z from 'zod';
|
|
1
2
|
import type { QuotaSnapshot } from './types.js';
|
|
2
3
|
import type { UsageSummary } from './usage.js';
|
|
4
|
+
type ToolContext = {
|
|
5
|
+
sessionID: string;
|
|
6
|
+
};
|
|
3
7
|
export declare function createQuotaSidebarTools(deps: {
|
|
4
8
|
getTitleEnabled: () => boolean;
|
|
5
9
|
setTitleEnabled: (enabled: boolean) => void;
|
|
@@ -50,28 +54,29 @@ export declare function createQuotaSidebarTools(deps: {
|
|
|
50
54
|
quota_summary: {
|
|
51
55
|
description: string;
|
|
52
56
|
args: {
|
|
53
|
-
period:
|
|
57
|
+
period: z.ZodOptional<z.ZodEnum<{
|
|
54
58
|
day: "day";
|
|
55
59
|
week: "week";
|
|
56
60
|
month: "month";
|
|
57
61
|
session: "session";
|
|
58
62
|
}>>;
|
|
59
|
-
toast:
|
|
60
|
-
includeChildren:
|
|
63
|
+
toast: z.ZodOptional<z.ZodBoolean>;
|
|
64
|
+
includeChildren: z.ZodOptional<z.ZodBoolean>;
|
|
61
65
|
};
|
|
62
|
-
execute(args: {
|
|
66
|
+
execute: (args: {
|
|
63
67
|
period?: "day" | "week" | "month" | "session" | undefined;
|
|
64
68
|
toast?: boolean | undefined;
|
|
65
69
|
includeChildren?: boolean | undefined;
|
|
66
|
-
}, context:
|
|
70
|
+
}, context: ToolContext) => Promise<string>;
|
|
67
71
|
};
|
|
68
72
|
quota_show: {
|
|
69
73
|
description: string;
|
|
70
74
|
args: {
|
|
71
|
-
enabled:
|
|
75
|
+
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
72
76
|
};
|
|
73
|
-
execute(args: {
|
|
77
|
+
execute: (args: {
|
|
74
78
|
enabled?: boolean | undefined;
|
|
75
|
-
}, context:
|
|
79
|
+
}, context: ToolContext) => Promise<string>;
|
|
76
80
|
};
|
|
77
81
|
};
|
|
82
|
+
export {};
|
package/dist/tools.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import * as z from 'zod';
|
|
2
|
+
function tool(input) {
|
|
3
|
+
return input;
|
|
4
|
+
}
|
|
3
5
|
export function createQuotaSidebarTools(deps) {
|
|
4
6
|
let toggleLock = Promise.resolve();
|
|
5
7
|
const waitForStartupTitleWork = async () => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@leo000001/opencode-quota-sidebar",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.5",
|
|
4
4
|
"description": "OpenCode plugin that shows quota and token usage in TUI sidebar panels and compact session titles",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -78,7 +78,8 @@
|
|
|
78
78
|
"dependencies": {
|
|
79
79
|
"@opentui/core": "^0.1.92",
|
|
80
80
|
"@opentui/solid": "^0.1.92",
|
|
81
|
-
"solid-js": "^1.9.10"
|
|
81
|
+
"solid-js": "^1.9.10",
|
|
82
|
+
"zod": "^4.1.8"
|
|
82
83
|
},
|
|
83
84
|
"devDependencies": {
|
|
84
85
|
"@opencode-ai/plugin": "^1.3.5",
|