e0557334bc
leo 2026-08-26:「今天已經好幾次問我,為什麼 hooks 沒有攔下來?」 實查:總管問 leo 走的動作是 AskUserQuestion,而 hooks.json 裡它出現 0 次, 沒有任何 matcher。判準其實早就寫好了——self-drive-police / self-drive-judge 用的就是同一套四題公式——但那兩支只掛在 Stop 與 SubagentStop, 是回合結束後才跑的。問題早就送到他眼前了,事後再反問「你查過了嗎」, 成本已經轉嫁出去。判準對了,時機錯了。 新增 hooks/ask-user-question-guard.sh(PreToolUse / AskUserQuestion): - 觸發條件是那個動作本身,不是任何句型或關鍵字——全檔零個判擋用的正則, 換句話說閃不過去,講得謹慎也不會被多罰(leo 2026-08-17 文字層封路的檢驗) - 進來之後用四題公式的 haiku 判官分「該問 / 不該問」,命中任一題一律放行 - 同一個問題只擋一次(雜湊戳記):判官誤判時重送即過, leo 該收到的問題不會因為一支閘而永遠送不到 - 判官掛掉/沒網路/claude 不在 PATH 一律 fail-open,壞掉等於它不存在 版本 0.3.9 → 0.4.0。這不是儀式,是傳輸機制本身:產物按版本號分資料夾 (~/.claude/plugins/cache/inkstone/isep/<版本>/),版本沒動就不會長出新資料夾, 這支閘一個 session 都載入不到。docs/TESTING.md 開頭那段講的就是這件事, 而第一版我漏了——總管複驗時量出來的。 假設(沒有前例可循,先裁再記):跳 0.4.0 而不是 0.3.10。理由是這一版第一次 掛上 AskUserQuestion 這個事件面,是新能力不是修補;而且 0.3.10 在 plugin 快取目錄的 ls 裡會排到 0.3.1 旁邊,肉眼不好認。錯了打回,改號很便宜。 順手修掉自己寫出來的一個坑:訊息原本用沒加引號的 heredoc, 反引號被當命令執行,wiki 路徑與豁免指令兩行變成空白(閘照擋,只看離開碼看不出來)。 已收成 mistakes.md 一條,並由 ⑩b 這條測試守著。 實測: - hooks/tests/ask-user-question-guard.test.sh 14/14(離線,不花錢) - hooks/tests/ask-user-question-guard.live.test.sh 9/9 連跑三次(真的叫 haiku) A 群 5 條真人閘(花錢/不可逆/跨專案結構/品味方向/物理人閘)全部放行,誤攔 0 B 群 4 條純技術路徑選擇全部擋下 - 既有 7 支測試與改動前逐條對照,結果完全相同(沒有被我弄壞) 順手對帳:plugin.json 與 marketplace.json 的描述寫「43 支機械閘、53 條註冊」, 實際數過是 46/56(含本次新增這支)。docs/hooks-inventory.md 一併更正。 【工單】inkstone/InkStoneCo#55
339 lines
9.2 KiB
JSON
339 lines
9.2 KiB
JSON
{
|
|
"description": "InkStone Environment Plugin (ISEP) —— leo 的 Claude Code 環境唯一真相源:所有機械閘、slash command、skill、腳本。本機與雲端裝同一份,總管自己也吃它(dogfood)。",
|
|
"hooks": {
|
|
"PreToolUse": [
|
|
{
|
|
"matcher": "Bash",
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/github-contact-guard.sh"
|
|
},
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/kbdb-api-wall-guard.sh"
|
|
},
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/stage-before-prod-guard.sh"
|
|
},
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/main-and-prod-push-guard.sh"
|
|
},
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/prod-write-guard.sh"
|
|
},
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/not-my-branch-guard.sh"
|
|
},
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/leo21c-write-guard.sh"
|
|
},
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/release-tag-guard.sh"
|
|
},
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/ticket-api-bypass-guard.sh"
|
|
},
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/milestone-due-guard.sh"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": ".*(arcrun_push_workflow|arcrun_delete_workflow|arcrun_recipe_push|arcrun_recipe_delete|arcrun_create_tag|arcrun_delete_tag|arcrun_tag_resource|arcrun_untag_resource|kbdb_create_record|kbdb_create_template).*",
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/prod-write-guard.sh"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": "Write|Edit|MultiEdit",
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/guard-cross-project.sh"
|
|
},
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/wiki-secret-scan.sh"
|
|
},
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/component-guard.sh"
|
|
},
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/sdd-guard.sh"
|
|
},
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/credential-only-guard.sh"
|
|
},
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/arcrun-intent-guard.sh"
|
|
},
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/kbdb-api-wall-guard.sh"
|
|
},
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/subagent-first-guard.sh"
|
|
},
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/mistake-needs-ticket-guard.sh"
|
|
},
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/pending-changes-retired.sh"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": "Grep|Glob|Read|Bash",
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/wiki-first-search.sh"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": "Task",
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/subagent-wiki-guard.sh"
|
|
},
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/kbdb-api-wall-guard.sh"
|
|
},
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/micromanage-guard.sh"
|
|
},
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/irreversible-dispatch-guard.sh"
|
|
},
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/no-ticket-no-dispatch.sh"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": ".*arcrun_(push_workflow|validate_yaml).*",
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/arcrun-intent-guard.sh"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": "Edit|MultiEdit",
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/history-first-guard.sh"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": "Agent",
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/micromanage-guard.sh"
|
|
},
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/irreversible-dispatch-guard.sh"
|
|
},
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/no-ticket-no-dispatch.sh"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": "AskUserQuestion",
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/ask-user-question-guard.sh"
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"SessionStart": [
|
|
{
|
|
"matcher": "startup|resume|clear",
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/session-start-recall.sh"
|
|
},
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/skill-deploy-drift-guard.sh"
|
|
},
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/isep-presence-beacon.sh"
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"Stop": [
|
|
{
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "\"${CLAUDE_PLUGIN_ROOT}\"/hooks/empty-handed-stop-guard.sh"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/worklist-guard.sh"
|
|
},
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/factory-idle-guard.sh"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/browser-verify-guard.sh"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/self-drive-police.sh"
|
|
},
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/self-drive-judge.sh"
|
|
},
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/delivery-police.sh"
|
|
},
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/wiki-first-police.sh"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/unpushed-police.sh"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/claim-verify-police.sh"
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"SubagentStop": [
|
|
{
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/subagent-claim-worksheet.sh"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/worklist-guard.sh"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/self-drive-police.sh"
|
|
},
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/self-drive-judge.sh"
|
|
},
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/delivery-police.sh"
|
|
},
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/wiki-first-police.sh"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/unpushed-police.sh"
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"PostToolUse": [
|
|
{
|
|
"matcher": ".*kbdb_(search|get_map|query|graph_neighbors).*",
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/kbdb-asked-stamp.sh"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": "Agent|Task",
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/subagent-first-stamp.sh"
|
|
},
|
|
{
|
|
"type": "command",
|
|
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/issue-status-autoflip.sh"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
} |