dsh-codex-connect 0.1.0-alpha.4.27 → 0.1.0-alpha.4.29

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.
package/INSTALL.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Installation Runbook for CLI Agents
2
2
 
3
- Alpha 4.27 is verified with DSH `0.1.2-rc.1` and its declared pi-ai range `^0.84.2`.
3
+ Alpha 4.29 is verified with DSH `0.1.2-rc.1` and its declared pi-ai range `^0.84.2`.
4
4
 
5
5
  Install `dsh-codex-connect` into one requested DeepSeek Harness profile without changing its current default model, search route, global configuration, or OAuth state.
6
6
 
@@ -23,14 +23,14 @@ Check `dsh --version` before changing the requested profile. Use `dsh --help` to
23
23
  | `0.1.0-rc.7` | `0.1.0-alpha.4.14` |
24
24
  | `0.1.1-rc.2` | `0.1.0-alpha.4.21` |
25
25
  | `0.1.2-alpha.2` | `0.1.0-alpha.4.23` |
26
- | `0.1.2-rc.1` | `0.1.0-alpha.4.27` |
26
+ | `0.1.2-rc.1` | `0.1.0-alpha.4.29` |
27
27
  | `0.1.2-alpha.5` | `0.1.0-alpha.4.25` |
28
28
 
29
29
  If your exact DSH version is unknown or not listed, stop and verify the combination before installing. Do not blindly install `dsh-codex-connect@alpha`: `alpha` is a moving tag, not a compatibility guarantee. Do not infer support for newer DSH versions from these rows.
30
30
 
31
- Alpha 4.27's verified contract is DSH plugin API packages `0.1.2-rc.1`, `@earendil-works/pi-ai` `^0.84.2`, and Node.js `^22.19.0 || >=24.0.0`. Alpha 4.25 remains the verified choice for DSH `0.1.2-alpha.5`, Alpha 4.23 remains the verified choice for DSH `0.1.2-alpha.2`, Alpha 4.21 remains the verified choice for DSH `0.1.1-rc.2`, and staying on DSH `0.1.0-rc.7` means selecting Alpha 4.14. Upgrading DSH is a separate decision: upgrade the DSH API packages and pi-ai together, then rerun `dsh-codex-connect doctor --json` and `pnpm --silent run check:compatibility` for the selected combination.
31
+ Alpha 4.29's verified contract is DSH plugin API packages `0.1.2-rc.1`, `@earendil-works/pi-ai` `^0.84.2`, and Node.js `^22.19.0 || >=24.0.0`. Alpha 4.25 remains the verified choice for DSH `0.1.2-alpha.5`, Alpha 4.23 remains the verified choice for DSH `0.1.2-alpha.2`, Alpha 4.21 remains the verified choice for DSH `0.1.1-rc.2`, and staying on DSH `0.1.0-rc.7` means selecting Alpha 4.14. Upgrading DSH is a separate decision: upgrade the DSH API packages and pi-ai together, then rerun `dsh-codex-connect doctor --json` and `pnpm --silent run check:compatibility` for the selected combination.
32
32
 
33
- The Alpha 4.27 row reflects a fresh isolated installation and runtime probe. Historical rows remain the repository's existing verification record. This guidance does not change upstream DSH behavior or resolve [Issue #64](https://github.com/franksong2702/dsh-codex-connect/issues/64).
33
+ The Alpha 4.29 row reflects a fresh isolated installation and runtime probe. Historical rows remain the repository's existing verification record. This guidance does not change upstream DSH behavior or resolve [Issue #64](https://github.com/franksong2702/dsh-codex-connect/issues/64).
34
34
 
35
35
  ### Install the selected version and validate
36
36
 
@@ -53,10 +53,10 @@ The Alpha 4.27 row reflects a fresh isolated installation and runtime probe. His
53
53
  dsh plugin --profile web add dsh-codex-connect@0.1.0-alpha.4.23
54
54
  ```
55
55
 
56
- For DSH `0.1.2-rc.1`, use Alpha 4.27:
56
+ For DSH `0.1.2-rc.1`, use Alpha 4.29:
57
57
 
58
58
  ```sh
59
- dsh plugin --profile web add dsh-codex-connect@0.1.0-alpha.4.27
59
+ dsh plugin --profile web add dsh-codex-connect@0.1.0-alpha.4.29
60
60
  ```
61
61
 
62
62
  For DSH `0.1.2-alpha.5`, use Alpha 4.25:
@@ -65,7 +65,7 @@ The Alpha 4.27 row reflects a fresh isolated installation and runtime probe. His
65
65
  dsh plugin --profile web add dsh-codex-connect@0.1.0-alpha.4.25
66
66
  ```
67
67
 
68
- If npm is unavailable after the matching GitHub prerelease is created, use `dsh plugin --profile web add 'github:franksong2702/dsh-codex-connect#v0.1.0-alpha.4.21'` only for the DSH `0.1.1-rc.2` combination, `dsh plugin --profile web add 'github:franksong2702/dsh-codex-connect#v0.1.0-alpha.4.23'` only for the DSH `0.1.2-alpha.2` combination, `dsh plugin --profile web add 'github:franksong2702/dsh-codex-connect#v0.1.0-alpha.4.25'` only for the DSH `0.1.2-alpha.5` combination, or `dsh plugin --profile web add 'github:franksong2702/dsh-codex-connect#v0.1.0-alpha.4.27'` only for the DSH `0.1.2-rc.1` combination.
68
+ If npm is unavailable after the matching GitHub prerelease is created, use `dsh plugin --profile web add 'github:franksong2702/dsh-codex-connect#v0.1.0-alpha.4.21'` only for the DSH `0.1.1-rc.2` combination, `dsh plugin --profile web add 'github:franksong2702/dsh-codex-connect#v0.1.0-alpha.4.23'` only for the DSH `0.1.2-alpha.2` combination, `dsh plugin --profile web add 'github:franksong2702/dsh-codex-connect#v0.1.0-alpha.4.25'` only for the DSH `0.1.2-alpha.5` combination, or `dsh plugin --profile web add 'github:franksong2702/dsh-codex-connect#v0.1.0-alpha.4.29'` only for the DSH `0.1.2-rc.1` combination.
69
69
 
70
70
  3. Run `dsh web --help` once to compose the installed profile without starting the server. DSH `0.1.2-rc.1` prepares profile plugin dependency fallback during this step.
71
71
  4. Run `dsh --profile web --dump-config` and require exactly one `llm-openai-codex` row loading `dsh-codex-connect`.
package/NOTICE CHANGED
@@ -13,3 +13,8 @@ release validation.
13
13
 
14
14
  The upstream material and the Codex Connect modifications are distributed
15
15
  under the Apache License, Version 2.0 included in LICENSE.
16
+
17
+ This product also includes OAuth login and refresh code from earendil-works/pi
18
+ (@earendil-works/pi-ai 0.84.4), under the MIT license reproduced in
19
+ docs/licenses/pi-ai-oauth.txt. JWT payload decoding, callback connection cleanup
20
+ and structured refresh rejection handling are modified.
package/README.i18n.yaml CHANGED
@@ -2,5 +2,5 @@
2
2
  # side as of the last confirmed-consistent state. Both languages carry equal authority;
