feat(pkg): 匯入 jsc-pkg 技能組
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
---
|
||||
name: pkg-update
|
||||
description: Update every external package of a project to its latest stable version using list-packages.sh and latest-version.sh, then run build and tests. Revert all changes on failure. Supports nodejs, python, and dotnet projects. Use for dependency refresh; not for adding or removing packages.
|
||||
---
|
||||
|
||||
# pkg-update — 套件批次更新
|
||||
|
||||
## 步驟
|
||||
|
||||
1. `tools/list-packages.sh {專案目錄}` 取得所有外部套件(ecosystem / name / current)。
|
||||
2. 確認工作樹乾淨:有未認可變更就先停止並回報(避免還原時誤傷)。
|
||||
3. 逐 ecosystem 更新,此步驟**必須以 sub agent 執行**(每個 ecosystem 一個 sub agent):
|
||||
1. 對每個套件 `tools/latest-version.sh {ecosystem} {name}` 查最新穩定版。
|
||||
2. 改寫版本來源檔(package.json / requirements.txt / pyproject.toml / *.csproj)。
|
||||
3. 重新解析安裝(`npm install` / `pip install -r` / `dotnet restore`)。
|
||||
4. 執行建置與測試:
|
||||
- nodejs:`npm run build`(如有)+ `npm test`(如有)。
|
||||
- python:`pytest`(如有測試)。
|
||||
- dotnet:`dotnet build` + `dotnet test`。
|
||||
- 推斷不出指令時依 `jsc-ask:ask` 規則詢問使用者。
|
||||
5. 建置或測試失敗 → 還原全部變更(`git checkout -- .` 與清除未追蹤的 lock 變更),回報失敗套件與錯誤摘要。
|
||||
6. 成功 → 回報更新清單(套件 / 舊版 / 新版),交由 `jsc-git:commit` 認可。
|
||||
Executable
+29
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env sh
|
||||
# latest-version.sh — 查詢套件最新且穩定的版本號。
|
||||
# 用法: latest-version.sh <ecosystem> <name>
|
||||
# ecosystem: nodejs | python | dotnet
|
||||
# 輸出: 版本號一行;查不到 exit 4
|
||||
set -u
|
||||
eco="${1:?ecosystem required (nodejs|python|dotnet)}"
|
||||
name="${2:?package name required}"
|
||||
|
||||
case "$eco" in
|
||||
nodejs)
|
||||
v=$(curl -sSf "https://registry.npmjs.org/$name/latest" 2>/dev/null \
|
||||
| python3 2>/dev/null -c 'import json,sys;print(json.load(sys.stdin).get("version",""))') ;;
|
||||
python)
|
||||
v=$(curl -sSf "https://pypi.org/pypi/$name/json" 2>/dev/null \
|
||||
| python3 2>/dev/null -c 'import json,sys;print(json.load(sys.stdin)["info"]["version"])') ;;
|
||||
dotnet)
|
||||
lname=$(printf '%s' "$name" | tr '[:upper:]' '[:lower:]')
|
||||
v=$(curl -sSf "https://api.nuget.org/v3-flatcontainer/$lname/index.json" 2>/dev/null \
|
||||
| python3 2>/dev/null -c '
|
||||
import json,sys,re
|
||||
vs=json.load(sys.stdin).get("versions",[])
|
||||
stable=[x for x in vs if re.match(r"^[0-9]+(\.[0-9]+)*$",x)]
|
||||
print((stable or vs)[-1] if (stable or vs) else "")') ;;
|
||||
*) echo "unknown ecosystem: $eco" >&2; exit 2 ;;
|
||||
esac
|
||||
|
||||
[ -n "${v:-}" ] || { echo "not found: $eco/$name" >&2; exit 4; }
|
||||
printf '%s\n' "$v"
|
||||
Executable
+59
@@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env sh
|
||||
# list-packages.sh — 列出專案的所有外部套件與目前版本。
|
||||
# 用法: list-packages.sh [專案目錄](預設目前目錄)
|
||||
# 輸出(TSV): ecosystem<TAB>name<TAB>current
|
||||
# 支援: nodejs(package.json)、python(requirements.txt / pyproject.toml)、dotnet(*.csproj)
|
||||
set -u
|
||||
DIR="${1:-.}"
|
||||
|
||||
# nodejs: package.json 的 dependencies / devDependencies
|
||||
if [ -f "$DIR/package.json" ]; then
|
||||
python3 - "$DIR/package.json" <<'EOF'
|
||||
import json,sys
|
||||
d=json.load(open(sys.argv[1],encoding="utf-8"))
|
||||
for k in ("dependencies","devDependencies"):
|
||||
for name,ver in (d.get(k) or {}).items():
|
||||
print(f"nodejs\t{name}\t{ver}")
|
||||
EOF
|
||||
fi
|
||||
|
||||
# python: requirements.txt
|
||||
if [ -f "$DIR/requirements.txt" ]; then
|
||||
python3 - "$DIR/requirements.txt" <<'EOF'
|
||||
import re,sys
|
||||
for line in open(sys.argv[1],encoding="utf-8"):
|
||||
line=line.split("#")[0].strip()
|
||||
if not line or line.startswith("-"): continue
|
||||
m=re.match(r"([A-Za-z0-9_.\-\[\]]+)\s*(?:(?:==|>=|<=|~=|!=|>|<)\s*([^,;\s]+))?",line)
|
||||
if m: print(f"python\t{m.group(1)}\t{m.group(2) or ''}")
|
||||
EOF
|
||||
fi
|
||||
|
||||
# python: pyproject.toml 的 [project] dependencies
|
||||
if [ -f "$DIR/pyproject.toml" ]; then
|
||||
python3 - "$DIR/pyproject.toml" <<'EOF'
|
||||
import re,sys
|
||||
try:
|
||||
import tomllib
|
||||
d=tomllib.load(open(sys.argv[1],"rb"))
|
||||
except Exception:
|
||||
sys.exit(0)
|
||||
deps=(d.get("project") or {}).get("dependencies") or []
|
||||
for dep in deps:
|
||||
m=re.match(r"([A-Za-z0-9_.\-\[\]]+)\s*(?:(?:==|>=|<=|~=|!=|>|<)\s*([^,;\s]+))?",dep)
|
||||
if m: print(f"python\t{m.group(1)}\t{m.group(2) or ''}")
|
||||
EOF
|
||||
fi
|
||||
|
||||
# dotnet: *.csproj 的 PackageReference
|
||||
find "$DIR" -maxdepth 3 -name '*.csproj' 2>/dev/null | while IFS= read -r proj; do
|
||||
python3 - "$proj" <<'EOF'
|
||||
import re,sys
|
||||
text=open(sys.argv[1],encoding="utf-8").read()
|
||||
for tag in re.findall(r"<PackageReference\b[^>]*>",text):
|
||||
inc=re.search(r'Include="([^"]+)"',tag)
|
||||
ver=re.search(r'Version="([^"]+)"',tag)
|
||||
if inc: print(f"dotnet\t{inc.group(1)}\t{ver.group(1) if ver else ''}")
|
||||
EOF
|
||||
done
|
||||
exit 0
|
||||
Reference in New Issue
Block a user