fix(ask): 文字作答时在 stderr 提示答案去向,消除静默的空 stdout#435
Open
lRoccoon wants to merge 1 commit into
Open
Conversation
用户在话题里打字作答(而非点选按钮)时,broker 走 submitCustomReply settle 成 `answers` 各问为空数组、`comment` 携带原文。此时 toLegacySelected 按设计返回 null,非 JSON 模式的 stdout 落到空字符串, exit code 仍为 0。 问题在于这个空字符串与「多选/多问」的降级空值完全一致,stderr 也没有 任何线索:调用方无法区分「用户其实作答了、原文在 comment 里」和「用户 选了多项所以拿不到单一 key」,shell 分支会静默走进兜底。ask 的存在意义 是把决策引到人,stdout 是它唯一的契约面,这个静默降级正好落在契约上。 comment 可能含换行(用户可以发多行消息),直接回落进 stdout 会撕碎 「一行一个 option key」的约定,因此不改 stdout。本提交只: - core/ask-types.ts 新增纯函数 isCustomReply(),与既有 toLegacySelected 同款风格,判定「无任何选中项 + comment 非 null」 - cli.ts 的 cmdAsk 在该分支多打一行 stderr,指明用 `--json` 读 comment - ask-types-shape.test.ts 补 5 条用例覆盖文字作答/多问未选/按钮路径/ 带附注的按钮路径/非 answered 结果 stdout 与 exit code 零变更,现有脚本不受影响。 影响面:新增函数无调用方副作用;仅 cmdAsk 非 JSON 分支多一行 stderr。 不触及 CLI adapter、backend、IM 层;ask-hook/* 的 formatAnswer 回落路径 未改动。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #434
改了什么
用户在话题里打字作答(而非点选按钮)时,
botmux ask(非--json)的 stdout 落到空字符串、exit code 为 0、stderr 一片安静,与「多选/多问」的降级空值无法区分。调用方既不知道用户其实已作答,也不知道原文在comment里,shell 分支会静默走进兜底。本 PR 不改 stdout、不改 exit code,只在检测到文字作答时往 stderr 打一行提示:
src/core/ask-types.ts— 新增纯函数isCustomReply(),与既有toLegacySelected同款风格,判定「各问均无选中项 +comment非 null」src/cli.ts—cmdAsk的非 JSON 分支调用它,console.error指明用--json读comment取回原文test/ask-types-shape.test.ts— 补 5 条用例为什么这么改
三点前提先确认清楚,避免改错地方:
daemon.ts注释:「待回答 ask 会把它当答案吞掉」),不该动。submitCustomReply让answers各问为空数组、toLegacySelected因此返回null,同样是设计,test/ask-types-shape.test.ts已有用例锁定。ask-types.ts注释写明 comment 回落是 hook adapterformatAnswer的职责,不是cmdAsk的。所以真正的缺口只在可观测性:
answered+ 空 stdout + exit 0 + 静默 stderr,让文字作答成为一个不可观测的降级。为什么不把 comment 回落进 stdout:
comment可以是多行的(实测回复含换行与空行),而ask的 stdout 约定是「一行一个 option key」,供$(...)与字符串比较使用。灌进去会撕碎该约定,且失败得比现状更隐蔽。故只走 stderr。影响面
isCustomReply()为新增导出,无既有调用方,无副作用cmdAsk仅在文字作答分支多一行 stderr;stdout 与 exit code 零变更,现有脚本不受影响ask-hook/*的formatAnswer回落路径未改动--json输出结构不变实际测试验证
全部 ask 相关测试文件(
ask-types-shape/ask-args/ask-broker/ask-api/ask-card/ask-hook-claude/ask-hook-codex/ask-hook-opencode/cmd-hook):全量单测回归对比(本机
node-pty的 gyp 编译失败,需pnpm install --ignore-scripts,故有一批与本改动无关的预存失败;用git stash做了基线对照):失败数完全一致,通过数 +5,正是本 PR 新增的 5 条用例。
未做 live daemon 验证:本机
node-pty编译不过,且pnpm switch:here会抢占全局botmux指向(当前会话本身跑在 botmux 上)。鉴于改动只新增一行 stderr、stdout 与 exit code 零变更,判断单测 + typecheck 已足够覆盖。真实载荷则来自线上实测——{"selected":null,"answers":[[]],"comment":"我发个多行消息试试\n这是第二行\n\n这是第四行","timedOut":false},测试用例直接采用了这条真实数据的形状。顺带一提
ask命令在文档站 14 页与CONTRIBUTING.md的 agent-facing 子命令表里均无记载,使用者无从得知--json是取回 custom reply 的唯一途径。如果需要,我可以另开一个纯文档 PR 补上。