@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,285 @@
1
+ import { i as isJsonObject } from "./protocol-CANUwXJ3.mjs";
2
+ import { n as projectCodexCatalogNativeResponse, r as projectCodexCatalogNativeThread } from "./session-catalog-native-projection-DjhwGL6x.mjs";
3
+ import { coerceErrorMessage } from "openclaw/plugin-sdk/error-runtime";
4
+ import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
5
+ import { sanitizeTerminalText } from "openclaw/plugin-sdk/text-chunking";
6
+ //#region extensions/codex/src/app-server/protocol-json.ts
7
+ function isRpcResponse(message) {
8
+ return message !== null && typeof message === "object" && "id" in message && (typeof message.id === "number" || typeof message.id === "string") && !("method" in message);
9
+ }
10
+ //#endregion
11
+ //#region extensions/codex/src/app-server/client-line-preview.ts
12
+ const CODEX_APP_SERVER_PARSE_LOG_MAX = 500;
13
+ function redactCodexAppServerLinePreview(value) {
14
+ const redacted = value.replace(/\s+/g, " ").trim().replace(/(Bearer\s+)[A-Za-z0-9._~+/-]+/gi, "$1<redacted>").replace(/("(?:api_?key|authorization|token|access_token|refresh_token)"\s*:\s*")([^"]+)(")/gi, "$1<redacted>$3").replace(/\b([a-z0-9_]*(?:api_?key|authorization|access_token|refresh_token|token))(\s*=\s*)(["']?)[^\s"']+(\3)/gi, "$1$2$3<redacted>$4");
15
+ return redacted.length > CODEX_APP_SERVER_PARSE_LOG_MAX ? `${truncateUtf16Safe(redacted, CODEX_APP_SERVER_PARSE_LOG_MAX)}...` : redacted;
16
+ }
17
+ //#endregion
18
+ //#region extensions/codex/src/app-server/client-message-decoder.ts
19
+ const PARSE_BUFFER_MAX = 8388608;
20
+ const PARSE_BUFFER_MAX_LINES = 1e3;
21
+ const UNICODE_ESCAPE_QUAD = /^[\da-fA-F]{4}$/u;
22
+ /** Recovers the raw newlines observed inside native JSON string values. */
23
+ var CodexAppServerMessageDecoder = class {
24
+ constructor(reportError) {
25
+ this.reportError = reportError;
26
+ }
27
+ clear() {
28
+ this.pending = void 0;
29
+ }
30
+ get hasPending() {
31
+ return this.pending !== void 0;
32
+ }
33
+ parse(line) {
34
+ const rawLine = line.endsWith("\r") ? line.slice(0, -1) : line;
35
+ if (this.pending) return this.parseContinuation(rawLine, this.pending);
36
+ const trimmed = rawLine.trim();
37
+ if (!trimmed) return;
38
+ try {
39
+ return JSON.parse(trimmed);
40
+ } catch (error) {
41
+ if (isRecoverableParseFailure(trimmed, error)) {
42
+ const text = rawLine.trimStart();
43
+ this.pending = {
44
+ fragments: [text],
45
+ length: text.length,
46
+ inString: endsInsideJsonString(text)
47
+ };
48
+ } else this.reportError(trimmed, error, 1);
49
+ }
50
+ }
51
+ parseContinuation(line, pending) {
52
+ pending.fragments.push(line);
53
+ pending.length += 2 + line.length;
54
+ const withinBounds = pending.length <= PARSE_BUFFER_MAX && pending.fragments.length <= PARSE_BUFFER_MAX_LINES;
55
+ if (withinBounds && pending.inString && scanJsonString(line, 0) === line.length) return;
56
+ const candidate = pending.fragments.join("\\n");
57
+ this.pending = void 0;
58
+ try {
59
+ return JSON.parse(candidate);
60
+ } catch (error) {
61
+ if (withinBounds && isRecoverableParseFailure(candidate, error)) {
62
+ pending.inString = endsInsideJsonString(candidate);
63
+ this.pending = pending;
64
+ } else this.reportError(candidate, error, pending.fragments.length);
65
+ }
66
+ }
67
+ };
68
+ function isRecoverableParseFailure(value, error) {
69
+ if (!value.startsWith("{") && !value.startsWith("[")) return false;
70
+ const message = coerceErrorMessage(error);
71
+ return message.includes("Unterminated string") || message.includes("Unexpected end of JSON input");
72
+ }
73
+ function endsInsideJsonString(value) {
74
+ for (let index = 0; index < value.length; index++) {
75
+ if (value[index] !== "\"") continue;
76
+ const end = scanJsonString(value, index + 1);
77
+ if (end < 0) return false;
78
+ if (end === value.length) return true;
79
+ index = end;
80
+ }
81
+ return false;
82
+ }
83
+ /** Finds a closing quote; incomplete or invalid escapes require native parsing. */
84
+ function scanJsonString(value, start) {
85
+ for (let index = start; index < value.length; index++) {
86
+ const character = value[index];
87
+ if (character === "\"") return index;
88
+ if (value.charCodeAt(index) < 32) return -1;
89
+ if (character !== "\\") continue;
90
+ const escape = value[++index];
91
+ if (escape === "u") {
92
+ if (!UNICODE_ESCAPE_QUAD.test(value.slice(index + 1, index + 5))) return -1;
93
+ index += 4;
94
+ } else if (!escape || !"\"\\/bfnrt".includes(escape)) return -1;
95
+ }
96
+ return value.length;
97
+ }
98
+ //#endregion
99
+ //#region extensions/codex/src/app-server/client-message-frames.ts
100
+ const UNPAIRED_SURROGATE_RE = /[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g;
101
+ /** One byte reader owns framing and stops at an asynchronous page decode. */
102
+ function listenCodexAppServerLines(input, onLine, onError) {
103
+ let fragments = [];
104
+ let length = 0;
105
+ let remainder;
106
+ let waiting = false;
107
+ let ended = false;
108
+ let closed = false;
109
+ const close = () => {
110
+ closed = true;
111
+ fragments = [];
112
+ remainder = void 0;
113
+ input.off("data", onData);
114
+ input.off("end", onEnd);
115
+ input.pause();
116
+ };
117
+ const deliver = (tail) => {
118
+ const line = fragments.length ? Buffer.concat([...fragments, tail], length + tail.length) : tail;
119
+ fragments = [];
120
+ length = 0;
121
+ const completion = onLine(line);
122
+ if (!completion) return true;
123
+ waiting = true;
124
+ input.pause();
125
+ completion.then(() => {
126
+ waiting = false;
127
+ if (!closed) {
128
+ drain();
129
+ if (!waiting && !ended && !closed) input.resume();
130
+ }
131
+ }).catch((error) => {
132
+ close();
133
+ onError(error);
134
+ });
135
+ return false;
136
+ };
137
+ const drain = () => {
138
+ try {
139
+ const chunk = remainder;
140
+ remainder = void 0;
141
+ if (chunk) {
142
+ let start = 0;
143
+ let end;
144
+ while ((end = chunk.indexOf(10, start)) !== -1) {
145
+ if (closed) return;
146
+ remainder = chunk.subarray(end + 1);
147
+ if (!deliver(chunk.subarray(start, end))) return;
148
+ remainder = void 0;
149
+ start = end + 1;
150
+ }
151
+ if (!closed && start < chunk.length) {
152
+ fragments.push(chunk.subarray(start));
153
+ length += chunk.length - start;
154
+ }
155
+ }
156
+ if (ended && !closed) {
157
+ if (length && !deliver(Buffer.alloc(0))) return;
158
+ close();
159
+ }
160
+ } catch (error) {
161
+ close();
162
+ onError(error);
163
+ }
164
+ };
165
+ const onData = (chunk) => {
166
+ remainder = chunk;
167
+ drain();
168
+ };
169
+ const onEnd = () => {
170
+ ended = true;
171
+ if (!waiting) drain();
172
+ };
173
+ input.on("data", onData);
174
+ input.once("end", onEnd);
175
+ return close;
176
+ }
177
+ function codexCatalogResponseRoute(id) {
178
+ return typeof id === "number" && Number.isSafeInteger(id) && id >= 2 ** 52 ? {
179
+ id,
180
+ kind: id % 2 === 1 ? "list" : "thread"
181
+ } : void 0;
182
+ }
183
+ /** Read bounded envelope keys and IDs; skip native payload strings as bytes. */
184
+ function readCodexCatalogDecodeRoute(line) {
185
+ let depth = 0;
186
+ let route;
187
+ let response = false;
188
+ for (let index = 0; index < line.length; index++) {
189
+ const byte = line[index];
190
+ if (byte === 123 || byte === 91) depth++;
191
+ else if (byte === 125 || byte === 93) depth--;
192
+ else if (byte === 34) {
193
+ const start = index;
194
+ for (;;) {
195
+ index = line.indexOf(34, index + 1);
196
+ if (index < 0) return "unresolved";
197
+ let slash = index - 1;
198
+ while (line[slash] === 92) slash--;
199
+ if ((index - slash) % 2 === 1) break;
200
+ }
201
+ if (depth !== 1 || index - start > 64) continue;
202
+ let colon = index + 1;
203
+ while (line[colon] === 32 || line[colon] === 9 || line[colon] === 13) colon++;
204
+ if (line[colon] !== 58) continue;
205
+ const token = line.toString("utf8", start, index + 1);
206
+ let key = token.slice(1, -1);
207
+ if (token.includes("\\")) try {
208
+ key = JSON.parse(token);
209
+ } catch {
210
+ return "unresolved";
211
+ }
212
+ if (key === "method") return;
213
+ if (key === "result" || key === "error") {
214
+ response = true;
215
+ if (route) return route;
216
+ }
217
+ if (key !== "id") continue;
218
+ const match = /^\s*:\s*(\d+)(?=\s*[,}])/u.exec(line.toString("utf8", index + 1, Math.min(index + 100, line.length)));
219
+ if (!match) continue;
220
+ route = codexCatalogResponseRoute(Number(match[1]));
221
+ if (!route || response) return route;
222
+ }
223
+ }
224
+ return response || route ? "unresolved" : void 0;
225
+ }
226
+ function stringifyCodexAppServerMessage(message) {
227
+ return JSON.stringify(message, (_key, value) => typeof value === "string" ? value.replace(UNPAIRED_SURROGATE_RE, "") : value) ?? "null";
228
+ }
229
+ //#endregion
230
+ //#region extensions/codex/src/app-server/client-catalog-response.ts
231
+ /** The worker retains recovery fragments, but never a completed native page. */
232
+ function createCodexCatalogDecoder() {
233
+ let failures = [];
234
+ const decoder = new CodexAppServerMessageDecoder((value, error, fragmentCount) => {
235
+ failures.push({
236
+ value: redactCodexAppServerLinePreview(value),
237
+ error,
238
+ fragmentCount
239
+ });
240
+ });
241
+ return (input) => {
242
+ failures = [];
243
+ const result = projectCodexCatalogMessage(decoder.parse(Buffer.from(input.bytes.buffer, input.bytes.byteOffset, input.bytes.byteLength).toString("utf8")), input);
244
+ result.pending = decoder.hasPending;
245
+ result.failures = failures;
246
+ return result;
247
+ };
248
+ }
249
+ function projectCodexCatalogMessage(parsed, input, cachedPreview) {
250
+ const result = {
251
+ pending: false,
252
+ failures: []
253
+ };
254
+ if (!isJsonObject(parsed)) return result;
255
+ result.message = parsed;
256
+ if (!isRpcResponse(parsed)) return result;
257
+ const message = parsed;
258
+ const route = codexCatalogResponseRoute(message.id);
259
+ if (message.error || !route) return result;
260
+ const remainingRows = input.route === "unresolved" ? input.catalogRows?.has(route.id) ? input.catalogRows.get(route.id) : 0 : input.remainingRows;
261
+ try {
262
+ if (!isJsonObject(message.result)) throw new Error("Codex catalog response contains an invalid result");
263
+ if (route.kind === "list") {
264
+ const raw = message.result;
265
+ message.result = projectCodexCatalogNativeResponse(raw, sanitizeTerminalText, cachedPreview, remainingRows);
266
+ if (!cachedPreview) result.previewStates = Array.isArray(raw.data) ? raw.data.slice(0, Array.isArray(message.result.data) ? message.result.data.length : 0).map((row) => isJsonObject(row) && typeof row.preview === "string" ? Boolean(row.preview) : void 0) : [];
267
+ } else {
268
+ const thread = message.result.thread;
269
+ message.result = { thread: {
270
+ ...projectCodexCatalogNativeThread(thread, sanitizeTerminalText),
271
+ ...isJsonObject(thread) && typeof thread.cwd === "string" ? { cwd: thread.cwd } : {},
272
+ ...isJsonObject(thread) && (thread.historyMode === "paginated" || thread.historyMode === "legacy") ? { historyMode: thread.historyMode } : {}
273
+ } };
274
+ }
275
+ } catch (error) {
276
+ delete result.message;
277
+ result.projectionError = {
278
+ id: route.id,
279
+ error: error instanceof Error ? error : new Error("Codex catalog projection failed", { cause: error })
280
+ };
281
+ }
282
+ return result;
283
+ }
284
+ //#endregion
285
+ export { stringifyCodexAppServerMessage as a, isRpcResponse as c, readCodexCatalogDecodeRoute as i, projectCodexCatalogMessage as n, CodexAppServerMessageDecoder as o, listenCodexAppServerLines as r, redactCodexAppServerLinePreview as s, createCodexCatalogDecoder as t };
@@ -1,11 +1,16 @@
1
- import { o as formatCodexDisplayText } from "./command-formatters-CGEkdawF.mjs";
2
- import { n as describeControlFailure } from "./capabilities-_vXcZGSx.mjs";
1
+ import { o as formatCodexDisplayText } from "./command-formatters-R3ckE3Co.mjs";
2
+ import { n as describeControlFailure } from "./capabilities-B3WEZl4e.mjs";
3
3
  //#region extensions/codex/src/command-dispatch.ts
