---
name: create-pr
description: 为 Yakit 仓库一站式完成提 PR 流程：提交工作区改动、调用 code-review skill 评审、推送远端后在 yaklang/yakit 创建或更新 PR。当用户要求提 PR、提交 PR、创建 PR、发 PR、raise/submit/open PR、"create PR"、更新已有 PR，或使用 /create-pr 时触发。
---

# create-pr

一站式：**commit → code review → push → 创建/更新 PR**。调用即授权 push / 创建 PR，不再逐步确认；commit 仍走 `commit-msg` 弹窗。不要整理历史 commit、改写远端、force push、合并 PR。

**不支持 fork**：origin 必须是 `yaklang/yakit`（PR 建在 `--repo yaklang/yakit`）。origin 指向个人 fork 时第 1 步停止，提示自行推送并用网页创建 PR。

## 交互与 skill 加载

文中 `AskUserQuestion` 指当前环境可用的交互工具（如 `request_user_input_async`）；工具用途允许时使用，无适用工具则在对话中询问。需要回答时等待用户真实答复，异步请求待答、超时或空结果不算同意；本次会话已明确的选择或授权直接沿用。

通过当前环境的加载机制调用 skill；没有专用 `Skill` 工具时，直接读取真实 `SKILL.md` 及其所需 references 并遵循。工具缺失不等于 skill 缺失，只有找不到或读不到 skill 内容才走缺失分支。

## 输入（均可选，可同时出现）

从用户原文识别，不要追问、不要猜测、不要搜索：

1. **合并方式**：`merge` / `squash` / `rebase` 或「合并提交 / 压缩合并 / 变基合并」。有则直接用，不走自动规则。
2. **关联**：本仓库 issue（`close` / `fix` / `ref #xxxx`）与其它仓库 PR URL（如 yaklang 引擎）。**仅用户明确提供时写入**。都没有则「关联 Issue / PR」填 `None`。

## 1. 前置检查

- 获取分支：`pr_branch="$(git branch --show-current)"`；命令失败、分支名为空（detached HEAD）或为 `master` 时停止。
- 以下 Bash/Zsh 示例通过 `"$pr_branch"` 传递分支名；每次独立 shell 调用须先执行上述赋值并检查结果。不得将读出的分支名回填进 shell 命令文本或交给 `eval`；其他执行工具使用参数数组或对应 shell 的安全变量传参。
- `git remote -v`：origin 必须是 `yaklang/yakit`，否则停止（fork 按上方提示）。
- **gh**：`command -v gh` + `gh auth status`（PowerShell：`Get-Command gh`）。已装且已登录则继续；否则走下方降级，**不要直接停止**。
- **`code-review` skill 必须存在**（第 3 步强制依赖；外部指定范围时直接执行、不弹框）。不存在则**立即停止**，不要自行评审——此时尚未 commit / push。
- `git fetch origin master`；PR base 固定 `master`。
- `git status` + `git log origin/master..HEAD --oneline` 摸底。无 commit 且工作区无改动 → 停止。
- gh 可用时先查重并保存旧 PR 快照，供评审历史问题与第 5–7 步复用：

  ```bash
  gh pr view "$pr_branch" --repo yaklang/yakit --json number,url,state,title,body
  ```

  仅明确返回「该分支无 PR」才按新建处理；认证、网络或其它查询失败 → 停止并报告错误，不得当作不存在。手动模式跳过查询；用户提供旧描述时采用其内容。

### 🔴 CHECKPOINT：gh 降级（未安装或未登录）

`AskUserQuestion` 二选一（question 说明当前 gh 状态）；Other 取消则停止：

- **安装并登录 gh**：macOS `brew install gh`；Windows `winget install GitHub.cli`（或 scoop / choco）；Linux 提示官方安装。装完让用户自行 `gh auth login`（交互式，agent 不能代办），确认后**回到第 1 步重检**。安装或登录失败则停止。
- **手动创建 PR**：第 1–6 步照常，第 7 步改「手动模式」（不跑任何 `gh`）。

## 2. 处理工作区改动

