@openclaw/codex 2026.9.5 → 2026.9.7

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 (174) hide show
  1. package/README.md +2 -0
  2. package/assets/icon.png +0 -0
  3. package/dist/.setup/{account-usage-runtime-C2MOIvfq.mjs → account-usage-runtime-DFhbh1zz.mjs} +6 -6
  4. package/dist/.setup/{apply-CJ0ZfmBG.mjs → apply-D3GcSoSa.mjs} +35 -55
  5. package/dist/.setup/{attempt-client-cleanup-BpYKdTA0.mjs → attempt-client-cleanup-DOP-cW5j.mjs} +179 -73
  6. package/dist/.setup/attempt-workspace-context-C5HigshI.mjs +164 -0
  7. package/dist/.setup/{auth-binding-DhLWa_7K.mjs → auth-binding-BLWz7stm.mjs} +14 -1
  8. package/dist/.setup/{auth-cache-key-QirmgiCo.mjs → auth-cache-key-Dbvq-QgB.mjs} +41 -111
  9. package/dist/.setup/{auth-profile-WqZtZfXN.mjs → auth-profile-B0okYl2D.mjs} +1 -2
  10. package/dist/.setup/auth-profile-health-oHizqgye.mjs +53 -0
  11. package/dist/.setup/auth-profile-recovery-BREezV0L.mjs +14 -0
  12. package/dist/.setup/auth-start-options-BPIPeEX8.mjs +44 -0
  13. package/dist/.setup/{binding-connection-Bm38niE8.mjs → binding-connection-DTtN1KrX.mjs} +2 -2
  14. package/dist/.setup/{binding-connection.runtime-CnRMC0ta.mjs → binding-connection.runtime-6TpgD1M6.mjs} +5 -5
  15. package/dist/.setup/{bounded-turn-BtlZcivC.mjs → bounded-turn-CbjoN2OW.mjs} +140 -37
  16. package/dist/.setup/bounded-turn-isolation-B8K_ylqk.mjs +14 -0
  17. package/dist/.setup/{build-state-Xx9ybZqa.mjs → build-state-Da1_z0kd.mjs} +1 -1
  18. package/dist/.setup/{capabilities-_vXcZGSx.mjs → capabilities-B3WEZl4e.mjs} +2 -10
  19. package/dist/.setup/{client-vXs2929Q.mjs → client-N0JpgSzF.mjs} +635 -872
  20. package/dist/.setup/client-catalog-response-5HHLdcde.mjs +285 -0
  21. package/dist/.setup/{command-dispatch-naHIZwwF.mjs → command-dispatch-BeAoaovI.mjs} +9 -8
  22. package/dist/.setup/{command-formatters-CGEkdawF.mjs → command-formatters-R3ckE3Co.mjs} +36 -64
  23. package/dist/.setup/{command-handlers-BtAJEW1X.mjs → command-handlers-ylTMS00z.mjs} +301 -488
  24. package/dist/.setup/{command-rpc-DHFpn4le.mjs → command-rpc-CGJGUQ6Y.mjs} +40 -28
  25. package/dist/.setup/compact-C2WamavS.mjs +776 -0
  26. package/dist/.setup/{config-CedDWjM-.mjs → config-DKhXquav.mjs} +26 -28
  27. package/dist/.setup/{config-options-BsanJ8QG.mjs → config-options-CzyWLTJt.mjs} +68 -65
  28. package/dist/.setup/{config-parsing-CcB9iPoq.mjs → config-parsing-b088LyhT.mjs} +57 -60
  29. package/dist/.setup/{config-runtime-CeAhl_h4.mjs → config-runtime-C0NbLms1.mjs} +2 -2
  30. package/dist/.setup/{config-security-BRQ2mgW9.mjs → config-security-CE-FcGw9.mjs} +51 -215
  31. package/dist/.setup/{config-utils-DujwEnhg.mjs → config-utils-D0CXecki.mjs} +3 -13
  32. package/dist/.setup/context-engine-projection-PezSESth.mjs +387 -0
  33. package/dist/.setup/{conversation-binding-DhzrpTM6.mjs → conversation-binding-3Min8qvP.mjs} +71 -105
  34. package/dist/.setup/{conversation-binding-data-CrcyZk6O.mjs → conversation-binding-data-C746z5Pn.mjs} +8 -12
  35. package/dist/.setup/{conversation-control-DN53ns41.mjs → conversation-control-CEP8X5JC.mjs} +30 -69
  36. package/dist/.setup/{cyber-failover-DYwbmf1o.mjs → cyber-failover-XV0nNRZu.mjs} +1 -1
  37. package/dist/.setup/{cyber-failover-notice-e9G3J9-e.mjs → cyber-failover-notice-RNpGpTyP.mjs} +1 -1
  38. package/dist/.setup/{dynamic-tools-D16lOp67.mjs → dynamic-tools-DzlsLUuS.mjs} +3136 -3167
  39. package/dist/.setup/{effective-mcp-catalog-K6kLCN8X.mjs → effective-mcp-catalog-CxUtC-xG.mjs} +8 -17
  40. package/dist/.setup/{ephemeral-turn-R1gA8Sn6.mjs → ephemeral-turn-CDsPJOa2.mjs} +9 -6
  41. package/dist/.setup/event-projector-assistant-message-CigreO4K.mjs +69 -0
  42. package/dist/.setup/{event-projector-usage-C7Ntzs-f.mjs → event-projector-usage-03R0I2dM.mjs} +4 -26
  43. package/dist/.setup/event-projector-values-DJSz8BTk.mjs +106 -0
  44. package/dist/.setup/incognito-session-DWYapfwf.mjs +2 -0
  45. package/dist/.setup/{inference-context-fulhZuz8.mjs → inference-context-D-9gWlTR.mjs} +16 -18
  46. package/dist/.setup/inference-dispatch-CMZtjQyz.mjs +359 -0
  47. package/dist/.setup/inference-metadata-CgIf7sOx.mjs +81 -0
  48. package/dist/.setup/inference-proxy-DhcXOgUE.mjs +561 -0
  49. package/dist/.setup/{isolated-completion-B6srt48J.mjs → isolated-completion-Dm3PzxJk.mjs} +15 -11
  50. package/dist/.setup/launch-args-DbFCehO7.mjs +196 -0
  51. package/dist/.setup/{managed-binary-DP6Rib3P.mjs → managed-binary-kiWRhNRE.mjs} +16 -9
  52. package/dist/.setup/{model-catalog-DkvUuBey.mjs → model-catalog-PAuZgJC6.mjs} +14 -14
  53. package/dist/.setup/model-runtime-BdqzOMkU.mjs +11 -0
  54. package/dist/.setup/{models-BDFgm_G-.mjs → models-DHXZtVVk.mjs} +9 -18
  55. package/dist/.setup/{native-auth-BLZGqFjw.mjs → native-auth-CuG53tu4.mjs} +5 -5
  56. package/dist/.setup/{native-execution-policy-YBMHSzC4.mjs → native-execution-policy-BxZJy5mP.mjs} +6 -31
  57. package/dist/.setup/{native-subagent-monitor-B1hxzIOy.mjs → native-subagent-monitor-Dpsmf2wz.mjs} +4422 -3808
  58. package/dist/.setup/native-subagent-pending-assignments-DwkCzLvD.mjs +203 -0
  59. package/dist/.setup/native-task-assignments-DMQ0g3hu.mjs +194 -0
  60. package/dist/.setup/{node-cli-sessions-Cl8b2ZF3.mjs → node-cli-sessions-HC4W6FLI.mjs} +99 -111
  61. package/dist/.setup/node-exec-server.runtime-BgBfWQqo.mjs +244 -0
  62. package/dist/.setup/{plan-xD7WKYTM.mjs → plan-Y-QIvrKB.mjs} +118 -163
  63. package/dist/.setup/{plugin-activation-r8nq5Jzp.mjs → plugin-activation-cNHRfaxU.mjs} +10 -47
  64. package/dist/.setup/{plugin-app-cache-key-BOxKP7db.mjs → plugin-app-cache-key-BL9B5H0L.mjs} +9 -42
  65. package/dist/.setup/{plugin-inventory-DUle8DLz.mjs → plugin-inventory-Cky2XJUw.mjs} +32 -23
  66. package/dist/.setup/{plugin-marketplace-discovery-P-Vndfqq.mjs → plugin-marketplace-discovery-D_dV9FXa.mjs} +22 -25
  67. package/dist/.setup/{plugin-metadata-cache-DsS5buNa.mjs → plugin-metadata-cache-DsjsL1dr.mjs} +328 -318
  68. package/dist/.setup/protocol-CANUwXJ3.mjs +17 -0
  69. package/dist/.setup/provider-DH8NSzGt.mjs +51 -0
  70. package/dist/.setup/{provider-capabilities-B8J4Dy-O.mjs → provider-capabilities-CAxoF-X1.mjs} +35 -12
  71. package/dist/.setup/{rate-limits-DOEGYRNs.mjs → rate-limits-B7-X2TgG.mjs} +123 -166
  72. package/dist/.setup/{request-BioXJLYa.mjs → request-BHZ1nz8d.mjs} +25 -16
  73. package/dist/.setup/responses-oauth-twnuTaAa.mjs +93 -0
  74. package/dist/.setup/rpc-error-BlD2vuzn.mjs +31 -0
  75. package/dist/.setup/{run-attempt-rlA07pUv.mjs → run-attempt-D8RZUOzY.mjs} +2046 -1454
  76. package/dist/.setup/{run-attempt-lifecycle-B7JbY4-F.mjs → run-attempt-lifecycle-C-6O3Exn.mjs} +10 -24
  77. package/dist/.setup/{runtime-artifact-Dy38Z5iU.mjs → runtime-artifact-DDQ-HGXf.mjs} +43 -47
  78. package/dist/.setup/runtime-artifact-connection-D68qQn1m.mjs +78 -0
  79. package/dist/.setup/sandbox-guard-DjCz2eOw.mjs +126 -0
  80. package/dist/.setup/scope-DOC1Xjc8.mjs +6 -0
  81. package/dist/.setup/session-binding-DGCYAfvD.mjs +443 -0
  82. package/dist/.setup/{session-binding-record-TH3xA0zj.mjs → session-binding-record-Oe9L-CNY.mjs} +73 -132
  83. package/dist/.setup/{session-binding-sidecars-CKYEcfNn.mjs → session-binding-sidecars-jo6H8dFr.mjs} +242 -60
  84. package/dist/.setup/{session-catalog-fUdWDx-U.mjs → session-catalog-4sCdv5qx.mjs} +598 -452
  85. package/dist/.setup/{session-catalog-adoption-CR_whkEW.mjs → session-catalog-adoption-BU_pHWG7.mjs} +59 -26
  86. package/dist/.setup/{session-catalog-archive-CwZaPacf.mjs → session-catalog-archive-spHfihri.mjs} +7 -7
  87. package/dist/.setup/session-catalog-events-DePDzzjc.mjs +139 -0
  88. package/dist/.setup/session-catalog-home-id-vlih0B_g.mjs +22 -0
  89. package/dist/.setup/{session-catalog-index-B141u15s.mjs → session-catalog-index-CZvDzC6z.mjs} +286 -182
  90. package/dist/.setup/{session-catalog-index-order-Cc5BzlQr.mjs → session-catalog-index-order-BcQpHks3.mjs} +2 -2
  91. package/dist/.setup/{session-catalog-index-state-BAuDztHN.mjs → session-catalog-index-state-TeO7EyO-.mjs} +6 -2
  92. package/dist/.setup/session-catalog-limits-DDxOsQeC.mjs +14 -0
  93. package/dist/.setup/session-catalog-list-request-CvtxrYSe.mjs +170 -0
  94. package/dist/.setup/session-catalog-native-projection-DjhwGL6x.mjs +178 -0
  95. package/dist/.setup/{session-catalog-node-adoption-BVRsYOSh.mjs → session-catalog-node-adoption-DgXvSGu0.mjs} +30 -35
  96. package/dist/.setup/{session-catalog-node-continue-Dowv8osw.mjs → session-catalog-node-continue-DjKXHBbi.mjs} +25 -18
  97. package/dist/.setup/session-catalog-node-lookup-CtAXI5W5.mjs +56 -0
  98. package/dist/.setup/{session-catalog-native-projection-ChV3cCtm.mjs → session-catalog-parsing-CPGaPYr-.mjs} +14 -180
  99. package/dist/.setup/{session-catalog-projection-C1Bj9Jl-.mjs → session-catalog-projection-Cr5qP5Dj.mjs} +15 -5
  100. package/dist/.setup/session-catalog-provenance-DoAvktcj.mjs +95 -0
  101. package/dist/.setup/{session-cli-DIj-IE-E.mjs → session-cli-Cn_nCqfq.mjs} +11 -24
  102. package/dist/.setup/{session-history-C--SrLI8.mjs → session-history-D83lJWHG.mjs} +16 -23
  103. package/dist/.setup/{session-history-import-JHXT5Xfi.mjs → session-history-import-WhX-X33a.mjs} +7 -10
  104. package/dist/.setup/session-history-read-Ov3StuL4.mjs +133 -0
  105. package/dist/.setup/{session-history.worker-CpNj7H_P.mjs → session-history.worker-MnPKncqP.mjs} +14 -23
  106. package/dist/.setup/session-initialization-6aveB9qb.mjs +22 -0
  107. package/dist/.setup/{session-permission-policy-DhurXY0l.mjs → session-permission-policy-Ci_fVX6y.mjs} +4 -8
  108. package/dist/.setup/{session-retirement-CU87AOg9.mjs → session-retirement-qMTxkNx2.mjs} +31 -12
  109. package/dist/.setup/{settled-turn-context-fmwouT5I.mjs → settled-turn-context-D4yj4rxf.mjs} +1 -1
  110. package/dist/.setup/{settled-turn-finalizer-CiY2bLFK.mjs → settled-turn-finalizer-BsvEabkw.mjs} +17 -13
  111. package/dist/.setup/{shared-client-BpTtuLQ5.mjs → shared-client-DqyTMYug.mjs} +826 -485
  112. package/dist/.setup/shared-client-lifecycle-DJIgqgMw.mjs +153 -0
  113. package/dist/.setup/{side-question-DSCZyoBD.mjs → side-question-C4kCmQy1.mjs} +206 -334
  114. package/dist/.setup/{source-Bjp4UQij.mjs → source-CS_7GFJZ.mjs} +82 -139
  115. package/dist/.setup/spawn-error-CL3n6MAa.mjs +57 -0
  116. package/dist/.setup/{thread-archive-guard-jmecf6OJ.mjs → thread-archive-guard-C9frICzX.mjs} +10 -3
  117. package/dist/.setup/thread-lifecycle-DPflntEJ.mjs +2362 -0
  118. package/dist/.setup/{incognito-session-uhrBF6wJ.mjs → thread-ownership-queue-Dp24d7-F.mjs} +1 -2
  119. package/dist/.setup/{thread-ownership-skomxnIt.mjs → thread-ownership-roNP0l1c.mjs} +47 -10
  120. package/dist/.setup/thread-policy-DTd-DtkX.mjs +109 -0
  121. package/dist/.setup/thread-requests-B_bRnMGN.mjs +2102 -0
  122. package/dist/.setup/{thread-resume-BkNpj9Pz.mjs → thread-resume-CdDaoc7T.mjs} +6 -6
  123. package/dist/.setup/timeout-CXOfNoaX.mjs +46 -0
  124. package/dist/.setup/transcript-history-projection-DRSifI-1.mjs +201 -0
  125. package/dist/.setup/{transcript-mirror-attestation-CzM-94NC.mjs → transcript-mirror-attestation-YSegaktH.mjs} +3 -4
  126. package/dist/.setup/{transcript-mirror-D4qp_leP.mjs → transcript-mirror-kxmCYsuF.mjs} +224 -206
  127. package/dist/.setup/{transport-stdio-Cmx94Oiy.mjs → transport-stdio-Bdegpn2V.mjs} +138 -75
  128. package/dist/.setup/transport-websocket-BTBE-LD9.mjs +211 -0
  129. package/dist/.setup/{upstream-prompt-provenance-LphB8slG.mjs → upstream-prompt-provenance-fXkKbPVC.mjs} +3 -9
  130. package/dist/.setup/{upstream-session-fork-D3UKxgVD.mjs → upstream-session-fork-CBeVjBpT.mjs} +48 -40
  131. package/dist/.setup/{usage-BOgBEKso.mjs → usage-BMzNxeR_.mjs} +5 -4
  132. package/dist/.setup/{usage-limit-error-C0ow7DOc.mjs → usage-limit-error-QXerDo3i.mjs} +5 -20
  133. package/dist/.setup/{web-search-provider.runtime-CTGuJt6i.mjs → web-search-provider.runtime-P77OUeoo.mjs} +10 -20
  134. package/dist/api.js +25 -16
  135. package/dist/catalog-page-worker-entrypoint.js +12 -0
  136. package/dist/catalog-page.worker.js +9 -0
  137. package/dist/cli-metadata.js +1 -1
  138. package/dist/doctor-contract-api.js +50 -8
  139. package/dist/harness.js +344 -1
  140. package/dist/index.js +345 -346
  141. package/dist/media-understanding-provider.js +9 -22
  142. package/dist/migration-provider-api.js +1 -1
  143. package/dist/provider-discovery.js +1 -1
  144. package/dist/session-history-worker-runtime.js +16 -33
  145. package/dist/session-history.worker.js +1 -1
  146. package/openclaw.plugin.json +14 -2
  147. package/package.json +11 -7
  148. package/dist/.setup/attempt-context-VXVwTCfS.mjs +0 -636
  149. package/dist/.setup/compact-C3i3qlzj.mjs +0 -687
  150. package/dist/.setup/event-projector-assistant-message-DNUR1s0A.mjs +0 -105
  151. package/dist/.setup/event-projector-items-DyTQ_XqL.mjs +0 -200
  152. package/dist/.setup/harness-rxaaoN-o.mjs +0 -349
  153. package/dist/.setup/history-rejection-B4nOXNXF.mjs +0 -13
  154. package/dist/.setup/image-payload-sanitizer-tupAr-2o.mjs +0 -79
  155. package/dist/.setup/inference-proxy-CC15HuSi.mjs +0 -311
  156. package/dist/.setup/launch-args-DnMak49W.mjs +0 -111
  157. package/dist/.setup/local-runtime-attribution-B_2mnqhb.mjs +0 -19
  158. package/dist/.setup/native-subagent-history-YXaL6dMd.mjs +0 -135
  159. package/dist/.setup/native-subagent-task-ids-DsuOonKv.mjs +0 -411
  160. package/dist/.setup/node-exec-server.runtime-BaViBKNz.mjs +0 -226
  161. package/dist/.setup/plugin-approval-roundtrip-CjfzafAZ.mjs +0 -122
  162. package/dist/.setup/provider-fFh_-VR3.mjs +0 -50
  163. package/dist/.setup/rolldown-runtime-8H4AJuhK.mjs +0 -14
  164. package/dist/.setup/sandbox-guard-BBP-RbTf.mjs +0 -166
  165. package/dist/.setup/session-binding-_0W_fHRr.mjs +0 -721
  166. package/dist/.setup/session-catalog-events-jMcYfQyd.mjs +0 -250
  167. package/dist/.setup/session-history-read-B3ZfSUbF.mjs +0 -50
  168. package/dist/.setup/session-initialization-DH1z6fXn.mjs +0 -75
  169. package/dist/.setup/thread-history-page-BTx-4xsg.mjs +0 -83
  170. package/dist/.setup/thread-lifecycle-Cik28qWn.mjs +0 -4904
  171. package/dist/.setup/thread-policy-Cjs4B8xf.mjs +0 -54
  172. package/dist/.setup/timeout-DZF05XrR.mjs +0 -63
  173. package/dist/.setup/transcript-history-projection-DHNBDhCU.mjs +0 -243
  174. package/dist/.setup/version-CoqzXPgK.mjs +0 -12
