@openclaw/codex 2026.8.1-beta.3 → 2026.8.2
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/api.js +5 -6
- package/dist/{attempt-client-cleanup-URjUlCHg.js → attempt-client-cleanup-CpVfwctT.js} +47 -5
- package/dist/{auth-binding-B4FfbcCg.js → auth-binding-Ds_QVm-X.js} +18 -3
- package/dist/{binding-connection-DAvZwp96.js → binding-connection-CF7BmrDk.js} +2 -2
- package/dist/{bounded-turn-4BjrZEwW.js → bounded-turn-DRC3hcjm.js} +16 -20
- package/dist/{capabilities-CH3K57v4.js → capabilities-D6m_TdVy.js} +1 -1
- package/dist/cli-metadata.js +1 -1
- package/dist/{command-formatters-D0nZ3qtd.js → command-formatters--UToCokS.js} +4 -3
- package/dist/{command-handlers-DC86lgT4.js → command-handlers-CLFx2Ypa.js} +114 -79
- package/dist/{compact-COqgBRny.js → compact-5xqW1oCh.js} +13 -12
- package/dist/{config-CpNeo5AE.js → config-CcYL77O6.js} +350 -288
- package/dist/{conversation-binding-data-CW2GuupV.js → conversation-binding-data-BiodpIzq.js} +2 -1
- package/dist/doctor-contract-api.js +121 -16
- package/dist/{dynamic-tools-fJZhl4CE.js → dynamic-tools-BmeXjwNZ.js} +243 -1002
- package/dist/{effective-mcp-catalog-4YKn51aG.js → effective-mcp-catalog-XXQKgK1U.js} +2 -2
- package/dist/{event-projector-assistant-message-BwxV4d6N.js → event-projector-assistant-message-C5-Ds8mA.js} +18 -1
- package/dist/{event-projector-usage-CLwNEJqW.js → event-projector-usage-B2r5vhWH.js} +9 -14
- package/dist/{harness-DoKQcF8n.js → harness-BgeB7LnD.js} +42 -52
- package/dist/harness.js +1 -1
- package/dist/index.js +308 -306
- package/dist/{isolated-completion-DPMtlH9r.js → isolated-completion-CxTus3vZ.js} +4 -4
- package/dist/launch-args-sXOAg0SX.js +84 -0
- package/dist/{managed-binary-By4FZC6i.js → managed-binary-ZkGodW19.js} +43 -7
- package/dist/media-understanding-provider.js +1 -1
- package/dist/model-catalog-DULBcniB.js +101 -0
- package/dist/{models-CZw1wClT.js → models-DaWfETQk.js} +27 -29
- package/dist/{native-subagent-monitor-GGq3RnOo.js → native-subagent-monitor-vXYUZH37.js} +226 -129
- package/dist/{node-exec-server.runtime-Bsu1LdFZ.js → node-exec-server.runtime-DirKVZ5h.js} +9 -6
- package/dist/{plugin-approval-roundtrip-C75Yiiwc.js → plugin-approval-roundtrip-CCWQGlAI.js} +2 -1
- package/dist/{plugin-marketplace-discovery-CSWDkMrP.js → plugin-marketplace-discovery-BXjIFEiw.js} +38 -46
- package/dist/{plugin-metadata-cache-BXH5NF-4.js → plugin-metadata-cache-DQQm4gWT.js} +163 -136
- package/dist/{protocol-validators-VAVyEnDp.js → protocol-validators-Bg5rpNxk.js} +148 -5
- package/dist/{rate-limits-BI1dMHDG.js → rate-limits-BqHEHXQJ.js} +3 -2
- package/dist/{sandbox-guard-C1qEeZ5C.js → request-BWxweEdK.js} +183 -2
- package/dist/{run-attempt-BV3HzuCf.js → run-attempt-BVLE4Gbi.js} +706 -517
- package/dist/{runtime-artifact-BvyT1uyd.js → runtime-artifact-D9pYp4zL.js} +3 -3
- package/dist/{session-binding-BTrLf9Qm.js → session-binding-D0zinCP1.js} +195 -122
- package/dist/{session-catalog-ezP_UcRM.js → session-catalog-eMhVm0Ql.js} +448 -313
- package/dist/session-catalog-home-id-Dt2GiG5o.js +112 -0
- package/dist/{session-cli-B1hKvfkI.js → session-cli-B2lyjJA0.js} +1 -1
- package/dist/session-history-C5J1AKzG.js +87 -0
- package/dist/session-permission-policy-ScnAyG90.js +160 -0
- package/dist/session-retirement-CtUtUTr9.js +90 -0
- package/dist/{session-upstream-marker-D_2npHlA.js → session-upstream-marker-gqrYIRHk.js} +2 -3
- package/dist/settled-turn-context-Bk3IUwod.js +290 -0
- package/dist/settled-turn-finalizer-BXLN9PfJ.js +104 -0
- package/dist/{shared-client-Dw-rzii0.js → shared-client-B1tT5U6r.js} +1738 -806
- package/dist/{side-question-DbXkJZzg.js → side-question-CZ-mCw-t.js} +76 -43
- package/dist/{thread-lifecycle-DKdrnTMX.js → thread-lifecycle-CGGKP720.js} +991 -455
- package/dist/{thread-ownership-i2NBwDUL.js → thread-ownership-RkaoZCmQ.js} +18 -8
- package/dist/{plugin-app-cache-key-DMNQ8Zi8.js → thread-resume-BFt1-ZDa.js} +55 -8
- package/dist/{transcript-mirror-BU0_LKAL.js → transcript-mirror-1ep4XjzF.js} +124 -18
- package/dist/transport-stdio-NT_Dpd9V.js +724 -0
- package/dist/{upstream-prompt-provenance-CFmsKwr9.js → upstream-prompt-provenance-LphB8slG.js} +8 -4
- package/dist/{upstream-session-fork-BDVJCLAD.js → upstream-session-fork-Dc8BFExw.js} +76 -90
- package/dist/{usage-9dKJCgcy.js → usage-DUhd58gI.js} +3 -3
- package/dist/{web-search-provider.runtime-DCdx4DGu.js → web-search-provider.runtime-BEmlE7ov.js} +3 -3
- package/openclaw.plugin.json +19 -1
- package/package.json +8 -8
- package/dist/app-server-policy-bg5QPSVP.js +0 -25
- package/dist/command-rpc-xUIIonsO.js +0 -90
- package/dist/incognito-session-ET_ufDH-.js +0 -2
- package/dist/model-catalog-CmGoqVKB.js +0 -48
- package/dist/request-DSK0W6YI.js +0 -157
- package/dist/session-catalog-home-id-BNwAJ9D7.js +0 -18
- package/dist/session-retirement-CE4iMiLh.js +0 -36
- package/dist/settled-turn-finalizer-Dx1onIqg.js +0 -328
- package/dist/thread-resume-CdJk2Ehf.js +0 -30
- package/dist/transport-stdio-DhoGy33Z.js +0 -99
|
@@ -1,40 +1,44 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { c as reclaimCurrentCodexSessionGeneration, d as sessionBindingIdentity } from "./session-binding-
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { n as
|
|
7
|
-
import {
|
|
8
|
-
import { t as
|
|
9
|
-
import { r as
|
|
10
|
-
import {
|
|
11
|
-
import { n as
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
1
|
+
import { F as resolveCodexAppServerLocalHomeDir, I as resolveCodexAppServerUserHomeDir, P as resolveCodexAppServerHomeDir, T as readCodexPluginConfig, i as resolveCodexAppServerRuntimeOptions, s as resolveCodexSupervisionAppServerRuntimeOptions } from "./config-CcYL77O6.js";
|
|
2
|
+
import { $ as CodexAppServerRpcError, Et as withTimeout, Ht as isJsonObject, Lt as resolveCodexAppServerPreparedAuthHandoff, Mt as resolveCodexAppServerAuthProfileId, Pt as resolveCodexAppServerAuthProfileStore, Q as resolveCodexAppServerClientInstanceId, Rt as CODEX_INTERACTIVE_CUSTOM_THREAD_SOURCES, c as getLeasedSharedCodexAppServerClient, h as releaseLeasedSharedCodexAppServerClient, zt as CODEX_INTERACTIVE_THREAD_SOURCE_KINDS } from "./shared-client-B1tT5U6r.js";
|
|
3
|
+
import { c as reclaimCurrentCodexSessionGeneration, d as sessionBindingIdentity } from "./session-binding-D0zinCP1.js";
|
|
4
|
+
import { i as assertCodexThreadForkParams } from "./protocol-validators-Bg5rpNxk.js";
|
|
5
|
+
import { a as closeCodexStartupClientBestEffort } from "./attempt-client-cleanup-CpVfwctT.js";
|
|
6
|
+
import { n as listCodexAppServerModels } from "./models-DaWfETQk.js";
|
|
7
|
+
import { a as replaceCodexCatalogConnectionHomes, n as buildCodexAppServerConnectionFingerprint, t as resumeCodexAppServerThread } from "./thread-resume-BFt1-ZDa.js";
|
|
8
|
+
import { i as readCodexSessionMeta, n as codexCatalogHomeId, r as isOpenClawManagedCodexThread, t as canonicalCodexCatalogHome } from "./session-catalog-home-id-Dt2GiG5o.js";
|
|
9
|
+
import { i as requestCodexAppServerJson, o as withCodexAppServerJsonClient, r as requestCodexAppServerClientJson } from "./request-BWxweEdK.js";
|
|
10
|
+
import { m as projectCodexUserItemText, r as importCodexThreadHistoryToTranscript } from "./transcript-mirror-1ep4XjzF.js";
|
|
11
|
+
import { n as describeControlFailure, t as CODEX_CONTROL_METHODS } from "./capabilities-D6m_TdVy.js";
|
|
12
|
+
import { r as formatCodexDisplayText } from "./command-formatters--UToCokS.js";
|
|
13
|
+
import { n as createCodexCliNodeConversationBindingData } from "./conversation-binding-data-BiodpIzq.js";
|
|
14
|
+
import { n as prepareCodexAppServerAuthBinding } from "./auth-binding-Ds_QVm-X.js";
|
|
15
|
+
import { i as createImportedCodexSession, n as codexUpstreamBaseline, r as codexUpstreamContinueResult, t as codexLastTerminalTurnId } from "./session-upstream-marker-gqrYIRHk.js";
|
|
14
16
|
import { asFiniteNumber, isRecord, normalizeBoundedOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
15
17
|
import fs from "node:fs/promises";
|
|
16
18
|
import path from "node:path";
|
|
17
19
|
import { timestampMsToIsoString } from "openclaw/plugin-sdk/number-runtime";
|
|
18
20
|
import { resolvePreferredOpenClawTmpDir } from "openclaw/plugin-sdk/temp-path";
|
|
21
|
+
import { prepareAgentRuntimeAuth } from "openclaw/plugin-sdk/agent-harness-runtime";
|
|
19
22
|
import fsSync from "node:fs";
|
|
20
23
|
import os from "node:os";
|
|
21
|
-
import { listAgentIds, resolveAgentDir, resolveAllowedModelRef, resolveDefaultAgentDir, resolveDefaultAgentId, resolveDefaultModelForAgent
|
|
22
|
-
import { pruneMapToMaxSize } from "openclaw/plugin-sdk/collection-runtime";
|
|
24
|
+
import { listAgentIds, resolveAgentDir as resolveAgentDir$1, resolveAgentWorkspaceDir, resolveAllowedModelRef, resolveDefaultAgentDir, resolveDefaultAgentId, resolveDefaultModelForAgent } from "openclaw/plugin-sdk/agent-runtime";
|
|
23
25
|
import { runCommandBuffered } from "openclaw/plugin-sdk/process-runtime";
|
|
26
|
+
import { resolveSessionAgentIdsStrict } from "openclaw/plugin-sdk/agent-scope-runtime";
|
|
24
27
|
import { materializeWindowsSpawnProgram, resolveWindowsSpawnProgram } from "openclaw/plugin-sdk/windows-spawn";
|
|
25
|
-
import { resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime";
|
|
28
|
+
import { getSessionEntry, resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime";
|
|
26
29
|
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
27
30
|
import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
|
|
28
31
|
import { sanitizeTerminalText } from "openclaw/plugin-sdk/text-chunking";
|
|
29
32
|
import { parseAgentSessionKey } from "openclaw/plugin-sdk/routing";
|
|
30
|
-
import { root } from "openclaw/plugin-sdk/file-access-runtime";
|
|
31
33
|
import process$1 from "node:process";
|
|
34
|
+
import { resolveSessionModelRef } from "openclaw/plugin-sdk/model-session-runtime";
|
|
35
|
+
import { resolveApiKeyForProvider } from "openclaw/plugin-sdk/provider-auth-runtime";
|
|
32
36
|
import { createSessionCatalogAdoptionCoordinator, listSessionCatalogEntries, sessionCatalogAdoptedSessionKey, sessionCatalogAdoptedSourceKey } from "openclaw/plugin-sdk/session-catalog";
|
|
33
37
|
import { decodeNodePtyResumeParams, resolveNodeHostExecutable, runNodePtyCommand } from "openclaw/plugin-sdk/node-host";
|
|
34
|
-
import {
|
|
38
|
+
import { pruneMapToMaxSize } from "openclaw/plugin-sdk/collection-runtime";
|
|
35
39
|
//#region extensions/codex/src/jsonl-lines.ts
|
|
36
|
-
const JSONL_STREAM_THRESHOLD_BYTES =
|
|
37
|
-
const JSONL_READ_CHUNK_BYTES =
|
|
40
|
+
const JSONL_STREAM_THRESHOLD_BYTES = 4194304;
|
|
41
|
+
const JSONL_READ_CHUNK_BYTES = 1048576;
|
|
38
42
|
async function visitJsonlLines(file, visitor, chunkBytes = JSONL_READ_CHUNK_BYTES) {
|
|
39
43
|
let size;
|
|
40
44
|
try {
|
|
@@ -134,7 +138,7 @@ const CODEX_CLI_SESSIONS_LIST_COMMAND = "codex.cli.sessions.list";
|
|
|
134
138
|
const CODEX_CLI_SESSION_RESUME_COMMAND = "codex.cli.session.resume";
|
|
135
139
|
const DEFAULT_SESSION_LIMIT = 10;
|
|
136
140
|
const MAX_SESSION_LIMIT = 50;
|
|
137
|
-
const DEFAULT_RESUME_TIMEOUT_MS =
|
|
141
|
+
const DEFAULT_RESUME_TIMEOUT_MS = 12e5;
|
|
138
142
|
const SESSION_ID_PATTERN = /^[A-Za-z0-9._:-]{1,128}$/;
|
|
139
143
|
const activeResumeSessions = /* @__PURE__ */ new Set();
|
|
140
144
|
function createCodexCliSessionNodeHostCommands() {
|
|
@@ -525,7 +529,7 @@ function normalizeLimit$1(value) {
|
|
|
525
529
|
return typeof value === "number" && Number.isFinite(value) ? Math.min(MAX_SESSION_LIMIT, Math.max(1, Math.floor(value))) : DEFAULT_SESSION_LIMIT;
|
|
526
530
|
}
|
|
527
531
|
function normalizeTimeoutMs(value) {
|
|
528
|
-
return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.min(
|
|
532
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.min(36e5, Math.floor(value)) : DEFAULT_RESUME_TIMEOUT_MS;
|
|
529
533
|
}
|
|
530
534
|
function truncateText(value, max) {
|
|
531
535
|
if (value.length <= max) return value;
|
|
@@ -546,6 +550,197 @@ function formatNodeLabel(node) {
|
|
|
546
550
|
].filter(Boolean).join(" / ") || "node";
|
|
547
551
|
}
|
|
548
552
|
//#endregion
|
|
553
|
+
//#region extensions/codex/src/command-rpc.ts
|
|
554
|
+
async function prepareControlAuth(options, startOptions) {
|
|
555
|
+
if (!options.onResponse || !options.config || !options.sessionKey || options.authProfileId === null || startOptions.homeScope === "user") return {
|
|
556
|
+
authProfileId: options.authProfileId ?? void 0,
|
|
557
|
+
clientOptions: { authProfileId: options.authProfileId }
|
|
558
|
+
};
|
|
559
|
+
const config = options.config;
|
|
560
|
+
const { sessionAgentId } = resolveSessionAgentIdsStrict({
|
|
561
|
+
config,
|
|
562
|
+
sessionKey: options.sessionKey,
|
|
563
|
+
agentId: options.agentId
|
|
564
|
+
});
|
|
565
|
+
const agentDir = options.agentDir ?? resolveAgentDir$1(config, sessionAgentId);
|
|
566
|
+
const workspaceDir = resolveAgentWorkspaceDir(config, sessionAgentId);
|
|
567
|
+
const entry = getSessionEntry({
|
|
568
|
+
agentId: sessionAgentId,
|
|
569
|
+
storePath: resolveStorePath(config.session?.store, { agentId: sessionAgentId }),
|
|
570
|
+
sessionKey: options.sessionKey,
|
|
571
|
+
hydrateSkillPromptRefs: false,
|
|
572
|
+
readConsistency: "latest"
|
|
573
|
+
});
|
|
574
|
+
const model = resolveSessionModelRef(config, entry, sessionAgentId);
|
|
575
|
+
const store = resolveCodexAppServerAuthProfileStore({
|
|
576
|
+
agentDir,
|
|
577
|
+
config
|
|
578
|
+
});
|
|
579
|
+
const { plan, attempts } = prepareAgentRuntimeAuth({
|
|
580
|
+
provider: model.provider,
|
|
581
|
+
modelId: model.model,
|
|
582
|
+
config,
|
|
583
|
+
agentDir,
|
|
584
|
+
workspaceDir,
|
|
585
|
+
authProfileStore: store,
|
|
586
|
+
sessionAuthProfileId: entry?.authProfileOverride ?? options.authProfileId,
|
|
587
|
+
sessionAuthProfileSource: entry?.authProfileOverrideSource,
|
|
588
|
+
harnessId: "codex",
|
|
589
|
+
harnessAuthBootstrap: "harness"
|
|
590
|
+
});
|
|
591
|
+
const route = plan.modelRoute;
|
|
592
|
+
const resolvedAuth = route ? await resolveApiKeyForProvider({
|
|
593
|
+
provider: route.provider,
|
|
594
|
+
modelId: route.modelId,
|
|
595
|
+
modelApi: route.api,
|
|
596
|
+
cfg: config,
|
|
597
|
+
agentDir,
|
|
598
|
+
workspaceDir,
|
|
599
|
+
store,
|
|
600
|
+
profileId: attempts[0]?.profileId,
|
|
601
|
+
lockedProfile: plan.forwardedAuthProfileSource === "user",
|
|
602
|
+
allowAuthProfileFallback: attempts[0]?.allowAuthProfileFallback,
|
|
603
|
+
skipSetupProviderFallback: true
|
|
604
|
+
}) : void 0;
|
|
605
|
+
const handoff = await resolveCodexAppServerPreparedAuthHandoff({
|
|
606
|
+
authRequirement: route?.authRequirement,
|
|
607
|
+
resolvedApiKey: resolvedAuth?.apiKey,
|
|
608
|
+
authProfileId: route ? plan.forwardedAuthProfileId : resolveCodexAppServerAuthProfileId({
|
|
609
|
+
authProfileId: plan.forwardedAuthProfileId,
|
|
610
|
+
store,
|
|
611
|
+
config
|
|
612
|
+
}),
|
|
613
|
+
authProfileStore: store,
|
|
614
|
+
agentDir,
|
|
615
|
+
homeScope: startOptions.homeScope ?? "agent",
|
|
616
|
+
config,
|
|
617
|
+
subscriptionProfileRequiredError: "Prepared Codex subscription route requires a forwarded OpenAI OAuth or token profile.",
|
|
618
|
+
subscriptionProfileUnusableError: "Prepared Codex subscription auth profile is unusable."
|
|
619
|
+
});
|
|
620
|
+
const binding = handoff.authProfileId ? await prepareCodexAppServerAuthBinding({
|
|
621
|
+
authProfileId: handoff.authProfileId,
|
|
622
|
+
authProfileStore: store,
|
|
623
|
+
agentDir,
|
|
624
|
+
config
|
|
625
|
+
}) : void 0;
|
|
626
|
+
return {
|
|
627
|
+
authProfileId: handoff.authProfileId,
|
|
628
|
+
clientOptions: {
|
|
629
|
+
...handoff.preparedAuth ? { preparedAuth: handoff.preparedAuth } : { authProfileId: handoff.authProfileId },
|
|
630
|
+
authRequirement: route?.authRequirement,
|
|
631
|
+
authProfileStore: binding?.authProfileStore ?? store,
|
|
632
|
+
authBindingFingerprint: binding?.fingerprint,
|
|
633
|
+
agentDir
|
|
634
|
+
}
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
function requestOptions(pluginConfig, limit, config, agentDir) {
|
|
638
|
+
const runtime = resolveCodexAppServerRuntimeOptions({ pluginConfig });
|
|
639
|
+
return {
|
|
640
|
+
limit,
|
|
641
|
+
timeoutMs: runtime.requestTimeoutMs,
|
|
642
|
+
startOptions: runtime.start,
|
|
643
|
+
config,
|
|
644
|
+
agentDir
|
|
645
|
+
};
|
|
646
|
+
}
|
|
647
|
+
async function codexControlRequest(pluginConfig, method, requestParams, options = {}) {
|
|
648
|
+
const runtime = options.startOptions ? resolveCodexSupervisionAppServerRuntimeOptions({ pluginConfig }) : resolveCodexAppServerRuntimeOptions({ pluginConfig });
|
|
649
|
+
const startOptions = options.startOptions ?? runtime.start;
|
|
650
|
+
const auth = await prepareControlAuth(options, startOptions);
|
|
651
|
+
const controlRequestOptions = {
|
|
652
|
+
timeoutMs: options.timeoutMs ?? runtime.requestTimeoutMs,
|
|
653
|
+
startOptions,
|
|
654
|
+
config: options.config,
|
|
655
|
+
sessionKey: options.sessionKey,
|
|
656
|
+
sessionId: options.sessionId,
|
|
657
|
+
agentDir: options.agentDir,
|
|
658
|
+
isolated: options.isolated,
|
|
659
|
+
...auth.clientOptions
|
|
660
|
+
};
|
|
661
|
+
if (options.onResponse || options.beforeRequest) return await withCodexAppServerJsonClient(controlRequestOptions, async (request, client, scope) => {
|
|
662
|
+
await options.beforeRequest?.(request);
|
|
663
|
+
scope.assertCurrent();
|
|
664
|
+
let response;
|
|
665
|
+
if (method === "thread/resume") {
|
|
666
|
+
if (!isJsonObject(requestParams) || typeof requestParams.threadId !== "string") throw new Error("Codex thread/resume requires a thread id.");
|
|
667
|
+
response = await resumeCodexAppServerThread({
|
|
668
|
+
client,
|
|
669
|
+
request: {
|
|
670
|
+
...requestParams,
|
|
671
|
+
threadId: requestParams.threadId
|
|
672
|
+
},
|
|
673
|
+
requestResume: () => request({
|
|
674
|
+
method,
|
|
675
|
+
requestParams
|
|
676
|
+
}),
|
|
677
|
+
abandonClient: () => closeCodexStartupClientBestEffort(client)
|
|
678
|
+
});
|
|
679
|
+
} else response = await request({
|
|
680
|
+
method,
|
|
681
|
+
requestParams
|
|
682
|
+
});
|
|
683
|
+
await options.onResponse?.(response, client, {
|
|
684
|
+
authProfileId: auth.authProfileId,
|
|
685
|
+
assertCurrent: scope.assertCurrent
|
|
686
|
+
});
|
|
687
|
+
scope.assertCurrent();
|
|
688
|
+
return response;
|
|
689
|
+
});
|
|
690
|
+
return await requestCodexAppServerJson({
|
|
691
|
+
method,
|
|
692
|
+
requestParams,
|
|
693
|
+
...controlRequestOptions
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
async function safeCodexControlRequest(pluginConfig, method, requestParams, options = {}) {
|
|
697
|
+
return await safeValue(async () => await codexControlRequest(pluginConfig, method, requestParams, options));
|
|
698
|
+
}
|
|
699
|
+
async function safeCodexModelList(pluginConfig, limit, config, agentDir) {
|
|
700
|
+
return await safeValue(async () => await listCodexAppServerModels(requestOptions(pluginConfig, limit, config, agentDir)));
|
|
701
|
+
}
|
|
702
|
+
async function readCodexStatusProbes(pluginConfig, config, agentDir) {
|
|
703
|
+
const [models, account, limits, mcps, skills] = await Promise.all([
|
|
704
|
+
safeCodexModelList(pluginConfig, 20, config, agentDir),
|
|
705
|
+
safeCodexControlRequest(pluginConfig, CODEX_CONTROL_METHODS.account, { refreshToken: false }, {
|
|
706
|
+
config,
|
|
707
|
+
agentDir
|
|
708
|
+
}),
|
|
709
|
+
safeCodexControlRequest(pluginConfig, CODEX_CONTROL_METHODS.rateLimits, void 0, {
|
|
710
|
+
config,
|
|
711
|
+
agentDir
|
|
712
|
+
}),
|
|
713
|
+
safeCodexControlRequest(pluginConfig, CODEX_CONTROL_METHODS.listMcpServers, { limit: 100 }, {
|
|
714
|
+
config,
|
|
715
|
+
agentDir
|
|
716
|
+
}),
|
|
717
|
+
safeCodexControlRequest(pluginConfig, CODEX_CONTROL_METHODS.listSkills, {}, {
|
|
718
|
+
config,
|
|
719
|
+
agentDir
|
|
720
|
+
})
|
|
721
|
+
]);
|
|
722
|
+
return {
|
|
723
|
+
models,
|
|
724
|
+
account,
|
|
725
|
+
limits,
|
|
726
|
+
mcps,
|
|
727
|
+
skills
|
|
728
|
+
};
|
|
729
|
+
}
|
|
730
|
+
async function safeValue(read) {
|
|
731
|
+
try {
|
|
732
|
+
return {
|
|
733
|
+
ok: true,
|
|
734
|
+
value: await read()
|
|
735
|
+
};
|
|
736
|
+
} catch (error) {
|
|
737
|
+
return {
|
|
738
|
+
ok: false,
|
|
739
|
+
error: describeControlFailure(error)
|
|
740
|
+
};
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
//#endregion
|
|
549
744
|
//#region extensions/codex/src/app-server/thread-archive-guard.ts
|
|
550
745
|
const DESCENDANT_PAGE_LIMIT = 100;
|
|
551
746
|
const MAX_DESCENDANT_PAGES = 100;
|
|
@@ -613,7 +808,7 @@ const MAX_SESSION_PREVIEW_LENGTH = 500;
|
|
|
613
808
|
const MAX_SESSION_KEY_LENGTH = 1024;
|
|
614
809
|
const MAX_METADATA_LENGTH = 500;
|
|
615
810
|
const MAX_ACTIVE_FLAGS = 16;
|
|
616
|
-
const MAX_TRANSCRIPT_PAGE_BYTES =
|
|
811
|
+
const MAX_TRANSCRIPT_PAGE_BYTES = 20971520;
|
|
617
812
|
var CatalogParamsError = class extends Error {};
|
|
618
813
|
function readControlCursor(value, label) {
|
|
619
814
|
if (value === void 0 || value === null) return;
|
|
@@ -821,7 +1016,7 @@ function filterCatalogPageByTitle(page, searchTerm) {
|
|
|
821
1016
|
if (!searchTerm) return page;
|
|
822
1017
|
return {
|
|
823
1018
|
...page,
|
|
824
|
-
sessions: page.sessions.filter((session) => session.name?.toLocaleLowerCase().includes(searchTerm.toLocaleLowerCase()))
|
|
1019
|
+
sessions: page.sessions.filter((session) => (session.name ?? session.fallbackName)?.toLocaleLowerCase().includes(searchTerm.toLocaleLowerCase()))
|
|
825
1020
|
};
|
|
826
1021
|
}
|
|
827
1022
|
function unwrapNodeInvokePayload(value) {
|
|
@@ -997,7 +1192,7 @@ async function createOrReuseNodeAdoptedSession(params) {
|
|
|
997
1192
|
key: nodeAdoptionSessionKey(params.hostId, params.record.threadId),
|
|
998
1193
|
agentId: params.agentId,
|
|
999
1194
|
recoverMatchingInitialEntry: true,
|
|
1000
|
-
|
|
1195
|
+
displayName: params.record.name ?? void 0,
|
|
1001
1196
|
...params.record.cwd?.trim() ? { spawnedCwd: params.record.cwd.trim() } : {},
|
|
1002
1197
|
initialEntry: {
|
|
1003
1198
|
agentHarnessId: "codex",
|
|
@@ -1040,182 +1235,6 @@ async function createOrReuseNodeAdoptedSession(params) {
|
|
|
1040
1235
|
}
|
|
1041
1236
|
}
|
|
1042
1237
|
//#endregion
|
|
1043
|
-
//#region extensions/codex/src/session-catalog-terminal.ts
|
|
1044
|
-
const CODEX_TERMINAL_RESUME_COMMAND = "codex.terminal.resume.v1";
|
|
1045
|
-
function resolveCodexCatalogTerminalHome(sources) {
|
|
1046
|
-
const runtimeConfig = sources.getRuntimeConfig();
|
|
1047
|
-
if (!runtimeConfig) throw new Error("OpenClaw runtime config is unavailable");
|
|
1048
|
-
const agentDir = sources.source?.agentDir ?? (sources.agentId ? resolveAgentDir(runtimeConfig, sources.agentId) : resolveDefaultAgentDir(runtimeConfig));
|
|
1049
|
-
return resolveCodexAppServerLocalHomeDir(sources.source?.appServer.start ?? resolveCodexSupervisionAppServerRuntimeOptions({ pluginConfig: sources.getPluginConfig() }).start, agentDir);
|
|
1050
|
-
}
|
|
1051
|
-
function resolveLocalCodexTerminalExecutable(env = process.env) {
|
|
1052
|
-
return resolveLocalCodexTerminalResolution(env)?.executable;
|
|
1053
|
-
}
|
|
1054
|
-
function resolveLocalCodexTerminalResolution(env = process.env) {
|
|
1055
|
-
return resolveNodeHostExecutable("codex", {
|
|
1056
|
-
env,
|
|
1057
|
-
pathEnv: env.PATH ?? env.Path ?? "",
|
|
1058
|
-
strategy: "fallback"
|
|
1059
|
-
});
|
|
1060
|
-
}
|
|
1061
|
-
function codexNodeTerminalCapability(node) {
|
|
1062
|
-
const commands = node.invocableCommands ?? node.commands;
|
|
1063
|
-
return node.connected === true && commands?.includes("codex.terminal.resume.v1") === true ? { canOpenTerminalCodex: true } : {};
|
|
1064
|
-
}
|
|
1065
|
-
async function requireCatalogEligibleThread(control, threadId) {
|
|
1066
|
-
const cached = await findCatalogEligibleThread(control, threadId, false);
|
|
1067
|
-
if (cached) return cached;
|
|
1068
|
-
const refreshed = await findCatalogEligibleThread(control, threadId, true);
|
|
1069
|
-
if (refreshed) return refreshed;
|
|
1070
|
-
throw new CatalogParamsError("Codex session is not a non-archived interactive Codex session");
|
|
1071
|
-
}
|
|
1072
|
-
async function findCatalogEligibleThread(control, threadId, forceRefresh) {
|
|
1073
|
-
let cursor;
|
|
1074
|
-
const seenCursors = /* @__PURE__ */ new Set();
|
|
1075
|
-
for (let pageIndex = 0; pageIndex < 100; pageIndex += 1) {
|
|
1076
|
-
const page = await control.listPage({
|
|
1077
|
-
limit: 100,
|
|
1078
|
-
...cursor ? { cursor } : {},
|
|
1079
|
-
...forceRefresh ? { forceRefresh: true } : {}
|
|
1080
|
-
});
|
|
1081
|
-
const candidate = page.sessions.find((session) => session.threadId === threadId);
|
|
1082
|
-
if (candidate) {
|
|
1083
|
-
if (isInteractiveThreadSource(candidate.source)) return candidate;
|
|
1084
|
-
throw new CatalogParamsError("Codex session is not a non-archived interactive Codex session");
|
|
1085
|
-
}
|
|
1086
|
-
const nextCursor = page.nextCursor?.trim();
|
|
1087
|
-
if (!nextCursor) return;
|
|
1088
|
-
if (seenCursors.has(nextCursor)) throw new CatalogParamsError("Codex session eligibility could not be verified");
|
|
1089
|
-
seenCursors.add(nextCursor);
|
|
1090
|
-
cursor = nextCursor;
|
|
1091
|
-
}
|
|
1092
|
-
throw new CatalogParamsError("Codex session eligibility could not be verified");
|
|
1093
|
-
}
|
|
1094
|
-
function createCodexTerminalNodeHostCommand(bindRequest, configSources) {
|
|
1095
|
-
return {
|
|
1096
|
-
command: CODEX_TERMINAL_RESUME_COMMAND,
|
|
1097
|
-
cap: CODEX_APP_SERVER_THREADS_CAPABILITY,
|
|
1098
|
-
dangerous: false,
|
|
1099
|
-
duplex: true,
|
|
1100
|
-
isAvailable: ({ env }) => Boolean(resolveNodeHostExecutable("codex", {
|
|
1101
|
-
env,
|
|
1102
|
-
pathEnv: env.PATH ?? env.Path ?? "",
|
|
1103
|
-
strategy: "direct"
|
|
1104
|
-
})),
|
|
1105
|
-
handle: async (paramsJSON, io) => {
|
|
1106
|
-
if (!io) throw new Error("Codex terminal command requires duplex transport");
|
|
1107
|
-
const request = bindRequest(paramsJSON);
|
|
1108
|
-
const resume = decodeNodePtyResumeParams(request.paramsJSON, (value) => {
|
|
1109
|
-
if (typeof value !== "string" || !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iu.test(value)) throw new CatalogParamsError("threadId must be a UUID");
|
|
1110
|
-
return value;
|
|
1111
|
-
});
|
|
1112
|
-
const record = await requireCatalogEligibleThread(request.control, resume.threadId);
|
|
1113
|
-
const resolution = resolveNodeHostExecutable("codex", {
|
|
1114
|
-
env: process.env,
|
|
1115
|
-
pathEnv: process.env.PATH ?? process.env.Path ?? "",
|
|
1116
|
-
strategy: "direct"
|
|
1117
|
-
});
|
|
1118
|
-
if (!resolution) throw new Error("Codex CLI is unavailable");
|
|
1119
|
-
return JSON.stringify(await runNodePtyCommand({
|
|
1120
|
-
file: resolution.executable,
|
|
1121
|
-
args: ["resume", resume.threadId],
|
|
1122
|
-
cwd: record.cwd,
|
|
1123
|
-
env: { CODEX_HOME: resolveCodexCatalogTerminalHome({
|
|
1124
|
-
...configSources,
|
|
1125
|
-
agentId: request.agentId
|
|
1126
|
-
}) },
|
|
1127
|
-
cols: resume.cols,
|
|
1128
|
-
rows: resume.rows
|
|
1129
|
-
}, io));
|
|
1130
|
-
}
|
|
1131
|
-
};
|
|
1132
|
-
}
|
|
1133
|
-
async function resolveNodeCatalogEligibleThread(params) {
|
|
1134
|
-
let cursor;
|
|
1135
|
-
const seenCursors = /* @__PURE__ */ new Set();
|
|
1136
|
-
for (let pageIndex = 0; pageIndex < 100; pageIndex += 1) {
|
|
1137
|
-
const raw = await params.runtime.nodes.invoke({
|
|
1138
|
-
nodeId: params.nodeId,
|
|
1139
|
-
command: CODEX_APP_SERVER_THREADS_LIST_COMMAND,
|
|
1140
|
-
params: {
|
|
1141
|
-
agentId: params.agentId,
|
|
1142
|
-
limit: 100,
|
|
1143
|
-
...cursor ? { cursor } : {}
|
|
1144
|
-
},
|
|
1145
|
-
timeoutMs: NODE_INVOKE_TIMEOUT_MS,
|
|
1146
|
-
scopes: ["operator.write"]
|
|
1147
|
-
});
|
|
1148
|
-
const page = params.parseCatalogPage(unwrapNodeInvokePayload(raw));
|
|
1149
|
-
const record = page.sessions.find((candidate) => candidate.threadId === params.threadId);
|
|
1150
|
-
if (record) {
|
|
1151
|
-
if (isInteractiveThreadSource(record.source)) return record;
|
|
1152
|
-
break;
|
|
1153
|
-
}
|
|
1154
|
-
const nextCursor = page.nextCursor?.trim();
|
|
1155
|
-
if (!nextCursor || seenCursors.has(nextCursor)) break;
|
|
1156
|
-
seenCursors.add(nextCursor);
|
|
1157
|
-
cursor = nextCursor;
|
|
1158
|
-
}
|
|
1159
|
-
throw new CatalogParamsError("Codex session is not a non-archived interactive Codex session");
|
|
1160
|
-
}
|
|
1161
|
-
async function openCodexCatalogTerminal(params) {
|
|
1162
|
-
const title = `codex resume ${params.threadId.slice(0, 8)}…`;
|
|
1163
|
-
if (params.hostId === "gateway:local" || params.hostId.startsWith(`gateway:local:`)) {
|
|
1164
|
-
const record = await requireCatalogEligibleThread(params.control, params.threadId);
|
|
1165
|
-
const resolution = resolveLocalCodexTerminalResolution();
|
|
1166
|
-
if (!resolution) throw new CatalogParamsError("Codex CLI is unavailable");
|
|
1167
|
-
return {
|
|
1168
|
-
kind: "local",
|
|
1169
|
-
argv: [
|
|
1170
|
-
resolution.executable,
|
|
1171
|
-
"resume",
|
|
1172
|
-
params.threadId
|
|
1173
|
-
],
|
|
1174
|
-
...record.cwd ? { cwd: record.cwd } : {},
|
|
1175
|
-
env: { CODEX_HOME: resolveCodexCatalogTerminalHome(params) },
|
|
1176
|
-
...resolution.pathEnv ? { pathEnv: resolution.pathEnv } : {},
|
|
1177
|
-
title
|
|
1178
|
-
};
|
|
1179
|
-
}
|
|
1180
|
-
if (!params.hostId.startsWith("node:")) throw new CatalogParamsError("hostId is invalid");
|
|
1181
|
-
const nodeId = params.hostId.slice(5);
|
|
1182
|
-
if (!(await params.api.runtime.nodes.list()).nodes.find((candidate) => {
|
|
1183
|
-
const commands = candidate.invocableCommands ?? candidate.commands;
|
|
1184
|
-
return candidate.nodeId === nodeId && candidate.connected === true && commands?.includes("codex.appServer.threads.list.v1") === true && commands.includes("codex.terminal.resume.v1");
|
|
1185
|
-
})) throw new CatalogParamsError("paired-node Codex terminal is unavailable");
|
|
1186
|
-
const record = await resolveNodeCatalogEligibleThread({
|
|
1187
|
-
agentId: params.agentId,
|
|
1188
|
-
runtime: params.api.runtime,
|
|
1189
|
-
nodeId,
|
|
1190
|
-
threadId: params.threadId,
|
|
1191
|
-
parseCatalogPage: params.parseCatalogPage
|
|
1192
|
-
});
|
|
1193
|
-
return {
|
|
1194
|
-
kind: "node",
|
|
1195
|
-
nodeId,
|
|
1196
|
-
command: CODEX_TERMINAL_RESUME_COMMAND,
|
|
1197
|
-
paramsJSON: JSON.stringify({
|
|
1198
|
-
agentId: params.agentId,
|
|
1199
|
-
threadId: params.threadId
|
|
1200
|
-
}),
|
|
1201
|
-
...record.cwd ? { cwd: record.cwd } : {},
|
|
1202
|
-
title
|
|
1203
|
-
};
|
|
1204
|
-
}
|
|
1205
|
-
async function startCodexCatalogTerminal(params) {
|
|
1206
|
-
if (params.nodeId) throw new CatalogParamsError("Paired-node Codex terminal start is unavailable; omit hostId to start on the gateway host");
|
|
1207
|
-
const resolution = resolveLocalCodexTerminalResolution();
|
|
1208
|
-
if (!resolution) throw new CatalogParamsError("Codex CLI is unavailable; install Codex or add codex to PATH, then try again");
|
|
1209
|
-
return {
|
|
1210
|
-
kind: "local",
|
|
1211
|
-
argv: [resolution.executable, ...params.initialMessage !== void 0 ? ["--", params.initialMessage] : []],
|
|
1212
|
-
cwd: params.cwd,
|
|
1213
|
-
env: { CODEX_HOME: resolveCodexCatalogTerminalHome(params) },
|
|
1214
|
-
...resolution.pathEnv ? { pathEnv: resolution.pathEnv } : {},
|
|
1215
|
-
title: "codex"
|
|
1216
|
-
};
|
|
1217
|
-
}
|
|
1218
|
-
//#endregion
|
|
1219
1238
|
//#region extensions/codex/src/session-catalog-adoption.ts
|
|
1220
1239
|
const CODEX_SUPERVISION_SESSION_KEY_PREFIX = "harness:codex:supervision:";
|
|
1221
1240
|
const boundCatalogSessionId = (value) => boundedCatalogString(value, 256);
|
|
@@ -1377,6 +1396,7 @@ async function createOrReuseAdoptedSession(params) {
|
|
|
1377
1396
|
config: params.config,
|
|
1378
1397
|
key: adoptionSessionKey(params.sourceThread.id, params.sourceHomeId),
|
|
1379
1398
|
agentId: params.agentId,
|
|
1399
|
+
displayName: params.sourceThread.name ?? void 0,
|
|
1380
1400
|
thread: params.sourceThread,
|
|
1381
1401
|
throughTurnId: pendingLastTurnId ?? null,
|
|
1382
1402
|
recoverMatchingInitialEntry: true,
|
|
@@ -1439,7 +1459,7 @@ async function createOrReuseAdoptedSession(params) {
|
|
|
1439
1459
|
}
|
|
1440
1460
|
}
|
|
1441
1461
|
async function continueLocalCodexSessionInner(params) {
|
|
1442
|
-
await
|
|
1462
|
+
await params.control.requireEligibleThread(params.threadId);
|
|
1443
1463
|
const existing = await findAdoptedSessionEntry({
|
|
1444
1464
|
...params,
|
|
1445
1465
|
runtime: params.api.runtime
|
|
@@ -1532,8 +1552,8 @@ async function archiveLocalCodexSession(params) {
|
|
|
1532
1552
|
return await runSessionActionExclusive(sessionCatalogAdoptedSourceKey(params.hostId ?? "gateway:local", params.threadId), async () => {
|
|
1533
1553
|
return await params.bindingStore.withThreadArchiveFence(async () => {
|
|
1534
1554
|
const run = async (control) => {
|
|
1535
|
-
await requireCatalogEligibleThread(control, params.threadId);
|
|
1536
1555
|
await assertNoPendingSupervisionBranch(params);
|
|
1556
|
+
await control.requireEligibleThread(params.threadId);
|
|
1537
1557
|
const thread = await control.readThread(params.threadId, false);
|
|
1538
1558
|
if (thread.id !== params.threadId) throw new Error("Codex app-server returned a different thread than requested");
|
|
1539
1559
|
requireIdleThread(thread, "archive");
|
|
@@ -1720,6 +1740,7 @@ async function readNodeCodexHistory(params) {
|
|
|
1720
1740
|
id: params.record.threadId,
|
|
1721
1741
|
createdAt: params.record.createdAt ?? 0,
|
|
1722
1742
|
modelProvider: params.record.modelProvider ?? "openai",
|
|
1743
|
+
projectId: null,
|
|
1723
1744
|
turns: page.data.toReversed()
|
|
1724
1745
|
};
|
|
1725
1746
|
return {
|
|
@@ -1783,7 +1804,7 @@ async function continueNodeCodexSessionInner(params) {
|
|
|
1783
1804
|
detachHint: "Start a new chat to leave the paired-node Codex session.",
|
|
1784
1805
|
data: createCodexCliNodeConversationBindingData({
|
|
1785
1806
|
nodeId,
|
|
1786
|
-
sessionId:
|
|
1807
|
+
sessionId: params.threadId,
|
|
1787
1808
|
agentId: adopted.agentId,
|
|
1788
1809
|
cwd: record.cwd
|
|
1789
1810
|
})
|
|
@@ -1799,10 +1820,10 @@ async function continueNodeCodexSession(params) {
|
|
|
1799
1820
|
if (params.clientScopes?.includes("operator.admin") !== true) throw new CatalogParamsError("continuing a paired-node Codex session requires operator.admin");
|
|
1800
1821
|
const nodeId = params.hostId.slice(5).trim();
|
|
1801
1822
|
if (!nodeId || params.hostId !== `node:${nodeId}`) throw new CatalogParamsError("Codex session catalog hostId is invalid");
|
|
1802
|
-
const agentId =
|
|
1823
|
+
const agentId = resolveSessionAgentIdsStrict({
|
|
1803
1824
|
config: params.config,
|
|
1804
1825
|
agentId: params.agentId
|
|
1805
|
-
}).
|
|
1826
|
+
}).sessionAgentId;
|
|
1806
1827
|
const sourceKey = sessionCatalogAdoptedSourceKey(`node:${nodeId}`, params.threadId);
|
|
1807
1828
|
const operationKey = sessionCatalogAdoptedSourceKey(agentId, sourceKey);
|
|
1808
1829
|
return await continueNodeAdoption({
|
|
@@ -1816,6 +1837,154 @@ async function continueNodeCodexSession(params) {
|
|
|
1816
1837
|
});
|
|
1817
1838
|
}
|
|
1818
1839
|
//#endregion
|
|
1840
|
+
//#region extensions/codex/src/session-catalog-terminal.ts
|
|
1841
|
+
const CODEX_TERMINAL_RESUME_COMMAND = "codex.terminal.resume.v1";
|
|
1842
|
+
function resolveCodexCatalogTerminalHome(sources) {
|
|
1843
|
+
const runtimeConfig = sources.getRuntimeConfig();
|
|
1844
|
+
if (!runtimeConfig) throw new Error("OpenClaw runtime config is unavailable");
|
|
1845
|
+
const agentDir = sources.source?.agentDir ?? (sources.agentId ? resolveAgentDir$1(runtimeConfig, sources.agentId) : resolveDefaultAgentDir(runtimeConfig));
|
|
1846
|
+
const startOptions = sources.source?.appServer.start ?? resolveCodexSupervisionAppServerRuntimeOptions({ pluginConfig: sources.getPluginConfig() }).start;
|
|
1847
|
+
return resolveCodexAppServerLocalHomeDir(startOptions, agentDir);
|
|
1848
|
+
}
|
|
1849
|
+
function resolveLocalCodexTerminalExecutable(env = process.env) {
|
|
1850
|
+
return resolveLocalCodexTerminalResolution(env)?.executable;
|
|
1851
|
+
}
|
|
1852
|
+
function resolveLocalCodexTerminalResolution(env = process.env) {
|
|
1853
|
+
return resolveNodeHostExecutable("codex", {
|
|
1854
|
+
env,
|
|
1855
|
+
pathEnv: env.PATH ?? env.Path ?? "",
|
|
1856
|
+
strategy: "fallback"
|
|
1857
|
+
});
|
|
1858
|
+
}
|
|
1859
|
+
function codexNodeTerminalCapability(node) {
|
|
1860
|
+
const commands = node.invocableCommands ?? node.commands;
|
|
1861
|
+
return node.connected === true && commands?.includes("codex.terminal.resume.v1") === true ? { canOpenTerminalCodex: true } : {};
|
|
1862
|
+
}
|
|
1863
|
+
function createCodexTerminalNodeHostCommand(bindRequest, configSources) {
|
|
1864
|
+
return {
|
|
1865
|
+
command: CODEX_TERMINAL_RESUME_COMMAND,
|
|
1866
|
+
cap: CODEX_APP_SERVER_THREADS_CAPABILITY,
|
|
1867
|
+
dangerous: false,
|
|
1868
|
+
duplex: true,
|
|
1869
|
+
isAvailable: ({ env }) => Boolean(resolveNodeHostExecutable("codex", {
|
|
1870
|
+
env,
|
|
1871
|
+
pathEnv: env.PATH ?? env.Path ?? "",
|
|
1872
|
+
strategy: "direct"
|
|
1873
|
+
})),
|
|
1874
|
+
handle: async (paramsJSON, io) => {
|
|
1875
|
+
if (!io) throw new Error("Codex terminal command requires duplex transport");
|
|
1876
|
+
const request = bindRequest(paramsJSON);
|
|
1877
|
+
const resume = decodeNodePtyResumeParams(request.paramsJSON, (value) => {
|
|
1878
|
+
if (typeof value !== "string" || !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iu.test(value)) throw new CatalogParamsError("threadId must be a UUID");
|
|
1879
|
+
return value;
|
|
1880
|
+
});
|
|
1881
|
+
const record = await request.control.requireEligibleThread(resume.threadId);
|
|
1882
|
+
const resolution = resolveNodeHostExecutable("codex", {
|
|
1883
|
+
env: process.env,
|
|
1884
|
+
pathEnv: process.env.PATH ?? process.env.Path ?? "",
|
|
1885
|
+
strategy: "direct"
|
|
1886
|
+
});
|
|
1887
|
+
if (!resolution) throw new Error("Codex CLI is unavailable");
|
|
1888
|
+
return JSON.stringify(await runNodePtyCommand({
|
|
1889
|
+
file: resolution.executable,
|
|
1890
|
+
args: ["resume", resume.threadId],
|
|
1891
|
+
...record.cwd ? { cwd: record.cwd } : {},
|
|
1892
|
+
env: { CODEX_HOME: resolveCodexCatalogTerminalHome({
|
|
1893
|
+
...configSources,
|
|
1894
|
+
agentId: request.agentId
|
|
1895
|
+
}) },
|
|
1896
|
+
cols: resume.cols,
|
|
1897
|
+
rows: resume.rows
|
|
1898
|
+
}, io));
|
|
1899
|
+
}
|
|
1900
|
+
};
|
|
1901
|
+
}
|
|
1902
|
+
async function resolveNodeCatalogEligibleThread(params) {
|
|
1903
|
+
let cursor;
|
|
1904
|
+
const seenCursors = /* @__PURE__ */ new Set();
|
|
1905
|
+
for (let pageIndex = 0; pageIndex < 100; pageIndex += 1) {
|
|
1906
|
+
const raw = await params.runtime.nodes.invoke({
|
|
1907
|
+
nodeId: params.nodeId,
|
|
1908
|
+
command: CODEX_APP_SERVER_THREADS_LIST_COMMAND,
|
|
1909
|
+
params: {
|
|
1910
|
+
agentId: params.agentId,
|
|
1911
|
+
limit: 100,
|
|
1912
|
+
...cursor ? { cursor } : {}
|
|
1913
|
+
},
|
|
1914
|
+
timeoutMs: NODE_INVOKE_TIMEOUT_MS,
|
|
1915
|
+
scopes: ["operator.write"]
|
|
1916
|
+
});
|
|
1917
|
+
const page = params.parseCatalogPage(unwrapNodeInvokePayload(raw));
|
|
1918
|
+
const record = page.sessions.find((candidate) => candidate.threadId === params.threadId);
|
|
1919
|
+
if (record) {
|
|
1920
|
+
if (isInteractiveThreadSource(record.source)) return record;
|
|
1921
|
+
break;
|
|
1922
|
+
}
|
|
1923
|
+
const nextCursor = page.nextCursor?.trim();
|
|
1924
|
+
if (!nextCursor || seenCursors.has(nextCursor)) break;
|
|
1925
|
+
seenCursors.add(nextCursor);
|
|
1926
|
+
cursor = nextCursor;
|
|
1927
|
+
}
|
|
1928
|
+
throw new CatalogParamsError("Codex session is not a non-archived interactive Codex session");
|
|
1929
|
+
}
|
|
1930
|
+
async function openCodexCatalogTerminal(params) {
|
|
1931
|
+
const title = `codex resume ${params.threadId.slice(0, 8)}…`;
|
|
1932
|
+
if (params.hostId === "gateway:local" || params.hostId.startsWith(`gateway:local:`)) {
|
|
1933
|
+
const record = await params.control.requireEligibleThread(params.threadId);
|
|
1934
|
+
const resolution = resolveLocalCodexTerminalResolution();
|
|
1935
|
+
if (!resolution) throw new CatalogParamsError("Codex CLI is unavailable");
|
|
1936
|
+
return {
|
|
1937
|
+
kind: "local",
|
|
1938
|
+
argv: [
|
|
1939
|
+
resolution.executable,
|
|
1940
|
+
"resume",
|
|
1941
|
+
params.threadId
|
|
1942
|
+
],
|
|
1943
|
+
...record.cwd ? { cwd: record.cwd } : {},
|
|
1944
|
+
env: { CODEX_HOME: resolveCodexCatalogTerminalHome(params) },
|
|
1945
|
+
...resolution.pathEnv ? { pathEnv: resolution.pathEnv } : {},
|
|
1946
|
+
title
|
|
1947
|
+
};
|
|
1948
|
+
}
|
|
1949
|
+
if (!params.hostId.startsWith("node:")) throw new CatalogParamsError("hostId is invalid");
|
|
1950
|
+
const nodeId = params.hostId.slice(5);
|
|
1951
|
+
if (!(await params.api.runtime.nodes.list()).nodes.find((candidate) => {
|
|
1952
|
+
const commands = candidate.invocableCommands ?? candidate.commands;
|
|
1953
|
+
return candidate.nodeId === nodeId && candidate.connected === true && commands?.includes("codex.appServer.threads.list.v1") === true && commands.includes("codex.terminal.resume.v1");
|
|
1954
|
+
})) throw new CatalogParamsError("paired-node Codex terminal is unavailable");
|
|
1955
|
+
const record = await resolveNodeCatalogEligibleThread({
|
|
1956
|
+
agentId: params.agentId,
|
|
1957
|
+
runtime: params.api.runtime,
|
|
1958
|
+
nodeId,
|
|
1959
|
+
threadId: params.threadId,
|
|
1960
|
+
parseCatalogPage: params.parseCatalogPage
|
|
1961
|
+
});
|
|
1962
|
+
return {
|
|
1963
|
+
kind: "node",
|
|
1964
|
+
nodeId,
|
|
1965
|
+
command: CODEX_TERMINAL_RESUME_COMMAND,
|
|
1966
|
+
paramsJSON: JSON.stringify({
|
|
1967
|
+
agentId: params.agentId,
|
|
1968
|
+
threadId: params.threadId
|
|
1969
|
+
}),
|
|
1970
|
+
...record.cwd ? { cwd: record.cwd } : {},
|
|
1971
|
+
title
|
|
1972
|
+
};
|
|
1973
|
+
}
|
|
1974
|
+
async function startCodexCatalogTerminal(params) {
|
|
1975
|
+
if (params.nodeId) throw new CatalogParamsError("Paired-node Codex terminal start is unavailable; omit hostId to start on the gateway host");
|
|
1976
|
+
const resolution = resolveLocalCodexTerminalResolution();
|
|
1977
|
+
if (!resolution) throw new CatalogParamsError("Codex CLI is unavailable; install Codex or add codex to PATH, then try again");
|
|
1978
|
+
return {
|
|
1979
|
+
kind: "local",
|
|
1980
|
+
argv: [resolution.executable, ...params.initialMessage !== void 0 ? ["--", params.initialMessage] : []],
|
|
1981
|
+
cwd: params.cwd,
|
|
1982
|
+
env: { CODEX_HOME: resolveCodexCatalogTerminalHome(params) },
|
|
1983
|
+
...resolution.pathEnv ? { pathEnv: resolution.pathEnv } : {},
|
|
1984
|
+
title: "codex"
|
|
1985
|
+
};
|
|
1986
|
+
}
|
|
1987
|
+
//#endregion
|
|
1819
1988
|
//#region extensions/codex/src/session-catalog-listing.ts
|
|
1820
1989
|
async function listVisiblePage(params) {
|
|
1821
1990
|
const excluded = params.excludedThreadIds;
|
|
@@ -1903,7 +2072,7 @@ async function listGatewayHost(params) {
|
|
|
1903
2072
|
}
|
|
1904
2073
|
/** Lists Gateway-local and paired-node Codex sessions with per-host failures. */
|
|
1905
2074
|
async function listCodexSessionCatalog(params) {
|
|
1906
|
-
const agentId =
|
|
2075
|
+
const agentId = resolveSessionAgentIdsStrict({
|
|
1907
2076
|
config: params.config ?? {},
|
|
1908
2077
|
agentId: params.agentId
|
|
1909
2078
|
}).sessionAgentId;
|
|
@@ -1977,7 +2146,7 @@ function createCodexSessionCatalogNodeHostCommands(controlFactory, configSources
|
|
|
1977
2146
|
if (!isRecord(parsed)) throw new CatalogParamsError("Codex session catalog parameters must be an object");
|
|
1978
2147
|
const requestedAgentId = readBoundedOptionalString(parsed, "agentId", 256);
|
|
1979
2148
|
const config = configSources.getRuntimeConfig() ?? {};
|
|
1980
|
-
const agentId =
|
|
2149
|
+
const agentId = resolveSessionAgentIdsStrict({
|
|
1981
2150
|
config,
|
|
1982
2151
|
agentId: requestedAgentId
|
|
1983
2152
|
}).sessionAgentId;
|
|
@@ -2034,7 +2203,7 @@ function createCodexSessionCatalogNodeHostCommands(controlFactory, configSources
|
|
|
2034
2203
|
const request = bindRequest(paramsJSON);
|
|
2035
2204
|
const action = readNodeTranscriptParams(request.params);
|
|
2036
2205
|
try {
|
|
2037
|
-
await
|
|
2206
|
+
await request.control.requireEligibleThread(action.threadId);
|
|
2038
2207
|
const page = parseTranscriptPage(await request.control.listTurnPage({
|
|
2039
2208
|
threadId: action.threadId,
|
|
2040
2209
|
limit: action.limit,
|
|
@@ -2079,7 +2248,7 @@ function flattenTranscriptPageDesc(page) {
|
|
|
2079
2248
|
/** Reads the persisted transcript for a Gateway-local or paired-node Codex session. */
|
|
2080
2249
|
async function readCodexSessionTranscript(params) {
|
|
2081
2250
|
if (params.source || params.hostId === "gateway:local") {
|
|
2082
|
-
await
|
|
2251
|
+
await params.control.requireEligibleThread(params.threadId);
|
|
2083
2252
|
const listParams = {
|
|
2084
2253
|
threadId: params.threadId,
|
|
2085
2254
|
limit: params.limit,
|
|
@@ -2145,7 +2314,7 @@ function toGenericTranscriptItem(item) {
|
|
|
2145
2314
|
const fallback = item.title ?? item.name ?? item.tool ?? item.command ?? item.query ?? void 0;
|
|
2146
2315
|
const resultText = item.aggregatedOutput || (item.result === void 0 ? void 0 : JSON.stringify(item.result, null, 2));
|
|
2147
2316
|
const changesText = Array.isArray(item.changes) ? item.changes.map((change) => `${change.kind}: ${change.path}`).join("\n") || void 0 : void 0;
|
|
2148
|
-
const text = item.text || resultText || changesText || fallback;
|
|
2317
|
+
const text = item.type === "userMessage" ? projectCodexUserItemText(item) : item.text || resultText || changesText || fallback;
|
|
2149
2318
|
return {
|
|
2150
2319
|
id: item.id,
|
|
2151
2320
|
type,
|
|
@@ -2310,7 +2479,7 @@ function existingCatalogHomeCandidates(value, label) {
|
|
|
2310
2479
|
/** Resolves every local Codex store the operator already owns, without path disclosure. */
|
|
2311
2480
|
function resolveCodexCatalogHomes(params) {
|
|
2312
2481
|
const { config, env, ownerAgentId, pluginConfig } = params;
|
|
2313
|
-
const ownerAgentDir = resolveAgentDir(config, ownerAgentId, env);
|
|
2482
|
+
const ownerAgentDir = resolveAgentDir$1(config, ownerAgentId, env);
|
|
2314
2483
|
const configuredHomes = readCodexPluginConfig(pluginConfig).sessionCatalog?.homes ?? [];
|
|
2315
2484
|
const base = resolveCodexSupervisionAppServerRuntimeOptions({
|
|
2316
2485
|
pluginConfig,
|
|
@@ -2333,7 +2502,7 @@ function resolveCodexCatalogHomes(params) {
|
|
|
2333
2502
|
usesProcessHomeFallback: !processHomeConfigured
|
|
2334
2503
|
});
|
|
2335
2504
|
const agentIds = listAgentIds(config).toSorted((left, right) => left === ownerAgentId ? -1 : right === ownerAgentId ? 1 : left.localeCompare(right));
|
|
2336
|
-
candidates.push(...agentIds.flatMap((agentId) => existingCatalogHomeCandidates(resolveCodexAppServerHomeDir(resolveAgentDir(config, agentId, env)), agentId)), ...configuredHomes.flatMap((entry) => {
|
|
2505
|
+
candidates.push(...agentIds.flatMap((agentId) => existingCatalogHomeCandidates(resolveCodexAppServerHomeDir(resolveAgentDir$1(config, agentId, env)), agentId)), ...configuredHomes.flatMap((entry) => {
|
|
2337
2506
|
const { path: home, label } = typeof entry === "string" ? { path: entry } : entry;
|
|
2338
2507
|
return existingCatalogHomeCandidates(home, label);
|
|
2339
2508
|
}));
|
|
@@ -2399,96 +2568,6 @@ function createCodexCatalogHomeResolver(params) {
|
|
|
2399
2568
|
} };
|
|
2400
2569
|
}
|
|
2401
2570
|
//#endregion
|
|
2402
|
-
//#region extensions/codex/src/session-catalog-provenance.ts
|
|
2403
|
-
const MAX_SESSION_META_BYTES = 1024 * 1024;
|
|
2404
|
-
const SESSION_META_READ_CHUNK_BYTES = 64 * 1024;
|
|
2405
|
-
const MAX_PROVENANCE_CACHE_ENTRIES = 2e4;
|
|
2406
|
-
const provenanceByPath = /* @__PURE__ */ new Map();
|
|
2407
|
-
function cacheProvenance(key, value) {
|
|
2408
|
-
provenanceByPath.delete(key);
|
|
2409
|
-
provenanceByPath.set(key, value);
|
|
2410
|
-
while (provenanceByPath.size > MAX_PROVENANCE_CACHE_ENTRIES) {
|
|
2411
|
-
const oldest = provenanceByPath.keys().next().value;
|
|
2412
|
-
if (oldest === void 0) break;
|
|
2413
|
-
provenanceByPath.delete(oldest);
|
|
2414
|
-
}
|
|
2415
|
-
}
|
|
2416
|
-
/** Undefined means the metadata line is not durable enough to cache yet. */
|
|
2417
|
-
async function readOpenClawOriginator(sessionsRoot, rolloutPath, threadId) {
|
|
2418
|
-
let safeRoot;
|
|
2419
|
-
try {
|
|
2420
|
-
safeRoot = await root(sessionsRoot, {
|
|
2421
|
-
hardlinks: "reject",
|
|
2422
|
-
maxBytes: Number.MAX_SAFE_INTEGER,
|
|
2423
|
-
symlinks: "reject"
|
|
2424
|
-
});
|
|
2425
|
-
} catch {
|
|
2426
|
-
return;
|
|
2427
|
-
}
|
|
2428
|
-
const candidates = rolloutPath.endsWith(".zst") ? [rolloutPath, rolloutPath.slice(0, -4)] : [rolloutPath, `${rolloutPath}.zst`];
|
|
2429
|
-
for (const candidate of candidates) {
|
|
2430
|
-
let opened;
|
|
2431
|
-
try {
|
|
2432
|
-
opened = await safeRoot.open(path.relative(sessionsRoot, candidate));
|
|
2433
|
-
} catch {
|
|
2434
|
-
continue;
|
|
2435
|
-
}
|
|
2436
|
-
const input = opened.handle.createReadStream({
|
|
2437
|
-
autoClose: false,
|
|
2438
|
-
highWaterMark: SESSION_META_READ_CHUNK_BYTES
|
|
2439
|
-
});
|
|
2440
|
-
const reader = candidate.endsWith(".zst") ? input.pipe(createZstdDecompress()) : input;
|
|
2441
|
-
try {
|
|
2442
|
-
const chunks = [];
|
|
2443
|
-
let bytesReadTotal = 0;
|
|
2444
|
-
let line;
|
|
2445
|
-
for await (const value of reader) {
|
|
2446
|
-
const chunk = Buffer.isBuffer(value) ? value : Buffer.from(value);
|
|
2447
|
-
const remaining = MAX_SESSION_META_BYTES - bytesReadTotal;
|
|
2448
|
-
if (remaining <= 0) break;
|
|
2449
|
-
const bounded = chunk.subarray(0, remaining);
|
|
2450
|
-
bytesReadTotal += bounded.length;
|
|
2451
|
-
const newline = bounded.indexOf(10);
|
|
2452
|
-
chunks.push(newline >= 0 ? bounded.subarray(0, newline) : bounded);
|
|
2453
|
-
if (newline >= 0) {
|
|
2454
|
-
line = Buffer.concat(chunks).toString("utf8");
|
|
2455
|
-
break;
|
|
2456
|
-
}
|
|
2457
|
-
}
|
|
2458
|
-
if (!line) continue;
|
|
2459
|
-
let parsed;
|
|
2460
|
-
try {
|
|
2461
|
-
parsed = JSON.parse(line);
|
|
2462
|
-
} catch {
|
|
2463
|
-
continue;
|
|
2464
|
-
}
|
|
2465
|
-
if (!isRecord(parsed) || parsed.type !== "session_meta" || !isRecord(parsed.payload)) return false;
|
|
2466
|
-
const payload = parsed.payload;
|
|
2467
|
-
return (payload.id ?? payload.session_id) === threadId && payload.originator === "openclaw";
|
|
2468
|
-
} catch {
|
|
2469
|
-
continue;
|
|
2470
|
-
} finally {
|
|
2471
|
-
reader.destroy();
|
|
2472
|
-
input.destroy();
|
|
2473
|
-
await opened.handle.close().catch(() => void 0);
|
|
2474
|
-
}
|
|
2475
|
-
}
|
|
2476
|
-
}
|
|
2477
|
-
/**
|
|
2478
|
-
* Codex 0.147 reports OpenClaw app-server rollouts as `vscode`, so the rollout's
|
|
2479
|
-
* immutable session metadata is the authoritative historical provenance.
|
|
2480
|
-
*/
|
|
2481
|
-
async function isOpenClawManagedCodexThread(thread, localSessionsRoot) {
|
|
2482
|
-
const rolloutPath = typeof thread.path === "string" ? thread.path.trim() : "";
|
|
2483
|
-
if (!localSessionsRoot || !rolloutPath) return false;
|
|
2484
|
-
const cacheKey = `${localSessionsRoot}\0${rolloutPath}`;
|
|
2485
|
-
const cached = provenanceByPath.get(cacheKey);
|
|
2486
|
-
if (cached !== void 0) return cached;
|
|
2487
|
-
const managed = await readOpenClawOriginator(localSessionsRoot, rolloutPath, thread.id);
|
|
2488
|
-
if (managed !== void 0) cacheProvenance(cacheKey, managed);
|
|
2489
|
-
return managed ?? false;
|
|
2490
|
-
}
|
|
2491
|
-
//#endregion
|
|
2492
2571
|
//#region extensions/codex/src/session-catalog-control.ts
|
|
2493
2572
|
const CODEX_SESSION_CATALOG_LIST_TTL_MS = 32e3;
|
|
2494
2573
|
const CODEX_SESSION_CATALOG_LIST_CACHE_MAX_ENTRIES = 32;
|
|
@@ -2508,10 +2587,10 @@ function createCodexCatalogRequestSnapshot(requestTimeoutMs, request) {
|
|
|
2508
2587
|
listThreads: (params, timeoutMs) => request(CODEX_CONTROL_METHODS.listThreads, params, timeoutMs),
|
|
2509
2588
|
listThreadTurns: (params) => request(CODEX_CONTROL_METHODS.listThreadTurns, params),
|
|
2510
2589
|
forkThread: (params) => request(CODEX_CONTROL_METHODS.forkThread, assertCodexThreadForkParams(params)),
|
|
2511
|
-
readThread: async (threadId, includeTurns) => (await request(CODEX_CONTROL_METHODS.readThread, {
|
|
2590
|
+
readThread: async (threadId, includeTurns, timeoutMs) => (await request(CODEX_CONTROL_METHODS.readThread, {
|
|
2512
2591
|
threadId,
|
|
2513
2592
|
includeTurns
|
|
2514
|
-
})).thread,
|
|
2593
|
+
}, timeoutMs)).thread,
|
|
2515
2594
|
archiveThread: async (threadId) => {
|
|
2516
2595
|
await request(CODEX_CONTROL_METHODS.archiveThread, { threadId });
|
|
2517
2596
|
}
|
|
@@ -2522,6 +2601,58 @@ function createCodexSessionCatalogControlFromRequests(params) {
|
|
|
2522
2601
|
...params.clientId ? { clientId: params.clientId } : {},
|
|
2523
2602
|
...params.connectionFingerprint ? { connectionFingerprint: params.connectionFingerprint } : {},
|
|
2524
2603
|
withPinnedConnection: params.withPinnedConnection,
|
|
2604
|
+
async requireEligibleThread(threadId) {
|
|
2605
|
+
const requests = params.createRequestSnapshot();
|
|
2606
|
+
const deadline = params.now() + requests.requestTimeoutMs;
|
|
2607
|
+
const unverified = () => new CatalogParamsError("Codex session eligibility could not be verified. Refresh the catalog and verify the session in its native Codex home before retrying.");
|
|
2608
|
+
const remaining = () => {
|
|
2609
|
+
const timeoutMs = Math.ceil(deadline - params.now());
|
|
2610
|
+
if (timeoutMs <= 0) throw unverified();
|
|
2611
|
+
return timeoutMs;
|
|
2612
|
+
};
|
|
2613
|
+
const verify = async () => {
|
|
2614
|
+
if (params.sourceHomeId && await params.managedThreads?.has(params.sourceHomeId, threadId)) throw unverified();
|
|
2615
|
+
const root = params.localSessionsRoot;
|
|
2616
|
+
const thread = root ? await requests.readThread(threadId, false, remaining()) : void 0;
|
|
2617
|
+
if (root && (!thread || thread.id !== threadId || !isInteractiveThreadSource(thread.source))) throw unverified();
|
|
2618
|
+
let cursor;
|
|
2619
|
+
const seenCursors = /* @__PURE__ */ new Set();
|
|
2620
|
+
for (let pageIndex = 0; pageIndex < 100; pageIndex += 1) {
|
|
2621
|
+
const page = await requests.listThreads({
|
|
2622
|
+
archived: false,
|
|
2623
|
+
limit: 100,
|
|
2624
|
+
modelProviders: [],
|
|
2625
|
+
sortKey: root ? "recency_at" : "updated_at",
|
|
2626
|
+
sortDirection: "desc",
|
|
2627
|
+
...root ? {
|
|
2628
|
+
useStateDbOnly: true,
|
|
2629
|
+
...thread?.cwd ? { cwd: thread.cwd } : {}
|
|
2630
|
+
} : {},
|
|
2631
|
+
...cursor ? { cursor } : {}
|
|
2632
|
+
}, remaining());
|
|
2633
|
+
remaining();
|
|
2634
|
+
const candidate = page.data.find((value) => value.id === threadId);
|
|
2635
|
+
if (candidate) {
|
|
2636
|
+
if (!isInteractiveThreadSource(candidate.source)) throw unverified();
|
|
2637
|
+
if (root && thread) {
|
|
2638
|
+
const rolloutPath = thread.path;
|
|
2639
|
+
if (!rolloutPath || !candidate.path || rolloutPath.replace(/\.zst$/u, "") !== candidate.path.replace(/\.zst$/u, "")) throw unverified();
|
|
2640
|
+
const metadata = await readCodexSessionMeta(root, rolloutPath, threadId);
|
|
2641
|
+
remaining();
|
|
2642
|
+
if (!metadata || !isInteractiveThreadSource(metadata.source) || metadata.originator === "openclaw") throw unverified();
|
|
2643
|
+
return thread;
|
|
2644
|
+
}
|
|
2645
|
+
return candidate;
|
|
2646
|
+
}
|
|
2647
|
+
const nextCursor = readControlCursor(page.nextCursor, "next response");
|
|
2648
|
+
if (!nextCursor || seenCursors.has(nextCursor)) throw unverified();
|
|
2649
|
+
seenCursors.add(nextCursor);
|
|
2650
|
+
cursor = nextCursor;
|
|
2651
|
+
}
|
|
2652
|
+
throw unverified();
|
|
2653
|
+
};
|
|
2654
|
+
return await withTimeout(verify(), requests.requestTimeoutMs, "Codex session eligibility could not be verified", unverified);
|
|
2655
|
+
},
|
|
2525
2656
|
async listPage(pageParams) {
|
|
2526
2657
|
const limit = normalizeLimit(pageParams.limit, "limit");
|
|
2527
2658
|
const search = pageParams.searchTerm?.trim().toLocaleLowerCase() || void 0;
|
|
@@ -2558,7 +2689,7 @@ function createCodexSessionCatalogControlFromRequests(params) {
|
|
|
2558
2689
|
continue;
|
|
2559
2690
|
}
|
|
2560
2691
|
const session = toCatalogSession(thread, false);
|
|
2561
|
-
if (session && (!search || session.name?.toLocaleLowerCase().includes(search))) sessions.push(session);
|
|
2692
|
+
if (session && (!search || (session.name ?? session.fallbackName)?.toLocaleLowerCase().includes(search))) sessions.push(session);
|
|
2562
2693
|
}
|
|
2563
2694
|
nextCursor = readControlCursor(response.nextCursor, "next response");
|
|
2564
2695
|
if (!nextCursor || sessions.length >= limit) break;
|
|
@@ -2605,7 +2736,7 @@ function createCodexSessionCatalogControl(params) {
|
|
|
2605
2736
|
const catalogPagesByConfig = /* @__PURE__ */ new WeakMap();
|
|
2606
2737
|
const resolveRequestOptions = (startOptions, agentId, source) => {
|
|
2607
2738
|
const runtimeConfig = params.getRuntimeConfig();
|
|
2608
|
-
const agentDir = source?.agentDir ?? resolveAgentDir(runtimeConfig ?? {}, agentId);
|
|
2739
|
+
const agentDir = source?.agentDir ?? resolveAgentDir$1(runtimeConfig ?? {}, agentId);
|
|
2609
2740
|
const resolvedStartOptions = source?.appServer.start ?? startOptions;
|
|
2610
2741
|
if (!runtimeConfig) return {
|
|
2611
2742
|
agentDir,
|
|
@@ -2661,6 +2792,8 @@ function createCodexSessionCatalogControl(params) {
|
|
|
2661
2792
|
connectionFingerprint: buildCodexAppServerConnectionFingerprint(runtime, agentDir),
|
|
2662
2793
|
createRequestSnapshot: () => requests,
|
|
2663
2794
|
...source?.localSessionsRoot ? { localSessionsRoot: source.localSessionsRoot } : {},
|
|
2795
|
+
sourceHomeId: source?.sourceHomeId,
|
|
2796
|
+
managedThreads: params.managedThreads,
|
|
2664
2797
|
now,
|
|
2665
2798
|
withPinnedConnection: async (nestedRun) => await nestedRun(pinnedControl)
|
|
2666
2799
|
});
|
|
@@ -2677,6 +2810,7 @@ function createCodexSessionCatalogControl(params) {
|
|
|
2677
2810
|
});
|
|
2678
2811
|
return {
|
|
2679
2812
|
...control,
|
|
2813
|
+
requireEligibleThread: (threadId) => withPinnedConnection((pinned) => pinned.requireEligibleThread(threadId)),
|
|
2680
2814
|
async listPage(pageParams) {
|
|
2681
2815
|
const runtimeConfig = params.getRuntimeConfig();
|
|
2682
2816
|
if (!runtimeConfig) return await control.listPage(pageParams);
|
|
@@ -2687,7 +2821,7 @@ function createCodexSessionCatalogControl(params) {
|
|
|
2687
2821
|
}
|
|
2688
2822
|
const key = codexCatalogPageCacheKey(pageParams, agentId, source);
|
|
2689
2823
|
const cached = cache.get(key);
|
|
2690
|
-
if (
|
|
2824
|
+
if (cached) {
|
|
2691
2825
|
cache.delete(key);
|
|
2692
2826
|
cache.set(key, cached);
|
|
2693
2827
|
if (cached.expiresAt > now()) return cached.value ?? await cached.page;
|
|
@@ -2718,7 +2852,7 @@ function createCodexSessionCatalogControl(params) {
|
|
|
2718
2852
|
});
|
|
2719
2853
|
else cache.delete(key);
|
|
2720
2854
|
};
|
|
2721
|
-
if (
|
|
2855
|
+
if (staleValue) {
|
|
2722
2856
|
page.then(settle, restore);
|
|
2723
2857
|
return staleValue;
|
|
2724
2858
|
}
|
|
@@ -2812,7 +2946,7 @@ function registerCodexSessionCatalog(params) {
|
|
|
2812
2946
|
const homes = params.control.homesForAgent(agentId);
|
|
2813
2947
|
return allowProcessHomeFallback === false ? homes.filter((home) => !home.usesProcessHomeFallback) : homes;
|
|
2814
2948
|
};
|
|
2815
|
-
const resolveRequestAgentId = (agentId) =>
|
|
2949
|
+
const resolveRequestAgentId = (agentId) => resolveSessionAgentIdsStrict({
|
|
2816
2950
|
config: params.getRuntimeConfig() ?? params.api.config,
|
|
2817
2951
|
agentId
|
|
2818
2952
|
}).sessionAgentId;
|
|
@@ -2893,7 +3027,7 @@ function registerCodexSessionCatalog(params) {
|
|
|
2893
3027
|
if (!isLocalCodexCatalogHost(request.hostId)) throw new CatalogParamsError("Codex session catalog hostId is invalid");
|
|
2894
3028
|
const { agentId, source, control } = bindLocalRequest(request);
|
|
2895
3029
|
let upstreamBaseline;
|
|
2896
|
-
|
|
3030
|
+
const continued = await continueLocalCodexSession({
|
|
2897
3031
|
agentId,
|
|
2898
3032
|
api: params.api,
|
|
2899
3033
|
bindingStore: params.bindingStore,
|
|
@@ -2906,7 +3040,8 @@ function registerCodexSessionCatalog(params) {
|
|
|
2906
3040
|
onContinued: (baseline) => {
|
|
2907
3041
|
upstreamBaseline = baseline;
|
|
2908
3042
|
}
|
|
2909
|
-
})
|
|
3043
|
+
});
|
|
3044
|
+
return codexUpstreamContinueResult(continued.sessionKey, request.threadId, upstreamBaseline);
|
|
2910
3045
|
},
|
|
2911
3046
|
checkUpstreamActivity: (probes, policy) => checkUpstreamActivity(probes.filter((probe) => !isLocalCodexCatalogHost(probe.hostId) || policy?.allowProcessHomeFallback !== false || catalogHomes(probe.agentId, false).some((home) => home.hostId === probe.hostId))),
|
|
2912
3047
|
archive: async (request) => {
|
|
@@ -2960,4 +3095,4 @@ const codexSessionCatalogRuntime = {
|
|
|
2960
3095
|
archiveLocal: archiveLocalCodexSession
|
|
2961
3096
|
};
|
|
2962
3097
|
//#endregion
|
|
2963
|
-
export { CODEX_LOCAL_SESSION_HOST_ID as a,
|
|
3098
|
+
export { CODEX_LOCAL_SESSION_HOST_ID as a, readCodexStatusProbes as c, createCodexCliSessionNodeHostCommands as d, createCodexCliSessionNodeInvokePolicies as f, resumeCodexCliSessionOnNode as g, resolveCodexCliSessionForBindingOnNode as h, createCodexSessionCatalogNodeHostCommands as i, requestOptions as l, listCodexCliSessionsOnNode as m, createCodexSessionCatalogNodeInvokePolicies as n, assertCodexArchiveDescendantsUnowned as o, formatCodexCliSessions as p, createCodexSessionCatalogControl as r, codexControlRequest as s, codexSessionCatalogRuntime as t, safeCodexControlRequest as u };
|