Initial commit

This commit is contained in:
Zhongwei Li
2025-11-30 09:04:17 +08:00
commit 652915e226
62 changed files with 8212 additions and 0 deletions

View File

@@ -0,0 +1,203 @@
#!/bin/bash
# Script to add skill availability instructions to all agents and commands
# Usage: bash add-skill-instructions.sh (can be run from anywhere)
set -e
# Find marketplace root by looking for plugins/ directory
find_marketplace_root() {
local current_dir="$PWD"
# Check if we're already in marketplace root
if [ -d "$current_dir/plugins" ] && [ -d "$current_dir/scripts" ]; then
echo "$current_dir"
return 0
fi
# Check if script is in scripts/ subdirectory
local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
local parent_dir="$(dirname "$script_dir")"
if [ -d "$parent_dir/plugins" ] && [ -d "$parent_dir/scripts" ]; then
echo "$parent_dir"
return 0
fi
# Search upwards for marketplace root
while [ "$current_dir" != "/" ]; do
if [ -d "$current_dir/plugins" ] && [ -d "$current_dir/scripts" ] && [ -f "$current_dir/.claude-plugin/marketplace.json" ]; then
echo "$current_dir"
return 0
fi
current_dir="$(dirname "$current_dir")"
done
echo "ERROR: Could not find ai-dev-marketplace root directory" >&2
echo "Please run this script from within the marketplace directory" >&2
return 1
}
MARKETPLACE_DIR=$(find_marketplace_root)
if [ $? -ne 0 ]; then
exit 1
fi
cd "$MARKETPLACE_DIR"
echo "📍 Working in: $MARKETPLACE_DIR"
echo ""
echo "🔍 Adding skill availability instructions to agents and commands..."
echo ""
# Counters
agents_updated=0
commands_updated=0
agents_skipped=0
commands_skipped=0
# Function to get skills for a plugin
get_plugin_skills() {
local plugin_path="$1"
local skills_dir="$plugin_path/skills"
if [ -d "$skills_dir" ]; then
# List all skill directories
ls "$skills_dir" 2>/dev/null | sort
fi
}
# Function to add skills section to a file
add_skills_section() {
local file="$1"
local plugin_name="$2"
local plugin_path="plugins/$plugin_name"
# Check if file already has skill instructions
if grep -q "## Available Skills" "$file"; then
return 1 # Skip
fi
# Get skills for this plugin
local skills=$(get_plugin_skills "$plugin_path")
local skill_count=$(echo "$skills" | grep -v "^$" | wc -l)
if [ "$skill_count" -eq 0 ]; then
return 1 # No skills, skip
fi
# Build skill list
local skill_list=""
while IFS= read -r skill; do
if [ -n "$skill" ]; then
# Read skill description from SKILL.md if available
local skill_file="$plugin_path/skills/$skill/SKILL.md"
if [ -f "$skill_file" ]; then
local description=$(grep "^description:" "$skill_file" | sed 's/description: //')
skill_list="${skill_list}- **$skill**: $description
"
else
skill_list="${skill_list}- **$skill**
"
fi
fi
done <<< "$skills"
# Create skills section
local skills_section="## Available Skills
This $(basename $(dirname "$file")) has access to the following skills from the $plugin_name plugin:
$skill_list
**To use a skill:**
\`\`\`
!{skill skill-name}
\`\`\`
Use skills when you need:
- Domain-specific templates and examples
- Validation scripts and automation
- Best practices and patterns
- Configuration generators
Skills provide pre-built resources to accelerate your work.
---
"
# Find insertion point (after security section, before main content)
# Look for the first ## that's not "Security"
local line_num=$(grep -n "^## " "$file" | grep -v "## Security" | grep -v "## Available Skills" | head -1 | cut -d: -f1)
if [ -z "$line_num" ]; then
# No section found, add after frontmatter and security
line_num=$(grep -n "^---$" "$file" | tail -1 | cut -d: -f1)
line_num=$((line_num + 1))
# Skip past security section
local security_end=$(tail -n +$line_num "$file" | grep -n "^---$" | head -1 | cut -d: -f1)
if [ -n "$security_end" ]; then
line_num=$((line_num + security_end))
fi
fi
# Insert skills section
if [ -n "$line_num" ]; then
# Insert at line_num
echo "$skills_section" | cat - <(tail -n +$line_num "$file") > "$file.tmp"
head -n $((line_num - 1)) "$file" >> "$file.tmp.header"
cat "$file.tmp.header" "$file.tmp" > "$file"
rm "$file.tmp" "$file.tmp.header"
return 0
else
# Couldn't find insertion point, append at end
echo "" >> "$file"
echo "$skills_section" >> "$file"
return 0
fi
}
# Process all agent files
echo "📝 Processing agents..."
for plugin_dir in plugins/*/; do
plugin_name=$(basename "$plugin_dir")
for agent_file in "$plugin_dir"agents/*.md; do
if [[ -f "$agent_file" ]]; then
if add_skills_section "$agent_file" "$plugin_name"; then
echo " ✅ Updated: $agent_file"
agents_updated=$((agents_updated + 1))
else
agents_skipped=$((agents_skipped + 1))
fi
fi
done
done
echo ""
echo "📝 Processing commands..."
for plugin_dir in plugins/*/; do
plugin_name=$(basename "$plugin_dir")
for command_file in "$plugin_dir"commands/*.md; do
if [[ -f "$command_file" ]]; then
if add_skills_section "$command_file" "$plugin_name"; then
echo " ✅ Updated: $command_file"
commands_updated=$((commands_updated + 1))
else
commands_skipped=$((commands_skipped + 1))
fi
fi
done
done
echo ""
echo "✨ Summary:"
echo " Agents updated: $agents_updated"
echo " Agents skipped (no skills or already has section): $agents_skipped"
echo " Commands updated: $commands_updated"
echo " Commands skipped (no skills or already has section): $commands_skipped"
echo ""
echo "Total updated: $((agents_updated + commands_updated))"
echo ""
echo "✅ Done! Run 'git diff' to review changes."

View File

@@ -0,0 +1,105 @@
#!/bin/bash
# Script to add Skill tool to all agents and commands that are missing it
# Usage: bash add-skill-tool.sh (can be run from anywhere)
set -e
# Find marketplace root by looking for plugins/ directory
find_marketplace_root() {
local current_dir="$PWD"
# Check if we're already in marketplace root
if [ -d "$current_dir/plugins" ] && [ -d "$current_dir/scripts" ]; then
echo "$current_dir"
return 0
fi
# Check if script is in scripts/ subdirectory
local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
local parent_dir="$(dirname "$script_dir")"
if [ -d "$parent_dir/plugins" ] && [ -d "$parent_dir/scripts" ]; then
echo "$parent_dir"
return 0
fi
# Search upwards for marketplace root
while [ "$current_dir" != "/" ]; do
if [ -d "$current_dir/plugins" ] && [ -d "$current_dir/scripts" ] && [ -f "$current_dir/.claude-plugin/marketplace.json" ]; then
echo "$current_dir"
return 0
fi
current_dir="$(dirname "$current_dir")"
done
echo "ERROR: Could not find ai-dev-marketplace root directory" >&2
echo "Please run this script from within the marketplace directory" >&2
return 1
}
MARKETPLACE_DIR=$(find_marketplace_root)
if [ $? -ne 0 ]; then
exit 1
fi
cd "$MARKETPLACE_DIR"
echo "📍 Working in: $MARKETPLACE_DIR"
echo ""
echo "🔍 Adding Skill tool to agents and commands..."
echo ""
# Counters
agents_updated=0
commands_updated=0
agents_skipped=0
commands_skipped=0
# Process all agent files
echo "📝 Processing agents..."
for agent_file in plugins/*/agents/*.md; do
if [[ -f "$agent_file" ]]; then
# Check if file has tools: line
if grep -q "^tools:" "$agent_file"; then
# Check if Skill is already present
if grep -q "^tools:.*Skill" "$agent_file"; then
agents_skipped=$((agents_skipped + 1))
else
# Add Skill to the tools line
sed -i 's/^tools: \(.*\)$/tools: \1, Skill/' "$agent_file"
echo " ✅ Updated: $agent_file"
agents_updated=$((agents_updated + 1))
fi
fi
fi
done
echo ""
echo "📝 Processing commands..."
for command_file in plugins/*/commands/*.md; do
if [[ -f "$command_file" ]]; then
# Check if file has allowed-tools: line
if grep -q "^allowed-tools:" "$command_file"; then
# Check if Skill is already present
if grep -q "^allowed-tools:.*Skill" "$command_file"; then
commands_skipped=$((commands_skipped + 1))
else
# Add Skill to the allowed-tools line
sed -i 's/^allowed-tools: \(.*\)$/allowed-tools: \1, Skill/' "$command_file"
echo " ✅ Updated: $command_file"
commands_updated=$((commands_updated + 1))
fi
fi
fi
done
echo ""
echo "✨ Summary:"
echo " Agents updated: $agents_updated"
echo " Agents skipped (already have Skill): $agents_skipped"
echo " Commands updated: $commands_updated"
echo " Commands skipped (already have Skill): $commands_skipped"
echo ""
echo "Total updated: $((agents_updated + commands_updated))"
echo ""
echo "✅ Done! Run 'git diff' to review changes."

View File

@@ -0,0 +1,466 @@
#!/usr/bin/env python3
"""
Create New Plugin with Enterprise Structure
Creates a complete plugin scaffold following enterprise standards:
- .claude-plugin/plugin.json
- .mcp.json placeholder
- hooks/hooks.json
- LICENSE (MIT)
- CHANGELOG.md
- commands/
- agents/
- skills/{skill-name}/
├── SKILL.md
├── reference.md
├── examples.md
├── scripts/
└── templates/
Usage:
python create-plugin-structure.py <plugin-name> [--skill <skill-name>]
Examples:
python create-plugin-structure.py multiagent-analytics --skill analytics-assistant
python create-plugin-structure.py multiagent-testing --skill test-runner
"""
import sys
import json
from pathlib import Path
from datetime import datetime
MARKETPLACE_DIR = Path.home() / ".claude/marketplaces/multiagent-dev/plugins"
# Templates
LICENSE_TEMPLATE = """MIT License
Copyright (c) {year} Multiagent Framework
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
CHANGELOG_TEMPLATE = """# Changelog
All notable changes to this plugin will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
### Planned
- Initial plugin implementation
- Core features and commands
- Documentation
## [1.0.0] - {date}
### Added
- Plugin structure created
- Enterprise directory layout
- Skill scaffolding for {skill_name}
"""
PLUGIN_JSON_TEMPLATE = {
"name": "{plugin_name}",
"version": "1.0.0",
"description": "{description}",
"author": {
"name": "Multiagent Framework",
"email": "noreply@multiagent.dev"
},
"license": "MIT",
"keywords": ["{subsystem}", "multiagent", "automation"],
"components": {
"commands": 0,
"agents": 0,
"skills": 1
}
}
MCP_JSON_TEMPLATE = {
"mcpServers": {},
"notes": "MCP server configurations for this plugin. Add servers as needed."
}
HOOKS_JSON_TEMPLATE = {
"hooks": {},
"notes": "Event hooks for this plugin. Configure hook triggers and scripts as needed."
}
SKILL_MD_TEMPLATE = """---
name: {skill_display_name}
description: {skill_description}
allowed-tools: Read, Write, Bash
---
# {skill_display_name}
## Instructions
TODO: Add detailed instructions for this skill.
### Features
1. Feature 1
2. Feature 2
3. Feature 3
### Trigger Patterns
This skill is automatically invoked when:
- Pattern 1
- Pattern 2
- Pattern 3
## Examples
### Example 1: Basic Usage
TODO: Add example showing basic usage
```bash
# Example command or code
```
### Example 2: Advanced Usage
TODO: Add example showing advanced features
```bash
# Example command or code
```
"""
REFERENCE_MD_TEMPLATE = """# {skill_display_name} - Reference
## API Reference
### Trigger Patterns
- Pattern 1: Description
- Pattern 2: Description
- Pattern 3: Description
### Input Requirements
- Input 1: Description and format
- Input 2: Description and format
### Output Format
- Output 1: Description
- Output 2: Description
## Configuration
### Environment Variables
```bash
# VARIABLE_NAME=value # Description
```
### Settings
TODO: Document configurable settings
## Advanced Usage
### Performance Considerations
TODO: Add performance notes
## Troubleshooting
### Issue 1
**Problem:** Description
**Solution:** How to fix
"""
EXAMPLES_MD_TEMPLATE = """# {skill_display_name} - Examples
## Example 1: Basic Use Case
TODO: Add first example
```bash
# Example code
```
**Expected Output:**
```
Expected result
```
## Example 2: Advanced Use Case
TODO: Add second example
```bash
# Example code
```
**Expected Output:**
```
Expected result
```
## Example 3: Real-World Scenario
TODO: Add real-world example
```bash
# Example code
```
**Expected Output:**
```
Expected result
```
"""
README_TEMPLATE = """# {plugin_name}
{description}
## Installation
```bash
/plugin install {plugin_name}@multiagent-dev
```
## Components
- **Commands**: 0 slash commands
- **Agents**: 0 specialized agents
- **Skills**: 1 skill
## Skills
### {skill_display_name}
{skill_description}
See `skills/{skill_slug}/SKILL.md` for details.
## Development
This plugin follows the multiagent enterprise plugin structure.
### Directory Layout
```
{plugin_name}/
├── .claude-plugin/
│ └── plugin.json
├── .mcp.json
├── hooks/
│ └── hooks.json
├── LICENSE
├── CHANGELOG.md
├── README.md
├── commands/ # Slash commands
├── agents/ # Specialized agents
└── skills/ # Auto-discovered skills
└── {skill_slug}/
├── SKILL.md
├── reference.md
├── examples.md
├── scripts/
└── templates/
```
## License
MIT License - see LICENSE file for details
"""
def create_plugin_structure(plugin_name: str, skill_name: str = None):
"""Create complete enterprise plugin structure."""
# Extract subsystem name
subsystem = plugin_name.replace("multiagent-", "")
# Default skill name if not provided
if not skill_name:
skill_name = f"{subsystem}-assistant"
skill_slug = skill_name.lower().replace(" ", "-")
skill_display_name = skill_name.replace("-", " ").title()
plugin_dir = MARKETPLACE_DIR / plugin_name
if plugin_dir.exists():
print(f"❌ Plugin directory already exists: {plugin_dir}")
print(f" Please remove it first or choose a different name.")
return False
print("=" * 70)
print(f"Creating Plugin: {plugin_name}")
print("=" * 70)
print(f"Skill: {skill_display_name} ({skill_slug})")
print(f"Location: {plugin_dir}\n")
# Create directory structure
print("Creating directory structure...")
dirs_to_create = [
plugin_dir / ".claude-plugin",
plugin_dir / "hooks",
plugin_dir / "commands",
plugin_dir / "agents",
plugin_dir / "skills" / skill_slug / "scripts",
plugin_dir / "skills" / skill_slug / "templates",
]
for dir_path in dirs_to_create:
dir_path.mkdir(parents=True, exist_ok=True)
print(f" ✓ Created: {dir_path.relative_to(plugin_dir)}/")
# Create plugin.json
print("\nCreating plugin.json...")
plugin_json = PLUGIN_JSON_TEMPLATE.copy()
plugin_json["name"] = plugin_name
plugin_json["description"] = f"{subsystem.title()} functionality for multiagent framework"
plugin_json["keywords"] = [subsystem, "multiagent", "automation"]
plugin_json_path = plugin_dir / ".claude-plugin" / "plugin.json"
with open(plugin_json_path, 'w') as f:
json.dump(plugin_json, f, indent=2)
print(f" ✓ Created: .claude-plugin/plugin.json")
# Create .mcp.json
print("\nCreating .mcp.json...")
mcp_json_path = plugin_dir / ".mcp.json"
with open(mcp_json_path, 'w') as f:
json.dump(MCP_JSON_TEMPLATE, f, indent=2)
print(f" ✓ Created: .mcp.json")
# Create hooks.json
print("\nCreating hooks/hooks.json...")
hooks_json_path = plugin_dir / "hooks" / "hooks.json"
with open(hooks_json_path, 'w') as f:
json.dump(HOOKS_JSON_TEMPLATE, f, indent=2)
print(f" ✓ Created: hooks/hooks.json")
# Create LICENSE
print("\nCreating LICENSE...")
license_path = plugin_dir / "LICENSE"
license_content = LICENSE_TEMPLATE.format(year=datetime.now().year)
license_path.write_text(license_content)
print(f" ✓ Created: LICENSE")
# Create CHANGELOG.md
print("\nCreating CHANGELOG.md...")
changelog_path = plugin_dir / "CHANGELOG.md"
changelog_content = CHANGELOG_TEMPLATE.format(
date=datetime.now().strftime("%Y-%m-%d"),
skill_name=skill_display_name
)
changelog_path.write_text(changelog_content)
print(f" ✓ Created: CHANGELOG.md")
# Create README.md
print("\nCreating README.md...")
readme_path = plugin_dir / "README.md"
readme_content = README_TEMPLATE.format(
plugin_name=plugin_name,
description=f"{subsystem.title()} functionality for multiagent framework",
skill_display_name=skill_display_name,
skill_description=f"Provides {subsystem} capabilities",
skill_slug=skill_slug
)
readme_path.write_text(readme_content)
print(f" ✓ Created: README.md")
# Create skill files
skill_dir = plugin_dir / "skills" / skill_slug
print(f"\nCreating skill documentation for '{skill_display_name}'...")
# SKILL.md
skill_md_path = skill_dir / "SKILL.md"
skill_md_content = SKILL_MD_TEMPLATE.format(
skill_display_name=skill_display_name,
skill_description=f"Provides {subsystem} capabilities for the multiagent framework"
)
skill_md_path.write_text(skill_md_content)
print(f" ✓ Created: skills/{skill_slug}/SKILL.md")
# reference.md
reference_md_path = skill_dir / "reference.md"
reference_content = REFERENCE_MD_TEMPLATE.format(
skill_display_name=skill_display_name
)
reference_md_path.write_text(reference_content)
print(f" ✓ Created: skills/{skill_slug}/reference.md")
# examples.md
examples_md_path = skill_dir / "examples.md"
examples_content = EXAMPLES_MD_TEMPLATE.format(
skill_display_name=skill_display_name
)
examples_md_path.write_text(examples_content)
print(f" ✓ Created: skills/{skill_slug}/examples.md")
# Create .gitkeep files
(skill_dir / "scripts" / ".gitkeep").touch()
(skill_dir / "templates" / ".gitkeep").touch()
(plugin_dir / "commands" / ".gitkeep").touch()
(plugin_dir / "agents" / ".gitkeep").touch()
print("\n" + "=" * 70)
print("SUCCESS: Plugin Structure Created!")
print("=" * 70)
print(f"\nLocation: {plugin_dir}")
print(f"\nNext Steps:")
print(f" 1. Edit skills/{skill_slug}/SKILL.md with actual skill instructions")
print(f" 2. Add commands to commands/ directory")
print(f" 3. Add agents to agents/ directory")
print(f" 4. Add scripts to skills/{skill_slug}/scripts/")
print(f" 5. Add templates to skills/{skill_slug}/templates/")
print(f" 6. Update README.md with actual documentation")
print(f" 7. Test with: /plugin install {plugin_name}@multiagent-dev")
print()
return True
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: python create-plugin-structure.py <plugin-name> [--skill <skill-name>]")
print("\nExamples:")
print(" python create-plugin-structure.py multiagent-analytics")
print(" python create-plugin-structure.py multiagent-testing --skill test-runner")
sys.exit(1)
plugin_name = sys.argv[1]
skill_name = None
# Parse optional --skill argument
if "--skill" in sys.argv:
skill_idx = sys.argv.index("--skill")
if skill_idx + 1 < len(sys.argv):
skill_name = sys.argv[skill_idx + 1]
success = create_plugin_structure(plugin_name, skill_name)
sys.exit(0 if success else 1)

View File

@@ -0,0 +1,168 @@
#!/usr/bin/env python3
"""
Create Skill Directory Structures for Existing Plugins
Mechanically creates the directory structure for skills in plugins
that don't have them yet. Agent will fill in content later.
Usage:
python create-skill-structures.py [--dry-run]
"""
import sys
from pathlib import Path
from datetime import datetime
MARKETPLACE_DIR = Path.home() / ".claude/marketplaces/multiagent-dev/plugins"
# Mapping: plugin-name → skill-name
PLUGIN_SKILLS = {
"multiagent-ai-infrastructure": "ai-infrastructure-assistant",
"multiagent-backend": "backend-developer",
"multiagent-build": "build-assistant",
"multiagent-compliance": "compliance-advisor",
"multiagent-core": "core-initializer",
"multiagent-cto": "architecture-reviewer",
"multiagent-deployment": "deployment-assistant",
"multiagent-docs": "documentation-writer",
"multiagent-enhancement": "enhancement-manager",
"multiagent-frontend": "frontend-developer",
"multiagent-github": "github-integration",
"multiagent-idea": "idea-tracker",
"multiagent-implementation": "implementation-orchestrator",
"multiagent-iterate": "iteration-manager",
"multiagent-mcp": "mcp-manager",
"multiagent-notes": "notes-tracker",
"multiagent-observability": "observability-monitor",
"multiagent-performance": "performance-optimizer",
"multiagent-profile": "developer-profile",
"multiagent-refactoring": "refactoring-analyzer",
"multiagent-reliability": "reliability-engineer",
"multiagent-security": "security-advisor",
"multiagent-supervisor": "supervisor-coordinator",
"multiagent-validation": "validation-checker",
"multiagent-version": "version-manager",
}
def create_skill_structure(plugin_name: str, skill_name: str, dry_run: bool = False):
"""Create mechanical skill directory structure."""
plugin_dir = MARKETPLACE_DIR / plugin_name
skill_slug = skill_name.lower().replace(" ", "-")
skill_dir = plugin_dir / "skills" / skill_slug
# Check if plugin exists
if not plugin_dir.exists():
print(f" WARNING: Plugin directory not found: {plugin_dir}")
return False
# Check if skill already exists
if (skill_dir / "SKILL.md").exists():
print(f" SKIP: Skill already exists: {skill_slug}")
return False
print(f"\n[{plugin_name}]")
print(f" Creating skill: {skill_slug}")
if dry_run:
print(f" [DRY RUN] Would create:")
print(f" - {skill_dir}/")
print(f" - {skill_dir}/scripts/")
print(f" - {skill_dir}/templates/")
print(f" - {skill_dir}/SKILL.md (placeholder)")
print(f" - {skill_dir}/reference.md (placeholder)")
print(f" - {skill_dir}/examples.md (placeholder)")
return True
# Create directories
skill_dir.mkdir(parents=True, exist_ok=True)
(skill_dir / "scripts").mkdir(exist_ok=True)
(skill_dir / "templates").mkdir(exist_ok=True)
print(f" OK: Created directories")
# Create placeholder files (agent will fill these)
skill_md = skill_dir / "SKILL.md"
skill_md.write_text(f"""---
name: {skill_name.title()}
description: TODO - Agent will fill this
allowed-tools: Read, Write, Bash
---
# {skill_name.title()}
TODO: Agent will generate content using skill-builder
""")
reference_md = skill_dir / "reference.md"
reference_md.write_text(f"""# {skill_name.title()} - Reference
TODO: Agent will generate API reference
""")
examples_md = skill_dir / "examples.md"
examples_md.write_text(f"""# {skill_name.title()} - Examples
TODO: Agent will generate examples
""")
# Create .gitkeep in empty dirs
(skill_dir / "scripts" / ".gitkeep").touch()
(skill_dir / "templates" / ".gitkeep").touch()
print(f" OK: Created placeholder files")
print(f" Location: {skill_dir}")
return True
def main():
"""Create skill structures for all plugins."""
dry_run = "--dry-run" in sys.argv
print("=" * 70)
print("Creating Skill Structures for Existing Plugins")
print("=" * 70)
if dry_run:
print("\n⚠️ DRY RUN MODE - No changes will be made\n")
print(f"\nMarketplace: {MARKETPLACE_DIR}")
print(f"Plugins to process: {len(PLUGIN_SKILLS)}\n")
created = 0
skipped = 0
errors = 0
for plugin_name, skill_name in PLUGIN_SKILLS.items():
try:
result = create_skill_structure(plugin_name, skill_name, dry_run)
if result:
created += 1
else:
skipped += 1
except Exception as e:
print(f" ERROR: {e}")
errors += 1
print("\n" + "=" * 70)
print("Summary")
print("=" * 70)
print(f"Created: {created}")
print(f"Skipped: {skipped}")
print(f"Errors: {errors}")
print()
if dry_run:
print("Run without --dry-run to create structures")
else:
print("Next step: Run headless skill generation to fill content")
print(" ./scripts/plugins/marketplace/fill-skill-content.sh")
return 0 if errors == 0 else 1
if __name__ == "__main__":
sys.exit(main())

View File

@@ -0,0 +1,44 @@
#!/bin/bash
# Find hardcoded paths in plugin files
# Usage: bash find-hardcoded-paths.sh [directory]
DIR="${1:-$HOME/.claude/plugins/marketplaces/domain-plugin-builder/plugins/domain-plugin-builder}"
echo "Scanning for hardcoded paths in: $DIR"
echo "================================================"
echo ""
# Find markdown files with hardcoded paths (excluding URLs)
echo "## Hardcoded paths in markdown files:"
echo ""
# Look for absolute paths that aren't URLs
grep -rn \
--include="*.md" \
-E '(~/.claude/|/home/[^/]+/|\.claude/plugins/marketplaces/|plugins/[^/]+/)' \
"$DIR" \
| grep -v 'http://' \
| grep -v 'https://' \
| grep -v 'bash ~/.claude/plugins/marketplaces/domain-plugin-builder/plugins/domain-plugin-builder/skills/build-assistant/scripts/' \
| grep -v '# ' \
| grep -v 'CRITICAL: Script Paths Must Be Absolute' \
| grep -v 'Example:' \
| grep -v '```'
echo ""
echo "================================================"
echo ""
echo "## What should be fixed:"
echo ""
echo "For documentation references in agents/commands/skills:"
echo " ❌ ~/.claude/plugins/.../docs/frameworks/claude/dans-composition-pattern.md"
echo " ✅ @dans-composition-pattern.md"
echo ""
echo "For bash validation scripts (these SHOULD stay absolute):"
echo " ✅ bash ~/.claude/plugins/marketplaces/domain-plugin-builder/plugins/domain-plugin-builder/skills/build-assistant/scripts/validate-agent.sh"
echo ""
echo "For @ references in prompts:"
echo " ✅ @agent-color-decision.md"
echo " ✅ @docs/frameworks/claude/dans-composition-pattern.md"
echo ""

View File

@@ -0,0 +1,66 @@
#!/bin/bash
# fix-argument-hints.sh
# Fixes argument hint formatting issues found by validate-argument-hints.sh
PLUGIN_DIR="${1:-.}"
FIXES_APPLIED=0
echo "=== Fixing Argument Hints ==="
echo ""
if [ ! -d "$PLUGIN_DIR" ]; then
echo "❌ ERROR: Directory not found: $PLUGIN_DIR"
exit 1
fi
# Find all command files
COMMAND_FILES=$(find "$PLUGIN_DIR" -type f -path "*/commands/*.md" 2>/dev/null)
if [ -z "$COMMAND_FILES" ]; then
echo "⚠️ No command files found in $PLUGIN_DIR"
exit 0
fi
echo "Scanning and fixing command files..."
echo ""
while IFS= read -r file; do
# Check if argument-hint is missing
if ! grep -q "^argument-hint:" "$file"; then
echo "📝 Adding missing argument-hint to: $file"
# Add after description line
sed -i '/^description:/a argument-hint: none' "$file"
((FIXES_APPLIED++))
fi
# Fix improper format (quoted strings without brackets)
HINT=$(sed -n '/^---$/,/^---$/p' "$file" | grep "^argument-hint:" | sed 's/argument-hint: *//')
# Check if it's a quoted string like "Spec directory (e.g., 002-system-context-we)"
if echo "$HINT" | grep -qE '^".*\(e\.g\.'; then
echo "🔧 Fixing format in: $file"
# Extract the main part before (e.g.,
MAIN_PART=$(echo "$HINT" | sed 's/".*(\(e\.g\.,.*\))".*/<\1>/' | sed 's/Spec directory/<spec-directory>/')
sed -i "s|^argument-hint:.*|argument-hint: <spec-directory>|" "$file"
((FIXES_APPLIED++))
fi
# Fix legacy subsystem references
if grep -q "^argument-hint:.*subsystem" "$file"; then
echo "🔄 Replacing 'subsystem' with 'plugin' in: $file"
sed -i 's/argument-hint:.*subsystem/argument-hint: <plugin-name>/' "$file"
((FIXES_APPLIED++))
fi
done <<< "$COMMAND_FILES"
echo ""
echo "=== Summary ==="
if [ $FIXES_APPLIED -eq 0 ]; then
echo "✅ No fixes needed"
exit 0
else
echo "✅ Applied $FIXES_APPLIED fix(es)"
exit 0
fi

View File

@@ -0,0 +1,70 @@
#!/bin/bash
# Fix hardcoded documentation references to use @ symbol
# Usage: bash fix-hardcoded-doc-refs.sh <marketplace-directory>
MARKETPLACE_DIR="${1:-$(pwd)}"
echo "Fixing hardcoded documentation references in: $MARKETPLACE_DIR"
echo "========================================================"
# Counter
FIXED=0
# Find all markdown files
find "$MARKETPLACE_DIR" -type f -name "*.md" | while read -r FILE; do
# Skip CLAUDE.md script path examples (those should stay absolute)
if [[ "$FILE" == *"/CLAUDE.md" ]]; then
# Only fix @ references in CLAUDE.md, not bash script paths
if grep -q "@plugins/domain-plugin-builder/" "$FILE" 2>/dev/null; then
echo "Fixing @ references in: $FILE"
# Fix template references
sed -i 's|@plugins/domain-plugin-builder/skills/build-assistant/templates/commands/template-command-patterns.md|@template-command-patterns.md|g' "$FILE"
sed -i 's|@plugins/domain-plugin-builder/skills/build-assistant/templates/agents/agent-with-phased-webfetch.md|@agent-with-phased-webfetch.md|g' "$FILE"
# Fix framework doc references
sed -i 's|@plugins/domain-plugin-builder/docs/frameworks/claude/component-decision-framework.md|@component-decision-framework.md|g' "$FILE"
sed -i 's|@plugins/domain-plugin-builder/docs/sdks/|@|g' "$FILE"
((FIXED++))
fi
continue
fi
# For all other files, fix @ references
if grep -q "@plugins/" "$FILE" 2>/dev/null; then
echo "Fixing: $FILE"
# Template references
sed -i 's|@plugins/domain-plugin-builder/skills/build-assistant/templates/commands/template-command-patterns.md|@template-command-patterns.md|g' "$FILE"
sed -i 's|@plugins/domain-plugin-builder/skills/build-assistant/templates/agents/agent-with-phased-webfetch.md|@agent-with-phased-webfetch.md|g' "$FILE"
# Framework docs
sed -i 's|@plugins/domain-plugin-builder/docs/frameworks/claude/component-decision-framework.md|@component-decision-framework.md|g' "$FILE"
sed -i 's|@plugins/domain-plugin-builder/docs/frameworks/claude/dans-composition-pattern.md|@dans-composition-pattern.md|g' "$FILE"
sed -i 's|@plugins/domain-plugin-builder/docs/frameworks/claude/agent-skills-architecture.md|@agent-skills-architecture.md|g' "$FILE"
# SDK docs (simplified)
sed -i 's|@plugins/domain-plugin-builder/docs/sdks/claude-agent-sdk-documentation.md|@claude-agent-sdk-documentation.md|g' "$FILE"
sed -i 's|@plugins/domain-plugin-builder/docs/sdks/\([^/]*\)|@\1|g' "$FILE"
# Plugin-specific docs (keep relative @plugins/PLUGIN_NAME/docs/)
# These are OK and should stay as-is for cross-plugin references
((FIXED++))
fi
done
echo ""
echo "========================================================"
echo "✅ Fixed $FIXED files"
echo ""
echo "Files with @ references should now use short names:"
echo " @template-command-patterns.md"
echo " @component-decision-framework.md"
echo " @dans-composition-pattern.md"
echo ""
echo "Cross-plugin references stay as:"
echo " @plugins/PLUGIN_NAME/docs/file.md"
echo ""

View File

@@ -0,0 +1,105 @@
#!/usr/bin/env bash
# Script: fix-hardcoded-paths.sh
# Purpose: Fix hardcoded multiagent-core paths to use simple project-relative paths
# Usage: ./fix-hardcoded-paths.sh [--dry-run]
set -euo pipefail
DRY_RUN=false
if [[ "${1:-}" == "--dry-run" ]]; then
DRY_RUN=true
echo "DRY RUN MODE - No files will be changed"
echo ""
fi
PLUGINS_DIR="$HOME/.claude/marketplaces/multiagent-dev/plugins"
echo "=== Fixing Hardcoded Paths in Plugins ==="
echo ""
# Complex path pattern that needs replacement
COMPLEX_CONFIG_PATH='$([ -f "$([ -d "$HOME/.claude/marketplaces/multiagent-dev/plugins/*/skills/*/config" ] && echo "$HOME/.claude/marketplaces/multiagent-dev/plugins/*/skills/*/config" || find "$HOME/.claude/marketplaces/multiagent-dev/plugins/multiagent-config" -type d -path "*/skills/*" -name "config" 2>/dev/null | head -1).json" ] && echo "$([ -d "$HOME/.claude/marketplaces/multiagent-dev/plugins/*/skills/*/config" ] && echo "$HOME/.claude/marketplaces/multiagent-dev/plugins/*/skills/*/config" || find "$HOME/.claude/marketplaces/multiagent-dev/plugins/multiagent-config" -type d -path "*/skills/*" -name "config" 2>/dev/null | head -1).json" || find "$HOME/.claude/marketplaces/multiagent-dev/plugins/multiagent-core/skills/*" -name "config.json" -type f 2>/dev/null | head -1)'
SIMPLE_CONFIG_PATH='.multiagent/config.json'
# Count before
COMPLEX_PATHS_BEFORE=$(grep -r "multiagent-core/skills" "$PLUGINS_DIR"/*/commands/*.md "$PLUGINS_DIR"/*/agents/*.md 2>/dev/null | wc -l)
echo "Before:"
echo " - Complex multiagent-core paths: $COMPLEX_PATHS_BEFORE"
echo ""
if $DRY_RUN; then
echo "[DRY RUN] Would perform these replacements:"
echo ""
fi
FIXED_FILES=0
# Fix all agent and command files
for file in "$PLUGINS_DIR"/*/agents/*.md "$PLUGINS_DIR"/*/commands/*.md; do
[ -f "$file" ] || continue
# Check if file has hardcoded multiagent-core references
if grep -q "multiagent-core" "$file" 2>/dev/null; then
if $DRY_RUN; then
echo "[DRY RUN] Would fix: $file"
grep -n "multiagent-core" "$file" | head -3
echo ""
else
# Create backup
cp "$file" "$file.backup"
# Replace all complex config paths with simple .multiagent/config.json
sed -i 's|\$HOME/\.\(claude\|multiagent\)/[^"]*config\.json|.multiagent/config.json|g' "$file"
sed -i 's|\$(find[^)]*multiagent-core[^)]*)|.multiagent/config.json|g' "$file"
sed -i 's|\$(find[^)]*multiagent-config[^)]*)|.multiagent/config.json|g' "$file"
# Fix script references
sed -i 's|\$HOME/\.\(claude\|multiagent\)/[^"]*\.sh|.multiagent/scripts/\$(basename \$0)|g' "$file"
sed -i 's|\$(find[^)]*multiagent-core[^)]*\.sh[^)]*)|.multiagent/scripts/\$(basename \$0)|g' "$file"
# Fix template references
sed -i 's|\$HOME/\.\(claude\|multiagent\)/[^"]*templates|.multiagent/templates|g' "$file"
sed -i 's|\$(find[^)]*multiagent-core[^)]*templates[^)]*)|.multiagent/templates|g' "$file"
# Fix specific worktree reference
sed -i 's|../multiagent-core-worktrees/|../PROJECT-worktrees/|g' "$file"
# Fix validation reference
sed -i 's|--plugin multiagent-core|--plugin \$(basename \$(git rev-parse --show-toplevel))|g' "$file"
echo "✓ Fixed: $file"
((FIXED_FILES++))
fi
fi
done
echo ""
if $DRY_RUN; then
echo "[DRY RUN] Would fix $FIXED_FILES files"
else
echo "✓ Fixed $FIXED_FILES files"
# Count after
COMPLEX_PATHS_AFTER=$(grep -r "multiagent-core" "$PLUGINS_DIR"/*/commands/*.md "$PLUGINS_DIR"/*/agents/*.md 2>/dev/null | wc -l || echo 0)
echo ""
echo "After:"
echo " - Complex multiagent-core paths: $COMPLEX_PATHS_AFTER (was $COMPLEX_PATHS_BEFORE)"
echo ""
if [ "$COMPLEX_PATHS_AFTER" -eq 0 ]; then
echo "🎉 All hardcoded paths fixed!"
else
echo "⚠️ Some references remain - may need manual review"
echo ""
echo "Remaining issues:"
grep -rn "multiagent-core" "$PLUGINS_DIR"/*/commands/*.md "$PLUGINS_DIR"/*/agents/*.md 2>/dev/null | head -5
fi
echo ""
echo "Backups saved with .backup extension"
echo "To restore: find $PLUGINS_DIR -name '*.backup' -exec bash -c 'mv \"\$0\" \"\${0%.backup}\"' {} \\;"
fi

View File

@@ -0,0 +1,79 @@
#!/bin/bash
# Fix script issues across marketplaces:
# 1. Make all .sh scripts executable
# 2. Verify script references use absolute paths (they should!)
# Usage: bash fix-script-issues.sh <marketplace-directory>
MARKETPLACE_DIR="${1:-$(pwd)}"
echo "Fixing script issues in: $MARKETPLACE_DIR"
echo "========================================================"
echo ""
# Counter
FIXED_PERMS=0
WRONG_REFS=0
echo "## Phase 1: Making all .sh scripts executable"
echo ""
# Find all .sh files and make them executable
find "$MARKETPLACE_DIR" -type f -name "*.sh" | while read -r SCRIPT; do
if [ ! -x "$SCRIPT" ]; then
echo "Making executable: $SCRIPT"
chmod +x "$SCRIPT"
((FIXED_PERMS++))
fi
done
echo "✅ Fixed permissions on $FIXED_PERMS scripts"
echo ""
echo "## Phase 2: Checking script references in markdown files"
echo ""
# Find markdown files with script references that DON'T use absolute paths
find "$MARKETPLACE_DIR" -type f -name "*.md" -exec grep -l '!{bash .*\.sh' {} \; | while read -r FILE; do
# Check for relative script paths (bad)
if grep -q '!{bash plugins/.*\.sh' "$FILE" 2>/dev/null; then
echo "⚠️ Found RELATIVE script path in: $FILE"
grep -n '!{bash plugins/.*\.sh' "$FILE"
((WRONG_REFS++))
fi
# Check for $HOME variable usage (bad - should be ~)
if grep -q '!{bash \$HOME/.claude/.*\.sh' "$FILE" 2>/dev/null; then
echo "⚠️ Found \$HOME instead of ~ in: $FILE"
grep -n '!{bash \$HOME/.claude/.*\.sh' "$FILE"
((WRONG_REFS++))
fi
done
echo ""
echo "========================================================"
echo "✅ Made $FIXED_PERMS scripts executable"
echo ""
if [ $WRONG_REFS -gt 0 ]; then
echo "⚠️ Found $WRONG_REFS files with incorrect script references"
echo ""
echo "Script references should use ABSOLUTE paths:"
echo " ✅ !{bash ~/.claude/plugins/marketplaces/domain-plugin-builder/plugins/domain-plugin-builder/skills/build-assistant/scripts/validate-agent.sh}"
echo " ❌ !{bash plugins/domain-plugin-builder/skills/build-assistant/scripts/validate-agent.sh}"
echo " ❌ !{bash \$HOME/.claude/plugins/...}"
echo ""
echo "Why: Scripts must be callable from ANY working directory"
else
echo "✅ All script references use absolute paths correctly"
fi
echo ""
echo "## Summary"
echo ""
echo "Executable scripts:"
find "$MARKETPLACE_DIR" -type f -name "*.sh" -executable | wc -l
echo ""
echo "Non-executable scripts:"
find "$MARKETPLACE_DIR" -type f -name "*.sh" ! -executable | wc -l
echo ""

View File

@@ -0,0 +1,99 @@
#!/usr/bin/env bash
set -euo pipefail
# Fix tool formatting across all plugins
# Converts ALL formats to horizontal comma-separated without quotes
# Removes incorrect MCP wildcards and brackets
# Portable: Use argument or current directory (works from any location)
MARKETPLACE_ROOT="${1:-$(pwd)}"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "🔧 Fixing Tool Formatting"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
fix_all_tool_formats() {
local file="$1"
python3 - "$file" << 'PYTHON'
import sys
import re
file_path = sys.argv[1]
with open(file_path, 'r') as f:
content = f.read()
original = content
# Fix 1: Convert JSON array format to comma-separated
# tools: ["Bash", "Read", "Write"] -> tools: Bash, Read, Write
pattern1 = r'(tools|allowed-tools):\s*\[(.*?)\]'
def fix_json_array(match):
prefix = match.group(1)
tools_str = match.group(2)
# Extract tool names from quoted strings
tools = re.findall(r'"([^"]+)"', tools_str)
return f'{prefix}: {", ".join(tools)}'
content = re.sub(pattern1, fix_json_array, content, flags=re.DOTALL)
# Fix 2: Convert vertical lists to horizontal
# tools:\n - Bash\n - Read -> tools: Bash, Read
pattern2 = r'(tools|allowed-tools):\n((?: - [^\n]+\n)+)'
def fix_vertical(match):
prefix = match.group(1)
tools_section = match.group(2)
tools = re.findall(r' - ([^\n]+)', tools_section)
return f'{prefix}: {", ".join(tools)}\n'
content = re.sub(pattern2, fix_vertical, content)
# Fix 3: Remove (*) from all tools EXCEPT Bash with restrictions
# Task(*) -> Task, but keep Bash(git add:*)
content = re.sub(r'\b(Task|Read|Write|Edit|Grep|Glob|WebFetch|AskUserQuestion|TodoWrite|SlashCommand)\(\*\)', r'\1', content)
# Fix 4: Remove wildcards from MCP tools
# mcp__server__* -> mcp__server
# Task(mcp__*) -> mcp__servername (placeholder)
content = re.sub(r'mcp__([^_,)\s]+)__\*', r'mcp__\1', content)
content = re.sub(r'Task\(mcp__\*\)', r'mcp__servername', content)
# Fix 5: Remove brackets from mcp tools (except those with specific tool names)
# mcp__server(*) -> mcp__server
content = re.sub(r'(mcp__[a-z0-9_]+)\(\*\)', r'\1', content)
if content != original:
with open(file_path, 'w') as f:
f.write(content)
print(f"✅ Fixed: {file_path}")
return True
return False
PYTHON
}
# Process all agent files
echo ""
echo "📋 Fixing Agent Files..."
find "$MARKETPLACE_ROOT/plugins" -name "*.md" -path "*/agents/*" | while read -r file; do
fix_all_tool_formats "$file"
done
# Process all command files
echo ""
echo "📋 Fixing Command Files..."
find "$MARKETPLACE_ROOT/plugins" -name "*.md" -path "*/commands/*" | while read -r file; do
fix_all_tool_formats "$file"
done
# Process template files
echo ""
echo "📋 Fixing Template Files..."
find "$MARKETPLACE_ROOT/plugins/domain-plugin-builder/skills/build-assistant/templates" -name "*.md" 2>/dev/null | while read -r file; do
fix_all_tool_formats "$file"
done
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "✅ Tool Formatting Fixed!"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"

View File

@@ -0,0 +1,59 @@
#!/usr/bin/env bash
# Script: install-plugin-locally.sh
# Purpose: Install plugin to local Claude marketplace for testing
# Usage: ./install-plugin-locally.sh <plugin-directory>
set -euo pipefail
PLUGIN_DIR="${1:?Usage: $0 <plugin-directory>}"
MARKETPLACE_DIR="$HOME/.claude/plugins/marketplaces/ai-dev-marketplace"
echo "[INFO] Installing plugin to local marketplace"
# Check plugin directory exists
if [[ ! -d "$PLUGIN_DIR" ]]; then
echo "❌ ERROR: Plugin directory not found: $PLUGIN_DIR"
exit 1
fi
# Get plugin name
PLUGIN_NAME=$(basename "$PLUGIN_DIR")
# Check if marketplace exists
if [[ ! -d "$MARKETPLACE_DIR" ]]; then
echo "❌ ERROR: Marketplace not found at $MARKETPLACE_DIR"
echo "[INFO] Run: /plugin marketplace add ai-dev-marketplace"
exit 1
fi
# Check if we're in the development directory
DEV_MARKETPLACE="/home/vanman2025/Projects/ai-dev-marketplace"
CURRENT_DIR=$(pwd)
if [[ "$CURRENT_DIR" == "$DEV_MARKETPLACE" ]]; then
echo "[INFO] Running from development directory"
else
echo "⚠️ WARNING: Not in development directory"
echo "[INFO] Expected: $DEV_MARKETPLACE"
echo "[INFO] Current: $CURRENT_DIR"
fi
# Copy plugin to marketplace
echo "[INFO] Copying plugin to marketplace..."
cp -r "$PLUGIN_DIR" "$MARKETPLACE_DIR/plugins/"
# Update marketplace.json
echo "[INFO] Updating marketplace.json..."
cp .claude-plugin/marketplace.json "$MARKETPLACE_DIR/.claude-plugin/marketplace.json"
echo "✅ Plugin installed to local marketplace"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "📦 NEXT STEP: Install Plugin"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo " /plugin install $PLUGIN_NAME@ai-dev-marketplace"
echo ""
echo " Verify: /$PLUGIN_NAME:init (or any command from the plugin)"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
exit 0

View File

@@ -0,0 +1,54 @@
#!/bin/bash
# List all available agents across plugins and global directory
# Searches: plugins/*/agents/*.md and ~/.claude/agents/*.md
# Portable: Use current directory or argument (works from any location)
MARKETPLACE_DIR="${1:-$(pwd)}"
GLOBAL_AGENTS_DIR="$HOME/.claude/agents"
echo "=== Available Agents ==="
echo ""
# Track total count
TOTAL=0
# Function to extract agent info from frontmatter
extract_agent_info() {
local file="$1"
local location="$2"
# Extract name and description from frontmatter
local name=$(grep -m1 "^name:" "$file" | cut -d: -f2- | sed 's/^[[:space:]]*//' | sed 's/[[:space:]]*$//')
local desc=$(grep -m1 "^description:" "$file" | cut -d: -f2- | sed 's/^[[:space:]]*//' | sed 's/[[:space:]]*$//')
if [ -n "$name" ]; then
echo " - $name"
[ -n "$desc" ] && echo " $desc"
echo " Location: $location"
echo ""
((TOTAL++))
fi
}
# Find all plugin agents
echo "Plugin Agents:"
while IFS= read -r agent_file; do
plugin_name=$(echo "$agent_file" | sed -E 's|.*/plugins/([^/]+)/agents/.*|\1|')
extract_agent_info "$agent_file" "$plugin_name plugin"
done < <(find "$MARKETPLACE_DIR/plugins" -type f -path "*/agents/*.md" 2>/dev/null | sort)
# Find global agents
if [ -d "$GLOBAL_AGENTS_DIR" ]; then
echo "Global Agents:"
while IFS= read -r agent_file; do
extract_agent_info "$agent_file" "global"
done < <(find "$GLOBAL_AGENTS_DIR" -type f -name "*.md" 2>/dev/null | sort)
fi
echo "---"
echo "Total: $TOTAL agents available"
echo ""
echo "Built-in agents (always available):"
echo " - general-purpose: Multi-step tasks and complex questions"
echo " - Explore: Fast codebase exploration and search"

View File

@@ -0,0 +1,74 @@
#!/usr/bin/env bash
# Register plugin commands in .claude/settings.local.json
# Usage: ./register-commands-in-settings.sh <plugin-name>
set -e
PLUGIN_NAME=$1
SETTINGS_FILE="$HOME/.claude/settings.local.json"
if [ -z "$PLUGIN_NAME" ]; then
echo "Usage: $0 <plugin-name>"
echo "Example: $0 elevenlabs"
exit 1
fi
if [ ! -d "plugins/$PLUGIN_NAME" ]; then
echo "ERROR: Plugin directory plugins/$PLUGIN_NAME does not exist"
exit 1
fi
if [ ! -f "$SETTINGS_FILE" ]; then
echo "ERROR: Settings file $SETTINGS_FILE does not exist"
exit 1
fi
echo "[INFO] Registering commands for plugin: $PLUGIN_NAME"
# Get list of commands
COMMANDS=$(ls plugins/$PLUGIN_NAME/commands/*.md 2>/dev/null | sed 's|plugins/||; s|/commands/|:|; s|.md||' || true)
if [ -z "$COMMANDS" ]; then
echo "[WARN] No commands found for plugin $PLUGIN_NAME"
exit 0
fi
echo "[INFO] Found commands:"
echo "$COMMANDS"
# Check if wildcard already registered
if grep -q "\"SlashCommand(/$PLUGIN_NAME:\*)\"" "$SETTINGS_FILE"; then
echo "[INFO] Commands already registered for $PLUGIN_NAME"
exit 0
fi
echo "[INFO] Adding commands to $SETTINGS_FILE"
# Create temp file with commands to add
TEMP_COMMANDS=$(mktemp)
echo " \"SlashCommand(/$PLUGIN_NAME:*)\"," > "$TEMP_COMMANDS"
while IFS= read -r cmd; do
echo " \"SlashCommand(/$cmd)\"," >> "$TEMP_COMMANDS"
done <<< "$COMMANDS"
# Find the line before "Bash" and insert commands there
LINE_NUM=$(grep -n '"Bash"' "$SETTINGS_FILE" | head -1 | cut -d: -f1)
if [ -z "$LINE_NUM" ]; then
echo "ERROR: Could not find 'Bash' entry in $SETTINGS_FILE"
rm "$TEMP_COMMANDS"
exit 1
fi
# Insert before Bash line
head -n $((LINE_NUM - 1)) "$SETTINGS_FILE" > "${SETTINGS_FILE}.tmp"
cat "$TEMP_COMMANDS" >> "${SETTINGS_FILE}.tmp"
tail -n +$LINE_NUM "$SETTINGS_FILE" >> "${SETTINGS_FILE}.tmp"
# Replace original file
mv "${SETTINGS_FILE}.tmp" "$SETTINGS_FILE"
rm "$TEMP_COMMANDS"
echo "[SUCCESS] Commands registered for $PLUGIN_NAME"
echo "[INFO] Added $(echo "$COMMANDS" | wc -l) commands plus wildcard"

View File

@@ -0,0 +1,95 @@
#!/usr/bin/env bash
# Register plugin skills in ~/.claude/settings.json
# Usage: ./register-skills-in-settings.sh <plugin-name>
set -e
PLUGIN_NAME=$1
SETTINGS_FILE="$HOME/.claude/settings.json"
if [ -z "$PLUGIN_NAME" ]; then
echo "Usage: $0 <plugin-name>"
echo "Example: $0 domain-plugin-builder"
exit 1
fi
if [ ! -d "plugins/$PLUGIN_NAME" ]; then
echo "ERROR: Plugin directory plugins/$PLUGIN_NAME does not exist"
exit 1
fi
if [ ! -f "$SETTINGS_FILE" ]; then
echo "ERROR: Settings file $SETTINGS_FILE does not exist"
exit 1
fi
echo "[INFO] Registering skills for plugin: $PLUGIN_NAME"
# Get list of skills (directories in skills/)
SKILL_DIRS=$(find plugins/$PLUGIN_NAME/skills -maxdepth 1 -mindepth 1 -type d 2>/dev/null || true)
if [ -z "$SKILL_DIRS" ]; then
echo "[WARN] No skills found for plugin $PLUGIN_NAME"
exit 0
fi
echo "[INFO] Found skills:"
for SKILL_DIR in $SKILL_DIRS; do
SKILL_NAME=$(basename "$SKILL_DIR")
echo " - $SKILL_NAME"
done
# Check each skill and add if not already registered
for SKILL_DIR in $SKILL_DIRS; do
SKILL_NAME=$(basename "$SKILL_DIR")
SKILL_ENTRY="Skill($PLUGIN_NAME:$SKILL_NAME)"
# Check if this skill is already registered
if grep -q "\"$SKILL_ENTRY\"" "$SETTINGS_FILE"; then
echo "[INFO] Skill already registered: $SKILL_NAME"
continue
fi
echo "[INFO] Adding skill to settings.json: $SKILL_NAME"
# Find the last Skill() entry and add after it
# Use Python for JSON manipulation to ensure valid JSON
python3 << EOF
import json
with open('$SETTINGS_FILE', 'r') as f:
settings = json.load(f)
# Add skill to permissions.allow
if 'permissions' not in settings:
settings['permissions'] = {}
if 'allow' not in settings['permissions']:
settings['permissions']['allow'] = []
skill_entry = '$SKILL_ENTRY'
if skill_entry not in settings['permissions']['allow']:
# Find position after last Skill() entry
last_skill_index = -1
for i, entry in enumerate(settings['permissions']['allow']):
if isinstance(entry, str) and entry.startswith('Skill('):
last_skill_index = i
if last_skill_index >= 0:
# Insert after last skill
settings['permissions']['allow'].insert(last_skill_index + 1, skill_entry)
else:
# No skills yet, add at end
settings['permissions']['allow'].append(skill_entry)
with open('$SETTINGS_FILE', 'w') as f:
json.dump(settings, f, indent=2)
print(f"[SUCCESS] Added {skill_entry} to settings.json")
else:
print(f"[INFO] Skill already registered: {skill_entry}")
EOF
done
echo "[SUCCESS] Skill registration complete for plugin: $PLUGIN_NAME"

View File

@@ -0,0 +1,99 @@
#!/usr/bin/env bash
# Script: sync-marketplace.sh
# Purpose: Sync all plugins to marketplace.json registry
# Usage: ./sync-marketplace.sh
# This ensures marketplace.json is up-to-date with all plugins
set -euo pipefail
# Find script location and navigate to marketplace root
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
MARKETPLACE_ROOT="$(cd "$SCRIPT_DIR/../../../../.." && pwd)"
cd "$MARKETPLACE_ROOT"
MARKETPLACE_FILE=".claude-plugin/marketplace.json"
BACKUP_FILE=".claude-plugin/marketplace.json.backup"
echo "[INFO] Syncing plugins to marketplace.json in: $MARKETPLACE_ROOT"
# Find all plugins with plugin.json
PLUGINS=()
PLUGIN_JSON_FILES=$(find plugins -path "*/.claude-plugin/plugin.json" -type f | sort)
for plugin_json in $PLUGIN_JSON_FILES; do
PLUGIN_DIR=$(dirname "$(dirname "$plugin_json")")
PLUGIN_NAME=$(basename "$PLUGIN_DIR")
# Read plugin.json data
DESCRIPTION=$(python3 -c "import json; print(json.load(open('$plugin_json'))['description'])" 2>/dev/null || echo "No description")
VERSION=$(python3 -c "import json; print(json.load(open('$plugin_json'))['version'])" 2>/dev/null || echo "1.0.0")
# Extract author if exists
AUTHOR_NAME=$(python3 -c "import json; d=json.load(open('$plugin_json')); print(d.get('author', {}).get('name', 'vanman2024'))" 2>/dev/null || echo "vanman2024")
AUTHOR_EMAIL=$(python3 -c "import json; d=json.load(open('$plugin_json')); print(d.get('author', {}).get('email', 'noreply@ai-dev-marketplace.dev'))" 2>/dev/null || echo "noreply@ai-dev-marketplace.dev")
# Extract keywords if exists
KEYWORDS=$(python3 -c "import json; d=json.load(open('$plugin_json')); print(','.join(['\"' + k + '\"' for k in d.get('keywords', [])]))" 2>/dev/null || echo "")
# Build plugin entry
PLUGIN_ENTRY=$(cat <<EOF
{
"name": "$PLUGIN_NAME",
"description": "$DESCRIPTION",
"version": "$VERSION",
"author": {
"name": "$AUTHOR_NAME",
"email": "$AUTHOR_EMAIL"
},
"source": "./plugins/$PLUGIN_NAME",
"category": "development",
"keywords": [$KEYWORDS]
}
EOF
)
PLUGINS+=("$PLUGIN_ENTRY")
done
# Build marketplace.json
PLUGIN_COUNT=${#PLUGINS[@]}
PLUGINS_JSON=""
for i in "${!PLUGINS[@]}"; do
PLUGINS_JSON+="${PLUGINS[$i]}"
if [[ $i -lt $((PLUGIN_COUNT - 1)) ]]; then
PLUGINS_JSON+=","
fi
done
# Write marketplace.json
cat > "$MARKETPLACE_FILE" <<EOF
{
"name": "ai-dev-marketplace",
"version": "1.0.0",
"description": "AI Development Marketplace - Master repository for tech-specific plugins (SDKs, frameworks, platforms)",
"owner": {
"name": "AI Development Team",
"email": "noreply@ai-dev-marketplace.dev"
},
"plugins": [
$PLUGINS_JSON
]
}
EOF
# Format JSON
python3 -m json.tool "$MARKETPLACE_FILE" > "${MARKETPLACE_FILE}.tmp" && mv "${MARKETPLACE_FILE}.tmp" "$MARKETPLACE_FILE"
echo "✅ Updated marketplace.json with $PLUGIN_COUNT plugins"
# Show summary
echo ""
echo "Registered plugins in marketplace:"
for plugin_json in $PLUGIN_JSON_FILES; do
PLUGIN_DIR=$(dirname "$(dirname "$plugin_json")")
PLUGIN_NAME=$(basename "$PLUGIN_DIR")
VERSION=$(python3 -c "import json; print(json.load(open('$plugin_json'))['version'])" 2>/dev/null || echo "1.0.0")
echo " - $PLUGIN_NAME (v$VERSION)"
done

View File

@@ -0,0 +1,93 @@
#!/usr/bin/env bash
# Script: sync-settings-permissions.sh
# Purpose: Automatically sync all plugin commands to .claude/settings.local.json
# Usage: ./sync-settings-permissions.sh
# This ensures all commands are registered and can be invoked
set -euo pipefail
# Find script location and navigate to marketplace root
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
MARKETPLACE_ROOT="$(cd "$SCRIPT_DIR/../../../../.." && pwd)"
cd "$MARKETPLACE_ROOT"
SETTINGS_FILE="$HOME/.claude/settings.local.json"
BACKUP_FILE="$HOME/.claude/settings.local.json.backup"
echo "[INFO] Syncing plugin commands to settings.local.json from: $MARKETPLACE_ROOT"
# Find all plugins
PLUGINS=$(find plugins -mindepth 1 -maxdepth 1 -type d | sort)
# Build command list
COMMANDS=()
for plugin in $PLUGINS; do
PLUGIN_NAME=$(basename "$plugin")
# Check if plugin has commands
if [[ -d "$plugin/commands" ]]; then
# Add wildcard permission for the plugin
COMMANDS+=(" \"SlashCommand(/$PLUGIN_NAME:*)\"")
# Find all command files
COMMAND_FILES=$(find "$plugin/commands" -name "*.md" -type f | sort)
for cmd_file in $COMMAND_FILES; do
CMD_NAME=$(basename "$cmd_file" .md)
COMMANDS+=(" \"SlashCommand(/$PLUGIN_NAME:$CMD_NAME)\"")
done
fi
done
# Add base tools
BASE_TOOLS=(
"Bash"
"Write"
"Read"
"Edit"
"WebFetch"
"WebSearch"
"AskUserQuestion"
"Glob"
"Grep"
"Task"
"Skill"
)
for tool in "${BASE_TOOLS[@]}"; do
COMMANDS+=(" \"$tool\"")
done
# Build JSON
cat > "$SETTINGS_FILE" <<EOF
{
"permissions": {
"allow": [
$(IFS=$',\n'; echo "${COMMANDS[*]}")
]
},
"enableAllProjectMcpServers": true,
"enabledMcpjsonServers": [
"filesystem",
"playwright",
"context7",
"postman"
]
}
EOF
echo "✅ Updated settings.local.json with $(echo "${COMMANDS[@]}" | wc -w) permissions"
echo "[INFO] All plugin commands are now registered"
# Show summary
echo ""
echo "Registered plugins:"
for plugin in $PLUGINS; do
PLUGIN_NAME=$(basename "$plugin")
CMD_COUNT=$(find "$plugin/commands" -name "*.md" -type f 2>/dev/null | wc -l || echo "0")
if [[ $CMD_COUNT -gt 0 ]]; then
echo " - $PLUGIN_NAME ($CMD_COUNT commands)"
fi
done

View File

@@ -0,0 +1,78 @@
#!/usr/bin/env bash
# Script: sync-to-local-marketplace.sh
# Purpose: Automatically sync development directory to installed marketplace
# Usage: ./sync-to-local-marketplace.sh [plugin-name]
# Called by: git pre-commit hook (automatic) or manually
set -euo pipefail
DEV_DIR="/home/vanman2025/Projects/ai-dev-marketplace"
MARKETPLACE_DIR="$HOME/.claude/plugins/marketplaces/ai-dev-marketplace"
# Check if marketplace exists
if [[ ! -d "$MARKETPLACE_DIR" ]]; then
echo "[INFO] Marketplace not installed at $MARKETPLACE_DIR"
echo "[INFO] Run: /plugin marketplace add vanman2024/ai-dev-marketplace"
exit 0 # Not an error - just not installed
fi
# Check if marketplace is a git repo
if [[ ! -d "$MARKETPLACE_DIR/.git" ]]; then
echo "⚠️ WARNING: Marketplace is not a git repository"
echo "[INFO] Expected git clone, found regular directory"
exit 1
fi
cd "$DEV_DIR"
# If plugin name provided, sync only that plugin
if [[ -n "${1:-}" ]]; then
PLUGIN_NAME="$1"
echo "[INFO] Syncing plugin: $PLUGIN_NAME"
if [[ ! -d "plugins/$PLUGIN_NAME" ]]; then
echo "❌ ERROR: Plugin not found: plugins/$PLUGIN_NAME"
exit 1
fi
# Copy plugin directory
rsync -av --delete "plugins/$PLUGIN_NAME/" "$MARKETPLACE_DIR/plugins/$PLUGIN_NAME/"
echo "✅ Synced plugin: $PLUGIN_NAME"
else
# Sync entire repository
echo "[INFO] Syncing entire marketplace..."
# Sync all plugins
rsync -av --delete plugins/ "$MARKETPLACE_DIR/plugins/"
# Sync marketplace.json
rsync -av .claude-plugin/marketplace.json "$MARKETPLACE_DIR/.claude-plugin/marketplace.json"
# Sync other important files
rsync -av README.md "$MARKETPLACE_DIR/README.md"
echo "✅ Synced all plugins and marketplace metadata"
fi
# Show what was synced
cd "$MARKETPLACE_DIR"
git status --short || true
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "📦 LOCAL MARKETPLACE SYNCED"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "Changes are immediately available to Claude Code!"
echo ""
echo "To sync these changes to GitHub:"
echo " 1. cd $DEV_DIR"
echo " 2. git add -A && git commit -m 'feat: ...'"
echo " 3. git push origin master"
echo ""
echo "To pull GitHub changes to local marketplace:"
echo " /plugin marketplace update ai-dev-marketplace"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
exit 0

View File

@@ -0,0 +1,163 @@
#!/usr/bin/env bash
# Script: test-build-system.sh
# Purpose: Automated testing for domain-plugin-builder infrastructure
# Usage: ./test-build-system.sh [--quick|--full]
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PLUGIN_DIR="$HOME/.claude/plugins/marketplaces/domain-plugin-builder/plugins/domain-plugin-builder"
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
PASSED=0
FAILED=0
SKIPPED=0
echo "================================================"
echo "Domain Plugin Builder Testing Suite"
echo "================================================"
echo ""
echo "Testing: $PLUGIN_DIR"
echo ""
# Test functions
test_file_exists() {
local file=$1
if [ -f "$file" ]; then
echo -e "${GREEN}${NC} $file"
PASSED=$((PASSED + 1))
return 0
else
echo -e "${RED}${NC} $file (missing)"
FAILED=$((FAILED + 1))
return 1
fi
}
test_dir_exists() {
local dir=$1
if [ -d "$dir" ]; then
echo -e "${GREEN}${NC} $dir/"
PASSED=$((PASSED + 1))
return 0
else
echo -e "${RED}${NC} $dir/ (missing)"
FAILED=$((FAILED + 1))
return 1
fi
}
test_executable() {
local file=$1
if [ -x "$file" ]; then
echo -e "${GREEN}${NC} $file (executable)"
PASSED=$((PASSED + 1))
return 0
else
echo -e "${RED}${NC} $file (not executable)"
FAILED=$((FAILED + 1))
return 1
fi
}
# Test 1: Core Directory Structure
echo "[1/8] Testing Core Directory Structure..."
test_dir_exists "$PLUGIN_DIR/commands"
test_dir_exists "$PLUGIN_DIR/agents"
test_dir_exists "$PLUGIN_DIR/skills"
test_dir_exists "$PLUGIN_DIR/docs"
test_dir_exists "$PLUGIN_DIR/skills/build-assistant/scripts"
test_dir_exists "$PLUGIN_DIR/skills/build-assistant/templates"
echo ""
# Test 2: Commands
echo "[2/8] Testing Commands..."
test_file_exists "$PLUGIN_DIR/commands/plugin-create.md"
test_file_exists "$PLUGIN_DIR/commands/build-plugin.md"
test_file_exists "$PLUGIN_DIR/commands/agents-create.md"
test_file_exists "$PLUGIN_DIR/commands/slash-commands-create.md"
test_file_exists "$PLUGIN_DIR/commands/skills-create.md"
test_file_exists "$PLUGIN_DIR/commands/hooks-create.md"
test_file_exists "$PLUGIN_DIR/commands/validate.md"
echo ""
# Test 3: Agents
echo "[3/8] Testing Agents..."
test_file_exists "$PLUGIN_DIR/agents/agents-builder.md"
test_file_exists "$PLUGIN_DIR/agents/slash-commands-builder.md"
test_file_exists "$PLUGIN_DIR/agents/skills-builder.md"
test_file_exists "$PLUGIN_DIR/agents/hooks-builder.md"
test_file_exists "$PLUGIN_DIR/agents/plugin-validator.md"
echo ""
# Test 4: Skills
echo "[4/8] Testing Skills..."
test_dir_exists "$PLUGIN_DIR/skills/build-assistant"
test_file_exists "$PLUGIN_DIR/skills/build-assistant/SKILL.md"
test_file_exists "$PLUGIN_DIR/skills/build-assistant/reference.md"
test_file_exists "$PLUGIN_DIR/skills/build-assistant/examples.md"
echo ""
# Test 5: Templates
echo "[5/8] Testing Templates..."
test_dir_exists "$PLUGIN_DIR/skills/build-assistant/templates/agents"
test_dir_exists "$PLUGIN_DIR/skills/build-assistant/templates/commands"
test_dir_exists "$PLUGIN_DIR/skills/build-assistant/templates/skills"
test_file_exists "$PLUGIN_DIR/skills/build-assistant/templates/agents/agent-with-phased-webfetch.md"
test_file_exists "$PLUGIN_DIR/skills/build-assistant/templates/commands/template-command-patterns.md"
test_file_exists "$PLUGIN_DIR/skills/build-assistant/templates/skills/SKILL.md.template"
echo ""
# Test 6: Documentation
echo "[6/8] Testing Documentation..."
test_file_exists "$PLUGIN_DIR/README.md"
test_file_exists "$PLUGIN_DIR/CLAUDE.md"
test_dir_exists "$PLUGIN_DIR/docs/frameworks/claude"
test_dir_exists "$PLUGIN_DIR/docs/frameworks/claude/agents"
test_dir_exists "$PLUGIN_DIR/docs/frameworks/claude/plugins"
test_dir_exists "$PLUGIN_DIR/docs/frameworks/claude/reference"
test_file_exists "$PLUGIN_DIR/docs/frameworks/claude/agents/agent-color-decision.md"
test_file_exists "$PLUGIN_DIR/docs/frameworks/claude/agents/agent-color-standard.md"
test_file_exists "$PLUGIN_DIR/docs/frameworks/claude/reference/component-decision-framework.md"
test_file_exists "$PLUGIN_DIR/docs/frameworks/claude/reference/dans-composition-pattern.md"
echo ""
# Test 7: Validation Scripts
echo "[7/8] Testing Validation Scripts..."
test_executable "$PLUGIN_DIR/skills/build-assistant/scripts/validate-agent.sh"
test_executable "$PLUGIN_DIR/skills/build-assistant/scripts/validate-command.sh"
test_executable "$PLUGIN_DIR/skills/build-assistant/scripts/validate-skill.sh"
test_executable "$PLUGIN_DIR/skills/build-assistant/scripts/validate-plugin.sh"
test_executable "$PLUGIN_DIR/skills/build-assistant/scripts/validate-all.sh"
test_executable "$PLUGIN_DIR/skills/build-assistant/scripts/sync-marketplace.sh"
test_executable "$PLUGIN_DIR/skills/build-assistant/scripts/register-commands-in-settings.sh"
test_executable "$PLUGIN_DIR/skills/build-assistant/scripts/register-skills-in-settings.sh"
echo ""
# Test 8: Configuration Files
echo "[8/8] Testing Configuration Files..."
test_file_exists "$PLUGIN_DIR/.claude-plugin/plugin.json"
test_file_exists "$HOME/.claude/plugins/marketplaces/domain-plugin-builder/docs/security/SECURITY-RULES.md"
echo ""
# Summary
echo "================================================"
echo "Test Summary"
echo "================================================"
echo -e "${GREEN}Passed:${NC} $PASSED"
echo -e "${RED}Failed:${NC} $FAILED"
echo -e "${YELLOW}Skipped:${NC} $SKIPPED"
echo ""
if [ $FAILED -eq 0 ]; then
echo -e "${GREEN}✓ All tests passed!${NC}"
exit 0
else
echo -e "${RED}✗ Some tests failed${NC}"
exit 1
fi

View File

@@ -0,0 +1,88 @@
#!/bin/bash
# Validate that all agent references in commands exist
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PLUGIN_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
if [ $# -eq 0 ]; then
echo "Usage: $0 <plugin-path>"
echo "Example: $0 plugins/domain-plugin-builder"
exit 1
fi
PLUGIN_PATH="$1"
if [ ! -d "$PLUGIN_PATH" ]; then
echo "❌ Error: Plugin directory not found: $PLUGIN_PATH"
exit 1
fi
echo "🔍 Validating agent references in: $PLUGIN_PATH"
echo ""
# Extract all agent references from commands
AGENT_REFS=$(grep -rh 'subagent_type="[^"]*"' "$PLUGIN_PATH/commands/" 2>/dev/null | \
grep -o 'subagent_type="[^"]*"' | \
sed 's/subagent_type="//; s/"$//' | \
sed 's/.*://' | \
sort -u)
if [ -z "$AGENT_REFS" ]; then
echo "✅ No agent references found in commands"
exit 0
fi
TOTAL=0
VALID=0
INVALID=0
MISSING_AGENTS=()
echo "📋 Checking agent references..."
echo ""
for agent in $AGENT_REFS; do
TOTAL=$((TOTAL + 1))
AGENT_FILE="$PLUGIN_PATH/agents/${agent}.md"
if [ -f "$AGENT_FILE" ]; then
echo "$agent"
VALID=$((VALID + 1))
else
echo "$agent (MISSING: $AGENT_FILE)"
INVALID=$((INVALID + 1))
MISSING_AGENTS+=("$agent")
fi
done
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "📊 Summary:"
echo " Total agent references: $TOTAL"
echo " Valid: $VALID"
echo " Invalid: $INVALID"
echo ""
if [ $INVALID -gt 0 ]; then
echo "❌ VALIDATION FAILED"
echo ""
echo "Commands reference non-existent agents:"
for agent in "${MISSING_AGENTS[@]}"; do
echo " - $agent (referenced in commands but agents/$agent.md doesn't exist)"
done
echo ""
echo "🔧 FIX THIS BY:"
echo " 1. Check which commands reference these agents:"
echo " grep -r 'subagent_type=\".*:$agent\"' $PLUGIN_PATH/commands/"
echo ""
echo " 2. Update commands to use ACTUAL agent names from agents/ directory:"
echo " ls $PLUGIN_PATH/agents/"
echo ""
echo " 3. Fix the subagent_type in commands to match real agent filenames"
echo ""
echo "❌ DO NOT create new agents to match wrong command references!"
echo "✅ FIX the commands to use correct existing agent names!"
exit 1
else
echo "✅ ALL AGENT REFERENCES VALID"
exit 0
fi

View File

@@ -0,0 +1,68 @@
#!/usr/bin/env bash
# Script: validate-agent.sh
# Purpose: Validate agent file compliance with framework standards
# Subsystem: build-system
# Called by: /build:agent command after generation
# Outputs: Validation report to stdout
set -euo pipefail
AGENT_FILE="${1:?Usage: $0 <agent-file>}"
echo "[INFO] Validating agent file: $AGENT_FILE"
# Check file exists
if [[ ! -f "$AGENT_FILE" ]]; then
echo "❌ ERROR: File not found: $AGENT_FILE"
exit 1
fi
# Check frontmatter exists
if ! grep -q "^---$" "$AGENT_FILE"; then
echo "❌ ERROR: Missing frontmatter"
exit 1
fi
# Check required frontmatter fields
REQUIRED_FIELDS=("name:" "description:" "model:")
for field in "${REQUIRED_FIELDS[@]}"; do
if ! grep -q "^$field" "$AGENT_FILE"; then
echo "❌ ERROR: Missing required field: $field"
exit 1
fi
done
# Warn if tools field is present (agents should inherit tools)
if grep -q "^tools:" "$AGENT_FILE"; then
echo "⚠️ WARNING: tools field found - agents should inherit tools from parent, not specify them"
fi
# Check for incorrect MCP server naming (common mistake: mcp__supabase instead of mcp__plugin_supabase_supabase)
INVALID_MCP_NAMES=("mcp__supabase" "mcp__shadcn" "mcp__nextjs" "mcp__vercel-ai")
for invalid_name in "${INVALID_MCP_NAMES[@]}"; do
if grep -q "\`$invalid_name\`" "$AGENT_FILE" 2>/dev/null; then
echo "❌ ERROR: Found $invalid_name - plugin-specific MCP servers must use full name:"
echo " - Use: mcp__plugin_supabase_supabase (not mcp__supabase)"
echo " - Use: mcp__plugin_*_shadcn (not mcp__shadcn)"
echo " Generic MCP servers are fine: mcp__github, mcp__filesystem, mcp__docker, mcp__fetch, etc."
exit 1
fi
done
# Check Step 0 exists (optional - only for validator agents)
if ! grep -q "### Step 0: Load Required Context" "$AGENT_FILE"; then
echo "⚠️ WARNING: Missing Step 0: Load Required Context section (only required for validator agents)"
fi
# Check for @ symbol references
if ! grep -q 'Read("' "$AGENT_FILE"; then
echo "⚠️ WARNING: No Read() calls found - agent may not load context"
fi
# Check Success Criteria exists (optional - only for validator agents)
if ! grep -q "## Success Criteria" "$AGENT_FILE"; then
echo "⚠️ WARNING: Missing Success Criteria section (only required for validator agents)"
fi
echo "✅ Agent validation passed"
exit 0

View File

@@ -0,0 +1,157 @@
#!/usr/bin/env bash
# validate-all.sh - Master validation script for entire plugin
# Usage: validate-all.sh <plugin-directory>
set -euo pipefail
PLUGIN_DIR="${1:?Plugin directory required}"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Counters
TOTAL_COMMANDS=0
PASSED_COMMANDS=0
TOTAL_AGENTS=0
PASSED_AGENTS=0
TOTAL_SKILLS=0
PASSED_SKILLS=0
echo "========================================="
echo " Plugin Validation: $(basename "$PLUGIN_DIR")"
echo "========================================="
echo ""
# Validate plugin structure
echo "[1/4] Validating plugin structure..."
if bash "$SCRIPT_DIR/validate-plugin.sh" "$PLUGIN_DIR"; then
echo -e "${GREEN}✅ Plugin structure valid${NC}"
else
echo -e "${RED}❌ Plugin structure invalid${NC}"
exit 1
fi
echo ""
# Validate all commands
echo "[2/4] Validating commands..."
if [ -d "$PLUGIN_DIR/commands" ]; then
for cmd in "$PLUGIN_DIR/commands"/*.md; do
if [ -f "$cmd" ]; then
TOTAL_COMMANDS=$((TOTAL_COMMANDS + 1))
CMD_NAME=$(basename "$cmd")
if bash "$SCRIPT_DIR/validate-command.sh" "$cmd" > /dev/null 2>&1; then
PASSED_COMMANDS=$((PASSED_COMMANDS + 1))
echo -e " ${GREEN}${NC} $CMD_NAME"
else
echo -e " ${RED}${NC} $CMD_NAME"
# Show errors for failed commands
bash "$SCRIPT_DIR/validate-command.sh" "$cmd" 2>&1 | grep -E "ERROR|WARNING" || true
fi
fi
done
else
echo -e "${YELLOW}⚠ No commands directory found${NC}"
fi
echo ""
echo "Commands: $PASSED_COMMANDS/$TOTAL_COMMANDS passed"
echo ""
# Validate all agents
echo "[3/4] Validating agents..."
if [ -d "$PLUGIN_DIR/agents" ]; then
for agent in "$PLUGIN_DIR/agents"/*.md; do
if [ -f "$agent" ]; then
TOTAL_AGENTS=$((TOTAL_AGENTS + 1))
AGENT_NAME=$(basename "$agent")
if bash "$SCRIPT_DIR/validate-agent.sh" "$agent" > /dev/null 2>&1; then
PASSED_AGENTS=$((PASSED_AGENTS + 1))
echo -e " ${GREEN}${NC} $AGENT_NAME"
else
echo -e " ${RED}${NC} $AGENT_NAME"
# Show errors for failed agents
bash "$SCRIPT_DIR/validate-agent.sh" "$agent" 2>&1 | grep -E "ERROR|WARNING" || true
fi
fi
done
else
echo -e "${YELLOW}⚠ No agents directory found${NC}"
fi
echo ""
echo "Agents: $PASSED_AGENTS/$TOTAL_AGENTS passed"
echo ""
# Validate all skills
echo "[4/5] Validating skills..."
if [ -d "$PLUGIN_DIR/skills" ]; then
for skill_dir in "$PLUGIN_DIR/skills"/*/; do
if [ -d "$skill_dir" ]; then
TOTAL_SKILLS=$((TOTAL_SKILLS + 1))
SKILL_NAME=$(basename "$skill_dir")
if bash "$SCRIPT_DIR/validate-skill.sh" "$skill_dir" > /dev/null 2>&1; then
PASSED_SKILLS=$((PASSED_SKILLS + 1))
echo -e " ${GREEN}${NC} $SKILL_NAME"
else
echo -e " ${RED}${NC} $SKILL_NAME"
fi
fi
done
if [ $TOTAL_SKILLS -eq 0 ]; then
echo -e "${YELLOW}⚠ Skills directory empty${NC}"
fi
else
echo -e "${YELLOW}⚠ No skills directory found${NC}"
fi
echo ""
if [ $TOTAL_SKILLS -gt 0 ]; then
echo "Skills: $PASSED_SKILLS/$TOTAL_SKILLS passed"
fi
echo ""
# Validate plugin completeness (templates, examples, scripts)
echo "[5/5] Validating plugin completeness..."
if bash "$SCRIPT_DIR/validate-plugin-completeness.sh" "$PLUGIN_DIR"; then
echo -e "${GREEN}✅ Plugin completeness check passed${NC}"
else
echo -e "${RED}❌ Plugin completeness check failed${NC}"
echo "Some skills may be missing templates, examples, or scripts."
fi
echo ""
# Summary
echo "========================================="
echo " Validation Summary"
echo "========================================="
echo ""
echo "Commands: $PASSED_COMMANDS/$TOTAL_COMMANDS"
echo "Agents: $PASSED_AGENTS/$TOTAL_AGENTS"
if [ $TOTAL_SKILLS -gt 0 ]; then
echo "Skills: $PASSED_SKILLS/$TOTAL_SKILLS"
fi
echo ""
# Calculate total
TOTAL=$((TOTAL_COMMANDS + TOTAL_AGENTS + TOTAL_SKILLS))
PASSED=$((PASSED_COMMANDS + PASSED_AGENTS + PASSED_SKILLS))
if [ $PASSED -eq $TOTAL ]; then
echo -e "${GREEN}✅ ALL VALIDATIONS PASSED ($PASSED/$TOTAL)${NC}"
echo ""
exit 0
else
FAILED=$((TOTAL - PASSED))
echo -e "${RED}❌ VALIDATION FAILED: $FAILED failures out of $TOTAL total${NC}"
echo ""
echo "Fix the failed validations and run again."
exit 1
fi

View File

@@ -0,0 +1,109 @@
#!/usr/bin/env bash
# Script: validate-and-sync-all.sh
# Purpose: Complete validation and synchronization of all plugins
# Usage: ./validate-and-sync-all.sh
# This is the MASTER script that ensures everything is in sync
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
echo "========================================="
echo " Plugin System Validation & Sync"
echo "========================================="
echo ""
# Step 1: Validate all individual plugins
echo "[STEP 1/4] Validating individual plugins..."
echo ""
PLUGINS=$(find plugins -mindepth 1 -maxdepth 1 -type d -name "*" ! -name ".*" | sort)
PLUGIN_COUNT=0
VALID_COUNT=0
INVALID_COUNT=0
for plugin in $PLUGINS; do
((PLUGIN_COUNT++))
PLUGIN_NAME=$(basename "$plugin")
# Check if has .claude-plugin directory (skip if not a valid plugin)
if [[ ! -d "$plugin/.claude-plugin" ]]; then
echo " ⏭️ Skipping $PLUGIN_NAME (not a Claude Code plugin)"
continue
fi
echo " Validating: $PLUGIN_NAME"
if bash "$SCRIPT_DIR/validate-plugin.sh" "$plugin" 2>&1 | grep -q "✅"; then
((VALID_COUNT++))
else
((INVALID_COUNT++))
echo " ❌ Validation failed for $PLUGIN_NAME"
fi
done
echo ""
echo " Plugins found: $PLUGIN_COUNT"
echo " Valid: $VALID_COUNT"
echo " Invalid: $INVALID_COUNT"
echo ""
# Step 2: Sync all commands to settings.local.json
echo "[STEP 2/4] Syncing commands to settings.local.json..."
echo ""
bash "$SCRIPT_DIR/sync-settings-permissions.sh"
echo ""
# Step 3: Sync all plugins to marketplace.json
echo "[STEP 3/4] Syncing plugins to marketplace.json..."
echo ""
bash "$SCRIPT_DIR/sync-marketplace.sh"
echo ""
# Step 4: Final validation
echo "[STEP 4/4] Final validation checks..."
echo ""
# Check settings.local.json is valid JSON
if python3 -m json.tool "$HOME/.claude/settings.local.json" > /dev/null 2>&1; then
echo " ✅ settings.local.json is valid JSON"
else
echo " ❌ settings.local.json is INVALID JSON"
exit 1
fi
# Check marketplace.json is valid JSON
if python3 -m json.tool .claude-plugin/marketplace.json > /dev/null 2>&1; then
echo " ✅ marketplace.json is valid JSON"
else
echo " ❌ marketplace.json is INVALID JSON"
exit 1
fi
# Count registrations
SETTINGS_PERMISSIONS=$(grep -c "SlashCommand" "$HOME/.claude/settings.local.json" || echo "0")
MARKETPLACE_PLUGINS=$(python3 -c "import json; print(len(json.load(open('.claude-plugin/marketplace.json'))['plugins']))" 2>/dev/null || echo "0")
echo "$SETTINGS_PERMISSIONS slash commands registered in settings"
echo "$MARKETPLACE_PLUGINS plugins registered in marketplace"
echo ""
echo "========================================="
echo " ✅ All validations passed!"
echo "========================================="
echo ""
echo "Summary:"
echo " - Plugins validated: $VALID_COUNT/$PLUGIN_COUNT"
echo " - Commands registered: $SETTINGS_PERMISSIONS"
echo " - Marketplace entries: $MARKETPLACE_PLUGINS"
echo ""
echo "Next steps:"
echo " 1. Test a command: /fastmcp:new-server my-test"
echo " 2. Commit changes: git add .claude/ .claude-plugin/"
echo " 3. Review docs: cat SETTINGS-SYNC-GUIDE.md"
echo ""
exit 0

View File

@@ -0,0 +1,105 @@
#!/bin/bash
# validate-argument-hints.sh
# Validates command argument-hint frontmatter for proper formatting
PLUGIN_DIR="${1:-.}"
ISSUES_FOUND=0
echo "=== Validating Command Argument Hints ==="
echo ""
# Check if directory exists
if [ ! -d "$PLUGIN_DIR" ]; then
echo "❌ ERROR: Directory not found: $PLUGIN_DIR"
exit 1
fi
# Find all command files
COMMAND_FILES=$(find "$PLUGIN_DIR" -type f -path "*/commands/*.md" 2>/dev/null)
if [ -z "$COMMAND_FILES" ]; then
echo "⚠️ No command files found in $PLUGIN_DIR"
exit 0
fi
echo "Scanning command files..."
echo ""
while IFS= read -r file; do
# Extract argument-hint from frontmatter
HINT=$(sed -n '/^---$/,/^---$/p' "$file" | grep "^argument-hint:" | sed 's/argument-hint: *//')
if [ -z "$HINT" ]; then
echo "⚠️ MISSING argument-hint: $file"
((ISSUES_FOUND++))
continue
fi
# Check for old "subsystem" terminology
if echo "$HINT" | grep -qi "subsystem"; then
echo "❌ LEGACY TERM 'subsystem': $file"
echo " Current: $HINT"
echo " Should use: <plugin-name>, <spec-directory>, or specific argument"
echo ""
((ISSUES_FOUND++))
fi
# Check for proper formatting patterns
# Valid patterns: <required>, [optional], <arg1> <arg2>, [--flag]
# Check if using proper brackets
if ! echo "$HINT" | grep -qE '(<[^>]+>|\[.*\]|--[a-z-]+)'; then
# If no brackets at all and not empty
if [ "$HINT" != "none" ] && [ "$HINT" != "" ]; then
echo "⚠️ IMPROPER FORMAT (missing brackets): $file"
echo " Current: $HINT"
echo " Should use: <required-arg> or [optional-arg] or [--flag]"
echo ""
((ISSUES_FOUND++))
fi
fi
# Check for common bad patterns
if echo "$HINT" | grep -qE '\$[0-9]|\$ARGUMENTS|multiagent_core'; then
echo "❌ CONTAINS VARIABLES/LEGACY: $file"
echo " Current: $HINT"
echo " Should be: Plain text description, not variable references"
echo ""
((ISSUES_FOUND++))
fi
# Check for overly generic hints
if [ "$HINT" = "<args>" ] || [ "$HINT" = "[args]" ] || [ "$HINT" = "args" ]; then
echo "⚠️ TOO GENERIC: $file"
echo " Current: $HINT"
echo " Should be: Specific argument names (e.g., <spec-directory> [--type=TYPE])"
echo ""
((ISSUES_FOUND++))
fi
done <<< "$COMMAND_FILES"
echo ""
echo "=== Summary ==="
if [ $ISSUES_FOUND -eq 0 ]; then
echo "✅ All argument hints are properly formatted"
exit 0
else
echo "❌ Found $ISSUES_FOUND issue(s) with argument hints"
echo ""
echo "Valid formats:"
echo " <required-arg> - Required argument"
echo " [optional-arg] - Optional argument"
echo " <arg1> <arg2> - Multiple arguments"
echo " [--flag] - Optional flag"
echo " <spec> [--type=TYPE] - Mixed required/optional"
echo " none - No arguments"
echo ""
echo "Bad patterns:"
echo " ❌ subsystem - Use 'plugin-name' or 'spec-directory'"
echo " ❌ \$1, \$ARGUMENTS - No variable references"
echo " ❌ args - Too generic, be specific"
echo " ❌ No brackets - Must use <> or [] or --"
exit 1
fi

View File

@@ -0,0 +1,148 @@
#!/usr/bin/env bash
# Script: validate-command.sh
# Purpose: Validate slash command file compliance with framework standards
# Subsystem: build-system
# Called by: framework-slash-command after generation
# Outputs: Validation report to stdout
set -euo pipefail
COMMAND_FILE="${1:?Usage: $0 <command-file>}"
EXIT_CODE=0
echo "[INFO] Validating command file: $COMMAND_FILE"
echo ""
# Check file exists
if [[ ! -f "$COMMAND_FILE" ]]; then
echo "❌ ERROR: File not found: $COMMAND_FILE"
exit 1
fi
# Check frontmatter exists
if ! grep -q "^---$" "$COMMAND_FILE"; then
echo "❌ ERROR: Missing frontmatter"
EXIT_CODE=1
fi
# Check required frontmatter fields
REQUIRED_FIELDS=("allowed-tools:" "description:")
for field in "${REQUIRED_FIELDS[@]}"; do
if ! grep -q "^$field" "$COMMAND_FILE"; then
echo "❌ ERROR: Missing required field: $field"
EXIT_CODE=1
fi
done
# Check file length (target: 120-150, allow 15% overage = 172)
LINE_COUNT=$(wc -l < "$COMMAND_FILE")
TARGET_MAX=150
TOLERANCE_MAX=172 # 150 + 15% overage
if ((LINE_COUNT > TOLERANCE_MAX)); then
echo "❌ ERROR: Command file is $LINE_COUNT lines (max: $TOLERANCE_MAX with 15% tolerance)"
EXIT_CODE=1
elif ((LINE_COUNT > TARGET_MAX)); then
OVERAGE=$((LINE_COUNT - TARGET_MAX))
echo "⚠️ WARNING: Command file is $LINE_COUNT lines (target: $TARGET_MAX, +$OVERAGE over)"
elif ((LINE_COUNT < 50)); then
echo "⚠️ WARNING: Command file is $LINE_COUNT lines (might be too short)"
fi
# Check for $ARGUMENTS usage (not $1, $2, $3)
if grep -qE '\$[0-9]' "$COMMAND_FILE"; then
echo "❌ ERROR: Found \$1/\$2/\$3 - use \$ARGUMENTS instead"
EXIT_CODE=1
fi
if grep -q '\$ARGUMENTS' "$COMMAND_FILE" || grep -q 'DOLLAR_ARGUMENTS' "$COMMAND_FILE"; then
echo "✅ Uses \$ARGUMENTS correctly"
else
echo "⚠️ WARNING: No \$ARGUMENTS found"
fi
# Check for agent invocation patterns
USES_NATURAL_LANGUAGE=false
USES_EXPLICIT_TASK=false
USES_PARALLEL_PATTERN=false
# Check for natural language agent invocation
if grep -qiE "(Invoke the|Launch.*agent|Run.*agent)" "$COMMAND_FILE"; then
USES_NATURAL_LANGUAGE=true
fi
# Check for explicit Task tool with subagent_type
if grep -q "subagent_type=" "$COMMAND_FILE"; then
USES_EXPLICIT_TASK=true
fi
# Check for parallel execution pattern
if grep -qiE "(in parallel|IN PARALLEL|simultaneously|all at once)" "$COMMAND_FILE"; then
USES_PARALLEL_PATTERN=true
fi
# Validate invocation patterns
if $USES_NATURAL_LANGUAGE || $USES_EXPLICIT_TASK; then
if $USES_NATURAL_LANGUAGE; then
echo "✅ Uses agent invocation (natural language)"
fi
if $USES_EXPLICIT_TASK; then
echo "✅ Uses explicit Task tool with subagent_type"
fi
# If parallel pattern detected, check for proper implementation
if $USES_PARALLEL_PATTERN; then
echo "✅ Uses parallel execution pattern"
# Check if it properly explains Task tool usage for parallel
if grep -q "Task tool" "$COMMAND_FILE" && grep -q "SAME.*message\|single.*message\|ONE message" "$COMMAND_FILE"; then
echo "✅ Properly explains parallel Task tool execution (multiple calls in ONE message)"
elif $USES_EXPLICIT_TASK; then
echo "✅ Uses explicit Task tool (parallel execution implied)"
else
echo "⚠️ WARNING: Parallel pattern found but no Task tool explanation"
echo " Consider adding explicit Task tool syntax for clarity"
fi
fi
else
echo "⚠️ WARNING: No agent invocation found - might be Pattern 1 (simple command)"
fi
# Check for backticks in examples (causes parsing issues)
if grep -q '`' "$COMMAND_FILE"; then
BACKTICK_COUNT=$(grep -o '`' "$COMMAND_FILE" | wc -l)
echo "⚠️ WARNING: Found $BACKTICK_COUNT backticks - may cause parsing issues"
fi
# Check for code blocks (should NOT be in slash commands - use scripts instead)
if grep -q "\`\`\`" "$COMMAND_FILE"; then
CODE_BLOCK_COUNT=$(grep -c "\`\`\`" "$COMMAND_FILE")
echo "❌ ERROR: Found code blocks (triple backticks) - move code to scripts"
EXIT_CODE=1
fi
# Check for proper allowed-tools format
if grep -q "allowed-tools:.*Task(\*)" "$COMMAND_FILE"; then
echo "✅ Proper allowed-tools format found"
else
echo "⚠️ WARNING: allowed-tools may not be properly formatted"
fi
# Check for bash execution patterns (! prefix)
if grep -q '!{' "$COMMAND_FILE"; then
echo "✅ Uses bash execution pattern !{command}"
fi
# Check for file loading patterns (@ prefix)
if grep -q '@/' "$COMMAND_FILE" || grep -q '@[a-zA-Z]' "$COMMAND_FILE"; then
echo "✅ Uses file loading pattern @filename"
fi
echo ""
if [ $EXIT_CODE -eq 0 ]; then
echo "✅ Command validation passed"
else
echo "❌ Command validation failed"
fi
exit $EXIT_CODE

View File

@@ -0,0 +1,108 @@
#!/bin/bash
# Validate that all plugin skills have sufficient content in templates, scripts, and examples
set -e
# Use current directory if no argument provided (portable - works from any location)
PLUGIN_DIR="${1:-$(pwd)}"
MIN_EXAMPLES=3
MIN_SCRIPTS=3
MIN_TEMPLATES_PER_DIR=2
echo "🔍 Validating Plugin Completeness: $(basename $PLUGIN_DIR)"
echo "================================================"
ISSUES_FOUND=0
# Find all skills
for SKILL_DIR in "$PLUGIN_DIR/skills"/*; do
if [ ! -d "$SKILL_DIR" ]; then
continue
fi
SKILL_NAME=$(basename "$SKILL_DIR")
echo ""
echo "📦 Skill: $SKILL_NAME"
echo "----------------------------------------"
# Check SKILL.md exists
if [ ! -f "$SKILL_DIR/SKILL.md" ]; then
echo " ❌ SKILL.md is missing"
((ISSUES_FOUND++))
else
echo " ✅ SKILL.md exists"
fi
# Check scripts directory
if [ -d "$SKILL_DIR/scripts" ]; then
SCRIPT_COUNT=$(find "$SKILL_DIR/scripts" -type f -name "*.sh" | wc -l)
echo " 📜 Scripts: $SCRIPT_COUNT files"
if [ $SCRIPT_COUNT -lt $MIN_SCRIPTS ]; then
echo " ⚠️ Warning: Less than $MIN_SCRIPTS scripts"
((ISSUES_FOUND++))
fi
else
echo " ❌ scripts/ directory missing"
((ISSUES_FOUND++))
fi
# Check templates directory
if [ -d "$SKILL_DIR/templates" ]; then
echo " 📄 Templates:"
# Find all template subdirectories
EMPTY_DIRS=0
for TEMPLATE_DIR in "$SKILL_DIR/templates"/*; do
if [ -d "$TEMPLATE_DIR" ]; then
DIR_NAME=$(basename "$TEMPLATE_DIR")
FILE_COUNT=$(find "$TEMPLATE_DIR" -type f | wc -l)
if [ $FILE_COUNT -eq 0 ]; then
echo "$DIR_NAME/ is EMPTY"
((EMPTY_DIRS++))
((ISSUES_FOUND++))
elif [ $FILE_COUNT -lt $MIN_TEMPLATES_PER_DIR ]; then
echo " ⚠️ $DIR_NAME/ has only $FILE_COUNT file(s)"
find "$TEMPLATE_DIR" -type f -exec basename {} \; | sed 's/^/ - /'
else
echo "$DIR_NAME/ has $FILE_COUNT files"
find "$TEMPLATE_DIR" -type f -exec basename {} \; | sed 's/^/ - /'
fi
fi
done
if [ $EMPTY_DIRS -gt 0 ]; then
echo " ⚠️ Total empty template directories: $EMPTY_DIRS"
fi
else
echo " ❌ templates/ directory missing"
((ISSUES_FOUND++))
fi
# Check examples directory
if [ -d "$SKILL_DIR/examples" ]; then
EXAMPLE_COUNT=$(find "$SKILL_DIR/examples" -type f -name "*.md" | wc -l)
echo " 📚 Examples: $EXAMPLE_COUNT files"
if [ $EXAMPLE_COUNT -lt $MIN_EXAMPLES ]; then
echo " ❌ Less than $MIN_EXAMPLES examples"
((ISSUES_FOUND++))
fi
# List examples
find "$SKILL_DIR/examples" -type f -name "*.md" -exec basename {} \; | sed 's/^/ - /'
else
echo " ❌ examples/ directory missing"
((ISSUES_FOUND++))
fi
done
echo ""
echo "================================================"
if [ $ISSUES_FOUND -eq 0 ]; then
echo "✅ All validations passed! Plugin is complete."
exit 0
else
echo "❌ Found $ISSUES_FOUND issue(s) that need to be addressed."
exit 1
fi

View File

@@ -0,0 +1,136 @@
#!/usr/bin/env bash
# Validate and fix plugin.json manifest
# Usage: ./validate-plugin-manifest.sh <plugin-name> [--fix]
set -e
PLUGIN_NAME=$1
FIX_MODE=false
if [ "$2" = "--fix" ]; then
FIX_MODE=true
fi
if [ -z "$PLUGIN_NAME" ]; then
echo "Usage: $0 <plugin-name> [--fix]"
echo "Example: $0 elevenlabs --fix"
exit 1
fi
MANIFEST_FILE="plugins/$PLUGIN_NAME/.claude-plugin/plugin.json"
if [ ! -f "$MANIFEST_FILE" ]; then
echo "ERROR: Manifest file not found: $MANIFEST_FILE"
exit 1
fi
echo "[INFO] Validating plugin manifest: $MANIFEST_FILE"
# Test 1: Valid JSON syntax
if ! python3 -m json.tool "$MANIFEST_FILE" > /dev/null 2>&1; then
echo "❌ FAIL: Invalid JSON syntax"
exit 1
fi
echo "✅ PASS: Valid JSON syntax"
# Test 2: Required fields
REQUIRED_FIELDS=("name" "version" "description" "author")
MISSING_FIELDS=()
for field in "${REQUIRED_FIELDS[@]}"; do
if ! grep -q "\"$field\"" "$MANIFEST_FILE"; then
MISSING_FIELDS+=("$field")
fi
done
if [ ${#MISSING_FIELDS[@]} -gt 0 ]; then
echo "❌ FAIL: Missing required fields: ${MISSING_FIELDS[*]}"
exit 1
fi
echo "✅ PASS: All required fields present"
# Test 3: Repository field format (should be string, not object)
if grep -q '"repository".*{' "$MANIFEST_FILE"; then
echo "❌ FAIL: repository field is an object (should be string)"
if [ "$FIX_MODE" = true ]; then
echo "[INFO] Fixing repository field..."
# Extract URL from repository object
REPO_URL=$(grep -A2 '"repository"' "$MANIFEST_FILE" | grep '"url"' | sed 's/.*"url": "\(.*\)".*/\1/')
if [ -n "$REPO_URL" ]; then
# Create temp file with fixed repository
python3 << EOF
import json
with open("$MANIFEST_FILE", "r") as f:
data = json.load(f)
if isinstance(data.get("repository"), dict):
data["repository"] = data["repository"].get("url", "")
with open("$MANIFEST_FILE", "w") as f:
json.dump(data, f, indent=2)
f.write("\n")
EOF
echo "✅ FIXED: repository changed to string: $REPO_URL"
else
echo "❌ Could not extract repository URL"
exit 1
fi
else
echo "[HINT] Run with --fix to automatically correct this"
exit 1
fi
else
echo "✅ PASS: repository field is correct format"
fi
# Test 4: Category field (should NOT exist)
if grep -q '"category"' "$MANIFEST_FILE"; then
echo "❌ FAIL: 'category' field found (not a valid field)"
if [ "$FIX_MODE" = true ]; then
echo "[INFO] Removing category field..."
python3 << EOF
import json
with open("$MANIFEST_FILE", "r") as f:
data = json.load(f)
if "category" in data:
del data["category"]
with open("$MANIFEST_FILE", "w") as f:
json.dump(data, f, indent=2)
f.write("\n")
EOF
echo "✅ FIXED: category field removed"
else
echo "[HINT] Run with --fix to automatically correct this"
exit 1
fi
else
echo "✅ PASS: No invalid 'category' field"
fi
# Test 5: Author field structure
if ! grep -A1 '"author"' "$MANIFEST_FILE" | grep -q '"name"'; then
echo "❌ FAIL: author.name field missing"
exit 1
fi
echo "✅ PASS: author field properly structured"
# Final validation
if python3 -m json.tool "$MANIFEST_FILE" > /dev/null 2>&1; then
echo ""
echo "=========================================="
echo "✅ MANIFEST VALIDATION PASSED"
echo "=========================================="
echo "Plugin: $PLUGIN_NAME"
echo "File: $MANIFEST_FILE"
echo ""
exit 0
else
echo ""
echo "=========================================="
echo "❌ MANIFEST VALIDATION FAILED"
echo "=========================================="
exit 1
fi

View File

@@ -0,0 +1,137 @@
#!/usr/bin/env bash
# Script: validate-plugin.sh
# Purpose: Validate plugin directory compliance with Claude Code standards
# Subsystem: build-system
# Called by: /build:plugin command after generation
# Outputs: Validation report to stdout
set -euo pipefail
PLUGIN_DIR="${1:?Usage: $0 <plugin-directory>}"
SETTINGS_FILE="$HOME/.claude/settings.local.json"
echo "[INFO] Validating plugin directory: $PLUGIN_DIR"
# Check directory exists
if [[ ! -d "$PLUGIN_DIR" ]]; then
echo "❌ ERROR: Directory not found: $PLUGIN_DIR"
exit 1
fi
# Check .claude-plugin directory exists
if [[ ! -d "$PLUGIN_DIR/.claude-plugin" ]]; then
echo "❌ ERROR: Missing .claude-plugin directory"
exit 1
fi
# Check plugin.json exists
if [[ ! -f "$PLUGIN_DIR/.claude-plugin/plugin.json" ]]; then
echo "❌ ERROR: Missing plugin.json manifest"
exit 1
fi
# Validate JSON syntax
if ! python3 -m json.tool "$PLUGIN_DIR/.claude-plugin/plugin.json" > /dev/null 2>&1; then
echo "❌ ERROR: Invalid JSON in plugin.json"
exit 1
fi
# Validate plugin.json schema (only allowed fields)
ALLOWED_FIELDS=("name" "version" "description" "author" "homepage" "repository" "license" "keywords" "category" "tags" "strict" "commands" "agents" "hooks" "mcpServers")
INVALID_FIELDS=$(python3 -c "
import json, sys
with open('$PLUGIN_DIR/.claude-plugin/plugin.json') as f:
data = json.load(f)
allowed = set($( printf "'%s', " "${ALLOWED_FIELDS[@]}" | sed 's/, $//' ))
invalid = [k for k in data.keys() if k not in allowed]
if invalid:
print(' '.join(invalid))
" 2>/dev/null)
if [[ -n "$INVALID_FIELDS" ]]; then
echo "❌ ERROR: Invalid fields in plugin.json: $INVALID_FIELDS"
echo "[INFO] Allowed fields: ${ALLOWED_FIELDS[*]}"
echo "[INFO] Move custom metadata to keywords array for discoverability"
exit 1
fi
# Check required fields in plugin.json
REQUIRED_FIELDS=("name" "version" "description")
for field in "${REQUIRED_FIELDS[@]}"; do
if ! grep -q "\"$field\":" "$PLUGIN_DIR/.claude-plugin/plugin.json"; then
echo "❌ ERROR: Missing required field: $field"
exit 1
fi
done
# Validate author field structure if present
if grep -q "\"author\":" "$PLUGIN_DIR/.claude-plugin/plugin.json"; then
AUTHOR_VALID=$(python3 -c "
import json
with open('$PLUGIN_DIR/.claude-plugin/plugin.json') as f:
data = json.load(f)
author = data.get('author')
if isinstance(author, dict):
if 'name' in author:
print('valid')
else:
print('missing_name')
elif isinstance(author, str):
print('string')
" 2>/dev/null)
if [[ "$AUTHOR_VALID" == "string" ]]; then
echo "❌ ERROR: author field must be an object with 'name' and 'email' fields, not a string"
exit 1
elif [[ "$AUTHOR_VALID" == "missing_name" ]]; then
echo "❌ ERROR: author object must include 'name' field"
exit 1
fi
fi
# Check component directories are at root (not inside .claude-plugin)
if [[ -d "$PLUGIN_DIR/.claude-plugin/commands" ]] || \
[[ -d "$PLUGIN_DIR/.claude-plugin/skills" ]] || \
[[ -d "$PLUGIN_DIR/.claude-plugin/hooks" ]]; then
echo "❌ ERROR: Component directories must be at plugin root, not inside .claude-plugin/"
exit 1
fi
# NEW: Check if plugin commands are registered in settings.local.json
PLUGIN_NAME=$(basename "$PLUGIN_DIR")
if [[ -f "$SETTINGS_FILE" ]]; then
if [[ -d "$PLUGIN_DIR/commands" ]]; then
# Check for wildcard permission
if ! grep -q "SlashCommand(/$PLUGIN_NAME:\\*)" "$SETTINGS_FILE"; then
echo "⚠️ WARNING: Plugin commands not registered in settings.local.json"
echo "[INFO] Run: bash plugins/domain-plugin-builder/skills/build-assistant/scripts/sync-settings-permissions.sh"
else
echo "✅ Plugin commands registered in settings.local.json"
fi
fi
else
echo "⚠️ WARNING: No settings.local.json found"
echo "[INFO] Run: bash plugins/domain-plugin-builder/skills/build-assistant/scripts/sync-settings-permissions.sh"
fi
echo "✅ Plugin validation passed"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "📦 NEXT STEP: Install Plugin to Test"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "To make the plugin available for use:"
echo ""
echo " 1. Update marketplace in ~/.claude:"
echo " cp -r $PLUGIN_DIR ~/.claude/plugins/marketplaces/ai-dev-marketplace/plugins/"
echo " cp .claude-plugin/marketplace.json ~/.claude/plugins/marketplaces/ai-dev-marketplace/.claude-plugin/"
echo ""
echo " 2. Install the plugin:"
echo " /plugin install $PLUGIN_NAME@ai-dev-marketplace"
echo ""
echo " 3. Verify installation:"
echo " /$PLUGIN_NAME:init (or any command from the plugin)"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
exit 0

View File

@@ -0,0 +1,206 @@
#!/usr/bin/env bash
# Script: validate-skill.sh
# Purpose: Validate Agent Skill directory compliance with Claude Code standards
# Subsystem: build-system
# Called by: /build:skill command after generation
# Outputs: Validation report to stdout
set -euo pipefail
SKILL_DIR="${1:?Usage: $0 <skill-directory>}"
EXIT_CODE=0
echo "[INFO] Validating skill directory: $SKILL_DIR"
echo ""
# Check directory exists
if [[ ! -d "$SKILL_DIR" ]]; then
echo "❌ ERROR: Directory not found: $SKILL_DIR"
exit 1
fi
# Check SKILL.md exists
if [[ ! -f "$SKILL_DIR/SKILL.md" ]]; then
echo "❌ ERROR: Missing SKILL.md file"
exit 1
fi
# Check frontmatter exists and starts at line 1
FIRST_LINE=$(head -n 1 "$SKILL_DIR/SKILL.md")
if [[ "$FIRST_LINE" != "---" ]]; then
echo "❌ ERROR: YAML frontmatter MUST start at line 1"
echo " Found: $FIRST_LINE"
echo " Expected: ---"
echo " CRITICAL: Nothing can come before the opening --- (no titles, no comments, no blank lines)"
exit 1
fi
if ! grep -q "^---$" "$SKILL_DIR/SKILL.md"; then
echo "❌ ERROR: Missing closing frontmatter delimiter in SKILL.md"
exit 1
fi
# Check required frontmatter fields
REQUIRED_FIELDS=("name:" "description:")
for field in "${REQUIRED_FIELDS[@]}"; do
if ! grep -q "^$field" "$SKILL_DIR/SKILL.md"; then
echo "❌ ERROR: Missing required field: $field"
exit 1
fi
done
# Check description includes trigger keywords
if ! grep -q "Use when" "$SKILL_DIR/SKILL.md"; then
echo "⚠️ WARNING: Description should include 'Use when' trigger context"
fi
echo ""
echo "[INFO] Checking minimum requirements (scripts, templates, examples)..."
echo ""
# Minimum requirements per skill
MIN_SCRIPTS=3
MIN_TEMPLATES=4
MIN_EXAMPLES=3
# Count scripts
if [[ -d "$SKILL_DIR/scripts" ]]; then
SCRIPT_COUNT=$(find "$SKILL_DIR/scripts" -type f -name "*.sh" | wc -l)
echo "📂 Scripts found: $SCRIPT_COUNT"
if ((SCRIPT_COUNT >= MIN_SCRIPTS)); then
echo " ✅ Meets minimum requirement (>= $MIN_SCRIPTS scripts)"
else
echo " ❌ ERROR: Below minimum requirement (need $MIN_SCRIPTS, found $SCRIPT_COUNT)"
echo " Each skill should have 3-5 helper scripts (setup, validate, generate, etc.)"
EXIT_CODE=1
fi
# List scripts
if ((SCRIPT_COUNT > 0)); then
echo " Scripts:"
find "$SKILL_DIR/scripts" -type f -name "*.sh" -exec basename {} \; | sed 's/^/ - /'
fi
else
echo "📂 Scripts: directory not found"
echo " ❌ ERROR: Missing scripts/ directory"
EXIT_CODE=1
fi
echo ""
# Count templates
if [[ -d "$SKILL_DIR/templates" ]]; then
TEMPLATE_COUNT=$(find "$SKILL_DIR/templates" -type f | wc -l)
echo "📂 Templates found: $TEMPLATE_COUNT"
if ((TEMPLATE_COUNT >= MIN_TEMPLATES)); then
echo " ✅ Meets minimum requirement (>= $MIN_TEMPLATES templates)"
else
echo " ❌ ERROR: Below minimum requirement (need $MIN_TEMPLATES, found $TEMPLATE_COUNT)"
echo " Each skill should have 4-6 templates (basic, advanced, TS, Python, etc.)"
EXIT_CODE=1
fi
# Check for TypeScript and Python coverage
TS_COUNT=$(find "$SKILL_DIR/templates" -type f -name "*.ts" -o -name "*.tsx" | wc -l)
PY_COUNT=$(find "$SKILL_DIR/templates" -type f -name "*.py" | wc -l)
if ((TS_COUNT > 0)) && ((PY_COUNT > 0)); then
echo " ✅ Has both TypeScript ($TS_COUNT) and Python ($PY_COUNT) templates"
elif ((TS_COUNT > 0)); then
echo " ⚠️ WARNING: Has TypeScript templates but no Python templates"
elif ((PY_COUNT > 0)); then
echo " ⚠️ WARNING: Has Python templates but no TypeScript templates"
fi
# List templates by type
if ((TEMPLATE_COUNT > 0)); then
echo " Templates:"
find "$SKILL_DIR/templates" -type f | sed "s|$SKILL_DIR/templates/||" | sed 's/^/ - /'
fi
else
echo "📂 Templates: directory not found"
echo " ❌ ERROR: Missing templates/ directory"
EXIT_CODE=1
fi
echo ""
# Count examples
if [[ -d "$SKILL_DIR/examples" ]]; then
EXAMPLE_COUNT=$(find "$SKILL_DIR/examples" -type f -name "*.md" | wc -l)
echo "📂 Examples found: $EXAMPLE_COUNT"
if ((EXAMPLE_COUNT >= MIN_EXAMPLES)); then
echo " ✅ Meets minimum requirement (>= $MIN_EXAMPLES examples)"
else
echo " ❌ ERROR: Below minimum requirement (need $MIN_EXAMPLES, found $EXAMPLE_COUNT)"
echo " Each skill should have 3-5 examples (basic, advanced, patterns, edge-cases, integration)"
EXIT_CODE=1
fi
# List examples
if ((EXAMPLE_COUNT > 0)); then
echo " Examples:"
find "$SKILL_DIR/examples" -type f -name "*.md" -exec basename {} \; | sed 's/^/ - /'
fi
else
echo "📂 Examples: directory not found"
echo " ❌ ERROR: Missing examples/ directory"
EXIT_CODE=1
fi
echo ""
# Cross-reference: Check that SKILL.md references match actual files
echo "[INFO] Checking SKILL.md references match actual files..."
echo ""
# Count references in SKILL.md
SCRIPT_REFS=$(grep -oE 'scripts/[a-zA-Z0-9_-]+\.sh' "$SKILL_DIR/SKILL.md" 2>/dev/null | sort -u | wc -l || echo 0)
TEMPLATE_REFS=$(grep -oE 'templates/[a-zA-Z0-9_/.-]+\.(ts|py|tsx|js)' "$SKILL_DIR/SKILL.md" 2>/dev/null | sort -u | wc -l || echo 0)
EXAMPLE_REFS=$(grep -oE 'examples/[a-zA-Z0-9_-]+\.md' "$SKILL_DIR/SKILL.md" 2>/dev/null | sort -u | wc -l || echo 0)
echo "📝 SKILL.md references:"
echo " Scripts referenced: $SCRIPT_REFS"
echo " Templates referenced: $TEMPLATE_REFS"
echo " Examples referenced: $EXAMPLE_REFS"
echo ""
# Compare references to actual files
if [[ -d "$SKILL_DIR/scripts" ]]; then
if ((SCRIPT_REFS == SCRIPT_COUNT)); then
echo " ✅ Script references match actual files ($SCRIPT_REFS = $SCRIPT_COUNT)"
else
echo " ⚠️ WARNING: Script count mismatch (referenced: $SCRIPT_REFS, actual: $SCRIPT_COUNT)"
fi
fi
if [[ -d "$SKILL_DIR/templates" ]]; then
if ((TEMPLATE_REFS == TEMPLATE_COUNT)); then
echo " ✅ Template references match actual files ($TEMPLATE_REFS = $TEMPLATE_COUNT)"
else
echo " ⚠️ WARNING: Template count mismatch (referenced: $TEMPLATE_REFS, actual: $TEMPLATE_COUNT)"
fi
fi
if [[ -d "$SKILL_DIR/examples" ]]; then
if ((EXAMPLE_REFS == EXAMPLE_COUNT)); then
echo " ✅ Example references match actual files ($EXAMPLE_REFS = $EXAMPLE_COUNT)"
else
echo " ⚠️ WARNING: Example count mismatch (referenced: $EXAMPLE_REFS, actual: $EXAMPLE_COUNT)"
fi
fi
echo ""
# Final result
if [ $EXIT_CODE -eq 0 ]; then
echo "✅ Skill validation passed - all minimum requirements met!"
else
echo "❌ Skill validation failed - does not meet minimum requirements"
fi
exit $EXIT_CODE