`git status`（含未跟踪）。干净则跳过，不空提交。**🔴 CHECKPOINT：未提交改动的处理选择**，`AskUserQuestion`（概述如「3 个已修改 + 1 个未跟踪」）；Other 取消则停止：

- **提交为一个 commit**：`git add -A`，生成**一个** commit。优先按上述加载机制调用 `commit-msg`；找不到或读不到该 skill 时按其规范自行做（确认完整 message 与范围 → 保留换行写临时文件 → `git commit -F`；基于 diff 按实际改动类型归纳，每种类型一行 `type: subject`、中文为主、每行 72 字符内、不带 `(#PR号)`）。**终态核验**：仅当 `COMMITTED` 且 `git rev-parse HEAD` 已前移、`git diff --cached` 为空才进第 3 步；`CANCELLED` / `FAILED` 或核验不符 → **STOP：停止整个流程**，不得带着旧 HEAD 评审或推送。
- **stash 暂存**：`git stash push -u -m "create-pr: 暂存未提交改动"`。本次 PR 不含这些改动；报告 stash 已创建，**不要自动 `stash pop`**。

## 3. 代码评审（强制，推送前）

对象：`git diff origin/master...HEAD`（第 2 步之后的最终 HEAD）。只读：只记录问题，不顺手修（含 P0）。

- 评审开始记录 `git rev-parse HEAD` 完整 SHA。
- **必须按上述加载机制调用 `code-review`**，范围为本分支 vs `origin/master`（已指定范围，不弹框）。找不到或读不到该 skill → 停止，不要自行评审。更新 PR 时同时复核快照中的历史问题（含已修复项），记录当前证据；未复核不能认定已修复。
- 从报告提取：P0+P1 全部（警告不写入 PR）→「建议合并前修复的问题」；「三、合并结论」的结论（不通过 / 需要修复 / 可以合并）与统计行 →「代码评审结论」（必需）。每条问题记 `文件:行号` + 一句话。结论只能来自实际 code-review 输出，不得编造。

## 4. 推送远端

- 推送前再 `git rev-parse HEAD`，与第 3 步 SHA 一致才继续；不一致则停止。
- **禁止裸 `git push`**。执行 `git push -u origin "HEAD:refs/heads/$pr_branch"`（显式 origin）。
- 推送后：`git ls-remote origin "refs/heads/$pr_branch"` 的 OID == 本地 HEAD，否则停止。
- push 被拒（远端有本地没有的提交）：停止，不要 pull / rebase / force push。

## 5. 生成 PR 标题与描述

**标题**（`git log origin/master..HEAD --format='%B'` 读取全部 commit 的完整 message，**不用分支名**）：单行 `type: subject`（中文为主、无句号、不带 `(#PR号)`、尽量 72 字符、中文按 2 计）。仅一个 commit 且 message 只有一行时可直接沿用；多行 message 或多个 commit 时归纳主语义为一行 PR 标题（type：feat/fix/docs/style/perf/refactor/test/build/ci/chore）。

更新已有 PR：旧标题 == 分支名 → 换成总结标题；旧标题 ≠ 分支名 → **保留旧标题**。

**描述**：先读 `.github/PULL_REQUEST_TEMPLATE.md`（不要默写），按模板填，可删 HTML 注释但**保留全部小节**。更新 OPEN PR 时用第 1 步快照，按第 7 步规则迁移旧字段与问题状态。模板不存在时用 [`references/pr-examples.md`](references/pr-examples.md) 的约定结构；「合并方式」仍须三项 checkbox，不得写成单行。无法从 diff / log / 用户输入确认的信息标「待补充」，创建前向用户说明。正例与同步示例见该 references。

