offsite 0.0.81 → 0.0.83
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/apps/client/dist/assets/{XIcon-41gae75-.js → XIcon-DmLCL5gE.js} +1 -1
- package/apps/client/dist/assets/{diff-panel-C5Y2kAT1.js → diff-panel-Di2OEL7f.js} +1 -1
- package/apps/client/dist/assets/{editor-dialog-Ca40iXLG.js → editor-dialog-0HOoUwVn.js} +35 -35
- package/apps/client/dist/assets/{image-viewer-juD9pPaf.js → image-viewer-CqDZsnzA.js} +1 -1
- package/apps/client/dist/assets/index-C2ngx4R-.css +2 -0
- package/apps/client/dist/assets/index-ypm7DKvh.js +72 -0
- package/apps/client/dist/assets/{preview-dialog-BQ7xp6ft.js → preview-dialog-D9Xmcp07.js} +1 -1
- package/apps/client/dist/assets/{use-editor-shortcut-BAl1jKWS.js → use-editor-shortcut-De1Hmg-b.js} +26 -26
- package/apps/client/dist/assets/{video-viewer-B6wuIPsW.js → video-viewer-DcIn1jcr.js} +1 -1
- package/apps/client/dist/index.html +5 -5
- package/apps/client/dist/sw.js +1 -1
- package/apps/server/dist/main.mjs +299 -184
- package/apps/server/dist/main.mjs.map +1 -1
- package/package.json +1 -1
- package/apps/client/dist/assets/index-Bi58_RHj.js +0 -72
- package/apps/client/dist/assets/index-Kw4OdzUC.css +0 -2
|
@@ -88,6 +88,208 @@ function publish$2(sessionId, event) {
|
|
|
88
88
|
function broadcast(event) {
|
|
89
89
|
for (const client of clients) client.send(event);
|
|
90
90
|
}
|
|
91
|
+
// src/services/usage.ts
|
|
92
|
+
const freshFor = 6e4;
|
|
93
|
+
const forcedFreshFor = 1e4;
|
|
94
|
+
const entries = /* @__PURE__ */ new Map();
|
|
95
|
+
const fetching = /* @__PURE__ */ new Map();
|
|
96
|
+
function cachedUsage(accountId) {
|
|
97
|
+
return entries.get(accountId) ?? {
|
|
98
|
+
limits: [],
|
|
99
|
+
fetchedAt: null,
|
|
100
|
+
updatedAt: null,
|
|
101
|
+
error: null
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function recordLimits(accountId, limits) {
|
|
105
|
+
const current = cachedUsage(accountId);
|
|
106
|
+
entries.set(accountId, {
|
|
107
|
+
...current,
|
|
108
|
+
limits: [...current.limits.map((limit) => limits.find((item) => item.window === limit.window) ?? limit), ...limits.filter((item) => !current.limits.some((limit) => limit.window === item.window))],
|
|
109
|
+
updatedAt: Date.now()
|
|
110
|
+
});
|
|
111
|
+
broadcast({
|
|
112
|
+
type: "limits",
|
|
113
|
+
accountId,
|
|
114
|
+
limits
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
async function readUsage(accountId, force) {
|
|
118
|
+
const current = cachedUsage(accountId);
|
|
119
|
+
if (current.fetchedAt !== null && Date.now() - current.fetchedAt < (force ? forcedFreshFor : freshFor)) return current;
|
|
120
|
+
const pending = fetching.get(accountId);
|
|
121
|
+
if (pending !== void 0) return pending;
|
|
122
|
+
const next = fetchUsage(accountId);
|
|
123
|
+
fetching.set(accountId, next);
|
|
124
|
+
try {
|
|
125
|
+
return await next;
|
|
126
|
+
} finally {
|
|
127
|
+
fetching.delete(accountId);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
function forgetUsage(accountId) {
|
|
131
|
+
entries.delete(accountId);
|
|
132
|
+
}
|
|
133
|
+
async function fetchUsage(accountId) {
|
|
134
|
+
const account = storedAccounts().find((item) => item.id === accountId);
|
|
135
|
+
if (account === void 0) throw new Error("That account was removed");
|
|
136
|
+
let usage;
|
|
137
|
+
try {
|
|
138
|
+
usage = {
|
|
139
|
+
limits: await providerLimits(account),
|
|
140
|
+
fetchedAt: Date.now(),
|
|
141
|
+
updatedAt: Date.now(),
|
|
142
|
+
error: null
|
|
143
|
+
};
|
|
144
|
+
} catch (error) {
|
|
145
|
+
console.warn(`could not read usage limits for ${account.name}: ${error}`);
|
|
146
|
+
usage = {
|
|
147
|
+
...cachedUsage(accountId),
|
|
148
|
+
fetchedAt: Date.now(),
|
|
149
|
+
error: error instanceof Error ? error.message : String(error)
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
entries.set(accountId, usage);
|
|
153
|
+
broadcast({
|
|
154
|
+
type: "usage",
|
|
155
|
+
accountId,
|
|
156
|
+
usage
|
|
157
|
+
});
|
|
158
|
+
return usage;
|
|
159
|
+
}
|
|
160
|
+
function providerLimits(account) {
|
|
161
|
+
switch (account.provider) {
|
|
162
|
+
case "claude": return claudeLimits(account);
|
|
163
|
+
case "codex": return codexLimits(account);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
// src/lib/claude/content.ts
|
|
167
|
+
const imageTypes = [
|
|
168
|
+
"image/png",
|
|
169
|
+
"image/jpeg",
|
|
170
|
+
"image/gif",
|
|
171
|
+
"image/webp"
|
|
172
|
+
];
|
|
173
|
+
function toMessage(type, item, time) {
|
|
174
|
+
return {
|
|
175
|
+
type,
|
|
176
|
+
uuid: item.uuid,
|
|
177
|
+
time,
|
|
178
|
+
content: isRecord(item.message) ? toBlocks(item.message.content, answersOf(item.tool_use_result)) : [],
|
|
179
|
+
parent: item.parent_tool_use_id
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
function toUserInput(prompt, uuid, priority) {
|
|
183
|
+
for (const image of prompt.images) if (!imageTypes.includes(image.mediaType)) throw new Error(`${image.mediaType} images are not supported`);
|
|
184
|
+
return {
|
|
185
|
+
type: "user",
|
|
186
|
+
message: {
|
|
187
|
+
role: "user",
|
|
188
|
+
content: [...prompt.text === "" ? [] : [{
|
|
189
|
+
type: "text",
|
|
190
|
+
text: prompt.text
|
|
191
|
+
}], ...prompt.images.map((image) => ({
|
|
192
|
+
type: "image",
|
|
193
|
+
source: {
|
|
194
|
+
type: "base64",
|
|
195
|
+
media_type: image.mediaType,
|
|
196
|
+
data: image.data
|
|
197
|
+
}
|
|
198
|
+
}))]
|
|
199
|
+
},
|
|
200
|
+
parent_tool_use_id: null,
|
|
201
|
+
uuid,
|
|
202
|
+
...priority === void 0 ? {} : { priority }
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
function promptMessage(prompt, uuid) {
|
|
206
|
+
return {
|
|
207
|
+
type: "user",
|
|
208
|
+
uuid,
|
|
209
|
+
time: Date.now(),
|
|
210
|
+
content: [...prompt.text === "" ? [] : [{
|
|
211
|
+
type: "text",
|
|
212
|
+
text: prompt.text
|
|
213
|
+
}], ...prompt.images.map((image) => ({
|
|
214
|
+
type: "image",
|
|
215
|
+
...image
|
|
216
|
+
}))],
|
|
217
|
+
parent: null
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
function notice(text) {
|
|
221
|
+
return {
|
|
222
|
+
type: "notice",
|
|
223
|
+
uuid: randomUUID(),
|
|
224
|
+
time: Date.now(),
|
|
225
|
+
text,
|
|
226
|
+
isError: true
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
function contextTokens(message) {
|
|
230
|
+
if (!isRecord(message) || !isRecord(message.usage)) return null;
|
|
231
|
+
const usage = message.usage;
|
|
232
|
+
return [
|
|
233
|
+
usage.input_tokens,
|
|
234
|
+
usage.cache_creation_input_tokens,
|
|
235
|
+
usage.cache_read_input_tokens,
|
|
236
|
+
usage.output_tokens
|
|
237
|
+
].reduce((total, value) => total + (typeof value === "number" ? value : 0), 0);
|
|
238
|
+
}
|
|
239
|
+
function answersOf(output) {
|
|
240
|
+
if (!isRecord(output) || !isRecord(output.answers)) return null;
|
|
241
|
+
const answers = {};
|
|
242
|
+
for (const [question, answer] of Object.entries(output.answers)) {
|
|
243
|
+
if (typeof answer !== "string") return null;
|
|
244
|
+
answers[question] = answer;
|
|
245
|
+
}
|
|
246
|
+
return answers;
|
|
247
|
+
}
|
|
248
|
+
function toBlocks(content, answers) {
|
|
249
|
+
if (typeof content === "string") return [{
|
|
250
|
+
type: "text",
|
|
251
|
+
text: content
|
|
252
|
+
}];
|
|
253
|
+
if (!Array.isArray(content)) return [];
|
|
254
|
+
return content.flatMap((block) => {
|
|
255
|
+
if (!isRecord(block)) return [];
|
|
256
|
+
switch (block.type) {
|
|
257
|
+
case "text": return typeof block.text === "string" && !block.text.startsWith("<system-reminder>") && !block.text.startsWith("<local-command-caveat>") ? [{
|
|
258
|
+
type: "text",
|
|
259
|
+
text: block.text
|
|
260
|
+
}] : [];
|
|
261
|
+
case "thinking": return typeof block.thinking === "string" && block.thinking !== "" ? [{
|
|
262
|
+
type: "thinking",
|
|
263
|
+
thinking: block.thinking
|
|
264
|
+
}] : [];
|
|
265
|
+
case "image": {
|
|
266
|
+
const source = block.source;
|
|
267
|
+
return isRecord(source) && source.type === "base64" && typeof source.media_type === "string" && typeof source.data === "string" ? [{
|
|
268
|
+
type: "image",
|
|
269
|
+
mediaType: source.media_type,
|
|
270
|
+
data: source.data
|
|
271
|
+
}] : [];
|
|
272
|
+
}
|
|
273
|
+
case "tool_use": return typeof block.id === "string" && typeof block.name === "string" && isRecord(block.input) ? [{
|
|
274
|
+
type: "tool_use",
|
|
275
|
+
id: block.id,
|
|
276
|
+
name: block.name,
|
|
277
|
+
input: block.input
|
|
278
|
+
}] : [];
|
|
279
|
+
case "tool_result": return typeof block.tool_use_id === "string" ? [{
|
|
280
|
+
type: "tool_result",
|
|
281
|
+
toolUseId: block.tool_use_id,
|
|
282
|
+
content: toBlocks(block.content, null).filter((item) => item.type === "text"),
|
|
283
|
+
isError: block.is_error === true,
|
|
284
|
+
answers
|
|
285
|
+
}] : [];
|
|
286
|
+
default: return [];
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
function isRecord(value) {
|
|
291
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
292
|
+
}
|
|
91
293
|
// src/args.ts
|
|
92
294
|
let command = "web";
|
|
93
295
|
let name = null;
|
|
@@ -478,13 +680,13 @@ async function codexAccount(account) {
|
|
|
478
680
|
const base = {
|
|
479
681
|
...account,
|
|
480
682
|
email: null,
|
|
683
|
+
displayName: null,
|
|
684
|
+
organization: null,
|
|
481
685
|
plan: null,
|
|
482
|
-
limits: [],
|
|
483
686
|
linked
|
|
484
687
|
};
|
|
485
688
|
try {
|
|
486
|
-
const
|
|
487
|
-
const result = await server.request("account/read", {});
|
|
689
|
+
const result = await appServer(configDir).request("account/read", {});
|
|
488
690
|
if (result.account === null) return {
|
|
489
691
|
...base,
|
|
490
692
|
error: `Not logged in. Run CODEX_HOME=${configDir} codex login in a terminal`,
|
|
@@ -494,9 +696,10 @@ async function codexAccount(account) {
|
|
|
494
696
|
case "chatgpt": return {
|
|
495
697
|
...base,
|
|
496
698
|
email: result.account.email,
|
|
699
|
+
displayName: codexDisplayName(configDir),
|
|
700
|
+
organization: result.account.workspaceName,
|
|
497
701
|
plan: result.account.planType,
|
|
498
702
|
error: null,
|
|
499
|
-
limits: await rateLimits(server),
|
|
500
703
|
valid: linked
|
|
501
704
|
};
|
|
502
705
|
case "apiKey": return {
|
|
@@ -552,19 +755,10 @@ async function skills(server, cwd) {
|
|
|
552
755
|
return (await server.request("skills/list", { cwds: [cwd] })).data.flatMap((entry) => entry.skills.filter((skill) => skill.enabled));
|
|
553
756
|
}
|
|
554
757
|
function publishCodexLimits(home, snapshot) {
|
|
555
|
-
for (const account of storedAccounts()) if (account.provider === "codex" && (account.configDir ?? codexBaseDir) === home)
|
|
556
|
-
type: "limits",
|
|
557
|
-
accountId: account.id,
|
|
558
|
-
limits: toLimits(snapshot)
|
|
559
|
-
});
|
|
758
|
+
for (const account of storedAccounts()) if (account.provider === "codex" && (account.configDir ?? codexBaseDir) === home) recordLimits(account.id, toLimits(snapshot));
|
|
560
759
|
}
|
|
561
|
-
async function
|
|
562
|
-
|
|
563
|
-
return toLimits((await server.request("account/rateLimits/read", {})).rateLimits);
|
|
564
|
-
} catch (error) {
|
|
565
|
-
console.warn(`could not read Codex usage limits: ${error}`);
|
|
566
|
-
return [];
|
|
567
|
-
}
|
|
760
|
+
async function codexLimits(account) {
|
|
761
|
+
return toLimits((await appServer(account.configDir ?? codexBaseDir).request("account/rateLimits/read", {})).rateLimits);
|
|
568
762
|
}
|
|
569
763
|
function toLimits(snapshot) {
|
|
570
764
|
return [snapshot.primary, snapshot.secondary].flatMap((window) => window === null ? [] : [{
|
|
@@ -574,6 +768,22 @@ function toLimits(snapshot) {
|
|
|
574
768
|
rejected: window.usedPercent >= 100
|
|
575
769
|
}]);
|
|
576
770
|
}
|
|
771
|
+
function codexDisplayName(home) {
|
|
772
|
+
let raw;
|
|
773
|
+
try {
|
|
774
|
+
raw = JSON.parse(readFileSync(path.join(home, "auth.json"), "utf8"));
|
|
775
|
+
} catch (error) {
|
|
776
|
+
if (error.code !== "ENOENT") console.warn(`could not read the Codex account name: ${error}`);
|
|
777
|
+
return null;
|
|
778
|
+
}
|
|
779
|
+
if (!isRecord(raw) || !isRecord(raw.tokens) || typeof raw.tokens.id_token !== "string") return null;
|
|
780
|
+
const payload = raw.tokens.id_token.split(".").at(1);
|
|
781
|
+
if (payload === void 0) return null;
|
|
782
|
+
const claims = JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
|
|
783
|
+
if (!isRecord(claims) || typeof claims.name !== "string") return null;
|
|
784
|
+
const name = claims.name.trim();
|
|
785
|
+
return name === "" ? null : name;
|
|
786
|
+
}
|
|
577
787
|
function isMirror(dir) {
|
|
578
788
|
try {
|
|
579
789
|
if (realpathSync(dir) === realpathSync(codexBaseDir)) return true;
|
|
@@ -583,133 +793,6 @@ function isMirror(dir) {
|
|
|
583
793
|
throw error;
|
|
584
794
|
}
|
|
585
795
|
}
|
|
586
|
-
// src/lib/claude/content.ts
|
|
587
|
-
const imageTypes = [
|
|
588
|
-
"image/png",
|
|
589
|
-
"image/jpeg",
|
|
590
|
-
"image/gif",
|
|
591
|
-
"image/webp"
|
|
592
|
-
];
|
|
593
|
-
function toMessage(type, item, time) {
|
|
594
|
-
return {
|
|
595
|
-
type,
|
|
596
|
-
uuid: item.uuid,
|
|
597
|
-
time,
|
|
598
|
-
content: isRecord(item.message) ? toBlocks(item.message.content, answersOf(item.tool_use_result)) : [],
|
|
599
|
-
parent: item.parent_tool_use_id
|
|
600
|
-
};
|
|
601
|
-
}
|
|
602
|
-
function toUserInput(prompt, uuid, priority) {
|
|
603
|
-
for (const image of prompt.images) if (!imageTypes.includes(image.mediaType)) throw new Error(`${image.mediaType} images are not supported`);
|
|
604
|
-
return {
|
|
605
|
-
type: "user",
|
|
606
|
-
message: {
|
|
607
|
-
role: "user",
|
|
608
|
-
content: [...prompt.text === "" ? [] : [{
|
|
609
|
-
type: "text",
|
|
610
|
-
text: prompt.text
|
|
611
|
-
}], ...prompt.images.map((image) => ({
|
|
612
|
-
type: "image",
|
|
613
|
-
source: {
|
|
614
|
-
type: "base64",
|
|
615
|
-
media_type: image.mediaType,
|
|
616
|
-
data: image.data
|
|
617
|
-
}
|
|
618
|
-
}))]
|
|
619
|
-
},
|
|
620
|
-
parent_tool_use_id: null,
|
|
621
|
-
uuid,
|
|
622
|
-
...priority === void 0 ? {} : { priority }
|
|
623
|
-
};
|
|
624
|
-
}
|
|
625
|
-
function promptMessage(prompt, uuid) {
|
|
626
|
-
return {
|
|
627
|
-
type: "user",
|
|
628
|
-
uuid,
|
|
629
|
-
time: Date.now(),
|
|
630
|
-
content: [...prompt.text === "" ? [] : [{
|
|
631
|
-
type: "text",
|
|
632
|
-
text: prompt.text
|
|
633
|
-
}], ...prompt.images.map((image) => ({
|
|
634
|
-
type: "image",
|
|
635
|
-
...image
|
|
636
|
-
}))],
|
|
637
|
-
parent: null
|
|
638
|
-
};
|
|
639
|
-
}
|
|
640
|
-
function notice(text) {
|
|
641
|
-
return {
|
|
642
|
-
type: "notice",
|
|
643
|
-
uuid: randomUUID(),
|
|
644
|
-
time: Date.now(),
|
|
645
|
-
text,
|
|
646
|
-
isError: true
|
|
647
|
-
};
|
|
648
|
-
}
|
|
649
|
-
function contextTokens(message) {
|
|
650
|
-
if (!isRecord(message) || !isRecord(message.usage)) return null;
|
|
651
|
-
const usage = message.usage;
|
|
652
|
-
return [
|
|
653
|
-
usage.input_tokens,
|
|
654
|
-
usage.cache_creation_input_tokens,
|
|
655
|
-
usage.cache_read_input_tokens,
|
|
656
|
-
usage.output_tokens
|
|
657
|
-
].reduce((total, value) => total + (typeof value === "number" ? value : 0), 0);
|
|
658
|
-
}
|
|
659
|
-
function answersOf(output) {
|
|
660
|
-
if (!isRecord(output) || !isRecord(output.answers)) return null;
|
|
661
|
-
const answers = {};
|
|
662
|
-
for (const [question, answer] of Object.entries(output.answers)) {
|
|
663
|
-
if (typeof answer !== "string") return null;
|
|
664
|
-
answers[question] = answer;
|
|
665
|
-
}
|
|
666
|
-
return answers;
|
|
667
|
-
}
|
|
668
|
-
function toBlocks(content, answers) {
|
|
669
|
-
if (typeof content === "string") return [{
|
|
670
|
-
type: "text",
|
|
671
|
-
text: content
|
|
672
|
-
}];
|
|
673
|
-
if (!Array.isArray(content)) return [];
|
|
674
|
-
return content.flatMap((block) => {
|
|
675
|
-
if (!isRecord(block)) return [];
|
|
676
|
-
switch (block.type) {
|
|
677
|
-
case "text": return typeof block.text === "string" && !block.text.startsWith("<system-reminder>") && !block.text.startsWith("<local-command-caveat>") ? [{
|
|
678
|
-
type: "text",
|
|
679
|
-
text: block.text
|
|
680
|
-
}] : [];
|
|
681
|
-
case "thinking": return typeof block.thinking === "string" && block.thinking !== "" ? [{
|
|
682
|
-
type: "thinking",
|
|
683
|
-
thinking: block.thinking
|
|
684
|
-
}] : [];
|
|
685
|
-
case "image": {
|
|
686
|
-
const source = block.source;
|
|
687
|
-
return isRecord(source) && source.type === "base64" && typeof source.media_type === "string" && typeof source.data === "string" ? [{
|
|
688
|
-
type: "image",
|
|
689
|
-
mediaType: source.media_type,
|
|
690
|
-
data: source.data
|
|
691
|
-
}] : [];
|
|
692
|
-
}
|
|
693
|
-
case "tool_use": return typeof block.id === "string" && typeof block.name === "string" && isRecord(block.input) ? [{
|
|
694
|
-
type: "tool_use",
|
|
695
|
-
id: block.id,
|
|
696
|
-
name: block.name,
|
|
697
|
-
input: block.input
|
|
698
|
-
}] : [];
|
|
699
|
-
case "tool_result": return typeof block.tool_use_id === "string" ? [{
|
|
700
|
-
type: "tool_result",
|
|
701
|
-
toolUseId: block.tool_use_id,
|
|
702
|
-
content: toBlocks(block.content, null).filter((item) => item.type === "text"),
|
|
703
|
-
isError: block.is_error === true,
|
|
704
|
-
answers
|
|
705
|
-
}] : [];
|
|
706
|
-
default: return [];
|
|
707
|
-
}
|
|
708
|
-
});
|
|
709
|
-
}
|
|
710
|
-
function isRecord(value) {
|
|
711
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
712
|
-
}
|
|
713
796
|
// src/lib/images.ts
|
|
714
797
|
const extensions = {
|
|
715
798
|
"image/png": "png",
|
|
@@ -4404,9 +4487,10 @@ function disabledAccount(account) {
|
|
|
4404
4487
|
return {
|
|
4405
4488
|
...account,
|
|
4406
4489
|
email: null,
|
|
4490
|
+
displayName: null,
|
|
4491
|
+
organization: null,
|
|
4407
4492
|
plan: null,
|
|
4408
4493
|
error: null,
|
|
4409
|
-
limits: [],
|
|
4410
4494
|
linked: true,
|
|
4411
4495
|
valid: false
|
|
4412
4496
|
};
|
|
@@ -4490,6 +4574,7 @@ async function updateAccount(update) {
|
|
|
4490
4574
|
} : item)
|
|
4491
4575
|
});
|
|
4492
4576
|
forgetClaude(update.id);
|
|
4577
|
+
forgetUsage(update.id);
|
|
4493
4578
|
if (before.enabled && !update.enabled) await stopAccount(before);
|
|
4494
4579
|
}
|
|
4495
4580
|
function removeAccount(id) {
|
|
@@ -4500,6 +4585,7 @@ function removeAccount(id) {
|
|
|
4500
4585
|
codexAccounts: config.codexAccounts.filter((item) => item.id !== id)
|
|
4501
4586
|
});
|
|
4502
4587
|
forgetClaude(id);
|
|
4588
|
+
forgetUsage(id);
|
|
4503
4589
|
}
|
|
4504
4590
|
function validAccount(name, configDir) {
|
|
4505
4591
|
if (name.trim() === "") throw new Error("Give the account a name");
|
|
@@ -4649,7 +4735,6 @@ const modes = [
|
|
|
4649
4735
|
"auto"
|
|
4650
4736
|
];
|
|
4651
4737
|
const probes = /* @__PURE__ */ new Map();
|
|
4652
|
-
const limits = /* @__PURE__ */ new Map();
|
|
4653
4738
|
let executable$1 = "";
|
|
4654
4739
|
function findClaude() {
|
|
4655
4740
|
const name = process.platform === "win32" ? "claude.exe" : "claude";
|
|
@@ -4765,15 +4850,17 @@ async function claudeCapabilities(account, cwd) {
|
|
|
4765
4850
|
};
|
|
4766
4851
|
}
|
|
4767
4852
|
async function claudeAccount(account) {
|
|
4768
|
-
const
|
|
4853
|
+
const configDir = account.configDir ?? claudeBaseDir();
|
|
4854
|
+
const linked = isLinked(configDir);
|
|
4769
4855
|
try {
|
|
4770
4856
|
const info = (await initialization(account.id, os.homedir())).account;
|
|
4771
4857
|
return {
|
|
4772
4858
|
...account,
|
|
4773
4859
|
email: info.email ?? null,
|
|
4860
|
+
displayName: claudeDisplayName(configDir),
|
|
4861
|
+
organization: info.organization ?? null,
|
|
4774
4862
|
plan: info.subscriptionType ?? null,
|
|
4775
4863
|
error: null,
|
|
4776
|
-
limits: accountLimits(account.id),
|
|
4777
4864
|
linked,
|
|
4778
4865
|
valid: linked
|
|
4779
4866
|
};
|
|
@@ -4781,9 +4868,10 @@ async function claudeAccount(account) {
|
|
|
4781
4868
|
return {
|
|
4782
4869
|
...account,
|
|
4783
4870
|
email: null,
|
|
4871
|
+
displayName: null,
|
|
4872
|
+
organization: null,
|
|
4784
4873
|
plan: null,
|
|
4785
4874
|
error: error instanceof Error ? error.message : String(error),
|
|
4786
|
-
limits: accountLimits(account.id),
|
|
4787
4875
|
linked,
|
|
4788
4876
|
valid: linked
|
|
4789
4877
|
};
|
|
@@ -4791,52 +4879,87 @@ async function claudeAccount(account) {
|
|
|
4791
4879
|
}
|
|
4792
4880
|
function forgetClaude(accountId) {
|
|
4793
4881
|
for (const key of probes.keys()) if (key.startsWith(`${accountId}\n`)) probes.delete(key);
|
|
4794
|
-
limits.delete(accountId);
|
|
4795
4882
|
}
|
|
4796
|
-
function
|
|
4797
|
-
const
|
|
4883
|
+
function eventLimits(info, current) {
|
|
4884
|
+
const changed = /* @__PURE__ */ new Map();
|
|
4798
4885
|
const windows = info.unifiedWindows;
|
|
4799
4886
|
if (isRecord(windows)) {
|
|
4800
|
-
for (const [name, value] of Object.entries(windows)) if (isRecord(value))
|
|
4887
|
+
for (const [name, value] of Object.entries(windows)) if (isRecord(value)) changed.set(name, {
|
|
4801
4888
|
window: name,
|
|
4802
4889
|
utilization: typeof value.utilization === "number" ? value.utilization : null,
|
|
4803
4890
|
resetsAt: typeof value.resetsAt === "number" ? value.resetsAt : null,
|
|
4804
|
-
rejected: current.
|
|
4891
|
+
rejected: current.find((limit) => limit.window === name)?.rejected ?? false
|
|
4805
4892
|
});
|
|
4806
4893
|
}
|
|
4807
4894
|
if (info.rateLimitType !== void 0) {
|
|
4808
|
-
const existing =
|
|
4809
|
-
|
|
4895
|
+
const existing = changed.get(info.rateLimitType) ?? current.find((limit) => limit.window === info.rateLimitType);
|
|
4896
|
+
changed.set(info.rateLimitType, {
|
|
4810
4897
|
window: info.rateLimitType,
|
|
4811
4898
|
utilization: info.utilization ?? existing?.utilization ?? null,
|
|
4812
4899
|
resetsAt: info.resetsAt ?? existing?.resetsAt ?? null,
|
|
4813
4900
|
rejected: info.status === "rejected"
|
|
4814
4901
|
});
|
|
4815
4902
|
}
|
|
4816
|
-
|
|
4817
|
-
return accountLimits(accountId);
|
|
4903
|
+
return [...changed.values()];
|
|
4818
4904
|
}
|
|
4819
|
-
async function
|
|
4905
|
+
async function claudeLimits(account) {
|
|
4906
|
+
const closed = Promise.withResolvers();
|
|
4907
|
+
const probe = query({
|
|
4908
|
+
prompt: idle(closed.promise),
|
|
4909
|
+
options: claudeOptions(account.id, os.homedir())
|
|
4910
|
+
});
|
|
4820
4911
|
try {
|
|
4912
|
+
await probe.initializationResult();
|
|
4821
4913
|
const usage = await probe.usage_EXPERIMENTAL_MAY_CHANGE_DO_NOT_RELY_ON_THIS_API_YET({ skipBehaviors: true });
|
|
4822
|
-
if (usage.rate_limits === null) return;
|
|
4823
|
-
|
|
4824
|
-
|
|
4825
|
-
|
|
4826
|
-
|
|
4827
|
-
|
|
4828
|
-
|
|
4829
|
-
|
|
4830
|
-
|
|
4831
|
-
|
|
4832
|
-
|
|
4833
|
-
|
|
4834
|
-
|
|
4914
|
+
if (usage.rate_limits === null) return [];
|
|
4915
|
+
return [
|
|
4916
|
+
{
|
|
4917
|
+
name: "five_hour",
|
|
4918
|
+
window: usage.rate_limits.five_hour
|
|
4919
|
+
},
|
|
4920
|
+
{
|
|
4921
|
+
name: "seven_day",
|
|
4922
|
+
window: usage.rate_limits.seven_day
|
|
4923
|
+
},
|
|
4924
|
+
{
|
|
4925
|
+
name: "seven_day_opus",
|
|
4926
|
+
window: usage.rate_limits.seven_day_opus
|
|
4927
|
+
},
|
|
4928
|
+
{
|
|
4929
|
+
name: "seven_day_sonnet",
|
|
4930
|
+
window: usage.rate_limits.seven_day_sonnet
|
|
4931
|
+
},
|
|
4932
|
+
...(usage.rate_limits.model_scoped ?? []).map((row) => ({
|
|
4933
|
+
name: row.display_name,
|
|
4934
|
+
window: row
|
|
4935
|
+
}))
|
|
4936
|
+
].flatMap((entry) => {
|
|
4937
|
+
const window = entry.window;
|
|
4938
|
+
if (window === void 0 || window === null) return [];
|
|
4939
|
+
return [{
|
|
4940
|
+
window: entry.name,
|
|
4941
|
+
utilization: window.utilization === null ? null : window.utilization / 100,
|
|
4942
|
+
resetsAt: window.resets_at === null ? null : Date.parse(window.resets_at) / 1e3,
|
|
4943
|
+
rejected: window.utilization !== null && window.utilization >= 100
|
|
4944
|
+
}];
|
|
4835
4945
|
});
|
|
4836
|
-
|
|
4946
|
+
} finally {
|
|
4947
|
+
closed.resolve();
|
|
4948
|
+
probe.close();
|
|
4949
|
+
}
|
|
4950
|
+
}
|
|
4951
|
+
function claudeDisplayName(configDir) {
|
|
4952
|
+
const file = path.resolve(configDir) === path.join(os.homedir(), ".claude") ? path.join(os.homedir(), ".claude.json") : path.join(configDir, ".claude.json");
|
|
4953
|
+
let raw;
|
|
4954
|
+
try {
|
|
4955
|
+
raw = JSON.parse(readFileSync(file, "utf8"));
|
|
4837
4956
|
} catch (error) {
|
|
4838
|
-
console.warn(`could not read Claude
|
|
4957
|
+
if (error.code !== "ENOENT") console.warn(`could not read the Claude account name: ${error}`);
|
|
4958
|
+
return null;
|
|
4839
4959
|
}
|
|
4960
|
+
if (!isRecord(raw) || !isRecord(raw.oauthAccount) || typeof raw.oauthAccount.displayName !== "string") return null;
|
|
4961
|
+
const name = raw.oauthAccount.displayName.trim();
|
|
4962
|
+
return name === "" ? null : name;
|
|
4840
4963
|
}
|
|
4841
4964
|
function isLinked(configDir) {
|
|
4842
4965
|
const base = claudeBaseDir();
|
|
@@ -4848,9 +4971,6 @@ function isLinked(configDir) {
|
|
|
4848
4971
|
throw error;
|
|
4849
4972
|
}
|
|
4850
4973
|
}
|
|
4851
|
-
function accountLimits(accountId) {
|
|
4852
|
-
return [...limits.get(accountId)?.values() ?? []];
|
|
4853
|
-
}
|
|
4854
4974
|
function initialization(accountId, cwd) {
|
|
4855
4975
|
const key = `${accountId}\n${cwd}`;
|
|
4856
4976
|
const existing = probes.get(key);
|
|
@@ -4867,9 +4987,7 @@ async function runProbe(accountId, cwd) {
|
|
|
4867
4987
|
options: claudeOptions(accountId, cwd)
|
|
4868
4988
|
});
|
|
4869
4989
|
try {
|
|
4870
|
-
|
|
4871
|
-
await recordUsage(accountId, probe);
|
|
4872
|
-
return result;
|
|
4990
|
+
return await probe.initializationResult();
|
|
4873
4991
|
} finally {
|
|
4874
4992
|
closed.resolve();
|
|
4875
4993
|
probe.close();
|
|
@@ -5664,11 +5782,7 @@ var Run = class {
|
|
|
5664
5782
|
case "rate_limit_event": {
|
|
5665
5783
|
const accountId = this.settings.accountId;
|
|
5666
5784
|
if (accountId === null) throw new Error("Rate limit event for a run without an account");
|
|
5667
|
-
|
|
5668
|
-
type: "limits",
|
|
5669
|
-
accountId,
|
|
5670
|
-
limits: recordLimit(accountId, message.rate_limit_info)
|
|
5671
|
-
});
|
|
5785
|
+
recordLimits(accountId, eventLimits(message.rate_limit_info, cachedUsage(accountId).limits));
|
|
5672
5786
|
return;
|
|
5673
5787
|
}
|
|
5674
5788
|
case "result": {
|
|
@@ -7926,6 +8040,7 @@ const handlers = {
|
|
|
7926
8040
|
publishAccounts();
|
|
7927
8041
|
return null;
|
|
7928
8042
|
},
|
|
8043
|
+
"accounts.usage": (params) => readUsage(params.id, params.force),
|
|
7929
8044
|
capabilities: (params) => capabilities(params.provider, params.accountId, params.projectId === null || params.projectId === "no-project" ? os.homedir() : projectPath(params.projectId)),
|
|
7930
8045
|
"files.list": (params) => params.projectId === "no-project" ? [] : listFiles(projectPath(params.projectId)),
|
|
7931
8046
|
"files.entries": (params) => listEntries(projectPath(params.projectId)),
|