Files
ISEP/hooks/subagent-first-stamp.sh
T
Leo e177f6372b subagent-first-guard 補三個洞:閘不管 .sh、派過工變免死金牌、警報響一次就啞掉
leo 2026-08-27(inkstone/ISEP#66):「你禁止寫 code,為什麼你改?為什麼你可以執行?」
總管親手改了 no-ticket-no-dispatch.sh,這道閘一聲不響。

三個洞,一次補:
1. `.sh` 從沒進過受管副檔名清單——這個 repo 自己的閘全是 .sh,等於這道閘
   從第一行 case 就直接放行,路徑白名單根本沒機會判斷。這才是真正原因,
   不是路徑豁免。修法:閘本身(`.claude/hooks/*.sh`、`hooks/*.sh`)獨立收進
   受管清單;同時拿掉 `*/.claude/hooks/*` 整目錄豁免——能改閘的人等於能關掉
   所有其他閘,這句話本身就是拿掉它的理由。
2. 「這個 session 派過一次工」曾被當永久放行條件,但那混淆了「這件任務有沒有
   交出去」跟「下一次任意的手改合不合理」——整個拿掉,改成純資訊(留在被擋下
   時的訊息裡,告訴你上次派工是幾分鐘前)。
3. 「同一 session 只擋一次」讓警報響過一次就對餘生啞掉。改成寬限期(預設 15
   分鐘,可用 SUBAGENT_GUARD_NAG_TTL 覆寫做測試):寬限期內不重複鬼打牆,
   過了就再響——不選邊犧牲「有效」或「不煩人」。

放行只剩三種:CLAUDE_CODE_CHILD_SESSION=1(subagent 本人,它就是被派來寫的)/
solo-ok 非空(寫了理由,不是 touch 空檔)/檔案本身不歸這道閘管(測試檔/
system-dev 的 wiki/非受管副檔名)。

新增 scripts/test-subagent-first-guard.sh,20/20 通過:涵蓋三個洞各自的重演、
CHILD_SESSION 放行、測試檔/wiki 放行、solo-ok 空檔不算數、寬限期到期再響。

plugin.json 0.5.0 → 0.5.1;docs/hooks-inventory.md 同步更新兩支閘的說明。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 14:06:06 +08:00

24 lines
1.2 KiB
Bash
Executable File
Raw 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
# subagent-first-stamp.sh — PostToolUse:記下「這個 session 真的派過工了」。
#
# 配 subagent-first-guard.sh 使用(同 kbdb-asked-stamp.sh 的形狀)。
# 只留時戳,不擋任何東西。
#
# 🔴 2026-08-27inkstone/ISEP#66):這個時戳**不再是放行條件**。
# 「派過一次工」曾經被 subagent-first-guard.sh 當成「這個 session 永久放行」——
# 但那混淆了「這件任務有沒有交出去」跟「下一次任意的手改合不合理」,是兩件事。
# 現在這支只負責留時戳,給被擋下時的訊息當脈絡用(「上次派工是幾分鐘前」),
# 純資訊、不影響放行判斷。
#
# 🔴 為什麼要按 session 分開存(而不是像 KBDB 那道用全域+1 小時 TTL):
# 「這一輪工作有沒有先考慮派工」是**每個 session 各自要回答**的問題。
# 用全域檔的話,昨天派過一次就等於永久解鎖,這道閘會在第二天起完全失效。
set -eu
SID=$(cat 2>/dev/null | python3 -c '
import sys, json
try: print(json.load(sys.stdin).get("session_id", "") or "nosid")
except Exception: print("nosid")
' 2>/dev/null || echo nosid)
date +%s > "/tmp/.subagent-spawned-$SID"
exit 0