- 改动类型：读取本 PR 全部 commit 的完整 message（含多行 `type: subject` / `type(scope): subject`），以其中的类型为线索，结合 `origin/master...HEAD` 的实际改动归纳并去重后全部勾选，不限数量，不受 PR 标题的单一 type 限制。映射到模板：feat → 新功能、fix → Bug 修复、docs → 文档改动、style → 样式 / UI 调整、perf → 性能优化、refactor → 重构、test → 测试改动、build → 构建 / 依赖 / 打包配置、ci → CI 流程改动、chore → 杂项。无法识别类型时结合 diff 判断，不把 message 正文中的普通文字当作类型。
- **fix 归因**：检查修复前后的代码、相关提交及 `origin/master` 中的对应行为。若只是修补本分支新增 feat 引入的问题，归入该 feat，不额外勾选 Bug 修复；只有本 PR 修复了基线已有的问题，才新增该勾选。同一 PR 同时新增功能并修复基线问题时，feat 与 fix 都勾选。不能只按 commit 前缀、提交顺序或文件是否新增判断；证据不足时标注待确认，不自动勾选 fix。更新已有 PR 时，用户原有勾选仍按第 7 步保留。
- 🔗 关联 Issue / PR：用户明确提供的 issue（`close` / `fix` / `ref #xxxx`）与跨仓库 PR URL；都没有填 `None`。不要编造编号或链接。
- 💡 背景与方案：原先问题 → 本次做法；基于全量 diff，不逐文件罗列。
- 影响范围：用户可见行为变化；纯重构写「不改变用户可见行为」；UI 变化建议附截图。
- 合并方式：勾选第 6 步选定的一项。

**模板外追加**（插在「影响范围」之后、「合并方式」之前）：

```markdown
## 代码评审结论

**结论：不通过**（正确 6 项 / 问题 3 项（P0 1 项 / P1 2 项）/ 警告 2 项）
```

必需小节；放在「建议合并前修复的问题」**之前**。更新已有 PR 时**每次覆盖重写**。

```markdown
## 建议合并前修复的问题

- [ ] `src/xxx.ts:123` <问题描述>
```

第 3 步全部 P0+P1；已修复 `- [x]`。无此类问题则省略整节。更新已有 PR 时该节**累积保留**（含已标注已修复的），不得因重生成描述而丢失；是否已修复以本次评审为准，同步规则见第 7 步。

## 6. 合并方式选择

1. 用户本次指定 → 直接用。
2. 更新 OPEN PR 且用户未指定 → **保留旧描述「## 合并方式」已勾选的方式**（`gh pr edit --body` 是整段替换）。无该小节或三项都未勾选 → 优先级 3。
3. 自动（新建，或更新但旧描述无有效勾选）：`git log origin/master..HEAD --format='%an'` 去重作者数 + commit 总数，**从上到下**：

| 顺序 | 条件 | 方式 |
| --- | --- | --- |
| 1 | 作者 ≥ 2，**或** commit > 3 | merge |
| 2 | commit = 1 | rebase |
| 3 | commit 2–3 且同一作者 | squash |

描述里勾选对应一项，**保留三项完整文案**（与模板一致）：

```markdown
## 合并方式

- [ ] Create a merge commit（保留完整提交历史）
- [x] Squash and merge（压缩为一条提交）
- [ ] Rebase and merge（线性历史）
```

判断示例见 [`references/pr-examples.md`](references/pr-examples.md)。

## 7. 创建或更新 PR

gh 可用时按第 1 步快照选择以下分支，不重复生成已确定的字段；用户选了「手动创建 PR」则跳到文末「手动模式」。

动态文本（正文 / 标题）**禁止内插进 shell**：先写入系统临时目录下的临时文件（下文用 `<pr-body-file>` 代指），用 `--body-file`，用完删除。title 用单引号包裹并对内部单引号转义。

