首页/新闻资讯/正文详情

plannotator PR 描述文本标注(Phase 1)实现剖析:复用既有注释引擎,把 prose 批注送入 Agent 反馈管道

发布时间:2026/9/25 6:00:33 来源:云帆数科 栏目:资讯中心
plannotator PR 描述文本标注(Phase 1)实现剖析:复用既有注释引擎,把 prose 批注送入 Agent 反馈管道
【免费下载链接】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点击查看免费下载本文基于仓库中的研究综合文档 synthesis-description-annotation-20260630-174500.md并结合 Phase 1 规格、ADR 004 及packages/ui、packages/review-editor的源码与测试完整还原在 PR 描述上做文本级批注这一功能的决策依据、实现链路与验证结论。读者读完可以掌握plannotator 的两套标注体系为何分工、useAnnotationHighlighter的comment模式如何做到选中即弹评论框、注释如何从 store 贯穿侧边栏与反馈导出以及 React 渲染与 web-highlighter DOM 注入冲突这一核心风险的标准解法。一、背景PR 描述只读但批注能力已经存在在 plannotator 的 review 界面中PR Overview 面板展示 PR 描述与评论时间线但两者都是只读的。ADR 004 提出像 plan/annotate 应用一样允许用户在描述正文中选中任意文字并发表评论并让这些笔记与既有 diff 标注一起进入发送给 Agent 的反馈。关键前提是仓库里早已存在两套互不相同的标注体系见 ADR 004体系锚定方式实现位置代码评审CodeAnnotationdiff 行文件 行号 左右侧无法锚定 proseplan/annotateAnnotation渲染后 Markdown 中的选中文本startMeta/endMetaoriginalTextpackages/ui中的useAnnotationHighlighterAnnotationToolbarCommentPopoverFloatingQuickLabelPicker后者通过 web-highlighter 做文本级锚定整套引擎完全位于packages/ui没有 plan 专属依赖并且已经在第二个表面useHtmlAnnotation运行于 iframe 之上被复用——这证明了它是表面无关的。因此 ADR 004 的决策非常明确使用 prose 引擎而非CodeAnnotation复用 hook 与组件而非整个 planViewer后者携带约 50 个 plan 专属 props。同一决策还包含渲染器升级PR 描述此前由MarkdownBody一个仅支持 5 种块类型、无表格/HTML/alert 渲染的精简引擎渲染现改为共享的全功能BlockRendererRenderedMarkdown每个块带data-block-idDOM 因此可标注。二、Phase 1 要交付什么完整需求与数据流综合文档开篇用一句话概括了产品形态在 PR 描述中选中文本 → 评论框立即打开comment-only→ 笔记可选 Ask AI出现在 Annotations 侧边栏的 PR description 分组下、计入评审计数并在 Send Feedback 时随反馈发给 Agent。生命周期与 diff 评论一致只是锚定在 prose 上。刻意比 plan/annotate 更简单comment-only无工具栏、无快捷标签、无删除/红线选择器。Phase 1 规格 给出了完整数据流选中描述文本 → web-highlighter 触发 → hook 处于 comment 模式 → 直接打开 CommentPopover无工具栏 → 用户输入评论或点击 Ask AI→ 提交 → 构建 AnnotationoriginalText startMeta/endMeta高亮文本加入 descriptionAnnotations store → 卡片出现在侧边栏 PR description 分组下totalAnnotationCount 1 → Send Feedback 出现 → Send Feedback → feedbackMarkdown 含 PR Description Feedback 小节 → 走既有 /api/feedback POST值得注意的是最后一步全程无服务端改动。prose 标注搭的是既有反馈管道只是把内容追加进导出的 Markdown。三、实现拆解六步构建与源码印证规格的 build 部分把工作拆为七块下面结合当前仓库代码逐一印证多数步骤已落地为实际代码。3.1 标注引擎挂载AnnotatableDescription包装器comment-onlyPR 描述是直接 DOM 容器无需 iframe因此useAnnotationHighlighter直接挂载。实现见 AnnotatableDescription.tsxcontainerRef只包住描述RenderedMarkdownuseAnnotationHighlighter({ containerRef, annotations: descriptionAnnotations, ..., mode: comment })——comment 模式下hook 的 CREATE 处理器直接setCommentPopover(...)工具栏只在else分支渲染因此选中即弹评论框、无工具栏只渲染CommentPopover由hook.commentPopover与hook.handleCommentSubmit/handleCommentClose驱动不渲染AnnotationToolbar或FloatingQuickLabelPicker组件用React.memo包裹仅在markdown或descriptionAnnotations变化时重渲染对应风险缓解第 1 条。渲染位置见 PRSummaryTab.tsxPRSummaryTab保持 props-based内部以AnnotatableDescription markdown{context.body} classNamemd-compact /取代裸RenderedMarkdownstore 由包装器通过useReviewState()自取。3.2 存储与上下文线程化规格要求在 App.tsx 中新增const [descriptionAnnotations, setDescriptionAnnotations] useStateAnnotation[]([]); const [selectedDescriptionAnnotationId, setSelectedDescriptionAnnotationId] useStatestring|null(null);外加三个 handleronAddDescriptionAnnotation(ann)追加并选中、onSelectDescriptionAnnotation(id)、onDeleteDescriptionAnnotation(id)——镜像 plan 编辑器的小表面。这些状态必须同时加入 ReviewStateContext.tsx 的ReviewState接口、provider value 对象以及它的 deps 数组规格特别提醒那是大型useMemo漏掉 dep 会导致 stale。从源码看接口中已经存在// PR description prose annotations (comment-only; text-anchored Annotation[], // kept separate from the diff CodeAnnotation[] above). descriptionAnnotations: Annotation[]; selectedDescriptionAnnotationId: string | null; onAddDescriptionAnnotation: (ann: Annotation) void; onSelectDescriptionAnnotation: (id: string | null) void; onDeleteDescriptionAnnotation: (id: string) void;3.3 侧边栏 PR description 分组ReviewSidebar此前已能渲染第二种标注类型editorAnnotations自带删除路径Phase 1 直接镜像该模式。从 ReviewSidebar.tsx 可以看到新增 propsdescriptionAnnotations?: Annotation[]等totalCount把三/四类计数相加annotations.length (editorAnnotations?.length ?? 0) (descriptionAnnotations?.length ?? 0) (commentAnnotations?.length ?? 0)渲染一个共享的renderProseAnnotationCard卡片外壳作用域标签、引用的原文、评论、选中态、复制/删除操作renderDescriptionAnnotationCard把Annotation字段映射上去label 为 PR description、quote 为originalText、note 为annotation.text点击卡片 →onSelectDescriptionAnnotation(id)→ 设置selectedDescriptionAnnotationId→ hook 滚动并.focused描述中的高亮删除卡片 →onDeleteDescriptionAnnotation(id)→hook.removeHighlight(id) 从 store 移除。一个值得注意的规格细节选择描述卡片时只有PR Overview 面板打开时才能聚焦高亮v1 的方案是打开/聚焦 overview 面板或接受 no-op。3.4 计数与导出两处计数器 一处追加两个计数器App.tsx的totalAnnotationCountgates Send Feedback和ReviewSidebar.tsx的totalCount侧边栏计数/空态都要 descriptionAnnotations.length。导出feedbackMarkdown追加exportAnnotations(parseMarkdownToBlocks(prContext.body), descriptionAnnotations, [], PR Description Feedback, PR description)。App已持有prContext源码中prContext: PRContext | null在ReviewState接口中可见。exportAnnotations定义在 packages/ui/utils/parser.ts以# {title}开头、按blockId/startOffset排序——prose 标注两者都携带且块 id 与导出时重新解析的prContext.body一致因此排序天然成立。追加时需前置\n\n并对prContext?.body做空值守卫preflight 发现的三处补充之一。3.5 Ask AI 复用file-less 的 scope-selection ask规格第 7 节确认这是零新增工作AskAIParams本就有一等scope字段buildDefaultPrompt见 useAIChat.ts已经能构建带标签、无文件的 selection ask——Re: {label}Selected text: … 问题。HTML viewer 正是这样通过CommentPopover的askAIContext喂入的。接线方式与HtmlViewer.tsx一致onAskAI: (question) askAI({ prompt: question, scope: { kind: selection, label: PR description, text: selectedText }, }) // 无 filePathAnnotatableDescription.tsx中可见实际实现CommentPopover ... onAskAI{onAskAIForDescription} askAIContext{{ kind: selection, label: PR description, text: hook.commentPopover.selectedText ?? hook.commentPopover.contextText, }} /答案落入 AI 侧边栏因为scope存在问题上卡片自带 PR description 上下文。可选优化非必需AITab.tsx按question.scope?.label分组让描述类提问聚合在自己的标题下。3.6 高亮 CSS 上移共享.annotation-highlight与.deletion/.comment/.focused/:hover此前只存在于 packages/editor/index.css118-161 行附近约 40 行需搬入共享的packages/ui/theme.css让 plan 编辑器和 review 编辑器共用--focus-highlight已定义在 review 编辑器加载的主题文件中因此.focused可直接生效。四、验证矩阵代码级逐条确认综合文档记录了对所有承重声明的代码验证与 规格的 Verification 清单 对应声明结论证据选中即弹评论框无工具栏✅useAnnotationHighlighterCREATE 处理器modecomment→setCommentPopover(...)工具栏只在else分支恢复可安全重跑幂等✅applyAnnotationsInternal跳过已标记 idgetDoms/[data-bind-id]再走fromStore→findTextInDOM文本回退点击高亮即选中✅Highlighter.event.CLICK → onSelectAnnotation(id)侧边栏已支持第二种标注类型✅ReviewSidebar的editorAnnotations→EditorAnnotationCard自带删除、totalCount两者求和App 持有描述正文供导出✅App.tsx的prContextfeedbackMarkdown、totalAnnotationCount为插入点无文件选中也可 Ask AI✅AskAIParams.scopebuildDefaultPrompt构建Re: {label}Selected text: prompt已被HtmlViewer使用高亮 CSS --focus-highlight✅packages/editor/index.css样式--focus-highlight在 review 编辑器加载的主题中preflight 还确认了三处规格未预见的补充实现均不改变设计EditorAnnotationCard强类型于EditorAnnotationlabel filePath放不下 proseAnnotation形状故新建小型DescriptionAnnotationCard评论文本 引用原文 作者 删除 选中态渲染位置与editorAnnotations块相同两个计数器而非一个导出需处理空 body 与\n\n前置。五、唯一真实风险与三层缓解web-highlighter 向 React 渲染的 DOM 注入markRenderedMarkdown一旦重渲染可能清掉这些标记。这是全功能唯一需要小心之处AnnotatableDescription.tsx的注释也明确记载了这一点。缓解方案全部是已知、低新颖度的标准做法React.memo隔离AnnotatableDescription/RenderedMarkdown仅在markdown或descriptionAnnotations变化时重渲染避免父级无关重渲染带来的意外 reconciliation。渲染后重放useEffect(() hook.applyAnnotations(descriptionAnnotations), [descriptionAnnotations, markdown key])。applyAnnotationsInternal已验证幂等跳过已标记 id因此可放心频繁调用。当前实现还额外用prevIdsRef对比删除的 id 并调用hook.removeHighlight(id)保证从侧边栏删除标注时高亮同步移除。文本搜索回退applyAnnotations在startMeta因 DOM 变化无法解析时按originalText通过findTextInDOM重新绑定。残余风险live-context SSE 更新若改变了描述正文其下已锚定的标注可能丢失锚点。发生频率低v1 明确接受回退文本搜索或丢弃。对应地规格风险 2 也指出描述正文可能经 SSE 刷新文本锚不一定能重绑。六、为什么信心等级是 High综合文档给出的信心判断没有任何真正的新子系统——评论引擎、评论框、Ask AI、侧边栏、导出、计数全部是既有机制接到一个新表面上。新增代码量很小包装器 一个 store 上下文字段 一个侧边栏分组 两处导出/计数 搬 CSS。唯一真实风险是众所周知的 React-vs-DOM 注入问题且缓解方案是 plan viewer 已在用的标准做法。规格的 Reuse map 进一步给出了逐项复用对照需求复用无改动选中 → 评论框useAnnotationHighlighter的mode: comment评论输入 Ask AICommentPopoveronAskAI/askAIContext消费方模板HtmlViewer.tsx的CommentPopoverportalstore 形状editor/App.tsx的标注小表面侧边栏第二类型模式ReviewSidebar的editorAnnotations路径选中处 Ask AIaskAI({ scope: { kind:selection, label, text } })导出exportAnnotations(blocks, anns, [], title, subject)ADR 004 还锁定了后续边界描述先行端到端打通选中 → 评论 → 侧边栏 → 发送每条 PR 评论的批注是 Phase 2卡片上放评论按钮不做卡片内文本选择以避开卡片点击/折叠处理器冲突。七、Ready-to-build 清单来自规格AnnotatableDescription包装器React.memo——hook 进入comment模式只渲染CommentPopover带 re-apply effect。descriptionAnnotationsstore handlers 置于App.tsx经ReviewStateContext线程化value和deps。ReviewSidebar增加 PR description 分组镜像editorAnnotations/EditorAnnotationCard。totalAnnotationCountfeedbackMarkdown纳入 proseexportAnnotations(parseMarkdownToBlocks(prContext.body), …, PR Description Feedback, PR description)。Ask AIonAskAI→askAI({ scope: { kind:selection, label:PR description, text } })同HtmlViewer。把.annotation-highlight样式移入packages/ui/theme.css。八、验证路径与延伸阅读ADR004-annotate-pr-description-and-comments-20260630-155000.md规格description-annotation-phase1-20260630-171500.md渲染器前置工作SPIKE-renderer-migration-20260630-155500.md、SPIKE-renderer-density-parameterization-20260630-160500.md核心实现AnnotatableDescription.tsx、ReviewSidebar.tsx、ReviewStateContext.tsx、App.tsx底层引擎useAnnotationHighlighter.ts含幂等恢复、文本回退、comment模式分支、跨块引用的 block-boundary 归一化等大量边界处理导出工具exportAnnotations对希望理解如何在一个已有丰富标注能力的代码库上低成本地把新表面接入同一套注释管道的读者这份综合文档及其配套源码是一份难得的端到端范本两条标注模型在内存中分离仅在展示边界侧边栏分组与导出边界反馈 Markdown汇合最终换来无新子系统、无服务端改动、信心 High的交付结果。赞分享【免费下载链接】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点击查看免费下载相关推荐plannotator PR 描述标注Phase 1实战指南选中即评、复用现有注释引擎为 PR 描述接入 Agent 反馈管线plannotator PR 描述标注Phase 1实战指南选中即评、复用现有注释引擎为 PR 描述接入 Agent 反馈管线 导读 本文基于 plannplannotator PR 描述批注实战用共享 Prose 批注引擎让评审者一行划选就能评论 PR 正文plannotator PR 描述批注实战用共享 Prose 批注引擎让评审者一行划选就能评论 PR 正文 本篇基于 plannotator 仓库中的意图文档plannotator 架构决策 004为 PR 描述与评论接入 Agent 反馈注释管线plannotator 架构决策 004为 PR 描述与评论接入 Agent 反馈注释管线 导读 本文基于 plannotator 仓库中的架构决策记录 AD上一篇如何安装和配置EverythingToolbar5分钟快速上手教程下一篇PostHog 实验与特性开关审计的修复动作指南基于 auditing-experiments-flags Skill 的 Remediation Actions 全解析创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关推荐

