<!-- codsh-publication:grok-cli-dsh-rewrite:ticket-47 --> ## Parent https://github.com/Blackman99/codsh/issues/132 **Ticket:** 47 **Status:** ready-for-agent **User Stories:** 22, 50(见父规格) ## What to build 用户进入计划模式、回答单选/多选/自由输入问题,审阅计划后明确批准执行,并持续查看待办。 ## Acceptance criteria - [ ] 问答只消费本次用户决策,不偷用 Queue 内容;退回编辑、取消和未回答状态明确。 - [ ] 计划模式的能力限制、计划文件允许范围、审阅/要求修改/执行入口符合参考,不能提前实现计划。 - [ ] 空计划、失败、重启和重复批准不会误启动两次工作,待办展示来自实际状态。 - [ ] 在两种终端模式与非交互入口验证需要用户决策的行为,并同步文档及 Changeset。 ## Blocked by - #142 — Ticket 10: 权限模式与持久规则 - #151 — Ticket 19: 排队、运行中干预与旁路提问 - #153 — Ticket 21: 完整内容、工具卡与差异阅读 ## Delivery contract 用户于2026-09-20批准当前测试与任务拆分。按父规格的已安装产物/真实终端和公开协议测试验收;实际实现须带适用的文档、Changeset及必要检查。ready-for-agent表示任务已定义,不表示前置任务已完成,也不授权自动开始本轮实施、购买付费资源或发布软件版本。
Activity
feat(rust): plan mode, question card, and todos through dsh (#179)
Blackman99 commentedon Sep 25, 2026
Ticket 47 / #179 已合入
rewrite/grok-dsh-20260920的452a09d。这次是快进推送(7b96914..452a09d),没有强推。提交已 rebase 到 #174(7b96914,工作树)之上。冲突出现在rust.mjs的环境变量白名单、main.rs(Launch 字段、延后参数列表、帮助文本)、editor_acp.rs、prompt_edit.rs、rust-acp-file-approval.mjs和文档,两边的改动都保留了。计划模式、问答与待办的状态都由 dsh 维护:
ctx.planMode管理,状态写入会话日志。exit_plan_mode通过ctx.userQuestions发起评审。ask_user_question使用 dsh 的dsh-tool-ask-user。todo_write维护。客户端只负责显示 dsh 的提问,并把答案送回。
rust-acp-plan.mjs:enter_plan_mode:通过普通审批提示请求进入,拒绝时返回 "User declined to enter plan mode."。$GROK_HOME/sessions/<编码后的 cwd>/<会话 id>/plan.md。exit_plan_mode会把计划保存到这里。调用中没有#计划时从磁盘读回;两处都没有计划时,仍会打开空评审。--yolo下也一样。实现是前置 pre-execute 拒绝加单调 guard。计划文件的编辑免确认,但 Hook 和 deny 规则仍然优先。--no-plan/--no-ask-user会移除对应工具。--todo-gate:回合结束时如果还有待处理或进行中的待办,把模型送回继续,每个提示最多两次。rust-acp-interaction.mjs:作为user-questions/request的应答方。CODSH_INTERACTION=tui)下,问题通过控制 socket 发给客户端,等待卡片的结果:回答、放弃(Shift+X)、评审中按q、超时或取消。迟到的回答会作为 stale 被拒绝。agent stdio),提问返回参考实现的 no-operator 文本,计划评审自动批准。plan_state和todos随会话事件推送给客户端。/plan、/plan <任务>(进入计划模式后再发送任务)、/plan off、/view-plan(别名/show-plan、/plan-view)。requirements.toml锁定关闭始终批准时跳过这一档。plan开头。a批准(评论作为下一条消息附上)s在输入框中提出修改c对一行或 Shift+方向键选中的范围评论y复制,q放弃计划[]切换问题z输入自定义答案,Space 切换多选项y复制,Ctrl+F 展开features.ask_user_question/GROK_ASK_USER_QUESTION,以及toolset.ask_user_question.timeout_enabled/timeout_secs(默认开启,1800 秒;对应环境变量GROK_ASK_USER_QUESTION_TIMEOUT_ENABLED/_SECS)。inspect会显示这三项及其来源。.changeset/rust-plan-questions-todos.md(patch)。验证(Linux x86_64,Node 22,干净环境
env -i,rebase 后的最终树):pnpm typecheck:通过。pnpm test:88 个文件,2364 通过、1 失败。失败的是已知的reference-evidence.spec.mjs"drives interactive help":高负载下超过默认 5s 超时。单独用--testTimeout=60000跑,11/11 通过,和本改动无关。新增
scripts/rust-plan.spec.mjs:13/13 通过,其中 7 个单元测试、6 个用例使用真实 dsh + overlay + 无密钥 mock(interaction模式),测试扮演客户端一端的控制 socket。覆盖:--no-plan/--no-ask-user移除工具--todo-gate最多触发 2 次plan_setenter_plan_mode的批准和拒绝session/resume后计划模式保留scripts/rust-control.spec.mjs已更新(9/9)。新增
scripts/rust-plan-pty-test.py(已提交,Linux/macOS 均可运行),在这台 Linux 机器的干净环境中通过,全部项为 true。它驱动真实 Rust 客户端:/plan与状态标记、计划闸门、评审按a、/view-plan、卡片数字选择提交、待办面板与 Ctrl+T、Shift+Tab 三档循环、enter_plan_mode审批q放弃、多选加输入答案--no-ask-user --no-plan、--todo-gate同时在 Linux 上重跑了
rust-worktree-pty-test.py、rust-subagent-pty-test.py、rust-queue-pty-test.py,均通过。cargo fmt --check:通过。cargo clippy -D warnings:失败,原因只有filesystem_sandbox.rs里已有的两处问题(tail_marker未使用、多余的return)。加-A dead_code -A clippy::needless_return后全部通过,本改动的代码没有警告。cargo test --locked --workspace --no-fail-fast:522 + 498 + 42 + 61 + 2 + 379 通过,4 个失败,都是已有问题:filesystem_sandbox的strict_requests_network_isolation...和trusted_project_custom_applies...privacy::drafts_stay_local...和voice::substitute_route...新增的 interaction、control 以及 main 胶水层单测全部通过。
未验证:
scripts/rust-*-pty-test.py(例如rust-permission-pty-test.py,在 Linux 上直接退出并提示 "macOS PTY evidence required")和已安装产物(installed-artifact)脚本:没有在这台 Linux 机器上运行。rust.mjs解析dsh-tool-ask-user的路径未验证。它沿用 lsp 的../../../node_modules方式,找不到时该工具不会出现。test:e2e,真实编辑器或图形界面,付费模型。评审的s/c键只有 Rust 单测覆盖,没有 PTY 覆盖。与参考实现的差异,以及需要确认的决定:
slug-hash16。这里的哈希是 SHA-256,参考实现是 BLAKE3,已在文档中写明。未触碰 main、npm 发布、默认版本和 PR #213。
现在可以开始的后续工作:#180(目标执行与停止条件)、#195(Ship 可选安装与首阶段接入)。