repo-sync · git:20261102.7c0d61e · 2026-11-02 · sha256 b71e7245b0b40ac9

repo-sync git:20261102.7c0d61eA

Immutable. This exact content never changes and is served at /api/v1/blob/b71e7245b0b40ac9.

---
name: repo-sync
description: modelmux 仓库的收尾与同步流程:把一轮代码改动同步到 docs 文档、规划进度与 commit 历史,并在需要上线时走完分支 → PR → CI → rebase merge → 删分支的闭环。用户说「收尾」「同步文档」「更新 plan/进度」「做好 commit/PR/merge」「整理提交历史」「结项」时必须使用本技能,即使没有明确点名。
---

# repo-sync —— 仓库收尾与同步

本技能覆盖 modelmux 仓库的**一轮工作如何收尾**:代码改完 ≠ 完成。必须同步 docs、
规划与 commit 历史;需要推送到远端时再走 PR 闭环。规则源头是根 `AGENTS.md` 与
[docs/AGENTS.md](../../../docs/AGENTS.md),本技能是**可执行的操作手册**;冲突时以前两者为准。

## 0. 事实基线(动手前必须先跑)

```bash
git status --short            # 工作树状态
git branch --show-current     # 当前分支(大改造禁止在 main 上)
git fetch --prune             # 先 prune,否则已删的远端分支仍会出现在 branch -a
git log --oneline -5          # 最近历史与提交风格
git rev-list --left-right --count main...origin/main   # 本地与远端差多少
```

判定「大改造」(必须开分支,命中任一即算):

- 改动跨越 `packages/` 下两个及以上包;
- 涉及目录结构、包边界、`workspaces`、`tsconfig` references 的调整;
- 涉及契约(`docs/CONTRACT-TS.md`)、存储落点、池架构的规则修改;
- 对外 API 形态或模型 id 形态变更;
- 预计改动超过 20 个文件。

分支名:`feat/<模块>` / `fix/<模块>` / `refactor/<模块>`,从**最新 main** 创建。

**节奏**:大改造立即开分支并走完整 PR 流程;小改动(单包/单文件/文档/注释/UI 微调)
先在 `main` 本地攒 commit,攒够一批或需要让改动生效时再一次性走 PR —— 不要一个 commit
开一个 PR。

## 1. 文档同步矩阵(代码改了哪些地方 → 哪些文档必须跟着改)

文档分层、事实归属与写作规则以 [docs/AGENTS.md](../../../docs/AGENTS.md) 为准;本表只列
代码改动对应的文档落点。

| 改动落点 | 必须同步的文档 |
| --- | --- |
| 契约 / CLI 形态 / 模块边界 / 分层 | `docs/CONTRACT-TS.md`、根 `AGENTS.md` 的「代码约定」 |
| **代码注释(渠道包 `src/` 与共享层模块的文件头 / docstring)** | **必须对照 [`docs/MODULE-COMMENTS.md`](../../../docs/MODULE-COMMENTS.md) 校验**(见下方「注释格式检查」) |
| 池(模型池 / 账号池 / 账本 / 路由) | `docs/POOL-ARCHITECTURE.md` |
| 存储落点 / 文件命名 / 权限 | `docs/STORAGE-CONVENTION.md` |
| 进程模型 / 监督者 / 守护 | `docs/DAEMON-SUPERVISOR.md` |
| 日志落点 / 字段 / 轮转 | `docs/LOGGING.md` |
| Web 控制台(页面 / API / 主题) | `docs/WEB-CONSOLE.md` |
| 引流入口 / 安装 / 接入方式 | 根 `README.md`(全中文,GitHub 只渲染它) |
| 某渠道的协议 / 端点 / 头部 / 限制 / 实测 | `docs/channels/<cid>/PROTOCOL.md`(含「使用与实测」「参考实现」小节) |
| 新增/改名/删除任何 `docs/*.md` | `docs/README.md` 索引(同步更新) |
| 新增/改名/删除渠道目录 | `docs/README.md` 与 `docs/channels/README.md` 两张表都要登记 |

### 代码注释整改(强制)

**只要动了代码注释,收尾前逐条对照 [`docs/MODULE-COMMENTS.md`](../../../docs/MODULE-COMMENTS.md)
的三层分工** —— 注释与文档出现双份事实源是最常见的腐化路径:

