dsh-codex-connect 0.1.0-alpha.4.19 → 0.1.0-alpha.4.20
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 +2 -2
- package/README.i18n.yaml +2 -2
- package/README.md +13 -2
- package/cordis.patch.yml +1 -0
- package/docs/README.zh.md +13 -2
- package/lib/bin.js +1 -1
- package/lib/client.js +287 -4
- package/lib/index.d.ts +84 -3
- package/lib/index.js +2 -2
- package/lib/{src-CiOi4nFr.js → src-B2d5HLN5.js} +477 -100
- package/package.json +4 -1
package/INSTALL.md
CHANGED
|
@@ -12,7 +12,7 @@ Install `dsh-codex-connect` into one requested DeepSeek Harness profile without
|
|
|
12
12
|
|
|
13
13
|
## Install and validate
|
|
14
14
|
|
|
15
|
-
The only verified combination is DSH plugin API packages `0.1.1-rc.2`, `@earendil-works/pi-ai` `0.82.1`, and Node.js `^22.19.0 || >=24.0.0`. Alpha 4.
|
|
15
|
+
The only verified combination is DSH plugin API packages `0.1.1-rc.2`, `@earendil-works/pi-ai` `0.82.1`, and Node.js `^22.19.0 || >=24.0.0`. Alpha 4.20 uses the rc.2 keyed Plugin configuration slot; users of older DSH API packages should upgrade the DSH API packages and pi-ai together, then rerun `dsh-codex-connect doctor --json` and `pnpm --silent run check:compatibility`; the contract does not make claims about future versions.
|
|
16
16
|
|
|
17
17
|
1. Check `dsh --version` or `dsh --help`. From a Harness checkout use `pnpm dsh`.
|
|
18
18
|
2. Install the package:
|
|
@@ -21,7 +21,7 @@ The only verified combination is DSH plugin API packages `0.1.1-rc.2`, `@earendi
|
|
|
21
21
|
dsh plugin --profile web add dsh-codex-connect@alpha
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
After `0.1.0-alpha.4.
|
|
24
|
+
After `0.1.0-alpha.4.20` is published, pin it exactly with `dsh plugin --profile web add dsh-codex-connect@0.1.0-alpha.4.20`. If npm is unavailable after its matching GitHub prerelease is created, use `dsh plugin --profile web add 'github:franksong2702/dsh-codex-connect#v0.1.0-alpha.4.20'`.
|
|
25
25
|
|
|
26
26
|
3. Run `dsh --profile web --dump-config` and require exactly one `llm-openai-codex` row loading `dsh-codex-connect`.
|
|
27
27
|
4. Confirm the effective `agent-default-model` and `web.searchProvider` values are unchanged from before installation.
|
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:
|
|
6
|
-
docs/README.zh.md:
|
|
5
|
+
README.md: 29729f3c078749ca04dc1d648c496c7b57bf3b17
|
|
6
|
+
docs/README.zh.md: a7141cd531059e44771f763a8e5b75d529fc3f83
|
package/README.md
CHANGED
|
@@ -28,7 +28,7 @@ dsh plugin --profile web add dsh-codex-connect@alpha
|
|
|
28
28
|
|
|
29
29
|
Expected result: the package is added to that profile. This does not change the profile's default model or global search route.
|
|
30
30
|
|
|
31
|
-
To reproduce this release exactly, use `dsh plugin --profile web add dsh-codex-connect@0.1.0-alpha.4.
|
|
31
|
+
To reproduce this release exactly, use `dsh plugin --profile web add dsh-codex-connect@0.1.0-alpha.4.20`. If npm is unavailable after the matching GitHub prerelease exists, use `dsh plugin --profile web add 'github:franksong2702/dsh-codex-connect#v0.1.0-alpha.4.20'`. A local checkout can be installed as `link:/absolute/path/to/dsh-codex-connect`.
|
|
32
32
|
|
|
33
33
|
### Version updates
|
|
34
34
|
|
|
@@ -139,6 +139,7 @@ The installed bundle is intentionally inert beyond model-provider registration:
|
|
|
139
139
|
```yaml
|
|
140
140
|
- id: llm-openai-codex
|
|
141
141
|
config:
|
|
142
|
+
enableProxy: false
|
|
142
143
|
enableSearch: false
|
|
143
144
|
enableImageTool: false
|
|
144
145
|
enableImageGeneration: false
|
|
@@ -146,6 +147,14 @@ The installed bundle is intentionally inert beyond model-provider registration:
|
|
|
146
147
|
|
|
147
148
|
Open **Settings → Plugins → Plugin configuration → Codex Connect** to manage the account and these options in one card. **Save changes** affects only this plugin's capability section and applies live. It never selects a default model or a global search route.
|
|
148
149
|
|
|
150
|
+
### Network connection and proxy detection
|
|
151
|
+
|
|
152
|
+
Codex Connect uses a **Direct connection** by default. A proxy is optional and applies only to this plugin's Codex requests: model streaming, OAuth login and token refresh, usage, standalone search, and image generation. Other providers and unscoped network requests keep the process's original dispatcher.
|
|
153
|
+
|
|
154
|
+
Select **Detect proxy** to test only the standard proxy environment variables and the documented loopback candidates `127.0.0.1:7890`, `127.0.0.1:7897`, and `127.0.0.1:10809`. Detection makes no model call, consumes no quota, and does not write settings. A response from the canonical Codex endpoint proves network reachability; `401/403`, proxy `407`, DNS, refused connection, timeout, TLS, and CONNECT failures remain separate diagnostics.
|
|
155
|
+
|
|
156
|
+
Choose **Use this proxy** only after reviewing a candidate, then click **Save changes**. **Configure manually** lets you test a credential-free HTTP(S) proxy origin before activation. **Disable proxy** is always available. A failed probe leaves the previous mode unchanged, and an enabled proxy failure is shown as an actionable error; Codex Connect never silently retries the request through a direct connection.
|
|
157
|
+
|
|
149
158
|
### Enable only the capability you intend to use
|
|
150
159
|
|
|
151
160
|
- `enableSearch: true` registers Codex as an available search provider. It does not select the profile's global search route.
|
|
@@ -210,6 +219,8 @@ Selecting Codex as the profile's global search route is another explicit change:
|
|
|
210
219
|
| Field | Default | Values |
|
|
211
220
|
|---|---:|---|
|
|
212
221
|
| `models` | full catalog | Codex model id array; empty hides all entries |
|
|
222
|
+
| `enableProxy` | `false` | boolean; direct connection unless explicitly enabled |
|
|
223
|
+
| `proxyUrl` | `http://127.0.0.1:7890` (inactive placeholder) | Credential-free HTTP(S) proxy origin |
|
|
213
224
|
| `enableSearch` | `false` | boolean |
|
|
214
225
|
| `enableImageTool` | `false` | boolean |
|
|
215
226
|
| `enableImageGeneration` | `false` | boolean |
|
|
@@ -239,7 +250,7 @@ Selecting Codex as the profile's global search route is another explicit change:
|
|
|
239
250
|
|
|
240
251
|
## Compatibility and security boundary
|
|
241
252
|
|
|
242
|
-
- The only verified compatibility combination is DSH plugin API packages `0.1.1-rc.2`, `@earendil-works/pi-ai` `0.82.1`, and Node.js `^22.19.0 || >=24.0.0`; see [compatibility.json](compatibility.json). Alpha 4.
|
|
253
|
+
- The only verified compatibility combination is DSH plugin API packages `0.1.1-rc.2`, `@earendil-works/pi-ai` `0.82.1`, and Node.js `^22.19.0 || >=24.0.0`; see [compatibility.json](compatibility.json). Alpha 4.20 uses the rc.2 keyed Plugin configuration slot; users of older DSH API packages should upgrade to the rc.2 API packages.
|
|
243
254
|
- Upgrade the DSH plugin API packages and `@earendil-works/pi-ai` as one group, then run `dsh-codex-connect doctor --json` and the compatibility check again. This contract does not make claims about future versions.
|
|
244
255
|
- When the daily upstream check finds a new `latest` or `next` DSH candidate, it installs Codex Connect into an isolated profile, boots the installed model runtime without OAuth credentials, verifies model and reasoning-effort discovery, and confirms provider disposal. Live sign-in, quota, and model requests still require manual validation in the test profile.
|
|
245
256
|
- ChatGPT plan eligibility, model access, quotas, and backend behavior are controlled by OpenAI and may change.
|
package/cordis.patch.yml
CHANGED
package/docs/README.zh.md
CHANGED
|
@@ -28,7 +28,7 @@ dsh plugin --profile web add dsh-codex-connect@alpha
|
|
|
28
28
|
|
|
29
29
|
预期结果:包被加入该 profile。这个动作不会更改 profile 的默认模型或全局搜索路由。
|
|
30
30
|
|
|
31
|
-
如需精确复现这个版本,使用 `dsh plugin --profile web add dsh-codex-connect@0.1.0-alpha.4.
|
|
31
|
+
如需精确复现这个版本,使用 `dsh plugin --profile web add dsh-codex-connect@0.1.0-alpha.4.20`。对应 GitHub prerelease 已创建但 npm 不可用时,可使用 `dsh plugin --profile web add 'github:franksong2702/dsh-codex-connect#v0.1.0-alpha.4.20'`。本地 checkout 可安装为 `link:/absolute/path/to/dsh-codex-connect`。
|
|
32
32
|
|
|
33
33
|
### 版本更新提醒
|
|
34
34
|
|
|
@@ -139,6 +139,7 @@ dsh plugin --profile web exec dsh-codex-connect doctor --json
|
|
|
139
139
|
```yaml
|
|
140
140
|
- id: llm-openai-codex
|
|
141
141
|
config:
|
|
142
|
+
enableProxy: false
|
|
142
143
|
enableSearch: false
|
|
143
144
|
enableImageTool: false
|
|
144
145
|
enableImageGeneration: false
|
|
@@ -146,6 +147,14 @@ dsh plugin --profile web exec dsh-codex-connect doctor --json
|
|
|
146
147
|
|
|
147
148
|
打开 **设置 → 插件 → 插件配置 → Codex Connect**,即可在同一张卡片中管理账户和这些选项。**保存更改**只影响本插件的能力配置并即时生效,绝不会选择默认模型或全局搜索路由。
|
|
148
149
|
|
|
150
|
+
### 网络连接与代理检测
|
|
151
|
+
|
|
152
|
+
Codex Connect 默认使用**直连**。代理是可选项,只作用于本插件的 Codex 请求:模型流式请求、OAuth 登录和 token 刷新、额度、独立搜索以及图片生成。其他提供方和未进入插件作用域的网络请求仍使用进程原来的 dispatcher。
|
|
153
|
+
|
|
154
|
+
点击 **检测代理** 时,只会测试标准代理环境变量,以及文档列出的本机候选地址:`127.0.0.1:7890`、`127.0.0.1:7897` 和 `127.0.0.1:10809`。检测不调用模型、不消耗额度,也不会写入设置。规范 Codex 端点返回任何 HTTP 响应都表示网络可达;`401/403`、代理 `407`、DNS、连接被拒绝、超时、TLS 和 CONNECT 失败会分别显示为诊断类别。
|
|
155
|
+
|
|
156
|
+
请先检查候选地址,再选择 **使用此代理**,最后点击 **保存更改**。**手动配置**可以先测试一个不带凭据的 HTTP(S) proxy origin,再启用它。**停用代理**始终可用。检测失败会保留原来的模式;代理已启用但请求失败时,界面会给出可操作的错误,绝不会静默改走直连。
|
|
157
|
+
|
|
149
158
|
### 只开启你准备使用的能力
|
|
150
159
|
|
|
151
160
|
- `enableSearch: true` 会把 Codex 注册为可选择的搜索提供方,不会把它选为 profile 的全局搜索路由。
|
|
@@ -210,6 +219,8 @@ dsh plugin --profile web exec dsh-codex-connect doctor --json
|
|
|
210
219
|
| 字段 | 默认值 | 可选值 |
|
|
211
220
|
|---|---:|---|
|
|
212
221
|
| `models` | 完整目录 | Codex model id 数组;空数组隐藏全部条目 |
|
|
222
|
+
| `enableProxy` | `false` | boolean;除非显式启用,否则使用直连 |
|
|
223
|
+
| `proxyUrl` | `http://127.0.0.1:7890`(未启用的占位值) | 不带凭据的 HTTP(S) proxy origin |
|
|
213
224
|
| `enableSearch` | `false` | boolean |
|
|
214
225
|
| `enableImageTool` | `false` | boolean |
|
|
215
226
|
| `enableImageGeneration` | `false` | boolean |
|
|
@@ -239,7 +250,7 @@ dsh plugin --profile web exec dsh-codex-connect doctor --json
|
|
|
239
250
|
|
|
240
251
|
## 兼容性与安全边界
|
|
241
252
|
|
|
242
|
-
- 当前唯一已验证的兼容组合是 DSH 插件 API packages `0.1.1-rc.2`、`@earendil-works/pi-ai` `0.82.1` 和 Node.js `^22.19.0 || >=24.0.0`;详见 [compatibility.json](../compatibility.json)。Alpha 4.
|
|
253
|
+
- 当前唯一已验证的兼容组合是 DSH 插件 API packages `0.1.1-rc.2`、`@earendil-works/pi-ai` `0.82.1` 和 Node.js `^22.19.0 || >=24.0.0`;详见 [compatibility.json](../compatibility.json)。Alpha 4.20 使用 rc.2 的 keyed 插件配置 slot;旧版 DSH API packages 用户应升级到 rc.2 API packages。
|
|
243
254
|
- 升级时请将 DSH 插件 API packages 与 `@earendil-works/pi-ai` 作为一组升级,再运行 `dsh-codex-connect doctor --json` 和兼容性检查。本契约不对未来版本作判断。
|
|
244
255
|
- 每日上游检查发现新的 DSH `latest` 或 `next` 候选版本时,会把 Codex Connect 安装到隔离 Profile 中,在没有 OAuth 凭据的情况下启动已安装的模型运行时,验证模型与推理强度发现,并确认提供方可被正确卸载。真实登录、额度和模型请求仍需在测试 Profile 中人工验证。
|
|
245
256
|
- ChatGPT 套餐资格、模型权限、额度和后端行为由 OpenAI 控制,可能变化。
|
package/lib/bin.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { At as openAICodexAuthPath, Et as openAICodexAuthStatus, Tt as logoutOpenAICodex, bt as normalizeTrustedOrigin, c as migrateOpenAICodexSearchHistory, j as CODEX_CONNECT_VERSION, k as diagnoseOpenAICodex, wt as loginOpenAICodex, yt as OpenAICodexTrustedOriginsStore } from "./src-B2d5HLN5.js";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
import { realpathSync } from "node:fs";
|
|
5
5
|
import { spawn } from "node:child_process";
|
package/lib/client.js
CHANGED
|
@@ -11,8 +11,35 @@ window.__ModuleLoader__.load({
|
|
|
11
11
|
/** Node-free settings contract shared by the Host plugin and browser card. */
|
|
12
12
|
/** Stable Harness settings namespace owned by this plugin. */
|
|
13
13
|
const OPENAI_CODEX_SETTINGS_NAMESPACE = "llm-openai-codex";
|
|
14
|
+
/** Suggested local HTTP proxy shown by the settings UI; it is never enabled by default. */
|
|
15
|
+
const DEFAULT_OPENAI_CODEX_PROXY_URL = "http://127.0.0.1:7890";
|
|
16
|
+
/**
|
|
17
|
+
* Normalize the credential-free HTTP proxy URL accepted by Codex Connect.
|
|
18
|
+
* Paths, query strings, fragments, and embedded credentials are rejected so
|
|
19
|
+
* the value remains an origin rather than an opaque request target.
|
|
20
|
+
*/
|
|
21
|
+
function normalizeOpenAICodexProxyUrl(value) {
|
|
22
|
+
if (typeof value !== "string" || value.trim().length === 0) return void 0;
|
|
23
|
+
try {
|
|
24
|
+
const parsed = new URL(value.trim());
|
|
25
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return void 0;
|
|
26
|
+
if (parsed.username !== "" || parsed.password !== "") return void 0;
|
|
27
|
+
if (parsed.pathname !== "/" || parsed.search !== "" || parsed.hash !== "") return void 0;
|
|
28
|
+
if (parsed.hostname.length === 0) return void 0;
|
|
29
|
+
if (parsed.port !== "" && (!/^\d+$/u.test(parsed.port) || Number(parsed.port) < 1 || Number(parsed.port) > 65535)) return void 0;
|
|
30
|
+
return parsed.origin;
|
|
31
|
+
} catch {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/** Whether a value is a supported, canonical HTTP(S) proxy origin. */
|
|
36
|
+
function isValidOpenAICodexProxyUrl(value) {
|
|
37
|
+
return normalizeOpenAICodexProxyUrl(value) !== void 0;
|
|
38
|
+
}
|
|
14
39
|
Object.freeze({
|
|
15
40
|
models: void 0,
|
|
41
|
+
enableProxy: false,
|
|
42
|
+
proxyUrl: DEFAULT_OPENAI_CODEX_PROXY_URL,
|
|
16
43
|
enableSearch: false,
|
|
17
44
|
enableImageTool: false,
|
|
18
45
|
enableImageGeneration: false,
|
|
@@ -28,6 +55,8 @@ window.__ModuleLoader__.load({
|
|
|
28
55
|
function decodeOpenAICodexSettings(value) {
|
|
29
56
|
if (!isRecord$2(value)) return void 0;
|
|
30
57
|
const models = value["models"];
|
|
58
|
+
const enableProxy = value["enableProxy"];
|
|
59
|
+
const proxyUrl = value["proxyUrl"];
|
|
31
60
|
const enableSearch = value["enableSearch"];
|
|
32
61
|
const enableImageTool = value["enableImageTool"];
|
|
33
62
|
const enableImageGeneration = value["enableImageGeneration"];
|
|
@@ -36,6 +65,8 @@ window.__ModuleLoader__.load({
|
|
|
36
65
|
const searchContextSize = value["searchContextSize"];
|
|
37
66
|
const searchMaxOutputTokens = value["searchMaxOutputTokens"];
|
|
38
67
|
if (models !== void 0 && (!Array.isArray(models) || models.some((model) => typeof model !== "string"))) return void 0;
|
|
68
|
+
if (enableProxy !== void 0 && typeof enableProxy !== "boolean") return void 0;
|
|
69
|
+
if (proxyUrl !== void 0 && (typeof proxyUrl !== "string" || !isValidOpenAICodexProxyUrl(proxyUrl))) return void 0;
|
|
39
70
|
if (typeof enableSearch !== "boolean" || typeof enableImageTool !== "boolean") return void 0;
|
|
40
71
|
if (enableImageGeneration !== void 0 && typeof enableImageGeneration !== "boolean") return void 0;
|
|
41
72
|
if (typeof searchModel !== "string" || searchModel.trim().length === 0) return void 0;
|
|
@@ -44,6 +75,8 @@ window.__ModuleLoader__.load({
|
|
|
44
75
|
if (typeof searchMaxOutputTokens !== "number" || !Number.isInteger(searchMaxOutputTokens) || searchMaxOutputTokens < 1) return void 0;
|
|
45
76
|
return {
|
|
46
77
|
models: models === void 0 ? void 0 : [...new Set(models)],
|
|
78
|
+
enableProxy: enableProxy ?? false,
|
|
79
|
+
proxyUrl: proxyUrl === void 0 ? DEFAULT_OPENAI_CODEX_PROXY_URL : normalizeOpenAICodexProxyUrl(proxyUrl),
|
|
47
80
|
enableSearch,
|
|
48
81
|
enableImageTool,
|
|
49
82
|
enableImageGeneration: enableImageGeneration ?? false,
|
|
@@ -87,6 +120,13 @@ window.__ModuleLoader__.load({
|
|
|
87
120
|
return catalog;
|
|
88
121
|
}
|
|
89
122
|
//#endregion
|
|
123
|
+
//#region src/proxy-paths.ts
|
|
124
|
+
/** Node-free route constants shared by the Host and browser plugin halves. */
|
|
125
|
+
/** Detect bounded local/environment proxy candidates without changing settings. */
|
|
126
|
+
const OPENAI_CODEX_PROXY_DETECT_PATH = "/plugins/dsh-openai-codex/proxy/detect";
|
|
127
|
+
/** Test one manually entered proxy origin without changing settings. */
|
|
128
|
+
const OPENAI_CODEX_PROXY_TEST_PATH = "/plugins/dsh-openai-codex/proxy/test";
|
|
129
|
+
//#endregion
|
|
90
130
|
//#region src/client/OpenAICodexConfiguration.tsx
|
|
91
131
|
/** Staged optional-capability editor inside the OpenAI Codex plugin card. */
|
|
92
132
|
const sectionStyle$1 = {
|
|
@@ -223,6 +263,8 @@ window.__ModuleLoader__.load({
|
|
|
223
263
|
};
|
|
224
264
|
const CONFIG_FIELDS = [
|
|
225
265
|
"models",
|
|
266
|
+
"enableProxy",
|
|
267
|
+
"proxyUrl",
|
|
226
268
|
"enableSearch",
|
|
227
269
|
"enableImageTool",
|
|
228
270
|
"enableImageGeneration",
|
|
@@ -250,6 +292,10 @@ window.__ModuleLoader__.load({
|
|
|
250
292
|
const [feedback, setFeedback] = (0, react.useState)("idle");
|
|
251
293
|
const [modelCatalog, setModelCatalog] = (0, react.useState)();
|
|
252
294
|
const [modelCatalogError, setModelCatalogError] = (0, react.useState)(false);
|
|
295
|
+
const [proxyDetection, setProxyDetection] = (0, react.useState)({ status: "idle" });
|
|
296
|
+
const [manualProxy, setManualProxy] = (0, react.useState)(false);
|
|
297
|
+
const [manualProbe, setManualProbe] = (0, react.useState)();
|
|
298
|
+
const [manualProbeBusy, setManualProbeBusy] = (0, react.useState)(false);
|
|
253
299
|
(0, react.useEffect)(() => {
|
|
254
300
|
if (scope === void 0) return;
|
|
255
301
|
const controller = new AbortController();
|
|
@@ -291,10 +337,73 @@ window.__ModuleLoader__.load({
|
|
|
291
337
|
setDraft(scope?.getSnapshot().value);
|
|
292
338
|
setDirty(false);
|
|
293
339
|
setFeedback("idle");
|
|
340
|
+
setProxyDetection({ status: "idle" });
|
|
341
|
+
setManualProbe(void 0);
|
|
342
|
+
};
|
|
343
|
+
const detectProxy = async () => {
|
|
344
|
+
setProxyDetection({ status: "detecting" });
|
|
345
|
+
try {
|
|
346
|
+
const response = await fetch(OPENAI_CODEX_PROXY_DETECT_PATH, {
|
|
347
|
+
method: "POST",
|
|
348
|
+
credentials: "same-origin",
|
|
349
|
+
headers: { accept: "application/json" }
|
|
350
|
+
});
|
|
351
|
+
if (!response.ok) throw new Error(`proxy detection failed: ${String(response.status)}`);
|
|
352
|
+
const value = await response.json();
|
|
353
|
+
if (!Array.isArray(value.candidates) || !Array.isArray(value.results)) throw new Error("proxy detection response was invalid");
|
|
354
|
+
setProxyDetection(value.candidates.length > 0 ? {
|
|
355
|
+
status: "candidate",
|
|
356
|
+
candidates: value.candidates
|
|
357
|
+
} : {
|
|
358
|
+
status: "failed",
|
|
359
|
+
results: value.results
|
|
360
|
+
});
|
|
361
|
+
} catch {
|
|
362
|
+
setProxyDetection({
|
|
363
|
+
status: "failed",
|
|
364
|
+
results: []
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
};
|
|
368
|
+
const useProxy = (proxyUrl) => {
|
|
369
|
+
if (draft === void 0 || !isValidOpenAICodexProxyUrl(proxyUrl)) return;
|
|
370
|
+
setDraft({
|
|
371
|
+
...draft,
|
|
372
|
+
proxyUrl,
|
|
373
|
+
enableProxy: true
|
|
374
|
+
});
|
|
375
|
+
setDirty(true);
|
|
376
|
+
setFeedback("idle");
|
|
377
|
+
setManualProxy(true);
|
|
378
|
+
setManualProbe(void 0);
|
|
379
|
+
setProxyDetection({ status: "idle" });
|
|
380
|
+
};
|
|
381
|
+
const testManualProxy = async () => {
|
|
382
|
+
if (draft === void 0 || !isValidOpenAICodexProxyUrl(draft.proxyUrl)) return;
|
|
383
|
+
setManualProbeBusy(true);
|
|
384
|
+
try {
|
|
385
|
+
const path = `${OPENAI_CODEX_PROXY_TEST_PATH}?proxyUrl=${encodeURIComponent(draft.proxyUrl)}`;
|
|
386
|
+
const response = await fetch(path, {
|
|
387
|
+
method: "POST",
|
|
388
|
+
credentials: "same-origin",
|
|
389
|
+
headers: { accept: "application/json" }
|
|
390
|
+
});
|
|
391
|
+
if (!response.ok) throw new Error(`proxy test failed: ${String(response.status)}`);
|
|
392
|
+
setManualProbe(await response.json());
|
|
393
|
+
} catch {
|
|
394
|
+
setManualProbe({
|
|
395
|
+
proxyUrl: draft.proxyUrl,
|
|
396
|
+
reachable: false,
|
|
397
|
+
classification: "connect-failure"
|
|
398
|
+
});
|
|
399
|
+
} finally {
|
|
400
|
+
setManualProbeBusy(false);
|
|
401
|
+
}
|
|
294
402
|
};
|
|
295
403
|
const validModel = draft !== void 0 && draft.searchModel.trim().length > 0;
|
|
296
404
|
const validTokens = draft !== void 0 && Number.isInteger(draft.searchMaxOutputTokens) && draft.searchMaxOutputTokens > 0;
|
|
297
|
-
const
|
|
405
|
+
const validProxy = draft !== void 0 && isValidOpenAICodexProxyUrl(draft.proxyUrl);
|
|
406
|
+
const valid = validModel && validTokens && validProxy;
|
|
298
407
|
const save = async () => {
|
|
299
408
|
if (scope === void 0 || draft === void 0 || !snapshot.writable || !valid) return;
|
|
300
409
|
const desired = {
|
|
@@ -398,6 +507,135 @@ window.__ModuleLoader__.load({
|
|
|
398
507
|
}, model.id);
|
|
399
508
|
})
|
|
400
509
|
}),
|
|
510
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
511
|
+
style: { paddingTop: 4 },
|
|
512
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
513
|
+
style: headingStyle,
|
|
514
|
+
children: t("networkHeading")
|
|
515
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
516
|
+
style: {
|
|
517
|
+
...bodyStyle$2,
|
|
518
|
+
marginTop: 4
|
|
519
|
+
},
|
|
520
|
+
children: t("networkIntro")
|
|
521
|
+
})]
|
|
522
|
+
}),
|
|
523
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
524
|
+
style: bodyStyle$2,
|
|
525
|
+
role: "status",
|
|
526
|
+
children: draft.enableProxy ? t("customProxyActive", { proxyUrl: draft.proxyUrl }) : t("directConnection")
|
|
527
|
+
}),
|
|
528
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
529
|
+
style: buttonsStyle,
|
|
530
|
+
children: [
|
|
531
|
+
!draft.enableProxy ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
532
|
+
type: "button",
|
|
533
|
+
style: buttonStyle$2,
|
|
534
|
+
onClick: () => {
|
|
535
|
+
detectProxy();
|
|
536
|
+
},
|
|
537
|
+
disabled: proxyDetection.status === "detecting",
|
|
538
|
+
children: proxyDetection.status === "detecting" ? t("detectingProxy") : t("detectProxy")
|
|
539
|
+
}) : null,
|
|
540
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
541
|
+
type: "button",
|
|
542
|
+
style: buttonStyle$2,
|
|
543
|
+
onClick: () => {
|
|
544
|
+
setManualProxy(true);
|
|
545
|
+
},
|
|
546
|
+
children: t("configureProxyManually")
|
|
547
|
+
}),
|
|
548
|
+
draft.enableProxy ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
549
|
+
type: "button",
|
|
550
|
+
style: buttonStyle$2,
|
|
551
|
+
onClick: () => {
|
|
552
|
+
update("enableProxy", false);
|
|
553
|
+
},
|
|
554
|
+
children: t("disableProxy")
|
|
555
|
+
}) : null
|
|
556
|
+
]
|
|
557
|
+
}),
|
|
558
|
+
proxyDetection.status === "candidate" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
559
|
+
style: fieldsetStyle,
|
|
560
|
+
role: "status",
|
|
561
|
+
children: [
|
|
562
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
563
|
+
style: bodyStyle$2,
|
|
564
|
+
children: t("proxyCandidatesFound")
|
|
565
|
+
}),
|
|
566
|
+
proxyDetection.candidates.map((candidate) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
567
|
+
style: actionsStyle,
|
|
568
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
|
|
569
|
+
style: modelIdStyle,
|
|
570
|
+
children: candidate.proxyUrl
|
|
571
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
572
|
+
type: "button",
|
|
573
|
+
style: primaryButtonStyle$2,
|
|
574
|
+
onClick: () => {
|
|
575
|
+
useProxy(candidate.proxyUrl);
|
|
576
|
+
},
|
|
577
|
+
children: t("useThisProxy")
|
|
578
|
+
})]
|
|
579
|
+
}, candidate.proxyUrl)),
|
|
580
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
581
|
+
type: "button",
|
|
582
|
+
style: buttonStyle$2,
|
|
583
|
+
onClick: () => {
|
|
584
|
+
setProxyDetection({ status: "idle" });
|
|
585
|
+
},
|
|
586
|
+
children: t("keepDirectConnection")
|
|
587
|
+
})
|
|
588
|
+
]
|
|
589
|
+
}) : null,
|
|
590
|
+
proxyDetection.status === "failed" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
591
|
+
style: errorStyle$2,
|
|
592
|
+
role: "alert",
|
|
593
|
+
children: t("proxyDetectionFailed")
|
|
594
|
+
}) : null,
|
|
595
|
+
manualProxy ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
596
|
+
style: fieldsetStyle,
|
|
597
|
+
children: [
|
|
598
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
599
|
+
style: formFieldStyle,
|
|
600
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
601
|
+
style: labelStyle,
|
|
602
|
+
children: t("proxyAddress")
|
|
603
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
604
|
+
style: controlStyle,
|
|
605
|
+
value: draft.proxyUrl,
|
|
606
|
+
"aria-invalid": !isValidOpenAICodexProxyUrl(draft.proxyUrl),
|
|
607
|
+
onChange: (event) => {
|
|
608
|
+
update("proxyUrl", event.currentTarget.value);
|
|
609
|
+
}
|
|
610
|
+
})]
|
|
611
|
+
}),
|
|
612
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
613
|
+
style: buttonsStyle,
|
|
614
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
615
|
+
type: "button",
|
|
616
|
+
style: buttonStyle$2,
|
|
617
|
+
disabled: !isValidOpenAICodexProxyUrl(draft.proxyUrl) || manualProbeBusy,
|
|
618
|
+
onClick: () => {
|
|
619
|
+
testManualProxy();
|
|
620
|
+
},
|
|
621
|
+
children: manualProbeBusy ? t("testingProxy") : t("testProxy")
|
|
622
|
+
}), !draft.enableProxy ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
623
|
+
type: "button",
|
|
624
|
+
style: primaryButtonStyle$2,
|
|
625
|
+
disabled: !isValidOpenAICodexProxyUrl(draft.proxyUrl),
|
|
626
|
+
onClick: () => {
|
|
627
|
+
useProxy(draft.proxyUrl);
|
|
628
|
+
},
|
|
629
|
+
children: t("useThisProxy")
|
|
630
|
+
}) : null]
|
|
631
|
+
}),
|
|
632
|
+
manualProbe === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
633
|
+
style: manualProbe.reachable ? successStyle : errorStyle$2,
|
|
634
|
+
role: "status",
|
|
635
|
+
children: manualProbe.reachable ? t("proxyTestSucceeded", { status: manualProbe.status ?? manualProbe.classification }) : t("proxyTestFailed", { reason: manualProbe.classification })
|
|
636
|
+
})
|
|
637
|
+
]
|
|
638
|
+
}) : null,
|
|
401
639
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
402
640
|
style: { paddingTop: 4 },
|
|
403
641
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
@@ -575,6 +813,11 @@ window.__ModuleLoader__.load({
|
|
|
575
813
|
role: "alert",
|
|
576
814
|
children: t("invalidSearchTokens")
|
|
577
815
|
}) : null,
|
|
816
|
+
!validProxy && draft !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
817
|
+
style: errorStyle$2,
|
|
818
|
+
role: "alert",
|
|
819
|
+
children: t("invalidProxyUrl")
|
|
820
|
+
}) : null,
|
|
578
821
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
579
822
|
style: bodyStyle$2,
|
|
580
823
|
children: t("routingNote")
|
|
@@ -621,7 +864,8 @@ window.__ModuleLoader__.load({
|
|
|
621
864
|
"search-stability",
|
|
622
865
|
"image-generation",
|
|
623
866
|
"oauth-history",
|
|
624
|
-
"model-visibility"
|
|
867
|
+
"model-visibility",
|
|
868
|
+
"proxy-connection"
|
|
625
869
|
];
|
|
626
870
|
function isHighlightKind(value) {
|
|
627
871
|
return typeof value === "string" && HIGHLIGHT_KINDS.includes(value);
|
|
@@ -1125,7 +1369,8 @@ window.__ModuleLoader__.load({
|
|
|
1125
1369
|
"search-stability": "updateHighlightSearchStability",
|
|
1126
1370
|
"image-generation": "updateHighlightImageGeneration",
|
|
1127
1371
|
"oauth-history": "updateHighlightOauthHistory",
|
|
1128
|
-
"model-visibility": "updateHighlightModelVisibility"
|
|
1372
|
+
"model-visibility": "updateHighlightModelVisibility",
|
|
1373
|
+
"proxy-connection": "updateHighlightProxyConnection"
|
|
1129
1374
|
};
|
|
1130
1375
|
const compatibilityTitleKeys = {
|
|
1131
1376
|
compatible: "compatibilityCompatibleTitle",
|
|
@@ -2567,6 +2812,24 @@ window.__ModuleLoader__.load({
|
|
|
2567
2812
|
modelCatalogFailed: "Available models could not be loaded.",
|
|
2568
2813
|
capabilitiesHeading: "Optional capabilities",
|
|
2569
2814
|
capabilitiesIntro: "Choose which extra Codex capabilities this dsh profile may register.",
|
|
2815
|
+
networkHeading: "Network connection",
|
|
2816
|
+
networkIntro: "Direct connection is the default. Proxy detection only tests a bounded set of local and environment candidates; nothing is saved until you choose Use this proxy and save.",
|
|
2817
|
+
directConnection: "Direct connection",
|
|
2818
|
+
customProxyActive: "Custom proxy selected: {proxyUrl}",
|
|
2819
|
+
detectProxy: "Detect proxy",
|
|
2820
|
+
detectingProxy: "Detecting…",
|
|
2821
|
+
configureProxyManually: "Configure manually",
|
|
2822
|
+
disableProxy: "Disable proxy",
|
|
2823
|
+
proxyCandidatesFound: "Working proxy candidates found. Choose one to stage it for activation.",
|
|
2824
|
+
keepDirectConnection: "Keep direct connection",
|
|
2825
|
+
useThisProxy: "Use this proxy",
|
|
2826
|
+
proxyDetectionFailed: "No working proxy candidate was found. Check DNS, connection refused, timeout, TLS, or proxy authentication errors, then try again.",
|
|
2827
|
+
proxyAddress: "Custom proxy address",
|
|
2828
|
+
testProxy: "Test proxy",
|
|
2829
|
+
testingProxy: "Testing…",
|
|
2830
|
+
proxyTestSucceeded: "Proxy reached the Codex endpoint (HTTP {status}).",
|
|
2831
|
+
proxyTestFailed: "Proxy test failed: {reason}.",
|
|
2832
|
+
invalidProxyUrl: "Enter an HTTP(S) proxy origin without credentials or a path.",
|
|
2570
2833
|
enableSearch: "Enable Codex search provider",
|
|
2571
2834
|
enableSearchHelp: "Makes OpenAI Codex available as a search provider. It does not select the global search route.",
|
|
2572
2835
|
searchModel: "Search model",
|
|
@@ -2675,6 +2938,7 @@ window.__ModuleLoader__.load({
|
|
|
2675
2938
|
updateHighlightImageGeneration: "Added optional GPT Image generation in the Codex Connect settings and a preview card in the conversation.",
|
|
2676
2939
|
updateHighlightOauthHistory: "Added safer session-history migration and a sign-in fallback when the account needs to reconnect.",
|
|
2677
2940
|
updateHighlightModelVisibility: "You can now choose which Codex models appear in model selectors.",
|
|
2941
|
+
updateHighlightProxyConnection: "Added opt-in Codex proxy detection with explicit confirmation and a visible direct-connection fallback.",
|
|
2678
2942
|
viewTechnicalDetails: "View technical details",
|
|
2679
2943
|
hideTechnicalDetails: "Hide technical details",
|
|
2680
2944
|
technicalDetailsHeading: "Technical changes",
|
|
@@ -2751,6 +3015,24 @@ window.__ModuleLoader__.load({
|
|
|
2751
3015
|
modelCatalogFailed: "无法加载可用模型。",
|
|
2752
3016
|
capabilitiesHeading: "可选能力",
|
|
2753
3017
|
capabilitiesIntro: "选择允许此 dsh profile 注册哪些额外的 Codex 能力。",
|
|
3018
|
+
networkHeading: "网络连接",
|
|
3019
|
+
networkIntro: "默认使用直连。代理检测只测试有限的本机和环境变量候选地址;只有你选择“使用此代理”并保存后才会写入设置。",
|
|
3020
|
+
directConnection: "直连",
|
|
3021
|
+
customProxyActive: "已选择自定义代理:{proxyUrl}",
|
|
3022
|
+
detectProxy: "检测代理",
|
|
3023
|
+
detectingProxy: "正在检测…",
|
|
3024
|
+
configureProxyManually: "手动配置",
|
|
3025
|
+
disableProxy: "停用代理",
|
|
3026
|
+
proxyCandidatesFound: "找到了可用的代理候选地址。请选择一个,将其暂存以便启用。",
|
|
3027
|
+
keepDirectConnection: "保持直连",
|
|
3028
|
+
useThisProxy: "使用此代理",
|
|
3029
|
+
proxyDetectionFailed: "没有找到可用代理。请检查 DNS、连接被拒绝、超时、TLS 或代理认证错误后重试。",
|
|
3030
|
+
proxyAddress: "自定义代理地址",
|
|
3031
|
+
testProxy: "测试代理",
|
|
3032
|
+
testingProxy: "正在测试…",
|
|
3033
|
+
proxyTestSucceeded: "代理已到达 Codex 端点(HTTP {status})。",
|
|
3034
|
+
proxyTestFailed: "代理测试失败:{reason}。",
|
|
3035
|
+
invalidProxyUrl: "请输入不含凭据或路径的 HTTP(S) 代理 origin。",
|
|
2754
3036
|
enableSearch: "启用 Codex 搜索提供方",
|
|
2755
3037
|
enableSearchHelp: "让 OpenAI Codex 可被选作搜索提供方,但不会自动改动全局搜索路由。",
|
|
2756
3038
|
searchModel: "搜索模型",
|
|
@@ -2859,6 +3141,7 @@ window.__ModuleLoader__.load({
|
|
|
2859
3141
|
updateHighlightImageGeneration: "在 Codex Connect 设置中加入可选的 GPT Image 生图,并在对话里展示生成结果卡片。",
|
|
2860
3142
|
updateHighlightOauthHistory: "增加更安全的会话历史迁移,并在账号需要重新登录时提供备用登录路径。",
|
|
2861
3143
|
updateHighlightModelVisibility: "现在可以选择哪些 Codex 模型显示在模型选择菜单中。",
|
|
3144
|
+
updateHighlightProxyConnection: "增加可选的 Codex 代理检测,启用前需要明确确认,并始终保留直连回退入口。",
|
|
2862
3145
|
viewTechnicalDetails: "查看完整技术说明",
|
|
2863
3146
|
hideTechnicalDetails: "收起技术说明",
|
|
2864
3147
|
technicalDetailsHeading: "技术变更",
|
|
@@ -3947,7 +4230,7 @@ window.__ModuleLoader__.load({
|
|
|
3947
4230
|
}
|
|
3948
4231
|
//#endregion
|
|
3949
4232
|
//#region src/version.ts
|
|
3950
|
-
const CODEX_CONNECT_VERSION = "0.1.0-alpha.4.
|
|
4233
|
+
const CODEX_CONNECT_VERSION = "0.1.0-alpha.4.20";
|
|
3951
4234
|
//#endregion
|
|
3952
4235
|
//#region src/client/index.tsx
|
|
3953
4236
|
/** Stable browser-plugin name. */
|