@cocorograph/hub-agent 0.7.60 → 0.7.62
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/package.json +1 -1
- package/src/usage.mjs +78 -11
package/package.json
CHANGED
package/src/usage.mjs
CHANGED
|
@@ -1284,14 +1284,67 @@ function codexSessionsDir() {
|
|
|
1284
1284
|
// (Claude の readOfficial の bucketize と同じ約束事)。
|
|
1285
1285
|
const CODEX_DEFAULT_LIMIT = 100
|
|
1286
1286
|
|
|
1287
|
-
|
|
1288
|
-
|
|
1287
|
+
// threadId → rollout 絶対パスのメモ (2026-07-15)。rollout ファイルは threadId ごとに
|
|
1288
|
+
// 不変(作成日ディレクトリに置かれ、以降はそのファイルへ追記され続ける)ため、一度解決
|
|
1289
|
+
// できたら永続的にキャッシュしてよい。フォールバック全走査 (下記) のコストを usage.request
|
|
1290
|
+
// ポーリング (既定 60s) のたびに払わないための保険。存在確認 (stat) で削除検知して捨てる。
|
|
1291
|
+
const _codexRolloutPathMemo = new Map() // threadId → fp
|
|
1292
|
+
|
|
1293
|
+
export function _resetCodexRolloutPathMemo() {
|
|
1294
|
+
_codexRolloutPathMemo.clear()
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
/** base 配下の全 Y/M/D ディレクトリを新しい順に走査して threadId の rollout を探す。
|
|
1298
|
+
* 直近 lookbackDays の高速パスから漏れた「窓外の古い(=9 日以上前に作成された)長寿命
|
|
1299
|
+
* スレッド」を拾うためのフォールバック。resume で復帰した古いスレッドが該当する。
|
|
1300
|
+
* @returns {Promise<string|null>}
|
|
1301
|
+
*/
|
|
1302
|
+
async function scanAllDatesForCodexRollout(base, threadId) {
|
|
1303
|
+
const suffix = `-${threadId}.jsonl`
|
|
1304
|
+
const years = await fs.readdir(base).catch(() => [])
|
|
1305
|
+
// 新しい年→月→日から辿ると、resume される(=比較的最近使われた)スレッドに早く当たる。
|
|
1306
|
+
for (const y of years.filter((s) => /^\d{4}$/.test(s)).sort().reverse()) {
|
|
1307
|
+
const yDir = path.join(base, y)
|
|
1308
|
+
const months = await fs.readdir(yDir).catch(() => [])
|
|
1309
|
+
for (const m of months.sort().reverse()) {
|
|
1310
|
+
const mDir = path.join(yDir, m)
|
|
1311
|
+
const days = await fs.readdir(mDir).catch(() => [])
|
|
1312
|
+
for (const d of days.sort().reverse()) {
|
|
1313
|
+
const dDir = path.join(mDir, d)
|
|
1314
|
+
const files = await fs.readdir(dDir).catch(() => [])
|
|
1315
|
+
const match = files.find((f) => f.endsWith(suffix))
|
|
1316
|
+
if (match) return path.join(dDir, match)
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
return null
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
/** threadId から rollout jsonl の絶対パスを検索する(日付シャード配下)。
|
|
1324
|
+
* 高速パス = 直近 `lookbackDays` 日の Y/M/D を走査(月またぎでも 1〜2 readdir で済む)。
|
|
1325
|
+
* ⚠️ rollout ファイルは「スレッド作成日」のディレクトリに置かれ、以降そのファイルへ
|
|
1326
|
+
* 追記され続ける。そのため 9 日以上前に作成されたスレッドを resume で復帰させると、
|
|
1327
|
+
* 作成日ディレクトリが高速パスの窓外にあり見つからず、context ドーナツ・5h/7d が
|
|
1328
|
+
* 表示できなくなる(2026-07-15 の resume 修正で古いスレッド復帰が正しく動くようになり
|
|
1329
|
+
* 露出)。高速パスで見つからなければ全日付フォールバック走査に落とし、結果を threadId
|
|
1330
|
+
* でメモ化する。
|
|
1289
1331
|
* `session-mirror.mjs`(Stream C ターミナルミラー)からも再利用するため export する。
|
|
1290
1332
|
* @returns {Promise<string|null>}
|
|
1291
1333
|
*/
|
|
1292
1334
|
export async function findCodexRolloutFile(threadId, { lookbackDays = 9, now = Date.now() } = {}) {
|
|
1293
1335
|
if (!threadId) return null
|
|
1336
|
+
// メモ命中: ファイルが今も存在するなら即返す(消えていれば捨てて再探索)。
|
|
1337
|
+
const memoed = _codexRolloutPathMemo.get(threadId)
|
|
1338
|
+
if (memoed) {
|
|
1339
|
+
try {
|
|
1340
|
+
await fs.stat(memoed)
|
|
1341
|
+
return memoed
|
|
1342
|
+
} catch {
|
|
1343
|
+
_codexRolloutPathMemo.delete(threadId)
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1294
1346
|
const base = codexSessionsDir()
|
|
1347
|
+
// 高速パス: 直近 lookbackDays の日付シャードのみ。
|
|
1295
1348
|
for (let i = 0; i < lookbackDays; i++) {
|
|
1296
1349
|
const d = new Date(now - i * 24 * 60 * 60 * 1000)
|
|
1297
1350
|
const y = String(d.getFullYear())
|
|
@@ -1301,9 +1354,16 @@ export async function findCodexRolloutFile(threadId, { lookbackDays = 9, now = D
|
|
|
1301
1354
|
const files = await fs.readdir(dir).catch(() => null)
|
|
1302
1355
|
if (!files) continue
|
|
1303
1356
|
const match = files.find((f) => f.endsWith(`-${threadId}.jsonl`))
|
|
1304
|
-
if (match)
|
|
1357
|
+
if (match) {
|
|
1358
|
+
const fp = path.join(dir, match)
|
|
1359
|
+
_codexRolloutPathMemo.set(threadId, fp)
|
|
1360
|
+
return fp
|
|
1361
|
+
}
|
|
1305
1362
|
}
|
|
1306
|
-
|
|
1363
|
+
// フォールバック: 窓外の古い(長寿命 resume)スレッドを全日付走査で拾う。
|
|
1364
|
+
const scanned = await scanAllDatesForCodexRollout(base, threadId)
|
|
1365
|
+
if (scanned) _codexRolloutPathMemo.set(threadId, scanned)
|
|
1366
|
+
return scanned
|
|
1307
1367
|
}
|
|
1308
1368
|
|
|
1309
1369
|
/** P5(perf): rollout ファイルの token_count 抽出結果を mtime+size でメモ化。 */
|
|
@@ -1385,15 +1445,22 @@ export async function codexUsageForThread(threadId) {
|
|
|
1385
1445
|
const rateLimits = found.payload.rate_limits
|
|
1386
1446
|
|
|
1387
1447
|
let contextPercent = null
|
|
1388
|
-
const totalTok = info?.total_token_usage
|
|
1389
1448
|
const windowSize = info?.model_context_window
|
|
1390
|
-
|
|
1449
|
+
// context 窓の「現在の占有率」は last_token_usage(直近ターンで実際に窓へ載った
|
|
1450
|
+
// トークン)で測る。total_token_usage は会話累積(キャッシュ再利用分も加算し
|
|
1451
|
+
// 単調増加)なので、ターンを重ねると窓サイズを超過し Math.min(100,…) で 100% に
|
|
1452
|
+
// クランプされてドーナツが固着する(2026-07-15 バグ修正: 実測で累積 1,341,719 /
|
|
1453
|
+
// 窓 258,400 = 519% → 100% 張り付き。実占有は last=66,973 → 25.9%)。Codex は
|
|
1454
|
+
// 自動コンパクションで実文脈を使い回すため、累積で割ると必ず張り付く。
|
|
1455
|
+
// last_token_usage が無い旧 Codex 版のみ従来の total_token_usage にフォールバック。
|
|
1456
|
+
const usageForContext = info?.last_token_usage ?? info?.total_token_usage
|
|
1457
|
+
if (usageForContext && typeof windowSize === "number" && windowSize > 0) {
|
|
1391
1458
|
const tokens =
|
|
1392
|
-
typeof
|
|
1393
|
-
?
|
|
1394
|
-
: (
|
|
1395
|
-
(
|
|
1396
|
-
(
|
|
1459
|
+
typeof usageForContext.total_tokens === "number"
|
|
1460
|
+
? usageForContext.total_tokens
|
|
1461
|
+
: (usageForContext.input_tokens || 0) +
|
|
1462
|
+
(usageForContext.cached_input_tokens || 0) +
|
|
1463
|
+
(usageForContext.output_tokens || 0)
|
|
1397
1464
|
contextPercent = Math.min(100, Math.round((tokens / windowSize) * 1000) / 10)
|
|
1398
1465
|
}
|
|
1399
1466
|
|