多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

Kilo Code Agent Manager 中的紧凑 PR Checks:按状态分桶、去重与持久化的实现方案

Kilo Code Agent Manager 中的紧凑 PR Checks:按状态分桶、去重与持久化的实现方案 Kilo Code Agent Manager 中的紧凑 PR Checks按状态分桶、去重与持久化的实现方案【免费下载链接】kilocodeKilo is the all-in-one agentic engineering platform. Build, ship, and iterate faster with the most popular open source coding agent.项目地址: https://gitcode.com/GitHub_Trending/ki/kilocode本文围绕 Kilo Code 仓库中的规划文档 plans/pr-checks-compact-plan.md 展开讲解 Agent Manager 的 PR 面板如何将多达数十条的 GitHub 检查checks从“每行一条”的原始列表重构为按状态分桶、按严重度排序、可折叠且失败永不隐藏的紧凑视图。读完后你可以掌握一条完整的 UI 数据链路宿主侧ghGraphQL 数据如何解析与去重、纯函数分组模块如何组织桶序与自然排序、组件与 CSS 如何呈现以及展开状态如何在组件重挂载remount之后仍然保持。目标35 条全绿检查不该占 35 行规划文档开篇给出了一条核心设计原则A green PR with 35 checks must not cost 35 rows. Show signal, hide noise, keep everything expandable, and never hide a failure.重构前的现状是 PRChecks.tsx 按gh返回的原始顺序逐条渲染 check没有分组、排序或去重。当 PR 挂着几十个矩阵化 job如test (linux)、test (windows)、unit (windows, 10/6)时面板被大量绿色行淹没真正失败的检查反而要靠滚动才能找到。文档明确把 GitHub CLIcli/cli仓库的pkg/cmd/pr/checks/aggregate.go与output.go列为参考实现并提炼出 8 条规则按状态桶status bucket分组而不是按 app 或 workflow 分组桶的固定顺序为 failure、pending、cancelled、skipped、success桶内用“数值感知的自然序”numeric-aware natural sort按名称排序failure 与 pending 组默认展开success 与 skipped 组默认折叠使用计数标签如1 failing check、27 successful checks矩阵 job 保持为独立行不合并按“check 标识 最新 startedAt”去重剔除陈旧的 rerun 记录汇总行用 tally 形式5 pending · 1 failing而不是X of Y。预期效果来自规划文档的 Expected result 小节Checks 5 pending · 1 failing [Fix with Kilo] v 1 failing check Vercel - docs [link] v 5 pending checks test (linux) [link] typecheck [link] 29 successful checks全绿时则收敛为一行折叠的35 successful checks。数据入口宿主侧解析、状态映射与去重PR 面板的数据由 VS Code 扩展宿主侧从gh的 GraphQL 结果解析而来核心逻辑在 am-pr-utils.ts。规划文档中“Host data”一节提出的三条要求都可以在这份源码中找到对应实现状态映射TIMED_OUT / STARTUP_FAILURE 算失败EXPECTED 算 pendingcheckStatus()负责把 GitHub 的状态枚举折叠为面板使用的 5 值类型CheckStatus定义见 pr-types.ts 第 6 行SUCCESS、NEUTRAL→success规划文档特别指出NEUTRAL应保留为成功避免“中性结论”的检查被误读为异常FAILURE、ERROR、ACTION_REQUIRED、TIMED_OUT、STARTUP_FAILURE→failurePENDING、QUEUED、IN_PROGRESS、REQUESTED、WAITING、EXPECTED→pendingSKIPPED→skippedCANCELLED、STALE→cancelled无法识别的未知状态兜底为pending保证“不确定的东西不会伪装成绿色”。按 check 标识 最新 startedAt 去重checks()函数am-pr-utils.ts 第 110–156 行实现了文档第 7 条规则。它的做法是为每个原始 item 计算去重键commit status 用status:contextcheck run 用run:name:workflowName:event——这就是文档所说的“check 标识”check identity计算每个 item 的started时间戳有startedAt就用它没有的话仍处于活动状态PENDING/QUEUED 等的记录取Infinity其余取-Infinity保证活动中的重跑总是压过陈旧的完成记录相同键保留started最大的一条最后按原始index排序输出保持用户熟悉的相对顺序。这样一次失败后重跑成功的 workflow 不会留下两条记录反之一次陈旧的成功 rerun 也不会覆盖新的失败。汇总语义保持不变规划文档强调“Keep aggregate counts unchanged. Grouping is a view concern only.”。summarize()am-pr-utils.ts 第 158–167 行在去重之后计算total / passed / failed / pending / status其中 skipped 不计入 total、cancelled计入 failed——这些聚合值继续供徽章badge与上层编排使用分组只发生在视图层不改动这一层。纯分组模块DOM-free、可单测分组逻辑独立为 pr-check-groups.ts——这正是规划文档“Pure grouping module”一节要求新增的文件。整个模块只有 3 个导出函数和一个桶类型没有任何 DOM 依赖export type CheckBucket failure | pending | cancelled | skipped | success const ORDER: CheckBucket[] [failure, pending, cancelled, skipped, success] const SORT new Intl.Collator(undefined, { numeric: true, sensitivity: base }) export function groups(checks: PRCheck[]): CheckGroup[] { return ORDER.flatMap((bucket) { const values checks .filter((check) check.status bucket) .slice() .sort((a, b) SORT.compare(a.name, b.name) || SORT.compare(a.url ?? , b.url ?? )) return values.length 0 ? [{ bucket, checks: values }] : [] }) }几个实现细节值得注意单一共享的 CollatorIntl.Collator(undefined, { numeric: true })在模块级创建一次实际还加了sensitivity: basenumeric: true让unit (windows, 2/6)排在unit (windows, 10/6)前面——这是文档第 3 条“natural numeric-aware name comparison”的直接落地也是矩阵 job 命名1/6…10/6排序正确的前提空桶被剔除flatMap中空桶返回[]所以一个全绿 PR 只产生一个success组二级排序键名称相同时按url排序保证同名不同链接的 job 顺序稳定默认展开规则expands(bucket)除success与skipped外一律默认展开即 failure/pending/cancelled 三个“需要行动”的桶默认打开——落实了“never hide a failure”计数数据counts(checks)直接复用groups()为本地化摘要提供每个桶的数量。对应的单测 pr-check-groups.test.ts 覆盖了规划文档“Verification”小节的三项要求桶顺序[failure, pending, skipped, success]、自然排序2/6在10/6前、以及expands()对各桶的默认展开断言。组件层PRChecks.tsx 的分组渲染PRChecks.tsx 消费上述纯模块。与文档对照几个关键实现点如下SectionHeading 承载 tallycount()memo 用counts()取各桶数量按tallyLabel本地化后以分隔符连接。这里有一个额外的信号优先处理只要存在任何非 success 的桶汇总行就只显示信号桶如5 pending · 1 failing全绿时才退化为35 successful checks。样式上通过am-pr-checks-count-${status}类定义于 pr-panel.css 第 184–191 行给失败/等待状态着不同颜色组标题可点击展开每组是一个buttonaria-expanded反映当前展开态chevron 图标随状态切换符合文档“Keep group headings visually below the main Checks section heading”与“one status signal per row”的意图规则行内不再重复状态文字每行只剩图标 名称 可选时长 外链按钮状态完全由data-status驱动图标着色CSS 中.am-pr-panel-check-item[data-statusfailure] .am-pr-check-icon等规则即文档所说“Remove duplicated per-row status words. Improve density by removing duplicate content, not by shrinking type.”Fix with Kilo保持在检查组之上checkFeedback()生成的修复建议按钮渲染在组列表之前对应文档“KeepFix with Kiloabove the check groups”内滚动的行阈值data-scrollable{checks.length 12}在超过约 12 行时才给容器加滚动类[data-scrollabletrue]样式见 pr-panel.css 第 847 行落实“Add an inner scrollbar only after a sensible row-count threshold is reached”长名称与窄面板名称走am-pr-check-name的省略号截断外链收进带 Tooltip 的小按钮避免在窄面板中换行挤掉控件。矩阵 job 按文档要求保持独立行分组只发生在桶维度桶内部逐条列出不做任何合并。展开状态持久化跨 remount 存活文档的“Persistence”一节要求把 checks 区的展开态与每个桶的用户覆盖态存进 pr-comment-state.ts并按 worktree 为键。该模块的注释解释了动机任何一次短暂拿不到gh状态的轮询、worktree 重选、侧边栏切换都会重挂载 PR 面板组件局部状态会随 remount 死亡。CommentState接口为此扩展了两个字段pr-comment-state.ts 第 36–37 行checksOpen: boolean // Checks 整区是否展开 checkGroups: Recordstring, boolean // 每个桶的用户覆盖PRChecks.tsx 中的解析优先级是三级回落const groupOpen (bucket) state()?.checkGroups[bucket] ?? localGroups()[bucket] ?? expands(bucket)即“持久化用户覆盖 无 worktreeId 时的局部信号 模块默认展开规则”。切换组时有worktreeId就写patchCommentState持久化否则退回写局部信号。toggleOpen对 Checks 整区做同样处理。这样就实现了文档的两条要求“Make every collapse reversible in one click and preserve it across remounts”——用户在 worktree A 折叠的 success 组切走再回来时依旧折叠。本地化与样式约束规划文档还给出了一批“意图规则”UI preferences约束实现不得另起炉灶复用 kilo-ui 组件与既有pr-panel.css类不新增内联样式或裸 hex 色值——PRChecks.tsx 中确实只从kilocode/kilo-ui引入 Button/Icon/Spinner/Tooltip图标全部来自图标注册表circle-check、circle-x-outline、stop、circle-ban-sign、chevron-down等所有用户可见文案——组标题1 failing check/27 successful checks这类带{{count}}占位符的 one/other 复数形式、行内状态标签、汇总分隔符、外链 Tooltip——都走useLanguage()的t()与agentManager.pr.checks.*键见 PRChecks.tsx 中GROUP_KEYS/TALLY_KEYS两张键表并需补进 Agent Manager 的全部 locale样式取值“从现有样式表与设计令牌中取具体值而不是发明固定值”例如滚动阈值 12 与组标题的字号层级都锚定在既有pr-panel.css的规则上。验证清单与明确不做的事规划文档的 Verification 一节给出可执行清单可作为后续维护该功能的回归基线单测覆盖分组、自然排序、状态映射、去重pr-check-groups.test.ts 已覆盖前三项的分组侧测试断言成功组默认折叠、失败组默认展开、展开态在 remount 后保持在packages/kilo-vscode/下运行bun run compile、bun run test:unit、bun run lint、bun run knip以及 Agent Manager 架构测试用同一视口与代表性 check 数据截取前后对比截图。文档的 Out of scope 一节同样值得引用它划定了这条方案的边界避免读者误期待必需检查徽章required badges——需要额外一次 GraphQL 请求按 workflow 分组——GitHub 在 Checks 页签用它但 merge box 场景不用把矩阵 job 合并成一行——保持逐行牺牲少量行数换取定位失败的精度。小结一条“视图关切”的完整链路这套紧凑 PR checks 方案值得借鉴的地方在于职责切分得非常干净去重与状态折叠在宿主侧 am-pr-utils.ts 完成数据关切桶序、自然排序、默认展开、计数在 DOM-free 的 pr-check-groups.ts 完成可单测的逻辑关切渲染、截断、内滚动阈值在 PRChecks.tsx 与 pr-panel.css呈现关切展开态持久化按 worktree 键控在 pr-comment-state.ts状态关切。聚合计数始终不随分组变化失败与等待永远不会被默认隐藏——这正是文档开篇那句原则在每一层代码里的具体投影。【免费下载链接】kilocodeKilo is the all-in-one agentic engineering platform. Build, ship, and iterate faster with the most popular open source coding agent.项目地址: https://gitcode.com/GitHub_Trending/ki/kilocode创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表