Skip to content

[Grok/dsh 47] 计划、问答与待办状态 #179

Closed

Description

@Blackman99

Parent

#132

Ticket: 47

Status: ready-for-agent

User Stories: 22, 50(见父规格)

What to build

用户进入计划模式、回答单选/多选/自由输入问题,审阅计划后明确批准执行,并持续查看待办。

Acceptance criteria

  • 问答只消费本次用户决策,不偷用 Queue 内容;退回编辑、取消和未回答状态明确。
  • 计划模式的能力限制、计划文件允许范围、审阅/要求修改/执行入口符合参考,不能提前实现计划。
  • 空计划、失败、重启和重复批准不会误启动两次工作,待办展示来自实际状态。
  • 在两种终端模式与非交互入口验证需要用户决策的行为,并同步文档及 Changeset。

Blocked by

Delivery contract

用户于2026-09-20批准当前测试与任务拆分。按父规格的已安装产物/真实终端和公开协议测试验收;实际实现须带适用的文档、Changeset及必要检查。ready-for-agent表示任务已定义,不表示前置任务已完成,也不授权自动开始本轮实施、购买付费资源或发布软件版本。

Activity

  1. Blackman99 commented on Sep 25, 2026

    @Blackman99
    OwnerAuthor

    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 的提问,并把答案送回。

    • dsh 插件 rust-acp-plan.mjs:
      • enter_plan_mode:通过普通审批提示请求进入,拒绝时返回 "User declined to enter plan mode."。
      • 计划文件:$GROK_HOME/sessions/<编码后的 cwd>/<会话 id>/plan.md。
        • exit_plan_mode 会把计划保存到这里。调用中没有 # 计划时从磁盘读回;两处都没有计划时,仍会打开空评审。
      • 计划闸门:计划模式开启时,除计划文件外的所有编辑都在执行前被拒绝,在 always-approve / --yolo 下也一样。实现是前置 pre-execute 拒绝加单调 guard。计划文件的编辑免确认,但 Hook 和 deny 规则仍然优先。
        • 与参考实现一致:不检查 bash,不覆盖子代理。
      • --no-plan / --no-ask-user 会移除对应工具。
      • 隐藏参数 --todo-gate:回合结束时如果还有待处理或进行中的待办,把模型送回继续,每个提示最多两次。
    • rust-acp-interaction.mjs:作为 user-questions/request 的应答方。
      • TUI(CODSH_INTERACTION=tui)下,问题通过控制 socket 发给客户端,等待卡片的结果:回答、放弃(Shift+X)、评审中按 q、超时或取消。迟到的回答会作为 stale 被拒绝。
      • 没有终端时(plain 和编辑器 agent stdio),提问返回参考实现的 no-operator 文本,计划评审自动批准。
      • plan_state 和 todos 随会话事件推送给客户端。
    • Rust 客户端:
      • 命令:/plan、/plan <任务>(进入计划模式后再发送任务)、/plan off、/view-plan(别名 /show-plan、/plan-view)。
      • Shift+Tab 循环:普通 → 计划 → 始终批准 → 普通。requirements.toml 锁定关闭始终批准时跳过这一档。
      • 计划模式开启时,状态行以 plan 开头。
      • 计划评审:
        • a 批准(评论作为下一条消息附上)
        • s 在输入框中提出修改
        • c 对一行或 Shift+方向键选中的范围评论
        • y 复制,q 放弃计划
        • Tab 在预览和输入框之间切换
        • 输入框里完整的斜杠命令会作为命令执行
        • minimal 模式把计划打印到滚动历史,并保留一个提示条
      • 问题卡片:
        • ↑↓ / jk 移动,Tab 循环,←→ / hl / [ ] 切换问题
        • 1–9 然后 a–f 选择,z 输入自定义答案,Space 切换多选项
        • Esc 先取消选择,再把焦点停到滚动区
        • y 复制,Ctrl+F 展开
        • 待处理的权限审批优先于卡片
      • 待办面板,Ctrl+T 隐藏。
    • 配置: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 会显示这三项及其来源。
    • 文档(README 中英文、CONTEXT、CONTRIBUTING、packages/cli/README)已更新。变更集是 .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。覆盖:

      • headless 下的 no-operator 回答
      • --no-plan / --no-ask-user 移除工具
      • --todo-gate 最多触发 2 次
      • plan_set
      • always-approve 和 ask 两种模式下的计划闸门(其他文件不会被写出)
      • 计划文件免确认写入
      • 评审的批准(带评论)和放弃
      • 空计划评审
      • 单选和多选(含自定义答案)
      • 超时,以及随后迟到回答被拒为 stale
      • enter_plan_mode 的批准和拒绝
      • session/resume 后计划模式保留

      scripts/rust-control.spec.mjs 已更新(9/9)。

    • 新增 scripts/rust-plan-pty-test.py(已提交,Linux/macOS 均可运行),在这台 Linux 机器的干净环境中通过,全部项为 true。它驱动真实 Rust 客户端:

      • fullscreen:/plan 与状态标记、计划闸门、评审按 a、/view-plan、卡片数字选择提交、待办面板与 Ctrl+T、Shift+Tab 三档循环、enter_plan_mode 审批
      • minimal:计划打印到滚动历史、评审按 q 放弃、多选加输入答案
      • headless:no-operator、--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 胶水层单测全部通过。

    未验证:

    • macOS 专用的 scripts/rust-*-pty-test.py(例如 rust-permission-pty-test.py,在 Linux 上直接退出并提示 "macOS PTY evidence required")和已安装产物(installed-artifact)脚本:没有在这台 Linux 机器上运行。
    • 已安装 npm 包中 rust.mjs 解析 dsh-tool-ask-user 的路径未验证。它沿用 lsp 的 ../../../node_modules 方式,找不到时该工具不会出现。
    • macOS、Windows,test:e2e,真实编辑器或图形界面,付费模型。评审的 s / c 键只有 Rust 单测覆盖,没有 PTY 覆盖。

    与参考实现的差异,以及需要确认的决定:

    • 编码后超过 255 字节的 cwd 目录名使用 slug-hash16。这里的哈希是 SHA-256,参考实现是 BLAKE3,已在文档中写明。
    • 编辑器 ACP 会话没有问题卡片:提问返回 no-operator,计划评审自动批准。
    • 批准时附带的评论,是在批准之后作为同一回合的下一条用户消息(steer)发送的。

    未触碰 main、npm 发布、默认版本和 PR #213。
    现在可以开始的后续工作:#180(目标执行与停止条件)、#195(Ship 可选安装与首阶段接入)。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions