@openclaw/codex 2026.5.10-beta.3 → 2026.5.10-beta.5

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.
@@ -1,5 +1,5 @@
1
1
  //#region extensions/codex/src/app-server/client-factory.ts
2
- const defaultCodexAppServerClientFactory = (startOptions, authProfileId, agentDir, config) => import("./shared-client-BRX9tReb.js").then((n) => n.r).then(({ getSharedCodexAppServerClient }) => getSharedCodexAppServerClient({
2
+ const defaultCodexAppServerClientFactory = (startOptions, authProfileId, agentDir, config) => import("./shared-client-K13b0L1X.js").then((n) => n.i).then(({ getSharedCodexAppServerClient }) => getSharedCodexAppServerClient({
3
3
  startOptions,
4
4
  authProfileId,
5
5
  agentDir,
@@ -1,26 +1,4 @@
1
1
  import { t as isJsonObject } from "./protocol-C9UWI98H.js";
2
- import { n as CodexAppServerRpcError } from "./client-CpksBQ9l.js";
3
- import { i as withTimeout, n as getSharedCodexAppServerClient } from "./shared-client-BRX9tReb.js";
4
- //#region extensions/codex/src/app-server/capabilities.ts
5
- const CODEX_CONTROL_METHODS = {
6
- account: "account/read",
7
- compact: "thread/compact/start",
8
- feedback: "feedback/upload",
9
- listMcpServers: "mcpServerStatus/list",
10
- listSkills: "skills/list",
11
- listThreads: "thread/list",
12
- rateLimits: "account/rateLimits/read",
13
- resumeThread: "thread/resume",
14
- review: "review/start"
15
- };
16
- function describeControlFailure(error) {
17
- if (isUnsupportedControlError(error)) return "unsupported by this Codex app-server";
18
- return error instanceof Error ? error.message : String(error);
19
- }
20
- function isUnsupportedControlError(error) {
21
- return error instanceof CodexAppServerRpcError && error.code === -32601;
22
- }
23
- //#endregion
24
2
  //#region extensions/codex/src/app-server/rate-limits.ts
25
3
  const CODEX_LIMIT_ID = "codex";
26
4
  const LIMIT_WINDOW_KEYS = ["primary", "secondary"];
@@ -52,13 +30,34 @@ function summarizeCodexRateLimits(value, nowMs = Date.now()) {
52
30
  return snapshots.slice(0, 4).map((snapshot) => summarizeRateLimitSnapshot(snapshot, nowMs)).join("; ");
53
31
  }
54
32
  function summarizeCodexAccountRateLimits(value, nowMs = Date.now()) {
33
+ const summary = summarizeCodexAccountUsage(value, nowMs);
34
+ if (!summary) return;
35
+ if (!summary.blocked) return ["Codex is available."];
36
+ return [summary.blockedUntilText ? `Codex is paused until ${summary.blockedUntilText}.` : "Codex is paused by a usage limit.", summary.blockingReason ? `Your ${summary.blockingReason}.` : "Your Codex usage limit is reached."];
37
+ }
38
+ function resolveCodexUsageLimitResetAtMs(value, nowMs = Date.now()) {
39
+ return selectBlockingRateLimitReset(value, nowMs)?.resetsAtMs;
40
+ }
41
+ function summarizeCodexAccountUsage(value, nowMs = Date.now()) {
55
42
  const snapshots = collectCodexRateLimitSnapshots(value);
56
43
  if (snapshots.length === 0) return;
44
+ const usageSnapshot = snapshots.find(isCodexLimitSnapshot) ?? snapshots[0];
57
45
  const blockedSnapshots = snapshots.filter(snapshotHasLimitBlock);
58
46
  const blockingSnapshot = blockedSnapshots.find(isCodexLimitSnapshot) ?? blockedSnapshots[0] ?? void 0;
59
- if (!blockingSnapshot) return ["Codex is available."];
60
- const blockingReset = selectSnapshotBlockingReset(blockingSnapshot, nowMs);
61
- return [blockingReset ? `Codex is paused until ${formatAccountResetTime(blockingReset.resetsAtMs, nowMs)}.` : "Codex is paused by a usage limit.", formatBlockingLimitReason(blockingReset)];
47
+ const blockingReset = blockingSnapshot ? selectSnapshotBlockingReset(blockingSnapshot, nowMs) : void 0;
48
+ const blockingPeriod = formatBlockingLimitPeriod(blockingReset?.windowDurationMins);
49
+ const blockedUntilText = blockingReset ? formatAccountResetTime(blockingReset.resetsAtMs, nowMs) : void 0;
50
+ const blockedResetRelative = blockingReset ? `in ${formatRelativeDuration(blockingReset.resetsAtMs - nowMs)}` : void 0;
51
+ const blockingReason = blockingPeriod ? `${blockingPeriod} Codex usage limit is reached` : blockingSnapshot ? "Codex usage limit is reached" : void 0;
52
+ return {
53
+ usageLine: formatUsageLine(usageSnapshot),
54
+ blocked: Boolean(blockingSnapshot),
55
+ ...blockingReset ? { blockedUntilMs: blockingReset.resetsAtMs } : {},
56
+ ...blockedUntilText ? { blockedUntilText } : {},
57
+ ...blockedResetRelative ? { blockedResetRelative } : {},
58
+ ...blockingPeriod ? { blockingPeriod } : {},
59
+ ...blockingReason ? { blockingReason } : {}
60
+ };
62
61
  }
63
62
  function isCodexUsageLimitError(codexErrorInfo, message) {
64
63
  if (codexErrorInfo === "usageLimitExceeded") return true;
@@ -71,9 +70,12 @@ function selectNextRateLimitReset(value, nowMs) {
71
70
  const futureWindows = collectCodexRateLimitSnapshots(value).flatMap((snapshot) => LIMIT_WINDOW_KEYS.flatMap((key) => readRateLimitWindow(snapshot, key) ?? [])).filter((window) => window.resetsAtMs > nowMs);
72
71
  if (futureWindows.length === 0) return;
73
72
  const exhaustedWindows = futureWindows.filter((window) => window.usedPercent !== void 0 && window.usedPercent >= 100);
74
- const candidates = exhaustedWindows.length > 0 ? exhaustedWindows : futureWindows;
75
- candidates.sort((left, right) => left.resetsAtMs - right.resetsAtMs);
76
- return candidates[0];
73
+ return (exhaustedWindows.length > 0 ? exhaustedWindows : futureWindows).toSorted((left, right) => left.resetsAtMs - right.resetsAtMs)[0];
74
+ }
75
+ function selectBlockingRateLimitReset(value, nowMs) {
76
+ const blockedSnapshots = collectCodexRateLimitSnapshots(value).filter(snapshotHasLimitBlock);
77
+ const blockingSnapshot = blockedSnapshots.find(isCodexLimitSnapshot) ?? blockedSnapshots[0] ?? void 0;
78
+ return blockingSnapshot ? selectSnapshotBlockingReset(blockingSnapshot, nowMs) : void 0;
77
79
  }
78
80
  function summarizeRateLimitSnapshot(snapshot, nowMs) {
79
81
  const label = formatLimitLabel(snapshot);
@@ -176,8 +178,8 @@ function selectSnapshotBlockingReset(snapshot, nowMs) {
176
178
  const futureWindows = readWindowEntries(snapshot).map((entry) => entry.window).filter((window) => window.resetsAtMs > nowMs);
177
179
  const exhaustedWindows = futureWindows.filter((window) => window.usedPercent !== void 0 && window.usedPercent >= 100);
178
180
  const candidates = exhaustedWindows.length > 0 ? exhaustedWindows : futureWindows;
179
- candidates.sort((left, right) => left.resetsAtMs - right.resetsAtMs);
180
- return candidates[0];
181
+ const resetSort = exhaustedWindows.length > 0 ? (left, right) => right.resetsAtMs - left.resetsAtMs : (left, right) => left.resetsAtMs - right.resetsAtMs;
182
+ return candidates.toSorted(resetSort)[0];
181
183
  }
182
184
  function readWindowEntries(snapshot) {
183
185
  return LIMIT_WINDOW_KEYS.flatMap((key) => {
@@ -188,15 +190,25 @@ function readWindowEntries(snapshot) {
188
190
  }] : [];
189
191
  });
190
192
  }
191
- function formatBlockingLimitReason(window) {
192
- const period = formatBlockingLimitPeriod(window?.windowDurationMins);
193
- return period ? `Your ${period} Codex usage limit is reached.` : "Your Codex usage limit is reached.";
194
- }
195
193
  function formatBlockingLimitPeriod(minutes) {
196
194
  if (minutes === 10080) return "weekly";
197
195
  if (minutes === 1440) return "daily";
198
196
  if (minutes !== void 0 && minutes > 0 && minutes < 1440) return "short-term";
199
197
  }
198
+ function formatUsageLine(snapshot) {
199
+ const windows = readWindowEntries(snapshot).filter((entry) => entry.window.usedPercent !== void 0).toSorted((left, right) => (right.window.windowDurationMins ?? 0) - (left.window.windowDurationMins ?? 0)).map((entry) => {
200
+ return `${formatUsageWindowLabel(entry.window.windowDurationMins)} ${Math.round(entry.window.usedPercent ?? 0)}%`;
201
+ });
202
+ return windows.length > 0 ? windows.join(" · ") : void 0;
203
+ }
204
+ function formatUsageWindowLabel(minutes) {
205
+ if (minutes === 10080) return "weekly";
206
+ if (minutes === 1440) return "daily";
207
+ if (minutes !== void 0 && minutes > 0 && minutes < 1440) return "short-term";
208
+ if (minutes !== void 0 && minutes > 0 && minutes % 1440 === 0) return `${minutes / 1440}-day`;
209
+ if (minutes !== void 0 && minutes > 0 && minutes % 60 === 0) return `${minutes / 60}-hour`;
210
+ return "usage";
211
+ }
200
212
  function formatCalendarResetTime(resetsAtMs, nowMs) {
201
213
  const resetDate = new Date(resetsAtMs);
202
214
  const resetParts = new Intl.DateTimeFormat("en-US", {
@@ -295,11 +307,30 @@ function formatThreads(response) {
295
307
  return `- ${formatCodexDisplayText(id)}${title ? ` - ${formatCodexDisplayText(title)}` : ""}${details.length > 0 ? ` (${details.map(formatCodexDisplayText).join(", ")})` : ""}\n Resume: ${formatCodexResumeHint(id)}`;
296
308
  })].join("\n");
297
309
  }
298
- function formatAccount(account, limits) {
310
+ function formatAccount(account, limits, authOverview) {
311
+ if (authOverview) return formatAccountAuthOverview(authOverview);
299
312
  const formattedLimits = limits.ok ? formatCodexRateLimitDetails(limits.value) : formatCodexDisplayText(limits.error);
300
313
  const rateLimitBlock = formattedLimits.startsWith("Codex is ") ? formattedLimits : formattedLimits.includes("\n") ? `Rate limits:\n${formattedLimits}` : `Rate limits: ${formattedLimits}`;
301
314
  return [`Account: ${account.ok ? formatCodexAccountSummary(account.value) : formatCodexDisplayText(account.error)}`, rateLimitBlock].join("\n\n");
302
315
  }
316
+ function formatAccountAuthOverview(overview) {
317
+ const lines = [];
318
+ if (overview.currentLine) lines.push(overview.currentLine, "");
319
+ if (overview.subscriptionLabel) {
320
+ lines.push(`Subscription ${overview.subscriptionLabel}`);
321
+ if (overview.subscriptionUsage) lines.push(` ${overview.subscriptionUsage}`);
322
+ lines.push("");
323
+ }
324
+ if (overview.rows.length > 0) {
325
+ lines.push(overview.orderTitle);
326
+ for (const [index, row] of overview.rows.entries()) lines.push(` ${index + 1}. ${row.label} ${row.kind} — ${formatAuthRowStatus(row)}`);
327
+ }
328
+ while (lines.at(-1) === "") lines.pop();
329
+ return lines.map(formatCodexAccountLine).join("\n");
330
+ }
331
+ function formatAuthRowStatus(row) {
332
+ return row.billingNote ? `${row.status} · ${row.billingNote}` : row.status;
333
+ }
303
334
  function formatComputerUseStatus(status) {
304
335
  const lines = [`Computer Use: ${status.ready ? "ready" : status.enabled ? "not ready" : "disabled"}`];
305
336
  lines.push(`Plugin: ${formatCodexDisplayText(status.pluginName)} (${computerUsePluginState(status)})`);
@@ -335,13 +366,15 @@ function formatCodexAccountSummary(value) {
335
366
  return isLikelyEmailAddress(safe) ? escapeCodexChatTextPreservingAt(safe) : escapeCodexChatText(safe);
336
367
  }
337
368
  function formatCodexTextForDisplay(value) {
369
+ return sanitizeCodexTextForDisplay(value).trim() || "<unknown>";
370
+ }
371
+ function sanitizeCodexTextForDisplay(value) {
338
372
  let safe = "";
339
373
  for (const character of value) {
340
374
  const codePoint = character.codePointAt(0);
341
375
  safe += codePoint != null && isUnsafeDisplayCodePoint(codePoint) ? "?" : character;
342
376
  }
343
- safe = safe.trim();
344
- return safe || "<unknown>";
377
+ return safe;
345
378
  }
346
379
  function escapeCodexChatText(value) {
347
380
  return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("@", "@").replaceAll("`", "`").replaceAll("[", "[").replaceAll("]", "]").replaceAll("(", "(").replaceAll(")", ")").replaceAll("*", "∗").replaceAll("_", "_").replaceAll("~", "~").replaceAll("|", "|");
@@ -349,6 +382,22 @@ function escapeCodexChatText(value) {
349
382
  function escapeCodexChatTextPreservingAt(value) {
350
383
  return escapeCodexChatText(value).replaceAll("@", "@");
351
384
  }
385
+ function formatCodexAccountLine(value) {
386
+ if (value === "") return "";
387
+ const safe = sanitizeCodexTextForDisplay(value).trimEnd();
388
+ if (!safe.trim()) return "";
389
+ const emailPattern = /[^\s@<>()[\]`]+@[^\s@<>()[\]`]+\.[^\s@<>()[\]`]+/gu;
390
+ let formatted = "";
391
+ let lastIndex = 0;
392
+ for (const match of safe.matchAll(emailPattern)) {
393
+ const index = match.index ?? 0;
394
+ formatted += escapeCodexChatText(safe.slice(lastIndex, index));
395
+ formatted += escapeCodexChatTextPreservingAt(match[0]);
396
+ lastIndex = index + match[0].length;
397
+ }
398
+ formatted += escapeCodexChatText(safe.slice(lastIndex));
399
+ return formatted;
400
+ }
352
401
  function isLikelyEmailAddress(value) {
353
402
  return /^[^\s@<>()[\]`]+@[^\s@<>()[\]`]+\.[^\s@<>()[\]`]+$/.test(value);
354
403
  }
@@ -434,17 +483,4 @@ function readString(record, key) {
434
483
  return typeof value === "string" && value.trim() ? value.trim() : void 0;
435
484
  }
436
485
  //#endregion
437
- //#region extensions/codex/src/app-server/request.ts
438
- async function requestCodexAppServerJson(params) {
439
- const timeoutMs = params.timeoutMs ?? 6e4;
440
- return await withTimeout((async () => {
441
- return await (await getSharedCodexAppServerClient({
442
- startOptions: params.startOptions,
443
- timeoutMs,
444
- authProfileId: params.authProfileId,
445
- config: params.config
446
- })).request(params.method, params.requestParams, { timeoutMs });
447
- })(), timeoutMs, `codex app-server ${params.method} timed out`);
448
- }
449
- //#endregion
450
- export { formatCodexStatus as a, formatModels as c, formatCodexUsageLimitErrorMessage as d, shouldRefreshCodexRateLimitsForUsageLimitMessage as f, formatCodexDisplayText as i, formatThreads as l, describeControlFailure as m, buildHelp as n, formatComputerUseStatus as o, CODEX_CONTROL_METHODS as p, formatAccount as r, formatList as s, requestCodexAppServerJson as t, readString as u };
486
+ export { formatComputerUseStatus as a, formatThreads as c, resolveCodexUsageLimitResetAtMs as d, shouldRefreshCodexRateLimitsForUsageLimitMessage as f, formatCodexStatus as i, readString as l, formatAccount as n, formatList as o, summarizeCodexAccountUsage as p, formatCodexDisplayText as r, formatModels as s, buildHelp as t, formatCodexUsageLimitErrorMessage as u };
@@ -1,11 +1,294 @@
1
1
  import { i as isCodexFastServiceTier, s as resolveCodexAppServerRuntimeOptions } from "./config-C7xdbzrp.js";
2
- import { n as listCodexAppServerModels, t as listAllCodexAppServerModels } from "./models-lvthKXfT.js";
2
+ import { n as listCodexAppServerModels, t as listAllCodexAppServerModels } from "./models-Bg-Qf5s-.js";
3
3
  import { t as isJsonObject } from "./protocol-C9UWI98H.js";
4
- import { a as formatCodexStatus, c as formatModels, i as formatCodexDisplayText, l as formatThreads, m as describeControlFailure, n as buildHelp, o as formatComputerUseStatus, p as CODEX_CONTROL_METHODS, r as formatAccount, s as formatList, t as requestCodexAppServerJson, u as readString } from "./request-Bj4IRDU9.js";
5
- import { i as readCodexAppServerBinding, o as writeCodexAppServerBinding, t as clearCodexAppServerBinding } from "./session-binding-BAaJ-7s-.js";
6
- import { a as parseCodexFastModeArg, c as setCodexConversationFastMode, d as steerCodexConversationTurn, f as stopCodexConversationTurn, i as formatPermissionsMode, l as setCodexConversationModel, m as resolveCodexDefaultWorkspaceDir, o as parseCodexPermissionsModeArg, p as readCodexConversationBindingData, r as startCodexConversationThread, s as readCodexConversationActiveTurn, u as setCodexConversationPermissions } from "./conversation-binding-zeuTIuN2.js";
7
- import { a as readCodexComputerUseStatus, i as installCodexComputerUse, n as rememberCodexRateLimits } from "./rate-limit-cache-BFTJlMhx.js";
4
+ import { n as CODEX_CONTROL_METHODS, r as describeControlFailure, t as requestCodexAppServerJson } from "./request-BCAfJvSg.js";
5
+ import { a as formatComputerUseStatus, c as formatThreads, i as formatCodexStatus, l as readString$1, n as formatAccount, o as formatList, p as summarizeCodexAccountUsage, r as formatCodexDisplayText, s as formatModels, t as buildHelp } from "./command-formatters-Ttwc_kgX.js";
6
+ import { i as readCodexAppServerBinding, o as writeCodexAppServerBinding, t as clearCodexAppServerBinding } from "./session-binding-UFKjHkKJ.js";
7
+ import { a as parseCodexFastModeArg, c as setCodexConversationFastMode, d as steerCodexConversationTurn, f as stopCodexConversationTurn, i as formatPermissionsMode, l as setCodexConversationModel, m as resolveCodexDefaultWorkspaceDir, o as parseCodexPermissionsModeArg, p as readCodexConversationBindingData, r as startCodexConversationThread, s as readCodexConversationActiveTurn, u as setCodexConversationPermissions } from "./conversation-binding-D4XZ-tvV.js";
8
+ import { n as installCodexComputerUse, r as readCodexComputerUseStatus } from "./computer-use-CVLaKaW3.js";
9
+ import { n as rememberCodexRateLimits } from "./rate-limit-cache-dvhq-4pi.js";
8
10
  import crypto from "node:crypto";
11
+ import { ensureAuthProfileStore, findNormalizedProviderValue, resolveAuthProfileEligibility, resolveAuthProfileOrder, resolveDefaultAgentDir, resolveProfileUnusableUntilForDisplay } from "openclaw/plugin-sdk/agent-runtime";
12
+ //#region extensions/codex/src/command-account.ts
13
+ const OPENAI_PROVIDER_ID = "openai";
14
+ const OPENAI_CODEX_PROVIDER_ID = "openai-codex";
15
+ async function readCodexAccountAuthOverview(params) {
16
+ const config = params.ctx.config;
17
+ const store = ensureAuthProfileStore(resolveDefaultAgentDir(config), {
18
+ allowKeychainPrompt: false,
19
+ config
20
+ });
21
+ const order = resolveDisplayAuthOrder({
22
+ config,
23
+ store
24
+ });
25
+ if (order.length === 0) return;
26
+ const now = Date.now();
27
+ const activeProfileId = resolveActiveProfileId({
28
+ store,
29
+ order,
30
+ config,
31
+ account: params.account,
32
+ limits: params.limits,
33
+ now
34
+ });
35
+ const subscriptionProfileId = order.find((profileId) => isChatGptSubscriptionProfile(store.profiles[profileId]));
36
+ const activeIsSubscription = activeProfileId !== void 0 && isChatGptSubscriptionProfile(store.profiles[activeProfileId]);
37
+ const activeUsage = activeIsSubscription && params.limits.ok ? summarizeCodexAccountUsage(params.limits.value, now) : void 0;
38
+ const subscriptionUsage = subscriptionProfileId && (!activeIsSubscription || subscriptionProfileId !== activeProfileId) ? await readSubscriptionUsage({
39
+ ...params,
40
+ config,
41
+ subscriptionProfileId,
42
+ now
43
+ }) : activeUsage;
44
+ if (!params.account.ok && !params.limits.ok && !subscriptionUsage) return;
45
+ const rows = order.map((profileId, index) => buildProfileRow({
46
+ store,
47
+ config,
48
+ profileId,
49
+ activeProfileId,
50
+ activeIndex: activeProfileId ? order.indexOf(activeProfileId) : -1,
51
+ index,
52
+ now,
53
+ usage: profileId === subscriptionProfileId ? subscriptionUsage : void 0
54
+ }));
55
+ const activeRow = rows.find((row) => row.active);
56
+ if (!activeRow) return {
57
+ currentLine: "OpenAI credentials: no working credential",
58
+ orderTitle: "Auth order",
59
+ rows
60
+ };
61
+ const activeIsApiKey = store.profiles[activeRow.profileId]?.type === "api_key";
62
+ const subscriptionLabel = subscriptionProfileId ? formatProfileLabel(subscriptionProfileId, store.profiles[subscriptionProfileId]) : activeIsSubscription ? activeRow.label : void 0;
63
+ const subscriptionUsageLine = formatSubscriptionUsageLine(subscriptionUsage);
64
+ return {
65
+ ...activeIsApiKey ? { currentLine: buildApiKeyActiveLine(activeRow, subscriptionUsage) } : {},
66
+ ...subscriptionLabel ? { subscriptionLabel } : {},
67
+ ...subscriptionUsageLine ? { subscriptionUsage: subscriptionUsageLine } : {},
68
+ orderTitle: "Auth order",
69
+ rows
70
+ };
71
+ }
72
+ function resolveDisplayAuthOrder(params) {
73
+ const codexOrder = resolveOrder(params.store.order, OPENAI_CODEX_PROVIDER_ID) ?? resolveOrder(params.config?.auth?.order, OPENAI_CODEX_PROVIDER_ID);
74
+ if (codexOrder && codexOrder.length > 0) return dedupe(codexOrder);
75
+ return resolveAuthProfileOrder({
76
+ cfg: params.config,
77
+ store: params.store,
78
+ provider: OPENAI_CODEX_PROVIDER_ID
79
+ });
80
+ }
81
+ function resolveOrder(order, provider) {
82
+ return findNormalizedProviderValue(order, provider);
83
+ }
84
+ function resolveActiveProfileId(params) {
85
+ const liveProfileId = resolveLiveAccountProfileId({
86
+ account: params.account,
87
+ store: params.store,
88
+ order: params.order
89
+ });
90
+ if (liveProfileId) return liveProfileId;
91
+ const lastGood = [params.store.lastGood?.[OPENAI_PROVIDER_ID], params.store.lastGood?.[OPENAI_CODEX_PROVIDER_ID]].find((profileId) => !!profileId && params.order.includes(profileId) && isActiveProfileCandidate(params, profileId));
92
+ if (lastGood) return lastGood;
93
+ const mostRecent = params.order.map((profileId) => ({
94
+ profileId,
95
+ lastUsed: params.store.usageStats?.[profileId]?.lastUsed ?? 0
96
+ })).filter((entry) => entry.lastUsed > 0 && isActiveProfileCandidate(params, entry.profileId)).toSorted((left, right) => right.lastUsed - left.lastUsed)[0]?.profileId;
97
+ if (mostRecent) return mostRecent;
98
+ if (shouldInferApiKeyActiveFromRateLimitProbe(params.limits)) {
99
+ const apiKeyProfile = params.order.find((profileId) => params.store.profiles[profileId]?.type === "api_key");
100
+ if (apiKeyProfile) return apiKeyProfile;
101
+ }
102
+ return resolveAuthProfileOrder({
103
+ cfg: params.config,
104
+ store: params.store,
105
+ provider: OPENAI_CODEX_PROVIDER_ID
106
+ })[0];
107
+ }
108
+ function isActiveProfileCandidate(params, profileId) {
109
+ return !isActiveUntil(resolveProfileUnusableUntilForDisplay(params.store, profileId) ?? void 0, params.now);
110
+ }
111
+ function resolveLiveAccountProfileId(params) {
112
+ if (!params.account.ok || !isJsonObject(params.account.value)) return;
113
+ const account = isJsonObject(params.account.value.account) ? params.account.value.account : params.account.value;
114
+ const type = readString(account, "type")?.toLowerCase();
115
+ if (type === "chatgpt") {
116
+ const email = readString(account, "email")?.toLowerCase();
117
+ const firstSubscription = params.order.find((profileId) => isChatGptSubscriptionProfile(params.store.profiles[profileId]));
118
+ if (!email) return firstSubscription;
119
+ return params.order.find((profileId) => {
120
+ const credential = params.store.profiles[profileId];
121
+ if (!isChatGptSubscriptionProfile(credential)) return false;
122
+ return (credential.email?.trim().toLowerCase() ?? extractEmailFromProfileId(profileId))?.toLowerCase() === email;
123
+ }) ?? firstSubscription;
124
+ }
125
+ if (type === "apikey" || type === "api_key") return params.order.find((profileId) => params.store.profiles[profileId]?.type === "api_key");
126
+ }
127
+ function shouldInferApiKeyActiveFromRateLimitProbe(limits) {
128
+ return !limits.ok && limits.error.toLowerCase().includes("chatgpt authentication required");
129
+ }
130
+ async function readSubscriptionUsage(params) {
131
+ const limits = await params.safeCodexControlRequest(params.pluginConfig, CODEX_CONTROL_METHODS.rateLimits, void 0, {
132
+ config: params.config,
133
+ authProfileId: params.subscriptionProfileId,
134
+ isolated: true
135
+ });
136
+ if (!limits.ok) return;
137
+ rememberCodexRateLimits(limits.value);
138
+ return summarizeCodexAccountUsage(limits.value, params.now);
139
+ }
140
+ function buildProfileRow(params) {
141
+ const credential = params.store.profiles[params.profileId];
142
+ const label = formatProfileLabel(params.profileId, credential);
143
+ const kind = formatProfileKind(credential);
144
+ const active = params.profileId === params.activeProfileId;
145
+ const status = active ? "active now" : params.usage?.blocked ? formatUsageBlockedStatus(params.usage) : describeInactiveProfileStatus({
146
+ store: params.store,
147
+ config: params.config,
148
+ profileId: params.profileId,
149
+ credential,
150
+ now: params.now,
151
+ afterActive: params.activeIndex >= 0 && params.index > params.activeIndex
152
+ });
153
+ return {
154
+ profileId: params.profileId,
155
+ label,
156
+ kind,
157
+ status,
158
+ active,
159
+ ...credential?.type === "api_key" && active ? { billingNote: "billed per token" } : {},
160
+ ...params.usage?.usageLine ? { usage: params.usage.usageLine } : {}
161
+ };
162
+ }
163
+ function formatUsageBlockedStatus(usage) {
164
+ return usage.blocked ? "rate-limited" : "available if needed";
165
+ }
166
+ function describeInactiveProfileStatus(params) {
167
+ const stats = params.store.usageStats?.[params.profileId];
168
+ const blockedUntil = stats?.blockedUntil;
169
+ if (isActiveUntil(blockedUntil, params.now)) return `rate-limited - resets ${formatRelativeReset(blockedUntil, params.now)}`;
170
+ if (isActiveUntil(resolveProfileUnusableUntilForDisplay(params.store, params.profileId) ?? void 0, params.now)) return describeFailureStatus(stats?.disabledReason ?? stats?.cooldownReason, params.credential);
171
+ const eligibility = resolveAuthProfileEligibility({
172
+ cfg: params.config,
173
+ store: params.store,
174
+ provider: OPENAI_CODEX_PROVIDER_ID,
175
+ profileId: params.profileId,
176
+ now: params.now
177
+ });
178
+ if (!eligibility.eligible) return describeEligibilityStatus(eligibility.reasonCode, params.credential);
179
+ return "available if needed";
180
+ }
181
+ function buildApiKeyActiveLine(activeRow, subscriptionUsage) {
182
+ if (subscriptionUsage?.blocked) {
183
+ const switchBack = subscriptionUsage.blockedResetRelative ? ` · switches back ${subscriptionUsage.blockedResetRelative}` : " · switches back automatically";
184
+ return `Now using: ${activeRow.label} - subscription rate-limited${switchBack}`;
185
+ }
186
+ return `Now using: ${activeRow.label} - subscription unavailable · switches back automatically`;
187
+ }
188
+ function formatSubscriptionUsageLine(usage) {
189
+ if (!usage) return;
190
+ const parts = usage.usageLine ? [formatUsageLineForDisplay(usage.usageLine)] : [];
191
+ if (usage.blockedResetRelative) parts.push(`Resets ${usage.blockedResetRelative}`);
192
+ return parts.length > 0 ? parts.join(" · ") : void 0;
193
+ }
194
+ function formatUsageLineForDisplay(value) {
195
+ return value.replace(/^weekly\b/u, "Weekly").replace(/\bshort-term\b/u, "Short-term");
196
+ }
197
+ function readString(record, key) {
198
+ const value = record[key];
199
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
200
+ }
201
+ function isChatGptSubscriptionProfile(credential) {
202
+ return credential?.type === "oauth" || credential?.type === "token";
203
+ }
204
+ function formatProfileKind(credential) {
205
+ if (!credential) return "credential";
206
+ if (isChatGptSubscriptionProfile(credential)) return "ChatGPT subscription";
207
+ if (credential.type === "api_key") return "API key";
208
+ return "credential";
209
+ }
210
+ function formatProfileLabel(profileId, credential) {
211
+ const tail = profileId.includes(":") ? profileId.slice(profileId.indexOf(":") + 1) : profileId;
212
+ const displayName = credential?.displayName?.trim();
213
+ if (displayName) return credential?.type === "api_key" ? simplifyApiKeyDisplayName(displayName, tail) : displayName;
214
+ const email = credential?.email?.trim() ?? extractEmailFromProfileId(profileId);
215
+ if (email) return email;
216
+ if (credential?.type === "api_key") return tail || "API key";
217
+ return humanizeProfileTail(tail);
218
+ }
219
+ function simplifyApiKeyDisplayName(value, tail) {
220
+ const stripped = value.replace(/^OpenAI\s+/iu, "").trim();
221
+ if (tail && stripped.toLowerCase() === humanizeApiKeyProfileTail(tail).toLowerCase()) return tail;
222
+ return stripped || value;
223
+ }
224
+ function humanizeApiKeyProfileTail(tail) {
225
+ const words = splitProfileTail(tail);
226
+ const hasBackup = words.includes("backup");
227
+ return [
228
+ words.filter((word) => word !== "api" && word !== "key" && word !== "backup").map(titleCase).join(" "),
229
+ "API key",
230
+ hasBackup ? "backup" : ""
231
+ ].filter(Boolean).join(" ");
232
+ }
233
+ function humanizeProfileTail(tail) {
234
+ const words = splitProfileTail(tail);
235
+ return words.length > 0 ? words.map(titleCase).join(" ") : tail;
236
+ }
237
+ function splitProfileTail(tail) {
238
+ return tail.replace(/[_\s]+/gu, "-").split("-").map((word) => word.trim().toLowerCase()).filter(Boolean);
239
+ }
240
+ function titleCase(value) {
241
+ return value ? `${value[0]?.toUpperCase() ?? ""}${value.slice(1)}` : value;
242
+ }
243
+ function extractEmailFromProfileId(profileId) {
244
+ const tail = profileId.includes(":") ? profileId.slice(profileId.indexOf(":") + 1) : profileId;
245
+ return /^[^\s@<>()[\]`]+@[^\s@<>()[\]`]+\.[^\s@<>()[\]`]+$/.test(tail) ? tail : void 0;
246
+ }
247
+ function describeFailureStatus(reason, credential) {
248
+ if (reason === "auth" || reason === "auth_permanent" || reason === "session_expired") return credential?.type === "api_key" ? "auth failed - check key" : "sign-in expired";
249
+ if (reason === "billing") return "billing unavailable";
250
+ if (reason === "rate_limit") return "rate-limited";
251
+ return "temporarily unavailable";
252
+ }
253
+ function describeEligibilityStatus(reason, credential) {
254
+ if (reason === "profile_missing" || reason === "missing_credential") return credential?.type === "api_key" ? "not configured" : "sign-in required";
255
+ if (reason === "expired" || reason === "invalid_expires") return "sign-in expired";
256
+ if (reason === "unresolved_ref") return "credential unavailable";
257
+ if (reason === "provider_mismatch") return "wrong provider";
258
+ if (reason === "mode_mismatch") return "wrong credential type";
259
+ return "unavailable";
260
+ }
261
+ function isActiveUntil(value, now) {
262
+ return typeof value === "number" && Number.isFinite(value) && value > now;
263
+ }
264
+ function formatRelativeReset(untilMs, nowMs) {
265
+ const durationMs = Math.max(1e3, untilMs - nowMs);
266
+ const minuteMs = 6e4;
267
+ const hourMs = 60 * minuteMs;
268
+ const dayMs = 24 * hourMs;
269
+ if (durationMs < hourMs) {
270
+ const minutes = Math.ceil(durationMs / minuteMs);
271
+ return `in ${minutes} ${minutes === 1 ? "minute" : "minutes"}`;
272
+ }
273
+ if (durationMs < dayMs) {
274
+ const hours = Math.ceil(durationMs / hourMs);
275
+ return `in ${hours} ${hours === 1 ? "hour" : "hours"}`;
276
+ }
277
+ const days = Math.ceil(durationMs / dayMs);
278
+ return `in ${days} ${days === 1 ? "day" : "days"}`;
279
+ }
280
+ function dedupe(values) {
281
+ const seen = /* @__PURE__ */ new Set();
282
+ const result = [];
283
+ for (const value of values) {
284
+ const trimmed = value.trim();
285
+ if (!trimmed || seen.has(trimmed)) continue;
286
+ seen.add(trimmed);
287
+ result.push(trimmed);
288
+ }
289
+ return result;
290
+ }
291
+ //#endregion
9
292
  //#region extensions/codex/src/command-rpc.ts
10
293
  function requestOptions(pluginConfig, limit, config) {
11
294
  const runtime = resolveCodexAppServerRuntimeOptions({ pluginConfig });
@@ -23,7 +306,9 @@ async function codexControlRequest(pluginConfig, method, requestParams, options
23
306
  requestParams,
24
307
  timeoutMs: runtime.requestTimeoutMs,
25
308
  startOptions: runtime.start,
26
- config: options.config
309
+ config: options.config,
310
+ authProfileId: options.authProfileId,
311
+ isolated: options.isolated
27
312
  });
28
313
  }
29
314
  async function safeCodexControlRequest(pluginConfig, method, requestParams, options = {}) {
@@ -149,7 +434,13 @@ async function handleCodexSubcommand(ctx, options) {
149
434
  if (rest.length > 0) return { text: "Usage: /codex account" };
150
435
  const [account, limits] = await Promise.all([deps.safeCodexControlRequest(options.pluginConfig, CODEX_CONTROL_METHODS.account, { refreshToken: false }), deps.safeCodexControlRequest(options.pluginConfig, CODEX_CONTROL_METHODS.rateLimits, void 0)]);
151
436
  if (limits.ok) rememberCodexRateLimits(limits.value);
152
- return { text: formatAccount(account, limits) };
437
+ return { text: formatAccount(account, limits, await readCodexAccountAuthOverview({
438
+ ctx,
439
+ pluginConfig: options.pluginConfig,
440
+ safeCodexControlRequest: deps.safeCodexControlRequest,
441
+ account,
442
+ limits
443
+ })) };
153
444
  }
154
445
  return { text: `Unknown Codex command: ${formatCodexDisplayText(subcommand)}\n\n${buildHelp()}` };
155
446
  }
@@ -239,12 +530,12 @@ async function resumeThread(deps, ctx, pluginConfig, args) {
239
530
  persistExtendedHistory: true
240
531
  });
241
532
  const thread = isJsonObject(response) && isJsonObject(response.thread) ? response.thread : {};
242
- const effectiveThreadId = readString(thread, "id") ?? normalizedThreadId;
533
+ const effectiveThreadId = readString$1(thread, "id") ?? normalizedThreadId;
243
534
  await deps.writeCodexAppServerBinding(ctx.sessionFile, {
244
535
  threadId: effectiveThreadId,
245
- cwd: readString(thread, "cwd") ?? "",
246
- model: isJsonObject(response) ? readString(response, "model") : void 0,
247
- modelProvider: isJsonObject(response) ? readString(response, "modelProvider") : void 0
536
+ cwd: readString$1(thread, "cwd") ?? "",
537
+ model: isJsonObject(response) ? readString$1(response, "model") : void 0,
538
+ modelProvider: isJsonObject(response) ? readString$1(response, "modelProvider") : void 0
248
539
  });
249
540
  return `Attached this OpenClaw session to Codex thread ${formatCodexDisplayText(effectiveThreadId)}.`;
250
541
  }
@@ -442,7 +733,7 @@ async function sendCodexDiagnosticsFeedbackForTargets(deps, ctx, pluginConfig, n
442
733
  });
443
734
  continue;
444
735
  }
445
- const responseThreadId = isJsonObject(response.value) ? readString(response.value, "threadId") : void 0;
736
+ const responseThreadId = isJsonObject(response.value) ? readString$1(response.value, "threadId") : void 0;
446
737
  sent.push({
447
738
  ...target,
448
739
  threadId: responseThreadId ?? target.threadId
@@ -1,7 +1,7 @@
1
1
  import { s as resolveCodexAppServerRuntimeOptions } from "./config-C7xdbzrp.js";
2
2
  import { t as isJsonObject } from "./protocol-C9UWI98H.js";
3
- import { i as readCodexAppServerBinding } from "./session-binding-BAaJ-7s-.js";
4
- import { n as defaultCodexAppServerClientFactory, t as createCodexAppServerClientFactoryTestHooks } from "./client-factory-BHbKz0nI.js";
3
+ import { i as readCodexAppServerBinding } from "./session-binding-UFKjHkKJ.js";
4
+ import { n as defaultCodexAppServerClientFactory, t as createCodexAppServerClientFactoryTestHooks } from "./client-factory-D2P0KD6r.js";
5
5
  import { embeddedAgentLog, formatErrorMessage, isActiveHarnessContextEngine, runHarnessContextEngineMaintenance } from "openclaw/plugin-sdk/agent-harness-runtime";
6
6
  //#region extensions/codex/src/app-server/compact.ts
7
7
  const DEFAULT_CODEX_COMPACTION_WAIT_TIMEOUT_MS = 300 * 1e3;
@@ -1,5 +1,5 @@
1
1
  import { c as resolveCodexComputerUseConfig, s as resolveCodexAppServerRuntimeOptions } from "./config-C7xdbzrp.js";
2
- import { m as describeControlFailure, t as requestCodexAppServerJson } from "./request-Bj4IRDU9.js";
2
+ import { r as describeControlFailure, t as requestCodexAppServerJson } from "./request-BCAfJvSg.js";
3
3
  import { existsSync } from "node:fs";
4
4
  //#region extensions/codex/src/app-server/computer-use.ts
5
5
  var CodexComputerUseSetupError = class extends Error {
@@ -364,27 +364,4 @@ function resolveComputerUseConfig(params) {
364
364
  });
365
365
  }
366
366
  //#endregion
367
- //#region extensions/codex/src/app-server/rate-limit-cache.ts
368
- const DEFAULT_CODEX_RATE_LIMIT_CACHE_MAX_AGE_MS = 10 * 6e4;
369
- const CODEX_RATE_LIMIT_CACHE_STATE = Symbol.for("openclaw.codexRateLimitCacheState");
370
- function getCodexRateLimitCacheState() {
371
- const globalState = globalThis;
372
- globalState[CODEX_RATE_LIMIT_CACHE_STATE] ??= {};
373
- return globalState[CODEX_RATE_LIMIT_CACHE_STATE];
374
- }
375
- function rememberCodexRateLimits(value, nowMs = Date.now()) {
376
- if (value === void 0) return;
377
- const state = getCodexRateLimitCacheState();
378
- state.value = value;
379
- state.updatedAtMs = nowMs;
380
- }
381
- function readRecentCodexRateLimits(options) {
382
- const state = getCodexRateLimitCacheState();
383
- if (state.value === void 0 || state.updatedAtMs === void 0) return;
384
- const nowMs = options?.nowMs ?? Date.now();
385
- const maxAgeMs = options?.maxAgeMs ?? DEFAULT_CODEX_RATE_LIMIT_CACHE_MAX_AGE_MS;
386
- if (maxAgeMs >= 0 && nowMs - state.updatedAtMs > maxAgeMs) return;
387
- return state.value;
388
- }
389
- //#endregion
390
- export { readCodexComputerUseStatus as a, installCodexComputerUse as i, rememberCodexRateLimits as n, ensureCodexComputerUse as r, readRecentCodexRateLimits as t };
367
+ export { installCodexComputerUse as n, readCodexComputerUseStatus as r, ensureCodexComputerUse as t };
@@ -1,8 +1,9 @@
1
1
  import { i as isCodexFastServiceTier, r as codexSandboxPolicyForTurn, s as resolveCodexAppServerRuntimeOptions } from "./config-C7xdbzrp.js";
2
2
  import { t as isJsonObject } from "./protocol-C9UWI98H.js";
3
- import { i as formatCodexDisplayText, p as CODEX_CONTROL_METHODS } from "./request-Bj4IRDU9.js";
4
- import { c as resolveCodexAppServerAuthProfileIdForAgent, n as getSharedCodexAppServerClient } from "./shared-client-BRX9tReb.js";
5
- import { i as readCodexAppServerBinding, n as isCodexAppServerNativeAuthProfile, o as writeCodexAppServerBinding, r as normalizeCodexAppServerBindingModelProvider, t as clearCodexAppServerBinding } from "./session-binding-BAaJ-7s-.js";
3
+ import { n as CODEX_CONTROL_METHODS } from "./request-BCAfJvSg.js";
4
+ import { r as formatCodexDisplayText } from "./command-formatters-Ttwc_kgX.js";
5
+ import { l as resolveCodexAppServerAuthProfileIdForAgent, r as getSharedCodexAppServerClient } from "./shared-client-K13b0L1X.js";
6
+ import { i as readCodexAppServerBinding, n as isCodexAppServerNativeAuthProfile, o as writeCodexAppServerBinding, r as normalizeCodexAppServerBindingModelProvider, t as clearCodexAppServerBinding } from "./session-binding-UFKjHkKJ.js";
6
7
  import { formatErrorMessage } from "openclaw/plugin-sdk/agent-harness-runtime";
7
8
  import path from "node:path";
8
9
  import { fileURLToPath } from "node:url";