@openclaw/codex 2026.5.12 → 2026.5.14-beta.1

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.
@@ -1,7 +1,7 @@
1
1
  import { CODEX_PROVIDER_ID, FALLBACK_CODEX_MODELS } from "./provider-catalog.js";
2
2
  import { s as resolveCodexAppServerRuntimeOptions } from "./config-0rd3LnKg.js";
3
3
  import { i as assertCodexTurnStartResponse, l as readCodexTurnCompletedNotification, o as readCodexErrorNotification, r as assertCodexThreadStartResponse } from "./protocol-validators-CSY0BFBo.js";
4
- import { i as readModelListResult } from "./models-BmLfrDci.js";
4
+ import { i as readModelListResult } from "./models-GCYf5s8J.js";
5
5
  import { t as isJsonObject } from "./protocol-C9UWI98H.js";
6
6
  import { validateJsonSchemaValue } from "openclaw/plugin-sdk/json-schema-runtime";
7
7
  //#region extensions/codex/media-understanding-provider.ts
@@ -62,7 +62,7 @@ async function runBoundedCodexVisionTurn(params) {
62
62
  const appServer = resolveCodexAppServerRuntimeOptions({ pluginConfig: params.options.pluginConfig });
63
63
  const timeoutMs = Math.max(100, params.timeoutMs);
64
64
  const ownsClient = !params.options.clientFactory;
65
- const client = params.options.clientFactory ? await params.options.clientFactory(appServer.start, params.profile) : await import("./shared-client-Cr6W-a2G.js").then((n) => n.i).then(({ createIsolatedCodexAppServerClient }) => createIsolatedCodexAppServerClient({
65
+ const client = params.options.clientFactory ? await params.options.clientFactory(appServer.start, params.profile) : await import("./shared-client-BwUqd3lh.js").then((n) => n.a).then(({ createIsolatedCodexAppServerClient }) => createIsolatedCodexAppServerClient({
66
66
  startOptions: appServer.start,
67
67
  timeoutMs,
68
68
  authProfileId: params.profile
@@ -39,7 +39,7 @@ async function listAllCodexAppServerModels(options = {}) {
39
39
  async function withCodexAppServerModelClient(options, run) {
40
40
  const timeoutMs = options.timeoutMs ?? 2500;
41
41
  const useSharedClient = options.sharedClient !== false;
42
- const { createIsolatedCodexAppServerClient, getSharedCodexAppServerClient } = await import("./shared-client-Cr6W-a2G.js").then((n) => n.i);
42
+ const { createIsolatedCodexAppServerClient, getSharedCodexAppServerClient } = await import("./shared-client-BwUqd3lh.js").then((n) => n.a);
43
43
  const client = useSharedClient ? await getSharedCodexAppServerClient({
44
44
  startOptions: options.startOptions,
45
45
  timeoutMs,
@@ -1,13 +1,18 @@
1
1
  import { i as isCodexFastServiceTier, r as codexSandboxPolicyForTurn, s as resolveCodexAppServerRuntimeOptions } from "./config-0rd3LnKg.js";
2
2
  import { t as isJsonObject } from "./protocol-C9UWI98H.js";
3
- import { n as CODEX_CONTROL_METHODS } from "./request-ohCy5ASa.js";
4
- import { r as formatCodexDisplayText } from "./command-formatters-Ttwc_kgX.js";
5
- import { l as resolveCodexAppServerAuthProfileIdForAgent, r as getSharedCodexAppServerClient } from "./shared-client-Cr6W-a2G.js";
3
+ import { n as CODEX_CONTROL_METHODS } from "./request-BxAP1uyw.js";
4
+ import { r as formatCodexDisplayText } from "./command-formatters-CJH9-hFT.js";
5
+ import { i as getSharedCodexAppServerClient, u as resolveCodexAppServerAuthProfileIdForAgent } from "./shared-client-BwUqd3lh.js";
6
6
  import { i as readCodexAppServerBinding, n as isCodexAppServerNativeAuthProfile, o as writeCodexAppServerBinding, r as normalizeCodexAppServerBindingModelProvider, t as clearCodexAppServerBinding } from "./session-binding-CMTXuyoz.js";
7
+ import os from "node:os";
7
8
  import { formatErrorMessage } from "openclaw/plugin-sdk/agent-harness-runtime";
9
+ import { spawn } from "node:child_process";
10
+ import { materializeWindowsSpawnProgram, resolveWindowsSpawnProgram } from "openclaw/plugin-sdk/windows-spawn";
11
+ import fs from "node:fs/promises";
8
12
  import path from "node:path";
9
13
  import { fileURLToPath } from "node:url";
10
14
  import process from "node:process";
15
+ import { resolvePreferredOpenClawTmpDir } from "openclaw/plugin-sdk/temp-path";
11
16
  //#region extensions/codex/src/conversation-binding-data.ts
12
17
  const BINDING_DATA_VERSION = 1;
13
18
  function createCodexConversationBindingData(params) {
@@ -18,13 +23,34 @@ function createCodexConversationBindingData(params) {
18
23
  workspaceDir: params.workspaceDir
19
24
  };
20
25
  }
26
+ function createCodexCliNodeConversationBindingData(params) {
27
+ const cwd = params.cwd?.trim();
28
+ return {
29
+ kind: "codex-cli-node-session",
30
+ version: BINDING_DATA_VERSION,
31
+ nodeId: params.nodeId,
32
+ sessionId: params.sessionId,
33
+ ...cwd ? { cwd } : {}
34
+ };
35
+ }
21
36
  function readCodexConversationBindingData(binding) {
22
37
  const data = binding?.data;
23
38
  if (!data || typeof data !== "object" || Array.isArray(data)) return;
24
39
  return readCodexConversationBindingDataRecord(data);
25
40
  }
26
41
  function readCodexConversationBindingDataRecord(data) {
27
- if (data.kind !== "codex-app-server-session" || data.version !== BINDING_DATA_VERSION || typeof data.sessionFile !== "string" || !data.sessionFile.trim()) return;
42
+ if (data.kind === "codex-cli-node-session") {
43
+ if (data.version !== BINDING_DATA_VERSION || typeof data.nodeId !== "string" || !data.nodeId.trim() || typeof data.sessionId !== "string" || !data.sessionId.trim()) return;
44
+ return {
45
+ kind: "codex-cli-node-session",
46
+ version: BINDING_DATA_VERSION,
47
+ nodeId: data.nodeId.trim(),
48
+ sessionId: data.sessionId.trim(),
49
+ cwd: typeof data.cwd === "string" && data.cwd.trim() ? data.cwd.trim() : void 0
50
+ };
51
+ }
52
+ if (data.kind !== "codex-app-server-session") return;
53
+ if (data.version !== BINDING_DATA_VERSION || typeof data.sessionFile !== "string" || !data.sessionFile.trim()) return;
28
54
  return {
29
55
  kind: "codex-app-server-session",
30
56
  version: BINDING_DATA_VERSION,
@@ -453,6 +479,32 @@ async function handleCodexConversationInboundClaim(event, ctx, options = {}) {
453
479
  if (event.commandAuthorized !== true) return { handled: true };
454
480
  const prompt = event.bodyForAgent?.trim() || event.content?.trim() || "";
455
481
  if (!prompt) return { handled: true };
482
+ if (data.kind === "codex-cli-node-session") {
483
+ const resume = options.resumeCodexCliSessionOnNode;
484
+ if (!resume) return {
485
+ handled: true,
486
+ reply: { text: "Codex CLI node binding is unavailable because Gateway node runtime is not attached." }
487
+ };
488
+ try {
489
+ return {
490
+ handled: true,
491
+ reply: (await enqueueBoundTurn(`${data.nodeId}:${data.sessionId}`, async () => {
492
+ return { reply: { text: (await resume({
493
+ nodeId: data.nodeId,
494
+ sessionId: data.sessionId,
495
+ prompt,
496
+ cwd: data.cwd,
497
+ timeoutMs: options.timeoutMs
498
+ })).text.trim() || "Codex completed without a text reply." } };
499
+ })).reply
500
+ };
501
+ } catch (error) {
502
+ return {
503
+ handled: true,
504
+ reply: { text: `Codex CLI node turn failed: ${formatCodexDisplayText(formatErrorMessage(error))}` }
505
+ };
506
+ }
507
+ }
456
508
  try {
457
509
  return {
458
510
  handled: true,
@@ -474,7 +526,7 @@ async function handleCodexConversationInboundClaim(event, ctx, options = {}) {
474
526
  async function handleCodexConversationBindingResolved(event) {
475
527
  if (event.status !== "denied") return;
476
528
  const data = readCodexConversationBindingDataRecord(event.request.data ?? {});
477
- if (!data) return;
529
+ if (!data || data.kind !== "codex-app-server-session") return;
478
530
  await clearCodexAppServerBinding(data.sessionFile);
479
531
  }
480
532
  async function attachExistingThread(params) {
@@ -653,4 +705,464 @@ function resolveThreadRequestModelProvider(params) {
653
705
  return modelProvider.toLowerCase() === "openai-codex" ? "openai" : modelProvider;
654
706
  }
655
707
  //#endregion
656
- export { parseCodexFastModeArg as a, setCodexConversationFastMode as c, steerCodexConversationTurn as d, stopCodexConversationTurn as f, formatPermissionsMode as i, setCodexConversationModel as l, resolveCodexDefaultWorkspaceDir as m, handleCodexConversationInboundClaim as n, parseCodexPermissionsModeArg as o, readCodexConversationBindingData as p, startCodexConversationThread as r, readCodexConversationActiveTurn as s, handleCodexConversationBindingResolved as t, setCodexConversationPermissions as u };
708
+ //#region extensions/codex/src/node-cli-sessions.ts
709
+ const CODEX_CLI_SESSIONS_LIST_COMMAND = "codex.cli.sessions.list";
710
+ const CODEX_CLI_SESSION_RESUME_COMMAND = "codex.cli.session.resume";
711
+ const DEFAULT_SESSION_LIMIT = 10;
712
+ const MAX_SESSION_LIMIT = 50;
713
+ const DEFAULT_RESUME_TIMEOUT_MS = 20 * 6e4;
714
+ const SESSION_ID_PATTERN = /^[A-Za-z0-9._:-]{1,128}$/;
715
+ const activeResumeSessions = /* @__PURE__ */ new Set();
716
+ const DEFAULT_RESUME_SPAWN_RUNTIME = {
717
+ platform: process.platform,
718
+ env: process.env,
719
+ execPath: process.execPath
720
+ };
721
+ function createCodexCliSessionNodeHostCommands() {
722
+ return [{
723
+ command: CODEX_CLI_SESSIONS_LIST_COMMAND,
724
+ cap: "codex-cli-sessions",
725
+ handle: listLocalCodexCliSessions
726
+ }, {
727
+ command: CODEX_CLI_SESSION_RESUME_COMMAND,
728
+ cap: "codex-cli-sessions",
729
+ dangerous: true,
730
+ handle: resumeLocalCodexCliSession
731
+ }];
732
+ }
733
+ function createCodexCliSessionNodeInvokePolicies() {
734
+ return [{
735
+ commands: [CODEX_CLI_SESSIONS_LIST_COMMAND],
736
+ defaultPlatforms: [
737
+ "macos",
738
+ "linux",
739
+ "windows"
740
+ ],
741
+ handle: (ctx) => ctx.invokeNode()
742
+ }, {
743
+ commands: [CODEX_CLI_SESSION_RESUME_COMMAND],
744
+ dangerous: true,
745
+ handle: (ctx) => ctx.invokeNode()
746
+ }];
747
+ }
748
+ async function listCodexCliSessionsOnNode(params) {
749
+ const node = await resolveCodexCliNode({
750
+ runtime: params.runtime,
751
+ requestedNode: params.requestedNode,
752
+ command: CODEX_CLI_SESSIONS_LIST_COMMAND
753
+ });
754
+ return {
755
+ node,
756
+ result: parseCodexCliSessionsListResult(await params.runtime.nodes.invoke({
757
+ nodeId: readNodeId(node),
758
+ command: CODEX_CLI_SESSIONS_LIST_COMMAND,
759
+ params: {
760
+ limit: params.limit,
761
+ filter: params.filter
762
+ },
763
+ timeoutMs: 15e3
764
+ }))
765
+ };
766
+ }
767
+ async function resolveCodexCliSessionForBindingOnNode(params) {
768
+ const listing = await listCodexCliSessionsOnNode({
769
+ runtime: params.runtime,
770
+ requestedNode: params.requestedNode,
771
+ filter: params.sessionId,
772
+ limit: MAX_SESSION_LIMIT
773
+ });
774
+ if (!listing.node.commands?.includes("codex.cli.session.resume")) throw new Error(`Node ${formatNodeLabel(listing.node)} does not expose ${CODEX_CLI_SESSION_RESUME_COMMAND}.`);
775
+ return {
776
+ node: listing.node,
777
+ session: listing.result.sessions.find((session) => session.sessionId === params.sessionId)
778
+ };
779
+ }
780
+ async function resumeCodexCliSessionOnNode(params) {
781
+ const payload = unwrapNodeInvokePayload(await params.runtime.nodes.invoke({
782
+ nodeId: params.nodeId,
783
+ command: CODEX_CLI_SESSION_RESUME_COMMAND,
784
+ params: {
785
+ sessionId: params.sessionId,
786
+ prompt: params.prompt,
787
+ cwd: params.cwd,
788
+ timeoutMs: params.timeoutMs
789
+ },
790
+ timeoutMs: (params.timeoutMs ?? DEFAULT_RESUME_TIMEOUT_MS) + 5e3
791
+ }));
792
+ if (!isRecord(payload) || payload.ok !== true || typeof payload.text !== "string") throw new Error("Codex CLI resume returned an invalid payload.");
793
+ return {
794
+ ok: true,
795
+ sessionId: typeof payload.sessionId === "string" ? payload.sessionId : params.sessionId,
796
+ text: payload.text
797
+ };
798
+ }
799
+ function formatCodexCliSessions(params) {
800
+ if (params.result.sessions.length === 0) return `No Codex CLI sessions returned from ${formatCodexDisplayText(formatNodeLabel(params.node))}.`;
801
+ return [`Codex CLI sessions on ${formatCodexDisplayText(formatNodeLabel(params.node))}:`, ...params.result.sessions.map((session) => {
802
+ const details = [session.cwd, session.updatedAt].filter((value) => Boolean(value));
803
+ return `- ${formatCodexDisplayText(session.sessionId)}${session.lastMessage ? ` - ${formatCodexDisplayText(session.lastMessage)}` : ""}${details.length > 0 ? ` (${details.map(formatCodexDisplayText).join(", ")})` : ""}\n Bind: /codex resume ${formatCodexDisplayText(session.sessionId)} --host ${formatCodexDisplayText(readNodeId(params.node))} --bind here`;
804
+ })].join("\n");
805
+ }
806
+ async function listLocalCodexCliSessions(paramsJSON) {
807
+ const params = readRecordParam(paramsJSON);
808
+ const limit = normalizeLimit(params.limit);
809
+ const filter = typeof params.filter === "string" ? params.filter.trim().toLowerCase() : "";
810
+ const codexHome = resolveCodexHome();
811
+ const summaries = await readHistorySessions(codexHome);
812
+ await hydrateSessionFiles(codexHome, summaries);
813
+ await hydrateSessionsFromSessionFiles(codexHome, summaries);
814
+ const sessions = [...summaries.values()].filter((session) => {
815
+ if (!filter) return true;
816
+ return [
817
+ session.sessionId,
818
+ session.cwd,
819
+ session.lastMessage
820
+ ].some((value) => value?.toLowerCase().includes(filter));
821
+ }).toSorted((a, b) => compareOptionalStringsDesc(a.updatedAt, b.updatedAt)).slice(0, limit);
822
+ return JSON.stringify({
823
+ sessions,
824
+ codexHome
825
+ });
826
+ }
827
+ async function resumeLocalCodexCliSession(paramsJSON) {
828
+ const params = readRecordParam(paramsJSON);
829
+ const sessionId = typeof params.sessionId === "string" ? params.sessionId.trim() : "";
830
+ const prompt = typeof params.prompt === "string" ? params.prompt.trim() : "";
831
+ if (!sessionId || !SESSION_ID_PATTERN.test(sessionId)) throw new Error("Missing or invalid Codex CLI session id.");
832
+ if (!prompt) throw new Error("Missing Codex CLI prompt.");
833
+ if (activeResumeSessions.has(sessionId)) throw new Error(`Codex CLI session ${sessionId} already has an active resume turn.`);
834
+ activeResumeSessions.add(sessionId);
835
+ try {
836
+ const text = await runCodexExecResume({
837
+ sessionId,
838
+ prompt,
839
+ cwd: typeof params.cwd === "string" && params.cwd.trim() ? params.cwd.trim() : void 0,
840
+ timeoutMs: normalizeTimeoutMs(params.timeoutMs)
841
+ });
842
+ return JSON.stringify({
843
+ ok: true,
844
+ sessionId,
845
+ text: text.trim() || "Codex completed without a text reply."
846
+ });
847
+ } finally {
848
+ activeResumeSessions.delete(sessionId);
849
+ }
850
+ }
851
+ async function runCodexExecResume(params) {
852
+ const outputPath = path.join(await fs.mkdtemp(path.join(resolvePreferredOpenClawTmpDir(), "openclaw-codex-cli-")), "last-message.txt");
853
+ try {
854
+ const invocation = resolveCodexCliResumeSpawnInvocation([
855
+ "exec",
856
+ "resume",
857
+ "--skip-git-repo-check",
858
+ "--output-last-message",
859
+ outputPath,
860
+ params.sessionId,
861
+ "-"
862
+ ], {
863
+ platform: process.platform,
864
+ env: process.env,
865
+ execPath: process.execPath
866
+ });
867
+ const child = spawn(invocation.command, invocation.args, {
868
+ cwd: params.cwd || process.cwd(),
869
+ stdio: [
870
+ "pipe",
871
+ "pipe",
872
+ "pipe"
873
+ ],
874
+ env: process.env,
875
+ shell: invocation.shell,
876
+ windowsHide: invocation.windowsHide
877
+ });
878
+ const stdout = [];
879
+ const stderr = [];
880
+ let timedOut = false;
881
+ let forceKillTimeout;
882
+ const timeout = setTimeout(() => {
883
+ timedOut = true;
884
+ child.kill("SIGTERM");
885
+ forceKillTimeout = setTimeout(() => child.kill("SIGKILL"), 2e3);
886
+ forceKillTimeout.unref?.();
887
+ }, params.timeoutMs);
888
+ child.stdout.on("data", (chunk) => stdout.push(chunk));
889
+ child.stderr.on("data", (chunk) => stderr.push(chunk));
890
+ child.stdin.end(params.prompt);
891
+ const exitCode = await new Promise((resolve, reject) => {
892
+ child.on("error", reject);
893
+ child.on("exit", (code) => resolve(code));
894
+ }).finally(() => {
895
+ clearTimeout(timeout);
896
+ if (forceKillTimeout) clearTimeout(forceKillTimeout);
897
+ });
898
+ if (timedOut) throw new Error(`codex exec resume timed out after ${String(params.timeoutMs)}ms`);
899
+ if (exitCode !== 0) {
900
+ const message = Buffer.concat(stderr).toString("utf8").trim() || Buffer.concat(stdout).toString("utf8").trim() || `codex exec resume exited with code ${String(exitCode)}`;
901
+ throw new Error(message);
902
+ }
903
+ return await fs.readFile(outputPath, "utf8");
904
+ } finally {
905
+ await fs.rm(path.dirname(outputPath), {
906
+ recursive: true,
907
+ force: true
908
+ });
909
+ }
910
+ }
911
+ function resolveCodexCliResumeSpawnInvocation(args, runtime = DEFAULT_RESUME_SPAWN_RUNTIME) {
912
+ const resolved = materializeWindowsSpawnProgram(resolveWindowsSpawnProgram({
913
+ command: "codex",
914
+ platform: runtime.platform,
915
+ env: runtime.env,
916
+ execPath: runtime.execPath,
917
+ packageName: "@openai/codex"
918
+ }), args);
919
+ return {
920
+ command: resolved.command,
921
+ args: resolved.argv,
922
+ shell: resolved.shell,
923
+ windowsHide: resolved.windowsHide
924
+ };
925
+ }
926
+ async function readHistorySessions(codexHome) {
927
+ const summaries = /* @__PURE__ */ new Map();
928
+ const content = await readFileIfExists(path.join(codexHome, "history.jsonl"));
929
+ if (!content) return summaries;
930
+ for (const line of content.split(/\r?\n/u)) {
931
+ const trimmed = line.trim();
932
+ if (!trimmed) continue;
933
+ let parsed;
934
+ try {
935
+ parsed = JSON.parse(trimmed);
936
+ } catch {
937
+ continue;
938
+ }
939
+ if (!isRecord(parsed) || typeof parsed.session_id !== "string") continue;
940
+ const sessionId = parsed.session_id.trim();
941
+ if (!sessionId) continue;
942
+ const entry = summaries.get(sessionId) ?? {
943
+ sessionId,
944
+ messageCount: 0
945
+ };
946
+ entry.messageCount += 1;
947
+ if (typeof parsed.text === "string" && parsed.text.trim()) entry.lastMessage = truncateText(parsed.text.trim(), 140);
948
+ if (typeof parsed.ts === "number" && Number.isFinite(parsed.ts)) entry.updatedAt = (/* @__PURE__ */ new Date(parsed.ts * 1e3)).toISOString();
949
+ summaries.set(sessionId, entry);
950
+ }
951
+ return summaries;
952
+ }
953
+ async function hydrateSessionFiles(codexHome, summaries) {
954
+ if (summaries.size === 0) return;
955
+ const files = await findSessionFiles(path.join(codexHome, "sessions"), 4);
956
+ const pending = new Set(summaries.keys());
957
+ for (const file of files) {
958
+ const basename = path.basename(file);
959
+ const sessionId = [...pending].find((id) => basename.includes(id));
960
+ if (!sessionId) continue;
961
+ const entry = summaries.get(sessionId);
962
+ if (!entry) continue;
963
+ entry.sessionFile = file;
964
+ const cwd = readSessionMetaCwd(await readFirstLine(file) ?? "");
965
+ if (cwd) entry.cwd = cwd;
966
+ pending.delete(sessionId);
967
+ if (pending.size === 0) return;
968
+ }
969
+ }
970
+ async function hydrateSessionsFromSessionFiles(codexHome, summaries) {
971
+ const files = await findSessionFiles(path.join(codexHome, "sessions"), 4);
972
+ for (const file of files) {
973
+ const summary = await readSessionFileSummary(file);
974
+ if (!summary) continue;
975
+ const existing = summaries.get(summary.sessionId);
976
+ summaries.set(summary.sessionId, {
977
+ ...summary,
978
+ ...existing,
979
+ cwd: existing?.cwd ?? summary.cwd,
980
+ sessionFile: existing?.sessionFile ?? summary.sessionFile,
981
+ updatedAt: existing?.updatedAt ?? summary.updatedAt,
982
+ lastMessage: existing?.lastMessage ?? summary.lastMessage,
983
+ messageCount: existing?.messageCount ?? summary.messageCount
984
+ });
985
+ }
986
+ }
987
+ async function readSessionFileSummary(file) {
988
+ const content = await readFileIfExists(file);
989
+ if (!content) return null;
990
+ let sessionId = "";
991
+ let cwd;
992
+ let updatedAt;
993
+ let lastMessage;
994
+ let messageCount = 0;
995
+ for (const line of content.split(/\r?\n/u)) {
996
+ const trimmed = line.trim();
997
+ if (!trimmed) continue;
998
+ let parsed;
999
+ try {
1000
+ parsed = JSON.parse(trimmed);
1001
+ } catch {
1002
+ continue;
1003
+ }
1004
+ if (!isRecord(parsed)) continue;
1005
+ if (typeof parsed.timestamp === "string" && parsed.timestamp.trim()) updatedAt = parsed.timestamp.trim();
1006
+ if (parsed.type === "session_meta" && isRecord(parsed.payload)) {
1007
+ if (typeof parsed.payload.id === "string" && parsed.payload.id.trim()) sessionId = parsed.payload.id.trim();
1008
+ if (typeof parsed.payload.cwd === "string" && parsed.payload.cwd.trim()) cwd = parsed.payload.cwd.trim();
1009
+ continue;
1010
+ }
1011
+ const messageText = readResponseItemMessageText(parsed);
1012
+ if (messageText) {
1013
+ messageCount += 1;
1014
+ lastMessage = truncateText(messageText, 140);
1015
+ }
1016
+ }
1017
+ if (!sessionId) sessionId = readSessionIdFromFilename(file) ?? "";
1018
+ if (!sessionId) return null;
1019
+ return {
1020
+ sessionId,
1021
+ updatedAt: updatedAt ?? await readFileMtimeIso(file),
1022
+ lastMessage,
1023
+ cwd,
1024
+ sessionFile: file,
1025
+ messageCount
1026
+ };
1027
+ }
1028
+ async function findSessionFiles(dir, maxDepth) {
1029
+ if (maxDepth < 0) return [];
1030
+ let entries;
1031
+ try {
1032
+ entries = await fs.readdir(dir, { withFileTypes: true });
1033
+ } catch {
1034
+ return [];
1035
+ }
1036
+ const files = [];
1037
+ for (const entry of entries) {
1038
+ const entryPath = path.join(dir, entry.name);
1039
+ if (entry.isDirectory()) files.push(...await findSessionFiles(entryPath, maxDepth - 1));
1040
+ else if (entry.isFile() && entry.name.endsWith(".jsonl")) files.push(entryPath);
1041
+ }
1042
+ return files;
1043
+ }
1044
+ function readSessionMetaCwd(line) {
1045
+ try {
1046
+ const parsed = JSON.parse(line);
1047
+ if (!isRecord(parsed) || parsed.type !== "session_meta" || !isRecord(parsed.payload)) return;
1048
+ return typeof parsed.payload.cwd === "string" && parsed.payload.cwd.trim() ? parsed.payload.cwd.trim() : void 0;
1049
+ } catch {
1050
+ return;
1051
+ }
1052
+ }
1053
+ function readResponseItemMessageText(parsed) {
1054
+ if (parsed.type !== "response_item" || !isRecord(parsed.payload)) return;
1055
+ if (parsed.payload.type !== "message") return;
1056
+ if ((typeof parsed.payload.role === "string" ? parsed.payload.role : "") !== "user") return;
1057
+ const parts = (Array.isArray(parsed.payload.content) ? parsed.payload.content : []).flatMap((entry) => {
1058
+ if (!isRecord(entry)) return [];
1059
+ const text = typeof entry.text === "string" ? entry.text : typeof entry.input_text === "string" ? entry.input_text : void 0;
1060
+ return text?.trim() ? [text.trim()] : [];
1061
+ });
1062
+ return parts.length > 0 ? parts.join(" ") : void 0;
1063
+ }
1064
+ function readSessionIdFromFilename(file) {
1065
+ return path.basename(file).match(/[0-9a-f]{8}-[0-9a-f-]{27,}/iu)?.[0];
1066
+ }
1067
+ async function resolveCodexCliNode(params) {
1068
+ const list = await params.runtime.nodes.list(params.requestedNode ? void 0 : { connected: true });
1069
+ const requested = params.requestedNode?.trim();
1070
+ const candidates = list.nodes.filter((node) => {
1071
+ if (requested) return [
1072
+ node.nodeId,
1073
+ node.displayName,
1074
+ node.remoteIp
1075
+ ].some((value) => value === requested);
1076
+ return node.connected === true && node.commands?.includes(params.command);
1077
+ });
1078
+ if (candidates.length === 0) throw new Error(requested ? `Codex CLI node ${requested} was not found.` : "No connected node exposes Codex CLI session commands.");
1079
+ const usable = candidates.filter((node) => node.commands?.includes(params.command));
1080
+ if (usable.length === 0) throw new Error(`Node ${requested ?? "candidate"} does not expose ${params.command}.`);
1081
+ if (usable.length > 1) throw new Error("Multiple Codex CLI-capable nodes connected. Pass --host <node-id>.");
1082
+ return usable[0];
1083
+ }
1084
+ function parseCodexCliSessionsListResult(raw) {
1085
+ const payload = unwrapNodeInvokePayload(raw);
1086
+ if (!isRecord(payload) || !Array.isArray(payload.sessions)) throw new Error("Codex CLI session list returned an invalid payload.");
1087
+ return {
1088
+ codexHome: typeof payload.codexHome === "string" ? payload.codexHome : "",
1089
+ sessions: payload.sessions.flatMap((entry) => {
1090
+ if (!isRecord(entry) || typeof entry.sessionId !== "string") return [];
1091
+ return [{
1092
+ sessionId: entry.sessionId,
1093
+ updatedAt: typeof entry.updatedAt === "string" ? entry.updatedAt : void 0,
1094
+ lastMessage: typeof entry.lastMessage === "string" ? entry.lastMessage : void 0,
1095
+ cwd: typeof entry.cwd === "string" ? entry.cwd : void 0,
1096
+ sessionFile: typeof entry.sessionFile === "string" ? entry.sessionFile : void 0,
1097
+ messageCount: typeof entry.messageCount === "number" && Number.isFinite(entry.messageCount) ? entry.messageCount : 0
1098
+ }];
1099
+ })
1100
+ };
1101
+ }
1102
+ function unwrapNodeInvokePayload(raw) {
1103
+ const record = isRecord(raw) ? raw : {};
1104
+ if (typeof record.payloadJSON === "string" && record.payloadJSON.trim()) try {
1105
+ return JSON.parse(record.payloadJSON);
1106
+ } catch (error) {
1107
+ throw new Error("Codex CLI node command returned malformed payloadJSON.", { cause: error });
1108
+ }
1109
+ if ("payload" in record) return record.payload;
1110
+ return raw;
1111
+ }
1112
+ function readRecordParam(paramsJSON) {
1113
+ if (!paramsJSON?.trim()) return {};
1114
+ try {
1115
+ const parsed = JSON.parse(paramsJSON);
1116
+ return isRecord(parsed) ? parsed : {};
1117
+ } catch {
1118
+ return {};
1119
+ }
1120
+ }
1121
+ function resolveCodexHome() {
1122
+ return process.env.CODEX_HOME?.trim() || path.join(os.homedir(), ".codex");
1123
+ }
1124
+ async function readFileIfExists(file) {
1125
+ try {
1126
+ return await fs.readFile(file, "utf8");
1127
+ } catch {
1128
+ return;
1129
+ }
1130
+ }
1131
+ async function readFirstLine(file) {
1132
+ return (await readFileIfExists(file))?.split(/\r?\n/u)[0];
1133
+ }
1134
+ async function readFileMtimeIso(file) {
1135
+ try {
1136
+ return (await fs.stat(file)).mtime.toISOString();
1137
+ } catch {
1138
+ return;
1139
+ }
1140
+ }
1141
+ function normalizeLimit(value) {
1142
+ return typeof value === "number" && Number.isFinite(value) ? Math.min(MAX_SESSION_LIMIT, Math.max(1, Math.floor(value))) : DEFAULT_SESSION_LIMIT;
1143
+ }
1144
+ function normalizeTimeoutMs(value) {
1145
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.min(60 * 6e4, Math.floor(value)) : DEFAULT_RESUME_TIMEOUT_MS;
1146
+ }
1147
+ function truncateText(value, max) {
1148
+ return value.length > max ? `${value.slice(0, max - 3)}...` : value;
1149
+ }
1150
+ function compareOptionalStringsDesc(a, b) {
1151
+ return (b ?? "").localeCompare(a ?? "");
1152
+ }
1153
+ function readNodeId(node) {
1154
+ if (!node.nodeId) throw new Error("Codex CLI node did not include a node id.");
1155
+ return node.nodeId;
1156
+ }
1157
+ function formatNodeLabel(node) {
1158
+ return [
1159
+ node.displayName,
1160
+ node.nodeId,
1161
+ node.remoteIp
1162
+ ].filter(Boolean).join(" / ") || "node";
1163
+ }
1164
+ function isRecord(value) {
1165
+ return Boolean(value && typeof value === "object" && !Array.isArray(value));
1166
+ }
1167
+ //#endregion
1168
+ export { steerCodexConversationTurn as _, resolveCodexCliSessionForBindingOnNode as a, readCodexConversationBindingData as b, handleCodexConversationInboundClaim as c, parseCodexFastModeArg as d, parseCodexPermissionsModeArg as f, setCodexConversationPermissions as g, setCodexConversationModel as h, listCodexCliSessionsOnNode as i, startCodexConversationThread as l, setCodexConversationFastMode as m, createCodexCliSessionNodeInvokePolicies as n, resumeCodexCliSessionOnNode as o, readCodexConversationActiveTurn as p, formatCodexCliSessions as r, handleCodexConversationBindingResolved as s, createCodexCliSessionNodeHostCommands as t, formatPermissionsMode as u, stopCodexConversationTurn as v, resolveCodexDefaultWorkspaceDir as x, createCodexCliNodeConversationBindingData as y };
@@ -1,4 +1,4 @@
1
- import { d as resolveCodexAppServerHomeDir } from "./shared-client-Cr6W-a2G.js";
1
+ import { f as resolveCodexAppServerHomeDir } from "./shared-client-BwUqd3lh.js";
2
2
  import { i as buildCodexAppInventoryCacheKey } from "./plugin-activation-PXGqUjwY.js";
3
3
  import { createHash } from "node:crypto";
4
4
  //#region extensions/codex/src/app-server/plugin-app-cache-key.ts
package/dist/provider.js CHANGED
@@ -123,7 +123,7 @@ async function listModelsBestEffort(params) {
123
123
  }
124
124
  }
125
125
  async function listCodexAppServerModelsLazy(options) {
126
- const { listCodexAppServerModels } = await import("./models-BmLfrDci.js").then((n) => n.r);
126
+ const { listCodexAppServerModels } = await import("./models-GCYf5s8J.js").then((n) => n.r);
127
127
  return listCodexAppServerModels(options);
128
128
  }
129
129
  function normalizeTimeoutMs(value) {
@@ -1,5 +1,5 @@
1
- import { n as CodexAppServerRpcError } from "./client-iRf11BEu.js";
2
- import { a as withTimeout, n as createIsolatedCodexAppServerClient, r as getSharedCodexAppServerClient } from "./shared-client-Cr6W-a2G.js";
1
+ import { n as CodexAppServerRpcError } from "./client-CoctX13d.js";
2
+ import { i as getSharedCodexAppServerClient, o as withTimeout, r as createIsolatedCodexAppServerClient } from "./shared-client-BwUqd3lh.js";
3
3
  //#region extensions/codex/src/app-server/capabilities.ts
4
4
  const CODEX_CONTROL_METHODS = {
5
5
  account: "account/read",