release: v0.2.5 develop 到 master #36

Merged
admin merged 9 commits from develop into master 2026-08-27 09:00:47 +00:00
Member

摘要

  • 需求描述:把 jsc-hooks 0.2.5 從 develop 放行到 master,共 9 個 commit。內容是使用者 15 條工作規則的第三群「技能組治理」在本存取庫的落地:新增第八支 hook restart-gate.sh,部署完沒重啟就擋下技能呼叫,並把接線與冒煙測試從七支同步到八支。
  • 計畫名稱:無
  • 計畫頁:無
  • 分析頁:無

變更內容

檔案 為什麼改
hooks/restart-gate.sh 新增第八支 hook。PreToolUse 時機,狀態檔 $JSC_HOME/restart-required 存在時擋下技能呼叫並回 exit 2。
hooks/hooks.json 註冊 restart-gate.sh,順序排在 version-guard.sh 前面:沒重啟就先擋,不必再花一次網路往返去比版本。
hooks/session-timer.sh 偵測到新工作階段時清除狀態檔,讓重啟本身就是解除條件,不需要人手動清。
tools/wire-cli.sh 接線與冒煙測試從七支 hook 改八支,並補上非 claude 的 CLI 沒有 pre-tool hook 時的降級說法。
skills/hooks-install/SKILL.md 技能同步到八支 hook,豁免清單補齊為九支,與實作和 jsc-meta 準則對齊。
README.md、AGENTS.md 補上部署後重啟閘門的說明與狀態檔格式。
plugin.json、.claude-plugin/plugin.json、.codex-plugin/plugin.json 三份 manifest 同步升版到 0.2.5,描述補齊八支 hook。

設計重點

  • 這一段才是讓已安裝的 CLI 抓到新內容的那一段。develop 併了不等於生效:marketplace 與本存取庫的 hooks/version-guard.sh 讀的都是存取庫的預設分支 master。version-guard.sh 取 raw plugin.json 時刻意不指定 ref,Gitea 就回預設分支那一份,所以只有這個 PR 合進 master,五支 CLI 才看得到 0.2.5。
  • 閘門不自鎖。豁免九支涵蓋所有能解除困境的路: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。被擋住的人還是能提交、能開 PR、能重跑部署、能記錄。
  • 逃生門 JSC_RESTART_GATE=off。閘門判斷錯的時候,使用者不必去刪狀態檔就能繼續工作。
  • 取不到技能名就放行。寧可漏擋也不要誤擋,判斷資訊不足時不是預設擋下。
  • 排在 version-guard.sh 前面是刻意的。版本閘門要打網路取 raw plugin.json,重啟閘門只讀本機檔案,先做便宜的那個。

升級後使用者會立刻感受到的差異

  • 重啟閘門會開始擋人。 部署完沒重啟就呼叫非豁免技能,會 exit 2 被擋下。逃生門是 JSC_RESTART_GATE=off。
  • 只有 claude 擋得住。 codex、copilot、antigravity、kiro 都沒有 pre-tool hook,那四支一次都擋不下來。狀態檔照樣寫、照樣清,但實際的重啟只能靠 deploy 收尾的提示,使用者得自己照做。這是四支 CLI 的能力限制,不是接線漏掉。

