Initial commit
This commit is contained in:
467
skills/documentation-update/SKILL.md
Normal file
467
skills/documentation-update/SKILL.md
Normal file
@@ -0,0 +1,467 @@
|
||||
---
|
||||
name: documentation-update
|
||||
description: Regenerates documentation files (agents.md, agent-skills.md, plugins.md, usage.md) from marketplace data using Jinja templates. Use when plugins are added, updated, or removed to keep documentation in sync.
|
||||
---
|
||||
|
||||
# Documentation Update Skill
|
||||
|
||||
This skill automatically regenerates documentation files in the `docs/` directory by reading the marketplace catalog and applying Jinja2 templates.
|
||||
|
||||
## Purpose
|
||||
|
||||
Maintain synchronized documentation by:
|
||||
|
||||
- Generating agent reference documentation
|
||||
- Creating skill catalog documentation
|
||||
- Building plugin directory
|
||||
- Updating usage guides
|
||||
- Ensuring consistency across all docs
|
||||
|
||||
## When to Use
|
||||
|
||||
Use this skill when:
|
||||
|
||||
- A new plugin is added to the marketplace
|
||||
- An existing plugin is updated (components added/removed)
|
||||
- Agent or skill metadata changes
|
||||
- Documentation needs to be regenerated
|
||||
- Ensuring docs match marketplace state
|
||||
|
||||
## Documentation Files
|
||||
|
||||
This skill generates four main documentation files:
|
||||
|
||||
### 1. agents.md
|
||||
|
||||
Complete reference of all agents across all plugins:
|
||||
|
||||
- Organized by plugin
|
||||
- Lists agent name, description, and model
|
||||
- Includes links to agent files
|
||||
- Shows agent capabilities and use cases
|
||||
|
||||
### 2. agent-skills.md
|
||||
|
||||
Catalog of all skills with progressive disclosure details:
|
||||
|
||||
- Organized by plugin
|
||||
- Lists skill name and description
|
||||
- Shows "Use when" triggers
|
||||
- Includes skill structure information
|
||||
|
||||
### 3. plugins.md
|
||||
|
||||
Directory of all plugins in the marketplace:
|
||||
|
||||
- Organized by category
|
||||
- Shows plugin name, description, and version
|
||||
- Lists components (agents, commands, skills)
|
||||
- Provides installation and usage information
|
||||
|
||||
### 4. usage.md
|
||||
|
||||
Usage guide and command reference:
|
||||
|
||||
- Getting started instructions
|
||||
- Command usage examples
|
||||
- Workflow patterns
|
||||
- Integration guides
|
||||
|
||||
## Template Structure
|
||||
|
||||
Templates are stored in `assets/` using Jinja2 syntax:
|
||||
|
||||
```
|
||||
assets/
|
||||
├── agents.md.j2
|
||||
├── agent-skills.md.j2
|
||||
├── plugins.md.j2
|
||||
└── usage.md.j2
|
||||
```
|
||||
|
||||
### Template Variables
|
||||
|
||||
All templates receive the following context:
|
||||
|
||||
```python
|
||||
{
|
||||
"marketplace": {
|
||||
"name": "marketplace-name",
|
||||
"owner": {...},
|
||||
"metadata": {...},
|
||||
"plugins": [...]
|
||||
},
|
||||
"plugins_by_category": {
|
||||
"category-name": [plugin1, plugin2, ...]
|
||||
},
|
||||
"all_agents": [
|
||||
{
|
||||
"plugin": "plugin-name",
|
||||
"name": "agent-name",
|
||||
"file": "agent-file.md",
|
||||
"description": "...",
|
||||
"model": "..."
|
||||
}
|
||||
],
|
||||
"all_skills": [
|
||||
{
|
||||
"plugin": "plugin-name",
|
||||
"name": "skill-name",
|
||||
"path": "skill-path",
|
||||
"description": "..."
|
||||
}
|
||||
],
|
||||
"all_commands": [
|
||||
{
|
||||
"plugin": "plugin-name",
|
||||
"name": "command-name",
|
||||
"file": "command-file.md",
|
||||
"description": "..."
|
||||
}
|
||||
],
|
||||
"stats": {
|
||||
"total_plugins": 10,
|
||||
"total_agents": 25,
|
||||
"total_commands": 15,
|
||||
"total_skills": 30
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Python Script
|
||||
|
||||
The skill includes a Python script `doc_generator.py` that:
|
||||
|
||||
1. **Loads marketplace.json**
|
||||
|
||||
- Reads the marketplace catalog
|
||||
- Validates structure
|
||||
- Builds component index
|
||||
|
||||
2. **Scans Plugin Files**
|
||||
|
||||
- Reads agent/command frontmatter
|
||||
- Extracts skill metadata
|
||||
- Builds comprehensive component list
|
||||
|
||||
3. **Prepares Template Context**
|
||||
|
||||
- Organizes plugins by category
|
||||
- Creates component indexes
|
||||
- Calculates statistics
|
||||
|
||||
4. **Renders Templates**
|
||||
- Applies Jinja2 templates
|
||||
- Generates documentation files
|
||||
- Writes to docs/ directory
|
||||
|
||||
### Usage
|
||||
|
||||
```bash
|
||||
# Generate all documentation files
|
||||
python doc_generator.py
|
||||
|
||||
# Generate specific file only
|
||||
python doc_generator.py --file agents
|
||||
|
||||
# Dry run (show output without writing)
|
||||
python doc_generator.py --dry-run
|
||||
|
||||
# Specify custom paths
|
||||
python doc_generator.py \
|
||||
--marketplace .claude-plugin/marketplace.json \
|
||||
--templates plugins/claude-plugin/skills/documentation-update/assets \
|
||||
--output docs
|
||||
```
|
||||
|
||||
## Integration with Commands
|
||||
|
||||
The `/claude-plugin:create` and `/claude-plugin:update` commands should invoke this skill automatically after marketplace updates:
|
||||
|
||||
### Workflow
|
||||
|
||||
```
|
||||
1. Plugin operation completes (add/update/remove)
|
||||
2. Marketplace.json is updated
|
||||
3. Invoke documentation-update skill
|
||||
4. Documentation files regenerated
|
||||
5. Changes ready to commit
|
||||
```
|
||||
|
||||
### Example Integration
|
||||
|
||||
```python
|
||||
# After creating/updating plugin
|
||||
print("Updating documentation...")
|
||||
|
||||
# Run doc generator
|
||||
import subprocess
|
||||
result = subprocess.run(
|
||||
["python", "plugins/claude-plugin/skills/documentation-update/doc_generator.py"],
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
|
||||
if result.returncode == 0:
|
||||
print("✓ Documentation updated")
|
||||
else:
|
||||
print(f"❌ Documentation update failed: {result.stderr}")
|
||||
```
|
||||
|
||||
## Template Examples
|
||||
|
||||
### agents.md.j2
|
||||
|
||||
```jinja2
|
||||
# Agent Reference
|
||||
|
||||
This document lists all agents available across plugins in the marketplace.
|
||||
|
||||
{% for category, plugins in plugins_by_category.items() %}
|
||||
## {{ category|title }}
|
||||
|
||||
{% for plugin in plugins %}
|
||||
### {{ plugin.name }}
|
||||
|
||||
{{ plugin.description }}
|
||||
|
||||
**Agents:**
|
||||
|
||||
{% for agent in all_agents %}
|
||||
{% if agent.plugin == plugin.name %}
|
||||
- **{{ agent.name }}** (`{{ agent.model }}`)
|
||||
- {{ agent.description }}
|
||||
- File: `plugins/{{ plugin.name }}/agents/{{ agent.file }}`
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
|
||||
---
|
||||
*Last updated: {{ now }}*
|
||||
*Total agents: {{ stats.total_agents }}*
|
||||
```
|
||||
|
||||
### agent-skills.md.j2
|
||||
|
||||
```jinja2
|
||||
# Agent Skills Reference
|
||||
|
||||
This document catalogs all skills with progressive disclosure patterns.
|
||||
|
||||
{% for plugin in marketplace.plugins %}
|
||||
## {{ plugin.name }}
|
||||
|
||||
{{ plugin.description }}
|
||||
|
||||
**Skills:**
|
||||
|
||||
{% for skill in all_skills %}
|
||||
{% if skill.plugin == plugin.name %}
|
||||
### {{ skill.name }}
|
||||
|
||||
{{ skill.description }}
|
||||
|
||||
- **Location:** `plugins/{{ plugin.name }}/skills/{{ skill.path }}/`
|
||||
- **Structure:** SKILL.md + assets/ + references/
|
||||
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% endfor %}
|
||||
|
||||
---
|
||||
*Last updated: {{ now }}*
|
||||
*Total skills: {{ stats.total_skills }}*
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Marketplace Not Found
|
||||
|
||||
```
|
||||
Error: Marketplace file not found: .claude-plugin/marketplace.json
|
||||
Suggestion: Ensure marketplace.json exists
|
||||
```
|
||||
|
||||
### Template Not Found
|
||||
|
||||
```
|
||||
Error: Template file not found: assets/agents.md.j2
|
||||
Suggestion: Ensure all template files exist in assets/
|
||||
```
|
||||
|
||||
### Invalid Plugin Structure
|
||||
|
||||
```
|
||||
Warning: Plugin 'plugin-name' missing components
|
||||
Suggestion: Verify plugin has agents or commands
|
||||
```
|
||||
|
||||
### Frontmatter Parse Error
|
||||
|
||||
```
|
||||
Warning: Could not parse frontmatter in agents/agent-name.md
|
||||
Suggestion: Check YAML frontmatter syntax
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Always Regenerate After Changes**
|
||||
|
||||
- Run after every plugin add/update/remove
|
||||
- Ensure docs stay synchronized
|
||||
- Commit documentation with plugin changes
|
||||
|
||||
2. **Validate Before Generation**
|
||||
|
||||
- Run marketplace validation first
|
||||
- Fix any errors or warnings
|
||||
- Ensure all files exist
|
||||
|
||||
3. **Review Generated Output**
|
||||
|
||||
- Check generated files for correctness
|
||||
- Verify formatting and links
|
||||
- Test any code examples
|
||||
|
||||
4. **Template Maintenance**
|
||||
|
||||
- Keep templates simple and readable
|
||||
- Use consistent formatting
|
||||
- Document template variables
|
||||
|
||||
5. **Version Control**
|
||||
- Commit documentation changes
|
||||
- Include in pull requests
|
||||
- Document significant changes
|
||||
|
||||
## Template Customization
|
||||
|
||||
### Adding New Sections
|
||||
|
||||
To add a new section to a template:
|
||||
|
||||
1. **Modify Template**
|
||||
|
||||
```jinja2
|
||||
## New Section
|
||||
|
||||
{% for plugin in marketplace.plugins %}
|
||||
### {{ plugin.name }}
|
||||
[Your content here]
|
||||
{% endfor %}
|
||||
```
|
||||
|
||||
2. **Update Context (if needed)**
|
||||
|
||||
- Add new data to template context in doc_generator.py
|
||||
- Process additional metadata
|
||||
|
||||
3. **Test Output**
|
||||
- Run generator with dry-run
|
||||
- Verify formatting
|
||||
- Check for errors
|
||||
|
||||
### Creating New Templates
|
||||
|
||||
To add a new documentation file:
|
||||
|
||||
1. **Create Template**
|
||||
|
||||
- Add `assets/newdoc.md.j2`
|
||||
- Define structure and content
|
||||
|
||||
2. **Update Script**
|
||||
|
||||
- Add to doc_generator.py template list
|
||||
- Define output path
|
||||
|
||||
3. **Test Generation**
|
||||
- Run generator
|
||||
- Verify output
|
||||
- Commit template and output
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
plugins/claude-plugin/skills/documentation-update/
|
||||
├── SKILL.md # This file
|
||||
├── doc_generator.py # Python implementation
|
||||
├── assets/ # Jinja2 templates
|
||||
│ ├── agents.md.j2
|
||||
│ ├── agent-skills.md.j2
|
||||
│ ├── plugins.md.j2
|
||||
│ └── usage.md.j2
|
||||
└── references/ # Optional examples
|
||||
└── template-examples.md
|
||||
```
|
||||
|
||||
## Requirements
|
||||
|
||||
- Python 3.8+
|
||||
- No external dependencies (uses standard library only)
|
||||
- Access to `.claude-plugin/marketplace.json`
|
||||
- Read access to plugin directories
|
||||
- Write access to `docs/` directory
|
||||
|
||||
## Success Criteria
|
||||
|
||||
After running this skill:
|
||||
|
||||
- ✓ All documentation files generated
|
||||
- ✓ Content matches marketplace state
|
||||
- ✓ All links are valid
|
||||
- ✓ Formatting is consistent
|
||||
- ✓ Statistics are accurate
|
||||
- ✓ No template rendering errors
|
||||
|
||||
## Maintenance
|
||||
|
||||
### Updating Templates
|
||||
|
||||
When marketplace structure changes:
|
||||
|
||||
1. **Assess Impact**
|
||||
|
||||
- Identify affected templates
|
||||
- Determine required changes
|
||||
|
||||
2. **Update Templates**
|
||||
|
||||
- Modify Jinja2 templates
|
||||
- Test with current data
|
||||
|
||||
3. **Update Script**
|
||||
|
||||
- Adjust context preparation if needed
|
||||
- Add new data processing
|
||||
|
||||
4. **Validate Output**
|
||||
- Regenerate all docs
|
||||
- Review changes
|
||||
- Test links and formatting
|
||||
|
||||
### Version Compatibility
|
||||
|
||||
- Templates should handle missing fields gracefully
|
||||
- Use Jinja2 default filters for optional data
|
||||
- Validate marketplace version compatibility
|
||||
|
||||
## Example Output
|
||||
|
||||
The skill generates comprehensive, well-formatted documentation:
|
||||
|
||||
- **agents.md**: ~500-1000 lines for 20-30 agents
|
||||
- **agent-skills.md**: ~300-600 lines for 30-50 skills
|
||||
- **plugins.md**: ~400-800 lines for 10-20 plugins
|
||||
- **usage.md**: ~200-400 lines of usage information
|
||||
|
||||
All files include:
|
||||
|
||||
- Clear structure and headings
|
||||
- Formatted tables where appropriate
|
||||
- Links to source files
|
||||
- Statistics and metadata
|
||||
- Last updated timestamp
|
||||
73
skills/documentation-update/assets/agent-skills.md.j2
Normal file
73
skills/documentation-update/assets/agent-skills.md.j2
Normal file
@@ -0,0 +1,73 @@
|
||||
# Agent Skills Reference
|
||||
|
||||
This document catalogs all agent skills with progressive disclosure patterns across the marketplace.
|
||||
|
||||
## Overview
|
||||
|
||||
- **Total Skills**: {{ stats.total_skills }}
|
||||
- **Total Plugins**: {{ stats.total_plugins }}
|
||||
- **Last Updated**: {{ now }}
|
||||
|
||||
---
|
||||
|
||||
## What are Agent Skills?
|
||||
|
||||
Agent skills are modular knowledge packages that use progressive disclosure architecture:
|
||||
|
||||
1. **Metadata** (Frontmatter) - Always loaded
|
||||
2. **Instructions** - Core guidance loaded when activated
|
||||
3. **Resources** (assets/) - Loaded on demand
|
||||
|
||||
All skills follow the [Anthropic Agent Skills Specification](https://github.com/anthropics/skills/blob/main/agent_skills_spec.md).
|
||||
|
||||
---
|
||||
|
||||
{% for plugin in marketplace.plugins %}
|
||||
## {{ plugin.name }}
|
||||
|
||||
**Description**: {{ plugin.description }}
|
||||
|
||||
**Version**: {{ plugin.version }}
|
||||
|
||||
{% if plugin.skills %}
|
||||
**Skills**:
|
||||
|
||||
{% for skill in all_skills %}
|
||||
{% if skill.plugin == plugin.name %}
|
||||
### {{ skill.name }}
|
||||
|
||||
{{ skill.description }}
|
||||
|
||||
**Location**: `plugins/{{ plugin.name }}/skills/{{ skill.path }}/`
|
||||
|
||||
**Structure**:
|
||||
- `SKILL.md` - Skill definition with frontmatter
|
||||
- `assets/` - Templates, configurations, examples
|
||||
- `references/` - Additional documentation
|
||||
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
*No skills defined*
|
||||
{% endif %}
|
||||
|
||||
---
|
||||
|
||||
{% endfor %}
|
||||
|
||||
## Progressive Disclosure Benefits
|
||||
|
||||
- **Token Efficiency**: Load only relevant knowledge when needed
|
||||
- **Specialized Expertise**: Deep domain knowledge without bloat
|
||||
- **Clear Activation**: Explicit triggers prevent unwanted invocation
|
||||
- **Composability**: Mix and match skills across workflows
|
||||
- **Maintainability**: Isolated updates don't affect other skills
|
||||
|
||||
## Using Skills
|
||||
|
||||
Skills are automatically invoked by agents when their trigger conditions are met. You can also manually invoke skills when needed for specific operations.
|
||||
|
||||
---
|
||||
|
||||
*This documentation is automatically generated from the marketplace catalog.*
|
||||
*Last updated: {{ now }}*
|
||||
64
skills/documentation-update/assets/agents.md.j2
Normal file
64
skills/documentation-update/assets/agents.md.j2
Normal file
@@ -0,0 +1,64 @@
|
||||
# Agent Reference
|
||||
|
||||
This document provides a comprehensive reference of all agents available across plugins in the marketplace.
|
||||
|
||||
## Overview
|
||||
|
||||
- **Total Agents**: {{ stats.total_agents }}
|
||||
- **Total Plugins**: {{ stats.total_plugins }}
|
||||
- **Last Updated**: {{ now }}
|
||||
|
||||
---
|
||||
|
||||
{% for category, plugins in plugins_by_category.items() %}
|
||||
## {{ category|title }} Agents
|
||||
|
||||
{% for plugin in plugins %}
|
||||
### {{ plugin.name }}
|
||||
|
||||
**Description**: {{ plugin.description }}
|
||||
|
||||
**Version**: {{ plugin.version }}
|
||||
|
||||
{% if plugin.agents %}
|
||||
**Agents**:
|
||||
|
||||
{% for agent in all_agents %}
|
||||
{% if agent.plugin == plugin.name %}
|
||||
#### {{ agent.name }}
|
||||
|
||||
- **Model**: `{{ agent.model }}`
|
||||
- **Description**: {{ agent.description }}
|
||||
- **Location**: `plugins/{{ plugin.name }}/agents/{{ agent.file }}`
|
||||
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
*No agents defined*
|
||||
{% endif %}
|
||||
|
||||
---
|
||||
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
|
||||
## Usage
|
||||
|
||||
To use an agent from the command line:
|
||||
|
||||
```bash
|
||||
# Invoke with Task tool
|
||||
Use Task tool with subagent_type="<agent-name>"
|
||||
```
|
||||
|
||||
## Model Distribution
|
||||
|
||||
Agents are optimized for specific models based on their complexity:
|
||||
|
||||
- **Haiku**: Fast execution for deterministic tasks
|
||||
- **Sonnet**: Complex reasoning and architecture decisions
|
||||
|
||||
---
|
||||
|
||||
*This documentation is automatically generated from the marketplace catalog.*
|
||||
*Last updated: {{ now }}*
|
||||
88
skills/documentation-update/assets/plugins.md.j2
Normal file
88
skills/documentation-update/assets/plugins.md.j2
Normal file
@@ -0,0 +1,88 @@
|
||||
# Plugin Directory
|
||||
|
||||
Complete catalog of all plugins available in the marketplace.
|
||||
|
||||
## Overview
|
||||
|
||||
- **Total Plugins**: {{ stats.total_plugins }}
|
||||
- **Total Agents**: {{ stats.total_agents }}
|
||||
- **Total Commands**: {{ stats.total_commands }}
|
||||
- **Total Skills**: {{ stats.total_skills }}
|
||||
- **Last Updated**: {{ now }}
|
||||
|
||||
---
|
||||
|
||||
{% for category, plugins in plugins_by_category.items() %}
|
||||
## {{ category|title }}
|
||||
|
||||
{% for plugin in plugins %}
|
||||
### {{ plugin.name }}
|
||||
|
||||
{{ plugin.description }}
|
||||
|
||||
**Version**: {{ plugin.version }}
|
||||
|
||||
**Author**: {% if plugin.author %}{{ plugin.author.name }}{% else %}{{ marketplace.owner.name }}{% endif %}
|
||||
|
||||
**License**: {{ plugin.license }}
|
||||
|
||||
{% if plugin.keywords %}
|
||||
**Keywords**: {{ plugin.keywords|join(', ') }}
|
||||
{% endif %}
|
||||
|
||||
**Components**:
|
||||
{% if plugin.agents %}
|
||||
- **Agents**: {{ plugin.agents|length }}
|
||||
{% endif %}
|
||||
{% if plugin.commands %}
|
||||
- **Commands**: {{ plugin.commands|length }}
|
||||
{% endif %}
|
||||
{% if plugin.skills %}
|
||||
- **Skills**: {{ plugin.skills|length }}
|
||||
{% endif %}
|
||||
|
||||
**Location**: `{{ plugin.source }}`
|
||||
|
||||
{% if plugin.homepage %}
|
||||
**Homepage**: {{ plugin.homepage }}
|
||||
{% endif %}
|
||||
|
||||
{% if plugin.repository %}
|
||||
**Repository**: {{ plugin.repository }}
|
||||
{% endif %}
|
||||
|
||||
---
|
||||
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
|
||||
## Plugin Architecture
|
||||
|
||||
Each plugin follows these principles:
|
||||
|
||||
- **Single Responsibility**: One plugin does one thing well
|
||||
- **Composability**: Mix and match plugins based on needs
|
||||
- **Context Efficiency**: Smaller tools for better LLM performance
|
||||
- **Maintainability**: Isolated updates, clear boundaries
|
||||
|
||||
## Installation
|
||||
|
||||
All plugins are included in this marketplace. To use a plugin:
|
||||
|
||||
1. Ensure the plugin directory exists in `plugins/`
|
||||
2. Use agents via the Task tool
|
||||
3. Use commands via slash commands
|
||||
4. Skills are automatically loaded when needed
|
||||
|
||||
## Categories
|
||||
|
||||
Plugins are organized into the following categories:
|
||||
|
||||
{% for category in plugins_by_category.keys() %}
|
||||
- **{{ category|title }}**: {{ plugins_by_category[category]|length }} plugin(s)
|
||||
{% endfor %}
|
||||
|
||||
---
|
||||
|
||||
*This documentation is automatically generated from the marketplace catalog.*
|
||||
*Last updated: {{ now }}*
|
||||
250
skills/documentation-update/assets/usage.md.j2
Normal file
250
skills/documentation-update/assets/usage.md.j2
Normal file
@@ -0,0 +1,250 @@
|
||||
# Usage Guide
|
||||
|
||||
Comprehensive guide for using Claude Code plugins, agents, commands, and skills from this marketplace.
|
||||
|
||||
## Overview
|
||||
|
||||
This marketplace provides {{ stats.total_plugins }} plugin(s) with:
|
||||
- {{ stats.total_agents }} specialized agent(s)
|
||||
- {{ stats.total_commands }} command(s)
|
||||
- {{ stats.total_skills }} skill(s)
|
||||
|
||||
**Last Updated**: {{ now }}
|
||||
|
||||
---
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Using Agents
|
||||
|
||||
Agents are specialized domain experts invoked via the Task tool:
|
||||
|
||||
```
|
||||
Use Task tool with subagent_type="<agent-name>"
|
||||
```
|
||||
|
||||
**Example**:
|
||||
```
|
||||
Use Task tool with subagent_type="plugin-architect" to design a new plugin
|
||||
```
|
||||
|
||||
### Using Commands
|
||||
|
||||
Commands are slash commands for specific workflows:
|
||||
|
||||
```bash
|
||||
/<command-name> [arguments]
|
||||
```
|
||||
|
||||
**Available Commands**:
|
||||
|
||||
{% for command in all_commands %}
|
||||
- `{{ command.name }}` - {{ command.description }}
|
||||
- Plugin: {{ command.plugin }}
|
||||
- File: `plugins/{{ command.plugin }}/commands/{{ command.file }}`
|
||||
{% endfor %}
|
||||
|
||||
### Using Skills
|
||||
|
||||
Skills are automatically invoked by agents when their trigger conditions are met. Skills provide:
|
||||
|
||||
- Modular knowledge packages
|
||||
- Progressive disclosure (metadata → instructions → resources)
|
||||
- Spec-compliant with Anthropic guidelines
|
||||
|
||||
**Available Skills**:
|
||||
|
||||
{% for skill in all_skills %}
|
||||
- `{{ skill.name }}` - {{ skill.description }}
|
||||
- Plugin: {{ skill.plugin }}
|
||||
- Path: `plugins/{{ skill.plugin }}/skills/{{ skill.path }}/`
|
||||
{% endfor %}
|
||||
|
||||
---
|
||||
|
||||
## Common Workflows
|
||||
|
||||
### Creating a New Plugin
|
||||
|
||||
Use the `claude-plugin` plugin to create new plugins:
|
||||
|
||||
```bash
|
||||
# Create a new plugin
|
||||
/create <plugin-name> "<description>" [components]
|
||||
|
||||
# Example
|
||||
/create golang-advanced "Advanced Go development tools" agents,commands,skills
|
||||
```
|
||||
|
||||
### Updating an Existing Plugin
|
||||
|
||||
Modify plugins by adding, updating, or removing components:
|
||||
|
||||
```bash
|
||||
# Add a new agent
|
||||
/update <plugin-name> add agent <agent-name>
|
||||
|
||||
# Modify a command
|
||||
/update <plugin-name> modify command <command-name>
|
||||
|
||||
# Remove a skill
|
||||
/update <plugin-name> remove skill <skill-name>
|
||||
```
|
||||
|
||||
### Working with Agents
|
||||
|
||||
Invoke agents for specialized tasks:
|
||||
|
||||
```
|
||||
# For architecture and design
|
||||
Use Task tool with subagent_type="plugin-architect"
|
||||
|
||||
# Add your task description
|
||||
[Describe what you need the agent to do]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Plugin Architecture
|
||||
|
||||
### Directory Structure
|
||||
|
||||
```
|
||||
plugins/
|
||||
├── <plugin-name>/
|
||||
│ ├── agents/ # Specialized agents (optional)
|
||||
│ │ └── agent.md
|
||||
│ ├── commands/ # Slash commands (optional)
|
||||
│ │ └── command.md
|
||||
│ └── skills/ # Agent skills (optional)
|
||||
│ └── skill-name/
|
||||
│ ├── SKILL.md
|
||||
│ ├── assets/
|
||||
│ └── references/
|
||||
```
|
||||
|
||||
### Component Requirements
|
||||
|
||||
Each plugin must have:
|
||||
- At least one agent OR one command
|
||||
- Proper YAML frontmatter in all files
|
||||
- Clear, focused purpose
|
||||
- Entry in marketplace.json
|
||||
|
||||
---
|
||||
|
||||
## Agent Reference
|
||||
|
||||
### Available Agents
|
||||
|
||||
{% for agent in all_agents %}
|
||||
#### {{ agent.name }}
|
||||
|
||||
- **Plugin**: {{ agent.plugin }}
|
||||
- **Model**: {{ agent.model }}
|
||||
- **Description**: {{ agent.description }}
|
||||
- **Invocation**: `Use Task tool with subagent_type="{{ agent.name }}"`
|
||||
|
||||
{% endfor %}
|
||||
|
||||
### Model Selection
|
||||
|
||||
Agents use different models based on task complexity:
|
||||
|
||||
- **Haiku**: Fast execution for deterministic tasks
|
||||
- Code generation from specs
|
||||
- Test creation
|
||||
- Documentation generation
|
||||
|
||||
- **Sonnet**: Complex reasoning and architecture
|
||||
- System design
|
||||
- Security audits
|
||||
- Language expertise
|
||||
- Multi-agent orchestration
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### When Creating Plugins
|
||||
|
||||
1. **Single Responsibility**: One plugin, one purpose
|
||||
2. **Clear Naming**: Use hyphen-case, be descriptive
|
||||
3. **Complete Documentation**: Include frontmatter and examples
|
||||
4. **Spec Compliance**: Follow Anthropic guidelines
|
||||
5. **Test Thoroughly**: Verify functionality before committing
|
||||
|
||||
### When Using Agents
|
||||
|
||||
1. **Choose the Right Agent**: Match agent expertise to task
|
||||
2. **Provide Clear Context**: Detailed task descriptions
|
||||
3. **Use Appropriate Models**: Haiku for speed, Sonnet for complexity
|
||||
4. **Compose When Needed**: Combine multiple agents for complex workflows
|
||||
|
||||
### When Working with Skills
|
||||
|
||||
1. **Progressive Disclosure**: Load only what's needed
|
||||
2. **Clear Triggers**: Use explicit activation criteria
|
||||
3. **Modular Design**: Keep skills focused and reusable
|
||||
4. **Document Well**: Include usage examples
|
||||
|
||||
---
|
||||
|
||||
## Marketplace Management
|
||||
|
||||
### Adding Plugins
|
||||
|
||||
Plugins are added via the marketplace update process:
|
||||
|
||||
1. Create plugin directory and components
|
||||
2. Update `.claude-plugin/marketplace.json`
|
||||
3. Regenerate documentation
|
||||
|
||||
### Updating Documentation
|
||||
|
||||
Documentation is automatically generated from the marketplace:
|
||||
|
||||
```bash
|
||||
# Regenerate all docs
|
||||
python plugins/claude-plugin/skills/documentation-update/doc_generator.py
|
||||
|
||||
# Generate specific file
|
||||
python plugins/claude-plugin/skills/documentation-update/doc_generator.py --file agents
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Categories
|
||||
|
||||
Plugins are organized by category:
|
||||
|
||||
{% for category, plugins in plugins_by_category.items() %}
|
||||
### {{ category|title }}
|
||||
|
||||
{% for plugin in plugins %}
|
||||
- **{{ plugin.name }}** - {{ plugin.description }}
|
||||
{% endfor %}
|
||||
|
||||
{% endfor %}
|
||||
|
||||
---
|
||||
|
||||
## Getting Help
|
||||
|
||||
- **Documentation**: See `docs/` directory for detailed references
|
||||
- **Architecture**: See `docs/architecture.md` for design principles
|
||||
- **Contributing**: See `.github/CONTRIBUTING.md` for contribution guidelines
|
||||
|
||||
---
|
||||
|
||||
## Resources
|
||||
|
||||
- [Architecture Documentation](./architecture.md)
|
||||
- [Agent Reference](./agents.md)
|
||||
- [Skills Reference](./agent-skills.md)
|
||||
- [Plugin Directory](./plugins.md)
|
||||
|
||||
---
|
||||
|
||||
*This documentation is automatically generated from the marketplace catalog.*
|
||||
*Last updated: {{ now }}*
|
||||
476
skills/documentation-update/doc_generator.py
Executable file
476
skills/documentation-update/doc_generator.py
Executable file
@@ -0,0 +1,476 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Documentation Generator
|
||||
|
||||
Generates documentation files from marketplace data using Jinja2 templates.
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Any, Optional
|
||||
import argparse
|
||||
|
||||
# Try to use real Jinja2 if available, otherwise use SimpleTemplate fallback
|
||||
try:
|
||||
from jinja2 import Template as Jinja2Template
|
||||
USE_JINJA2 = True
|
||||
except ImportError:
|
||||
USE_JINJA2 = False
|
||||
|
||||
|
||||
class SimpleTemplate:
|
||||
"""Minimal Jinja2-like template engine"""
|
||||
|
||||
def __init__(self, template_str: str):
|
||||
self.template = template_str
|
||||
|
||||
def apply_filter(self, value: Any, filter_name: str) -> Any:
|
||||
"""Apply a filter to a value"""
|
||||
if filter_name == 'title':
|
||||
return str(value).replace('-', ' ').replace('_', ' ').title()
|
||||
elif filter_name == 'length':
|
||||
return len(value) if hasattr(value, '__len__') else 0
|
||||
elif filter_name.startswith('join'):
|
||||
# Extract separator from filter (e.g., "join(', ')")
|
||||
match = re.search(r"join\(['\"]([^'\"]*)['\"]\)", filter_name)
|
||||
if match and isinstance(value, list):
|
||||
separator = match.group(1)
|
||||
return separator.join(str(v) for v in value)
|
||||
return str(value)
|
||||
return value
|
||||
|
||||
def resolve_value(self, expr: str, context: Dict[str, Any]) -> Any:
|
||||
"""Resolve a variable expression with optional filters"""
|
||||
# Split expression and filters
|
||||
parts = expr.strip().split('|')
|
||||
var_expr = parts[0].strip()
|
||||
filters = [f.strip() for f in parts[1:]]
|
||||
|
||||
# Resolve the base variable
|
||||
value = context
|
||||
for key in var_expr.split('.'):
|
||||
key = key.strip()
|
||||
if isinstance(value, dict):
|
||||
value = value.get(key, '')
|
||||
elif hasattr(value, key):
|
||||
value = getattr(value, key)
|
||||
else:
|
||||
value = ''
|
||||
break
|
||||
|
||||
# Apply filters
|
||||
for filter_name in filters:
|
||||
value = self.apply_filter(value, filter_name)
|
||||
|
||||
return value
|
||||
|
||||
def render(self, context: Dict[str, Any]) -> str:
|
||||
"""Render template with context"""
|
||||
result = self.template
|
||||
|
||||
# Handle nested loops with .items(): {% for key, value in dict.items() %}...{% endfor %}
|
||||
items_pattern = r'{%\s*for\s+(\w+)\s*,\s*(\w+)\s+in\s+([\w.]+)\.items\(\)\s*%}(.*?){%\s*endfor\s*%}'
|
||||
|
||||
def replace_items_loop(match):
|
||||
key_var = match.group(1)
|
||||
value_var = match.group(2)
|
||||
dict_name = match.group(3)
|
||||
loop_body = match.group(4)
|
||||
|
||||
dict_obj = self.resolve_value(dict_name, context)
|
||||
if not isinstance(dict_obj, dict):
|
||||
return ""
|
||||
|
||||
output = []
|
||||
for key, value in dict_obj.items():
|
||||
loop_context = context.copy()
|
||||
loop_context[key_var] = key
|
||||
loop_context[value_var] = value
|
||||
|
||||
# Recursively render the loop body
|
||||
template = SimpleTemplate(loop_body)
|
||||
body_result = template.render(loop_context)
|
||||
output.append(body_result)
|
||||
|
||||
return "".join(output)
|
||||
|
||||
result = re.sub(items_pattern, replace_items_loop, result, flags=re.DOTALL)
|
||||
|
||||
# Handle loops with .keys(): {% for key in dict.keys() %}...{% endfor %}
|
||||
keys_pattern = r'{%\s*for\s+(\w+)\s+in\s+([\w.]+)\.keys\(\)\s*%}(.*?){%\s*endfor\s*%}'
|
||||
|
||||
def replace_keys_loop(match):
|
||||
var_name = match.group(1)
|
||||
dict_name = match.group(2)
|
||||
loop_body = match.group(3)
|
||||
|
||||
dict_obj = self.resolve_value(dict_name, context)
|
||||
if not isinstance(dict_obj, dict):
|
||||
return ""
|
||||
|
||||
output = []
|
||||
for key in dict_obj.keys():
|
||||
loop_context = context.copy()
|
||||
loop_context[var_name] = key
|
||||
|
||||
# Recursively render the loop body
|
||||
template = SimpleTemplate(loop_body)
|
||||
body_result = template.render(loop_context)
|
||||
output.append(body_result)
|
||||
|
||||
return "".join(output)
|
||||
|
||||
result = re.sub(keys_pattern, replace_keys_loop, result, flags=re.DOTALL)
|
||||
|
||||
# Handle regular loops: {% for item in items %}...{% endfor %}
|
||||
for_pattern = r'{%\s*for\s+(\w+)\s+in\s+([\w.]+)\s*%}(.*?){%\s*endfor\s*%}'
|
||||
|
||||
def replace_for(match):
|
||||
var_name = match.group(1)
|
||||
list_name = match.group(2)
|
||||
loop_body = match.group(3)
|
||||
|
||||
items = self.resolve_value(list_name, context)
|
||||
if not isinstance(items, (list, dict)):
|
||||
return ""
|
||||
|
||||
# Handle both lists and dict values
|
||||
if isinstance(items, dict):
|
||||
items = list(items.values())
|
||||
|
||||
output = []
|
||||
for item in items:
|
||||
loop_context = context.copy()
|
||||
loop_context[var_name] = item
|
||||
|
||||
# If item is a dict, also add its keys directly to context for easier access
|
||||
if isinstance(item, dict):
|
||||
for key, value in item.items():
|
||||
loop_context[f"{var_name}.{key}"] = value
|
||||
|
||||
# Recursively render the loop body
|
||||
template = SimpleTemplate(loop_body)
|
||||
body_result = template.render(loop_context)
|
||||
output.append(body_result)
|
||||
|
||||
return "".join(output)
|
||||
|
||||
result = re.sub(for_pattern, replace_for, result, flags=re.DOTALL)
|
||||
|
||||
# Handle conditionals with comparison: {% if var1 == var2 %}...{% endif %}
|
||||
if_compare_pattern = r'{%\s*if\s+([\w.]+)\s*==\s*([\w.]+)\s*%}(.*?){%\s*endif\s*%}'
|
||||
|
||||
def replace_if_compare(match):
|
||||
left_expr = match.group(1)
|
||||
right_expr = match.group(2)
|
||||
body = match.group(3)
|
||||
|
||||
left_val = self.resolve_value(left_expr, context)
|
||||
right_val = self.resolve_value(right_expr, context)
|
||||
|
||||
if left_val == right_val:
|
||||
template = SimpleTemplate(body)
|
||||
return template.render(context)
|
||||
return ""
|
||||
|
||||
result = re.sub(if_compare_pattern, replace_if_compare, result, flags=re.DOTALL)
|
||||
|
||||
# Handle conditionals with else: {% if condition %}...{% else %}...{% endif %}
|
||||
if_else_pattern = r'{%\s*if\s+([\w.]+)\s*%}(.*?){%\s*else\s*%}(.*?){%\s*endif\s*%}'
|
||||
|
||||
def replace_if_else(match):
|
||||
condition = match.group(1)
|
||||
true_body = match.group(2)
|
||||
false_body = match.group(3)
|
||||
|
||||
cond_val = self.resolve_value(condition, context)
|
||||
|
||||
if cond_val:
|
||||
template = SimpleTemplate(true_body)
|
||||
return template.render(context)
|
||||
else:
|
||||
template = SimpleTemplate(false_body)
|
||||
return template.render(context)
|
||||
|
||||
result = re.sub(if_else_pattern, replace_if_else, result, flags=re.DOTALL)
|
||||
|
||||
# Handle simple conditionals: {% if condition %}...{% endif %}
|
||||
if_pattern = r'{%\s*if\s+([\w.]+)\s*%}(.*?){%\s*endif\s*%}'
|
||||
|
||||
def replace_if(match):
|
||||
condition = match.group(1)
|
||||
body = match.group(2)
|
||||
|
||||
cond_val = self.resolve_value(condition, context)
|
||||
|
||||
if cond_val:
|
||||
template = SimpleTemplate(body)
|
||||
return template.render(context)
|
||||
return ""
|
||||
|
||||
result = re.sub(if_pattern, replace_if, result, flags=re.DOTALL)
|
||||
|
||||
# Replace variables with filters: {{ variable|filter }}
|
||||
var_pattern = r'{{\s*([\w.|()\'",\s]+)\s*}}'
|
||||
|
||||
def replace_var(match):
|
||||
expr = match.group(1)
|
||||
value = self.resolve_value(expr, context)
|
||||
return str(value) if value is not None else ''
|
||||
|
||||
result = re.sub(var_pattern, replace_var, result)
|
||||
|
||||
# Clean up any remaining template syntax
|
||||
result = re.sub(r'{%.*?%}', '', result)
|
||||
result = re.sub(r'{{.*?}}', '', result)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
class DocGenerator:
|
||||
"""Generates documentation from marketplace data"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
marketplace_path: str = ".claude-plugin/marketplace.json",
|
||||
templates_dir: str = "plugins/claude-plugin/skills/documentation-update/assets",
|
||||
output_dir: str = "docs",
|
||||
):
|
||||
self.marketplace_path = Path(marketplace_path)
|
||||
self.templates_dir = Path(templates_dir)
|
||||
self.output_dir = Path(output_dir)
|
||||
self.marketplace_data: Dict[str, Any] = {}
|
||||
|
||||
def load_marketplace(self) -> None:
|
||||
"""Load marketplace.json"""
|
||||
if not self.marketplace_path.exists():
|
||||
raise FileNotFoundError(f"Marketplace not found: {self.marketplace_path}")
|
||||
|
||||
with open(self.marketplace_path, 'r') as f:
|
||||
self.marketplace_data = json.load(f)
|
||||
|
||||
def extract_frontmatter(self, file_path: Path) -> Dict[str, str]:
|
||||
"""Extract YAML frontmatter from a markdown file"""
|
||||
if not file_path.exists():
|
||||
return {}
|
||||
|
||||
try:
|
||||
with open(file_path, 'r') as f:
|
||||
content = f.read()
|
||||
|
||||
# Match frontmatter between --- delimiters
|
||||
match = re.match(r'^---\s*\n(.*?)\n---\s*\n', content, re.DOTALL)
|
||||
if not match:
|
||||
return {}
|
||||
|
||||
frontmatter_text = match.group(1)
|
||||
frontmatter = {}
|
||||
|
||||
# Simple YAML parsing (key: value)
|
||||
for line in frontmatter_text.split('\n'):
|
||||
if ':' in line:
|
||||
key, value = line.split(':', 1)
|
||||
frontmatter[key.strip()] = value.strip().strip('"\'')
|
||||
|
||||
return frontmatter
|
||||
|
||||
except Exception as e:
|
||||
print(f"Warning: Could not parse frontmatter in {file_path}: {e}")
|
||||
return {}
|
||||
|
||||
def build_context(self) -> Dict[str, Any]:
|
||||
"""Build template context from marketplace data"""
|
||||
context = {
|
||||
"marketplace": self.marketplace_data,
|
||||
"now": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
||||
"plugins_by_category": {},
|
||||
"all_agents": [],
|
||||
"all_skills": [],
|
||||
"all_commands": [],
|
||||
"stats": {
|
||||
"total_plugins": 0,
|
||||
"total_agents": 0,
|
||||
"total_commands": 0,
|
||||
"total_skills": 0,
|
||||
},
|
||||
}
|
||||
|
||||
if "plugins" not in self.marketplace_data:
|
||||
return context
|
||||
|
||||
plugins = self.marketplace_data["plugins"]
|
||||
context["stats"]["total_plugins"] = len(plugins)
|
||||
|
||||
# Organize plugins by category
|
||||
for plugin in plugins:
|
||||
category = plugin.get("category", "general")
|
||||
if category not in context["plugins_by_category"]:
|
||||
context["plugins_by_category"][category] = []
|
||||
context["plugins_by_category"][category].append(plugin)
|
||||
|
||||
plugin_name = plugin.get("name", "")
|
||||
plugin_dir = Path(f"plugins/{plugin_name}")
|
||||
|
||||
# Extract agent information
|
||||
if "agents" in plugin:
|
||||
for agent_path in plugin["agents"]:
|
||||
agent_file = agent_path.replace("./agents/", "")
|
||||
full_path = plugin_dir / agent_path.lstrip('./')
|
||||
frontmatter = self.extract_frontmatter(full_path)
|
||||
|
||||
context["all_agents"].append({
|
||||
"plugin": plugin_name,
|
||||
"name": frontmatter.get("name", agent_file.replace(".md", "")),
|
||||
"file": agent_file,
|
||||
"description": frontmatter.get("description", ""),
|
||||
"model": frontmatter.get("model", ""),
|
||||
})
|
||||
|
||||
context["stats"]["total_agents"] += len(plugin["agents"])
|
||||
|
||||
# Extract command information
|
||||
if "commands" in plugin:
|
||||
for cmd_path in plugin["commands"]:
|
||||
cmd_file = cmd_path.replace("./commands/", "")
|
||||
full_path = plugin_dir / cmd_path.lstrip('./')
|
||||
frontmatter = self.extract_frontmatter(full_path)
|
||||
|
||||
context["all_commands"].append({
|
||||
"plugin": plugin_name,
|
||||
"name": frontmatter.get("name", cmd_file.replace(".md", "")),
|
||||
"file": cmd_file,
|
||||
"description": frontmatter.get("description", ""),
|
||||
})
|
||||
|
||||
context["stats"]["total_commands"] += len(plugin["commands"])
|
||||
|
||||
# Extract skill information
|
||||
if "skills" in plugin:
|
||||
for skill_path in plugin["skills"]:
|
||||
skill_name = skill_path.replace("./skills/", "")
|
||||
full_path = plugin_dir / skill_path.lstrip('./') / "SKILL.md"
|
||||
frontmatter = self.extract_frontmatter(full_path)
|
||||
|
||||
context["all_skills"].append({
|
||||
"plugin": plugin_name,
|
||||
"name": frontmatter.get("name", skill_name),
|
||||
"path": skill_name,
|
||||
"description": frontmatter.get("description", ""),
|
||||
})
|
||||
|
||||
context["stats"]["total_skills"] += len(plugin["skills"])
|
||||
|
||||
return context
|
||||
|
||||
def render_template(self, template_name: str, context: Dict[str, Any]) -> str:
|
||||
"""Render a template with context"""
|
||||
template_path = self.templates_dir / f"{template_name}.md.j2"
|
||||
|
||||
if not template_path.exists():
|
||||
raise FileNotFoundError(f"Template not found: {template_path}")
|
||||
|
||||
with open(template_path, 'r') as f:
|
||||
template_content = f.read()
|
||||
|
||||
if USE_JINJA2:
|
||||
# Use real Jinja2 for full compatibility
|
||||
template = Jinja2Template(template_content)
|
||||
return template.render(**context)
|
||||
else:
|
||||
# Fallback to SimpleTemplate
|
||||
template = SimpleTemplate(template_content)
|
||||
return template.render(context)
|
||||
|
||||
def generate_all(self, dry_run: bool = False, specific_file: Optional[str] = None) -> None:
|
||||
"""Generate all documentation files"""
|
||||
self.load_marketplace()
|
||||
context = self.build_context()
|
||||
|
||||
docs_to_generate = {
|
||||
"agents": "agents.md",
|
||||
"agent-skills": "agent-skills.md",
|
||||
"plugins": "plugins.md",
|
||||
"usage": "usage.md",
|
||||
}
|
||||
|
||||
if specific_file:
|
||||
if specific_file not in docs_to_generate:
|
||||
raise ValueError(f"Unknown documentation file: {specific_file}")
|
||||
docs_to_generate = {specific_file: docs_to_generate[specific_file]}
|
||||
|
||||
for template_name, output_file in docs_to_generate.items():
|
||||
try:
|
||||
print(f"Generating {output_file}...")
|
||||
content = self.render_template(template_name, context)
|
||||
|
||||
if dry_run:
|
||||
print(f"\n--- {output_file} ---")
|
||||
print(content[:500] + "..." if len(content) > 500 else content)
|
||||
print()
|
||||
else:
|
||||
output_path = self.output_dir / output_file
|
||||
output_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
with open(output_path, 'w') as f:
|
||||
f.write(content)
|
||||
|
||||
print(f"✓ Generated {output_path}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error generating {output_file}: {e}")
|
||||
|
||||
|
||||
def main():
|
||||
"""Main entry point"""
|
||||
parser = argparse.ArgumentParser(description="Generate documentation from marketplace")
|
||||
parser.add_argument(
|
||||
"--marketplace",
|
||||
default=".claude-plugin/marketplace.json",
|
||||
help="Path to marketplace.json",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--templates",
|
||||
default="plugins/claude-plugin/skills/documentation-update/assets",
|
||||
help="Path to templates directory",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--output",
|
||||
default="docs",
|
||||
help="Output directory for documentation",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--file",
|
||||
choices=["agents", "agent-skills", "plugins", "usage"],
|
||||
help="Generate specific file only",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--dry-run",
|
||||
action="store_true",
|
||||
help="Show output without writing files",
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
generator = DocGenerator(
|
||||
marketplace_path=args.marketplace,
|
||||
templates_dir=args.templates,
|
||||
output_dir=args.output,
|
||||
)
|
||||
|
||||
generator.generate_all(dry_run=args.dry_run, specific_file=args.file)
|
||||
|
||||
if not args.dry_run:
|
||||
print("\n✓ Documentation generation complete")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
357
skills/marketplace-update/SKILL.md
Normal file
357
skills/marketplace-update/SKILL.md
Normal file
@@ -0,0 +1,357 @@
|
||||
---
|
||||
name: marketplace-update
|
||||
description: Updates the .claude-plugin/marketplace.json file when plugins are added, modified, or removed. Use when creating or updating plugin entries in the marketplace catalog.
|
||||
---
|
||||
|
||||
# Marketplace Update Skill
|
||||
|
||||
This skill provides functionality to update the `.claude-plugin/marketplace.json` file when plugins are added, modified, or removed from the marketplace.
|
||||
|
||||
## Purpose
|
||||
|
||||
Maintain the marketplace catalog by:
|
||||
|
||||
- Adding new plugin entries
|
||||
- Updating existing plugin metadata
|
||||
- Removing obsolete plugins
|
||||
- Validating marketplace structure
|
||||
- Ensuring consistency across the catalog
|
||||
|
||||
## When to Use
|
||||
|
||||
Use this skill when:
|
||||
|
||||
- A new plugin is created and needs to be registered
|
||||
- An existing plugin's components change (agents, commands, skills added/removed)
|
||||
- Plugin metadata needs updating (version, description, keywords, etc.)
|
||||
- A plugin is being removed from the marketplace
|
||||
- Validating marketplace.json structure
|
||||
|
||||
## Marketplace Structure
|
||||
|
||||
The marketplace.json file follows this schema:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "marketplace-name",
|
||||
"owner": {
|
||||
"name": "Owner Name",
|
||||
"email": "email@example.com",
|
||||
"url": "https://github.com/username"
|
||||
},
|
||||
"metadata": {
|
||||
"description": "Marketplace description",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"plugins": [
|
||||
{
|
||||
"name": "plugin-name",
|
||||
"source": "./plugins/plugin-name",
|
||||
"description": "Plugin description",
|
||||
"version": "1.0.0",
|
||||
"author": {
|
||||
"name": "Author Name",
|
||||
"url": "https://github.com/username"
|
||||
},
|
||||
"homepage": "https://github.com/username/repo",
|
||||
"repository": "https://github.com/username/repo",
|
||||
"license": "MIT",
|
||||
"keywords": ["keyword1", "keyword2"],
|
||||
"category": "category-name",
|
||||
"strict": false,
|
||||
"commands": ["./commands/command-name.md"],
|
||||
"agents": ["./agents/agent-name.md"],
|
||||
"skills": ["./skills/skill-name"]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Operations
|
||||
|
||||
### Add Plugin
|
||||
|
||||
Add a new plugin entry to the marketplace:
|
||||
|
||||
```python
|
||||
# Use the provided Python script
|
||||
python marketplace_update.py add \
|
||||
--name "plugin-name" \
|
||||
--description "Plugin description" \
|
||||
--version "1.0.0" \
|
||||
--category "category-name" \
|
||||
--agents "agent1.md,agent2.md" \
|
||||
--commands "command1.md,command2.md" \
|
||||
--skills "skill1,skill2"
|
||||
```
|
||||
|
||||
**Required Fields:**
|
||||
|
||||
- `name` - Plugin name (hyphen-case)
|
||||
- `description` - Brief plugin description
|
||||
- `version` - Semantic version (e.g., "1.0.0")
|
||||
|
||||
**Optional Fields:**
|
||||
|
||||
- `category` - Plugin category (default: "general")
|
||||
- `agents` - Comma-separated list of agent files
|
||||
- `commands` - Comma-separated list of command files
|
||||
- `skills` - Comma-separated list of skill directories
|
||||
- `keywords` - Comma-separated list of keywords
|
||||
- `license` - License type (default: "MIT")
|
||||
- `strict` - Strict mode flag (default: false)
|
||||
|
||||
### Update Plugin
|
||||
|
||||
Update an existing plugin entry:
|
||||
|
||||
```python
|
||||
python marketplace_update.py update \
|
||||
--name "plugin-name" \
|
||||
--description "Updated description" \
|
||||
--version "1.1.0" \
|
||||
--add-agent "new-agent.md" \
|
||||
--remove-command "old-command.md"
|
||||
```
|
||||
|
||||
**Update Operations:**
|
||||
|
||||
- `--description` - Update description
|
||||
- `--version` - Update version
|
||||
- `--category` - Update category
|
||||
- `--keywords` - Update keywords (replaces all)
|
||||
- `--add-agent` - Add agent file
|
||||
- `--remove-agent` - Remove agent file
|
||||
- `--add-command` - Add command file
|
||||
- `--remove-command` - Remove command file
|
||||
- `--add-skill` - Add skill directory
|
||||
- `--remove-skill` - Remove skill directory
|
||||
|
||||
### Remove Plugin
|
||||
|
||||
Remove a plugin from the marketplace:
|
||||
|
||||
```python
|
||||
python marketplace_update.py remove --name "plugin-name"
|
||||
```
|
||||
|
||||
### Validate Marketplace
|
||||
|
||||
Validate the marketplace.json structure:
|
||||
|
||||
```python
|
||||
python marketplace_update.py validate
|
||||
```
|
||||
|
||||
This checks:
|
||||
|
||||
- JSON syntax validity
|
||||
- Required fields presence
|
||||
- File path existence
|
||||
- Component reference validity
|
||||
- Duplicate plugin names
|
||||
|
||||
## Python Script
|
||||
|
||||
The skill includes a Python script at `marketplace_update.py` that provides command-line interface for all operations.
|
||||
|
||||
### Usage from Claude Code
|
||||
|
||||
When invoked as a skill:
|
||||
|
||||
1. **Read Plugin Structure**
|
||||
|
||||
- Scan plugin directory for components
|
||||
- Extract metadata from frontmatter
|
||||
- Build component lists
|
||||
|
||||
2. **Execute Python Script**
|
||||
|
||||
- Call marketplace_update.py with appropriate arguments
|
||||
- Pass plugin details
|
||||
- Handle success/error responses
|
||||
|
||||
3. **Validate Result**
|
||||
- Verify marketplace.json is valid
|
||||
- Confirm plugin entry is correct
|
||||
- Report success or errors
|
||||
|
||||
## Examples
|
||||
|
||||
### Example 1: Add New Plugin
|
||||
|
||||
```python
|
||||
# Plugin: golang-development
|
||||
# Components: 3 agents, 1 command, 4 skills
|
||||
|
||||
python marketplace_update.py add \
|
||||
--name "golang-development" \
|
||||
--description "Go language development tools" \
|
||||
--version "1.0.0" \
|
||||
--category "languages" \
|
||||
--keywords "golang,go,development" \
|
||||
--agents "golang-pro.md,gin-pro.md,charm-pro.md" \
|
||||
--commands "golang-scaffold.md" \
|
||||
--skills "async-golang-patterns,golang-testing-patterns,golang-packaging,golang-performance-optimization"
|
||||
```
|
||||
|
||||
### Example 2: Update Plugin Version
|
||||
|
||||
```python
|
||||
# Update version and add new agent
|
||||
|
||||
python marketplace_update.py update \
|
||||
--name "golang-development" \
|
||||
--version "1.1.0" \
|
||||
--add-agent "gorm-pro.md"
|
||||
```
|
||||
|
||||
### Example 3: Remove Plugin
|
||||
|
||||
```python
|
||||
python marketplace_update.py remove --name "obsolete-plugin"
|
||||
```
|
||||
|
||||
## Integration with Commands
|
||||
|
||||
The `/claude-plugin:create` and `/claude-plugin:update` commands should invoke this skill automatically:
|
||||
|
||||
### From /claude-plugin:create Command
|
||||
|
||||
After creating a new plugin:
|
||||
|
||||
```
|
||||
1. Scan plugin directory for components
|
||||
2. Extract metadata from agent/command frontmatter
|
||||
3. Invoke marketplace-update skill:
|
||||
- Operation: add
|
||||
- Plugin name: [from user input]
|
||||
- Components: [scanned from directory]
|
||||
- Metadata: [extracted from frontmatter]
|
||||
```
|
||||
|
||||
### From /claude-plugin:update Command
|
||||
|
||||
After updating a plugin:
|
||||
|
||||
```
|
||||
1. Determine what changed (added/removed/modified)
|
||||
2. Invoke marketplace-update skill:
|
||||
- Operation: update
|
||||
- Plugin name: [from user input]
|
||||
- Changes: [specific updates]
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Plugin Already Exists (Add)
|
||||
|
||||
```
|
||||
Error: Plugin 'plugin-name' already exists in marketplace.
|
||||
Suggestion: Use 'update' operation instead.
|
||||
```
|
||||
|
||||
### Plugin Not Found (Update/Remove)
|
||||
|
||||
```
|
||||
Error: Plugin 'plugin-name' not found in marketplace.
|
||||
Suggestion: Use 'add' operation to create it.
|
||||
```
|
||||
|
||||
### Invalid JSON
|
||||
|
||||
```
|
||||
Error: marketplace.json contains invalid JSON.
|
||||
Suggestion: Fix JSON syntax before proceeding.
|
||||
```
|
||||
|
||||
### Component File Missing
|
||||
|
||||
```
|
||||
Warning: Component file './agents/agent-name.md' not found.
|
||||
Suggestion: Create the file or remove from plugin entry.
|
||||
```
|
||||
|
||||
### Validation Failure
|
||||
|
||||
```
|
||||
Error: Marketplace validation failed:
|
||||
- Plugin 'plugin-a' missing required field 'description'
|
||||
- Plugin 'plugin-b' references non-existent agent 'missing.md'
|
||||
Suggestion: Fix errors and validate again.
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Always Validate After Changes**
|
||||
|
||||
- Run validate after add/update/remove
|
||||
- Fix any warnings or errors
|
||||
- Ensure all referenced files exist
|
||||
|
||||
2. **Scan Plugin Directory**
|
||||
|
||||
- Don't manually list components
|
||||
- Scan directory to detect agents/commands/skills
|
||||
- Extract metadata from frontmatter
|
||||
|
||||
3. **Semantic Versioning**
|
||||
|
||||
- Patch: Bug fixes, documentation updates (1.0.0 → 1.0.1)
|
||||
- Minor: New components, enhancements (1.0.0 → 1.1.0)
|
||||
- Major: Breaking changes, removals (1.0.0 → 2.0.0)
|
||||
|
||||
4. **Consistent Metadata**
|
||||
|
||||
- Keep descriptions concise (< 100 chars)
|
||||
- Use relevant keywords
|
||||
- Maintain consistent author information
|
||||
- Use appropriate categories
|
||||
|
||||
5. **Backup Before Changes**
|
||||
- Create backup of marketplace.json
|
||||
- Test changes in development first
|
||||
- Validate before committing
|
||||
|
||||
## Categories
|
||||
|
||||
Common plugin categories:
|
||||
|
||||
- `languages` - Language-specific tools (Python, Go, Rust, etc.)
|
||||
- `development` - General development tools
|
||||
- `security` - Security scanning and analysis
|
||||
- `testing` - Test generation and automation
|
||||
- `operations` - DevOps and operations tools
|
||||
- `infrastructure` - Cloud and infrastructure tools
|
||||
- `documentation` - Documentation generation
|
||||
- `architecture` - Architecture and design tools
|
||||
- `workflow` - Workflow orchestration
|
||||
- `general` - General purpose tools
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
plugins/claude-plugin/skills/marketplace-update/
|
||||
├── SKILL.md # This file
|
||||
├── marketplace_update.py # Python implementation
|
||||
└── references/ # Optional examples
|
||||
└── examples.md
|
||||
```
|
||||
|
||||
## Requirements
|
||||
|
||||
- Python 3.8+
|
||||
- No external dependencies (uses standard library only)
|
||||
- Access to `.claude-plugin/marketplace.json`
|
||||
- Read/write permissions on marketplace file
|
||||
|
||||
## Success Criteria
|
||||
|
||||
After running this skill:
|
||||
|
||||
- ✓ marketplace.json is valid JSON
|
||||
- ✓ Plugin entry is correct and complete
|
||||
- ✓ All referenced files exist
|
||||
- ✓ No duplicate plugin names
|
||||
- ✓ Required fields are present
|
||||
- ✓ Validation passes without errors
|
||||
406
skills/marketplace-update/marketplace_update.py
Executable file
406
skills/marketplace-update/marketplace_update.py
Executable file
@@ -0,0 +1,406 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Marketplace Update Script
|
||||
|
||||
Updates the .claude-plugin/marketplace.json file when plugins are added,
|
||||
modified, or removed.
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Optional, Any
|
||||
import argparse
|
||||
|
||||
|
||||
class MarketplaceUpdater:
|
||||
"""Handles marketplace.json updates"""
|
||||
|
||||
def __init__(self, marketplace_path: str = ".claude-plugin/marketplace.json"):
|
||||
self.marketplace_path = Path(marketplace_path)
|
||||
self.marketplace_data: Dict[str, Any] = {}
|
||||
|
||||
def load(self) -> None:
|
||||
"""Load marketplace.json file"""
|
||||
if not self.marketplace_path.exists():
|
||||
raise FileNotFoundError(f"Marketplace file not found: {self.marketplace_path}")
|
||||
|
||||
try:
|
||||
with open(self.marketplace_path, 'r') as f:
|
||||
self.marketplace_data = json.load(f)
|
||||
except json.JSONDecodeError as e:
|
||||
raise ValueError(f"Invalid JSON in marketplace file: {e}")
|
||||
|
||||
def save(self) -> None:
|
||||
"""Save marketplace.json file"""
|
||||
with open(self.marketplace_path, 'w') as f:
|
||||
json.dump(self.marketplace_data, f, indent=2)
|
||||
f.write('\n') # Add trailing newline
|
||||
|
||||
def add_plugin(
|
||||
self,
|
||||
name: str,
|
||||
description: str,
|
||||
version: str,
|
||||
category: str = "general",
|
||||
agents: Optional[List[str]] = None,
|
||||
commands: Optional[List[str]] = None,
|
||||
skills: Optional[List[str]] = None,
|
||||
keywords: Optional[List[str]] = None,
|
||||
license: str = "MIT",
|
||||
strict: bool = False,
|
||||
author_name: Optional[str] = None,
|
||||
author_url: Optional[str] = None,
|
||||
) -> None:
|
||||
"""Add a new plugin to the marketplace"""
|
||||
self.load()
|
||||
|
||||
# Check if plugin already exists
|
||||
if "plugins" not in self.marketplace_data:
|
||||
self.marketplace_data["plugins"] = []
|
||||
|
||||
existing_plugin = self._find_plugin(name)
|
||||
if existing_plugin:
|
||||
raise ValueError(f"Plugin '{name}' already exists in marketplace")
|
||||
|
||||
# Build plugin entry
|
||||
plugin_entry: Dict[str, Any] = {
|
||||
"name": name,
|
||||
"source": f"./plugins/{name}",
|
||||
"description": description,
|
||||
"version": version,
|
||||
"category": category,
|
||||
"license": license,
|
||||
"strict": strict,
|
||||
}
|
||||
|
||||
# Add author if provided, otherwise use marketplace owner
|
||||
if author_name or author_url:
|
||||
plugin_entry["author"] = {}
|
||||
if author_name:
|
||||
plugin_entry["author"]["name"] = author_name
|
||||
if author_url:
|
||||
plugin_entry["author"]["url"] = author_url
|
||||
elif "owner" in self.marketplace_data:
|
||||
plugin_entry["author"] = {
|
||||
"name": self.marketplace_data["owner"].get("name", ""),
|
||||
"url": self.marketplace_data["owner"].get("url", ""),
|
||||
}
|
||||
|
||||
# Add homepage and repository from owner if available
|
||||
if "owner" in self.marketplace_data and "url" in self.marketplace_data["owner"]:
|
||||
base_url = self.marketplace_data["owner"]["url"]
|
||||
# Extract repo name from URL if it's a GitHub URL
|
||||
if "github.com" in base_url:
|
||||
plugin_entry["homepage"] = base_url
|
||||
plugin_entry["repository"] = base_url
|
||||
|
||||
# Add optional fields
|
||||
if keywords:
|
||||
plugin_entry["keywords"] = keywords
|
||||
|
||||
if agents:
|
||||
plugin_entry["agents"] = [f"./agents/{agent}" for agent in agents]
|
||||
|
||||
if commands:
|
||||
plugin_entry["commands"] = [f"./commands/{cmd}" for cmd in commands]
|
||||
|
||||
if skills:
|
||||
plugin_entry["skills"] = [f"./skills/{skill}" for skill in skills]
|
||||
|
||||
# Add plugin to marketplace
|
||||
self.marketplace_data["plugins"].append(plugin_entry)
|
||||
self.save()
|
||||
|
||||
print(f"✓ Added plugin '{name}' to marketplace")
|
||||
|
||||
def update_plugin(
|
||||
self,
|
||||
name: str,
|
||||
description: Optional[str] = None,
|
||||
version: Optional[str] = None,
|
||||
category: Optional[str] = None,
|
||||
keywords: Optional[List[str]] = None,
|
||||
add_agent: Optional[str] = None,
|
||||
remove_agent: Optional[str] = None,
|
||||
add_command: Optional[str] = None,
|
||||
remove_command: Optional[str] = None,
|
||||
add_skill: Optional[str] = None,
|
||||
remove_skill: Optional[str] = None,
|
||||
) -> None:
|
||||
"""Update an existing plugin"""
|
||||
self.load()
|
||||
|
||||
plugin = self._find_plugin(name)
|
||||
if not plugin:
|
||||
raise ValueError(f"Plugin '{name}' not found in marketplace")
|
||||
|
||||
# Update basic fields
|
||||
if description:
|
||||
plugin["description"] = description
|
||||
if version:
|
||||
plugin["version"] = version
|
||||
if category:
|
||||
plugin["category"] = category
|
||||
if keywords:
|
||||
plugin["keywords"] = keywords
|
||||
|
||||
# Update agents
|
||||
if add_agent:
|
||||
if "agents" not in plugin:
|
||||
plugin["agents"] = []
|
||||
agent_path = f"./agents/{add_agent}"
|
||||
if agent_path not in plugin["agents"]:
|
||||
plugin["agents"].append(agent_path)
|
||||
|
||||
if remove_agent:
|
||||
if "agents" in plugin:
|
||||
agent_path = f"./agents/{remove_agent}"
|
||||
if agent_path in plugin["agents"]:
|
||||
plugin["agents"].remove(agent_path)
|
||||
|
||||
# Update commands
|
||||
if add_command:
|
||||
if "commands" not in plugin:
|
||||
plugin["commands"] = []
|
||||
cmd_path = f"./commands/{add_command}"
|
||||
if cmd_path not in plugin["commands"]:
|
||||
plugin["commands"].append(cmd_path)
|
||||
|
||||
if remove_command:
|
||||
if "commands" in plugin:
|
||||
cmd_path = f"./commands/{remove_command}"
|
||||
if cmd_path in plugin["commands"]:
|
||||
plugin["commands"].remove(cmd_path)
|
||||
|
||||
# Update skills
|
||||
if add_skill:
|
||||
if "skills" not in plugin:
|
||||
plugin["skills"] = []
|
||||
skill_path = f"./skills/{add_skill}"
|
||||
if skill_path not in plugin["skills"]:
|
||||
plugin["skills"].append(skill_path)
|
||||
|
||||
if remove_skill:
|
||||
if "skills" in plugin:
|
||||
skill_path = f"./skills/{remove_skill}"
|
||||
if skill_path in plugin["skills"]:
|
||||
plugin["skills"].remove(skill_path)
|
||||
|
||||
self.save()
|
||||
print(f"✓ Updated plugin '{name}' in marketplace")
|
||||
|
||||
def remove_plugin(self, name: str) -> None:
|
||||
"""Remove a plugin from the marketplace"""
|
||||
self.load()
|
||||
|
||||
plugin = self._find_plugin(name)
|
||||
if not plugin:
|
||||
raise ValueError(f"Plugin '{name}' not found in marketplace")
|
||||
|
||||
self.marketplace_data["plugins"].remove(plugin)
|
||||
self.save()
|
||||
|
||||
print(f"✓ Removed plugin '{name}' from marketplace")
|
||||
|
||||
def validate(self) -> bool:
|
||||
"""Validate marketplace structure"""
|
||||
self.load()
|
||||
|
||||
errors = []
|
||||
warnings = []
|
||||
|
||||
# Check required top-level fields
|
||||
required_fields = ["name", "owner", "metadata", "plugins"]
|
||||
for field in required_fields:
|
||||
if field not in self.marketplace_data:
|
||||
errors.append(f"Missing required field: {field}")
|
||||
|
||||
# Validate plugins
|
||||
if "plugins" in self.marketplace_data:
|
||||
plugin_names = set()
|
||||
for i, plugin in enumerate(self.marketplace_data["plugins"]):
|
||||
# Check required plugin fields
|
||||
plugin_required = ["name", "source", "description", "version"]
|
||||
for field in plugin_required:
|
||||
if field not in plugin:
|
||||
errors.append(f"Plugin {i}: Missing required field '{field}'")
|
||||
|
||||
# Check for duplicate names
|
||||
if "name" in plugin:
|
||||
if plugin["name"] in plugin_names:
|
||||
errors.append(f"Duplicate plugin name: {plugin['name']}")
|
||||
plugin_names.add(plugin["name"])
|
||||
|
||||
# Validate component file paths
|
||||
plugin_dir = Path(f"plugins/{plugin['name']}")
|
||||
|
||||
if "agents" in plugin:
|
||||
for agent in plugin["agents"]:
|
||||
agent_path = plugin_dir / agent
|
||||
if not agent_path.exists():
|
||||
warnings.append(
|
||||
f"Plugin '{plugin['name']}': Agent file not found: {agent_path}"
|
||||
)
|
||||
|
||||
if "commands" in plugin:
|
||||
for command in plugin["commands"]:
|
||||
cmd_path = plugin_dir / command
|
||||
if not cmd_path.exists():
|
||||
warnings.append(
|
||||
f"Plugin '{plugin['name']}': Command file not found: {cmd_path}"
|
||||
)
|
||||
|
||||
if "skills" in plugin:
|
||||
for skill in plugin["skills"]:
|
||||
skill_path = plugin_dir / skill / "SKILL.md"
|
||||
if not skill_path.exists():
|
||||
warnings.append(
|
||||
f"Plugin '{plugin['name']}': Skill file not found: {skill_path}"
|
||||
)
|
||||
|
||||
# Report results
|
||||
if errors:
|
||||
print("❌ Validation failed with errors:")
|
||||
for error in errors:
|
||||
print(f" - {error}")
|
||||
else:
|
||||
print("✓ Validation passed with no errors")
|
||||
|
||||
if warnings:
|
||||
print("\n⚠️ Warnings:")
|
||||
for warning in warnings:
|
||||
print(f" - {warning}")
|
||||
|
||||
return len(errors) == 0
|
||||
|
||||
def _find_plugin(self, name: str) -> Optional[Dict[str, Any]]:
|
||||
"""Find a plugin by name"""
|
||||
if "plugins" not in self.marketplace_data:
|
||||
return None
|
||||
|
||||
for plugin in self.marketplace_data["plugins"]:
|
||||
if plugin.get("name") == name:
|
||||
return plugin
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def main():
|
||||
"""Main entry point"""
|
||||
parser = argparse.ArgumentParser(description="Update marketplace.json")
|
||||
subparsers = parser.add_subparsers(dest="command", help="Command to execute")
|
||||
|
||||
# Add command
|
||||
add_parser = subparsers.add_parser("add", help="Add a new plugin")
|
||||
add_parser.add_argument("--name", required=True, help="Plugin name")
|
||||
add_parser.add_argument("--description", required=True, help="Plugin description")
|
||||
add_parser.add_argument("--version", required=True, help="Plugin version")
|
||||
add_parser.add_argument("--category", default="general", help="Plugin category")
|
||||
add_parser.add_argument("--agents", help="Comma-separated list of agent files")
|
||||
add_parser.add_argument("--commands", help="Comma-separated list of command files")
|
||||
add_parser.add_argument("--skills", help="Comma-separated list of skill directories")
|
||||
add_parser.add_argument("--keywords", help="Comma-separated list of keywords")
|
||||
add_parser.add_argument("--license", default="MIT", help="License type")
|
||||
add_parser.add_argument("--strict", action="store_true", help="Enable strict mode")
|
||||
add_parser.add_argument("--author-name", help="Author name")
|
||||
add_parser.add_argument("--author-url", help="Author URL")
|
||||
add_parser.add_argument(
|
||||
"--marketplace",
|
||||
default=".claude-plugin/marketplace.json",
|
||||
help="Path to marketplace.json",
|
||||
)
|
||||
|
||||
# Update command
|
||||
update_parser = subparsers.add_parser("update", help="Update an existing plugin")
|
||||
update_parser.add_argument("--name", required=True, help="Plugin name")
|
||||
update_parser.add_argument("--description", help="Updated description")
|
||||
update_parser.add_argument("--version", help="Updated version")
|
||||
update_parser.add_argument("--category", help="Updated category")
|
||||
update_parser.add_argument("--keywords", help="Updated keywords (comma-separated)")
|
||||
update_parser.add_argument("--add-agent", help="Agent file to add")
|
||||
update_parser.add_argument("--remove-agent", help="Agent file to remove")
|
||||
update_parser.add_argument("--add-command", help="Command file to add")
|
||||
update_parser.add_argument("--remove-command", help="Command file to remove")
|
||||
update_parser.add_argument("--add-skill", help="Skill directory to add")
|
||||
update_parser.add_argument("--remove-skill", help="Skill directory to remove")
|
||||
update_parser.add_argument(
|
||||
"--marketplace",
|
||||
default=".claude-plugin/marketplace.json",
|
||||
help="Path to marketplace.json",
|
||||
)
|
||||
|
||||
# Remove command
|
||||
remove_parser = subparsers.add_parser("remove", help="Remove a plugin")
|
||||
remove_parser.add_argument("--name", required=True, help="Plugin name")
|
||||
remove_parser.add_argument(
|
||||
"--marketplace",
|
||||
default=".claude-plugin/marketplace.json",
|
||||
help="Path to marketplace.json",
|
||||
)
|
||||
|
||||
# Validate command
|
||||
validate_parser = subparsers.add_parser("validate", help="Validate marketplace.json")
|
||||
validate_parser.add_argument(
|
||||
"--marketplace",
|
||||
default=".claude-plugin/marketplace.json",
|
||||
help="Path to marketplace.json",
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if not args.command:
|
||||
parser.print_help()
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
updater = MarketplaceUpdater(
|
||||
getattr(args, "marketplace", ".claude-plugin/marketplace.json")
|
||||
)
|
||||
|
||||
if args.command == "add":
|
||||
updater.add_plugin(
|
||||
name=args.name,
|
||||
description=args.description,
|
||||
version=args.version,
|
||||
category=args.category,
|
||||
agents=args.agents.split(",") if args.agents else None,
|
||||
commands=args.commands.split(",") if args.commands else None,
|
||||
skills=args.skills.split(",") if args.skills else None,
|
||||
keywords=args.keywords.split(",") if args.keywords else None,
|
||||
license=args.license,
|
||||
strict=args.strict,
|
||||
author_name=args.author_name,
|
||||
author_url=args.author_url,
|
||||
)
|
||||
|
||||
elif args.command == "update":
|
||||
updater.update_plugin(
|
||||
name=args.name,
|
||||
description=args.description,
|
||||
version=args.version,
|
||||
category=args.category,
|
||||
keywords=args.keywords.split(",") if args.keywords else None,
|
||||
add_agent=args.add_agent,
|
||||
remove_agent=args.remove_agent,
|
||||
add_command=args.add_command,
|
||||
remove_command=args.remove_command,
|
||||
add_skill=args.add_skill,
|
||||
remove_skill=args.remove_skill,
|
||||
)
|
||||
|
||||
elif args.command == "remove":
|
||||
updater.remove_plugin(name=args.name)
|
||||
|
||||
elif args.command == "validate":
|
||||
if not updater.validate():
|
||||
sys.exit(1)
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user