feat(hub-guide): add install scripts with settings.json registration
- install.sh: copies/symlinks plugin to ~/.claude/plugins/ + auto-register in settings.json - install.ps1: PowerShell variant for Windows - Fix .claude-plugin nesting issue in install_item - Remove --project flag (unnecessary complexity) - Add progress echo for manifest installation
This commit is contained in:
+82
@@ -0,0 +1,82 @@
|
||||
# install.ps1 — hub-guide plugin installer for Claude Code (Windows)
|
||||
#
|
||||
# Usage:
|
||||
# .\install.ps1 # Install to %USERPROFILE%\.claude\plugins\
|
||||
# .\install.ps1 -Project # Install to .claude\plugins\ (project-scoped)
|
||||
# .\install.ps1 -Link # Symlink (PowerShell Admin/Dev mode)
|
||||
# .\install.ps1 -NoHooks # Skills only
|
||||
# .\install.ps1 clean-code testing # Install specific skills
|
||||
|
||||
param(
|
||||
[switch]$Project,
|
||||
[switch]$Link,
|
||||
[switch]$NoHooks,
|
||||
[Parameter(Position=0, ValueFromRemainingArguments=$true)]
|
||||
[string[]]$SkillFilter
|
||||
)
|
||||
|
||||
$PluginName = "hub-guide"
|
||||
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
|
||||
# Determine target
|
||||
if ($Project) {
|
||||
$TargetDir = Join-Path (Get-Location) ".claude\plugins"
|
||||
} else {
|
||||
$TargetDir = Join-Path $env:USERPROFILE ".claude\plugins"
|
||||
}
|
||||
|
||||
$PluginDir = Join-Path $TargetDir $PluginName
|
||||
|
||||
Write-Host "📐 hub-guide installer" -ForegroundColor Cyan
|
||||
|
||||
# Ensure target exists
|
||||
New-Item -ItemType Directory -Force -Path $PluginDir | Out-Null
|
||||
|
||||
# Install manifest
|
||||
Copy-Item -Path (Join-Path $ScriptDir ".claude-plugin") -Destination $PluginDir -Recurse -Force
|
||||
|
||||
# Install hooks
|
||||
if (-not $NoHooks) {
|
||||
Write-Host " hooks/ → $PluginDir\hooks\"
|
||||
if ($Link) {
|
||||
New-Item -ItemType SymbolicLink -Path "$PluginDir\hooks" -Target (Join-Path $ScriptDir "hooks") -Force | Out-Null
|
||||
} else {
|
||||
Copy-Item -Path (Join-Path $ScriptDir "hooks") -Destination $PluginDir -Recurse -Force
|
||||
}
|
||||
}
|
||||
|
||||
# Install skills
|
||||
if ($SkillFilter.Count -gt 0) {
|
||||
$SkillDir = Join-Path $PluginDir "skills"
|
||||
New-Item -ItemType Directory -Force -Path $SkillDir | Out-Null
|
||||
foreach ($skill in $SkillFilter) {
|
||||
$skillName = Split-Path $skill -Leaf
|
||||
$src = Join-Path $ScriptDir "skills" $skillName
|
||||
if (Test-Path $src) {
|
||||
Write-Host " skills/$skillName/ → $SkillDir"
|
||||
if ($Link) {
|
||||
New-Item -ItemType SymbolicLink -Path (Join-Path $SkillDir $skillName) -Target $src -Force | Out-Null
|
||||
} else {
|
||||
Copy-Item -Path $src -Destination $SkillDir -Recurse -Force
|
||||
}
|
||||
} else {
|
||||
Write-Host " ⚠️ Skill '$skillName' not found at $src" -ForegroundColor Yellow
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Write-Host " skills/ (all) → $PluginDir\skills\"
|
||||
if ($Link) {
|
||||
New-Item -ItemType SymbolicLink -Path (Join-Path $PluginDir "skills") -Target (Join-Path $ScriptDir "skills") -Force | Out-Null
|
||||
} else {
|
||||
Copy-Item -Path (Join-Path $ScriptDir "skills") -Destination $PluginDir -Recurse -Force
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "✅ hub-guide installed to $PluginDir" -ForegroundColor Green
|
||||
if ($Link) {
|
||||
Write-Host " (symlink — edits in this repo are live)"
|
||||
}
|
||||
Write-Host ""
|
||||
Write-Host " Restart Claude Code or run /reload to activate."
|
||||
Write-Host " Skills auto-trigger when you work — no commands needed."
|
||||
Executable
+123
@@ -0,0 +1,123 @@
|
||||
#!/bin/bash
|
||||
# install.sh — hub-guide plugin installer for Claude Code
|
||||
#
|
||||
# Usage:
|
||||
# ./install.sh # Install to ~/.claude/plugins/ + register in settings.json
|
||||
# ./install.sh --link # Symlink (edits in this repo are live)
|
||||
# ./install.sh --no-hooks # Skills only, skip hooks
|
||||
# ./install.sh clean-code testing # Install specific skills only
|
||||
#
|
||||
# Requires: Claude Code, python3 (for JSON manipulation)
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
PLUGIN_NAME="hub-guide"
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
# Determine target
|
||||
if [ "${1:-}" = "--link" ]; then
|
||||
LINK_MODE=true
|
||||
TARGET_DIR="${HOME}/.claude/plugins"
|
||||
shift
|
||||
else
|
||||
TARGET_DIR="${HOME}/.claude/plugins"
|
||||
fi
|
||||
|
||||
LINK_MODE="${LINK_MODE:-false}"
|
||||
INSTALL_HOOKS=true
|
||||
FILTER_SKILLS=()
|
||||
|
||||
# Parse remaining args
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--no-hooks) INSTALL_HOOKS=false ;;
|
||||
--link) LINK_MODE=true ;;
|
||||
--*) echo "Unknown option: $arg"; exit 1 ;;
|
||||
*) FILTER_SKILLS+=("$arg") ;;
|
||||
esac
|
||||
done
|
||||
|
||||
echo "📐 hub-guide installer"
|
||||
|
||||
# Ensure target dir exists
|
||||
mkdir -p "${TARGET_DIR}/${PLUGIN_NAME}"
|
||||
|
||||
install_item() {
|
||||
local src="$1"
|
||||
local dst="${TARGET_DIR}/${PLUGIN_NAME}/${src#${SCRIPT_DIR}/}"
|
||||
|
||||
if [ "$LINK_MODE" = true ]; then
|
||||
mkdir -p "$(dirname "$dst")"
|
||||
ln -sf "$src" "$dst"
|
||||
else
|
||||
rm -rf "$dst"
|
||||
cp -r "$src" "$dst"
|
||||
fi
|
||||
}
|
||||
|
||||
# Install manifest
|
||||
echo " .claude-plugin/ → ${TARGET_DIR}/${PLUGIN_NAME}/"
|
||||
install_item "${SCRIPT_DIR}/.claude-plugin"
|
||||
|
||||
# Install hooks
|
||||
if [ "$INSTALL_HOOKS" = true ]; then
|
||||
echo " hooks/ → ${TARGET_DIR}/${PLUGIN_NAME}/hooks/"
|
||||
if [ "$LINK_MODE" = true ]; then
|
||||
ln -sf "${SCRIPT_DIR}/hooks" "${TARGET_DIR}/${PLUGIN_NAME}/hooks"
|
||||
else
|
||||
cp -r "${SCRIPT_DIR}/hooks" "${TARGET_DIR}/${PLUGIN_NAME}/"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Install skills
|
||||
if [ ${#FILTER_SKILLS[@]} -gt 0 ]; then
|
||||
# Install only specified skills
|
||||
for skill in "${FILTER_SKILLS[@]}"; do
|
||||
skill_name=$(basename "$skill")
|
||||
skill_src="${SCRIPT_DIR}/skills/${skill_name}"
|
||||
if [ -d "$skill_src" ]; then
|
||||
echo " skills/${skill_name}/ → ${TARGET_DIR}/${PLUGIN_NAME}/skills/"
|
||||
if [ "$LINK_MODE" = true ]; then
|
||||
ln -sf "$skill_src" "${TARGET_DIR}/${PLUGIN_NAME}/skills/${skill_name}"
|
||||
else
|
||||
mkdir -p "${TARGET_DIR}/${PLUGIN_NAME}/skills"
|
||||
cp -r "$skill_src" "${TARGET_DIR}/${PLUGIN_NAME}/skills/"
|
||||
fi
|
||||
else
|
||||
echo " ⚠️ Skill '${skill_name}' not found at ${skill_src}"
|
||||
fi
|
||||
done
|
||||
else
|
||||
# Install all skills
|
||||
echo " skills/ (all 26) → ${TARGET_DIR}/${PLUGIN_NAME}/skills/"
|
||||
if [ "$LINK_MODE" = true ]; then
|
||||
ln -sf "${SCRIPT_DIR}/skills" "${TARGET_DIR}/${PLUGIN_NAME}/skills"
|
||||
else
|
||||
cp -r "${SCRIPT_DIR}/skills" "${TARGET_DIR}/${PLUGIN_NAME}/"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Register in settings.json so Claude Code loads the plugin
|
||||
SETTINGS_FILE="${HOME}/.claude/settings.json"
|
||||
if [ "$TARGET_DIR" = "${HOME}/.claude/plugins" ] && [ -f "$SETTINGS_FILE" ]; then
|
||||
if grep -q "\"${PLUGIN_NAME}\"" "$SETTINGS_FILE" 2>/dev/null; then
|
||||
echo " ⏭️ ${PLUGIN_NAME} already registered in settings.json"
|
||||
else
|
||||
# Add to enabledPlugins using Python for reliable JSON manipulation
|
||||
python3 -c "
|
||||
import json, sys
|
||||
with open('$SETTINGS_FILE') as f: cfg = json.load(f)
|
||||
cfg.setdefault('enabledPlugins', {})['${PLUGIN_NAME}'] = True
|
||||
with open('$SETTINGS_FILE', 'w') as f: json.dump(cfg, f, indent=2)
|
||||
" && echo " ✅ Registered ${PLUGIN_NAME} in settings.json enabledPlugins"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "✅ hub-guide installed to ${TARGET_DIR}/${PLUGIN_NAME}/"
|
||||
if [ "$LINK_MODE" = true ]; then
|
||||
echo " (symlink — edits in this repo are live)"
|
||||
fi
|
||||
echo ""
|
||||
echo " Restart Claude Code or run /reload to activate."
|
||||
echo " Skills auto-trigger when you work — no commands needed."
|
||||
Reference in New Issue
Block a user