dsh-codex-connect 0.1.0-alpha.4.13 → 0.1.0-alpha.4.14
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 +1 -1
- package/MIGRATION.md +18 -0
- package/README.i18n.yaml +2 -2
- package/README.md +3 -2
- package/docs/README.zh.md +3 -2
- package/lib/bin.js +43 -5
- package/lib/client.js +39 -11
- package/lib/index.d.ts +36 -1
- package/lib/index.js +2 -2
- package/lib/{src-zOltFEBG.js → src-15cHQKm5.js} +268 -4
- package/package.json +1 -1
package/INSTALL.md
CHANGED
|
@@ -21,7 +21,7 @@ The only verified combination is DSH plugin API packages `0.1.0-rc.7`, `@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.14` is published, pin it exactly with `dsh plugin --profile web add dsh-codex-connect@0.1.0-alpha.4.14`. 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.14'`.
|
|
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/MIGRATION.md
CHANGED
|
@@ -10,3 +10,21 @@
|
|
|
10
10
|
6. Run `--dump-config`, then `dsh-codex-connect doctor`. Do not run OAuth again when `status` already reports signed in.
|
|
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
|
+
|
|
14
|
+
## Repairing search history written by Alpha 4.10
|
|
15
|
+
|
|
16
|
+
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.
|
|
17
|
+
|
|
18
|
+
Upgrade Codex Connect, then inspect the default `$DSH_HOME/sessions` root without changing it:
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
dsh plugin --profile web exec dsh-codex-connect migrate-history --json
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
If the dry run reports affected events, stop every DSH process that can write this Session root and apply the migration. `--confirm-stopped` is required together with `--apply`:
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
dsh plugin --profile web exec dsh-codex-connect migrate-history --apply --confirm-stopped --json
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The migration changes only that retired event's envelope by adding `"ignorable": true`. It preserves event data, sequence, time, and the concatenated Zstandard frame layout, and creates `session.jsonl.zstd.pre-codex-search-history-migration` beside every changed artifact before replacing it. Keep that backup until you have reopened and verified the repaired Session. Re-running the command is safe. For a non-default JSONL persistence root, pass `--root /absolute/path/to/sessions`. SQLite and uncompressed JSONL stores are not modified by this command. Applying fails closed when the filesystem cannot create the required same-directory hard-link backup. Applying is also fail-closed on Windows; Windows users can run the dry-run only.
|
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: c496db682e79e0cd36471a2c592de4284819b450
|
|
6
|
+
docs/README.zh.md: 718224bb667a95a9b20fabf59f3d5d5732923790
|
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.14`. 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.14'`. A local checkout can be installed as `link:/absolute/path/to/dsh-codex-connect`.
|
|
32
32
|
|
|
33
33
|
### 2. Start Harness
|
|
34
34
|
|
|
@@ -50,7 +50,7 @@ Expected result: a fresh installation shows **Not signed in** and a **Sign in wi
|
|
|
50
50
|
|
|
51
51
|
### 4. Sign in with ChatGPT
|
|
52
52
|
|
|
53
|
-
Click **Sign in with ChatGPT** and complete the browser approval yourself. Do not copy an authorization URL, code, token, or account identifier into an issue, log, or configuration file.
|
|
53
|
+
Click **Sign in with ChatGPT** and complete the browser approval yourself. If an embedded WebView blocks the sign-in window, use the displayed **Open ChatGPT sign-in page** link to continue in your system browser. Do not copy an authorization URL, code, token, or account identifier into an issue, log, or configuration file.
|
|
54
54
|
|
|
55
55
|
Expected result: the account area changes to **Signed in**. The screenshot below is the successful end state after this step; it is not the initial sign-in screen.
|
|
56
56
|
|
|
@@ -164,6 +164,7 @@ Selecting Codex as the profile's global search route is another explicit change:
|
|
|
164
164
|
- If the card says **Sign in again** or the server asks for reauthentication, click that action and complete the same safe browser flow. It preserves this plugin's capability settings and does not silently change your default model or global search route. Do not run `logout` just to renew a session.
|
|
165
165
|
- `doctor` reads process and filesystem metadata only. `doctor --json` emits exactly one secret-free JSON document with schema version 1, package/version/Node metadata, credential-file state and safe mode, capabilities, conflict status, and hints. It omits the absolute credential path and OAuth, account, and expiry data.
|
|
166
166
|
- `status --json` emits only signed-in or signed-out state with package metadata. `status --json` reads the credential only to determine sign-in state, but never prints credential contents or starts OAuth.
|
|
167
|
+
- Alpha 4.10 users whose search histories fail with an unknown `web/openai-codex-search-llm-request` event can run `dsh-codex-connect migrate-history --json`, stop DSH, then apply the reported repair with `migrate-history --apply --confirm-stopped --json`. The command is dry-run by default, backs up every changed compressed JSONL artifact, and is dry-run only on Windows; see [MIGRATION.md](MIGRATION.md).
|
|
167
168
|
- OAuth is stored separately at `$DSH_HOME/.openai-codex-auth.json` (`~/.dsh` by default). `~/.codex/auth.json` is never copied or modified. The parent directory and file use owner-only permissions where supported, writes are atomic, and refresh writes use a cross-process file lock.
|
|
168
169
|
- By default, the OAuth routes accept loopback browser requests only. When DSH runs on one device and you open it from another device on a trusted network, approve the browser address-bar origin explicitly on the device that runs DSH:
|
|
169
170
|
|
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.14`。对应 GitHub prerelease 已创建但 npm 不可用时,可使用 `dsh plugin --profile web add 'github:franksong2702/dsh-codex-connect#v0.1.0-alpha.4.14'`。本地 checkout 可安装为 `link:/absolute/path/to/dsh-codex-connect`。
|
|
32
32
|
|
|
33
33
|
### 2. 启动 Harness
|
|
34
34
|
|
|
@@ -50,7 +50,7 @@ dsh web
|
|
|
50
50
|
|
|
51
51
|
### 4. 使用 ChatGPT 登录
|
|
52
52
|
|
|
53
|
-
点击 **使用 ChatGPT
|
|
53
|
+
点击 **使用 ChatGPT 登录**,并自行完成浏览器审批。如果内嵌 WebView 阻止登录窗口,请点击页面显示的 **打开 ChatGPT 登录页面**,在系统浏览器中继续。不要把授权 URL、授权码、token 或账户标识复制到 Issue、日志或配置文件中。
|
|
54
54
|
|
|
55
55
|
预期结果:账户区变为 **已登录**。下图展示的是完成本步骤后的成功状态,不是开始登录前的页面。
|
|
56
56
|
|
|
@@ -163,6 +163,7 @@ dsh plugin --profile web exec dsh-codex-connect doctor --json
|
|
|
163
163
|
|
|
164
164
|
- 卡片显示 **重新登录**,或服务端要求重新认证时,点击该操作并完成同一套安全的浏览器流程。它会保留本插件的能力配置,不会偷偷改动默认模型或全局搜索路由。不要为了刷新会话而运行 `logout`。
|
|
165
165
|
- `doctor` 只读取进程与文件系统元数据。`doctor --json` 只输出一条可解析的非敏感 JSON,包含 schema version 1、包/版本/Node 信息、认证文件状态与安全 mode、能力、冲突状态和提示;它省略认证文件绝对路径以及 OAuth、账户和过期时间信息。
|
|
166
|
+
- Alpha 4.10 用户若因未知的 `web/openai-codex-search-llm-request` 事件而无法读取搜索历史,可先运行 `dsh-codex-connect migrate-history --json`,停止 DSH 后再以 `migrate-history --apply --confirm-stopped --json` 应用修复。该命令默认只预检,会备份每个被修改的压缩 JSONL 文件,Windows 仅支持预检;详见 [MIGRATION.md](../MIGRATION.md)。
|
|
166
167
|
- `status --json` 只输出 signed-in 或 signed-out 状态及包元数据。它只为判断登录态读取认证文件,但不会输出认证文件内容或启动 OAuth。
|
|
167
168
|
- OAuth 单独存储于 `$DSH_HOME/.openai-codex-auth.json`(默认 `~/.dsh`)。`~/.codex/auth.json` 不会被复制或修改。支持的平台上,父目录与文件使用仅所有者可访问权限;写入采用原子替换,刷新写入使用跨进程文件锁。
|
|
168
169
|
- 默认情况下,OAuth 路由只接受 loopback 浏览器请求。当 DSH 在一台设备运行,而你从可信网络中的另一台设备打开 DSH 时,请在运行 DSH 的设备上显式批准浏览器地址栏中的 origin:
|
package/lib/bin.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { L as diagnoseOpenAICodex, c as migrateOpenAICodexSearchHistory, ct as logoutOpenAICodex, lt as openAICodexAuthStatus, nt as OpenAICodexTrustedOriginsStore, pt as openAICodexAuthPath, rt as normalizeTrustedOrigin, st as loginOpenAICodex, z as CODEX_CONNECT_VERSION } from "./src-15cHQKm5.js";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
|
-
import { spawn } from "node:child_process";
|
|
5
4
|
import { realpathSync } from "node:fs";
|
|
5
|
+
import { spawn } from "node:child_process";
|
|
6
6
|
import { createInterface } from "node:readline/promises";
|
|
7
7
|
//#region src/bin.ts
|
|
8
8
|
/** Standalone credential CLI for the optional OpenAI Codex bundle. */
|
|
@@ -65,6 +65,7 @@ async function answerPrompt(prompt, deviceCode, question) {
|
|
|
65
65
|
function printHelp() {
|
|
66
66
|
process.stdout.write([
|
|
67
67
|
"Usage: dsh-codex-connect <doctor|login|logout|status> [--device-code|--json]",
|
|
68
|
+
" dsh-codex-connect migrate-history [--apply --confirm-stopped] [--root <path>] [--json]",
|
|
68
69
|
" dsh-codex-connect trust-origin <origin>",
|
|
69
70
|
" dsh-codex-connect trusted-origins [--json]",
|
|
70
71
|
" dsh-codex-connect untrust-origin <origin>",
|
|
@@ -72,12 +73,13 @@ function printHelp() {
|
|
|
72
73
|
" doctor inspect secret-free runtime and OAuth file metadata",
|
|
73
74
|
" login sign in with a separate ChatGPT OAuth session",
|
|
74
75
|
" logout remove the dsh credential without changing ~/.codex",
|
|
76
|
+
" migrate-history find or repair Alpha 4.10 private search events (dry-run by default)",
|
|
75
77
|
" status report non-secret dsh credential state",
|
|
76
78
|
" trust-origin allow one exact browser origin to reach Web OAuth routes",
|
|
77
79
|
" trusted-origins list the currently allowed browser origins",
|
|
78
80
|
" untrust-origin remove one exact browser origin from the allowlist",
|
|
79
81
|
" --device-code use headless device-code login (login only)",
|
|
80
|
-
" --json emit one
|
|
82
|
+
" --json emit one JSON document (doctor/status/trusted-origins/migrate-history)",
|
|
81
83
|
""
|
|
82
84
|
].join("\n"));
|
|
83
85
|
}
|
|
@@ -118,12 +120,13 @@ async function run(argv) {
|
|
|
118
120
|
"doctor",
|
|
119
121
|
"login",
|
|
120
122
|
"logout",
|
|
123
|
+
"migrate-history",
|
|
121
124
|
"status",
|
|
122
125
|
"trust-origin",
|
|
123
126
|
"trusted-origins",
|
|
124
127
|
"untrust-origin"
|
|
125
128
|
].includes(rawAction)) {
|
|
126
|
-
process.stderr.write(`dsh-codex-connect: expected doctor, login, logout, status, trust-origin, trusted-origins, or untrust-origin; got ${JSON.stringify(rawAction)}\n`);
|
|
129
|
+
process.stderr.write(`dsh-codex-connect: expected doctor, login, logout, migrate-history, status, trust-origin, trusted-origins, or untrust-origin; got ${JSON.stringify(rawAction)}\n`);
|
|
127
130
|
return 1;
|
|
128
131
|
}
|
|
129
132
|
const action = rawAction;
|
|
@@ -131,7 +134,25 @@ async function run(argv) {
|
|
|
131
134
|
const optionFlags = action === "trust-origin" || action === "untrust-origin" ? flags.slice(1) : flags;
|
|
132
135
|
const deviceCode = optionFlags.includes("--device-code");
|
|
133
136
|
const jsonOutput = optionFlags.includes("--json");
|
|
134
|
-
|
|
137
|
+
let migrationRoot;
|
|
138
|
+
let migrationApply = false;
|
|
139
|
+
let migrationConfirmStopped = false;
|
|
140
|
+
const unknown = [];
|
|
141
|
+
if (action === "migrate-history") for (let index = 0; index < optionFlags.length; index += 1) {
|
|
142
|
+
const flag = optionFlags[index];
|
|
143
|
+
if (flag === "--apply") {
|
|
144
|
+
if (migrationApply) unknown.push(flag ?? "");
|
|
145
|
+
migrationApply = true;
|
|
146
|
+
} else if (flag === "--confirm-stopped") {
|
|
147
|
+
if (migrationConfirmStopped) unknown.push(flag ?? "");
|
|
148
|
+
migrationConfirmStopped = true;
|
|
149
|
+
} else if (flag === "--json") {} else if (flag === "--root" && migrationRoot === void 0 && optionFlags[index + 1] !== void 0 && !optionFlags[index + 1]?.startsWith("--")) {
|
|
150
|
+
migrationRoot = optionFlags[index + 1];
|
|
151
|
+
index += 1;
|
|
152
|
+
} else unknown.push(flag ?? "");
|
|
153
|
+
}
|
|
154
|
+
else unknown.push(...optionFlags.filter((flag) => flag !== "--device-code" && flag !== "--json"));
|
|
155
|
+
if (unknown.length > 0 || deviceCode && action !== "login" || jsonOutput && (action === "login" || action === "logout" || deviceCode) || action === "migrate-history" && (migrationConfirmStopped && !migrationApply || migrationApply && !migrationConfirmStopped) || (action === "trust-origin" || action === "untrust-origin") && (originArgument === void 0 || optionFlags.length !== 0)) {
|
|
135
156
|
process.stderr.write(`dsh-codex-connect: invalid options for ${action}: ${flags.join(" ")}\n`);
|
|
136
157
|
return 1;
|
|
137
158
|
}
|
|
@@ -154,6 +175,23 @@ async function run(argv) {
|
|
|
154
175
|
].join("\n"));
|
|
155
176
|
return doctorExitCode(report);
|
|
156
177
|
}
|
|
178
|
+
case "migrate-history": {
|
|
179
|
+
const result = await migrateOpenAICodexSearchHistory({
|
|
180
|
+
apply: migrationApply,
|
|
181
|
+
...migrationConfirmStopped ? { confirmStopped: true } : {},
|
|
182
|
+
...migrationRoot === void 0 ? {} : { root: migrationRoot }
|
|
183
|
+
});
|
|
184
|
+
if (jsonOutput) printJson({
|
|
185
|
+
schemaVersion: JSON_SCHEMA_VERSION,
|
|
186
|
+
...result
|
|
187
|
+
});
|
|
188
|
+
else {
|
|
189
|
+
const verb = result.mode === "apply" ? "Repaired" : "Found";
|
|
190
|
+
process.stdout.write(`${verb} ${result.changedEvents} legacy Codex search event(s) in ${result.changedFiles} session file(s) under ${result.root}.\n`);
|
|
191
|
+
if (result.mode === "dry-run" && result.changedEvents > 0) process.stdout.write("Stop DSH, then run again with --apply --confirm-stopped to create backups and repair these histories.\n");
|
|
192
|
+
}
|
|
193
|
+
return 0;
|
|
194
|
+
}
|
|
157
195
|
case "status": {
|
|
158
196
|
const status = await openAICodexAuthStatus();
|
|
159
197
|
if (jsonOutput) {
|
package/lib/client.js
CHANGED
|
@@ -745,6 +745,7 @@ window.__ModuleLoader__.load({
|
|
|
745
745
|
const [busy, setBusy] = (0, react.useState)(false);
|
|
746
746
|
const [copied, setCopied] = (0, react.useState)(false);
|
|
747
747
|
const [copyFailed, setCopyFailed] = (0, react.useState)(false);
|
|
748
|
+
const [loginUrl, setLoginUrl] = (0, react.useState)();
|
|
748
749
|
const mounted = (0, react.useRef)(true);
|
|
749
750
|
const trustedOriginCommand = `dsh plugin --profile web exec dsh-codex-connect trust-origin ${window.location.origin}`;
|
|
750
751
|
(0, react.useEffect)(() => {
|
|
@@ -783,27 +784,27 @@ window.__ModuleLoader__.load({
|
|
|
783
784
|
controller.abort();
|
|
784
785
|
};
|
|
785
786
|
}, [refresh, status.status]);
|
|
787
|
+
(0, react.useEffect)(() => {
|
|
788
|
+
if (status.status !== "signing-in") setLoginUrl(void 0);
|
|
789
|
+
}, [status.status]);
|
|
786
790
|
const signIn = async () => {
|
|
787
791
|
const popup = window.open("about:blank", "_blank");
|
|
788
|
-
if (popup
|
|
789
|
-
setStatus({
|
|
790
|
-
status: "error",
|
|
791
|
-
message: t("popupBlocked")
|
|
792
|
-
});
|
|
793
|
-
return;
|
|
794
|
-
}
|
|
795
|
-
popup.opener = null;
|
|
792
|
+
if (popup !== null) popup.opener = null;
|
|
796
793
|
setBusy(true);
|
|
797
794
|
setStatus({ status: "signing-in" });
|
|
798
795
|
try {
|
|
799
796
|
const challenge = await jsonRequest(OPENAI_CODEX_AUTH_LOGIN_PATH, "POST");
|
|
800
797
|
if (!mounted.current) {
|
|
801
|
-
popup
|
|
798
|
+
popup?.close();
|
|
802
799
|
return;
|
|
803
800
|
}
|
|
804
|
-
popup
|
|
801
|
+
if (popup !== null) {
|
|
802
|
+
setLoginUrl(void 0);
|
|
803
|
+
popup.location.replace(challenge.url);
|
|
804
|
+
} else setLoginUrl(challenge.url);
|
|
805
805
|
} catch (error) {
|
|
806
806
|
popup?.close();
|
|
807
|
+
setLoginUrl(void 0);
|
|
807
808
|
if (mounted.current) setStatus(error instanceof AccountRequestError && error.code === "remote-web-origin-not-trusted" ? { status: "remote-web-origin-not-trusted" } : {
|
|
808
809
|
status: "error",
|
|
809
810
|
message: error instanceof Error ? error.message : t("requestFailed")
|
|
@@ -874,7 +875,7 @@ window.__ModuleLoader__.load({
|
|
|
874
875
|
signOut();
|
|
875
876
|
},
|
|
876
877
|
children: busy ? t("working") : t("logout")
|
|
877
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
878
|
+
}) : status.status === "signing-in" && loginUrl !== void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
878
879
|
type: "button",
|
|
879
880
|
style: primaryButtonStyle,
|
|
880
881
|
disabled: busy,
|
|
@@ -884,6 +885,29 @@ window.__ModuleLoader__.load({
|
|
|
884
885
|
children: busy ? t("working") : status.status === "error" || status.status === "reauth-required" ? t("loginAgain") : t("login")
|
|
885
886
|
})]
|
|
886
887
|
}),
|
|
888
|
+
loginUrl === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
889
|
+
style: {
|
|
890
|
+
display: "flex",
|
|
891
|
+
flexDirection: "column",
|
|
892
|
+
alignItems: "flex-start",
|
|
893
|
+
gap: 10
|
|
894
|
+
},
|
|
895
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
896
|
+
style: bodyStyle,
|
|
897
|
+
children: t("popupBlockedFallback")
|
|
898
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
899
|
+
href: loginUrl,
|
|
900
|
+
target: "_blank",
|
|
901
|
+
rel: "noopener noreferrer",
|
|
902
|
+
style: {
|
|
903
|
+
...primaryButtonStyle,
|
|
904
|
+
display: "inline-flex",
|
|
905
|
+
alignItems: "center",
|
|
906
|
+
textDecoration: "none"
|
|
907
|
+
},
|
|
908
|
+
children: t("openLoginInBrowser")
|
|
909
|
+
})]
|
|
910
|
+
}),
|
|
887
911
|
status.status === "error" || status.status === "reauth-required" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
888
912
|
style: errorStyle,
|
|
889
913
|
children: status.message
|
|
@@ -1479,6 +1503,8 @@ window.__ModuleLoader__.load({
|
|
|
1479
1503
|
working: "Working…",
|
|
1480
1504
|
retry: "Retry",
|
|
1481
1505
|
popupBlocked: "The browser blocked the sign-in window. Allow pop-ups for this dsh page and retry.",
|
|
1506
|
+
popupBlockedFallback: "The sign-in window could not be opened automatically. Use the link below to continue in your browser.",
|
|
1507
|
+
openLoginInBrowser: "Open ChatGPT sign-in page",
|
|
1482
1508
|
usageLimits: "Usage limits",
|
|
1483
1509
|
fiveHourLimit: "5-hour limit",
|
|
1484
1510
|
weeklyLimit: "Weekly limit",
|
|
@@ -1576,6 +1602,8 @@ window.__ModuleLoader__.load({
|
|
|
1576
1602
|
working: "处理中…",
|
|
1577
1603
|
retry: "重试",
|
|
1578
1604
|
popupBlocked: "浏览器阻止了登录窗口。请允许此 dsh 页面弹出窗口后重试。",
|
|
1605
|
+
popupBlockedFallback: "无法自动打开登录窗口。请使用下面的链接在浏览器中继续登录。",
|
|
1606
|
+
openLoginInBrowser: "打开 ChatGPT 登录页面",
|
|
1579
1607
|
usageLimits: "使用额度",
|
|
1580
1608
|
fiveHourLimit: "5 小时额度",
|
|
1581
1609
|
weeklyLimit: "每周额度",
|
package/lib/index.d.ts
CHANGED
|
@@ -471,6 +471,41 @@ declare class FastModeRegistry {
|
|
|
471
471
|
/** GET/POST endpoint for one conversation's process-local Fast Mode state. */
|
|
472
472
|
declare const OPENAI_CODEX_FAST_MODE_PATH = "/plugins/dsh-openai-codex/fast-mode";
|
|
473
473
|
//#endregion
|
|
474
|
+
//#region src/history-migration.d.ts
|
|
475
|
+
/** Offline compatibility migration for the private Codex search event emitted by Alpha 4.10. */
|
|
476
|
+
/** Private event written by Alpha 4.10 before the provider stopped persisting it. */
|
|
477
|
+
declare const OPENAI_CODEX_SEARCH_MODEL_REQUEST_EVENT = "web/openai-codex-search-llm-request";
|
|
478
|
+
/** Backup suffix created beside every changed session artifact. */
|
|
479
|
+
declare const OPENAI_CODEX_HISTORY_BACKUP_SUFFIX = ".pre-codex-search-history-migration";
|
|
480
|
+
interface OpenAICodexHistoryMigrationOptions {
|
|
481
|
+
/** Apply changes; omitted/false performs a read-only dry run. */
|
|
482
|
+
readonly apply?: boolean;
|
|
483
|
+
/** Required acknowledgement that every DSH writer using this root is stopped. */
|
|
484
|
+
readonly confirmStopped?: boolean;
|
|
485
|
+
/** Explicit JSONL persistence root. Defaults to `<DSH_HOME>/sessions`. */
|
|
486
|
+
readonly root?: string;
|
|
487
|
+
/** Optional Harness home override used only when `root` is omitted. */
|
|
488
|
+
readonly dshHome?: string;
|
|
489
|
+
}
|
|
490
|
+
interface OpenAICodexHistoryMigrationFile {
|
|
491
|
+
readonly path: string;
|
|
492
|
+
readonly changedEvents: number;
|
|
493
|
+
readonly backupPath?: string;
|
|
494
|
+
}
|
|
495
|
+
interface OpenAICodexHistoryMigrationResult {
|
|
496
|
+
readonly mode: 'apply' | 'dry-run';
|
|
497
|
+
readonly root: string;
|
|
498
|
+
readonly changedFiles: number;
|
|
499
|
+
readonly changedEvents: number;
|
|
500
|
+
readonly files: readonly OpenAICodexHistoryMigrationFile[];
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Mark the retired Alpha 4.10 search event ignorable in compressed JSONL logs.
|
|
504
|
+
* Applying is an offline maintenance operation and fails closed without the
|
|
505
|
+
* caller's explicit acknowledgement that all DSH writers are stopped.
|
|
506
|
+
*/
|
|
507
|
+
declare function migrateOpenAICodexSearchHistory(options?: OpenAICodexHistoryMigrationOptions): Promise<OpenAICodexHistoryMigrationResult>;
|
|
508
|
+
//#endregion
|
|
474
509
|
//#region src/index.d.ts
|
|
475
510
|
declare module '@deepseek-ai/cordis' {
|
|
476
511
|
interface Context {
|
|
@@ -511,4 +546,4 @@ declare const Config: z<Config>;
|
|
|
511
546
|
*/
|
|
512
547
|
declare function apply(ctx: Context, config: Config): void;
|
|
513
548
|
//#endregion
|
|
514
|
-
export { COMPATIBILITY_CONTRACT, COMPATIBILITY_PACKAGES, COMPATIBILITY_SCHEMA_VERSION, type CompatibilityDetectionOptions, type CompatibilityEntry, type CompatibilityEvaluationInput, type CompatibilityPackageName, type CompatibilityReport, type CompatibilityStatus, Config, 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, type GeneratedImagePayload, IMAGE_GENERATE_TOOL_NAME, type ImageGenerationRequest, type ImageGenerationResponse, type ImageRequestContext, OPENAI_CODEX_AUTH_FILENAME, 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_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_PROVIDER, 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_USAGE_URL, type OpenAICodexAuthStatus, OpenAICodexCredentialStore, type OpenAICodexCredits, type OpenAICodexDiagnosticOptions, type OpenAICodexDiagnosticReport, type OpenAICodexIndividualLimit, type OpenAICodexRateLimit, type OpenAICodexRateLimitWindow, type OpenAICodexSearchContextSize, type OpenAICodexSearchMode, OpenAICodexSearchProvider, type OpenAICodexSearchProviderOptions, type OpenAICodexSearchRequestRecord, type OpenAICodexSettingsConfig, OpenAICodexTransport, OpenAICodexTransportError, type OpenAICodexTransportErrorCode, type OpenAICodexTransportV1, type OpenAICodexUsage, PI_AI_PACKAGE, SUPPORTED_DSH_PLUGIN_API_VERSION, SUPPORTED_NODE_RANGE, SUPPORTED_PI_AI_VERSION, VIEW_IMAGE_TOOL_NAME, apply, assertNoOpenAICodexProviderConflict, assessCompatibility, decodeOpenAICodexSettings, detectCompatibility, diagnoseOpenAICodex, evaluateCompatibility, inject, isFastModeSessionId, isOpenAICodexTransportError, loginOpenAICodex, logoutOpenAICodex, mapOpenAICodexSearchResponse, name, openAICodexAuthPath, openAICodexAuthStatus, openAICodexConflictMessage, parseOpenAICodexUsage, readOpenAICodexRateLimits, resolveOpenAICodexSettings };
|
|
549
|
+
export { COMPATIBILITY_CONTRACT, COMPATIBILITY_PACKAGES, COMPATIBILITY_SCHEMA_VERSION, type CompatibilityDetectionOptions, type CompatibilityEntry, type CompatibilityEvaluationInput, type CompatibilityPackageName, type CompatibilityReport, type CompatibilityStatus, Config, 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, type GeneratedImagePayload, IMAGE_GENERATE_TOOL_NAME, type ImageGenerationRequest, type ImageGenerationResponse, type ImageRequestContext, OPENAI_CODEX_AUTH_FILENAME, 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_PROVIDER, 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_USAGE_URL, type OpenAICodexAuthStatus, OpenAICodexCredentialStore, type OpenAICodexCredits, type OpenAICodexDiagnosticOptions, type OpenAICodexDiagnosticReport, type OpenAICodexHistoryMigrationFile, type OpenAICodexHistoryMigrationOptions, type OpenAICodexHistoryMigrationResult, type OpenAICodexIndividualLimit, type OpenAICodexRateLimit, type OpenAICodexRateLimitWindow, type OpenAICodexSearchContextSize, type OpenAICodexSearchMode, OpenAICodexSearchProvider, type OpenAICodexSearchProviderOptions, type OpenAICodexSearchRequestRecord, type OpenAICodexSettingsConfig, OpenAICodexTransport, OpenAICodexTransportError, type OpenAICodexTransportErrorCode, type OpenAICodexTransportV1, type OpenAICodexUsage, PI_AI_PACKAGE, SUPPORTED_DSH_PLUGIN_API_VERSION, SUPPORTED_NODE_RANGE, SUPPORTED_PI_AI_VERSION, VIEW_IMAGE_TOOL_NAME, apply, assertNoOpenAICodexProviderConflict, assessCompatibility, decodeOpenAICodexSettings, detectCompatibility, diagnoseOpenAICodex, evaluateCompatibility, inject, isFastModeSessionId, isOpenAICodexTransportError, loginOpenAICodex, logoutOpenAICodex, mapOpenAICodexSearchResponse, migrateOpenAICodexSearchHistory, name, openAICodexAuthPath, openAICodexAuthStatus, openAICodexConflictMessage, parseOpenAICodexUsage, readOpenAICodexRateLimits, resolveOpenAICodexSettings };
|
package/lib/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { A as
|
|
2
|
-
export { COMPATIBILITY_CONTRACT, COMPATIBILITY_PACKAGES, COMPATIBILITY_SCHEMA_VERSION, Config, 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_AUTH_FILENAME, 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_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_PROVIDER, 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_USAGE_URL, OpenAICodexCredentialStore, OpenAICodexSearchProvider, OpenAICodexTransport, OpenAICodexTransportError, PI_AI_PACKAGE, SUPPORTED_DSH_PLUGIN_API_VERSION, SUPPORTED_NODE_RANGE, SUPPORTED_PI_AI_VERSION, VIEW_IMAGE_TOOL_NAME, apply, assertNoOpenAICodexProviderConflict, assessCompatibility, decodeOpenAICodexSettings, detectCompatibility, diagnoseOpenAICodex, evaluateCompatibility, inject, isFastModeSessionId, isOpenAICodexTransportError, loginOpenAICodex, logoutOpenAICodex, mapOpenAICodexSearchResponse, name, openAICodexAuthPath, openAICodexAuthStatus, openAICodexConflictMessage, parseOpenAICodexUsage, readOpenAICodexRateLimits, resolveOpenAICodexSettings };
|
|
1
|
+
import { $ as OPENAI_CODEX_FAST_MODE_MAX_SESSIONS, A as OPENAI_CODEX_TRANSPORT_SERVICE, B as COMPATIBILITY_CONTRACT, C as OPENAI_CODEX_IMAGE_MAX_COUNT, D as OPENAI_CODEX_IMAGE_REQUEST_TIMEOUT_MS, E as OPENAI_CODEX_IMAGE_PROMPT_MAX_LENGTH, F as IMAGE_GENERATE_TOOL_NAME, G as SUPPORTED_DSH_PLUGIN_API_VERSION, H as COMPATIBILITY_SCHEMA_VERSION, I as assertNoOpenAICodexProviderConflict, J as assessCompatibility, K as SUPPORTED_NODE_RANGE, L as diagnoseOpenAICodex, M as OpenAICodexTransportError, N as isOpenAICodexTransportError, O as OPENAI_CODEX_TRANSPORT_API_VERSION, P as VIEW_IMAGE_TOOL_NAME, Q as FastModeRegistry, R as openAICodexConflictMessage, S as OPENAI_CODEX_IMAGE_GENERATION_URL, T as OPENAI_CODEX_IMAGE_MAX_RESPONSE_BYTES, U as DSH_PLUGIN_API_PACKAGES, V as COMPATIBILITY_PACKAGES, W as PI_AI_PACKAGE, X as evaluateCompatibility, Y as detectCompatibility, Z as OPENAI_CODEX_FAST_MODE_PATH, _ as DEFAULT_OPENAI_CODEX_SEARCH_MODEL, a as name, at as parseOpenAICodexUsage, b as decodeOpenAICodexSettings, c as migrateOpenAICodexSearchHistory, ct as logoutOpenAICodex, d as OPENAI_CODEX_SEARCH_URL, dt as OPENAI_CODEX_PROVIDER, et as OPENAI_CODEX_FAST_MODE_MAX_SESSION_ID_LENGTH, f as OpenAICodexSearchProvider, ft as OpenAICodexCredentialStore, g as DEFAULT_OPENAI_CODEX_SEARCH_MODE, h as DEFAULT_OPENAI_CODEX_SEARCH_MAX_OUTPUT_TOKENS, i as inject, it as OPENAI_CODEX_USAGE_URL, j as OpenAICodexTransport, k as OPENAI_CODEX_TRANSPORT_ERROR_CODES, l as OPENAI_CODEX_BASE_URL, lt as openAICodexAuthStatus, m as DEFAULT_OPENAI_CODEX_SEARCH_CONTEXT_SIZE, n as OPENAI_CODEX_SETTINGS_NS, o as OPENAI_CODEX_HISTORY_BACKUP_SUFFIX, ot as readOpenAICodexRateLimits, p as mapOpenAICodexSearchResponse, pt as openAICodexAuthPath, q as SUPPORTED_PI_AI_VERSION, r as apply, s as OPENAI_CODEX_SEARCH_MODEL_REQUEST_EVENT, st as loginOpenAICodex, t as Config, tt as isFastModeSessionId, u as OPENAI_CODEX_SEARCH_PROVIDER, ut as OPENAI_CODEX_AUTH_FILENAME, v as DEFAULT_OPENAI_CODEX_SETTINGS, w as OPENAI_CODEX_IMAGE_MAX_ERROR_BYTES, x as resolveOpenAICodexSettings, y as OPENAI_CODEX_SETTINGS_NAMESPACE } from "./src-15cHQKm5.js";
|
|
2
|
+
export { COMPATIBILITY_CONTRACT, COMPATIBILITY_PACKAGES, COMPATIBILITY_SCHEMA_VERSION, Config, 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_AUTH_FILENAME, 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_PROVIDER, 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_USAGE_URL, OpenAICodexCredentialStore, OpenAICodexSearchProvider, OpenAICodexTransport, OpenAICodexTransportError, PI_AI_PACKAGE, SUPPORTED_DSH_PLUGIN_API_VERSION, SUPPORTED_NODE_RANGE, SUPPORTED_PI_AI_VERSION, VIEW_IMAGE_TOOL_NAME, apply, assertNoOpenAICodexProviderConflict, assessCompatibility, decodeOpenAICodexSettings, detectCompatibility, diagnoseOpenAICodex, evaluateCompatibility, inject, isFastModeSessionId, isOpenAICodexTransportError, loginOpenAICodex, logoutOpenAICodex, mapOpenAICodexSearchResponse, migrateOpenAICodexSearchHistory, name, openAICodexAuthPath, openAICodexAuthStatus, openAICodexConflictMessage, parseOpenAICodexUsage, readOpenAICodexRateLimits, resolveOpenAICodexSettings };
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { randomUUID } from "node:crypto";
|
|
1
|
+
import { randomBytes, randomUUID } from "node:crypto";
|
|
2
2
|
import z from "@deepseek-ai/schemastery";
|
|
3
3
|
import { deepEqualJson, installSettingsSection, settingsNamespace } from "@deepseek-ai/dsh-settings";
|
|
4
4
|
import { createModels } from "@earendil-works/pi-ai";
|
|
5
5
|
import { openaiCodexProvider } from "@earendil-works/pi-ai/providers/openai-codex";
|
|
6
6
|
import { createUserMessage, resolveRetryPolicy } from "@deepseek-ai/dsh-llm";
|
|
7
7
|
import { PiAiAdapter } from "@deepseek-ai/dsh-llm-pi-ai";
|
|
8
|
-
import { lstat, mkdir, readFile, rm, stat } from "node:fs/promises";
|
|
8
|
+
import { link, lstat, mkdir, open, readFile, readdir, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
9
9
|
import { basename, dirname, join, parse, resolve } from "node:path";
|
|
10
10
|
import { withFileLock, writeFileAtomic } from "@deepseek-ai/dsh-atomic-write";
|
|
11
11
|
import { resolveDshHome } from "@deepseek-ai/dsh-home-paths";
|
|
@@ -18,6 +18,8 @@ import { request as request$1 } from "node:https";
|
|
|
18
18
|
import { BlockList, isIP } from "node:net";
|
|
19
19
|
import { Service } from "@deepseek-ai/cordis";
|
|
20
20
|
import { WebError } from "@deepseek-ai/dsh-web";
|
|
21
|
+
import { constants } from "node:fs";
|
|
22
|
+
import { constants as constants$1, zstdCompressSync, zstdDecompressSync } from "node:zlib";
|
|
21
23
|
//#region src/store.ts
|
|
22
24
|
/**
|
|
23
25
|
* Owner-only persistent OAuth credential storage for the OpenAI Codex bundle.
|
|
@@ -1209,7 +1211,7 @@ async function detectCompatibility(options = {}) {
|
|
|
1209
1211
|
}
|
|
1210
1212
|
//#endregion
|
|
1211
1213
|
//#region src/version.ts
|
|
1212
|
-
const CODEX_CONNECT_VERSION = "0.1.0-alpha.4.
|
|
1214
|
+
const CODEX_CONNECT_VERSION = "0.1.0-alpha.4.14";
|
|
1213
1215
|
//#endregion
|
|
1214
1216
|
//#region src/doctor.ts
|
|
1215
1217
|
/** Secret-free diagnostics and duplicate-provider guidance. */
|
|
@@ -2471,6 +2473,268 @@ var OpenAICodexSearchProvider = class {
|
|
|
2471
2473
|
}
|
|
2472
2474
|
};
|
|
2473
2475
|
//#endregion
|
|
2476
|
+
//#region src/history-migration.ts
|
|
2477
|
+
/** Offline compatibility migration for the private Codex search event emitted by Alpha 4.10. */
|
|
2478
|
+
/** Private event written by Alpha 4.10 before the provider stopped persisting it. */
|
|
2479
|
+
const OPENAI_CODEX_SEARCH_MODEL_REQUEST_EVENT = "web/openai-codex-search-llm-request";
|
|
2480
|
+
/** Backup suffix created beside every changed session artifact. */
|
|
2481
|
+
const OPENAI_CODEX_HISTORY_BACKUP_SUFFIX = ".pre-codex-search-history-migration";
|
|
2482
|
+
const ZSTD_MAGIC = 4247762216;
|
|
2483
|
+
const CHECKSUM_OPTIONS = { params: { [constants$1.ZSTD_c_checksumFlag]: 1 } };
|
|
2484
|
+
const STABLE_READ_ATTEMPTS = 3;
|
|
2485
|
+
function scanZstdFrames(buffer) {
|
|
2486
|
+
const frames = [];
|
|
2487
|
+
let offset = 0;
|
|
2488
|
+
while (offset < buffer.length) {
|
|
2489
|
+
const start = offset;
|
|
2490
|
+
if (buffer.length - offset < 4) throw new Error(`incomplete Zstandard frame magic at byte ${offset}`);
|
|
2491
|
+
if (buffer.readUInt32LE(offset) !== ZSTD_MAGIC) throw new Error(`invalid Zstandard frame magic at byte ${offset}`);
|
|
2492
|
+
offset += 4;
|
|
2493
|
+
if (offset === buffer.length) throw new Error(`incomplete Zstandard frame descriptor at byte ${offset}`);
|
|
2494
|
+
const descriptor = buffer.readUInt8(offset);
|
|
2495
|
+
offset += 1;
|
|
2496
|
+
if ((descriptor & 24) !== 0) throw new Error(`reserved Zstandard frame-header bit at byte ${offset - 1}`);
|
|
2497
|
+
const contentSizeFlag = descriptor >>> 6;
|
|
2498
|
+
const singleSegment = (descriptor & 32) !== 0;
|
|
2499
|
+
const checksum = (descriptor & 4) !== 0;
|
|
2500
|
+
const dictionaryFlag = descriptor & 3;
|
|
2501
|
+
const dictionaryBytes = dictionaryFlag === 3 ? 4 : dictionaryFlag;
|
|
2502
|
+
const contentSizeBytes = contentSizeFlag === 0 ? singleSegment ? 1 : 0 : 1 << contentSizeFlag;
|
|
2503
|
+
const remainingHeaderBytes = (singleSegment ? 0 : 1) + dictionaryBytes + contentSizeBytes;
|
|
2504
|
+
if (buffer.length - offset < remainingHeaderBytes) throw new Error(`incomplete Zstandard frame header at byte ${start}`);
|
|
2505
|
+
offset += remainingHeaderBytes;
|
|
2506
|
+
for (;;) {
|
|
2507
|
+
if (buffer.length - offset < 3) throw new Error(`incomplete Zstandard block header at byte ${offset}`);
|
|
2508
|
+
const blockHeader = buffer.readUIntLE(offset, 3);
|
|
2509
|
+
offset += 3;
|
|
2510
|
+
const lastBlock = (blockHeader & 1) !== 0;
|
|
2511
|
+
const blockType = blockHeader >>> 1 & 3;
|
|
2512
|
+
const blockSize = blockHeader >>> 3;
|
|
2513
|
+
if (blockType === 3) throw new Error(`reserved Zstandard block type at byte ${offset - 3}`);
|
|
2514
|
+
const payloadBytes = blockType === 1 ? 1 : blockSize;
|
|
2515
|
+
if (buffer.length - offset < payloadBytes) throw new Error(`incomplete Zstandard block payload at byte ${offset}`);
|
|
2516
|
+
offset += payloadBytes;
|
|
2517
|
+
if (lastBlock) break;
|
|
2518
|
+
}
|
|
2519
|
+
if (checksum) {
|
|
2520
|
+
if (buffer.length - offset < 4) throw new Error(`incomplete Zstandard checksum at byte ${offset}`);
|
|
2521
|
+
offset += 4;
|
|
2522
|
+
}
|
|
2523
|
+
frames.push({
|
|
2524
|
+
start,
|
|
2525
|
+
end: offset
|
|
2526
|
+
});
|
|
2527
|
+
}
|
|
2528
|
+
return frames;
|
|
2529
|
+
}
|
|
2530
|
+
function markLegacyEventIgnorable(line) {
|
|
2531
|
+
let record;
|
|
2532
|
+
try {
|
|
2533
|
+
record = JSON.parse(line);
|
|
2534
|
+
} catch {
|
|
2535
|
+
return;
|
|
2536
|
+
}
|
|
2537
|
+
if (typeof record !== "object" || record === null || Array.isArray(record)) return void 0;
|
|
2538
|
+
const event = record;
|
|
2539
|
+
if (event["type"] !== "web/openai-codex-search-llm-request" || event["ignorable"] === true) return void 0;
|
|
2540
|
+
if (event["ignorable"] !== void 0) throw new Error(`legacy Codex search event seq ${String(event["seq"])} has an unexpected ignorable value`);
|
|
2541
|
+
let objectEnd = line.length - 1;
|
|
2542
|
+
while (objectEnd >= 0 && /\s/u.test(line[objectEnd] ?? "")) objectEnd -= 1;
|
|
2543
|
+
if (line[objectEnd] !== "}") throw new Error(`legacy Codex search event seq ${String(event["seq"])} is not a JSON object`);
|
|
2544
|
+
return `${line.slice(0, objectEnd)},"ignorable":true${line.slice(objectEnd)}`;
|
|
2545
|
+
}
|
|
2546
|
+
function rewriteFrame(frame) {
|
|
2547
|
+
const lines = zstdDecompressSync(frame).toString("utf8").split("\n");
|
|
2548
|
+
let changedEvents = 0;
|
|
2549
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
2550
|
+
const line = lines[index];
|
|
2551
|
+
if (line === void 0 || line.length === 0) continue;
|
|
2552
|
+
const migrated = markLegacyEventIgnorable(line);
|
|
2553
|
+
if (migrated === void 0) continue;
|
|
2554
|
+
lines[index] = migrated;
|
|
2555
|
+
changedEvents += 1;
|
|
2556
|
+
}
|
|
2557
|
+
if (changedEvents === 0) return {
|
|
2558
|
+
frame,
|
|
2559
|
+
changedEvents
|
|
2560
|
+
};
|
|
2561
|
+
return {
|
|
2562
|
+
frame: zstdCompressSync(Buffer.from(lines.join("\n")), CHECKSUM_OPTIONS),
|
|
2563
|
+
changedEvents
|
|
2564
|
+
};
|
|
2565
|
+
}
|
|
2566
|
+
function validateMigration(original, migrated, expectedChanges) {
|
|
2567
|
+
const beforeFrames = scanZstdFrames(original);
|
|
2568
|
+
const afterFrames = scanZstdFrames(migrated);
|
|
2569
|
+
if (beforeFrames.length !== afterFrames.length) throw new Error("Zstandard frame count changed during migration");
|
|
2570
|
+
let changes = 0;
|
|
2571
|
+
for (let index = 0; index < beforeFrames.length; index += 1) {
|
|
2572
|
+
const beforeRange = beforeFrames[index];
|
|
2573
|
+
const afterRange = afterFrames[index];
|
|
2574
|
+
if (beforeRange === void 0 || afterRange === void 0) throw new Error("missing Zstandard frame during validation");
|
|
2575
|
+
const beforeLines = zstdDecompressSync(original.subarray(beforeRange.start, beforeRange.end)).toString("utf8").split("\n");
|
|
2576
|
+
const afterLines = zstdDecompressSync(migrated.subarray(afterRange.start, afterRange.end)).toString("utf8").split("\n");
|
|
2577
|
+
if (beforeLines.length !== afterLines.length) throw new Error(`logical line count changed in frame ${index}`);
|
|
2578
|
+
for (let line = 0; line < beforeLines.length; line += 1) {
|
|
2579
|
+
if (beforeLines[line] === afterLines[line]) continue;
|
|
2580
|
+
const expected = markLegacyEventIgnorable(beforeLines[line] ?? "");
|
|
2581
|
+
if (expected === void 0) throw new Error(`non-target record changed in frame ${index}, line ${line + 1}`);
|
|
2582
|
+
if (afterLines[line] !== expected) throw new Error(`legacy event changed beyond its ignorable marker in frame ${index}, line ${line + 1}`);
|
|
2583
|
+
changes += 1;
|
|
2584
|
+
}
|
|
2585
|
+
}
|
|
2586
|
+
if (changes !== expectedChanges) throw new Error(`validated ${changes} changes, expected ${expectedChanges}`);
|
|
2587
|
+
}
|
|
2588
|
+
function revision(metadata) {
|
|
2589
|
+
return [
|
|
2590
|
+
metadata.dev,
|
|
2591
|
+
metadata.ino,
|
|
2592
|
+
metadata.size,
|
|
2593
|
+
metadata.mtimeNs,
|
|
2594
|
+
metadata.ctimeNs
|
|
2595
|
+
].join(":");
|
|
2596
|
+
}
|
|
2597
|
+
async function readStableFile(path) {
|
|
2598
|
+
for (let attempt = 0; attempt < STABLE_READ_ATTEMPTS; attempt += 1) {
|
|
2599
|
+
const before = revision(await stat(path, { bigint: true }));
|
|
2600
|
+
const content = await readFile(path);
|
|
2601
|
+
if (before === revision(await stat(path, { bigint: true }))) return content;
|
|
2602
|
+
}
|
|
2603
|
+
throw new Error(`session kept changing during ${STABLE_READ_ATTEMPTS} stable-read attempts: ${path}`);
|
|
2604
|
+
}
|
|
2605
|
+
function renderMigration(original) {
|
|
2606
|
+
const frames = scanZstdFrames(original);
|
|
2607
|
+
const output = [];
|
|
2608
|
+
let changedEvents = 0;
|
|
2609
|
+
for (const frame of frames) {
|
|
2610
|
+
const rewritten = rewriteFrame(original.subarray(frame.start, frame.end));
|
|
2611
|
+
output.push(rewritten.frame);
|
|
2612
|
+
changedEvents += rewritten.changedEvents;
|
|
2613
|
+
}
|
|
2614
|
+
const migrated = Buffer.concat(output);
|
|
2615
|
+
if (changedEvents > 0) validateMigration(original, migrated, changedEvents);
|
|
2616
|
+
return {
|
|
2617
|
+
migrated,
|
|
2618
|
+
changedEvents
|
|
2619
|
+
};
|
|
2620
|
+
}
|
|
2621
|
+
async function* sessionArtifacts(root) {
|
|
2622
|
+
const pending = [root];
|
|
2623
|
+
while (pending.length > 0) {
|
|
2624
|
+
const current = pending.pop();
|
|
2625
|
+
if (current === void 0) continue;
|
|
2626
|
+
let entries;
|
|
2627
|
+
try {
|
|
2628
|
+
entries = await readdir(current, { withFileTypes: true });
|
|
2629
|
+
} catch (error) {
|
|
2630
|
+
if (error.code === "ENOENT") continue;
|
|
2631
|
+
throw error;
|
|
2632
|
+
}
|
|
2633
|
+
for (const entry of entries) {
|
|
2634
|
+
const path = join(current, entry.name);
|
|
2635
|
+
if (entry.isDirectory()) pending.push(path);
|
|
2636
|
+
else if (entry.isFile() && entry.name === "session.jsonl.zstd") yield path;
|
|
2637
|
+
}
|
|
2638
|
+
}
|
|
2639
|
+
}
|
|
2640
|
+
async function syncParentDirectory(path) {
|
|
2641
|
+
const directory = await open(dirname(path), "r");
|
|
2642
|
+
try {
|
|
2643
|
+
await directory.sync();
|
|
2644
|
+
} finally {
|
|
2645
|
+
await directory.close();
|
|
2646
|
+
}
|
|
2647
|
+
}
|
|
2648
|
+
async function migrateArtifact(path, apply) {
|
|
2649
|
+
if (!apply) {
|
|
2650
|
+
const { changedEvents } = renderMigration(await readStableFile(path));
|
|
2651
|
+
return changedEvents === 0 ? void 0 : {
|
|
2652
|
+
path,
|
|
2653
|
+
changedEvents
|
|
2654
|
+
};
|
|
2655
|
+
}
|
|
2656
|
+
return withFileLock(path, async () => {
|
|
2657
|
+
const original = await readStableFile(path);
|
|
2658
|
+
const { migrated, changedEvents } = renderMigration(original);
|
|
2659
|
+
if (changedEvents === 0) return void 0;
|
|
2660
|
+
const metadata = await stat(path);
|
|
2661
|
+
const sourceIdentity = await stat(path, { bigint: true });
|
|
2662
|
+
const backupPath = path + OPENAI_CODEX_HISTORY_BACKUP_SUFFIX;
|
|
2663
|
+
try {
|
|
2664
|
+
await link(path, backupPath);
|
|
2665
|
+
} catch (error) {
|
|
2666
|
+
if (error.code !== "EEXIST") throw error;
|
|
2667
|
+
}
|
|
2668
|
+
const backupHandle = await open(backupPath, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
2669
|
+
try {
|
|
2670
|
+
const backupIdentity = await backupHandle.stat({ bigint: true });
|
|
2671
|
+
if (!backupIdentity.isFile()) throw new Error(`migration backup path is not a regular file: ${backupPath}`);
|
|
2672
|
+
if (backupIdentity.dev !== sourceIdentity.dev || backupIdentity.ino !== sourceIdentity.ino) throw new Error(`migration backup does not reference the current Session artifact: ${backupPath}`);
|
|
2673
|
+
if (!(await backupHandle.readFile()).equals(original)) throw new Error(`migration backup already exists with different content: ${backupPath}`);
|
|
2674
|
+
await backupHandle.sync();
|
|
2675
|
+
} finally {
|
|
2676
|
+
await backupHandle.close();
|
|
2677
|
+
}
|
|
2678
|
+
await syncParentDirectory(backupPath);
|
|
2679
|
+
const temporary = `${path}.codex-search-history-${randomBytes(6).toString("hex")}.tmp`;
|
|
2680
|
+
try {
|
|
2681
|
+
await writeFile(temporary, migrated, {
|
|
2682
|
+
flag: "wx",
|
|
2683
|
+
mode: metadata.mode & 511
|
|
2684
|
+
});
|
|
2685
|
+
const handle = await open(temporary, "r");
|
|
2686
|
+
try {
|
|
2687
|
+
await handle.sync();
|
|
2688
|
+
} finally {
|
|
2689
|
+
await handle.close();
|
|
2690
|
+
}
|
|
2691
|
+
if (!(await readStableFile(path)).equals(original)) throw new Error(`session changed while migration was prepared: ${path}`);
|
|
2692
|
+
await rename(temporary, path);
|
|
2693
|
+
try {
|
|
2694
|
+
await syncParentDirectory(path);
|
|
2695
|
+
} catch (error) {
|
|
2696
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2697
|
+
throw new Error(`session was repaired and backed up at ${backupPath}, but synchronizing its directory failed: ${message}`, { cause: error });
|
|
2698
|
+
}
|
|
2699
|
+
if (!(await readStableFile(backupPath)).equals(original)) throw new Error(`a Session writer changed the preserved backup during migration; stop DSH and restore ${backupPath}`);
|
|
2700
|
+
} finally {
|
|
2701
|
+
await rm(temporary, { force: true });
|
|
2702
|
+
}
|
|
2703
|
+
return {
|
|
2704
|
+
path,
|
|
2705
|
+
changedEvents,
|
|
2706
|
+
backupPath
|
|
2707
|
+
};
|
|
2708
|
+
});
|
|
2709
|
+
}
|
|
2710
|
+
/**
|
|
2711
|
+
* Mark the retired Alpha 4.10 search event ignorable in compressed JSONL logs.
|
|
2712
|
+
* Applying is an offline maintenance operation and fails closed without the
|
|
2713
|
+
* caller's explicit acknowledgement that all DSH writers are stopped.
|
|
2714
|
+
*/
|
|
2715
|
+
async function migrateOpenAICodexSearchHistory(options = {}) {
|
|
2716
|
+
const apply = options.apply === true;
|
|
2717
|
+
if (apply && options.confirmStopped !== true) throw new Error("refusing to rewrite Session history without confirmStopped=true after stopping every DSH writer");
|
|
2718
|
+
if (apply && process.platform === "win32") throw new Error("applying this history migration is not supported on Windows; dry-run only");
|
|
2719
|
+
const root = resolve(options.root ?? join(resolveDshHome(options.dshHome), "sessions"));
|
|
2720
|
+
const files = [];
|
|
2721
|
+
for await (const path of sessionArtifacts(root)) try {
|
|
2722
|
+
const result = await migrateArtifact(path, apply);
|
|
2723
|
+
if (result !== void 0) files.push(result);
|
|
2724
|
+
} catch (error) {
|
|
2725
|
+
const partial = apply && files.length > 0 ? `; ${files.length} earlier file(s) were already repaired and remain backed up` : "";
|
|
2726
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2727
|
+
throw new Error(`Codex search history migration failed at ${path}${partial}: ${message}`, { cause: error });
|
|
2728
|
+
}
|
|
2729
|
+
return {
|
|
2730
|
+
mode: apply ? "apply" : "dry-run",
|
|
2731
|
+
root,
|
|
2732
|
+
changedFiles: files.length,
|
|
2733
|
+
changedEvents: files.reduce((sum, file) => sum + file.changedEvents, 0),
|
|
2734
|
+
files
|
|
2735
|
+
};
|
|
2736
|
+
}
|
|
2737
|
+
//#endregion
|
|
2474
2738
|
//#region src/index.ts
|
|
2475
2739
|
/** Stable Cordis plugin name. */
|
|
2476
2740
|
const name = "llm-openai-codex";
|
|
@@ -2637,4 +2901,4 @@ function apply(ctx, config) {
|
|
|
2637
2901
|
scheduleCapabilities();
|
|
2638
2902
|
}
|
|
2639
2903
|
//#endregion
|
|
2640
|
-
export {
|
|
2904
|
+
export { OPENAI_CODEX_FAST_MODE_MAX_SESSIONS as $, OPENAI_CODEX_TRANSPORT_SERVICE as A, COMPATIBILITY_CONTRACT as B, OPENAI_CODEX_IMAGE_MAX_COUNT as C, OPENAI_CODEX_IMAGE_REQUEST_TIMEOUT_MS as D, OPENAI_CODEX_IMAGE_PROMPT_MAX_LENGTH as E, IMAGE_GENERATE_TOOL_NAME as F, SUPPORTED_DSH_PLUGIN_API_VERSION as G, COMPATIBILITY_SCHEMA_VERSION as H, assertNoOpenAICodexProviderConflict as I, assessCompatibility as J, SUPPORTED_NODE_RANGE as K, diagnoseOpenAICodex as L, OpenAICodexTransportError as M, isOpenAICodexTransportError as N, OPENAI_CODEX_TRANSPORT_API_VERSION as O, VIEW_IMAGE_TOOL_NAME as P, FastModeRegistry as Q, openAICodexConflictMessage as R, OPENAI_CODEX_IMAGE_GENERATION_URL as S, OPENAI_CODEX_IMAGE_MAX_RESPONSE_BYTES as T, DSH_PLUGIN_API_PACKAGES as U, COMPATIBILITY_PACKAGES as V, PI_AI_PACKAGE as W, evaluateCompatibility as X, detectCompatibility as Y, OPENAI_CODEX_FAST_MODE_PATH as Z, DEFAULT_OPENAI_CODEX_SEARCH_MODEL as _, name as a, parseOpenAICodexUsage as at, decodeOpenAICodexSettings as b, migrateOpenAICodexSearchHistory as c, logoutOpenAICodex as ct, OPENAI_CODEX_SEARCH_URL as d, OPENAI_CODEX_PROVIDER as dt, OPENAI_CODEX_FAST_MODE_MAX_SESSION_ID_LENGTH as et, OpenAICodexSearchProvider as f, OpenAICodexCredentialStore as ft, DEFAULT_OPENAI_CODEX_SEARCH_MODE as g, DEFAULT_OPENAI_CODEX_SEARCH_MAX_OUTPUT_TOKENS as h, inject as i, OPENAI_CODEX_USAGE_URL as it, OpenAICodexTransport as j, OPENAI_CODEX_TRANSPORT_ERROR_CODES as k, OPENAI_CODEX_BASE_URL as l, openAICodexAuthStatus as lt, DEFAULT_OPENAI_CODEX_SEARCH_CONTEXT_SIZE as m, OPENAI_CODEX_SETTINGS_NS as n, OpenAICodexTrustedOriginsStore as nt, OPENAI_CODEX_HISTORY_BACKUP_SUFFIX as o, readOpenAICodexRateLimits as ot, mapOpenAICodexSearchResponse as p, openAICodexAuthPath as pt, SUPPORTED_PI_AI_VERSION as q, apply as r, normalizeTrustedOrigin as rt, OPENAI_CODEX_SEARCH_MODEL_REQUEST_EVENT as s, loginOpenAICodex as st, Config as t, isFastModeSessionId as tt, OPENAI_CODEX_SEARCH_PROVIDER as u, OPENAI_CODEX_AUTH_FILENAME as ut, DEFAULT_OPENAI_CODEX_SETTINGS as v, OPENAI_CODEX_IMAGE_MAX_ERROR_BYTES as w, resolveOpenAICodexSettings as x, OPENAI_CODEX_SETTINGS_NAMESPACE as y, CODEX_CONNECT_VERSION as z };
|
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.
|
|
5
|
+
"version": "0.1.0-alpha.4.14",
|
|
6
6
|
"author": "Frank Song",
|
|
7
7
|
"contributors": [
|
|
8
8
|
"Yan-Zero (original dsh-codex author)"
|