1. **what 去文档**:协议事实(端点、字段、状态码、实测数字)只活在
   `docs/channels/<cid>/PROTOCOL.md`。代码注释里出现同一事实的副本 = 违规 ——
   删副本,留一行指针(如「端点/字段/实测见 docs/channels/<cid>/PROTOCOL.md」)。
2. **why 跟函数**:设计取舍写在被治理函数的 docstring 上。
   **不写日期、不写实验记录、不写「推翻了某结论」的时间线** —— 那些属于
   PROTOCOL.md 的证据等级体系;docstring 只留影响代码行为的 why。
3. **文件头只做导航(≤ 12 行)**:一句话职责 + 关键约束 ≤ 3 条 + 铁律一行(如需要)+
   指引到 PROTOCOL.md。头部出现大段实测记录、多个日期 = 违规 —— 下放文档,头部瘦身。
4. 口诀:**what 去文档、why 跟函数、头部只做导航**。

机械下限由 `npm run verify:comments` 守(R1 文件头 ≤ 12 行、R2 署名与审批留痕、R3 修订记录、
R4 TODO/@deprecated 条件);它只拦零误报的硬违规,语义层(协议事实副本、指向已删文件的过时指针)
仍需按上面三条人工过一遍。

### md 文档整改(强制,每轮收尾)

`.md` 只描述**当前状态**:自指变更史、实施状态注解、变更箭头与 TODO 标记都属于历史,归 git。
每轮收尾先扫一遍、再逐条判断:

```bash
grep -rnE '此前|原先|曾经|旧版|早期|改造前|修复后|结论已反转|本次实现|已落地|已实施|已完成|待实施|部分实现|<!--' \
  docs README.md AGENTS.md packages/core/channels/*/AGENTS.md --include='*.md'
```

- **改**:「此前是 X,现在改成 Y」写成当前规则本身;「已实现 / 已完成」从正文与标题去掉;
  指向已改名章节的引用(如 `AGENTS.md` 的「命令与构建」)改成实际章节名。
- **留**:外部事实的实测证据(上游行为、限流、真机数字 —— 日期必须留)、影响行为的 why、
  `docs/AGENTS.md` / `CODE-COMMENTS.md` 里作为反例的词、设计依据文档顶部的一行状态、
  `PROGRESS.md` 与渠道 `ROADMAP.md` 的状态表、`WALKTHROUGH` 类过程记录。
- 改完必须 `node scripts/verify-docs.mjs` 通过(相对链接与索引登记会拦)。

落点约束(`scripts/verify-docs.mjs` 会拦):`.md` 只允许落在 `docs/`(含
`docs/channels/<cid>/`)、根 `README.md` / `AGENTS.md`、
`packages/core/channels/<cid>/AGENTS.md`、`.agents/skills/<name>/` 与
`.zcode/skills/<name>/`(后两者是**整包**,允许 `references/`、`scripts/`)。
渠道包只放实现,不再带 `docs/`。

`verify-docs` 检查的是落点、索引登记、渠道 PROTOCOL 缺失、README 样板与相对链接死链;
「文档与代码同一 commit」「中文、无 emoji」「注释同步」属于**评审约束**,它不检查。

## 2. 规划同步

- 多步任务用 `planning-with-files` 技能的 `.planning/<PLAN_ID>/`(`task_plan.md` /
  `progress.md` / `findings.md`);阶段状态变化后立即更新。
- 记录踩过的错误与解决方式(防重复踩坑)。
- 结项:`.planning/` 与 `.zcode/plans/` 是过程文件(已 gitignore),任务结束删除;
  需要时从 git 历史取,不设 `archive/`。

## 3. 提交规范

1. 一次逻辑变更 = 一个提交;能合并的不要拆碎。
2. 信息格式 `type(scope): 中文描述`,scope 必填,结尾不加句号;
   type ∈ feat/fix/docs/style/refactor/perf/test/chore(merge 仅限合并提交)。
3. 提交信息写入 `.tmp/commit-msg.txt`,用 `git commit -F` 提交 —— 多行中文内联进 shell
   会被引号与换行破坏。
4. 换行一律 LF;提交前 `git status` / `git diff` 自查,敏感信息(token/密码/密钥/
   .env)绝不入库。