3
3
  # after editing either side, bring the other along and re-record with:
4
4
  # git hash-object README.md docs/README.zh.md
5
- README.md: c135f207b65d25355ffa0dadf44a18732cad765f
6
- docs/README.zh.md: c95461b5c330da72852c0161ee1b05625b7f914b
5
+ README.md: 02e02fc550c598823a846a1938f2146dbf826418
6
+ docs/README.zh.md: 5587a2ad4853e2479aa03a414a4199baba92b1c0
package/README.md CHANGED
@@ -32,7 +32,7 @@ The command below is the verified public pairing for DSH `0.1.2-rc.1`. Check `ds
32
32
  ### 1. Install one exact version
33
33
 
34
34
  ```sh
35
- dsh plugin --profile web add dsh-codex-connect@0.1.0-alpha.4.27
35
+ dsh plugin --profile web add dsh-codex-connect@0.1.0-alpha.4.29
36
36
  ```
37
37
 
38
38
  Replace `web` with your existing profile name. From a DeepSeek Harness source checkout, prefix commands with `pnpm`. Installation must leave the profile's default model and search route unchanged.
@@ -70,11 +70,18 @@ The effective configuration should contain exactly one `llm-openai-codex` row. A
70
70
  The Models card and the Plugin configuration page share the same account state. **Manage accounts** can add, select, or remove accounts. Browser responses expose only plugin-generated account keys and masked labels, never OAuth tokens or raw OpenAI account ids.
71
71
 
72
72
  - Adding an account leaves the current account usable while authorization is pending.
73
- - Cancelling or timing out a new authorization preserves every existing account. Pending authorization expires after 10 minutes by default; `oauthTimeoutMs` accepts 1,000–1,800,000 milliseconds and is applied when the plugin loads.
74
- - Switching accounts affects subsequent requests. A request captures its account before resolving authentication, so a concurrent switch cannot mix credentials.
73
+ - Cancelling or timing out a new authorization preserves every existing account and closes accepted callback connections, including incomplete HTTP requests. After cancellation, the browser reads account labels and quota together before updating the view. Pending authorization expires after 10 minutes by default; `oauthTimeoutMs` accepts 1,000–1,800,000 milliseconds and is applied when the plugin loads.
74
+ - Switching accounts affects subsequent requests. A request captures its account before resolving authentication, so a concurrent switch cannot mix credentials. If that account becomes unavailable during authentication, the request fails and requires an explicit retry with the selected account.
75
+ - Quota, search, image generation and Auto-review keep that same account through token refresh. Each quota response pairs its usage and account labels from one snapshot; a concurrent switch may leave an older snapshot visible until the next refresh, but does not relabel its quota as another account's.
75
76
  - Removing the active account requires selecting a replacement when another account remains. Removing the last account signs out; **Sign out all accounts** deletes all locally stored Codex credentials.
76
77
  - Codex Connect does not rotate accounts automatically or fail over when a request is rejected.
77
78
 
79
+ Credential changes wait up to 20 seconds for the writer lock, allowing an in-progress token refresh to finish. A lock timeout fails the operation without deleting another writer's lock or changing stored accounts. A lock left behind by a crashed process requires operator recovery after confirming that no writer is running.
80
+
81
+ Request authentication failures use fixed messages without upstream response bodies or nested provider errors. A failed refresh preserves the stored credentials.
82
+
83
+ An explicit OAuth `invalid_grant` rejection during refresh shows the reauthorization prompt. Network failures, timeouts and server errors keep the account selected and show a quota error so you can retry; they do not delete credentials or start a new login.
84
+
78
85
  For GPT Codex conversations, the Composer shows two session controls:
79
86
 
80
87
  - **Fast Mode** requests the faster `1.5×` mode for that conversation only. It is off by default and does not change the model.
@@ -98,15 +105,18 @@ Fresh installations register the model provider and leave every additional capab
98
105
  enableAutoReview: false
99
106
  ```
100
107
 
101
- Edit these options under **Settings → Plugins → Plugin configuration → Codex Connect** or **Settings → Models → Openai-Codex → More settings**. Changes are staged until **Save changes**. Most settings affect only this plugin; enabling Codex Search also selects it as the active profile-wide search route.
108
+ Edit these options under **Settings → Plugins → Plugin configuration → Codex Connect** or **Settings → Models → Openai-Codex → More settings**. Changes are staged until **Save changes**. Saving commits edited fields together and preserves concurrent changes to untouched fields. A conflicting edit or failed save keeps your draft; discard it to reload the latest settings. Most settings affect only this plugin; enabling Codex Search also selects it as the active profile-wide search route.
102
109
 
103
110
  ### Proxy
104
111
 
112
+ Disabling the proxy or unloading the plugin gives active proxy operations one second to finish, then destroys this instance's pools with a further one-second completion limit. New proxy operations are rejected during shutdown; interrupted requests are not retried directly. Arbitrary application callbacks cannot be forcibly terminated by the proxy manager. The scoped dispatcher remains until late callbacks settle, so they cannot bypass their destroyed proxy; unrelated traffic still uses the host dispatcher.
113
+
105
114
  Direct connection is the default. An enabled credential-free HTTP(S) proxy applies only to this plugin's model, OAuth, refresh, quota, search, image, and Auto-review traffic. Detection checks standard proxy environment variables and documented loopback candidates without making a model call, consuming quota, or saving settings. A failed proxy request never silently retries through a direct connection. Loading Codex Connect does not replace Node's environment-proxy dispatcher, so unrelated Harness requests continue using the process's existing proxy policy.
106
115
 
107
116
  ### Search and image tools
108
117
 
109
118
  - `enableSearch: true` registers Codex as an available search provider and selects it for profile-wide searches. Disabling it unregisters the provider and restores the route that was active before Codex Search was enabled.
119
+ - Search has a 30-second total deadline covering authentication, response headers and body reading. Responses larger than 1 MiB are rejected, and unfinished response bodies are cancelled on failure. Caller cancellation can end a search sooner.
110
120
  - `enableImageTool: true` registers `view_image` on vision-capable models. Remote reads accept credential-free public HTTP(S) only and revalidate DNS and redirects.
111
121
  - `enableImageGeneration: true` registers prompt-only GPT Image generation. Use the image generation capability included with your current GPT subscription. Availability, dimensions, and quota remain account- and service-controlled.
112
122
 
package/docs/README.zh.md CHANGED
@@ -32,7 +32,7 @@ Codex Connect 为 DeepSeek Harness 添加 ChatGPT OAuth 和 `openai-codex` 模
32
32
  ### 1. 安装一个精确版本
33
33
 
34
34
  ```sh
35
- dsh plugin --profile web add dsh-codex-connect@0.1.0-alpha.4.27
35
+ dsh plugin --profile web add dsh-codex-connect@0.1.0-alpha.4.29
36
36
  ```