@@ -0,0 +1,17 @@
1
+ import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
2
+ //#region extensions/codex/src/app-server/protocol.ts
3
+ /** Namespace Codex keeps directly model-visible without exposing it to Code Mode guests. */
4
+ const CODEX_OPENCLAW_DIRECT_DYNAMIC_TOOL_NAMESPACE = "openclaw_direct";
5
+ function flattenCodexDynamicToolFunctions(tools) {
6
+ return (tools ?? []).flatMap((tool) => tool.type === "namespace" ? tool.tools : [tool]);
7
+ }
8
+ /** Asserts the experimental beforeTurnId request field before it crosses the app-server boundary. */
9
+ function assertCodexThreadForkParams(value) {
10
+ if (!isRecord(value) || typeof value.threadId !== "string" || !value.threadId.trim() || value.beforeTurnId !== void 0 && value.beforeTurnId !== null && typeof value.beforeTurnId !== "string") throw new Error("Invalid Codex app-server thread/fork params");
11
+ return value;
12
+ }
13
+ function isJsonObject(value) {
14
+ return isRecord(value);
15
+ }
16
+ //#endregion
17
+ export { isJsonObject as i, assertCodexThreadForkParams as n, flattenCodexDynamicToolFunctions as r, CODEX_OPENCLAW_DIRECT_DYNAMIC_TOOL_NAMESPACE as t };
@@ -0,0 +1,51 @@
1
+ import { t as isOnlyMigrationKind } from "./scope-DOC1Xjc8.mjs";
2
+ //#region extensions/codex/src/migration/provider.ts
3
+ function buildCodexMigrationProvider(params = {}) {
4
+ return {
5
+ id: "codex",
6
+ label: "Codex",
7
+ description: [
8
+ "Import consolidated memories, selected Codex and personal AgentSkills, and selected eligible openai-curated plugins.",
9
+ "Auth credentials require separate consent. Sessions and chat history are not imported.",
10
+ "Codex config and hooks are saved for manual review, not activated. Source files are not moved or deleted."
11
+ ].join(" "),
12
+ supportedItemKinds: ["memory", "auth"],
13
+ async detect(ctx) {
14
+ const { discoverCodexSource, hasCodexSource } = await import("./source-CS_7GFJZ.mjs").then((n) => n.a);
15
+ const memoryOnly = isOnlyMigrationKind(ctx, "memory");
16
+ const authOnly = isOnlyMigrationKind(ctx, "auth");
17
+ const source = await discoverCodexSource({
18
+ input: ctx.source,
19
+ memoryOnly,
20
+ authOnly
21
+ });
22
+ const found = memoryOnly ? source.memoryFiles.length > 0 : authOnly ? Boolean(source.authPath) : hasCodexSource(source);
23
+ return {
24
+ found,
25
+ source: source.root,
26
+ label: "Codex",
27
+ confidence: found ? source.confidence : "low",
28
+ message: found ? "Codex state found." : "Codex state not found."
29
+ };
30
+ },
31
+ async plan(ctx) {
32
+ const { buildCodexMigrationPlan } = await import("./plan-Y-QIvrKB.mjs");
33
+ return buildCodexMigrationPlan(ctx);
34
+ },
35
+ deferredApply: { retrySafe: true },
36
+ prepareApply(ctx) {
37
+ if (isOnlyMigrationKind(ctx, "memory") || isOnlyMigrationKind(ctx, "auth")) return;
38
+ return import("./apply-D3GcSoSa.mjs").then(({ prepareTargetCodexAppServer }) => prepareTargetCodexAppServer(ctx));
39
+ },
40
+ async apply(ctx, plan) {
41
+ const { applyCodexMigrationPlan } = await import("./apply-D3GcSoSa.mjs");
42
+ return await applyCodexMigrationPlan({
43
+ ctx,
44
+ plan,
45
+ runtime: params.runtime
46
+ });
47
+ }
48
+ };
49
+ }
50
+ //#endregion
51
+ export { buildCodexMigrationProvider as t };
@@ -1,5 +1,5 @@
1
- import { h as releaseLeasedSharedCodexAppServerClient } from "./shared-client-BpTtuLQ5.mjs";
2
- import { lt as normalizeCodexDynamicToolName } from "./thread-lifecycle-Cik28qWn.mjs";
1
+ import { h as releaseLeasedSharedCodexAppServerClient } from "./shared-client-DqyTMYug.mjs";
2
+ import { dt as normalizeCodexDynamicToolName } from "./thread-requests-B_bRnMGN.mjs";
3
3
  import { pinExecToolTarget } from "openclaw/plugin-sdk/codex-mcp-projection";
