development #394
32
CHANGELOG.md
32
CHANGELOG.md
@@ -4,6 +4,38 @@ 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/).
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
|
|
||||||
|
## [Unreleased]
|
||||||
|
|
||||||
|
### 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.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## [5.8.0] - 2026-02-02
|
## [5.8.0] - 2026-02-02
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
@@ -415,6 +415,87 @@ 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)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Automatic Validation Features
|
## Automatic Validation Features
|
||||||
|
|
||||||
### API Validation
|
### API Validation
|
||||||
|
|||||||
337
scripts/install-plugin.sh
Executable file
337
scripts/install-plugin.sh
Executable file
@@ -0,0 +1,337 @@
|
|||||||
|
#!/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 entry (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=()
|
||||||
|
|
||||||
|
# --- 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
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Check if MCP Server Exists for Plugin ---
|
||||||
|
has_mcp_server() {
|
||||||
|
local plugin_name="$1"
|
||||||
|
local mcp_dir="$REPO_ROOT/mcp-servers/$plugin_name"
|
||||||
|
|
||||||
|
if [[ -d "$mcp_dir" && -f "$mcp_dir/run.sh" ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Update .mcp.json ---
|
||||||
|
update_mcp_json() {
|
||||||
|
local plugin_name="$1"
|
||||||
|
local target_path="$2"
|
||||||
|
local mcp_json="$target_path/.mcp.json"
|
||||||
|
local mcp_server_path="$REPO_ROOT/mcp-servers/$plugin_name/run.sh"
|
||||||
|
|
||||||
|
# Check if plugin has MCP server
|
||||||
|
if ! has_mcp_server "$plugin_name"; then
|
||||||
|
log_skip "Plugin '$plugin_name' has no MCP server - skipping .mcp.json update"
|
||||||
|
SKIPPED+=(".mcp.json: No MCP server 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
|
||||||
|
|
||||||
|
# Check if entry already exists
|
||||||
|
if jq -e ".mcpServers[\"$plugin_name\"]" "$mcp_json" > /dev/null 2>&1; then
|
||||||
|
log_skip "MCP server '$plugin_name' already in .mcp.json"
|
||||||
|
SKIPPED+=(".mcp.json: $plugin_name already present")
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add MCP server entry
|
||||||
|
log_info "Adding MCP server '$plugin_name' to .mcp.json"
|
||||||
|
local tmp_file=$(mktemp)
|
||||||
|
jq ".mcpServers[\"$plugin_name\"] = {\"command\": \"$mcp_server_path\", \"args\": []}" "$mcp_json" > "$tmp_file"
|
||||||
|
mv "$tmp_file" "$mcp_json"
|
||||||
|
|
||||||
|
CHANGES_MADE+=("Added $plugin_name to .mcp.json")
|
||||||
|
log_success "Added MCP server entry for '$plugin_name'"
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- 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
|
||||||
|
|
||||||
|
# Read integration content
|
||||||
|
local integration_content
|
||||||
|
integration_content=$(cat "$integration_file")
|
||||||
|
|
||||||
|
# Extract the first line (# header) to use as marker for detection
|
||||||
|
local header_marker
|
||||||
|
header_marker=$(head -1 "$integration_file")
|
||||||
|
|
||||||
|
# Check if already integrated - look for the integration file's header
|
||||||
|
# Handles both formats: "# {name} Plugin - CLAUDE.md Integration" and "# {name} CLAUDE.md Integration"
|
||||||
|
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"
|
||||||
|
SKIPPED+=("CLAUDE.md: $plugin_name already present")
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 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
|
||||||
|
log_info "Adding '$plugin_name' integration to CLAUDE.md"
|
||||||
|
echo "" >> "$target_claude_md"
|
||||||
|
echo "---" >> "$target_claude_md"
|
||||||
|
echo "" >> "$target_claude_md"
|
||||||
|
echo "$integration_content" >> "$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 tools reminder
|
||||||
|
if has_mcp_server "$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"
|
||||||
293
scripts/list-installed.sh
Executable file
293
scripts/list-installed.sh
Executable file
@@ -0,0 +1,293 @@
|
|||||||
|
#!/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 Plugins with MCP Servers ---
|
||||||
|
get_mcp_plugins() {
|
||||||
|
for dir in "$REPO_ROOT"/mcp-servers/*/; do
|
||||||
|
if [[ -d "$dir" && -f "$dir/run.sh" ]]; then
|
||||||
|
basename "$dir"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- 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
|
||||||
|
|
||||||
|
# Check if this plugin's MCP server is referenced
|
||||||
|
if jq -e ".mcpServers[\"$plugin_name\"]" "$mcp_json" > /dev/null 2>&1; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Also check if any entry points to this marketplace's mcp-servers
|
||||||
|
if grep -q "leo-claude-mktplace.*mcp-servers/$plugin_name" "$mcp_json" 2>/dev/null || \
|
||||||
|
grep -q "claude-plugins-work.*mcp-servers/$plugin_name" "$mcp_json" 2>/dev/null; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- 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
|
||||||
|
|
||||||
|
# Look for plugin-specific headers that install-plugin.sh adds
|
||||||
|
# Formats vary by plugin:
|
||||||
|
# "# {plugin-name} Plugin - CLAUDE.md Integration"
|
||||||
|
# "# {plugin-name} CLAUDE.md Integration"
|
||||||
|
# Use regex to match both patterns
|
||||||
|
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
|
||||||
|
has_mcp_server=false
|
||||||
|
|
||||||
|
# Check if plugin has MCP server
|
||||||
|
if [[ -d "$REPO_ROOT/mcp-servers/$plugin" ]]; then
|
||||||
|
has_mcp_server=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check MCP installation (only if plugin has MCP server)
|
||||||
|
if $has_mcp_server && 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 $mcp_installed || $claude_installed; then
|
||||||
|
if $has_mcp_server; then
|
||||||
|
if $mcp_installed && $claude_installed; then
|
||||||
|
INSTALLED_PLUGINS+=("$plugin")
|
||||||
|
else
|
||||||
|
PARTIAL_PLUGINS+=("$plugin")
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# Plugins without MCP servers just need CLAUDE.md
|
||||||
|
if $claude_installed; then
|
||||||
|
INSTALLED_PLUGINS+=("$plugin")
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
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
|
||||||
|
echo " ✗ MCP server NOT in .mcp.json"
|
||||||
|
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
|
||||||
266
scripts/uninstall-plugin.sh
Executable file
266
scripts/uninstall-plugin.sh
Executable file
@@ -0,0 +1,266 @@
|
|||||||
|
#!/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 entry 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"
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- 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
|
||||||
|
|
||||||
|
# Check if entry exists
|
||||||
|
if ! jq -e ".mcpServers[\"$plugin_name\"]" "$mcp_json" > /dev/null 2>&1; then
|
||||||
|
log_skip "MCP server '$plugin_name' not in .mcp.json"
|
||||||
|
SKIPPED+=(".mcp.json: $plugin_name not present")
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Remove MCP server entry
|
||||||
|
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'"
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- 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
|
||||||
|
|
||||||
|
# Look for the plugin section header (handles multiple formats)
|
||||||
|
# Formats: "# {plugin-name} Plugin - CLAUDE.md Integration" or "# {plugin-name} CLAUDE.md Integration"
|
||||||
|
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"
|
||||||
|
|
||||||
|
# Create temp file and use awk to remove section
|
||||||
|
# Remove from header to next "---" divider or next plugin header
|
||||||
|
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)
|
||||||
|
# Patterns: "# {name} Plugin - CLAUDE.md Integration" or "# {name} CLAUDE.md Integration"
|
||||||
|
is_new_plugin_section = /^# [a-z-]+( Plugin)? -? ?CLAUDE\.md Integration/ && !in_code_block && $0 != header
|
||||||
|
|
||||||
|
if (skip) {
|
||||||
|
# Stop skipping when we hit --- (outside code block) or a new plugin section
|
||||||
|
if (is_hr) {
|
||||||
|
# This --- ends the section we are removing, skip it too
|
||||||
|
skip = 0
|
||||||
|
next
|
||||||
|
}
|
||||||
|
if (is_new_plugin_section) {
|
||||||
|
# New plugin section starts, stop skipping and print it
|
||||||
|
skip = 0
|
||||||
|
print
|
||||||
|
}
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
# Not skipping - print the line
|
||||||
|
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