oh-my-codex 0.18.3 发布解析:HUD 生命周期清理、Deep-Interview 权限收紧与插件边界保护
【免费下载链接】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.3 是继 0.18.2 之后的一个 patch 版本,聚焦于dev分支上的"发布后可靠性与运维体验"补丁列车(post-release reliability and operator-experience train)。它集中修复了 HUD/tmux 生命周期清理、提升 Team diff 的可读性、支持 auth 槽位热切换、保持 explore 提示语法可见、支持 deep-interview 运行时配置覆盖与更严格的下游执行权限、保护插件自有 hook,并新增了 Scholastic ontology 评审 agent。读完本文,你将掌握 0.18.3 各项改动的设计动机、底层实现路径、可复用的配置方法,以及版本发布前的完整验证流程与已知残余风险。
版本定位与发布范围
0.18.3是一个 patch 版本,来源为dev分支上对0.18.2的跟进修复。从发布就绪文档(docs/qa/release-readiness-0.18.3.md)可知:
- 上一个 tag:
v0.18.2(commit29e87a24a0ed354283604bfc1ba995d1245813c4); - 候选分支:
dev在7f0a3fa1,发布元数据 rebase 到最新origin/devdelta 之上; - 发布的 tag:
v0.18.3。
0.18.3 打包的改动面(即本文的核心主线)包括:
- HUD 生命周期/reconcile 修复:按 leader 合并启动期 pane、保留 session id/owner 环境变量、回收 dead-leader HUD pane、在 UserPromptSubmit 复活时复用既有 HUD;
- Team diff 在换行多行 hunk 上保留 diff gutter;
- deep-interview 运行时配置覆盖,以及更严格的
plan_then_execute下游执行权限约束; - auth 槽位热切换(hot-swap)wrapper 支持;
- explore 运行时指引中保持 prompt 语法可见;
- setup/update 路径上保留插件自有的 Codex hook,不覆盖用户/插件表面;
- 新增 Scholastic ontology 评审 agent(agent catalog 与 native config 表面);
- skills/agents 膨胀审计(bloat-audit)与连通性路线图文档。
HUD 生命周期清理:更少陈旧、更少重复的 HUD pane
这是 0.18.3 最大的修复主题。HUD 是 oh-my-codex 在 tmux 窗口中渲染的实时状态看板,由一个hud --watchpane 承载。核心改动来自 src/hud/reconcile.ts 中reconcileHudForPromptSubmit及其辅助函数。
同一 leader 的 HUD pane 合并(coalesce)
启动路径与每次 prompt submit 都可能触发 HUD reconcile。当同一个 leader(Codex REPL pane)在窗口内拥有多个 HUD pane 时,planOwnedHudPaneDedupe会挑选一个 keeper pane,将其余同 owner 的 pane 标记为重复并杀掉,最终状态以replaced_duplicates返回。这样即使多个创建者并发观察到"无 HUD"并各自分裂出一个 HUD,第二个创建者也会通过 create 后的二次扫描(postCreatededupe)把竞争产生的重复 pane 收敛掉,而不是让用户窗口堆满重复看板。
会话所有权保留(session ownership)
HUD watch pane 通过环境变量声明归属:
OMX_TMUX_HUD_OWNER(值1)标记该 pane 是显式由 omx 创建的 HUD;OMX_TMUX_HUD_LEADER_PANE记录其所属 leader pane。
这些字段在 src/hud/tmux.ts 中被解析为HudPaneOwner(含sessionId、leaderPaneId等)。0.18.3 修复了 HUD 启动/恢复过程中 session id 与 owner 环境变量的漂移,避免跨 worktree 累积与陈旧 session-id/env 残留。
回收 dead-leader HUD pane(reap)
reapOrphanedSessionHudPanes针对一个典型退化场景:当 leader pane 被销毁(例如teamsetup/teardown 周期拆掉了 leader REPL pane),其 owner 标记的 HUD pane 仍指向已死亡的 leader id,既无法被findHudWatchPaneIds(要求记录的 leader 等于当前 pane)匹配,也无法被findLegacyFocusedHudWatchPaneIds(只收养缺少 owner 元数据的 HUD)匹配。于是每次 prompt submit 时 reconcile 都看到"没有 HUD",重新创建一个,最终窗口退化成只剩一堆堆叠的 HUD 条带、没有任何 leader/worker pane。
修复的关键约束是回收范围严格限定在当前 session:属于其他 session 的 HUD pane(其 leader 可能合法地存在于本窗口看不到的其他 tmux 窗口中)绝不会被触碰。reapStaleCurrentLeaderHudPanes则处理另一种情况——Codex 自更新会在同一 tmux pane 内以新的 OMX session id 重启/恢复 leader,而旧 HUD watcher 仍然存活,此时只回收绑定到该确切 leader pane 的陈旧 HUD,相邻 pane 的 HUD 仍按leaderPaneId隔离。
reconcile 的并发安全
由于同一窗口内所有 OMX pane 的布局变更 hook 可能同时触发,reconcile 通过.omx/state/hud-reconcile.lock目录锁将 tmux 布局变更串行化:
HUD_RECONCILE_LOCK_STALE_MS = 10_000(锁过期阈值);HUD_RECONCILE_LOCK_RETRY_MS = 50(重试间隔);HUD_RECONCILE_LOCK_WAIT_MS = 2_000(最长等待时间)。
锁实现会读取owner.json(含 token、pid、acquired_at),对过期锁先 rename 到.stale.*路径做二次校验(token 与 mtime 双重比对),再原子接管;持有者的 pid 已死才会被判定为陈旧,否则视为"并发的邻接 leader 正在持有"而短暂等待。拿不到锁时返回skipped_concurrent,并尽力重挂 resize hook,避免邻接 leader 的一次性 hook 被误判为并发而丢弃。
UserPromptSubmit 复活时复用既有 HUD
发布说明明确提到,0.18.3 在 UserPromptSubmit revive 路径上复用现有 HUD而不是重新分裂。结合 reconcile 逻辑:当检测到单个 HUD pane 且几何拓扑无需重建(needsHudTopologyRecreate为 false)时,仅做高度对齐(needsHudHeightResize)与 resize hook 重挂,状态为unchanged或resized;只有 HUD 缺失或拓扑错误(宽度不贴合 leader、未紧贴 leader 下方或窗口底部)时才重建。此外,窗口高度过矮(isTmuxWindowTooCrampedForHudSplit)时 prompt submit 也会跳过分裂,防止复活出启动路径本就拒绝添加的 2 行高挤压 HUD(对应 issue #2754)。
Team diff 可读性:换行 hunk 保留 gutter
0.18.3 修复了 Team 输出中 diff hunk 的渲染问题:被换行的多行 diff hunk 之前会丢失左侧的 diff gutter,导致长补丁在 tmux pane 中难以对照阅读。本次改动让 wrapped 的多行 diff 仍保留 gutter 前缀,长补丁在窄 pane 中依然保持可读。
对应测试见 src/team/tests/tmux-session.test.ts 中的用例 "redraws the leader pane after team layout changes so wrapped diff hunks repaint with gutters"(约第 5316 行):该用例用 mock tmux fixture 模拟 leader/worker/HUD 多 pane 布局变化,验证 leader pane 在 Team 布局变更后会被重绘,从而让换行的 diff hunks 带着 gutter 重新上屏。
Deep-Interview:运行时配置覆盖与 plan_then_execute 权限门
0.18.3 对 deep-interview 做了两件事:支持运行时配置覆盖,以及把plan_then_execute下游执行权限作为绑定门(binding gate)强制。
运行时配置覆盖
deep-interview 的运行时配置解析集中在 src/config/deep-interview.ts:
- 三个预设 profile:
quick/standard/deep,默认standard; - 每个 profile 有独立的阈值(threshold)与最大轮数(maxRounds)默认值:
| profile | threshold 默认 | maxRounds 默认 |
|---|---|---|
| quick | 0.30 | 5 |
| standard | 0.20 | 12 |
| deep | 0.15 | 20 |
配置以 TOML 表[omx.deepInterview]形式出现,支持键:defaultProfile、quickThreshold、standardThreshold、deepThreshold、quickMaxRounds、standardMaxRounds、deepMaxRounds、enableChallengeModes。enableChallengeModes默认true;threshold 必须落在(0, 1]区间,maxRounds 必须是正整数,非法值会被忽略并回退到默认值。
配置文件按优先级级联查找(getDeepInterviewConfigCandidatePaths):
<cwd>/.omx/config.toml(project-omx)<cwd>/omx.toml(project-root)- git worktree 根目录的
.omx/config.toml与omx.toml(若 cwd 不是 worktree 根) ~/.omx/config.toml(user)
resolveDeepInterviewRuntimeConfig按此顺序取第一个包含[omx.deepInterview]表的文件,构建DeepInterviewRuntimeConfig(profile、threshold、maxRounds、enableChallengeModes、sourcePath)。测试 src/config/tests/deep-interview.test.ts 覆盖了优先级级联:例如 home 级standardThreshold = 0.40、项目根omx.toml为0.30、项目.omx/config.toml为0.10时,最终取最高优先级 0.10。这里同时体现 0.18.3 的关键语义:高层级文件即使存在但未包含 deepInterview 表,也不会级联到低优先级文件(测试 "does not cascade to lower-precedence configs when an existing higher-precedence file omits deepInterview")。
profile 也可以从调用文本中解析:parseDeepInterviewProfileFromText识别$deep-interview/deep-interview调用之后的--quick/--standard/--deepflag,flag 优先于defaultProfile。最终运行时会把这些配置写入状态字段(deep_interview_config、profile、threshold、max_rounds、enable_challenge_modes、config_source),供后续流程读取。
plan_then_execute 下游权限门
src/question/deep-interview.ts 中DeepInterviewStateRecord明确携带downstream_authority?: 'plan_then_execute' | 'execute_now'。0.18.3(PR #2476/#2478)将其作为 binding gate 强制执行:deep-interview 提问完成后,下游执行权限只能是plan_then_execute(先规划后执行),不能跳过规划直接execute_now。同时该文件实现了完整的提问义务(obligation)生命周期状态机:
createDeepInterviewQuestionObligation创建 pending 义务(obligation_id、source: 'omx-question'、lifecycle_outcome: 'askuserQuestion'、requested_at);satisfyDeepInterviewQuestionObligation在收到已回答记录后置为 satisfied;clearDeepInterviewQuestionObligation在 handoff / abort / error 三种原因下清空;reconcileDeepInterviewQuestionEnforcementFromAnsweredRecords从 question 记录目录反查已答记录并自动满足义务;- 与 autopilot 的等待声明(
AUTOPILOT_DEEP_INTERVIEW_QUESTION_OWNER_ENV)协同,防止 autopilot 在执行模式阻塞时重复发起提问。
runDeepInterviewQuestion是入口:创建义务、声明 autopilot 等待、写 enforcement 状态、调用runOmxQuestion提问、成功则满足义务并 resolve 等待,失败则清空义务并标记cleared。
Auth 槽位热切换(hot-swap)wrapper
0.18.3 纳入了 auth slot hot-swap wrapper(PR #2484/#2493),核心实现见 src/auth/hotswap.ts 的runAuthHotswap。
其流程要点:
- 通过
stripHotswapArg从 argv 中剥离--hotswap,并剥离 leader 启动策略参数(--direct/--tmux); - 读取 auth 配置与已配置槽位:
omx auth add <slot>注册槽位,omx auth use <slot>切换;无槽位时直接提示错误并返回 1; - 生成一次性的 hot-swap session id(
omx-<timestamp>-<random>),调用lifecycle.preLaunch建立启动绑定; - 把当前槽位的 auth.json 写入
liveAuthPath(useSlot),循环尝试槽位:- 成功(exit 0)直接返回;
- 识别
token_invalidated/refresh_token_invalidated等鉴权失效错误(isAuthInvalidationError)与 quota 错误(isQuotaError,见 src/auth/quota-detector.ts); - 遇 quota 则标记该槽位(
markSlotQuota)并旋转到下一槽位;rotation 模式为manual时提示用户手动处理并返回; - 遇 token 失效同样旋转,并提示之后用
omx auth add <slot> --device-auth刷新; - quota 场景还会用
buildResumeArgsWithPreservedFlags构造codex resume <sessionId>参数(保留原全局选项如-m/--model、-p/--profile、-c/--config、--sandbox等),在旋转槽位后恢复最近的 rollout session,避免配额切换后丢失上下文;
- 结束后执行
postLaunch与运行时 codex home 清理,任何异常信息经 src/auth/redact.ts 的redactAuthSecrets脱敏后输出。
相关测试见 src/auth/tests/hotswap.test.ts。
Explore 运行时指引保持 prompt 语法可见
0.18.3(PR #2494/#2495)确保omx explore的运行时指引中始终展示 prompt 调用语法(omx explore --prompt "<prompt>"与omx explore --prompt-file <file>),这样运维者在实际使用 explore 时不至于丢失调用形态。
值得注意的是当前仓库中omx explore已经进入 hard-deprecated 状态:src/cli/explore.ts 的EXPLORE_DEPRECATION_MESSAGE明确说明该命令表面已被移除,建议改用常规的 Codex 仓库检视工具/subagent 做只读检索,或使用omx sparkshell -- <command>获取 shell 原生只读证据与--tmux-pane摘要。此外,内置 explore harness 在 Windows 上不可用(allowlist 运行时依赖 POSIX sh/bash wrapper),可通过OMX_EXPLORE_BIN指定兼容的自定义 harness,或直接运行omx doctor查看就绪状态。0.18.3 的贡献是保证在这个过渡期里,explore 相关的运行时指引不会隐藏 prompt 语法本身。
插件自有 hook 的保留
0.18.3(PR #2477)让 setup 与 native hook 路径尊重插件所有权边界:Codex 配置/安装过程中保留插件自有的 hook,不再覆盖用户或插件表面,同时对无效/缺失覆盖给出告警。
相关的所有权保护语义在技能目录场景中也有同族测试佐证:src/cli/tests/setup-skills-overwrite.test.ts 覆盖了:
- 普通刷新时退役 catalog 已移除的 OMX 技能、同时保留用户自建技能("a user-authored skill is never OMX-owned");
- 即使技能目录收据与徽章被伪造,也保留用户文件;
- 已退役的技能字节可回溯(setup 备份根中
prometheus-strict/SKILL.md可恢复); - setup 与
--force刷新期间保留无关的用户自建技能目录。
新增 Scholastic ontology 评审 agent
0.18.3 引入了一等公民的 Scholastic ontology 评审 agent(PR #2483),进入 agent catalog 与 native config 表面。该 agent 面向本体论密集(ontology-heavy)的评审场景:对评审对象做概念归一化、类别错误(category mistake)检测、模态声明(modal claims)分离等本体层面的审查。
在后续文档(docs/ultragoal.md 第 200 行)中可以看到其评审输出形态的实例:
"scholasticReview": { "recommendation": "APPROVE", "ontologyStatus": "SOUND", "evidence": "terms normalized; no category mistake; modal claims separated" }即评审以结构化 JSON 呈现:recommendation(结论)、ontologyStatus(本体状态)、evidence(证据链)。ultragoal 工作流中,已通过 Scholastic 评审的 advisory 证据可带入质量门;非 clean 的 Scholastic 结论应作为阻断性证据而非完成声明。当前版本迭代中该 agent 后续被 deregistered(见 CHANGELOG.md 第 45 行附近 #3506/#3502/#3508 的说明),但在 0.18.3 发布时刻它属于新增能力。
Skills/Agents 膨胀审计文档
0.18.3 携带了 skills/agents 膨胀审计(bloat-audit)与连通性路线图(PR #2474),完整落盘于 docs/audit/skills-agents-bloat-audit/ 目录:
- inventory.md:全量清单(skill + agent),含状态、LOC、最后提交、引用计数与 skill↔agent 叙事耦合矩阵;
- bloat-audit.md:逐条分类为 KEEP-AS-IS / CONSOLIDATE / STREAMLINE / DEPRECATE / AMBIGUOUS,每条附证据、动作与风险;
- connectivity-roadmap.md:孤儿(orphan)分析、连通性修复建议(quick wins / medium / strategic)与建议的 PR-by-PR 落地序列。
顶层结论(源自审计时点):技能侧 50 个 catalog 条目、46 个磁盘条目,其中 18 个 KEEP-AS-IS、7 个 STREAMLINE、4 个 CONSOLIDATE、16 个 DEPRECATE、5 个 AMBIGUOUS;agent 侧 36 个(33 个在AGENT_DEFINITIONS),其中 23 个 KEEP-AS-IS、10 个 CONSOLIDATE、2 个 DEPRECATE、1 个 AMBIGUOUS。审计明确是"意见 + 证据,而非单边强制",任何删除都需 owner 逐个 PR 审查,且审计本身未改动任何生产表面。
发布验证流程与已知残余风险
UltraQA 与本地门禁
0.18.3 的验证记录在 docs/qa/release-readiness-0.18.3.md,使用的 UltraQA 规划产物包括.omx/context/release-0-18-3-after-ultraqa-20260525T040404Z.md、.omx/plans/prd-0.18.3-release.md、.omx/plans/test-spec-0.18.3-release.md、.omx/plans/release-0.18.3-ralplan-consensus.md与.omx/qa/ultraqa-release-0.18.3.md。
完成的本地门禁:
npm run lint:PASS(检查 665 个文件,无自动修复);npm run check:no-unused:PASS;npm run test:PASS(5335 passed、0 failed、1 skipped,catalog 检查通过);- 对抗性发布 harness:对畸形状态、prompt 注入文本、反复中断/取消措辞、有界挂起的子进程、误导性成功输出、无 tag 副作用守卫均 PASS;
- 项目原生 targeted 变更区测试:经
dist/scripts/run-test-files.js重跑两次,每次 1149 个测试、0 失败; npm pack --dry-run(metadata bump 前后各一次):最终产出oh-my-codex-0.18.3.tgz清单,包大小 3.6 MB、解包 21.8 MB、2910 个文件;- bump 后最终
npm run build/lint/check:no-unused/verify:native-agents/sync:plugin/verify:plugin-bundle/generate-catalog-docs.js --check/git diff --check全部 PASS。
已接受的残余风险
cargo test在crates/omx-explore/src/main.rs的run_command_with_timeout_kills_process_group_children断言失败:期望子进程 TERM trap 文件包含term,但断言窗口内为空。发布负责人明确指示本版本忽略该失败,记录在就绪文档中,并建议在下一次涉及 explore/process-tree 行为变更的版本前修复或隔离该断言(crates/omx-explore)。
发布纪律
- UltraQA 期间
git tag --points-at HEAD与git tag --list 'v0.18.3'均无本地 tag,未执行任何npm publish; - 剩余外部动作:提交 release prep、合并到发布分支、维护者批准后创建/推送
v0.18.3tag、验证 GitHub release 工作流产物与 npm 发布、发布后回填证据。
合并 PR 清单与总结
0.18.3 的合并 PR 清单:#2474、#2476、#2477、#2478、#2481、#2482、#2483、#2484、#2485、#2486、#2487、#2488、#2489、#2491、#2492、#2493、#2494、#2495。对应关系可从 docs/qa/release-readiness-0.18.3.md 的 Merged PR inventory 中逐一查阅(如 #2481 合并启动 HUD pane、#2489 回收 dead-leader HUD、#2485/#2486 保留 HUD session id 与 owner env、#2487/#2491 Team diff gutter、#2476/#2478 deep-interview 权限、#2482 deepInterview 运行时配置覆盖、#2494/#2495 explore 语法可见性等)。
总体而言,0.18.3 是一个典型的"可靠性补丁"版本:它不引入新的大功能面,而是把 HUD 生命周期、Team 输出渲染、deep-interview 权限、auth 旋转、插件所有权边界这些运维高频痛点在源码层面逐一钉死,并用一套可复现的 UltraQA 流程与对抗性 harness 保证回归安全。对运维者和插件开发者而言,本版本最值得关注的是三件事:HUD reconcile 的并发锁与 dead-leader 回收语义、[omx.deepInterview]配置的级联优先级与plan_then_execute权限门、以及插件 hook 与用户技能目录的所有权保护边界。
【免费下载链接】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),仅供参考