@ycodium-ai/agent-codex 0.2.3369 → 0.2.3377

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.
Files changed (2) hide show
  1. package/dist/index.js +2059 -767
  2. package/package.json +3 -2
package/dist/index.js CHANGED
@@ -435,321 +435,1188 @@ var probeCodexAccount = (accountPath) => {
435
435
  };
436
436
  };
437
437
 
438
- // src/codexInstance.ts
438
+ // src/liveHistory.ts
439
+ import * as NodeFSP4 from "node:fs/promises";
440
+ import * as NodePath7 from "node:path";
439
441
  import * as NodeProcess from "node:process";
440
- import {
441
- describeExecutorSpawnFailure,
442
- ExecutorSpawnRefusedError as ExecutorSpawnRefusedError2,
443
- raceAbort as raceAbort2
444
- } from "@ycodium-ai/plugin-api/executor";
445
-
446
- // src/appServerLaunch.ts
447
- import {
448
- ExecutorSpawnAbortedError,
449
- ExecutorSpawnRefusedError,
450
- throwIfExecutorSpawnAborted
451
- } from "@ycodium-ai/plugin-api/executor";
452
-
453
- // src/connection.ts
454
- import { mergeLaunchEnv } from "@ycodium-ai/plugin-api/executor";
455
-
456
- // src/config.ts
457
- import { modelSelectionStringOption } from "@ycodium-ai/plugin-api/executor";
458
442
 
459
- // src/apiKeyEnv.ts
460
- var CODEX_INSTANCE_API_KEY_ENV = "YCODIUM_CODEX_API_KEY";
443
+ // ../../packages/ycodium-jsonl-stream/src/historyErrors.ts
444
+ var NativeHistoryCursorError = class extends Error {
445
+ name = "NativeHistoryCursorError";
446
+ };
447
+ var NativeHistoryPendingError = class extends Error {
448
+ name = "NativeHistoryPendingError";
449
+ };
461
450
 
