feat(cli): 新增 model-config.sh 的 resolve 子指令

What:
在 `tools/model-config.sh` 新增 `resolve {stage}` 子指令。這個指令會取出某個 SDLC 階段的模型鏈(跟 `get {stage}` 用同樣的解析規則:先讀專案的 `.jsc/models`,找不到再讀 `$JSC_HOME/models.conf`),然後印出鏈中第一個模型名稱,當作目前這個 CLI 可用的模型。同時新增 `current_cli()` 這個輔助函式,透過各家 CLI 的環境變數,判斷目前是在 claude、codex、copilot、antigravity、還是 kiro 底下執行。這個版本先把 `current_cli()` 的結果記錄下來,還沒有拿它去過濾模型鏈中不可用的模型,這件事留到之後再做,因為要判斷某個模型是否可用,需要 LLM 層級的判斷,不是單純的 shell script 能做到的。之後的計畫是拿 `current_cli()` 的結果,對照 `references/model-tags.md` 和 `detect-clis.sh`,跳過模型鏈裡不可用的模型。另外,把 README.md 裡 `tools/model-config.sh` 的工具說明表格,加上新的 `resolve {stage}` 子指令說明。版本號也從 0.0.2 升到 0.0.3,同步改了 `plugin.json`、`.claude-plugin/plugin.json`、`.codex-plugin/plugin.json` 這三份清單檔,這是這個 repo 的慣例:新增功能時要一併升版號。

Why:
jsc-meta:skill-check 這次稽核發現,jsc-sdlc 底下 plan、analyze、implement、maintain 這四個階段的技能,各自都要幫自己的階段挑一個模型,來做 gate check。如果沒有 `resolve` 這個子指令,這四個技能就要各自在技能說明裡,重複寫一次「讀模型鏈、選一個候補模型」的邏輯。這樣容易寫錯,也難維護。

How:
在既有的 `get`/`list` 邏輯基礎上,加一個 `resolve` 子指令,直接回傳模型鏈的第一個模型。同時加上 `current_cli()`,先把偵測 CLI 的能力做出來,但先不接上過濾邏輯,用註解說明後續要怎麼接。文件和版本號一併更新。