- **已有 OPEN PR**：**不新建**，`gh pr edit` 更新描述，且**每次都必须带 `--title`**（第 5 步智能替换后的最终标题；省略 `--title` 可能改掉标题）：

  写入前按 PR 编号重新读取 `number,url,state,title,body`。查询失败则停止；状态已非 OPEN 则停止并报告，不能继续 edit。若标题或正文与快照不同，以最新内容替换快照，复核新增或变化的历史问题，并重新执行第 5–6 步及下方迁移规则后再写入，避免覆盖评审期间的修改。

  ```bash
  gh pr edit <PR number> --repo yaklang/yakit --title '<最终标题>' --body-file /tmp/pr-body.md
  ```

  第 5 步生成描述时，按快照中的旧描述应用以下规则：

  - **改动类型**：保留旧小节所有已勾选项，再补勾第 5 步结合 diff 和基线归因确认的类型；不取消用户已有勾选，不重复新增条目。全未勾或无该节时按第 5 步生成。
  - **关联 Issue / PR**：旧内容非 `None` 则保留；本次用户又提供新关联则合并去重；旧为 `None` 且本次未提供才填 `None`。
  - **合并方式**：第 6 步优先级 2。
  - **建议合并前修复的问题**：依据第 3 步本次评审与复核证据同步，不删除历史条目（含旧「## P0 问题」）：
    - 所有状态转换均更新原条目，按时间顺序保留历次修复哈希与复发记录；再次修复时追加本次修复记录，证据不足或修复提交未定位时也不得丢弃已有历史。同一状态、同一证据的重复复核不重复追加记录。以下格式仅示意当前状态，不能覆盖已有历史；旧「本次复核」转为历史时改称「曾复核」。
    - 当前证据确认已修复：`- [x] ~~<原问题>~~（✅ 已修复：<核实的修复短哈希>）`；无法定位修复提交时写「本次复核确认，修复提交未定位」，不编造哈希。
    - 曾标已修复、当前确认同一缺陷复发：原条目改为 `- [ ] <原问题>（曾修复：<原短哈希>；本次复核：已复发）`，去掉删除线，保留修复历史，不追加重复条目。
    - 当前证据不足：保留原问题，标 `- [ ]` 和「待复核」；原已修复标注改为「曾标已修复：<原短哈希>」，不得当作本次确认修复。
    - 仍未修复：原样保留；旧普通列表改为 `- [ ]`；新问题 `- [ ]` 追加。
    - 旧无该节且本次也无 P0/P1：不生成该节。

  完成后报告：PR 链接、已更新描述、合并方式（沿用旧勾选 / 本次指定 / 自动）、评审结论与统计、关联信息、建议修复项及状态。

- **已有 CLOSED / MERGED PR**：**不要更新、不要 reopen**，按下方**新建**；新描述按第 5 步生成，不迁移旧 PR 历史。
- **没有 OPEN PR**（not found，或仅有 CLOSED / MERGED）：

  ```bash
  gh pr create --repo yaklang/yakit --base master --head "$pr_branch" --title '<commit 总结标题>' --body-file /tmp/pr-body.md
  ```

  标题为第 5 步基于全部 commit 的 `type: subject`（多 commit 不照搬单条 message）。成功后报告：链接、标题、合并方式、评审结论与统计、关联信息、建议修复项（如有）。

- create 报「A pull request already exists」：先按第 1 步重新读取 `number,url,state,title,body`；查询失败则停止。确认 OPEN 后复核其历史问题，按第 5–7 步更新规则重新生成标题、描述与合并方式，再 `gh pr edit`（必须带 `--title`）；不得用新建描述覆盖旧字段。若已 CLOSED / MERGED，停止并报告状态，不反复 create。
- **回读验证**：`gh pr view <PR number> --repo yaklang/yakit --json title,body --jq '{title: .title, body: .body}'`（编号：更新用查重结果，新建用 create 输出链接中的编号，避免旧 closed PR 干扰）。① 标题 == 第 5 步最终标题（新建 = 总结标题；更新 = 智能替换），不符则 `gh pr edit ... --title '<最终标题>'`；② 描述含完整「## 合并方式」且勾选与第 6 步一致，不符则再 `gh pr edit`。两点都过才能向用户报告。

用户只要求生成描述不创建时，按实际要求裁剪步骤，不要强行走完全流程。

### 手动模式

前 6 步照常；本步不执行任何 `gh`、**不写任何文件**，标题与描述在对话框展示后结束（创建结果由用户自行处理）：

1. **PR 标题**：单独代码块（第 5 步总结标题）。
2. **描述全文**：代码块展示 markdown **源码**（不截断、不渲染）。
3. 创建入口：`https://github.com/yaklang/yakit/compare/master...<当前分支>?expand=1`。无法自动查重，提醒先看页面是否已有 PR。
4. 读不到旧 PR 描述，默认不含旧勾选 / 关联 / 合并方式 / 累积问题。用户若把旧描述全文贴给 agent，按第 7 步同步规则合并；未提供则提醒在网页编辑器自行合并。
