opencodex Codex Warmup 预览发布实战:npm dist-tag 发布流程与 Windows 迭代超时修复
2026/9/23 14:48:09 网站建设 项目流程

【免费下载链接】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

项目地址:https://gitcode.com/gh_mirrors/ope/opencodex
点击查看免费下载

本篇文章基于 opencodex 仓库中devlog/_fin/260710_codex_warmup_preview_release/的完整发布记录,深入剖析一次「spec-satisfaction」型预览发布循环:如何将 Codex warmup 修复与 Cursor GPT-5.6 模型目录以2.7.1-preview.20260710版本发布到 npmpreviewdist-tag,如何在发布途中修复 Windows 平台独有的迭代超时挂起问题,以及如何将并发开发的 injection-effort 功能纳入同一发布头。读完本文,你将掌握 opencodex 的预览通道发布规范、gh workflow run+ npm/GitHub 元数据双验证的实操命令,以及基于signalWithTimeout的跨平台中止信号修复模式。

一、发布背景与基线:预览通道的定位

opencodex 采用latestpreview双 dist-tag 通道策略。preview通道用于承载「已经提交但尚未走完稳定发布流程」的修复与新增功能,供用户在正式发布前先行验证;latest通道保持稳定版本不动。

本次发布的目标是@bitkyc08/opencodex@2.7.1-preview.20260710,基线状态如下:

  • 分支:preview
  • 初始发布 HEAD:3ce5f9c0806962037c0458849113b87d7b498c08
  • 发布前 npm 通道状态:latest: 2.7.0preview: 2.6.31-preview.20260707
  • 目标版本、Git 标签、GitHub Release 在预检(preflight)时均不存在

发布内容包含三个已提交的变更:

Commit内容
a3cc86e8将 Codex warmup 输入作为 Responses API 消息条目发送
b46dc824更新剩余 warmup 负载回归测试预期
3ce5f9c0新增请求的 Cursor GPT-5.6 预览模型

二、发布循环规范(Loop Specification)

该发布单元遵循spec-satisfaction release loop原型,其核心要素如下:

  • 触发器(Trigger):首次发布尝试在真正发布前中止后,将已提交的 Codex warmup 修复与 Cursor GPT-5.6 目录新增发布出去。
  • 目标(Goal):以 npm dist-tagpreview发布目标版本,并创建配套的 prerelease GitHub Release。
  • 非目标(Non-goals):不额外 bump 版本;不改变 npmlatestdist-tag;不通过提高 CI 超时来掩盖挂起的测试;除 web-search 超时修复与用户要求的 injection-effort 功能外不做其他代码变更。
  • 验证器(Verifier):发布 HEAD 上 Cross-platform CI 与 Release 工作流均成功,随后通过 npm 与 GitHub 工件查询确认。
  • 停止条件(Stop condition):npm 在preview下暴露目标版本、latest保持2.7.0、GitHub 在发布 HEAD 暴露匹配的 prerelease 标签/发布。
  • 预期终态(Expected terminal outcomes)DONE(所有公开工件一致)、BLOCKED(凭据或基础设施不可用)、UNSAFE(公开元数据不一致,自动重试可能重复或错误指向发布)。
  • 升级条件(Escalation condition):npm 发布成功但标签/Release 创建失败;验证期间 release 分支移动;trusted publishing 拒绝工作流身份。

三、Phase 1:发布预览包的标准执行流程

Phase 1 的目标是完成预览包的发布与验证,其核心前提是:不要以相同版本重跑scripts/release.ts——因为package.json已 bump,重复执行会导致第二次版本 bump 提交。只允许修改 Phase 2 所述的 web-search 超时回归测试,禁止改动工作流 YAML、lockfile、包元数据,也不得提高 CI 超时。

3.1 两步手动工作流派发

由于「仅 devlog 提交」不匹配ci.ymlservice-lifecycle.yml的 push 路径过滤器,两次前置检查都必须显式workflow_dispatch

gh workflow run ci.yml --ref preview gh workflow run service-lifecycle.yml --ref preview

派发后按分支、精确 HEAD 与创建时间识别两个新 run,要求均以success结论结束,并再次确认origin/preview仍等于该 SHA(防止分支漂移)。

3.2 Release 工作流派发

前置门全部通过后,派发一次非 dry-run的 Release 工作流:

gh workflow run release.yml --ref preview \ -f version=2.7.1-preview.20260710 \ -f tag=preview \ -f dry-run=false

3.3 工作流内置的六重门控

