chore(release): 放行技能組稽核修正到預設分支 #46

Merged
admin merged 5 commits from develop into master 2026-08-31 03:56:30 +00:00
9 changed files with 159 additions and 27 deletions
Showing only changes of commit 7dc5c32de3 - Show all commits
+8 -5
View File
@@ -19,12 +19,15 @@
# 技能組以外的檔案。domain 清單取自 marketplace.json,不寫死。
# 每個 domain 先找 {root}/{domain},再找 {root}/jsc-{domain};兩者都沒有就略過。
# 每個存取庫內排除 .git 目錄。
# 根目錄預設取本腳本位置的上兩層(meta/tools -> meta -> 根),換機器不必改腳本;
# 用 JSC_PLUGINS_ROOT 覆寫,指向別處的技能組工作目錄。
# 根目錄交給 tools/plugins-root.sh 推導(JSC_PLUGINS_ROOT -> 從 $PWD 往上找 ->
# 腳本位置上兩層 -> $HOME/plugins)。以 plugin 形式安裝時,「腳本位置上兩層」會落在
# plugin 快取目錄,單靠它一定推錯,所以推導規則抽成共用腳本。
# 輸出: 命中檔案清單(去重、排序),一行一個路徑(stdout);掃描摘要走 stderr。
# 結束碼: 0=有命中 1=掃完但零命中 2=用法錯誤
# 3=找不到根目錄、讀不到 domain 清單、本機一個 domain 存取庫都沒有,或掃描失敗
# 3=推導不出根目錄、讀不到 domain 清單、本機一個 domain 存取庫都沒有、
# 建不了暫存檔,或掃描失敗
# 零命中與掃描失敗必須分開:拿掃描失敗當「沒有引用」會讓刪除技能少改檔案。
# 環境變數: JSC_PLUGINS_ROOT(根目錄,見 plugins-root.sh)
set -u
usage() {
@@ -38,8 +41,8 @@ SKILL=$2
[ -n "$DOMAIN" ] && [ -n "$SKILL" ] || usage
HERE=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
ROOT="${JSC_PLUGINS_ROOT:-$(CDPATH= cd -- "$HERE/../.." && pwd)}"
[ -d "$ROOT" ] || { echo "找不到 plugins 根目錄:$ROOT(可用 JSC_PLUGINS_ROOT 指定)" >&2; exit 3; }
. "$HERE/plugins-root.sh"
ROOT=$(jsc_plugins_root) || exit 3
# 正本 domain 清單:優先讀本機任一份 marketplace 副本(每個 repo 都帶同一份)。
mkt=""
+14 -4
View File
@@ -3,15 +3,25 @@
#
# 用法: inventory-tooling.sh [root]
#
# root: 預設取本腳本位置的上兩層(meta/tools -> meta -> 根)。
# 也可用參數或 JSC_PLUGINS_ROOT 覆寫。
# root: 給了參數就用參數。沒給就交給 tools/plugins-root.sh 推導
# (JSC_PLUGINS_ROOT -> 從 $PWD 往上找 -> 腳本位置上兩層 -> $HOME/plugins)。
# 以 plugin 形式安裝時,「腳本位置上兩層」會落在 plugin 快取目錄,單靠它一定推錯,
# 所以推導規則抽成共用腳本。
#
# 輸出: Markdown。內容包含 domain、manifest、技能、工具、hooks 與管理入口。
# 結束碼: 0=成功 1=根目錄、marketplace 或必要工具缺失
# 同一趟已經跑過 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)
ROOT=${1:-${JSC_PLUGINS_ROOT:-$(CDPATH= cd -- "$HERE/../.." && 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; }
+7 -5
View File
@@ -10,17 +10,19 @@
# 誤把它們當成技能組的一部分。domain 清單取自 marketplace.json,不寫死。
# 清單只反映本機檔案;要確保檔案齊全請先跑 sync-domains.sh。
#
# 根目錄: 預設取本腳本位置的上兩層(meta/tools -> meta -> 根)。
# 用 JSC_PLUGINS_ROOT 覆寫,換機器不必改腳本。
# 根目錄: 交給 tools/plugins-root.sh 推導(JSC_PLUGINS_ROOT -> 從 $PWD 往上找 ->
# 腳本位置上兩層 -> $HOME/plugins)。以 plugin 形式安裝時,「腳本位置上兩層」會落在
# plugin 快取目錄,單靠它一定推錯,所以推導規則抽成共用腳本。
#
# 輸出: 一行一個技能,格式 {domain}<TAB>{name}<TAB>{description},依 domain、name 排序。
# 結束碼: 0=至少列出一個技能 1=找不到根目錄、讀不到 domain 清單,或一個技能都沒有
# 結束碼: 0=至少列出一個技能
# 1=推導不出根目錄、讀不到 domain 清單,或一個技能都沒有
set -u
HERE=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
ROOT="${JSC_PLUGINS_ROOT:-$(CDPATH= cd -- "$HERE/../.." && pwd)}"
. "$HERE/plugins-root.sh"
[ -d "$ROOT" ] || { echo "找不到 plugins 根目錄:$ROOT(可用 JSC_PLUGINS_ROOT 指定)" >&2; exit 1; }
ROOT=$(jsc_plugins_root) || exit 1
# 正本 domain 清單:優先讀本機任一份 marketplace 副本(每個 repo 都帶同一份)。
mkt=""
+95
View File
@@ -0,0 +1,95 @@
#!/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
+3 -1
View File
@@ -8,7 +8,9 @@
# 4. 簡體字(只收沒有繁體正當用法的字,避免誤報)
# 5. 中文並列項用斜線(半形 / 或全形 / 夾在中日韓字元之間),應改頓號「、」
# 6. 亂碼(U+FFFD 替代字元、Latin-1 雙重編碼殘留)
# 輸出: {檔案}:{行號}:{類別}:{命中內容};全部通過 exit 0,有命中 exit 1。
# 輸出: {檔案}:{行號}:{類別}:{命中內容}(stdout);用法錯誤走 stderr。
# 結束碼: 0=掃過的檔案全部通過 1=有命中 2=沒給檢查對象(空跑會回 0,看起來像通過,所以擋掉)
# 環境變數: JSC_SIMPLIFIED_FILE(簡體字表路徑,優先於自動搜尋)
# 掃描範圍與分流:
# 文件檔(.md、.json)跑全部六項。
# 程式碼檔(.sh .js .ts .py .cs .java .go .rb .php .sql .yml .yaml .toml)只跑簡體字與亂碼。
+6 -5
View File
@@ -10,13 +10,14 @@
# 3. 本機已有的 domain:git pull。工作區有未提交變更就跳過 pull,只在 stderr 提醒——
# 正在改的 repo 不該被自動 pull 覆蓋。
#
# 根目錄: 預設取本腳本位置的上兩層(meta/tools -> meta -> 根)。
# 用 JSC_PLUGINS_ROOT 覆寫,換機器不必改腳本。
# 根目錄: 交給 tools/plugins-root.sh 推導(JSC_PLUGINS_ROOT -> 從 $PWD 往上找 ->
# 腳本位置上兩層 -> $HOME/plugins)。以 plugin 形式安裝時,「腳本位置上兩層」會落在
# plugin 快取目錄,單靠它一定推錯,所以推導規則抽成共用腳本。
# 存取庫目錄名: 先找 {root}/{domain},再找 {root}/jsc-{domain};都沒有才 clone 成 {root}/{domain}。
#
# 輸出: 一行一個 domain,格式 {domain}<TAB>{path}(stdout);警告與失敗說明走 stderr。
# 結束碼: 0=正本讀到、每個 domain 都在本機,而且每個既有存取庫都更新到最新
# 1=讀不到正本 marketplace 或找不到 gitea.sh(不輸出任何 domain)
# 1=推導不出根目錄、讀不到正本 marketplace,或找不到 gitea.sh(不輸出任何 domain)
# 2=正本讀到,但有 domain 沒能取得或 clone 失敗(已輸出其餘 domain)
# 3=每個 domain 都在本機,但有存取庫沒更新到最新:工作區髒而跳過 pull,
# 或 pull 失敗。stderr 會逐一列出這些路徑。**exit 0 才代表「全部最新」**;
@@ -28,10 +29,10 @@
set -u
HERE=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
ROOT="${JSC_PLUGINS_ROOT:-$(CDPATH= cd -- "$HERE/../.." && pwd)}"
. "$HERE/plugins-root.sh"
DRY="${JSC_SYNC_DRY_RUN:-}"
[ -d "$ROOT" ] || { echo "找不到 plugins 根目錄:$ROOT(可用 JSC_PLUGINS_ROOT 指定)" >&2; exit 1; }
ROOT=$(jsc_plugins_root) || exit 1
GITEA=""
for g in "$ROOT/gitea/tools/gitea.sh" "$ROOT/jsc-gitea/tools/gitea.sh"; do
+8 -4
View File
@@ -18,14 +18,17 @@
# python3 不在 PATH 時:腳本不寫任何檔案,印出缺少 python3 的訊息,回 1。
# 呼叫端要先裝 python3 再重跑,不可改用 sed 手動改 marketplace。
#
# 根目錄: 預設取本腳本位置的上兩層(meta/tools -> meta -> 根)。
# 用 JSC_PLUGINS_ROOT 覆寫,換機器不必改腳本。
# 根目錄: 交給 tools/plugins-root.sh 推導(JSC_PLUGINS_ROOT -> 從 $PWD 往上找 ->
# 腳本位置上兩層 -> $HOME/plugins)。以 plugin 形式安裝時,「腳本位置上兩層」會落在
# plugin 快取目錄,單靠它一定推錯,所以推導規則抽成共用腳本。
# 存取庫目錄名: 先找 {root}/{domain},再找 {root}/jsc-{domain}。
#
# 輸出: 一行一個實際寫入的檔案路徑(stdout);略過與失敗說明走 stderr。
# 結束碼: 0=全部寫入且逐檔一致 2=用法錯誤
# 1=缺 python3、正本讀寫失敗,或有檔案比對不一致
# 1=推導不出根目錄、缺 python3、正本讀寫失敗、建不了暫存目錄,
# 或有檔案比對不一致
# 3=寫入成功,但有 domain 存取庫不在本機(先跑 sync-domains.sh 再重跑)
# 環境變數: JSC_PLUGINS_ROOT(根目錄,見 plugins-root.sh)
set -u
usage() {
@@ -41,7 +44,8 @@ DESC=$3
HERE=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
META=$(CDPATH= cd -- "$HERE/.." && pwd)
ROOT="${JSC_PLUGINS_ROOT:-$(CDPATH= cd -- "$HERE/../.." && pwd)}"
. "$HERE/plugins-root.sh"
ROOT=$(jsc_plugins_root) || exit 1
REL_CLAUDE='.claude-plugin/marketplace.json'
REL_AGENTS='.agents/plugins/marketplace.json'
+8 -1
View File
@@ -13,7 +13,14 @@
# .codex-plugin/plugin.json,version 一律 bump 成同一個新值(以第一份找到的 manifest 版本為準,
# 右側數字加一,滿 9 就往左進位;major 不設上限,minor 與 patch 都不超過 9)。
#
# 輸出: 變更摘要——README 新增/移除的技能小節、各 manifest 的舊版本 -> 新版本。
# 輸出: 變更摘要——README 新增或移除的技能小節、各 manifest 的舊版本 -> 新版本(stdout);
# 失敗說明走 stderr。
# 結束碼: 0=README 區塊與三份 manifest 都已同步
# 1=domain 路徑不存在、缺 skills/、缺 README.md、README 缺 JSC-SKILLS 標記、
# 掃不到任何 SKILL.md、找不到 plugin manifest,或 manifest 讀不到 version 欄位
# 2=用法錯誤(本腳本只吃一個參數)
# 本腳本是 set -e:上列以外的指令失敗會直接中止,結束碼由該指令決定,
# 呼叫端把「不是 0、1、2」一律當執行環境故障處理,不得視為同步成功。
set -eu
usage() {
+10 -2
View File
@@ -14,9 +14,16 @@
# 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=沒偵測到任何 CLI 或找不到可檢查的位置
# 結束碼: 0=沒有殘留 1=有殘留 2=用法錯誤
# 3=推導不出根目錄、找不到 detect-clis.sh、沒偵測到任何 CLI,
# 或找不到可檢查的位置(**不等於乾淨**)
# 環境變數: JSC_PLUGINS_ROOT(根目錄,見 plugins-root.sh)
set -u
usage() {
@@ -30,7 +37,8 @@ SKILL=$2
[ -n "$DOMAIN" ] && [ -n "$SKILL" ] || usage
HERE=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
ROOT="${JSC_PLUGINS_ROOT:-$(CDPATH= cd -- "$HERE/../.." && 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