diff --git a/scripts/bootstrap_skill.sh b/scripts/bootstrap_skill.sh new file mode 100755 index 0000000..92a1147 --- /dev/null +++ b/scripts/bootstrap_skill.sh @@ -0,0 +1,65 @@ +#!/usr/bin/env bash +# +# Bootstrap Skill Seekers into an Operational Skill for Claude Code +# +# Usage: ./scripts/bootstrap_skill.sh +# Output: output/skill-seekers/ (skill directory) +# + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +SKILL_NAME="skill-seekers" +OUTPUT_DIR="$PROJECT_ROOT/output/$SKILL_NAME" +HEADER_FILE="$SCRIPT_DIR/skill_header.md" + +echo "============================================" +echo " Skill Seekers Bootstrap" +echo "============================================" + +# Step 1: Sync dependencies +echo "Step 1: uv sync..." +command -v uv &> /dev/null || { echo "Error: uv not installed"; exit 1; } +cd "$PROJECT_ROOT" +uv sync --quiet +echo "✓ Done" + +# Step 2: Run codebase analysis +echo "Step 2: Analyzing codebase..." +rm -rf "$OUTPUT_DIR" 2>/dev/null || true +uv run skill-seekers-codebase \ + --directory "$PROJECT_ROOT" \ + --output "$OUTPUT_DIR" \ + --depth deep \ + --ai-mode none 2>&1 | grep -E "^(INFO|✅)" || true +echo "✓ Done" + +# Step 3: Prepend header to SKILL.md +echo "Step 3: Adding operational header..." +if [[ -f "$HEADER_FILE" ]]; then + # Get auto-generated content (skip its frontmatter) + AUTO_CONTENT=$(tail -n +6 "$OUTPUT_DIR/SKILL.md") + # Combine: header + auto-generated + cat "$HEADER_FILE" > "$OUTPUT_DIR/SKILL.md" + echo "$AUTO_CONTENT" >> "$OUTPUT_DIR/SKILL.md" + echo "✓ Done ($(wc -l < "$OUTPUT_DIR/SKILL.md") lines)" +else + echo "Warning: $HEADER_FILE not found, using auto-generated only" +fi + +echo "" +echo "============================================" +echo " Bootstrap Complete!" +echo "============================================" +echo "" +echo "Output: $OUTPUT_DIR/" +echo " - SKILL.md ($(wc -l < "$OUTPUT_DIR/SKILL.md") lines)" +echo " - references/ (API docs, patterns, examples)" +echo "" +echo "Install to Claude Code:" +echo " cp -r output/$SKILL_NAME ~/.claude/skills/" +echo "" +echo "Verify:" +echo " ls ~/.claude/skills/$SKILL_NAME/SKILL.md" +echo "" diff --git a/scripts/skill_header.md b/scripts/skill_header.md new file mode 100644 index 0000000..ce2bfb3 --- /dev/null +++ b/scripts/skill_header.md @@ -0,0 +1,44 @@ +--- +name: skill-seekers +description: Generate LLM skills from documentation, codebases, and GitHub repositories +--- + +# Skill Seekers + +## Prerequisites + +```bash +pip install skill-seekers +# Or: uv pip install skill-seekers +``` + +## Commands + +| Source | Command | +|--------|---------| +| Local code | `skill-seekers-codebase --directory ./path` | +| Docs URL | `skill-seekers scrape --url https://...` | +| GitHub | `skill-seekers github --repo owner/repo` | +| PDF | `skill-seekers pdf --file doc.pdf` | + +## Quick Start + +```bash +# Analyze local codebase +skill-seekers-codebase --directory /path/to/project --output output/my-skill/ + +# Package for Claude +yes | skill-seekers package output/my-skill/ --no-open +``` + +## Options + +| Flag | Description | +|------|-------------| +| `--depth surface/deep/full` | Analysis depth | +| `--skip-patterns` | Skip pattern detection | +| `--skip-test-examples` | Skip test extraction | +| `--ai-mode none/api/local` | AI enhancement | + +--- + diff --git a/tests/test_bootstrap_skill.py b/tests/test_bootstrap_skill.py new file mode 100644 index 0000000..c882b57 --- /dev/null +++ b/tests/test_bootstrap_skill.py @@ -0,0 +1,83 @@ +"""Tests for the bootstrap skill script.""" + +import subprocess +import pytest +from pathlib import Path + + +@pytest.fixture +def project_root(): + """Get project root directory.""" + return Path(__file__).parent.parent + + +class TestBootstrapSkillScript: + """Tests for scripts/bootstrap_skill.sh""" + + def test_script_exists(self, project_root): + """Test that bootstrap script exists and is executable.""" + script = project_root / "scripts" / "bootstrap_skill.sh" + assert script.exists(), "bootstrap_skill.sh should exist" + assert script.stat().st_mode & 0o111, "bootstrap_skill.sh should be executable" + + def test_header_template_exists(self, project_root): + """Test that skill header template exists.""" + header = project_root / "scripts" / "skill_header.md" + assert header.exists(), "skill_header.md should exist" + + def test_header_has_required_sections(self, project_root): + """Test that header template has required operational sections.""" + header = project_root / "scripts" / "skill_header.md" + content = header.read_text() + + # Must have prerequisites + assert "## Prerequisites" in content, "Header must have Prerequisites section" + assert "pip install skill-seekers" in content, "Header must have pip install instruction" + + # Must have commands table + assert "## Commands" in content, "Header must have Commands section" + assert "skill-seekers-codebase" in content, "Header must mention codebase command" + assert "skill-seekers scrape" in content, "Header must mention scrape command" + assert "skill-seekers github" in content, "Header must mention github command" + + def test_header_has_yaml_frontmatter(self, project_root): + """Test that header has valid YAML frontmatter.""" + header = project_root / "scripts" / "skill_header.md" + content = header.read_text() + + assert content.startswith("---"), "Header must start with YAML frontmatter" + assert "name: skill-seekers" in content, "Header must have skill name" + assert "description:" in content, "Header must have description" + + @pytest.mark.slow + def test_bootstrap_script_runs(self, project_root, tmp_path): + """Test that bootstrap script runs successfully. + + Note: This test is slow as it runs full codebase analysis. + Run with: pytest -m slow + """ + script = project_root / "scripts" / "bootstrap_skill.sh" + + # Run script (skip if uv not available) + result = subprocess.run( + ["bash", str(script)], + cwd=project_root, + capture_output=True, + text=True, + timeout=600, # 10 minute timeout + ) + + # Check script completed + assert result.returncode == 0, f"Script failed: {result.stderr}" + + # Check outputs exist (directory named 'skill-seekers' for Claude Code) + output_dir = project_root / "output" / "skill-seekers" + assert output_dir.exists(), "Output directory should be created" + + skill_md = output_dir / "SKILL.md" + assert skill_md.exists(), "SKILL.md should be created" + + # Check SKILL.md has header prepended + content = skill_md.read_text() + assert "## Prerequisites" in content, "SKILL.md should have header prepended" + assert "pip install skill-seekers" in content, "SKILL.md should have install instructions"