Release 工作流并非盲发,而是在执行中逐项校验(这些是既有工作流分支,不是新代码路径,证据来自真实发布运行):

  • CI 门:查询自身GITHUB_SHA的成功ci.yml运行,日志必须指名成功 run 的 URL;
  • Service lifecycle 门:因package.jsonv2.7.0后变更,需查询成功service-lifecycle.yml运行;
  • 版本门:工作流输入必须与package.json精确一致;
  • 通道门preview分支要求 prerelease 版本与 npm tagpreview
  • 公开元数据预检:目标 npm 版本、Git 标签、GitHub Release 在派发前必须全部缺席;
  • Registry 冒烟:发布后,工作流在创建 Release 元数据前必须先观察到 npm 上的精确版本。

3.4 独立验证命令集

工作流成功后,用独立查询交叉验证 npm、远程标签与 GitHub Release:

gh run view <ci-run-id> --json status,conclusion,url,headSha,jobs gh run view <service-run-id> --json status,conclusion,url,headSha,jobs gh run view <release-run-id> --json status,conclusion,url,headSha,jobs npm view @bitkyc08/opencodex@2.7.1-preview.20260710 version npm dist-tag ls @bitkyc08/opencodex git ls-remote origin refs/tags/v2.7.1-preview.20260710 gh release view v2.7.1-preview.20260710 --json tagName,targetCommitish,url,isPrerelease

3.5 恢复边界

  • npm 发布前:仅在检查失败 job 且确认所有公开元数据仍缺席后,才可重试;
  • npm 发布后:npm 版本不可变,不得重试同一版本的 publish 步骤,只修复缺失的标签/Release 元数据;
  • 预览不可用:将 npmpreview移回2.6.31-preview.20260707,不触碰latest

四、Phase 2:Windows 平台迭代超时挂起的根因修复

这是本次发布中最具技术深度的部分。Cross-platform CI 运行29039366674(HEAD69d8ec7c)中,windows-latestjob(86192390158)的 WindowsTest步骤到达tests/web-search.test.ts:210loop per-iteration timeout surfaces 504 instead of hanging用例后,再无任何测试输出,直至 GitHub 在 8 分钟限制处取消 job;其余五个 job 全部通过。同一聚焦测试在 macOS 上用 Bun1.3.14约 103ms 即可完成。

4.1 假设与证伪(Hypotheses and falsifiers)

发布记录对三个候选根因逐一做了源码级证伪:

  • H1(运行时组合超时边界):Bun on Windows 在 loop 组合AbortSignal.any([parent, AbortSignal.timeout(...)])时不可靠地唤醒 pending adapter promise,或超时在 mock 订阅前触发导致一次性事件丢失。证伪器:能同时处理「已中止信号」与「后续中止」的 adapter 应在 Windows 上约 100ms 返回 504,修复后的回归测试显式覆盖两种订阅状态。
  • H2(信号未传入)runWithWebSearch未将组合信号传给adapter.fetchResponse证伪:源码追踪显示fetchOnce传递abortSignal: iterationSignal,测试 adapter 直接订阅该选项。H2 被 src/web-search/loop.ts 与 tests/web-search/web-search.test.ts 拒绝。
  • H3(共享状态污染):前序测试污染globalThis.fetch或共享状态。证伪afterEach恢复原始 fetch,挂起 adapter 不调用全局 fetch。H3 被测试文件的恢复逻辑与 adapter 实现拒绝。

主因定位:运行时特有的复合超时边界,迟到订阅(late subscription)作为竞争机制保留,直到加固后的 Windows 回归测试通过。仓库此前已为 sidecar 与 vision 调用规避复合原语——改用signalWithTimeout,一个基于setTimeout的控制器,带父信号传播与显式清理。

4.2 复用决策:不新增 helper

直接复用 src/lib/abort.ts 的signalWithTimeout(已被src/web-search/executor.tssrc/vision/describe.ts使用),不新增 helper、依赖、重试、sleep 或仅测试用的生产分支。该函数的核心实现:

  • 创建独立AbortControllersetTimeout到期后以DOMException("Timeout elapsed", "TimeoutError")中止;
  • 父信号已中止时立即传播;否则注册一次性abort监听;
  • 返回{ signal, cleanup }cleanup()清除定时器并移除父监听,保证确定性清理。

同文件中的clearableDeadline(src/lib/abort.ts)注释明确解释了两者的分工:signalWithTimeout().cleanup()会移除父监听,适用于操作完全结束时;而 fetch 响应体在 headers 到达后截止,但原始父信号必须保持挂接在 body 上,故用AbortSignal.any()提供直接生命周期链接、clear()只清定时器。

4.3 Diff 级实现:三个关键改动

改动一:导入切换src/web-search/loop.ts

