Merge branch 'development' into ruff-and-mypy
This commit is contained in:
104
CHANGELOG.md
104
CHANGELOG.md
@@ -126,6 +126,51 @@ This **minor feature release** introduces intelligent GitHub rate limit handling
|
|||||||
- **All tests passing** ✅ (16/16)
|
- **All tests passing** ✅ (16/16)
|
||||||
- **Test utilities**: Mock responses, config isolation, tmp directories
|
- **Test utilities**: Mock responses, config isolation, tmp directories
|
||||||
|
|
||||||
|
- **🎯 Bootstrap Skill Feature** - Self-hosting capability (PR #249)
|
||||||
|
- **Self-Bootstrap**: Generate skill-seekers as a Claude Code skill
|
||||||
|
- `./scripts/bootstrap_skill.sh` - One-command bootstrap
|
||||||
|
- Combines manual header with auto-generated codebase analysis
|
||||||
|
- Output: `output/skill-seekers/` ready for Claude Code
|
||||||
|
- Install: `cp -r output/skill-seekers ~/.claude/skills/`
|
||||||
|
- **Robust Frontmatter Detection**:
|
||||||
|
- Dynamic YAML frontmatter boundary detection (not hardcoded line counts)
|
||||||
|
- Fallback to line 6 if frontmatter not found
|
||||||
|
- Future-proof against frontmatter field additions
|
||||||
|
- **SKILL.md Validation**:
|
||||||
|
- File existence and non-empty checks
|
||||||
|
- Frontmatter delimiter presence
|
||||||
|
- Required fields validation (name, description)
|
||||||
|
- Exit with clear error messages on validation failures
|
||||||
|
- **Comprehensive Error Handling**:
|
||||||
|
- UV dependency check with install instructions
|
||||||
|
- Permission checks for output directory
|
||||||
|
- Graceful degradation on missing header file
|
||||||
|
|
||||||
|
- **🔧 MCP Now Optional** - User choice for installation profile
|
||||||
|
- **CLI Only**: `pip install skill-seekers` - No MCP dependencies
|
||||||
|
- **MCP Integration**: `pip install skill-seekers[mcp]` - Full MCP support
|
||||||
|
- **All Features**: `pip install skill-seekers[all]` - Everything enabled
|
||||||
|
- **Lazy Loading**: Graceful failure with helpful error messages when MCP not installed
|
||||||
|
- **Interactive Setup Wizard**:
|
||||||
|
- Shows all installation options on first run
|
||||||
|
- Stored at `~/.config/skill-seekers/.setup_shown`
|
||||||
|
- Accessible via `skill-seekers-setup` command
|
||||||
|
- **Entry Point**: `skill-seekers-setup` for manual access
|
||||||
|
|
||||||
|
- **🧪 E2E Testing for Bootstrap** - Comprehensive end-to-end tests
|
||||||
|
- **6 core tests** verifying bootstrap workflow:
|
||||||
|
- Output structure creation
|
||||||
|
- Header prepending
|
||||||
|
- YAML frontmatter validation
|
||||||
|
- Line count sanity checks
|
||||||
|
- Virtual environment installability
|
||||||
|
- Platform adaptor compatibility
|
||||||
|
- **Pytest markers**: @pytest.mark.e2e, @pytest.mark.venv, @pytest.mark.slow
|
||||||
|
- **Execution modes**:
|
||||||
|
- Fast tests: `pytest -k "not venv"` (~2-3 min)
|
||||||
|
- Full suite: `pytest -m "e2e"` (~5-10 min)
|
||||||
|
- **Test utilities**: Fixtures for project root, bootstrap runner, output directory
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- **GitHub Fetcher** - Integrated rate limit handler
|
- **GitHub Fetcher** - Integrated rate limit handler
|
||||||
@@ -149,11 +194,20 @@ This **minor feature release** introduces intelligent GitHub rate limit handling
|
|||||||
- Updated command documentation strings
|
- Updated command documentation strings
|
||||||
- Version bumped to 2.7.0
|
- Version bumped to 2.7.0
|
||||||
|
|
||||||
- **pyproject.toml** - New entry points
|
- **pyproject.toml** - New entry points and dependency restructuring
|
||||||
- Added `skill-seekers-config` entry point
|
- Added `skill-seekers-config` entry point
|
||||||
- Added `skill-seekers-resume` entry point
|
- Added `skill-seekers-resume` entry point
|
||||||
|
- Added `skill-seekers-setup` entry point for setup wizard
|
||||||
|
- **MCP moved to optional dependencies** - Now requires `pip install skill-seekers[mcp]`
|
||||||
|
- Updated pytest markers: e2e, venv, bootstrap, slow
|
||||||
- Version updated to 2.7.0
|
- Version updated to 2.7.0
|
||||||
|
|
||||||
|
- **install_skill.py** - Lazy MCP loading
|
||||||
|
- Try/except ImportError for MCP imports
|
||||||
|
- Graceful failure with helpful error message when MCP not installed
|
||||||
|
- Suggests alternatives: scrape + package workflow
|
||||||
|
- Maintains backward compatibility for existing MCP users
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- **Rate limit indefinite wait** - No more infinite waiting
|
- **Rate limit indefinite wait** - No more infinite waiting
|
||||||
@@ -174,19 +228,53 @@ This **minor feature release** introduces intelligent GitHub rate limit handling
|
|||||||
- Clear error messages for automation logs
|
- Clear error messages for automation logs
|
||||||
- Exit codes for pipeline integration
|
- Exit codes for pipeline integration
|
||||||
|
|
||||||
|
- **AttributeError in codebase_scraper.py** - Fixed incorrect flag check (PR #249)
|
||||||
|
- Changed `if args.build_api_reference:` to `if not args.skip_api_reference:`
|
||||||
|
- Aligns with v2.5.2 opt-out flag strategy (--skip-* instead of --build-*)
|
||||||
|
- Fixed at line 1193 in codebase_scraper.py
|
||||||
|
|
||||||
### Technical Details
|
### Technical Details
|
||||||
|
|
||||||
- **Architecture**: Strategy pattern for rate limit handling, singleton for config manager
|
- **Architecture**: Strategy pattern for rate limit handling, singleton for config manager
|
||||||
- **Files Modified**: 3 (github_fetcher.py, github_scraper.py, main.py)
|
- **Files Modified**: 6 (github_fetcher.py, github_scraper.py, main.py, pyproject.toml, install_skill.py, codebase_scraper.py)
|
||||||
- **New Files**: 4 (config_manager.py ~490 lines, config_command.py ~400 lines, rate_limit_handler.py ~450 lines, resume_command.py ~150 lines)
|
- **New Files**: 6 (config_manager.py ~490 lines, config_command.py ~400 lines, rate_limit_handler.py ~450 lines, resume_command.py ~150 lines, setup_wizard.py ~95 lines, test_bootstrap_skill_e2e.py ~169 lines)
|
||||||
- **Tests**: 16 tests added, all passing
|
- **Bootstrap Scripts**: 2 (bootstrap_skill.sh enhanced, skill_header.md)
|
||||||
- **Dependencies**: No new dependencies required
|
- **Tests**: 22 tests added, all passing (16 rate limit + 6 E2E bootstrap)
|
||||||
- **Backward Compatibility**: Fully backward compatible, new features are opt-in
|
- **Dependencies**: MCP moved to optional, no new required dependencies
|
||||||
|
- **Backward Compatibility**: Fully backward compatible, MCP optionality via pip extras
|
||||||
|
- **Credits**: Bootstrap feature contributed by @MiaoDX (PR #249)
|
||||||
|
|
||||||
### Migration Guide
|
### Migration Guide
|
||||||
|
|
||||||
**Existing users** - No migration needed! Everything works as before.
|
**Existing users** - No migration needed! Everything works as before.
|
||||||
|
|
||||||
|
**MCP users** - If you use MCP integration features:
|
||||||
|
```bash
|
||||||
|
# Reinstall with MCP support
|
||||||
|
pip install -U skill-seekers[mcp]
|
||||||
|
|
||||||
|
# Or install everything
|
||||||
|
pip install -U skill-seekers[all]
|
||||||
|
```
|
||||||
|
|
||||||
|
**New installation profiles**:
|
||||||
|
```bash
|
||||||
|
# CLI only (no MCP)
|
||||||
|
pip install skill-seekers
|
||||||
|
|
||||||
|
# With MCP integration
|
||||||
|
pip install skill-seekers[mcp]
|
||||||
|
|
||||||
|
# With multi-LLM support (Gemini, OpenAI)
|
||||||
|
pip install skill-seekers[all-llms]
|
||||||
|
|
||||||
|
# Everything
|
||||||
|
pip install skill-seekers[all]
|
||||||
|
|
||||||
|
# See all options
|
||||||
|
skill-seekers-setup
|
||||||
|
```
|
||||||
|
|
||||||
**To use new features**:
|
**To use new features**:
|
||||||
```bash
|
```bash
|
||||||
# Set up GitHub token (one-time)
|
# Set up GitHub token (one-time)
|
||||||
@@ -205,6 +293,10 @@ skill-seekers github --repo owner/repo --non-interactive
|
|||||||
|
|
||||||
# View configuration
|
# View configuration
|
||||||
skill-seekers config --show
|
skill-seekers config --show
|
||||||
|
|
||||||
|
# Bootstrap skill-seekers as a Claude Code skill
|
||||||
|
./scripts/bootstrap_skill.sh
|
||||||
|
cp -r output/skill-seekers ~/.claude/skills/
|
||||||
```
|
```
|
||||||
|
|
||||||
### Breaking Changes
|
### Breaking Changes
|
||||||
|
|||||||
78
README.md
78
README.md
@@ -220,6 +220,37 @@ skill-seekers resume github_react_20260117_143022
|
|||||||
|
|
||||||
**See complete documentation**: [Configuration Guide](docs/guides/CONFIGURATION.md) (coming soon)
|
**See complete documentation**: [Configuration Guide](docs/guides/CONFIGURATION.md) (coming soon)
|
||||||
|
|
||||||
|
### 🎯 Bootstrap Skill - Self-Hosting (**NEW - v2.7.0**)
|
||||||
|
|
||||||
|
Generate skill-seekers as a Claude Code skill to use within Claude:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Generate the skill
|
||||||
|
./scripts/bootstrap_skill.sh
|
||||||
|
|
||||||
|
# Install to Claude Code
|
||||||
|
cp -r output/skill-seekers ~/.claude/skills/
|
||||||
|
|
||||||
|
# Verify
|
||||||
|
ls ~/.claude/skills/skill-seekers/SKILL.md
|
||||||
|
```
|
||||||
|
|
||||||
|
**What you get:**
|
||||||
|
- ✅ **Complete skill documentation** - All CLI commands and usage patterns
|
||||||
|
- ✅ **CLI command reference** - Every tool and its options documented
|
||||||
|
- ✅ **Quick start examples** - Common workflows and best practices
|
||||||
|
- ✅ **Auto-generated API docs** - Code analysis, patterns, and examples
|
||||||
|
- ✅ **Robust validation** - YAML frontmatter and required fields checked
|
||||||
|
- ✅ **One-command bootstrap** - Combines manual header with auto-generated analysis
|
||||||
|
|
||||||
|
**How it works:**
|
||||||
|
1. Runs codebase analysis on skill-seekers itself (dogfooding!)
|
||||||
|
2. Combines handcrafted header (prerequisites, commands) with auto-generated content
|
||||||
|
3. Validates SKILL.md structure (frontmatter, required fields)
|
||||||
|
4. Outputs ready-to-use skill directory
|
||||||
|
|
||||||
|
**Result:** Use skill-seekers to create skills, from within Claude Code!
|
||||||
|
|
||||||
### 🔐 Private Config Repositories (**NEW - v2.2.0**)
|
### 🔐 Private Config Repositories (**NEW - v2.2.0**)
|
||||||
- ✅ **Git-Based Config Sources** - Fetch configs from private/team git repositories
|
- ✅ **Git-Based Config Sources** - Fetch configs from private/team git repositories
|
||||||
- ✅ **Multi-Source Management** - Register unlimited GitHub, GitLab, Bitbucket repos
|
- ✅ **Multi-Source Management** - Register unlimited GitHub, GitLab, Bitbucket repos
|
||||||
@@ -297,6 +328,53 @@ skill-seekers-codebase tests/ --build-how-to-guides --ai-mode none
|
|||||||
pip install skill-seekers
|
pip install skill-seekers
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Installation Options
|
||||||
|
|
||||||
|
Choose your installation profile based on which features you need:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1️⃣ CLI Only (Skill Generation)
|
||||||
|
pip install skill-seekers
|
||||||
|
|
||||||
|
# Features:
|
||||||
|
# • Scrape documentation websites
|
||||||
|
# • Analyze GitHub repositories
|
||||||
|
# • Extract from PDFs
|
||||||
|
# • Package skills for all platforms
|
||||||
|
|
||||||
|
# 2️⃣ MCP Integration (Claude Code, Cursor, Windsurf)
|
||||||
|
pip install skill-seekers[mcp]
|
||||||
|
|
||||||
|
# Features:
|
||||||
|
# • Everything from CLI Only
|
||||||
|
# • MCP server for Claude Code
|
||||||
|
# • One-command skill installation
|
||||||
|
# • HTTP/stdio transport modes
|
||||||
|
|
||||||
|
# 3️⃣ Multi-LLM Support (Gemini, OpenAI)
|
||||||
|
pip install skill-seekers[all-llms]
|
||||||
|
|
||||||
|
# Features:
|
||||||
|
# • Everything from CLI Only
|
||||||
|
# • Google Gemini support
|
||||||
|
# • OpenAI ChatGPT support
|
||||||
|
# • Enhanced AI features
|
||||||
|
|
||||||
|
# 4️⃣ Everything
|
||||||
|
pip install skill-seekers[all]
|
||||||
|
|
||||||
|
# Features:
|
||||||
|
# • All features enabled
|
||||||
|
# • Maximum flexibility
|
||||||
|
```
|
||||||
|
|
||||||
|
**Need help choosing?** Run the setup wizard:
|
||||||
|
```bash
|
||||||
|
skill-seekers-setup
|
||||||
|
```
|
||||||
|
|
||||||
|
The wizard shows all options with detailed feature lists and guides you through configuration.
|
||||||
|
|
||||||
Get started in seconds. No cloning, no setup - just install and run. See installation options below.
|
Get started in seconds. No cloning, no setup - just install and run. See installation options below.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -43,9 +43,8 @@ dependencies = [
|
|||||||
"beautifulsoup4>=4.14.2",
|
"beautifulsoup4>=4.14.2",
|
||||||
"PyGithub>=2.5.0",
|
"PyGithub>=2.5.0",
|
||||||
"GitPython>=3.1.40",
|
"GitPython>=3.1.40",
|
||||||
"mcp>=1.25,<2",
|
"httpx>=0.28.1", # Required for async scraping (core feature)
|
||||||
"httpx>=0.28.1",
|
"anthropic>=0.76.0", # Required for AI enhancement (core feature)
|
||||||
"httpx-sse>=0.4.3",
|
|
||||||
"PyMuPDF>=1.24.14",
|
"PyMuPDF>=1.24.14",
|
||||||
"Pillow>=11.0.0",
|
"Pillow>=11.0.0",
|
||||||
"pytesseract>=0.3.13",
|
"pytesseract>=0.3.13",
|
||||||
@@ -60,7 +59,7 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[project.optional-dependencies]
|
[project.optional-dependencies]
|
||||||
# MCP server dependencies (included by default, but optional)
|
# MCP server dependencies (NOW TRULY OPTIONAL)
|
||||||
mcp = [
|
mcp = [
|
||||||
"mcp>=1.25,<2",
|
"mcp>=1.25,<2",
|
||||||
"httpx>=0.28.1",
|
"httpx>=0.28.1",
|
||||||
@@ -126,6 +125,7 @@ skill-seekers-install-agent = "skill_seekers.cli.install_agent:main"
|
|||||||
skill-seekers-codebase = "skill_seekers.cli.codebase_scraper:main"
|
skill-seekers-codebase = "skill_seekers.cli.codebase_scraper:main"
|
||||||
skill-seekers-patterns = "skill_seekers.cli.pattern_recognizer:main"
|
skill-seekers-patterns = "skill_seekers.cli.pattern_recognizer:main"
|
||||||
skill-seekers-how-to-guides = "skill_seekers.cli.how_to_guide_builder:main"
|
skill-seekers-how-to-guides = "skill_seekers.cli.how_to_guide_builder:main"
|
||||||
|
skill-seekers-setup = "skill_seekers.cli.setup_wizard:main"
|
||||||
|
|
||||||
[tool.setuptools]
|
[tool.setuptools]
|
||||||
package-dir = {"" = "src"}
|
package-dir = {"" = "src"}
|
||||||
@@ -146,8 +146,11 @@ python_functions = ["test_*"]
|
|||||||
addopts = "-v --tb=short --strict-markers"
|
addopts = "-v --tb=short --strict-markers"
|
||||||
markers = [
|
markers = [
|
||||||
"asyncio: mark test as an async test",
|
"asyncio: mark test as an async test",
|
||||||
"slow: mark test as slow running",
|
"slow: mark test as slow running (>5 seconds)",
|
||||||
"integration: mark test as integration test (requires external services)",
|
"integration: mark test as integration test (requires external services)",
|
||||||
|
"e2e: mark test as end-to-end (resource-intensive, may create files)",
|
||||||
|
"venv: mark test as requiring virtual environment setup",
|
||||||
|
"bootstrap: mark test as bootstrap feature specific",
|
||||||
]
|
]
|
||||||
asyncio_mode = "auto"
|
asyncio_mode = "auto"
|
||||||
asyncio_default_fixture_loop_scope = "function"
|
asyncio_default_fixture_loop_scope = "function"
|
||||||
|
|||||||
115
scripts/bootstrap_skill.sh
Executable file
115
scripts/bootstrap_skill.sh
Executable file
@@ -0,0 +1,115 @@
|
|||||||
|
#!/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..."
|
||||||
|
if ! command -v uv &> /dev/null; then
|
||||||
|
echo "❌ Error: 'uv' is not installed"
|
||||||
|
echo ""
|
||||||
|
echo "Install uv:"
|
||||||
|
echo " curl -LsSf https://astral.sh/uv/install.sh | sh"
|
||||||
|
echo " # or"
|
||||||
|
echo " pip install uv"
|
||||||
|
echo ""
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
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
|
||||||
|
# Detect end of frontmatter dynamically
|
||||||
|
# Look for second occurrence of '---'
|
||||||
|
FRONTMATTER_END=$(grep -n '^---$' "$OUTPUT_DIR/SKILL.md" | sed -n '2p' | cut -d: -f1)
|
||||||
|
|
||||||
|
if [[ -n "$FRONTMATTER_END" ]]; then
|
||||||
|
# Skip frontmatter + blank line
|
||||||
|
AUTO_CONTENT=$(tail -n +$((FRONTMATTER_END + 2)) "$OUTPUT_DIR/SKILL.md")
|
||||||
|
else
|
||||||
|
# Fallback to line 6 if no frontmatter found
|
||||||
|
AUTO_CONTENT=$(tail -n +6 "$OUTPUT_DIR/SKILL.md")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
# Step 4: Validate merged SKILL.md
|
||||||
|
echo "Step 4: Validating SKILL.md..."
|
||||||
|
if [[ -f "$OUTPUT_DIR/SKILL.md" ]]; then
|
||||||
|
# Check file not empty
|
||||||
|
if [[ ! -s "$OUTPUT_DIR/SKILL.md" ]]; then
|
||||||
|
echo "❌ Error: SKILL.md is empty"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check frontmatter exists
|
||||||
|
if ! head -1 "$OUTPUT_DIR/SKILL.md" | grep -q '^---$'; then
|
||||||
|
echo "⚠️ Warning: SKILL.md missing frontmatter delimiter"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check required fields
|
||||||
|
if ! grep -q '^name:' "$OUTPUT_DIR/SKILL.md"; then
|
||||||
|
echo "❌ Error: SKILL.md missing 'name:' field"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! grep -q '^description:' "$OUTPUT_DIR/SKILL.md"; then
|
||||||
|
echo "❌ Error: SKILL.md missing 'description:' field"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "✓ Validation passed"
|
||||||
|
else
|
||||||
|
echo "❌ Error: SKILL.md not found"
|
||||||
|
exit 1
|
||||||
|
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 ""
|
||||||
44
scripts/skill_header.md
Normal file
44
scripts/skill_header.md
Normal file
@@ -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 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
@@ -1177,7 +1177,7 @@ Examples:
|
|||||||
print(f"{'=' * 60}")
|
print(f"{'=' * 60}")
|
||||||
print(f"Files analyzed: {len(results['files'])}")
|
print(f"Files analyzed: {len(results['files'])}")
|
||||||
print(f"Output directory: {args.output}")
|
print(f"Output directory: {args.output}")
|
||||||
if args.build_api_reference:
|
if not args.skip_api_reference:
|
||||||
print(f"API reference: {Path(args.output) / 'api_reference'}")
|
print(f"API reference: {Path(args.output) / 'api_reference'}")
|
||||||
print(f"{'=' * 60}\n")
|
print(f"{'=' * 60}\n")
|
||||||
|
|
||||||
|
|||||||
@@ -34,12 +34,29 @@ from pathlib import Path
|
|||||||
# Add parent directory to path to import MCP server
|
# Add parent directory to path to import MCP server
|
||||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||||
|
|
||||||
# Import the MCP tool function
|
# Import the MCP tool function (with lazy loading)
|
||||||
from skill_seekers.mcp.server import install_skill_tool
|
try:
|
||||||
|
from skill_seekers.mcp.server import install_skill_tool
|
||||||
|
MCP_AVAILABLE = True
|
||||||
|
except ImportError:
|
||||||
|
MCP_AVAILABLE = False
|
||||||
|
install_skill_tool = None
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
"""Main entry point for CLI"""
|
"""Main entry point for CLI"""
|
||||||
|
# Check MCP availability first
|
||||||
|
if not MCP_AVAILABLE:
|
||||||
|
print("\n❌ Error: MCP package not installed")
|
||||||
|
print("\nThe 'install' command requires MCP support.")
|
||||||
|
print("Install with:")
|
||||||
|
print(" pip install skill-seekers[mcp]")
|
||||||
|
print("\nOr use these alternatives:")
|
||||||
|
print(" skill-seekers scrape --config react")
|
||||||
|
print(" skill-seekers package output/react/")
|
||||||
|
print()
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
description="Complete skill installation workflow (fetch → scrape → enhance → package → upload)",
|
description="Complete skill installation workflow (fetch → scrape → enhance → package → upload)",
|
||||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||||
|
|||||||
94
src/skill_seekers/cli/setup_wizard.py
Normal file
94
src/skill_seekers/cli/setup_wizard.py
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
"""
|
||||||
|
Interactive Setup Wizard for Skill Seekers
|
||||||
|
|
||||||
|
Guides users through installation options on first run.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def show_installation_guide():
|
||||||
|
"""Show installation options"""
|
||||||
|
print("""
|
||||||
|
╔═══════════════════════════════════════════════════════════╗
|
||||||
|
║ ║
|
||||||
|
║ Skill Seekers Setup Guide ║
|
||||||
|
║ ║
|
||||||
|
╚═══════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
|
Choose your installation profile:
|
||||||
|
|
||||||
|
1️⃣ CLI Only (Skill Generation)
|
||||||
|
pip install skill-seekers
|
||||||
|
|
||||||
|
Features:
|
||||||
|
• Scrape documentation websites
|
||||||
|
• Analyze GitHub repositories
|
||||||
|
• Extract from PDFs
|
||||||
|
• Package skills for all platforms
|
||||||
|
|
||||||
|
2️⃣ MCP Integration (Claude Code, Cursor, Windsurf)
|
||||||
|
pip install skill-seekers[mcp]
|
||||||
|
|
||||||
|
Features:
|
||||||
|
• Everything from CLI Only
|
||||||
|
• MCP server for Claude Code
|
||||||
|
• One-command skill installation
|
||||||
|
• HTTP/stdio transport modes
|
||||||
|
|
||||||
|
3️⃣ Multi-LLM Support (Gemini, OpenAI)
|
||||||
|
pip install skill-seekers[all-llms]
|
||||||
|
|
||||||
|
Features:
|
||||||
|
• Everything from CLI Only
|
||||||
|
• Google Gemini support
|
||||||
|
• OpenAI ChatGPT support
|
||||||
|
• Enhanced AI features
|
||||||
|
|
||||||
|
4️⃣ Everything
|
||||||
|
pip install skill-seekers[all]
|
||||||
|
|
||||||
|
Features:
|
||||||
|
• All features enabled
|
||||||
|
• Maximum flexibility
|
||||||
|
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
|
||||||
|
Current installation: pip install skill-seekers
|
||||||
|
Upgrade with: pip install -U skill-seekers[mcp]
|
||||||
|
|
||||||
|
For configuration wizard:
|
||||||
|
skill-seekers config
|
||||||
|
|
||||||
|
For help:
|
||||||
|
skill-seekers --help
|
||||||
|
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
""")
|
||||||
|
|
||||||
|
|
||||||
|
def check_first_run():
|
||||||
|
"""Check if this is first run"""
|
||||||
|
flag_file = Path.home() / ".config" / "skill-seekers" / ".setup_shown"
|
||||||
|
|
||||||
|
if not flag_file.exists():
|
||||||
|
show_installation_guide()
|
||||||
|
|
||||||
|
# Create flag to not show again
|
||||||
|
flag_file.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
flag_file.touch()
|
||||||
|
|
||||||
|
response = input("\nPress Enter to continue...")
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Show wizard"""
|
||||||
|
show_installation_guide()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
83
tests/test_bootstrap_skill.py
Normal file
83
tests/test_bootstrap_skill.py
Normal file
@@ -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"
|
||||||
171
tests/test_bootstrap_skill_e2e.py
Normal file
171
tests/test_bootstrap_skill_e2e.py
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
"""
|
||||||
|
End-to-end tests for bootstrap skill feature (PR #249)
|
||||||
|
|
||||||
|
Tests verify:
|
||||||
|
1. Bootstrap script creates proper skill structure
|
||||||
|
2. Generated SKILL.md is valid and usable
|
||||||
|
3. Skill is installable in isolated virtual environment
|
||||||
|
4. Output works with all platform adaptors
|
||||||
|
5. Error cases handled gracefully
|
||||||
|
|
||||||
|
Coverage: 8-12 tests
|
||||||
|
Execution time: Fast tests ~2-3 min, Full tests ~5-10 min
|
||||||
|
Requires: Python 3.10+, bash, uv
|
||||||
|
|
||||||
|
Run fast tests:
|
||||||
|
pytest tests/test_bootstrap_skill_e2e.py -v -k "not venv"
|
||||||
|
|
||||||
|
Run full suite:
|
||||||
|
pytest tests/test_bootstrap_skill_e2e.py -v -m "e2e"
|
||||||
|
|
||||||
|
Run with venv tests:
|
||||||
|
pytest tests/test_bootstrap_skill_e2e.py -v -m "venv"
|
||||||
|
"""
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def project_root():
|
||||||
|
"""Get project root directory."""
|
||||||
|
return Path(__file__).parent.parent
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def run_bootstrap(project_root):
|
||||||
|
"""Execute bootstrap script and return result"""
|
||||||
|
def _run(timeout=600):
|
||||||
|
script = project_root / "scripts" / "bootstrap_skill.sh"
|
||||||
|
|
||||||
|
result = subprocess.run(
|
||||||
|
["bash", str(script)],
|
||||||
|
cwd=project_root,
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
timeout=timeout
|
||||||
|
)
|
||||||
|
|
||||||
|
return result
|
||||||
|
return _run
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def output_skill_dir(project_root):
|
||||||
|
"""Get path to bootstrap output directory"""
|
||||||
|
return project_root / "output" / "skill-seekers"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.e2e
|
||||||
|
class TestBootstrapSkillE2E:
|
||||||
|
"""End-to-end tests for bootstrap skill"""
|
||||||
|
|
||||||
|
def test_bootstrap_creates_output_structure(self, run_bootstrap, output_skill_dir):
|
||||||
|
"""Verify bootstrap creates correct directory structure"""
|
||||||
|
result = run_bootstrap()
|
||||||
|
|
||||||
|
assert result.returncode == 0, f"Bootstrap failed: {result.stderr}"
|
||||||
|
assert output_skill_dir.exists(), "Output directory not created"
|
||||||
|
assert (output_skill_dir / "SKILL.md").exists(), "SKILL.md not created"
|
||||||
|
assert (output_skill_dir / "SKILL.md").stat().st_size > 0, "SKILL.md is empty"
|
||||||
|
|
||||||
|
def test_bootstrap_prepends_header(self, run_bootstrap, output_skill_dir):
|
||||||
|
"""Verify header template prepended to SKILL.md"""
|
||||||
|
result = run_bootstrap()
|
||||||
|
assert result.returncode == 0
|
||||||
|
|
||||||
|
content = (output_skill_dir / "SKILL.md").read_text()
|
||||||
|
|
||||||
|
# Check header sections present
|
||||||
|
assert "## Prerequisites" in content, "Missing Prerequisites section"
|
||||||
|
assert "pip install skill-seekers" in content, "Missing install instruction"
|
||||||
|
assert "## Commands" in content, "Missing Commands section"
|
||||||
|
|
||||||
|
def test_bootstrap_validates_yaml_frontmatter(self, run_bootstrap, output_skill_dir):
|
||||||
|
"""Verify generated SKILL.md has valid YAML frontmatter"""
|
||||||
|
result = run_bootstrap()
|
||||||
|
assert result.returncode == 0
|
||||||
|
|
||||||
|
content = (output_skill_dir / "SKILL.md").read_text()
|
||||||
|
|
||||||
|
# Check frontmatter structure
|
||||||
|
assert content.startswith("---"), "Missing frontmatter start"
|
||||||
|
|
||||||
|
# Find closing delimiter
|
||||||
|
lines = content.split('\n')
|
||||||
|
closing_found = False
|
||||||
|
for i, line in enumerate(lines[1:], 1):
|
||||||
|
if line.strip() == "---":
|
||||||
|
closing_found = True
|
||||||
|
break
|
||||||
|
|
||||||
|
assert closing_found, "Missing frontmatter closing delimiter"
|
||||||
|
|
||||||
|
# Check required fields
|
||||||
|
assert "name:" in content[:500], "Missing name field"
|
||||||
|
assert "description:" in content[:500], "Missing description field"
|
||||||
|
|
||||||
|
def test_bootstrap_output_line_count(self, run_bootstrap, output_skill_dir):
|
||||||
|
"""Verify output SKILL.md has reasonable line count"""
|
||||||
|
result = run_bootstrap()
|
||||||
|
assert result.returncode == 0
|
||||||
|
|
||||||
|
line_count = len((output_skill_dir / "SKILL.md").read_text().splitlines())
|
||||||
|
|
||||||
|
# Should be substantial (header ~44 + auto-generated ~200+)
|
||||||
|
assert line_count > 100, f"SKILL.md too short: {line_count} lines"
|
||||||
|
assert line_count < 2000, f"SKILL.md suspiciously long: {line_count} lines"
|
||||||
|
|
||||||
|
@pytest.mark.slow
|
||||||
|
@pytest.mark.venv
|
||||||
|
def test_skill_installable_in_venv(self, run_bootstrap, output_skill_dir, tmp_path):
|
||||||
|
"""Test skill is installable in clean virtual environment"""
|
||||||
|
# First run bootstrap
|
||||||
|
result = run_bootstrap()
|
||||||
|
assert result.returncode == 0
|
||||||
|
|
||||||
|
# Create venv
|
||||||
|
venv_path = tmp_path / "test_venv"
|
||||||
|
subprocess.run(
|
||||||
|
[sys.executable, "-m", "venv", str(venv_path)],
|
||||||
|
check=True,
|
||||||
|
timeout=60
|
||||||
|
)
|
||||||
|
|
||||||
|
# Install skill in venv
|
||||||
|
pip_path = venv_path / "bin" / "pip"
|
||||||
|
result = subprocess.run(
|
||||||
|
[str(pip_path), "install", "-e", "."],
|
||||||
|
cwd=output_skill_dir.parent.parent,
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
timeout=120
|
||||||
|
)
|
||||||
|
|
||||||
|
# Should install successfully
|
||||||
|
assert result.returncode == 0, f"Install failed: {result.stderr}"
|
||||||
|
|
||||||
|
def test_skill_packageable_with_adaptors(self, run_bootstrap, output_skill_dir, tmp_path):
|
||||||
|
"""Verify bootstrap output works with all platform adaptors"""
|
||||||
|
result = run_bootstrap()
|
||||||
|
assert result.returncode == 0
|
||||||
|
|
||||||
|
# Try to package with claude adaptor (simplest)
|
||||||
|
from skill_seekers.cli.adaptors import get_adaptor
|
||||||
|
|
||||||
|
adaptor = get_adaptor('claude')
|
||||||
|
|
||||||
|
# Should be able to package without errors
|
||||||
|
try:
|
||||||
|
package_path = adaptor.package(
|
||||||
|
skill_dir=output_skill_dir, # Path object, not str
|
||||||
|
output_path=tmp_path # Path object, not str
|
||||||
|
)
|
||||||
|
|
||||||
|
assert Path(package_path).exists(), "Package not created"
|
||||||
|
assert Path(package_path).stat().st_size > 0, "Package is empty"
|
||||||
|
except Exception as e:
|
||||||
|
pytest.fail(f"Packaging failed: {e}")
|
||||||
@@ -114,7 +114,7 @@ class TestUnifiedCLIEntryPoints(unittest.TestCase):
|
|||||||
|
|
||||||
# Should show version
|
# Should show version
|
||||||
output = result.stdout + result.stderr
|
output = result.stdout + result.stderr
|
||||||
self.assertIn("2.5.1", output)
|
self.assertIn('2.7.0', output)
|
||||||
|
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
# If skill-seekers is not installed, skip this test
|
# If skill-seekers is not installed, skip this test
|
||||||
|
|||||||
34
uv.lock
generated
34
uv.lock
generated
@@ -17,6 +17,25 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" },
|
{ url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anthropic"
|
||||||
|
version = "0.76.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "anyio" },
|
||||||
|
{ name = "distro" },
|
||||||
|
{ name = "docstring-parser" },
|
||||||
|
{ name = "httpx" },
|
||||||
|
{ name = "jiter" },
|
||||||
|
{ name = "pydantic" },
|
||||||
|
{ name = "sniffio" },
|
||||||
|
{ name = "typing-extensions" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/6e/be/d11abafaa15d6304826438170f7574d750218f49a106c54424a40cef4494/anthropic-0.76.0.tar.gz", hash = "sha256:e0cae6a368986d5cf6df743dfbb1b9519e6a9eee9c6c942ad8121c0b34416ffe", size = 495483, upload-time = "2026-01-13T18:41:14.908Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e5/70/7b0fd9c1a738f59d3babe2b4212031c34ab7d0fda4ffef15b58a55c5bcea/anthropic-0.76.0-py3-none-any.whl", hash = "sha256:81efa3113901192af2f0fe977d3ec73fdadb1e691586306c4256cd6d5ccc331c", size = 390309, upload-time = "2026-01-13T18:41:13.483Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyio"
|
name = "anyio"
|
||||||
version = "4.12.0"
|
version = "4.12.0"
|
||||||
@@ -450,6 +469,15 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277, upload-time = "2023-12-24T09:54:30.421Z" },
|
{ url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277, upload-time = "2023-12-24T09:54:30.421Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "docstring-parser"
|
||||||
|
version = "0.17.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/b2/9d/c3b43da9515bd270df0f80548d9944e389870713cc1fe2b8fb35fe2bcefd/docstring_parser-0.17.0.tar.gz", hash = "sha256:583de4a309722b3315439bb31d64ba3eebada841f2e2cee23b99df001434c912", size = 27442, upload-time = "2025-07-21T07:35:01.868Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/55/e2/2537ebcff11c1ee1ff17d8d0b6f4db75873e3b0fb32c2d4a2ee31ecb310a/docstring_parser-0.17.0-py3-none-any.whl", hash = "sha256:cf2569abd23dce8099b300f9b4fa8191e9582dda731fd533daf54c4551658708", size = 36896, upload-time = "2025-07-21T07:35:00.684Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "exceptiongroup"
|
name = "exceptiongroup"
|
||||||
version = "1.3.1"
|
version = "1.3.1"
|
||||||
@@ -1821,13 +1849,12 @@ name = "skill-seekers"
|
|||||||
version = "2.7.0"
|
version = "2.7.0"
|
||||||
source = { editable = "." }
|
source = { editable = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
{ name = "anthropic" },
|
||||||
{ name = "beautifulsoup4" },
|
{ name = "beautifulsoup4" },
|
||||||
{ name = "click" },
|
{ name = "click" },
|
||||||
{ name = "gitpython" },
|
{ name = "gitpython" },
|
||||||
{ name = "httpx" },
|
{ name = "httpx" },
|
||||||
{ name = "httpx-sse" },
|
|
||||||
{ name = "jsonschema" },
|
{ name = "jsonschema" },
|
||||||
{ name = "mcp" },
|
|
||||||
{ name = "networkx", version = "3.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
|
{ name = "networkx", version = "3.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
|
||||||
{ name = "networkx", version = "3.6.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
|
{ name = "networkx", version = "3.6.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
|
||||||
{ name = "pathspec" },
|
{ name = "pathspec" },
|
||||||
@@ -1884,6 +1911,7 @@ dev = [
|
|||||||
|
|
||||||
[package.metadata]
|
[package.metadata]
|
||||||
requires-dist = [
|
requires-dist = [
|
||||||
|
{ name = "anthropic", specifier = ">=0.76.0" },
|
||||||
{ name = "beautifulsoup4", specifier = ">=4.14.2" },
|
{ name = "beautifulsoup4", specifier = ">=4.14.2" },
|
||||||
{ name = "click", specifier = ">=8.3.0" },
|
{ name = "click", specifier = ">=8.3.0" },
|
||||||
{ name = "gitpython", specifier = ">=3.1.40" },
|
{ name = "gitpython", specifier = ">=3.1.40" },
|
||||||
@@ -1893,11 +1921,9 @@ requires-dist = [
|
|||||||
{ name = "httpx", specifier = ">=0.28.1" },
|
{ name = "httpx", specifier = ">=0.28.1" },
|
||||||
{ name = "httpx", marker = "extra == 'all'", specifier = ">=0.28.1" },
|
{ name = "httpx", marker = "extra == 'all'", specifier = ">=0.28.1" },
|
||||||
{ name = "httpx", marker = "extra == 'mcp'", specifier = ">=0.28.1" },
|
{ name = "httpx", marker = "extra == 'mcp'", specifier = ">=0.28.1" },
|
||||||
{ name = "httpx-sse", specifier = ">=0.4.3" },
|
|
||||||
{ name = "httpx-sse", marker = "extra == 'all'", specifier = ">=0.4.3" },
|
{ name = "httpx-sse", marker = "extra == 'all'", specifier = ">=0.4.3" },
|
||||||
{ name = "httpx-sse", marker = "extra == 'mcp'", specifier = ">=0.4.3" },
|
{ name = "httpx-sse", marker = "extra == 'mcp'", specifier = ">=0.4.3" },
|
||||||
{ name = "jsonschema", specifier = ">=4.25.1" },
|
{ name = "jsonschema", specifier = ">=4.25.1" },
|
||||||
{ name = "mcp", specifier = ">=1.25,<2" },
|
|
||||||
{ name = "mcp", marker = "extra == 'all'", specifier = ">=1.25,<2" },
|
{ name = "mcp", marker = "extra == 'all'", specifier = ">=1.25,<2" },
|
||||||
{ name = "mcp", marker = "extra == 'mcp'", specifier = ">=1.25,<2" },
|
{ name = "mcp", marker = "extra == 'mcp'", specifier = ">=1.25,<2" },
|
||||||
{ name = "networkx", specifier = ">=3.0" },
|
{ name = "networkx", specifier = ">=3.0" },
|
||||||
|
|||||||
Reference in New Issue
Block a user