@wbline/pi-plan-build0.0.6
Plan/Build dual-mode for the Pi coding agent: read-only planning, explicit approval, step-wise execution.
Untested on omp
This is a pi package. No one has reported whether it works on omp yet. If you try it, add your result below.
Reports 0
No reports yet.
Readme
pi-plan-build
让 agent 先规划、经你审批、再动手。为 Pi coding agent 设计的 plan/build 双模式工作流扩展。
只读规划 → 显式审批 → 分步/整段实现 → 验证闭环。 规划期间 agent 改不了你的项目;审批之前没有实现;每一步的完成与验证都有据可查。
plan 模式(只读) 审批(三选一) build 模式
调研讨论 → 写计划文件 ──▶ plan_exit ──▶ 本会话 / 分步 / 留在 plan ──▶ 实现 → 验证 → plan_complete
▲ 守卫:只许写计划文件 ▲ 守卫:计划文件只读
快速开始
pi install npm:@wbline/pi-plan-build
零配置,装上即用。计划文件自动落在当前项目 .pi/agent/plans/(<创建时刻>-<标题>.md,随项目走)。30 秒体验完整闭环:
- Alt+M 切到 plan 模式:只读调研讨论,agent 的文件写入被守卫拦截
- 让 agent 规划:
plan_task new建计划(你未明确要求规划时,会先弹窗确认:创建计划还是直接执行)→ 写完整计划文件(含验证小节与实现步骤)→plan_exit提请审批 - 你三选一:本会话连续实现 / 分步实现 / 留在 plan——选择之前 agent 劫不了代码
- build 模式实现:计划文件受保护;分步模式默认每步等点头,说「剩下的都做完」可授权连跑
- 验证闭环:能自动验证的当场跑;只能你验证的(登录、硬件、线上效果)记为
awaiting_validation,你下一条消息时主动弹窗确认,通过才收尾
它解决什么问题
| 没有 plan-build | 有了 plan-build |
|---|---|
| agent 听完需求直接开改 | 规划期只读,写文件被守卫拦截 |
| "方案同意了"就等于开写 | 审批是显式的三选一,选择前零改动 |
| 计划与实现混在一个上下文里 | 双模式状态机,计划随会话持久化、可恢复 |
| "做完了"全靠 agent 自述 | 验证策略内置,必需的用户验证主动发问 |
核心机制
- 🔒 双模式权限守卫:
tool_call前拦截,路径归一化(@/~/相对路径)+ symlink 解析。plan 模式只许写计划文件,无路径或波及面无法验证(未知工具、语义重命名)一律阻断——宁可误拦不可放行 - 🏷️ 动态工具分类:不写死工具名单,按配置覆盖 > 注解(
readOnlyHint)> 方法后缀 > 动词约定(写动词优先)分类;新增 IDE 变更工具不再漏拦 - ⏱️ 时序硬闸:
plan_task生命周期转移未收尾时,依赖它的文件变更与生命周期工具一律先等——把"转移先于依赖动作"从提示词约束升级为硬拦截 - 🚪 全链路显式决策:
plan_task new先问「创建计划还是直接执行」(明确要求规划可传参跳过),plan_exit后问「本会话/分步/留下」;build 模式建计划、build 中途修订计划(plan_task revise)、plan 模式被守卫拦截时各有一道确认门——每次模式转换都由用户一键拍板 - 📒 事后对账:放行波及面无法验证的工具(IDE 终端命令、shell)前记录计划文件基线,回合结束时文件被改动即警告核对
- 🪜 分步执行:计划里的实现步骤逐个就绪,你说"继续"才开工,说「剩下的都做完」即授权连跑自动推进;侧栏实时显示
[待办]/[就绪]/[进行]/[完成]/[跳过]进度 - ✅ 验证闭环:
awaiting_validation结算后,在你下一条消息时确认一次「必需验证通过了吗?」,通过才收尾,否则计划保持开放——不会在你还没开始验证时就弹窗 - 🌐 中英双语提示词与工具描述:菜单一键切换;7 个工具全模式常驻(稳定工具目录),模式切换不抖动工具列表,prompt cache 持续命中
命令
| 命令 / 快捷键 | 说明 |
|---|---|
/plan-build |
交互菜单:切换模式 / 查看状态 / 标记完成 / 放弃计划(原因必填,文件保留)/ 语言切换 / 设置文件 |
/plan /build |
直切模式;IDE(ACP)桥接层按命令名调用,JetBrains AI 聊天的模式选择器依赖这两个命令 |
Alt+M |
直接切换模式;新会话默认模式由设置 defaultMode 决定 |
状态栏徽标(📋 plan / 🔨 build + 计划标题与进度)显示在底部;分步执行时步骤列表 widget 同步显示。
工具
| 工具 | 说明 |
|---|---|
plan_task |
任务生命周期:new 建计划(plan 模式)、revise 请求切回 plan 修订当前计划(弹窗确认,build 中途修计划的专用通道)、include 追加用户批准的范围、update 改名、exclude 记录排除、abandon、list/show。所有转移必须带 expectedAttached 做乐观并发(new 传 null,其余传当前 seq),不匹配即拒。new 内置入口询问:用户未明确要求规划(传 planningRequested: true 可跳过)时,先弹窗让用户选「创建计划 / 直接执行」,选直接执行即自动切 build、不建计划;build 模式调用 new 会先弹窗确认切到 plan。new 支持 fromFile 恢复既有计划文件(plans 目录内原地接管,外部文件复制并在原文件标记「已接管」;换会话后接着干);list 附带 plans 目录历史计划与归档结局 |
plan_exit |
plan 模式终点。要求计划文件已写盘,然后弹出审批:本会话连续实现 / 分步实现 / 留在 plan 模式。取消对话框 ≠ 主动留下(模型会向你询问意图);无交互 UI(print/json)时跳过审批门自动选本会话连续实现 |
plan_step_control |
分步执行:start 批准就绪步(advance: "all" 一次授权连跑剩余步骤,遇阻塞才停)、acknowledge 指认用户声明的已完成步(无需先 start)、skip、revise 修订未完成步(同步改文件)、pause/resume、cancel。一次只许一个转移 |
plan_step_complete |
完成当前进行中的步(摘要必填),立即生效不等待验收;最后一步完成即自动收尾整计划 |
plan_complete |
标记整计划完成——仅在全部工作与必需检查通过,或用户明确指示时。收尾时在计划文件文末写入状态块(> **状态:已完成**(日期) + 摘要),放弃同理(含原因),历史计划单看文件即可知结局 |
plan_set_outcome |
记录未完成结局并保持计划开放:awaiting_validation(必填精确的 userAction)/ blocked / waiting_for_input / still_working |
plan_question |
结构化选择题,收集决策;无交互 UI 时自动降级为文本提问 |
设置
~/.pi/agent/pi-plan-build.json,全部可省略:
| 字段 | 默认 | 说明 |
|---|---|---|
lang |
"zh" |
提示词语言:"zh" / "en" |
defaultMode |
"build" |
新会话默认模式(startup/new 生效;resume 尊重恢复出的状态) |
protectPlanFile |
true |
build 模式是否保护计划文件(关闭后对账一并停用) |
toolGuard |
— | 工具分类强制覆盖:{ "readonly": [], "mutating": [] },列出的工具名优先级最高 |
权限边界
守卫在 tool_call 前拦截,路径先归一化再做 symlink 解析,不存在的文件解析最远存在父目录:
- 管辖范围:只守卫 pi 内置工具与 JetBrains IDE 桥接工具(
ide_前缀)——内置 8 个全量显式分类(edit/write 变更、bash/powershell 执行面、read/find/grep/ls 只读),ide_*动态分类;其它扩展/MCP 工具不守卫(codemode 的嵌套调用走 pi 同一 tool_call 管线,仍受守卫约束) - plan 模式:文件变更通道(原生
edit/write与 IDE 桥接工具)只许目标为当前计划文件。IDE 工具动态分类不写死名单;无路径或波及面无法验证(未知变更工具、语义重命名)的调用一律阻断——宁可误拦不可放行;有 UI 时拦截会弹确认门,用户确认即切 build 放行本次修改,拒绝则本回合只拦不再问(回合结束重置) - 时序硬闸:最近一条 assistant 消息里
plan_task结构转移(new/revise/include/update/exclude/abandon 等非只读动作)未收尾时,文件变更与生命周期工具一律先等转移收尾(list/show只读动作不拦) - 事后对账:build 模式放行波及面无法验证的变更工具前记录计划文件内容基线,结算(agent_settled)时发现文件被改动即警告提示核对;bash/powershell 与 IDE 执行面工具改写计划文件同样纳入
- 模式边界:
plan_task new仅限 plan 模式(build 下创建的计划无法走 plan_exit 审批);分步执行进行中禁止切回 plan 模式(避免"只读 + 实现第 N 步"的矛盾注入);plan 模式且无计划时,new先弹窗询问「创建计划 / 直接执行」(用户明确要求规划可跳过),选直接执行自动切 build;build 模式调用new也会弹窗确认切到 plan(拒绝则保持 build);build 中途修订计划走plan_task revise(弹窗确认切回 plan)——所有模式转换都由用户拍板 - build 模式:已写盘的计划文件受保护(
protectPlanFile: false可关);修订计划调用plan_task revise(确认门切回 plan)或由用户 /plan;未列入的 IDE 变更工具同样过守卫(无法验证目标时放行) - bash/powershell 与 IDE 执行面工具不做分类沙箱:终端命令、运行配置、构建、SQL 执行、inspection KTS 的目标不可提取且能力与 shell 等价——plan 模式为提示词约束,build 模式放行并纳入事后对账;诚实标注而非冒充沙箱
- 扩展自身对计划文件的修订(步骤 revise、终态状态块)不经 tool_call 守卫(守卫只拦模型调用),但受同一状态机校验并在计划文件上留痕;终态归档 append-only,文件为空或写失败则静默跳过
设计取舍
- 集中状态机而非分散闭包:全部状态收敛为一个不可变
State(mode + plan + execution),唯一transition()入口,纯函数单测全覆盖。代价是新增行为必须先定义转移事件——换来任何状态变化都有唯一出处 - 原生 UI 而非接管 composer:只用
setStatus/setWidget/ui.custom/ui.select,不碰编辑器与消息栏——与任何其它扩展零冲突 - 砍掉干净会话交接:跨会话 transfer/reconcile 的多段状态机收益低、分支爆炸,不做。换会话后用
plan_task new fromFile恢复既有计划文件接着干(list可查历史计划与结局) - 宽容步骤解析:编号 / checkbox / 短横线都接受,重复步骤去重;解析失败不报错,而是返回一段模型可执行的修复指引
- 上下文锚定注入:计划块作为 user 消息插在最后一条真实用户消息之前,位置与内容稳定——前缀缓存持续命中
- 验证问询等下一条消息:
awaiting_validation结算后不在回合刚结束时弹窗(那时你还没验证),而在你下一次发消息时确认一次;未通过不自动重问,重新结算才重置——比误重问的选择框更安静 - 无 UI 跳过审批门:print/json 模式没有可交互的用户,入口询问与
plan_exit审批门一致跳过(后者自动选本会话连续实现)——不会出现"计划建了却永远拿不到实现授权"的死锁
开发
npm install # 安装开发依赖(含 pi 1.3.0 类型)
npm run check # biome + tsc 双检查
npm test # 26 个纯函数单测:状态机 / 步骤解析 / 路径守卫 / 持久化解码
npm run smoke # 装配冒烟:stub ExtensionAPI 走完整流程(注册、守卫、菜单、注入)
历史更新见 CHANGELOG.md(Keep a Changelog 格式,随版本发布维护)。
License
MIT