37
37
 
38
38
  将 `web` 替换为你正在使用的 profile 名。从 DeepSeek Harness 源码 checkout 执行时,请在命令前加 `pnpm`。安装后,profile 的默认模型和搜索路由必须保持不变。
@@ -70,11 +70,18 @@ dsh plugin --profile web exec dsh-codex-connect doctor --json
70
70
  “模型”卡片和“插件配置”页面共享同一份账户状态。**管理账户**可以添加、选择或移除账户。浏览器响应只会包含插件生成的账户 key 和脱敏标签,不会暴露 OAuth token 或原始 OpenAI account id。
71
71
 
72
72
  - 添加账户期间,当前账户仍可继续使用。
73
- - 取消新的授权或等待超时,不会删除任何已有账户。待处理授权默认 10 分钟后过期;`oauthTimeoutMs` 接受 1,000–1,800,000 毫秒,并在插件加载时应用。
74
- - 切换账户只影响后续请求。每个请求会在解析认证前固定当前账户,因此并发切换不会混用凭据。
73
+ - 取消新的授权或等待超时,不会删除任何已有账户,并会关闭已接受的回调连接,包括未完成的 HTTP 请求。取消后,浏览器会一起读取账户标签与额度,再更新显示。待处理授权默认 10 分钟后过期;`oauthTimeoutMs` 接受 1,000–1,800,000 毫秒,并在插件加载时应用。
74
+ - 切换账户只影响后续请求。每个请求会在解析认证前固定当前账户,因此并发切换不会混用凭据。如果该账户在认证过程中变得不可用,请求会失败,需要使用所选账户显式重试。
75
+ - 额度、搜索、图片生成和自动审查会在 token 刷新期间保持同一请求账户。每次额度响应的用量与账户标签来自同一快照;并发切换时,旧快照可能显示到下次刷新,但不会把它的额度标为另一个账户的。
75
76
  - 如果还有其他账户,移除当前账户时必须选择替代账户;移除最后一个账户即退出登录;**退出所有账户**会删除本地保存的全部 Codex 凭据。
76
77
  - 请求被拒绝时,Codex Connect 不会自动轮换账户或进行故障切换。
77
78
 
79
+ 凭据修改最多等待写锁 20 秒,以便正在进行的 token 刷新完成。等待超时会使操作失败,但不会删除其他写入者的锁或更改已保存的账户。进程崩溃遗留的锁需要操作者确认没有写入者运行后再恢复。
80
+
81
+ 请求认证失败时使用固定提示,不包含上游响应正文或嵌套的提供方异常。刷新失败会保留已保存的凭据。
82
+
83
+ 刷新时收到明确的 OAuth `invalid_grant` 拒绝,会显示重新授权提示。网络故障、超时和服务端错误会保留当前账户并显示额度查询错误,供你重试;不会删除凭据或启动新的登录。
84
+
78
85
  GPT Codex 对话的 Composer 会显示两个会话级控件:
79
86
 
80
87
  - **Fast Mode** 只为当前对话请求更快的 `1.5×` 模式。默认关闭,也不会更换模型。
@@ -98,15 +105,18 @@ GPT Codex 对话的 Composer 会显示两个会话级控件:
98
105
  enableAutoReview: false