-import { cancelBodyOnAbort } from "../lib/abort"; +import { cancelBodyOnAbort, signalWithTimeout } from "../lib/abort";

改动二:以链接式超时句柄替换每次迭代的AbortSignal.any构造

-const iterationSignal = deps.connectTimeoutMs - ? AbortSignal.any([signal, AbortSignal.timeout(deps.connectTimeoutMs)]) - : signal; +const iterationTimeout = deps.connectTimeoutMs + ? signalWithTimeout(deps.connectTimeoutMs, signal) + : null; +const iterationSignal = iterationTimeout?.signal ?? signal;

runIterationEvents的 fetch/429/parse 主体包裹进try/finally,并在finally中调用iterationTimeout?.cleanup()。这保证:一次迭代的截止时间跨越所有 429 重试保持不变,且定时器与父监听在成功/失败/生成器关闭路径上都被移除。

改动三:以yield*委托替换手动迭代器转发

-const it = runIterationEvents(forceAnswer); -let r = await it.next(); -while (!r.done) { - yield r.value; - r = await it.next(); -} -split = r.value; +split = yield* runIterationEvents(forceAnswer);

委托的yield*将外层生成器关闭传播到内层迭代器,因此即使 SSE 消费者在转发 429 心跳期间关闭流,内层finally也会执行——这是此前手动while转发无法保证的清理语义。

4.4 测试加固与激活验证

tests/web-search.test.ts的三类加固:

  1. 加固挂起 adapterabortSignal.aborted已为真时立即拒绝,否则只订阅一次,消除 Windows 激活探针的迟到订阅歧义;
  2. 新增「先延迟 429 再挂起轮转」用例:用一个短connectTimeoutMs断言总迭代返回 504,而不是在轮转后获得全新超时——验证「一次截止时间跨轮转」;
  3. 新增父中止用例:等待挂起 adapter 收到信号后中止父 controller,断言迭代随信号中止立即收敛。

本地验证命令:

bun test tests/web-search.test.ts -t "loop per-iteration timeout" bun test tests/web-search.test.ts bun run typecheck bun test tests

现有回归测试 tests/web-search/web-search.test.ts 正是该激活探针:挂起 adapter 在connectTimeoutMs: 100下应返回 HTTP 504 且消息包含 "timeout"。GitHub Actions 侧的完成标准是:WindowsTest步骤越过该测试文件、全部六个 CI job 成功、精确 HEAD 的 Service lifecycle 工作流成功。

五、Phase 3:并入 injection-effort 选择器

用户要求并发开发的injectionEffort功能随本次预览一同发布。其设计记录位于devlog/260710_injection_effort/000_design.md,落点围绕现有 opencodex 开发者 Dashboard、全局 i18n 与密集工具表单,不新增设计 token、素材、卡片、动效、依赖或页面结构,复用现有Select原语与委派面板。用户产出:同时配置首选子代理模型与传给spawn_agentreasoning_effort

5.1 变更清单

  • src/types.ts:新增可选OcxConfig.injectionEffort
  • src/reasoning-effort.ts:导出既有 Codex effort 梯级的成员校验(isCodexReasoningEffort,见 src/reasoning-effort.ts);
  • src/server/management-api.ts:GET 返回当前 effort 与允许的 effort 集合;PUT 在变更配置前校验 model/effort,支持 clear/unchanged 语义,清 model 时连带清 effort;
  • src/server/responses.ts:仅当注入模型与 effort同时配置时才注入reasoning_effort指引;无模型时保留原有 max/ultra 门控;
  • gui/src/pages/Dashboard.tsx:加载 effort 元数据,仅当模型激活时显示第二个既有风格的选择器,保存期间禁用两个控件,成功响应后才更新本地状态;
  • gui/src/i18n/en.tsko.tszh.ts:三种发布语言补充标签与模型默认文案;
  • tests/multi-agent-compat.test.ts:覆盖模型+effort 提示文本、effort 未设置、effort 无模型的门控行为;
  • 新增tests/injection-model-api.test.ts:覆盖 GET/PUT 往返、校验原子性、effort 清除、模型清除与 effort 缺席兼容。

5.2 契约与失败态检查

  • 无效 effort 必须返回 400,且不改变内存或磁盘中已存储的 model/effort;
  • PUT 中缺失effort时保留既有 effort(model 仍设置),保持旧 GUI 客户端兼容;
  • 清 model 连带清 effort;单独清 effort 保留 model;
  • Dashboard 保存失败时保留服务器最后一次确认的选择;控件保持键盘可操作并通过现有Select原语携带无障碍标签。

5.3 验证

bun test tests/injection-model-api.test.ts tests/multi-agent-compat.test.ts bun run typecheck bun test tests cd gui && bun run build

