OmX 0.14.2 补丁发布解析:omx question 可靠渲染、MCP 重复进程自清理与 deep-interview 状态加固
本文以 OmX(Oh My codeX)0.14.2 补丁版发布说明为骨架,逐项剖析这次"快速跟进(fast-follow)"版本在问题渲染、MCP 生命周期、deep-interview 状态机、多语言输入路由与工具链基线上的可靠性修复。读者将理解 omx question 在 tmux 内外的 fail-closed 策略与共享提交语义、重复 MCP 兄弟进程的闲置自退出机制、会话级清空墓碑(tombstone)如何压制陈旧根状态,并掌握每个修复背后的源码级实现与可验证证据。
版本定位:0.14.1 之后的快速跟进补丁
0.14.2 是 0.14.1 之后的补丁版本(patch release),其发布说明(docs/release-notes-0.14.2.md)将本次迭代定性为聚焦"快速跟进操作员可靠性(fast-follow operator reliability)"的发布。补丁覆盖了六个彼此独立但都影响日常操作体验的问题域:
omx question渲染安全:在未附加(attached)的 tmux 窗格外运行omx question时,不再静默创建不可见的分离式 tmux 会话,而是直接向操作员返回清晰的错误;- MCP 重复进程治理:同一父进程下的旧 stdio 重复服务器(duplicate siblings)可在安全的流量空闲窗口后自行退出,遏制陈旧 MCP 服务器堆积;
- deep-interview 状态加固:会话级模式清空在必要时留下非活动会话墓碑,避免遗留根回退状态立即重新激活模式;失败的提问启动会清除挂起的 deep-interview 义务;
- 多语言输入路由:韩文 2-set 键盘下
ulw简写的 IME 漂移输入(ㅕㅣㅈ)能正确归一化后触发 ultrawork 简写; - 提交语义统一:
omx question答案注入复用与 reply-listener 一致的 tmux 窗格发送路径; - 工具链基线刷新:TypeScript 升级至
6.0.3,Biome 锁文件元数据刷新至2.4.12。
配套的发布就绪评估记录在 docs/qa/release-readiness-0.14.2.md,其中给出了完整的范围审查、代码审查证据与验证结果。
omx question 渲染策略与 fail-closed 修复
渲染策略矩阵
omx question 的渲染器启动逻辑集中在 src/question/renderer.ts,核心入口 resolveQuestionRendererStrategy(src/question/renderer.ts#L81-L105)根据环境信号选择渲染策略,共支持七种:
| 策略 | 触发条件 |
|---|---|
test-noop |
环境变量 OMX_QUESTION_TEST_RENDERER=noop(测试专用) |
windows-psmux-shell-pane |
Windows + TMUX 含 psmux 或存在 TMUX_PANE |
windows-console |
Windows 且存在显式提问返回窗格目标 |
inside-tmux |
存在 TMUX 环境变量、显式窗格目标或持久化返回目标 |
inline-tty |
Windows 下 stdin/stdout 均为 TTY |
detached-tmux |
历史上用于分离式 tmux 会话渲染 |
unsupported |
以上均不满足 |
fail-closed:不再静默创建分离渲染器
在 0.14.2 之前,当进程位于 tmux 之外且没有任何可见渲染器信号时,omx question 可能退化为创建分离式(detached)tmux 会话——用户在 Codex App 或非 tmux 终端里提问,渲染器却悄悄开在看不见的地方。0.14.2 改为 fail-closed:当策略判定为 unsupported 时,launchQuestionRenderer 直接抛出带有明确指引的错误(src/question/renderer.ts#L829-L833):
omx question cannot open a visible renderer because this process is outside an attached tmux pane and has no explicit tmux return bridge. Codex App/outside-tmux sessions need an attached tmux OMX CLI session or
OMX_QUESTION_RETURN_PANEbridge. Run omx question from inside tmux.
同时,inside-tmux 分支也新增了附加性检查:如果 TMUX 存在但当前 tmux 会话没有附加客户端(#{session_attached} 为 0),同样抛错并提示"从附加的 tmux 窗格运行"(src/question/renderer.ts#L867-L871)。回归测试证明该路径不会再创建 detached tmux 会话(见 src/question/tests/renderer.test.ts)。
渲染器的探测、销毁与存活保障
围绕渲染器还有一套完整的生命周期辅助:resolveAvailablePaneHeight/Width 通过 tmux display-message -p '#{pane_height}' 探测窗格尺寸(探测失败回退 80 列 / 40 行);estimateQuestionRenderFootprint 依据问题记录计算渲染足迹,配合 computeAdaptiveQuestionPaneHeight 与 shouldOpenQuestionInNewWindow 决定用 split-window -v -l 分窗还是 new-window 开新窗口;isLaunchedQuestionPaneAlive 用 #{pane_dead} 校验窗格存活,closeQuestionRenderer 负责 kill-pane/kill-session 回收。渲染器进程实际执行 omx question --ui --state-path <recordPath>(src/question/renderer.ts#L332-L346),问题记录以 JSON 形式落盘于状态目录下的 questions/ 子目录,记录格式要求 kind === 'omx.question/v1' 且携带 question_id。
共享 tmux 提交语义:buildSendPaneArgvs 统一答案注入
三处注入收敛为一条路径
0.14.2 修复了 omx question 答案提交与通知 reply-listener 窗格注入之间的漂移:injectQuestionAnswerToPane 与 injectQuestionAnswersToPane(src/question/renderer.ts#L694-L733)现在与 reply-listener 共用 src/notifications/tmux-detector.ts 中导出的 buildSendPaneArgvs。在此之前,提问渲染器与回复监听器各自维护一套 send-keys 参数构造逻辑,文本提交细节容易分叉。
提交语义的三条硬性规则
buildSendPaneArgvs(src/notifications/tmux-detector.ts#L89-L113)将注入语义收敛为三条可测试的硬性规则:
- 换行净化:文本中的
\r?\n一律替换为空格,防止换行在字面发送时被当作提交按键; - 字面发送防注入:使用
send-keys -t <pane> -l -- <text>,-l(literal)确保文本中的 tmux 键名不会被解释为按键,--防止以-开头的文本被解析为 tmux 标志——注释明确引用 issue #107 与 #156 的注入教训; - 隔离的 C-m 提交:
C-m(回车)始终单独成一次send-keys调用且发送两次(Codex CLI 使用 raw input mode,需要两次回车可靠提交),绝不与文本载荷捆绑,杜绝通过文本内嵌C-m触发提交的注入面。
sendToPane(src/notifications/tmux-detector.ts#L147-L173)在逐条执行这些 argv 时还引入时间节奏:首次发送后等待 TMUX_TEXT_SETTLE_MS(120ms),后续提交之间等待 TMUX_SUBMIT_REPEAT_DELAY_MS(100ms)。提问渲染器侧同样维持 QUESTION_TEXT_SETTLE_MS 与 QUESTION_SUBMIT_REPEAT_DELAY_MS 常量,保证文本送达与提交之间的节奏一致。
双层净化
在 buildSendPaneArgvs 的换行处理之上,还有一层 sanitizeReplyInput(src/notifications/reply-listener.ts#L337):它剥离控制字符、合并多余空白、对反引号与 $()、${} 做转义,防止文本被解释为 shell 展开。测试用例(src/notifications/tests/reply-listener.test.ts)覆盖了 NUL/ESC/换行/$(whoami)/${HOME} 等注入向量。注入到窗格的文本统一带 [omx question answered] 前缀(见 formatQuestionAnswerForInjection),使下游能识别答案来源。
MCP 重复兄弟进程:安全空闲后的自清理
问题背景
第一方 MCP 服务器(state、memory、code_intel、trace、wiki、hermes)以 stdio 方式按需自动启动。当同一父进程为同一入口点反复拉起新实例时,旧实例可能堆积——尤其是 Codex App 这类长期存活父进程跨会话复用场景。0.14.2 在 src/mcp/bootstrap.ts 中把重复兄弟清理从"仅限未处理流量的早期退出"扩展为"可在安全的后流量空闲窗口自退出"。
判定与退出逻辑
analyzeDuplicateSiblingState(src/mcp/bootstrap.ts#L222-L290)通过 ps axww -o pid=,ppid=,command=(Windows 下走 PowerShell Get-CimInstance Win32_Process)读取进程表,按 ppid(同父)+ 入口点标记(extractMcpEntrypointMarker 匹配 *-server.js 或 mcp-serve <target>)分组,将当前进程归类为 ambiguous / unique / newest / older_duplicate——PID 较大的更新兄弟存活,旧兄弟被标记为重复。随后的退出判定由三个守卫组成:
- 流量前宽限:
shouldSelfExitForDuplicateSibling在无流量时要求重复状态持续超过duplicateSiblingPreTrafficGraceMs(默认 2000ms)才退出; - 流量后空闲:一旦收到过 stdin 字节(意味着客户端已初始化该传输),要求"自重复观察与最近流量二者中较晚时刻起"空闲满
duplicateSiblingPostTrafficIdleMs(默认 60000ms)才退出——这是 0.14.2 新增的关键路径; - 硬上限:
shouldSelfExitForPreTrafficSiblingHardCap/shouldSelfExitForPostTrafficSiblingHardCap在同入口点兄弟数超过OMX_MCP_MAX_SIBLINGS_PER_ENTRYPOINT(默认 4)时,仅淘汰最旧的、且(流量后场景)已被取代满整个空闲窗口的实例。
可调时序与观测
整个生命周期时序均可通过环境变量覆盖(src/mcp/bootstrap.ts#L19-L32):
| 环境变量 | 默认值 | 含义 |
|---|---|---|
OMX_MCP_PARENT_WATCHDOG_INTERVAL_MS |
1000 | 父进程存活探测间隔 |
OMX_MCP_DUPLICATE_SIBLING_WATCHDOG_INTERVAL_MS |
5000 | 重复兄弟看门狗扫描间隔 |
OMX_MCP_DUPLICATE_SIBLING_PRE_TRAFFIC_GRACE_MS |
2000 | 流量前重复宽限期 |
OMX_MCP_DUPLICATE_SIBLING_POST_TRAFFIC_IDLE_MS |
60000 | 流量后空闲退出窗口 |
OMX_MCP_DUPLICATE_SIBLING_INITIAL_DELAY_MS |
未设置(自动抖动) | 初始延迟固定值 |
OMX_MCP_DUPLICATE_SIBLING_INITIAL_DELAY_MAX_MS |
1000 | 初始延迟抖动上限(按入口点哈希) |
OMX_MCP_MAX_SIBLINGS_PER_ENTRYPOINT |
4 | 每入口点保留的兄弟数上限 |
OMX_MCP_ENTRYPOINT_MARKER |
— | 显式入口点标记 |
OMX_MCP_TRANSPORT_DEBUG |
关闭 | 开启后输出生命周期调试日志 |
初始延迟通过 stableStringHash(server:entrypoint) % (maxMs + 1) 做确定性抖动,避免多服务器同时启动时扫描撞车;duplicateObservedAtMs 与 lastTrafficAtMs 两个时间戳驱动全部闲置判定。生命周期事件(bootstrap_start、duplicate_sibling_observed、shutdown 等)会写入 lifecycle-telemetry,退出原因包括 superseded_duplicate_after_idle、superseded_duplicate_before_traffic、superseded_hard_cap_pre_traffic、superseded_hard_cap_post_traffic 等,便于事后归因。回归测试(src/mcp/tests/bootstrap.test.ts、src/mcp/tests/server-lifecycle.test.ts)验证了"旧重复在流量后空闲退出、最新兄弟存活"的行为。
deep-interview 状态机加固:墓碑与义务清理
会话级清空墓碑
deep-interview 状态按会话作用域(session-scoped)管理,但历史版本存在根级回退状态(root fallback state)。0.14.2 修复了一个棘手的复活问题:当会话级模式被清空、但根目录还残留旧状态文件时,遗留的根回退状态可能让已清空的模式"立即重新激活"。修复方式是:会话级清空在发现存在遗留根回退文件时,写入一个非活动的 current_phase: "cleared" 墓碑,压制根状态回退(实现涉及 src/state/operations.ts 与 src/mcp/state-server.ts)。测试(src/state/tests/operations.test.ts、src/mcp/tests/state-server.test.ts、src/cli/tests/session-scoped-runtime.test.ts)验证了 CLI、MCP、status/read 三个界面下"已清空的会话作用域保持非活动(deep-interview: inactive (phase: cleared))"。
失败提问清理挂起义务
deep-interview 在提问时会向 Autopilot 状态写入挂起义务(pending obligation,包含 obligation_id、question_id、状态等字段)。若提问启动失败,此前义务可能残留,导致后续会话被陈旧的门禁卡住。0.14.2 确保:一旦提问渲染器启动失败,立即清除挂起义务。对应测试(src/question/tests/deep-interview.test.ts#L140-L193)覆盖了"提问失败后清理挂起义务"与"渲染器启动失败后清理挂起义务"两个场景,另有测试验证"提问返回后满足义务"与"从已答复记录调和义务"的完整生命周期。
后台提问终端的指引闭环
0.14.2 同时补齐了指引层面的缺口:skills/deep-interview/SKILL.md、templates/AGENTS.md 与 src/scripts/codex-native-hook.ts 中现在明确要求 Agent 等待后台 omx question 终端执行完毕、读取 JSON 答案后再继续访谈;关键字路由也避免仅凭"cleanup / state-management"等措辞触发 deep-interview 激活(回归用例见 src/hooks/tests/keyword-detector.test.ts,如 cleanup stale deep-interview state after session clear 不触发)。这一改动同时服务于"显式终端停止模型":访谈是阻塞性门禁,必须有明确的完成信号。
多语言输入路由:韩文 IME 漂移与 ulw 简写
0.14.2 的发布说明记载:韩文 2-set 键盘下用户输入 ㅕㅣㅈ(ulw 的 IME 漂移形态)时,关键字检测会在激活前将其归一化为既有的 ulw ultrawork 简写。当时的实现位于 src/hooks/keyword-detector.ts 的 normalizeWorkflowKeyboardTypos。
需要说明的是:从当前仓库源码看,该归一化函数已变为 no-op(src/hooks/keyword-detector.ts#L1294-L1304),注释解释其原因——ulw 唯一的目标是 ultrawork 技能,而 ultrawork 如今是已下线的 sunset 技能(不再有触发入口),继续把漂移输入映射到一个已移除的技能没有意义;函数缝(seam)被保留,以便未来新增活跃简写时可以有意识地接入而非复活对已移除技能的映射。对应的回归测试(src/hooks/tests/keyword-detector.test.ts)也验证了 ㅕㅣㅈ로 이 작업 처리해줘 与 $ㅕㅣㅈ로 이 작업 처리해줘 在当前不再路由到任何技能。这一演进恰好体现了 OmX 关键字路由的一个设计原则:归一化映射的生命周期必须跟随目标技能的生命周期,避免把用户输入导向已不存在的入口。
工具链基线刷新
0.14.2 同步刷新了开发工具链基线:
- TypeScript
6.0.3:package.json与package-lock.json对齐; - Biome
2.4.12:锁文件元数据刷新; - tsconfig.json:为 TS 6 构建路径显式固定 Node 环境类型(ambient types)。
配套的发布元数据(Cargo.toml、Cargo.lock、CHANGELOG.md、RELEASE_BODY.md、本发布说明)同步对齐到 0.14.2。
验证证据与剩余风险
发布门禁
0.14.2 的发布验证证据记录在 docs/qa/release-readiness-0.14.2.md:
| 检查项 | 结果 |
|---|---|
npm run lint |
✅ |
npm test |
✅ |
cargo test -p omx-explore-harness -p omx-sparkshell |
✅ |
npm pack --dry-run |
✅ |
$code-review(v0.14.1..dev 范围) |
code-reviewer COMMENT、architect WATCH,无阻塞性发现 |
已知的非阻塞风险
发布说明与就绪报告共同列出了四项 architect 关注的后续清理项(均不阻塞发布):
- 已清空会话墓碑辅助逻辑在 CLI 与 MCP 两条状态路径中重复(
operations.ts与state-server.ts各有一份); - 分离式提问渲染器代码作为遗留分支保留,但正常策略解析不再选择它(
resolveQuestionRendererStrategy已不会返回detached-tmux); - MCP 重复清理仍依赖保守的进程/时序启发式(同父、进程年龄、流量空闲窗口),而非更确定的协调协议;
- deep-interview 指引文案在多个发布面(技能、模板、原生钩子)重复维护。
此外,本次就绪评估是本地发布通道(local release-readiness pass),并非完整 CI 矩阵重跑;发布后最有价值的观测面仍是真实 tmux / 复用会话下的 omx question、提示词提交、工作流/状态清空、MCP 重复兄弟清理,以及多语言输入触发工作流的实机行为。
小结
0.14.2 是一次典型的"补丁含金量"示范:六个独立的可靠性修复各自都有明确的源码落点与回归测试兜底——omx question 的 fail-closed 策略(src/question/renderer.ts)、共享提交语义 buildSendPaneArgvs(src/notifications/tmux-detector.ts)、MCP 重复兄弟闲置自退出(src/mcp/bootstrap.ts)、deep-interview 墓碑与义务清理(src/state/operations.ts)、关键字归一化的生命周期纪律(src/hooks/keyword-detector.ts),外加工具链基线刷新。对于 OmX 使用者,0.14.2 意味着:提问界面不再"凭空消失"、陈旧 MCP 进程不会无限堆积、已清空的 deep-interview 不会被根状态悄悄复活、失败提问不会留下卡住后续会话的义务残留——每一项都是把"操作员可靠性"落到实处的具体工程改进。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0631
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
video-shotcraftAI宣传片skill,使用 Remotion 制作电影级产品视频:提供106 张镜头配方卡和可复用的视频魔板。适用于 Claude Code 与 Codex以及所有其他智能体Markdown00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python09
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00