關掉 CLI 後立刻重開新階段時,角色會被自己上一個階段的殘留鎖擋住: 原本只有「持有者 transcript 閒置超過 30 分鐘」與手動 --unlock 兩條釋放 路徑,而剛關閉的 transcript mtime 還很新,機制無法區分「已關閉」與 「正在別的視窗打字」,因此最久要等 30 分鐘才叫得回角色。 新增 SessionEnd hook(role_unload.sh)作為快速路徑,工作階段正常結束時 立即刪鎖。mtime 閒置逾時後援保留不動 —— SessionEnd 不保證觸發 (kill -9、直接關終端機、WSL 關機、當機都不會跑),少了後援會在異常 結束時把角色鎖死到下次手動解鎖,兩條路徑缺一不可。 只在鎖檔登記的 transcript 等於自己時才釋放:被鎖擋下的第二個階段結束時 同樣會觸發 SessionEnd,若無條件刪鎖會把仍在使用中的第一個階段的鎖一起 刪掉,等於讓單一實例限制形同虛設。無法取得 transcript、sub agent (ROLE_SKIP_INSTANCE_LOCK=1)、限制已停用(ROLE_SINGLE_INSTANCE=0) 一律不動鎖。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
60 lines
3.1 KiB
JSON
60 lines
3.1 KiB
JSON
{
|
|
"hooks": {
|
|
"SessionStart": [
|
|
{
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "rel='scripts/role/role_load.sh'; own='generic'; plug='jsc-generic'; root=\"${CLAUDE_PLUGIN_ROOT:-}\"; if [ -n \"$root\" ] && [ -f \"$root/$rel\" ]; then exec \"$root/$rel\"; fi; for base in \"$HOME/.claude/plugins/cache\" \"$HOME/.codex/plugins/cache\"; do for dir in \"$base/$own/$plug\" \"$base\"; do s=$(find \"$dir\" -path \"*/$plug/*/$rel\" -type f 2>/dev/null | sort -V | tail -n 1); if [ -n \"$s\" ]; then exec \"$s\"; fi; done; done; exit 0",
|
|
"timeout": 20
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"SessionEnd": [
|
|
{
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "rel='scripts/role/role_unload.sh'; own='generic'; plug='jsc-generic'; root=\"${CLAUDE_PLUGIN_ROOT:-}\"; if [ -n \"$root\" ] && [ -f \"$root/$rel\" ]; then exec \"$root/$rel\"; fi; for base in \"$HOME/.claude/plugins/cache\" \"$HOME/.codex/plugins/cache\"; do for dir in \"$base/$own/$plug\" \"$base\"; do s=$(find \"$dir\" -path \"*/$plug/*/$rel\" -type f 2>/dev/null | sort -V | tail -n 1); if [ -n \"$s\" ]; then exec \"$s\"; fi; done; done; exit 0",
|
|
"timeout": 10
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"Stop": [
|
|
{
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "rel='scripts/role/role_capture.sh'; own='generic'; plug='jsc-generic'; root=\"${CLAUDE_PLUGIN_ROOT:-}\"; if [ -n \"$root\" ] && [ -f \"$root/$rel\" ]; then exec \"$root/$rel\"; fi; for base in \"$HOME/.claude/plugins/cache\" \"$HOME/.codex/plugins/cache\"; do for dir in \"$base/$own/$plug\" \"$base\"; do s=$(find \"$dir\" -path \"*/$plug/*/$rel\" -type f 2>/dev/null | sort -V | tail -n 1); if [ -n \"$s\" ]; then exec \"$s\"; fi; done; done; exit 0",
|
|
"timeout": 60
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"PreCompact": [
|
|
{
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "rel='scripts/role/role_capture.sh'; own='generic'; plug='jsc-generic'; root=\"${CLAUDE_PLUGIN_ROOT:-}\"; if [ -n \"$root\" ] && [ -f \"$root/$rel\" ]; then exec \"$root/$rel\" --precompact; fi; for base in \"$HOME/.claude/plugins/cache\" \"$HOME/.codex/plugins/cache\"; do for dir in \"$base/$own/$plug\" \"$base\"; do s=$(find \"$dir\" -path \"*/$plug/*/$rel\" -type f 2>/dev/null | sort -V | tail -n 1); if [ -n \"$s\" ]; then exec \"$s\" --precompact; fi; done; done; exit 0",
|
|
"timeout": 60
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"PostCompact": [
|
|
{
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "rel='scripts/role/role_capture.sh'; own='generic'; plug='jsc-generic'; root=\"${CLAUDE_PLUGIN_ROOT:-}\"; if [ -n \"$root\" ] && [ -f \"$root/$rel\" ]; then exec \"$root/$rel\" --postcompact; fi; for base in \"$HOME/.claude/plugins/cache\" \"$HOME/.codex/plugins/cache\"; do for dir in \"$base/$own/$plug\" \"$base\"; do s=$(find \"$dir\" -path \"*/$plug/*/$rel\" -type f 2>/dev/null | sort -V | tail -n 1); if [ -n \"$s\" ]; then exec \"$s\" --postcompact; fi; done; done; exit 0",
|
|
"timeout": 30
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
}
|