@openclaw/codex 2026.7.2-beta.7 → 2026.7.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/README.md +3 -27
  2. package/dist/{command-formatters-C336eRVS.js → .setup/app-server-policy-C_qTMEMy.mjs} +51 -9
  3. package/dist/{attempt-notifications-AP-a-Q5k.js → .setup/attempt-notifications-F8krwWL4.mjs} +6 -3
  4. package/dist/{command-handlers-DAHUSry9.js → .setup/command-handlers-DSRFfor4.mjs} +1156 -1319
  5. package/dist/.setup/command-rpc-BvYsfQ7G.mjs +786 -0
  6. package/dist/{compact-D_uvHurS.js → .setup/compact-BNgh7I4t.mjs} +10 -40
  7. package/dist/.setup/computer-use-C3QkmSO3.mjs +377 -0
  8. package/dist/.setup/config-CYEDnLJ2.mjs +1138 -0
  9. package/dist/{conversation-binding-data-BHRpYbX3.js → .setup/conversation-binding-data-CrRxtDBu.mjs} +1 -1
  10. package/dist/{bounded-turn-D2ZAgZVz.js → .setup/media-understanding-provider-EbJCyDqe.mjs} +203 -109
  11. package/dist/{models-BBMKU4jA.js → .setup/models-C_aZk03A.mjs} +11 -6
  12. package/dist/.setup/notification-correlation-iYs4WieS.mjs +35 -0
  13. package/dist/.setup/plugin-app-cache-key-DR8jV9oS.mjs +99 -0
  14. package/dist/.setup/protocol-2POPqAY4.mjs +13 -0
  15. package/dist/{transcript-mirror-DzsdNCf5.js → .setup/protocol-validators-dZQ-UTOa.mjs} +112 -922
  16. package/dist/{rate-limits-CU-gVCCS.js → .setup/provider-DGxDs6g8.mjs} +269 -13
  17. package/dist/{dynamic-tools-D2gYkSBO.js → .setup/provider-capabilities-DS2N_zc1.mjs} +5632 -3953
  18. package/dist/.setup/request-DFR0JyoV.mjs +36 -0
  19. package/dist/.setup/run-attempt-C7xEKFVB.mjs +8180 -0
  20. package/dist/{sandbox-guard-NuhpXmPB.js → .setup/sandbox-guard-DA2TQfZW.mjs} +1 -14
  21. package/dist/.setup/session-binding-DuihlMJc.mjs +628 -0
  22. package/dist/.setup/shared-client-B2KmLPRw.mjs +1854 -0
  23. package/dist/{side-question-_ulBk1AL.js → .setup/side-question-Cv6JXWCS.mjs} +84 -159
  24. package/dist/.setup/thread-lifecycle-u6CZdOOH.mjs +2593 -0
  25. package/dist/{web-search-provider.runtime-CCFhg2z5.js → .setup/web-search-provider.runtime-Ce2zOHxW.mjs} +3 -3
  26. package/dist/doctor-contract-api.js +122 -88
  27. package/dist/harness.js +20 -89
  28. package/dist/index.js +436 -1615
  29. package/dist/media-understanding-provider.js +1 -173
  30. package/dist/prompt-overlay.js +15 -0
  31. package/dist/provider-catalog.js +79 -0
  32. package/dist/provider-discovery.js +34 -0
  33. package/dist/provider.js +2 -0
  34. package/dist/web-search-contract-api.js +1 -1
  35. package/openclaw.plugin.json +178 -221
  36. package/package.json +8 -9
  37. package/dist/app-server-policy-BSaO2JIT.js +0 -49
  38. package/dist/auth-binding-B4FfbcCg.js +0 -62
  39. package/dist/capabilities-BFDTVYr4.js +0 -36
  40. package/dist/cli-metadata.js +0 -20
  41. package/dist/computer-use-CYEc8U3w.js +0 -693
  42. package/dist/conversation-control-xsIeXbo4.js +0 -287
  43. package/dist/effective-mcp-catalog-Bbd98Inw.js +0 -114
  44. package/dist/event-projector-assistant-message-DTgnPPVF.js +0 -101
  45. package/dist/event-projector-usage-Xp4AlR2k.js +0 -86
  46. package/dist/incognito-session-ET_ufDH-.js +0 -2
  47. package/dist/notification-correlation-CU6_AnOb.js +0 -67
  48. package/dist/plugin-app-cache-key-DztPafOA.js +0 -408
  49. package/dist/request-qKh331yu.js +0 -157
  50. package/dist/run-attempt-CY9WlDLc.js +0 -12413
  51. package/dist/runtime-artifact-CmtG_t1L.js +0 -554
  52. package/dist/session-binding-BXpo9ymA.js +0 -2214
  53. package/dist/session-catalog-DyOgR4WH.js +0 -2668
  54. package/dist/session-cli-2PZaFLRh.js +0 -175
  55. package/dist/session-upstream-marker-B6U7tLw5.js +0 -82
  56. package/dist/settled-turn-finalizer-CXY2Z9dT.js +0 -316
  57. package/dist/shared-client-DTbvH-XV.js +0 -3069
  58. package/dist/thread-lifecycle-DF53ogiA.js +0 -3987
  59. package/dist/transport-stdio-DXgGZ7Ib.js +0 -88
  60. package/dist/upstream-session-fork-Dy4Xvuoj.js +0 -320
  61. package/dist/usage-CQ6GhD5-.js +0 -25
  62. /package/dist/{rolldown-runtime-8H4AJuhK.js → .setup/rolldown-runtime-8H4AJuhK.mjs} +0 -0
  63. /package/dist/{session-binding-meta-B7aEMU7g.js → .setup/session-binding-meta-B7aEMU7g.mjs} +0 -0
  64. /package/dist/{web-search-provider.shared-BrZmlqyR.js → .setup/web-search-provider.shared-BrZmlqyR.mjs} +0 -0
