dsh-codex-connect 0.1.0-alpha.4.30 → 0.1.0-alpha.4.32

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.29 is verified with DSH `0.1.2-rc.1` and its declared pi-ai range `^0.84.2`.
3
+ Alpha 4.31 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.29` |
26
+ | `0.1.2-rc.1` | `0.1.0-alpha.4.31` |
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.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.
31
+ Alpha 4.31'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.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).
33
+ The Alpha 4.31 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.29 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.29:
56
+ For DSH `0.1.2-rc.1`, use Alpha 4.31:
57
57
 
58
58
  ```sh
59
- dsh plugin --profile web add dsh-codex-connect@0.1.0-alpha.4.29
59
+ dsh plugin --profile web add dsh-codex-connect@0.1.0-alpha.4.31
60
60
  ```
61
61
 
62
62
  For DSH `0.1.2-alpha.5`, use Alpha 4.25:
@@ -65,7 +65,7 @@ The Alpha 4.29 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.29'` 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.31'` 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/MIGRATION.md CHANGED
@@ -11,6 +11,19 @@
11
11
 
12
12
  Rollback is the inverse package swap. Do not delete or copy the separate OAuth file during either direction. If Harness reports a duplicate `openai-codex` adapter, the old bundle or a manual provider row is still active; resolve that one row instead of changing credentials.
13
13
 
14
+ ## Astra reasoning selections
15
+
16
+ The plugin's Astra fallback definition offers `low`, `medium`, `high`, `xhigh`, and `max`. An omitted `reasoningEffort` preserves the provider default; it does not select Low or disable reasoning. The native dependency definition still takes precedence when present.
17
+
18
+ Before using Astra with a saved `minimal` or `off` selection, update the selected conversation and, if applicable, the default model setting:
19
+
20
+ | Saved value | Selection preserving its effective request behavior |
21
+ | --- | --- |
22
+ | `minimal` | Select `Low` (`reasoningEffort: low`); both send `low`. |
23
+ | `off` | Select `Default` (provider default), omitting `reasoningEffort`; both omit wire `reasoning`. This never guaranteed disabled reasoning. |
24
+
25
+ Other valid explicit efforts remain unchanged. A saved `minimal`, `off`, or unsupported `none` request is rejected with `UNSUPPORTED_REASONING_EFFORT` before authentication or model traffic; the plugin does not silently change it. `none` has no supported prior behavior to preserve: choose a valid effort or `Default` explicitly. The plugin does not rewrite settings or historical Session events. Use the conversation model selector for an existing Session; changing only the default model does not replace that Session's explicit selection. OAuth credentials do not need migration.
26
+
14
27
  ## Repairing search history written by Alpha 4.10
15
28
 
16
29
  Alpha 4.10 briefly wrote `web/openai-codex-search-llm-request` as a required private Session event. Because an external plugin cannot extend the Host persistence vocabulary across independent module instances, a newer Harness can refuse to read those histories after the event writer is removed.
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: a46589829b432cfcb97af069f7d7a7b3080e42af
6
- docs/README.zh.md: c42807c90ad4fcc4a4850d1228cfd6330b2bc184
5
+ README.md: b3d0bdd487da3988c277f9d6ed0cdd0ef3f62023
6
+ docs/README.zh.md: 75b42211584eeaa14dfcc1b2aee451052d3c874f
package/README.md CHANGED
@@ -16,7 +16,7 @@ This guide describes the published pairing below. Check `dsh --version` first; f
16
16
 
17
17
  | Requirement | Verified pairing |
18
18
  |---|---|
19
- | Codex Connect | `0.1.0-alpha.4.29` |
19
+ | Codex Connect | `0.1.0-alpha.4.31` |
20
20
  | DeepSeek Harness | `0.1.2-rc.1` |
21
21
  | Node.js | `^22.19.0 \|\| >=24.0.0` |
22
22
  | Account | ChatGPT OAuth with access to the requested Codex model; availability is decided by OpenAI |
@@ -24,7 +24,7 @@ This guide describes the published pairing below. Check `dsh --version` first; f
24
24
  ### 1. Install
25
25
 
26
26
  ```sh
27
- dsh plugin --profile web add dsh-codex-connect@0.1.0-alpha.4.29
27
+ dsh plugin --profile web add dsh-codex-connect@0.1.0-alpha.4.31
28
28
  dsh web
29
29
  ```
30
30
 
@@ -52,7 +52,7 @@ dsh plugin --profile web exec dsh-codex-connect doctor --json
52
52
  ## Core capabilities
53
53
 
