使用 AI Agent 高效修复 GitHub Issue:以 liam 仓库 fix-issue 命令工作流为实战指南
【免费下载链接】liamAutomatically generates beautiful and easy-to-read ER diagrams from your database.项目地址: https://gitcode.com/GitHub_Trending/li/liam
在 liam(Liam ERD)仓库中,从用户提交的 GitHub Issue 到代码修复合并,背后有一套完整的自动化工作流——它由 .claude/commands/fix-issue.md 这个 Claude Code 命令驱动,覆盖"拉取 Issue → 定位问题 → 实现修复 → 测试验证 → 通过 lint → 规范提交"的全链路。本文以该命令为核心骨架,结合仓库中的 lint 配置、提交规范、测试原则与 Issue 模板,还原一条可直接复制的 AI 辅助修复流水线。读完本文,你将掌握如何用ghCLI 精准获取 Issue、如何在 monorepo 中快速定位问题文件、如何用pnpm体系完成测试与质量门禁,以及如何写出符合项目规范的提交消息。
一、命令概览:fix-issue 的定位与输入参数
.claude/commands/fix-issue.md是 Claude Code 的 slash command 定义文件,其头部 YAML 元数据声明了它的用途:
--- description: Fetch and read a GitHub issue, then implement and verify the fix ---这段描述点明了命令的三段式职责:获取(Fetch)→ 实现(Implement)→ 验证(Verify)。与同目录下的 read-issue.md(只负责"读取并展示 Issue,不做改动")相比,fix-issue 是完整闭环:它不仅理解问题,还要落地修复、跑通测试并产出合规提交。
该命令接受一个参数——Issue 编号,支持两种等价写法:
123 # 纯数字 #123 # 带 # 前缀命令第一步就是从参数中提取 Issue 编号,这是后续所有gh调用的基础。
二、第一步:用 GitHub CLI 拉取 Issue 详情
命令的核心取数动作是:
gh issue view <issue-number>以编号123为例,实际执行为gh issue view 123。该命令会返回 Issue 的标题、正文、标签、assignee、状态等完整信息,是 AI Agent 理解问题背景的第一手材料。使用前需确保本机已安装 GitHub CLI 并通过gh auth login完成认证(这是 create-pull-request.md 中列出的前置条件)。
为了"读懂"取回的 Issue 内容,可以对照仓库的 Bug 报告模板 .github/ISSUE_TEMPLATE/1_bug_report.yml 理解字段语义。该模板要求报告者填写:
| 模板字段 | 含义 | 对修复工作的价值 |
|---|---|---|
| Version Type | 用户使用的是 Web 版还是 CLI 版(npm 包) | 决定问题发生在frontend/apps/app还是frontend/packages/cli |
| Steps to reproduce | 复现步骤 | 指导编写回归测试的输入场景 |
| Expected Behavior | 期望行为 | 定义修复的验收标准 |
| Actual Behavior | 实际行为 | 定位缺陷的直接线索 |
| Additional Context | 日志、截图等补充信息 | 辅助缩小搜索范围 |
例如,当 Issue 标注为"CLI Version"时,问题大概率落在 frontend/packages/cli 包内;若是 Web 版,则先查 frontend/apps/app 及其内部组件。
三、分析与定位:在 monorepo 中搜索相关文件
拿到 Issue 后,命令要求"search the codebase for relevant files related to the issue"。liam 是一个 pnpm workspace + Turborepo 的 monorepo,定位问题需要先理解包结构。项目根目录 CLAUDE.md 给出了官方架构地图:
- 应用层:frontend/apps/app(主 Next.js Web 应用,
@liam-hq/app)、frontend/apps/docs(文档站) - 公开包:frontend/packages/cli(CLI 工具)、frontend/packages/erd-core(ER 图核心渲染)、frontend/packages/schema(Schema 解析器)、frontend/packages/ui(UI 组件库)
- 内部包:frontend/internal-packages/agent(基于 LangGraph 的 AI Agent)、frontend/internal-packages/db(数据库工具)、frontend/internal-packages/mcp-server(MCP 服务)
搜索策略建议分三步递进:
- 按关键词搜索:以 Issue 标题/正文中的核心术语为关键词,在仓库内做正则搜索(对应
ripgrep的rg <pattern>用法),先命中直接相关的文件; - 按组件定位:命中结果若在
frontend/apps/app,再结合目录结构下钻到具体组件目录(如components/SessionDetailPage、features/sessions等),确认调用链; - 按类型收束:若 Issue 涉及数据库 schema 或类型定义,优先查看 frontend/internal-packages/db/supabase/database.types.ts 与 frontend/internal-packages/db/src/schema.ts。
从源码结构可以推断,liam 的数据流是"schema 解析(@liam-hq/schema)→ ERD 渲染(@liam-hq/erd-core)→ UI 展示(@liam-hq/ui)",遇到渲染类 Bug 时沿这条链路排查通常最快。定位完成后,还应把文件路径、行号、搜索结果作为证据记录下来——create-issue.md 的 Best Practices 中特别强调 "Evidence documentation: Include specific file paths, line numbers, and search results",这条原则同样适用于修复过程的记录。
四、实现修复:先读懂项目编码规范
定位到问题文件后动手修改前,需要先对齐 liam 的编码约束,避免"修好一个 Bug、引入一堆 lint 报错"。仓库 CLAUDE.md 明确的核心原则是"Less is more":实现要尽量小而直观,能用代码自解释就绝不多写注释,敢于删除死代码。
具体到代码层面,需要遵守的硬性规范包括:
- TypeScript:外部数据必须用
valibot做运行时校验;逻辑优先早返回(early return); - 组件:只用命名导出(no default exports);事件处理函数以
handle前缀命名(如handleClick);样式一律使用 CSS Modules;UI 组件与图标优先从@liam-hq/ui导入; - 文件组织:不要在
page.tsx里直接写逻辑,应拆分到独立页面组件;用 const 而非 function 声明const toggle = () => {}; - 数据变更:所有增删改操作使用 Server Actions(对应 frontend/apps/app/app 下各
actions/目录的组织方式)。
从代码结构看,这些规范并非口头约定——仓库通过自定义 ESLint 插件(见 frontend/internal-packages/configs/eslint 下的no-non-english-plugin.js、no-throw-error-plugin.js、prefer-clsx-plugin.js、require-use-server-plugin.js)在 lint 阶段强制执行,这解释了为何 fix-issue 工作流把"通过 lint"列为独立验证步骤。
五、测试验证:为修复建立回归防线
命令要求"Write and run tests to verify the fix",这对应仓库的测试体系。项目根 package.json 暴露了三个入口:
pnpm test # 等价于 turbo test,跑所有包的单元测试 pnpm test:e2e # 等价于 turbo test:e2e,跑 Playwright 端到端测试 pnpm test:coverage # 等价于 vitest --coverage,生成覆盖率单包执行则用 filter 语法,例如pnpm --filter @liam-hq/agent test。从 docs/test-principles.md 与 .claude/commands/implement-regression-tests.md 可以提炼出三条测试原则:
- 测试"当前真实行为"而非理想行为——回归测试保护的是现状不被破坏;
- 测试必须通过——它们记录的是"是什么"(what IS),不通过的测试没有任何文档价值;
- 最小化 mock——只在外部边界(网络、数据库等)处打桩。
写测试时还应对照 Issue 中的复现步骤:Steps to reproduce就是最自然的测试用例输入,Expected Behavior就是断言目标。仓库中大量*.test.ts(如 frontend/internal-packages/agent/src 下的 createGraph.test.ts、getMessages.test.ts 等)展示了"行为描述式"的用例写法,可直接作为风格参考。
六、质量门禁:理解 pnpm lint 的完整链路
fix-issue 的第 7 步是"Ensure code passes linting and type checking (usepnpm lint)"。这里的pnpm lint并不是单一命令,从根 package.json 可以看到它由三层组成:
"lint": "pnpm lint:turbo && pnpm lint:syncpack && pnpm lint:knip", "lint:turbo": "turbo lint", "lint:syncpack": "syncpack lint", "lint:knip": "knip --treat-config-hints-as-errors"| 子命令 | 检查内容 | 与修复工作的关系 |
|---|---|---|
pnpm lint:turbo | 逐个包运行 ESLint + Biome 等静态检查 | 捕捉未使用变量、风格违规、非英文代码等 |
pnpm lint:syncpack | 校验 workspace 依赖版本一致性 | 防止修复时误引入版本漂移的依赖 |
pnpm lint:knip | 检测未使用的文件、依赖与导出 | 提醒清理修复后遗留的死代码 |
三者用&&串联,任一环节失败整个 lint 即失败,保证提交前代码全面合规。类型检查方面,各包独立的tsconfig.json(如 frontend/apps/app/tsconfig.json)定义了编译目标与路径别名,pnpm build会触发完整的类型检查,可作为 lint 之外的第二道防线。
这套门禁还被两道机制"锁死":
- Git pre-commit hook:lefthook.yml 在
pre-commit阶段对*.{js,jsx,ts,tsx,json,md,mdx,yml,yaml}运行pnpm lint,并设置stage_fixed: true自动暂存修复后的文件,失败信息明确提示"Please fix all linting errors before committing"; - 权限封禁:.claude/settings.json 在 Claude 权限层直接
deny了Bash(git commit --no-verify:*),从机制上杜绝绕过 lint 的提交。
因此,修复流程中正确的顺序是:改代码 → 写测试 →pnpm test→pnpm lint→ 通过后才进入提交环节。
七、提交规范:写出有信息量的 commit message
fix-issue 的最后一步要求"Create a descriptive commit message following the project's commit conventions"。项目规范沉淀在 .claude/commands/commit.md 中,核心要求有三条:
- 拆分大变更:改动涉及多个关注点时,拆成多个独立提交,每个提交只做一件事;
- 消息匹配内容:清晰描述"改了什么组件、做了什么动作",禁止 "fix bug"、"update code" 这类空话;
- 使用 gitmoji(可选但推荐):用真实 emoji 字符而非
:smile:文本形式。
对照规范,好与坏的提交示例:
❌ fix bug ❌ update code ❌ changes made ✅ 🐛 Fixed a bug in the authentication module causing login failures ✅ ✨ Added a new feature to filter tables by column ✅ 📝 Updated README.md with new installation instructions其中与修复场景最相关的 gitmoji 分类如下:
| 场景 | gitmoji | 含义 |
|---|---|---|
| Bug 修复 | 🐛 | Fix a bug |
| 补充回归测试 | ✅ | Add, update, or pass tests |
| 修复 lint/编译器告警 | 🚨 | Fix compiler / linter warnings |
| 简单修补 | 🩹 | Simple fix for a non-critical issue |
| 关键热修复 | 🚑 | Critical hotfix |
| 修复拼写/文案 | ✏️ | Fix typos |
对于一个典型的 Issue 修复,合理的提交序列可能是:先✅补上暴露缺陷的回归测试,再🐛提交真正的修复代码,最后🚨(若涉及)清理 lint 告警——每个提交语义单一、可独立回滚。
八、工作流延伸:从修复到 Pull Request
fix-issue 的终点是"合规提交",但修复的落地上游还有一步——提交 PR。仓库 .github/pull_request_template.md 定义了 PR 模板,.claude/commands/create-pull-request.md 则给出配套命令:
gh pr create --draft --title "🐛(scope): Your descriptive title" --body-file .github/pull_request_template.md --base main要点包括:标题遵循 conventional commit + emoji 格式(如🐛(auth): Fix login redirect issue);所有 PR 内容必须使用英文;PR-Agent 的pr_agent:summary与pr_agent:walkthrough区块名称不得改动;工作进行中先以--draft创建草稿 PR,完成后用gh pr ready转正。这与 fix-issue 的提交规范同源,共同构成"Issue → 修复 → 提交 → PR"的完整闭环。
九、全流程速查
| 阶段 | 关键命令 / 操作 | 仓库依据 |
|---|---|---|
| 取 Issue | gh issue view <编号>,参数支持123/#123 | .claude/commands/fix-issue.md |
| 理解模板 | 对照 Bug 模板字段 | .github/ISSUE_TEMPLATE/1_bug_report.yml |
| 定位代码 | 按包结构 + 关键词搜索 | CLAUDE.md |
| 运行测试 | pnpm test/pnpm test:e2e/pnpm --filter <pkg> test | package.json |
| 质量门禁 | pnpm lint(= turbo lint + syncpack lint + knip) | package.json、lefthook.yml |
| 提交 | gitmoji + 描述性消息,禁止--no-verify | .claude/commands/commit.md、.claude/settings.json |
| 创建 PR | gh pr create --draft --body-file .github/pull_request_template.md | .claude/commands/create-pull-request.md |
总结
以.claude/commands/fix-issue.md为蓝图,liam 仓库把"修复一个 GitHub Issue"这件事拆解成了可被 AI Agent 稳定执行的八步流水线:gh issue view取数、按 monorepo 结构定位、遵守 "Less is more" 规范实现、按测试原则补回归用例、通过三层 lint 门禁、最后用 gitmoji 规范提交。这套工作流的价值在于,每一步都有仓库内的硬约束兜底——pre-commit hook、权限 deny 列表、syncpack/knip 检查——从而把"修复正确"从个人经验变成可重复执行的工程流程。对于希望用 AI Agent 参与开源维护的开发者,这套模式同样可以直接迁移到自己的仓库中。
【免费下载链接】liamAutomatically generates beautiful and easy-to-read ER diagrams from your database.项目地址: https://gitcode.com/GitHub_Trending/li/liam
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考