@ycodium-ai/agent-codex 0.2.3369 → 0.2.3389
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +2059 -767
- 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/
|
|
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/
|
|
460
|
-
var
|
|
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/
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
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
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
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
|
-
}
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
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
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
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
|
-
|
|
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
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
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
|
-
|
|
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
|
-
|
|
656
|
+
var historyIdentity = async (path) => {
|
|
657
|
+
const stat4 = await NodeFSP3.stat(path);
|
|
590
658
|
return {
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
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
|
-
|
|
600
|
-
|
|
601
|
-
|
|
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
|
-
|
|
604
|
-
|
|
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/
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
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
|
-
|
|
629
|
-
|
|
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
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
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
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
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
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
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
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
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
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
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
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
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
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 (!
|
|
914
|
-
const thread =
|
|
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 (!
|
|
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 (!
|
|
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 (!
|
|
1006
|
-
return asString(params["threadId"]) ?? asString(params["conversationId"]) ?? (
|
|
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 (!
|
|
1010
|
-
const item =
|
|
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 (
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
2556
|
+
for (const [, entry] of pending2) {
|
|
1075
2557
|
entry.reject(attach(new Error(`codex app-server ${entry.method} failed: ${reason}`)));
|
|
1076
2558
|
}
|
|
1077
|
-
|
|
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 =
|
|
2582
|
+
const entry = pending2.get(typed.id);
|
|
1101
2583
|
if (entry === void 0) return;
|
|
1102
|
-
|
|
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((
|
|
1168
|
-
|
|
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
|
-
|
|
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((
|
|
2705
|
+
new Promise((resolve4) => {
|
|
1224
2706
|
timer = setTimeout(() => {
|
|
1225
2707
|
options.onDrainTimeout();
|
|
1226
|
-
|
|
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: () =>
|
|
2725
|
+
pendingCountForTests: () => pending2.size
|
|
1244
2726
|
};
|
|
1245
2727
|
}
|
|
1246
2728
|
|
|
1247
2729
|
// src/sessionRuntime.ts
|
|
1248
|
-
import * as
|
|
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 (!
|
|
1475
|
-
const item =
|
|
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
|
|
2991
|
+
import * as NodeCrypto3 from "node:crypto";
|
|
1510
2992
|
var CODEX_PROVIDER = "codex";
|
|
1511
|
-
var EVENT_ID_PREFIX = `codex-evt-${
|
|
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 (!
|
|
1548
|
-
const item =
|
|
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 (!
|
|
1553
|
-
const item =
|
|
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 (!
|
|
1558
|
-
return asString(params["turnId"]) ?? (
|
|
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 (!
|
|
1562
|
-
const item =
|
|
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 (!
|
|
1567
|
-
const item =
|
|
1568
|
-
const 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 =
|
|
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 (!
|
|
1599
|
-
const last =
|
|
1600
|
-
const total =
|
|
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 =
|
|
3105
|
+
const turn = isRecord2(params) ? isRecord2(params["turn"]) ? params["turn"] : params : {};
|
|
1624
3106
|
const state = toTurnStatus(asString(turn["status"]) ?? void 0);
|
|
1625
|
-
const error =
|
|
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 (!
|
|
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 =
|
|
1751
|
-
const total = tokenUsage &&
|
|
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 (!
|
|
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 (!
|
|
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 (!
|
|
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 (!
|
|
1819
|
-
const item =
|
|
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 (!
|
|
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 (!
|
|
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 (
|
|
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 =
|
|
1871
|
-
if (!
|
|
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(
|
|
2213
|
-
const willRetry =
|
|
2214
|
-
const nested =
|
|
2215
|
-
const message = (nested ? trimText(nested["message"]) : void 0) ?? (
|
|
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 =
|
|
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 =
|
|
2260
|
-
const providerThreadId =
|
|
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 =
|
|
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 =
|
|
2333
|
-
const nativeThreadId =
|
|
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
|
-
|
|
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 =
|
|
2392
|
-
const turnError =
|
|
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: (
|
|
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 =
|
|
2446
|
-
const plan = rawPlan.filter(
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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" &&
|
|
2637
|
-
const contentIndex = method === "item/reasoning/textDelta" &&
|
|
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 =
|
|
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 =
|
|
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:
|
|
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 =
|
|
2728
|
-
const toModel =
|
|
2729
|
-
const reason =
|
|
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 =
|
|
4228
|
+
const summary = isRecord2(params) ? trimText(params["summary"]) : void 0;
|
|
2745
4229
|
if (!summary) return [];
|
|
2746
|
-
const details =
|
|
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" &&
|
|
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 =
|
|
4249
|
+
const success = isRecord2(params) ? params["success"] : void 0;
|
|
2766
4250
|
if (typeof success !== "boolean") return [];
|
|
2767
|
-
const name =
|
|
2768
|
-
const error =
|
|
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 (!
|
|
2791
|
-
const item =
|
|
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 (!
|
|
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
|
-
...
|
|
4280
|
+
...isRecord2(change) ? change : {}
|
|
2797
4281
|
}));
|
|
2798
4282
|
const out = [];
|
|
2799
4283
|
for (const entry of entries) {
|
|
2800
|
-
if (!
|
|
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 =
|
|
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 =
|
|
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 =
|
|
2887
|
-
const permissions =
|
|
2888
|
-
const fileSystem =
|
|
2889
|
-
const 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 (!
|
|
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 =
|
|
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 =
|
|
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 (!
|
|
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 =
|
|
2955
|
-
const properties = schema &&
|
|
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 (!
|
|
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] =
|
|
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(
|
|
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(
|
|
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
|
|
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,
|
|
3133
|
-
if (
|
|
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(
|
|
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(
|
|
3148
|
-
if (!
|
|
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
|
|
3152
|
-
if (turnId === void 0 || entry.turnId === turnId)
|
|
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 (!
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
3271
|
-
const spawn =
|
|
3272
|
-
if (method === "thread/started" && thread !== void 0 &&
|
|
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 =
|
|
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, {
|
|
4787
|
+
this.upsertCollabChild(agentThreadId, {
|
|
4788
|
+
agentPath: activity.agentPath
|
|
4789
|
+
});
|
|
3303
4790
|
}
|
|
3304
4791
|
if (method === "thread/settings/updated" || method === "model/rerouted") {
|
|
3305
|
-
const settings =
|
|
4792
|
+
const settings = isRecord2(params) && isRecord2(params["threadSettings"]) ? params["threadSettings"] : {};
|
|
3306
4793
|
const reroute = method === "model/rerouted";
|
|
3307
4794
|
const model = metaValue(
|
|
3308
|
-
reroute ?
|
|
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 =
|
|
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 =
|
|
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 || !
|
|
4930
|
+
if (this.runtime.closed || meta.closed || !isRecord2(response)) return;
|
|
3441
4931
|
const thread = response["thread"];
|
|
3442
|
-
if (!
|
|
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
|
-
...
|
|
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(
|
|
3474
|
-
if (
|
|
3475
|
-
return
|
|
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
|
-
|
|
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((
|
|
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(
|
|
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((
|
|
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(
|
|
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
|
-
|
|
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
|
|
3597
|
-
if (!
|
|
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" &&
|
|
3602
|
-
wire = toMcpElicitationResponse("allow",
|
|
5092
|
+
if (decision === "allow" && pending2.kind === "mcp-elicitation") {
|
|
5093
|
+
wire = toMcpElicitationResponse("allow", pending2.params);
|
|
3603
5094
|
}
|
|
3604
|
-
if (
|
|
3605
|
-
wire = toPermissionsResponse(decision,
|
|
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(
|
|
3608
|
-
if (
|
|
3609
|
-
wire = { decision: wireDecisionFromPersist(
|
|
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(
|
|
3613
|
-
|
|
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(
|
|
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
|
|
3633
|
-
if (!
|
|
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(
|
|
3639
|
-
|
|
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,
|
|
3656
|
-
|
|
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(
|
|
5155
|
+
payload: { requestType: toRequestTypeFromKind(pending2.kind), decision: "cancel" }
|
|
3665
5156
|
});
|
|
3666
5157
|
}
|
|
3667
5158
|
}
|
|
3668
5159
|
/** 会话收口时把还挂着的审批答成「取消」:应答形状按审批种类,权限审批不认 decision。 */
|
|
3669
5160
|
settlePendingApprovals() {
|
|
3670
|
-
for (const [requestId,
|
|
3671
|
-
|
|
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,
|
|
3677
|
-
|
|
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((
|
|
3696
|
-
setTimeout(
|
|
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-${
|
|
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((
|
|
3804
|
-
this.writeAcks.set(jsonRpcId, { resolve:
|
|
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((
|
|
5312
|
+
return await new Promise((resolve4) => {
|
|
3822
5313
|
const previous = existing.resolve;
|
|
3823
5314
|
existing.resolve = (status) => {
|
|
3824
5315
|
previous(status);
|
|
3825
|
-
|
|
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 =
|
|
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, {
|
|
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 =
|
|
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
|
|
3883
|
-
if (
|
|
3884
|
-
|
|
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" &&
|
|
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 (!
|
|
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 =
|
|
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 (!
|
|
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((
|
|
4212
|
-
this.#waiters.push(
|
|
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((
|
|
4461
|
-
settle =
|
|
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 =
|
|
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 =
|
|
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 (!
|
|
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 (!
|
|
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 (!
|
|
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 (!
|
|
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 (!
|
|
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 =
|
|
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 (!
|
|
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 (!
|
|
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 (!
|
|
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 (!
|
|
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
|
|
4687
|
-
import * as
|
|
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(
|
|
4694
|
-
watched.add(
|
|
4695
|
-
if (
|
|
4696
|
-
const parent =
|
|
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 =
|
|
5993
|
+
const skillDirectory = NodePath8.dirname(skill.path);
|
|
4703
5994
|
watched.add(skillDirectory);
|
|
4704
|
-
watched.add(
|
|
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 =
|
|
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 (!
|
|
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((
|
|
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 =
|
|
4974
|
-
const type =
|
|
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
|
-
...
|
|
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
|
|
6363
|
+
import * as NodeFSP5 from "node:fs/promises";
|
|
5073
6364
|
import * as NodeOS3 from "node:os";
|
|
5074
|
-
import * as
|
|
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 (
|
|
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 (!
|
|
6515
|
+
if (!isRecord2(attachment) || attachment.type !== "image") continue;
|
|
5225
6516
|
const candidate = asString(attachment.path) ?? asString(attachment.filePath) ?? asString(attachment.savedPath);
|
|
5226
|
-
if (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
|
|
5242
|
-
const schemaPath =
|
|
5243
|
-
const outputPath =
|
|
5244
|
-
await
|
|
5245
|
-
await
|
|
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((
|
|
5290
|
-
timer = setTimeout(() =>
|
|
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
|
|
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 (!
|
|
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
|
|
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 =
|
|
6617
|
+
const inputRecord = isRecord2(raw) ? raw : {};
|
|
5327
6618
|
const includeBranch = inputRecord.includeBranch === true;
|
|
5328
|
-
const 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 =
|
|
5364
|
-
const 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 =
|
|
5413
|
-
const 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 (!
|
|
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 =
|
|
5449
|
-
const 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 (!
|
|
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 =
|
|
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 =
|
|
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
|
|
5539
|
-
import * as
|
|
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
|
|
5543
|
-
import * as
|
|
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
|
|
6837
|
+
import * as NodePath11 from "node:path";
|
|
5547
6838
|
|
|
5548
6839
|
// src/usage/codexTranscriptScan.ts
|
|
5549
|
-
import * as
|
|
5550
|
-
import * as
|
|
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
|
|
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 =
|
|
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
|
|
5657
|
-
if (
|
|
5658
|
-
found.push({ path: child, size:
|
|
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
|
|
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
|
|
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
|
|
5745
|
-
if (
|
|
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 =
|
|
5883
|
-
return relative2 === "" || relative2 !== ".." && !relative2.startsWith(`..${
|
|
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
|
|
5927
|
-
if (!
|
|
5928
|
-
return { volumeId:
|
|
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 =
|
|
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
|
|
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,
|
|
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((
|
|
6130
|
-
setImmediate(
|
|
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:
|
|
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:
|
|
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((
|
|
7891
|
+
new Promise((resolve4) => {
|
|
6600
7892
|
const onAbort = () => {
|
|
6601
7893
|
signal.removeEventListener("abort", onAbort);
|
|
6602
|
-
|
|
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:
|
|
7927
|
+
apiVersion: 37,
|
|
6636
7928
|
executors,
|
|
6637
7929
|
activate(ctx) {
|
|
6638
7930
|
capturedAttachments = ctx.attachments;
|