以 plugin 形式安裝時,腳本會落在 CLI 的 plugin 快取目錄。 六支腳本原本一律取「腳本位置的上兩層」當技能組根目錄,這時一定推錯。 這一輪例行稽核的第一步就實際踩到:不先手動設環境變數,腳本根本跑不動, 而叫用它們的技能說明也沒提要設,等於留了一個必炸的預設值。 把推導規則抽成共用腳本,依序試環境變數、從目前目錄往上找、 腳本位置的上兩層、家目錄底下的 plugins,並以 gitea.sh 在不在當判準。 marketplace 每個 domain 存取庫都帶一份,單看它會把 domain 誤判成根。 推不出來就結束並指名要設環境變數,同時列出試過的每一個候選, 呼叫端一眼看得出要設什麼。只 clone 單一存取庫的環境留了逃生門: 環境變數有設且是目錄就照用,並在錯誤輸出提醒。 順手補上語言檢查與 manifest 同步兩支腳本的結束碼宣告與環境變數說明。 沒有宣告,呼叫端只能猜;猜錯就把失敗當成功。
284 lines
8.4 KiB
Bash
Executable File
284 lines
8.4 KiB
Bash
Executable File
#!/usr/bin/env sh
|
||
# inventory-tooling.sh — 盤點 jsc plugins、skills、tools、hooks,輸出技能組基礎指引。
|
||
#
|
||
# 用法: inventory-tooling.sh [root]
|
||
#
|
||
# root: 給了參數就用參數。沒給就交給 tools/plugins-root.sh 推導
|
||
# (JSC_PLUGINS_ROOT -> 從 $PWD 往上找 -> 腳本位置上兩層 -> $HOME/plugins)。
|
||
# 以 plugin 形式安裝時,「腳本位置上兩層」會落在 plugin 快取目錄,單靠它一定推錯,
|
||
# 所以推導規則抽成共用腳本。
|
||
#
|
||
# 輸出: Markdown。內容包含 domain、manifest、技能、工具、hooks 與管理入口。
|
||
# 同一趟已經跑過 list-skills.sh、detect-clis.sh 與 wire-cli.sh status,結果都寫進輸出,
|
||
# 呼叫端沿用即可,不必再各跑一次。
|
||
# 結束碼: 0=成功 1=推導不出根目錄、根目錄不存在、marketplace 或必要工具缺失
|
||
# 環境變數: JSC_PLUGINS_ROOT(根目錄,見 plugins-root.sh)
|
||
set -eu
|
||
|
||
HERE=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
||
. "$HERE/plugins-root.sh"
|
||
if [ "$#" -ge 1 ] && [ -n "$1" ]; then
|
||
ROOT=$1
|
||
else
|
||
ROOT=$(jsc_plugins_root) || exit 1
|
||
fi
|
||
ROOT=${ROOT%/}
|
||
|
||
[ -d "$ROOT" ] || { echo "找不到 plugins 根目錄:$ROOT" >&2; exit 1; }
|
||
|
||
MARKETPLACE=""
|
||
for cand in "$ROOT/meta/.claude-plugin/marketplace.json" "$ROOT"/*/.claude-plugin/marketplace.json; do
|
||
[ -f "$cand" ] && { MARKETPLACE=$cand; break; }
|
||
done
|
||
[ -n "$MARKETPLACE" ] || { echo "找不到 marketplace.json,無法判定 domain 清單" >&2; exit 1; }
|
||
|
||
LIST_SKILLS="$ROOT/meta/tools/list-skills.sh"
|
||
[ -x "$LIST_SKILLS" ] || { echo "找不到可執行的 list-skills.sh:$LIST_SKILLS" >&2; exit 1; }
|
||
|
||
tmp=$(mktemp -d)
|
||
trap 'rm -rf "$tmp"' EXIT
|
||
|
||
domains_file="$tmp/domains.tsv"
|
||
skills_file="$tmp/skills.tsv"
|
||
clis_file="$tmp/clis.tsv"
|
||
hook_status_file="$tmp/hook-status.tsv"
|
||
|
||
sed -n 's/.*"name"[[:space:]]*:[[:space:]]*"jsc-\([a-z0-9-]*\)".*/\1/p' "$MARKETPLACE" |
|
||
sort -u |
|
||
while read -r domain; do
|
||
[ -n "$domain" ] || continue
|
||
path="$ROOT/$domain"
|
||
[ -d "$path" ] || path="$ROOT/jsc-$domain"
|
||
if [ -d "$path" ]; then
|
||
version=$(sed -n 's/.*"version": *"\([^"]*\)".*/\1/p' "$path/plugin.json" 2>/dev/null | head -1)
|
||
[ -n "$version" ] || version="未知"
|
||
printf '%s\t%s\t%s\n' "$domain" "$version" "$path"
|
||
else
|
||
printf '%s\t%s\t%s\n' "$domain" "缺本機存取庫" "-"
|
||
fi
|
||
done > "$domains_file"
|
||
|
||
JSC_PLUGINS_ROOT="$ROOT" "$LIST_SKILLS" > "$skills_file" 2>/dev/null || : > "$skills_file"
|
||
|
||
DETECT_CLIS="$ROOT/cli/tools/detect-clis.sh"
|
||
if [ -x "$DETECT_CLIS" ]; then
|
||
"$DETECT_CLIS" > "$clis_file" 2>/dev/null || : > "$clis_file"
|
||
else
|
||
: > "$clis_file"
|
||
fi
|
||
|
||
WIRE_CLI="$ROOT/hooks/tools/wire-cli.sh"
|
||
: > "$hook_status_file"
|
||
if [ -x "$WIRE_CLI" ] && [ -s "$clis_file" ]; then
|
||
while IFS="$(printf '\t')" read -r cli path version; do
|
||
[ -n "$cli" ] || continue
|
||
out="$tmp/wire-$cli.out"
|
||
err="$tmp/wire-$cli.err"
|
||
if "$WIRE_CLI" status "$cli" > "$out" 2> "$err"; then
|
||
rc=0
|
||
else
|
||
rc=$?
|
||
fi
|
||
verdict=$(sed -n '1{s/[|]/-/g;p;}' "$out")
|
||
[ -n "$verdict" ] || verdict=$(sed -n '1{s/[|]/-/g;p;}' "$err")
|
||
[ -n "$verdict" ] || verdict="無狀態輸出"
|
||
case "$rc" in
|
||
0|1|3|5) ;;
|
||
2) verdict="CLI 代號不符合 wire-cli.sh 用法" ;;
|
||
*) verdict="未知狀態,結束碼 $rc" ;;
|
||
esac
|
||
printf '%s\t%s\t%s\n' "$cli" "$rc" "$verdict" >> "$hook_status_file"
|
||
done < "$clis_file"
|
||
fi
|
||
|
||
count_lines() {
|
||
file=$1
|
||
[ -s "$file" ] || { echo 0; return; }
|
||
wc -l < "$file" | tr -d ' '
|
||
}
|
||
|
||
domains_count=$(count_lines "$domains_file")
|
||
skills_count=$(count_lines "$skills_file")
|
||
clis_count=$(count_lines "$clis_file")
|
||
|
||
cat <<EOF
|
||
# jsc 技能組基礎指引
|
||
|
||
產生時間:$(date '+%Y-%m-%d %H:%M:%S %z')
|
||
|
||
資料來源:
|
||
|
||
- plugins 根目錄:\`$ROOT\`
|
||
- marketplace:\`$MARKETPLACE\`
|
||
- 技能清單工具:\`$LIST_SKILLS\`
|
||
|
||
## Source freshness
|
||
|
||
| 項目 | 狀態 |
|
||
| --- | --- |
|
||
| 本機 domain 清單 | synced |
|
||
| marketplace | \`$MARKETPLACE\` |
|
||
|
||
## 現況摘要
|
||
|
||
| 項目 | 數量 |
|
||
| --- | ---: |
|
||
| 已註冊 plugin domain | $domains_count |
|
||
| 已掃到技能 | $skills_count |
|
||
| 已偵測 CLI | $clis_count |
|
||
|
||
## Supported plugins
|
||
|
||
| domain | version | 本機路徑 |
|
||
| --- | --- | --- |
|
||
EOF
|
||
|
||
while IFS="$(printf '\t')" read -r domain version path; do
|
||
[ -n "$domain" ] || continue
|
||
printf '| `%s` | `%s` | `%s` |\n' "$domain" "$version" "$path"
|
||
done < "$domains_file"
|
||
|
||
cat <<'EOF'
|
||
|
||
## Supported skills
|
||
|
||
| domain | skill | 用途 |
|
||
| --- | --- | --- |
|
||
EOF
|
||
|
||
if [ -s "$skills_file" ]; then
|
||
while IFS="$(printf '\t')" read -r domain name desc; do
|
||
[ -n "$domain" ] || continue
|
||
printf '| `%s` | `%s` | %s |\n' "$domain" "$name" "$desc"
|
||
done < "$skills_file"
|
||
else
|
||
echo '| - | - | 未掃到技能。請先執行 `meta/tools/sync-domains.sh`。 |'
|
||
fi
|
||
|
||
cat <<'EOF'
|
||
|
||
Skill 使用方式:
|
||
|
||
- Claude、Antigravity:使用 `/jsc-{domain}:{name}`。
|
||
- Codex:使用技能名稱或自然語意觸發。
|
||
- Copilot、Kiro:用需求描述觸發。
|
||
- 每支技能只保留決策與流程。可標準輸入輸出的細節放到 `tools/`。
|
||
- 需要強制執行的規則放到 `jsc-hooks`,不要散落在各 domain。
|
||
|
||
## Supported CLIs
|
||
|
||
| CLI | 執行檔 | 版本 |
|
||
| --- | --- | --- |
|
||
EOF
|
||
|
||
if [ -s "$clis_file" ]; then
|
||
while IFS="$(printf '\t')" read -r cli path version; do
|
||
[ -n "$cli" ] || continue
|
||
printf '| `%s` | `%s` | `%s` |\n' "$cli" "$path" "$version"
|
||
done < "$clis_file"
|
||
else
|
||
echo '| - | - | 這台機器未偵測到支援的 CLI,或找不到 `cli/tools/detect-clis.sh`。 |'
|
||
fi
|
||
|
||
cat <<'EOF'
|
||
|
||
## Supported tools
|
||
|
||
| domain | tool | 用途 |
|
||
| --- | --- | --- |
|
||
EOF
|
||
|
||
while IFS="$(printf '\t')" read -r domain version path; do
|
||
[ -d "$path/tools" ] || continue
|
||
for tool in "$path"/tools/*; do
|
||
[ -f "$tool" ] || continue
|
||
base=$(basename "$tool")
|
||
first=$(sed -n '2{s/^# *//;p;}' "$tool" 2>/dev/null)
|
||
[ -n "$first" ] || first="工具腳本"
|
||
printf '| `%s` | `%s` | %s |\n' "$domain" "$base" "$first"
|
||
done
|
||
done < "$domains_file"
|
||
|
||
cat <<'EOF'
|
||
|
||
Tool 使用方式:
|
||
|
||
- 先讀工具檔頭的用法與結束碼。
|
||
- 用真實參數驗證新增或修改的工具。
|
||
- 結束碼沒有文件化時,先補工具說明,再讓技能呼叫它。
|
||
|
||
## Hook management
|
||
|
||
| hook | 用途 |
|
||
| --- | --- |
|
||
EOF
|
||
|
||
HOOK_DIR="$ROOT/hooks/hooks"
|
||
if [ -d "$HOOK_DIR" ]; then
|
||
for hook in "$HOOK_DIR"/*.sh; do
|
||
[ -f "$hook" ] || continue
|
||
base=$(basename "$hook")
|
||
first=$(sed -n '2{s/^# *//;p;}' "$hook" 2>/dev/null)
|
||
[ -n "$first" ] || first="hook 腳本"
|
||
printf '| `%s` | %s |\n' "$base" "$first"
|
||
done
|
||
else
|
||
echo '| - | 找不到 `hooks/hooks`。請先執行 `meta/tools/sync-domains.sh`。 |'
|
||
fi
|
||
|
||
cat <<'EOF'
|
||
|
||
Hook 使用方式:
|
||
|
||
- Hook 只放在 `jsc-hooks` domain。
|
||
- `jsc-hooks:hooks-install` 負責接線到各 CLI。
|
||
- hook 腳本要能接受 stdin JSON 與環境變數。
|
||
- 缺欄位時安靜降級並 `exit 0`。
|
||
- 版本閘門與重啟閘門要保留解除自己的路徑。
|
||
|
||
## Hook wiring status
|
||
|
||
| CLI | 結束碼 | 狀態 |
|
||
| --- | ---: | --- |
|
||
EOF
|
||
|
||
if [ -s "$hook_status_file" ]; then
|
||
while IFS="$(printf '\t')" read -r cli rc status; do
|
||
[ -n "$cli" ] || continue
|
||
printf '| `%s` | %s | %s |\n' "$cli" "$rc" "$status"
|
||
done < "$hook_status_file"
|
||
else
|
||
echo '| - | - | 未偵測到 CLI,或找不到 `hooks/tools/wire-cli.sh`。 |'
|
||
fi
|
||
|
||
cat <<'EOF'
|
||
|
||
## Plugin and skill management
|
||
|
||
- 新增技能:使用 `jsc-meta:skill-new`。
|
||
- 更新單一技能:使用 `jsc-meta:skill-update`。
|
||
- 批次更新技能組:使用 `jsc-meta:skillset-update`。
|
||
- 刪除技能:使用 `jsc-meta:skill-delete`。
|
||
- 安裝、更新、移除整組 plugin:使用 `jsc-cli:deploy`。
|
||
- 例行稽核:使用 `jsc-meta:skill-check`。
|
||
- 重新接線 hooks:使用 `jsc-hooks:hooks-install`。
|
||
|
||
## Operational checks
|
||
|
||
- 體檢目前環境:使用 `jsc-cli:doctor`。
|
||
- 修復體檢項目:使用 `jsc-cli:setup`。
|
||
- 版本前置檢查:由 `jsc-hooks/hooks/version-guard.sh` 管理。
|
||
- 部署後重啟閘門:由 `jsc-hooks/hooks/restart-gate.sh` 管理。
|
||
- 語言提示與掃描:由 `jsc-hooks/hooks/ste100-guard.sh` 與 `jsc-hooks/hooks/lang-guard.sh` 管理。
|
||
- 註解範圍檢查:由 `jsc-hooks/hooks/comment-scope.sh` 管理。
|
||
|
||
## Use this when
|
||
|
||
- 先執行 `meta/tools/sync-domains.sh`,同步 marketplace 上的 domain。
|
||
- 再執行 `meta/tools/list-skills.sh`,確認技能清單。
|
||
- 執行本工具,產出基礎指引。
|
||
- 若新增或修改技能,執行 `meta/tools/sync-skill-manifest.sh {domain-path}`。
|
||
- 執行 `meta/tools/ste100-lint.sh {domain-path}`。
|
||
- 依 `jsc-git:pr` 開立 Push Request。
|
||
EOF
|