fix(hub-guide): correct install target to ~/.claude/skills/
Skills go directly to ~/.claude/skills/<name>/ (not ~/.claude/plugins/). Hooks configured via setup-hooks.sh -> settings.local.json. Changes: - install.sh: targets ~/.claude/skills/, no settings.json registration needed - install.ps1: updated to match - setup-hooks.sh: new script to add hooks to settings.local.json - README: fix install instructions - Remove nested .claude-plugin directory - 26 skills symlinked to ~/.claude/skills/
This commit is contained in:
@@ -26,21 +26,24 @@ Skills activate automatically when Claude detects relevant context (language, fr
|
|||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
### As a Claude Code Plugin
|
### Quick Install
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Link for development (edits take effect immediately)
|
# Clone
|
||||||
ln -s /path/to/hub-guide ~/.claude/plugins/hub-guide
|
git clone https://github.com/asepharyana/asepharyana-hub-hub-guide.git
|
||||||
|
cd asepharyana-hub-hub-guide
|
||||||
|
|
||||||
# Or copy
|
# Copy all 26 skills (recommended)
|
||||||
cp -r /path/to/hub-guide ~/.claude/plugins/hub-guide
|
./install.sh
|
||||||
```
|
|
||||||
|
|
||||||
### Manual Install (skills only)
|
# Or symlink (edits in this repo are live)
|
||||||
|
./install.sh --link
|
||||||
|
|
||||||
```bash
|
# Install only specific skills
|
||||||
# Copy individual skills
|
./install.sh clean-code testing docker
|
||||||
cp -r skills/<skill-name> ~/.claude/skills/<skill-name>
|
|
||||||
|
# Configure hooks (auto-detect project type on session start)
|
||||||
|
./setup-hooks.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|||||||
+46
-83
@@ -1,36 +1,27 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# install.sh — hub-guide plugin installer for Claude Code
|
# install.sh — hub-guide skill installer for Claude Code
|
||||||
|
#
|
||||||
|
# Skills go to ~/.claude/skills/<name>/ where Claude Code auto-discovers them.
|
||||||
|
# Hooks can be configured manually (see README).
|
||||||
#
|
#
|
||||||
# Usage:
|
# Usage:
|
||||||
# ./install.sh # Install to ~/.claude/plugins/ + register in settings.json
|
# ./install.sh # Copy all 26 skills to ~/.claude/skills/
|
||||||
# ./install.sh --link # Symlink (edits in this repo are live)
|
# ./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
|
||||||
# ./install.sh clean-code testing # Install specific skills only
|
# ./install.sh --link clean-code # Symlink specific skills
|
||||||
#
|
#
|
||||||
# Requires: Claude Code, python3 (for JSON manipulation)
|
# Requires: Claude Code
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
PLUGIN_NAME="hub-guide"
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
SKILLS_DIR="${HOME}/.claude/skills"
|
||||||
# Determine target
|
LINK_MODE=false
|
||||||
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=()
|
FILTER_SKILLS=()
|
||||||
|
|
||||||
# Parse remaining args
|
# Parse args
|
||||||
for arg in "$@"; do
|
for arg in "$@"; do
|
||||||
case "$arg" in
|
case "$arg" in
|
||||||
--no-hooks) INSTALL_HOOKS=false ;;
|
|
||||||
--link) LINK_MODE=true ;;
|
--link) LINK_MODE=true ;;
|
||||||
--*) echo "Unknown option: $arg"; exit 1 ;;
|
--*) echo "Unknown option: $arg"; exit 1 ;;
|
||||||
*) FILTER_SKILLS+=("$arg") ;;
|
*) FILTER_SKILLS+=("$arg") ;;
|
||||||
@@ -38,86 +29,58 @@ for arg in "$@"; do
|
|||||||
done
|
done
|
||||||
|
|
||||||
echo "📐 hub-guide installer"
|
echo "📐 hub-guide installer"
|
||||||
|
echo " Target: ${SKILLS_DIR}/"
|
||||||
|
echo " Mode: $([ "$LINK_MODE" = true ] && echo 'symlink' || echo 'copy')"
|
||||||
|
echo ""
|
||||||
|
|
||||||
# Ensure target dir exists
|
# Ensure target dir exists
|
||||||
mkdir -p "${TARGET_DIR}/${PLUGIN_NAME}"
|
mkdir -p "$SKILLS_DIR"
|
||||||
|
|
||||||
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
|
if [ ${#FILTER_SKILLS[@]} -gt 0 ]; then
|
||||||
# Install only specified skills
|
INSTALL_LIST=()
|
||||||
for skill in "${FILTER_SKILLS[@]}"; do
|
for skill in "${FILTER_SKILLS[@]}"; do
|
||||||
skill_name=$(basename "$skill")
|
skill_name=$(basename "$skill")
|
||||||
skill_src="${SCRIPT_DIR}/skills/${skill_name}"
|
src="${SCRIPT_DIR}/skills/${skill_name}"
|
||||||
if [ -d "$skill_src" ]; then
|
if [ -d "$src" ]; then
|
||||||
echo " skills/${skill_name}/ → ${TARGET_DIR}/${PLUGIN_NAME}/skills/"
|
INSTALL_LIST+=("$skill_name")
|
||||||
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
|
else
|
||||||
echo " ⚠️ Skill '${skill_name}' not found at ${skill_src}"
|
echo " ⚠️ Skill '${skill_name}' not found"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
else
|
else
|
||||||
# Install all skills
|
# Gather all skills from source
|
||||||
echo " skills/ (all 26) → ${TARGET_DIR}/${PLUGIN_NAME}/skills/"
|
INSTALL_LIST=()
|
||||||
if [ "$LINK_MODE" = true ]; then
|
for d in "${SCRIPT_DIR}/skills/"*/; do
|
||||||
ln -sf "${SCRIPT_DIR}/skills" "${TARGET_DIR}/${PLUGIN_NAME}/skills"
|
INSTALL_LIST+=("$(basename "$d")")
|
||||||
else
|
done
|
||||||
cp -r "${SCRIPT_DIR}/skills" "${TARGET_DIR}/${PLUGIN_NAME}/"
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Register in settings.json so Claude Code loads the plugin
|
installed=0
|
||||||
SETTINGS_FILE="${HOME}/.claude/settings.json"
|
for skill_name in "${INSTALL_LIST[@]}"; do
|
||||||
if [ "$TARGET_DIR" = "${HOME}/.claude/plugins" ] && [ -f "$SETTINGS_FILE" ]; then
|
src="${SCRIPT_DIR}/skills/${skill_name}"
|
||||||
if grep -q "\"${PLUGIN_NAME}\"" "$SETTINGS_FILE" 2>/dev/null; then
|
dst="${SKILLS_DIR}/${skill_name}"
|
||||||
echo " ⏭️ ${PLUGIN_NAME} already registered in settings.json"
|
|
||||||
|
if [ "$LINK_MODE" = true ]; then
|
||||||
|
rm -rf "$dst"
|
||||||
|
ln -sf "$src" "$dst"
|
||||||
else
|
else
|
||||||
# Add to enabledPlugins using Python for reliable JSON manipulation
|
rm -rf "$dst"
|
||||||
python3 -c "
|
mkdir -p "$(dirname "$dst")"
|
||||||
import json, sys
|
cp -r "$src" "$dst"
|
||||||
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
|
||||||
fi
|
echo " ✅ ${skill_name}"
|
||||||
|
installed=$((installed + 1))
|
||||||
|
done
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "✅ hub-guide installed to ${TARGET_DIR}/${PLUGIN_NAME}/"
|
echo "✅ ${installed} skill(s) installed to ${SKILLS_DIR}/"
|
||||||
if [ "$LINK_MODE" = true ]; then
|
if [ "$LINK_MODE" = true ]; then
|
||||||
echo " (symlink — edits in this repo are live)"
|
echo " (symlink — edits in this repo are live)"
|
||||||
fi
|
fi
|
||||||
echo ""
|
echo ""
|
||||||
echo " Restart Claude Code or run /reload to activate."
|
echo " Restart Claude Code or run /reload."
|
||||||
echo " Skills auto-trigger when you work — no commands needed."
|
echo " Skills auto-trigger when you work — no commands needed."
|
||||||
|
echo ""
|
||||||
|
echo "📌 Hooks (auto-detect project):"
|
||||||
|
echo " For hooks support, add to ~/.claude/settings.local.json or"
|
||||||
|
echo " run: ./setup-hooks.sh"
|
||||||
|
|||||||
Executable
+58
@@ -0,0 +1,58 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# setup-hooks.sh — Configure hub-guide hooks in Claude Code
|
||||||
|
#
|
||||||
|
# Adds hub-guide hooks to ~/.claude/settings.local.json
|
||||||
|
# This allows Claude to auto-detect your project and suggest relevant skills.
|
||||||
|
#
|
||||||
|
# Usage: ./setup-hooks.sh
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
SETTINGS_FILE="${HOME}/.claude/settings.local.json"
|
||||||
|
|
||||||
|
echo "📐 hub-guide hooks setup"
|
||||||
|
|
||||||
|
python3 << PYEOF
|
||||||
|
import json, os
|
||||||
|
|
||||||
|
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
settings_file = os.path.expanduser("~/.claude/settings.local.json")
|
||||||
|
|
||||||
|
# Read existing or create empty
|
||||||
|
if os.path.exists(settings_file):
|
||||||
|
with open(settings_file) as f:
|
||||||
|
cfg = json.load(f)
|
||||||
|
else:
|
||||||
|
cfg = {}
|
||||||
|
|
||||||
|
# Build hooks config
|
||||||
|
cfg["hooks"] = {
|
||||||
|
"SessionStart": [{
|
||||||
|
"hooks": [{
|
||||||
|
"type": "command",
|
||||||
|
"command": f"bash \"{script_dir}/hooks/scripts/detect-project.sh\"",
|
||||||
|
"timeout": 10
|
||||||
|
}]
|
||||||
|
}],
|
||||||
|
"PreToolUse": [{
|
||||||
|
"matcher": "Write|Edit",
|
||||||
|
"hooks": [{
|
||||||
|
"type": "command",
|
||||||
|
"command": f"bash \"{script_dir}/hooks/scripts/detect-file-type.sh\" \"\$TOOL_INPUT\"",
|
||||||
|
"timeout": 10
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Ensure parent dir exists
|
||||||
|
os.makedirs(os.path.dirname(settings_file), exist_ok=True)
|
||||||
|
|
||||||
|
with open(settings_file, 'w') as f:
|
||||||
|
json.dump(cfg, f, indent=2)
|
||||||
|
|
||||||
|
print(f"✅ Hooks configured in {settings_file}")
|
||||||
|
PYEOF
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo " Restart Claude Code or run /reload to activate hooks."
|
||||||
Reference in New Issue
Block a user