ccus-cli 0.2.8 → 0.2.9
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 +1 -1
- package/dist/lib/codex-sessions.js +31 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -311,7 +311,7 @@ ccus install --codex --uninstall # 移除 ccus 的 Stop hook
|
|
|
311
311
|
- **定时同步**:Stop hook 还兜底触发 `ccus sync`(与 Claude statusline 对称)——配过 `ccus sync config --target` 后,Codex 每 turn 结束都会检查 3h 周期,到期自动 export + 复制 bundle(含 Codex token/消息)到目标目录。只用 Codex、不开 Claude Code 时也能自动同步。
|
|
312
312
|
- **缓存节流**:Stop 每 turn 触发,额度按 5 分钟 TTL 缓存(`codex-quota-cache.json`),命中秒回不 spawn;过期才拉一次(带 ~10s 超时),失败回退旧缓存。
|
|
313
313
|
- **字段映射**:app-server 返回 `primary`(5h)/ `secondary`(weekly)两窗口,取各自的 `usedPercent`(驼峰,clamp 0–100);ccus 填进 `rate_limits.five_hour` / `seven_day` 的 `used_percentage`,`computeStatuslineEvent` 读时自动算出 usage。
|
|
314
|
-
- **token / 消息 / 额度都进 export / aggregate**:Codex 的 token、用户消息数、API 请求数从 `<CODEX_HOME>/sessions` 的 rollout
|
|
314
|
+
- **token / 消息 / 额度都进 export / aggregate**:Codex 的 token、用户消息数、API 请求数从 `<CODEX_HOME>/sessions` 的 rollout 统计,并排除 `source.subagent.other="guardian"` 的 Codex Desktop 内部安全审查会话,进 `ccus export` 的 `weeklySummary.codex` / `dailySummaries[].codex` 段;Stop 落盘的额度快照(`source="codex"` 事件)也进 export/aggregate——export bundle 里 Codex 额度单列到 codex 段、与 Claude 分开看,aggregate daily/weekly CSV 则把 Codex **叠加进 Claude 主字段**合计(累加量相加、额度 peak 取两源 max、latest 两源相加、7d 累计含两源读数),不再单列 `codex*` 列;detail.csv 的 `source` 列区分来源。
|
|
315
315
|
- **Windows**:`install --codex` 在 Windows 写 `ccus.cmd __codex-hook`(npm 全局装会生成 `ccus.cmd`);Windows 上 Stop hook 偶发收到非法 JSON(已知 bug #23784),ccus 容错按无 payload 处理、仍照常拉额度 + 落盘。
|
|
316
316
|
|
|
317
317
|
> 该路径依赖 Codex 内部 app-server 协议(`account/rateLimits/read` 的返回结构)与 hooks payload schema,随版本变;解析层宽松,字段缺失返回 null、失败静默。
|
|
@@ -19,6 +19,29 @@ function getNumber(value) {
|
|
|
19
19
|
function getString(value) {
|
|
20
20
|
return typeof value === "string" && value.length > 0 ? value : null;
|
|
21
21
|
}
|
|
22
|
+
/** Guardian 是 Codex Desktop 的动作安全审查子代理,不代表用户请求或业务模型调用。 */
|
|
23
|
+
function isGuardianRollout(content) {
|
|
24
|
+
let offset = 0;
|
|
25
|
+
while (offset < content.length) {
|
|
26
|
+
const newline = content.indexOf("\n", offset);
|
|
27
|
+
const line = content.slice(offset, newline === -1 ? content.length : newline).trim();
|
|
28
|
+
offset = newline === -1 ? content.length : newline + 1;
|
|
29
|
+
try {
|
|
30
|
+
const record = JSON.parse(line);
|
|
31
|
+
if (!isRecord(record) || record.type !== "session_meta" || !isRecord(record.payload)) {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
const source = record.payload.source;
|
|
35
|
+
return isRecord(source)
|
|
36
|
+
&& isRecord(source.subagent)
|
|
37
|
+
&& source.subagent.other === "guardian";
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
22
45
|
async function collectRolloutFiles(directoryPath) {
|
|
23
46
|
try {
|
|
24
47
|
const entries = await promises_1.default.readdir(directoryPath, { withFileTypes: true });
|
|
@@ -150,6 +173,7 @@ function summarizeRollout(content, start, end) {
|
|
|
150
173
|
}
|
|
151
174
|
/**
|
|
152
175
|
* 从 Codex 本地 session rollout(<CODEX_HOME>/sessions 下递归的 .jsonl)统计消息数、请求数和 token 用量。
|
|
176
|
+
* Codex Desktop 的 guardian 安全审查 rollout 整体排除,避免把内部审批轮次计为用户使用量。
|
|
153
177
|
*
|
|
154
178
|
* 消息数 = task_started 的 distinct turn_id(跨文件去重)。重放副本会让同一 turn_id 出现在多个文件,
|
|
155
179
|
* 故用全局 Map<turn_id, minMs> 收集(取最早 timestamp = 真实发生时刻,早于任何重放副本),最后取 size。
|
|
@@ -166,6 +190,9 @@ async function summarizeCodexSessionUsage(start, end) {
|
|
|
166
190
|
for (const filePath of files) {
|
|
167
191
|
try {
|
|
168
192
|
const content = await promises_1.default.readFile(filePath, "utf8");
|
|
193
|
+
if (isGuardianRollout(content)) {
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
169
196
|
const parsed = summarizeRollout(content, start, end);
|
|
170
197
|
for (const turn of parsed.turns) {
|
|
171
198
|
const prev = turnMinMs.get(turn.turnId);
|
|
@@ -194,6 +221,7 @@ async function summarizeCodexSessionUsage(start, end) {
|
|
|
194
221
|
}
|
|
195
222
|
/**
|
|
196
223
|
* 按天汇总 Codex session rollout 中的消息数、请求数和 token 用量。
|
|
224
|
+
* 与周汇总一致,排除 Codex Desktop 的 guardian 安全审查 rollout。
|
|
197
225
|
*
|
|
198
226
|
* 消息数同 weekly:先全局 Map<turn_id, minMs> 去重,再按 minMs 的本地日归桶(保证 weekly = Σ daily、
|
|
199
227
|
* 且重放副本跨天不重复)。token 维度按 token_count 事件 timestamp 的本地日累加。
|
|
@@ -227,6 +255,9 @@ async function summarizeCodexSessionUsageByDay(start, end) {
|
|
|
227
255
|
catch {
|
|
228
256
|
continue;
|
|
229
257
|
}
|
|
258
|
+
if (isGuardianRollout(content)) {
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
230
261
|
const lines = content.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
|
|
231
262
|
for (const line of lines) {
|
|
232
263
|
try {
|