Files
ISEP/hooks/irreversible-dispatch-guard.sh
Leo c2638668e3 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>
2026-08-20 11:41:46 +08:00

80 lines
3.4 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/sh
# irreversible-dispatch-guard.sh — PreToolUse(Agent|Task):擋「把不可逆動作寫成選項」的派工單
#
# 🔴 事故(Gitea Leo/arcrun-rag#332026-08-09):subagent 未經 leo 同意刪掉兩條遠端分支。
# 根因不是它亂來——是總管的派工單寫了「作廢就刪掉分支」,等於預先授權了一個不可逆動作。
# 它刪掉的那條裡,還有一件它自己標明「等 leo 排序」的工作,一併蒸發。
#
# 【對照組,同一天同一個總管】#14 的派工單寫
# 「🔴 刪資料不可逆。動手前先把清單寫在 issue 留言,等總管回覆確認才執行」
# ⇒ 那個 agent 真的停下來等。同一個人一次寫對一次寫錯 ⇒ 靠自律不行,要機械閘。
#
# 判準(細節與正則見 irreversible_dispatch_check.py):
# 派工單裡出現「不可逆動作」的動詞+對象(刪分支/drop tablerm -rfforce push…)
# 且沒被否定(不是「不准刪」這種禁令句)
# 且全文找不到「停下來等回覆才執行」這類守門片語
# ⇒ 判定為把不可逆動作寫成收工方可以自己執行的選項,擋下。
#
# 🔴 寧可誤擋,不可漏放——這是安全機制,不是文風檢查。豁免走留痕:
# 命中那一行尾巴加 `irreversible-ok`。
set -eu
INPUT="$(cat)"
PROMPT=$(printf '%s' "$INPUT" | python3 -c '
import sys, json
try:
d = json.load(sys.stdin)
print(d.get("tool_input", {}).get("prompt", "") or "")
except Exception:
print("")
' 2>/dev/null || echo "")
[ -z "$PROMPT" ] && exit 0
HOOK_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
RESULT=$(printf '%s' "$PROMPT" | python3 "$HOOK_DIR/irreversible_dispatch_check.py" 2>/dev/null || echo '{"verdict":"OK","hits":[]}')
VERDICT=$(printf '%s' "$RESULT" | python3 -c '
import sys, json
try:
d = json.load(sys.stdin)
print(d.get("verdict", "OK"))
except Exception:
print("OK")
' 2>/dev/null || echo "OK")
[ "$VERDICT" != "BLOCK" ] && exit 0
HITS=$(printf '%s' "$RESULT" | python3 -c '
import sys, json
try:
d = json.load(sys.stdin)
for ln, line, word in d.get("hits", []):
print(f" 第 {ln} 行(命中「{word}」):{line}")
except Exception:
pass
' 2>/dev/null || echo "")
cat >&2 <<EOF
🔴 不可逆動作警察:這張派工單把「刪東西」寫成收工方可以自己執行的選項,擋下。
【事故(Gitea Leo/arcrun-rag#332026-08-09)】subagent 未經 leo 同意刪掉兩條遠端分支,
根因是派工單寫了「作廢就刪掉分支」——判斷可以,動手不行,這份單子卻兩個都給了。
其中一條被刪的分支裡,還有一件它自己標明「等 leo 排序」的工作,一併蒸發。
【對照組,同一天同一個總管】#14 寫「🔴 刪資料不可逆。動手前先把清單寫在 issue 留言,
等總管回覆確認才執行」⇒ 那個 agent 真的停下來等。同一個人一次寫對一次寫錯,
證明這件事不能只靠自律,要靠這道閘。
【命中的不可逆動作】
$HITS
【怎麼改】判斷可以,動手不行——把授權句改成「列清單、標明理由、停在這裡等回覆」:
❌「作廢就刪掉分支」
✅「盤點出作廢的分支,列成清單留言在 issue,動手前等總管回覆確認才執行」
真有必要略過(極少數情況):在命中那一行尾巴加 irreversible-ok 留痕,並在派工單裡寫清楚為什麼。
改完重送即放行。
EOF
exit 2