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

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