4
4
  /** Dispatches a `/codex` command to the lazily loaded handler. */
5
5
  async function handleCodexCommand(ctx, options) {
6
- const { loadSubcommandHandler, resolvePluginConfig, ...subcommandOptions } = options;
6
+ const commandContext = {
7
+ ...ctx,
8
+ gatewayClientScopes: ctx.gatewayClientScopes?.slice()
9
+ };
10
+ const { resolvePluginConfig, ...subcommandOptions } = options;
7
11
  try {
8
- return await (loadSubcommandHandler ? await loadSubcommandHandler() : await loadDefaultCodexSubcommandHandler())(ctx, {
12
+ const { handleCodexSubcommand } = await import("./command-handlers-ylTMS00z.mjs");
13
+ return await handleCodexSubcommand(commandContext, {
9
14
  ...subcommandOptions,
10
15
  pluginConfig: resolvePluginConfig?.() ?? subcommandOptions.pluginConfig
11
16
  });
@@ -13,9 +18,5 @@ async function handleCodexCommand(ctx, options) {
13
18
  return { text: `Codex command failed: ${formatCodexDisplayText(describeControlFailure(error))}` };
14
19
  }
15
20
  }
16
- async function loadDefaultCodexSubcommandHandler() {
17
- const { handleCodexSubcommand } = await import("./command-handlers-BtAJEW1X.mjs");
18
- return handleCodexSubcommand;
19
- }
20
21
  //#endregion
21
22
  export { handleCodexCommand };
@@ -1,30 +1,27 @@
1
- import { m as isJsonObject } from "./config-security-BRQ2mgW9.mjs";
2
- import { c as summarizeCodexRateLimits, o as summarizeCodexAccountRateLimits, r as hasCodexRateLimitSnapshots } from "./rate-limits-DOEGYRNs.mjs";
1
+ import { i as isJsonObject } from "./protocol-CANUwXJ3.mjs";
2
+ import { c as summarizeCodexRateLimits, o as summarizeCodexAccountRateLimits, r as hasCodexRateLimitSnapshots } from "./rate-limits-B7-X2TgG.mjs";
3
3
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
4
4
  //#region extensions/codex/src/command-formatters.ts
5
5
  /**
6
6
  * Formats Codex command responses for safe chat display, including status,
7
7
  * lists, account summaries, and user-facing help text.
8
8
  */
9
- /** Formats the combined `/codex status` probe result. */
10
9
  function formatCodexStatus(probes) {
11
10
  const lines = [`Codex app-server: ${probes.models.ok || probes.account.ok || probes.limits.ok || probes.mcps.ok || probes.skills.ok ? "connected" : "unavailable"}`];
12
11
  if (probes.models.ok) lines.push(`Models: ${probes.models.value.models.map((model) => formatCodexDisplayText(model.id)).slice(0, 8).join(", ") || "none"}`);
13
12
  else lines.push(`Models: ${formatCodexDisplayText(probes.models.error)}`);
14
- lines.push(`Account: ${probes.account.ok ? formatCodexAccountSummary(probes.account.value) : formatCodexDisplayText(probes.account.error)}`);
15
- lines.push(`Rate limits: ${probes.limits.ok ? formatCodexRateLimitSummary(probes.limits.value) : formatCodexDisplayText(probes.limits.error)}`);
16
- lines.push(`MCP servers: ${probes.mcps.ok ? summarizeArrayLike(probes.mcps.value) : formatCodexDisplayText(probes.mcps.error)}`);
17
- lines.push(`Skills: ${probes.skills.ok ? summarizeCodexSkills(probes.skills.value) : formatCodexDisplayText(probes.skills.error)}`);
13
+ lines.push(`Account: ${formatProbe(probes.account, formatCodexAccountSummary)}`, `Rate limits: ${formatProbe(probes.limits, formatCodexRateLimitSummary)}`, `MCP servers: ${formatProbe(probes.mcps, summarizeArrayLike)}`, `Skills: ${formatProbe(probes.skills, summarizeCodexSkills)}`);
18
14
  return lines.join("\n");
19
15
  }
20
- /** Formats Codex model-list results for `/codex models`. */
16
+ function formatProbe(probe, format) {
17
+ return probe.ok ? format(probe.value) : formatCodexDisplayText(probe.error);
18
+ }
21
19
  function formatModels(result) {
22
20
  if (result.models.length === 0) return "No Codex app-server models returned.";
23
21
  const lines = ["Codex models:", ...result.models.map((model) => `- ${formatCodexDisplayText(model.id)}${model.isDefault ? " (default)" : ""}`)];
24
22
  if (result.truncated) lines.push("- More models available; output truncated.");
25
23
  return lines.join("\n");
26
24
  }
27
- /** Formats Codex thread-list responses with safe resume hints. */
28
25
  function formatThreads(response) {
29
26
  const threads = extractArray(response);
30
27
  if (threads.length === 0) return "No Codex threads returned.";
@@ -40,12 +37,15 @@ function formatThreads(response) {
40
37
  return `- ${formatCodexDisplayText(id)}${title ? ` - ${formatCodexDisplayText(title)}` : ""}${details.length > 0 ? ` (${details.map(formatCodexDisplayText).join(", ")})` : ""}\n Resume: ${formatCodexResumeHint(id)}`;
41
38
  })].join("\n");
42
39
  }
43
- /** Formats account and rate-limit output for `/codex account`. */
44
40
  function formatAccount(account, limits, authOverview) {
45
- if (authOverview) return formatAccountAuthOverview(authOverview);
41
+ if (authOverview?.rows.some((row) => row.active)) return formatAccountAuthOverview(authOverview);
46
42
  const formattedLimits = limits.ok ? formatCodexRateLimitDetails(limits.value) : formatCodexDisplayText(limits.error);
47
43
  const rateLimitBlock = formattedLimits.startsWith("Codex is ") ? formattedLimits : formattedLimits.includes("\n") ? `Rate limits:\n${formattedLimits}` : `Rate limits: ${formattedLimits}`;
48
- return [`Account: ${account.ok ? formatCodexAccountSummary(account.value) : formatCodexDisplayText(account.error)}`, rateLimitBlock].join("\n\n");
44
+ return [
45
+ `Account: ${account.ok ? formatCodexAccountSummary(account.value) : formatCodexDisplayText(account.error)}`,
46
+ rateLimitBlock,
47
+ ...authOverview ? [formatAccountAuthOverview(authOverview)] : []
48
+ ].join("\n\n");
49
49
  }
50
50
  function formatAccountAuthOverview(overview) {
51
51
  const lines = [];
@@ -57,22 +57,20 @@ function formatAccountAuthOverview(overview) {
57
57
  }
58
58
  if (overview.rows.length > 0) {
59
59
  lines.push(overview.orderTitle);
60
- for (const [index, row] of overview.rows.entries()) lines.push(` ${index + 1}. ${row.label} ${row.kind} — ${formatAuthRowStatus(row)}`);
60
+ for (const [index, row] of overview.rows.entries()) lines.push(` ${index + 1}. ${row.label} ${row.kind} — ${row.billingNote ? `${row.status} · ${row.billingNote}` : row.status}`);
61
61
  }
62
62
  while (lines.at(-1) === "") lines.pop();
63
63
  return lines.map(formatCodexAccountLine).join("\n");
64
64
  }
65
- function formatAuthRowStatus(row) {
66
- return row.billingNote ? `${row.status} · ${row.billingNote}` : row.status;
67
- }
68
- /** Formats Codex Computer Use readiness and plugin/MCP availability. */
69
65
  function formatComputerUseStatus(status) {
70
- const lines = [`Computer Use: ${status.ready ? "ready" : status.enabled ? "not ready" : "disabled"}`];
71
- lines.push(`Plugin: ${formatCodexDisplayText(status.pluginName)} (${computerUsePluginState(status)})`);
72
- lines.push(`Installation: ${formatCodexDisplayText(status.installation.status)} (${status.installation.ok ? "ok" : "not ok"})`);
73
- lines.push(`MCP server: ${formatCodexDisplayText(status.mcpServerName)}${status.mcpServerAvailable ? ` (${status.tools.length} tools)` : " (unavailable)"}`);
74
- lines.push(`Exposure: ${formatCodexDisplayText(status.exposure.status)} (${status.exposure.ok ? "ok" : "not ok"})`);
75
- lines.push(`Live test: ${formatCodexDisplayText(status.liveTest.status)} (${status.liveTest.attempted ? `${status.liveTest.attempts} attempt${status.liveTest.attempts === 1 ? "" : "s"}, ${status.liveTest.timeoutMs}ms` : "not run"})`);
66
+ const lines = [
67
+ `Computer Use: ${status.ready ? "ready" : status.enabled ? "not ready" : "disabled"}`,
68
+ `Plugin: ${formatCodexDisplayText(status.pluginName)} (${computerUsePluginState(status)})`,
69
+ `Installation: ${formatCodexDisplayText(status.installation.status)} (${status.installation.ok ? "ok" : "not ok"})`,
70
+ `MCP server: ${formatCodexDisplayText(status.mcpServerName)}${status.mcpServerAvailable ? ` (${status.tools.length} tools)` : " (unavailable)"}`,
71
+ `Exposure: ${formatCodexDisplayText(status.exposure.status)} (${status.exposure.ok ? "ok" : "not ok"})`,
72
+ `Live test: ${formatCodexDisplayText(status.liveTest.status)} (${status.liveTest.attempted ? `${status.liveTest.attempts} attempt${status.liveTest.attempts === 1 ? "" : "s"}, ${status.liveTest.timeoutMs}ms` : "not run"})`
73
+ ];
76
74
  if (status.liveTest.retried || status.liveTest.repaired) lines.push(`Live test recovery: retried=${status.liveTest.retried ? "yes" : "no"}, repaired=${status.liveTest.repaired ? "yes" : "no"}`);
77
75
  if (status.marketplaceName) lines.push(`Marketplace: ${formatCodexDisplayText(status.marketplaceName)}`);
78
76
  if (status.tools.length > 0) lines.push(`Tools: ${status.tools.slice(0, 8).map(formatCodexDisplayText).join(", ")}`);
@@ -81,10 +79,10 @@ function formatComputerUseStatus(status) {
81
79
  return lines.join("\n");
82
80
  }
83
81
  function computerUsePluginState(status) {
82
+ if (status.installed === null) return "installation unchecked";
84
83
  if (!status.installed) return "not installed";
85
84
  return status.pluginEnabled ? "installed" : "installed, disabled";
86
85
  }
87
- /** Formats generic array-like Codex app-server responses. */
88
86
  function formatList(response, label) {
89
87
  const entries = extractArray(response);
90
88
  if (entries.length === 0) return `${label}: none returned.`;
@@ -93,29 +91,9 @@ function formatList(response, label) {
93
91
  return `- ${formatCodexDisplayText(normalizeOptionalString(record.name) ?? normalizeOptionalString(record.id) ?? JSON.stringify(entry))}`;
94
92
  })].join("\n");
95
93
  }
