From 76b3f2dcb61f01c268f82d758a7da1cb809bbe16 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Mon, 31 Aug 2026 13:35:40 +0800 Subject: [PATCH 1/5] =?UTF-8?q?docs(references):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E4=BA=94=E6=94=AF=E6=8A=80=E8=83=BD=E7=9A=84=E8=A1=8C=E7=82=BA?= =?UTF-8?q?=E6=B8=85=E5=96=AE=E4=BD=9C=E7=82=BA=E9=A9=97=E8=AD=89=E5=9F=BA?= =?UTF-8?q?=E6=BA=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit What:新增 references/behaviors.md。這一頁列出 delegate、deploy、doctor、models、setup 五支技能的行為。每支技能記錄觸發時機、關鍵步驟、外部呼叫、完成條件、可驗證跡象五個項目。 Why:技能驗證以前沒有共同基準。驗證的人只能自己讀 SKILL.md 反推該有哪些行為,兩個人推出來的結果不會一樣。有了這一頁,驗證就比對同一份基準。 How:一支技能一個章節,章節內用一張兩欄表格寫滿五個項目。外部呼叫欄位寫出腳本路徑與子命令,可驗證跡象欄位寫出實際會被改動的檔案或目錄。頁首寫明規則:技能異動時,要在同一個 PR 內一起更新這一頁。 Who:技能驗證基準。 --- references/behaviors.md | 53 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 references/behaviors.md diff --git a/references/behaviors.md b/references/behaviors.md new file mode 100644 index 0000000..a8f18c9 --- /dev/null +++ b/references/behaviors.md @@ -0,0 +1,53 @@ +# jsc-cli 技能行為清單 + +本頁記錄 jsc-cli 每支技能的行為基準,供技能驗證比對。技能異動時,在同一個 PR 內一起更新這一頁。 + +## delegate + +| 項目 | 內容 | +| --- | --- | +| 觸發時機 | 一件邊界清楚的工作要交給另一支已安裝的 AI agent CLI 執行時用。盤點模型(models)、部署技能組(deploy)、必須留在目前 agent 手上的工作都不用;給不出通過或失敗判準的目標也不用 | +| 關鍵步驟 | 寫下一句目標與可判定通過或失敗的驗收條件、同時起跑 detect-clis.sh 與 list-models.sh 取得 CLI 清單與模型清單、先選定目標 CLI 再用 model-tags.sh 的 gate 或 model 驗證模型能力標籤、組出帶目標、驗收條件、目標 CLI、模型代號、最小脈絡、寫入範圍與 TSV 輸出合約的提示、開一個 sub agent 執行、查驗回傳的結束碼與 result、summary、criterion、wrote 各行、把成功、失敗、需要使用者補充分三段回報 | +| 外部呼叫 | jsc-cli/tools/detect-clis.sh、jsc-cli/tools/list-models.sh、jsc-cli/tools/model-tags.sh(gate 與 model 兩個子命令)、一個代跑工作的 sub agent | +| 完成條件 | 目標 CLI 與模型各只有一個,且模型通過能力要求;sub agent 回傳的每一條驗收條件都有判定;每個 wrote 路徑都落在寫入範圍內;報告分三段列出結果。中途停下時,停下的原因要寫在報告裡 | +| 可驗證跡象 | 技能自己不寫檔。可檢查的是 sub agent 依寫入範圍實際改動的檔案,逐條列在回傳的 wrote 行上,照那些路徑去看即可比對;寫入範圍為空的唯讀委派沒有寫入跡象,只有回報內容 | + +## deploy + +| 項目 | 內容 | +| --- | --- | +| 觸發時機 | 整組 jsc 技能要在這台機器的每一支已安裝 CLI 上安裝、更新或解除安裝時用。只處理單一技能不用;只想知道版本落後與否,看 doctor 就夠 | +| 關鍵步驟 | 同時取得三項事實(detect-clis.sh 的 CLI 清單、version-guard.sh 的 report 版本表與 recommend 結論、marketplace.json 的 domain 清單)、把版本表原樣秀出並定出建議、依 jsc-ask 決策樹問出模式(呼叫端已帶模式就沿用並標明來源)、每支 CLI 各開一個 sub agent 同時跑 tools/deploy.sh {mode} {cli} {domain}...、安裝或更新後把 CLI 清單交給 jsc-hooks:hooks-install、整台機器跑一次 tools/write-guides.sh、彙整每支 CLI 的結果並要求重新啟動工作階段 | +| 外部呼叫 | jsc-cli/tools/detect-clis.sh、jsc-cli/tools/deploy.sh、jsc-cli/tools/write-guides.sh、jsc-cli/tools/check-requires.sh(由 deploy.sh 在每個 domain 更新前轉呼叫)、jsc-hooks/hooks/version-guard.sh 的 report 與 recommend、jsc-hooks/hooks/restart-gate.sh require(由 deploy.sh 收尾轉呼叫)、jsc-gitea/tools/gitea.sh 讀 plugins/meta 的 marketplace.json、jsc-ask:ask、jsc-hooks:hooks-install | +| 完成條件 | 每一支偵測到的 CLI 都回報結束碼與 result 行,每個 skip、warn、compat 行都照實列出;安裝或更新還要拿到 hooks-install 對每支 CLI 的總結,兩份指引都印出 wrote,收尾印出重啟指示與兩份指引路徑 | +| 可驗證跡象 | 各 CLI 的外掛目錄多出或少掉 jsc-{domain}:claude 與 codex 在各自的 plugin 快取、copilot 在 installed-plugins、antigravity 與 kiro 走 $JSC_LOCAL_PLUGINS 的本地 clone 與 $JSC_KIRO_SKILLS 的複製。$JSC_HOME/restart-required.d/{cli} 出現這次的重啟狀態檔;$JSC_HOME/update-guide.md 與 $JSC_HOME/remove-guide.md 被重寫;各 CLI 的 hook 設定檔由 hooks-install 改寫 | + +## doctor + +| 項目 | 內容 | +| --- | --- | +| 觸發時機 | 裝完或更新完技能組、技能因設定或接線問題失敗、機器要交接前用。要動手修不用這支,那是 jsc-cli:setup | +| 關鍵步驟 | 同時開四個 sub agent 收版本、hook 接線、設定與未登錄變數,每個 sub agent 回傳原始輸出行、把四份輸出各存成檔、依 templates/check-page.md 印出五個區塊並寫明掃描的專案目錄、用 tools/build-todo.sh 把三份輸出合成待修項目表、透過 jsc-gitea:wiki 整頁覆寫 CHECK_{HASH} 並把本機那一列 upsert 進 CHECK_CONTENTS、報出四項計數並視情況建議 /jsc-cli:setup | +| 外部呼叫 | jsc-hooks/hooks/version-guard.sh report、jsc-cli/tools/detect-clis.sh、jsc-hooks/tools/wire-cli.sh status(一律帶 JSC_READONLY=1)、jsc-cli/tools/scan-config.sh 的 scan all 與 orphans、jsc-cli/tools/build-todo.sh、jsc-gitea/tools/gitea.sh 的 wiki-repo 與 hash-id、jsc-gitea:wiki | +| 完成條件 | 四項檢查各有結論,或明寫無法驗證與原因;五個區塊與待修項目表都在畫面上;wiki 頁寫成功,或寫入略過連同結束碼一起回報;必要項缺漏、設定錯誤、CLI 未接線、domain 落後四項計數都講出來 | +| 可驗證跡象 | wiki 的 CHECK_{HASH} 頁(雜湊來源是 {主機名}/{登入帳號})被整頁覆寫成這次的結果,CHECK_CONTENTS 多出本機那一列,或該列的缺漏數與最後體檢時間被更新。機器本身的設定、接線與版本都不動:這支技能不寫任何設定 | + +## models + +| 項目 | 內容 | +| --- | --- | +| 觸發時機 | 要盤點各 CLI 可用模型、確認模型合不合 SDLC 階段的能力要求、或檢視階段閘門設定時用。切換模型不用,改 .jsc/models 與 models.conf 也不用 | +| 關鍵步驟 | 同時起跑三個收集器(detect-clis.sh、list-models.sh 以 sub agent 執行、model-config.sh list)、對讀不到設定的 CLI 補上標「預設推定」的預設模型、依 references/model-tags.md 為每個模型掛能力標籤、印出 CLI、模型、標籤、使用中四欄表、跑 tools/model-tags.sh sync 把標籤表寫進 $JSC_HOME/model-tags.tsv、附上 SDLC 階段需求表與階段偏好模型表 | +| 外部呼叫 | jsc-cli/tools/detect-clis.sh、jsc-cli/tools/list-models.sh、jsc-cli/tools/model-config.sh list、jsc-cli/tools/model-tags.sh sync、references/model-tags.md;標籤表上查不到的模型改用 jsc-ask:ask 發問 | +| 完成條件 | 每支偵測到的 CLI 都有模型清單或一組預設推定;每個模型都掛到標籤,或已排進發問;sync 印出寫入路徑,失敗則連同結束碼回報;兩張階段表都列滿 plan、analyze、implement、maintain 四個階段 | +| 可驗證跡象 | $JSC_HOME/model-tags.tsv 被重寫,內容就是這次掛好的標籤表;jsc-hooks/hooks/sdlc-gate.sh 讀的正是這份檔,檔案不在,SDLC 階段閘門就判不出來。各 CLI 的模型設定檔不動 | + +## setup + +| 項目 | 內容 | +| --- | --- | +| 觸發時機 | doctor 報出待修項目、要實際動手修這台機器時用。只想做唯讀體檢不用這支,那是 jsc-cli:doctor | +| 關鍵步驟 | 從 wiki CHECK_{HASH} 讀待修項目表,讀不到就以 sub agent 同時重跑設定、接線、版本三個檢查器再用 build-todo.sh 合併、依 jsc-ask 決策樹逐項循序確認、依 fix 欄分流(auto 與 ask 走 apply-config.sh 的 set 或 mkdir、manual 印出步驟交給操作者、domain 落後轉呼叫 jsc-cli:deploy 並附上手上的版本報告、hook 未接線轉呼叫 jsc-hooks:hooks-install、缺 model-tags.tsv 轉呼叫 jsc-cli:models)、同時重驗每個已套用項目、重寫 CHECK_{HASH} 並 upsert CHECK_CONTENTS、報出已修、略過、轉呼叫、未修好四項計數 | +| 外部呼叫 | jsc-cli/tools/scan-config.sh、jsc-cli/tools/detect-clis.sh、jsc-hooks/tools/wire-cli.sh status(一律帶 JSC_READONLY=1)、jsc-hooks/hooks/version-guard.sh report、jsc-cli/tools/build-todo.sh、jsc-cli/tools/apply-config.sh 的 set、mkdir 與 show、jsc-gitea/tools/gitea.sh 的 wiki-repo 與 hash-id、jsc-ask:ask、jsc-gitea:wiki、jsc-cli:deploy、jsc-hooks:hooks-install、jsc-cli:models | +| 完成條件 | 每一項都有已修、略過、轉呼叫或未修好的結果;每個已套用項目都由自己那一列指定的檢查器重驗過;每個寫進去的環境變數都附上 export 那一行;頁面寫好或略過都有回報;四項計數都講出來 | +| 可驗證跡象 | 各 shell rc 檔的 `# jsc-config` 區塊被改寫,改寫前的備份落在 $JSC_HOME/backup/config/{時間戳}/;auto 路線建立的目錄實際出現在磁碟上;wiki CHECK_{HASH} 被改寫成修完後的狀態,CHECK_CONTENTS 的本機列跟著更新;轉呼叫出去的項目留下各自技能的跡象,也就是 deploy 的重啟狀態檔、hooks-install 改寫的接線設定、models 產生的 model-tags.tsv | From 4ed0bf11a234122dda0c12aebc4054c308c8e044 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Mon, 31 Aug 2026 13:35:41 +0800 Subject: [PATCH 2/5] =?UTF-8?q?fix(check-requires):=20=E5=88=86=E9=96=8B?= =?UTF-8?q?=E7=9B=B8=E4=BE=9D=E4=B8=8D=E7=AC=A6=E8=88=87=E5=88=A4=E4=B8=8D?= =?UTF-8?q?=E5=87=BA=E7=B5=90=E8=AB=96=E7=9A=84=E7=B5=90=E6=9D=9F=E7=A2=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit What:把原本的結束碼 1 拆成兩個。1 只代表相依版本不符或缺相依 plugin。新增 4 代表判不出結論,成因是 manifest 不存在、不是有效 JSON、或缺 python3。這三種成因的輸出從 status=blocked 改成 status=unknown。 Why:兩種成因共用同一個結束碼,呼叫端就只能用同一句話講兩件事。環境壞掉會被講成版本落後。操作者照著去補版本,補到最後也碰不到真正的問題點。 How:找不到 manifest、找不到 python3、JSON 解析失敗三處改回傳 4,狀態字串一併改成 unknown。檔頭的輸出格式表與結束碼表跟著改寫,並寫下 1 與 4 分開的理由。 Who:相依檢查結論分流。 --- tools/check-requires.sh | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/tools/check-requires.sh b/tools/check-requires.sh index 6a264ff..1a40671 100755 --- a/tools/check-requires.sh +++ b/tools/check-requires.sh @@ -4,11 +4,17 @@ # check-requires.sh {claude|codex|copilot|antigravity|kiro} {manifest} # 輸出(單行,可供程式判讀): # status=ok reason={沒有宣告相依版本|相依版本符合:...} -# status=blocked reason={缺哪一個 plugin、差哪一版,或 manifest 讀不到} +# status=blocked reason={缺哪一個 plugin、差哪一版} +# status=unknown reason={manifest 讀不到、不是有效 JSON,或缺 python3} # 結束碼:0=通過(沒有宣告相依,或全部符合) -# 1=擋下(相依版本不符、缺相依 plugin、manifest 不存在或不是有效 JSON、缺 python3) +# 1=相依版本不符或缺相依 plugin # 2=用法錯誤(參數個數不對,或 CLI 代號不在五個之內) -# deploy.sh update 在每個 domain 更新前呼叫一次;擋下就跳過該 domain,不更新到一半才失敗。 +# 4=判不出結論(manifest 不存在、不是有效 JSON、缺 python3) +# 1 與 4 分開的理由:兩者都不是「通過」,但成因完全不同。混成同一個碼,呼叫端就只能 +# 用同一句話講兩件事,環境壞掉會被說成版本落後,操作者照著去補版本永遠補不到問題點。 +# deploy.sh update 在每個 domain 更新前呼叫一次,但擋下不代表跳過:deploy.sh 照樣更新, +# 只印一行提醒說缺哪一版。跳過會讓落後的 domain 永遠更新不到,形成死鎖。 +# 真正的阻擋在 jsc-hooks 的 version-guard.sh,技能被叫用時才擋。 set -u usage() { @@ -26,14 +32,14 @@ case "$CLI" in esac [ -f "$MANIFEST" ] || { - printf 'status=blocked reason=找不到 manifest:%s\n' "$MANIFEST" - exit 1 + printf 'status=unknown reason=找不到 manifest:%s\n' "$MANIFEST" + exit 4 } command -v python3 >/dev/null 2>&1 || { # 直接讓 shell 回 127 的話,呼叫端會看到一個沒宣告過的結束碼,也讀不到原因。 - printf 'status=blocked reason=找不到 python3,無法解析 manifest:%s\n' "$MANIFEST" - exit 1 + printf 'status=unknown reason=找不到 python3,無法解析 manifest:%s\n' "$MANIFEST" + exit 4 } JSC_HOME_DIR="${JSC_HOME:-$HOME/.jsc}" @@ -53,8 +59,8 @@ try: with open(manifest, encoding="utf-8") as fh: data = json.load(fh) except Exception as exc: - print(f"status=blocked reason=manifest 不是有效 JSON:{manifest}:{exc}") - sys.exit(1) + print(f"status=unknown reason=manifest 不是有效 JSON:{manifest}:{exc}") + sys.exit(4) requires = ((data.get("jsc") or {}).get("requires") or {}) if not requires: From ed4092bb3d69517f43f64d3a3e98763b600d6f99 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Mon, 31 Aug 2026 13:35:41 +0800 Subject: [PATCH 3/5] =?UTF-8?q?fix(deploy):=20=E7=9B=B8=E4=BE=9D=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E4=B8=8D=E7=AC=A6=E6=94=B9=E6=88=90=E7=85=A7=E6=A8=A3?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E4=B8=A6=E6=8F=90=E9=86=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit What:check_requires() 對 check-requires.sh 的四種結束碼重新分流。0 照常更新。1 改印一行 warn,該 domain 照樣更新,訊息寫出還缺哪一版。4 印一行 note,也照樣更新。2 或其他代碼維持印 skip、跳過該 domain,並記成失敗。 Why:跳過會讓落後的 domain 永遠等不到它要的相依版本,也就永遠更新不到,兩個 domain 互相等就形成死鎖。阻擋移到技能叫用那一層,由 jsc-hooks 的 version-guard.sh 執行,更新照跑不會壞事。判不出結論跟版本落後要講不同的話,混成一句會把環境問題誤導成版本問題。檢查腳本自己出錯是另一回事,讀不到結論就不能當成通過。 How:結束碼 1 的分支從印 skip、回傳 1 改成印 warn、回傳 0,結束碼 4 新增一個印 note、回傳 0 的分支,其餘代碼維持原本的 skip 與 FAILED。函式上方與檔頭補上這四條分流的理由。檔頭的輸出格式表補進 warn 與 compat 兩欄,結束碼說明也把 warn 列為不算失敗但要據實回報。 Who:相依版本不符的處置。 --- tools/deploy.sh | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/tools/deploy.sh b/tools/deploy.sh index f155550..6af0d68 100755 --- a/tools/deploy.sh +++ b/tools/deploy.sh @@ -9,11 +9,20 @@ # cmd{指令} 即將執行的指令 # exit{結束碼}{指令} 該指令的結束碼;dry-run 時結束碼印「-」 # skip{domain}{原因} 本地 clone 是開發中的樹,略過 git pull +# warn{domain}{原因} 相依版本不符,仍照樣更新的提醒 +# compatcodex{舊路徑}{新路徑} codex 舊版快取路徑補成指向新版的相容連結 # note{cli}{原因} 非逐指令的說明(例:kiro 整批改走複製退路的理由) # restart{路徑} 這次寫下的重啟狀態檔 # requires{domain}{檢查結果} update 前的 jsc.requires 檢查 # result{cli}{mode}{domain 清單}{ok|fail} -# 結束碼:全部指令成功 0;任一指令失敗 1;參數錯誤 2。skip、note 不算失敗,但呼叫端要據實回報。 +# 結束碼:全部指令成功 0;任一指令失敗 1;參數錯誤 2。skip、warn、note 不算失敗,但呼叫端要據實回報。 +# update 前每個 domain 都先跑一次同目錄的 check-requires.sh,它的四種結束碼分流如下: +# 0 相依符合,或沒有宣告相依 → 照常更新這個 domain +# 1 相依版本不符或缺相依 plugin +# → 印一行 warn,這個 domain 照樣更新(跳過會讓落後的 domain 永遠更新不到) +# 4 判不出結論(manifest 讀不到、不是有效 JSON、缺 python3) +# → 印一行 note,這個 domain 照樣更新。沒有證據不等於落後,話要跟 warn 分開講 +# 2 或其他 檢查腳本自己出錯(用法錯誤或腳本壞掉)→ 印一行 skip,跳過這個 domain 並記為失敗 # marketplace 指令一輪只跑一次:install 與 update 先跑,uninstall 最後跑。 # 各 CLI 的細節都收在這裡,SKILL.md 只描述何時呼叫與參數: # antigravity 不接受 gitea URL,先 clone 到本地再從路徑安裝,更新時 pull 同一份。 @@ -134,7 +143,12 @@ restart_gate_sh() { return 1 } -check_requires() { # $1=domain;0=可更新,1=略過這個 domain +# 相依版本不符只回報、不跳過。跳過的話,落後的 domain 永遠等不到那一版相依, +# 也就永遠更新不到,兩個 domain 互相等就形成死鎖。阻擋改放在技能呼叫那一層: +# jsc-hooks 的 version-guard.sh 會在版本不足時擋下該 domain 的技能,更新照跑不會壞事。 +# 檢查腳本自己出錯(退出碼 2 以上:用法錯誤或腳本壞掉)是另一回事,那不是相依不符, +# 讀不到結論就不能當成通過,照舊記 FAILED 並跳過這個 domain。 +check_requires() { # $1=domain;0=繼續更新,1=略過這個 domain(只有檢查腳本自己出錯才會回 1) [ "$MODE" = update ] || return 0 sync_local "$1" manifest="$LOCAL_DIR/$1/plugin.json" @@ -145,8 +159,15 @@ check_requires() { # $1=domain;0=可更新,1=略過這個 domain return 0 fi if [ "$code" -eq 1 ]; then - printf 'skip\t%s\t%s\n' "$1" "相依版本不符,未更新:$out" - return 1 + printf 'warn\t%s\t%s\n' "$1" "相依版本不符,這次照樣更新;補齊相依版本以前,叫用這個 domain 的技能會被 jsc-hooks 的 version-guard.sh 擋下。要補的版本:$out" + return 0 + fi + # 判不出結論跟版本落後要講不同的話。把兩者混成同一句,環境壞掉會被說成版本落後, + # 操作者照著去補版本永遠補不到問題點。照樣更新的理由與 version-guard.sh 一致: + # 沒有證據不等於落後,缺基礎設施就停掉更新,等於讓環境永遠修不好。 + if [ "$code" -eq 4 ]; then + printf 'note\t%s\t%s\n' "$1" "判不出相依版本,這次照樣更新;成因不是版本落後,先修環境再重跑檢查:$out" + return 0 fi FAILED=1 printf 'skip\t%s\t%s\n' "$1" "相依版本檢查失敗,未更新:$out" From 5f1c4cc6d7c6773c182c62040903558b188829a7 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Mon, 31 Aug 2026 13:35:42 +0800 Subject: [PATCH 4/5] =?UTF-8?q?docs(deploy):=20=E5=90=8C=E6=AD=A5=E7=9B=B8?= =?UTF-8?q?=E4=BE=9D=E6=AA=A2=E6=9F=A5=E6=94=B9=E7=82=BA=E7=85=A7=E6=A8=A3?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E7=9A=84=E8=A1=8C=E7=82=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit What:SKILL.md 第 4 步改寫成四種結束碼的處置,第 7 步的回報清單補上 warn 行。README 的 check-requires.sh 表格列與 deploy 技能段落改寫成同一套說法。 Why:文件還寫著版本不符就跳過該 domain。操作者依文件預期那個 domain 不會動,實際上它已經更新,回報也對不上腳本印出來的行。 How:SKILL.md 逐一寫出 0、1、4、2 或其他四種結束碼各自的處置與理由,完成條件改成 skip 要有檢查腳本出錯或本地樹的原因、warn 要指名還缺哪一版。README 兩處改寫成同樣的四種分流,並寫明真正的阻擋在 version-guard.sh。 Who:相依版本不符的處置。 --- README.md | 4 ++-- skills/deploy/SKILL.md | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index dfde9cc..a7d6f89 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Marketplace 統一為 `jsc`(https://gitea.jsc.idv.tw/plugins/meta.git),安 | --- | --- | | `tools/detect-clis.sh` | 列出已安裝的 AI CLI 與執行檔路徑(TSV:name / path / version;antigravity 的執行檔為 `agy`、kiro 為 `kiro-cli`) | | `tools/deploy.sh` | 對單一 CLI 執行安裝、更新或解除安裝(`deploy.sh [-n] {mode} {cli} {domain}...`,mode 為 install / update / uninstall);印出每個指令與其結束碼,最後一行 `result` 標 ok 或 fail。`-n` 只印指令不執行。上表五個 CLI 的指令差異全部收在這支腳本裡。Codex 更新 `jsc-cli` 與 `jsc-hooks` 後會把舊版快取路徑補成指向新版的相容連結,避免正在跑的部署流程找不到 helper 腳本,也避免尚未重啟的工作階段在 Stop hook 階段找不到舊路徑。install 或 update 全數成功時,收尾轉呼叫 `jsc-hooks` 的 `restart-gate.sh require` 掛上重啟閘門,並印一行 `restart` 標出狀態檔位置;uninstall 不寫。尋找 `restart-gate.sh` 時優先用 `$JSC_HOME/current/jsc-hooks`、本地 clone 與 Kiro skills,最後才掃各 CLI 快取,避免部署收尾綁死單一 CLI 的版號路徑。狀態檔的路徑、格式與判讀全在 `restart-gate.sh`,這支腳本不自己拼——格式只留一個真實來源。站台取自 `GITEA_HOST`,本地 clone 目錄取自 `JSC_LOCAL_PLUGINS`,兩者的預設值見下表 | -| `tools/check-requires.sh` | `check-requires.sh {cli} {manifest}` 檢查 manifest 的 `jsc.requires` 最低版本。沒有宣告就通過;版本不符或缺相依 plugin 就回 `status=blocked`。`deploy.sh update` 在每個 domain 更新前呼叫它,不符就跳過該 domain 並列出原因 | +| `tools/check-requires.sh` | `check-requires.sh {cli} {manifest}` 檢查 manifest 的 `jsc.requires` 最低版本。沒有宣告就通過;版本不符或缺相依 plugin 就回 `status=blocked` 與結束碼 1。`deploy.sh update` 在每個 domain 更新前呼叫它一次:結束碼 1 只印一行 `warn`,那個 domain 照樣更新——跳過會讓落後的 domain 永遠等不到相依版本,也就永遠更新不到,真正的阻擋由 `jsc-hooks` 的 `version-guard.sh` 在技能被叫用時執行;結束碼 2 以上是檢查腳本自己出錯,讀不到結論就不當成通過,印 `skip` 並跳過該 domain | | `tools/write-guides.sh` | 產生這台機器專屬的更新指引 `$JSC_HOME/update-guide.md` 與移除指引 `$JSC_HOME/remove-guide.md`(`write-guides.sh [-n] {install\|update} {domain}...`),一輪部署跑一次。CLI 清單取自 `detect-clis.sh`,每支 CLI 的指令字面直接取自 `deploy.sh -n` 的輸出,所以指引寫的就是實際會跑的指令;kiro 走不走本地複製退路也依實際偵測結果標注 | | `tools/list-models.sh` | 讀各 CLI 設定檔列出模型(TSV:cli / model / in-use);設定檔缺失就不輸出該 CLI 的列,一律 exit 0。設定檔位置只寫在這支腳本裡 | | `tools/model-config.sh` | 解析 SDLC 各階段的偏好模型鏈(`get {stage}`、`list`、`resolve {stage}` 印出目前 CLI 可用的第一個模型);專案 `.jsc/models` 優先於 `$JSC_HOME/models.conf`,格式見 `references/model-tags.md`。鏈只影響建議與偏好順序,不影響閘門放行 | @@ -50,7 +50,7 @@ Marketplace 統一為 `jsc`(https://gitea.jsc.idv.tw/plugins/meta.git),安 ### `deploy` -技能庫批次安裝、更新、解除安裝:**偵測 CLI、版本建議、marketplace domain 清單三者併行取得** → 秀出 `jsc-hooks/hooks/version-guard.sh report` 的版本證據表,再依 `recommend` 的一行結論(`recommend{update|none|unverifiable}`,只印這一行,不混印表格)標出推薦選項;輸出裡找不到 `recommend` 行就退回 `report` 自行推導並在回報寫明是降級路徑 → 決策樹選模式(呼叫方已確認過模式就沿用,不重問)→ 每個 CLI 一個 sub agent,**全部同時啟動**呼叫 `tools/deploy.sh` 執行原生 plugin 指令(統一 marketplace `jsc`,token `jsc-{domain}@jsc`)→ update 前逐一檢查 `jsc.requires`,版本不符就跳過該 domain 並回報缺哪一版 → Codex 更新 `jsc-cli` 與 `jsc-hooks` 時保留舊快取相容連結 → install、update 後把偵測到的 CLI 清單交給 `jsc-hooks:hooks-install`,取它的彙總結果,只自行加判一條「smoke 出現 `No such file` 一律視為更新失敗」。domain 名單動態取自 `plugins/meta` 的 marketplace.json,不硬編碼。 +技能庫批次安裝、更新、解除安裝:**偵測 CLI、版本建議、marketplace domain 清單三者併行取得** → 秀出 `jsc-hooks/hooks/version-guard.sh report` 的版本證據表,再依 `recommend` 的一行結論(`recommend{update|none|unverifiable}`,只印這一行,不混印表格)標出推薦選項;輸出裡找不到 `recommend` 行就退回 `report` 自行推導並在回報寫明是降級路徑 → 決策樹選模式(呼叫方已確認過模式就沿用,不重問)→ 每個 CLI 一個 sub agent,**全部同時啟動**呼叫 `tools/deploy.sh` 執行原生 plugin 指令(統一 marketplace `jsc`,token `jsc-{domain}@jsc`)→ update 前逐一檢查 `jsc.requires`,版本不符只印 `warn` 並照樣更新該 domain、回報還缺哪一版,阻擋交給 `version-guard.sh` 在技能被叫用時執行;檢查腳本自己出錯才印 `skip` 跳過該 domain → Codex 更新 `jsc-cli` 與 `jsc-hooks` 時保留舊快取相容連結 → install、update 後把偵測到的 CLI 清單交給 `jsc-hooks:hooks-install`,取它的彙總結果,只自行加判一條「smoke 出現 `No such file` 一律視為更新失敗」。domain 名單動態取自 `plugins/meta` 的 marketplace.json,不硬編碼。 ### `doctor` diff --git a/skills/deploy/SKILL.md b/skills/deploy/SKILL.md index d295a2f..32c343c 100644 --- a/skills/deploy/SKILL.md +++ b/skills/deploy/SKILL.md @@ -61,9 +61,9 @@ Nothing passed in → run every step as written below. | 2 | Usage error — the mode, the CLI name or the domain list is wrong. Report it as a defect in this skill, and do not retry with a guessed argument | | other | Record that CLI as failed with the exit code and stderr | - On update, `tools/check-requires.sh {cli} {manifest}` checks each domain's `jsc.requires` before that domain is updated. A missing or too-old required jsc plugin prints a `skip` line and leaves that domain untouched. Codex update preserves old `jsc-cli` and `jsc-hooks` cache version paths as symlinks to the newest installed version, so a still-running Codex deploy can keep using its helper scripts and a still-running Codex session whose hook_run_id points at the old cache can finish without `No such file`. Antigravity cannot install from a Gitea URL, so the script clones each domain into the local plugin directory (`JSC_LOCAL_PLUGINS`, default `$JSC_HOME/plugins`) and installs from that path — keep that clone, because update pulls the same one. That default deliberately avoids a development checkout: when the directory holds uncommitted changes or unpushed commits, the script prints a `skip` line, leaves the tree untouched, and installs the on-disk content. + On update, `tools/check-requires.sh {cli} {manifest}` checks each domain's `jsc.requires` before that domain is updated. Exit 0 updates the domain as usual. Exit 1 — a missing or too-old required jsc plugin — prints a `warn` line and the domain **is still updated**: skipping it would leave a behind domain permanently unable to reach the version its dependency needs. The block lives one layer up, at skill invocation time, where `jsc-hooks/hooks/version-guard.sh` stops that domain's skills. Exit 4 — the manifest is unreadable, is not valid JSON, or python3 is missing — prints a `note` line and also still updates the domain: no verdict is not the same fact as behind, so it gets its own line rather than a `warn` that would send the operator hunting for a version problem that is not there. Exit 2 or any other code — a `check-requires.sh` usage error or a broken script — prints a `skip` line and leaves that domain untouched, because a checker that failed outright is not a pass. Codex update preserves old `jsc-cli` and `jsc-hooks` cache version paths as symlinks to the newest installed version, so a still-running Codex deploy can keep using its helper scripts and a still-running Codex session whose hook_run_id points at the old cache can finish without `No such file`. Antigravity cannot install from a Gitea URL, so the script clones each domain into the local plugin directory (`JSC_LOCAL_PLUGINS`, default `$JSC_HOME/plugins`) and installs from that path — keep that clone, because update pulls the same one. That default deliberately avoids a development checkout: when the directory holds uncommitted changes or unpushed commits, the script prints a `skip` line, leaves the tree untouched, and installs the on-disk content. - Done when every detected CLI has reported an exit code and a `result` line, and every skipped domain has a dependency reason or a local-tree reason. + Done when every detected CLI has reported an exit code and a `result` line, every skipped domain has a checker-failure reason or a local-tree reason, and every `warn` domain is named with the version it still has to catch up to. 5. After install or update, call `jsc-hooks:hooks-install` and **hand it the CLI list from step 1.1**, so it does not probe the same five executables a second time. `hooks-install` still detects for itself when it receives no list — that fallback is what keeps it usable on its own. @@ -82,7 +82,7 @@ Nothing passed in → run every step as written below. Done when both `wrote` lines are printed, or the failure is reported with the exit code and the paths involved. -7. Report the run and close it, in one block. The result and any failure reason for every CLI × mode, plus every `skip` line, every Codex `compat` line, and every CLI that could not be version-checked in step 2. +7. Report the run and close it, in one block. The result and any failure reason for every CLI × mode, plus every `skip` line, every `warn` line, every Codex `compat` line, and every CLI that could not be version-checked in step 2. For install or update, the same block ends with the restart instruction, in these words: 「請關閉目前的工作階段並重新啟動,新的技能內容才會載入」. `deploy.sh` recorded this round in `$JSC_HOME/restart-required.d/{cli}` — one file per CLI — and prints its path on a `restart` line; `jsc-hooks` reads only that CLI's own file and keeps reminding until that CLI restarts, with `JSC_RESTART_GATE=off` as the escape hatch. Restarting one CLI clears its own file and leaves the others' gates standing. Name the two guide paths from step 6 in that same closing block, so the operator knows where this machine's update and removal commands now live. From 99e055499539b0da9d8fba7a76d5f90aac8b8bc1 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Mon, 31 Aug 2026 13:35:43 +0800 Subject: [PATCH 5/5] =?UTF-8?q?chore(plugin):=20=E7=89=88=E8=99=9F?= =?UTF-8?q?=E5=8D=87=E5=88=B0=200.2.6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit What:plugin.json、.claude-plugin/plugin.json、.codex-plugin/plugin.json 三份 manifest 的 version 從 0.2.5 改成 0.2.6。 Why:這一輪改了相依檢查的結束碼與部署時的處置,外部行為跟 0.2.5 不同。三份 manifest 是版本檢查與部署推薦的依據,版號不動,version-guard.sh 就看不出這台機器該更新。 How:三份檔案只改 version 一個欄位,其餘內容不動,三份保持同一個版號。 Who:版號發布。 --- .claude-plugin/plugin.json | 2 +- .codex-plugin/plugin.json | 2 +- plugin.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index 87fc8b8..a53df42 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "jsc-cli", - "version": "0.2.5", + "version": "0.2.6", "description": "CLI 偵測、模型能力標籤、子代理派工與技能庫批次部署", "skills": "./skills", "author": { diff --git a/.codex-plugin/plugin.json b/.codex-plugin/plugin.json index c527f07..fcadf6e 100644 --- a/.codex-plugin/plugin.json +++ b/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "jsc-cli", - "version": "0.2.5", + "version": "0.2.6", "description": "CLI 偵測、模型能力標籤、子代理派工與技能庫批次部署", "skills": "./skills", "jsc": { diff --git a/plugin.json b/plugin.json index 72ca953..93f2fde 100644 --- a/plugin.json +++ b/plugin.json @@ -1,6 +1,6 @@ { "name": "jsc-cli", - "version": "0.2.5", + "version": "0.2.6", "description": "CLI 偵測、模型能力標籤、子代理派工與技能庫批次部署", "skills": "./skills/", "jsc": {