# DSH Codex Suite [![CI](https://github.com/DamonBao/dsh-codex-suite/actions/workflows/ci.yml/badge.svg)](https://github.com/DamonBao/dsh-codex-suite/actions/workflows/ci.yml) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) [![Node](https://img.shields.io/badge/node-%5E22.19%20%7C%7C%20%3E%3D24-green.svg)](#开发) [![pnpm](https://img.shields.io/badge/pnpm-11-orange.svg)](#开发) [English](README.md) | 简体中文 为 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(DSH)打造的插件套件:把 **ChatGPT / OpenAI Codex 模型**和 **Codex 风格的对话体验**带进 DSH Web UI。基于 DSH `0.1.6-alpha.2` 构建(peer 范围 `>=0.1.6-alpha.2 <0.1.7-0`)。 本仓库是 pnpm monorepo,包含两个相互独立的运行时插件和一个纯组合包: | 包 | 类型 | 功能 | | --- | --- | --- | | [`@jcy2387/dsh-codex-provider`](packages/codex-provider) | 运行时插件 | 注册 `openai-codex` Provider:ChatGPT OAuth 登录、主动令牌刷新、用量面板、代理感知网络和原生设置页。 | | [`@jcy2387/dsh-conversation-ui`](packages/conversation-ui) | 运行时插件 | 将 Web 对话重绘为 Codex 风格事件流:Turn 折叠、语义化 Tool 活动、流式揭示、产物卡片和平滑视口跟随。 | | [`@jcy2387/dsh-suite`](packages/all) | 纯组合包 | 不含运行时代码,仅通过一个 profile patch 一次装齐两个插件。 | 两个插件完全解耦:Conversation UI 可服务任意模型,Codex Provider 也可搭配原生对话界面使用。 --- ## 为什么需要这套件 **Codex Provider —— 无需 API Key 的可靠 ChatGPT 接入** - **双流程 ChatGPT OAuth。** 浏览器登录 + 设备码兜底。登录失败会被归类为无敏感信息的本地化原因(区域受限、回调端口冲突、令牌交换错误、网络问题……),而不是裸报错堆栈。 - **IPv6 回环回调桥。** pi-ai 的 OAuth 监听只绑 IPv4;在 IPv6 优先的主机上,套件会透明转发回环回调,登录依然可用。 - **主动令牌刷新。** 访问令牌在过期前约 5 分钟轮换,失败按退避重试;刷新令牌失效会被精确识别并提示「需要重新连接」,而不是在流式中途崩掉。 - **用量面板。** 从 ChatGPT 账号级接口获取套餐(以 Plus / Pro 5x / Pro 20x 等对外名称显示)、Credits、主/次限额窗口的用量百分比条和重置时间。 - **重置次数(额度银行)。** 查看账号可用的 banked reset 次数与最早到期时间,并在确认弹窗中一键兑换,恢复 5 小时与每周限额窗口。 - **代理感知网络。** 自动探测环境变量与系统代理(macOS / Windows / Linux),仅让 OpenAI 流量走代理、回环保持直连,并提供显式代理模式(auto / environment / off)。 - **可靠性优先的默认值。** 默认 SSE 传输(避免 WebSocket 后期失败导致部分输出重复)、5 分钟流空闲超时、可配置重试策略。 - **原生设置页** 位于 *设置 → OpenAI Codex*,中英文界面、实时状态,RPC 仅限 loopback 权限——凭据绝不离开 Host。 **Conversation UI —— 像 Codex CLI 一样渲染对话** - **单一有序事件流。** 过程答复、思考、工具调用、重试、工作流、压缩和命令按自然顺序在各自 Turn 内呈现。 - **Turn 折叠。** Turn 开始即显示计时与思考占位;最终答复落地后过程区自动折叠(可展开,并提供持久化的「自动展开思考」偏好)。 - **语义化工具图标。** 搜索、文件读写、Shell、数据库、网页、技能、Agent 等工具各有专属图标,活动一眼可扫。 - **两种揭示模式。** `teleprompter`(默认):即时快照向上平滑滑动;`typewriter`:按字素渐进揭示。三档平滑预设(`realtime` / `balanced` / `silky`)调节节奏。 - **智能视口跟随。** 新内容在限速范围内平滑跟随;用户上滑阅读即释放跟随,回到底部自动恢复。尊重 `prefers-reduced-motion`,低帧率下优雅降级。 - **产物卡片。** 每个完成的 Turn 列出生成的文件与站点,并附带增删行数。 --- ## 安装 前置条件:DeepSeek Harness(`dsh`)`>=0.1.6-alpha.2 <0.1.7-0`(装有 `web` profile)、Node.js `^22.19 || >=24`、pnpm 11。 **安装整套 Suite(推荐):** ```sh dsh plugin --profile web add @jcy2387/dsh-suite@0.1.6-alpha.2 dsh web ``` **或单独安装插件:** ```sh dsh plugin --profile web add @jcy2387/dsh-codex-provider@0.1.6-alpha.2 dsh plugin --profile web add @jcy2387/dsh-conversation-ui@0.1.6-alpha.2 dsh web ``` **本地开发** —— 用工作区内的包替代发布版: ```sh dsh plugin --profile web add link:$PWD/packages/codex-provider dsh plugin --profile web add link:$PWD/packages/conversation-ui dsh web ``` 在同一个 profile 里,整套 Suite 和单独插件**二选一**安装,不要让同一插件的两份来源共存。共存不会崩溃(Suite 通过嵌套加载组挂载插件,避免了重复 loader entry id),但直接安装的行与 Suite 的子行会共享同一个加载条目:在**运行中的** dsh 进程里移除任意一侧,对应插件会静默停止,直到下次重启才恢复。变更 bundle 列表后请重启 dsh。 ## 快速开始 1. 安装套件(见上)并打开 Web UI(`dsh web`)。 2. 进入 **设置 → OpenAI Codex**,点击**连接**,选择**浏览器登录**(无头/远程机器可用**设备码登录**),完成 ChatGPT 授权。 3. 回到对话,在模型选择器中挑选 `openai-codex` 模型即可开聊。 4. 可选:在同一设置页查看用量面板,并在 **插件 → DSH Codex Suite(或 Conversation UI)** 中调节对话流参数。 ## 配置 两个插件都通过 profile 的 `cordis.patch.yml` overlay 配置;用户级偏好保存在设置界面并跨重启持久化。 **Codex Provider**(profile patch ID:`codex-provider`) | 选项 | 取值 | 默认 | 说明 | | --- | --- | --- | --- | | `transport` | `sse` \| `websocket` \| `websocket-cached` \| `auto` | `sse` | SSE 可避免流后期失败时部分输出被重复。 | | `streamIdleTimeoutMs` | 正整数 | `300000` | 读取单个响应流的最大空闲间隔。 | | `timeoutMs` / `websocketConnectTimeoutMs` | 正整数 | — | 可选的请求级超时。 | | `retryPolicy` | 重试策略对象 | 内置 | 请求重试行为。 | | `credentialRef` | 凭据引用 | `OPENAI_CODEX_OAUTH` | 保存 OAuth 状态的 Harness 凭据槽。 | | `ipv6CallbackBridge` | 布尔 | `true` | 为 IPv6 主机转发 OAuth 回环回调。 | | `proactiveRefresh` | 布尔 | `true` | 在过期前主动刷新令牌。 | | `proxyMode` | `auto` \| `environment` \| `off` | `auto` | 重启后生效;也可在设置页修改。 | **Conversation UI**(profile patch ID:`conversation-ui`) | 选项 | 取值 | 默认 | 说明 | | --- | --- | --- | --- | | `mode` | `teleprompter` \| `typewriter` | `teleprompter` | 助手内容的揭示风格。 | | `preset` | `realtime` \| `balanced` \| `silky` | `balanced` | 平滑节奏档位。 | | `revealCharsPerSec` | 5–200 | `80` | 打字机揭示速度。 | | `scrollSpeedPxPerSec` | 1–200 | `48` | 已弃用的兼容字段;滚动由 DSH 管理。 | | `maxScrollSpeedPxPerSec` | 1–2000 | `1000` | 已弃用的兼容字段;滚动由 DSH 管理。 | 若想临时禁用 Conversation UI 而不卸载,应用包内自带的 [`conversation-ui-off.yml`](packages/conversation-ui/conversation-ui-off.yml) overlay: ```yaml - id: conversation-ui disabled: true ``` ### 设置入口 | 位置 | 可控内容 | | --- | --- | | 设置 → OpenAI Codex | 连接/断开账号、登录方式、用量面板、重置次数查看与兑换、代理模式。 | | 插件 → DSH Codex Suite(或 Conversation UI) | 自动展开思考(实时生效)、插件版本、npm 安装一键更新。 | ## 架构 每个运行时插件都由两半组成: - **Host 半**(Node)—— Cordis 插件:Provider 注册、OAuth 生命周期、网络与设置持久化,从包根加载。 - **Web 半**(浏览器)—— 通过 `dsh.client` manifest 发现的 React 视图。Codex Provider 提供设置分区;Conversation UI 替换助手节点视图并包装工具行。 两半之间只通过两条窄通道通信:注入到 HTML 的**启动配置全局变量**(`window.__DSH_CONVERSATION_UI_CONFIG__`)把校验后的插件配置带给浏览器;**经鉴权的 Connection RPC** 把设置读写带回 Host。机密信息(令牌、代理地址)绝不跨越 RPC 边界。 各包详细文档:[codex-provider](packages/codex-provider/README.zh.md) · [conversation-ui](packages/conversation-ui/README.md) · [suite](packages/all/README.md) ## 开发 要求:Node.js `^22.19.0 || >=24.0.0`,pnpm `11.7`。 ```sh pnpm install pnpm run check # typecheck + test + build + pack dry-run,与 CI 一致 ``` 单包命令: ```sh pnpm --filter @jcy2387/dsh-codex-provider check # typecheck + test + build + publint pnpm --filter @jcy2387/dsh-conversation-ui typecheck pnpm --filter @jcy2387/dsh-conversation-ui test pnpm --filter @jcy2387/dsh-conversation-ui build pnpm --dir packages/all pack --dry-run ``` 测试基于 [vitest](https://vitest.dev),共 15 个套件,覆盖 OAuth 状态机、令牌刷新、网络/代理探测、用量与重置次数解析、设置控制器和流式客户端视图。客户端测试直接解析已安装的 DSH 发布包(用一个小型 module-table 替身实例化其浏览器 factory bundle)。CI 会校验发布 tag 与三个包版本一致、审计发布 tarball 的内容,并跑一个消费方冒烟测试:把打包出的 tarball 装进一个全新工程(用真实 registry 解析已发布的 peer 依赖区间),再导入全部 Node 侧入口。 ### 发布 发布由 **Release** 工作流([`.github/workflows/release.yml`](.github/workflows/release.yml))自动完成:只要发布一个 GitHub Release 就会触发。它要求 release tag 与三个包的共同版本一致(允许可选的 `v` 前缀),重跑全部质量门禁,打包三个 tarball,校验 suite 组合包不再携带 `workspace:` 区间,然后按依赖顺序(provider → conversation-ui → suite)发布到 npm,自带 **provenance** 溯源,采用 **OIDC Trusted Publishing** 认证 —— 不需要任何长期有效的 `NPM_TOKEN` secret。 一次性配置:在 npmjs.com 上为 `@jcy2387/dsh-codex-provider`、`@jcy2387/dsh-conversation-ui`、`@jcy2387/dsh-suite` 分别配置 [Trusted Publishing](https://docs.npmjs.com/trusted-publishing),授权仓库 `DamonBao/dsh-codex-suite`、工作流 `release.yml`(environment 留空)。 dist-tag 跟随 GitHub Release 的 pre-release 勾选:正式 Release(不勾 pre-release)一律发 `latest`(包括 rc 版本);勾了 pre-release 则按版本通道打 tag(`0.1.2-alpha.4` → `alpha`,`0.1.2-rc.1` → `rc`)。工作流具备幂等性 —— 某个包的版本若已存在于 npm 则跳过,因此部分失败后重跑只会补发缺失的包。 一次典型的发布: ```sh # 先在三个 packages/*/package.json 里统一升版本号,然后: pnpm run check VERSION="$(node -p "require('./packages/codex-provider/package.json').version")" git commit -am "release: $VERSION" git tag "$VERSION" git push origin main --tags ``` 随后为该 tag 创建并发布一个 GitHub Release 即可。Dependabot 每周检查 GitHub Actions 依赖。刻意未启用 Dependabot 的 npm 依赖更新:它重新生成 `pnpm-lock.yaml` 时不带 workspace overrides,PR 无法通过 `pnpm install --frozen-lockfile` —— 依赖升级请用 `pnpm update` 手动处理。 ### 仓库结构 ```text . ├─ packages/ │ ├─ codex-provider/ # @jcy2387/dsh-codex-provider │ │ ├─ src/ # Host 半:OAuth、刷新、网络、用量、重置次数、LLM 适配器 │ │ ├─ src/client/ # Web 半:设置分区 UI │ │ ├─ tests/ # 12 个 vitest 套件 │ │ └─ cordis.patch.yml │ ├─ conversation-ui/ # @jcy2387/dsh-conversation-ui │ │ ├─ src/ # Host 半:配置桥、设置 RPC │ │ ├─ src/client/ # Web 半:流式视图、卡片、原生滚动桥接 │ │ ├─ tests/ # 3 个 vitest 套件 │ │ └─ cordis.patch.yml │ └─ all/ # @jcy2387/dsh-suite(纯组合包,无运行时代码) ├─ .github/workflows/ci.yml # 校验 + tarball 审计 + 消费方冒烟 ├─ .github/workflows/release.yml # GitHub Release 触发 npm 发布 ├─ pnpm-workspace.yaml └─ README.md / README.zh.md ``` ## 故障排查 - **浏览器登录迟迟不完成** —— 回调桥监听 `127.0.0.1:1455`;请确认端口空闲且浏览器可达回环地址。设置页会给出具体失败类别(端口冲突、超时、state 不匹配……)。 - **区域不受支持** —— OpenAI 拒绝受限区域登录;设置页会以独立原因提示。可通过代理模式(`proxyMode`)改变出口线路(需重启生效)。 - **一段时间后提示「需要重新连接」** —— 刷新令牌已过期或被吊销(如改密)。在设置页重新连接一次即可。 ## 许可证 [MIT](LICENSE) © jcy2387