96
- /** Formats Codex skills grouped by scope, omitting disabled entries. */
97
94
  function formatSkills(response) {
98
- const groups = isJsonObject(response) && Array.isArray(response.data) ? response.data : [];
99
- if (groups.length === 0) return "Codex skills: none returned.";
100
- const lines = ["Codex skills:"];
101
- let renderedSkills = 0;
102
- let loadErrors = 0;
103
- for (const group of groups) {
104
- const record = isJsonObject(group) ? group : {};
105
- if (Array.isArray(record.errors)) loadErrors += record.errors.length;
106
- const skills = Array.isArray(record.skills) ? record.skills : [];
107
- if (skills.length === 0) continue;
108
- for (const skill of skills) {
109
- if (isJsonObject(skill) && skill.enabled === false) continue;
110
- lines.push(`- ${formatCodexSkillEntry(skill)}`);
111
- renderedSkills += 1;
112
- }
113
- }
114
- if (renderedSkills === 0) {
115
- if (loadErrors > 0) return `Codex skills: none returned (${loadErrors} load ${loadErrors === 1 ? "error" : "errors"}).`;
116
- return "Codex skills: none returned.";
117
- }
118
- return lines.join("\n");
95
+ const { skills, emptySummary } = readEnabledCodexSkills(response);
96
+ return skills.length > 0 ? ["Codex skills:", ...skills.map((skill) => `- ${formatCodexSkillEntry(skill)}`)].join("\n") : `Codex skills: ${emptySummary}.`;
119
97
  }