4
4
  import { loadNodeExecAvailability } from "openclaw/plugin-sdk/node-selection-runtime";
5
5
  //#region extensions/codex/src/app-server/shell-dynamic-tools.ts
@@ -7,7 +7,6 @@ const CODEX_NODE_EXEC_DYNAMIC_TOOL_NAME = "node_exec";
7
7
  const CODEX_GATEWAY_EXEC_DYNAMIC_TOOL_NAME = "gateway_exec";
8
8
  const CODEX_GATEWAY_PROCESS_DYNAMIC_TOOL_NAME = "gateway_process";
9
9
  const PROCESS_FOLLOWUP_TEXT = "Use process (list/poll/log/write/send-keys/submit/paste/kill/clear/remove) for follow-up.";
10
- /** Returns true when plugin config explicitly removes any named dynamic tool. */
11
10
  function isCodexDynamicToolExcluded(config, names) {
12
11
  const normalizedNames = new Set(names.map((name) => normalizeCodexDynamicToolName(name)));
13
12
  return (config.codexDynamicToolsExclude ?? []).some((name) => normalizedNames.has(normalizeCodexDynamicToolName(name)));
@@ -21,18 +20,11 @@ async function createNodeExecAliasDynamicTool(execTool, node, discoverySignal, a
21
20
  host: "node",
22
21
  ...pinnedNode ? { node: pinnedNode } : {}
23
22
  });
