@openclaw/codex 2026.5.7-beta.1 → 2026.5.9-beta.1

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.
@@ -0,0 +1,389 @@
1
+ import { l as resolveCodexPluginsPolicy, t as CODEX_PLUGINS_MARKETPLACE_NAME } from "./config-BZiM7rhH.js";
2
+ import "node:fs/promises";
3
+ import "node:path";
4
+ var CodexAppInventoryCache = class {
5
+ constructor(options = {}) {
6
+ this.entries = /* @__PURE__ */ new Map();
7
+ this.inFlight = /* @__PURE__ */ new Map();
8
+ this.refreshTokens = /* @__PURE__ */ new Map();
9
+ this.diagnostics = /* @__PURE__ */ new Map();
10
+ this.revision = 0;
11
+ this.ttlMs = options.ttlMs ?? 36e5;
12
+ }
13
+ read(params) {
14
+ const nowMs = params.nowMs ?? Date.now();
15
+ const entry = this.entries.get(params.key);
16
+ if (!entry) {
17
+ const refreshScheduled = this.scheduleRefresh(params);
18
+ return {
19
+ state: "missing",
20
+ key: params.key,
21
+ revision: this.revision,
22
+ refreshScheduled,
23
+ ...this.diagnostics.get(params.key) ? { diagnostic: this.diagnostics.get(params.key) } : {}
24
+ };
25
+ }
26
+ const state = entry.invalidated || entry.expiresAtMs <= nowMs ? "stale" : "fresh";
27
+ const refreshScheduled = state === "fresh" && !params.forceRefetch ? false : this.scheduleRefresh(params);
28
+ return {
29
+ state,
30
+ key: params.key,
31
+ revision: entry.revision,
32
+ snapshot: stripEntryState(entry),
33
+ refreshScheduled,
34
+ ...entry.lastError ? { diagnostic: entry.lastError } : {}
35
+ };
36
+ }
37
+ refreshNow(params) {
38
+ return this.refresh(params);
39
+ }
40
+ invalidate(key, reason, nowMs = Date.now()) {
41
+ this.revision += 1;
42
+ const diagnostic = {
43
+ message: reason,
44
+ atMs: nowMs
45
+ };
46
+ const entry = this.entries.get(key);
47
+ if (entry) {
48
+ entry.invalidated = true;
49
+ entry.lastError = diagnostic;
50
+ entry.revision = this.revision;
51
+ } else this.diagnostics.set(key, diagnostic);
52
+ return this.revision;
53
+ }
54
+ clear() {
55
+ this.entries.clear();
56
+ this.inFlight.clear();
57
+ this.refreshTokens.clear();
58
+ this.diagnostics.clear();
59
+ this.revision = 0;
60
+ }
61
+ getRevision() {
62
+ return this.revision;
63
+ }
64
+ scheduleRefresh(params) {
65
+ if (this.inFlight.has(params.key) && !params.forceRefetch) return true;
66
+ const promise = this.refresh(params);
67
+ this.inFlight.set(params.key, promise);
68
+ promise.catch(() => void 0);
69
+ return true;
70
+ }
71
+ async refresh(params) {
72
+ const existing = this.inFlight.get(params.key);
73
+ if (existing && !params.forceRefetch) return existing;
74
+ const refreshToken = (this.refreshTokens.get(params.key) ?? 0) + 1;
75
+ this.refreshTokens.set(params.key, refreshToken);
76
+ const promise = this.refreshUncoalesced(params, refreshToken);
77
+ this.inFlight.set(params.key, promise);
78
+ try {
79
+ return await promise;
80
+ } finally {
81
+ if (this.inFlight.get(params.key) === promise) this.inFlight.delete(params.key);
82
+ }
83
+ }
84
+ async refreshUncoalesced(params, refreshToken) {
85
+ const nowMs = params.nowMs ?? Date.now();
86
+ try {
87
+ const apps = await listAllApps(params.request, params.forceRefetch ?? false);
88
+ this.revision += 1;
89
+ const snapshot = {
90
+ key: params.key,
91
+ apps,
92
+ fetchedAtMs: nowMs,
93
+ expiresAtMs: nowMs + this.ttlMs,
94
+ revision: this.revision
95
+ };
96
+ if (this.refreshTokens.get(params.key) === refreshToken) {
97
+ this.entries.set(params.key, {
98
+ ...snapshot,
99
+ invalidated: false
100
+ });
101
+ this.diagnostics.delete(params.key);
102
+ }
103
+ return snapshot;
104
+ } catch (error) {
105
+ const diagnostic = {
106
+ message: error instanceof Error ? error.message : String(error),
107
+ atMs: nowMs
108
+ };
109
+ this.diagnostics.set(params.key, diagnostic);
110
+ const entry = this.entries.get(params.key);
111
+ if (entry) entry.lastError = diagnostic;
112
+ throw error;
113
+ }
114
+ }
115
+ };
116
+ const defaultCodexAppInventoryCache = new CodexAppInventoryCache();
117
+ function buildCodexAppInventoryCacheKey(input) {
118
+ return JSON.stringify({
119
+ codexHome: input.codexHome ?? null,
120
+ endpoint: input.endpoint ?? null,
121
+ authProfileId: input.authProfileId ?? null,
122
+ accountId: input.accountId ?? null,
123
+ envApiKeyFingerprint: input.envApiKeyFingerprint ?? null,
124
+ appServerVersion: input.appServerVersion ?? null
125
+ });
126
+ }
127
+ async function listAllApps(request, forceRefetch) {
128
+ const apps = [];
129
+ let cursor;
130
+ do {
131
+ const response = await request("app/list", {
132
+ cursor,
133
+ limit: 100,
134
+ forceRefetch
135
+ });
136
+ apps.push(...response.data);
137
+ cursor = response.nextCursor;
138
+ } while (cursor);
139
+ return apps;
140
+ }
141
+ function stripEntryState(entry) {
142
+ const { invalidated: _invalidated, ...snapshot } = entry;
143
+ return snapshot;
144
+ }
145
+ //#endregion
146
+ //#region extensions/codex/src/app-server/plugin-inventory.ts
147
+ async function readCodexPluginInventory(params) {
148
+ const policy = params.policy ?? resolveCodexPluginsPolicy(params.pluginConfig);
149
+ if (!policy.enabled) return {
150
+ policy,
151
+ records: [],
152
+ diagnostics: [{
153
+ code: "disabled",
154
+ message: "Native Codex plugin support is disabled."
155
+ }]
156
+ };
157
+ const appInventory = readCachedAppInventory(params);
158
+ const marketplaceEntry = (await params.request("plugin/list", { cwds: [] })).marketplaces.find((marketplace) => marketplace.name === CODEX_PLUGINS_MARKETPLACE_NAME);
159
+ if (!marketplaceEntry) return {
160
+ policy,
161
+ records: [],
162
+ diagnostics: policy.pluginPolicies.filter((pluginPolicy) => pluginPolicy.enabled).map((pluginPolicy) => ({
163
+ code: "marketplace_missing",
164
+ plugin: pluginPolicy,
165
+ message: `Codex marketplace ${CODEX_PLUGINS_MARKETPLACE_NAME} was not found.`
166
+ })),
167
+ ...appInventory ? { appInventory } : {}
168
+ };
169
+ const marketplace = marketplaceRef(marketplaceEntry);
170
+ const diagnostics = [];
171
+ const records = [];
172
+ if (appInventory?.state === "missing") diagnostics.push({
173
+ code: "app_inventory_missing",
174
+ message: "Cached Codex app inventory is missing; plugin apps are excluded for this setup."
175
+ });
176
+ else if (appInventory?.state === "stale") diagnostics.push({
177
+ code: "app_inventory_stale",
178
+ message: "Cached Codex app inventory is stale; using stale app readiness and refreshing."
179
+ });
180
+ for (const pluginPolicy of policy.pluginPolicies) {
181
+ if (!pluginPolicy.enabled) continue;
182
+ const summary = findPluginSummary(marketplaceEntry, pluginPolicy.pluginName);
183
+ if (!summary) {
184
+ diagnostics.push({
185
+ code: "plugin_missing",
186
+ plugin: pluginPolicy,
187
+ message: `${pluginPolicy.pluginName} was not found in ${CODEX_PLUGINS_MARKETPLACE_NAME}.`
188
+ });
189
+ continue;
190
+ }
191
+ const detail = await readPluginDetail(params, marketplace, pluginPolicy, diagnostics);
192
+ const ownedAppIds = detail?.apps.map((app) => app.id).filter(Boolean).toSorted() ?? [];
193
+ const appOwnership = resolveAppOwnership({
194
+ detail,
195
+ appInventory,
196
+ summary
197
+ });
198
+ if (appOwnership === "ambiguous") diagnostics.push({
199
+ code: "app_ownership_ambiguous",
200
+ plugin: pluginPolicy,
201
+ message: `${pluginPolicy.pluginName} has only display-name app matches; apps are not exposed until ownership is stable.`
202
+ });
203
+ if (summary.installed && !summary.enabled) diagnostics.push({
204
+ code: "plugin_disabled",
205
+ plugin: pluginPolicy,
206
+ message: `${pluginPolicy.pluginName} is installed in Codex but disabled.`
207
+ });
208
+ const apps = resolveOwnedApps({
209
+ detail,
210
+ appInventory
211
+ });
212
+ records.push({
213
+ policy: pluginPolicy,
214
+ summary,
215
+ ...detail ? { detail } : {},
216
+ activationRequired: !summary.installed || !summary.enabled,
217
+ authRequired: apps.some((app) => app.needsAuth || !app.accessible),
218
+ appOwnership,
219
+ ownedAppIds,
220
+ apps
221
+ });
222
+ }
223
+ return {
224
+ policy,
225
+ marketplace,
226
+ records,
227
+ diagnostics,
228
+ ...appInventory ? { appInventory } : {}
229
+ };
230
+ }
231
+ function findOpenAiCuratedPluginSummary(listed, pluginName) {
232
+ const marketplaceEntry = listed.marketplaces.find((marketplace) => marketplace.name === CODEX_PLUGINS_MARKETPLACE_NAME);
233
+ if (!marketplaceEntry) return;
234
+ const summary = findPluginSummary(marketplaceEntry, pluginName);
235
+ return summary ? {
236
+ marketplace: marketplaceRef(marketplaceEntry),
237
+ summary
238
+ } : void 0;
239
+ }
240
+ function pluginReadParams(marketplace, pluginName) {
241
+ return {
242
+ ...marketplace.path ? { marketplacePath: marketplace.path } : {},
243
+ ...marketplace.remoteMarketplaceName ? { remoteMarketplaceName: marketplace.remoteMarketplaceName } : {},
244
+ pluginName
245
+ };
246
+ }
247
+ function readCachedAppInventory(params) {
248
+ if (!params.appCache || !params.appCacheKey) return;
249
+ const request = async (method, requestParams) => await params.request(method, requestParams);
250
+ return params.appCache.read({
251
+ key: params.appCacheKey,
252
+ request,
253
+ nowMs: params.nowMs
254
+ });
255
+ }
256
+ async function readPluginDetail(params, marketplace, pluginPolicy, diagnostics) {
257
+ if (params.readPluginDetails === false) return;
258
+ try {
259
+ return (await params.request("plugin/read", pluginReadParams(marketplace, pluginPolicy.pluginName))).plugin;
260
+ } catch (error) {
261
+ diagnostics.push({
262
+ code: "plugin_detail_unavailable",
263
+ plugin: pluginPolicy,
264
+ message: `${pluginPolicy.pluginName} detail unavailable: ${error instanceof Error ? error.message : String(error)}`
265
+ });
266
+ return;
267
+ }
268
+ }
269
+ function resolveAppOwnership(params) {
270
+ if (params.detail && params.detail.apps.length > 0) return "proven";
271
+ return (params.appInventory?.snapshot?.apps ?? []).filter((app) => app.pluginDisplayNames.some((displayName) => displayName === params.summary.name)).length > 0 ? "ambiguous" : "none";
272
+ }
273
+ function resolveOwnedApps(params) {
274
+ const detailApps = params.detail?.apps ?? [];
275
+ if (detailApps.length === 0) return [];
276
+ if (params.appInventory?.state === "missing") return [];
277
+ const appInfoById = new Map((params.appInventory?.snapshot?.apps ?? []).map((app) => [app.id, app]));
278
+ return detailApps.map((app) => {
279
+ const info = appInfoById.get(app.id);
280
+ if (!info) return {
281
+ id: app.id,
282
+ name: app.name,
283
+ accessible: false,
284
+ enabled: false,
285
+ needsAuth: true
286
+ };
287
+ return {
288
+ id: app.id,
289
+ name: app.name,
290
+ accessible: info.isAccessible,
291
+ enabled: info.isEnabled,
292
+ needsAuth: app.needsAuth || !info.isAccessible
293
+ };
294
+ }).toSorted((left, right) => left.id.localeCompare(right.id));
295
+ }
296
+ function findPluginSummary(marketplace, pluginName) {
297
+ return marketplace.plugins.find((plugin) => plugin.name === pluginName || plugin.id === pluginName || plugin.id === `${pluginName}@${marketplace.name}` || pluginNameFromPluginId(plugin.id, marketplace.name) === pluginName);
298
+ }
299
+ function pluginNameFromPluginId(pluginId, marketplaceName) {
300
+ const trimmed = pluginId.trim();
301
+ if (!trimmed) return;
302
+ const marketplaceSuffix = `@${marketplaceName}`;
303
+ return (trimmed.endsWith(marketplaceSuffix) ? trimmed.slice(0, -marketplaceSuffix.length) : trimmed).split("/").at(-1)?.trim() || void 0;
304
+ }
305
+ function marketplaceRef(marketplace) {
306
+ return {
307
+ name: CODEX_PLUGINS_MARKETPLACE_NAME,
308
+ ...marketplace.path ? { path: marketplace.path } : {},
309
+ ...!marketplace.path ? { remoteMarketplaceName: marketplace.name } : {}
310
+ };
311
+ }
312
+ //#endregion
313
+ //#region extensions/codex/src/app-server/plugin-activation.ts
314
+ async function ensureCodexPluginActivation(params) {
315
+ if (params.identity.marketplaceName !== "openai-curated") return activationFailure(params.identity, "marketplace_missing", { message: "Only " + CODEX_PLUGINS_MARKETPLACE_NAME + " plugins can be activated." });
316
+ const resolved = findOpenAiCuratedPluginSummary(await params.request("plugin/list", { cwds: [] }), params.identity.pluginName);
317
+ if (!resolved) return activationFailure(params.identity, "plugin_missing", { message: `${params.identity.pluginName} was not found in ${CODEX_PLUGINS_MARKETPLACE_NAME}.` });
318
+ if (resolved.summary.installed && resolved.summary.enabled && !params.installEvenIfActive) return {
319
+ identity: params.identity,
320
+ ok: true,
321
+ reason: "already_active",
322
+ installAttempted: false,
323
+ marketplace: resolved.marketplace,
324
+ diagnostics: []
325
+ };
326
+ const installResponse = await params.request("plugin/install", pluginReadParams(resolved.marketplace, params.identity.pluginName));
327
+ const refreshDiagnostics = [];
328
+ let refreshFailed = false;
329
+ try {
330
+ const refreshResult = await refreshCodexPluginRuntimeState({
331
+ request: params.request,
332
+ appCache: params.appCache,
333
+ appCacheKey: params.appCacheKey
334
+ });
335
+ refreshDiagnostics.push(...refreshResult.diagnostics);
336
+ } catch (error) {
337
+ refreshFailed = true;
338
+ refreshDiagnostics.push({ message: `Codex plugin runtime refresh failed after install: ${error instanceof Error ? error.message : String(error)}` });
339
+ }
340
+ const authRequired = installResponse.appsNeedingAuth.length > 0;
341
+ return {
342
+ identity: params.identity,
343
+ ok: !authRequired && !refreshFailed,
344
+ reason: refreshFailed ? "refresh_failed" : authRequired ? "auth_required" : resolved.summary.installed && resolved.summary.enabled ? "already_active" : "installed",
345
+ installAttempted: true,
346
+ marketplace: resolved.marketplace,
347
+ installResponse,
348
+ diagnostics: [...refreshDiagnostics, ...installResponse.appsNeedingAuth.map((app) => ({ message: `${app.name} requires app authentication before plugin tools are exposed.` }))]
349
+ };
350
+ }
351
+ async function refreshCodexPluginRuntimeState(params) {
352
+ const diagnostics = [];
353
+ await params.request("plugin/list", { cwds: [] });
354
+ await params.request("skills/list", {
355
+ cwds: [],
356
+ forceReload: true
357
+ });
358
+ try {
359
+ await params.request("hooks/list", { cwds: [] });
360
+ } catch (error) {
361
+ diagnostics.push({ message: `Codex hooks refresh skipped: ${error instanceof Error ? error.message : String(error)}` });
362
+ }
363
+ await params.request("config/mcpServer/reload", void 0);
364
+ if (params.appCache && params.appCacheKey) {
365
+ params.appCache.invalidate(params.appCacheKey, "Codex plugin activation changed app inventory");
366
+ const request = async (method, requestParams) => await params.request(method, requestParams);
367
+ try {
368
+ await params.appCache.refreshNow({
369
+ key: params.appCacheKey,
370
+ request,
371
+ forceRefetch: true
372
+ });
373
+ } catch (error) {
374
+ diagnostics.push({ message: `Codex app inventory refresh skipped: ${error instanceof Error ? error.message : String(error)}` });
375
+ }
376
+ }
377
+ return { diagnostics };
378
+ }
379
+ function activationFailure(identity, reason, diagnostic) {
380
+ return {
381
+ identity,
382
+ ok: false,
383
+ reason,
384
+ installAttempted: false,
385
+ diagnostics: [diagnostic]
386
+ };
387
+ }
388
+ //#endregion
389
+ export { defaultCodexAppInventoryCache as i, readCodexPluginInventory as n, buildCodexAppInventoryCacheKey as r, ensureCodexPluginActivation as t };