Files
ISEP/hooks/guard-cross-project.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

94 lines
4.2 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.
#!/usr/bin/env bash
# guard-cross-project.sh — 頂層總管 guardrail
#
# 職責邊界(InkStoneCo CLAUDE.md D9):頂層只做「跨專案的整理與安排」(總管),
# 不進單一子 repo 做實作。子 repo 的程式碼/設定實作 = 在那個子 repo 的專案裡執行,
# 頂層只負責「交棒」(寫 docs/HANDOFF-*.md)並記錄安排。
#
# 本 hook 攔 PreToolUse 的 Write/Edit/MultiEdit
# - 目標路徑落在子 repo 目錄(matrix/ polaris/ products/ _archive/)內
# - 且不是 .md 文件
# → 擋下(exit 2),提示改用交棒(寫 HANDOFF)。
# 放行:頂層自己的檔(CLAUDE.md / .claude/ / docs/ / MEMORY.md…)、
# 以及子 repo 內的 .md(交棒 HANDOFF / 筆記 / 文件——leo 2026-06-15 拍板放行所有 .md)。
#
# 誠實限制(arcrun mindset §7):本 hook 擋的是「路徑語法層」——能擋「寫程式碼進子 repo」,
# 擋不了「把實作偽裝成 .md」或「該交棒卻判斷成可直改」這種語意層越界。它是底線,不是萬能。
input="$(cat)"
# 取 file_pathWrite/Edit/MultiEdit 都用 tool_input.file_path
file_path="$(printf '%s' "$input" | python3 -c '
import sys, json
try:
d = json.load(sys.stdin)
print(d.get("tool_input", {}).get("file_path", ""))
except Exception:
print("")
' 2>/dev/null || true)"
# 拿不到路徑就放行(不誤擋;hook 不該因解析失敗卡死正常操作)
[ -z "$file_path" ] && exit 0
# 頂層 repo 根(hook 檔位於 <root>/.claude/hooks/
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
# 轉成相對 repo_root 的路徑(file_path 可能是絕對或相對)
case "$file_path" in
/*) rel="${file_path#"$repo_root"/}" ;; # 絕對路徑 → 去掉 repo_root 前綴
*) rel="$file_path" ;; # 相對路徑 → 假定相對 repo_root
esac
# 不在子 repo 目錄內 → 放行(頂層自己的檔)
case "$rel" in
matrix/*|polaris/*|products/*|_archive/*) : ;; # 落在子 repo,繼續判斷
*) exit 0 ;;
esac
# 自動派工放行(2026-06-28 leo 拍板上線,實測通過):
# 子 repo 的 subagent 可直接寫該 repo code(繞 D9)——因 subagent 心智已是該 repo
# A/B 實驗證 ≈ claude -p),讓「心智是該 repo 的小弟寫該 repo」符合 context 隔離。
# 雙重夾:① CHILD_SESSION=1harness 內建 subagent 標籤,總管主 session 無此標籤仍被擋)
# ② 路徑在下面白名單 array 內。
# 隔離保證=prompt reset(軟,靠監測)非結構級;要絕對純走 claude -p。心法見 wiki。
#
# 🔧 leo 維護:要放開一個 repo 給 subagent 自動寫 code,就在這 array 加一行路徑前綴。
# ⚠️ 加 = 放權,想清楚私人/共用(改它影響誰)再加。array 空 = 誰都不放(安全預設)。
AUTODISPATCH_ALLOW=(
"polaris/mira" # 私人環境(只影響 leo
"matrix/arcrun" # 共用框架(影響全部人,走 PR 把關)
"products/arcrun-rag" # 產品組裝 repo2026-07-13 leo 放行 G8:回覆「放行」)
)
if [ "$CLAUDE_CODE_CHILD_SESSION" = "1" ]; then
for allowed in "${AUTODISPATCH_ALLOW[@]}"; do
case "$rel" in
"$allowed"/*) echo "🤝 [guard] subagent 放行:$allowed(自動派工)" >&2; exit 0 ;;
esac
done
fi
# 在子 repo 內:.md 放行(交棒 / 文件),其餘擋
case "$rel" in
*.md|*.MD|*.markdown) exit 0 ;;
esac
# 走到這 = 寫非 .md 檔進子 repo 目錄 = 越界實作 → 擋
sub="${rel%%/*}"
cat >&2 <<EOF
❌ BLOCKED by InkStoneCo 總管 guardrail(職責邊界 D9
違反:頂層總管直接寫實作檔進子 repo($sub/)。
路徑:$rel
頂層只做「跨專案的整理與安排」,不進單一 repo 做實作。
子 repo 的程式碼 / 設定 = 在該子 repo($sub)的專案裡改,不在頂層。
正確做法:
• 要子 repo 改什麼 → 寫一份交棒文件:$sub/docs/HANDOFF-*.md.md 放行),
給判準與論證,成品由該 repo 的 CC 按它自己的 rules 產出。
• 真要由你(總管)動這個子 repo → 切換到那個子 repo 的工作脈絡再做,不在頂層越界。
參考:CLAUDE.md「職責邊界(核心原則)」+ decisions-summary D9。
EOF
exit 2