mirror of
https://github.com/boshu2/agentops.git
synced 2026-09-14 15:08:13 +08:00
092b99dad9
## What
Adds `scripts/skill-eval.sh` — a thin gate that runs one skill's
`SKILL.md` through Jeff Emanuel's `ms` (meta_skill) `lint` + `validate`.
The wrapper decides the gate purely on whether a **blocking** `rule_id`
appears (ms's own severity/exit is not trusted):
- Blocking: `no-secrets`, `no-injection`, `safe-paths`,
`required-metadata`, `no-cycle`, `valid-version` → non-zero exit.
- Everything else → annotated only (`::warning::`), never fails.
- `ms` not on PATH (or `MS_BIN` missing) → **loud `::error::` hard-fail
(exit 3)**, never skip-and-pass — a silent skip would recreate the
no-evaluation gap this gate closes.
Planted `skills/_fixtures/{bad,good}-skill/SKILL.md` fixtures +
`tests/scripts/skill-eval.bats` (10 tests) exercise the
bad/good/ms-absent contracts.
## Fixture scoping
`skills/_fixtures/` is non-skill scaffolding (planted fixtures). The
skill-enumerating gates/generators are taught to skip `skills/_*` so the
fixtures never inflate the skill count (stays 82) or fail registry /
schema / wiring / runtime / count gates. Touched enumerators:
`generate-registry`, `validate-skill-schema`, `sync-skill-counts`,
`validate-skill-count`, `generate-skill-catalog`,
`generate-context-map`, `validate-manifests`, `check-wiring-closure`,
`validate-headless-runtime-skills`, `lib/sku_catalog.py`,
`check-alias-collisions`, `run-all`, `test-runtime-opencode-smoke`,
`release-smoke-test`, `smoke-test`, `validate-skill`.
Does **not** touch `validate.yml` — wiring skill-eval.sh into CI is a
separate bead.
Epic: ag-czzf
## Verification
- `bats tests/scripts/skill-eval.bats` → 10/10 pass (ms 0.1.2 on PATH)
- `shellcheck scripts/skill-eval.sh` → clean
- `check-registry-drift`, `validate-skill-schema`, `sync-skill-counts`,
`run-all`, opencode-smoke → all PASS with fixtures present, skill count
= 82 (fixtures excluded)
Closes-scenario: ag-yzoz#skill-eval
Bounded-context: BC2-Validation
Evidence: scripts/skill-eval.sh
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
127 lines
4.6 KiB
Bash
Executable File
127 lines
4.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Release smoke test - verify all skills are loadable
|
|
# Usage: ./tests/release-smoke-test.sh [--full]
|
|
#
|
|
# Default: Fast verification (~30s) - checks components are registered
|
|
# --full: Slow verification (~10min) - invokes each skill individually
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
|
|
source "$SCRIPT_DIR/claude-code/test-helpers.sh"
|
|
|
|
# Logging (redefine to avoid conflict with macOS log command)
|
|
log() { echo -e "${BLUE}[TEST]${NC} $1"; }
|
|
pass() { echo -e "${GREEN} ✓${NC} $1"; }
|
|
fail() { echo -e "${RED} ✗${NC} $1"; }
|
|
|
|
# Expected counts — computed dynamically from skill directories
|
|
EXPECTED_SKILLS=$(find "$REPO_ROOT/skills" -maxdepth 2 -name SKILL.md -type f | wc -l | tr -d ' ')
|
|
|
|
# Parse args
|
|
FULL_TEST=false
|
|
[[ "${1:-}" == "--full" ]] && FULL_TEST=true
|
|
[[ "${1:-}" == "--help" ]] && { echo "Usage: $0 [--full]"; echo " --full Run slow individual tests (~10min)"; exit 0; }
|
|
|
|
echo ""
|
|
echo "═══════════════════════════════════════════"
|
|
echo " AgentOps Release Smoke Test"
|
|
echo "═══════════════════════════════════════════"
|
|
echo ""
|
|
|
|
if $FULL_TEST; then
|
|
# =========================================================================
|
|
# FULL TEST: Individual invocation of each skill
|
|
# =========================================================================
|
|
log "Running FULL test (individual invocations)..."
|
|
|
|
# Build skills array dynamically from skill directories
|
|
SKILLS=()
|
|
for skill_dir in "$REPO_ROOT"/skills/*/; do
|
|
# Skip leading-underscore scaffolding (e.g. skills/_fixtures/) — planted
|
|
# test fixtures, not invokable skills.
|
|
case "$(basename "$skill_dir")" in _*) continue ;; esac
|
|
[[ -f "${skill_dir}SKILL.md" ]] && SKILLS+=("$(basename "$skill_dir")")
|
|
done
|
|
|
|
passed=0
|
|
failed=0
|
|
|
|
for skill in "${SKILLS[@]}"; do
|
|
# Skills need unrestricted tool access — they may use Write, Edit,
|
|
# WebFetch, etc. internally. --dangerously-skip-permissions is correct
|
|
# here; scoped --allowedTools would cause false failures.
|
|
if timeout 45 claude -p "Invoke agentops:$skill skill" \
|
|
--plugin-dir "$REPO_ROOT" \
|
|
--dangerously-skip-permissions \
|
|
--max-turns 3 \
|
|
--no-session-persistence \
|
|
--max-budget-usd 0.50 \
|
|
>/dev/null 2>&1; then
|
|
pass "$skill"
|
|
((passed++))
|
|
else
|
|
fail "$skill"
|
|
((failed++))
|
|
fi
|
|
done
|
|
|
|
print_summary "$passed" "$failed" 0
|
|
exit $((failed > 0))
|
|
fi
|
|
|
|
# =============================================================================
|
|
# FAST TEST: Single prompt to verify all components are registered
|
|
# =============================================================================
|
|
log "Running FAST test (registration check)..."
|
|
echo ""
|
|
|
|
log "Checking Claude can load the plugin..."
|
|
|
|
load_output=$(timeout 30 claude --plugin-dir "$REPO_ROOT" --help 2>&1) || {
|
|
fail "Claude plugin load failed"
|
|
printf '%s\n' "$load_output" | sed -n '1,40p'
|
|
exit 1
|
|
}
|
|
|
|
if printf '%s\n' "$load_output" | grep -qiE "invalid manifest|validation error|failed to load"; then
|
|
fail "Claude reported plugin load errors"
|
|
printf '%s\n' "$load_output" | grep -iE "invalid|failed|error" | head -5
|
|
exit 1
|
|
fi
|
|
|
|
skill_count="$EXPECTED_SKILLS"
|
|
|
|
echo ""
|
|
echo -e "${BLUE}═══════════════════════════════════════════${NC}"
|
|
echo "Release Smoke Test Results"
|
|
echo -e "${BLUE}───────────────────────────────────────────${NC}"
|
|
|
|
passed=0
|
|
failed=0
|
|
|
|
# Check skills
|
|
if [[ "$skill_count" -ge "$EXPECTED_SKILLS" ]]; then
|
|
pass "Skills: $skill_count found (expected $EXPECTED_SKILLS)"
|
|
((passed++)) || true
|
|
else
|
|
fail "Skills: $skill_count found (expected $EXPECTED_SKILLS)"
|
|
((failed++)) || true
|
|
fi
|
|
|
|
echo -e "${BLUE}───────────────────────────────────────────${NC}"
|
|
echo -e " Total: ${GREEN}$passed passed${NC}, ${RED}$failed failed${NC}"
|
|
echo -e "${BLUE}═══════════════════════════════════════════${NC}"
|
|
|
|
if [[ $failed -gt 0 ]]; then
|
|
echo ""
|
|
echo -e "${RED}RELEASE BLOCKED${NC}"
|
|
exit 1
|
|
fi
|
|
|
|
echo ""
|
|
echo -e "${GREEN}RELEASE READY: All components registered${NC}"
|
|
exit 0
|