以 plugin 形式安裝時,腳本會落在 CLI 的 plugin 快取目錄。 六支腳本原本一律取「腳本位置的上兩層」當技能組根目錄,這時一定推錯。 這一輪例行稽核的第一步就實際踩到:不先手動設環境變數,腳本根本跑不動, 而叫用它們的技能說明也沒提要設,等於留了一個必炸的預設值。 把推導規則抽成共用腳本,依序試環境變數、從目前目錄往上找、 腳本位置的上兩層、家目錄底下的 plugins,並以 gitea.sh 在不在當判準。 marketplace 每個 domain 存取庫都帶一份,單看它會把 domain 誤判成根。 推不出來就結束並指名要設環境變數,同時列出試過的每一個候選, 呼叫端一眼看得出要設什麼。只 clone 單一存取庫的環境留了逃生門: 環境變數有設且是目錄就照用,並在錯誤輸出提醒。 順手補上語言檢查與 manifest 同步兩支腳本的結束碼宣告與環境變數說明。 沒有宣告,呼叫端只能猜;猜錯就把失敗當成功。
86 lines
3.3 KiB
Bash
Executable File
86 lines
3.3 KiB
Bash
Executable File
#!/usr/bin/env sh
|
||
# verify-skill-removed.sh — 刪除技能後,實地檢查各 CLI 的磁碟上有沒有殘留。
|
||
#
|
||
# 用法: verify-skill-removed.sh <domain> <skill-name>
|
||
#
|
||
# 行為: 先用 jsc-cli/tools/detect-clis.sh 找出已安裝的 CLI,再逐一 grep 該 CLI 的技能快取
|
||
# 與 hook 設定,找技能名稱字面與指令形式 /jsc-{domain}:{name}。
|
||
# 未安裝的 CLI 不檢查;設定位置不存在就跳過(安靜降級,不算殘留)。
|
||
#
|
||
# 檢查位置(每個 CLI 的技能快取與 hook 設定):
|
||
# claude — ~/.claude/plugins/、~/.claude/settings.json、~/.claude/settings.local.json
|
||
# codex — ${CODEX_HOME:-~/.codex}/(config.toml 的 notify、AGENTS.md、plugins/)
|
||
# copilot — ~/.config/copilot/
|
||
# antigravity — ~/.antigravity/、~/.config/antigravity/
|
||
# kiro — ~/.kiro/、工作目錄的 .kiro/hooks/
|
||
#
|
||
# 根目錄: 交給 tools/plugins-root.sh 推導(JSC_PLUGINS_ROOT -> 從 $PWD 往上找 ->
|
||
# 腳本位置上兩層 -> $HOME/plugins)。以 plugin 形式安裝時,「腳本位置上兩層」會落在
|
||
# plugin 快取目錄,單靠它一定推錯,所以推導規則抽成共用腳本。
|
||
#
|
||
# 輸出: 檢查過的位置一行一個(stderr),殘留一行一個 {file}:{line}:{內容}(stdout)。
|
||
# 沒有殘留會印「無殘留」到 stderr,區別於「什麼都沒檢查」。
|
||
# 結束碼: 0=沒有殘留 1=有殘留 2=用法錯誤
|
||
# 3=推導不出根目錄、找不到 detect-clis.sh、沒偵測到任何 CLI,
|
||
# 或找不到可檢查的位置(**不等於乾淨**)
|
||
# 環境變數: JSC_PLUGINS_ROOT(根目錄,見 plugins-root.sh)
|
||
set -u
|
||
|
||
usage() {
|
||
echo 'usage: verify-skill-removed.sh <domain> <skill-name>' >&2
|
||
exit 2
|
||
}
|
||
|
||
[ "$#" -eq 2 ] || usage
|
||
DOMAIN=$1
|
||
SKILL=$2
|
||
[ -n "$DOMAIN" ] && [ -n "$SKILL" ] || usage
|
||
|
||
HERE=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
||
. "$HERE/plugins-root.sh"
|
||
ROOT=$(jsc_plugins_root) || exit 3
|
||
|
||
DETECT=""
|
||
for d in "$ROOT/cli/tools/detect-clis.sh" "$ROOT/jsc-cli/tools/detect-clis.sh"; do
|
||
[ -f "$d" ] && { DETECT="$d"; break; }
|
||
done
|
||
[ -n "$DETECT" ] || { echo "找不到 detect-clis.sh:請先取得 jsc-cli 存取庫" >&2; exit 3; }
|
||
|
||
CLIS=$(sh "$DETECT" 2>/dev/null | cut -f1)
|
||
[ -n "$CLIS" ] || { echo "沒偵測到任何已安裝的 CLI,無處可查" >&2; exit 3; }
|
||
|
||
cli_paths() { # $1=CLI 代號;印出該 CLI 的技能快取與 hook 設定位置
|
||
case "$1" in
|
||
claude)
|
||
printf '%s\n' "$HOME/.claude/plugins" "$HOME/.claude/settings.json" \
|
||
"$HOME/.claude/settings.local.json" ;;
|
||
codex)
|
||
printf '%s\n' "${CODEX_HOME:-$HOME/.codex}" ;;
|
||
copilot)
|
||
printf '%s\n' "$HOME/.config/copilot" ;;
|
||
antigravity)
|
||
printf '%s\n' "$HOME/.antigravity" "$HOME/.config/antigravity" ;;
|
||
kiro)
|
||
printf '%s\n' "$HOME/.kiro" "./.kiro" ;;
|
||
esac
|
||
}
|
||
|
||
checked=0
|
||
hit=0
|
||
for cli in $CLIS; do
|
||
for p in $(cli_paths "$cli"); do
|
||
[ -e "$p" ] || continue
|
||
checked=$((checked + 1))
|
||
echo "檢查 $cli:$p" >&2
|
||
out=$(grep -rnI --exclude-dir=.git -e "$SKILL" -e "/jsc-${DOMAIN}:${SKILL}" "$p" 2>/dev/null)
|
||
if [ -n "$out" ]; then
|
||
printf '%s\n' "$out"
|
||
hit=1
|
||
fi
|
||
done
|
||
done
|
||
|
||
[ "$checked" -gt 0 ] || { echo "偵測到 CLI,但沒有任何設定位置存在,無處可查" >&2; exit 3; }
|
||
[ "$hit" -eq 0 ] && echo "無殘留:已檢查 $checked 個位置" >&2
|
||
exit $hit
|