feat(ms-ai-architect): add plugin to open marketplace (v1.5.0 baseline)
Initial addition of ms-ai-architect plugin to the open-source marketplace. Private content excluded: orchestrator/ (Linear tooling), docs/utredning/ (client investigation), generated test reports and PDF export script. skill-gen tooling moved from orchestrator/ to scripts/skill-gen/. Security scan: WARNING (risk 20/100) — no secrets, no injection found. False positive fixed: added gitleaks:allow to Python variable reference in output-validation-grounding-verification.md line 109. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
a8d79e4484
commit
6a7632146e
490 changed files with 213249 additions and 2 deletions
293
plugins/ms-ai-architect/tests/validate-plugin.sh
Executable file
293
plugins/ms-ai-architect/tests/validate-plugin.sh
Executable file
|
|
@ -0,0 +1,293 @@
|
|||
#!/bin/bash
|
||||
# validate-plugin.sh — Static validation for ms-ai-architect plugin
|
||||
# Usage: bash tests/validate-plugin.sh
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
PLUGIN_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
PASS=0
|
||||
FAIL=0
|
||||
WARN=0
|
||||
|
||||
pass() { echo -e "${GREEN} ✓ $1${NC}"; PASS=$((PASS + 1)); }
|
||||
fail() { echo -e "${RED} ✗ $1${NC}"; FAIL=$((FAIL + 1)); }
|
||||
warn() { echo -e "${YELLOW} ⚠ $1${NC}"; WARN=$((WARN + 1)); }
|
||||
|
||||
echo "=== ms-ai-architect Plugin Validation ==="
|
||||
echo "Plugin root: $PLUGIN_ROOT"
|
||||
echo ""
|
||||
|
||||
# -------------------------------------------------------
|
||||
# Check 1: Agent Frontmatter
|
||||
# -------------------------------------------------------
|
||||
echo "--- Check 1: Agent Frontmatter ---"
|
||||
|
||||
VALID_MODELS="opus sonnet haiku"
|
||||
VALID_COLORS="blue green yellow purple cyan red orange magenta white"
|
||||
|
||||
for agent_file in "$PLUGIN_ROOT"/agents/*.md; do
|
||||
[ -f "$agent_file" ] || continue
|
||||
basename_file="$(basename "$agent_file")"
|
||||
|
||||
# Must have --- on line 1
|
||||
first_line="$(head -n 1 "$agent_file")"
|
||||
if [ "$first_line" != "---" ]; then
|
||||
fail "$basename_file: missing frontmatter delimiter (---) on line 1"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Extract frontmatter (between first and second ---)
|
||||
frontmatter="$(sed -n '1,/^---$/{ /^---$/d; p; }' "$agent_file" | sed '1d')"
|
||||
# sed '1d' removes the first --- captured; we actually need lines between first and second ---
|
||||
# Redo: extract lines between line 2 and next ---
|
||||
frontmatter="$(awk 'NR==1{next} /^---$/{exit} {print}' "$agent_file")"
|
||||
|
||||
# Check required fields
|
||||
for field in "name:" "description:" "model:" "color:" "tools:"; do
|
||||
if echo "$frontmatter" | grep -q "^${field}"; then
|
||||
pass "$basename_file: has $field"
|
||||
elif echo "$frontmatter" | grep -q "^ *${field}"; then
|
||||
# indented (part of multiline) - still counts for description
|
||||
pass "$basename_file: has $field"
|
||||
else
|
||||
# description can be multi-line with |
|
||||
if [ "$field" = "description:" ] && echo "$frontmatter" | grep -q "description:"; then
|
||||
pass "$basename_file: has $field"
|
||||
else
|
||||
fail "$basename_file: missing $field"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# Validate model value
|
||||
model_value="$(echo "$frontmatter" | grep "^model:" | sed 's/^model: *//' | tr -d '[:space:]')"
|
||||
if [ -n "$model_value" ]; then
|
||||
model_valid=false
|
||||
for m in $VALID_MODELS; do
|
||||
if [ "$model_value" = "$m" ]; then
|
||||
model_valid=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
if $model_valid; then
|
||||
pass "$basename_file: model '$model_value' is valid"
|
||||
else
|
||||
fail "$basename_file: model '$model_value' is not valid (expected: $VALID_MODELS)"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Validate color value
|
||||
color_value="$(echo "$frontmatter" | grep "^color:" | sed 's/^color: *//' | tr -d '[:space:]')"
|
||||
if [ -n "$color_value" ]; then
|
||||
color_valid=false
|
||||
for c in $VALID_COLORS; do
|
||||
if [ "$color_value" = "$c" ]; then
|
||||
color_valid=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
if $color_valid; then
|
||||
pass "$basename_file: color '$color_value' is valid"
|
||||
else
|
||||
fail "$basename_file: color '$color_value' is not valid (expected: $VALID_COLORS)"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Validate tools is a JSON array (starts with [)
|
||||
tools_line="$(echo "$frontmatter" | grep "^tools:" || true)"
|
||||
if [ -n "$tools_line" ]; then
|
||||
tools_value="$(echo "$tools_line" | sed 's/^tools: *//')"
|
||||
if echo "$tools_value" | grep -q '^\['; then
|
||||
pass "$basename_file: tools is a JSON array"
|
||||
else
|
||||
fail "$basename_file: tools is not a JSON array (got: $tools_value)"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
|
||||
# -------------------------------------------------------
|
||||
# Check 2: Command Frontmatter
|
||||
# -------------------------------------------------------
|
||||
echo "--- Check 2: Command Frontmatter ---"
|
||||
|
||||
for cmd_file in "$PLUGIN_ROOT"/commands/*.md; do
|
||||
[ -f "$cmd_file" ] || continue
|
||||
basename_file="$(basename "$cmd_file")"
|
||||
basename_noext="${basename_file%.md}"
|
||||
|
||||
# Must have --- on line 1
|
||||
first_line="$(head -n 1 "$cmd_file")"
|
||||
if [ "$first_line" != "---" ]; then
|
||||
fail "$basename_file: missing frontmatter delimiter (---) on line 1"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Extract frontmatter
|
||||
frontmatter="$(awk 'NR==1{next} /^---$/{exit} {print}' "$cmd_file")"
|
||||
|
||||
# Check required fields: name, description
|
||||
for field in "name:" "description:"; do
|
||||
if echo "$frontmatter" | grep -q "${field}"; then
|
||||
pass "$basename_file: has $field"
|
||||
else
|
||||
fail "$basename_file: missing $field"
|
||||
fi
|
||||
done
|
||||
|
||||
# Check allowed-tools (warn if missing)
|
||||
if echo "$frontmatter" | grep -q "allowed-tools:"; then
|
||||
pass "$basename_file: has allowed-tools"
|
||||
else
|
||||
warn "$basename_file: missing allowed-tools (recommended)"
|
||||
fi
|
||||
|
||||
# Validate name matches filename pattern
|
||||
name_value="$(echo "$frontmatter" | grep "^name:" | sed 's/^name: *//' | tr -d '[:space:]')"
|
||||
if [ -n "$name_value" ] && [ "$name_value" = "$basename_noext" ]; then
|
||||
pass "$basename_file: name matches filename"
|
||||
elif [ -n "$name_value" ]; then
|
||||
fail "$basename_file: name '$name_value' does not match filename '$basename_noext'"
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
|
||||
# -------------------------------------------------------
|
||||
# Check 3: Encoding Validation
|
||||
# -------------------------------------------------------
|
||||
echo "--- Check 3: Encoding Validation ---"
|
||||
|
||||
encoding_issues=0
|
||||
for dir in agents commands skills; do
|
||||
dir_path="$PLUGIN_ROOT/$dir"
|
||||
[ -d "$dir_path" ] || continue
|
||||
|
||||
while IFS= read -r -d '' mdfile; do
|
||||
basename_file="$(basename "$mdfile")"
|
||||
rel_path="${mdfile#$PLUGIN_ROOT/}"
|
||||
|
||||
# Check for broken UTF-8 sequences
|
||||
if grep -ql 'æ\|ø\|Ã¥\|Ã\†\|Ø\|Ã…' "$mdfile" 2>/dev/null; then
|
||||
fail "$rel_path: broken æ/ø/å encoding detected"
|
||||
encoding_issues=$((encoding_issues + 1))
|
||||
fi
|
||||
|
||||
if grep -ql 'â€"' "$mdfile" 2>/dev/null; then
|
||||
fail "$rel_path: broken em-dash/en-dash encoding detected"
|
||||
encoding_issues=$((encoding_issues + 1))
|
||||
fi
|
||||
done < <(find "$dir_path" -name '*.md' -print0)
|
||||
done
|
||||
|
||||
if [ "$encoding_issues" -eq 0 ]; then
|
||||
pass "No encoding issues found in agents/, commands/, skills/"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
# -------------------------------------------------------
|
||||
# Check 4: KB Reference Validation
|
||||
# -------------------------------------------------------
|
||||
echo "--- Check 4: KB Reference Validation ---"
|
||||
|
||||
for agent_file in "$PLUGIN_ROOT"/agents/*.md; do
|
||||
[ -f "$agent_file" ] || continue
|
||||
basename_file="$(basename "$agent_file")"
|
||||
|
||||
# Extract lines referencing references/ paths
|
||||
ref_paths="$(grep -o 'references/[a-zA-Z0-9_-]*/\?' "$agent_file" | sort -u || true)"
|
||||
|
||||
if [ -z "$ref_paths" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
while IFS= read -r ref_path; do
|
||||
# Normalize: remove trailing slash, build full path relative to skill references
|
||||
ref_dir="$(echo "$ref_path" | sed 's|/$||')"
|
||||
# Check across all skill directories
|
||||
full_path=""
|
||||
for skill_dir in "$PLUGIN_ROOT"/skills/*/; do
|
||||
if [ -d "${skill_dir}${ref_dir}" ]; then
|
||||
full_path="${skill_dir}${ref_dir}"
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [ -z "$full_path" ]; then
|
||||
full_path="$PLUGIN_ROOT/skills/ms-ai-engineering/$ref_dir"
|
||||
fi
|
||||
|
||||
if [ -d "$full_path" ]; then
|
||||
# Check if directory has files
|
||||
file_count="$(find "$full_path" -maxdepth 1 -name '*.md' -type f | wc -l | tr -d ' ')"
|
||||
if [ "$file_count" -gt 0 ]; then
|
||||
pass "$basename_file: $ref_dir/ exists ($file_count files)"
|
||||
else
|
||||
warn "$basename_file: $ref_dir/ exists but is empty"
|
||||
fi
|
||||
else
|
||||
fail "$basename_file: referenced $ref_dir/ does not exist at $full_path"
|
||||
fi
|
||||
done <<< "$ref_paths"
|
||||
done
|
||||
|
||||
echo ""
|
||||
|
||||
# -------------------------------------------------------
|
||||
# Check 5: Plugin.json Validation
|
||||
# -------------------------------------------------------
|
||||
echo "--- Check 5: Plugin.json Validation ---"
|
||||
|
||||
plugin_json="$PLUGIN_ROOT/.claude-plugin/plugin.json"
|
||||
|
||||
if [ ! -f "$plugin_json" ]; then
|
||||
fail "plugin.json not found at .claude-plugin/plugin.json"
|
||||
else
|
||||
pass "plugin.json exists"
|
||||
|
||||
# Check required fields
|
||||
for field in "name" "version" "description"; do
|
||||
if grep -q "\"$field\"" "$plugin_json"; then
|
||||
pass "plugin.json: has \"$field\""
|
||||
else
|
||||
fail "plugin.json: missing \"$field\""
|
||||
fi
|
||||
done
|
||||
|
||||
# Check auto_discover: true
|
||||
if grep -q '"auto_discover"' "$plugin_json"; then
|
||||
auto_val="$(grep '"auto_discover"' "$plugin_json" | grep -o 'true\|false')"
|
||||
if [ "$auto_val" = "true" ]; then
|
||||
pass "plugin.json: auto_discover is true"
|
||||
else
|
||||
fail "plugin.json: auto_discover is not true (got: $auto_val)"
|
||||
fi
|
||||
else
|
||||
fail "plugin.json: missing auto_discover"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
# -------------------------------------------------------
|
||||
# Summary
|
||||
# -------------------------------------------------------
|
||||
echo "=== Results ==="
|
||||
echo -e "${GREEN}PASS: $PASS${NC}"
|
||||
echo -e "${RED}FAIL: $FAIL${NC}"
|
||||
echo -e "${YELLOW}WARN: $WARN${NC}"
|
||||
|
||||
if [ $FAIL -gt 0 ]; then
|
||||
echo -e "${RED}VALIDATION FAILED${NC}"
|
||||
exit 1
|
||||
else
|
||||
echo -e "${GREEN}VALIDATION PASSED${NC}"
|
||||
exit 0
|
||||
fi
|
||||
Loading…
Add table
Add a link
Reference in a new issue