197 lines
5.7 KiB
Bash
Executable file
197 lines
5.7 KiB
Bash
Executable file
#!/bin/bash
|
|
# LinkedIn Studio Plugin — Structure Validator
|
|
# Validates the REAL v3.1 layout: registration counts (derived dynamically),
|
|
# frontmatter shape, hook drift, and plugin.json fields. Counts are asserted
|
|
# against the declared contract below, which is kept in sync with the
|
|
# CLAUDE.md "## Agents (N)" / "## Commands (N)" headers (cross-checked here)
|
|
# and the STATE.md "Telling" block. Adding or removing an agent, command,
|
|
# reference, or skill breaks the count-equality and fails the lint — this is
|
|
# the registration guard that gates the remediation plan's later steps.
|
|
#
|
|
# The stat-consistency grep (one magnitude per algorithm effect across the
|
|
# tree) is added in remediation Step 3, after reconciliation makes it pass.
|
|
# The version-consistency grep is added in Step 21.
|
|
#
|
|
# Usage: bash scripts/test-runner.sh
|
|
# bash 3.2-safe: plain arrays only, no `declare -A`, no `mapfile`/`readarray`.
|
|
|
|
set -e
|
|
|
|
PLUGIN_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
cd "$PLUGIN_ROOT"
|
|
PASS=0
|
|
FAIL=0
|
|
WARN=0
|
|
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[0;33m'
|
|
NC='\033[0m' # No Color
|
|
|
|
pass() { echo -e "${GREEN}✓${NC} $1"; PASS=$((PASS + 1)); }
|
|
fail() { echo -e "${RED}✗${NC} $1"; FAIL=$((FAIL + 1)); }
|
|
warn() { echo -e "${YELLOW}⚠${NC} $1"; WARN=$((WARN + 1)); }
|
|
|
|
# --- Declared registration contract (the "Telling" block) ---
|
|
# Source of truth: CLAUDE.md headers + STATE.md Telling. Bump these together
|
|
# with the files when adding/removing an agent, command, reference, or skill.
|
|
EXPECT_AGENTS=19
|
|
EXPECT_COMMANDS=26
|
|
EXPECT_REFS=25
|
|
EXPECT_SKILLS=6
|
|
|
|
echo "================================================"
|
|
echo "LinkedIn Studio Plugin — Structure Validator"
|
|
echo "Plugin root: $PLUGIN_ROOT"
|
|
echo "================================================"
|
|
echo ""
|
|
|
|
# --- Section 1: Core Files ---
|
|
echo "--- Core Files ---"
|
|
|
|
for f in ".claude-plugin/plugin.json" "CLAUDE.md" "CHANGELOG.md" "README.md" "config/REMEMBER.template.md"; do
|
|
if [ -f "$f" ]; then
|
|
pass "$f exists"
|
|
else
|
|
fail "$f MISSING"
|
|
fi
|
|
done
|
|
|
|
echo ""
|
|
|
|
# --- Section 2: Registration Counts (dynamic) ---
|
|
echo "--- Registration Counts ---"
|
|
|
|
AGENTS=$(ls agents/*.md 2>/dev/null | wc -l | tr -d ' ')
|
|
COMMANDS=$(ls commands/*.md 2>/dev/null | wc -l | tr -d ' ')
|
|
REFS=$(ls references/*.md 2>/dev/null | wc -l | tr -d ' ')
|
|
SKILLS=$(ls skills/*/SKILL.md 2>/dev/null | wc -l | tr -d ' ')
|
|
|
|
assert_count() {
|
|
# $1 label, $2 actual, $3 expected
|
|
if [ "$2" -eq "$3" ]; then
|
|
pass "$1: $2 (expected $3)"
|
|
else
|
|
fail "$1: $2 (expected $3) — registration drift"
|
|
fi
|
|
}
|
|
|
|
assert_count "agents/*.md" "$AGENTS" "$EXPECT_AGENTS"
|
|
assert_count "commands/*.md" "$COMMANDS" "$EXPECT_COMMANDS"
|
|
assert_count "references/*.md" "$REFS" "$EXPECT_REFS"
|
|
assert_count "skills/*/SKILL.md" "$SKILLS" "$EXPECT_SKILLS"
|
|
|
|
# Cross-check the CLAUDE.md declared headers against the contract (doc-drift guard)
|
|
DOC_AGENTS=$(grep -oE '^## Agents \([0-9]+\)' CLAUDE.md | grep -oE '[0-9]+' | head -1)
|
|
DOC_COMMANDS=$(grep -oE '^## Commands \([0-9]+\)' CLAUDE.md | grep -oE '[0-9]+' | head -1)
|
|
if [ "$DOC_AGENTS" = "$EXPECT_AGENTS" ]; then
|
|
pass "CLAUDE.md '## Agents ($DOC_AGENTS)' matches contract"
|
|
else
|
|
fail "CLAUDE.md agents header ($DOC_AGENTS) != contract ($EXPECT_AGENTS)"
|
|
fi
|
|
if [ "$DOC_COMMANDS" = "$EXPECT_COMMANDS" ]; then
|
|
pass "CLAUDE.md '## Commands ($DOC_COMMANDS)' matches contract"
|
|
else
|
|
fail "CLAUDE.md commands header ($DOC_COMMANDS) != contract ($EXPECT_COMMANDS)"
|
|
fi
|
|
|
|
echo ""
|
|
|
|
# --- Section 3: Agent Frontmatter ---
|
|
echo "--- Agent Frontmatter ---"
|
|
|
|
for f in agents/*.md; do
|
|
if head -1 "$f" | grep -q "^---"; then
|
|
if grep -q "^name:" "$f" && grep -q "^description:" "$f"; then
|
|
pass "$f (frontmatter OK)"
|
|
else
|
|
fail "$f (missing name:/description:)"
|
|
fi
|
|
else
|
|
fail "$f (no YAML frontmatter)"
|
|
fi
|
|
done
|
|
|
|
echo ""
|
|
|
|
# --- Section 4: Command Frontmatter ---
|
|
echo "--- Command Frontmatter ---"
|
|
|
|
for f in commands/*.md; do
|
|
if head -1 "$f" | grep -q "^---"; then
|
|
if grep -q "^name:" "$f" && grep -q "^description:" "$f"; then
|
|
pass "$f (frontmatter OK)"
|
|
else
|
|
fail "$f (missing name:/description:)"
|
|
fi
|
|
else
|
|
fail "$f (no YAML frontmatter)"
|
|
fi
|
|
done
|
|
|
|
echo ""
|
|
|
|
# --- Section 5: Hook Configuration (drift) ---
|
|
echo "--- Hook Configuration ---"
|
|
|
|
if [ -f "hooks/hooks.json" ]; then
|
|
pass "hooks/hooks.json exists"
|
|
if python3 hooks/scripts/compile-hooks.py --check >/dev/null 2>&1; then
|
|
pass "hooks.json matches compiled template (no drift)"
|
|
else
|
|
fail "hooks.json DRIFT — run: python3 hooks/scripts/compile-hooks.py"
|
|
fi
|
|
else
|
|
fail "hooks/hooks.json MISSING"
|
|
fi
|
|
|
|
echo ""
|
|
|
|
# --- Section 6: Plugin.json Validation ---
|
|
echo "--- Plugin.json Validation ---"
|
|
|
|
if python3 -c "
|
|
import json, sys
|
|
with open('.claude-plugin/plugin.json') as f:
|
|
data = json.load(f)
|
|
required = ['name', 'version', 'description']
|
|
missing = [field for field in required if field not in data]
|
|
if missing:
|
|
print('Missing fields:', missing)
|
|
sys.exit(1)
|
|
print('Version:', data['version'])
|
|
" 2>/dev/null; then
|
|
pass "plugin.json structure valid (name/version/description)"
|
|
else
|
|
fail "plugin.json structure invalid"
|
|
fi
|
|
|
|
echo ""
|
|
|
|
# --- Section 7: Analytics Source ---
|
|
echo "--- Analytics Source ---"
|
|
|
|
if [ -f "scripts/analytics/src/cli.ts" ]; then
|
|
pass "scripts/analytics/src/cli.ts exists"
|
|
else
|
|
fail "scripts/analytics/src/cli.ts MISSING"
|
|
fi
|
|
|
|
echo ""
|
|
|
|
# --- Summary ---
|
|
echo "================================================"
|
|
echo "RESULTS"
|
|
echo "================================================"
|
|
echo -e "${GREEN}Passed: $PASS${NC}"
|
|
echo -e "${RED}Failed: $FAIL${NC}"
|
|
echo -e "${YELLOW}Warnings: $WARN${NC}"
|
|
echo ""
|
|
|
|
if [ $FAIL -eq 0 ]; then
|
|
echo -e "${GREEN}All structural checks passed!${NC}"
|
|
exit 0
|
|
else
|
|
echo -e "${RED}$FAIL check(s) failed. Review above.${NC}"
|
|
exit 1
|
|
fi
|