@openclaw/codex 2026.5.24-beta.2 → 2026.5.26-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.
Files changed (27) hide show
  1. package/dist/{client-1sSy4p3z.js → client-BVK_jmHW.js} +10 -3
  2. package/dist/{client-factory-Bk6i4FnW.js → client-factory-CaOpX89B.js} +1 -1
  3. package/dist/{command-handlers-CcTABuem.js → command-handlers-D4C2y46B.js} +10 -23
  4. package/dist/compact-CRI0BEc_.js +155 -0
  5. package/dist/{computer-use-Hdq1WgTA.js → computer-use-CDDlIBhY.js} +2 -2
  6. package/dist/{config-DDMrwfJl.js → config-0-UN67Qg.js} +8 -4
  7. package/dist/{node-cli-sessions-9CAqnIaA.js → conversation-binding-BnnjOmgs.js} +426 -434
  8. package/dist/{dynamic-tools-Bq717oJR.js → dynamic-tools-BG9ICyU4.js} +20 -11
  9. package/dist/harness.js +5 -5
  10. package/dist/index.js +452 -18
  11. package/dist/media-understanding-provider.js +8 -6
  12. package/dist/{models-DtGLkqMP.js → models-ASKu9eOY.js} +4 -4
  13. package/dist/{notification-correlation-qKY_sgga.js → notification-correlation-YINts3PA.js} +26 -11
  14. package/dist/{protocol-validators-_gKDcd0x.js → protocol-validators-CSuFMLvY.js} +138 -29
  15. package/dist/provider.js +3 -3
  16. package/dist/{request-D93E78SA.js → request-DmBkYLPy.js} +3 -3
  17. package/dist/{run-attempt-CT1N__qp.js → run-attempt-CFBsGx1T.js} +488 -280
  18. package/dist/{session-binding-Bw_mfIW2.js → session-binding-UFjjws4k.js} +1 -1
  19. package/dist/{shared-client-CFCUGEVs.js → shared-client-Fou5nAyt.js} +66 -11
  20. package/dist/{side-question-CYFMTA1O.js → side-question-fq_T2d_x.js} +17 -12
  21. package/dist/test-api.js +3 -3
  22. package/dist/{thread-lifecycle-DGoaguJh.js → thread-lifecycle-BapIT9Qs.js} +113 -28
  23. package/dist/{vision-tools-DOnxzH2y.js → vision-tools-B30YCKRK.js} +16 -4
  24. package/npm-shrinkwrap.json +222 -305
  25. package/package.json +8 -8
  26. package/dist/compact-DnTgL6UT.js +0 -475
  27. package/dist/protocol-oeJQu4rs.js +0 -9
package/dist/index.js CHANGED
@@ -1,22 +1,24 @@
1
1
  import { createCodexAppServerAgentHarness } from "./harness.js";
2
- import { c as readCodexPluginConfig, l as resolveCodexAppServerRuntimeOptions, t as CODEX_PLUGINS_MARKETPLACE_NAME } from "./config-DDMrwfJl.js";
2
+ import { c as readCodexPluginConfig, l as resolveCodexAppServerRuntimeOptions, t as CODEX_PLUGINS_MARKETPLACE_NAME } from "./config-0-UN67Qg.js";
3
3
  import { buildCodexProvider } from "./provider.js";
4
- import { v as ensureCodexPluginActivation, x as defaultCodexAppInventoryCache, y as pluginReadParams } from "./thread-lifecycle-DGoaguJh.js";
4
+ import { C as defaultCodexAppInventoryCache, b as ensureCodexPluginActivation, x as pluginReadParams } from "./thread-lifecycle-BapIT9Qs.js";
5
5
  import { buildCodexMediaUnderstandingProvider } from "./media-understanding-provider.js";
6
- import { i as describeControlFailure, n as buildCodexPluginAppCacheKey, t as requestCodexAppServerJson } from "./request-D93E78SA.js";
7
- import { s as formatCodexDisplayText } from "./notification-correlation-qKY_sgga.js";
8
- import { c as resolveCodexAppServerAuthAccountCacheKey, d as resolveCodexAppServerEnvApiKeyCacheKey, i as getSharedCodexAppServerClient, n as clearSharedCodexAppServerClientIfCurrentAndWait, u as resolveCodexAppServerAuthProfileIdForAgent } from "./shared-client-CFCUGEVs.js";
9
- import { a as resolveCodexCliSessionForBindingOnNode, c as handleCodexConversationInboundClaim, i as listCodexCliSessionsOnNode, n as createCodexCliSessionNodeInvokePolicies, o as resumeCodexCliSessionOnNode, s as handleCodexConversationBindingResolved, t as createCodexCliSessionNodeHostCommands } from "./node-cli-sessions-9CAqnIaA.js";
6
+ import { i as describeControlFailure, n as buildCodexPluginAppCacheKey, t as requestCodexAppServerJson } from "./request-DmBkYLPy.js";
7
+ import { s as formatCodexDisplayText } from "./notification-correlation-YINts3PA.js";
8
+ import { c as resolveCodexAppServerAuthAccountCacheKey, d as resolveCodexAppServerFallbackApiKeyCacheKey, i as getSharedCodexAppServerClient, n as clearSharedCodexAppServerClientIfCurrentAndWait, u as resolveCodexAppServerAuthProfileIdForAgent } from "./shared-client-Fou5nAyt.js";
9
+ import { a as createCodexCliSessionNodeInvokePolicies, c as resolveCodexCliSessionForBindingOnNode, i as createCodexCliSessionNodeHostCommands, l as resumeCodexCliSessionOnNode, n as handleCodexConversationInboundClaim, s as listCodexCliSessionsOnNode, t as handleCodexConversationBindingResolved } from "./conversation-binding-BnnjOmgs.js";
10
10
  import { mutateConfigFile } from "openclaw/plugin-sdk/config-mutation";
