同步上游 EGM
將 marcus-darden/egm 的變更帶入此移植版本,同時保留移植後的名稱變更、Cursor 適配或移植專屬檔案。請先閱讀儲存庫根目錄的 AGENTS.md:這是本技能適用的規則手冊。本技能位於 .cursor/skills/,是專案本機的技能;install.sh 不會安裝它。
以 /egm-sync-upstream [--dry-run] [upstream-ref] 叫用。upstream-ref 預設為上游的 main。加上 --dry-run 時,執行步驟 1 到 4 並印出計畫,不做任何更動。
嚴格規則
- 絕不推送到
main。 所有工作都在sync/upstream-<shortsha>分支上進行;Juan 負責合併 pull request。 - 絕不覆寫移植專屬檔案(列表在
AGENTS.md中)。如果上游變更了那些檔案所鏡像的內容(例如上游 README 的安裝章節),請在報告中描述,而非直接修改。 - 不要猜測。 新的上游技能或代理、被刪除的上游檔案、被重新命名的上游檔案以及合併衝突,都應標記給 Juan,並附上確切路徑,不要自行發明名稱或選擇一方。
- 保留出處標示。
LICENSE保留兩項版權聲明;UPSTREAM_COMMIT僅在分支實際包含上游變更時才移動。
輔助工具
<skill-dir> 是存放此檔案的資料夾。
python3 <skill-dir>/scripts/port_names.py path <upstream-path>...將上游路徑對應到移植路徑,並指出路徑是移植專屬、未移植或新的。python3 <skill-dir>/scripts/port_names.py merge <clone> <old> <new> <upstream-path> [--write]對一個上游檔案變更與其移植檔案進行三方合併(基礎和他們的版本會先改寫成移植名稱,我們的版本是移植檔案),如此一來,未改動行中的 Cursor 適配就會保留。退出碼 0 表示乾淨,1 表示留下衝突標記,3 表示無需動作(移植專屬、未移植或新的)。python3 <skill-dir>/scripts/port_names.py rewrite <file>/check <file>...改寫文字中的名稱,或列出殘留的舊斜線名稱。bash <skill-dir>/scripts/check_port.sh執行所有移植檢查(步驟 7)。
工作流程
EGM 同步進度:
- [ ] 步驟 1:工作目錄乾淨,且在最新的 main 分支上
- [ ] 步驟 2:上游已複製到暫存目錄;old = UPSTREAM_COMMIT,new = 上游 HEAD
- [ ] 步驟 3:讀取自 old 以來的 CHANGELOG 條目;列出已變更的檔案及其狀態
- [ ] 步驟 4:每個已變更的檔案都經過對應和分類(合併 / 標記 / 跳過)
- [ ] 步驟 5:建立 sync/upstream-<shortsha> 分支;套用合併;重新檢查適配
- [ ] 步驟 6:更新 UPSTREAM_COMMIT
- [ ] 步驟 7:check_port.sh 通過
- [ ] 步驟 8:撰寫 SYNC-REPORT.md
- [ ] 步驟 9:推送分支;用 gh 開啟 PR;通知 Juan
步驟 1:乾淨的開始
git status --porcelain 必須為空,且當前分支為 main,並與 origin/main 同步(git fetch origin && git status -sb)。否則,停下來告訴 Juan 哪些東西是髒的。不要暫存他的工作。
步驟 2:擷取上游
tmp="$(mktemp -d)"
git clone --quiet https://github.com/marcus-darden/egm.git "$tmp/upstream"
old="$(cat UPSTREAM_COMMIT)"; new="$(git -C "$tmp/upstream" rev-parse ${REF:-HEAD})"
如果 old == new,回報「自 以來上游沒有新提交」並停止(不建立分支,不發 PR)。如果 old 不是 new 的祖先(git -C "$tmp/upstream" merge-base --is-ancestor $old $new),上游改寫了歷史:停下來並標記。
步驟 3:讀取變更內容
git -C "$tmp/upstream" log --oneline $old..$newgit -C "$tmp/upstream" diff --name-status -M $old $new- 新的
CHANGELOG.md條目(包含old的標籤之後的標籤)。CHANGELOG 說明了原因;在報告中引用相關行。
步驟 4:對應和分類每個檔案
對每個變更的上游路徑執行 port_names.py path,然後將每個路徑放入一個類別:
| 上游狀態和對應 | 類別 |
|---|---|
| M,對應到現有的移植檔案 | 合併 |
A,對應到已知的技能資料夾(例如 skills/goldfish/ 中的新資產) | 合併(建立檔案) |
| A,新的技能、代理或逐步指南(「NEW」註記) | 標記:Juan 選擇 egm- 名稱以及是否移植它 |
| D(上游已刪除) | 標記:不要刪除移植檔案 |
| R(上游已重新命名) | 標記:顯示舊路徑和新路徑以及移植路徑 |
| 移植專屬或未移植的註記 | 跳過(如果變更很重要,例如 README 安裝文字,則描述它) |
LICENSE | 合併,然後確認兩項版權聲明都保留 |
使用 --dry-run 時,印出這張表格和提交列表,然後停止。
步驟 5:在分支上套用
git switch -c "sync/upstream-${new:0:7}"
python3 <skill-dir>/scripts/port_names.py merge "$tmp/upstream" $old $new <upstream-path> --write
對每個合併檔案執行一次合併。若退出碼為 1,則不要將衝突標記納入提交中:還原檔案(git checkout -- <port-path>),並在報告中記錄衝突區塊給 Juan。合併之後,針對 AGENTS.md(Task-tool spawn 文字、代理中的 readonly: true、與 CLAUDE.md 並列的 AGENTS.md、審閱者忽略 AGENTS.md 和 .cursor/rules/、/review 而非 /code-review、runtimes.md 中的 Cursor 行)中列出的每個觸及檔案,重新檢查 Cursor 適配。如果上游新增了一個需要適配的地方(例如新的 CLAUDE.md 查閱、代理中新的 tools: 行、新的 Claude 專屬 spawn 指令),則套用相同的適配並在「已適配」下列出。以邏輯分組進行提交,並在提交訊息中引用上游提交。
步驟 6:移動指標
僅在每個合併檔案都乾淨合併或其衝突已記錄的情況下,才將 new 寫入 UPSTREAM_COMMIT。最後提交它。
步驟 7:檢查
bash <skill-dir>/scripts/check_port.sh。它會檢查名稱是否等於資料夾、評估 JSON、check_gate.py(BLOCKED 然後 GO)、殘留的舊斜線名稱,以及對暫存目錄進行測試安裝(不得包含此技能)。修復由合併引起的失敗;其他任何問題都放入報告中。
步驟 8:SYNC-REPORT.md
在分支的儲存庫根目錄寫入 SYNC-REPORT.md,並使用與 PR 內文相同的文字:
# 上游同步:<old7>..<new7>
上游提交:<列表>
CHANGELOG:<引用的行>
## 已套用
- <移植路徑> <- <上游路徑>:<一行說明>
## 已為 Cursor 適配
- <移植路徑>:<哪項適配及其原因>
## 已略過
- <上游路徑>:<移植專屬 | 未移植>,<變更內容,若重要的話>
## 已標記給 Juan
- <新技能/代理、刪除、重新命名、衝突>:<路徑、區塊、問題>
## 檢查
<check_port.sh 摘要>
## 待解決問題
- <...>
步驟 9:推送並開啟 PR
git push -u origin "sync/upstream-${new:0:7}"
gh pr create --base main --head "sync/upstream-${new:0:7}" --title "Sync upstream marcus-darden/egm ${old:0:7}..${new:0:7}" --body-file SYNC-REPORT.md
告訴 Juan PR 的 URL、統計數據(已套用、已適配、已略過、已標記)以及已標記的項目。不要合併 PR。刪除暫存複製。