@openclaw/codex 2026.7.2-beta.7 → 2026.8.1-beta.3

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 (68) hide show
  1. package/README.md +2 -0
  2. package/dist/api.js +147 -0
  3. package/dist/app-server-policy-bg5QPSVP.js +25 -0
  4. package/dist/attempt-client-cleanup-URjUlCHg.js +735 -0
  5. package/dist/binding-connection-DAvZwp96.js +45 -0
  6. package/dist/{bounded-turn-D2ZAgZVz.js → bounded-turn-4BjrZEwW.js} +63 -56
  7. package/dist/{capabilities-BFDTVYr4.js → capabilities-CH3K57v4.js} +8 -2
  8. package/dist/cli-metadata.js +1 -1
  9. package/dist/{command-formatters-C336eRVS.js → command-formatters-D0nZ3qtd.js} +18 -18
  10. package/dist/{command-handlers-DAHUSry9.js → command-handlers-DC86lgT4.js} +507 -101
  11. package/dist/command-rpc-xUIIonsO.js +90 -0
  12. package/dist/{compact-D_uvHurS.js → compact-COqgBRny.js} +234 -214
  13. package/dist/{session-binding-BXpo9ymA.js → config-CpNeo5AE.js} +284 -1163
  14. package/dist/context-compaction-activity-BOeJf7yo.js +58 -0
  15. package/dist/{conversation-binding-data-BHRpYbX3.js → conversation-binding-data-CW2GuupV.js} +6 -10
  16. package/dist/doctor-contract-api.js +48 -50
  17. package/dist/{dynamic-tools-D2gYkSBO.js → dynamic-tools-fJZhl4CE.js} +3442 -1433
  18. package/dist/{effective-mcp-catalog-Bbd98Inw.js → effective-mcp-catalog-4YKn51aG.js} +20 -15
  19. package/dist/elicitation-input-DMkeki8d.js +71 -0
  20. package/dist/{event-projector-assistant-message-DTgnPPVF.js → event-projector-assistant-message-BwxV4d6N.js} +11 -23
  21. package/dist/{attempt-notifications-AP-a-Q5k.js → event-projector-usage-CLwNEJqW.js} +113 -29
  22. package/dist/harness-DoKQcF8n.js +258 -0
  23. package/dist/harness.js +2 -160
  24. package/dist/image-payload-sanitizer-CnfoUPCE.js +65 -0
  25. package/dist/index.js +730 -256
  26. package/dist/isolated-completion-DPMtlH9r.js +75 -0
  27. package/dist/local-runtime-attribution-B_2mnqhb.js +19 -0
  28. package/dist/managed-binary-By4FZC6i.js +212 -0
  29. package/dist/media-understanding-provider.js +5 -5
  30. package/dist/model-catalog-CmGoqVKB.js +48 -0
  31. package/dist/{models-BBMKU4jA.js → models-CZw1wClT.js} +12 -17
  32. package/dist/native-subagent-monitor-GGq3RnOo.js +3225 -0
  33. package/dist/node-exec-server.runtime-Bsu1LdFZ.js +192 -0
  34. package/dist/{plugin-app-cache-key-DztPafOA.js → plugin-app-cache-key-DMNQ8Zi8.js} +18 -6
  35. package/dist/plugin-approval-roundtrip-C75Yiiwc.js +95 -0
  36. package/dist/plugin-marketplace-discovery-CSWDkMrP.js +399 -0
  37. package/dist/{computer-use-CYEc8U3w.js → plugin-metadata-cache-BXH5NF-4.js} +109 -6
  38. package/dist/protocol-validators-VAVyEnDp.js +2399 -0
  39. package/dist/{rate-limits-CU-gVCCS.js → rate-limits-BI1dMHDG.js} +17 -35
  40. package/dist/{request-qKh331yu.js → request-DSK0W6YI.js} +3 -3
  41. package/dist/{run-attempt-CY9WlDLc.js → run-attempt-BV3HzuCf.js} +3416 -7194
  42. package/dist/{runtime-artifact-CmtG_t1L.js → runtime-artifact-BvyT1uyd.js} +11 -29
  43. package/dist/{sandbox-guard-NuhpXmPB.js → sandbox-guard-C1qEeZ5C.js} +29 -30
  44. package/dist/session-binding-BTrLf9Qm.js +874 -0
  45. package/dist/{session-catalog-DyOgR4WH.js → session-catalog-ezP_UcRM.js} +1584 -1289
  46. package/dist/session-catalog-home-id-BNwAJ9D7.js +18 -0
  47. package/dist/{session-cli-2PZaFLRh.js → session-cli-B1hKvfkI.js} +20 -7
  48. package/dist/session-retirement-CE4iMiLh.js +36 -0
  49. package/dist/{session-upstream-marker-B6U7tLw5.js → session-upstream-marker-D_2npHlA.js} +1 -1
  50. package/dist/{settled-turn-finalizer-CXY2Z9dT.js → settled-turn-finalizer-Dx1onIqg.js} +40 -28
  51. package/dist/{shared-client-DTbvH-XV.js → shared-client-Dw-rzii0.js} +1315 -469
  52. package/dist/{side-question-_ulBk1AL.js → side-question-DbXkJZzg.js} +140 -69
  53. package/dist/{thread-lifecycle-DF53ogiA.js → thread-lifecycle-DKdrnTMX.js} +927 -768
  54. package/dist/thread-ownership-i2NBwDUL.js +92 -0
  55. package/dist/thread-resume-CdJk2Ehf.js +30 -0
  56. package/dist/transcript-mirror-BU0_LKAL.js +588 -0
  57. package/dist/{transport-stdio-DXgGZ7Ib.js → transport-stdio-DhoGy33Z.js} +13 -2
  58. package/dist/upstream-prompt-provenance-CFmsKwr9.js +39 -0
  59. package/dist/{upstream-session-fork-Dy4Xvuoj.js → upstream-session-fork-BDVJCLAD.js} +14 -8
  60. package/dist/{usage-CQ6GhD5-.js → usage-9dKJCgcy.js} +3 -3
  61. package/dist/{web-search-provider.runtime-CCFhg2z5.js → web-search-provider.runtime-DCdx4DGu.js} +8 -9
  62. package/openclaw.plugin.json +49 -4
  63. package/package.json +6 -5
  64. package/dist/app-server-policy-BSaO2JIT.js +0 -49
  65. package/dist/conversation-control-xsIeXbo4.js +0 -287
  66. package/dist/event-projector-usage-Xp4AlR2k.js +0 -86
  67. package/dist/notification-correlation-CU6_AnOb.js +0 -67
  68. package/dist/transcript-mirror-DzsdNCf5.js +0 -6924