Slot _a is unbootable真相:A/B分区机制状态提示而非系统损坏
Slot _a is unbootable真相:A/B分区机制状态提示而非系统损坏

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 6:00:33

如何免费部署Magnet Player这样的P2P流媒体站点到GitHub Pages?Jekyll+HTTPS避坑指南
如何免费部署Magnet Player这样的P2P流媒体站点到GitHub Pages?Jekyll+HTTPS避坑指南

如何免费部署Magnet Player这样的P2P流媒体站点到GitHub Pages?JekyllHTTPS避坑指南 【免费下载链接】magnet-player Stream torrents directly from your browser using WebTorrent. Paste a magnet link or torrent URL and watch videos instantly with peer-to-… · 2026/9/25 6:00:33

Excel连续数据选中原理与快捷键实战指南
Excel连续数据选中原理与快捷键实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 6:00:27

DNF服务端本地复现:虚拟机+Ubuntu+MySQL局域网联机全栈实践
DNF服务端本地复现:虚拟机+Ubuntu+MySQL局域网联机全栈实践

1. 项目概述:这不是“私服”,而是一次完整的本地游戏服务架构复现DNF单机版搭建——这个词在搜索框里一敲,出来的全是“私服发布网”“免VM一键安装包”“台服源码下载”这类内容。但我要说清楚:我们今天做的,不是绕过… · 2026/9/25 6:31:37

AI算力落地三维地图:云端、边缘、端侧芯片选型实战指南
AI算力落地三维地图:云端、边缘、端侧芯片选型实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 6:31:37

嵌入式烧录与仿真调试工具链:原理、故障排查与选型指南
嵌入式烧录与仿真调试工具链:原理、故障排查与选型指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 6:31:31

TI电压基准芯片断供下的国产替代选型与验证指南
TI电压基准芯片断供下的国产替代选型与验证指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 6:31:31

赣网杯Web赛道WP深度解析:PHP安全边界与实战攻防
赣网杯Web赛道WP深度解析:PHP安全边界与实战攻防

1. 这不是普通CTF题解:赣网杯Web赛道的“真实战场”还原你点开这篇,大概率是因为刚打完赣网杯,或者正卡在某道Web题上反复刷新页面、抓包抓到手软,又或者——你根本没参赛,但看到“wp”两个字就条件反射点进来&#xf… · 2026/9/25 6:31:31

IAR+Traveo II双核开发环境搭建:CYT4BB实战指南
IAR+Traveo II双核开发环境搭建:CYT4BB实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 6:31:25

数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)
数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31

创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31

MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码