oh-my-codex 0.18.4 补丁发布解读:Ultragoal 恢复硬化、omx explore 弃用契约与运行时安全修复全览
【免费下载链接】oh-my-codexOmX - Oh My codeX: Your codex is not alone. Add hooks, agent teams, HUDs, and so much more.项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-codex
本文是 oh-my-codex 仓库0.18.4补丁版本(紧随0.18.3之后,源自dev分支的运行时安全与操作者体验修复集)的技术指南,覆盖 Ultragoal 恢复逻辑加固、omx explore正式弃用、Team/HUD 所有权收敛、插件原生 Agent 安装、项目级 Codex 信任同步、Autopilot 提问等待,以及 ralplan 评审交接契约收紧。读完本文,你将掌握本次补丁涉及的核心机制、底层实现位置、命令行验证门禁,以及每个修复背后的源码级依据,可直接用于排查与回归验证。
版本定位:一次专注「安全与体验」的补丁发布
0.18.4是0.18.3之后的 patch 版本,全部变更集中在已经合入dev分支的运行时安全(runtime-safety)与操作者体验(operator-experience)修复。官方发布说明(docs/release-notes-0.18.4.md)将其范围归纳为七个方向:
- Ultragoal 恢复更安全——纯文本标签的 checklist 章节不再混淆 Ultragoal 解析;已完成聚合目标不再触发不可恢复的 Stop 恢复循环;
- Explore 弃用但不破坏旧调用方——运行期引导将操作者从
omx explore引导到新的查询工作流,同时保留兼容行为; - Autopilot 提问流程正确等待——deep-interview 问题处理可以等待
omx question的答案,而不是提前继续; - Team 与 HUD 所有权更清晰——worker 的 UserPromptSubmit 路径不再接管 leader 的 HUD 对账,重复 HUD pane 生成的收敛问题得到修复;
- 插件原生 Agent 设置更可靠——doctor/setup 路径暴露缺失的 reviewer 角色、保留插件专属的 obsolete Agent、插件原生 Agent 角色 CI 得到覆盖;
- 项目级信任同步更安全——Codex 信任同步重启不再损坏本地配置;
- Ralplan 评审契约更紧——评审子代理指令收窄,确保在执行交接前评审证据保持 grounded。
合并 PR 清单与一一对应关系
0.18.4的变更体量通过合并 PR 清单可以精确回溯,共 12 个 PR(#2499、#2501、#2502、#2504、#2507、#2508、#2515、#2519、#2521、#2522、#2524、#2525)。对照 docs/qa/release-readiness-0.18.4.md 中的逐条说明,每个 PR 与修复目标的对应关系如下:
| PR | 主题 | 修复目标 |
|---|---|---|
| #2499 | Ultragoal 解析 | 忽略纯文本标签的 Ultragoal checklist 章节 |
| #2501 | ralplan | ralplan 等待前先对账已完成的 subagents |
| #2502 | HUD 所有权 | worker 的 UserPromptSubmit 不再拥有 HUD 对账 |
| #2504 | CLI | 在运行期引导中弃用omx explore |
| #2507 | Ultragoal 恢复 | 防止不可恢复的 Ultragoal Stop 恢复循环 |
| #2508 | Autopilot | 允许 deep-interview 等待omx question |
| #2515 | doctor | 在 doctor 中暴露插件原生 reviewer 角色就绪状态 |
| #2519 | CI | 修复插件原生 Agent 角色设置的 CI |
| #2521 | 插件 | 保留插件专属的 obsolete 原生 Agent |
| #2522 | 信任同步 | 修复项目级 Codex 信任同步重启回归 |
| #2524 | ralplan | 收紧 ralplan 评审子代理契约 |
| #2525 | HUD | 修复重复 HUD pane 生成收敛 |
Ultragoal 恢复硬化(#2499、#2507):解析与 Stop 循环双修复
Ultragoal 是 oh-my-codex 的持久化多目标执行引擎,其运行期工件固定在.omx/ultragoal/目录下:brief.md(目标简报)、goals.json(目标计划)、ledger.jsonl(审计流水)。这三个常量的定义位于 src/ultragoal/artifacts.ts:
export const ULTRAGOAL_DIR = '.omx/ultragoal'; export const ULTRAGOAL_BRIEF = 'brief.md'; export const ULTRAGOAL_GOALS = 'goals.json'; export const ULTRAGOAL_LEDGER = 'ledger.jsonl';修复一:纯文本标签 checklist 章节不再被误解析为 story
Ultragoal 需要把 Markdown 简报推导为可执行目标。核心解析函数parseMarkdownListItems与normalizeSectionLabel会把章节标签归一化为小写文本,例如 ATX 标题### Checklist与纯文本标签Checklist:都会被识别为同一类章节。随后sectionLooksNonStory与sectionLooksStory两组正则决定哪些章节属于「故事」(story,可成为目标)哪些属于「非故事」(检查清单、证据、约束、风险等)。
在0.18.3及之前,纯文本标签(plain-label)的 checklist 章节(例如没有#前缀、只有Checklist:这样一行文字的章节)存在被误判为 story 的风险,导致目标解析出现无关目标。#2499让这类章节在归一化后进入sectionLooksNonStory的判定范围,从而被正确排除。相关的章节判定逻辑可以在 src/ultragoal/artifacts.ts 中看到:
function normalizeSectionLabel(value: string): string | undefined { if (/^\s*(?:[-*+]\s+|\d+[.)]\s+)/.test(value)) return undefined; const atx = /^#{1,6}\s+(.+?)\s*#*\s*$/.exec(value)?.[1]; const plain = /^([^\s].{1,100}):\s*$/.exec(value)?.[1]; return (atx ?? plain)?.replace(/[`*_~]/g, '').replace(/:$/, '').trim().toLowerCase(); } function sectionLooksNonStory(section: string | undefined): boolean { return /^(?:acceptance\s+criteria|verification(?:\s+checklist)?|validation(?:\s+checklist)?|checklist|evidence|constraints?|risks?|immediate\s+next\s+actions?|next\s+actions?|follow-?ups?|notes?)$/.test(section ?? '') || sectionLooksPlanReview(section); }同时,assertSafeImplicitMarkdownGoalCount设置了隐式 Markdown 目标的硬上限MAX_IMPLICIT_MARKDOWN_GOALS = 20(src/ultragoal/artifacts.ts):当从简报推导出的隐式目标超过 20 个时,引擎会拒绝执行并提示改用紧凑可执行的故事,例如重复传入--goal "Title::Objective",或把简报改写为显式的### Stories/### Goals章节。这为操作者提供了清晰的错误修复路径。
修复二:已完成聚合目标不再触发不可恢复的 Stop 恢复循环
#2507解决的是 Ultragoal 聚合模式下(codexGoalMode === 'aggregate')的恢复死循环问题。在聚合模式下,Codex 只持有一个覆盖整个 ultragoal run 的聚合目标(aggregateCodexObjective生成,见 src/ultragoal/artifacts.ts)。当 Stop 恢复流程遇到已经完成(status 为 complete)的聚合 Codex 目标时,旧逻辑可能反复尝试创建/标记目标,陷入不可恢复的循环。
修复通过isSafeCompletedAggregateBlockerSnapshot实现条件化判定(src/ultragoal/artifacts.ts):
function isSafeCompletedAggregateBlockerSnapshot( plan: UltragoalPlan, goal: UltragoalItem, snapshot: ReturnType<typeof parseCodexGoalSnapshot>, evidence: string | undefined, ): boolean { if (codexGoalMode(plan) !== 'aggregate') return false; if (goal.status !== 'in_progress' || plan.activeGoalId !== goal.id) return false; if (snapshot?.status !== 'complete' || !snapshot.objective) return false; if (!evidenceDescribesCompletedAggregateMicrogoalLoop(evidence)) return false; const actual = normalizeObjective(snapshot.objective); return [expectedCodexObjective(plan, goal), ...compatibleCodexObjectives(plan)] .some((objective) => normalizeObjective(objective) === actual); }只有同时满足以下条件时才把「已完成聚合目标」视为安全阻塞快照:证据文本描述的是aggregate codex goal+complete(d)+microgoal+unreconcilable/mismatch/loop/already complete这类循环特征(evidenceDescribesCompletedAggregateMicrogoalLoop),且 Codex 快照目标与计划期望的聚合目标或其兼容别名精确匹配。最终完成判定则由isFinalRunCompletionCandidate/isUltragoalDone(src/ultragoal/artifacts.ts)统一把关,确保 Stop 恢复走干净路径而非死循环。
相关文档契约
Ultragoal 的文档契约由 src/ultragoal/tests/docs-contract.test.ts 强制维护:技能卡片必须保持精简(≤120 行)、必须提及.omx/ultragoal/brief.md、goals.json、ledger.jsonl三件套、默认聚合 Codex 目标模式、get_goal/create_goal/update_goal边界,以及「不得从 shell 或技能中调用 Codex/goal clear」等约束;同时要求插件镜像卡片与源卡片逐字节一致(docs[0] === docs[1])。详情可继续阅读 skills/ultragoal/SKILL.md 与 docs/ultragoal.md。
omx explore 正式弃用(#2504):兼容保留、引导迁移
omx explore的弃用契约在0.18.4中正式写入运行期引导,但不破坏旧调用方。其实现位于 src/cli/explore.ts,核心是两个导出常量与一个命令入口:
export const EXPLORE_DEPRECATION_MESSAGE = [ 'omx explore is hard-deprecated and the direct command surface has been removed.', 'Use normal Codex repository inspection tools/subagents for read-only repository lookups.', 'Use `omx sparkshell -- <command>` only for explicit shell-native read-only evidence or `--tmux-pane` summaries.', ].join(' ');exploreCommand的行为是:如果参数全部是--help/-h/help,则打印EXPLORE_HELP帮助文本并正常返回;否则抛出包含弃用说明与迁移指引的Error(src/cli/explore.ts)。也就是说:
omx explore --help:仍可用,展示用法与迁移建议;omx explore --prompt "<prompt>"、omx explore --prompt-file <file>:旧形态全部有意失败(fail intentionally),并给出弃用消息;- 迁移路径:简单只读仓库查询改用常规 Codex 仓库检查工具/子代理;需要显式 shell 原生只读证据时改用
omx sparkshell -- <command>,或使用其--tmux-pane摘要能力。
此外,explore.ts中还保留了 Windows 平台的内置 explore harness 不可用说明(getBuiltinExploreHarnessUnsupportedReason):由于内置 harness 的 allowlist 运行期依赖 POSIX sh/bash 包装器,在 Windows 上不可用,可通过设置OMX_EXPLORE_BIN指向自定义 harness 解决,或直接改用omx sparkshell。
Autopilot 提问等待(#2508):deep-interview 正确等待 omx question
0.18.4之前,Autopilot 监督的 deep-interview 提问环节存在「提前继续」的缺陷:问题已发出但答案未归位时,流程可能不再等待直接推进。#2508让 Autopilot 的 deep-interview 阶段能够真正等待omx question的答案。
实现集中在 src/question/autopilot-wait.ts,核心判定函数isPendingAutopilotQuestionWait要求三要素齐备才视为「等待中的提问」:
function isPendingAutopilotQuestionWait(wait: Record<string, unknown>): boolean { return safeString(wait.status) === 'waiting_for_user' && safeString(wait.source) === 'omx-question' && safeString(wait.obligation_id).length > 0; }配套机制包括:以状态文件 + 目录锁(.deep-interview-question.lock)实现的互斥等待,maybeRecoverStaleAutopilotQuestionWaitLock清理陈旧锁,以及withAutopilotQuestionWaitLock的超时兜底(到 deadline 后调用onTimeout)。流程上,deep-interview 阶段发起waiting_for_user状态的提问义务(写入deep_interview_question嵌套状态),Autopilot 停留在waiting-for-user阶段直到用户通过omx question应答,再依据previous_phase/previous_run_outcome恢复执行。整个机制保证了提问环节的「先答后行」。
Team / HUD 所有权收敛(#2502、#2525):leader 独享对账
HUD(Head-Up Display)对账属于 leader 的专属职责,0.18.4从两个方向收敛所有权:
- #2502:worker 的 UserPromptSubmit 路径不再拥有(owning)leader 的 HUD reconcile。此前 worker 侧钩子可能越权触发本应仅由 leader 执行的对账,造成状态归属混乱;修复后对账在所有 worker 提示钩子中保持 leader 独有(release notes 原话:HUD reconciliation remains leader-owned across worker prompt hooks)。
- #2525:修复重复 HUD pane 生成的收敛问题,避免多个 pane 因并发/重复触发而叠加生成。
这与 Ultragoal 文档契约中的「worker 不拥有 ultragoal 目标状态、leader 使用新鲜的get_goal快照记录 checkpoint」原则(见 src/ultragoal/tests/docs-contract.test.ts 与 templates/AGENTS.md 中的Durable Runtime Invariants (canonical SSOT))一脉相承:执行可并行,状态归 leader。
插件原生 Agent 设置可靠性(#2515、#2519、#2521)
插件(plugin)模式下原生 Agent 的设置路径在0.18.4中经历三处修复:
- #2515:
omx doctor(以及 setup 路径)现在能暴露插件原生reviewer 角色缺失的就绪状态,操作者可以据此补齐角色配置; - #2519:修复插件原生 Agent 角色设置的 CI,确保该路径持续被回归覆盖(release notes 称plugin native-agent role CI covered);
- #2521:保留插件专属的 obsolete 原生 Agent。此前清理逻辑可能把仅由插件持有、但在主仓库视角已过时的 Agent 一并删除,导致插件功能受损;修复后清理只针对确实可安全移除的条目。
该领域有专门的验证脚本支撑:npm run verify:native-agents。在0.18.4的发布就绪证据(docs/qa/release-readiness-0.18.4.md)中,该门禁结果为 PASS,覆盖22 个可安装原生 Agent、37 个 setup 提示资产。
项目级 Codex 信任同步回归修复(#2522)
omx在项目作用域启动时会向项目级config.toml写入「OMX-owned 的 Codex 钩子信任状态」以及「OMX-synced 的项目信任状态」,使 Codex 把工作区视为已信任、不再反复询问。#2522修复的是信任同步重启(relaunch)回归:旧逻辑在重启场景下可能损坏本地配置(例如重复写入钩子信任表、破坏 setup 所有的钩子信任块)。
相关行为在 src/cli/tests/index.test.ts 中有端到端测试覆盖,测试名直接对应 issue 编号:
project-scope launch registers native hooks exactly once and persists trust state (GH #2470)——断言项目作用域启动恰好注册一次原生钩子,信任状态块以# OMX-owned Codex hook trust state/# End OMX-owned Codex hook trust state为界,且trusted_hash = "sha256:..."被持久化;repairs duplicate project hook trust state before relaunching project-scope Codex home (GH #2401)——断言重启前会修复重复的项目钩子信任状态,且「用户所有的项目信任源在启动修复期间必须保持外部」;keeps setup-owned hook trust state targeted at the project hooks path (GH #2470)——断言 setup 所有的钩子信任状态始终指向项目钩子路径,运行期CODEX_HOME不再持有 hooks.json 镜像。
这套测试同时约束了「运行期信任同步不得复制 setup 所有的钩子信任状态」与「下次启动必须继承已持久化的工作区信任条目」两条不变量。
ralplan 评审交接契约收紧(#2501、#2524)
ralplan(review/plan 编排层)在0.18.4中做了两处契约收紧:
- #2501:ralplan 在进入等待(wait)之前,先对账(reconcile)已完成(completed)的 subagents,避免基于陈旧子代理状态进入等待;
- #2524:评审子代理(reviewer subagent)的指令被收窄,确保评审证据在执行交接(handoff)之前保持 grounded,防止评审结论在交接后漂移或脱离证据。相关实现分散于 src/ralplan/runtime.ts、src/ralplan/runtime-contract.ts、src/ralplan/advisory-contract.ts 等文件,
runtime-contract.ts中定义了provenance_kind?: 'native_subagent'这类来源溯源字段,为「证据必须可溯源到具体子代理」提供了类型级约束。
发布验证门禁:从本地到 GitHub Release 的两阶段闸门
0.18.4的发布验证分两阶段。第一阶段是打标签前的本地门禁,记录于 docs/qa/release-readiness-0.18.4.md,全部在dev分支上执行:
| 门禁命令 | 作用 | 0.18.4 结果 |
|---|---|---|
npm run build | 全量构建 | PASS |
npm run lint | 静态检查(Checked 681 files) | PASS |
npm run check:no-unused | 未使用代码检查 | PASS |
npm run verify:native-agents | 原生 Agent 清单验证(22 个 Agent / 37 个资产) | PASS |
npm run sync:plugin | 插件镜像同步(29 个技能目录) | PASS |
npm run verify:plugin-bundle | 插件包一致性验证 | PASS |
node dist/scripts/generate-catalog-docs.js --check | 目录文档生成一致性 | PASS |
git diff --check | 空白错误检查 | PASS |
npm pack --dry-run | 打包演练(3.6 MB / 解包 22.1 MB / 2974 文件) | PASS |
第二阶段是标签推送后的 GitHub Release 工作流,它仍是跨平台原生资产与 npm 发布的权威闸门(The GitHub release workflow remains the authoritative cross-platform native asset and npm publication gate after tag push)。本地准备阶段明确不做npm publish,发布行为全部委托给v0.18.4标签推送后触发的 Release 工作流,以保证「未验证前不得宣称已发布」。
发布就绪文档还记录了外部发布动作顺序:按 Lore commit 协议提交发布准备 → 推送dev→ 合并dev到main→ 从合并后的main创建并推送v0.18.4标签 → 验证 GitHub Release 资产与 npm 发布 → 视需要补充 CI/发布证据。
贡献者与变更范围
v0.18.3...v0.18.4变更区间由两位贡献者完成:@Yeachan-Heo(#2501、#2502、#2504、#2507、#2508、#2515、#2519、#2521、#2522、#2524、#2525)与 @iqdoctor(#2499)。贡献者信息与完整 Changelog 索引见 docs/release-notes-0.18.4.md 末尾。
小结与升级建议
0.18.4虽是一个 patch 版本,但其修复密度与安全性价值不容小觑:Ultragoal 的解析与 Stop 恢复双硬化直接降低了持久化目标执行卡死的概率;omx explore的弃用契约为后续命令面瘦身铺平道路;HUD/trust sync 的修复避免了状态所有权与本地配置被破坏的隐性风险。若你正在使用0.18.3或更早版本并依赖 Ultragoal 聚合模式、插件原生 Agent 或项目级信任同步,建议重点回归以下场景:
- 简报中包含
Checklist:/Verification:等纯文本标签章节的 Ultragoal 解析结果; - 聚合模式(aggregate Codex goal)下已存在 completed 聚合目标的 Stop 恢复;
- 插件模式下 doctor 报告的 reviewer 角色缺失与 obsolete Agent 保留;
- 项目作用域重复启动后的
config.toml信任状态完整性与唯一性。
以上修复对应的全部本地验证证据可继续查阅 docs/qa/release-readiness-0.18.4.md,实现细节可沿本文给出的源码路径逐层深入。
【免费下载链接】oh-my-codexOmX - Oh My codeX: Your codex is not alone. Add hooks, agent teams, HUDs, and so much more.项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-codex
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考