Initial commit
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"name": "[marketplace-name]",
|
||||
"version": "1.0.0",
|
||||
"description": "[Marketplace description]",
|
||||
"author": {
|
||||
"name": "[Author Name]",
|
||||
"email": "[author@example.com]",
|
||||
"url": "https://github.com/[username]"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/[username]/[marketplace-name].git"
|
||||
},
|
||||
"license": "MIT",
|
||||
"keywords": ["claude-code", "marketplace", "plugins", "skills"],
|
||||
"homepage": "https://github.com/[username]/[marketplace-name]#readme",
|
||||
"bugs": {
|
||||
"url": "https://github.com/[username]/[marketplace-name]/issues"
|
||||
},
|
||||
"engines": {
|
||||
"claude-code": ">=1.0.0"
|
||||
},
|
||||
"categories": ["productivity", "development"],
|
||||
"permissions": {
|
||||
"tools": ["Read", "Write", "Bash", "WebFetch"],
|
||||
"domains": ["github.com", "docs.claude.com"],
|
||||
"fileSystem": {
|
||||
"allowedPaths": ["./workspace", "/tmp"],
|
||||
"deniedPaths": ["/etc", "/usr/bin"]
|
||||
}
|
||||
},
|
||||
"commands": [
|
||||
{
|
||||
"name": "[command-name]",
|
||||
"description": "[Command description]",
|
||||
"usage": "/[command-name] [options]",
|
||||
"examples": ["/[command-name] --help", "/[command-name] input.txt output.txt"]
|
||||
}
|
||||
],
|
||||
"skills": [
|
||||
{
|
||||
"name": "[skill-name]",
|
||||
"description": "[Skill description]",
|
||||
"category": "development"
|
||||
}
|
||||
]
|
||||
}
|
||||
104
skills/claude-code-marketplace/templates/standard/README.md
Normal file
104
skills/claude-code-marketplace/templates/standard/README.md
Normal file
@@ -0,0 +1,104 @@
|
||||
# [Marketplace Name]
|
||||
|
||||
> **Description**: [Brief description of your marketplace]
|
||||
|
||||
## Overview
|
||||
|
||||
This marketplace provides a curated collection of Claude Code plugins and skills for [specific purpose or domain].
|
||||
|
||||
## Installation
|
||||
|
||||
Add this marketplace to Claude Code:
|
||||
|
||||
```bash
|
||||
/plugin marketplace add [repository-url]
|
||||
```
|
||||
|
||||
## Available Plugins
|
||||
|
||||
### [Plugin Name]
|
||||
|
||||
- **Description**: [Brief description]
|
||||
- **Version**: [version]
|
||||
- **Usage**: `/[command-name] [options]`
|
||||
|
||||
## Available Skills
|
||||
|
||||
### [Skill Name]
|
||||
|
||||
- **Description**: [Brief description]
|
||||
- **Category**: [category]
|
||||
- **Usage**: [trigger phrase or usage pattern]
|
||||
|
||||
## Quick Start
|
||||
|
||||
1. Install the marketplace:
|
||||
|
||||
```bash
|
||||
/plugin marketplace add [repository-url]
|
||||
```
|
||||
|
||||
2. Browse available plugins:
|
||||
|
||||
```bash
|
||||
/plugin
|
||||
```
|
||||
|
||||
3. Install desired plugins:
|
||||
```bash
|
||||
/plugin install [plugin-name]@[marketplace-name]
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
### Adding Plugins
|
||||
|
||||
1. Create plugin directory in `plugins/`
|
||||
2. Add plugin configuration to marketplace.json
|
||||
3. Test plugin locally
|
||||
4. Submit pull request
|
||||
|
||||
### Adding Skills
|
||||
|
||||
1. Create skill directory in `skills/`
|
||||
2. Add skill documentation and examples
|
||||
3. Test skill functionality
|
||||
4. Update marketplace configuration
|
||||
|
||||
## Validation
|
||||
|
||||
Validate marketplace structure:
|
||||
|
||||
```bash
|
||||
node scripts/validate.js
|
||||
```
|
||||
|
||||
## Deployment
|
||||
|
||||
Deploy marketplace changes:
|
||||
|
||||
```bash
|
||||
node scripts/deploy.js
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
1. Fork the repository
|
||||
2. Create feature branch
|
||||
3. Add your plugin or skill
|
||||
4. Ensure all validations pass
|
||||
5. Submit pull request
|
||||
|
||||
## License
|
||||
|
||||
This marketplace is licensed under the [License Type] License.
|
||||
|
||||
## Support
|
||||
|
||||
- **Issues**: [GitHub Issues URL]
|
||||
- **Discussions**: [GitHub Discussions URL]
|
||||
- **Documentation**: [Documentation URL]
|
||||
|
||||
---
|
||||
|
||||
_Generated with Claude Code Marketplace Manager_
|
||||
343
skills/claude-code-marketplace/templates/standard/docs/GUIDE.md
Normal file
343
skills/claude-code-marketplace/templates/standard/docs/GUIDE.md
Normal file
@@ -0,0 +1,343 @@
|
||||
# [Marketplace Name] - User Guide
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Installation](#installation)
|
||||
2. [Getting Started](#getting-started)
|
||||
3. [Available Plugins](#available-plugins)
|
||||
4. [Available Skills](#available-skills)
|
||||
5. [Usage Examples](#usage-examples)
|
||||
6. [Configuration](#configuration)
|
||||
7. [Troubleshooting](#troubleshooting)
|
||||
|
||||
## Installation
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Claude Code Pro subscription
|
||||
- Git installed and configured
|
||||
- Node.js 18+ (for development)
|
||||
|
||||
### Adding the Marketplace
|
||||
|
||||
1. Add the marketplace to Claude Code:
|
||||
|
||||
```bash
|
||||
/plugin marketplace add [repository-url]
|
||||
```
|
||||
|
||||
2. Verify installation:
|
||||
```bash
|
||||
/plugin marketplace list
|
||||
```
|
||||
|
||||
### Installing Plugins
|
||||
|
||||
Browse available plugins:
|
||||
|
||||
```bash
|
||||
/plugin
|
||||
```
|
||||
|
||||
Install specific plugin:
|
||||
|
||||
```bash
|
||||
/plugin install [plugin-name]@[marketplace-name]
|
||||
```
|
||||
|
||||
## Getting Started
|
||||
|
||||
### First Steps
|
||||
|
||||
1. **Install Core Plugins**: Start with essential plugins for your workflow
|
||||
2. **Explore Skills**: Test different skills to understand their capabilities
|
||||
3. **Configure Settings**: Adjust plugin settings according to your needs
|
||||
4. **Read Documentation**: Review individual plugin and skill documentation
|
||||
|
||||
### Basic Workflow
|
||||
|
||||
```bash
|
||||
# 1. List available tools
|
||||
/help
|
||||
|
||||
# 2. Use a command from installed plugin
|
||||
/[plugin-command] [options]
|
||||
|
||||
# 3. Use a skill directly
|
||||
"Perform task using [skill-name]"
|
||||
|
||||
# 4. Check plugin status
|
||||
/plugin info [plugin-name]
|
||||
```
|
||||
|
||||
## Available Plugins
|
||||
|
||||
### [Plugin Name 1]
|
||||
|
||||
**Description**: [Detailed description]
|
||||
|
||||
**Commands**:
|
||||
|
||||
- `[command-1]`: [Description]
|
||||
- `[command-2]`: [Description]
|
||||
|
||||
**Examples**:
|
||||
|
||||
```bash
|
||||
/[command-1] --option value
|
||||
/[command-2] input.txt
|
||||
```
|
||||
|
||||
### [Plugin Name 2]
|
||||
|
||||
**Description**: [Detailed description]
|
||||
|
||||
**Commands**:
|
||||
|
||||
- `[command-1]`: [Description]
|
||||
- `[command-2]`: [Description]
|
||||
|
||||
**Examples**:
|
||||
|
||||
```bash
|
||||
/[command-1] --option value
|
||||
/[command-2] input.txt
|
||||
```
|
||||
|
||||
## Available Skills
|
||||
|
||||
### [Skill Name 1]
|
||||
|
||||
**Category**: [category]
|
||||
|
||||
**Description**: [Detailed description]
|
||||
|
||||
**When to Use**: [Usage scenarios]
|
||||
|
||||
**Examples**:
|
||||
|
||||
```bash
|
||||
"Use [skill-name] to [perform task]"
|
||||
"Process this file using [skill-name]"
|
||||
```
|
||||
|
||||
### [Skill Name 2]
|
||||
|
||||
**Category**: [category]
|
||||
|
||||
**Description**: [Detailed description]
|
||||
|
||||
**When to Use**: [Usage scenarios]
|
||||
|
||||
**Examples**:
|
||||
|
||||
```bash
|
||||
"Use [skill-name] to [perform task]"
|
||||
"Process this file using [skill-name]"
|
||||
```
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Example 1: [Task Name]
|
||||
|
||||
```bash
|
||||
# Step 1: Install required plugin
|
||||
/plugin install [plugin-name]@[marketplace-name]
|
||||
|
||||
# Step 2: Use the command
|
||||
/[command] [options] [input]
|
||||
|
||||
# Step 3: Use supporting skill
|
||||
"Complete the task using [skill-name]"
|
||||
```
|
||||
|
||||
### Example 2: [Task Name]
|
||||
|
||||
```bash
|
||||
# Step 1: Install multiple plugins
|
||||
/plugin install [plugin-1]@[marketplace-name]
|
||||
/plugin install [plugin-2]@[marketplace-name]
|
||||
|
||||
# Step 2: Combine commands
|
||||
/[command-1] [options]
|
||||
/[command-2] [options]
|
||||
|
||||
# Step 3: Use skill for final processing
|
||||
"Process results using [skill-name]"
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Plugin Settings
|
||||
|
||||
Most plugins support configuration through settings files or command-line options.
|
||||
|
||||
#### Configuration File Location
|
||||
|
||||
- **Global**: `~/.claude/settings.json`
|
||||
- **Project**: `.claude/settings.json`
|
||||
|
||||
#### Example Configuration
|
||||
|
||||
```json
|
||||
{
|
||||
"plugins": {
|
||||
"[plugin-name]": {
|
||||
"option1": "value1",
|
||||
"option2": "value2"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Skill Configuration
|
||||
|
||||
Skills can be configured through their SKILL.md files or at runtime.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
#### Plugin Installation Fails
|
||||
|
||||
**Problem**: Plugin won't install or shows errors
|
||||
|
||||
**Solution**:
|
||||
|
||||
```bash
|
||||
# Check marketplace connection
|
||||
/plugin marketplace list
|
||||
|
||||
# Update marketplace
|
||||
/plugin marketplace update [marketplace-name]
|
||||
|
||||
# Try alternative installation
|
||||
/plugin install [plugin-name]@[marketplace-name] --force
|
||||
```
|
||||
|
||||
#### Commands Not Available
|
||||
|
||||
**Problem**: Installed plugin commands don't appear in `/help`
|
||||
|
||||
**Solution**:
|
||||
|
||||
```bash
|
||||
# Check plugin status
|
||||
/plugin info [plugin-name]
|
||||
|
||||
# Restart Claude Code
|
||||
# Exit and restart Claude Code
|
||||
|
||||
# Verify installation
|
||||
/plugin list
|
||||
```
|
||||
|
||||
#### Skills Not Loading
|
||||
|
||||
**Problem**: Skills don't trigger or work correctly
|
||||
|
||||
**Solution**:
|
||||
|
||||
```bash
|
||||
# Check skill availability
|
||||
/skill-list
|
||||
|
||||
# Test skill manually
|
||||
"Test [skill-name] functionality"
|
||||
|
||||
# Check skill configuration
|
||||
/skill-info [skill-name]
|
||||
```
|
||||
|
||||
### Getting Help
|
||||
|
||||
If you encounter issues:
|
||||
|
||||
1. **Check Documentation**: Review individual plugin/skill documentation
|
||||
2. **Search Issues**: Look for similar issues in GitHub repository
|
||||
3. **Ask Community**: Post questions in discussions or issues
|
||||
4. **Report Bugs**: Create detailed issue reports with reproduction steps
|
||||
|
||||
### Debug Mode
|
||||
|
||||
Enable debug mode for troubleshooting:
|
||||
|
||||
```bash
|
||||
claude --debug
|
||||
claude --verbose
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Plugin Usage
|
||||
|
||||
1. **Start Small**: Begin with essential plugins
|
||||
2. **Read Documentation**: Understand plugin capabilities before use
|
||||
3. **Test Incrementally**: Test plugins with small tasks first
|
||||
4. **Monitor Performance**: Watch for performance impacts
|
||||
|
||||
### Skill Usage
|
||||
|
||||
1. **Be Specific**: Provide clear instructions and context
|
||||
2. **Use Examples**: Include example inputs when asking for help
|
||||
3. **Iterate**: Refine requests based on results
|
||||
4. **Provide Feedback**: Report issues and suggest improvements
|
||||
|
||||
### Workspace Management
|
||||
|
||||
1. **Organize Projects**: Use dedicated directories for different projects
|
||||
2. **Clean Regularly**: Remove unused plugins and skills
|
||||
3. **Backup Configuration**: Save your settings and preferences
|
||||
4. **Update Regularly**: Keep plugins and marketplace updated
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
### Custom Workflows
|
||||
|
||||
Combine multiple plugins and skills for complex workflows:
|
||||
|
||||
```bash
|
||||
# Example: Document processing workflow
|
||||
/[plugin-1] extract-text document.pdf
|
||||
"Analyze extracted text using [skill-name]"
|
||||
/[plugin-2] format-output --type markdown
|
||||
```
|
||||
|
||||
### Script Integration
|
||||
|
||||
Integrate with external scripts and automation:
|
||||
|
||||
```bash
|
||||
# Example: Batch processing
|
||||
for file in *.txt; do
|
||||
claude "Process $file using [skill-name]"
|
||||
done
|
||||
```
|
||||
|
||||
### API Integration
|
||||
|
||||
Some plugins support API integration for external services:
|
||||
|
||||
```json
|
||||
{
|
||||
"plugins": {
|
||||
"[plugin-name]": {
|
||||
"api_key": "your-api-key",
|
||||
"endpoint": "https://api.example.com"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Resources
|
||||
|
||||
- **Official Documentation**: [Link to docs]
|
||||
- **Community Forum**: [Link to forum]
|
||||
- **GitHub Repository**: [Link to repo]
|
||||
- **Video Tutorials**: [Link to videos]
|
||||
|
||||
---
|
||||
|
||||
_Last updated: [Date]_
|
||||
@@ -0,0 +1,352 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Marketplace Deployment Script
|
||||
* Handles deployment of marketplace plugins and updates
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { spawn } = require('child_process');
|
||||
|
||||
class MarketplaceDeployer {
|
||||
constructor(options = {}) {
|
||||
this.verbose = options.verbose || false;
|
||||
this.dryRun = options.dryRun || false;
|
||||
this.force = options.force || false;
|
||||
}
|
||||
|
||||
log(message, level = 'info') {
|
||||
if (this.verbose || level === 'error') {
|
||||
const timestamp = new Date().toISOString();
|
||||
console.log(`[${timestamp}] [${level.toUpperCase()}] ${message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute command safely
|
||||
*/
|
||||
async executeCommand(command, args = [], cwd = process.cwd()) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const child = spawn(command, args, {
|
||||
cwd,
|
||||
stdio: this.verbose ? 'inherit' : 'pipe',
|
||||
});
|
||||
|
||||
let stdout = '';
|
||||
let stderr = '';
|
||||
|
||||
if (!this.verbose) {
|
||||
child.stdout?.on('data', data => {
|
||||
stdout += data.toString();
|
||||
});
|
||||
|
||||
child.stderr?.on('data', data => {
|
||||
stderr += data.toString();
|
||||
});
|
||||
}
|
||||
|
||||
child.on('close', code => {
|
||||
if (code === 0) {
|
||||
resolve({ stdout, stderr, code });
|
||||
} else {
|
||||
reject(new Error(`Command failed with code ${code}: ${stderr}`));
|
||||
}
|
||||
});
|
||||
|
||||
child.on('error', error => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate marketplace before deployment
|
||||
*/
|
||||
async validateBeforeDeploy(marketplacePath) {
|
||||
this.log('Validating marketplace before deployment...');
|
||||
|
||||
const validatorPath = path.join(__dirname, 'validate.js');
|
||||
|
||||
try {
|
||||
await this.executeCommand('node', [validatorPath, '--verbose'], marketplacePath);
|
||||
this.log('Marketplace validation passed');
|
||||
return true;
|
||||
} catch (error) {
|
||||
this.log(`Marketplace validation failed: ${error.message}`, 'error');
|
||||
|
||||
if (!this.force) {
|
||||
throw new Error('Deployment aborted due to validation failures. Use --force to override.');
|
||||
}
|
||||
|
||||
this.log('Proceeding with deployment despite validation failures (force mode)', 'warn');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current version from marketplace configuration
|
||||
*/
|
||||
getCurrentVersion(marketplacePath) {
|
||||
const configPath = path.join(marketplacePath, '.claude-plugin', 'marketplace.json');
|
||||
|
||||
if (!fs.existsSync(configPath)) {
|
||||
throw new Error('Marketplace configuration not found');
|
||||
}
|
||||
|
||||
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
||||
return config.version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment version based on release type
|
||||
*/
|
||||
incrementVersion(version, type = 'patch') {
|
||||
const parts = version.split('.');
|
||||
|
||||
if (parts.length !== 3) {
|
||||
throw new Error(`Invalid version format: ${version}`);
|
||||
}
|
||||
|
||||
const [major, minor, patch] = parts.map(p => parseInt(p, 10));
|
||||
|
||||
switch (type) {
|
||||
case 'major':
|
||||
return `${major + 1}.0.0`;
|
||||
case 'minor':
|
||||
return `${major}.${minor + 1}.0`;
|
||||
case 'patch':
|
||||
return `${major}.${minor}.${patch + 1}`;
|
||||
default:
|
||||
throw new Error(`Invalid release type: ${type}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update marketplace version
|
||||
*/
|
||||
updateVersion(marketplacePath, newVersion) {
|
||||
const configPath = path.join(marketplacePath, '.claude-plugin', 'marketplace.json');
|
||||
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
||||
|
||||
config.version = newVersion;
|
||||
config.updated = new Date().toISOString();
|
||||
|
||||
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
||||
this.log(`Updated marketplace version to: ${newVersion}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create git tag for release
|
||||
*/
|
||||
async createGitTag(marketplacePath, version) {
|
||||
this.log(`Creating git tag: v${version}`);
|
||||
|
||||
if (!this.dryRun) {
|
||||
try {
|
||||
await this.executeCommand('git', ['add', '.'], marketplacePath);
|
||||
await this.executeCommand('git', ['commit', '-m', `Release v${version}`], marketplacePath);
|
||||
await this.executeCommand(
|
||||
'git',
|
||||
['tag', `-a`, `v${version}`, '-m', `Release v${version}`],
|
||||
marketplacePath
|
||||
);
|
||||
this.log(`Git tag v${version} created successfully`);
|
||||
} catch (error) {
|
||||
this.log(`Failed to create git tag: ${error.message}`, 'error');
|
||||
throw error;
|
||||
}
|
||||
} else {
|
||||
this.log(`[DRY RUN] Would create git tag: v${version}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Push to remote repository
|
||||
*/
|
||||
async pushToRemote(marketplacePath, version) {
|
||||
this.log('Pushing to remote repository...');
|
||||
|
||||
if (!this.dryRun) {
|
||||
try {
|
||||
await this.executeCommand('git', ['push', 'origin', 'main'], marketplacePath);
|
||||
await this.executeCommand('git', ['push', 'origin', `v${version}`], marketplacePath);
|
||||
this.log('Successfully pushed to remote repository');
|
||||
} catch (error) {
|
||||
this.log(`Failed to push to remote: ${error.message}`, 'error');
|
||||
throw error;
|
||||
}
|
||||
} else {
|
||||
this.log('[DRY RUN] Would push to remote repository');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate release notes
|
||||
*/
|
||||
generateReleaseNotes(marketplacePath, version) {
|
||||
const configPath = path.join(marketplacePath, '.claude-plugin', 'marketplace.json');
|
||||
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
||||
|
||||
const notes = [
|
||||
`# Release ${version}`,
|
||||
'',
|
||||
`## Changes`,
|
||||
'',
|
||||
`### Marketplace`,
|
||||
`- Updated marketplace configuration`,
|
||||
`- Version bump to ${version}`,
|
||||
'',
|
||||
`### Plugins`,
|
||||
`${config.plugins.length} plugins included`,
|
||||
'',
|
||||
`### Skills`,
|
||||
`${config.skills.length} skills included`,
|
||||
'',
|
||||
`## Installation`,
|
||||
'```bash',
|
||||
`/plugin marketplace add [repository-url]`,
|
||||
'```',
|
||||
'',
|
||||
`## Verification`,
|
||||
'```bash',
|
||||
`/plugin marketplace list`,
|
||||
`/plugin install [plugin-name]@[marketplace-name]`,
|
||||
'```',
|
||||
'',
|
||||
`---`,
|
||||
`*Released on ${new Date().toISOString().split('T')[0]}*`,
|
||||
];
|
||||
|
||||
const notesPath = path.join(marketplacePath, 'RELEASE_NOTES.md');
|
||||
fs.writeFileSync(notesPath, notes.join('\n'));
|
||||
|
||||
this.log(`Release notes generated: ${notesPath}`);
|
||||
return notesPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deploy marketplace
|
||||
*/
|
||||
async deploy(marketplacePath = './', options = {}) {
|
||||
const releaseType = options.type || 'patch';
|
||||
const skipValidation = options.skipValidation || false;
|
||||
const skipGit = options.skipGit || false;
|
||||
|
||||
console.log(`Starting marketplace deployment for: ${marketplacePath}`);
|
||||
console.log(`Release type: ${releaseType}`);
|
||||
console.log('='.repeat(50));
|
||||
|
||||
try {
|
||||
// Validate marketplace unless skipped
|
||||
if (!skipValidation) {
|
||||
await this.validateBeforeDeploy(marketplacePath);
|
||||
}
|
||||
|
||||
// Get current version
|
||||
const currentVersion = this.getCurrentVersion(marketplacePath);
|
||||
this.log(`Current version: ${currentVersion}`);
|
||||
|
||||
// Calculate new version
|
||||
const newVersion = this.incrementVersion(currentVersion, releaseType);
|
||||
this.log(`New version: ${newVersion}`);
|
||||
|
||||
// Update version in configuration
|
||||
this.updateVersion(marketplacePath, newVersion);
|
||||
|
||||
// Generate release notes
|
||||
const notesPath = this.generateReleaseNotes(marketplacePath, newVersion);
|
||||
|
||||
// Git operations unless skipped
|
||||
if (!skipGit) {
|
||||
await this.createGitTag(marketplacePath, newVersion);
|
||||
await this.pushToRemote(marketplacePath, newVersion);
|
||||
}
|
||||
|
||||
console.log('='.repeat(50));
|
||||
console.log('✅ Deployment completed successfully');
|
||||
console.log(`Version: ${newVersion}`);
|
||||
console.log(`Release notes: ${notesPath}`);
|
||||
|
||||
if (!skipGit) {
|
||||
console.log('Git tag created and pushed');
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
version: newVersion,
|
||||
notesPath,
|
||||
skipped: { validation: skipValidation, git: skipGit },
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('❌ Deployment failed:', error.message);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deploy individual plugin
|
||||
*/
|
||||
async deployPlugin(pluginPath, options = {}) {
|
||||
this.log(`Deploying plugin: ${pluginPath}`);
|
||||
|
||||
// Validate plugin structure
|
||||
const pluginJsonPath = path.join(pluginPath, '.claude-plugin', 'plugin.json');
|
||||
if (!fs.existsSync(pluginJsonPath)) {
|
||||
throw new Error('Plugin configuration not found');
|
||||
}
|
||||
|
||||
const pluginConfig = JSON.parse(fs.readFileSync(pluginJsonPath, 'utf8'));
|
||||
this.log(`Plugin: ${pluginConfig.name} v${pluginConfig.version}`);
|
||||
|
||||
// Implementation would depend on deployment target
|
||||
// This is a placeholder for actual plugin deployment logic
|
||||
|
||||
if (!this.dryRun) {
|
||||
// Add actual plugin deployment logic here
|
||||
// Could involve:
|
||||
// - Publishing to npm registry
|
||||
// - Creating GitHub release
|
||||
// - Uploading to plugin registry
|
||||
// etc.
|
||||
}
|
||||
|
||||
this.log(`Plugin deployment completed: ${pluginConfig.name}`);
|
||||
return { success: true, plugin: pluginConfig.name };
|
||||
}
|
||||
}
|
||||
|
||||
// CLI interface
|
||||
if (require.main === module) {
|
||||
const args = process.argv.slice(2);
|
||||
|
||||
const options = {
|
||||
verbose: args.includes('--verbose'),
|
||||
dryRun: args.includes('--dry-run'),
|
||||
force: args.includes('--force'),
|
||||
type: 'patch',
|
||||
skipValidation: args.includes('--skip-validation'),
|
||||
skipGit: args.includes('--skip-git'),
|
||||
};
|
||||
|
||||
// Parse release type
|
||||
const typeIndex = args.findIndex(arg => arg.startsWith('--type='));
|
||||
if (typeIndex !== -1) {
|
||||
options.type = args[typeIndex].split('=')[1];
|
||||
}
|
||||
|
||||
const marketplacePath = args.find(arg => !arg.startsWith('--')) || './';
|
||||
const deployer = new MarketplaceDeployer(options);
|
||||
|
||||
deployer
|
||||
.deploy(marketplacePath, options)
|
||||
.then(result => {
|
||||
console.log('\nDeployment summary:', result);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('\nDeployment failed:', error.message);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = MarketplaceDeployer;
|
||||
@@ -0,0 +1,391 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Marketplace Validation Script
|
||||
* Validates marketplace structure, configuration, and content
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
class MarketplaceValidator {
|
||||
constructor() {
|
||||
this.errors = [];
|
||||
this.warnings = [];
|
||||
this.info = [];
|
||||
}
|
||||
|
||||
log(message, type = 'info') {
|
||||
this[type].push(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate marketplace directory structure
|
||||
*/
|
||||
validateStructure(marketplacePath) {
|
||||
console.log('Validating marketplace structure...');
|
||||
|
||||
const requiredDirs = ['.claude-plugin'];
|
||||
const requiredFiles = ['.claude-plugin/marketplace.json'];
|
||||
const optionalDirs = ['plugins', 'skills', 'docs', 'tests', 'scripts', 'examples'];
|
||||
|
||||
// Check required directories
|
||||
requiredDirs.forEach(dir => {
|
||||
const dirPath = path.join(marketplacePath, dir);
|
||||
if (!fs.existsSync(dirPath)) {
|
||||
this.log(`Required directory missing: ${dir}`, 'errors');
|
||||
} else {
|
||||
this.log(`Required directory found: ${dir}`, 'info');
|
||||
}
|
||||
});
|
||||
|
||||
// Check required files
|
||||
requiredFiles.forEach(file => {
|
||||
const filePath = path.join(marketplacePath, file);
|
||||
if (!fs.existsSync(filePath)) {
|
||||
this.log(`Required file missing: ${file}`, 'errors');
|
||||
} else {
|
||||
this.log(`Required file found: ${file}`, 'info');
|
||||
}
|
||||
});
|
||||
|
||||
// Check optional directories
|
||||
optionalDirs.forEach(dir => {
|
||||
const dirPath = path.join(marketplacePath, dir);
|
||||
if (fs.existsSync(dirPath)) {
|
||||
this.log(`Optional directory found: ${dir}`, 'info');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate marketplace configuration
|
||||
*/
|
||||
validateConfiguration(marketplacePath) {
|
||||
console.log('Validating marketplace configuration...');
|
||||
|
||||
const configPath = path.join(marketplacePath, '.claude-plugin', 'marketplace.json');
|
||||
|
||||
if (!fs.existsSync(configPath)) {
|
||||
this.log('Marketplace configuration file missing', 'errors');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
||||
|
||||
// Validate required fields
|
||||
const requiredFields = ['name', 'version', 'description', 'owner'];
|
||||
requiredFields.forEach(field => {
|
||||
if (!config[field]) {
|
||||
this.log(`Required configuration field missing: ${field}`, 'errors');
|
||||
} else {
|
||||
this.log(`Required field found: ${field}`, 'info');
|
||||
}
|
||||
});
|
||||
|
||||
// Validate version format
|
||||
if (config.version && !this.isValidVersion(config.version)) {
|
||||
this.log(`Invalid version format: ${config.version}`, 'errors');
|
||||
}
|
||||
|
||||
// Validate plugins array
|
||||
if (config.plugins) {
|
||||
if (!Array.isArray(config.plugins)) {
|
||||
this.log('Plugins field must be an array', 'errors');
|
||||
} else {
|
||||
this.log(`Found ${config.plugins.length} plugins in configuration`, 'info');
|
||||
}
|
||||
}
|
||||
|
||||
// Validate skills array
|
||||
if (config.skills) {
|
||||
if (!Array.isArray(config.skills)) {
|
||||
this.log('Skills field must be an array', 'errors');
|
||||
} else {
|
||||
this.log(`Found ${config.skills.length} skills in configuration`, 'info');
|
||||
}
|
||||
}
|
||||
|
||||
// Validate owner object
|
||||
if (config.owner) {
|
||||
const ownerFields = ['name', 'email'];
|
||||
ownerFields.forEach(field => {
|
||||
if (config.owner[field]) {
|
||||
this.log(`Owner ${field} found: ${config.owner[field]}`, 'info');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.log('Configuration file structure validated', 'info');
|
||||
} catch (error) {
|
||||
this.log(`Invalid JSON in configuration file: ${error.message}`, 'errors');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate plugins
|
||||
*/
|
||||
validatePlugins(marketplacePath) {
|
||||
console.log('Validating plugins...');
|
||||
|
||||
const configPath = path.join(marketplacePath, '.claude-plugin', 'marketplace.json');
|
||||
|
||||
if (!fs.existsSync(configPath)) {
|
||||
this.log('Cannot validate plugins - configuration file missing', 'warnings');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
||||
|
||||
if (!config.plugins || config.plugins.length === 0) {
|
||||
this.log('No plugins configured in marketplace', 'warnings');
|
||||
return;
|
||||
}
|
||||
|
||||
const pluginsDir = path.join(marketplacePath, 'plugins');
|
||||
|
||||
if (!fs.existsSync(pluginsDir)) {
|
||||
this.log('Plugins directory not found', 'warnings');
|
||||
return;
|
||||
}
|
||||
|
||||
for (const plugin of config.plugins) {
|
||||
this.validatePlugin(plugin, pluginsDir);
|
||||
}
|
||||
} catch (error) {
|
||||
this.log(`Error validating plugins: ${error.message}`, 'errors');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate individual plugin
|
||||
*/
|
||||
validatePlugin(plugin, pluginsDir) {
|
||||
if (!plugin.name) {
|
||||
this.log('Plugin found without name in configuration', 'errors');
|
||||
return;
|
||||
}
|
||||
|
||||
const pluginPath = path.join(pluginsDir, plugin.name);
|
||||
if (!fs.existsSync(pluginPath)) {
|
||||
this.log(`Plugin directory not found: ${plugin.name}`, 'warnings');
|
||||
return;
|
||||
}
|
||||
|
||||
const pluginJsonPath = path.join(pluginPath, '.claude-plugin', 'plugin.json');
|
||||
if (!fs.existsSync(pluginJsonPath)) {
|
||||
this.log(`Plugin configuration missing: ${plugin.name}/plugin.json`, 'errors');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const pluginConfig = JSON.parse(fs.readFileSync(pluginJsonPath, 'utf8'));
|
||||
|
||||
// Validate plugin structure
|
||||
const requiredFields = ['name', 'version', 'description'];
|
||||
requiredFields.forEach(field => {
|
||||
if (!pluginConfig[field]) {
|
||||
this.log(`Plugin ${plugin.name}: Required field missing: ${field}`, 'errors');
|
||||
}
|
||||
});
|
||||
|
||||
this.log(`Plugin validated: ${plugin.name}`, 'info');
|
||||
} catch (error) {
|
||||
this.log(`Plugin ${plugin.name}: Invalid configuration - ${error.message}`, 'errors');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate skills
|
||||
*/
|
||||
validateSkills(marketplacePath) {
|
||||
console.log('Validating skills...');
|
||||
|
||||
const skillsDir = path.join(marketplacePath, 'skills');
|
||||
|
||||
if (!fs.existsSync(skillsDir)) {
|
||||
this.log('Skills directory not found', 'warnings');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const skills = fs
|
||||
.readdirSync(skillsDir, { withFileTypes: true })
|
||||
.filter(dirent => dirent.isDirectory())
|
||||
.map(dirent => dirent.name);
|
||||
|
||||
if (skills.length === 0) {
|
||||
this.log('No skills found in marketplace', 'warnings');
|
||||
return;
|
||||
}
|
||||
|
||||
for (const skill of skills) {
|
||||
this.validateSkill(path.join(skillsDir, skill), skill);
|
||||
}
|
||||
} catch (error) {
|
||||
this.log(`Error validating skills: ${error.message}`, 'errors');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate individual skill
|
||||
*/
|
||||
validateSkill(skillPath, skillName) {
|
||||
const skillMdPath = path.join(skillPath, 'SKILL.md');
|
||||
|
||||
if (!fs.existsSync(skillMdPath)) {
|
||||
this.log(`Skill SKILL.md missing: ${skillName}`, 'errors');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const content = fs.readFileSync(skillMdPath, 'utf8');
|
||||
|
||||
// Check for required frontmatter
|
||||
if (!content.includes('---')) {
|
||||
this.log(`Skill ${skillName}: Missing frontmatter`, 'errors');
|
||||
return;
|
||||
}
|
||||
|
||||
// Extract and validate frontmatter
|
||||
const frontmatterMatch = content.match(/^---\n(.*?)\n---/s);
|
||||
if (frontmatterMatch) {
|
||||
try {
|
||||
const frontmatter = JSON.parse(frontmatterMatch[1].replace(/(\w+):/g, '"$1":'));
|
||||
|
||||
if (!frontmatter.name) {
|
||||
this.log(`Skill ${skillName}: Missing name in frontmatter`, 'errors');
|
||||
}
|
||||
|
||||
if (!frontmatter.description) {
|
||||
this.log(`Skill ${skillName}: Missing description in frontmatter`, 'warnings');
|
||||
}
|
||||
} catch (error) {
|
||||
this.log(`Skill ${skillName}: Invalid frontmatter format`, 'errors');
|
||||
}
|
||||
}
|
||||
|
||||
this.log(`Skill validated: ${skillName}`, 'info');
|
||||
} catch (error) {
|
||||
this.log(`Skill ${skillName}: Error reading file - ${error.message}`, 'errors');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate documentation
|
||||
*/
|
||||
validateDocumentation(marketplacePath) {
|
||||
console.log('Validating documentation...');
|
||||
|
||||
const docsDir = path.join(marketplacePath, 'docs');
|
||||
|
||||
if (!fs.existsSync(docsDir)) {
|
||||
this.log('Documentation directory not found', 'warnings');
|
||||
return;
|
||||
}
|
||||
|
||||
const requiredDocs = ['README.md'];
|
||||
const recommendedDocs = ['GUIDE.md', 'CONTRIBUTING.md'];
|
||||
|
||||
// Check required documentation
|
||||
requiredDocs.forEach(doc => {
|
||||
const docPath = path.join(marketplacePath, doc);
|
||||
if (fs.existsSync(docPath)) {
|
||||
this.log(`Required documentation found: ${doc}`, 'info');
|
||||
} else {
|
||||
this.log(`Required documentation missing: ${doc}`, 'errors');
|
||||
}
|
||||
});
|
||||
|
||||
// Check recommended documentation
|
||||
recommendedDocs.forEach(doc => {
|
||||
const docPath = path.join(docsDir, doc);
|
||||
if (fs.existsSync(docPath)) {
|
||||
this.log(`Recommended documentation found: ${doc}`, 'info');
|
||||
} else {
|
||||
this.log(`Recommended documentation missing: ${doc}`, 'warnings');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if version string is valid
|
||||
*/
|
||||
isValidVersion(version) {
|
||||
return /^\d+\.\d+\.\d+(-.*)?$/.test(version);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run complete validation
|
||||
*/
|
||||
async validate(marketplacePath = './') {
|
||||
console.log(`Starting marketplace validation for: ${marketplacePath}`);
|
||||
console.log('='.repeat(50));
|
||||
|
||||
// Check if marketplace exists
|
||||
if (!fs.existsSync(marketplacePath)) {
|
||||
console.error('Error: Marketplace directory does not exist');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Run all validations
|
||||
this.validateStructure(marketplacePath);
|
||||
this.validateConfiguration(marketplacePath);
|
||||
this.validatePlugins(marketplacePath);
|
||||
this.validateSkills(marketplacePath);
|
||||
this.validateDocumentation(marketplacePath);
|
||||
|
||||
// Report results
|
||||
console.log('='.repeat(50));
|
||||
console.log('Validation Results:');
|
||||
console.log(`Errors: ${this.errors.length}`);
|
||||
console.log(`Warnings: ${this.warnings.length}`);
|
||||
console.log(`Info: ${this.info.length}`);
|
||||
|
||||
if (this.errors.length > 0) {
|
||||
console.log('\nErrors:');
|
||||
this.errors.forEach(error => console.log(` ❌ ${error}`));
|
||||
}
|
||||
|
||||
if (this.warnings.length > 0) {
|
||||
console.log('\nWarnings:');
|
||||
this.warnings.forEach(warning => console.log(` ⚠️ ${warning}`));
|
||||
}
|
||||
|
||||
if (this.verbose && this.info.length > 0) {
|
||||
console.log('\nInfo:');
|
||||
this.info.forEach(info => console.log(` ℹ️ ${info}`));
|
||||
}
|
||||
|
||||
// Exit with appropriate code
|
||||
if (this.errors.length > 0) {
|
||||
console.log('\n❌ Validation failed with errors');
|
||||
process.exit(1);
|
||||
} else if (this.warnings.length > 0) {
|
||||
console.log('\n⚠️ Validation completed with warnings');
|
||||
process.exit(2);
|
||||
} else {
|
||||
console.log('\n✅ Validation passed successfully');
|
||||
process.exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CLI interface
|
||||
if (require.main === module) {
|
||||
const args = process.argv.slice(2);
|
||||
const marketplacePath = args[0] || './';
|
||||
const validator = new MarketplaceValidator();
|
||||
|
||||
// Check for verbose flag
|
||||
validator.verbose = args.includes('--verbose');
|
||||
|
||||
validator.validate(marketplacePath).catch(error => {
|
||||
console.error('Validation error:', error.message);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = MarketplaceValidator;
|
||||
Reference in New Issue
Block a user