@openclaw/codex 2026.9.5 → 2026.9.7
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/README.md +2 -0
- package/assets/icon.png +0 -0
- package/dist/.setup/{account-usage-runtime-C2MOIvfq.mjs → account-usage-runtime-DFhbh1zz.mjs} +6 -6
- package/dist/.setup/{apply-CJ0ZfmBG.mjs → apply-D3GcSoSa.mjs} +35 -55
- package/dist/.setup/{attempt-client-cleanup-BpYKdTA0.mjs → attempt-client-cleanup-DOP-cW5j.mjs} +179 -73
- package/dist/.setup/attempt-workspace-context-C5HigshI.mjs +164 -0
- package/dist/.setup/{auth-binding-DhLWa_7K.mjs → auth-binding-BLWz7stm.mjs} +14 -1
- package/dist/.setup/{auth-cache-key-QirmgiCo.mjs → auth-cache-key-Dbvq-QgB.mjs} +41 -111
- package/dist/.setup/{auth-profile-WqZtZfXN.mjs → auth-profile-B0okYl2D.mjs} +1 -2
- package/dist/.setup/auth-profile-health-oHizqgye.mjs +53 -0
- package/dist/.setup/auth-profile-recovery-BREezV0L.mjs +14 -0
- package/dist/.setup/auth-start-options-BPIPeEX8.mjs +44 -0
- package/dist/.setup/{binding-connection-Bm38niE8.mjs → binding-connection-DTtN1KrX.mjs} +2 -2
- package/dist/.setup/{binding-connection.runtime-CnRMC0ta.mjs → binding-connection.runtime-6TpgD1M6.mjs} +5 -5
- package/dist/.setup/{bounded-turn-BtlZcivC.mjs → bounded-turn-CbjoN2OW.mjs} +140 -37
- package/dist/.setup/bounded-turn-isolation-B8K_ylqk.mjs +14 -0
- package/dist/.setup/{build-state-Xx9ybZqa.mjs → build-state-Da1_z0kd.mjs} +1 -1
- package/dist/.setup/{capabilities-_vXcZGSx.mjs → capabilities-B3WEZl4e.mjs} +2 -10
- package/dist/.setup/{client-vXs2929Q.mjs → client-N0JpgSzF.mjs} +635 -872
- package/dist/.setup/client-catalog-response-5HHLdcde.mjs +285 -0
- package/dist/.setup/{command-dispatch-naHIZwwF.mjs → command-dispatch-BeAoaovI.mjs} +9 -8
- package/dist/.setup/{command-formatters-CGEkdawF.mjs → command-formatters-R3ckE3Co.mjs} +36 -64
- package/dist/.setup/{command-handlers-BtAJEW1X.mjs → command-handlers-ylTMS00z.mjs} +301 -488
- package/dist/.setup/{command-rpc-DHFpn4le.mjs → command-rpc-CGJGUQ6Y.mjs} +40 -28
- package/dist/.setup/compact-C2WamavS.mjs +776 -0
- package/dist/.setup/{config-CedDWjM-.mjs → config-DKhXquav.mjs} +26 -28
- package/dist/.setup/{config-options-BsanJ8QG.mjs → config-options-CzyWLTJt.mjs} +68 -65
- package/dist/.setup/{config-parsing-CcB9iPoq.mjs → config-parsing-b088LyhT.mjs} +57 -60
- package/dist/.setup/{config-runtime-CeAhl_h4.mjs → config-runtime-C0NbLms1.mjs} +2 -2
- package/dist/.setup/{config-security-BRQ2mgW9.mjs → config-security-CE-FcGw9.mjs} +51 -215
- package/dist/.setup/{config-utils-DujwEnhg.mjs → config-utils-D0CXecki.mjs} +3 -13
- package/dist/.setup/context-engine-projection-PezSESth.mjs +387 -0
- package/dist/.setup/{conversation-binding-DhzrpTM6.mjs → conversation-binding-3Min8qvP.mjs} +71 -105
- package/dist/.setup/{conversation-binding-data-CrcyZk6O.mjs → conversation-binding-data-C746z5Pn.mjs} +8 -12
- package/dist/.setup/{conversation-control-DN53ns41.mjs → conversation-control-CEP8X5JC.mjs} +30 -69
- package/dist/.setup/{cyber-failover-DYwbmf1o.mjs → cyber-failover-XV0nNRZu.mjs} +1 -1
- package/dist/.setup/{cyber-failover-notice-e9G3J9-e.mjs → cyber-failover-notice-RNpGpTyP.mjs} +1 -1
- package/dist/.setup/{dynamic-tools-D16lOp67.mjs → dynamic-tools-DzlsLUuS.mjs} +3136 -3167
- package/dist/.setup/{effective-mcp-catalog-K6kLCN8X.mjs → effective-mcp-catalog-CxUtC-xG.mjs} +8 -17
- package/dist/.setup/{ephemeral-turn-R1gA8Sn6.mjs → ephemeral-turn-CDsPJOa2.mjs} +9 -6
- package/dist/.setup/event-projector-assistant-message-CigreO4K.mjs +69 -0
- package/dist/.setup/{event-projector-usage-C7Ntzs-f.mjs → event-projector-usage-03R0I2dM.mjs} +4 -26
- package/dist/.setup/event-projector-values-DJSz8BTk.mjs +106 -0
- package/dist/.setup/incognito-session-DWYapfwf.mjs +2 -0
- package/dist/.setup/{inference-context-fulhZuz8.mjs → inference-context-D-9gWlTR.mjs} +16 -18
- package/dist/.setup/inference-dispatch-CMZtjQyz.mjs +359 -0
- package/dist/.setup/inference-metadata-CgIf7sOx.mjs +81 -0
- package/dist/.setup/inference-proxy-DhcXOgUE.mjs +561 -0
- package/dist/.setup/{isolated-completion-B6srt48J.mjs → isolated-completion-Dm3PzxJk.mjs} +15 -11
- package/dist/.setup/launch-args-DbFCehO7.mjs +196 -0
- package/dist/.setup/{managed-binary-DP6Rib3P.mjs → managed-binary-kiWRhNRE.mjs} +16 -9
- package/dist/.setup/{model-catalog-DkvUuBey.mjs → model-catalog-PAuZgJC6.mjs} +14 -14
- package/dist/.setup/model-runtime-BdqzOMkU.mjs +11 -0
- package/dist/.setup/{models-BDFgm_G-.mjs → models-DHXZtVVk.mjs} +9 -18
- package/dist/.setup/{native-auth-BLZGqFjw.mjs → native-auth-CuG53tu4.mjs} +5 -5
- package/dist/.setup/{native-execution-policy-YBMHSzC4.mjs → native-execution-policy-BxZJy5mP.mjs} +6 -31
- package/dist/.setup/{native-subagent-monitor-B1hxzIOy.mjs → native-subagent-monitor-Dpsmf2wz.mjs} +4422 -3808
- package/dist/.setup/native-subagent-pending-assignments-DwkCzLvD.mjs +203 -0
- package/dist/.setup/native-task-assignments-DMQ0g3hu.mjs +194 -0
- package/dist/.setup/{node-cli-sessions-Cl8b2ZF3.mjs → node-cli-sessions-HC4W6FLI.mjs} +99 -111
- package/dist/.setup/node-exec-server.runtime-BgBfWQqo.mjs +244 -0
- package/dist/.setup/{plan-xD7WKYTM.mjs → plan-Y-QIvrKB.mjs} +118 -163
- package/dist/.setup/{plugin-activation-r8nq5Jzp.mjs → plugin-activation-cNHRfaxU.mjs} +10 -47
- package/dist/.setup/{plugin-app-cache-key-BOxKP7db.mjs → plugin-app-cache-key-BL9B5H0L.mjs} +9 -42
- package/dist/.setup/{plugin-inventory-DUle8DLz.mjs → plugin-inventory-Cky2XJUw.mjs} +32 -23
- package/dist/.setup/{plugin-marketplace-discovery-P-Vndfqq.mjs → plugin-marketplace-discovery-D_dV9FXa.mjs} +22 -25
- package/dist/.setup/{plugin-metadata-cache-DsS5buNa.mjs → plugin-metadata-cache-DsjsL1dr.mjs} +328 -318
- package/dist/.setup/protocol-CANUwXJ3.mjs +17 -0
- package/dist/.setup/provider-DH8NSzGt.mjs +51 -0
- package/dist/.setup/{provider-capabilities-B8J4Dy-O.mjs → provider-capabilities-CAxoF-X1.mjs} +35 -12
- package/dist/.setup/{rate-limits-DOEGYRNs.mjs → rate-limits-B7-X2TgG.mjs} +123 -166
- package/dist/.setup/{request-BioXJLYa.mjs → request-BHZ1nz8d.mjs} +25 -16
- package/dist/.setup/responses-oauth-twnuTaAa.mjs +93 -0
- package/dist/.setup/rpc-error-BlD2vuzn.mjs +31 -0
- package/dist/.setup/{run-attempt-rlA07pUv.mjs → run-attempt-D8RZUOzY.mjs} +2046 -1454
- package/dist/.setup/{run-attempt-lifecycle-B7JbY4-F.mjs → run-attempt-lifecycle-C-6O3Exn.mjs} +10 -24
- package/dist/.setup/{runtime-artifact-Dy38Z5iU.mjs → runtime-artifact-DDQ-HGXf.mjs} +43 -47
- package/dist/.setup/runtime-artifact-connection-D68qQn1m.mjs +78 -0
- package/dist/.setup/sandbox-guard-DjCz2eOw.mjs +126 -0
- package/dist/.setup/scope-DOC1Xjc8.mjs +6 -0
- package/dist/.setup/session-binding-DGCYAfvD.mjs +443 -0
- package/dist/.setup/{session-binding-record-TH3xA0zj.mjs → session-binding-record-Oe9L-CNY.mjs} +73 -132
- package/dist/.setup/{session-binding-sidecars-CKYEcfNn.mjs → session-binding-sidecars-jo6H8dFr.mjs} +242 -60
- package/dist/.setup/{session-catalog-fUdWDx-U.mjs → session-catalog-4sCdv5qx.mjs} +598 -452
- package/dist/.setup/{session-catalog-adoption-CR_whkEW.mjs → session-catalog-adoption-BU_pHWG7.mjs} +59 -26
- package/dist/.setup/{session-catalog-archive-CwZaPacf.mjs → session-catalog-archive-spHfihri.mjs} +7 -7
- package/dist/.setup/session-catalog-events-DePDzzjc.mjs +139 -0
- package/dist/.setup/session-catalog-home-id-vlih0B_g.mjs +22 -0
- package/dist/.setup/{session-catalog-index-B141u15s.mjs → session-catalog-index-CZvDzC6z.mjs} +286 -182
- package/dist/.setup/{session-catalog-index-order-Cc5BzlQr.mjs → session-catalog-index-order-BcQpHks3.mjs} +2 -2
- package/dist/.setup/{session-catalog-index-state-BAuDztHN.mjs → session-catalog-index-state-TeO7EyO-.mjs} +6 -2
- package/dist/.setup/session-catalog-limits-DDxOsQeC.mjs +14 -0
- package/dist/.setup/session-catalog-list-request-CvtxrYSe.mjs +170 -0
- package/dist/.setup/session-catalog-native-projection-DjhwGL6x.mjs +178 -0
- package/dist/.setup/{session-catalog-node-adoption-BVRsYOSh.mjs → session-catalog-node-adoption-DgXvSGu0.mjs} +30 -35
- package/dist/.setup/{session-catalog-node-continue-Dowv8osw.mjs → session-catalog-node-continue-DjKXHBbi.mjs} +25 -18
- package/dist/.setup/session-catalog-node-lookup-CtAXI5W5.mjs +56 -0
- package/dist/.setup/{session-catalog-native-projection-ChV3cCtm.mjs → session-catalog-parsing-CPGaPYr-.mjs} +14 -180
- package/dist/.setup/{session-catalog-projection-C1Bj9Jl-.mjs → session-catalog-projection-Cr5qP5Dj.mjs} +15 -5
- package/dist/.setup/session-catalog-provenance-DoAvktcj.mjs +95 -0
- package/dist/.setup/{session-cli-DIj-IE-E.mjs → session-cli-Cn_nCqfq.mjs} +11 -24
- package/dist/.setup/{session-history-C--SrLI8.mjs → session-history-D83lJWHG.mjs} +16 -23
- package/dist/.setup/{session-history-import-JHXT5Xfi.mjs → session-history-import-WhX-X33a.mjs} +7 -10
- package/dist/.setup/session-history-read-Ov3StuL4.mjs +133 -0
- package/dist/.setup/{session-history.worker-CpNj7H_P.mjs → session-history.worker-MnPKncqP.mjs} +14 -23
- package/dist/.setup/session-initialization-6aveB9qb.mjs +22 -0
- package/dist/.setup/{session-permission-policy-DhurXY0l.mjs → session-permission-policy-Ci_fVX6y.mjs} +4 -8
- package/dist/.setup/{session-retirement-CU87AOg9.mjs → session-retirement-qMTxkNx2.mjs} +31 -12
- package/dist/.setup/{settled-turn-context-fmwouT5I.mjs → settled-turn-context-D4yj4rxf.mjs} +1 -1
- package/dist/.setup/{settled-turn-finalizer-CiY2bLFK.mjs → settled-turn-finalizer-BsvEabkw.mjs} +17 -13
- package/dist/.setup/{shared-client-BpTtuLQ5.mjs → shared-client-DqyTMYug.mjs} +826 -485
- package/dist/.setup/shared-client-lifecycle-DJIgqgMw.mjs +153 -0
- package/dist/.setup/{side-question-DSCZyoBD.mjs → side-question-C4kCmQy1.mjs} +206 -334
- package/dist/.setup/{source-Bjp4UQij.mjs → source-CS_7GFJZ.mjs} +82 -139
- package/dist/.setup/spawn-error-CL3n6MAa.mjs +57 -0
- package/dist/.setup/{thread-archive-guard-jmecf6OJ.mjs → thread-archive-guard-C9frICzX.mjs} +10 -3
- package/dist/.setup/thread-lifecycle-DPflntEJ.mjs +2362 -0
- package/dist/.setup/{incognito-session-uhrBF6wJ.mjs → thread-ownership-queue-Dp24d7-F.mjs} +1 -2
- package/dist/.setup/{thread-ownership-skomxnIt.mjs → thread-ownership-roNP0l1c.mjs} +47 -10
- package/dist/.setup/thread-policy-DTd-DtkX.mjs +109 -0
- package/dist/.setup/thread-requests-B_bRnMGN.mjs +2102 -0
- package/dist/.setup/{thread-resume-BkNpj9Pz.mjs → thread-resume-CdDaoc7T.mjs} +6 -6
- package/dist/.setup/timeout-CXOfNoaX.mjs +46 -0
- package/dist/.setup/transcript-history-projection-DRSifI-1.mjs +201 -0
- package/dist/.setup/{transcript-mirror-attestation-CzM-94NC.mjs → transcript-mirror-attestation-YSegaktH.mjs} +3 -4
- package/dist/.setup/{transcript-mirror-D4qp_leP.mjs → transcript-mirror-kxmCYsuF.mjs} +224 -206
- package/dist/.setup/{transport-stdio-Cmx94Oiy.mjs → transport-stdio-Bdegpn2V.mjs} +138 -75
- package/dist/.setup/transport-websocket-BTBE-LD9.mjs +211 -0
- package/dist/.setup/{upstream-prompt-provenance-LphB8slG.mjs → upstream-prompt-provenance-fXkKbPVC.mjs} +3 -9
- package/dist/.setup/{upstream-session-fork-D3UKxgVD.mjs → upstream-session-fork-CBeVjBpT.mjs} +48 -40
- package/dist/.setup/{usage-BOgBEKso.mjs → usage-BMzNxeR_.mjs} +5 -4
- package/dist/.setup/{usage-limit-error-C0ow7DOc.mjs → usage-limit-error-QXerDo3i.mjs} +5 -20
- package/dist/.setup/{web-search-provider.runtime-CTGuJt6i.mjs → web-search-provider.runtime-P77OUeoo.mjs} +10 -20
- package/dist/api.js +25 -16
- package/dist/catalog-page-worker-entrypoint.js +12 -0
- package/dist/catalog-page.worker.js +9 -0
- package/dist/cli-metadata.js +1 -1
- package/dist/doctor-contract-api.js +50 -8
- package/dist/harness.js +344 -1
- package/dist/index.js +345 -346
- package/dist/media-understanding-provider.js +9 -22
- package/dist/migration-provider-api.js +1 -1
- package/dist/provider-discovery.js +1 -1
- package/dist/session-history-worker-runtime.js +16 -33
- package/dist/session-history.worker.js +1 -1
- package/openclaw.plugin.json +14 -2
- package/package.json +11 -7
- package/dist/.setup/attempt-context-VXVwTCfS.mjs +0 -636
- package/dist/.setup/compact-C3i3qlzj.mjs +0 -687
- package/dist/.setup/event-projector-assistant-message-DNUR1s0A.mjs +0 -105
- package/dist/.setup/event-projector-items-DyTQ_XqL.mjs +0 -200
- package/dist/.setup/harness-rxaaoN-o.mjs +0 -349
- package/dist/.setup/history-rejection-B4nOXNXF.mjs +0 -13
- package/dist/.setup/image-payload-sanitizer-tupAr-2o.mjs +0 -79
- package/dist/.setup/inference-proxy-CC15HuSi.mjs +0 -311
- package/dist/.setup/launch-args-DnMak49W.mjs +0 -111
- package/dist/.setup/local-runtime-attribution-B_2mnqhb.mjs +0 -19
- package/dist/.setup/native-subagent-history-YXaL6dMd.mjs +0 -135
- package/dist/.setup/native-subagent-task-ids-DsuOonKv.mjs +0 -411
- package/dist/.setup/node-exec-server.runtime-BaViBKNz.mjs +0 -226
- package/dist/.setup/plugin-approval-roundtrip-CjfzafAZ.mjs +0 -122
- package/dist/.setup/provider-fFh_-VR3.mjs +0 -50
- package/dist/.setup/rolldown-runtime-8H4AJuhK.mjs +0 -14
- package/dist/.setup/sandbox-guard-BBP-RbTf.mjs +0 -166
- package/dist/.setup/session-binding-_0W_fHRr.mjs +0 -721
- package/dist/.setup/session-catalog-events-jMcYfQyd.mjs +0 -250
- package/dist/.setup/session-history-read-B3ZfSUbF.mjs +0 -50
- package/dist/.setup/session-initialization-DH1z6fXn.mjs +0 -75
- package/dist/.setup/thread-history-page-BTx-4xsg.mjs +0 -83
- package/dist/.setup/thread-lifecycle-Cik28qWn.mjs +0 -4904
- package/dist/.setup/thread-policy-Cjs4B8xf.mjs +0 -54
- package/dist/.setup/timeout-DZF05XrR.mjs +0 -63
- package/dist/.setup/transcript-history-projection-DHNBDhCU.mjs +0 -243
- package/dist/.setup/version-CoqzXPgK.mjs +0 -12
|
@@ -1,11 +1,18 @@
|
|
|
1
|
-
import { r as normalizeCodexAppServerArgs } from "./launch-args-
|
|
1
|
+
import { r as normalizeCodexAppServerArgs } from "./launch-args-DbFCehO7.mjs";
|
|
2
|
+
import { i as resolveManagedCodexNativeCommand } from "./managed-binary-kiWRhNRE.mjs";
|
|
3
|
+
import { i as recordCodexAppServerSpawnFailure, r as getCodexAppServerSpawnFailure } from "./spawn-error-CL3n6MAa.mjs";
|
|
2
4
|
import { createHash, randomUUID } from "node:crypto";
|
|
5
|
+
import { stripVTControlCharacters } from "node:util";
|
|
6
|
+
import { embeddedAgentLog } from "openclaw/plugin-sdk/agent-harness-registration";
|
|
3
7
|
import { z } from "zod";
|
|
4
8
|
import { materializeWindowsSpawnProgram, resolveWindowsSpawnProgram } from "openclaw/plugin-sdk/windows-spawn";
|
|
5
9
|
import { closeSync, constants, openSync, readSync } from "node:fs";
|
|
6
10
|
import path from "node:path";
|
|
7
11
|
import { readFile, readdir } from "node:fs/promises";
|
|
12
|
+
import { resolveGlobalSingleton } from "openclaw/plugin-sdk/global-singleton";
|
|
8
13
|
import { once } from "node:events";
|
|
14
|
+
import { KeyedAsyncQueue } from "openclaw/plugin-sdk/keyed-async-queue";
|
|
15
|
+
import { resolveStateDir } from "openclaw/plugin-sdk/state-paths";
|
|
9
16
|
import { execFile, spawn } from "node:child_process";
|
|
10
17
|
import { setImmediate } from "node:timers/promises";
|
|
11
18
|
import { finished } from "node:stream/promises";
|
|
@@ -302,6 +309,8 @@ const MAX_PROCESS_QUIESCE_PASSES = 16;
|
|
|
302
309
|
/** Discharges the registered root obligation, including an already-obsolete PID. */
|
|
303
310
|
async function terminateCodexAppServerOrphan(expected) {
|
|
304
311
|
const deadline = Date.now() + MAX_PROCESS_CONTAINMENT_MS;
|
|
312
|
+
const initial = (await readCodexAppServerProcessSnapshot(deadline, [expected.pid])).find((row) => row.pid === expected.pid);
|
|
313
|
+
if (!initial || !hasSameIdentity(initial, expected) || isDeadProcessState(initial.state)) return true;
|
|
305
314
|
const result = await terminateCodexAppServerDescendants({
|
|
306
315
|
pid: expected.pid,
|
|
307
316
|
kill: (signal) => signalProcess(expected.pid, signal ?? "SIGTERM")
|
|
@@ -314,7 +323,7 @@ async function terminateCodexAppServerOrphan(expected) {
|
|
|
314
323
|
if (current && isSameLiveRoot(current, contained.root, true)) signalProcess(current.pgid === current.pid ? -current.pid : current.pid, "SIGKILL");
|
|
315
324
|
}
|
|
316
325
|
while (Date.now() < deadline) {
|
|
317
|
-
const snapshot = await readCodexAppServerProcessSnapshot(deadline).catch(() => void 0);
|
|
326
|
+
const snapshot = await readCodexAppServerProcessSnapshot(deadline, [expected.pid]).catch(() => void 0);
|
|
318
327
|
if (!snapshot?.some((row) => row.pid === process.pid)) return false;
|
|
319
328
|
const current = snapshot.find((row) => row.pid === expected.pid);
|
|
320
329
|
if (!current || !hasSameIdentity(current, expected) || isDeadProcessState(current.state)) {
|
|
@@ -531,21 +540,37 @@ const registrationSchema = z.object({
|
|
|
531
540
|
parent: processIdentity,
|
|
532
541
|
child: childIdentity
|
|
533
542
|
}).strict();
|
|
543
|
+
const registrationCleanup = /* @__PURE__ */ new WeakMap();
|
|
544
|
+
const processReaper = resolveGlobalSingleton(Symbol.for("openclaw.codexAppServerProcessReaper"), () => new KeyedAsyncQueue());
|
|
545
|
+
/** Join bookkeeping after the transport owner has observed physical exit. */
|
|
546
|
+
async function waitForCodexAppServerProcessRegistrationCleanup(child) {
|
|
547
|
+
await registrationCleanup.get(child);
|
|
548
|
+
}
|
|
534
549
|
function fingerprintProcessCommand(command) {
|
|
535
550
|
return createHash("sha256").update(command).digest("hex");
|
|
536
551
|
}
|
|
537
552
|
async function openProcessRegistrationStore() {
|
|
538
|
-
const
|
|
539
|
-
|
|
553
|
+
const env = {
|
|
554
|
+
...process.env,
|
|
555
|
+
OPENCLAW_STATE_DIR: resolveStateDir()
|
|
556
|
+
};
|
|
557
|
+
const { createPluginStateKeyedStore } = await import("openclaw/plugin-sdk/plugin-state-store-runtime");
|
|
558
|
+
return createPluginStateKeyedStore("codex", {
|
|
540
559
|
namespace: "app-server-processes",
|
|
541
560
|
maxEntries: 512,
|
|
542
|
-
overflowPolicy: "reject-new"
|
|
561
|
+
overflowPolicy: "reject-new",
|
|
562
|
+
env
|
|
543
563
|
});
|
|
544
564
|
}
|
|
545
565
|
async function reapRegisteredCodexAppServerOrphans() {
|
|
546
566
|
const store = await openProcessRegistrationStore();
|
|
567
|
+
await processReaper.enqueue("orphans", () => sweepRegisteredCodexAppServerOrphans(store));
|
|
568
|
+
return store;
|
|
569
|
+
}
|
|
570
|
+
async function sweepRegisteredCodexAppServerOrphans(store) {
|
|
571
|
+
const entries = await store.entries();
|
|
547
572
|
const deadline = Date.now() + PROCESS_REGISTRATION_INSPECTION_MS;
|
|
548
|
-
for (const entry of
|
|
573
|
+
for (const entry of entries) {
|
|
549
574
|
if (Date.now() >= deadline) throw new Error("Codex orphan cleanup exceeded its startup budget. Retry to finish cleanup.");
|
|
550
575
|
const registration = registrationSchema.parse(entry.value);
|
|
551
576
|
const snapshot = await readCodexAppServerProcessSnapshot(deadline, [registration.parent.pid, registration.child.pid]);
|
|
@@ -557,29 +582,34 @@ async function reapRegisteredCodexAppServerOrphans() {
|
|
|
557
582
|
try {
|
|
558
583
|
command = await readCodexAppServerProcessCommand(child, deadline);
|
|
559
584
|
} catch (error) {
|
|
560
|
-
|
|
585
|
+
const current = (await readCodexAppServerProcessSnapshot(deadline, [registration.child.pid])).find((row) => row.pid === registration.child.pid);
|
|
586
|
+
if (current?.startedAt === registration.child.startedAt && !isDeadProcessState(current.state)) throw error;
|
|
561
587
|
}
|
|
562
588
|
if (command !== void 0 && fingerprintProcessCommand(command) !== registration.child.commandFingerprint) {
|
|
563
|
-
store.delete(entry.key);
|
|
589
|
+
await store.delete(entry.key);
|
|
564
590
|
continue;
|
|
565
591
|
}
|
|
566
592
|
}
|
|
567
593
|
if (!await terminateCodexAppServerOrphan(registration.child)) throw new Error(`Cannot reap registered Codex process ${registration.child.pid}. Stop it before retrying.`);
|
|
568
|
-
store.delete(entry.key);
|
|
594
|
+
await store.delete(entry.key);
|
|
569
595
|
}
|
|
570
596
|
}
|
|
571
597
|
function createCodexAppServerProcessReaperService() {
|
|
598
|
+
let pendingSweep;
|
|
572
599
|
return {
|
|
573
600
|
id: "codex-app-server-process-reaper",
|
|
574
601
|
start(ctx) {
|
|
575
602
|
if (process.platform === "win32") return;
|
|
576
|
-
(async () => {
|
|
603
|
+
pendingSweep = (async () => {
|
|
577
604
|
try {
|
|
578
605
|
await reapRegisteredCodexAppServerOrphans();
|
|
579
606
|
} catch (error) {
|
|
580
607
|
ctx.logger.warn(`Codex app-server orphan cleanup failed: ${String(error)}`);
|
|
581
608
|
}
|
|
582
609
|
})();
|
|
610
|
+
},
|
|
611
|
+
async stop() {
|
|
612
|
+
await pendingSweep;
|
|
583
613
|
}
|
|
584
614
|
};
|
|
585
615
|
}
|
|
@@ -588,8 +618,7 @@ async function prepareCodexAppServerProcessRegistration() {
|
|
|
588
618
|
if (process.platform === "win32") return async (child) => {
|
|
589
619
|
await once(child, "spawn");
|
|
590
620
|
};
|
|
591
|
-
await reapRegisteredCodexAppServerOrphans();
|
|
592
|
-
const store = await openProcessRegistrationStore();
|
|
621
|
+
const store = await reapRegisteredCodexAppServerOrphans();
|
|
593
622
|
return async (child) => {
|
|
594
623
|
await once(child, "spawn");
|
|
595
624
|
if (!child.pid) throw new ProcessInspectionError("unavailable");
|
|
@@ -601,21 +630,63 @@ async function prepareCodexAppServerProcessRegistration() {
|
|
|
601
630
|
const command = await readCodexAppServerProcessCommand(spawned, deadline);
|
|
602
631
|
if (child.exitCode !== null || child.signalCode !== null) throw new Error("Cannot register the Codex child process command: the child exited during inspection. Retry.");
|
|
603
632
|
const key = randomUUID();
|
|
604
|
-
|
|
633
|
+
const value = {
|
|
605
634
|
parent: processIdentity.parse(parent),
|
|
606
635
|
child: childIdentity.parse({
|
|
607
636
|
...spawned,
|
|
608
637
|
commandFingerprint: fingerprintProcessCommand(command)
|
|
609
638
|
})
|
|
639
|
+
};
|
|
640
|
+
const exited = new Promise((resolve) => {
|
|
641
|
+
child.once("exit", () => resolve());
|
|
610
642
|
});
|
|
611
|
-
|
|
643
|
+
const registered = store.register(key, value);
|
|
644
|
+
const cleanup = (async () => {
|
|
645
|
+
await exited;
|
|
646
|
+
await registered.catch(() => void 0);
|
|
612
647
|
try {
|
|
613
|
-
store.delete(key);
|
|
648
|
+
await store.delete(key);
|
|
614
649
|
} catch {}
|
|
615
|
-
});
|
|
650
|
+
})();
|
|
651
|
+
registrationCleanup.set(child, cleanup);
|
|
652
|
+
await registered;
|
|
653
|
+
if (child.exitCode !== null || child.signalCode !== null) {
|
|
654
|
+
await cleanup;
|
|
655
|
+
throw new Error("Cannot register the Codex child process: the child exited during registration. Retry.");
|
|
656
|
+
}
|
|
616
657
|
};
|
|
617
658
|
}
|
|
618
659
|
//#endregion
|
|
660
|
+
//#region extensions/codex/src/app-server/managed-launcher-failure.ts
|
|
661
|
+
/** The official npm launcher prints Node's native spawn error and exits before initialization. */
|
|
662
|
+
function observeManagedCodexLauncherFailure(child, nativeCommand) {
|
|
663
|
+
let prefix = "";
|
|
664
|
+
let launchCode;
|
|
665
|
+
const startupFailure = { complete() {
|
|
666
|
+
child.stderr.off("data", onData);
|
|
667
|
+
child.off("exit", onExit);
|
|
668
|
+
prefix = "";
|
|
669
|
+
} };
|
|
670
|
+
const onData = (chunk) => {
|
|
671
|
+
if (launchCode || prefix.length >= 16384) return;
|
|
672
|
+
prefix = (prefix + stripVTControlCharacters(chunk.toString())).slice(0, 16384);
|
|
673
|
+
if (/\bError: spawn\b/u.test(prefix) && /syscall: ['"]spawn(?: [^'"\r\n]*)?['"]/u.test(prefix)) launchCode = /\bcode: ['"](ENOENT|EACCES|EBADARCH|Unknown system error -86)['"]/u.exec(prefix)?.[1];
|
|
674
|
+
else if (/Error: Missing optional dependency @openai\/codex-[\w-]+\. Reinstall Codex:/u.test(prefix)) launchCode = "ENOENT";
|
|
675
|
+
};
|
|
676
|
+
const onExit = (code) => {
|
|
677
|
+
startupFailure.complete();
|
|
678
|
+
if (code !== 1 || !launchCode) return;
|
|
679
|
+
const described = recordCodexAppServerSpawnFailure(Object.assign(/* @__PURE__ */ new Error(`spawn ${launchCode}`), {
|
|
680
|
+
code: launchCode,
|
|
681
|
+
syscall: "spawn"
|
|
682
|
+
}), nativeCommand, nativeCommand);
|
|
683
|
+
if (described instanceof Error) startupFailure.error = described;
|
|
684
|
+
};
|
|
685
|
+
child.stderr.on("data", onData);
|
|
686
|
+
child.once("exit", onExit);
|
|
687
|
+
Object.assign(child, { startupFailure });
|
|
688
|
+
}
|
|
689
|
+
//#endregion
|
|
619
690
|
//#region extensions/codex/src/app-server/transport.ts
|
|
620
691
|
/**
|
|
621
692
|
* Shared transport lifecycle helpers for stdio and WebSocket Codex app-server
|
|
@@ -645,12 +716,7 @@ function beginCodexAppServerTransportClose(child, options) {
|
|
|
645
716
|
finishCodexAppServerTransportClose(child, options, forceKill);
|
|
646
717
|
return "uncertain";
|
|
647
718
|
}
|
|
648
|
-
|
|
649
|
-
try {
|
|
650
|
-
contained = await terminateCodexAppServerDescendants(child);
|
|
651
|
-
} catch {
|
|
652
|
-
contained = void 0;
|
|
653
|
-
}
|
|
719
|
+
const contained = await terminateCodexAppServerDescendants(child).catch(() => void 0);
|
|
654
720
|
if (contained === "exited") return "natural";
|
|
655
721
|
try {
|
|
656
722
|
finishCodexAppServerTransportClose(child, options, forceKill, contained?.resume);
|
|
@@ -696,6 +762,7 @@ async function closeCodexAppServerTransportAndWait(child, options = {}) {
|
|
|
696
762
|
const closure = beginCodexAppServerTransportClose(child, options);
|
|
697
763
|
const containment = await closure.closing;
|
|
698
764
|
const settled = await waitForCodexAppServerTransportExit(child, options.exitTimeoutMs ?? 2e3, drained);
|
|
765
|
+
if (settled) await waitForCodexAppServerProcessRegistrationCleanup(child);
|
|
699
766
|
closure.naturalExit = containment === "natural" && settled;
|
|
700
767
|
if (options.drainStdio) {
|
|
701
768
|
child.stdout.destroy?.();
|
|
@@ -710,7 +777,7 @@ async function closeCodexAppServerTransportAndWait(child, options = {}) {
|
|
|
710
777
|
};
|
|
711
778
|
}
|
|
712
779
|
function hasCodexAppServerTransportExited(child) {
|
|
713
|
-
return child.exitCode
|
|
780
|
+
return child.exitCode != null || child.signalCode != null;
|
|
714
781
|
}
|
|
715
782
|
async function waitForCodexAppServerTransportExit(child, timeoutMs, drained) {
|
|
716
783
|
return await new Promise((resolve) => {
|
|
@@ -756,46 +823,36 @@ const RUNTIME_INJECTION_ENVIRONMENT_KEYS = /* @__PURE__ */ new Set([
|
|
|
756
823
|
"LD_PRELOAD"
|
|
757
824
|
]);
|
|
758
825
|
const QA_PARENT_PID_ENV = "OPENCLAW_QA_PARENT_PID";
|
|
759
|
-
const DEFAULT_SPAWN_RUNTIME = {
|
|
760
|
-
platform: process.platform,
|
|
761
|
-
env: process.env,
|
|
762
|
-
execPath: process.execPath,
|
|
763
|
-
isBun: typeof process.versions.bun === "string"
|
|
764
|
-
};
|
|
765
826
|
/** Resolves the concrete command/argv/shell settings used to spawn Codex app-server. */
|
|
766
|
-
function resolveCodexAppServerSpawnInvocation(options,
|
|
827
|
+
function resolveCodexAppServerSpawnInvocation(options, env) {
|
|
767
828
|
if (options.commandSource === "managed") throw new Error("Managed Codex app-server start options must be resolved before spawn.");
|
|
768
829
|
const program = resolveWindowsSpawnProgram({
|
|
769
830
|
command: options.command,
|
|
770
|
-
platform:
|
|
771
|
-
env
|
|
772
|
-
execPath:
|
|
831
|
+
platform: process.platform,
|
|
832
|
+
env,
|
|
833
|
+
execPath: process.execPath,
|
|
773
834
|
packageName: "@openai/codex"
|
|
774
835
|
});
|
|
775
836
|
const args = normalizeCodexAppServerArgs(options.args);
|
|
776
837
|
const resolved = materializeWindowsSpawnProgram(program, args);
|
|
777
|
-
if (
|
|
838
|
+
if (options.commandSource === "resolved-managed" && resolved.resolution === "direct" && [
|
|
778
839
|
".cjs",
|
|
779
840
|
".js",
|
|
780
841
|
".mjs"
|
|
781
842
|
].includes(path.extname(resolved.command).toLowerCase())) return {
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
return {
|
|
787
|
-
command: resolved.command,
|
|
788
|
-
args: resolved.argv,
|
|
789
|
-
shell: resolved.shell,
|
|
790
|
-
windowsHide: resolved.windowsHide
|
|
843
|
+
...resolved,
|
|
844
|
+
command: process.execPath,
|
|
845
|
+
argv: [resolved.command, ...resolved.argv],
|
|
846
|
+
resolution: "node-entrypoint"
|
|
791
847
|
};
|
|
848
|
+
return resolved;
|
|
792
849
|
}
|
|
793
850
|
/** Merges app-server environment overrides while honoring clearEnv and unsafe key filtering. */
|
|
794
851
|
function resolveCodexAppServerSpawnEnv(options, baseEnv = process.env, platform = process.platform) {
|
|
795
852
|
const env = Object.create(null);
|
|
796
853
|
copySafeEnvironmentEntries(env, baseEnv);
|
|
797
854
|
copySafeEnvironmentEntries(env, options.env ?? {});
|
|
798
|
-
const keysToClear =
|
|
855
|
+
const keysToClear = (options.clearEnv ?? []).map((key) => key.trim()).filter(Boolean);
|
|
799
856
|
if (platform === "win32") {
|
|
800
857
|
const lowerCaseKeysToClear = new Set(keysToClear.map((key) => key.toLowerCase()));
|
|
801
858
|
for (const candidate of Object.keys(env)) if (lowerCaseKeysToClear.has(candidate.toLowerCase())) delete env[candidate];
|
|
@@ -807,18 +864,6 @@ function isCodexRuntimeInjectionEnvironmentKey(rawKey) {
|
|
|
807
864
|
const key = rawKey.toUpperCase();
|
|
808
865
|
return RUNTIME_INJECTION_ENVIRONMENT_KEYS.has(key) || key.startsWith("DYLD_");
|
|
809
866
|
}
|
|
810
|
-
/** Keeps QA-owned app-server processes inside the gateway process-group cleanup boundary. */
|
|
811
|
-
function resolveCodexAppServerDetachedMode(env, platform = process.platform) {
|
|
812
|
-
return platform !== "win32" && !env[QA_PARENT_PID_ENV]?.trim();
|
|
813
|
-
}
|
|
814
|
-
function normalizedEnvironmentKeys(rawKeys) {
|
|
815
|
-
const keys = [];
|
|
816
|
-
for (const rawKey of rawKeys) {
|
|
817
|
-
const key = rawKey.trim();
|
|
818
|
-
if (key.length > 0) keys.push(key);
|
|
819
|
-
}
|
|
820
|
-
return keys;
|
|
821
|
-
}
|
|
822
867
|
function copySafeEnvironmentEntries(target, source) {
|
|
823
868
|
for (const [key, value] of Object.entries(source)) {
|
|
824
869
|
if (UNSAFE_ENVIRONMENT_KEYS.has(key)) continue;
|
|
@@ -828,27 +873,45 @@ function copySafeEnvironmentEntries(target, source) {
|
|
|
828
873
|
/** Spawns the Codex app-server process and returns the shared transport interface. */
|
|
829
874
|
async function createStdioTransport(options, baseEnv = process.env, assertCurrent, onSpawn) {
|
|
830
875
|
const env = resolveCodexAppServerSpawnEnv(options, baseEnv);
|
|
831
|
-
const invocation = resolveCodexAppServerSpawnInvocation(options,
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
876
|
+
const invocation = resolveCodexAppServerSpawnInvocation(options, env);
|
|
877
|
+
const nativeCommand = options.commandSource === "resolved-managed" ? resolveManagedCodexNativeCommand(options.command, { pathExists: () => true }) : void 0;
|
|
878
|
+
const launchKey = JSON.stringify([
|
|
879
|
+
invocation.command,
|
|
880
|
+
options.cwd ?? process.cwd(),
|
|
881
|
+
nativeCommand ?? null,
|
|
882
|
+
path.isAbsolute(invocation.command) ? null : env.PATH ?? env.Path
|
|
883
|
+
]);
|
|
884
|
+
const previousFailure = getCodexAppServerSpawnFailure(launchKey) ?? (nativeCommand ? getCodexAppServerSpawnFailure(nativeCommand) : void 0);
|
|
885
|
+
if (previousFailure) throw previousFailure;
|
|
837
886
|
const register = await prepareCodexAppServerProcessRegistration();
|
|
838
887
|
assertCurrent?.();
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
"pipe",
|
|
847
|
-
"pipe"
|
|
848
|
-
],
|
|
849
|
-
windowsHide: invocation.windowsHide
|
|
888
|
+
embeddedAgentLog.debug("Codex app-server spawn", {
|
|
889
|
+
command: invocation.command,
|
|
890
|
+
launcher: options.command,
|
|
891
|
+
...options.cwd ? { cwd: options.cwd } : {},
|
|
892
|
+
...nativeCommand ? { nativeCommand } : {},
|
|
893
|
+
platform: process.platform,
|
|
894
|
+
arch: process.arch
|
|
850
895
|
});
|
|
896
|
+
let child;
|
|
897
|
+
try {
|
|
898
|
+
child = spawn(invocation.command, invocation.argv, {
|
|
899
|
+
...options.cwd !== void 0 ? { cwd: options.cwd } : {},
|
|
900
|
+
env,
|
|
901
|
+
detached: process.platform !== "win32" && !env[QA_PARENT_PID_ENV]?.trim(),
|
|
902
|
+
shell: invocation.shell,
|
|
903
|
+
stdio: [
|
|
904
|
+
"pipe",
|
|
905
|
+
"pipe",
|
|
906
|
+
"pipe"
|
|
907
|
+
],
|
|
908
|
+
windowsHide: invocation.windowsHide
|
|
909
|
+
});
|
|
910
|
+
} catch (error) {
|
|
911
|
+
throw recordCodexAppServerSpawnFailure(error, invocation.command, launchKey);
|
|
912
|
+
}
|
|
851
913
|
try {
|
|
914
|
+
if (nativeCommand && invocation.resolution === "node-entrypoint") observeManagedCodexLauncherFailure(child, nativeCommand);
|
|
852
915
|
onSpawn?.(child);
|
|
853
916
|
await register(child);
|
|
854
917
|
assertCurrent?.();
|
|
@@ -856,8 +919,8 @@ async function createStdioTransport(options, baseEnv = process.env, assertCurren
|
|
|
856
919
|
} catch (error) {
|
|
857
920
|
await closeCodexAppServerTransportAndWait(child, { drainStdio: true });
|
|
858
921
|
assertCurrent?.();
|
|
859
|
-
throw error;
|
|
922
|
+
throw child.startupFailure?.error ?? recordCodexAppServerSpawnFailure(error, invocation.command, launchKey);
|
|
860
923
|
}
|
|
861
924
|
}
|
|
862
925
|
//#endregion
|
|
863
|
-
export {
|
|
926
|
+
export { closeCodexAppServerTransportAndWait as a, closeCodexAppServerTransport as i, resolveCodexAppServerSpawnEnv as n, hasCodexAppServerNaturalExit as o, resolveCodexAppServerSpawnInvocation as r, createCodexAppServerProcessReaperService as s, createStdioTransport as t };
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { r as resolveCodexAppServerUserHomeDir } from "./auth-start-options-BPIPeEX8.mjs";
|
|
2
|
+
import "./config-DKhXquav.mjs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { EventEmitter } from "node:events";
|
|
5
|
+
import net from "node:net";
|
|
6
|
+
import { PassThrough, Writable } from "node:stream";
|
|
7
|
+
import { StringDecoder } from "node:string_decoder";
|
|
8
|
+
import { WebSocket } from "openclaw/plugin-sdk/websocket-runtime";
|
|
9
|
+
//#region extensions/codex/src/app-server/transport-websocket.ts
|
|
10
|
+
/**
|
|
11
|
+
* Adapts a remote Codex app-server WebSocket endpoint to the shared stdio-like
|
|
12
|
+
* transport interface.
|
|
13
|
+
*/
|
|
14
|
+
const WEBSOCKET_HANDSHAKE_TIMEOUT_MS = 1e4;
|
|
15
|
+
const WEBSOCKET_PING_INTERVAL_MS = 2e4;
|
|
16
|
+
const WEBSOCKET_PONG_TIMEOUT_MS = 2e4;
|
|
17
|
+
const MAX_CONSECUTIVE_MISSED_WEBSOCKET_PONGS = 5;
|
|
18
|
+
/** Only the transport can prove that its buffered initialize never reached a peer. */
|
|
19
|
+
function isCodexWebSocketOpenFailure(error) {
|
|
20
|
+
const seen = /* @__PURE__ */ new Set();
|
|
21
|
+
let current = error;
|
|
22
|
+
while (current instanceof Error && !seen.has(current)) {
|
|
23
|
+
seen.add(current);
|
|
24
|
+
if ("code" in current && current.code === "CODEX_APP_SERVER_WEBSOCKET_OPEN_FAILED") return true;
|
|
25
|
+
current = current.cause;
|
|
26
|
+
}
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
/** Opens a WebSocket app-server transport and maps newline-delimited frames to stdout/stdin. */
|
|
30
|
+
function createWebSocketTransport(options) {
|
|
31
|
+
if (!options.url) throw new Error("codex app-server websocket transport requires plugins.entries.codex.config.appServer.url");
|
|
32
|
+
const events = new EventEmitter();
|
|
33
|
+
const stdout = new PassThrough();
|
|
34
|
+
const stderr = new PassThrough();
|
|
35
|
+
const websocketOptions = {
|
|
36
|
+
headers: {
|
|
37
|
+
...options.headers,
|
|
38
|
+
...options.authToken ? { Authorization: `Bearer ${options.authToken}` } : {}
|
|
39
|
+
},
|
|
40
|
+
perMessageDeflate: false,
|
|
41
|
+
...options.transport === "websocket" ? { handshakeTimeout: WEBSOCKET_HANDSHAKE_TIMEOUT_MS } : {}
|
|
42
|
+
};
|
|
43
|
+
const unixSocketPath = resolveCodexAppServerUnixSocketPath(options);
|
|
44
|
+
const socket = unixSocketPath ? new WebSocket("ws://localhost/", {
|
|
45
|
+
...websocketOptions,
|
|
46
|
+
createConnection: () => connectCodexAppServerUnixSocket(unixSocketPath)
|
|
47
|
+
}) : new WebSocket(options.url, websocketOptions);
|
|
48
|
+
const pendingFrames = [];
|
|
49
|
+
const stdinDecoder = new StringDecoder("utf8");
|
|
50
|
+
let pendingLine = "";
|
|
51
|
+
let opened = false;
|
|
52
|
+
let killed = false;
|
|
53
|
+
let exitCode = null;
|
|
54
|
+
let pingTimeout;
|
|
55
|
+
let pongTimeout;
|
|
56
|
+
let expectedPong;
|
|
57
|
+
let consecutiveMissedPongs = 0;
|
|
58
|
+
let heartbeatSequence = 0;
|
|
59
|
+
const clearConnectionHealthTimers = () => {
|
|
60
|
+
if (pingTimeout) {
|
|
61
|
+
clearTimeout(pingTimeout);
|
|
62
|
+
pingTimeout = void 0;
|
|
63
|
+
}
|
|
64
|
+
if (pongTimeout) {
|
|
65
|
+
clearTimeout(pongTimeout);
|
|
66
|
+
pongTimeout = void 0;
|
|
67
|
+
}
|
|
68
|
+
expectedPong = void 0;
|
|
69
|
+
};
|
|
70
|
+
const sendHeartbeatPing = () => {
|
|
71
|
+
if (socket.readyState !== WebSocket.OPEN || pongTimeout) return;
|
|
72
|
+
const payload = Buffer.from(`openclaw-codex-${++heartbeatSequence}`);
|
|
73
|
+
expectedPong = payload;
|
|
74
|
+
pongTimeout = setTimeout(() => {
|
|
75
|
+
pongTimeout = void 0;
|
|
76
|
+
expectedPong = void 0;
|
|
77
|
+
consecutiveMissedPongs += 1;
|
|
78
|
+
if (consecutiveMissedPongs >= MAX_CONSECUTIVE_MISSED_WEBSOCKET_PONGS) {
|
|
79
|
+
socket.terminate();
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
sendHeartbeatPing();
|
|
83
|
+
}, WEBSOCKET_PONG_TIMEOUT_MS);
|
|
84
|
+
pongTimeout.unref();
|
|
85
|
+
socket.ping(payload, void 0, (error) => {
|
|
86
|
+
if (error) socket.terminate();
|
|
87
|
+
});
|
|
88
|
+
};
|
|
89
|
+
const scheduleHeartbeatPing = () => {
|
|
90
|
+
if (options.transport !== "websocket" || socket.readyState !== WebSocket.OPEN || pingTimeout || pongTimeout) return;
|
|
91
|
+
pingTimeout = setTimeout(() => {
|
|
92
|
+
pingTimeout = void 0;
|
|
93
|
+
sendHeartbeatPing();
|
|
94
|
+
}, WEBSOCKET_PING_INTERVAL_MS);
|
|
95
|
+
pingTimeout.unref();
|
|
96
|
+
};
|
|
97
|
+
const recordConnectionActivity = () => {
|
|
98
|
+
consecutiveMissedPongs = 0;
|
|
99
|
+
if (pongTimeout) {
|
|
100
|
+
clearTimeout(pongTimeout);
|
|
101
|
+
pongTimeout = void 0;
|
|
102
|
+
}
|
|
103
|
+
expectedPong = void 0;
|
|
104
|
+
scheduleHeartbeatPing();
|
|
105
|
+
};
|
|
106
|
+
const sendFrame = (frame) => {
|
|
107
|
+
const trimmed = frame.trim();
|
|
108
|
+
if (!trimmed) return;
|
|
109
|
+
if (socket.readyState === WebSocket.OPEN) {
|
|
110
|
+
socket.send(trimmed);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
pendingFrames.push(trimmed);
|
|
114
|
+
};
|
|
115
|
+
socket.once("open", () => {
|
|
116
|
+
opened = true;
|
|
117
|
+
for (const frame of pendingFrames.splice(0)) socket.send(frame);
|
|
118
|
+
scheduleHeartbeatPing();
|
|
119
|
+
});
|
|
120
|
+
socket.on("pong", (payload) => {
|
|
121
|
+
if (expectedPong?.equals(payload)) recordConnectionActivity();
|
|
122
|
+
});
|
|
123
|
+
socket.once("error", (error) => {
|
|
124
|
+
clearConnectionHealthTimers();
|
|
125
|
+
const code = "code" in error ? error.code : void 0;
|
|
126
|
+
if (options.transport === "websocket" && !opened && (code === "ECONNREFUSED" || code === "ECONNRESET" || code === "ETIMEDOUT" || error.message === "Opening handshake has timed out")) {
|
|
127
|
+
events.emit("error", Object.assign(new Error(error.message, { cause: error }), { code: "CODEX_APP_SERVER_WEBSOCKET_OPEN_FAILED" }));
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
events.emit("error", error);
|
|
131
|
+
});
|
|
132
|
+
socket.once("close", (code, reason) => {
|
|
133
|
+
clearConnectionHealthTimers();
|
|
134
|
+
killed = true;
|
|
135
|
+
exitCode = code;
|
|
136
|
+
events.emit("exit", code, reason.toString("utf8"));
|
|
137
|
+
});
|
|
138
|
+
socket.on("message", (data) => {
|
|
139
|
+
if (options.transport === "websocket") recordConnectionActivity();
|
|
140
|
+
const frame = websocketFrameToBuffer(data);
|
|
141
|
+
const writable = stdout.write(frame);
|
|
142
|
+
const delimited = frame.at(-1) === 10 || stdout.write(Buffer.from("\n"));
|
|
143
|
+
if (!writable || !delimited) socket.pause();
|
|
144
|
+
});
|
|
145
|
+
stdout.on("drain", () => {
|
|
146
|
+
if (socket.readyState === WebSocket.OPEN) socket.resume();
|
|
147
|
+
});
|
|
148
|
+
const stdin = new Writable({
|
|
149
|
+
write(chunk, _encoding, callback) {
|
|
150
|
+
pendingLine += stdinDecoder.write(chunk);
|
|
151
|
+
const lines = pendingLine.split("\n");
|
|
152
|
+
pendingLine = lines.pop() ?? "";
|
|
153
|
+
for (const frame of lines) sendFrame(frame);
|
|
154
|
+
callback();
|
|
155
|
+
},
|
|
156
|
+
final(callback) {
|
|
157
|
+
pendingLine += stdinDecoder.end();
|
|
158
|
+
if (pendingLine) sendFrame(pendingLine);
|
|
159
|
+
pendingLine = "";
|
|
160
|
+
callback();
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
const closeSocket = () => {
|
|
164
|
+
if (socket.readyState === WebSocket.CLOSED || socket.readyState === WebSocket.CLOSING) return;
|
|
165
|
+
socket.close();
|
|
166
|
+
};
|
|
167
|
+
stdin.once("finish", closeSocket);
|
|
168
|
+
stdin.once("close", closeSocket);
|
|
169
|
+
return {
|
|
170
|
+
maxFrameBytes: 16777216,
|
|
171
|
+
stdin,
|
|
172
|
+
stdout,
|
|
173
|
+
stderr,
|
|
174
|
+
get killed() {
|
|
175
|
+
return killed;
|
|
176
|
+
},
|
|
177
|
+
get exitCode() {
|
|
178
|
+
return exitCode;
|
|
179
|
+
},
|
|
180
|
+
kill: (signal) => {
|
|
181
|
+
killed = true;
|
|
182
|
+
clearConnectionHealthTimers();
|
|
183
|
+
if (signal === "SIGKILL") socket.terminate();
|
|
184
|
+
else socket.close();
|
|
185
|
+
},
|
|
186
|
+
once: (event, listener) => events.once(event, listener),
|
|
187
|
+
off: (event, listener) => events.off(event, listener)
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
/** Named local-only socket boundary for the egress classifier. */
|
|
191
|
+
function connectCodexAppServerUnixSocket(socketPath) {
|
|
192
|
+
return net.createConnection(socketPath);
|
|
193
|
+
}
|
|
194
|
+
/** Resolves the canonical or explicitly configured Codex control socket. */
|
|
195
|
+
function resolveCodexAppServerUnixSocketPath(options) {
|
|
196
|
+
if (options.transport !== "unix") {
|
|
197
|
+
if (options.url?.startsWith("unix://")) throw new Error("codex app-server unix URL requires unix transport");
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
const url = options.url ?? "unix://";
|
|
201
|
+
if (!url.startsWith("unix://")) throw new Error("codex app-server unix transport requires a unix:// URL");
|
|
202
|
+
return url.slice(7) || path.join(resolveCodexAppServerUserHomeDir(options.env ?? process.env), "app-server-control", "app-server-control.sock");
|
|
203
|
+
}
|
|
204
|
+
function websocketFrameToBuffer(data) {
|
|
205
|
+
if (typeof data === "string") return Buffer.from(data);
|
|
206
|
+
if (Buffer.isBuffer(data)) return data;
|
|
207
|
+
if (Array.isArray(data)) return Buffer.concat(data);
|
|
208
|
+
return Buffer.from(data);
|
|
209
|
+
}
|
|
210
|
+
//#endregion
|
|
211
|
+
export { isCodexWebSocketOpenFailure as n, resolveCodexAppServerUnixSocketPath as r, createWebSocketTransport as t };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { asOptionalRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
1
|
+
import { asOptionalRecord, readNonEmptyStringPreservingWhitespace } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
2
2
|
//#region extensions/codex/src/app-server/upstream-prompt-provenance.ts
|
|
3
3
|
const UPSTREAM_USER_TEXT_META_KEY = "upstreamUserText";
|
|
4
4
|
const MIRROR_IDENTITY_META_KEY = "mirrorIdentity";
|
|
@@ -16,10 +16,7 @@ function attachCodexMirrorIdentity(message, identity) {
|
|
|
16
16
|
}
|
|
17
17
|
function readMirrorIdentity(message) {
|
|
18
18
|
const meta = CODEX_META_KEY in message ? message[CODEX_META_KEY] : void 0;
|
|
19
|
-
|
|
20
|
-
if (!record) return;
|
|
21
|
-
const id = record[MIRROR_IDENTITY_META_KEY];
|
|
22
|
-
return typeof id === "string" && id ? id : void 0;
|
|
19
|
+
return readNonEmptyStringPreservingWhitespace(asOptionalRecord(meta)?.[MIRROR_IDENTITY_META_KEY]);
|
|
23
20
|
}
|
|
24
21
|
function attachUpstreamUserText(message, text) {
|
|
25
22
|
const existing = CODEX_META_KEY in message ? message[CODEX_META_KEY] : void 0;
|
|
@@ -34,10 +31,7 @@ function attachUpstreamUserText(message, text) {
|
|
|
34
31
|
}
|
|
35
32
|
function readUpstreamUserText(message) {
|
|
36
33
|
const meta = message && CODEX_META_KEY in message ? message[CODEX_META_KEY] : void 0;
|
|
37
|
-
|
|
38
|
-
if (!record) return;
|
|
39
|
-
const text = record[UPSTREAM_USER_TEXT_META_KEY];
|
|
40
|
-
return typeof text === "string" && text ? text : void 0;
|
|
34
|
+
return readNonEmptyStringPreservingWhitespace(asOptionalRecord(meta)?.[UPSTREAM_USER_TEXT_META_KEY]);
|
|
41
35
|
}
|
|
42
36
|
//#endregion
|
|
43
37
|
export { readUpstreamUserText as i, attachUpstreamUserText as n, readMirrorIdentity as r, attachCodexMirrorIdentity as t };
|