【免费下载链接】plannotatorAnnotate and review coding agent plans and code diffs visually, share with your team, send feedback to agents with one click.项目地址https://gitcode.com/gh_mirrors/pl/plannotator点击查看免费下载导读本文基于仓库 ADR 记录 006-guided-review-first-class-feature及其配套的 Spec、Synthesis 与 Recap深入讲解 Plannotator 如何把Guided Review引导式评审建设为代码评审应用的一等公民功能由 Agent 将一次变更集PR 或本地 diff按核心实现在前、连锁后果其次、胶水代码收尾的语义顺序组织成章节化导览每个章节用散文解释为什么改并配以真实、可标注的 diff 切片。读完本文你将掌握该功能的完整数据模型、Agent 生成管线Claude/Codex/标记类引擎三路接入、服务端 fail-closed 校验策略、客户端屏幕接管式呈现以及它如何在不复制一行代码的前提下复用既有标注系统保证引导视图里的标注与普通 diff 视图里的标注完全同源。一、背景大型变更集为什么逐文件审阅会失败ADR 006 的 Context 部分明确点出了这个功能的出发点大型变更集large changeset很难按文件逐个审阅。文件树按路径排序而一次真实的工作通常横跨多个文件、遵循先核心后外围的推理顺序按路径顺序读下来审阅者很难在短时间内建立起这一大坨改动里什么才是关键部分的认知。Linear 的 Guidesbeta展示了更好的形态由 Agent 把 diff 拆分成章节章节顺序按照工作被推理出来的方式排列——核心实现第一、连锁后果其次、胶水代码和低信号改动单独分离每个章节把这个变更为什么存在的散文解释与相关 diff 并排呈现。而 Plannotator 当时已经具备了这个功能所需的几乎所有基础设施ADR 原文逐一点名agent-jobs 引擎可派生 CLI 提供者spawned CLI providers、SSE 状态/日志流式传输、结构化输出解析Code Tour 提供者作为受 schema 约束的叙事性输出的先例共享的 agent 评审提示词机器agent-review-message.ts能描述任意 diff 模式PR 或本地Pierre 系 diff 渲染FileDiff与虚拟化的CodeView统一的标注系统useAnnotationToolbar→CodeAnnotation→/api/feedback且已经支持来自多个表面的标注。结论是不需要新建子系统只需要新增一个 job provider、一个输出 schema、一个数据模型、一个接管式界面以及组合既有部件这一点在后续的 Synthesis 中被称为scope calibration 成立。二、决策内容Guided Review 成为一等公民功能ADR 006 的 Decision 由六条构成直接定义了功能的产品形态与工程边界Guide 的形态guide 是一组有序的页面section章节。每个页面包含标题、位置指示器如 01 / 04、一个勾选后可将页面折叠的Reviewed复选框、一段散文式概览这个变更是什么、为什么存在以及一个或多个 diff 区段——它们是同一份底层评审补丁的真实渲染切片。一个页面可以只挂一个 diff也可以挂多个。适用于任意变更集guide 既为 PR 生成也为本地 diffsince-base、未提交改动等生成。guide 标题在有 PR 时取自 PR否则从变更本身推导。生成是一个 agent jobguide 由派生的 Agent 通过既有 agent-jobs 基建产出——相同的启动路径、相同的 engine/model/effort 设置useAgentSettings、相同的 SSE 生命周期。结构上遵循 Code Tour 提供者基于当前 diff 上下文、经由共享提示词机器生成受 schema 约束的结构化输出。呈现方式是屏幕接管screen takeover而非对话框或停靠面板入口是左上角头部、文件树开关旁边的 Guide 徽章。点击后主工作区被替换文件树与中央 dock 隐藏右侧边栏可以保留。整个屏幕是一张干净、优雅、Notion 风格的页面。尚无 guide 时展示空态——Start a guided review?——带启动控件与首次使用的模型默认值与 agent job 使用的同一套设置。标注一致性annotation parity是硬约束guide 页面内的 diff 与普通 diff 视图使用完全相同的组件与状态——同一套工具栏/弹出层/建议机制、App.tsx中同一个CodeAnnotation列表、同一份 feedback 导出。原则是复用而不是复制Reuse, not copies。在 guide 里做的标注与在 diff 视图里做的标注无法区分并汇入同一个 Send Feedback 载荷。范围校准预期复杂度与 agent-jobs 部分相当而非一个新子系统。ADR 同时明确列出有意推迟的三件事留给 spec/规划阶段解决不改变本决策guide 超越服务器内存的持久化Tour 只驻内存guide 可能需要持久化单活跃 guide还是每会话多 guideguide diff 切片回真实补丁的锚定粒度文件级 vs hunk 级。后文可见Spec 与 Synthesis 分别给出了这些问题的 v1 答案内存 Map reviewed PUT 端点、最新完成 job 作为活跃 guide、文件级锚定lineStart/lineEnd仅作高亮提示而非切片边界。三、Guide 数据模型章节、概览与真实文件引用Guide 的数据模型定义在 packages/shared/guide.ts类型实际由 packages/core/guide.ts 导出shared 包做 re-export并随 Pi 扩展的 vendor 流程同步。核心三型interface GuideDiffRef { file: string; // 仓库相对路径必须匹配某个 DiffFile.path summary?: string; // 该文件本次改动的 1-2 句语义描述可选标记类引擎可省略 } interface GuideSection { title: string; // 概念级标题如 Payment Localization Module禁止文件名式转述 overview: string; // Markdown 散文这是什么、为什么存在、关键影响 diffs: GuideDiffRef[]; // 1..n 个文件引用 } interface CodeGuideOutput { title: string; // 有 PR 时取 PR 标题否则从变更推导 intent: string; // 标题下的 1-2 句引导语为什么存在这次变更 sections: GuideSection[]; // 有序核心在前、支撑在后 unplacedFiles?: string[]; // 模型未安置的变更文件渲染为末尾 Everything else 章节 } type CodeGuideData CodeGuideOutput { reviewed: boolean[] }; // 服务端输出 每节审阅状态值得注意的设计细节源码注释中均有说明模型不携带 diff 正文。GuideDiffRef只引用file路径真正的补丁内容由客户端从当前files数组按路径解析。Spec 中明确这是对 Tour 的刻意偏离Tour 锚定的是模型编造的hunk文本并以只读方式渲染DiffHunkPreview零标注接线违反标注一致性硬约束Guide 必须引用真实变更集让章节渲染真实补丁的活切片。语义顺序由数组位置承载而不是某个 label 字段——kind字段并未进入最终 schemaSpec 初稿中的core | consequence | support最终简化为位置即顺序见GuideSection注释。实现中GuideDiffRef的字段是file 可选的summary不是初稿中的lineStart/lineEnd/notelineStart/lineEnd的高亮提示、非切片边界语义被保留为 v1 之后的预留方向。CodeGuideData还扩展了持久化相关字段saved、moved服务端SavedGuideListEntry属于后续 guide 持久化/分享#1112演进的产物v1 阶段只有reviewed。四、生成机制一次标准的 agent jobGuide 生成完全复用 agent-jobs 管线packages/server/guide/guide-review.ts 镜像了 packages/server/tour/tour-review.ts 的模块结构系统提示词 JSON schema 各引擎 CLI 构建器 解析器 内存会话。4.1 引擎接入与命令行构建createGuideSession().buildCommand按配置选择引擎三路并行ClaudebuildGuideClaudeCommand生成形如claude -p --permission-mode dontAsk --output-format stream-json --verbose --json-schema schema --no-session-persistence --model model [--effort effort]的命令并通过--allowedTools白名单与--disallowedTools黑名单约束工具面。白名单严格限定为评审所需Read/Glob/Grep/Agent、只读的git/jj/gh/glab子命令git diff:*、git log:*、gh pr view:*、gh issue view:*等以支持提示词追踪Fixes #123式关联 issue黑名单封禁一切写操作与任意代码执行Edit/Write、python:*、node:*、bash:*等。CodexbuildGuideCodexCommand先把GUIDE_SCHEMA_JSON物化到数据目录下的guide-schema.json再生成codex -m model exec --output-schema schemaPath -o outputPath --approve-for-me --ephemeral -C cwd prompt输出写入临时文件plannotator-guide-uuid.json完成后由parseGuideFileOutput读取并删除。标记类引擎Cursor / OpenCode / Pi这三者都没有 schema 标志位因此复用marker-review.ts的 marker 协议——在提示词尾部追加带 nonce 的plannotator-review-json:pn12位hex标记块用composeGuideMarkerPrompt把方法论 输出契约 用户消息拼装成完整提示词stdout 以 NDJSON 回流解析时用extractMarkerNonce从job.prompt恢复 nonce 再取最后一个完整标记块。源码注释明确没有 nonce 就没有信任基础解析 fail-closed。4.2 用户消息构建让模型对照真实文件集规划章节buildGuideUserMessage复用agent-review-message.ts的 diff 上下文框架并按输入形态分支有 PR 元数据仅给出 PR URL 与 Organize this PRs changeset into a guided review. 指令本地 worktree 场景会额外提示git diff origin/base...HEAD并警告不要对本地main分支做 diff它可能已过期prDiffScope: full-stack时说明这是 stacked PRdiff 展示的是从默认分支到当前 head 的累积变更本地 diff通过getLocalDiffInstruction按 diff 类型since-base、未提交等生成指令workspace 多仓库场景走buildWorkspaceGuideUserMessage附上嵌套 VCS 仓库的上下文行最后兜底内联diff补丁。无论哪种形态都会追加buildChangedFilesBlock生成的Changed files 清单——每行path (增/-删)统计——让模型对照这份真实文件集规划章节安置源码注释diffs[].file must match one of these paths verbatim。该清单的数据来源是 packages/shared/review-core.ts 中的listPatchFilesRecap 确认其正确处理重命名/删除/带引号路径/workspace 前缀等边界。4.3 输出解析流式、文件式与机械修复兜底Claude 走parseGuideStreamOutput从末尾向前扫 NDJSON 的result事件取structured_output要求sections非空数组否则视为无效Codex 走parseGuideFileOutput→parseGuideOutputText读临时文件、JSON.parse失败则落入机械修复标记引擎走parseGuideMarkerOutputNDJSON reduce → 取 nonce 限定的最后一个标记块 → 解析 → 形状检查。三路共享repairGuideJsonText这个纯字符串级机械修复器用于模型输出截断/包了代码围栏/带尾逗号等发射问题依次尝试原样解析、剥离json代码围栏、截取首个{到末个}、去除字符串外的尾逗号、按 LIFO 补齐未闭合括号每次尝试后重试JSON.parse首个得到非空sections的候选胜出。源码特意强调修复绝不改写内容标题/概览/路径/摘要原样保留只修结构与语法stripTrailingCommasOutsideStrings用逐字符扫描而非正则避免误伤字符串字面量里的逗号。五、提示词方法论章节编排本身就是产品ADR 006 的 Consequences 最后一条直言提示词与 schema 的质量决定该功能的价值——按语义重要性分章节核心在前、胶水殿后就是产品本身所以 guide 提示词要获得与TOUR_REVIEW_PROMPT同等的投入。 guide-review.ts 中的GUIDE_REVIEW_PROMPTGuided Review Organizer正是这一判断的落地其核心纪律包括身份与定位资深工程师角色任务是把变更组织成一次能读完的引导式评审明确你不是在找 bug不是在写 findings 报告职责是分章并解释每章改了什么、为何存在、实际意味着什么。声音Voice像同事向另一位资深工程师口头解释一样写作——短句25 词封顶、朴素用词说 file/function/module不说 artifact/surface/backbone、代码名进反引号且一句至多两个、禁用评价性词汇elegant/robust/seamless/critically/simply。速度预算diff 本身就是主信息源读一遍占 90% 的工作量只允许少数有名字的问题驱动的定向查找探索仓库/读未变更文件/宽泛搜索被明令禁止第三次探索性工具调用即停止。章节排序规则按重要性而非路径/大小/时间排序——最重要章节实现心脏理解了它一切随之解锁第一后果按信号递减调用点更新、下游逻辑、配套测试测试跟随被测代码胶水与低信号改动分组殿后给一个诚实朴素的标题Wiring and config、Housekeeping和一两句概览即可。章节切分规则章节是逻辑变更单元而非文件/文件夹——三文件为一因 → 一章挂三文件一文件含两件不相干的事 → 拆两章绝不默认一文件一章多个独立工作各自成章互不共享章节。overview 的三项职责按序具体改了什么为什么存在含非显然决策我们做 X 而非 Y 因为 Z正是审阅者最需要、diff 给不出的信息关键影响系统行为/用户体验/API 与数据契约/性能/运维。高风险部分用 [!IMPORTANT]/ [!WARNING]标注多数章节应当一个都没有。coverage rule硬约束每个变更文件必须恰好出现一次——要么在某章节的diffs要么在unplacedFiles。不得两处、不得两次、不得遗漏模型被告知但不被信任服务端另行强制见下节。其余硬约束diffs[].file必须是 diff/清单中的精确路径不得发明、缩写、改大小写章节通常 2-6 个、上限 10全文禁用 em-dash—与双连字符、禁用 emojititle 一行、intent 1-2 句、overview 2-6 句。校准guide不是 review任务是解释与定向不是批评发现疑似 bug 时可在相关章节 overview 里一句话带过但不要去找问题大多数 overview 零 bug 是正常且预期的。提示词工程上还有两个值得一提的机制composeGuideMethodology支持审阅者附加常驻偏好指令#1265上限GUIDE_EXTRA_INSTRUCTIONS_MAX_CHARS 2000见 packages/core/guide.ts以明确分隔的 Additional reviewer instructions 区块追加、绝不替换内置方法论并对形似 marker 标签的序列做去武装处理以防破坏 nonce 恢复另外 guide 方法论被逐字镜像到独立的plannotator-guideagent skill 中保证Agent 自产的 guide 与 App 内产出的 guide 遵循同一套规则。六、服务端校验fail-closed 与覆盖保证Spec 与实现把模型不被信任落到代码里validateGuideOutput是对自动摄取onJobComplete与人工修复submitManualOutput共用的校验核心纯函数规则如下零章节 → 任务失败GUIDE_EMPTY_OUTPUT_ERRORGuide generation returned empty or malformed output结构性空输出无章节/空白概览的专用GUIDE_NO_SECTIONS_ERROR不上失败卡片由调用方替换为通用文案。越界文件引用 → 整体丢弃diffs[].file不在当前变更文件集合中时该 ref 被剔除编造路径永不浮出水面若因此所有章节归零返回可操作的错误说明Guide referenced N file(s) outside the changeset under review (e.g. ...)。要引导不同提交先在 Commits 面板打开它再重新启动——因为模型引导了错误提交是可修复的与结构性空输出不同。重复安置 → 首个安置生效同一文件出现在多个章节时保留第一次后续重复跳过。unplacedFiles 服务端补齐unplacedFiles 模型列出且真实存在且未被安置的文件 ∪ 所有从未进入任何章节的变更文件。换言之覆盖规则由服务端用集合差分强制即使模型漏报也自动兜底同时剔除既在章节又在 unplacedFiles的重复渲染。零 diff 章节的保留规则模型原始输出就是零 diff 且有真实 overview 文本的纯散文上下文章节被保留因校验丢光 diff 的章节则被丢弃绝不留下空壳。标题/意图做防御性类型强制标记引擎仅靠提示词约束非字符串的 title/intent 会直接让 React 崩溃因此title兜底为 Guided review、intent兜底为空串。onJobComplete还坚持一个关键纪律源码注释明确先记录launchChangedFiles启动时刻的变更文件快照再做解析与校验——guide 是针对启动时补丁生成的中途若 diff/base/PR 被切换校验仍对照模型规划章节时看到的那份文件集而不是屏幕当下显示的补丁同时按 jobId 记录launchReviews完整补丁上限MAX_LAUNCH_REVIEWS 20最旧淘汰供后续导出与修复复用同一份模型所见的 diff。失败的原始输出被stashFailedPayload捕获上限 200KB供手动修复 UI 读取。会话内存态由三个 Map 承载guideResultsjobId → CodeGuideOutput、guideReviewedjobId → boolean[]、failedPayloadsjobId → 原始文本外加launchChangedFiles与launchReviews。API 形态与 Tour 对齐GET /api/guide/:jobId与PUT /api/guide/:jobId/reviewedTour 的 checklist 先例PUT /api/tour/:jobId/checklist集成进 packages/server/review.ts 的既有provider guide分支。七、客户端呈现屏幕接管、组件与数据流7.1 布局分支而非浮层Spec 明确否决了TourDialog/PRSwitchOverlay那种fixed inset-0浮层模型——guide 是一等阅读模式应作为主内容行里的条件分支存在。两个关键工程决策Synthesis 中由 spike 证实dock 必须 CSS 隐藏而非卸载DockviewReact一旦卸载会丢失面板/标签布局files.length 0分支已证明重挂载会从零重建。因此guideOpen时用 CSS 隐藏 dock 包装层与文件树DockviewReact始终保持挂载。焦点仲裁修复focusedFilePath在ReviewStateContext填充时一次性算出所有 dock 面板的isFocused都派生自它guide 打开时在该处置空一行改动隐藏 dock 里的 DiffViewer 就从源头失去了工具栏焦点主张guide 侧实例之间再按章节可见性自行仲裁——避免同一文件的草稿在两个表面间竞态。7.2 入口与快捷键Guide 徽章位于文件树开关分隔线之后激活态随guideOpen切换快捷键ModShiftG注册进reviewEditorShortcuts先例toggleTour。首个 guide 完成时自动接管屏幕沿用 tour 的 auto-open 效果模式用 refSet去重避免 SSE 快照重放导致重复触发。7.3 组件族packages/review-editor/components/guide/GuideScreen——接管根组件按空态/生成中/视图三分支GuideEmptyState——Notion 风格的启动页engine/model/effort 走useAgentSettings新增的guide*设置切片cookie 钩子镜像 tour 切片Generate 按钮调用 App 级launchJob复用同一个useAgentJobs()实例不新增第二条 SSE 连接GuideGenerating——job 状态 实时日志预览复用既有 jobs/jobLogs props取消即既有 killJobGuideView——标题、元信息、有序GuideSectionCard列表 末尾由unplacedFiles渲染的 Everything else 章节GuideSectionCard——标题、NN / MM位置指示、Reviewed 复选框勾选折叠为单行且peek 重新展开不会取消勾选、overview 的既有 Markdown 渲染随后逐 ref 渲染GuideDiffSectionGuideDiffSection——ReviewDiffPanel式的薄适配层files.find(f f.path ref.file)解析文件、挂载一个DiffViewerToolbarHost并接上同一套handleAddAnnotation文件缺失时渲染 outdated 芯片——锚点漂移优雅降级。数据获取由 packages/review-editor/hooks/guide/useGuideData.ts 承载镜像useTourDataGET /api/guide/:jobId拉取勾选经 500ms 防抖PUT .../reviewed持久化卸载时用keepalive: true兜底冲刷用skipNextSaveRef区分fetch 种子的初始状态与用户真实勾选以规避 React StrictMode 开发态的效果重放normalizeReviewed把持久化的 reviewed 数组按当前章节数填充/截断防服务端重启或 schema 漂移导致的崩溃dev 环境支持DEMO_GUIDE_ID演示夹具短路对应 packages/review-editor/demoGuide.ts。7.4 复用而非复制Recap 特意强调AgentControls.tsx选择器原语从 AgentsTab 提升为共享文件、renderMarkdownProse.tsxtour 与 guide 共用散文渲染、导出的模型目录、useAgentSettings的跨实例同步两个活消费方都是抽取出来共享的而非复制。AgentsTab 新增 Guided Review 启动模式job 列表中出现guide任务完成卡片带 Open guide 动作跳转到接管视图。八、标注一致性硬约束如何在代码里落地复用不是复制在客户端的具体含义Recap 原文guide diff 挂载的是真实的DiffViewer使用文件级作用域的处理器handleAddAnnotation变体标注落进同一个CodeAnnotation状态并通过同一个 Send Feedback 载荷导出。Spec 论证了为什么这几乎零成本DiffViewer本就与 dock 无关所有 dock 耦合都集中在约 110 行的ReviewDiffPanel包装层里useAnnotationToolbar本就支持多个同时实例模块级以filePath为键的草稿Map由isFocused仲裁ReviewStateProvider包裹整个应用主体——guide 屏幕在它内部天然获得标注/jobs/config而DiffFile.patch是自包含的单文件补丁files.find(f f.path path)就是 v1 的全部锚定解析故事。九、审阅状态与陈旧性语义Reviewed 状态按 jobId 维度、驻内存tour checklist 先例每个章节一个复选框v1 刻意不做每 diff 复选框保持状态模型最小重新生成创建新 job → 全新 reviewed 状态旧 guide 仍可按旧 jobId 取回。diff 陈旧性guide 渲染的是当前files数组的内容——生成后若用户刷新/切换了 diff仍能解析的 ref 渲染新内容无法解析的 ref 显示 outdated 芯片并给出 Regenerate guide 入口。guide 从不钉死自己的补丁副本。失败恢复解析/校验失败的 job 会进入错误态空态页显示失败横幅失败的原始输出可被捕获经submitManualOutput走机械修复 → 解析 → 用该 job 自己的launchChangedFiles重新校验的路径以同一个 jobId落回结果 Mapreviewed 状态本就以该 jobId 为键手动修复成功后任务卡片翻转为 done。此外还有独立的Guide Repair启动路径repair分支用修复提示词只修结构语法、绝不改内容替换正常组织提示词并强制低成本/低推理档位Claudeeffort: low、Codexreasoning_effort: low——因为这是机械 JSON 修复不是重新分析。十、工程验证与已知边界10.1 验证情况Recap 记录bun run typecheck全包含 Pi 重新 vendor通过bun test packages/ui308 通过 0 失败含新增快捷键绑定的注册表覆盖Piserver.test.ts12 通过apps/review与build:hook构建通过自我评审确认启动快照纪律、fail-closed 摄取、按 job 的 reviewed 状态、标注数据一致性、dock 永不卸载、listPatchFiles路径保真。相关测试文件包括 packages/server/guide/guide-review.test.ts 与 packages/server/guide/guide-cli.test.ts。10.2 已知边界v1 接受guide 与 reviewed 状态为单进程内存tour 先例持久化由 ADR 006 显式推迟guide diff 以固定高度420px带内部滚动渲染DiffViewer填充有界父容器尺寸待真实使用后再议侧边栏标注点击无法展开已折叠章节的 diff本版未做 guide 查看器内的搜索/lineStart滚动定位重载后 SSE 快照重放会再次触发自动接管tour 同等行为标记类引擎Cursor/OpenCode在 v1 不作为 guide 生成器——不过后续代码演化中 marker 引擎接入已实现buildGuideMarkerOutputContract等本文按当前仓库源码如实呈现。十一、结语与延伸阅读Guided Review 的完整决策链在仓库中有迹可循从 ADR 006 出发经过四个 research spikeprovider-tour-pattern、launch-settings-reuse、diff-annotation-reuse、takeover-layout合成出 Synthesis再由 Spec 落到实现细节最终以 Recap 收束验证结果。实现代码集中在 packages/server/guide/服务端、packages/shared/guide.ts数据模型与 packages/review-editor/components/guide/、packages/review-editor/hooks/guide/客户端。如需了解后续演进的 guide 分享与便携式渲染可继续阅读 guide-format.ts 与 portable-guided-reviews 等记录。赞分享【免费下载链接】plannotatorAnnotate and review coding agent plans and code diffs visually, share with your team, send feedback to agents with one click.项目地址https://gitcode.com/gh_mirrors/pl/plannotator点击查看免费下载相关推荐云端数据库管理革命3大核心优势解析CloudBeaver企业级部署实战云端数据库管理革命3大核心优势解析CloudBeaver企业级部署实战 在当今数据驱动的时代数据库管理工具正经历着从桌面到云端的深刻变革。CloudBeavHome Assistant 代码评审技能 ha-review用 SKILL.md 把 AI 辅助 Code Review 标准化Home Assistant 代码评审技能 ha review用 SKILL.md 把 AI 辅助 Code Review 标准化 本文解析 Home Ass智能家居物联网后端工作流自动化Flutter 仓库中的 AI 代码评审实践如何把大型 Review 切分成可控的小块Flutter 仓库中的 AI 代码评审实践如何把大型 Review 切分成可控的小块 在 Flutter 仓库的 .agents/agents/reidba跨平台移动开发前端UI组件桌面应用上一篇Apache Druid日志配置完全指南Log4j集成与日志级别管理下一篇Heat.js颜色范围定制6种视图模式下的色彩配置技巧创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