渲染验证使用既有 GUI 服务器与原生浏览器工具,在 1440px、1024px、768px、390px 宽度下检查委派面板在无模型、有模型、模型默认 effort、具体 effort 四种状态下的表现,确认英/韩/中三种语言的标签无重叠裁切,且清除模型后 effort 选择器隐藏。

六、Phase 4:预览提升到稳定通道

预览验证通过后,将preview头提升到main,发布稳定版2.7.1(npmlatest),并保留2.7.1-preview.20260710作为已发布的预览工件。前置条件包括:origin/mainorigin/preview的祖先(0/14 分叉计数)、预览头308787a4已通过 CI 与 Service lifecycle、预览 Release 已公开且指向该头、npm2.7.1与 GitHub releasev2.7.1尚不存在。

流程为:本地main快进到previewpackage.json版本从2.7.1-preview.20260710改为2.7.1→ 提交并推送 → 本地 typecheck/全量测试/隐私扫描/GUI 构建/diff 检查 → 精确稳定提交上的 Cross-platform CI 与 Service lifecycle → 从main派发release.yml(version2.7.1、taglatestdry-run=false)→ 验证 npm 版本/dist-tags、Git 标签、GitHub Release 元数据与干净的 git 状态。回滚纪律:绝不移动或覆盖已发布标签;任一门失败则停止发布,在main上前向修复并重跑精确提交门。

七、风险与恢复、验收标准与证据台账

7.1 风险与恢复矩阵

风险恢复策略
CI 取消或失败重跑或编辑前检查精确最新 HEAD 的 job 状态;部分绿灯 job 不算成功运行
Windows 超时修复保留迭代级截止时间与父中止语义;嵌套迭代事件用yield*委托;异步生成器完成/抛出/被消费者关闭时总是清理定时器与监听
分支漂移origin/preview不再匹配审计后的发布 HEAD 时中止派发
部分 npm 发布npm 版本不可变;发布成功但 GitHub 元数据失败时不得重发同版本,确认 npm 状态后仅修复缺失标签/Release
预览回滚npmpreview恢复至2.6.31-preview.20260707;保留不可变的已发布版本与发布证据
稳定通道安全发布后验证latest仍为2.7.0

7.2 验收标准

最终发布 HEAD 需同时满足:Cross-platform CI 与 Service lifecycle 均以success结论完成;挂起 adapter 回归在本地返回 HTTP 504 且在 Windows CI job 上正常完成而非耗尽 job 超时;injection-model API 测试证明 model/effort 往返、清除与无效 effort 的原子拒绝,提示测试证明 effort 仅在伴随模型时注入;GUI 构建通过且 Dashboard 的 model/effort 控件在桌面/平板/移动宽度下无裁切重叠;Release 工作流以dry-run=false、tagpreview、目标版本成功;npm view @bitkyc08/opencodex@2.7.1-preview.20260710 version返回目标版本;npm dist-tag ls报告preview: 2.7.1-preview.20260710latest: 2.7.0;远程标签v2.7.1-preview.20260710解析到发布 HEAD;对应 GitHub Release 存在且标记为 prerelease;闭卷记录提交推送后工作树干净。

7.3 证据台账与文档归档

预检证据记录于计划文档;最终 CI、工作流、registry、标签与 Release 证据在 D 阶段(closure)追加到证据台账后,将实现单元归档至devlog/_fin/。整个发布单元的文档脉络为:000_plan.md(发布意图、风险与证据台账)→ 010_phase1_preview_release.md(精确执行与验证步骤)→ 020_phase2_windows_timeout.md(Windows CI 根因假设、diff 级修复与激活证明)→ 030_phase3_injection_effort.md(并发功能纳入图与门)→ 040_phase4_latest_promotion.md(稳定通道提升)。

这套流程为后续所有预览发布提供了可复用的模板:发布意图先落盘、版本与分支强绑定、CI/生命周期/版本/通道/元数据预检/registry 冒烟六重门控、npm 版本不可变约束下的恢复纪律、精确 HEAD 而非「差不多绿」的验证原则——尤其是「不得以提高 CI 超时掩盖挂起测试」这一非目标,直接驱动了 Windows 超时问题的源码级根因修复而非治标。

【免费下载链接】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

项目地址:https://gitcode.com/gh_mirrors/ope/opencodex
点击查看免费下载
上一篇:angular-cli 中的 TempScopedNodeJsSyncHost:Angular DevKit 临时目录同步虚拟文件系统测试工具解析
下一篇:kustomize ConfigMapGenerator 完全指南:参数解析、源码原理与滚动更新实践

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询