24
- const execute = async (toolCallId, args, signal, onUpdate) => {
25
- const result = await pinnedTool.execute(toolCallId, args, signal, onUpdate);
26
- return {
27
- ...result,
28
- content: result.content.map((item) => item.type === "text" ? Object.assign({}, item, { text: item.text.replace(PROCESS_FOLLOWUP_TEXT, "Remote-node background follow-up is unavailable. Wait for the command to complete.") }) : item)
29
- };
30
- };
31
23
  return {
32
24
  ...pinnedTool,
33
25
  name: CODEX_NODE_EXEC_DYNAMIC_TOOL_NAME,
34
26
  description: pinnedNode ? "Run a shell command to completion on the OpenClaw configured remote node for this session. This tool always uses OpenClaw host=node internally and follows the existing node exec approval and allowlist policy. Remote-node background follow-up is unavailable. Use Codex's native shell for local app-server work when it is available." : "Run a shell command to completion on an OpenClaw remote node. The sole connected node that can execute commands is selected automatically; select by name or id when several can. This tool always uses OpenClaw host=node internally and follows the existing node exec approval and allowlist policy. Remote-node background follow-up is unavailable. Use Codex's native shell for local app-server work when it is available.",
35
- execute
27
+ execute: withProcessFollowupText(pinnedTool, "Remote-node background follow-up is unavailable. Wait for the command to complete.")
36
28
  };
37
29
  }
38
30
  function createGatewayExecProjection(createProjection, execTool, params) {
@@ -51,6 +43,30 @@ function createGatewayProcessProjection(createProjection, processTool) {
51
43
  description: "Manage background shell sessions in the existing per-session OpenClaw process scope: list, poll, log, write, send-keys, submit, paste, kill, clear, or remove. Use for gateway_exec follow-up; use native Codex shell session handling for ordinary local work."
52
44
  });
53
45
  }
46
+ function createSandboxExecProjection(execTool) {
47
+ return {
48
+ ...execTool,
49
+ name: "sandbox_exec",
50
+ description: "Run a shell command through OpenClaw's configured sandbox backend for this session. Use when OpenClaw sandboxing is active or when a command must execute in the sandbox backend, such as an SSH-backed sandbox or Docker container-path bind layout. Use Codex's native shell only when no OpenClaw sandbox is active and native Code Mode is available.",
51
+ execute: withProcessFollowupText(execTool, "Use sandbox_process (list/poll/log/write/send-keys/submit/paste/kill/clear/remove) for follow-up.")
52
+ };
53
+ }
54
+ function withProcessFollowupText(tool, followupText) {
55
+ return async (toolCallId, args, signal, onUpdate) => {
56
+ const result = await tool.execute(toolCallId, args, signal, onUpdate);
57
+ return {
58
+ ...result,
59
+ content: result.content.map((item) => item.type === "text" ? Object.assign({}, item, { text: item.text.replace(PROCESS_FOLLOWUP_TEXT, followupText) }) : item)
60
+ };
61
+ };
62
+ }
63
+ function createSandboxProcessProjection(processTool) {
64
+ return {
65
+ ...processTool,
66
+ name: "sandbox_process",
67
+ description: "Manage background shell sessions through OpenClaw's configured sandbox backend for this session: list, poll, log, write, send-keys, submit, paste, kill, clear, or remove. Use only for sandbox follow-up; use Codex's native shell session handling only when no OpenClaw sandbox is active and native Code Mode is available."
68
+ };
69
+ }
54
70
  //#endregion
55
71
  //#region extensions/codex/src/app-server/provider-capabilities.ts