54
54
  - **Accounts:** save up to 16 accounts on the DSH host and manually select the active account for subsequent requests. Account selection is not a per-session binding. Requests keep their captured account; the plugin does not rotate accounts or silently fail over.
55
- - **Models and Astra support:** the currently verified DSH and plugin combination supports `gpt-6-astra`. The plugin supplies the Astra model definition missing from the current dependency catalog, so users can select it without separately upgrading the underlying library. When the installed dependency catalog includes Astra, the plugin prefers its native definition. A model appearing in the list does not mean the current account has permission to use it; overall compatibility with new dependency versions still requires separate verification.
55
+ - **Models and Astra support:** the currently verified DSH and plugin combination supports `gpt-6-astra`. The plugin supplies its missing model definition with Low, Medium, High, Xhigh, and Max reasoning levels; Default preserves the provider default. Saved Off/Minimal selections require an [explicit update](MIGRATION.md#astra-reasoning-selections). When the installed dependency catalog includes Astra, the plugin prefers its native definition. A model appearing in the list does not mean the current account has permission to use it; overall compatibility with new dependency versions still requires separate verification.
56
56
  - **Fast Mode:** request priority service for one conversation, off by default. Actual speed and quota consumption depend on the service; no fixed speed multiplier is guaranteed.
57
57
  - **Quota:** show the server-returned `5h` and `7d` windows and reset times, normally refreshed every 60 seconds while signed in. Missing windows are not invented; Spark uses its separate quota bucket.
58
58
  - **Update guidance:** compare the installed DSH/plugin pair with the public verification record without installing an upgrade.
@@ -121,7 +121,7 @@ pnpm run test:browser
121
121
  pnpm run check:dsh-install
122
122
  ```
123
123
 
124
- `check` covers static checks, unit tests, build, compatibility, and packaging. Browser regression and isolated DSH installation are separate commands. These checks use no real OAuth authorization and do not replace real-account acceptance.
124
+ `check` covers static checks, unit tests, build, compatibility, and packaging. `lint:metadata` checks package and release rules; `lint:source` checks host and browser TypeScript for unhandled or misused promises, invalid awaits, duplicate cases, and unreachable code. Browser regression and isolated DSH installation are separate commands. These checks use no real OAuth authorization and do not replace real-account acceptance.
125
125
 
126
126
  ## License and acknowledgements
127
127
 
package/docs/README.zh.md CHANGED
@@ -16,7 +16,7 @@ Codex Connect 为标准 Harness agent loop 添加 `openai-codex` 模型提供方
16
16
 
17
17
  | 要求 | 已验证组合 |
18
18
  |---|---|
19
- | Codex Connect | `0.1.0-alpha.4.29` |
19
+ | Codex Connect | `0.1.0-alpha.4.31` |
20
20
  | DeepSeek Harness | `0.1.2-rc.1` |
21
21
  | Node.js | `^22.19.0 \|\| >=24.0.0` |
22
22
  | 账户 | 通过 ChatGPT OAuth 使用所请求的 Codex 模型;可用性由 OpenAI 决定 |
@@ -24,7 +24,7 @@ Codex Connect 为标准 Harness agent loop 添加 `openai-codex` 模型提供方
24
24
  ### 1. 安装
25
25
 
26
26
  ```sh
27
- dsh plugin --profile web add dsh-codex-connect@0.1.0-alpha.4.29
27
+ dsh plugin --profile web add dsh-codex-connect@0.1.0-alpha.4.31
28
28
  dsh web
29
29
  ```
30
30
 
@@ -52,7 +52,7 @@ dsh plugin --profile web exec dsh-codex-connect doctor --json
52
52
  ## 核心能力
53
53
 
54
54
  - **账户:**在 DSH 主机上保存最多 16 个账户,手动选择后续请求使用的活动账户,不按会话绑定。请求保持已固定的账户,插件不会自动轮换或静默故障切换。
55
- - **模型与 Astra 支持:**当前已验证的 DSH 与插件组合已支持 `gpt-6-astra`。插件为当前依赖目录尚未收录的 Astra 补充了模型定义,让用户无需单独升级底层库即可选择该模型。未来使用的依赖目录包含 Astra 时,插件会优先采用其原生定义。模型出现在列表中,不代表当前账户具有调用权限;新依赖版本的整体兼容性仍需单独验证。
55
+ - **模型与 Astra 支持:**当前已验证的 DSH 与插件组合已支持 `gpt-6-astra`。插件补充缺失的模型定义,提供 Low、Medium、High、Xhigh 和 Max 五档推理强度;Default 保持提供方默认值。已保存的 Off/Minimal 选择需要[明确更新](../MIGRATION.md#astra-reasoning-selections)。未来使用的依赖目录包含 Astra 时,插件会优先采用其原生定义。模型出现在列表中,不代表当前账户具有调用权限;新依赖版本的整体兼容性仍需单独验证。
56
56
  - **Fast Mode:**为单个对话请求优先服务,默认关闭。实际速度和额度消耗取决于服务端,不保证固定提速倍数。
57
57
  - **额度:**显示服务端返回的 `5h`、`7d` 窗口及重置时间,已登录时通常每 60 秒刷新一次。不虚构缺失窗口;Spark 使用独立额度桶。
58
58
  - **更新指引:**将已安装的 DSH/plugin 组合与公开验证记录比较,但不会自动执行升级。
@@ -121,7 +121,7 @@ pnpm run test:browser
121
121
  pnpm run check:dsh-install
122
122
  ```
123
123
 
124
- `check` 包含静态检查、单元测试、构建、兼容性和打包检查;浏览器回归与隔离 DSH 安装是另外两个命令。这些检查不使用真实 OAuth 授权,也不能替代真实账户验收。
124
+ `check` 包含静态检查、单元测试、构建、兼容性和打包检查。`lint:metadata` 检查包元数据与发布规则;`lint:source` 检查宿主与浏览器 TypeScript 中未处理或误用的 Promise、无效 await、重复 case 和不可达代码。浏览器回归与隔离 DSH 安装是另外两个命令。这些检查不使用真实 OAuth 授权,也不能替代真实账户验收。
125
125
 
126
126
  ## 许可证与致谢
127
127
 
@@ -1,4 +1,4 @@
1
1
  # Bilingual-pair consistency record for the design document. Re-record with:
2
2
  # git hash-object docs/design.md docs/design.zh.md
3
- design.md: 26dd77d6b775164863d8658e38703650b3cb09b5
4
- design.zh.md: d34694bbb8aa883492871ef951323757ba7032a1
3
+ design.md: 7292502d8abc9997ee9994890bb1413b1007ffc7
4
+ design.zh.md: 2586023ae73b50966f46566b1798efa5ccbc6234
package/docs/design.md CHANGED
@@ -16,12 +16,16 @@ Browser account routes expose deterministic plugin-derived keys, local display l
16
16
 
17
17
  The settings routes and CLI reuse the existing OAuth path and route names for migration compatibility. Only an explicit login operation emits an authorization URL or code. Browser requests are accepted by default only from loopback; a remote request must use an exact effective HTTP(S) origin in the current sidecar, must not carry cross-site Fetch Metadata, and must match any supplied Origin exactly. The sidecar is re-read for every request, and unknown fields or modes fail closed. A login challenge accepts only credential-free HTTPS URLs and fails closed after 30 seconds or when the provider finishes without a URL; logout and disposal cancel pending waiters. Status responses are redacted. Doctor uses `lstat` metadata and never opens the document.
18
18
 
19
+ Browser account and update requests have a 45-second deadline covering response headers and JSON bodies. A timed-out account mutation is not retried automatically: while the account view is observed, the browser reads server state again because the mutation may already have committed. Failed state reads retry after five seconds, including when no account is stored. Plugin disposal aborts browser waits without logging out the server account.
20
+
19
21
  ## Search and images
20
22
 
21
23
  When `enableSearch: true`, the plugin registers its standalone search provider. It does not append a plugin-owned required-on-read Session event because an external package cannot guarantee that its `@deepseek-ai/dsh-session` module instance owns the Host persistence vocabulary; the standard web Tool call and result remain in the Session log. DSH `0.1.2-rc.1` does not expose the WebRuntime provider selection through its settings service, so the compatibility adapter verifies that release's runtime field, records the previous provider, and selects Codex only while the capability is active. Disable and disposal restore the recorded provider unless another owner has selected a newer route. An unsupported runtime fails activation instead of reporting a route change that did not occur. Search responses are mapped to Harness text and citation records.
22
24
 
23
25
  When `enableImageTool: true`, `view_image` is registered only after tools, filesystem, and attachment services are available. Local files remain bounded by the Harness filesystem surface. Remote images allow only credential-free public HTTP(S): all DNS answers must be public unicast, each redirect is revalidated, and each socket is pinned to the validated address to close DNS-rebinding gaps. The tool also checks bounded bytes, accepted media signatures, and current-model image support before saving a Harness attachment.
24
26
 
27
+ Each remote-image redirect hop has one 30-second deadline covering DNS, connection, and body consumption. Cancellation settles the caller's wait immediately; an operating-system DNS lookup may still finish later, but its result cannot start a new HTTP request after cancellation or timeout.
28
+
25
29
  ## Conflicts and diagnostics
26
30
 
27
31
  Before registration the plugin checks current provider ids. An existing `openai-codex` adapter produces a focused message naming the likely legacy-bundle or manual-provider cause. The boot-free CLI `doctor` reports package/runtime version, OAuth path metadata, capability defaults, and safe conflict guidance without returning auth content.
package/docs/design.zh.md CHANGED
@@ -16,10 +16,14 @@ Host 将 `llm-openai-codex` 注册为插件自有的能力 settings namespace。
16
16
 
17
17
  为兼容迁移,设置页路由、OAuth 路径和 provider id 不改名。浏览器请求默认只允许 loopback;远程请求必须使用当前 sidecar 中的精确有效 HTTP(S) origin,不能带 cross-site Fetch Metadata,若带 Origin 还必须精确匹配。每次请求都会重新读取 sidecar;未知字段或错误 mode 会快速失败。登录挑战只接受不含凭据的 HTTPS 地址;30 秒内未得到地址、provider 已结束但没有地址、退出登录或插件卸载时,所有 waiter 都会被清理。只有显式登录会输出授权 URL 或代码;状态输出会脱敏。doctor 只用 `lstat` 检查元数据,不打开文件。
18
18
 
19
+ 浏览器账户与更新请求具有 45 秒期限,覆盖响应头和 JSON 响应体。账户修改超时后不会自动重试写操作:只要账户视图仍在观察状态,浏览器就会重新读取服务端状态,因为修改可能已经提交。状态读取失败后每五秒重试,即使尚未保存账户也一样。插件卸载会取消浏览器等待,但不会退出服务端账户。
20
+
19
21
  ## 搜索与图片
20
22
 
21
23
  仅当 `enableSearch: true` 时注册 Codex 独立搜索提供方和不含凭据的请求事件。DSH `0.1.2-rc.1` 没有通过 settings 服务开放 WebRuntime 的 provider 选择,因此兼容适配器会先核对该版本的运行时字段,记录此前的提供方,并仅在能力开启期间选择 Codex。关闭能力或卸载插件时会恢复此前的提供方;如果另一个 owner 已经选择了更新的路由,则不会覆盖它。不支持的运行时会让能力启用失败,不会谎报路由已经变化。仅当 `enableImageTool: true` 且 tools、filesystem、attachments 服务存在时注册 `view_image`。本地文件继续受 Harness 文件系统边界与大小限制;远程图片只允许不含凭据的公共 HTTP(S),所有 DNS 结果必须是公共单播地址,每次重定向都会重新验证,并把实际连接固定到已验证地址以关闭 DNS rebinding 缺口。
22
24
 
25
+ 远程图片的每次重定向跳转共用一个 30 秒期限,覆盖 DNS、连接与响应体读取。取消会立即结束调用方等待;操作系统 DNS 查询可能稍后才完成,但其结果不能在取消或超时后启动新的 HTTP 请求。
26
+
23
27
  ## 冲突、诊断与兼容边界
24
28
 
25
29
  注册前检查现有 provider id;发现 `openai-codex` 已被占用时,给出旧 bundle 或手动 provider 配置的定向迁移提示。boot-free CLI doctor 只报告包/运行时版本、OAuth 路径元数据、能力默认值和安全提示。
package/lib/bin.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
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-D2Ig4NNT.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-K61G4PZz.js";
3
3
  import { i as fetch, r as ProxyAgent, t as Agent } from "./undici-runtime-H2uktiw6.js";
4
4
  import { createHash } from "node:crypto";
5
5
  import { realpathSync } from "node:fs";
package/lib/client.js CHANGED
@@ -124,6 +124,55 @@ window.__ModuleLoader__.load({
124
124
  };
125
125
  }
126
126
  //#endregion
127
+ //#region src/client/request-json.ts
128
+ /** Bounded same-origin JSON reads, including response-body consumption. */
129
+ /** Allow the server's 30-second authorization-URL deadline to report first. */
130
+ const BROWSER_REQUEST_TIMEOUT_MS = 45e3;
131
+ /** A timed-out mutation may already have committed on the server. */
132
+ var BrowserRequestTimeoutError = class extends Error {
133
+ constructor() {
134
+ super("Request timed out; server outcome is unconfirmed");
135
+ }
136
+ };
137
+ /** Read headers and JSON within one deadline; cancellation also settles uncooperative transports. */
138
+ async function requestJson(path, init) {
139
+ const controller = new AbortController();
140
+ const parent = init.signal;
141
+ const abort = () => {
142
+ controller.abort(parent?.reason);
143
+ };
144
+ if (parent?.aborted) abort();
145
+ else parent?.addEventListener("abort", abort, { once: true });
146
+ const timer = setTimeout(() => {
147
+ controller.abort(new BrowserRequestTimeoutError());
148
+ }, BROWSER_REQUEST_TIMEOUT_MS);
149
+ let rejectAbort;
150
+ try {
151
+ if (controller.signal.aborted) throw controller.signal.reason;
152
+ const cancelled = new Promise((_resolve, reject) => {
153
+ rejectAbort = () => {
154
+ reject(controller.signal.reason);
155
+ };
156
+ controller.signal.addEventListener("abort", rejectAbort, { once: true });
157
+ });
158
+ const reading = (async () => {
159
+ const response = await fetch(path, {
160
+ ...init,
161
+ signal: controller.signal
162
+ });
163
+ return {
164
+ response,
165
+ value: await response.json().catch(() => void 0)
166
+ };
167
+ })();
168
+ return await Promise.race([reading, cancelled]);
169
+ } finally {
170
+ clearTimeout(timer);
171
+ parent?.removeEventListener("abort", abort);
172
+ if (rejectAbort !== void 0) controller.signal.removeEventListener("abort", rejectAbort);
173
+ }
174
+ }
175
+ //#endregion
127
176
  //#region src/auth-paths.ts
128
177
  /** Node-free route constants shared by the Host and browser plugin halves. */
129
178
  /** Plugin-owned status endpoint consumed by its browser half. */
@@ -226,7 +275,7 @@ window.__ModuleLoader__.load({
226
275
  return { url: url.href };
227
276
  }
228
277
  async function request(path, method = "GET", signal, body) {
229
- const response = await fetch(path, {
278
+ const { response, value } = await requestJson(path, {
230
279
  method,
231
280
  headers: {
232
281
  accept: "application/json",
@@ -236,7 +285,6 @@ window.__ModuleLoader__.load({
236
285
  ...signal === void 0 ? {} : { signal },
237
286
  ...body === void 0 ? {} : { body: JSON.stringify(body) }
238
287
  });
239
- const value = await response.json().catch(() => void 0);
240
288
  if (!response.ok) throw new AccountRequestError(typeof value === "object" && value !== null && "error" in value && typeof value.error === "string" ? value.error : `HTTP ${response.status}`);
241
289
  return value;
242
290
  }
@@ -252,6 +300,7 @@ window.__ModuleLoader__.load({
252
300
  controller;
253
301
  timer;
254
302
  disposed = false;
303
+ lifetime = new AbortController();
255
304
  popup = null;
256
305
  getSnapshot = () => this.snapshot;
257
306
  subscribe = (listener) => {
@@ -285,18 +334,21 @@ window.__ModuleLoader__.load({
285
334
  }
286
335
  schedule() {
287
336
  clearTimeout(this.timer);
288
- const interval = this.snapshot.operation.kind === "waiting-authorization" || this.snapshot.status.status === "signing-in" ? 1e3 : this.snapshot.operationError !== void 0 && this.snapshot.accounts.length > 0 ? 5e3 : this.snapshot.status.status === "signed-in" ? 6e4 : this.snapshot.status.status === "error" && this.snapshot.accounts.length > 0 ? 5e3 : void 0;
337
+ const interval = this.snapshot.operation.kind === "waiting-authorization" || this.snapshot.status.status === "signing-in" ? 1e3 : this.snapshot.operationError !== void 0 ? 5e3 : this.snapshot.status.status === "signed-in" ? 6e4 : this.snapshot.status.status === "error" ? 5e3 : void 0;
289
338
  if (!this.disposed && this.listeners.size > 0 && interval !== void 0) this.timer = setTimeout(() => {
290
339
  this.refresh();
291
340
  }, interval);
292
341
  }
293
342
  async readServerState(signal) {
294
- const response = await request(OPENAI_CODEX_AUTH_STATUS_PATH, "GET", signal);
343
+ const response = await this.request(OPENAI_CODEX_AUTH_STATUS_PATH, "GET", signal);
295
344
  return {
296
345
  status: parseStatus(response),
297
346
  accounts: parseAccounts(response)
298
347
  };
299
348
  }
349
+ request(path, method = "GET", signal, body) {
350
+ return request(path, method, signal === void 0 ? this.lifetime.signal : AbortSignal.any([signal, this.lifetime.signal]), body);
351
+ }
300
352
  stableStatus(status, accounts) {
301
353
  if (status.status !== "signing-in" || accounts.length === 0) return status;
302
354
  if (accounts.find((account) => account.active)?.accountKey !== this.snapshot.accounts.find((account) => account.active)?.accountKey) return status;
@@ -345,7 +397,7 @@ window.__ModuleLoader__.load({
345
397
  operation: { kind: "starting-authorization" }
346
398
  });
347
399
  try {
348
- const challenge = parseChallenge(await request(OPENAI_CODEX_AUTH_LOGIN_PATH, "POST"));
400
+ const challenge = parseChallenge(await this.request(OPENAI_CODEX_AUTH_LOGIN_PATH, "POST"));
349
401
  if (this.disposed) {
350
402
  popup?.close();
351
403
  return;
@@ -372,7 +424,7 @@ window.__ModuleLoader__.load({
372
424
  operation: { kind: "idle" },
373
425
  operationError: this.errorMessage(error)
374
426
  });
375
- if (error instanceof AccountRequestError && error.message === "OpenAI Codex sign-in cancelled") await this.refresh();
427
+ if (error instanceof BrowserRequestTimeoutError || error instanceof AccountRequestError && error.message === "OpenAI Codex sign-in cancelled") await this.refresh();
376
428
  } finally {
377
429
  if (this.popup === popup) this.popup = null;
378
430
  this.schedule();
@@ -388,7 +440,7 @@ window.__ModuleLoader__.load({
388
440
  operation: { kind: "cancelling-authorization" }
389
441
  });
390
442
  try {
391
- await request(OPENAI_CODEX_AUTH_CANCEL_PATH, "POST");
443
+ await this.request(OPENAI_CODEX_AUTH_CANCEL_PATH, "POST");
392
444
  const { status, accounts } = await this.readServerState();
393
445
  this.publish({
394
446
  status,
@@ -409,6 +461,7 @@ window.__ModuleLoader__.load({
409
461
  operation: { kind: "idle" },
410
462
  operationError: this.errorMessage(error)
411
463
  });
464
+ if (error instanceof BrowserRequestTimeoutError) await this.refresh();
412
465
  } finally {
413
466
  this.schedule();
414
467
  }
@@ -423,7 +476,7 @@ window.__ModuleLoader__.load({
423
476
  operation: { kind: "signing-out" }
424
477
  });
425
478
  try {
426
- await request(OPENAI_CODEX_AUTH_LOGOUT_PATH, "POST");
479
+ await this.request(OPENAI_CODEX_AUTH_LOGOUT_PATH, "POST");
427
480
  this.publish({
428
481
  status: { status: "signed-out" },
429
482
  busy: false,
@@ -438,6 +491,9 @@ window.__ModuleLoader__.load({
438
491
  operation: { kind: "idle" },
439
492
  operationError: this.errorMessage(error)
440
493
  });
494
+ if (error instanceof BrowserRequestTimeoutError) await this.refresh();
495
+ } finally {
496
+ this.schedule();
441
497
  }
442
498
  }
443
499
  /** Select one stored account and refresh account-specific status and quota. */
@@ -464,7 +520,7 @@ window.__ModuleLoader__.load({
464
520
  }
465
521
  });
466
522
  try {
467
- await request(OPENAI_CODEX_AUTH_ACCOUNTS_PATH, method, void 0, body);
523
+ await this.request(OPENAI_CODEX_AUTH_ACCOUNTS_PATH, method, void 0, body);
468
524
  const { status, accounts } = await this.readServerState();
469
525
  this.publish({
470
526
  status,
@@ -480,6 +536,7 @@ window.__ModuleLoader__.load({
480
536
  operation: { kind: "idle" },
481
537
  operationError: this.errorMessage(error)
482
538
  });
539
+ if (error instanceof BrowserRequestTimeoutError) await this.refresh();
483
540
  } finally {
484
541
  this.schedule();
485
542
  }
@@ -487,6 +544,7 @@ window.__ModuleLoader__.load({
487
544
  /** Stop local observation on plugin unload; do not log out the server account. */
488
545
  dispose() {
489
546
  this.disposed = true;
547
+ this.lifetime.abort();
490
548
  this.stopPolling();
491
549
  this.popup?.close();
492
550
  this.popup = null;
@@ -2451,13 +2509,12 @@ window.__ModuleLoader__.load({
2451
2509
  ...this.snapshot.dismissedNotice === void 0 ? {} : { dismissedNotice: this.snapshot.dismissedNotice }
2452
2510
  });
2453
2511
  try {
2454
- const runtimeResponse = await fetch(OPENAI_CODEX_RUNTIME_PATH, {
2512
+ const { response: runtimeResponse, value: runtimeValue } = await requestJson(OPENAI_CODEX_RUNTIME_PATH, {
2455
2513
  method: "GET",
2456
2514
  headers: { accept: "application/json" },
2457
2515
  credentials: "same-origin",
2458
2516
  signal: controller.signal
2459
2517
  });
2460
- const runtimeValue = await runtimeResponse.json().catch(() => void 0);
2461
2518
  const rawCurrentDshVersion = (typeof runtimeValue === "object" && runtimeValue !== null && !Array.isArray(runtimeValue) ? runtimeValue : void 0)?.["currentDshVersion"];
2462
2519
  currentDshVersion = runtimeResponse.ok && typeof rawCurrentDshVersion === "string" && parseOpenAICodexVersion(rawCurrentDshVersion) !== void 0 ? rawCurrentDshVersion : void 0;
2463
2520
  const currentDsh = currentDshVersion === void 0 ? {} : { currentDshVersion };
@@ -2471,13 +2528,12 @@ window.__ModuleLoader__.load({
2471
2528
  return;
2472
2529
  }
2473
2530
  }
2474
- const response = await fetch(OPENAI_CODEX_UPDATE_PATH, {
2531
+ const { response, value } = await requestJson(OPENAI_CODEX_UPDATE_PATH, {
2475
2532
  method: "GET",
2476
2533
  headers: { accept: "application/json" },
2477
2534
  credentials: "same-origin",
2478
2535
  signal: controller.signal
2479
2536
  });
2480
- const value = await response.json().catch(() => void 0);
2481
2537
  const safeResult = (response.ok ? parseOpenAICodexUpdateResult(value) : void 0) ?? {
2482
2538
  status: "unavailable",
2483
2539
  currentVersion: this.currentVersion,
@@ -6273,7 +6329,7 @@ window.__ModuleLoader__.load({
6273
6329
  }
6274
6330
  //#endregion
6275
6331
  //#region src/version.ts
6276
- const CODEX_CONNECT_VERSION = "0.1.0-alpha.4.30";
6332
+ const CODEX_CONNECT_VERSION = "0.1.0-alpha.4.32";
6277
6333
  //#endregion
6278
6334
  //#region src/client/OpenAICodexModelsCard.tsx
6279
6335
  /** Compact Models account entry with quota disclosure and shared configuration. */
package/lib/index.js CHANGED
@@ -1,2 +1,2 @@
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-D2Ig4NNT.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-K61G4PZz.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 };
@@ -1224,7 +1224,8 @@ const OPENAI_CODEX_ASTRA_MODEL = {
1224
1224
  contextWindow: 272e3,
1225
1225
  maxTokens: 128e3,
1226
1226
  thinkingLevelMap: {
1227
- minimal: "low",
1227
+ off: null,
1228
+ minimal: null,
1228
1229
  xhigh: "xhigh",
1229
1230
  max: "max"
1230
1231
  },
@@ -3765,7 +3766,7 @@ function registerOpenAICodexOriginalImageRoute(ctx, trustedOrigins, assets) {
3765
3766
  }
3766
3767
  //#endregion
3767
3768
  //#region src/version.ts
3768
- const CODEX_CONNECT_VERSION = "0.1.0-alpha.4.30";
3769
+ const CODEX_CONNECT_VERSION = "0.1.0-alpha.4.32";
3769
3770
  //#endregion
3770
3771
  //#region src/doctor.ts
3771
3772
  /** Secret-free diagnostics and duplicate-provider guidance. */
@@ -4286,6 +4287,53 @@ function isPublicNetworkAddress(rawAddress) {
4286
4287
  function abortError(signal) {
4287
4288
  return signal.reason instanceof Error ? signal.reason : new Error(signal.reason === void 0 ? "remote image request aborted" : String(signal.reason));
4288
4289
  }
4290
+ async function runPublicHttpHop(signal, operation) {
4291
+ if (signal.aborted) throw abortError(signal);
4292
+ const controller = new AbortController();
4293
+ return new Promise((resolve, reject) => {
4294
+ let settled = false;
4295
+ const timer = setTimeout(() => {
4296
+ const error = /* @__PURE__ */ new Error(`remote image request exceeded ${String(PUBLIC_HTTP_HOP_TIMEOUT_MS)}ms`);
4297
+ controller.abort(error);
4298
+ finish({
4299
+ ok: false,
4300
+ error
4301
+ });
4302
+ }, PUBLIC_HTTP_HOP_TIMEOUT_MS);
4303
+ const cleanup = () => {
4304
+ clearTimeout(timer);
4305
+ signal.removeEventListener("abort", onAbort);
4306
+ };
4307
+ const finish = (result) => {
4308
+ if (settled) return;
4309
+ settled = true;
4310
+ cleanup();
4311
+ if (result.ok) resolve(result.value);
4312
+ else reject(result.error);
4313
+ };
4314
+ const onAbort = () => {
4315
+ const error = abortError(signal);
4316
+ controller.abort(signal.reason);
4317
+ finish({
4318
+ ok: false,
4319
+ error
4320
+ });
4321
+ };
4322
+ timer.unref();
4323
+ signal.addEventListener("abort", onAbort, { once: true });
4324
+ operation(controller.signal).then((value) => {
4325
+ finish({
4326
+ ok: true,
4327
+ value
4328
+ });
4329
+ }, (error) => {
4330
+ finish({
4331
+ ok: false,
4332
+ error
4333
+ });
4334
+ });
4335
+ });
4336
+ }
4289
4337
  function assertTargetUrl(url) {
4290
4338
  if (url.protocol !== "http:" && url.protocol !== "https:") throw new Error("view_image URL must use http or https");
4291
4339
  if (url.username !== "" || url.password !== "") throw new Error("view_image URL must not contain credentials");
@@ -4428,9 +4476,12 @@ async function fetchPublicHttpResource(source, maxBytes, signal, runtime = NODE_
4428
4476
  assertTargetUrl(url);
4429
4477
  for (let redirects = 0;; redirects += 1) {
4430
4478
  if (signal.aborted) throw abortError(signal);
4431
- const addresses = await runtime.resolve(url.hostname, signal);
4432
- if (addresses.length === 0 || addresses.some((candidate) => !isPublicNetworkAddress(candidate.address))) throw new Error(`remote image host ${JSON.stringify(url.hostname)} must resolve only to public network addresses`);
4433
- const hop = await runtime.get(url, addresses[0], maxBytes, signal);
4479
+ const hop = await runPublicHttpHop(signal, async (hopSignal) => {
4480
+ const addresses = await runtime.resolve(url.hostname, hopSignal);
4481
+ if (hopSignal.aborted) throw abortError(hopSignal);
4482
+ if (addresses.length === 0 || addresses.some((candidate) => !isPublicNetworkAddress(candidate.address))) throw new Error(`remote image host ${JSON.stringify(url.hostname)} must resolve only to public network addresses`);
4483
+ return runtime.get(url, addresses[0], maxBytes, hopSignal);
4484
+ });
4434
4485
  if (hop.status >= 300 && hop.status < 400) {
4435
4486
  if (redirects >= 5) throw new Error(`remote image exceeded ${String(5)} redirects`);
4436
4487
  if (hop.location === void 0) throw new Error(`remote image redirect ${String(hop.status)} has no location`);
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "dsh-codex-connect",
3
3
  "displayName": "Codex Connect",
4
4
  "description": "ChatGPT OAuth and Codex models for DeepSeek Harness.",
5
- "version": "0.1.0-alpha.4.30",
5
+ "version": "0.1.0-alpha.4.32",
6
6
  "author": "Frank Song",
7
7
  "contributors": [
8
8
  "Yan-Zero (original dsh-codex author)"
@@ -38,7 +38,9 @@
38
38
  "dsh-codex-connect": "lib/bin.js"
39
39
  },
40
40
  "scripts": {
41
- "lint": "node scripts/lint.mjs",
41
+ "lint": "pnpm run lint:metadata && pnpm run lint:source",
42
+ "lint:metadata": "node scripts/lint.mjs",
43
+ "lint:source": "eslint src --max-warnings=0 && node scripts/check-source-lint.mjs",
42
44
  "build": "tsdown",
43
45
  "test": "vitest run",
44
46
  "test:browser": "vitest run --config vitest.browser.config.ts",
@@ -198,12 +200,14 @@
198
200
  "@types/react": "~18.3.1",
199
201
  "@types/react-dom": "~18.3.1",
200
202
  "@vitest/browser-playwright": "4.1.11",
203
+ "eslint": "^10.10.0",
201
204
  "jsdom": "29.1.1",
202
205
  "playwright": "1.62.1",
203
206
  "react": "^18.2.0",
204
207
  "react-dom": "^18.2.0",
205
208
  "tsdown": "^0.22.2",
206
209
  "typescript": "^5.9.3",
210
+ "typescript-eslint": "^8.69.0",
207
211
  "vitest": "^4.1.8"
208
212
  }
209
213
  }