#!/usr/bin/env bash # Install Claude Code plugins from brain manifest # Adds marketplaces, installs plugins, warns on SHA mismatch. # # CORRECTION B: real Claude CLI subcommand shape is # `claude plugin marketplace add ` (NOT `claude marketplace add`) # `claude plugin marketplace list` # `claude plugin install ` # `claude plugin info --json` # Phase 0 discovery confirmed: `marketplace` is a child of `plugin`, not a # top-level subcommand. The plan originally had the wrong shape. # # Usage: install-plugins.sh --marketplaces= --manifest= set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" source "$SCRIPT_DIR/common.sh" marketplaces="" manifest="" while [ $# -gt 0 ]; do case "$1" in --marketplaces=*) marketplaces="${1#--marketplaces=}" ;; --manifest=*) manifest="${1#--manifest=}" ;; *) log_error "Unknown arg: $1"; exit 1 ;; esac shift done [ -f "$marketplaces" ] || { log_error "Marketplaces file: $marketplaces not found"; exit 1; } [ -f "$manifest" ] || { log_error "Manifest file: $manifest not found"; exit 1; } require_cmd jq || exit 1 # Fallback: if `claude` CLI is not in PATH (common on this Windows machine where # the VSCode-extension binary lives outside %PATH%), log instructions and exit 0 # so installer can continue with manual JSON edits. if ! command -v claude >/dev/null 2>&1; then log_warn "claude CLI not found — fallback: edit JSON configs manually and restart" log_info "Required edits:" log_info " 1. Copy $marketplaces -> ~/.claude/plugins/known_marketplaces.json" log_info " 2. Copy $manifest -> ~/.claude/plugins/installed_plugins.json" log_info " 3. Update ~/.claude/settings.json:enabledPlugins" log_info " 4. Restart Claude Code" exit 0 fi # Add marketplaces (CORRECTION B: `claude plugin marketplace ...`) for mp in $(jq -r 'keys[]' "$marketplaces"); do repo=$(jq -r ".[\"$mp\"].source.repo" "$marketplaces") if claude plugin marketplace list 2>/dev/null | grep -q "$mp"; then log_info "Marketplace $mp already added" else log_info "Adding marketplace: $repo" claude plugin marketplace add "$repo" || { log_error "plugin marketplace add failed: $repo"; exit 6; } fi done # Install plugins for plugin in $(jq -r '.plugins | keys[]' "$manifest"); do expected_sha=$(jq -r ".plugins[\"$plugin\"][0].gitCommitSha" "$manifest") expected_ver=$(jq -r ".plugins[\"$plugin\"][0].version" "$manifest") log_info "Installing $plugin (pinned v$expected_ver, SHA $expected_sha)" claude plugin install "$plugin" || { log_error "plugin install failed: $plugin"; exit 6; } actual_sha=$(claude plugin info "$plugin" --json 2>/dev/null | jq -r '.gitCommitSha // "unknown"') if [ "$actual_sha" = "$expected_sha" ]; then log_info " SHA match: $actual_sha" else log_warn " SHA mismatch (expected $expected_sha, got $actual_sha) — marketplace may have updated" fi done