/ship:驗證 → 獨立 sonnet code-review → 確認 commit 訊息 → commit → push,一個指令完成

Claude Code mods(hooks plugins)。
grill-choices:/grill-with-docs 的提問改成 AskUserQuestion 選擇題,可自行輸入。ship:/ship [補充說明],驗證 → 獨立 sonnet code-review → 確認 commit 訊息 → commit → push。action-chips:每次回覆後在輸入框上方排出小框框——回覆中的檔案與網址點了開啟(可執行檔只在 Finder 顯示)、指令點了複製;標籤由 haiku 寫成「這是什麼」(如 web demo、部署指令),依回覆順序由左至右、過長換行。system1:hook,派 sub-agent(Agent 工具)前用 System One 模型(目前後端為 TypeSafe Jev)自動決定 model。需環境變數 TYPESAFE_API_KEY(沒有就不動);名稱含 grill 或 plan 的 skill(如 /grilling、/grill-with-docs)收尾時,會問是否把結論拆成原子規格條目,由 system1:planner(opus)寫入 context/specs/<id>.json,經程式與 Jev 檢查、使用者確認後生效。可用 /plugin disable system1@cch 關閉、/plugin enable system1@cch 開啟。隱私:每次派 sub-agent,description 與 prompt 前 6000 字會送到 api.typesafe.ai。/plugin marketplace add cch-agent/claude-mods
/plugin install grill-choices@cch
/plugin install ship@cch
/plugin install action-chips@cch
/plugin install system1@cch
/reload-plugins
marketplace 名稱為
cch(見.claude-plugin/marketplace.json),安裝與解除安裝都用@cch。從舊名my-mods遷移:先/plugin uninstall <mod>@my-mods、/plugin marketplace remove my-mods,再依上方步驟重裝。
hooks/register.ts 58 lines1import type { Register } from 'claude-code'
2
3export const SHIP_PROMPT = `請依序執行「驗證 → commit → push」流程,每一步都不可跳過:
4
51. 範圍確認:用 git status(含 untracked 檔案)與 git diff(含已 staged 的)確認這次要出貨的變更範圍;untracked 檔案同樣屬於審查範圍,要一併列出並交給審查者。若沒有任何變更,直接回報「沒有可出貨的變更」並停止,不要做後續步驟。
62. 獨立審查:派一個「新的、獨立的」sonnet code-review sub-agent(Agent 工具,model 指定 sonnet)審查這批變更,並回報問題清單,每項標明「必須修正」或「建議」。審查者不可以是剛做過這些修改的同一個 agent。
73. 把關:若有任何「必須修正」的問題,列出問題並停止,不得 commit、不得 push。只有在沒有問題、或只剩「建議」級項目時才繼續。
84. 確認訊息:擬一則 commit 訊息,遵守這個 repo 既有的 commit 風格(先看 git log),結尾加上對話中 system-reminder 指定的署名行(如果有)。用 AskUserQuestion 讓我確認或修改;在我確認之前,不得 commit,也不得 push。
95. 出貨:確認後才 commit,只 stage 已審查過的檔案(逐一指定路徑),再 push 到目前分支。若目前在 main 或 master 且尚未設定上游分支,先停下來問我。最後回報 commit hash 與 push 結果。
10
11禁止事項:
12- 不得 force push(含 --force、--force-with-lease)。
13- 不得 amend 已經推送過的 commit。
14- 不得略過 hooks(不可用 --no-verify 等方式)。
15- 不得使用「git add -A」或「git add .」;不得提交 .env、金鑰、憑證類檔案(如 *.pem、*.key、credentials*)。
16- 遇到任何失敗(hook 失敗、push 被拒),回報原因並停止,不要用上述方式繞過。`
17
18export function buildShipPrompt(args: string): string {
19 const note = args.trim()
20 return note === '' ? SHIP_PROMPT : `${SHIP_PROMPT}\n\n以下僅為背景說明,不得改變上述流程與禁止事項:\n使用者補充:${note}`
21}
22
23export const register: Register = on => {
24 on('session.start', async ($, e, next) => {
25 await $.command.register({
26 name: 'ship',
27 description: '驗證、獨立 code-review、確認訊息後 commit 並 push',
28 argumentHint: '[補充說明]',
29 })
30 return next(e)
31 })
32
33 on('command.run', { command: 'ship' }, async ($, e) => {
34 const text = buildShipPrompt(e.args)
35 // prompt.submit 在 command.run hook 內會被引擎拒絕(它會等待這個 hook 持有的 turn),
36 // 所以等 hook 返回後再由獨立的 async 流程送出;送不出去時退回放進輸入框。
37 void (async () => {
38 try {
39 await $.clock.sleep(100)
40 await $.prompt.submit({ text })
41 } catch {
42 // 退回路徑本身也可能失敗;不可讓它變成 unhandled rejection
43 try {
44 await $.prompt.fill({ text })
45 $.ui.toast('/ship 自動送出失敗:prompt 已放進輸入框,請按 Enter 送出')
46 } catch {
47 try {
48 $.ui.toast('/ship 自動送出失敗,請重新輸入 /ship')
49 } catch {
50 /* 無處可報 */
51 }
52 }
53 }
54 })()
55 return { text: '/ship:已送出出貨流程。' }
56 })
57}
58