devrage 0.5.4 → 0.5.5

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/dist/cli.js CHANGED
@@ -569,11 +569,19 @@ function codexAdapter() {
569
569
  }
570
570
  },
571
571
  async *usage(options) {
572
+ const seenUsage = /* @__PURE__ */ new Set();
572
573
  for await (const file of discoverCodexSessionFiles(CODEX_SESSIONS_DIR)) {
573
- yield* parseCodexUsageJsonl(file.filePath, {
574
+ for await (const record of parseCodexUsageJsonl(file.filePath, {
574
575
  session: file.session,
575
576
  since: options?.since
576
- });
577
+ })) {
578
+ const key = codexUsageRecordKey(record);
579
+ if (seenUsage.has(key)) {
580
+ continue;
581
+ }
582
+ seenUsage.add(key);
583
+ yield record;
584
+ }
577
585
  }
578
586
  }
579
587
  };
@@ -591,10 +599,15 @@ async function* discoverCodexSessionFiles(dir) {
591
599
  if (entryStat.isDirectory()) {
592
600
  yield* discoverCodexSessionFiles(fullPath);
593
601
  } else if (entry.endsWith(".jsonl")) {
594
- yield { filePath: fullPath, session: entry.replace(".jsonl", "") };
602
+ yield { filePath: fullPath, session: sessionFromRolloutFileName(entry) };
595
603
  }
596
604
  }
597
605
  }
606
+ function sessionFromRolloutFileName(fileName) {
607
+ return fileName.match(
608
+ /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.jsonl$/i
609
+ )?.[1] ?? fileName.replace(".jsonl", "");
610
+ }
598
611
  async function* parseCodexJsonl(filePath, context) {
599
612
  const rl = createInterface2({
600
613
  input: createReadStream2(filePath, { encoding: "utf-8" }),
@@ -655,6 +668,8 @@ async function* parseCodexUsageJsonl(filePath, context) {
655
668
  let model;
656
669
  let previousTotal = null;
657
670
  let previousUsageSignature = null;
671
+ let session = context.session;
672
+ let sawSessionMeta = false;
658
673
  for await (const line of rl) {
659
674
  if (!line.trim()) {
660
675
  continue;
@@ -662,6 +677,14 @@ async function* parseCodexUsageJsonl(filePath, context) {
662
677
  try {
663
678
  const entry = JSON.parse(line);
664
679
  const payload = asRecord3(entry["payload"]);
680
+ if (entry["type"] === "session_meta") {
681
+ const metaSession = stringValue2(payload?.["id"]) ?? stringValue2(entry["id"]);
682
+ if (metaSession && !sawSessionMeta) {
683
+ session = metaSession;
684
+ sawSessionMeta = true;
685
+ }
686
+ continue;
687
+ }
665
688
  if (entry["type"] === "turn_context") {
666
689
  model = stringValue2(payload?.["model"]) ?? model;
667
690
  continue;
@@ -710,7 +733,7 @@ async function* parseCodexUsageJsonl(filePath, context) {
710
733
  provider: "openai",
711
734
  model,
712
735
  timestamp,
713
- session: context.session,
736
+ session,
714
737
  inputTokens: Math.max(usage2.inputTokens - usage2.cachedInputTokens, 0),
715
738
  outputTokens: Math.max(usage2.outputTokens - reasoningTokens, 0),
716
739
  reasoningTokens,
@@ -721,6 +744,19 @@ async function* parseCodexUsageJsonl(filePath, context) {
721
744
  }
722
745
  }
723
746
  }
747
+ function codexUsageRecordKey(record) {
748
+ return JSON.stringify([
749
+ record.session ?? "",
750
+ record.timestamp ?? "",
751
+ record.provider ?? "",
752
+ record.model ?? "",
753
+ record.inputTokens,
754
+ record.outputTokens,
755
+ record.reasoningTokens,
756
+ record.cacheReadTokens,
757
+ record.cacheWriteTokens
758
+ ]);
759
+ }
724
760
  function parseCodexTokenUsage(value) {
725
761
  const usage2 = asRecord3(value);
726
762
  if (!usage2) {
@@ -3209,7 +3245,7 @@ async function main() {
3209
3245
  process.exit(0);
3210
3246
  }
3211
3247
  if (command === "--version") {
3212
- console.log("0.5.4");
3248
+ console.log("0.5.5");
3213
3249
  process.exit(0);
3214
3250
  }
3215
3251
  const parsed = parseCommand(args);