## 4. 分支 → PR → CI → merge(需要推送时执行)

```bash
# 1) 从最新 main 开分支并提交
git checkout main && git pull origin main
git checkout -b fix/<模块>
git add <files> && git commit -F .tmp/commit-msg.txt

# 2) 【推送前必须】本地推送门禁:与 CI 等价,全绿才推
npm run gate

# 3) 推送(.githooks/pre-push 会自动再跑一次同一门禁)
git push -u origin fix/<模块>

# 4) 建 PR(gh 优先;标题必须合规)
gh pr create --title "fix(<scope>): 中文描述" --body-file .tmp/pr-body.md

# 5) 等 CI 双绿(node 22 / node 24)再合并
gh pr checks <n>
```

- **推送前必须先 `npm run gate`**(干净 clone 里 `npm ci` + `npm test`):开发工作树与
  ubuntu-latest 有真实差异(git 历史深度、平台原生依赖、未提交改动与陈旧产物),
  在工作树上跑绿不代表 CI 会绿。`pre-push` 会对**所有推送**全量再跑一次 `npm test`,
  它是兜底拦截,不是提前发现,也不按文件范围分流。
- **改了 `.github/workflows/**` 必须本地先跑通再推**:workflow 的失败模式通常只有真跑
  产物才暴露。演示站点的 `demo-pages.yml` 要本地验三件事:`DEMO=1 DEMO_BASE=/<repo>/`
  构建后资源引用带前缀、`index.html` 复制成 `404.html` 后深链能渲染、Pages 源为
  `build_type: workflow`。workflow 改动仍以 `npm run gate` 为准;
  本机没有 `act`,不要假设能用 act 复现。
- 合并统一用 **`gh pr merge <n> --rebase`**(保持线性历史,禁止 merge commit)。
  rebase 保留分支内的各条提交信息;PR 标题只有在 squash 时才会变成提交信息
  (`merge_commit_title=PR_TITLE`)。`verify:commits` 校验的是提交,不是 PR 标题。
- **禁止** `--no-verify` 绕过 pre-push;CI 红着时禁止继续推送新提交。
- 合并后:删远端分支(`gh api -X DELETE repos/bluechonk/modelmux/git/refs/heads/<branch>`)、
  `git fetch --prune`、`git checkout main`、`git reset --hard origin/main`(rebase 会重写 SHA,
  本地与远端分叉属正常)、删本地分支,再确认 main 的 CI 双绿。

### 4.1 发版:**只打 tag,绝不建 Release**(主人明确要求,违反即返工)

```
发版 = 改版本号落点 → chore(release) 提交 → PR 合并 → 在 main 打 vX.Y.Z tag → 停。
```

- **禁止** `gh release create` / `gh release edit` / `gh release upload`,
  **禁止**用全局 `github:release` 技能,**禁止**点 GitHub 网页的「Draft a new release」。
  与全局 `~/.agents/AGENTS.md`「标签与发布」里「打 tag → 出 Release」冲突时**以本仓规则为准**
  (本仓细则见 [docs/WORKFLOW.md](../../../docs/WORKFLOW.md) 的「版本与发版」)。
- 为什么:本仓没有发布物 —— 没有 `npm publish`、没有产物打包 workflow、没有 exe/安装包,
  发布物只有 **web 控制台 + CLI 源码**。Release 页面承载的「版本说明」的权威来源是 `git log`,
  多一个页面就多一份会漂移的事实源(主人原话:「我又不做 exe,我只做 web 和 cli」)。
- 打 tag 前先过推送门禁;tag 只打在**合并后的 main** 上,不打开发分支。
- **Releases 页必须保持为空**(含 draft):`gh release list --repo bluechonk/modelmux` 要**没有输出**,
  `gh api repos/bluechonk/modelmux/releases` 要是 `[]`。若发现残留(历史遗留也算),
  删掉并**保留 tag**:`gh release delete <tag> --yes`(⚠ 别加 `--cleanup-tag`,那会连 tag 一起删)。
- 删除 Release 与「发布」无关,不影响 tag、不影响任何产物 —— 本仓本就没有发布物。

## 5. 收尾检查清单(一条都不能漏)