120
98
  function formatCodexSkillEntry(entry) {
121
99
  const record = isJsonObject(entry) ? entry : {};
@@ -139,12 +117,7 @@ function formatCodexTextForDisplay(value) {
139
117
  return sanitizeCodexTextForDisplay(value).trim() || "<unknown>";
140
118
  }
141
119
  function sanitizeCodexTextForDisplay(value) {
142
- let safe = "";
143
- for (const character of value) {
144
- const codePoint = character.codePointAt(0);
145
- safe += codePoint != null && isUnsafeDisplayCodePoint(codePoint) ? "?" : character;
146
- }
147
- return safe;
120
+ return value.replace(/[\p{Cc}\u00ad\u061c\u180e\u200b-\u200f\u202a-\u202e\u2060-\u206f\ufeff\ufff9-\ufffb\u{e0000}-\u{e007f}]/gu, "?");
148
121
  }
149
122
  function escapeCodexChatText(value) {
150
123
  return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("@", "@").replaceAll("`", "`").replaceAll("[", "[").replaceAll("]", "]").replaceAll("(", "(").replaceAll(")", ")").replaceAll("*", "∗").replaceAll("_", "_").replaceAll("~", "~").replaceAll("|", "|");
@@ -171,10 +144,6 @@ function formatCodexAccountLine(value) {
171
144
  function isLikelyEmailAddress(value) {
172
145
  return /^[^\s@<>()[\]`]+@[^\s@<>()[\]`]+\.[^\s@<>()[\]`]+$/.test(value);
173
146
  }
174
- function isUnsafeDisplayCodePoint(codePoint) {
175
- return codePoint <= 31 || codePoint >= 127 && codePoint <= 159 || codePoint === 173 || codePoint === 1564 || codePoint === 6158 || codePoint >= 8203 && codePoint <= 8207 || codePoint >= 8234 && codePoint <= 8238 || codePoint >= 8288 && codePoint <= 8303 || codePoint === 65279 || codePoint >= 65529 && codePoint <= 65531 || codePoint >= 917504 && codePoint <= 917631;
176
- }
177
- /** Builds the portable `/codex` command help text. */
178
147
  function buildHelp() {
179
148
  return [
180
149
  "Codex commands:",
@@ -215,20 +184,23 @@ function summarizeArrayLike(value) {
215
184
  if (entries.length === 0) return "none returned";
216
185
  return `${entries.length}`;
217
186
  }
218
- function summarizeCodexSkills(value) {
187
+ function readEnabledCodexSkills(value) {
219
188
  const groups = isJsonObject(value) && Array.isArray(value.data) ? value.data : [];
220
- if (groups.length === 0) return "none returned";
221
- let enabledSkills = 0;
189
+ const skills = [];
222
190
  let loadErrors = 0;
223
191
  for (const group of groups) {
224
192
  if (!isJsonObject(group)) continue;
225
193
  if (Array.isArray(group.errors)) loadErrors += group.errors.length;
226
- if (!Array.isArray(group.skills)) continue;
227
- enabledSkills += group.skills.filter((skill) => !isJsonObject(skill) || skill.enabled !== false).length;
194
+ for (const skill of Array.isArray(group.skills) ? group.skills : []) if (!isJsonObject(skill) || skill.enabled !== false) skills.push(skill);
228
195
  }
229
- if (enabledSkills > 0) return `${enabledSkills}`;
230
- if (loadErrors > 0) return `none returned (${loadErrors} load ${loadErrors === 1 ? "error" : "errors"})`;
231
- return "none returned";
196
+ return {
197
+ skills,
198
+ emptySummary: loadErrors > 0 ? `none returned (${loadErrors} load ${loadErrors === 1 ? "error" : "errors"})` : "none returned"
199
+ };
200
+ }
201
+ function summarizeCodexSkills(value) {
202
+ const { skills, emptySummary } = readEnabledCodexSkills(value);
203
+ return skills.length > 0 ? `${skills.length}` : emptySummary;
232
204
  }
233
205
  function formatCodexRateLimitSummary(value) {
234
206
  const summary = summarizeCodexRateLimits(value);