56
72
  function resolveOverriddenProviderWebSearchSupport(modelProviderOverride) {
@@ -59,6 +75,12 @@ function resolveOverriddenProviderWebSearchSupport(modelProviderOverride) {
59
75
  return provider === "openai" ? "supported" : "unsupported";
60
76
  }
61
77
  async function readConfiguredProviderWebSearchSupport(params) {
78
+ if (params.expectedNativeModelProvider) {
79
+ if (((await params.client.request("config/read", { includeLayers: false }, {
80
+ timeoutMs: params.timeoutMs,
81
+ signal: params.signal
82
+ })).config.model_provider ?? "openai") !== params.expectedNativeModelProvider) return "unknown";
83
+ }
62
84
  return (await params.client.request("modelProvider/capabilities/read", {}, {
63
85
  timeoutMs: params.timeoutMs,
64
86
  signal: params.signal
@@ -89,6 +111,7 @@ async function resolveCodexProviderWebSearchSupport(params) {
89
111
  client,
90
112
  timeoutMs: params.appServer.requestTimeoutMs,
91
113
  modelProviderOverride: params.modelProviderOverride,
114
+ expectedNativeModelProvider: params.expectedNativeModelProvider,
92
115
  signal: params.signal
93
116
  });
94
117
  } catch {
@@ -98,4 +121,4 @@ async function resolveCodexProviderWebSearchSupport(params) {
98
121
  }
99
122
  }
100
123
  //#endregion
101
- export { CODEX_NODE_EXEC_DYNAMIC_TOOL_NAME as a, createNodeExecAliasDynamicTool as c, CODEX_GATEWAY_PROCESS_DYNAMIC_TOOL_NAME as i, isCodexDynamicToolExcluded as l, resolveCodexProviderWebSearchSupportForClient as n, createGatewayExecProjection as o, CODEX_GATEWAY_EXEC_DYNAMIC_TOOL_NAME as r, createGatewayProcessProjection as s, resolveCodexProviderWebSearchSupport as t };
124
+ export { CODEX_NODE_EXEC_DYNAMIC_TOOL_NAME as a, createNodeExecAliasDynamicTool as c, isCodexDynamicToolExcluded as d, CODEX_GATEWAY_PROCESS_DYNAMIC_TOOL_NAME as i, createSandboxExecProjection as l, resolveCodexProviderWebSearchSupportForClient as n, createGatewayExecProjection as o, CODEX_GATEWAY_EXEC_DYNAMIC_TOOL_NAME as r, createGatewayProcessProjection as s, resolveCodexProviderWebSearchSupport as t, createSandboxProcessProjection as u };
@@ -1,20 +1,72 @@
1
- import { m as isJsonObject } from "./config-security-BRQ2mgW9.mjs";
1
+ import { i as isJsonObject } from "./protocol-CANUwXJ3.mjs";
2
2
  import { normalizeOptionalString, parseStrictFiniteNumber } from "openclaw/plugin-sdk/string-coerce-runtime";
3
3
  import { z } from "zod";
4
4
  import { MAX_DATE_TIMESTAMP_MS, resolveExpiresAtMsFromEpochSeconds } from "openclaw/plugin-sdk/number-runtime";
5
- import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
6
5
  import { PROVIDER_LABELS, clampPercent } from "openclaw/plugin-sdk/provider-usage";
7
- //#region extensions/codex/src/app-server/rate-limits.ts
8
- /**
9
- * Parses Codex account rate-limit payloads into user-facing usage summaries,
10
- * reset hints, and enriched usage-limit error messages.
11
- */
12
- const CODEX_LIMIT_ID = "codex";
13
- const LIMIT_WINDOW_KEYS = ["primary", "secondary"];
6
+ //#region extensions/codex/src/app-server/rate-limit-time.ts
7
+ /** Human-readable Codex quota reset times; no account or routing decisions. */
14
8
  const ONE_SECOND_MS = 1e3;
15
9
  const ONE_MINUTE_MS = 6e4;
16
10
  const ONE_HOUR_MS = 60 * ONE_MINUTE_MS;
17
- const ONE_DAY_MS = 24 * ONE_HOUR_MS;
11
+ const ONE_DAY_MS$1 = 24 * ONE_HOUR_MS;
12
+ function formatCalendarResetTime(resetsAtMs, nowMs) {
13
+ const resetDate = new Date(resetsAtMs);
14
+ const resetParts = new Intl.DateTimeFormat("en-US", {
15
+ month: "short",
16
+ day: "numeric",
17
+ ...resetDate.getFullYear() === new Date(nowMs).getFullYear() ? {} : { year: "numeric" },
18
+ hour: "numeric",
19
+ minute: "2-digit",
20
+ timeZoneName: "short"
21
+ }).formatToParts(resetDate);
22
+ const part = (type) => resetParts.find((entry) => entry.type === type)?.value;
23
+ const dateParts = [
24
+ part("month"),
25
+ part("day"),
26
+ part("year")
27
+ ].filter(Boolean);
28
+ return [
29
+ dateParts.length > 1 ? `${dateParts[0]} ${dateParts.slice(1).join(", ")}` : dateParts[0],
30
+ "at",
31
+ [
32
+ [part("hour"), part("minute")].filter(Boolean).join(":"),
33
+ part("dayPeriod"),
34
+ part("timeZoneName")
35
+ ].filter(Boolean).join(" ")
36
+ ].filter(Boolean).join(" ");
37
+ }
38
+ function formatRelativeDuration(durationMs) {
39
+ const safeMs = Math.max(1e3, durationMs);
40
+ if (safeMs < ONE_MINUTE_MS) return `${Math.ceil(safeMs / 1e3)} seconds`;
41
+ if (safeMs < ONE_HOUR_MS) {
42
+ const minutes = Math.ceil(safeMs / ONE_MINUTE_MS);
43
+ return `${minutes} ${minutes === 1 ? "minute" : "minutes"}`;
44
+ }
45
+ if (safeMs < ONE_DAY_MS$1) {
46
+ const hours = Math.ceil(safeMs / ONE_HOUR_MS);
47
+ return `${hours} ${hours === 1 ? "hour" : "hours"}`;
48
+ }
49
+ const days = Math.ceil(safeMs / ONE_DAY_MS$1);
50
+ return `${days} ${days === 1 ? "day" : "days"}`;
51
+ }
52
+ function formatResetDuration(resetsAtMs, nowMs) {
53
+ const durationMs = Math.round(Math.max(ONE_SECOND_MS, resetsAtMs - nowMs) / ONE_SECOND_MS) * ONE_SECOND_MS;
54
+ const days = Math.floor(durationMs / ONE_DAY_MS$1);
55
+ const hours = Math.floor(durationMs % ONE_DAY_MS$1 / ONE_HOUR_MS);
56
+ const minutes = Math.floor(durationMs % ONE_HOUR_MS / ONE_MINUTE_MS);
57
+ const seconds = Math.floor(durationMs % ONE_MINUTE_MS / ONE_SECOND_MS);
58
+ if (days > 0) return hours > 0 ? `${days}d ${hours}h` : `${days}d`;
59
+ if (hours > 0) return minutes > 0 ? `${hours}h ${minutes}m` : `${hours}h`;
60
+ if (minutes > 0) return seconds > 0 ? `${minutes}m ${seconds}s` : `${minutes}m`;
61
+ return `${seconds}s`;
62
+ }
63
+ //#endregion
64
+ //#region extensions/codex/src/app-server/rate-limits.ts
65
+ const CODEX_LIMIT_ID = "codex";
66
+ const CODEX_RESERVE_ROUTE = "gpt-reserve";
67
+ const CODEX_RESERVE_USAGE_NOTICE = "Luna Reserve is a separate, backend-authorized route. Ordinary Luna does not use this reserve, even with Fast off. An unused reserve does not establish eligibility or per-request billing. Ordinary usage may consume credits after included limits are reached.";
68
+ const LIMIT_WINDOW_KEYS = ["primary", "secondary"];
69
+ const ONE_DAY_MS = 864e5;
18
70
  const DAY_WINDOW_MINUTES = 1440;
19
71
  const WEEKLY_WINDOW_MINUTES = 7 * DAY_WINDOW_MINUTES;
20
72
  const WEEKLY_RESET_GAP_MS = 3 * ONE_DAY_MS;
@@ -24,32 +76,18 @@ const optionalNumber = z.number().optional().catch(void 0);
24
76
  const optionalBoolean = z.boolean().optional().catch(void 0);
25
77
  const rateLimitWindowSchema = z.object({
26
78
  usedPercent: optionalNumber,
27
- used_percent: optionalNumber,
28
79
  resetsAt: optionalNumber,
29
- resets_at: optionalNumber,
30
- windowDurationMins: optionalNumber,
31
- window_duration_mins: optionalNumber,
32
- windowMinutes: optionalNumber,
33
- window_minutes: optionalNumber
34
- }).transform((window) => {
35
- const resetsAt = window.resetsAt ?? window.resets_at;
36
- return {
37
- usedPercent: window.usedPercent ?? window.used_percent,
38
- resetsAt,
39
- resetsAtMs: resolveExpiresAtMsFromEpochSeconds(resetsAt, { maxMs: MAX_DATE_TIMESTAMP_MS }) ?? 0,
40
- windowDurationMins: window.windowDurationMins ?? window.window_duration_mins ?? window.windowMinutes ?? window.window_minutes
41
- };
42
- }).optional().catch(void 0);
80
+ windowDurationMins: optionalNumber
81
+ }).transform((window) => ({
82
+ usedPercent: window.usedPercent,
83
+ resetsAtMs: resolveExpiresAtMsFromEpochSeconds(window.resetsAt, { maxMs: MAX_DATE_TIMESTAMP_MS }) ?? 0,
84
+ windowDurationMins: window.windowDurationMins
85
+ })).optional().catch(void 0);
43
86
  const creditsSchema = z.object({
44
87
  hasCredits: optionalBoolean,
45
- has_credits: optionalBoolean,
46
88
  unlimited: optionalBoolean,
47
89
  balance: z.preprocess(parseStrictFiniteNumber, optionalNumber)
48
- }).transform((credits) => ({
49
- hasCredits: credits.hasCredits ?? credits.has_credits,
50
- unlimited: credits.unlimited,
51
- balance: credits.balance
52
- })).optional().catch(void 0);
90
+ }).optional().catch(void 0);
53
91
  const rateLimitSnapshotSchema = z.looseObject({
54
92
  primary: rateLimitWindowSchema,
55
93
  secondary: rateLimitWindowSchema,
@@ -58,19 +96,22 @@ const rateLimitSnapshotSchema = z.looseObject({
58
96
  primary: snapshot.primary,
59
97
  secondary: snapshot.secondary,
60
98
  credits: snapshot.credits,
61
- limitId: normalizeOptionalString(snapshot.limitId) ?? normalizeOptionalString(snapshot.limit_id),
62
- limitName: normalizeOptionalString(snapshot.limitName) ?? normalizeOptionalString(snapshot.limit_name),
63
- planType: normalizeOptionalString(snapshot.planType) ?? normalizeOptionalString(snapshot.plan_type),
64
- rateLimitReachedType: normalizeOptionalString(snapshot.rateLimitReachedType) ?? normalizeOptionalString(snapshot.rate_limit_reached_type)
99
+ limitId: normalizeOptionalString(snapshot.limitId),
100
+ limitName: normalizeOptionalString(snapshot.limitName),
101
+ planType: normalizeOptionalString(snapshot.planType),
102
+ rateLimitReachedType: normalizeOptionalString(snapshot.rateLimitReachedType)
65
103
  }));
66
- /** Enriches Codex usage-limit failures with reset timing and recovery guidance. */
67
104
  function formatCodexUsageLimitErrorMessage(params) {
68
105
  const message = normalizeOptionalString(params.message);
69
- if (!isCodexUsageLimitError(params.codexErrorInfo)) return;
106
+ if (params.codexErrorInfo !== "usageLimitExceeded") return;
70
107
  const nowMs = params.nowMs ?? Date.now();
71
- const usageSummary = summarizeCodexAccountUsage(params.rateLimits, nowMs);
72
- if (params.rateLimitsAuthoritative && hasCodexRateLimitSnapshots(params.rateLimits) && !usageSummary?.blocked) return [CODEX_USAGE_LIMIT_STATE_MISMATCH_MESSAGE, "Retry the request, use another Codex account if available, or switch to another configured model/provider."].join(" ");
73
- const nextReset = selectBlockingRateLimitReset(params.rateLimits, nowMs) ?? (usageSummary?.blocked ? void 0 : selectNextRateLimitReset(params.rateLimits, nowMs));
108
+ const ordinaryUsageAllowed = readOrdinaryUsageAllowed(params.rateLimits);
109
+ const snapshots = collectCodexRateLimitSnapshots(params.rateLimits).filter(snapshotHasDisplayableData);
110
+ const usageSnapshot = snapshots.find(isCodexLimitSnapshot) ?? snapshots[0];
111
+ const blockingSnapshot = selectBlockingRateLimitSnapshot(snapshots, ordinaryUsageAllowed);
112
+ const usageSummary = usageSnapshot ? summarizeRateLimitUsage(usageSnapshot, blockingSnapshot, nowMs) : void 0;
113
+ if (params.rateLimitsAuthoritative && (ordinaryUsageAllowed === true && !blockingSnapshot || ordinaryUsageAllowed === void 0 && usageSummary?.blocked === false)) return [CODEX_USAGE_LIMIT_STATE_MISMATCH_MESSAGE, "Retry the request, use another Codex account if available, or switch to another configured model/provider."].join(" ");
114
+ const nextReset = (blockingSnapshot ? selectSnapshotBlockingReset(blockingSnapshot, nowMs) : void 0) ?? (ordinaryUsageAllowed === void 0 && !usageSummary?.blocked ? selectNextRateLimitReset(params.rateLimits, nowMs) : void 0);
74
115
  const parts = [CODEX_USAGE_LIMIT_MESSAGE_PREFIX];
75
116
  let recoveryAction = "Wait until Codex becomes available";
76
117
  if (nextReset) {
@@ -89,40 +130,42 @@ function formatCodexUsageLimitErrorMessage(params) {
89
130
  parts.push(`${recoveryAction}, use another Codex account if available, or switch to another configured model/provider.`);
90
131
  return parts.join(" ");
91
132
  }
92
- /** Detects usage-limit messages that need a fresh rate-limit query before display. */
93
133
  function shouldRefreshCodexRateLimitsForUsageLimitMessage(message) {
94
134
  const text = normalizeOptionalString(message);
95
135
  return Boolean(text?.startsWith(CODEX_USAGE_LIMIT_MESSAGE_PREFIX) && !text.includes("Next reset "));
96
136
  }
97
- /** Formats compact summaries for raw Codex rate-limit snapshot payloads. */
98
137
  function summarizeCodexRateLimits(value, nowMs = Date.now()) {
99
138
  const snapshots = collectCodexRateLimitSnapshots(value).filter(snapshotHasDisplayableData);
100
139
  if (snapshots.length === 0) return;
101
140
  const summaries = snapshots.slice(0, 4).map((snapshot) => summarizeRateLimitSnapshot(snapshot, nowMs)).filter((summary) => summary !== void 0);
102
- return summaries.length > 0 ? summaries.join("; ") : void 0;
141
+ if (summaries.length === 0) return;
142
+ return [summaries.join("; "), reserveUsageNotice(snapshots)].filter(Boolean).join(". ");
103
143
  }
104
- /** Returns true when a value contains any recognizable Codex rate-limit snapshots. */
105
144
  function hasCodexRateLimitSnapshots(value) {
106
145
  return collectCodexRateLimitSnapshots(value).length > 0;
107
146
  }
108
- /** Builds short account availability lines suitable for status surfaces. */
109
147
  function summarizeCodexAccountRateLimits(value, nowMs = Date.now()) {
110
148
  const summary = summarizeCodexAccountUsage(value, nowMs);
111
149
  if (!summary) return;
112
150
  if (!summary.blocked) return ["Codex is available."];
113
151
  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."];
114
152
  }
115
- /** Returns the reset timestamp for the currently blocking Codex usage limit. */
116
153
  function resolveCodexUsageLimitResetAtMs(value, nowMs = Date.now()) {
117
- return selectBlockingRateLimitReset(value, nowMs)?.resetsAtMs;
154
+ const blockingSnapshot = selectBlockingRateLimitSnapshot(collectCodexRateLimitSnapshots(value), readOrdinaryUsageAllowed(value));
155
+ return blockingSnapshot ? selectSnapshotBlockingReset(blockingSnapshot, nowMs)?.resetsAtMs : void 0;
118
156
  }
119
- /** Summarizes account availability, blocking reason, and reset time from rate-limit data. */
120
157
  function summarizeCodexAccountUsage(value, nowMs = Date.now()) {
121
- const snapshots = collectCodexRateLimitSnapshots(value).filter(snapshotHasDisplayableData);
122
- if (snapshots.length === 0) return;
123
- const usageSnapshot = snapshots.find(isCodexLimitSnapshot) ?? expectDefined(snapshots[0], "displayable Codex rate-limit snapshot");
124
- const blockedSnapshots = snapshots.filter(snapshotHasLimitBlock);
125
- const blockingSnapshot = blockedSnapshots.find(isCodexLimitSnapshot) ?? blockedSnapshots[0] ?? void 0;
158
+ const ordinaryUsageAllowed = readOrdinaryUsageAllowed(value);
159
+ if (ordinaryUsageAllowed === null) return;
160
+ const snapshot = collectCodexRateLimitSnapshots(value).find(isCodexLimitSnapshot);
161
+ if (ordinaryUsageAllowed !== void 0) return {
162
+ usageLine: snapshot ? formatUsageLine(snapshot) : void 0,
163
+ blocked: !ordinaryUsageAllowed,
164
+ ...!ordinaryUsageAllowed ? { blockingReason: "Codex usage limit is reached" } : {}
165
+ };
166
+ return snapshot && snapshotHasDisplayableData(snapshot) ? summarizeRateLimitUsage(snapshot, snapshotHasLimitBlock(snapshot) ? snapshot : void 0, nowMs) : void 0;
167
+ }
168
+ function summarizeRateLimitUsage(usageSnapshot, blockingSnapshot, nowMs) {
126
169
  const blockingEntries = blockingSnapshot ? readWindowEntries(blockingSnapshot) : [];
127
170
  const blockingWindowEntry = selectBlockingWindowEntry(blockingEntries, nowMs);
128
171
  const blockingWindow = blockingWindowEntry?.window;
@@ -141,13 +184,14 @@ function summarizeCodexAccountUsage(value, nowMs = Date.now()) {
141
184
  ...blockingReason ? { blockingReason } : {}
142
185
  };
143
186
  }
144
- /** Converts Codex app-server rate-limit payloads into OpenAI/Codex usage windows. */
145
187
  function buildCodexAppServerUsageSnapshot(value, options = {}) {
146
188
  const snapshots = collectCodexRateLimitSnapshots(value);
147
189
  const snapshot = snapshots.find(isCodexLimitSnapshot) ?? snapshots[0];
148
190
  const entries = snapshot ? readWindowEntries(snapshot) : [];
149
191
  const windows = entries.map((entry) => readProviderUsageWindow(entry, entries)).filter((window) => Boolean(window));
192
+ const summary = reserveUsageNotice(snapshots);
150
193
  const result = {
194
+ ...summary ? { summary } : {},
151
195
  provider: "openai",
152
196
  displayName: PROVIDER_LABELS.openai,
153
197
  windows,
@@ -176,29 +220,21 @@ function buildCodexAppServerUsageSnapshot(value, options = {}) {
176
220
  }
177
221
  return result;
178
222
  }
179
- function isCodexUsageLimitError(codexErrorInfo) {
180
- if (codexErrorInfo === "usageLimitExceeded") return true;
181
- if (typeof codexErrorInfo === "string") {
182
- if (codexErrorInfo.replace(/[_\s-]/gu, "").toLowerCase() === "usagelimitexceeded") return true;
183
- }
184
- return false;
185
- }
186
223
  function selectNextRateLimitReset(value, nowMs) {
187
224
  const futureWindows = collectCodexRateLimitSnapshots(value).flatMap((snapshot) => LIMIT_WINDOW_KEYS.flatMap((key) => snapshot[key] ?? [])).filter((window) => window.resetsAtMs > nowMs);
188
225
  if (futureWindows.length === 0) return;
189
226
  const exhaustedWindows = futureWindows.filter((window) => window.usedPercent !== void 0 && window.usedPercent >= 100);
190
227
  return (exhaustedWindows.length > 0 ? exhaustedWindows : futureWindows).toSorted((left, right) => left.resetsAtMs - right.resetsAtMs)[0];
191
228
  }
192
- function selectBlockingRateLimitReset(value, nowMs) {
193
- const blockedSnapshots = collectCodexRateLimitSnapshots(value).filter(snapshotHasLimitBlock);
194
- const blockingSnapshot = blockedSnapshots.find(isCodexLimitSnapshot) ?? blockedSnapshots[0] ?? void 0;
195
- return blockingSnapshot ? selectSnapshotBlockingReset(blockingSnapshot, nowMs) : void 0;
229
+ function selectBlockingRateLimitSnapshot(snapshots, ordinaryUsageAllowed) {
230
+ const blockedSnapshots = snapshots.filter((snapshot) => snapshotHasLimitBlock(snapshot) && (ordinaryUsageAllowed !== true && ordinaryUsageAllowed !== null || !isCodexLimitSnapshot(snapshot)));
231
+ return blockedSnapshots.find(isCodexLimitSnapshot) ?? blockedSnapshots[0];
196
232
  }
197
233
  function summarizeRateLimitSnapshot(snapshot, nowMs) {
198
234
  const label = formatLimitLabel(snapshot);
199
235
  const windows = LIMIT_WINDOW_KEYS.flatMap((key) => {
200
236
  const window = snapshot[key];
201
- return window ? [formatRateLimitWindow(key, window, nowMs)] : [];
237
+ return window ? [`${key} ${formatRateLimitWindowDetails(window, nowMs)}`] : [];
202
238
  });
203
239
  const reachedType = snapshot.rateLimitReachedType;
204
240
  const suffix = reachedType ? ` (${formatReachedType(reachedType)})` : "";
@@ -206,28 +242,14 @@ function summarizeRateLimitSnapshot(snapshot, nowMs) {
206
242
  if (reachedType) return `${label}: ${formatReachedType(reachedType)}`;
207
243
  }
208
244
  function collectCodexRateLimitSnapshots(value) {
209
- const snapshots = [];
210
- collectRateLimitSnapshots(value, snapshots, /* @__PURE__ */ new Set());
211
- return snapshots;
212
- }
213
- function collectRateLimitSnapshots(value, snapshots, seen) {
214
- if (Array.isArray(value)) {
215
- for (const entry of value) collectRateLimitSnapshots(entry, snapshots, seen);
216
- return;
217
- }
218
- if (!isJsonObject(value)) return;
219
- if (isRateLimitSnapshot(value)) {
220
- addRateLimitSnapshot(rateLimitSnapshotSchema.parse(value), snapshots, seen);
221
- return;
222
- }
245
+ if (!isJsonObject(value)) return [];
246
+ if (isRateLimitSnapshot(value)) return [rateLimitSnapshotSchema.parse(value)];
223
247
  const byLimitId = value.rateLimitsByLimitId;
224
- if (isJsonObject(byLimitId)) for (const key of sortedRateLimitKeys(Object.keys(byLimitId))) collectRateLimitSnapshots(byLimitId[key], snapshots, seen);
225
- const snakeByLimitId = value.rate_limits_by_limit_id;
226
- if (isJsonObject(snakeByLimitId)) for (const key of sortedRateLimitKeys(Object.keys(snakeByLimitId))) collectRateLimitSnapshots(snakeByLimitId[key], snapshots, seen);
227
- collectRateLimitSnapshots(value.rateLimits, snapshots, seen);
228
- collectRateLimitSnapshots(value.rate_limits, snapshots, seen);
229
- collectRateLimitSnapshots(value.data, snapshots, seen);
230
- collectRateLimitSnapshots(value.items, snapshots, seen);
248
+ return (isJsonObject(byLimitId) ? sortedRateLimitKeys(Object.keys(byLimitId)).map((key) => byLimitId[key]) : [value.rateLimits]).filter(isJsonObject).filter(isRateLimitSnapshot).map((snapshot) => rateLimitSnapshotSchema.parse(snapshot));
249
+ }
250
+ function readOrdinaryUsageAllowed(value) {
251
+ const allowed = isJsonObject(value) ? value.ordinaryUsageAllowed : void 0;
252
+ return allowed === null || typeof allowed === "boolean" ? allowed : void 0;
231
253
  }
232
254
  function sortedRateLimitKeys(keys) {
233
255
  return keys.toSorted((left, right) => {
@@ -236,33 +258,26 @@ function sortedRateLimitKeys(keys) {
236
258
  return left.localeCompare(right);
237
259
  });
238
260
  }
239
- function addRateLimitSnapshot(snapshot, snapshots, seen) {
240
- const signature = [
241
- snapshot.limitId ?? "",
242
- snapshot.limitName ?? "",
243
- formatWindowSignature(snapshot.primary),
244
- formatWindowSignature(snapshot.secondary)
245
- ].join("|");
246
- if (seen.has(signature)) return;
247
- seen.add(signature);
248
- snapshots.push(snapshot);
249
- }
250
261
  function isRateLimitSnapshot(value) {
251
- return isJsonObject(value.primary) || isJsonObject(value.secondary) || value.rateLimitReachedType !== void 0 || value.rate_limit_reached_type !== void 0 || value.limitId !== void 0 || value.limit_id !== void 0 || value.limitName !== void 0 || value.limit_name !== void 0;
262
+ return isJsonObject(value.primary) || isJsonObject(value.secondary) || value.rateLimitReachedType !== void 0 || value.limitId !== void 0 || value.limitName !== void 0;
252
263
  }
253
264
  function snapshotHasDisplayableData(snapshot) {
254
265
  return Boolean(snapshot.rateLimitReachedType) || readWindowEntries(snapshot).some((entry) => entry.window.usedPercent !== void 0 || entry.window.resetsAtMs > 0);
255
266
  }
256
- function formatRateLimitWindow(key, window, nowMs) {
257
- return `${key} ${formatRateLimitWindowDetails(window, nowMs)}`;
258
- }
259
267
  function formatRateLimitWindowDetails(window, nowMs) {
260
268
  return `${window.usedPercent === void 0 ? "usage unknown" : `${Math.max(0, 100 - Math.round(window.usedPercent))}% left`}${window.resetsAtMs > nowMs ? ` ⏱${formatResetDuration(window.resetsAtMs, nowMs)}` : ""}`;
261
269
  }
270
+ function reserveUsageNotice(snapshots) {
271
+ return snapshots.some(isReserveSnapshot) ? CODEX_RESERVE_USAGE_NOTICE : void 0;
272
+ }
273
+ function isReserveSnapshot(snapshot) {
274
+ return snapshot.limitName === CODEX_RESERVE_ROUTE || snapshot.limitId === CODEX_RESERVE_ROUTE;
275
+ }
262
276
  function formatLimitLabel(snapshot) {
277
+ if (isReserveSnapshot(snapshot)) return "Luna Reserve (separate route)";
263
278
  const label = snapshot.limitName ?? snapshot.limitId;
264
279
  if (!label || label === CODEX_LIMIT_ID) return "Codex";
265
- return label.replace(/[_-]+/gu, " ").replace(/\s+/gu, " ").trim();
280
+ return formatReachedType(label);
266
281
  }
267
282
  function formatReachedType(value) {
268
283
  return value.replace(/[_-]+/gu, " ").replace(/\s+/gu, " ").trim();
@@ -312,11 +327,8 @@ function formatCodexCreditSummary(credits) {
312
327
  return roundedBalance > 0 ? `${roundedBalance} credits` : void 0;
313
328
  }
314
329
  function selectSnapshotBlockingReset(snapshot, nowMs) {
315
- const futureWindows = readWindowEntries(snapshot).map((entry) => entry.window).filter((window) => window.resetsAtMs > nowMs);
316
- const exhaustedWindows = futureWindows.filter((window) => window.usedPercent !== void 0 && window.usedPercent >= 100);
317
- const candidates = exhaustedWindows.length > 0 ? exhaustedWindows : futureWindows;
318
- const resetSort = exhaustedWindows.length > 0 ? (left, right) => right.resetsAtMs - left.resetsAtMs : (left, right) => left.resetsAtMs - right.resetsAtMs;
319
- return candidates.toSorted(resetSort)[0];
330
+ const window = selectBlockingWindowEntry(readWindowEntries(snapshot), nowMs)?.window;
331
+ return window && window.resetsAtMs > nowMs ? window : void 0;
320
332
  }
321
333
  function selectBlockingWindowEntry(entries, nowMs) {
322
334
  const futureEntries = entries.filter((entry) => entry.window.resetsAtMs > nowMs);
@@ -351,10 +363,9 @@ function formatUsageLine(snapshot) {
351
363
  return windows.length > 0 ? windows.join(" · ") : void 0;
352
364
  }
353
365
  function formatUsageWindowLabel(entry, entries) {
366
+ const period = formatBlockingLimitPeriod(entry, entries);
367
+ if (period) return period;
354
368
  const minutes = entry.window.windowDurationMins;
355
- if (minutes === WEEKLY_WINDOW_MINUTES || hasWeeklySecondaryResetCadence(entry, entries)) return "weekly";
356
- if (minutes === DAY_WINDOW_MINUTES) return "daily";
357
- if (minutes !== void 0 && minutes > 0 && minutes < DAY_WINDOW_MINUTES) return "short-term";
358
369
  if (minutes !== void 0 && minutes > 0 && minutes % DAY_WINDOW_MINUTES === 0) return `${minutes / DAY_WINDOW_MINUTES}-day`;
359
370
  if (minutes !== void 0 && minutes > 0 && minutes % 60 === 0) return `${minutes / 60}-hour`;
360
371
  return "usage";
@@ -364,60 +375,6 @@ function hasWeeklySecondaryResetCadence(entry, entries) {
364
375
  const primaryResetMs = entries.find((candidate) => candidate.key === "primary")?.window.resetsAtMs;
365
376
  return typeof primaryResetMs === "number" && primaryResetMs > 0 && entry.window.resetsAtMs > 0 && entry.window.resetsAtMs - primaryResetMs >= WEEKLY_RESET_GAP_MS;
366
377
  }
367
- function formatCalendarResetTime(resetsAtMs, nowMs) {
368
- const resetDate = new Date(resetsAtMs);
369
- const resetParts = new Intl.DateTimeFormat("en-US", {
370
- month: "short",
371
- day: "numeric",
372
- ...resetDate.getFullYear() === new Date(nowMs).getFullYear() ? {} : { year: "numeric" },
373
- hour: "numeric",
374
- minute: "2-digit",
375
- timeZoneName: "short"
376
- }).formatToParts(resetDate);
377
- const part = (type) => resetParts.find((entry) => entry.type === type)?.value;
378
- const dateParts = [
379
- part("month"),
380
- part("day"),
381
- part("year")
382
- ].filter(Boolean);
383
- return [
384
- dateParts.length > 1 ? `${dateParts[0]} ${dateParts.slice(1).join(", ")}` : dateParts[0],
385
- "at",
386
- [
387
- [part("hour"), part("minute")].filter(Boolean).join(":"),
388
- part("dayPeriod"),
389
- part("timeZoneName")
390
- ].filter(Boolean).join(" ")
391
- ].filter(Boolean).join(" ");
392
- }
393
- function formatRelativeDuration(durationMs) {
394
- const safeMs = Math.max(1e3, durationMs);
395
- if (safeMs < ONE_MINUTE_MS) return `${Math.ceil(safeMs / 1e3)} seconds`;
396
- if (safeMs < ONE_HOUR_MS) {
397
- const minutes = Math.ceil(safeMs / ONE_MINUTE_MS);
398
- return `${minutes} ${minutes === 1 ? "minute" : "minutes"}`;
399
- }
400
- if (safeMs < ONE_DAY_MS) {
401
- const hours = Math.ceil(safeMs / ONE_HOUR_MS);
402
- return `${hours} ${hours === 1 ? "hour" : "hours"}`;
403
- }
404
- const days = Math.ceil(safeMs / ONE_DAY_MS);
405
- return `${days} ${days === 1 ? "day" : "days"}`;
406
- }
407
- function formatResetDuration(resetsAtMs, nowMs) {
408
- const durationMs = Math.round(Math.max(ONE_SECOND_MS, resetsAtMs - nowMs) / ONE_SECOND_MS) * ONE_SECOND_MS;
409
- const days = Math.floor(durationMs / ONE_DAY_MS);
410
- const hours = Math.floor(durationMs % ONE_DAY_MS / ONE_HOUR_MS);
411
- const minutes = Math.floor(durationMs % ONE_HOUR_MS / ONE_MINUTE_MS);
412
- const seconds = Math.floor(durationMs % ONE_MINUTE_MS / ONE_SECOND_MS);
413
- if (days > 0) return hours > 0 ? `${days}d ${hours}h` : `${days}d`;
414
- if (hours > 0) return minutes > 0 ? `${hours}h ${minutes}m` : `${hours}h`;
415
- if (minutes > 0) return seconds > 0 ? `${minutes}m ${seconds}s` : `${minutes}m`;
416
- return `${seconds}s`;
417
- }
418
- function formatWindowSignature(window) {
419
- return window ? `${window.usedPercent ?? ""}:${window.resetsAt ?? ""}` : "";
420
- }
421
378
  function extractCodexRetryHint(message) {
422
379
  if (!message) return;
423
380
  const tryAgainAt = /\btry again\s+(at\s+[^.!?\n]+)(?:[.!?]|$)/iu.exec(message);
@@ -425,4 +382,4 @@ function extractCodexRetryHint(message) {
425
382
  return /\btry again\s+((?:tomorrow|in\s+[^.!?\n]+)[^.!?\n]*)(?:[.!?]|$)/iu.exec(message)?.[1]?.trim();
426
383
  }
427
384
  //#endregion
428
- export { shouldRefreshCodexRateLimitsForUsageLimitMessage as a, summarizeCodexRateLimits as c, resolveCodexUsageLimitResetAtMs as i, formatCodexUsageLimitErrorMessage as n, summarizeCodexAccountRateLimits as o, hasCodexRateLimitSnapshots as r, summarizeCodexAccountUsage as s, buildCodexAppServerUsageSnapshot as t };
385
+ export { shouldRefreshCodexRateLimitsForUsageLimitMessage as a, summarizeCodexRateLimits as c, resolveCodexUsageLimitResetAtMs as i, formatRelativeDuration as l, formatCodexUsageLimitErrorMessage as n, summarizeCodexAccountRateLimits as o, hasCodexRateLimitSnapshots as r, summarizeCodexAccountUsage as s, buildCodexAppServerUsageSnapshot as t };