@tokz/cli 0.2.12 → 0.2.13
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/{Root-FWMJ2TO2.js → Root-HZIVZ2YT.js} +266 -137
- package/dist/cli.js +1 -1
- package/package.json +1 -1
|
@@ -632,149 +632,210 @@ var codebuffAdapter = {
|
|
|
632
632
|
};
|
|
633
633
|
|
|
634
634
|
// src/agents/codex.ts
|
|
635
|
-
import { access as access5, readFile as readFile4 } from "fs/promises";
|
|
635
|
+
import { access as access5, readFile as readFile4, stat as stat2 } from "fs/promises";
|
|
636
636
|
import { homedir as homedir6 } from "os";
|
|
637
637
|
import { join as join6 } from "path";
|
|
638
638
|
import { glob as glob4 } from "tinyglobby";
|
|
639
|
-
import { z } from "zod";
|
|
640
|
-
var TokenTotals = z.object({
|
|
641
|
-
input_tokens: z.number().catch(0).default(0),
|
|
642
|
-
cached_input_tokens: z.number().catch(0).default(0),
|
|
643
|
-
output_tokens: z.number().catch(0).default(0),
|
|
644
|
-
reasoning_output_tokens: z.number().catch(0).default(0),
|
|
645
|
-
total_tokens: z.number().catch(0).default(0)
|
|
646
|
-
});
|
|
647
|
-
var Line = z.object({
|
|
648
|
-
timestamp: z.string().optional(),
|
|
649
|
-
type: z.string().optional(),
|
|
650
|
-
// old-format meta lines carry cwd at the top level
|
|
651
|
-
cwd: z.string().optional(),
|
|
652
|
-
payload: z.object({
|
|
653
|
-
type: z.string().optional(),
|
|
654
|
-
cwd: z.string().optional(),
|
|
655
|
-
model: z.string().optional(),
|
|
656
|
-
name: z.string().optional(),
|
|
657
|
-
info: z.object({
|
|
658
|
-
total_token_usage: TokenTotals.optional(),
|
|
659
|
-
// Codex writes the per-turn amount here directly; prefer it over
|
|
660
|
-
// differencing cumulative totals.
|
|
661
|
-
last_token_usage: TokenTotals.optional()
|
|
662
|
-
}).nullish()
|
|
663
|
-
}).passthrough().optional()
|
|
664
|
-
});
|
|
665
|
-
function codexHome(home) {
|
|
666
|
-
if (home) return join6(home, ".codex");
|
|
667
|
-
return process.env.CODEX_HOME ?? join6(homedir6(), ".codex");
|
|
668
|
-
}
|
|
669
639
|
var DEFAULT_MODEL = "gpt-5";
|
|
640
|
+
var CODEX_AUTO_REVIEW_MODEL = "codex-auto-review";
|
|
641
|
+
var CODEX_AUTO_REVIEW_FALLBACKS = [
|
|
642
|
+
{ releasedOn: "2026-04-23", model: "gpt-5.5" },
|
|
643
|
+
{ releasedOn: "2026-03-05", model: "gpt-5.4" },
|
|
644
|
+
{ releasedOn: "2026-02-05", model: "gpt-5.3-codex" },
|
|
645
|
+
{ releasedOn: "2025-12-11", model: "gpt-5.2-codex" },
|
|
646
|
+
{ releasedOn: "2025-11-13", model: "gpt-5.1-codex" },
|
|
647
|
+
{ releasedOn: "2025-09-15", model: "gpt-5-codex" },
|
|
648
|
+
{ releasedOn: "2025-08-07", model: "gpt-5" }
|
|
649
|
+
];
|
|
650
|
+
function codexHomes(home) {
|
|
651
|
+
if (home) return [join6(home, ".codex")];
|
|
652
|
+
const env = process.env.CODEX_HOME;
|
|
653
|
+
if (env) {
|
|
654
|
+
return env.split(",").map((p) => p.trim()).filter((p) => p.length > 0);
|
|
655
|
+
}
|
|
656
|
+
return [join6(homedir6(), ".codex")];
|
|
657
|
+
}
|
|
658
|
+
function asDict(v) {
|
|
659
|
+
return typeof v === "object" && v !== null && !Array.isArray(v) ? v : void 0;
|
|
660
|
+
}
|
|
661
|
+
function u64(v) {
|
|
662
|
+
if (typeof v === "number") {
|
|
663
|
+
return Number.isInteger(v) && v >= 0 ? v : void 0;
|
|
664
|
+
}
|
|
665
|
+
if (typeof v === "string") {
|
|
666
|
+
const t = v.trim();
|
|
667
|
+
return /^\d+$/.test(t) ? Number(t) : void 0;
|
|
668
|
+
}
|
|
669
|
+
return void 0;
|
|
670
|
+
}
|
|
671
|
+
function rawUsage(v) {
|
|
672
|
+
const o = asDict(v);
|
|
673
|
+
if (!o) return void 0;
|
|
674
|
+
const input = u64(o.input_tokens) ?? u64(o.prompt_tokens) ?? u64(o.input) ?? 0;
|
|
675
|
+
const cached = u64(o.cached_input_tokens) ?? u64(o.cache_read_input_tokens) ?? u64(o.cached_tokens) ?? 0;
|
|
676
|
+
const output = u64(o.output_tokens) ?? u64(o.completion_tokens) ?? u64(o.output) ?? 0;
|
|
677
|
+
const reasoning = u64(o.reasoning_output_tokens) ?? u64(o.reasoning_tokens) ?? 0;
|
|
678
|
+
const sum = input + output + reasoning;
|
|
679
|
+
const totalField = u64(o.total_tokens);
|
|
680
|
+
const total = totalField !== void 0 && (totalField > 0 || sum === 0) ? totalField : sum;
|
|
681
|
+
return { input, cached, output, reasoning, total };
|
|
682
|
+
}
|
|
683
|
+
function subtractUsage(current, previous) {
|
|
684
|
+
return {
|
|
685
|
+
input: Math.max(0, current.input - (previous?.input ?? 0)),
|
|
686
|
+
cached: Math.max(0, current.cached - (previous?.cached ?? 0)),
|
|
687
|
+
output: Math.max(0, current.output - (previous?.output ?? 0)),
|
|
688
|
+
reasoning: Math.max(0, current.reasoning - (previous?.reasoning ?? 0)),
|
|
689
|
+
total: Math.max(0, current.total - (previous?.total ?? 0))
|
|
690
|
+
};
|
|
691
|
+
}
|
|
692
|
+
function nonEmpty(v) {
|
|
693
|
+
if (typeof v !== "string") return void 0;
|
|
694
|
+
const t = v.trim();
|
|
695
|
+
return t.length > 0 ? t : void 0;
|
|
696
|
+
}
|
|
697
|
+
function modelFromParts(v) {
|
|
698
|
+
const o = asDict(v);
|
|
699
|
+
if (!o) return void 0;
|
|
700
|
+
return nonEmpty(o.model) ?? nonEmpty(o.model_name) ?? nonEmpty(asDict(o.metadata)?.model);
|
|
701
|
+
}
|
|
702
|
+
function timestampDate(ts) {
|
|
703
|
+
const date = ts.slice(0, 10);
|
|
704
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) return void 0;
|
|
705
|
+
const year = Number(date.slice(0, 4));
|
|
706
|
+
const month = Number(date.slice(5, 7));
|
|
707
|
+
const day = Number(date.slice(8, 10));
|
|
708
|
+
const daysInMonth = month === 2 ? year % 4 === 0 && year % 100 !== 0 || year % 400 === 0 ? 29 : 28 : [1, 3, 5, 7, 8, 10, 12].includes(month) ? 31 : [4, 6, 9, 11].includes(month) ? 30 : void 0;
|
|
709
|
+
if (daysInMonth === void 0 || day < 1 || day > daysInMonth) return void 0;
|
|
710
|
+
return date;
|
|
711
|
+
}
|
|
712
|
+
function autoReviewFallback(model, timestamp) {
|
|
713
|
+
if (model !== CODEX_AUTO_REVIEW_MODEL) return void 0;
|
|
714
|
+
const date = timestampDate(timestamp);
|
|
715
|
+
if (!date) return DEFAULT_MODEL;
|
|
716
|
+
return CODEX_AUTO_REVIEW_FALLBACKS.find((f) => date >= f.releasedOn)?.model ?? DEFAULT_MODEL;
|
|
717
|
+
}
|
|
718
|
+
function resolveModel(parsed, timestamp, state) {
|
|
719
|
+
if (parsed !== void 0) {
|
|
720
|
+
state.current = parsed;
|
|
721
|
+
state.currentIsFallback = false;
|
|
722
|
+
}
|
|
723
|
+
let model = parsed ?? state.current;
|
|
724
|
+
if (model === void 0) {
|
|
725
|
+
state.currentIsFallback = true;
|
|
726
|
+
state.current = DEFAULT_MODEL;
|
|
727
|
+
model = DEFAULT_MODEL;
|
|
728
|
+
}
|
|
729
|
+
return autoReviewFallback(model, timestamp) ?? model;
|
|
730
|
+
}
|
|
731
|
+
function normalizeTimestamp(v) {
|
|
732
|
+
if (typeof v === "string") {
|
|
733
|
+
const t = v.trim();
|
|
734
|
+
if (t.length === 0) return void 0;
|
|
735
|
+
const ms2 = Date.parse(t);
|
|
736
|
+
return Number.isNaN(ms2) ? void 0 : new Date(ms2).toISOString();
|
|
737
|
+
}
|
|
738
|
+
const raw = u64(v);
|
|
739
|
+
if (raw === void 0) return void 0;
|
|
740
|
+
const ms = raw > 1e10 ? raw : raw * 1e3;
|
|
741
|
+
return new Date(ms).toISOString();
|
|
742
|
+
}
|
|
743
|
+
function rawOrNormalizedTimestamp(v) {
|
|
744
|
+
if (typeof v === "string") {
|
|
745
|
+
const t = v.trim();
|
|
746
|
+
if (t.length === 0) return void 0;
|
|
747
|
+
if (timestampDate(t) !== void 0) return t;
|
|
748
|
+
return normalizeTimestamp(t);
|
|
749
|
+
}
|
|
750
|
+
return normalizeTimestamp(v);
|
|
751
|
+
}
|
|
670
752
|
function tsSecond(ts) {
|
|
671
753
|
return (ts ?? "").slice(0, 19);
|
|
672
754
|
}
|
|
755
|
+
function parseLine(raw) {
|
|
756
|
+
let obj;
|
|
757
|
+
try {
|
|
758
|
+
obj = JSON.parse(raw);
|
|
759
|
+
} catch {
|
|
760
|
+
return void 0;
|
|
761
|
+
}
|
|
762
|
+
const o = asDict(obj);
|
|
763
|
+
if (!o) return void 0;
|
|
764
|
+
return {
|
|
765
|
+
timestamp: typeof o.timestamp === "string" ? o.timestamp : void 0,
|
|
766
|
+
type: typeof o.type === "string" ? o.type : void 0,
|
|
767
|
+
cwd: typeof o.cwd === "string" ? o.cwd : void 0,
|
|
768
|
+
payload: asDict(o.payload),
|
|
769
|
+
obj: o
|
|
770
|
+
};
|
|
771
|
+
}
|
|
772
|
+
function tokenCountInfo(p) {
|
|
773
|
+
return p.type === "event_msg" && p.payload?.type === "token_count" ? asDict(p.payload.info) : void 0;
|
|
774
|
+
}
|
|
673
775
|
function replayBurstSecond(content, lines) {
|
|
674
776
|
const head = content.slice(0, 16384);
|
|
675
777
|
if (!head.includes("thread_spawn") && !head.includes("forked_from_id")) return void 0;
|
|
676
778
|
let first;
|
|
677
779
|
for (const p of lines) {
|
|
678
|
-
const info = p
|
|
679
|
-
if (!info
|
|
780
|
+
const info = tokenCountInfo(p);
|
|
781
|
+
if (!info) continue;
|
|
782
|
+
if (!asDict(info.last_token_usage) && !asDict(info.total_token_usage)) continue;
|
|
680
783
|
const sec = tsSecond(p.timestamp);
|
|
681
784
|
if (first === void 0) first = sec;
|
|
682
785
|
else return first === sec ? first : void 0;
|
|
683
786
|
}
|
|
684
787
|
return void 0;
|
|
685
788
|
}
|
|
789
|
+
function headlessUsage(o) {
|
|
790
|
+
const usage = rawUsage(asDict(o.usage)) ?? rawUsage(asDict(asDict(o.data)?.usage)) ?? rawUsage(asDict(asDict(o.result)?.usage)) ?? rawUsage(asDict(asDict(o.response)?.usage));
|
|
791
|
+
if (!usage) return void 0;
|
|
792
|
+
if (usage.input === 0 && usage.cached === 0 && usage.output === 0 && usage.reasoning === 0 && usage.total === 0) {
|
|
793
|
+
return void 0;
|
|
794
|
+
}
|
|
795
|
+
return usage;
|
|
796
|
+
}
|
|
797
|
+
function headlessModel(o) {
|
|
798
|
+
return modelFromParts(o) ?? modelFromParts(asDict(o.data)) ?? modelFromParts(asDict(o.result)) ?? modelFromParts(asDict(o.response));
|
|
799
|
+
}
|
|
800
|
+
function headlessTimestamp(o, pick) {
|
|
801
|
+
const fromFields = (f) => f ? pick(f.timestamp) ?? pick(f.created_at) ?? pick(f.createdAt) : void 0;
|
|
802
|
+
return fromFields(o) ?? fromFields(asDict(o.data)) ?? fromFields(asDict(o.result)) ?? fromFields(asDict(o.response));
|
|
803
|
+
}
|
|
686
804
|
async function parseCodexRollout(file, seen = /* @__PURE__ */ new Set()) {
|
|
687
805
|
const stats = { file, usageByModel: {}, toolCalls: {}, toolCostUsd: {}, dailyUsage: {} };
|
|
688
806
|
const content = await readFile4(file, "utf8").catch(() => "");
|
|
689
807
|
const lines = [];
|
|
690
808
|
for (const raw of content.split("\n")) {
|
|
691
809
|
if (!raw.trim()) continue;
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
obj = JSON.parse(raw);
|
|
695
|
-
} catch {
|
|
696
|
-
continue;
|
|
697
|
-
}
|
|
698
|
-
const parsed = Line.safeParse(obj);
|
|
699
|
-
if (parsed.success) lines.push(parsed.data);
|
|
810
|
+
const parsed = parseLine(raw);
|
|
811
|
+
if (parsed) lines.push(parsed);
|
|
700
812
|
}
|
|
701
813
|
const burstSecond = replayBurstSecond(content, lines);
|
|
702
814
|
let skippingReplay = burstSecond !== void 0;
|
|
703
|
-
|
|
704
|
-
let prev
|
|
815
|
+
const modelState = { currentIsFallback: false };
|
|
816
|
+
let prev;
|
|
705
817
|
let turnTools = [];
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
if (
|
|
709
|
-
|
|
710
|
-
if (timestamp) {
|
|
711
|
-
if (!stats.firstTs) stats.firstTs = timestamp;
|
|
712
|
-
stats.lastTs = timestamp;
|
|
818
|
+
let mtimeIso;
|
|
819
|
+
const fileMtime = async () => {
|
|
820
|
+
if (mtimeIso === void 0) {
|
|
821
|
+
mtimeIso = await stat2(file).then((s) => s.mtime.toISOString()).catch(() => (/* @__PURE__ */ new Date(0)).toISOString());
|
|
713
822
|
}
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
}
|
|
719
|
-
const info = payload2?.type === "token_count" ? payload2.info : void 0;
|
|
720
|
-
const last = info?.last_token_usage;
|
|
721
|
-
const totals = info?.total_token_usage;
|
|
722
|
-
if (!last && !totals) continue;
|
|
723
|
-
if (skippingReplay && tsSecond(timestamp) === burstSecond) {
|
|
724
|
-
if (totals) {
|
|
725
|
-
prev = {
|
|
726
|
-
input: totals.input_tokens,
|
|
727
|
-
cached: totals.cached_input_tokens,
|
|
728
|
-
output: totals.output_tokens,
|
|
729
|
-
total: totals.total_tokens
|
|
730
|
-
};
|
|
731
|
-
}
|
|
732
|
-
turnTools = [];
|
|
733
|
-
continue;
|
|
734
|
-
}
|
|
735
|
-
skippingReplay = false;
|
|
736
|
-
const idTotals = last ?? totals;
|
|
737
|
-
const dedupKey = `${timestamp ?? ""}|${model}|${idTotals.input_tokens}|${idTotals.cached_input_tokens}|${idTotals.output_tokens}|${idTotals.reasoning_output_tokens}|${idTotals.total_tokens}`;
|
|
738
|
-
let dInput;
|
|
739
|
-
let dCached;
|
|
740
|
-
let dOutput;
|
|
741
|
-
if (last) {
|
|
742
|
-
dInput = last.input_tokens;
|
|
743
|
-
dCached = last.cached_input_tokens;
|
|
744
|
-
dOutput = last.output_tokens;
|
|
745
|
-
if (totals) {
|
|
746
|
-
prev = {
|
|
747
|
-
input: totals.input_tokens,
|
|
748
|
-
cached: totals.cached_input_tokens,
|
|
749
|
-
output: totals.output_tokens,
|
|
750
|
-
total: totals.total_tokens
|
|
751
|
-
};
|
|
752
|
-
}
|
|
753
|
-
} else {
|
|
754
|
-
const cur = {
|
|
755
|
-
input: totals.input_tokens,
|
|
756
|
-
cached: totals.cached_input_tokens,
|
|
757
|
-
output: totals.output_tokens,
|
|
758
|
-
total: totals.total_tokens
|
|
759
|
-
};
|
|
760
|
-
if (cur.total < prev.total) prev = { input: 0, cached: 0, output: 0, total: 0 };
|
|
761
|
-
dInput = Math.max(0, cur.input - prev.input);
|
|
762
|
-
dCached = Math.max(0, cur.cached - prev.cached);
|
|
763
|
-
dOutput = Math.max(0, cur.output - prev.output);
|
|
764
|
-
prev = cur;
|
|
765
|
-
}
|
|
766
|
-
if (dInput + dOutput === 0) continue;
|
|
823
|
+
return mtimeIso;
|
|
824
|
+
};
|
|
825
|
+
const accumulate = (usage, model, timestamp) => {
|
|
826
|
+
const cached = Math.min(usage.cached, usage.input);
|
|
827
|
+
const dedupKey = `${timestamp ?? ""}|${model}|${usage.input}|${cached}|${usage.output}|${usage.reasoning}|${usage.total}`;
|
|
767
828
|
if (seen.has(dedupKey)) {
|
|
768
829
|
turnTools = [];
|
|
769
|
-
|
|
830
|
+
return;
|
|
770
831
|
}
|
|
771
832
|
seen.add(dedupKey);
|
|
772
833
|
const delta = {
|
|
773
834
|
// Codex's input_tokens INCLUDES cached tokens; split them out.
|
|
774
|
-
inputTokens: Math.max(0,
|
|
775
|
-
cacheReadTokens:
|
|
835
|
+
inputTokens: Math.max(0, usage.input - cached),
|
|
836
|
+
cacheReadTokens: cached,
|
|
776
837
|
cacheCreationTokens: 0,
|
|
777
|
-
outputTokens:
|
|
838
|
+
outputTokens: usage.output,
|
|
778
839
|
turns: 1
|
|
779
840
|
};
|
|
780
841
|
const accs = [stats.usageByModel[model] ??= emptyUsage()];
|
|
@@ -796,15 +857,84 @@ async function parseCodexRollout(file, seen = /* @__PURE__ */ new Set()) {
|
|
|
796
857
|
}
|
|
797
858
|
}
|
|
798
859
|
turnTools = [];
|
|
860
|
+
};
|
|
861
|
+
for (const parsed of lines) {
|
|
862
|
+
const { timestamp, type, payload: payload2 } = parsed;
|
|
863
|
+
if (!stats.cwd) {
|
|
864
|
+
const payloadCwd = typeof payload2?.cwd === "string" ? payload2.cwd : void 0;
|
|
865
|
+
stats.cwd = payloadCwd ?? parsed.cwd;
|
|
866
|
+
}
|
|
867
|
+
if (timestamp) {
|
|
868
|
+
if (!stats.firstTs) stats.firstTs = timestamp;
|
|
869
|
+
stats.lastTs = timestamp;
|
|
870
|
+
}
|
|
871
|
+
const toolName = payload2?.type === "function_call" || payload2?.type === "custom_tool_call" ? nonEmpty(payload2.name) : payload2?.type === "local_shell_call" ? "shell" : type === "function_call" ? nonEmpty(parsed.obj.name) : void 0;
|
|
872
|
+
if (toolName) {
|
|
873
|
+
stats.toolCalls[toolName] = (stats.toolCalls[toolName] ?? 0) + 1;
|
|
874
|
+
turnTools.push(toolName);
|
|
875
|
+
}
|
|
876
|
+
if (type === "turn_context") {
|
|
877
|
+
const model2 = modelFromParts(payload2);
|
|
878
|
+
if (model2 !== void 0) {
|
|
879
|
+
modelState.current = model2;
|
|
880
|
+
modelState.currentIsFallback = false;
|
|
881
|
+
}
|
|
882
|
+
continue;
|
|
883
|
+
}
|
|
884
|
+
const info = tokenCountInfo(parsed);
|
|
885
|
+
if (info) {
|
|
886
|
+
const totals = rawUsage(info.total_token_usage);
|
|
887
|
+
const last = rawUsage(info.last_token_usage);
|
|
888
|
+
if (!last && !totals) continue;
|
|
889
|
+
if (skippingReplay && tsSecond(timestamp) === burstSecond) {
|
|
890
|
+
if (totals) prev = totals;
|
|
891
|
+
turnTools = [];
|
|
892
|
+
continue;
|
|
893
|
+
}
|
|
894
|
+
skippingReplay = false;
|
|
895
|
+
const usage2 = last ?? subtractUsage(totals, prev);
|
|
896
|
+
if (totals) prev = totals;
|
|
897
|
+
if (usage2.input === 0 && usage2.cached === 0 && usage2.output === 0 && usage2.reasoning === 0) {
|
|
898
|
+
continue;
|
|
899
|
+
}
|
|
900
|
+
const ts = nonEmpty(timestamp) ?? normalizeTimestamp(parsed.obj.timestamp);
|
|
901
|
+
const parsedModel = modelFromParts(payload2) ?? modelFromParts(info);
|
|
902
|
+
const model2 = resolveModel(parsedModel, ts ?? "", modelState);
|
|
903
|
+
accumulate(usage2, model2, ts);
|
|
904
|
+
continue;
|
|
905
|
+
}
|
|
906
|
+
if (type === "event_msg" || payload2?.type === "turn_context") continue;
|
|
907
|
+
const usage = headlessUsage(parsed.obj);
|
|
908
|
+
if (!usage) continue;
|
|
909
|
+
const eventTs = headlessTimestamp(parsed.obj, normalizeTimestamp) ?? await fileMtime();
|
|
910
|
+
const modelTs = headlessTimestamp(parsed.obj, rawOrNormalizedTimestamp) ?? await fileMtime();
|
|
911
|
+
const model = resolveModel(headlessModel(parsed.obj), modelTs, modelState);
|
|
912
|
+
accumulate(usage, model, eventTs);
|
|
799
913
|
}
|
|
800
914
|
return stats;
|
|
801
915
|
}
|
|
802
916
|
async function loadCodexProjects(home, onProgress) {
|
|
803
|
-
const
|
|
804
|
-
const
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
917
|
+
const files = [];
|
|
918
|
+
for (const root of codexHomes(home)) {
|
|
919
|
+
const sources = [];
|
|
920
|
+
for (const dir of ["sessions", "archived_sessions"]) {
|
|
921
|
+
const full = join6(root, dir);
|
|
922
|
+
const ok = await access5(full).then(() => true).catch(() => false);
|
|
923
|
+
if (ok) sources.push(full);
|
|
924
|
+
}
|
|
925
|
+
if (sources.length === 0) sources.push(root);
|
|
926
|
+
const seenRelative = /* @__PURE__ */ new Set();
|
|
927
|
+
for (const source of sources) {
|
|
928
|
+
const found = await glob4(["**/*.jsonl"], { cwd: source, absolute: false }).catch(() => []);
|
|
929
|
+
found.sort();
|
|
930
|
+
for (const rel of found) {
|
|
931
|
+
const key = rel.replaceAll("\\", "/");
|
|
932
|
+
if (seenRelative.has(key)) continue;
|
|
933
|
+
seenRelative.add(key);
|
|
934
|
+
files.push(join6(source, rel));
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
}
|
|
808
938
|
if (files.length === 0) return [];
|
|
809
939
|
const sessions = [];
|
|
810
940
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -822,12 +952,11 @@ var codexAdapter = {
|
|
|
822
952
|
name: "OpenAI Codex",
|
|
823
953
|
supported: true,
|
|
824
954
|
async detect(home) {
|
|
825
|
-
|
|
826
|
-
await access5(join6(
|
|
827
|
-
return true;
|
|
828
|
-
} catch {
|
|
829
|
-
return false;
|
|
955
|
+
for (const root of codexHomes(home)) {
|
|
956
|
+
const ok = await access5(join6(root, "sessions")).then(() => true).catch(() => false);
|
|
957
|
+
if (ok) return true;
|
|
830
958
|
}
|
|
959
|
+
return false;
|
|
831
960
|
},
|
|
832
961
|
loadProjects: loadCodexProjects
|
|
833
962
|
};
|
|
@@ -933,7 +1062,7 @@ var copilotAdapter = {
|
|
|
933
1062
|
};
|
|
934
1063
|
|
|
935
1064
|
// src/agents/droid.ts
|
|
936
|
-
import { access as access7, stat as
|
|
1065
|
+
import { access as access7, stat as stat3 } from "fs/promises";
|
|
937
1066
|
import { homedir as homedir8 } from "os";
|
|
938
1067
|
import { basename as basename2, join as join8 } from "path";
|
|
939
1068
|
import { glob as glob6 } from "tinyglobby";
|
|
@@ -947,7 +1076,7 @@ async function parseFile2(file) {
|
|
|
947
1076
|
let ts = str(settings, "updatedAt") ?? str(settings, "createdAt");
|
|
948
1077
|
if (!ts) {
|
|
949
1078
|
try {
|
|
950
|
-
ts = (await
|
|
1079
|
+
ts = (await stat3(file)).mtime.toISOString();
|
|
951
1080
|
} catch {
|
|
952
1081
|
}
|
|
953
1082
|
}
|
|
@@ -1535,27 +1664,27 @@ import { access as access14, readFile as readFile6 } from "fs/promises";
|
|
|
1535
1664
|
import { homedir as homedir15 } from "os";
|
|
1536
1665
|
import { join as join15 } from "path";
|
|
1537
1666
|
import { glob as glob10 } from "tinyglobby";
|
|
1538
|
-
import { z
|
|
1539
|
-
var Message =
|
|
1540
|
-
sessionID:
|
|
1541
|
-
role:
|
|
1542
|
-
modelID:
|
|
1543
|
-
providerID:
|
|
1544
|
-
time:
|
|
1545
|
-
tokens:
|
|
1546
|
-
input:
|
|
1547
|
-
output:
|
|
1548
|
-
reasoning:
|
|
1549
|
-
cache:
|
|
1667
|
+
import { z } from "zod";
|
|
1668
|
+
var Message = z.object({
|
|
1669
|
+
sessionID: z.string(),
|
|
1670
|
+
role: z.string(),
|
|
1671
|
+
modelID: z.string().optional(),
|
|
1672
|
+
providerID: z.string().optional(),
|
|
1673
|
+
time: z.object({ created: z.number().optional(), completed: z.number().optional() }).optional(),
|
|
1674
|
+
tokens: z.object({
|
|
1675
|
+
input: z.number().catch(0).default(0),
|
|
1676
|
+
output: z.number().catch(0).default(0),
|
|
1677
|
+
reasoning: z.number().catch(0).default(0),
|
|
1678
|
+
cache: z.object({ read: z.number().catch(0).default(0), write: z.number().catch(0).default(0) }).optional()
|
|
1550
1679
|
}).optional()
|
|
1551
1680
|
});
|
|
1552
|
-
var Session =
|
|
1553
|
-
id:
|
|
1554
|
-
directory:
|
|
1555
|
-
projectID:
|
|
1556
|
-
time:
|
|
1681
|
+
var Session = z.object({
|
|
1682
|
+
id: z.string(),
|
|
1683
|
+
directory: z.string().optional(),
|
|
1684
|
+
projectID: z.string().optional(),
|
|
1685
|
+
time: z.object({ created: z.number().optional() }).optional()
|
|
1557
1686
|
});
|
|
1558
|
-
var Project =
|
|
1687
|
+
var Project = z.object({ id: z.string(), worktree: z.string().optional() });
|
|
1559
1688
|
function opencodeRoot(home) {
|
|
1560
1689
|
if (home) return join15(home, ".local", "share", "opencode");
|
|
1561
1690
|
return process.env.OPENCODE_DATA_DIR ?? join15(homedir15(), ".local", "share", "opencode");
|
package/dist/cli.js
CHANGED
|
@@ -276,7 +276,7 @@ program.action(async () => {
|
|
|
276
276
|
const [{ render }, React, { Root }, { Fullscreen }] = await Promise.all([
|
|
277
277
|
import("ink"),
|
|
278
278
|
import("react"),
|
|
279
|
-
import("./Root-
|
|
279
|
+
import("./Root-HZIVZ2YT.js"),
|
|
280
280
|
import("./Fullscreen-GK2ZYXHV.js")
|
|
281
281
|
]);
|
|
282
282
|
render(React.createElement(Fullscreen, null, React.createElement(Root)));
|