ccus-cli 0.2.9 → 0.2.11
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 +8 -5
- package/dist/cli.js +55 -17
- package/dist/lib/aggregate-dashboard.js +67 -8
- package/dist/lib/aggregate.js +113 -23
- package/dist/lib/api-equivalent-cost.js +189 -0
- package/dist/lib/api-pricing-catalog.json +270 -0
- package/dist/lib/api-pricing-table.js +163 -0
- package/dist/lib/claude.js +52 -9
- package/dist/lib/codex-sessions.js +153 -45
- package/dist/lib/dashboard-pages.js +15 -0
- package/dist/lib/dashboard.js +35 -1
- package/dist/lib/export.js +12 -0
- package/dist/lib/paths.js +37 -0
- package/package.json +3 -2
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
{
|
|
2
|
+
"catalogVersion": "2026-08-17",
|
|
3
|
+
"currency": "USD",
|
|
4
|
+
"basis": "event-time-standard-api",
|
|
5
|
+
"entries": [
|
|
6
|
+
{
|
|
7
|
+
"provider": "claude",
|
|
8
|
+
"model": "claude-opus-3",
|
|
9
|
+
"effectiveFrom": "2024-02-29T00:00:00.000Z",
|
|
10
|
+
"effectiveTo": null,
|
|
11
|
+
"prices": { "inputUsdPerMillion": 15, "outputUsdPerMillion": 75, "cacheReadInputUsdPerMillion": 1.5, "cacheWrite5mInputUsdPerMillion": 18.75, "cacheWrite1hInputUsdPerMillion": 30 }
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"provider": "claude",
|
|
15
|
+
"model": "claude-haiku-3",
|
|
16
|
+
"effectiveFrom": "2024-03-13T00:00:00.000Z",
|
|
17
|
+
"effectiveTo": null,
|
|
18
|
+
"prices": { "inputUsdPerMillion": 0.25, "outputUsdPerMillion": 1.25, "cacheReadInputUsdPerMillion": 0.025, "cacheWrite5mInputUsdPerMillion": 0.3125, "cacheWrite1hInputUsdPerMillion": 0.5 }
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"provider": "claude",
|
|
22
|
+
"model": "claude-sonnet-3.5",
|
|
23
|
+
"effectiveFrom": "2024-06-20T00:00:00.000Z",
|
|
24
|
+
"effectiveTo": null,
|
|
25
|
+
"prices": { "inputUsdPerMillion": 3, "outputUsdPerMillion": 15, "cacheReadInputUsdPerMillion": 0.3, "cacheWrite5mInputUsdPerMillion": 3.75, "cacheWrite1hInputUsdPerMillion": 6 }
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"provider": "claude",
|
|
29
|
+
"model": "claude-haiku-3.5",
|
|
30
|
+
"effectiveFrom": "2024-10-22T00:00:00.000Z",
|
|
31
|
+
"effectiveTo": null,
|
|
32
|
+
"prices": { "inputUsdPerMillion": 0.8, "outputUsdPerMillion": 4, "cacheReadInputUsdPerMillion": 0.08, "cacheWrite5mInputUsdPerMillion": 1, "cacheWrite1hInputUsdPerMillion": 1.6 }
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"provider": "claude",
|
|
36
|
+
"model": "claude-sonnet-3.7",
|
|
37
|
+
"effectiveFrom": "2025-02-24T00:00:00.000Z",
|
|
38
|
+
"effectiveTo": null,
|
|
39
|
+
"prices": { "inputUsdPerMillion": 3, "outputUsdPerMillion": 15, "cacheReadInputUsdPerMillion": 0.3, "cacheWrite5mInputUsdPerMillion": 3.75, "cacheWrite1hInputUsdPerMillion": 6 }
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"provider": "claude",
|
|
43
|
+
"model": "claude-opus-4",
|
|
44
|
+
"effectiveFrom": "2025-05-22T00:00:00.000Z",
|
|
45
|
+
"effectiveTo": null,
|
|
46
|
+
"prices": { "inputUsdPerMillion": 15, "outputUsdPerMillion": 75, "cacheReadInputUsdPerMillion": 1.5, "cacheWrite5mInputUsdPerMillion": 18.75, "cacheWrite1hInputUsdPerMillion": 30 }
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"provider": "claude",
|
|
50
|
+
"model": "claude-sonnet-4",
|
|
51
|
+
"effectiveFrom": "2025-05-22T00:00:00.000Z",
|
|
52
|
+
"effectiveTo": null,
|
|
53
|
+
"prices": { "inputUsdPerMillion": 3, "outputUsdPerMillion": 15, "cacheReadInputUsdPerMillion": 0.3, "cacheWrite5mInputUsdPerMillion": 3.75, "cacheWrite1hInputUsdPerMillion": 6 },
|
|
54
|
+
"longContext": {
|
|
55
|
+
"thresholdInputTokens": 200000,
|
|
56
|
+
"prices": { "inputUsdPerMillion": 6, "outputUsdPerMillion": 22.5, "cacheReadInputUsdPerMillion": 0.6, "cacheWrite5mInputUsdPerMillion": 7.5, "cacheWrite1hInputUsdPerMillion": 12 }
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"provider": "claude",
|
|
61
|
+
"model": "claude-opus-4.1",
|
|
62
|
+
"effectiveFrom": "2025-08-05T00:00:00.000Z",
|
|
63
|
+
"effectiveTo": null,
|
|
64
|
+
"prices": { "inputUsdPerMillion": 15, "outputUsdPerMillion": 75, "cacheReadInputUsdPerMillion": 1.5, "cacheWrite5mInputUsdPerMillion": 18.75, "cacheWrite1hInputUsdPerMillion": 30 }
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"provider": "claude",
|
|
68
|
+
"model": "claude-sonnet-4.5",
|
|
69
|
+
"effectiveFrom": "2025-09-29T00:00:00.000Z",
|
|
70
|
+
"effectiveTo": null,
|
|
71
|
+
"prices": { "inputUsdPerMillion": 3, "outputUsdPerMillion": 15, "cacheReadInputUsdPerMillion": 0.3, "cacheWrite5mInputUsdPerMillion": 3.75, "cacheWrite1hInputUsdPerMillion": 6 },
|
|
72
|
+
"longContext": {
|
|
73
|
+
"thresholdInputTokens": 200000,
|
|
74
|
+
"prices": { "inputUsdPerMillion": 6, "outputUsdPerMillion": 22.5, "cacheReadInputUsdPerMillion": 0.6, "cacheWrite5mInputUsdPerMillion": 7.5, "cacheWrite1hInputUsdPerMillion": 12 }
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"provider": "claude",
|
|
79
|
+
"model": "claude-haiku-4.5",
|
|
80
|
+
"effectiveFrom": "2025-10-15T00:00:00.000Z",
|
|
81
|
+
"effectiveTo": null,
|
|
82
|
+
"prices": { "inputUsdPerMillion": 1, "outputUsdPerMillion": 5, "cacheReadInputUsdPerMillion": 0.1, "cacheWrite5mInputUsdPerMillion": 1.25, "cacheWrite1hInputUsdPerMillion": 2 }
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"provider": "claude",
|
|
86
|
+
"model": "claude-opus-4.5",
|
|
87
|
+
"effectiveFrom": "2025-11-24T00:00:00.000Z",
|
|
88
|
+
"effectiveTo": null,
|
|
89
|
+
"prices": { "inputUsdPerMillion": 5, "outputUsdPerMillion": 25, "cacheReadInputUsdPerMillion": 0.5, "cacheWrite5mInputUsdPerMillion": 6.25, "cacheWrite1hInputUsdPerMillion": 10 }
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"provider": "claude",
|
|
93
|
+
"model": "claude-opus-4.6",
|
|
94
|
+
"effectiveFrom": "2026-02-05T00:00:00.000Z",
|
|
95
|
+
"effectiveTo": null,
|
|
96
|
+
"prices": { "inputUsdPerMillion": 5, "outputUsdPerMillion": 25, "cacheReadInputUsdPerMillion": 0.5, "cacheWrite5mInputUsdPerMillion": 6.25, "cacheWrite1hInputUsdPerMillion": 10 }
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"provider": "claude",
|
|
100
|
+
"model": "claude-sonnet-4.6",
|
|
101
|
+
"effectiveFrom": "2026-02-17T00:00:00.000Z",
|
|
102
|
+
"effectiveTo": null,
|
|
103
|
+
"prices": { "inputUsdPerMillion": 3, "outputUsdPerMillion": 15, "cacheReadInputUsdPerMillion": 0.3, "cacheWrite5mInputUsdPerMillion": 3.75, "cacheWrite1hInputUsdPerMillion": 6 },
|
|
104
|
+
"longContext": {
|
|
105
|
+
"thresholdInputTokens": 200000,
|
|
106
|
+
"prices": { "inputUsdPerMillion": 6, "outputUsdPerMillion": 22.5, "cacheReadInputUsdPerMillion": 0.6, "cacheWrite5mInputUsdPerMillion": 7.5, "cacheWrite1hInputUsdPerMillion": 12 }
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"provider": "claude",
|
|
111
|
+
"model": "claude-opus-4.7",
|
|
112
|
+
"effectiveFrom": "2026-04-16T00:00:00.000Z",
|
|
113
|
+
"effectiveTo": null,
|
|
114
|
+
"prices": { "inputUsdPerMillion": 5, "outputUsdPerMillion": 25, "cacheReadInputUsdPerMillion": 0.5, "cacheWrite5mInputUsdPerMillion": 6.25, "cacheWrite1hInputUsdPerMillion": 10 }
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"provider": "claude",
|
|
118
|
+
"model": "claude-opus-4.8",
|
|
119
|
+
"effectiveFrom": "2026-05-28T00:00:00.000Z",
|
|
120
|
+
"effectiveTo": null,
|
|
121
|
+
"prices": { "inputUsdPerMillion": 5, "outputUsdPerMillion": 25, "cacheReadInputUsdPerMillion": 0.5, "cacheWrite5mInputUsdPerMillion": 6.25, "cacheWrite1hInputUsdPerMillion": 10 }
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"provider": "claude",
|
|
125
|
+
"model": "claude-fable-5",
|
|
126
|
+
"effectiveFrom": "2026-06-09T00:00:00.000Z",
|
|
127
|
+
"effectiveTo": null,
|
|
128
|
+
"prices": { "inputUsdPerMillion": 10, "outputUsdPerMillion": 50, "cacheReadInputUsdPerMillion": 1, "cacheWrite5mInputUsdPerMillion": 12.5, "cacheWrite1hInputUsdPerMillion": 20 }
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
"provider": "claude",
|
|
132
|
+
"model": "claude-sonnet-5",
|
|
133
|
+
"effectiveFrom": "2026-06-30T00:00:00.000Z",
|
|
134
|
+
"effectiveTo": "2026-09-01T00:00:00.000Z",
|
|
135
|
+
"prices": { "inputUsdPerMillion": 2, "outputUsdPerMillion": 10, "cacheReadInputUsdPerMillion": 0.2, "cacheWrite5mInputUsdPerMillion": 2.5, "cacheWrite1hInputUsdPerMillion": 4 }
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
"provider": "claude",
|
|
139
|
+
"model": "claude-sonnet-5",
|
|
140
|
+
"effectiveFrom": "2026-09-01T00:00:00.000Z",
|
|
141
|
+
"effectiveTo": null,
|
|
142
|
+
"prices": { "inputUsdPerMillion": 3, "outputUsdPerMillion": 15, "cacheReadInputUsdPerMillion": 0.3, "cacheWrite5mInputUsdPerMillion": 3.75, "cacheWrite1hInputUsdPerMillion": 6 }
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
"provider": "claude",
|
|
146
|
+
"model": "claude-opus-5",
|
|
147
|
+
"effectiveFrom": "2026-07-24T00:00:00.000Z",
|
|
148
|
+
"effectiveTo": null,
|
|
149
|
+
"prices": { "inputUsdPerMillion": 5, "outputUsdPerMillion": 25, "cacheReadInputUsdPerMillion": 0.5, "cacheWrite5mInputUsdPerMillion": 6.25, "cacheWrite1hInputUsdPerMillion": 10 }
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
"provider": "codex",
|
|
153
|
+
"model": "gpt-5",
|
|
154
|
+
"effectiveFrom": "2025-08-07T00:00:00.000Z",
|
|
155
|
+
"effectiveTo": null,
|
|
156
|
+
"prices": { "inputUsdPerMillion": 1.25, "outputUsdPerMillion": 10, "cacheReadInputUsdPerMillion": 0.125 }
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
"provider": "codex",
|
|
160
|
+
"model": "gpt-5-codex",
|
|
161
|
+
"effectiveFrom": "2025-09-23T00:00:00.000Z",
|
|
162
|
+
"effectiveTo": null,
|
|
163
|
+
"prices": { "inputUsdPerMillion": 1.25, "outputUsdPerMillion": 10, "cacheReadInputUsdPerMillion": 0.125 }
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
"provider": "codex",
|
|
167
|
+
"model": "gpt-5.1",
|
|
168
|
+
"effectiveFrom": "2025-11-13T00:00:00.000Z",
|
|
169
|
+
"effectiveTo": null,
|
|
170
|
+
"prices": { "inputUsdPerMillion": 1.25, "outputUsdPerMillion": 10, "cacheReadInputUsdPerMillion": 0.125 }
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
"provider": "codex",
|
|
174
|
+
"model": "gpt-5.1-codex",
|
|
175
|
+
"effectiveFrom": "2025-11-13T00:00:00.000Z",
|
|
176
|
+
"effectiveTo": null,
|
|
177
|
+
"prices": { "inputUsdPerMillion": 1.25, "outputUsdPerMillion": 10, "cacheReadInputUsdPerMillion": 0.125 }
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
"provider": "codex",
|
|
181
|
+
"model": "gpt-5.1-codex-mini",
|
|
182
|
+
"effectiveFrom": "2025-11-13T00:00:00.000Z",
|
|
183
|
+
"effectiveTo": null,
|
|
184
|
+
"prices": { "inputUsdPerMillion": 0.25, "outputUsdPerMillion": 2, "cacheReadInputUsdPerMillion": 0.025 }
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
"provider": "codex",
|
|
188
|
+
"model": "gpt-5.1-codex-max",
|
|
189
|
+
"effectiveFrom": "2025-12-04T00:00:00.000Z",
|
|
190
|
+
"effectiveTo": null,
|
|
191
|
+
"prices": { "inputUsdPerMillion": 1.25, "outputUsdPerMillion": 10, "cacheReadInputUsdPerMillion": 0.125 }
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
"provider": "codex",
|
|
195
|
+
"model": "gpt-5.2",
|
|
196
|
+
"effectiveFrom": "2025-12-11T00:00:00.000Z",
|
|
197
|
+
"effectiveTo": null,
|
|
198
|
+
"prices": { "inputUsdPerMillion": 1.75, "outputUsdPerMillion": 14, "cacheReadInputUsdPerMillion": 0.175 }
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
"provider": "codex",
|
|
202
|
+
"model": "gpt-5.2-codex",
|
|
203
|
+
"effectiveFrom": "2025-12-18T00:00:00.000Z",
|
|
204
|
+
"effectiveTo": null,
|
|
205
|
+
"prices": { "inputUsdPerMillion": 1.75, "outputUsdPerMillion": 14, "cacheReadInputUsdPerMillion": 0.175 }
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
"provider": "codex",
|
|
209
|
+
"model": "gpt-5.3-codex",
|
|
210
|
+
"effectiveFrom": "2026-02-05T00:00:00.000Z",
|
|
211
|
+
"effectiveTo": null,
|
|
212
|
+
"prices": { "inputUsdPerMillion": 1.75, "outputUsdPerMillion": 14, "cacheReadInputUsdPerMillion": 0.175 }
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
"provider": "codex",
|
|
216
|
+
"model": "gpt-5.4",
|
|
217
|
+
"effectiveFrom": "2026-03-05T00:00:00.000Z",
|
|
218
|
+
"effectiveTo": null,
|
|
219
|
+
"prices": { "inputUsdPerMillion": 2.5, "outputUsdPerMillion": 15, "cacheReadInputUsdPerMillion": 0.25 },
|
|
220
|
+
"longContext": {
|
|
221
|
+
"thresholdInputTokens": 272000,
|
|
222
|
+
"prices": { "inputUsdPerMillion": 5, "outputUsdPerMillion": 22.5, "cacheReadInputUsdPerMillion": 0.5 }
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
"provider": "codex",
|
|
227
|
+
"model": "gpt-5.5",
|
|
228
|
+
"effectiveFrom": "2026-05-01T00:00:00.000Z",
|
|
229
|
+
"effectiveTo": null,
|
|
230
|
+
"prices": { "inputUsdPerMillion": 5, "outputUsdPerMillion": 30, "cacheReadInputUsdPerMillion": 0.5 },
|
|
231
|
+
"longContext": {
|
|
232
|
+
"thresholdInputTokens": 272000,
|
|
233
|
+
"prices": { "inputUsdPerMillion": 10, "outputUsdPerMillion": 45, "cacheReadInputUsdPerMillion": 1 }
|
|
234
|
+
}
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
"provider": "codex",
|
|
238
|
+
"model": "gpt-5.6-sol",
|
|
239
|
+
"effectiveFrom": "2026-08-01T00:00:00.000Z",
|
|
240
|
+
"effectiveTo": null,
|
|
241
|
+
"prices": { "inputUsdPerMillion": 5, "outputUsdPerMillion": 30, "cacheReadInputUsdPerMillion": 0.5 },
|
|
242
|
+
"longContext": {
|
|
243
|
+
"thresholdInputTokens": 272000,
|
|
244
|
+
"prices": { "inputUsdPerMillion": 10, "outputUsdPerMillion": 45, "cacheReadInputUsdPerMillion": 1 }
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
"provider": "codex",
|
|
249
|
+
"model": "gpt-5.6-terra",
|
|
250
|
+
"effectiveFrom": "2026-08-01T00:00:00.000Z",
|
|
251
|
+
"effectiveTo": null,
|
|
252
|
+
"prices": { "inputUsdPerMillion": 2.5, "outputUsdPerMillion": 15, "cacheReadInputUsdPerMillion": 0.25 },
|
|
253
|
+
"longContext": {
|
|
254
|
+
"thresholdInputTokens": 272000,
|
|
255
|
+
"prices": { "inputUsdPerMillion": 5, "outputUsdPerMillion": 22.5, "cacheReadInputUsdPerMillion": 0.5 }
|
|
256
|
+
}
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
"provider": "codex",
|
|
260
|
+
"model": "gpt-5.6-luna",
|
|
261
|
+
"effectiveFrom": "2026-08-01T00:00:00.000Z",
|
|
262
|
+
"effectiveTo": null,
|
|
263
|
+
"prices": { "inputUsdPerMillion": 1, "outputUsdPerMillion": 6, "cacheReadInputUsdPerMillion": 0.1 },
|
|
264
|
+
"longContext": {
|
|
265
|
+
"thresholdInputTokens": 272000,
|
|
266
|
+
"prices": { "inputUsdPerMillion": 2, "outputUsdPerMillion": 9, "cacheReadInputUsdPerMillion": 0.2 }
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
]
|
|
270
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.API_PRICING_PAGE_PATH = exports.API_PRICING_PAGE_FILE = void 0;
|
|
4
|
+
exports.renderCurrentApiPricingTable = renderCurrentApiPricingTable;
|
|
5
|
+
exports.buildApiPricingPage = buildApiPricingPage;
|
|
6
|
+
const api_equivalent_cost_1 = require("./api-equivalent-cost");
|
|
7
|
+
exports.API_PRICING_PAGE_FILE = "pricing.html";
|
|
8
|
+
exports.API_PRICING_PAGE_PATH = `/${exports.API_PRICING_PAGE_FILE}`;
|
|
9
|
+
function escapeHtml(value) {
|
|
10
|
+
return value
|
|
11
|
+
.replaceAll("&", "&")
|
|
12
|
+
.replaceAll("<", "<")
|
|
13
|
+
.replaceAll(">", ">")
|
|
14
|
+
.replaceAll('"', """)
|
|
15
|
+
.replaceAll("'", "'");
|
|
16
|
+
}
|
|
17
|
+
function formatPrice(value) {
|
|
18
|
+
return value === undefined ? "--" : `$${value.toLocaleString("en-US", { maximumFractionDigits: 6 })}`;
|
|
19
|
+
}
|
|
20
|
+
function renderPriceRow(entry, tier, prices) {
|
|
21
|
+
return `
|
|
22
|
+
<tr>
|
|
23
|
+
<td>${entry.provider === "claude" ? "Claude" : "Codex"}</td>
|
|
24
|
+
<td><code>${escapeHtml(entry.model)}</code></td>
|
|
25
|
+
<td>${escapeHtml(tier)}</td>
|
|
26
|
+
<td>${escapeHtml(entry.effectiveFrom.slice(0, 10))}</td>
|
|
27
|
+
<td>${formatPrice(prices.inputUsdPerMillion)}</td>
|
|
28
|
+
<td>${formatPrice(prices.outputUsdPerMillion)}</td>
|
|
29
|
+
<td>${formatPrice(prices.cacheReadInputUsdPerMillion)}</td>
|
|
30
|
+
<td>${formatPrice(prices.cacheWrite5mInputUsdPerMillion)}</td>
|
|
31
|
+
<td>${formatPrice(prices.cacheWrite1hInputUsdPerMillion)}</td>
|
|
32
|
+
</tr>`;
|
|
33
|
+
}
|
|
34
|
+
function providerRank(provider) {
|
|
35
|
+
return provider === "codex" ? 0 : 1;
|
|
36
|
+
}
|
|
37
|
+
function compareModelVersionsDescending(left, right) {
|
|
38
|
+
const leftParts = left.match(/\d+(?:\.\d+)*/)?.[0].split(".").map(Number) ?? [];
|
|
39
|
+
const rightParts = right.match(/\d+(?:\.\d+)*/)?.[0].split(".").map(Number) ?? [];
|
|
40
|
+
const length = Math.max(leftParts.length, rightParts.length);
|
|
41
|
+
for (let index = 0; index < length; index += 1) {
|
|
42
|
+
const difference = (rightParts[index] ?? 0) - (leftParts[index] ?? 0);
|
|
43
|
+
if (difference !== 0) {
|
|
44
|
+
return difference;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return 0;
|
|
48
|
+
}
|
|
49
|
+
function comparePricingEntries(left, right) {
|
|
50
|
+
const providerDifference = providerRank(left.provider) - providerRank(right.provider);
|
|
51
|
+
if (providerDifference !== 0) {
|
|
52
|
+
return providerDifference;
|
|
53
|
+
}
|
|
54
|
+
return left.provider === "codex"
|
|
55
|
+
? compareModelVersionsDescending(left.model, right.model)
|
|
56
|
+
: left.model.localeCompare(right.model);
|
|
57
|
+
}
|
|
58
|
+
/** 按页面生成时间渲染有效区间内的普通与长上下文价格。 */
|
|
59
|
+
function renderCurrentApiPricingTable(catalog = api_equivalent_cost_1.API_PRICING_CATALOG, generatedAt = new Date()) {
|
|
60
|
+
const generatedAtMs = generatedAt.getTime();
|
|
61
|
+
const entries = catalog.entries
|
|
62
|
+
.filter((entry) => {
|
|
63
|
+
const effectiveFromMs = new Date(entry.effectiveFrom).getTime();
|
|
64
|
+
const effectiveToMs = entry.effectiveTo === null ? Number.POSITIVE_INFINITY : new Date(entry.effectiveTo).getTime();
|
|
65
|
+
return generatedAtMs >= effectiveFromMs && generatedAtMs < effectiveToMs;
|
|
66
|
+
})
|
|
67
|
+
.sort(comparePricingEntries);
|
|
68
|
+
const rows = entries.flatMap((entry) => {
|
|
69
|
+
const itemRows = [renderPriceRow(entry, "普通", entry.prices)];
|
|
70
|
+
if (entry.longContext) {
|
|
71
|
+
itemRows.push(renderPriceRow(entry, `长上下文(输入类 token > ${entry.longContext.thresholdInputTokens.toLocaleString("en-US")})`, entry.longContext.prices));
|
|
72
|
+
}
|
|
73
|
+
return itemRows;
|
|
74
|
+
}).join("");
|
|
75
|
+
return `
|
|
76
|
+
<section class="panel table-panel">
|
|
77
|
+
<div class="panel-header">
|
|
78
|
+
<p class="muted">目录 ${escapeHtml(catalog.catalogVersion)} · USD / 百万 token · 标准同步 API</p>
|
|
79
|
+
</div>
|
|
80
|
+
<div class="table-wrap">
|
|
81
|
+
<table class="pricing-table">
|
|
82
|
+
<thead>
|
|
83
|
+
<tr>
|
|
84
|
+
<th>来源</th>
|
|
85
|
+
<th>模型</th>
|
|
86
|
+
<th>计价档位</th>
|
|
87
|
+
<th>生效日期</th>
|
|
88
|
+
<th>输入</th>
|
|
89
|
+
<th>输出</th>
|
|
90
|
+
<th>缓存读取</th>
|
|
91
|
+
<th>5 分钟缓存写入</th>
|
|
92
|
+
<th>1 小时缓存写入</th>
|
|
93
|
+
</tr>
|
|
94
|
+
</thead>
|
|
95
|
+
<tbody>${rows}</tbody>
|
|
96
|
+
</table>
|
|
97
|
+
</div>
|
|
98
|
+
</section>`;
|
|
99
|
+
}
|
|
100
|
+
/** 生成可独立打开的当前 API 价格页面。 */
|
|
101
|
+
function buildApiPricingPage(generatedAt = new Date(), catalog = api_equivalent_cost_1.API_PRICING_CATALOG) {
|
|
102
|
+
return `<!doctype html>
|
|
103
|
+
<html lang="zh-CN">
|
|
104
|
+
<head>
|
|
105
|
+
<meta charset="utf-8" />
|
|
106
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
107
|
+
<title>ccus 当前模型价格</title>
|
|
108
|
+
<style>
|
|
109
|
+
:root {
|
|
110
|
+
--bg: #0a0d12;
|
|
111
|
+
--panel: rgba(16, 21, 31, 0.84);
|
|
112
|
+
--panel-border: rgba(120, 141, 173, 0.18);
|
|
113
|
+
--text: #ecf3ff;
|
|
114
|
+
--muted: #91a0b8;
|
|
115
|
+
--accent: #5eead4;
|
|
116
|
+
--shadow: 0 24px 80px rgba(0, 0, 0, 0.35);
|
|
117
|
+
}
|
|
118
|
+
* { box-sizing: border-box; }
|
|
119
|
+
body {
|
|
120
|
+
margin: 0;
|
|
121
|
+
min-height: 100vh;
|
|
122
|
+
font-family: Georgia, "Times New Roman", serif;
|
|
123
|
+
color: var(--text);
|
|
124
|
+
background:
|
|
125
|
+
radial-gradient(circle at top left, rgba(34, 197, 94, 0.18), transparent 30%),
|
|
126
|
+
radial-gradient(circle at top right, rgba(94, 234, 212, 0.16), transparent 28%),
|
|
127
|
+
linear-gradient(160deg, #06080c 0%, #0a0d12 48%, #101520 100%);
|
|
128
|
+
}
|
|
129
|
+
.shell { max-width: 1240px; margin: 0 auto; padding: 40px 24px 64px; }
|
|
130
|
+
.hero { display: grid; gap: 12px; padding: 28px 0 18px; }
|
|
131
|
+
.eyebrow { margin: 0 0 8px; color: var(--accent); text-transform: uppercase; letter-spacing: 0.14em; font-size: 12px; }
|
|
132
|
+
h1, p { margin: 0; }
|
|
133
|
+
h1 { font-size: clamp(36px, 5vw, 60px); line-height: 0.95; font-weight: 600; }
|
|
134
|
+
.muted { color: var(--muted); font-size: 14px; }
|
|
135
|
+
.panel { background: var(--panel); border: 1px solid var(--panel-border); border-radius: 24px; box-shadow: var(--shadow); }
|
|
136
|
+
.table-panel { margin-top: 22px; }
|
|
137
|
+
.panel-header { padding: 24px 24px 0; }
|
|
138
|
+
.table-wrap { overflow: auto; padding: 16px 20px 22px; }
|
|
139
|
+
table { width: 100%; min-width: 1080px; border-collapse: collapse; }
|
|
140
|
+
th, td { text-align: left; padding: 12px 10px; border-bottom: 1px solid rgba(145, 160, 184, 0.12); vertical-align: top; }
|
|
141
|
+
th { color: var(--muted); font-size: 12px; text-transform: uppercase; letter-spacing: 0.08em; font-weight: 500; }
|
|
142
|
+
td { font-size: 14px; }
|
|
143
|
+
code { font-family: "Cascadia Code", "SFMono-Regular", Consolas, monospace; font-size: 12px; }
|
|
144
|
+
@media (max-width: 720px) {
|
|
145
|
+
.shell { padding-inline: 16px; }
|
|
146
|
+
}
|
|
147
|
+
</style>
|
|
148
|
+
</head>
|
|
149
|
+
<body>
|
|
150
|
+
<main class="shell">
|
|
151
|
+
<section class="hero">
|
|
152
|
+
<div>
|
|
153
|
+
<p class="eyebrow">Current API Pricing</p>
|
|
154
|
+
<h1>当前模型价格</h1>
|
|
155
|
+
</div>
|
|
156
|
+
<p class="muted">标准同步 API 参考价格,不是订阅或实际账单。</p>
|
|
157
|
+
</section>
|
|
158
|
+
${renderCurrentApiPricingTable(catalog, generatedAt)}
|
|
159
|
+
</main>
|
|
160
|
+
</body>
|
|
161
|
+
</html>`;
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=api-pricing-table.js.map
|
package/dist/lib/claude.js
CHANGED
|
@@ -8,6 +8,7 @@ exports.findActiveSessionFiles = findActiveSessionFiles;
|
|
|
8
8
|
exports.summarizeClaudeProjectUsageByDay = summarizeClaudeProjectUsageByDay;
|
|
9
9
|
const promises_1 = __importDefault(require("node:fs/promises"));
|
|
10
10
|
const node_path_1 = __importDefault(require("node:path"));
|
|
11
|
+
const api_equivalent_cost_1 = require("./api-equivalent-cost");
|
|
11
12
|
const paths_1 = require("./paths");
|
|
12
13
|
function isRecord(value) {
|
|
13
14
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -18,6 +19,39 @@ function getNumber(value) {
|
|
|
18
19
|
function getString(value) {
|
|
19
20
|
return typeof value === "string" && value.length > 0 ? value : null;
|
|
20
21
|
}
|
|
22
|
+
function hasOwn(record, key) {
|
|
23
|
+
return Object.prototype.hasOwnProperty.call(record, key);
|
|
24
|
+
}
|
|
25
|
+
function summarizeAssistantUsage(message, timestamp) {
|
|
26
|
+
const usage = message.usage;
|
|
27
|
+
const cacheCreation = isRecord(usage.cache_creation) ? usage.cache_creation : null;
|
|
28
|
+
const hasFiveMinuteDetail = cacheCreation !== null && hasOwn(cacheCreation, "ephemeral_5m_input_tokens");
|
|
29
|
+
const hasOneHourDetail = cacheCreation !== null && hasOwn(cacheCreation, "ephemeral_1h_input_tokens");
|
|
30
|
+
const cacheWrite5mInputTokens = hasFiveMinuteDetail || hasOneHourDetail
|
|
31
|
+
? getNumber(cacheCreation?.ephemeral_5m_input_tokens)
|
|
32
|
+
: getNumber(usage.cache_creation_input_tokens);
|
|
33
|
+
const cacheWrite1hInputTokens = hasFiveMinuteDetail || hasOneHourDetail
|
|
34
|
+
? getNumber(cacheCreation?.ephemeral_1h_input_tokens)
|
|
35
|
+
: 0;
|
|
36
|
+
const inputTokens = getNumber(usage.input_tokens);
|
|
37
|
+
const outputTokens = getNumber(usage.output_tokens);
|
|
38
|
+
const cacheReadInputTokens = getNumber(usage.cache_read_input_tokens);
|
|
39
|
+
return {
|
|
40
|
+
inputTokens,
|
|
41
|
+
outputTokens,
|
|
42
|
+
cacheReadInputTokens,
|
|
43
|
+
apiEquivalentCost: (0, api_equivalent_cost_1.priceApiRequest)({
|
|
44
|
+
provider: "claude",
|
|
45
|
+
timestamp,
|
|
46
|
+
model: getString(message.model),
|
|
47
|
+
inputTokens,
|
|
48
|
+
outputTokens,
|
|
49
|
+
cacheReadInputTokens,
|
|
50
|
+
cacheWrite5mInputTokens,
|
|
51
|
+
cacheWrite1hInputTokens,
|
|
52
|
+
}),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
21
55
|
async function collectProjectJsonlFiles(directoryPath) {
|
|
22
56
|
try {
|
|
23
57
|
const entries = await promises_1.default.readdir(directoryPath, { withFileTypes: true });
|
|
@@ -87,11 +121,13 @@ function summarizeProjectTranscript(content, start, end) {
|
|
|
87
121
|
inputTokens: 0,
|
|
88
122
|
outputTokens: 0,
|
|
89
123
|
cacheReadInputTokens: 0,
|
|
124
|
+
apiEquivalentCost: (0, api_equivalent_cost_1.emptyApiEquivalentCost)(),
|
|
90
125
|
};
|
|
91
126
|
for (const line of lines) {
|
|
92
127
|
try {
|
|
93
128
|
const record = JSON.parse(line);
|
|
94
|
-
|
|
129
|
+
const timestamp = isRecord(record) ? getString(record.timestamp) : null;
|
|
130
|
+
if (!isRecord(record) || !timestampInRange(timestamp, start, end)) {
|
|
95
131
|
continue;
|
|
96
132
|
}
|
|
97
133
|
if (isHumanUserMessage(record)) {
|
|
@@ -100,10 +136,12 @@ function summarizeProjectTranscript(content, start, end) {
|
|
|
100
136
|
if (record.type !== "assistant" || !isRecord(record.message) || !isRecord(record.message.usage)) {
|
|
101
137
|
continue;
|
|
102
138
|
}
|
|
139
|
+
const assistantUsage = summarizeAssistantUsage(record.message, timestamp);
|
|
103
140
|
summary.apiRequestCount += 1;
|
|
104
|
-
summary.inputTokens +=
|
|
105
|
-
summary.outputTokens +=
|
|
106
|
-
summary.cacheReadInputTokens +=
|
|
141
|
+
summary.inputTokens += assistantUsage.inputTokens;
|
|
142
|
+
summary.outputTokens += assistantUsage.outputTokens;
|
|
143
|
+
summary.cacheReadInputTokens += assistantUsage.cacheReadInputTokens;
|
|
144
|
+
summary.apiEquivalentCost = (0, api_equivalent_cost_1.mergeApiEquivalentCosts)([summary.apiEquivalentCost, assistantUsage.apiEquivalentCost]);
|
|
107
145
|
}
|
|
108
146
|
catch {
|
|
109
147
|
continue;
|
|
@@ -112,7 +150,7 @@ function summarizeProjectTranscript(content, start, end) {
|
|
|
112
150
|
return summary;
|
|
113
151
|
}
|
|
114
152
|
/**
|
|
115
|
-
* 从 Claude 本地 project transcript
|
|
153
|
+
* 从 Claude 本地 project transcript 中统计本周消息数、请求数、token 用量和标准 API 等效成本。
|
|
116
154
|
*/
|
|
117
155
|
async function summarizeClaudeProjectUsage(start, end) {
|
|
118
156
|
const claudeDataDir = (0, paths_1.getClaudeDataDir)();
|
|
@@ -124,6 +162,7 @@ async function summarizeClaudeProjectUsage(start, end) {
|
|
|
124
162
|
inputTokens: 0,
|
|
125
163
|
outputTokens: 0,
|
|
126
164
|
cacheReadInputTokens: 0,
|
|
165
|
+
apiEquivalentCost: (0, api_equivalent_cost_1.emptyApiEquivalentCost)(),
|
|
127
166
|
matchedFileCount: files.length,
|
|
128
167
|
claudeDataDir,
|
|
129
168
|
};
|
|
@@ -136,6 +175,7 @@ async function summarizeClaudeProjectUsage(start, end) {
|
|
|
136
175
|
totals.inputTokens += summary.inputTokens;
|
|
137
176
|
totals.outputTokens += summary.outputTokens;
|
|
138
177
|
totals.cacheReadInputTokens += summary.cacheReadInputTokens;
|
|
178
|
+
totals.apiEquivalentCost = (0, api_equivalent_cost_1.mergeApiEquivalentCosts)([totals.apiEquivalentCost, summary.apiEquivalentCost]);
|
|
139
179
|
}
|
|
140
180
|
catch {
|
|
141
181
|
continue;
|
|
@@ -187,7 +227,7 @@ async function findActiveSessionFiles(start, end) {
|
|
|
187
227
|
return result;
|
|
188
228
|
}
|
|
189
229
|
/**
|
|
190
|
-
* 按天汇总 Claude project transcript
|
|
230
|
+
* 按天汇总 Claude project transcript 中的消息数、请求数、token 用量和标准 API 等效成本。
|
|
191
231
|
*/
|
|
192
232
|
async function summarizeClaudeProjectUsageByDay(start, end) {
|
|
193
233
|
const claudeDataDir = (0, paths_1.getClaudeDataDir)();
|
|
@@ -221,15 +261,18 @@ async function summarizeClaudeProjectUsageByDay(start, end) {
|
|
|
221
261
|
inputTokens: 0,
|
|
222
262
|
outputTokens: 0,
|
|
223
263
|
cacheReadInputTokens: 0,
|
|
264
|
+
apiEquivalentCost: (0, api_equivalent_cost_1.emptyApiEquivalentCost)(),
|
|
224
265
|
};
|
|
225
266
|
if (isHumanUserMessage(record)) {
|
|
226
267
|
current.userMessageCount += 1;
|
|
227
268
|
}
|
|
228
269
|
if (record.type === "assistant" && isRecord(record.message) && isRecord(record.message.usage)) {
|
|
270
|
+
const assistantUsage = summarizeAssistantUsage(record.message, timestamp);
|
|
229
271
|
current.apiRequestCount += 1;
|
|
230
|
-
current.inputTokens +=
|
|
231
|
-
current.outputTokens +=
|
|
232
|
-
current.cacheReadInputTokens +=
|
|
272
|
+
current.inputTokens += assistantUsage.inputTokens;
|
|
273
|
+
current.outputTokens += assistantUsage.outputTokens;
|
|
274
|
+
current.cacheReadInputTokens += assistantUsage.cacheReadInputTokens;
|
|
275
|
+
current.apiEquivalentCost = (0, api_equivalent_cost_1.mergeApiEquivalentCosts)([current.apiEquivalentCost, assistantUsage.apiEquivalentCost]);
|
|
233
276
|
}
|
|
234
277
|
daily.set(date, current);
|
|
235
278
|
}
|