462
- // src/config.ts
463
- var CODEX_INSTANCE_MODEL_PROVIDER = "ycodium_api";
464
- function isRecord2(value) {
465
- return typeof value === "object" && value !== null && !Array.isArray(value);
466
- }
467
- function readString2(value) {
468
- return typeof value === "string" ? value : "";
469
- }
470
- function readTrimmed(value) {
471
- return readString2(value).trim();
472
- }
473
- function readAuthMode(value) {
474
- return value === "chatgpt" || value === "apiKey" ? value : "default";
475
- }
476
- function readEnvironment(value) {
477
- if (!Array.isArray(value)) return {};
478
- const env = {};
479
- for (const entry of value) {
480
- if (!isRecord2(entry)) continue;
481
- const name = readTrimmed(entry["name"]);
482
- if (name.length === 0) continue;
483
- env[name] = readString2(entry["value"]);
484
- }
485
- return env;
486
- }
487
- function parseCodexInstanceConfig(config) {
488
- if (!isRecord2(config)) {
489
- return {
490
- binaryPath: "",
491
- launchArgs: CODEX_DEFAULT_LAUNCH_ARGS,
492
- homePath: "",
493
- shadowHomePath: "",
494
- homeEnvVar: "",
495
- authMode: "default",
496
- apiBaseUrl: "",
497
- environment: {},
498
- envelopeDriver: void 0
499
- };
500
- }
501
- const nested = isRecord2(config["config"]) ? config["config"] : void 0;
502
- const settings = nested ?? config;
503
- return {
504
- binaryPath: readTrimmed(settings["binaryPath"]),
505
- launchArgs: readString2(settings["launchArgs"]) || CODEX_DEFAULT_LAUNCH_ARGS,
506
- homePath: readTrimmed(settings["homePath"]) || readTrimmed(config["homePath"]),
507
- shadowHomePath: readTrimmed(settings["shadowHomePath"]),
508
- homeEnvVar: readTrimmed(settings["homeEnvVar"]) || readTrimmed(config["homeEnvVar"]),
509
- authMode: readAuthMode(settings["authMode"]),
510
- apiBaseUrl: readTrimmed(settings["apiBaseUrl"]),
511
- environment: readEnvironment(config["environment"]),
512
- envelopeDriver: readTrimmed(config["driver"]) || void 0
451
+ // ../../packages/ycodium-jsonl-stream/src/historyWaiting.ts
452
+ import * as NodeFS3 from "node:fs";
453
+ import * as NodeFSP2 from "node:fs/promises";
454
+ import * as NodePath4 from "node:path";
455
+ var pending = (error) => error instanceof NativeHistoryPendingError || error !== null && typeof error === "object" && "code" in error && error.code === "ENOENT";
456
+ var waitForJsonlHistory = (input) => {
457
+ const controller = new AbortController();
458
+ const sources = /* @__PURE__ */ new Set();
459
+ const operations = /* @__PURE__ */ new Set();
460
+ const own = (promise) => {
461
+ operations.add(promise);
462
+ void promise.finally(() => operations.delete(promise)).catch(() => void 0);
463
+ return promise;
513
464
  };
514
- }
515
- function tokenizeLaunchArgs(value) {
516
- const input = value.trim();
517
- if (!input) return [];
518
- const tokens = [];
519
- let current = "";
520
- let quote;
521
- let quoted = false;
522
- for (let index = 0; index < input.length; index++) {
523
- const char = input[index];
524
- if (char === void 0) continue;
525
- if (quote) {
526
- if (char === quote) {
527
- quote = void 0;
528
- quoted = true;
529
- } else if (char === "\\" && quote === '"') {
530
- const next = input[index + 1];
531
- if (next !== void 0 && ['"', "\\", "$", "`"].includes(next)) {
532
- current += next;
533
- index++;
534
- } else {
535
- current += char;
465
+ const iterators = /* @__PURE__ */ new Set();
466
+ const open2 = () => own(
467
+ (async () => {
468
+ const signal = AbortSignal.any([
469
+ controller.signal,
470
+ ...input.signal ? [input.signal] : []
471
+ ]);
472
+ const source = await input.open(signal);
473
+ if (source === void 0) throw new NativeHistoryPendingError();
474
+ sources.add(source);
475
+ return source;
476
+ })()
477
+ );
478
+ const release = async (source) => {
479
+ await source.close();
480
+ sources.delete(source);
481
+ };
482
+ return {
483
+ page: (options) => own(
484
+ (async () => {
485
+ const source = await open2();
486
+ try {
487
+ return await source.page(options);
488
+ } finally {
489
+ await release(source);
536
490
  }
537
- } else {
538
- current += char;
539
- }
540
- continue;
491
+ })()
492
+ ),
493
+ follow: (options) => {
494
+ let iterator;
495
+ iterator = (async function* () {
496
+ const signal = AbortSignal.any([
497
+ controller.signal,
498
+ ...input.signal ? [input.signal] : [],
499
+ ...options.signal ? [options.signal] : []
500
+ ]);
501
+ let root = NodePath4.resolve(input.root);
502
+ while (true) {
503
+ try {
504
+ if ((await NodeFSP2.stat(root)).isDirectory()) break;
505
+ } catch (error2) {
506
+ if (!pending(error2)) throw error2;
507
+ }
508
+ const parent = NodePath4.dirname(root);
509
+ if (parent === root) throw new NativeHistoryPendingError();
510
+ root = parent;
511
+ }
512
+ let dirty = true;
513
+ let wake;
514
+ let error;
515
+ const notify = () => {
516
+ dirty = true;
517
+ wake?.();
518
+ wake = void 0;
519
+ };
520
+ const watcher = NodeFS3.watch(root, { recursive: true, signal }, (_event, name) => {
521
+ if (name == null || input.accepts(NodePath4.resolve(root, String(name)))) notify();
522
+ });
523
+ watcher.on("error", (cause) => {
524
+ error = cause;
525
+ notify();
526
+ });
527
+ signal.addEventListener("abort", notify, { once: true });
528
+ let announced = false;
529
+ try {
530
+ while (true) {
531
+ signal.throwIfAborted();
532
+ if (error !== void 0) throw error;
533
+ if (!dirty)
534
+ await new Promise((resolve4) => {
535
+ wake = resolve4;
536
+ });
537
+ signal.throwIfAborted();
538
+ dirty = false;
539
+ let source;
540
+ try {
541
+ source = await open2();
542
+ } catch (cause) {
543
+ if (!pending(cause)) throw cause;
544
+ if (!announced) {
545
+ announced = true;
546
+ yield { _tag: "unavailable", reason: "native-session-unavailable" };
547
+ yield { _tag: "synchronized" };
548
+ }
549
+ continue;
550
+ }
551
+ announced = false;
552
+ try {
553
+ for await (const frame of source.follow({ ...options, signal })) yield frame;
554
+ } catch (cause) {
555
+ if (!pending(cause)) throw cause;
556
+ } finally {
557
+ await release(source);
558
+ }
559
+ }
560
+ } finally {
561
+ watcher.close();
562
+ signal.removeEventListener("abort", notify);
563
+ wake?.();
564
+ if (iterator !== void 0) iterators.delete(iterator);
565
+ }
566
+ })();
567
+ iterators.add(iterator);
568
+ return iterator;
569
+ },
570
+ close: async () => {
571
+ controller.abort();
572
+ await Promise.all([...sources].map(release));
573
+ await Promise.all([...iterators].map((iterator) => iterator.return(void 0)));
574
+ await Promise.allSettled(operations);
541
575
  }
542
- if (char === "'" || char === '"') {
543
- quote = char;
544
- quoted = true;
545
- } else if (/\s/.test(char)) {
546
- if (current || quoted) {
547
- tokens.push(current);
548
- current = "";
549
- quoted = false;
550
- }
551
- } else if (char === "\\") {
552
- const next = input[index + 1];
553
- if (next !== void 0 && /\s/.test(next)) {
554
- current += next;
555
- index++;
556
- } else {
557
- current += char;
576
+ };
577
+ };
578
+
579
+ // ../../packages/ycodium-jsonl-stream/src/history.ts
580
+ import * as NodeFS4 from "node:fs";
581
+ import * as NodePath5 from "node:path";
582
+
583
+ // ../../packages/ycodium-jsonl-stream/src/historyFile.ts
584
+ import * as NodeFSP3 from "node:fs/promises";
585
+ import * as NodeCrypto from "node:crypto";
586
+ var HISTORY_READ_BYTES = 65536;
587
+ async function* historyBytes(path, start, end, signal) {
588
+ const file = await NodeFSP3.open(path, "r");
589
+ try {
590
+ let offset = start;
591
+ while (offset < end) {
592
+ signal?.throwIfAborted();
593
+ const buffer = Buffer.allocUnsafe(Math.min(HISTORY_READ_BYTES, end - offset));
594
+ const { bytesRead } = await file.read(buffer, 0, buffer.length, offset);
595
+ if (bytesRead === 0) throw new Error("Native history changed during a read.");
596
+ offset += bytesRead;
597
+ yield buffer.subarray(0, bytesRead);
598
+ }
599
+ } finally {
600
+ await file.close();
601
+ }
602
+ }
603
+ async function* historyText(path, range, signal) {
604
+ const decoder = new TextDecoder("utf-8", { fatal: true });
605
+ for await (const bytes of historyBytes(path, range.start, range.end, signal)) {
606
+ const text = decoder.decode(bytes, { stream: true });
607
+ if (text) yield text;
608
+ }
609
+ const last = decoder.decode();
610
+ if (last) yield last;
611
+ }
612
+ async function* historyLines(path, start, end, backwards, signal) {
613
+ if (!backwards) {
614
+ let lineStart = start;
615
+ let offset = start;
616
+ for await (const bytes of historyBytes(path, start, end, signal)) {
617
+ for (let index = 0; index < bytes.length; index += 1) {
618
+ if (bytes[index] !== 10) continue;
619
+ const lineEnd = offset + index;
620
+ if (lineEnd > lineStart)
621
+ yield { start: lineStart, end: lineEnd, commit: lineEnd + 1, terminated: true };
622
+ lineStart = lineEnd + 1;
558
623
  }
559
- } else {
560
- current += char;
624
+ offset += bytes.length;
561
625
  }
626
+ if (lineStart < end) yield { start: lineStart, end, commit: end, terminated: false };
627
+ return;
562
628
  }
563
- if (current || quoted) tokens.push(current);
564
- return tokens;
565
- }
566
- function encodeQuotedArgs(args) {
567
- return args.map((arg) => `"${arg.replaceAll("\\", "\\\\").replaceAll('"', '\\"')}"`).join(" ");
568
- }
569
- function codexExecLaunchArgs(launchArgs) {
570
- const args = tokenizeLaunchArgs(launchArgs ?? "");
571
- const execArgs = [];
572
- for (let index = 0; index < args.length; index++) {
573
- const arg = args[index];
574
- if (arg === void 0) continue;
575
- if (arg === "--strict-config" || arg.startsWith("--config=") || arg.startsWith("-c=")) {
576
- execArgs.push(arg);
577
- } else if (arg === "--config" || arg === "-c" || arg === "--enable" || arg === "--disable") {
578
- const value = args[index + 1];
579
- if (value !== void 0 && !value.startsWith("-")) {
580
- execArgs.push(arg, value);
581
- index++;
629
+ const file = await NodeFSP3.open(path, "r");
630
+ try {
631
+ let scan = end;
632
+ let lineEnd = end;
633
+ let terminated = false;
634
+ while (scan > start) {
635
+ signal?.throwIfAborted();
636
+ const from = Math.max(start, scan - HISTORY_READ_BYTES);
637
+ const buffer = Buffer.allocUnsafe(scan - from);
638
+ const { bytesRead } = await file.read(buffer, 0, buffer.length, from);
639
+ if (bytesRead !== buffer.length) throw new Error("Native history changed during a read.");
640
+ for (let index = buffer.length - 1; index >= 0; index -= 1) {
641
+ if (buffer[index] !== 10) continue;
642
+ const at = from + index;
643
+ if (at + 1 < lineEnd)
644
+ yield { start: at + 1, end: lineEnd, commit: lineEnd + (terminated ? 1 : 0), terminated };
645
+ lineEnd = at;
646
+ terminated = true;
582
647
  }
583
- } else if (arg.startsWith("--enable=") || arg.startsWith("--disable=")) {
584
- execArgs.push(arg);
648
+ scan = from;
585
649
  }
650
+ if (lineEnd > start)
651
+ yield { start, end: lineEnd, commit: lineEnd + (terminated ? 1 : 0), terminated };
652
+ } finally {
653
+ await file.close();
586
654
  }
587
- return execArgs;
588
655
  }
589
- function codexMcpThreadConfig(servers) {
656
+ var historyIdentity = async (path) => {
657
+ const stat4 = await NodeFSP3.stat(path);
590
658
  return {
591
- mcp_servers: Object.fromEntries(
592
- servers.map(({ name, transport }) => [
593
- name,
594
- transport.type === "stdio" ? { command: transport.command, args: transport.args ?? [], env: transport.env ?? {} } : { url: transport.url, http_headers: transport.headers ?? {} }
595
- ])
596
- )
659
+ size: stat4.size,
660
+ mtimeMs: stat4.mtimeMs,
661
+ ctimeMs: stat4.ctimeMs,
662
+ identity: NodeCrypto.createHash("sha256").update(`${path}/${stat4.dev}/${stat4.ino}/${stat4.birthtimeMs}`).digest("hex")
597
663
  };
598
- }
599
- function modelIdFromSelection(selection) {
600
- if (typeof selection !== "object" || selection === null || Array.isArray(selection)) {
601
- return void 0;
664
+ };
665
+ var historyCommittedFingerprint = async (path, sequence, signal) => {
666
+ const hash = NodeCrypto.createHash("sha256");
667
+ const starts = [
668
+ 0,
669
+ Math.max(0, Math.floor(sequence / 3) - 512),
670
+ Math.max(0, Math.floor(sequence * 2 / 3) - 512),
671
+ Math.max(0, sequence - 1024)
672
+ ];
673
+ for (const start of new Set(starts)) {
674
+ const end = Math.min(sequence, start + 1024);
675
+ hash.update(`${start}:${end}:`);
676
+ for await (const bytes of historyBytes(path, start, end, signal)) hash.update(bytes);
602
677
  }
603
- const model = selection["model"];
604
- return typeof model === "string" ? model.trim() || void 0 : void 0;
605
- }
678
+ return hash.digest("hex");
679
+ };
680
+ var historyBoundary = async (path, identity, sequence, signal) => {
681
+ const hash = NodeCrypto.createHash("sha256");
682
+ for await (const bytes of historyBytes(path, Math.max(0, sequence - 128), sequence, signal))
683
+ hash.update(bytes);
684
+ hash.update(await historyCommittedFingerprint(path, sequence, signal));
685
+ return { epoch: `${identity}.${hash.digest("hex")}`, sequence };
686
+ };
606
687
 
607
- // src/connection.ts
608
- function codexApiConnectionError(recipe, environment) {
609
- if (recipe.authMode !== "apiKey") return null;
610
- try {
611
- const url = new URL(recipe.apiBaseUrl);
612
- if (url.protocol !== "http:" && url.protocol !== "https:") {
613
- return "Codex API base URL must use HTTP or HTTPS.";
688
+ // ../../packages/ycodium-jsonl-stream/src/historyRecord.ts
689
+ import * as NodeCrypto2 from "node:crypto";
690
+
691
+ // ../../packages/ycodium-jsonl-stream/src/jsonlStream.ts
692
+ var DEFAULT_MAX_RETAINED_CHARS = 8e6;
693
+ var MAX_DEPTH = 128;
694
+ var MAX_KEY_CHARS = 256;
695
+ var MAX_BARE_CHARS = 64;
696
+ var NUMBER_PATTERN = /^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?$/u;
697
+ var OversizedRecordParser = class {
698
+ #fields;
699
+ #budget;
700
+ #options;
701
+ #retained = 0;
702
+ #malformed = false;
703
+ #done = false;
704
+ #result = void 0;
705
+ #stack = [];
706
+ // 词法状态。
707
+ #inString = false;
708
+ #stringIsKey = false;
709
+ #escape = false;
710
+ #unicodeLeft = 0;
711
+ #unicodeValue = 0;
712
+ #bare = "";
713
+ // 当前字符串的保留规则与累积。
714
+ #strObserver;
715
+ #strRetain = false;
716
+ #strCap = void 0;
717
+ #strHead = "";
718
+ #strTail = "";
719
+ #strLength = 0;
720
+ #key = "";
721
+ #keyOverflow = false;
722
+ // 值之间的位置。
723
+ #expectKey = false;
724
+ #expectColon = false;
725
+ #expectComma = false;
726
+ #expectValue = true;
727
+ constructor(fields2, maxRetainedChars = DEFAULT_MAX_RETAINED_CHARS, options) {
728
+ this.#fields = fields2;
729
+ this.#budget = maxRetainedChars;
730
+ this.#options = options;
731
+ }
732
+ write(chunk) {
733
+ if (this.#malformed) return;
734
+ try {
735
+ this.#consume(chunk);
736
+ } catch (cause) {
737
+ if (cause instanceof MalformedRecord) {
738
+ this.#malformed = true;
739
+ return;
740
+ }
741
+ throw cause;
614
742
  }
615
- } catch {
616
- return "Codex API base URL is missing or invalid.";
617
- }
618
- return environment[CODEX_INSTANCE_API_KEY_ENV]?.trim() ? null : "An API key is required for this Codex account.";
619
- }
620
- function connectionArgv(recipe, layout) {
621
- const args = [...tokenizeLaunchArgs(recipe.launchArgs)];
622
- const override = (key, value) => {
623
- args.push("-c", `${key}=${JSON.stringify(value)}`);
624
- };
625
- if (layout.mode === "authOverlay" || recipe.authMode !== "default") {
626
- override("sqlite_home", layout.sharedHomePath);
627
743
  }
628
- if (layout.mode === "authOverlay") {
629
- override("cli_auth_credentials_store", "file");
744
+ /** 完整且合法才返回记录;其余(含空行)返回 `undefined`。 */
745
+ finish() {
746
+ if (this.#malformed) return void 0;
747
+ try {
748
+ if (this.#bare.length > 0) this.#finishBare();
749
+ } catch (cause) {
750
+ if (cause instanceof MalformedRecord) return void 0;
751
+ throw cause;
752
+ }
753
+ if (!this.#done || this.#inString || this.#result === SKIPPED) return void 0;
754
+ return this.#result;
755
+ }
756
+ #fail() {
757
+ throw new MalformedRecord();
758
+ }
759
+ #charge(chars) {
760
+ this.#retained += chars;
761
+ if (this.#retained > this.#budget) this.#fail();
762
+ }
763
+ #consume(chunk) {
764
+ const n = chunk.length;
765
+ let i = 0;
766
+ while (i < n) {
767
+ if (this.#inString) {
768
+ i = this.#consumeString(chunk, i);
769
+ continue;
770
+ }
771
+ const c = chunk.charCodeAt(i);
772
+ if (this.#bare.length > 0) {
773
+ if (isBareChar(c)) {
774
+ if (this.#bare.length >= MAX_BARE_CHARS) this.#fail();
775
+ this.#bare += chunk[i];
776
+ i += 1;
777
+ continue;
778
+ }
779
+ this.#finishBare();
780
+ }
781
+ i += 1;
782
+ if (c === 32 || c === 9 || c === 10 || c === 13) continue;
783
+ if (this.#done) this.#fail();
784
+ switch (c) {
785
+ case 123:
786
+ this.#requireValue();
787
+ this.#openContainer(false);
788
+ break;
789
+ case 91:
790
+ this.#requireValue();
791
+ this.#openContainer(true);
792
+ break;
793
+ case 125:
794
+ this.#closeContainer(false);
795
+ break;
796
+ case 93:
797
+ this.#closeContainer(true);
798
+ break;
799
+ case 44:
800
+ this.#comma();
801
+ break;
802
+ case 58:
803
+ if (!this.#expectColon) this.#fail();
804
+ this.#expectColon = false;
805
+ this.#expectValue = true;
806
+ break;
807
+ case 34:
808
+ this.#openString();
809
+ break;
810
+ default:
811
+ if (isBareChar(c)) {
812
+ this.#requireValue();
813
+ this.#bare = chunk[i - 1] ?? "";
814
+ } else this.#fail();
815
+ }
816
+ }
630
817
  }
631
- if (recipe.authMode === "chatgpt") {
632
- override("model_provider", "openai");
633
- override("forced_login_method", "chatgpt");
634
- } else if (recipe.authMode === "apiKey") {
635
- override("model_provider", CODEX_INSTANCE_MODEL_PROVIDER);
636
- override(`model_providers.${CODEX_INSTANCE_MODEL_PROVIDER}.name`, "Ycodium API");
637
- override(`model_providers.${CODEX_INSTANCE_MODEL_PROVIDER}.base_url`, recipe.apiBaseUrl);
638
- override(
639
- `model_providers.${CODEX_INSTANCE_MODEL_PROVIDER}.env_key`,
640
- CODEX_INSTANCE_API_KEY_ENV
818
+ #top() {
819
+ return this.#stack[this.#stack.length - 1];
820
+ }
821
+ #requireValue() {
822
+ if (!this.#expectValue) this.#fail();
823
+ this.#expectValue = false;
824
+ }
825
+ /** 当前要读的值(刚要开始)落在什么模式;`isContainer` 决定 scalarOnly 清单项是否适用。 */
826
+ #childMode(isContainer) {
827
+ const parent = this.#top();
828
+ if (parent === void 0) return this.#classify([], isContainer);
829
+ if (parent.mode === "skip") return { mode: "skip", cap: void 0, path: [] };
830
+ if (parent.mode === "keep") return { mode: "keep", cap: parent.cap, path: [] };
831
+ const segment = parent.isArray ? String(parent.index) : parent.key ?? "";
832
+ if (parent.skipValue) return { mode: "skip", cap: void 0, path: [] };
833
+ return this.#classify([...parent.path, segment], isContainer);
834
+ }
835
+ #classify(path, isContainer) {
836
+ let descend = false;
837
+ for (const field of this.#fields) {
838
+ const fieldPath = field.path;
839
+ if (fieldPath.length <= path.length) {
840
+ if (field.scalarOnly === true && (isContainer || fieldPath.length !== path.length)) {
841
+ continue;
842
+ }
843
+ if (matchesPrefix(fieldPath, path, fieldPath.length)) {
844
+ return { mode: "keep", cap: field.maxChars, path };
845
+ }
846
+ } else if (matchesPrefix(fieldPath, path, path.length)) {
847
+ descend = true;
848
+ }
849
+ }
850
+ return { mode: descend ? "descend" : "skip", cap: void 0, path };
851
+ }
852
+ #openContainer(isArray2) {
853
+ if (this.#stack.length >= MAX_DEPTH) this.#fail();
854
+ const { mode, cap, path } = this.#childMode(true);
855
+ const keeping = mode !== "skip";
856
+ let target = null;
857
+ if (keeping) {
858
+ this.#charge(16);
859
+ target = isArray2 ? [] : {};
860
+ }
861
+ this.#stack.push({ isArray: isArray2, mode, path, cap, target, key: null, skipValue: false, index: 0 });
862
+ this.#expectValue = isArray2;
863
+ this.#expectKey = !isArray2;
864
+ this.#expectComma = false;
865
+ this.#expectColon = false;
866
+ }
867
+ #closeContainer(isArray2) {
868
+ const top = this.#top();
869
+ if (top === void 0 || top.isArray !== isArray2) this.#fail();
870
+ if (!this.#expectComma && top.index > 0) this.#fail();
871
+ if (this.#expectColon || !isArray2 && this.#expectValue) this.#fail();
872
+ this.#stack.pop();
873
+ this.#expectValue = false;
874
+ this.#expectKey = false;
875
+ this.#expectColon = false;
876
+ this.#expectComma = true;
877
+ const empty = top.target !== null && Object.keys(top.target).length === 0;
878
+ this.#store(
879
+ this.#options?.pruneEmpty && top.mode === "descend" && empty && this.#stack.length > 0 ? SKIPPED : top.target ?? SKIPPED
641
880
  );
642
- override(`model_providers.${CODEX_INSTANCE_MODEL_PROVIDER}.requires_openai_auth`, false);
643
- override(`model_providers.${CODEX_INSTANCE_MODEL_PROVIDER}.wire_api`, "responses");
644
881
  }
645
- return args;
646
- }
647
- function codexSpawnArgs(recipe, layout) {
648
- const needsOverrides = layout.mode === "authOverlay" || recipe.authMode !== "default";
649
- if (!needsOverrides) return tokenizeLaunchArgs(recipe.launchArgs);
650
- return connectionArgv(recipe, layout);
651
- }
652
- function encodeCodexConnectionArgs(recipe, layout) {
653
- return encodeQuotedArgs(connectionArgv(recipe, layout));
654
- }
655
- var CRUSHED_API_KEYS = {
656
- OPENAI_API_KEY: void 0,
657
- CODEX_API_KEY: void 0
882
+ #comma() {
883
+ const top = this.#top();
884
+ if (top === void 0 || !this.#expectComma) this.#fail();
885
+ this.#expectComma = false;
886
+ if (top.isArray) {
887
+ this.#expectValue = true;
888
+ } else {
889
+ this.#expectKey = true;
890
+ }
891
+ }
892
+ /** 一个值读完:交给外层容器,或成为整条记录。 */
893
+ #store(value) {
894
+ const parent = this.#top();
895
+ if (parent === void 0) {
896
+ this.#result = value;
897
+ this.#done = true;
898
+ this.#expectComma = false;
899
+ return;
900
+ }
901
+ this.#expectComma = true;
902
+ if (parent.isArray) {
903
+ parent.index += 1;
904
+ if (parent.target !== null && value !== SKIPPED) {
905
+ parent.target.push(value);
906
+ this.#charge(8);
907
+ }
908
+ return;
909
+ }
910
+ parent.index += 1;
911
+ const key = parent.key;
912
+ parent.key = null;
913
+ parent.skipValue = false;
914
+ if (parent.target !== null && value !== SKIPPED && key !== null) {
915
+ Object.defineProperty(parent.target, key, {
916
+ value,
917
+ enumerable: true,
918
+ writable: true,
919
+ configurable: true
920
+ });
921
+ this.#charge(key.length + 8);
922
+ }
923
+ }
924
+ #openString() {
925
+ const parent = this.#top();
926
+ const asKey = parent !== void 0 && !parent.isArray && this.#expectKey;
927
+ if (!asKey) this.#requireValue();
928
+ this.#inString = true;
929
+ this.#stringIsKey = asKey;
930
+ this.#escape = false;
931
+ this.#unicodeLeft = 0;
932
+ this.#strLength = 0;
933
+ this.#strHead = "";
934
+ this.#strTail = "";
935
+ this.#key = "";
936
+ if (asKey) {
937
+ this.#keyOverflow = false;
938
+ this.#strRetain = true;
939
+ this.#strCap = void 0;
940
+ return;
941
+ }
942
+ const { mode, cap, path } = this.#childMode(false);
943
+ this.#strObserver = this.#fields.find(
944
+ (field) => field.path.length === path.length && matchesPrefix(field.path, path, path.length)
945
+ );
946
+ this.#strRetain = mode === "keep" && this.#strObserver?.onChunk === void 0;
947
+ this.#strCap = cap;
948
+ }
949
+ /** 字符串里的一个解码后片段;按保留规则累积。 */
950
+ #append(text) {
951
+ if (text.length === 0) return;
952
+ if (this.#stringIsKey) {
953
+ if (this.#keyOverflow) return;
954
+ this.#key += text;
955
+ if (this.#key.length > MAX_KEY_CHARS) {
956
+ this.#keyOverflow = true;
957
+ this.#key = "";
958
+ }
959
+ return;
960
+ }
961
+ this.#strLength += text.length;
962
+ this.#strObserver?.onChunk?.(text);
963
+ if (!this.#strRetain) return;
964
+ const cap = this.#strCap;
965
+ if (cap === void 0) {
966
+ this.#strHead += text;
967
+ this.#charge(text.length);
968
+ return;
969
+ }
970
+ if (this.#strHead.length < cap) {
971
+ const room = cap - this.#strHead.length;
972
+ this.#strHead += text.slice(0, room);
973
+ text = text.slice(room);
974
+ if (text.length === 0) return;
975
+ }
976
+ this.#strTail += text;
977
+ if (this.#strTail.length > cap * 2) this.#strTail = this.#strTail.slice(-cap);
978
+ }
979
+ #consumeString(chunk, start) {
980
+ const n = chunk.length;
981
+ let i = start;
982
+ while (i < n) {
983
+ if (this.#unicodeLeft > 0) {
984
+ const digit = hexValue(chunk.charCodeAt(i));
985
+ if (digit < 0) this.#fail();
986
+ this.#unicodeValue = this.#unicodeValue * 16 + digit;
987
+ this.#unicodeLeft -= 1;
988
+ i += 1;
989
+ if (this.#unicodeLeft === 0) this.#append(String.fromCharCode(this.#unicodeValue));
990
+ continue;
991
+ }
992
+ if (this.#escape) {
993
+ this.#escape = false;
994
+ const c2 = chunk[i] ?? "";
995
+ i += 1;
996
+ switch (c2) {
997
+ case '"':
998
+ case "\\":
999
+ case "/":
1000
+ this.#append(c2);
1001
+ break;
1002
+ case "b":
1003
+ this.#append("\b");
1004
+ break;
1005
+ case "f":
1006
+ this.#append("\f");
1007
+ break;
1008
+ case "n":
1009
+ this.#append("\n");
1010
+ break;
1011
+ case "r":
1012
+ this.#append("\r");
1013
+ break;
1014
+ case "t":
1015
+ this.#append(" ");
1016
+ break;
1017
+ case "u":
1018
+ this.#unicodeLeft = 4;
1019
+ this.#unicodeValue = 0;
1020
+ break;
1021
+ default:
1022
+ this.#fail();
1023
+ }
1024
+ continue;
1025
+ }
1026
+ const runStart = i;
1027
+ while (i < n) {
1028
+ const c2 = chunk.charCodeAt(i);
1029
+ if (c2 === 34 || c2 === 92 || c2 < 32) break;
1030
+ i += 1;
1031
+ }
1032
+ if (i > runStart) this.#append(chunk.slice(runStart, i));
1033
+ if (i >= n) break;
1034
+ const c = chunk.charCodeAt(i);
1035
+ i += 1;
1036
+ if (c === 92) {
1037
+ this.#escape = true;
1038
+ } else if (c === 34) {
1039
+ this.#inString = false;
1040
+ this.#endString();
1041
+ return i;
1042
+ } else {
1043
+ this.#fail();
1044
+ }
1045
+ }
1046
+ return i;
1047
+ }
1048
+ #endString() {
1049
+ if (this.#stringIsKey) {
1050
+ const parent = this.#top();
1051
+ if (parent === void 0) this.#fail();
1052
+ parent.key = this.#key;
1053
+ parent.skipValue = this.#keyOverflow;
1054
+ this.#key = "";
1055
+ this.#expectKey = false;
1056
+ this.#expectColon = true;
1057
+ return;
1058
+ }
1059
+ this.#strObserver?.onEnd?.(this.#strLength);
1060
+ this.#strObserver = void 0;
1061
+ if (!this.#strRetain) {
1062
+ this.#store(SKIPPED);
1063
+ return;
1064
+ }
1065
+ const cap = this.#strCap;
1066
+ let text = this.#strHead;
1067
+ if (cap !== void 0) {
1068
+ let tail = this.#strTail;
1069
+ if (tail.length > cap) tail = tail.slice(-cap);
1070
+ if (this.#strLength > text.length + tail.length) {
1071
+ if (isHighSurrogate(text.charCodeAt(text.length - 1))) text = text.slice(0, -1);
1072
+ if (isLowSurrogate(tail.charCodeAt(0))) tail = tail.slice(1);
1073
+ const omitted = this.#strLength - text.length - tail.length;
1074
+ text = `${text}
1075
+ [\u2026 ${omitted} chars omitted \u2026]
1076
+ ${tail}`;
1077
+ } else {
1078
+ text = `${text}${tail}`;
1079
+ }
1080
+ this.#charge(text.length);
1081
+ }
1082
+ this.#strHead = "";
1083
+ this.#strTail = "";
1084
+ this.#store(text);
1085
+ }
1086
+ #finishBare() {
1087
+ const text = this.#bare;
1088
+ this.#bare = "";
1089
+ const { mode, path } = this.#childMode(false);
1090
+ let value;
1091
+ if (text === "true") value = true;
1092
+ else if (text === "false") value = false;
1093
+ else if (text === "null") value = null;
1094
+ else if (NUMBER_PATTERN.test(text)) value = Number(text);
1095
+ else this.#fail();
1096
+ const observer = this.#fields.find(
1097
+ (field) => field.path.length === path.length && matchesPrefix(field.path, path, path.length)
1098
+ );
1099
+ if (observer?.onScalar !== void 0) {
1100
+ observer.onScalar(value);
1101
+ this.#store(SKIPPED);
1102
+ } else this.#store(mode === "keep" ? value : SKIPPED);
1103
+ }
658
1104
  };
659
- function buildCodexSpawnEnv(input) {
660
- const { HOME: _instanceHome, ...instanceTable } = input.recipe.environment;
661
- return mergeLaunchEnv({
662
- accountHome: input.layout.effectiveHomePath !== void 0 ? { CODEX_HOME: input.layout.effectiveHomePath } : {},
663
- instanceTable,
664
- handOverrides: input.crushApiKeys ? CRUSHED_API_KEYS : {}
665
- });
666
- }
667
- function nativeLoginSpawnEnv(processEnv, isolatedHome) {
668
- return mergeLaunchEnv({
669
- inherited: processEnv,
670
- handOverrides: { ...CRUSHED_API_KEYS, CODEX_HOME: isolatedHome }
671
- });
672
- }
673
- function shouldCrushApiKeys(authMode) {
674
- return authMode === "chatgpt";
675
- }
676
-
677
- // src/appServerLaunch.ts
678
- function throwIfCodexSpawnControlled(error) {
679
- if (error instanceof ExecutorSpawnRefusedError || error instanceof ExecutorSpawnAbortedError) {
1105
+ var SKIPPED = /* @__PURE__ */ Symbol("skipped");
1106
+ var MalformedRecord = class extends Error {
1107
+ };
1108
+ function isBareChar(c) {
1109
+ return c >= 48 && c <= 57 || // 0-9
1110
+ c >= 97 && c <= 122 || // a-z
1111
+ c >= 65 && c <= 90 || // A-Z
1112
+ c === 43 || c === 45 || c === 46;
1113
+ }
1114
+ function hexValue(c) {
1115
+ if (c >= 48 && c <= 57) return c - 48;
1116
+ if (c >= 97 && c <= 102) return c - 97 + 10;
1117
+ if (c >= 65 && c <= 70) return c - 65 + 10;
1118
+ return -1;
1119
+ }
1120
+ var isHighSurrogate = (c) => c >= 55296 && c <= 56319;
1121
+ var isLowSurrogate = (c) => c >= 56320 && c <= 57343;
1122
+ function matchesPrefix(pattern, path, length) {
1123
+ for (let index = 0; index < length; index += 1) {
1124
+ const expected = pattern[index];
1125
+ if (expected !== "*" && expected !== path[index]) return false;
1126
+ }
1127
+ return true;
1128
+ }
1129
+
1130
+ // ../../packages/ycodium-jsonl-stream/src/historyRecord.ts
1131
+ var textFields = (paths, accept) => {
1132
+ let completed = 0;
1133
+ let started = false;
1134
+ const begin = () => {
1135
+ if (started) return;
1136
+ if (completed > 0) accept("\n");
1137
+ started = true;
1138
+ };
1139
+ return paths.map((path) => ({
1140
+ path,
1141
+ scalarOnly: true,
1142
+ onChunk: (text) => {
1143
+ begin();
1144
+ accept(text);
1145
+ },
1146
+ onEnd: () => {
1147
+ begin();
1148
+ completed += 1;
1149
+ started = false;
1150
+ }
1151
+ }));
1152
+ };
1153
+ var createHistoryRecordAccumulator = (layout) => {
1154
+ const selected = layout();
1155
+ let rawTotal = 0;
1156
+ let messageTotal = 0;
1157
+ const hash = NodeCrypto2.createHash("sha256");
1158
+ const decoder = new TextDecoder("utf-8", { fatal: true });
1159
+ const parser = new OversizedRecordParser(
1160
+ [
1161
+ ...selected.fields,
1162
+ ...textFields(selected.textPaths, (text) => {
1163
+ messageTotal += text.length;
1164
+ })
1165
+ ],
1166
+ Number.MAX_SAFE_INTEGER,
1167
+ { pruneEmpty: true }
1168
+ );
1169
+ const accept = (text) => {
1170
+ rawTotal += text.length;
1171
+ parser.write(text);
1172
+ };
1173
+ return {
1174
+ write: (bytes) => {
1175
+ hash.update(bytes);
1176
+ accept(decoder.decode(bytes, { stream: true }));
1177
+ },
1178
+ finish: (range) => {
1179
+ accept(decoder.decode());
1180
+ const metadata = parser.finish();
1181
+ if (metadata === void 0) {
1182
+ if (!range.terminated) return void 0;
1183
+ throw new SyntaxError("Malformed complete native history record.");
1184
+ }
1185
+ return {
1186
+ range,
1187
+ hash: hash.digest("hex"),
1188
+ rawTotal,
1189
+ messageTotal,
1190
+ items: selected.describe(metadata).map(
1191
+ (item) => item.text === "message" && messageTotal === 0 ? { ...item, text: "raw" } : item
1192
+ )
1193
+ };
1194
+ }
1195
+ };
1196
+ };
1197
+ var inspectHistoryRecord = async (path, range, layout, signal) => {
1198
+ const accumulator = createHistoryRecordAccumulator(layout);
1199
+ try {
1200
+ for await (const bytes of historyBytes(path, range.start, range.end, signal))
1201
+ accumulator.write(bytes);
1202
+ return accumulator.finish(range);
1203
+ } catch (error) {
1204
+ if (!range.terminated && error instanceof TypeError) return void 0;
680
1205
  throw error;
681
1206
  }
682
- }
683
- async function spawnCodexAppServer(input) {
684
- await materializeCodexShadowHome(input.layout, input.host.log);
685
- throwIfExecutorSpawnAborted(input.signal);
686
- const env = input.env ?? buildCodexSpawnEnv({
687
- recipe: input.recipe,
688
- layout: input.layout,
689
- crushApiKeys: shouldCrushApiKeys(input.recipe.authMode)
1207
+ };
1208
+ async function* historyRecordWindows(path, info, mode, from, until, limit, layout, signal) {
1209
+ let seen = 0;
1210
+ let offset = from;
1211
+ let pending2 = "";
1212
+ const ready = [];
1213
+ const accept = (text) => {
1214
+ const begin = Math.max(0, from - seen);
1215
+ const end = Math.min(text.length, until - seen);
1216
+ seen += text.length;
1217
+ if (end > begin) pending2 += text.slice(begin, end);
1218
+ while (pending2.length >= limit) {
1219
+ let size = limit;
1220
+ const code = pending2.charCodeAt(size - 1);
1221
+ if (code >= 55296 && code <= 56319) size -= 1;
1222
+ ready.push({ offset, text: pending2.slice(0, size) });
1223
+ pending2 = pending2.slice(size);
1224
+ offset += size;
1225
+ }
1226
+ };
1227
+ const selected = layout();
1228
+ const parser = mode === "raw" ? void 0 : new OversizedRecordParser(textFields(selected.textPaths, accept), Number.MAX_SAFE_INTEGER, {
1229
+ pruneEmpty: true
690
1230
  });
691
- const args = input.args ?? codexSpawnArgs(input.recipe, input.layout);
692
- const handle = await input.host.process.spawn({
693
- program: input.recipe.binaryPath,
694
- args,
695
- owner: { bindingId: input.host.bindingId },
696
- ...input.cwd === void 0 ? {} : { cwd: input.cwd },
697
- ...input.env !== void 0 || Object.keys(env).length > 0 ? { env } : {},
698
- ...input.signal === void 0 ? {} : { signal: input.signal }
1231
+ for await (const text of historyText(path, info.range, signal)) {
1232
+ if (parser === void 0) accept(text);
1233
+ else parser.write(text);
1234
+ while (ready.length > 0) yield ready.shift();
1235
+ if (seen >= until) break;
1236
+ }
1237
+ if (pending2) yield { offset, text: pending2 };
1238
+ }
1239
+ var verifyHistoryRecord = async (path, range, layout, signal) => {
1240
+ const selected = layout();
1241
+ const parser = new OversizedRecordParser(selected.fields, Number.MAX_SAFE_INTEGER, {
1242
+ pruneEmpty: true
699
1243
  });
700
- return { handle, args };
701
- }
702
-
703
- // src/cliVersion.ts
704
- var CODEX_VERSION_TIMEOUT_MS = 15e3;
705
- var VERSION_PATTERN = /(?<![\d.])(\d+\.\d+\.\d+(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?)/;
706
- async function collect(stream) {
707
- const chunks = [];
708
- for await (const chunk of stream) {
709
- chunks.push(Buffer.from(chunk));
710
- if (Buffer.concat(chunks).length > 64 * 1024) break;
711
- }
712
- return Buffer.concat(chunks).toString("utf8");
713
- }
714
- async function readCodexCliVersion(input) {
715
- if (input.recipe.binaryPath.length === 0) return null;
716
- let handle;
717
1244
  try {
718
- handle = await input.host.process.spawn({
719
- program: input.recipe.binaryPath,
720
- args: ["--version"],
721
- owner: { bindingId: input.host.bindingId }
722
- });
723
- } catch {
724
- return null;
1245
+ for await (const text of historyText(path, range, signal)) parser.write(text);
1246
+ } catch (error) {
1247
+ if (!range.terminated && error instanceof TypeError) return false;
1248
+ throw error;
725
1249
  }
726
- const collected = Promise.all([collect(handle.stdout), collect(handle.stderr), handle.exited]);
727
- let timer;
728
- const timeout = new Promise((resolve2) => {
729
- timer = setTimeout(() => resolve2("timeout"), CODEX_VERSION_TIMEOUT_MS);
730
- timer.unref?.();
731
- });
1250
+ const metadata = parser.finish();
1251
+ if (metadata === void 0 && range.terminated)
1252
+ throw new SyntaxError("Malformed complete native history record.");
1253
+ return selected.verify(metadata);
1254
+ };
1255
+
1256
+ // ../../packages/ycodium-jsonl-stream/src/history.ts
1257
+ var RECORD_CACHE_LIMIT = 32;
1258
+ var TEXT_CACHE_CHARS = 262144;
1259
+ var recordCache = /* @__PURE__ */ new Map();
1260
+ var headCache = /* @__PURE__ */ new Map();
1261
+ var cacheKey = (path, identity) => `${path}\0${identity.identity}\0${identity.size}\0${identity.mtimeMs}\0${identity.ctimeMs}`;
1262
+ var remember = (cache, key, value, limit = RECORD_CACHE_LIMIT) => {
1263
+ cache.delete(key);
1264
+ cache.set(key, value);
1265
+ if (cache.size > limit) cache.delete(cache.keys().next().value);
1266
+ return value;
1267
+ };
1268
+ var encode = (position) => Buffer.from(JSON.stringify(position)).toString("base64url");
1269
+ var decode = (value) => {
1270
+ let p;
732
1271
  try {
733
- const settled = await Promise.race([collected, timeout]);
734
- if (settled === "timeout") {
735
- collected.catch(() => void 0);
736
- return null;
737
- }
738
- const [stdout, stderr, exitCode] = settled;
739
- if (exitCode !== 0) return null;
740
- return VERSION_PATTERN.exec(`${stdout}
741
- ${stderr}`)?.[1] ?? null;
1272
+ p = JSON.parse(Buffer.from(value, "base64url").toString("utf8"));
742
1273
  } catch {
743
- return null;
744
- } finally {
745
- if (timer !== void 0) clearTimeout(timer);
746
- await handle.kill("SIGTERM").catch(() => void 0);
1274
+ throw new NativeHistoryCursorError();
747
1275
  }
1276
+ if (!p || typeof p.e !== "string" || typeof p.h !== "string" || ![p.p, p.k, p.o].every((n) => typeof n === "number" && Number.isSafeInteger(n) && n >= 0))
1277
+ throw new NativeHistoryCursorError();
1278
+ return p;
1279
+ };
1280
+ var width = (n) => String(n).padStart(20, "0");
1281
+ var high = (n) => n >= 55296 && n <= 56319;
1282
+ var low = (n) => n >= 56320 && n <= 57343;
1283
+ var totalOf = (info, index) => info.items[index].text === "raw" ? info.rawTotal : info.messageTotal;
1284
+ var nativeItem = (identity, info, index, offset, text) => {
1285
+ const { text: _mode, ...item } = info.items[index];
1286
+ const total = totalOf(info, index);
1287
+ const position = { e: identity, p: info.range.start, k: index, h: info.hash };
1288
+ return {
1289
+ ...item,
1290
+ id: `${identity}:${info.range.start}:${index}`,
1291
+ orderKey: `${width(info.range.start)}:${width(index)}`,
1292
+ beforeCursor: encode({ ...position, o: offset }),
1293
+ afterCursor: encode({ ...position, o: offset + text.length }),
1294
+ text,
1295
+ textWindow: {
1296
+ offset,
1297
+ returned: text.length,
1298
+ total,
1299
+ nextOffset: offset + text.length < total ? offset + text.length : null
1300
+ }
1301
+ };
1302
+ };
1303
+ var readWindow = async (path, info, index, from, until, layout, signal, cached) => {
1304
+ const base = Math.max(0, from - 1);
1305
+ const end = Math.min(totalOf(info, index), until + 1);
1306
+ const mode = info.items[index].text;
1307
+ if (cached.text === void 0 && totalOf(info, index) <= TEXT_CACHE_CHARS) {
1308
+ const parts = [];
1309
+ for await (const window of historyRecordWindows(
1310
+ path,
1311
+ info,
1312
+ mode,
1313
+ 0,
1314
+ totalOf(info, index),
1315
+ 65536,
1316
+ layout,
1317
+ signal
1318
+ ))
1319
+ parts.push(window.text);
1320
+ cached.text = parts.join("");
1321
+ cached.mode = mode;
1322
+ }
1323
+ let text = cached.mode === mode ? cached.text?.slice(base, end) ?? "" : "";
1324
+ if (cached.mode !== mode) {
1325
+ for await (const window of historyRecordWindows(
1326
+ path,
1327
+ info,
1328
+ mode,
1329
+ base,
1330
+ end,
1331
+ Math.max(2, end - base),
1332
+ layout,
1333
+ signal
1334
+ ))
1335
+ text += window.text;
1336
+ }
1337
+ let startIndex = from - base;
1338
+ let endIndex = until - base;
1339
+ if (low(text.charCodeAt(startIndex)) && high(text.charCodeAt(startIndex - 1))) startIndex -= 1;
1340
+ if (low(text.charCodeAt(endIndex)) && high(text.charCodeAt(endIndex - 1))) endIndex -= 1;
1341
+ return { offset: base + startIndex, text: text.slice(startIndex, endIndex) };
1342
+ };
1343
+ async function openJsonlHistory(path, layout, signal) {
1344
+ const controller = new AbortController();
1345
+ const combined = (next) => AbortSignal.any([controller.signal, ...signal ? [signal] : [], ...next ? [next] : []]);
1346
+ let verified;
1347
+ const verify = async (readSignal) => {
1348
+ const identity = await historyIdentity(path);
1349
+ if (verified?.identity === identity.identity && verified.size === identity.size && verified.mtimeMs === identity.mtimeMs && verified.ctimeMs === identity.ctimeMs)
1350
+ return identity;
1351
+ let checked = 0;
1352
+ for await (const range of historyLines(path, 0, identity.size, false, readSignal)) {
1353
+ if (await verifyHistoryRecord(path, range, layout, readSignal)) {
1354
+ verified = identity;
1355
+ return identity;
1356
+ }
1357
+ if (++checked >= 100) break;
1358
+ }
1359
+ throw new NativeHistoryPendingError();
1360
+ };
1361
+ await verify(combined());
1362
+ const active = /* @__PURE__ */ new Set();
1363
+ const iterators = /* @__PURE__ */ new Set();
1364
+ const tracked = (promise) => {
1365
+ active.add(promise);
1366
+ void promise.finally(() => active.delete(promise)).catch(() => void 0);
1367
+ return promise;
1368
+ };
1369
+ const inspect = async (range, identity, readSignal) => {
1370
+ const key = `${cacheKey(path, identity)}\0${range.start}`;
1371
+ const cached = recordCache.get(key);
1372
+ if (cached?.info.range.end === range.end) return cached;
1373
+ const info = await inspectHistoryRecord(path, range, layout, readSignal);
1374
+ return info === void 0 ? void 0 : remember(recordCache, key, { info });
1375
+ };
1376
+ const head = async (identity, readSignal) => {
1377
+ const key = cacheKey(path, identity);
1378
+ const saved = headCache.get(key);
1379
+ if (saved !== void 0) return saved;
1380
+ for await (const range of historyLines(path, 0, identity.size, true, readSignal)) {
1381
+ const info = await inspect(range, identity, readSignal);
1382
+ if (info !== void 0)
1383
+ return remember(
1384
+ headCache,
1385
+ key,
1386
+ await historyBoundary(path, identity.identity, range.commit, readSignal)
1387
+ );
1388
+ }
1389
+ return remember(headCache, key, await historyBoundary(path, identity.identity, 0, readSignal));
1390
+ };
1391
+ const page = async (input) => {
1392
+ const readSignal = combined(input.signal);
1393
+ readSignal.throwIfAborted();
1394
+ if (input.before !== void 0 && input.after !== void 0)
1395
+ throw new NativeHistoryCursorError();
1396
+ if (input.fromStart && input.before !== void 0) throw new NativeHistoryCursorError();
1397
+ const identity = await verify(readSignal);
1398
+ const position = input.before !== void 0 ? decode(input.before) : input.after !== void 0 ? decode(input.after) : void 0;
1399
+ if (position !== void 0 && (position.e !== identity.identity || position.p > identity.size))
1400
+ throw new NativeHistoryCursorError();
1401
+ const backwards = input.after === void 0 && input.fromStart !== true;
1402
+ const initialRange = position === void 0 ? void 0 : await (async () => {
1403
+ const cached = recordCache.get(`${cacheKey(path, identity)}\0${position.p}`);
1404
+ if (cached !== void 0) return cached.info.range;
1405
+ for await (const range of historyLines(
1406
+ path,
1407
+ position.p,
1408
+ identity.size,
1409
+ false,
1410
+ readSignal
1411
+ ))
1412
+ return range;
1413
+ throw new NativeHistoryCursorError();
1414
+ })();
1415
+ const ranges = async function* () {
1416
+ if (initialRange !== void 0) yield initialRange;
1417
+ yield* backwards ? historyLines(path, 0, position?.p ?? identity.size, true, readSignal) : historyLines(path, initialRange?.commit ?? 0, identity.size, false, readSignal);
1418
+ };
1419
+ const items = [];
1420
+ let budget = Math.min(12e3, input.textLimit ?? 12e3);
1421
+ const limit = Math.min(50, input.limit ?? 20);
1422
+ let more = false;
1423
+ for await (const range of ranges()) {
1424
+ if (items.length >= limit || budget < 2) {
1425
+ more = true;
1426
+ break;
1427
+ }
1428
+ const cached = await inspect(range, identity, readSignal);
1429
+ if (cached === void 0) continue;
1430
+ const info = cached.info;
1431
+ const first = position !== void 0 && range.start === position.p;
1432
+ if (first && (position.h !== info.hash || position.k >= info.items.length || position.o > totalOf(info, position.k)))
1433
+ throw new NativeHistoryCursorError();
1434
+ const indices = Array.from({ length: info.items.length }, (_, index) => index);
1435
+ if (backwards) indices.reverse();
1436
+ for (const index of indices) {
1437
+ if (first && (backwards ? index > position.k : index < position.k)) continue;
1438
+ const total = totalOf(info, index);
1439
+ if (first && index === position.k && total === 0) continue;
1440
+ const boundary = first && index === position.k ? position.o : backwards ? total : 0;
1441
+ if (total > 0 && (backwards ? boundary === 0 : boundary === total)) continue;
1442
+ if (items.length >= limit || budget < 2) {
1443
+ more = true;
1444
+ break;
1445
+ }
1446
+ const from = backwards ? Math.max(0, boundary - budget) : boundary;
1447
+ const until = backwards ? boundary : Math.min(total, from + budget);
1448
+ const window = await readWindow(path, info, index, from, until, layout, readSignal, cached);
1449
+ const item = nativeItem(identity.identity, info, index, window.offset, window.text);
1450
+ if (backwards) items.unshift(item);
1451
+ else items.push(item);
1452
+ budget -= window.text.length;
1453
+ if (backwards ? window.offset > 0 : window.offset + window.text.length < total) {
1454
+ more = true;
1455
+ break;
1456
+ }
1457
+ }
1458
+ if (more) break;
1459
+ }
1460
+ const liveCursor = await head(identity, readSignal);
1461
+ return {
1462
+ sourceEpoch: identity.identity,
1463
+ items,
1464
+ olderCursor: items.length === 0 ? null : backwards && !more && position === void 0 ? null : items[0].beforeCursor,
1465
+ newerCursor: items.length === 0 ? null : !backwards && !more ? null : backwards ? input.before !== void 0 ? items.at(-1).afterCursor : null : more ? items.at(-1).afterCursor : null,
1466
+ liveCursor
1467
+ };
1468
+ };
1469
+ const follow = (input) => {
1470
+ let iterator;
1471
+ iterator = (async function* () {
1472
+ const readSignal = combined(input.signal);
1473
+ let dirty = true;
1474
+ let wake;
1475
+ let failure;
1476
+ const notify = () => {
1477
+ dirty = true;
1478
+ wake?.();
1479
+ wake = void 0;
1480
+ };
1481
+ const watcher = NodeFS4.watch(
1482
+ NodePath5.dirname(path),
1483
+ { signal: readSignal },
1484
+ (_event, file) => {
1485
+ if (file == null || String(file) === NodePath5.basename(path)) notify();
1486
+ }
1487
+ );
1488
+ watcher.on("error", (error) => {
1489
+ failure = error;
1490
+ notify();
1491
+ });
1492
+ const abort = () => notify();
1493
+ readSignal.addEventListener("abort", abort, { once: true });
1494
+ let committed = input.after;
1495
+ const reset = async () => page({
1496
+ ...input.limit === void 0 ? {} : { limit: input.limit },
1497
+ ...input.textLimit === void 0 ? {} : { textLimit: input.textLimit },
1498
+ signal: readSignal
1499
+ });
1500
+ try {
1501
+ let identity = await verify(readSignal);
1502
+ const boundary = committed !== void 0 && committed.sequence <= identity.size ? await historyBoundary(path, identity.identity, committed.sequence, readSignal) : void 0;
1503
+ if (committed === void 0 || boundary?.epoch !== committed.epoch || identity.size - committed.sequence > 1048576) {
1504
+ const value = await reset();
1505
+ committed = value.liveCursor;
1506
+ yield { _tag: "snapshot", cursor: committed, value };
1507
+ }
1508
+ let synchronized = false;
1509
+ let scanned = committed.sequence;
1510
+ let pendingStart = scanned;
1511
+ let accumulator = createHistoryRecordAccumulator(layout);
1512
+ const appended = async function* (end) {
1513
+ for await (const bytes of historyBytes(path, scanned, end, readSignal)) {
1514
+ let from = 0;
1515
+ const chunkStart = scanned;
1516
+ for (let index = 0; index < bytes.length; index += 1) {
1517
+ if (bytes[index] !== 10) continue;
1518
+ accumulator.write(bytes.subarray(from, index));
1519
+ const at = chunkStart + index;
1520
+ const info = at > pendingStart ? accumulator.finish({
1521
+ start: pendingStart,
1522
+ end: at,
1523
+ commit: at + 1,
1524
+ terminated: true
1525
+ }) : void 0;
1526
+ pendingStart = at + 1;
1527
+ accumulator = createHistoryRecordAccumulator(layout);
1528
+ from = index + 1;
1529
+ if (info !== void 0) yield info;
1530
+ }
1531
+ accumulator.write(bytes.subarray(from));
1532
+ scanned += bytes.length;
1533
+ }
1534
+ };
1535
+ while (true) {
1536
+ readSignal.throwIfAborted();
1537
+ if (failure !== void 0) throw failure;
1538
+ if (!dirty)
1539
+ await new Promise((resolve4) => {
1540
+ wake = resolve4;
1541
+ });
1542
+ readSignal.throwIfAborted();
1543
+ dirty = false;
1544
+ identity = await historyIdentity(path);
1545
+ const current = committed;
1546
+ const valid = scanned <= identity.size && current.sequence <= identity.size && (await historyBoundary(path, identity.identity, current.sequence, readSignal)).epoch === current.epoch;
1547
+ if (!valid) {
1548
+ const value = await reset();
1549
+ synchronized = false;
1550
+ committed = value.liveCursor;
1551
+ scanned = committed.sequence;
1552
+ pendingStart = scanned;
1553
+ accumulator = createHistoryRecordAccumulator(layout);
1554
+ yield { _tag: "snapshot", cursor: committed, value };
1555
+ } else {
1556
+ for await (const info of appended(identity.size)) {
1557
+ const next = await historyBoundary(
1558
+ path,
1559
+ identity.identity,
1560
+ info.range.commit,
1561
+ readSignal
1562
+ );
1563
+ for (let index = 0; index < info.items.length; index += 1) {
1564
+ const total = totalOf(info, index);
1565
+ if (total === 0) {
1566
+ yield {
1567
+ _tag: "delta",
1568
+ cursor: index === info.items.length - 1 ? next : committed,
1569
+ items: [nativeItem(identity.identity, info, index, 0, "")]
1570
+ };
1571
+ continue;
1572
+ }
1573
+ for await (const window of historyRecordWindows(
1574
+ path,
1575
+ info,
1576
+ info.items[index].text,
1577
+ 0,
1578
+ total,
1579
+ Math.min(12e3, input.textLimit ?? 12e3),
1580
+ layout,
1581
+ readSignal
1582
+ )) {
1583
+ const done = index === info.items.length - 1 && window.offset + window.text.length === total;
1584
+ yield {
1585
+ _tag: "delta",
1586
+ cursor: done ? next : committed,
1587
+ items: [nativeItem(identity.identity, info, index, window.offset, window.text)]
1588
+ };
1589
+ }
1590
+ }
1591
+ committed = next;
1592
+ }
1593
+ }
1594
+ if (!synchronized) {
1595
+ synchronized = true;
1596
+ yield { _tag: "synchronized" };
1597
+ }
1598
+ }
1599
+ } finally {
1600
+ watcher.close();
1601
+ readSignal.removeEventListener("abort", abort);
1602
+ wake?.();
1603
+ if (iterator !== void 0) iterators.delete(iterator);
1604
+ }
1605
+ })();
1606
+ iterators.add(iterator);
1607
+ return iterator;
1608
+ };
1609
+ return {
1610
+ page: (input) => tracked(page(input)),
1611
+ follow,
1612
+ close: async () => {
1613
+ controller.abort();
1614
+ await Promise.all([...iterators].map((iterator) => iterator.return(void 0)));
1615
+ await Promise.allSettled(active);
1616
+ }
1617
+ };
748
1618
  }
749
1619
 
750
- // src/failureCategory.ts
751
- var codexProcessExitCategory = (session) => session !== void 0 && !session.stopRequested && typeof session.nativeThreadId === "string" && session.nativeThreadId.length > 0 ? "transport" : void 0;
752
-
753
1620
  // src/protocol.ts
754
1621
  var CODEX_INITIALIZE_PARAMS = {
755
1622
  clientInfo: { name: "ycodium", title: "Ycodium", version: "0" },
@@ -870,7 +1737,7 @@ function codexCollaborationMode(input) {
870
1737
  }
871
1738
  };
872
1739
  }
873
- function isRecord3(value) {
1740
+ function isRecord2(value) {
874
1741
  return typeof value === "object" && value !== null && !Array.isArray(value);
875
1742
  }
876
1743
  function asString(value) {
@@ -885,11 +1752,11 @@ function asNumber(value) {
885
1752
  return typeof value === "number" && Number.isFinite(value) ? value : null;
886
1753
  }
887
1754
  function codexVersionFromInitialize(initializeResult) {
888
- const userAgent = isRecord3(initializeResult) ? asString(initializeResult["userAgent"]) : null;
1755
+ const userAgent = isRecord2(initializeResult) ? asString(initializeResult["userAgent"]) : null;
889
1756
  return userAgent?.match(/\/(\S+)/)?.[1] ?? null;
890
1757
  }
891
1758
  function decodeThreadOpen(result) {
892
- const thread = isRecord3(result) ? isRecord3(result["thread"]) ? result["thread"] : result : null;
1759
+ const thread = isRecord2(result) ? isRecord2(result["thread"]) ? result["thread"] : result : null;
893
1760
  const id = thread ? asString(thread["id"]) : null;
894
1761
  if (!id) throw new Error("codex thread/start|resume returned no thread id");
895
1762
  return {
@@ -899,22 +1766,22 @@ function decodeThreadOpen(result) {
899
1766
  };
900
1767
  }
901
1768
  function decodeTurnStart(result) {
902
- const turn = isRecord3(result) ? isRecord3(result["turn"]) ? result["turn"] : result : null;
1769
+ const turn = isRecord2(result) ? isRecord2(result["turn"]) ? result["turn"] : result : null;
903
1770
  const id = turn ? asString(turn["id"]) : null;
904
1771
  if (!id) throw new Error("codex turn/start returned no turn id");
905
1772
  return { turnId: id };
906
1773
  }
907
1774
  function decodeTurnSteer(result) {
908
- const id = isRecord3(result) ? asString(result["turnId"]) : null;
1775
+ const id = isRecord2(result) ? asString(result["turnId"]) : null;
909
1776
  if (!id) throw new Error("codex turn/steer returned no turn id");
910
1777
  return { turnId: id };
911
1778
  }
912
1779
  function inProgressTurnIdFromThreadRead(result) {
913
- if (!isRecord3(result)) return void 0;
914
- const thread = isRecord3(result["thread"]) ? result["thread"] : result;
1780
+ if (!isRecord2(result)) return void 0;
1781
+ const thread = isRecord2(result["thread"]) ? result["thread"] : result;
915
1782
  const turns = Array.isArray(thread["turns"]) ? thread["turns"] : [];
916
1783
  for (const turn of turns) {
917
- if (!isRecord3(turn)) continue;
1784
+ if (!isRecord2(turn)) continue;
918
1785
  const status = asString(turn["status"]);
919
1786
  if (status === "inProgress" || status === "in_progress" || status === "active") {
920
1787
  return asString(turn["id"]) ?? void 0;
@@ -997,28 +1864,643 @@ function isMemoryConsolidationThread(name) {
997
1864
  return (name ?? "").toLowerCase().includes(MEMORY_CONSOLIDATION_NAME);
998
1865
  }
999
1866
  function parseCodexResumeCursor(value) {
1000
- if (!isRecord3(value)) return void 0;
1867
+ if (!isRecord2(value)) return void 0;
1001
1868
  const threadId = asString(value["threadId"])?.trim();
1002
1869
  return threadId ? { threadId } : void 0;
1003
1870
  }
1004
1871
  function conversationIdFromNotification(params) {
1005
- if (!isRecord3(params)) return void 0;
1006
- return asString(params["threadId"]) ?? asString(params["conversationId"]) ?? (isRecord3(params["thread"]) ? asString(params["thread"]["id"]) : null) ?? (isRecord3(params["turn"]) ? asString(params["turn"]["threadId"]) : null) ?? void 0;
1872
+ if (!isRecord2(params)) return void 0;
1873
+ return asString(params["threadId"]) ?? asString(params["conversationId"]) ?? (isRecord2(params["thread"]) ? asString(params["thread"]["id"]) : null) ?? (isRecord2(params["turn"]) ? asString(params["turn"]["threadId"]) : null) ?? void 0;
1007
1874
  }
1008
1875
  function itemTypeOf(params) {
1009
- if (!isRecord3(params)) return void 0;
1010
- const item = isRecord3(params["item"]) ? params["item"] : params;
1876
+ if (!isRecord2(params)) return void 0;
1877
+ const item = isRecord2(params["item"]) ? params["item"] : params;
1011
1878
  return asString(item["type"]) ?? asString(item["itemType"]) ?? void 0;
1012
1879
  }
1013
- function jsonRpcErrorMessage(error) {
1014
- if (isRecord3(error) && typeof error["message"] === "string") return error["message"];
1880
+ function jsonRpcErrorMessage(error) {
1881
+ if (isRecord2(error) && typeof error["message"] === "string") return error["message"];
1882
+ try {
1883
+ return JSON.stringify(error);
1884
+ } catch {
1885
+ return String(error);
1886
+ }
1887
+ }
1888
+
1889
+ // src/sessions.ts
1890
+ import * as NodeFS5 from "node:fs";
1891
+ import * as NodePath6 from "node:path";
1892
+ import * as NodeReadline from "node:readline";
1893
+ var EXTENDED_LENGTH_UNC = "//?/UNC/";
1894
+ var EXTENDED_LENGTH = "//?/";
1895
+ function normalize(value, caseInsensitive) {
1896
+ let unified = value.trim().replace(/\\/gu, "/");
1897
+ const upper = unified.toUpperCase();
1898
+ if (upper.startsWith(EXTENDED_LENGTH_UNC)) {
1899
+ unified = `//${unified.slice(EXTENDED_LENGTH_UNC.length)}`;
1900
+ } else if (upper.startsWith(EXTENDED_LENGTH)) {
1901
+ unified = unified.slice(EXTENDED_LENGTH.length);
1902
+ }
1903
+ const isUnc = unified.startsWith("//");
1904
+ unified = unified.replace(/\/+/gu, "/").replace(/\/+$/u, "");
1905
+ if (isUnc) unified = `/${unified}`;
1906
+ return caseInsensitive ? unified.toLowerCase() : unified;
1907
+ }
1908
+ function isWithinDirectory(candidate, root, caseInsensitive) {
1909
+ const normalizedRoot = normalize(root, caseInsensitive);
1910
+ if (normalizedRoot.length === 0 || normalizedRoot === "/") return false;
1911
+ const normalizedCandidate = normalize(candidate, caseInsensitive);
1912
+ return normalizedCandidate === normalizedRoot || normalizedCandidate.startsWith(`${normalizedRoot}/`);
1913
+ }
1914
+ var PAGE_LIMIT = 50;
1915
+ var MAX_PAGES = 10;
1916
+ var MAX_ROWS = 50;
1917
+ var PREVIEW_LIMIT = 200;
1918
+ function truncate(value) {
1919
+ const trimmed = value?.trim() ?? "";
1920
+ if (trimmed.length === 0) return null;
1921
+ return trimmed.length <= PREVIEW_LIMIT ? trimmed : `${trimmed.slice(0, PREVIEW_LIMIT)}\u2026`;
1922
+ }
1923
+ var nativeModel = (value) => {
1924
+ const model = asString(value)?.trim();
1925
+ return model && model !== "<synthetic>" ? model : null;
1926
+ };
1927
+ function readListPage(response) {
1928
+ if (!response || typeof response !== "object") return { threads: [], nextCursor: null };
1929
+ const typed = response;
1930
+ const rows = Array.isArray(typed.data) ? typed.data : [];
1931
+ const threads = [];
1932
+ for (const row of rows) {
1933
+ if (!isRecord2(row)) continue;
1934
+ if (typeof row.id !== "string" || typeof row.cwd !== "string") continue;
1935
+ threads.push({
1936
+ id: row.id,
1937
+ cwd: row.cwd,
1938
+ name: asString(row.name),
1939
+ preview: asString(row.preview),
1940
+ model: asString(row.model),
1941
+ updatedAt: typeof row.updatedAt === "number" ? row.updatedAt : 0
1942
+ });
1943
+ }
1944
+ return { threads, nextCursor: asString(typed.nextCursor) };
1945
+ }
1946
+ function readThreadTurns(response) {
1947
+ if (!isRecord2(response)) return [];
1948
+ const thread = isRecord2(response.thread) ? response.thread : null;
1949
+ if (!thread) return [];
1950
+ const turns = Array.isArray(thread.turns) ? thread.turns : [];
1951
+ return turns.flatMap((turn) => {
1952
+ if (!isRecord2(turn)) return [];
1953
+ return [
1954
+ {
1955
+ ...typeof turn.id === "string" && turn.id.length > 0 ? { id: turn.id } : {},
1956
+ ...typeof turn.model === "string" && turn.model.length > 0 ? { model: turn.model } : {},
1957
+ startedAt: typeof turn.startedAt === "number" ? turn.startedAt : null,
1958
+ items: Array.isArray(turn.items) ? turn.items : []
1959
+ }
1960
+ ];
1961
+ });
1962
+ }
1963
+ function itemText(item) {
1964
+ if (!isRecord2(item)) return void 0;
1965
+ const type = (asString(item.type) ?? "").toLowerCase();
1966
+ const text = asString(item.text) ?? asString(item.content) ?? (Array.isArray(item.content) ? item.content.map((entry) => isRecord2(entry) ? asString(entry.text) : null).filter((entry) => typeof entry === "string").join("\n") : null);
1967
+ if (!text || text.trim().length === 0) return void 0;
1968
+ if (type.includes("user")) return { role: "user", text };
1969
+ if (type.includes("agent") || type.includes("assistant")) return { role: "assistant", text };
1970
+ if (type.includes("system")) return { role: "system", text };
1971
+ return void 0;
1972
+ }
1973
+ async function scanCodexSessions(input) {
1974
+ const threads = [];
1975
+ let cursor = null;
1976
+ for (let page = 0; page < MAX_PAGES && threads.length < MAX_ROWS; page += 1) {
1977
+ const listed = readListPage(
1978
+ await input.client.request("thread/list", {
1979
+ limit: PAGE_LIMIT,
1980
+ sortKey: "updated_at",
1981
+ sortDirection: "desc",
1982
+ ...cursor === null ? {} : { cursor }
1983
+ })
1984
+ );
1985
+ for (const thread of listed.threads) {
1986
+ if (!isWithinDirectory(thread.cwd, input.directory, input.caseInsensitive)) continue;
1987
+ threads.push(thread);
1988
+ if (threads.length >= MAX_ROWS) break;
1989
+ }
1990
+ if (listed.nextCursor === null || listed.nextCursor.length === 0) break;
1991
+ cursor = listed.nextCursor;
1992
+ }
1993
+ const rows = [];
1994
+ for (const thread of threads) {
1995
+ const turnCount = await input.client.request("thread/read", { threadId: thread.id, includeTurns: true }).then((response) => readThreadTurns(response).length).catch(() => 0);
1996
+ rows.push({
1997
+ nativeSessionId: thread.id,
1998
+ cwd: thread.cwd,
1999
+ title: truncate(thread.name),
2000
+ preview: truncate(thread.preview),
2001
+ model: truncate(thread.model),
2002
+ turnCount,
2003
+ updatedAt: thread.updatedAt * 1e3,
2004
+ availability: "importable",
2005
+ openElsewhere: false
2006
+ });
2007
+ }
2008
+ return rows;
2009
+ }
2010
+ async function readCodexSession(input) {
2011
+ const response = await input.client.request("thread/read", {
2012
+ threadId: input.threadId,
2013
+ includeTurns: true
2014
+ });
2015
+ const record = isRecord2(response) ? response : null;
2016
+ const thread = record && isRecord2(record.thread) ? record.thread : null;
2017
+ const path = input.caseInsensitive ? NodePath6.win32 : NodePath6;
2018
+ const sameDirectory = (left, right) => isWithinDirectory(path.resolve(left), path.resolve(right), input.caseInsensitive) && isWithinDirectory(path.resolve(right), path.resolve(left), input.caseInsensitive);
2019
+ if (!isRecord2(thread) || thread.id !== input.threadId || typeof thread.cwd !== "string" || !path.isAbsolute(thread.cwd) || !path.isAbsolute(input.cwd) || !sameDirectory(thread.cwd, input.cwd)) {
2020
+ throw new Error("The native Codex session does not match the requested session and directory.");
2021
+ }
2022
+ const model = nativeModel(thread.model) ?? await readRolloutModel(
2023
+ {
2024
+ threadId: input.threadId,
2025
+ cwd: input.cwd,
2026
+ homePath: input.homePath,
2027
+ caseInsensitive: input.caseInsensitive
2028
+ },
2029
+ thread.path,
2030
+ sameDirectory
2031
+ );
2032
+ const messages = [];
2033
+ for (const turn of readThreadTurns(response)) {
2034
+ for (const item of turn.items) {
2035
+ const mapped = itemText(item);
2036
+ if (mapped) {
2037
+ messages.push({
2038
+ ...mapped,
2039
+ ...typeof turn.startedAt === "number" ? { createdAt: turn.startedAt * 1e3 } : {}
2040
+ });
2041
+ }
2042
+ }
2043
+ }
2044
+ return {
2045
+ nativeSessionId: input.threadId,
2046
+ messages,
2047
+ resumeCursor: { threadId: input.threadId },
2048
+ model
2049
+ };
2050
+ }
2051
+ async function readRolloutModel(input, rolloutPath, sameDirectory) {
2052
+ const path = input.caseInsensitive ? NodePath6.win32 : NodePath6;
2053
+ if (typeof rolloutPath !== "string" || !path.isAbsolute(rolloutPath) || path.extname(rolloutPath).toLowerCase() !== ".jsonl") {
2054
+ return null;
2055
+ }
2056
+ const resolved = path.resolve(rolloutPath);
2057
+ const roots = input.homePath ? [path.join(input.homePath, "sessions"), path.join(input.homePath, "archived_sessions")] : [];
2058
+ if (!roots.some((root) => isWithinDirectory(resolved, path.resolve(root), input.caseInsensitive))) {
2059
+ return null;
2060
+ }
2061
+ let verified = false;
2062
+ let model = null;
2063
+ try {
2064
+ const stream = NodeFS5.createReadStream(resolved, { encoding: "utf8" });
2065
+ const rl = NodeReadline.createInterface({ input: stream, crlfDelay: Infinity });
2066
+ for await (const line of rl) {
2067
+ if (!line.includes('"session_meta"') && !line.includes('"turn_context"')) continue;
2068
+ let record;
2069
+ try {
2070
+ record = isRecord2(JSON.parse(line)) ? JSON.parse(line) : null;
2071
+ } catch {
2072
+ continue;
2073
+ }
2074
+ const payload = isRecord2(record?.payload) ? record.payload : null;
2075
+ if (!record || !payload) continue;
2076
+ if (record.type === "session_meta" && !verified) {
2077
+ if ((payload.id ?? payload.session_id) !== input.threadId || typeof payload.cwd !== "string" || !path.isAbsolute(payload.cwd) || !sameDirectory(payload.cwd, input.cwd)) {
2078
+ return null;
2079
+ }
2080
+ verified = true;
2081
+ } else if (record.type === "turn_context" && verified) {
2082
+ model = nativeModel(payload.model) ?? model;
2083
+ }
2084
+ }
2085
+ } catch {
2086
+ return null;
2087
+ }
2088
+ return model;
2089
+ }
2090
+
2091
+ // src/liveHistory.ts
2092
+ var valueAt = (value, keys) => keys.reduce((next, key) => isRecord2(next) ? next[key] : void 0, value);
2093
+ var fields = [
2094
+ "type",
2095
+ "timestamp",
2096
+ "payload.type",
2097
+ "payload.id",
2098
+ "payload.cwd",
2099
+ "payload.role",
2100
+ "payload.name",
2101
+ "payload.call_id",
2102
+ "payload.truncated",
2103
+ "payload.inputTruncated",
2104
+ "payload.outputTruncated",
2105
+ "payload.source.subagent.thread_spawn.parent_thread_id",
2106
+ "payload.source.subAgent.thread_spawn.parent_thread_id"
2107
+ ].map((path) => ({ path: path.split("."), maxChars: 2048, scalarOnly: true }));
2108
+ var codexHistoryLayout = (input) => () => {
2109
+ let nonText = false;
2110
+ let blockType = "";
2111
+ const verify = (metadata) => {
2112
+ if (!isRecord2(metadata) || metadata.type !== "session_meta") return false;
2113
+ const cwd = valueAt(metadata, ["payload", "cwd"]);
2114
+ const parent = valueAt(metadata, ["payload", "source", "subagent", "thread_spawn", "parent_thread_id"]) ?? valueAt(metadata, ["payload", "source", "subAgent", "thread_spawn", "parent_thread_id"]);
2115
+ if (valueAt(metadata, ["payload", "id"]) !== input.nativeSessionId || parent !== input.parentNativeSessionId || typeof cwd !== "string" || !isWithinDirectory(cwd, input.cwd, NodeProcess.platform === "win32") || !isWithinDirectory(input.cwd, cwd, NodeProcess.platform === "win32"))
2116
+ throw new Error("Native session ownership does not match the recorded agent.");
2117
+ return true;
2118
+ };
2119
+ return {
2120
+ fields: [
2121
+ ...fields,
2122
+ {
2123
+ path: ["payload", "content", "*", "type"],
2124
+ onChunk: (text) => {
2125
+ blockType = (blockType + text).slice(0, 64);
2126
+ },
2127
+ onEnd: () => {
2128
+ nonText ||= !["input_text", "output_text", "text"].includes(blockType);
2129
+ blockType = "";
2130
+ }
2131
+ }
2132
+ ],
2133
+ textPaths: [["payload", "content", "*", "text"]],
2134
+ verify,
2135
+ describe: (metadata) => {
2136
+ if (!isRecord2(metadata) || metadata.type !== "response_item" || !isRecord2(metadata.payload))
2137
+ return [];
2138
+ const item = metadata.payload;
2139
+ const type = typeof item.type === "string" ? item.type : "record";
2140
+ const kind = type === "message" ? "message" : type.endsWith("_call_output") ? "tool_result" : type.endsWith("_call") ? "tool_call" : "record";
2141
+ const role = item.role === "developer" ? "system" : item.role === "user" || item.role === "assistant" || item.role === "system" ? item.role : void 0;
2142
+ return [
2143
+ {
2144
+ kind,
2145
+ text: kind === "message" && !nonText ? "message" : "raw",
2146
+ ...role === void 0 ? {} : { role },
2147
+ ...typeof item.name === "string" ? { name: item.name } : {},
2148
+ ...typeof item.call_id === "string" ? { toolCallId: item.call_id } : {},
2149
+ ...typeof metadata.timestamp === "string" ? { createdAt: metadata.timestamp } : {},
2150
+ ...item.truncated === true || item.inputTruncated === true || item.outputTruncated === true ? { sourceTruncated: true } : {}
2151
+ }
2152
+ ];
2153
+ }
2154
+ };
2155
+ };
2156
+ var findCodexHistory = async (input) => {
2157
+ if (!/^[A-Za-z0-9_-]+$/u.test(input.nativeSessionId))
2158
+ throw new Error("Invalid native session identifier.");
2159
+ for (const directory of ["sessions", "archived_sessions"]) {
2160
+ let entries;
2161
+ try {
2162
+ entries = await NodeFSP4.opendir(NodePath7.join(input.homePath, directory), {
2163
+ recursive: true,
2164
+ bufferSize: 32
2165
+ });
2166
+ } catch (error) {
2167
+ if (isRecord2(error) && error.code === "ENOENT") continue;
2168
+ throw error;
2169
+ }
2170
+ for await (const entry of entries) {
2171
+ input.signal?.throwIfAborted();
2172
+ if (entry.isFile() && entry.name.endsWith(`-${input.nativeSessionId}.jsonl`))
2173
+ return openJsonlHistory(
2174
+ NodePath7.join(entry.parentPath, entry.name),
2175
+ codexHistoryLayout(input),
2176
+ input.signal
2177
+ );
2178
+ }
2179
+ }
2180
+ return void 0;
2181
+ };
2182
+ var openCodexHistory = (input) => waitForJsonlHistory({
2183
+ root: input.homePath,
2184
+ accepts: (path) => path.endsWith(`-${input.nativeSessionId}.jsonl`) || NodePath7.resolve(input.homePath).startsWith(path + NodePath7.sep),
2185
+ open: (signal) => findCodexHistory({ ...input, signal }),
2186
+ ...input.signal === void 0 ? {} : { signal: input.signal }
2187
+ });
2188
+
2189
+ // src/codexInstance.ts
2190
+ import * as NodeProcess2 from "node:process";
2191
+ import {
2192
+ describeExecutorSpawnFailure,
2193
+ ExecutorSpawnRefusedError as ExecutorSpawnRefusedError2,
2194
+ raceAbort as raceAbort2
2195
+ } from "@ycodium-ai/plugin-api/executor";
2196
+
2197
+ // src/appServerLaunch.ts
2198
+ import {
2199
+ ExecutorSpawnAbortedError,
2200
+ ExecutorSpawnRefusedError,
2201
+ throwIfExecutorSpawnAborted
2202
+ } from "@ycodium-ai/plugin-api/executor";
2203
+
2204
+ // src/connection.ts
2205
+ import { mergeLaunchEnv } from "@ycodium-ai/plugin-api/executor";
2206
+
2207
+ // src/config.ts
2208
+ import { modelSelectionStringOption } from "@ycodium-ai/plugin-api/executor";
2209
+
2210
+ // src/apiKeyEnv.ts
2211
+ var CODEX_INSTANCE_API_KEY_ENV = "YCODIUM_CODEX_API_KEY";
2212
+
2213
+ // src/config.ts
2214
+ var CODEX_INSTANCE_MODEL_PROVIDER = "ycodium_api";
2215
+ function isRecord3(value) {
2216
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2217
+ }
2218
+ function readString2(value) {
2219
+ return typeof value === "string" ? value : "";
2220
+ }
2221
+ function readTrimmed(value) {
2222
+ return readString2(value).trim();
2223
+ }
2224
+ function readAuthMode(value) {
2225
+ return value === "chatgpt" || value === "apiKey" ? value : "default";
2226
+ }
2227
+ function readEnvironment(value) {
2228
+ if (!Array.isArray(value)) return {};
2229
+ const env = {};
2230
+ for (const entry of value) {
2231
+ if (!isRecord3(entry)) continue;
2232
+ const name = readTrimmed(entry["name"]);
2233
+ if (name.length === 0) continue;
2234
+ env[name] = readString2(entry["value"]);
2235
+ }
2236
+ return env;
2237
+ }
2238
+ function parseCodexInstanceConfig(config) {
2239
+ if (!isRecord3(config)) {
2240
+ return {
2241
+ binaryPath: "",
2242
+ launchArgs: CODEX_DEFAULT_LAUNCH_ARGS,
2243
+ homePath: "",
2244
+ shadowHomePath: "",
2245
+ homeEnvVar: "",
2246
+ authMode: "default",
2247
+ apiBaseUrl: "",
2248
+ environment: {},
2249
+ envelopeDriver: void 0
2250
+ };
2251
+ }
2252
+ const nested = isRecord3(config["config"]) ? config["config"] : void 0;
2253
+ const settings = nested ?? config;
2254
+ return {
2255
+ binaryPath: readTrimmed(settings["binaryPath"]),
2256
+ launchArgs: readString2(settings["launchArgs"]) || CODEX_DEFAULT_LAUNCH_ARGS,
2257
+ homePath: readTrimmed(settings["homePath"]) || readTrimmed(config["homePath"]),
2258
+ shadowHomePath: readTrimmed(settings["shadowHomePath"]),
2259
+ homeEnvVar: readTrimmed(settings["homeEnvVar"]) || readTrimmed(config["homeEnvVar"]),
2260
+ authMode: readAuthMode(settings["authMode"]),
2261
+ apiBaseUrl: readTrimmed(settings["apiBaseUrl"]),
2262
+ environment: readEnvironment(config["environment"]),
2263
+ envelopeDriver: readTrimmed(config["driver"]) || void 0
2264
+ };
2265
+ }
2266
+ function tokenizeLaunchArgs(value) {
2267
+ const input = value.trim();
2268
+ if (!input) return [];
2269
+ const tokens = [];
2270
+ let current = "";
2271
+ let quote;
2272
+ let quoted = false;
2273
+ for (let index = 0; index < input.length; index++) {
2274
+ const char = input[index];
2275
+ if (char === void 0) continue;
2276
+ if (quote) {
2277
+ if (char === quote) {
2278
+ quote = void 0;
2279
+ quoted = true;
2280
+ } else if (char === "\\" && quote === '"') {
2281
+ const next = input[index + 1];
2282
+ if (next !== void 0 && ['"', "\\", "$", "`"].includes(next)) {
2283
+ current += next;
2284
+ index++;
2285
+ } else {
2286
+ current += char;
2287
+ }
2288
+ } else {
2289
+ current += char;
2290
+ }
2291
+ continue;
2292
+ }
2293
+ if (char === "'" || char === '"') {
2294
+ quote = char;
2295
+ quoted = true;
2296
+ } else if (/\s/.test(char)) {
2297
+ if (current || quoted) {
2298
+ tokens.push(current);
2299
+ current = "";
2300
+ quoted = false;
2301
+ }
2302
+ } else if (char === "\\") {
2303
+ const next = input[index + 1];
2304
+ if (next !== void 0 && /\s/.test(next)) {
2305
+ current += next;
2306
+ index++;
2307
+ } else {
2308
+ current += char;
2309
+ }
2310
+ } else {
2311
+ current += char;
2312
+ }
2313
+ }
2314
+ if (current || quoted) tokens.push(current);
2315
+ return tokens;
2316
+ }
2317
+ function encodeQuotedArgs(args) {
2318
+ return args.map((arg) => `"${arg.replaceAll("\\", "\\\\").replaceAll('"', '\\"')}"`).join(" ");
2319
+ }
2320
+ function codexExecLaunchArgs(launchArgs) {
2321
+ const args = tokenizeLaunchArgs(launchArgs ?? "");
2322
+ const execArgs = [];
2323
+ for (let index = 0; index < args.length; index++) {
2324
+ const arg = args[index];
2325
+ if (arg === void 0) continue;
2326
+ if (arg === "--strict-config" || arg.startsWith("--config=") || arg.startsWith("-c=")) {
2327
+ execArgs.push(arg);
2328
+ } else if (arg === "--config" || arg === "-c" || arg === "--enable" || arg === "--disable") {
2329
+ const value = args[index + 1];
2330
+ if (value !== void 0 && !value.startsWith("-")) {
2331
+ execArgs.push(arg, value);
2332
+ index++;
2333
+ }
2334
+ } else if (arg.startsWith("--enable=") || arg.startsWith("--disable=")) {
2335
+ execArgs.push(arg);
2336
+ }
2337
+ }
2338
+ return execArgs;
2339
+ }
2340
+ function codexMcpThreadConfig(servers) {
2341
+ return {
2342
+ mcp_servers: Object.fromEntries(
2343
+ servers.map(({ name, transport }) => [
2344
+ name,
2345
+ transport.type === "stdio" ? { command: transport.command, args: transport.args ?? [], env: transport.env ?? {} } : { url: transport.url, http_headers: transport.headers ?? {} }
2346
+ ])
2347
+ )
2348
+ };
2349
+ }
2350
+ function modelIdFromSelection(selection) {
2351
+ if (typeof selection !== "object" || selection === null || Array.isArray(selection)) {
2352
+ return void 0;
2353
+ }
2354
+ const model = selection["model"];
2355
+ return typeof model === "string" ? model.trim() || void 0 : void 0;
2356
+ }
2357
+
2358
+ // src/connection.ts
2359
+ function codexApiConnectionError(recipe, environment) {
2360
+ if (recipe.authMode !== "apiKey") return null;
2361
+ try {
2362
+ const url = new URL(recipe.apiBaseUrl);
2363
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
2364
+ return "Codex API base URL must use HTTP or HTTPS.";
2365
+ }
2366
+ } catch {
2367
+ return "Codex API base URL is missing or invalid.";
2368
+ }
2369
+ return environment[CODEX_INSTANCE_API_KEY_ENV]?.trim() ? null : "An API key is required for this Codex account.";
2370
+ }
2371
+ function connectionArgv(recipe, layout) {
2372
+ const args = [...tokenizeLaunchArgs(recipe.launchArgs)];
2373
+ const override = (key, value) => {
2374
+ args.push("-c", `${key}=${JSON.stringify(value)}`);
2375
+ };
2376
+ if (layout.mode === "authOverlay" || recipe.authMode !== "default") {
2377
+ override("sqlite_home", layout.sharedHomePath);
2378
+ }
2379
+ if (layout.mode === "authOverlay") {
2380
+ override("cli_auth_credentials_store", "file");
2381
+ }
2382
+ if (recipe.authMode === "chatgpt") {
2383
+ override("model_provider", "openai");
2384
+ override("forced_login_method", "chatgpt");
2385
+ } else if (recipe.authMode === "apiKey") {
2386
+ override("model_provider", CODEX_INSTANCE_MODEL_PROVIDER);
2387
+ override(`model_providers.${CODEX_INSTANCE_MODEL_PROVIDER}.name`, "Ycodium API");
2388
+ override(`model_providers.${CODEX_INSTANCE_MODEL_PROVIDER}.base_url`, recipe.apiBaseUrl);
2389
+ override(
2390
+ `model_providers.${CODEX_INSTANCE_MODEL_PROVIDER}.env_key`,
2391
+ CODEX_INSTANCE_API_KEY_ENV
2392
+ );
2393
+ override(`model_providers.${CODEX_INSTANCE_MODEL_PROVIDER}.requires_openai_auth`, false);
2394
+ override(`model_providers.${CODEX_INSTANCE_MODEL_PROVIDER}.wire_api`, "responses");
2395
+ }
2396
+ return args;
2397
+ }
2398
+ function codexSpawnArgs(recipe, layout) {
2399
+ const needsOverrides = layout.mode === "authOverlay" || recipe.authMode !== "default";
2400
+ if (!needsOverrides) return tokenizeLaunchArgs(recipe.launchArgs);
2401
+ return connectionArgv(recipe, layout);
2402
+ }
2403
+ function encodeCodexConnectionArgs(recipe, layout) {
2404
+ return encodeQuotedArgs(connectionArgv(recipe, layout));
2405
+ }
2406
+ var CRUSHED_API_KEYS = {
2407
+ OPENAI_API_KEY: void 0,
2408
+ CODEX_API_KEY: void 0
2409
+ };
2410
+ function buildCodexSpawnEnv(input) {
2411
+ const { HOME: _instanceHome, ...instanceTable } = input.recipe.environment;
2412
+ return mergeLaunchEnv({
2413
+ accountHome: input.layout.effectiveHomePath !== void 0 ? { CODEX_HOME: input.layout.effectiveHomePath } : {},
2414
+ instanceTable,
2415
+ handOverrides: input.crushApiKeys ? CRUSHED_API_KEYS : {}
2416
+ });
2417
+ }
2418
+ function nativeLoginSpawnEnv(processEnv, isolatedHome) {
2419
+ return mergeLaunchEnv({
2420
+ inherited: processEnv,
2421
+ handOverrides: { ...CRUSHED_API_KEYS, CODEX_HOME: isolatedHome }
2422
+ });
2423
+ }
2424
+ function shouldCrushApiKeys(authMode) {
2425
+ return authMode === "chatgpt";
2426
+ }
2427
+
2428
+ // src/appServerLaunch.ts
2429
+ function throwIfCodexSpawnControlled(error) {
2430
+ if (error instanceof ExecutorSpawnRefusedError || error instanceof ExecutorSpawnAbortedError) {
2431
+ throw error;
2432
+ }
2433
+ }
2434
+ async function spawnCodexAppServer(input) {
2435
+ await materializeCodexShadowHome(input.layout, input.host.log);
2436
+ throwIfExecutorSpawnAborted(input.signal);
2437
+ const env = input.env ?? buildCodexSpawnEnv({
2438
+ recipe: input.recipe,
2439
+ layout: input.layout,
2440
+ crushApiKeys: shouldCrushApiKeys(input.recipe.authMode)
2441
+ });
2442
+ const args = input.args ?? codexSpawnArgs(input.recipe, input.layout);
2443
+ const handle = await input.host.process.spawn({
2444
+ program: input.recipe.binaryPath,
2445
+ args,
2446
+ owner: { bindingId: input.host.bindingId },
2447
+ ...input.cwd === void 0 ? {} : { cwd: input.cwd },
2448
+ ...input.env !== void 0 || Object.keys(env).length > 0 ? { env } : {},
2449
+ ...input.signal === void 0 ? {} : { signal: input.signal }
2450
+ });
2451
+ return { handle, args };
2452
+ }
2453
+
2454
+ // src/cliVersion.ts
2455
+ var CODEX_VERSION_TIMEOUT_MS = 15e3;
2456
+ var VERSION_PATTERN = /(?<![\d.])(\d+\.\d+\.\d+(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?)/;
2457
+ async function collect(stream) {
2458
+ const chunks = [];
2459
+ for await (const chunk of stream) {
2460
+ chunks.push(Buffer.from(chunk));
2461
+ if (Buffer.concat(chunks).length > 64 * 1024) break;
2462
+ }
2463
+ return Buffer.concat(chunks).toString("utf8");
2464
+ }
2465
+ async function readCodexCliVersion(input) {
2466
+ if (input.recipe.binaryPath.length === 0) return null;
2467
+ let handle;
1015
2468
  try {
1016
- return JSON.stringify(error);
2469
+ handle = await input.host.process.spawn({
2470
+ program: input.recipe.binaryPath,
2471
+ args: ["--version"],
2472
+ owner: { bindingId: input.host.bindingId }
2473
+ });
1017
2474
  } catch {
1018
- return String(error);
2475
+ return null;
2476
+ }
2477
+ const collected = Promise.all([collect(handle.stdout), collect(handle.stderr), handle.exited]);
2478
+ let timer;
2479
+ const timeout = new Promise((resolve4) => {
2480
+ timer = setTimeout(() => resolve4("timeout"), CODEX_VERSION_TIMEOUT_MS);
2481
+ timer.unref?.();
2482
+ });
2483
+ try {
2484
+ const settled = await Promise.race([collected, timeout]);
2485
+ if (settled === "timeout") {
2486
+ collected.catch(() => void 0);
2487
+ return null;
2488
+ }
2489
+ const [stdout, stderr, exitCode] = settled;
2490
+ if (exitCode !== 0) return null;
2491
+ return VERSION_PATTERN.exec(`${stdout}
2492
+ ${stderr}`)?.[1] ?? null;
2493
+ } catch {
2494
+ return null;
2495
+ } finally {
2496
+ if (timer !== void 0) clearTimeout(timer);
2497
+ await handle.kill("SIGTERM").catch(() => void 0);
1019
2498
  }
1020
2499
  }
1021
2500
 
2501
+ // src/failureCategory.ts
2502
+ var codexProcessExitCategory = (session) => session !== void 0 && !session.stopRequested && typeof session.nativeThreadId === "string" && session.nativeThreadId.length > 0 ? "transport" : void 0;
2503
+
1022
2504
  // src/rpc.ts
1023
2505
  function createLineAssembler() {
1024
2506
  const fragments = [];
@@ -1060,7 +2542,7 @@ function classifyStderrLine(line) {
1060
2542
  var CodexRpcResponseError = class extends Error {
1061
2543
  };
1062
2544
  async function createCodexRpcClient(handle, handlers) {
1063
- const pending = /* @__PURE__ */ new Map();
2545
+ const pending2 = /* @__PURE__ */ new Map();
1064
2546
  const decoder = new TextDecoder();
1065
2547
  let nextId = 1;
1066
2548
  let stderrTail = "";
@@ -1071,10 +2553,10 @@ async function createCodexRpcClient(handle, handlers) {
1071
2553
  const failAll = (reason, failureCategory) => {
1072
2554
  if (exitReason === null) exitFailureCategory = failureCategory;
1073
2555
  exitReason = reason;
1074
- for (const [, entry] of pending) {
2556
+ for (const [, entry] of pending2) {
1075
2557
  entry.reject(attach(new Error(`codex app-server ${entry.method} failed: ${reason}`)));
1076
2558
  }
1077
- pending.clear();
2559
+ pending2.clear();
1078
2560
  };
1079
2561
  const dispatch = (line) => {
1080
2562
  if (line.trim().length === 0) return;
@@ -1097,9 +2579,9 @@ async function createCodexRpcClient(handle, handlers) {
1097
2579
  return;
1098
2580
  }
1099
2581
  if (hasId && !hasMethod) {
1100
- const entry = pending.get(typed.id);
2582
+ const entry = pending2.get(typed.id);
1101
2583
  if (entry === void 0) return;
1102
- pending.delete(typed.id);
2584
+ pending2.delete(typed.id);
1103
2585
  if (typed.error !== void 0 && typed.error !== null) {
1104
2586
  entry.reject(
1105
2587
  new CodexRpcResponseError(
@@ -1164,8 +2646,8 @@ async function createCodexRpcClient(handle, handlers) {
1164
2646
  }
1165
2647
  const id = nextId;
1166
2648
  nextId += 1;
1167
- const settled = new Promise((resolve2, reject) => {
1168
- pending.set(id, { resolve: resolve2, reject, method });
2649
+ const settled = new Promise((resolve4, reject) => {
2650
+ pending2.set(id, { resolve: resolve4, reject, method });
1169
2651
  });
1170
2652
  const limit = timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
1171
2653
  let timer;
@@ -1184,7 +2666,7 @@ async function createCodexRpcClient(handle, handlers) {
1184
2666
  ]);
1185
2667
  return await Promise.race([settled, timedOut]);
1186
2668
  } catch (error) {
1187
- pending.delete(id);
2669
+ pending2.delete(id);
1188
2670
  throw error;
1189
2671
  } finally {
1190
2672
  if (timer !== void 0) clearTimeout(timer);
@@ -1220,10 +2702,10 @@ async function createCodexRpcClient(handle, handlers) {
1220
2702
  try {
1221
2703
  await Promise.race([
1222
2704
  drained,
1223
- new Promise((resolve2) => {
2705
+ new Promise((resolve4) => {
1224
2706
  timer = setTimeout(() => {
1225
2707
  options.onDrainTimeout();
1226
- resolve2();
2708
+ resolve4();
1227
2709
  }, options.drainTimeoutMs);
1228
2710
  })
1229
2711
  ]);
@@ -1240,12 +2722,12 @@ async function createCodexRpcClient(handle, handlers) {
1240
2722
  respondError,
1241
2723
  close,
1242
2724
  pid: handle.pid,
1243
- pendingCountForTests: () => pending.size
2725
+ pendingCountForTests: () => pending2.size
1244
2726
  };
1245
2727
  }
1246
2728
 
1247
2729
  // src/sessionRuntime.ts
1248
- import * as NodeCrypto2 from "node:crypto";
2730
+ import * as NodeCrypto4 from "node:crypto";
1249
2731
 
1250
2732
  // src/approvalGrant.ts
1251
2733
  function codexApprovalGrantKey(kind, identity) {
@@ -1471,8 +2953,8 @@ function buildCodexDeveloperInstructions(interactionMode, runtime, browserToolsA
1471
2953
  // src/codexArtifacts.ts
1472
2954
  function imageGenerationArtifacts(input) {
1473
2955
  if (input.itemType !== "imageGeneration" || input.status !== "completed") return [];
1474
- if (!isRecord3(input.params)) return [];
1475
- const item = isRecord3(input.params["item"]) ? input.params["item"] : input.params;
2956
+ if (!isRecord2(input.params)) return [];
2957
+ const item = isRecord2(input.params["item"]) ? input.params["item"] : input.params;
1476
2958
  const savedPath = item["savedPath"];
1477
2959
  if (typeof savedPath !== "string" || savedPath.trim().length === 0) return [];
1478
2960
  return [{ path: savedPath, ...input.itemId ? { toolCallId: input.itemId } : {} }];
@@ -1506,9 +2988,9 @@ function toCanonicalItemType(raw) {
1506
2988
  }
1507
2989
 
1508
2990
  // src/events/base.ts
1509
- import * as NodeCrypto from "node:crypto";
2991
+ import * as NodeCrypto3 from "node:crypto";
1510
2992
  var CODEX_PROVIDER = "codex";
1511
- var EVENT_ID_PREFIX = `codex-evt-${NodeCrypto.randomUUID()}`;
2993
+ var EVENT_ID_PREFIX = `codex-evt-${NodeCrypto3.randomUUID()}`;
1512
2994
  var eventSeq = 0;
1513
2995
  function nextEventId() {
1514
2996
  eventSeq += 1;
@@ -1544,28 +3026,28 @@ function baseEvent(input) {
1544
3026
 
1545
3027
  // src/events/fields.ts
1546
3028
  function itemIdOf(params) {
1547
- if (!isRecord3(params)) return void 0;
1548
- const item = isRecord3(params["item"]) ? params["item"] : params;
3029
+ if (!isRecord2(params)) return void 0;
3030
+ const item = isRecord2(params["item"]) ? params["item"] : params;
1549
3031
  return asString(item["id"]) ?? asString(params["itemId"]) ?? void 0;
1550
3032
  }
1551
3033
  function itemStatusOf(params) {
1552
- if (!isRecord3(params)) return void 0;
1553
- const item = isRecord3(params["item"]) ? params["item"] : params;
3034
+ if (!isRecord2(params)) return void 0;
3035
+ const item = isRecord2(params["item"]) ? params["item"] : params;
1554
3036
  return asString(item["status"]) ?? void 0;
1555
3037
  }
1556
3038
  function turnIdOf(params) {
1557
- if (!isRecord3(params)) return void 0;
1558
- return asString(params["turnId"]) ?? (isRecord3(params["turn"]) ? asString(params["turn"]["id"]) : null) ?? void 0;
3039
+ if (!isRecord2(params)) return void 0;
3040
+ return asString(params["turnId"]) ?? (isRecord2(params["turn"]) ? asString(params["turn"]["id"]) : null) ?? void 0;
1559
3041
  }
1560
3042
  function itemTitle(params) {
1561
- if (!isRecord3(params)) return void 0;
1562
- const item = isRecord3(params["item"]) ? params["item"] : params;
3043
+ if (!isRecord2(params)) return void 0;
3044
+ const item = isRecord2(params["item"]) ? params["item"] : params;
1563
3045
  return trimText(item["title"]) ?? trimText(item["name"]) ?? trimText(item["command"]) ?? trimText(item["summary"]) ?? void 0;
1564
3046
  }
1565
3047
  function itemDetail(params) {
1566
- if (!isRecord3(params)) return void 0;
1567
- const item = isRecord3(params["item"]) ? params["item"] : params;
1568
- const query = isRecord3(item["action"]) ? item["action"]["queries"] : item["query"];
3048
+ if (!isRecord2(params)) return void 0;
3049
+ const item = isRecord2(params["item"]) ? params["item"] : params;
3050
+ const query = isRecord2(item["action"]) ? item["action"]["queries"] : item["query"];
1569
3051
  if (Array.isArray(query)) {
1570
3052
  const joined = query.filter((entry) => typeof entry === "string").join(", ");
1571
3053
  if (joined.length > 0) return joined;
@@ -1586,7 +3068,7 @@ function toTurnStatus(status) {
1586
3068
  }
1587
3069
  }
1588
3070
  function threadStateFromStatus(status) {
1589
- const type = isRecord3(status) ? asString(status["type"]) : asString(status);
3071
+ const type = isRecord2(status) ? asString(status["type"]) : asString(status);
1590
3072
  if (type === "idle") return "idle";
1591
3073
  if (type === "systemError" || type === "error") return "error";
1592
3074
  return "active";
@@ -1595,9 +3077,9 @@ function codexCompactionId(threadId, turnId) {
1595
3077
  return `codex:${threadId}:${turnId ?? "session"}`;
1596
3078
  }
1597
3079
  function normalizeCodexTokenUsage(tokenUsage) {
1598
- if (!isRecord3(tokenUsage)) return void 0;
1599
- const last = isRecord3(tokenUsage["last"]) ? tokenUsage["last"] : void 0;
1600
- const total = isRecord3(tokenUsage["total"]) ? tokenUsage["total"] : void 0;
3080
+ if (!isRecord2(tokenUsage)) return void 0;
3081
+ const last = isRecord2(tokenUsage["last"]) ? tokenUsage["last"] : void 0;
3082
+ const total = isRecord2(tokenUsage["total"]) ? tokenUsage["total"] : void 0;
1601
3083
  const count = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
1602
3084
  const usedTokens = count(last?.["totalTokens"]);
1603
3085
  if (usedTokens === void 0 || usedTokens <= 0) return void 0;
@@ -1620,9 +3102,9 @@ function normalizeCodexTokenUsage(tokenUsage) {
1620
3102
  };
1621
3103
  }
1622
3104
  function turnCompletedControlFlow(params) {
1623
- const turn = isRecord3(params) ? isRecord3(params["turn"]) ? params["turn"] : params : {};
3105
+ const turn = isRecord2(params) ? isRecord2(params["turn"]) ? params["turn"] : params : {};
1624
3106
  const state = toTurnStatus(asString(turn["status"]) ?? void 0);
1625
- const error = isRecord3(turn["error"]) ? trimText(turn["error"]["message"]) : void 0;
3107
+ const error = isRecord2(turn["error"]) ? trimText(turn["error"]["message"]) : void 0;
1626
3108
  return error ? { state, errorMessage: error } : { state };
1627
3109
  }
1628
3110
 
@@ -1647,7 +3129,7 @@ function pathLeaf(value) {
1647
3129
  return parts.at(-1);
1648
3130
  }
1649
3131
  function mapCollabAgentEvent(input) {
1650
- if (!isRecord3(input.params)) return [];
3132
+ if (!isRecord2(input.params)) return [];
1651
3133
  const agentThreadId = asString(input.params["agentThreadId"]) ?? asString(input.params["threadId"]);
1652
3134
  if (!agentThreadId) return [];
1653
3135
  const agentPath = asString(input.params["agentPath"]) ?? asString(input.params["path"]) ?? void 0;
@@ -1657,8 +3139,10 @@ function mapCollabAgentEvent(input) {
1657
3139
  const title = knownName ?? agentThreadId;
1658
3140
  const model = trimText(input.params["model"]);
1659
3141
  const effort = trimText(input.params["effort"]);
3142
+ const parentNativeId = asString(input.params["parentThreadId"]) ?? void 0;
1660
3143
  const linkage = {
1661
3144
  role,
3145
+ ...parentNativeId ? { parentAgentId: parentNativeId } : {},
1662
3146
  ...knownName ? { title: knownName } : {},
1663
3147
  ...model ? { model } : {},
1664
3148
  ...effort ? { effort } : {},
@@ -1747,8 +3231,8 @@ function mapCollabAgentEvent(input) {
1747
3231
  ];
1748
3232
  }
1749
3233
  if (method === "collabAgent/tokenUsage") {
1750
- const tokenUsage = isRecord3(input.params["tokenUsage"]) ? input.params["tokenUsage"] : void 0;
1751
- const total = tokenUsage && isRecord3(tokenUsage["total"]) ? tokenUsage["total"] : void 0;
3234
+ const tokenUsage = isRecord2(input.params["tokenUsage"]) ? input.params["tokenUsage"] : void 0;
3235
+ const total = tokenUsage && isRecord2(tokenUsage["total"]) ? tokenUsage["total"] : void 0;
1752
3236
  const count = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
1753
3237
  const totalTokens = total ? count(total["totalTokens"]) : void 0;
1754
3238
  if (total === void 0 || totalTokens === void 0) return [];
@@ -1783,18 +3267,18 @@ function mapCollabAgentEvent(input) {
1783
3267
 
1784
3268
  // src/events/userInput.ts
1785
3269
  function toUserInputQuestions(params) {
1786
- if (!isRecord3(params)) return void 0;
3270
+ if (!isRecord2(params)) return void 0;
1787
3271
  const questions = Array.isArray(params["questions"]) ? params["questions"] : [];
1788
3272
  const mapped = [];
1789
3273
  for (const question of questions) {
1790
- if (!isRecord3(question)) return void 0;
3274
+ if (!isRecord2(question)) return void 0;
1791
3275
  const id = asString(question["id"]);
1792
3276
  const header = asString(question["header"]);
1793
3277
  const text = asString(question["question"]);
1794
3278
  const rawOptions = Array.isArray(question["options"]) ? question["options"] : [];
1795
3279
  const options = [];
1796
3280
  for (const option of rawOptions) {
1797
- if (!isRecord3(option)) continue;
3281
+ if (!isRecord2(option)) continue;
1798
3282
  const label = trimText(option["label"]);
1799
3283
  if (!label) continue;
1800
3284
  options.push({
@@ -1815,12 +3299,12 @@ function toUserInputQuestions(params) {
1815
3299
  return mapped.length > 0 ? mapped : void 0;
1816
3300
  }
1817
3301
  function toAsyncQuestions(params) {
1818
- if (!isRecord3(params)) return void 0;
1819
- const item = isRecord3(params["item"]) ? params["item"] : params;
3302
+ if (!isRecord2(params)) return void 0;
3303
+ const item = isRecord2(params["item"]) ? params["item"] : params;
1820
3304
  if (item["delivery"] !== "async" || !Array.isArray(item["questions"])) return void 0;
1821
3305
  const mapped = [];
1822
3306
  item["questions"].forEach((question, index) => {
1823
- if (!isRecord3(question)) return;
3307
+ if (!isRecord2(question)) return;
1824
3308
  const title = trimText(question["title"]);
1825
3309
  if (!title) return;
1826
3310
  const labels = Array.isArray(question["options"]) ? question["options"] : [];
@@ -1837,7 +3321,7 @@ function toAsyncQuestions(params) {
1837
3321
  return mapped.length > 0 ? mapped : void 0;
1838
3322
  }
1839
3323
  function toCodexUserInputAnswers(answers) {
1840
- if (!isRecord3(answers)) return void 0;
3324
+ if (!isRecord2(answers)) return void 0;
1841
3325
  const out = {};
1842
3326
  for (const [questionId, value] of Object.entries(answers)) {
1843
3327
  if (typeof value === "string") {
@@ -1848,7 +3332,7 @@ function toCodexUserInputAnswers(answers) {
1848
3332
  out[questionId] = { answers: [...value] };
1849
3333
  continue;
1850
3334
  }
1851
- if (isRecord3(value) && Array.isArray(value["answers"]) && value["answers"].every((entry) => typeof entry === "string")) {
3335
+ if (isRecord2(value) && Array.isArray(value["answers"]) && value["answers"].every((entry) => typeof entry === "string")) {
1852
3336
  out[questionId] = { answers: [...value["answers"]] };
1853
3337
  continue;
1854
3338
  }
@@ -1867,8 +3351,8 @@ function toCanonicalUserInputAnswers(answers) {
1867
3351
 
1868
3352
  // src/windowsSandbox.ts
1869
3353
  function windowsSandboxWarnings(input) {
1870
- const item = isRecord3(input.params) ? input.params["item"] : void 0;
1871
- if (!isRecord3(item) || item["type"] !== "commandExecution" || item["source"] !== "unifiedExecStartup" || item["status"] !== "failed" || item["processId"] !== null || item["exitCode"] !== -1 || item["durationMs"] !== 0)
3354
+ const item = isRecord2(input.params) ? input.params["item"] : void 0;
3355
+ if (!isRecord2(item) || item["type"] !== "commandExecution" || item["source"] !== "unifiedExecStartup" || item["status"] !== "failed" || item["processId"] !== null || item["exitCode"] !== -1 || item["durationMs"] !== 0)
1872
3356
  return [];
1873
3357
  const output = item["aggregatedOutput"];
1874
3358
  if (typeof output !== "string" || !/^Failed to create unified exec process: (?:CreateProcessWithLogonW failed: \d+\b|orchestrator_helper_launch_canceled: ShellExecuteExW failed to launch setup helper: \d+\b)/.test(
@@ -2209,10 +3693,10 @@ function mapNotificationToEvents(input) {
2209
3693
  return mapCollabAgentEvent({ method, params, rootThreadId: threadId, providerInstanceId });
2210
3694
  }
2211
3695
  if (method === "error") {
2212
- if (isUsageLimitExceeded(isRecord3(params) ? params["error"] : void 0)) return [];
2213
- const willRetry = isRecord3(params) && params["willRetry"] === true;
2214
- const nested = isRecord3(params) && isRecord3(params["error"]) ? params["error"] : void 0;
2215
- const message = (nested ? trimText(nested["message"]) : void 0) ?? (isRecord3(params) ? trimText(params["message"]) : void 0) ?? "Codex error";
3696
+ if (isUsageLimitExceeded(isRecord2(params) ? params["error"] : void 0)) return [];
3697
+ const willRetry = isRecord2(params) && params["willRetry"] === true;
3698
+ const nested = isRecord2(params) && isRecord2(params["error"]) ? params["error"] : void 0;
3699
+ const message = (nested ? trimText(nested["message"]) : void 0) ?? (isRecord2(params) ? trimText(params["message"]) : void 0) ?? "Codex error";
2216
3700
  const payload = { message };
2217
3701
  if (!willRetry) payload["class"] = "provider_error";
2218
3702
  if (params !== void 0) payload["detail"] = params;
@@ -2228,7 +3712,7 @@ function mapNotificationToEvents(input) {
2228
3712
  ];
2229
3713
  }
2230
3714
  if (method === "process/stderr") {
2231
- const text = isRecord3(params) ? trimText(params["text"]) ?? "" : "";
3715
+ const text = isRecord2(params) ? trimText(params["text"]) ?? "" : "";
2232
3716
  if (!text) return [];
2233
3717
  if (isFatalStderr(text)) {
2234
3718
  return [
@@ -2256,8 +3740,8 @@ function mapNotificationToEvents(input) {
2256
3740
  const type = itemTypeOf(params);
2257
3741
  switch (method) {
2258
3742
  case "thread/started": {
2259
- const startedThread = isRecord3(params) ? params["thread"] : void 0;
2260
- const providerThreadId = isRecord3(startedThread) ? trimText(startedThread["id"]) : void 0;
3743
+ const startedThread = isRecord2(params) ? params["thread"] : void 0;
3744
+ const providerThreadId = isRecord2(startedThread) ? trimText(startedThread["id"]) : void 0;
2261
3745
  return [
2262
3746
  baseEvent({
2263
3747
  type: "thread.started",
@@ -2269,7 +3753,7 @@ function mapNotificationToEvents(input) {
2269
3753
  ];
2270
3754
  }
2271
3755
  case "thread/status/changed": {
2272
- const status = isRecord3(params) ? params["status"] : void 0;
3756
+ const status = isRecord2(params) ? params["status"] : void 0;
2273
3757
  return [
2274
3758
  baseEvent({
2275
3759
  type: "thread.state.changed",
@@ -2329,8 +3813,8 @@ function mapNotificationToEvents(input) {
2329
3813
  })
2330
3814
  ];
2331
3815
  case "thread/name/updated": {
2332
- const threadName = isRecord3(params) ? trimText(params["threadName"]) ?? trimText(params["name"]) : void 0;
2333
- const nativeThreadId = isRecord3(params) ? asString(params["threadId"]) : void 0;
3816
+ const threadName = isRecord2(params) ? trimText(params["threadName"]) ?? trimText(params["name"]) : void 0;
3817
+ const nativeThreadId = isRecord2(params) ? asString(params["threadId"]) : void 0;
2334
3818
  return [
2335
3819
  baseEvent({
2336
3820
  type: "thread.metadata.updated",
@@ -2351,7 +3835,7 @@ function mapNotificationToEvents(input) {
2351
3835
  }
2352
3836
  case "thread/tokenUsage/updated": {
2353
3837
  const usage = normalizeCodexTokenUsage(
2354
- isRecord3(params) ? params["tokenUsage"] ?? params["usage"] : void 0
3838
+ isRecord2(params) ? params["tokenUsage"] ?? params["usage"] : void 0
2355
3839
  );
2356
3840
  if (!usage) return [];
2357
3841
  return [
@@ -2388,8 +3872,8 @@ function mapNotificationToEvents(input) {
2388
3872
  ];
2389
3873
  case "turn/completed": {
2390
3874
  const controlFlow = turnCompletedControlFlow(params);
2391
- const turn = isRecord3(params) ? isRecord3(params["turn"]) ? params["turn"] : params : {};
2392
- const turnError = isRecord3(turn["error"]) ? turn["error"] : void 0;
3875
+ const turn = isRecord2(params) ? isRecord2(params["turn"]) ? params["turn"] : params : {};
3876
+ const turnError = isRecord2(turn["error"]) ? turn["error"] : void 0;
2393
3877
  if (controlFlow.state === "failed" && isUsageLimitExceeded(turnError)) {
2394
3878
  const message = codexUsageLimitMessage(
2395
3879
  rateLimits,
@@ -2434,7 +3918,7 @@ function mapNotificationToEvents(input) {
2434
3918
  threadId,
2435
3919
  turnId,
2436
3920
  payload: {
2437
- reason: (isRecord3(params) ? trimText(params["reason"]) : void 0) ?? (isRecord3(params) ? trimText(params["message"]) : void 0) ?? "Turn aborted"
3921
+ reason: (isRecord2(params) ? trimText(params["reason"]) : void 0) ?? (isRecord2(params) ? trimText(params["message"]) : void 0) ?? "Turn aborted"
2438
3922
  },
2439
3923
  method,
2440
3924
  providerInstanceId
@@ -2442,12 +3926,12 @@ function mapNotificationToEvents(input) {
2442
3926
  ];
2443
3927
  case "turn/plan":
2444
3928
  case "turn/plan/updated": {
2445
- const rawPlan = isRecord3(params) && Array.isArray(params["plan"]) ? params["plan"] : [];
2446
- const plan = rawPlan.filter(isRecord3).map((step) => ({
3929
+ const rawPlan = isRecord2(params) && Array.isArray(params["plan"]) ? params["plan"] : [];
3930
+ const plan = rawPlan.filter(isRecord2).map((step) => ({
2447
3931
  step: trimText(step["step"]) ?? "step",
2448
3932
  status: step["status"] === "completed" || step["status"] === "inProgress" ? step["status"] : "pending"
2449
3933
  }));
2450
- const explanation = isRecord3(params) ? trimText(params["explanation"]) : void 0;
3934
+ const explanation = isRecord2(params) ? trimText(params["explanation"]) : void 0;
2451
3935
  return [
2452
3936
  baseEvent({
2453
3937
  type: "turn.plan.updated",
@@ -2463,7 +3947,7 @@ function mapNotificationToEvents(input) {
2463
3947
  ];
2464
3948
  }
2465
3949
  case "turn/diff/updated": {
2466
- const unifiedDiff = isRecord3(params) ? asString(params["diff"]) : void 0;
3950
+ const unifiedDiff = isRecord2(params) ? asString(params["diff"]) : void 0;
2467
3951
  if (unifiedDiff === void 0) return [];
2468
3952
  return [
2469
3953
  baseEvent({
@@ -2611,7 +4095,7 @@ function mapNotificationToEvents(input) {
2611
4095
  ];
2612
4096
  }
2613
4097
  case "item/plan/delta": {
2614
- const delta = isRecord3(params) ? asString(params["delta"]) : void 0;
4098
+ const delta = isRecord2(params) ? asString(params["delta"]) : void 0;
2615
4099
  if (!delta) return [];
2616
4100
  return [
2617
4101
  baseEvent({
@@ -2630,11 +4114,11 @@ function mapNotificationToEvents(input) {
2630
4114
  case "item/reasoning/summaryTextDelta":
2631
4115
  case "item/commandExecution/outputDelta":
2632
4116
  case "item/fileChange/outputDelta": {
2633
- const delta = isRecord3(params) ? asString(params["delta"]) ?? asString(params["text"]) ?? "" : "";
4117
+ const delta = isRecord2(params) ? asString(params["delta"]) ?? asString(params["text"]) ?? "" : "";
2634
4118
  if (delta.length === 0) return [];
2635
4119
  const streamKind = method === "item/agentMessage/delta" ? "assistant_text" : method === "item/reasoning/textDelta" ? "reasoning_text" : method === "item/reasoning/summaryTextDelta" ? "reasoning_summary_text" : method === "item/commandExecution/outputDelta" ? "command_output" : "file_change_output";
2636
- const summaryIndex = method === "item/reasoning/summaryTextDelta" && isRecord3(params) ? asNumber(params["summaryIndex"]) : null;
2637
- const contentIndex = method === "item/reasoning/textDelta" && isRecord3(params) ? asNumber(params["contentIndex"]) : null;
4120
+ const summaryIndex = method === "item/reasoning/summaryTextDelta" && isRecord2(params) ? asNumber(params["summaryIndex"]) : null;
4121
+ const contentIndex = method === "item/reasoning/textDelta" && isRecord2(params) ? asNumber(params["contentIndex"]) : null;
2638
4122
  return [
2639
4123
  baseEvent({
2640
4124
  type: "content.delta",
@@ -2653,7 +4137,7 @@ function mapNotificationToEvents(input) {
2653
4137
  ];
2654
4138
  }
2655
4139
  case "item/reasoning/summaryPartAdded": {
2656
- const summaryIndex = isRecord3(params) ? asNumber(params["summaryIndex"]) : null;
4140
+ const summaryIndex = isRecord2(params) ? asNumber(params["summaryIndex"]) : null;
2657
4141
  if (summaryIndex === null) return [];
2658
4142
  return [
2659
4143
  baseEvent({
@@ -2672,7 +4156,7 @@ function mapNotificationToEvents(input) {
2672
4156
  ];
2673
4157
  }
2674
4158
  case "item/mcpToolCall/progress": {
2675
- const summary = isRecord3(params) ? trimText(params["message"]) : void 0;
4159
+ const summary = isRecord2(params) ? trimText(params["message"]) : void 0;
2676
4160
  if (!summary) return [];
2677
4161
  return [
2678
4162
  baseEvent({
@@ -2717,16 +4201,16 @@ function mapNotificationToEvents(input) {
2717
4201
  type: "account.rate-limits.updated",
2718
4202
  threadId,
2719
4203
  payload: {
2720
- rateLimits: isRecord3(params) && "rateLimits" in params ? params["rateLimits"] : params ?? {}
4204
+ rateLimits: isRecord2(params) && "rateLimits" in params ? params["rateLimits"] : params ?? {}
2721
4205
  },
2722
4206
  method,
2723
4207
  providerInstanceId
2724
4208
  })
2725
4209
  ];
2726
4210
  case "model/rerouted": {
2727
- const fromModel = isRecord3(params) ? trimText(params["fromModel"]) : void 0;
2728
- const toModel = isRecord3(params) ? trimText(params["toModel"]) : void 0;
2729
- const reason = isRecord3(params) ? trimText(params["reason"]) : void 0;
4211
+ const fromModel = isRecord2(params) ? trimText(params["fromModel"]) : void 0;
4212
+ const toModel = isRecord2(params) ? trimText(params["toModel"]) : void 0;
4213
+ const reason = isRecord2(params) ? trimText(params["reason"]) : void 0;
2730
4214
  if (!fromModel || !toModel || !reason) return [];
2731
4215
  return [
2732
4216
  baseEvent({
@@ -2741,9 +4225,9 @@ function mapNotificationToEvents(input) {
2741
4225
  }
2742
4226
  case "configWarning":
2743
4227
  case "deprecationNotice": {
2744
- const summary = isRecord3(params) ? trimText(params["summary"]) : void 0;
4228
+ const summary = isRecord2(params) ? trimText(params["summary"]) : void 0;
2745
4229
  if (!summary) return [];
2746
- const details = isRecord3(params) ? trimText(params["details"]) : void 0;
4230
+ const details = isRecord2(params) ? trimText(params["details"]) : void 0;
2747
4231
  return [
2748
4232
  baseEvent({
2749
4233
  type: method === "configWarning" ? "config.warning" : "deprecation.notice",
@@ -2751,7 +4235,7 @@ function mapNotificationToEvents(input) {
2751
4235
  payload: {
2752
4236
  summary,
2753
4237
  ...details ? { details } : {},
2754
- ...method === "configWarning" && isRecord3(params) ? {
4238
+ ...method === "configWarning" && isRecord2(params) ? {
2755
4239
  ...trimText(params["path"]) ? { path: trimText(params["path"]) } : {},
2756
4240
  ...params["range"] !== void 0 && params["range"] !== null ? { range: params["range"] } : {}
2757
4241
  } : {}
@@ -2762,10 +4246,10 @@ function mapNotificationToEvents(input) {
2762
4246
  ];
2763
4247
  }
2764
4248
  case "mcpServer/oauthLogin/completed": {
2765
- const success = isRecord3(params) ? params["success"] : void 0;
4249
+ const success = isRecord2(params) ? params["success"] : void 0;
2766
4250
  if (typeof success !== "boolean") return [];
2767
- const name = isRecord3(params) ? trimText(params["name"]) : void 0;
2768
- const error = isRecord3(params) ? trimText(params["error"]) : void 0;
4251
+ const name = isRecord2(params) ? trimText(params["name"]) : void 0;
4252
+ const error = isRecord2(params) ? trimText(params["error"]) : void 0;
2769
4253
  return [
2770
4254
  baseEvent({
2771
4255
  type: "mcp.oauth.completed",
@@ -2787,17 +4271,17 @@ function mapNotificationToEvents(input) {
2787
4271
 
2788
4272
  // src/approvalMapping.ts
2789
4273
  function fileChangeEntries(params) {
2790
- if (!isRecord3(params)) return [];
2791
- const item = isRecord3(params["item"]) ? params["item"] : params;
4274
+ if (!isRecord2(params)) return [];
4275
+ const item = isRecord2(params["item"]) ? params["item"] : params;
2792
4276
  const changes = item["changes"] ?? item["fileChanges"] ?? params["fileChanges"];
2793
- if (!isRecord3(changes) && !Array.isArray(changes)) return [];
4277
+ if (!isRecord2(changes) && !Array.isArray(changes)) return [];
2794
4278
  const entries = Array.isArray(changes) ? changes : Object.entries(changes).map(([path, change]) => ({
2795
4279
  path,
2796
- ...isRecord3(change) ? change : {}
4280
+ ...isRecord2(change) ? change : {}
2797
4281
  }));
2798
4282
  const out = [];
2799
4283
  for (const entry of entries) {
2800
- if (!isRecord3(entry)) continue;
4284
+ if (!isRecord2(entry)) continue;
2801
4285
  const path = asString(entry["path"]) ?? asString(entry["file"]);
2802
4286
  if (!path) continue;
2803
4287
  out.push({
@@ -2855,7 +4339,7 @@ function toApplyPatchFileChanges(params) {
2855
4339
  return out;
2856
4340
  }
2857
4341
  function describeCommandApproval(params) {
2858
- const record = isRecord3(params) ? params : {};
4342
+ const record = isRecord2(params) ? params : {};
2859
4343
  const commandValue = record["command"];
2860
4344
  const command = Array.isArray(commandValue) ? commandValue.filter((entry) => typeof entry === "string").join(" ") : asString(commandValue) ?? "";
2861
4345
  const cwd = asString(record["cwd"]);
@@ -2869,7 +4353,7 @@ function describeCommandApproval(params) {
2869
4353
  };
2870
4354
  }
2871
4355
  function describeFileChangeApproval(params) {
2872
- const record = isRecord3(params) ? params : {};
4356
+ const record = isRecord2(params) ? params : {};
2873
4357
  const reason = trimText(record["reason"]);
2874
4358
  const grantRoot = asString(record["grantRoot"]);
2875
4359
  const callId = asString(record["callId"]);
@@ -2883,16 +4367,16 @@ function describeFileChangeApproval(params) {
2883
4367
  };
2884
4368
  }
2885
4369
  function describePermissionsApproval(params) {
2886
- const record = isRecord3(params) ? params : {};
2887
- const permissions = isRecord3(record["permissions"]) ? record["permissions"] : {};
2888
- const fileSystem = isRecord3(permissions["fileSystem"]) ? permissions["fileSystem"] : {};
2889
- const network = isRecord3(permissions["network"]) ? permissions["network"] : {};
4370
+ const record = isRecord2(params) ? params : {};
4371
+ const permissions = isRecord2(record["permissions"]) ? record["permissions"] : {};
4372
+ const fileSystem = isRecord2(permissions["fileSystem"]) ? permissions["fileSystem"] : {};
4373
+ const network = isRecord2(permissions["network"]) ? permissions["network"] : {};
2890
4374
  const pathsOf = (value) => Array.isArray(value) ? value.flatMap((entry) => typeof entry === "string" && entry.length > 0 ? [entry] : []) : [];
2891
4375
  const read = pathsOf(fileSystem["read"]);
2892
4376
  const write = pathsOf(fileSystem["write"]);
2893
4377
  const entries = Array.isArray(fileSystem["entries"]) ? fileSystem["entries"] : [];
2894
4378
  for (const entry of entries) {
2895
- if (!isRecord3(entry) || !isRecord3(entry["path"])) continue;
4379
+ if (!isRecord2(entry) || !isRecord2(entry["path"])) continue;
2896
4380
  const target = entry["path"];
2897
4381
  const path = target["type"] === "path" ? asString(target["path"]) : target["type"] === "glob_pattern" ? asString(target["pattern"]) : void 0;
2898
4382
  if (!path) continue;
@@ -2909,7 +4393,7 @@ function describePermissionsApproval(params) {
2909
4393
  }
2910
4394
  function toPermissionsResponse(decision, params, persistent) {
2911
4395
  if (decision !== "allow") return { permissions: {} };
2912
- const requested = isRecord3(params) && isRecord3(params["permissions"]) ? params["permissions"] : {};
4396
+ const requested = isRecord2(params) && isRecord2(params["permissions"]) ? params["permissions"] : {};
2913
4397
  return {
2914
4398
  permissions: {
2915
4399
  ...requested["fileSystem"] !== void 0 ? { fileSystem: requested["fileSystem"] } : {},
@@ -2919,7 +4403,7 @@ function toPermissionsResponse(decision, params, persistent) {
2919
4403
  };
2920
4404
  }
2921
4405
  function describeMcpElicitation(params) {
2922
- const record = isRecord3(params) ? params : {};
4406
+ const record = isRecord2(params) ? params : {};
2923
4407
  const appName = asString(record["appName"]) ?? asString(record["serverName"]) ?? void 0;
2924
4408
  const serverName = asString(record["serverName"]);
2925
4409
  const message = trimText(record["message"]);
@@ -2936,7 +4420,7 @@ function describeMcpElicitation(params) {
2936
4420
  };
2937
4421
  }
2938
4422
  function persistFromMeta(meta) {
2939
- if (!isRecord3(meta)) return void 0;
4423
+ if (!isRecord2(meta)) return void 0;
2940
4424
  const persist = asString(meta["persist"]) ?? asString(meta["persistence"]);
2941
4425
  if (persist === "session" || persist === "acceptForSession") return "session";
2942
4426
  if (persist === "always" || persist === "permanent" || persist === "forever" || persist === "persistent" || persist === "acceptAlways") {
@@ -2951,16 +4435,16 @@ function toMcpElicitationResponse(decision, params) {
2951
4435
  action: decision === "allow" ? "decline" : decision === "cancel" ? "cancel" : "decline"
2952
4436
  };
2953
4437
  }
2954
- const schema = isRecord3(described.schema) ? described.schema : void 0;
2955
- const properties = schema && isRecord3(schema["properties"]) ? schema["properties"] : {};
4438
+ const schema = isRecord2(described.schema) ? described.schema : void 0;
4439
+ const properties = schema && isRecord2(schema["properties"]) ? schema["properties"] : {};
2956
4440
  const required = schema && Array.isArray(schema["required"]) ? schema["required"] : [];
2957
4441
  const content = {};
2958
4442
  for (const [key, spec] of Object.entries(properties)) {
2959
- if (!isRecord3(spec)) continue;
4443
+ if (!isRecord2(spec)) continue;
2960
4444
  if (Array.isArray(spec["oneOf"]) || Array.isArray(spec["enum"])) {
2961
4445
  const options = Array.isArray(spec["oneOf"]) ? spec["oneOf"] : Array.isArray(spec["enum"]) ? spec["enum"] : [];
2962
4446
  const first = options[0];
2963
- content[key] = isRecord3(first) ? first["const"] ?? first["value"] ?? first : first;
4447
+ content[key] = isRecord2(first) ? first["const"] ?? first["value"] ?? first : first;
2964
4448
  } else if (spec["type"] === "boolean") {
2965
4449
  content[key] = true;
2966
4450
  } else if (typeof spec["default"] !== "undefined") {
@@ -2972,7 +4456,7 @@ function toMcpElicitationResponse(decision, params) {
2972
4456
  return { action: "decline" };
2973
4457
  }
2974
4458
  }
2975
- const persist = persistFromMeta(isRecord3(params) ? params["_meta"] : void 0);
4459
+ const persist = persistFromMeta(isRecord2(params) ? params["_meta"] : void 0);
2976
4460
  return {
2977
4461
  action: "accept",
2978
4462
  content,
@@ -3023,7 +4507,7 @@ function toRequestTypeFromMethod(method) {
3023
4507
  }
3024
4508
  }
3025
4509
  function elicitationOptions(params) {
3026
- const persist = persistFromMeta(isRecord3(params) ? params["_meta"] : void 0);
4510
+ const persist = persistFromMeta(isRecord2(params) ? params["_meta"] : void 0);
3027
4511
  return [
3028
4512
  { decision: "cancel", label: "Cancel" },
3029
4513
  { decision: "decline", label: "Decline" },
@@ -3122,15 +4606,15 @@ function posixCommandMatches(expected, argv) {
3122
4606
  return posixShellCommandMatches({ shell, script }, argv);
3123
4607
  }
3124
4608
  var windowsPath = (path) => path.replaceAll("/", "\\").toLowerCase();
3125
- function basename(path) {
4609
+ function basename2(path) {
3126
4610
  const parts = path.split(/[\\/]/);
3127
4611
  return (parts[parts.length - 1] ?? "").toLowerCase();
3128
4612
  }
3129
4613
  function codexCommandMatcher(display) {
3130
4614
  const expected = splitPosixCommand(display);
3131
4615
  if (expected === null || expected.length === 0) return void 0;
3132
- return (argv, platform2) => {
3133
- if (platform2 !== "win32") return posixCommandMatches(expected, argv);
4616
+ return (argv, platform3) => {
4617
+ if (platform3 !== "win32") return posixCommandMatches(expected, argv);
3134
4618
  if (argv.length !== expected.length) return false;
3135
4619
  const [actualExe, ...actualRest] = argv;
3136
4620
  const [expectedExe, ...expectedRest] = expected;
@@ -3140,32 +4624,32 @@ function codexCommandMatcher(display) {
3140
4624
  return expectedRest.every((arg, index) => {
3141
4625
  const actual = actualRest[index];
3142
4626
  if (actual === arg) return true;
3143
- return index === lastIndex && index >= 1 && expectedRest[index - 1]?.toLowerCase() === "-command" && isPowerShellExecutableName(basename(expectedExe)) && actual === WINDOWS_POWERSHELL_PREFIX + arg;
4627
+ return index === lastIndex && index >= 1 && expectedRest[index - 1]?.toLowerCase() === "-command" && isPowerShellExecutableName(basename2(expectedExe)) && actual === WINDOWS_POWERSHELL_PREFIX + arg;
3144
4628
  });
3145
4629
  };
3146
4630
  }
3147
- function trackOpenCommand(open, method, params) {
3148
- if (!isRecord3(params)) return;
4631
+ function trackOpenCommand(open2, method, params) {
4632
+ if (!isRecord2(params)) return;
3149
4633
  const turnId = turnIdOf(params);
3150
4634
  if (method === "turn/completed") {
3151
- for (const [id2, entry] of open) {
3152
- if (turnId === void 0 || entry.turnId === turnId) open.delete(id2);
4635
+ for (const [id2, entry] of open2) {
4636
+ if (turnId === void 0 || entry.turnId === turnId) open2.delete(id2);
3153
4637
  }
3154
4638
  return;
3155
4639
  }
3156
4640
  const item = params["item"];
3157
- if (!isRecord3(item) || item["type"] !== "commandExecution") return;
4641
+ if (!isRecord2(item) || item["type"] !== "commandExecution") return;
3158
4642
  const id = item["id"];
3159
4643
  if (typeof id !== "string") return;
3160
4644
  if (method === "item/completed") {
3161
- open.delete(id);
4645
+ open2.delete(id);
3162
4646
  return;
3163
4647
  }
3164
4648
  if (method !== "item/started") return;
3165
4649
  const startedAtMs = params["startedAtMs"];
3166
4650
  const command = item["command"];
3167
4651
  if (typeof startedAtMs !== "number" || typeof command !== "string") return;
3168
- open.set(id, { turnId, startedAtMs, command });
4652
+ open2.set(id, { turnId, startedAtMs, command });
3169
4653
  }
3170
4654
  function codexSessionProcessMatcher(appServerArgs) {
3171
4655
  return (argv) => argv.length === appServerArgs.length + 1 && sameArgv(argv.slice(1), appServerArgs);
@@ -3253,7 +4737,7 @@ function isRootChild(agentPath, agentThreadId, rootThreadId) {
3253
4737
  function readSubAgentActivity(method, params) {
3254
4738
  if (method !== "item/started" && method !== "item/completed") return void 0;
3255
4739
  if (itemTypeOf(params) !== "subAgentActivity") return void 0;
3256
- const item = isRecord3(params) ? isRecord3(params["item"]) ? params["item"] : params : {};
4740
+ const item = isRecord2(params) ? isRecord2(params["item"]) ? params["item"] : params : {};
3257
4741
  return {
3258
4742
  agentThreadId: asString(item["agentThreadId"]) ?? void 0,
3259
4743
  agentPath: asString(item["agentPath"]) ?? void 0
@@ -3265,17 +4749,18 @@ var CodexSessionCollab = class {
3265
4749
  this.runtime = runtime;
3266
4750
  }
3267
4751
  interceptCollab(method, params, conversationId) {
3268
- const thread = isRecord3(params) && isRecord3(params["thread"]) ? params["thread"] : void 0;
4752
+ const thread = isRecord2(params) && isRecord2(params["thread"]) ? params["thread"] : void 0;
3269
4753
  const source = thread === void 0 ? void 0 : thread["source"];
3270
- const subAgent = isRecord3(source) ? source["subAgent"] : void 0;
3271
- const spawn = isRecord3(subAgent) ? subAgent["thread_spawn"] : void 0;
3272
- if (method === "thread/started" && thread !== void 0 && isRecord3(spawn)) {
4754
+ const subAgent = isRecord2(source) ? source["subAgent"] : void 0;
4755
+ const spawn = isRecord2(subAgent) ? subAgent["thread_spawn"] : void 0;
4756
+ if (method === "thread/started" && thread !== void 0 && isRecord2(spawn)) {
3273
4757
  const agentPath = asString(spawn["agent_path"]) ?? void 0;
3274
4758
  const knownPath = agentPath ?? this.runtime.collabChildren.get(conversationId)?.agentPath;
3275
4759
  if (isRootChild(knownPath, conversationId, this.runtime.nativeThreadId ?? this.runtime.threadId))
3276
4760
  return;
3277
4761
  this.upsertCollabChild(conversationId, {
3278
4762
  agentPath,
4763
+ parentThreadId: asString(spawn["parent_thread_id"]) ?? void 0,
3279
4764
  role: asString(spawn["agent_role"]) ?? asString(thread["agentRole"]) ?? void 0,
3280
4765
  nickname: asString(spawn["agent_nickname"]) ?? asString(thread["agentNickname"]) ?? void 0
3281
4766
  });
@@ -3283,7 +4768,7 @@ var CodexSessionCollab = class {
3283
4768
  }
3284
4769
  const itemType = itemTypeOf(params);
3285
4770
  if ((method === "item/started" || method === "item/completed") && itemType === "collabAgentToolCall") {
3286
- const item = isRecord3(params) ? isRecord3(params["item"]) ? params["item"] : params : {};
4771
+ const item = isRecord2(params) ? isRecord2(params["item"]) ? params["item"] : params : {};
3287
4772
  const receiver = asString(item["receiverThreadId"]) ?? asString(item["agentThreadId"]);
3288
4773
  if (receiver && this.runtime.activeTurnId)
3289
4774
  this.runtime.collabReceiverTurns.set(receiver, this.runtime.activeTurnId);
@@ -3299,13 +4784,15 @@ var CodexSessionCollab = class {
3299
4784
  )) {
3300
4785
  return;
3301
4786
  }
3302
- this.upsertCollabChild(agentThreadId, { agentPath: activity.agentPath });
4787
+ this.upsertCollabChild(agentThreadId, {
4788
+ agentPath: activity.agentPath
4789
+ });
3303
4790
  }
3304
4791
  if (method === "thread/settings/updated" || method === "model/rerouted") {
3305
- const settings = isRecord3(params) && isRecord3(params["threadSettings"]) ? params["threadSettings"] : {};
4792
+ const settings = isRecord2(params) && isRecord2(params["threadSettings"]) ? params["threadSettings"] : {};
3306
4793
  const reroute = method === "model/rerouted";
3307
4794
  const model = metaValue(
3308
- reroute ? isRecord3(params) ? params["toModel"] : void 0 : settings["model"]
4795
+ reroute ? isRecord2(params) ? params["toModel"] : void 0 : settings["model"]
3309
4796
  );
3310
4797
  const effort = reroute ? void 0 : metaValue(settings["effort"]);
3311
4798
  this.updateCollabChildMeta(conversationId, { model, effort }, true);
@@ -3333,7 +4820,7 @@ var CodexSessionCollab = class {
3333
4820
  return;
3334
4821
  }
3335
4822
  if (method === "turn/completed") {
3336
- const turn = isRecord3(params) && isRecord3(params["turn"]) ? params["turn"] : void 0;
4823
+ const turn = isRecord2(params) && isRecord2(params["turn"]) ? params["turn"] : void 0;
3337
4824
  const turnStatus = turn === void 0 ? void 0 : asString(turn["status"]) ?? void 0;
3338
4825
  child.status = collabTurnEndStatus(turnStatus);
3339
4826
  this.emitCollab(
@@ -3344,7 +4831,7 @@ var CodexSessionCollab = class {
3344
4831
  return;
3345
4832
  }
3346
4833
  if (method === "error") {
3347
- const willRetry = isRecord3(params) ? params["willRetry"] === true : false;
4834
+ const willRetry = isRecord2(params) ? params["willRetry"] === true : false;
3348
4835
  if (willRetry) return;
3349
4836
  child.status = "failed";
3350
4837
  this.emitCollab("collabAgent/statusChanged", child, { status: "systemError" });
@@ -3361,8 +4848,8 @@ var CodexSessionCollab = class {
3361
4848
  }
3362
4849
  /**
3363
4850
  * 两条登记路(根线程的 subAgentActivity、子线程的 thread/started)都走这里。
3364
- * 第一次见到就登记并宣布;已登记的只合并身份:已有的字段保留,缺的补上,补到了就发
3365
- * 一条带当前状态的元数据更新。不能再宣布一次:一轮结束之后才到的宣布,会让宿主把
4851
+ * 第一次见到就登记并宣布;普通身份字段只补缺,出生父号以 thread_spawn 为准并可纠正旧值。
4852
+ * 补到身份后发一条带当前状态的元数据更新。不能再宣布一次:一轮结束之后才到的宣布,会让宿主把
3366
4853
  * idle 当成新一轮开始。
3367
4854
  */
3368
4855
  upsertCollabChild(agentThreadId, identity) {
@@ -3371,6 +4858,7 @@ var CodexSessionCollab = class {
3371
4858
  const agentPath = fill(existing?.agentPath, identity.agentPath);
3372
4859
  const role = fill(existing?.role, identity.role);
3373
4860
  const nickname = fill(existing?.nickname, identity.nickname);
4861
+ const parentThreadId = identity.parentThreadId !== void 0 && identity.parentThreadId.length > 0 ? identity.parentThreadId : existing?.parentThreadId;
3374
4862
  if (existing === void 0) {
3375
4863
  const spawnTurnId = this.runtime.activeTurnId;
3376
4864
  const child = {
@@ -3378,6 +4866,7 @@ var CodexSessionCollab = class {
3378
4866
  ...agentPath ? { agentPath } : {},
3379
4867
  ...role ? { role } : {},
3380
4868
  ...nickname ? { nickname } : {},
4869
+ ...parentThreadId ? { parentThreadId } : {},
3381
4870
  ...spawnTurnId ? { spawnTurnId } : {},
3382
4871
  status: "running"
3383
4872
  };
@@ -3386,14 +4875,15 @@ var CodexSessionCollab = class {
3386
4875
  this.startCollabChildMetaLookup(agentThreadId);
3387
4876
  return;
3388
4877
  }
3389
- if (agentPath === existing.agentPath && role === existing.role && nickname === existing.nickname) {
4878
+ if (agentPath === existing.agentPath && role === existing.role && nickname === existing.nickname && parentThreadId === existing.parentThreadId) {
3390
4879
  return;
3391
4880
  }
3392
4881
  const merged = {
3393
4882
  ...existing,
3394
4883
  ...agentPath ? { agentPath } : {},
3395
4884
  ...role ? { role } : {},
3396
- ...nickname ? { nickname } : {}
4885
+ ...nickname ? { nickname } : {},
4886
+ ...parentThreadId ? { parentThreadId } : {}
3397
4887
  };
3398
4888
  this.runtime.collabChildren.set(agentThreadId, merged);
3399
4889
  this.emitCollab("collabAgent/metadata", merged, { status: merged.status });
@@ -3437,9 +4927,9 @@ var CodexSessionCollab = class {
3437
4927
  { threadId: agentThreadId, excludeTurns: true },
3438
4928
  COLLAB_META_LOOKUP_TIMEOUT_MS
3439
4929
  ).then((response) => {
3440
- if (this.runtime.closed || meta.closed || !isRecord3(response)) return;
4930
+ if (this.runtime.closed || meta.closed || !isRecord2(response)) return;
3441
4931
  const thread = response["thread"];
3442
- if (!isRecord3(thread) || thread["id"] !== agentThreadId) return;
4932
+ if (!isRecord2(thread) || thread["id"] !== agentThreadId) return;
3443
4933
  this.updateCollabChildMeta(
3444
4934
  agentThreadId,
3445
4935
  { model: metaValue(response["model"]), effort: metaValue(response["reasoningEffort"]) },
@@ -3454,9 +4944,10 @@ var CodexSessionCollab = class {
3454
4944
  agentPath: child.agentPath,
3455
4945
  agentRole: child.role ?? pathLeaf(child.agentPath) ?? "general-purpose",
3456
4946
  agentNickname: child.nickname,
4947
+ ...child.parentThreadId && child.parentThreadId !== (this.runtime.nativeThreadId ?? this.runtime.threadId) ? { parentThreadId: child.parentThreadId } : {},
3457
4948
  ...meta?.model ? { model: meta.model } : {},
3458
4949
  ...meta?.effort ? { effort: meta.effort } : {},
3459
- ...isRecord3(extra) ? extra : {}
4950
+ ...isRecord2(extra) ? extra : {}
3460
4951
  };
3461
4952
  for (const event of mapNotificationToEvents({
3462
4953
  method,
@@ -3470,9 +4961,9 @@ var CodexSessionCollab = class {
3470
4961
  };
3471
4962
 
3472
4963
  // src/sessionRequests.ts
3473
- function cancelWireFor(pending) {
3474
- if (pending.kind === "permission") return toPermissionsResponse("cancel", pending.params, false);
3475
- return pending.kind === "mcp-elicitation" ? toMcpElicitationResponse("cancel", pending.params) : { decision: "cancel" };
4964
+ function cancelWireFor(pending2) {
4965
+ if (pending2.kind === "permission") return toPermissionsResponse("cancel", pending2.params, false);
4966
+ return pending2.kind === "mcp-elicitation" ? toMcpElicitationResponse("cancel", pending2.params) : { decision: "cancel" };
3476
4967
  }
3477
4968
  function unconfirmedAnswerError(requestId, delivery) {
3478
4969
  return new Error(
@@ -3526,7 +5017,7 @@ var CodexSessionRequests = class {
3526
5017
  method,
3527
5018
  params,
3528
5019
  "permission",
3529
- isRecord3(params) ? asString(params["itemId"]) ?? "permission" : "permission"
5020
+ isRecord2(params) ? asString(params["itemId"]) ?? "permission" : "permission"
3530
5021
  );
3531
5022
  return;
3532
5023
  }
@@ -3543,12 +5034,12 @@ var CodexSessionRequests = class {
3543
5034
  await this.runtime.rpc.respond(id, {});
3544
5035
  return;
3545
5036
  }
3546
- await new Promise((resolve2) => {
5037
+ await new Promise((resolve4) => {
3547
5038
  this.runtime.pendingUserInputs.set(requestId, {
3548
5039
  jsonRpcId: id,
3549
5040
  settle: (result) => {
3550
5041
  this.runtime.pendingUserInputs.delete(requestId);
3551
- void this.runtime.rpc.respond(id, result).catch((error) => this.#warnAnswerWriteFailed(method, id, error)).finally(resolve2);
5042
+ void this.runtime.rpc.respond(id, result).catch((error) => this.#warnAnswerWriteFailed(method, id, error)).finally(resolve4);
3552
5043
  }
3553
5044
  });
3554
5045
  for (const event of events) this.runtime.emit(event);
@@ -3573,7 +5064,7 @@ var CodexSessionRequests = class {
3573
5064
  providerInstanceId: this.runtime.host.instanceId
3574
5065
  });
3575
5066
  this.runtime.requestKinds.set(requestId, kind);
3576
- await new Promise((resolve2) => {
5067
+ await new Promise((resolve4) => {
3577
5068
  this.runtime.pendingApprovals.set(requestId, {
3578
5069
  jsonRpcId: id,
3579
5070
  method,
@@ -3582,35 +5073,35 @@ var CodexSessionRequests = class {
3582
5073
  identity,
3583
5074
  settle: (decision) => {
3584
5075
  this.runtime.pendingApprovals.delete(requestId);
3585
- void this.runtime.rpc.respond(id, decision).catch((error) => this.#warnAnswerWriteFailed(method, id, error)).finally(resolve2);
5076
+ void this.runtime.rpc.respond(id, decision).catch((error) => this.#warnAnswerWriteFailed(method, id, error)).finally(resolve4);
3586
5077
  },
3587
5078
  release: () => {
3588
5079
  this.runtime.pendingApprovals.delete(requestId);
3589
- resolve2();
5080
+ resolve4();
3590
5081
  }
3591
5082
  });
3592
5083
  for (const event of events) this.runtime.emit(event);
3593
5084
  });
3594
5085
  }
3595
5086
  async respondToRequest(requestId, decision, reason, persist) {
3596
- const pending = this.runtime.pendingApprovals.get(requestId);
3597
- if (!pending) throw new Error(`Unknown pending Codex approval request: ${requestId}`);
5087
+ const pending2 = this.runtime.pendingApprovals.get(requestId);
5088
+ if (!pending2) throw new Error(`Unknown pending Codex approval request: ${requestId}`);
3598
5089
  if (decision === "deny" && reason)
3599
5090
  this.runtime.declineRelay.queue(this.runtime.threadId, reason);
3600
5091
  let wire = { decision: decision === "allow" ? "accept" : "decline" };
3601
- if (decision === "allow" && pending.kind === "mcp-elicitation") {
3602
- wire = toMcpElicitationResponse("allow", pending.params);
5092
+ if (decision === "allow" && pending2.kind === "mcp-elicitation") {
5093
+ wire = toMcpElicitationResponse("allow", pending2.params);
3603
5094
  }
3604
- if (pending.kind === "permission") {
3605
- wire = toPermissionsResponse(decision, pending.params, persist !== void 0);
5095
+ if (pending2.kind === "permission") {
5096
+ wire = toPermissionsResponse(decision, pending2.params, persist !== void 0);
3606
5097
  } else if (decision === "allow" && persist) {
3607
- this.runtime.grants.remember(codexApprovalGrantKey(pending.kind, pending.identity), persist);
3608
- if (pending.kind !== "mcp-elicitation") {
3609
- wire = { decision: wireDecisionFromPersist(pending.kind, persist) };
5098
+ this.runtime.grants.remember(codexApprovalGrantKey(pending2.kind, pending2.identity), persist);
5099
+ if (pending2.kind !== "mcp-elicitation") {
5100
+ wire = { decision: wireDecisionFromPersist(pending2.kind, persist) };
3610
5101
  }
3611
5102
  }
3612
- const ack = this.runtime.registerWriteAck(pending.jsonRpcId);
3613
- pending.settle(wire);
5103
+ const ack = this.runtime.registerWriteAck(pending2.jsonRpcId);
5104
+ pending2.settle(wire);
3614
5105
  const delivery = await ack.catch(() => "closed");
3615
5106
  this.runtime.emit({
3616
5107
  eventId: nextEventId(),
@@ -3621,7 +5112,7 @@ var CodexSessionRequests = class {
3621
5112
  requestId,
3622
5113
  // requestType 是契约必填;缺了它宿主整条解不动,卡片停在「等待决议」。
3623
5114
  payload: {
3624
- requestType: toRequestTypeFromKind(pending.kind),
5115
+ requestType: toRequestTypeFromKind(pending2.kind),
3625
5116
  decision,
3626
5117
  ...reason ? { reason } : {}
3627
5118
  }
@@ -3629,14 +5120,14 @@ var CodexSessionRequests = class {
3629
5120
  if (delivery !== "written") throw unconfirmedAnswerError(requestId, delivery);
3630
5121
  }
3631
5122
  async respondToUserInput(requestId, answers) {
3632
- const pending = this.runtime.pendingUserInputs.get(requestId);
3633
- if (!pending) throw new Error(`Unknown pending Codex user input request: ${requestId}`);
5123
+ const pending2 = this.runtime.pendingUserInputs.get(requestId);
5124
+ if (!pending2) throw new Error(`Unknown pending Codex user input request: ${requestId}`);
3634
5125
  const mapped = toCodexUserInputAnswers(answers);
3635
5126
  if (mapped === void 0) {
3636
5127
  throw new Error(`invalid user input answers for request ${requestId}`);
3637
5128
  }
3638
- const ack = this.runtime.registerWriteAck(pending.jsonRpcId);
3639
- pending.settle({ answers: mapped });
5129
+ const ack = this.runtime.registerWriteAck(pending2.jsonRpcId);
5130
+ pending2.settle({ answers: mapped });
3640
5131
  const delivery = await ack.catch(() => "closed");
3641
5132
  this.runtime.emit({
3642
5133
  eventId: nextEventId(),
@@ -3652,8 +5143,8 @@ var CodexSessionRequests = class {
3652
5143
  }
3653
5144
  /** 把还挂着的审批答成「取消」,逐条发 request.resolved。 */
3654
5145
  cancelPendingApprovals() {
3655
- for (const [requestId, pending] of this.runtime.pendingApprovals) {
3656
- pending.settle(cancelWireFor(pending));
5146
+ for (const [requestId, pending2] of this.runtime.pendingApprovals) {
5147
+ pending2.settle(cancelWireFor(pending2));
3657
5148
  this.runtime.emit({
3658
5149
  eventId: nextEventId(),
3659
5150
  provider: CODEX_DRIVER_KIND,
@@ -3661,20 +5152,20 @@ var CodexSessionRequests = class {
3661
5152
  createdAt: nowIso(),
3662
5153
  type: "request.resolved",
3663
5154
  requestId,
3664
- payload: { requestType: toRequestTypeFromKind(pending.kind), decision: "cancel" }
5155
+ payload: { requestType: toRequestTypeFromKind(pending2.kind), decision: "cancel" }
3665
5156
  });
3666
5157
  }
3667
5158
  }
3668
5159
  /** 会话收口时把还挂着的审批答成「取消」:应答形状按审批种类,权限审批不认 decision。 */
3669
5160
  settlePendingApprovals() {
3670
- for (const [requestId, pending] of this.runtime.pendingApprovals) {
3671
- pending.settle(cancelWireFor(pending));
5161
+ for (const [requestId, pending2] of this.runtime.pendingApprovals) {
5162
+ pending2.settle(cancelWireFor(pending2));
3672
5163
  this.runtime.pendingApprovals.delete(requestId);
3673
5164
  }
3674
5165
  }
3675
5166
  settlePendingUserInputs(result) {
3676
- for (const [requestId, pending] of this.runtime.pendingUserInputs) {
3677
- pending.settle(result);
5167
+ for (const [requestId, pending2] of this.runtime.pendingUserInputs) {
5168
+ pending2.settle(result);
3678
5169
  this.runtime.pendingUserInputs.delete(requestId);
3679
5170
  }
3680
5171
  }
@@ -3692,8 +5183,8 @@ async function markProviderRejection(run) {
3692
5183
  }
3693
5184
 
3694
5185
  // src/sessionRuntime.ts
3695
- var sleep = (ms) => new Promise((resolve2) => {
3696
- setTimeout(resolve2, ms);
5186
+ var sleep = (ms) => new Promise((resolve4) => {
5187
+ setTimeout(resolve4, ms);
3697
5188
  });
3698
5189
  var CodexSessionRuntime = class {
3699
5190
  threadId;
@@ -3747,7 +5238,7 @@ var CodexSessionRuntime = class {
3747
5238
  * 对外 requestId 的前缀,每个会话(即每个 app-server 进程)一份。JSON-RPC id 每个进程
3748
5239
  * 都从 0 数起,宿主按 requestId 记「已接受」,不加前缀的话重启后的新请求会撞上旧请求。
3749
5240
  */
3750
- #requestIdPrefix = `codex-${NodeCrypto2.randomUUID()}:`;
5241
+ #requestIdPrefix = `codex-${NodeCrypto4.randomUUID()}:`;
3751
5242
  /** JSON-RPC id → 对外 requestId。`serverRequest/resolved` 里的 id 可能是数字也可能是字符串。 */
3752
5243
  requestIdFor(jsonRpcId) {
3753
5244
  return `${this.#requestIdPrefix}${String(jsonRpcId)}`;
@@ -3800,8 +5291,8 @@ var CodexSessionRuntime = class {
3800
5291
  }
3801
5292
  registerWriteAck(jsonRpcId) {
3802
5293
  if (this.closing) return Promise.resolve("closed");
3803
- return new Promise((resolve2) => {
3804
- this.writeAcks.set(jsonRpcId, { resolve: resolve2 });
5294
+ return new Promise((resolve4) => {
5295
+ this.writeAcks.set(jsonRpcId, { resolve: resolve4 });
3805
5296
  });
3806
5297
  }
3807
5298
  settleNativeWrite(requestId, status) {
@@ -3818,11 +5309,11 @@ var CodexSessionRuntime = class {
3818
5309
  async confirmAfterNativeWrite(jsonRpcId) {
3819
5310
  const existing = this.writeAcks.get(jsonRpcId);
3820
5311
  if (existing) {
3821
- return await new Promise((resolve2) => {
5312
+ return await new Promise((resolve4) => {
3822
5313
  const previous = existing.resolve;
3823
5314
  existing.resolve = (status) => {
3824
5315
  previous(status);
3825
- resolve2(status);
5316
+ resolve4(status);
3826
5317
  };
3827
5318
  });
3828
5319
  }
@@ -3862,7 +5353,7 @@ var CodexSessionRuntime = class {
3862
5353
  return;
3863
5354
  }
3864
5355
  if (method === "thread/started") {
3865
- const name = isRecord3(params) ? asString(params["name"]) ?? (isRecord3(params["thread"]) ? asString(params["thread"]["name"]) : null) : null;
5356
+ const name = isRecord2(params) ? asString(params["name"]) ?? (isRecord2(params["thread"]) ? asString(params["thread"]["name"]) : null) : null;
3866
5357
  if (isMemoryConsolidationThread(name ?? void 0) && conversationId) {
3867
5358
  this.memoryThreadIds.add(conversationId);
3868
5359
  return;
@@ -3870,18 +5361,20 @@ var CodexSessionRuntime = class {
3870
5361
  }
3871
5362
  const activity = readSubAgentActivity(method, params);
3872
5363
  if (activity?.agentThreadId !== void 0 && !isRootChild(activity.agentPath, activity.agentThreadId, this.nativeThreadId ?? this.threadId)) {
3873
- this.#collab.upsertCollabChild(activity.agentThreadId, { agentPath: activity.agentPath });
5364
+ this.#collab.upsertCollabChild(activity.agentThreadId, {
5365
+ agentPath: activity.agentPath
5366
+ });
3874
5367
  }
3875
5368
  this.dispatchMapped(method, params);
3876
5369
  }
3877
5370
  dispatchMapped(method, params) {
3878
5371
  if (method === "serverRequest/resolved") {
3879
- const rawId = isRecord3(params) ? params["requestId"] : void 0;
5372
+ const rawId = isRecord2(params) ? params["requestId"] : void 0;
3880
5373
  if (typeof rawId !== "number" && typeof rawId !== "string") return;
3881
5374
  const resolvedId = this.requestIdFor(rawId);
3882
- const pending = this.pendingApprovals.get(resolvedId);
3883
- if (pending === void 0) return;
3884
- pending.release();
5375
+ const pending2 = this.pendingApprovals.get(resolvedId);
5376
+ if (pending2 === void 0) return;
5377
+ pending2.release();
3885
5378
  this.emit({
3886
5379
  eventId: nextEventId(),
3887
5380
  provider: CODEX_DRIVER_KIND,
@@ -3897,7 +5390,7 @@ var CodexSessionRuntime = class {
3897
5390
  return;
3898
5391
  }
3899
5392
  trackOpenCommand(this.openCommands, method, params);
3900
- if (method === "account/rateLimits/updated" && isRecord3(params)) {
5393
+ if (method === "account/rateLimits/updated" && isRecord2(params)) {
3901
5394
  this.rateLimits = mergeCodexRateLimits(this.rateLimits, params["rateLimits"]);
3902
5395
  }
3903
5396
  for (const event of mapNotificationToEvents({
@@ -4022,7 +5515,7 @@ var CodexSessionRuntime = class {
4022
5515
  async #imageInputs(attachments) {
4023
5516
  const items = [];
4024
5517
  for (const attachment of attachments ?? []) {
4025
- if (!isRecord3(attachment) || attachment["type"] !== "image") continue;
5518
+ if (!isRecord2(attachment) || attachment["type"] !== "image") continue;
4026
5519
  const id = asString(attachment["id"]);
4027
5520
  const mimeType = asString(attachment["mimeType"]);
4028
5521
  if (!id || !mimeType) {
@@ -4141,10 +5634,10 @@ var CodexSessionRuntime = class {
4141
5634
  },
4142
5635
  0
4143
5636
  );
4144
- const thread = isRecord3(result) && isRecord3(result["thread"]) ? result["thread"] : null;
5637
+ const thread = isRecord2(result) && isRecord2(result["thread"]) ? result["thread"] : null;
4145
5638
  const turnsRaw = thread && Array.isArray(thread["turns"]) ? thread["turns"] : [];
4146
5639
  const turns = turnsRaw.flatMap((turn) => {
4147
- if (!isRecord3(turn)) return [];
5640
+ if (!isRecord2(turn)) return [];
4148
5641
  const id = asString(turn["id"]);
4149
5642
  if (!id) return [];
4150
5643
  return [{ id, items: Array.isArray(turn["items"]) ? turn["items"] : [] }];
@@ -4208,216 +5701,14 @@ var EventBus = class {
4208
5701
  const queued = this.#queued.shift();
4209
5702
  if (queued !== void 0) return Promise.resolve({ done: false, value: queued });
4210
5703
  if (this.#closed) return Promise.resolve({ done: true, value: void 0 });
4211
- return new Promise((resolve2) => {
4212
- this.#waiters.push(resolve2);
5704
+ return new Promise((resolve4) => {
5705
+ this.#waiters.push(resolve4);
4213
5706
  });
4214
5707
  }
4215
5708
  };
4216
5709
  }
4217
5710
  };
4218
5711
 
4219
- // src/sessions.ts
4220
- import * as NodeFS3 from "node:fs";
4221
- import * as NodePath4 from "node:path";
4222
- import * as NodeReadline from "node:readline";
4223
- var EXTENDED_LENGTH_UNC = "//?/UNC/";
4224
- var EXTENDED_LENGTH = "//?/";
4225
- function normalize(value, caseInsensitive) {
4226
- let unified = value.trim().replace(/\\/gu, "/");
4227
- const upper = unified.toUpperCase();
4228
- if (upper.startsWith(EXTENDED_LENGTH_UNC)) {
4229
- unified = `//${unified.slice(EXTENDED_LENGTH_UNC.length)}`;
4230
- } else if (upper.startsWith(EXTENDED_LENGTH)) {
4231
- unified = unified.slice(EXTENDED_LENGTH.length);
4232
- }
4233
- const isUnc = unified.startsWith("//");
4234
- unified = unified.replace(/\/+/gu, "/").replace(/\/+$/u, "");
4235
- if (isUnc) unified = `/${unified}`;
4236
- return caseInsensitive ? unified.toLowerCase() : unified;
4237
- }
4238
- function isWithinDirectory(candidate, root, caseInsensitive) {
4239
- const normalizedRoot = normalize(root, caseInsensitive);
4240
- if (normalizedRoot.length === 0 || normalizedRoot === "/") return false;
4241
- const normalizedCandidate = normalize(candidate, caseInsensitive);
4242
- return normalizedCandidate === normalizedRoot || normalizedCandidate.startsWith(`${normalizedRoot}/`);
4243
- }
4244
- var PAGE_LIMIT = 50;
4245
- var MAX_PAGES = 10;
4246
- var MAX_ROWS = 50;
4247
- var PREVIEW_LIMIT = 200;
4248
- function truncate(value) {
4249
- const trimmed = value?.trim() ?? "";
4250
- if (trimmed.length === 0) return null;
4251
- return trimmed.length <= PREVIEW_LIMIT ? trimmed : `${trimmed.slice(0, PREVIEW_LIMIT)}\u2026`;
4252
- }
4253
- var nativeModel = (value) => {
4254
- const model = asString(value)?.trim();
4255
- return model && model !== "<synthetic>" ? model : null;
4256
- };
4257
- function readListPage(response) {
4258
- if (!response || typeof response !== "object") return { threads: [], nextCursor: null };
4259
- const typed = response;
4260
- const rows = Array.isArray(typed.data) ? typed.data : [];
4261
- const threads = [];
4262
- for (const row of rows) {
4263
- if (!isRecord3(row)) continue;
4264
- if (typeof row.id !== "string" || typeof row.cwd !== "string") continue;
4265
- threads.push({
4266
- id: row.id,
4267
- cwd: row.cwd,
4268
- name: asString(row.name),
4269
- preview: asString(row.preview),
4270
- model: asString(row.model),
4271
- updatedAt: typeof row.updatedAt === "number" ? row.updatedAt : 0
4272
- });
4273
- }
4274
- return { threads, nextCursor: asString(typed.nextCursor) };
4275
- }
4276
- function readThreadTurns(response) {
4277
- if (!isRecord3(response)) return [];
4278
- const thread = isRecord3(response.thread) ? response.thread : null;
4279
- if (!thread) return [];
4280
- const turns = Array.isArray(thread.turns) ? thread.turns : [];
4281
- return turns.flatMap((turn) => {
4282
- if (!isRecord3(turn)) return [];
4283
- return [
4284
- {
4285
- ...typeof turn.id === "string" && turn.id.length > 0 ? { id: turn.id } : {},
4286
- ...typeof turn.model === "string" && turn.model.length > 0 ? { model: turn.model } : {},
4287
- startedAt: typeof turn.startedAt === "number" ? turn.startedAt : null,
4288
- items: Array.isArray(turn.items) ? turn.items : []
4289
- }
4290
- ];
4291
- });
4292
- }
4293
- function itemText(item) {
4294
- if (!isRecord3(item)) return void 0;
4295
- const type = (asString(item.type) ?? "").toLowerCase();
4296
- const text = asString(item.text) ?? asString(item.content) ?? (Array.isArray(item.content) ? item.content.map((entry) => isRecord3(entry) ? asString(entry.text) : null).filter((entry) => typeof entry === "string").join("\n") : null);
4297
- if (!text || text.trim().length === 0) return void 0;
4298
- if (type.includes("user")) return { role: "user", text };
4299
- if (type.includes("agent") || type.includes("assistant")) return { role: "assistant", text };
4300
- if (type.includes("system")) return { role: "system", text };
4301
- return void 0;
4302
- }
4303
- async function scanCodexSessions(input) {
4304
- const threads = [];
4305
- let cursor = null;
4306
- for (let page = 0; page < MAX_PAGES && threads.length < MAX_ROWS; page += 1) {
4307
- const listed = readListPage(
4308
- await input.client.request("thread/list", {
4309
- limit: PAGE_LIMIT,
4310
- sortKey: "updated_at",
4311
- sortDirection: "desc",
4312
- ...cursor === null ? {} : { cursor }
4313
- })
4314
- );
4315
- for (const thread of listed.threads) {
4316
- if (!isWithinDirectory(thread.cwd, input.directory, input.caseInsensitive)) continue;
4317
- threads.push(thread);
4318
- if (threads.length >= MAX_ROWS) break;
4319
- }
4320
- if (listed.nextCursor === null || listed.nextCursor.length === 0) break;
4321
- cursor = listed.nextCursor;
4322
- }
4323
- const rows = [];
4324
- for (const thread of threads) {
4325
- const turnCount = await input.client.request("thread/read", { threadId: thread.id, includeTurns: true }).then((response) => readThreadTurns(response).length).catch(() => 0);
4326
- rows.push({
4327
- nativeSessionId: thread.id,
4328
- cwd: thread.cwd,
4329
- title: truncate(thread.name),
4330
- preview: truncate(thread.preview),
4331
- model: truncate(thread.model),
4332
- turnCount,
4333
- updatedAt: thread.updatedAt * 1e3,
4334
- availability: "importable",
4335
- openElsewhere: false
4336
- });
4337
- }
4338
- return rows;
4339
- }
4340
- async function readCodexSession(input) {
4341
- const response = await input.client.request("thread/read", {
4342
- threadId: input.threadId,
4343
- includeTurns: true
4344
- });
4345
- const record = isRecord3(response) ? response : null;
4346
- const thread = record && isRecord3(record.thread) ? record.thread : null;
4347
- const path = input.caseInsensitive ? NodePath4.win32 : NodePath4;
4348
- const sameDirectory = (left, right) => isWithinDirectory(path.resolve(left), path.resolve(right), input.caseInsensitive) && isWithinDirectory(path.resolve(right), path.resolve(left), input.caseInsensitive);
4349
- if (!isRecord3(thread) || thread.id !== input.threadId || typeof thread.cwd !== "string" || !path.isAbsolute(thread.cwd) || !path.isAbsolute(input.cwd) || !sameDirectory(thread.cwd, input.cwd)) {
4350
- throw new Error("The native Codex session does not match the requested session and directory.");
4351
- }
4352
- const model = nativeModel(thread.model) ?? await readRolloutModel(
4353
- {
4354
- threadId: input.threadId,
4355
- cwd: input.cwd,
4356
- homePath: input.homePath,
4357
- caseInsensitive: input.caseInsensitive
4358
- },
4359
- thread.path,
4360
- sameDirectory
4361
- );
4362
- const messages = [];
4363
- for (const turn of readThreadTurns(response)) {
4364
- for (const item of turn.items) {
4365
- const mapped = itemText(item);
4366
- if (mapped) {
4367
- messages.push({
4368
- ...mapped,
4369
- ...typeof turn.startedAt === "number" ? { createdAt: turn.startedAt * 1e3 } : {}
4370
- });
4371
- }
4372
- }
4373
- }
4374
- return {
4375
- nativeSessionId: input.threadId,
4376
- messages,
4377
- resumeCursor: { threadId: input.threadId },
4378
- model
4379
- };
4380
- }
4381
- async function readRolloutModel(input, rolloutPath, sameDirectory) {
4382
- const path = input.caseInsensitive ? NodePath4.win32 : NodePath4;
4383
- if (typeof rolloutPath !== "string" || !path.isAbsolute(rolloutPath) || path.extname(rolloutPath).toLowerCase() !== ".jsonl") {
4384
- return null;
4385
- }
4386
- const resolved = path.resolve(rolloutPath);
4387
- const roots = input.homePath ? [path.join(input.homePath, "sessions"), path.join(input.homePath, "archived_sessions")] : [];
4388
- if (!roots.some((root) => isWithinDirectory(resolved, path.resolve(root), input.caseInsensitive))) {
4389
- return null;
4390
- }
4391
- let verified = false;
4392
- let model = null;
4393
- try {
4394
- const stream = NodeFS3.createReadStream(resolved, { encoding: "utf8" });
4395
- const rl = NodeReadline.createInterface({ input: stream, crlfDelay: Infinity });
4396
- for await (const line of rl) {
4397
- if (!line.includes('"session_meta"') && !line.includes('"turn_context"')) continue;
4398
- let record;
4399
- try {
4400
- record = isRecord3(JSON.parse(line)) ? JSON.parse(line) : null;
4401
- } catch {
4402
- continue;
4403
- }
4404
- const payload = isRecord3(record?.payload) ? record.payload : null;
4405
- if (!record || !payload) continue;
4406
- if (record.type === "session_meta" && !verified) {
4407
- if ((payload.id ?? payload.session_id) !== input.threadId || typeof payload.cwd !== "string" || !path.isAbsolute(payload.cwd) || !sameDirectory(payload.cwd, input.cwd)) {
4408
- return null;
4409
- }
4410
- verified = true;
4411
- } else if (record.type === "turn_context" && verified) {
4412
- model = nativeModel(payload.model) ?? model;
4413
- }
4414
- }
4415
- } catch {
4416
- return null;
4417
- }
4418
- return model;
4419
- }
4420
-
4421
5712
  // src/mcpOAuth.ts
4422
5713
  function codexMcpOAuthLaunchConfig(name, transport) {
4423
5714
  const key = `mcp_servers.${name}`;
@@ -4457,13 +5748,13 @@ async function startCodexMcpOAuth(input) {
4457
5748
  env
4458
5749
  });
4459
5750
  let settle;
4460
- const completed = new Promise((resolve2) => {
4461
- settle = resolve2;
5751
+ const completed = new Promise((resolve4) => {
5752
+ settle = resolve4;
4462
5753
  });
4463
5754
  const rpc = await createCodexRpcClient(handle, {
4464
5755
  onNotification: (notification) => {
4465
5756
  if (notification.method !== "mcpServer/oauthLogin/completed") return;
4466
- const params = isRecord3(notification.params) ? notification.params : {};
5757
+ const params = isRecord2(notification.params) ? notification.params : {};
4467
5758
  if (asString(params["name"]) !== input.server.name) return;
4468
5759
  const error = asString(params["error"]);
4469
5760
  settle?.({
@@ -4485,7 +5776,7 @@ async function startCodexMcpOAuth(input) {
4485
5776
  name: input.server.name,
4486
5777
  ...input.timeoutSecs === void 0 ? {} : { timeoutSecs: input.timeoutSecs }
4487
5778
  });
4488
- const authorizationUrl = isRecord3(response) ? asString(response["authorizationUrl"]) : void 0;
5779
+ const authorizationUrl = isRecord2(response) ? asString(response["authorizationUrl"]) : void 0;
4489
5780
  if (!authorizationUrl) {
4490
5781
  await close();
4491
5782
  throw new Error(`Codex did not return an authorization URL for '${input.server.name}'.`);
@@ -4511,7 +5802,7 @@ function reasoningDescriptor(row) {
4511
5802
  if (!Array.isArray(supported) || supported.length === 0) return null;
4512
5803
  const defaultEffort = asString(row["defaultReasoningEffort"]);
4513
5804
  const options = supported.flatMap((entry) => {
4514
- if (!isRecord3(entry)) return [];
5805
+ if (!isRecord2(entry)) return [];
4515
5806
  const id = asString(entry["reasoningEffort"]);
4516
5807
  if (!id) return [];
4517
5808
  const description = asString(entry["description"]);
@@ -4536,7 +5827,7 @@ function reasoningDescriptor(row) {
4536
5827
  function serviceTierDescriptor(row) {
4537
5828
  const declared = Array.isArray(row["serviceTiers"]) ? row["serviceTiers"] : [];
4538
5829
  const tiers = declared.length > 0 ? declared.flatMap((entry) => {
4539
- if (!isRecord3(entry)) return [];
5830
+ if (!isRecord2(entry)) return [];
4540
5831
  const id = asString(entry["id"]);
4541
5832
  if (!id) return [];
4542
5833
  const name = asString(entry["name"]);
@@ -4572,7 +5863,7 @@ function serviceTierDescriptor(row) {
4572
5863
  };
4573
5864
  }
4574
5865
  function codexProbeModel(row) {
4575
- if (!isRecord3(row)) return null;
5866
+ if (!isRecord2(row)) return null;
4576
5867
  const slug = asString(row["model"]);
4577
5868
  if (!slug) return null;
4578
5869
  const displayName = asString(row["displayName"]);
@@ -4603,7 +5894,7 @@ async function listCodexModels(rpc) {
4603
5894
  } catch {
4604
5895
  return void 0;
4605
5896
  }
4606
- if (!isRecord3(response) || !Array.isArray(response["data"])) return void 0;
5897
+ if (!isRecord2(response) || !Array.isArray(response["data"])) return void 0;
4607
5898
  for (const row of response["data"]) {
4608
5899
  const model = codexProbeModel(row);
4609
5900
  if (model !== null) models.push(model);
@@ -4618,12 +5909,12 @@ async function listCodexModels(rpc) {
4618
5909
  // src/skills.ts
4619
5910
  var SKILLS_LIST_TIMEOUT_MS = 15e3;
4620
5911
  function codexProbeSkill(raw, includeRepo = false) {
4621
- if (!isRecord3(raw)) return null;
5912
+ if (!isRecord2(raw)) return null;
4622
5913
  const name = asString(raw["name"]);
4623
5914
  const path = asString(raw["path"]);
4624
5915
  const scope = asString(raw["scope"]);
4625
5916
  if (!name || !path || scope === "repo" && !includeRepo) return null;
4626
- const face = isRecord3(raw["interface"]) ? raw["interface"] : void 0;
5917
+ const face = isRecord2(raw["interface"]) ? raw["interface"] : void 0;
4627
5918
  const description = asString(raw["description"]);
4628
5919
  const displayName = asString(face?.["displayName"]);
4629
5920
  const shortDescription = asString(face?.["shortDescription"]) || asString(raw["shortDescription"]);
@@ -4639,12 +5930,12 @@ function codexProbeSkill(raw, includeRepo = false) {
4639
5930
  }
4640
5931
  async function listCodexWorkspaceSkills(rpc, cwd) {
4641
5932
  const response = await rpc.request("skills/list", { cwds: [cwd] }, SKILLS_LIST_TIMEOUT_MS);
4642
- if (!isRecord3(response) || !Array.isArray(response["data"])) {
5933
+ if (!isRecord2(response) || !Array.isArray(response["data"])) {
4643
5934
  throw new Error("skills/list returned an unexpected shape");
4644
5935
  }
4645
5936
  const skills = /* @__PURE__ */ new Map();
4646
5937
  for (const entry of response["data"]) {
4647
- if (!isRecord3(entry) || !Array.isArray(entry["skills"])) continue;
5938
+ if (!isRecord2(entry) || !Array.isArray(entry["skills"])) continue;
4648
5939
  for (const raw of entry["skills"]) {
4649
5940
  const skill = codexProbeSkill(raw, true);
4650
5941
  if (skill !== null) skills.set(skill.path, skill);
@@ -4659,10 +5950,10 @@ async function listCodexSkills(rpc) {
4659
5950
  } catch {
4660
5951
  return void 0;
4661
5952
  }
4662
- if (!isRecord3(response) || !Array.isArray(response["data"])) return void 0;
5953
+ if (!isRecord2(response) || !Array.isArray(response["data"])) return void 0;
4663
5954
  const skills = /* @__PURE__ */ new Map();
4664
5955
  for (const entry of response["data"]) {
4665
- if (!isRecord3(entry) || !Array.isArray(entry["skills"])) continue;
5956
+ if (!isRecord2(entry) || !Array.isArray(entry["skills"])) continue;
4666
5957
  for (const raw of entry["skills"]) {
4667
5958
  const skill = codexProbeSkill(raw);
4668
5959
  if (skill !== null) skills.set(skill.path, skill);
@@ -4683,25 +5974,25 @@ async function setCodexSessionSkillRoots(rpc, skills, log, threadId) {
4683
5974
  }
4684
5975
 
4685
5976
  // src/workspaceInventory.ts
4686
- import * as NodeFS4 from "node:fs";
4687
- import * as NodePath5 from "node:path";
5977
+ import * as NodeFS6 from "node:fs";
5978
+ import * as NodePath8 from "node:path";
4688
5979
  var MAX_ANCESTORS = 12;
4689
5980
  var codexWorkspaceWatchPaths = (cwd, skills) => {
4690
5981
  const watched = /* @__PURE__ */ new Set();
4691
5982
  let directory = cwd;
4692
5983
  for (let level = 0; level < MAX_ANCESTORS; level += 1) {
4693
- watched.add(NodePath5.join(directory, ".agents", "skills"));
4694
- watched.add(NodePath5.join(directory, ".codex", "skills"));
4695
- if (NodeFS4.existsSync(NodePath5.join(directory, ".git"))) break;
4696
- const parent = NodePath5.dirname(directory);
5984
+ watched.add(NodePath8.join(directory, ".agents", "skills"));
5985
+ watched.add(NodePath8.join(directory, ".codex", "skills"));
5986
+ if (NodeFS6.existsSync(NodePath8.join(directory, ".git"))) break;
5987
+ const parent = NodePath8.dirname(directory);
4697
5988
  if (parent === directory) break;
4698
5989
  directory = parent;
4699
5990
  }
4700
5991
  for (const skill of skills) {
4701
5992
  watched.add(skill.path);
4702
- const skillDirectory = NodePath5.dirname(skill.path);
5993
+ const skillDirectory = NodePath8.dirname(skill.path);
4703
5994
  watched.add(skillDirectory);
4704
- watched.add(NodePath5.dirname(skillDirectory));
5995
+ watched.add(NodePath8.dirname(skillDirectory));
4705
5996
  }
4706
5997
  return [...watched];
4707
5998
  };
@@ -4803,7 +6094,7 @@ async function startCodexSignIn(input) {
4803
6094
  const rpc = await createCodexRpcClient(handle2, {
4804
6095
  onNotification: (notification) => {
4805
6096
  if (notification.method !== "account/login/completed") return;
4806
- const params = isRecord3(notification.params) ? notification.params : {};
6097
+ const params = isRecord2(notification.params) ? notification.params : {};
4807
6098
  const loginId = asString(params["loginId"]);
4808
6099
  receiveCompletion({
4809
6100
  loginId,
@@ -4830,7 +6121,7 @@ async function startCodexSignIn(input) {
4830
6121
  rpc.request("account/login/start", { type: "chatgptDeviceCode" }),
4831
6122
  lifetime.signal
4832
6123
  );
4833
- if (!isRecord3(started) || asString(started["type"]) !== "chatgptDeviceCode") {
6124
+ if (!isRecord2(started) || asString(started["type"]) !== "chatgptDeviceCode") {
4834
6125
  await closeSignInRpc(rpc, input.host, handle2);
4835
6126
  return void 0;
4836
6127
  }
@@ -4892,7 +6183,7 @@ async function startCodexSignIn(input) {
4892
6183
  const combined2 = `${stdout.text}
4893
6184
  ${stderr.text}`;
4894
6185
  if (deviceCodeUrl(combined2) && deviceCodeValue(combined2)) break;
4895
- await new Promise((resolve2) => setTimeout(resolve2, 50));
6186
+ await new Promise((resolve4) => setTimeout(resolve4, 50));
4896
6187
  }
4897
6188
  const combined = `${stdout.text}
4898
6189
  ${stderr.text}`;
@@ -4970,8 +6261,8 @@ async function verifyCodexSignIn(input) {
4970
6261
  );
4971
6262
  await rpc.notify("initialized");
4972
6263
  const account = await rpc.request("account/read", { refreshToken: true }, 15e3);
4973
- const details = isRecord3(account) && isRecord3(account["account"]) ? account["account"] : account;
4974
- const type = isRecord3(details) ? asString(details["type"]) : null;
6264
+ const details = isRecord2(account) && isRecord2(account["account"]) ? account["account"] : account;
6265
+ const type = isRecord2(details) ? asString(details["type"]) : null;
4975
6266
  if (type !== "chatgpt") {
4976
6267
  return {
4977
6268
  installed: true,
@@ -4989,7 +6280,7 @@ async function verifyCodexSignIn(input) {
4989
6280
  auth: {
4990
6281
  ...auth,
4991
6282
  status: "authenticated",
4992
- ...isRecord3(details) && asString(details["email"]) ? { email: asString(details["email"]) } : {}
6283
+ ...isRecord2(details) && asString(details["email"]) ? { email: asString(details["email"]) } : {}
4993
6284
  },
4994
6285
  ...models === void 0 ? {} : { models },
4995
6286
  ...CODEX_NATIVE_MODE_REPORT
@@ -5069,9 +6360,9 @@ function buildTurnSummaryPrompt(raw) {
5069
6360
  }
5070
6361
 
5071
6362
  // src/textGeneration.ts
5072
- import * as NodeFSP2 from "node:fs/promises";
6363
+ import * as NodeFSP5 from "node:fs/promises";
5073
6364
  import * as NodeOS3 from "node:os";
5074
- import * as NodePath6 from "node:path";
6365
+ import * as NodePath9 from "node:path";
5075
6366
  import {
5076
6367
  mergeLaunchEnv as mergeLaunchEnv2
5077
6368
  } from "@ycodium-ai/plugin-api/executor";
@@ -5098,7 +6389,7 @@ function unwrapNestedTitleObject(raw) {
5098
6389
  if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) return raw;
5099
6390
  try {
5100
6391
  const parsed = JSON.parse(trimmed);
5101
- if (isRecord3(parsed) && typeof parsed.title === "string") return parsed.title;
6392
+ if (isRecord2(parsed) && typeof parsed.title === "string") return parsed.title;
5102
6393
  } catch {
5103
6394
  }
5104
6395
  return raw;
@@ -5221,9 +6512,9 @@ function absoluteImagePaths(attachments) {
5221
6512
  if (!Array.isArray(attachments)) return [];
5222
6513
  const paths = [];
5223
6514
  for (const attachment of attachments) {
5224
- if (!isRecord3(attachment) || attachment.type !== "image") continue;
6515
+ if (!isRecord2(attachment) || attachment.type !== "image") continue;
5225
6516
  const candidate = asString(attachment.path) ?? asString(attachment.filePath) ?? asString(attachment.savedPath);
5226
- if (candidate && NodePath6.isAbsolute(candidate)) paths.push(candidate);
6517
+ if (candidate && NodePath9.isAbsolute(candidate)) paths.push(candidate);
5227
6518
  }
5228
6519
  return paths;
5229
6520
  }
@@ -5238,11 +6529,11 @@ function createCodexTextGeneration(input) {
5238
6529
  if (input.recipe.binaryPath.length === 0) {
5239
6530
  throw new Error("Codex CLI is required but not available on PATH.");
5240
6531
  }
5241
- const tmp = await NodeFSP2.mkdtemp(NodePath6.join(NodeOS3.tmpdir(), "ycodium-codex-tg-"));
5242
- const schemaPath = NodePath6.join(tmp, "schema.json");
5243
- const outputPath = NodePath6.join(tmp, "output.json");
5244
- await NodeFSP2.writeFile(schemaPath, JSON.stringify(schema));
5245
- await NodeFSP2.writeFile(outputPath, "");
6532
+ const tmp = await NodeFSP5.mkdtemp(NodePath9.join(NodeOS3.tmpdir(), "ycodium-codex-tg-"));
6533
+ const schemaPath = NodePath9.join(tmp, "schema.json");
6534
+ const outputPath = NodePath9.join(tmp, "output.json");
6535
+ await NodeFSP5.writeFile(schemaPath, JSON.stringify(schema));
6536
+ await NodeFSP5.writeFile(outputPath, "");
5246
6537
  const reasoningEffort = modelSelectionStringOption(modelSelection, "reasoningEffort") ?? DEFAULT_TEXT_GENERATION_REASONING_EFFORT;
5247
6538
  const serviceTier = modelSelectionStringOption(modelSelection, "serviceTier");
5248
6539
  const model = modelIdFromSelection(modelSelection) ?? "gpt-5.6-luna";
@@ -5286,8 +6577,8 @@ function createCodexTextGeneration(input) {
5286
6577
  await handle.closeStdin();
5287
6578
  const timedOut = await Promise.race([
5288
6579
  handle.exited.then(() => false),
5289
- new Promise((resolve2) => {
5290
- timer = setTimeout(() => resolve2(true), CODEX_TIMEOUT_MS);
6580
+ new Promise((resolve4) => {
6581
+ timer = setTimeout(() => resolve4(true), CODEX_TIMEOUT_MS);
5291
6582
  })
5292
6583
  ]);
5293
6584
  if (timedOut) {
@@ -5305,27 +6596,27 @@ function createCodexTextGeneration(input) {
5305
6596
  detail.length > 0 ? `Codex CLI command failed: ${detail}` : `Codex CLI command failed with code ${String(exitCode)}.`
5306
6597
  );
5307
6598
  }
5308
- const raw = await NodeFSP2.readFile(outputPath, "utf8");
6599
+ const raw = await NodeFSP5.readFile(outputPath, "utf8");
5309
6600
  let parsed;
5310
6601
  try {
5311
6602
  parsed = JSON.parse(raw);
5312
6603
  } catch (cause) {
5313
6604
  throw new Error("Codex returned invalid structured output.", { cause });
5314
6605
  }
5315
- if (!isRecord3(parsed)) throw new Error("Codex returned invalid structured output.");
6606
+ if (!isRecord2(parsed)) throw new Error("Codex returned invalid structured output.");
5316
6607
  return parsed;
5317
6608
  } finally {
5318
6609
  if (timer !== void 0) clearTimeout(timer);
5319
6610
  signal?.removeEventListener("abort", onAbort);
5320
- await NodeFSP2.rm(tmp, { recursive: true, force: true }).catch(() => void 0);
6611
+ await NodeFSP5.rm(tmp, { recursive: true, force: true }).catch(() => void 0);
5321
6612
  void operation;
5322
6613
  }
5323
6614
  };
5324
6615
  return {
5325
6616
  generateCommitMessage: async (raw, signal) => {
5326
- const inputRecord = isRecord3(raw) ? raw : {};
6617
+ const inputRecord = isRecord2(raw) ? raw : {};
5327
6618
  const includeBranch = inputRecord.includeBranch === true;
5328
- const policy = isRecord3(inputRecord.policy) ? inputRecord.policy : {};
6619
+ const policy = isRecord2(inputRecord.policy) ? inputRecord.policy : {};
5329
6620
  const prompt = [
5330
6621
  "You write concise git commit messages.",
5331
6622
  includeBranch ? "Return a JSON object with keys: subject, body, branch." : "Return a JSON object with keys: subject, body.",
@@ -5360,8 +6651,8 @@ function createCodexTextGeneration(input) {
5360
6651
  };
5361
6652
  },
5362
6653
  generatePrContent: async (raw, signal) => {
5363
- const inputRecord = isRecord3(raw) ? raw : {};
5364
- const policy = isRecord3(inputRecord.policy) ? inputRecord.policy : {};
6654
+ const inputRecord = isRecord2(raw) ? raw : {};
6655
+ const policy = isRecord2(inputRecord.policy) ? inputRecord.policy : {};
5365
6656
  const template = asString(inputRecord.changeRequestTemplate)?.trim();
5366
6657
  const bodyRules = template ? [
5367
6658
  "- body must be markdown and follow the repository change request template structure",
@@ -5409,11 +6700,11 @@ function createCodexTextGeneration(input) {
5409
6700
  };
5410
6701
  },
5411
6702
  generateBranchName: async (raw, signal) => {
5412
- const inputRecord = isRecord3(raw) ? raw : {};
5413
- const policy = isRecord3(inputRecord.policy) ? inputRecord.policy : {};
6703
+ const inputRecord = isRecord2(raw) ? raw : {};
6704
+ const policy = isRecord2(inputRecord.policy) ? inputRecord.policy : {};
5414
6705
  const attachments = Array.isArray(inputRecord.attachments) ? inputRecord.attachments : [];
5415
6706
  const attachmentLines = attachments.flatMap((attachment) => {
5416
- if (!isRecord3(attachment)) return [];
6707
+ if (!isRecord2(attachment)) return [];
5417
6708
  const name = asString(attachment.name) ?? "attachment";
5418
6709
  const mime = asString(attachment.mimeType) ?? "application/octet-stream";
5419
6710
  const size = typeof attachment.sizeBytes === "number" ? attachment.sizeBytes : 0;
@@ -5445,11 +6736,11 @@ function createCodexTextGeneration(input) {
5445
6736
  return { branch: sanitizeBranchFragment(readStringField(generated, "branch")) };
5446
6737
  },
5447
6738
  generateThreadTitle: async (raw, signal) => {
5448
- const inputRecord = isRecord3(raw) ? raw : {};
5449
- const policy = isRecord3(inputRecord.policy) ? inputRecord.policy : {};
6739
+ const inputRecord = isRecord2(raw) ? raw : {};
6740
+ const policy = isRecord2(inputRecord.policy) ? inputRecord.policy : {};
5450
6741
  const attachments = Array.isArray(inputRecord.attachments) ? inputRecord.attachments : [];
5451
6742
  const attachmentLines = attachments.flatMap((attachment) => {
5452
- if (!isRecord3(attachment)) return [];
6743
+ if (!isRecord2(attachment)) return [];
5453
6744
  const name = asString(attachment.name) ?? "attachment";
5454
6745
  const mime = asString(attachment.mimeType) ?? "application/octet-stream";
5455
6746
  const size = typeof attachment.sizeBytes === "number" ? attachment.sizeBytes : 0;
@@ -5491,7 +6782,7 @@ ${extra}` : ""}`;
5491
6782
  };
5492
6783
  },
5493
6784
  summarizeTurn: async (raw, signal) => {
5494
- const input2 = isRecord3(raw) ? raw : {};
6785
+ const input2 = isRecord2(raw) ? raw : {};
5495
6786
  const generated = await run(
5496
6787
  "summarizeTurn",
5497
6788
  asString(input2.cwd) ?? ".",
@@ -5504,7 +6795,7 @@ ${extra}` : ""}`;
5504
6795
  return { summary: readStringField(generated, "summary").trim() };
5505
6796
  },
5506
6797
  summarizeHandover: async (raw, signal) => {
5507
- const inputRecord = isRecord3(raw) ? raw : {};
6798
+ const inputRecord = isRecord2(raw) ? raw : {};
5508
6799
  const prompt = [
5509
6800
  "You write handover notes so a different coding agent can pick up work already in progress.",
5510
6801
  "Return a JSON object with exactly one key: summary.",
@@ -5535,19 +6826,19 @@ ${extra}` : ""}`;
5535
6826
  }
5536
6827
 
5537
6828
  // src/usage/codexUsage.ts
5538
- import * as NodeFS7 from "node:fs";
5539
- import * as NodePath10 from "node:path";
6829
+ import * as NodeFS9 from "node:fs";
6830
+ import * as NodePath13 from "node:path";
5540
6831
 
5541
6832
  // src/usage/codexTokenUsage.ts
5542
- import * as NodeFS6 from "node:fs";
5543
- import * as NodePath9 from "node:path";
6833
+ import * as NodeFS8 from "node:fs";
6834
+ import * as NodePath12 from "node:path";
5544
6835
 
5545
6836
  // src/usage/codexScanCache.ts
5546
- import * as NodePath8 from "node:path";
6837
+ import * as NodePath11 from "node:path";
5547
6838
 
5548
6839
  // src/usage/codexTranscriptScan.ts
5549
- import * as NodeFS5 from "node:fs";
5550
- import * as NodePath7 from "node:path";
6840
+ import * as NodeFS7 from "node:fs";
6841
+ import * as NodePath10 from "node:path";
5551
6842
 
5552
6843
  // src/usage/codexTranscripts.ts
5553
6844
  var int = (value) => typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.trunc(value) : 0;
@@ -5641,21 +6932,21 @@ var listTranscriptFiles = async (root, sinceMs) => {
5641
6932
  const walk = async (dir) => {
5642
6933
  let entries;
5643
6934
  try {
5644
- entries = await NodeFS5.promises.readdir(dir, { withFileTypes: true });
6935
+ entries = await NodeFS7.promises.readdir(dir, { withFileTypes: true });
5645
6936
  } catch {
5646
6937
  return;
5647
6938
  }
5648
6939
  for (const entry of entries) {
5649
- const child = NodePath7.join(dir, entry.name);
6940
+ const child = NodePath10.join(dir, entry.name);
5650
6941
  if (entry.isDirectory()) {
5651
6942
  await walk(child);
5652
6943
  continue;
5653
6944
  }
5654
6945
  if (!entry.isFile() || !entry.name.endsWith(TRANSCRIPT_SUFFIX)) continue;
5655
6946
  try {
5656
- const stat2 = await NodeFS5.promises.stat(child);
5657
- if (stat2.mtimeMs >= sinceMs)
5658
- found.push({ path: child, size: stat2.size, mtimeMs: stat2.mtimeMs });
6947
+ const stat4 = await NodeFS7.promises.stat(child);
6948
+ if (stat4.mtimeMs >= sinceMs)
6949
+ found.push({ path: child, size: stat4.size, mtimeMs: stat4.mtimeMs });
5659
6950
  } catch {
5660
6951
  }
5661
6952
  }
@@ -5680,7 +6971,7 @@ var readMatchingGuard = async (filePath, position) => {
5680
6971
  if (guardLength <= 0 || guardLength > GUARD_LENGTH || guardLength > resumeOffset) return null;
5681
6972
  try {
5682
6973
  const chunks = [];
5683
- for await (const chunk of NodeFS5.createReadStream(filePath, {
6974
+ for await (const chunk of NodeFS7.createReadStream(filePath, {
5684
6975
  start: resumeOffset - guardLength,
5685
6976
  end: resumeOffset - 1
5686
6977
  })) {
@@ -5719,7 +7010,7 @@ var readCodexRollout = async (filePath, resumeFrom) => {
5719
7010
  const records = [];
5720
7011
  let resumeOffset = start;
5721
7012
  let pendingChunks = [];
5722
- for await (const raw of NodeFS5.createReadStream(filePath, start > 0 ? { start } : void 0)) {
7013
+ for await (const raw of NodeFS7.createReadStream(filePath, start > 0 ? { start } : void 0)) {
5723
7014
  const chunk = asBuffer(raw);
5724
7015
  if (!chunk.includes(NEWLINE)) {
5725
7016
  pendingChunks.push(chunk);
@@ -5741,8 +7032,8 @@ var readCodexRollout = async (filePath, resumeFrom) => {
5741
7032
  }
5742
7033
  const tailRecords = [];
5743
7034
  if (pendingChunks.length > 0) {
5744
- const pending = pendingChunks.length === 1 ? pendingChunks[0] : Buffer.concat(pendingChunks);
5745
- if (pending.length > 0) parseLine(toLineString(pending), { ...state }, tailRecords);
7035
+ const pending2 = pendingChunks.length === 1 ? pendingChunks[0] : Buffer.concat(pendingChunks);
7036
+ if (pending2.length > 0) parseLine(toLineString(pending2), { ...state }, tailRecords);
5746
7037
  }
5747
7038
  return {
5748
7039
  records,
@@ -5879,8 +7170,8 @@ var pruneScanCache = (cache, options) => {
5879
7170
  for (const [path, entry] of cache) {
5880
7171
  const agedOut = entry.mtimeMs < options.retentionCutoffMs;
5881
7172
  const underWalkedRoot = options.walkedRoots.some((root) => {
5882
- const relative2 = NodePath8.relative(root, path);
5883
- return relative2 === "" || relative2 !== ".." && !relative2.startsWith(`..${NodePath8.sep}`) && !NodePath8.isAbsolute(relative2);
7173
+ const relative2 = NodePath11.relative(root, path);
7174
+ return relative2 === "" || relative2 !== ".." && !relative2.startsWith(`..${NodePath11.sep}`) && !NodePath11.isAbsolute(relative2);
5884
7175
  });
5885
7176
  const deleted = underWalkedRoot && entry.mtimeMs >= options.windowStartMs && !options.livePaths.has(path);
5886
7177
  if (agedOut || deleted) {
@@ -5923,9 +7214,9 @@ var persistCache = async (state, sharedHomePath, cache) => {
5923
7214
  };
5924
7215
  var statDirectory = async (path) => {
5925
7216
  try {
5926
- const stat2 = await NodeFS6.promises.stat(path, { bigint: true });
5927
- if (!stat2.isDirectory()) return null;
5928
- return { volumeId: stat2.ino === 0n ? "" : `${String(stat2.dev)}:${String(stat2.ino)}` };
7217
+ const stat4 = await NodeFS8.promises.stat(path, { bigint: true });
7218
+ if (!stat4.isDirectory()) return null;
7219
+ return { volumeId: stat4.ino === 0n ? "" : `${String(stat4.dev)}:${String(stat4.ino)}` };
5929
7220
  } catch {
5930
7221
  return null;
5931
7222
  }
@@ -5966,7 +7257,7 @@ var readOnce = async (input) => {
5966
7257
  const home = await statDirectory(input.sharedHomePath);
5967
7258
  const roots = [];
5968
7259
  for (const subdirectory of TRANSCRIPT_SUBDIRECTORIES) {
5969
- const root = NodePath9.join(input.sharedHomePath, subdirectory);
7260
+ const root = NodePath12.join(input.sharedHomePath, subdirectory);
5970
7261
  if (await statDirectory(root) !== null) roots.push(root);
5971
7262
  }
5972
7263
  if (home === null || roots.length === 0) {
@@ -6054,7 +7345,7 @@ var createCodexUsage = (input) => {
6054
7345
  if (fromLaunchArgs !== null) return fromLaunchArgs;
6055
7346
  let contents;
6056
7347
  try {
6057
- contents = await NodeFS7.promises.readFile(NodePath10.join(accountHome, "config.toml"), "utf8");
7348
+ contents = await NodeFS9.promises.readFile(NodePath13.join(accountHome, "config.toml"), "utf8");
6058
7349
  } catch (error) {
6059
7350
  const code = error.code;
6060
7351
  return code === "ENOENT" || code === "ENOTDIR" ? null : "config.toml:unreadable";
@@ -6084,7 +7375,7 @@ var createCodexUsage = (input) => {
6084
7375
  reason: error instanceof CodexRpcResponseError ? classifyRateLimitsError(error.message) : "unreachable"
6085
7376
  };
6086
7377
  }
6087
- return mapCodexRateLimits(response, NodePath10.join(accountHome, "auth.json")) ?? {
7378
+ return mapCodexRateLimits(response, NodePath13.join(accountHome, "auth.json")) ?? {
6088
7379
  status: "unavailable",
6089
7380
  reason: "unreachable"
6090
7381
  };
@@ -6126,8 +7417,8 @@ function missingBinaryDetail(binaryPath) {
6126
7417
  const relyOnPath = !/[\\/]/.test(binaryPath);
6127
7418
  return `Could not start Codex (${binaryPath}). Check the "Program path" setting of this provider on this machine.` + (relyOnPath ? " The Codex desktop app may not add codex to PATH; enter the full path to the codex executable there." : " Make sure the configured file exists and can be run.");
6128
7419
  }
6129
- var yieldTick = () => new Promise((resolve2) => {
6130
- setImmediate(resolve2);
7420
+ var yieldTick = () => new Promise((resolve4) => {
7421
+ setImmediate(resolve4);
6131
7422
  });
6132
7423
  function accountToAuth2(account) {
6133
7424
  switch (account.state) {
@@ -6496,6 +7787,7 @@ var createCodexInstance = (config, host, attachments, cache) => {
6496
7787
  inheritedEnvironment: process.env
6497
7788
  }),
6498
7789
  sessions: {
7790
+ openHistory: async (input) => openCodexHistory({ ...input, homePath: layoutFor(recipe).sharedHomePath }),
6499
7791
  scan: async (input) => {
6500
7792
  if (recipe.binaryPath.length === 0) {
6501
7793
  throw new Error("Codex program path is not configured");
@@ -6515,7 +7807,7 @@ var createCodexInstance = (config, host, attachments, cache) => {
6515
7807
  const candidates = await scanCodexSessions({
6516
7808
  client: rpc,
6517
7809
  directory: input.directory ?? host.workspacePath(input.projectId),
6518
- caseInsensitive: NodeProcess.platform === "win32"
7810
+ caseInsensitive: NodeProcess2.platform === "win32"
6519
7811
  });
6520
7812
  return { candidates };
6521
7813
  } finally {
@@ -6547,7 +7839,7 @@ var createCodexInstance = (config, host, attachments, cache) => {
6547
7839
  threadId: input.nativeSessionId,
6548
7840
  cwd: input.cwd,
6549
7841
  homePath: accountHomeFromLayout(layout),
6550
- caseInsensitive: NodeProcess.platform === "win32"
7842
+ caseInsensitive: NodeProcess2.platform === "win32"
6551
7843
  });
6552
7844
  } finally {
6553
7845
  await rpc.close().catch(() => void 0);
@@ -6596,10 +7888,10 @@ var createCodexInstance = (config, host, attachments, cache) => {
6596
7888
  if (signal.aborted) return;
6597
7889
  await Promise.race([
6598
7890
  Promise.all(waiters),
6599
- new Promise((resolve2) => {
7891
+ new Promise((resolve4) => {
6600
7892
  const onAbort = () => {
6601
7893
  signal.removeEventListener("abort", onAbort);
6602
- resolve2();
7894
+ resolve4();
6603
7895
  };
6604
7896
  signal.addEventListener("abort", onAbort);
6605
7897
  })
@@ -6632,7 +7924,7 @@ var executors = [
6632
7924
  ];
6633
7925
  var index_default = definePlugin({
6634
7926
  id: "agent-codex",
6635
- apiVersion: 35,
7927
+ apiVersion: 36,
6636
7928
  executors,
6637
7929
  activate(ctx) {
6638
7930
  capturedAttachments = ctx.attachments;