Files
cli/tools/check-requires.sh
T

120 lines
3.9 KiB
Bash
Executable File
Raw 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
# check-requires.sh — Check jsc.requires before updating one plugin.
set -u
usage() {
echo "用法:check-requires.sh {claude|codex|copilot|antigravity|kiro} {manifest}" >&2
exit 2
}
[ "$#" -eq 2 ] || usage
CLI=$1
MANIFEST=$2
case "$CLI" in
claude|codex|copilot|antigravity|kiro) ;;
*) usage ;;
esac
[ -f "$MANIFEST" ] || {
printf 'status=blocked reason=找不到 manifest:%s\n' "$MANIFEST"
exit 1
}
JSC_HOME_DIR="${JSC_HOME:-$HOME/.jsc}"
LOCAL_DIR="${JSC_LOCAL_PLUGINS:-$JSC_HOME_DIR/plugins}"
KIRO_SKILLS="${JSC_KIRO_SKILLS:-$HOME/.kiro/skills}"
python3 - "$CLI" "$MANIFEST" "$LOCAL_DIR" "$KIRO_SKILLS" <<'PY'
import glob
import json
import os
import re
import sys
cli, manifest, local_dir, kiro_skills = sys.argv[1:5]
try:
with open(manifest, encoding="utf-8") as fh:
data = json.load(fh)
except Exception as exc:
print(f"status=blocked reason=manifest 不是有效 JSON:{manifest}:{exc}")
sys.exit(1)
requires = ((data.get("jsc") or {}).get("requires") or {})
if not requires:
print("status=ok reason=沒有宣告相依版本")
sys.exit(0)
def version_tuple(value):
value = str(value or "").strip()
parts = value.split(".")
out = []
for part in parts[:3]:
match = re.match(r"^(\d+)", part)
out.append(int(match.group(1)) if match else 0)
while len(out) < 3:
out.append(0)
return tuple(out)
def current_version(plugin):
domain = plugin[4:] if plugin.startswith("jsc-") else plugin
candidates = []
patterns = []
if cli == "claude":
registry = os.path.expanduser("~/.claude/plugins/installed_plugins.json")
try:
with open(registry, encoding="utf-8") as fh:
entries = (json.load(fh).get("plugins") or {}).get(f"jsc-{domain}@jsc") or []
for entry in entries:
path = os.path.join(entry.get("installPath") or "", "plugin.json")
with open(path, encoding="utf-8") as fh:
version = json.load(fh).get("version", "")
if version:
return version, path
except Exception:
pass
patterns.append(os.path.expanduser(f"~/.claude/plugins/cache/jsc/jsc-{domain}/*/plugin.json"))
elif cli == "codex":
patterns.append(os.path.expanduser(f"~/.codex/plugins/cache/jsc/jsc-{domain}/*/plugin.json"))
elif cli == "copilot":
patterns.append(os.path.expanduser(f"~/.copilot/installed-plugins/jsc/jsc-{domain}/plugin.json"))
elif cli == "antigravity":
patterns.append(os.path.join(local_dir, domain, "plugin.json"))
patterns.append(os.path.expanduser(f"~/.antigravity/plugins/jsc-{domain}/plugin.json"))
elif cli == "kiro":
patterns.append(os.path.join(kiro_skills, f"jsc-{domain}", "plugin.json"))
for pattern in patterns:
for path in glob.glob(pattern):
try:
with open(path, encoding="utf-8") as fh:
version = json.load(fh).get("version", "")
except Exception:
continue
if version:
candidates.append((version_tuple(version), version, path))
if not candidates:
return "", ""
candidates.sort()
return candidates[-1][1], candidates[-1][2]
failures = []
for plugin, constraint in sorted(requires.items()):
required = str(constraint).strip()
minimum = required[2:].strip() if required.startswith(">=") else required
current, path = current_version(plugin)
if not current:
failures.append(f"{plugin} 需要 {required},目前未安裝")
continue
if version_tuple(current) < version_tuple(minimum):
failures.append(f"{plugin} 需要 {required},目前 {current}({path})")
if failures:
print("status=blocked reason=" + ";".join(failures))
sys.exit(1)
print("status=ok reason=相依版本符合:" + ", ".join(f"{k} {v}" for k, v in sorted(requires.items())))
sys.exit(0)
PY