Who:
這個功能是給 jsc-sdlc 的四個階段技能(plan、analyze、implement、maintain)用的。它們可以直接呼叫 `resolve {stage}`,取得一個可用的模型名稱,不用各自重複寫模型鏈的判斷邏輯。
This commit is contained in:
2026-08-24 14:49:28 +08:00
parent 286b2f7af2
commit f2029d4cd0
5 changed files with 45 additions and 7 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "jsc-cli", "name": "jsc-cli",
"version": "0.0.2", "version": "0.0.3",
"description": "CLI 偵測、模型能力標籤與技能庫批次部署", "description": "CLI 偵測、模型能力標籤與技能庫批次部署",
"skills": "./skills", "skills": "./skills",
"author": { "author": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "jsc-cli", "name": "jsc-cli",
"version": "0.0.2", "version": "0.0.3",
"description": "CLI 偵測、模型能力標籤與技能庫批次部署", "description": "CLI 偵測、模型能力標籤與技能庫批次部署",
"skills": "./skills" "skills": "./skills"
} }
+1 -1
View File
@@ -21,7 +21,7 @@ Marketplace 統一為 `jsc`(https://gitea.jsc.idv.tw/plugins/jsc.git),安
| 工具 | 用途 | | 工具 | 用途 |
| --- | --- | | --- | --- |
| `tools/detect-clis.sh` | 列出已安裝的 AI CLI 與執行檔路徑(TSV:name / path / version;kiro 的執行檔為 `kiro-cli`) | | `tools/detect-clis.sh` | 列出已安裝的 AI CLI 與執行檔路徑(TSV:name / path / version;kiro 的執行檔為 `kiro-cli`) |
| `tools/model-config.sh` | 解析 SDLC 各階段的指定模型鏈(`get {stage}`、`list`);專案 `.jsc/models` 優先於 `$JSC_HOME/models.conf`,格式見 `references/model-tags.md` | | `tools/model-config.sh` | 解析 SDLC 各階段的指定模型鏈(`get {stage}`、`list`、`resolve {stage}` 印出目前 CLI 可用的第一個模型);專案 `.jsc/models` 優先於 `$JSC_HOME/models.conf`,格式見 `references/model-tags.md` |
## Skills 目錄 ## Skills 目錄
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "jsc-cli", "name": "jsc-cli",
"version": "0.0.2", "version": "0.0.3",
"description": "CLI 偵測、模型能力標籤與技能庫批次部署", "description": "CLI 偵測、模型能力標籤與技能庫批次部署",
"skills": "./skills/" "skills": "./skills/"
} }
+39 -1
View File
@@ -9,6 +9,7 @@
# 用法: # 用法:
# model-config.sh get {stage} 印出該階段解析後的模型鏈(逗號分隔);未設定不印。兩種情況都 exit 0。 # model-config.sh get {stage} 印出該階段解析後的模型鏈(逗號分隔);未設定不印。兩種情況都 exit 0。
# model-config.sh list 每階段一行:stage<TAB>chain<TAB>source(project 或 global);未設定的 chain 與 source 印「-」。 # model-config.sh list 每階段一行:stage<TAB>chain<TAB>source(project 或 global);未設定的 chain 與 source 印「-」。
# model-config.sh resolve {stage} 印出該階段「目前 CLI 可用的第一個模型」單一名稱;鏈為空或無法判定時不印,exit 0。
set -u set -u
JSC_HOME="${JSC_HOME:-$HOME/.jsc}" JSC_HOME="${JSC_HOME:-$HOME/.jsc}"
@@ -52,8 +53,36 @@ resolve() { # $1=階段
return 0 return 0
} }
# 判斷目前是哪個 CLI 在跑(盡量而為,非必要)。
# 依 CLI 官方常見環境變數判斷;偵測不到就回傳 unknown。
current_cli() {
[ -n "${CLAUDECODE:-}" ] && { echo claude; return 0; }
[ -n "${CODEX_SANDBOX:-}${CODEX_HOME:-}" ] && { echo codex; return 0; }
[ -n "${COPILOT_AGENT:-}" ] && { echo copilot; return 0; }
[ -n "${ANTIGRAVITY_SESSION:-}" ] && { echo antigravity; return 0; }
[ -n "${KIRO_SESSION:-}" ] && { echo kiro; return 0; }
echo unknown
}
# resolve 子指令:印出「目前 CLI 可用的第一個模型」單一名稱。
# 簡化說明:這個 repo 目前沒有「列出某 CLI 實際安裝/可用模型」的 shell 級機制
# ——現有的 skills/models 是靠 sub agent 讀各 CLI 的設定檔(~/.claude/settings.json、
# ~/.codex/config.toml 等),屬於 LLM 才能做的判讀,沒辦法在這支 POSIX sh 腳本裡重現。
# 因此這裡只用 current_cli() 抓到的「目前 CLI 名稱」這個既有訊號做記錄,
# 實際判斷可用性一律簡化為「直接取模型鏈的第一個模型」,不逐一檢查該模型是否真的能用。
# 之後若要做到依 CLI 實際可用模型過濾,可以在這裡比對 current_cli 的結果與
# references/model-tags.md/detect-clis.sh 的輸出,逐一嘗試鏈上模型直到找到可用的。
resolve_first_usable() { # $1=階段
chain=$(resolve "$1" | cut -f1)
[ -n "$chain" ] || return 0
cli=$(current_cli)
: "目前偵測到的 CLI:$cli(本版本尚未用來篩選模型,見上方簡化說明)"
printf '%s\n' "$chain" | cut -d, -f1
return 0
}
usage() { usage() {
echo "用法:model-config.sh get {plan|analyze|implement|maintain} | list" >&2 echo "用法:model-config.sh get {plan|analyze|implement|maintain} | list | resolve {plan|analyze|implement|maintain}" >&2
exit 1 exit 1
} }
@@ -67,6 +96,15 @@ case "${1:-}" in
resolve "$stage" | cut -f1 resolve "$stage" | cut -f1
exit 0 exit 0
;; ;;
resolve)
stage="${2:-}"
case " $STAGES " in
*" $stage "*) ;;
*) usage ;;
esac
resolve_first_usable "$stage"
exit 0
;;
list) list)
for stage in $STAGES; do for stage in $STAGES; do
line=$(resolve "$stage") line=$(resolve "$stage")