【免费下载链接】opencodex
Universal provider proxy for OpenAI Codex & Claude Code — use any LLM (Claude, Gemini, Grok, DeepSeek, Ollama…) with Codex CLI, App, SDK, and Claude Code
导读
本文以 opencodex 仓库中devlog/_fin/260627_windows-80-nine-cycle/00_cycle_map.md为核心骨架,完整还原一次针对 Windows 平台稳定性问题的九周期(实际十个工作切片)PABCD(Plan → Act → Build → Commit → Document)渐进式硬化作战计划。该计划把庞大的"Windows 80 稳定性"目标拆解为十个彼此独立、可单独验证、原子提交的补丁切片,覆盖/v1/responses超时控制、passthrough 原生中继、传输生命周期日志、Windows 服务包装器、任务计划程序加固、Bun 运行时覆盖与 CLI 诊断等多个维度。读完本文,你将掌握 opencodex 在 Windows 上排查"代理静默停止""SSE 中途卡死""服务无法自愈"类问题的完整方法论,以及每一周期对应的源码落点、验证命令与提交粒度规范。
一、计划背景与基线约束
1.1 目标定义
周期地图开篇明确了总目标:在dev分支上执行至少九个小型、可独立验证的 PABCD 工作周期,把既有的 Windows 80 稳定性计划(源自 devlog/80_windows-codex-path-hardening/15_final_gpt_pro_plan.md)转化为可合入的硬化补丁。每个周期必须同时产出:
- 文档证据(plan 文件);
- 实现证据(源码 diff);
- 验证证据(测试与类型检查通过);
- 涉及源码变更的周期必须原子提交(一个周期一个 commit,禁止合并提交)。
1.2 基线状态与硬性约束
计划记录了三项不能逾越的约束,体现了对回归风险的显式管理:
- 不得在本目标内复活 Cursor provider 工作——避免扩大变更面;
- 保留 ChatGPT forward/pool 认证行为——认证链路是敏感路径,不容破坏;
- Windows 变更必须能从 macOS/Linux 通过静态检查与单元测试验证——开发环境与目标平台分离,要求所有补丁都是平台无关的可测逻辑;
- 未经用户明确批准,不得 push / reset / force。
1.3 基线审计(Cycle 0)
配套的 01_baseline_audit.md 记录了 Cycle 0 的验证方式:确认计划涉及的源码与测试面真实存在。从当前仓库结构看,计划中提及的src/server.ts、src/service.ts已随后续重构演进为 src/server/、src/service/ 目录,但核心函数面仍可一一对应(详见各周期小节)。
基线验证命令(可在任意周期开始前复跑):
git status --short --branch bun test tests/oauth-status-privacy.test.ts tests/cli-help.test.ts tests/config.test.ts bun x tsc --noEmit计划明确注明:若devlog/目录被 git 忽略,则 Cycle 0 无需源码提交,仅记录cli-jaw goal update证据即可。
二、九个源码/文档变更周期的完整切片
Cycle 1 —/v1/responses请求超时禁用钩子
问题:Bun 服务器默认对请求设有超时,Windows 上安静的 SSE 长连接容易因超时被中途掐断。
方案:仅对 HTTP POST/v1/responses显式禁用请求超时,/api/*、/healthz、静态 GUI、/v1/models与 WebSocket 升级路径一概不动。计划给出的核心辅助函数如下:
export function disableResponsesRequestTimeout(req: Request, server: Pick<Server, "timeout"> | undefined): boolean { try { server?.timeout(req, 0); return !!server; } catch { return false; } }要点有三:
- 借助
fetch(req, server)的第二个请求级 server 参数拿到timeout能力; - fail closed:当运行时不存在该 API 或调用抛错时返回
false且不向上抛异常,避免在不支持的运行时上连带崩溃; - 仅在
url.pathname === "/v1/responses"且非 WebSocket 升级时调用。
验证:bun test tests/server-auth.test.ts tests/bridge-lifecycle.test.ts+bun x tsc --noEmit,建议提交fix(windows): disable responses request timeout。
接受标准:长连接工作开始前有超时禁用钩子;管理/静态/模型/WebSocket 行为零变化。
Cycle 2 — Passthrough 原生中继包装器防护
问题:原生 ChatGPT/OpenAI Responses passthrough 的 SSE 响应体被trackStreamLifetime(nativeBody, turnAc)再次包装,而该包装本身是一个 async-pull 生命周期流,在 Windows 热路径上引入了不必要的二次拉取层。
方案:在relaySseWithHeartbeat(...)上增加可选生命周期参数,把"包装"替换为"注册/回调":
options?: { onStart?: () => void; onDone?: () => void }passthrough 分支从:
const trackedNative = trackStreamLifetime(nativeBody, turnAc); return new Response(trackedNative, ...)改为:
registerTurn(turnAc); const nativeRelay = relaySseWithHeartbeat(nativeBody, upstream, 15_000, terminalRecorder, { onDone: () => unregisterTurn(turnAc), }); return new Response(nativeRelay, ...)最终形态可用onStart代替预注册,但必须避免在 passthrough SSE 分支使用trackStreamLifetime。非 passthrough 的桥接流仍保持 track 语义。
从源码佐证看,当前仓库 src/server/responses/passthrough-delivery.ts 的 passthrough 交付路径中仍存在trackStreamLifetime包装(如 L340、L901),而 src/server/chat-native.ts 的注释也明确警惕"再加一层 trackStreamLifetime 包装在 bundled Bun#32111 上不安全"——这印证了该周期要解决的真实风险。registerTurn/unregisterTurn/trackStreamLifetime的实现位于 src/server/lifecycle.ts。
验证:bun test tests/passthrough-abort.test.ts tests/shutdown-drain.test.ts tests/server-auth.test.ts+ typecheck。要求:onStart 读入时调用一次、onDone 在正常 EOF 与 cancel 时各调用一次、cancel 仍能中止上游。
Cycle 3 — 传输关闭日志(Transport Close Logging)
问题:Windows 用户报"代理停了",但请求日志无法区分是流正常结束、失败、不完整还是被客户端取消。
方案:扩展RequestLogEntry,新增两个字段:
terminalStatus?: ResponsesTerminalStatus; closeReason?: "terminal" | "client_cancel" | "non_stream";在addFinalRequestLog(...)与responseWithDeferredRequestLog(...)中:
- 非流响应记录
{ closeReason: "non_stream" }; - SSE 正常终止记录
{ closeReason: "terminal", terminalStatus: status }; - 客户端取消记录
{ closeReason: "client_cancel" }并以 HTTP 499 返回。
红线:日志中不得出现 prompt 内容、工具参数、API Key、token 或 Authorization 头;请求 id、provider、model、流开始、首个上游字节、终止状态、客户端中止、上游中止、关闭分类是允许项。该周期是"token-safe 生命周期证据"原则的第一次系统化落地。
验证:bun test tests/request-log.test.ts tests/server-auth.test.ts tests/passthrough-abort.test.ts+ typecheck,并在/api/logs中可区分 SSE 终止与客户端取消。
Cycle 4 — Windows 服务日志路径与包装器启动证据
问题:通过任务计划程序(Task Scheduler)启动的服务没有任何持久化的启动/运行时身份日志,出问题无从查起。
方案(本周期刻意只做"包装器启动身份",不做调度器 XML 与子进程退出策略):
- 在 src/service/ 相关实现中导出确定性的 Windows 服务日志路径辅助函数(计划中命名为
serviceLogPath()),并在buildWindowsServiceScript(...)生成的包装器中写入OCX_SERVICE_LOG变量; - 启动 Bun 之前,先追加以下 token-safe 启动行:时间戳、Bun 路径、CLI 路径、
OPENCODEX_HOME、CODEX_HOME、配置目录/日志路径; - 子进程 stdout/stderr 重定向到同一日志文件;
- 只允许输出 token 文件路径,绝不输出 token 内容本身。
验证:tests/service.test.ts断言包装脚本包含OCX_SERVICE_LOG赋值、启动标记、Bun/CLI/CODEX_HOME/OPENCODEX_HOME 标签、子命令追加日志、且无原始OPENCODEX_API_AUTH_TOKEN值。
Cycle 5 — Windows 子进程退出与状态诊断
目标:捕获子进程退出/重启决策,并把服务日志路径暴露到ocx service status/ocx status。
要点:
- 子进程 stdout/stderr 或退出码追加进服务日志;
ocx service status无需管理员命令即可显示日志路径;- 通过
serviceStatusSummary()与既有ocx status流程暴露诊断信息,不改动服务生命周期语义。
验证:bun test tests/service.test.ts tests/cli-help.test.ts+ typecheck,建议提交fix(windows): expose service diagnostics。
Cycle 6 — 任务计划程序设置加固(Scheduler XML / 参数)
问题:裸的schtasks /create标志存在默认执行时限与电池策略风险,代理可能在笔记本上被意外停止。
方案:用显式的 Windows 任务设置替换裸标志。当前仓库 src/service/windows-taskxml.ts 的buildWindowsTaskXml已落地该方向的完整形态(计划中称为"若 XML 或 PowerShell 任务定义比 schtasks 标志更稳定则采用之"),关键 XML 片段:
<RunLevel>LeastPrivilege</RunLevel> <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy> <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries> <StopIfGoingOnBatteries>false</StopIfGoingOnBatteries> <ExecutionTimeLimit>PT0S</ExecutionTimeLimit> <RestartOnFailure>...</RestartOnFailure>即:
ExecutionTimeLimit设为PT0S(无限执行时限);- 重启间隔与次数成对设置;
- 电池策略放开(不在电池状态下停止);
- 实例策略
IgnoreNew防止重复拉起; - 保留
ocx service stop的语义:显式停止后不得被调度器立即复活; - 权限保持
LeastPrivilege(LIMITED),不做提权。
该文件同时提供taskXmlRunLevelAcceptable等健康检查函数,windowsTaskRegistrationHealthy会验证 XML 中是否确实包含MultipleInstancesPolicy=IgnoreNew与ExecutionTimeLimit=PT0S,为注册状态提供可编程校验。
验证:tests/service.test.ts断言生成的参数含加固标志、仍保持 LIMITED 权限、路径带引号且 shell-safe;typecheck 通过。
Cycle 7 — Bun 运行时覆盖与身份(Runtime Override)
问题:Windows 用户可能因 bundled Bun 损坏而无法启动,需要一条逃生通道。
方案:
- 支持
OPENCODEX_BUN_PATH(或命名清晰的对等变量)作为覆盖路径; - 对无效覆盖路径大声拒绝(fail loudly);
- 记录 bundled 与 override 运行时选择。
当前仓库 src/lib/bun-runtime.ts 已把该能力实现为"单一事实来源"模块:durableBunPath()/durableBunRuntime()解析 bundled Bun(经bunnpm 依赖 +@oven/bun-*平台包 + postinstallinstall.js),并定义了运行时来源枚举"override" | "bundled" | "process"与来源标记环境变量OCX_BUN_RUNTIME_SOURCE/OCX_BUN_RUNTIME_PATH。二进制真实性校验依赖 src/lib/bun-binary-validator.mjs 的isRealBunBinary(...)。值得强调的是标记成对校验逻辑:reportedBunRuntimeSource()只有同时满足"来源值在允许清单内"且"记录路径与process.execPath一致"时才返回来源,否则诚实报告 unknown——避免在服务重启后给出自信的错误答案。
验证:bun test tests/bun-runtime.test.ts tests/service.test.ts+ typecheck,建议提交fix(windows): support bun runtime override。
Cycle 8 — PID 清理健壮性
问题:Windows 上 PID 身份检查(命令行校验)失败时,显式 stop/uninstall 可能无法清理。
方案(状态/报告仍保持严格身份校验,但清理走宽松路径):
- 对 status/reporting 保留严格身份校验(防止误杀同名进程);
- 对显式 stop/uninstall:若 PID 文件存在但命令行检查失败,执行安全的 best-effort 清理并在日志中记录不确定性;
- 仅当需要分离 PID 读取辅助函数时才改 src/config/(如 src/config/process-state.ts 中的
getPidPath/readPid)。
验证:bun test tests/process-control.test.ts tests/service.test.ts tests/uninstall.test.ts+ typecheck,建议提交fix(windows): make explicit pid cleanup resilient。
Cycle 9 — Clone GUI 开发体验与 CLI 现势化(Currentization)
问题:bun run dev只起后端代理、不提供/的 GUI 页面,且 CLI 缺少年份/状态面板,造成用户困惑。
要点:
- 版本命令:新增
ocx -v、ocx --version、ocx version,且不产生任何配置变更。当前仓库 src/cli/root.ts 已实现--version/-v/version的统一解析入口,能力声明位于 src/cli/capabilities.ts。 - 脚本/文案拆分:
package.json中把后端代理与 GUI 开发/构建语义分开;README 说明bun run dev暴露/healthz、/v1/responses、/api/*,GUI 用ocx gui(打包版)或cd gui && bun dev(前端开发)。 - 根路径回退:
GET /在没有内置 GUI 时应给出精确的 clone/dev 指引。 - 状态现势化:状态面板应安全标记过期的、不支持的 OAuth 配置(计划提到
c560b54之后的既有能力),并结合 Cycle 7/8 输出运行时与 PID 信息——当前 src/cli/status.ts 已展示Runtime:与 PID 文件相关输出能力(如pidFile、readPid()、运行时解析),印证了该周期的验收形态。
建议提交(本周期允许拆两个原子提交):
git commit -m "feat(cli): add version diagnostics" git commit -m "docs(dev): clarify clone gui workflow"验证:bun test tests/cli-help.test.ts tests/server-auth.test.ts tests/oauth-status-privacy.test.ts+ typecheck,并可用rg -n "bun run dev|cd gui|proxy API" README.md README.ko.md README.zh-CN.md docs-site/src/content/docs/getting-started/installation.md复核文档改动范围(仅当公开快速上手文案变化时才改 README 系列)。
三、每个周期之后的强制停机规则(Stop Rules)
周期地图最后给出了所有源码变更周期的统一出口纪律,这是该计划与普通"任务清单"的本质区别:
- 运行聚焦测试与类型检查(
bun x tsc --noEmit); - 以
cli-jaw goal update记录文档、实现、验证三份证据; - 原子提交;
- 重新进入 P(Plan)阶段开始下一周期。
同时明确两条禁止项:未经显式请求不得 push;不得把多个周期折叠进一个宽泛提交——这正是"每个周期可独立验证"的提交粒度保障。
四、九个切片背后的共同设计原则
把十个周期放在一起看,可以提炼出 opencodex 平台硬化方法论的四条主线:
| 原则 | 体现周期 | 关键落点 |
|---|---|---|
| 最小爆炸半径 | C1、C2 | 仅动/v1/responses路径,管理/静态/模型/WebSocket 零变化 |
| fail closed / fail loudly | C1、C7 | 超时 API 缺失时静默降级返回 false;Bun 覆盖路径无效时大声拒绝 |
| token-safe 可观测性 | C3、C4 | 日志只含身份/生命周期字段,绝不含密钥与正文 |
| 状态与动作分离 | C5、C7、C8 | 诊断面板只读不启动代理;显式清理与严格身份校验分层 |
五、局限与后续参考
- 计划明确记录了一次审计限制:
cli-jaw dispatch --agent Backend因"Not logged in"失败,Cycle 0 仅采用本地静态审计作为兜底证据——说明计划对"证据类型"是诚实标注的。 - 本文引用的源码文件(如 src/server/lifecycle.ts、src/service/windows-taskxml.ts、src/lib/bun-runtime.ts、src/cli/status.ts、src/server/responses/passthrough-delivery.ts)均为当前仓库实际存在的实现,是验证各周期验收标准的最佳阅读材料;配套周期计划文档位于 devlog/_fin/260627_windows-80-nine-cycle/,上游完整计划见 devlog/80_windows-codex-path-hardening/15_final_gpt_pro_plan.md。
【免费下载链接】opencodex
Universal provider proxy for OpenAI Codex & Claude Code — use any LLM (Claude, Gemini, Grok, DeepSeek, Ollama…) with Codex CLI, App, SDK, and Claude Code
相关推荐
opencodex Kiro 网关对齐硬化路线图:从 P0 流终止到 P2 可观测性的完整加固指南
opencodex Kiro 网关对齐硬化路线图:从 P0 流终止到 P2 可观测性的完整加固指南 导读 本文基于 opencodex 仓库中 Kiro(AWS
Slate v2 的 ScrubberApi 硬切:从全局可变诊断钩子到内部 formatDebugValue 格式化器
Slate v2 的 ScrubberApi 硬切:从全局可变诊断钩子到内部 formatDebugValue 格式化器 本文围绕 Plate 所依赖的 Sla
前端富文本UI组件opencodex 跨平台部署稳定性加固:生命周期、活跃探测与运行中更新的闭环实践
opencodex 跨平台部署稳定性加固:生命周期、活跃探测与运行中更新的闭环实践 本篇技术指南围绕 opencodex(Universal provider
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考