測試結果

  • ste100-lint.sh 掃本存取庫全綠。
  • 三份 manifest 版本一致為 0.2.5。
  • restart-gate.sh 擋下情境:jsc-sdlc:implement 與 jsc-sdlc:plan 在狀態檔存在時都回 exit 2。
  • restart-gate.sh 豁免情境:九支豁免技能全部放行。
  • restart-gate.sh 逃生門:JSC_RESTART_GATE=off 時放行。
  • restart-gate.sh 降級情境:技能名取不到時放行。
  • restart-gate.sh 清除機制:同一個 session id 續接不清、換 id 才清、restart 子命令也清。
  • 跨存取庫狀態檔對齊實測:jsc-cli 的 deploy.sh update 經 restart-gate.sh require 寫出 key=value 格式的狀態檔,本存取庫的 restart-gate.sh 讀得懂並正確擋下。
  • wire-cli.sh smoke claude 回 status=ok,14 項判定路徑都與預期相同。
  • 沒跑的部分據實說明:非 claude 的四支 CLI 上的重啟閘門無法測試。codex、copilot、antigravity、kiro 沒有 pre-tool hook,沒有可以掛上去的時機,所以這是能力限制導致的不可測,不是還沒測。
  • 本次放行本身沒有重跑腳本測試。上列測試是在子功能 PR(#33、#34)與主幹 PR(#35)階段跑的,這個 PR 只是把已驗證的 develop 內容推到預設分支。

前置 Push Request

  • 無
## 摘要 - 需求描述:把 jsc-hooks 0.2.5 從 `develop` 放行到 `master`,共 9 個 commit。內容是使用者 15 條工作規則的第三群「技能組治理」在本存取庫的落地:新增第八支 hook `restart-gate.sh`,部署完沒重啟就擋下技能呼叫,並把接線與冒煙測試從七支同步到八支。 - 計畫名稱:無 - 計畫頁:無 - 分析頁:無 ## 變更內容 | 檔案 | 為什麼改 | | --- | --- | | `hooks/restart-gate.sh` | 新增第八支 hook。PreToolUse 時機,狀態檔 `$JSC_HOME/restart-required` 存在時擋下技能呼叫並回 exit 2。 | | `hooks/hooks.json` | 註冊 `restart-gate.sh`,順序排在 `version-guard.sh` 前面:沒重啟就先擋,不必再花一次網路往返去比版本。 | | `hooks/session-timer.sh` | 偵測到新工作階段時清除狀態檔,讓重啟本身就是解除條件,不需要人手動清。 | | `tools/wire-cli.sh` | 接線與冒煙測試從七支 hook 改八支,並補上非 claude 的 CLI 沒有 pre-tool hook 時的降級說法。 | | `skills/hooks-install/SKILL.md` | 技能同步到八支 hook,豁免清單補齊為九支,與實作和 jsc-meta 準則對齊。 | | `README.md`、`AGENTS.md` | 補上部署後重啟閘門的說明與狀態檔格式。 | | `plugin.json`、`.claude-plugin/plugin.json`、`.codex-plugin/plugin.json` | 三份 manifest 同步升版到 0.2.5,描述補齊八支 hook。 | ## 設計重點 - 這一段才是讓已安裝的 CLI 抓到新內容的那一段。`develop` 併了不等於生效:marketplace 與本存取庫的 `hooks/version-guard.sh` 讀的都是存取庫的**預設分支** `master`。`version-guard.sh` 取 raw `plugin.json` 時刻意不指定 ref,Gitea 就回預設分支那一份,所以只有這個 PR 合進 `master`,五支 CLI 才看得到 0.2.5。 - 閘門不自鎖。豁免九支涵蓋所有能解除困境的路:`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`。被擋住的人還是能提交、能開 PR、能重跑部署、能記錄。 - 逃生門 `JSC_RESTART_GATE=off`。閘門判斷錯的時候,使用者不必去刪狀態檔就能繼續工作。 - 取不到技能名就放行。寧可漏擋也不要誤擋,判斷資訊不足時不是預設擋下。 - 排在 `version-guard.sh` 前面是刻意的。版本閘門要打網路取 raw `plugin.json`,重啟閘門只讀本機檔案,先做便宜的那個。 ## 升級後使用者會立刻感受到的差異 - **重啟閘門會開始擋人。** 部署完沒重啟就呼叫非豁免技能,會 exit 2 被擋下。逃生門是 `JSC_RESTART_GATE=off`。 - **只有 claude 擋得住。** codex、copilot、antigravity、kiro 都沒有 pre-tool hook,那四支一次都擋不下來。狀態檔照樣寫、照樣清,但實際的重啟只能靠 `deploy` 收尾的提示,使用者得自己照做。這是四支 CLI 的能力限制,不是接線漏掉。 ## 測試結果 - `ste100-lint.sh` 掃本存取庫全綠。 - 三份 manifest 版本一致為 0.2.5。 - `restart-gate.sh` 擋下情境:`jsc-sdlc:implement` 與 `jsc-sdlc:plan` 在狀態檔存在時都回 exit 2。 - `restart-gate.sh` 豁免情境:九支豁免技能全部放行。 - `restart-gate.sh` 逃生門:`JSC_RESTART_GATE=off` 時放行。 - `restart-gate.sh` 降級情境:技能名取不到時放行。 - `restart-gate.sh` 清除機制:同一個 session id 續接不清、換 id 才清、`restart` 子命令也清。 - 跨存取庫狀態檔對齊實測:jsc-cli 的 `deploy.sh update` 經 `restart-gate.sh require` 寫出 key=value 格式的狀態檔,本存取庫的 `restart-gate.sh` 讀得懂並正確擋下。 - `wire-cli.sh smoke claude` 回 `status=ok`,14 項判定路徑都與預期相同。 - 沒跑的部分據實說明:**非 claude 的四支 CLI 上的重啟閘門無法測試**。codex、copilot、antigravity、kiro 沒有 pre-tool hook,沒有可以掛上去的時機,所以這是能力限制導致的不可測,不是還沒測。 - 本次放行本身沒有重跑腳本測試。上列測試是在子功能 PR(#33、#34)與主幹 PR(#35)階段跑的,這個 PR 只是把已驗證的 `develop` 內容推到預設分支。 ## 前置 Push Request - 無
jiantw83 added 9 commits 2026-08-27 09:00:05 +00:00
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` 收尾寫入狀態檔的那一端。
What:`tools/wire-cli.sh` 四處增修。`smoke` 加跑 `restart-gate.sh`,另外自備一份暫時的 `$JSC_HOME`,把八條判定路徑(狀態檔不存在、狀態檔存在且技能為 `jsc-sdlc:implement`、四支豁免技能各一條、逃生門、取不到技能名)各跑一次並比對結束碼,再驗一次清除機制真的清得掉;claude 的接線驗證與 `status` 盤點各加一個 `restart-gate` 檢查點;codex、copilot、antigravity、kiro 四支的 degraded 說法補上「部署後重啟閘門也接不上」;檔頭與各處「七支」一律改為「八支」。

Why:新的 hook 接進 `hooks.json` 只代表宣告在檔案裡。接線驗證不點名就漏得掉——`comment-scope.sh` 與 `lang-guard.sh` 當初就是為同一個原因各列一項。冒煙測試也一樣:不自備狀態檔,只走得到「狀態檔不存在」與「取不到技能名」兩條捷徑,擋人與豁免那幾條一次都跑不到,判定寫了卻沒驗等於沒寫。四個 CLI 的降級說法不補,回報就會暗示每個 CLI 都擋得下來。

How:驗的是判定結果本身,不只是腳本跑得完——每一條路徑都給定預期結束碼,對不上就計入失敗並印出前 200 字的輸出。狀態檔放在暫時目錄,冒煙測試不該把使用者真正的 `$JSC_HOME/restart-required` 拆掉。清除機制那一段刻意走 `session-timer.sh start` 這條真實路徑,不直接呼叫 `clear`:要驗的是「新工作階段會不會清」,不是「`clear` 這個子命令能不能刪檔」。每次呼叫都接 `</dev/null`:hook 模式會讀標準輸入,管線沒人關閉時整支會卡死。建不出暫存目錄也算失敗,不能靜悄悄跳過。四支非 claude 的 CLI 除了 degraded 一句,另外逐支印一行講明後果:一次技能呼叫都擋不下來,狀態檔照樣寫、下次工作階段開始照樣清,只是中間沒有判定點,重啟要靠 `/jsc-cli:deploy` 收尾的提示自己動手。

Who:`jsc-hooks:hooks-install` 的接線、冒煙與盤點三個子命令。
What:`skills/hooks-install/SKILL.md` 四處增修。`description` 與目標段落的 hook 清單加入 `restart-gate.sh`,七支改八支;降級說明補上「四個 CLI 連部署後重啟閘門也接不上」與後果一句;第 4 步的冒煙說明補上重啟閘門的每條判定路徑;備註新增 `restart-gate.sh` 一條,並在 `session-timer.sh` 那一條補上「`start` 與 `restart` 會清除閘門」。

Why:技能是接線這件事的對外說法。hook 加了一支、技能還寫七支,回報就會少一項,而且降級說法不補會暗示每個 CLI 都擋得下來——這正是準則明文禁止的。`session-timer.sh` 那條也要補:清除閘門掛在那兩個事件上,接線少了它們,閘門會一路擋到使用者自己下逃生門。

How:降級那一段把後果講明白,不只說「接不上」:在那四個 CLI 上一次技能呼叫都擋不下來,狀態檔照樣寫、下一個工作階段開始照樣清,重啟本身只靠 `jsc-cli:deploy` 的收尾訊息。備註那一條寫出豁免清單與逃生門,並講明豁免的理由是異動報告與工作日誌要寫得完,讓接線的人知道哪些技能在閘門升起時仍然叫得動。

Who:`/jsc-hooks:hooks-install` 的接線流程與對使用者的回報。
What:`README.md` 五處增修:hook 表新增 `hooks/restart-gate.sh` 一列,`session-timer.sh` 那一列補上會清除閘門、`wire-cli.sh` 那一列補上冒煙新增的判定路徑;覆蓋範圍那段的「七支」改「八支」並補上四個 CLI 接不上重啟閘門的後果;新增「部署後重啟狀態檔」一節,用表列出四個欄位與範例,寫明誰寫誰讀;環境變數表新增 `JSC_RESTART_GATE` 一列;`hooks-install` 段落同步。`AGENTS.md` 的 domain 一句話說明補上「部署後強制重啟閘門」。

Why:狀態檔的格式是 `jsc-hooks` 與 `jsc-cli` 兩邊的介面。介面只寫在腳本註解裡,另一邊改的時候看不到,格式一走鐘閘門就掛不上——這次就真的發生過:`jsc-cli` 寫四欄 TSV、這邊讀 `key=value`,狀態檔存在卻解不出欄位。覆蓋範圍也要據實寫,八支 hook 只有 claude 全接得上。

How:格式壓到最簡的純文字 `key=value`,一行一欄位,順序不拘,不認得的鍵一律忽略,與工作包狀態檔同一套寫法,兩邊各自實作也對得上。表只寫欄位與範例,判定規則寫在表底下:判定看檔案在不在、欄位只用在擋人訊息上、寫的一律是 `jsc-cli:deploy`、清的一律是 `session-timer.sh`,而且判準留在 `session-timer.sh`、狀態檔留在 `restart-gate.sh`,兩邊都不抄對方那一半。

Who:讀 `jsc-hooks` 說明的人,以及 `jsc-cli` 那一側寫 `deploy.sh` 的人。
What:`plugin.json`、`.claude-plugin/plugin.json`、`.codex-plugin/plugin.json` 的 `version` 由 0.2.3 改為 0.2.4,`description` 的 hook 清單從五支補齊到八支,補上註解範圍守門、繁中編碼守門與部署後強制重啟。

Why:本次新增第八支 hook `restart-gate.sh` 並接進 `hooks.json`,`session-timer.sh` 多了清除閘門這件事,接線與冒煙也跟著改,屬於行為變更,版本要跟著往上走,各 CLI 才知道要更新。`description` 原本只列到「版本前置檢查」,而註解範圍與繁中編碼兩支早就在跑了,`README.md` 與 `AGENTS.md` 也都寫了八支——manifest 是各 CLI 安裝時唯一看得到的說明,落後就會讓人以為這個外掛只有五支 hook。

How:三份只改 `version` 與 `description` 兩個欄位,其餘內容不動,三份保持同一版號與同一段描述。

Who:`jsc-hooks` 外掛的套件描述檔。
Reviewed-on: #33
What:`skills/hooks-install/SKILL.md` 的 Notes 段落,重啟閘門的豁免技能清單從六支補到九支,補上 `jsc-ask:ask`、`jsc-git:pr`、`jsc-git:commit`,並寫明「閘門認技能名不認呼叫鏈」以及清單的唯一來源在 `hooks/restart-gate.sh`。

Why:這三支是使用者在同一輪追問後才裁定加入的,實作 `hooks/restart-gate.sh` 與準則 `guidelines.md`「部署後重啟閘門」都已經是九支,只有這份技能文件還停在六支。技能文件是接線時唯一會被讀到的說明,少列三支會讓人以為 `deploy` 問模式、收尾開 PR 都會被擋,反而去下逃生門。

How:只改那一行,補上三支與兩句說明,並指向清單的唯一來源,避免下次又各自維護一份。三份 manifest 版本同步升到 0.2.5。

Who:`jsc-hooks:hooks-install` 技能文件,以及部署後重啟閘門這條規則的說明一致性。
Reviewed-on: #34
Reviewed-by: 系統管理員 <1+admin@noreply.localhost>
Reviewed-on: #35
admin approved these changes 2026-08-27 09:00:43 +00:00
admin merged commit e8b14c947a into master 2026-08-27 09:00:47 +00:00
Sign in to join this conversation.
No Reviewers
No labels
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: plugins/hooks#36