fix(hooks-install): 使用穩定路徑寫入 hook 接線
This commit is contained in:
@@ -31,7 +31,7 @@ Marketplace 統一為 `jsc`(https://gitea.jsc.idv.tw/plugins/meta.git),安
|
||||
| `hooks/lang-guard.sh` | UserPromptSubmit、PostToolUse(Write、Edit、MultiEdit)、codex `notify`、kiro `userPromptSubmit`、`tools/jsc-wrap.sh` 收尾 | 所有非程式碼輸出一律繁體中文、UTF-8、無亂碼、無簡體字,共三種模式。`prompt`:在每次提示注入規則摘要(適用範圍與自我檢查各一行),五個 CLI 都接得到。無參數:寫檔後的逐檔掃描,從 stdin JSON 取 `file_path`(或環境變數 `JSC_CHANGED_FILE`),只有 claude 的 PostToolUse 接得上。`sweep [dir]`:掃整個 git 工作區這次改過的所有檔案,給沒有 post-tool hook 的四個 CLI 用,找不到 git 就安靜 exit 0。接線位置與掃描時機跟 `comment-scope.sh` 完全一樣,見下面那張表。偵測三項:簡體字(字表在 `hooks/simplified.txt`,讀不到就安靜跳過這一項)、亂碼(U+FFFD 替代字元與雙重編碼殘骸)、非 UTF-8 編碼(用 `iconv` 判定,沒有 `iconv` 就跳過)。三項都掃整個檔案、不只掃註解行,`.md` 與純文字檔照掃——那些正是「非程式碼輸出」的主場,這兩點跟 `comment-scope.sh` 刻意不同。掃描深度仍只看 `git diff HEAD` 的新增行、不翻舊帳,命中就把警告與最多三行證據送到 stderr 並以 exit 2 交回模型就地修正(不擋寫入)。二進位檔(只認 NUL 位元組)與 `*.lock`、`*.min.js`、`*.map` 這類產生檔跳過;`hooks/simplified.txt`、`hooks/ste100-guard.sh`、`hooks/lang-guard.sh` 也跳過,那三份檔案裡的簡體字與亂碼樣本是被討論的對象,不是被使用。規則正文的唯一來源在 `jsc-meta` 的 `references/ste100.md`。逃生門 `JSC_LANG_GUARD=off` |
|
||||
| `hooks/sdlc-gate.sh` | UserPromptSubmit、PreToolUse(Skill) | SDLC 階段能力標籤閘門與模型鎖:`lock {stage}` 由 jsc-sdlc 階段技能呼叫,從 transcript 讀出實際模型 id 比對該階段必要標籤(`$JSC_HOME/model-tags.tsv`),不符就拒絕上鎖;`check` 在模型不符時以 exit 2 擋下該輪提示(其他 hook 一律 exit 0,此處是刻意例外);`unlock` 為逃生門。另含工作包 PR 閘門:`wp-lock {owner}/{repo} {index} [{工作包代號}]` 記下一筆未結清的工作包 PR、`wp-unlock {owner}/{repo} {index}` 結清那一筆(檔案不存在也算成功)、`wp-claim {owner}/{repo} {工作包代號} [{PR 編號}] [{分析頁頁名}]` 記下這個存取庫目前領取哪一包、`wp-unclaim {owner}/{repo}` 交回、`wp-report` 印出所有未結清、`wp-check {prompt|skill}` 為 hook 模式。狀態檔一個工作包一支,在 `$JSC_HOME/wp/{owner}-{repo}-{index}.pr`,**刻意不綁 session**——PR 沒合併時換一個工作階段照樣要擋;一個工作包一支鎖檔是為了讓好幾個互不相依的工作包能同時記在案,不會互相覆蓋掉對方的鎖。`wp-check prompt` 只注入提醒、絕不擋提示(擋了連「去修那支 PR」的對話都送不出去);`wp-check skill` 在有未結清 PR 時以 exit 2 擋下 `plan`、`analyze`、`maintain`,但一律放行 `implement`(結清 PR 正是 implement 的步驟,擋它會鎖死流程)——這一層是整個存取庫共用的粗粒度提醒,「某個候選工作包能不能挑」的細粒度判斷在 `jsc-sdlc/tools/wp-gate.sh check-deps`,不是這裡。另外會比對歸屬:未結清的 PR 不屬於目前領取的工作包時,`prompt` 多注入一行「那幾支交給領取它的工作階段」,`skill` 在擋下 `plan`、`analyze`、`maintain` 時一併點名,`implement` 仍放行但收到同一則提醒。逃生門 `JSC_WP_GATE=off`。這道閘門只讀檔案、不打網路,PR 的真實合併狀態由 `jsc-sdlc/tools/wp-gate.sh` 查證 |
|
||||
|
||||
Claude 由 `hooks/hooks.json` 自動接線八支 hook;其他 CLI 用 `hooks-install` 技能接線、改裝包裝啟動器,或降級為規則檔。
|
||||
Claude 由 `hooks/hooks.json` 自動接線八支 hook;其他 CLI 用 `hooks-install` 技能接線、改裝包裝啟動器,或降級為規則檔。寫進使用者設定的長期命令一律指向 `$JSC_HOME/current/jsc-hooks`,不指向帶版號的 plugin 快取目錄,也不指向開發存取庫。
|
||||
|
||||
> 覆蓋範圍要據實看待:只有 claude 同時有 PreToolUse、PostToolUse 與 UserPromptSubmit,八支 hook 全接得上,回報 `wired`。codex、copilot、antigravity、kiro 都沒有 pre-tool hook,接不上 `version-guard.sh` 的版本前置檢查,也接不上 `restart-gate.sh` 的部署後重啟閘門,SDLC 模型鎖也只剩技能步驟檢查,這四個 CLI 一律回報 `degraded`,靠 `/jsc-cli:deploy` 定期更新。重啟閘門在這四個 CLI 上一次技能呼叫都擋不下來:那一支自己那份狀態檔照樣寫、下一個工作階段開始照樣清,只是中間沒有判定點,重啟得靠 `/jsc-cli:deploy` 收尾的提示自己動手。codex 另外沒有工作階段開始事件,計時改由 `tools/jsc-wrap.sh` 的 `codex` 別名在啟動當下開始;沒走別名啟動時,時間從第一輪回應算起。
|
||||
|
||||
@@ -115,7 +115,7 @@ Claude 由 `hooks/hooks.json` 自動接線八支 hook;其他 CLI 用 `hooks-in
|
||||
| `tools/jsc-wrap.sh` | 沒有完整 hook 系統的 CLI 的包裝啟動器:匯出 `JSC_CLI`、`JSC_SESSION_ID`,前後接 `session-timer.sh`,結束時自動跑 `scan-logs.sh` 回填,再依序跑一次 `comment-scope.sh sweep` 與 `lang-guard.sh sweep` 掃整個 git 工作區的註解範圍與繁中編碼(copilot 與 antigravity 沒有任何逐輪事件,整個工作階段只有這裡掃得到)。兩次收尾掃描一律不影響結束碼:包裝器原樣回傳 CLI 自己的結束碼,`sweep` 命中只把警告印到 stderr。`JSC_CLI` 存 CLI 代號,實際執行的是對應的執行檔(antigravity 是 agy、kiro 是 kiro-cli) |
|
||||
| `tools/scan-logs.sh` | 離線回填:解析 copilot、antigravity、codex 的原生日誌,把技能用量與階段界線補進 `$JSC_HOME`,重掃不重複 |
|
||||
| `tools/report-error.sh` | 失敗回報流程:把一筆 hook 或工具異常寫成 wiki 的 `ERROR_{HASH}`,並在 `ERROR_CONTENTS` 附上一列索引。wiki 位置由 `jsc-gitea` 的 `gitea.sh wiki-repo ERROR` 解析,解析不出來就安靜降級。由操作者手動執行,或由 `hooks-install` 在 `wire-cli.sh` 回報 `status=failed` 時執行;**不接在失敗的 hook 上自動觸發**(hook 一律安靜 exit 0,自我回報會疊出迴圈) |
|
||||
| `tools/wire-cli.sh` | 單一 CLI 的 hook 生命週期,共三個用法。`{cli}` 是接線:對應的設定編輯、包裝別名安裝、hook 檔建立,皆以 `<!-- jsc-hooks -->`(或 `# jsc-hooks`)標記整段重寫,重跑等同先移除再重裝;寫完每個檔案會重讀驗證位置正確才回報成功(codex 的 `notify` 必須是根層鍵、kiro 的 JSON 必須成對且 `on`、`run` 在最上層),以 `status=wired\|degraded\|skipped\|failed` 回報。`purge {cli}` 是移除:把該 CLI 的**所有** hook 清掉,含非 jsc 的第三方項目,動到的檔案先原樣備份到 `$JSC_HOME/backup/hooks/{cli}/{yyyyMMdd_HHmmss}/`,備份失敗就不移除,移除後重讀驗證,驗不過自動還原備份,以 `status=purged\|skipped\|failed` 回報。`smoke {cli}` 是執行期冒煙測試:八支 hook 的每個接線模式各跑一次,非零退出即為錯誤,另外用一份暫時的 `$JSC_HOME` 狀態檔把工作包歸屬的四條判定路徑(查無歸屬、自己的工作包、別的工作包、逃生門)與重啟閘門的五條判定路徑(狀態檔不存在、狀態檔存在、豁免技能、逃生門、取不到技能名)各跑一次並比對結束碼,再驗一次重啟閘門的清除機制真的清得掉,驗的是判定結果本身,不只是腳本跑得完(例外有三個:`sdlc-gate.sh check` 的 exit 2 是階段鎖的設計行為,`comment-scope.sh` 與 `lang-guard.sh` 掃描模式的 exit 2 是掃到違規的設計行為——`sweep` 在髒工作區本來就會回 2,不算 hook 壞掉),以 `status=ok\|failed` 回報。`status {cli}` 是唯讀盤點:只讀設定檔判斷標記段落在不在,不寫檔也不執行 hook,每個接線點印一行 `item<TAB>{項目}<TAB>{路徑}<TAB>{present\|missing}`,以 `status=wired\|degraded\|unwired\|skipped` 回報(結束碼 0、1、5、3)。體檢類技能(`/jsc-cli:doctor`)只能用這個子命令,另外三個都會動到環境 |
|
||||
| `tools/wire-cli.sh` | 單一 CLI 的 hook 生命週期,共三個用法。`{cli}` 是接線:先建立或更新 `$JSC_HOME/current/jsc-hooks` 指向目前這版 plugin,接著把對應的設定編輯、包裝別名安裝、hook 檔建立成穩定路徑,皆以 `<!-- jsc-hooks -->`(或 `# jsc-hooks`)標記整段重寫,重跑等同先移除再重裝;寫完每個檔案會重讀驗證位置正確才回報成功(codex 的 `notify` 必須是根層鍵、kiro 的 JSON 必須成對且 `on`、`run` 在最上層),也會確認寫入路徑能解到既有腳本。檔案系統不能建立 symlink 時,會明確回報並退回目前根目錄,不會靜默寫出壞路徑。`status=wired\|degraded\|skipped\|failed` 回報接線結果。`purge {cli}` 是移除:把該 CLI 的**所有** hook 清掉,含非 jsc 的第三方項目,動到的檔案先原樣備份到 `$JSC_HOME/backup/hooks/{cli}/{yyyyMMdd_HHmmss}/`,備份失敗就不移除,移除後重讀驗證,驗不過自動還原備份,以 `status=purged\|skipped\|failed` 回報。`smoke {cli}` 是執行期冒煙測試:八支 hook 的每個接線模式各跑一次,非零退出即為錯誤,另外用一份暫時的 `$JSC_HOME` 狀態檔把工作包歸屬的五條判定路徑與重啟閘門的十二條判定與清除路徑各跑一次並比對結束碼,驗的是判定結果本身,不只是腳本跑得完(例外有三個:`sdlc-gate.sh check` 的 exit 2 是階段鎖的設計行為,`comment-scope.sh` 與 `lang-guard.sh` 掃描模式的 exit 2 是掃到違規的設計行為——`sweep` 在髒工作區本來就會回 2,不算 hook 壞掉),以 `status=ok\|failed` 回報。`status {cli}` 是唯讀盤點:只讀設定檔判斷標記段落在不在,不寫檔也不執行 hook,每個接線點印一行 `item<TAB>{項目}<TAB>{路徑}<TAB>{present\|missing}`,也會把帶版號快取路徑、開發存取庫路徑與不存在的腳本列為缺項;`status claude` 讀 Claude Code 實際載入的 `installed_plugins.json`,不再檢查目前腳本旁邊那份 `hooks.json`。體檢類技能(`/jsc-cli:doctor`)只能用這個子命令,另外三個都會動到環境 |
|
||||
| `tools/scan-hook-errors.sh` | 掃 CLI 原生紀錄找 hook 的執行期錯誤(接線寫對、跑起來出錯)。只有 claude 有 hook 結果紀錄,掃 `~/.claude/projects/**/*.jsonl` 的 `hook_non_blocking_error` 與非空 `hookErrors`;codex、copilot、antigravity、kiro 沒有等價紀錄,一律回報 `unavailable` 並指向 `wire-cli.sh smoke {cli}`。每筆錯誤附加一行 JSON 到 `$JSC_HOME/errors/hooks.jsonl`,`jsc` 欄位標明是不是 jsc 自己的 hook(第三方 hook 的錯誤只回報,不由 jsc 修正);去重與 `scan-logs.sh` 同法,重掃只讀新增段落,以 `status=clean\|errors\|unavailable` 回報 |
|
||||
|
||||
## 失敗回報範本
|
||||
@@ -136,7 +136,7 @@ Claude 由 `hooks/hooks.json` 自動接線八支 hook;其他 CLI 用 `hooks-in
|
||||
|
||||
### `hooks-install`
|
||||
|
||||
把八支 hook 接線到所有已安裝的 CLI,每個 CLI 走四道關卡:先 `tools/wire-cli.sh purge {cli}` 備份後移除所有 hook(含非 jsc 的第三方項目,乾淨起跑才分得清後續失敗是誰的),再 `tools/wire-cli.sh {cli}` 接線(claude 由 `hooks.json` 自動接線,無需寫入),接著 `tools/wire-cli.sh smoke {cli}` 驗執行期,最後 `tools/scan-hook-errors.sh --cli {cli}` 掃原生紀錄。codex、copilot、antigravity 由接線腳本裝上 `tools/jsc-wrap.sh` 包裝別名補上計時與用量回填(結束時自動跑 `tools/scan-logs.sh`),語言規則仍重寫到各自的規則檔(以 `<!-- jsc-hooks -->` 標記整段取代,等同先移除再重裝,不重複追加)。codex、copilot、antigravity、kiro 的 SDLC 模型鎖降級為技能步驟檢查,鎖檔仍由 SDLC 技能直接呼叫 `sdlc-gate.sh lock` 寫入;這四個 CLI 沒有 pre-tool hook,版本前置檢查與部署後重啟閘門都接不上(重啟閘門在那四支上一次技能呼叫都擋不下來,狀態檔照樣寫、下個工作階段照樣清);也沒有 post-tool hook,`comment-scope.sh` 接不到逐檔即時掃描,改用 `sweep` 掃整個 git 工作區——codex 每輪結束、kiro 每輪提示送出時、copilot 與 antigravity 只有工作階段結束時掃一次,腳本會在 `reason` 裡講明各自的時機,只有 claude 回報 `wired`,也只有 claude 掃得到執行期錯誤紀錄。任一關卡出錯(purge、接線、冒煙失敗,或掃到 `jsc=true` 的執行期錯誤)就先寫 `ERROR_{HASH}`,再交給 `repair` 技能接手並以 `develop` PR 收尾;此時允許中止剩下的安裝,但修正一定要開始。掃到 `jsc=false` 的第三方 hook 錯誤只回報,不轉修正。
|
||||
把八支 hook 接線到所有已安裝的 CLI,每個 CLI 走四道關卡:先 `tools/wire-cli.sh purge {cli}` 備份後移除所有 hook(含非 jsc 的第三方項目,乾淨起跑才分得清後續失敗是誰的),再 `tools/wire-cli.sh {cli}` 接線(claude 由 `hooks.json` 自動接線,無需寫入;其他 CLI 的持久命令會寫成 `$JSC_HOME/current/jsc-hooks` 穩定路徑),接著 `tools/wire-cli.sh smoke {cli}` 驗執行期,最後 `tools/scan-hook-errors.sh --cli {cli}` 掃原生紀錄。codex、copilot、antigravity 由接線腳本裝上 `tools/jsc-wrap.sh` 包裝別名補上計時與用量回填(結束時自動跑 `tools/scan-logs.sh`),語言規則仍重寫到各自的規則檔(以 `<!-- jsc-hooks -->` 標記整段取代,等同先移除再重裝,不重複追加)。codex、copilot、antigravity、kiro 的 SDLC 模型鎖降級為技能步驟檢查,鎖檔仍由 SDLC 技能直接呼叫 `sdlc-gate.sh lock` 寫入;這四個 CLI 沒有 pre-tool hook,版本前置檢查與部署後重啟閘門都接不上(重啟閘門在那四支上一次技能呼叫都擋不下來,狀態檔照樣寫、下個工作階段照樣清);也沒有 post-tool hook,`comment-scope.sh` 接不到逐檔即時掃描,改用 `sweep` 掃整個 git 工作區——codex 每輪結束、kiro 每輪提示送出時、copilot 與 antigravity 只有工作階段結束時掃一次,腳本會在 `reason` 裡講明各自的時機,只有 claude 回報 `wired`,也只有 claude 掃得到執行期錯誤紀錄。任一關卡出錯(purge、接線、冒煙失敗,或掃到 `jsc=true` 的執行期錯誤)就先寫 `ERROR_{HASH}`,再交給 `repair` 技能接手並以 `develop` PR 收尾;此時允許中止剩下的安裝,但修正一定要開始。掃到 `jsc=false` 的第三方 hook 錯誤只回報,不轉修正。
|
||||
|
||||
### `repair`
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ Goal: make the eight hooks (`ste100-guard.sh`, `session-timer.sh`, `skill-usage.
|
||||
|
||||
Install on a clean slate. Every CLI is purged of all hooks first, third-party ones included, so a later failure has exactly one owner. `tools/wire-cli.sh purge` backs up every file it touches before it removes anything, so the removal stays reversible.
|
||||
|
||||
The wiring commands stored in user config use `$JSC_HOME/current/jsc-hooks`, not the versioned plugin cache path and not the development checkout. `tools/wire-cli.sh {cli}` creates or refreshes that symlink before it writes `notify`, shell aliases or Kiro hook JSON, then verifies the linked scripts exist. If the filesystem cannot create the symlink, the script must say so and explicitly fall back to the current root; it must never write a silent broken path.
|
||||
|
||||
Only claude has PreToolUse, PostToolUse and UserPromptSubmit, so only claude reports `wired`. On codex, copilot, antigravity and kiro neither the version guard nor the post-deploy restart gate can be wired at all, and the SDLC gate degrades to the skill-step check, so all four report `degraded` — report that gap as the script words it instead of implying every CLI is covered. On those four the restart gate blocks no skill call whatsoever: the state file is still written and still cleared at the next session start, so the restart itself rests on the `jsc-cli:deploy` closing message.
|
||||
|
||||
`comment-scope.sh` and `lang-guard.sh` both reach all five, wired at the same set of places, but on a different event and at a different moment each. Report the timing per CLI; never state it as one uniform behaviour:
|
||||
@@ -32,8 +34,8 @@ The detailed flow **MUST run as a sub agent**; the main agent only reports the s
|
||||
|
||||
1. Run `jsc-cli/tools/detect-clis.sh`. Done when you hold the list of installed CLIs; when the list is empty, report that and stop.
|
||||
2. For each installed CLI, run `tools/wire-cli.sh purge {cli}`. The script backs up every file it touches, removes all hooks, re-reads each file to confirm the removal, and restores the backup by itself when a check fails. Done when every CLI has printed exactly one `status=purged|skipped|failed reason=...` line and you have noted the backup directory path from its `[jsc]` output.
|
||||
3. For each installed CLI, run `tools/wire-cli.sh {cli}`. The script owns both the wiring and its verification: it writes the config, alias or hook file inside a `<!-- jsc-hooks -->` (or `# jsc-hooks`) marker block, re-reads every file it wrote, and confirms the block is present and correctly placed before it prints a success status. Trust its first line, `status=wired|degraded|skipped|failed reason=...`. Exit 2 means a bad CLI name, not a wiring outcome — fix the name and rerun. Done when every installed CLI has printed exactly one `status=` line and none exited 2.
|
||||
4. For each installed CLI, run `tools/wire-cli.sh smoke {cli}`. This runs all eight hooks once each, every wired mode included, plus each decision path of the work-package check and of the restart gate, and catches what the wiring check cannot see: a hook that is wired correctly and still fails when it executes. Done when every CLI has printed one `status=ok|failed reason=...` line plus one result line per hook.
|
||||
3. For each installed CLI, run `tools/wire-cli.sh {cli}`. The script owns both the wiring and its verification: it refreshes `$JSC_HOME/current/jsc-hooks`, writes the config, alias or hook file inside a `<!-- jsc-hooks -->` (or `# jsc-hooks`) marker block, re-reads every file it wrote, confirms the block is present and correctly placed, and confirms the stored runtime paths resolve to existing scripts before it prints a success status. Trust its first line, `status=wired|degraded|skipped|failed reason=...`. Exit 2 means a bad CLI name, not a wiring outcome — fix the name and rerun. Done when every installed CLI has printed exactly one `status=` line and none exited 2.
|
||||
4. For each installed CLI, run `tools/wire-cli.sh smoke {cli}`. This runs all eight hooks once each, every wired mode included, plus each decision path of the work-package check and of the restart gate, and catches what the wiring check cannot see: a hook that is wired correctly and still fails when it executes. Done when every CLI has printed one `status=ok|failed reason=...` line plus 31 result lines: 14 hook mode lines, 5 work-package decision lines, and 12 restart-gate decision and cleanup lines. The line count is higher than the hook count because `sdlc-gate.sh`, `comment-scope.sh` and `lang-guard.sh` each have multiple wired modes.
|
||||
5. For each installed CLI, run `tools/scan-hook-errors.sh --cli {cli}`. Only claude keeps hook results in its native records and can answer `clean` or `errors`; codex, copilot, antigravity and kiro answer `unavailable`, and their runtime evidence comes from step 4 alone. Done when every CLI has printed one `status=clean|errors|unavailable reason=...` line and the four `unavailable` CLIs are reported as exactly that, not as clean.
|
||||
6. For each error — `purge` failed, wiring failed, smoke failed, or a scanned error with `jsc=true` — run `tools/report-error.sh --hook {script name} --exit {code} --summary "{reason}" --cli {cli}` with the script's `[jsc]` output on stdin, then hand the failure to `jsc-hooks:repair`, which **MUST run as a sub agent** and must finish by opening a PR against `develop`. Aborting the remaining installs here is allowed as long as the repair starts. A scanned error with `jsc=false` belongs to a third-party hook: report it and leave it alone. Done when each error has either an `ERROR_{HASH}` page name on stdout, or an empty exit 0 meaning `JSC_WIKI_REPO_ERROR` and `JSC_WIKI_REPO` are both unset — in that second case carry the reason into step 7 instead. Skip this step when every CLI passed all four checks.
|
||||
7. Report four results per CLI — purge, wiring, smoke, scan — each with the reason its script printed, plus any `ERROR_{HASH}` page name and repair PR URL. Done when every detected CLI has exactly one status per check and every repair has a PR against `develop`.
|
||||
@@ -45,6 +47,7 @@ The detailed flow **MUST run as a sub agent**; the main agent only reports the s
|
||||
- `restart-gate.sh` blocks jsc skill calls while `$JSC_HOME/restart-required.d/{cli}` exists — one file per CLI, named after the CLI code — so a freshly deployed skill set is not used by a process still running the old one. Each CLI reads only its own file: another CLI's file never blocks this one, and a restart clears only the file of the CLI that restarted. `jsc-cli:deploy` writes the current CLI's file through `restart-gate.sh require {install|update} [{domain}...]` at the end of an install or update; `restart-gate.sh report` prints one line per file, so it is visible which CLIs still owe a restart. A leftover old-format single file at `$JSC_HOME/restart-required` blocks every CLI and is deleted on the next `clear` — transitional only, and `hooks/restart-gate.sh` records when it can be dropped. Exempt skills stay callable — `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` — because the change report and the worklog still have to be finished after a deploy, and the first six reach that finish line only through the last three: the deploy asks for its mode, the report closes with a PR. The gate matches skill names, not call chains, so a nested call to anything off the list is blocked all the same. `hooks/restart-gate.sh` owns the list; guidelines.md「部署後重啟閘門」carries the same nine with a reason per entry. Escape hatch: `JSC_RESTART_GATE=off`.
|
||||
- `purge` reaches the user-level config only. Hooks that another plugin ships in its own `hooks.json` stay active, and uninstalling that plugin is the only way to clear them — say so when reporting, and treat their errors as third-party.
|
||||
- Backups land in `$JSC_HOME/backup/hooks/{cli}/{yyyyMMdd_HHmmss}/`, one directory per purge run, under the original file names. Hand that path to the user whenever a purge removed something.
|
||||
- `status claude` reads Claude Code's `installed_plugins.json` and checks the `installPath` that the CLI actually loads. It must not check only the `hooks.json` next to the `wire-cli.sh` that happens to be running, because a development checkout can otherwise hide a broken installed plugin.
|
||||
- `smoke` treats `sdlc-gate.sh check` exit 2 as healthy: that exit is the stage lock blocking a turn on purpose, not a runtime error. `comment-scope.sh` and `lang-guard.sh` exit 2 count as healthy for the same reason — the scan found something and warned about it. Their no-argument mode has no file name during smoke and exits 0 in silence; `sweep` depends on the worktree it runs in, so it answers 2 whenever that worktree happens to carry an offending comment, a simplified character or a mojibake sequence. None of these is a broken hook.
|
||||
- `comment-scope.sh` takes three modes: `prompt` (inject the rule summary at UserPromptSubmit), no argument at all (scan the file just written at PostToolUse, reading `file_path` from stdin JSON or `JSC_CHANGED_FILE`), and `sweep [dir]` (scan every file the git worktree changed, for the four CLIs with no post-tool hook). All scanning modes read only the lines a diff added, skip markdown and binary files, and turn off entirely with `JSC_COMMENT_SCOPE=off`. The rule text itself lives in one place only, `jsc-review`'s `references/comment-scope.md`; never restate the list anywhere in this repo.
|
||||
- `lang-guard.sh` takes the same three modes as `comment-scope.sh` and is wired at the same places, but it scans differently on purpose: it reads the whole file rather than comment lines only, and it does scan `.md` and plain-text files, because those are exactly the non-code output the rule targets. It flags three things — simplified characters (word list in `hooks/simplified.txt`, the single source of truth for this repo; a missing list skips that check in silence), mojibake (U+FFFD and double-encoding remnants), and non-UTF-8 encoding (decided by `iconv`; no `iconv` skips that check). It skips binaries, generated files, and the three files whose subject is those very characters (`simplified.txt`, `ste100-guard.sh`, `lang-guard.sh`). Turn it off with `JSC_LANG_GUARD=off`. The rule text lives only in `jsc-meta`'s `references/ste100.md`.
|
||||
|
||||
+123
-20
@@ -13,7 +13,7 @@
|
||||
# smoke 在接線之後跑,補上接線驗證看不到的那一半:接線只證明設定寫對位置,證不了 hook
|
||||
# 跑起來不出錯(缺 node、路徑錯、權限不足都只在真的執行時才現形)。
|
||||
# 有分支的判定另外驗結果,不只驗跑得完:sdlc-gate.sh 的工作包歸屬比對會自備一份暫時的
|
||||
# $JSC_HOME 狀態檔,把「查無歸屬」「自己的工作包」「別的工作包」與逃生門各跑一次,比對結束碼。
|
||||
# $JSC_HOME 狀態檔,把「查無歸屬」「自己的工作包」「別的工作包的阻擋與放行」與逃生門各跑一次,比對結束碼。
|
||||
# restart-gate.sh 的部署後重啟閘門同法:當前 CLI 沒有狀態檔、只有別支 CLI 有狀態檔、當前
|
||||
# CLI 那份存在、豁免技能、逃生門、取不到技能名各跑一次,再驗狀態檔本身在不在——清除只刪自己
|
||||
# 那一份、別支那一份留著、舊格式的單一狀態檔照樣擋得下來且清得掉。
|
||||
@@ -77,6 +77,11 @@ set -u
|
||||
HERE=$(cd "$(dirname "$0")" && pwd)
|
||||
ROOT=$(cd "$HERE/.." && pwd)
|
||||
HOOKS="$ROOT/hooks"
|
||||
JSC_HOME="${JSC_HOME:-$HOME/.jsc}"
|
||||
WIRE_ROOT="$ROOT"
|
||||
WIRE_HOOKS="$HOOKS"
|
||||
WIRE_TOOLS="$HERE"
|
||||
WIRE_PATH_NOTE=""
|
||||
# cli_bin(CLI 代號 → 實際執行檔)的唯一來源在 lib.sh,包裝啟動器也用同一份
|
||||
. "$HOOKS/lib.sh"
|
||||
|
||||
@@ -111,6 +116,61 @@ lang_guard_text() { sh "$HOOKS/lang-guard.sh" prompt 2>/dev/null | sed '/^exit /
|
||||
# 三段合在一個標記段落裡,purge 與重跑接線都是整段處理,不必各自再記一組標記。
|
||||
rules_text() { ste100_text; comment_scope_text; lang_guard_text; }
|
||||
|
||||
# 寫入 CLI 設定時用版本無關的穩定路徑。執行中的腳本仍從自己的 repo 讀規則,避免開發中
|
||||
# 的檔案和剛建立的連結互相踩到;只有寫進外部設定的命令改走 current 連結。
|
||||
ensure_stable_root() {
|
||||
_link="$JSC_HOME/current/jsc-hooks"
|
||||
_parent=$(dirname "$_link")
|
||||
if mkdir -p "$_parent" 2>/dev/null &&
|
||||
{ [ ! -e "$_link" ] || [ -L "$_link" ]; } &&
|
||||
ln -sfn "$ROOT" "$_link" 2>/dev/null &&
|
||||
[ -f "$_link/hooks/session-timer.sh" ] &&
|
||||
[ -f "$_link/tools/jsc-wrap.sh" ]; then
|
||||
WIRE_ROOT="$_link"
|
||||
WIRE_HOOKS="$_link/hooks"
|
||||
WIRE_TOOLS="$_link/tools"
|
||||
WIRE_PATH_NOTE="[jsc] 接線命令使用穩定路徑 $_link,已指向 $ROOT。"
|
||||
return 0
|
||||
fi
|
||||
WIRE_ROOT="$ROOT"
|
||||
WIRE_HOOKS="$HOOKS"
|
||||
WIRE_TOOLS="$HERE"
|
||||
WIRE_PATH_NOTE="[jsc] 無法建立穩定路徑 $_link,已明確退回目前路徑 $ROOT;下次 plugin 換版後請重新接線。"
|
||||
return 0
|
||||
}
|
||||
|
||||
verify_wire_script() {
|
||||
[ -f "$1" ] || fail "接線路徑不存在:$1"
|
||||
}
|
||||
|
||||
verify_wire_root() {
|
||||
verify_wire_script "$WIRE_HOOKS/session-timer.sh"
|
||||
verify_wire_script "$WIRE_HOOKS/comment-scope.sh"
|
||||
verify_wire_script "$WIRE_HOOKS/lang-guard.sh"
|
||||
verify_wire_script "$WIRE_TOOLS/jsc-wrap.sh"
|
||||
}
|
||||
|
||||
# 讀 Claude Code 真正載入的 jsc-hooks installPath。status claude 要看載入路徑,不看
|
||||
# 目前這支 wire-cli.sh 所在位置,否則用開發 repo 跑 status 會蓋掉壞掉的安裝快取。
|
||||
claude_loaded_root() {
|
||||
_reg="$HOME/.claude/plugins/installed_plugins.json"
|
||||
[ -f "$_reg" ] && [ -r "$_reg" ] || return 1
|
||||
_seg=$(tr -d '\n' < "$_reg" \
|
||||
| sed -n 's/.*"jsc-hooks@jsc"[[:space:]]*:[[:space:]]*\[\([^]]*\)\].*/\1/p')
|
||||
[ -n "$_seg" ] || return 1
|
||||
printf '%s' "$_seg" | tr ',' '\n' \
|
||||
| sed -n 's/.*"installPath"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -n1
|
||||
}
|
||||
|
||||
bad_runtime_path() {
|
||||
case "$1" in
|
||||
/root/plugins/hooks/*) return 0 ;;
|
||||
*/cache/*/jsc-hooks/[0-9]*/*) return 0 ;;
|
||||
esac
|
||||
[ -e "$1" ] || return 0
|
||||
return 1
|
||||
}
|
||||
|
||||
# 驗證:規則檔真的收到註解範圍那一段了嗎。比對字串取自腳本的第一行實際輸出,
|
||||
# 不是另外抄一句關鍵字——抄的關鍵字改腳本時不會跟著改,驗證就會永遠通過。
|
||||
# $1=檔案
|
||||
@@ -841,22 +901,51 @@ if [ "$action" = status ]; then
|
||||
st_item "$1" "$HOME/.bashrc" missing
|
||||
}
|
||||
|
||||
st_runtime_paths() {
|
||||
_item="$1"
|
||||
_file="$2"
|
||||
[ -f "$_file" ] || { st_item "$_item" "$_file" missing; return 0; }
|
||||
_scan="$_file"
|
||||
_tmp=""
|
||||
if [ -n "${3:-}" ]; then
|
||||
_tmp=$(mktemp) || { st_item "$_item" "$_file" missing; return 0; }
|
||||
awk -v bopen="$3" -v bshut="${4:-}" '
|
||||
$0==bopen { take=1; print; next }
|
||||
bshut != "" && $0==bshut { print; take=0; next }
|
||||
take { print }
|
||||
' "$_file" > "$_tmp"
|
||||
_scan="$_tmp"
|
||||
fi
|
||||
_bad=""
|
||||
_paths=$(grep -Eo "/[^\"' ;]+/(hooks|tools)/[^\"' ;]+\\.sh" "$_scan" 2>/dev/null || true)
|
||||
for _p in $_paths; do
|
||||
if bad_runtime_path "$_p"; then
|
||||
_bad="$_p"
|
||||
break
|
||||
fi
|
||||
done
|
||||
[ -n "$_tmp" ] && rm -f "$_tmp"
|
||||
[ -z "$_bad" ] && st_item "$_item" "$_file" present || st_item "$_item" "$_bad" missing
|
||||
}
|
||||
|
||||
case "$cli" in
|
||||
claude)
|
||||
if [ -f "$HOOKS/hooks.json" ]; then st_item hooks.json "$HOOKS/hooks.json" present
|
||||
else st_item hooks.json "$HOOKS/hooks.json" missing; fi
|
||||
claude_root=$(claude_loaded_root || true)
|
||||
claude_hooks="$claude_root/hooks/hooks.json"
|
||||
if [ -n "$claude_root" ] && [ -f "$claude_hooks" ]; then st_item hooks.json "$claude_hooks" present
|
||||
else st_item hooks.json "${claude_hooks:-$HOME/.claude/plugins/installed_plugins.json}" missing; fi
|
||||
# 八支 hook 全靠這一個檔宣告,只看檔案在不在會漏掉「檔在、某支沒接進去」。
|
||||
# 後來才加進來的 comment-scope.sh、lang-guard.sh 與 restart-gate.sh 是最可能漏的三支,
|
||||
# 所以各列一項。
|
||||
if [ -f "$HOOKS/hooks.json" ] && grep -qF 'comment-scope.sh' "$HOOKS/hooks.json" 2>/dev/null
|
||||
then st_item comment-scope "$HOOKS/hooks.json" present
|
||||
else st_item comment-scope "$HOOKS/hooks.json" missing; fi
|
||||
if [ -f "$HOOKS/hooks.json" ] && grep -qF 'lang-guard.sh' "$HOOKS/hooks.json" 2>/dev/null
|
||||
then st_item lang-guard "$HOOKS/hooks.json" present
|
||||
else st_item lang-guard "$HOOKS/hooks.json" missing; fi
|
||||
if [ -f "$HOOKS/hooks.json" ] && grep -qF 'restart-gate.sh' "$HOOKS/hooks.json" 2>/dev/null
|
||||
then st_item restart-gate "$HOOKS/hooks.json" present
|
||||
else st_item restart-gate "$HOOKS/hooks.json" missing; fi ;;
|
||||
if [ -f "$claude_hooks" ] && grep -qF 'comment-scope.sh' "$claude_hooks" 2>/dev/null
|
||||
then st_item comment-scope "$claude_hooks" present
|
||||
else st_item comment-scope "$claude_hooks" missing; fi
|
||||
if [ -f "$claude_hooks" ] && grep -qF 'lang-guard.sh' "$claude_hooks" 2>/dev/null
|
||||
then st_item lang-guard "$claude_hooks" present
|
||||
else st_item lang-guard "$claude_hooks" missing; fi
|
||||
if [ -f "$claude_hooks" ] && grep -qF 'restart-gate.sh' "$claude_hooks" 2>/dev/null
|
||||
then st_item restart-gate "$claude_hooks" present
|
||||
else st_item restart-gate "$claude_hooks" missing; fi ;;
|
||||
|
||||
codex)
|
||||
config="${CODEX_HOME:-$HOME/.codex}/config.toml"
|
||||
@@ -885,6 +974,8 @@ if [ "$action" = status ]; then
|
||||
st_block ste100 "${CODEX_HOME:-$HOME/.codex}/AGENTS.md" "<!-- jsc-hooks -->"
|
||||
st_comment_scope comment-scope "${CODEX_HOME:-$HOME/.codex}/AGENTS.md"
|
||||
st_lang_guard lang-guard "${CODEX_HOME:-$HOME/.codex}/AGENTS.md"
|
||||
st_runtime_paths runtime-paths "$config" "# jsc-hooks" "# /jsc-hooks"
|
||||
st_runtime_paths alias-paths "$HOME/.bashrc" "# jsc-hooks:codex" "# /jsc-hooks:codex"
|
||||
st_degrade="STE100 降級為 prompt 檔,SDLC 模型鎖降級為技能步驟檢查,無 pre-tool hook 可接版本前置檢查與部署後重啟閘門,註解範圍與繁中編碼改為每輪結束掃整個工作區,不是逐檔即時" ;;
|
||||
|
||||
copilot)
|
||||
@@ -892,6 +983,7 @@ if [ "$action" = status ]; then
|
||||
st_block ste100 "${JSC_COPILOT_INSTRUCTIONS:-$HOME/.config/copilot/copilot-instructions.md}" "<!-- jsc-hooks -->"
|
||||
st_comment_scope comment-scope "${JSC_COPILOT_INSTRUCTIONS:-$HOME/.config/copilot/copilot-instructions.md}"
|
||||
st_lang_guard lang-guard "${JSC_COPILOT_INSTRUCTIONS:-$HOME/.config/copilot/copilot-instructions.md}"
|
||||
st_runtime_paths alias-paths "$HOME/.bashrc" "# jsc-hooks:copilot" "# /jsc-hooks:copilot"
|
||||
st_degrade="STE100 降級為 prompt 檔,SDLC 模型鎖降級為技能步驟檢查,無 pre-tool hook 可接版本前置檢查與部署後重啟閘門,註解範圍與繁中編碼只在工作階段結束時掃一次整個工作區" ;;
|
||||
|
||||
antigravity)
|
||||
@@ -899,6 +991,7 @@ if [ "$action" = status ]; then
|
||||
st_block ste100 "${JSC_ANTIGRAVITY_RULES:-$HOME/.antigravity/AGENTS.md}" "<!-- jsc-hooks -->"
|
||||
st_comment_scope comment-scope "${JSC_ANTIGRAVITY_RULES:-$HOME/.antigravity/AGENTS.md}"
|
||||
st_lang_guard lang-guard "${JSC_ANTIGRAVITY_RULES:-$HOME/.antigravity/AGENTS.md}"
|
||||
st_runtime_paths alias-paths "$HOME/.bashrc" "# jsc-hooks:antigravity" "# /jsc-hooks:antigravity"
|
||||
st_degrade="STE100 降級為 prompt 檔,SDLC 模型鎖降級為技能步驟檢查,無 pre-tool hook 可接版本前置檢查與部署後重啟閘門,註解範圍與繁中編碼只在工作階段結束時掃一次整個工作區" ;;
|
||||
|
||||
kiro)
|
||||
@@ -926,6 +1019,8 @@ if [ "$action" = status ]; then
|
||||
grep -qF 'lang-guard.sh\" sweep' ./.kiro/hooks/jsc-hooks.json 2>/dev/null
|
||||
then st_item lang-guard-sweep ./.kiro/hooks/jsc-hooks.json present
|
||||
else st_item lang-guard-sweep ./.kiro/hooks/jsc-hooks.json missing; fi
|
||||
st_runtime_paths session-runtime-paths ./.kiro/hooks/jsc-hooks-session-start.json
|
||||
st_runtime_paths hook-runtime-paths ./.kiro/hooks/jsc-hooks.json
|
||||
st_degrade="SDLC 模型鎖降級為技能步驟檢查,無 pre-tool hook 可接版本前置檢查與部署後重啟閘門,註解範圍與繁中編碼改為每輪提示送出時掃整個工作區,不是逐檔即時" ;;
|
||||
esac
|
||||
|
||||
@@ -941,6 +1036,9 @@ if [ "$action" = status ]; then
|
||||
cat "$st_items"; rm -f "$st_items"; exit 0
|
||||
fi
|
||||
|
||||
ensure_stable_root
|
||||
verify_wire_root
|
||||
|
||||
case "$cli" in
|
||||
claude)
|
||||
bin=$(cli_bin claude)
|
||||
@@ -953,6 +1051,7 @@ case "$cli" in
|
||||
grep -qF 'restart-gate.sh' "$HOOKS/hooks.json" 2>/dev/null \
|
||||
|| fail "$HOOKS/hooks.json 沒有接上 restart-gate.sh,部署後重啟閘門不會生效"
|
||||
printf 'status=wired reason=%s\n' "hooks.json 自動接線"
|
||||
echo "$WIRE_PATH_NOTE"
|
||||
echo "[jsc] claude:由 hooks/hooks.json 自動接線全部八支 hook,無需寫入設定。"
|
||||
echo "[jsc] claude:只有 claude 有 pre-tool hook,版本前置檢查與部署後重啟閘門只在這裡擋得下技能呼叫;其他四個 CLI 兩道閘門都接不上。"
|
||||
echo "[jsc] claude:只有 claude 有 post-tool hook,comment-scope.sh 與 lang-guard.sh 的逐檔即時掃描只在這裡接得上;其他四個 CLI 改用 sweep 掃整個工作區,時機晚一輪或晚到工作階段結束。"
|
||||
@@ -972,11 +1071,11 @@ case "$cli" in
|
||||
# notify 最後再掛 comment-scope.sh sweep:codex 沒有 post-tool hook,拿不到「剛剛寫了
|
||||
# 哪個檔」,只能改掃整個 git 工作區的 diff。每輪結束掃一次,時機比 claude 晚,那一輪
|
||||
# 寫過的檔一個都不會漏。
|
||||
timer="sh '$HOOKS/session-timer.sh'"
|
||||
scope="sh '$HOOKS/comment-scope.sh'"
|
||||
lang="sh '$HOOKS/lang-guard.sh'"
|
||||
timer="sh '$WIRE_HOOKS/session-timer.sh'"
|
||||
scope="sh '$WIRE_HOOKS/comment-scope.sh'"
|
||||
lang="sh '$WIRE_HOOKS/lang-guard.sh'"
|
||||
notify_line="notify = [\"env\", \"JSC_CLI=codex\", \"sh\", \"-c\", \"$timer start </dev/null; $timer mark </dev/null; $scope sweep </dev/null; $lang sweep </dev/null\"]"
|
||||
alias_line="alias $bin='sh \"$HERE/jsc-wrap.sh\" codex'"
|
||||
alias_line="alias $bin='sh \"$WIRE_TOOLS/jsc-wrap.sh\" codex'"
|
||||
replace_block_toml "$config" "# jsc-hooks" "# /jsc-hooks" "$notify_line" \
|
||||
|| fail "無法寫入 $config"
|
||||
has_block "$config" "# jsc-hooks" || fail "$config 寫入後讀不到 jsc-hooks 標記段落"
|
||||
@@ -993,6 +1092,7 @@ case "$cli" in
|
||||
has_comment_scope "$agents" || fail "$agents 寫入後讀不到註解範圍規則"
|
||||
has_lang_guard "$agents" || fail "$agents 寫入後讀不到繁中與編碼規則"
|
||||
printf 'status=degraded reason=%s\n' "STE100 降級為 prompt 檔,SDLC 模型鎖降級為技能步驟檢查,無 pre-tool hook 可接版本前置檢查與部署後重啟閘門,註解範圍與繁中編碼改為每輪結束掃整個工作區,不是逐檔即時"
|
||||
echo "$WIRE_PATH_NOTE"
|
||||
echo "[jsc] codex:已在 shell rc 加上 $bin 別名,轉呼叫 tools/jsc-wrap.sh codex,啟動當下開始計時。"
|
||||
echo "[jsc] codex:別名要開新的 shell 或重新 source rc 檔才生效。"
|
||||
echo "[jsc] codex:已設定 $config 的 notify(根層鍵,已驗證),每輪補 session-timer.sh start 再 mark,最後跑 comment-scope.sh sweep 與 lang-guard.sh sweep。"
|
||||
@@ -1007,7 +1107,7 @@ case "$cli" in
|
||||
bin=$(cli_bin copilot)
|
||||
command -v "$bin" >/dev/null 2>&1 || skip "未偵測到 copilot 執行檔"
|
||||
instr="${JSC_COPILOT_INSTRUCTIONS:-$HOME/.config/copilot/copilot-instructions.md}"
|
||||
alias_line="alias $bin='sh \"$HERE/jsc-wrap.sh\" copilot'"
|
||||
alias_line="alias $bin='sh \"$WIRE_TOOLS/jsc-wrap.sh\" copilot'"
|
||||
write_alias_rc "jsc-hooks:copilot" "$alias_line" || fail "無法把 $bin 別名寫進 shell rc 檔"
|
||||
replace_block "$instr" "<!-- jsc-hooks -->" "<!-- /jsc-hooks -->" "$(rules_text)" \
|
||||
|| fail "無法寫入 $instr"
|
||||
@@ -1015,6 +1115,7 @@ case "$cli" in
|
||||
has_comment_scope "$instr" || fail "$instr 寫入後讀不到註解範圍規則"
|
||||
has_lang_guard "$instr" || fail "$instr 寫入後讀不到繁中與編碼規則"
|
||||
printf 'status=degraded reason=%s\n' "STE100 降級為 prompt 檔,SDLC 模型鎖降級為技能步驟檢查,無 pre-tool hook 可接版本前置檢查與部署後重啟閘門,註解範圍與繁中編碼只在工作階段結束時掃一次整個工作區"
|
||||
echo "$WIRE_PATH_NOTE"
|
||||
echo "[jsc] copilot:已在 shell rc 加上 $bin 別名,轉呼叫 tools/jsc-wrap.sh copilot。"
|
||||
echo "[jsc] copilot:已在 $instr 寫入 STE100、註解範圍與繁中編碼規則段落(prompt 降級)。"
|
||||
echo "[jsc] copilot:別名要開新的 shell 或重新 source rc 檔才生效。"
|
||||
@@ -1028,7 +1129,7 @@ case "$cli" in
|
||||
bin=$(cli_bin antigravity)
|
||||
command -v "$bin" >/dev/null 2>&1 || skip "未偵測到 antigravity(agy)執行檔"
|
||||
rules="${JSC_ANTIGRAVITY_RULES:-$HOME/.antigravity/AGENTS.md}"
|
||||
alias_line="alias $bin='sh \"$HERE/jsc-wrap.sh\" antigravity'"
|
||||
alias_line="alias $bin='sh \"$WIRE_TOOLS/jsc-wrap.sh\" antigravity'"
|
||||
write_alias_rc "jsc-hooks:antigravity" "$alias_line" || fail "無法把 $bin 別名寫進 shell rc 檔"
|
||||
replace_block "$rules" "<!-- jsc-hooks -->" "<!-- /jsc-hooks -->" "$(rules_text)" \
|
||||
|| fail "無法寫入 $rules"
|
||||
@@ -1036,6 +1137,7 @@ case "$cli" in
|
||||
has_comment_scope "$rules" || fail "$rules 寫入後讀不到註解範圍規則"
|
||||
has_lang_guard "$rules" || fail "$rules 寫入後讀不到繁中與編碼規則"
|
||||
printf 'status=degraded reason=%s\n' "STE100 降級為 prompt 檔,SDLC 模型鎖降級為技能步驟檢查,無 pre-tool hook 可接版本前置檢查與部署後重啟閘門,註解範圍與繁中編碼只在工作階段結束時掃一次整個工作區"
|
||||
echo "$WIRE_PATH_NOTE"
|
||||
echo "[jsc] antigravity:已在 shell rc 加上 $bin 別名,轉呼叫 tools/jsc-wrap.sh antigravity。"
|
||||
echo "[jsc] antigravity:已在 $rules 寫入 STE100、註解範圍與繁中編碼規則段落(prompt 降級)。"
|
||||
echo "[jsc] antigravity:別名要開新的 shell 或重新 source rc 檔才生效。"
|
||||
@@ -1060,7 +1162,7 @@ case "$cli" in
|
||||
"description": "jsc session timer start (auto-generated by jsc-hooks:hooks-install, do not edit by hand)",
|
||||
"on": ["sessionStart"],
|
||||
"env": { "JSC_CLI": "kiro" },
|
||||
"run": "sh \\"$HOOKS/session-timer.sh\\" restart </dev/null"
|
||||
"run": "sh \\"$WIRE_HOOKS/session-timer.sh\\" restart </dev/null"
|
||||
}
|
||||
EOF
|
||||
# userPromptSubmit 那一輪的 run 最後再掛 comment-scope.sh sweep 與 lang-guard.sh sweep:
|
||||
@@ -1072,7 +1174,7 @@ EOF
|
||||
"description": "jsc session timer + STE100 guard + comment scope + language guard bridge (auto-generated by jsc-hooks:hooks-install, do not edit by hand)",
|
||||
"on": ["sessionEnd", "userPromptSubmit"],
|
||||
"env": { "JSC_CLI": "kiro" },
|
||||
"run": "sh \\"$HOOKS/session-timer.sh\\" mark </dev/null; sh \\"$HOOKS/ste100-guard.sh\\" </dev/null; sh \\"$HOOKS/comment-scope.sh\\" prompt </dev/null; sh \\"$HOOKS/comment-scope.sh\\" sweep </dev/null; sh \\"$HOOKS/lang-guard.sh\\" prompt </dev/null; sh \\"$HOOKS/lang-guard.sh\\" sweep </dev/null"
|
||||
"run": "sh \\"$WIRE_HOOKS/session-timer.sh\\" mark </dev/null; sh \\"$WIRE_HOOKS/ste100-guard.sh\\" </dev/null; sh \\"$WIRE_HOOKS/comment-scope.sh\\" prompt </dev/null; sh \\"$WIRE_HOOKS/comment-scope.sh\\" sweep </dev/null; sh \\"$WIRE_HOOKS/lang-guard.sh\\" prompt </dev/null; sh \\"$WIRE_HOOKS/lang-guard.sh\\" sweep </dev/null"
|
||||
}
|
||||
EOF
|
||||
for f in "$startfile" "$hookfile"; do
|
||||
@@ -1095,6 +1197,7 @@ EOF
|
||||
grep -qF 'lang-guard.sh\" sweep' "$hookfile" 2>/dev/null \
|
||||
|| fail "$hookfile 的 run 沒有接到 lang-guard.sh sweep,kiro 每輪不會掃簡體字與亂碼"
|
||||
printf 'status=degraded reason=%s\n' "SDLC 模型鎖降級為技能步驟檢查,無 pre-tool hook 可接版本前置檢查與部署後重啟閘門,註解範圍與繁中編碼改為每輪提示送出時掃整個工作區,不是逐檔即時"
|
||||
echo "$WIRE_PATH_NOTE"
|
||||
echo "[jsc] kiro:已建立 $startfile(sessionStart 開始計時)與 $hookfile(JSC_CLI=kiro),兩份都已驗證。"
|
||||
echo "[jsc] kiro:SDLC 模型鎖降級為技能步驟檢查,鎖檔仍由 sdlc-gate.sh lock 寫入。"
|
||||
echo "[jsc] kiro:版本前置檢查接不上(kiro 沒有 pre-tool hook),改由 /jsc-cli:deploy 定期更新。"
|
||||
|
||||
Reference in New Issue
Block a user