Releases: 447662/dsh-native-codex-cli
Release list
v0.2.3 - resolver correctness, green cross-platform CI
v0.2.3 — resolver correctness, and a green cross-platform CI
Follow-up to v0.2.2. That release's own CI went red on the new check, which is precisely what the check is for.
What was wrong
lib/resolve-bin.js is written to be pure and testable — it takes platform and env as parameters. But it split the candidate PATH with the host's path.delimiter instead of the target platform's. On Linux CI, a fabricated Windows PATH (A;B) was therefore treated as a single entry, and each drive letter would have been shredded into a bogus candidate.
Production was not affected: platform is process.platform there, so host and target always agreed. The defect made the self-check meaningless off-platform — which the CI caught immediately.
The fix
- Split
PATHwith the target platform's separator (;on Windows,:elsewhere); join POSIX candidates withposix.join. - The self-check now also asserts that no drive letter is split into a bogus entry — the assertion that caught this.
Verified on Linux CI (run #4, green) and locally on Windows, including the real scenario the previous release was about: with the Codex directory removed from PATH, the resolver still finds the desktop app's CLI:
PATH = C:\Windows\system32;C:\Windows (where.exe codex → not found)
resolveCodexBin() → C:\Users\<you>\AppData\Local\Programs\OpenAI\Codex\bin\codex.exe
CI now covers four checks
| Step | What it protects |
|---|---|
| Encoding guard | no tracked file is non-UTF-8 or BOM-prefixed |
| Load-time self-check | bundle preamble, six slot declarations, composer selector purity, session-mirror event shapes, the Markdown renderer |
| Missing-binary self-check | a missing Codex CLI rejects cleanly instead of killing the DSH host |
| CLI resolution self-check | the candidate list covers the Codex desktop app directory on Windows and POSIX |
Install
dsh plugin --profile desktop add git+https://github.com/447662/dsh-native-codex-cli.gitThen restart DSH.
Full documentation: README (中文) · README (English)
v0.2.2 - find the CLI the Codex desktop app already installed
v0.2.2 — find the CLI the Codex desktop app already installed
The symptom
On a machine where the Codex desktop app was installed, the plugin still reported:
spawn codex ENOENT path: 'codex' spawnargs: [ 'app-server' ]
The CLI was there all along: the desktop installer puts it in its own directory and appends it to the user environment. But DSH is Electron, and a process that inherited a stale environment — one already running, or one started by explorer.exe, which keeps the environment it had at logon — cannot see that directory. So "Codex is installed" and "Codex is missing" looked exactly the same.
The fix
lib/resolve-bin.js no longer trusts PATH alone. It searches, in order:
| Platform | Locations |
|---|---|
| Windows | PATH → %LOCALAPPDATA%\Programs\OpenAI\Codex\bin (the desktop app's own CLI) → %LOCALAPPDATA%\OpenAI\Codex\bin → %ProgramFiles%\OpenAI\Codex\bin → %APPDATA%\npm → %LOCALAPPDATA%\pnpm → ~/.codex/packages/standalone/current/bin → ~/.codex/bin → ~/.codex/plugins/.plugin-appserver → the standalone releases/<version>/bin tree, newest first |
| macOS / Linux | PATH → ~/.codex/packages/standalone/current/bin → ~/.codex/bin → ~/.local/bin → /usr/local/bin → /opt/homebrew/bin → /usr/bin |
- The resolved absolute path is logged and exposed on
GET /dsh-native-codex-cli/health, so support questions answer themselves. - An explicit
codexBinis still respected verbatim — the search never silently substitutes a different binary. - A bare
codexBinname is searched for too. - When nothing is found, the error now lists every directory that was searched.
Verified on a real machine with the Codex desktop app installed, with the Codex directory removed from PATH:
live resolution (stale PATH): C:\Users\<you>\AppData\Local\Programs\OpenAI\Codex\bin\codex.exe
Tests
test/resolve-bin-check.mjs injects a fake environment and asserts the candidate list for Windows and POSIX (including that PATH entries come first and that the desktop app's directory is present). It runs on CI with no Codex installed. Wired into npm run check and the workflow.
Still true from v0.2.1
A missing CLI can no longer take DSH down: the default 'error' listener, the spawn/initialize race, and the actionable message are all in place, guarded by test/spawn-failure-check.mjs.
Install
dsh plugin --profile desktop add git+https://github.com/447662/dsh-native-codex-cli.gitThen restart DSH.
Full documentation: README (中文) · README (English)
v0.2.1 - a missing Codex CLI no longer crashes DSH
v0.2.1 — a missing Codex CLI no longer crashes DSH
The bug
On a machine without the Codex CLI installed, starting DSH with this plugin enabled killed the whole host process:
dsh: fatal uncaught exception: Error: spawn codex ENOENT
at onErrorNT (node:internal/child_process:508:16)
errno: -4058,
code: 'ENOENT',
syscall: 'spawn codex',
path: 'codex',
spawnargs: [ 'app-server' ]
The app showed "应用无法启动或已意外停止" and could not start at all.
Why it was fatal rather than a normal error: the stdio transport's error handler called this.emit('error', error) on an EventEmitter with no 'error' listener. Node's EventEmitter rethrows in that case, and it rethrows synchronously inside a Node event handler — so the RPC route's try/catch never saw it. A plugin must never be able to do that.
The fix
- A default
'error'listener is always installed, so emitting can no longer throw. Extra listeners still receive the same error. start()now rejects instead of leaving the caller to wait out the 20s handshake timeout: theinitializerequest races the spawn failure, and the child is torn down on the losing path.ENOENT/EACCESare described in terms of what to do:未找到 Codex CLI:无法执行 "codex"。请先安装 Codex CLI(npm i -g @openai/codex),或在配置里把 codexBin 指向它的完整路径
- A synchronous throw from
spawn(bad cwd, invalid args) is handled too. - The UI shows the reason in a banner that clears itself as soon as any RPC succeeds again.
test/spawn-failure-check.mjsruns against a deliberately missing binary and asserts thatstart()rejects with an actionable message, that nothing escapes as an unhandled rejection or uncaught exception, and that a retry still behaves. It is wired intonpm run checkand CI.
If you are stuck on the crashing version
The crash dialog has an escape hatch: "禁用第三方插件、备份 profile patch 并重启" — use it to boot DSH with third-party plugins disabled, then either install the Codex CLI or remove this plugin, restart, and install v0.2.1.
Install
dsh plugin --profile desktop add git+https://github.com/447662/dsh-native-codex-cli.gitThen restart DSH.
Also in this release
Carried over from v0.2.0: the plugin was renamed from dsh-codex (that name belongs to an unrelated plugin on npm and GitHub).
Requirements: DeepSeek Harness with the Web GUI, Codex CLI on PATH and logged in (codex --version), Node 18+ for the self-checks.
Full documentation: README (中文) · README (English)
v0.2.0 - renamed to dsh-native-codex-cli
v0.2.0 — renamed to dsh-native-codex-cli
Renamed from
dsh-codex. That name is already used on npm and on GitHub by an unrelated plugin (Yan-Zero/dsh-codex, a ChatGPT-subscription provider for DSH) which also carries thedsh-plugintopic — two different plugins would have appeared under the same name in the plugin hub. The old repository URL redirects here, but the package name, plugin id, HTTP routes, storage directory and log file all changed, so v0.1.0 should not be installed any more.
DSH owns the chat interface; the Codex CLI owns task execution and native thread history. Tasks go straight to Codex — no second AI paraphrases them, and no chat archive is replayed to fake continuity.
What it does
- Old conversations — list Codex threads from
thread/list, restore the selected one withthread/resume - New task — create a native thread with an explicit working directory, model, approval policy and sandbox
- Send — the message goes verbatim into
turn/start; follow-ups during a run useturn/steer - Streaming —
item/*/deltaframes accumulate live, with tool cards for command execution (output, exit code, duration), file changes (with diff), MCP / dynamic tool calls, and errors - Stop —
turn/interrupt, a real interrupt; pending approvals are refused first so it is not queued behind an unanswered prompt - Approvals & questions — command / file-change / permission requests and
request_user_inputbecome UI cards, and the choice is sent back to Codex - Refresh & restart — the session⇄thread binding is persisted,
clientMessageIdmakes resends idempotent, and SSE reconnects re-read a snapshot - Images — paste or pick a screenshot; it is staged on disk and sent as a
localImageinput, and the transcript shows a thumbnail you can click to enlarge - Markdown — Codex's replies render properly (headings, lists, quotes, code, links)
Where it appears
A standalone Codex panel in the sidebar, a Codex view inside any session, a composer takeover for bound sessions, an @codex hand-off button in the native composer, and a main-page dock showing the Codex conversation plus its context (directory / model / approval / sandbox).
@codex is case-insensitive and also accepts the full-width @.
Verified
| Check | Result |
|---|---|
npm run check:utf8 |
every tracked file is clean UTF-8 |
npm run check:load |
green — bundle preamble, slot declarations, event shapes, Markdown renderer |
npm run check:smoke |
25/25 against a real codex app-server, including a real approval round-trip and a real interrupt |
npm run check:http |
22/22 over the exact RPC + SSE surface the browser uses |
Tested against Codex CLI 0.153.4 and the DSH Desktop desktop profile.
Install
dsh plugin --profile desktop add git+https://github.com/447662/dsh-native-codex-cli.gitThen restart DSH (a profile's bundle list is not hot-reloaded).
Requirements
- DeepSeek Harness with the Web GUI (desktop or
dsh web) - Codex CLI on
PATH, logged in (codex --version) - Node 18+ for the self-checks only
Known limitations
transport: daemon is still a reserved adapter; Codex threads are process-scoped (auto-resumed on demand); thread/turns/list is unimplemented in Codex 0.153.4 so history comes from thread/resume; and assistant/message cannot be authored by a plugin (it embeds the provider stream), so the DSH session log mirrors the user side and Codex's answers render in the main-page dock. See the README for the full list.
Full documentation: README (中文) · README (English) · Protocol reference