Compare commits
36 Commits
v5.9.0
...
3d2f14b0ab
| Author | SHA1 | Date | |
|---|---|---|---|
| 3d2f14b0ab | |||
| b76e53c215 | |||
| 3d96f6b505 | |||
| edee44088c | |||
| 938ddd7b69 | |||
| aa68883f87 | |||
| dd36a79bcb | |||
| 091e3d25f3 | |||
| b605a2de5e | |||
| 4aa0baa2a6 | |||
| e3db084195 | |||
| 2a92211b28 | |||
| de6cba5f31 | |||
| 31dcf0338c | |||
| 569dc9a8f2 | |||
| 7217790143 | |||
| 97159274c7 | |||
| 5cf4b4a78c | |||
| 96a612a1f4 | |||
| 47a3a8b48a | |||
| 1b75b10fec | |||
| e925f80252 | |||
| b1070aac52 | |||
| d2b6560fba | |||
| 4b1c561bb6 | |||
| 786d3c0013 | |||
| 59cc67f857 | |||
| 6613ef1d67 | |||
| 6619d0a2fb | |||
| dc08ce1439 | |||
| 2173f3389a | |||
| fab1345bcb | |||
| 36e6ac2dd0 | |||
| 3e0e779803 | |||
| 74198743ab | |||
| d57bff184e |
@@ -6,7 +6,7 @@
|
||||
},
|
||||
"metadata": {
|
||||
"description": "Project management plugins with Gitea and NetBox integrations",
|
||||
"version": "5.9.0"
|
||||
"version": "5.8.0"
|
||||
},
|
||||
"plugins": [
|
||||
{
|
||||
|
||||
85
CHANGELOG.md
85
CHANGELOG.md
@@ -4,91 +4,6 @@ All notable changes to the Leo Claude Marketplace will be documented in this fil
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
---
|
||||
|
||||
## [5.9.0] - 2026-02-03
|
||||
|
||||
### Added
|
||||
|
||||
#### Plugin Installation Scripts
|
||||
New scripts for installing marketplace plugins into consumer projects:
|
||||
|
||||
- **`scripts/install-plugin.sh`** — Install a plugin to a consumer project
|
||||
- Adds MCP server entry to target's `.mcp.json` (if plugin has MCP server)
|
||||
- Appends integration snippet to target's `CLAUDE.md`
|
||||
- Idempotent: safe to run multiple times
|
||||
- Validates plugin exists and target path is valid
|
||||
|
||||
- **`scripts/uninstall-plugin.sh`** — Remove a plugin from a consumer project
|
||||
- Removes MCP server entry from `.mcp.json`
|
||||
- Removes integration section from `CLAUDE.md`
|
||||
|
||||
- **`scripts/list-installed.sh`** — Show installed plugins in a project
|
||||
- Lists fully installed, partially installed, and available plugins
|
||||
- Shows plugin versions and descriptions
|
||||
|
||||
**Usage:**
|
||||
```bash
|
||||
./scripts/install-plugin.sh data-platform ~/projects/personal-portfolio
|
||||
./scripts/list-installed.sh ~/projects/personal-portfolio
|
||||
./scripts/uninstall-plugin.sh data-platform ~/projects/personal-portfolio
|
||||
```
|
||||
|
||||
**Documentation:** `docs/CONFIGURATION.md` updated with "Installing Plugins to Consumer Projects" section.
|
||||
|
||||
### Fixed
|
||||
|
||||
#### Plugin Installation Scripts — MCP Mapping & Section Markers
|
||||
|
||||
**MCP Server Mapping:**
|
||||
- Added `mcp_servers` field to plugin.json for plugins that use shared MCP servers
|
||||
- `projman` and `pr-review` now correctly install `gitea` MCP server
|
||||
- `cmdb-assistant` now correctly installs `netbox` MCP server
|
||||
- Scripts read MCP server names from plugin.json instead of assuming plugin name = server name
|
||||
|
||||
**CLAUDE.md Section Markers:**
|
||||
- Install script now wraps integration content with HTML comment markers:
|
||||
`<!-- BEGIN marketplace-plugin: {name} -->` and `<!-- END marketplace-plugin: {name} -->`
|
||||
- Uninstall script uses markers for precise section removal (no more code block false positives)
|
||||
- Backward compatible: falls back to legacy header detection for pre-marker installations
|
||||
|
||||
**Plugins updated with `mcp_servers` field:**
|
||||
- `projman` → `["gitea"]`
|
||||
- `pr-review` → `["gitea"]`
|
||||
- `cmdb-assistant` → `["netbox"]`
|
||||
- `data-platform` → `["data-platform"]`
|
||||
- `viz-platform` → `["viz-platform"]`
|
||||
- `contract-validator` → `["contract-validator"]`
|
||||
|
||||
#### Agent Model Selection
|
||||
|
||||
Per-agent model selection using Claude Code's now-supported `model` frontmatter field.
|
||||
|
||||
- All 25 marketplace agents assigned appropriate model (`sonnet`, `haiku`, or `inherit`)
|
||||
- Model assignment based on reasoning depth, tool complexity, and latency requirements
|
||||
- Documentation added to `CLAUDE.md` and `docs/CONFIGURATION.md`
|
||||
|
||||
**Supported values:** `sonnet` (default), `opus`, `haiku`, `inherit`
|
||||
|
||||
**Model assignments:**
|
||||
| Model | Agent Types |
|
||||
|-------|-------------|
|
||||
| sonnet | Planner, Orchestrator, Executor, Code Reviewer, Coordinator, Security Reviewers, Data Advisor, Design Reviewer, etc. |
|
||||
| haiku | Maintainability Auditor, Test Validator, Component Check, Theme Setup, Git Assistant, Data Ingestion, Agent Check |
|
||||
|
||||
### Fixed
|
||||
|
||||
#### Agent Frontmatter Standardization
|
||||
|
||||
- Fixed viz-platform and data-platform agents using non-standard `agent:` field (now `name:`)
|
||||
- Removed non-standard `triggers:` field from domain agents (trigger info already in agent body)
|
||||
- Added missing frontmatter to 13 agents across pr-review, viz-platform, contract-validator, clarity-assist, git-flow, doc-guardian, code-sentinel, cmdb-assistant, and data-platform
|
||||
- All 25 agents now have consistent `name`, `description`, and `model` fields
|
||||
|
||||
---
|
||||
|
||||
## [5.8.0] - 2026-02-02
|
||||
|
||||
### Added
|
||||
|
||||
36
CLAUDE.md
36
CLAUDE.md
@@ -146,7 +146,7 @@ When user says "fix the sprint-plan command", edit the SOURCE code.
|
||||
## Project Overview
|
||||
|
||||
**Repository:** leo-claude-mktplace
|
||||
**Version:** 5.9.0
|
||||
**Version:** 5.8.0
|
||||
**Status:** Production Ready
|
||||
|
||||
A plugin marketplace for Claude Code containing:
|
||||
@@ -271,40 +271,6 @@ leo-claude-mktplace/
|
||||
| **Executor** | Implementation-focused | Code implementation, branch management, MR creation |
|
||||
| **Code Reviewer** | Thorough, practical | Pre-close quality review, security scan, test verification |
|
||||
|
||||
### Agent Model Selection
|
||||
|
||||
Agents specify their model in frontmatter using Claude Code's `model` field. Supported values: `sonnet` (default), `opus`, `haiku`, `inherit`.
|
||||
|
||||
| Plugin | Agent | Model | Rationale |
|
||||
|--------|-------|-------|-----------|
|
||||
| projman | Planner | sonnet | Architectural analysis, sprint planning |
|
||||
| projman | Orchestrator | sonnet | Coordination and tool dispatch |
|
||||
| projman | Executor | sonnet | Code generation and implementation |
|
||||
| projman | Code Reviewer | sonnet | Quality gate, pattern detection |
|
||||
| pr-review | Coordinator | sonnet | Orchestrates sub-agents, aggregates findings |
|
||||
| pr-review | Security Reviewer | sonnet | Security analysis |
|
||||
| pr-review | Performance Analyst | sonnet | Performance pattern detection |
|
||||
| pr-review | Maintainability Auditor | haiku | Pattern matching (complexity, duplication) |
|
||||
| pr-review | Test Validator | haiku | Coverage gap detection |
|
||||
| data-platform | Data Advisor | sonnet | Schema validation, dbt orchestration |
|
||||
| data-platform | Data Analysis | sonnet | Data exploration and profiling |
|
||||
| data-platform | Data Ingestion | haiku | Data loading operations |
|
||||
| viz-platform | Design Reviewer | sonnet | DMC validation + accessibility |
|
||||
| viz-platform | Layout Builder | sonnet | Dashboard design guidance |
|
||||
| viz-platform | Component Check | haiku | Quick component validation |
|
||||
| viz-platform | Theme Setup | haiku | Theme configuration |
|
||||
| contract-validator | Agent Check | haiku | Reference checking |
|
||||
| contract-validator | Full Validation | sonnet | Marketplace sweep |
|
||||
| code-sentinel | Security Reviewer | sonnet | Security analysis |
|
||||
| code-sentinel | Refactor Advisor | sonnet | Code refactoring advice |
|
||||
| doc-guardian | Doc Analyzer | sonnet | Documentation drift detection |
|
||||
| clarity-assist | Clarity Coach | sonnet | Conversational coaching |
|
||||
| git-flow | Git Assistant | haiku | Git operations |
|
||||
| claude-config-maintainer | Maintainer | sonnet | CLAUDE.md optimization |
|
||||
| cmdb-assistant | CMDB Assistant | sonnet | NetBox operations |
|
||||
|
||||
Override by editing the `model:` field in `plugins/{plugin}/agents/{agent}.md`.
|
||||
|
||||
### MCP Server Tools (Gitea)
|
||||
|
||||
| Category | Tools |
|
||||
|
||||
12
README.md
12
README.md
@@ -1,4 +1,4 @@
|
||||
# Leo Claude Marketplace - v5.9.0
|
||||
# Leo Claude Marketplace - v5.8.0
|
||||
|
||||
A collection of Claude Code plugins for project management, infrastructure automation, and development workflows.
|
||||
|
||||
@@ -47,11 +47,11 @@ Comprehensive pull request review using specialized agents.
|
||||
**Commands:** `/pr-review`, `/pr-summary`, `/pr-findings`, `/pr-diff`, `/initial-setup`, `/project-init`, `/project-sync`
|
||||
|
||||
#### [claude-config-maintainer](./plugins/claude-config-maintainer)
|
||||
**CLAUDE.md and Settings Optimization**
|
||||
**CLAUDE.md Optimization and Maintenance**
|
||||
|
||||
Analyze, optimize, and create CLAUDE.md configuration files. Audit and optimize settings.local.json permissions.
|
||||
Analyze, optimize, and create CLAUDE.md configuration files for Claude Code projects.
|
||||
|
||||
**Commands:** `/analyze`, `/optimize`, `/init`, `/config-diff`, `/config-lint`, `/config-audit-settings`, `/config-optimize-settings`, `/config-permissions-map`
|
||||
**Commands:** `/config-analyze`, `/config-optimize`, `/config-init`, `/config-diff`, `/config-lint`
|
||||
|
||||
#### [contract-validator](./plugins/contract-validator) *NEW in v5.0.0*
|
||||
**Cross-Plugin Compatibility Validation**
|
||||
@@ -122,7 +122,7 @@ Comprehensive data engineering toolkit with persistent DataFrame storage.
|
||||
- 100k row limit with chunking support
|
||||
- Auto-detection of dbt projects
|
||||
|
||||
**Commands:** `/ingest`, `/profile`, `/schema`, `/explain`, `/lineage`, `/lineage-viz`, `/run`, `/dbt-test`, `/data-quality`, `/data-review`, `/data-gate`, `/initial-setup`
|
||||
**Commands:** `/ingest`, `/profile`, `/schema`, `/explain`, `/lineage`, `/lineage-viz`, `/run`, `/dbt-test`, `/data-quality`, `/initial-setup`
|
||||
|
||||
### Visualization
|
||||
|
||||
@@ -312,7 +312,7 @@ After installing plugins, the `/plugin` command may show `(no content)` - this i
|
||||
| clarity-assist | `/clarity-assist:clarify` |
|
||||
| doc-guardian | `/doc-guardian:doc-audit` |
|
||||
| code-sentinel | `/code-sentinel:security-scan` |
|
||||
| claude-config-maintainer | `/claude-config-maintainer:analyze` |
|
||||
| claude-config-maintainer | `/claude-config-maintainer:config-analyze` |
|
||||
| cmdb-assistant | `/cmdb-assistant:cmdb-search` |
|
||||
| data-platform | `/data-platform:ingest` |
|
||||
| viz-platform | `/viz-platform:chart` |
|
||||
|
||||
@@ -182,42 +182,10 @@ MCP servers are **shared at repository root** and configured in `.mcp.json`.
|
||||
| MCP configuration | `.mcp.json` | `.mcp.json` (at repo root) |
|
||||
| Shared MCP server | `mcp-servers/{server}/` | `mcp-servers/gitea/` |
|
||||
| MCP server code | `mcp-servers/{server}/mcp_server/` | `mcp-servers/gitea/mcp_server/` |
|
||||
| MCP venv (local) | `mcp-servers/{server}/.venv/` | `mcp-servers/gitea/.venv/` |
|
||||
| MCP venv | `mcp-servers/{server}/.venv/` | `mcp-servers/gitea/.venv/` |
|
||||
|
||||
**Note:** Plugins do NOT have their own `mcp-servers/` directories. All MCP servers are shared at root and configured via `.mcp.json`.
|
||||
|
||||
### MCP Venv Paths - CRITICAL
|
||||
|
||||
**Venvs live in a CACHE directory that SURVIVES marketplace updates.**
|
||||
|
||||
When checking for venvs, ALWAYS check in this order:
|
||||
|
||||
| Priority | Path | Survives Updates? |
|
||||
|----------|------|-------------------|
|
||||
| 1 (CHECK FIRST) | `~/.cache/claude-mcp-venvs/leo-claude-mktplace/{server}/.venv/` | YES |
|
||||
| 2 (fallback) | `{marketplace}/mcp-servers/{server}/.venv/` | NO |
|
||||
|
||||
**Why cache first?**
|
||||
- Marketplace directory gets WIPED on every update/reinstall
|
||||
- Cache directory SURVIVES updates
|
||||
- False "venv missing" errors waste hours of debugging
|
||||
|
||||
**Pattern for hooks checking venvs:**
|
||||
```bash
|
||||
CACHE_VENV="$HOME/.cache/claude-mcp-venvs/leo-claude-mktplace/{server}/.venv/bin/python"
|
||||
LOCAL_VENV="$MARKETPLACE_ROOT/mcp-servers/{server}/.venv/bin/python"
|
||||
|
||||
if [[ -f "$CACHE_VENV" ]]; then
|
||||
VENV_PATH="$CACHE_VENV"
|
||||
elif [[ -f "$LOCAL_VENV" ]]; then
|
||||
VENV_PATH="$LOCAL_VENV"
|
||||
else
|
||||
echo "venv missing"
|
||||
fi
|
||||
```
|
||||
|
||||
**See lesson learned:** [Startup Hooks Must Check Venv Cache Path First](https://gitea.hotserv.cloud/personal-projects/leo-claude-mktplace/wiki/lessons/patterns/startup-hooks-must-check-venv-cache-path-first)
|
||||
|
||||
### Documentation Paths
|
||||
|
||||
| Type | Location |
|
||||
|
||||
@@ -415,144 +415,6 @@ The command auto-detects that system config exists and runs quick project setup.
|
||||
|
||||
---
|
||||
|
||||
## Installing Plugins to Consumer Projects
|
||||
|
||||
The marketplace provides scripts to install plugins into consumer projects. This sets up the MCP server connections and adds CLAUDE.md integration snippets.
|
||||
|
||||
### Install a Plugin
|
||||
|
||||
```bash
|
||||
cd /path/to/leo-claude-mktplace
|
||||
./scripts/install-plugin.sh <plugin-name> <target-project-path>
|
||||
```
|
||||
|
||||
**Examples:**
|
||||
```bash
|
||||
# Install data-platform to a portfolio project
|
||||
./scripts/install-plugin.sh data-platform ~/projects/personal-portfolio
|
||||
|
||||
# Install multiple plugins
|
||||
./scripts/install-plugin.sh viz-platform ~/projects/personal-portfolio
|
||||
./scripts/install-plugin.sh projman ~/projects/personal-portfolio
|
||||
```
|
||||
|
||||
**What it does:**
|
||||
1. Validates the plugin exists in the marketplace
|
||||
2. Adds MCP server entry to target's `.mcp.json` (if plugin has MCP server)
|
||||
3. Appends integration snippet to target's `CLAUDE.md`
|
||||
4. Reports changes and lists available commands
|
||||
|
||||
**After installation:** Restart your Claude Code session for MCP tools to become available.
|
||||
|
||||
### Uninstall a Plugin
|
||||
|
||||
```bash
|
||||
./scripts/uninstall-plugin.sh <plugin-name> <target-project-path>
|
||||
```
|
||||
|
||||
Removes the MCP server entry and CLAUDE.md integration section.
|
||||
|
||||
### List Installed Plugins
|
||||
|
||||
```bash
|
||||
./scripts/list-installed.sh <target-project-path>
|
||||
```
|
||||
|
||||
Shows which marketplace plugins are installed, partially installed, or available.
|
||||
|
||||
**Output example:**
|
||||
```
|
||||
✓ Fully Installed:
|
||||
PLUGIN VERSION DESCRIPTION
|
||||
------ ------- -----------
|
||||
data-platform 1.3.0 pandas, PostgreSQL, and dbt integration...
|
||||
viz-platform 1.1.0 DMC validation, Plotly charts, and theming...
|
||||
|
||||
○ Available (not installed):
|
||||
projman 3.4.0 Sprint planning and project management...
|
||||
```
|
||||
|
||||
### Plugins with MCP Servers
|
||||
|
||||
Not all plugins have MCP servers. The install script handles this automatically:
|
||||
|
||||
| Plugin | Has MCP Server | Notes |
|
||||
|--------|---------------|-------|
|
||||
| data-platform | ✓ | pandas, PostgreSQL, dbt tools |
|
||||
| viz-platform | ✓ | DMC validation, chart, theme tools |
|
||||
| contract-validator | ✓ | Plugin compatibility validation |
|
||||
| cmdb-assistant | ✓ (via netbox) | NetBox CMDB tools |
|
||||
| projman | ✓ (via gitea) | Issue, wiki, PR tools |
|
||||
| pr-review | ✓ (via gitea) | PR review tools |
|
||||
| git-flow | ✗ | Commands only |
|
||||
| doc-guardian | ✗ | Commands and hooks only |
|
||||
| code-sentinel | ✗ | Commands and hooks only |
|
||||
| clarity-assist | ✗ | Commands only |
|
||||
|
||||
### Script Requirements
|
||||
|
||||
- **jq** must be installed (`sudo apt install jq`)
|
||||
- Scripts are idempotent (safe to run multiple times)
|
||||
|
||||
---
|
||||
|
||||
## Agent Model Selection
|
||||
|
||||
Marketplace agents specify their preferred model using Claude Code's `model` frontmatter field. This allows cost/performance optimization per agent.
|
||||
|
||||
### Supported Values
|
||||
|
||||
| Value | Description |
|
||||
|-------|-------------|
|
||||
| `sonnet` | Default. Balanced performance and cost. |
|
||||
| `opus` | Higher reasoning depth. Use for complex analysis. |
|
||||
| `haiku` | Faster, lower cost. Use for mechanical tasks. |
|
||||
| `inherit` | Use session's current model setting. |
|
||||
|
||||
### How It Works
|
||||
|
||||
Each agent in `plugins/{plugin}/agents/{agent}.md` has frontmatter like:
|
||||
|
||||
```yaml
|
||||
---
|
||||
name: planner
|
||||
description: Sprint planning agent - thoughtful architecture analysis
|
||||
model: sonnet
|
||||
---
|
||||
```
|
||||
|
||||
Claude Code reads this field when invoking the agent as a subagent.
|
||||
|
||||
### Model Assignments
|
||||
|
||||
Agents are assigned models based on their task complexity:
|
||||
|
||||
| Model | Agents | Rationale |
|
||||
|-------|--------|-----------|
|
||||
| **sonnet** | Planner, Orchestrator, Executor, Code Reviewer, Coordinator, Security Reviewers, Performance Analyst, Data Advisor, Data Analysis, Design Reviewer, Layout Builder, Full Validation, Doc Analyzer, Clarity Coach, Maintainer, CMDB Assistant, Refactor Advisor | Standard reasoning, tool orchestration, code generation |
|
||||
| **haiku** | Maintainability Auditor, Test Validator, Component Check, Theme Setup, Agent Check, Data Ingestion, Git Assistant | Pattern matching, quick validation, mechanical tasks |
|
||||
|
||||
### Overriding Model Selection
|
||||
|
||||
**Per-agent override:** Edit the `model:` field in the agent file:
|
||||
|
||||
```bash
|
||||
# Change executor to use opus for heavy implementation work
|
||||
nano plugins/projman/agents/executor.md
|
||||
# Change model: sonnet to model: opus
|
||||
```
|
||||
|
||||
**Session-level:** Users on Opus subscription can change the agent's model to `inherit` to use whatever model the session is using.
|
||||
|
||||
### Best Practices
|
||||
|
||||
1. **Default to sonnet** - Good balance for most tasks
|
||||
2. **Use haiku for speed-sensitive agents** - Sub-agents dispatched in parallel, read-only tasks
|
||||
3. **Reserve opus for heavy analysis** - Only when sonnet's reasoning isn't sufficient
|
||||
4. **Use inherit sparingly** - Only when you want session-level control
|
||||
|
||||
---
|
||||
|
||||
## Automatic Validation Features
|
||||
|
||||
### API Validation
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "clarity-assist",
|
||||
"version": "1.2.0",
|
||||
"version": "1.0.0",
|
||||
"description": "Prompt optimization and requirement clarification with ND-friendly accommodations",
|
||||
"author": {
|
||||
"name": "Leo Miranda",
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
---
|
||||
name: clarity-coach
|
||||
description: Patient, structured coach helping users articulate requirements clearly. Uses neurodivergent-friendly communication patterns.
|
||||
model: sonnet
|
||||
---
|
||||
|
||||
# Clarity Coach Agent
|
||||
|
||||
## Visual Output Requirements
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
name: maintainer
|
||||
description: CLAUDE.md optimization and maintenance agent
|
||||
model: sonnet
|
||||
---
|
||||
|
||||
# CLAUDE.md Maintainer Agent
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
---
|
||||
name: cmdb-assistant
|
||||
description: Infrastructure management assistant specialized in NetBox CMDB operations. Use for device management, IP addressing, and infrastructure queries.
|
||||
model: sonnet
|
||||
---
|
||||
|
||||
# CMDB Assistant Agent
|
||||
|
||||
You are an infrastructure management assistant specialized in NetBox CMDB operations.
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
---
|
||||
name: refactor-advisor
|
||||
description: Code structure and refactoring specialist. Use when analyzing code quality, design patterns, or planning refactoring work.
|
||||
model: sonnet
|
||||
description: Code structure and refactoring specialist
|
||||
---
|
||||
|
||||
# Refactor Advisor Agent
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
name: security-reviewer
|
||||
description: Security-focused code review agent
|
||||
model: sonnet
|
||||
---
|
||||
|
||||
# Security Reviewer Agent
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "contract-validator",
|
||||
"version": "1.2.0",
|
||||
"version": "1.1.0",
|
||||
"description": "Cross-plugin compatibility validation and Claude.md agent verification",
|
||||
"author": {
|
||||
"name": "Leo Miranda",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
name: agent-check
|
||||
description: Agent definition validator for quick verification
|
||||
model: haiku
|
||||
---
|
||||
|
||||
# Agent Check Agent
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
---
|
||||
name: full-validation
|
||||
description: Contract validation specialist for comprehensive cross-plugin compatibility validation of the entire marketplace.
|
||||
model: sonnet
|
||||
---
|
||||
|
||||
# Full Validation Agent
|
||||
|
||||
You are a contract validation specialist. Your role is to perform comprehensive cross-plugin compatibility validation for the entire marketplace.
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
---
|
||||
name: data-advisor
|
||||
description: Reviews code for data integrity, schema validity, and dbt compliance using data-platform MCP tools. Use when validating database operations or data pipelines.
|
||||
model: sonnet
|
||||
agent: data-advisor
|
||||
description: Reviews code for data integrity, schema validity, and dbt compliance using data-platform MCP tools
|
||||
triggers:
|
||||
- /data-review command
|
||||
- /data-gate command
|
||||
- projman orchestrator domain gate
|
||||
---
|
||||
|
||||
# Data Advisor Agent
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
name: data-analysis
|
||||
description: Data analysis specialist for exploration and profiling
|
||||
model: sonnet
|
||||
---
|
||||
|
||||
# Data Analysis Agent
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
---
|
||||
name: data-ingestion
|
||||
description: Data ingestion specialist for loading, transforming, and preparing data for analysis.
|
||||
model: haiku
|
||||
---
|
||||
|
||||
# Data Ingestion Agent
|
||||
|
||||
You are a data ingestion specialist. Your role is to help users load, transform, and prepare data for analysis.
|
||||
|
||||
@@ -5,26 +5,11 @@
|
||||
|
||||
PREFIX="[data-platform]"
|
||||
|
||||
# Check if MCP venv exists - check cache first, then local
|
||||
CACHE_VENV="$HOME/.cache/claude-mcp-venvs/leo-claude-mktplace/data-platform/.venv/bin/python"
|
||||
# Check if MCP venv exists
|
||||
PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-$(dirname "$(dirname "$(realpath "$0")")")}"
|
||||
MARKETPLACE_ROOT="$(dirname "$(dirname "$PLUGIN_ROOT")")"
|
||||
LOCAL_VENV="$MARKETPLACE_ROOT/mcp-servers/data-platform/.venv/bin/python"
|
||||
VENV_PATH="$PLUGIN_ROOT/mcp-servers/data-platform/.venv/bin/python"
|
||||
|
||||
# Check cache first (preferred), then local symlink
|
||||
CACHE_VENV_DIR="$HOME/.cache/claude-mcp-venvs/leo-claude-mktplace/data-platform/.venv"
|
||||
LOCAL_VENV_DIR="$MARKETPLACE_ROOT/mcp-servers/data-platform/.venv"
|
||||
|
||||
if [[ -f "$CACHE_VENV" ]]; then
|
||||
VENV_PATH="$CACHE_VENV"
|
||||
# Auto-create symlink in installed marketplace if missing
|
||||
if [[ ! -e "$LOCAL_VENV_DIR" && -d "$CACHE_VENV_DIR" ]]; then
|
||||
mkdir -p "$(dirname "$LOCAL_VENV_DIR")" 2>/dev/null
|
||||
ln -sf "$CACHE_VENV_DIR" "$LOCAL_VENV_DIR" 2>/dev/null
|
||||
fi
|
||||
elif [[ -f "$LOCAL_VENV" ]]; then
|
||||
VENV_PATH="$LOCAL_VENV"
|
||||
else
|
||||
if [[ ! -f "$VENV_PATH" ]]; then
|
||||
echo "$PREFIX MCP venv missing - run /initial-setup or setup.sh"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "doc-guardian",
|
||||
"description": "Automatic documentation drift detection and synchronization",
|
||||
"version": "1.1.0",
|
||||
"version": "1.0.0",
|
||||
"author": {
|
||||
"name": "Leo Miranda",
|
||||
"email": "leobmiranda@gmail.com"
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
---
|
||||
name: doc-analyzer
|
||||
description: Specialized agent for documentation analysis and drift detection. Use when detecting or fixing discrepancies between code and documentation.
|
||||
model: sonnet
|
||||
description: Specialized agent for documentation analysis and drift detection
|
||||
---
|
||||
|
||||
# Documentation Analyzer Agent
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "git-flow",
|
||||
"version": "1.2.0",
|
||||
"version": "1.0.0",
|
||||
"description": "Git workflow automation with intelligent commit messages and branch management",
|
||||
"author": {
|
||||
"name": "Leo Miranda",
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
---
|
||||
name: git-assistant
|
||||
description: Git workflow assistant for complex git operations, conflict resolution, and repository history management.
|
||||
model: haiku
|
||||
---
|
||||
|
||||
# Git Assistant Agent
|
||||
|
||||
## Visual Output Requirements
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
---
|
||||
name: coordinator
|
||||
description: Review coordinator that orchestrates the multi-agent PR review process. Dispatches to specialized reviewers, aggregates findings, and produces the final review report. Use proactively after code changes.
|
||||
model: sonnet
|
||||
---
|
||||
|
||||
# Coordinator Agent
|
||||
|
||||
## Visual Output Requirements
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
---
|
||||
name: maintainability-auditor
|
||||
description: Identifies code complexity, duplication, naming issues, and architecture concerns in PR changes.
|
||||
model: haiku
|
||||
---
|
||||
|
||||
# Maintainability Auditor Agent
|
||||
|
||||
## Visual Output Requirements
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
---
|
||||
name: performance-analyst
|
||||
description: Performance-focused code reviewer that identifies performance issues, inefficiencies, and optimization opportunities.
|
||||
model: sonnet
|
||||
---
|
||||
|
||||
# Performance Analyst Agent
|
||||
|
||||
## Visual Output Requirements
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
name: security-reviewer
|
||||
description: Security-focused code reviewer for PR analysis
|
||||
model: sonnet
|
||||
---
|
||||
|
||||
# Security Reviewer Agent
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
---
|
||||
name: test-validator
|
||||
description: Test quality reviewer that validates test coverage, test quality, and testing practices in PR changes.
|
||||
model: haiku
|
||||
---
|
||||
|
||||
# Test Validator Agent
|
||||
|
||||
## Visual Output Requirements
|
||||
|
||||
@@ -5,18 +5,11 @@
|
||||
|
||||
PREFIX="[pr-review]"
|
||||
|
||||
# Check if MCP venv exists - check cache first, then local
|
||||
CACHE_VENV="$HOME/.cache/claude-mcp-venvs/leo-claude-mktplace/gitea/.venv/bin/python"
|
||||
# Check if MCP venv exists
|
||||
PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-$(dirname "$(dirname "$(realpath "$0")")")}"
|
||||
MARKETPLACE_ROOT="$(dirname "$(dirname "$PLUGIN_ROOT")")"
|
||||
LOCAL_VENV="$MARKETPLACE_ROOT/mcp-servers/gitea/.venv/bin/python"
|
||||
VENV_PATH="$PLUGIN_ROOT/mcp-servers/gitea/.venv/bin/python"
|
||||
|
||||
# Check cache first (preferred), then local
|
||||
if [[ -f "$CACHE_VENV" ]]; then
|
||||
VENV_PATH="$CACHE_VENV"
|
||||
elif [[ -f "$LOCAL_VENV" ]]; then
|
||||
VENV_PATH="$LOCAL_VENV"
|
||||
else
|
||||
if [[ ! -f "$VENV_PATH" ]]; then
|
||||
echo "$PREFIX MCP venvs missing - run setup.sh from installed marketplace"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "projman",
|
||||
"version": "3.4.0",
|
||||
"version": "3.3.0",
|
||||
"description": "Sprint planning and project management with Gitea integration",
|
||||
"author": {
|
||||
"name": "Leo Miranda",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
name: code-reviewer
|
||||
description: Pre-sprint code quality review agent
|
||||
model: sonnet
|
||||
---
|
||||
|
||||
# Code Reviewer Agent
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
name: executor
|
||||
description: Implementation executor agent - precise implementation guidance and code quality
|
||||
model: sonnet
|
||||
---
|
||||
|
||||
# Implementation Executor Agent
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
name: orchestrator
|
||||
description: Sprint orchestration agent - coordinates execution and tracks progress
|
||||
model: sonnet
|
||||
---
|
||||
|
||||
# Sprint Orchestration Agent
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
name: planner
|
||||
description: Sprint planning agent - thoughtful architecture analysis and issue creation
|
||||
model: sonnet
|
||||
---
|
||||
|
||||
# Sprint Planning Agent
|
||||
|
||||
@@ -29,19 +29,17 @@ if [[ -f ".env" ]]; then
|
||||
|
||||
if [[ -n "$GITEA_API_URL" && -n "$GITEA_API_TOKEN" && -n "$GITEA_REPO" ]]; then
|
||||
# Quick check for open issues without milestone (unplanned work)
|
||||
# Note: grep -c returns 0 on no match but exits non-zero, causing || to also fire
|
||||
# Use subshell to ensure single value
|
||||
OPEN_ISSUES=$(curl -s -m 5 \
|
||||
-H "Authorization: token $GITEA_API_TOKEN" \
|
||||
"${GITEA_API_URL}/repos/${GITEA_REPO}/issues?state=open&milestone=none&limit=1" 2>/dev/null | \
|
||||
grep -c '"number"' 2>/dev/null) || OPEN_ISSUES=0
|
||||
grep -c '"number"' || echo "0")
|
||||
|
||||
if [[ "$OPEN_ISSUES" -gt 0 ]]; then
|
||||
# Count total unplanned issues
|
||||
TOTAL_UNPLANNED=$(curl -s -m 5 \
|
||||
-H "Authorization: token $GITEA_API_TOKEN" \
|
||||
"${GITEA_API_URL}/repos/${GITEA_REPO}/issues?state=open&milestone=none" 2>/dev/null | \
|
||||
grep -c '"number"' 2>/dev/null) || TOTAL_UNPLANNED="?"
|
||||
grep -c '"number"' || echo "?")
|
||||
echo "$PREFIX ${TOTAL_UNPLANNED} open issues without milestone - consider /sprint-plan"
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
name: component-check
|
||||
description: DMC component validation specialist
|
||||
model: haiku
|
||||
---
|
||||
|
||||
# Component Check Agent
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
---
|
||||
name: design-reviewer
|
||||
description: Reviews code for design system compliance using viz-platform MCP tools. Use when validating DMC components, theme tokens, or accessibility standards.
|
||||
model: sonnet
|
||||
agent: design-reviewer
|
||||
description: Reviews code for design system compliance using viz-platform MCP tools
|
||||
triggers:
|
||||
- /design-review command
|
||||
- /design-gate command
|
||||
- projman orchestrator domain gate
|
||||
---
|
||||
|
||||
# Design Reviewer Agent
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
---
|
||||
name: layout-builder
|
||||
description: Practical dashboard layout specialist for creating well-structured layouts with filtering, grid systems, and responsive design.
|
||||
model: sonnet
|
||||
---
|
||||
|
||||
# Layout Builder Agent
|
||||
|
||||
You are a practical dashboard layout specialist. Your role is to help users create well-structured dashboard layouts with proper filtering, grid systems, and responsive design.
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
---
|
||||
name: theme-setup
|
||||
description: Design-focused theme setup specialist for creating consistent, brand-aligned themes for Dash Mantine Components applications.
|
||||
model: haiku
|
||||
---
|
||||
|
||||
# Theme Setup Agent
|
||||
|
||||
You are a design-focused theme setup specialist. Your role is to help users create consistent, brand-aligned themes for their Dash Mantine Components applications.
|
||||
|
||||
@@ -1,384 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# =============================================================================
|
||||
# install-plugin.sh - Install marketplace plugin to a consumer project
|
||||
# =============================================================================
|
||||
#
|
||||
# Usage: ./scripts/install-plugin.sh <plugin-name> <target-project-path>
|
||||
#
|
||||
# This script:
|
||||
# 1. Validates plugin exists in the marketplace
|
||||
# 2. Updates target project's .mcp.json with MCP server entries (if applicable)
|
||||
# 3. Appends CLAUDE.md integration snippet to target project
|
||||
# 4. Is idempotent (safe to run multiple times)
|
||||
#
|
||||
# Examples:
|
||||
# ./scripts/install-plugin.sh data-platform ~/projects/personal-portfolio
|
||||
# ./scripts/install-plugin.sh projman /home/user/my-project
|
||||
#
|
||||
# =============================================================================
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||
|
||||
# --- Color Definitions ---
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
CYAN='\033[0;36m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# --- Logging Functions ---
|
||||
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
|
||||
log_success() { echo -e "${GREEN}[OK]${NC} $1"; }
|
||||
log_skip() { echo -e "${YELLOW}[SKIP]${NC} $1"; }
|
||||
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
||||
log_warning() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
||||
|
||||
# --- Track Changes ---
|
||||
CHANGES_MADE=()
|
||||
SKIPPED=()
|
||||
MCP_SERVERS_INSTALLED=()
|
||||
|
||||
# --- Usage ---
|
||||
usage() {
|
||||
echo "Usage: $0 <plugin-name> <target-project-path>"
|
||||
echo ""
|
||||
echo "Install a marketplace plugin to a consumer project."
|
||||
echo ""
|
||||
echo "Arguments:"
|
||||
echo " plugin-name Name of the plugin (e.g., data-platform, viz-platform, projman)"
|
||||
echo " target-project-path Path to the target project (absolute or relative)"
|
||||
echo ""
|
||||
echo "Available plugins:"
|
||||
for dir in "$REPO_ROOT"/plugins/*/; do
|
||||
if [[ -d "$dir" ]]; then
|
||||
basename "$dir"
|
||||
fi
|
||||
done
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " $0 data-platform ~/projects/personal-portfolio"
|
||||
echo " $0 projman /home/user/my-project"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# --- Prerequisite Check ---
|
||||
check_prerequisites() {
|
||||
if ! command -v jq &> /dev/null; then
|
||||
log_error "jq is required but not installed."
|
||||
echo "Install with: sudo apt install jq"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# --- Validate Plugin Exists ---
|
||||
validate_plugin() {
|
||||
local plugin_name="$1"
|
||||
local plugin_dir="$REPO_ROOT/plugins/$plugin_name"
|
||||
|
||||
if [[ ! -d "$plugin_dir" ]]; then
|
||||
log_error "Plugin '$plugin_name' not found in $REPO_ROOT/plugins/"
|
||||
echo ""
|
||||
echo "Available plugins:"
|
||||
for dir in "$REPO_ROOT"/plugins/*/; do
|
||||
if [[ -d "$dir" ]]; then
|
||||
echo " - $(basename "$dir")"
|
||||
fi
|
||||
done
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "$plugin_dir/.claude-plugin/plugin.json" ]]; then
|
||||
log_error "Plugin '$plugin_name' missing .claude-plugin/plugin.json"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_success "Plugin '$plugin_name' found"
|
||||
}
|
||||
|
||||
# --- Validate Target Project ---
|
||||
validate_target() {
|
||||
local target_path="$1"
|
||||
|
||||
if [[ ! -d "$target_path" ]]; then
|
||||
log_error "Target project path does not exist: $target_path"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_success "Target project found: $target_path"
|
||||
|
||||
# Warn if no CLAUDE.md
|
||||
if [[ ! -f "$target_path/CLAUDE.md" ]]; then
|
||||
log_warning "Target project has no CLAUDE.md - will create one"
|
||||
fi
|
||||
}
|
||||
|
||||
# --- Get MCP Servers for Plugin ---
|
||||
# Reads the mcp_servers array from plugin.json
|
||||
# Returns newline-separated list of MCP server names, or empty if none
|
||||
get_mcp_servers() {
|
||||
local plugin_name="$1"
|
||||
local plugin_json="$REPO_ROOT/plugins/$plugin_name/.claude-plugin/plugin.json"
|
||||
|
||||
if [[ ! -f "$plugin_json" ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
# Read mcp_servers array from plugin.json
|
||||
# Returns empty if field doesn't exist or is empty
|
||||
jq -r '.mcp_servers // [] | .[]' "$plugin_json" 2>/dev/null || true
|
||||
}
|
||||
|
||||
# --- Check if plugin has any MCP servers ---
|
||||
has_mcp_servers() {
|
||||
local plugin_name="$1"
|
||||
local servers
|
||||
servers=$(get_mcp_servers "$plugin_name")
|
||||
[[ -n "$servers" ]]
|
||||
}
|
||||
|
||||
# --- Update .mcp.json ---
|
||||
update_mcp_json() {
|
||||
local plugin_name="$1"
|
||||
local target_path="$2"
|
||||
local mcp_json="$target_path/.mcp.json"
|
||||
|
||||
# Get MCP servers for this plugin
|
||||
local mcp_servers
|
||||
mcp_servers=$(get_mcp_servers "$plugin_name")
|
||||
|
||||
if [[ -z "$mcp_servers" ]]; then
|
||||
log_skip "Plugin '$plugin_name' has no MCP servers - skipping .mcp.json update"
|
||||
SKIPPED+=(".mcp.json: No MCP servers for $plugin_name")
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Create .mcp.json if it doesn't exist
|
||||
if [[ ! -f "$mcp_json" ]]; then
|
||||
log_info "Creating new .mcp.json"
|
||||
echo '{"mcpServers":{}}' > "$mcp_json"
|
||||
CHANGES_MADE+=("Created .mcp.json")
|
||||
fi
|
||||
|
||||
# Add each MCP server
|
||||
local servers_added=0
|
||||
while IFS= read -r server_name; do
|
||||
[[ -z "$server_name" ]] && continue
|
||||
|
||||
local mcp_server_path="$REPO_ROOT/mcp-servers/$server_name/run.sh"
|
||||
|
||||
# Verify server exists
|
||||
if [[ ! -f "$mcp_server_path" ]]; then
|
||||
log_warning "MCP server '$server_name' not found at $mcp_server_path"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Check if entry already exists
|
||||
if jq -e ".mcpServers[\"$server_name\"]" "$mcp_json" > /dev/null 2>&1; then
|
||||
log_skip "MCP server '$server_name' already in .mcp.json"
|
||||
SKIPPED+=(".mcp.json: $server_name already present")
|
||||
continue
|
||||
fi
|
||||
|
||||
# Add MCP server entry
|
||||
log_info "Adding MCP server '$server_name' to .mcp.json"
|
||||
local tmp_file=$(mktemp)
|
||||
jq ".mcpServers[\"$server_name\"] = {\"command\": \"$mcp_server_path\", \"args\": []}" "$mcp_json" > "$tmp_file"
|
||||
mv "$tmp_file" "$mcp_json"
|
||||
|
||||
CHANGES_MADE+=("Added $server_name to .mcp.json")
|
||||
MCP_SERVERS_INSTALLED+=("$server_name")
|
||||
log_success "Added MCP server entry for '$server_name'"
|
||||
((++servers_added))
|
||||
done <<< "$mcp_servers"
|
||||
}
|
||||
|
||||
# --- Update CLAUDE.md ---
|
||||
update_claude_md() {
|
||||
local plugin_name="$1"
|
||||
local target_path="$2"
|
||||
local target_claude_md="$target_path/CLAUDE.md"
|
||||
local integration_file="$REPO_ROOT/plugins/$plugin_name/claude-md-integration.md"
|
||||
|
||||
# Check if integration file exists
|
||||
if [[ ! -f "$integration_file" ]]; then
|
||||
log_skip "No claude-md-integration.md for plugin '$plugin_name'"
|
||||
SKIPPED+=("CLAUDE.md: No integration snippet for $plugin_name")
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Create CLAUDE.md if it doesn't exist
|
||||
if [[ ! -f "$target_claude_md" ]]; then
|
||||
log_info "Creating new CLAUDE.md"
|
||||
cat > "$target_claude_md" << 'EOF'
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code when working with code in this repository.
|
||||
|
||||
EOF
|
||||
CHANGES_MADE+=("Created CLAUDE.md")
|
||||
fi
|
||||
|
||||
# Check if already integrated using HTML comment marker (preferred)
|
||||
local begin_marker="<!-- BEGIN marketplace-plugin: $plugin_name -->"
|
||||
if grep -qF "$begin_marker" "$target_claude_md" 2>/dev/null; then
|
||||
log_skip "Plugin '$plugin_name' integration already in CLAUDE.md"
|
||||
SKIPPED+=("CLAUDE.md: $plugin_name already present")
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Fallback: check for legacy header format (backward compatibility)
|
||||
if grep -qE "^# ${plugin_name}( Plugin)? -? ?CLAUDE\.md Integration" "$target_claude_md" 2>/dev/null; then
|
||||
log_skip "Plugin '$plugin_name' integration already in CLAUDE.md (legacy format)"
|
||||
SKIPPED+=("CLAUDE.md: $plugin_name already present")
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Read integration content
|
||||
local integration_content
|
||||
integration_content=$(cat "$integration_file")
|
||||
|
||||
# Check for or create Marketplace Plugin Integration section
|
||||
local section_header="## Marketplace Plugin Integration"
|
||||
|
||||
if ! grep -qF "$section_header" "$target_claude_md"; then
|
||||
log_info "Creating '$section_header' section"
|
||||
echo "" >> "$target_claude_md"
|
||||
echo "$section_header" >> "$target_claude_md"
|
||||
echo "" >> "$target_claude_md"
|
||||
echo "The following plugins are installed from the leo-claude-mktplace:" >> "$target_claude_md"
|
||||
echo "" >> "$target_claude_md"
|
||||
fi
|
||||
|
||||
# Append integration content with HTML comment markers
|
||||
log_info "Adding '$plugin_name' integration to CLAUDE.md"
|
||||
local end_marker="<!-- END marketplace-plugin: $plugin_name -->"
|
||||
|
||||
echo "" >> "$target_claude_md"
|
||||
echo "---" >> "$target_claude_md"
|
||||
echo "" >> "$target_claude_md"
|
||||
echo "$begin_marker" >> "$target_claude_md"
|
||||
echo "" >> "$target_claude_md"
|
||||
echo "$integration_content" >> "$target_claude_md"
|
||||
echo "" >> "$target_claude_md"
|
||||
echo "$end_marker" >> "$target_claude_md"
|
||||
|
||||
CHANGES_MADE+=("Added $plugin_name integration to CLAUDE.md")
|
||||
log_success "Added CLAUDE.md integration for '$plugin_name'"
|
||||
}
|
||||
|
||||
# --- Get Commands for Plugin ---
|
||||
get_plugin_commands() {
|
||||
local plugin_name="$1"
|
||||
local commands_dir="$REPO_ROOT/plugins/$plugin_name/commands"
|
||||
|
||||
if [[ ! -d "$commands_dir" ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
for cmd_file in "$commands_dir"/*.md; do
|
||||
if [[ -f "$cmd_file" ]]; then
|
||||
local cmd_name
|
||||
cmd_name=$(basename "$cmd_file" .md)
|
||||
echo " /$cmd_name"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# --- Print Summary ---
|
||||
print_summary() {
|
||||
local plugin_name="$1"
|
||||
local target_path="$2"
|
||||
|
||||
echo ""
|
||||
echo "=============================================="
|
||||
echo -e "${GREEN}Installation Summary${NC}"
|
||||
echo "=============================================="
|
||||
echo ""
|
||||
echo -e "${CYAN}Plugin:${NC} $plugin_name"
|
||||
echo -e "${CYAN}Target:${NC} $target_path"
|
||||
echo ""
|
||||
|
||||
if [[ ${#CHANGES_MADE[@]} -gt 0 ]]; then
|
||||
echo -e "${GREEN}Changes Made:${NC}"
|
||||
for change in "${CHANGES_MADE[@]}"; do
|
||||
echo " ✓ $change"
|
||||
done
|
||||
echo ""
|
||||
fi
|
||||
|
||||
if [[ ${#SKIPPED[@]} -gt 0 ]]; then
|
||||
echo -e "${YELLOW}Skipped (already present or N/A):${NC}"
|
||||
for skip in "${SKIPPED[@]}"; do
|
||||
echo " - $skip"
|
||||
done
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Show available commands
|
||||
echo -e "${CYAN}Commands Now Available:${NC}"
|
||||
local commands
|
||||
commands=$(get_plugin_commands "$plugin_name")
|
||||
if [[ -n "$commands" ]]; then
|
||||
echo "$commands"
|
||||
else
|
||||
echo " (No commands - this plugin may be hooks-only)"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# MCP servers info
|
||||
if [[ ${#MCP_SERVERS_INSTALLED[@]} -gt 0 ]]; then
|
||||
echo -e "${CYAN}MCP Servers Installed:${NC}"
|
||||
for server in "${MCP_SERVERS_INSTALLED[@]}"; do
|
||||
echo " - $server"
|
||||
done
|
||||
echo ""
|
||||
elif has_mcp_servers "$plugin_name"; then
|
||||
echo -e "${CYAN}MCP Tools:${NC}"
|
||||
echo " This plugin includes MCP server tools. Use ToolSearch to discover them."
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Important reminder
|
||||
echo -e "${YELLOW}⚠️ IMPORTANT:${NC}"
|
||||
echo " Restart your Claude Code session for changes to take effect."
|
||||
echo " The .mcp.json changes require a session restart to load MCP servers."
|
||||
echo ""
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# Main Execution
|
||||
# =============================================================================
|
||||
|
||||
# Check arguments
|
||||
if [[ $# -lt 2 ]]; then
|
||||
usage
|
||||
fi
|
||||
|
||||
PLUGIN_NAME="$1"
|
||||
TARGET_PATH="$2"
|
||||
|
||||
# Resolve target path to absolute
|
||||
TARGET_PATH=$(cd "$TARGET_PATH" 2>/dev/null && pwd || echo "$TARGET_PATH")
|
||||
|
||||
echo ""
|
||||
echo "=============================================="
|
||||
echo -e "${BLUE}Installing Plugin: $PLUGIN_NAME${NC}"
|
||||
echo "=============================================="
|
||||
echo ""
|
||||
|
||||
# Run checks
|
||||
check_prerequisites
|
||||
validate_plugin "$PLUGIN_NAME"
|
||||
validate_target "$TARGET_PATH"
|
||||
|
||||
echo ""
|
||||
|
||||
# Perform installation
|
||||
update_mcp_json "$PLUGIN_NAME" "$TARGET_PATH"
|
||||
update_claude_md "$PLUGIN_NAME" "$TARGET_PATH"
|
||||
|
||||
# Print summary
|
||||
print_summary "$PLUGIN_NAME" "$TARGET_PATH"
|
||||
@@ -1,322 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# =============================================================================
|
||||
# list-installed.sh - Show installed marketplace plugins in a project
|
||||
# =============================================================================
|
||||
#
|
||||
# Usage: ./scripts/list-installed.sh <target-project-path>
|
||||
#
|
||||
# This script:
|
||||
# 1. Checks .mcp.json for MCP server entries from this marketplace
|
||||
# 2. Checks CLAUDE.md for plugin integration sections
|
||||
# 3. Reports which plugins are installed
|
||||
#
|
||||
# Examples:
|
||||
# ./scripts/list-installed.sh ~/projects/personal-portfolio
|
||||
# ./scripts/list-installed.sh .
|
||||
#
|
||||
# =============================================================================
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||
|
||||
# --- Color Definitions ---
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
CYAN='\033[0;36m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# --- Logging Functions ---
|
||||
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
|
||||
log_success() { echo -e "${GREEN}[OK]${NC} $1"; }
|
||||
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
||||
log_warning() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
||||
|
||||
# --- Usage ---
|
||||
usage() {
|
||||
echo "Usage: $0 <target-project-path>"
|
||||
echo ""
|
||||
echo "Show which marketplace plugins are installed in a project."
|
||||
echo ""
|
||||
echo "Arguments:"
|
||||
echo " target-project-path Path to the target project (absolute or relative)"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " $0 ~/projects/personal-portfolio"
|
||||
echo " $0 ."
|
||||
exit 1
|
||||
}
|
||||
|
||||
# --- Prerequisite Check ---
|
||||
check_prerequisites() {
|
||||
if ! command -v jq &> /dev/null; then
|
||||
log_error "jq is required but not installed."
|
||||
echo "Install with: sudo apt install jq"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# --- Get Available Plugins ---
|
||||
get_available_plugins() {
|
||||
for dir in "$REPO_ROOT"/plugins/*/; do
|
||||
if [[ -d "$dir" ]]; then
|
||||
basename "$dir"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# --- Get MCP Servers for Plugin ---
|
||||
# Reads the mcp_servers array from plugin.json
|
||||
get_mcp_servers() {
|
||||
local plugin_name="$1"
|
||||
local plugin_json="$REPO_ROOT/plugins/$plugin_name/.claude-plugin/plugin.json"
|
||||
|
||||
if [[ ! -f "$plugin_json" ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
jq -r '.mcp_servers // [] | .[]' "$plugin_json" 2>/dev/null || true
|
||||
}
|
||||
|
||||
# --- Check if plugin has any MCP servers defined ---
|
||||
has_mcp_servers() {
|
||||
local plugin_name="$1"
|
||||
local servers
|
||||
servers=$(get_mcp_servers "$plugin_name")
|
||||
[[ -n "$servers" ]]
|
||||
}
|
||||
|
||||
# --- Check MCP Installation ---
|
||||
check_mcp_installed() {
|
||||
local plugin_name="$1"
|
||||
local target_path="$2"
|
||||
local mcp_json="$target_path/.mcp.json"
|
||||
|
||||
if [[ ! -f "$mcp_json" ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Get MCP servers for this plugin from plugin.json
|
||||
local mcp_servers
|
||||
mcp_servers=$(get_mcp_servers "$plugin_name")
|
||||
|
||||
if [[ -z "$mcp_servers" ]]; then
|
||||
# Plugin has no MCP servers defined, so MCP check passes
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Check if ALL required MCP servers are present
|
||||
while IFS= read -r server_name; do
|
||||
[[ -z "$server_name" ]] && continue
|
||||
|
||||
if ! jq -e ".mcpServers[\"$server_name\"]" "$mcp_json" > /dev/null 2>&1; then
|
||||
# Also check if any entry points to this marketplace's mcp-servers
|
||||
if ! grep -q "mcp-servers/$server_name" "$mcp_json" 2>/dev/null; then
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
done <<< "$mcp_servers"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# --- Check CLAUDE.md Integration ---
|
||||
check_claude_md_installed() {
|
||||
local plugin_name="$1"
|
||||
local target_path="$2"
|
||||
local target_claude_md="$target_path/CLAUDE.md"
|
||||
|
||||
if [[ ! -f "$target_claude_md" ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check for HTML comment marker (preferred, new format)
|
||||
local begin_marker="<!-- BEGIN marketplace-plugin: $plugin_name -->"
|
||||
if grep -qF "$begin_marker" "$target_claude_md" 2>/dev/null; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Fallback: check for legacy header format
|
||||
if grep -qE "^# ${plugin_name}( Plugin)? -? ?CLAUDE\.md Integration" "$target_claude_md" 2>/dev/null; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# --- Get Plugin Version ---
|
||||
get_plugin_version() {
|
||||
local plugin_name="$1"
|
||||
local plugin_json="$REPO_ROOT/plugins/$plugin_name/.claude-plugin/plugin.json"
|
||||
|
||||
if [[ -f "$plugin_json" ]]; then
|
||||
jq -r '.version // "unknown"' "$plugin_json"
|
||||
else
|
||||
echo "unknown"
|
||||
fi
|
||||
}
|
||||
|
||||
# --- Get Plugin Description ---
|
||||
get_plugin_description() {
|
||||
local plugin_name="$1"
|
||||
local plugin_json="$REPO_ROOT/plugins/$plugin_name/.claude-plugin/plugin.json"
|
||||
|
||||
if [[ -f "$plugin_json" ]]; then
|
||||
jq -r '.description // "No description"' "$plugin_json" | cut -c1-60
|
||||
else
|
||||
echo "No description"
|
||||
fi
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# Main Execution
|
||||
# =============================================================================
|
||||
|
||||
# Check arguments
|
||||
if [[ $# -lt 1 ]]; then
|
||||
usage
|
||||
fi
|
||||
|
||||
TARGET_PATH="$1"
|
||||
|
||||
# Resolve target path to absolute
|
||||
if [[ -d "$TARGET_PATH" ]]; then
|
||||
TARGET_PATH=$(cd "$TARGET_PATH" && pwd)
|
||||
else
|
||||
log_error "Target project path does not exist: $TARGET_PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
check_prerequisites
|
||||
|
||||
echo ""
|
||||
echo "=============================================="
|
||||
echo -e "${BLUE}Installed Plugins: $(basename "$TARGET_PATH")${NC}"
|
||||
echo "=============================================="
|
||||
echo -e "${CYAN}Target:${NC} $TARGET_PATH"
|
||||
echo ""
|
||||
|
||||
# Collect results
|
||||
declare -A INSTALLED_MCP
|
||||
declare -A INSTALLED_CLAUDE_MD
|
||||
INSTALLED_PLUGINS=()
|
||||
PARTIAL_PLUGINS=()
|
||||
NOT_INSTALLED=()
|
||||
|
||||
# Check each available plugin
|
||||
for plugin in $(get_available_plugins); do
|
||||
mcp_installed=false
|
||||
claude_installed=false
|
||||
needs_mcp=false
|
||||
|
||||
# Check if plugin has MCP servers defined
|
||||
if has_mcp_servers "$plugin"; then
|
||||
needs_mcp=true
|
||||
fi
|
||||
|
||||
# Check MCP installation
|
||||
if check_mcp_installed "$plugin" "$TARGET_PATH"; then
|
||||
mcp_installed=true
|
||||
INSTALLED_MCP[$plugin]=true
|
||||
fi
|
||||
|
||||
# Check CLAUDE.md integration
|
||||
if check_claude_md_installed "$plugin" "$TARGET_PATH"; then
|
||||
claude_installed=true
|
||||
INSTALLED_CLAUDE_MD[$plugin]=true
|
||||
fi
|
||||
|
||||
# Categorize
|
||||
if $claude_installed; then
|
||||
if $needs_mcp; then
|
||||
if $mcp_installed; then
|
||||
INSTALLED_PLUGINS+=("$plugin")
|
||||
else
|
||||
PARTIAL_PLUGINS+=("$plugin")
|
||||
fi
|
||||
else
|
||||
# Plugins without MCP servers just need CLAUDE.md
|
||||
INSTALLED_PLUGINS+=("$plugin")
|
||||
fi
|
||||
elif $mcp_installed && $needs_mcp; then
|
||||
# Has MCP but missing CLAUDE.md
|
||||
PARTIAL_PLUGINS+=("$plugin")
|
||||
else
|
||||
NOT_INSTALLED+=("$plugin")
|
||||
fi
|
||||
done
|
||||
|
||||
# Print fully installed plugins
|
||||
if [[ ${#INSTALLED_PLUGINS[@]} -gt 0 ]]; then
|
||||
echo -e "${GREEN}✓ Fully Installed:${NC}"
|
||||
echo ""
|
||||
printf " %-24s %-10s %s\n" "PLUGIN" "VERSION" "DESCRIPTION"
|
||||
printf " %-24s %-10s %s\n" "------" "-------" "-----------"
|
||||
for plugin in "${INSTALLED_PLUGINS[@]}"; do
|
||||
version=$(get_plugin_version "$plugin")
|
||||
desc=$(get_plugin_description "$plugin")
|
||||
printf " %-24s %-10s %s\n" "$plugin" "$version" "$desc"
|
||||
done
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Print partially installed plugins
|
||||
if [[ ${#PARTIAL_PLUGINS[@]} -gt 0 ]]; then
|
||||
echo -e "${YELLOW}⚠ Partially Installed:${NC}"
|
||||
echo ""
|
||||
for plugin in "${PARTIAL_PLUGINS[@]}"; do
|
||||
version=$(get_plugin_version "$plugin")
|
||||
echo " $plugin (v$version)"
|
||||
if [[ -v INSTALLED_MCP[$plugin] ]]; then
|
||||
echo " ✓ MCP server configured in .mcp.json"
|
||||
else
|
||||
# Show which MCP servers are missing
|
||||
mcp_servers=$(get_mcp_servers "$plugin")
|
||||
if [[ -n "$mcp_servers" ]]; then
|
||||
echo " ✗ MCP server(s) NOT in .mcp.json: $mcp_servers"
|
||||
fi
|
||||
fi
|
||||
if [[ -v INSTALLED_CLAUDE_MD[$plugin] ]]; then
|
||||
echo " ✓ Integration in CLAUDE.md"
|
||||
else
|
||||
echo " ✗ Integration NOT in CLAUDE.md"
|
||||
fi
|
||||
echo ""
|
||||
done
|
||||
echo " Run install-plugin.sh to complete installation."
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Print available but not installed
|
||||
if [[ ${#NOT_INSTALLED[@]} -gt 0 ]]; then
|
||||
echo -e "${BLUE}○ Available (not installed):${NC}"
|
||||
echo ""
|
||||
for plugin in "${NOT_INSTALLED[@]}"; do
|
||||
version=$(get_plugin_version "$plugin")
|
||||
desc=$(get_plugin_description "$plugin")
|
||||
printf " %-24s %-10s %s\n" "$plugin" "$version" "$desc"
|
||||
done
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Summary
|
||||
echo "----------------------------------------------"
|
||||
total_available=$(get_available_plugins | wc -l)
|
||||
total_installed=${#INSTALLED_PLUGINS[@]}
|
||||
total_partial=${#PARTIAL_PLUGINS[@]}
|
||||
|
||||
echo -e "Total: ${GREEN}$total_installed installed${NC}"
|
||||
if [[ $total_partial -gt 0 ]]; then
|
||||
echo -e " ${YELLOW}$total_partial partial${NC}"
|
||||
fi
|
||||
echo " $((total_available - total_installed - total_partial)) available"
|
||||
echo ""
|
||||
|
||||
# Install hint
|
||||
if [[ ${#NOT_INSTALLED[@]} -gt 0 ]]; then
|
||||
echo "To install a plugin:"
|
||||
echo " $SCRIPT_DIR/install-plugin.sh <plugin-name> $TARGET_PATH"
|
||||
echo ""
|
||||
fi
|
||||
@@ -1,363 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# =============================================================================
|
||||
# uninstall-plugin.sh - Remove marketplace plugin from a consumer project
|
||||
# =============================================================================
|
||||
#
|
||||
# Usage: ./scripts/uninstall-plugin.sh <plugin-name> <target-project-path>
|
||||
#
|
||||
# This script:
|
||||
# 1. Removes MCP server entries from target project's .mcp.json
|
||||
# 2. Removes CLAUDE.md integration section for the plugin
|
||||
# 3. Is idempotent (safe to run multiple times)
|
||||
#
|
||||
# Examples:
|
||||
# ./scripts/uninstall-plugin.sh data-platform ~/projects/personal-portfolio
|
||||
# ./scripts/uninstall-plugin.sh projman /home/user/my-project
|
||||
#
|
||||
# =============================================================================
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||
|
||||
# --- Color Definitions ---
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
CYAN='\033[0;36m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# --- Logging Functions ---
|
||||
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
|
||||
log_success() { echo -e "${GREEN}[OK]${NC} $1"; }
|
||||
log_skip() { echo -e "${YELLOW}[SKIP]${NC} $1"; }
|
||||
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
||||
log_warning() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
||||
|
||||
# --- Track Changes ---
|
||||
CHANGES_MADE=()
|
||||
SKIPPED=()
|
||||
|
||||
# --- Usage ---
|
||||
usage() {
|
||||
echo "Usage: $0 <plugin-name> <target-project-path>"
|
||||
echo ""
|
||||
echo "Remove a marketplace plugin from a consumer project."
|
||||
echo ""
|
||||
echo "Arguments:"
|
||||
echo " plugin-name Name of the plugin (e.g., data-platform, viz-platform, projman)"
|
||||
echo " target-project-path Path to the target project (absolute or relative)"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " $0 data-platform ~/projects/personal-portfolio"
|
||||
echo " $0 projman /home/user/my-project"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# --- Prerequisite Check ---
|
||||
check_prerequisites() {
|
||||
if ! command -v jq &> /dev/null; then
|
||||
log_error "jq is required but not installed."
|
||||
echo "Install with: sudo apt install jq"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# --- Validate Target Project ---
|
||||
validate_target() {
|
||||
local target_path="$1"
|
||||
|
||||
if [[ ! -d "$target_path" ]]; then
|
||||
log_error "Target project path does not exist: $target_path"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_success "Target project found: $target_path"
|
||||
}
|
||||
|
||||
# --- Get MCP Servers for Plugin ---
|
||||
# Reads the mcp_servers array from plugin.json
|
||||
# Returns newline-separated list of MCP server names, or empty if none
|
||||
get_mcp_servers() {
|
||||
local plugin_name="$1"
|
||||
local plugin_json="$REPO_ROOT/plugins/$plugin_name/.claude-plugin/plugin.json"
|
||||
|
||||
if [[ ! -f "$plugin_json" ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
# Read mcp_servers array from plugin.json
|
||||
# Returns empty if field doesn't exist or is empty
|
||||
jq -r '.mcp_servers // [] | .[]' "$plugin_json" 2>/dev/null || true
|
||||
}
|
||||
|
||||
# --- Remove from .mcp.json ---
|
||||
remove_from_mcp_json() {
|
||||
local plugin_name="$1"
|
||||
local target_path="$2"
|
||||
local mcp_json="$target_path/.mcp.json"
|
||||
|
||||
# Check if .mcp.json exists
|
||||
if [[ ! -f "$mcp_json" ]]; then
|
||||
log_skip "No .mcp.json found - nothing to remove"
|
||||
SKIPPED+=(".mcp.json: File does not exist")
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Get MCP servers for this plugin
|
||||
local mcp_servers
|
||||
mcp_servers=$(get_mcp_servers "$plugin_name")
|
||||
|
||||
if [[ -z "$mcp_servers" ]]; then
|
||||
# Fallback: try to remove entry with plugin name (backward compatibility)
|
||||
if jq -e ".mcpServers[\"$plugin_name\"]" "$mcp_json" > /dev/null 2>&1; then
|
||||
log_info "Removing MCP server '$plugin_name' from .mcp.json"
|
||||
local tmp_file=$(mktemp)
|
||||
jq "del(.mcpServers[\"$plugin_name\"])" "$mcp_json" > "$tmp_file"
|
||||
mv "$tmp_file" "$mcp_json"
|
||||
CHANGES_MADE+=("Removed $plugin_name from .mcp.json")
|
||||
log_success "Removed MCP server entry for '$plugin_name'"
|
||||
else
|
||||
log_skip "Plugin '$plugin_name' has no MCP servers configured"
|
||||
SKIPPED+=(".mcp.json: No MCP servers for $plugin_name")
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Remove each MCP server
|
||||
local servers_removed=0
|
||||
while IFS= read -r server_name; do
|
||||
[[ -z "$server_name" ]] && continue
|
||||
|
||||
# Check if entry exists
|
||||
if ! jq -e ".mcpServers[\"$server_name\"]" "$mcp_json" > /dev/null 2>&1; then
|
||||
log_skip "MCP server '$server_name' not in .mcp.json"
|
||||
SKIPPED+=(".mcp.json: $server_name not present")
|
||||
continue
|
||||
fi
|
||||
|
||||
# Remove MCP server entry
|
||||
log_info "Removing MCP server '$server_name' from .mcp.json"
|
||||
local tmp_file=$(mktemp)
|
||||
jq "del(.mcpServers[\"$server_name\"])" "$mcp_json" > "$tmp_file"
|
||||
mv "$tmp_file" "$mcp_json"
|
||||
|
||||
CHANGES_MADE+=("Removed $server_name from .mcp.json")
|
||||
log_success "Removed MCP server entry for '$server_name'"
|
||||
((++servers_removed))
|
||||
done <<< "$mcp_servers"
|
||||
}
|
||||
|
||||
# --- Remove from CLAUDE.md ---
|
||||
remove_from_claude_md() {
|
||||
local plugin_name="$1"
|
||||
local target_path="$2"
|
||||
local target_claude_md="$target_path/CLAUDE.md"
|
||||
|
||||
# Check if CLAUDE.md exists
|
||||
if [[ ! -f "$target_claude_md" ]]; then
|
||||
log_skip "No CLAUDE.md found - nothing to remove"
|
||||
SKIPPED+=("CLAUDE.md: File does not exist")
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Try HTML comment markers first (preferred method)
|
||||
local begin_marker="<!-- BEGIN marketplace-plugin: $plugin_name -->"
|
||||
local end_marker="<!-- END marketplace-plugin: $plugin_name -->"
|
||||
|
||||
if grep -qF "$begin_marker" "$target_claude_md" 2>/dev/null; then
|
||||
log_info "Removing '$plugin_name' section from CLAUDE.md (using markers)"
|
||||
|
||||
# Remove everything between markers (inclusive) and preceding ---
|
||||
local tmp_file=$(mktemp)
|
||||
awk -v begin="$begin_marker" -v end="$end_marker" '
|
||||
BEGIN { skip = 0; prev_hr = 0; buffer = "" }
|
||||
{
|
||||
is_hr = /^---[[:space:]]*$/
|
||||
|
||||
if ($0 == begin) {
|
||||
skip = 1
|
||||
# If previous line was ---, dont print it
|
||||
if (prev_hr) {
|
||||
buffer = ""
|
||||
}
|
||||
next
|
||||
}
|
||||
|
||||
if (skip) {
|
||||
if ($0 == end) {
|
||||
skip = 0
|
||||
}
|
||||
next
|
||||
}
|
||||
|
||||
# Print buffered content
|
||||
if (buffer != "") {
|
||||
print buffer
|
||||
}
|
||||
|
||||
# Buffer current line (in case its --- before a marker)
|
||||
buffer = $0
|
||||
prev_hr = is_hr
|
||||
}
|
||||
END {
|
||||
# Print final buffered content
|
||||
if (buffer != "") {
|
||||
print buffer
|
||||
}
|
||||
}
|
||||
' "$target_claude_md" > "$tmp_file"
|
||||
|
||||
# Clean up multiple consecutive blank lines
|
||||
awk 'NF{blank=0} !NF{blank++} blank<=2' "$tmp_file" > "${tmp_file}.clean"
|
||||
mv "${tmp_file}.clean" "$target_claude_md"
|
||||
rm -f "$tmp_file"
|
||||
|
||||
CHANGES_MADE+=("Removed $plugin_name section from CLAUDE.md")
|
||||
log_success "Removed CLAUDE.md section for '$plugin_name'"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Fallback: try legacy header-based detection
|
||||
local section_header
|
||||
section_header=$(grep -E "^# ${plugin_name}( Plugin)? -? ?CLAUDE\.md Integration" "$target_claude_md" 2>/dev/null | head -1)
|
||||
|
||||
if [[ -z "$section_header" ]]; then
|
||||
log_skip "Plugin '$plugin_name' section not found in CLAUDE.md"
|
||||
SKIPPED+=("CLAUDE.md: $plugin_name section not found")
|
||||
return 0
|
||||
fi
|
||||
|
||||
log_info "Removing '$plugin_name' section from CLAUDE.md (legacy format)"
|
||||
|
||||
# Create temp file and use awk to remove section
|
||||
local tmp_file=$(mktemp)
|
||||
|
||||
awk -v header="$section_header" '
|
||||
BEGIN { skip = 0; found = 0; in_code_block = 0 }
|
||||
{
|
||||
# Track code blocks (``` markers)
|
||||
if (/^```/) {
|
||||
in_code_block = !in_code_block
|
||||
}
|
||||
|
||||
# Check if this is the section header we want to remove
|
||||
if ($0 == header) {
|
||||
skip = 1
|
||||
found = 1
|
||||
next
|
||||
}
|
||||
|
||||
# Check if this is a horizontal rule (---) - only count if not in code block
|
||||
is_hr = /^---[[:space:]]*$/ && !in_code_block
|
||||
|
||||
# Check if this is a new plugin section header (only outside code blocks)
|
||||
is_new_plugin_section = /^# [a-z-]+( Plugin)? -? ?CLAUDE\.md Integration/ && !in_code_block && $0 != header
|
||||
|
||||
# Check for HTML marker (new format)
|
||||
is_begin_marker = /^<!-- BEGIN marketplace-plugin:/ && !in_code_block
|
||||
|
||||
if (skip) {
|
||||
# Stop skipping when we hit --- or a new section
|
||||
if (is_hr) {
|
||||
skip = 0
|
||||
next
|
||||
}
|
||||
if (is_new_plugin_section || is_begin_marker) {
|
||||
skip = 0
|
||||
print
|
||||
}
|
||||
next
|
||||
}
|
||||
|
||||
print
|
||||
}
|
||||
END { if (!found) exit 1 }
|
||||
' "$target_claude_md" > "$tmp_file" 2>/dev/null
|
||||
|
||||
if [[ $? -eq 0 ]]; then
|
||||
# Clean up multiple consecutive blank lines
|
||||
awk 'NF{blank=0} !NF{blank++} blank<=2' "$tmp_file" > "${tmp_file}.clean"
|
||||
mv "${tmp_file}.clean" "$target_claude_md"
|
||||
rm -f "$tmp_file"
|
||||
CHANGES_MADE+=("Removed $plugin_name section from CLAUDE.md")
|
||||
log_success "Removed CLAUDE.md section for '$plugin_name'"
|
||||
else
|
||||
rm -f "$tmp_file"
|
||||
log_skip "Could not locate exact section boundaries in CLAUDE.md"
|
||||
log_warning "You may need to manually remove the $plugin_name section"
|
||||
SKIPPED+=("CLAUDE.md: Manual removal may be needed")
|
||||
fi
|
||||
}
|
||||
|
||||
# --- Print Summary ---
|
||||
print_summary() {
|
||||
local plugin_name="$1"
|
||||
local target_path="$2"
|
||||
|
||||
echo ""
|
||||
echo "=============================================="
|
||||
echo -e "${GREEN}Uninstallation Summary${NC}"
|
||||
echo "=============================================="
|
||||
echo ""
|
||||
echo -e "${CYAN}Plugin:${NC} $plugin_name"
|
||||
echo -e "${CYAN}Target:${NC} $target_path"
|
||||
echo ""
|
||||
|
||||
if [[ ${#CHANGES_MADE[@]} -gt 0 ]]; then
|
||||
echo -e "${GREEN}Changes Made:${NC}"
|
||||
for change in "${CHANGES_MADE[@]}"; do
|
||||
echo " ✓ $change"
|
||||
done
|
||||
echo ""
|
||||
fi
|
||||
|
||||
if [[ ${#SKIPPED[@]} -gt 0 ]]; then
|
||||
echo -e "${YELLOW}Skipped (not present or N/A):${NC}"
|
||||
for skip in "${SKIPPED[@]}"; do
|
||||
echo " - $skip"
|
||||
done
|
||||
echo ""
|
||||
fi
|
||||
|
||||
if [[ ${#CHANGES_MADE[@]} -gt 0 ]]; then
|
||||
echo -e "${YELLOW}⚠️ IMPORTANT:${NC}"
|
||||
echo " Restart your Claude Code session for changes to take effect."
|
||||
echo ""
|
||||
fi
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# Main Execution
|
||||
# =============================================================================
|
||||
|
||||
# Check arguments
|
||||
if [[ $# -lt 2 ]]; then
|
||||
usage
|
||||
fi
|
||||
|
||||
PLUGIN_NAME="$1"
|
||||
TARGET_PATH="$2"
|
||||
|
||||
# Resolve target path to absolute
|
||||
TARGET_PATH=$(cd "$TARGET_PATH" 2>/dev/null && pwd || echo "$TARGET_PATH")
|
||||
|
||||
echo ""
|
||||
echo "=============================================="
|
||||
echo -e "${BLUE}Uninstalling Plugin: $PLUGIN_NAME${NC}"
|
||||
echo "=============================================="
|
||||
echo ""
|
||||
|
||||
# Run checks
|
||||
check_prerequisites
|
||||
validate_target "$TARGET_PATH"
|
||||
|
||||
echo ""
|
||||
|
||||
# Perform uninstallation
|
||||
remove_from_mcp_json "$PLUGIN_NAME" "$TARGET_PATH"
|
||||
remove_from_claude_md "$PLUGIN_NAME" "$TARGET_PATH"
|
||||
|
||||
# Print summary
|
||||
print_summary "$PLUGIN_NAME" "$TARGET_PATH"
|
||||
Reference in New Issue
Block a user