Files
cli/tools/model-config.sh
T
jiantw83andClaude Opus 5 26ffaa8a07 fix(cli): 補齊稽核缺失並修掉護欄失效
What:依 jsc-meta:skill-check 的稽核結果修正技能與工具——補上每個步驟的可檢核完成條件、
把留在內文的標準輸入輸出流程下放 tools/、修正查表與退碼路由造成的誤判。

Why:稽核發現這些缺失會讓技能在實際執行時走錯分支或靜默通過。
完成條件缺漏是最常被違反的一項;退碼誤判與查表錯誤則會讓良性狀況被當成失敗。

How:逐項對照 references/guidelines.md 的審核檢查清單修正,新增的工具都有
documented exit codes,並以真實執行驗證每條路徑。

Who:jsc-meta:skill-check 例行稽核(2026-08-25)。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 14:58:54 +08:00

123 lines
4.3 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env sh
# model-config.sh — 解析 SDLC 各階段的指定模型鏈(角色式路由)。
# 設定格式(一行一階段):stage=model[,fallback1[,fallback2...]]
# 「#」開頭為註解,空白行忽略。階段限定:plan、analyze、implement、maintain。
# 解析順序:
# 1. 目前工作目錄的 ./.jsc/models(專案覆寫)
# 2. $JSC_HOME/models.conf(JSC_HOME 預設 ~/.jsc)
# 專案檔有設定的階段完全覆寫全域設定;其餘階段仍讀全域檔。
# 用法:
# model-config.sh get {stage} 印出該階段解析後的模型鏈(逗號分隔);未設定不印。兩種情況都 exit 0。
# model-config.sh list 每階段一行:stage<TAB>chain<TAB>source(project 或 global);未設定的 chain 與 source 印「-」。
# model-config.sh resolve {stage} 印出該階段「目前 CLI 可用的第一個模型」單一名稱;鏈為空或無法判定時不印,exit 0。
set -u
JSC_HOME="${JSC_HOME:-$HOME/.jsc}"
PROJECT_FILE=./.jsc/models
GLOBAL_FILE="$JSC_HOME/models.conf"
STAGES="plan analyze implement maintain"
# 取出單一設定檔裡某階段的模型鏈。
# 同階段出現多行時取最後一行,結果才有確定性。
read_chain() { # $1=設定檔 $2=階段
[ -f "$1" ] || return 0
awk -F= -v stage="$2" '
{ sub(/\r$/, "") } # 去掉 CR
/^[ \t]*#/ { next } # 註解行
/^[ \t]*$/ { next } # 空白行
index($0, "=") == 0 { next }
{
key = $1
gsub(/[ \t]/, "", key)
if (key != stage) next
val = substr($0, index($0, "=") + 1)
gsub(/[ \t]/, "", val)
if (val != "") chain = val
}
END { if (chain != "") print chain }
' "$1"
}
# 解析單一階段:專案檔優先,該階段沒設定才退回全域檔。
# 輸出:chain<TAB>source;兩檔都沒設定時不輸出。
resolve() { # $1=階段
chain=$(read_chain "$PROJECT_FILE" "$1")
if [ -n "$chain" ]; then
printf '%s\tproject\n' "$chain"
return 0
fi
chain=$(read_chain "$GLOBAL_FILE" "$1")
if [ -n "$chain" ]; then
printf '%s\tglobal\n' "$chain"
fi
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 可用的第一個模型」單一名稱。
# 簡化說明:可用性一律簡化為「直接取模型鏈的第一個模型」,不逐一檢查該模型是否真的能用。
# tools/list-models.sh 已經能讀各 CLI 設定檔列出模型,但五個 CLI 都沒有
# 「列出可用模型」的指令,設定檔沒寫出來的模型仍然查不到;拿這份清單當白名單過濾,
# 會把合法但沒寫進設定檔的模型誤判成不可用,比不過濾更糟。
# 因此這裡只用 current_cli() 抓到的「目前 CLI 名稱」這個既有訊號做記錄。
# 之後若要依 CLI 實際可用模型過濾,等各 CLI 提供列出模型的指令,再比對
# list-models.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() {
echo "用法:model-config.sh get {plan|analyze|implement|maintain} | list | resolve {plan|analyze|implement|maintain}" >&2
exit 1
}
case "${1:-}" in
get)
stage="${2:-}"
case " $STAGES " in
*" $stage "*) ;;
*) usage ;;
esac
resolve "$stage" | cut -f1
exit 0
;;
resolve)
stage="${2:-}"
case " $STAGES " in
*" $stage "*) ;;
*) usage ;;
esac
resolve_first_usable "$stage"
exit 0
;;
list)
for stage in $STAGES; do
line=$(resolve "$stage")
if [ -n "$line" ]; then
printf '%s\t%s\n' "$stage" "$line"
else
printf '%s\t-\t-\n' "$stage"
fi
done
exit 0
;;
*)
usage
;;
esac