```bash
npm run build                  # 全仓编译(含 ui + bundle + copy-ui)
npm test                       # build + typecheck + 全部 verify:* + 全部包测试,必须全绿
node packages/cli/dist/cli.js restart   # 改了 packages/core/** / cli / ui 必须重启
node packages/cli/dist/cli.js status    # 必须不含「网关在跑旧代码」
# 真机验证:见下方分工
node scripts/verify-docs.mjs            # 文档整改复查:落点 + 链接 + 索引登记(§1「md 文档整改」)
npm run verify:comments                 # 代码注释整改下限:文件头 / 署名 / 修订记录 / TODO 条件(§1)
git status                     # 工作树干净(无未提交 tracked 文件)
git fetch --prune && git branch -a      # 本地/远端只剩 main
gh release list --repo bluechonk/modelmux   # 必须没有任何输出(含 draft;§4.1)
git tag -l                      # tag 才是发布物,必须都在
ls .tmp                        # 清理临时文件;截图与诊断产物不留仓库
```

验证分工(不要在本技能里重复展开细节):

- `mx` 命令用法与坑 → `mx-cli` 技能;
- 日志与失败码 → `log-triage` 技能;
- 渠道端到端验收 → `opencode-mx-test` 技能;
- 跨会话核对进度 → `zcode-session-archaeology` 技能。

- 涉及登录/凭据/上游的改动:必须 `mx login <cid>` → `mx status <cid>` → 真实对话。
- 双实例(如 4413 调试实例):重启后确认 `health=200`;日志按**分层目录**落
  (`~/.modelmux/logs/system/<日期>/`,实例各自写自己的 `worker.log`),见
  [`docs/LOGGING.md`](../../../docs/LOGGING.md) §2。
- 在 linked worktree 里收尾:先读 `AGENTS.md` 的「Worktree 约束」;删分支前先
  `git worktree remove` + `git worktree prune`。

## 6. 常见错误(都真机踩过)

| 错误 | 后果 | 正确处理 |
| --- | --- | --- |
| 只 push 不建 PR / 合并后不删分支 | 分支残留、历史碎 | 走完 §4 全流程 |
| PR 标题写英文/无 scope | squash 时提交信息不合规 | 标题必须是 `type(scope): 中文` |
| 一次提交后立刻开 PR | 历史碎片化 | 小改动先本地攒批次 |
| 未提交就继续做新任务 | 改动混批、历史难看 | 每轮收尾再开工 |
| 文档里写自身变更史 / 实施状态(「此前…」「已落地」) | 越写越像流水账,与 git 重复 | 按 §1「md 文档整改」清掉,只留当前状态与外部证据 |
| `git add -u` 漏掉新文件 | CI 构建失败(UNRESOLVED_IMPORT) | 新文件用 `git add <path>` |
| 改了代码没 restart | 验证的是旧进程 | build → restart → status 无陈旧 |
| **给本仓建了 GitHub Release**(`gh release create` / `github:release` 技能 / 网页 Draft) | 主人明确禁止:本仓发布物只有 tag,Release 页是多余事实源 | 只打 tag(§4.1);已建的要删掉并保留 tag:`gh release delete <tag> --yes` |
| 本地绿但推送门禁红 | 平台/依赖差异(如漏提交新文件) | 用门禁同款命令在干净 clone 复现 |
| `.tmp` 被删后重定向失败 | 测试没跑却以为绿了 | 先 `mkdir -p .tmp` |
| 合并后本地 `git pull` 冲突 | rebase 重写了 SHA,同内容不同源 | `git fetch --prune` 后 `git reset --hard origin/main` |

## 7. 输出要求

收尾完成后给用户一份简短清单:本轮提交(SHA + 一行说明)、PR 编号与合并方式、
CI 状态、真机验证结论、分支/工作树/临时文件状态、以及**需要用户配合的事项**
(如需要真实账号的登录验证)必须单独列出,不能混在「已完成」里。

### Agent 交付说明(每轮变更的固定格式)

除清单外,每轮代码变更附一段结构化说明 —— 便于复盘、CR 与跨会话对齐:

```text
变更范围:<packages/xxx / docs/xxx / scripts/xxx>
变更目的(Why):<解决了什么问题 / 为什么要做>
关键取舍与风险:<选了什么、放弃了什么、已知边界>
测试点:<验证了什么(命令 / 真机步骤),没验证的写明原因>
关联项:<PR / issue / 计划文件路径,无则「无」>
```