Initial commit
This commit is contained in:
724
skills/generate.marketplace/SKILL.md
Normal file
724
skills/generate.marketplace/SKILL.md
Normal file
@@ -0,0 +1,724 @@
|
||||
---
|
||||
name: Generate Marketplace
|
||||
description: Generate marketplace catalog files from Betty Framework registries
|
||||
---
|
||||
|
||||
# generate.marketplace
|
||||
|
||||
## Overview
|
||||
|
||||
**generate.marketplace** generates the RiskExec Claude Marketplace catalogs by filtering certified skills, agents, commands, and hooks from the Betty Framework registries. It transforms registry entries into marketplace-ready JSON files optimized for discovery and distribution.
|
||||
|
||||
## Purpose
|
||||
|
||||
Automates the generation of marketplace catalogs to maintain consistency between:
|
||||
- **Skill Registry** (`registry/skills.json`) - All registered skills
|
||||
- **Agent Registry** (`registry/agents.json`) - All registered agents
|
||||
- **Command Registry** (`registry/commands.json`) - All registered commands
|
||||
- **Hook Registry** (`registry/hooks.json`) - All registered hooks
|
||||
- **Skills Marketplace** (`marketplace/skills.json`) - Certified skills for distribution
|
||||
- **Agents Marketplace** (`marketplace/agents.json`) - Certified agents for distribution
|
||||
- **Commands Marketplace** (`marketplace/commands.json`) - Certified commands for distribution
|
||||
- **Hooks Marketplace** (`marketplace/hooks.json`) - Certified hooks for distribution
|
||||
|
||||
This eliminates manual curation of marketplace catalogs and ensures only production-ready, certified components are published.
|
||||
|
||||
## What It Does
|
||||
|
||||
1. **Reads Registries**: Loads `registry/skills.json`, `registry/agents.json`, `registry/commands.json`, and `registry/hooks.json`
|
||||
2. **Filters Active Items**: Processes only entries with `status: active`
|
||||
3. **Filters Certified Items**: Includes only entries with `certified: true` (if field exists)
|
||||
4. **Transforms Format**: Converts registry entries to marketplace format
|
||||
5. **Enriches Metadata**: Adds maintainer, usage examples, documentation URLs, and last_updated timestamps
|
||||
6. **Generates Catalogs**: Outputs `marketplace/skills.json`, `marketplace/agents.json`, `marketplace/commands.json`, and `marketplace/hooks.json`
|
||||
7. **Reports Statistics**: Shows certification counts and totals
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```bash
|
||||
python skills/generate.marketplace/generate_marketplace.py
|
||||
```
|
||||
|
||||
No arguments required - reads from standard registry locations.
|
||||
|
||||
### Via Betty CLI
|
||||
|
||||
```bash
|
||||
/marketplace/generate
|
||||
```
|
||||
|
||||
### Expected Directory Structure
|
||||
|
||||
```
|
||||
betty/
|
||||
├── registry/
|
||||
│ ├── skills.json # Source: All registered skills
|
||||
│ ├── agents.json # Source: All registered agents
|
||||
│ ├── commands.json # Source: All registered commands
|
||||
│ └── hooks.json # Source: All registered hooks
|
||||
└── marketplace/
|
||||
├── skills.json # Output: Certified skills only
|
||||
├── agents.json # Output: Certified agents only
|
||||
├── commands.json # Output: Certified commands only
|
||||
└── hooks.json # Output: Certified hooks only
|
||||
```
|
||||
|
||||
## Filtering Logic
|
||||
|
||||
### Certification Criteria
|
||||
|
||||
A skill, agent, command, or hook is included in the marketplace if:
|
||||
|
||||
1. **Status is Active**: `status: "active"`
|
||||
2. **Certified Flag** (if present): `certified: true`
|
||||
|
||||
If the `certified` field is not present, active items are considered certified by default.
|
||||
|
||||
### Status Values
|
||||
|
||||
| Status | Included in Marketplace | Purpose |
|
||||
|--------|------------------------|---------|
|
||||
| `active` | Yes | Production-ready, certified items |
|
||||
| `draft` | No | Work in progress, not ready for distribution |
|
||||
| `deprecated` | No | Outdated, should not be used |
|
||||
| `experimental` | No | Testing phase, unstable |
|
||||
|
||||
## Output Format
|
||||
|
||||
### Skills Marketplace Structure
|
||||
|
||||
```json
|
||||
{
|
||||
"marketplace_version": "1.0.0",
|
||||
"generated_at": "2025-10-23T17:51:58.579847+00:00",
|
||||
"last_updated": "2025-10-23T17:51:58.579847+00:00",
|
||||
"description": "Betty Framework Certified Skills Marketplace",
|
||||
"total_skills": 20,
|
||||
"certified_count": 16,
|
||||
"draft_count": 4,
|
||||
"catalog": [
|
||||
{
|
||||
"name": "api.validate",
|
||||
"version": "0.1.0",
|
||||
"description": "Validate OpenAPI and AsyncAPI specifications",
|
||||
"status": "certified",
|
||||
"tags": ["api", "validation", "openapi"],
|
||||
"maintainer": "Betty Core Team",
|
||||
"usage_examples": [
|
||||
"Validate OpenAPI spec: /skill/api/validate --spec_path api.yaml"
|
||||
],
|
||||
"documentation_url": "https://betty-framework.dev/docs/skills/api.validate",
|
||||
"dependencies": ["context.schema"],
|
||||
"entrypoints": [...],
|
||||
"inputs": [...],
|
||||
"outputs": [...]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Agents Marketplace Structure
|
||||
|
||||
```json
|
||||
{
|
||||
"marketplace_version": "1.0.0",
|
||||
"generated_at": "2025-10-23T17:03:16.154165+00:00",
|
||||
"last_updated": "2025-10-23T17:03:16.154165+00:00",
|
||||
"description": "Betty Framework Certified Agents Marketplace",
|
||||
"total_agents": 5,
|
||||
"certified_count": 3,
|
||||
"draft_count": 2,
|
||||
"catalog": [
|
||||
{
|
||||
"name": "api.designer",
|
||||
"version": "0.1.0",
|
||||
"description": "Design RESTful APIs following enterprise guidelines",
|
||||
"status": "certified",
|
||||
"reasoning_mode": "iterative",
|
||||
"skills_available": ["api.define", "api.validate"],
|
||||
"capabilities": [
|
||||
"Design RESTful APIs from natural language requirements"
|
||||
],
|
||||
"tags": ["api", "design", "openapi"],
|
||||
"maintainer": "Betty Core Team",
|
||||
"documentation_url": "https://betty-framework.dev/docs/agents/api.designer",
|
||||
"dependencies": ["context.schema"]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Commands Marketplace Structure
|
||||
|
||||
```json
|
||||
{
|
||||
"marketplace_version": "1.0.0",
|
||||
"generated_at": "2025-10-23T17:51:58.579847+00:00",
|
||||
"last_updated": "2025-10-23T17:51:58.579847+00:00",
|
||||
"description": "Betty Framework Certified Commands Marketplace",
|
||||
"total_commands": 4,
|
||||
"certified_count": 1,
|
||||
"draft_count": 3,
|
||||
"catalog": [
|
||||
{
|
||||
"name": "/test-workflow-command",
|
||||
"version": "1.0.0",
|
||||
"description": "Test complete workflow",
|
||||
"status": "certified",
|
||||
"tags": ["test", "workflow"],
|
||||
"execution": {
|
||||
"type": "skill",
|
||||
"target": "api.validate"
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "input",
|
||||
"type": "string",
|
||||
"required": true,
|
||||
"description": "Input parameter"
|
||||
}
|
||||
],
|
||||
"maintainer": "Betty Core Team"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Hooks Marketplace Structure
|
||||
|
||||
```json
|
||||
{
|
||||
"marketplace_version": "1.0.0",
|
||||
"generated_at": "2025-10-23T17:51:58.579847+00:00",
|
||||
"last_updated": "2025-10-23T17:51:58.579847+00:00",
|
||||
"description": "Betty Framework Certified Hooks Marketplace",
|
||||
"total_hooks": 4,
|
||||
"certified_count": 1,
|
||||
"draft_count": 3,
|
||||
"catalog": [
|
||||
{
|
||||
"name": "test-workflow-hook",
|
||||
"version": "1.0.0",
|
||||
"description": "Test complete workflow",
|
||||
"status": "certified",
|
||||
"tags": ["test", "workflow", "openapi"],
|
||||
"event": "on_file_edit",
|
||||
"command": "python validate.py {file_path}",
|
||||
"blocking": true,
|
||||
"when": {
|
||||
"pattern": "*.openapi.yaml"
|
||||
},
|
||||
"timeout": 30000,
|
||||
"on_failure": "show_errors",
|
||||
"maintainer": "Betty Core Team"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Marketplace Transformations
|
||||
|
||||
### From Registry to Marketplace
|
||||
|
||||
The skill transforms registry entries to marketplace format:
|
||||
|
||||
#### Skills and Agents
|
||||
|
||||
| Registry Field | Marketplace Field | Transformation |
|
||||
|----------------|-------------------|----------------|
|
||||
| `status: "active"` | `status: "certified"` | Renamed for marketplace context |
|
||||
| `name` | `name` | Preserved |
|
||||
| `version` | `version` | Preserved |
|
||||
| `description` | `description` | Preserved |
|
||||
| `tags` | `tags` | Preserved (default: `[]`) |
|
||||
| `dependencies` | `dependencies` | Preserved (default: `[]`) |
|
||||
| `entrypoints` | `entrypoints` | Preserved (skills only) |
|
||||
| `inputs` | `inputs` | Preserved (skills only) |
|
||||
| `outputs` | `outputs` | Preserved (skills only) |
|
||||
| `skills_available` | `skills_available` | Preserved (agents only) |
|
||||
| `capabilities` | `capabilities` | Preserved (agents only) |
|
||||
| `reasoning_mode` | `reasoning_mode` | Preserved (agents only) |
|
||||
| N/A | `maintainer` | Added (default: "Betty Core Team") |
|
||||
| N/A | `usage_examples` | Generated from entrypoints or provided |
|
||||
| N/A | `documentation_url` | Generated: `https://betty-framework.dev/docs/{type}/{name}` |
|
||||
| N/A | `last_updated` | Added: ISO timestamp |
|
||||
|
||||
#### Commands
|
||||
|
||||
| Registry Field | Marketplace Field | Transformation |
|
||||
|----------------|-------------------|----------------|
|
||||
| `status: "active"` | `status: "certified"` | Renamed for marketplace context |
|
||||
| `name` | `name` | Preserved |
|
||||
| `version` | `version` | Preserved |
|
||||
| `description` | `description` | Preserved |
|
||||
| `tags` | `tags` | Preserved (default: `[]`) |
|
||||
| `execution` | `execution` | Preserved |
|
||||
| `parameters` | `parameters` | Preserved (default: `[]`) |
|
||||
| N/A | `maintainer` | Added (default: "Betty Core Team") |
|
||||
| N/A | `last_updated` | Added: ISO timestamp |
|
||||
|
||||
#### Hooks
|
||||
|
||||
| Registry Field | Marketplace Field | Transformation |
|
||||
|----------------|-------------------|----------------|
|
||||
| `status: "active"` | `status: "certified"` | Renamed for marketplace context |
|
||||
| `name` | `name` | Preserved |
|
||||
| `version` | `version` | Preserved |
|
||||
| `description` | `description` | Preserved |
|
||||
| `tags` | `tags` | Preserved (default: `[]`) |
|
||||
| `event` | `event` | Preserved |
|
||||
| `command` | `command` | Preserved |
|
||||
| `blocking` | `blocking` | Preserved (default: `false`) |
|
||||
| `when` | `when` | Preserved (default: `{}`) |
|
||||
| `timeout` | `timeout` | Preserved |
|
||||
| `on_failure` | `on_failure` | Preserved |
|
||||
| N/A | `maintainer` | Added (default: "Betty Core Team") |
|
||||
| N/A | `last_updated` | Added: ISO timestamp |
|
||||
|
||||
### Metadata Enrichment
|
||||
|
||||
The skill adds marketplace-specific metadata:
|
||||
|
||||
1. **Maintainer**: Defaults to "Betty Core Team" if not specified
|
||||
2. **Usage Examples**: Auto-generated from entrypoint commands if missing (skills only)
|
||||
3. **Documentation URL**: Generated following the pattern `https://betty-framework.dev/docs/{skills|agents}/{name}` (skills and agents only)
|
||||
4. **Last Updated**: ISO timestamp added to all marketplace files
|
||||
5. **Statistics**: Adds total counts, certified counts, and draft counts
|
||||
|
||||
## Behavior
|
||||
|
||||
### 1. Registry Loading
|
||||
|
||||
Reads JSON files from:
|
||||
- `registry/skills.json`
|
||||
- `registry/agents.json`
|
||||
- `registry/commands.json`
|
||||
- `registry/hooks.json`
|
||||
|
||||
If a registry file is missing, the skill fails with an error.
|
||||
|
||||
### 2. Filtering
|
||||
|
||||
For each skill/agent/command/hook in the registry:
|
||||
- Checks `status` field - must be `"active"`
|
||||
- Checks `certified` field (if present) - must be `true`
|
||||
- Skips items that don't meet criteria
|
||||
- Logs which items are included/excluded
|
||||
|
||||
### 3. Transformation
|
||||
|
||||
Converts each certified entry:
|
||||
- Copies core fields (name, version, description, tags)
|
||||
- Transforms `status: "active"` → `status: "certified"`
|
||||
- Adds marketplace metadata (maintainer, last_updated timestamp)
|
||||
- For skills: Adds docs URL and generates usage examples if not provided
|
||||
- For agents: Adds docs URL
|
||||
- Preserves all technical details (entrypoints, inputs, outputs, execution, parameters, event, command, etc.)
|
||||
|
||||
### 4. Statistics Calculation
|
||||
|
||||
Tracks:
|
||||
- **Total items**: All items in registry
|
||||
- **Certified count**: Items included in marketplace
|
||||
- **Draft count**: Items excluded (total - certified)
|
||||
|
||||
### 5. File Writing
|
||||
|
||||
Writes marketplace catalogs:
|
||||
- Creates `marketplace/` directory if needed
|
||||
- Formats JSON with 2-space indentation
|
||||
- Preserves Unicode characters (no ASCII escaping)
|
||||
- Adds generation timestamp
|
||||
|
||||
## Outputs
|
||||
|
||||
### Success Response
|
||||
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"status": "success",
|
||||
"skills_output": "/home/user/betty/marketplace/skills.json",
|
||||
"agents_output": "/home/user/betty/marketplace/agents.json",
|
||||
"commands_output": "/home/user/betty/marketplace/commands.json",
|
||||
"hooks_output": "/home/user/betty/marketplace/hooks.json",
|
||||
"skills_certified": 16,
|
||||
"skills_total": 20,
|
||||
"agents_certified": 3,
|
||||
"agents_total": 5,
|
||||
"commands_certified": 1,
|
||||
"commands_total": 4,
|
||||
"hooks_certified": 1,
|
||||
"hooks_total": 4
|
||||
}
|
||||
```
|
||||
|
||||
### Failure Response
|
||||
|
||||
```json
|
||||
{
|
||||
"ok": false,
|
||||
"status": "failed",
|
||||
"error": "Registry file not found: /home/user/betty/registry/skills.json"
|
||||
}
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Example 1: Basic Marketplace Generation
|
||||
|
||||
**Scenario**: Generate marketplace catalogs after adding new certified skills
|
||||
|
||||
```bash
|
||||
# Register new skills
|
||||
/skill/define skills/data.transform/skill.yaml
|
||||
/skill/define skills/api.monitor/skill.yaml
|
||||
|
||||
# Update registry
|
||||
/registry/update
|
||||
|
||||
# Generate marketplace
|
||||
/marketplace/generate
|
||||
```
|
||||
|
||||
**Output**:
|
||||
```
|
||||
INFO: Starting marketplace catalog generation from registries...
|
||||
INFO: Loading registry files...
|
||||
INFO: Generating marketplace catalogs...
|
||||
INFO: Added certified skill: api.validate
|
||||
INFO: Added certified skill: api.define
|
||||
INFO: Skipped non-certified skill: test.hello (status: draft)
|
||||
INFO: Added certified agent: api.designer
|
||||
INFO: Added certified command: /test-workflow-command
|
||||
INFO: Skipped non-certified command: /test-command (status: draft)
|
||||
INFO: Added certified hook: test-workflow-hook
|
||||
INFO: Skipped non-certified hook: test-validation-hook (status: draft)
|
||||
INFO: Writing marketplace files...
|
||||
INFO: ✅ Written marketplace file to /home/user/betty/marketplace/skills.json
|
||||
INFO: ✅ Written marketplace file to /home/user/betty/marketplace/agents.json
|
||||
INFO: ✅ Written marketplace file to /home/user/betty/marketplace/commands.json
|
||||
INFO: ✅ Written marketplace file to /home/user/betty/marketplace/hooks.json
|
||||
INFO: ✅ Generated marketplace catalogs:
|
||||
INFO: Skills: 16/20 certified
|
||||
INFO: Agents: 3/5 certified
|
||||
INFO: Commands: 1/4 certified
|
||||
INFO: Hooks: 1/4 certified
|
||||
```
|
||||
|
||||
### Example 2: After Promoting Skills to Active
|
||||
|
||||
**Scenario**: Skills were marked as active and should now appear in marketplace
|
||||
|
||||
```bash
|
||||
# Edit registry to mark skills as active
|
||||
# (Normally done via skill.define)
|
||||
|
||||
# Regenerate marketplace
|
||||
/marketplace/generate
|
||||
```
|
||||
|
||||
**Before** (registry):
|
||||
```json
|
||||
{
|
||||
"name": "my.skill",
|
||||
"status": "draft"
|
||||
}
|
||||
```
|
||||
|
||||
**After** (registry updated):
|
||||
```json
|
||||
{
|
||||
"name": "my.skill",
|
||||
"status": "active"
|
||||
}
|
||||
```
|
||||
|
||||
**Marketplace** (now includes):
|
||||
```json
|
||||
{
|
||||
"name": "my.skill",
|
||||
"status": "certified"
|
||||
}
|
||||
```
|
||||
|
||||
### Example 3: Publishing to GitHub Pages
|
||||
|
||||
**Scenario**: Deploy marketplace catalogs to public API endpoint
|
||||
|
||||
```bash
|
||||
# Generate marketplace
|
||||
/marketplace/generate
|
||||
|
||||
# Copy to GitHub Pages directory
|
||||
cp marketplace/*.json docs/api/v1/
|
||||
|
||||
# Commit and push
|
||||
git add marketplace/ docs/api/v1/
|
||||
git commit -m "Update marketplace catalog"
|
||||
git push
|
||||
```
|
||||
|
||||
Now accessible at:
|
||||
- `https://riskexec.github.io/betty/api/v1/skills.json`
|
||||
- `https://riskexec.github.io/betty/api/v1/agents.json`
|
||||
- `https://riskexec.github.io/betty/api/v1/commands.json`
|
||||
- `https://riskexec.github.io/betty/api/v1/hooks.json`
|
||||
|
||||
### Example 4: CI/CD Integration
|
||||
|
||||
**Scenario**: Auto-generate marketplace on every registry change
|
||||
|
||||
```yaml
|
||||
# .github/workflows/marketplace.yml
|
||||
name: Update Marketplace
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'registry/*.json'
|
||||
|
||||
jobs:
|
||||
generate:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Generate Marketplace
|
||||
run: python skills/generate.marketplace/generate_marketplace.py
|
||||
- name: Commit Changes
|
||||
run: |
|
||||
git config user.name "Betty Bot"
|
||||
git config user.email "bot@riskexec.com"
|
||||
git add marketplace/
|
||||
git commit -m "chore: update marketplace catalog"
|
||||
git push
|
||||
```
|
||||
|
||||
## Integration
|
||||
|
||||
### With skill.define Workflow
|
||||
|
||||
After registering skills, regenerate marketplace:
|
||||
|
||||
```bash
|
||||
/skill/define skills/new.skill/skill.yaml
|
||||
/registry/update
|
||||
/marketplace/generate
|
||||
```
|
||||
|
||||
### With Workflows
|
||||
|
||||
Include marketplace generation as a workflow step:
|
||||
|
||||
```yaml
|
||||
# workflows/skill_lifecycle.yaml
|
||||
steps:
|
||||
- skill: skill.create
|
||||
args: ["new.skill", "Description"]
|
||||
|
||||
- skill: skill.define
|
||||
args: ["skills/new.skill/skill.yaml"]
|
||||
|
||||
- skill: registry.update
|
||||
args: ["skills/new.skill/skill.yaml"]
|
||||
|
||||
- skill: generate.marketplace
|
||||
args: []
|
||||
```
|
||||
|
||||
### With Hooks
|
||||
|
||||
Auto-regenerate marketplace when registries change:
|
||||
|
||||
```yaml
|
||||
# .claude/hooks.yaml
|
||||
- event: on_file_save
|
||||
pattern: "registry/*.json"
|
||||
command: python skills/generate.marketplace/generate_marketplace.py
|
||||
blocking: false
|
||||
description: Auto-regenerate marketplace when registry changes
|
||||
```
|
||||
|
||||
## What Gets Included
|
||||
|
||||
### Included in Marketplace
|
||||
|
||||
- Skills/agents/commands/hooks with `status: "active"`
|
||||
- Skills/agents/commands/hooks with `certified: true` (if field exists)
|
||||
- All technical metadata (entrypoints, inputs, outputs, execution, parameters, event, command, etc.)
|
||||
- All semantic metadata (tags, dependencies)
|
||||
- Last updated timestamp for all entries
|
||||
|
||||
### Not Included
|
||||
|
||||
- Skills/agents/commands/hooks with `status: "draft"`
|
||||
- Skills/agents/commands/hooks with `status: "deprecated"`
|
||||
- Skills/agents/commands/hooks with `certified: false`
|
||||
- Internal-only items
|
||||
- Test/experimental items (unless marked active)
|
||||
|
||||
## Common Errors
|
||||
|
||||
| Error | Cause | Solution |
|
||||
|-------|-------|----------|
|
||||
| "Registry file not found" | Missing registry file | Ensure `registry/skills.json` and `registry/agents.json` exist |
|
||||
| "Failed to parse JSON" | Invalid JSON syntax | Fix JSON syntax in registry files |
|
||||
| "Permission denied" | Cannot write marketplace files | Check write permissions on `marketplace/` directory |
|
||||
| Empty marketplace | No active skills | Mark skills as `status: "active"` in registry |
|
||||
|
||||
## Files Read
|
||||
|
||||
- `registry/skills.json` - Skill registry (source)
|
||||
- `registry/agents.json` - Agent registry (source)
|
||||
- `registry/commands.json` - Command registry (source)
|
||||
- `registry/hooks.json` - Hook registry (source)
|
||||
|
||||
## Files Modified
|
||||
|
||||
- `marketplace/skills.json` - Skills marketplace catalog (output)
|
||||
- `marketplace/agents.json` - Agents marketplace catalog (output)
|
||||
- `marketplace/commands.json` - Commands marketplace catalog (output)
|
||||
- `marketplace/hooks.json` - Hooks marketplace catalog (output)
|
||||
|
||||
## Exit Codes
|
||||
|
||||
- **0**: Success (marketplace catalogs generated successfully)
|
||||
- **1**: Failure (error during generation)
|
||||
|
||||
## Logging
|
||||
|
||||
Logs generation progress:
|
||||
|
||||
```
|
||||
INFO: Starting marketplace catalog generation from registries...
|
||||
INFO: Loading registry files...
|
||||
INFO: Generating marketplace catalogs...
|
||||
INFO: Added certified skill: api.validate
|
||||
INFO: Added certified skill: hook.define
|
||||
DEBUG: Skipped non-certified skill: test.hello (status: draft)
|
||||
INFO: Added certified agent: api.designer
|
||||
INFO: Added certified command: /test-workflow-command
|
||||
DEBUG: Skipped non-certified command: /test-command (status: draft)
|
||||
INFO: Added certified hook: test-workflow-hook
|
||||
DEBUG: Skipped non-certified hook: test-validation-hook (status: draft)
|
||||
INFO: Writing marketplace files...
|
||||
INFO: ✅ Written marketplace file to marketplace/skills.json
|
||||
INFO: ✅ Written marketplace file to marketplace/agents.json
|
||||
INFO: ✅ Written marketplace file to marketplace/commands.json
|
||||
INFO: ✅ Written marketplace file to marketplace/hooks.json
|
||||
INFO: ✅ Generated marketplace catalogs:
|
||||
INFO: Skills: 16/20 certified
|
||||
INFO: Agents: 3/5 certified
|
||||
INFO: Commands: 1/4 certified
|
||||
INFO: Hooks: 1/4 certified
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Run After Registry Updates**: Regenerate marketplace after adding/updating skills
|
||||
2. **Automate with CI/CD**: Set up automated marketplace generation in pipelines
|
||||
3. **Review Before Publishing**: Check generated catalogs before deploying
|
||||
4. **Version Control**: Commit marketplace files with registry changes
|
||||
5. **Keep Registries Clean**: Remove deprecated skills to keep marketplace focused
|
||||
6. **Document Thoroughly**: Ensure skills have good descriptions and examples
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Marketplace Files Not Updating
|
||||
|
||||
**Problem**: Changes to registry don't appear in marketplace
|
||||
|
||||
**Solutions**:
|
||||
- Ensure skill status is `"active"` in registry
|
||||
- Check that `certified` field is `true` (if present)
|
||||
- Run `/registry/update` before `/marketplace/generate`
|
||||
- Verify registry JSON syntax is valid
|
||||
|
||||
### Skills Missing from Marketplace
|
||||
|
||||
**Problem**: Active skills not appearing in marketplace
|
||||
|
||||
**Solutions**:
|
||||
- Check skill status in `registry/skills.json`
|
||||
- Verify no `certified: false` field
|
||||
- Ensure skill.yaml has been validated with `/skill/define`
|
||||
- Check logs for filtering messages
|
||||
|
||||
### Empty Marketplace Catalogs
|
||||
|
||||
**Problem**: Marketplace has 0 certified items
|
||||
|
||||
**Solutions**:
|
||||
- Mark skills as `status: "active"` in registry
|
||||
- Remove `certified: false` from skill entries
|
||||
- Ensure registry files are not empty
|
||||
- Run `/skill/define` to register skills first
|
||||
|
||||
## Version Diff (Optional)
|
||||
|
||||
To add version diff vs. last release:
|
||||
|
||||
```python
|
||||
# Future enhancement
|
||||
def get_version_diff(old_marketplace, new_marketplace):
|
||||
"""Compare two marketplace versions and return diff."""
|
||||
added = [s for s in new if s not in old]
|
||||
removed = [s for s in old if s not in new]
|
||||
updated = [s for s in new if s in old and version_changed(s)]
|
||||
return {"added": added, "removed": removed, "updated": updated}
|
||||
```
|
||||
|
||||
## Upload to API (Optional)
|
||||
|
||||
To upload generated catalogs to an API:
|
||||
|
||||
```python
|
||||
# Future enhancement
|
||||
import requests
|
||||
|
||||
def upload_to_api(marketplace_data, api_endpoint, api_key):
|
||||
"""Upload marketplace catalog to internal API."""
|
||||
response = requests.post(
|
||||
api_endpoint,
|
||||
json=marketplace_data,
|
||||
headers={"Authorization": f"Bearer {api_key}"}
|
||||
)
|
||||
return response.status_code == 200
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
### Skill Categories
|
||||
|
||||
**Infrastructure** - generate.marketplace maintains the marketplace layer by transforming registry state into certified catalogs.
|
||||
|
||||
### Design Principles
|
||||
|
||||
- **Single Source of Truth**: Registry files are the source
|
||||
- **Idempotent**: Can be run multiple times safely
|
||||
- **Certification Filter**: Only production-ready items included
|
||||
- **Metadata Enrichment**: Adds marketplace-specific fields
|
||||
- **Clear Statistics**: Reports certification rates
|
||||
|
||||
## See Also
|
||||
|
||||
- **plugin.sync** - Generate plugin.yaml from registries ([SKILL.md](../plugin.sync/SKILL.md))
|
||||
- **registry.update** - Update skill registry ([SKILL.md](../registry.update/SKILL.md))
|
||||
- **skill.define** - Validate and register skills ([SKILL.md](../skill.define/SKILL.md))
|
||||
- **Betty Architecture** - Framework overview ([betty-architecture.md](../../docs/betty-architecture.md))
|
||||
|
||||
## Dependencies
|
||||
|
||||
- **registry.update**: Registry management
|
||||
- **betty.config**: Configuration constants and paths
|
||||
- **betty.logging_utils**: Logging infrastructure
|
||||
|
||||
## Status
|
||||
|
||||
**Active** - Production-ready infrastructure skill
|
||||
|
||||
## Version History
|
||||
|
||||
- **0.2.0** (Oct 2025) - Added support for commands and hooks, added last_updated timestamps
|
||||
- **0.1.0** (Oct 2025) - Initial implementation with filtering and marketplace generation for skills and agents
|
||||
1
skills/generate.marketplace/__init__.py
Normal file
1
skills/generate.marketplace/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
# Auto-generated package initializer for skills.
|
||||
522
skills/generate.marketplace/generate_marketplace.py
Executable file
522
skills/generate.marketplace/generate_marketplace.py
Executable file
@@ -0,0 +1,522 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
generate_marketplace.py - Implementation of the generate.marketplace Skill
|
||||
Generates marketplace JSON files from registry entries:
|
||||
- marketplace/skills.json
|
||||
- marketplace/agents.json
|
||||
- marketplace/commands.json
|
||||
- marketplace/hooks.json
|
||||
|
||||
Filters by status: active and certified: true (if present).
|
||||
Adds last_updated ISO timestamp to all marketplace files.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
from typing import Dict, Any, List, Optional
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
from betty.config import BASE_DIR
|
||||
from betty.logging_utils import setup_logger
|
||||
|
||||
logger = setup_logger(__name__)
|
||||
|
||||
|
||||
def load_registry_file(registry_path: str) -> Dict[str, Any]:
|
||||
"""
|
||||
Load a JSON registry file.
|
||||
|
||||
Args:
|
||||
registry_path: Path to the registry JSON file
|
||||
|
||||
Returns:
|
||||
Parsed registry data
|
||||
|
||||
Raises:
|
||||
FileNotFoundError: If registry file doesn't exist
|
||||
json.JSONDecodeError: If JSON is invalid
|
||||
"""
|
||||
try:
|
||||
with open(registry_path) as f:
|
||||
return json.load(f)
|
||||
except FileNotFoundError:
|
||||
logger.error(f"Registry file not found: {registry_path}")
|
||||
raise
|
||||
except json.JSONDecodeError as e:
|
||||
logger.error(f"Failed to parse JSON from {registry_path}: {e}")
|
||||
raise
|
||||
|
||||
|
||||
def is_certified(item: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
Check if an item is certified for marketplace inclusion.
|
||||
|
||||
Args:
|
||||
item: Skill or agent entry
|
||||
|
||||
Returns:
|
||||
True if item should be included in marketplace
|
||||
"""
|
||||
# Filter by status: active
|
||||
if item.get("status") != "active":
|
||||
return False
|
||||
|
||||
# If certified field exists, check it
|
||||
if "certified" in item:
|
||||
return item.get("certified") is True
|
||||
|
||||
# If no certified field, consider active items as certified
|
||||
return True
|
||||
|
||||
|
||||
def convert_skill_to_marketplace(skill: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
Convert a registry skill entry to marketplace format.
|
||||
|
||||
Args:
|
||||
skill: Skill entry from registry
|
||||
|
||||
Returns:
|
||||
Skill entry in marketplace format
|
||||
"""
|
||||
skill_name = skill.get("name")
|
||||
marketplace_skill = {
|
||||
"name": skill_name,
|
||||
"version": skill.get("version"),
|
||||
"description": skill.get("description"),
|
||||
"status": "certified", # Transform active -> certified for marketplace
|
||||
"tags": skill.get("tags", []),
|
||||
"manifest_path": f"skills/{skill_name}/skill.yaml",
|
||||
"maintainer": skill.get("maintainer", "Betty Core Team"),
|
||||
"usage_examples": skill.get("usage_examples", []),
|
||||
"documentation_url": f"https://betty-framework.dev/docs/skills/{skill_name}",
|
||||
"dependencies": skill.get("dependencies", []),
|
||||
"entrypoints": skill.get("entrypoints", []),
|
||||
"inputs": skill.get("inputs", []),
|
||||
"outputs": skill.get("outputs", [])
|
||||
}
|
||||
|
||||
# Generate usage examples if not present
|
||||
if not marketplace_skill["usage_examples"] and marketplace_skill["entrypoints"]:
|
||||
examples = []
|
||||
for entrypoint in marketplace_skill["entrypoints"]:
|
||||
command = entrypoint.get("command", "")
|
||||
desc = entrypoint.get("description", skill.get("description", ""))
|
||||
if command:
|
||||
# Create a simple example from the command
|
||||
example = f"Run {skill.get('name')}: {command}"
|
||||
examples.append(example.strip())
|
||||
marketplace_skill["usage_examples"] = examples[:2] # Limit to 2 examples
|
||||
|
||||
return marketplace_skill
|
||||
|
||||
|
||||
def convert_agent_to_marketplace(agent: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
Convert a registry agent entry to marketplace format.
|
||||
|
||||
Args:
|
||||
agent: Agent entry from registry
|
||||
|
||||
Returns:
|
||||
Agent entry in marketplace format
|
||||
"""
|
||||
agent_name = agent.get("name")
|
||||
marketplace_agent = {
|
||||
"name": agent_name,
|
||||
"version": agent.get("version"),
|
||||
"description": agent.get("description"),
|
||||
"status": "certified", # Transform active -> certified for marketplace
|
||||
"reasoning_mode": agent.get("reasoning_mode", "oneshot"),
|
||||
"skills_available": agent.get("skills_available", []),
|
||||
"capabilities": agent.get("capabilities", []),
|
||||
"tags": agent.get("tags", []),
|
||||
"manifest_path": f"agents/{agent_name}/agent.yaml",
|
||||
"maintainer": agent.get("maintainer", "Betty Core Team"),
|
||||
"documentation_url": f"https://betty-framework.dev/docs/agents/{agent_name}",
|
||||
"dependencies": agent.get("dependencies", [])
|
||||
}
|
||||
|
||||
return marketplace_agent
|
||||
|
||||
|
||||
def convert_command_to_marketplace(command: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
Convert a registry command entry to marketplace format.
|
||||
|
||||
Args:
|
||||
command: Command entry from registry
|
||||
|
||||
Returns:
|
||||
Command entry in marketplace format
|
||||
"""
|
||||
marketplace_command = {
|
||||
"name": command.get("name"),
|
||||
"version": command.get("version"),
|
||||
"description": command.get("description"),
|
||||
"status": "certified", # Transform active -> certified for marketplace
|
||||
"tags": command.get("tags", []),
|
||||
"execution": command.get("execution", {}),
|
||||
"parameters": command.get("parameters", []),
|
||||
"maintainer": command.get("maintainer", "Betty Core Team")
|
||||
}
|
||||
|
||||
return marketplace_command
|
||||
|
||||
|
||||
def convert_hook_to_marketplace(hook: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
Convert a registry hook entry to marketplace format.
|
||||
|
||||
Args:
|
||||
hook: Hook entry from registry
|
||||
|
||||
Returns:
|
||||
Hook entry in marketplace format
|
||||
"""
|
||||
marketplace_hook = {
|
||||
"name": hook.get("name"),
|
||||
"version": hook.get("version"),
|
||||
"description": hook.get("description"),
|
||||
"status": "certified", # Transform active -> certified for marketplace
|
||||
"tags": hook.get("tags", []),
|
||||
"event": hook.get("event"),
|
||||
"command": hook.get("command"),
|
||||
"blocking": hook.get("blocking", False),
|
||||
"when": hook.get("when", {}),
|
||||
"timeout": hook.get("timeout"),
|
||||
"on_failure": hook.get("on_failure"),
|
||||
"maintainer": hook.get("maintainer", "Betty Core Team")
|
||||
}
|
||||
|
||||
return marketplace_hook
|
||||
|
||||
|
||||
def generate_skills_marketplace(registry_data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
Generate marketplace skills catalog from registry.
|
||||
|
||||
Args:
|
||||
registry_data: Parsed skills.json from registry
|
||||
|
||||
Returns:
|
||||
Marketplace-formatted skills catalog
|
||||
"""
|
||||
skills = registry_data.get("skills", [])
|
||||
|
||||
# Filter and convert active/certified skills
|
||||
certified_skills = []
|
||||
for skill in skills:
|
||||
if is_certified(skill):
|
||||
marketplace_skill = convert_skill_to_marketplace(skill)
|
||||
certified_skills.append(marketplace_skill)
|
||||
logger.info(f"Added certified skill: {skill.get('name')}")
|
||||
else:
|
||||
logger.debug(f"Skipped non-certified skill: {skill.get('name')} (status: {skill.get('status')})")
|
||||
|
||||
# Build marketplace catalog
|
||||
marketplace = {
|
||||
"marketplace_version": "1.0.0",
|
||||
"generated_at": datetime.now(timezone.utc).isoformat(),
|
||||
"last_updated": datetime.now(timezone.utc).isoformat(),
|
||||
"description": "Betty Framework Certified Skills Marketplace",
|
||||
"total_skills": len(skills),
|
||||
"certified_count": len(certified_skills),
|
||||
"draft_count": len(skills) - len(certified_skills),
|
||||
"catalog": certified_skills
|
||||
}
|
||||
|
||||
return marketplace
|
||||
|
||||
|
||||
def generate_agents_marketplace(registry_data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
Generate marketplace agents catalog from registry.
|
||||
|
||||
Args:
|
||||
registry_data: Parsed agents.json from registry
|
||||
|
||||
Returns:
|
||||
Marketplace-formatted agents catalog
|
||||
"""
|
||||
agents = registry_data.get("agents", [])
|
||||
|
||||
# Filter and convert active/certified agents
|
||||
certified_agents = []
|
||||
for agent in agents:
|
||||
if is_certified(agent):
|
||||
marketplace_agent = convert_agent_to_marketplace(agent)
|
||||
certified_agents.append(marketplace_agent)
|
||||
logger.info(f"Added certified agent: {agent.get('name')}")
|
||||
else:
|
||||
logger.debug(f"Skipped non-certified agent: {agent.get('name')} (status: {agent.get('status')})")
|
||||
|
||||
# Build marketplace catalog
|
||||
marketplace = {
|
||||
"marketplace_version": "1.0.0",
|
||||
"generated_at": datetime.now(timezone.utc).isoformat(),
|
||||
"last_updated": datetime.now(timezone.utc).isoformat(),
|
||||
"description": "Betty Framework Certified Agents Marketplace",
|
||||
"total_agents": len(agents),
|
||||
"certified_count": len(certified_agents),
|
||||
"draft_count": len(agents) - len(certified_agents),
|
||||
"catalog": certified_agents
|
||||
}
|
||||
|
||||
return marketplace
|
||||
|
||||
|
||||
def generate_commands_marketplace(registry_data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
Generate marketplace commands catalog from registry.
|
||||
|
||||
Args:
|
||||
registry_data: Parsed commands.json from registry
|
||||
|
||||
Returns:
|
||||
Marketplace-formatted commands catalog
|
||||
"""
|
||||
commands = registry_data.get("commands", [])
|
||||
|
||||
# Filter and convert active/certified commands
|
||||
certified_commands = []
|
||||
for command in commands:
|
||||
if is_certified(command):
|
||||
marketplace_command = convert_command_to_marketplace(command)
|
||||
certified_commands.append(marketplace_command)
|
||||
logger.info(f"Added certified command: {command.get('name')}")
|
||||
else:
|
||||
logger.debug(f"Skipped non-certified command: {command.get('name')} (status: {command.get('status')})")
|
||||
|
||||
# Build marketplace catalog
|
||||
marketplace = {
|
||||
"marketplace_version": "1.0.0",
|
||||
"generated_at": datetime.now(timezone.utc).isoformat(),
|
||||
"last_updated": datetime.now(timezone.utc).isoformat(),
|
||||
"description": "Betty Framework Certified Commands Marketplace",
|
||||
"total_commands": len(commands),
|
||||
"certified_count": len(certified_commands),
|
||||
"draft_count": len(commands) - len(certified_commands),
|
||||
"catalog": certified_commands
|
||||
}
|
||||
|
||||
return marketplace
|
||||
|
||||
|
||||
def generate_hooks_marketplace(registry_data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
Generate marketplace hooks catalog from registry.
|
||||
|
||||
Args:
|
||||
registry_data: Parsed hooks.json from registry
|
||||
|
||||
Returns:
|
||||
Marketplace-formatted hooks catalog
|
||||
"""
|
||||
hooks = registry_data.get("hooks", [])
|
||||
|
||||
# Filter and convert active/certified hooks
|
||||
certified_hooks = []
|
||||
for hook in hooks:
|
||||
if is_certified(hook):
|
||||
marketplace_hook = convert_hook_to_marketplace(hook)
|
||||
certified_hooks.append(marketplace_hook)
|
||||
logger.info(f"Added certified hook: {hook.get('name')}")
|
||||
else:
|
||||
logger.debug(f"Skipped non-certified hook: {hook.get('name')} (status: {hook.get('status')})")
|
||||
|
||||
# Build marketplace catalog
|
||||
marketplace = {
|
||||
"marketplace_version": "1.0.0",
|
||||
"generated_at": datetime.now(timezone.utc).isoformat(),
|
||||
"last_updated": datetime.now(timezone.utc).isoformat(),
|
||||
"description": "Betty Framework Certified Hooks Marketplace",
|
||||
"total_hooks": len(hooks),
|
||||
"certified_count": len(certified_hooks),
|
||||
"draft_count": len(hooks) - len(certified_hooks),
|
||||
"catalog": certified_hooks
|
||||
}
|
||||
|
||||
return marketplace
|
||||
|
||||
|
||||
def write_marketplace_file(data: Dict[str, Any], output_path: str):
|
||||
"""
|
||||
Write marketplace JSON file with proper formatting.
|
||||
|
||||
Args:
|
||||
data: Marketplace data dictionary
|
||||
output_path: Path where to write the file
|
||||
"""
|
||||
os.makedirs(os.path.dirname(output_path), exist_ok=True)
|
||||
|
||||
with open(output_path, 'w') as f:
|
||||
json.dump(data, f, indent=2, ensure_ascii=False)
|
||||
|
||||
logger.info(f"✅ Written marketplace file to {output_path}")
|
||||
|
||||
|
||||
def generate_claude_code_marketplace() -> Dict[str, Any]:
|
||||
"""
|
||||
Generate Claude Code marketplace.json file.
|
||||
|
||||
This file lists Betty Framework as an installable plugin in Claude Code's
|
||||
marketplace format, as specified in Claude Code's plugin marketplace documentation.
|
||||
|
||||
Returns:
|
||||
Claude Code marketplace JSON structure
|
||||
"""
|
||||
# Load plugin.yaml to get current metadata
|
||||
plugin_yaml_path = os.path.join(BASE_DIR, "plugin.yaml")
|
||||
|
||||
try:
|
||||
import yaml
|
||||
with open(plugin_yaml_path, 'r') as f:
|
||||
plugin_data = yaml.safe_load(f)
|
||||
except Exception as e:
|
||||
logger.warning(f"Could not load plugin.yaml: {e}. Using defaults.")
|
||||
plugin_data = {}
|
||||
|
||||
# Build Claude Code marketplace structure
|
||||
marketplace = {
|
||||
"name": "betty-marketplace",
|
||||
"version": plugin_data.get("version", "1.0.0"),
|
||||
"description": "Betty Framework Plugin Marketplace - Enterprise-grade AI-assisted engineering framework",
|
||||
"owner": {
|
||||
"name": plugin_data.get("author", {}).get("name", "RiskExec"),
|
||||
"email": plugin_data.get("author", {}).get("email", "platform@riskexec.com"),
|
||||
"url": plugin_data.get("author", {}).get("url", "https://github.com/epieczko/betty")
|
||||
},
|
||||
"metadata": {
|
||||
"homepage": plugin_data.get("metadata", {}).get("homepage", "https://github.com/epieczko/betty"),
|
||||
"repository": plugin_data.get("metadata", {}).get("repository", "https://github.com/epieczko/betty"),
|
||||
"documentation": plugin_data.get("metadata", {}).get("documentation", "https://github.com/epieczko/betty/tree/main/docs"),
|
||||
"generated_at": datetime.now(timezone.utc).isoformat(),
|
||||
"generated_by": "generate.marketplace skill"
|
||||
},
|
||||
"plugins": [
|
||||
{
|
||||
"name": plugin_data.get("name", "betty-framework"),
|
||||
"source": ".",
|
||||
"version": plugin_data.get("version", "1.0.0"),
|
||||
"description": plugin_data.get("description", "Betty Framework for structured AI-assisted engineering"),
|
||||
"author": {
|
||||
"name": plugin_data.get("author", {}).get("name", "RiskExec"),
|
||||
"email": plugin_data.get("author", {}).get("email", "platform@riskexec.com"),
|
||||
"url": plugin_data.get("author", {}).get("url", "https://github.com/epieczko/betty")
|
||||
},
|
||||
"license": plugin_data.get("license", "MIT"),
|
||||
"tags": plugin_data.get("metadata", {}).get("tags", [
|
||||
"framework",
|
||||
"api-development",
|
||||
"workflow",
|
||||
"governance",
|
||||
"enterprise"
|
||||
]),
|
||||
"requirements": plugin_data.get("requirements", {
|
||||
"python": ">=3.11",
|
||||
"packages": ["pyyaml"]
|
||||
}),
|
||||
"strict": True # Requires plugin.yaml manifest
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
return marketplace
|
||||
|
||||
|
||||
def main():
|
||||
"""Main CLI entry point."""
|
||||
logger.info("Starting marketplace catalog generation from registries...")
|
||||
|
||||
# Define registry and output paths
|
||||
skills_registry_path = os.path.join(BASE_DIR, "registry", "skills.json")
|
||||
agents_registry_path = os.path.join(BASE_DIR, "registry", "agents.json")
|
||||
commands_registry_path = os.path.join(BASE_DIR, "registry", "commands.json")
|
||||
hooks_registry_path = os.path.join(BASE_DIR, "registry", "hooks.json")
|
||||
|
||||
marketplace_dir = os.path.join(BASE_DIR, "marketplace")
|
||||
skills_output_path = os.path.join(marketplace_dir, "skills.json")
|
||||
agents_output_path = os.path.join(marketplace_dir, "agents.json")
|
||||
commands_output_path = os.path.join(marketplace_dir, "commands.json")
|
||||
hooks_output_path = os.path.join(marketplace_dir, "hooks.json")
|
||||
|
||||
try:
|
||||
# Load registry files
|
||||
logger.info("Loading registry files...")
|
||||
skills_registry = load_registry_file(skills_registry_path)
|
||||
agents_registry = load_registry_file(agents_registry_path)
|
||||
commands_registry = load_registry_file(commands_registry_path)
|
||||
hooks_registry = load_registry_file(hooks_registry_path)
|
||||
|
||||
# Generate marketplace catalogs
|
||||
logger.info("Generating marketplace catalogs...")
|
||||
skills_marketplace = generate_skills_marketplace(skills_registry)
|
||||
agents_marketplace = generate_agents_marketplace(agents_registry)
|
||||
commands_marketplace = generate_commands_marketplace(commands_registry)
|
||||
hooks_marketplace = generate_hooks_marketplace(hooks_registry)
|
||||
|
||||
# Write Betty marketplace catalogs to files
|
||||
logger.info("Writing Betty marketplace files...")
|
||||
write_marketplace_file(skills_marketplace, skills_output_path)
|
||||
write_marketplace_file(agents_marketplace, agents_output_path)
|
||||
write_marketplace_file(commands_marketplace, commands_output_path)
|
||||
write_marketplace_file(hooks_marketplace, hooks_output_path)
|
||||
|
||||
# Generate and write Claude Code marketplace.json
|
||||
logger.info("Generating Claude Code marketplace.json...")
|
||||
claude_marketplace = generate_claude_code_marketplace()
|
||||
claude_marketplace_path = os.path.join(BASE_DIR, ".claude-plugin", "marketplace.json")
|
||||
write_marketplace_file(claude_marketplace, claude_marketplace_path)
|
||||
|
||||
# Report results
|
||||
result = {
|
||||
"ok": True,
|
||||
"status": "success",
|
||||
"skills_output": skills_output_path,
|
||||
"agents_output": agents_output_path,
|
||||
"commands_output": commands_output_path,
|
||||
"hooks_output": hooks_output_path,
|
||||
"claude_marketplace_output": claude_marketplace_path,
|
||||
"skills_certified": skills_marketplace["certified_count"],
|
||||
"skills_total": skills_marketplace["total_skills"],
|
||||
"agents_certified": agents_marketplace["certified_count"],
|
||||
"agents_total": agents_marketplace["total_agents"],
|
||||
"commands_certified": commands_marketplace["certified_count"],
|
||||
"commands_total": commands_marketplace["total_commands"],
|
||||
"hooks_certified": hooks_marketplace["certified_count"],
|
||||
"hooks_total": hooks_marketplace["total_hooks"]
|
||||
}
|
||||
|
||||
# Print summary
|
||||
logger.info(f"✅ Generated marketplace catalogs:")
|
||||
logger.info(f" Skills: {result['skills_certified']}/{result['skills_total']} certified")
|
||||
logger.info(f" Agents: {result['agents_certified']}/{result['agents_total']} certified")
|
||||
logger.info(f" Commands: {result['commands_certified']}/{result['commands_total']} certified")
|
||||
logger.info(f" Hooks: {result['hooks_certified']}/{result['hooks_total']} certified")
|
||||
logger.info(f"📄 Outputs:")
|
||||
logger.info(f" - {skills_output_path}")
|
||||
logger.info(f" - {agents_output_path}")
|
||||
logger.info(f" - {commands_output_path}")
|
||||
logger.info(f" - {hooks_output_path}")
|
||||
logger.info(f" - {claude_marketplace_path} (Claude Code format)")
|
||||
|
||||
print(json.dumps(result, indent=2))
|
||||
sys.exit(0)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to generate marketplace catalogs: {e}")
|
||||
result = {
|
||||
"ok": False,
|
||||
"status": "failed",
|
||||
"error": str(e)
|
||||
}
|
||||
print(json.dumps(result, indent=2))
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
37
skills/generate.marketplace/skill.yaml
Normal file
37
skills/generate.marketplace/skill.yaml
Normal file
@@ -0,0 +1,37 @@
|
||||
name: generate.marketplace
|
||||
version: 0.3.0
|
||||
description: >
|
||||
Generate marketplace catalog files from Betty Framework registries.
|
||||
Filters active and certified skills/agents/commands/hooks and outputs marketplace-ready JSON files
|
||||
with last_updated timestamps. Also generates Claude Code marketplace.json format.
|
||||
inputs: []
|
||||
outputs:
|
||||
- marketplace/skills.json
|
||||
- marketplace/agents.json
|
||||
- marketplace/commands.json
|
||||
- marketplace/hooks.json
|
||||
- .claude-plugin/marketplace.json
|
||||
dependencies:
|
||||
- registry.update
|
||||
status: active
|
||||
|
||||
entrypoints:
|
||||
- command: /marketplace/generate
|
||||
handler: generate_marketplace.py
|
||||
runtime: python
|
||||
description: >
|
||||
Generate marketplace catalogs from registry files. Filters by status: active and certified: true.
|
||||
Outputs skills, agents, commands, and hooks marketplace files with last_updated timestamps.
|
||||
Also generates .claude-plugin/marketplace.json in Claude Code marketplace format.
|
||||
parameters: []
|
||||
permissions:
|
||||
- filesystem:read
|
||||
- filesystem:write
|
||||
|
||||
tags:
|
||||
- marketplace
|
||||
- registry
|
||||
- automation
|
||||
- infrastructure
|
||||
- commands
|
||||
- hooks
|
||||
Reference in New Issue
Block a user