feat(hooks): 新增部署後強制重啟閘門,接線與冒煙同步到八支 hook #33
1 Participants
Notifications
Due Date
No due date set.
Blocks
#27 feat(cli): 部署收尾產生更新與移除指引,並掛上部署後重啟閘門
plugins/cli
Reference: plugins/hooks#33
Reference in New Issue
Block a user
feat(hooks): 新增部署後強制重啟閘門,接線與冒煙同步到八支 hook
摘要
jsc-hooks的落地。部署後強制重啟:狀態檔$JSC_HOME/restart-required存在時擋下技能呼叫,逃生門JSC_RESTART_GATE=off,豁免九支(jsc-cli:deploy、jsc-hooks:hooks-install、jsc-gitea:wiki、jsc-log:worklog、jsc-log:learn、jsc-meta:*、jsc-ask:ask、jsc-git:pr、jsc-git:commit)。狀態檔由jsc-cli:deploy收尾寫入、由新工作階段開始時清除。決策紀錄在 wikiknowledges/QUESTION的QUESTION_FB8DF0B5。變更內容
hooks/restart-gate.shrequire、clear、report三個子命令供jsc-cli與session-timer.sh呼叫hooks/hooks.jsonversion-guard.sh前面hooks/session-timer.shstart與restart判定為新工作階段時轉呼叫restart-gate.sh cleartools/wire-cli.shsmoke補八條判定路徑與清除機制,claude 的接線驗證與status各加一個檢查點,四個 CLI 的 degraded 說法補上重啟閘門接不上skills/hooks-install/SKILL.mdrestart-gate.sh與session-timer.sh的清除職責README.md、AGENTS.mdjsc-cli的介面,只寫在腳本註解裡另一邊看不到。新增 hook 列、「部署後重啟狀態檔」一節、JSC_RESTART_GATE環境變數列,覆蓋範圍改八支plugin.json、.claude-plugin/plugin.json、.codex-plugin/plugin.json設計重點
at、mode、domains、cli四個欄位缺了只讓擋人訊息少幾個字,不影響判定。格式是純文字key=value,與工作包狀態檔同一套,jsc-hooks與jsc-cli兩邊各自實作也對得上。version-guard.sh:狀態檔讀不到、技能名取不到、工具名不是Skill、技能不是jsc-*:*,四種都 exit 0。沒有證據時擋下等於停掉每一次技能呼叫。jsc-ask:ask、jsc-git:pr、jsc-git:commit)自己不是收尾規則的主體,是為了讓前六支走得完才補進來的——清單認的是技能名,不是呼叫鏈,豁免技能轉呼叫的下一層若不在清單上照樣會被擋。session-timer.sh,狀態檔留在restart-gate.sh。 新舊工作階段的判準(sessions/{sid}.start在不在)只有session-timer.sh知道,兩邊各寫一份就會漂移。續接同一階段(SessionStart 再觸發、resume、compact)走不到那一段,閘門就一路留到真的重新啟動。require、clear、report都不讀標準輸入,只有 hook 模式讀;工具端呼叫一律補</dev/null。理由與sdlc-gate.sh相同:標準輸入是管線又沒人關閉時,讀取會一直等,呼叫端整支卡死。version-guard.sh前面。 還沒重啟的舊版比落後一個版號更該先攔;先問「你在跑的是不是舊版」,再問「磁碟上的是不是最新版」。/jsc-cli:deploy收尾的提示自己動手。這一句在wire-cli.sh、技能與 README 三處都寫一致。測試結果
tools/ste100-lint.sh對本存取庫全綠;三份 manifest 版本一致為 0.2.4。restart-gate.sh判定路徑逐條實測:狀態檔不存在放行(exit 0);狀態檔存在且技能為jsc-sdlc:implement或jsc-sdlc:plan擋下(exit 2);九支豁免技能全放行(exit 0);JSC_RESTART_GATE=off放行;技能名取不到放行。restart子命令清。tools/wire-cli.sh smoke claude→status=ok,14 項判定路徑全部「與預期相同」。jsc-cli的deploy.sh update經restart-gate.sh require寫出的狀態檔是key=value四欄,本端讀得懂並正確擋下。修正前jsc-cli自己寫四欄 TSV、本端讀key=value,兩邊對不上;改成由jsc-cli轉呼叫require後才通過。ste100-lint.sh全綠,三份 manifest 版本各自一致。前置 Push Request
What:新增第八支 hook `hooks/restart-gate.sh`。hook 模式在 `$JSC_HOME/restart-required` 存在時以 exit 2 擋下 jsc 技能呼叫,另有三個子命令:`require {模式} [{domain}...]` 寫入狀態檔掛上閘門、`clear` 清除狀態檔、`report` 印出狀態檔內容。`hooks/hooks.json` 把它接到 PreToolUse(Skill),排在 `version-guard.sh` 前面。`hooks/session-timer.sh` 的 `start` 與 `restart` 在判定為新工作階段時轉呼叫 `clear`。 Why:部署換掉的是磁碟上的技能檔,正在跑的 CLI 行程載入的還是舊版——SKILL.md、hook 腳本與 tools 都在啟動當下讀進記憶體。這段落差期間跑技能,改動看起來沒生效,人會以為部署失敗又重跑一次。所以部署收尾要求重新啟動,這道閘門負責讓「還沒重啟就繼續用技能」擋在門外。 How:判定看的是「檔案在不在」,欄位只用在擋人訊息上——欄位缺了只讓訊息少幾個字,不影響判定。狀態檔用純文字 `key=value`(`at`、`mode`、`domains`、`cli`),格式與工作包狀態檔同一套,`jsc-hooks` 與 `jsc-cli` 兩邊各自實作也對得上。放行原則比照 `version-guard.sh`:只擋確定違規,狀態檔讀不到、技能名取不到、工具名不是 `Skill`、技能不是 `jsc-*:*` 一律 exit 0,沒有證據時擋下等於停掉每一次技能呼叫。九支豁免(`jsc-cli:deploy`、`jsc-hooks:hooks-install`、`jsc-gitea:wiki`、`jsc-log:worklog`、`jsc-log:learn`、`jsc-meta:*`、`jsc-ask:ask`、`jsc-git:pr`、`jsc-git:commit`)的理由是同一件事:部署後還要寫得完技能組異動報告與工作日誌,整批擋下去「先重啟」與「先寫完報告」會互相打死。後三支自己不是收尾規則的主體,是為了讓前六支走得完才補進來的——清單認的是技能名,不是呼叫鏈。清除交給 `session-timer.sh`,不由本檔自己判:新舊工作階段的判準(`sessions/{sid}.start` 在不在)只有那支腳本知道,兩邊各寫一份就會漂移;續接同一階段走不到那一段,閘門就一路留到真的重新啟動。`require`、`clear`、`report` 都不讀標準輸入,只有 hook 模式讀,工具端呼叫一律再補 `</dev/null`,理由與 `sdlc-gate.sh` 相同。接線排在 `version-guard.sh` 前面:還沒重啟的舊版比落後一個版號更該先攔。不認得的子命令一律安靜 exit 0,不中斷宿主 CLI。擋人訊息依實際 CLI 給重啟方式,並附上豁免清單與逃生門 `JSC_RESTART_GATE=off`。 Who:部署後的第一次技能呼叫,以及 `jsc-cli:deploy` 收尾寫入狀態檔的那一端。