| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307 |
- #!/usr/bin/env bash
- # ============================================================
- # Claude Code — Update all components
- # Pulls latest config, updates submodules, refreshes symlinks,
- # and runs doctor to verify.
- # ============================================================
- set -euo pipefail
- GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'; NC='\033[0m'
- ok() { echo -e "${GREEN}✓${NC} $1"; }
- warn() { echo -e "${YELLOW}⚠${NC} $1"; }
- info() { echo -e "${BLUE}→${NC} $1"; }
- REPO="$(cd "$(dirname "$0")" && pwd)"
- VERSION=$(cat "$REPO/version.txt" 2>/dev/null || echo "unknown")
- # Load shared detection library
- # shellcheck source=lib/detect-plugins.sh
- source "$REPO/lib/detect-plugins.sh"
- echo ""
- echo "═══ claude-config update (v${VERSION}) ═══"
- echo ""
- # ── 0. Update Claude Code CLI ──
- echo "── Updating Claude Code CLI..."
- if command -v claude &>/dev/null; then
- CURRENT_VER=$(claude --version 2>/dev/null | head -1 || echo "unknown")
- info "Current: $CURRENT_VER"
- if npm install -g @anthropic-ai/claude-code@latest 2>/dev/null; then
- NEW_VER=$(claude --version 2>/dev/null | head -1 || echo "unknown")
- if [ "$CURRENT_VER" = "$NEW_VER" ]; then
- ok "Claude Code already up to date ($NEW_VER)"
- else
- ok "Claude Code updated: $CURRENT_VER → $NEW_VER"
- fi
- else
- warn "Claude Code update failed — try manually: npm install -g @anthropic-ai/claude-code@latest"
- fi
- else
- warn "Claude Code not found — install first with: make install"
- fi
- echo ""
- # ── 1. Pull latest config ──
- echo "── Pulling latest config..."
- cd "$REPO"
- if git pull --rebase 2>/dev/null; then
- ok "Config repo updated"
- else
- warn "git pull failed — check for uncommitted changes"
- fi
- # ── 2. Update GStack submodule ──
- echo ""
- echo "── Updating GStack submodule..."
- warn "GStack tracks branch = main (no commit hash). Review upstream commits before updating."
- echo ""
- printf " Proceed with GStack update? [y/N] "
- read -r _gstack_confirm
- if [[ "$_gstack_confirm" =~ ^[Yy]$ ]]; then
- if git submodule update --remote skills-external/gstack 2>/dev/null; then
- if [ -d "skills-external/gstack" ]; then
- if [ -x "skills-external/gstack/setup" ]; then
- if (cd skills-external/gstack && ./setup) 2>/dev/null; then
- ok "GStack updated"
- else
- warn "GStack ./setup failed — submodule updated but setup did not complete"
- fi
- else
- warn "GStack ./setup not found or not executable — skipping"
- ok "GStack submodule pointer updated"
- fi
- fi
- else
- warn "GStack submodule update failed — run: git submodule update --init"
- fi
- else
- info "GStack update skipped"
- fi
- # ── 3. Update RTK (if pinned version available) ──
- echo ""
- echo "── Updating RTK..."
- if command -v cargo &>/dev/null; then
- RTK_VERSION=""
- if [ -f "$REPO/plugins.lock.json" ] && command -v python3 &>/dev/null; then
- RTK_VERSION=$(python3 -c "
- import json
- with open('$REPO/plugins.lock.json') as f:
- d = json.load(f)
- print(d.get('rtk',{}).get('version',''))
- " 2>/dev/null || true)
- fi
- if [ -n "$RTK_VERSION" ] && [ "$RTK_VERSION" != "latest" ]; then
- info "Pinned version: $RTK_VERSION"
- info "Compiling from source — this may take a few minutes..."
- if cargo install --git https://github.com/rtk-ai/rtk --tag "$RTK_VERSION" --force; then
- ok "RTK updated to $RTK_VERSION"
- else
- warn "RTK update failed"
- fi
- else
- info "No pinned version — installing latest"
- info "Compiling from source — this may take a few minutes..."
- if cargo install --git https://github.com/rtk-ai/rtk --force; then
- ok "RTK updated (latest)"
- else
- warn "RTK update failed"
- fi
- fi
- else
- warn "Cargo not available — skipping RTK"
- fi
- # ── 4. Update GSD v2 ──
- echo ""
- echo "── Updating GSD v2 (gsd-pi)..."
- if command -v gsd &>/dev/null; then
- GSD_VER=""
- if [ -f "$REPO/plugins.lock.json" ] && command -v python3 &>/dev/null; then
- GSD_VER=$(python3 -c "
- import json
- with open('$REPO/plugins.lock.json') as f:
- d = json.load(f)
- print(d.get('gsd',{}).get('version',''))
- " 2>/dev/null || true)
- fi
- if [ -n "$GSD_VER" ] && [ "$GSD_VER" != "latest" ]; then
- info "Pinned version: $GSD_VER"
- if npm install -g "gsd-pi@${GSD_VER}" 2>/dev/null; then
- ok "GSD v2 updated to $GSD_VER"
- else
- warn "GSD v2 update failed"
- fi
- else
- info "No pinned version — installing latest"
- if npm install -g gsd-pi 2>/dev/null; then
- ok "GSD v2 updated (latest)"
- else
- warn "GSD v2 update failed"
- fi
- fi
- else
- warn "GSD v2 not installed — skipping (run: npm install -g gsd-pi)"
- fi
- # ── 5. Update Context7 CLI ──
- echo ""
- echo "── Updating Context7 CLI..."
- if command -v ctx7 &>/dev/null; then
- CTX7_VER=""
- if [ -f "$REPO/plugins.lock.json" ] && command -v python3 &>/dev/null; then
- CTX7_VER=$(python3 -c "
- import json
- with open('$REPO/plugins.lock.json') as f:
- d = json.load(f)
- print(d.get('ctx7',{}).get('version',''))
- " 2>/dev/null || true)
- fi
- if [ -n "$CTX7_VER" ] && [ "$CTX7_VER" != "latest" ]; then
- info "Pinned version: $CTX7_VER"
- if npm install -g "ctx7@${CTX7_VER}" 2>/dev/null; then
- ok "ctx7 updated to $CTX7_VER"
- else
- warn "ctx7 update failed"
- fi
- else
- if npm install -g ctx7@latest 2>/dev/null; then
- ok "ctx7 updated (latest)"
- else
- warn "ctx7 update failed"
- fi
- fi
- else
- info "ctx7 not installed — skipping"
- fi
- # ── 6. Update Graphifyy ──
- echo ""
- echo "── Updating Graphifyy..."
- if command -v graphify &>/dev/null; then
- if pipx upgrade graphifyy 2>/dev/null; then
- ok "graphifyy updated"
- else
- warn "graphifyy update failed — try: pipx upgrade graphifyy"
- fi
- else
- info "graphifyy not installed — skipping"
- fi
- # ── 7. Update Emil Design Engineering skill ──
- echo ""
- echo "── Updating Emil Design Engineering..."
- EMIL_DIR="$REPO/skills-external/emil-design-eng"
- EMIL_URL="https://raw.githubusercontent.com/emilkowalski/skill/main/skills/emil-design-eng/SKILL.md"
- if [ -d "$EMIL_DIR" ]; then
- info "Fetching latest SKILL.md from emilkowalski/skill..."
- if curl -fsSL "$EMIL_URL" -o "$EMIL_DIR/SKILL.md.tmp" \
- && mv "$EMIL_DIR/SKILL.md.tmp" "$EMIL_DIR/SKILL.md"; then
- ok "emil-design-eng updated"
- else
- warn "emil-design-eng update failed"
- fi
- else
- info "emil-design-eng not installed — skipping (run: make plugin)"
- fi
- # ── 7.5. Update external skills (npx skills) ──
- echo ""
- echo "── Updating external skills (npx skills)..."
- if command -v npx &>/dev/null; then
- NPX_SKILLS=(
- "alchaincyf/darwin-skill"
- "alchaincyf/find-skills"
- )
- for _src in "${NPX_SKILLS[@]}"; do
- _name="${_src##*/}"
- if [ ! -d "$HOME/.agents/skills/$_name" ]; then
- info "$_name not installed — skipping (run: make plugin)"
- continue
- fi
- # `skills add` is idempotent and pulls latest from the source repo,
- # which is the closest thing to an update operation the CLI exposes.
- if npx -y skills add "$_src" 2>/dev/null; then
- ok "$_name refreshed from $_src"
- else
- warn "$_name refresh failed — run manually: npx -y skills add $_src"
- fi
- done
- else
- info "npx not available — skipping external skills"
- fi
- # ── 8. Update marketplace plugins ──
- echo ""
- echo "── Updating marketplace plugins..."
- if command -v claude &>/dev/null; then
- _plugins=$(claude plugin list 2>/dev/null \
- | grep -oP '(?<=❯ )\S+' || true)
- if [ -n "$_plugins" ]; then
- while IFS= read -r _p; do
- _name="${_p%%@*}"
- info "Updating $_name..."
- # Pass the full "name@marketplace" spec — the CLI rejects
- # the bare name when several marketplaces are registered.
- if claude plugin update "$_p" 2>/dev/null; then
- ok "$_name updated"
- else
- warn "$_name update failed"
- fi
- done <<< "$_plugins"
- else
- info "No marketplace plugins installed — skipping"
- fi
- else
- warn "Claude Code not found — skipping plugin update"
- fi
- # ── 9. Update shellcheck ──
- echo ""
- echo "── Updating shellcheck..."
- if command -v shellcheck &>/dev/null; then
- # Detect OS for package manager update
- if [[ "$OSTYPE" == "darwin"* ]]; then
- if brew upgrade shellcheck 2>/dev/null; then
- ok "shellcheck updated"
- else
- ok "shellcheck already up to date"
- fi
- elif command -v apt-get &>/dev/null; then
- if sudo apt-get install -y --only-upgrade shellcheck 2>/dev/null; then
- ok "shellcheck updated"
- else
- ok "shellcheck already up to date"
- fi
- elif command -v dnf &>/dev/null; then
- if sudo dnf upgrade -y shellcheck 2>/dev/null; then
- ok "shellcheck updated"
- else
- ok "shellcheck already up to date"
- fi
- elif command -v pacman &>/dev/null; then
- if sudo pacman -S --noconfirm shellcheck 2>/dev/null; then
- ok "shellcheck updated"
- else
- ok "shellcheck already up to date"
- fi
- else
- info "shellcheck installed via binary — update manually"
- fi
- else
- info "shellcheck not installed — skipping (run: make plugin)"
- fi
- # ── 10. Refresh symlinks ──
- echo ""
- echo "── Refreshing symlinks..."
- bash "$REPO/link.sh"
- # ── 11. Run doctor ──
- echo ""
- bash "$REPO/doctor.sh"
|