99
106
  ```
100
107
 
101
- 请在 **设置 → 插件 → 插件配置 → Codex Connect** 或 **设置 → 模型 → Openai-Codex → 更多设置** 中编辑这些选项。修改会暂存到点击 **保存更改** 为止。大多数设置只影响本插件;启用 Codex 搜索还会把它选为整个 profile 当前使用的搜索路由。
108
+ 请在 **设置 → 插件 → 插件配置 → Codex Connect** 或 **设置 → 模型 → Openai-Codex → 更多设置** 中编辑这些选项。修改会暂存到点击 **保存更改** 为止。保存会一次提交所有已编辑字段,并保留其他页面对未编辑字段的修改。发生编辑冲突或保存失败时会保留草稿;放弃草稿可重新加载最新设置。大多数设置只影响本插件;启用 Codex 搜索还会把它选为整个 profile 当前使用的搜索路由。
102
109
 
103
110
  ### 代理
104
111
 
112
+ 关闭代理或卸载插件时,先给活动代理操作一秒收尾,再销毁本实例的连接池,最多再等待一秒完成。关闭期间拒绝新的代理操作;被中断的请求不会改走直连重试。代理管理器无法强制终止任意应用回调。作用域 dispatcher 会保留至迟到回调结束,防止它们绕过已销毁的代理;无关流量仍使用宿主 dispatcher。
113
+
105
114
  默认使用直连。启用后,不带凭据的 HTTP(S) proxy 只应用于本插件的模型、OAuth、刷新、额度、搜索、图片和自动审查流量。检测只检查标准代理环境变量和文档列出的 loopback 候选地址,不调用模型、不消耗额度,也不保存设置。代理请求失败时,绝不会静默改走直连。加载 Codex Connect 不会替换 Node 的环境代理 dispatcher,因此其他 Harness 请求会继续使用进程已有的代理策略。
106
115
 
107
116
  ### 搜索与图片工具
108
117
 
109
118
  - `enableSearch: true` 将 Codex 注册为可用搜索提供方,并用于整个 profile 的搜索。关闭时会注销该提供方,并恢复启用 Codex 搜索之前的路由。
119
+ - 搜索从认证开始到读完响应共用 30 秒总期限。超过 1 MiB 的响应会被拒绝,失败时会取消尚未读完的响应体。调用方也可以提前取消搜索。
110
120
  - `enableImageTool: true` 为具备视觉能力的模型注册 `view_image`。远程读取只接受不带凭据的公网 HTTP(S),并重新检查 DNS 与重定向。
111
121
  - `enableImageGeneration: true` 注册只接受提示词的 GPT Image 图片生成。使用你当前 GPT 订阅计划提供的图片生成能力。可用性、尺寸和额度仍由账户及服务端控制。
112
122
 
@@ -0,0 +1,9 @@
1
+ # Account recovery state
2
+
3
+ Cancellation ignores the status-only mutation response and reads the same combined account/quota endpoint used by other account mutations. The browser publishes that pair together. If the read fails, it retains the prior pair and reports an operation error; normal retry scheduling remains active.
4
+
5
+ The pinned OAuth implementation retains an explicit HTTP 400/401 `invalid_grant` JSON response as a typed, secret-free refresh rejection. Request authentication converts the pi-ai OAuth wrapper into `REAUTH_REQUIRED`; quota status maps it to the existing reauthorization UI. Network failures, timeouts, 5xx, rate limits, malformed responses and client-configuration failures do not establish revoked credentials. They remain safe generic failures and preserve the stored account.
6
+
7
+ The vendored implementation now supplies login and refresh through pi-ai's public OAuth provider methods. pi-ai still schedules refresh and the credential store still serializes it and commits only a successful result. This preserves structured errors before upstream formatting discards their fields; it does not parse arbitrary exception messages. Vendor generation verifies both patches against pi-ai 0.84.4. Remove a patch only after the upstream behavior passes its corresponding regression.
8
+
9
+ Regression tests use two independent account stores against the real account routes and temporary credential files, and real pi-ai refresh resolution with fixture HTTP responses. No real account or authorization is required. JWT payload decoding is covered by the [OAuth decoding note](oauth-jwt-decoding.md).
@@ -0,0 +1,5 @@
1
+ # Public authentication diagnostics
2
+
3
+ Browser and CLI authentication failures expose only a closed vocabulary of messages. Unknown provider errors and nested causes are not copied into public diagnostics. Numeric usage HTTP statuses remain available without response bodies. This also intentionally removes arbitrary filesystem and provider error detail from these public outputs.
4
+
5
+ The refresh regression uses the installed pi-ai OAuth implementation and a synthetic malformed response. Separate browser-route and CLI regressions exercise the public sinks. No real credentials or account access are required.
@@ -0,0 +1,7 @@
1
+ # Host dispatcher preservation
2
+
3
+ Undici v1 and v2 dispatchers retain separate protocol slots. Initialization preserves an existing host v1 dispatcher without assigning it to the incompatible v2 slot. A separate runtime chunk initializes before provider evaluation. The HTTP helper uses CommonJS loading because Node 26's node:http ESM facade initializes built-in Undici during module linking, before preservation code can execute.
4
+
5
+ During proxy ownership, unrelated v1 requests use their original dispatcher; scoped requests use Undici's v1 bridge. Unrelated v2 requests use their original v2 dispatcher. Reacquisition captures third-party replacements in a new immutable wrapper, so third-party wrappers retaining an older dispatcher do not form cycles. Final disposal restores only objects still owned by the plugin and preserves independent v1 and v2 replacements.
6
+
7
+ Fresh-process checks cover custom legacy dispatchers and environment proxies. Node 22 and 24 native fetch consumes v1; Node 26 native fetch consumes v2, so the legacy protocol is also exercised directly. This change does not add operation deadlines or change proxy drain limits.
@@ -0,0 +1,9 @@
1
+ # OAuth cancellation and credential commits
2
+
3
+ Credential modification checks cancellation before waiting and immediately before invoking the mutation callback under the file lock. The callback is pi-ai's commit point: cancellation before invocation prevents mutation; cancellation after invocation waits for the mutation result. Cross-process serialization and atomic replacement remain unchanged.
4
+
5
+ The same cancellation checks apply to captured-account stores used for request authentication. The wrapper forwards operation options and checks cancellation before calling a refresh callback, without updating its request-local credential on rejection.
6
+
7
+ The regression combines the installed pi-ai login orchestration with the real credential store and file lock. OAuth returns a synthetic credential while another writer holds the lock. Cancellation returns before the lock is released; the queued mutation then rejects without adding or activating an account. A separate control verifies that cancellation after callback invocation does not report failure for a completed commit.
8
+
9
+ This change does not extend lock wait limits or change callback-server socket shutdown.
@@ -0,0 +1,7 @@
1
+ # OAuth JWT payload decoding
2
+
3
+ The pinned OAuth copy decodes the payload using the base64url alphabet and a fatal UTF-8 decoder before JSON parsing. Existing account identity validation still requires a nonempty string. Padding is accepted for compatibility with existing fixtures, while invalid alphabet characters and invalid UTF-8 fail. This is claim extraction from an OAuth response, not JWT signature verification or an entitlement check.
4
+
5
+ Login and refresh use the same decoder. Failed extraction prevents a credential commit; refresh cannot change the captured account identity. The reproducible vendor script owns the patch and rejects an unexpected upstream decoder before rewriting anything.
6
+
7
+ Tests exercise actual device-code login and refresh resolution against temporary credential files with fixture HTTP responses. They cover both base64url-specific characters, unpadded payloads, Unicode identities and claims, malformed JSON, invalid UTF-8, missing/invalid account identities and unchanged old credentials after failure. No real credentials or device authorization are used.
@@ -0,0 +1,7 @@
1
+ # Request response lifecycle
2
+
3
+ Quota reads cancel discarded non-success response bodies before reporting the HTTP status. Cancellation failure does not replace the status or the existing HTTP 401/403 reauthorization result. Successful response parsing is unchanged.
4
+
5
+ Proxy probes recognize native `TimeoutError` exceptions and explicit timeout codes through nested causes. Caller cancellation remains a connection failure rather than an operation timeout. DNS, connection-refused and TLS classifications retain their existing string-code handling.
6
+
7
+ Regression tests use a local HTTP server with an unfinished error body to verify prompt socket closure, plus fixture responses for cancellation failure and reauthorization. Probe tests use the native `AbortSignal.timeout` reason and nested network errors. These checks do not establish real provider availability or real-account acceptance.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Mario Zechner
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/lib/bin.js CHANGED
@@ -1,8 +1,9 @@
1
1
  #!/usr/bin/env node
2
- import { Bt as OPENAI_CODEX_PROVIDER, Dt as OpenAICodexTrustedOriginsStore, Ft as openAICodexModelCatalog, H as DSH_PLUGIN_API_PACKAGES, Ht as openAICodexAuthPath, Mt as loginOpenAICodex, N as CODEX_CONNECT_VERSION, Nt as logoutOpenAICodex, Ot as normalizeTrustedOrigin, Pt as openAICodexAuthStatus, Vt as OpenAICodexCredentialStore, X as readInstalledPackageVersion, Y as evaluateCompatibility, bt as ProxyAgent, c as migrateOpenAICodexSearchHistory, d as OPENAI_CODEX_BASE_URL, gt as normalizeOpenAICodexProxyUrl, j as diagnoseOpenAICodex, l as CODEX_AUTO_REVIEW_MODEL, u as probeCodexAutoReview, xt as fetch, yt as Agent } from "./src-BcyhDCEJ.js";
2
+ import { At as loginOpenAICodex, Bt as openAICodexAuthPath, H as DSH_PLUGIN_API_PACKAGES, Mt as openAICodexAuthStatus, N as CODEX_CONNECT_VERSION, Nt as publicAuthError, Rt as OPENAI_CODEX_PROVIDER, Tt as normalizeTrustedOrigin, X as readInstalledPackageVersion, Y as evaluateCompatibility, c as migrateOpenAICodexSearchHistory, d as OPENAI_CODEX_BASE_URL, gt as normalizeOpenAICodexProxyUrl, j as diagnoseOpenAICodex, jt as logoutOpenAICodex, kt as openAICodexModelCatalog, l as CODEX_AUTO_REVIEW_MODEL, u as probeCodexAutoReview, wt as OpenAICodexTrustedOriginsStore, zt as OpenAICodexCredentialStore } from "./src-BNfobpwF.js";
3
+ import { i as fetch, r as ProxyAgent, t as Agent } from "./undici-runtime-H2uktiw6.js";
3
4
  import { createHash } from "node:crypto";
4
- import { fileURLToPath } from "node:url";
5
5
  import { realpathSync } from "node:fs";
6
+ import { fileURLToPath } from "node:url";
6
7
  import { spawn } from "node:child_process";
7
8
  import { createInterface } from "node:readline/promises";
8
9
  //#region src/capability-probe.ts
@@ -511,10 +512,6 @@ function openBrowser(rawUrl) {
511
512
  child.unref();
512
513
  } catch {}
513
514
  }
514
- /** Remove token-like strings from an external OAuth diagnostic. */
515
- function safeMessage(error) {
516
- return (error instanceof Error ? error.message : String(error)).replace(/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/gu, "[redacted token]").replace(/(\b(?:code|token|refresh_token|access_token)=)[^&\s]+/giu, "$1[redacted]");
517
- }
518
515
  /** Render one provider event without exposing stored credentials. */
519
516
  function notify(event, useBrowser) {
520
517
  switch (event.type) {
@@ -744,7 +741,7 @@ async function run(argv) {
744
741
  }
745
742
  }
746
743
  } catch (error) {
747
- process.stderr.write(`dsh-codex-connect: ${action} failed: ${safeMessage(error)}\n`);
744
+ process.stderr.write(`dsh-codex-connect: ${action} failed: ${publicAuthError(error)}\n`);
748
745
  return 1;
749
746
  }
750
747
  }
package/lib/client.js CHANGED
@@ -299,6 +299,7 @@ window.__ModuleLoader__.load({
299
299
  }
300
300
  stableStatus(status, accounts) {
301
301
  if (status.status !== "signing-in" || accounts.length === 0) return status;
302
+ if (accounts.find((account) => account.active)?.accountKey !== this.snapshot.accounts.find((account) => account.active)?.accountKey) return status;
302
303
  return this.snapshot.status.status === "signed-in" || this.snapshot.status.status === "reauth-required" ? this.snapshot.status : status;
303
304
  }
304
305
  /** Refresh only while observed, without overlapping status reads or OAuth mutations. */
@@ -387,11 +388,12 @@ window.__ModuleLoader__.load({
387
388
  operation: { kind: "cancelling-authorization" }
388
389
  });
389
390
  try {
390
- const status = parseStatus(await request(OPENAI_CODEX_AUTH_CANCEL_PATH, "POST"));
391
+ await request(OPENAI_CODEX_AUTH_CANCEL_PATH, "POST");
392
+ const { status, accounts } = await this.readServerState();
391
393
  this.publish({
392
394
  status,
393
395
  busy: false,
394
- accounts: this.snapshot.accounts,
396
+ accounts,
395
397
  operation: { kind: "idle" }
396
398
  });
397
399
  } catch (error) {
@@ -462,8 +464,8 @@ window.__ModuleLoader__.load({
462
464
  }
463
465
  });
464
466
  try {
465
- const status = parseStatus(await request(OPENAI_CODEX_AUTH_ACCOUNTS_PATH, method, void 0, body));
466
- const accounts = parseAccounts(await request(OPENAI_CODEX_AUTH_ACCOUNTS_PATH));
467
+ await request(OPENAI_CODEX_AUTH_ACCOUNTS_PATH, method, void 0, body);
468
+ const { status, accounts } = await this.readServerState();
467
469
  this.publish({
468
470
  status,
469
471
  accounts,
@@ -910,15 +912,13 @@ window.__ModuleLoader__.load({
910
912
  if (left === void 0 || right === void 0) return left === right;
911
913
  return Array.isArray(left) && Array.isArray(right) && left.length === right.length && left.every((model, index) => model === right[index]);
912
914
  }
913
- function sameConfig(left, right) {
914
- return left !== void 0 && right !== void 0 && CONFIG_FIELDS.every((field) => sameField(field, left[field], right[field]));
915
- }
916
915
  /** Edit the Host-owned llm-openai-codex settings section with Save/Discard staging. */
917
916
  function OpenAICodexConfiguration({ scope, t, activeModule, panelIdPrefix }) {
918
917
  const subscribe = (0, react.useCallback)((listener) => scope?.subscribe(listener) ?? (() => void 0), [scope]);
919
918
  const getSnapshot = (0, react.useCallback)(() => scope?.getSnapshot() ?? UNAVAILABLE_SNAPSHOT, [scope]);
920
919
  const snapshot = (0, react.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
921
920
  const [draft, setDraft] = (0, react.useState)(snapshot.value);
921
+ const baseline = (0, react.useRef)(snapshot.value);
922
922
  const [dirty, setDirty] = (0, react.useState)(false);
923
923
  const [busy, setBusy] = (0, react.useState)(false);
924
924
  const [feedback, setFeedback] = (0, react.useState)("idle");
@@ -960,6 +960,7 @@ window.__ModuleLoader__.load({
960
960
  }, [scope]);
961
961
  (0, react.useEffect)(() => {
962
962
  if (!dirty && !busy) {
963
+ baseline.current = snapshot.value;
963
964
  setDraft(snapshot.value);
964
965
  setManualProxyUrl(snapshot.value?.proxyUrl ?? "");
965
966
  }
@@ -1140,19 +1141,28 @@ window.__ModuleLoader__.load({
1140
1141
  setBusy(true);
1141
1142
  setFeedback("idle");
1142
1143
  try {
1143
- for (const field of CONFIG_FIELDS) {
1144
- const accepted = scope.getSnapshot().value;
1145
- if (accepted !== void 0 && sameField(field, accepted[field], desired[field])) continue;
1144
+ const current = scope.getSnapshot();
1145
+ const original = baseline.current;
1146
+ if (current.value === void 0 || original === void 0 || current.revision === void 0) throw new Error("Host settings are unavailable");
1147
+ const changed = CONFIG_FIELDS.filter((field) => !sameField(field, original[field], desired[field]));
1148
+ const ops = changed.map((field) => {
1149
+ if (!sameField(field, original[field], current.value[field]) && !sameField(field, desired[field], current.value[field])) throw new Error(`Concurrent change to ${field}`);
1146
1150
  const value = field === "contextWindowOverrides" ? {
1147
1151
  ...Object.fromEntries((modelCatalog ?? []).map((model) => [model.id, null])),
1148
1152
  ...desired.contextWindowOverrides
1149
1153
  } : desired[field];
1150
- await scope.set(field, value);
1151
- const committed = scope.getSnapshot().value;
1152
- if (committed === void 0 || !sameField(field, committed[field], desired[field])) throw new Error(`Host refused ${field}`);
1153
- }
1154
+ return value === void 0 ? {
1155
+ op: "unset",
1156
+ path: [field]
1157
+ } : {
1158
+ op: "set",
1159
+ path: [field],
1160
+ value
1161
+ };
1162
+ });
1163
+ if (ops.length > 0) await scope.mutate(ops, current.revision);
1154
1164
  const accepted = scope.getSnapshot().value;
1155
- if (!sameConfig(accepted, desired)) throw new Error("Host returned a different configuration");
1165
+ if (accepted === void 0 || changed.some((field) => !sameField(field, accepted[field], desired[field]))) throw new Error("Host refused the configuration change");
1156
1166
  setDraft(accepted);
1157
1167
  setDirty(false);
1158
1168
  setFeedback("saved");
@@ -6230,7 +6240,7 @@ window.__ModuleLoader__.load({
6230
6240
  }
6231
6241
  //#endregion
6232
6242
  //#region src/version.ts
6233
- const CODEX_CONNECT_VERSION = "0.1.0-alpha.4.27";
6243
+ const CODEX_CONNECT_VERSION = "0.1.0-alpha.4.29";
6234
6244
  //#endregion
6235
6245
  //#region src/client/OpenAICodexModelsCard.tsx
6236
6246
  /** Compact Models account entry with quota disclosure and shared configuration. */
package/lib/index.d.ts CHANGED
@@ -24,6 +24,11 @@ interface OpenAICodexAccountSummary {
24
24
  profileSource: OpenAICodexAccountProfileSource;
25
25
  active: boolean;
26
26
  }
27
+ /** One request's credentials and browser labels from the same document read. */
28
+ interface CapturedOpenAICodexAccount extends CredentialStore {
29
+ accounts(): Promise<readonly OpenAICodexAccountSummary[]>;
30
+ captureActiveAccount(): Promise<CapturedOpenAICodexAccount>;
31
+ }
27
32
  /**
28
33
  * Resolve the default OAuth document path.
29
34
  * @param dshHome - optional Harness-home override.
@@ -51,7 +56,7 @@ declare class OpenAICodexCredentialStore implements CredentialStore {
51
56
  * Refreshes through the returned store update only that captured account and
52
57
  * never change the user's current account selection.
53
58
  */
54
- captureActiveAccount(): Promise<CredentialStore>;
59
+ captureActiveAccount(): Promise<CapturedOpenAICodexAccount>;
55
60
  private modifyCapturedAccount;
56
61
  /** @inheritdoc */
57
62
  list(): Promise<readonly CredentialInfo[]>;
@@ -64,9 +69,11 @@ declare class OpenAICodexCredentialStore implements CredentialStore {
64
69
  /** Remove one account; active removal requires an explicit stored replacement. */
65
70
  removeAccount(selectedAccountKey: string, replacementAccountKey?: string): Promise<void>;
66
71
  /** @inheritdoc */
67
- modify(providerId: string, fn: (current: Credential | undefined) => Promise<Credential | undefined>): Promise<Credential | undefined>;
72
+ modify(providerId: string, fn: (current: Credential | undefined) => Promise<Credential | undefined>, options?: Parameters<CredentialStore['modify']>[2]): Promise<Credential | undefined>;
68
73
  /** @inheritdoc */
69
74
  delete(providerId: string): Promise<void>;
75
+ /** Allow the provider's 15-second refresh plus bounded filesystem completion. */
76
+ private withWriterLock;
70
77
  }
71
78
  //#endregion
72
79
  //#region src/provider-proxy.d.ts
@@ -97,12 +104,15 @@ declare function listOpenAICodexProxyCandidates(): readonly string[];
97
104
  /** One plugin instance owns its proxy agents and contributes one global wrapper owner. */
98
105
  declare class OpenAICodexProxyManager {
99
106
  private readonly agents;
107
+ private readonly connections;
100
108
  private activeOperations;
101
109
  private idleWaiters;
102
110
  private disposed;
103
111
  private disposePromise;
112
+ private closing;
104
113
  private waitForIdle;
105
114
  private closeAgents;
115
+ private shutdown;
106
116
  private agentFor;
107
117
  private acquire;
108
118
  /** Run a synchronous or asynchronous Codex operation in the selected proxy scope. */
@@ -113,9 +123,9 @@ declare class OpenAICodexProxyManager {
113
123
  }>(proxyUrl: string | undefined, operation: () => T): T;
114
124
  /** Probe one proxy without credentials, model calls, quota calls, or settings writes. */
115
125
  probe(proxyUrl: string): Promise<OpenAICodexProxyProbeResult>;
116
- /** Close owned pools only after all scoped operations have become quiescent. */
126
+ /** Allow one second to drain, then destroy owned pools with a one-second completion bound. */
117
127
  dispose(): Promise<void>;
118
- /** Release the process wrapper and pools after the user disables the proxy. */
128
+ /** Bound shutdown as on disposal; reject new proxy leases until reconfiguration finishes. */
119
129
  deactivate(): Promise<void>;
120
130
  }
121
131
  /** Probe the bounded automatic candidate set in parallel. */
@@ -198,7 +208,6 @@ declare class OpenAICodexTransport extends Service implements OpenAICodexTranspo
198
208
  private readonly proxyManager?;
199
209
  private readonly resolveProxyUrl;
200
210
  readonly apiVersion: 1;
201
- private readonly models;
202
211
  constructor(ctx: Context, credentials: OpenAICodexCredentialStore, proxyManager?: OpenAICodexProxyManager | undefined, resolveProxyUrl?: () => string | undefined);
203
212
  generateImages(input: ImageGenerationRequest, context: ImageRequestContext): Promise<ImageGenerationResponse>;
204
213
  private generateImagesWithoutProxy;
@@ -381,7 +390,7 @@ declare function parseOpenAICodexUsage(value: unknown): OpenAICodexUsage;
381
390
  * @param store - plugin-owned OAuth credential store.
382
391
  * @returns current rate-limit buckets safe to expose to the local browser page.
383
392
  */
384
- declare function readOpenAICodexRateLimits(store: OpenAICodexCredentialStore): Promise<OpenAICodexUsage>;
393
+ declare function readOpenAICodexRateLimits(store: Pick<OpenAICodexCredentialStore, 'captureActiveAccount'>): Promise<OpenAICodexUsage>;
385
394
  //#endregion
386
395
  //#region src/settings-contract.d.ts
387
396
  /** Node-free settings contract shared by the Host plugin and browser card. */
@@ -519,7 +528,6 @@ declare function mapOpenAICodexSearchResponse(value: unknown): WebSearchResult;
519
528
  declare class OpenAICodexSearchProvider implements WebSearchProvider {
520
529
  private readonly options;
521
530
  readonly id = "openai-codex";
522
- private readonly models;
523
531
  /**
524
532
  * @param options - fixed trusted endpoint policy and deployment tunables.
525
533
  */
@@ -562,7 +570,7 @@ declare function logoutOpenAICodex(store?: OpenAICodexCredentialStore): Promise<
562
570
  * @param store - credential store, defaulting under `$DSH_HOME`.
563
571
  * @returns stored login state and expiry.
564
572
  */
565
- declare function openAICodexAuthStatus(store?: OpenAICodexCredentialStore): Promise<OpenAICodexAuthStatus>;
573
+ declare function openAICodexAuthStatus(store?: CredentialStore): Promise<OpenAICodexAuthStatus>;
566
574
  //#endregion
567
575
  //#region src/fast-mode.d.ts
568
576
  /** Process-local, per-session OpenAI Codex Fast Mode state. */
package/lib/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import { $ as OPENAI_CODEX_LOCAL_PROXY_CANDIDATES, A as assertNoOpenAICodexProviderConflict, At as parseOpenAICodexUsage, B as COMPATIBILITY_PACKAGES, Bt as OPENAI_CODEX_PROVIDER, C as OPENAI_CODEX_TRANSPORT_ERROR_CODES, Ct as FastModeRegistry, D as isOpenAICodexTransportError, E as OpenAICodexTransportError, Et as isFastModeSessionId, F as checkForOpenAICodexUpdate, G as SUPPORTED_NODE_RANGE, H as DSH_PLUGIN_API_PACKAGES, Ht as openAICodexAuthPath, I as compareOpenAICodexVersions, It as OPENAI_CODEX_ACCOUNT_LIMIT, J as detectCompatibility, K as SUPPORTED_PI_AI_RANGE, L as parseOpenAICodexUpdateResult, Lt as OPENAI_CODEX_AUTH_DOCUMENT_LIMIT, M as openAICodexConflictMessage, Mt as loginOpenAICodex, Nt as logoutOpenAICodex, O as VIEW_IMAGE_TOOL_NAME, P as OPENAI_CODEX_UPDATE_PATH, Pt as openAICodexAuthStatus, Q as OPENAI_CODEX_PROXY_TEST_PATH, R as parseOpenAICodexVersion, Rt as OPENAI_CODEX_AUTH_FILENAME, S as OPENAI_CODEX_TRANSPORT_API_VERSION, St as OPENAI_CODEX_FAST_MODE_PATH, T as OpenAICodexTransport, Tt as OPENAI_CODEX_FAST_MODE_MAX_SESSION_ID_LENGTH, U as PI_AI_PACKAGE, V as COMPATIBILITY_SCHEMA_VERSION, Vt as OpenAICodexCredentialStore, W as SUPPORTED_DSH_PLUGIN_API_VERSION, Y as evaluateCompatibility, Z as OPENAI_CODEX_PROXY_DETECT_PATH, _ as OPENAI_CODEX_IMAGE_MAX_COUNT, _t as resolveOpenAICodexProxyUrl, a as name, at as listOpenAICodexProxyCandidates, b as OPENAI_CODEX_IMAGE_PROMPT_MAX_LENGTH, c as migrateOpenAICodexSearchHistory, ct as DEFAULT_OPENAI_CODEX_SEARCH_MAX_OUTPUT_TOKENS, d as OPENAI_CODEX_BASE_URL, dt as DEFAULT_OPENAI_CODEX_SETTINGS, et as OPENAI_CODEX_PROXY_CANDIDATE_LIMIT, f as OPENAI_CODEX_SEARCH_PROVIDER, ft as OPENAI_CODEX_SETTINGS_NAMESPACE, g as OPENAI_CODEX_IMAGE_GENERATION_URL, h as mapOpenAICodexSearchResponse, ht as isValidOpenAICodexProxyUrl, i as inject, it as detectOpenAICodexProxies, j as diagnoseOpenAICodex, jt as readOpenAICodexRateLimits, k as IMAGE_GENERATE_TOOL_NAME, kt as OPENAI_CODEX_USAGE_URL, lt as DEFAULT_OPENAI_CODEX_SEARCH_MODE, m as OpenAICodexSearchProvider, mt as isValidOpenAICodexContextWindowOverrides, n as OPENAI_CODEX_SETTINGS_NS, nt as OPENAI_CODEX_PROXY_PROBE_URL, o as OPENAI_CODEX_HISTORY_BACKUP_SUFFIX, ot as DEFAULT_OPENAI_CODEX_PROXY_URL, p as OPENAI_CODEX_SEARCH_URL, pt as decodeOpenAICodexSettings, q as assessCompatibility, r as apply, rt as OpenAICodexProxyManager, s as OPENAI_CODEX_SEARCH_MODEL_REQUEST_EVENT, st as DEFAULT_OPENAI_CODEX_SEARCH_CONTEXT_SIZE, t as Config, tt as OPENAI_CODEX_PROXY_PROBE_TIMEOUT_MS, ut as DEFAULT_OPENAI_CODEX_SEARCH_MODEL, v as OPENAI_CODEX_IMAGE_MAX_ERROR_BYTES, vt as resolveOpenAICodexSettings, w as OPENAI_CODEX_TRANSPORT_SERVICE, wt as OPENAI_CODEX_FAST_MODE_MAX_SESSIONS, x as OPENAI_CODEX_IMAGE_REQUEST_TIMEOUT_MS, y as OPENAI_CODEX_IMAGE_MAX_RESPONSE_BYTES, z as COMPATIBILITY_CONTRACT, zt as OPENAI_CODEX_AUTH_V1_BACKUP_SUFFIX } from "./src-BcyhDCEJ.js";
1
+ import { $ as OPENAI_CODEX_LOCAL_PROXY_CANDIDATES, A as assertNoOpenAICodexProviderConflict, At as loginOpenAICodex, B as COMPATIBILITY_PACKAGES, Bt as openAICodexAuthPath, C as OPENAI_CODEX_TRANSPORT_ERROR_CODES, Ct as isFastModeSessionId, D as isOpenAICodexTransportError, Dt as parseOpenAICodexUsage, E as OpenAICodexTransportError, Et as OPENAI_CODEX_USAGE_URL, F as checkForOpenAICodexUpdate, Ft as OPENAI_CODEX_AUTH_DOCUMENT_LIMIT, G as SUPPORTED_NODE_RANGE, H as DSH_PLUGIN_API_PACKAGES, I as compareOpenAICodexVersions, It as OPENAI_CODEX_AUTH_FILENAME, J as detectCompatibility, K as SUPPORTED_PI_AI_RANGE, L as parseOpenAICodexUpdateResult, Lt as OPENAI_CODEX_AUTH_V1_BACKUP_SUFFIX, M as openAICodexConflictMessage, Mt as openAICodexAuthStatus, O as VIEW_IMAGE_TOOL_NAME, Ot as readOpenAICodexRateLimits, P as OPENAI_CODEX_UPDATE_PATH, Pt as OPENAI_CODEX_ACCOUNT_LIMIT, Q as OPENAI_CODEX_PROXY_TEST_PATH, R as parseOpenAICodexVersion, Rt as OPENAI_CODEX_PROVIDER, S as OPENAI_CODEX_TRANSPORT_API_VERSION, St as OPENAI_CODEX_FAST_MODE_MAX_SESSION_ID_LENGTH, T as OpenAICodexTransport, U as PI_AI_PACKAGE, V as COMPATIBILITY_SCHEMA_VERSION, W as SUPPORTED_DSH_PLUGIN_API_VERSION, Y as evaluateCompatibility, Z as OPENAI_CODEX_PROXY_DETECT_PATH, _ as OPENAI_CODEX_IMAGE_MAX_COUNT, _t as resolveOpenAICodexProxyUrl, a as name, at as listOpenAICodexProxyCandidates, b as OPENAI_CODEX_IMAGE_PROMPT_MAX_LENGTH, bt as FastModeRegistry, c as migrateOpenAICodexSearchHistory, ct as DEFAULT_OPENAI_CODEX_SEARCH_MAX_OUTPUT_TOKENS, d as OPENAI_CODEX_BASE_URL, dt as DEFAULT_OPENAI_CODEX_SETTINGS, et as OPENAI_CODEX_PROXY_CANDIDATE_LIMIT, f as OPENAI_CODEX_SEARCH_PROVIDER, ft as OPENAI_CODEX_SETTINGS_NAMESPACE, g as OPENAI_CODEX_IMAGE_GENERATION_URL, h as mapOpenAICodexSearchResponse, ht as isValidOpenAICodexProxyUrl, i as inject, it as detectOpenAICodexProxies, j as diagnoseOpenAICodex, jt as logoutOpenAICodex, k as IMAGE_GENERATE_TOOL_NAME, lt as DEFAULT_OPENAI_CODEX_SEARCH_MODE, m as OpenAICodexSearchProvider, mt as isValidOpenAICodexContextWindowOverrides, n as OPENAI_CODEX_SETTINGS_NS, nt as OPENAI_CODEX_PROXY_PROBE_URL, o as OPENAI_CODEX_HISTORY_BACKUP_SUFFIX, ot as DEFAULT_OPENAI_CODEX_PROXY_URL, p as OPENAI_CODEX_SEARCH_URL, pt as decodeOpenAICodexSettings, q as assessCompatibility, r as apply, rt as OpenAICodexProxyManager, s as OPENAI_CODEX_SEARCH_MODEL_REQUEST_EVENT, st as DEFAULT_OPENAI_CODEX_SEARCH_CONTEXT_SIZE, t as Config, tt as OPENAI_CODEX_PROXY_PROBE_TIMEOUT_MS, ut as DEFAULT_OPENAI_CODEX_SEARCH_MODEL, v as OPENAI_CODEX_IMAGE_MAX_ERROR_BYTES, vt as resolveOpenAICodexSettings, w as OPENAI_CODEX_TRANSPORT_SERVICE, x as OPENAI_CODEX_IMAGE_REQUEST_TIMEOUT_MS, xt as OPENAI_CODEX_FAST_MODE_MAX_SESSIONS, y as OPENAI_CODEX_IMAGE_MAX_RESPONSE_BYTES, yt as OPENAI_CODEX_FAST_MODE_PATH, z as COMPATIBILITY_CONTRACT, zt as OpenAICodexCredentialStore } from "./src-BNfobpwF.js";
2
2
  export { COMPATIBILITY_CONTRACT, COMPATIBILITY_PACKAGES, COMPATIBILITY_SCHEMA_VERSION, Config, DEFAULT_OPENAI_CODEX_PROXY_URL, DEFAULT_OPENAI_CODEX_SEARCH_CONTEXT_SIZE, DEFAULT_OPENAI_CODEX_SEARCH_MAX_OUTPUT_TOKENS, DEFAULT_OPENAI_CODEX_SEARCH_MODE, DEFAULT_OPENAI_CODEX_SEARCH_MODEL, DEFAULT_OPENAI_CODEX_SETTINGS, DSH_PLUGIN_API_PACKAGES, FastModeRegistry, FastModeRegistry as OpenAICodexFastModeRegistry, IMAGE_GENERATE_TOOL_NAME, OPENAI_CODEX_ACCOUNT_LIMIT, OPENAI_CODEX_AUTH_DOCUMENT_LIMIT, OPENAI_CODEX_AUTH_FILENAME, OPENAI_CODEX_AUTH_V1_BACKUP_SUFFIX, OPENAI_CODEX_BASE_URL, OPENAI_CODEX_FAST_MODE_MAX_SESSIONS, OPENAI_CODEX_FAST_MODE_MAX_SESSION_ID_LENGTH, OPENAI_CODEX_FAST_MODE_PATH, OPENAI_CODEX_HISTORY_BACKUP_SUFFIX, OPENAI_CODEX_IMAGE_GENERATION_URL, OPENAI_CODEX_IMAGE_MAX_COUNT, OPENAI_CODEX_IMAGE_MAX_ERROR_BYTES, OPENAI_CODEX_IMAGE_MAX_RESPONSE_BYTES, OPENAI_CODEX_IMAGE_PROMPT_MAX_LENGTH, OPENAI_CODEX_IMAGE_REQUEST_TIMEOUT_MS, OPENAI_CODEX_LOCAL_PROXY_CANDIDATES, OPENAI_CODEX_PROVIDER, OPENAI_CODEX_PROXY_CANDIDATE_LIMIT, OPENAI_CODEX_PROXY_DETECT_PATH, OPENAI_CODEX_PROXY_PROBE_TIMEOUT_MS, OPENAI_CODEX_PROXY_PROBE_URL, OPENAI_CODEX_PROXY_TEST_PATH, OPENAI_CODEX_SEARCH_MODEL_REQUEST_EVENT, OPENAI_CODEX_SEARCH_PROVIDER, OPENAI_CODEX_SEARCH_URL, OPENAI_CODEX_SETTINGS_NAMESPACE, OPENAI_CODEX_SETTINGS_NS, OPENAI_CODEX_TRANSPORT_API_VERSION, OPENAI_CODEX_TRANSPORT_ERROR_CODES, OPENAI_CODEX_TRANSPORT_SERVICE, OPENAI_CODEX_UPDATE_PATH, OPENAI_CODEX_USAGE_URL, OpenAICodexCredentialStore, OpenAICodexProxyManager, OpenAICodexSearchProvider, OpenAICodexTransport, OpenAICodexTransportError, PI_AI_PACKAGE, SUPPORTED_DSH_PLUGIN_API_VERSION, SUPPORTED_NODE_RANGE, SUPPORTED_PI_AI_RANGE, VIEW_IMAGE_TOOL_NAME, apply, assertNoOpenAICodexProviderConflict, assessCompatibility, checkForOpenAICodexUpdate, compareOpenAICodexVersions, decodeOpenAICodexSettings, detectCompatibility, detectOpenAICodexProxies, diagnoseOpenAICodex, evaluateCompatibility, inject, isFastModeSessionId, isOpenAICodexTransportError, isValidOpenAICodexContextWindowOverrides, isValidOpenAICodexProxyUrl, listOpenAICodexProxyCandidates, loginOpenAICodex, logoutOpenAICodex, mapOpenAICodexSearchResponse, migrateOpenAICodexSearchHistory, name, openAICodexAuthPath, openAICodexAuthStatus, openAICodexConflictMessage, parseOpenAICodexUpdateResult, parseOpenAICodexUsage, parseOpenAICodexVersion, readOpenAICodexRateLimits, resolveOpenAICodexProxyUrl, resolveOpenAICodexSettings };