ISEP 0.1.0:環境設定收成一個 plugin,本機與雲端共用一份
leo 2026-08-20:「同一個 plugin 你用,薄殼也用,保證兩邊同步」
「我要你幫雲端做薄殼,永遠都有問題,你要做的就是這組設定
你自己可以 dogfooding」
搬進來:41 支 hook(51 條註冊)/7 支 command/2 支 skill/23 支腳本。
不搬 .env、wiki、docs——那些是知識不是環境。
51 條 hook 路徑全部從 $CLAUDE_PROJECT_DIR/.claude/hooks/ 改成 ${CLAUDE_PLUGIN_ROOT}/hooks/,
零漏網。那正是薄殼一直壞掉的根:雲端 cwd 不是真身,寫死路徑就斷。
尚未驗證:Claude Code 能不能從私有 Gitea repo 裝 marketplace(要憑證)。
下一步就是在本機實際裝一次,通了才動雲端 bootstrap.sh。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Executable
+165
@@ -0,0 +1,165 @@
|
||||
#!/usr/bin/env bash
|
||||
# self-drive-police.sh — 自走警察(Stop hook)
|
||||
#
|
||||
# 病根(leo 2026-06-29 一個 session 點破三次):我「做一條停一條」「把該自己做的推給 leo」
|
||||
# ——不是缺 loop,是每個決策點退回「推給 leo」的省事預設。CLAUDE.md 寫規則沒用(我會不讀)。
|
||||
# leo 的解法:在我「要停下來」那一刻攔截 + 反問,逼我先窮盡查證才准停。
|
||||
# 靈感=leo 之前做的「Haiku 警察 Anna」(檢查回話、犯規就抓)。先用輕的(純 bash grep),不夠再升級。
|
||||
#
|
||||
# 機制(官方 Stop hook,核實 code.claude.com/docs/en/hooks):
|
||||
# Claude 結束回合想停 → 本 hook 觸發 → 讀 transcript 我這回合輸出 → grep 三類推卸句式:
|
||||
# ① 憑記憶問「要不要/該選/哪個」 → 反問「查 wiki/internet 官方了嗎」
|
||||
# ② 問「下一步/接下來做什麼」 → 反問「查 SDD/派工表/北極星了嗎」
|
||||
# ③ 推卸「交給你/這是你的/你去開」 → 反問「規劃做完了嗎、能 spawn subagent 嗎、為何停」
|
||||
# 命中 → exit 2 + stderr(reason) → Claude 不停、收到反問繼續做。
|
||||
# 沒命中 → exit 0 放行(真的該停,不擾)。
|
||||
#
|
||||
# 防無限迴圈(官方):stop_hook_active=true(已 block 過一輪)→ 放行。
|
||||
# + Claude Code 內建 block cap(連續 8 次自動放行)。
|
||||
#
|
||||
# 誠實限制:靠句式 grep,擋得住「明顯推卸句」,擋不住「換句話說的推卸」。是底線不是萬能。
|
||||
# 不夠時升級成 type:prompt(Haiku 判語意) 或 type:agent(查 wiki/SDD 客觀驗),見 hook 末註。
|
||||
|
||||
input="$(cat)"
|
||||
|
||||
# 防無限迴圈:已經 block 過一輪(Claude 正在回應上一次 block)→ 放行
|
||||
stop_active="$(printf '%s' "$input" | python3 -c '
|
||||
import sys, json
|
||||
try:
|
||||
print(json.load(sys.stdin).get("stop_hook_active", False))
|
||||
except Exception:
|
||||
print(False)
|
||||
' 2>/dev/null)"
|
||||
if [ "$stop_active" = "True" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 取 transcript 路徑
|
||||
transcript="$(printf '%s' "$input" | python3 -c '
|
||||
import sys, json
|
||||
try:
|
||||
print(json.load(sys.stdin).get("transcript_path", ""))
|
||||
except Exception:
|
||||
print("")
|
||||
' 2>/dev/null)"
|
||||
|
||||
[ -z "$transcript" ] || [ ! -f "$transcript" ] && exit 0
|
||||
|
||||
# 抽「我這回合最後的 assistant 文字輸出」(transcript 是 JSONL,每行一事件)
|
||||
# 取最後一個 assistant 訊息的 text,避免掃到歷史
|
||||
last_text="$(python3 -c '
|
||||
import sys, json
|
||||
path = sys.argv[1]
|
||||
texts = []
|
||||
try:
|
||||
with open(path) as f:
|
||||
lines = f.readlines()
|
||||
# 從尾往前找最後一個 assistant 訊息的 text 內容
|
||||
for line in reversed(lines):
|
||||
try:
|
||||
ev = json.loads(line)
|
||||
except Exception:
|
||||
continue
|
||||
msg = ev.get("message", ev)
|
||||
if msg.get("role") == "assistant":
|
||||
content = msg.get("content", "")
|
||||
if isinstance(content, list):
|
||||
for b in content:
|
||||
if isinstance(b, dict) and b.get("type") == "text":
|
||||
texts.append(b.get("text", ""))
|
||||
elif isinstance(content, str):
|
||||
texts.append(content)
|
||||
break
|
||||
except Exception:
|
||||
pass
|
||||
print("\n".join(texts))
|
||||
' "$transcript" 2>/dev/null)"
|
||||
|
||||
[ -z "$last_text" ] && exit 0
|
||||
|
||||
# ── 豁免:撞真閘就別逼它做不可能的事(2026-07-22 補)──
|
||||
# 病例:雲端總管有 token、備好 patch,但 harness classifier 擋掉 mutating 寫入 →
|
||||
# 舊版警察會抓「Which way do you want it?」逼它繼續,它撞牆到 block cap 才放行=空轉。
|
||||
# 明說「四題第X命中」也放行(本 hook 註解原本就要求這格式,但沒實作豁免)。
|
||||
if printf '%s' "$last_text" | grep -qiE '權限閘|classifier|分類器擋|denied by|四題第|需要你放行|需要 leo 放行'; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# ── 三類推卸句式偵測 ──────────────────────────────────────────────
|
||||
# ③ 推卸給 leo(最該抓)——「交給你/這是你的/你去/請你去開/leo 去做」
|
||||
if printf '%s' "$last_text" | grep -qiE '交給(你|leo)|這是你的|是你的工作|你(去|來)(開|做|跑|查|執行)|請你去|leo (去|來)(開|做)|由你(去|來)|該你'; then
|
||||
cat >&2 << 'EOF'
|
||||
🚓 自走警察:偵測到「推卸給 leo」。停下前先答這三題:
|
||||
1. 所有規劃工作做完了嗎?(查 autonomy-dispatch/tasks.md 派工表 + 北極星)
|
||||
2. 這件事我能不能 spawn 一個 subagent 去做?(子 repo 寫 code 走 guard 白名單 CHILD_SESSION;偵察/文書/診斷都能 spawn)
|
||||
3. 為什麼要停下來?——只有四題命中(花錢/不可逆/品味方向/物理人閘如 terminal consent、merge 批准)才輪到 leo。
|
||||
「做 vs 問」是假二選一,真三選一:自己做 / spawn subagent 做 / 才輪到 leo。叫 leo 當人肉中繼=親手裝回剛拔掉的瓶頸。
|
||||
若確認真四題命中才需 leo,下一回合明說「四題第X命中:<理由>」再停。
|
||||
EOF
|
||||
exit 2
|
||||
fi
|
||||
|
||||
# ② 問「下一步做什麼」——答案在規劃文件裡
|
||||
if printf '%s' "$last_text" | grep -qiE '下一步(要|該)?做什麼|接下來(要)?做什麼|接下來呢|要做什麼好|現在(要|該)做什麼'; then
|
||||
cat >&2 << 'EOF'
|
||||
🚓 自走警察:偵測到「問下一步做什麼」。答案多半在規劃文件裡,先查再說:
|
||||
1. 查 SDD 了嗎?(system-dev/docs/3-specs/*/tasks.md — 唯一進度來源)
|
||||
2. 查派工表了嗎?(system-dev/docs/3-specs/autonomy-dispatch/tasks.md — issue 開哪、誰做、狀態)
|
||||
3. 查北極星了嗎?(system-dev/docs/6-user/20260627-northstar.md §8.4 順序)
|
||||
查完下一條自然浮現,自己往前推,別把判斷推給 leo。若真查過且確認無下一條/撞人類閘,下一回合明說再停。
|
||||
EOF
|
||||
exit 2
|
||||
fi
|
||||
|
||||
# ⓪ 🔴 請示句:「要我 X 嗎/我可以開始嗎/需要我 X 嗎」——**已交代過的事不必再請示**
|
||||
# 2026-08-04 leo 兩度點破:「不要停下來問要不要繼續,**這是前面明說要做的事**」
|
||||
# 「都列表了你還要問這個問題?」「**就是個自問自答功能,你問的問題明明有答案**」
|
||||
# ⇒ 舊 ① 只認「要不要/該選哪個」,**漏掉最常見的請示句型「要我…嗎」**。
|
||||
# 判準不是句型漂亮與否,而是:**這個問題的答案,是不是已經存在於既有資料裡?**
|
||||
if printf '%s' "$last_text" | grep -qiE '要我(現在|先|繼續|開始)?[^??]{0,12}嗎|需要我[^??]{0,12}嗎|我(現在|可以|該)(開始|繼續|動手)[^??]{0,8}嗎|(繼續|開工|動手)嗎'; then
|
||||
cat >&2 << 'EOF'
|
||||
🚓 自走警察(請示句):你在問「要我 X 嗎」——**先自問自答:這個問題有答案嗎?**
|
||||
|
||||
【leo 2026-08-04】「不要停下來問要不要繼續,**這是前面明說要做的事**」
|
||||
「都列表了你還要問這個問題?」
|
||||
「**就是個自問自答功能,你問的問題明明有答案,應該就可以找到答案了**」
|
||||
|
||||
━━━ 送出前先在這三處找答案(找到就別問,直接做)━━━
|
||||
A. **leo 這個 session 說過的話**——他是不是已經給了優先序/清單/「開工」?
|
||||
(已交代過的事再請示=把他當按鈕按,正是自走規則要拔掉的瓶頸)
|
||||
B. **你自己剛列的 todo/任務表**——下一項就是答案,照著做
|
||||
C. **wiki/tasks.md**——`system-dev/wiki/status.md`、對應 tasks.md 有沒有定案
|
||||
|
||||
━━━ 只有這種情況才可以問(且要明說已查過)━━━
|
||||
真命中四題人閘:花錢/不可逆(push main、刪資料、部署上線)/
|
||||
跨專案結構決策/品味方向。**其餘一律自己裁、往前推,錯了被擋回再修。**
|
||||
|
||||
📌 想收尾時不要問「要我繼續嗎」,直接**做下一項並回報做了什麼**。
|
||||
EOF
|
||||
exit 2
|
||||
fi
|
||||
|
||||
# ① 憑記憶問「要不要/該選哪個」——先查證再決定
|
||||
if printf '%s' "$last_text" | grep -qiE '要不要|該不該|該選(哪|什麼)|哪個(比較)?好|選哪(個|條)|是不是要|可不可以'; then
|
||||
# 但若這回合已有查證跡象(提到查了 wiki/官方/grep/WebFetch/出處),放行——別擾正常提問
|
||||
if printf '%s' "$last_text" | grep -qiE '查(了|過)|官方(確認|核實|出處)|核實|grep|WebFetch|出處|wiki 寫|記憶(卡|寫)'; then
|
||||
exit 0
|
||||
fi
|
||||
cat >&2 << 'EOF'
|
||||
🚓 自走警察:偵測到「憑判斷問要不要/該選哪個」,但沒看到查證跡象。停下問 leo 前先窮盡:
|
||||
1. 查 wiki/記憶了嗎?(system-dev/wiki/ + MEMORY.md — 這事可能已有定案,別重議)
|
||||
2. 查 internet 官方說明了嗎?(LLM/平台/API 機制憑記憶會錯,查官方原文 + 給出處)
|
||||
查完答案多半自己浮現,四題全否就自己裁、不問 leo。若查過仍需 leo 的品味/方向判斷(第④題),下一回合明說「查過,這是品味題」再問。
|
||||
EOF
|
||||
exit 2
|
||||
fi
|
||||
|
||||
# 沒命中任何推卸句式 → 真的該停,放行
|
||||
exit 0
|
||||
|
||||
# ── 升級路徑(不夠用時,leo 點頭)──────────────────────────────────
|
||||
# 輕→重三級:
|
||||
# L1(現在):command bash grep 句式三分流。最省,擋明顯推卸句。
|
||||
# L2:改 type:prompt(Haiku 判語意),settings.json 寫 {"type":"prompt","prompt":"判斷這回合是否在推卸/未查證就停…"}。
|
||||
# 擋「換句話說的推卸」,但每次停叫一次 Haiku(便宜)。
|
||||
# L3:改 type:agent,spawn subagent 真查 wiki/SDD/派工表客觀驗「規劃是否做完」(像 Ralph 的 passes)。最強最貴。
|
||||
Reference in New Issue
Block a user