diff --git a/README.md b/README.md index caa7b07..874b973 100644 --- a/README.md +++ b/README.md @@ -26,21 +26,24 @@ Skills activate automatically when Claude detects relevant context (language, fr ## Installation -### As a Claude Code Plugin +### Quick Install ```bash -# Link for development (edits take effect immediately) -ln -s /path/to/hub-guide ~/.claude/plugins/hub-guide +# Clone +git clone https://github.com/asepharyana/asepharyana-hub-hub-guide.git +cd asepharyana-hub-hub-guide -# Or copy -cp -r /path/to/hub-guide ~/.claude/plugins/hub-guide -``` +# Copy all 26 skills (recommended) +./install.sh -### Manual Install (skills only) +# Or symlink (edits in this repo are live) +./install.sh --link -```bash -# Copy individual skills -cp -r skills/ ~/.claude/skills/ +# Install only specific skills +./install.sh clean-code testing docker + +# Configure hooks (auto-detect project type on session start) +./setup-hooks.sh ``` ## Usage diff --git a/install.sh b/install.sh index 886f199..a09bcd8 100755 --- a/install.sh +++ b/install.sh @@ -1,36 +1,27 @@ #!/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// where Claude Code auto-discovers them. +# Hooks can be configured manually (see README). # # 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 +# ./install.sh # Copy all 26 skills to ~/.claude/skills/ +# ./install.sh --link # Symlink (edits in this repo are live) +# ./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 -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 +SKILLS_DIR="${HOME}/.claude/skills" +LINK_MODE=false FILTER_SKILLS=() -# Parse remaining args +# Parse 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") ;; @@ -38,86 +29,58 @@ for arg in "$@"; do done echo "📐 hub-guide installer" +echo " Target: ${SKILLS_DIR}/" +echo " Mode: $([ "$LINK_MODE" = true ] && echo 'symlink' || echo 'copy')" +echo "" # 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 - # Install only specified skills + INSTALL_LIST=() 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 + src="${SCRIPT_DIR}/skills/${skill_name}" + if [ -d "$src" ]; then + INSTALL_LIST+=("$skill_name") else - echo " ⚠️ Skill '${skill_name}' not found at ${skill_src}" + echo " ⚠️ Skill '${skill_name}' not found" 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 + # Gather all skills from source + INSTALL_LIST=() + for d in "${SCRIPT_DIR}/skills/"*/; do + INSTALL_LIST+=("$(basename "$d")") + done 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" +installed=0 +for skill_name in "${INSTALL_LIST[@]}"; do + src="${SCRIPT_DIR}/skills/${skill_name}" + dst="${SKILLS_DIR}/${skill_name}" + + if [ "$LINK_MODE" = true ]; then + rm -rf "$dst" + ln -sf "$src" "$dst" 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" + rm -rf "$dst" + mkdir -p "$(dirname "$dst")" + cp -r "$src" "$dst" fi -fi + echo " ✅ ${skill_name}" + installed=$((installed + 1)) +done echo "" -echo "✅ hub-guide installed to ${TARGET_DIR}/${PLUGIN_NAME}/" +echo "✅ ${installed} skill(s) installed to ${SKILLS_DIR}/" 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 " Restart Claude Code or run /reload." 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" diff --git a/setup-hooks.sh b/setup-hooks.sh new file mode 100755 index 0000000..6280dac --- /dev/null +++ b/setup-hooks.sh @@ -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."