@@ -1,408 +0,0 @@
1
- import { K as resolveCodexAppServerHomeDir } from "./shared-client-DTbvH-XV.js";
2
- import { w as resolveCodexAppServerUserHomeDir } from "./session-binding-BXpo9ymA.js";
3
- import { createRequire } from "node:module";
4
- import { isFutureDateTimestampMs, resolveDateTimestampMs, resolveExpiresAtMsFromDurationMs } from "openclaw/plugin-sdk/number-runtime";
5
- import { OPENCLAW_VERSION, embeddedAgentLog } from "openclaw/plugin-sdk/agent-harness-runtime";
6
- import { createHash } from "node:crypto";
7
- import { readPluginPackageVersion } from "openclaw/plugin-sdk/extension-shared";
8
- import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
9
- import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
10
- //#region extensions/codex/src/app-server/app-inventory-cache.ts
11
- /**
12
- * Process-local cache for Codex app-server app inventories, keyed by runtime
13
- * identity and safe to refresh in the background.
14
- */
15
- /** Default app inventory cache freshness window. */
16
- const CODEX_APP_INVENTORY_CACHE_TTL_MS = 3600 * 1e3;
17
- const CODEX_APP_READ_BATCH_LIMIT = 100;
18
- const MAX_SERIALIZED_ERROR_MESSAGE_LENGTH = 500;
19
- /** In-memory app inventory cache with coalesced refreshes per key. */
20
- var CodexAppInventoryCache = class {
21
- constructor(options = {}) {
22
- this.entries = /* @__PURE__ */ new Map();
23
- this.inFlight = /* @__PURE__ */ new Map();
24
- this.refreshTokens = /* @__PURE__ */ new Map();
25
- this.diagnostics = /* @__PURE__ */ new Map();
26
- this.revision = 0;
27
- this.ttlMs = options.ttlMs ?? CODEX_APP_INVENTORY_CACHE_TTL_MS;
28
- }
29
- /** Reads a snapshot and schedules refresh when missing, stale, or forced. */
30
- read(params) {
31
- const nowMs = resolveDateTimestampMs(params.nowMs);
32
- const entry = this.entries.get(params.key);
33
- if (!entry) {
34
- const refreshScheduled = params.suppressRefresh ? false : this.scheduleRefresh(params);
35
- return {
36
- state: "missing",
37
- key: params.key,
38
- revision: this.revision,
39
- refreshScheduled,
40
- ...this.diagnostics.get(params.key) ? { diagnostic: this.diagnostics.get(params.key) } : {}
41
- };
42
- }
43
- const state = entry.invalidated || !isFutureDateTimestampMs(entry.expiresAtMs, { nowMs }) ? "stale" : "fresh";
44
- const refreshScheduled = state === "fresh" && !params.forceRefetch ? false : this.scheduleRefresh(params);
45
- return {
46
- state,
47
- key: params.key,
48
- revision: entry.revision,
49
- snapshot: stripEntryState(entry),
50
- refreshScheduled,
51
- ...entry.lastError ? { diagnostic: entry.lastError } : {}
52
- };
53
- }
54
- /** Forces or joins an immediate refresh for a cache key. */
55
- refreshNow(params) {
56
- return this.refresh(params);
57
- }
58
- /**
59
- * Marks a key stale and records the reason as a diagnostic. A scope names
60
- * the app ids the invalidation concerns so a covering targeted refresh can
61
- * clear it; without one, only a complete refresh revalidates the entry.
62
- */
63
- invalidate(key, reason, nowMs = Date.now(), invalidatedAppIds) {
64
- this.revision += 1;
65
- this.refreshTokens.set(key, (this.refreshTokens.get(key) ?? 0) + 1);
66
- this.inFlight.delete(key);
67
- const diagnostic = {
68
- message: reason,
69
- atMs: nowMs
70
- };
71
- const entry = this.entries.get(key);
72
- if (entry) {
73
- const scope = invalidatedAppIds?.filter(Boolean) ?? [];
74
- if (!entry.invalidated) entry.invalidatedAppIds = scope.length ? [...scope].toSorted() : void 0;
75
- else if (entry.invalidatedAppIds && scope.length) entry.invalidatedAppIds = Array.from(/* @__PURE__ */ new Set([...entry.invalidatedAppIds, ...scope])).toSorted();
76
- else entry.invalidatedAppIds = void 0;
77
- entry.invalidated = true;
78
- entry.lastError = diagnostic;
79
- entry.revision = this.revision;
80
- } else this.diagnostics.set(key, diagnostic);
81
- return this.revision;
82
- }
83
- /** Clears all cached snapshots, diagnostics, in-flight requests, and revision state. */
84
- clear() {
85
- this.entries.clear();
86
- this.inFlight.clear();
87
- this.refreshTokens.clear();
88
- this.diagnostics.clear();
89
- this.revision = 0;
90
- }
91
- /** Returns the monotonically increasing cache revision. */
92
- getRevision() {
93
- return this.revision;
94
- }
95
- scheduleRefresh(params) {
96
- const existing = this.inFlight.get(params.key);
97
- if (existing && !params.forceRefetch && doesInFlightRefreshCover(existing, params)) return true;
98
- this.refresh(params).catch(() => void 0);
99
- return true;
100
- }
101
- async refresh(params) {
102
- const existing = this.inFlight.get(params.key);
103
- if (existing && !params.forceRefetch && doesInFlightRefreshCover(existing, params)) return existing.promise;
104
- const refreshToken = (this.refreshTokens.get(params.key) ?? 0) + 1;
105
- this.refreshTokens.set(params.key, refreshToken);
106
- const previousRefresh = params.forceRefetch ? void 0 : existing?.promise;
107
- const promise = this.refreshUncoalesced(params, refreshToken, previousRefresh);
108
- const currentRefresh = {
109
- promise,
110
- targetAppIds: new Set(params.targetAppIds?.filter(Boolean) ?? [])
111
- };
112
- this.inFlight.set(params.key, currentRefresh);
113
- try {
114
- return await promise;
115
- } finally {
116
- if (this.inFlight.get(params.key) === currentRefresh) this.inFlight.delete(params.key);
117
- }
118
- }
119
- async refreshUncoalesced(params, refreshToken, previousRefresh) {
120
- const nowMs = resolveDateTimestampMs(params.nowMs);
121
- try {
122
- let previousRefreshSucceeded = false;
123
- if (previousRefresh) try {
124
- await previousRefresh;
125
- previousRefreshSucceeded = true;
126
- } catch {}
127
- const inventory = await readInstalledApps(params.request, {
128
- forceRefresh: params.forceRefetch === true || !this.entries.has(params.key) && !previousRefreshSucceeded,
129
- targetAppIds: params.targetAppIds
130
- });
131
- this.revision += 1;
132
- const expiresAtMs = resolveExpiresAtMsFromDurationMs(this.ttlMs, { nowMs }) ?? 0;
133
- const snapshot = {
134
- key: params.key,
135
- apps: inventory.apps,
136
- installedApps: inventory.installedApps,
137
- ...params.targetAppIds?.some(Boolean) ? { targetAppIds: Array.from(new Set(params.targetAppIds.filter(Boolean))).toSorted() } : {},
138
- fetchedAtMs: nowMs,
139
- expiresAtMs,
140
- revision: this.revision
141
- };
142
- if (this.refreshTokens.get(params.key) === refreshToken) {
143
- const existingEntry = this.entries.get(params.key);
144
- const published = resolvePublishedInventorySnapshot(existingEntry, snapshot, nowMs);
145
- const remaining = resolveRemainingInvalidationScope(existingEntry, snapshot);
146
- this.entries.set(params.key, {
147
- ...published,
148
- ...remaining,
149
- ...remaining.invalidated && existingEntry?.lastError ? { lastError: existingEntry.lastError } : {}
150
- });
151
- this.diagnostics.delete(params.key);
152
- }
153
- return snapshot;
154
- } catch (error) {
155
- const diagnostic = {
156
- message: sanitizeErrorMessage(error instanceof Error ? error.message : String(error)),
157
- atMs: nowMs
158
- };
159
- this.diagnostics.set(params.key, diagnostic);
160
- const entry = this.entries.get(params.key);
161
- if (entry) entry.lastError = diagnostic;
162
- embeddedAgentLog.warn("codex app inventory refresh failed", {
163
- forceRefetch: params.forceRefetch === true,
164
- keyFingerprint: fingerprintInventoryCacheKey(params.key),
165
- error: serializeCodexAppInventoryError(error)
166
- });
167
- throw error;
168
- }
169
- }
170
- };
171
- /**
172
- * Publish policy for refreshed snapshots. A complete refresh replaces the
173
- * entry, but a targeted refresh only rewrites its own target rows in place —
174
- * replacing the whole entry with a narrow snapshot makes agents that share
175
- * the runtime identity see each other's plugin apps vanish and force a hosted
176
- * connector refresh per turn. The refreshed snapshot stays authoritative for
177
- * its target set, so target rows it no longer returns are deleted.
178
- */
179
- function resolvePublishedInventorySnapshot(existing, snapshot, nowMs) {
180
- if (!snapshot.targetAppIds?.length || !existing) return snapshot;
181
- if (!isFutureDateTimestampMs(existing.expiresAtMs, { nowMs })) return snapshot;
182
- const refreshedTargetIds = new Set(snapshot.targetAppIds);
183
- const { targetAppIds: snapshotTargetAppIds, ...snapshotBase } = snapshot;
184
- return {
185
- ...snapshotBase,
186
- fetchedAtMs: existing.fetchedAtMs,
187
- expiresAtMs: existing.expiresAtMs,
188
- apps: mergeRefreshedRows(existing.apps, snapshot.apps, refreshedTargetIds),
189
- installedApps: mergeRefreshedRows(existing.installedApps, snapshot.installedApps, refreshedTargetIds),
190
- ...existing.targetAppIds?.length ? { targetAppIds: Array.from(/* @__PURE__ */ new Set([...existing.targetAppIds, ...snapshotTargetAppIds])).toSorted() } : {}
191
- };
192
- }
193
- /** Replaces refreshed target rows in place, deletes vanished ones, appends new ones. */
194
- function mergeRefreshedRows(existingRows, refreshedRows, refreshedTargetIds) {
195
- const refreshedById = new Map(refreshedRows.map((row) => [row.id, row]));
196
- const existingIds = new Set(existingRows.map((row) => row.id));
197
- return [...existingRows.flatMap((row) => {
198
- if (!refreshedTargetIds.has(row.id)) return [row];
199
- const refreshed = refreshedById.get(row.id);
200
- return refreshed ? [refreshed] : [];
201
- }), ...refreshedRows.filter((row) => !existingIds.has(row.id))];
202
- }
203
- /**
204
- * A refresh retires exactly the invalidation scope it re-read: a complete
205
- * refresh clears everything; a targeted one subtracts its target ids so
206
- * separate covering refreshes accumulate until no scope remains. Unscoped
207
- * invalidations require a complete refresh.
208
- */
209
- function resolveRemainingInvalidationScope(existing, snapshot) {
210
- if (!existing?.invalidated || !snapshot.targetAppIds?.length) return { invalidated: false };
211
- if (!existing.invalidatedAppIds) return { invalidated: true };
212
- const refreshedTargetIds = new Set(snapshot.targetAppIds);
213
- const remaining = existing.invalidatedAppIds.filter((appId) => !refreshedTargetIds.has(appId));
214
- return remaining.length > 0 ? {
215
- invalidated: true,
216
- invalidatedAppIds: remaining
217
- } : { invalidated: false };
218
- }
219
- function doesInFlightRefreshCover(existing, params) {
220
- if (existing.targetAppIds.size === 0) return true;
221
- const requestedAppIds = new Set(params.targetAppIds?.filter(Boolean) ?? []);
222
- return requestedAppIds.size > 0 && Array.from(requestedAppIds).every((appId) => existing.targetAppIds.has(appId));
223
- }
224
- /** Serializes a refresh failure without leaking large or sensitive error data. */
225
- function serializeCodexAppInventoryError(error) {
226
- const record = isRecord(error) ? error : void 0;
227
- const data = record && "data" in record ? redactErrorData(record.data) : void 0;
228
- return {
229
- name: error instanceof Error ? error.name : typeof record?.name === "string" ? record.name : void 0,
230
- message: sanitizeErrorMessage(error instanceof Error ? error.message : String(error)),
231
- ...typeof record?.code === "number" ? { code: record.code } : {},
232
- ...data !== void 0 ? { data } : {}
233
- };
234
- }
235
- /** Shared app inventory cache used by Codex app-server runtime paths. */
236
- const defaultCodexAppInventoryCache = new CodexAppInventoryCache();
237
- /** Builds a stable cache key from build versions and runtime identity fields. */
238
- function buildCodexAppInventoryCacheKey(input, openClawVersion, codexPluginVersion) {
239
- return JSON.stringify({
240
- openClawVersion,
241
- codexPluginVersion,
242
- codexHome: input.codexHome ?? null,
243
- endpoint: input.endpoint ?? null,
244
- runtimeIdentity: normalizeRuntimeIdentityForCacheKey(input.runtimeIdentity),
245
- authProfileId: input.authProfileId ?? null,
246
- accountId: input.accountId ?? null,
247
- envApiKeyFingerprint: input.envApiKeyFingerprint ?? null,
248
- appServerVersion: input.appServerVersion ?? null
249
- });
250
- }
251
- function normalizeRuntimeIdentityForCacheKey(value) {
252
- if (!value) return null;
253
- const entries = Object.entries(value).flatMap(([key, rawValue]) => {
254
- const normalized = rawValue?.trim();
255
- return normalized ? [[key, normalized]] : [];
256
- }).toSorted(([left], [right]) => left.localeCompare(right));
257
- return entries.length > 0 ? Object.fromEntries(entries) : null;
258
- }
259
- async function readInstalledApps(request, options) {
260
- const installed = await request("app/installed", { forceRefresh: options.forceRefresh });
261
- const targetIds = new Set((options.targetAppIds ?? []).filter(Boolean));
262
- const apps = targetIds.size === 0 ? installed.apps : installed.apps.filter((app) => targetIds.has(app.id));
263
- if (apps.length === 0) return {
264
- apps: [],
265
- installedApps: []
266
- };
267
- const metadataResponses = await Promise.all(Array.from({ length: Math.ceil(apps.length / CODEX_APP_READ_BATCH_LIMIT) }, (_, index) => request("app/read", { appIds: apps.slice(index * CODEX_APP_READ_BATCH_LIMIT, (index + 1) * CODEX_APP_READ_BATCH_LIMIT).map((app) => app.id) })));
268
- const metadataById = new Map(metadataResponses.flatMap((response) => response.apps).map((metadata) => [metadata.id, metadata]));
269
- return {
270
- apps: apps.flatMap((installedApp) => {
271
- const metadata = metadataById.get(installedApp.id);
272
- if (!metadata) return [];
273
- return [{
274
- id: installedApp.id,
275
- name: metadata.name,
276
- description: metadata.description ?? null,
277
- logoUrl: metadata.iconUrl ?? null,
278
- logoUrlDark: metadata.iconUrlDark ?? null,
279
- distributionChannel: metadata.distributionChannel ?? null,
280
- branding: null,
281
- appMetadata: null,
282
- labels: null,
283
- installUrl: metadata.installUrl ?? null,
284
- isAccessible: true,
285
- isEnabled: installedApp.enabled,
286
- pluginDisplayNames: metadata.pluginDisplayNames
287
- }];
288
- }),
289
- installedApps: apps
290
- };
291
- }
292
- function stripEntryState(entry) {
293
- const { invalidated: _invalidated, invalidatedAppIds: _invalidatedAppIds, ...snapshot } = entry;
294
- return snapshot;
295
- }
296
- function fingerprintInventoryCacheKey(key) {
297
- let hash = 0;
298
- for (let index = 0; index < key.length; index += 1) hash = hash * 31 + key.charCodeAt(index) >>> 0;
299
- return hash.toString(16).padStart(8, "0");
300
- }
301
- function truncateSerializedErrorText(value) {
302
- return value.length > MAX_SERIALIZED_ERROR_MESSAGE_LENGTH ? `${truncateUtf16Safe(value, MAX_SERIALIZED_ERROR_MESSAGE_LENGTH)}...` : value;
303
- }
304
- function redactErrorData(value, depth = 0) {
305
- if (value === void 0) return;
306
- if (value === null || typeof value === "boolean" || typeof value === "number") return value;
307
- if (depth > 6) return "[truncated]";
308
- if (Array.isArray(value)) return value.map((entry) => redactErrorData(entry, depth + 1) ?? null);
309
- if (isRecord(value)) {
310
- const redacted = {};
311
- for (const [key, entry] of Object.entries(value)) redacted[key] = isSensitiveErrorDataKey(key) ? "<redacted>" : redactErrorData(entry, depth + 1) ?? null;
312
- return redacted;
313
- }
314
- if (typeof value === "string") return truncateSerializedErrorText(value);
315
- if (typeof value === "bigint") return value.toString();
316
- if (typeof value === "symbol") return value.description ? `Symbol(${value.description})` : "Symbol()";
317
- if (typeof value === "function") return value.name ? `[function ${value.name}]` : "[function]";
318
- return "[unserializable]";
319
- }
320
- function sanitizeErrorMessage(message) {
321
- const htmlStart = message.search(/<html[\s>]/i);
322
- return truncateSerializedErrorText((htmlStart >= 0 ? `${message.slice(0, htmlStart).trimEnd()} [HTML response body omitted]` : message).replace(/([?&][^=\s"'<>]*(?:api[_-]?key|authorization|cookie|credential|password|secret|token|tk)[^=\s"'<>]*=)[^&\s"'<>]+/gi, "$1<redacted>"));
323
- }
324
- function isSensitiveErrorDataKey(key) {
325
- return /api[_-]?key|authorization|cookie|credential|password|secret|token/i.test(key);
326
- }
327
- //#endregion
328
- //#region extensions/codex/src/app-server/plugin-app-cache-key.ts
329
- /**
330
- * Builds stable Codex plugin/app inventory cache keys from app-server startup,
331
- * auth, account, and version inputs without storing secret material.
332
- */
333
- const CODEX_PLUGIN_VERSION = readPluginPackageVersion({ require: createRequire(import.meta.url) });
334
- /** Builds the full app inventory cache key for Codex plugin/app discovery. */
335
- function buildCodexPluginAppCacheKey(params) {
336
- return buildCodexAppInventoryCacheKey({
337
- codexHome: params.runtimeIdentity?.codexHome ?? resolveCodexPluginAppCacheCodexHome(params.appServer, params.agentDir),
338
- endpoint: resolveCodexPluginAppCacheEndpoint(params.appServer),
339
- authProfileId: params.authProfileId,
340
- accountId: params.accountId,
341
- envApiKeyFingerprint: params.envApiKeyFingerprint,
342
- appServerVersion: params.appServerVersion ?? params.runtimeIdentity?.serverVersion,
343
- runtimeIdentity: params.runtimeIdentity
344
- }, OPENCLAW_VERSION, CODEX_PLUGIN_VERSION);
345
- }
346
- /** Builds a durable thread-binding fingerprint for one initialized app-server runtime. */
347
- function buildCodexAppServerRuntimeFingerprint(params) {
348
- return JSON.stringify({
349
- endpoint: resolveCodexPluginAppCacheEndpoint(params.appServer),
350
- connectionClass: params.appServer.connectionClass,
351
- remoteWorkspaceRoot: params.appServer.remoteWorkspaceRoot ?? null,
352
- appServerVersion: params.appServerVersion ?? params.runtimeIdentity?.serverVersion ?? null,
353
- runtimeIdentity: params.runtimeIdentity ?? null
354
- });
355
- }
356
- /** Fingerprints the configured connection that owns a supervised source thread. */
357
- function buildCodexAppServerConnectionFingerprint(appServer, agentDir) {
358
- return JSON.stringify({
359
- endpoint: resolveCodexPluginAppCacheEndpoint(appServer),
360
- connectionClass: appServer.connectionClass,
361
- remoteWorkspaceRoot: appServer.remoteWorkspaceRoot ?? null,
362
- homeScope: appServer.start.homeScope ?? null,
363
- codexHome: resolveCodexAppServerConnectionHome(appServer.start, agentDir),
364
- cwd: appServer.start.cwd ?? null
365
- });
366
- }
367
- function resolveCodexAppServerConnectionHome(start, agentDir) {
368
- const configured = start.env?.CODEX_HOME?.trim();
369
- if (configured) return configured;
370
- if (start.transport === "unix" && (!start.url || start.url === "unix://")) return resolveCodexAppServerUserHomeDir(start.env ?? process.env);
371
- if (start.transport !== "stdio") return null;
372
- if (start.homeScope === "user") return resolveCodexAppServerUserHomeDir(process.env);
373
- return agentDir ? resolveCodexAppServerHomeDir(agentDir) : null;
374
- }
375
- /** Serializes app-server endpoint identity, including credential fingerprints. */
376
- function resolveCodexPluginAppCacheEndpoint(appServer) {
377
- return JSON.stringify({
378
- transport: appServer.start.transport,
379
- command: appServer.start.command,
380
- args: appServer.start.args,
381
- url: appServer.start.url ?? null,
382
- credentialFingerprint: fingerprintCodexPluginAppCacheCredentials(appServer.start)
383
- });
384
- }
385
- /** Resolves the CODEX_HOME value that scopes local app-server inventory. */
386
- function resolveCodexPluginAppCacheCodexHome(appServer, agentDir) {
387
- const configuredCodexHome = appServer.start.env?.CODEX_HOME?.trim();
388
- if (configuredCodexHome) return configuredCodexHome;
389
- return appServer.start.transport === "stdio" && agentDir ? resolveCodexAppServerHomeDir(agentDir) : void 0;
390
- }
391
- function fingerprintCodexPluginAppCacheCredentials(startOptions) {
392
- const authToken = startOptions.authToken ?? "";
393
- const headers = Object.entries(startOptions.headers).map(([key, value]) => [key.toLowerCase(), value]).toSorted(([left], [right]) => left.localeCompare(right));
394
- if (!authToken && headers.length === 0) return null;
395
- const hash = createHash("sha256");
396
- hash.update("openclaw:codex:plugin-app-cache-credentials:v1");
397
- hash.update("\0");
398
- hash.update(authToken);
399
- for (const [key, value] of headers) {
400
- hash.update("\0");
401
- hash.update(key);
402
- hash.update("\0");
403
- hash.update(value);
404
- }
405
- return `sha256:${hash.digest("hex")}`;
406
- }
407
- //#endregion
408
- export { serializeCodexAppInventoryError as a, defaultCodexAppInventoryCache as i, buildCodexAppServerRuntimeFingerprint as n, buildCodexPluginAppCacheKey as r, buildCodexAppServerConnectionFingerprint as t };
@@ -1,157 +0,0 @@
1
- import { a as getLeasedSharedCodexAppServerClient, g as withTimeout, i as createIsolatedCodexAppServerClient, l as releaseLeasedSharedCodexAppServerClient, p as retireSharedCodexAppServerClientIfCurrent, s as isCodexAppServerStartSelectionChangedError } from "./shared-client-DTbvH-XV.js";
2
- import { t as resolveCodexAppServerDirectSandboxBypassBlock } from "./sandbox-guard-NuhpXmPB.js";
3
- //#region extensions/codex/src/app-server/request.ts
4
- /** Sends one guarded request over a client lease owned by the caller. */
5
- async function requestCodexAppServerClientJson(params) {
6
- const sandboxBlock = resolveCodexAppServerDirectSandboxBypassBlock({
7
- method: params.method,
8
- requestParams: params.requestParams,
9
- config: params.config,
10
- sessionKey: params.sessionKey,
11
- sessionId: params.sessionId
12
- });
13
- if (sandboxBlock) throw new Error(sandboxBlock);
14
- const timeoutMs = params.timeoutMs ?? 6e4;
15
- return await withTimeout(params.client.request(params.method, params.requestParams, { timeoutMs }), timeoutMs, `codex app-server ${params.method} timed out`);
16
- }
17
- async function requestCodexAppServerJson(params) {
18
- const sandboxBlock = resolveCodexAppServerDirectSandboxBypassBlock({
19
- method: params.method,
20
- requestParams: params.requestParams,
21
- config: params.config,
22
- sessionKey: params.sessionKey,
23
- sessionId: params.sessionId
24
- });
25
- if (sandboxBlock) throw new Error(sandboxBlock);
26
- return await withCodexAppServerJsonClient({
27
- ...params,
28
- timeoutMessage: `codex app-server ${params.method} timed out`
29
- }, async (request) => await request({
30
- method: params.method,
31
- requestParams: params.requestParams
32
- }));
33
- }
34
- const CODEX_USAGE_ISOLATED_SHUTDOWN = {
35
- forceKillDelayMs: 200,
36
- exitTimeoutMs: 300
37
- };
38
- const CODEX_ACCOUNT_READ_MAX_TIMEOUT_MS = 4e3;
39
- const CODEX_USAGE_DEADLINE_RESERVE_MS = CODEX_USAGE_ISOLATED_SHUTDOWN.forceKillDelayMs + CODEX_USAGE_ISOLATED_SHUTDOWN.exitTimeoutMs + 250;
40
- /** Reads rate limits and best-effort account identity from one isolated app-server session. */
41
- async function readCodexAppServerUsage(options) {
42
- const deadline = Date.now() + options.timeoutMs;
43
- return await withCodexAppServerJsonClient({
44
- timeoutMs: options.timeoutMs,
45
- timeoutMessage: "codex app-server usage read timed out",
46
- agentDir: options.agentDir,
47
- ...options.authProfileId ? { authProfileId: options.authProfileId } : {},
48
- config: options.config,
49
- startOptions: options.startOptions,
50
- isolated: true,
51
- isolatedShutdown: CODEX_USAGE_ISOLATED_SHUTDOWN
52
- }, async (request) => {
53
- const rateLimits = await request({ method: "account/rateLimits/read" });
54
- const accountEmail = await readCodexAccountEmailBestEffort(request, deadline);
55
- return {
56
- rateLimits,
57
- ...accountEmail ? { accountEmail } : {}
58
- };
59
- });
60
- }
61
- function extractCodexAccountEmail(value) {
62
- if (!value || typeof value !== "object") return;
63
- const record = value;
64
- const account = record.account && typeof record.account === "object" ? record.account : record;
65
- const email = account.email ?? account.accountEmail;
66
- return typeof email === "string" && email.trim() ? email.trim() : void 0;
67
- }
68
- async function readCodexAccountEmailBestEffort(request, deadline) {
69
- const boundMs = Math.min(CODEX_ACCOUNT_READ_MAX_TIMEOUT_MS, deadline - Date.now() - CODEX_USAGE_DEADLINE_RESERVE_MS);
70
- if (boundMs <= 0) return;
71
- const read = request({
72
- method: "account/read",
73
- requestParams: {}
74
- }).then((account) => extractCodexAccountEmail(account), () => void 0);
75
- let timer;
76
- const timeout = new Promise((resolve) => {
77
- timer = setTimeout(() => resolve(void 0), boundMs);
78
- timer.unref?.();
79
- });
80
- try {
81
- return await Promise.race([read, timeout]);
82
- } finally {
83
- if (timer) clearTimeout(timer);
84
- }
85
- }
86
- /**
87
- * Runs several guarded requests over one acquired client (shared lease or
88
- * isolated child) so related reads see the same app-server session. The whole
89
- * callback re-runs once when the client's start selection changed underneath it.
90
- */
91
- async function withCodexAppServerJsonClient(params, run) {
92
- const timeoutMs = params.timeoutMs ?? 6e4;
93
- const timeoutMessage = params.timeoutMessage ?? "codex app-server request timed out";
94
- const timeoutController = new AbortController();
95
- const deadline = Number.isFinite(timeoutMs) && timeoutMs > 0 ? Date.now() + timeoutMs : void 0;
96
- const isPastDeadline = () => deadline !== void 0 && Date.now() >= deadline;
97
- const throwIfAbandoned = () => {
98
- if (timeoutController.signal.aborted || isPastDeadline()) throw new Error(timeoutMessage);
99
- };
100
- const remainingTimeoutMs = () => {
101
- throwIfAbandoned();
102
- return deadline === void 0 ? timeoutMs : Math.max(1, deadline - Date.now());
103
- };
104
- try {
105
- return await withTimeout((async () => {
106
- for (let attempt = 0; attempt < 2; attempt += 1) {
107
- throwIfAbandoned();
108
- const client = await (params.isolated ? createIsolatedCodexAppServerClient : getLeasedSharedCodexAppServerClient)({
109
- startOptions: params.startOptions,
110
- pluginConfig: params.pluginConfig,
111
- timeoutMs: remainingTimeoutMs(),
112
- authProfileId: params.authProfileId,
113
- agentDir: params.agentDir,
114
- config: params.config,
115
- abandonSignal: timeoutController.signal
116
- });
117
- try {
118
- throwIfAbandoned();
119
- const scopedRequest = async (request) => {
120
- const sandboxBlock = resolveCodexAppServerDirectSandboxBypassBlock({
121
- method: request.method,
122
- requestParams: request.requestParams,
123
- config: params.config,
124
- sessionKey: params.sessionKey,
125
- sessionId: params.sessionId
126
- });
127
- if (sandboxBlock) throw new Error(sandboxBlock);
128
- throwIfAbandoned();
129
- return await client.request(request.method, request.requestParams, {
130
- timeoutMs: remainingTimeoutMs(),
131
- signal: timeoutController.signal
132
- });
133
- };
134
- return await run(scopedRequest);
135
- } catch (error) {
136
- if (!isCodexAppServerStartSelectionChangedError(error) || attempt > 0) throw error;
137
- if (!params.isolated) retireSharedCodexAppServerClientIfCurrent(client);
138
- throwIfAbandoned();
139
- } finally {
140
- if (params.isolated) await client.closeAndWait({
141
- exitTimeoutMs: params.isolatedShutdown?.exitTimeoutMs ?? 2e3,
142
- forceKillDelayMs: params.isolatedShutdown?.forceKillDelayMs ?? 250
143
- });
144
- else releaseLeasedSharedCodexAppServerClient(client);
145
- }
146
- }
147
- throw new Error("Codex app-server selection retry loop exited unexpectedly");
148
- })(), timeoutMs, timeoutMessage);
149
- } catch (error) {
150
- if (isPastDeadline()) throw new Error(timeoutMessage, { cause: error });
151
- throw error;
152
- } finally {
153
- timeoutController.abort();
154
- }
155
- }
156
- //#endregion
157
- export { withCodexAppServerJsonClient as i, requestCodexAppServerClientJson as n, requestCodexAppServerJson as r, readCodexAppServerUsage as t };