11
11
  import { resolveLivePluginConfigObject } from "openclaw/plugin-sdk/plugin-config-runtime";
12
12
  import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
13
13
  import os from "node:os";
14
+ import { asBoolean, isRecord, normalizeOptionalString, uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
14
15
  import fs from "node:fs/promises";
15
16
  import path from "node:path";
16
- import { resolveAgentConfig, resolveAgentWorkspaceDir, resolveDefaultAgentId } from "openclaw/plugin-sdk/agent-runtime";
17
+ import { loadAuthProfileStoreWithoutExternalProfiles, resolveAgentConfig, resolveAgentWorkspaceDir, resolveDefaultAgentId } from "openclaw/plugin-sdk/agent-runtime";
17
18
  import { pathExists } from "openclaw/plugin-sdk/security-runtime";
18
19
  import { MIGRATION_REASON_TARGET_EXISTS, applyMigrationManualItem, createMigrationItem, createMigrationManualItem, hasMigrationConfigPatchConflict, markMigrationItemConflict, markMigrationItemError, markMigrationItemSkipped, readMigrationConfigPath, summarizeMigrationItems, writeMigrationConfigPath } from "openclaw/plugin-sdk/migration";
19
20
  import { archiveMigrationItem, copyMigrationFileItem, withCachedMigrationConfigRuntime, writeMigrationReport } from "openclaw/plugin-sdk/migration-runtime";
21
+ import { applyAuthProfileConfig, buildApiKeyCredential, buildOauthProviderAuthResult, readCodexCliCredentialsCached, updateAuthProfileStoreWithLock } from "openclaw/plugin-sdk/provider-auth";
20
22
  import { readJsonFileWithFallback } from "openclaw/plugin-sdk/json-store";
21
23
  //#region extensions/codex/src/commands.ts
22
24
  function createCodexCommand(options) {
@@ -45,7 +47,7 @@ async function handleCodexCommand(ctx, options = {}) {
45
47
  }
46
48
  }
47
49
  async function loadDefaultCodexSubcommandHandler() {
48
- const { handleCodexSubcommand } = await import("./command-handlers-CcTABuem.js");
50
+ const { handleCodexSubcommand } = await import("./command-handlers-D4C2y46B.js");
49
51
  return handleCodexSubcommand;
50
52
  }
51
53
  //#endregion
@@ -78,6 +80,406 @@ async function readJsonObject(filePath) {
78
80
  return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
79
81
  }
80
82
  //#endregion
83
+ //#region extensions/codex/src/migration/auth.ts
84
+ const OPENAI_CODEX_PROVIDER_ID = "openai-codex";
85
+ const OPENAI_PROVIDER_ID = "openai";
86
+ const OPENAI_CODEX_DEFAULT_MODEL = "openai/gpt-5.5";
87
+ const CODEX_IMPORT_DISPLAY_NAME = "Codex import";
88
+ const CODEX_REASON_AUTH_NOT_SELECTED = "auth credential migration not selected";
89
+ const CODEX_REASON_AUTH_PROFILE_EXISTS = "auth profile exists";
90
+ const CODEX_REASON_AUTH_PROFILE_WRITE_FAILED = "failed to write auth profile";
91
+ const CODEX_REASON_AUTH_NO_LONGER_PRESENT = "auth credential no longer present";
92
+ const CODEX_REASON_MISSING_AUTH_METADATA = "missing auth metadata";
93
+ const CODEX_CONFIG_PATCH_MODE_RETURN$1 = "return";
94
+ var CodexAuthConfigConflict = class extends Error {};
95
+ function decodeJwtPayload(token) {
96
+ const payload = token.split(".")[1];
97
+ if (!payload) return;
98
+ try {
99
+ const parsed = JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
100
+ return isRecord(parsed) ? parsed : void 0;
101
+ } catch {
102
+ return;
103
+ }
104
+ }
105
+ function resolveCodexIdentity(access, accountId) {
106
+ const payload = decodeJwtPayload(access);
107
+ const auth = isRecord(payload?.["https://api.openai.com/auth"]) ? payload["https://api.openai.com/auth"] : {};
108
+ const email = normalizeOptionalString((isRecord(payload?.["https://api.openai.com/profile"]) ? payload["https://api.openai.com/profile"] : {}).email);
109
+ const resolvedAccountId = accountId ?? normalizeOptionalString(auth.chatgpt_account_id);
110
+ const chatgptPlanType = normalizeOptionalString(auth.chatgpt_plan_type);
111
+ if (email) return {
112
+ ...resolvedAccountId ? { accountId: resolvedAccountId } : {},
113
+ ...chatgptPlanType ? { chatgptPlanType } : {},
114
+ email,
115
+ profileName: email
116
+ };
117
+ const stableSubject = normalizeOptionalString(auth.chatgpt_account_user_id) ?? normalizeOptionalString(auth.chatgpt_user_id) ?? normalizeOptionalString(auth.user_id) ?? normalizeOptionalString(payload?.sub) ?? resolvedAccountId;
118
+ return {
119
+ ...resolvedAccountId ? { accountId: resolvedAccountId } : {},
120
+ ...chatgptPlanType ? { chatgptPlanType } : {},
121
+ ...stableSubject ? { profileName: `id-${Buffer.from(stableSubject).toString("base64url")}` } : {}
122
+ };
123
+ }
124
+ function credentialExtra(identity) {
125
+ const extra = {
126
+ ...identity.accountId ? { accountId: identity.accountId } : {},
127
+ ...identity.chatgptPlanType ? { chatgptPlanType: identity.chatgptPlanType } : {},
128
+ ...identity.idToken ? { idToken: identity.idToken } : {}
129
+ };
130
+ return Object.keys(extra).length > 0 ? extra : void 0;
131
+ }
132
+ function importProfileName(identity, fallback) {
133
+ if (identity.accountId) return `account-${identity.accountId.replaceAll(/[^A-Za-z0-9._-]+/gu, "-")}`;
134
+ if (identity.profileName?.startsWith("id-")) return identity.profileName;
135
+ return fallback;
136
+ }
137
+ async function readModelRefs(source) {
138
+ const cache = await readJsonObject(source.modelsCachePath);
139
+ const models = Array.isArray(cache.models) ? cache.models : [];
140
+ const refs = /* @__PURE__ */ new Set();
141
+ for (const model of models) {
142
+ const slug = typeof model === "string" ? model.trim() : isRecord(model) ? normalizeOptionalString(model.slug) ?? normalizeOptionalString(model.id) ?? normalizeOptionalString(model.name) : void 0;
143
+ if (!slug) continue;
144
+ refs.add(`${OPENAI_PROVIDER_ID}/${slug}`);
145
+ }
146
+ refs.add(OPENAI_CODEX_DEFAULT_MODEL);
147
+ return [...refs].toSorted();
148
+ }
149
+ function readProviderAuthModelConfigs(result) {
150
+ const models = result.configPatch?.agents?.defaults?.models;
151
+ if (isRecord(models)) return { ...models };
152
+ return { [normalizeOptionalString(result.defaultModel) ?? OPENAI_CODEX_DEFAULT_MODEL]: {} };
153
+ }
154
+ async function buildCodexOAuthCredential(source) {
155
+ const credential = readCodexCliCredentialsCached({
156
+ codexHome: source.codexHome,
157
+ allowKeychainPrompt: false,
158
+ ttlMs: 0
159
+ });
160
+ if (!credential) return null;
161
+ const identity = resolveCodexIdentity(credential.access, credential.accountId);
162
+ const modelRefs = await readModelRefs(source);
163
+ const configPatch = { agents: { defaults: { models: Object.fromEntries(modelRefs.map((modelRef) => [modelRef, {}])) } } };
164
+ const result = buildOauthProviderAuthResult({
165
+ providerId: OPENAI_CODEX_PROVIDER_ID,
166
+ defaultModel: OPENAI_CODEX_DEFAULT_MODEL,
167
+ access: credential.access,
168
+ refresh: credential.refresh,
169
+ expires: credential.expires,
170
+ email: identity.email,
171
+ profileName: importProfileName(identity, "codex-import"),
172
+ displayName: CODEX_IMPORT_DISPLAY_NAME,
173
+ credentialExtra: credentialExtra({
174
+ accountId: identity.accountId,
175
+ chatgptPlanType: identity.chatgptPlanType,
176
+ idToken: credential.idToken
177
+ }),
178
+ configPatch
179
+ });
180
+ const profile = result.profiles[0];
181
+ return profile ? {
182
+ kind: "oauth",
183
+ provider: OPENAI_CODEX_PROVIDER_ID,
184
+ profileId: profile.profileId,
185
+ result,
186
+ modelConfigs: readProviderAuthModelConfigs(result)
187
+ } : null;
188
+ }
189
+ async function buildCodexApiKeyCredential(source) {
190
+ const key = normalizeOptionalString((await readJsonObject(source.authPath)).OPENAI_API_KEY);
191
+ if (!key) return null;
192
+ return {
193
+ kind: "api_key",
194
+ provider: OPENAI_PROVIDER_ID,
195
+ profileId: "openai:codex-import",
196
+ key
197
+ };
198
+ }
199
+ async function readCodexAuthCredentials(source) {
200
+ return [await buildCodexOAuthCredential(source), await buildCodexApiKeyCredential(source)].filter((entry) => entry !== null);
201
+ }
202
+ function findMatchingOAuthProfile(store, credential) {
203
+ for (const [profileId, existing] of Object.entries(store.profiles)) {
204
+ if (existing.type !== "oauth" || existing.provider !== credential.provider) continue;
205
+ if (credential.accountId && existing.accountId === credential.accountId) return profileId;
206
+ if ((!credential.accountId || !existing.accountId) && credential.email && existing.email === credential.email) return profileId;
207
+ }
208
+ }
209
+ function findMatchingApiKeyProfile(store, provider, key) {
210
+ for (const [profileId, existing] of Object.entries(store.profiles)) if (existing.type === "api_key" && existing.provider === provider && existing.key === key) return profileId;
211
+ }
212
+ function itemProfileTarget(credential, store) {
213
+ if (credential.kind === "oauth") {
214
+ const profile = credential.result.profiles[0];
215
+ const matched = profile?.credential.type === "oauth" ? findMatchingOAuthProfile(store, profile.credential) : void 0;
216
+ return {
217
+ profileId: matched ?? credential.profileId,
218
+ matchedExisting: Boolean(matched)
219
+ };
220
+ }
221
+ const matched = findMatchingApiKeyProfile(store, credential.provider, credential.key);
222
+ return {
223
+ profileId: matched ?? credential.profileId,
224
+ matchedExisting: Boolean(matched)
225
+ };
226
+ }
227
+ function replaceConfigDraft(draft, next) {
228
+ for (const key of Object.keys(draft)) delete draft[key];
229
+ Object.assign(draft, next);
230
+ }
231
+ function existingAuthProfileConfigIsCompatible(existing, profile) {
232
+ if (existing.provider !== profile.provider || existing.mode !== profile.mode) return false;
233
+ if (existing.email && profile.email && existing.email !== profile.email) return false;
234
+ return true;
235
+ }
236
+ function hasAuthProfileConfigConflict(config, profile, overwrite) {
237
+ if (overwrite) return false;
238
+ const existing = config.auth?.profiles?.[profile.profileId];
239
+ return Boolean(existing && !existingAuthProfileConfigIsCompatible(existing, profile));
240
+ }
241
+ function hasCurrentAuthProfileConfigConflict(ctx, profile) {
242
+ let config = ctx.config;
243
+ try {
244
+ config = ctx.runtime?.config?.current?.() ?? config;
245
+ } catch {}
246
+ return hasAuthProfileConfigConflict(config, profile, Boolean(ctx.overwrite));
247
+ }
248
+ function applyDefaultModelIfMissing(cfg) {
249
+ const currentModel = cfg.agents?.defaults?.model;
250
+ if (typeof currentModel === "string" ? currentModel : isRecord(currentModel) ? normalizeOptionalString(currentModel.primary) : void 0) return cfg;
251
+ return {
252
+ ...cfg,
253
+ agents: {
254
+ ...cfg.agents,
255
+ defaults: {
256
+ ...cfg.agents?.defaults,
257
+ model: {
258
+ ...isRecord(currentModel) ? currentModel : {},
259
+ primary: OPENAI_CODEX_DEFAULT_MODEL
260
+ }
261
+ }
262
+ }
263
+ };
264
+ }
265
+ function mergeModelConfigEntry(existing, patch) {
266
+ if (existing && isRecord(existing) && isRecord(patch)) return {
267
+ ...existing,
268
+ ...patch
269
+ };
270
+ return existing ?? patch;
271
+ }
272
+ function applyOAuthModelConfigsToConfig(cfg, credential) {
273
+ const existingModels = cfg.agents?.defaults?.models ?? {};
274
+ const models = credential.result.replaceDefaultModels ? { ...credential.modelConfigs } : { ...existingModels };
275
+ if (!credential.result.replaceDefaultModels) for (const [modelRef, modelConfig] of Object.entries(credential.modelConfigs)) models[modelRef] = mergeModelConfigEntry(models[modelRef], modelConfig);
276
+ return {
277
+ ...cfg,
278
+ agents: {
279
+ ...cfg.agents,
280
+ defaults: {
281
+ ...cfg.agents?.defaults,
282
+ models
283
+ }
284
+ }
285
+ };
286
+ }
287
+ function applyOAuthConfigToConfig(cfg, credential, profileId) {
288
+ let next = applyOAuthModelConfigsToConfig(cfg, credential);
289
+ const profile = credential.result.profiles[0];
290
+ if (profile) next = applyAuthProfileConfig(next, {
291
+ profileId,
292
+ provider: profile.credential.provider,
293
+ mode: "oauth",
294
+ ..."email" in profile.credential && profile.credential.email ? { email: profile.credential.email } : {},
295
+ ..."displayName" in profile.credential && profile.credential.displayName ? { displayName: profile.credential.displayName } : {},
296
+ preferProfileFirst: false
297
+ });
298
+ return applyDefaultModelIfMissing(next);
299
+ }
300
+ function applyApiKeyConfigToConfig(cfg, credential, profileId) {
301
+ return applyAuthProfileConfig(cfg, {
302
+ profileId,
303
+ provider: credential.provider,
304
+ mode: "api_key",
305
+ displayName: CODEX_IMPORT_DISPLAY_NAME,
306
+ preferProfileFirst: false
307
+ });
308
+ }
309
+ function shouldReturnAuthConfigPatch(ctx) {
310
+ return ctx.providerOptions?.configPatchMode === CODEX_CONFIG_PATCH_MODE_RETURN$1;
311
+ }
312
+ function oauthAuthProfileConfig(credential, profileId) {
313
+ const profile = credential.result.profiles[0];
314
+ if (!profile || profile.credential.type !== "oauth") return null;
315
+ return {
316
+ profileId,
317
+ provider: profile.credential.provider,
318
+ mode: "oauth",
319
+ ..."email" in profile.credential && profile.credential.email ? { email: profile.credential.email } : {},
320
+ ..."displayName" in profile.credential && profile.credential.displayName ? { displayName: profile.credential.displayName } : {}
321
+ };
322
+ }
323
+ function apiKeyAuthProfileConfig(credential, profileId) {
324
+ return {
325
+ profileId,
326
+ provider: credential.provider,
327
+ mode: "api_key",
328
+ displayName: CODEX_IMPORT_DISPLAY_NAME
329
+ };
330
+ }
331
+ function authProfileConfigForCredential(credential, profileId) {
332
+ return credential.kind === "oauth" ? oauthAuthProfileConfig(credential, profileId) : apiKeyAuthProfileConfig(credential, profileId);
333
+ }
334
+ async function applyCodexAuthProfileConfig(ctx, profile, applyConfig) {
335
+ const configApi = ctx.runtime?.config;
336
+ if (!configApi?.current || !configApi.mutateConfigFile) return "unavailable";
337
+ try {
338
+ await configApi.mutateConfigFile({
339
+ base: "runtime",
340
+ afterWrite: { mode: "auto" },
341
+ mutate(draft) {
342
+ const current = draft;
343
+ if (hasAuthProfileConfigConflict(current, profile, Boolean(ctx.overwrite))) throw new CodexAuthConfigConflict();
344
+ replaceConfigDraft(draft, applyConfig(current));
345
+ }
346
+ });
347
+ return "configured";
348
+ } catch (error) {
349
+ return error instanceof CodexAuthConfigConflict ? "conflict" : "unavailable";
350
+ }
351
+ }
352
+ async function applyOAuthConfig(ctx, credential, profileId) {
353
+ const profile = oauthAuthProfileConfig(credential, profileId);
354
+ if (!profile) return "unavailable";
355
+ return applyCodexAuthProfileConfig(ctx, profile, (config) => applyOAuthConfigToConfig(config, credential, profileId));
356
+ }
357
+ async function applyApiKeyConfig(ctx, credential, profileId) {
358
+ return applyCodexAuthProfileConfig(ctx, apiKeyAuthProfileConfig(credential, profileId), (config) => applyApiKeyConfigToConfig(config, credential, profileId));
359
+ }
360
+ async function buildCodexAuthItems(params) {
361
+ const credentials = await readCodexAuthCredentials(params.source);
362
+ if (credentials.length === 0) return [];
363
+ const store = loadAuthProfileStoreWithoutExternalProfiles(params.targets.agentDir);
364
+ const skipped = !params.ctx.includeSecrets;
365
+ return credentials.map((credential) => {
366
+ const { profileId, matchedExisting } = itemProfileTarget(credential, store);
367
+ const targetExists = Boolean(store.profiles[profileId]);
368
+ const configProfile = authProfileConfigForCredential(credential, profileId);
369
+ const configConflict = configProfile ? hasAuthProfileConfigConflict(params.ctx.config, configProfile, Boolean(params.ctx.overwrite)) : false;
370
+ const conflict = (targetExists && !matchedExisting && !params.ctx.overwrite || configConflict) && !skipped;
371
+ return createMigrationItem({
372
+ id: `auth:${credential.provider}`,
373
+ kind: "auth",
374
+ action: skipped ? "skip" : "create",
375
+ source: params.source.authPath,
376
+ target: `${params.targets.agentDir}/auth-profiles.json#${profileId}`,
377
+ status: skipped ? "skipped" : conflict ? "conflict" : "planned",
378
+ sensitive: true,
379
+ reason: skipped ? CODEX_REASON_AUTH_NOT_SELECTED : conflict ? CODEX_REASON_AUTH_PROFILE_EXISTS : void 0,
380
+ message: credential.kind === "oauth" ? "Import Codex OAuth credentials and configure OpenAI Codex models." : "Import Codex OpenAI API key.",
381
+ details: {
382
+ provider: credential.provider,
383
+ profileId,
384
+ sourceProfileId: credential.profileId,
385
+ sourceKind: "codex-auth-json",
386
+ credentialKind: credential.kind
387
+ }
388
+ });
389
+ });
390
+ }
391
+ async function applyCodexAuthItem(params) {
392
+ const { ctx, item, source, targets } = params;
393
+ if (item.status !== "planned") return item;
394
+ const profileId = typeof item.details?.profileId === "string" ? item.details.profileId : "";
395
+ const provider = typeof item.details?.provider === "string" ? item.details.provider : "";
396
+ const sourceProfileId = typeof item.details?.sourceProfileId === "string" ? item.details.sourceProfileId : void 0;
397
+ if (!profileId || !provider) return markMigrationItemError(item, CODEX_REASON_MISSING_AUTH_METADATA);
398
+ const credential = (await readCodexAuthCredentials(source)).find((candidate) => candidate.provider === provider);
399
+ if (!credential) return markMigrationItemSkipped(item, CODEX_REASON_AUTH_NO_LONGER_PRESENT);
400
+ if (credential.kind === "oauth" && sourceProfileId && credential.profileId !== sourceProfileId) return markMigrationItemSkipped(item, CODEX_REASON_AUTH_NO_LONGER_PRESENT);
401
+ const oauthProfile = credential.kind === "oauth" ? credential.result.profiles[0] : void 0;
402
+ const oauthCredential = oauthProfile?.credential.type === "oauth" ? oauthProfile.credential : void 0;
403
+ if (credential.kind === "oauth" && !oauthCredential) return markMigrationItemError(item, CODEX_REASON_MISSING_AUTH_METADATA);
404
+ const configProfile = authProfileConfigForCredential(credential, profileId);
405
+ if (!configProfile) return markMigrationItemError(item, CODEX_REASON_MISSING_AUTH_METADATA);
406
+ if (hasCurrentAuthProfileConfigConflict(ctx, configProfile)) return markMigrationItemConflict(item, CODEX_REASON_AUTH_PROFILE_EXISTS);
407
+ let conflicted = false;
408
+ let wrote = false;
409
+ const store = await updateAuthProfileStoreWithLock({
410
+ agentDir: targets.agentDir,
411
+ updater: (freshStore) => {
412
+ const existing = freshStore.profiles[profileId];
413
+ if (!ctx.overwrite && existing) {
414
+ if ((credential.kind === "oauth" ? findMatchingOAuthProfile(freshStore, oauthCredential) : findMatchingApiKeyProfile(freshStore, credential.provider, credential.key)) === profileId) return false;
415
+ conflicted = true;
416
+ return false;
417
+ }
418
+ freshStore.profiles[profileId] = credential.kind === "oauth" ? {
419
+ ...oauthCredential,
420
+ displayName: CODEX_IMPORT_DISPLAY_NAME
421
+ } : {
422
+ ...buildApiKeyCredential(credential.provider, credential.key),
423
+ displayName: CODEX_IMPORT_DISPLAY_NAME
424
+ };
425
+ wrote = true;
426
+ return true;
427
+ }
428
+ });
429
+ if (conflicted) return markMigrationItemConflict(item, CODEX_REASON_AUTH_PROFILE_EXISTS);
430
+ if (!store?.profiles[profileId]) return markMigrationItemError(item, CODEX_REASON_AUTH_PROFILE_WRITE_FAILED);
431
+ const configResult = shouldReturnAuthConfigPatch(ctx) ? "unavailable" : credential.kind === "oauth" ? await applyOAuthConfig(ctx, credential, profileId) : await applyApiKeyConfig(ctx, credential, profileId);
432
+ if (configResult === "conflict") return markMigrationItemConflict(item, CODEX_REASON_AUTH_PROFILE_EXISTS);
433
+ return {
434
+ ...item,
435
+ status: "migrated",
436
+ details: {
437
+ ...item.details,
438
+ wroteAuthProfile: wrote,
439
+ configUpdated: configResult === "configured",
440
+ ...shouldReturnAuthConfigPatch(ctx) ? { configPatchReturned: true } : {}
441
+ }
442
+ };
443
+ }
444
+ async function buildCodexAuthConfigPatchItems(params) {
445
+ const { ctx, item, source } = params;
446
+ if (item.status !== "migrated" || !shouldReturnAuthConfigPatch(ctx)) return [];
447
+ const profileId = typeof item.details?.profileId === "string" ? item.details.profileId : "";
448
+ const provider = typeof item.details?.provider === "string" ? item.details.provider : "";
449
+ const sourceProfileId = typeof item.details?.sourceProfileId === "string" ? item.details.sourceProfileId : void 0;
450
+ if (!profileId || !provider) return [];
451
+ const credential = (await readCodexAuthCredentials(source)).find((candidate) => candidate.provider === provider);
452
+ if (!credential) return [];
453
+ if (credential.kind === "oauth" && sourceProfileId && credential.profileId !== sourceProfileId) return [];
454
+ const next = credential.kind === "oauth" ? applyOAuthConfigToConfig(ctx.config, credential, profileId) : applyApiKeyConfigToConfig(ctx.config, credential, profileId);
455
+ const items = [];
456
+ if (next.auth) items.push(createMigrationItem({
457
+ id: `${item.id}:config:auth`,
458
+ kind: "config",
459
+ action: "merge",
460
+ status: "migrated",
461
+ target: "auth",
462
+ message: "Configure imported Codex auth profile.",
463
+ details: {
464
+ path: ["auth"],
465
+ value: next.auth
466
+ }
467
+ }));
468
+ if (next.agents?.defaults) items.push(createMigrationItem({
469
+ id: `${item.id}:config:agents-defaults`,
470
+ kind: "config",
471
+ action: "merge",
472
+ status: "migrated",
473
+ target: "agents.defaults",
474
+ message: "Configure imported Codex models.",
475
+ details: {
476
+ path: ["agents", "defaults"],
477
+ value: next.agents.defaults
478
+ }
479
+ }));
480
+ return items;
481
+ }
482
+ //#endregion
81
483
  //#region extensions/codex/src/migration/source.ts
82
484
  const SKILL_FILENAME = "SKILL.md";
83
485
  const MAX_SCAN_DEPTH = 6;
@@ -415,6 +817,8 @@ async function discoverCodexSource(inputOrOptions) {
415
817
  const codexSkillsDir = path.join(codexHome, "skills");
416
818
  const agentsSkillsDir = personalAgentsSkillsDir();
417
819
  const configPath = path.join(codexHome, "config.toml");
820
+ const authPath = path.join(codexHome, "auth.json");
821
+ const modelsCachePath = path.join(codexHome, "models_cache.json");
418
822
  const hooksPath = path.join(codexHome, "hooks", "hooks.json");
419
823
  const codexSkills = await discoverSkillDirs({
420
824
  root: codexSkillsDir,
@@ -446,7 +850,8 @@ async function discoverCodexSource(inputOrOptions) {
446
850
  message: "Codex native hooks are archived for manual review because they can execute commands"
447
851
  });
448
852
  const skills = [...codexSkills, ...personalAgentSkills].toSorted((a, b) => a.source.localeCompare(b.source));
449
- const high = Boolean(codexSkills.length || plugins.length || archivePaths.length);
853
+ const hasAuth = await exists(authPath);
854
+ const high = Boolean(codexSkills.length || plugins.length || archivePaths.length || hasAuth);
450
855
  const medium = personalAgentSkills.length > 0;
451
856
  return {
452
857
  root: codexHome,
@@ -455,6 +860,8 @@ async function discoverCodexSource(inputOrOptions) {
455
860
  ...await isDirectory(codexSkillsDir) ? { codexSkillsDir } : {},
456
861
  ...await isDirectory(agentsSkillsDir) ? { personalAgentsSkillsDir: agentsSkillsDir } : {},
457
862
  ...await exists(configPath) ? { configPath } : {},
863
+ ...hasAuth ? { authPath } : {},
864
+ ...await exists(modelsCachePath) ? { modelsCachePath } : {},
458
865
  ...await exists(hooksPath) ? { hooksPath } : {},
459
866
  skills,
460
867
  plugins,
@@ -645,11 +1052,7 @@ function readCodexPluginMigrationConfigEntry(item, enabled) {
645
1052
  };
646
1053
  }
647
1054
  function readExistingAllowDestructiveActions(config) {
648
- const value = readMigrationConfigPath(config, [...CODEX_PLUGIN_NATIVE_CONFIG_PATH, "allow_destructive_actions"]);
649
- return typeof value === "boolean" ? value : void 0;
650
- }
651
- function isRecord(value) {
652
- return Boolean(value && typeof value === "object" && !Array.isArray(value));
1055
+ return asBoolean(readMigrationConfigPath(config, [...CODEX_PLUGIN_NATIVE_CONFIG_PATH, "allow_destructive_actions"]));
653
1056
  }
654
1057
  function buildCodexPluginsConfigValue(entries, params = {}) {
655
1058
  const plugins = Object.fromEntries(entries.toSorted((a, b) => a.configKey.localeCompare(b.configKey)).map((entry) => [entry.configKey, {
@@ -712,6 +1115,11 @@ async function buildCodexMigrationPlan(ctx) {
712
1115
  });
713
1116
  if (!hasCodexSource(source)) throw new Error(`Codex state was not found at ${source.root}. Pass --from <path> if it lives elsewhere.`);
714
1117
  const items = [];
1118
+ items.push(...await buildCodexAuthItems({
1119
+ ctx,
1120
+ source,
1121
+ targets
1122
+ }));
715
1123
  items.push(...await buildSkillItems({
716
1124
  skills: source.skills,
717
1125
  workspaceDir: targets.workspaceDir,
@@ -730,6 +1138,7 @@ async function buildCodexMigrationPlan(ctx) {
730
1138
  details: { archiveRelativePath: archivePath.relativePath }
731
1139
  }));
732
1140
  const warnings = [
1141
+ ...!ctx.includeSecrets && items.some((item) => item.kind === "auth") ? ["Auth credentials were detected but skipped. Re-run interactively or pass --include-secrets to import supported credentials."] : [],
733
1142
  ...items.some((item) => item.status === "conflict") ? ["Conflicts were found. Re-run with --overwrite to replace conflicting migration targets after item-level backups."] : [],
734
1143
  ...source.pluginDiscoveryError ? [`Codex app-server plugin inventory discovery failed: ${source.pluginDiscoveryError}. Cached plugin bundles, if any, are advisory only.`] : [],
735
1144
  ...source.plugins.some((plugin) => plugin.migrationBlock?.code === "codex_subscription_required") ? [codexPluginMigrationSubscriptionWarning()] : []
@@ -793,6 +1202,18 @@ async function applyCodexMigrationPlan(params) {
793
1202
  const plan = params.plan ?? await buildCodexMigrationPlan(params.ctx);
794
1203
  const reportDir = params.ctx.reportDir ?? path.join(params.ctx.stateDir, "migration", "codex");
795
1204
  const items = [];
1205
+ const targets = resolveCodexMigrationTargets(params.ctx);
1206
+ const codexHome = typeof plan.metadata?.codexHome === "string" && plan.metadata.codexHome.trim() ? plan.metadata.codexHome : plan.source;
1207
+ const authSource = {
1208
+ root: plan.source,
1209
+ confidence: "high",
1210
+ codexHome,
1211
+ authPath: path.join(codexHome, "auth.json"),
1212
+ modelsCachePath: path.join(codexHome, "models_cache.json"),
1213
+ skills: [],
1214
+ plugins: [],
1215
+ archivePaths: []
1216
+ };
796
1217
  const runtime = withCachedMigrationConfigRuntime(params.ctx.runtime ?? params.runtime, params.ctx.config);
797
1218
  const applyCtx = {
798
1219
  ...params.ctx,
@@ -804,7 +1225,20 @@ async function applyCodexMigrationPlan(params) {
804
1225
  continue;
805
1226
  }
806
1227
  if (item.id === "config:codex-plugins") items.push(await applyCodexPluginConfigItem(applyCtx, item, items));
807
- else if (item.kind === "plugin" && item.action === "install") items.push(await applyCodexPluginInstallItem(applyCtx, item));
1228
+ else if (item.kind === "auth") {
1229
+ const authItem = await applyCodexAuthItem({
1230
+ ctx: applyCtx,
1231
+ item,
1232
+ source: authSource,
1233
+ targets
1234
+ });
1235
+ items.push(authItem);
1236
+ items.push(...await buildCodexAuthConfigPatchItems({
1237
+ ctx: applyCtx,
1238
+ item: authItem,
1239
+ source: authSource
1240
+ }));
1241
+ } else if (item.kind === "plugin" && item.action === "install") items.push(await applyCodexPluginInstallItem(applyCtx, item));
808
1242
  else if (item.kind === "manual") items.push(applyMigrationManualItem(item));
809
1243
  else if (item.action === "archive") items.push(await archiveMigrationItem(item, reportDir));
810
1244
  else items.push(await copyMigrationFileItem(item, reportDir, { overwrite: params.ctx.overwrite }));
@@ -817,8 +1251,8 @@ async function applyCodexMigrationPlan(params) {
817
1251
  reportDir
818
1252
  };
819
1253
  if (items.some(isCodexPluginLoadWarningItem)) {
820
- result.warnings = [...new Set([...result.warnings ?? [], CODEX_PLUGIN_LOAD_WARNING])];
821
- result.nextSteps = [...new Set([CODEX_PLUGIN_LOAD_WARNING, ...result.nextSteps ?? []])];
1254
+ result.warnings = uniqueStrings([...result.warnings ?? [], CODEX_PLUGIN_LOAD_WARNING]);
1255
+ result.nextSteps = uniqueStrings([CODEX_PLUGIN_LOAD_WARNING, ...result.nextSteps ?? []]);
822
1256
  }
823
1257
  await writeMigrationReport(result, { title: "Codex Migration Report" });
824
1258
  return result;
@@ -970,7 +1404,7 @@ async function buildTargetCodexPluginAppCacheKey(ctx) {
970
1404
  agentDir: targets.agentDir,
971
1405
  config: ctx.config
972
1406
  });
973
- const envApiKeyFingerprint = authProfileId ? void 0 : resolveCodexAppServerEnvApiKeyCacheKey({ startOptions: appServer.start });
1407
+ const envApiKeyFingerprint = authProfileId ? void 0 : resolveCodexAppServerFallbackApiKeyCacheKey({ startOptions: appServer.start });
974
1408
  return buildCodexPluginAppCacheKey({
975
1409
  appServer,
976
1410
  agentDir: targets.agentDir,
@@ -1,10 +1,12 @@
1
1
  import { CODEX_PROVIDER_ID, FALLBACK_CODEX_MODELS } from "./provider-catalog.js";
2
- import { l as resolveCodexAppServerRuntimeOptions } from "./config-DDMrwfJl.js";
3
- import { i as assertCodexTurnStartResponse, l as readCodexTurnCompletedNotification, o as readCodexErrorNotification, r as assertCodexThreadStartResponse } from "./protocol-validators-_gKDcd0x.js";
4
- import { i as readModelListResult } from "./models-DtGLkqMP.js";
5
- import { t as isJsonObject } from "./protocol-oeJQu4rs.js";
6
- import { n as buildCodexRuntimeThreadConfig } from "./thread-lifecycle-DGoaguJh.js";
2
+ import "./client-factory-CaOpX89B.js";
3
+ import { l as resolveCodexAppServerRuntimeOptions } from "./config-0-UN67Qg.js";
4
+ import { i as assertCodexTurnStartResponse, l as readCodexTurnCompletedNotification, o as readCodexErrorNotification, r as assertCodexThreadStartResponse } from "./protocol-validators-CSuFMLvY.js";
5
+ import { i as readModelListResult } from "./models-ASKu9eOY.js";
6
+ import { l as isJsonObject } from "./client-BVK_jmHW.js";
7
+ import { r as buildCodexRuntimeThreadConfig } from "./thread-lifecycle-BapIT9Qs.js";
7
8
  import { validateJsonSchemaValue } from "openclaw/plugin-sdk/json-schema-runtime";
9
+ import "openclaw/plugin-sdk/media-understanding";
8
10
  //#region extensions/codex/media-understanding-provider.ts
9
11
  const DEFAULT_CODEX_IMAGE_MODEL = FALLBACK_CODEX_MODELS.find((model) => model.inputModalities.includes("image"))?.id ?? FALLBACK_CODEX_MODELS[0]?.id;
10
12
  const DEFAULT_CODEX_IMAGE_PROMPT = "Describe the image.";
@@ -63,7 +65,7 @@ async function runBoundedCodexVisionTurn(params) {
63
65
  const appServer = resolveCodexAppServerRuntimeOptions({ pluginConfig: params.options.pluginConfig });
64
66
  const timeoutMs = Math.max(100, params.timeoutMs);
65
67
  const ownsClient = !params.options.clientFactory;
66
- const client = params.options.clientFactory ? await params.options.clientFactory(appServer.start, params.profile) : await import("./shared-client-CFCUGEVs.js").then((n) => n.a).then(({ createIsolatedCodexAppServerClient }) => createIsolatedCodexAppServerClient({
68
+ const client = params.options.clientFactory ? await params.options.clientFactory(appServer.start, params.profile) : await import("./shared-client-Fou5nAyt.js").then((n) => n.a).then(({ createIsolatedCodexAppServerClient }) => createIsolatedCodexAppServerClient({
67
69
  startOptions: appServer.start,
68
70
  timeoutMs,
69
71
  authProfileId: params.profile
@@ -1,5 +1,6 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
2
- import { s as readCodexModelListResponse } from "./protocol-validators-_gKDcd0x.js";
2
+ import { s as readCodexModelListResponse } from "./protocol-validators-CSuFMLvY.js";
3
+ import { uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
3
4
  //#region extensions/codex/src/app-server/models.ts
4
5
  var models_exports = /* @__PURE__ */ __exportAll({
5
6
  listAllCodexAppServerModels: () => listAllCodexAppServerModels,
@@ -39,7 +40,7 @@ async function listAllCodexAppServerModels(options = {}) {
39
40
  async function withCodexAppServerModelClient(options, run) {
40
41
  const timeoutMs = options.timeoutMs ?? 2500;
41
42
  const useSharedClient = options.sharedClient !== false;
42
- const { createIsolatedCodexAppServerClient, getSharedCodexAppServerClient } = await import("./shared-client-CFCUGEVs.js").then((n) => n.a);
43
+ const { createIsolatedCodexAppServerClient, getSharedCodexAppServerClient } = await import("./shared-client-Fou5nAyt.js").then((n) => n.a);
43
44
  const client = useSharedClient ? await getSharedCodexAppServerClient({
44
45
  startOptions: options.startOptions,
45
46
  timeoutMs,
@@ -96,8 +97,7 @@ function readCodexModel(value) {
96
97
  };
97
98
  }
98
99
  function readReasoningEfforts(value) {
99
- const efforts = value.map((entry) => readNonEmptyString(entry.reasoningEffort)).filter((entry) => entry !== void 0);
100
- return [...new Set(efforts)];
100
+ return uniqueStrings(value.map((entry) => readNonEmptyString(entry.reasoningEffort)).filter((entry) => entry !== void 0));
101
101
  }
102
102
  function readNonEmptyString(value) {
103
103
  if (typeof value !== "string") return;