Files
meta/tools/plugins-root.sh
jiantw83 7dc5c32de3 fix(tools): 改用共用推導取得技能組根目錄,並補齊結束碼宣告
以 plugin 形式安裝時,腳本會落在 CLI 的 plugin 快取目錄。
六支腳本原本一律取「腳本位置的上兩層」當技能組根目錄,這時一定推錯。
這一輪例行稽核的第一步就實際踩到:不先手動設環境變數,腳本根本跑不動,
而叫用它們的技能說明也沒提要設,等於留了一個必炸的預設值。

把推導規則抽成共用腳本,依序試環境變數、從目前目錄往上找、
腳本位置的上兩層、家目錄底下的 plugins,並以 gitea.sh 在不在當判準。
marketplace 每個 domain 存取庫都帶一份,單看它會把 domain 誤判成根。
推不出來就結束並指名要設環境變數,同時列出試過的每一個候選,
呼叫端一眼看得出要設什麼。只 clone 單一存取庫的環境留了逃生門:
環境變數有設且是目錄就照用,並在錯誤輸出提醒。

順手補上語言檢查與 manifest 同步兩支腳本的結束碼宣告與環境變數說明。
沒有宣告,呼叫端只能猜;猜錯就把失敗當成功。
2026-08-31 11:11:12 +08:00

96 lines
4.2 KiB
Bash
Executable File
Raw Permalink 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
# plugins-root.sh — 推導 jsc 技能組工作目錄的根,meta/tools 六支腳本共用同一套規則。
#
# 用法:
# . "$(dirname -- "$0")/plugins-root.sh" # 以 source 載入,取得 jsc_plugins_root()
# ROOT=$(jsc_plugins_root) || exit {該腳本的碼}
# sh plugins-root.sh # 直接執行,把推導結果印到 stdout
#
# 為什麼要抽出來:
# 舊寫法一律取「本腳本位置的上兩層」。技能組以 plugin 形式安裝時,腳本落在
# ~/.claude/plugins/cache/jsc/jsc-meta/{版本}/tools/,上兩層是 .../cache/jsc/jsc-meta,
# 那是 plugin 快取,不是放各 domain 存取庫的工作目錄,**一定推錯**。
# 2026-08 例行稽核第一步就實際踩到:不手動設 JSC_PLUGINS_ROOT 就跑不動,
# 而呼叫這些腳本的 SKILL.md 都沒提要設。
#
# 推導順序(取第一個帶得出 gitea.sh 的候選):
# 1. JSC_PLUGINS_ROOT
# 2. 從 $PWD 逐層往上,找含 meta/.claude-plugin/marketplace.json
# (或 jsc-meta/.claude-plugin/marketplace.json)的目錄
# 3. 本腳本位置的上兩層({root}/meta/tools -> {root})
# 4. $HOME/plugins
#
# 判準: 候選目錄下要有 gitea/tools/gitea.sh 或 jsc-gitea/tools/gitea.sh。
# marketplace.json 每個 domain 存取庫都帶一份,單看它會把某個 domain 存取庫自己
# 誤判成根;gitea.sh 只存在於 jsc-gitea 存取庫裡,拿它當標記才分得出根與 domain。
#
# 逃生門: 候選都不帶 gitea.sh,但 JSC_PLUGINS_ROOT 有設且是目錄時,照設定值使用,
# 並在 stderr 提醒。只 clone plugins/meta 的環境(CI、單存取庫維護)本來就沒有
# jsc-gitea;這時硬擋會讓「請設 JSC_PLUGINS_ROOT」變成解不開的死路。
#
# 結束碼(直接執行時): 0=推導成功,根目錄印在 stdout
# 1=推導不出來,訊息會指名要設 JSC_PLUGINS_ROOT 並列出試過的候選
# 環境變數: JSC_PLUGINS_ROOT(根目錄,最優先)
set -u
_jsc_walk_up() { # 從 $PWD 逐層往上,印出第一個含 meta 存取庫的目錄
_jpr_d=$(pwd -P 2>/dev/null) || return 1
while [ -n "$_jpr_d" ]; do
if [ -f "$_jpr_d/meta/.claude-plugin/marketplace.json" ] ||
[ -f "$_jpr_d/jsc-meta/.claude-plugin/marketplace.json" ]; then
printf '%s\n' "$_jpr_d"
return 0
fi
[ "$_jpr_d" = / ] && break
_jpr_d=$(dirname -- "$_jpr_d")
done
return 1
}
_jsc_has_gitea() { # $1=候選根目錄;jsc-gitea 存取庫是「這是根」的唯一可靠標記
[ -f "$1/gitea/tools/gitea.sh" ] || [ -f "$1/jsc-gitea/tools/gitea.sh" ]
}
jsc_plugins_root() { # 印出根目錄(stdout);推不出來回 1,說明走 stderr
_jpr_tried=''
for _jpr_src in env pwd here home; do
case "$_jpr_src" in
env) _jpr_c="${JSC_PLUGINS_ROOT:-}" ;;
pwd) _jpr_c=$(_jsc_walk_up 2>/dev/null) || _jpr_c='' ;;
here) _jpr_c=$(CDPATH= cd -- "$(dirname -- "$0")/../.." 2>/dev/null && pwd) || _jpr_c='' ;;
home) if [ -n "${HOME:-}" ]; then _jpr_c="$HOME/plugins"; else _jpr_c=''; fi ;;
*) _jpr_c='' ;;
esac
[ -n "$_jpr_c" ] || continue
_jpr_tried="$_jpr_tried $_jpr_src: $_jpr_c
"
[ -d "$_jpr_c" ] || continue
_jsc_has_gitea "$_jpr_c" || continue
_jpr_c=$(CDPATH= cd -- "$_jpr_c" && pwd) || continue
printf '%s\n' "${_jpr_c%/}"
return 0
done
if [ -n "${JSC_PLUGINS_ROOT:-}" ] && [ -d "$JSC_PLUGINS_ROOT" ]; then
echo "JSC_PLUGINS_ROOT 底下找不到 gitea/tools/gitea.sh,仍照設定值使用:$JSC_PLUGINS_ROOT" >&2
_jpr_c=$(CDPATH= cd -- "$JSC_PLUGINS_ROOT" && pwd) || return 1
printf '%s\n' "${_jpr_c%/}"
return 0
fi
{
echo '推導不出 jsc 技能組的根目錄。'
echo '以 plugin 形式安裝時,腳本位在 ~/.claude/plugins/cache/jsc/jsc-meta/{版本}/tools/,'
echo '上兩層落在 plugin 快取目錄,不是放各 domain 存取庫的工作目錄,所以推不出來。'
echo '請設 JSC_PLUGINS_ROOT 指向放各 domain 存取庫的工作目錄(底下要有 gitea 或 jsc-gitea)。'
echo '已試過的候選:'
printf '%s' "$_jpr_tried"
} >&2
return 1
}
# 直接執行時印出結果;被 source 時只提供函式。
case "${0##*/}" in
plugins-root.sh) jsc_plugins_root || exit 1 ;;
esac