develop-to-master #12
+13
-19
@@ -7,26 +7,20 @@ description: Batch install, update, or uninstall the whole jsc skill set on ever
|
|||||||
|
|
||||||
## Steps
|
## Steps
|
||||||
|
|
||||||
1. Run `tools/detect-clis.sh` to find the installed CLIs and their executable paths.
|
1. Run `tools/detect-clis.sh` to find the installed CLIs and their executable paths. Done when the TSV lists at least one CLI with an executable path.
|
||||||
2. **Check versions before asking anything**, so the recommendation is based on fact rather than a guess:
|
2. **Check versions before asking anything**, so the recommendation is based on fact rather than a guess:
|
||||||
1. Run `jsc-hooks/hooks/version-guard.sh report`. It prints one line per installed jsc plugin — `{domain}<TAB>{本機}<TAB>{遠端}<TAB>{落後|最新|超前|查詢失敗}` — and a final `behind<TAB>{落後個數}`.
|
1. Run `jsc-hooks/hooks/version-guard.sh report`. It prints one line per installed jsc plugin — `{domain}<TAB>{本機}<TAB>{遠端}<TAB>{落後|最新|超前|查詢失敗}` — and a final `behind<TAB>{落後個數}`.
|
||||||
2. Show that table to the user as-is. It is the evidence behind the recommendation, so never summarise it away.
|
2. **No local plugin registry → report this CLI as unverifiable, never as up to date.** Two forms of the same fact: a report carrying no `{domain}` row at all before the `behind` line, or the script's explicit no-registry line (`noregistry<TAB>{路徑}`). Both mean the version check could not run for this CLI, so `behind<TAB>0` here proves nothing. State that plainly and base no recommendation on it.
|
||||||
3. **`behind` ≥ 1 → mark `update` as the recommended option**, and name every domain that is behind together with its local and remote version. One domain behind is enough; do not wait for a majority.
|
3. Show that table to the user as-is. It is the evidence behind the recommendation, so never summarise it away.
|
||||||
4. `behind` = 0 → recommend nothing; present the three options neutrally.
|
4. **`behind` ≥ 1 → mark `update` as the recommended option**, and name every domain that is behind together with its local and remote version. One domain behind is enough; do not wait for a majority.
|
||||||
5. `查詢失敗` on any domain → say so explicitly. An unverified domain is not the same as an up-to-date one, and must not be counted as either.
|
5. `behind` = 0 **with at least one domain row** → recommend nothing; present the three options neutrally.
|
||||||
3. Ask the user for the mode per the `jsc-ask:ask` rules: `install` / `update` / `uninstall`. Every option states its impact scope: which CLIs it touches and which configs it writes.
|
6. `查詢失敗` on any domain → say so explicitly. An unverified domain is not the same as an up-to-date one, and must not be counted as either.
|
||||||
|
|
||||||
|
Done when the report is shown and either every domain row carries one of the four status literals `落後` `最新` `超前` `查詢失敗`, or the CLI is reported as having no local registry and therefore unverifiable.
|
||||||
|
3. Ask the user for the mode per the `jsc-ask:ask` rules: `install` / `update` / `uninstall`. Every option states its impact scope: which CLIs it touches and which configs it writes. Done when the user has named exactly one of `install`, `update` or `uninstall`.
|
||||||
4. Get the domain list (**never hardcode it**; this skill follows automatically when domains are added or removed): read `plugins[].name` from the unified marketplace via
|
4. Get the domain list (**never hardcode it**; this skill follows automatically when domains are added or removed): read `plugins[].name` from the unified marketplace via
|
||||||
`jsc-gitea/tools/gitea.sh api GET /repos/plugins/meta/raw/.claude-plugin/marketplace.json`.
|
`jsc-gitea/tools/gitea.sh api GET /repos/plugins/meta/raw/.claude-plugin/marketplace.json`.
|
||||||
The marketplace is unified as `jsc` (`{MKT}` = `https://gitea.jsc.idv.tw/plugins/meta.git`); the install token is `jsc-{domain}@jsc`.
|
The marketplace is unified as `jsc`; the install token is `jsc-{domain}@jsc`. Done when the domain list comes from that response and holds at least one name.
|
||||||
5. Run the matching commands for each CLI (add the marketplace once per CLI, then install per domain). This step **MUST run as a sub agent** (one sub agent per CLI):
|
5. Run `tools/deploy.sh {mode} {cli} {domain}...` once per detected CLI, passing the whole domain list in one call so the marketplace command runs only once. This step **MUST run as a sub agent** (one sub agent per CLI). The script prints `cmd` and `exit` lines for every command, then one `result` line; `-n` prints the commands without running them. 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 status for every command it ran.
|
||||||
|
6. After install or update, call `jsc-hooks:hooks-install` to rewire the hooks. Done when hooks-install reports a wiring result for each detected CLI.
|
||||||
| CLI | install | update | uninstall |
|
7. Report the result and any failure reason for every CLI × mode, plus every `skip` line and every CLI that could not be version-checked in step 2. Done when every detected CLI appears in the report with its `result` status.
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| claude | `claude plugin marketplace add {MKT}`, then per domain `claude plugin install jsc-{domain}@jsc` | `claude plugin marketplace update jsc`, then per domain `claude plugin update jsc-{domain}@jsc` | per domain `claude plugin uninstall jsc-{domain}@jsc`, finally `claude plugin marketplace remove jsc` |
|
|
||||||
| codex | `codex plugin marketplace add {MKT}`, then per domain `codex plugin add jsc-{domain}@jsc` | `codex plugin marketplace upgrade jsc` | per domain `codex plugin remove jsc-{domain}@jsc`, finally `codex plugin marketplace remove jsc` |
|
|
||||||
| copilot | `copilot plugin marketplace add {MKT}`, then per domain `copilot plugin install jsc-{domain}@jsc` | `copilot plugin marketplace update jsc`, then per domain `copilot plugin update jsc-{domain}@jsc` | per domain `copilot plugin uninstall jsc-{domain}@jsc`, finally `copilot plugin marketplace remove jsc` |
|
|
||||||
| antigravity | per domain `git clone https://gitea.jsc.idv.tw/plugins/{domain}.git ~/plugins/{domain}`, then `agy plugin install ~/plugins/{domain}` (agy cannot install from a gitea URL) | `git -C ~/plugins/{domain} pull`, then `agy plugin uninstall jsc-{domain}` and install again | `agy plugin uninstall jsc-{domain}` |
|
|
||||||
| kiro | same plugin commands as copilot (executable `kiro-cli`); if unsupported, copy each repo's `skills/` into the kiro skills directory | pull again, then copy again | delete the matching skills directories |
|
|
||||||
|
|
||||||
6. After install or update, call `jsc-hooks:hooks-install` to rewire the hooks.
|
|
||||||
7. Report the result and any failure reason for every CLI × mode.
|
|
||||||
|
|||||||
+6
-16
@@ -1,26 +1,16 @@
|
|||||||
---
|
---
|
||||||
name: models
|
name: models
|
||||||
description: List every model usable by each installed AI CLI (claude, codex, copilot, antigravity, kiro) and attach capability tags from references/model-tags.md. Syncs the tag table to $JSC_HOME/model-tags.tsv via tools/model-tags.sh so jsc-sdlc gates can be enforced in code, states which tags each SDLC stage requires (plan and analyze need reasoning-max, implement needs coding, maintain any), and resolves each stage's preferred model chain via tools/model-config.sh (project .jsc/models overrides $JSC_HOME/models.conf) for switch suggestions only. Use when checking model fitness, inventorying models, or reviewing stage gating; not for switching models or editing the config files.
|
description: List every model usable by each installed AI CLI (claude, codex, copilot, antigravity, kiro) and attach capability tags from references/model-tags.md. Syncs the tag table to $JSC_HOME/model-tags.tsv via tools/model-tags.sh, so jsc-sdlc gates are enforced in code. States each SDLC stage's required tags: plan and analyze need reasoning-max, implement needs coding, maintain any. Resolves each stage's preferred model chain via tools/model-config.sh (project .jsc/models overrides $JSC_HOME/models.conf), for switch suggestions only. Use when checking model fitness, inventorying models, or reviewing stage gating; not for switching models or editing the config files.
|
||||||
---
|
---
|
||||||
|
|
||||||
# models — list CLI models with capability tags
|
# models — list CLI models with capability tags
|
||||||
|
|
||||||
## Steps
|
## Steps
|
||||||
|
|
||||||
1. Run `jsc-cli/tools/detect-clis.sh` to get the installed CLIs.
|
1. Run `jsc-cli/tools/detect-clis.sh` to get the installed CLIs. Done when the TSV lists every detected CLI with its executable path.
|
||||||
2. For each CLI, read the available models and the model currently in use. This step **MUST run as a sub agent**:
|
2. Run `jsc-cli/tools/list-models.sh` to read each CLI's models and the model currently in use. It prints `cli<TAB>model<TAB>in-use` from each CLI's own config, and stays silent for a CLI whose config it cannot read. For every detected CLI it returns no rows for, list that CLI's known default models and mark each one with the literal label 「預設推定」 (assumed default). This step **MUST run as a sub agent**. Done when every detected CLI has a model list or is marked unreadable.
|
||||||
|
3. Attach capability tags to every model per `references/model-tags.md`. A model missing from that table is not tagged by guesswork: add it to the table from the vendor's documentation, or queue it as a `jsc-ask:ask` question. Done when every listed model carries at least one tag and every unlisted model is either added to the table or queued as a `jsc-ask:ask` question.
|
||||||
| CLI | Source |
|
4. Output a table with four columns: CLI, model, tags, currently in use. Done when the table holds one row per model from step 2.
|
||||||
| --- | --- |
|
|
||||||
| claude | `model` in `~/.claude/settings.json`; known families are in the claude rows of model-tags.md |
|
|
||||||
| codex | `model` in `~/.codex/config.toml` |
|
|
||||||
| copilot | model options listed in the copilot config (`~/.config/copilot/`) |
|
|
||||||
| antigravity | models listed in the agy config |
|
|
||||||
| kiro | models listed in the kiro config |
|
|
||||||
|
|
||||||
If a config is unreadable, list that CLI's known default models and mark each one with the literal label 「預設推定」 (assumed default).
|
|
||||||
3. Attach capability tags to every model per `references/model-tags.md`. Handle unlisted models per the closing rule of that file.
|
|
||||||
4. Output a table with four columns: CLI, model, tags, currently in use.
|
|
||||||
5. Run `tools/model-tags.sh sync` to write the tag table to `$JSC_HOME/model-tags.tsv`, and report the path. This file is what `jsc-hooks/hooks/sdlc-gate.sh` reads, so the SDLC gate stays broken until it exists. Done when the command prints the path.
|
5. Run `tools/model-tags.sh sync` to write the tag table to `$JSC_HOME/model-tags.tsv`, and report the path. This file is what `jsc-hooks/hooks/sdlc-gate.sh` reads, so the SDLC gate stays broken until it exists. Done when the command prints the path.
|
||||||
6. Append the SDLC stage requirement table (plan and analyze need `reasoning-max`; implement needs `coding`; maintain accepts any), and state that gating is done in code by `sdlc-gate.sh lock {stage}` against the transcript's actual model id — **the models listed here are never allowed to self-assess their own tags**.
|
6. Append the SDLC stage requirement table (plan and analyze need `reasoning-max`; implement needs `coding`; maintain accepts any), and state that gating is done in code by `sdlc-gate.sh lock {stage}` against the transcript's actual model id — **the models listed here are never allowed to self-assess their own tags**. Done when all four stages appear with their required tags.
|
||||||
7. Run `jsc-cli/tools/model-config.sh list` and append a 「階段偏好模型」 table right after the stage requirement table, with three columns: stage, chain, source (`project` / `global`). State below the table that the chain does **not** grant passage: it only names the model to suggest switching to when the gate blocks, and expresses preference among models that already satisfy the required tags. Done when the table shows all four stages, with `-` for unconfigured ones.
|
7. Run `jsc-cli/tools/model-config.sh list` and append a 「階段偏好模型」 table right after the stage requirement table, with three columns: stage, chain, source (`project` / `global`). State below the table that the chain does **not** grant passage: it only names the model to suggest switching to when the gate blocks, and expresses preference among models that already satisfy the required tags. Done when the table shows all four stages, with `-` for unconfigured ones.
|
||||||
|
|||||||
Executable
+226
@@ -0,0 +1,226 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
# deploy.sh — 對單一 CLI 執行 jsc 技能組的安裝、更新或解除安裝。
|
||||||
|
# 用法:
|
||||||
|
# deploy.sh [-n] {install|update|uninstall} {claude|codex|copilot|antigravity|kiro} {domain} [domain...]
|
||||||
|
# -n 或 --dry-run(或 JSC_DEPLOY_DRYRUN=1):只印指令,不執行。
|
||||||
|
# 輸出(TSV,一行一筆):
|
||||||
|
# cmd<TAB>{指令} 即將執行的指令
|
||||||
|
# exit<TAB>{結束碼}<TAB>{指令} 該指令的結束碼;dry-run 時結束碼印「-」
|
||||||
|
# skip<TAB>{domain}<TAB>{原因} 本地 clone 是開發中的樹,略過 git pull
|
||||||
|
# result<TAB>{cli}<TAB>{mode}<TAB>{domain 清單}<TAB>{ok|fail}
|
||||||
|
# 結束碼:全部指令成功 0;任一指令失敗 1;參數錯誤 2。skip 不算失敗,但呼叫端要據實回報。
|
||||||
|
# marketplace 指令一輪只跑一次:install 與 update 先跑,uninstall 最後跑。
|
||||||
|
# 各 CLI 的細節都收在這裡,SKILL.md 只描述何時呼叫與參數:
|
||||||
|
# antigravity 不接受 gitea URL,先 clone 到本地再從路徑安裝,更新時 pull 同一份。
|
||||||
|
# kiro 的執行檔是 kiro-cli;plugin 指令失敗時退回複製 skills 目錄。
|
||||||
|
# 環境變數:
|
||||||
|
# GITEA_HOST Gitea 站台,可省略 scheme(預設 https://gitea.jsc.idv.tw)
|
||||||
|
# JSC_GITEA_OWNER 存取庫的 owner(預設 plugins)
|
||||||
|
# JSC_LOCAL_PLUGINS antigravity/kiro 用的本地 clone 目錄
|
||||||
|
# 預設 $JSC_HOME/plugins(即 ~/.jsc/plugins),刻意不用 ~/plugins:
|
||||||
|
# 那是維護者放開發 checkout 的地方,pull 下去會蓋掉未提交的工作。
|
||||||
|
# 指到開發中的樹(有未提交變更或未推送的 commit)時只印 skip,不 pull。
|
||||||
|
# JSC_KIRO_SKILLS kiro 退路用的 skills 目錄(預設 ~/.kiro/skills)
|
||||||
|
# JSC_DEPLOY_DRYRUN 設為 1 等同 -n
|
||||||
|
set -u
|
||||||
|
|
||||||
|
# Gitea 站台一律讀 GITEA_HOST(技能準則指定的變數),未設定才用正本站台。
|
||||||
|
HOST="${GITEA_HOST:-https://gitea.jsc.idv.tw}"
|
||||||
|
case "$HOST" in http://*|https://*) ;; *) HOST="https://$HOST" ;; esac
|
||||||
|
HOST="${HOST%/}"
|
||||||
|
OWNER="${JSC_GITEA_OWNER:-plugins}"
|
||||||
|
MKT="$HOST/$OWNER/meta.git"
|
||||||
|
REPO_BASE="$HOST/$OWNER"
|
||||||
|
LOCAL_DIR="${JSC_LOCAL_PLUGINS:-${JSC_HOME:-$HOME/.jsc}/plugins}"
|
||||||
|
KIRO_SKILLS="${JSC_KIRO_SKILLS:-$HOME/.kiro/skills}"
|
||||||
|
DRYRUN="${JSC_DEPLOY_DRYRUN:-0}"
|
||||||
|
FAILED=0
|
||||||
|
|
||||||
|
# CLI 代號 → 實際執行檔。唯一真實來源是 jsc-hooks 的 hooks/lib.sh cli_bin()。
|
||||||
|
# 這裡保留一份副本,因為這支腳本是整組技能的安裝入口:jsc-hooks 還沒裝上來時
|
||||||
|
# 也要能跑,不能 source 一個可能不存在的檔案。lib.sh 的對應表改了就同步改這裡。
|
||||||
|
cli_bin() { # $1=CLI 代號
|
||||||
|
case "$1" in
|
||||||
|
antigravity) printf 'agy' ;;
|
||||||
|
kiro) printf 'kiro-cli' ;;
|
||||||
|
*) printf '%s' "$1" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
echo "用法:deploy.sh [-n] {install|update|uninstall} {claude|codex|copilot|antigravity|kiro} {domain} [domain...]" >&2
|
||||||
|
exit 2
|
||||||
|
}
|
||||||
|
|
||||||
|
# 執行一個指令,並印出指令本身與結束碼。失敗就記進 FAILED。
|
||||||
|
run() { # $@=指令
|
||||||
|
printf 'cmd\t%s\n' "$*"
|
||||||
|
if [ "$DRYRUN" = 1 ]; then
|
||||||
|
printf 'exit\t-\t%s\n' "$*"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
"$@"
|
||||||
|
code=$?
|
||||||
|
printf 'exit\t%s\t%s\n' "$code" "$*"
|
||||||
|
[ "$code" -eq 0 ] || FAILED=1
|
||||||
|
return "$code"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 同 run,但失敗不記進 FAILED——留給「失敗還有退路」的指令用。
|
||||||
|
run_soft() { # $@=指令
|
||||||
|
printf 'cmd\t%s\n' "$*"
|
||||||
|
if [ "$DRYRUN" = 1 ]; then
|
||||||
|
printf 'exit\t-\t%s\n' "$*"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
"$@"
|
||||||
|
code=$?
|
||||||
|
printf 'exit\t%s\t%s\n' "$code" "$*"
|
||||||
|
return "$code"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 這份 clone 是不是「開發中的樹」。有原因就印出原因,沒有就不印。
|
||||||
|
# 判斷兩件事:有未提交變更,或有還沒推上去的 commit。兩者被 pull 蓋掉都救不回來。
|
||||||
|
local_hold() { # $1=存取庫路徑
|
||||||
|
if [ -n "$(git -C "$1" status --porcelain 2>/dev/null)" ]; then
|
||||||
|
printf '有未提交變更'
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
up=$(git -C "$1" rev-parse --abbrev-ref --symbolic-full-name '@{upstream}' 2>/dev/null) || return 0
|
||||||
|
[ -n "$up" ] || return 0
|
||||||
|
ahead=$(git -C "$1" rev-list --count "$up..HEAD" 2>/dev/null) || return 0
|
||||||
|
[ "${ahead:-0}" -eq 0 ] || printf '有 %s 個未推送的 commit' "$ahead"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 把某 domain 的存取庫抓到本地:有 .git 就 pull,沒有就 clone。
|
||||||
|
# 目標是開發中的樹時只印 skip,改用現地內容安裝,不 pull:這支腳本可以被指到任何
|
||||||
|
# 目錄,蓋掉維護者未提交或未推送的工作救不回來,安裝一份舊內容還能重跑。
|
||||||
|
sync_local() { # $1=domain
|
||||||
|
dir="$LOCAL_DIR/$1"
|
||||||
|
if [ -d "$dir/.git" ]; then
|
||||||
|
hold=$(local_hold "$dir")
|
||||||
|
if [ -n "$hold" ]; then
|
||||||
|
printf 'skip\t%s\t%s %s,未執行 git pull\n' "$1" "$dir" "$hold"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
run git -C "$dir" pull
|
||||||
|
else
|
||||||
|
run git clone "$REPO_BASE/$1.git" "$dir"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# claude、copilot、kiro-cli 共用的 plugin 指令組。
|
||||||
|
marketplace_cli() { # $1=執行檔
|
||||||
|
case "$MODE" in
|
||||||
|
install)
|
||||||
|
run "$1" plugin marketplace add "$MKT"
|
||||||
|
for d in $DOMAINS; do run "$1" plugin install "jsc-$d@jsc"; done
|
||||||
|
;;
|
||||||
|
update)
|
||||||
|
run "$1" plugin marketplace update jsc
|
||||||
|
for d in $DOMAINS; do run "$1" plugin update "jsc-$d@jsc"; done
|
||||||
|
;;
|
||||||
|
uninstall)
|
||||||
|
for d in $DOMAINS; do run "$1" plugin uninstall "jsc-$d@jsc"; done
|
||||||
|
run "$1" plugin marketplace remove jsc
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
deploy_codex() {
|
||||||
|
bin=$(cli_bin codex)
|
||||||
|
case "$MODE" in
|
||||||
|
install)
|
||||||
|
run "$bin" plugin marketplace add "$MKT"
|
||||||
|
for d in $DOMAINS; do run "$bin" plugin add "jsc-$d@jsc"; done
|
||||||
|
;;
|
||||||
|
update)
|
||||||
|
run "$bin" plugin marketplace upgrade jsc
|
||||||
|
;;
|
||||||
|
uninstall)
|
||||||
|
for d in $DOMAINS; do run "$bin" plugin remove "jsc-$d@jsc"; done
|
||||||
|
run "$bin" plugin marketplace remove jsc
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
deploy_antigravity() {
|
||||||
|
bin=$(cli_bin antigravity)
|
||||||
|
for d in $DOMAINS; do
|
||||||
|
case "$MODE" in
|
||||||
|
install)
|
||||||
|
sync_local "$d"
|
||||||
|
run "$bin" plugin install "$LOCAL_DIR/$d"
|
||||||
|
;;
|
||||||
|
update)
|
||||||
|
sync_local "$d"
|
||||||
|
run "$bin" plugin uninstall "jsc-$d"
|
||||||
|
run "$bin" plugin install "$LOCAL_DIR/$d"
|
||||||
|
;;
|
||||||
|
uninstall)
|
||||||
|
run "$bin" plugin uninstall "jsc-$d"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# plugin 指令不支援時的退路:從本地 clone 複製 skills 目錄。
|
||||||
|
kiro_copy() { # $1=domain
|
||||||
|
sync_local "$1"
|
||||||
|
run mkdir -p "$KIRO_SKILLS/jsc-$1"
|
||||||
|
run cp -R "$LOCAL_DIR/$1/skills/." "$KIRO_SKILLS/jsc-$1/"
|
||||||
|
}
|
||||||
|
|
||||||
|
deploy_kiro() {
|
||||||
|
bin=$(cli_bin kiro)
|
||||||
|
case "$MODE" in
|
||||||
|
install) run_soft "$bin" plugin marketplace add "$MKT" ;;
|
||||||
|
update) run_soft "$bin" plugin marketplace update jsc ;;
|
||||||
|
esac
|
||||||
|
for d in $DOMAINS; do
|
||||||
|
case "$MODE" in
|
||||||
|
install)
|
||||||
|
run_soft "$bin" plugin install "jsc-$d@jsc" || kiro_copy "$d"
|
||||||
|
;;
|
||||||
|
update)
|
||||||
|
run_soft "$bin" plugin update "jsc-$d@jsc" || kiro_copy "$d"
|
||||||
|
;;
|
||||||
|
uninstall)
|
||||||
|
run_soft "$bin" plugin uninstall "jsc-$d@jsc" || run rm -rf "$KIRO_SKILLS/jsc-$d"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
[ "$MODE" = uninstall ] && run_soft "$bin" plugin marketplace remove jsc
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
case "${1:-}" in
|
||||||
|
-n|--dry-run) DRYRUN=1; shift ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
[ $# -ge 3 ] || usage
|
||||||
|
MODE=$1
|
||||||
|
CLI=$2
|
||||||
|
shift 2
|
||||||
|
DOMAINS="$*"
|
||||||
|
|
||||||
|
case "$MODE" in
|
||||||
|
install|update|uninstall) ;;
|
||||||
|
*) usage ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
case "$CLI" in
|
||||||
|
claude) marketplace_cli "$(cli_bin claude)" ;;
|
||||||
|
copilot) marketplace_cli "$(cli_bin copilot)" ;;
|
||||||
|
codex) deploy_codex ;;
|
||||||
|
antigravity) deploy_antigravity ;;
|
||||||
|
kiro) deploy_kiro ;;
|
||||||
|
*) usage ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ "$FAILED" -eq 0 ]; then
|
||||||
|
printf 'result\t%s\t%s\t%s\tok\n' "$CLI" "$MODE" "$DOMAINS"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
printf 'result\t%s\t%s\t%s\tfail\n' "$CLI" "$MODE" "$DOMAINS"
|
||||||
|
exit 1
|
||||||
Executable
+83
@@ -0,0 +1,83 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
# list-models.sh — 讀各 AI CLI 的設定檔,列出模型與目前使用中的模型。
|
||||||
|
# 輸出(TSV,一行一個模型):cli<TAB>model<TAB>in-use(in-use 為 yes 或 no)
|
||||||
|
# 設定檔不存在或裡面沒寫模型,就不輸出該 CLI 的列;一律 exit 0。
|
||||||
|
# 設定檔位置只寫在這裡,SKILL.md 不再抄一份:
|
||||||
|
# claude ${CLAUDE_CONFIG_DIR:-~/.claude}/settings.json 的 model;ANTHROPIC_MODEL 可覆寫使用中的模型
|
||||||
|
# codex ${CODEX_HOME:-~/.codex}/config.toml:頂層 model 為使用中,[profiles.*] 的 model 併入清單
|
||||||
|
# copilot ~/.copilot/settings.json,退回 ~/.config/copilot/settings.json
|
||||||
|
# antigravity ~/.antigravity/settings.json,退回 ~/.config/antigravity/settings.json
|
||||||
|
# kiro ~/.kiro/settings/cli.json,退回 ~/.config/kiro/settings.json
|
||||||
|
# 五個 CLI 都沒有「列出可用模型」的指令,所以清單只到設定檔寫出來的模型。
|
||||||
|
# 沒有列的 CLI 由 skills/models 的 sub agent 補上預設模型並標註「預設推定」。
|
||||||
|
set -u
|
||||||
|
|
||||||
|
# 取第一個存在的檔案;都不存在就不印。
|
||||||
|
first_file() { # $@=候選路徑
|
||||||
|
for f in "$@"; do
|
||||||
|
[ -f "$f" ] && { printf '%s\n' "$f"; return 0; }
|
||||||
|
done
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# 取 JSON 檔裡某個鍵的所有字串值,一行一個,順序照檔案。
|
||||||
|
json_val() { # $1=檔案 $2=鍵名
|
||||||
|
[ -n "$1" ] || return 0
|
||||||
|
[ -f "$1" ] || return 0
|
||||||
|
grep -oE "\"$2\"[[:space:]]*:[[:space:]]*\"[^\"]+\"" "$1" 2>/dev/null \
|
||||||
|
| sed -e 's/^[^:]*:[[:space:]]*"//' -e 's/"$//'
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# 取 TOML 檔裡所有 model 設定值,一行一個,順序照檔案。
|
||||||
|
# 只認行首的 model=,所以 model_reasoning_effort 這類鍵不會誤中。
|
||||||
|
toml_val() { # $1=檔案
|
||||||
|
[ -n "$1" ] || return 0
|
||||||
|
[ -f "$1" ] || return 0
|
||||||
|
grep -E '^[[:space:]]*model[[:space:]]*=' "$1" 2>/dev/null \
|
||||||
|
| sed -e 's/^[^=]*=[[:space:]]*//' -e 's/[[:space:]]*#.*$//' \
|
||||||
|
-e 's/^"//' -e 's/"[[:space:]]*$//' -e "s/^'//" -e "s/'[[:space:]]*$//"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# 印出某 CLI 的列:使用中的模型排第一,重複的只留一筆。
|
||||||
|
emit() { # $1=cli $2=使用中的模型(可空) $3=模型清單(換行分隔,可空)
|
||||||
|
printf '%s\n%s\n' "$2" "$3" | awk -v cli="$1" -v cur="$2" '
|
||||||
|
{ gsub(/^[ \t]+|[ \t]+$/, "") }
|
||||||
|
$0 == "" { next }
|
||||||
|
seen[$0]++ { next }
|
||||||
|
{ printf "%s\t%s\t%s\n", cli, $0, ($0 == cur ? "yes" : "no") }'
|
||||||
|
}
|
||||||
|
|
||||||
|
# claude
|
||||||
|
cfg=$(first_file "${CLAUDE_CONFIG_DIR:-$HOME/.claude}/settings.json")
|
||||||
|
list=$(json_val "$cfg" model)
|
||||||
|
cur="${ANTHROPIC_MODEL:-}"
|
||||||
|
[ -n "$cur" ] || cur=$(printf '%s\n' "$list" | head -n1)
|
||||||
|
emit claude "$cur" "$list"
|
||||||
|
|
||||||
|
# codex
|
||||||
|
cfg=$(first_file "${CODEX_HOME:-$HOME/.codex}/config.toml")
|
||||||
|
list=$(toml_val "$cfg")
|
||||||
|
cur=$(printf '%s\n' "$list" | head -n1)
|
||||||
|
emit codex "$cur" "$list"
|
||||||
|
|
||||||
|
# copilot
|
||||||
|
cfg=$(first_file "$HOME/.copilot/settings.json" "$HOME/.config/copilot/settings.json")
|
||||||
|
list=$(json_val "$cfg" model)
|
||||||
|
cur=$(printf '%s\n' "$list" | head -n1)
|
||||||
|
emit copilot "$cur" "$list"
|
||||||
|
|
||||||
|
# antigravity
|
||||||
|
cfg=$(first_file "$HOME/.antigravity/settings.json" "$HOME/.config/antigravity/settings.json")
|
||||||
|
list=$(json_val "$cfg" model)
|
||||||
|
cur=$(printf '%s\n' "$list" | head -n1)
|
||||||
|
emit antigravity "$cur" "$list"
|
||||||
|
|
||||||
|
# kiro
|
||||||
|
cfg=$(first_file "$HOME/.kiro/settings/cli.json" "$HOME/.config/kiro/settings.json")
|
||||||
|
list=$(json_val "$cfg" model)
|
||||||
|
cur=$(printf '%s\n' "$list" | head -n1)
|
||||||
|
emit kiro "$cur" "$list"
|
||||||
|
|
||||||
|
exit 0
|
||||||
@@ -65,13 +65,13 @@ current_cli() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# resolve 子指令:印出「目前 CLI 可用的第一個模型」單一名稱。
|
# resolve 子指令:印出「目前 CLI 可用的第一個模型」單一名稱。
|
||||||
# 簡化說明:這個 repo 目前沒有「列出某 CLI 實際安裝/可用模型」的 shell 級機制
|
# 簡化說明:可用性一律簡化為「直接取模型鏈的第一個模型」,不逐一檢查該模型是否真的能用。
|
||||||
# ——現有的 skills/models 是靠 sub agent 讀各 CLI 的設定檔(~/.claude/settings.json、
|
# tools/list-models.sh 已經能讀各 CLI 設定檔列出模型,但五個 CLI 都沒有
|
||||||
# ~/.codex/config.toml 等),屬於 LLM 才能做的判讀,沒辦法在這支 POSIX sh 腳本裡重現。
|
# 「列出可用模型」的指令,設定檔沒寫出來的模型仍然查不到;拿這份清單當白名單過濾,
|
||||||
# 因此這裡只用 current_cli() 抓到的「目前 CLI 名稱」這個既有訊號做記錄,
|
# 會把合法但沒寫進設定檔的模型誤判成不可用,比不過濾更糟。
|
||||||
# 實際判斷可用性一律簡化為「直接取模型鏈的第一個模型」,不逐一檢查該模型是否真的能用。
|
# 因此這裡只用 current_cli() 抓到的「目前 CLI 名稱」這個既有訊號做記錄。
|
||||||
# 之後若要做到依 CLI 實際可用模型過濾,可以在這裡比對 current_cli 的結果與
|
# 之後若要依 CLI 實際可用模型過濾,等各 CLI 提供列出模型的指令,再比對
|
||||||
# references/model-tags.md/detect-clis.sh 的輸出,逐一嘗試鏈上模型直到找到可用的。
|
# list-models.sh 的輸出,逐一嘗試鏈上模型直到找到可用的。
|
||||||
resolve_first_usable() { # $1=階段
|
resolve_first_usable() { # $1=階段
|
||||||
chain=$(resolve "$1" | cut -f1)
|
chain=$(resolve "$1" | cut -f1)
|
||||||
[ -n "$chain" ] || return 0
|
[ -n "$chain" ] || return 0
|
||||||
|
|||||||
Reference in New Issue
Block a user