feat(update-claude-skills): add update skill + scripts [v0.1.0]
New skill and cross-platform scripts that automate the full uplift cycle: git pull → conditionally rebuild MCP servers → install skills → version diff → reload hints. Claude-Code-only (Hermes uses hermes-installer-skill). - scripts/update.sh: bash version (Linux/macOS/git-bash) - scripts/update.ps1: PowerShell version (Windows) - skills/update-claude-skills/SKILL.md: thin wrapper, detects platform - hermes/mapping.yaml: mode: skip (Claude-Code-only) - dist/update-claude-skills.skill: built archive - .tasks/STATUS.md: task marked done Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
186
scripts/update.ps1
Normal file
186
scripts/update.ps1
Normal file
@@ -0,0 +1,186 @@
|
||||
# update.ps1 — Full uplift cycle for claude-skills on Windows (PowerShell)
|
||||
#
|
||||
# Steps:
|
||||
# 1. git pull --ff-only in claude-skills repo
|
||||
# 2. Conditionally rebuild projects-meta-mcp (if source changed)
|
||||
# 3. Conditionally rebuild interns-mcp (if source changed)
|
||||
# 4. Install all skills via install.ps1
|
||||
# 5. Show version diff (before -> after)
|
||||
# 6. Print reload hints
|
||||
#
|
||||
# Usage: update.ps1 [-Yes]
|
||||
# -Yes — skip confirmation prompts (assume yes)
|
||||
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[switch]$Yes
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
# ── Paths ──────────────────────────────────────────────────────────────────
|
||||
|
||||
$root = Split-Path -Parent $PSScriptRoot
|
||||
$skillsSrc = Join-Path $root 'skills'
|
||||
$target = if ($env:CLAUDE_SKILLS_DIR) { $env:CLAUDE_SKILLS_DIR } else { Join-Path $env:USERPROFILE '.claude\skills' }
|
||||
|
||||
$commonRoot = if ($env:COMMON_ROOT) { $env:COMMON_ROOT } else { Join-Path $env:USERPROFILE 'projects\.common' }
|
||||
$metaMcp = Join-Path $commonRoot 'lib\projects-meta-mcp'
|
||||
$internsMcp = Join-Path $commonRoot 'lib\interns-mcp'
|
||||
|
||||
# ── Collect before-versions ────────────────────────────────────────────────
|
||||
|
||||
$beforeVersions = @{}
|
||||
if (Test-Path $target) {
|
||||
Get-ChildItem -Path $target -Directory | ForEach-Object {
|
||||
$vf = Join-Path $_.FullName 'SKILL.md'
|
||||
if (Test-Path $vf) {
|
||||
$ver = (Select-String -Path $vf -Pattern '^version:\s*(\d+\.\d+\.\d+)' |
|
||||
Select-Object -First 1).Matches.Groups[1].Value
|
||||
if (-not $ver) { $ver = '?' }
|
||||
$beforeVersions[$_.Name] = $ver
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ── Step 1: git pull ────────────────────────────────────────────────────────
|
||||
|
||||
Write-Host "`n[update] Pulling claude-skills repo..." -ForegroundColor Cyan
|
||||
Push-Location $root
|
||||
|
||||
$dirty = git status --porcelain 2>$null
|
||||
if ($LASTEXITCODE -ne 0) { $dirty = $true }
|
||||
if ($dirty) {
|
||||
Write-Host "[warn] Working tree has uncommitted changes. Stashing..." -ForegroundColor Yellow
|
||||
git stash push -m 'update-ps1-auto-stash'
|
||||
if ($LASTEXITCODE -ne 0) { Write-Error "Cannot stash changes"; Pop-Location; exit 1 }
|
||||
$stashed = $true
|
||||
} else {
|
||||
$stashed = $false
|
||||
}
|
||||
|
||||
git pull --ff-only
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error "git pull --ff-only failed (diverged or no upstream)"
|
||||
Pop-Location; exit 1
|
||||
}
|
||||
Write-Host "[ok] Repo updated." -ForegroundColor Green
|
||||
|
||||
if ($stashed) {
|
||||
Write-Host "[update] Popping stashed changes..." -ForegroundColor Cyan
|
||||
git stash pop 2>$null
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Host "[warn] Could not pop stash — resolve manually" -ForegroundColor Yellow
|
||||
}
|
||||
}
|
||||
|
||||
# ── Step 2: projects-meta-mcp ─────────────────────────────────────────────
|
||||
|
||||
$mcpRebuilt = $false
|
||||
|
||||
if (Test-Path (Join-Path $metaMcp '.git')) {
|
||||
Write-Host "[update] Checking projects-meta-mcp..." -ForegroundColor Cyan
|
||||
Push-Location $metaMcp
|
||||
$preSha = git rev-parse HEAD
|
||||
git pull --ff-only 2>$null
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Host "[warn] projects-meta-mcp: pull failed or no upstream" -ForegroundColor Yellow
|
||||
}
|
||||
$postSha = git rev-parse HEAD
|
||||
|
||||
if ($preSha -ne $postSha) {
|
||||
Write-Host "[update] Source changed, rebuilding projects-meta-mcp..." -ForegroundColor Cyan
|
||||
npm run build 2>$null
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
npm install; npm run build
|
||||
}
|
||||
Write-Host "[ok] projects-meta-mcp rebuilt." -ForegroundColor Green
|
||||
$mcpRebuilt = $true
|
||||
} else {
|
||||
Write-Host "[ok] projects-meta-mcp: up to date." -ForegroundColor Green
|
||||
}
|
||||
Pop-Location
|
||||
} else {
|
||||
Write-Host "[warn] projects-meta-mcp not found at $metaMcp — skipping." -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
# ── Step 3: interns-mcp ───────────────────────────────────────────────────
|
||||
|
||||
if (Test-Path (Join-Path $internsMcp '.git')) {
|
||||
Write-Host "[update] Checking interns-mcp..." -ForegroundColor Cyan
|
||||
Push-Location $internsMcp
|
||||
$preSha = git rev-parse HEAD
|
||||
git pull --ff-only 2>$null
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Host "[warn] interns-mcp: pull failed or no upstream" -ForegroundColor Yellow
|
||||
}
|
||||
$postSha = git rev-parse HEAD
|
||||
|
||||
if ($preSha -ne $postSha) {
|
||||
Write-Host "[update] Source changed, reinstalling interns-mcp..." -ForegroundColor Cyan
|
||||
pip install -e . 2>$null
|
||||
if ($LASTEXITCODE -ne 0) { pip3 install -e . }
|
||||
Write-Host "[ok] interns-mcp reinstalled." -ForegroundColor Green
|
||||
$mcpRebuilt = $true
|
||||
} else {
|
||||
Write-Host "[ok] interns-mcp: up to date." -ForegroundColor Green
|
||||
}
|
||||
Pop-Location
|
||||
} else {
|
||||
Write-Host "[warn] interns-mcp not found at $internsMcp — skipping." -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
# ── Step 4: Install skills ─────────────────────────────────────────────────
|
||||
|
||||
Pop-Location
|
||||
Write-Host "[update] Installing skills..." -ForegroundColor Cyan
|
||||
& "$root\scripts\install.ps1"
|
||||
Write-Host "[ok] Skills installed." -ForegroundColor Green
|
||||
|
||||
# ── Step 5: Version diff ───────────────────────────────────────────────────
|
||||
|
||||
Write-Host "[update] Version diff:" -ForegroundColor Cyan
|
||||
$changes = $false
|
||||
Get-ChildItem -Path $target -Directory | ForEach-Object {
|
||||
$vf = Join-Path $_.FullName 'SKILL.md'
|
||||
if (Test-Path $vf) {
|
||||
$after = (Select-String -Path $vf -Pattern '^version:\s*(\d+\.\d+\.\d+)' |
|
||||
Select-Object -First 1).Matches.Groups[1].Value
|
||||
if (-not $after) { $after = '?' }
|
||||
$before = $beforeVersions[$_.Name]
|
||||
if (-not $before) { $before = 'new' }
|
||||
if ($before -ne $after) {
|
||||
Write-Host " $before -> $after ($($_.Name))"
|
||||
$changes = $true
|
||||
}
|
||||
}
|
||||
}
|
||||
if (-not $changes) {
|
||||
Write-Host ' (no version changes)'
|
||||
}
|
||||
|
||||
# ── Step 6: New setup-skills hint ──────────────────────────────────────────
|
||||
|
||||
$newSetup = @()
|
||||
Get-ChildItem -Path $skillsSrc -Directory | ForEach-Object {
|
||||
$name = $_.Name
|
||||
if ($name -like 'setup-*' -and -not (Test-Path (Join-Path $target $name))) {
|
||||
$newSetup += $name
|
||||
}
|
||||
}
|
||||
|
||||
if ($newSetup.Count -gt 0) {
|
||||
Write-Host ''
|
||||
Write-Host '[update] New setup skills available:' -ForegroundColor Cyan
|
||||
$newSetup | ForEach-Object { Write-Host " - $_" }
|
||||
Write-Host ' Run the setup skill to configure it.'
|
||||
}
|
||||
|
||||
# ── Step 7: Reload hints ──────────────────────────────────────────────────
|
||||
|
||||
Write-Host ''
|
||||
Write-Host '[ok] Update complete!' -ForegroundColor Green
|
||||
if ($mcpRebuilt) {
|
||||
Write-Host ' -> Run /reload-mcp to reload MCP servers (source changed)'
|
||||
}
|
||||
Write-Host ' -> Start a new Claude session for skill changes to take full effect'
|
||||
175
scripts/update.sh
Normal file
175
scripts/update.sh
Normal file
@@ -0,0 +1,175 @@
|
||||
#!/usr/bin/env bash
|
||||
# update.sh — Full uplift cycle for claude-skills on Linux/macOS (and git-bash on Windows)
|
||||
#
|
||||
# Steps:
|
||||
# 1. git pull --ff-only in claude-skills repo
|
||||
# 2. Conditionally rebuild projects-meta-mcp (if source changed)
|
||||
# 3. Conditionally rebuild interns-mcp (if source changed)
|
||||
# 4. Install all skills via install.sh
|
||||
# 5. Show version diff (before → after)
|
||||
# 6. Print reload hints
|
||||
#
|
||||
# Usage: update.sh [--yes]
|
||||
# --yes — skip confirmation prompts (assume yes)
|
||||
set -euo pipefail
|
||||
|
||||
YES_MODE=false
|
||||
[[ "${1:-}" == "--yes" ]] && YES_MODE=true
|
||||
|
||||
# ── Paths ──────────────────────────────────────────────────────────────────
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
SKILLS_SRC="$ROOT/skills"
|
||||
TARGET="${CLAUDE_SKILLS_DIR:-$HOME/.claude/skills}"
|
||||
|
||||
COMMON_ROOT="${COMMON_ROOT:-$HOME/projects/.common}"
|
||||
META_MCP="$COMMON_ROOT/lib/projects-meta-mcp"
|
||||
INTERNS_MCP="$COMMON_ROOT/lib/interns-mcp"
|
||||
|
||||
# ── Helpers ────────────────────────────────────────────────────────────────
|
||||
|
||||
info() { echo -e "\033[1;34m[update]\033[0m $*"; }
|
||||
ok() { echo -e "\033[1;32m[ok]\033[0m $*"; }
|
||||
warn() { echo -e "\033[1;33m[warn]\033[0m $*"; }
|
||||
fail() { echo -e "\033[1;31m[fail]\033[0m $*" >&2; exit 1; }
|
||||
|
||||
confirm() {
|
||||
local msg="$1"
|
||||
if $YES_MODE; then return 0; fi
|
||||
read -rp "$msg [y/N] " ans
|
||||
[[ "$ans" =~ ^[Yy] ]]
|
||||
}
|
||||
|
||||
# ── Collect before-versions ────────────────────────────────────────────────
|
||||
|
||||
declare -A BEFORE_VERSIONS=()
|
||||
if [[ -d "$TARGET" ]]; then
|
||||
for skill_dir in "$TARGET"/*/; do
|
||||
name="$(basename "$skill_dir")"
|
||||
vf="$skill_dir/SKILL.md"
|
||||
if [[ -f "$vf" ]]; then
|
||||
ver="$(grep -oP '^version:\s*\K[0-9]+\.[0-9]+\.[0-9]+' "$vf" 2>/dev/null || echo '?')"
|
||||
BEFORE_VERSIONS["$name"]="$ver"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# ── Step 1: git pull ────────────────────────────────────────────────────────
|
||||
|
||||
info "Pulling claude-skills repo..."
|
||||
cd "$ROOT"
|
||||
|
||||
if [[ -n "$(git status --porcelain)" ]]; then
|
||||
warn "Working tree has uncommitted changes. Stashing..."
|
||||
git stash push -m "update-sh-auto-stash" || fail "Cannot stash changes"
|
||||
STASHED=true
|
||||
else
|
||||
STASHED=false
|
||||
fi
|
||||
|
||||
git pull --ff-only || fail "git pull --ff-only failed (diverged or no upstream)"
|
||||
ok "Repo updated."
|
||||
|
||||
if $STASHED; then
|
||||
info "Popping stashed changes..."
|
||||
git stash pop || warn "Could not pop stash — resolve manually"
|
||||
fi
|
||||
|
||||
# ── Step 2: projects-meta-mcp ─────────────────────────────────────────────
|
||||
|
||||
if [[ -d "$META_MCP/.git" ]]; then
|
||||
info "Checking projects-meta-mcp..."
|
||||
cd "$META_MCP"
|
||||
PRE_SHA="$(git rev-parse HEAD)"
|
||||
git pull --ff-only 2>/dev/null || warn "projects-meta-mcp: pull failed or no upstream"
|
||||
POST_SHA="$(git rev-parse HEAD)"
|
||||
|
||||
if [[ "$PRE_SHA" != "$POST_SHA" ]]; then
|
||||
info "Source changed, rebuilding projects-meta-mcp..."
|
||||
npm run build 2>/dev/null || npm install && npm run build
|
||||
ok "projects-meta-mcp rebuilt."
|
||||
MCP_REBUILT=true
|
||||
else
|
||||
ok "projects-meta-mcp: up to date."
|
||||
MCP_REBUILT=false
|
||||
fi
|
||||
else
|
||||
warn "projects-meta-mcp not found at $META_MCP — skipping."
|
||||
MCP_REBUILT=false
|
||||
fi
|
||||
|
||||
# ── Step 3: interns-mcp ───────────────────────────────────────────────────
|
||||
|
||||
if [[ -d "$INTERNS_MCP/.git" ]]; then
|
||||
info "Checking interns-mcp..."
|
||||
cd "$INTERNS_MCP"
|
||||
PRE_SHA="$(git rev-parse HEAD)"
|
||||
git pull --ff-only 2>/dev/null || warn "interns-mcp: pull failed or no upstream"
|
||||
POST_SHA="$(git rev-parse HEAD)"
|
||||
|
||||
if [[ "$PRE_SHA" != "$POST_SHA" ]]; then
|
||||
info "Source changed, reinstalling interns-mcp..."
|
||||
pip install -e . 2>/dev/null || pip3 install -e .
|
||||
ok "interns-mcp reinstalled."
|
||||
MCP_REBUILT=true
|
||||
else
|
||||
ok "interns-mcp: up to date."
|
||||
fi
|
||||
else
|
||||
warn "interns-mcp not found at $INTERNS_MCP — skipping."
|
||||
fi
|
||||
|
||||
# ── Step 4: Install skills ─────────────────────────────────────────────────
|
||||
|
||||
cd "$ROOT"
|
||||
info "Installing skills..."
|
||||
bash "$ROOT/scripts/install.sh"
|
||||
ok "Skills installed."
|
||||
|
||||
# ── Step 5: Version diff ───────────────────────────────────────────────────
|
||||
|
||||
info "Version diff:"
|
||||
CHANGES=false
|
||||
for skill_dir in "$TARGET"/*/; do
|
||||
name="$(basename "$skill_dir")"
|
||||
vf="$skill_dir/SKILL.md"
|
||||
if [[ -f "$vf" ]]; then
|
||||
after="$(grep -oP '^version:\s*\K[0-9]+\.[0-9]+\.[0-9]+' "$vf" 2>/dev/null || echo '?')"
|
||||
before="${BEFORE_VERSIONS[$name]:-new}"
|
||||
if [[ "$before" != "$after" ]]; then
|
||||
echo " $before → $after ($name)"
|
||||
CHANGES=true
|
||||
fi
|
||||
fi
|
||||
done
|
||||
if ! $CHANGES; then
|
||||
echo " (no version changes)"
|
||||
fi
|
||||
|
||||
# ── Step 6: New setup-skills hint ──────────────────────────────────────────
|
||||
|
||||
NEW_SETUP=()
|
||||
for skill_dir in "$SKILLS_SRC"/*/; do
|
||||
name="$(basename "$skill_dir")"
|
||||
if [[ "$name" == setup-* ]] && [[ ! -d "$TARGET/$name" ]]; then
|
||||
NEW_SETUP+=("$name")
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ ${#NEW_SETUP[@]} -gt 0 ]]; then
|
||||
echo ""
|
||||
info "New setup skills available:"
|
||||
for s in "${NEW_SETUP[@]}"; do
|
||||
echo " - $s"
|
||||
done
|
||||
echo " Run the setup skill to configure it."
|
||||
fi
|
||||
|
||||
# ── Step 7: Reload hints ──────────────────────────────────────────────────
|
||||
|
||||
echo ""
|
||||
ok "Update complete!"
|
||||
if $MCP_REBUILT; then
|
||||
echo " → Run /reload-mcp to reload MCP servers (source changed)"
|
||||
fi
|
||||
echo " → Start a new Claude session for skill changes to take full effect"
|
||||
Reference in New Issue
Block a user