feat: consolidate marketplace skills into kyberforge plugin
Moves create-plugin, marketplace-architect, write-skill, and write-eval from canonical .agents/skills/ into plugins/kyberforge/skills/, along with all bundled sub-files, evals, and the plugin-marketplace-architecture research doc. Bundles templates/plugin/ into create-plugin/assets/plugin-template/ so the skill is self-contained after install-time caching. Removes templates/plugin/ and docs/research/plugin-marketplace-architecture.md from the repo root as they are now exclusively in the plugin. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
194
plugins/kyberforge/tests/test_scripts.sh
Executable file
194
plugins/kyberforge/tests/test_scripts.sh
Executable file
@@ -0,0 +1,194 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPTS_DIR="$(cd "$(dirname "$0")/../scripts" && pwd)"
|
||||
PASS=0; FAIL=0
|
||||
# Use += to avoid ((var++)) returning 0 exit code when var was 0 under set -e
|
||||
|
||||
# ── helpers ─────────────────────────────────────────────────────────────────
|
||||
|
||||
tmpdir() { mktemp -d; }
|
||||
|
||||
assert_contains() {
|
||||
local label="$1" expected="$2" actual="$3"
|
||||
if echo "$actual" | grep -qF "$expected"; then
|
||||
echo " PASS: $label"
|
||||
PASS=$((PASS+1))
|
||||
else
|
||||
echo " FAIL: $label"
|
||||
echo " expected to contain: $expected"
|
||||
echo " got: $(echo "$actual" | head -5)"
|
||||
FAIL=$((FAIL+1))
|
||||
fi
|
||||
}
|
||||
|
||||
assert_not_contains() {
|
||||
local label="$1" unexpected="$2" actual="$3"
|
||||
if echo "$actual" | grep -qF "$unexpected"; then
|
||||
echo " FAIL: $label"
|
||||
echo " expected NOT to contain: $unexpected"
|
||||
FAIL=$((FAIL+1))
|
||||
else
|
||||
echo " PASS: $label"
|
||||
PASS=$((PASS+1))
|
||||
fi
|
||||
}
|
||||
|
||||
assert_exit() {
|
||||
local label="$1" expected="$2" actual="$3"
|
||||
if [[ "$actual" -eq "$expected" ]]; then
|
||||
echo " PASS: $label"
|
||||
PASS=$((PASS+1))
|
||||
else
|
||||
echo " FAIL: $label"
|
||||
echo " expected exit $expected, got $actual"
|
||||
FAIL=$((FAIL+1))
|
||||
fi
|
||||
}
|
||||
|
||||
assert_file_exists() {
|
||||
local label="$1" path="$2"
|
||||
if [[ -f "$path" ]]; then
|
||||
echo " PASS: $label"
|
||||
PASS=$((PASS+1))
|
||||
else
|
||||
echo " FAIL: $label"
|
||||
echo " file not found: $path"
|
||||
FAIL=$((FAIL+1))
|
||||
fi
|
||||
}
|
||||
|
||||
assert_file_absent() {
|
||||
local label="$1" path="$2"
|
||||
if [[ ! -e "$path" ]]; then
|
||||
echo " PASS: $label"
|
||||
PASS=$((PASS+1))
|
||||
else
|
||||
echo " FAIL: $label"
|
||||
echo " file should not exist: $path"
|
||||
FAIL=$((FAIL+1))
|
||||
fi
|
||||
}
|
||||
|
||||
# ── inventory.sh tests ───────────────────────────────────────────────────────
|
||||
|
||||
echo "=== inventory.sh ==="
|
||||
|
||||
# 1. SKILL.md classified as skill
|
||||
t=$(tmpdir)
|
||||
mkdir -p "$t/skills/my-skill"
|
||||
echo "---" > "$t/skills/my-skill/SKILL.md"
|
||||
out=$("$SCRIPTS_DIR/inventory.sh" "$t")
|
||||
assert_contains "SKILL.md classified as skill" "skill" "$out"
|
||||
rm -rf "$t"
|
||||
|
||||
# 2. agents/foo.agent.md classified as agent-copilot
|
||||
t=$(tmpdir)
|
||||
mkdir -p "$t/agents"
|
||||
touch "$t/agents/my-agent.agent.md"
|
||||
out=$("$SCRIPTS_DIR/inventory.sh" "$t")
|
||||
assert_contains "agents/*.agent.md classified as agent-copilot" "agent-copilot" "$out"
|
||||
rm -rf "$t"
|
||||
|
||||
# 3. ../ in file content produces cross-reference warning
|
||||
t=$(tmpdir)
|
||||
mkdir -p "$t/skills/my-skill"
|
||||
printf -- '---\ndescription: test\n---\nSee ../shared/file.md\n' > "$t/skills/my-skill/SKILL.md"
|
||||
out=$("$SCRIPTS_DIR/inventory.sh" "$t")
|
||||
assert_contains "../ cross-reference warning emitted" "Cross-reference" "$out"
|
||||
assert_contains "../ path shown in warning" "../shared/file.md" "$out"
|
||||
rm -rf "$t"
|
||||
|
||||
# ── gen_manifests.sh tests ───────────────────────────────────────────────────
|
||||
|
||||
echo ""
|
||||
echo "=== gen_manifests.sh ==="
|
||||
|
||||
# 4. Without --write, no files are created
|
||||
t=$(tmpdir)
|
||||
mkdir -p "$t/plugins/my-plugin/skills/hello"
|
||||
echo "---" > "$t/plugins/my-plugin/skills/hello/SKILL.md"
|
||||
"$SCRIPTS_DIR/gen_manifests.sh" "$t" --marketplace-name my-marketplace >/dev/null
|
||||
assert_file_absent "dry run: .claude-plugin/marketplace.json not written" "$t/.claude-plugin/marketplace.json"
|
||||
assert_file_absent "dry run: plugin.json not written" "$t/plugins/my-plugin/plugin.json"
|
||||
rm -rf "$t"
|
||||
|
||||
# 5. With --write, creates plugin.json in both locations
|
||||
t=$(tmpdir)
|
||||
mkdir -p "$t/plugins/my-plugin/skills/hello"
|
||||
echo "---" > "$t/plugins/my-plugin/skills/hello/SKILL.md"
|
||||
"$SCRIPTS_DIR/gen_manifests.sh" "$t" --marketplace-name my-marketplace --write >/dev/null
|
||||
assert_file_exists "--write: plugin root plugin.json created" "$t/plugins/my-plugin/plugin.json"
|
||||
assert_file_exists "--write: .claude-plugin/plugin.json created" "$t/plugins/my-plugin/.claude-plugin/plugin.json"
|
||||
rm -rf "$t"
|
||||
|
||||
# 6. Reserved name exits 1
|
||||
t=$(tmpdir)
|
||||
mkdir -p "$t/plugins/my-plugin"
|
||||
set +e
|
||||
out=$("$SCRIPTS_DIR/gen_manifests.sh" "$t" --marketplace-name claude-plugins-official 2>&1)
|
||||
code=$?
|
||||
set -e
|
||||
assert_exit "reserved name: exit 1" 1 "$code"
|
||||
assert_contains "reserved name: error message" "reserved" "$out"
|
||||
rm -rf "$t"
|
||||
|
||||
# ── validate.sh tests ────────────────────────────────────────────────────────
|
||||
|
||||
echo ""
|
||||
echo "=== validate.sh ==="
|
||||
|
||||
# 7. Invalid JSON exits 1
|
||||
t=$(tmpdir)
|
||||
mkdir -p "$t/.claude-plugin"
|
||||
echo "not json" > "$t/.claude-plugin/marketplace.json"
|
||||
set +e
|
||||
out=$("$SCRIPTS_DIR/validate.sh" "$t" 2>&1)
|
||||
code=$?
|
||||
set -e
|
||||
assert_exit "invalid JSON: exit 1" 1 "$code"
|
||||
assert_contains "invalid JSON: error message" "ERROR" "$out"
|
||||
rm -rf "$t"
|
||||
|
||||
# 8. Reserved marketplace name exits 1
|
||||
t=$(tmpdir)
|
||||
mkdir -p "$t/.claude-plugin"
|
||||
printf '{"name":"claude-plugins-official","plugins":[]}\n' > "$t/.claude-plugin/marketplace.json"
|
||||
set +e
|
||||
out=$("$SCRIPTS_DIR/validate.sh" "$t" 2>&1)
|
||||
code=$?
|
||||
set -e
|
||||
assert_exit "reserved marketplace name: exit 1" 1 "$code"
|
||||
assert_contains "reserved marketplace name: error message" "reserved" "$out"
|
||||
rm -rf "$t"
|
||||
|
||||
# 9. ../ in plugin file exits 1
|
||||
t=$(tmpdir)
|
||||
mkdir -p "$t/.claude-plugin" "$t/plugins/my-plugin/skills/hello"
|
||||
printf '{"name":"my-marketplace","plugins":[{"name":"my-plugin","source":"./plugins/my-plugin"}]}\n' \
|
||||
> "$t/.claude-plugin/marketplace.json"
|
||||
printf -- '---\ndescription: test\n---\nSee ../shared.md\n' \
|
||||
> "$t/plugins/my-plugin/skills/hello/SKILL.md"
|
||||
set +e
|
||||
out=$("$SCRIPTS_DIR/validate.sh" "$t" 2>&1)
|
||||
code=$?
|
||||
set -e
|
||||
assert_exit "..// in plugin: exit 1" 1 "$code"
|
||||
assert_contains "..// in plugin: error message" "../" "$out"
|
||||
rm -rf "$t"
|
||||
|
||||
# 10. No marketplace.json warns but exits 0
|
||||
t=$(tmpdir)
|
||||
set +e
|
||||
out=$("$SCRIPTS_DIR/validate.sh" "$t" 2>&1)
|
||||
code=$?
|
||||
set -e
|
||||
assert_exit "no marketplace.json: exit 0" 0 "$code"
|
||||
assert_contains "no marketplace.json: warning emitted" "WARN" "$out"
|
||||
rm -rf "$t"
|
||||
|
||||
# ── summary ──────────────────────────────────────────────────────────────────
|
||||
|
||||
echo ""
|
||||
echo "Results: $PASS passed, $FAIL failed"
|
||||
[[ $FAIL -eq 0 ]]
|
||||
Reference in New Issue
Block a user