@@ -0,0 +1,399 @@
1
+ import { M as isCodexFastServiceTier } from "./config-CpNeo5AE.js";
2
+ import { a as getLeasedSharedCodexAppServerClient, l as releaseLeasedSharedCodexAppServerClient } from "./shared-client-Dw-rzii0.js";
3
+ import { o as isCodexAppServerNativeAuthProfile, r as bindingStoreKey, s as normalizeCodexAppServerBindingModelProvider } from "./session-binding-BTrLf9Qm.js";
4
+ import { _ as resolveCodexAppServerRequestModelSelection, y as resolveCodexBindingModelProviderFallback } from "./thread-lifecycle-DKdrnTMX.js";
5
+ import { r as formatCodexDisplayText } from "./command-formatters-D0nZ3qtd.js";
6
+ import { n as resolveCodexBindingAppServerConnection } from "./binding-connection-DAvZwp96.js";
7
+ import { asOptionalRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
8
+ import { resolveAgentDir } from "openclaw/plugin-sdk/agent-runtime";
9
+ import { getSessionEntry, patchSessionEntry, resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime";
10
+ import { ModelSelectionLockedError, applyModelOverrideWithAuthProfileCompatibility } from "openclaw/plugin-sdk/model-session-runtime";
11
+ //#region extensions/codex/src/command-authorization.ts
12
+ const CODEX_NATIVE_EXECUTION_AUTH_ERROR = "Only an owner or operator.admin can control Codex native execution.";
13
+ const CODEX_FULL_PERMISSIONS_AUTH_ERROR = "Full Codex permissions require operator.admin. Choose Admin in the Control UI permission picker, or use an admin-authenticated CLI.";
14
+ function hasCodexAdminScope(ctx) {
15
+ return ctx.gatewayClientScopes?.includes("operator.admin") === true;
16
+ }
17
+ function canMutateCodexHost(ctx) {
18
+ return ctx.senderIsOwner === true || hasCodexAdminScope(ctx);
19
+ }
20
+ //#endregion
21
+ //#region extensions/codex/src/conversation-control.ts
22
+ const CODEX_CONVERSATION_CONTROL_STATE = Symbol.for("openclaw.codex.conversationControl");
23
+ function getActiveTurns() {
24
+ const globalState = globalThis;
25
+ globalState[CODEX_CONVERSATION_CONTROL_STATE] ??= /* @__PURE__ */ new Map();
26
+ return globalState[CODEX_CONVERSATION_CONTROL_STATE];
27
+ }
28
+ function trackCodexConversationActiveTurn(active) {
29
+ const activeTurns = getActiveTurns();
30
+ const key = bindingStoreKey(active.identity);
31
+ activeTurns.set(key, active);
32
+ return () => {
33
+ if (activeTurns.get(key)?.turnId === active.turnId) activeTurns.delete(key);
34
+ };
35
+ }
36
+ function readCodexConversationActiveTurn(identity) {
37
+ return getActiveTurns().get(bindingStoreKey(identity));
38
+ }
39
+ async function stopCodexConversationTurn(params) {
40
+ const active = readCodexConversationActiveTurn(params.identity);
41
+ if (!active) return {
42
+ stopped: false,
43
+ message: "No active Codex run to stop."
44
+ };
45
+ const lookup = buildBindingLookup(params);
46
+ const binding = await params.bindingStore.read(params.identity);
47
+ if (binding?.threadId !== active.threadId) return {
48
+ stopped: false,
49
+ message: "The active Codex run no longer matches this session binding."
50
+ };
51
+ const connection = resolveCodexBindingAppServerConnection({
52
+ binding,
53
+ authProfileId: binding?.authProfileId,
54
+ pluginConfig: params.pluginConfig
55
+ });
56
+ const runtime = connection.appServer;
57
+ const client = active.client ?? await getLeasedSharedCodexAppServerClient({
58
+ startOptions: runtime.start,
59
+ timeoutMs: runtime.requestTimeoutMs,
60
+ authProfileId: connection.clientAuthProfileId,
61
+ ...lookup
62
+ });
63
+ try {
64
+ await client.request("turn/interrupt", {
65
+ threadId: active.threadId,
66
+ turnId: active.turnId
67
+ }, { timeoutMs: runtime.requestTimeoutMs });
68
+ } finally {
69
+ if (!active.client) releaseLeasedSharedCodexAppServerClient(client);
70
+ }
71
+ return {
72
+ stopped: true,
73
+ message: "Codex stop requested."
74
+ };
75
+ }
76
+ async function steerCodexConversationTurn(params) {
77
+ const active = readCodexConversationActiveTurn(params.identity);
78
+ const text = params.message.trim();
79
+ if (!text) return {
80
+ steered: false,
81
+ message: "Usage: /codex steer <message>"
82
+ };
83
+ if (!active) return {
84
+ steered: false,
85
+ message: "No active Codex run to steer."
86
+ };
87
+ const lookup = buildBindingLookup(params);
88
+ const binding = await params.bindingStore.read(params.identity);
89
+ if (binding?.threadId !== active.threadId) return {
90
+ steered: false,
91
+ message: "The active Codex run no longer matches this session binding."
92
+ };
93
+ const connection = resolveCodexBindingAppServerConnection({
94
+ binding,
95
+ authProfileId: binding?.authProfileId,
96
+ pluginConfig: params.pluginConfig
97
+ });
98
+ const runtime = connection.appServer;
99
+ const client = active.client ?? await getLeasedSharedCodexAppServerClient({
100
+ startOptions: runtime.start,
101
+ timeoutMs: runtime.requestTimeoutMs,
102
+ authProfileId: connection.clientAuthProfileId,
103
+ ...lookup
104
+ });
105
+ try {
106
+ await client.request("turn/steer", {
107
+ threadId: active.threadId,
108
+ expectedTurnId: active.turnId,
109
+ input: [{
110
+ type: "text",
111
+ text,
112
+ text_elements: []
113
+ }]
114
+ }, { timeoutMs: runtime.requestTimeoutMs });
115
+ } finally {
116
+ if (!active.client) releaseLeasedSharedCodexAppServerClient(client);
117
+ }
118
+ return {
119
+ steered: true,
120
+ message: "Sent steer message to Codex."
121
+ };
122
+ }
123
+ async function setCodexConversationModel(params) {
124
+ const model = params.model.trim();
125
+ if (!model) return "Usage: /codex model <model>";
126
+ const lookup = buildBindingLookup(params);
127
+ const binding = await requireThreadBinding(params.bindingStore, params.identity);
128
+ if (binding.connectionScope === "supervision") throw new ModelSelectionLockedError();
129
+ const modelSelection = resolveCodexAppServerRequestModelSelection({
130
+ model,
131
+ modelProvider: resolveConversationControlModelProvider({
132
+ authProfileId: binding.authProfileId,
133
+ bindingModel: binding.model,
134
+ bindingModelProvider: binding.modelProvider,
135
+ currentModel: model,
136
+ ...lookup
137
+ }),
138
+ authProfileId: binding.authProfileId,
139
+ ...lookup
140
+ });
141
+ const nextModelProvider = normalizeCodexAppServerBindingModelProvider({
142
+ authProfileId: binding.authProfileId,
143
+ modelProvider: modelSelection.modelProvider,
144
+ ...lookup
145
+ });
146
+ const nextModel = modelSelection.model;
147
+ const modelChanged = nextModel !== binding.model || nextModelProvider !== binding.modelProvider;
148
+ const session = params.session ?? (params.identity.kind === "session" && params.identity.sessionKey ? {
149
+ agentId: params.identity.agentId,
150
+ sessionId: params.identity.sessionId,
151
+ sessionKey: params.identity.sessionKey
152
+ } : void 0);
153
+ if (session) {
154
+ if (!await patchSessionEntry({
155
+ agentId: session.agentId,
156
+ storePath: resolveStorePath(params.config?.session?.store, { agentId: session.agentId }),
157
+ sessionKey: session.sessionKey,
158
+ requireWriteSuccess: true,
159
+ replaceEntry: true,
160
+ update: (entry) => {
161
+ if (entry.sessionId !== session.sessionId) throw new Error("Codex session changed while applying the model selection.");
162
+ applyModelOverrideWithAuthProfileCompatibility({
163
+ cfg: params.config ?? {},
164
+ agentDir: params.agentDir ?? resolveAgentDir(params.config ?? {}, session.agentId),
165
+ entry,
166
+ currentProvider: binding.modelProvider ?? "openai",
167
+ selection: {
168
+ provider: nextModelProvider ?? "openai",
169
+ model: nextModel
170
+ },
171
+ markLiveSwitchPending: true
172
+ });
173
+ return entry;
174
+ }
175
+ })) throw new Error("Codex session changed while applying the model selection.");
176
+ if (params.identity.kind === "conversation") await patchThreadBinding(params.bindingStore, params.identity, binding.threadId, {
177
+ model: nextModel,
178
+ modelProvider: nextModelProvider,
179
+ ...modelChanged && binding.contextEngine?.projection ? { contextEngine: {
180
+ ...binding.contextEngine,
181
+ projection: void 0
182
+ } } : {}
183
+ });
184
+ else if (modelChanged && binding.contextEngine?.projection) await patchThreadBinding(params.bindingStore, params.identity, binding.threadId, { contextEngine: {
185
+ ...binding.contextEngine,
186
+ projection: void 0
187
+ } });
188
+ } else await patchThreadBinding(params.bindingStore, params.identity, binding.threadId, {
189
+ model: nextModel,
190
+ modelProvider: nextModelProvider,
191
+ ...modelChanged && binding.contextEngine?.projection ? { contextEngine: {
192
+ ...binding.contextEngine,
193
+ projection: void 0
194
+ } } : {}
195
+ });
196
+ return `Codex model set to ${formatCodexDisplayText(nextModel)}.`;
197
+ }
198
+ async function setCodexConversationFastMode(params) {
199
+ const binding = await requireThreadBinding(params.bindingStore, params.identity);
200
+ if (params.enabled == null) return `Codex fast mode: ${isCodexFastServiceTier(binding.serviceTier) ? "on" : "off"}.`;
201
+ const serviceTier = params.enabled ? "priority" : "flex";
202
+ await patchThreadBinding(params.bindingStore, params.identity, binding.threadId, { serviceTier });
203
+ return `Codex fast mode ${params.enabled ? "enabled" : "disabled"}.`;
204
+ }
205
+ async function setCodexConversationPermissions(params) {
206
+ const storePath = resolveStorePath(params.config?.session?.store, { agentId: params.session.agentId });
207
+ if (!params.mode) {
208
+ const entry = getSessionEntry({
209
+ agentId: params.session.agentId,
210
+ hydrateSkillPromptRefs: false,
211
+ readConsistency: "latest",
212
+ sessionKey: params.session.sessionKey,
213
+ storePath
214
+ });
215
+ if (entry?.sessionId !== params.session.sessionId) throw new Error("Codex session changed while reading the permission mode.");
216
+ return `Codex permissions: ${formatPermissionsMode(entry.permissionMode)}.`;
217
+ }
218
+ if (!await patchSessionEntry({
219
+ agentId: params.session.agentId,
220
+ storePath,
221
+ sessionKey: params.session.sessionKey,
222
+ requireWriteSuccess: true,
223
+ replaceEntry: true,
224
+ update: (entry) => {
225
+ if (entry.sessionId !== params.session.sessionId) throw new Error("Codex session changed while applying the permission mode.");
226
+ if (params.mode === "yolo") entry.permissionMode = "full";
227
+ else delete entry.permissionMode;
228
+ return entry;
229
+ }
230
+ })) throw new Error("Codex session changed while applying the permission mode.");
231
+ return `Codex permissions set to ${params.mode === "yolo" ? "full access" : "default"}.`;
232
+ }
233
+ function parseCodexFastModeArg(arg) {
234
+ const normalized = arg?.trim().toLowerCase();
235
+ if (!normalized || normalized === "status") return;
236
+ if (normalized === "on" || normalized === "true" || normalized === "fast") return true;
237
+ if (normalized === "off" || normalized === "false" || normalized === "flex") return false;
238
+ }
239
+ function parseCodexPermissionsModeArg(arg) {
240
+ const normalized = arg?.trim().toLowerCase();
241
+ if (!normalized || normalized === "status") return;
242
+ if (normalized === "yolo" || normalized === "full" || normalized === "full-access") return "yolo";
243
+ if (normalized === "default" || normalized === "guardian") return "default";
244
+ }
245
+ function formatPermissionsMode(mode) {
246
+ return mode === "full" ? "full access" : "default";
247
+ }
248
+ async function requireThreadBinding(bindingStore, identity) {
249
+ const binding = await bindingStore.read(identity);
250
+ if (!binding?.threadId) throw new Error("No Codex thread is attached to this OpenClaw session yet.");
251
+ return binding;
252
+ }
253
+ async function patchThreadBinding(bindingStore, identity, threadId, patch) {
254
+ if (!await bindingStore.mutate(identity, {
255
+ kind: "patch",
256
+ threadId,
257
+ patch
258
+ })) throw new Error("Codex thread binding changed while applying the control update.");
259
+ }
260
+ function buildBindingLookup(params) {
261
+ const agentDir = params.agentDir?.trim();
262
+ return {
263
+ ...agentDir ? { agentDir } : {},
264
+ ...params.config ? { config: params.config } : {}
265
+ };
266
+ }
267
+ function resolveConversationControlModelProvider(params) {
268
+ const modelProvider = resolveCodexBindingModelProviderFallback({
269
+ currentModel: params.currentModel,
270
+ bindingModel: params.bindingModel,
271
+ bindingModelProvider: params.bindingModelProvider
272
+ })?.trim();
273
+ if (!modelProvider || modelProvider.toLowerCase() === "codex") return;
274
+ if (isCodexAppServerNativeAuthProfile(params) && modelProvider.toLowerCase() === "openai") return;
275
+ return modelProvider.toLowerCase() === "openai" ? "openai" : modelProvider;
276
+ }
277
+ //#endregion
278
+ //#region extensions/codex/src/plugin-marketplace-discovery.ts
279
+ /** Read-only discovery of Codex-owned local, curated, and remote plugin marketplaces. */
280
+ const PLUGIN_SEGMENT_PATTERN = /^[A-Za-z0-9_-]+$/;
281
+ const MAX_PLUGIN_DESCRIPTION_LENGTH = 160;
282
+ const SUPPLEMENTAL_MARKETPLACE_KINDS = [
283
+ "workspace-directory",
284
+ "shared-with-me",
285
+ "created-by-me-remote",
286
+ "vertical"
287
+ ];
288
+ /** Validates the same identifier segments required by Codex's stable PluginId parser. */
289
+ function parseCodexPluginMarketplaceId(value) {
290
+ const separator = value.lastIndexOf("@");
291
+ if (separator <= 0 || separator === value.length - 1) return;
292
+ const pluginName = value.slice(0, separator);
293
+ const marketplaceName = value.slice(separator + 1);
294
+ return PLUGIN_SEGMENT_PATTERN.test(pluginName) && PLUGIN_SEGMENT_PATTERN.test(marketplaceName) ? {
295
+ pluginName,
296
+ marketplaceName
297
+ } : void 0;
298
+ }
299
+ /** Lists local/global first and separately requests workspace, shared, and personal catalogs. */
300
+ async function discoverCodexMarketplacePlugins(params) {
301
+ const requestParams = { cwds: [params.workspaceDir] };
302
+ const primary = await params.request(requestParams);
303
+ const warnings = (primary.marketplaceLoadErrors ?? []).map((error) => boundedCatalogText(error.message));
304
+ const marketplaces = [...primary.marketplaces];
305
+ try {
306
+ const supplemental = await params.request({
307
+ ...requestParams,
308
+ marketplaceKinds: [...SUPPLEMENTAL_MARKETPLACE_KINDS]
309
+ });
310
+ marketplaces.push(...supplemental.marketplaces);
311
+ warnings.push(...(supplemental.marketplaceLoadErrors ?? []).map((error) => boundedCatalogText(error.message)));
312
+ } catch (error) {
313
+ let recoveredSupplementalMarketplace = false;
314
+ for (const kind of SUPPLEMENTAL_MARKETPLACE_KINDS) try {
315
+ const supplemental = await params.request({
316
+ ...requestParams,
317
+ marketplaceKinds: [kind]
318
+ });
319
+ marketplaces.push(...supplemental.marketplaces);
320
+ recoveredSupplementalMarketplace ||= supplemental.marketplaces.length > 0;
321
+ warnings.push(...(supplemental.marketplaceLoadErrors ?? []).map((loadError) => boundedCatalogText(loadError.message)));
322
+ } catch (kindError) {
323
+ warnings.push(boundedCatalogText(`${kind} marketplace unavailable: ${kindError instanceof Error ? kindError.message : String(kindError)}`));
324
+ }
325
+ if (!recoveredSupplementalMarketplace && warnings.length === 0) warnings.push(boundedCatalogText(`Additional marketplaces could not be listed: ${error instanceof Error ? error.message : String(error)}`));
326
+ }
327
+ const discovered = /* @__PURE__ */ new Map();
328
+ const ambiguous = /* @__PURE__ */ new Set();
329
+ for (const marketplace of marketplaces) {
330
+ if (!PLUGIN_SEGMENT_PATTERN.test(marketplace.name)) continue;
331
+ for (const summary of marketplace.plugins) {
332
+ const pluginName = pluginSlug(summary, marketplace.name);
333
+ if (!pluginName) continue;
334
+ const id = `${pluginName}@${marketplace.name}`;
335
+ if (ambiguous.has(id)) continue;
336
+ const previous = discovered.get(id);
337
+ const next = {
338
+ id,
339
+ pluginName,
340
+ marketplaceName: marketplace.name,
341
+ installed: summary.installed,
342
+ enabled: summary.enabled,
343
+ available: summary.availability !== "DISABLED_BY_ADMIN" && summary.installPolicy !== "NOT_AVAILABLE",
344
+ ...summary.installPolicy ? { installPolicy: summary.installPolicy } : {},
345
+ ...summary.authPolicy ? { authPolicy: summary.authPolicy } : {},
346
+ ...marketplace.path ? { marketplacePath: marketplace.path } : {},
347
+ ...summary.remotePluginId?.trim() ? {
348
+ remotePluginId: summary.remotePluginId.trim(),
349
+ mustShowInstallationInterstitial: summary.mustShowInstallationInterstitial ?? null
350
+ } : {},
351
+ summaryId: summary.id
352
+ };
353
+ const description = pluginDescription(summary);
354
+ if (description) next.description = description;
355
+ if (previous && (previous.marketplacePath !== next.marketplacePath || previous.remotePluginId !== next.remotePluginId)) {
356
+ discovered.delete(id);
357
+ ambiguous.add(id);
358
+ warnings.push(`Multiple discovered plugins share ${id}; installation requires a unique identity.`);
359
+ continue;
360
+ }
361
+ if (!previous) discovered.set(id, next);
362
+ else {
363
+ const preferred = !previous.installed && next.installed || !previous.enabled && next.installed && next.enabled ? next : previous;
364
+ discovered.set(id, {
365
+ ...preferred,
366
+ available: previous.available && next.available,
367
+ ...preferred.remotePluginId ? { mustShowInstallationInterstitial: previous.mustShowInstallationInterstitial === true || next.mustShowInstallationInterstitial === true ? true : previous.mustShowInstallationInterstitial === false && next.mustShowInstallationInterstitial === false ? false : null } : {},
368
+ ...previous.installPolicy === "NOT_AVAILABLE" || next.installPolicy === "NOT_AVAILABLE" ? { installPolicy: "NOT_AVAILABLE" } : {}
369
+ });
370
+ }
371
+ }
372
+ }
373
+ return {
374
+ plugins: [...discovered.values()].toSorted((left, right) => left.id.localeCompare(right.id)),
375
+ warnings
376
+ };
377
+ }
378
+ function pluginSlug(summary, marketplaceName) {
379
+ const qualified = parseCodexPluginMarketplaceId(summary.id);
380
+ if (qualified?.marketplaceName === marketplaceName) return qualified.pluginName;
381
+ const identitySegment = summary.id.split("/").at(-1);
382
+ if (identitySegment && PLUGIN_SEGMENT_PATTERN.test(identitySegment)) return identitySegment;
383
+ return PLUGIN_SEGMENT_PATTERN.test(summary.name) ? summary.name : void 0;
384
+ }
385
+ function pluginDescription(summary) {
386
+ const description = asOptionalRecord(summary.interface)?.shortDescription;
387
+ if (typeof description !== "string") return;
388
+ return boundedCatalogText(description) || void 0;
389
+ }
390
+ function boundedCatalogText(value) {
391
+ let sanitized = "";
392
+ for (const character of value) {
393
+ const codePoint = character.codePointAt(0);
394
+ sanitized += codePoint !== void 0 && (codePoint <= 31 || codePoint >= 127 && codePoint <= 159) ? " " : character;
395
+ }
396
+ return sanitized.replace(/\s+/g, " ").trim().slice(0, MAX_PLUGIN_DESCRIPTION_LENGTH);
397
+ }
398
+ //#endregion
399
+ export { parseCodexPermissionsModeArg as a, setCodexConversationModel as c, stopCodexConversationTurn as d, trackCodexConversationActiveTurn as f, hasCodexAdminScope as g, canMutateCodexHost as h, parseCodexFastModeArg as i, setCodexConversationPermissions as l, CODEX_NATIVE_EXECUTION_AUTH_ERROR as m, parseCodexPluginMarketplaceId as n, readCodexConversationActiveTurn as o, CODEX_FULL_PERMISSIONS_AUTH_ERROR as p, formatPermissionsMode as r, setCodexConversationFastMode as s, discoverCodexMarketplacePlugins as t, steerCodexConversationTurn as u };
@@ -1,7 +1,7 @@
1
- import { C as isCodexAppServerIndeterminateRequestCancellationError, G as resolveFirstExistingMacOSDesktopCodexBundledMarketplacePath, S as isCodexAppServerConnectionClosedError, _ as acquireCodexNativeConfigFence, a as getLeasedSharedCodexAppServerClient, l as releaseLeasedSharedCodexAppServerClient, u as resolveCodexNativeConfigFenceKey, w as isCodexAppServerIndeterminateTransportError } from "./shared-client-DTbvH-XV.js";
2
- import { g as resolveCodexAppServerRuntimeOptions, v as resolveCodexComputerUseConfig } from "./session-binding-BXpo9ymA.js";
3
- import { n as describeControlFailure } from "./capabilities-BFDTVYr4.js";
4
- import { r as requestCodexAppServerJson } from "./request-qKh331yu.js";
1
+ import { i as resolveCodexAppServerRuntimeOptions, o as resolveCodexComputerUseConfig } from "./config-CpNeo5AE.js";
2
+ import { M as isCodexAppServerConnectionClosedError, N as isCodexAppServerIndeterminateRequestCancellationError, P as isCodexAppServerIndeterminateTransportError, a as getLeasedSharedCodexAppServerClient, dt as resolveFirstExistingMacOSDesktopCodexBundledMarketplacePath, l as releaseLeasedSharedCodexAppServerClient, u as resolveCodexNativeConfigFenceKey, v as acquireCodexNativeConfigFence } from "./shared-client-Dw-rzii0.js";
3
+ import { n as describeControlFailure } from "./capabilities-CH3K57v4.js";
4
+ import { r as requestCodexAppServerJson } from "./request-DSK0W6YI.js";
5
5
  import { existsSync } from "node:fs";
6
6
  import { runExec } from "openclaw/plugin-sdk/process-runtime";
7
7
  //#region extensions/codex/src/app-server/computer-use-process-repair.ts
@@ -208,6 +208,7 @@ async function inspectCodexComputerUse(params) {
208
208
  try {
209
209
  return await inspectCodexComputerUseWithoutFence({
210
210
  ...params,
211
+ releaseNativeConfigFence: release,
211
212
  ...client ? {
212
213
  client,
213
214
  timeoutMs: params.timeoutMs ?? runtime?.requestTimeoutMs
@@ -251,7 +252,8 @@ async function inspectCodexComputerUseWithoutFence(params) {
251
252
  config: params.computerUseConfig,
252
253
  plugin: pluginInspection.plugin,
253
254
  installPlugin: params.installPlugin,
254
- repairComputerUseMcpChildren
255
+ repairComputerUseMcpChildren,
256
+ releaseNativeConfigFence: params.releaseNativeConfigFence
255
257
  });
256
258
  }
257
259
  async function ensureComputerUsePlugin(params) {
@@ -315,6 +317,7 @@ async function readComputerUseTools(params) {
315
317
  reason: "ready",
316
318
  message: "Computer Use is ready."
317
319
  });
320
+ params.releaseNativeConfigFence?.();
318
321
  const { liveTest, repair } = await runCodexComputerUseLiveTest({
319
322
  request: params.request,
320
323
  config: params.config,
@@ -690,4 +693,104 @@ function resolveComputerUseConfig(params) {
690
693
  });
691
694
  }
692
695
  //#endregion
693
- export { killStaleComputerUseMcpChildren as a, runCodexComputerUseLiveTest as i, installCodexComputerUse as n, readCodexComputerUseStatus as r, ensureCodexComputerUse as t };
696
+ //#region extensions/codex/src/app-server/plugin-metadata-cache.ts
697
+ const CODEX_PLUGIN_METADATA_CACHE_TTL_MS = 3600 * 1e3;
698
+ /** Process-local plugin metadata cache with coalesced loads per query. */
699
+ var CodexPluginMetadataCache = class {
700
+ constructor(nowMs = Date.now) {
701
+ this.nowMs = nowMs;
702
+ this.entries = /* @__PURE__ */ new Map();
703
+ this.inFlight = /* @__PURE__ */ new Map();
704
+ this.generations = /* @__PURE__ */ new Map();
705
+ this.clearGeneration = 0;
706
+ }
707
+ /** Returns a fresh cached snapshot without issuing a request. */
708
+ read(appCacheKey, queryKind, requestParams, catalogScope) {
709
+ const entryKey = buildMetadataCacheEntryKey(appCacheKey, queryKind, requestParams, catalogScope);
710
+ const entry = this.entries.get(entryKey);
711
+ if (!entry) return;
712
+ if (entry.expiresAtMs <= this.nowMs()) {
713
+ this.entries.delete(entryKey);
714
+ return;
715
+ }
716
+ return entry.snapshot;
717
+ }
718
+ /** Returns a fresh snapshot or coalesces one catalog or installed-plugin request. */
719
+ async load(params) {
720
+ const entryKey = buildMetadataCacheEntryKey(params.appCacheKey, params.queryKind, params.requestParams, params.catalogScope);
721
+ const cached = this.read(params.appCacheKey, params.queryKind, params.requestParams, params.catalogScope);
722
+ if (cached) return cached;
723
+ const pending = this.inFlight.get(entryKey);
724
+ if (pending) try {
725
+ return await pending.promise;
726
+ } catch {
727
+ if (this.inFlight.get(entryKey) === pending) this.inFlight.delete(entryKey);
728
+ return await this.load(params);
729
+ }
730
+ const generation = this.generations.get(params.appCacheKey) ?? 0;
731
+ const clearGeneration = this.clearGeneration;
732
+ const promise = (async () => {
733
+ const method = params.queryKind === "installed" ? "plugin/installed" : "plugin/list";
734
+ const response = await params.request(method, params.requestParams);
735
+ const snapshot = {
736
+ appCacheKey: params.appCacheKey,
737
+ queryKind: params.queryKind,
738
+ response
739
+ };
740
+ if (generation === (this.generations.get(params.appCacheKey) ?? 0) && clearGeneration === this.clearGeneration && !hasMarketplaceLoadErrors(response) && (params.cacheable?.(response) ?? true)) this.entries.set(entryKey, {
741
+ snapshot,
742
+ expiresAtMs: this.nowMs() + CODEX_PLUGIN_METADATA_CACHE_TTL_MS
743
+ });
744
+ return snapshot;
745
+ })();
746
+ this.inFlight.set(entryKey, {
747
+ appCacheKey: params.appCacheKey,
748
+ promise
749
+ });
750
+ try {
751
+ return await promise;
752
+ } finally {
753
+ if (this.inFlight.get(entryKey)?.promise === promise) this.inFlight.delete(entryKey);
754
+ }
755
+ }
756
+ /** Invalidates all plugin metadata queries for one app-server runtime. */
757
+ invalidate(appCacheKey) {
758
+ this.generations.set(appCacheKey, (this.generations.get(appCacheKey) ?? 0) + 1);
759
+ for (const [entryKey, entry] of this.entries) if (entry.snapshot.appCacheKey === appCacheKey) this.entries.delete(entryKey);
760
+ for (const [entryKey, pending] of this.inFlight) if (pending.appCacheKey === appCacheKey) this.inFlight.delete(entryKey);
761
+ }
762
+ /** Clears snapshots and prevents late in-flight loads from repopulating them. */
763
+ clear() {
764
+ this.clearGeneration += 1;
765
+ this.generations.clear();
766
+ this.entries.clear();
767
+ this.inFlight.clear();
768
+ }
769
+ };
770
+ /** Shared plugin metadata cache used by Codex app-server runtime paths. */
771
+ const defaultCodexPluginMetadataCache = new CodexPluginMetadataCache();
772
+ function hasMarketplaceLoadErrors(response) {
773
+ return response.marketplaceLoadErrors.length > 0;
774
+ }
775
+ function buildMetadataCacheEntryKey(appCacheKey, queryKind, requestParams, catalogScope) {
776
+ if (queryKind !== "installed") {
777
+ const listParams = requestParams;
778
+ const entry = [
779
+ appCacheKey,
780
+ queryKind,
781
+ listParams?.cwds ?? [],
782
+ Array.from(new Set(listParams?.marketplaceKinds ?? [])).toSorted(),
783
+ ...catalogScope ? [catalogScope] : []
784
+ ];
785
+ return JSON.stringify(entry);
786
+ }
787
+ const installedParams = requestParams;
788
+ return JSON.stringify([
789
+ appCacheKey,
790
+ queryKind,
791
+ installedParams?.cwds ?? [],
792
+ Array.from(new Set(installedParams?.installSuggestionPluginNames ?? [])).toSorted()
793
+ ]);
794
+ }
795
+ //#endregion
796
+ export { runCodexComputerUseLiveTest as a, readCodexComputerUseStatus as i, ensureCodexComputerUse as n, killStaleComputerUseMcpChildren as o, installCodexComputerUse as r, defaultCodexPluginMetadataCache as t };