From d6f1e0e7ba6da657d37b870640c46947078c95ba Mon Sep 17 00:00:00 2001 From: Jeffery Date: Fri, 4 Sep 2026 18:04:51 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E6=8E=A5=E7=B7=9A):=20status=20=E5=8A=A0?= =?UTF-8?q?=20--verdict=EF=BC=8C=E6=8A=8A=E7=8B=80=E6=85=8B=E8=88=87?= =?UTF-8?q?=E6=88=90=E6=95=97=E5=85=A9=E7=A8=AE=E8=AA=9E=E6=84=8F=E5=88=86?= =?UTF-8?q?=E9=96=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit status 的結束碼帶的是狀態:0 是接好、1 是接好但這支 CLI 做不到、5 是有東西 沒接。那是給人看的三分法,本身沒有錯。 問題出在被當成檢查用。助理的內建檢查項照結束碼判成敗,非零就是那一筆失敗、 失敗次數加一。於是有先天限制的那一支 CLI 每一輪都讓那一筆失敗一次,一天 96 次,而沒有人修得動——那支 CLI 擋不下技能叫用是它的架構限制,不是接線缺漏, 16 個接線項目全部就位。 那個計數存在的理由是指出「有一筆壞掉的項目每輪重試而沒人知道」。被一個修不動 的數字填滿,就等於用假的壞掉把真的壞掉蓋掉。 修在這一邊而不是修在讀的那一邊:狀態與成敗是兩種語意,混在同一個通道上才是 根因。這個旗標把成敗那一種單獨拉出來,status 保持原樣給人看。 --verdict 之下輸出一字不變——degraded 那一行照印,人看得到——只有結束碼換一套 語意:該接的都接了就回 0,先天限制不算;真的缺項目照樣回 5。 只有 status 收這個旗標,別的子命令帶了回 2:另外三個子命令的結束碼本來就是 成敗語意,多一個旗標只會讓人以為它們也有兩套。 實測:五支 CLI 兩種模式各跑一次,只有帶先天限制那一支從 1 變 0;輸出逐字 相同;暫時拿掉一個接線項目之後 --verdict 回 5,還原後回 0;旗標的三條錯誤 路徑都回 2。 三份 manifest 版號 0.4.4 升到 0.4.5。 Co-Authored-By: Claude Opus 5 --- .claude-plugin/plugin.json | 2 +- .codex-plugin/plugin.json | 2 +- plugin.json | 2 +- tools/wire-cli.sh | 36 ++++++++++++++++++++++++++++++++++-- 4 files changed, 37 insertions(+), 5 deletions(-) diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index 3569378..787b4e5 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "jsc-hooks", - "version": "0.4.4", + "version": "0.4.5", "description": "跨 CLI hooks:STE100 語言強制、工時計時、技能用量記錄、SDLC 模型鎖、版本前置檢查、註解範圍守門、繁中編碼守門、部署後強制重啟、寫入與提交閘門", "skills": "./skills", "author": { diff --git a/.codex-plugin/plugin.json b/.codex-plugin/plugin.json index 5b8f35c..77fd845 100644 --- a/.codex-plugin/plugin.json +++ b/.codex-plugin/plugin.json @@ -1,7 +1,7 @@ { "hooks": "./hooks/codex-hooks.json", "name": "jsc-hooks", - "version": "0.4.4", + "version": "0.4.5", "description": "跨 CLI hooks:STE100 語言強制、工時計時、技能用量記錄、SDLC 模型鎖、版本前置檢查、註解範圍守門、繁中編碼守門、部署後強制重啟、寫入與提交閘門", "skills": "./skills", "jsc": { diff --git a/plugin.json b/plugin.json index ab17314..989a183 100644 --- a/plugin.json +++ b/plugin.json @@ -1,6 +1,6 @@ { "name": "jsc-hooks", - "version": "0.4.4", + "version": "0.4.5", "description": "跨 CLI hooks:STE100 語言強制、工時計時、技能用量記錄、SDLC 模型鎖、版本前置檢查、註解範圍守門、繁中編碼守門、部署後強制重啟、寫入與提交閘門", "skills": "./skills/", "jsc": { diff --git a/tools/wire-cli.sh b/tools/wire-cli.sh index 46f7b70..f649fbd 100755 --- a/tools/wire-cli.sh +++ b/tools/wire-cli.sh @@ -4,7 +4,9 @@ # wire-cli.sh {claude|codex|copilot|antigravity|kiro} 接線 # wire-cli.sh purge {claude|codex|copilot|antigravity|kiro} 備份後移除該 CLI 的所有 hook # wire-cli.sh smoke {claude|codex|copilot|antigravity|kiro} 跑一輪九支 hook,驗執行期 -# wire-cli.sh status {claude|codex|copilot|antigravity|kiro} 唯讀盤點接線現況,不寫檔也不執行 hook +# wire-cli.sh status {claude|codex|copilot|antigravity|kiro} [--verdict] +# 唯讀盤點接線現況,不寫檔也不執行 hook。 +# --verdict 只換結束碼語意,輸出一字不變 # # JSC_READONLY=1 時只准 status 與 smoke,purge 與接線一律拒絕並回 exit 6。體檢類技能全程帶著 # 這個變數跑,「子命令打錯一個字就重新接線或刪檔」的風險就由程式擋掉,不靠呼叫端自我約束。 @@ -128,6 +130,9 @@ # 結束碼(purge): 0=purged 2=用法錯誤 3=skipped 4=failed # 結束碼(smoke): 0=ok 2=用法錯誤 4=failed(含結果行數與預期不符) # 結束碼(status): 0=wired 1=degraded 2=用法錯誤 3=skipped 5=unwired(該接的段落缺了至少一項) +# 結束碼(status --verdict): 0=該接的都接了(含 degraded——先天限制不算缺漏) +# 2=用法錯誤 3=skipped 5=unwired +# 給拿結束碼判成敗的呼叫端用,例如助理的內建檢查項。理由見下方 --verdict 那一段。 # 結束碼(唯讀模式): 6=readonly(JSC_READONLY=1 之下拒絕 purge 與接線),status 與 smoke 不受影響 # status 之外的動作都會寫檔,體檢類技能(/jsc-cli:doctor)只能呼叫 status。判讀邏輯跟接線 # 共用同一組檔案位置與標記字串,分兩份實作就會各自漂移,體檢說沒接、實際上接著。 @@ -169,6 +174,30 @@ case "$cli" in claude|codex|copilot|antigravity|kiro) ;; *) usage ;; esac +shift 2>/dev/null || true + +# --verdict:輸出一字不變,只有結束碼換一套語意——該接的都接了就回 0,先天限制不算。 +# +# 為什麼要有這個旗標。status 的結束碼帶的是狀態:0 是接好、1 是接好但這支 CLI 做不到、 +# 5 是有東西沒接。那是給人看的三分法,也是對的。問題出在被當成檢查用:助理的內建檢查項 +# 照結束碼判成敗,非零就是那一筆失敗、失敗次數加一。 +# 於是有先天限制的那一支 CLI 每一輪都讓那一筆失敗一次,一天 96 次,而沒有人修得動—— +# 那支 CLI 擋不下技能叫用是它的架構,不是接線缺漏,16 個接線項目全部就位。 +# 那個計數存在的理由是指出「有一筆壞掉的項目每輪重試而沒人知道」,被這樣填滿就等於用 +# 一個修不動的數字把真的壞掉蓋掉。 +# 修在這裡而不是修在讀的那一邊:狀態與成敗是兩種語意,混在同一個通道上才是根因。這個 +# 旗標把成敗那一種單獨拉出來,`status` 保持原樣給人看。 +VERDICT_ONLY=0 +while [ "$#" -gt 0 ]; do + case "$1" in + --verdict) VERDICT_ONLY=1; shift ;; + *) usage ;; + esac +done +case "$action:$VERDICT_ONLY" in + status:1|*:0) ;; + *) printf '[jsc] --verdict 只有 status 用得到,%s 不收這個旗標。\n' "$action" >&2; exit 2 ;; +esac # 唯讀契約在程式層把關,不靠呼叫端記得只打 status。子命令解析完就判:預設動作是接線, # 所以少打一個子命令就會直接改環境,這個判定要擋的正是那一次手滑。 @@ -2519,7 +2548,10 @@ if [ "$action" = status ]; then fi if [ -n "$st_degrade" ]; then printf 'status=degraded reason=%s\n' "$st_degrade" - cat "$st_items"; rm -f "$st_items"; exit 1 + cat "$st_items"; rm -f "$st_items" + # --verdict 之下先天限制不算失敗:輸出照印,讓人看得到,但結束碼說「該接的都接了」。 + [ "$VERDICT_ONLY" -eq 1 ] && exit 0 + exit 1 fi printf 'status=wired reason=%s\n' "$st_wired" cat "$st_items"; rm -f "$st_items"; exit 0 -- 2.53.0