@covro/covro 0.6.1-dev.1 → 0.6.1-dev.3
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 +2 -2
- package/README.zh-CN.md +2 -2
- package/dist/codex/account-usage.js +132 -0
- package/dist/codex/account-usage.js.map +7 -0
- package/dist/codex/adapter.js +31 -2
- package/dist/codex/adapter.js.map +2 -2
- package/dist/server/events.js +20 -3
- package/dist/server/events.js.map +2 -2
- package/dist/server/http.js +8 -0
- package/dist/server/http.js.map +2 -2
- package/dist/server/service.js +32 -11
- package/dist/server/service.js.map +2 -2
- package/dist/server/thread-patch.js +58 -0
- package/dist/server/thread-patch.js.map +7 -0
- package/dist/server/websocket.js +14 -1
- package/dist/server/websocket.js.map +2 -2
- package/dist/shared/account-usage.js +1 -0
- package/dist/shared/account-usage.js.map +7 -0
- package/dist/shared/thread-patch.js +38 -0
- package/dist/shared/thread-patch.js.map +7 -0
- package/dist/shared/validation.js +1 -0
- package/dist/shared/validation.js.map +2 -2
- package/dist/web/assets/{abnfDiagram-WEYOIA3C-12kbP4fE.js → abnfDiagram-WEYOIA3C-BzVXOBcA.js} +1 -1
- package/dist/web/assets/{arc-3Cwtj2dL.js → arc-CyQWAnQd.js} +1 -1
- package/dist/web/assets/{architecture-WOLXFQ4H-DLpj2b3w.js → architecture-WOLXFQ4H-BEoyxwG0.js} +1 -1
- package/dist/web/assets/{architectureDiagram-ZHVYKT53-RlF4-Ioc.js → architectureDiagram-ZHVYKT53-CCXl4OZW.js} +1 -1
- package/dist/web/assets/{blockDiagram-RJAE7QA3-C4qOX-bt.js → blockDiagram-RJAE7QA3-D7dGEImG.js} +1 -1
- package/dist/web/assets/{c4Diagram-XDPPPE54-D7JMbo-C.js → c4Diagram-XDPPPE54-DV8znYp0.js} +1 -1
- package/dist/web/assets/channel-kBOj6wNa.js +1 -0
- package/dist/web/assets/{chunk-2E7WHVMD-IDKX-Tea.js → chunk-2E7WHVMD-0QrTjfW_.js} +1 -1
- package/dist/web/assets/{chunk-4EMNKR2T-Dc-yhxET.js → chunk-4EMNKR2T-D-zlzBAy.js} +1 -1
- package/dist/web/assets/{chunk-55XCU76K-CGd2UwoZ.js → chunk-55XCU76K-CVHEMROA.js} +1 -1
- package/dist/web/assets/{chunk-7S6XSTFO-BvKa88G4.js → chunk-7S6XSTFO-C2rIevGp.js} +1 -1
- package/dist/web/assets/{chunk-AQDTSKZB-C7nMX4W-.js → chunk-AQDTSKZB-DYAv-Riy.js} +1 -1
- package/dist/web/assets/{chunk-DSNLSHJZ-BzJy_vEu.js → chunk-DSNLSHJZ-DWI7CHhD.js} +1 -1
- package/dist/web/assets/{chunk-HAGFOTED-r9b5k0Ex.js → chunk-HAGFOTED-CO_q1459.js} +1 -1
- package/dist/web/assets/{chunk-HNE4Q36P-DQoXCaGC.js → chunk-HNE4Q36P-CgksCWEg.js} +1 -1
- package/dist/web/assets/{chunk-NQOKRVIF-1bL6YAHF.js → chunk-NQOKRVIF-BkpxlXF9.js} +1 -1
- package/dist/web/assets/{chunk-UHW7PFBP-psrTYP5z.js → chunk-UHW7PFBP-BMZQKGkg.js} +1 -1
- package/dist/web/assets/{chunk-VQ5W62QI-E2m7QCpn.js → chunk-VQ5W62QI-DxCsqxIr.js} +1 -1
- package/dist/web/assets/{chunk-WQQL4CDK-Y328jV78.js → chunk-WQQL4CDK-Drs4qCbY.js} +1 -1
- package/dist/web/assets/{chunk-XXDRQBXY-D4uat8z8.js → chunk-XXDRQBXY--mv0FkSH.js} +1 -1
- package/dist/web/assets/{chunk-YZO67HFG-C5FacS0u.js → chunk-YZO67HFG-BrXN1Efx.js} +1 -1
- package/dist/web/assets/{chunk-ZAUX2LTX-lmxyuzUz.js → chunk-ZAUX2LTX-DWiVb0QN.js} +1 -1
- package/dist/web/assets/{chunk-ZCHMQSOR-B-eLKLDi.js → chunk-ZCHMQSOR-p8m3-BJN.js} +1 -1
- package/dist/web/assets/{classDiagram-v2-4MYWR3UA-ClhXABmk.js → classDiagram-v2-4MYWR3UA-lnHHmraY.js} +1 -1
- package/dist/web/assets/{cose-bilkent-JH36ORCC-BwPkaA_U.js → cose-bilkent-JH36ORCC-B1BVV8Wv.js} +1 -1
- package/dist/web/assets/{cynefin-EF2NZ3EQ-Bsl3oI8o.js → cynefin-EF2NZ3EQ-C4TULYfr.js} +1 -1
- package/dist/web/assets/{cynefinDiagram-WF24UDRP-ap8wP3TK.js → cynefinDiagram-WF24UDRP-rExRJUWB.js} +1 -1
- package/dist/web/assets/{dagre-NK4GIZVX-D93ljWDv.js → dagre-NK4GIZVX-DI6KC0Pk.js} +1 -1
- package/dist/web/assets/{diagram-CBK3MWTC-CgXKZEzJ.js → diagram-CBK3MWTC-Don_Jr-E.js} +1 -1
- package/dist/web/assets/{diagram-I5XIIV2D-Ce32mo7i.js → diagram-I5XIIV2D-BW1FwPhX.js} +1 -1
- package/dist/web/assets/{diagram-ODIL2UCW-WM-FVzky.js → diagram-ODIL2UCW-DxqQXqCa.js} +1 -1
- package/dist/web/assets/{diagram-PFBEJUXE-4gCFo57A.js → diagram-PFBEJUXE-DeFKndZw.js} +1 -1
- package/dist/web/assets/{diagram-RJA3I4VV-BsUVCONT.js → diagram-RJA3I4VV-CM31q1uK.js} +1 -1
- package/dist/web/assets/{diagram-TYUNFSNR-CuIasd0o.js → diagram-TYUNFSNR-DTq2AOnu.js} +1 -1
- package/dist/web/assets/{dist-DE2aWlVX.js → dist-V4sbzI-h.js} +1 -1
- package/dist/web/assets/{ebnfDiagram-V4P3TTPT-BMFDt5P9.js → ebnfDiagram-V4P3TTPT-DF58HT_y.js} +1 -1
- package/dist/web/assets/{elk-QONTBCTQ-CbWBnkf9.js → elk-QONTBCTQ-BwrVYRCb.js} +1 -1
- package/dist/web/assets/{erDiagram-KYQIGQAA-BfujTOMs.js → erDiagram-KYQIGQAA-P1WxHJun.js} +1 -1
- package/dist/web/assets/{eventmodeling-K75KTNOO-D9yPZPJr.js → eventmodeling-K75KTNOO-BtccOmRK.js} +1 -1
- package/dist/web/assets/flowDiagram-IUGLLWBU-DnTlbOxw.js +1 -0
- package/dist/web/assets/{ganttDiagram-R7GPNTJY-BQailqpt.js → ganttDiagram-R7GPNTJY-D3qJC4vO.js} +1 -1
- package/dist/web/assets/{gitGraph-VSP46ZUC-Cn0-LfrH.js → gitGraph-VSP46ZUC-BVY9Gtih.js} +1 -1
- package/dist/web/assets/{gitGraphDiagram-PDYL7XHY-D_Bv68A5.js → gitGraphDiagram-PDYL7XHY-CZvvvj3Q.js} +1 -1
- package/dist/web/assets/{index-B3yair14.js → index-B9qAZAx0.js} +47 -47
- package/dist/web/assets/{index-qYBdGqKM.css → index-_yn3Nt0h.css} +1 -1
- package/dist/web/assets/{info-OHQRW6UA-C-rFhEgh.js → info-OHQRW6UA-BGqiJ9Yx.js} +1 -1
- package/dist/web/assets/{infoDiagram-MVDRKAX5-yWVzvl2L.js → infoDiagram-MVDRKAX5-DxdTuj3n.js} +1 -1
- package/dist/web/assets/{ishikawaDiagram-HPEHV2GE-DFYQOW9-.js → ishikawaDiagram-HPEHV2GE-DbhjLHsb.js} +1 -1
- package/dist/web/assets/{journeyDiagram-BOSHW7O7-B1zy7CA-.js → journeyDiagram-BOSHW7O7-DJROkZUW.js} +1 -1
- package/dist/web/assets/{kanban-definition-FNSA4HC5-CxyXZtX-.js → kanban-definition-FNSA4HC5-D4HijqrG.js} +1 -1
- package/dist/web/assets/{line-DU2ihvUj.js → line-d2EHEr40.js} +1 -1
- package/dist/web/assets/{linear-CFRZhmcT.js → linear-CnT_m8Aq.js} +1 -1
- package/dist/web/assets/{mermaid-parser.core-DKeYv3x5.js → mermaid-parser.core-BqD0_cdI.js} +3 -3
- package/dist/web/assets/{mermaid.core-D8iJrzMj.js → mermaid.core-Dd1sHHm2.js} +4 -4
- package/dist/web/assets/{mindmap-definition-6OY57UG3-CKbrIT8N.js → mindmap-definition-6OY57UG3-KPpq2dAV.js} +1 -1
- package/dist/web/assets/{packet-JDAUHWVQ-B9qYbkxZ.js → packet-JDAUHWVQ-CXnrw9bC.js} +1 -1
- package/dist/web/assets/{pegDiagram-ECIUJNBX-QnJNmnXC.js → pegDiagram-ECIUJNBX-BIXIhs7W.js} +1 -1
- package/dist/web/assets/{pie-XZMESJXO-BWBbsmjp.js → pie-XZMESJXO-TrDzTbhs.js} +1 -1
- package/dist/web/assets/{pieDiagram-GNMPY74T-Bubnnbvj.js → pieDiagram-GNMPY74T-D8a4Sfn1.js} +1 -1
- package/dist/web/assets/{quadrantDiagram-D57K4MC3-Cs_Ch2cN.js → quadrantDiagram-D57K4MC3-Bt2I_ygO.js} +1 -1
- package/dist/web/assets/{radar-ABXABTNO-DR6emy7T.js → radar-ABXABTNO-BZDG4zL1.js} +1 -1
- package/dist/web/assets/{railroad-I3PHUGI6-B0D7AskV.js → railroad-I3PHUGI6-CVZI3RsT.js} +1 -1
- package/dist/web/assets/{railroad-abnf-LNEFI6M7-Bz6aNqE_.js → railroad-abnf-LNEFI6M7-BLFBfBsa.js} +1 -1
- package/dist/web/assets/{railroad-ebnf-DWYD2UWJ-D0OpFEED.js → railroad-ebnf-DWYD2UWJ-CKhl-KNN.js} +1 -1
- package/dist/web/assets/{railroad-peg-JR7BVNR7-C_NZ01lj.js → railroad-peg-JR7BVNR7-CaxuMu1-.js} +1 -1
- package/dist/web/assets/{railroadDiagram-Y72NRBL7-Dj39CKJS.js → railroadDiagram-Y72NRBL7-BmN9o9yG.js} +1 -1
- package/dist/web/assets/{requirementDiagram-EQYSW5RA-B3LvvxeY.js → requirementDiagram-EQYSW5RA-CytiXIk0.js} +1 -1
- package/dist/web/assets/{sankeyDiagram-SY24JHO5-DZRJovJs.js → sankeyDiagram-SY24JHO5-2oasnbjI.js} +1 -1
- package/dist/web/assets/{sequenceDiagram-BLEHNHQU-Cjtr9DEf.js → sequenceDiagram-BLEHNHQU-CgKYeJhF.js} +1 -1
- package/dist/web/assets/{src-CiORhf3I.js → src-DeJ6DlL6.js} +1 -1
- package/dist/web/assets/{stateDiagram-v2-A6IESKWZ-CRWe83GV.js → stateDiagram-v2-A6IESKWZ-BcBo9Tt9.js} +1 -1
- package/dist/web/assets/{swimlanes-B3ENRKFQ-Dl64HZAr.js → swimlanes-B3ENRKFQ-DHvDY449.js} +1 -1
- package/dist/web/assets/swimlanesDiagram-AYQRV4AK-2cPOFNNL.js +8 -0
- package/dist/web/assets/{timeline-definition-JXYKGLGB-CNMLxrA1.js → timeline-definition-JXYKGLGB-DHOYx58-.js} +1 -1
- package/dist/web/assets/{treeView-D4JQ5SDB-DJKJS2TK.js → treeView-D4JQ5SDB-BKzsH1H3.js} +1 -1
- package/dist/web/assets/{treemap-SAJKECNS-Bys6-NSp.js → treemap-SAJKECNS-Dznq3JYy.js} +1 -1
- package/dist/web/assets/{usecaseDiagram-WPOLBNNX-tYc1Q8xT.js → usecaseDiagram-WPOLBNNX-B_Qb6GIb.js} +1 -1
- package/dist/web/assets/{vennDiagram-Q3Y3IDCW-yr790RR-.js → vennDiagram-Q3Y3IDCW-DDRYcnZj.js} +1 -1
- package/dist/web/assets/{wardley-7MLQ67FV-d-Le2twL.js → wardley-7MLQ67FV-CwCK5TZf.js} +1 -1
- package/dist/web/assets/{wardleyDiagram-IVAIDKWA-1Q-unpfn.js → wardleyDiagram-IVAIDKWA-DW68fX4l.js} +1 -1
- package/dist/web/assets/{xychartDiagram-4URNHDU4-zofaLTye.js → xychartDiagram-4URNHDU4-Cdk5RxaR.js} +1 -1
- package/dist/web/index.html +2 -2
- package/package.json +3 -3
- package/dist/web/assets/channel-AXdPKUi0.js +0 -1
- package/dist/web/assets/flowDiagram-IUGLLWBU-DosDBlJM.js +0 -1
- package/dist/web/assets/swimlanesDiagram-AYQRV4AK-Cmp6k7s_.js +0 -8
package/README.md
CHANGED
|
@@ -29,9 +29,9 @@
|
|
|
29
29
|
|
|
30
30
|
## ✨ What you can do
|
|
31
31
|
|
|
32
|
-
- 📱 **Follow tasks from any device.** Review changes, handle approvals,
|
|
32
|
+
- 📱 **Follow tasks from any device.** Review changes, handle approvals, answer questions, and check [account quotas](docs/account-usage.md) on desktop or mobile. Tasks keep running when you close the page.
|
|
33
33
|
- 🗂️ **Keep projects and conversations together.** Start without a project, track parallel tasks, and resume or fork your Codex CLI conversations.
|
|
34
|
-
- 📖 **Read results while you chat.** Preview documents, diagrams, and code changes beside the conversation on desktop, or full-screen on mobile.
|
|
34
|
+
- 📖 **Read results while you chat.** Preview documents, diagrams, and code changes beside the conversation on desktop, or full-screen on mobile. Loaded history stays complete as new responses stream in.
|
|
35
35
|
- 🔔 **Know when your attention is needed.** Enable browser notifications for completed work, questions, and approvals; keep the page open in a supported desktop browser.
|
|
36
36
|
|
|
37
37
|
Find controls, shortcuts, and supported commands in the [usage guide · 中文](docs/usage.zh-CN.md) and [command guide](docs/slash-commands.md).
|
package/README.zh-CN.md
CHANGED
|
@@ -29,9 +29,9 @@
|
|
|
29
29
|
|
|
30
30
|
## ✨ 你可以做什么
|
|
31
31
|
|
|
32
|
-
- 📱 **随时随地跟进任务。**
|
|
32
|
+
- 📱 **随时随地跟进任务。** 用电脑或手机查看改动、处理审批、回答问题和[账户额度](docs/account-usage.md)。关闭页面,任务仍会继续。
|
|
33
33
|
- 🗂️ **集中管理项目与会话。** 无需项目即可开始任务,在一个工作台查看并行进展,接续或 Fork Codex CLI 会话。
|
|
34
|
-
- 📖 **一边看产出,一边讨论。**
|
|
34
|
+
- 📖 **一边看产出,一边讨论。** 电脑上将文档、图表和代码变更与会话并排阅读,手机上使用全屏阅读器。新回复实时到达时,已加载的历史正文保持完整。
|
|
35
35
|
- 🔔 **及时收到待办提醒。** 开启浏览器通知,在工作结束、需要回答或审批时收到提醒;需在支持通知的桌面浏览器中保持页面运行。
|
|
36
36
|
|
|
37
37
|
操作、快捷键和命令用法见[使用指南](docs/usage.zh-CN.md)与[Slash 命令说明](docs/slash-commands.md)。
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { CodexError, isRecord } from "./transport.js";
|
|
4
|
+
const nullable = (value) => value.nullish().transform((v) => v ?? null);
|
|
5
|
+
const text = nullable(z.string());
|
|
6
|
+
const number = nullable(z.number().finite());
|
|
7
|
+
const boolean = nullable(z.boolean());
|
|
8
|
+
const timestamp = nullable(z.number().finite().min(0).max(864e10));
|
|
9
|
+
const window = nullable(
|
|
10
|
+
z.object({
|
|
11
|
+
usedPercent: number,
|
|
12
|
+
windowDurationMins: nullable(z.number().finite().nonnegative()),
|
|
13
|
+
resetsAt: timestamp
|
|
14
|
+
})
|
|
15
|
+
);
|
|
16
|
+
const group = z.object({
|
|
17
|
+
limitId: text,
|
|
18
|
+
limitName: text,
|
|
19
|
+
normalModelSlug: text,
|
|
20
|
+
planType: text,
|
|
21
|
+
primary: window,
|
|
22
|
+
secondary: window,
|
|
23
|
+
credits: nullable(z.object({ hasCredits: boolean, unlimited: boolean, balance: text })),
|
|
24
|
+
individualLimit: nullable(
|
|
25
|
+
z.object({
|
|
26
|
+
limit: text,
|
|
27
|
+
used: text,
|
|
28
|
+
remainingPercent: number,
|
|
29
|
+
resetsAt: timestamp
|
|
30
|
+
})
|
|
31
|
+
),
|
|
32
|
+
spendControlReached: boolean,
|
|
33
|
+
rateLimitReachedType: text
|
|
34
|
+
});
|
|
35
|
+
const response = z.object({
|
|
36
|
+
rateLimits: nullable(group),
|
|
37
|
+
rateLimitsByLimitId: nullable(z.record(z.string(), group)),
|
|
38
|
+
ordinaryUsageAllowed: boolean,
|
|
39
|
+
rateLimitResetCredits: nullable(
|
|
40
|
+
z.object({ availableCount: nullable(z.number().int().nonnegative()) })
|
|
41
|
+
)
|
|
42
|
+
});
|
|
43
|
+
function accountUsageValues(input) {
|
|
44
|
+
const value = response.parse(input);
|
|
45
|
+
const groups = Object.entries(value.rateLimitsByLimitId ?? {}).map(
|
|
46
|
+
([id, entry]) => ({ ...entry, limitId: entry.limitId ?? id })
|
|
47
|
+
);
|
|
48
|
+
if (value.rateLimits && (!groups.length || value.rateLimits.limitId !== null && !groups.some((entry) => entry.limitId === value.rateLimits?.limitId))) {
|
|
49
|
+
groups.unshift(value.rateLimits);
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
groups,
|
|
53
|
+
ordinaryUsageAllowed: value.ordinaryUsageAllowed,
|
|
54
|
+
resetCreditsAvailable: value.rateLimitResetCredits?.availableCount ?? null
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
class AccountUsageReader {
|
|
58
|
+
constructor(source) {
|
|
59
|
+
this.source = source;
|
|
60
|
+
}
|
|
61
|
+
source;
|
|
62
|
+
sequence = 0;
|
|
63
|
+
identity;
|
|
64
|
+
value = this.empty("offline");
|
|
65
|
+
snapshot() {
|
|
66
|
+
return structuredClone(this.value);
|
|
67
|
+
}
|
|
68
|
+
empty(status) {
|
|
69
|
+
return {
|
|
70
|
+
scope: randomUUID(),
|
|
71
|
+
status,
|
|
72
|
+
refreshing: false,
|
|
73
|
+
updatedAt: null,
|
|
74
|
+
groups: [],
|
|
75
|
+
ordinaryUsageAllowed: null,
|
|
76
|
+
resetCreditsAvailable: null
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
invalidate(status) {
|
|
80
|
+
this.sequence++;
|
|
81
|
+
this.identity = void 0;
|
|
82
|
+
this.value = this.empty(status);
|
|
83
|
+
this.source.changed();
|
|
84
|
+
}
|
|
85
|
+
async refresh() {
|
|
86
|
+
const sequence = ++this.sequence;
|
|
87
|
+
this.value = { ...this.value, refreshing: true };
|
|
88
|
+
this.source.changed();
|
|
89
|
+
try {
|
|
90
|
+
const result = await this.source.account();
|
|
91
|
+
if (sequence !== this.sequence) return this.snapshot();
|
|
92
|
+
if (!isRecord(result) || !Object.hasOwn(result, "account") || typeof result.requiresOpenaiAuth !== "boolean")
|
|
93
|
+
throw new Error("Invalid account response");
|
|
94
|
+
const identity = JSON.stringify(result.account);
|
|
95
|
+
if (this.identity !== void 0 && identity !== this.identity) {
|
|
96
|
+
this.value = this.empty("loading");
|
|
97
|
+
this.source.changed();
|
|
98
|
+
}
|
|
99
|
+
this.identity = identity;
|
|
100
|
+
this.source.authenticated(result.account !== null || !result.requiresOpenaiAuth);
|
|
101
|
+
if (!result.account) {
|
|
102
|
+
this.value = {
|
|
103
|
+
...this.empty(result.requiresOpenaiAuth ? "signedOut" : "unsupported"),
|
|
104
|
+
scope: this.value.scope
|
|
105
|
+
};
|
|
106
|
+
} else if (result.account.type !== "chatgpt") {
|
|
107
|
+
this.value = { ...this.empty("unsupported"), scope: this.value.scope };
|
|
108
|
+
} else {
|
|
109
|
+
const values = accountUsageValues(await this.source.limits());
|
|
110
|
+
if (sequence !== this.sequence) return this.snapshot();
|
|
111
|
+
this.value = {
|
|
112
|
+
...this.value,
|
|
113
|
+
...values,
|
|
114
|
+
status: "ready",
|
|
115
|
+
refreshing: false,
|
|
116
|
+
updatedAt: Date.now()
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
} catch (error) {
|
|
120
|
+
if (sequence !== this.sequence) return this.snapshot();
|
|
121
|
+
const unsupported = error instanceof CodexError && (error.rpcCode === -32601 || error.code === "PROTOCOL_INCOMPATIBLE");
|
|
122
|
+
this.value = unsupported ? { ...this.empty("unsupported"), scope: this.value.scope } : { ...this.value, status: "error", refreshing: false };
|
|
123
|
+
}
|
|
124
|
+
if (sequence === this.sequence) this.source.changed();
|
|
125
|
+
return this.snapshot();
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
export {
|
|
129
|
+
AccountUsageReader,
|
|
130
|
+
accountUsageValues
|
|
131
|
+
};
|
|
132
|
+
//# sourceMappingURL=account-usage.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/codex/account-usage.ts"],
|
|
4
|
+
"sourcesContent": ["import { randomUUID } from 'node:crypto';\nimport { z } from 'zod';\nimport type { GetAccountResponse } from './generated/v2/GetAccountResponse.js';\nimport type { AccountUsage, UsageGroup } from '../shared/account-usage.js';\nimport { CodexError, isRecord } from './transport.js';\n\nconst nullable = <T extends z.ZodType>(value: T) => value.nullish().transform((v) => v ?? null);\nconst text = nullable(z.string());\nconst number = nullable(z.number().finite());\nconst boolean = nullable(z.boolean());\nconst timestamp = nullable(z.number().finite().min(0).max(8.64e12));\nconst window = nullable(\n z.object({\n usedPercent: number,\n windowDurationMins: nullable(z.number().finite().nonnegative()),\n resetsAt: timestamp,\n }),\n);\nconst group = z.object({\n limitId: text,\n limitName: text,\n normalModelSlug: text,\n planType: text,\n primary: window,\n secondary: window,\n credits: nullable(z.object({ hasCredits: boolean, unlimited: boolean, balance: text })),\n individualLimit: nullable(\n z.object({\n limit: text,\n used: text,\n remainingPercent: number,\n resetsAt: timestamp,\n }),\n ),\n spendControlReached: boolean,\n rateLimitReachedType: text,\n});\nconst response = z.object({\n rateLimits: nullable(group),\n rateLimitsByLimitId: nullable(z.record(z.string(), group)),\n ordinaryUsageAllowed: boolean,\n rateLimitResetCredits: nullable(\n z.object({ availableCount: nullable(z.number().int().nonnegative()) }),\n ),\n});\n\nexport function accountUsageValues(input: unknown) {\n const value = response.parse(input);\n const groups: UsageGroup[] = Object.entries(value.rateLimitsByLimitId ?? {}).map(\n ([id, entry]) => ({ ...entry, limitId: entry.limitId ?? id }),\n );\n // The legacy bucket mirrors a map entry. Keep it only when it adds a distinct bucket.\n if (\n value.rateLimits &&\n (!groups.length ||\n (value.rateLimits.limitId !== null &&\n !groups.some((entry) => entry.limitId === value.rateLimits?.limitId)))\n ) {\n groups.unshift(value.rateLimits);\n }\n return {\n groups,\n ordinaryUsageAllowed: value.ordinaryUsageAllowed,\n resetCreditsAvailable: value.rateLimitResetCredits?.availableCount ?? null,\n };\n}\n\n/** Owns freshness and identity boundaries. Sparse notifications trigger a full read. */\nexport class AccountUsageReader {\n private sequence = 0;\n private identity?: string;\n private value: AccountUsage = this.empty('offline');\n constructor(\n private readonly source: {\n account: () => Promise<GetAccountResponse>;\n limits: () => Promise<unknown>;\n changed: () => void;\n authenticated: (value: boolean) => void;\n },\n ) {}\n\n snapshot(): AccountUsage {\n return structuredClone(this.value);\n }\n\n private empty(status: AccountUsage['status']): AccountUsage {\n return {\n scope: randomUUID(),\n status,\n refreshing: false,\n updatedAt: null,\n groups: [],\n ordinaryUsageAllowed: null,\n resetCreditsAvailable: null,\n };\n }\n\n invalidate(status: 'offline' | 'loading'): void {\n this.sequence++;\n this.identity = undefined;\n this.value = this.empty(status);\n this.source.changed();\n }\n\n async refresh(): Promise<AccountUsage> {\n const sequence = ++this.sequence;\n this.value = { ...this.value, refreshing: true };\n this.source.changed();\n try {\n const result = await this.source.account();\n if (sequence !== this.sequence) return this.snapshot();\n if (\n !isRecord(result) ||\n !Object.hasOwn(result, 'account') ||\n typeof result.requiresOpenaiAuth !== 'boolean'\n )\n throw new Error('Invalid account response');\n const identity = JSON.stringify(result.account);\n if (this.identity !== undefined && identity !== this.identity) {\n this.value = this.empty('loading');\n this.source.changed();\n }\n this.identity = identity;\n this.source.authenticated(result.account !== null || !result.requiresOpenaiAuth);\n if (!result.account) {\n this.value = {\n ...this.empty(result.requiresOpenaiAuth ? 'signedOut' : 'unsupported'),\n scope: this.value.scope,\n };\n } else if (result.account.type !== 'chatgpt') {\n this.value = { ...this.empty('unsupported'), scope: this.value.scope };\n } else {\n const values = accountUsageValues(await this.source.limits());\n if (sequence !== this.sequence) return this.snapshot();\n this.value = {\n ...this.value,\n ...values,\n status: 'ready',\n refreshing: false,\n updatedAt: Date.now(),\n };\n }\n } catch (error) {\n if (sequence !== this.sequence) return this.snapshot();\n const unsupported =\n error instanceof CodexError &&\n (error.rpcCode === -32601 || error.code === 'PROTOCOL_INCOMPATIBLE');\n this.value = unsupported\n ? { ...this.empty('unsupported'), scope: this.value.scope }\n : { ...this.value, status: 'error', refreshing: false };\n }\n if (sequence === this.sequence) this.source.changed();\n return this.snapshot();\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/codex/adapter.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { CODEX_COMPATIBILITY } from "./compatibility.js";
|
|
2
|
+
import { AccountUsageReader } from "./account-usage.js";
|
|
2
3
|
import { SHELL_TIMEOUT_MS, SHELL_OUTPUT_BYTES } from "../shared/shell.js";
|
|
3
4
|
import { spawn, execFile } from "node:child_process";
|
|
4
5
|
import { randomUUID } from "node:crypto";
|
|
@@ -71,7 +72,8 @@ const CAPABILITIES = [
|
|
|
71
72
|
"config/batchWrite",
|
|
72
73
|
"configRequirements/read",
|
|
73
74
|
"experimentalFeature/list",
|
|
74
|
-
"account/read"
|
|
75
|
+
"account/read",
|
|
76
|
+
"account/rateLimits/read"
|
|
75
77
|
];
|
|
76
78
|
function permissionPathLabel(path) {
|
|
77
79
|
if (path.type === "path") return path.path;
|
|
@@ -98,6 +100,21 @@ class CodexAdapter {
|
|
|
98
100
|
this.options = options;
|
|
99
101
|
}
|
|
100
102
|
options;
|
|
103
|
+
accountUsage = new AccountUsageReader({
|
|
104
|
+
account: () => this.call("account/read", { refreshToken: false }),
|
|
105
|
+
limits: () => this.call("account/rateLimits/read", { excludeResetCreditDetails: true }),
|
|
106
|
+
changed: () => this.publishRuntime(),
|
|
107
|
+
authenticated: (value) => {
|
|
108
|
+
this.state.authenticated = value;
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
async refreshAccountUsage() {
|
|
112
|
+
if (!this.ready) {
|
|
113
|
+
this.accountUsage.invalidate("offline");
|
|
114
|
+
return this.accountUsage.snapshot();
|
|
115
|
+
}
|
|
116
|
+
return this.accountUsage.refresh();
|
|
117
|
+
}
|
|
101
118
|
commandOutputs = /* @__PURE__ */ new Map();
|
|
102
119
|
epoch = randomUUID();
|
|
103
120
|
child;
|
|
@@ -137,7 +154,7 @@ class CodexAdapter {
|
|
|
137
154
|
return this.state.ready;
|
|
138
155
|
}
|
|
139
156
|
diagnostics() {
|
|
140
|
-
return structuredClone(this.state);
|
|
157
|
+
return { ...structuredClone(this.state), accountUsage: this.accountUsage.snapshot() };
|
|
141
158
|
}
|
|
142
159
|
onEvent(listener) {
|
|
143
160
|
this.listeners.add(listener);
|
|
@@ -172,6 +189,7 @@ class CodexAdapter {
|
|
|
172
189
|
error: void 0,
|
|
173
190
|
capabilities: []
|
|
174
191
|
};
|
|
192
|
+
this.accountUsage.invalidate("loading");
|
|
175
193
|
this.publishRuntime();
|
|
176
194
|
try {
|
|
177
195
|
const env = {
|
|
@@ -235,6 +253,7 @@ class CodexAdapter {
|
|
|
235
253
|
this.tokenUsage.clear();
|
|
236
254
|
this.denials.clear();
|
|
237
255
|
this.state.connection = "unavailable";
|
|
256
|
+
this.accountUsage.invalidate("offline");
|
|
238
257
|
this.state.error = error.message;
|
|
239
258
|
this.expireActions();
|
|
240
259
|
this.publishRuntime();
|
|
@@ -319,6 +338,7 @@ class CodexAdapter {
|
|
|
319
338
|
this.state.connection = "ready";
|
|
320
339
|
this.state.capabilities = CAPABILITIES.filter((method) => !this.disabled.has(method));
|
|
321
340
|
this.publishRuntime();
|
|
341
|
+
void this.refreshAccountUsage();
|
|
322
342
|
} catch (error) {
|
|
323
343
|
const failure = asCodexError(error);
|
|
324
344
|
this.state.ready = false;
|
|
@@ -332,6 +352,7 @@ class CodexAdapter {
|
|
|
332
352
|
}
|
|
333
353
|
async stop() {
|
|
334
354
|
this.stopped = true;
|
|
355
|
+
this.accountUsage.invalidate("offline");
|
|
335
356
|
clearTimeout(this.restartTimer);
|
|
336
357
|
this.restartTimer = void 0;
|
|
337
358
|
await this.starting?.catch(() => {
|
|
@@ -959,6 +980,14 @@ class CodexAdapter {
|
|
|
959
980
|
const event = message;
|
|
960
981
|
const p = event.params;
|
|
961
982
|
switch (event.method) {
|
|
983
|
+
case "account/updated":
|
|
984
|
+
this.state.authenticated = null;
|
|
985
|
+
this.accountUsage.invalidate("loading");
|
|
986
|
+
if (this.ready) void this.refreshAccountUsage();
|
|
987
|
+
break;
|
|
988
|
+
case "account/rateLimits/updated":
|
|
989
|
+
if (this.ready) void this.refreshAccountUsage();
|
|
990
|
+
break;
|
|
962
991
|
case "command/exec/outputDelta": {
|
|
963
992
|
const { processId, stream, deltaBase64, capReached } = event.params;
|
|
964
993
|
this.commandOutputs.get(processId)?.(
|